From 2233ba702528b394585f52ccc093f3c2d7fb53bd Mon Sep 17 00:00:00 2001 From: Joseph Aquino Date: Sat, 27 Dec 2025 09:19:17 -0500 Subject: [PATCH] sfml and it's dependencies now build from source on windows, all within premake no cmake required --- Create-Solution.bat | 1 - premake5.lua | 60 +- vendor/flac/AUTHORS | 60 + vendor/flac/COPYING.FDL | 397 + vendor/flac/COPYING.GPL | 339 + vendor/flac/COPYING.LGPL | 504 + vendor/flac/COPYING.Xiph | 29 + vendor/flac/README.md | 278 + vendor/flac/build-flac.lua | 44 + vendor/flac/include/FLAC++/Makefile.am | 39 + vendor/flac/include/FLAC++/all.h | 49 + vendor/flac/include/FLAC++/decoder.h | 248 + vendor/flac/include/FLAC++/encoder.h | 265 + vendor/flac/include/FLAC++/export.h | 100 + vendor/flac/include/FLAC++/metadata.h | 1234 ++ vendor/flac/include/FLAC/Makefile.am | 43 + vendor/flac/include/FLAC/all.h | 450 + vendor/flac/include/FLAC/assert.h | 51 + vendor/flac/include/FLAC/callback.h | 190 + vendor/flac/include/FLAC/export.h | 115 + vendor/flac/include/FLAC/format.h | 1032 + vendor/flac/include/FLAC/metadata.h | 2234 +++ vendor/flac/include/FLAC/ordinals.h | 55 + vendor/flac/include/FLAC/stream_decoder.h | 1584 ++ vendor/flac/include/FLAC/stream_encoder.h | 1837 ++ vendor/flac/include/Makefile.am | 23 + vendor/flac/include/share/Makefile.am | 17 + vendor/flac/include/share/alloc.h | 318 + vendor/flac/include/share/compat.h | 240 + vendor/flac/include/share/endswap.h | 84 + vendor/flac/include/share/getopt.h | 184 + vendor/flac/include/share/grabbag.h | 30 + vendor/flac/include/share/grabbag/Makefile.am | 8 + vendor/flac/include/share/grabbag/cuesheet.h | 43 + vendor/flac/include/share/grabbag/file.h | 65 + vendor/flac/include/share/grabbag/picture.h | 54 + .../flac/include/share/grabbag/replaygain.h | 73 + vendor/flac/include/share/grabbag/seektable.h | 39 + vendor/flac/include/share/macros.h | 45 + vendor/flac/include/share/private.h | 54 + .../flac/include/share/replaygain_analysis.h | 59 + .../flac/include/share/replaygain_synthesis.h | 52 + vendor/flac/include/share/safe_str.h | 71 + vendor/flac/include/share/utf8.h | 25 + vendor/flac/include/share/win_utf8_io.h | 71 + .../flac/include/test_libs_common/Makefile.am | 5 + .../test_libs_common/file_utils_flac.h | 36 + .../include/test_libs_common/metadata_utils.h | 71 + vendor/flac/lib/flac.idb | Bin 0 -> 617472 bytes vendor/flac/lib/flac.lib | Bin 0 -> 2265364 bytes vendor/flac/m4/Makefile.am | 26 + vendor/flac/m4/add_cflags.m4 | 15 + vendor/flac/m4/add_cxxflags.m4 | 16 + vendor/flac/m4/ax_add_fortify_source.m4 | 53 + vendor/flac/m4/ax_check_compile_flag.m4 | 53 + vendor/flac/m4/ax_check_enable_debug.m4 | 124 + vendor/flac/m4/bswap.m4 | 66 + vendor/flac/m4/c_attribute.m4 | 18 + vendor/flac/m4/clang.m4 | 28 + vendor/flac/m4/codeset.m4 | 23 + vendor/flac/m4/endian.m4 | 169 + vendor/flac/m4/gcc_version.m4 | 34 + vendor/flac/m4/iconv.m4 | 268 + vendor/flac/m4/lib-ld.m4 | 119 + vendor/flac/m4/lib-link.m4 | 777 + vendor/flac/m4/lib-prefix.m4 | 224 + vendor/flac/m4/ogg.m4 | 114 + vendor/flac/m4/really_gcc.m4 | 29 + vendor/flac/m4/stack_protect.m4 | 67 + vendor/flac/man/Makefile.am | 34 + vendor/flac/man/flac.md | 760 + vendor/flac/man/metaflac.md | 299 + vendor/flac/microbench/CMakeLists.txt | 17 + vendor/flac/microbench/Makefile.am | 42 + vendor/flac/microbench/benchmark_residual.c | 151 + vendor/flac/microbench/util.c | 205 + vendor/flac/microbench/util.h | 43 + vendor/flac/oss-fuzz/Makefile.am | 104 + vendor/flac/oss-fuzz/Readme.md | 13 + vendor/flac/oss-fuzz/common.h | 2 + vendor/flac/oss-fuzz/decoder.cc | 408 + vendor/flac/oss-fuzz/empty.cc | 0 vendor/flac/oss-fuzz/encoder.cc | 257 + vendor/flac/oss-fuzz/encoder_v2.cc | 352 + vendor/flac/oss-fuzz/fuzzer_decoder.dict | 6 + vendor/flac/oss-fuzz/fuzzer_encoder.dict | 18 + vendor/flac/oss-fuzz/fuzzer_reencoder.dict | 6 + vendor/flac/oss-fuzz/fuzzer_tool_flac.dict | 19 + .../fuzzing/datasource/datasource.hpp | 190 + .../flac/oss-fuzz/fuzzing/datasource/id.hpp | 75 + vendor/flac/oss-fuzz/fuzzing/exception.hpp | 67 + vendor/flac/oss-fuzz/fuzzing/memory.hpp | 96 + vendor/flac/oss-fuzz/fuzzing/types.hpp | 158 + vendor/flac/oss-fuzz/metadata.cc | 526 + vendor/flac/oss-fuzz/reencoder.cc | 304 + .../aiff-with-foreign-metadata-8bps.fuzz | Bin 0 -> 475 bytes .../flac-foreign-metadata-aiff-8bps.fuzz | Bin 0 -> 684 bytes .../flac-foreign-metadata-wav-8bps.fuzz | Bin 0 -> 715 bytes .../replaygain-which-is-not-lossless-ogg.fuzz | Bin 0 -> 15406 bytes .../replaygain-which-is-not-lossless.fuzz | Bin 0 -> 15852 bytes .../wav-with-foreign-metadata-8bps.fuzz | Bin 0 -> 559 bytes vendor/flac/oss-fuzz/seek.cc | 195 + vendor/flac/oss-fuzz/tool_flac.c | 117 + vendor/flac/oss-fuzz/tool_metaflac.c | 136 + vendor/flac/src/CMakeLists.txt | 36 + vendor/flac/src/Makefile.am | 40 + vendor/flac/src/flac/CMakeLists.txt | 25 + vendor/flac/src/flac/Makefile.am | 69 + vendor/flac/src/flac/analyze.c | 252 + vendor/flac/src/flac/analyze.h | 32 + vendor/flac/src/flac/decode.c | 1674 ++ vendor/flac/src/flac/decode.h | 73 + vendor/flac/src/flac/encode.c | 2852 +++ vendor/flac/src/flac/encode.h | 116 + vendor/flac/src/flac/foreign_metadata.c | 952 + vendor/flac/src/flac/foreign_metadata.h | 83 + vendor/flac/src/flac/iffscan.c | 129 + vendor/flac/src/flac/local_string_utils.c | 109 + vendor/flac/src/flac/local_string_utils.h | 28 + vendor/flac/src/flac/main.c | 2442 +++ vendor/flac/src/flac/utils.c | 439 + vendor/flac/src/flac/utils.h | 77 + vendor/flac/src/flac/version.rc | 38 + vendor/flac/src/flac/vorbiscomment.c | 254 + vendor/flac/src/flac/vorbiscomment.h | 27 + vendor/flac/src/libFLAC++/CMakeLists.txt | 41 + vendor/flac/src/libFLAC++/Makefile.am | 68 + vendor/flac/src/libFLAC++/flac++.pc.in | 11 + vendor/flac/src/libFLAC++/libFLAC++.m4 | 114 + vendor/flac/src/libFLAC++/metadata.cpp | 1745 ++ vendor/flac/src/libFLAC++/stream_decoder.cpp | 394 + vendor/flac/src/libFLAC++/stream_encoder.cpp | 519 + vendor/flac/src/libFLAC++/version.rc | 40 + vendor/flac/src/libFLAC/CMakeLists.txt | 126 + vendor/flac/src/libFLAC/Makefile.am | 123 + vendor/flac/src/libFLAC/bitmath.c | 73 + vendor/flac/src/libFLAC/bitreader.c | 1052 + vendor/flac/src/libFLAC/bitwriter.c | 955 + vendor/flac/src/libFLAC/cpu.c | 255 + vendor/flac/src/libFLAC/crc.c | 436 + .../bitreader_read_rice_signed_block.c | 143 + .../lpc_compute_autocorrelation_intrin.c | 14 + .../lpc_compute_autocorrelation_intrin_neon.c | 70 + .../lpc_compute_autocorrelation_intrin_sse2.c | 81 + vendor/flac/src/libFLAC/fixed.c | 667 + vendor/flac/src/libFLAC/fixed_intrin_avx2.c | 343 + vendor/flac/src/libFLAC/fixed_intrin_sse2.c | 194 + vendor/flac/src/libFLAC/fixed_intrin_sse42.c | 223 + vendor/flac/src/libFLAC/fixed_intrin_ssse3.c | 179 + vendor/flac/src/libFLAC/flac.pc.in | 12 + vendor/flac/src/libFLAC/float.c | 302 + vendor/flac/src/libFLAC/format.c | 608 + vendor/flac/src/libFLAC/include/Makefile.am | 32 + .../src/libFLAC/include/private/Makefile.am | 53 + vendor/flac/src/libFLAC/include/private/all.h | 50 + .../src/libFLAC/include/private/bitmath.h | 210 + .../src/libFLAC/include/private/bitreader.h | 101 + .../src/libFLAC/include/private/bitwriter.h | 104 + vendor/flac/src/libFLAC/include/private/cpu.h | 198 + vendor/flac/src/libFLAC/include/private/crc.h | 60 + .../flac/src/libFLAC/include/private/fixed.h | 117 + .../flac/src/libFLAC/include/private/float.h | 95 + .../flac/src/libFLAC/include/private/format.h | 47 + vendor/flac/src/libFLAC/include/private/lpc.h | 238 + .../flac/src/libFLAC/include/private/macros.h | 74 + vendor/flac/src/libFLAC/include/private/md5.h | 50 + .../flac/src/libFLAC/include/private/memory.h | 58 + .../src/libFLAC/include/private/metadata.h | 46 + .../include/private/ogg_decoder_aspect.h | 80 + .../include/private/ogg_encoder_aspect.h | 63 + .../src/libFLAC/include/private/ogg_helper.h | 44 + .../src/libFLAC/include/private/ogg_mapping.h | 64 + .../libFLAC/include/private/stream_encoder.h | 67 + .../include/private/stream_encoder_framing.h | 46 + .../flac/src/libFLAC/include/private/window.h | 74 + .../src/libFLAC/include/protected/Makefile.am | 35 + .../flac/src/libFLAC/include/protected/all.h | 39 + .../include/protected/stream_decoder.h | 60 + .../include/protected/stream_encoder.h | 124 + vendor/flac/src/libFLAC/libFLAC.m4 | 114 + vendor/flac/src/libFLAC/lpc.c | 1629 ++ vendor/flac/src/libFLAC/lpc_intrin_avx2.c | 1122 ++ vendor/flac/src/libFLAC/lpc_intrin_fma.c | 73 + vendor/flac/src/libFLAC/lpc_intrin_neon.c | 1273 ++ vendor/flac/src/libFLAC/lpc_intrin_sse2.c | 966 + vendor/flac/src/libFLAC/lpc_intrin_sse41.c | 950 + vendor/flac/src/libFLAC/md5.c | 517 + vendor/flac/src/libFLAC/memory.c | 219 + vendor/flac/src/libFLAC/metadata_iterators.c | 3554 ++++ vendor/flac/src/libFLAC/metadata_object.c | 2018 ++ vendor/flac/src/libFLAC/ogg_decoder_aspect.c | 251 + vendor/flac/src/libFLAC/ogg_encoder_aspect.c | 228 + vendor/flac/src/libFLAC/ogg_helper.c | 210 + vendor/flac/src/libFLAC/ogg_mapping.c | 48 + vendor/flac/src/libFLAC/stream_decoder.c | 3731 ++++ vendor/flac/src/libFLAC/stream_encoder.c | 4738 +++++ .../flac/src/libFLAC/stream_encoder_framing.c | 594 + .../src/libFLAC/stream_encoder_intrin_avx2.c | 146 + .../src/libFLAC/stream_encoder_intrin_sse2.c | 159 + .../src/libFLAC/stream_encoder_intrin_ssse3.c | 148 + vendor/flac/src/libFLAC/version.rc | 40 + vendor/flac/src/libFLAC/window.c | 308 + vendor/flac/src/metaflac/CMakeLists.txt | 18 + vendor/flac/src/metaflac/Makefile.am | 65 + vendor/flac/src/metaflac/main.c | 75 + vendor/flac/src/metaflac/operations.c | 823 + vendor/flac/src/metaflac/operations.h | 27 + .../flac/src/metaflac/operations_shorthand.h | 26 + .../metaflac/operations_shorthand_cuesheet.c | 226 + .../metaflac/operations_shorthand_picture.c | 184 + .../metaflac/operations_shorthand_seektable.c | 220 + .../operations_shorthand_streaminfo.c | 127 + .../operations_shorthand_vorbiscomment.c | 430 + vendor/flac/src/metaflac/options.c | 1146 ++ vendor/flac/src/metaflac/options.h | 221 + vendor/flac/src/metaflac/usage.c | 349 + vendor/flac/src/metaflac/usage.h | 26 + vendor/flac/src/metaflac/utils.c | 282 + vendor/flac/src/metaflac/utils.h | 47 + vendor/flac/src/metaflac/version.rc | 38 + vendor/flac/src/share/Makefile.am | 73 + vendor/flac/src/share/README | 5 + vendor/flac/src/share/getopt/CMakeLists.txt | 13 + vendor/flac/src/share/getopt/getopt.c | 1053 ++ vendor/flac/src/share/getopt/getopt1.c | 189 + vendor/flac/src/share/grabbag/CMakeLists.txt | 14 + vendor/flac/src/share/grabbag/alloc.c | 48 + vendor/flac/src/share/grabbag/cuesheet.c | 681 + vendor/flac/src/share/grabbag/file.c | 207 + vendor/flac/src/share/grabbag/picture.c | 515 + vendor/flac/src/share/grabbag/replaygain.c | 669 + vendor/flac/src/share/grabbag/seektable.c | 105 + vendor/flac/src/share/grabbag/snprintf.c | 101 + .../share/replaygain_analysis/CMakeLists.txt | 2 + .../replaygain_analysis/replaygain_analysis.c | 575 + .../share/replaygain_synthesis/CMakeLists.txt | 2 + .../replaygain_synthesis.c | 429 + vendor/flac/src/share/utf8/CMakeLists.txt | 8 + vendor/flac/src/share/utf8/charmaps.h | 57 + vendor/flac/src/share/utf8/charset.c | 534 + vendor/flac/src/share/utf8/charset.h | 72 + vendor/flac/src/share/utf8/charset_test.c | 263 + vendor/flac/src/share/utf8/iconvert.c | 257 + vendor/flac/src/share/utf8/iconvert.h | 49 + vendor/flac/src/share/utf8/makemap.c | 81 + vendor/flac/src/share/utf8/utf8.c | 202 + .../flac/src/share/win_utf8_io/win_utf8_io.c | 398 + vendor/flac/src/test_grabbag/CMakeLists.txt | 2 + vendor/flac/src/test_grabbag/Makefile.am | 22 + .../src/test_grabbag/cuesheet/CMakeLists.txt | 5 + .../src/test_grabbag/cuesheet/Makefile.am | 37 + vendor/flac/src/test_grabbag/cuesheet/main.c | 147 + .../src/test_grabbag/picture/CMakeLists.txt | 5 + .../flac/src/test_grabbag/picture/Makefile.am | 37 + vendor/flac/src/test_grabbag/picture/main.c | 222 + vendor/flac/src/test_libFLAC++/CMakeLists.txt | 10 + vendor/flac/src/test_libFLAC++/Makefile.am | 50 + vendor/flac/src/test_libFLAC++/decoders.cpp | 1179 ++ vendor/flac/src/test_libFLAC++/decoders.h | 25 + vendor/flac/src/test_libFLAC++/encoders.cpp | 576 + vendor/flac/src/test_libFLAC++/encoders.h | 25 + vendor/flac/src/test_libFLAC++/main.cpp | 42 + vendor/flac/src/test_libFLAC++/metadata.cpp | 41 + vendor/flac/src/test_libFLAC++/metadata.h | 25 + .../src/test_libFLAC++/metadata_manip.cpp | 2241 +++ .../src/test_libFLAC++/metadata_object.cpp | 2099 ++ vendor/flac/src/test_libFLAC/CMakeLists.txt | 25 + vendor/flac/src/test_libFLAC/Makefile.am | 63 + vendor/flac/src/test_libFLAC/bitreader.c | 355 + vendor/flac/src/test_libFLAC/bitreader.h | 27 + vendor/flac/src/test_libFLAC/bitwriter.c | 688 + vendor/flac/src/test_libFLAC/bitwriter.h | 27 + vendor/flac/src/test_libFLAC/crc.c | 274 + vendor/flac/src/test_libFLAC/crc.h | 26 + vendor/flac/src/test_libFLAC/decoders.c | 1054 ++ vendor/flac/src/test_libFLAC/decoders.h | 27 + vendor/flac/src/test_libFLAC/encoders.c | 530 + vendor/flac/src/test_libFLAC/encoders.h | 27 + vendor/flac/src/test_libFLAC/endswap.c | 111 + vendor/flac/src/test_libFLAC/endswap.h | 26 + vendor/flac/src/test_libFLAC/format.c | 260 + vendor/flac/src/test_libFLAC/format.h | 27 + vendor/flac/src/test_libFLAC/main.c | 64 + vendor/flac/src/test_libFLAC/matrix | 69 + vendor/flac/src/test_libFLAC/md5.c | 221 + vendor/flac/src/test_libFLAC/md5.h | 26 + vendor/flac/src/test_libFLAC/metadata.c | 41 + vendor/flac/src/test_libFLAC/metadata.h | 29 + vendor/flac/src/test_libFLAC/metadata_manip.c | 2146 +++ .../flac/src/test_libFLAC/metadata_object.c | 2291 +++ .../flac/src/test_libs_common/CMakeLists.txt | 4 + vendor/flac/src/test_libs_common/Makefile.am | 29 + vendor/flac/src/test_libs_common/README | 2 + .../src/test_libs_common/file_utils_flac.c | 155 + .../src/test_libs_common/metadata_utils.c | 636 + vendor/flac/src/test_seeking/CMakeLists.txt | 5 + vendor/flac/src/test_seeking/Makefile.am | 39 + vendor/flac/src/test_seeking/main.c | 473 + vendor/flac/src/test_streams/CMakeLists.txt | 2 + vendor/flac/src/test_streams/Makefile.am | 29 + vendor/flac/src/test_streams/main.c | 1398 ++ vendor/flac/src/utils/Makefile.am | 19 + vendor/flac/src/utils/flacdiff/CMakeLists.txt | 5 + vendor/flac/src/utils/flacdiff/Makefile.am | 21 + vendor/flac/src/utils/flacdiff/main.cpp | 230 + .../flac/src/utils/flactimer/CMakeLists.txt | 2 + vendor/flac/src/utils/flactimer/Makefile.am | 21 + vendor/flac/src/utils/flactimer/main.cpp | 175 + vendor/flac/src/utils/loudness/loudness.sci | 115 + vendor/freetype/LICENSE.TXT | 46 + vendor/freetype/README | 107 + vendor/freetype/README.git | 102 + vendor/freetype/build-freetype.lua | 71 + vendor/freetype/builds/amiga/README | 110 + .../builds/amiga/include/config/ftconfig.h | 55 + .../builds/amiga/include/config/ftmodule.h | 158 + vendor/freetype/builds/amiga/makefile.os4 | 297 + vendor/freetype/builds/amiga/smakefile | 299 + .../freetype/builds/amiga/src/base/ftdebug.c | 348 + .../freetype/builds/amiga/src/base/ftsystem.c | 530 + vendor/freetype/builds/ansi/ansi-def.mk | 77 + vendor/freetype/builds/ansi/ansi.mk | 21 + vendor/freetype/builds/atari/ATARI.H | 20 + vendor/freetype/builds/atari/FNames.SIC | 37 + vendor/freetype/builds/atari/FREETYPE.PRJ | 32 + vendor/freetype/builds/atari/README.TXT | 51 + .../freetype/builds/atari/deflinejoiner.awk | 181 + .../freetype/builds/atari/gen-purec-patch.sh | 40 + vendor/freetype/builds/beos/beos-def.mk | 79 + vendor/freetype/builds/beos/beos.mk | 19 + vendor/freetype/builds/beos/detect.mk | 41 + .../freetype/builds/cmake/FindBrotliDec.cmake | 52 + .../freetype/builds/cmake/FindHarfBuzz.cmake | 203 + vendor/freetype/builds/cmake/iOS.cmake | 270 + vendor/freetype/builds/cmake/testbuild.sh | 157 + vendor/freetype/builds/compiler/ansi-cc.mk | 80 + vendor/freetype/builds/compiler/bcc-dev.mk | 86 + vendor/freetype/builds/compiler/bcc.mk | 86 + vendor/freetype/builds/compiler/emx.mk | 77 + vendor/freetype/builds/compiler/gcc-dev.mk | 96 + vendor/freetype/builds/compiler/gcc.mk | 77 + vendor/freetype/builds/compiler/intelc.mk | 85 + vendor/freetype/builds/compiler/unix-lcc.mk | 83 + vendor/freetype/builds/compiler/visualage.mk | 76 + vendor/freetype/builds/compiler/visualc.mk | 82 + vendor/freetype/builds/compiler/watcom.mk | 81 + vendor/freetype/builds/compiler/win-lcc.mk | 81 + vendor/freetype/builds/detect.mk | 128 + vendor/freetype/builds/dos/detect.mk | 152 + vendor/freetype/builds/dos/dos-def.mk | 48 + vendor/freetype/builds/dos/dos-emx.mk | 21 + vendor/freetype/builds/dos/dos-gcc.mk | 21 + vendor/freetype/builds/dos/dos-wat.mk | 20 + vendor/freetype/builds/exports.mk | 80 + vendor/freetype/builds/freetype.mk | 385 + vendor/freetype/builds/link_dos.mk | 42 + vendor/freetype/builds/link_std.mk | 42 + .../builds/mac/FreeType.m68k_cfm.make.txt | 209 + .../builds/mac/FreeType.m68k_far.make.txt | 208 + .../builds/mac/FreeType.ppc_carbon.make.txt | 212 + .../builds/mac/FreeType.ppc_classic.make.txt | 213 + vendor/freetype/builds/mac/README | 393 + vendor/freetype/builds/mac/ascii2mpw.py | 24 + .../freetype/builds/mac/freetype-Info.plist | 36 + vendor/freetype/builds/mac/ftlib.prj.xml | 1194 ++ vendor/freetype/builds/mac/ftmac.c | 1542 ++ .../builds/meson/extract_freetype_version.py | 117 + .../builds/meson/extract_libtool_version.py | 115 + .../builds/meson/generate_reference_docs.py | 89 + .../builds/meson/parse_modules_cfg.py | 177 + .../builds/meson/process_ftoption_h.py | 115 + vendor/freetype/builds/modules.mk | 79 + vendor/freetype/builds/os2/detect.mk | 81 + vendor/freetype/builds/os2/os2-def.mk | 48 + vendor/freetype/builds/os2/os2-dev.mk | 30 + vendor/freetype/builds/os2/os2-gcc.mk | 26 + vendor/freetype/builds/symbian/bld.inf | 72 + vendor/freetype/builds/symbian/freetype.mmp | 146 + vendor/freetype/builds/toplevel.mk | 317 + vendor/freetype/builds/unix/.gitignore | 18 + .../builds/unix/ax_compare_version.m4 | 177 + .../builds/unix/ax_prog_python_version.m4 | 66 + vendor/freetype/builds/unix/ax_pthread.m4 | 522 + vendor/freetype/builds/unix/configure.raw | 1179 ++ vendor/freetype/builds/unix/detect.mk | 99 + .../freetype/builds/unix/freetype-config.in | 211 + vendor/freetype/builds/unix/freetype2.in | 14 + vendor/freetype/builds/unix/freetype2.m4 | 194 + vendor/freetype/builds/unix/ft-munmap.m4 | 32 + vendor/freetype/builds/unix/ftconfig.h.in | 52 + vendor/freetype/builds/unix/ftsystem.c | 436 + vendor/freetype/builds/unix/install.mk | 102 + vendor/freetype/builds/unix/pkg.m4 | 199 + vendor/freetype/builds/unix/unix-cc.in | 130 + vendor/freetype/builds/unix/unix-def.in | 163 + vendor/freetype/builds/unix/unix-dev.mk | 26 + vendor/freetype/builds/unix/unix-lcc.mk | 24 + vendor/freetype/builds/unix/unix.mk | 62 + vendor/freetype/builds/unix/unixddef.mk | 46 + vendor/freetype/builds/vms/apinames_vms.bash | 2 + vendor/freetype/builds/vms/ftconfig.h | 58 + vendor/freetype/builds/vms/ftsystem.c | 328 + vendor/freetype/builds/wince/ftdebug.c | 353 + .../builds/wince/vc2005-ce/freetype.vcproj | 878 + .../builds/wince/vc2005-ce/index.html | 47 + .../builds/wince/vc2008-ce/freetype.vcproj | 3517 ++++ .../builds/wince/vc2008-ce/index.html | 47 + vendor/freetype/builds/windows/.gitignore | 5 + vendor/freetype/builds/windows/detect.mk | 202 + vendor/freetype/builds/windows/ftdebug.c | 698 + vendor/freetype/builds/windows/ftsystem.c | 499 + .../builds/windows/vc2010/freetype.user.props | 68 + .../freetype/builds/windows/vc2010/index.html | 40 + .../builds/windows/visualc/freetype.dsp | 354 + .../builds/windows/visualc/freetype.dsw | 29 + .../builds/windows/visualc/freetype.vcproj | 587 + .../builds/windows/visualc/index.html | 38 + .../builds/windows/visualce/freetype.dsp | 391 + .../builds/windows/visualce/freetype.dsw | 29 + .../builds/windows/visualce/freetype.vcproj | 3706 ++++ .../builds/windows/visualce/index.html | 47 + vendor/freetype/builds/windows/w32-bcc.mk | 28 + vendor/freetype/builds/windows/w32-bccd.mk | 26 + vendor/freetype/builds/windows/w32-dev.mk | 32 + vendor/freetype/builds/windows/w32-gcc.mk | 31 + vendor/freetype/builds/windows/w32-icc.mk | 28 + vendor/freetype/builds/windows/w32-intl.mk | 28 + vendor/freetype/builds/windows/w32-lcc.mk | 24 + vendor/freetype/builds/windows/w32-mingw32.mk | 33 + vendor/freetype/builds/windows/w32-vcc.mk | 28 + vendor/freetype/builds/windows/w32-wat.mk | 28 + vendor/freetype/builds/windows/win32-def.mk | 51 + vendor/freetype/devel/ft2build.h | 41 + vendor/freetype/devel/ftoption.h | 1014 + .../include/freetype/config/ftconfig.h | 51 + .../include/freetype/config/ftheader.h | 836 + .../include/freetype/config/ftmodule.h | 33 + .../include/freetype/config/ftoption.h | 1014 + .../include/freetype/config/ftstdlib.h | 185 + .../include/freetype/config/integer-types.h | 250 + .../include/freetype/config/mac-support.h | 49 + .../include/freetype/config/public-macros.h | 138 + vendor/freetype/include/freetype/freetype.h | 5337 ++++++ vendor/freetype/include/freetype/ftadvanc.h | 188 + vendor/freetype/include/freetype/ftbbox.h | 101 + vendor/freetype/include/freetype/ftbdf.h | 212 + vendor/freetype/include/freetype/ftbitmap.h | 329 + vendor/freetype/include/freetype/ftbzip2.h | 102 + vendor/freetype/include/freetype/ftcache.h | 1087 ++ vendor/freetype/include/freetype/ftchapters.h | 168 + vendor/freetype/include/freetype/ftcid.h | 167 + vendor/freetype/include/freetype/ftcolor.h | 1667 ++ vendor/freetype/include/freetype/ftdriver.h | 1246 ++ vendor/freetype/include/freetype/fterrdef.h | 283 + vendor/freetype/include/freetype/fterrors.h | 296 + vendor/freetype/include/freetype/ftfntfmt.h | 93 + vendor/freetype/include/freetype/ftgasp.h | 143 + vendor/freetype/include/freetype/ftglyph.h | 750 + vendor/freetype/include/freetype/ftgxval.h | 354 + vendor/freetype/include/freetype/ftgzip.h | 151 + vendor/freetype/include/freetype/ftimage.h | 1284 ++ vendor/freetype/include/freetype/ftincrem.h | 348 + vendor/freetype/include/freetype/ftlcdfil.h | 323 + vendor/freetype/include/freetype/ftlist.h | 296 + vendor/freetype/include/freetype/ftlogging.h | 184 + vendor/freetype/include/freetype/ftlzw.h | 100 + vendor/freetype/include/freetype/ftmac.h | 289 + vendor/freetype/include/freetype/ftmm.h | 805 + vendor/freetype/include/freetype/ftmodapi.h | 807 + vendor/freetype/include/freetype/ftmoderr.h | 204 + vendor/freetype/include/freetype/ftotval.h | 206 + vendor/freetype/include/freetype/ftoutln.h | 588 + vendor/freetype/include/freetype/ftparams.h | 218 + vendor/freetype/include/freetype/ftpfr.h | 179 + vendor/freetype/include/freetype/ftrender.h | 244 + vendor/freetype/include/freetype/ftsizes.h | 159 + vendor/freetype/include/freetype/ftsnames.h | 272 + vendor/freetype/include/freetype/ftstroke.h | 773 + vendor/freetype/include/freetype/ftsynth.h | 104 + vendor/freetype/include/freetype/ftsystem.h | 350 + vendor/freetype/include/freetype/fttrigon.h | 350 + vendor/freetype/include/freetype/fttypes.h | 617 + vendor/freetype/include/freetype/ftwinfnt.h | 276 + .../include/freetype/internal/autohint.h | 234 + .../include/freetype/internal/cffotypes.h | 107 + .../include/freetype/internal/cfftypes.h | 416 + .../freetype/internal/compiler-macros.h | 343 + .../include/freetype/internal/ftcalc.h | 581 + .../include/freetype/internal/ftdebug.h | 442 + .../include/freetype/internal/ftdrv.h | 289 + .../include/freetype/internal/ftgloadr.h | 147 + .../include/freetype/internal/fthash.h | 135 + .../include/freetype/internal/ftmemory.h | 398 + .../include/freetype/internal/ftmmtypes.h | 91 + .../include/freetype/internal/ftobjs.h | 1238 ++ .../include/freetype/internal/ftpsprop.h | 47 + .../include/freetype/internal/ftrfork.h | 245 + .../include/freetype/internal/ftserv.h | 495 + .../include/freetype/internal/ftstream.h | 570 + .../include/freetype/internal/fttrace.h | 172 + .../include/freetype/internal/ftvalid.h | 160 + .../include/freetype/internal/psaux.h | 1434 ++ .../include/freetype/internal/pshints.h | 699 + .../freetype/internal/services/svbdf.h | 66 + .../freetype/internal/services/svcfftl.h | 90 + .../freetype/internal/services/svcid.h | 69 + .../freetype/internal/services/svfntfmt.h | 55 + .../freetype/internal/services/svgldict.h | 72 + .../freetype/internal/services/svgxval.h | 72 + .../freetype/internal/services/svkern.h | 51 + .../freetype/internal/services/svmetric.h | 131 + .../include/freetype/internal/services/svmm.h | 214 + .../freetype/internal/services/svotval.h | 55 + .../freetype/internal/services/svpfr.h | 65 + .../freetype/internal/services/svpostnm.h | 65 + .../freetype/internal/services/svprop.h | 66 + .../freetype/internal/services/svpscmap.h | 145 + .../freetype/internal/services/svpsinfo.h | 86 + .../freetype/internal/services/svsfnt.h | 88 + .../freetype/internal/services/svttcmap.h | 90 + .../freetype/internal/services/svtteng.h | 53 + .../freetype/internal/services/svttglyf.h | 56 + .../freetype/internal/services/svwinfnt.h | 50 + .../freetype/include/freetype/internal/sfnt.h | 1092 ++ .../include/freetype/internal/svginterface.h | 46 + .../include/freetype/internal/t1types.h | 259 + .../include/freetype/internal/tttypes.h | 1741 ++ .../include/freetype/internal/wofftypes.h | 312 + vendor/freetype/include/freetype/otsvg.h | 336 + vendor/freetype/include/freetype/t1tables.h | 793 + vendor/freetype/include/freetype/ttnameid.h | 1235 ++ vendor/freetype/include/freetype/tttables.h | 855 + vendor/freetype/include/freetype/tttags.h | 124 + vendor/freetype/include/ft2build.h | 42 + vendor/freetype/lib/freetype.idb | Bin 0 -> 855040 bytes vendor/freetype/lib/freetype.lib | Bin 0 -> 4589898 bytes vendor/freetype/objs/.gitignore | 3 + vendor/freetype/objs/README | 2 + vendor/freetype/src/autofit/afblue.c | 779 + vendor/freetype/src/autofit/afblue.cin | 39 + vendor/freetype/src/autofit/afblue.dat | 1121 ++ vendor/freetype/src/autofit/afblue.h | 429 + vendor/freetype/src/autofit/afblue.hin | 146 + vendor/freetype/src/autofit/afcjk.c | 2383 +++ vendor/freetype/src/autofit/afcjk.h | 141 + vendor/freetype/src/autofit/afcover.h | 105 + vendor/freetype/src/autofit/afdummy.c | 77 + vendor/freetype/src/autofit/afdummy.h | 40 + vendor/freetype/src/autofit/aferrors.h | 42 + vendor/freetype/src/autofit/afglobal.c | 513 + vendor/freetype/src/autofit/afglobal.h | 173 + vendor/freetype/src/autofit/afhints.c | 1796 ++ vendor/freetype/src/autofit/afhints.h | 467 + vendor/freetype/src/autofit/afindic.c | 157 + vendor/freetype/src/autofit/afindic.h | 41 + vendor/freetype/src/autofit/aflatin.c | 3644 ++++ vendor/freetype/src/autofit/aflatin.h | 194 + vendor/freetype/src/autofit/afloader.c | 706 + vendor/freetype/src/autofit/afloader.h | 91 + vendor/freetype/src/autofit/afmodule.c | 527 + vendor/freetype/src/autofit/afmodule.h | 55 + vendor/freetype/src/autofit/afranges.c | 1072 ++ vendor/freetype/src/autofit/afranges.h | 47 + vendor/freetype/src/autofit/afscript.h | 408 + vendor/freetype/src/autofit/afshaper.c | 690 + vendor/freetype/src/autofit/afshaper.h | 71 + vendor/freetype/src/autofit/afstyles.h | 487 + vendor/freetype/src/autofit/aftypes.h | 511 + vendor/freetype/src/autofit/afws-decl.h | 33 + vendor/freetype/src/autofit/afws-iter.h | 31 + vendor/freetype/src/autofit/autofit.c | 35 + vendor/freetype/src/autofit/ft-hb.c | 115 + vendor/freetype/src/autofit/ft-hb.h | 48 + vendor/freetype/src/autofit/module.mk | 23 + vendor/freetype/src/autofit/rules.mk | 88 + vendor/freetype/src/base/ftadvanc.c | 174 + vendor/freetype/src/base/ftbase.c | 41 + vendor/freetype/src/base/ftbase.h | 82 + vendor/freetype/src/base/ftbbox.c | 542 + vendor/freetype/src/base/ftbdf.c | 90 + vendor/freetype/src/base/ftbitmap.c | 1144 ++ vendor/freetype/src/base/ftcalc.c | 1127 ++ vendor/freetype/src/base/ftcid.c | 117 + vendor/freetype/src/base/ftcolor.c | 156 + vendor/freetype/src/base/ftdbgmem.c | 971 + vendor/freetype/src/base/ftdebug.c | 644 + vendor/freetype/src/base/fterrors.c | 45 + vendor/freetype/src/base/ftfntfmt.c | 54 + vendor/freetype/src/base/ftfstype.c | 61 + vendor/freetype/src/base/ftgasp.c | 60 + vendor/freetype/src/base/ftgloadr.c | 392 + vendor/freetype/src/base/ftglyph.c | 911 + vendor/freetype/src/base/ftgxval.c | 141 + vendor/freetype/src/base/fthash.c | 338 + vendor/freetype/src/base/ftinit.c | 263 + vendor/freetype/src/base/ftlcdfil.c | 437 + vendor/freetype/src/base/ftmac.c | 1090 ++ vendor/freetype/src/base/ftmm.c | 704 + vendor/freetype/src/base/ftobjs.c | 5914 ++++++ vendor/freetype/src/base/ftotval.c | 90 + vendor/freetype/src/base/ftoutln.c | 1118 ++ vendor/freetype/src/base/ftpatent.c | 50 + vendor/freetype/src/base/ftpfr.c | 152 + vendor/freetype/src/base/ftpsprop.c | 284 + vendor/freetype/src/base/ftrfork.c | 934 + vendor/freetype/src/base/ftsnames.c | 185 + vendor/freetype/src/base/ftstream.c | 872 + vendor/freetype/src/base/ftstroke.c | 2403 +++ vendor/freetype/src/base/ftsynth.c | 180 + vendor/freetype/src/base/ftsystem.c | 338 + vendor/freetype/src/base/fttrigon.c | 517 + vendor/freetype/src/base/fttype1.c | 126 + vendor/freetype/src/base/ftutil.c | 442 + vendor/freetype/src/base/ftver.rc | 61 + vendor/freetype/src/base/ftwinfnt.c | 52 + vendor/freetype/src/base/md5.c | 291 + vendor/freetype/src/base/md5.h | 45 + vendor/freetype/src/base/rules.mk | 108 + vendor/freetype/src/bdf/README | 152 + vendor/freetype/src/bdf/bdf.c | 34 + vendor/freetype/src/bdf/bdf.h | 253 + vendor/freetype/src/bdf/bdfdrivr.c | 1013 + vendor/freetype/src/bdf/bdfdrivr.h | 72 + vendor/freetype/src/bdf/bdferror.h | 45 + vendor/freetype/src/bdf/bdflib.c | 2387 +++ vendor/freetype/src/bdf/module.mk | 34 + vendor/freetype/src/bdf/rules.mk | 84 + vendor/freetype/src/bzip2/ftbzip2.c | 535 + vendor/freetype/src/bzip2/rules.mk | 64 + vendor/freetype/src/cache/ftcache.c | 31 + vendor/freetype/src/cache/ftcbasic.c | 638 + vendor/freetype/src/cache/ftccache.c | 599 + vendor/freetype/src/cache/ftccache.h | 355 + vendor/freetype/src/cache/ftccback.h | 93 + vendor/freetype/src/cache/ftccmap.c | 323 + vendor/freetype/src/cache/ftcerror.h | 42 + vendor/freetype/src/cache/ftcglyph.c | 204 + vendor/freetype/src/cache/ftcglyph.h | 315 + vendor/freetype/src/cache/ftcimage.c | 164 + vendor/freetype/src/cache/ftcimage.h | 106 + vendor/freetype/src/cache/ftcmanag.c | 696 + vendor/freetype/src/cache/ftcmanag.h | 175 + vendor/freetype/src/cache/ftcmru.c | 352 + vendor/freetype/src/cache/ftcmru.h | 248 + vendor/freetype/src/cache/ftcsbits.c | 414 + vendor/freetype/src/cache/ftcsbits.h | 91 + vendor/freetype/src/cache/rules.mk | 85 + vendor/freetype/src/cff/cff.c | 28 + vendor/freetype/src/cff/cffcmap.c | 230 + vendor/freetype/src/cff/cffcmap.h | 67 + vendor/freetype/src/cff/cffdrivr.c | 1263 ++ vendor/freetype/src/cff/cffdrivr.h | 35 + vendor/freetype/src/cff/cfferrs.h | 42 + vendor/freetype/src/cff/cffgload.c | 762 + vendor/freetype/src/cff/cffgload.h | 62 + vendor/freetype/src/cff/cffload.c | 2579 +++ vendor/freetype/src/cff/cffload.h | 124 + vendor/freetype/src/cff/cffobjs.c | 1204 ++ vendor/freetype/src/cff/cffobjs.h | 84 + vendor/freetype/src/cff/cffparse.c | 1513 ++ vendor/freetype/src/cff/cffparse.h | 143 + vendor/freetype/src/cff/cfftoken.h | 150 + vendor/freetype/src/cff/module.mk | 23 + vendor/freetype/src/cff/rules.mk | 75 + vendor/freetype/src/cid/ciderrs.h | 41 + vendor/freetype/src/cid/cidgload.c | 618 + vendor/freetype/src/cid/cidgload.h | 58 + vendor/freetype/src/cid/cidload.c | 950 + vendor/freetype/src/cid/cidload.h | 52 + vendor/freetype/src/cid/cidobjs.c | 543 + vendor/freetype/src/cid/cidobjs.h | 154 + vendor/freetype/src/cid/cidparse.c | 286 + vendor/freetype/src/cid/cidparse.h | 130 + vendor/freetype/src/cid/cidriver.c | 274 + vendor/freetype/src/cid/cidriver.h | 36 + vendor/freetype/src/cid/cidtoken.h | 115 + vendor/freetype/src/cid/module.mk | 23 + vendor/freetype/src/cid/rules.mk | 73 + vendor/freetype/src/cid/type1cid.c | 28 + vendor/freetype/src/dlg/dlgwrap.c | 32 + vendor/freetype/src/dlg/rules.mk | 70 + vendor/freetype/src/gxvalid/README | 532 + vendor/freetype/src/gxvalid/gxvalid.c | 46 + vendor/freetype/src/gxvalid/gxvalid.h | 107 + vendor/freetype/src/gxvalid/gxvbsln.c | 334 + vendor/freetype/src/gxvalid/gxvcommn.c | 1747 ++ vendor/freetype/src/gxvalid/gxvcommn.h | 584 + vendor/freetype/src/gxvalid/gxverror.h | 51 + vendor/freetype/src/gxvalid/gxvfeat.c | 339 + vendor/freetype/src/gxvalid/gxvfeat.h | 173 + vendor/freetype/src/gxvalid/gxvfgen.c | 484 + vendor/freetype/src/gxvalid/gxvjust.c | 721 + vendor/freetype/src/gxvalid/gxvkern.c | 920 + vendor/freetype/src/gxvalid/gxvlcar.c | 224 + vendor/freetype/src/gxvalid/gxvmod.c | 288 + vendor/freetype/src/gxvalid/gxvmod.h | 46 + vendor/freetype/src/gxvalid/gxvmort.c | 301 + vendor/freetype/src/gxvalid/gxvmort.h | 99 + vendor/freetype/src/gxvalid/gxvmort0.c | 152 + vendor/freetype/src/gxvalid/gxvmort1.c | 260 + vendor/freetype/src/gxvalid/gxvmort2.c | 312 + vendor/freetype/src/gxvalid/gxvmort4.c | 126 + vendor/freetype/src/gxvalid/gxvmort5.c | 234 + vendor/freetype/src/gxvalid/gxvmorx.c | 199 + vendor/freetype/src/gxvalid/gxvmorx.h | 73 + vendor/freetype/src/gxvalid/gxvmorx0.c | 112 + vendor/freetype/src/gxvalid/gxvmorx1.c | 278 + vendor/freetype/src/gxvalid/gxvmorx2.c | 331 + vendor/freetype/src/gxvalid/gxvmorx4.c | 56 + vendor/freetype/src/gxvalid/gxvmorx5.c | 226 + vendor/freetype/src/gxvalid/gxvopbd.c | 218 + vendor/freetype/src/gxvalid/gxvprop.c | 330 + vendor/freetype/src/gxvalid/gxvtrak.c | 288 + vendor/freetype/src/gxvalid/module.mk | 23 + vendor/freetype/src/gxvalid/rules.mk | 98 + vendor/freetype/src/gzip/README.freetype | 23 + vendor/freetype/src/gzip/adler32.c | 192 + vendor/freetype/src/gzip/crc32.c | 1135 ++ vendor/freetype/src/gzip/crc32.h | 9446 +++++++++ vendor/freetype/src/gzip/ftgzip.c | 805 + vendor/freetype/src/gzip/ftzconf.h | 547 + vendor/freetype/src/gzip/gzguts.h | 219 + vendor/freetype/src/gzip/inffast.c | 323 + vendor/freetype/src/gzip/inffast.h | 11 + vendor/freetype/src/gzip/inffixed.h | 94 + vendor/freetype/src/gzip/inflate.c | 1605 ++ vendor/freetype/src/gzip/inflate.h | 131 + vendor/freetype/src/gzip/inftrees.c | 304 + vendor/freetype/src/gzip/inftrees.h | 67 + .../src/gzip/patches/freetype-zlib.diff | 469 + vendor/freetype/src/gzip/rules.mk | 81 + vendor/freetype/src/gzip/zlib.h | 1971 ++ vendor/freetype/src/gzip/zutil.c | 334 + vendor/freetype/src/gzip/zutil.h | 281 + vendor/freetype/src/lzw/ftlzw.c | 415 + vendor/freetype/src/lzw/ftzopen.c | 429 + vendor/freetype/src/lzw/ftzopen.h | 174 + vendor/freetype/src/lzw/rules.mk | 72 + vendor/freetype/src/otvalid/module.mk | 23 + vendor/freetype/src/otvalid/otvalid.c | 31 + vendor/freetype/src/otvalid/otvalid.h | 77 + vendor/freetype/src/otvalid/otvbase.c | 345 + vendor/freetype/src/otvalid/otvcommn.c | 1099 ++ vendor/freetype/src/otvalid/otvcommn.h | 468 + vendor/freetype/src/otvalid/otverror.h | 42 + vendor/freetype/src/otvalid/otvgdef.c | 303 + vendor/freetype/src/otvalid/otvgpos.c | 1051 + vendor/freetype/src/otvalid/otvgpos.h | 36 + vendor/freetype/src/otvalid/otvgsub.c | 627 + vendor/freetype/src/otvalid/otvjstf.c | 259 + vendor/freetype/src/otvalid/otvmath.c | 453 + vendor/freetype/src/otvalid/otvmod.c | 281 + vendor/freetype/src/otvalid/otvmod.h | 38 + vendor/freetype/src/otvalid/rules.mk | 81 + vendor/freetype/src/pcf/README | 96 + vendor/freetype/src/pcf/module.mk | 34 + vendor/freetype/src/pcf/pcf.c | 35 + vendor/freetype/src/pcf/pcf.h | 251 + vendor/freetype/src/pcf/pcfdrivr.c | 836 + vendor/freetype/src/pcf/pcfdrivr.h | 44 + vendor/freetype/src/pcf/pcferror.h | 41 + vendor/freetype/src/pcf/pcfread.c | 1731 ++ vendor/freetype/src/pcf/pcfread.h | 44 + vendor/freetype/src/pcf/pcfutil.c | 119 + vendor/freetype/src/pcf/pcfutil.h | 55 + vendor/freetype/src/pcf/rules.mk | 82 + vendor/freetype/src/pfr/module.mk | 23 + vendor/freetype/src/pfr/pfr.c | 29 + vendor/freetype/src/pfr/pfrcmap.c | 188 + vendor/freetype/src/pfr/pfrcmap.h | 45 + vendor/freetype/src/pfr/pfrdrivr.c | 212 + vendor/freetype/src/pfr/pfrdrivr.h | 36 + vendor/freetype/src/pfr/pfrerror.h | 41 + vendor/freetype/src/pfr/pfrgload.c | 849 + vendor/freetype/src/pfr/pfrgload.h | 49 + vendor/freetype/src/pfr/pfrload.c | 1062 ++ vendor/freetype/src/pfr/pfrload.h | 123 + vendor/freetype/src/pfr/pfrobjs.c | 603 + vendor/freetype/src/pfr/pfrobjs.h | 96 + vendor/freetype/src/pfr/pfrsbit.c | 813 + vendor/freetype/src/pfr/pfrsbit.h | 37 + vendor/freetype/src/pfr/pfrtypes.h | 331 + vendor/freetype/src/pfr/rules.mk | 76 + vendor/freetype/src/psaux/afmparse.c | 1094 ++ vendor/freetype/src/psaux/afmparse.h | 88 + vendor/freetype/src/psaux/cffdecode.c | 2423 +++ vendor/freetype/src/psaux/cffdecode.h | 63 + vendor/freetype/src/psaux/module.mk | 23 + vendor/freetype/src/psaux/psarrst.c | 240 + vendor/freetype/src/psaux/psarrst.h | 99 + vendor/freetype/src/psaux/psaux.c | 40 + vendor/freetype/src/psaux/psauxerr.h | 42 + vendor/freetype/src/psaux/psauxmod.c | 190 + vendor/freetype/src/psaux/psauxmod.h | 60 + vendor/freetype/src/psaux/psblues.c | 583 + vendor/freetype/src/psaux/psblues.h | 185 + vendor/freetype/src/psaux/psconv.c | 610 + vendor/freetype/src/psaux/psconv.h | 70 + vendor/freetype/src/psaux/pserror.c | 52 + vendor/freetype/src/psaux/pserror.h | 120 + vendor/freetype/src/psaux/psfixed.h | 94 + vendor/freetype/src/psaux/psfont.c | 566 + vendor/freetype/src/psaux/psfont.h | 134 + vendor/freetype/src/psaux/psft.c | 895 + vendor/freetype/src/psaux/psft.h | 167 + vendor/freetype/src/psaux/psglue.h | 144 + vendor/freetype/src/psaux/pshints.c | 1952 ++ vendor/freetype/src/psaux/pshints.h | 288 + vendor/freetype/src/psaux/psintrp.c | 3059 +++ vendor/freetype/src/psaux/psintrp.h | 83 + vendor/freetype/src/psaux/psobjs.c | 2562 +++ vendor/freetype/src/psaux/psobjs.h | 312 + vendor/freetype/src/psaux/psread.c | 112 + vendor/freetype/src/psaux/psread.h | 68 + vendor/freetype/src/psaux/psstack.c | 329 + vendor/freetype/src/psaux/psstack.h | 122 + vendor/freetype/src/psaux/pstypes.h | 77 + vendor/freetype/src/psaux/rules.mk | 89 + vendor/freetype/src/psaux/t1cmap.c | 393 + vendor/freetype/src/psaux/t1cmap.h | 104 + vendor/freetype/src/psaux/t1decode.c | 2159 +++ vendor/freetype/src/psaux/t1decode.h | 73 + vendor/freetype/src/pshinter/module.mk | 23 + vendor/freetype/src/pshinter/pshalgo.c | 2191 +++ vendor/freetype/src/pshinter/pshalgo.h | 233 + vendor/freetype/src/pshinter/pshglob.c | 795 + vendor/freetype/src/pshinter/pshglob.h | 196 + vendor/freetype/src/pshinter/pshinter.c | 27 + vendor/freetype/src/pshinter/pshmod.c | 125 + vendor/freetype/src/pshinter/pshmod.h | 38 + vendor/freetype/src/pshinter/pshnterr.h | 41 + vendor/freetype/src/pshinter/pshrec.c | 1224 ++ vendor/freetype/src/pshinter/pshrec.h | 171 + vendor/freetype/src/pshinter/rules.mk | 75 + vendor/freetype/src/psnames/module.mk | 23 + vendor/freetype/src/psnames/psmodule.c | 621 + vendor/freetype/src/psnames/psmodule.h | 37 + vendor/freetype/src/psnames/psnamerr.h | 42 + vendor/freetype/src/psnames/psnames.c | 24 + vendor/freetype/src/psnames/pstables.h | 4238 +++++ vendor/freetype/src/psnames/rules.mk | 73 + vendor/freetype/src/raster/ftmisc.h | 139 + vendor/freetype/src/raster/ftraster.c | 3294 ++++ vendor/freetype/src/raster/ftraster.h | 47 + vendor/freetype/src/raster/ftrend1.c | 209 + vendor/freetype/src/raster/ftrend1.h | 37 + vendor/freetype/src/raster/module.mk | 23 + vendor/freetype/src/raster/raster.c | 25 + vendor/freetype/src/raster/rasterrs.h | 42 + vendor/freetype/src/raster/rules.mk | 72 + vendor/freetype/src/sdf/ftbsdf.c | 1350 ++ vendor/freetype/src/sdf/ftsdf.c | 3932 ++++ vendor/freetype/src/sdf/ftsdf.h | 97 + vendor/freetype/src/sdf/ftsdfcommon.c | 147 + vendor/freetype/src/sdf/ftsdfcommon.h | 141 + vendor/freetype/src/sdf/ftsdferrs.h | 37 + vendor/freetype/src/sdf/ftsdfrend.c | 603 + vendor/freetype/src/sdf/ftsdfrend.h | 118 + vendor/freetype/src/sdf/module.mk | 29 + vendor/freetype/src/sdf/rules.mk | 78 + vendor/freetype/src/sdf/sdf.c | 29 + vendor/freetype/src/sfnt/module.mk | 23 + vendor/freetype/src/sfnt/pngshim.c | 462 + vendor/freetype/src/sfnt/pngshim.h | 50 + vendor/freetype/src/sfnt/rules.mk | 86 + vendor/freetype/src/sfnt/sfdriver.c | 1369 ++ vendor/freetype/src/sfnt/sfdriver.h | 35 + vendor/freetype/src/sfnt/sferrors.h | 41 + vendor/freetype/src/sfnt/sfnt.c | 40 + vendor/freetype/src/sfnt/sfobjs.c | 1535 ++ vendor/freetype/src/sfnt/sfobjs.h | 58 + vendor/freetype/src/sfnt/sfwoff.c | 434 + vendor/freetype/src/sfnt/sfwoff.h | 43 + vendor/freetype/src/sfnt/sfwoff2.c | 2392 +++ vendor/freetype/src/sfnt/sfwoff2.h | 78 + vendor/freetype/src/sfnt/ttbdf.c | 257 + vendor/freetype/src/sfnt/ttbdf.h | 49 + vendor/freetype/src/sfnt/ttcmap.c | 3902 ++++ vendor/freetype/src/sfnt/ttcmap.h | 126 + vendor/freetype/src/sfnt/ttcmapc.h | 56 + vendor/freetype/src/sfnt/ttcolr.c | 1921 ++ vendor/freetype/src/sfnt/ttcolr.h | 83 + vendor/freetype/src/sfnt/ttcpal.c | 310 + vendor/freetype/src/sfnt/ttcpal.h | 48 + vendor/freetype/src/sfnt/ttkern.c | 317 + vendor/freetype/src/sfnt/ttkern.h | 51 + vendor/freetype/src/sfnt/ttload.c | 1496 ++ vendor/freetype/src/sfnt/ttload.h | 111 + vendor/freetype/src/sfnt/ttmtx.c | 338 + vendor/freetype/src/sfnt/ttmtx.h | 54 + vendor/freetype/src/sfnt/ttpost.c | 484 + vendor/freetype/src/sfnt/ttpost.h | 46 + vendor/freetype/src/sfnt/ttsbit.c | 1685 ++ vendor/freetype/src/sfnt/ttsbit.h | 62 + vendor/freetype/src/sfnt/ttsvg.c | 413 + vendor/freetype/src/sfnt/ttsvg.h | 43 + vendor/freetype/src/sfnt/woff2tags.c | 119 + vendor/freetype/src/sfnt/woff2tags.h | 41 + vendor/freetype/src/smooth/ftgrays.c | 2244 +++ vendor/freetype/src/smooth/ftgrays.h | 57 + vendor/freetype/src/smooth/ftsmerrs.h | 42 + vendor/freetype/src/smooth/ftsmooth.c | 605 + vendor/freetype/src/smooth/ftsmooth.h | 37 + vendor/freetype/src/smooth/module.mk | 23 + vendor/freetype/src/smooth/rules.mk | 73 + vendor/freetype/src/smooth/smooth.c | 25 + vendor/freetype/src/svg/ftsvg.c | 355 + vendor/freetype/src/svg/ftsvg.h | 35 + vendor/freetype/src/svg/module.mk | 23 + vendor/freetype/src/svg/rules.mk | 70 + vendor/freetype/src/svg/svg.c | 24 + vendor/freetype/src/svg/svgtypes.h | 42 + vendor/freetype/src/tools/afblue.pl | 551 + vendor/freetype/src/tools/apinames.c | 556 + vendor/freetype/src/tools/chktrcmp.py | 119 + vendor/freetype/src/tools/cordic.py | 32 + vendor/freetype/src/tools/ftrandom/README | 69 + vendor/freetype/src/tools/ftrandom/ftrandom.c | 720 + vendor/freetype/src/tools/glnames.py | 5533 ++++++ .../src/tools/make_distribution_archives.py | 208 + vendor/freetype/src/tools/no-copyright | 66 + vendor/freetype/src/tools/test_afm.c | 156 + vendor/freetype/src/tools/test_bbox.c | 187 + vendor/freetype/src/tools/test_trig.c | 257 + vendor/freetype/src/tools/update-copyright | 14 + .../freetype/src/tools/update-copyright-year | 157 + .../freetype/src/tools/vms_shorten_symbol.c | 250 + vendor/freetype/src/truetype/module.mk | 23 + vendor/freetype/src/truetype/rules.mk | 75 + vendor/freetype/src/truetype/truetype.c | 29 + vendor/freetype/src/truetype/ttdriver.c | 691 + vendor/freetype/src/truetype/ttdriver.h | 35 + vendor/freetype/src/truetype/tterrors.h | 42 + vendor/freetype/src/truetype/ttgload.c | 2743 +++ vendor/freetype/src/truetype/ttgload.h | 61 + vendor/freetype/src/truetype/ttgxvar.c | 4661 +++++ vendor/freetype/src/truetype/ttgxvar.h | 453 + vendor/freetype/src/truetype/ttinterp.c | 7753 ++++++++ vendor/freetype/src/truetype/ttinterp.h | 465 + vendor/freetype/src/truetype/ttobjs.c | 1539 ++ vendor/freetype/src/truetype/ttobjs.h | 426 + vendor/freetype/src/truetype/ttpload.c | 665 + vendor/freetype/src/truetype/ttpload.h | 74 + vendor/freetype/src/type1/module.mk | 23 + vendor/freetype/src/type1/rules.mk | 76 + vendor/freetype/src/type1/t1afm.c | 413 + vendor/freetype/src/type1/t1afm.h | 53 + vendor/freetype/src/type1/t1driver.c | 813 + vendor/freetype/src/type1/t1driver.h | 35 + vendor/freetype/src/type1/t1errors.h | 41 + vendor/freetype/src/type1/t1gload.c | 606 + vendor/freetype/src/type1/t1gload.h | 52 + vendor/freetype/src/type1/t1load.c | 2761 +++ vendor/freetype/src/type1/t1load.h | 126 + vendor/freetype/src/type1/t1objs.c | 655 + vendor/freetype/src/type1/t1objs.h | 160 + vendor/freetype/src/type1/t1parse.c | 487 + vendor/freetype/src/type1/t1parse.h | 137 + vendor/freetype/src/type1/t1tokens.h | 143 + vendor/freetype/src/type1/type1.c | 29 + vendor/freetype/src/type42/module.mk | 23 + vendor/freetype/src/type42/rules.mk | 73 + vendor/freetype/src/type42/t42drivr.c | 248 + vendor/freetype/src/type42/t42drivr.h | 36 + vendor/freetype/src/type42/t42error.h | 41 + vendor/freetype/src/type42/t42objs.c | 698 + vendor/freetype/src/type42/t42objs.h | 123 + vendor/freetype/src/type42/t42parse.c | 1355 ++ vendor/freetype/src/type42/t42parse.h | 91 + vendor/freetype/src/type42/t42types.h | 56 + vendor/freetype/src/type42/type42.c | 26 + vendor/freetype/src/winfonts/fnterrs.h | 42 + vendor/freetype/src/winfonts/module.mk | 23 + vendor/freetype/src/winfonts/rules.mk | 68 + vendor/freetype/src/winfonts/winfnt.c | 1219 ++ vendor/freetype/src/winfonts/winfnt.h | 164 + vendor/freetype/subprojects/harfbuzz.wrap | 12 + vendor/freetype/subprojects/libpng.wrap | 13 + vendor/freetype/subprojects/zlib.wrap | 13 + vendor/ogg/AUTHORS | 7 + vendor/ogg/COPYING | 28 + vendor/ogg/README.md | 160 + vendor/ogg/build-ogg.lua | 20 + vendor/ogg/include/Makefile.am | 3 + vendor/ogg/include/ogg/Makefile.am | 6 + vendor/ogg/include/ogg/config_types.h.in | 26 + vendor/ogg/include/ogg/ogg.h | 209 + vendor/ogg/include/ogg/os_types.h | 158 + vendor/ogg/lib/ogg.idb | Bin 0 -> 68608 bytes vendor/ogg/lib/ogg.lib | Bin 0 -> 107644 bytes vendor/ogg/libogg.spec.in | 109 + vendor/ogg/ogg-uninstalled.pc.in | 14 + vendor/ogg/ogg.m4 | 116 + vendor/ogg/ogg.pc.in | 14 + vendor/ogg/releases.sha2 | 40 + vendor/ogg/src/Makefile.am | 28 + vendor/ogg/src/bitwise.c | 1087 ++ vendor/ogg/src/crctable.h | 278 + vendor/ogg/src/framing.c | 2114 +++ vendor/vorbis/AUTHORS | 3 + vendor/vorbis/COPYING | 28 + vendor/vorbis/README.md | 147 + vendor/vorbis/build-vorbis.lua | 64 + vendor/vorbis/contrib/oss-fuzz/build.sh | 23 + .../vorbis/contrib/oss-fuzz/decode_fuzzer.cc | 48 + vendor/vorbis/debian/changelog | 208 + vendor/vorbis/debian/control | 60 + vendor/vorbis/debian/copyright | 38 + vendor/vorbis/debian/libvorbis-dev.docs | 1 + vendor/vorbis/debian/libvorbis-dev.examples | 2 + vendor/vorbis/debian/libvorbis-dev.install | 16 + vendor/vorbis/debian/libvorbis0a.install | 1 + vendor/vorbis/debian/libvorbisenc2.install | 1 + vendor/vorbis/debian/libvorbisfile3.install | 1 + vendor/vorbis/debian/rules | 154 + vendor/vorbis/debian/watch | 3 + vendor/vorbis/include/Makefile.am | 3 + vendor/vorbis/include/vorbis/Makefile.am | 7 + vendor/vorbis/include/vorbis/codec.h | 242 + vendor/vorbis/include/vorbis/vorbisenc.h | 435 + vendor/vorbis/include/vorbis/vorbisfile.h | 205 + vendor/vorbis/lib/Makefile.am | 63 + vendor/vorbis/lib/analysis.c | 119 + vendor/vorbis/lib/backends.h | 143 + vendor/vorbis/lib/barkmel.c | 63 + vendor/vorbis/lib/bitrate.c | 252 + vendor/vorbis/lib/bitrate.h | 58 + vendor/vorbis/lib/block.c | 1046 + vendor/vorbis/lib/books/Makefile.am | 3 + vendor/vorbis/lib/books/coupled/Makefile.am | 3 + .../vorbis/lib/books/coupled/res_books_51.h | 12273 ++++++++++++ .../lib/books/coupled/res_books_stereo.h | 15782 ++++++++++++++++ vendor/vorbis/lib/books/floor/Makefile.am | 3 + vendor/vorbis/lib/books/floor/floor_books.h | 1546 ++ vendor/vorbis/lib/books/uncoupled/Makefile.am | 3 + .../lib/books/uncoupled/res_books_uncoupled.h | 7757 ++++++++ vendor/vorbis/lib/codebook.c | 461 + vendor/vorbis/lib/codebook.h | 117 + vendor/vorbis/lib/codec_internal.h | 166 + vendor/vorbis/lib/envelope.c | 374 + vendor/vorbis/lib/envelope.h | 79 + vendor/vorbis/lib/floor0.c | 223 + vendor/vorbis/lib/floor1.c | 1086 ++ vendor/vorbis/lib/highlevel.h | 57 + vendor/vorbis/lib/info.c | 687 + vendor/vorbis/lib/lookup.c | 93 + vendor/vorbis/lib/lookup.h | 31 + vendor/vorbis/lib/lookup_data.h | 191 + vendor/vorbis/lib/lookups.pl | 141 + vendor/vorbis/lib/lpc.c | 159 + vendor/vorbis/lib/lpc.h | 28 + vendor/vorbis/lib/lsp.c | 454 + vendor/vorbis/lib/lsp.h | 27 + vendor/vorbis/lib/mapping0.c | 808 + vendor/vorbis/lib/masking.h | 784 + vendor/vorbis/lib/mdct.c | 562 + vendor/vorbis/lib/mdct.h | 70 + vendor/vorbis/lib/misc.c | 216 + vendor/vorbis/lib/misc.h | 57 + vendor/vorbis/lib/modes/Makefile.am | 6 + vendor/vorbis/lib/modes/floor_all.h | 259 + vendor/vorbis/lib/modes/psych_11.h | 50 + vendor/vorbis/lib/modes/psych_16.h | 132 + vendor/vorbis/lib/modes/psych_44.h | 641 + vendor/vorbis/lib/modes/psych_8.h | 100 + vendor/vorbis/lib/modes/residue_16.h | 162 + vendor/vorbis/lib/modes/residue_44.h | 291 + vendor/vorbis/lib/modes/residue_44p51.h | 450 + vendor/vorbis/lib/modes/residue_44u.h | 317 + vendor/vorbis/lib/modes/residue_8.h | 108 + vendor/vorbis/lib/modes/setup_11.h | 142 + vendor/vorbis/lib/modes/setup_16.h | 152 + vendor/vorbis/lib/modes/setup_22.h | 127 + vendor/vorbis/lib/modes/setup_32.h | 131 + vendor/vorbis/lib/modes/setup_44.h | 116 + vendor/vorbis/lib/modes/setup_44p51.h | 73 + vendor/vorbis/lib/modes/setup_44u.h | 73 + vendor/vorbis/lib/modes/setup_8.h | 148 + vendor/vorbis/lib/modes/setup_X.h | 224 + vendor/vorbis/lib/os.h | 189 + vendor/vorbis/lib/psy.c | 1209 ++ vendor/vorbis/lib/psy.h | 153 + vendor/vorbis/lib/psytune.c | 523 + vendor/vorbis/lib/registry.c | 44 + vendor/vorbis/lib/registry.h | 31 + vendor/vorbis/lib/res0.c | 886 + vendor/vorbis/lib/scales.h | 89 + vendor/vorbis/lib/sharedbook.c | 604 + vendor/vorbis/lib/smallft.c | 1254 ++ vendor/vorbis/lib/smallft.h | 33 + vendor/vorbis/lib/synthesis.c | 179 + vendor/vorbis/lib/tone.c | 54 + vendor/vorbis/lib/vorbisenc.c | 1224 ++ vendor/vorbis/lib/vorbisfile.c | 2427 +++ vendor/vorbis/lib/window.c | 2135 +++ vendor/vorbis/lib/window.h | 25 + vendor/vorbis/symbian/bld.inf | 35 + vendor/vorbis/symbian/config.h | 54 + vendor/vorbis/symbian/vorbis.mmp | 43 + vendor/vorbis/test/Makefile.am | 19 + vendor/vorbis/test/test.c | 99 + vendor/vorbis/test/util.c | 52 + vendor/vorbis/test/util.h | 23 + vendor/vorbis/test/write_read.c | 297 + vendor/vorbis/test/write_read.h | 27 + vendor/vorbis/vq/16.vqs | 74 + vendor/vorbis/vq/16u.vqs | 69 + vendor/vorbis/vq/44c-1.vqs | 63 + vendor/vorbis/vq/44c0.vqs | 65 + vendor/vorbis/vq/44c1.vqs | 66 + vendor/vorbis/vq/44c2.vqs | 37 + vendor/vorbis/vq/44c3.vqs | 36 + vendor/vorbis/vq/44c4.vqs | 36 + vendor/vorbis/vq/44c5.vqs | 37 + vendor/vorbis/vq/44c6.vqs | 37 + vendor/vorbis/vq/44c7.vqs | 38 + vendor/vorbis/vq/44c8.vqs | 39 + vendor/vorbis/vq/44c9.vqs | 37 + vendor/vorbis/vq/44p-1.vqs | 49 + vendor/vorbis/vq/44p0.vqs | 49 + vendor/vorbis/vq/44p1.vqs | 49 + vendor/vorbis/vq/44p2.vqs | 52 + vendor/vorbis/vq/44p3.vqs | 52 + vendor/vorbis/vq/44p4.vqs | 52 + vendor/vorbis/vq/44p5.vqs | 52 + vendor/vorbis/vq/44p6.vqs | 52 + vendor/vorbis/vq/44p7.vqs | 52 + vendor/vorbis/vq/44p8.vqs | 52 + vendor/vorbis/vq/44p9.vqs | 52 + vendor/vorbis/vq/44u0.vqs | 33 + vendor/vorbis/vq/44u1.vqs | 33 + vendor/vorbis/vq/44u2.vqs | 32 + vendor/vorbis/vq/44u3.vqs | 33 + vendor/vorbis/vq/44u4.vqs | 33 + vendor/vorbis/vq/44u5.vqs | 35 + vendor/vorbis/vq/44u6.vqs | 35 + vendor/vorbis/vq/44u7.vqs | 34 + vendor/vorbis/vq/44u8.vqs | 35 + vendor/vorbis/vq/44u9.vqs | 36 + vendor/vorbis/vq/8.vqs | 43 + vendor/vorbis/vq/8u.vqs | 41 + vendor/vorbis/vq/Makefile.am | 36 + vendor/vorbis/vq/bookutil.c | 476 + vendor/vorbis/vq/bookutil.h | 42 + vendor/vorbis/vq/distribution.c | 247 + vendor/vorbis/vq/floor_11.vqs | 10 + vendor/vorbis/vq/floor_22.vqs | 27 + vendor/vorbis/vq/floor_44.vqs | 83 + vendor/vorbis/vq/huffbuild.c | 197 + vendor/vorbis/vq/latticebuild.c | 176 + vendor/vorbis/vq/latticetune.c | 163 + vendor/vorbis/vq/localcodebook.h | 120 + vendor/vorbis/vq/make_floor_books.pl | 108 + vendor/vorbis/vq/make_residue_books.pl | 177 + vendor/vorbis/vq/metrics.c | 294 + vendor/vorbis/vq/vqgen.c | 566 + vendor/vorbis/vq/vqgen.h | 84 + 1157 files changed, 441139 insertions(+), 47 deletions(-) create mode 100644 vendor/flac/AUTHORS create mode 100644 vendor/flac/COPYING.FDL create mode 100644 vendor/flac/COPYING.GPL create mode 100644 vendor/flac/COPYING.LGPL create mode 100644 vendor/flac/COPYING.Xiph create mode 100644 vendor/flac/README.md create mode 100644 vendor/flac/build-flac.lua create mode 100644 vendor/flac/include/FLAC++/Makefile.am create mode 100644 vendor/flac/include/FLAC++/all.h create mode 100644 vendor/flac/include/FLAC++/decoder.h create mode 100644 vendor/flac/include/FLAC++/encoder.h create mode 100644 vendor/flac/include/FLAC++/export.h create mode 100644 vendor/flac/include/FLAC++/metadata.h create mode 100644 vendor/flac/include/FLAC/Makefile.am create mode 100644 vendor/flac/include/FLAC/all.h create mode 100644 vendor/flac/include/FLAC/assert.h create mode 100644 vendor/flac/include/FLAC/callback.h create mode 100644 vendor/flac/include/FLAC/export.h create mode 100644 vendor/flac/include/FLAC/format.h create mode 100644 vendor/flac/include/FLAC/metadata.h create mode 100644 vendor/flac/include/FLAC/ordinals.h create mode 100644 vendor/flac/include/FLAC/stream_decoder.h create mode 100644 vendor/flac/include/FLAC/stream_encoder.h create mode 100644 vendor/flac/include/Makefile.am create mode 100644 vendor/flac/include/share/Makefile.am create mode 100644 vendor/flac/include/share/alloc.h create mode 100644 vendor/flac/include/share/compat.h create mode 100644 vendor/flac/include/share/endswap.h create mode 100644 vendor/flac/include/share/getopt.h create mode 100644 vendor/flac/include/share/grabbag.h create mode 100644 vendor/flac/include/share/grabbag/Makefile.am create mode 100644 vendor/flac/include/share/grabbag/cuesheet.h create mode 100644 vendor/flac/include/share/grabbag/file.h create mode 100644 vendor/flac/include/share/grabbag/picture.h create mode 100644 vendor/flac/include/share/grabbag/replaygain.h create mode 100644 vendor/flac/include/share/grabbag/seektable.h create mode 100644 vendor/flac/include/share/macros.h create mode 100644 vendor/flac/include/share/private.h create mode 100644 vendor/flac/include/share/replaygain_analysis.h create mode 100644 vendor/flac/include/share/replaygain_synthesis.h create mode 100644 vendor/flac/include/share/safe_str.h create mode 100644 vendor/flac/include/share/utf8.h create mode 100644 vendor/flac/include/share/win_utf8_io.h create mode 100644 vendor/flac/include/test_libs_common/Makefile.am create mode 100644 vendor/flac/include/test_libs_common/file_utils_flac.h create mode 100644 vendor/flac/include/test_libs_common/metadata_utils.h create mode 100644 vendor/flac/lib/flac.idb create mode 100644 vendor/flac/lib/flac.lib create mode 100644 vendor/flac/m4/Makefile.am create mode 100644 vendor/flac/m4/add_cflags.m4 create mode 100644 vendor/flac/m4/add_cxxflags.m4 create mode 100644 vendor/flac/m4/ax_add_fortify_source.m4 create mode 100644 vendor/flac/m4/ax_check_compile_flag.m4 create mode 100644 vendor/flac/m4/ax_check_enable_debug.m4 create mode 100644 vendor/flac/m4/bswap.m4 create mode 100644 vendor/flac/m4/c_attribute.m4 create mode 100644 vendor/flac/m4/clang.m4 create mode 100644 vendor/flac/m4/codeset.m4 create mode 100644 vendor/flac/m4/endian.m4 create mode 100644 vendor/flac/m4/gcc_version.m4 create mode 100644 vendor/flac/m4/iconv.m4 create mode 100644 vendor/flac/m4/lib-ld.m4 create mode 100644 vendor/flac/m4/lib-link.m4 create mode 100644 vendor/flac/m4/lib-prefix.m4 create mode 100644 vendor/flac/m4/ogg.m4 create mode 100644 vendor/flac/m4/really_gcc.m4 create mode 100644 vendor/flac/m4/stack_protect.m4 create mode 100644 vendor/flac/man/Makefile.am create mode 100644 vendor/flac/man/flac.md create mode 100644 vendor/flac/man/metaflac.md create mode 100644 vendor/flac/microbench/CMakeLists.txt create mode 100644 vendor/flac/microbench/Makefile.am create mode 100644 vendor/flac/microbench/benchmark_residual.c create mode 100644 vendor/flac/microbench/util.c create mode 100644 vendor/flac/microbench/util.h create mode 100644 vendor/flac/oss-fuzz/Makefile.am create mode 100644 vendor/flac/oss-fuzz/Readme.md create mode 100644 vendor/flac/oss-fuzz/common.h create mode 100644 vendor/flac/oss-fuzz/decoder.cc create mode 100644 vendor/flac/oss-fuzz/empty.cc create mode 100644 vendor/flac/oss-fuzz/encoder.cc create mode 100644 vendor/flac/oss-fuzz/encoder_v2.cc create mode 100644 vendor/flac/oss-fuzz/fuzzer_decoder.dict create mode 100644 vendor/flac/oss-fuzz/fuzzer_encoder.dict create mode 100644 vendor/flac/oss-fuzz/fuzzer_reencoder.dict create mode 100644 vendor/flac/oss-fuzz/fuzzer_tool_flac.dict create mode 100644 vendor/flac/oss-fuzz/fuzzing/datasource/datasource.hpp create mode 100644 vendor/flac/oss-fuzz/fuzzing/datasource/id.hpp create mode 100644 vendor/flac/oss-fuzz/fuzzing/exception.hpp create mode 100644 vendor/flac/oss-fuzz/fuzzing/memory.hpp create mode 100644 vendor/flac/oss-fuzz/fuzzing/types.hpp create mode 100644 vendor/flac/oss-fuzz/metadata.cc create mode 100644 vendor/flac/oss-fuzz/reencoder.cc create mode 100644 vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/aiff-with-foreign-metadata-8bps.fuzz create mode 100644 vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/flac-foreign-metadata-aiff-8bps.fuzz create mode 100644 vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/flac-foreign-metadata-wav-8bps.fuzz create mode 100644 vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/replaygain-which-is-not-lossless-ogg.fuzz create mode 100644 vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/replaygain-which-is-not-lossless.fuzz create mode 100644 vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/wav-with-foreign-metadata-8bps.fuzz create mode 100644 vendor/flac/oss-fuzz/seek.cc create mode 100644 vendor/flac/oss-fuzz/tool_flac.c create mode 100644 vendor/flac/oss-fuzz/tool_metaflac.c create mode 100644 vendor/flac/src/CMakeLists.txt create mode 100644 vendor/flac/src/Makefile.am create mode 100644 vendor/flac/src/flac/CMakeLists.txt create mode 100644 vendor/flac/src/flac/Makefile.am create mode 100644 vendor/flac/src/flac/analyze.c create mode 100644 vendor/flac/src/flac/analyze.h create mode 100644 vendor/flac/src/flac/decode.c create mode 100644 vendor/flac/src/flac/decode.h create mode 100644 vendor/flac/src/flac/encode.c create mode 100644 vendor/flac/src/flac/encode.h create mode 100644 vendor/flac/src/flac/foreign_metadata.c create mode 100644 vendor/flac/src/flac/foreign_metadata.h create mode 100644 vendor/flac/src/flac/iffscan.c create mode 100644 vendor/flac/src/flac/local_string_utils.c create mode 100644 vendor/flac/src/flac/local_string_utils.h create mode 100644 vendor/flac/src/flac/main.c create mode 100644 vendor/flac/src/flac/utils.c create mode 100644 vendor/flac/src/flac/utils.h create mode 100644 vendor/flac/src/flac/version.rc create mode 100644 vendor/flac/src/flac/vorbiscomment.c create mode 100644 vendor/flac/src/flac/vorbiscomment.h create mode 100644 vendor/flac/src/libFLAC++/CMakeLists.txt create mode 100644 vendor/flac/src/libFLAC++/Makefile.am create mode 100644 vendor/flac/src/libFLAC++/flac++.pc.in create mode 100644 vendor/flac/src/libFLAC++/libFLAC++.m4 create mode 100644 vendor/flac/src/libFLAC++/metadata.cpp create mode 100644 vendor/flac/src/libFLAC++/stream_decoder.cpp create mode 100644 vendor/flac/src/libFLAC++/stream_encoder.cpp create mode 100644 vendor/flac/src/libFLAC++/version.rc create mode 100644 vendor/flac/src/libFLAC/CMakeLists.txt create mode 100644 vendor/flac/src/libFLAC/Makefile.am create mode 100644 vendor/flac/src/libFLAC/bitmath.c create mode 100644 vendor/flac/src/libFLAC/bitreader.c create mode 100644 vendor/flac/src/libFLAC/bitwriter.c create mode 100644 vendor/flac/src/libFLAC/cpu.c create mode 100644 vendor/flac/src/libFLAC/crc.c create mode 100644 vendor/flac/src/libFLAC/deduplication/bitreader_read_rice_signed_block.c create mode 100644 vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c create mode 100644 vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c create mode 100644 vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c create mode 100644 vendor/flac/src/libFLAC/fixed.c create mode 100644 vendor/flac/src/libFLAC/fixed_intrin_avx2.c create mode 100644 vendor/flac/src/libFLAC/fixed_intrin_sse2.c create mode 100644 vendor/flac/src/libFLAC/fixed_intrin_sse42.c create mode 100644 vendor/flac/src/libFLAC/fixed_intrin_ssse3.c create mode 100644 vendor/flac/src/libFLAC/flac.pc.in create mode 100644 vendor/flac/src/libFLAC/float.c create mode 100644 vendor/flac/src/libFLAC/format.c create mode 100644 vendor/flac/src/libFLAC/include/Makefile.am create mode 100644 vendor/flac/src/libFLAC/include/private/Makefile.am create mode 100644 vendor/flac/src/libFLAC/include/private/all.h create mode 100644 vendor/flac/src/libFLAC/include/private/bitmath.h create mode 100644 vendor/flac/src/libFLAC/include/private/bitreader.h create mode 100644 vendor/flac/src/libFLAC/include/private/bitwriter.h create mode 100644 vendor/flac/src/libFLAC/include/private/cpu.h create mode 100644 vendor/flac/src/libFLAC/include/private/crc.h create mode 100644 vendor/flac/src/libFLAC/include/private/fixed.h create mode 100644 vendor/flac/src/libFLAC/include/private/float.h create mode 100644 vendor/flac/src/libFLAC/include/private/format.h create mode 100644 vendor/flac/src/libFLAC/include/private/lpc.h create mode 100644 vendor/flac/src/libFLAC/include/private/macros.h create mode 100644 vendor/flac/src/libFLAC/include/private/md5.h create mode 100644 vendor/flac/src/libFLAC/include/private/memory.h create mode 100644 vendor/flac/src/libFLAC/include/private/metadata.h create mode 100644 vendor/flac/src/libFLAC/include/private/ogg_decoder_aspect.h create mode 100644 vendor/flac/src/libFLAC/include/private/ogg_encoder_aspect.h create mode 100644 vendor/flac/src/libFLAC/include/private/ogg_helper.h create mode 100644 vendor/flac/src/libFLAC/include/private/ogg_mapping.h create mode 100644 vendor/flac/src/libFLAC/include/private/stream_encoder.h create mode 100644 vendor/flac/src/libFLAC/include/private/stream_encoder_framing.h create mode 100644 vendor/flac/src/libFLAC/include/private/window.h create mode 100644 vendor/flac/src/libFLAC/include/protected/Makefile.am create mode 100644 vendor/flac/src/libFLAC/include/protected/all.h create mode 100644 vendor/flac/src/libFLAC/include/protected/stream_decoder.h create mode 100644 vendor/flac/src/libFLAC/include/protected/stream_encoder.h create mode 100644 vendor/flac/src/libFLAC/libFLAC.m4 create mode 100644 vendor/flac/src/libFLAC/lpc.c create mode 100644 vendor/flac/src/libFLAC/lpc_intrin_avx2.c create mode 100644 vendor/flac/src/libFLAC/lpc_intrin_fma.c create mode 100644 vendor/flac/src/libFLAC/lpc_intrin_neon.c create mode 100644 vendor/flac/src/libFLAC/lpc_intrin_sse2.c create mode 100644 vendor/flac/src/libFLAC/lpc_intrin_sse41.c create mode 100644 vendor/flac/src/libFLAC/md5.c create mode 100644 vendor/flac/src/libFLAC/memory.c create mode 100644 vendor/flac/src/libFLAC/metadata_iterators.c create mode 100644 vendor/flac/src/libFLAC/metadata_object.c create mode 100644 vendor/flac/src/libFLAC/ogg_decoder_aspect.c create mode 100644 vendor/flac/src/libFLAC/ogg_encoder_aspect.c create mode 100644 vendor/flac/src/libFLAC/ogg_helper.c create mode 100644 vendor/flac/src/libFLAC/ogg_mapping.c create mode 100644 vendor/flac/src/libFLAC/stream_decoder.c create mode 100644 vendor/flac/src/libFLAC/stream_encoder.c create mode 100644 vendor/flac/src/libFLAC/stream_encoder_framing.c create mode 100644 vendor/flac/src/libFLAC/stream_encoder_intrin_avx2.c create mode 100644 vendor/flac/src/libFLAC/stream_encoder_intrin_sse2.c create mode 100644 vendor/flac/src/libFLAC/stream_encoder_intrin_ssse3.c create mode 100644 vendor/flac/src/libFLAC/version.rc create mode 100644 vendor/flac/src/libFLAC/window.c create mode 100644 vendor/flac/src/metaflac/CMakeLists.txt create mode 100644 vendor/flac/src/metaflac/Makefile.am create mode 100644 vendor/flac/src/metaflac/main.c create mode 100644 vendor/flac/src/metaflac/operations.c create mode 100644 vendor/flac/src/metaflac/operations.h create mode 100644 vendor/flac/src/metaflac/operations_shorthand.h create mode 100644 vendor/flac/src/metaflac/operations_shorthand_cuesheet.c create mode 100644 vendor/flac/src/metaflac/operations_shorthand_picture.c create mode 100644 vendor/flac/src/metaflac/operations_shorthand_seektable.c create mode 100644 vendor/flac/src/metaflac/operations_shorthand_streaminfo.c create mode 100644 vendor/flac/src/metaflac/operations_shorthand_vorbiscomment.c create mode 100644 vendor/flac/src/metaflac/options.c create mode 100644 vendor/flac/src/metaflac/options.h create mode 100644 vendor/flac/src/metaflac/usage.c create mode 100644 vendor/flac/src/metaflac/usage.h create mode 100644 vendor/flac/src/metaflac/utils.c create mode 100644 vendor/flac/src/metaflac/utils.h create mode 100644 vendor/flac/src/metaflac/version.rc create mode 100644 vendor/flac/src/share/Makefile.am create mode 100644 vendor/flac/src/share/README create mode 100644 vendor/flac/src/share/getopt/CMakeLists.txt create mode 100644 vendor/flac/src/share/getopt/getopt.c create mode 100644 vendor/flac/src/share/getopt/getopt1.c create mode 100644 vendor/flac/src/share/grabbag/CMakeLists.txt create mode 100644 vendor/flac/src/share/grabbag/alloc.c create mode 100644 vendor/flac/src/share/grabbag/cuesheet.c create mode 100644 vendor/flac/src/share/grabbag/file.c create mode 100644 vendor/flac/src/share/grabbag/picture.c create mode 100644 vendor/flac/src/share/grabbag/replaygain.c create mode 100644 vendor/flac/src/share/grabbag/seektable.c create mode 100644 vendor/flac/src/share/grabbag/snprintf.c create mode 100644 vendor/flac/src/share/replaygain_analysis/CMakeLists.txt create mode 100644 vendor/flac/src/share/replaygain_analysis/replaygain_analysis.c create mode 100644 vendor/flac/src/share/replaygain_synthesis/CMakeLists.txt create mode 100644 vendor/flac/src/share/replaygain_synthesis/replaygain_synthesis.c create mode 100644 vendor/flac/src/share/utf8/CMakeLists.txt create mode 100644 vendor/flac/src/share/utf8/charmaps.h create mode 100644 vendor/flac/src/share/utf8/charset.c create mode 100644 vendor/flac/src/share/utf8/charset.h create mode 100644 vendor/flac/src/share/utf8/charset_test.c create mode 100644 vendor/flac/src/share/utf8/iconvert.c create mode 100644 vendor/flac/src/share/utf8/iconvert.h create mode 100644 vendor/flac/src/share/utf8/makemap.c create mode 100644 vendor/flac/src/share/utf8/utf8.c create mode 100644 vendor/flac/src/share/win_utf8_io/win_utf8_io.c create mode 100644 vendor/flac/src/test_grabbag/CMakeLists.txt create mode 100644 vendor/flac/src/test_grabbag/Makefile.am create mode 100644 vendor/flac/src/test_grabbag/cuesheet/CMakeLists.txt create mode 100644 vendor/flac/src/test_grabbag/cuesheet/Makefile.am create mode 100644 vendor/flac/src/test_grabbag/cuesheet/main.c create mode 100644 vendor/flac/src/test_grabbag/picture/CMakeLists.txt create mode 100644 vendor/flac/src/test_grabbag/picture/Makefile.am create mode 100644 vendor/flac/src/test_grabbag/picture/main.c create mode 100644 vendor/flac/src/test_libFLAC++/CMakeLists.txt create mode 100644 vendor/flac/src/test_libFLAC++/Makefile.am create mode 100644 vendor/flac/src/test_libFLAC++/decoders.cpp create mode 100644 vendor/flac/src/test_libFLAC++/decoders.h create mode 100644 vendor/flac/src/test_libFLAC++/encoders.cpp create mode 100644 vendor/flac/src/test_libFLAC++/encoders.h create mode 100644 vendor/flac/src/test_libFLAC++/main.cpp create mode 100644 vendor/flac/src/test_libFLAC++/metadata.cpp create mode 100644 vendor/flac/src/test_libFLAC++/metadata.h create mode 100644 vendor/flac/src/test_libFLAC++/metadata_manip.cpp create mode 100644 vendor/flac/src/test_libFLAC++/metadata_object.cpp create mode 100644 vendor/flac/src/test_libFLAC/CMakeLists.txt create mode 100644 vendor/flac/src/test_libFLAC/Makefile.am create mode 100644 vendor/flac/src/test_libFLAC/bitreader.c create mode 100644 vendor/flac/src/test_libFLAC/bitreader.h create mode 100644 vendor/flac/src/test_libFLAC/bitwriter.c create mode 100644 vendor/flac/src/test_libFLAC/bitwriter.h create mode 100644 vendor/flac/src/test_libFLAC/crc.c create mode 100644 vendor/flac/src/test_libFLAC/crc.h create mode 100644 vendor/flac/src/test_libFLAC/decoders.c create mode 100644 vendor/flac/src/test_libFLAC/decoders.h create mode 100644 vendor/flac/src/test_libFLAC/encoders.c create mode 100644 vendor/flac/src/test_libFLAC/encoders.h create mode 100644 vendor/flac/src/test_libFLAC/endswap.c create mode 100644 vendor/flac/src/test_libFLAC/endswap.h create mode 100644 vendor/flac/src/test_libFLAC/format.c create mode 100644 vendor/flac/src/test_libFLAC/format.h create mode 100644 vendor/flac/src/test_libFLAC/main.c create mode 100644 vendor/flac/src/test_libFLAC/matrix create mode 100644 vendor/flac/src/test_libFLAC/md5.c create mode 100644 vendor/flac/src/test_libFLAC/md5.h create mode 100644 vendor/flac/src/test_libFLAC/metadata.c create mode 100644 vendor/flac/src/test_libFLAC/metadata.h create mode 100644 vendor/flac/src/test_libFLAC/metadata_manip.c create mode 100644 vendor/flac/src/test_libFLAC/metadata_object.c create mode 100644 vendor/flac/src/test_libs_common/CMakeLists.txt create mode 100644 vendor/flac/src/test_libs_common/Makefile.am create mode 100644 vendor/flac/src/test_libs_common/README create mode 100644 vendor/flac/src/test_libs_common/file_utils_flac.c create mode 100644 vendor/flac/src/test_libs_common/metadata_utils.c create mode 100644 vendor/flac/src/test_seeking/CMakeLists.txt create mode 100644 vendor/flac/src/test_seeking/Makefile.am create mode 100644 vendor/flac/src/test_seeking/main.c create mode 100644 vendor/flac/src/test_streams/CMakeLists.txt create mode 100644 vendor/flac/src/test_streams/Makefile.am create mode 100644 vendor/flac/src/test_streams/main.c create mode 100644 vendor/flac/src/utils/Makefile.am create mode 100644 vendor/flac/src/utils/flacdiff/CMakeLists.txt create mode 100644 vendor/flac/src/utils/flacdiff/Makefile.am create mode 100644 vendor/flac/src/utils/flacdiff/main.cpp create mode 100644 vendor/flac/src/utils/flactimer/CMakeLists.txt create mode 100644 vendor/flac/src/utils/flactimer/Makefile.am create mode 100644 vendor/flac/src/utils/flactimer/main.cpp create mode 100644 vendor/flac/src/utils/loudness/loudness.sci create mode 100644 vendor/freetype/LICENSE.TXT create mode 100644 vendor/freetype/README create mode 100644 vendor/freetype/README.git create mode 100644 vendor/freetype/build-freetype.lua create mode 100644 vendor/freetype/builds/amiga/README create mode 100644 vendor/freetype/builds/amiga/include/config/ftconfig.h create mode 100644 vendor/freetype/builds/amiga/include/config/ftmodule.h create mode 100644 vendor/freetype/builds/amiga/makefile.os4 create mode 100644 vendor/freetype/builds/amiga/smakefile create mode 100644 vendor/freetype/builds/amiga/src/base/ftdebug.c create mode 100644 vendor/freetype/builds/amiga/src/base/ftsystem.c create mode 100644 vendor/freetype/builds/ansi/ansi-def.mk create mode 100644 vendor/freetype/builds/ansi/ansi.mk create mode 100644 vendor/freetype/builds/atari/ATARI.H create mode 100644 vendor/freetype/builds/atari/FNames.SIC create mode 100644 vendor/freetype/builds/atari/FREETYPE.PRJ create mode 100644 vendor/freetype/builds/atari/README.TXT create mode 100644 vendor/freetype/builds/atari/deflinejoiner.awk create mode 100644 vendor/freetype/builds/atari/gen-purec-patch.sh create mode 100644 vendor/freetype/builds/beos/beos-def.mk create mode 100644 vendor/freetype/builds/beos/beos.mk create mode 100644 vendor/freetype/builds/beos/detect.mk create mode 100644 vendor/freetype/builds/cmake/FindBrotliDec.cmake create mode 100644 vendor/freetype/builds/cmake/FindHarfBuzz.cmake create mode 100644 vendor/freetype/builds/cmake/iOS.cmake create mode 100644 vendor/freetype/builds/cmake/testbuild.sh create mode 100644 vendor/freetype/builds/compiler/ansi-cc.mk create mode 100644 vendor/freetype/builds/compiler/bcc-dev.mk create mode 100644 vendor/freetype/builds/compiler/bcc.mk create mode 100644 vendor/freetype/builds/compiler/emx.mk create mode 100644 vendor/freetype/builds/compiler/gcc-dev.mk create mode 100644 vendor/freetype/builds/compiler/gcc.mk create mode 100644 vendor/freetype/builds/compiler/intelc.mk create mode 100644 vendor/freetype/builds/compiler/unix-lcc.mk create mode 100644 vendor/freetype/builds/compiler/visualage.mk create mode 100644 vendor/freetype/builds/compiler/visualc.mk create mode 100644 vendor/freetype/builds/compiler/watcom.mk create mode 100644 vendor/freetype/builds/compiler/win-lcc.mk create mode 100644 vendor/freetype/builds/detect.mk create mode 100644 vendor/freetype/builds/dos/detect.mk create mode 100644 vendor/freetype/builds/dos/dos-def.mk create mode 100644 vendor/freetype/builds/dos/dos-emx.mk create mode 100644 vendor/freetype/builds/dos/dos-gcc.mk create mode 100644 vendor/freetype/builds/dos/dos-wat.mk create mode 100644 vendor/freetype/builds/exports.mk create mode 100644 vendor/freetype/builds/freetype.mk create mode 100644 vendor/freetype/builds/link_dos.mk create mode 100644 vendor/freetype/builds/link_std.mk create mode 100644 vendor/freetype/builds/mac/FreeType.m68k_cfm.make.txt create mode 100644 vendor/freetype/builds/mac/FreeType.m68k_far.make.txt create mode 100644 vendor/freetype/builds/mac/FreeType.ppc_carbon.make.txt create mode 100644 vendor/freetype/builds/mac/FreeType.ppc_classic.make.txt create mode 100644 vendor/freetype/builds/mac/README create mode 100644 vendor/freetype/builds/mac/ascii2mpw.py create mode 100644 vendor/freetype/builds/mac/freetype-Info.plist create mode 100644 vendor/freetype/builds/mac/ftlib.prj.xml create mode 100644 vendor/freetype/builds/mac/ftmac.c create mode 100644 vendor/freetype/builds/meson/extract_freetype_version.py create mode 100644 vendor/freetype/builds/meson/extract_libtool_version.py create mode 100644 vendor/freetype/builds/meson/generate_reference_docs.py create mode 100644 vendor/freetype/builds/meson/parse_modules_cfg.py create mode 100644 vendor/freetype/builds/meson/process_ftoption_h.py create mode 100644 vendor/freetype/builds/modules.mk create mode 100644 vendor/freetype/builds/os2/detect.mk create mode 100644 vendor/freetype/builds/os2/os2-def.mk create mode 100644 vendor/freetype/builds/os2/os2-dev.mk create mode 100644 vendor/freetype/builds/os2/os2-gcc.mk create mode 100644 vendor/freetype/builds/symbian/bld.inf create mode 100644 vendor/freetype/builds/symbian/freetype.mmp create mode 100644 vendor/freetype/builds/toplevel.mk create mode 100644 vendor/freetype/builds/unix/.gitignore create mode 100644 vendor/freetype/builds/unix/ax_compare_version.m4 create mode 100644 vendor/freetype/builds/unix/ax_prog_python_version.m4 create mode 100644 vendor/freetype/builds/unix/ax_pthread.m4 create mode 100644 vendor/freetype/builds/unix/configure.raw create mode 100644 vendor/freetype/builds/unix/detect.mk create mode 100644 vendor/freetype/builds/unix/freetype-config.in create mode 100644 vendor/freetype/builds/unix/freetype2.in create mode 100644 vendor/freetype/builds/unix/freetype2.m4 create mode 100644 vendor/freetype/builds/unix/ft-munmap.m4 create mode 100644 vendor/freetype/builds/unix/ftconfig.h.in create mode 100644 vendor/freetype/builds/unix/ftsystem.c create mode 100644 vendor/freetype/builds/unix/install.mk create mode 100644 vendor/freetype/builds/unix/pkg.m4 create mode 100644 vendor/freetype/builds/unix/unix-cc.in create mode 100644 vendor/freetype/builds/unix/unix-def.in create mode 100644 vendor/freetype/builds/unix/unix-dev.mk create mode 100644 vendor/freetype/builds/unix/unix-lcc.mk create mode 100644 vendor/freetype/builds/unix/unix.mk create mode 100644 vendor/freetype/builds/unix/unixddef.mk create mode 100644 vendor/freetype/builds/vms/apinames_vms.bash create mode 100644 vendor/freetype/builds/vms/ftconfig.h create mode 100644 vendor/freetype/builds/vms/ftsystem.c create mode 100644 vendor/freetype/builds/wince/ftdebug.c create mode 100644 vendor/freetype/builds/wince/vc2005-ce/freetype.vcproj create mode 100644 vendor/freetype/builds/wince/vc2005-ce/index.html create mode 100644 vendor/freetype/builds/wince/vc2008-ce/freetype.vcproj create mode 100644 vendor/freetype/builds/wince/vc2008-ce/index.html create mode 100644 vendor/freetype/builds/windows/.gitignore create mode 100644 vendor/freetype/builds/windows/detect.mk create mode 100644 vendor/freetype/builds/windows/ftdebug.c create mode 100644 vendor/freetype/builds/windows/ftsystem.c create mode 100644 vendor/freetype/builds/windows/vc2010/freetype.user.props create mode 100644 vendor/freetype/builds/windows/vc2010/index.html create mode 100644 vendor/freetype/builds/windows/visualc/freetype.dsp create mode 100644 vendor/freetype/builds/windows/visualc/freetype.dsw create mode 100644 vendor/freetype/builds/windows/visualc/freetype.vcproj create mode 100644 vendor/freetype/builds/windows/visualc/index.html create mode 100644 vendor/freetype/builds/windows/visualce/freetype.dsp create mode 100644 vendor/freetype/builds/windows/visualce/freetype.dsw create mode 100644 vendor/freetype/builds/windows/visualce/freetype.vcproj create mode 100644 vendor/freetype/builds/windows/visualce/index.html create mode 100644 vendor/freetype/builds/windows/w32-bcc.mk create mode 100644 vendor/freetype/builds/windows/w32-bccd.mk create mode 100644 vendor/freetype/builds/windows/w32-dev.mk create mode 100644 vendor/freetype/builds/windows/w32-gcc.mk create mode 100644 vendor/freetype/builds/windows/w32-icc.mk create mode 100644 vendor/freetype/builds/windows/w32-intl.mk create mode 100644 vendor/freetype/builds/windows/w32-lcc.mk create mode 100644 vendor/freetype/builds/windows/w32-mingw32.mk create mode 100644 vendor/freetype/builds/windows/w32-vcc.mk create mode 100644 vendor/freetype/builds/windows/w32-wat.mk create mode 100644 vendor/freetype/builds/windows/win32-def.mk create mode 100644 vendor/freetype/devel/ft2build.h create mode 100644 vendor/freetype/devel/ftoption.h create mode 100644 vendor/freetype/include/freetype/config/ftconfig.h create mode 100644 vendor/freetype/include/freetype/config/ftheader.h create mode 100644 vendor/freetype/include/freetype/config/ftmodule.h create mode 100644 vendor/freetype/include/freetype/config/ftoption.h create mode 100644 vendor/freetype/include/freetype/config/ftstdlib.h create mode 100644 vendor/freetype/include/freetype/config/integer-types.h create mode 100644 vendor/freetype/include/freetype/config/mac-support.h create mode 100644 vendor/freetype/include/freetype/config/public-macros.h create mode 100644 vendor/freetype/include/freetype/freetype.h create mode 100644 vendor/freetype/include/freetype/ftadvanc.h create mode 100644 vendor/freetype/include/freetype/ftbbox.h create mode 100644 vendor/freetype/include/freetype/ftbdf.h create mode 100644 vendor/freetype/include/freetype/ftbitmap.h create mode 100644 vendor/freetype/include/freetype/ftbzip2.h create mode 100644 vendor/freetype/include/freetype/ftcache.h create mode 100644 vendor/freetype/include/freetype/ftchapters.h create mode 100644 vendor/freetype/include/freetype/ftcid.h create mode 100644 vendor/freetype/include/freetype/ftcolor.h create mode 100644 vendor/freetype/include/freetype/ftdriver.h create mode 100644 vendor/freetype/include/freetype/fterrdef.h create mode 100644 vendor/freetype/include/freetype/fterrors.h create mode 100644 vendor/freetype/include/freetype/ftfntfmt.h create mode 100644 vendor/freetype/include/freetype/ftgasp.h create mode 100644 vendor/freetype/include/freetype/ftglyph.h create mode 100644 vendor/freetype/include/freetype/ftgxval.h create mode 100644 vendor/freetype/include/freetype/ftgzip.h create mode 100644 vendor/freetype/include/freetype/ftimage.h create mode 100644 vendor/freetype/include/freetype/ftincrem.h create mode 100644 vendor/freetype/include/freetype/ftlcdfil.h create mode 100644 vendor/freetype/include/freetype/ftlist.h create mode 100644 vendor/freetype/include/freetype/ftlogging.h create mode 100644 vendor/freetype/include/freetype/ftlzw.h create mode 100644 vendor/freetype/include/freetype/ftmac.h create mode 100644 vendor/freetype/include/freetype/ftmm.h create mode 100644 vendor/freetype/include/freetype/ftmodapi.h create mode 100644 vendor/freetype/include/freetype/ftmoderr.h create mode 100644 vendor/freetype/include/freetype/ftotval.h create mode 100644 vendor/freetype/include/freetype/ftoutln.h create mode 100644 vendor/freetype/include/freetype/ftparams.h create mode 100644 vendor/freetype/include/freetype/ftpfr.h create mode 100644 vendor/freetype/include/freetype/ftrender.h create mode 100644 vendor/freetype/include/freetype/ftsizes.h create mode 100644 vendor/freetype/include/freetype/ftsnames.h create mode 100644 vendor/freetype/include/freetype/ftstroke.h create mode 100644 vendor/freetype/include/freetype/ftsynth.h create mode 100644 vendor/freetype/include/freetype/ftsystem.h create mode 100644 vendor/freetype/include/freetype/fttrigon.h create mode 100644 vendor/freetype/include/freetype/fttypes.h create mode 100644 vendor/freetype/include/freetype/ftwinfnt.h create mode 100644 vendor/freetype/include/freetype/internal/autohint.h create mode 100644 vendor/freetype/include/freetype/internal/cffotypes.h create mode 100644 vendor/freetype/include/freetype/internal/cfftypes.h create mode 100644 vendor/freetype/include/freetype/internal/compiler-macros.h create mode 100644 vendor/freetype/include/freetype/internal/ftcalc.h create mode 100644 vendor/freetype/include/freetype/internal/ftdebug.h create mode 100644 vendor/freetype/include/freetype/internal/ftdrv.h create mode 100644 vendor/freetype/include/freetype/internal/ftgloadr.h create mode 100644 vendor/freetype/include/freetype/internal/fthash.h create mode 100644 vendor/freetype/include/freetype/internal/ftmemory.h create mode 100644 vendor/freetype/include/freetype/internal/ftmmtypes.h create mode 100644 vendor/freetype/include/freetype/internal/ftobjs.h create mode 100644 vendor/freetype/include/freetype/internal/ftpsprop.h create mode 100644 vendor/freetype/include/freetype/internal/ftrfork.h create mode 100644 vendor/freetype/include/freetype/internal/ftserv.h create mode 100644 vendor/freetype/include/freetype/internal/ftstream.h create mode 100644 vendor/freetype/include/freetype/internal/fttrace.h create mode 100644 vendor/freetype/include/freetype/internal/ftvalid.h create mode 100644 vendor/freetype/include/freetype/internal/psaux.h create mode 100644 vendor/freetype/include/freetype/internal/pshints.h create mode 100644 vendor/freetype/include/freetype/internal/services/svbdf.h create mode 100644 vendor/freetype/include/freetype/internal/services/svcfftl.h create mode 100644 vendor/freetype/include/freetype/internal/services/svcid.h create mode 100644 vendor/freetype/include/freetype/internal/services/svfntfmt.h create mode 100644 vendor/freetype/include/freetype/internal/services/svgldict.h create mode 100644 vendor/freetype/include/freetype/internal/services/svgxval.h create mode 100644 vendor/freetype/include/freetype/internal/services/svkern.h create mode 100644 vendor/freetype/include/freetype/internal/services/svmetric.h create mode 100644 vendor/freetype/include/freetype/internal/services/svmm.h create mode 100644 vendor/freetype/include/freetype/internal/services/svotval.h create mode 100644 vendor/freetype/include/freetype/internal/services/svpfr.h create mode 100644 vendor/freetype/include/freetype/internal/services/svpostnm.h create mode 100644 vendor/freetype/include/freetype/internal/services/svprop.h create mode 100644 vendor/freetype/include/freetype/internal/services/svpscmap.h create mode 100644 vendor/freetype/include/freetype/internal/services/svpsinfo.h create mode 100644 vendor/freetype/include/freetype/internal/services/svsfnt.h create mode 100644 vendor/freetype/include/freetype/internal/services/svttcmap.h create mode 100644 vendor/freetype/include/freetype/internal/services/svtteng.h create mode 100644 vendor/freetype/include/freetype/internal/services/svttglyf.h create mode 100644 vendor/freetype/include/freetype/internal/services/svwinfnt.h create mode 100644 vendor/freetype/include/freetype/internal/sfnt.h create mode 100644 vendor/freetype/include/freetype/internal/svginterface.h create mode 100644 vendor/freetype/include/freetype/internal/t1types.h create mode 100644 vendor/freetype/include/freetype/internal/tttypes.h create mode 100644 vendor/freetype/include/freetype/internal/wofftypes.h create mode 100644 vendor/freetype/include/freetype/otsvg.h create mode 100644 vendor/freetype/include/freetype/t1tables.h create mode 100644 vendor/freetype/include/freetype/ttnameid.h create mode 100644 vendor/freetype/include/freetype/tttables.h create mode 100644 vendor/freetype/include/freetype/tttags.h create mode 100644 vendor/freetype/include/ft2build.h create mode 100644 vendor/freetype/lib/freetype.idb create mode 100644 vendor/freetype/lib/freetype.lib create mode 100644 vendor/freetype/objs/.gitignore create mode 100644 vendor/freetype/objs/README create mode 100644 vendor/freetype/src/autofit/afblue.c create mode 100644 vendor/freetype/src/autofit/afblue.cin create mode 100644 vendor/freetype/src/autofit/afblue.dat create mode 100644 vendor/freetype/src/autofit/afblue.h create mode 100644 vendor/freetype/src/autofit/afblue.hin create mode 100644 vendor/freetype/src/autofit/afcjk.c create mode 100644 vendor/freetype/src/autofit/afcjk.h create mode 100644 vendor/freetype/src/autofit/afcover.h create mode 100644 vendor/freetype/src/autofit/afdummy.c create mode 100644 vendor/freetype/src/autofit/afdummy.h create mode 100644 vendor/freetype/src/autofit/aferrors.h create mode 100644 vendor/freetype/src/autofit/afglobal.c create mode 100644 vendor/freetype/src/autofit/afglobal.h create mode 100644 vendor/freetype/src/autofit/afhints.c create mode 100644 vendor/freetype/src/autofit/afhints.h create mode 100644 vendor/freetype/src/autofit/afindic.c create mode 100644 vendor/freetype/src/autofit/afindic.h create mode 100644 vendor/freetype/src/autofit/aflatin.c create mode 100644 vendor/freetype/src/autofit/aflatin.h create mode 100644 vendor/freetype/src/autofit/afloader.c create mode 100644 vendor/freetype/src/autofit/afloader.h create mode 100644 vendor/freetype/src/autofit/afmodule.c create mode 100644 vendor/freetype/src/autofit/afmodule.h create mode 100644 vendor/freetype/src/autofit/afranges.c create mode 100644 vendor/freetype/src/autofit/afranges.h create mode 100644 vendor/freetype/src/autofit/afscript.h create mode 100644 vendor/freetype/src/autofit/afshaper.c create mode 100644 vendor/freetype/src/autofit/afshaper.h create mode 100644 vendor/freetype/src/autofit/afstyles.h create mode 100644 vendor/freetype/src/autofit/aftypes.h create mode 100644 vendor/freetype/src/autofit/afws-decl.h create mode 100644 vendor/freetype/src/autofit/afws-iter.h create mode 100644 vendor/freetype/src/autofit/autofit.c create mode 100644 vendor/freetype/src/autofit/ft-hb.c create mode 100644 vendor/freetype/src/autofit/ft-hb.h create mode 100644 vendor/freetype/src/autofit/module.mk create mode 100644 vendor/freetype/src/autofit/rules.mk create mode 100644 vendor/freetype/src/base/ftadvanc.c create mode 100644 vendor/freetype/src/base/ftbase.c create mode 100644 vendor/freetype/src/base/ftbase.h create mode 100644 vendor/freetype/src/base/ftbbox.c create mode 100644 vendor/freetype/src/base/ftbdf.c create mode 100644 vendor/freetype/src/base/ftbitmap.c create mode 100644 vendor/freetype/src/base/ftcalc.c create mode 100644 vendor/freetype/src/base/ftcid.c create mode 100644 vendor/freetype/src/base/ftcolor.c create mode 100644 vendor/freetype/src/base/ftdbgmem.c create mode 100644 vendor/freetype/src/base/ftdebug.c create mode 100644 vendor/freetype/src/base/fterrors.c create mode 100644 vendor/freetype/src/base/ftfntfmt.c create mode 100644 vendor/freetype/src/base/ftfstype.c create mode 100644 vendor/freetype/src/base/ftgasp.c create mode 100644 vendor/freetype/src/base/ftgloadr.c create mode 100644 vendor/freetype/src/base/ftglyph.c create mode 100644 vendor/freetype/src/base/ftgxval.c create mode 100644 vendor/freetype/src/base/fthash.c create mode 100644 vendor/freetype/src/base/ftinit.c create mode 100644 vendor/freetype/src/base/ftlcdfil.c create mode 100644 vendor/freetype/src/base/ftmac.c create mode 100644 vendor/freetype/src/base/ftmm.c create mode 100644 vendor/freetype/src/base/ftobjs.c create mode 100644 vendor/freetype/src/base/ftotval.c create mode 100644 vendor/freetype/src/base/ftoutln.c create mode 100644 vendor/freetype/src/base/ftpatent.c create mode 100644 vendor/freetype/src/base/ftpfr.c create mode 100644 vendor/freetype/src/base/ftpsprop.c create mode 100644 vendor/freetype/src/base/ftrfork.c create mode 100644 vendor/freetype/src/base/ftsnames.c create mode 100644 vendor/freetype/src/base/ftstream.c create mode 100644 vendor/freetype/src/base/ftstroke.c create mode 100644 vendor/freetype/src/base/ftsynth.c create mode 100644 vendor/freetype/src/base/ftsystem.c create mode 100644 vendor/freetype/src/base/fttrigon.c create mode 100644 vendor/freetype/src/base/fttype1.c create mode 100644 vendor/freetype/src/base/ftutil.c create mode 100644 vendor/freetype/src/base/ftver.rc create mode 100644 vendor/freetype/src/base/ftwinfnt.c create mode 100644 vendor/freetype/src/base/md5.c create mode 100644 vendor/freetype/src/base/md5.h create mode 100644 vendor/freetype/src/base/rules.mk create mode 100644 vendor/freetype/src/bdf/README create mode 100644 vendor/freetype/src/bdf/bdf.c create mode 100644 vendor/freetype/src/bdf/bdf.h create mode 100644 vendor/freetype/src/bdf/bdfdrivr.c create mode 100644 vendor/freetype/src/bdf/bdfdrivr.h create mode 100644 vendor/freetype/src/bdf/bdferror.h create mode 100644 vendor/freetype/src/bdf/bdflib.c create mode 100644 vendor/freetype/src/bdf/module.mk create mode 100644 vendor/freetype/src/bdf/rules.mk create mode 100644 vendor/freetype/src/bzip2/ftbzip2.c create mode 100644 vendor/freetype/src/bzip2/rules.mk create mode 100644 vendor/freetype/src/cache/ftcache.c create mode 100644 vendor/freetype/src/cache/ftcbasic.c create mode 100644 vendor/freetype/src/cache/ftccache.c create mode 100644 vendor/freetype/src/cache/ftccache.h create mode 100644 vendor/freetype/src/cache/ftccback.h create mode 100644 vendor/freetype/src/cache/ftccmap.c create mode 100644 vendor/freetype/src/cache/ftcerror.h create mode 100644 vendor/freetype/src/cache/ftcglyph.c create mode 100644 vendor/freetype/src/cache/ftcglyph.h create mode 100644 vendor/freetype/src/cache/ftcimage.c create mode 100644 vendor/freetype/src/cache/ftcimage.h create mode 100644 vendor/freetype/src/cache/ftcmanag.c create mode 100644 vendor/freetype/src/cache/ftcmanag.h create mode 100644 vendor/freetype/src/cache/ftcmru.c create mode 100644 vendor/freetype/src/cache/ftcmru.h create mode 100644 vendor/freetype/src/cache/ftcsbits.c create mode 100644 vendor/freetype/src/cache/ftcsbits.h create mode 100644 vendor/freetype/src/cache/rules.mk create mode 100644 vendor/freetype/src/cff/cff.c create mode 100644 vendor/freetype/src/cff/cffcmap.c create mode 100644 vendor/freetype/src/cff/cffcmap.h create mode 100644 vendor/freetype/src/cff/cffdrivr.c create mode 100644 vendor/freetype/src/cff/cffdrivr.h create mode 100644 vendor/freetype/src/cff/cfferrs.h create mode 100644 vendor/freetype/src/cff/cffgload.c create mode 100644 vendor/freetype/src/cff/cffgload.h create mode 100644 vendor/freetype/src/cff/cffload.c create mode 100644 vendor/freetype/src/cff/cffload.h create mode 100644 vendor/freetype/src/cff/cffobjs.c create mode 100644 vendor/freetype/src/cff/cffobjs.h create mode 100644 vendor/freetype/src/cff/cffparse.c create mode 100644 vendor/freetype/src/cff/cffparse.h create mode 100644 vendor/freetype/src/cff/cfftoken.h create mode 100644 vendor/freetype/src/cff/module.mk create mode 100644 vendor/freetype/src/cff/rules.mk create mode 100644 vendor/freetype/src/cid/ciderrs.h create mode 100644 vendor/freetype/src/cid/cidgload.c create mode 100644 vendor/freetype/src/cid/cidgload.h create mode 100644 vendor/freetype/src/cid/cidload.c create mode 100644 vendor/freetype/src/cid/cidload.h create mode 100644 vendor/freetype/src/cid/cidobjs.c create mode 100644 vendor/freetype/src/cid/cidobjs.h create mode 100644 vendor/freetype/src/cid/cidparse.c create mode 100644 vendor/freetype/src/cid/cidparse.h create mode 100644 vendor/freetype/src/cid/cidriver.c create mode 100644 vendor/freetype/src/cid/cidriver.h create mode 100644 vendor/freetype/src/cid/cidtoken.h create mode 100644 vendor/freetype/src/cid/module.mk create mode 100644 vendor/freetype/src/cid/rules.mk create mode 100644 vendor/freetype/src/cid/type1cid.c create mode 100644 vendor/freetype/src/dlg/dlgwrap.c create mode 100644 vendor/freetype/src/dlg/rules.mk create mode 100644 vendor/freetype/src/gxvalid/README create mode 100644 vendor/freetype/src/gxvalid/gxvalid.c create mode 100644 vendor/freetype/src/gxvalid/gxvalid.h create mode 100644 vendor/freetype/src/gxvalid/gxvbsln.c create mode 100644 vendor/freetype/src/gxvalid/gxvcommn.c create mode 100644 vendor/freetype/src/gxvalid/gxvcommn.h create mode 100644 vendor/freetype/src/gxvalid/gxverror.h create mode 100644 vendor/freetype/src/gxvalid/gxvfeat.c create mode 100644 vendor/freetype/src/gxvalid/gxvfeat.h create mode 100644 vendor/freetype/src/gxvalid/gxvfgen.c create mode 100644 vendor/freetype/src/gxvalid/gxvjust.c create mode 100644 vendor/freetype/src/gxvalid/gxvkern.c create mode 100644 vendor/freetype/src/gxvalid/gxvlcar.c create mode 100644 vendor/freetype/src/gxvalid/gxvmod.c create mode 100644 vendor/freetype/src/gxvalid/gxvmod.h create mode 100644 vendor/freetype/src/gxvalid/gxvmort.c create mode 100644 vendor/freetype/src/gxvalid/gxvmort.h create mode 100644 vendor/freetype/src/gxvalid/gxvmort0.c create mode 100644 vendor/freetype/src/gxvalid/gxvmort1.c create mode 100644 vendor/freetype/src/gxvalid/gxvmort2.c create mode 100644 vendor/freetype/src/gxvalid/gxvmort4.c create mode 100644 vendor/freetype/src/gxvalid/gxvmort5.c create mode 100644 vendor/freetype/src/gxvalid/gxvmorx.c create mode 100644 vendor/freetype/src/gxvalid/gxvmorx.h create mode 100644 vendor/freetype/src/gxvalid/gxvmorx0.c create mode 100644 vendor/freetype/src/gxvalid/gxvmorx1.c create mode 100644 vendor/freetype/src/gxvalid/gxvmorx2.c create mode 100644 vendor/freetype/src/gxvalid/gxvmorx4.c create mode 100644 vendor/freetype/src/gxvalid/gxvmorx5.c create mode 100644 vendor/freetype/src/gxvalid/gxvopbd.c create mode 100644 vendor/freetype/src/gxvalid/gxvprop.c create mode 100644 vendor/freetype/src/gxvalid/gxvtrak.c create mode 100644 vendor/freetype/src/gxvalid/module.mk create mode 100644 vendor/freetype/src/gxvalid/rules.mk create mode 100644 vendor/freetype/src/gzip/README.freetype create mode 100644 vendor/freetype/src/gzip/adler32.c create mode 100644 vendor/freetype/src/gzip/crc32.c create mode 100644 vendor/freetype/src/gzip/crc32.h create mode 100644 vendor/freetype/src/gzip/ftgzip.c create mode 100644 vendor/freetype/src/gzip/ftzconf.h create mode 100644 vendor/freetype/src/gzip/gzguts.h create mode 100644 vendor/freetype/src/gzip/inffast.c create mode 100644 vendor/freetype/src/gzip/inffast.h create mode 100644 vendor/freetype/src/gzip/inffixed.h create mode 100644 vendor/freetype/src/gzip/inflate.c create mode 100644 vendor/freetype/src/gzip/inflate.h create mode 100644 vendor/freetype/src/gzip/inftrees.c create mode 100644 vendor/freetype/src/gzip/inftrees.h create mode 100644 vendor/freetype/src/gzip/patches/freetype-zlib.diff create mode 100644 vendor/freetype/src/gzip/rules.mk create mode 100644 vendor/freetype/src/gzip/zlib.h create mode 100644 vendor/freetype/src/gzip/zutil.c create mode 100644 vendor/freetype/src/gzip/zutil.h create mode 100644 vendor/freetype/src/lzw/ftlzw.c create mode 100644 vendor/freetype/src/lzw/ftzopen.c create mode 100644 vendor/freetype/src/lzw/ftzopen.h create mode 100644 vendor/freetype/src/lzw/rules.mk create mode 100644 vendor/freetype/src/otvalid/module.mk create mode 100644 vendor/freetype/src/otvalid/otvalid.c create mode 100644 vendor/freetype/src/otvalid/otvalid.h create mode 100644 vendor/freetype/src/otvalid/otvbase.c create mode 100644 vendor/freetype/src/otvalid/otvcommn.c create mode 100644 vendor/freetype/src/otvalid/otvcommn.h create mode 100644 vendor/freetype/src/otvalid/otverror.h create mode 100644 vendor/freetype/src/otvalid/otvgdef.c create mode 100644 vendor/freetype/src/otvalid/otvgpos.c create mode 100644 vendor/freetype/src/otvalid/otvgpos.h create mode 100644 vendor/freetype/src/otvalid/otvgsub.c create mode 100644 vendor/freetype/src/otvalid/otvjstf.c create mode 100644 vendor/freetype/src/otvalid/otvmath.c create mode 100644 vendor/freetype/src/otvalid/otvmod.c create mode 100644 vendor/freetype/src/otvalid/otvmod.h create mode 100644 vendor/freetype/src/otvalid/rules.mk create mode 100644 vendor/freetype/src/pcf/README create mode 100644 vendor/freetype/src/pcf/module.mk create mode 100644 vendor/freetype/src/pcf/pcf.c create mode 100644 vendor/freetype/src/pcf/pcf.h create mode 100644 vendor/freetype/src/pcf/pcfdrivr.c create mode 100644 vendor/freetype/src/pcf/pcfdrivr.h create mode 100644 vendor/freetype/src/pcf/pcferror.h create mode 100644 vendor/freetype/src/pcf/pcfread.c create mode 100644 vendor/freetype/src/pcf/pcfread.h create mode 100644 vendor/freetype/src/pcf/pcfutil.c create mode 100644 vendor/freetype/src/pcf/pcfutil.h create mode 100644 vendor/freetype/src/pcf/rules.mk create mode 100644 vendor/freetype/src/pfr/module.mk create mode 100644 vendor/freetype/src/pfr/pfr.c create mode 100644 vendor/freetype/src/pfr/pfrcmap.c create mode 100644 vendor/freetype/src/pfr/pfrcmap.h create mode 100644 vendor/freetype/src/pfr/pfrdrivr.c create mode 100644 vendor/freetype/src/pfr/pfrdrivr.h create mode 100644 vendor/freetype/src/pfr/pfrerror.h create mode 100644 vendor/freetype/src/pfr/pfrgload.c create mode 100644 vendor/freetype/src/pfr/pfrgload.h create mode 100644 vendor/freetype/src/pfr/pfrload.c create mode 100644 vendor/freetype/src/pfr/pfrload.h create mode 100644 vendor/freetype/src/pfr/pfrobjs.c create mode 100644 vendor/freetype/src/pfr/pfrobjs.h create mode 100644 vendor/freetype/src/pfr/pfrsbit.c create mode 100644 vendor/freetype/src/pfr/pfrsbit.h create mode 100644 vendor/freetype/src/pfr/pfrtypes.h create mode 100644 vendor/freetype/src/pfr/rules.mk create mode 100644 vendor/freetype/src/psaux/afmparse.c create mode 100644 vendor/freetype/src/psaux/afmparse.h create mode 100644 vendor/freetype/src/psaux/cffdecode.c create mode 100644 vendor/freetype/src/psaux/cffdecode.h create mode 100644 vendor/freetype/src/psaux/module.mk create mode 100644 vendor/freetype/src/psaux/psarrst.c create mode 100644 vendor/freetype/src/psaux/psarrst.h create mode 100644 vendor/freetype/src/psaux/psaux.c create mode 100644 vendor/freetype/src/psaux/psauxerr.h create mode 100644 vendor/freetype/src/psaux/psauxmod.c create mode 100644 vendor/freetype/src/psaux/psauxmod.h create mode 100644 vendor/freetype/src/psaux/psblues.c create mode 100644 vendor/freetype/src/psaux/psblues.h create mode 100644 vendor/freetype/src/psaux/psconv.c create mode 100644 vendor/freetype/src/psaux/psconv.h create mode 100644 vendor/freetype/src/psaux/pserror.c create mode 100644 vendor/freetype/src/psaux/pserror.h create mode 100644 vendor/freetype/src/psaux/psfixed.h create mode 100644 vendor/freetype/src/psaux/psfont.c create mode 100644 vendor/freetype/src/psaux/psfont.h create mode 100644 vendor/freetype/src/psaux/psft.c create mode 100644 vendor/freetype/src/psaux/psft.h create mode 100644 vendor/freetype/src/psaux/psglue.h create mode 100644 vendor/freetype/src/psaux/pshints.c create mode 100644 vendor/freetype/src/psaux/pshints.h create mode 100644 vendor/freetype/src/psaux/psintrp.c create mode 100644 vendor/freetype/src/psaux/psintrp.h create mode 100644 vendor/freetype/src/psaux/psobjs.c create mode 100644 vendor/freetype/src/psaux/psobjs.h create mode 100644 vendor/freetype/src/psaux/psread.c create mode 100644 vendor/freetype/src/psaux/psread.h create mode 100644 vendor/freetype/src/psaux/psstack.c create mode 100644 vendor/freetype/src/psaux/psstack.h create mode 100644 vendor/freetype/src/psaux/pstypes.h create mode 100644 vendor/freetype/src/psaux/rules.mk create mode 100644 vendor/freetype/src/psaux/t1cmap.c create mode 100644 vendor/freetype/src/psaux/t1cmap.h create mode 100644 vendor/freetype/src/psaux/t1decode.c create mode 100644 vendor/freetype/src/psaux/t1decode.h create mode 100644 vendor/freetype/src/pshinter/module.mk create mode 100644 vendor/freetype/src/pshinter/pshalgo.c create mode 100644 vendor/freetype/src/pshinter/pshalgo.h create mode 100644 vendor/freetype/src/pshinter/pshglob.c create mode 100644 vendor/freetype/src/pshinter/pshglob.h create mode 100644 vendor/freetype/src/pshinter/pshinter.c create mode 100644 vendor/freetype/src/pshinter/pshmod.c create mode 100644 vendor/freetype/src/pshinter/pshmod.h create mode 100644 vendor/freetype/src/pshinter/pshnterr.h create mode 100644 vendor/freetype/src/pshinter/pshrec.c create mode 100644 vendor/freetype/src/pshinter/pshrec.h create mode 100644 vendor/freetype/src/pshinter/rules.mk create mode 100644 vendor/freetype/src/psnames/module.mk create mode 100644 vendor/freetype/src/psnames/psmodule.c create mode 100644 vendor/freetype/src/psnames/psmodule.h create mode 100644 vendor/freetype/src/psnames/psnamerr.h create mode 100644 vendor/freetype/src/psnames/psnames.c create mode 100644 vendor/freetype/src/psnames/pstables.h create mode 100644 vendor/freetype/src/psnames/rules.mk create mode 100644 vendor/freetype/src/raster/ftmisc.h create mode 100644 vendor/freetype/src/raster/ftraster.c create mode 100644 vendor/freetype/src/raster/ftraster.h create mode 100644 vendor/freetype/src/raster/ftrend1.c create mode 100644 vendor/freetype/src/raster/ftrend1.h create mode 100644 vendor/freetype/src/raster/module.mk create mode 100644 vendor/freetype/src/raster/raster.c create mode 100644 vendor/freetype/src/raster/rasterrs.h create mode 100644 vendor/freetype/src/raster/rules.mk create mode 100644 vendor/freetype/src/sdf/ftbsdf.c create mode 100644 vendor/freetype/src/sdf/ftsdf.c create mode 100644 vendor/freetype/src/sdf/ftsdf.h create mode 100644 vendor/freetype/src/sdf/ftsdfcommon.c create mode 100644 vendor/freetype/src/sdf/ftsdfcommon.h create mode 100644 vendor/freetype/src/sdf/ftsdferrs.h create mode 100644 vendor/freetype/src/sdf/ftsdfrend.c create mode 100644 vendor/freetype/src/sdf/ftsdfrend.h create mode 100644 vendor/freetype/src/sdf/module.mk create mode 100644 vendor/freetype/src/sdf/rules.mk create mode 100644 vendor/freetype/src/sdf/sdf.c create mode 100644 vendor/freetype/src/sfnt/module.mk create mode 100644 vendor/freetype/src/sfnt/pngshim.c create mode 100644 vendor/freetype/src/sfnt/pngshim.h create mode 100644 vendor/freetype/src/sfnt/rules.mk create mode 100644 vendor/freetype/src/sfnt/sfdriver.c create mode 100644 vendor/freetype/src/sfnt/sfdriver.h create mode 100644 vendor/freetype/src/sfnt/sferrors.h create mode 100644 vendor/freetype/src/sfnt/sfnt.c create mode 100644 vendor/freetype/src/sfnt/sfobjs.c create mode 100644 vendor/freetype/src/sfnt/sfobjs.h create mode 100644 vendor/freetype/src/sfnt/sfwoff.c create mode 100644 vendor/freetype/src/sfnt/sfwoff.h create mode 100644 vendor/freetype/src/sfnt/sfwoff2.c create mode 100644 vendor/freetype/src/sfnt/sfwoff2.h create mode 100644 vendor/freetype/src/sfnt/ttbdf.c create mode 100644 vendor/freetype/src/sfnt/ttbdf.h create mode 100644 vendor/freetype/src/sfnt/ttcmap.c create mode 100644 vendor/freetype/src/sfnt/ttcmap.h create mode 100644 vendor/freetype/src/sfnt/ttcmapc.h create mode 100644 vendor/freetype/src/sfnt/ttcolr.c create mode 100644 vendor/freetype/src/sfnt/ttcolr.h create mode 100644 vendor/freetype/src/sfnt/ttcpal.c create mode 100644 vendor/freetype/src/sfnt/ttcpal.h create mode 100644 vendor/freetype/src/sfnt/ttkern.c create mode 100644 vendor/freetype/src/sfnt/ttkern.h create mode 100644 vendor/freetype/src/sfnt/ttload.c create mode 100644 vendor/freetype/src/sfnt/ttload.h create mode 100644 vendor/freetype/src/sfnt/ttmtx.c create mode 100644 vendor/freetype/src/sfnt/ttmtx.h create mode 100644 vendor/freetype/src/sfnt/ttpost.c create mode 100644 vendor/freetype/src/sfnt/ttpost.h create mode 100644 vendor/freetype/src/sfnt/ttsbit.c create mode 100644 vendor/freetype/src/sfnt/ttsbit.h create mode 100644 vendor/freetype/src/sfnt/ttsvg.c create mode 100644 vendor/freetype/src/sfnt/ttsvg.h create mode 100644 vendor/freetype/src/sfnt/woff2tags.c create mode 100644 vendor/freetype/src/sfnt/woff2tags.h create mode 100644 vendor/freetype/src/smooth/ftgrays.c create mode 100644 vendor/freetype/src/smooth/ftgrays.h create mode 100644 vendor/freetype/src/smooth/ftsmerrs.h create mode 100644 vendor/freetype/src/smooth/ftsmooth.c create mode 100644 vendor/freetype/src/smooth/ftsmooth.h create mode 100644 vendor/freetype/src/smooth/module.mk create mode 100644 vendor/freetype/src/smooth/rules.mk create mode 100644 vendor/freetype/src/smooth/smooth.c create mode 100644 vendor/freetype/src/svg/ftsvg.c create mode 100644 vendor/freetype/src/svg/ftsvg.h create mode 100644 vendor/freetype/src/svg/module.mk create mode 100644 vendor/freetype/src/svg/rules.mk create mode 100644 vendor/freetype/src/svg/svg.c create mode 100644 vendor/freetype/src/svg/svgtypes.h create mode 100644 vendor/freetype/src/tools/afblue.pl create mode 100644 vendor/freetype/src/tools/apinames.c create mode 100644 vendor/freetype/src/tools/chktrcmp.py create mode 100644 vendor/freetype/src/tools/cordic.py create mode 100644 vendor/freetype/src/tools/ftrandom/README create mode 100644 vendor/freetype/src/tools/ftrandom/ftrandom.c create mode 100644 vendor/freetype/src/tools/glnames.py create mode 100644 vendor/freetype/src/tools/make_distribution_archives.py create mode 100644 vendor/freetype/src/tools/no-copyright create mode 100644 vendor/freetype/src/tools/test_afm.c create mode 100644 vendor/freetype/src/tools/test_bbox.c create mode 100644 vendor/freetype/src/tools/test_trig.c create mode 100644 vendor/freetype/src/tools/update-copyright create mode 100644 vendor/freetype/src/tools/update-copyright-year create mode 100644 vendor/freetype/src/tools/vms_shorten_symbol.c create mode 100644 vendor/freetype/src/truetype/module.mk create mode 100644 vendor/freetype/src/truetype/rules.mk create mode 100644 vendor/freetype/src/truetype/truetype.c create mode 100644 vendor/freetype/src/truetype/ttdriver.c create mode 100644 vendor/freetype/src/truetype/ttdriver.h create mode 100644 vendor/freetype/src/truetype/tterrors.h create mode 100644 vendor/freetype/src/truetype/ttgload.c create mode 100644 vendor/freetype/src/truetype/ttgload.h create mode 100644 vendor/freetype/src/truetype/ttgxvar.c create mode 100644 vendor/freetype/src/truetype/ttgxvar.h create mode 100644 vendor/freetype/src/truetype/ttinterp.c create mode 100644 vendor/freetype/src/truetype/ttinterp.h create mode 100644 vendor/freetype/src/truetype/ttobjs.c create mode 100644 vendor/freetype/src/truetype/ttobjs.h create mode 100644 vendor/freetype/src/truetype/ttpload.c create mode 100644 vendor/freetype/src/truetype/ttpload.h create mode 100644 vendor/freetype/src/type1/module.mk create mode 100644 vendor/freetype/src/type1/rules.mk create mode 100644 vendor/freetype/src/type1/t1afm.c create mode 100644 vendor/freetype/src/type1/t1afm.h create mode 100644 vendor/freetype/src/type1/t1driver.c create mode 100644 vendor/freetype/src/type1/t1driver.h create mode 100644 vendor/freetype/src/type1/t1errors.h create mode 100644 vendor/freetype/src/type1/t1gload.c create mode 100644 vendor/freetype/src/type1/t1gload.h create mode 100644 vendor/freetype/src/type1/t1load.c create mode 100644 vendor/freetype/src/type1/t1load.h create mode 100644 vendor/freetype/src/type1/t1objs.c create mode 100644 vendor/freetype/src/type1/t1objs.h create mode 100644 vendor/freetype/src/type1/t1parse.c create mode 100644 vendor/freetype/src/type1/t1parse.h create mode 100644 vendor/freetype/src/type1/t1tokens.h create mode 100644 vendor/freetype/src/type1/type1.c create mode 100644 vendor/freetype/src/type42/module.mk create mode 100644 vendor/freetype/src/type42/rules.mk create mode 100644 vendor/freetype/src/type42/t42drivr.c create mode 100644 vendor/freetype/src/type42/t42drivr.h create mode 100644 vendor/freetype/src/type42/t42error.h create mode 100644 vendor/freetype/src/type42/t42objs.c create mode 100644 vendor/freetype/src/type42/t42objs.h create mode 100644 vendor/freetype/src/type42/t42parse.c create mode 100644 vendor/freetype/src/type42/t42parse.h create mode 100644 vendor/freetype/src/type42/t42types.h create mode 100644 vendor/freetype/src/type42/type42.c create mode 100644 vendor/freetype/src/winfonts/fnterrs.h create mode 100644 vendor/freetype/src/winfonts/module.mk create mode 100644 vendor/freetype/src/winfonts/rules.mk create mode 100644 vendor/freetype/src/winfonts/winfnt.c create mode 100644 vendor/freetype/src/winfonts/winfnt.h create mode 100644 vendor/freetype/subprojects/harfbuzz.wrap create mode 100644 vendor/freetype/subprojects/libpng.wrap create mode 100644 vendor/freetype/subprojects/zlib.wrap create mode 100644 vendor/ogg/AUTHORS create mode 100644 vendor/ogg/COPYING create mode 100644 vendor/ogg/README.md create mode 100644 vendor/ogg/build-ogg.lua create mode 100644 vendor/ogg/include/Makefile.am create mode 100644 vendor/ogg/include/ogg/Makefile.am create mode 100644 vendor/ogg/include/ogg/config_types.h.in create mode 100644 vendor/ogg/include/ogg/ogg.h create mode 100644 vendor/ogg/include/ogg/os_types.h create mode 100644 vendor/ogg/lib/ogg.idb create mode 100644 vendor/ogg/lib/ogg.lib create mode 100644 vendor/ogg/libogg.spec.in create mode 100644 vendor/ogg/ogg-uninstalled.pc.in create mode 100644 vendor/ogg/ogg.m4 create mode 100644 vendor/ogg/ogg.pc.in create mode 100644 vendor/ogg/releases.sha2 create mode 100644 vendor/ogg/src/Makefile.am create mode 100644 vendor/ogg/src/bitwise.c create mode 100644 vendor/ogg/src/crctable.h create mode 100644 vendor/ogg/src/framing.c create mode 100644 vendor/vorbis/AUTHORS create mode 100644 vendor/vorbis/COPYING create mode 100644 vendor/vorbis/README.md create mode 100644 vendor/vorbis/build-vorbis.lua create mode 100644 vendor/vorbis/contrib/oss-fuzz/build.sh create mode 100644 vendor/vorbis/contrib/oss-fuzz/decode_fuzzer.cc create mode 100644 vendor/vorbis/debian/changelog create mode 100644 vendor/vorbis/debian/control create mode 100644 vendor/vorbis/debian/copyright create mode 100644 vendor/vorbis/debian/libvorbis-dev.docs create mode 100644 vendor/vorbis/debian/libvorbis-dev.examples create mode 100644 vendor/vorbis/debian/libvorbis-dev.install create mode 100644 vendor/vorbis/debian/libvorbis0a.install create mode 100644 vendor/vorbis/debian/libvorbisenc2.install create mode 100644 vendor/vorbis/debian/libvorbisfile3.install create mode 100644 vendor/vorbis/debian/rules create mode 100644 vendor/vorbis/debian/watch create mode 100644 vendor/vorbis/include/Makefile.am create mode 100644 vendor/vorbis/include/vorbis/Makefile.am create mode 100644 vendor/vorbis/include/vorbis/codec.h create mode 100644 vendor/vorbis/include/vorbis/vorbisenc.h create mode 100644 vendor/vorbis/include/vorbis/vorbisfile.h create mode 100644 vendor/vorbis/lib/Makefile.am create mode 100644 vendor/vorbis/lib/analysis.c create mode 100644 vendor/vorbis/lib/backends.h create mode 100644 vendor/vorbis/lib/barkmel.c create mode 100644 vendor/vorbis/lib/bitrate.c create mode 100644 vendor/vorbis/lib/bitrate.h create mode 100644 vendor/vorbis/lib/block.c create mode 100644 vendor/vorbis/lib/books/Makefile.am create mode 100644 vendor/vorbis/lib/books/coupled/Makefile.am create mode 100644 vendor/vorbis/lib/books/coupled/res_books_51.h create mode 100644 vendor/vorbis/lib/books/coupled/res_books_stereo.h create mode 100644 vendor/vorbis/lib/books/floor/Makefile.am create mode 100644 vendor/vorbis/lib/books/floor/floor_books.h create mode 100644 vendor/vorbis/lib/books/uncoupled/Makefile.am create mode 100644 vendor/vorbis/lib/books/uncoupled/res_books_uncoupled.h create mode 100644 vendor/vorbis/lib/codebook.c create mode 100644 vendor/vorbis/lib/codebook.h create mode 100644 vendor/vorbis/lib/codec_internal.h create mode 100644 vendor/vorbis/lib/envelope.c create mode 100644 vendor/vorbis/lib/envelope.h create mode 100644 vendor/vorbis/lib/floor0.c create mode 100644 vendor/vorbis/lib/floor1.c create mode 100644 vendor/vorbis/lib/highlevel.h create mode 100644 vendor/vorbis/lib/info.c create mode 100644 vendor/vorbis/lib/lookup.c create mode 100644 vendor/vorbis/lib/lookup.h create mode 100644 vendor/vorbis/lib/lookup_data.h create mode 100644 vendor/vorbis/lib/lookups.pl create mode 100644 vendor/vorbis/lib/lpc.c create mode 100644 vendor/vorbis/lib/lpc.h create mode 100644 vendor/vorbis/lib/lsp.c create mode 100644 vendor/vorbis/lib/lsp.h create mode 100644 vendor/vorbis/lib/mapping0.c create mode 100644 vendor/vorbis/lib/masking.h create mode 100644 vendor/vorbis/lib/mdct.c create mode 100644 vendor/vorbis/lib/mdct.h create mode 100644 vendor/vorbis/lib/misc.c create mode 100644 vendor/vorbis/lib/misc.h create mode 100644 vendor/vorbis/lib/modes/Makefile.am create mode 100644 vendor/vorbis/lib/modes/floor_all.h create mode 100644 vendor/vorbis/lib/modes/psych_11.h create mode 100644 vendor/vorbis/lib/modes/psych_16.h create mode 100644 vendor/vorbis/lib/modes/psych_44.h create mode 100644 vendor/vorbis/lib/modes/psych_8.h create mode 100644 vendor/vorbis/lib/modes/residue_16.h create mode 100644 vendor/vorbis/lib/modes/residue_44.h create mode 100644 vendor/vorbis/lib/modes/residue_44p51.h create mode 100644 vendor/vorbis/lib/modes/residue_44u.h create mode 100644 vendor/vorbis/lib/modes/residue_8.h create mode 100644 vendor/vorbis/lib/modes/setup_11.h create mode 100644 vendor/vorbis/lib/modes/setup_16.h create mode 100644 vendor/vorbis/lib/modes/setup_22.h create mode 100644 vendor/vorbis/lib/modes/setup_32.h create mode 100644 vendor/vorbis/lib/modes/setup_44.h create mode 100644 vendor/vorbis/lib/modes/setup_44p51.h create mode 100644 vendor/vorbis/lib/modes/setup_44u.h create mode 100644 vendor/vorbis/lib/modes/setup_8.h create mode 100644 vendor/vorbis/lib/modes/setup_X.h create mode 100644 vendor/vorbis/lib/os.h create mode 100644 vendor/vorbis/lib/psy.c create mode 100644 vendor/vorbis/lib/psy.h create mode 100644 vendor/vorbis/lib/psytune.c create mode 100644 vendor/vorbis/lib/registry.c create mode 100644 vendor/vorbis/lib/registry.h create mode 100644 vendor/vorbis/lib/res0.c create mode 100644 vendor/vorbis/lib/scales.h create mode 100644 vendor/vorbis/lib/sharedbook.c create mode 100644 vendor/vorbis/lib/smallft.c create mode 100644 vendor/vorbis/lib/smallft.h create mode 100644 vendor/vorbis/lib/synthesis.c create mode 100644 vendor/vorbis/lib/tone.c create mode 100644 vendor/vorbis/lib/vorbisenc.c create mode 100644 vendor/vorbis/lib/vorbisfile.c create mode 100644 vendor/vorbis/lib/window.c create mode 100644 vendor/vorbis/lib/window.h create mode 100644 vendor/vorbis/symbian/bld.inf create mode 100644 vendor/vorbis/symbian/config.h create mode 100644 vendor/vorbis/symbian/vorbis.mmp create mode 100644 vendor/vorbis/test/Makefile.am create mode 100644 vendor/vorbis/test/test.c create mode 100644 vendor/vorbis/test/util.c create mode 100644 vendor/vorbis/test/util.h create mode 100644 vendor/vorbis/test/write_read.c create mode 100644 vendor/vorbis/test/write_read.h create mode 100644 vendor/vorbis/vq/16.vqs create mode 100644 vendor/vorbis/vq/16u.vqs create mode 100644 vendor/vorbis/vq/44c-1.vqs create mode 100644 vendor/vorbis/vq/44c0.vqs create mode 100644 vendor/vorbis/vq/44c1.vqs create mode 100644 vendor/vorbis/vq/44c2.vqs create mode 100644 vendor/vorbis/vq/44c3.vqs create mode 100644 vendor/vorbis/vq/44c4.vqs create mode 100644 vendor/vorbis/vq/44c5.vqs create mode 100644 vendor/vorbis/vq/44c6.vqs create mode 100644 vendor/vorbis/vq/44c7.vqs create mode 100644 vendor/vorbis/vq/44c8.vqs create mode 100644 vendor/vorbis/vq/44c9.vqs create mode 100644 vendor/vorbis/vq/44p-1.vqs create mode 100644 vendor/vorbis/vq/44p0.vqs create mode 100644 vendor/vorbis/vq/44p1.vqs create mode 100644 vendor/vorbis/vq/44p2.vqs create mode 100644 vendor/vorbis/vq/44p3.vqs create mode 100644 vendor/vorbis/vq/44p4.vqs create mode 100644 vendor/vorbis/vq/44p5.vqs create mode 100644 vendor/vorbis/vq/44p6.vqs create mode 100644 vendor/vorbis/vq/44p7.vqs create mode 100644 vendor/vorbis/vq/44p8.vqs create mode 100644 vendor/vorbis/vq/44p9.vqs create mode 100644 vendor/vorbis/vq/44u0.vqs create mode 100644 vendor/vorbis/vq/44u1.vqs create mode 100644 vendor/vorbis/vq/44u2.vqs create mode 100644 vendor/vorbis/vq/44u3.vqs create mode 100644 vendor/vorbis/vq/44u4.vqs create mode 100644 vendor/vorbis/vq/44u5.vqs create mode 100644 vendor/vorbis/vq/44u6.vqs create mode 100644 vendor/vorbis/vq/44u7.vqs create mode 100644 vendor/vorbis/vq/44u8.vqs create mode 100644 vendor/vorbis/vq/44u9.vqs create mode 100644 vendor/vorbis/vq/8.vqs create mode 100644 vendor/vorbis/vq/8u.vqs create mode 100644 vendor/vorbis/vq/Makefile.am create mode 100644 vendor/vorbis/vq/bookutil.c create mode 100644 vendor/vorbis/vq/bookutil.h create mode 100644 vendor/vorbis/vq/distribution.c create mode 100644 vendor/vorbis/vq/floor_11.vqs create mode 100644 vendor/vorbis/vq/floor_22.vqs create mode 100644 vendor/vorbis/vq/floor_44.vqs create mode 100644 vendor/vorbis/vq/huffbuild.c create mode 100644 vendor/vorbis/vq/latticebuild.c create mode 100644 vendor/vorbis/vq/latticetune.c create mode 100644 vendor/vorbis/vq/localcodebook.h create mode 100644 vendor/vorbis/vq/make_floor_books.pl create mode 100644 vendor/vorbis/vq/make_residue_books.pl create mode 100644 vendor/vorbis/vq/metrics.c create mode 100644 vendor/vorbis/vq/vqgen.c create mode 100644 vendor/vorbis/vq/vqgen.h diff --git a/Create-Solution.bat b/Create-Solution.bat index 48b428c..2cd4d72 100644 --- a/Create-Solution.bat +++ b/Create-Solution.bat @@ -1,3 +1,2 @@ -echo SFML will be downloaded and built from source, this may take a while depending on your system. .\vendor\premake5\premake5.exe vs2022 PAUSE \ No newline at end of file diff --git a/premake5.lua b/premake5.lua index c39d918..575e8bb 100644 --- a/premake5.lua +++ b/premake5.lua @@ -3,42 +3,27 @@ require "ninja/ninja" workspace "snake" architecture "x64" - + startproject"snake" configurations { "Debug", "Release" } - prebuildcommands { - "git clone https://github.com/SFML/SFML.git vendor/SFML", - "cd vendor/SFML && git checkout 3.0.2", - } - filter "action:vs*" - prebuildcommands - { - "cd vendor/SFML && cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=0 -DSFML_BUILD_AUDIO=1 -DSFML_BUILD_GRAPHICS=1 -DSFML_BUILD_WINDOW=1 -DSFML_USE_STATIC_STD_LIBS=1 -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=./lib" - } project_dir = "$(SolutionDir)" - filter "action:gmake" - prebuildcommands - { - "cd vendor/SFML && cmake -S . -B build -G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=0 -DSFML_BUILD_AUDIO=1 -DSFML_BUILD_GRAPHICS=1 -DSFML_BUILD_WINDOW=1", - "cd vendor/SFML && cmake --build build" - } + filter "system:windows" project_dir = "%{wks.location}/" + group "Dependencies" + include "vendor/ogg/build-ogg.lua" + include "vendor/vorbis/build-vorbis.lua" + include "vendor/flac/build-flac.lua" + include "vendor/freetype/build-freetype.lua" + include "vendor/sfml/build-sfml.lua" - filter "action:premake-ninja" - prebuildcommands - { - "cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=0 -DSFML_BUILD_AUDIO=1 -DSFML_BUILD_GRAPHICS=1 -DSFML_BUILD_WINDOW=1", - "cmake --build build" - } - project_dir = "%{wks.location}/" - filter"" + group"" project "snake" output_dir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}" @@ -56,6 +41,7 @@ workspace "snake" targetdir (bindir) objdir (intdir) debugdir (project_dir) + links {"sfml"} includedirs { "src", @@ -81,43 +67,25 @@ workspace "snake" --windows specific settings-- filter{"system:windows"} defines {"PLATFORM_WINDOWS", "SFML_STATIC"} - staticruntime "on" + staticruntime "off" filter {"system:windows", "configurations:debug"} defines{"_DEBUG", "_CONSOLE"} links { - "sfml-main-d", - "sfml-graphics-s-d", - "sfml-window-s-d", + "legacy_stdio_definitions", "opengl32", "gdi32", - "freetyped", - "sfml-audio-s-d", - "flacd", - "vorbisfiled", - "vorbisd", - "oggd", - "sfml-system-s-d", - "winmm" + "winmm", + "ws2_32" } filter {"system:windows", "configurations:release"} defines{"NDEBUG"} links { - "sfml-main", - "sfml-graphics-s", - "sfml-window-s", "opengl32", "gdi32", - "freetype", - "sfml-audio-s", - "flac", - "vorbisfile", - "vorbis", - "ogg", - "sfml-system-s", "winmm" } diff --git a/vendor/flac/AUTHORS b/vendor/flac/AUTHORS new file mode 100644 index 0000000..34c5f89 --- /dev/null +++ b/vendor/flac/AUTHORS @@ -0,0 +1,60 @@ +/* FLAC - Free Lossless Audio Codec + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This file is part the FLAC project. FLAC is comprised of several + * components distributed under different licenses. The codec libraries + * are distributed under Xiph.Org's BSD-like license (see the file + * COPYING.Xiph in this distribution). All other programs, libraries, and + * plugins are distributed under the GPL (see COPYING.GPL). The documentation + * is distributed under the Gnu FDL (see COPYING.FDL). Each file in the + * FLAC distribution contains at the top the terms under which it may be + * distributed. + * + * Since this particular file is relevant to all components of FLAC, + * it may be distributed under the Xiph.Org license, which is the least + * restrictive of those mentioned above. See the file COPYING.Xiph in this + * distribution. + */ + +This file lists major contributors to the FLAC project. This list is not +exhaustive. For an exhaustive list, run the command `git shortlog -s` on +the git repo or visit https://gitlab.xiph.org/xiph/flac/-/graphs/master + +For a complete list of contributions, run the command `git log` on the +git repo, visit https://github.com/xiph/flac/commits or visit +https://gitlab.xiph.org/xiph/flac/commits + +Original author: Josh Coalson +Maintainer 2012-2020: Erik de Castro Lopo +Maintainer from 2022: Martijn van Beurden + +Website : https://www.xiph.org/flac/ + +Other major contributors and their contributions: + +"lvqcl" +* Visual Studio build system. +* Optimisations in the encoder and decoder. + +"Janne Hyvärinen" +* Visual Studio build system. +* Unicode handling on Windows. + +"Andrey Astafiev" +* Russian translation of the HTML documentation + +"Miroslav Lichvar" +* IA-32 assembly versions of several libFLAC routines + +"Brady Patterson" +* AIFF file support, PPC assembly versions of libFLAC routines + +"Daisuke Shimamura" +* i18n support in the XMMS plugin + +"X-Fixer" +* Configuration system, tag editing, and file info in the Winamp2 plugin + +"Matt Zimmerman" +* Libtool/autoconf/automake make system, flac man page diff --git a/vendor/flac/COPYING.FDL b/vendor/flac/COPYING.FDL new file mode 100644 index 0000000..4a0fe1c --- /dev/null +++ b/vendor/flac/COPYING.FDL @@ -0,0 +1,397 @@ + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/vendor/flac/COPYING.GPL b/vendor/flac/COPYING.GPL new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/vendor/flac/COPYING.GPL @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/vendor/flac/COPYING.LGPL b/vendor/flac/COPYING.LGPL new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/vendor/flac/COPYING.LGPL @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/vendor/flac/COPYING.Xiph b/vendor/flac/COPYING.Xiph new file mode 100644 index 0000000..86629af --- /dev/null +++ b/vendor/flac/COPYING.Xiph @@ -0,0 +1,29 @@ +Copyright (C) 2000-2009 Josh Coalson +Copyright (C) 2011-2023 Xiph.Org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.Org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/flac/README.md b/vendor/flac/README.md new file mode 100644 index 0000000..2979862 --- /dev/null +++ b/vendor/flac/README.md @@ -0,0 +1,278 @@ + + +# Free Lossless Audio Codec (FLAC) + +FLAC is open source software that can reduce the amount of storage space +needed to store digital audio signals without needing to remove +information in doing so. + +The files read and produced by this software are called FLAC files. As +these files (which follow the [FLAC format](https://xiph.org/flac/format.html)) +can be read from and written to by other software as well, this software +is often referred to as the FLAC reference implementation. + +FLAC has been developed by volunteers. If you want to help out, see +CONTRIBUTING.md for more information. + +## Components + +FLAC is comprised of + * libFLAC, a library which implements reference encoders and + decoders for native FLAC and Ogg FLAC, and a metadata interface + * libFLAC++, a C++ object wrapper library around libFLAC + * `flac`, a command-line program for encoding and decoding files + * `metaflac`, a command-line program for viewing and editing FLAC + metadata + * user and API documentation + +The libraries (libFLAC, libFLAC++) are licensed under Xiph.org's +BSD-like license (see COPYING.Xiph). All other programs and plugins are +licensed under the GNU General Public License (see COPYING.GPL). The +documentation is licensed under the GNU Free Documentation License +(see COPYING.FDL). + +## Documentation + +For documentation of the `flac` and `metaflac` command line tools, see +the directory man, which contains the files flac.md and metaflac.md + +The API documentation is in html and is generated by Doxygen. It can be +found in the directory doc/html/api. It is included in a release tarball +and must be build with Doxygen when the source is taken directly from +git. + +The directory examples contains example source code on using libFLAC and +libFLAC++. + +Documentation concerning the FLAC format itself (which can be used to +create software reading and writing FLAC software independent from +libFLAC) was included in previous releases, but can now be found on +https://datatracker.ietf.org/doc/draft-ietf-cellar-flac/ Additionally +a set of files for conformance testing called the FLAC decoder testbench +can be found at https://github.com/ietf-wg-cellar/flac-test-files + +If you have questions about FLAC that this document does not answer, +please submit them at the following tracker so this document can be +improved: + +https://github.com/xiph/flac/issues + +## Building FLAC + +All components of the FLAC project can be build with a variety of +compilers (including GCC, Clang, Visual Studio, Intel C++ Compiler) on +many architectures (inluding x86, x86_64, ARMv7, ARMv8 and PowerPC) +for many different operating systems. + +To do this, FLAC provides two build systems: one using GNU's autotools +and one with CMake. Both differ slighly in configuration options, but +should be considered equivalent for most use cases. + +FLAC used to provide files specifically for building with Visual Studio, +but these have been removed in favor of using CMake. + +## Building with CMake + +CMake is a cross-platform build system. FLAC can be built on Windows, +Linux, Mac OS X using CMake. + +You can use either CMake's CLI or GUI. We recommend you to have a +separate build folder outside the repository in order to not spoil it +with generated files. It is possible however to do a so-called in-tree +build, in that case /path/to/flac-build in the following examples is +equal to /path/to/flac-source. + +### CMake CLI + +Go to your build folder and run something like this: + +``` +/path/to/flac-build$ cmake /path/to/flac-source +``` + +or e.g. in Windows shell + +``` +C:\path\to\flac-build> cmake \path\to\flac-source +``` + +(provided that cmake is in your %PATH% variable) + +That will generate build scripts for the default build system (e.g. +Makefiles for UNIX). After that you start build with a command like +this: + +``` +/path/to/flac-build$ make +``` + +And afterwards you can run tests or install the built libraries and +headers + +``` +/path/to/flac-build$ make test +/path/to/flac-build$ make install +``` + +If you want use a build system other than default add -G flag to cmake, +e.g.: + +``` +/path/to/flac-build$ cmake /path/to/flac-source -GNinja +/path/to/flac-build$ ninja +``` + +or: + +``` +/path/to/flac-build$ cmake /path/to/flac-source -GXcode +``` + +Use cmake --help to see the list of available generators. + +By default CMake will search for OGG. If CMake fails to find it you can +help CMake by specifying the exact path: + +``` +/path/to/flac-build$ cmake /path/to/flac-source -DOGG_ROOT=/path/to/ogg +``` + +If you would like CMake to build OGG alongside FLAC, you can place the +ogg sources directly in the flac source directory as a subdirectory with +the name ogg, for example: + +``` +/path/to/flac-source/ogg +``` + +If you don't want to build flac with OGG support you can tell CMake not +to look for OGG: + +``` +/path/to/flac-build$ cmake /path/to/flac-source -DWITH_OGG=OFF +``` + +Other FLAC's options (e.g. building C++ lib or docs) can also be put to +cmake through -D flag. If you want to know what options are available, +use -LH: + +``` +/path/to/flac-build$ cmake /path/to/flac-source -LH +``` + +### CMake GUI (for Visual Studio) +It is likely that you would prefer to use the CMake GUI if you use +Visual Studio to build FLAC. It's in essence the same process as +building using CLI. + +Open cmake-gui. In the window select a source directory (the +repository's root), a build directory (some other directory outside the +repository). Then press button "Configure". CMake will ask you which +build system you prefer. Choose that version of Visual Studio which you +have on your system, choose whether you want to build for Win32 or x64. +Press OK. + +After CMake finishes you can change the configuration to your liking and +if you change anything, run Configure again. With the "Generate" button, +CMake creates Visual Studio files, which can be opened from Visual +Studio. With the button "Open Project" CMake will launch Visual Studio +and open the generated solution. You can use the project files as usual +but remember that they were generated by CMake. That means that your +changes (e.g. some additional compile flags) will be lost when you run +CMake next time. + +CMake searches by default for OGG on your system and returns an error +if it cannot find it. If you want to build OGG alongside FLAC, you can +download the OGG sources and extract them in a subdirectory of the FLAC +source directory with the name ogg (i.e. /path/to/flac-source/ogg) +before running CMake. If you don't want to build FLAC with OGG support, +untick the box following WITH_OGG flag in the list of variables in +cmake-gui window and run "Configure" again. + +If CMake fails to find MSVC compiler then running cmake-gui from MS +Developer comand prompt should help. + +## Building with GNU autotools + +FLAC uses autoconf and libtool for configuring and building. To +configure a build, open a commmand line/terminal and run `./configure` +You can provide options to this command, which are listed by running +`./configure --help`. + +In case the configure script is not present (for example when building +from git and not from a release tarball), it can be generated by running +`./autogen.sh`. This may require a libtool development package though. + +After configuration, build with `make`, verify the build with +`make check` and install with `make install`. Installation might require +administrator priviledged, i.e. `sudo make install`. + +The 'make check' step is optional; omit it to skip all the tests, which +can take about an hour to complete. Even though it will stop with an +explicit message on any failure, it does print out a lot of stuff so you +might want to capture the output to a file if you're having a problem. +Also, don't run 'make check' as root because it confuses some of the +tests. + +Summarizing: + +``` +./configure +make && make check +sudo make install +``` + +## Note to embedded developers + +libFLAC has grown larger over time as more functionality has been +included, but much of it may be unnecessary for a particular embedded +implementation. Unused parts may be pruned by some simple editing of +configure.ac and src/libFLAC/Makefile.am; the following dependency +graph shows which modules may be pruned without breaking things +further down: + +``` +metadata.h + stream_decoder.h + format.h + +stream_encoder.h + stream_decoder.h + format.h + +stream_decoder.h + format.h +``` + +In other words, for pure decoding applications, both the stream encoder +and metadata editing interfaces can be safely removed. Note that this +is specific to building the libraries for embedded use. The command line +tools do not provide such compartmentalization, and require a complete +libFLAC build to function. + +There is a section dedicated to embedded use in the libFLAC API +HTML documentation (see doc/html/api/index.html). + +Also, there are several places in the libFLAC code with comments marked +with "OPT:" where a #define can be changed to enable code that might be +faster on a specific platform. Experimenting with these can yield +faster binaries. diff --git a/vendor/flac/build-flac.lua b/vendor/flac/build-flac.lua new file mode 100644 index 0000000..ba0f806 --- /dev/null +++ b/vendor/flac/build-flac.lua @@ -0,0 +1,44 @@ +project"flac" + cppdialect"c++17" + kind"staticLib" + targetdir"lib" + staticruntime "off" + + defines + { + "FLAC__NO_DLL", + "CPU_IS_BIG_ENDIAN=0", + "FLAC__HAS_OGG=1", + "PACKAGE_VERSION=\"\"" + } + + includedirs + { + "include", + "src/libFLAC/include", + "../ogg/include" + } + + files + { + "src/libFLAC/**.c", + } + + removefiles + { + "src/libFLAC/deduplication/**" + } + + filter"system:windows" + files + { + "src/share/win_utf8_io/**.c" + } + + filter "configurations:Debug" + runtime "Debug" + symbols "on" + + filter "configurations:Release" + runtime "Release" + optimize "Speed" \ No newline at end of file diff --git a/vendor/flac/include/FLAC++/Makefile.am b/vendor/flac/include/FLAC++/Makefile.am new file mode 100644 index 0000000..ba5daa5 --- /dev/null +++ b/vendor/flac/include/FLAC++/Makefile.am @@ -0,0 +1,39 @@ +# libFLAC++ - Free Lossless Audio Codec library +# Copyright (C) 2002-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +flaccppincludedir = $(includedir)/FLAC++ +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +flaccppinclude_HEADERS = \ + all.h \ + decoder.h \ + encoder.h \ + export.h \ + metadata.h diff --git a/vendor/flac/include/FLAC++/all.h b/vendor/flac/include/FLAC++/all.h new file mode 100644 index 0000000..fa5bd41 --- /dev/null +++ b/vendor/flac/include/FLAC++/all.h @@ -0,0 +1,49 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLACPP__ALL_H +#define FLACPP__ALL_H + +#include "export.h" + +#include "encoder.h" +#include "decoder.h" +#include "metadata.h" + +/** \defgroup flacpp FLAC C++ API + * + * The FLAC C++ API is the interface to libFLAC++, a set of classes + * that encapsulate the encoders, decoders, and metadata interfaces + * in libFLAC. + */ + +#endif diff --git a/vendor/flac/include/FLAC++/decoder.h b/vendor/flac/include/FLAC++/decoder.h new file mode 100644 index 0000000..6f0bda9 --- /dev/null +++ b/vendor/flac/include/FLAC++/decoder.h @@ -0,0 +1,248 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLACPP__DECODER_H +#define FLACPP__DECODER_H + +#include "export.h" + +#include +#include "FLAC/stream_decoder.h" + + +/** \file include/FLAC++/decoder.h + * + * \brief + * This module contains the classes which implement the various + * decoders. + * + * See the detailed documentation in the + * \link flacpp_decoder decoder \endlink module. + */ + +/** \defgroup flacpp_decoder FLAC++/decoder.h: decoder classes + * \ingroup flacpp + * + * \brief + * This module describes the decoder layers provided by libFLAC++. + * + * The libFLAC++ decoder classes are object wrappers around their + * counterparts in libFLAC. All decoding layers available in + * libFLAC are also provided here. The interface is very similar; + * make sure to read the \link flac_decoder libFLAC decoder module \endlink. + * + * There are only two significant differences here. First, instead of + * passing in C function pointers for callbacks, you inherit from the + * decoder class and provide implementations for the callbacks in your + * derived class; because of this there is no need for a 'client_data' + * property. + * + * Second, there are two stream decoder classes. FLAC::Decoder::Stream + * is used for the same cases that FLAC__stream_decoder_init_stream() / + * FLAC__stream_decoder_init_ogg_stream() are used, and FLAC::Decoder::File + * is used for the same cases that + * FLAC__stream_decoder_init_FILE() and FLAC__stream_decoder_init_file() / + * FLAC__stream_decoder_init_ogg_FILE() and FLAC__stream_decoder_init_ogg_file() + * are used. + */ + +namespace FLAC { + namespace Decoder { + + /** \ingroup flacpp_decoder + * \brief + * This class wraps the ::FLAC__StreamDecoder. If you are + * decoding from a file, FLAC::Decoder::File may be more + * convenient. + * + * The usage of this class is similar to FLAC__StreamDecoder, + * except instead of providing callbacks to + * FLAC__stream_decoder_init*_stream(), you will inherit from this + * class and override the virtual callback functions with your + * own implementations, then call init() or init_ogg(). The rest + * of the calls work the same as in the C layer. + * + * Only the read, write, and error callbacks are mandatory. The + * others are optional; this class provides default + * implementations that do nothing. In order for seeking to work + * you must override seek_callback(), tell_callback(), + * length_callback(), and eof_callback(). + */ + class FLACPP_API Stream { + public: + /** This class is a wrapper around FLAC__StreamDecoderState. + */ + class FLACPP_API State { + public: + inline State(::FLAC__StreamDecoderState state): state_(state) { } + inline operator ::FLAC__StreamDecoderState() const { return state_; } + inline const char *as_cstring() const { return ::FLAC__StreamDecoderStateString[state_]; } + inline const char *resolved_as_cstring(const Stream &decoder) const { return ::FLAC__stream_decoder_get_resolved_state_string(decoder.decoder_); } + protected: + ::FLAC__StreamDecoderState state_; + }; + + Stream(); + virtual ~Stream(); + + //@{ + /** Call after construction to check that the object was created + * successfully. If not, use get_state() to find out why not. + */ + virtual bool is_valid() const; + inline operator bool() const { return is_valid(); } ///< See is_valid() + //@} + + virtual bool set_ogg_serial_number(long value); ///< See FLAC__stream_decoder_set_ogg_serial_number() + virtual bool set_md5_checking(bool value); ///< See FLAC__stream_decoder_set_md5_checking() + virtual bool set_metadata_respond(::FLAC__MetadataType type); ///< See FLAC__stream_decoder_set_metadata_respond() + virtual bool set_metadata_respond_application(const FLAC__byte id[4]); ///< See FLAC__stream_decoder_set_metadata_respond_application() + virtual bool set_metadata_respond_all(); ///< See FLAC__stream_decoder_set_metadata_respond_all() + virtual bool set_metadata_ignore(::FLAC__MetadataType type); ///< See FLAC__stream_decoder_set_metadata_ignore() + virtual bool set_metadata_ignore_application(const FLAC__byte id[4]); ///< See FLAC__stream_decoder_set_metadata_ignore_application() + virtual bool set_metadata_ignore_all(); ///< See FLAC__stream_decoder_set_metadata_ignore_all() + + /* get_state() is not virtual since we want subclasses to be able to return their own state */ + State get_state() const; ///< See FLAC__stream_decoder_get_state() + virtual bool get_md5_checking() const; ///< See FLAC__stream_decoder_get_md5_checking() + virtual FLAC__uint64 get_total_samples() const; ///< See FLAC__stream_decoder_get_total_samples() + virtual uint32_t get_channels() const; ///< See FLAC__stream_decoder_get_channels() + virtual ::FLAC__ChannelAssignment get_channel_assignment() const; ///< See FLAC__stream_decoder_get_channel_assignment() + virtual uint32_t get_bits_per_sample() const; ///< See FLAC__stream_decoder_get_bits_per_sample() + virtual uint32_t get_sample_rate() const; ///< See FLAC__stream_decoder_get_sample_rate() + virtual uint32_t get_blocksize() const; ///< See FLAC__stream_decoder_get_blocksize() + virtual bool get_decode_position(FLAC__uint64 *position) const; ///< See FLAC__stream_decoder_get_decode_position() + + virtual ::FLAC__StreamDecoderInitStatus init(); ///< Seek FLAC__stream_decoder_init_stream() + virtual ::FLAC__StreamDecoderInitStatus init_ogg(); ///< Seek FLAC__stream_decoder_init_ogg_stream() + + virtual bool finish(); ///< See FLAC__stream_decoder_finish() + + virtual bool flush(); ///< See FLAC__stream_decoder_flush() + virtual bool reset(); ///< See FLAC__stream_decoder_reset() + + virtual bool process_single(); ///< See FLAC__stream_decoder_process_single() + virtual bool process_until_end_of_metadata(); ///< See FLAC__stream_decoder_process_until_end_of_metadata() + virtual bool process_until_end_of_stream(); ///< See FLAC__stream_decoder_process_until_end_of_stream() + virtual bool skip_single_frame(); ///< See FLAC__stream_decoder_skip_single_frame() + + virtual bool seek_absolute(FLAC__uint64 sample); ///< See FLAC__stream_decoder_seek_absolute() + protected: + /// see FLAC__StreamDecoderReadCallback + virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) = 0; + + /// see FLAC__StreamDecoderSeekCallback + virtual ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + + /// see FLAC__StreamDecoderTellCallback + virtual ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); + + /// see FLAC__StreamDecoderLengthCallback + virtual ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length); + + /// see FLAC__StreamDecoderEofCallback + virtual bool eof_callback(); + + /// see FLAC__StreamDecoderWriteCallback + virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) = 0; + + /// see FLAC__StreamDecoderMetadataCallback + virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata); + + /// see FLAC__StreamDecoderErrorCallback + virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) = 0; + +#if (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC) + // lame hack: some compilers can't see a protected decoder_ from nested State::resolved_as_cstring() + friend State; +#endif + ::FLAC__StreamDecoder *decoder_; + + static ::FLAC__StreamDecoderReadStatus read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + static ::FLAC__StreamDecoderSeekStatus seek_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); + static ::FLAC__StreamDecoderTellStatus tell_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + static ::FLAC__StreamDecoderLengthStatus length_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); + static FLAC__bool eof_callback_(const ::FLAC__StreamDecoder *decoder, void *client_data); + static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); + static void metadata_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data); + static void error_callback_(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data); + private: + // Private and undefined so you can't use them: + Stream(const Stream &); + void operator=(const Stream &); + }; + + /** \ingroup flacpp_decoder + * \brief + * This class wraps the ::FLAC__StreamDecoder. If you are + * not decoding from a file, you may need to use + * FLAC::Decoder::Stream. + * + * The usage of this class is similar to FLAC__StreamDecoder, + * except instead of providing callbacks to + * FLAC__stream_decoder_init*_FILE() or + * FLAC__stream_decoder_init*_file(), you will inherit from this + * class and override the virtual callback functions with your + * own implementations, then call init() or init_off(). The rest + * of the calls work the same as in the C layer. + * + * Only the write, and error callbacks from FLAC::Decoder::Stream + * are mandatory. The others are optional; this class provides + * full working implementations for all other callbacks and + * supports seeking. + */ + class FLACPP_API File: public Stream { + public: + File(); + virtual ~File(); + + using Stream::init; + virtual ::FLAC__StreamDecoderInitStatus init(FILE *file); ///< See FLAC__stream_decoder_init_FILE() + virtual ::FLAC__StreamDecoderInitStatus init(const char *filename); ///< See FLAC__stream_decoder_init_file() + virtual ::FLAC__StreamDecoderInitStatus init(const std::string &filename); ///< See FLAC__stream_decoder_init_file() + using Stream::init_ogg; + virtual ::FLAC__StreamDecoderInitStatus init_ogg(FILE *file); ///< See FLAC__stream_decoder_init_ogg_FILE() + virtual ::FLAC__StreamDecoderInitStatus init_ogg(const char *filename); ///< See FLAC__stream_decoder_init_ogg_file() + virtual ::FLAC__StreamDecoderInitStatus init_ogg(const std::string &filename); ///< See FLAC__stream_decoder_init_ogg_file() + protected: + // this is a dummy implementation to satisfy the pure virtual in Stream that is actually supplied internally by the C layer + virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes); + private: + // Private and undefined so you can't use them: + File(const File &); + void operator=(const File &); + }; + + } +} + +#endif diff --git a/vendor/flac/include/FLAC++/encoder.h b/vendor/flac/include/FLAC++/encoder.h new file mode 100644 index 0000000..2400823 --- /dev/null +++ b/vendor/flac/include/FLAC++/encoder.h @@ -0,0 +1,265 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLACPP__ENCODER_H +#define FLACPP__ENCODER_H + +#include "export.h" + +#include "FLAC/stream_encoder.h" +#include "decoder.h" +#include "metadata.h" + + +/** \file include/FLAC++/encoder.h + * + * \brief + * This module contains the classes which implement the various + * encoders. + * + * See the detailed documentation in the + * \link flacpp_encoder encoder \endlink module. + */ + +/** \defgroup flacpp_encoder FLAC++/encoder.h: encoder classes + * \ingroup flacpp + * + * \brief + * This module describes the encoder layers provided by libFLAC++. + * + * The libFLAC++ encoder classes are object wrappers around their + * counterparts in libFLAC. All encoding layers available in + * libFLAC are also provided here. The interface is very similar; + * make sure to read the \link flac_encoder libFLAC encoder module \endlink. + * + * There are only two significant differences here. First, instead of + * passing in C function pointers for callbacks, you inherit from the + * encoder class and provide implementations for the callbacks in your + * derived class; because of this there is no need for a 'client_data' + * property. + * + * Second, there are two stream encoder classes. FLAC::Encoder::Stream + * is used for the same cases that FLAC__stream_encoder_init_stream() / + * FLAC__stream_encoder_init_ogg_stream() are used, and FLAC::Encoder::File + * is used for the same cases that + * FLAC__stream_encoder_init_FILE() and FLAC__stream_encoder_init_file() / + * FLAC__stream_encoder_init_ogg_FILE() and FLAC__stream_encoder_init_ogg_file() + * are used. + */ + +namespace FLAC { + namespace Encoder { + + /** \ingroup flacpp_encoder + * \brief + * This class wraps the ::FLAC__StreamEncoder. If you are + * encoding to a file, FLAC::Encoder::File may be more + * convenient. + * + * The usage of this class is similar to FLAC__StreamEncoder, + * except instead of providing callbacks to + * FLAC__stream_encoder_init*_stream(), you will inherit from this + * class and override the virtual callback functions with your + * own implementations, then call init() or init_ogg(). The rest of + * the calls work the same as in the C layer. + * + * Only the write callback is mandatory. The others are + * optional; this class provides default implementations that do + * nothing. In order for some STREAMINFO and SEEKTABLE data to + * be written properly, you must override seek_callback() and + * tell_callback(); see FLAC__stream_encoder_init_stream() as to + * why. + */ + class FLACPP_API Stream { + public: + /** This class is a wrapper around FLAC__StreamEncoderState. + */ + class FLACPP_API State { + public: + inline State(::FLAC__StreamEncoderState state): state_(state) { } + inline operator ::FLAC__StreamEncoderState() const { return state_; } + inline const char *as_cstring() const { return ::FLAC__StreamEncoderStateString[state_]; } + inline const char *resolved_as_cstring(const Stream &encoder) const { return ::FLAC__stream_encoder_get_resolved_state_string(encoder.encoder_); } + protected: + ::FLAC__StreamEncoderState state_; + }; + + Stream(); + virtual ~Stream(); + + //@{ + /** Call after construction to check that the object was created + * successfully. If not, use get_state() to find out why not. + * + */ + virtual bool is_valid() const; + inline operator bool() const { return is_valid(); } ///< See is_valid() + //@} + + virtual bool set_ogg_serial_number(long value); ///< See FLAC__stream_encoder_set_ogg_serial_number() + virtual bool set_verify(bool value); ///< See FLAC__stream_encoder_set_verify() + virtual bool set_streamable_subset(bool value); ///< See FLAC__stream_encoder_set_streamable_subset() + virtual bool set_channels(uint32_t value); ///< See FLAC__stream_encoder_set_channels() + virtual bool set_bits_per_sample(uint32_t value); ///< See FLAC__stream_encoder_set_bits_per_sample() + virtual bool set_sample_rate(uint32_t value); ///< See FLAC__stream_encoder_set_sample_rate() + virtual bool set_compression_level(uint32_t value); ///< See FLAC__stream_encoder_set_compression_level() + virtual bool set_blocksize(uint32_t value); ///< See FLAC__stream_encoder_set_blocksize() + virtual bool set_do_mid_side_stereo(bool value); ///< See FLAC__stream_encoder_set_do_mid_side_stereo() + virtual bool set_loose_mid_side_stereo(bool value); ///< See FLAC__stream_encoder_set_loose_mid_side_stereo() + virtual bool set_apodization(const char *specification); ///< See FLAC__stream_encoder_set_apodization() + virtual bool set_max_lpc_order(uint32_t value); ///< See FLAC__stream_encoder_set_max_lpc_order() + virtual bool set_qlp_coeff_precision(uint32_t value); ///< See FLAC__stream_encoder_set_qlp_coeff_precision() + virtual bool set_do_qlp_coeff_prec_search(bool value); ///< See FLAC__stream_encoder_set_do_qlp_coeff_prec_search() + virtual bool set_do_escape_coding(bool value); ///< See FLAC__stream_encoder_set_do_escape_coding() + virtual bool set_do_exhaustive_model_search(bool value); ///< See FLAC__stream_encoder_set_do_exhaustive_model_search() + virtual bool set_min_residual_partition_order(uint32_t value); ///< See FLAC__stream_encoder_set_min_residual_partition_order() + virtual bool set_max_residual_partition_order(uint32_t value); ///< See FLAC__stream_encoder_set_max_residual_partition_order() + virtual bool set_rice_parameter_search_dist(uint32_t value); ///< See FLAC__stream_encoder_set_rice_parameter_search_dist() + virtual bool set_total_samples_estimate(FLAC__uint64 value); ///< See FLAC__stream_encoder_set_total_samples_estimate() + virtual bool set_metadata(::FLAC__StreamMetadata **metadata, uint32_t num_blocks); ///< See FLAC__stream_encoder_set_metadata() + virtual bool set_metadata(FLAC::Metadata::Prototype **metadata, uint32_t num_blocks); ///< See FLAC__stream_encoder_set_metadata() + virtual bool set_limit_min_bitrate(bool value); ///< See FLAC__stream_encoder_set_limit_min_bitrate() + + /* get_state() is not virtual since we want subclasses to be able to return their own state */ + State get_state() const; ///< See FLAC__stream_encoder_get_state() + virtual Decoder::Stream::State get_verify_decoder_state() const; ///< See FLAC__stream_encoder_get_verify_decoder_state() + virtual void get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got); ///< See FLAC__stream_encoder_get_verify_decoder_error_stats() + virtual bool get_verify() const; ///< See FLAC__stream_encoder_get_verify() + virtual bool get_streamable_subset() const; ///< See FLAC__stream_encoder_get_streamable_subset() + virtual bool get_do_mid_side_stereo() const; ///< See FLAC__stream_encoder_get_do_mid_side_stereo() + virtual bool get_loose_mid_side_stereo() const; ///< See FLAC__stream_encoder_get_loose_mid_side_stereo() + virtual uint32_t get_channels() const; ///< See FLAC__stream_encoder_get_channels() + virtual uint32_t get_bits_per_sample() const; ///< See FLAC__stream_encoder_get_bits_per_sample() + virtual uint32_t get_sample_rate() const; ///< See FLAC__stream_encoder_get_sample_rate() + virtual uint32_t get_blocksize() const; ///< See FLAC__stream_encoder_get_blocksize() + virtual uint32_t get_max_lpc_order() const; ///< See FLAC__stream_encoder_get_max_lpc_order() + virtual uint32_t get_qlp_coeff_precision() const; ///< See FLAC__stream_encoder_get_qlp_coeff_precision() + virtual bool get_do_qlp_coeff_prec_search() const; ///< See FLAC__stream_encoder_get_do_qlp_coeff_prec_search() + virtual bool get_do_escape_coding() const; ///< See FLAC__stream_encoder_get_do_escape_coding() + virtual bool get_do_exhaustive_model_search() const; ///< See FLAC__stream_encoder_get_do_exhaustive_model_search() + virtual uint32_t get_min_residual_partition_order() const; ///< See FLAC__stream_encoder_get_min_residual_partition_order() + virtual uint32_t get_max_residual_partition_order() const; ///< See FLAC__stream_encoder_get_max_residual_partition_order() + virtual uint32_t get_rice_parameter_search_dist() const; ///< See FLAC__stream_encoder_get_rice_parameter_search_dist() + virtual FLAC__uint64 get_total_samples_estimate() const; ///< See FLAC__stream_encoder_get_total_samples_estimate() + virtual bool get_limit_min_bitrate() const; ///< See FLAC__stream_encoder_get_limit_min_bitrate() + + virtual ::FLAC__StreamEncoderInitStatus init(); ///< See FLAC__stream_encoder_init_stream() + virtual ::FLAC__StreamEncoderInitStatus init_ogg(); ///< See FLAC__stream_encoder_init_ogg_stream() + + virtual bool finish(); ///< See FLAC__stream_encoder_finish() + + virtual bool process(const FLAC__int32 * const buffer[], uint32_t samples); ///< See FLAC__stream_encoder_process() + virtual bool process_interleaved(const FLAC__int32 buffer[], uint32_t samples); ///< See FLAC__stream_encoder_process_interleaved() + protected: + /// See FLAC__StreamEncoderReadCallback + virtual ::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes); + + /// See FLAC__StreamEncoderWriteCallback + virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame) = 0; + + /// See FLAC__StreamEncoderSeekCallback + virtual ::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + + /// See FLAC__StreamEncoderTellCallback + virtual ::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); + + /// See FLAC__StreamEncoderMetadataCallback + virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata); + +#if (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC) + // lame hack: some compilers can't see a protected encoder_ from nested State::resolved_as_cstring() + friend State; +#endif + ::FLAC__StreamEncoder *encoder_; + + static ::FLAC__StreamEncoderReadStatus read_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + static ::FLAC__StreamEncoderWriteStatus write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); + static ::FLAC__StreamEncoderSeekStatus seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); + static ::FLAC__StreamEncoderTellStatus tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + static void metadata_callback_(const ::FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data); + private: + // Private and undefined so you can't use them: + Stream(const Stream &); + void operator=(const Stream &); + }; + + /** \ingroup flacpp_encoder + * \brief + * This class wraps the ::FLAC__StreamEncoder. If you are + * not encoding to a file, you may need to use + * FLAC::Encoder::Stream. + * + * The usage of this class is similar to FLAC__StreamEncoder, + * except instead of providing callbacks to + * FLAC__stream_encoder_init*_FILE() or + * FLAC__stream_encoder_init*_file(), you will inherit from this + * class and override the virtual callback functions with your + * own implementations, then call init() or init_ogg(). The rest + * of the calls work the same as in the C layer. + * + * There are no mandatory callbacks; all the callbacks from + * FLAC::Encoder::Stream are implemented here fully and support + * full post-encode STREAMINFO and SEEKTABLE updating. There is + * only an optional progress callback which you may override to + * get periodic reports on the progress of the encode. + */ + class FLACPP_API File: public Stream { + public: + File(); + virtual ~File(); + + using Stream::init; + virtual ::FLAC__StreamEncoderInitStatus init(FILE *file); ///< See FLAC__stream_encoder_init_FILE() + virtual ::FLAC__StreamEncoderInitStatus init(const char *filename); ///< See FLAC__stream_encoder_init_file() + virtual ::FLAC__StreamEncoderInitStatus init(const std::string &filename); ///< See FLAC__stream_encoder_init_file() + using Stream::init_ogg; + virtual ::FLAC__StreamEncoderInitStatus init_ogg(FILE *file); ///< See FLAC__stream_encoder_init_ogg_FILE() + virtual ::FLAC__StreamEncoderInitStatus init_ogg(const char *filename); ///< See FLAC__stream_encoder_init_ogg_file() + virtual ::FLAC__StreamEncoderInitStatus init_ogg(const std::string &filename); ///< See FLAC__stream_encoder_init_ogg_file() + protected: + /// See FLAC__StreamEncoderProgressCallback + virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate); + + /// This is a dummy implementation to satisfy the pure virtual in Stream that is actually supplied internally by the C layer + virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame); + private: + static void progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data); + + // Private and undefined so you can't use them: + File(const Stream &); + void operator=(const Stream &); + }; + + } +} + +#endif diff --git a/vendor/flac/include/FLAC++/export.h b/vendor/flac/include/FLAC++/export.h new file mode 100644 index 0000000..21d9d8b --- /dev/null +++ b/vendor/flac/include/FLAC++/export.h @@ -0,0 +1,100 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLACPP__EXPORT_H +#define FLACPP__EXPORT_H + +/** \file include/FLAC++/export.h + * + * \brief + * This module contains \#defines and symbols for exporting function + * calls, and providing version information and compiled-in features. + * + * See the \link flacpp_export export \endlink module. + */ + +/** \defgroup flacpp_export FLAC++/export.h: export symbols + * \ingroup flacpp + * + * \brief + * This module contains \#defines and symbols for exporting function + * calls, and providing version information and compiled-in features. + * + * If you are compiling for Windows (with Visual Studio or MinGW for + * example) and will link to the static library (libFLAC++.lib) you + * should define FLAC__NO_DLL in your project to make sure the symbols + * are exported properly. + * + * \{ + */ + +/** This \#define is used internally in libFLAC and its headers to make + * sure the correct symbols are exported when working with shared + * libraries. On Windows, this \#define is set to __declspec(dllexport) + * when compiling libFLAC into a library and to __declspec(dllimport) + * when the headers are used to link to that DLL. On non-Windows systems + * it is used to set symbol visibility. + * + * Because of this, the define FLAC__NO_DLL must be defined when linking + * to libFLAC statically or linking will fail. + */ +/* This has grown quite complicated. FLAC__NO_DLL is used by MSVC sln + * files and CMake, which build either static or shared. autotools can + * build static, shared or **both**. Therefore, DLL_EXPORT, which is set + * by libtool, must override FLAC__NO_DLL on building shared components + */ +#if defined(_WIN32) +#if defined(FLAC__NO_DLL) && !(defined(DLL_EXPORT)) +#define FLACPP_API +#else +#ifdef FLACPP_API_EXPORTS +#define FLACPP_API __declspec(dllexport) +#else +#define FLACPP_API __declspec(dllimport) +#endif +#endif +#elif defined(FLAC__USE_VISIBILITY_ATTR) +#define FLACPP_API __attribute__ ((visibility ("default"))) +#else +#define FLACPP_API +#endif + +/** These \#defines will mirror the libtool-based library version number, see + * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning + */ +#define FLACPP_API_VERSION_CURRENT 10 +#define FLACPP_API_VERSION_REVISION 1 /**< see above */ +#define FLACPP_API_VERSION_AGE 0 /**< see above */ + +/* \} */ + +#endif diff --git a/vendor/flac/include/FLAC++/metadata.h b/vendor/flac/include/FLAC++/metadata.h new file mode 100644 index 0000000..26bc476 --- /dev/null +++ b/vendor/flac/include/FLAC++/metadata.h @@ -0,0 +1,1234 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLACPP__METADATA_H +#define FLACPP__METADATA_H + +#include "export.h" + +#include "FLAC/metadata.h" + +// =============================================================== +// +// Full documentation for the metadata interface can be found +// in the C layer in include/FLAC/metadata.h +// +// =============================================================== + +/** \file include/FLAC++/metadata.h + * + * \brief + * This module provides classes for creating and manipulating FLAC + * metadata blocks in memory, and three progressively more powerful + * interfaces for traversing and editing metadata in FLAC files. + * + * See the detailed documentation for each interface in the + * \link flacpp_metadata metadata \endlink module. + */ + +/** \defgroup flacpp_metadata FLAC++/metadata.h: metadata interfaces + * \ingroup flacpp + * + * \brief + * This module provides classes for creating and manipulating FLAC + * metadata blocks in memory, and three progressively more powerful + * interfaces for traversing and editing metadata in FLAC files. + * + * The behavior closely mimics the C layer interface; be sure to read + * the detailed description of the + * \link flac_metadata C metadata module \endlink. Note that like the + * C layer, currently only the Chain interface (level 2) supports Ogg + * FLAC files, and it is read-only i.e. no writing back changed + * metadata to file. + */ + + +namespace FLAC { + namespace Metadata { + + // ============================================================ + // + // Metadata objects + // + // ============================================================ + + /** \defgroup flacpp_metadata_object FLAC++/metadata.h: metadata object classes + * \ingroup flacpp_metadata + * + * This module contains classes representing FLAC metadata + * blocks in memory. + * + * The behavior closely mimics the C layer interface; be + * sure to read the detailed description of the + * \link flac_metadata_object C metadata object module \endlink. + * + * Any time a metadata object is constructed or assigned, you + * should check is_valid() to make sure the underlying + * ::FLAC__StreamMetadata object was able to be created. + * + * \warning + * When the get_*() methods of any metadata object method + * return you a const pointer, DO NOT disobey and write into it. + * Always use the set_*() methods. + * + * \{ + */ + + /** Base class for all metadata block types. + * See the \link flacpp_metadata_object overview \endlink for more. + */ + class FLACPP_API Prototype { + protected: + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + Prototype(const Prototype &); + Prototype(const ::FLAC__StreamMetadata &); + Prototype(const ::FLAC__StreamMetadata *); + //@} + + /** Constructs an object with copy control. When \a copy + * is \c true, behaves identically to + * FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object). + * When \a copy is \c false, the instance takes ownership of + * the pointer and the ::FLAC__StreamMetadata object will + * be freed by the destructor. + * + * \assert + * \code object != NULL \endcode + */ + Prototype(::FLAC__StreamMetadata *object, bool copy); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + Prototype &operator=(const Prototype &); + Prototype &operator=(const ::FLAC__StreamMetadata &); + Prototype &operator=(const ::FLAC__StreamMetadata *); + //@} + + /** Assigns an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + Prototype &assign_object(::FLAC__StreamMetadata *object, bool copy); + + /** Deletes the underlying ::FLAC__StreamMetadata object. + */ + virtual void clear(); + + ::FLAC__StreamMetadata *object_; + public: + /** Deletes the underlying ::FLAC__StreamMetadata object. + */ + virtual ~Prototype(); + + //@{ + /** Check for equality, performing a deep compare by following pointers. + */ + inline bool operator==(const Prototype &) const; + inline bool operator==(const ::FLAC__StreamMetadata &) const; + inline bool operator==(const ::FLAC__StreamMetadata *) const; + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const Prototype &) const; + inline bool operator!=(const ::FLAC__StreamMetadata &) const; + inline bool operator!=(const ::FLAC__StreamMetadata *) const; + //@} + + friend class SimpleIterator; + friend class Iterator; + + /** Returns \c true if the object was correctly constructed + * (i.e. the underlying ::FLAC__StreamMetadata object was + * properly allocated), else \c false. + */ + inline bool is_valid() const; + + /** Returns \c true if this block is the last block in a + * stream, else \c false. + * + * \assert + * \code is_valid() \endcode + */ + bool get_is_last() const; + + /** Returns the type of the block. + * + * \assert + * \code is_valid() \endcode + */ + ::FLAC__MetadataType get_type() const; + + /** Returns the stream length of the metadata block. + * + * \note + * The length does not include the metadata block header, + * per spec. + * + * \assert + * \code is_valid() \endcode + */ + uint32_t get_length() const; + + /** Sets the "is_last" flag for the block. When using the iterators + * it is not necessary to set this flag; they will do it for you. + * + * \assert + * \code is_valid() \endcode + */ + void set_is_last(bool); + + /** Returns a pointer to the underlying ::FLAC__StreamMetadata + * object. This can be useful for plugging any holes between + * the C++ and C interfaces. + * + * \assert + * \code is_valid() \endcode + */ + inline operator const ::FLAC__StreamMetadata *() const; + private: + /** Private and undefined so you can't use it. */ + Prototype(); + + // These are used only by Iterator + bool is_reference_; + inline void set_reference(bool x) { is_reference_ = x; } + }; + + // local utility routines + + namespace local { + + /** Construct a new object of the type provided in object->type and return it. */ + Prototype *construct_block(::FLAC__StreamMetadata *object); + + } + +#ifdef _MSC_VER +// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning) +#pragma warning ( disable : 4800 ) +#endif + + inline bool Prototype::operator==(const Prototype &object) const + { return (bool)::FLAC__metadata_object_is_equal(object_, object.object_); } + + inline bool Prototype::operator==(const ::FLAC__StreamMetadata &object) const + { return (bool)::FLAC__metadata_object_is_equal(object_, &object); } + + inline bool Prototype::operator==(const ::FLAC__StreamMetadata *object) const + { return (bool)::FLAC__metadata_object_is_equal(object_, object); } + +#ifdef _MSC_VER +#pragma warning ( default : 4800 ) +#endif + + inline bool Prototype::operator!=(const Prototype &object) const + { return !operator==(object); } + + inline bool Prototype::operator!=(const ::FLAC__StreamMetadata &object) const + { return !operator==(object); } + + inline bool Prototype::operator!=(const ::FLAC__StreamMetadata *object) const + { return !operator==(object); } + + inline bool Prototype::is_valid() const + { return 0 != object_; } + + inline Prototype::operator const ::FLAC__StreamMetadata *() const + { return object_; } + + /** Create a deep copy of an object and return it. */ + FLACPP_API Prototype *clone(const Prototype *); + + + /** STREAMINFO metadata block. + * See the \link flacpp_metadata_object overview \endlink for more, + * and the format specification. + */ + class FLACPP_API StreamInfo : public Prototype { + public: + StreamInfo(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline StreamInfo(const StreamInfo &object): Prototype(object) { } + inline StreamInfo(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline StreamInfo(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline StreamInfo(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~StreamInfo(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline StreamInfo &operator=(const StreamInfo &object) { Prototype::operator=(object); return *this; } + inline StreamInfo &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline StreamInfo &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline StreamInfo &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const StreamInfo &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const StreamInfo &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + //@{ + /** See format specification. */ + uint32_t get_min_blocksize() const; + uint32_t get_max_blocksize() const; + uint32_t get_min_framesize() const; + uint32_t get_max_framesize() const; + uint32_t get_sample_rate() const; + uint32_t get_channels() const; + uint32_t get_bits_per_sample() const; + FLAC__uint64 get_total_samples() const; + const FLAC__byte *get_md5sum() const; + + void set_min_blocksize(uint32_t value); + void set_max_blocksize(uint32_t value); + void set_min_framesize(uint32_t value); + void set_max_framesize(uint32_t value); + void set_sample_rate(uint32_t value); + void set_channels(uint32_t value); + void set_bits_per_sample(uint32_t value); + void set_total_samples(FLAC__uint64 value); + void set_md5sum(const FLAC__byte value[16]); + //@} + }; + + /** PADDING metadata block. + * See the \link flacpp_metadata_object overview \endlink for more, + * and the format specification. + */ + class FLACPP_API Padding : public Prototype { + public: + Padding(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline Padding(const Padding &object): Prototype(object) { } + inline Padding(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline Padding(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline Padding(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + /** Constructs an object with the given length. + */ + Padding(uint32_t length); + + ~Padding(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline Padding &operator=(const Padding &object) { Prototype::operator=(object); return *this; } + inline Padding &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline Padding &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline Padding &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const Padding &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const Padding &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + /** Sets the length in bytes of the padding block. + */ + void set_length(uint32_t length); + }; + + /** APPLICATION metadata block. + * See the \link flacpp_metadata_object overview \endlink for more, + * and the format specification. + */ + class FLACPP_API Application : public Prototype { + public: + Application(); + // + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline Application(const Application &object): Prototype(object) { } + inline Application(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline Application(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline Application(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~Application(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline Application &operator=(const Application &object) { Prototype::operator=(object); return *this; } + inline Application &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline Application &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline Application &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const Application &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const Application &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + const FLAC__byte *get_id() const; + const FLAC__byte *get_data() const; + + void set_id(const FLAC__byte value[4]); + //! This form always copies \a data + bool set_data(const FLAC__byte *data, uint32_t length); + bool set_data(FLAC__byte *data, uint32_t length, bool copy); + }; + + /** SEEKTABLE metadata block. + * See the \link flacpp_metadata_object overview \endlink for more, + * and the format specification. + */ + class FLACPP_API SeekTable : public Prototype { + public: + SeekTable(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline SeekTable(const SeekTable &object): Prototype(object) { } + inline SeekTable(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline SeekTable(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline SeekTable(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~SeekTable(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline SeekTable &operator=(const SeekTable &object) { Prototype::operator=(object); return *this; } + inline SeekTable &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline SeekTable &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline SeekTable &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const SeekTable &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const SeekTable &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + uint32_t get_num_points() const; + ::FLAC__StreamMetadata_SeekPoint get_point(uint32_t index) const; + + //! See FLAC__metadata_object_seektable_resize_points() + bool resize_points(uint32_t new_num_points); + + //! See FLAC__metadata_object_seektable_set_point() + void set_point(uint32_t index, const ::FLAC__StreamMetadata_SeekPoint &point); + + //! See FLAC__metadata_object_seektable_insert_point() + bool insert_point(uint32_t index, const ::FLAC__StreamMetadata_SeekPoint &point); + + //! See FLAC__metadata_object_seektable_delete_point() + bool delete_point(uint32_t index); + + //! See FLAC__metadata_object_seektable_is_legal() + bool is_legal() const; + + //! See FLAC__metadata_object_seektable_template_append_placeholders() + bool template_append_placeholders(uint32_t num); + + //! See FLAC__metadata_object_seektable_template_append_point() + bool template_append_point(FLAC__uint64 sample_number); + + //! See FLAC__metadata_object_seektable_template_append_points() + bool template_append_points(FLAC__uint64 sample_numbers[], uint32_t num); + + //! See FLAC__metadata_object_seektable_template_append_spaced_points() + bool template_append_spaced_points(uint32_t num, FLAC__uint64 total_samples); + + //! See FLAC__metadata_object_seektable_template_append_spaced_points_by_samples() + bool template_append_spaced_points_by_samples(uint32_t samples, FLAC__uint64 total_samples); + + //! See FLAC__metadata_object_seektable_template_sort() + bool template_sort(bool compact); + }; + + /** VORBIS_COMMENT metadata block. + * See the \link flacpp_metadata_object overview \endlink for more, + * and the format specification. + */ + class FLACPP_API VorbisComment : public Prototype { + public: + /** Convenience class for encapsulating Vorbis comment + * entries. An entry is a vendor string or a comment + * field. In the case of a vendor string, the field + * name is undefined; only the field value is relevant. + * + * A \a field as used in the methods refers to an + * entire 'NAME=VALUE' string; for convenience the + * string is NUL-terminated. A length field is + * required in the unlikely event that the value + * contains contain embedded NULs. + * + * A \a field_name is what is on the left side of the + * first '=' in the \a field. By definition it is ASCII + * and so is NUL-terminated and does not require a + * length to describe it. \a field_name is undefined + * for a vendor string entry. + * + * A \a field_value is what is on the right side of the + * first '=' in the \a field. By definition, this may + * contain embedded NULs and so a \a field_value_length + * is required to describe it. However in practice, + * embedded NULs are not known to be used, so it is + * generally safe to treat field values as NUL- + * terminated UTF-8 strings. + * + * Always check is_valid() after the constructor or operator= + * to make sure memory was properly allocated and that the + * Entry conforms to the Vorbis comment specification. + */ + class FLACPP_API Entry { + public: + Entry(); + + Entry(const char *field, uint32_t field_length); + Entry(const char *field); // assumes \a field is NUL-terminated + + Entry(const char *field_name, const char *field_value, uint32_t field_value_length); + Entry(const char *field_name, const char *field_value); // assumes \a field_value is NUL-terminated + + Entry(const Entry &entry); + + Entry &operator=(const Entry &entry); + + virtual ~Entry(); + + virtual bool is_valid() const; ///< Returns \c true iff object was properly constructed. + + uint32_t get_field_length() const; + uint32_t get_field_name_length() const; + uint32_t get_field_value_length() const; + + ::FLAC__StreamMetadata_VorbisComment_Entry get_entry() const; + const char *get_field() const; + const char *get_field_name() const; + const char *get_field_value() const; + + bool set_field(const char *field, uint32_t field_length); + bool set_field(const char *field); // assumes \a field is NUL-terminated + bool set_field_name(const char *field_name); + bool set_field_value(const char *field_value, uint32_t field_value_length); + bool set_field_value(const char *field_value); // assumes \a field_value is NUL-terminated + protected: + bool is_valid_; + ::FLAC__StreamMetadata_VorbisComment_Entry entry_; + char *field_name_; + uint32_t field_name_length_; + char *field_value_; + uint32_t field_value_length_; + private: + void zero(); + void clear(); + void clear_entry(); + void clear_field_name(); + void clear_field_value(); + void construct(const char *field, uint32_t field_length); + void construct(const char *field); // assumes \a field is NUL-terminated + void construct(const char *field_name, const char *field_value, uint32_t field_value_length); + void construct(const char *field_name, const char *field_value); // assumes \a field_value is NUL-terminated + void compose_field(); + void parse_field(); + }; + + VorbisComment(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline VorbisComment(const VorbisComment &object): Prototype(object) { } + inline VorbisComment(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline VorbisComment(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline VorbisComment(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~VorbisComment(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline VorbisComment &operator=(const VorbisComment &object) { Prototype::operator=(object); return *this; } + inline VorbisComment &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline VorbisComment &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline VorbisComment &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const VorbisComment &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const VorbisComment &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + uint32_t get_num_comments() const; + const FLAC__byte *get_vendor_string() const; // NUL-terminated UTF-8 string + Entry get_comment(uint32_t index) const; + + //! See FLAC__metadata_object_vorbiscomment_set_vendor_string() + bool set_vendor_string(const FLAC__byte *string); // NUL-terminated UTF-8 string + + //! See FLAC__metadata_object_vorbiscomment_resize_comments() + bool resize_comments(uint32_t new_num_comments); + + //! See FLAC__metadata_object_vorbiscomment_set_comment() + bool set_comment(uint32_t index, const Entry &entry); + + //! See FLAC__metadata_object_vorbiscomment_insert_comment() + bool insert_comment(uint32_t index, const Entry &entry); + + //! See FLAC__metadata_object_vorbiscomment_append_comment() + bool append_comment(const Entry &entry); + + //! See FLAC__metadata_object_vorbiscomment_replace_comment() + bool replace_comment(const Entry &entry, bool all); + + //! See FLAC__metadata_object_vorbiscomment_delete_comment() + bool delete_comment(uint32_t index); + + //! See FLAC__metadata_object_vorbiscomment_find_entry_from() + int find_entry_from(uint32_t offset, const char *field_name); + + //! See FLAC__metadata_object_vorbiscomment_remove_entry_matching() + int remove_entry_matching(const char *field_name); + + //! See FLAC__metadata_object_vorbiscomment_remove_entries_matching() + int remove_entries_matching(const char *field_name); + }; + + /** CUESHEET metadata block. + * See the \link flacpp_metadata_object overview \endlink for more, + * and the format specification. + */ + class FLACPP_API CueSheet : public Prototype { + public: + /** Convenience class for encapsulating a cue sheet + * track. + * + * Always check is_valid() after the constructor or operator= + * to make sure memory was properly allocated. + */ + class FLACPP_API Track { + protected: + ::FLAC__StreamMetadata_CueSheet_Track *object_; + public: + Track(); + Track(const ::FLAC__StreamMetadata_CueSheet_Track *track); + Track(const Track &track); + Track &operator=(const Track &track); + + virtual ~Track(); + + virtual bool is_valid() const; ///< Returns \c true iff object was properly constructed. + + + inline FLAC__uint64 get_offset() const { return object_->offset; } + inline FLAC__byte get_number() const { return object_->number; } + inline const char *get_isrc() const { return object_->isrc; } + inline uint32_t get_type() const { return object_->type; } + inline bool get_pre_emphasis() const { return object_->pre_emphasis; } + + inline FLAC__byte get_num_indices() const { return object_->num_indices; } + ::FLAC__StreamMetadata_CueSheet_Index get_index(uint32_t i) const; + + inline const ::FLAC__StreamMetadata_CueSheet_Track *get_track() const { return object_; } + + inline void set_offset(FLAC__uint64 value) { object_->offset = value; } + inline void set_number(FLAC__byte value) { object_->number = value; } + void set_isrc(const char value[12]); + void set_type(uint32_t value); + inline void set_pre_emphasis(bool value) { object_->pre_emphasis = value? 1 : 0; } + + void set_index(uint32_t i, const ::FLAC__StreamMetadata_CueSheet_Index &index); + //@@@ It's awkward but to insert/delete index points + //@@@ you must use the routines in the CueSheet class. + }; + + CueSheet(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline CueSheet(const CueSheet &object): Prototype(object) { } + inline CueSheet(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline CueSheet(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline CueSheet(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~CueSheet(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline CueSheet &operator=(const CueSheet &object) { Prototype::operator=(object); return *this; } + inline CueSheet &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline CueSheet &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline CueSheet &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const CueSheet &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const CueSheet &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + const char *get_media_catalog_number() const; + FLAC__uint64 get_lead_in() const; + bool get_is_cd() const; + + uint32_t get_num_tracks() const; + Track get_track(uint32_t i) const; + + void set_media_catalog_number(const char value[128]); + void set_lead_in(FLAC__uint64 value); + void set_is_cd(bool value); + + void set_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index); + + //! See FLAC__metadata_object_cuesheet_track_resize_indices() + bool resize_indices(uint32_t track_num, uint32_t new_num_indices); + + //! See FLAC__metadata_object_cuesheet_track_insert_index() + bool insert_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index); + + //! See FLAC__metadata_object_cuesheet_track_insert_blank_index() + bool insert_blank_index(uint32_t track_num, uint32_t index_num); + + //! See FLAC__metadata_object_cuesheet_track_delete_index() + bool delete_index(uint32_t track_num, uint32_t index_num); + + //! See FLAC__metadata_object_cuesheet_resize_tracks() + bool resize_tracks(uint32_t new_num_tracks); + + //! See FLAC__metadata_object_cuesheet_set_track() + bool set_track(uint32_t i, const Track &track); + + //! See FLAC__metadata_object_cuesheet_insert_track() + bool insert_track(uint32_t i, const Track &track); + + //! See FLAC__metadata_object_cuesheet_insert_blank_track() + bool insert_blank_track(uint32_t i); + + //! See FLAC__metadata_object_cuesheet_delete_track() + bool delete_track(uint32_t i); + + //! See FLAC__metadata_object_cuesheet_is_legal() + bool is_legal(bool check_cd_da_subset = false, const char **violation = 0) const; + + //! See FLAC__metadata_object_cuesheet_calculate_cddb_id() + FLAC__uint32 calculate_cddb_id() const; + }; + + /** PICTURE metadata block. + * See the \link flacpp_metadata_object overview \endlink for more, + * and the format specification. + */ + class FLACPP_API Picture : public Prototype { + public: + Picture(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline Picture(const Picture &object): Prototype(object) { } + inline Picture(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline Picture(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline Picture(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~Picture(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline Picture &operator=(const Picture &object) { Prototype::operator=(object); return *this; } + inline Picture &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline Picture &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline Picture &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const Picture &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const Picture &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + ::FLAC__StreamMetadata_Picture_Type get_type() const; + const char *get_mime_type() const; // NUL-terminated printable ASCII string + const FLAC__byte *get_description() const; // NUL-terminated UTF-8 string + FLAC__uint32 get_width() const; + FLAC__uint32 get_height() const; + FLAC__uint32 get_depth() const; + FLAC__uint32 get_colors() const; ///< a return value of \c 0 means true-color, i.e. 2^depth colors + FLAC__uint32 get_data_length() const; + const FLAC__byte *get_data() const; + + void set_type(::FLAC__StreamMetadata_Picture_Type type); + + //! See FLAC__metadata_object_picture_set_mime_type() + bool set_mime_type(const char *string); // NUL-terminated printable ASCII string + + //! See FLAC__metadata_object_picture_set_description() + bool set_description(const FLAC__byte *string); // NUL-terminated UTF-8 string + + void set_width(FLAC__uint32 value) const; + void set_height(FLAC__uint32 value) const; + void set_depth(FLAC__uint32 value) const; + void set_colors(FLAC__uint32 value) const; ///< a value of \c 0 means true-color, i.e. 2^depth colors + + //! See FLAC__metadata_object_picture_set_data() + bool set_data(const FLAC__byte *data, FLAC__uint32 data_length); + + //! See FLAC__metadata_object_picture_is_legal() + bool is_legal(const char **violation); + }; + + /** Opaque metadata block for storing unknown types. + * This should not be used unless you know what you are doing; + * it is currently used only internally to support forward + * compatibility of metadata blocks. + * See the \link flacpp_metadata_object overview \endlink for more, + */ + class FLACPP_API Unknown : public Prototype { + public: + Unknown(); + // + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline Unknown(const Unknown &object): Prototype(object) { } + inline Unknown(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline Unknown(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline Unknown(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~Unknown(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline Unknown &operator=(const Unknown &object) { Prototype::operator=(object); return *this; } + inline Unknown &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline Unknown &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline Unknown &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const Unknown &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const Unknown &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + const FLAC__byte *get_data() const; + + //! This form always copies \a data + bool set_data(const FLAC__byte *data, uint32_t length); + bool set_data(FLAC__byte *data, uint32_t length, bool copy); + }; + + /* \} */ + + + /** \defgroup flacpp_metadata_level0 FLAC++/metadata.h: metadata level 0 interface + * \ingroup flacpp_metadata + * + * \brief + * Level 0 metadata iterators. + * + * See the \link flac_metadata_level0 C layer equivalent \endlink + * for more. + * + * \{ + */ + + FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo); ///< See FLAC__metadata_get_streaminfo(). + + FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags); ///< See FLAC__metadata_get_tags(). + FLACPP_API bool get_tags(const char *filename, VorbisComment &tags); ///< See FLAC__metadata_get_tags(). + + FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet); ///< See FLAC__metadata_get_cuesheet(). + FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet); ///< See FLAC__metadata_get_cuesheet(). + + FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors); ///< See FLAC__metadata_get_picture(). + FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors); ///< See FLAC__metadata_get_picture(). + + /* \} */ + + + /** \defgroup flacpp_metadata_level1 FLAC++/metadata.h: metadata level 1 interface + * \ingroup flacpp_metadata + * + * \brief + * Level 1 metadata iterator. + * + * The flow through the iterator in the C++ layer is similar + * to the C layer: + * - Create a SimpleIterator instance + * - Check SimpleIterator::is_valid() + * - Call SimpleIterator::init() and check the return + * - Traverse and/or edit. Edits are written to file + * immediately. + * - Destroy the SimpleIterator instance + * + * The ownership of pointers in the C++ layer follows that in + * the C layer, i.e. + * - The objects returned by get_block() are yours to + * modify, but changes are not reflected in the FLAC file + * until you call set_block(). The objects are also + * yours to delete; they are not automatically deleted + * when passed to set_block() or insert_block_after(). + * + * See the \link flac_metadata_level1 C layer equivalent \endlink + * for more. + * + * \{ + */ + + /** This class is a wrapper around the FLAC__metadata_simple_iterator + * structures and methods; see the + * \link flacpp_metadata_level1 usage guide \endlink and + * ::FLAC__Metadata_SimpleIterator. + */ + class FLACPP_API SimpleIterator { + public: + /** This class is a wrapper around FLAC__Metadata_SimpleIteratorStatus. + */ + class FLACPP_API Status { + public: + inline Status(::FLAC__Metadata_SimpleIteratorStatus status): status_(status) { } + inline operator ::FLAC__Metadata_SimpleIteratorStatus() const { return status_; } + inline const char *as_cstring() const { return ::FLAC__Metadata_SimpleIteratorStatusString[status_]; } + protected: + ::FLAC__Metadata_SimpleIteratorStatus status_; + }; + + SimpleIterator(); + virtual ~SimpleIterator(); + + bool is_valid() const; ///< Returns \c true iff object was properly constructed. + + bool init(const char *filename, bool read_only, bool preserve_file_stats); ///< See FLAC__metadata_simple_iterator_init(). + + Status status(); ///< See FLAC__metadata_simple_iterator_status(). + bool is_writable() const; ///< See FLAC__metadata_simple_iterator_is_writable(). + + bool next(); ///< See FLAC__metadata_simple_iterator_next(). + bool prev(); ///< See FLAC__metadata_simple_iterator_prev(). + bool is_last() const; ///< See FLAC__metadata_simple_iterator_is_last(). + + off_t get_block_offset() const; ///< See FLAC__metadata_simple_iterator_get_block_offset(). + ::FLAC__MetadataType get_block_type() const; ///< See FLAC__metadata_simple_iterator_get_block_type(). + uint32_t get_block_length() const; ///< See FLAC__metadata_simple_iterator_get_block_length(). + bool get_application_id(FLAC__byte *id); ///< See FLAC__metadata_simple_iterator_get_application_id(). + Prototype *get_block(); ///< See FLAC__metadata_simple_iterator_get_block(). + bool set_block(Prototype *block, bool use_padding = true); ///< See FLAC__metadata_simple_iterator_set_block(). + bool insert_block_after(Prototype *block, bool use_padding = true); ///< See FLAC__metadata_simple_iterator_insert_block_after(). + bool delete_block(bool use_padding = true); ///< See FLAC__metadata_simple_iterator_delete_block(). + + protected: + ::FLAC__Metadata_SimpleIterator *iterator_; + void clear(); + + private: // Do not use. + SimpleIterator(const SimpleIterator&); + SimpleIterator&operator=(const SimpleIterator&); + }; + + /* \} */ + + + /** \defgroup flacpp_metadata_level2 FLAC++/metadata.h: metadata level 2 interface + * \ingroup flacpp_metadata + * + * \brief + * Level 2 metadata iterator. + * + * The flow through the iterator in the C++ layer is similar + * to the C layer: + * - Create a Chain instance + * - Check Chain::is_valid() + * - Call Chain::read() and check the return + * - Traverse and/or edit with an Iterator or with + * Chain::merge_padding() or Chain::sort_padding() + * - Write changes back to FLAC file with Chain::write() + * - Destroy the Chain instance + * + * The ownership of pointers in the C++ layer is slightly + * different than in the C layer, i.e. + * - The objects returned by Iterator::get_block() are NOT + * owned by the iterator and should be deleted by the + * caller when finished, BUT, when you modify the block, + * it will directly edit what's in the chain and you do + * not need to call Iterator::set_block(). However the + * changes will not be reflected in the FLAC file until + * the chain is written with Chain::write(). + * - When you pass an object to Iterator::set_block(), + * Iterator::insert_block_before(), or + * Iterator::insert_block_after(), the iterator takes + * ownership of the block and it will be deleted by the + * chain. + * + * See the \link flac_metadata_level2 C layer equivalent \endlink + * for more. + * + * \{ + */ + + /** This class is a wrapper around the FLAC__metadata_chain + * structures and methods; see the + * \link flacpp_metadata_level2 usage guide \endlink and + * ::FLAC__Metadata_Chain. + */ + class FLACPP_API Chain { + public: + /** This class is a wrapper around FLAC__Metadata_ChainStatus. + */ + class FLACPP_API Status { + public: + inline Status(::FLAC__Metadata_ChainStatus status): status_(status) { } + inline operator ::FLAC__Metadata_ChainStatus() const { return status_; } + inline const char *as_cstring() const { return ::FLAC__Metadata_ChainStatusString[status_]; } + protected: + ::FLAC__Metadata_ChainStatus status_; + }; + + Chain(); + virtual ~Chain(); + + friend class Iterator; + + bool is_valid() const; ///< Returns \c true iff object was properly constructed. + + Status status(); ///< See FLAC__metadata_chain_status(). + + bool read(const char *filename, bool is_ogg = false); ///< See FLAC__metadata_chain_read(), FLAC__metadata_chain_read_ogg(). + bool read(FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, bool is_ogg = false); ///< See FLAC__metadata_chain_read_with_callbacks(), FLAC__metadata_chain_read_ogg_with_callbacks(). + + bool check_if_tempfile_needed(bool use_padding); ///< See FLAC__metadata_chain_check_if_tempfile_needed(). + + bool write(bool use_padding = true, bool preserve_file_stats = false); ///< See FLAC__metadata_chain_write(). + bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks); ///< See FLAC__metadata_chain_write_with_callbacks(). + bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks); ///< See FLAC__metadata_chain_write_with_callbacks_and_tempfile(). + + void merge_padding(); ///< See FLAC__metadata_chain_merge_padding(). + void sort_padding(); ///< See FLAC__metadata_chain_sort_padding(). + + protected: + ::FLAC__Metadata_Chain *chain_; + virtual void clear(); + + private: // Do not use. + Chain(const Chain&); + Chain&operator=(const Chain&); + }; + + /** This class is a wrapper around the FLAC__metadata_iterator + * structures and methods; see the + * \link flacpp_metadata_level2 usage guide \endlink and + * ::FLAC__Metadata_Iterator. + */ + class FLACPP_API Iterator { + public: + Iterator(); + virtual ~Iterator(); + + bool is_valid() const; ///< Returns \c true iff object was properly constructed. + + + void init(Chain &chain); ///< See FLAC__metadata_iterator_init(). + + bool next(); ///< See FLAC__metadata_iterator_next(). + bool prev(); ///< See FLAC__metadata_iterator_prev(). + + ::FLAC__MetadataType get_block_type() const; ///< See FLAC__metadata_iterator_get_block_type(). + Prototype *get_block(); ///< See FLAC__metadata_iterator_get_block(). + bool set_block(Prototype *block); ///< See FLAC__metadata_iterator_set_block(). + bool delete_block(bool replace_with_padding); ///< See FLAC__metadata_iterator_delete_block(). + bool insert_block_before(Prototype *block); ///< See FLAC__metadata_iterator_insert_block_before(). + bool insert_block_after(Prototype *block); ///< See FLAC__metadata_iterator_insert_block_after(). + + protected: + ::FLAC__Metadata_Iterator *iterator_; + virtual void clear(); + + private: // Do not use. + Iterator(const Iterator&); + Iterator&operator=(const Iterator&); + }; + + /* \} */ + + } +} + +#endif diff --git a/vendor/flac/include/FLAC/Makefile.am b/vendor/flac/include/FLAC/Makefile.am new file mode 100644 index 0000000..80ded61 --- /dev/null +++ b/vendor/flac/include/FLAC/Makefile.am @@ -0,0 +1,43 @@ +# libFLAC - Free Lossless Audio Codec library +# Copyright (C) 2000-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +flaccincludedir = $(includedir)/FLAC + +flaccinclude_HEADERS = \ + all.h \ + assert.h \ + callback.h \ + export.h \ + format.h \ + metadata.h \ + ordinals.h \ + stream_decoder.h \ + stream_encoder.h diff --git a/vendor/flac/include/FLAC/all.h b/vendor/flac/include/FLAC/all.h new file mode 100644 index 0000000..277dcbc --- /dev/null +++ b/vendor/flac/include/FLAC/all.h @@ -0,0 +1,450 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__ALL_H +#define FLAC__ALL_H + +#include "export.h" + +#include "assert.h" +#include "callback.h" +#include "format.h" +#include "metadata.h" +#include "ordinals.h" +#include "stream_decoder.h" +#include "stream_encoder.h" + +/** \mainpage + * + * \section intro Introduction + * + * This is the documentation for the FLAC C and C++ APIs. It is + * highly interconnected; this introduction should give you a top + * level idea of the structure and how to find the information you + * need. As a prerequisite you should have at least a basic + * knowledge of the FLAC format, documented + * here. + * + * \section c_api FLAC C API + * + * The FLAC C API is the interface to libFLAC, a set of structures + * describing the components of FLAC streams, and functions for + * encoding and decoding streams, as well as manipulating FLAC + * metadata in files. The public include files will be installed + * in your include area (for example /usr/include/FLAC/...). + * + * By writing a little code and linking against libFLAC, it is + * relatively easy to add FLAC support to another program. The + * library is licensed under Xiph's BSD license. + * Complete source code of libFLAC as well as the command-line + * encoder and plugins is available and is a useful source of + * examples. + * + * Aside from encoders and decoders, libFLAC provides a powerful + * metadata interface for manipulating metadata in FLAC files. It + * allows the user to add, delete, and modify FLAC metadata blocks + * and it can automatically take advantage of PADDING blocks to avoid + * rewriting the entire FLAC file when changing the size of the + * metadata. + * + * libFLAC usually only requires the standard C library and C math + * library. In particular, threading is not used so there is no + * dependency on a thread library. However, libFLAC does not use + * global variables and should be thread-safe. + * + * libFLAC also supports encoding to and decoding from Ogg FLAC. + * However the metadata editing interfaces currently have limited + * read-only support for Ogg FLAC files. + * + * \section cpp_api FLAC C++ API + * + * The FLAC C++ API is a set of classes that encapsulate the + * structures and functions in libFLAC. They provide slightly more + * functionality with respect to metadata but are otherwise + * equivalent. For the most part, they share the same usage as + * their counterparts in libFLAC, and the FLAC C API documentation + * can be used as a supplement. The public include files + * for the C++ API will be installed in your include area (for + * example /usr/include/FLAC++/...). + * + * libFLAC++ is also licensed under + * Xiph's BSD license. + * + * \section getting_started Getting Started + * + * A good starting point for learning the API is to browse through + * the modules. Modules are logical + * groupings of related functions or classes, which correspond roughly + * to header files or sections of header files. Each module includes a + * detailed description of the general usage of its functions or + * classes. + * + * From there you can go on to look at the documentation of + * individual functions. You can see different views of the individual + * functions through the links in top bar across this page. + * + * If you prefer a more hands-on approach, you can jump right to some + * example code. + * + * \section porting_guide Porting Guide + * + * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink + * has been introduced which gives detailed instructions on how to + * port your code to newer versions of FLAC. + * + * \section embedded_developers Embedded Developers + * + * libFLAC has grown larger over time as more functionality has been + * included, but much of it may be unnecessary for a particular embedded + * implementation. Unused parts may be pruned by some simple editing of + * src/libFLAC/Makefile.am. In general, the decoders, encoders, and + * metadata interface are all independent from each other. + * + * It is easiest to just describe the dependencies: + * + * - All modules depend on the \link flac_format Format \endlink module. + * - The decoders and encoders depend on the bitbuffer. + * - The decoder is independent of the encoder. The encoder uses the + * decoder because of the verify feature, but this can be removed if + * not needed. + * - Parts of the metadata interface require the stream decoder (but not + * the encoder). + * - Ogg support is selectable through the compile time macro + * \c FLAC__HAS_OGG. + * + * For example, if your application only requires the stream decoder, no + * encoder, and no metadata interface, you can remove the stream encoder + * and the metadata interface, which will greatly reduce the size of the + * library. + * + * Also, there are several places in the libFLAC code with comments marked + * with "OPT:" where a \#define can be changed to enable code that might be + * faster on a specific platform. Experimenting with these can yield faster + * binaries. + */ + +/** \defgroup porting Porting Guide for New Versions + * + * This module describes differences in the library interfaces from + * version to version. It assists in the porting of code that uses + * the libraries to newer versions of FLAC. + * + * One simple facility for making porting easier that has been added + * in FLAC 1.1.3 is a set of \#defines in \c export.h of each + * library's includes (e.g. \c include/FLAC/export.h). The + * \#defines mirror the libraries' + * libtool version numbers, + * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT, + * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE. + * These can be used to support multiple versions of an API during the + * transition phase, e.g. + * + * \code + * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 + * legacy code + * #else + * new code + * #endif + * \endcode + * + * The source will work for multiple versions and the legacy code can + * easily be removed when the transition is complete. + * + * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in + * include/FLAC/export.h), which can be used to determine whether or not + * the library has been compiled with support for Ogg FLAC. This is + * simpler than trying to call an Ogg init function and catching the + * error. + */ + +/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3 + * \ingroup porting + * + * \brief + * This module describes porting from FLAC 1.1.2 to FLAC 1.1.3. + * + * The main change between the APIs in 1.1.2 and 1.1.3 is that they have + * been simplified. First, libOggFLAC has been merged into libFLAC and + * libOggFLAC++ has been merged into libFLAC++. Second, both the three + * decoding layers and three encoding layers have been merged into a + * single stream decoder and stream encoder. That is, the functionality + * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged + * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and + * FLAC__FileEncoder into FLAC__StreamEncoder. Only the + * FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means + * is there is now a single API that can be used to encode or decode + * streams to/from native FLAC or Ogg FLAC and the single API can work + * on both seekable and non-seekable streams. + * + * Instead of creating an encoder or decoder of a certain layer, now the + * client will always create a FLAC__StreamEncoder or + * FLAC__StreamDecoder. The old layers are now differentiated by the + * initialization function. For example, for the decoder, + * FLAC__stream_decoder_init() has been replaced by + * FLAC__stream_decoder_init_stream(). This init function takes + * callbacks for the I/O, and the seeking callbacks are optional. This + * allows the client to use the same object for seekable and + * non-seekable streams. For decoding a FLAC file directly, the client + * can use FLAC__stream_decoder_init_file() and pass just a filename + * and fewer callbacks; most of the other callbacks are supplied + * internally. For situations where fopen()ing by filename is not + * possible (e.g. Unicode filenames on Windows) the client can instead + * open the file itself and supply the FILE* to + * FLAC__stream_decoder_init_FILE(). The init functions now returns a + * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState. + * Since the callbacks and client data are now passed to the init + * function, the FLAC__stream_decoder_set_*_callback() functions and + * FLAC__stream_decoder_set_client_data() are no longer needed. The + * rest of the calls to the decoder are the same as before. + * + * There are counterpart init functions for Ogg FLAC, e.g. + * FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls + * and callbacks are the same as for native FLAC. + * + * As an example, in FLAC 1.1.2 a seekable stream decoder would have + * been set up like so: + * + * \code + * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new(); + * if(decoder == NULL) do_something; + * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true); + * [... other settings ...] + * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback); + * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback); + * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback); + * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback); + * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback); + * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback); + * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback); + * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback); + * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data); + * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something; + * \endcode + * + * In FLAC 1.1.3 it is like this: + * + * \code + * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); + * if(decoder == NULL) do_something; + * FLAC__stream_decoder_set_md5_checking(decoder, true); + * [... other settings ...] + * if(FLAC__stream_decoder_init_stream( + * decoder, + * my_read_callback, + * my_seek_callback, // or NULL + * my_tell_callback, // or NULL + * my_length_callback, // or NULL + * my_eof_callback, // or NULL + * my_write_callback, + * my_metadata_callback, // or NULL + * my_error_callback, + * my_client_data + * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; + * \endcode + * + * or you could do; + * + * \code + * [...] + * FILE *file = fopen("somefile.flac","rb"); + * if(file == NULL) do_somthing; + * if(FLAC__stream_decoder_init_FILE( + * decoder, + * file, + * my_write_callback, + * my_metadata_callback, // or NULL + * my_error_callback, + * my_client_data + * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; + * \endcode + * + * or just: + * + * \code + * [...] + * if(FLAC__stream_decoder_init_file( + * decoder, + * "somefile.flac", + * my_write_callback, + * my_metadata_callback, // or NULL + * my_error_callback, + * my_client_data + * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; + * \endcode + * + * Another small change to the decoder is in how it handles unparseable + * streams. Before, when the decoder found an unparseable stream + * (reserved for when the decoder encounters a stream from a future + * encoder that it can't parse), it changed the state to + * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. Now the decoder instead + * drops sync and calls the error callback with a new error code + * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM. This is + * more robust. If your error callback does not discriminate on the the + * error state, your code does not need to be changed. + * + * The encoder now has a new setting: + * FLAC__stream_encoder_set_apodization(). This is for setting the + * method used to window the data before LPC analysis. You only need to + * add a call to this function if the default is not suitable. There + * are also two new convenience functions that may be useful: + * FLAC__metadata_object_cuesheet_calculate_cddb_id() and + * FLAC__metadata_get_cuesheet(). + * + * The \a bytes parameter to FLAC__StreamDecoderReadCallback, + * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback + * is now \c size_t instead of \c uint32_t. + */ + +/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4 + * \ingroup porting + * + * \brief + * This module describes porting from FLAC 1.1.3 to FLAC 1.1.4. + * + * There were no changes to any of the interfaces from 1.1.3 to 1.1.4. + * There was a slight change in the implementation of + * FLAC__stream_encoder_set_metadata(); the function now makes a copy + * of the \a metadata array of pointers so the client no longer needs + * to maintain it after the call. The objects themselves that are + * pointed to by the array are still not copied though and must be + * maintained until the call to FLAC__stream_encoder_finish(). + */ + +/** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0 + * \ingroup porting + * + * \brief + * This module describes porting from FLAC 1.1.4 to FLAC 1.2.0. + * + * There were only very minor changes to the interfaces from 1.1.4 to 1.2.0. + * In libFLAC, \c FLAC__format_sample_rate_is_subset() was added. + * In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added. + * + * Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN + * has changed to reflect the conversion of one of the reserved bits + * into active use. It used to be \c 2 and now is \c 1. However the + * FLAC frame header length has not changed, so to skip the proper + * number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN + + * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN + */ + +/** \defgroup porting_1_3_4_to_1_4_0 Porting from FLAC 1.3.4 to 1.4.0 + * \ingroup porting + * + * \brief + * This module describes porting from FLAC 1.3.4 to FLAC 1.4.0. + * + * \section porting_1_3_4_to_1_4_0_summary Summary + * + * Between FLAC 1.3.4 and FLAC 1.4.0, there have four breaking changes + * - the function get_client_data_from_decoder has been renamed to + * FLAC__get_decoder_client_data + * - some data types in the FLAC__Frame struct have changed + * - all functions resizing metadata blocks now return the object + * untouched if memory allocation fails, whereas previously the + * handling varied and was more or less undefined + * - all functions accepting a filename now take UTF-8 encoded filenames + * on Windows instead of filenames in the current codepage + * + * Furthermore, there have been the following additions + * - the functions FLAC__stream_encoder_set_limit_min_bitrate, + * FLAC__stream_encoder_get_limit_min_bitrate, + * FLAC::encoder::file::set_limit_min_bitrate() and + * FLAC::encoder::file::get_limit_min_bitrate() have been added + * - Added FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA to the + * FLAC__StreamDecoderErrorStatus enum + * + * \section porting_1_3_4_to_1_4_0_breaking Breaking changes + * + * The function \b get_client_data_from_decoder was added in FLAC 1.3.3 + * but did not follow the API naming convention and was not properly + * exported. The function is now renamed and properly integrated as + * FLAC__stream_decoder_get_client_data + * + * To accomodate encoding and decoding 32-bit int PCM, some data types + * in the \b FLAC__frame struct were changed. Specifically, warmup + * in both the FLAC__Subframe_Fixed struc and the FLAC__Subframe_LPC + * struct is changed from FLAC__int32 to FLAC__int64. Also, value + * in the FLAC__Subframe_Constant is changed from FLAC__int32 to + * FLAC__int64. Finally, in FLAC__Subframe_Verbatim struct data is + * changes from a FLAC__int32 array to a union containing a FLAC__int32 + * array and a FLAC__int64 array. Also, a new member is added, + * data_type, which clarifies whether the FLAC__int32 or FLAC__int64 + * array is in use. + * + * Furthermore, the following functions now return the object untouched + * if memory allocation fails, whereas previously the handling varied + * and was more or less undefined + * + * - FLAC__metadata_object_seektable_resize_points + * - FLAC__metadata_object_vorbiscomment_resize_comments + * - FLAC__metadata_object_cuesheet_track_resize_indices + * - FLAC__metadata_object_cuesheet_resize_tracks + * + * The last breaking change is that all API functions taking a filename + * as an argument now, on Windows, must be supplied with that filename + * in the UTF-8 character encoding instead of using the current code + * page. libFLAC internally translates these UTF-8 encoded filenames to + * an appropriate representation to use with _wfopen. On all other + * systems, filename is passed to fopen without any translation, as it + * in libFLAC 1.3.4 and earlier. + * + * \section porting_1_3_4_to_1_4_0_additions Additions + * + * To aid in creating properly streamable FLAC files, a set of functions + * was added to make it possible to enfore a minimum bitrate to files + * created through libFLAC's stream_encoder.h interface. With this + * function enabled the resulting FLAC files have a minimum bitrate of + * 1bit/sample independent of the number of channels, i.e. 48kbit/s for + * 48kHz. This can be beneficial for streaming, as very low bitrates for + * silent sections compressed with 'constant' subframes can result in a + * bitrate of 1kbit/s, creating problems with clients that aren't aware + * of this possibility and buffer too much data. + * + * Finally, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA was added to + * the FLAC__StreamDecoderErrorStatus enum to signal that the decoder + * encountered unreadable metadata. + * + */ + +/** \defgroup flac FLAC C API + * + * The FLAC C API is the interface to libFLAC, a set of structures + * describing the components of FLAC streams, and functions for + * encoding and decoding streams, as well as manipulating FLAC + * metadata in files. + * + * You should start with the format components as all other modules + * are dependent on it. + */ + +#endif diff --git a/vendor/flac/include/FLAC/assert.h b/vendor/flac/include/FLAC/assert.h new file mode 100644 index 0000000..ee3ee08 --- /dev/null +++ b/vendor/flac/include/FLAC/assert.h @@ -0,0 +1,51 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__ASSERT_H +#define FLAC__ASSERT_H + +/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +#define FLAC__ASSERT(x) if(!(x)) __builtin_abort(); +#define FLAC__ASSERT_DECLARATION(x) x +#else +#ifndef NDEBUG +#include +#define FLAC__ASSERT(x) assert(x) +#define FLAC__ASSERT_DECLARATION(x) x +#else +#define FLAC__ASSERT(x) +#define FLAC__ASSERT_DECLARATION(x) +#endif +#endif + +#endif diff --git a/vendor/flac/include/FLAC/callback.h b/vendor/flac/include/FLAC/callback.h new file mode 100644 index 0000000..4babcd3 --- /dev/null +++ b/vendor/flac/include/FLAC/callback.h @@ -0,0 +1,190 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__CALLBACK_H +#define FLAC__CALLBACK_H + +#include "ordinals.h" +#include /* for size_t */ + +/** \file include/FLAC/callback.h + * + * \brief + * This module defines the structures for describing I/O callbacks + * to the other FLAC interfaces. + * + * See the detailed documentation for callbacks in the + * \link flac_callbacks callbacks \endlink module. + */ + +/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures + * \ingroup flac + * + * \brief + * This module defines the structures for describing I/O callbacks + * to the other FLAC interfaces. + * + * The purpose of the I/O callback functions is to create a common way + * for the metadata interfaces to handle I/O. + * + * Originally the metadata interfaces required filenames as the way of + * specifying FLAC files to operate on. This is problematic in some + * environments so there is an additional option to specify a set of + * callbacks for doing I/O on the FLAC file, instead of the filename. + * + * In addition to the callbacks, a FLAC__IOHandle type is defined as an + * opaque structure for a data source. + * + * The callback function prototypes are similar (but not identical) to the + * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use + * stdio streams to implement the callbacks, you can pass fread, fwrite, and + * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or + * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle + * is required. \warning You generally CANNOT directly use fseek or ftell + * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems + * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with + * large files. You will have to find an equivalent function (e.g. ftello), + * or write a wrapper. The same is true for feof() since this is usually + * implemented as a macro, not as a function whose address can be taken. + * + * \{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the opaque handle type used by the callbacks. Typically + * this is a \c FILE* or address of a file descriptor. + */ +typedef void* FLAC__IOHandle; + +/** Signature for the read callback. + * The signature and semantics match POSIX fread() implementations + * and can generally be used interchangeably. Note that the global + * variable errno from errno.h is read by some libFLAC functions to + * detect read errors. + * + * \param ptr The address of the read buffer. + * \param size The size of the records to be read. + * \param nmemb The number of records to be read. + * \param handle The handle to the data source. + * \retval size_t + * The number of records read. + */ +typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); + +/** Signature for the write callback. + * The signature and semantics match POSIX fwrite() implementations + * and can generally be used interchangeably. + * + * \param ptr The address of the write buffer. + * \param size The size of the records to be written. + * \param nmemb The number of records to be written. + * \param handle The handle to the data source. + * \retval size_t + * The number of records written. + */ +typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); + +/** Signature for the seek callback. + * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT + * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long' + * and 32-bits wide. + * + * \param handle The handle to the data source. + * \param offset The new position, relative to \a whence + * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END + * \retval int + * \c 0 on success, \c -1 on error. + */ +typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence); + +/** Signature for the tell callback. + * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT + * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long' + * and 32-bits wide. + * + * \param handle The handle to the data source. + * \retval FLAC__int64 + * The current position on success, \c -1 on error. + */ +typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle); + +/** Signature for the EOF callback. + * The signature and semantics mostly match POSIX feof() but WATCHOUT: + * on many systems, feof() is a macro, so in this case a wrapper function + * must be provided instead. + * + * \param handle The handle to the data source. + * \retval int + * \c 0 if not at end of file, nonzero if at end of file. + */ +typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle); + +/** Signature for the close callback. + * The signature and semantics match POSIX fclose() implementations + * and can generally be used interchangeably. + * + * \param handle The handle to the data source. + * \retval int + * \c 0 on success, \c EOF on error. + */ +typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle); + +/** A structure for holding a set of callbacks. + * Each FLAC interface that requires a FLAC__IOCallbacks structure will + * describe which of the callbacks are required. The ones that are not + * required may be set to NULL. + * + * If the seek requirement for an interface is optional, you can signify that + * a data source is not seekable by setting the \a seek field to \c NULL. + * + * See the detailed documentation for callbacks in the + * \link flac_callbacks callbacks \endlink module. + */ +typedef struct { + FLAC__IOCallback_Read read; /**< See FLAC__IOCallbacks */ + FLAC__IOCallback_Write write; /**< See FLAC__IOCallbacks */ + FLAC__IOCallback_Seek seek; /**< See FLAC__IOCallbacks */ + FLAC__IOCallback_Tell tell; /**< See FLAC__IOCallbacks */ + FLAC__IOCallback_Eof eof; /**< See FLAC__IOCallbacks */ + FLAC__IOCallback_Close close; /**< See FLAC__IOCallbacks */ +} FLAC__IOCallbacks; + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/FLAC/export.h b/vendor/flac/include/FLAC/export.h new file mode 100644 index 0000000..d14728a --- /dev/null +++ b/vendor/flac/include/FLAC/export.h @@ -0,0 +1,115 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__EXPORT_H +#define FLAC__EXPORT_H + +/** \file include/FLAC/export.h + * + * \brief + * This module contains \#defines and symbols for exporting function + * calls, and providing version information and compiled-in features. + * + * See the \link flac_export export \endlink module. + */ + +/** \defgroup flac_export FLAC/export.h: export symbols + * \ingroup flac + * + * \brief + * This module contains \#defines and symbols for exporting function + * calls, and providing version information and compiled-in features. + * + * If you are compiling for Windows (with Visual Studio or MinGW for + * example) and will link to the static library (libFLAC++.lib) you + * should define FLAC__NO_DLL in your project to make sure the symbols + * are exported properly. + * + * \{ + */ + +/** This \#define is used internally in libFLAC and its headers to make + * sure the correct symbols are exported when working with shared + * libraries. On Windows, this \#define is set to __declspec(dllexport) + * when compiling libFLAC into a library and to __declspec(dllimport) + * when the headers are used to link to that DLL. On non-Windows systems + * it is used to set symbol visibility. + * + * Because of this, the define FLAC__NO_DLL must be defined when linking + * to libFLAC statically or linking will fail. + */ +/* This has grown quite complicated. FLAC__NO_DLL is used by MSVC sln + * files and CMake, which build either static or shared. autotools can + * build static, shared or **both**. Therefore, DLL_EXPORT, which is set + * by libtool, must override FLAC__NO_DLL on building shared components + */ +#if defined(_WIN32) + +#if defined(FLAC__NO_DLL) && !(defined(DLL_EXPORT)) +#define FLAC_API +#else +#ifdef FLAC_API_EXPORTS +#define FLAC_API __declspec(dllexport) +#else +#define FLAC_API __declspec(dllimport) +#endif +#endif + +#elif defined(FLAC__USE_VISIBILITY_ATTR) +#define FLAC_API __attribute__ ((visibility ("default"))) + +#else +#define FLAC_API + +#endif + +/** These \#defines will mirror the libtool-based library version number, see + * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning + */ +#define FLAC_API_VERSION_CURRENT 13 +#define FLAC_API_VERSION_REVISION 0 /**< see above */ +#define FLAC_API_VERSION_AGE 1 /**< see above */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */ +extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC; + +#ifdef __cplusplus +} +#endif + +/* \} */ + +#endif diff --git a/vendor/flac/include/FLAC/format.h b/vendor/flac/include/FLAC/format.h new file mode 100644 index 0000000..ef7c8b2 --- /dev/null +++ b/vendor/flac/include/FLAC/format.h @@ -0,0 +1,1032 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__FORMAT_H +#define FLAC__FORMAT_H + +#include "export.h" +#include "ordinals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file include/FLAC/format.h + * + * \brief + * This module contains structure definitions for the representation + * of FLAC format components in memory. These are the basic + * structures used by the rest of the interfaces. + * + * See the detailed documentation in the + * \link flac_format format \endlink module. + */ + +/** \defgroup flac_format FLAC/format.h: format components + * \ingroup flac + * + * \brief + * This module contains structure definitions for the representation + * of FLAC format components in memory. These are the basic + * structures used by the rest of the interfaces. + * + * First, you should be familiar with the + * FLAC format. Many of the values here + * follow directly from the specification. As a user of libFLAC, the + * interesting parts really are the structures that describe the frame + * header and metadata blocks. + * + * The format structures here are very primitive, designed to store + * information in an efficient way. Reading information from the + * structures is easy but creating or modifying them directly is + * more complex. For the most part, as a user of a library, editing + * is not necessary; however, for metadata blocks it is, so there are + * convenience functions provided in the \link flac_metadata metadata + * module \endlink to simplify the manipulation of metadata blocks. + * + * \note + * It's not the best convention, but symbols ending in _LEN are in bits + * and _LENGTH are in bytes. _LENGTH symbols are \#defines instead of + * global variables because they are usually used when declaring byte + * arrays and some compilers require compile-time knowledge of array + * sizes when declared on the stack. + * + * \{ + */ + + +/* + Most of the values described in this file are defined by the FLAC + format specification. There is nothing to tune here. +*/ + +/** The largest legal metadata type code. */ +#define FLAC__MAX_METADATA_TYPE_CODE (126u) + +/** The minimum block size, in samples, permitted by the format. */ +#define FLAC__MIN_BLOCK_SIZE (16u) + +/** The maximum block size, in samples, permitted by the format. */ +#define FLAC__MAX_BLOCK_SIZE (65535u) + +/** The maximum block size, in samples, permitted by the FLAC subset for + * sample rates up to 48kHz. */ +#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u) + +/** The maximum number of channels permitted by the format. */ +#define FLAC__MAX_CHANNELS (8u) + +/** The minimum sample resolution permitted by the format. */ +#define FLAC__MIN_BITS_PER_SAMPLE (4u) + +/** The maximum sample resolution permitted by the format. */ +#define FLAC__MAX_BITS_PER_SAMPLE (32u) + +/** The maximum sample resolution permitted by libFLAC. + * + * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However, + * the reference encoder/decoder used to be limited to 24 bits. This + * value was used to signal that limit. + */ +#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (32u) + +/** The maximum sample rate permitted by the format. The value is + * ((2 ^ 20) - 1) + */ +#define FLAC__MAX_SAMPLE_RATE (1048575u) + +/** The maximum LPC order permitted by the format. */ +#define FLAC__MAX_LPC_ORDER (32u) + +/** The maximum LPC order permitted by the FLAC subset for sample rates + * up to 48kHz. */ +#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u) + +/** The minimum quantized linear predictor coefficient precision + * permitted by the format. + */ +#define FLAC__MIN_QLP_COEFF_PRECISION (5u) + +/** The maximum quantized linear predictor coefficient precision + * permitted by the format. + */ +#define FLAC__MAX_QLP_COEFF_PRECISION (15u) + +/** The maximum order of the fixed predictors permitted by the format. */ +#define FLAC__MAX_FIXED_ORDER (4u) + +/** The maximum Rice partition order permitted by the format. */ +#define FLAC__MAX_RICE_PARTITION_ORDER (15u) + +/** The maximum Rice partition order permitted by the FLAC Subset. */ +#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u) + +/** The version string of the release, stamped onto the libraries and binaries. + * + * \note + * This does not correspond to the shared library version number, which + * is used to determine binary compatibility. + */ +extern FLAC_API const char *FLAC__VERSION_STRING; + +/** The vendor string inserted by the encoder into the VORBIS_COMMENT block. + * This is a NUL-terminated ASCII string; when inserted into the + * VORBIS_COMMENT the trailing null is stripped. + */ +extern FLAC_API const char *FLAC__VENDOR_STRING; + +/** The byte string representation of the beginning of a FLAC stream. */ +extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */ + +/** The 32-bit integer big-endian representation of the beginning of + * a FLAC stream. + */ +extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */ + +/** The length of the FLAC signature in bits. */ +extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */ + +/** The length of the FLAC signature in bytes. */ +#define FLAC__STREAM_SYNC_LENGTH (4u) + + +/***************************************************************************** + * + * Subframe structures + * + *****************************************************************************/ + +/*****************************************************************************/ + +/** An enumeration of the available entropy coding methods. */ +typedef enum { + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0, + /**< Residual is coded by partitioning into contexts, each with it's own + * 4-bit Rice parameter. */ + + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1 + /**< Residual is coded by partitioning into contexts, each with it's own + * 5-bit Rice parameter. */ +} FLAC__EntropyCodingMethodType; + +/** Maps a FLAC__EntropyCodingMethodType to a C string. + * + * Using a FLAC__EntropyCodingMethodType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[]; + + +/** Contents of a Rice partitioned residual + */ +typedef struct { + + uint32_t *parameters; + /**< The Rice parameters for each context. */ + + uint32_t *raw_bits; + /**< Widths for escape-coded partitions. Will be non-zero for escaped + * partitions and zero for unescaped partitions. + */ + + uint32_t capacity_by_order; + /**< The capacity of the \a parameters and \a raw_bits arrays + * specified as an order, i.e. the number of array elements + * allocated is 2 ^ \a capacity_by_order. + */ +} FLAC__EntropyCodingMethod_PartitionedRiceContents; + +/** Header for a Rice partitioned residual. (c.f. format specification) + */ +typedef struct { + + uint32_t order; + /**< The partition order, i.e. # of contexts = 2 ^ \a order. */ + + const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents; + /**< The context's Rice parameters and/or raw bits. */ + +} FLAC__EntropyCodingMethod_PartitionedRice; + +extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */ +extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */ +extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */ +extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */ + +extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; +/**< == (1<format specification) + */ +typedef struct { + FLAC__EntropyCodingMethodType type; + union { + FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice; + } data; +} FLAC__EntropyCodingMethod; + +extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */ + +/*****************************************************************************/ + +/** An enumeration of the available subframe types. */ +typedef enum { + FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */ + FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */ + FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */ + FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */ +} FLAC__SubframeType; + +/** Maps a FLAC__SubframeType to a C string. + * + * Using a FLAC__SubframeType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__SubframeTypeString[]; + + +/** CONSTANT subframe. (c.f. format specification) + */ +typedef struct { + FLAC__int64 value; /**< The constant signal value. */ +} FLAC__Subframe_Constant; + +/** An enumeration of the possible verbatim subframe data types. */ +typedef enum { + FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32, /**< verbatim subframe has 32-bit int */ + FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64 /**< verbatim subframe has 64-bit int */ +} FLAC__VerbatimSubframeDataType; + + +/** VERBATIM subframe. (c.f. format specification) + */ +typedef struct { + union { + const FLAC__int32 *int32; /**< A FLAC__int32 pointer to verbatim signal. */ + const FLAC__int64 *int64; /**< A FLAC__int64 pointer to verbatim signal. */ + } data; + FLAC__VerbatimSubframeDataType data_type; +} FLAC__Subframe_Verbatim; + + +/** FIXED subframe. (c.f. format specification) + */ +typedef struct { + FLAC__EntropyCodingMethod entropy_coding_method; + /**< The residual coding method. */ + + uint32_t order; + /**< The polynomial order. */ + + FLAC__int64 warmup[FLAC__MAX_FIXED_ORDER]; + /**< Warmup samples to prime the predictor, length == order. */ + + const FLAC__int32 *residual; + /**< The residual signal, length == (blocksize minus order) samples. */ +} FLAC__Subframe_Fixed; + + +/** LPC subframe. (c.f. format specification) + */ +typedef struct { + FLAC__EntropyCodingMethod entropy_coding_method; + /**< The residual coding method. */ + + uint32_t order; + /**< The FIR order. */ + + uint32_t qlp_coeff_precision; + /**< Quantized FIR filter coefficient precision in bits. */ + + int quantization_level; + /**< The qlp coeff shift needed. */ + + FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; + /**< FIR filter coefficients. */ + + FLAC__int64 warmup[FLAC__MAX_LPC_ORDER]; + /**< Warmup samples to prime the predictor, length == order. */ + + const FLAC__int32 *residual; + /**< The residual signal, length == (blocksize minus order) samples. */ +} FLAC__Subframe_LPC; + +extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */ +extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */ + + +/** FLAC subframe structure. (c.f. format specification) + */ +typedef struct { + FLAC__SubframeType type; + union { + FLAC__Subframe_Constant constant; + FLAC__Subframe_Fixed fixed; + FLAC__Subframe_LPC lpc; + FLAC__Subframe_Verbatim verbatim; + } data; + uint32_t wasted_bits; +} FLAC__Subframe; + +/** == 1 (bit) + * + * This used to be a zero-padding bit (hence the name + * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit. It still has a + * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1 + * to mean something else. + */ +extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN; +extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */ +extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */ + +extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */ +extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */ +extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */ +extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */ + +/*****************************************************************************/ + + +/***************************************************************************** + * + * Frame structures + * + *****************************************************************************/ + +/** An enumeration of the available channel assignments. */ +typedef enum { + FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */ + FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */ + FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */ + FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */ +} FLAC__ChannelAssignment; + +/** Maps a FLAC__ChannelAssignment to a C string. + * + * Using a FLAC__ChannelAssignment as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__ChannelAssignmentString[]; + +/** An enumeration of the possible frame numbering methods. */ +typedef enum { + FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */ + FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */ +} FLAC__FrameNumberType; + +/** Maps a FLAC__FrameNumberType to a C string. + * + * Using a FLAC__FrameNumberType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__FrameNumberTypeString[]; + + +/** FLAC frame header structure. (c.f. format specification) + */ +typedef struct { + uint32_t blocksize; + /**< The number of samples per subframe. */ + + uint32_t sample_rate; + /**< The sample rate in Hz. */ + + uint32_t channels; + /**< The number of channels (== number of subframes). */ + + FLAC__ChannelAssignment channel_assignment; + /**< The channel assignment for the frame. */ + + uint32_t bits_per_sample; + /**< The sample resolution. */ + + FLAC__FrameNumberType number_type; + /**< The numbering scheme used for the frame. As a convenience, the + * decoder will always convert a frame number to a sample number because + * the rules are complex. */ + + union { + FLAC__uint32 frame_number; + FLAC__uint64 sample_number; + } number; + /**< The frame number or sample number of first sample in frame; + * use the \a number_type value to determine which to use. */ + + FLAC__uint8 crc; + /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) + * of the raw frame header bytes, meaning everything before the CRC byte + * including the sync code. + */ +} FLAC__FrameHeader; + +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */ +extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */ + + +/** FLAC frame footer structure. (c.f. format specification) + */ +typedef struct { + FLAC__uint16 crc; + /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with + * 0) of the bytes before the crc, back to and including the frame header + * sync code. + */ +} FLAC__FrameFooter; + +extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */ + + +/** FLAC frame structure. (c.f. format specification) + */ +typedef struct { + FLAC__FrameHeader header; + FLAC__Subframe subframes[FLAC__MAX_CHANNELS]; + FLAC__FrameFooter footer; +} FLAC__Frame; + +/*****************************************************************************/ + + +/***************************************************************************** + * + * Meta-data structures + * + *****************************************************************************/ + +/** An enumeration of the available metadata block types. */ +typedef enum { + + FLAC__METADATA_TYPE_STREAMINFO = 0, + /**< STREAMINFO block */ + + FLAC__METADATA_TYPE_PADDING = 1, + /**< PADDING block */ + + FLAC__METADATA_TYPE_APPLICATION = 2, + /**< APPLICATION block */ + + FLAC__METADATA_TYPE_SEEKTABLE = 3, + /**< SEEKTABLE block */ + + FLAC__METADATA_TYPE_VORBIS_COMMENT = 4, + /**< VORBISCOMMENT block (a.k.a. FLAC tags) */ + + FLAC__METADATA_TYPE_CUESHEET = 5, + /**< CUESHEET block */ + + FLAC__METADATA_TYPE_PICTURE = 6, + /**< PICTURE block */ + + FLAC__METADATA_TYPE_UNDEFINED = 7, + /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ + + FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE, + /**< No type will ever be greater than this. There is not enough room in the protocol block. */ +} FLAC__MetadataType; + +/** Maps a FLAC__MetadataType to a C string. + * + * Using a FLAC__MetadataType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__MetadataTypeString[]; + + +/** FLAC STREAMINFO structure. (c.f. format specification) + */ +typedef struct { + uint32_t min_blocksize, max_blocksize; + uint32_t min_framesize, max_framesize; + uint32_t sample_rate; + uint32_t channels; + uint32_t bits_per_sample; + FLAC__uint64 total_samples; + FLAC__byte md5sum[16]; +} FLAC__StreamMetadata_StreamInfo; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */ + +/** The total stream length of the STREAMINFO block in bytes. */ +#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u) + +/** FLAC PADDING structure. (c.f. format specification) + */ +typedef struct { + int dummy; + /**< Conceptually this is an empty struct since we don't store the + * padding bytes. Empty structs are not allowed by some C compilers, + * hence the dummy. + */ +} FLAC__StreamMetadata_Padding; + + +/** FLAC APPLICATION structure. (c.f. format specification) + */ +typedef struct { + FLAC__byte id[4]; + FLAC__byte *data; +} FLAC__StreamMetadata_Application; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */ + +/** SeekPoint structure used in SEEKTABLE blocks. (c.f. format specification) + */ +typedef struct { + FLAC__uint64 sample_number; + /**< The sample number of the target frame. */ + + FLAC__uint64 stream_offset; + /**< The offset, in bytes, of the target frame with respect to + * beginning of the first frame. */ + + uint32_t frame_samples; + /**< The number of samples in the target frame. */ +} FLAC__StreamMetadata_SeekPoint; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */ + +/** The total stream length of a seek point in bytes. */ +#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u) + +/** The value used in the \a sample_number field of + * FLAC__StreamMetadataSeekPoint used to indicate a placeholder + * point (== 0xffffffffffffffff). + */ +extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + + +/** FLAC SEEKTABLE structure. (c.f. format specification) + * + * \note From the format specification: + * - The seek points must be sorted by ascending sample number. + * - Each seek point's sample number must be the first sample of the + * target frame. + * - Each seek point's sample number must be unique within the table. + * - Existence of a SEEKTABLE block implies a correct setting of + * total_samples in the stream_info block. + * - Behavior is undefined when more than one SEEKTABLE block is + * present in a stream. + */ +typedef struct { + uint32_t num_points; + FLAC__StreamMetadata_SeekPoint *points; +} FLAC__StreamMetadata_SeekTable; + + +/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. format specification) + * + * For convenience, the APIs maintain a trailing NUL character at the end of + * \a entry which is not counted toward \a length, i.e. + * \code strlen(entry) == length \endcode + */ +typedef struct { + FLAC__uint32 length; + FLAC__byte *entry; +} FLAC__StreamMetadata_VorbisComment_Entry; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */ + + +/** FLAC VORBIS_COMMENT structure. (c.f. format specification) + */ +typedef struct { + FLAC__StreamMetadata_VorbisComment_Entry vendor_string; + FLAC__uint32 num_comments; + FLAC__StreamMetadata_VorbisComment_Entry *comments; +} FLAC__StreamMetadata_VorbisComment; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */ + + +/** FLAC CUESHEET track index structure. (See the + * format specification for + * the full description of each field.) + */ +typedef struct { + FLAC__uint64 offset; + /**< Offset in samples, relative to the track offset, of the index + * point. + */ + + FLAC__byte number; + /**< The index point number. */ +} FLAC__StreamMetadata_CueSheet_Index; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */ + + +/** FLAC CUESHEET track structure. (See the + * format specification for + * the full description of each field.) + */ +typedef struct { + FLAC__uint64 offset; + /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */ + + FLAC__byte number; + /**< The track number. */ + + char isrc[13]; + /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */ + + uint32_t type:1; + /**< The track type: 0 for audio, 1 for non-audio. */ + + uint32_t pre_emphasis:1; + /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */ + + FLAC__byte num_indices; + /**< The number of track index points. */ + + FLAC__StreamMetadata_CueSheet_Index *indices; + /**< NULL if num_indices == 0, else pointer to array of index points. */ + +} FLAC__StreamMetadata_CueSheet_Track; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */ + + +/** FLAC CUESHEET structure. (See the + * format specification + * for the full description of each field.) + */ +typedef struct { + char media_catalog_number[129]; + /**< Media catalog number, in ASCII printable characters 0x20-0x7e. In + * general, the media catalog number may be 0 to 128 bytes long; any + * unused characters should be right-padded with NUL characters. + */ + + FLAC__uint64 lead_in; + /**< The number of lead-in samples. */ + + FLAC__bool is_cd; + /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */ + + uint32_t num_tracks; + /**< The number of tracks. */ + + FLAC__StreamMetadata_CueSheet_Track *tracks; + /**< NULL if num_tracks == 0, else pointer to array of tracks. */ + +} FLAC__StreamMetadata_CueSheet; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */ + + +/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */ +typedef enum { + FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */ + FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */ + FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */ + FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */ + FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */ + FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */ + FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */ + FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */ + FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */ + FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED +} FLAC__StreamMetadata_Picture_Type; + +/** Maps a FLAC__StreamMetadata_Picture_Type to a C string. + * + * Using a FLAC__StreamMetadata_Picture_Type as the index to this array + * will give the string equivalent. The contents should not be + * modified. + */ +extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[]; + +/** FLAC PICTURE structure. (See the + * format specification + * for the full description of each field.) + */ +typedef struct { + FLAC__StreamMetadata_Picture_Type type; + /**< The kind of picture stored. */ + + char *mime_type; + /**< Picture data's MIME type, in ASCII printable characters + * 0x20-0x7e, NUL terminated. For best compatibility with players, + * use picture data of MIME type \c image/jpeg or \c image/png. A + * MIME type of '-->' is also allowed, in which case the picture + * data should be a complete URL. In file storage, the MIME type is + * stored as a 32-bit length followed by the ASCII string with no NUL + * terminator, but is converted to a plain C string in this structure + * for convenience. + */ + + FLAC__byte *description; + /**< Picture's description in UTF-8, NUL terminated. In file storage, + * the description is stored as a 32-bit length followed by the UTF-8 + * string with no NUL terminator, but is converted to a plain C string + * in this structure for convenience. + */ + + FLAC__uint32 width; + /**< Picture's width in pixels. */ + + FLAC__uint32 height; + /**< Picture's height in pixels. */ + + FLAC__uint32 depth; + /**< Picture's color depth in bits-per-pixel. */ + + FLAC__uint32 colors; + /**< For indexed palettes (like GIF), picture's number of colors (the + * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth). + */ + + FLAC__uint32 data_length; + /**< Length of binary picture data in bytes. */ + + FLAC__byte *data; + /**< Binary picture data. */ + +} FLAC__StreamMetadata_Picture; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */ + + +/** Structure that is used when a metadata block of unknown type is loaded. + * The contents are opaque. The structure is used only internally to + * correctly handle unknown metadata. + */ +typedef struct { + FLAC__byte *data; +} FLAC__StreamMetadata_Unknown; + + +/** FLAC metadata block structure. (c.f. format specification) + */ +typedef struct FLAC__StreamMetadata { + FLAC__MetadataType type; + /**< The type of the metadata block; used determine which member of the + * \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED + * then \a data.unknown must be used. */ + + FLAC__bool is_last; + /**< \c true if this metadata block is the last, else \a false */ + + uint32_t length; + /**< Length, in bytes, of the block data as it appears in the stream. */ + + union { + FLAC__StreamMetadata_StreamInfo stream_info; + FLAC__StreamMetadata_Padding padding; + FLAC__StreamMetadata_Application application; + FLAC__StreamMetadata_SeekTable seek_table; + FLAC__StreamMetadata_VorbisComment vorbis_comment; + FLAC__StreamMetadata_CueSheet cue_sheet; + FLAC__StreamMetadata_Picture picture; + FLAC__StreamMetadata_Unknown unknown; + } data; + /**< Polymorphic block data; use the \a type value to determine which + * to use. */ +} FLAC__StreamMetadata; + +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */ +extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */ + +/** The total stream length of a metadata block header in bytes. */ +#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u) + +/*****************************************************************************/ + + +/***************************************************************************** + * + * Utility functions + * + *****************************************************************************/ + +/** Tests that a sample rate is valid for FLAC. + * + * \param sample_rate The sample rate to test for compliance. + * \retval FLAC__bool + * \c true if the given sample rate conforms to the specification, else + * \c false. + */ +FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate); + +/** Tests that a blocksize at the given sample rate is valid for the FLAC + * subset. + * + * \param blocksize The blocksize to test for compliance. + * \param sample_rate The sample rate is needed, since the valid subset + * blocksize depends on the sample rate. + * \retval FLAC__bool + * \c true if the given blocksize conforms to the specification for the + * subset at the given sample rate, else \c false. + */ +FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate); + +/** Tests that a sample rate is valid for the FLAC subset. The subset rules + * for valid sample rates are slightly more complex since the rate has to + * be expressible completely in the frame header. + * + * \param sample_rate The sample rate to test for compliance. + * \retval FLAC__bool + * \c true if the given sample rate conforms to the specification for the + * subset, else \c false. + */ +FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate); + +/** Check a Vorbis comment entry name to see if it conforms to the Vorbis + * comment specification. + * + * Vorbis comment names must be composed only of characters from + * [0x20-0x3C,0x3E-0x7D]. + * + * \param name A NUL-terminated string to be checked. + * \assert + * \code name != NULL \endcode + * \retval FLAC__bool + * \c false if entry name is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name); + +/** Check a Vorbis comment entry value to see if it conforms to the Vorbis + * comment specification. + * + * Vorbis comment values must be valid UTF-8 sequences. + * + * \param value A string to be checked. + * \param length A the length of \a value in bytes. May be + * \c (uint32_t)(-1) to indicate that \a value is a plain + * UTF-8 NUL-terminated string. + * \assert + * \code value != NULL \endcode + * \retval FLAC__bool + * \c false if entry name is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length); + +/** Check a Vorbis comment entry to see if it conforms to the Vorbis + * comment specification. + * + * Vorbis comment entries must be of the form 'name=value', and 'name' and + * 'value' must be legal according to + * FLAC__format_vorbiscomment_entry_name_is_legal() and + * FLAC__format_vorbiscomment_entry_value_is_legal() respectively. + * + * \param entry An entry to be checked. + * \param length The length of \a entry in bytes. + * \assert + * \code value != NULL \endcode + * \retval FLAC__bool + * \c false if entry name is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length); + +/** Check a seek table to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * seek table. + * + * \param seek_table A pointer to a seek table to be checked. + * \assert + * \code seek_table != NULL \endcode + * \retval FLAC__bool + * \c false if seek table is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table); + +/** Sort a seek table's seek points according to the format specification. + * This includes a "unique-ification" step to remove duplicates, i.e. + * seek points with identical \a sample_number values. Duplicate seek + * points are converted into placeholder points and sorted to the end of + * the table. + * + * \param seek_table A pointer to a seek table to be sorted. + * \assert + * \code seek_table != NULL \endcode + * \retval uint32_t + * The number of duplicate seek points converted into placeholders. + */ +FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table); + +/** Check a cue sheet to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * cue sheet. + * + * \param cue_sheet A pointer to an existing cue sheet to be checked. + * \param check_cd_da_subset If \c true, check CUESHEET against more + * stringent requirements for a CD-DA (audio) disc. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code cue_sheet != NULL \endcode + * \retval FLAC__bool + * \c false if cue sheet is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation); + +/** Check picture data to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * PICTURE block. + * + * \param picture A pointer to existing picture data to be checked. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code picture != NULL \endcode + * \retval FLAC__bool + * \c false if picture data is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/FLAC/metadata.h b/vendor/flac/include/FLAC/metadata.h new file mode 100644 index 0000000..4747a5f --- /dev/null +++ b/vendor/flac/include/FLAC/metadata.h @@ -0,0 +1,2234 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__METADATA_H +#define FLAC__METADATA_H + +#include /* for off_t */ +#include "export.h" +#include "callback.h" +#include "format.h" + +/* -------------------------------------------------------------------- + (For an example of how all these routines are used, see the source + code for the unit tests in src/test_libFLAC/metadata_*.c, or + metaflac in src/metaflac/) + ------------------------------------------------------------------*/ + +/** \file include/FLAC/metadata.h + * + * \brief + * This module provides functions for creating and manipulating FLAC + * metadata blocks in memory, and three progressively more powerful + * interfaces for traversing and editing metadata in FLAC files. + * + * See the detailed documentation for each interface in the + * \link flac_metadata metadata \endlink module. + */ + +/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces + * \ingroup flac + * + * \brief + * This module provides functions for creating and manipulating FLAC + * metadata blocks in memory, and three progressively more powerful + * interfaces for traversing and editing metadata in native FLAC files. + * Note that currently only the Chain interface (level 2) supports Ogg + * FLAC files, and it is read-only i.e. no writing back changed + * metadata to file. + * + * There are three metadata interfaces of increasing complexity: + * + * Level 0: + * Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and + * PICTURE blocks. + * + * Level 1: + * Read-write access to all metadata blocks. This level is write- + * efficient in most cases (more on this below), and uses less memory + * than level 2. + * + * Level 2: + * Read-write access to all metadata blocks. This level is write- + * efficient in all cases, but uses more memory since all metadata for + * the whole file is read into memory and manipulated before writing + * out again. + * + * What do we mean by efficient? Since FLAC metadata appears at the + * beginning of the file, when writing metadata back to a FLAC file + * it is possible to grow or shrink the metadata such that the entire + * file must be rewritten. However, if the size remains the same during + * changes or PADDING blocks are utilized, only the metadata needs to be + * overwritten, which is much faster. + * + * Efficient means the whole file is rewritten at most one time, and only + * when necessary. Level 1 is not efficient only in the case that you + * cause more than one metadata block to grow or shrink beyond what can + * be accommodated by padding. In this case you should probably use level + * 2, which allows you to edit all the metadata for a file in memory and + * write it out all at once. + * + * All levels know how to skip over and not disturb an ID3v2 tag at the + * front of the file. + * + * All levels access files via their filenames. In addition, level 2 + * has additional alternative read and write functions that take an I/O + * handle and callbacks, for situations where access by filename is not + * possible. + * + * In addition to the three interfaces, this module defines functions for + * creating and manipulating various metadata objects in memory. As we see + * from the Format module, FLAC metadata blocks in memory are very primitive + * structures for storing information in an efficient way. Reading + * information from the structures is easy but creating or modifying them + * directly is more complex. The metadata object routines here facilitate + * this by taking care of the consistency and memory management drudgery. + * + * Unless you will be using the level 1 or 2 interfaces to modify existing + * metadata however, you will not probably not need these. + * + * From a dependency standpoint, none of the encoders or decoders require + * the metadata module. This is so that embedded users can strip out the + * metadata module from libFLAC to reduce the size and complexity. + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface + * \ingroup flac_metadata + * + * \brief + * The level 0 interface consists of individual routines to read the + * STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring + * only a filename. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * They try to skip any ID3v2 tag at the head of the file. + * + * \{ + */ + +/** Read the STREAMINFO metadata block of the given FLAC file. This function + * will try to skip any ID3v2 tag at the head of the file. + * + * \param filename The path to the FLAC file to read. + * \param streaminfo A pointer to space for the STREAMINFO block. Since + * FLAC__StreamMetadata is a simple structure with no + * memory allocation involved, you pass the address of + * an existing structure. It need not be initialized. + * \assert + * \code filename != NULL \endcode + * \code streaminfo != NULL \endcode + * \retval FLAC__bool + * \c true if a valid STREAMINFO block was read from \a filename. Returns + * \c false if there was a memory allocation error, a file decoder error, + * or the file contained no STREAMINFO block. (A memory allocation error + * is possible because this function must set up a file decoder.) + */ +FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo); + +/** Read the VORBIS_COMMENT metadata block of the given FLAC file. This + * function will try to skip any ID3v2 tag at the head of the file. + * + * \param filename The path to the FLAC file to read. + * \param tags The address where the returned pointer will be + * stored. The \a tags object must be deleted by + * the caller using FLAC__metadata_object_delete(). + * \assert + * \code filename != NULL \endcode + * \code tags != NULL \endcode + * \retval FLAC__bool + * \c true if a valid VORBIS_COMMENT block was read from \a filename, + * and \a *tags will be set to the address of the metadata structure. + * Returns \c false if there was a memory allocation error, a file + * decoder error, or the file contained no VORBIS_COMMENT block, and + * \a *tags will be set to \c NULL. + */ +FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags); + +/** Read the CUESHEET metadata block of the given FLAC file. This + * function will try to skip any ID3v2 tag at the head of the file. + * + * \param filename The path to the FLAC file to read. + * \param cuesheet The address where the returned pointer will be + * stored. The \a cuesheet object must be deleted by + * the caller using FLAC__metadata_object_delete(). + * \assert + * \code filename != NULL \endcode + * \code cuesheet != NULL \endcode + * \retval FLAC__bool + * \c true if a valid CUESHEET block was read from \a filename, + * and \a *cuesheet will be set to the address of the metadata + * structure. Returns \c false if there was a memory allocation + * error, a file decoder error, or the file contained no CUESHEET + * block, and \a *cuesheet will be set to \c NULL. + */ +FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet); + +/** Read a PICTURE metadata block of the given FLAC file. This + * function will try to skip any ID3v2 tag at the head of the file. + * Since there can be more than one PICTURE block in a file, this + * function takes a number of parameters that act as constraints to + * the search. The PICTURE block with the largest area matching all + * the constraints will be returned, or \a *picture will be set to + * \c NULL if there was no such block. + * + * \param filename The path to the FLAC file to read. + * \param picture The address where the returned pointer will be + * stored. The \a picture object must be deleted by + * the caller using FLAC__metadata_object_delete(). + * \param type The desired picture type. Use \c -1 to mean + * "any type". + * \param mime_type The desired MIME type, e.g. "image/jpeg". The + * string will be matched exactly. Use \c NULL to + * mean "any MIME type". + * \param description The desired description. The string will be + * matched exactly. Use \c NULL to mean "any + * description". + * \param max_width The maximum width in pixels desired. Use + * \c (uint32_t)(-1) to mean "any width". + * \param max_height The maximum height in pixels desired. Use + * \c (uint32_t)(-1) to mean "any height". + * \param max_depth The maximum color depth in bits-per-pixel desired. + * Use \c (uint32_t)(-1) to mean "any depth". + * \param max_colors The maximum number of colors desired. Use + * \c (uint32_t)(-1) to mean "any number of colors". + * \assert + * \code filename != NULL \endcode + * \code picture != NULL \endcode + * \retval FLAC__bool + * \c true if a valid PICTURE block was read from \a filename, + * and \a *picture will be set to the address of the metadata + * structure. Returns \c false if there was a memory allocation + * error, a file decoder error, or the file contained no PICTURE + * block, and \a *picture will be set to \c NULL. + */ +FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors); + +/* \} */ + + +/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface + * \ingroup flac_metadata + * + * \brief + * The level 1 interface provides read-write access to FLAC file metadata and + * operates directly on the FLAC file. + * + * The general usage of this interface is: + * + * - Create an iterator using FLAC__metadata_simple_iterator_new() + * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check + * the exit code. Call FLAC__metadata_simple_iterator_is_writable() to + * see if the file is writable, or only read access is allowed. + * - Use FLAC__metadata_simple_iterator_next() and + * FLAC__metadata_simple_iterator_prev() to traverse the blocks. + * This is does not read the actual blocks themselves. + * FLAC__metadata_simple_iterator_next() is relatively fast. + * FLAC__metadata_simple_iterator_prev() is slower since it needs to search + * forward from the front of the file. + * - Use FLAC__metadata_simple_iterator_get_block_type() or + * FLAC__metadata_simple_iterator_get_block() to access the actual data at + * the current iterator position. The returned object is yours to modify + * and free. + * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block + * back. You must have write permission to the original file. Make sure to + * read the whole comment to FLAC__metadata_simple_iterator_set_block() + * below. + * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks. + * Use the object creation functions from + * \link flac_metadata_object here \endlink to generate new objects. + * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block + * currently referred to by the iterator, or replace it with padding. + * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when + * finished. + * + * \note + * The FLAC file remains open the whole time between + * FLAC__metadata_simple_iterator_init() and + * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering + * the file during this time. + * + * \note + * Do not modify the \a is_last, \a length, or \a type fields of returned + * FLAC__StreamMetadata objects. These are managed automatically. + * + * \note + * If any of the modification functions + * (FLAC__metadata_simple_iterator_set_block(), + * FLAC__metadata_simple_iterator_delete_block(), + * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false, + * you should delete the iterator as it may no longer be valid. + * + * \{ + */ + +struct FLAC__Metadata_SimpleIterator; +/** The opaque structure definition for the level 1 iterator type. + * See the + * \link flac_metadata_level1 metadata level 1 module \endlink + * for a detailed description. + */ +typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator; + +/** Status type for FLAC__Metadata_SimpleIterator. + * + * The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status(). + */ +typedef enum { + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0, + /**< The iterator is in the normal OK state */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, + /**< The data passed into a function violated the function's usage criteria */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE, + /**< The iterator could not open the target file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE, + /**< The iterator could not find the FLAC signature at the start of the file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE, + /**< The iterator tried to write to a file that was not writable */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA, + /**< The iterator encountered input that does not conform to the FLAC metadata specification */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR, + /**< The iterator encountered an error while reading the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, + /**< The iterator encountered an error while seeking in the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR, + /**< The iterator encountered an error while writing the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR, + /**< The iterator encountered an error renaming the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR, + /**< The iterator encountered an error removing the temporary file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR, + /**< Memory allocation failed */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR + /**< The caller violated an assertion or an unexpected error occurred */ + +} FLAC__Metadata_SimpleIteratorStatus; + +/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string. + * + * Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[]; + + +/** Create a new iterator instance. + * + * \retval FLAC__Metadata_SimpleIterator* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void); + +/** Free an iterator instance. Deletes the object pointed to by \a iterator. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + */ +FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator); + +/** Get the current status of the iterator. Call this after a function + * returns \c false to get the reason for the error. Also resets the status + * to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + * \retval FLAC__Metadata_SimpleIteratorStatus + * The current status of the iterator. + */ +FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator); + +/** Initialize the iterator to point to the first metadata block in the + * given FLAC file. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * \param iterator A pointer to an existing iterator. + * \param filename The path to the FLAC file. + * \param read_only If \c true, the FLAC file will be opened + * in read-only mode; if \c false, the FLAC + * file will be opened for edit even if no + * edits are performed. + * \param preserve_file_stats If \c true, the owner and modification + * time will be preserved even if the FLAC + * file is written to. + * \assert + * \code iterator != NULL \endcode + * \code filename != NULL \endcode + * \retval FLAC__bool + * \c false if a memory allocation error occurs, the file can't be + * opened, or another error occurs, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats); + +/** Returns \c true if the FLAC file is writable. If \c false, calls to + * FLAC__metadata_simple_iterator_set_block() and + * FLAC__metadata_simple_iterator_insert_block_after() will fail. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + * \retval FLAC__bool + * See above. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator); + +/** Moves the iterator forward one metadata block, returning \c false if + * already at the end. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c false if already at the last metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator); + +/** Moves the iterator backward one metadata block, returning \c false if + * already at the beginning. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c false if already at the first metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator); + +/** Returns a flag telling if the current metadata block is the last. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c true if the current metadata block is the last in the file, + * else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator); + +/** Get the offset of the metadata block at the current position. This + * avoids reading the actual block data which can save time for large + * blocks. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval off_t + * The offset of the metadata block at the current iterator position. + * This is the byte offset relative to the beginning of the file of + * the current metadata block's header. + */ +FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator); + +/** Get the type of the metadata block at the current position. This + * avoids reading the actual block data which can save time for large + * blocks. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__MetadataType + * The type of the metadata block at the current iterator position. + */ +FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator); + +/** Get the length of the metadata block at the current position. This + * avoids reading the actual block data which can save time for large + * blocks. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval uint32_t + * The length of the metadata block at the current iterator position. + * The is same length as that in the + * metadata block header, + * i.e. the length of the metadata body that follows the header. + */ +FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator); + +/** Get the application ID of the \c APPLICATION block at the current + * position. This avoids reading the actual block data which can save + * time for large blocks. + * + * \param iterator A pointer to an existing initialized iterator. + * \param id A pointer to a buffer of at least \c 4 bytes where + * the ID will be stored. + * \assert + * \code iterator != NULL \endcode + * \code id != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c true if the ID was successfully read, else \c false, in which + * case you should check FLAC__metadata_simple_iterator_status() to + * find out why. If the status is + * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the + * current metadata block is not an \c APPLICATION block. Otherwise + * if the status is + * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or + * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error + * occurred and the iterator can no longer be used. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id); + +/** Get the metadata block at the current position. You can modify the + * block but must use FLAC__metadata_simple_iterator_set_block() to + * write it back to the FLAC file. + * + * You must call FLAC__metadata_object_delete() on the returned object + * when you are finished with it. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__StreamMetadata* + * The current metadata block, or \c NULL if there was a memory + * allocation error. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator); + +/** Write a block back to the FLAC file. This function tries to be + * as efficient as possible; how the block is actually written is + * shown by the following: + * + * Existing block is a STREAMINFO block and the new block is a + * STREAMINFO block: the new block is written in place. Make sure + * you know what you're doing when changing the values of a + * STREAMINFO block. + * + * Existing block is a STREAMINFO block and the new block is a + * not a STREAMINFO block: this is an error since the first block + * must be a STREAMINFO block. Returns \c false without altering the + * file. + * + * Existing block is not a STREAMINFO block and the new block is a + * STREAMINFO block: this is an error since there may be only one + * STREAMINFO block. Returns \c false without altering the file. + * + * Existing block and new block are the same length: the existing + * block will be replaced by the new block, written in place. + * + * Existing block is longer than new block: if use_padding is \c true, + * the existing block will be overwritten in place with the new + * block followed by a PADDING block, if possible, to make the total + * size the same as the existing block. Remember that a padding + * block requires at least four bytes so if the difference in size + * between the new block and existing block is less than that, the + * entire file will have to be rewritten, using the new block's + * exact size. If use_padding is \c false, the entire file will be + * rewritten, replacing the existing block by the new block. + * + * Existing block is shorter than new block: if use_padding is \c true, + * the function will try and expand the new block into the following + * PADDING block, if it exists and doing so won't shrink the PADDING + * block to less than 4 bytes. If there is no following PADDING + * block, or it will shrink to less than 4 bytes, or use_padding is + * \c false, the entire file is rewritten, replacing the existing block + * with the new block. Note that in this case any following PADDING + * block is preserved as is. + * + * After writing the block, the iterator will remain in the same + * place, i.e. pointing to the new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block The block to set. + * \param use_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \code block != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); + +/** This is similar to FLAC__metadata_simple_iterator_set_block() + * except that instead of writing over an existing block, it appends + * a block after the existing block. \a use_padding is again used to + * tell the function to try an expand into following padding in an + * attempt to avoid rewriting the entire file. + * + * This function will fail and return \c false if given a STREAMINFO + * block. + * + * After writing the block, the iterator will be pointing to the + * new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block The block to set. + * \param use_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \code block != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); + +/** Deletes the block at the current position. This will cause the + * entire FLAC file to be rewritten, unless \a use_padding is \c true, + * in which case the block will be replaced by an equal-sized PADDING + * block. The iterator will be left pointing to the block before the + * one just deleted. + * + * You may not delete the STREAMINFO block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param use_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding); + +/* \} */ + + +/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface + * \ingroup flac_metadata + * + * \brief + * The level 2 interface provides read-write access to FLAC file metadata; + * all metadata is read into memory, operated on in memory, and then written + * to file, which is more efficient than level 1 when editing multiple blocks. + * + * Currently Ogg FLAC is supported for read only, via + * FLAC__metadata_chain_read_ogg() but a subsequent + * FLAC__metadata_chain_write() will fail. + * + * The general usage of this interface is: + * + * - Create a new chain using FLAC__metadata_chain_new(). A chain is a + * linked list of FLAC metadata blocks. + * - Read all metadata into the chain from a FLAC file using + * FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and + * check the status. + * - Optionally, consolidate the padding using + * FLAC__metadata_chain_merge_padding() or + * FLAC__metadata_chain_sort_padding(). + * - Create a new iterator using FLAC__metadata_iterator_new() + * - Initialize the iterator to point to the first element in the chain + * using FLAC__metadata_iterator_init() + * - Traverse the chain using FLAC__metadata_iterator_next and + * FLAC__metadata_iterator_prev(). + * - Get a block for reading or modification using + * FLAC__metadata_iterator_get_block(). The pointer to the object + * inside the chain is returned, so the block is yours to modify. + * Changes will be reflected in the FLAC file when you write the + * chain. You can also add and delete blocks (see functions below). + * - When done, write out the chain using FLAC__metadata_chain_write(). + * Make sure to read the whole comment to the function below. + * - Delete the chain using FLAC__metadata_chain_delete(). + * + * \note + * Even though the FLAC file is not open while the chain is being + * manipulated, you must not alter the file externally during + * this time. The chain assumes the FLAC file will not change + * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg() + * and FLAC__metadata_chain_write(). + * + * \note + * Do not modify the is_last, length, or type fields of returned + * FLAC__StreamMetadata objects. These are managed automatically. + * + * \note + * The metadata objects returned by FLAC__metadata_iterator_get_block() + * are owned by the chain; do not FLAC__metadata_object_delete() them. + * In the same way, blocks passed to FLAC__metadata_iterator_set_block() + * become owned by the chain and they will be deleted when the chain is + * deleted. + * + * \{ + */ + +struct FLAC__Metadata_Chain; +/** The opaque structure definition for the level 2 chain type. + */ +typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain; + +struct FLAC__Metadata_Iterator; +/** The opaque structure definition for the level 2 iterator type. + */ +typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator; + +typedef enum { + FLAC__METADATA_CHAIN_STATUS_OK = 0, + /**< The chain is in the normal OK state */ + + FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT, + /**< The data passed into a function violated the function's usage criteria */ + + FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE, + /**< The chain could not open the target file */ + + FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE, + /**< The chain could not find the FLAC signature at the start of the file */ + + FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE, + /**< The chain tried to write to a file that was not writable */ + + FLAC__METADATA_CHAIN_STATUS_BAD_METADATA, + /**< The chain encountered input that does not conform to the FLAC metadata specification */ + + FLAC__METADATA_CHAIN_STATUS_READ_ERROR, + /**< The chain encountered an error while reading the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR, + /**< The chain encountered an error while seeking in the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR, + /**< The chain encountered an error while writing the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR, + /**< The chain encountered an error renaming the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR, + /**< The chain encountered an error removing the temporary file */ + + FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR, + /**< Memory allocation failed */ + + FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR, + /**< The caller violated an assertion or an unexpected error occurred */ + + FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS, + /**< One or more of the required callbacks was NULL */ + + FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH, + /**< FLAC__metadata_chain_write() was called on a chain read by + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), + * or + * FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile() + * was called on a chain read by + * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). + * Matching read/write methods must always be used. */ + + FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL + /**< FLAC__metadata_chain_write_with_callbacks() was called when the + * chain write requires a tempfile; use + * FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead. + * Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was + * called when the chain write does not require a tempfile; use + * FLAC__metadata_chain_write_with_callbacks() instead. + * Always check FLAC__metadata_chain_check_if_tempfile_needed() + * before writing via callbacks. */ + +} FLAC__Metadata_ChainStatus; + +/** Maps a FLAC__Metadata_ChainStatus to a C string. + * + * Using a FLAC__Metadata_ChainStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[]; + +/*********** FLAC__Metadata_Chain ***********/ + +/** Create a new chain instance. + * + * \retval FLAC__Metadata_Chain* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void); + +/** Free a chain instance. Deletes the object pointed to by \a chain. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain); + +/** Get the current status of the chain. Call this after a function + * returns \c false to get the reason for the error. Also resets the + * status to FLAC__METADATA_CHAIN_STATUS_OK. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__Metadata_ChainStatus + * The current status of the chain. + */ +FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain); + +/** Read all metadata from a FLAC file into the chain. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * \param chain A pointer to an existing chain. + * \param filename The path to the FLAC file to read. + * \assert + * \code chain != NULL \endcode + * \code filename != NULL \endcode + * \retval FLAC__bool + * \c true if a valid list of metadata blocks was read from + * \a filename, else \c false. On failure, check the status with + * FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename); + +/** Read all metadata from an Ogg FLAC file into the chain. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * \note Ogg FLAC metadata data writing is not supported yet and + * FLAC__metadata_chain_write() will fail. + * + * \param chain A pointer to an existing chain. + * \param filename The path to the Ogg FLAC file to read. + * \assert + * \code chain != NULL \endcode + * \code filename != NULL \endcode + * \retval FLAC__bool + * \c true if a valid list of metadata blocks was read from + * \a filename, else \c false. On failure, check the status with + * FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename); + +/** Read all metadata from a FLAC stream into the chain via I/O callbacks. + * + * The \a handle need only be open for reading, but must be seekable. + * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" + * for Windows). + * + * \param chain A pointer to an existing chain. + * \param handle The I/O handle of the FLAC stream to read. The + * handle will NOT be closed after the metadata is read; + * that is the duty of the caller. + * \param callbacks + * A set of callbacks to use for I/O. The mandatory + * callbacks are \a read, \a seek, and \a tell. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if a valid list of metadata blocks was read from + * \a handle, else \c false. On failure, check the status with + * FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); + +/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks. + * + * The \a handle need only be open for reading, but must be seekable. + * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" + * for Windows). + * + * \note Ogg FLAC metadata data writing is not supported yet and + * FLAC__metadata_chain_write() will fail. + * + * \param chain A pointer to an existing chain. + * \param handle The I/O handle of the Ogg FLAC stream to read. The + * handle will NOT be closed after the metadata is read; + * that is the duty of the caller. + * \param callbacks + * A set of callbacks to use for I/O. The mandatory + * callbacks are \a read, \a seek, and \a tell. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if a valid list of metadata blocks was read from + * \a handle, else \c false. On failure, check the status with + * FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); + +/** Checks if writing the given chain would require the use of a + * temporary file, or if it could be written in place. + * + * Under certain conditions, padding can be utilized so that writing + * edited metadata back to the FLAC file does not require rewriting the + * entire file. If rewriting is required, then a temporary workfile is + * required. When writing metadata using callbacks, you must check + * this function to know whether to call + * FLAC__metadata_chain_write_with_callbacks() or + * FLAC__metadata_chain_write_with_callbacks_and_tempfile(). When + * writing with FLAC__metadata_chain_write(), the temporary file is + * handled internally. + * + * \param chain A pointer to an existing chain. + * \param use_padding + * Whether or not padding will be allowed to be used + * during the write. The value of \a use_padding given + * here must match the value later passed to + * FLAC__metadata_chain_write_with_callbacks() or + * FLAC__metadata_chain_write_with_callbacks_with_tempfile(). + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if writing the current chain would require a tempfile, or + * \c false if metadata can be written in place. + */ +FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding); + +/** Write all metadata out to the FLAC file. This function tries to be as + * efficient as possible; how the metadata is actually written is shown by + * the following: + * + * If the current chain is the same size as the existing metadata, the new + * data is written in place. + * + * If the current chain is longer than the existing metadata, and + * \a use_padding is \c true, and the last block is a PADDING block of + * sufficient length, the function will truncate the final padding block + * so that the overall size of the metadata is the same as the existing + * metadata, and then just rewrite the metadata. Otherwise, if not all of + * the above conditions are met, the entire FLAC file must be rewritten. + * If you want to use padding this way it is a good idea to call + * FLAC__metadata_chain_sort_padding() first so that you have the maximum + * amount of padding to work with, unless you need to preserve ordering + * of the PADDING blocks for some reason. + * + * If the current chain is shorter than the existing metadata, and + * \a use_padding is \c true, and the final block is a PADDING block, the padding + * is extended to make the overall size the same as the existing data. If + * \a use_padding is \c true and the last block is not a PADDING block, a new + * PADDING block is added to the end of the new data to make it the same + * size as the existing data (if possible, see the note to + * FLAC__metadata_simple_iterator_set_block() about the four byte limit) + * and the new data is written in place. If none of the above apply or + * \a use_padding is \c false, the entire FLAC file is rewritten. + * + * If \a preserve_file_stats is \c true, the owner and modification time will + * be preserved even if the FLAC file is written. + * + * For this write function to be used, the chain must have been read with + * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(). + * + * \param chain A pointer to an existing chain. + * \param use_padding See above. + * \param preserve_file_stats See above. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if the write succeeded, else \c false. On failure, + * check the status with FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats); + +/** Write all metadata out to a FLAC stream via callbacks. + * + * (See FLAC__metadata_chain_write() for the details on how padding is + * used to write metadata in place if possible.) + * + * The \a handle must be open for updating and be seekable. The + * equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b" + * for Windows). + * + * For this write function to be used, the chain must have been read with + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), + * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). + * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned + * \c false. + * + * \param chain A pointer to an existing chain. + * \param use_padding See FLAC__metadata_chain_write() + * \param handle The I/O handle of the FLAC stream to write. The + * handle will NOT be closed after the metadata is + * written; that is the duty of the caller. + * \param callbacks A set of callbacks to use for I/O. The mandatory + * callbacks are \a write and \a seek. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if the write succeeded, else \c false. On failure, + * check the status with FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); + +/** Write all metadata out to a FLAC stream via callbacks. + * + * (See FLAC__metadata_chain_write() for the details on how padding is + * used to write metadata in place if possible.) + * + * This version of the write-with-callbacks function must be used when + * FLAC__metadata_chain_check_if_tempfile_needed() returns true. In + * this function, you must supply an I/O handle corresponding to the + * FLAC file to edit, and a temporary handle to which the new FLAC + * file will be written. It is the caller's job to move this temporary + * FLAC file on top of the original FLAC file to complete the metadata + * edit. + * + * The \a handle must be open for reading and be seekable. The + * equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" + * for Windows). + * + * The \a temp_handle must be open for writing. The + * equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb" + * for Windows). It should be an empty stream, or at least positioned + * at the start-of-file (in which case it is the caller's duty to + * truncate it on return). + * + * For this write function to be used, the chain must have been read with + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), + * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). + * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned + * \c true. + * + * \param chain A pointer to an existing chain. + * \param use_padding See FLAC__metadata_chain_write() + * \param handle The I/O handle of the original FLAC stream to read. + * The handle will NOT be closed after the metadata is + * written; that is the duty of the caller. + * \param callbacks A set of callbacks to use for I/O on \a handle. + * The mandatory callbacks are \a read, \a seek, and + * \a eof. + * \param temp_handle The I/O handle of the FLAC stream to write. The + * handle will NOT be closed after the metadata is + * written; that is the duty of the caller. + * \param temp_callbacks + * A set of callbacks to use for I/O on temp_handle. + * The only mandatory callback is \a write. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if the write succeeded, else \c false. On failure, + * check the status with FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks); + +/** Merge adjacent PADDING blocks into a single block. + * + * \note This function does not write to the FLAC file, it only + * modifies the chain. + * + * \warning Any iterator on the current chain will become invalid after this + * call. You should delete the iterator and get a new one. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain); + +/** This function will move all PADDING blocks to the end on the metadata, + * then merge them into a single block. + * + * \note This function does not write to the FLAC file, it only + * modifies the chain. + * + * \warning Any iterator on the current chain will become invalid after this + * call. You should delete the iterator and get a new one. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain); + + +/*********** FLAC__Metadata_Iterator ***********/ + +/** Create a new iterator instance. + * + * \retval FLAC__Metadata_Iterator* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void); + +/** Free an iterator instance. Deletes the object pointed to by \a iterator. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + */ +FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator); + +/** Initialize the iterator to point to the first metadata block in the + * given chain. + * + * \param iterator A pointer to an existing iterator. + * \param chain A pointer to an existing and initialized (read) chain. + * \assert + * \code iterator != NULL \endcode + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain); + +/** Moves the iterator forward one metadata block, returning \c false if + * already at the end. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if already at the last metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator); + +/** Moves the iterator backward one metadata block, returning \c false if + * already at the beginning. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if already at the first metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator); + +/** Get the type of the metadata block at the current position. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__MetadataType + * The type of the metadata block at the current iterator position. + */ +FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator); + +/** Get the metadata block at the current position. You can modify + * the block in place but must write the chain before the changes + * are reflected to the FLAC file. You do not need to call + * FLAC__metadata_iterator_set_block() to reflect the changes; + * the pointer returned by FLAC__metadata_iterator_get_block() + * points directly into the chain. + * + * \warning + * Do not call FLAC__metadata_object_delete() on the returned object; + * to delete a block use FLAC__metadata_iterator_delete_block(). + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__StreamMetadata* + * The current metadata block. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator); + +/** Set the metadata block at the current position, replacing the existing + * block. The new block passed in becomes owned by the chain and it will be + * deleted when the chain is deleted. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block A pointer to a metadata block. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \code block != NULL \endcode + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, or + * a memory allocation error occurs, otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); + +/** Removes the current block from the chain. If \a replace_with_padding is + * \c true, the block will instead be replaced with a padding block of equal + * size. You can not delete the STREAMINFO block. The iterator will be + * left pointing to the block before the one just "deleted", even if + * \a replace_with_padding is \c true. + * + * \param iterator A pointer to an existing initialized iterator. + * \param replace_with_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, + * otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding); + +/** Insert a new block before the current block. You cannot insert a block + * before the first STREAMINFO block. You cannot insert a STREAMINFO block + * as there can be only one, the one that already exists at the head when you + * read in a chain. The chain takes ownership of the new block and it will be + * deleted when the chain is deleted. The iterator will be left pointing to + * the new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block A pointer to a metadata block to insert. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, or + * a memory allocation error occurs, otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); + +/** Insert a new block after the current block. You cannot insert a STREAMINFO + * block as there can be only one, the one that already exists at the head when + * you read in a chain. The chain takes ownership of the new block and it will + * be deleted when the chain is deleted. The iterator will be left pointing to + * the new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block A pointer to a metadata block to insert. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, or + * a memory allocation error occurs, otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); + +/* \} */ + + +/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods + * \ingroup flac_metadata + * + * \brief + * This module contains methods for manipulating FLAC metadata objects. + * + * Since many are variable length we have to be careful about the memory + * management. We decree that all pointers to data in the object are + * owned by the object and memory-managed by the object. + * + * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete() + * functions to create all instances. When using the + * FLAC__metadata_object_set_*() functions to set pointers to data, set + * \a copy to \c true to have the function make it's own copy of the data, or + * to \c false to give the object ownership of your data. In the latter case + * your pointer must be freeable by free() and will be free()d when the object + * is FLAC__metadata_object_delete()d. It is legal to pass a null pointer as + * the data pointer to a FLAC__metadata_object_set_*() function as long as + * the length argument is 0 and the \a copy argument is \c false. + * + * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function + * will return \c NULL in the case of a memory allocation error, otherwise a new + * object. The FLAC__metadata_object_set_*() functions return \c false in the + * case of a memory allocation error. + * + * We don't have the convenience of C++ here, so note that the library relies + * on you to keep the types straight. In other words, if you pass, for + * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to + * FLAC__metadata_object_application_set_data(), you will get an assertion + * failure. + * + * For convenience the FLAC__metadata_object_vorbiscomment_*() functions + * maintain a trailing NUL on each Vorbis comment entry. This is not counted + * toward the length or stored in the stream, but it can make working with plain + * comments (those that don't contain embedded-NULs in the value) easier. + * Entries passed into these functions have trailing NULs added if missing, and + * returned entries are guaranteed to have a trailing NUL. + * + * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis + * comment entry/name/value will first validate that it complies with the Vorbis + * comment specification and return false if it does not. + * + * There is no need to recalculate the length field on metadata blocks you + * have modified. They will be calculated automatically before they are + * written back to a file. + * + * \{ + */ + + +/** Create a new metadata object instance of the given type. + * + * The object will be "empty"; i.e. values and data pointers will be \c 0, + * with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have + * the vendor string set (but zero comments). + * + * Do not pass in a value greater than or equal to + * \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're + * doing. + * + * \param type Type of object to create + * \retval FLAC__StreamMetadata* + * \c NULL if there was an error allocating memory or the type code is + * greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type); + +/** Create a copy of an existing metadata object. + * + * The copy is a "deep" copy, i.e. dynamically allocated data within the + * object is also copied. The caller takes ownership of the new block and + * is responsible for freeing it with FLAC__metadata_object_delete(). + * + * \param object Pointer to object to copy. + * \assert + * \code object != NULL \endcode + * \retval FLAC__StreamMetadata* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object); + +/** Free a metadata object. Deletes the object pointed to by \a object. + * + * The delete is a "deep" delete, i.e. dynamically allocated data within the + * object is also deleted. + * + * \param object A pointer to an existing object. + * \assert + * \code object != NULL \endcode + */ +FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object); + +/** Compares two metadata objects. + * + * The compare is "deep", i.e. dynamically allocated data within the + * object is also compared. + * + * \param block1 A pointer to an existing object. + * \param block2 A pointer to an existing object. + * \assert + * \code block1 != NULL \endcode + * \code block2 != NULL \endcode + * \retval FLAC__bool + * \c true if objects are identical, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2); + +/** Sets the application data of an APPLICATION block. + * + * If \a copy is \c true, a copy of the data is stored; otherwise, the object + * takes ownership of the pointer. The existing data will be freed if this + * function is successful, otherwise the original data will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a data if \a copy is \c true. + * + * \param object A pointer to an existing APPLICATION object. + * \param data A pointer to the data to set. + * \param length The length of \a data in bytes. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode + * \code (data != NULL && length > 0) || + * (data == NULL && length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy); + +/** Resize the seekpoint array. + * + * If the size shrinks, elements will truncated; if it grows, new placeholder + * points will be added to the end. If this function returns false, the + * object is left untouched. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param new_num_points The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) || + * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points); + +/** Set a seekpoint in a seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param point_num Index into seekpoint array to set. + * \param point The point to set. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code object->data.seek_table.num_points > point_num \endcode + */ +FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point); + +/** Insert a seekpoint into a seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param point_num Index into seekpoint array to set. + * \param point The point to set. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code object->data.seek_table.num_points >= point_num \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point); + +/** Delete a seekpoint from a seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param point_num Index into seekpoint array to set. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code object->data.seek_table.num_points > point_num \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num); + +/** Check a seektable to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if seek table is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object); + +/** Append a number of placeholder points to the end of a seek table. + * + * \note + * As with the other ..._seektable_template_... functions, you should + * call FLAC__metadata_object_seektable_template_sort() when finished + * to make the seek table legal. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param num The number of placeholder points to append. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num); + +/** Append a specific seek point template to the end of a seek table. + * + * \note + * As with the other ..._seektable_template_... functions, you should + * call FLAC__metadata_object_seektable_template_sort() when finished + * to make the seek table legal. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param sample_number The sample number of the seek point template. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number); + +/** Append specific seek point templates to the end of a seek table. + * + * \note + * As with the other ..._seektable_template_... functions, you should + * call FLAC__metadata_object_seektable_template_sort() when finished + * to make the seek table legal. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param sample_numbers An array of sample numbers for the seek points. + * \param num The number of seek point templates to append. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num); + +/** Append a set of evenly-spaced seek point templates to the end of a + * seek table. + * + * \note + * As with the other ..._seektable_template_... functions, you should + * call FLAC__metadata_object_seektable_template_sort() when finished + * to make the seek table legal. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param num The number of placeholder points to append. + * \param total_samples The total number of samples to be encoded; + * the seekpoints will be spaced approximately + * \a total_samples / \a num samples apart. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code total_samples > 0 \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples); + +/** Append a set of evenly-spaced seek point templates to the end of a + * seek table. + * + * \note + * As with the other ..._seektable_template_... functions, you should + * call FLAC__metadata_object_seektable_template_sort() when finished + * to make the seek table legal. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param samples The number of samples apart to space the placeholder + * points. The first point will be at sample \c 0, the + * second at sample \a samples, then 2*\a samples, and + * so on. As long as \a samples and \a total_samples + * are greater than \c 0, there will always be at least + * one seekpoint at sample \c 0. + * \param total_samples The total number of samples to be encoded; + * the seekpoints will be spaced + * \a samples samples apart. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code samples > 0 \endcode + * \code total_samples > 0 \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples); + +/** Sort a seek table's seek points according to the format specification, + * removing duplicates. + * + * \param object A pointer to a seek table to be sorted. + * \param compact If \c false, behaves like FLAC__format_seektable_sort(). + * If \c true, duplicates are deleted and the seek table is + * shrunk appropriately; the number of placeholder points + * present in the seek table will be the same after the call + * as before. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if realloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact); + +/** Sets the vendor string in a VORBIS_COMMENT block. + * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * + * If \a copy is \c true, a copy of the entry is stored; otherwise, the object + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param entry The entry to set the vendor string to. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); + +/** Resize the comment array. + * + * If the size shrinks, elements will truncated; if it grows, new empty + * fields will be added to the end. If this function returns false, the + * object is left untouched. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param new_num_comments The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) || + * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments); + +/** Sets a comment in a VORBIS_COMMENT block. + * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * + * If \a copy is \c true, a copy of the entry is stored; otherwise, the object + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param comment_num Index into comment array to set. + * \param entry The entry to set the comment to. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code comment_num < object->data.vorbis_comment.num_comments \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); + +/** Insert a comment in a VORBIS_COMMENT block at the given index. + * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * + * If \a copy is \c true, a copy of the entry is stored; otherwise, the object + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param comment_num The index at which to insert the comment. The comments + * at and after \a comment_num move right one position. + * To append a comment to the end, set \a comment_num to + * \c object->data.vorbis_comment.num_comments . + * \param entry The comment to insert. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code object->data.vorbis_comment.num_comments >= comment_num \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); + +/** Appends a comment to a VORBIS_COMMENT block. + * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * + * If \a copy is \c true, a copy of the entry is stored; otherwise, the object + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param entry The comment to insert. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); + +/** Replaces comments in a VORBIS_COMMENT block with a new one. + * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * + * Depending on the value of \a all, either all or just the first comment + * whose field name(s) match the given entry's name will be replaced by the + * given entry. If no comments match, \a entry will simply be appended. + * + * If \a copy is \c true, a copy of the entry is stored; otherwise, the object + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param entry The comment to insert. + * \param all If \c true, all comments whose field name matches + * \a entry's field name will be removed, and \a entry will + * be inserted at the position of the first matching + * comment. If \c false, only the first comment whose + * field name matches \a entry's field name will be + * replaced with \a entry. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy); + +/** Delete a comment in a VORBIS_COMMENT block at the given index. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param comment_num The index of the comment to delete. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code object->data.vorbis_comment.num_comments > comment_num \endcode + * \retval FLAC__bool + * \c false if realloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num); + +/** Creates a Vorbis comment entry from NUL-terminated name and value strings. + * + * On return, the filled-in \a entry->entry pointer will point to malloc()ed + * memory and shall be owned by the caller. For convenience the entry will + * have a terminating NUL. + * + * \param entry A pointer to a Vorbis comment entry. The entry's + * \c entry pointer should not point to allocated + * memory as it will be overwritten. + * \param field_name The field name in ASCII, \c NUL terminated. + * \param field_value The field value in UTF-8, \c NUL terminated. + * \assert + * \code entry != NULL \endcode + * \code field_name != NULL \endcode + * \code field_value != NULL \endcode + * \retval FLAC__bool + * \c false if malloc() fails, or if \a field_name or \a field_value does + * not comply with the Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value); + +/** Splits a Vorbis comment entry into NUL-terminated name and value strings. + * + * The returned pointers to name and value will be allocated by malloc() + * and shall be owned by the caller. + * + * \param entry An existing Vorbis comment entry. + * \param field_name The address of where the returned pointer to the + * field name will be stored. + * \param field_value The address of where the returned pointer to the + * field value will be stored. + * \assert + * \code (entry.entry != NULL && entry.length > 0) \endcode + * \code memchr(entry.entry, '=', entry.length) != NULL \endcode + * \code field_name != NULL \endcode + * \code field_value != NULL \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value); + +/** Check if the given Vorbis comment entry's field name matches the given + * field name. + * + * \param entry An existing Vorbis comment entry. + * \param field_name The field name to check. + * \param field_name_length The length of \a field_name, not including the + * terminating \c NUL. + * \assert + * \code (entry.entry != NULL && entry.length > 0) \endcode + * \retval FLAC__bool + * \c true if the field names match, else \c false + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length); + +/** Find a Vorbis comment with the given field name. + * + * The search begins at entry number \a offset; use an offset of 0 to + * search from the beginning of the comment array. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param offset The offset into the comment array from where to start + * the search. + * \param field_name The field name of the comment to find. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code field_name != NULL \endcode + * \retval int + * The offset in the comment array of the first comment whose field + * name matches \a field_name, or \c -1 if no match was found. + */ +FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name); + +/** Remove first Vorbis comment matching the given field name. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param field_name The field name of comment to delete. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \retval int + * \c -1 for memory allocation error, \c 0 for no matching entries, + * \c 1 for one matching entry deleted. + */ +FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name); + +/** Remove all Vorbis comments matching the given field name. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param field_name The field name of comments to delete. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \retval int + * \c -1 for memory allocation error, \c 0 for no matching entries, + * else the number of matching entries deleted. + */ +FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name); + +/** Create a new CUESHEET track instance. + * + * The object will be "empty"; i.e. values and data pointers will be \c 0. + * + * \retval FLAC__StreamMetadata_CueSheet_Track* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void); + +/** Create a copy of an existing CUESHEET track object. + * + * The copy is a "deep" copy, i.e. dynamically allocated data within the + * object is also copied. The caller takes ownership of the new object and + * is responsible for freeing it with + * FLAC__metadata_object_cuesheet_track_delete(). + * + * \param object Pointer to object to copy. + * \assert + * \code object != NULL \endcode + * \retval FLAC__StreamMetadata_CueSheet_Track* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object); + +/** Delete a CUESHEET track object + * + * \param object A pointer to an existing CUESHEET track object. + * \assert + * \code object != NULL \endcode + */ +FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object); + +/** Resize a track's index point array. + * + * If the size shrinks, elements will truncated; if it grows, new blank + * indices will be added to the end. If this function returns false, the + * track object is left untouched. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index of the track to modify. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param new_num_indices The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks > track_num \endcode + * \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) || + * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices); + +/** Insert an index point in a CUESHEET track at the given index. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index of the track to modify. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param index_num The index into the track's index array at which to + * insert the index point. NOTE: this is not necessarily + * the same as the index point's \a number field. The + * indices at and after \a index_num move right one + * position. To append an index point to the end, set + * \a index_num to + * \c object->data.cue_sheet.tracks[track_num].num_indices . + * \param index The index point to insert. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks > track_num \endcode + * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode + * \retval FLAC__bool + * \c false if realloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index); + +/** Insert a blank index point in a CUESHEET track at the given index. + * + * A blank index point is one in which all field values are zero. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index of the track to modify. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param index_num The index into the track's index array at which to + * insert the index point. NOTE: this is not necessarily + * the same as the index point's \a number field. The + * indices at and after \a index_num move right one + * position. To append an index point to the end, set + * \a index_num to + * \c object->data.cue_sheet.tracks[track_num].num_indices . + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks > track_num \endcode + * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode + * \retval FLAC__bool + * \c false if realloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num); + +/** Delete an index point in a CUESHEET track at the given index. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index into the track array of the track to + * modify. NOTE: this is not necessarily the same + * as the track's \a number field. + * \param index_num The index into the track's index array of the index + * to delete. NOTE: this is not necessarily the same + * as the index's \a number field. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks > track_num \endcode + * \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode + * \retval FLAC__bool + * \c false if realloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num); + +/** Resize the track array. + * + * If the size shrinks, elements will truncated; if it grows, new blank + * tracks will be added to the end. If this function returns false, the + * object is left untouched. + * + * \param object A pointer to an existing CUESHEET object. + * \param new_num_tracks The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) || + * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks); + +/** Sets a track in a CUESHEET block. + * + * If \a copy is \c true, a copy of the track is stored; otherwise, the object + * takes ownership of the \a track pointer. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num Index into track array to set. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param track The track to set the track to. You may safely pass in + * a const pointer if \a copy is \c true. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code track_num < object->data.cue_sheet.num_tracks \endcode + * \code (track->indices != NULL && track->num_indices > 0) || + * (track->indices == NULL && track->num_indices == 0) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); + +/** Insert a track in a CUESHEET block at the given index. + * + * If \a copy is \c true, a copy of the track is stored; otherwise, the object + * takes ownership of the \a track pointer. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index at which to insert the track. NOTE: this + * is not necessarily the same as the track's \a number + * field. The tracks at and after \a track_num move right + * one position. To append a track to the end, set + * \a track_num to \c object->data.cue_sheet.num_tracks . + * \param track The track to insert. You may safely pass in a const + * pointer if \a copy is \c true. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks >= track_num \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); + +/** Insert a blank track in a CUESHEET block at the given index. + * + * A blank track is one in which all field values are zero. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index at which to insert the track. NOTE: this + * is not necessarily the same as the track's \a number + * field. The tracks at and after \a track_num move right + * one position. To append a track to the end, set + * \a track_num to \c object->data.cue_sheet.num_tracks . + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks >= track_num \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num); + +/** Delete a track in a CUESHEET block at the given index. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index into the track array of the track to + * delete. NOTE: this is not necessarily the same + * as the track's \a number field. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks > track_num \endcode + * \retval FLAC__bool + * \c false if realloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num); + +/** Check a cue sheet to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * cue sheet. + * + * \param object A pointer to an existing CUESHEET object. + * \param check_cd_da_subset If \c true, check CUESHEET against more + * stringent requirements for a CD-DA (audio) disc. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \retval FLAC__bool + * \c false if cue sheet is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation); + +/** Calculate and return the CDDB/freedb ID for a cue sheet. The function + * assumes the cue sheet corresponds to a CD; the result is undefined + * if the cuesheet's is_cd bit is not set. + * + * \param object A pointer to an existing CUESHEET object. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \retval FLAC__uint32 + * The unsigned integer representation of the CDDB/freedb ID + */ +FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object); + +/** Sets the MIME type of a PICTURE block. + * + * If \a copy is \c true, a copy of the string is stored; otherwise, the object + * takes ownership of the pointer. The existing string will be freed if this + * function is successful, otherwise the original string will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param mime_type A pointer to the MIME type string. The string must be + * ASCII characters 0x20-0x7e, NUL-terminated. No validation + * is done. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (mime_type != NULL) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy); + +/** Sets the description of a PICTURE block. + * + * If \a copy is \c true, a copy of the string is stored; otherwise, the object + * takes ownership of the pointer. The existing string will be freed if this + * function is successful, otherwise the original string will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a description if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param description A pointer to the description string. The string must be + * valid UTF-8, NUL-terminated. No validation is done. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (description != NULL) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy); + +/** Sets the picture data of a PICTURE block. + * + * If \a copy is \c true, a copy of the data is stored; otherwise, the object + * takes ownership of the pointer. Also sets the \a data_length field of the + * metadata object to what is passed in as the \a length parameter. The + * existing data will be freed if this function is successful, otherwise the + * original data and data_length will remain if \a copy is \c true and + * malloc() fails. + * + * \note It is safe to pass a const pointer to \a data if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param data A pointer to the data to set. + * \param length The length of \a data in bytes. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (data != NULL && length > 0) || + * (data == NULL && length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy); + +/** Check a PICTURE block to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * PICTURE block. + * + * \param object A pointer to existing PICTURE block to be checked. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \retval FLAC__bool + * \c false if PICTURE block is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation); + + +/** Get the raw (binary) representation of a FLAC__StreamMetadata objeect. + * After use, free() the returned buffer. The length of the buffer is + * the length of the input metadata object plus 4 bytes for the header. + * + * \param object A pointer to metadata block to be converted. + * \assert + * \code object != NULL \endcode + * \retval FLAC__byte* + * \c NULL if there was an error, else a pointer to a buffer holding + * the requested data. + */ +FLAC_API FLAC__byte * FLAC__metadata_object_get_raw(const FLAC__StreamMetadata *object); + + +/** Turn a raw (binary) representation into a FLAC__StreamMetadata objeect. + * The returned object must be deleted with FLAC__metadata_object_delete() + * after use. + * + * \param buffer A pointer to a buffer containing a binary representation + * to be converted to a FLAC__StreamMetadata object + * \param length The length of the supplied buffer + * \retval FLAC__StreamMetadata* + * \c NULL if there was an error, else a pointer to a FLAC__StreamMetadata + * holding the requested data. + */ + +FLAC_API FLAC__StreamMetadata * FLAC__metadata_object_set_raw(FLAC__byte *buffer, FLAC__uint32 length); +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/FLAC/ordinals.h b/vendor/flac/include/FLAC/ordinals.h new file mode 100644 index 0000000..d61aac5 --- /dev/null +++ b/vendor/flac/include/FLAC/ordinals.h @@ -0,0 +1,55 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__ORDINALS_H +#define FLAC__ORDINALS_H + +/* This of course assumes C99 headers */ + +#include +#include + +typedef int8_t FLAC__int8; +typedef uint8_t FLAC__uint8; + +typedef int16_t FLAC__int16; +typedef int32_t FLAC__int32; +typedef int64_t FLAC__int64; +typedef uint16_t FLAC__uint16; +typedef uint32_t FLAC__uint32; +typedef uint64_t FLAC__uint64; + +typedef int FLAC__bool; + +typedef FLAC__uint8 FLAC__byte; + +#endif diff --git a/vendor/flac/include/FLAC/stream_decoder.h b/vendor/flac/include/FLAC/stream_decoder.h new file mode 100644 index 0000000..2272bca --- /dev/null +++ b/vendor/flac/include/FLAC/stream_decoder.h @@ -0,0 +1,1584 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__STREAM_DECODER_H +#define FLAC__STREAM_DECODER_H + +#include /* for FILE */ +#include "export.h" +#include "format.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \file include/FLAC/stream_decoder.h + * + * \brief + * This module contains the functions which implement the stream + * decoder. + * + * See the detailed documentation in the + * \link flac_stream_decoder stream decoder \endlink module. + */ + +/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces + * \ingroup flac + * + * \brief + * This module describes the decoder layers provided by libFLAC. + * + * The stream decoder can be used to decode complete streams either from + * the client via callbacks, or directly from a file, depending on how + * it is initialized. When decoding via callbacks, the client provides + * callbacks for reading FLAC data and writing decoded samples, and + * handling metadata and errors. If the client also supplies seek-related + * callback, the decoder function for sample-accurate seeking within the + * FLAC input is also available. When decoding from a file, the client + * needs only supply a filename or open \c FILE* and write/metadata/error + * callbacks; the rest of the callbacks are supplied internally. For more + * info see the \link flac_stream_decoder stream decoder \endlink module. + */ + +/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface + * \ingroup flac_decoder + * + * \brief + * This module contains the functions which implement the stream + * decoder. + * + * The stream decoder can decode native FLAC, and optionally Ogg FLAC + * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. + * + * The basic usage of this decoder is as follows: + * - The program creates an instance of a decoder using + * FLAC__stream_decoder_new(). + * - The program overrides the default settings using + * FLAC__stream_decoder_set_*() functions. + * - The program initializes the instance to validate the settings and + * prepare for decoding using + * - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE() + * or FLAC__stream_decoder_init_file() for native FLAC, + * - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE() + * or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC + * - The program calls the FLAC__stream_decoder_process_*() functions + * to decode data, which subsequently calls the callbacks. + * - The program finishes the decoding with FLAC__stream_decoder_finish(), + * which flushes the input and output and resets the decoder to the + * uninitialized state. + * - The instance may be used again or deleted with + * FLAC__stream_decoder_delete(). + * + * In more detail, the program will create a new instance by calling + * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*() + * functions to override the default decoder options, and call + * one of the FLAC__stream_decoder_init_*() functions. + * + * There are three initialization functions for native FLAC, one for + * setting up the decoder to decode FLAC data from the client via + * callbacks, and two for decoding directly from a FLAC file. + * + * For decoding via callbacks, use FLAC__stream_decoder_init_stream(). + * You must also supply several callbacks for handling I/O. Some (like + * seeking) are optional, depending on the capabilities of the input. + * + * For decoding directly from a file, use FLAC__stream_decoder_init_FILE() + * or FLAC__stream_decoder_init_file(). Then you must only supply an open + * \c FILE* or filename and fewer callbacks; the decoder will handle + * the other callbacks internally. + * + * There are three similarly-named init functions for decoding from Ogg + * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the + * library has been built with Ogg support. + * + * Once the decoder is initialized, your program will call one of several + * functions to start the decoding process: + * + * - FLAC__stream_decoder_process_single() - Tells the decoder to process at + * most one metadata block or audio frame and return, calling either the + * metadata callback or write callback, respectively, once. If the decoder + * loses sync it will return with only the error callback being called. + * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder + * to process the stream from the current location and stop upon reaching + * the first audio frame. The client will get one metadata, write, or error + * callback per metadata block, audio frame, or sync error, respectively. + * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder + * to process the stream from the current location until the read callback + * returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or + * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The client will get one metadata, + * write, or error callback per metadata block, audio frame, or sync error, + * respectively. + * + * When the decoder has finished decoding (normally or through an abort), + * the instance is finished by calling FLAC__stream_decoder_finish(), which + * ensures the decoder is in the correct state and frees memory. Then the + * instance may be deleted with FLAC__stream_decoder_delete() or initialized + * again to decode another stream. + * + * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method. + * At any point after the stream decoder has been initialized, the client can + * call this function to seek to an exact sample within the stream. + * Subsequently, the first time the write callback is called it will be + * passed a (possibly partial) block starting at that sample. + * + * If the client cannot seek via the callback interface provided, but still + * has another way of seeking, it can flush the decoder using + * FLAC__stream_decoder_flush() and start feeding data from the new position + * through the read callback. + * + * The stream decoder also provides MD5 signature checking. If this is + * turned on before initialization, FLAC__stream_decoder_finish() will + * report when the decoded MD5 signature does not match the one stored + * in the STREAMINFO block. MD5 checking is automatically turned off + * (until the next FLAC__stream_decoder_reset()) if there is no signature + * in the STREAMINFO block or when a seek is attempted. + * + * The FLAC__stream_decoder_set_metadata_*() functions deserve special + * attention. By default, the decoder only calls the metadata_callback for + * the STREAMINFO block. These functions allow you to tell the decoder + * explicitly which blocks to parse and return via the metadata_callback + * and/or which to skip. Use a FLAC__stream_decoder_set_metadata_respond_all(), + * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(), + * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify + * which blocks to return. Remember that metadata blocks can potentially + * be big (for example, cover art) so filtering out the ones you don't + * use can reduce the memory requirements of the decoder. Also note the + * special forms FLAC__stream_decoder_set_metadata_respond_application(id) + * and FLAC__stream_decoder_set_metadata_ignore_application(id) for + * filtering APPLICATION blocks based on the application ID. + * + * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but + * they still can legally be filtered from the metadata_callback. + * + * \note + * The "set" functions may only be called when the decoder is in the + * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after + * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but + * before FLAC__stream_decoder_init_*(). If this is the case they will + * return \c true, otherwise \c false. + * + * \note + * FLAC__stream_decoder_finish() resets all settings to the constructor + * defaults, including the callbacks. + * + * \{ + */ + + +/** State values for a FLAC__StreamDecoder + * + * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state(). + */ +typedef enum { + + FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0, + /**< The decoder is ready to search for metadata. */ + + FLAC__STREAM_DECODER_READ_METADATA, + /**< The decoder is ready to or is in the process of reading metadata. */ + + FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC, + /**< The decoder is ready to or is in the process of searching for the + * frame sync code. + */ + + FLAC__STREAM_DECODER_READ_FRAME, + /**< The decoder is ready to or is in the process of reading a frame. */ + + FLAC__STREAM_DECODER_END_OF_STREAM, + /**< The decoder has reached the end of the stream. */ + + FLAC__STREAM_DECODER_OGG_ERROR, + /**< An error occurred in the underlying Ogg layer. */ + + FLAC__STREAM_DECODER_SEEK_ERROR, + /**< An error occurred while seeking. The decoder must be flushed + * with FLAC__stream_decoder_flush() or reset with + * FLAC__stream_decoder_reset() before decoding can continue. + */ + + FLAC__STREAM_DECODER_ABORTED, + /**< The decoder was aborted by the read or write callback. */ + + FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR, + /**< An error occurred allocating memory. The decoder is in an invalid + * state and can no longer be used. + */ + + FLAC__STREAM_DECODER_UNINITIALIZED + /**< The decoder is in the uninitialized state; one of the + * FLAC__stream_decoder_init_*() functions must be called before samples + * can be processed. + */ + +} FLAC__StreamDecoderState; + +/** Maps a FLAC__StreamDecoderState to a C string. + * + * Using a FLAC__StreamDecoderState as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderStateString[]; + + +/** Possible return values for the FLAC__stream_decoder_init_*() functions. + */ +typedef enum { + + FLAC__STREAM_DECODER_INIT_STATUS_OK = 0, + /**< Initialization was successful. */ + + FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER, + /**< The library was not compiled with support for the given container + * format. + */ + + FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS, + /**< A required callback was not supplied. */ + + FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR, + /**< An error occurred allocating memory. */ + + FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE, + /**< fopen() failed in FLAC__stream_decoder_init_file() or + * FLAC__stream_decoder_init_ogg_file(). */ + + FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED + /**< FLAC__stream_decoder_init_*() was called when the decoder was + * already initialized, usually because + * FLAC__stream_decoder_finish() was not called. + */ + +} FLAC__StreamDecoderInitStatus; + +/** Maps a FLAC__StreamDecoderInitStatus to a C string. + * + * Using a FLAC__StreamDecoderInitStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[]; + + +/** Return values for the FLAC__StreamDecoder read callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, + /**< The read was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM, + /**< The read was attempted while at the end of the stream. Note that + * the client must only return this value when the read callback was + * called when already at the end of the stream. Otherwise, if the read + * itself moves to the end of the stream, the client should still return + * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on + * the next read callback it should return + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count + * of \c 0. + */ + + FLAC__STREAM_DECODER_READ_STATUS_ABORT + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + +} FLAC__StreamDecoderReadStatus; + +/** Maps a FLAC__StreamDecoderReadStatus to a C string. + * + * Using a FLAC__StreamDecoderReadStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[]; + + +/** Return values for the FLAC__StreamDecoder seek callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_SEEK_STATUS_OK, + /**< The seek was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_SEEK_STATUS_ERROR, + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + + FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED + /**< Client does not support seeking. */ + +} FLAC__StreamDecoderSeekStatus; + +/** Maps a FLAC__StreamDecoderSeekStatus to a C string. + * + * Using a FLAC__StreamDecoderSeekStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[]; + + +/** Return values for the FLAC__StreamDecoder tell callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_TELL_STATUS_OK, + /**< The tell was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_TELL_STATUS_ERROR, + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + + FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED + /**< Client does not support telling the position. */ + +} FLAC__StreamDecoderTellStatus; + +/** Maps a FLAC__StreamDecoderTellStatus to a C string. + * + * Using a FLAC__StreamDecoderTellStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[]; + + +/** Return values for the FLAC__StreamDecoder length callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_LENGTH_STATUS_OK, + /**< The length call was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR, + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + + FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED + /**< Client does not support reporting the length. */ + +} FLAC__StreamDecoderLengthStatus; + +/** Maps a FLAC__StreamDecoderLengthStatus to a C string. + * + * Using a FLAC__StreamDecoderLengthStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[]; + + +/** Return values for the FLAC__StreamDecoder write callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE, + /**< The write was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_WRITE_STATUS_ABORT + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + +} FLAC__StreamDecoderWriteStatus; + +/** Maps a FLAC__StreamDecoderWriteStatus to a C string. + * + * Using a FLAC__StreamDecoderWriteStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[]; + + +/** Possible values passed back to the FLAC__StreamDecoder error callback. + * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch- + * all. The rest could be caused by bad sync (false synchronization on + * data that is not the start of a frame) or corrupted data. The error + * itself is the decoder's best guess at what happened assuming a correct + * sync. For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER + * could be caused by a correct sync on the start of a frame, but some + * data in the frame header was corrupted. Or it could be the result of + * syncing on a point the stream that looked like the starting of a frame + * but was not. \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM + * could be because the decoder encountered a valid frame made by a future + * version of the encoder which it cannot parse, or because of a false + * sync making it appear as though an encountered frame was generated by + * a future encoder. \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA is + * caused by finding data that doesn't fit a metadata block (too large + * or too small) or finding inconsistencies in the metadata, for example + * a PICTURE block with an image that exceeds the size of the metadata + * block. + */ +typedef enum { + + FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, + /**< An error in the stream caused the decoder to lose synchronization. */ + + FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, + /**< The decoder encountered a corrupted frame header. */ + + FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, + /**< The frame's data did not match the CRC in the footer. */ + + FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM, + /**< The decoder encountered reserved fields in use in the stream. */ + + FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA + /**< The decoder encountered a corrupted metadata block. */ + +} FLAC__StreamDecoderErrorStatus; + +/** Maps a FLAC__StreamDecoderErrorStatus to a C string. + * + * Using a FLAC__StreamDecoderErrorStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[]; + + +/*********************************************************************** + * + * class FLAC__StreamDecoder + * + ***********************************************************************/ + +struct FLAC__StreamDecoderProtected; +struct FLAC__StreamDecoderPrivate; +/** The opaque structure definition for the stream decoder type. + * See the \link flac_stream_decoder stream decoder module \endlink + * for a detailed description. + */ +typedef struct { + struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */ + struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */ +} FLAC__StreamDecoder; + +/** Signature for the read callback. + * + * A function pointer matching this signature must be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder needs more input data. The address of the + * buffer to be filled is supplied, along with the number of bytes the + * buffer can hold. The callback may choose to supply less data and + * modify the byte count but must be careful not to overflow the buffer. + * The callback then returns a status code chosen from + * FLAC__StreamDecoderReadStatus. + * + * Here is an example of a read callback for stdio streams: + * \code + * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(*bytes > 0) { + * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); + * if(ferror(file)) + * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + * else if(*bytes == 0) + * return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + * else + * return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + * } + * else + * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param buffer A pointer to a location for the callee to store + * data to be decoded. + * \param bytes A pointer to the size of the buffer. On entry + * to the callback, it contains the maximum number + * of bytes that may be stored in \a buffer. The + * callee must set it to the actual number of bytes + * stored (0 in case of error or end-of-stream) before + * returning. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderReadStatus + * The callee's return status. Note that the callback should return + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if + * zero bytes were read and there is no more data to be read. + */ +typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + +/** Signature for the seek callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder needs to seek the input stream. The decoder + * will pass the absolute byte offset to seek to, 0 meaning the + * beginning of the stream. + * + * Here is an example of a seek callback for stdio streams: + * \code + * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(file == stdin) + * return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; + * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) + * return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + * else + * return FLAC__STREAM_DECODER_SEEK_STATUS_OK; + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param absolute_byte_offset The offset from the beginning of the stream + * to seek to. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderSeekStatus + * The callee's return status. + */ +typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); + +/** Signature for the tell callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder wants to know the current position of the + * stream. The callback should return the byte offset from the + * beginning of the stream. + * + * Here is an example of a tell callback for stdio streams: + * \code + * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * off_t pos; + * if(file == stdin) + * return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; + * else if((pos = ftello(file)) < 0) + * return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + * else { + * *absolute_byte_offset = (FLAC__uint64)pos; + * return FLAC__STREAM_DECODER_TELL_STATUS_OK; + * } + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param absolute_byte_offset A pointer to storage for the current offset + * from the beginning of the stream. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderTellStatus + * The callee's return status. + */ +typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + +/** Signature for the length callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder wants to know the total length of the stream + * in bytes. + * + * Here is an example of a length callback for stdio streams: + * \code + * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * struct stat filestats; + * + * if(file == stdin) + * return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; + * else if(fstat(fileno(file), &filestats) != 0) + * return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + * else { + * *stream_length = (FLAC__uint64)filestats.st_size; + * return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + * } + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param stream_length A pointer to storage for the length of the stream + * in bytes. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderLengthStatus + * The callee's return status. + */ +typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); + +/** Signature for the EOF callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder needs to know if the end of the stream has + * been reached. + * + * Here is an example of a EOF callback for stdio streams: + * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data) + * \code + * { + * FILE *file = ((MyClientData*)client_data)->file; + * return feof(file)? true : false; + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__bool + * \c true if the currently at the end of the stream, else \c false. + */ +typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data); + +/** Signature for the write callback. + * + * A function pointer matching this signature must be passed to one of + * the FLAC__stream_decoder_init_*() functions. + * The supplied function will be called when the decoder has decoded a + * single audio frame. The decoder will pass the frame metadata as well + * as an array of pointers (one for each channel) pointing to the + * decoded audio. + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param frame The description of the decoded frame. See + * FLAC__Frame. + * \param buffer An array of pointers to decoded channels of data. + * Each pointer will point to an array of signed + * samples of length \a frame->header.blocksize. + * Channels will be ordered according to the FLAC + * specification; see the documentation for the + * frame header. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderWriteStatus + * The callee's return status. + */ +typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); + +/** Signature for the metadata callback. + * + * A function pointer matching this signature must be passed to one of + * the FLAC__stream_decoder_init_*() functions. + * The supplied function will be called when the decoder has decoded a + * metadata block. In a valid FLAC file there will always be one + * \c STREAMINFO block, followed by zero or more other metadata blocks. + * These will be supplied by the decoder in the same order as they + * appear in the stream and always before the first audio frame (i.e. + * write callback). The metadata block that is passed in must not be + * modified, and it doesn't live beyond the callback, so you should make + * a copy of it with FLAC__metadata_object_clone() if you will need it + * elsewhere. Since metadata blocks can potentially be large, by + * default the decoder only calls the metadata callback for the + * \c STREAMINFO block; you can instruct the decoder to pass or filter + * other blocks with FLAC__stream_decoder_set_metadata_*() calls. + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param metadata The decoded metadata block. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + */ +typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); + +/** Signature for the error callback. + * + * A function pointer matching this signature must be passed to one of + * the FLAC__stream_decoder_init_*() functions. + * The supplied function will be called whenever an error occurs during + * decoding. + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param status The error encountered by the decoder. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + */ +typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +/** Create a new stream decoder instance. The instance is created with + * default settings; see the individual FLAC__stream_decoder_set_*() + * functions for each setting's default. + * + * \retval FLAC__StreamDecoder* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void); + +/** Free a decoder instance. Deletes the object pointed to by \a decoder. + * + * \param decoder A pointer to an existing decoder. + * \assert + * \code decoder != NULL \endcode + */ +FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder); + + +/*********************************************************************** + * + * Public class method prototypes + * + ***********************************************************************/ + +/** Set the serial number for the FLAC stream within the Ogg container. + * The default behavior is to use the serial number of the first Ogg + * page. Setting a serial number here will explicitly specify which + * stream is to be decoded. + * + * \note + * This does not need to be set for native FLAC decoding. + * + * \default \c use serial number of first page + * \param decoder A decoder instance to set. + * \param serial_number See above. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number); + +/** Set the "MD5 signature checking" flag. If \c true, the decoder will + * compute the MD5 signature of the unencoded audio data while decoding + * and compare it to the signature from the STREAMINFO block, if it + * exists, during FLAC__stream_decoder_finish(). + * + * MD5 signature checking will be turned off (until the next + * FLAC__stream_decoder_reset()) if there is no signature in the + * STREAMINFO block or when a seek is attempted. + * + * Clients that do not use the MD5 check should leave this off to speed + * up decoding. + * + * \default \c false + * \param decoder A decoder instance to set. + * \param value Flag value (see above). + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value); + +/** Direct the decoder to pass on all metadata blocks of type \a type. + * + * \default By default, only the \c STREAMINFO block is returned via the + * metadata callback. + * \param decoder A decoder instance to set. + * \param type See above. + * \assert + * \code decoder != NULL \endcode + * \a type is valid + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); + +/** Direct the decoder to pass on all APPLICATION metadata blocks of the + * given \a id. + * + * \default By default, only the \c STREAMINFO block is returned via the + * metadata callback. + * \param decoder A decoder instance to set. + * \param id See above. + * \assert + * \code decoder != NULL \endcode + * \code id != NULL \endcode + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); + +/** Direct the decoder to pass on all metadata blocks of any type. + * + * \default By default, only the \c STREAMINFO block is returned via the + * metadata callback. + * \param decoder A decoder instance to set. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder); + +/** Direct the decoder to filter out all metadata blocks of type \a type. + * + * \default By default, only the \c STREAMINFO block is returned via the + * metadata callback. + * \param decoder A decoder instance to set. + * \param type See above. + * \assert + * \code decoder != NULL \endcode + * \a type is valid + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); + +/** Direct the decoder to filter out all APPLICATION metadata blocks of + * the given \a id. + * + * \default By default, only the \c STREAMINFO block is returned via the + * metadata callback. + * \param decoder A decoder instance to set. + * \param id See above. + * \assert + * \code decoder != NULL \endcode + * \code id != NULL \endcode + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); + +/** Direct the decoder to filter out all metadata blocks of any type. + * + * \default By default, only the \c STREAMINFO block is returned via the + * metadata callback. + * \param decoder A decoder instance to set. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if the decoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder); + +/** Get the current decoder state. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderState + * The current decoder state. + */ +FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder); + +/** Get the current decoder state as a C string. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval const char * + * The decoder state as a C string. Do not modify the contents. + */ +FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder); + +/** Get the "MD5 signature checking" flag. + * This is the value of the setting, not whether or not the decoder is + * currently checking the MD5 (remember, it can be turned off automatically + * by a seek). When the decoder is reset the flag will be restored to the + * value returned by this function. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * See above. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder); + +/** Get the total number of samples in the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the \c STREAMINFO block. A value of \c 0 means "unknown". + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval uint32_t + * See above. + */ +FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder); + +/** Get the current number of channels in the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the most recently decoded frame header. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval uint32_t + * See above. + */ +FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder); + +/** Get the current channel assignment in the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the most recently decoded frame header. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__ChannelAssignment + * See above. + */ +FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder); + +/** Get the current sample resolution in the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the most recently decoded frame header. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval uint32_t + * See above. + */ +FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder); + +/** Get the current sample rate in Hz of the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the most recently decoded frame header. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval uint32_t + * See above. + */ +FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder); + +/** Get the current blocksize of the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the most recently decoded frame header. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval uint32_t + * See above. + */ +FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder); + +/** Returns the decoder's current read position within the stream. + * The position is the byte offset from the start of the stream. + * Bytes before this position have been fully decoded. Note that + * there may still be undecoded bytes in the decoder's read FIFO. + * The returned position is correct even after a seek. + * + * \warning This function currently only works for native FLAC, + * not Ogg FLAC streams. + * + * \param decoder A decoder instance to query. + * \param position Address at which to return the desired position. + * \assert + * \code decoder != NULL \endcode + * \code position != NULL \endcode + * \retval FLAC__bool + * \c true if successful, \c false if the stream is not native FLAC, + * or there was an error from the 'tell' callback or it returned + * \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position); + +/** Return client_data from decoder. + * The data pointed to by the pointer should not be modified. + * + * \param decoder A decoder instance. + * \retval const void * + * The callee's client data set through FLAC__stream_decoder_init_*(). + * Do not modify the contents. + */ +FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder); + +/** Initialize the decoder instance to decode native FLAC streams. + * + * This flavor of initialization sets up the decoder to decode from a + * native FLAC stream. I/O is performed via callbacks to the client. + * For decoding from a plain file via filename or open FILE*, + * FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE() + * provide a simpler interface. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \param decoder An uninitialized decoder instance. + * \param read_callback See FLAC__StreamDecoderReadCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamDecoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is not \c NULL then a + * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param tell_callback See FLAC__StreamDecoderTellCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param length_callback See FLAC__StreamDecoderLengthCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a length_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param eof_callback See FLAC__StreamDecoderEofCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a eof_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c false + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode Ogg FLAC streams. + * + * This flavor of initialization sets up the decoder to decode from a + * FLAC stream in an Ogg container. I/O is performed via callbacks to the + * client. For decoding from a plain file via filename or open FILE*, + * FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE() + * provide a simpler interface. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \note Support for Ogg FLAC in the library is optional. If this + * library has been built without support for Ogg FLAC, this function + * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. + * + * \param decoder An uninitialized decoder instance. + * \param read_callback See FLAC__StreamDecoderReadCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamDecoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is not \c NULL then a + * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param tell_callback See FLAC__StreamDecoderTellCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param length_callback See FLAC__StreamDecoderLengthCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a length_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param eof_callback See FLAC__StreamDecoderEofCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a eof_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c false + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode native FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a + * plain native FLAC file. For non-stdio streams, you must use + * FLAC__stream_decoder_init_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \param decoder An uninitialized decoder instance. + * \param file An open FLAC file. The file should have been + * opened with mode \c "rb" and rewound. The file + * becomes owned by the decoder and should not be + * manipulated by the client while decoding. + * Unless \a file is \c stdin, it will be closed + * when FLAC__stream_decoder_finish() is called. + * Note however that seeking will not work when + * decoding from \c stdin since it is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode Ogg FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a + * plain Ogg FLAC file. For non-stdio streams, you must use + * FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \note Support for Ogg FLAC in the library is optional. If this + * library has been built without support for Ogg FLAC, this function + * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. + * + * \param decoder An uninitialized decoder instance. + * \param file An open FLAC file. The file should have been + * opened with mode \c "rb" and rewound. The file + * becomes owned by the decoder and should not be + * manipulated by the client while decoding. + * Unless \a file is \c stdin, it will be closed + * when FLAC__stream_decoder_finish() is called. + * Note however that seeking will not work when + * decoding from \c stdin since it is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode native FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a plain + * native FLAC file. If POSIX fopen() semantics are not sufficient, you must + * use FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream() + * and provide callbacks for the I/O. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \param decoder An uninitialized decoder instance. + * \param filename The name of the file to decode from. The file will + * be opened with fopen(). Use \c NULL to decode from + * \c stdin. Note that \c stdin is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode Ogg FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a plain + * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, you must use + * FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream() + * and provide callbacks for the I/O. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \note Support for Ogg FLAC in the library is optional. If this + * library has been built without support for Ogg FLAC, this function + * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. + * + * \param decoder An uninitialized decoder instance. + * \param filename The name of the file to decode from. The file will + * be opened with fopen(). Use \c NULL to decode from + * \c stdin. Note that \c stdin is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Finish the decoding process. + * Flushes the decoding buffer, releases resources, resets the decoder + * settings to their defaults, and returns the decoder state to + * FLAC__STREAM_DECODER_UNINITIALIZED. + * + * In the event of a prematurely-terminated decode, it is not strictly + * necessary to call this immediately before FLAC__stream_decoder_delete() + * but it is good practice to match every FLAC__stream_decoder_init_*() + * with a FLAC__stream_decoder_finish(). + * + * \param decoder An uninitialized decoder instance. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if MD5 checking is on AND a STREAMINFO block was available + * AND the MD5 signature in the STREAMINFO block was non-zero AND the + * signature does not match the one computed by the decoder; else + * \c true. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder); + +/** Flush the stream input. + * The decoder's input buffer will be cleared and the state set to + * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. This will also turn + * off MD5 checking. + * + * \param decoder A decoder instance. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false if a memory allocation + * error occurs (in which case the state will be set to + * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); + +/** Reset the decoding process. + * The decoder's input buffer will be cleared and the state set to + * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. This is similar to + * FLAC__stream_decoder_finish() except that the settings are + * preserved; there is no need to call FLAC__stream_decoder_init_*() + * before decoding again. MD5 checking will be restored to its original + * setting. + * + * If the decoder is seekable, or was initialized with + * FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(), + * the decoder will also attempt to seek to the beginning of the file. + * If this rewind fails, this function will return \c false. It follows + * that FLAC__stream_decoder_reset() cannot be used when decoding from + * \c stdin. + * + * If the decoder was initialized with FLAC__stream_encoder_init*_stream() + * and is not seekable (i.e. no seek callback was provided or the seek + * callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it + * is the duty of the client to start feeding data from the beginning of + * the stream on the next FLAC__stream_decoder_process_*() call. + * + * \param decoder A decoder instance. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false if a memory allocation occurs + * (in which case the state will be set to + * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error + * occurs (the state will be unchanged). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); + +/** Decode one metadata block or audio frame. + * This version instructs the decoder to decode a either a single metadata + * block or a single frame and stop, unless the callbacks return a fatal + * error or the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. + * + * As the decoder needs more input it will call the read callback. + * Depending on what was decoded, the metadata or write callback will be + * called with the decoded metadata block or audio frame. + * + * Unless there is a fatal read error or end of stream, this function + * will return once one whole frame is decoded. In other words, if the + * stream is not synchronized or points to a corrupt frame header, the + * decoder will continue to try and resync until it gets to a valid + * frame, then decode one frame, then return. If the decoder points to + * a frame whose frame CRC in the frame footer does not match the + * computed frame CRC, this function will issue a + * FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the + * error callback, and return, having decoded one complete, although + * corrupt, frame. (Such corrupted frames are sent as silence of the + * correct length to the write callback.) + * + * \param decoder An initialized decoder instance. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder); + +/** Decode until the end of the metadata. + * This version instructs the decoder to decode from the current position + * and continue until all the metadata has been read, or until the + * callbacks return a fatal error or the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. + * + * As the decoder needs more input it will call the read callback. + * As each metadata block is decoded, the metadata callback will be called + * with the decoded metadata. + * + * \param decoder An initialized decoder instance. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder); + +/** Decode until the end of the stream. + * This version instructs the decoder to decode from the current position + * and continue until the end of stream (the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the + * callbacks return a fatal error. + * + * As the decoder needs more input it will call the read callback. + * As each metadata block and frame is decoded, the metadata or write + * callback will be called with the decoded metadata or frame. + * + * \param decoder An initialized decoder instance. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder); + +/** Skip one audio frame. + * This version instructs the decoder to 'skip' a single frame and stop, + * unless the callbacks return a fatal error or the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. + * + * The decoding flow is the same as what occurs when + * FLAC__stream_decoder_process_single() is called to process an audio + * frame, except that this function does not decode the parsed data into + * PCM or call the write callback. The integrity of the frame is still + * checked the same way as in the other process functions. + * + * This function will return once one whole frame is skipped, in the + * same way that FLAC__stream_decoder_process_single() will return once + * one whole frame is decoded. + * + * This function can be used in more quickly determining FLAC frame + * boundaries when decoding of the actual data is not needed, for + * example when an application is separating a FLAC stream into frames + * for editing or storing in a container. To do this, the application + * can use FLAC__stream_decoder_skip_single_frame() to quickly advance + * to the next frame, then use + * FLAC__stream_decoder_get_decode_position() to find the new frame + * boundary. + * + * This function should only be called when the stream has advanced + * past all the metadata, otherwise it will return \c false. + * + * \param decoder An initialized decoder instance not in a metadata + * state. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), or if the decoder + * is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or + * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder); + +/** Flush the input and seek to an absolute sample. + * Decoding will resume at the given sample. Note that because of + * this, the next write callback may contain a partial block. The + * client must support seeking the input or this function will fail + * and return \c false. Furthermore, if the decoder state is + * \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed + * with FLAC__stream_decoder_flush() or reset with + * FLAC__stream_decoder_reset() before decoding can continue. + * + * \param decoder A decoder instance. + * \param sample The target sample number to seek to. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/FLAC/stream_encoder.h b/vendor/flac/include/FLAC/stream_encoder.h new file mode 100644 index 0000000..a0d0263 --- /dev/null +++ b/vendor/flac/include/FLAC/stream_encoder.h @@ -0,0 +1,1837 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__STREAM_ENCODER_H +#define FLAC__STREAM_ENCODER_H + +#include /* for FILE */ +#include "export.h" +#include "format.h" +#include "stream_decoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \file include/FLAC/stream_encoder.h + * + * \brief + * This module contains the functions which implement the stream + * encoder. + * + * See the detailed documentation in the + * \link flac_stream_encoder stream encoder \endlink module. + */ + +/** \defgroup flac_encoder FLAC/ \*_encoder.h: encoder interfaces + * \ingroup flac + * + * \brief + * This module describes the encoder layers provided by libFLAC. + * + * The stream encoder can be used to encode complete streams either to the + * client via callbacks, or directly to a file, depending on how it is + * initialized. When encoding via callbacks, the client provides a write + * callback which will be called whenever FLAC data is ready to be written. + * If the client also supplies a seek callback, the encoder will also + * automatically handle the writing back of metadata discovered while + * encoding, like stream info, seek points offsets, etc. When encoding to + * a file, the client needs only supply a filename or open \c FILE* and an + * optional progress callback for periodic notification of progress; the + * write and seek callbacks are supplied internally. For more info see the + * \link flac_stream_encoder stream encoder \endlink module. + */ + +/** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface + * \ingroup flac_encoder + * + * \brief + * This module contains the functions which implement the stream + * encoder. + * + * The stream encoder can encode to native FLAC, and optionally Ogg FLAC + * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. + * + * The basic usage of this encoder is as follows: + * - The program creates an instance of an encoder using + * FLAC__stream_encoder_new(). + * - The program overrides the default settings using + * FLAC__stream_encoder_set_*() functions. At a minimum, the following + * functions should be called: + * - FLAC__stream_encoder_set_channels() + * - FLAC__stream_encoder_set_bits_per_sample() + * - FLAC__stream_encoder_set_sample_rate() + * - FLAC__stream_encoder_set_ogg_serial_number() (if encoding to Ogg FLAC) + * - FLAC__stream_encoder_set_total_samples_estimate() (if known) + * - If the application wants to control the compression level or set its own + * metadata, then the following should also be called: + * - FLAC__stream_encoder_set_compression_level() + * - FLAC__stream_encoder_set_verify() + * - FLAC__stream_encoder_set_metadata() + * - The rest of the set functions should only be called if the client needs + * exact control over how the audio is compressed; thorough understanding + * of the FLAC format is necessary to achieve good results. + * - The program initializes the instance to validate the settings and + * prepare for encoding using + * - FLAC__stream_encoder_init_stream() or FLAC__stream_encoder_init_FILE() + * or FLAC__stream_encoder_init_file() for native FLAC + * - FLAC__stream_encoder_init_ogg_stream() or FLAC__stream_encoder_init_ogg_FILE() + * or FLAC__stream_encoder_init_ogg_file() for Ogg FLAC + * - The program calls FLAC__stream_encoder_process() or + * FLAC__stream_encoder_process_interleaved() to encode data, which + * subsequently calls the callbacks when there is encoder data ready + * to be written. + * - The program finishes the encoding with FLAC__stream_encoder_finish(), + * which causes the encoder to encode any data still in its input pipe, + * update the metadata with the final encoding statistics if output + * seeking is possible, and finally reset the encoder to the + * uninitialized state. + * - The instance may be used again or deleted with + * FLAC__stream_encoder_delete(). + * + * In more detail, the stream encoder functions similarly to the + * \link flac_stream_decoder stream decoder \endlink, but has fewer + * callbacks and more options. Typically the client will create a new + * instance by calling FLAC__stream_encoder_new(), then set the necessary + * parameters with FLAC__stream_encoder_set_*(), and initialize it by + * calling one of the FLAC__stream_encoder_init_*() functions. + * + * Unlike the decoders, the stream encoder has many options that can + * affect the speed and compression ratio. When setting these parameters + * you should have some basic knowledge of the format (see the + * user-level documentation + * or the formal description). The + * FLAC__stream_encoder_set_*() functions themselves do not validate the + * values as many are interdependent. The FLAC__stream_encoder_init_*() + * functions will do this, so make sure to pay attention to the state + * returned by FLAC__stream_encoder_init_*() to make sure that it is + * FLAC__STREAM_ENCODER_INIT_STATUS_OK. Any parameters that are not set + * before FLAC__stream_encoder_init_*() will take on the defaults from + * the constructor. + * + * There are three initialization functions for native FLAC, one for + * setting up the encoder to encode FLAC data to the client via + * callbacks, and two for encoding directly to a file. + * + * For encoding via callbacks, use FLAC__stream_encoder_init_stream(). + * You must also supply a write callback which will be called anytime + * there is raw encoded data to write. If the client can seek the output + * it is best to also supply seek and tell callbacks, as this allows the + * encoder to go back after encoding is finished to write back + * information that was collected while encoding, like seek point offsets, + * frame sizes, etc. + * + * For encoding directly to a file, use FLAC__stream_encoder_init_FILE() + * or FLAC__stream_encoder_init_file(). Then you must only supply a + * filename or open \c FILE*; the encoder will handle all the callbacks + * internally. You may also supply a progress callback for periodic + * notification of the encoding progress. + * + * There are three similarly-named init functions for encoding to Ogg + * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the + * library has been built with Ogg support. + * + * The call to FLAC__stream_encoder_init_*() currently will also immediately + * call the write callback several times, once with the \c fLaC signature, + * and once for each encoded metadata block. Note that for Ogg FLAC + * encoding you will usually get at least twice the number of callbacks than + * with native FLAC, one for the Ogg page header and one for the page body. + * + * After initializing the instance, the client may feed audio data to the + * encoder in one of two ways: + * + * - Channel separate, through FLAC__stream_encoder_process() - The client + * will pass an array of pointers to buffers, one for each channel, to + * the encoder, each of the same length. The samples need not be + * block-aligned, but each channel should have the same number of samples. + * - Channel interleaved, through + * FLAC__stream_encoder_process_interleaved() - The client will pass a single + * pointer to data that is channel-interleaved (i.e. channel0_sample0, + * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). + * Again, the samples need not be block-aligned but they must be + * sample-aligned, i.e. the first value should be channel0_sample0 and + * the last value channelN_sampleM. + * + * Note that for either process call, each sample in the buffers should be a + * signed integer, right-justified to the resolution set by + * FLAC__stream_encoder_set_bits_per_sample(). For example, if the resolution + * is 16 bits per sample, the samples should all be in the range [-32768,32767]. + * + * When the client is finished encoding data, it calls + * FLAC__stream_encoder_finish(), which causes the encoder to encode any + * data still in its input pipe, and call the metadata callback with the + * final encoding statistics. Then the instance may be deleted with + * FLAC__stream_encoder_delete() or initialized again to encode another + * stream. + * + * For programs that write their own metadata, but that do not know the + * actual metadata until after encoding, it is advantageous to instruct + * the encoder to write a PADDING block of the correct size, so that + * instead of rewriting the whole stream after encoding, the program can + * just overwrite the PADDING block. If only the maximum size of the + * metadata is known, the program can write a slightly larger padding + * block, then split it after encoding. + * + * Make sure you understand how lengths are calculated. All FLAC metadata + * blocks have a 4 byte header which contains the type and length. This + * length does not include the 4 bytes of the header. See the format page + * for the specification of metadata blocks and their lengths. + * + * \note + * If you are writing the FLAC data to a file via callbacks, make sure it + * is open for update (e.g. mode "w+" for stdio streams). This is because + * after the first encoding pass, the encoder will try to seek back to the + * beginning of the stream, to the STREAMINFO block, to write some data + * there. (If using FLAC__stream_encoder_init*_file() or + * FLAC__stream_encoder_init*_FILE(), the file is managed internally.) + * + * \note + * The "set" functions may only be called when the encoder is in the + * state FLAC__STREAM_ENCODER_UNINITIALIZED, i.e. after + * FLAC__stream_encoder_new() or FLAC__stream_encoder_finish(), but + * before FLAC__stream_encoder_init_*(). If this is the case they will + * return \c true, otherwise \c false. + * + * \note + * FLAC__stream_encoder_finish() resets all settings to the constructor + * defaults. + * + * \{ + */ + + +/** State values for a FLAC__StreamEncoder. + * + * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state(). + * + * If the encoder gets into any other state besides \c FLAC__STREAM_ENCODER_OK + * or \c FLAC__STREAM_ENCODER_UNINITIALIZED, it becomes invalid for encoding and + * must be deleted with FLAC__stream_encoder_delete(). + */ +typedef enum { + + FLAC__STREAM_ENCODER_OK = 0, + /**< The encoder is in the normal OK state and samples can be processed. */ + + FLAC__STREAM_ENCODER_UNINITIALIZED, + /**< The encoder is in the uninitialized state; one of the + * FLAC__stream_encoder_init_*() functions must be called before samples + * can be processed. + */ + + FLAC__STREAM_ENCODER_OGG_ERROR, + /**< An error occurred in the underlying Ogg layer. */ + + FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR, + /**< An error occurred in the underlying verify stream decoder; + * check FLAC__stream_encoder_get_verify_decoder_state(). + */ + + FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA, + /**< The verify decoder detected a mismatch between the original + * audio signal and the decoded audio signal. + */ + + FLAC__STREAM_ENCODER_CLIENT_ERROR, + /**< One of the callbacks returned a fatal error. */ + + FLAC__STREAM_ENCODER_IO_ERROR, + /**< An I/O error occurred while opening/reading/writing a file. + * Check \c errno. + */ + + FLAC__STREAM_ENCODER_FRAMING_ERROR, + /**< An error occurred while writing the stream; usually, the + * write_callback returned an error. + */ + + FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR + /**< Memory allocation failed. */ + +} FLAC__StreamEncoderState; + +/** Maps a FLAC__StreamEncoderState to a C string. + * + * Using a FLAC__StreamEncoderState as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderStateString[]; + + +/** Possible return values for the FLAC__stream_encoder_init_*() functions. + */ +typedef enum { + + FLAC__STREAM_ENCODER_INIT_STATUS_OK = 0, + /**< Initialization was successful. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR, + /**< General failure to set up encoder; call FLAC__stream_encoder_get_state() for cause. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER, + /**< The library was not compiled with support for the given container + * format. + */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS, + /**< A required callback was not supplied. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS, + /**< The encoder has an invalid setting for number of channels. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE, + /**< The encoder has an invalid setting for bits-per-sample. + * FLAC supports 4-32 bps. + */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE, + /**< The encoder has an invalid setting for the input sample rate. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE, + /**< The encoder has an invalid setting for the block size. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER, + /**< The encoder has an invalid setting for the maximum LPC order. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION, + /**< The encoder has an invalid setting for the precision of the quantized linear predictor coefficients. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER, + /**< The specified block size is less than the maximum LPC order. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE, + /**< The encoder is bound to the Subset but other settings violate it. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA, + /**< The metadata input to the encoder is invalid, in one of the following ways: + * - FLAC__stream_encoder_set_metadata() was called with a null pointer but a block count > 0 + * - One of the metadata blocks contains an undefined type + * - It contains an illegal CUESHEET as checked by FLAC__format_cuesheet_is_legal() + * - It contains an illegal SEEKTABLE as checked by FLAC__format_seektable_is_legal() + * - It contains more than one SEEKTABLE block or more than one VORBIS_COMMENT block + */ + + FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED + /**< FLAC__stream_encoder_init_*() was called when the encoder was + * already initialized, usually because + * FLAC__stream_encoder_finish() was not called. + */ + +} FLAC__StreamEncoderInitStatus; + +/** Maps a FLAC__StreamEncoderInitStatus to a C string. + * + * Using a FLAC__StreamEncoderInitStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderInitStatusString[]; + + +/** Return values for the FLAC__StreamEncoder read callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE, + /**< The read was OK and decoding can continue. */ + + FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM, + /**< The read was attempted at the end of the stream. */ + + FLAC__STREAM_ENCODER_READ_STATUS_ABORT, + /**< An unrecoverable error occurred. */ + + FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED + /**< Client does not support reading back from the output. */ + +} FLAC__StreamEncoderReadStatus; + +/** Maps a FLAC__StreamEncoderReadStatus to a C string. + * + * Using a FLAC__StreamEncoderReadStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderReadStatusString[]; + + +/** Return values for the FLAC__StreamEncoder write callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_WRITE_STATUS_OK = 0, + /**< The write was OK and encoding can continue. */ + + FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR + /**< An unrecoverable error occurred. The encoder will return from the process call. */ + +} FLAC__StreamEncoderWriteStatus; + +/** Maps a FLAC__StreamEncoderWriteStatus to a C string. + * + * Using a FLAC__StreamEncoderWriteStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[]; + + +/** Return values for the FLAC__StreamEncoder seek callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_SEEK_STATUS_OK, + /**< The seek was OK and encoding can continue. */ + + FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR, + /**< An unrecoverable error occurred. */ + + FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED + /**< Client does not support seeking. */ + +} FLAC__StreamEncoderSeekStatus; + +/** Maps a FLAC__StreamEncoderSeekStatus to a C string. + * + * Using a FLAC__StreamEncoderSeekStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[]; + + +/** Return values for the FLAC__StreamEncoder tell callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_TELL_STATUS_OK, + /**< The tell was OK and encoding can continue. */ + + FLAC__STREAM_ENCODER_TELL_STATUS_ERROR, + /**< An unrecoverable error occurred. */ + + FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED + /**< Client does not support seeking. */ + +} FLAC__StreamEncoderTellStatus; + +/** Maps a FLAC__StreamEncoderTellStatus to a C string. + * + * Using a FLAC__StreamEncoderTellStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderTellStatusString[]; + + +/*********************************************************************** + * + * class FLAC__StreamEncoder + * + ***********************************************************************/ + +struct FLAC__StreamEncoderProtected; +struct FLAC__StreamEncoderPrivate; +/** The opaque structure definition for the stream encoder type. + * See the \link flac_stream_encoder stream encoder module \endlink + * for a detailed description. + */ +typedef struct { + struct FLAC__StreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */ + struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */ +} FLAC__StreamEncoder; + +/** Signature for the read callback. + * + * A function pointer matching this signature must be passed to + * FLAC__stream_encoder_init_ogg_stream() if seeking is supported. + * The supplied function will be called when the encoder needs to read back + * encoded data. This happens during the metadata callback, when the encoder + * has to read, modify, and rewrite the metadata (e.g. seekpoints) gathered + * while encoding. The address of the buffer to be filled is supplied, along + * with the number of bytes the buffer can hold. The callback may choose to + * supply less data and modify the byte count but must be careful not to + * overflow the buffer. The callback then returns a status code chosen from + * FLAC__StreamEncoderReadStatus. + * + * Here is an example of a read callback for stdio streams: + * \code + * FLAC__StreamEncoderReadStatus read_cb(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(*bytes > 0) { + * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); + * if(ferror(file)) + * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + * else if(*bytes == 0) + * return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; + * else + * return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; + * } + * else + * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + * } + * \endcode + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param buffer A pointer to a location for the callee to store + * data to be encoded. + * \param bytes A pointer to the size of the buffer. On entry + * to the callback, it contains the maximum number + * of bytes that may be stored in \a buffer. The + * callee must set it to the actual number of bytes + * stored (0 in case of error or end-of-stream) before + * returning. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_set_client_data(). + * \retval FLAC__StreamEncoderReadStatus + * The callee's return status. + */ +typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + +/** Signature for the write callback. + * + * A function pointer matching this signature must be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * by the encoder anytime there is raw encoded data ready to write. It may + * include metadata mixed with encoded audio frames and the data is not + * guaranteed to be aligned on frame or metadata block boundaries. + * + * The only duty of the callback is to write out the \a bytes worth of data + * in \a buffer to the current position in the output stream. The arguments + * \a samples and \a current_frame are purely informational. If \a samples + * is greater than \c 0, then \a current_frame will hold the current frame + * number that is being written; otherwise it indicates that the write + * callback is being called to write metadata. + * + * \note + * Unlike when writing to native FLAC, when writing to Ogg FLAC the + * write callback will be called twice when writing each audio + * frame; once for the page header, and once for the page body. + * When writing the page header, the \a samples argument to the + * write callback will be \c 0. + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param buffer An array of encoded data of length \a bytes. + * \param bytes The byte length of \a buffer. + * \param samples The number of samples encoded by \a buffer. + * \c 0 has a special meaning; see above. + * \param current_frame The number of the current frame being encoded. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + * \retval FLAC__StreamEncoderWriteStatus + * The callee's return status. + */ +typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); + +/** Signature for the seek callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * when the encoder needs to seek the output stream. The encoder will pass + * the absolute byte offset to seek to, 0 meaning the beginning of the stream. + * + * Here is an example of a seek callback for stdio streams: + * \code + * FLAC__StreamEncoderSeekStatus seek_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(file == stdin) + * return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; + * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) + * return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + * else + * return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; + * } + * \endcode + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param absolute_byte_offset The offset from the beginning of the stream + * to seek to. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + * \retval FLAC__StreamEncoderSeekStatus + * The callee's return status. + */ +typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); + +/** Signature for the tell callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * when the encoder needs to know the current position of the output stream. + * + * \warning + * The callback must return the true current byte offset of the output to + * which the encoder is writing. If you are buffering the output, make + * sure and take this into account. If you are writing directly to a + * FILE* from your write callback, ftell() is sufficient. If you are + * writing directly to a file descriptor from your write callback, you + * can use lseek(fd, SEEK_CUR, 0). The encoder may later seek back to + * these points to rewrite metadata after encoding. + * + * Here is an example of a tell callback for stdio streams: + * \code + * FLAC__StreamEncoderTellStatus tell_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * off_t pos; + * if(file == stdin) + * return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; + * else if((pos = ftello(file)) < 0) + * return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + * else { + * *absolute_byte_offset = (FLAC__uint64)pos; + * return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + * } + * } + * \endcode + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param absolute_byte_offset The address at which to store the current + * position of the output. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + * \retval FLAC__StreamEncoderTellStatus + * The callee's return status. + */ +typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + +/** Signature for the metadata callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * once at the end of encoding with the populated STREAMINFO structure. This + * is so the client can seek back to the beginning of the file and write the + * STREAMINFO block with the correct statistics after encoding (like + * minimum/maximum frame size and total samples). + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param metadata The final populated STREAMINFO block. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + */ +typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); + +/** Signature for the progress callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE(). + * The supplied function will be called when the encoder has finished + * writing a frame. The \c total_frames_estimate argument to the + * callback will be based on the value from + * FLAC__stream_encoder_set_total_samples_estimate(). + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param bytes_written Bytes written so far. + * \param samples_written Samples written so far. + * \param frames_written Frames written so far. + * \param total_frames_estimate The estimate of the total number of + * frames to be written. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + */ +typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data); + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +/** Create a new stream encoder instance. The instance is created with + * default settings; see the individual FLAC__stream_encoder_set_*() + * functions for each setting's default. + * + * \retval FLAC__StreamEncoder* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void); + +/** Free an encoder instance. Deletes the object pointed to by \a encoder. + * + * \param encoder A pointer to an existing encoder. + * \assert + * \code encoder != NULL \endcode + */ +FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder); + + +/*********************************************************************** + * + * Public class method prototypes + * + ***********************************************************************/ + +/** Set the serial number for the FLAC stream to use in the Ogg container. + * + * \note + * This does not need to be set for native FLAC encoding. + * + * \note + * It is recommended to set a serial number explicitly as the default of '0' + * may collide with other streams. + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param serial_number See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long serial_number); + +/** Set the "verify" flag. If \c true, the encoder will verify it's own + * encoded output by feeding it through an internal decoder and comparing + * the original signal against the decoded signal. If a mismatch occurs, + * the process call will return \c false. Note that this will slow the + * encoding process by the extra time required for decoding and comparison. + * + * \default \c false + * \param encoder An encoder instance to set. + * \param value Flag value (see above). + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Set the Subset flag. If \c true, + * the encoder will comply with the Subset and will check the + * settings during FLAC__stream_encoder_init_*() to see if all settings + * comply. If \c false, the settings may take advantage of the full + * range that the format allows. + * + * Make sure you know what it entails before setting this to \c false. + * + * \default \c true + * \param encoder An encoder instance to set. + * \param value Flag value (see above). + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Set the number of channels to be encoded. + * + * \default \c 2 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Set the sample resolution of the input to be encoded. + * + * \warning + * Do not feed the encoder data that is wider than the value you + * set here or you will generate an invalid stream. + * + * \default \c 16 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Set the sample rate (in Hz) of the input to be encoded. + * + * \default \c 44100 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Set the compression level + * + * The compression level is roughly proportional to the amount of effort + * the encoder expends to compress the file. A higher level usually + * means more computation but higher compression. The default level is + * suitable for most applications. + * + * Currently the levels range from \c 0 (fastest, least compression) to + * \c 8 (slowest, most compression). A value larger than \c 8 will be + * treated as \c 8. + * + * This function automatically calls the following other \c _set_ + * functions with appropriate values, so the client does not need to + * unless it specifically wants to override them: + * - FLAC__stream_encoder_set_do_mid_side_stereo() + * - FLAC__stream_encoder_set_loose_mid_side_stereo() + * - FLAC__stream_encoder_set_apodization() + * - FLAC__stream_encoder_set_max_lpc_order() + * - FLAC__stream_encoder_set_qlp_coeff_precision() + * - FLAC__stream_encoder_set_do_qlp_coeff_prec_search() + * - FLAC__stream_encoder_set_do_escape_coding() + * - FLAC__stream_encoder_set_do_exhaustive_model_search() + * - FLAC__stream_encoder_set_min_residual_partition_order() + * - FLAC__stream_encoder_set_max_residual_partition_order() + * - FLAC__stream_encoder_set_rice_parameter_search_dist() + * + * The actual values set for each level are: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
leveldo mid-side stereoloose mid-side stereoapodizationmax lpc orderqlp coeff precisionqlp coeff prec searchescape codingexhaustive model searchmin residual partition ordermax residual partition orderrice parameter search dist
0 false false tukey(0.5) 0 0 false false false 0 3 0
1 true true tukey(0.5) 0 0 false false false 0 3 0
2 true false tukey(0.5) 0 0 false false false 0 3 0
3 false false tukey(0.5) 6 0 false false false 0 4 0
4 true true tukey(0.5) 8 0 false false false 0 4 0
5 true false tukey(0.5) 8 0 false false false 0 5 0
6 true false subdivide_tukey(2) 8 0 false false false 0 6 0
7 true false subdivide_tukey(2) 12 0 false false false 0 6 0
8 true false subdivide_tukey(3) 12 0 false false false 0 6 0
+ * + * \default \c 5 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Set the blocksize to use while encoding. + * + * The number of samples to use per frame. Use \c 0 to let the encoder + * estimate a blocksize; this is usually best. + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Set to \c true to enable mid-side encoding on stereo input. The + * number of channels must be 2 for this to have any effect. Set to + * \c false to use only independent channel coding. + * + * \default \c true + * \param encoder An encoder instance to set. + * \param value Flag value (see above). + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Set to \c true to enable adaptive switching between mid-side and + * left-right encoding on stereo input. Set to \c false to use + * exhaustive searching. Setting this to \c true requires + * FLAC__stream_encoder_set_do_mid_side_stereo() to also be set to + * \c true in order to have any effect. + * + * \default \c false + * \param encoder An encoder instance to set. + * \param value Flag value (see above). + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Sets the apodization function(s) the encoder will use when windowing + * audio data for LPC analysis. + * + * The \a specification is a plain ASCII string which specifies exactly + * which functions to use. There may be more than one (up to 32), + * separated by \c ';' characters. Some functions take one or more + * comma-separated arguments in parentheses. + * + * The available functions are \c bartlett, \c bartlett_hann, + * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop, + * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall, + * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]), + * \c punchout_tukey(n[/ov[/P]]), \c subdivide_tukey(n[/P]), \c welch. + * + * For \c gauss(STDDEV), STDDEV specifies the standard deviation + * (0blocksize / (2 ^ order). + * + * Set both min and max values to \c 0 to force a single context, + * whose Rice parameter is based on the residual signal variance. + * Otherwise, set a min and max order, and the encoder will search + * all orders, using the mean of each context for its Rice parameter, + * and use the best. + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Set the maximum partition order to search when coding the residual. + * This is used in tandem with + * FLAC__stream_encoder_set_min_residual_partition_order(). + * + * The partition order determines the context size in the residual. + * The context size will be approximately blocksize / (2 ^ order). + * + * Set both min and max values to \c 0 to force a single context, + * whose Rice parameter is based on the residual signal variance. + * Otherwise, set a min and max order, and the encoder will search + * all orders, using the mean of each context for its Rice parameter, + * and use the best. + * + * \default \c 5 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Deprecated. Setting this value has no effect. + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value); + +/** Set an estimate of the total samples that will be encoded. + * This is merely an estimate and may be set to \c 0 if unknown. + * This value will be written to the STREAMINFO block before encoding, + * and can remove the need for the caller to rewrite the value later + * if the value is known before encoding. + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value); + +/** Set the metadata blocks to be emitted to the stream before encoding. + * A value of \c NULL, \c 0 implies no metadata; otherwise, supply an + * array of pointers to metadata blocks. The array is non-const since + * the encoder may need to change the \a is_last flag inside them, and + * in some cases update seek point offsets. Otherwise, the encoder will + * not modify or free the blocks. It is up to the caller to free the + * metadata blocks after encoding finishes. + * + * \note + * The encoder stores only copies of the pointers in the \a metadata array; + * the metadata blocks themselves must survive at least until after + * FLAC__stream_encoder_finish() returns. Do not free the blocks until then. + * + * \note + * The STREAMINFO block is always written and no STREAMINFO block may + * occur in the supplied array. + * + * \note + * By default the encoder does not create a SEEKTABLE. If one is supplied + * in the \a metadata array, but the client has specified that it does not + * support seeking, then the SEEKTABLE will be written verbatim. However + * by itself this is not very useful as the client will not know the stream + * offsets for the seekpoints ahead of time. In order to get a proper + * seektable the client must support seeking. See next note. + * + * \note + * SEEKTABLE blocks are handled specially. Since you will not know + * the values for the seek point stream offsets, you should pass in + * a SEEKTABLE 'template', that is, a SEEKTABLE object with the + * required sample numbers (or placeholder points), with \c 0 for the + * \a frame_samples and \a stream_offset fields for each point. If the + * client has specified that it supports seeking by providing a seek + * callback to FLAC__stream_encoder_init_stream() or both seek AND read + * callback to FLAC__stream_encoder_init_ogg_stream() (or by using + * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE()), + * then while it is encoding the encoder will fill the stream offsets in + * for you and when encoding is finished, it will seek back and write the + * real values into the SEEKTABLE block in the stream. There are helper + * routines for manipulating seektable template blocks; see metadata.h: + * FLAC__metadata_object_seektable_template_*(). If the client does + * not support seeking, the SEEKTABLE will have inaccurate offsets which + * will slow down or remove the ability to seek in the FLAC stream. + * + * \note + * The encoder instance \b will modify the first \c SEEKTABLE block + * as it transforms the template to a valid seektable while encoding, + * but it is still up to the caller to free all metadata blocks after + * encoding. + * + * \note + * A VORBIS_COMMENT block may be supplied. The vendor string in it + * will be ignored. libFLAC will use it's own vendor string. libFLAC + * will not modify the passed-in VORBIS_COMMENT's vendor string, it + * will simply write it's own into the stream. If no VORBIS_COMMENT + * block is present in the \a metadata array, libFLAC will write an + * empty one, containing only the vendor string. + * + * \note The Ogg FLAC mapping requires that the VORBIS_COMMENT block be + * the second metadata block of the stream. The encoder already supplies + * the STREAMINFO block automatically. If \a metadata does not contain a + * VORBIS_COMMENT block, the encoder will supply that too. Otherwise, if + * \a metadata does contain a VORBIS_COMMENT block and it is not the + * first, the init function will reorder \a metadata by moving the + * VORBIS_COMMENT block to the front; the relative ordering of the other + * blocks will remain as they were. + * + * \note The Ogg FLAC mapping limits the number of metadata blocks per + * stream to \c 65535. If \a num_blocks exceeds this the function will + * return \c false. + * + * \default \c NULL, 0 + * \param encoder An encoder instance to set. + * \param metadata See above. + * \param num_blocks See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + * \c false if the encoder is already initialized, or if + * \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks); + +/** Set to \c true to make the encoder not output frames which contain + * only constant subframes. This is beneficial for streaming + * applications: very small frames can cause problems with buffering + * as bitrates can drop as low 1kbit/s for CDDA audio encoded within + * subset. The minimum bitrate for a FLAC file encoded with this + * function used is raised to 1bit/sample (i.e. 48kbit/s for 48kHz + * material). + * + * \default \c false + * \param encoder An encoder instance to set. + * \param value Flag value (see above). + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_limit_min_bitrate(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Get the current encoder state. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderState + * The current encoder state. + */ +FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder); + +/** Get the state of the verify stream decoder. + * Useful when the stream encoder state is + * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamDecoderState + * The verify stream decoder state. + */ +FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder); + +/** Get the current encoder state as a C string. + * This version automatically resolves + * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR by getting the + * verify decoder's state. + * + * \param encoder A encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval const char * + * The encoder state as a C string. Do not modify the contents. + */ +FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder); + +/** Get relevant values about the nature of a verify decoder error. + * Useful when the stream encoder state is + * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. The arguments should + * be addresses in which the stats will be returned, or NULL if value + * is not desired. + * + * \param encoder An encoder instance to query. + * \param absolute_sample The absolute sample number of the mismatch. + * \param frame_number The number of the frame in which the mismatch occurred. + * \param channel The channel in which the mismatch occurred. + * \param sample The number of the sample (relative to the frame) in + * which the mismatch occurred. + * \param expected The expected value for the sample in question. + * \param got The actual value returned by the decoder. + * \assert + * \code encoder != NULL \endcode + */ +FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got); + +/** Get the "verify" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_verify(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder); + +/** Get the Subset flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_streamable_subset(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder); + +/** Get the number of input channels being processed. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_channels(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder); + +/** Get the input sample resolution setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_bits_per_sample(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder); + +/** Get the input sample rate setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_sample_rate(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder); + +/** Get the blocksize setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_blocksize(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder); + +/** Get the "mid/side stereo coding" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_get_do_mid_side_stereo(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder); + +/** Get the "adaptive mid/side switching" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_loose_mid_side_stereo(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder); + +/** Get the maximum LPC order setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_max_lpc_order(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder); + +/** Get the quantized linear predictor coefficient precision setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_qlp_coeff_precision(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder); + +/** Get the qlp coefficient precision search flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_do_qlp_coeff_prec_search(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder); + +/** Get the "escape coding" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_do_escape_coding(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder); + +/** Get the exhaustive model search flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_do_exhaustive_model_search(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder); + +/** Get the minimum residual partition order setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_min_residual_partition_order(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder); + +/** Get maximum residual partition order setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_max_residual_partition_order(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder); + +/** Get the Rice parameter search distance setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval uint32_t + * See FLAC__stream_encoder_set_rice_parameter_search_dist(). + */ +FLAC_API uint32_t FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder); + +/** Get the previously set estimate of the total samples to be encoded. + * The encoder merely mimics back the value given to + * FLAC__stream_encoder_set_total_samples_estimate() since it has no + * other way of knowing how many samples the client will encode. + * + * \param encoder An encoder instance to set. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__uint64 + * See FLAC__stream_encoder_get_total_samples_estimate(). + */ +FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder); + +/** Get the "limit_min_bitrate" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_limit_min_bitrate(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_limit_min_bitrate(const FLAC__StreamEncoder *encoder); + +/** Initialize the encoder instance to encode native FLAC streams. + * + * This flavor of initialization sets up the encoder to encode to a + * native FLAC stream. I/O is performed via callbacks to the client. + * For encoding to a plain file via filename or open \c FILE*, + * FLAC__stream_encoder_init_file() and FLAC__stream_encoder_init_FILE() + * provide a simpler interface. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * The call to FLAC__stream_encoder_init_stream() currently will also + * immediately call the write callback several times, once with the \c fLaC + * signature, and once for each encoded metadata block. + * + * \param encoder An uninitialized encoder instance. + * \param write_callback See FLAC__StreamEncoderWriteCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamEncoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. The encoder uses seeking to go back + * and write some some stream statistics to the + * STREAMINFO block; this is recommended but not + * necessary to create a valid FLAC stream. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param tell_callback See FLAC__StreamEncoderTellCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is \c NULL then + * this argument will be ignored. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. If the client provides a seek callback, + * this function is not necessary as the encoder + * will automatically seek back and update the + * STREAMINFO block. It may also be \c NULL if the + * client does not support seeking, since it will + * have no way of going back to update the + * STREAMINFO. However the client can still supply + * a callback if it would like to know the details + * from the STREAMINFO. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data); + +/** Initialize the encoder instance to encode Ogg FLAC streams. + * + * This flavor of initialization sets up the encoder to encode to a FLAC + * stream in an Ogg container. I/O is performed via callbacks to the + * client. For encoding to a plain file via filename or open \c FILE*, + * FLAC__stream_encoder_init_ogg_file() and FLAC__stream_encoder_init_ogg_FILE() + * provide a simpler interface. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * The call to FLAC__stream_encoder_init_ogg_stream() currently will also + * immediately call the write callback several times to write the metadata + * packets. + * + * \param encoder An uninitialized encoder instance. + * \param read_callback See FLAC__StreamEncoderReadCallback. This + * pointer must not be \c NULL if \a seek_callback + * is non-NULL since they are both needed to be + * able to write data back to the Ogg FLAC stream + * in the post-encode phase. + * \param write_callback See FLAC__StreamEncoderWriteCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamEncoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. The encoder uses seeking to go back + * and write some some stream statistics to the + * STREAMINFO block; this is recommended but not + * necessary to create a valid FLAC stream. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param tell_callback See FLAC__StreamEncoderTellCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is \c NULL then + * this argument will be ignored. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. If the client provides a seek callback, + * this function is not necessary as the encoder + * will automatically seek back and update the + * STREAMINFO block. It may also be \c NULL if the + * client does not support seeking, since it will + * have no way of going back to update the + * STREAMINFO. However the client can still supply + * a callback if it would like to know the details + * from the STREAMINFO. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderReadCallback read_callback, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data); + +/** Initialize the encoder instance to encode native FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a + * plain native FLAC file. For non-stdio streams, you must use + * FLAC__stream_encoder_init_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param file An open file. The file should have been opened + * with mode \c "w+b" and rewound. The file + * becomes owned by the encoder and should not be + * manipulated by the client while encoding. + * Unless \a file is \c stdout, it will be closed + * when FLAC__stream_encoder_finish() is called. + * Note however that a proper SEEKTABLE cannot be + * created when encoding to \c stdout since it is + * not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); + +/** Initialize the encoder instance to encode Ogg FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a + * plain Ogg FLAC file. For non-stdio streams, you must use + * FLAC__stream_encoder_init_ogg_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param file An open file. The file should have been opened + * with mode \c "w+b" and rewound. The file + * becomes owned by the encoder and should not be + * manipulated by the client while encoding. + * Unless \a file is \c stdout, it will be closed + * when FLAC__stream_encoder_finish() is called. + * Note however that a proper SEEKTABLE cannot be + * created when encoding to \c stdout since it is + * not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); + +/** Initialize the encoder instance to encode native FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a plain + * FLAC file. If POSIX fopen() semantics are not sufficient you must use + * FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream() + * and provide callbacks for the I/O. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param filename The name of the file to encode to. The file will + * be opened with fopen(). Use \c NULL to encode to + * \c stdout. Note however that a proper SEEKTABLE + * cannot be created when encoding to \c stdout since + * it is not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); + +/** Initialize the encoder instance to encode Ogg FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a plain + * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, you must use + * FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream() + * and provide callbacks for the I/O. + * + * On Windows, filename must be a UTF-8 encoded filename, which libFLAC + * internally translates to an appropriate representation to use with + * _wfopen. On all other systems, filename is passed to fopen without + * any translation. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param filename The name of the file to encode to. The file will + * be opened with fopen(). Use \c NULL to encode to + * \c stdout. Note however that a proper SEEKTABLE + * cannot be created when encoding to \c stdout since + * it is not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); + +/** Finish the encoding process. + * Flushes the encoding buffer, releases resources, resets the encoder + * settings to their defaults, and returns the encoder state to + * FLAC__STREAM_ENCODER_UNINITIALIZED. Note that this can generate + * one or more write callbacks before returning, and will generate + * a metadata callback. + * + * Note that in the course of processing the last frame, errors can + * occur, so the caller should be sure to check the return value to + * ensure the file was encoded properly. + * + * In the event of a prematurely-terminated encode, it is not strictly + * necessary to call this immediately before FLAC__stream_encoder_delete() + * but it is good practice to match every FLAC__stream_encoder_init_*() + * with a FLAC__stream_encoder_finish(). + * + * \param encoder An uninitialized encoder instance. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if an error occurred processing the last frame; or if verify + * mode is set (see FLAC__stream_encoder_set_verify()), there was a + * verify mismatch; else \c true. If \c false, caller should check the + * state with FLAC__stream_encoder_get_state() for more information + * about the error. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder); + +/** Submit data for encoding. + * This version allows you to supply the input data via an array of + * pointers, each pointer pointing to an array of \a samples samples + * representing one channel. The samples need not be block-aligned, + * but each channel should have the same number of samples. Each sample + * should be a signed integer, right-justified to the resolution set by + * FLAC__stream_encoder_set_bits_per_sample(). For example, if the + * resolution is 16 bits per sample, the samples should all be in the + * range [-32768,32767]. + * + * For applications where channel order is important, channels must + * follow the order as described in the + * frame header. + * + * \param encoder An initialized encoder instance in the OK state. + * \param buffer An array of pointers to each channel's signal. + * \param samples The number of samples in one channel. + * \assert + * \code encoder != NULL \endcode + * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode + * \retval FLAC__bool + * \c true if successful, else \c false; in this case, check the + * encoder state with FLAC__stream_encoder_get_state() to see what + * went wrong. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples); + +/** Submit data for encoding. + * This version allows you to supply the input data where the channels + * are interleaved into a single array (i.e. channel0_sample0, + * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). + * The samples need not be block-aligned but they must be + * sample-aligned, i.e. the first value should be channel0_sample0 + * and the last value channelN_sampleM. Each sample should be a signed + * integer, right-justified to the resolution set by + * FLAC__stream_encoder_set_bits_per_sample(). For example, if the + * resolution is 16 bits per sample, the samples should all be in the + * range [-32768,32767]. + * + * For applications where channel order is important, channels must + * follow the order as described in the + * frame header. + * + * \param encoder An initialized encoder instance in the OK state. + * \param buffer An array of channel-interleaved data (see above). + * \param samples The number of samples in one channel, the same as for + * FLAC__stream_encoder_process(). For example, if + * encoding two channels, \c 1000 \a samples corresponds + * to a \a buffer of 2000 values. + * \assert + * \code encoder != NULL \endcode + * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode + * \retval FLAC__bool + * \c true if successful, else \c false; in this case, check the + * encoder state with FLAC__stream_encoder_get_state() to see what + * went wrong. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/Makefile.am b/vendor/flac/include/Makefile.am new file mode 100644 index 0000000..01c5c9b --- /dev/null +++ b/vendor/flac/include/Makefile.am @@ -0,0 +1,23 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2001-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This file is part the FLAC project. FLAC is comprised of several +# components distributed under different licenses. The codec libraries +# are distributed under Xiph.Org's BSD-like license (see the file +# COPYING.Xiph in this distribution). All other programs, libraries, and +# plugins are distributed under the GPL (see COPYING.GPL). The documentation +# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the +# FLAC distribution contains at the top the terms under which it may be +# distributed. +# +# Since this particular file is relevant to all components of FLAC, +# it may be distributed under the Xiph.Org license, which is the least +# restrictive of those mentioned above. See the file COPYING.Xiph in this +# distribution. + +if FLaC__WITH_CPPLIBS +CPPLIBS_DIRS = FLAC++ +endif + +SUBDIRS = FLAC $(CPPLIBS_DIRS) share test_libs_common diff --git a/vendor/flac/include/share/Makefile.am b/vendor/flac/include/share/Makefile.am new file mode 100644 index 0000000..a6a3ca0 --- /dev/null +++ b/vendor/flac/include/share/Makefile.am @@ -0,0 +1,17 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = grabbag + +EXTRA_DIST = \ + alloc.h \ + compat.h \ + endswap.h \ + getopt.h \ + grabbag.h \ + macros.h \ + private.h \ + replaygain_analysis.h \ + replaygain_synthesis.h \ + safe_str.h \ + utf8.h \ + win_utf8_io.h diff --git a/vendor/flac/include/share/alloc.h b/vendor/flac/include/share/alloc.h new file mode 100644 index 0000000..b0da694 --- /dev/null +++ b/vendor/flac/include/share/alloc.h @@ -0,0 +1,318 @@ +/* alloc - Convenience routines for safely allocating memory + * Copyright (C) 2007-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__SHARE__ALLOC_H +#define FLAC__SHARE__ALLOC_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early + * before #including this file, otherwise SIZE_MAX might not be defined + */ + +#include /* for SIZE_MAX */ +#ifdef HAVE_STDINT_H +#include /* for SIZE_MAX in case limits.h didn't get it */ +#endif +#include /* for size_t, malloc(), etc */ +#include "share/compat.h" + +#ifndef SIZE_MAX +# ifndef SIZE_T_MAX +# ifdef _MSC_VER +# ifdef _WIN64 +# define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff) +# else +# define SIZE_T_MAX 0xffffffff +# endif +# else +# error +# endif +# endif +# define SIZE_MAX SIZE_T_MAX +#endif + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +extern int alloc_check_threshold, alloc_check_counter; + +static inline int alloc_check() { + if(alloc_check_threshold == INT32_MAX) + return 0; + else if(alloc_check_counter++ == alloc_check_threshold) + return 1; + else + return 0; +} + +#endif + +/* avoid malloc()ing 0 bytes, see: + * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 +*/ + +static inline void *safe_malloc_(size_t size) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Fail if requested */ + if(alloc_check()) + return NULL; +#endif + /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(!size) + size++; + return malloc(size); +} + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +static inline void *malloc_(size_t size) +{ + /* Fail if requested */ + if(alloc_check()) + return NULL; + return malloc(size); +} +#else +#define malloc_ malloc +#endif + + + +static inline void *safe_calloc_(size_t nmemb, size_t size) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Fail if requested */ + if(alloc_check()) + return NULL; +#endif + if(!nmemb || !size) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + return calloc(nmemb, size); +} + +/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */ + +static inline void *safe_malloc_add_2op_(size_t size1, size_t size2) +{ + size2 += size1; + if(size2 < size1) + return 0; + return safe_malloc_(size2); +} + +static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + return safe_malloc_(size3); +} + +static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + size4 += size3; + if(size4 < size3) + return 0; + return safe_malloc_(size4); +} + +void *safe_malloc_mul_2op_(size_t size1, size_t size2) ; + +static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || !size2 || !size3) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(size1 > SIZE_MAX / size2) + return 0; + size1 *= size2; + if(size1 > SIZE_MAX / size3) + return 0; + return malloc_(size1*size3); +} + +/* size1*size2 + size3 */ +static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || !size2) + return safe_malloc_(size3); + if(size1 > SIZE_MAX / size2) + return 0; + return safe_malloc_add_2op_(size1*size2, size3); +} + +/* size1 * (size2 + size3) */ +static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || (!size2 && !size3)) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + size2 += size3; + if(size2 < size3) + return 0; + if(size1 > SIZE_MAX / size2) + return 0; + return malloc_(size1*size2); +} + +static inline void *safe_realloc_(void *ptr, size_t size) +{ + void *oldptr; + void *newptr; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Fail if requested */ + if(alloc_check() && size > 0) { + free(ptr); + return NULL; + } +#endif + oldptr = ptr; + newptr = realloc(ptr, size); + if(size > 0 && newptr == 0) + free(oldptr); + return newptr; +} + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +static inline void *realloc_(void *ptr, size_t size) +{ + /* Fail if requested */ + if(alloc_check()) + return NULL; + return realloc(ptr, size); +} +#else +#define realloc_ realloc +#endif + + +static inline void *safe_realloc_nofree_add_2op_(void *ptr, size_t size1, size_t size2) +{ + size2 += size1; + if(size2 < size1) + return 0; + return realloc_(ptr, size2); +} + +static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) +{ + size2 += size1; + if(size2 < size1) { + free(ptr); + return 0; + } + size3 += size2; + if(size3 < size2) { + free(ptr); + return 0; + } + return safe_realloc_(ptr, size3); +} + +static inline void *safe_realloc_nofree_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + return realloc_(ptr, size3); +} + +static inline void *safe_realloc_nofree_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + size4 += size3; + if(size4 < size3) + return 0; + return realloc_(ptr, size4); +} + +static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) +{ + if(!size1 || !size2) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + if(size1 > SIZE_MAX / size2) { + free(ptr); + return 0; + } + return safe_realloc_(ptr, size1*size2); +} + +static inline void *safe_realloc_nofree_mul_2op_(void *ptr, size_t size1, size_t size2) +{ + if(!size1 || !size2) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + if(size1 > SIZE_MAX / size2) + return 0; + return realloc_(ptr, size1*size2); +} + +/* size1 * (size2 + size3) */ +static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) +{ + if(!size1 || (!size2 && !size3)) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + size2 += size3; + if(size2 < size3) { + free(ptr); + return 0; + } + return safe_realloc_mul_2op_(ptr, size1, size2); +} + +/* size1 * (size2 + size3) */ +static inline void *safe_realloc_nofree_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) +{ + if(!size1 || (!size2 && !size3)) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + size2 += size3; + if(size2 < size3) + return 0; + return safe_realloc_nofree_mul_2op_(ptr, size1, size2); +} + +#endif diff --git a/vendor/flac/include/share/compat.h b/vendor/flac/include/share/compat.h new file mode 100644 index 0000000..6ce23a5 --- /dev/null +++ b/vendor/flac/include/share/compat.h @@ -0,0 +1,240 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2012-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* This is the preferred location of all CPP hackery to make $random_compiler + * work like something approaching a C99 (or maybe more accurately GNU99) + * compiler. + * + * It is assumed that this header will be included after "config.h". + */ + +#ifndef FLAC__SHARE__COMPAT_H +#define FLAC__SHARE__COMPAT_H + +#include +#include + +#if defined _WIN32 && !defined __CYGWIN__ +/* where MSVC puts unlink() */ +# include +#else +# include +#endif + +#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ +#include /* for off_t */ +#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */ +#define FLAC__OFF_T_MAX INT64_MAX +#if !defined __MINGW32__ +#define fseeko _fseeki64 +#define ftello _ftelli64 +#else /* MinGW */ +#if !defined(HAVE_FSEEKO) +#define fseeko fseeko64 +#define ftello ftello64 +#endif +#endif +#else +#define FLAC__off_t off_t +#define FLAC__OFF_T_MAX OFF_T_MAX +#endif + + + +#ifdef HAVE_INTTYPES_H +#define __STDC_FORMAT_MACROS +#include +#endif + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#define strtoull _strtoui64 +#endif + +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline __inline +#endif + +#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64) +/* MSVS generates VERY slow 32-bit code with __restrict */ +#define flac_restrict __restrict +#elif defined __GNUC__ +#define flac_restrict __restrict__ +#else +#define flac_restrict +#endif + +#define FLAC__U64L(x) x##ULL + +#if defined _MSC_VER || defined __MINGW32__ +#define FLAC__STRCASECMP _stricmp +#define FLAC__STRNCASECMP _strnicmp +#elif defined __BORLANDC__ +#define FLAC__STRCASECMP stricmp +#define FLAC__STRNCASECMP strnicmp +#else +#define FLAC__STRCASECMP strcasecmp +#define FLAC__STRNCASECMP strncasecmp +#endif + +#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ +#include /* for _setmode(), chmod() */ +#include /* for _O_BINARY */ +#else +#include /* for chown(), unlink() */ +#endif + +#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ +#if defined __BORLANDC__ +#include /* for utime() */ +#else +#include /* for utime() */ +#endif +#else +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) +#include +#else +#include /* some flavors of BSD (like OS X) require this to get time_t */ +#include /* for utime() */ +#endif +#endif + +#if defined _MSC_VER +# if _MSC_VER >= 1800 +# include +# elif _MSC_VER >= 1600 +/* Visual Studio 2010 has decent C99 support */ +# include +# define PRIu64 "llu" +# define PRId64 "lld" +# define PRIx64 "llx" +# else +# include +# ifndef UINT32_MAX +# define UINT32_MAX _UI32_MAX +# endif +# define PRIu64 "I64u" +# define PRId64 "I64d" +# define PRIx64 "I64x" +# endif +# if defined(_USING_V110_SDK71_) && !defined(_DLL) +# pragma message("WARNING: This compile will NOT FUNCTION PROPERLY on Windows XP. See comments in include/share/compat.h for details") +#define FLAC__USE_FILELENGTHI64 +/* + ************************************************************************************* + * V110_SDK71, in MSVC 2017 also known as v141_xp, is a platform toolset that is supposed + * to target Windows XP. It turns out however that certain functions provided silently fail + * on Windows XP only, which makes debugging challenging. This only occurs when building with + * /MT. This problem has been reported to Microsoft, but there hasn't been a fix for years. See + * https://web.archive.org/web/20170327195018/https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always + * + * It is known that this problem affects the functions _wstat64 (used by flac_stat i.e. + * stat64_utf8) and _fstat64 (i.e. flac_fstat) and therefore affects both libFLAC in + * several places as well as the flac and metaflac command line tools + * + * As the extent of this problem is unknown and Microsoft seems unwilling to fix it, + * users of libFLAC building with Visual Studio are encouraged to not use the /MT compile + * switch when explicitly targeting Windows XP. When use of /MT is deemed necessary with + * this toolset, be sure to check whether your application works properly on Windows XP. + * It is also possible to build for Windows XP with MinGW instead. + ************************************************************************************* +*/ +# endif +#endif /* defined _MSC_VER */ + +#ifdef _WIN32 +/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */ + +#include "share/win_utf8_io.h" +#define flac_printf printf_utf8 +#define flac_fprintf fprintf_utf8 +#define flac_vfprintf vfprintf_utf8 +#define flac_fopen fopen_utf8 +#define flac_chmod chmod_utf8 +#define flac_utime utime_utf8 +#define flac_unlink unlink_utf8 +#define flac_rename rename_utf8 +#define flac_stat stat64_utf8 + +#else + +#define flac_printf printf +#define flac_fprintf fprintf +#define flac_vfprintf vfprintf + +#define flac_fopen fopen +#define flac_chmod chmod +#define flac_unlink unlink +#define flac_rename rename +#define flac_stat stat + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) +#define flac_utime(a, b) utimensat (AT_FDCWD, a, *b, 0) +#else +#define flac_utime utime +#endif +#endif + +#ifdef _WIN32 +#define flac_stat_s __stat64 /* stat struct */ +#define flac_fstat _fstat64 +#else +#define flac_stat_s stat /* stat struct */ +#define flac_fstat fstat +#endif + +#ifdef ANDROID +#include +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/* FLAC needs to compile and work correctly on systems with a normal ISO C99 + * snprintf as well as Microsoft Visual Studio which has an non-standards + * conformant snprint_s function. + * + * This function wraps the MS version to behave more like the ISO version. + */ +#ifdef __cplusplus +extern "C" { +#endif +int flac_snprintf(char *str, size_t size, const char *fmt, ...); +int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va); +#ifdef __cplusplus +}; +#endif + +#endif /* FLAC__SHARE__COMPAT_H */ diff --git a/vendor/flac/include/share/endswap.h b/vendor/flac/include/share/endswap.h new file mode 100644 index 0000000..8687b9d --- /dev/null +++ b/vendor/flac/include/share/endswap.h @@ -0,0 +1,84 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2012-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* It is assumed that this header will be included after "config.h". */ + +#ifdef HAVE_BSWAP32 /* GCC and Clang */ + +/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */ +#ifndef HAVE_BSWAP16 +static inline unsigned short __builtin_bswap16(unsigned short a) +{ + return (a<<8)|(a>>8); +} +#endif + +#define ENDSWAP_16(x) (__builtin_bswap16 (x)) +#define ENDSWAP_32(x) (__builtin_bswap32 (x)) +#define ENDSWAP_64(x) (__builtin_bswap64 (x)) + +#elif defined _MSC_VER /* Windows */ + +#include + +#define ENDSWAP_16(x) (_byteswap_ushort (x)) +#define ENDSWAP_32(x) (_byteswap_ulong (x)) +#define ENDSWAP_64(x) (_byteswap_uint64 (x)) + +#elif defined HAVE_BYTESWAP_H /* Linux */ + +#include + +#define ENDSWAP_16(x) (bswap_16 (x)) +#define ENDSWAP_32(x) (bswap_32 (x)) +#define ENDSWAP_64(x) (bswap_64 (x)) + +#else + +#define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8)) +#define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24)) +#define ENDSWAP_64(x) ((ENDSWAP_32(((x) >> 32) & 0xFFFFFFFF)) | (ENDSWAP_32((x) & 0xFFFFFFFF) << 32)) + +#endif + + +/* Host to little-endian byte swapping (for MD5 calculation) */ +#if CPU_IS_BIG_ENDIAN + +#define H2LE_16(x) ENDSWAP_16 (x) +#define H2LE_32(x) ENDSWAP_32 (x) + +#else + +#define H2LE_16(x) (x) +#define H2LE_32(x) (x) + +#endif diff --git a/vendor/flac/include/share/getopt.h b/vendor/flac/include/share/getopt.h new file mode 100644 index 0000000..66aced0 --- /dev/null +++ b/vendor/flac/include/share/getopt.h @@ -0,0 +1,184 @@ +/* + NOTE: + I cannot get the vanilla getopt code to work (i.e. compile only what + is needed and not duplicate symbols found in the standard library) + on all the platforms that FLAC supports. In particular the gating + of code with the ELIDE_CODE #define is not accurate enough on systems + that are POSIX but not glibc. If someone has a patch that works on + GNU/Linux, Darwin, AND Solaris please submit it on the project page: + https://sourceforge.net/p/flac/patches/ + + In the meantime I have munged the global symbols and removed gates + around code, while at the same time trying to touch the original as + little as possible. +*/ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifndef SHARE__GETOPT_H +#define SHARE__GETOPT_H + +/*[JEC] was:#ifndef __need_getopt*/ +/*[JEC] was:# define _GETOPT_H 1*/ +/*[JEC] was:#endif*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `share__getopt' to the caller. + When `share__getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *share__optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `share__getopt'. + + On entry to `share__getopt', zero means this is the first call; initialize. + + When `share__getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `share__optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int share__optind; + +/* Callers store zero here to inhibit the error message `share__getopt' prints + for unrecognized options. */ + +extern int share__opterr; + +/* Set to an option character which was unrecognized. */ + +extern int share__optopt; + +/*[JEC] was:#ifndef __need_getopt */ +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to share__getopt_long or share__getopt_long_only is a vector + of `struct share__option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + share__no_argument (or 0) if the option does not take an argument, + share__required_argument (or 1) if the option requires an argument, + share__optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `share__optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `share__getopt' + returns the contents of the `val' field. */ + +struct share__option +{ +# if defined __STDC__ && __STDC__ + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct share__option'. */ + +# define share__no_argument 0 +# define share__required_argument 1 +# define share__optional_argument 2 +/*[JEC] was:#endif*/ /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `share__optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `share__optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `share__getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `share__getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `share__getopt'. */ + +/*[JEC] was:#if defined __STDC__ && __STDC__*/ +/*[JEC] was:# ifdef __GNU_LIBRARY__*/ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int share__getopt (int argc, char *const *argv, const char *shortopts); +/*[JEC] was:# else*/ /* not __GNU_LIBRARY__ */ +/*[JEC] was:extern int getopt ();*/ +/*[JEC] was:# endif*/ /* __GNU_LIBRARY__ */ + +/*[JEC] was:# ifndef __need_getopt*/ +extern int share__getopt_long (int argc, char *const *argv, const char *shortopts, + const struct share__option *longopts, int *longind); +extern int share__getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct share__option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int share___getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct share__option *longopts, int *longind, + int long_only); +/*[JEC] was:# endif*/ +/*[JEC] was:#else*/ /* not __STDC__ */ +/*[JEC] was:extern int getopt ();*/ +/*[JEC] was:# ifndef __need_getopt*/ +/*[JEC] was:extern int getopt_long ();*/ +/*[JEC] was:extern int getopt_long_only ();*/ + +/*[JEC] was:extern int _getopt_internal ();*/ +/*[JEC] was:# endif*/ +/*[JEC] was:#endif*/ /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +/*[JEC] was:#undef __need_getopt*/ + +#endif /* getopt.h */ diff --git a/vendor/flac/include/share/grabbag.h b/vendor/flac/include/share/grabbag.h new file mode 100644 index 0000000..6424fa9 --- /dev/null +++ b/vendor/flac/include/share/grabbag.h @@ -0,0 +1,30 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SHARE__GRABBAG_H +#define SHARE__GRABBAG_H + +/* These can't be included by themselves, only from within grabbag.h */ +#include "grabbag/cuesheet.h" +#include "grabbag/file.h" +#include "grabbag/picture.h" +#include "grabbag/replaygain.h" +#include "grabbag/seektable.h" + +#endif diff --git a/vendor/flac/include/share/grabbag/Makefile.am b/vendor/flac/include/share/grabbag/Makefile.am new file mode 100644 index 0000000..22baa15 --- /dev/null +++ b/vendor/flac/include/share/grabbag/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = \ + cuesheet.h \ + file.h \ + picture.h \ + replaygain.h \ + seektable.h diff --git a/vendor/flac/include/share/grabbag/cuesheet.h b/vendor/flac/include/share/grabbag/cuesheet.h new file mode 100644 index 0000000..d0eb94d --- /dev/null +++ b/vendor/flac/include/share/grabbag/cuesheet.h @@ -0,0 +1,43 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABBAG__CUESHEET_H +#define GRABBAG__CUESHEET_H + +#include +#include "FLAC/metadata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t grabbag__cuesheet_msf_to_frame(uint32_t minutes, uint32_t seconds, uint32_t frames); +void grabbag__cuesheet_frame_to_msf(uint32_t frame, uint32_t *minutes, uint32_t *seconds, uint32_t *frames); + +FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, uint32_t *last_line_read, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset); + +void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/share/grabbag/file.h b/vendor/flac/include/share/grabbag/file.h new file mode 100644 index 0000000..9a2e086 --- /dev/null +++ b/vendor/flac/include/share/grabbag/file.h @@ -0,0 +1,65 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Convenience routines for manipulating files */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABAG__FILE_H +#define GRABAG__FILE_H + +/* needed because of off_t */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include /* for off_t */ +#include /* for FILE */ +#include "FLAC/ordinals.h" +#include "share/compat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void grabbag__file_copy_metadata(const char *srcpath, const char *destpath); +FLAC__off_t grabbag__file_get_filesize(const char *srcpath); +const char *grabbag__file_get_basename(const char *srcpath); + +/* read_only == false means "make file writable by user" + * read_only == true means "make file read-only for everyone" + */ +FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only); + +/* returns true iff stat() succeeds for both files and they have the same device and inode. */ +/* on windows, uses GetFileInformationByHandle() to compare */ +FLAC__bool grabbag__file_are_same(const char *f1, const char *f2); + +/* attempts to make writable before unlinking */ +FLAC__bool grabbag__file_remove_file(const char *filename); + +/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */ +FILE *grabbag__file_get_binary_stdin(void); +FILE *grabbag__file_get_binary_stdout(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/share/grabbag/picture.h b/vendor/flac/include/share/grabbag/picture.h new file mode 100644 index 0000000..6bc4c39 --- /dev/null +++ b/vendor/flac/include/share/grabbag/picture.h @@ -0,0 +1,54 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2006-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABBAG__PICTURE_H +#define GRABBAG__PICTURE_H + +#include "FLAC/metadata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* spec should be of the form "[TYPE]|MIME_TYPE|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE", e.g. + * "|image/jpeg|||cover.jpg" + * "4|image/jpeg||300x300x24|backcover.jpg" + * "|image/png|description|300x300x24/71|cover.png" + * "-->|image/gif||300x300x24/71|http://blah.blah.blah/cover.gif" + * + * empty type means default to FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER + * empty resolution spec means to get from the file (cannot get used with "-->" linked images) + * spec and error_message must not be NULL + */ +FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message); + +typedef struct PictureResolution +{ uint32_t width, height, depth, colors ; +} PictureResolution ; + +FLAC__StreamMetadata *grabbag__picture_from_specification(int type, const char *mime_type, const char * description, + const PictureResolution * res, const char * filepath, const char **error_message); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/share/grabbag/replaygain.h b/vendor/flac/include/share/grabbag/replaygain.h new file mode 100644 index 0000000..90e7a8c --- /dev/null +++ b/vendor/flac/include/share/grabbag/replaygain.h @@ -0,0 +1,73 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This wraps the replaygain_analysis lib, which is LGPL. This wrapper + * allows analysis of different input resolutions by automatically + * scaling the input signal + */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABBAG__REPLAYGAIN_H +#define GRABBAG__REPLAYGAIN_H + +#include "FLAC/metadata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const uint32_t GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED; + +extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */ +extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */ +extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK; /* = "REPLAYGAIN_TRACK_PEAK" */ +extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */ +extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */ + +FLAC__bool grabbag__replaygain_is_valid_sample_frequency(uint32_t sample_frequency); + +FLAC__bool grabbag__replaygain_init(uint32_t sample_frequency); + +/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */ +FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, uint32_t bps, uint32_t samples); + +void grabbag__replaygain_get_album(float *gain, float *peak); +void grabbag__replaygain_get_title(float *gain, float *peak); + +/* These three functions return an error string on error, or NULL if successful */ +const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak); +const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak); +const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block); +const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak); +const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak); +const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime); +const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime); +const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime); +const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime); + +FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak); +double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/share/grabbag/seektable.h b/vendor/flac/include/share/grabbag/seektable.h new file mode 100644 index 0000000..751995b --- /dev/null +++ b/vendor/flac/include/share/grabbag/seektable.h @@ -0,0 +1,39 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Convenience routines for working with seek tables */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABAG__SEEKTABLE_H +#define GRABAG__SEEKTABLE_H + +#include "FLAC/format.h" + +#ifdef __cplusplus +extern "C" { +#endif + +FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, uint32_t sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/flac/include/share/macros.h b/vendor/flac/include/share/macros.h new file mode 100644 index 0000000..3e7ee55 --- /dev/null +++ b/vendor/flac/include/share/macros.h @@ -0,0 +1,45 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2013-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* FLAC_CHECK_RETURN : Check the return value of the provided function and + * print an error message if it fails (ie returns a value < 0). + * + * Ideally, a library should not print anything, but this macro is only used + * for things that extremely unlikely to fail, like `chown` to a previoulsy + * saved `uid`. + */ + +#define FLAC_CHECK_RETURN(x) \ + { if ((x) < 0) \ + fprintf (stderr, "%s : %s\n", #x, strerror (errno)) ; \ + } diff --git a/vendor/flac/include/share/private.h b/vendor/flac/include/share/private.h new file mode 100644 index 0000000..5340d40 --- /dev/null +++ b/vendor/flac/include/share/private.h @@ -0,0 +1,54 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2013-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__SHARE__PRIVATE_H +#define FLAC__SHARE__PRIVATE_H + +/* + * Unpublished debug routines from libFLAC. This should not be used from any + * client code other than code shipped with the FLAC sources. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_disable_instruction_set(FLAC__StreamEncoder *encoder, int value); +FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); +FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); +FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); +/* + * The following two routines were intended as debug routines and are not + * in the public headers, but SHOULD NOT CHANGE! It is known they are used + * in some non-audio projects needing every last bit of performance. + * See https://github.com/xiph/flac/issues/547 for details. These projects + * provide their own prototypes, so changing the signature of these + * functions would break building. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value); +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder); + +#endif /* FLAC__SHARE__PRIVATE_H */ diff --git a/vendor/flac/include/share/replaygain_analysis.h b/vendor/flac/include/share/replaygain_analysis.h new file mode 100644 index 0000000..f06a9b2 --- /dev/null +++ b/vendor/flac/include/share/replaygain_analysis.h @@ -0,0 +1,59 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * minor cosmetic tweaks to integrate with FLAC by Josh Coalson + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +#ifndef GAIN_ANALYSIS_H +#define GAIN_ANALYSIS_H + +#include + +#define GAIN_NOT_ENOUGH_SAMPLES -24601 +#define GAIN_ANALYSIS_ERROR 0 +#define GAIN_ANALYSIS_OK 1 + +#define INIT_GAIN_ANALYSIS_ERROR 0 +#define INIT_GAIN_ANALYSIS_OK 1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef float flac_float_t; /* Type used for filtering */ + +extern flac_float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */ + +int InitGainAnalysis ( long samplefreq ); +int ValidGainFrequency ( long samplefreq ); +int AnalyzeSamples ( const flac_float_t* left_samples, const flac_float_t* right_samples, size_t num_samples, int num_channels ); +flac_float_t GetTitleGain ( void ); +flac_float_t GetAlbumGain ( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* GAIN_ANALYSIS_H */ diff --git a/vendor/flac/include/share/replaygain_synthesis.h b/vendor/flac/include/share/replaygain_synthesis.h new file mode 100644 index 0000000..1701995 --- /dev/null +++ b/vendor/flac/include/share/replaygain_synthesis.h @@ -0,0 +1,52 @@ +/* replaygain_synthesis - Routines for applying ReplayGain to a signal + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H +#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H + +#include /* for size_t */ +#include "FLAC/format.h" + +#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS FLAC__MAX_CHANNELS + +typedef enum { + NOISE_SHAPING_NONE = 0, + NOISE_SHAPING_LOW = 1, + NOISE_SHAPING_MEDIUM = 2, + NOISE_SHAPING_HIGH = 3 +} NoiseShaping; + +typedef struct { + const float* FilterCoeff; + FLAC__uint64 Mask; + double Add; + float Dither; + float ErrorHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; /* 16th order Noise shaping */ + float DitherHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; + int LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS]; + unsigned LastHistoryIndex; + NoiseShaping ShapingType; +} DitherContext; + +void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype); + +/* scale = (float) pow(10., (double)replaygain * 0.05); */ +size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, const uint32_t source_bps, const uint32_t target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context); + +#endif diff --git a/vendor/flac/include/share/safe_str.h b/vendor/flac/include/share/safe_str.h new file mode 100644 index 0000000..85ecbda --- /dev/null +++ b/vendor/flac/include/share/safe_str.h @@ -0,0 +1,71 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2013-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Safe string handling functions to replace things like strcpy, strncpy, + * strcat, strncat etc. + * All of these functions guarantee a correctly NUL terminated string but + * the string may be truncated if the destination buffer was too short. + */ + +#ifndef FLAC__SHARE_SAFE_STR_H +#define FLAC__SHARE_SAFE_STR_H + +static inline char * +safe_strncat(char *dest, const char *src, size_t dest_size) +{ + char * ret; + + if (dest_size < 1) + return dest; + + /* Assume dist has space for a term character .. */ + ret = strncat(dest, src, dest_size - strlen (dest)); + /* .. but set it explicitly. */ + dest [dest_size - 1] = 0; + + return ret; +} + +static inline char * +safe_strncpy(char *dest, const char *src, size_t dest_size) +{ + char * ret; + + if (dest_size < 1) + return dest; + + ret = strncpy(dest, src, dest_size - 1); + dest [dest_size - 1] = 0; + + return ret; +} + +#endif /* FLAC__SHARE_SAFE_STR_H */ diff --git a/vendor/flac/include/share/utf8.h b/vendor/flac/include/share/utf8.h new file mode 100644 index 0000000..7d6650d --- /dev/null +++ b/vendor/flac/include/share/utf8.h @@ -0,0 +1,25 @@ +#ifndef SHARE__UTF8_H +#define SHARE__UTF8_H + +/* + * Convert a string between UTF-8 and the locale's charset. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * + * If the locale's charset is not set explicitly then it is + * obtained using nl_langinfo(CODESET), where available, the + * environment variable CHARSET, or assumed to be US-ASCII. + * + * Return value of conversion functions: + * + * -1 : memory allocation failed + * 0 : data was converted exactly + * 1 : valid data was converted approximately (using '?') + * 2 : input was invalid (but still converted, using '#') + * 3 : unknown encoding (but still converted, using '?') + */ + +int utf8_encode(const char *from, char **to); +int utf8_decode(const char *from, char **to); + +#endif diff --git a/vendor/flac/include/share/win_utf8_io.h b/vendor/flac/include/share/win_utf8_io.h new file mode 100644 index 0000000..ed07386 --- /dev/null +++ b/vendor/flac/include/share/win_utf8_io.h @@ -0,0 +1,71 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2013-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _WIN32 + +#ifndef flac__win_utf8_io_h +#define flac__win_utf8_io_h + +#include +#include +#include +#include +#include "FLAC/ordinals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +size_t strlen_utf8(const char *str); +int win_get_console_width(void); + +int get_utf8_argv(int *argc, char ***argv); + +int printf_utf8(const char *format, ...); +int fprintf_utf8(FILE *stream, const char *format, ...); +int vfprintf_utf8(FILE *stream, const char *format, va_list argptr); + +FILE* fopen_utf8(const char *filename, const char *mode); +int stat64_utf8(const char *path, struct __stat64 *buffer); +int chmod_utf8(const char *filename, int pmode); +int utime_utf8(const char *filename, struct utimbuf *times); +int unlink_utf8(const char *filename); +int rename_utf8(const char *oldname, const char *newname); + +#include +HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif +#endif diff --git a/vendor/flac/include/test_libs_common/Makefile.am b/vendor/flac/include/test_libs_common/Makefile.am new file mode 100644 index 0000000..af82b4d --- /dev/null +++ b/vendor/flac/include/test_libs_common/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = \ + file_utils_flac.h \ + metadata_utils.h diff --git a/vendor/flac/include/test_libs_common/file_utils_flac.h b/vendor/flac/include/test_libs_common/file_utils_flac.h new file mode 100644 index 0000000..5c59c98 --- /dev/null +++ b/vendor/flac/include/test_libs_common/file_utils_flac.h @@ -0,0 +1,36 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_FILE_UTILS_H +#define FLAC__TEST_LIBFLAC_FILE_UTILS_H + +/* needed because of off_t */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/format.h" +#include /* for off_t */ +#include "share/compat.h" + +extern const long file_utils__ogg_serial_number; + +FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, FLAC__off_t *output_filesize, uint32_t length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, uint32_t num_metadata); + +#endif diff --git a/vendor/flac/include/test_libs_common/metadata_utils.h b/vendor/flac/include/test_libs_common/metadata_utils.h new file mode 100644 index 0000000..1ed923a --- /dev/null +++ b/vendor/flac/include/test_libs_common/metadata_utils.h @@ -0,0 +1,71 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBS_COMMON_METADATA_UTILS_H +#define FLAC__TEST_LIBS_COMMON_METADATA_UTILS_H + +/* + * These are not tests, just utility functions used by the metadata tests + */ + +#include "FLAC/format.h" + +FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy); + +FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, uint32_t block_length); + +FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, uint32_t block_length); + +FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy); + +FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy); + +FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy); + +FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy); + +FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, uint32_t block_length); + +FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy); + +void mutils__init_metadata_blocks( + FLAC__StreamMetadata *streaminfo, + FLAC__StreamMetadata *padding, + FLAC__StreamMetadata *seektable, + FLAC__StreamMetadata *application1, + FLAC__StreamMetadata *application2, + FLAC__StreamMetadata *vorbiscomment, + FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, + FLAC__StreamMetadata *unknown +); + +void mutils__free_metadata_blocks( + FLAC__StreamMetadata *streaminfo, + FLAC__StreamMetadata *padding, + FLAC__StreamMetadata *seektable, + FLAC__StreamMetadata *application1, + FLAC__StreamMetadata *application2, + FLAC__StreamMetadata *vorbiscomment, + FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, + FLAC__StreamMetadata *unknown +); + +#endif diff --git a/vendor/flac/lib/flac.idb b/vendor/flac/lib/flac.idb new file mode 100644 index 0000000000000000000000000000000000000000..03dd3f460f3fd69b588e10e71b424fa188b9c02f GIT binary patch literal 617472 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
y50+?MmOlgOn+07wPqn z&~kTuvozmH99Z8GoC zav^z=p7IDChyRfZqAU*doXPUvjsGk4|5;y9Hgomd?pLfN9_v0o^8)+wwCy+^z&yu3 zJ;wrM9Dv_b_`dA#b1Y!0-Qj0yy&tB9y2TA#;bQgr(nK!&0$LAD?Y z@3~!7?5GpoQwvo*wMx$e*t;OsQOJIviPs(7>p*fo9%!iasbsq( z)aJ=-D^^LjB?H#!QS|@WMhEEw47UAGdHJfUUA^Z)S9Du7M6o}Hje4P{-3vcEqRhv0 zJ?#+`AV|)60rTIipibIcZL+i@8NoJKPB13)We5Ipk=GniApdLuK z=CEB!1kS=Of6;-+==fzTmWSSWyk{xl5 z%l708No4Wra!C-a*g+R=86H60;q_l)(RJLp@hP?m{6Jr)Glo6>!ZyTE3S zSpHk^LP#98x8dhw*A!s$ZL|gvY`Dm@$fFQ?p;t?20K8l$Jo|*c{a1+r1sgM!T=IdI zicCa>+@&?TZF%dsXrSHQtE|kC6mc(~FDyf?p2$a*Rok=ev|0kBNFVY4FqZ#;`^&z{ z+q2nJ%3B(X_e9m4E<*(rS-M6QY1C^NkPdxVj;)NXG^6MTrCTB!v_W@ba7Cx`7__P{ z!xjxIE8Er77+T)=FqZ!+yNrokveV1ieX9ecMtG)adlju#cu(#Bp|sEQ=qSb#*_MQt zUtY+zgLby$GqL4fOQ#1zKi6U%%VBgNMfcaXjpRUOYe%7NR%`gfC#tZtcEzI^>+lUO zylgg=UCP!VKt|}Jv8-I;ZO<*A4Sm#*%0c8?sFtw11vX__{!hgB{7T>dIo+c7`~N$^ zzyEW6z(8{V>Wl6v(b+vN9rnPsGw*8UKkp^n_QJLDUn~C&P1EYJr-5Iym(Ty@cX|4W zVx2GvxDH@oJyAaY*T3Tba=sC#SaWVrZU2w@DWYUM0_nBJ(^)jPVYfQAbtvR8*C}kt zb}+BD|Hps-{vYM#pL2vcPxQZ`{MY<{7Y(eM|L=wd4jQLBGRZdX4(V#5S-jVp|yqRMpbqOMYx*N}^-ZBft|95%$=UhAbAqrCdE3N)SCP6DxQv#riqqf%oE9_UYjpM*n^Lf6al- zUa9|&rFwP^2<>`VAtAm$2Aa6$`rrA)@i7O zt^_|%c?}mmoGnxxkNG(OR*A;v?GWmK#@M8*8i{d z|NHuUIaKA}i=|t!7z(4}xsok8*Qx@5!PJLbEE8#%GU%;7`;l3`>nHt@mj~KN^m{@d zC=w>1)j1z6Cigp`FFyvZ8)x8JNC~*j2KpKq)9CvN;~!j?-`}pE^le@#l<)dUUoU;_ z`pNa?41?YEllz~PhYxDk&nvNJRDxKI+*2jUuAki3fZwfii$#L(V}-tg>63(eP|%Mb z{rk{&9R2s|5Omj1`fQLOyMA)t&1Vkx{n+ywtw#D7(?P68?(M}u|2oz0`sv@xe*93C zf3X_rBdC(q$Z<#sm8?ek3a8cB2svDHv^G{FeONGPtC9QbFqB)3>;p+yTdR@lr5LKU z8qY%d^%W{vjr7kz9}Kh_>9auxZ8g$&bYE5@{d)OUqwibrT$cwahd#9EJBopR=D4rR zgLU@Q{@jV{+($tIef~4h$N2)#2GoP}pT^KR*{A%a@6w6QJc9pg)gz?8H~M(}6RdT9 zuj0NT^qIl+;tcfN%RM9+&O#l`eL5s?-vx$eoih&lm1Us+o>x((=^y>^aY%Dm&h)iK zf0@rAlJu=cU-}H(b3+36n&G}imBMPsy$JEV3%!fi@xI&(iu*?%gx(DI>v?OD@ALEq zqzQcvaSXmZ(9cqNxbfiPKc9ha#zOXQVc}ne_&&5gdR0n~MNa>SK0@d-rJDZ#4o(RD zcd%#AUf^r^lY1_5-#+e(7{U{_%Ll1^~OVN)S{cUl-Vfy)d8fBM0 zs_46u{<0gC4t7FAIM7(59m8*nX9{7D$5_GXSPIMY0}LPyejuj&`xDkJ`5r|AJarJ` zOUu1n#!G$hlOppGy%xtO-E{ltX8GxDC_%+&L9fX%7jRbjLt2@W~SUhZ=<}CWv z=ja-t<4|c2HTEwE@}4^5%<~>T>hWPe66HJb5+(MV2=ZRB%->JxM^8!a_L+s3HV`qA zf4e-X{fg24b6rjAhjXaPKZ=44?1Kzqt=Aguk+(~#}C~_M6inCl2=x%ZBB7ab9~98D%HuPYa?NC7M3^_u;@iRE=^u@3A? z9YiiiwFxcv(7iQhvAl8Qnb2}imP*OpvZc~ORjs{FGrBynI{IJQE5U|UD%bkl7i+ev8)IhH_Jxvsq3 zSteKNNshG;TCQ#j*-lDz%zhN1^*h$}Uq#E37D4uHkT`IxhtToes;uo6-XME^NF3PS z68hbAd(5`lJ`<5Yta1z4ZyE(gynVR;%U_nB)iCE zpOw&Y_`+Q}21Q=>?+INt^`6HZuMwTmmLNt_l*iY< zk<0M}Li3Iv}s1N&2jb#M_DAM~`5+pB@P4 zvQD?cPfdJXion^VjyW^rP?mo$U-SRlR;cSt<~w4kx_qGn&f8iV>Z|-vUGx8&U3(>d zr2YR6Rr`NjG%ZTa|8Et`T+n#c{QqJ#tX{DBQS<*hRONq-)s@ad_RYaKR&hjN$ihgD z%#}>d|F14dE;VcZf4SHm-PVtc|6k6-3F7}l*ShSN;Cpuzeojg}B-i}^THg=;_u!iU z-x60C{6zjy^#40l?Z2xR{bf#3jRDpC|7z2==Kpusz?&|7Wc>dQRrz0=vF@7xU-;&m zrp;|M={5hq)$I)7dMF=t|Gz_3{;}LUvowOQGwGI^|KDl#=uY__Jj-hdP6Vy_|Mh*~ zq0+4R{~fCGue>eQ{C_6nxokd!FIoN1udm+Alx-tx{(lGDq75rgYyN+W`~LUaA*D$r%a6aSc)sJ+`^mUeR&I#oD zcD)xk{Q_}~fq01FI#aH1<(ff$7vLIHdQstCzMNytxtyHCJBXQpuJ=~+|E1kIv!$;2 z|0?;MZ}(fO`Ty$M?ded?|I1BHX1Fs)uXp;j84zsG<(Ea^1~8co{9z)zwZGx-M&;^C zH}`mrUEtdDQ_H;@RWm2sN$-l}>#gmfhwf&N9e;YBie&f+wq!EX#+(zjrJ8Pm(9d;v zxt0}}F720}ccKEyOr0FFsmBsdwxnSz5 zru-u%iX*NNAHigP+ePE<*5Q{ZSWFqO&{e)NK7<7sFgj8Vk*GTx3u$ct%l`t{@s-y9 zaLo{w>RDSKro9cc<7xNPZm0cD8=tm3ZF~8j{Q&6$(B5aCzH=BA44_%zqTu1BJq!dwhRpd<{n36%tClDSLor{D_+>&1j;?5 zhUvcF)lV2@i>9Twu3QI-aEQ9^j<-k9Ek!QE#w8(Wi0ywjTJ=ip|HimB0kG?TyMyol zN86w;8-Vr##{#+LKP3)0tW{B5<4wP9gkA?dew1S>Ag2uLsxuEojTZ1)B})H5o%_xxZ<57afszqc2K=yk~V? zX5X!Q+frU}-}CT9V+bo(eDK(lBEQI`A3j3!F66+p3c^cYbcE(Td!}NwHK(ggEISyz~!BSYDTR;$``ayhBy~CC(CG`obk_e4U?!)4wWQK1DINf!^o|%j?o& zzeVn%BO-U&Lf?D5F2@h;SmdRzPb8HM57zlUE4AE{w|5sE5xM++L1?)@Lw=S(|F>JY z6Z(53tX!AZzk9oI`c&l7Pc312UAmpOQ7NyKdHT8_bUD_(Fj&_LFa1FfnpgXapf3q| z4E-|_S`TwBD2;=}m%b_qt%vPY9Yr6mQs(I+lhE(Bmpv)U-ohQ;j(UU8ak%pxwnD`q zao}zRgyy}X%y)N-uCCdYRi1~;G#?(iO#r_1!3j7Jel6Llvm^qM<184ye{1i zsw?Fcx%8b$Xr1l;dXblYQt?YJB4FAzgH{uj>B ze@Uk-sGrU%N4M}{qCKPmm(s87>3A}l@u3uao-Z>4*}2uI!5QY(WvIU~O)FP!#6!1k zb%MgVMl{=-CQ^Ym)~QB8=sD(lGVx^*Bq&vamD&lfE#yS)VEM=A`HJ>G%#GfCeP6N_ zmfsg({l#%VvGLi~aGa0hfBa9z0|V~1SeyS>oBx+9w06Zg>JoMyXSvK5ymTQt&%o)H z5ApoJ?taQYx+anI{~^};h^L=;ZLf6sXS{5K*f!jEfv~*J7W-F)@dNr}C$!ux`sn-c z0Z%$uUT3#$Z%^#w?T^^6^ubQp%g&Df9_SyQ(7a#yecy554s3+x9U+38cscD_4>mNQ->s7GTJDiS=)T0~_btYk^TDKB zdhsk{2+D1{?;>k&Z?#F0mq%h3(}zEy<4~zDOkeSY<#qYtldAtkx$Kv-Uve=kw}FG?5vvad_%bQ`MvzmD&-(%EsUkoa=mAc5rQ_22l;PL2tL z`|U_Expf17-xMp?mCf$arAiZ>aeo{_%RNl_*XF(}lL0koM4+_Hay1a8D>Ng!EzO<_d9p6Tk*SR;1jUR62UJHbly9dT5br89??aCeC z9Iw;aXGD;@L3p{h2chHeS^E&5k^2bYu{LneAcB`4c*gfvec-6lw2(CBJ|Kh@@yP3R&rV&k4d%G<88~L$OCP?>6Wq;_yDf76Ebeu}Jwy23 z^j}PW-SZ%iV;B?h4DSC!`+&Pma$gwke966&=wqF6$6qCJ$7xA`*xt|=e}DUoySdBZ zeKe}g|0|imi+*oy{-3yQ!RSKR^Z&Y$^L4qFg3xZxJ2@)*{~-CmV6vq;b3h?^BV>om>ga>)P8>I{W739%2M}KQ_v@SzoGPQ*l>U zLd)G~T;FoJ7agJFn@3%!gT$BnViA_t>EUM;`Y_yOme6vyEQ_zm<=$3==DmKduKkK_ z(l=0{6PDNM?6H@0Y>T|-j53C>ysjNzJg;wF?xssoZ7SMZwk^i(+>?>ewoijJu(-~>;UsCUn~#0W03C<= zvNV=BaPL4u^L}eg-|^)hkOX-X!~A~9xLx|@<^FAimV0QKjUsUvD*K-?mvp1;NLYQl zw9vLC?M_K@?lMl;cXN5tL%Xko$mOoggyubL~7Yr-R(eedq`+cMIv@xEmzfy|xwhqXBe$N1U#u7URo(D+$f( zeYJ1i6ZSEN&~cb4oq2bQ#P`}AkbeO!_kP4l2jQhnMv(WOwhQezz$vKTbP!(dAxBub zPG`5E&eB16xz`+_<8bCE%~{j~_XH#~@1Ygacz-;A&~cb^Tj|S59Jp5^q2*q?SKo2q z99d!nFT1>czpAUb$Kq!0)>TcA3sA1~qrQVNcO9f0--(+D9fvXB(ws#-(4Hp9J5=SL zwmxCw>)MN{2lpLc?g>a(UY8%fzir>V+>@2idKh13KS;XWi8`LpX|e6GMY-J5QnC{J zI)skH9(xpdc_eZl$4!KOw^!{$iu}U+qwS3$bbM!CUF6epk3pUywA{zb%BJLpw|6pz z&~gvjcUXyFiNl;l#t@d*<;iPGS$oGg*dHS-uS>TtNki$Ri(JkVC$xSyjTfW9J#dAW zZ78AJ0Nuv2{e}8%SayIhgqHjMuZwcIA1LishE?-@Xx>j@TvoyX3(#kDC+sg0S`V?Z zwgpXu4eXB+n)lmVmMTrsg5Svq9f$D?(BXAqDXxiJ?%hgQxh}6?GPP8$=#2ZU5|-Ds zg~dIyy1LG*j&-p~V}d3RaASEM}< zopG;g!ty%(K6_Q)yxfnL&^r4Y>UkYR?gbkfLuk2Am6c85orpG_&~opVO5X_=UhX+d zkhf{LKd0{Ns0(!vJ#Zgs!pe2!_-*tzbP(Q!lQ5zFj(wR|k>HeS-)`9>}3o=-o@{I&DvZezaX`pAD5wO|FtIM-MEi7Vc*TATcz(+-b{aAcJhAe z$xH0J{d1g_TKw+8F+oDh-Sy4B^8?2m3Gz1I=*zu(erX+rD%S??1xo08{h=M)MG)>I zD%~!&b%f5px-DcoDSBZ0MQC2#zOn6-_Kj@^p?P)N!gdGMz75>poUnRu^}}d;;ut_S zcZX~j2`yK*n`~DlC;b%)A*?7@=7*QnQSxrwbDGe+4~*_RE!a;YH1F5vBZH_Qa%b&` zG7o6pUL`qx;XM=fHlcafm4qte<+?ROr?K8olY4DKlnpPU9we+>r{C4QUzZZ|I`LZvljjuPgI!A#dp*@x65nzVQK;*VVt3=4*59A)(Xl z#$$_8Ps26IN!**A&~jfzI_e;CnAq%pZ?L>BjW4@Wa~8`n_m?LuuPYZbe{N&cdxOYj z8%b#1pO&@V!pl9>3C(-?99vS?kbB|`V+hUr_+NY3?19LAb$5)P0hZV4clpe|dGCQu zLXdaGRu|j)_iUt%4wBdR+0+<9%gx!7BDcihi};_gmtB6i0Qc%3yn9c?JP*L~I{p4C zsX2>jq3dP6hjWm**%)51A&6bErQ_|KYz(2}7JI^7bVTF^=}U;*AU3JU4YDUP%l|CI zr_%U8%ldFYD5K6YENgpN2XL&Eb3Rxnu*|a#U|HAm0JR><=juy*gV?0P8)W}k;az|@ z6Sjo7GFxfySAL%)Y{P+7>Mp4RI}$a_o*FduUd&iknv{W z4YFsi@CMm8Sa>;~ZlF1J!ppt^%l{qFPo?sY>b3W~{)%57{>ZM-66=r*8yk70Q?rY)i4 zP-)&|kTGP5Ly-NGB@RJsXyN6UFk#=#*-Yi*!onM59-{CDnKwBWWsu=42O9_1W|glK z72b0Dsw(?G#Pz=g#JL)rSS7!fU4AdJrhWEL%Ba4l8`p$S|3A>NewN%%D#rue&+8%s zRco(~h!yso;R_mH3eYg`B3 zTY)j)ZN@b|LtmF;^6~o5K+#m1M?lFtM}hCi|C>QM=Z|svu($uO?SSv#fNoo28{oxM zkUEv^7XelFetXsJ8{0l<--3+Mi`;6yF$I|?BXXLczh_&_^%m0b^yORA+J8}Ym>cY%@C%FHQApXB0(kw^95&Hda z7UPu+2r}NoJ^-Q9Ah88w=7+a%tv0Uc>q2x^8&~x8QEvCr|4bO;iUW9C!;zeaAfA?QrY-&FA*%Ggt*k8w*U7U+o;v{|Mu%l z&i{|H{m;b);q@OiY9^NU679)$FIZuz#)m`E`&=fG8%%v#$Rj)Ty?2C@?R;?03Rybz z0xux|Ia{iuVnx8+tJRza9|y^{|BvZ_R%=*&#`)r^>YlLDQah?KKxJEH z1@uv~|A(Ud_qjQ(OIhC>jKc?aXZVSW_K^DyMqm`e2UL4JlTWsXA88lkwp=zHYmY!a z%q6ca>>W*9YR0kUNZ4H|YkoN8)lf8{(CBn&&yb89_e)UXGV} zDSk_-CfY3jC!$`c)c*e`e*a6fSNW2`vsYIp6UMGe7}uN9(B$vSZ98aiK;42bUFiru zp!wa(0BIiHXgP9myd#(MGVz{@t_rK&h}LVdyNX5IsgIzFE><1Ll#x^$?g`0EED`9N zbXDm*l;uC{u^Xo-CUPO4_&`ep2VOE^zYp3AY!#Tx=fbX%oT4yX8RL!>0W?+R2zs%Z z3tx8LL*0YT>@g6E#}r~1x(s`Gv8bO!JoFk{Tcenu5O42k4SVDj87C1dcx-P5YAIR% z(S@(r{)S%v)`Z2O|_d@=DkD+n~D|Qi&FP{>RE=l5*>br3CmX5`9St)TU zn|W=0&O!<2q1eXAi=|s(F=a!@YdYN|->D4Uh3YYAhGzLcqo4Ax=l_ge{m86w;APsoOM;)20m&U7|Q-XjQhsfiH7oOGS)O}jlbHw^1qhMZi=olO($kJ+gjE8@ump-A^ueL zH6NOo?zb$1ZZpIp^7|zv#_ynI_Gc!fy+RC~&)C}bO(fpdl8Z!W9Gk^1!Ek@5F?EK1 z!qbMn%0z9AetwTc_ocmz);27#!94giGS!Uw=`krgLs|Y4*_MQtUyf}VK|5RWnb>j< zBVHJ-&$VQiF6~`K!((7=)2Y8)3-PTk&01sJ;&yF%B5TAw->ScB7IVXlhWfSaN0*e6 z(&Ud?U9K-%sxI|z(`WSA+3DXLb*XO){Xpr3uU+jyySaVlv3{PCEg%bc32eICN55UY zWaF$hGZOvauK`@r|J=>bs?=AD% z>Oa4H{i=2T-L=pEo$`l^_rK-j`X|_nHfJq@I|9)8=n~%t`XfwlH~{p0jJZt$-2h{7 zn}gmC%4sIs>;d=rpi8&%U5?xiSB&4o`9^RHc^>HX=vKcB`oyl-&H?nc1C99u=r1sZ z1)f^X4|c@x9q5rmS^n|-t1-W50_bKKS7-t~0?UWq2R#jQJGKWs50PyJJ#qtV=LWj4 z*_c~Ef44J+AVF`yvZIxtm)9Ay1oR?I3pxz+Ht_ETnuFY#pbyP3=Ifw%ee3o!0X=ex z$Yi*nxCwM7Tw1`3h&dUN_$KIL^od>rU4)yz4cby~%(M!(zDU2YmsNJsI>Q zjJI;h#q(p0!6VHNA^%p;qbFf|PSCwKgqt+bZ%#JmRM1(-J^0JKhUcCGIv4s_0Xh=T zdja&H%}8_5u5IxSpts`r7`ZX4=OB-O-T=9r{;_B(+-`z);l1AgU4{3)67;jkba)l> z81(Wj(D#qPun(U3_d2+K!}){Ae|V(18*|8>0(}EYTn_r?!FUJIAA@%z&@&O~^FilA z{;Qz#kk0=Cy&U|^oc!;`2y%xc!{S$ z4_Mz{?so4u-+j&(5#KlQ|GYY5VxSD8fF^twhYHQ!(DPqG8{op@GSJu8^Yh3tcxn7) zp4r%#y+9L?^E&9w_Bg1!v>91A)c>2VQd&ai2nY!~Zj&hZAwW5K8|M=oQGH zSAdR3{z-y9G9611LEjn<-GV+m!FRiKKZO4o=RerpnA1Ub-WO#P6zaBh!9CE!Z*e>a zmBu@uKiD3wEJ3$E0C^9zYm70t)f9F{T>?7ylc+xspFi%2G{E^&;CmEw%R^A6K@S1* zX`naHGUhv=-$8tT40opW6`66LKwbtt3W@(XXb$I3g0k>IHRd;v|1;3*NBFM# z$IXV0asJpCxI_ZI4fuUW~Bdq1Q8nnJzjwHdKc&WLJ6mUHXngH z81&HXeYarCkRDg#9FH+jp; z`g`soJcHoc6D;_E98i&T92x?Ua^p7X;v>Uq-) z@LY}$#WDT=@f`KP^?OKql*39~dm6{$|BrmUhdlgWL;L?DAEB?yG5L6n{{Nam`||(C zca;C>|Brk_S^m$%^Unt^1TF$t!CnHO4YJ0`{h+@E9sqs^JP14lJPfeX|2^;s@F>7a zk_{glBX+4?0v-gO1^x{jg8!*w)c3Z7a5yOHVB2u8qCFZo2KX${3LFc>fF(d2NC5W% zsNZeFwjF34up2ND*d1U)iuS`AWc8ra09NRYKoc+nKs|38J{pB{0N7{NFlz>#59|l9 zu|E*V1Kq&!zzM*Kz)8T#02`50fzyC905(!*0cQi}0AB*W4E!%}D?p>?c3?;7;+LSX zpUkfS=7~FjyMViadw_d^2Jrm`^bf!jz%#&;z*7M8+#i8I0nY+|2A%_+2VMYP1Qz0c z8a(@ha@(d?aQrIp8t^*s2Jj}pM)ED-@4!ERe*$jkZ$6JN2RsBk4E#Uf_rN2-qrj8EQ@{$~kHAXcPr#pn=YZ#d z7Xa83=4H@VfLDQ`EdP(=`3;EA1wc2Be*#Rx@k(G<;4i>0@ZbHwi@;xit$JfMgF1MlLv3$y@yA6N~X4!n>5 zKM(pYa1gMzlbqbNGK?w3QkYBA_W<3XKXp6lT*{lvWh=~Q8nkpwDQi!~dh*$hOh6xH zRZnEV97@d63Rx?NcRG#P*YRvR0?GOA&^IQROoB0JWE2eF%T%SZF9szkS=E%^Y%1T9 z&UeOJrZrA!9Ln+^>h!_(Tz*-FLHiO_Rh2E%Ey*lqPzG~OHTXnmoH8As0%rDp@TfSc ze$a2?a+UKv7WNu+se1HRj{dT1m1%$lKcN>hPLcJNbSxccer%l`?5{GysBe;)Hs+l0 z>l_IET!)wIsgQ=jKd<HR9~gsO!hr)mc7v0cG8iNpee2_>uL9* zNd_$H3lQn>%AD7KnXA@hbSrhUIV^dMrNUN`tDmqoF@TP$s>p4^W&%YxMBR7CBXY5T z9()KI8p`r-E10x6 zwQ_)}(oD%gKc~c@U6(%w7D7fZamj$re=5+xT9x^PtErbokf5&j6Tah<4wip@GpgkO zV>4XiH?QFU*8g>n17%p-^?%aW=Q=>H0j$P}O3nX&Jk^mX_n_2k0N4Eg*E_$;HUIx> zRa>w!!gNpM+W{= z{0{a|mjAFn*EtKd=Kp7)@=)w!*Zluv`mm*n`uRxs|KYr{O7{OIxHbX6RG85B|19ka z*ZlvKEP(81ahmVBsOJBt+C_c7-b$807nkx)|LFSv8LIMcJF()oC<13a5s0k$|0(%; zbMx|4-%h@B=mnYvKQAsLFrM|A&W<)~;2uTUEMo?qaLdSo8mpip8;! zX9P|~YW_bkZDA<;{~tmBA6(87%vVI-ys-Muf4v62B67}G#N46w6@m3-S0Vm)PV|?% z?SwT=-@y4rShw^m(D~#2B~^df8h#OQp4=ZxH$b~L^_OdGgtb>(=5q!3jsz`W?GcxC z9W=riu$b9CDnXIMBpo8D9is2HD3`sA%A~pd_`c* z)y;_SWK7%Ua=`q-{_?-C9Dx&z51o$d|AWKr*EOaN^d3|KtnWskzGwq&!CJ2iLC2%q zKLGjy)<<&b*9BYnOCGBF|F6T?)83#jqh7cURD4C0`-u2Y@eMIppAbXp z3t}kC|BnCNz8}K!`GBln3pEWyqk*9;{|~^hy9|r9xqsj)7?Ipt?#_8|#DWIm&AI-1 zAg&Ke;MJD_q=P~Ey%2BZTwF%AY~CY$`u~BB^|R!DQaK*zeqI+D3tas4f0gc+d*r&j zTcvaPznqrKDL>czi`0AZnAghr<$qq|ae2J7yz+a?<@I%4-!I1l@i7j^0>V$qxXF2? zIF`!|>i>iO2j&3C$`*b3{}7(1!J`qT|Bq(K*8V@xpR?=#yFn{`|JxYXCIGPS%-rr* zMuXVnOW~k`<(6}JxE~08`Ewl~%k8XB`E&ZXM+o-_Wx3}1zQr&IIp6PDEZFbe9Shr* z+1aF+H5qJ~ZIx3pv5qF}*`u68g*En>Y}kUagSZzcJ*Ew(}X|J*XhIp&CoYu$CNo}DIZ6ouQ4e+k;~WBvv9k> zdAUae58-?g|8v)9CtQnDT~BPcJ{jOk<50wD_Fr6WdM zTsE__$&zjE>}C_HZ)m}WNEHji$wDCaR=`g5Z}Zkb29(mhW8f_ zMkf9{0-kHqmW+q?_k140_luFajn9&EG|%Iaa{OQ2GV{dH3xn>Pa<{bbO_15EI++b+V>-KUEW7#C_D;DWSGVpYxlXL> z_Q3KzVs56bqgf*hy0h{uLc(igtKh_Xx6mCMR6O9Eo4#yOqzb`%(+V zj5$nJ{jbFMf7D9KYezdUW0sw7^5fXZ_LGYfbP_vTA7l6zQ`IKA^GDU5O?+CyOe)(p zmnLd%(lYypMmUid(@j@$?PGJ92KjkA-{d_mc@7DjYm}H?YWh-^BJo>WT6Jsr%4K>b z`~PlZsQV^$`xxZ5W*2#z@ViCph4D_Cgo_R%S-F@R&M&(EiBHSel`a<6)3%ZqezP{t z6i0+#w6W6h1`8Sss&GWOQ#jGMkmqQ^@@-}|*G!t%u__V;=%p|T8s{lb9yW#n< z7J2vkSU4G6LcaK6?}Ne#pa0!RECyy!M&1U`BF7H=XC$(2!h)10pqeNuyn}ugPaz-C z^O$MwtKi>E@ow3Sg(()RE<)z-v)ib}tajv3&}4KtI)9%uD4fp!p4|fP+~l`~VbC8& z9vy|Q>$XMbQC{iyo!4aXYiFZmB0G{@%{_25N&26MUJGNI?EYz2$`*@f`;hZ13 z-uK|pL6-i#5ouGX-Z+eBPiF^~`e5M{bfEAeljUWk<(xyq&xNl?!&hNJaM;d?_6ka#R*?>h9RFxM+H|Kz(7Q}iv~@V&aN#eoIzcmciNgr3%q zbQV&w8_oYlQ63e}LFY$PFD`?E-4H>*Y_T#!m zfd%C~as0Yz_@B>B4P(9T!*`Dr$qW6y9KIJI=RK5@w@B|C%Gzz@-=UPtMd0m&LdU+M zeT;I`Q>a6h!k~o{3!g(b>%seX+hf6lybrBI{qXc?bQWI+{S{F;vG2}ZBYgMf=HcRv zeSf!C2JO4+sRO(4{5Pq`=OD8-be2+|4_u!%3w>NmeNp%q`LZO+2Ynth21m{C*MiSI zl;`)!yVs(6b{z6AhJKTwqRfYl2auobRdXA19kq>Bx%Q5_hL-BFqsNXdJn6PVS2FX; zG{W$f-d3)EE`FxbACxf=Zp+vmr+sopRLTB--TS8xtGR#h-)a3^Q1>U0`_!-M$2LA@ z>3}b({(B*+VQx*1oDbZ8|9;GES6%befH5@r7W6m$uAuHfaD1O1^nmy-vxkNx?m`f~ zRnZg%>qEr%A&RjD?PX9yT~Ko`IKC0>mJD0`VDhTF7aZ*`{_}`r2%;)w^hT>8hTx~| zuX1u7g|G6P(W;6FKJ5WJX z1(QKZ7DT&v#@8I}{HY!xZ;h|IHo=#71Fx*>UnZ}HR>EL?8I{SKPSA%iXqZJYbU{Nr z)>j>S?{aH8}4yweC9tL@lfT50|zJ?|WGF;@74mo~dAZ(6CGJ_3%1+@q_6hJ0%?Y zIoe1MYtn7|!T4(UC-{7ih`N2FH@+I82|nM`tU-u~>FHe9m9{|e`5t(#X+NYfzAx+? z4p)5Im$&F%c8pd-LBXe8yia$f8Lhf|!KdArI^_qWRhKLHv{O#-Df8v*)G^#e0DRgT z(4ilUFHMCT#`$H^Z>yC`OR0w5g5U0Bj?Ht`l*C2=nkorShNyj5v_YO$?@R^_xdmU| zt?qT7y8d9aUnc_vpZ21OU1aW!(P}Co__P<&zWKpuH5C&aZB*9JD(C~OOllY}INGSc zxX&9ZiNEpH)Kze_ksdB~3d~Dkv>Ij#jusgz+5h|H!SA!wpIH;DVXENdjm8A)F|_xC zrA<>BLA2X!`E}Q(4l0=5S}pk{c_jFJ_bt+Asjm}!dHudn{iNf=a~D*F@cG_Ix$}d` zt7(tmXruC=y9oSX@@fhyINB(Wmli1x8s-bW3}@ftbIq5X#Z$s5v7?RJ$$NQ@AFL>8 zswDWd!wTx#!03-(9>pCPz|lr&d!wN5w&p@pAiV^6a!7mSf-=coU`W7v@2|nN7wE7a{^{ZtzLA2*|UgFxFd6W-7 zSRQM+QE+^tvhz##Ax~|2tR)7)r=3iod0H(En@B@hP7-{+r#;qPX(q$EQ<+Z! zM;o;dXM8iySMRK>Yspmb`F`@C?zF~N%bS8P??cnePdH96;kf%4=JE^mR&-d~mZ@T){;w{gK*78_e9fIQ3HM;oQ>(5gJ0-WjcI zH3h#s?EY4sR?Dv@gO z`#a(D^p-X)mkNH_`NpYvI@zIG^R_;Hq~P=I3_o@K!T8FyOz`FXZ;`%R%e;cmche&6 z&eJ?eaI{gr6^=EmztGaI;Ao@%;@IPRE|apo75qHDZ+=&@f{BcUO@-PL68g*hKZw#+ zY#m1JtKjFc-~Os?w)R)sc7k+Pf8PbJzHM$3ibx$+*0nVt`1&o@4`~TnaI{g~JeI!P z4_0=xwI%p`Z$I9r%-2oXJqn_I>7=kfuIrw~U27oPst_FCs6YPdk9+2;tw_PAz0ZBf z)0@27P8HnGQQCB8njef-+Z%$Tjmqyu1>-a8?bOc*e!ltrkou^#qlXONmNE%^c^iu8 zS2n7G&-Z4JR$Gl$hjfNSK*e42fOmGtr)(j=S-Yd{Rl&&+mC1QSx+}u;@W{d3!v}o6 zM|tbC+M?YsdW_mv!I#%>f7Lcynbh{3;Olq0P4e>UowaA$t`dBmokE-C2a{J@je;+4 zCCC2{JR7c&9-<2!y3xNZog0F|>gM7+-ebd&I;Ao@ryZEc! zWiXv-n^*Apu0@&kgVD;KSrF|rdtK_Zs!U)C#G|9wrEyfU8ghOyP-cPF#w14LUlARH5H zNZI#;rA_^p;HS;+-_-Y6JE=ZN@M--%OZ}M@XPNH^zPt_YLtYA#SEgEm`#H+DY>|FQ zrY(X`JAH0LUQXZW2cwmlk>F^fI`l%3^#_>|2#z*tOJru^2jeRf5W(lW zsVOx21J%(5nMVk|yo1h&evBgHE0Zz7r_Fw|XIhzQ3BC-ItYIwREAukJ=X<|pQ~_-z z>%Zwi<~V{c?-51vSY~B{qmA-y?>o9D&iF2)z6d_w#h>U|zdE}pP~5x5i1&MK>NWgk zLok^b3gT;Hn5#eCov+nRna2pe3_~yPPHXb&yptf>TVD^?5f4Exez26jH6%0_a(tt) z(UD%euKyUV%nk)#hA-UabIrG@I)^3rd`D5I{9t@#jw3kQC@+4%`iUPbZ8C=xd>Mun z^z%k5vq-_ui>*({a~*g9cYsG9w^@gN9{4isu}7X(?~Lyg{7LZB_J(^%p5AC>!X)_e zPP!&f=kq7eA+8?!M7JIZ8C2Z9Bou4FVcnYUNHSG zqQ4RxZPaHq6zI%oWkM(Tv{!x2W6E2j-II1h@M(W!1t9v1(aJf-#KAd;a=30s=nYXA0_&(T<>C2tMCm(Z>40Xl0fuh<4(@uuc6IZI&M_Yh-FI zIKGk2{>}K^4VyENw&i zUhrv$phG_xt=de%mtpG@DqH_$>+|*feQEPLlWDEs>-W!{J=4mJRPgmMV~6e)+4S(w zZG%AYX@63roXHei5bcrgUgqZWgU_bp^@5chnFI^Iyv5cLW!^3LGF)6x-%MVa>kFba zn}!Dq%B0cC)Ld|Uqds5|Wyudlt78j-Xg~AxMJ{dsLViD3+H}5J@cHiYx1QS)nac~J zopMvi_g7Q9w^7#a$d*!Yzee@Vx3!cVrZt5!;}-n#``$0}(#jm3?L-%3sxLTsBfdl2 zhdjMisp$t|BME%IpJ5H%g8b50j_b&T;8;aTAj8^jw!KeM! zR5H>FMyq2Nf=}C(@QB`M&!P_!eA=~4p%HB*`+rLwO}Ps)=NEi=ullZ0g|VegM>+)2 znqB5CRo!W=oXK=w@cG_aB;RDJF8F1#Zqt0e$sB+E=rKAPBsjiNeS4eo;s=vK$9@Dy z8}%2(_S|KoDflwnbV8o%0)Dg7p`!zW&-ac0$1@Q5@VJDdjq1fEi$swRCa;b^ z2#z)?>yv)wBXJT? zhL zauB{+YKc>N`|LiXQuV*BwyDZpbJG`zQFCTiM?>O0muWfIUYqotq=<~ut(r_zOI_j_ z*x}@M-cyq{w=P?-BaaS$ z)0rCWZ}fIUvx;&wnt5*bxi_LzX`}*|v!5j|;~H>g#p( zM&kjUr`C8teZTgvw707Bdi!4IHthT2zK@)9_SFC9 z7Ds z_$xEv(!2WqQ&!Ob%S@(g|L>jGohg*&|9+p})BQghAE;L)5R$q%pw%XP0bp5|-PQ!|J{L=M*>bJ)5nh(Ue|0`c4S9<D1nt)|4V$Rt^!h@X>LzMEB>@vjGJm3 z8(T6l^qpKI!@Y&!mTuS|3|z80T6(a7~EnKTCE+*Z;KcC+lpD`PT#r8oz7It}(sV{WPxEd_d#* zV*7u!ZP~i&PB%d;$39s)|6lO{HJYKP^M7x(G@bu9cGOj>|If9QerZEl`bRnvT1xh5 z%e0sUbF2|#H1Ej`C9*5-bNjv~P~TXasrGJ0EW`d6Yw|I4)b}p1xiL=HnxO9IWy)k? zk(--@hE}%!*F4|${LIEj-)TLs*t%b215qBclXU#AcB}WT_Gl!Kj{jG}{B$)O|Lgwm zKYPbIHO@Z}EabbLiEoR3Q#)}2?|ZTnfGqeW7|Wm6AwK>23!hs4%&32z|NS#=Ucw*V ze(lAz?i=`?{#reH=76RDz4fiPPTx>7i|~x8eCg;)Kly3UReSQ4D?i8b6|4JSL} zGIVc@{KP-cghalsb>3cgTgcaje0a*Alg?`DiYfV;k)Jl*9Uy<(@{J-te)8F?Gn%^M zO1?aGUS8)>YspRuTekkO(Z9!FdCx?8_$+wmKfy*DPeA_MDF}&MDch1PSj{JYi z*QWgU=nS)b_3NCr?ii2{L-`|>KLhzK)?Gxp%Ighe*ZFMuvXDPF`J&dn6Y>`%->f=w zuj{eoBT8rW<#$8pR^_WszT)I3SogxnpMmZclHU{g@YKB=x;x@9A z(?qswQrd?e_suzY98zmD!6ke^iDgCO5h z^64qRM)HfLyIyn;$5`@4cY?@YqI~4ZAGxlWlrIULXOv=zbPmcP77$@@Jgd?m}DukHkp-%j1PB3}@y zU$7`zzxc_`!4)g?l|KB}2Vcc!9$)uVuXXykNH zf7fM0kR-=U>--u`ZA#|JF|uZvTNN@&uA%PXTyx>W`qE~1Kj_;vb1a2rRK}xy^YJ}s zqb~v)x0Y7*tqC#9oAf7_(8-C)HYOQvjBrB3!UWPer@hJccT3?GHu8}{ODT+^k`X2` z!+3RWi8@2FZr+$m5e{Am)^+NjL{^cRRyK(wMoyvX+gh4xTjf5eMA`CArb=Yw*_M>Z zi7BMcbeCT8$wlXLE%KsOqF8he-95OK$j`UrE|FDpZBw?cwV^ecgi>4+D;0TnaU~|v zJC#-O;bgyv636!~f^U9dc_1iFJfvvH+MhRS+g_3q2^0a*x>HeBi@ zB2eg~tHk2o<@T~fKB|7vA-qyJS^L@CT&j*DP8kkNmfBE}Z=sXnQc@N&aefd=WfPh{ zl*py=r0l#_e0Y~$6rF!2#t#W`3OzlQn7S^zoKpETHQ;MIiAe%B{EkxsEn9&juac9P z%-|xiPV>YThNBI*@k>JOksG*DbQHBD;faQ17}aG;-44nN1+N5F&bqv!CX+y|C6wCi z=95^fRgTh|7tg<9DX9!cVv%#*(iugEI!j>`X$m8Py1G)e9;VJbizXn|%p`arRoAhT zQe;vu9NqX(A{z!g+4_?A>D-{+ZgVI_qNoUjCv;1!D*1}noJ4U7o0d}BsJu|2ueZdM zmB8*#SZ5kqGR}KJ5|VM&yD8(Y_$Y;2C|6GRsFYYF;A9TkN)!mc-U$qW@YtM8zA@TN zXi+XQRb}C@R9%Zxmx+OSt|&?EKF3_Pwk61E4CXXFwEiZZSA+}CXo9qm0?Gxc!+j`qHZvm+%+6b(jL-Zf9) zB`S*1WOyFDL_STKc_k)|o*vglNigwlO({%Oa{WS=4~cR=V)V#{=AK4T$t497k?;Jm@seOMk`U){(M-o*K)We z?V3Q9O>&JwD|P;#k^QWdy#vrzV3Sl#G$QW|H;$9!9G)HV4udAjys5g&j;=Sp$&EBI zjldqQ4ZFqpMK8|i`x#Z|Rjlh2dT*)eW1rD&-6l!iR&ctXz%0WPx^`!JVFo$>D^u7 zUOgAo_zwxMQ?dIpvdwk5&RXqR_MrOs zOjjg%rnMtU_I261j@HJ8Ol^BZOLH|>^M-1vQB>2`kjd8MxU(=@SHmp=oL$V6F=5WW zv21#4s?D^unC~C2m}Tq7lrK%J^k!?DY8Wwb4|K_8ZAHa`oa^MMK-`B^s{V7?ZwB|n zS+<26=F(PG*SEAa6}x>qeuXivZY)^_me@SDwAr{NUwFok89%`l9{;OM*lc-UjUC@( z5nK7WkUtMad)k#PTfM1on3pYb^LqUJSy9QY=Xw%TtuvQS;*OYb<*Z9HUS^D|uPe;5 z@q11x{A$9uFw49@PRM-Vj}s^ES@_3^*_nl3O`2HmzA8vuGTLh_<}i81>{b77XDzRo z|36$82Dnjl_kaHWuA?7)e;kew30nWtylPY>?`&>aC<-#hP^ zAehZ}x+g$)13hwZc>mW@-tWtMts9P+76cD~OAZYE3NM=)-Y;-B|5v8R43v z)(_=pxO~cNs+$m1B`@DI6U#Ub>2d|peeg5BZd_QhR=Uhsi|EF*EFycI-%9gbQ7vxD zw%0QFtSz-EGPzw#UKXYqOk-w-ei%w>G`mR}b@X*vzoYjGQT_O_jNcu!sv0eCPc;hf68NB3wJQ)=5S#P@!aZMbM2fgGhUonw^g^yn$PKCYt#p8()h_?m+qx|!kBP)kZ|i-AW^XfX2QhL zeR}+dx&PPdz=X+@C%d-H%Yi+|jStpifN~kY4Ri3)T~nX`>wjN<^R4B7%)RrE{odXC zu0i*|wd~gq9r^t7Wy?PKcJSu%KfQLtvi0BZT>jhBpSx1BcnKl~Fv&x|`BB%aFH z=04)<@f*!BCU|e1&^P+J_>jg;bZ{pzKLuOiOImxWn=ww&^Jn2dn&DA!CqBEsN4x=k zug@dCficl*#82TX`efoe7(YEp{BwLt;}SZ!cKaY`BL4Jb{Av^5jlb#H#5>^s`rE`8 zFgE%H@l^a#Gqei+j2~)-T0z67g5ZAQd2HJ5N4&w2LGTaaE1_ek7POO|-xD8-ziRF4 zUW1$)A?Kd>tG<@c$Ki|mGUCBFqW%i;xs1o|72TSl59m$U{6&P|7#{W>@q)F2U|Ztz z5W0r=)9VHSNeZS-!EZeA?{{QuM||U<_-rS>v?>T@5?_G44B>)1px>3a4Zf3zAL9An zB1R4FuBkfoifis*HxhFT@uanbU_0W|5aK(;M=}O{llUP1dTkN+lq z1z}GkJ{6ze8xg;}UJ&re;D_+n82Y%K@c~Y}&-#pKiNCX35PXq%GCJm~;7y);F7dwT z<2mBNJnt3ae@!9pi97LQUQK*D`LY53xg9x<8}`1 z@en@?eWjO7!LaJbHa=$QfPwgQ_k;13FL}YIZJ@sS!D!`kUJ&gzTYmkJ$#a(u7)06h zgV8Fjg5&%5V{W_Znx_VA>ptYEjds{hhzZ=!&kuS)@=n_%Pp5ZAD_{45qm9yb_dE7$ z_#gWupZJ1kP2LBoLw+z?`OX)7zEAwcr_9SBANzt&D}VWZFuwA|FZi^F9$>$Q|FBQ; z*)KTS3-5badU#{F&owWDeESPN->?3-XIk9>Ao#Rr-_tX#?gM#BWg-D4N0X8-!~d z+kJ*RK2X-PH12eXK^^?wBEFU1sT#q?`v$>Jh^zRWEMR_#p{@xAod%ZLZTyq>sv zEO)FB4?Bo87vfjOaOVl}`J{(O1edLkj)*_CCN#v?ZH(@SUqdPC4|XQ8JTf@^)2s{e zyiG~JisyI94^$9rh#uGC`w8gb6h2Qw`PUO)ISCLCqii=2KRS-`Nc{FdbW8m3aPDCt zz8~iQkNDc%Nel6g2hdj&Bc2-@+>4OE^rREvE;;ABa1L z(q0p{@5mT~c;90gS3vhi+VCIn`5EXQBi`(A`g-ESAznay>*OG~n)qtu{t@vJ{QfHO zZv1}@{=Wl>Z0GZt=z*VtW-{p};w57l+b9NPaj@<#K`@^faoxQ*C-eCv-oJv}?-I9? zUPKQz{2$6TaU+ReAO15a3{UX6jqjf(4mJn^R2BS&=iE$u!yxXuA>MFLbWZ&E&>+}@ z_zv=8F#q2e{k_2F?;@|7uIxz(z6vDYH^2ozX}Jho z3@!oEvGj2n_!js!_zt)nTmh~Gi@;St2gxC^!rp3626sgJZ!A@Hucir~#h`6X5wR;uC=SmYE;}>OdCM zgDKF=B0dq^$@`;0Gw;6u+CUDpgAOnkbb^z>Y2XxaDp&x{0B3@;z&YSc;H%(k;5=|X zxCmSdG&lYZs8s*oP8$1yQ~F5n^Dg|a%Cvr0+4N)oKlAv_==|?{d+$HX{;$~H_x6AN zZairIyL4pV75l&B^?$Rp*>{DX?fb&Gkk5*q>!-`oS4eN)>p6PAA~_15t^fG^{P%@& z`=5KG>q!P*&YpfRltrI|!Qr@aN+joGV&&Nk@H_hGy@?NuJ}a(^@I1dQ<^5XT|Mefy z>w6#9L3=wG3hfkr(=+_v?Y-#q`_07aD<35m?cN@gMtwhpSZ$hQs#N{gc3e(*c+0Qfz45Ih7P29JP0fJeb&;Bla_ z)%)Nnbnq&85WEQ92jlr(dfN+p0!V-RfPKMKFb#YXXiO(PGgNV7cjfzG;7o89xDPN~ zapUSei7$aS!vr@T`wVdw)Pq@IHfR7Rg8n!L7=c{Zf<3@>V09V;>_~dFK4)WqQGD(X zV}RX}V^xd+RR2%mS;fZx8}r+6fQo{B--&nspZ4ap&)?e}fS-ctd+_}=(D+(oBq<^32?2Y$@wor#|ZyMRA~pYz@Q;7>s7i_e13g8ley2G}2b790Q` z;QN0O-%Y$7@lxXTh(8B*<9#id&if~cPX_aOzXNFD{S@#s@B==7k9a%q9{3fXHSax? zc#DCIQNiJSejEG)9LV=y1i$3{XyW6*IG}bwX;PaIw>^-)+Q8Z1VsH(32WU*KG4%F8 z<7mwXHX!~s@kYe{cv@rbv3$1`uyOTHyx$UNY&{%o4GPE9-{XH8SC0hKfX39y%jsYY z7!M`^zg~TU&wGP?z`o!-cu0?*0XELQfbY~V^)%L&9;Lq{iEYe%DW5g&Ry~;kF5~m( zh?_t)_&m@!d?v6l_wl^%fX>F=v-tc~KA%XeF}B9nUjQ0&YwUd?I2&l}eJo53yMSKz1MR&WKs{U33q`v2bQ?&iq0 zqPnZGz}?Vn29|=tx~qBalYD<3P~H6|_%7%Ki-GFy)!_R8Bl{#w&6=w7o{D-fC|P+c zzou$!ZsN`^f6qa}{JWe{CCN9kqBjqkNwRiE^yNJ&)U#bdDVdmeRGzph%-c`Fb$2nI zQ>pr2X#X!eP4AM!7?Mw(xJ$en@4KD22(O$>lzmfmH%C5+@^%Kk(d}P}G7h~#x6N-Y zV(3&#L8mndeG4ZkanzdR@AE1Ha|AEE^f1Y%bUPR&CuRvV_xw}F=3Kb{FB{xppA6Ss z)JJQ+r=WJ?7~-Dh3Hp64us)!>?Kk`X9EFIC;&GV}-|noNOGAcJT6~S=5i>kNB^A3rH0;mW|wQll`NlK zgP=l9#5@mLss4Y|O3EAFGOiP*p5MjTtsSPtow=$x4edFOA9mG^ZYL3=e#XD7HA(jL z0iM6}ggJZu+Y;sMA2Z53YwYb2$yF5JRa0+IjalwpIg0X{XJL;jKqzp>+#~VO#A<;TzdyT zZK}tP9y?YoZBs`xmrqsW`=FivYDI1kYRl{5F75woGhN-5t3n^v{(t1SZo|_q--RpD zg!R^ycfZrSw+AHGYx(Z-R^3xQmvcQlwC}B;>m#+$Qq$31Ke;A(PgmUr7j`ds52BaS z6ZdpMUBZvxe1FdQ@=cVll!Nfq{`s+jgGDQ?7nif@|791@)4X2xzeBuv{i}ocK+qh& z2-v$@?@yQ2SB`VqY1Vw{alCtHp;}TPwcuBUsC_!`9b!90S%1-yo zSY2eB`H8lHVWzVy52B0Q`zacep@!!*g?IU0;hu$KL+jE1&+cZ zc<#I=8<*>Vk!<>G$tDjwZ|k$0{qNxv_RYc#;&Vo@dGs;9XJ>in$3ugY8So#&E^`~t zJ&E1fd-r5xbuZ){$|f8%f0Z=|;oLR&oeGiLgiT1ke{*w;?kM=XA;+1>W#KukiV;qQ z=jkl2{a}aC81+R~%>IdNhx5O&JjV|^Z@|X(;P4wA_EEOfKyRvCa zx{reHH*2#oxD6ZHq)(xf&pH&a*@hUlY=vg=gLM`+PBPqB4ghpW>%IiZ|Gkl#gtDr+Imrcab6TX|kuP~g2ZWN}j!GSmGQ%~VA z{(oRpMt7jhYvcM2%JX!D(;<|Rl%NUshZ-2?tYUhhY`-lc4gn1bN~W%WArqVNLx9Zq|3 zEHd0izW<5;=}_6)$o?=o(LpnHLJKK3e)vA+X$ksMcsxq~eUmU2pseU1mqK=mi-NnU z$0t$muA53*K>bqCLA6b&b25NfME+`V+`@j|vp&avMn&cAD(bTWe{tazUU{_CPcEUi z@I2bpsMrr{MjzDN2%>#%^9$V>vxSJ@2cuQB7JR;ch{P~@qg9m`M0;MxrH=0;vY=A+ zU+NLaMU3jh^KoM+Y8F&AOoeJ11eea|!}D=f6f-|qI#q22N@^G1X%rC)I^XE{@P&$- z;PY*>AEQ4QUv)Wx`#H+PN!J+HFg99sXM#`rh1+_j?c`5_qy5Ey9?_Y%fa>Z8>F9+P^a_@`K5%;kDq?=G5nU!Dux+7kt_wMRcZV zgy7S@PTu&z_-fcB__Uuq$fwNfOv60E(MILr6VrO8)eul{w2{sh@52{fFd5Wz39eb{ zp)XXfSk7q5AvnGfZG-!eXKZ{mwGez6_C7yPr+1a=|21UP+JJ(|tKqreLVvz8==35A%c3Y6>8rwyrV3L)+&mH7%n$x}c%8;Op!n+6zAzU-buqpKpGDp}u5| z=#QEf2##-5-_~RN5cK#FkJBYo@Gjk{$aEliVKc5D(j=WtD%c; zoHO&rSIYo`;~SN;i(TQ!i)^%-!U(>+Kkc5hE*Uhv7JR;Y-$4cRg7MX|fZ%AO^6)lk z^@GuB`X>0avQhVg(P}CrINC^On{MV)hG&uWjh0X#1BTR>7?M(-hRAKnJ?=XPR14-h_?Q| z3tYX}oO0&}<9iNY3XX4-Z->)|`N3#4-4`5fRCdm%&GLiME~D)dL~G-nt3T~i=H=CL zhT!x4vTNM(^u|}qWP(q73+;s;j8;n>f}@S{?LPM*Pi?eue5@F49A6zqt0g+Ym*FSY z=tp80t)}vVPdkkI=Le(Ja*^O@qq6hH|M--7{c4FqaAiNrV0IO^Ac!@-sy<1wA?H>86utSWQ8UAi#06|R)x#SzPzVxo9C-{CWDs01<}4) zb*?LuM-|bpmNSKJd>;!rRjU509&cQr2TPll*99kURCbzn=~)kPd|VmdCm3f4j&CpH zJ}q?%z6`tkt>^ltEgiwv@Ar9*A4~>qMF~Fbl|}023pgeqt*78;Ao?^`abmH z2cy+Ckl<*e@k6#qU#KlT!O=!CEGj~)Ejz*IJLn8wf_&PvB_xQp^`&pR`qpw-&$Qak z5PZHv>js4Dv>Wc!Gwn{a%Yx5$&{jRuYO6x<+v>6C(1Nyal*g+7XA&3N z|5x|9BNzzEb^jl%-BzZyGhN!Ed^=W$HN9ZvL0g!DuZQe6Jwo0Zt+tp1pZ0+vJ@eI; zo#4|tM~@zBgJ?^F^u&s>TiX?V$?%_ ztiIa%V{IP`j&IbazF~|aK}-g1c?ym;%8MUt?Ms{2ueO&3KW&qK)}68O)%Kd;%h0%f z&wRC=D)@X0+bH9!En>l^ZJ-VCgVDzE8)&rJ>K7c}NWUjo!x%9)+MB2#f@sg_yu`H+ z^9pokf7SM*;LAJA7!~lxF^ zQ@dCjt+v<&pY}7HhQmEg*ryWDv?FW;0 z-KqF(1irjyeAB1Q^XdZ`23;xwB`!zh|5w_%i&r$XG)rSAwIBbaq<7 zoXm74Ga$jyMtOWE<0?Ox9%LdU__P-nsq->l6nxqdm-t-sI+MAY;Ao@r@E~n~A4~?B zQ3^iaO+6VZ)&JkHnJ;ZVZ8Ap_e0ldbl0OJHgRL`dwP2&dY325bdq6hwbkn1>-0yb~0lXe7?nO zlVqwXINGSJA1MbyUNCuODk(VHsBW$|+9Twx(aPLU@M(u$-ZQP%Fa)3WTT_iw_#gWu z6HvjYUHplj`Nr`HZhYhTFgIG6Hw(TDyPNVOQH)mg{}jF}*8i&u9S)@NxcX!A z;$r}_0m|mw1)tpF(c?`qD}AtmGq#*pnN`;i!^J{!$9=+M3!_IiH0umpZ>K<#dv527 zPyBS#VscMy@5593awM0$Yr)r1M|;aERpPwzB?r#A49=Tkq^D1c^3P4>vbAlQBDX(w zD*zvOLM7|J&IPG|lpRoS_2mPCuiyxOTK|jrGfV4#k^9>}()It$74-l9`u~vSk50Cw z5cTgG6KKA#^#Gj*)H;C1(MKK~+Bq~(ueDB~^#IxYYFuD-USj~&d#w|s{eMSo<4T{o zPy7Ft`u3{14Y^X3_>r#v^Hxy*S#r;h|L4W?{~O2mZ|eWAA%-)e&~;(z|8L~z>d045 z>i@5Z-zo;ZE9?JHcNJJre=ggmM!wsbFTWlArg_4Fyzgn9K>z(eFqQ#%6yo`3)`Aqh}6y@4t7w^{3M}3|HH`ru+PqyXSztK97_Q_<= zs=Zd(*~#ukcC)hQ*0E!)scVl;cC50u*ZDr3_tDv$1y!N#jrL(=d!l_bttadF_`)5- zb$*@k)1I$vTebEjdtEUwdNOJCaS5?Adf2SZ4-h4=B5E9W9qFjn++NQ?9+w2a#XvP&(JA zeKOfN>kOsN3h0c5?9^qmq+{Va3N8CEogI>`n(V^0o~W~XvRjZZbsdMVMLw-1>l}`b zxymk6$IoReAe-oINWX0UbWC68Z?tYFTT`7;)xOgR@=oi1ItL+}4DGvWk6-qD+W*x0 zx6apS-BbJdPY3L;kp>-smz|evMrEg`Jy`8^YcF5xVzL9)KE3S7wWg-C0NQ8L-h$Tc zbml?l@8n8AHo&r>(cX(}f8>53i(EPjrSlH5kgPjS|`@=VC{{_4tQb}IwVc9Ws$9eYi>&t)iZ4!&Fu|MS(c#+T`wlL zDvr zcl_iPHf5RCjJxJino|jB zs>wEITGW#Ck+TUGmfzY&3KcAp@@=I7pa#F1fb=KdR+7ttCL0QxfGG4c-&Rg0O~Mp3 zVAsIk4;q{+XppainwsG0u%srM3YugoXo8`zpvpyEFIw!@ZB?o9zs}>!K2mmg+B=Y~y7minW`6NOsNmReZ$b8j+CTU}D8;vx zm}!z&%(s<(*F>){Xo9JU_^S48B{{U{;D?p*ZKeMg^KIqx_I+FF`(nPW9_6=QT5!MD zvlNCX0!#G;xgqeqzJjLLf+_b7|@>WBSg=I^OhsWJ7uVnvkd;fNJ zr4;{PEX}wO$ETOk#_{Q8v~hfT8EqV&UPha=PcP%Ebw7b+t)f1?jCRD7aBWVsmKTLS zy^J=FPcNfYlO;I5kv(3apDv?~C!fxjYpd-^iYHyMkeh(P}+YaI}$qW}zPwlR@j&f-kRpZ&j-Q zH(wNmzPBuGaeQxC+T!@$GTJ!4w~SV6xq`2=Lf>0P8^`yS(Z=z;Wwdd8ZyBxjO$1-w zLf>0P8^`yS(Z=z;Wwdd8Zy9YI-&;l-$M=@e#__#nvZwiv(-uiF2`gS_gIzJfS1y$j+-`DSr z>?iucXtj4PxX)4F?fV7MzPizBDk=DS7HBTGI@0Ib5MjOZPmC38+D8b1a)#G_X zdhP?__`Nb2;`qHX+Bkl%j5dxhE2CXJh4u{i;Ov|45qoD4<$QyHz6eg#JxMI>A1R}a<44M9 z+Bklsj5dxRDXT+q{74z!IDVvzZyY~T##h(!2r9pyc{-e%{)_VL2ji>lF2S#x$BytR z^L?yr8wE!jjr$I*>X}xybiMh8GI`_phBDeXzM+gZj&CTVjpG~2Xyf>XGTOfQhKl3w zNqklRk036#|4(*y-RoV-{a-=URu}qvvb4qV_hhtj{5=_M9Dh$n8^_<1(Z=!jWVCVo zJsE8re@{jm$KR9D%1&4C>)V#BBl*E-WzQ;z*8B-P`;ADu#w9D+r zND%uN$A^>A#_{1~v~hem8EqUNPDUHYhm+C9@!@2&vO5=?&Z03)p${jcl{tdoK1Xe8 zZ$6w<|M^SN`meT~V&m+R*NpN=d-FQur~P{E-D@9DX8?8nPv`lx2BP03%WKf+%%2}j z-Z(y-j5dy6CZmnxYsqNi_*ydBIKGyQwkKap)K+Bp7`j5dz{B$GFe|0JW0<3Gu0llGrveB<~}GTJyk zk&HHuPb8!5$tP0M{r`%5f2owl@rh*e#_@?{v~heQ8EtPqktCMV=k*SE{nV0yu5 zbw);Tw7sma%VbXQ`4;*_GQK+3Blxt1K9P(zj!z_`P1+}t@zpsd!I!tt&ymr_@pELf zI+G-buZ>Fz{Tvx>96v`!JDjyt!O0utTcMvLqmAR|$Y|sEIWpQfevXVbj-Ml=?aj|o zrRM)f6sbdT{2W=@;`li-T3LF&u_@=ci2u4B=h}!5XU%B=@olUTVTu^6%Rq;>!E+RZ z5yS^E@4bTfO5!Vtzsz|rmY#yA88;tKynhvE;)w6$f143sO`3j0yfNdSpAdHr<(f(2 z@9Y)?UnHJ3g=Z1}knz&(#P>3G`W><6SQ=a1&e^u(i07^m`dS>z^XTe>>d`^)RpLAM z#QacnJK%$w_-Oe2AMszH=ZISHH=gsq#1FF0%}~spOKc&Y$ey3nJ)QlY9f{A~i#2xQ z(`Zw^L%bn;zf1heu6##44dUyGt7yykDcBME?-LJ3j;|0mAou;m=c7;F24`~Ck6~Z1 zod4ZGJdE!d_65U8KO(sVlCzbO2xL7wc|bVFT!x+(@%h_Rg5YPw zkMsXMh>zPDT@qi2G8Ph7kHr@^@!AJ+&XRZm`L!+ab)<72;#-jOYs7b~%Q;PA`Q-dO z@oW-v4enLLFTYi@Kvh|@MZrd;j5Ft2xd(OWSuR-E|OFVEw5PXw(8U4Vq#1HZL zTf|rL`P0P1C{NmUcy}lAj#xTD)xnQQ7fB4Rr*KRs-V)`1f%t-{LGTOW9VU`i;%gB; zOME=S|Csm=(sd8qdccH`w1;&Z1_cZkPQcrGFSH2F-?3T_z0Ibh;zw-16Q;;qojnZ!E) zib(LOHOVXDTPIUjiKp`67~(bHzb|p?aMrkpe?~ssNW262*-rd%IU(j`2E+!Z<8*HX0Q+CjGuzH)(&O*1J9kp=S|lL z0%_AGRU)`%JhBk0aE&86j`DaJ@gMhs2k|BF zM+L#d2s49t6UsG3E%-d;=|JKoU_G$zEs&WrFq{sRP85_&-Sv=JW77iKimh zeZ&Wi;`}u6$^7pm;v07+Z-}qmow7(QMK=>|PkMP|Z~^)HL*gs=-OZ3W-{|8;vJFy4&n_^`gz1BqpXXFA4eIN6Z6sC`}P#&whY@D$`O%(*FNWoLQUGdDMgrv>Q+2q)=^hUGki2@Q zn;+2jx`vh-Do%Yv%r?DJZ1Jpi&+K&0H*`&*1=tQffEsLgVIve6RmhDpp z;IVe*iHr-%F`99ioBIFCk110BU&;FaQvF}T*uL2KpDC7GqZvs2++9aM`u;f0$in%6 ze0!??$``2i|5S&^v!J3o;ohGf)^F_ts$QSRM0+;hX|GWJ0UkLx^a;9@_xti*dxde% z1TSPltNleg7rf#Dg~rxRO-VQ9s+9C;&1Gmw@JG-nFFoN9C~3jf2hGp5H)Q4{KLAD5 zj3VUyBZkz;&0lSDNpyU(KZ5bqap=sB+kRtJAIrTEG(JaS2sHwVai#Bz2iLXI> z?PVFVucdS1_{0iyCF}p_NvwQl8awK;^jz&HHYL5V71g6U+<|7>a;@1+oRx*-dac$z z^jgV1b;S=|S?_$b88sd4^^D)6d=h|z_Fi2oJUz2IV!(h@G z=oU5;_Xrj3NmAomvu#DDKk=K9)c;okx09@<{=Z7x`G~sr_PH$`WvI2yGslfixSfdv zrpDGb;)u39+^M&$O}4~Yh3jL}+uB$=KiAUH9MeXjPuyJ#9Cu-%Pn@;(MGwk)QNsGx zd?z=rDQR;MDt5H#@ifm?*-h+;~ca~$6N;PAKo_IAA+w9Da@+?2m-ZV7V ztK=l#=D_p|9oe?|Me;EI$Sj*#DD-^$jzb*~im!a@Di3p$RLdq_fta2PZ$v zZmMR{zOh9&Cd5-$A3NFniYx5Pu+|z45Xzw#Moi7w_Rf`DKrcGIrg$>wXdGJ>b+^9*U-x60=? z(M{Q=mbUo`XAY^LHIf}`Ss3SZ?MZh_Ox6E+)a7FJpQ9Lg`~L**|I8(@EK-*G5oQ4< zlw}&slE3Um6y!p-hoMk%O-Xjeb*`^N#%y(Xd0SguLvw9o(j_%&pV*U+p`$+a5Uy@D z#}YU}-OtOkmSI{-Day@FLPM1t|1)&Y*7a2M`;@KS8s)hCbf2E!x|Y_223#XYj~qL3 z%;;#9y(!aBp7CL0w#WpLUUF7jZBtdBH(#QP>4ps9!j!v>B9nOO_A?Y~ql7QKh!l@u zU(ziXJx6YSb7poKGE^$T?y3ytXqBx0D^(29a&v7{wyw3IwS3lpI>=KOr<3kWI}%l( zXbo<1^4(iB0M3@<*c2U3dF*;R+8Y|nvt+>fyc?sJsXk`xLe)^*LY*YK}mPl@AkHa(3dua)-XI)7NeXbH>hQHl<8<| z<1p*|qFWU!Ijbn|p}sOSVNt72`$#)eU)$8snDnAR^aLJI7pqU|Q$DNyFImC-zrUaV z@oQS7C}nbcE{>5tp3uwzFb(46>4xT%_@f;LQOV$|-wv>K73 z80FMz#F{X7+9Vo?=mNgvdFQgUJq_(x@wIA|rdIY22|p#TpSnyrje~0#pk!L-*OXx< zQdirajSiBnP&t+C|NTx9oBiiliiJ@oeRnXX9k@JjH+*!TJJ?8KgInzL&`GsW7wWc1c`S-BG66|-#pnDP}f zmNB~DG+j3B<*z31zR(}7vlZ&FlJ(zN{#&lsx3o1Cv%W198bfZZH|AF7nrr7|=_A=O zX$u#ntt`0}>N2qGx`VuX;Tb<>`~+8c^5tp#m`vDgd0&kk-(wM5=_R>to(<66?4FzY z`086xdsE*qFI!|#mCyq)Pe^r zPhIowvahrz6wJvvf<~Hqa#`LrK-nk#FWc^3D8ssqdebc6d?lFIly+MxeZ^S(C zdE!f}f?y`GxotGJj^?h>+%b||=SI`q8=AX7b7yDnF3qi{xz)sLopTSkKgW_E=DoSq zd=4LcFY(#jPMTZB*U7hs_}<({nwvj!pJ{Fk&8?of`!qL}<_6H*f|~owH%H>y5Wf48 z?&pXHV;b=a@xP{oZXeApqPYn*cbn#h&)oBw8%=ZfXYTI)QH7Z${LDS*uQ;y#44=&% z>fcE3%X~Jsm1p5L@9TUvw}+1%5CnJe+1vt}`$KbMXl^#my{Eb7G4qx z=4RB~7w$$npGCeL`SBvLx%t#}IaPc%w}<8ibr|LG0lqi4ljfGy+?tx(OLLEE?lzs9 z$x7CL+yVRnxy?E5V!I9Y2sjm&_(2LFmt+@kLF&~+~t~k+KtJl7x>-WUYeW9 z`N;n$-<$hObBAf}InAx5xyd!RzUKbY+|W*%8oKN>cc^N+hXQj0YVLo{O{uxzyi%?f zpudk(+r`ob1sb1yq$9Bm<=%^k40Cq0t# z`bWMux4Y)%_JG}j;B>w>x3lJc7dFoArn%F76Foi7cM8t!Cgs`rX)aeRe;4wD>ht$M z>v#XRV()b^h8iGT*Es*YdOsz?@9urDx$=!Z&iPiS?{;l4eUbB>&Dh!bnAZUF zXuz=|=j&UYA!f(U&-V=C&jOO-{Cg|kj|ZOzHQ)qL3+g}?)Pq@IHfR7Rf;pfWG=b}Z zI?Pt^1<(fCfjZl{pcBjk^TA2r6mT*)6`TgtS$+}xFIWK10B3@;z}Y~ZvhqrkgfD?F zgRg+Eg0F$|fClW}02cst))#?Gz@^}u;4<(n@NMuNa5=aFTnQF|tH9OZyWkp-1K$UW z!4JT_;D_Kk@FQ>o_%XN<`~=(tZU(o2pMqP#ZQy6%=ivXq9pFxI7gz#*0e%VY2KRtp zfnS5)fG5FI;A!v-SPGs6*Mb+oi{Sr(m%z*574RqU7w})O3@isKtOLOyFc_=>)&xVq zT3~Ik4p0~6s)5y01FHY2{m<%|w`r&i7a|F!?bRW3p3cCB-?h1bK zv)D#Y!#4fEa1OC-YDjZ8G`bsDeC&>IJu?ld22u?quYt7xPhO`f$5aC!77e8J|HG0~ zshp_>lGi{b$N$NvCgqrFAk{!$G@$y=6us#Dzo-2_-P@)4yY~LH7g#v|U(vk3FS4by zsRmLFlve}k_`kgRO}VEU=+7EZ{g`4E8@OvH{YZBDDir*_=)PmujGQ4XFN~0$H)~e>v^{dY3MxNHvgZpqv^= z>wh`5oAORI(7!d1*8l#UKdE%72Fj^{bpBsX?WVj_4fJmfsQxcO#A5UR5&SkDXbtj|Ed4q)iiU{WThJDMFVO7 z-;09MpHmI2#u`Zb|J68i)1;*u=tTo*|KE#((w|ceti~Ep{l}!XsQvHS{I))j|DV@( z;f0{RKkfC&|EKJBwI3*(U+wE_&rkb*X-GAYYM}pXpi<-i)b~gKFB_?ZtG@pe;FH-Z#x2= z{~faY(a9SUE9lIx)&w-y_wNGLdVtRS+MS~8NH`Z zO*POTG@$yQ+W+^5oJeIzHL&V6P|5NCs!whD#8d;R27C>q<9}Zp>HAazA1w{2{-^8z zAFVu3Q=4kQG@$z5SNlKt{jsxuI`1btK&|DcA=N;tfe)7kDmDIJd{F2^%+3RAA2788 z_;8h-RN4=}22}sk^S>Ydd`wf2YG7qFkkG!tynohExNo2Fjy>O4k4Kq$uT@Y9Q4>Tn(i4Kdz=yx>N(Jp9a$U zzxw5Anxa$#aW$a&&lY~s^S|=@I~Zuce@&pEyMMG-SLpvob9UJSXfIFudYap(A=N;t zf&Qz3wEyqFd6P<(YM|U2Nb7&OHJtKKHPC-GkkVRssRqiefwcaYTf-^;R0I82 z1FHY&`M>^~KdEG?2Fj^{wEr)sc2nM|2Ku)KRR1gC|3CHp*}uz0D&0pz1C^@(9}VrM zsZ2G{zcrAK|ND3Tq|&7tD5nO}{=b~sO?jsp=-(Ph>wo{wpH#Y31Lf2}rRu-V35?{J5@ zXdtcs2`DjTk!s*WssYviN}T`ykg6*cJJrByrGawv|GKkJYkXSw)4HD419ew`*8a2} zD0@Mz{iPw*K&pYtYM>nTUv*!50=?D$)CW*y^FDogssYviDX5{?{+~?#*95Zv9}W~$ zztxAUe(NqE?E~7KKeGKVR`0`qr?067QVsMM4OFuK?=Lz?;&%8}jm1>|j4OFWBr)&Sc3Do?6`Ri}Zp z{;xV+r%y^X(BCvr$@;${-~XxK|Nd4|Qh8QK4XFN~Ny3Wl|9_0%b_4^#n#&)Zw;{2D z?15EB<@dYgQ{h^k&id$lkDd3CU9ipq>8y`zhHb5H=ux4)u-OnhhUrVHfm8#lTm!2A z3wdg>`o9UkS^Xd4)qkDuN!x%`o?Yn!Qw=1l0oDK1{wGnDrp!_ed}uU~*8dMpR;7Zb z8c19Ns{g0Jwb=N7V}8@QUyb$medqNdMDD#m?=L+68~6Obc%>oLK&pYtX&~+YE2sPP z$*Be^t%0=uS2_pM=cgK|oCebIf8}(aJ~`Dur8SV&|4QdT`utP_mD507TdwLtIr)o% z_VsTCs z9|XTd&QYU-U=hzheDfgKVWS{;40+!`*0YfHa%8MV-nq#3b!5F8*@lz8A*5>wGL9gP zb4bhgSY2I&eD5OfKauZf$I{YeV*-$bA** zSc$i~mcI3YTdEZ9& z==LwjH=Hy*O`Z=!<~xzI8F^1Z&Wn)q-^lr8fJjC*(Q@IoCtZQRw?1^6_PK z(20C^Am2vFd>}flL%wa$#RbSa5#25#9d*ch5@}fz`R_s2{m`xI0)OvT7x>sMz@{to zME?+VW*~Cxcj3piyzbW2yZ*2W-$=G}|9=%KJbhHEfqtZc_uqQ|EwxqeAID2(uj-Cm zwk=nkn_XMiQeBtL&1r9GC7xTIYp$J>t)820u4`$lu5YZ(ROi|<)r}1^-TRph?M=1q zvqxt7#-e5Bi7=npF{|1b@J-)X_);`9XBs=|vem6^4RdSTvt3MQ_l>2oaVcwQt7~Yk zZOn~yOj_GoX0_EeRn<2%W^>g|4Vku)!c?$M{Q$OuDzqKp{084=&@s~Gc8R` z9nB5x^Q-4(s@q#y8llhecFg#Z6RP8)(^2A-L zI~%C6ow=$x4ehz=F{8VR+?dfLM~@skaZK9(_oK!*6(!ZcD%ODN|7@P=&+APD-T%$h zC}4W!<|p4+&V-7f^F2DlqjNv9^^qSR`RwDmbz?P4fE8thUS{ux%0-Z{A_;(JWE;t=$S7wq{L-)Jj)_$E;}x1 z#paN9+{luo4X2SSFIe>dm6CzQsJ5&ovNav;^^> zyFuFh(XPWI2iq?njI~?hhsTczcagMXq}>Yz?VkLJo><|siD5i(zcAM8om;E_S7M9x z|7@8AY>l|_|Ep2Tl^XT^8t>cvp6d72&uc6oO=-NZ-|Swn_os7yfYc~OJ^B8GWg1cq zq#9Vo8dz2Je-$SyeO#)6R0FX!AZrf`vL;c_J^jGY8sa!s`U=B+le&K+s}otyD9D0E zK~@v~jB{kA@&>#YRE1VMvNpMp z=g2Zf) zzPX$K`9YRJvMTu!E1(u0Vr(Vrq3JyPSw=vzU{TnL(a+-=W_jTodxh3XPcmXskadwP zTx1z!K^8Itd9JKy6i)WWZs9lKt5#t5Kpz%lIVJ0szcQYbHJ7ZE{2+@UKgd$(q(MP& z33=Xp82{ZeT;Y{f&H`3@Wt}DKAPcs#BP%3X2+0EL7W6D@96#)RP-x}!+>HFUvP_Z{ zmMn#2@g-|1Sqg2!I5j(kasnT%D!+q%7V}xwOk<{nH%iMQOBO)uQ9flg^!-nSBTQKt zDaevZR$1?p28Gl4pDdMRCH9%9EDd8-T9#Btp=(+E=p?HJS%}G6$$~7TWNjoXDp{dv zgnI{il10%0jB;iDB#R(flxcKp-mYX(q#&y=h1t`oQ`83wvU*aGHPotmxv(%CWpMosjEXZPR#FX%p zEZi)tNjhYaCJVfq(333tF5x@PC=_G~CaW!lbI`dg#J(K0C9=v=kQJfAQIvNDS+&W+ zO%`IZ8kEJEtn*|c_7Xy#K-y(NrtmrRX+c(Qj}^%a(a0K6)?xQhPGt2aYr5OWKUuuV zTI}tEkP*5Y$rD)sF7(R1Jwp~{h2f^d^54i}Z9RC)3QpFJvWS#bW3eFXMp@qZK~{PS zvWAnjn*~`O76w^D?!xnBaVaZH&CX=`CyO{)RbESdQILh5tQ9TDqEgn5vb2+BoMw2k zB3w${Jr4P0H7EE^be$B7<4yKYRHf-rr%<3vxsM-xHbt{PwMLww!wOh2I+VpXH<4 zzx2p@Upf4Z`|sM|Tfy8B<4%A5JD3}b(N%4YYQcyt>XpDp4@5kJB)iqBI7(*{&L4VWl3hH45$M^X` z4~XwF_s8&ey&7MYc44r-jQBo8&9KnGZ&Z30)Po3)Z$!Ig)Y2OLw$U4nAOuJIi~l?# z8G@*m8m-BoH59>5+h5nV)P${d)Ofj;My-u6!*iY<#M>HM)lk9byTd*9^l;RoJXKH+ zCpf-QUQF91{LNlXUX2FHSh?yoYBzG2nVre)I?9tI@U~+AC+D?_{|CnS6N=xzVcU6b9?d zs7y|adPjYwQ3Hbp7o?ta{vRnLjZzJK1T~=gKaX@5TmPrq%=`bD7vKMn`Y+oXP@n1B z0LVTd4XFlF4OCtO8Ututv3SPU+_+-?)b29bcttaI!5`afP%zFkTCErf{utz@6Y_ku zdc;uJ1+82O{&;Y!SMy^Vt&A`Uc0sFFf|KFG`ySR9ddUx?AEU@*&`ezLWvJUU&sVct zCb%wW^-%En{(8OW$0#zsT1^rhZ8R=^-3HhNwAm@)ik72|#$s!-8sUd+qYqlu5`4Z# zM5`G_Z!&1*N$~leW|NYL_+wG5l^?<9d*HdI{gBA`zOZw+3ggqhyhUDTqBdHsa0x!` z;(fX+&1kiXA^5Z#Gye92(Q2hu@bfKT_059%4%3-d9R#26loO0HjE%2$#RZ@C2K4O* zqdkx>1z!e#ZYhnJR$ilT6a4ae6BK!aBoe6xTRh9Oun^j~J9Y9eCjcDUS?+qwovoknsu8d!trn*w; zj-8}pD(Qt$aDWk95e0D=SwwIgcVrYtQNeuA|GxL6PQ9H< zZY6JZnwi|+@5!yIoH}*iyWexqeQtPRvRG4rm%Vh^#IjhUL6D8@?eANxS+Qh-ARE`W zH#=()zhG&=dJlqZ%!jvy3~Z#sWU;h?ARE)LTdwX{eZYzde7X5`GjkGKH)E{^L2qoE zH|6x&nhI+^@Ou5anKiX7-LTYwpf~mpyUDuggFPEoU4ZNXPk3|af46(Cmu#%-*i8UF zz5C|+UrR6Nk%3RcQ7zWZtj&RcHotafT_5x)S?6_S@OnR?I_iTx+fB!4$3zISvE2S( zjV6A<$_2(qz0+|{D)U=;;E4X^p4PeG%eVL=AIZC?F{`QyUu2w0wBcL3Y--&h~K zT>_hhy3r7>T9xfggfv9iFDv~%m|iT_z{~EJYx9;OJbFNojd^yTDT>M$#28C7@cHnJ zT>Uj!b|!$&hkKkXI|7y@##`X?!H>s`)#}Pa!0HWr8V(F^qJSbx13QEu{5zI$S8gmc zSv;RWkd67!Z-aGIZL;hP0H22aTJ%xuIsvcu+NF)O^2+qGvjx1~HJ42+3uglG`TLLR zV=b@)XL?x^0WbTOSD9qCn=n7V#WM`}H2j0+9zK{}c3AYVugS9G1biC4sr>fA(!f{;eBJS5A>*Wth3t|7ulK7%UTY)I*ck=LUbyk{ z@NAn@mwd1^utN-j-dNAR5Z*MTO_p6D;AM}`?U0x(J0rl$UUXPPC$CKQ9%TSP_WCp4 z7Sj8)`4h{s(*lBC8!t58`Cxk4B?VsgCC;|TcTAR@Sm4v!YK&#K2?W_VcHgEn`Cxk4 ztp-6h)}2bOo>`LE{R2L|<=eg1Mta$W1-@PU-7yVWcJnPscu)eb_ndDxXPTuK&rA?x zV_$OqI~saf#K+}f4xpnARM*pEgT)62Ok z;PrmW{wZ0!G4_q$VfPUPy|J!;@N@B>IlXvIfFK*o?PB$@K3JP)Tm-%y`*D*o)npkv zfS2`S3*(Oc47-KE=fjbg_!Kni13Ra{=feT6kHVwCrZnu>0{?8!4sRN|_l_^&9RWTK zH$B)qF|q8%3j%oAE0o_pm@M8L0NJ4*y(6^w+NoZ$k!N_wfS@+fWlit=qcabX zAREi=l&)r3D+|1BfX}mM+~1I8*Iqvx0v;2S@p@5U2h zvUm&u|7?G1F)zWB0C>H7=lV(0dxw4r1ld@|t>#g94}c&W+x&}PHgWyM4;%RUaP#Kz z$133oZrP335%B5VPxDJ3EWLO(05AKdZ%&*Byug5$-OdJxsND48u>}0Hwc0;pJOI9o z{dmDxV&es#VF10oH@`Ks&3*UsPu6Igc%J~DhF0SyUJfA0#&-N-dzh&Hz!>8_1-#zt zUe=rj`zj|40J1+iJDWfBG-vO4{lyyw1if+o@Wzi%tQT)L;AL+PZyNHJ20Zpa_;-A^ zy!VF5;z0v~Y^=YRxxO0h>OMkXTm-({{J6=Oswxlyrz?O@Z=d~Wl(Dyri@@vk<0fP3 zzVSPF6#}2$A6my4Wvtxr=mIK^@pa*Y2S*`AoD{KUg0~+CdSlz%v{Q4zS$a7K0lePl zyFGq92KS6VL%$9Dv-y6VKHrj$HyQBHc97bi4`!~!dkXmceWm(0A1uA>-vFQ9<@Qf~ z0k6uCKE1|E2zb5Ev_)f7ZeP9rkjx9s=h^=;MLAi#(tuCH--It_f}DWS&xXKh7r?*2 z{{3vv{CPVxmxa|yJlH@`73=!j^gKRTdhwJ6K{mFx!IQjXV{E~z3Iy5MF0OiGa~k%J zU&TWac)dHTE%;z*z(W@xd*`#Vwcf?5cRrXbUX~!}jdgPEp&Lh8u}@#ea};>J zr`TdNs<-swi3);jEVq|8FE7UXGdKf5kd68K#aB(7Uc56CA^wxKuI1PAof*>37;ZrT5aV@EZ& z3zNm08wAcp#smH6?iU#j@;M1@;SH^mr5N2!t zpZPjt{bYB5v(BUqGj=lu&xN@hn9G4;bAVGX!1opJ-L?5QtiR&)GC;OxUbZgTQ)8bG zCdU4b7CpVgej2b1NL z1n_BSwNK6|IG}1dzMfp}(#y$~uJ|LId;wnX=`HF5C%Ax5?~&I##nNf%e8uw{=lc<6`%E5 z8)<+^33$DWPMuhmldmAi#<}A^?mw|C%mcuuVLv8ZF4(idKmdGM?0;56aQ-o+@gs!? z>>^vE;M4HTXEtPcWqM(w0{+?V3qR73H(5>#1E1c*KGcx&dO2ARyx#9JptxZ50j2@q z^`3IfJSW*mFRTI}$i}tLhnq#m_d__X4}xs053di4yoPE$P6&)qz~}E{D-AiA9&Fu# zy$$&FqPNFk*HZR}!0CVB^*;24hF(s+%T*@?PWJ;Z`x1?_7GUL26%PSM3E=agoLh%# zIT->c%z>AE-#*QmW@W*+4SX8*J8pi|l(CkXUKk2M&>QReWs92iTHS$700i0C@AT!$ z!eluG54`OA-!z_t@WNzaK>%L%quTTE!DKn*4!mqRXO}QpPO}3qyX@qUE90t778U~# zWMiGIp4^-dmcOvP0WbU1UB*?07go=>7YGE|n7==Kf3vKm0oDcJ)BBsJPAm&c1n_$A z%(YF^%l$;a>;01YZXZk*W(9!k%K2Ge{Vw%|K3G1$mI8v_m}kG&-h>Y(3o8c*vN0c? ztv2R^rGYUC__pcCEXFfSJ}e?2=#6y}mIxnAFKct)_4>6t>-w(vMVJJE*SnMQ+XvH2 zzYV*4g5KDl&3j67Ju|&9+W?=2<67hytSlhN#{7M=e%A-n3zG)$ zvOnGEB^!M;tP#Mc;mm`Z8@=g;^$>X3PqwI&Fuwp~&-mjzgDq$K*I3V(rN!zF3?RU# zx0O!^Y%aj3;cdCLY3YTX2Ow+y`?u!mugNalF}r^(=#Ayp$`1yXB7p2m?zk*G+wYWq zAMDw8{4MmL4YH{x=qGK;Onm+HyKl{ zKVz%|Ue=F=jFUDN!j1{NtRIIMqclW>0OJn``4H2)Q+N{v6#Yef$ruW}UO&b%{#s3f zc?kqnv45DK>(8u=VPOGY_Uk)MTo%}0ftP*Pv8p64m|obMfR`Q5q$qE)u#W;SyR#Kk zPL{Pg@MY||0^kvlst{li1wn7j-?3fdKVxKd5=I)})9`7_&?sx^g`o;~y=S%13xg2w zdf)%S<}{dISfl{5#;55M*N+Uw&n& zDI6Hz!MFs1Y-|^Y{YyyExV-6QJOy6%lP&s5ScQO>efyE2rEZ}Y7A@dqzx%UsvGBsu z02>qtvN3~Y<7NZ zg7o*;^{@w;EfBjOeGN9hxiFUlb2+eW!+!SX=0URpFTyeM3Hxu|cjw-(-3`gQkU?(IOW zCzBl=Tt8UbILKGVKO5HFoI!`vwm1t*!bg3B8+7?-wWm5%U!I$?{_y23}ipOReyD)jbClE>}vhh^5{ry zt3J-A&OMGa*DK|rl*-svMpcGKbjj>+Rq^V2wLDx|mylyy{K9OF|E!_$88Dv!)(>;O z0JAXy%>Cy7<{X&#R^TveYGcTpeSzEqN~Tt!)pu9sz%MJ4^)PWE{Ldo zsJ?EfTv@-o;Iyk|u2bdF9HjUmd!Sp_==GO3bU=4=rYuR$6vqGK)B(2g|HJZ%Eg74i zOrjy!xg4|mVcVPY|Bab57tQ6sBPa*L@LtGH0a|l)V(_FF(=vEu^H8+ElIU>-2gU0+x2?=OC08*^Th+n!3b1C!5eMWJ+S(qDXz z_YDjbt&~QoIqhHvdXnL4xqqZ@fC|!)+<19ybA6;wRlF0%Ej6D}P016oyEyx0xpNzL zmD<2SPk%~3R@~!kD64ZTd;lEiwoS;C)klF(QyCr|q&g>5i8hB^6%ONV@%1?NcG^={ zbuNCS(KKpcpsq$(ExcRO08ky?Ap1t)RujL(+^8Lc{=PK{C0blP8thObZ;Wj9atF3` zR1}qJy*{!|y?Rf*V^wviHpHwYp+wqjV`>2Pp<1m2Iit}tY_iCbSbVmqiDg+%+WV_( z%azUgk&X(l`i{{XRCb}G>nYo%QHwj4cM=rlXA4jSn0n9)|tiK3g1>o1E|t#w;% zL>~Ud#P|&K+|ckNyA0#^YV=`*W7ZcscP0@aKQv z{AqRmhx;Jl=$rHZQ-;okxg40~9OxOYcYVYi+vLnQXS@GOpDk3{UK#&KKk;O}p2$y# zN4Q2yHMd=;;bt7gu$1>IcCnmb8jO&)bP)9PaJowa(@-~ z&cNltxq9w*xI^`Td$_ol2R;SP^uoyj9}xH9alZw3{=tRG{R;3f!THI3soYPwRQb+b znQ+X*E6%-F+&Kd81m}+7D1|eFdtTr-7zN*{M|?xwVJe;oJV!W9c&26vEfF9G+P z!T}1;J^bICqh6`J<}MuWVBwBB?oZ$jQaB@MBl>#FHllwuouh46p6?eObYAArr7M@% zxfz)(hSImPinH)&b^h{!qW2c!I=W}Lk8?%%E+wqSihHJ^Hmp{~{p#dDihaJWjiPc- zt-GgMUq4bCQoNzNK3HB~?cPuw?5PcR_x6`7+KjFA>%bPW!&SD3SC5YL9=^Kx?Nhf{ zUcIr>nZ3@;;HrnM_1D&74N9m8Z5qpDZY;J_2icWizg7Fi1(zn8>zf9O-W{_>({Qyz z!d+Kd0+o*1^h>RlvNg<1_yNoVyP!WdGcsxg01Y z2eAK_G)`EcEppHH6&jcq>ciW@0G-)3H|h06{RH2=Sup$m*gcniKiL02eEx4guP;3C z3)%m7k^O&c4Ez5>vj5-j?f={vK;Hy!G}3sqjz-8X={oIL=>clHq4 z**jpbA$9M7G4^IXC;JE7J2%lD0(bn{KEgAU4|nLfQuY#TAAvmu_-D7qegb^e+uEMO zY|Z~mao(1{gV*LODR(lPEPGYJ&j<5&2Agckz0fwlO5w;iy(#wx%Mm99sMKfrBjTl3Y;J@?YTc%quvc-!W+57s~6BLYHS z5;?}7ZXH7Wg2^%;rTu@(wSU(0+@12m*#0kY?f)6M_V0iHTD@s%|Kt8YV-FYM|Ff;k z^QW5Q=ly@UGr_n2$>#OU`^^VvzHBA!&grK+pHH33rJnSVba+@SdYe1_Q{yLbJNGm?Nx3FFUZ>wkukuaxbDRVzpUlKf z(%EYNd%f_kc{l#E@1YuNCv17Z_h);>wT6Ae`ZN4wfuHXT$am8RlTEp=%Ve2vfS@<7 zkMnninQY1(TqcVjF7VIxVf~H|CX4Sf@UmCfKjRnd?Y#>#-(@fRpO0@IHB2_;UO1D* zo(6*6Xj3>aylJG^WEqoyUz=WYRzr@xAuR<$VBH3Ss+hm{@%mtT@plG6Htvz$tbFmo zWbxYuK{nc$sx8Js{C`1^jcK^Dg)BbA!0X-ae4m0w{l$I_kRAHbJHq`zwNsmAEg$e5 z243%~vzle?*|32EWP9elE$H1-e#kzUUi_bd*PFj@4!yJ0{^jN{r3hgR zt+Y2gXiPBT_Y0k0M4jtO-%~ro=wt>FUm(0@(~`piEVM1)_|74KM{82e!2tq?1PELn zYr&c@1&`xC4(t|KSXf{o&jAAt4B(i~CTpvJQ++;Qbl`Bo%C77`IN7s!Az(BmtbA@3 z^A~4*0tW;v?4$3nfyCu{IL%KKFzEY$a|aEUKu1oX;&Q1xn?fvRCkkvDwF(?e@BxD> zhe8M(aJWyp&+96cIOxHl1U6$hOu^<8i=1yiFNik%VZ-Huqq7AXhe9|2LPyHMlYC&2 z$l?dX1kN2e7Wjbk0v(SJT!hMjlau3bv&bPl>EtZ-f9YH})M9}HDIA30Fo^{QI~I{_ zju0@GO%P_Q{o5o)2M$K6m62*sx7^~Y<$=|j+sRcH_qDbrMZT}7tzEkso=mX|OuxhM zN@mn+#OLa%X3sV49xSJ4Mrmr9`=24vQ0)7s2x`sI) zVlNr?z}W{!_VGKsHO!5E9*0wtx4BWu9n~g#xrQ>Z9ZKT-_juQJ<8Np^F+&^R{T1sj z32C_c&gOB@^gd0)9`Mh0+-vQ>S&Hr1QtnVTS%%$r&-ew)GtLQuARE^rpKFoclzXS`XE;9zyxs+u`_wkt5dJg3KijQO zYsk|6U#Yi#U(f!F|F4cvHvE4dO!NQc{Qp#Ufa3qx&J^`KFU)E|SLL2Fb&ASfumwLw{r(HGJvjcy6!kl9OyM(| zqOw;zgGFoxnduVJSjW7?LXtZHD}A&>!96n2Ang`kJD1Bx+=Sqnzq4M zb(P+8MtjNenFh|8Gv47##`$Obh48DTtrIw({X}&F+;dJiSKq^Tfj#b*#JaSfL<{5qhR}g=W_o4 zcJ2Sm|L;b9VSN8D^Z(o8{C_L|Kk~0AK7da60Zird$Ns8u0_6Su*y~H(7i3Rxrv84n zc5S;H0iE>o>ojKoCIH&$w#*qI>p%!_D1a~*i1U%W{}25QeQk>WPgEPC&*-nU|7QM= zE%yH(nvVa^BX$4ZxA7FeUQ9Na;uveU=KjC=02S%WyI@sj1}obC$M647$9I=;_Q z05lDc)crqo7lG4;*!;Hf8F~2F>`W17hv50)jFAucPw>wWI2QodjRkx<2tU+ZkidL`KpVyP z9 zMt$uQDiiv$i2}Sh`EbptjZg5ChI5B;h&^8Bcld0!3h*}JJLm&GM+ElcybCaVO8LOK z%|rD2@JVq_1l~D(nBet+Hwu4g0yY*nm@L2%b(-|kPq077nKpcw2=GY3g~a})4+qZk z@AUupw&-((yG6Z}@l@vuEe*5>pvNiQz3-*LHg%EG&-m~8zgRD@{V_xSukVNXf8hTb zn~4AG$Nu~eb|uzelg;ZPyZ(RE9sjrH*k9y19@e>!WZysL^V{lNKF7=y z{L>z(naLh#Pqk-ssK2jL9_gzMc1xMAFB}*e9jUG^kB-!IZP#$M zKm2dCTx50iXuCW5KIv%Bw5%>~*tE1=RoX|5?#g*ZGuoVX%6bRNg(M0+MWt!5Dq^T< z@8Y|M3yO+LmG1s5ru>4U0#mhoNgwaf`oa`)msm`fezi zS@uIMje7)i-OvSD;K($ABXtBQhB)$T0UBunuH#UNv zsF^5nr3Tpl^88;H=(CCT_3{6askEfFSDG*EIQFegGB<~SsguFl^8n)djose-C$Qb) z3xux^J`bEN#=ijH3-%eYf#btses!M5KxXXmGmp4L1N9B#vIl>WH(9_o8~cDHu0WoN zP&8Md=}qAZG+FG4fO0WTlvjL~H;rJjDO`ajTQpao>BYq#klt2YfhN0P)zn;pX3I|D z3N*b%a|N2-6s|y%olTp*rJuYHT#&duM$z{%9aP zTl7u+a6>fI1WRuU2a%;=W!KakL?+9A8t{GfZOU&8?Q#&AUiRTYc(&-*Jnt#Z4`;IM z%Yq;q{anhoTMDw+WK%eZOg4ps$YfJEh)gzxgUDo4IEYL(g@b6;+P^CftCQ@v0$*-N zUg8Ax(w+@pNPz6BYc31>nO{0Kw36{Jm@G%tfY*D|gA>;s<}<*zx4(0fb@oP0FGuZw z*ZWEPXH12?#V-^D+1U5J`RMVah8HGVU6uKY2HDt-ceF+xzhZfY?ZQrDfCOIlNnZ}{#=l^)_%Lz@Gqkz4`MAmIjU)f*>2qcyV(!jE~(MBLrUWEovt|m|px#K#-kcjAiVg{a+wO zvpN6g=w(Q6tUC`VUwp7b}-{OO^DFhbA0NF41z9p3Lxy?m9Ue8#! zfbIBZEVqi*F%~co*_!LTF6k9Q8sa$g3Dr>_EWNCyfY*ET=7uCkZ^Qre5l3@@&$C6R zHe`8adhtI7J`G1jzasmF$>PHVyzKiwXi`~hvInSrgCHC0*)v-_8@~0x%U<`giS^hE@{FFsfr@SOxfmC6nOpPgNLS-YPnT%~7PC2}Nvcm96T`1~Kz^Tpw(EjL) zSf{i)2f)#Nj{i@_4>p~10IZes_XW~sZtcp9maOHswL1f+a~^=Pbit~0{$GDCpj{tg zd_?`7f>r(QWcLc!5yARe?;A;uI?5^+il5y^+ zkMNlVUiMwb?${)3dNHH}FME~p%LkLC41t$DJ!j}Q*@@0RyylBuYa_iFpn=!>42^X@ znBHgU9C&T54sLgGLA_j8`YOYJW{HPSC5mwEE*VI)HlctlhvN; zP<_!fiMZ?r&WxHM<)+GZN?q9_#r0Zcy?k|iiW&dErM}4m_IUi|NA%f3efYunKgNH2 zg8lf<{EqdhN%e(mX)`oRaW4m5{ zrX~0(7NDZKX{a{bb}A-&u4cZJ={{dZ2UG6vug%C2vNAL}wYygH9ldf7iw=o=c}C7+ zmEp<^eqCRl(XaRRZL0Q6|M#=6#}rI^W;Dw19xo)F(IDP5O~@`doi>-1H6ru2%^r0I z^h`O0jO&}!TljH3b|0lq-v7rrvoODowxjzrPWtfJ_y&7B2=nb|t8W(MwUwJ$YtCR*IJX=h|mml5G%d7C4ig9cLK{l?p zKHt|YYkHyC173De&*Ov1V)F++&-|VM`vtZqfRhyPdcXTKueFiCjP=0F?$*4F8!rpS zOAuruXXkB}z^LBdGQNW#8|%aIHi+e9IqwIMz3R+21zXo<%|(1Lz04PZ*L%@nUb69Q z%nd=1jb*X3^2rC&i^CZ3dM{hlsAqh~WO4WbUT-;9A50e8G4SQ)ZOho5H608AdlB$@ zztkenI8zI@YCtClr_GhiXU{&+_ z-|hp!j!?w!R!{Gt} zzg~QIYnrQIFT|ghxir4N%uyH{yHg0h8|&9KeIsGzHKSEzZfP@qsYsivB~z0fQJ%a1 zqmA>qoxYS~?)-1j=YMBw{-4r4c+=fB&Hq1b>&`%Rq})>;DX;DusScM%YQy#E8^I>f zRcLQ&`lo9q4c%!WN-DCot|^DDthRE#sbi0}-)Rz_o2tzAJ5XlRR~h43wzILa`7a~m zwsjH2Y_h^M4{F3R!-y1p8XFSG}qj~$;>(e`y^*W@GHlL&-#MilC=eA2(!?NWsm=E zOUGM_VA=-ZP;KMN<>jHidX>F!@5?hC@1xlo|FgyQ`2O|W z`hV{J&pH0DG%_w*dxR!5Q~tkJ4keHW6}xCp_{K`;F<9|#xg)7Wt zi{=V5y(wH_COey4VU~tgTw${{{+l22LDpf#Ql1}U&S-&9AEJ+H-jCCsErl!0WK+1p zOt!2J4}>&C-^@H$n8_B+6=r%QAt z!c3MO7U27+_wB!YgL7DZFAPo5Cw*vMIb``2X%2oZPc#U|i?^EA9kZsE_Un z19Ub|xInKbnkVqhTLe4*oAH0t8ux$RUp)VZaew5`1e-rFzQFkY=KX2xo(*>l-}NyFf2gS>381(KEU*sc1GBr4d(1HzQ7at2;(1&Kk$N8%|621!^|1sKg#iRA|GM; zTstQW{|&q$_!Hlu=Sw*=Jekk1KQGK#3C1EjFU*+{I6$gOFMSQ?hv5^Oi~|Jz5B%}B zWe$*xLt&_|N8VNSYQpAXacmdb%zXL4P{L2PLwXRLvwFIFhWlV=7^+rMSQUzUrlB^d zE{glr$$xaTuAE5n%{H@r=HVvth}EMby@#*vs})>G;nb~>YHX~GY#vIfdF@mKRqOiZ z`bc%4gUlcU-NV&#T^FUyd`G@%yPu=PN_;ojl2Uuy$(K;F%>OS?e>u^(zP0$j)is8| zSPH`YD$ciGC;uQHbbK!aW?dkBH?FZ;*$+5>1A^YTmU!5HG*eeHz3t3Nxnms!y)g|> z*gq=F=}lRWTN<#R0RL?NTs;@6=ga1 z0(@B?}c#K1x|1nBJ6mvB`3eCwUBW!DSls4sjw0)Ixv)#S@wf3n!{MKb)Bq-)utu0kewS75QUf=A& z&@yE+yD+LLWi!7rDz9$&4DPa;Kv$8uRg2R`Y+E zU&1}+tj!lyMOTCxBb7MKz}R^oN58S z&HMW;uxZOY6#{4XL8!lReemg>;y+_#dQa3O2L#zTA3XAU8ERZGS@_36kZr+1Zn7yH zdrqe744aY_Gm7Htp2t*J+}bUTm!($i_DR$=v$ZWEY7? z1$f#0vMy`9)tfB*V^eXEnQS{8Wbl-LkcK!f*(tmkPr~?^HJf~8_H0+JDweOz^rrBY znQYN~Wu`ZUugqk3(>MY`QMKSJGg;;xz>iseUcz{2^O6*9Gt-;0b~o7+ZZnf*&kKZS zi*3lb&1S3pzyCwG&+}sz;$HiZYxWK($1Og4oF&1B)q0=`a8HlYGSgE=RLLH3#%)PG7P;*VToxRreS}y`$ zw?Ftfv^9e1P4WLT*%bdjlTGpeGuagXKa)+_=QPDfwiw)m2m5&`tK*eM%+Z+rsJ3Y1CIG|S67XsGnDWpElhx8L zdB3O~n`z4Y$I_5u^EcU)`&UgiW#7SM-=+y52zeIg6Zv~bO*TKjobC2swEf@ul@$BG z$)?!iQDv<-zOyh3Ecm6r{Z^N zsljM*#k;P%bF6&U*fGZ(@tAuKczB10#}3+W`OPQZ{DJR{omjqp|LeO>*nIc7Z{B>; z&*r~q?A_=5=G|X%UFRuH7w9=@GqeTrn7T`yys(trTT0#F9#hJaJ7V#DXFr8~ z681mX*ZBSmWPi}S`zoc4J4Ud_b8;G+ICgIA(%74^BV!weC60S4u)Sg<#h%F=3L7N0 zMeaAaRcXT(7i?@Q1Lkhb1F&IXo5J1%r#@Wy@ZWP*mH7uYm^+kqY#@w3*dZ8Wu^V6y zSoXqf{mwjrwK?l(*2k=SSYuJ34b*{_g5*cKU5meR(d%n z0JFpkRByP~6GlYNf!wEbzFz6YU-JN!-;GKeKA}%n{o#xOr}dYp?kqn;WvaRXe>~?r zj!+%IuaJA#I3vM%61dno3xaITe? z?^e2cls^0fVJ~3Z<{Zd3l=dr?_UEeZj3`aqeao4N-IV{sN+)xoQO(VkT-P3>84n}Sr0hl%7T zyMv7Ve$D_hR&g$vJ!zoF9rt0JiTz*28A8$af74sE{onMatV>Kb#r|)yDfWMpolX0{ zrJ-n>zUfV|>6>iI+S6oH);lJfV$(O-6q~-urr7jNHsx*;WNFveDfZ)f*0N-yEnOV0 zrcswwQa4)q#tkp{)}NQD!&RVfz~6_qjc*(6eEDBzXa4aqXAhJ<;28CB7r!vuOM?dh zexi+ZsnicvkJ{p4nxbz8|QqUAuaqJT%ldxOVz} z(q4)4mrgr8=Tnm-nxD4kcuvoZ($q5dr%8uD!ShxJE47~L@bn8HS04&`-o6dxkt%m# z_tZ8{x8Y?+BI76{C7$*FqSI+1%>lbg(X9V#HTJTmvB3I_wHs?v)mm+8s7qIeb#fVGg(Wqb~>*sTf;FQ zXKl?|oV6KicKrS5zgVMLU`={~<}a*8S*x+`W?jqLlC`N1GiASH?aq3hfPM5kxjJR6 z|Jy429d)7|_B(7n*lK)$n}9j257=6;d9Yq*ea!luwK}$j>Z)w*jy!AdtMtAo)_?3_ zgif;l8^=9%CIa>s0_#w04i<`FzoQ*u*Pz|D)&2_{|9Kwlas=!t$0=UAEVIAy8TL2} ztyurDt>jt%IVVXUL%`mFJ&XXy6*eIY*v1IhjR@G^2-uadFS3qgy@j0&`wX@<&aq`Kv}U`Z@f`@f1N1eh6tw=vzKdTxQWsx>9} zV}Q(&8USwockZJ-{~aco#jz;{8{Jg~q<&eO$HaovrpifApBMAARS^2dutj``>IAQ-wVr_;lyb|Fae$P#r+{ zZrm^TX9ej`_&%9KC32ziLZw(f&WCH^u+QWSM7z z(3ix1Cx3?4WK;ZqOtzi=J;ndW^xnI0YX2XTP4WLR*%W)Y$)@=Km~4vwkIB-<13%vT zF~G(Mi3IyJHfrCe`u!*NrglY8A;tg4(vaf+W3nm!KPH>v|6{T#{y!$Wt@!`IVdKlq zk8g~9af%)M09YUT_IA@QSvlEXdp7uMfY*EQ7fmYTzKP4Kus6#7XwVzyNV~=Lh<(HK zvcC?HJ>Us%4*uoaX)o6YlV$A=e0ulQ8r27rP4SB{*><>!&+E$U8~)kyK0l@x9y<_Z z<2?8eHgSrHws|o7%OJ?cx$RxKxwz>~xf9D|S+4=#Hn08zJ5E_({cWw(YTFDp$x zm~1<|#@NJw&xiX=QB-bkQ||CGS@ySpf3|yE{k=&4+av04=UgFv4j`mA*5CYD6-xs) zHsH&xOKV#K{y*OeiOb$&8(q5&l_spi`UG%YwU*me=@dbR=%vivAf}CgH4Bd96mVsqA>p> zukTTVW-UG)u21G;_@TT`50BpsekJ%~ELoD-lJM7|z2a+x9j_hEPwag7mtYITzKflL z_JNNIZ5#UrYe9U5Sbt!z#ZLn}Eo*#iJlHuH7x2@-p97m0zA4xl=O3NO1u+U57e27+G+_7MD?u$$tCR8|_N z%kPO_3O+peNiA5F*;=vXQIE01V#~w#1%E5!^}Iv%3L6amR_v8y|H9V+`y%ZXn+|;q z_EP+&u=(I;#oUW=5t|ZzU5wM%Z6@OK#1E;e^xy~9E{`X3Cj4=*PvF;s@72n#Z2gVz z61I43P52ct55m8Pwxp`j)Ry$NDM;OTm`Hvy-XGQFH30LWfE`u4EqKTPvaA8g)n zp*{pbZ?p-XmeXspU(|dZ_%wVow}!SfwBs|4uR8F0zdGbo+jutCECAUHH(nl|ZIkBL zK3E#?n*c#?T=Rb+ylF_AEc0~WWsldo#s`y4;jb}S)_(xK*PoG{?|+)o?}N#vaQ>Jq z>kSan8`sb;v42M8_7?vH;GZqer(v?3uK+=|1(%S?;==)gY^*z#Ts<>c){4NVH-A@& z$)@s6&Q|-kva|HI!#By=7WjM!j>@J~vFXJZ1^E8qQ>xDvUaJ3T`4>XU8FSOi8XNd> zyI5;IAFRz|zXGbl<9(F3Z!!NhS?oc;%X)he^GW*|>&b z}5#cx8I=Sp&X4Jmda` zEO*~%Ngo2X2oUtf{$au84Ow1U8dCP$O%^*B2zsN<^;X$Md@xz;I>4vl=#cn^w8=8o z0bh6gSjaeO-KO!6&Sv|+LyrJ_x#ew`_G~HKCMMg?IaX|Lz~}FNvK{$gda>C7FZ-r% zdP_~CKBVx>m|o6wfuJ{zv8_1fzx_O=LGWe#cgHkROTRC3VhAbcSgl>`zE^fO(Wjx+ z_=XJ?1ld@B^ZYgTY$@k%O%{72K<|&v&c^wk=IkABZ`l1nNJDI!Z~S&>Q=m540%b@DSRdo-41E6X(V{Hy>jyzLwxRm&_GDRX`M@3;@cHnm7V9kb z<$%|l=kqkZDd$a1mVHj(pY1z8pE$iKT&1R$^Y*~&{cwvsV~+}W*}Olk>E)aR2(q#6 zJaI*HdaW;^9~|!sqpa^I=|io1Yll~l^BBOVVR5dEEe-770x$bs?K%2jvMHQ_CJQeE z@On>wwAb2LUvT~h_%Z82m5l}b{B3&4SO>hU9}7MAead|oR&I<3!0Ywn1!IYg7qtHi zl(<&=f6OJdWf|5DJC1#8lU1vE`iyzDKL^PA0{;QK_nY$tJTK>cI1hyXHT8fw3BFjY zd-3%d)K~$0{@!a3qu(K@%MBrgOVhrZ!oOo>oWf&idfA%?A-!=7sJ1jbF%DP1F!cMo4n;@IrjjN{c`VHf(`Fn^>02{8rYu(L2v9QKl=8b-hSQ=9Jm`oO~3gGo#^=z-TkzVQ)*p7e4e#iU#a~|Mv@vAAEI#wU> z#{fPJyS{hgG~oLIkp0XrGkfaulrKKmv)!*U0zq$FJDqV9t*H@AHs!u|lg0M|c)g2G zZRq5c$-8cXMsi>I42J!0SEbn2F1cvuhy8#ya`oX3_C=%k_E=5M*P0czx)&8)>%m(uV?H z*B@JH$h}VgGg;260Y3(K?pnrRWq%0maGkWnx5Bwa;PauJTW8st3?CifW%GAyTUju! z0G|*09cPxUQi-#%rWZdc5cI}+cG;rl!mvEUM+yYlSa>y zA-%EO?##7KlTEoVz+^eU2hh86e%4pNOMRgaR?pyT0zS`vul0rxCX3G+2(mG~&sH1r z!P3yqIkgmCAJdz{4QsOVWitf6f7t)5Mrv<5x>VXBzD?oNHNBjP1|c6}8#=BG`!6^=U4`o z-W0wdlf};!1if)=$#b30*7)D3X^lRr?*#FJ2)+kYl{L|KM2#g)T%lff}amU7%cJBJ&9una7zC`OM3yiCp7KVWDEAaJUey)$Q zXTzTsc-gP-H1YU`FD&q~?>bf$#0Arf4>RzxB zo=a5-@IZo~H;!3jyTpIS$l6=V-Efv(cmaXedsYj*DSV`+7aw1MUOWGHZP&!<#jhIp zJo`+GGH&Ods1z<+OE3P|`2XJ+3L{G=YxO6;RAZz*Td0rT9REi@akyT4I|1`|0{ow! zRqXu#|1fsvqUisB!$S}J{Kq@rJpZAwvFQK*r?LBga&DXc|M-h=UYkCZvuDhw*t5bO z@Z85{YgV{8upM%)2cH#e%gn8(^8aVOz+3}c;(1-!c{%tU;i<%@hBMmOTsfP}*}HcA z{@F9c?}&K{?PMyyf4C;w_4&V5>1NH0ecb!{v){v6GR9ig;MfU|UZm$#+un7#>Y&;w zdv5sq!(rKuzd!Z|?38d+a)y$1EnK7cH!&~mq`yCQ2lM&Q`}yN)PwjT5Kudd40 zmdxkj^W^LwzB}+nz>msY2HP9^v+UQT`ulG!Uw@lN=WXOFju57@k^lMrKi|)2(W^G! z9u1jy`ZT7!X_H%-f=N6Td#W3{>utF!o6?#1bk>G@`UcDW^~{@7Y-MZZ^xW0k*I%u7 z5A;=rYxP?1NY{qG`e?bot3EQ?(^un{lSLXQt9%=l4 zQ#Puc&%f&FaNpqS@`g<_xUzl{oipkHCe~Z8R|`*T(Akl+)~m~k;>=qe3#+cwF7ubZ zw@+di3G=4izsK*BV~=FEJcd+u)|jDj@^WPtpJbMIRw@KMFbM4ETfn1|fER@YW@_x1 zu`0y-056_=fJNMg6t+BAc=Lgsk5+-%TTyIztQ-iPV9R5*Zvm?uGjmS-ae9}TAmK?T zXBOw|UH12X6IZix${9&Ihavc*U{1gEa%I4yRSvnPm~uq zHC}`kU@E}NpA{>sO4!v|UBjM^7cM)wSV5M$JUB$-$>A#xi9EOUuJwH*_3kB$$4?+G zS$yc?Lzk{xvRHBV=m2unUe-8^28I{)4Q{9o*Q-6%q52}7E^J!!bS>PJtT)i)_H>e0&ZNcTAPb&-iyW{eK5AKW-tbczSMUtU{N9_m|Kv|_TNQX8%+UR~EhvbMTX z8|>}lcxgh$VAp&5vQp_!GVD>~x~$qMR)sBn?+stQ;J4>}^e?Y?-Q!+${ipx!aQ;p0 zda`P}DxQ2VUNiR1KOemJTkE_2$9F4#_}VWne8RCWxb$7y{bB5xBd_~^yS?GG`);{m zk9UW`tIvDJ#e3}WzMr3e?s@S4{UGE2QzZ@o`x@{z(LDbjX(A{I0W!^u z`+a!sCrzrt|M@rE8zAV7dvgzmFY@0km|j{T*q)E0&Drlkus;ze8{sY)H~@p*DEovs z0z|bT4|$!!|7U5yCkpsy^ZZDRBI+93q1WGy4UahR_2EfBZ#)~ENE)0&z-|pf zeTe&+H~w=&FRv^OMRNt3-W0AtldZ0rnk&#`Q@8?6wrH+E(|hm2sks78HiawDWK*~T zO_miT@O7u8JqruW`c0PE5D4`l`Wmb{%OtbdWK(zrP4+l_75Fsxv1OkA2MGAF0$+b; z!YgQLNZ}PU*%V$ulTG0jG}#nhL6gn%3UaW03YjdNX~5TqJg=b1rtk`x zEdJ%dw@rWU+VcuB?*P8;_<0F)7Mqt`wMyfq5YijxeOrrz(4H-YgUDo$k|hH8eDG(= zu~h648&lC7gqDWMIEeD?7|t}{+kC%P$v&7~_Gv+ojbp%maaC^eCY!(ebRrHClYP48 zy1?trbC8%UR$Soo*Ppv?mxILg!ao8?!`9{?u{1pM#PoX`vB(0SXL$}1)0@IUVzMb5 zBqj_02ncD2V@sZc#AH)ANKEz~bqoN#tvEw>9v)V0!Tb0zo#e1M+t_m@K@a!0SEXB&Sp_O}1zb64T3h zC*b=Be@44q4ieM*NZ}x{^kSt2J|7OS#i+`G-3wdZ7tL2!uf)=j!dGIlDSRa+3s(v7?Jdt&VzSfWEAe_aX1_9?ai%xr zUKNw&-X7rf?%iU2aff~h_;Snhm6+ZXz7mryny|z_;&_qgD>2y=z7mtgZxW!_cmwi$B_^A~S7Nd$d?hBE!dGIlv&mOtX_zTr$q#oM zZ|>oR>E)a;@MDWVcg>mXed1T~7673>#5v-ooX@=JvK7c%H#aCjoDSRa+%RC8qTZNxTF~_obR0_9=>AgtfAn^4e&uwC|<%6c?HZj?v zxlK&(RNN*sOPfdG&kub4{o<>TXav)XA3X5+aPEeN9Is3k?-_vX<9B##*h85Kw~6VU z%5U4JA%)w-^rmo|m~0BSiOHsLo0x10w~5K7aGRKH3b%>L-gn|7gWJT?dzIFYAk@jY zX87O4ZDRS*4z~&CcYtrlRWo$bfD}wG_kaK|d-8^6qoc{^ z+$LQyK`GoOrZ^+$JWQ!fj%*DcmL|ix(~MbC~7(HcA-JILqG@9u(7? z!h>S6DLg19JDWTxmWC7_6qDtw7zk}BuF3K|C?=c2gJQC9pa8Eo&x2yJo(H8A*8%@% zn>?|oO_sBTz_qDM1#bi@BQ%p96GsR?6I8#hEg)_xui{?x*y(ye2CY!>UVzLW0rh`xxabA+= zOfgwbIRRu}a>r$1?f*N?J$x|x1NZs?ulJB&&-0?=^9SzR1IVtrCe!<+W5aA>T;9?! z$C;94NeX9*3w=9-JN6Qv&N1&=7`7KbHKyf zKRmYG{oa-q>m7_w4^Kr4u&aeeRn#pY*f&FM8Fx&-u-}zx2vSg&)U92rds! zQZj#K-jClreiztL7p%&7D%i*1oB;M{=C0T*Ib{X!1pYGcfa5CxX9uUIuvKy@ld+Wf z3bwVCT^aWU{WN!~a59K789#Ey1pIvQ8-UXbUspIFIE6#I!A4Tj3 z_*de)$!RY7KGvM@*TPW&UkRs(SOdb-!rl$*_^{qpdRVt`Zz!BItO?kQg2Vs9Qg(kS zr#Rs=!HQiw_icPjXTV4i4;brfUev~~r_Qlyd#STF`rA@Jq2`>rjAJ%N#8H;}y z_lClg&)yn*KKK-|MuTgGyFoddf&H634$gnz&xM^G9!E}9!PSHR4gN*=EipgkYyk5( z=D%>sU|Yp*%vlKLn4IjxHjKYEc3?7gVU+lL$OEVE?7K5| zajyvb>g+vZOTr%(A7%E=*#$HH98O9;YNk_LL&NoTP-qma zwy&l$TlH#+<^uUZ%KZgDNj!@;R9`n#uBq^QSJC$LR0oRA5Y$%JjILGb z7N6ky=6c^?FEyul-BS9B(dzK#7G*eE*V)Z(6-ZA_4_IG6QX5h{5pzyHk z!=Ll?KMfZlFm?m4_rAZ1|BR98U9c*f3kBI|m$>}OiDelpL6D7QeAvH)6pequ^fHeC zUiOn3i+nIy#!uj7-|i=p`jW{q4*_2GyFc?<8?x|_fgl_6cfH0}A51TEK7j1q`(7H> zUl*xte9&+k0`p4X^$v$O4QbQMUGX6NJFWpQ(RY0?S>{?G$j1Ere4m$WJR4`1fUgh! zY!m06Oz%LqxKjFh3h(xsP7ALq4>RU#sxsvqVV--WDGrm@tCi8=zLCw0^Bw5|dxnZv zYeU%JV5R6jn=IFe&^;RIw+f!2WXH-A5?$Q=$xF%2FC{XkDo3Xwuv<-GjRWh<60K5U#BLJR_HYPF)f z9m}M-`Txk~?hTdh5oNLX1M7OZWci`Xw*i*lqO_3>4Gmm(dcgw{MM>J883lwz|bhn`eLDfTlnN_ws?##&}%%YDH@w z=khO)`ch0;<5M~!bEj; zZLl+TyMcjD=xyqhQ^)BxD~^Viq2ec8>S_imeH|F5WIXN{=XtT4p*B5aQV0k9+Pdf_ zhx;lWnaSBgXk+$M1wV>1zNdd}2gca?=E2Ik4isoy{q$6Oi_eMC;r@YI2k1^U(Dl_S z#m~pJfG7`CdxrXkI?$UmMxVhXTWdT0NYowo;14gpB;y3QI=G>D-73uv7|+!ZwJXvg zlYx5IFh}oDdvsk?N6ZpiXaBDQo;Y*+f6esTq4S>G|C_=QWp4kk6+e3%H#)QbH>sif z?8z67GqK!jJP9{mO|=r6#sJGWHB#?M7z2x2=0Ut(`15FVl&N4?7p)~c%QP}dMw>D- z)`GPw*)pHhwFK$F$UD$&!%KN+2rErlR~Mw1Q>K?cJ(a=-$fosbb)Yh|d36U?B0c4i zDvSA!6v04cQ}K1CIkn-2y+w-^mQ@a0Hj!6vy4lL#RG4`^R%I;i+n_A!)*XRtT(zn~ z=|5tMLvP((9qg%ZEDuebOX*4{OL=8zv`FQ7_S9FD* z#IROOvGmr42UgjH<% z^Qfk=q&%{&lNGDCZ&S6!q$<69ChO38<(^+Q)G+43U}%YU?D zSyp83iz_Nyd~xNvF`Jh(4Sv(sIawzV&MtZXQ^lLJ%RSq&6%$T&l5#LK`l-rmUA2E`=F{AXf2B5}Dp2j|o-j+@LoPo& z8`9lJE0$!_gXz@zNuE2GqE;Quij|8y^7GkhSysEA+QymIEUUEHkQ5g#TlP|iEz8dX zRvgxowHKG&habL$)Dg>;=jIeEj;Q9R87s;wSC;nBu_j|J_|Xl=-t%97`p;k8KlX$A zga7^9KOT9*cDLOB@Ky!)Rwj@@$Z_bxs0v*#@SLpT(5 z;Ym6ruhUV-o}iQ9im%qm>ys5fq?6P;r_aen3dY*46K1IjWIP~@*rSmaL=Mm4=Z|eO^b&~I$inrI%@;4}c?eRK=hn$Ww za@y{3dx~8_@eB214=Fxx=j>G5#Y*&Qy?@c8b%Uhh<5!hRpH=*gr|6`;;!m6+rU%7u z?<$qnD1NKb`+UXMOJ0ZXOT*I3LBQMe`|nb$YzU_(dz7y_L|=Nk9_CubhdruPI!N(3 zO2m5XQ0>!^nzTBqxX)2eWDu%^DhxtlB(er;r@%NOEzgPTYCH5S}ubQuXQ~aO1l}h@_ z(mzZ8b&6lQP$&Eqe^&Xrm-6*FyXz#S-oNMRrP8YvAFj{zQR!Fu{nsi!O8IiP;_daj zKUVy^RjLDuH;QqfTk*NlLp{Du>3ON%j~%JHqxcj0olS~QTBOsAiZ?1B{!8)0%7-fz z|IJ@yx14=P`Sf1Be@K;Np7i{-OSgLJ{jK||4k-STD(9Vw|4W&=Uh%I_)iWvnsATt0 z{P#-yn-w1={r4$8TIK#H#c!AV%N2k7m{REm#hVp>PVr*p*OwH3QDEsF1c ze5oWArAH~hzo7W^eM%)2O{sT*+KA$_^!ZJSpQU=CtS&88zAB4K+v_=wRZN9Y7L@K# zzPwEF?awTgUZZ$lJ;Ys#Pu`_eQdKK`Wl!a?;@9cNey#ZEE-{2CChQ=r6pMqhu=E_| z_s4% z|5wv4?Wan5g5nMO5j|?@k5AQW#cxo3d6nXSd5+3V@vl`6{!Z~fO8BdaU$5s}r1%%g zr?V9Aq;h$l;=6a&DPYAf)Av5Ecn9UDezNpg<%hDkw8M#|($^IK=($Rh;-@PgzOT5h z^82CUH>tc!O8@!#|EKkmn+&=Xe_7@Cu;T5cyjOAeQn7U?-tVMR>FbJryhKbYiZ9Xg z=qF0=++BI3_{1G0qxd6xDen~jLYeXr#S8VY`pMF1FA}?les6C*zaF9VL6wKHptPs* zac6zLLizAYy+2-=f3@N(4igmbr+U<<_*=`wq@nnM`PnU{|Nca=edzryQvM%`|LGZe z7R66FMr~HHk{9}jFDsG%rq@S4UyL1!->=_$w0`fO4ixK%-ap}F)kVb{cNL?G;*qDQ zuTgx|i`BnK?g!6OS?K+plKZyeeNI!GSA3d;&r|%F!%L+PDE@%b{ZYlI>;FGj{B(VP z2YvrwJ>-bqU!Z)@ze2IavGR2$q+}~3CzD25wif?~`Zjn{|R+aBR zE57_u`i|o6ow6I!p00NAOTAyI#O@+}*DBss@hwX4V-@eG-+#LPf8D`)CdIE-`%o5_ zPLq;;#fKf6<;hjq-m~@k2`21Bx#=Lw%^?cdt^LQ#^k~sq_xTuh8fJt@yP{%vFk?eQ3tK z1Jh1T@Bdbr_VF+Lq!cs2;sS@q6^UzfrtK z3ENK3e~HTT4|;!$GT~gst6r!+Tk+`!st-}TPUZ9=#cxr5?J0TvTuE76dRUE1MO6Bg z%HunV33r{bY+nCpPgQq&H(%&I=l?gwA@w=`zwGY!$Ek+BLDlOE<*Y{8-{CbH@m2NI z=$gV$)tkIhpQuug!`>5LAP^UUO-|26@wNXf^*8LhCQsUVePb@R{}b~ZCg(q&>b3tZ z`@ZGXRNuA#n~uMV>EmEpYH3zXTJ!oR7V9I5!Y_?~!O z#69}oU3$HA^O|(=Kf{fBf2r^!eWt-VtWsGed|ddX@G0S1 z;nTurg#RmCCtNQ)X}-QA93XTF2MP;>g9K(I2MbRTo+>O94iVtpdAe|kzW+7--Yvqv z311h!A>1n5Cj7g=%;1~Cw}fvCjG)Y#n91C(?{nq&t-=q5KMVAGmnnX`@D2eh!Fz=F z3hxuH5Uv#7FML4wkZ_gokHS9*|15k&xLJA@2$u*N*h`n|GffP_OiL4!u(D+~^bCPn znI;`!w!c*IN`ZW4cBIKx$aiMe#|o6)@dD*`f^ee1Y~mx8!mZxt>T zE)(7+TrON8Fw1(U@Gjxq!h3}G3hxu%E?^D0Qt@HJ+w}VVia#KHQ23DW5#b+%e-fB^ zeN?zw_?Yl<;q}5Ngii|B2%i$J6+SI|M)<7oFT%eHHws@69u)o{JW;>LEQ}Q}vsG5q z%vM>UKVD#*{0m`kVL*6-u%GZpedkGv_ZQ$ATp%1MbO~5Z4i=swyhT_c*>@>^s=&(e z5aAiZp~4b@mH#Tq9HIDG!sqn*NX5?)juMU*juB|PCkW3I{z^DSI8``9c)sug;r|F{ z3NIGAg_j9`BdiwA64nS6p-1Qys=`{~<-(xw3Sn5N3nRksg;8OHu#s44J6rK9g>!^g z3Fist3l|7~FI*_RPI#m6CgDcmVtub$I8a!j_sfM7g@^S1D*`iSX1$*f-YWc3_?qx! zef}NA-xbc%>m|aadi|fmLcP96I7IlV@UQyp7U3rXe4XDH{#tmh{&%KuwD8x$F~ZmN z`R^3pr1&7kcPZXYF)NFw>vdT;S+BpR_-}>HdVR1^)9Y2jzX<=R_y3^yAmJh5OM1_W z_7ugBpRc+ioTm2=2)`AU3a{4xzMy!q;+G1VYL#}D+{OHV<&tc2Hs}90!O~{V|F5>O z-nD+J^-ZGx-!oL_o+%tE*xBPLmCyPA)d$P#tMbm(cF1r>T-Cg(G3Wm`Ir-$oyKdPg z)13d`RMef5<(?c`=luV&COPN-H&kC#c~*BZTkdoIfA!#xzI@LAZ_fX3xL)n47TLPy z{Qp|ar{?_sn&+95js4BuN^|~y={Yy&|F^}0X0nP#cFpWI|a;p>CS#%n{)P4e$6@i%{lw+p?Waq>^JA^$JXSWv)`Pv-~Orxt(^VlocxM) z@|%~xbMlGGd_u~dlO~&T=cLJY^3KVr?wqnT6n*EE=`H%sDbri@ol~Ya<<2RSZTHTp z$7(`+!K36)QO@d<{k=o)->yw*{9t^*|8J8%INibC6Tea*E*kiqOjl?AyQCdm*X3fb zpXV?+|M^s}{cqX#Ew85fuKnM1;J=gq%--kYe7@VWnOy$8eV&i=dMqt@Io|u{vS-c9 z+vg@fSvvB+&3C*$|9YbI*k@D8O_T3sv^L`17 zjZy@h>* zeTDsmCki(!U8f1&_m6tEllt5<6hB{hf$&1%MZ$}PmkEC(tQP2!*9aA%E{q5p1?t|} z!ruzCnO6zt3g-yt2^R_%39l92AY3Kh|@*4Z`Pzn}jb4UlzV9d{4MtxI?&8 z!1s@`{l0Lw@B`sq;fKP12tN}3Q^5D{$HGs9p9wz~ej)ryxKFrW_%Gqt!f%8Jgx?DP zE&N{CO?mPs#pe6>uwIw+*?eI;VS8Z*VMk#X;n4yHoqdFT1$_UWtazdDG~t=TA_1S) zWx`6~FyYz4bA@AtOB{S#yH@WZM zsCZ<%mo8qql-rmFMhA6=V!~x%8`~ghEROJSq>W!~hk8%sfe;6ZV`k!0=1p8l#XZiZ z&OMGa*DD>M;q%;2x@dE_(t`b|DaW=bij``chY5!ZxnpFJca$^#o!}i8zj0?6rTfno zOILZY1y|MN*)dYrQMz&BkqJ)Kb>tQRQHNHCq1CJQq*avSD!zzI%fl_GRi>R)jha&* zs0iHo!TLGv)}$dZrnq;w2D4JZg)9B)K ziJ2p=nRdEkX;wrMR5U?vp!MtQRl&t)a&}R3(buwstgyQXprNjbsc*2iujoEqwS;>& z>O*px#XJ8^?#c2z?sW;0=uN2U~C9o6PLauH+bO@^yQ*T2}C ztR3ysb-+bmgAS~15!n-A|#u(n9>3ZR-CU0uejeI@2N<5)Ni>pV29ctu_k*!`X z{NCusg~Z`%^u$~0+i3taQfKkxjTpYD2aD+FC|~;+v)JNvaorjV_s^#CLbXE*6`|nvPh3 zNO(Lw1GVsHZ$u<(K!-~cw*OYVQ5S5MkYH& zD5?rw`82I<>&Z9p8dkPt#b->m$&;YBxITS+9UX35AHUI~FavogZDm@*L$$Mnh#gG5 zXMIo4dJVyyQ9rVwHrnF0j%jaQX)ZgsX4&G-Bv>uB+^@UzI-^}9wN_WPqBC1LGSpw* zT(4>0w*%v6=z&uW3+>cFRwdY5WG^Z>ztLRZG*I;F*cy%Qpvk)Slu@I&u140KHN`La z<3nu>)0o7?MVqBOG+bZTfo`C$mb}y|un-EjM#Tb%J~Js+;C8aVsd$TTW?G>a-ptf` zd#Y);E!Rl}N279SF#p{;RSBzGNH@7Im^qE=n0#E(pP~nr`STEL(40K}sq9W|= zTceeIT0R%oJp20w#J*T`(J};@A4exvPBPl-f=xN&q-9q-?O!F)u((Qn2W+izg3yVK z(Tr)ZIpdG*w`VeIv#NB)?Su-_TNxZFdOj8w*#nbY zf84alD6W%{--7(1)o zr|RTwuKg)v;N+_f_w)^x`-`rrjS5w8P0b2+Fe$+W=KZG1PzRQ!szvn;EiU|?c3Wl| zCu8;5wZRVf)kyikKqvGzb;_yZbUR&~Qm!mzTeSEZIZ)~A%>1yw+G2q??b>0}!-ioh zSfg9rlsxUv^Ni@mz~N7eO?92<(ipdaW-8k34E=d&kYI8J|x z7uMK=MX!ruMp4Kk^%N(e;&O^Hpz!C>Bub`&VY$#GwC-ulL}aun*Ebj6;rU~31*cqD zV#A9LLSv;Vu)chmAl6O_u(=G8^pP?SqOiT8hXakRYNPUVsEx%?Pv#alcmLPi{a@I~r*p-QIW+_e_1yhmMcz;}cmLPi{a>Ra)zxsb$xmgt z+Fu^&s|~J>yVR91AcWaOc1_yh<-_wI9kHys#Ya6$^B8(mi+oSNbhh+AOJ-2gYw^>K!i2hr|dB8Z~*v;$`KTRjSFRZ`=(9OI72Sr_)5G zWt@hO*TPI|)KrP?saAAIXLxlPub39LiKP0wMcV7Dy)%I;h^33OZgV<06dFcTD`_tN zPG{HL{a<9G+e|y*;kGx^KTke1OE4Q6-&)CBc zpYTBGS7Sf<#m64r@y{E_?1HY_VIeMEcv7i!tKwr%$oRLf-bdWddjHTa;)YiI=*Co|$pX?{j9xLA`e0QVHJu&mB=J{e$8?mSnue9}|%`eAc%glJRa||GbPV z`(Jk|l@8G7|MX;WLo0sK;ic0172mW#+|h~;URf%=Tk%_u&G@#D-7n+&{^=7k?(e=6 zGw$+Dj}Ho z2s0?L@*$#!>_%b*K6KGCEc0%eY3f)im1brmT2ZO>`OnOj#S)buK(4L7x z_yn}QpusO;TFV9xhFdE9#=ibViZ&}0Ezr#UyoS0BXC4vRRQWyhTjmVE(aC4?0-$Bq zWB4LeyYFwHx63!tSd5pFW#*qxUw5BAotAli%%SU>^CF-N-OQUfuhXpKZSpzJ^CWp2 zzq?%~pK6k)Y0Y52-%p=+|Cm8Hj?A({be8-6YjpO>-b2TD?wmuD0aupYrVh`!&xWtW z1a%I-h?zdWU*&z;H+W+d+-LugSGCHriFA_B=S3Qyoswn;J#T#^*&g*@PvccPBAg@A zD^=kCTY>OUsk8vj9e?CC&K=7y#Kx%Wky;8Mo}! zx2ov6B96IA$LH3`J#mqH!0h$|I&=zXyr$zu_NpCAy;r%Fz=Q=!F7$ zqYwI`68+F0127PSFc?E{6^3FMhNBAMMYP?OYB#+I1H}tz_(MHP!z-#C9ufD%V+c>G zYv^biUR&XvRqrdMExf=6;Rfv19^O;?#o?!QCR*SjT(0dIIvsn(J1`m-V;k;6_*lhW zF1)Pnl~1BG==TV(s*beYbBngZ1YD1)_z6EEytjU!vA+-htIl*5?EqWFdcUmcv;wx~ z_5NqEuMZ!vE(l+(`{iF_t#~*M->hXc*1(hEZ_ozg0PjmuJ;hTR@+3xD8!TH=v975=_J!@^*A9F2qi}qiqFtU?;X< z6ng2aMsJKlAFR^;GhIwu(^}esUWfML@fa-rf`<26jkqmt6&LU}UX{N@TjKyek~gJ8 zY0DF`>?{nI@56pnYJU*vl`8OWuD}R?w^w5%(koRURUlO$RUlO$RUlO$RUlO$RUlO$ mRUlO$RUlO$RUlO$RUlO$RUlO$RUlO$RUlO$Rp7r}fjy;G literal 0 HcmV?d00001 diff --git a/vendor/flac/lib/flac.lib b/vendor/flac/lib/flac.lib new file mode 100644 index 0000000000000000000000000000000000000000..c3d658aaa60a7e4226edfd69c31f9f7adb395717 GIT binary patch literal 2265364 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Œ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≻JvR9TT(${+n}@ zv*t4vVFaz?8ZC>GuJ;&=FoM+m3qpmhqY zJP$EloMmM!!U$Sl5=)(jVM@C47>h81)>j%W&RWe_gb}p9)@VsjO@mo?g0ToAXr0z* zaaPqJl|8?aWD28(i72O*8LEKpVAZj zqSkq^a;-zHEBEKD#_fotBaD!)?-Ujy7B>H)rAx^}D`OExD6j7o7Utp3zYI+|E03`V zBWV3VtRVb^ztdf6)!?i}j71nh>jJUle*OjBqO+W}hp`AFXyJ^4kFk%%|5(CVzc3bI z1g)P0t-a?;<2b8PdkBPsFoM?4U^VFFu}$$WA7paYV8$YhpmmX0a=O|rxpRuMvKWgn zg4Qp@>WH84x4TuJW}LNvu?Qn*{VHe$w?1j%tX+&n7(we2v4Zdu{tk>7Sc|iMWGuo6 zTE7uXPS=|G_A#7QuLA_aK^Q^ncd+t0Uu9UG+<2uP4qz<82wHzAEQ}%6L(Uq*ScDO@ zE)y#VKjH6{e~mLa>p8|EjG%ReSaQ0s9&*+Pj71nh>ngG2dCKD0f=tf(gRuxBX#FW@ ztv(UHle1c5;ln`~LF+HDiuI7QVi}7tg4W-}lGD{FW^y5CO=2v<2wK;OCD+4R3*OJ; ztXCL|FoM=~LF>ZiKhint1Y;3K(7HjaApC^C?bF6T##x3=V1k1%g4Rv2^8RqezW$>) zE0nPaBWT?s7M2$t6C&ep+LU_eVJyN3TDJkqwSrbXzLm3{U@XE2TK^CW2c4L%7jiaF z<*ZGNMHoTrUqLIqt1X(djx!cv1g$&7QtDw+*LOMVAI2h#pmkT!YVG|?m9CDRArKD2 z2wFNl=7xVQ2V)UN(9#o2u7_!&icNTN4j~I(E zf>z}KT9+7$FoISULF@kWnO3gVxQmpBgb}o=5=*|O9E|;h817QPiI)_Km_$ykIDv}zDbUFSLL0%H+I(5fkD zVV&o!`dy_wB#fX{OGy{DufoYwchx!U$UJ z18ALNEW!v{9R#hg;ma3tEqpf(55fpq9f>8^dF$qpbvY}Hu?Qn*brQ6WEITlivqmx& zVFaztO1dyESmzx|ouA2Agb}p52wGU@IqP-CB8;Hbm00RJ&skqF7GVUfZh{updCsbG zKgJq>}b1`R)V=Tf5T6kAp$_>=Q^{AeT)?CIS zjG)zDVd2%`;ihl*<*Y4?MHoSA0I{m05FEIsC%r|B-;OaBVFaxQ1T9>j=d5dtMHoSA zAhG1OyyS~dr*T%Z5LATqLBt4Jg9NRy#}6;&tbvS07(r_=vE;gux9nUIXN_ho!U$SJ z1g&Sf4ETz(W-=CG1g%Jgg(;XaV8y0HrM%WN7GVS}qr$@S($`y1!db@|i!g$gNnxSZ zw--MgBfW)<-|jLNVFWF+!a}Wy3HRO4Sp!0m3%i0NM$ob-EDXnV4O7xp%vgjGw5$pX zwPG5LyUSUd8H+H2mQ7*FT6v1r1;!$bpcSRCP%E|5kr|xTC=5Np+pUNZw4#YsPYTw3 zb>ingQWPx{V-ZHsvI|-bpUQrlvvL`WFoISLvE(}c$xpu*a@JzTB8;FFD`@Q*^h81R-B-f_{}RlIICrEDU%2zXvGst-ERy~@-T|A2qS1Y z1+ALz9@xlPQyGgef|g5RVQjEJd|A=j&RB#Iv>sGgST`)U=RCk!2N{bnf>r{tnn}sl z*-mVFwNTMI≻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

RzCg>6uVyXcSsgtRMx)Cl3QBZ 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

b44ITIrL$ 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

xMs3Ee;RCX0@F|0>vRElm2jaCtgekzu5 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

    &AWm$-u2G zG}SM+xbmCv^x*ydqZ^Khi2wQDlDai*9N{l!bdNn}{?#pbOTxe7tIRlcuD3(eD{e$1<7+t&jbLy3GzPxO8@azN|a$hdY8$ z-;4Ab=PsVr^Q*3VrqmhIH)BxD-sQ>O2Znd)<)l0_ZREfqr7-3uGrC=kPu6(&WyNW| zN+j;Red|TP?9Kfv?z_=Fd3)9NKlwKO>^|%lMptWNu{BFegnjXm`<|=Mo3`v!{_B$G zcRPkuo<2uqYnFg>x}FEbvAFCS*EVroIk3B)pA<`x^s-~{I^DrquZBn8JBrx?8gsmtM*>_ zb1`FZXO|s=stgMF;JmXSeCW;U@a`Y|&Gb4?PJC{Ed*iC_mv_9A5>vgkG6mxmqkDY#fpPGR z?w^l5Rs5eS2~QvGObvMU&r#d@&Ff`n-l#m`U#!11C%q>}jXBa~j7!CK84ne|wq7>; z#Lcroe?DmEl3HKwpYp61`c!{Lw{l9_>D0;RavSX)o?2IL+xAmiAI0A{nqCpURm{EL zbi!sqSjy-Q4t4tb@!a{hAKyMPCZu<#)>l>c4)oq!xmi#``N|bHERVoCE2E1#JTXJ~ z!PBkbI{hcA@sam_Iy-Rx$U0~AuAP@{2nwM641TbkT$Ga!c^jJjIPCKsX?1GaXB{7^ zZoTaI^;dnyDnh>>GO(lP1=!h)?)O~JYX@g8+N&Sl?D7Zh#x;My4`b)jMt3cBPQA|6 zLXX3KVRX4OhYsJ>|F0>TSH{`4uQ?#FN3GxERyju6*4$cRf3Y9zFrHR}t?i<`T;`D5 zzy?!ey9CCUsrB{vHMKrHlyg01{&sJ>=8@kXE;$YUY(^JYeA$KV52{sKQL4OuTARuX zr++jmJ0+mXN5d!nX6tjQ!!r0m7~Qj^5z|Xl{VcBI$qj#OD1E5o_eYZ3mG>$h_|?L5 zkE=%9dWGGAElKa5hN{}@E{yUjJGbKt=ca#tU9I@!r@tR((C)L8nJ8H-nn+OJkD!MPyR{!^IV&D zZW$|dQr!>)D?^H#%$ZfxY%K4`H2{ z(Jgs7qr%xbzL)%;)L7ZEn%(oJ_KhoUTRt)%_Ls}Ln}3h^Nf7>IbX%4cKh&v#uT85a zx?lYFp8E7&?6sxid{iN;qk~*(53PI`dRvp;{fi>{?D3AOC>$6tH=$)@H(k;S5==qoGi!3iXE+I602=;bHhQ>z6 zjIbcpdY>o?kBlJ;N^@^Spm8cJmpjJnN z8T6KF!Fu_QDgaizbNuk&f`=1@mlB|?>(=CZIoEZO~ z&2vHldA44w>i;WRhW}Tz6rkiCJ1B;1%lFrJlmj7&hQx3Sqt-hLLWTxKL>FBSMx_|q zl={X|=^gVG86BoiG(cL>vxXZ_(S=aiM#jfc`HCn^ywnpD!sGDvXG@p*J607&IzxO6 z<;>GMSwo+IiDn&HgYd#^s|iD$StnNz6lxd|S5#@R!KfJxR_YS4kE~hsh6H`Mfefxe zqP1OATPcsg5E2}2$@+Mg&TGCDBEqdS3Co+uWGi&zuBaOC^ zFpR9=)1W7$!ej9SoE0h_B^;WpPaM&>sO7_z!*24{YDOBslF2qLddAS>bItatgz@L+@gv)!9=emcTjSY6}mrci~q(# zLudgWR_hH>Bjs8O-)5$EVvQDxTdg&2+u`IID{4Qa{%x%cCF2!D!>lvq!3bp~M?`dd zxHTpNSSODOO|i}tlMLmenr-5+$+sX_qZ5SF6tjqe#7vP(Goq;8ADQ25m^E^TVU0Um z6D$As&8H7#J36`5pa;xC=;$o~Y-NbOOPh_u3w9c5vjVNo>m)JKkS15W%z(=q3;_5sX_U=OgvwhiO?rn<&I73yaw1c*17-7?q)@F%wi1v zLzF&-oP0&SXkvq5-ZRr2TaK(E4)UkHJ+mjhlNmNcQKpMTdC{ApHuWYMxRg8$0o%m#K*)B zvcgU`amE*BjWUX|U@wNoL=UpUlFi_Flr|dAE?T_8-|>QpF!#;(H_T%3R3E$NL?*_^ z;&GlLHmF!*Ly}^xHP*-S4pPK?!2rOmEKzTT;l*nA=vXQm%!i^E&1An>?IL0~Y-=o$ z=bhkLSzghr4LyP$VlKKMJd|T7x<4W|m_HtBAwSl;_e-;23tHY~{1Gp7R3XN)|H5M zsj4v%5xk$w*xl7W$ha@i80>1RHg0=-QkNd#>Y_I8QL8lD0+hM_8Re>IGXh*~b;b*7 zW479To7#P^N}HuN=D6<(P~K6yA5BUX@>#&rU-LpS{LxL~qy_cLw<6 zrZn}rVccunsq)+Ja{zFF&z)h#e^-F_MirlPglGF)17br+37>PmsyVyTb}0iV-BL}O zOBFQfRZ?a3rVqfO$tVv1K`9Dev6H|_k0`mq8OGYc zUZsNksd{CqdcDH$y&zS+9Xz|nUH3GqdYSiBeRkecs|I9VBg%WK0Xy%h`exo&tDJ3J z!NBuw-1!z-v^|JXl1j!MZzZ)S(la20j^G(wCw}cA?g9@{_5b60sXV5q1M9iZ!65kub#yg;1_Ra z0`>!9JoP8UqFCy0QtCb_^$21^Sn4S$^}3XL7qK{&`dCV}M>pbF}z^}c`-<_ucX*+DfU2$*@Bt|hhj?fK%pIm2J_Jj7~Xd!yaIJwDJ7LwT0%mY zfsWm3u?fjZ`j9ZaAt@vQZ>_*XSMiDXDoAVR)H3uL3#{yf;^P}?=k~}TKL+BHDRiz7 z1~OnfK6bJUpJQpwzPG_yLSpoBjIFH5Bnb579<_5U#Nd4}I9}M)1dDGm(vqk*L`Nit z#)M#pnjr);?+`<1Y(k8lv2>O+yD`n(aqh-MI4WxkhcPAwIMYS{ftUlll`9_Kk_y4B zAwDt0gUN^iPX^aeuX-1(P$=O^-=Kg@St7QLGe z;LP@=Bc#%824jEfp9nF^ zr#?f7@jSH>N>UYJAB5EqPDWTA;aY^ynR*tX3qrb{>mkIu`|vq$=w`nZa}Z)BY^WG> z5XMN@cnPC2ab9XY&bvXv$Qt0--x791!X8W5GYNA?8MwTLV$4DCk+3!r)=9#;Nmz)4 zg-e)G!lp^smlF21gzb{By%P4Xgx#003aB%lzbazPL1-pnJ`zSFFsJJvVcR5(K1;*v z<*~lQKsrHIL7wy?Cyg`a76(;bpb%+eX+0xgWZr z)EN(IjeF8wyiiTW+pWOa;khQftj>5>qdcs0zo&ISq;Wq4iXi1(ol0|0YdoIz;^o+J zx^REcIcklWn(%J98uu(+Mpa*(`{^L%sS%~L?m0Ns2DzWoDNlo!F})hwNfWLF^#kzc z>Xcygf3D5CV55QMsZs9M7*A>4PXlj7Aacs`1R!D7vH0lrMES_0_?G_0U1?_?M{Yak_Mzs@evi7L5mCuDgPK z{1Zwc(9L)Um>XeFO<4T^2G;k?)Q*2fpjy>7Gr*Xc&ND)^4AvUYBW1^{9RbE`YM+~` z&&EPwfJnu=2V}cwckO_XSAmlbC)sIzUL*z?XSrUZu0yurBQnOGY9_rJUN*ou8s@#q zZ5u(4|1pAuK^o&OjqwllhubxW{-I=zV-8W=y{GE^=th(%EWns++y;p{bObImmxLB) zvTju5G9V!Bf+8l%bf&4YaQ8=8=qyFtc(NNi;iE0d_|wHuOhZd4+{rjwF^o_{emfO{ai zgDs3-9mLY0nAApN3~=?<`s^??Rc}Uj7j(vJ1q*l1E1Zh3Cv7w9KLQE2=MsHIiMY<+ zM97Jn-R5eImzn+CFPmiK&lasoUAk0-%XS52zf!bV{qG%0@FY$j1|6Ym`%!H*TE2KrN zh3GO&)L3T0nJwgoOcY%zPO$twByIFnOW48OHl&;GEc}zHR1cZz2D^sW!B*ukyy*8Y z`tZAj@>h_g8E8Kh%@&wgX6)ub9Nif)vw_$chV8}~yJiGeh_t~+3f0a%pqTEe`0R-y z6z+_n!YJ55jf7-H9Z`-#xWLklLU)+uRKvSrfN^ZDg0KxjeW945z9>&2tY-8V6!?0# z@CnkdA-x6C^B12_19Zs2R?2`-M^OnyN@8(l8i#mod<;P8%M%{LgN2U$&>WxZvv zR8tp~HHFQ>RTRKQan@pOl@|P*T_Ji36YpS~UzMj>6_t_fMVblX^9nY9!;&6^((FPb zP@P3V?VEZHsiE8PJjR==bdX9E&5A%1hCVE9mrefqpzmI)ov9xeMs{6kwy` zzR*{g1}$|MZtAHQm5#z)1@+RNHqo-Hl=9;N9R{YS`fK&x*jyY^MU%8ajI^RM1GQLB z5yfgH4s||*)k+jTJZ_J=^rQE43o{t4@P_QuWX{i71DXkpPW1-5#!QC>@+Y%PxCOq4 zT$=TD4fJL*Y&pIb-a<&l7wBi;OPM6s8#0G8xs~1^*He;vGLKv;C&?{?0Tr*;M^`Q( zv=L?c0-?D9J}+dOzkf8smmBz`|01KtvQ#|59fh&Q{Io43sGVsVhv^&+C9BE~=7NEC0cf~~LlF2}nyv^M z>oV2)z+bL`aP`2_asuElfs8jWPuxMqJ?&ge?)KBg{ZZ=`<0ebhL73=_E2c!c0h-HvcE!Vi$| zB?xs0mm(w^05aJ$w=wd@r@0h!5JuydW2s`yfsH~On=WC0NOVUej3%<2?q3O`i7dx3 z@nzCuY?Vdu+b8hDq#yG zY>|YmmasJvc2L5ON?7mWru+qqF$YZh3gH&v{t);@F!y1Ok@s_o7`J&I)}(iL^)NoA z0IreliUZFZ7u z#3-RNmem@wEc!{v%F`Ij2FZLR-QdzN9nnh?1TP19 zNi^&AMd0nTxD0)PS<_uA_M`sZ_ji~&_3WOqfVErJUq#M2Y2 zY0MF_u?($aSXj!-lq~p6XcUAk%ErPXtdW#Zyik-8YGaBu3{H@v_^%5`NX(lZA(T&U znd@wlFde9)m?xCBsm|$H;TE1{u0!(wiM4ZcG%J)cI#RX2-}pmMODiB$EUQ^OY$=uy9H! zZm~Yz>KOTnWk>E9`Ho?7$B3F?*@|FfbTAwv&Tx#xDeAJBNDgZ350)->jBxA=$uUwQ zk7HyZqd%i4CUg-d!@Y17juD>%9V2^LaaDzJjO=7Jb%He~IYu%W>lS4VVZCq$OAh>emDIRoB&+n31 z4c7*_WPU{Gg>XH>OoST{lC$C`gyf*uh>%MBGeWAFO$cWqq;$HCQaW8slumarN{1Uo z*oyF5gxLu9Al!lQ973#^r_$tPH$rk8>_=(cbC(Ro9GKUWW0S>H2Vtf}H(SDvN!Td~yDMQ2C5)~$F3(PkIS9cLHc-OI z1;^?g36m z>l_>lm#{$+_JxGaldwz)+b&@TCG4n#q2r4>Y{i&^;4WbeCCp#K+DTZ5goR6(LBfVf zSek@Qk+82N>>CNolCT{Tc1OYIVg#9aFN;^}Yi;FP_p@M`}k+3!r<}YD`By5O;jgqi&5@wXJ zX%hCGgpm`6*VXS5mMvj_NEkVGINf6jdnRFy#Z2W;i7^M^Lkasx!U82sD`9#GiV-FpywkC zd!qx5FX5k28*i(PkJQF_w2J@!4f4NpXf|-GDD> zmkzt6{WU)KHAcX@Ky^Ul^9LusHq2g)`wO;4*V6c$=c(BmY@r5>fl9dH2w1I}vs0b6 zlkb`S5@-@k%(Qq zDl~7biZ|@lR%8Etp*Cx;KwE|3-CH z7Ms!Z!g*sx+Yhsu+AM3`VIvM?SZ%g(GLFGJ}vmXnZAJ*CqdMsso7}Dvkm-flt=TX1`nJ62fMs6yJ5%o@D$Q6 z@5A}d@8&yqV%1{a72YtIcYp7lbs`>W1($gy`F;n7CQH~#iH=Igd4G|xEfRK9!pJeo>7Gj%9BCrvA;uhqCKBc=VWjrm);T< zAz@JxHcP_hO4w2fqj8_-WuJr{l(4fBc0s~yQI}jVJ!r#u%Sl*832P}~z7nRBu+9<| zBVh>=mMUQrCG44m(YVj`I->n}UQ}YtL8u~OH6)CtY@Cj!Y@F9e!srgcvF;MqTf*?5 zpLc-qbdd3oCLC*gy8|a>swUDBGTFXt=eCDB?V3V0@h(_+tS&OhW3;V9otCRes;k~a zSDhtuNCO+!SA#9V9(aPvJKOVc03O7fbVfCm%s6%0Gh5Y!8HlB|!jE91`fMTsZTMbo zM&IY!j1hM<8C8v%SG%SP`R>%$4xKQYCapC6u>V z2`G)M3dGVs&7opmqk`{2!PyxV8j*22M^@+^rb4&FGA9b1o43%^Fvz6QQSIKrmdZ-S zbMKa`R(7-XPw!qCRgNOUg3nh(<7w91w8;e}v{6lRe4m%V~L9xP;ax zSCv+uXs}qC_RL8&fwugEL6dgzj@JDNp2v&#wN1;$6M5U5=tN^5l;P`(l4P=CQ8HpE z7sZa^cbv`}E&q}pON`f?l!y*WM1OH2B#A_*B~%dcUyz6%a3Um$M7a{t9gzr%ay34O zRG;-mr%@aCre0K~KCwv*yP-tBb>Z3Cj4rwN{ZwOZC$!HfHv#pI6=U?@`>L_Q*j}G@ z`6cz=v0d%cve8M$`q^qSy4sUEG&O57ZCWNJWaIxdsf<(|FIgeTCwug64XTHF>r_0G zk-y>4Tg^}7qQBxH+-|6{ezwZp?uXEN&(V5idFx$#t@TV-EBP^b^U>ZebKgYgl3k!B zaDl4Qe&y6oiKDf+JaO@9(k|aYds6eE6W+uX%9{^Y=p7)=xIlebbs}{$b;#yxaLO*s zeMr|LHm-YfR0Qw0XMuIO!06D5M2FN18eF%F%+>C#4abuqr)hvd)natOATk40R|49p z8r5`Rpnjj`peNa&E_IH%bm^ZpT?J}99f2!An^7(umpv}|04z5-xVL|}iJS;du?fOE@7L<9LVvaCIIbS$u8_U)thDc)X z+Ny+=LXL1n*rHgeNKv-JqL=CEQ1jkNvIqFl!|o%&-Hx6hO@gb){5YtXTN4?4MaT** zZ8$J!fL$+SrIw;j;qh@XHhN!10rG?hBS z8HDW+;?|!!1R-X{sR;;gA>4xSHbPo%pmSe@bUqv*(P0;JI zA|x9WCIGWRvG&4jP^`u<8?+QcvO(#bY*0EU8eSL0_O;WP{Q<*`RbzHfU4)a~qUm4tPY?gpuXVG1^1M=~5+Zx`fS=u=Nu5vxH?! z*e(hCTf%NgSOwG_*HJ}`p>IlG{D8(^qM~+2Em~S^&p)R`c!#d+B=KCCg#$oTT;4V&j;R}zo0go7i z7UuS>t=>e736@Py?(uZ#m+eXKT%er*RLf~k;Q=G#UvhXZ#)&3;k2a$Z9G;^tnEfex zbw0a?aevAf(7*{)8v&f29db3{hc#)JUaD$f(|SC)(6mmXQ)6GGD&gcwLNAb~?-V&t z;GRl22QAW=V`-FYJE-Qa`8rt4BPhVblZ8_413M1Y%q^L zYVrc-t&^`&B337~t4perbex#$1lmkKCRQiR2^?KOeek-7FTvfutUksb70dtBTsiQe zq5NXmpT4Q=-cVF^A+Ozl1Y3`_%8hbd1=82^~Co45| zgRfYT;rIT+T*{yfJYAEolv?pn`YnWj0)3>Rhz;m%8xGAfIijjAk!h zz3P-vHCvmOeMj7~qBi>5!-wbu|DnAy(>+J6?2zl9UUIzl6|s!IASX z6kfsOU0F}ZODf{En;4ZWk+nNfXyHaRUmlzju0>oxlt^_cT{}GSn#Lzv^_hXLgzy}# z&mL8V3SL+865@JP8*TTJYf$YTus2upDl6UZIY>t1VW`)~1Get*6!r3nxnAyTIxrL+c{e3Dp8!*T>0i8t=D8I;ArEWlE=1KtI%!NKEA# z{iCT&zHol>GUf9hqkJe9UV78jmP&RTE>2v~bPwh>W=F)hf3rJc+`mb_5bn#Qp^y7F zr(qP$@86^wbzJ!~yFHR&k@a?A2VW7iuwBnKn8WlcHGZ!=QWZ9)CQ zjmx%3lkYT&3AkW;9{0z+ijNhJwsx#W==mBh=d6vR5M-mb>CNOv<&jSgOc%z_f9%b1 z(Shj!B;U4ZZ$QcT&*#AOm0+_2Qv=L`1G6h&I!q2sWH_x<^b_)6x`BvxOVCjs z))e(2tfZ$>OXD?ZsjU&Bzon8l9(!|A!x3V)PAd83>Lbh)&-aVxA3+wSlQl`{6L>9mEH_+k+vEp-t>SA=WCb9xO5otK9NLg^j| z>6}*giLW2R8VJ8Y=z?&Kcz#qoZ-tAA(mNxh^jL(%XFym5Aw7#+6=9}$ep)1rB^IOl0j))A-FFA(UB^3^b;*X7VzHM~t5$Y*q&qVVu`G3ZH+yZ`bw%fCp$jR7T|D-|#h$w=c=Hy8mH95trp zv)zQSJ3>)!j`6bU8=~bTQL0Wt?v^j%Fr8GdZ5&B@BTu@uk z2wef#b`i(EnpA3^RtSqD#H=fovWM#x?k03j6;6CK zGB(3M9~mj;AVf=8tQd0;mP*(P2|FoaXC>^JgwY#BxV*{G#dT1x=GY<$qa9Bid-sut zUJv}gkq5)06-OSjZ37D!c{&zmG=`{L;Bdm!q0wIk)gwyCV5Fw2|bWWoWozv(;=QR4zNXE_Wn(K^cB{p9-8-nHu*$v_@~Zy0jYQA+54&t~R|Z93M_3=9o;3YHCk%2jmeo z5#_^O$k-kxQCE9ScuC49c716z?kBXyCy-=MV)A;2$UG|tF`k&Ai{2&T(<*gY&|ESL z0*HmoB(n!??3lEt_KCwyy9VRoHA87&-j&;fO?Ak-k-Ug@I-etkZm>wy?y3zo>hO;1h?DTBgXBv&WMS=0dx%R2cRqOF8;9(1iRnOPc8tW z85^7Z!_UuN%uN`Kmb@>Zm)mV@^c3g*7RFGr!)Sj5%>v2W-xb|{3I6}VzXxWw1Mp8X zX|tJE(vmqRpZkBWXotCf63o!;umnGZ?PYq60J%a0VH@ninQz&^lmH{JD>LuPVx}s- zYJ)Zxna#ToY`WuWFQ=$0&Gor>M_l=)moD83;2G&O~@e#2+Edz&VY?QxP^pNc61`rX%c(@Kc0(5vQGNlW2eonEyZ-SL_{gj70+Y#h|!%@ zDJU8`2@N5w4y4sAKpH)zVLDndPLjrBB#k;6q_uMr+O5F59p@Gk>VJY4uMD>rszjB* z%kwJ;P6tb8mP~N;03q9-Ng*BN5#o8{F_K1Cm{O=&1>6tH3FZDOFO-V-K(Osz6}XwZ z9O9g(q7)+v&P|n2FHf#5>FEm^=%Jc{9szpjVAY3^dOqiJl47Kj%O~06-y(k?s7XE= zkL2Sp$)-|r*>WvhHpz9P3KkDbd5=UI$>xViE-`UxxdtwmWYYWbOot`8F-Sy92096W zXh|=$7Sf2=6q+>$2QR7x&Uu7%4cx%7y=>9CadiAXfJq)D#49?crK zT#`vIr!XCs6GBuw4_v=vg#=Q2BiE zuVfpOd5mh2a}iYn{!NE3BKhT$wJx?2Iho%{KFOv%1g66mk^J%(FpOQ#?<}8W4@C2t z4qrs_%U{B<_mfYu*&YQ^fhGAXiXfk4(_RMC;fqNA{Qtl()0kmuSL#Nbn%bMksI7Us zl1$tfq=To+c{U&wW5yeLnwq5&2al1KUl~?VPvf*s5*PI}&XvEXS(2a0<XHbSw+HXb;EOVxb%AYB>OrN%_Fx-F7n++r96`z z{ywrvF0G!K4okA1zo%@HODk-q!;)+p=zpJllU!PbGaZ&>+l#U}jj68XZNmAer|@

    aCoEsK}>f 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�ISkww zoIFP4kjVTS-0BF|MUDec052`dYYF)z2+~y!krltad_$!ex*X#!fb~L|Un7(`FKCd5 z`&?P18u9>m7=%1Lfw$DZLo?+lVNE#(tyJ-uFr9+R05*>00jG~jKw5H;8+7x?l!AT2 z&KEYiV6%~V0Hs0B1Bz8!9zei!c7|b=vyZnQS^>ctf)F}#1fGS$T{5C~lhb7)A+35e z0|<*!u(*I75QOdi7c7_U#)Ju5G>C*IL9>SPM(rU7OL|>s3h>y$=asB{VWmcq>dJAj zFpVl&EtD@~$VR;~6(to9FrB;4mS}$G-V>$bo_g z=^)I#vjqMU5k(T{Z#x_YzPLx~3blL#fUue;5OUDlT#{!JKM%tLIK-!+XJ^n|yn2Z! zDu@EPhh}5BL)%Nj!MlM1A*={M$Ba5g1XM>Pn26voVMHS%c0okhpj4Kq1|o7SK$42lcZ$0czg zO+Xtq(CRE=zzVs9A)5@9b6}CYJqR9|qOzheut+Z9fRwmNhYyGjYvfWo>L#8 zJst(G=1VgNvmEmN9pwTs<+XsA?jBrETt8nSPH@~}riaI))A2lmQ=+COO~p2-23Rm4 z@kXO2XC}CVo^VVkM*uVOFzGHCCEvpk9GZ)6n`6bm`Et{eVv-VY5fPgri5#oh6C4{AhD|aGBh3)z@Z!V6r^3;n$>Dgl_cM+X*(4Zdz_uIYK%j{z9{8eQ zP6Dvv2H|Y+;ckQAN#U&c8L^2m%;-rm@llD9Q+=mRnTEDHphX#kgDH$Z;`{}CCJdd> zbUlK>ti~T<&QXccF`-jncLg|E&MbMf}v_!}6qLSv;-q7F9XuO;#b zpTUos87?c24E0-iq$mqZTgYhw?yONbYer~-mbVqTZt7? zvaglJ^W}KCdgJLlA%_XGWvH`72yn|_>yJ>_34x3@?4{I)<6zM~AK{<2`9QBh(?nZ% z5`!nn_U{O0#D;?frQuC0Ku23pz!e{hX=o=6(2&BQ=>@R7lCx{$6F`dKU|9|6vkRI7 z6T(s`^k6hRp#G=vx@2Um14uNofc?OeU~GXLB9}YMHwMhX0f^lzN$-nBz{s5dtHj2+(?YpJWyEQsye0?3WqDu`QJM@$(>VZ! zFX#dCh-(deK*@tJCL#hdCu=iYRUjcKS>%17ddC~Bpg)p&>9FW0z`^@MTxjc~Q1Xb% zCXAXE1F`jm&}avnPk3x}aA*9V%`~#&;fJuo!k_1MF z%0f>kQHeil1gah6Cx8QjH?GNQ3uhf_3q3O+KA5_PMQSfBc&JZ>%9C`eI7PJK2`CT= zRud#wB+BMkZ|H_m6evsK@$t9{5jPH={jk)bCkDdehC~XAMsKKb@X*>D?-~VvfrjVh zWulCh4nTyFLndi#=wbQL)q)A5X`=p426PKgbcP#D-GisWo;``wqe_&i7?co+J?ge0 z#rA$%-h^0caFd{Ifq?0-BM>)9e+d2-Sjg4;haHRHJ<;%nP>2FNdM{8#92^M;78Nj& zFhS+Q_r#h2mH<~1su(}yR-&dxnHCDsVYK+%Y?N^{y@)a{pFhOnn*=~Go&vC$DBNoa z2$mgi>!9+-LBw21%(C;iQ2=alkTFEt;2>VKc80?su@3?o^hDmU>lCKBd;)lAv4`u1 zwpqG+qUlU(b0+?bh$9$i2W_-9BFt@G*qh_*V`GUFnKT(a0k~Ps(_Cx4+0Vr%|>Fa zjT#>%0z!)HJsPl}w#K6sEci$uWUYpbJ@Qh1Zy|Z9k!n>-qCoqAVG>-jQig12EJTF0 z5rNPw8Sa$Oe5SNpLNZY<2`pPYmA4u;6}U1!LNq4uW;X@C8RYpHZxeH0_f(!?J0Yq# zw}0F1Jlfks+jnj8YEF*sJ&H_*7X&cw-_K(&!?=Gxk6jNEW{`EWX4j6H&CqpQ^oeqG z)aI1iukU%@|LDdL4Q8^EzxfT5oCVJyzg+*AGkK{XZ{{847kaT@Kc5x3e0y<2VX)nx z%JNse(%-=;H8{R)^Tc;WSr1w*&Zme5hAX%(P_U;we`Wm?-moudu}(iu5a?|q23ZrQ z@%&4{>bGCs-kvS=_a60({^5%M@m@BbvE6#<9@r8F<)tEA1h!k z4&Dp8JhOj&xG`_@0Z$iXOV(gq)-~G%n?2L>&WQUP(kgDnF-L8__3~H197^!6DM4OV z4FvHN<4(0&HPtLDx)`2f)7afKr}V1z0SiTjBezMkauClT_!eCA0WY*M$kt_XDd#3U znOFXFuEJ=;iELk^Q`5GqMJO1aRJp9QTX6&Qtr*v+b=-Sh^=YL>3$9ha zj9y)3t7sRo^}6~Jf+)wh3Bfgo61o_6i)Z$|?@?KPA!O0MJnohyW{)c18WN1_y1|<9hLLi(e&m~-m$C;vGq~BKzIKmT zZ*lV1r?vSOK(6%a%q z#_hMc6s&x5ITW&S6$pC7wqaPsALxS$>5%mrQdPuM==+~$h~ ziuvXb-MeNTUXd^QS=2a)cK1PQ z#pEj&Y0It=gf(b3gM3!B;KsR$Z80~$e*b0VuMa5!S^! z3qDM3+BDamF5DUA$>pi^T4KKSg$V+bxLLa5(*bkm>&B!^Zdm59HhKPrsY~nMefe5DIjb})jycU^(prM}fN@I_ z9}DIO8`RXxWB__2;95`)Ico{=Kiw_;eqMOQEv@k1G-g%^-SPh3?bANk6T}&eds@)@X20BHms5Am&Un7V z-mOg6MmyLx)3f2ND8aIA!VcJMhh8Ki&oB3&2aP$lbM_ftn`!oW^XMVT_itYPvCsJD zlLrnII{1!B7+2C3U~szhgz;Lkn_BFS8>vL(**6RavXZ%XL)mff*gI7|ed_ zX>=iDv4zH_GeXNpOBYp#yXCRwPkz1n5dZBM4T6ZnxITT8E%oXA^5_fN#e&T}AJ0=u z-TSQJL*LWRc4|v??z(I3aqHWRr}uC< z3+FAsi@*%>`n?xD`<%FLz0JE~&y;JSnrn|geEIMoefq2+NqYxxXf}bXUNA26lJ=We zlND;W+ftXd<*Y~_@A|Rqxb5UOLkCS>bLpg$80;j*T^gIxrunhom{SXR(@q{Gqfgwn zDE9dkJa}*mb!qFjH^bqc4tSNAL7wfZJ!fufX8IR1-p|BbZ@&cI5To@eeZ5LX9P6L` zxoJ0?wu^DU*1TQ(^zinymtR)*-qAJhgn2ThX|}y+tD|v&SK)H~V1lT^xD_ov3wNA* z`qTXJhcgD-DdoENqu=aLPBUZ}4@=4#Shf+S0O4h121!&W9!c9^Z1&{U>E4rHOpdy} zJvL%Uy863sJFdRWTthwqdxdeq<1dBX%%8wKn@rm^$!qij+qJnjZly=ssJ9-`c|UT; zPB`)f<67VDI=y7^DDJEuT0L&^yS=iw|{Il+uT=+XTsevL<`2{4^b1nnyowS zh4uF)CGO?RFGq0puen5i@}V8BoMWW(m*`E=s9 z6SEf7W$l@r9rqn}N)eeDw>IBI|HQKRhCy}*d-ohZ`$NfGo3Ul%12b~o+NLj7zX$qJ zi*c&NspxH#nmeMO3r*J?>1FpVqjKB2!g-uDP7(LZ)qsAGCiI02QbEyr@9LobUczT9 z`=su5IAwgY$Bwt#7hE=c;yq#Z&qYRXUkk>m(_9^okLz2KW#$*PZm9Wvoy#K+Y*Hbg zeBWj_$S;2gwA&GkQ?jp}(59bRI#6l!$)2~Y?_@sFIiKJV^mbv%mAuq~TQ_0y1jb|x za^g~v{@WgVlZsbf8vBbjLs@*|dwuoIq0f&c24DI*e03&xXBhV}KcZMSsdn_VKxzx6 zPH$$)hrlClEw`S%j2pCn?190H;aV(=+jf<9GDCU83Js?5&0UYp7c;!vYWta99(276 z-OwguWC%e#$2fcO-plshYd!|4oVs_FaZ#4q=u>5X3!My~hYm{jr&87Z0hJE}x178=h-IJc-eRWnhHj%(L!T35+}%wdUW3lWxWX?l9-TiJ zm}=d7-mh^5jUk7A)sNA)QrS`XaY{((-7Ap4TNrn1*(LAB11iT(^_cMSoo86Kc5MXF z+ih(_ghhB4!GbYhhm7Gxa|Ri=&3T(*mG9%4fRMFAsxmJw)v8EqOE}NGJb1~fQOVcx z2x2P6t@@GH=E~%KiVCefwrBhDHhXcZk-oFdv&K~=6N#7W?FiyD#{K)fJ^kTTbq0CM zF?#f_mGh1*`S6qzQC;6{O4s*(YERQCw>^JpU5@Du@)wJ73$51<`8D5D5Hsq^^`H5n z4>zTI{5o5GuJ`37Z=22L?1ujB7{)EQ+HkITgy*=&{T$;awV8H}U-UAo)pGuo7dORK z<9m#s29s;>vO9y^#5$lma@3i!N4uTs{f(Qc#a^XMp{>!}4fpF$Q8&5YfI&OP`MOo%yQ+@y=uC0`r(cDN8K%^eMzn! zVl!aon-P;{gg?oDzYJEa;Kh6fsgW0Hq0pAPaAm(^W=VGUHV!blw{WcP<&2PdFW6ZH zJAT5cWEf|cJj<+SXxY0-YeH^5PTf~?!Qk1J9`;GLYi69knRIvAcQ^_Q@d!Hy~B$pk8k4~ zZN%<(mL3y`E2@(p^`PFXtauRqRaN7{_5)T^R@UzN2>RAtAEmp}pr^8{-NoVB9tV_@ zFAhyhtw{CN4)$Hh;_4T`Hy=$Lzy$7?RVo$dFMv1Iz^UYkzuT?$i>;FB}RDLRi2u6}ytgXxdey$e?R z&foQE2F>!9@x`^-CO4XH1l}cxl^B=m7{0z>|NF!R79O{lO8z4$VR=>!%ry~xO})eR zw~hzjC&~XK6`0)j~B%3 zIvF~NNxOGe7+1Ld6O{EK#ziHqQu)|T+~1LL;o+kqII#HW{4HCPhFq!$aoYRh;CE=V zesDAvgDmw?_?+fxFe`QIzyk)%Wi?Nx8@&%H-&+U*ZLgso-PEuqmW%SXT+N@X@bKk|d{&QE}xgOQHOkscT@An4HwEPje@6m+Q zy+q%1Z`;+@pmI1dP`YmysYf@Ce$sdO;?q0M8dyBuuz@J}-yE2aGy`P|{r=+d=GYsY)|8_)k9o1+Kw3VLuD? zZ{L(p9k$t@s&Fjva&(-v;*TTMRm;7Tk6+GuunFD>1Dnqv_g=l^{_L4E5oRzcCF}FB zgvJ}%J}Sp6S&POcY%CZ!3VhDl7?)gRT&1U+va&G4HF(vX>d5cOb9?VB*%#4e;JgA` zLz@ExaTep=vd$C_tx>s45^hBgdv2LVeG@wG)9B{zX6H}D6bPEwu$2^iC(t*$=rnq4dl%tLQ}|hI&5?V1@6ES+M;}kD0Gv&e0g)0J%Z?t6+rKVplCExyAqp;u1Esx>UPK=9V#^w*t&x=)W%xoMSN|@amb3gXr?Jsp( zK6BTtRi2b2V9$k-XKf!;`|g`Hs*=0bY4q~e-20RHaLzBr&3U=qbaX)cfzc!_GUM$5 zt3{^DxsCOe7c&Dib1*&Fjk2_F^|tS@b|Rs{RJ4daw9?ij(-R{C+L$7G^p)c7N2n{H=0 z{D=tkO|%|xb=8}*Fz&{<4Qi)cC+**U*H(3k=wYVg`V;pY&Mv*+XS>FJQo#G3Pr=7= z8G!N^nkas--eAZ`r}Gg_celOiyTB#tqVmt~IXhD$C#t`H^n)OlV%*k8LCaT8!K^;n%3@8OIWm z?=zlkjC))MeYp*c%^2jvBd^Zg98lRM?!DsF`VIB=hSa-iY&%C_L=kc z>-E@W^ElP32Ql(5Rkmag+*?<%^7EBM@yqKbT!MIuapx!fc)x8ix9KM3?&B%B!Z4p6 z_NI?cPn^8*>D%2*e$*xCrw5_@-JxCD zVule!I>x1&@$A#?&l)+q&0*uvE47mbjS;we-(U!C=JyU>b2a)nL0rZ-t$ibn##U39 zw=`TR>gy{aG)i_8S?B7TY(kdbIM^Ix0egf@QM#MEbp3So#njNz%(tsoCKl?%!KE9~ z58q7qWPh5wpdOv}8-#I@M`+>pTDdmyZMpTkYi|0kdv#&Ju^-)U#@;*ePB%ylc5)ZS z{fb~;KT6JS5s#gJVa`{_O{>(6)|_A5b0Uwz-m-TX_Zf^YF;3@3c*$q#2Rp97_w!t> zm1DpAjPJjz(0oxJ7jGu5u=kM~%?nqo-RcYXVU$TsL_ z5jf|Cb%jM*4jxM08wIs(!hg3|4l{Nq5^ef=JO8aBUv=uI=` zxnsufpBX;c7C3nB==kpWg>Y6f#%;0;Og?fvSKa8{$mHmR!pkG#=6j`yN8GZxNngii z#)0pA7~@<{=pEF3Zhlm)f&Fo`n|0PY+LxQ7%K`_c$4;kdeg7qby+LLu-Hp3V^co@# zZR|e!Y3SMuOoJRUV`!V6Vdx5meeV!5Gal?I#?3vw;E~qZlnt4aZ0FV=a0njvx!BR>^nhZ>EjGL4&!)lppg{OqjW>K z>E9B@%(NZYl02DL)OX_0)nhJt++AK&xhk!3{iYjG#}OE}W&LNv9;SC^U%WnL*$0(| z6EkNKM{j$XwIrQBRPs6}2GZP(amox;!JlNL1&b+3P+pW&>t6#!-C=`h=W+)B6ga z#kCFnc#7v>wktMnb^YKUwvCT_9Rh#%EXEZa8g%BH^U@XiJzsyS*!PTiz@|-sA$Y%e z+KC@sUd6rM0QS@hrCT0ncE|4MiQ7Y0P>U?Iy2K49jc>o6VO41`$!>c+=lpz_XT`X~ z4wtS>-MO$~@MOD!kk^Bz8T}lvsiq*YZrbUS_BXH1Jq6cqV;pPplZ&N2u3g@rw*7D$i0{0qhr22FR~Yi@E``|Ctuf2TIH{R4loeziS25Zy~-%kldaQ^3E+xOo+! zs;6dGy_u2np{jo8N8QiI+qg$uA5Xs+&zr7x!dX-Z38>wYa9`Wbs`l)o=l%bxH9PsF}U(_4DyfxoKt(;4Prsta=b*~%Fj zN{>~cf5W(hGQGL)-sL)&6rX-sT6o6L?#+u-+q$1!9bLcP->bA`B0*fiIIEuDEY!9s zMte-i@H?*a>FWvona)f4Yu>uiM)NE@U}%({=FAnp8;`jb~qeh|!eTN=l|yy?`tML(~RTQ@%%CFKDk*txaPp1+>&H_C1s4C23fykX3&%_(6_;>Cy?$b z%RTp2jxVxFD>e8&YXn<)-X%jzzv7RFKaHx0yrO(Rl^{GY?%(fg&c(QkKNRS<#iKYO z)y$B*lS^N+`X4{NOlzRY%By-IMkX5}zPlLraBGhFjjAmt=9bsb8S+s<-+%34rJO(> zf^|qAH7m8nIEck$Zq`H>+#O8$SVy&2|jNZsZ7~yGv3olAI^Wq zxPQMV`XE+KB z=4R$*mcuQ~;X5z^_8^6a1%`y8J&XU@re>0+22PHdk&qY_It8|h{-J9A zH<3xJIUzAVI67+5wEr+R$XZzJf1W9bCIapihlnELW2Oej#{P%dk`{7G;?zXg7Wk*j ztN%Au2DzI$H31qReCmIgFNkS+)U^2UN&k5~()#+(Bf>=sjrmj2{_n1Nhl|mJkD^a5fD%WHDX^8yJEotYSaamqBJR@5nU-uQJO48 zj0L+$OzaxF#%?tB*cE&4C5pzL*jw!NedkVLSr?<({lDLP!*7_GbH6!r%em*AduI0D zxNIXxUUXV|L_&(8)ks{TQ_|Eps*KBxiL#;DV`4`t*lPStB5!6QSlqe&$o>=c$ zdMn;|GMtc#tF(h4qjc z3Ck9z{=ZNc$;Pb02UYNm&g@v1h}cm+>Q)5PoZj=!eVLdQ$h#8by>`adnY+IU4zkB9Avp;m|9 z)Ts5&6(PRw_nJ>5=$Jgg!m@A0!W^ z4?iMEF_asx2lQ*-ugMkofJvGrEm}{@d?h0kEiT5;F&Z)iQBS0A)r%GNugVv5a+A}I zG#H9ah*GC%jNrW`MZl*ryw0hf`llpQT^Yzs(2QxR(aGtM2m`sH8PRbxDQsZtVj#0Z zZz)C{YaCv2m^$rTtyYO<3JQ|BYFDTdCV|EU1n(8R*gC`Ejr#fA{di~pIoQ0>>7t5L`Rbp zofcytH^?+NW#G5!1~L+bCMHw$`LY_%p+W?Re#K~D#!&-oK@p>=`t;0{3`4sLlfxwZ z8aKrVN=x**Xn<{aDN$cZ>ZFu3V?@f5B9bGM)G?_EsYc3Jbb?U|h%Ny$Yq((Xe2nBH zftm3_B&a5gccM|sOhb!FDzn&8$k*5hNEWiyH$$D4-OSKTK}eZ-HA0OQu?f8B8=5<9 zD+7+vso5$+jW#Neeuo;Jgr5%^ffs}=S)HEM#~3ALzwS1Wk?5-?8|=jioPID@iLkjotA+)h@e=ErQxAi)Uo=CZoEuKekNdLyr=a4 z%u~M7>VcCc8a=`Y$_S(HBtt!7p(7Zji=wkq>;vY2`SO(hDrzur^W|2k(tJE+sWC`H)1k&lQwZqNH#*zqbbUz zN9}%%EDL=s%P3<5=1vkP12aXP74x}e89MS23P-`R7(?Rr=Qw{&s|jM1nvzQI=?%@2*iqo&B^kl?z+Wbs z+Zd{fUbH0>5J-ZB+o(ny|)pR z1Ru>X+6Xr-G07OO3j|Ng@Onp&PE3i6QKuP8d1*3@@E(fZ^=M#sijh*|jrI`0>z(w~ zP7*%Wi9p5C^r#WhsTt1E2L1K~%KCqx4)M8{an!XYUY$r$8N+1_(S7E3;VUJh@Dsx6 z{HJ-w`6P(G{fIY8=8`o13=Xf6WJuo~CaU8iqv=(u{;v$syfZk z?}Csi_)&??j8gl_#r=@$E32vS6Dq^SA3x$rz@*JaDIaex4a}41;`5*4x*Et0?UxkY z&j?I}5Vzr+;$c3FP}}0z1#_MYL*Xxv18G|dF(#CX4}9PPGs_WgsO3PHNy2E)z{(ON zAsT*w5QY2lB8tUg)-WY42EMZ~#xGDRM(V?e7#LVR5N-Y!c%T32ml53(MEL&4ac=2- zou0ZeVnNtwg?oaZ=VIyz&YbhJbH{IrU3U89DlD;=!R~-vj=e7SCb}Ys3I+Y!C`%F ze!ItUIdpa(N6h|3Wy*2F@gt6e!LQ@7WBv$sX2o@rXgws_uM%yQM5AY5!MpO`{oHb+ z-TJZatH;Z?EIjnb3Cgrb>xeJ!!*FI<+}b%cCW?FdBr)`F^^`N?opYrXrhF8L>>PMk#IhNYv0b zm~L|>kEB}ez?E^=u2o90!2Yv!d@OPxD9`x}Wfb#VL=I=Q?j{2)Uem@OwEI(;Cbt6s?@4pWjK) zrvelI3!(V(>*IG5{8j=pVIhwzhl9TSVI~jmyG1-k{I8GSZ6wA3=eL+gkxc31_X70M zzzkZ#<4A|-i(f{tdE4 z>Iz$N?cs|2)dMDSHIFNegTC^X0{wx2;gR~wdkKkefIGK_M-^9pc1X5gi|OUD(}ry5 ztv{-cM!;MUaK-T>%~O6I{%LLc+Jo}v0NgVHTO7Y?$WW8@92c;GXK0FpK7JdK5Cu%7 zO*{^>JnF5#>Y#gV#sVtXX)CV0F-S-O=JXaGS6u&S23)7Dm@a4=kE8PI%U@k2%m8Nh zP99eY2Yu~J`P-k*aerZ_4ea&uOGLtBU?O%iSh4-L0&r)5xwnVM6(@h?P=96ja$KGL zJgzu-ZU}w_z*rpoJii?9YYfb9hk2X>4*JTg1iv{)&@YejxZ>*10STtZ(7q=>&yVE5 z>J+9WKEvaR>%Z$@$eNtRb1(8ZFC6sck1XBX%N+L#J8i|~kJ{s#KQZ0h6&_cdyrdz2 zZ-7a>&f_ZJpif>J;z7YTpx6H5aWGAK^H&kL@BZdE&0QW>wHSWmfSY^|)0#f|Jil@% zhsk5~;U_%Kq8NTvP>$}vWc|bA%Hg1|{z%T-KjXM=*l7cMz2zleHyW5YQoz`X(+7Qk z`vsWNFL@m4FMah_1?Alc%$YYlu09SdfBo>@C6cGne@pEB-W6WcS%)%BI=}@if}{4# z0qzF@3-&xthacgVeIdUM!0q}Mew4qfU&!w^aL@jQANdXT@9|G-E3Ukbz&Q)p;>t_> z{JxN11aR^H!jI%=xEU;uFdwmFlggooUo~Lr>*DnA^8qG8 z7pI3`e_%%H;&k{?`z`=xoi0ufzf-{csf*L$NA3Ggz)*Q-TsCA4gq)WU-(h}o_!%d8&ea`0XuEQ z)gR@rrGQ~T{41{h+<^=D7k(sviNNIO;`FrdY+#n@;&j@#3iurW=B6%A4?k0x30E3B zZN-(B^4AcU4!Sr!{CWb@TNkI3KjJqUn3=jbJ^VHUvriYN!;kvMO<R7tBccDF>0yAG1r-$E8V2RA2_^;`HQiIxx$0aeDY20OpJ?P7lAQ0)`a?|B90rQw#K8?6eiv zzEs|Z0)_$cuQ+~ff%DPjmsZrz9)tU1Kj9bD!C41K&wcy}uEQrdIdGgMUj{m*twWhl zaX*4C{{;8xb6tU3`3de*epHUXKEZv;uP$(@CI3Bt&4HWt1vq!$j(mdq^tsi5D{ZCc zxqPHK6v=GsivJCDaTFKTiuV#Q2!Vy+Iyk&J;N)_7V^5`*0_(~8`MS4u%%EQaAkOai zMP&bwE*`<5I@mxzPg-?8#8FPc3>v5AVfW`uXe{`30e`$djtExcS0@^EL{vh07N*+4 z@A^UIT61mfxL%n4oGXj>7gI1Xvv~ARh)zqju}82V!aXq=f$XmP77==szaV zOyl#^1#@QGa~5ntU?;9is47_LfrYKHY&K6b&EawwHAETQ1fC2-80g#;IspHQVLd9mr{c9jygtSDLjp_3`$e0lTgoiM^YO%_F_*A zNl!_`e03f)Q*DYOF)jsd7oQ}qMqf+7nH00Web>+stZvUa3oxDK=p}YoXP$jKng+0k zy9Xz-)mfNc!ULxCaOdg^Y;{(qmte|}5Z^8WODAAyty!#At6d^t6??HfB1)$`0;*{< zSL9T~i71`oh$y#aMNm405Kzrpv@C+sDT9D&(Uj-a5V^m|n%E=I-`me!rR?gVWXnve zJOcv)Lsk5W#VRjFsKSrQ_;yy-fIv^B$~OS(^+Nne^oa~_mdHw4P&Xiyi9V4{d9orD z%eA|QVTE$)R+J#)6GEvwkO&jajHh{c;(;nO23rWenvhsRctAiXEsh?n^uh}4v^sh@ zA>CX%oz*6>wBV`eD<0HvSWDhF0Lw^+@w~;%TM7>j^kJ^g8uq0Ymxr+jFLB*i;<_^vy+A0aTzx1}&>L~3>=u*f!Z!X@C?rX#@K-^1E11keReOi}sBpkC-xhYXQaV%v ze#NOy(^@W_RY6G#(sRC8j6EbiBOO!ACc{Ws*nMQTgwhh+Dz*+iRTmLa21XPtkw}IG zVPyY6&oDnF)6IlNSs0mBh8HS>H7cdRe6SQ+rd<*0;lu0-CBS~L1dl)uKSf9g>sLfK z7wG8iibAS|Kn)A<#S-l#0XKm);XGjbJe3~2x*!tT(?jJS;t`|>K?|_%FOdZrm4#?B z233eqstzKX5jiB(lNylamWU;Y=oRFp2nl6$5p2%D-RN0_=PMX0X_ zYn(mo30)Mysvu=BsUijGFv>lpm~fOLz)4dQ(UcKA0s-b~g0__b-D#0_@C^%5dEpeA zEm#>67#0j}q%jF(%4vace*kIJ0B?>o6{X9x(}R_szK|^jpdLX0Gi`vo(i_hS3=i-N zRCtoKOPML54HFS~P!W*1Hb@!ZDdHHYf$%^JZBUU1LfZue2Eej}aCHT+r8byVrJo<3 zs)ej4AWLc^wVtg76)VimeGrP@KB=&8K_6pS$lpZQAKICRKR$TR6-!H~j9f~-mMU0EBA z_J&ytRt5zIhl&N_>Ii(RXd~Is!$T3kE0<7TGOnVyRn-Rih6QvAKz}Y2AyIKu(}wYC zfi#JvII3%>2P?v*42c~?t_?s_cJ1b=3>B1%T*!0{ZH&T$JkMZ7fHxd_Q9n6qBRm2F zJNYW%6~eg`)kV#s0RJF(6RMyG&U2;Tz!Z8{*IWC{Y=>XhVa--2Hq*e4u+J)h`NKb8Q@H0Y61I8nYK7 zMNQp88yOPf7uHpUPU{XO)d__bl}pPaD2hu2tHh33$WuhODuNF1_3~1BB5DE0Puon1 z{n=F;-Lkp6FS;3`57c#-S3^}=1OrB)lHj;$-;H}%%tX~hN^h+ZToEA*zjO6l%;)7_+W554IMDcw_Vy1SIF z)SK=hrF-d3_mtAT^`;m4nLc{cy(G=zt2e!A6A92!KcJ}u=%gReOal1n2e?Q8fBk^w zY(TLS;)_MQ5GGQrA0^2OlW3Svo+eXI zlx9|#=Ib8>YvmiN2nq^x@5nN94hTd-eS=g`3Y}D5VHn5|SE6Hl1v;6RkPwxpG63EU zM;;cXVW5Sy0A)D(J^DV=zRIppt058u11vxgg8dXCJ^_O*;sQMcRUF`j%!NW(@=w5+ z3uy?RgoM%);9T)u5|Dy(4u!*lEX*cQrZ61CEy}KBxc$6fl)XvM^PZ?G6fRO=SSa)D z2#jGGz+nL)3NNK9G*G2*hqJ@<3#DSXMmbYLPX#O80|P^uJANA}SRXPiffN$#2!{0v z_mDt8gql=g!M?2h2~)Z#CJai5l~MxO76teOqL9>btnP_}eNn)7BqTIAd?w|9-6MJl zG^nK{6LuR*@(c)JElgz7Lb7jA7hVjBE-ONB$;Qj~*%Ly#g{Z=P1DY1n5KrW3F3sT0 zTi6i}(L>Pu6&@_8wh0WV2$Wk#14+*CjI|YI$RU8ZQ_bOCD zzFn1mArfnG^d}}`tPmK?s+VpSM|>-1^C>|b zv9SaMpuAP&l~YfF?jS#s90mf4gEs#0p}{);;4Gy0O3M~AHo&F8x8UbXEV<F*Bzmb^+zhVm^;_Cx?T6rpa0Ab}Wrb9>Q9MQlWi|q>3S0exymU zWkNv#7os4WP?mnI$tV#TxG+%&Ow#yH%p%lnVLE^6g^&ZR1hL-*4tSlT2u7V?fEXA6 z{q5)b9WRoUh&MVc(JR;&Lv+7x(p`9=!x9jahf;-(B^4mDG!qg90pLUBB+SIJgpeo} zmc>3P!CXi{{L2R&m)elX76O@dIy7Af>;Y`70*aW1g#@t_S<*0^K?DFb0|8130FqUe z7e-E!#-da!Ar(d76PZX;1ddXzg;ds6Nrw~BMj$fJm5*Q(xs*sofXH9Lf_OwOEs}lF zG9n9Gf#@0Nk3j?L>x3;MkfneFbxumK6PbuLF5D>cvlr5ZqEo<8hKMqnHzW+60eff5 z#O4^7nQ(|r1$ToT4)PUjFZ7X;sVho171GHds{*}LOCb?z zA_Oi$C=5p@iDyY65wgR_?pXIAo>qk^LcCB3Cn_|UkL(e`x)8zN3#ABa8We;sM8=*l zHrfwoDCyCq3U6m!g@0>HHL znUoF(1eO2}7~XuqHN-jLVJsSf zQ?iwmES3kZHC{)-Yv#j%(gUp}Bzx&e(I8PKnQo!6KXJ5?a1uwdcB1iQtxmX75)Nht zQ4+0MB7;Ye(h@{0eqs3<3m97o;}eQ^SEA8WiI$N@5G>p*GA$$BzT>&#^%L^%n;LL4lHMfCC#T@(qS>M6X0Hy(&wv*89|zxf2~r}S1J8b~7) zGzkrgq(-eEfxQCp+C+t>fIA3>ihr%bIyEtMkZ^c!OBF2%P(>+4%vz|@59+8;VoCoI zk4h5K3j>%!d9N(dSvUtTFN4C^?TGgAUh6B|jR8)uAM4vp-pRcufoB?t(lN#m((%3z zK~yC_YN8~JGlV2IZWGiPrC_8{coRHx+(hctguRy(k}zJAj0wH%qD1Lol<3pR&!5%4 z1xx7|=q@TLss`8^HjJdu8w>^$#b#hbU{mgMV1Gqd74_9{Ur+d(6yB$M%szXMCtfnD zLKWWl5i$?A_$-|DWEHv5Axzf(U=^vADc?Z71!w{8ge_74T`WW>z*FHz>bMIAqj3A( zgxiXgLH9OZ5b;hGFU$EsKE1|N2)9~lm*?MaW!=LIhFlTE6we7{8ZK@i`Qh#g_<;WS zuFE$RFhW z5<&1A(e=AA6}*`}Fv!=_Kg3t)RN^~#vIUe3f2C-$GF-Y9-e{3DbYMSUe>MQ5Tj7%y zN%joJ_XVt=lnSS`NGdv(7_cNMCkR~AA`rX)4V4}a_q0eNz4b-j$i<|4;ieWz2J=8K z=xpKhF#2T7x0!S;W7o~uApH#Pwxnx!m{9hHnkXfS0wn_N>EQzv%=57#D&G3QKPLZ_ zfHp)zu*p|}QL9KSMMN?1AZDTr5q+CVnJCAuUEy(9+SPy{WMFoNrY%+J09e||1%fNC ztKgcxhfwMJ90DrV(vH4eNRNyYKU@gKT)Y@fTC%tGpwqi|xQSgDjXog&jRb_oRmd~{ zc>V(lJ`*epWswDBsbzB^OEqzwrb+0p#&sFoMAx1aAyDB(5mc}xQwduA^%IT5_w8~( zl54C&F5n!Kg@+NKTA(MQi+VGL1l!2xmBgC-8yF|?!C?~44meVu;3gw!fne3LQNN@Aj_Ns}f`(P)--srXS`5PWKCb4&IL1RVG$(Mx<*SEOFan3Af8 zc4gHJwBW!IjvONC~cpv-4RsuC0M`5!f42A*5kfCxVkkut**qq4BlcPh)S97OkSaNSD* zK@(L3d4!YTlekb?As1JMM-8wx;qkaorNqW+Nd#*MOjST-Aj3+n%06;I>kCdSUbuv^ z+bKizHIgcn6(Sv%s4JIdU`M&3n#2qnDY&eOOZxaISdE!=u|Bp(N}5khT0lmU8ViAW zs$(&WzlK$dBko~B$T-+hC52%48p^sw6gcqZ!AE%E>~mCfWlKA{34KWj$}$q=MW`#R z=>)^ecR9U1j`}Bcee`RtRd_(vED32=rE`yJNLDA2!7;--)Qn#2$-MQ!gTm zh9?%9G^vf4n7}`>WZz%`qxJa}Q&%hl5Jx{j9%}>o5bQ_?<3$|BzJ0w_2s{Mfn-Yw? z5Zz}Ap*(Q(X&_j_;|)MhXY3q6X0ib@0awy9#GmymC>pA+!q#T;$5$^^DC-I&B2+My zil)$GU6~3;@g6Fi6wqNJM?EhL0*^jN_uc0~i21Tsr8?>h#(q3!QAN-VOvx4Pro850 zIi!!3@GyGA!5C48=mi?gb|AiAgcldwEr>$$e%|!$oR2>R)krR=Xnc0)*(6cCLjaH0 zl3B{4b`nlkn6ju=WlF|Tc;4q8M-QOlM`dMUiY6vo6qgr8MvyIfZD`3p%GKf3N!d-s zzD=ag_7~kK3}$(YprUezNP0ssJfhH1%b;IqTMd?PF;6N?p^kJCxJ$%32=AkVRd83} z$uZvuj)f)r*cP?y?HA|{-!KTa-3PWDH4?(=5;tCjHl>j>ws za9&?HZw*WX;XE4WjfC?IoIeAuS5Ime=k7;f(0b^e<2Pq*2R*QZWuTsJ0Z+oV z;T+$j%zl>BtL&sD1>28pe;S(WJ-%ND-?6Y6f>dN!|^{UPpSJiFZ!duSJF36x<=Kasq`u27=7XI37^-n7+4fS6&>e9fy zQ741%99cf2-r$vwF%b*H?Qix+_2)AjehM#{cKG3g_uY4I?cs3bUTDUiDjnB%Xz{~8 z9CwM~95t13dAt1hV-}YO;KwWsclf=T?fGHte4`F1q9$%1f7he- z)?E|q>(!llymFLd-TA<6X1FVh^O~I5vuNAkodts$Ju|D)b=L3Zc@aVKy>XS}Jiobu z_W8(gdG9OrJJMvs>9(V9yr^{j*O>TYS9@uKAC4{AXJM=E{vGhE#9$faZ+e;c4Tg2g zuR8M4hQ=#uRc^B?yp2;xj^^o@X>(S+ZczdgNX%fke($^YT`>2^%qn(0`#c@Gp>?&j z3w>HS%=7+vS5oWW8b8G>D<2uIL0YL3?um~V2Rtf>@3^&@lW=8JlwXEIz|-8F+(jPA9)wNJGht#56~yV(0^kA%kAF)6=4vhiEh-kRgKG2E3+ z_x7Kyv%6H^Cnb_DkGRo(Q`0NqZ4~aERu@e7QGS2#JR)AuDRNoB&2QG63Q!*3dphFQ zS|67UotnR&?lyTq?D?>gFHUcKorc-L7%p$xyh&YV2Ok<$yU%xH;}Q=q%5Xi_uXA`A zS;0^Jd-W;R06%JCxTT|pUCbHz=c}d%`{mSAn|X~fYh&{Fy%x8)#U|7KX)$yw$6aB# z6Mf74{c_s$hc6$VAE@dY*zPaer^mW(t<=gtwR|Oqb&Fy!=?G@5kjvsv4Ij&`bgA2T zje4~0kl3f|FZDXwzjlGzDQMw3e^0W~0~v1QNmos)-?Ap|9ag)BW&XLoigpXn-Tl~Y zkV)i}DU)(O%)L?H^5UNZ@_QdUY&qd1 z$Mt5oTXhEKI;8aLeRV?HS(&->lExQ2dimyb?~$uU_EjWzikk(!!EkF^or^rty5sh@ z-;bQ1-tgLr9u?OQ_+w+&ZDs%7a-{0^yUQ@PhfK?52Pb#3?bUh9uLJi6y>2l2V3Wi~ znU~KVf4|1*!_7b2n%Kez_Gh>yue(*6y;r+> zhCj)C5x>T|T=@6q%Ni^^)~uRSTQ8>{=et8r@k?*H?9c0i>)3DlyW!$79ekQ=LS!fV z6x2Adto7wz7Z)6Ij8)cyoHE=`>DNPZdrkUfbU;GJd#AO&u3nuxsGkk29eX9@=w0Q; zyO^km;qFu&_|V_+(C{CdmRYb@)$H2%u?N)N6FqW!-=DrA_dfid4nKk6_KbM#aHhTO@T9C?l2_ijX7~L2 zrw?~G`u#%RIj^0vDtPWg|6sU^l{U6(X4P}5{Rf|B;U5lN^IMhQbwTIvqiow>UcD^& zX&ZcRSel;ee0JFKf-xl;jGyHdyxP+3`k0gz+oR(YmY4Ra`p%s59D4i*h8uCD?1R+0 zQ>@Rw9x(oO-jt!;y`F8{>e~B39T_czZx<0rE}1S^l^dVnxICGbNbZ`Skih+ z?a?o8uf!xU4EJ%y!yj+`zHG?dm(!~)FFkQvlT4G_1KZ>*ZtpZLVCLj1ksO!La8v#X z{$ct4TOXQSf4aBoGLxMSmlGeX%^Xrg?$kVEWW9~^5spD!!!8_1-!x>Nlk?4cyQ=lR z(>vk(veei{Lv0?tU4H!Th#9h*m>7rQUOil~>!%;v`F;Q1zQWm%^7opaYya)YeZAd$ z&imc_u|Ix=$Sq*Fs4AwxOO`Yp(qh7%r9B;5JNLiU^X<0p$NVw!w}GSkzQYGX+!KbI zHK}fuZ4=V2)^}T9tzyf8PnQgC)n#M%h~aq;U5EZ?a|v?a9y(Aiv*LCnE;TuEA?L#n z4Q6br?xnM5j`AJiJJ;{!@ou%y9t>w=>D7MgcQu!cbPi9L-MGo+a!0>ix1gl# z=DVeC^}{DMLj7G}IP*5Ad%UhPVpTo!j@v7qYjI)3&2k4dZF@cZVac(H1E!rj3w?kw zn_Sj&d`^{z6;@~bGWAH8kCxdM!_K@bIB>S{-&@inkGyF)eFXdnhI=+C_7{hY(;br| zO#dLWsxTVJ}w-2|NH>Hfi>FkQ@O@5RIc%QD-;As6*rEF`o8vbn*Caq$)a}$mP-dI<1 z%Z>^?o;~u98C~{tELY8Y*45ai>QbR&IuF8RZ4B3Usr%9rd%~`t=oU4r(Vh{9$J^%* zd9699INI>1pW9`goQO#u%2EE>3|oD)P2h}Yy-M!5bll|Z?nQ5sAG9C(ZMA1pA0$ z{UqG_)=-o4{vYj+rc^_{e9v&bH)r16azAR&#e#*)>oxJ8-T2wPS@YEIhb%1_F`{~h z@8CeWF%fJce>4Gu)&`);aeEIwap|@$R;{-_fIY zTl=n^aYXh!*z)(?gX&Jr=D4*Cx4>ha!?*4BZoIa#LqS)k$ELpotWv049S6_5T(HA* zfzKJp0cPBi%ep=|A|JQMZr;#pW{c)e_N(>N*;x-fJ*_XtRUB?Q$ZAAm_%96C%G`N# z#T(t-syq(rJadxl+RV72vF#Rleso>4{$AfJ$NF&GEQb5}{gBsQilFBS(Yv?&wruk2 zHp2!uR&j6j*NvZ-^yKc&al-_u47d8Y&$yM}nuP2=IPFEeJk3z%q(;pDTk z-)~u4vTu6nZfhL?uQKd`T4!u$97#g^JKG6 z)8v<#2O71i)Bi#1xNP;!Nlzx=6&1!!828NWTlvLL-D6`Z$XybD^vbDB#n<8b!+g`24^e& zF?7^-j=4*3IUaa&qVzZW&9csx?(h@G&1AU6*SIJT`I4*luH*J{d50Z`4Fh^?rNyT#Pdr&MotM=ZeuAAH~gxI(vPrO;atNs2L{BgyuRLh z#C!GqpjDNg`{b`BrnxvPW%C*s*FPU7Qapd8^@VoM#vR+hLuxs^r_z`k?Zl7}3*H6E->1l)a z)2mIJ9+tb}dA4PE?wyCC z#;%#@x9BJ5Yx$ULhv8NQo4pv~U-kO|i|ehcs+e%%W|rfVsGX}%JHDQ@V@l9((Hz$q zHc2i^$oRSBv+~1gx0fHfa&2ze$2B+SE?S(?=tzE4ht+r1ze8V}%5bIUwU9rM_xruz z+XufM8D0Ocs%I+{oc?WC?M3Bxop;keY+ig=eyHA%^>F?wB+Cd%jLN z`{vz8mkvIAjzrr2Z0nZa(_&}qC;q+qPQ_=3PW0TizmCW+dvJZE$>|$s_ulIq>cnMs zeEG=th2q_*@+;46L^)y@?qL7TYoat>=SM2%9O&I+(UjLs4n#!N@29EX_xBYR4WG|&pST;#`)m3lxd;2 zl^l1K;ikGJKA4xXKWcAA*p59vthT;;x@;HkAuT@0Om8U5J!|k9u|2ejTsA3g&(;{O z#DH&`l{ninj(IH5uH}R4RU0{}$#1C8x5m5=X0Ge zr>;N$@{dI?{AN!t=~jRV85wTS-DM3rc1v5=QDzxG{NXy6u?;N7-6+_7c*GBz*S{I! z)(;=o)S>4N7~;CFo#`m2tMALTxjwVQpWV9z{c`n{rb}%7tb!E|ap)i64A*Rt>rUt2 z>{9A(_+{cRFCvrnOlg`i?%2oijd%9=ZP`D$htNM5u6LO`kAu4BCbdYKmK0ZI;*7zo zddcl?MmG(7x#NUG{gKcae>2<$$2ET2mblN;B#ip!hgtW6GH+FS>=13~KCjO9ZR5=> zk~z+;F6A$>`;nNllX@ujWm>L?3+VW#>#T8S&JB%kW%FuNxhLN){}mHnGu-kGe^)M1 z_lI4l26|)-$nt%+?!dH)vm>`$X>)XRo?YnF8JI|u;Z(Jn+Pr;hvE%nvYX_KZNk5v{ zw?&Efn-1)m9GJQF=*T}8AP$Q$t6Y{j*J)2>i+)pQ4)==u`NDztcbS8${kmjLY^i#q zrn%N=wGQ@!;p)BBoQWQ?(9UC3g!RH+->&HKvE6~}Et<^B@|*MfUjGBW%X)@udG|r) z2ld~VLWX9RbK5${aZ#MfiCW`KCbfBcLshH)qU)HnkKs;i+4qa>+*)tiMO6GDexK`~ z2g25T-)^_xtPUL~zZ!SBcL?IA^(lW>WX|U&HyCc`8eZ3b!yHPm*kzwg?Bhqp&pSjw$CfeDrw?qJ;e zCrf|yyM5N=;`Kh`R58I7+BCSft7q@|w;rxkgd`k6Y`OtGH#&XTpL41<`nJQt*xMJE zKBzgyGvTnshi~$J9T4Bs=E=49@OK%`e$BUzT@IKi&Xw^rv6+(}TV}~hZsh)g+pVG| zpIQGnr70#nWVnT;Nt4;^FkE=`+jqRliavUU|^td7E8+V+!ocAfDZjp8GLY zd1|w4;6KB<;y7=HD|be{11YHsM@rzZX_NUV2-)HR2HrH~62UoxYLRyS~?2?KpJ7 z&^JrAH~KO3=YnwOE4dx3q-VHr+&+d|&@3Wz)7Eh|j*q_0Ow`Og+PZIUz>s0B&$T*h zJ6oyfTLE8_In#4@#@lvTy=Pv{8jYN79{l#;@#1=KsvU6IkzcQ+yrS!&&23><8ScVg zrg_c1S4>(})jZQo6ZXf$9Vt&Ly%|w&oc}w!O^Oz<`?DEt{>r+Quf}ee|4qkR(X$RI zs^-atH-25YM)VYUn`%+A5owrgk>Mu)=)Sf5?AiBzeQEy2#d*THV2}^N5wasRLA}M)xS^hi3``fd1L-~_-%aOz;OB9 zy4{Pezv}7028Y|kYmU~{Y&#n}E}_G$iOH`gURs@R34fg79(t?NR%U*fJK$Pw?sw%D z?7!SREdKel;W^cMFGvrVSVfIbD`7+AvastPzMs~A*u&LkvGe~KZuiXGM;7(#k!z#g z?{fUDrMg!n#>osSRi z*xZFXx9iTz(+-DbHTHSB?e()kr;qlSHyG@I_ zUq9LLL!AXDrltRpylZ=#vnL1d;JAeh7pKW~nc#IJdDfeWwN@%VWS7Xk>mBG{;>GBr z*KhwCTp8oMCk*G&`{v9U8cv|x6w*KF9o6iS0|C6z6!;<@XDUiJ%816z;*WC15*EqQ&zt8KG(PLB*uTZ;$zL^YE{$k7xMSKklV;*`4Tk$* zzUOkC-B%(OZ9iMzqs?faf1Jxbux(|3!gf$Er*FKgz)#%5aP6xPdids4>V#3g2d3AT zPdc*upV9SJ|B*lS#j*5ZcTd&z!#JfSJ$I;cP@5r_zyEgN>$dY7A3GgazjLTh;2C-7 z*-6zRXBkQABCNWlH^13Q5hL zzf9djOIN44O%I>B)XKh8e>He3zmJlm{(9*N?clGlH3ck^l83w1-$=1*5Uf{rH;hq%2+K$pmeH?^jKF_LdySk z9jx@2D15A@=NVts9G@;lXGqf;V~I*Z*rJTIR$K3sY)yJXbRQ!u+h@$>B#pA%B3t4e z>&Qi<#eQbJ<3;nI+rrimApn>AGbrSc2>HZ?F)g~i0m?0q8R)W#}m z;TqSdKf_nI7CUB4pO~0Fm_5|MVl%THor1M0)6!K~RXq(;Uh83Lyitz2Uv#RzmN(uL z5^26_BXmTKIywVC)xe_UsTfVBN8+a*hSqkWkm2_fDTZ?6wT=;FASnV&(y*Gdo|gYA zQ^wR_Tug%Dd|)mT$&4AL&oECSN}Z-L+;V^wWvhQmGG)!cath**mI~`Htxf%(^&zrW z81-;5PS)ZuuRo#^#$kqX8jVq;COg?sZm2M-dX4d#F(%qbeiwNY#;W$Dgk)o~BmX2R zIxWV)rbOj~QwEkDFp!aG5L4CBy!kRz^?%AxMU12MS*@?qjuhVzO>Gi>0-9n30cPuZ z7)=vt3M)~SVLS;;&rHcMwDyEniAlqH5os)+2FeWtFd@kZ147YFpkajJ4S`%GsgqLD z;B^?PmcS}GGD#hinviOQjETJ>CR1h9Hb{z2FiKIOOkn*CmkFMaks>N!Ryex+@+dAm zu?Q@tL%-mQ5F@&&5d6q=?e%Qp4SLriv?uBwW0Gi8U8bRR$HKSiF?wUoU!^CLB9N=T z8S1p`W`^boy@^>rW4A(5B&`-?XzsKP0>)la)fq=pV6@bcNh&q^MU25#w#YbpTtmWRiwIjg>Im*2>mrH z*>Ja)s{DUa%IMT=l~Fncn{B{26()p-1WoewGQsLS!bskl5Ik0k%J#oz2a)X5NP}gR zbr?-bw9sGv^T1OO%|7b1WObsET(hi{td`Ar<7A*5ke`=g6iz}p1&L~IV7>%yWSP=6 z`bJa6i-;4CbXo@1nZt|<#YQ5((j+8Dxim4bp^E5oy%q44d7|<~ zC&4HitSea$HvFTJA|+&UY0N6iGDe*x37?@D!6QUKE6LDzZ9?ZYidrdB`{V|~^*6Ns zlOpgEFwr>K(~C2`SNrzv@hifLogwnQ6R%E&ndizB~%w?9XNkN1U8p6=l#9Ie?OJF#gjO0GaS%yY%3VR@8@j}n}a#;`u zf{Y7POpGQg(g@uzo=sL}l)8o>VLjc%!g$7i_S&HqViMyFbwPysPEARr*XD)`0Yuyg zCLUk38K;IY&>}`gX*yEEiH6oUjb`X&AzQz=u={?wh<{Gq#ipbs8Dm(9wcpjk%UfO| zzC3$k4`iVjW90`zg+61Ta0-%+&tPIi+x{PmrS6xSB1V}0BMVG(hm063O@-Q06KQDu zKr)lq`+5WG8GI7^ql%z2^>8xYSd)U7qEqzct)Sg~qNJteqYVnhqr@qZh6^az6u$pA zf)eG2;Kmw5U{I5of?qhK8AX@Ui!BW-j&U?I?|B% z53r$}@X;TbI0$y^eI!)gfXU5AY%p^YTOhX7Mo6j?T7mJ@R;^)*@g2vCTwH@Yh zF~{6-CbaC&R^iNwbJ^*Wt0=SE3^0O^#omVV2Dos;FX`EadpJiaB}bTxSM(QD(HO|5 zfp{3#7+A#g1QG zOB>~frp}e&h#5cFc9`RG=;R2Fl+U9$;#d8g2D>%8o6fAbo)RreIJ4pwNVFvqtwV^< zu={eKybC@f4rVl0Y+QsCpRwifABR$O_{c648}k|I(-faPYuuY|&f`$cd53*+Wj?tc zHn|?xXzXTKjZ#ddAENT9?W9!v$d^mR zZpOt)XJ$Big8dtCYOB+feL$z`!K4RV_2Qc{MxCg}6w9Bqr7u{P#H}3HU8ikJVx1X( zi6KpHY;G#6Yi=g1WL?+X)W+1@x`cI2oXE^fxd1zo13BZv|D#qHHpqb$7jK6Lu_=;C zCaCQtnJCS$Y@(O}y^NUvf)?^cbycUZzN-f&?lZs9s26ZdE9l0 z_LoGXeDe3ckZ7i;8=ht^oLO=95{+7&=hsl8HIZmV#JbW~2yaoz-Tir)ZHBz^QYp$J zeq_$I){#XY&`1{P7vm%_{Pu}jiA_^~RubENB8i`oE+1aYG{LhzD^UcXjUNVG`d%!*5rXniHx5{dS!MB6CQsOEWoCnVY#iRP0V;Z(*aH{HoW(S;P= z3q?5#-@M0uc~7DG(jg$2wMeht%YzQf9pKbtiA6^Gh@I)7c^)=y9%V9d$H!vtu-PF; z8ekcv^UgyZ-o_P&n_U`wUoJ1ivV-l0<34$^)7SGlm9agPTW&Nid~?n7I+e@wD3gCj zHr8y2PpEWl=53!II{ZpM8l zrBaoSW2vM#`P4x;%f)VnKVF4)1)_tF*q%gM8SGoI*C}3XY|v^ zgk1+o_g8>meaEzGRpk9EdrDa-W3ob&KNx5}fA%1D0Fm+lqL2qSI~UMs6P2=>zhu{9 zm+B|b=s@*KUCIW>L?U2&#c?@Q*O0;-HykmiN{$l84>pRPZ!X&^#?mqD_)$( z576DaHPCH$B|l&+JbL6IsZX-<6FmH}p0h#l;HRP)id+3HIF0u1P_XZe*0| zK=WF$HqLmhNVUl8Ju*gos+W}NC#7acsRMAv>&&52>d!dibtXypDC~vWvp-~1sUwHv z#!x%o#9s6Ba+pO+3aRk65^I1L@kH&R5lMxX0}o8z#T|khQB;kVgBEFLSHqkX0~oN> zLLF+y5eL$dda~zKL2iZ^;u~P^=U_)>m04?LMJy~ zpwfZrp86Nne*_V*!70e0Ysf!yR?gwL9oH9d%*Tsz?pwWtVHWA(K00( zNg@Sk*I(|b&!op_ta4bQ0Gh> zsk)ue7x?XyF#tJJk~*N3)3jm?MYTZzcd!_3Apb&ba08x*(X>G;<7orRzaiRyg;BKC z0oA>(I=F)FOzHsb!PLPm97!GA#xWm9x+Zl%*T-xeTxj#C$Bqp_P|kb&9C*_j#sKf!(kyY7gYhA-4Qf!O86 z_m+g@1X?^%tB(}5j-{AA^hcptAPWQ7&l{{y3>3v&Y9kM{iSB(n{*tQ+C$BWu(~iG3 zXF)pA-R~-3=s;y5>9fSqj|kY-LV74msBz}xZNL#zP;$TH*aAm5bUB_lZo<(Y$IUoW zU2MaVq^&P@UfSr4A3^i9NFkLULGv{F&*PQ|XV%=W5{;Zk9=BDZ9gt|$I{dv?B^tRj zJdH-tbU$Z1X{Y3sPsO#aH^kRJKjx`rM|aTniTX>>sAycJVzZWf-WMTI{BOGmTd@NLYCeHavr!(H-^Rz@<^E9efp0-M&ZFa!vCI}%X#6jty zq!kJ+MiQ>vbS#EgOVkgli5H(%S+Y9oUuuGcn3&L39YV|dOiWAG<*DpHJ%Xx&JhmzV z9WF`^oz4-eAO+`q70{U#mw^8~jY`1NhD)^35^Wb1mhbLh`H69qfhKO`DDvAU(vgN> zEk5TdHrh}afS18Eda@8Zb$F4X&QS=FS%NHu$O`>Q?W&>t=~j&mM%Kg-AqLhZvvJN> z4W01@fTvMY^E6VhJdHXHPh*PMCpS@uPEo8$&WETFm{R6FR^%P<$-A3>#}uQYk2_@t z+&bB0Ik=B4w-+3^!q}4S@T0hPd7&Kf!glz4oZ42Wh5%$(8_ssaK+bkJ$tIW#+iB_M zVUtyUGZkE$!4H()shnb?94DR)@)g5gS!R~a^RUdnYH7Vc*TZtG!V(evdv19l7@x`f z#@dWS*uN$Kn~0U7!GXN{5h7eJJMUdnfH6Pn8Y-QMlGF*3>ZQ|Zs-c@z0+NnR zikBqb#bT-k-!(+{LCa|w5z*1&BUdISe`6igqK2g^3`#q@1au}7te>06$D#_yU9}lJ z0D0hzM{6)p*aaXc(+hdSw7=YVyj@s|Q5nUw$RL|=$r7J<+{bTnHhxRSwVV+?AUBOPGoSJ&K>vD3i}8vdNx8N-dr}br36^19H}jU2lh}8v+w&!77RF zLYzw-OAAsf?5J>LAUK4es8Zs!Dg|q`a;-qu9%X($cqhjwQ+$a+#rwp7+X*8~YN|jJ zR>fi%k1`f$!dE-%_GBBnQqF{pWJuR=Pe*T;BYifG{y5IZu@{cN;7FrHx_*P>VjMr> zxCBRPiv>6~#B~mKUQ5s!uRwVkDNvp^P&l(jEsC_65^b(TqyC(O-I^m?LuXbTnQ%I@ z=5`8aRxAR+({4+&XTq5^MIMEF%ORgU&Otb{;+!N}U5PeEqWvh*P%py0s2PD@zC_zA z(N0RVvl6Wr`Z5397~#x{^UFI3^&{7mhA!C%UGees)t4t~p76~(NVSZ0l{sz<_CgC< z9_)0Tj_L%(Mhc;!)D1o{E4(sDi_F5J(O56Fs4ghl?`2GeJL6eo639+c$4JK+(*rEE zEK8w()uj%AkTs%=QU~A>)zMyjgqlRRctb@(PJ&HJRx(r+Iw8YG&t`%RWnyPXosySp z_B<_1?}`+0qk191Hp7vGk~RcfbEr&EHZ1&@f+H!GzJlNmz&S6tbjCYBJS`E|JguK_ zX3eg7+7yX4UBa!GXqzNjL)0nHuZeJGg^>o{*$88lH?W3~hz^>vWDxi7B$@CzebwjX z37?v;NK|Y`o&+-=yl=rvo+du|cjbz)K39jmmTPSCcAdUGVyEp0=6dAiYumg$x@Saz z?Qk+LWGd4Kz(j7B<7(JWIoZk5dFKjmNbl*1_d$vVkB5DbXWA&nc96rqkxgt`XcLu) zgjB*?p1fmt!Ly%i;cb1kkly7qkxU>9U#c*S0#PfVsoJe^5O{!VsUj)t&5{)QRIz^1 z9r@<_#Sb{+4W~2evuIzLiEgIbSDFDuPGU_QoxiZJU;*PIcC!-nIfW~Ehs(j_61=d7 z*ey+T!jSq`?6jB-sdMJFIL zMfoWl{K-uYL2tak6U)HnP`~!a@gjp);Oc7`%0?(ZUg+1OxA;~zIdd#+OmnuHTiMu_ zvMEu?ri86r3rnkD0XxKu-u;&%y9tmjS+J&BDBkqS;$U}eVRx%p*RfVx*N4q*jI(-r zEiRQs$97VG9K`Y)!}4DNWg(-5`Olfntf2KoAzvQm<~G(+$dq)Wt&WRvuj4G5%d zXd42(L~=G9$8T^Pfnz-!N815#Pnq;1?8wuA9fv0-r z^&Oq@`i`ej4tUyd2{&4z&6jA4BpSKu{JjSy+69SrS)#p?XzwH%8D;)nGRpjO_eit@ z677sc`$M8tK|km3l?!K9TtkW0M53*dXzL`JWPtN_F%<^&BXilgyLbakpJV8HGV}SV;%ZqB2FR{QRK>te%tZ%3&T3}vyN#7J}fk~h{@P%jpMFU&{SIq@_Gz5^k z5Q2I+<#3F}kpvr|J!XiZ`5TUvc^Y|;JS|%|v*yT`vS;H<@;LEo zz;^g{N-S=0x$lbxm*+kmTxw`=c}$Vp6oX6H$&KV9<=?i1!M5FSLU?w%S78dqt=cIK z^B+0zHx+)S;c^h!ot#f@0);eTkR{uUYqG!+r463O+t}Z6#@pDF(iuIzsNE%NAF4B8 ztpJ)WkR@{$wfPiID92@K}$Q_KyuMeR6);puF!2Q$3~qF zxR>M*0U?tETs;iTbVri13NUA7Va}==FpQ*3lKr6%GAZL^)8@156nqzCE}1KxA!HDP z^kC-69$vI)e8>RNUVNPQUx$pMnJVnp-$LBas#gS~xVC;NXrZX${;-05bx8rH#pz^ezB-&DmwnCz9l4#o` znjCrL@11av1YDt#wDj(yZ09L&zr$NZ}1xa`M$j4x!;!~51rk`LRQcvxf^7SU~E8L1yMSWV8Ct0OtA{1eNg z8-2-FUvj~sHvzX^V9UPN`LySgMehIzuM31RyqjGV%LD&PNNbF}N+8pL+K%)CsnrDn zy*2thRa^%g>*MHwBbk3M9KXd8{UIkFM?W0Nw+zH_9F9RaPQnp!hnyKW2IDvvNA%mA z#W?oDaVw5^N0@UMM|?WK-dUnI=a6?v>F;rjz>&VGRpCh0MRd|bWTkjLL}ym)-40Kq za`QB*cAhp~qAizbze%($5^aY>J1@}+B-#s!Mw)|v27TMhKZBe}p4L>NwUB6}H+US4 z?s(jKiAFt%r;+C3apWEIG(9l|gbqF;4-_t-umOu76p0%gN2+JhxB*o+iyN$^6AG~p zC#|d#JFwS|9oP;Z#rR0^gX(Ow&w>bo(n2tya6rGisLE=>LJI7by#1%I3vq>_TC2$I z49ceq;dd?GEU`#9q4+=pe5S%X@1P7^d+b!5W-R=~D>8*p#f2fczNVj!2$Vos;m(#g z(jbxF{zawf#u*%;3P=XZu)7~o)U)a& zcvg-8m$1MX-onaUW+St)P9}ma{#jemSsDD3St7lJgSOriv#O;!N$rF@!o_8bheY_{$}gELOw6#1Ei~#V^Ig_(8F;18Tz0#tx89t{SOLaU+={ zRZOOo)GBQmP<%JhV_o6e zMYtvz|39pK2V4|K^#2}5#{%{)D#k)=U_p(_!5wgN6gfb#oir5-D9xG(VnZ|&YB>$}u06rtHlk`$r=>^RI9qYE7-K3 z_YT&V_N)Xzoi!gasI@mG2Nsd6$@x$-73o1mq{GX^ibvVJG)K>udB^toGhZj@LKRu*TpS=w*n|FI!sMWT8k(mbW4em(v z+!ut=3FDns{TO$1bB&Ir4+iDma>wHcfPBc$4R+P!y!XxY)=duBuF1b`r}+TcYLQ8k zv-b*Pk>HFq*j1l%Ta|HcyDt=IJm2Sha39j(o{Jc(3Atto5;weU;?3FTuJL@8cPwuY zt?IixCRWaX<##pZvoM1pZ@mZk)0&(;@AWx*Z8bUjb{KLc+U^gf$IgBK;R9=3IUjt} zO6DC4I{DD^5uE$n{^BelXSa{Wr0J>Yq3Lew*`wPo+;hH13w+#lPeTkn7~|Y9#JKC8 zC#OzBESsfL4f0g#r<`{kVzXH4208T|VtllOy%1xzpgqBVbwol6EDmfy>m=($q1Puz z%cOX`cn@FuNlY+(@}~AYn^`amO241q)Xpj+4w40LYInzgrg4i##=9d+c#_FxH#}By z%cC*mxr2`HX5u_rm8WvTNUU|EBKi0Y?ieO>0C;1FT`<{1+t`67-E1Bdi%$dM0lid~ z)g-2aaDnU`_oxt~V?NVI)j&^`{KOoC0cr9*H!8X?!U>I;LJ~xiDm*Zx>H{}|%E1l8 zJy|t+OpDHwa8YE-uyq;der{xYqUltKv!RRPN(RQJ_4g9_`2$|G!cKU1AcF}m478z4 z@u|!}Wv0GonZQ$RP>4Hk%q_w$4pl!44V|HVfRY4`_ zp^2s-oL21=E(V z-UoGR$5d6Y5NU_*F->K|@;icj*#+`! z8sRiuq_?vXvZ~{}J;J&O{Sh`ms6|LE1OsLkwR4P&S@RKM1Z0y(1HxT64@GzoVHmN<+OA$)tPyloJMVhXACUrLyHw@ zRKKGk#f4gnNLwV+evoOu$+V3!?V3!xCDUHZwD&Ttidxc9LyS2K4P{zmnHDC~j55t6 z)8b{?E1C9Ara8e^7|pJuq!@D+D$6wTBq-HcXfD%yWExw< z*eWL5#LZ^;w?TprnOc(NH6-LRb~yI)r51>AWGrUl3CH5uL14HvYMFq8Q%{&S`_iRA=Vx za2ow`+(I$tA}o<g+71y+G45 zzarAdUKr+t)v27_^?P>P#qZDsG zc!X>7u4}Sy2*O)ZdB3tI|9%-#DcGi!%RYpSR4?=IRT5R^ox9f}?_~bn8rcVFy@QF$ zzK&Q2u7lyTkRM`sDKpi%EM?&o(ioSyASn9Uv^kj7nOI#kH{!FcT8QzP8hM)&@K1YRrBn@K*(iToHeKMUsi1LtHBXMMmSd0Q z7_FXgTtzuX{tTzZ$}y}ci8R_D$y3RX;jzf6{i+$HYIq#i9h;IAwsg5|B(DQb*ipO~4fEH-t(9N+#EAKQUykDuW}GN;}tlwu=ZOX158&;=eVUNYyE%uryI%jNws*m zN)bV_^uC}dEPW6N+~KE9A>`VVrKUr2?REUr!nG&Q-j`hpPojFIv4A+~MlBuf)%Ifqc)@W6sP!;kd74+EN*}Os1`uX&Yo34Lh9oflRYQJ~@r%N?b3M z4X4$TX**@wUYSO-8;+wM&Ux?4w8t`ykFQufwHROrsXsoz4lXL4E=PDwn`p~tUTN)o>j_(-|Hr3|c)8yRj5QO0o!^#7PAaUevn0;gigo88h z^lefj4Gk8fWSw1iyijGtj#0K34UF|kh9U1iJqAP)MdPinCj00WE(@ceg)r+QE-5gN zxYVYYcc96+)xiJ{0mH3>KL1e}CLQB#lqUNa8G3NREwGUOKNxYDN_oV^9a}cy_9bt` zfKitm5`F&tN=zlj+kTqt!!IS3rxYq_@GIm)6np4YUiwa`(B$0cKo%8)^)4Fr9fI<2 z*9dBRJ_rly;n0=lT9QWiJibo~<9@?U?{UuZ6qFa~5zebE=UNAVOK-aCkoS_M<(>QJ zU~e&ooBa}Y8OqV#x&xyqPVxcz^6?%ce=qU{>Kot-G-bX3wM5o3cU48Uxf@U$G42M` zM{ENAZSj&fDb)`#?gj+OsiP3%gYa*1Y`+{c5B}v)vmDnzj`fmbX>x459HR*`=Qt_H zZppDXatxb=MVyBmi;-h}!hj#Mml1wo{Iskz@DdnB+pxf=NLaqB2Ybxe#R# zHm6~e9YsyQBp0IKJ=ubDFIto&7lI})Fv996xDJEhLXi7V2NZrEwjoe@pqv?MluZoi z>2Mde0_UWvCG=Ib5H6@X3Q@>7X$S_EAI?e_g4Q}I??+i`2P`6Y$6{YH-sX@a#Hx0( ziMMYr# zFYd&rc*))HVb{Qa3cDNONKm*NT|l4`<+nwxJ+U0XWfgEYXrV_ss11<2LBr<&kvG=xJC4i)J%xY9ZG#9;`RBOH#9?9vE? zR9zzxo<#U1LUJ#@LP$3%MO-x= zN(`w@&dIUcAPZx6WZ=#sJ@zBL2?&qU0I1CiE2r~5p~GXUZMAuUj(LYRxC5^7%x}A^ zwBLTs$t#}cwYh<`anLC@upFKu%J3x}c@CP=`?a~Y6F%5zb32#IdE=g19gAOj+y(7D zHP1O`*A+mtxb^wLhTZVIKlVa8&O1Bin#!5C-B@IX7UcN|<$)LP6i)&!ue{0dA2X?!9p`T_s6O2v;NtoZQ6)D*lx?IVk4r3G3V3xQB9 zgy67M4S{Kv_LW#XJ7S*vm0&DnWJ@p>8&wAEz4>9)WM;u>5o-ZUuPdIbSe^wKTFWgg zAK$=RXnzRZk0HCs=Uwtfz4}a(dEymhan3jH(Zp+qNTq`vLU;)1cS{Q+f)2 z<3t?$o=)npk9CSFatoy%MlF=7D*Pj^0Xrf^9;z+&iTYY_P=2Ys*&%E$(tp4RLD8QO zl8j{tsb8%?NY}LzA=UR-{PX&z7=JY!r)7$%&h$=B5l6MhaRv5qOPjc9L6!z^>t?zw zGt=osr00#`8!GaQC35!FRKL%EWTzhC+V*VeoV(!2BR@hoc_nXu-oBvxD>gxG^GlCE zMhV9}4`yHefKf5sX#;9j@XS}g%-iR=b2+0SLlc3rmZ7#IN(@0VbvJ9tc+?~(zozcHE zORtL&rEEfM45RHpj7uTY!F8NRj3ywqxX&-8(wvT`(i#P=P1<5hqm*J|or+de zS`^rb-XAD3fZY(%&2oNZ!OXH}r&CRRQd5SQlwF6$4|46P;bKy(YNIN+&%7Mcq>UbA zv8gZO>nv{0G(3@SAPEPyD#P$iEuDNOyIM~ zNQ_4~3nBUhTg?P5i;N#EMAmhL=>1uxq33Ial%pvK+avr2p$6e}gw$SVAfy_fijdkn zos+T6#XmQ;6mw>8ir}>FVk+KRD&q#pv}rPpa>scW%d{V5+7X%dr%a=g<~pv*G-u?A z(@KdkXSSD#(`v}HC>cjr!}TW0v?Q4}R;K03w3#w(u1tF^)85N8XV?lcFJcUNk!dw# z8cnM>uCYv`6kwoNWc?=5SHH?5Vogi@GSJgT@NZ#bd;^n9(ft1c4$QlM&$@JVqSL z7){m1Ug(kzJh)kq1V-`#1$m4cMnrY2U@tu&11w(;|og0XfGHOZVI-=BS}^&- z|425;C9g#~tjRus#Q%+KlIvhmlGbFCOZ~r*O>!%LLiXRHYy>!@vZmg_bD}JDUe+X2 z_X)W-AVKO;=Gt#bO2h;96$sMAW2A{n16OKM`w|DGavaq@k5TP&4nqBlf9bF$`!N!g zrC2=KB-hsBYOTqBF3RTmCArFLGv}V?nPk$$NII;^eTzhtVrhG!bb^CW8n&slmkaAh zw0t5R7?H%1@eU(TDp$a5a@v3lzIB8^%j+uz?y5KRAKzH<{ z8Z_I)E)omESuz)o5f_a?q!&8lDm*TCrOa{H9i;}9>{TM%r736KfbJ(9G%4nKd5k2G zU4aA#wcy~V?#1mle}|sLHAm*+G2)_yL9yjLrE)iOP%6h!%i%F#L{|y(GBZ;G^{BsUM(daB4 z)?|Nfmc84V5OBkJ@6Q{2hK&Zu}~u)*5uO^!Q6^1IY>L_P-@{EB=@IJ$foIpD0_EF zmJ^AiDA}BYP|qz&)mpxzxoq(YCAm~v9Ie#A<&w-dpO8xnLcDcZmPJu=d0CK5T3(k9 zYx#|n+Qqmd5sS$WIiF)E$pA~~tgNXJA(I46%0 zXFB8b$L^-?*vFrSMZQ%0cE^8TY@12IOE|k@_h2H<`(w_Of}3vLK~2P4NePn-On;np z$9W>o2%n0x-k7_@;?;YENoC;xOq%2HMi+yi5&S`q!+APpU#To4t&M@Bx2d|r9<;-6 z9D9L*^1PAI9`p>z?+tyaBEB8N*N6T@@R%Sc7WpLoq+=LlH4^0!f5FrSNUMu~DQ_l7 z@Wb~0NNfR$V4)7738kO|MuSo^AkBo7P+Um_s3G_d1&!7|ipoLzkL2Lvd{S9Z-iNUA zO+cx-_lPmv0*KNwsD|X(Zr}b9oD1h*6m|6X@!j;Gbv>a0S-n zeTMW_49QEHhGMFnf;sv^t~YDt%w(i^MGUDz|{%1=L!-k5v1VZxiT>z_A1`t_GT zzxsMjxp7fF2km+6`{1ux6P9(0J zJtf5cW%na}awh8snhtuLzjk_H!0VDTBR@ZT{zciHCp~vP{4HTx%)=?QoHnyhw4SFL&U z%9{DNmh{a&HsR8-0b2k6I`s+?`F2vb@wowJoR^(9s37-@NIoiN}qb+&q*_OtlQ)Ce$wH` zJKHa>`F_YZGnQ7X2=DQI}2&yc~Z2@k+<3 zq1A_d^JC4Vkz0PBY&-7MJoS!COJ}_*{maX1aXTA5|E}qW?AgI1w{4$ybwbbhgK4+A zANHy`ce7_D>Ac~DuiCzFO}#0dr>P7v!(F_}Tza%?%)_}aIxp2{pZc!M+B%Z_lab9! z?X2y*PhDf~_0Z>ImfvmoxV+oKk%ML=zf{NP4z1`txqRroJ%iUaT~y)S{%g5M-%a@} zEbo^`E#i+IKjoaeq|f=yCxf?)&W#^hV)M^cCqFy?UE}iaf}1x_m&#}7fv+cgv2pNg z=Px%7iS6Rif5)4ey$-oFTr_4tujdc@mF%HTcN)`v<1dY8M&zG<`|F96QbPEz-cQvoRY;zJ*f`o;D3_6z^*dhK26jq1$G@{@W^+|~CVue4e#kFIchSas&1 zyGLG5bG@FF6+3F+9b>&)P0Ln3_fzt_s+}f%@OoH#=Y$!f z4h=gtB*))*_N`{B?`qe22s6YEUwlY@P~)V8S-G~V54iKD7JPdr;#2EQn@&}!vP4Q| z%7DfL6Oe|x1q{dU$)^Y}x8d8ua)?{4 z8i}lve@h2^VEkIjp`55yLHH%DaXuq4)X=qB=7%(>RkX8)`_Hu9sGuAthWQh}B(d*5 z3;Pt7~~ zJ#PienR204(M*bRMu%G=Ib}grtLW`Kee)PGyFnH4f@U(~N;=bQH5} zhgBGc)+1^lMn~mBa%d}|T2&LjbX}wF*9t5wry9c~03fyJs)giKXBa+P#?I$gZ`T%< zL%Be|z{OL}=%`*u4&}t0pX2Q|dl#1D&M*Tk@>8>roLUS+t4P#-GG^}jrLdgZ3{wu} zBemyRh2+#>7@DJyoD<)4hm9;)&K?Yt1v1qf9d!!HsSB!FMXQQb_pc7F?owFJXADyb z07*{WLUPb8A&2Ue`j_YE`EiBYPkn}24^t6<7#;Nr$stc#twJVPeqx*cjO96GPSJiE zGK^(8Hz*{>lVNC8f?9Ul7JmqTC=kvYY6!DK@hZQzpZYLh~8nlTKuQ!17DJ9dCjuzb82 z#uj9$zc(u+2hA6{Xm(7tBQl!UmYRZ%)BBiQK*(FkF4$Zk}Or@i`OtIw& znAuAhdUl$Q$}&Y-E2J4IPaGy<>dBNvB8BF@Ji1Gy&}^1RZ;F&=GNm-?o*xp1o~l(+ zK9ebeD5r%;@rE28)rpikjN)MkZAR^w4)Po91yH1hz}h3D_%Hx|sK+ph7qv(_Xxvm% zXnf}s>P2*rC&MV-E!jD?aY>Zsl6JCw4AWe~P%r0PlCD}3r8)I0I%tezm}ZhLYS)a? zvIPNfkUivbBn(+3PNBX>2iX>Tq4Cg!*z{ONzShDQ=Q|{@}X|h;`3?pEI zEpt)c)hZeT3G!e|_GB{`Hq)|$VHCQkz&RHI>K=)~=YXg-=)lG%b})=W7gdT`SE)z0 zcAL5Oi(Cw&(AAo8SzZ_SJW0t7k&9szy4omobvZxuwV6vL8X$&I=%U9A)GAjJjiXMB z5f8XGNN4m!HXRJ3(DenV=Ic6A-L|!vODA$Mj6zpC#$~CCdyJ%GfXKx#3SI3Lx*Au> z`@_sNUF2dIg{}^aOBxw^BsKeid)=gKqsYZD3SGX8OKKaVGygbf=DH|yF^oc&hH**P zHS&7*CwwFVS$HpUF^oc&ALEjAB{m<|)67*zY+4MX(B&_4k@Tz@b`QCCL1%#?7sDuY zX_0EKFV95dW;53yk&9szx^#?-%8(k}sGecJnYreOTnwYoMc#^8*Vb)~)Ml=oA{WCb zbOkDOoh&u~iJ9xZ$i*-UT|o+6+Z&`;HFH%EhjWHe=+b{gm#@ghFbZ8A6}mj`xRx^O z>L+qBj6zrNM|8~)xfn*F%b?KprsB*&W?kDvE{0L)3SnH-4ynHOO|i8xbKMrX7)GHh zRH19?u@ zVi<+4u1GbvjaBsnj+wbCl6!)KVHCQ$fog7tG%oYm4WT=TTnwYo)m`SIo|1NZ*EloR z0FjGf6uNpaF6p{f^)>b5Gcu5cIU*OsD0KB?T#}t{dvVeyXD>u9hEeG1g;aAHR-DtJpP8$cGw}*SFZ`<&y2zbU<4G~1V^;6DY>JtyqsYZD z3SDuGOS-Nd2|YWQxiUm9hEeE>XI#}pUC(NTZ8vj$FLE)ALRW%9*QkUVZOmMUL@tI= z=t^W<(sdoWJnD#<>$%9qFbZA06}rZGPJe3Vs^x-291Nq-)dy5_8U7XKQ^Cw-5V;se zp{pUR9czYlz6jFbZ8sj7zc`{qlE*n7I~aWl>{cC-Wnd_y<#V`t80~EUE^o-0hbJd~C#lbKNT?0YoWk~6tyV#!MD+6>EDsnN5 zLRT_U&24_(sMH;1uAw3q!zgs6FfQuL)aF-wJ9n6wYmvysFbZ9R6uLU>9bC@Lby(zL z7=^CEj7w^VUeULnn7LkvTnwYom8#J7ZL6Ng&0MuhA`u6}D0HQPYHo-2uY5Y2xk5xP zhEeEBXIzvODve*i9uaTm8Y*%zj6zoi1fpOIkxt>(At8C_aAaW4~T>KtlBtdiW&)2c( z%zQMC@7q5O&+OAdEk~^iw`C_5KOtrD4i;0=z(IJPW&pm5DxUOCO-vM{11;&PiTo_U zpz$}+OE|@6f#`$81!)QRa&LNKAu{`ZcR?)ESCANwFaM?%;_s7~ZsK2Wj8Bbk*7D=& zK82DCer>v-QWBq(JSZcbyE<<`H1wP&R z351mbDEdKAE(;AyYB;=&@g8Ct5}THmn3_)C^;A3qXFUhzDwIFY;*pU&Bq=$;qacIW zRXo^2Ymuo%FtZL-1S?M~f{}H)A{cpE5sU@9U=cD3!HOf!M<|Xopgtl@?3Eu8Bq53r zqUfMSh*4rbDoAPxXo?>dW{HdM8=I8u(X>!w;A$PTxRoP%PbC( z%WPR}nZ-eJnXQT~vpC34Rywz@pR98c#1$J+(!i#81g^7Qf(s9mAC+wd{!#Ikqw7ZnD}Wzw zz6$8aO_l=6r50s16i_a;SWqstMG?)|iqv93xzwVpkrk=Mf^w-v*&{1biv{IUeTrWK z#ex>ES$%38l&^_^JflS!5(ShufMP+p)K9h*b54r|3p@uJBO`R0 z5L1XQQlrI(j!Xt!XkcUz1ww}oCVyX3GkvgcXlSrb8y@2C+rdMl@u!~--t5--?Un0iRPXhg<&`$?1UrC3b#y7~I(dx9pAxuY8mfnK>dieYCP#bEd z#!+;L%9Wcp#UhEU8zKk@X#ie-=-i0x!jnj>qstaU1sX+yXM%PK9<`gH!d zHiO=;qra7FE8-fgwG?mC#QF?MN4y}eJV?w$P>6hieqp|0f#G4H9SsK7ILr-*T?lJb z1Bsh8Io1%&-BT(_@#0w9VA`Ac3eHVhxAbwhIGVL;+0v(Z^VU9I7DPmwHEr6mWlMK= zpH{7XI72VzgmL49mUqLFJR7L+r5?USXZbV%QD)%ZwmeUhf1O>W)j*>}bHp<29N@lR z!YQ<(>MOYVS?=Pe6k4`kFJkDN4tLk^UY0wkiFO)#Z4l z82;&?88LmV3vqDuvwKy)w&9pm<@>FDC&BrK)_63JT`G$2?W;icLN=EJ}_BZ zIj#}{Yx$!)eS@~4&*7hrqViV>@*V@@n9p(L5LlB(**^}l;9Bm5{n*cO)L*P!Zx$Nnj|cFq%u$Z>Dnj0L(5oCrS>vCMqVo3z^d17n;Uve= ztrKh4OXa*7n1yFJuBiG5M?!~&-)P_cVqmu2B?b!U|wM z`n~OoOIY#=mcD+}S*crH1Z#b%` z{+5g6G+^F}I47K2lb40-h<=N=1ia(&ifS*ONS^qfW29ee^60s@-+;UHfuqoTtd^fE z=#2z`Ee>n)ZXmrKaJ5t%Th#Ts0M|prNFuGtqh~|to5dq-xV)nBcN)oufmuWkc;Fy= zXieUI)NinzN@(T8aYfZ{IFc7)kbC69aYgmF@6nL@l)yKYOLJUN{i8Z?$AG!-#&Nbq z!ym--6MbiEnHl$Q(K%umRp`u(+- z^0otas2K9@6jRdDDw2ZwYX}d_o@8 z$B|;nI}hB=PspS4Q&%sZy($Y_O%Yp^J)rj2u9)&V0oUUb^4uYBL^0*f1Ma6!$Rodc zPch|P0`5*Rc2IC^Axc~l^@vyeKF;A0mmkGb`({=FMw0K7r0)F9eu?7BmQfN7$yuqzOLcEmOKB5PW^meA)Id^ z9PRQtSqN8H9+gXvS_S)gVR`Pr4J-z(4RDi-f$Ip|zCyUd`TGnwx7wf1Uj^V=6$AGL za3RIO`2v?)2v<0N;lLdz2Cge`mFpC|j>7U91D93^SGYb-0k^0SuCP4vZ!V>?x zv@|5i2l>kdk1W@wI|{ZxYA@3Z$%9^tU5F&73;vfB#L>E=#ZE-RHHG3g1#o!nui)

    1S%yHgoG!G9k9Lj)DuC;C5nPgP1>zwQy( z3mKc1*d4d3u!S-qF|{$Mc%9o9ZbC0Cx!~R8p9`}vTb06)r1;d7w3OcI?)4)YxQ7i& zPa2psJSn-4yFXq^lQbYPmFFqC2|d5<;C7MaDm-OKVyXeibpMp(^rYmBl#DdIMu8`* z1aq=qMrvBRoMK~<5)nHnDM1#gwnz!bj?jU~2VQOS8ASGC8ja~Gsj+<${ZoexN>9-Y z=#!F~l-_q>RC531lp)D@UmM4%1namikw%Tqh*!#Sm`xEdzoc|*OzoeT3b4PQzbsZ= z1RgM*zaQQsz{T1Y0n-_c`e;$42e5I4uP8Wim=UjPm##-b6}TP|)y&HWIZeab3zt>k zawJr1F9oW=MTjV`7A+O10@om-S~TObK8MD?kb8`qVIhGAKa;MDzb-sd9~NrThJ}Vj znu0W;T7%9MfV-3iyhY!^Z5zAR&@ipeqz{eO81!11tP&VmXV8V{LL>1;3y#Li=n1Wf zjEvCxMMdiHx)7eA<_VFyE|GXyKBw7onm@ZOiprp@;QcE+(N0tl8mW(rF-7PCbP>8x ze;wXK!PD(6(^+X!ZXGx^JR;1WDlRk-8OIISC@x#NCPz_mSP08}1yQ6ECu_s}qZnPv zr?Zl7ii`=@2{lC~mja0a5t=~8T@8T!tN^=&7^s|x%_J3AWieGHSf;Y#kr-_hNvJa> zmijS?RVz~EJX1fWWLsr&q?T0?rPwJ_!u2fS77{Q|)C8NN^+vs)-he`9bxjF2EFnD1 zsAo0g1{FlMWn`nis}8Rp;3P*zLXqntB2AirNFCnbCnmYFBn>JeT7z~`Ln!Iih1Sp5 z!S9r_O|+(TGPBIK*dg5pjWxm)t&1>HI}Oovq%$wP^~1sKAQ~~T?!0>I;#MDe!ok4>JB*n+3C#58_Yj$E6r%xD=XzZJjo8#G2E>qx|4FVfMyHD;=VNR0}mPDxdM16Y_2f0Msf=g;i} zkx)VYrVyilxCUi!VEtVti!^EiL{l@UMuJjt5ZRW<#z-yI2+J)I?T8o<9-uKsGP(q| zXW$spWnh;;UXVvN*8>it>e>}DFGH4&z8YJW%}qeZ!=6qP_JBAiSk5p5U|4cHio zw;?&WZDBw^v=9PD8BGC*qA5q{jA2m`kVYnwKsJH}2>hXBLPGTKsf@I0@?@7jMP_2YxAWu=DgC$6z5atcH z+A)+E@#avTJ4Z_}D@p^pcAy2afrxanL|W*!fJz1HYzd8`5yD^NAEeXzhlR)Bo%dX` zizUbifq+HmIz{PFLo{wv*_E)wupXt?YN9oIgT@d2R4U<;mZ%UtHUVJ}FvH0CAYr8} zVJt%ddTbDaLu$s7J4M*imRMGX#+XoKUl)N!h`uUi(A5%$Yfz%3@^G_6F=*8Rj2m5K9hU%;Hy9-V%fXKa9#AH$Ql41=L8ZMT*A7 zUCeYXON_>!T+IkgXdpa!a-FCp*S19XhlK^}btd$-NWAlm1L`ONA>nWzOyOY$y+3(` z{yKd$Ms?}hJ(OTBEh;=5X443m)F$d$gTc<~Ok#1#rT$rwNPaakuwIeC2<$HNkCcJ+ ziv*$!L&783l!;2FL6Ja%PGbyWlNQ1?ED}fNH!uPl{^Zj3w8V;q7zDps9!@@20KCIZ zK|1h9$hFbPGTlh-H9Ru0+T_}xSsLZ6u_YL`$*4C{ZzzP9s=A3KUMbvYLXQpWj5?H> zR#QtbGndraBEk%8l1S>CDG-HvqGVlB&^)_dmU!0OF;RhEsmInpV+ix3BxB%h2@Q|( zGw6*$u)VVBml|4gOPuJXDlNKXsasegjYdOM7ZWh04aIr2?gkfcY~?9n-8` zGDWQv=umw?fKF>FG)zhT*~b#yvbmog-7F%EJPsrCYN$vR7HqD$qgRLo7U7+ zPH$s1y_uZe)@r(!oc@K?bZb;LwQ_o()pWC;8Dup*K(;J;tLbqe6|E0G%l^%%t&yv%~BQrDD29In%*(MCkm&!XlYFej6!x zy-{is86=D&n5S#}j9~_>Et#Ss^sN2~Q%Z@6f)Qd@DFaF?0YPE7NVbqeB|{R*C;?rm zkjrwh%)YX->zpf+D3gQc92}a4bQO zHC1x+DM6aCu>>rM1)8X4si(kpkRK^sg*0j7>LVjKj!ihQyh>g^iIZk+4An&&fi*Eb zrucH(kfv-bU7D_A%_xZV8ImB)*cc)LT@uTTtaV5kk!EWQpby3RpvHjZ3O;p}OG}!y zF%+9EnB=xX9tf$DrfL=#xy6tLB#bmkV;Iz`E&^+JMyyS1<<20@)EGp{Ew#A4;K!yJ z%-8~TY!JX2M~E)O5B@EAm6QzQYfjc;p*9k0+YCXoL_)v>n-NA`B(-)Us})Lx^;M)w zYqET%NsGyZf&n(8&^BQ#4Xny25f<2-D6TZp{7%Xu%&j?{M+30rfKh_P?}P;0ztKdX zOfW$V3x)kQ(DE#`JW9kZ9F`amp~n>65F>Np4h~DeB0P*LY%G}oNu;fqC^i7THZF;@ z6BDJ2W$T%w%U(>t`d1J-F4ZBC9Yiwgbf`Kb#sdtw8gWIPAdZqqnuaro2%u^pfRhNI zwrUE%%t^Lbl1XIwuKnlY~emE;35;%82RWrPG3=8Y{}EUSkwI z19tC|HJhUlrV_9=6%m7RI9xA|y|70*)&VKqMogyx*%TIFBJbVAn-A;jgi(taaoGZk z)8ZlsH3I_J767oplNOgL(N0Xnd=e9YAU3EI-Cm}{hk!NHu~tPX4w5)cD9v{Cfs|oM zm!p^nGhu{F5Q%{!SeEG|CZg@|wL8{5NT#znMO-h`!HJ5D;46ECa4{n|FN`8a)9`R~ zAsXxnQ^Ha?L&>U3n%P-b(Xj!Em`Yisz`bGZo#>@4g$2Pm3X6ydU>+JP`NM!14)<-&RhC1A>tN4j68l!8L>uBU_Xpl${v`|I8l?G2v0+A(~K(ucLb%|T9s^GhqGrVzRV!`A|3O^z~(`i%kJP7vMGp$RdKQ_O`RX-+auGF*PR zg~^tBDA`#~maYe`HSRybYv#*nQfuDKS?Yh<7A06+DU^at98Pa zlyMkl*nKOxlxV;sNGTa2UB3DHnuwUvGA1YzH>0FM(0j2g_<=^9|;{Dbj6at z%rV4t-0#C8s*cZ^C<*fnF^SFFL^DPym}!`q;F*Jo%&UssmlTsQUy}zDy4yvGvNB2x z3O0nW(sy7f9mD)2BSpo4v4%|}Y3U6E25X955JO-a;bY(sO&1gO)y{e?{7qWkCm!36 z@@R3B(G;l(#AgLL+~K2e){{--MjKgMJI4yrB2)S>s~6A$(g~}$fPz>wp-`>HK;}3a zlTo<+twlD)H56py4H5TLad(_g^656FMr3ugyq-_9vhERpfm{>L49{_78ZK@a`Qd&V z_<$kUAEl4P8ZSNf&1M-V0I|)Yg2r70|Hv-f9#SoK@o9-EJS{4++kVekVUhiSzllvD zG}zOML^%9Lbp04+f;TaR;d*U|Q7?8X=_Wdj1(XbbMVYMYEVIHJRivQ<8}uP;0!Xaz zNfpW32y7@|7fPvcN)@T-Ski(ewQ_>MHB~@x12j@r4);`%NOygaH*ztF7jCK|8N$N? zV6z?EP9YU{Y$Hv2FZo=}&YQDII;A_(xgUm5c88iMPDFtbf%Wtcf(hnwoQaCNKJbsp zKP6xZB4M#fufeQUB9@QKxT?)Hd#Uzqq3^z zy9^$Kj*t7s7_o|l6=K|6V%{r}u_u9(X@H=eJ7gm$0lN}-g0uiFr(k1(nT4$ekZ$6^ z#sr>16(vsDh>m>;A|1OiXtqvE2;_^sMxwa2jK2055<4_$V8%drRE}=7kYjptPqUV$ zbkvz6+puA>wqFB7hNBzp#Ym6sBW=Wp95yHs#pK9#AAnAK3E=idGa7A)0F4?v%@a`v zTpiz{!j+=T9o@fHM(lj2$K`Y1QKim&ntCP^4BofN{XXooEva796*|A^x;=JvK2)W zmV&eflioiiAyJ>4mX3EenwmCk+6;}*(QObO9t+1Df!eSmyQKpOToY|dU}Z(a1vv*a zbYZk$#Xwav1h4lkW2eHR-Bl)jO4ksVIwU1Efn8!cPEnG0-AFn^Q#s>} zlqoo^1L3rHDk5()GbM3Qs z$8tHC3Y7I4svWv8lL?!U6IlnRi=$O7XyJTG-+d0k%C?Lk!3Hi_ zG91LfOds`V>Kx_{ijt%p(v~bJqx(2a5OsuJpusr_!?sNLsu3~abmPGgNL&7bLTKrb z1_;-}y_sDeT{6!m<(gU=cZcBbJ2F2(=_SDBjM6D>Ff&PHFeo1%%LX+vx(y+<9kG$o zT~bH3>9_!Mur9{L_FhsiyhV)S+?@{?CMp1O`{3u7ZnHa?#XbAIzD;y42CJ3$zionPU4~zmgC)7;KQcEEv zs4E(!$Q7lA!TeCx3f$!?r8noX&P5GMs&yK*;wUpk6$D)kH7v3h%q&vP?&oS~lPwl= z`5hlJ{(}HyW`RJoAjgJVTGtZ?Txw4{IJ0!)P_9{K!&rd{!gC0s=Nah8Kv&GdLpb#O z$`dg@6!Cu%zg-c}R3ZLSjMMiY-;43D5O;ts!Z_n$Viz&q7xAay>06V0F+p%wySwOj zK048V-}1%_Ubh`Ha&MV+tu8;?*P!~ssnuJr|KTPc5J_OTxs`Hqn>F8me_Owo-aQ@< zt@>uje7C;A-hKXlR<3NEWN3 z`pmS$Vb|9?ZQfq7$J0k42@}em>@Cy?TyUj#v&52-6FYq+2y+>3@N&Q9cDtjl9gm4y z&}jGAL*JCi&wiD5Ky&2tDRbLr{yAL`t}$HOoV7>VhRu80%W3dfyK?w$OGs zp08#&{o49-)_Wc^-hBBc$fTM?&kY(U;TCAhm{SQhJ4rL>AeMu65nMncj`X2rf*kV z>n?_y)M7!S54j@Q`wrT*(HwQIj;!`0Qk7rJ;nwpkLoMq~1+J!;XV3)^j$ z2A#t5-wfB~!D08QyWJLzu3`J*;+clJQ%)~Qi})%~#H2@tldT9p$f;edA4) zuXk%*?QwXg`7_j4=l2=iyZw*a4?gRDyEpjq(f)$)HN(w)m;EY06aFkIe%Iz-R?K|W zHfLn*YJRP5U7x$Gr*L;+YdlBCaBGhROMpS4c9YJZ{8_hS=&+BN*x zg%>5y;X9eIFYf9&*IT*2xyzT)Oc_|jp5wC z8}@GVuTF#0OU11FtI>dQ*G86FaNP6Z{4KT8Qnq@0wn`9oFx-7(_S|RpZXexw`P7q5 zLCun1WbSX&s^0JiZTbvLyfNd+G|cQANU!VkzRhf3jhr;Q?&iiBtuHRFSNr0m=t@V% z#ErkB8#iYq-to|t;iC6eYkb|_Z?cbic;~#{OTYUsa8bury{0ErP?g_33uLFLKZCK8o+k;o(qs^_w=UA9)4$5RN+cyIRra;;#I^6JI;K z9$c~ByZ`KytDd62jb*rr$FA&K(k7(qwYnV!_j%=6Ds}SRaWB1ckKQ?*v%6cxZpnC$ z0>jO&UfCg_^`Vw!gV#G`9%_<3(s<~2kMz8VfGM3Tdu=|f$MZ&biH5s6zvRiSL5nrX z&iAj?{qBd6yT2TexA4Mh$F7Fq-5TtxGWHUDScZFcqC$^xPJjK^?d`C>0nbNHiEVIW zgdwrz>Nm?v&zKP5&`J>2G2CtKzSIGJX#-zqb-%`Ux~RG~@9@JfJKuGmGUR!cr90Pt zgBc?|AExeK?%HqP-rV@F=euuf%=tDdch$3Dj$R);4lS5a|J3bM-T%T^#Bd`!Brcru z>yz|}&4SNp?7Os6B~16eqM6sbj%QfHuP?j7mVe7|)z%*$UhC`KUkq!pzS-K?fVZXF zH8|Dw&uLE@#Mo7j+da86Y&XN5?3VU&?Ab?OzN`24dgkYqOH`ZLu+~-Q*19df{yDBh zpSEx_THxgy?&_qBxlT{Z=X}<|{ov)R-vJoFC`A_Reo_t75ERxO!7V zr#kth&o8s|&wn((oKC1bvGd|UkNis~2b^qL+vD+$2PS55bKk83zIt>NH5Ryj<~$BUL0G2ERo z*X*<3wfpCbs~y)Y$XL)V>=*TmGyR74YP9(0Y0cM#VDNgtaJ$F8s&uMD=`jO`EJ4QpKAA9}tc%ku`PL~G#cJ{@&AD*VmVe0h@yAF+=wCT6k*{$I`^kKM>**@#r+l=?P z@~&LlYx8~o?iL-sCrU7u$AYmK)T8xHq+7r*XmkDXPr-c&l<`s8tH zr#)OLe-9^@7;wGgjXE>G-nnvb^=8)=O%%@0j(vN7N?^wRA*PEvF>WzjKi4~t!@K1U zY%y@oz&_Qc&l|O-mwTBT@y)_sY(HM9;W+p&C1Bg!)xXzXXV|*TZ&6y(`2Qv?xEG#z zv&!R2@s56r>TTQljjaRhOHYO~)ooVd%^Qd9f3*5_r0wSPBLfDvuzR<0|L&P#nOlyG z`+KP%EMvH}#|{VGy5%P%RPQr%-1FvX*H4v=aN4rVe{$Ef#d8|8M;ma#wYaOlb$#cV z6O&(k+@s%{tg2hJ?V8SQJ&ajt|4y8nh+&&$^JF4LAKd)cba(loSG!d`KD6IIY;#)XCHEVP z2VXl^3Ge%0xNVuu1n1D)OG|^&*6g|EJz#R1CSjLj{1exvOkDAz;_!R$km2LHt6ScE zkoi9GpNq!PndMqbVOeRJJZcleLjV22pa{?N)c;braLov+wWSk}JV z#>Pv}j{D+W@A#BuPgrYaqgdWd2EM;TQ7dG_nU*Aede|86Z53<&GL9Z8^c{z zH$FSlbBvo$=lUVz{%P5*{G>gjW_Imvmv!^2S$i*cTPz3%8Sba6LY%+*vMXhLrtT5) z4%N=iulL1IN4u>(G5gi{ciV=255EaA-PM;j-rIM&-ma2^pV$q&H1>Ljjm<81ZmaPN zUVGu&Al-<2X9XdJ;j~+;{#NOqrkh-@=$>{AY%%UT#}}tNZs^`%^q?V*W!`?s5`=t) zJJ9FdljUC{pSUQrFDfv%dkx z1+-Onb#TeH`9617PCjtScl%nWXYZFDI&tuqX=mCPo;!bi@l7c_xNl;(o~7Rk9Zn@p z9#wnAD|c_r@O^I==KW*SGtps5Qp)RwDQhuKGu%?I?wK36Of6CSQM=3mY4eY?8JruM zozvz_tJ9^w(`g1HZyy+L`fum|s`r!qoW+mQPM%zRV(j4Gv|p9TUwWZ-+rOHWe3jB1 z6Yk2Czw@_j@|p*(nz5$3eWq<%)VYV-Q=U|LJ+{Hrkhg9dH7ynh!c>M^yt;nXE4_bT zT%qI5_yq?w)$`P2n!Ku7D}I)H+Zu7|v8i|m8N>D6=$P2H%+yw?uclsDef)IPclQp~ z+x)J==|LB_KC09!2jfSBDx^2I!ptTUCQJ*i*?*Yd_`aXdsOL9g?H|*E`gBfv{o4NV znA`XUGQ;J^#N3N-xaQw4JrA|*n|7pr+Sb#(rzZI>n4bJ<`o*>R@R>F-+`~Xq>gvq* z-;cbSo7=VA(tVejNA-O+XG~U&eoNCsr&mkF(mKX|cXiaY_ao*E&w04kw)f)y#<)GT z4^qedeE914cROqU(lW7EEEY!?uECpu!9QGgyV7?^uleqaw&?dBd6QN;`cmon#veVZ z`L66P2){5~>&y|2E5~nm)MsAY>1!j`9Y0w8){hn2X86n-cHnfzU(?uA~n>QGzt5NmGTx#k(IFZg1%1S1ER*{@!AnzBRM^ z!!}pHyx!5X=7B$F$E4Nz_s<)FuvZK>@%W}_;mpoEt4~%sxS&bUzgu5D{p#eA9t%C% zrwp0@we4=)9mY!%+|^#4S518OMHi=SAw4QSDE%%^udCjnUjDoEQSYu_`Dt1C9K7F- z;YRJ8c(u&lp^L`$@fmet{TH!apVw{P;6VN|^~mGnYG(BP9sPshY$E2=j63k4#!;ic z!6*Ld_V6znuNpM?+Y6t+^SOSl%I|;Sy$1}pCc^f4c1ZORBY$eJzPe`G@f$;GKZ)D1 z_GIl>Gq%qP|0SNU4Y;d!3~qeB^`@<7o6NHLzFC=)gIlUS&fXv9y{mek)+;XP59C5G z#$b2#A730kI`HR7S3d98dQRN^hRL#o+kA7(e~ZeUo5-SY`YuHF7QqUsrZE0E#*``tLSrsAJRe$8I-uiLjBa@Pc} zt~=_~{_IC}tFN#zw(y0Y$Z$U{d|s=f=U-nQI?;dHzfM=S4j&gLF1hJ9uL|y_zRi05+Uf6qN-Yvrq$QU-H}sF6bVHW!!F(TcV0X2HyK}9( zWdb)2|K{Iox!>&kJFuJjSgtB+>EG>~rY`=2J{>ud;pY6_aL*gRZ)R1ieE(Vgx?7s{ ztzOx>M?U!>dF#89_Xgiz1b>a;vK`-daGKjo71r|4b$|JF%^7{?T?dAhC8LT|u^`l_Lwa9$PrG64zID)}?5f|K|GSHGi<`rmCOA*b>!NcQ z<7$5mbB{g@xAK?S({)XHZC_ra-&Zr%oqYUg^M;zwbM9q6Pnc6~`=m)P1>sMI^RE1+ znags!0l_`Sbly_#+3T&wjJH}Z)9%ZH-n8wmTrGE z`Td{jpO*F)gtZJ8_}}b?W!$d+@Uz$2DXXiD4p}q);+K2k{*1VDc;&nXqgFr0xWI7x zyw25pHm}l@&Q7U^9zJ;2ZP%6_l@8yF%-CJ+|MB)EfH7U)|8FuQi6l%y5PMV*LWJ0( zWF%n_yP|}MWJ1U$Gl|%02%4BiDJ|8Fs@kg6&GJQ?SYxT3YE>IsYbmwWTJry#d*8d0 znIyVoe*eqMx$oR_?tafXcX@YueI45NwYyjrY()8cVUzR5k1CFNvq`{#U;k>`xnH#p zJbu~l9$jnM#DJDX{lD%CImGC`ZT;C#OGYejKXYTc8Yj?J+O-e+arJjVawj9vfc$7ucqWjL!13R_39gO(!~MU%X%I!Y6U# z4i}C#4!oILal)$hBl?gm{g%;XJ{>XfqveO*t>ZOn!kt;0I@SAfmA<{tiXLz8OzQMm z%R8`R8#bYI1JWuT?Us0Jb>BbEj_bAO<$|vs_O3g<&8W7s4p(}%vG%gn=zok(s(a;! z+g=}qzgM*5-NvDh0>5lp6jt=;*RK+5d49b8Tt3=k6QkQd`KD>X?=@W}cNm$lazW!q z-!F2#xoO>okNe)rNUYaIodJ2^PwAeSI{n0e>ApTaa{pBQugj{;?|=WP&$)X&e9g^u zVHr<`LQnT&bjB^UXZ-QUg3kUccV650?w$r6Z(N<$;motjUAsR%_qp@Oqp<$R=*Ieg zF=Ipa=x;jd>s{=0d7I_O@!yS1XgN79W%C~%ksG^WPJ5ow^}SU6i{pJGj_f%Rb@@wu z@TT5vo-XV7=Ct_lU#fWj#Fj_U=Z#^*_^K^SS1ca#{=fsTHl8p%cWmOpkJCFG&Kxk* zQ+@XJDWfM;3P8Ouy0x!n{b-*1^TSsAGtEs6n(p&7A*$c5x4kT_RxQ2TcGh;(3!^(a z(et+lOPAezaP#}=(Zl+6`Bi)8@UZQ*+V@GVR?FwBkK=I4tr?{|?)dCn>C<5UmR}gM zwKL=IeErkt@1`_9Yw+v8>Z?BCv=uX$(ak;9!Px$@NsIPmHE!UVe|n;>%c|4Yie7$2 z6|-T&=)S>)lJq{K`}Se*m7{MgKWNBof3bRiW#bX7H&pQL8hORMq*?#EF_62zGP;Lv zOw8Oj^3tn$muF~tH5e7~(hJ`vuXB&rH29|Ccg~+yfLv>dGW)78RypQBI&gl{fQXbT zFMKd_;|ueS6mGBS8h-D;vDTkGD{t2? z`846d*=D|9H$5Xs+Zo*lJ;&8=)aH|xRi4eAu)?%0I&Q;XeHIqfINai=)>r>$=&}a& z(wx$ba9LHj`(E9eYbsR>%j#O|y#-CC?#c+S-6V7NHciNd-m9?Az~~+vzh@c0aPXoj zKe$}2o%;CxUUT@9t0y(hJ2u;ucfHoEKQPZ@bU}kFe>rm9RaO8410z5DK_Yld&D(sWGzu!DQPxLspc-hnZ>Uo49J`1Qc^ z`Pf5XbosBhe8W=XKtlHGYlfX&Q*+wo#W`8O&-%1rYpQcf;>s>s*prOz%l4;Zj&|zx z&6BBfKQuKzzhPv}ucw{aGHgfH-?km9`^~j=SPz44^;K71(bo5dZ|3H+FW&g%Pz=A{_QYpdwdZF%zIo_IZYb3_r`}SzVG9=JtuDa={Y?m=@O&cvC8FG zzrawZ7u!T`4LkV5ygNx(KAI7tjs7H|k8h)iwQl3yXQb_`cKvPjb$5?fc6@*N@dwKc z_Z$DYy3wZW{>}0;4~z{C^WU;ml3rzW1&jaewWn}c_|V%K_s4zV?mcv>^SXdlhg;Y4 z>)hRM{)bS&hZ)_^7iKi6vh}y-tLKI4+ZYF_k4-q+pkQ66bDyj}d*Frm2#oPMttj2s zO&12|j9$DlyKh4JQ@<~JcIZAJ)NpTl|&eRnNl%QYP7V06DOpLcTKs7EQM9{*Jo z9ID@aC`S9XwqyP%m%L85`;4Br1oKcvceU>Hn|)q5FnfM0&yV&*w?4lxx4_V2QCQCS z-^77EIZ6>MNfKRV}J$LMm8n5qe-|hT+*Pm@RVXL3f z)vUFpOKZ1LOR7B6w;uZJ!1>6H`NKXMFm;T!>$%U@CEtO)yPMI?IaKvVs{dQ=-#?nR z@R8-MStGjN+p@jG_!}*ojeqCRH=$WLp%_f*_Wj>M=kKFDuCIA3ce9~z@TK8XC!Cqw z(v%(e<(VB}z74*EoMd!|hGahSy4PsHx3Be2{^oz`#2w$aS~;*Nrg`(bP75DCxzP^y zr!%^5M?@{^Jh8s-yNTbdsv2|jt6r-QCeEolFR|-p?chJZjoXcRH*^EmpXarA-mhxo z^2q1L8^cBvUfZnhd)x2#$m~Z&y`_aC>pVt1GrIMgeyd%<|FxaRr-x0NHmT=dUllB^ z`F_l{UqZgiws;L*@(${m(H**3H}-tymp>I%Z!~jSGnW^heDPMokP`1bvY^SkUG8pO4BIc4(e15V^_3Y9 z=gfK#*#DVnLBFBK{w-ekAhTiLHJ!FK&c1);Q%O3-=vq!{Tjj_6-2nktX5tO02GCjn+x~t#P zzVE(SCq|NHGrG%5>z!(}VB2@oHcX%W+xn0mTYTDAjp;C_PvK3ovGt>o>m}(LqkHS_ zz}MFAyZkKZ!ks;J*QxS+&L!UXGGk@~U%xi#bDM5~o!GiPr7IPfw$5DP7kKIV&U)jo zj!*c0U21%bSss5pS%2i(oOjfh@Y}kKuI1*c^%q{gD6RhC&TajsXOq`X8tJ_2_BV|e z%&$6c@1rMsu%6B1%f2xA!u%c+r?;;-e&9;~z0ULR)e7G7(A>9smwHWSt6sr8paZ4* z@aBe{ug~uiIrV9k8m9(TyWZ+_*B9sR9p6#^edP7|Q*d*c^fsfb-!P+f9qpjJ!~<1V z4qjFB!mIAnKL54wPQ#tuI=V0PKBtHM$LOkMJpHQj7ma@TvrW#~mZt)B`?mSr{X%L)*T}QSB?E{i^q2KA!r< zt33;rHS=A3XxH8Brk|h5UvmGjDeKyC|48iZGP+rT{X=G+oBHDPN1Z=xdHBTGW&;N6 z`8(T%C&G;qzDRx{hav3u<(pH6{OE{}S$W9qy!b3dD&J@GGm zGb&wRbRRxjSmUS0p%=m))nD7UZiTgW&VXRigkv$a;o zC$o30egEB8d(P~+Jo3SjmtpH(WON>`-Meld-f+#_z@Z86w+uSx{oRXSeN<6>>94gN zn+;vu0{uRyGo>3d;!xbF#UpilGh8=}?c3|;4(}~Ed3x5k_8t$ndf$F={U^|ujPAST zaW5a}FwRFhJZfob=lDU9rZwtyhJcgX1KPNpi@4Dp>o1JXIpoC1M|I|GZ0g+Wo0_NF z{xIi~_kLsN(KlaPb9m9TrKeBfm!V&zbVn^T*ST5a^YoQV4h<=Co$Qiz@~^W6r&|8D z%@lL!al2)6u%E~1?k$dA>63n=#$%tS|ADoir*&L5^xd^?RVvl4^?MckJ_x!(<1YAv%lrDLrHoCB zN%HNEtMrUf*30&WBpB0U5`71m(&G|RqFM*FZXJaS_ma|+6HJq%hJ-~8#_1@~HjUL#)x1h8q{<=A?tFMrxb5l&Elnae^r&H40~GqKwHg z6VUJmG;CT_JWl0B8Pj5;aAhT(VGXomS(A>d%Hpl{UuVncR?+OY=Mz%OTaQUm zDfn@Sbdv)j!e@b#jVYKWL;RJJEk{>jP+&r`1LRrkSo)cd@~xUNWo0yB*{-}1B}Jv< z_bVoqHk$wY@Nh)VtP&OrgXNZtObp1Qm*p-Rv$*(#vE{8kiq|;V8083^Vq<|gWX1!{ zGLC(;S^5C^R}GvL1xbaUOTl-+<(^L?UvY`bT4Q+^q*7B-X+BrpmSl3t0d_5Z>BccN z6q}Mn5jmvk$Sg>7fUOB#Vn|~@Ph*w2|6Hd$Z>@Mtf+;D+G_L%u7>AW-`YzM~^+tm` zJ~r7AMl5t5hE6$4CyT^{e!t^0YHje&zODb#WY}p^5@*_*-?p{`bZ;UB# zO+mmUIiw3DMI}x#WTrxhmeO{PGcZUcm1?*DD-q3_lx^dblG%S16NF(*`TMJ_LSu{S z<e$*zGYZ|2aC6UHQ_&~LFh zKrkjn(Y}TeYS$5BRxv>xqc+Qy{f-;18L?^U_{lje(3QDP^e=~-ahxHMR&mPT&gd@8 z=EG*LL*j!y<1nL7UNAR}qhAFyIwX7PX^BaW*mW{aPR4CNj%WbcOfGLr78fU2j*P?j zEpL=;cgL7f-hC7(SKflDI3JQ|7#kByd!?mIP{)lq#6Lc%-19&-i;2fM7>6`9%<5D_ zntascpIcAG?cg{=T)OzhHR}&%M$-t1#xVzon1r#(hPY@*Z%lGx%XQcWEtecizg}7X zo@70bH=jH8M#iwCP+5Yp61w=El zWu$pidGnPN#k*>GcPx~Ch85h@g!q`Ggv80^&06s)W6_s4LJ~m6apjeWa!KXML923R z%35!<`4ltO;P|?mkPkBuwu0u&kv z_DiC?2T{7XbzIj)0)F2u+hV~H485=1Ob{4#pcpO)K=s);m zG7Tr|C-a)bJl}oqXWiW2UisqT69hsi)e{sVAveJrTR8 zC!|SL6^ci3lpm@p^aKg_mM|A4S5-Km6EHmhs{!@|qKd(CSxk`!l_+foI!rq87m0H|%GBKD%&5?n@z-r^2klQXBI zrU>IrVL7PJQR{QUT=973g!uq;z!RDi=C9A%?K?tW)QI9ofu)g%TZ7-OkfhPfM;&Dr z9u0nNTnWWZA95(&x4=Vj!v^a~8tE0`)4)dq<^{ym*{;Qj%Nb7wp8I9Dc$^{8fZvp$ zp<&bHsC4``7diW(Qc-Fx^$}x}ezn2bN$u~fQP*-m*~8VzS*vz;Z|LrafB5U{ zd1b8g~&G`aeBvn8O$l~ zz2tYg0GYz47JH}R%6nmd8B2ibhO12|m= zf$J=AHa)-Af9T)O?cBSb->qAtFlIa&{Nvq~q**7s?n>1~-SuTW)Tg*BA)w;Z4A1SX zFWJfUicDVlD)9jp>vVc9*Z;Po5dk^sSc=>)-i;{l_T8v8x&?J3h!WO~+5%EM?ErCc zk<=cLhIto2Dsw0xb)&g>csC-Sn?zlX<6>l=o0KGQ69taM9H;w4;7EUP9Mw3F@2J3? z6gbNOkAMN*7M*9VWg%A>t1&PEkeSPmfNeV$z9xC2M7a`L%B z;NeF&7>>p{$5B;s991R9*^jCT7;mNN6Ma^Ql#WrCSXQ{@;1xtF-4F9|F@bJk8FZE~ zpN?UE8K6ijgCgA0+b04F$`Eb|^Rx8!)?3sOA^FB3;g&kt;g&&l^f}Y~g7mq#@CVoO zF4*b=(9^O@7f_(f%5&A9xT4)uptJ1M=U;Kv2N&qHn|9_Gx@tFj_X|E6o)hMmGpJ6u zb2#-Yna63bn$qPXLO11ak`oC z@z8Ae5?Cm;0}uTld}Lf&g$(tGaJ!!C1`223HGoe&;bE@Sp36>4VZE?bJJwyx(2bJH z){Lx(?lYWevAc-=`TFi3>9}rk9u*xo-tPUiV((TRmnvfkP?>2YxWgYOMeIzH_5m}D(`)?{KmVSRx=hX*+WD%g-u=oCgxyHX85uPvusaohaCHtu;H#BHM zfuR)psaT2~y-1&uQwGUE{wg&DTV?!i27h;E^D^ro87)&0pt__%LW6>8pIm)(YN{f1 z3Nx9SFtN-e!2AFs02=|00Bj668qgn*23Q~#X=yafVxNZ^o9nYWqjb0cd+#&r_7?gB@>j>ktml&2df zaQAgSE|j*UU7RQEh2?nfYbSNt)CzbHJoLkE+?DL8M*4!1SqQ}@?$0+DDm~9!kj*;` z+viW)DS!610)BYTO!=GvNclF)jrkhftzf&MxX{DMGs2 z)e~iu9L+{FW!qKkmIqi?8Cck$Pt!^cZfZB~T%S`vWlq=cfHz2q0g&=#UqA25_45HB z<#)MUKX1U#>xX=9QUd;RT$1c_lRgo+jRMDQsjSKV5~Oi@L*15TC_`zY*b>&9+Z-01 z?D0V)T$a{{kBlsh)CfKP~NFgDE}m# z$l(_R&Ge4CGdBf%M{bmN0b9%OR91R#4!95xZ!Gd*{w;8cvd>MLCU9nf+bnQYtDN_! zz?~Gh|51jwQfHLcKd6#s;IS$;>J=UBngvB>&JBP6^pszu67nM1FzIi4H!T8CB;@K> zkt>qV75q7t{iXD%DxCo9$aod1h`gA8v#QF1pH~(6c)#X2DgnpMmVNG0w!o3qQOw}b zS#IeqkF5sBQlwd0FIT1vZGUothf^lqN@sL1G-tN9Zdl0piMHRS~> zEL~ZmY%G#F_qDV4Q?{r2NTvWCTb0%44kpuu&rV?D?ALAz_Y2B)(HHH@+FO)<@+wKO ztY@0Egm`UzDm^T2OPF_fNSKE)1apt9y?=GHc$;;(p{krPZ_Cd7D?ZsS1U$2Qs0g}d z_i)M{s@7-i)36*@&kAc^c-_;Qq;~c|taMuTA`#<9$U(DGGp3zQt8liNJIxBn4Kl0U z)fidivZ4iiq}4Q1FnqJ{XdsZ4&_3|-iOL`m8ZSbr$zk$>!ze=c!nX*IM(T)=70ee6 zAIB+D=oerH+jaNXfzyJ13LyO!7c zg`~bEBMDIZl6a{N|0Nm!rjul*#=-bEw+F;HHxC8Gcs5T0d>4@Ht@i*I0KN~n1n>ml zTELG0Hv_H$q>0jMz%zhr0M7v)0=xjY0g&?YDd1zk&j6nS?gDIzeC-B=oht1Cq($$& zfLN)L_5nr!5bI0H(kRRDa4|_fKH1~Asd6axd;}fY zwVaO1#OXE&+*X0xA#hYSPIq45ZVMbqIUZjnjY)o6Q_aLD|X_Xno0kp@SB#Nb@D&arVL==1P|-X)%*vP2z{4 zZDok9yzrIfhl)i><_^sgO=ZXrPyBW`mme65a0cx0sPJRZD)1>Xgm&r}8O>oUF|ru! zEI3O;N{Eq4f(;YS7~=$tU7Z(|il)&L_Dw3`ciWYiG4136t(#XU0)6pFh*MdY`FlB1 zrtF~7a@pZ!BRg10Y*8!=e5%QoCdaW{@ITZxBoC;4qGbG2m>I09Fpm6y(*RQ8DgXup zIslNW4EexBArhP9eUG|sfM zW+RQPC%zdvEL|4TpwlaZE(z;62xJ3MZ#kl%hgd*k3C9Xd{smvX`_Zf?y0q%SdDrXO zjMyMhg(`zmf1*%tDbNQW(91(tpHrESU04(y_;^$Xrxnu*iSrSv7rtcS)4)d(%NLfL z{ixjnJXr!C<8l3GqZYpzUt;UdI`!~jBZU@ZxFzrb7CKaHtewv>ZB*eiY-jtvp&Y8|n9#2U|7TENz>3-&NJiU~yq7;T&@ zZ1O0kl*lX@%z_7Ey{n4UteDB*f?9HRR=?oh2>Xv!@YHbDc(`kT@`gu)bt9`4K_j0Y zsxMOT_=UIxMAyxWnyD>AWWgA$Qj8!mg%N}zFp?1@!Ul0e=KtwlCgrb8c|vVaraU3x zL36%gEM5MG`Ugo4S3sU0%xfSKsBvEaq0@g59km07GP6Ak`(0U zl7f6(Qg9qe3XYp3=txp<9LWbx_nyF!eBe0J;+&2o1;>%3;J8A8BbmW*MFK}MgX3z* zK6k0Mz|o2okFS%!EfKhP1dg;Sr`s-YZ7}9Iu7m93%fgtTP4n~74WT7ro#kO<@g?Dp z!2P@#+Nv_bvxmOVycC;laRf}sz}u>$JjhL?zvHA_wT6FXp=~rwF^y(S)dLgG*^>7=eTzE zLSVuzp1Q5R@C4^YAjN>4mIEhl>Ozib!*1z99vWW=57$pK z-a5;EWX7UdaN>&2o$4%Ss?Sx@cNU2ly;z(QxOuI3b| zF^i@a`J;>$!3G>J9a0PrpcIiY6hgace>l<(Z@5=?;tH~Ly*AYhOB1C8jYX49L@asL zR3EuP(RL+TwFxr8=dgkBjYdW^>s|>g!YAx&tXY=@=y}LoR{XXDU8=BLg$H4 zYAD)d)JRK2=qDodOZdq8*I++HiMcu6SKv(}b-~!;X+*%6$>@5+$8(_Qzb}EYUyu6& zII@CP0FtEUu57C{y%e*RGzP85)nv@MPMe|bY)#pkOaZ2sp#ZBx;_JMIAcpEJhIgFy zKv62jWibUvLboa-S?aVCYqquuuqs4p7q8XKrb}jKF3pN(;gO^fNTR+pK=7!fB`7dW z5GfhXGYMBscSVyK$0fv@Sk5V#8H~OS)M*ttTV?Z5wn>jy zW^p>PtR{e;W_7@-vSB-4lKfaa30M_V(zeSgRT{OJMr6&Ev3Q~Kcfcb!*0qzBaHEccz_!#gf zz%K#s0>U;nKLGq1@G;;fKr{(0v6`I$q3O*2fI9%&$nVsX^Y9)GxD${L7wiF~_T2}# z5U>DnG2nhc(s!5@n~^v6j=ZsVb6lbv%GbR)&Ma`W z7Qk`u3*0(^`&8h*6S!jncV6Hw3*1wIqgLd3sV4i}rJ4dqZOPN^AaLOVrx&<5fg2}q zB!4;YG=WYrDTCq7;h)mEJW45%J-E)*m zX-EB(HDM}YnM#FJ5ls-&@$^$6w}c242;{EVGLIQ}#ZfzvVxZbF$w)U$x~R@80g`zE zrOVFWcmj6CyEh=2ZM6Z10M-GF0jvR-0tn$~CJjdTX@E5W&45IoE#pbRkyhgZj(l9e zaU2Oajx)$673NYaxm@X;Imf;Amf~b z5nB#}GGfmC^kY3k9%!?mjo9K-s&(;6JDW-kIg)BA$SPDFyZYcvZ~@kmvi54gl6LGW z3-0F=VL7R{xP%8B>rT^w6NN0kIbe;zVsd4jcE_2lyY(#xbs;~cx7S&I6uWM^qI~2{ zo3(+8WpN>HaHLnzseihD5o`rnx9h8a(1jc_oeB>)frxcQ2e2`js>`}iKSG_S3puBK zwH6i1a!6;nq6;{T@`T)(jL(MtB>j| zc{!Rwx*<)9NcjY)!!LQaw6&H(;WT;J*RmZhcV~icL|FC`VP-_YPHXj=VnCOP#N78Fxig?ea;QtBc);UWE8jUGxdXv!FYIVtLK*6e3RMO62*#v+ebGw_CmLf?ov$J5;rZgi&l zu$+ttxIi@#o->wD*CH|X_Kn0zFaJmjdL5nl8iz%~4!Tj%qeko^={6H}tYNFxqnWQ2 zaI^66^N>8WH{N4e=l~I#2_Fxo-SgQjlooY3?~m}kgGWPhMfP=sk0g+Fr`-!uF4Au6 z@e-(LcwyT|s{D7l#Qx?uCZlc6MOsxyb!PmNa^SP5gHEIr#CCy^1=GSFcmC1~&`7;u z1+`^}&z!14ZuY<$;R>lG%*h7QQ&lQ>l)VG%{-ZbOx&Coit-#kLwzDvK`JJJ*s&os{%(4id97BNUm=YXZVovpm;w z^1w$+<5dRfiAuwC;{=qa8EO_kNsXDJ0Y@qL3@@G0CmF}^l~k(tYYf#{RRO2RXh|{^ z@5dOfs#6;<7vDyuWU1IBn6Wnsp4m8J(^%ReJzz6Hs`2@(7$>C(*c@rh=Rkc%9A9I=veEy)QbDXWAEK?0rmT7WNXO(E?N7;c94>u8!CV{4# z7xh_Q>xWd<>`!L&G~sN?=%bKvgWzBC>KfOQkbdzDra2 zvT$nEP!_&YRU6@c&?Q%-DL6Omi};j@F*_{9(o6#FTNE9>!ca@TGERl%YjW+KYN7S4 z`5ePqm&_J2$Z2Z#2TraSRca|0txHWX4y{X*7)dHb53DIQg^BPXT3Fc^!_%u<^wEFirXG`>;>31^C+- z9QgcaW&Y0tj=RdS;UaJ(|L0G+aDua8Z4Yy+SRYC`(N7>Blz;e(3 z_*(rqTvZt#6;UHmZYZy{tP4wixE%ubD$(ap(X3~e5yl2;jbePbj+O4NipISkiOd`v zjReH$E!qgA1$ePrNTb|~jc6M9%29*rz|j!lII9pM_EdpqX%osy%Cbr^juuqBlhg7? zOW?>U%NhOnt9Yk_O5`ZKnB9s^0pUm|_+o%|0|s^`bLb$3Oc$E48E(b)lnpXn$2c(HJ8qAEv8#)bY z{u*!~AenT70QUe62K){Xb!I*VI24fN<#51@fFl6!0geQG1Q-X1_JPje3ndAFu=OFR z`GN?ncr%U4bU+>8B)~|(DS!h3rveTJG~<5;;7mXZ;4DBKDPj5i5U@MmKL&&?VcrP% zDj-dzF_$oJ0<-{b1$+%KAMka+=4h{X@$mTt`S^Ej9A}h6-Pk!lj-yV;>1ckzaUTjC zsWFcGLf|e49Q6*)dtcyae!+3H=*4;6WS<*^q=IWFaNPv1yTFYRIO-WZKAifMM=i_g{uDTBRgR+tFV0KW8ppK~xV8c}OyHsfZk)g+3fwe- zGYi~OfqPfrJ`p%-X`b$Ofy)!Pp9HQ@;5^hyo;_us8-9XZ!TAYXsKA8_T$I3#7Pz?r zH&5VJ3*35v+bnR~1n#WB{UUJCiE^D*kbO92AaKnDuA9Jh7q}`Fu)vBQ37_z_3WXR;#pC(ED^M7^aBYSZ@cpXvNe^j^`VPwdYFCt&R19V?EFUWtUCrJ{M z-6sd)C>5D?&~owtpI-92N}eld88E;UDM*_D-;Ar@A-Yo)mO5lDFxVr-PK;YD9cg{kgBCGXYsE@ZVUHA!mXQc+w7GTR$?lw-0vteey4;bsYdn2&+*E7?3;!)xmpmtr4~XQ7T3<9liMUI z*g{D0kKg14DOF|UqbN^Zki&|SrbA|#ut9dO?~Tyz*s069RbQvhL&7*gu2ZRWSshvG z-esiDxUXCMQKXS*5DnRn@&*hdsR6jq$P((;lBy#XH&y$2uJ0~(3!4bJO? z_Z4{4(3g`k9c`0yx=i>uog(O7MqBo@TXV?*l{exbNOKtO$`EwPF=>;d)A2)|bYZ`( zh*LJYYq1CtRF5#SN$Oa|UajYfxEf5vk+ocd#gM3ShQhMWfD>43mWmQmoz^L3IVf%<$R_3G)#jLWl zP(4C58k(*C^BrsD@HwUM4|cCv>eTsxO=2H^& zUvgI=T&a&h?wBz@k|1B$g#&*8j>h|KKx&OUfYSi)0?q*}0-O&By~l(#mOjj6xxf}Q ze+F0?@F<`bkOZp_;7@=x0e=C6h%i%2)dQp+(g3g_;621kJ?c-u=70|X$x?p^7y|eR zunS-{(CYzVak8W5_!_|c65gu(YhVS^%S_51db#YPa{>}Oaf=G+;l^9 zbT&7rr{xx`RjWCQ533(V3PV*poB9PbfvK!8)Az6ct(J+p81t9~A@MxqX z!l$T*K$Oh>BhX;f0NGZw9itV3s|@vEiti9z+94=gJFrJVq# zV@3P`R6Ryql~MaLYJ4idLP=}XW}%hY1qfUt5TZ6;VpOOT4atmwY;PK*SQ2Cmw1dW7 z^I|H4KDgn+`z#Bri7n}HFJJhJt0h_-#zK;Olz17;*D6pAbS@Z+`gkY~TF2&s(XSY9 z1`8vV_5cs9fGLaDq3rz(R$84Hjdja_4t5P^ONhlya%xq@QESN#3yzAtZDW!TL%7u> zCkuQuFjS}bsvUJ&6&RAioCX+PZ(gkI=?H-3j+`l17e#fM}$~ z`xvk@;2OXPz_oypfa?GU1AYoP3h*<)7{HBy@qnKLQg*%oOauH9kaF=A;1s~G0jB|O z0-OtoX}Xzq>$U)r%Ge6H0Puf+%K$NXXUl`z0YAh$Mz8rJz;6Ia)P4*2Iba@O9^gK} z?*aD%76Kjs{0;CR;2(fT0B-{x1*BF!4yXn^0q6#}3(yO2H=qw-0U(X1lYrC<-^0UI z1^M{LoE(=Vhq^JNh2y3R+!ER6&O{{VrTHqSTQBJL2;6>wBNfT%XzsyzX-SLY9t)f^ z^2u>j5>EGmz>%upI8qgyj#LH5#S7ecfun^iPB&NJ-VnIA1ny&jTPJYgkWZXfFZ)Vf zqhVD6SDvc^>Lb>0E@*FpO0D2nU-5b%%%Xm|h#UucW# z?GW%63vl8Aq$;2?uGdAtGgBP?s?tXVpZx}-^lw#&C>d!tDwwQ7>fzWlbO=rkL5b+0 zMey0|4wRGY4bPtcUW;f^8(g1IL1+}Dp$_b|2-%7xmuM>E`A@Zo{VAd6YmqRf7s@&v zWUobrl%hrYB6D1eME+YX((@l_5ju22TRv0}8WB2rmA)-itI)n1EN6B-4Nfd#YT+$4 zz|#rOAUuf>(iBe(2prO8`0|2jmWJ@TVxLqwQZv^YgYa*K7DUSLaO+K*s zBawkl?hGU@X`*w0q=~R(%T|gC0sG?pJRr?`E&x)^Rn|!6SisA8PXYWDkZR;NK+-%{ z0O<(CRX}V`NY?;K<6H-P3-EWqrGPg8NyFR(BnkZo;Aeoh07=u_2HXL72QUxtE?@!R zJ-`Eie*&Hcybnn7`T^j1z=wbr0UrU9CVC7=WAF(ewWt&FPwPV(Kwm&CN1K}fIs?+i zl^Y;!P`Cqz0agMeNlxXaUiA#|3WB5_XUmwHpe+5pPbH3_VGy$$2Ar> zDnG~3w2$)+5xC(3H$~uRd4N0 zr}Iad0NB-@yA(0I7`SeBYdKmXgsY6l>3L!{DJ27&%n3=QUB%Q3x#3RBj>Ri)c2Kr0 zU4a(1C7FbGfap++mhwcykn+t-FZb;oNoDgu)=x$U@v=7@iKtC||!#moWNqYkz%`?yjW~$S%fYgQO;o;qrd|c{r z97#QnBdN!6B=tCsGy%uGD{$0}IgYw9rz2^`aU{(+j-(mKku>AD>Hlk5&#^zW_X_P z?g3vZ-HU#hD%zA19TSgZY|)7^MpHCeGC4Y)PPWk%;;6kcH^c(!{;m7mr(X-uc(mx!$vK1_TKy|2`<}Pf03O zPm=Yq@=~%LXpoBO#L-O&H8ysiEJI8$```pfGGtnJILM3<$i z`de*C-;^r{K9v(re07LN>;7+Rj}A>yU6F|Cr{Ym^;l-+y#GvA+9QH~ySFY0efK=7k z#Wqtp7syrnI{dt9$>%1GAsU8@mwkNqlH=wI+)sk8P~d2x)t7ybT>M+)UQW-~tMrv+ zsd^Vj-$UtwCkR-HHV)6bnEb?2Xiz}D~dnc6tbKn`Qn+!-RE6Cqg(KdAZJA{s$c@KPzJU1B7KV$Z zp`D$8C0kKw@ZW`fNv_=TO%D6p)?`pu|O8fJDGI; zO^#XkG~l3VO$GFGd!vWWuel*CkKl8L_=JR1e(`f@7gQ;;Wi2A2sBU9Uz8>3;%50gT zv6iZwJ(j<_rQoVO41Yb?q#J^d9a5mr7$3n(`Vy0CS}s<;y(J#fE@bA>qDV9Lu42C! zK=QE(lJ0?L2u?39!X*Cyb~@=Gb!}BW77s}ay1k0ddj!EZlf4gCS(l`f*reVE_=zkm z3;C*mNj({6N;+LsPB^_s7qNZ-lV}Ty<^oKh${hz`toxJhs845CwRtg))cWE!3t#s@ zIvMNk?4hoStMxS=6>7li=H3W5?Z1Gl^_${?{TFcAzK3&l4~>g^OQNW)9FnE=YUSoE zt0d(|=ji}5WtdbYY&7icEyEd?D$*V)RHBs-%J@ANb`05d$Gto*I1H%;m6Mc@cWdE! z#gOde^yjgjVJ(nyrI-0D+D@gXv^5N0mJe3L@=0HFQWVX!F z2XF-5`vS%Q;*2I+<`@Jx4)22j=Ku}?d=(I9|IDueVmFTMy$%PY>KzUE1keCT1}fo6 zDMtaekl&$>*gNKY(kS4U0ODgzb}p6p_TW7Z@BkpalV!CO4_95};|4azk%7%|GX)*x zl;f5Q+(!bpQQ*jq;B+Si?u@`)61Xb@R|k0_4tKhASLW>?aGeE?_MbRie}TIya5n_5 z0#p&Fqf?jU<9nhUM|+|icTCWo61ejMcUj=DS1!kg-D{Z_V@Jl3wB+&C5jbCgBbCl? zGAe!n+t9%H>kFP2>w8>*s0|W$SHs0VJC}lZJl}mBaLHbF01;dJfw1Fw?g} zrOCG+k?QS^?bUGD75re*-zng^Rt4NbTR&7PWpB1vvf9~$6ctR0RK8%FWx6gh{9m={ zNWmKiAJ>xO;hTj=!>nGe5g`R-ElG=a9H#-zZ9FT1vA@cZdL!w^P(Tt_+?6zcnQo-t zCi?rU9BnmaJ6z@HEal;`*Oc}WzBE`q3mVBd?|^i<)Gqrv#=n!~Bu>eZq-TB|kjZw$sHcVM_GQ#oUI@|EXnFuDICjwF>y#YuIsbMo=4-Z*Zm9O}lVCLBlon$vwI``p=yXpZ|<;C2bRivstX zz>yuv^KKV7CNJ4l{d7B%FTb5BYqB@aB0tLLuum66 z=Py{pTB5y!^E&qM)LXRLH}e8^se5?j7dq*4z26SEYzwV zkIJN*|<)Lx|XGfXE?t357K4jV{IWjTzx>7f7L0%ax6UHm@Z_$ zHjBP%(Pce$($4xG$z{DrX*y|Nqizyusjth`74^*Z&gz+~vFJngO{%C5`JR8*8?Q~N zM6}@bOiR^ScH;J=tU_&gKwj?4t~eNaSEo(USaQSuir03K^6@r9W68?*Waum_E-N=o z!*K6daqr}gC`qRaDM(w7Wc;+9ozj{`T3qn4uu5k+rVBXE*#X_YAoSie`yPH@V95y6;=9G)EBBT*CShvO0(o+ zg$(OtIXygb`gs;pHaJs*iQzOpF~rSQjZqQH@$loEA2J`c^c+-f1^US*$%4oF@#}9? z=~8zgl0hob%_7wRai=1)lL?0*1{;$9U_4*3jZaHSijGZ8!0*RJV@#E~j8=z9WGuU2 zRf61O6@6>x>r8%AOd5U+hY{#OkV-h1vLvGEAPjA2(aKE?dAS1=X$Iq@7|fqyVke}h zvgrl&UK+gg5kgy7n;dAv!8x2CG0%3FF7-yT|zxGM)OiTf6cKzfC8M4u9pn844g zKu2j<5$O{`s((5{svM~N55JB=3L*%RG{l2nmXizE(Q5_83`f5aAq0L9OOFRoJCndC zMn4&kWj-^t{Tje}fa?Go0e%8Vwe=}r3qS}&b8A4<20J79COE0wKHey#F_^|FSX{4R-eSpU*L}}x;qn!}_0Tj-7sPodG=FZIaxuVlk z>GvsQBe$gR?1}g)F@}RoQ1rq(ca@|j#TF6nAYM9>P0Jf@URWCOa&O{XLEXvO!^5+J zRVL9b=p=(CAevwn&mw%-$ADO8T^xi>!Uk#XxcL*u= zB_zXBvp(zQjAnkr?8*eFAq-;KzNFIGT@>&rMP}J4w#1or3VfW>W;ot;D02Xzs*)RCWkW;8fl?Y7>WNu#4o~##!=i z?U{-I_LDpW$$f-}b8{bY=P_LI^rC@L+$wlD2lo-jUWQZQ42B!hack|&(m@Ri_c5cO zTyh_AQ7t2v#mWUGARM&`Plx-6gG8HJYJkOu3iJ^;oWen&oX$h|&~Ic8MkU68LP@!? z#(f5Fh#P;&De>CUSX1CR!7Pu7QO={pX3O(40&PnfqL2fwVWGsqeN>K145zy6DqW6q zmOM?al4lzi$+NXbAp)c?ASxBN79L(l+(+C{V3eL+TVyCKfa@3qrOAE7b&KKbxfTJd zxb^Vxw78GBXhwy!w9b+?&PCFq?X|7lS=(<>*Z^r%aZc_dPMUjx6Q6HZYU3(ZYF)9= zCDnN}kT@u8bsOO2oZLs8PN;Km4sw8Xxmd4ZLKH{p(xmX!pQAU(gE+fss6t@u`&dGhmNyajATE-}(xt!uYhlg`>A92%0 zIJgrkNeTBfQryW3QuJn2@pcdq%;XaCi4p1Wx#l|{UBnX0A zj)!w_A90XQRK~gs-WAourTcQctJ#tZ_j%%-b5OhycoerB9{adESmPe-%v74fK`C<% zk|W$ladQr$T7pM$%i*z)o6IFHM~df!MjNNLO@YTtaguCN+;VvA;|&+_5|vVWWyQ1 zjgev*O&WuVI4?B@J7$rXY=!}!0P0v!rL)+g5N{fA8Q?Op_{QMPg!^*neVi1Chkmcw z7sp0@*)MSY|IabcQ5teb^+NR&h!W86f%!t~yokSJfU|#ZfgF!PDdX{vc<2-f(Gflt zwUvxoOh-8lh%*`?RB9vQYK*5n_T79DGsPVQPAebPX)CE6IATzT3HUY1WYBaLxp;o; z)|iyiM6+0uSnAP8-+){Ym697Cb1*i$Z1W$3cB6JCy2;o-BnrxNGd!*Fbdht!zi#{V~|VgUqNq$>^AO+9TZpD*;?w(7tcnyE`+ouXbc8q$nW#&I!mDN*4D;{;PmYE+ydBg&W@GrM@mx^w%*$jmJt-9A5JdGE%VtsY$tyU_2zn8?#pE=~Hg z+8Z^zD#xvP_WSX-Vt%?atc7>}&9<4j+b%2^J8|vuTW$aRv1*m2vt~3|lm6?#es$id ze_vm9;N$8-=ep}-PPUwMw&>i!^d?Pque0G7iBbv1u-_&b%vvso{|KfA&(VcaJc8pdn zxc+Ld7DI=0NXfgrVa96*vpQ_6`s?1cS$WM{J^mr*$&Y;vN_eZPjVBij=w|2`5#<+o z;^fcK_kLd7sY>+6N_Zv9_5Srgdnvc;4%bi2?+oo4rf>Ax@S0u5nco=Jw(r38@duAI z{pH2)&u>uZ=e|*O{+f$v(wSj1YJKa}tkbhPTlaXTd39FeSDPx%?y~i>K;?bLxZZ`^ zSFc(Xd*tXzx15z@s~A&XdjH3vo4>v9^kPh{3kOex_A;6V_n!8-di1%5Lw7{}X1M%r zLWP^V6Q*t7l&hJ0vj6VwD+>qL@LF~{s+~v0%5U`=zv;rAv?&#o@_ICFm-SbC?I8`e z7JPj1XXoL$Q8ULry}M6pH*>kGQ$y|(QiOV8G;G$-TCn>W9G@-S-Xi*qXX+@>qkzw}D_;Hc3xj_-Um<}GvR^0Cd& z4XN~1YRmZPVg4yC7w^%3w(Rrh9?x2R?z$pr@6R>*B)xWa=7zQL*)_U++_lr!S6j@Q zkx^@24fl7}H0*S;O^o_tLiHY7*6yF>vvRG=+@-6X&#O1o9@pdi)s-%P9rW-1#eg3> zhi_S8==^%$z%iXqZ&htc9(>kM$cwNHWUQD%bhkXC(_X88S_NNy&tv*wt8==5AWZtZAIOcswLE)v7D_%V*QX zRRM3sJt7c@l+@g583c))hzrayU}lKqiQANp%Ar- zmJiA1Cg)Njo{GS#RkR{Oxu3sy8?t7fA2&ur^B%I|$yF>7k2|nxRaF*>-J~xolUKBLt0eVb(2FImdp=@s8zH;s+6lziFmY(2CGo4T*I11_?L`_xYepW z#8VwUa@rE{U|kI~lq+)Y8JuU7ELRnT*tVBfiFl}H(8nkexbDgMm`EUDn|7zI6Se9m z{8ie$YKeHz%%Gt)59*Ptd;PqsWIR+FwaN$4Q_GR7RwAAnz^d8FSIWhL;SX@^%sxLp zjD}Vjl>Fd!LA(|3&ovnh&E2VWLo^0+$#`f78})->Mlq7BSt1@95o%Qi{!%Wy$E`q@ zw9ii+M&pBcsHVu(E)fr%wot2Ry@cxL>n=$<;3rPXl1pszvk{&%|%vyIC@x7Z?pLAHpIqcMVF!gJFPp zs1B)~b>;`?+V=VJV>JEI$%gP~u$5$Au11VzGyc+e|8A-uCd-J_rXMzDGbX&g zc$zSpEM$SkM(r_k|16mwR6X*Xih@(l$TcYu4_W7G6|I<1F8XISpHwoQW{hSU;_-!# zT+BiJb?&Ns|xW~85b=| z#M6?|h)0nx ztxCib%xDyO={tBm7Pam3(}vMp!e6Ca!6o8p%Viv9wjcGV2)N-48yduYELB|C3Uh2c+4bs$Th&jV^+9G<8vA%Ez)re(^1JZCCV`ENDh)CxnYYT zONL?ED)EqxX(E-dPIF z#71-syl`FdSS`ktYks)Lt#=AbmRpd~NLXAET%nAMWFfWn>RI)?tX#P=7o)LBOUJkr zZU1Um>^*J?11+tWxfqR2THP3zl9u~|E(KPu0-1}^*rXN4xD?Gm<>IpmO6!u$#b|8O z3b#pX{CVfstX!%J#LGY5RNJHlWr;eZ9FlAF-OG)*hNZW0a{9yxfqR2T6)H%)ZvfEPAs-^y(x1s8k@9wGA?Q_%3*%` zhM%om+hi_AW0O`do3xG``ml?Y>!QrXXl&Bz&A7;NptRbB%x+=ja+eJSMq`s!q)l4e z3p(Dnas|s=jK(IdK8&k)9rBqA(9#H*i_zGm)z>DifPSmbSh=!fE=FUMRzJq2^!bUs z*U#bBJEgTw=3+E9Y4x{B>uz48+RAlY=3+E9X$=ru6g%}pK69bBM=}?qu}NznLaqI< z#?r3itz5n&nBf?WOC8tz0A0jv^?W~j^~yqkw?f}jK(Id;fzZe%ZH5fu2{K} zWiCczlhz2qMX{UfRk+EmQ+j(#=3+E9X+>Q)7trNVsk53Cz*@U*rbICJh+tcMLLDg{wR%9nTyfbq&1px zDRr2evumoA>s^_P(b%L#DpRfU#b0ty{I6#6nJ>NVlerj;O!L@v5d=yqK5mn)~*(OHcD@PZuA#lMdE=bDyEm?2*WfHjjv|WZ8uoC`p8_2#wINT z<0_sOpRochrORB5#wM+J#--HZ%0>D^R<8GDE=FUM)>y_RcO8lJvUOInSLR|gHffEs zN$dT=-Q2BQ7i2C*W0O__2wd5%&qp?YA zf=yZvznGY36vl(aQC@j3yc<7H_^nSR$Tu7SB9Jh3_JFS4E*Y z56+ItTts7=dIsZCAtH%Qb^>kp?H{k-TH4mFo?ei)d`Q%)qEs zf%r?VUWJtqqDr~wFfKVW9$T)Nz^GLx@t53|woUh0xrTUgEYa9<%>qWPs>g$+`kOam zY$|E}Pv#;Tj;mEgCS;hvF-96z%%Ktyk4ApuK#8ZB%tbV|sn2Fya*?F}xi<|_Qo@Z? zG8fT+i|@V-rkLk2u3_Z0ae=YpCKz$mAGx`B)T$uc3;~ybSfis8l2W5%V-j(biTo0u zX26LEhEFPvkDe4`#L)$l)ICxc7ENFM%U{qW8zz;&#Tn=qmr9@$l5sbdJwHp(9vPcx zh)F9!TE^`w_RML9zrQT!|Mm7AU`-~^|1SgqyI?PPk;8_H6cMmNNCF9@nFNp%4J{NY z0TP`|~^mvh&&5Haj~ryYIf==lSOT zrf&i8aF6NrPT!If^_m!6sy;JC8>_+RRy0w`^nLE%0`c*6O|mu)?vc@Dm_SqD;iK;w zjD;qqrezxFTNX0mWma?<-yw@{Tlu!Y46VtZ>jLik~jUAipluy4UDD2GEHuU{yD(dsU;rQATNf4*MgKtq+3E2Pi@l35)a2Y znZ6gz$=jRy_62KB-aaML@a1MsKCYBgW-3lfr*A9EXbLA{?*EYbgUm#q{2(h$`$0yc zbAFJKru`rzJhN9)5Bz}1_qZQ0{6?+(fZeyKm;{)wPOjhe*S9#jSN|PH^K<(j`TaZY z2aWw!+x(!l-@$&s&Zt|M>(PI}?mO7Ov7=Shzj0$w|Hh0_Z2!iMh5Z{lS`YpkHwN`H zW~FM)pYbg{!w-u1PTl^1^Y^%)GW?->{wez(=lVfm|DxP~P}sla`dMM$EDb*^;alj> z*nYp7{ETxc=$|n+U4wqcwgm2fVhC&2|HKe+48zhEGKNQ~Bvyl#N@Ue$sYF&+mP({^ zx;d3fq;tBLPNZ}GfJo=`_*u>$5Si}z`I?Ra1gD=te0?>1KaE>(pr0sM9vJMe@bh)z z@%Z@R>p?!<@iPQJ^!TC0j|}5iUqU971Wb&=k68TB;fJrgAH@_Q^$Qe9dBJ?KloXLg z$e!fWNgyx&=IY1TigZsKqN0v1A z#P??^EGtfp#(y)6?d0?Pq&&GozzgR6N`Au6hv81TgYeD7lsMxD-TTI}1i^kXfxki| z3*wWqpn_t=(p4hNO0bN*#*i`$ zq;O*y{(*iHvB+P@7s-mtCLNEOl`o|K*%0ayhIen3YvT8E4!Eq|C++%=^Q{5R8qFZTNUVeo{FlL=>#G;#WR)&Io%W3W8Vlc5ocC# zA^M|_(nMv!tFMV#{pPzSRvQ_Vr)yhR zFIQJrH&=I85303~PaCeukDFK9w%%>p_;|aUB*MRLuC8s{w&ij?ygWU92r05c?9d8S z+b8nG#bb*Pj+q`&hd375bX#PB|C#($sKy4$RBY;_5pXPxjl?mDepEGo(<8Z<91XvZ zM?nDlPa4F5Kiq1HNYi6zND)DqiGW! z7g7+{2ym?!ES5`fCZT%7VR%3IJAMj3(~v&mkl)MiaDINK0Yt=M_^{|(9QKPz5D{?- z_zi(^DDeZ0hM{UL5C-r0tW`HaGdqQxG%ZCRl5|gzVP!&?Aco#e)Xk+&PqQe$c7%x~8 zDpra8#S*bP9FC3C1WQ6t$W>ysST2JTdvvlDNmhyf5W+z=I?0wKiDfFGQmx?ysDMFERgdTrb+4xZDz;HA&l zVm6Z|K*CJHIErs$R}RAZmK0yE)PxF^DijGRF9^T6!xNe|b_I~nk`jnj z3JEWqFP8;~12rl>PbLw|gc`Y0AXL&_4blg3exZPjM{CkNwL-(^NhJO}ey~QN6w8%3 zoHDsm3NqFhSR;xNuq3q4MxH)!1aMDk0Ml ztIJM>S!rYUm1I!|i)8|hP!=L3vWtlp6rHFPLW60M#$-z-St=KVNQ9&(F&QdHScqlN zx&UY$=}DwmF%;|teGv7YEp}%0EXjFAu>MbH>ElRDvUCZ$rg07 zB19=(12(U^Gr$%k;b`YRHNC*N$RGI+z7erYpRLMh>zzww#f-ET$5agGkwvq)BEr4{6 zDP1WPh(Wdp07V=DR;B=dVIY(v50gpcJOOGyV`a*j!dL_pR03pe3KGf$ERKL$Fa_F} zf=Uz!nnWR&f!0>R^V)RnY)!$WDT;0?>#l5-wUTt{zQiho6O1H-$iHCS2H}YM4S`F;vU>atYIOaBCIatu;+Su(ryv z@8Mzwnp(@03X6gmTv5UI-O5T(ZBsa163$48L?Y+Yoy8Vg#}o>a2R zmP*?uN@B#IOw=>Q!Gu(UJfj|FEG95OK-P@%UEdT9;|-czDOAXnYPLb}oD|*c2Bt{9 zL?s4YDWjE(T8vf{D{c;^KyipHSO)XCScF)`(a;n|s|6fjqvH6@l&<8387st25Uwcz zhO$ezK&WPv3zw;MBU22Ik5-+MCkqs+jKw&bBKUH7uviEd7Z`4=y7;{$K&k+}2>F%9(P(8#SD_^f78x^a#?f$LYUW}J2Hm6*t8g}ahi8YnwJE+NbCm{W ztUL_HkQFUgQ!r7NIN6kP3EXl)cZ^#J#CJ21)voXaA&qx8#S?J{p8)Jiu}msfNr@fB zj*W*YR1xAY5vxR?dyT4}6|^>{IL1mXsnJxO5inRRS#&2LuQOn(vk=c0PNXqT9Cd7sE7D%F*Ib5vvBvFM$CIQf(9* zAJg2B2kR!#xEks0N~OCQ>FrCUyBp~pN~L=k=^aa@w=vQ?l}h(C(tS&%w>8rJN~L=l z>AX_u-bT8AsdOJBonI=QXQT^CrTZJ{!cyscBR!y0y1+;eER|ktXNpRt2N?CZxKuhk z1%~b@icV1J05>BbxO9NK5g;iY;9&$vO9!+e4#gg*13VWbRPl+^1ctm2)@mC&Ot&ab zN523;#3w)+c$aJ*u-gfV&BiGvp-G39CQ(nA&8nCtmMUPi603O%h1@@gROTY73}39! zfKmw71cZPigIqD)g2HrMUQ{ZLKqv$2hC&MqY2au9O(qP3dC&U8!Y-gzRYnLnSO9^D z)Ataz1aP*H3s{z*ie&*%IW=5bMVA0R7tkOup;BWBU|i8w5+E7l925=-V30KdD+TTt zWD$13g%hp35dhhT8i030Gy@dAVzwOqsV2V;lm7o>u_hBXs{ z>QD;(<#IJK#~%R&Vs#mbsE}YC0Y9DRuaZk3jH3xriplsRrb>>1=>UlQ;K3JE%gZ;Uk{c~~m}omwPWkZgn`kg3QBW3pv&vRDyHiy@|SN~E_X z{_-n&`Y+8h$0eM7m*NY zvxO`gDiUBp1nVRc1T1<=9`vh(j2V(y7m<)9V84a%0)<8@>lqR%_Bjfck;=M+gbH4` zDhwkV7}-J2tS?CCVy$sqgMHK7X5foVOtl2^&5&^7RR}3KGLR^kXAOFXZ$V>}6|_LGDArXo!5Ae5H6UVGCyiiWRE0{2-Kii9EHF+6)>9)8wzep7 zhaf*(S_U3lppYyA5aW;vrT$>wqE(4xP`<@v0mMYr5Jn~l^b!#PD!3S-5~@+!Rb*6< z3fi{>l?{K=o+id^5d{jk7zMHk%2Gmx42htDi-}C65&b*1ilAGZz=5ORQ30_|uU z2sv6%L2`daUO<_uHK2=$sz>t}B90_F0k6j*V9TF^rMxa0e~7+^i3K1N=z?PbRzJ-n zfIy%|%?pI95ox&1PvInduR&2)5ufHV^g)Rhh~=d=z!SJ5wnPKI#bWGDz>|O;*M!1? z0aMe5$yTBb-)0MtLyQepDX@W=g&0GPJSMBHX?y-XD|kpMc>w4So`T5eKGHx1PYGfR zKD=B8ORNNUPEa`@(UPKx0ZK7MQ6%BUTpWe~TN1GD!7_+i8ifjTSusRrj?y~?EX#5X zk(Eaha>iWN3;{xvBG9ck%`n-9NhW#`W|s;&1I!>Ev%i24Tb3n8N(h7j;7mb4c?N*$ z1a=?fQsbh6)Cvq0nm`kY*1;etQY$i4qD^s`#l%WXBB*pQO^i*b%qBw&Ps$^4Rzz1} zlf^K3SQb^8M1foiex0$$t1-#Om=NkuWMaoMVSAj($nvvi=uFcwCd?r-P@xI|TqWayBJ1F^zvS+)!j zG`R{D4Xo|KMxNyvBFGLMUL_g~c~&TzinlclC{VG?62M{Bg^!#yvz@C8+Lh(u% z8nP0TR$*WgJsbqU?g0ZpyAe0kV0ROvu_#OkfIS2TfMQMWY9a%c4m$~^bQOB+NXL~H z^II9|U?aj}4K^}tA%gV|g{Vl}2vOyVQD8#zAy%dcQAl|*FoMWF9oo8xvo_-VA&40Y z8({P@hBO-^4g3>aE;LfyB%{N%#*%D}D4aJEFi1tX?S?T6G$n|Yhuq2=ajfFPC51%e zkX*q?X4?Zw7q*7Mv7sZi#sVuEkz~=pRgINNqFXRLgB&XvaYl}4kg)a*8Fj=}HsZh% zAX|&ZUP7A$AyteJw)w^FYt3M)8Zja@>=&|jjfOQ|(8(ifF3Yr4MHi^#GFwjR)jf-Izhm z^Y;fg%U>xE!yOPZLl9BJh#*lYvLs`AO=CJM5=_@)1Q0f*U~_>OAc(E?9abU?`P$1Ilj`o?q;af7{iMF`0b0a+EX&Cfy&toq{|gxEV@-GvrWl)x_DZNc#+D^eBc z<+?1f9H_zZHNPhbX)xH4|A97USdjlOo7_Nu<=DO_H@1qmsi1c3-K4?G$+u`(vIPAOYxHB1z{87onPeD@~aCUSDZ@61j!t`C@I*&p5!gsG%K zbadzgq=WaZln|{(W;$-*;#4QP80p{uGj!ODh6ukY3W6gLc!WI*GMbnJ zd}AgDi8U~K9Vy@)7xMyd5_q8%gS=pWoaTiy0S|28?ko~uhnyy`!B8UwHpz>#5YH6b zig{p@oTh-31TyXero$dNlMW{X&~rq07FRqAvYXFT4x${!^&M-0L}M=?Q4|a>yTP^U zBk%;nO_#0Bz{`@QQ8|eznJGjEodyy(By#kc{CQvwO5xCvSPc<*2)ff=@-+e>xg~IL z$H3R68WK}8b(wn7L?m0#%n8{)Ged7MQoxYJVhKeVm6jMwR5IpaDnuv>ctkPOug^-Uuf zl)Go!5~y$5z@R+cXkO^r(ogg%!~&^G%qULwEDNspNCq(}Nfw3?aX=afN(mY$X^B`$ z;xI@CX(>S#DB(O8kzk~P<57YN%9GtUz-faJa6d{w;2eV5SU9*KC5U+V0_uit1m*=- zqy!n5%L9OFOHSx$N;{wf`reitzA;3_vnOxVxoKL^eYWJd38drU5ip`dNg5uSfix6# z3=DwIw6&`aQt{+d@|h=OP+4rv7$!vIlBLljjBILyHB<gz&@fM{Q_!JNVp6&GwG7=oMqzmHw55E020fIURcq& zMN0t`j*wK>9;=IuCY8X-XGLj}6G7QkhunA#1N|r_{a6>N85a`$!@*sFcf#7)SHtFp z;hKxJMpaI@5gL5a=;Go`2AcFQJdcA_L*oMni=4B9<%luTVb4!ZSYxB{=~Oj0o&V zZ)gM708c0Z0+^E7f#So#I)=(&-9(lKV5!Z>AdN<9I(!c!!iC?sh$SO|^ADw*9xM8> zKAfxQf?*dE|5#3re!`+}OM>gH6l44!q!+C!di-FSRKa=)ddQY6S}ZV7Yw(9>b45|9 zaPW>6cpPPRc0n(o#N*lvB^EEf#(^MX4@+r?(`7I#3A;LwOauV*9z>l4Dk+%*pcF_~V&@UL#gV{9Xf$wySKGD? z3=TE~V}{reV^EOD5YC7YkXYC@zt_SFvpa2lRgv<_<5_TwYF+h9d z+YvIh8mo>qWgdt%ki|2P=7~puA^uHolA+#A10b2#IBPLLMpiKlWism+3dtTiGrMnU z97dvqNbivMo52hsKiTk4qyxPE8os@O-yFEK!~*_uIbUZMjJdyg#egU8XEa<{W#UfP zEQ?2d+V@}T>oiR^YjT4q+*L+g!{rO^I_q9dTa{}SRq1fGW=EH=&G4BKHfwnW`^xp} zJp&EAk>IAhR{pv2@cl2YcU~QISYffJ&h_Ny>$3(l;ySg-9NK)#0(=E5@}u$$TL;W{ za=G_(U&9`cdn8_3krvl#V5JwIR-Sq?WG3exMd3?xxtyr3$73%{>c%^iWxFa~7IedV z_PFyG2PSw``mnXe%Z@Amf;U7H9Jiu)-;1+JhnKs|{@8wS??d+Myl%cd+}vUAI0v5% zi|@m^dwgLhm-C@u)xNP~I!SsJ+1I|Hs`=FIqHo8chkE#kE=it_=?Q21sX$A_O=?xK z|Iu^HWe=K!5huFoahFY%4N&k26#?5u)KSn zb}l{dcmK4r*T~C5|L!w9{WI)VQ&$LX_M~PFc23B+W*J|Cc{o%-mYf=hNW*%je7*CLSQ3CwYG=yfMfj!C95_ zTstGOiA?ig>TkW*cG&H-tMps4JgM!*?GZ#)h9{SZb*JjZ9&-r;5T0h)wh&ukU?F_hHW)Z=? znH0CMPUg9w)CkMh7MJVy%y|{DHSqPt2T#(S*N1Ls2@j7vBe>e0L{aquoH&;eXdk8N2`wm*yRdo_RY z%I2=pIj!G3ojqS$G+=r8h#|lE;X6@>5!@H+1J|4GzZtP)*9B*O`{AP3E;XK4^|C)* zwQrW}bFv>ZFVQ`VV@a9=6GO)nZy7{F7!O^n&U{qGf%3)>Is?byKI>%raW z%eqrf=K4TH2`;09a($D7R!tqYeeA3I;<&v0nn_h&hE=>j(BhKxtNjUGLy)UTg8S2R zcB`)=q-tHKlV`t7in+OHVDQ&Nd50UG7+dgstv&yRD*9k81}u%XqG1(PL>$6lEITp*};J-+T>%f1zcw1#`&2+qse zWn105U40t-qv$+q66f};_W~Yfp*Bt?p={+J9u)yJjhG zeG+e5=eL?SBzEcko~QEPSH2AM5+7LNOuOsFEqpfi#%0@;lU~|w@#t1@L6Kv?;#Di# zt!#NKgmZJyQ*s z{`TpkllyL-f4NQMmij&`ua#HRp3mFG=W6dwdN~0cI=D@W%c(Xo!Og0$_n%W6Z+FS` zxwfFGzo)IJ?yb?=(LqzU|tfOPgXCNx-nZ`#LtYraHsdW(?=a1EUDc-(|cy_ zkqenuCw!);c?1`FsDaB}YyZ*SoStE$;ug($9XLP8D{^9NEl$_U!mBM{S$RrueQMag z*;24=%4*>V$MV%3yPSAbX=TdFx-BFppM=-VI6R7?yx?guE~m~>rB$u4@q>1>omF8> zNO+C>h|Fx8t`oy+`ySdM3=fHf=dcLQb8d&nkAnA9n&xY9WxrRqO3QD(=;8lx>X}r# zS<&lWc);CN*9oraIN7-J-iBHBi_Sdc{e2;}?#QqOflhm`pG!XH>gaT{3A~MeT!`A}}b0=vkWleZLYFqHFqKjO-PlN6;VxI?nhg}QS6ZtSo!?97TN zXm`8M-Jlk~9XT^KT;J%`nR|gS9t8KP-Rc+a!QH5n6?)vRZFz0~-W%GF6{;OwvB4v0 z>bX^KU>;e6j^T2qI@GlZ@Hy7DdhiCDtYfVQ^i~}^-OVsc889}iuKV`mV(=pfZg1st zJ4Fk4sTH2xX*_3f?*o03N6pP&ZTp9$XV>P3>kYXM<3Vt5&(`WTwEWfAT|eh01ib4# zHmdo(UJ`BF)t{DEoito&;{^{E65J!f;f!Q|ead@*aD7bYYZiBA9xvz<_Jlh&`(3?7 z`__)9sCIDw8kdt)72IR=v%&b^q#gZ1(VG=O3MqxC;7;;ClON z=T2My(lF93_#)4`OGk^?i5|CjGvj`5A&*`Ep(~8V8G>uD;dIYNV-9r4_1xgLHY(tA z)sD^2w?8xCW%KZI4$%ijhrwGoz_#FW&UMv)7;@=FpQ5Ip?`E~ETdBch=SH_H_y~8b zKQpvae0#7Dk_pb`!l0G;Bg?fIKRZCV*4F3FNZqPkG4VXxYlk%Hv*x~SKvAa%E-`a@ z`8PEOHSy&hy?J|H^?!cfHe$)r%vQ(uM*FROyzw*W)0!ZwT+SM$)w=;whhDvxHs9dD zn{fJGw&Tm_J!{W77EandMe%nGylM@d*R^I z&T1zrE9m_T@jKq*Kr>D8{G6qaHqE)T3B^ni(H<$oocK z$huyg_Dg2_1x@}i?s^Xuyp@LF`aW6FA}Bm#LlDO{VQ|3)kI^k`#@)@|e{9H~+cth2 z-~(4&)~$o(ZgN~F*}2SrzCLl->py2dRb<_-_fMS|TmSh@ckLW+Ws^!#Nd(t>fcJ(@ zmcyKG71d~eXO`cMuAz#Bw?61YZ&+C8Xcow{yyS#)V=hoZQc5QAsaQ`4Ux z0{fsY)^C2r-2w6IS6ub3kktR?5Z}2wuXQ*y{%Dx@%=Yo&FYDfiv7JV6F@`}m<~p?M z=yxRU(beV8e;+AGJZAHy)~LUFCv>m$@-{dr_X%$4Z7Q12U3Safd)z^4)G@~adz*Gx zda~=0L{nEMzR!2&Zft&; zqWTkD^H2KoF#{Ic@z+FDTpZbPRkyF5@^ZK9v#xXREl9s}8QOZ1;BIbxdiX-q{gu;S zmP@%lJy`Elzw*Y|-7yLB(?eH_w!obd?>ptt&8`dJ=5EmCTu!X}wZXL|_7~1&1rPcZ)ac;qbEA3; znl)vB$Fl_!sywv(1a>>Y9f>b`xqOV|(FKdEcap|wVwJVqx46BpdyfV83s&<~iN`7G z62VQ}c;#x-rPk9HywIOJx8UrM^o@ePmG&;mcWi&Pb>%``8z|EO%e7zE(J?g7f_Jf+ zz@pOJy>Zo+t)_+^&VS?;J^B2`e{^mX6-RK3D_41Y>Tya;5U*gyRKu(q>Dmw4r;teJc;uQ|La19SqH6I{9d zUhgL>M<2QFw|i~*w_g?=JA3r+2^ZT*-c=ZL?NgO@U^fw5&8(sgRn|4W`L@l7{MHv- zc!#$;y?oH<-tvf+{em)TO`1hfI|*))dqmdO9pfrFzUY{hte$Zxwgl~cZJ%`S*eSaZnOGNX5Y1y{+pTG8}s0e~vu)10O zTXCBf)C#&EGy5pdVH9U@>%#htVy1B0H;m>C$$XhqM3f@g}8BvezPa07EZjj zb}#rIe&DOXdLF3BSe^A{Uhmr@M*LA@(c$ZDLK5Ci8{EHPk3|OA#0FZ58cuK_cfRzR z)^kw7TC2DPuLs+`u@-Tn|2lqqSkXSmzuRgfqbTYu!Nu!yJthR)O`ZL5V&m1kFS+G% zp9IRK<=zcHap%!r%K8^UTpY37SJh<>EiIxNMt+?*>x3}0&fpc5j-3p*X#4fdmCjKk zT0#FM5nQxn;3s|Op5D!0XZ29b`@MVX8J&*>U!6Q}|MUTO=Po+milVj>+>*KP8r5!b zwa>A$NfTa`zqPYxFKXK*nak_UeVdj&8>IvP$l`Y_*M?i6(G&Z?tv$!Tx-(+@z8isE zIj2Tgge{(;1 z4uC!-xB<3be9KRdw2-$wv+k<@AA<%yzU*_OP4-jkmjjy3upW{}QMU-rJ#5v;w;j5a z-zDu<`+3!(QDUKkZ_~X+hJHnNZ!KL`a}d0{$qDPHoP9F=z?4h9ss#@jmaM&e@qt6n z=dI=h$L_VLF}^5N2lH|~!C5M&{T6-XdBc+`zQjA`&2B{pmsM%$GxA#&dEdQLZ_`zZ zx=L`simQIPICW=H<)`V-=EEf#jj`N4=`L4%w(Y#s zdWz*dH~Y%zZ8=Vtp5=P%cZl~{kuN?n0(NEyZgYp@CsY3V^H$3qKGUL~Ij1^)X}ak2 zG{fc8eY@IUIMZ)8+=NeX{2up?t*L$H#QFg%UfIp?9kC{Ob>n{L^9H?1@ z4)`=&&XwpcBMkR%Q(R4gTjcuAHy&1*Pp#0W*0`Lrd8sga`9ZLA2##`ibmgVpBEjsh zJ7+cVD|A`k{44)!;e!py^{Oq|aeZ$R_}v6IY;R13-F*%`&&_#tApfs7b>8hLlxz*S zlYJ~hkzMh;KLtCEO|jfl%kD;}Y_m(4KK1hFi(R{Ydb8uj=v%Wd-Fq}3Yqsc&b^%4n z3GThegnO!pooO!y)E|H4Mwben_j6riD~ue~MQAg)nl;`%KaJq@Tk7|F@nT$uW()T{ zSu^WkBcJDwdwXC0QpGpm8uSdAb-xyuzvF%HhnPVb@-frHl|H#-7Gd`=Oiy#be_F-&bIEmoc)*2g-t4g zbNr~A^QM1f^-0U}cb(kzNe>uZhx(NDZAHl^pTi0*Z@W@^5L=Eq@ zyT5(Z)gC9hCAQ9u)op%JNwUVbBIqm7m0V8X>#5H6c6S&5<-T_8>UsmEYldCxb1?dh z^6~MNGn@BY{SRD%LU6Kswbq@L2~Qn77jb{R$YWD*o1z&$lY7Tq3Mv2Y+?GPnSF;K3 zu>0lT-p;HuHmrQcv4ZDCUH9+kR_FLrb>@KvK^y%%|9nkR4++k3ll7WK<)bGzZE^I$ zXU`7unsY1NJW^3pZ$^5H)?XDHeZl{5#`?9$sC?Q#`Jbh-7x@W62gCC=d}4~tf@a^DMj@rxKY#QPYRu*JUXmN(jTMalaDRQ^gfx>IjkBde{9dlq{=NQ>L9`G zcK`d@)UNZq2CQ-T+^e0?X4vsY?qLhxY<}BmZ^B8N>%HOFJYcz;V?|a~FAeG>j?Uvn zPuw;B3BSpXeG}}PH=BB@ezaq=1%Ug5;BGD*<$C_WlAZnb z9B07Czj+=X3xJm>M!{8_`Fq1ALsphp4J=qf}-LHZuzi5SNjjW@xkp#PXFdw ztALSK?JXWY^}J6lwV3wWbKnl}QwZ*KdbNk|r_CsMUvR09ri;AOgQ~AicG*$SOPW@* zUY!j~Vkzni!6lp>JepeV(X914?eMAt;$CgM7I~s)lYFg{V(|v40JqE}E?B>zXT0@Z ze`ilTIH*Y@+r1ald7TzteDXECuSL|Vq)3^^E$~+fZubX|N2e#uJEqO?x?8Kos5Pg+ z?=Q#ol|1S{)mh;X1?$!gg8MKbJ?C(@d&BnJ?`IX%sJk%4ad+y9ig8wrc9lP2y}BIe z)26W2a5*nI3ws{)sW4&dU)psEEiHC6iOGv`akfgn)3iru-?h=;fAk=@yY^?AMY@bh z=`7UQJI)=j#&P7CyeG*s4tSUIiCcQM(pc~p2(DYy=}mgsKZ9DjT8pShr|bLLpPlWL zw|1w^`e%1HJ5O|lM;zdn%MscvzIEV@L)~SSYw`#A)|)-9X|MfRg8EH!25+}&eh#i-Nmf_8oCHFSZYTc|Pc}tg_)gNv@?y&30 z3fR{mI9GL*_1#wF9$tKGTDeKCH$_#3ZWM2xW*OLQ^s)v0>s<%i^ftlSUjI7eS^t+U zY9@GXKPjIwssERGcb#po-sruz$H`;16V5=~%pJ>pFmL4f!`%yY7e0Re>ft9ka6GE& z^r}94yW8w(_fi^}J{9811ovsAm-P{gHa3NIo=@n~_12Tk9N9~!XOiKCUxTUf-5PuZ zIUu;5i*3%xUHmLNwvlY*AGHcqei67-b^mV3OwA?9|@`fFcn zH6GC0*~anHx+#gF=Z@W1{Z??SN6{ZMLH-Ete$##<>gaNM+?vo~cGigbDdY2By#IKv z$IvxH(|M`E@i5OH5ZqY99rcLFNehR|5;KdO){DIZI{Rtg^l1`zQ+48raLW_$lhGI8 zBtCm-H$e(;5<;wjbW4q-woz>~})=6NiEg(3jj2cxcNJGQJ_}dMX zbLZ8MHx7;8S$pgOFaO)KpMKeFps1Gw*E-wN{_5TXog=Cr8?RrGr@Wjuc+JUcU22?q zJvqtXTrC|ouXn}zG@Hl8o}M4 z*6>2(aobPyUe#yt!W(#*2{WDi^V718#;9ea2m4!3<(Xv-MG`Qsr}Z6Etih;6SdK+ zIA@ab8|AHNcm1!W`9~e&gs`@)A~3+U9a z`CyB_aDLVs%YE$7r$Fj>bnqCrYKsnP+;5K`ou>_)$RE+;*^Eu9g3i^zuO+zOe$R4m zP*t@j`Dpcp>cw^M46E3C?Sosde&6TsQ*nHa>mrIeMsNp)6xKQKTXk?s_QKTFk8j(( z?e(f)f2++`(&rXBW!DxQ0(;yC%RPJTaoyi`p7mTV-}`scnHam-J8nL?xv^??uU46B zTh9LnY=}VwH{^Kr=V{HRRJ>H!dwk)jDFeF(yxFqDyT|j^&OK%x-{l8(>=lCRUiCBO zdp>b=KgSh?Tn}E)!=LAldT7~QYqKy>_t9Cm7T&S~J{Qc7(40cMH;p^*{!@{*2#E1pk(l>pv`^<)o(mz1D7?Ac_yufBb0u z&)`S!jwFI>{wXDR@m;%H3E7dexbt_251sg=uNr#2>MYd~rv`p2BPhxdWRS~Q@MV1M zYfb#_@C$!iE^{dN+0)j&&b}o*1u0waN}fH;-3WdU!5ykny>Gt{Lk7NgQG79slZWXQ ztsLj({4QJ8ZhMpA?;fp&Ytabq#Jt$>quvR1sFU5NrFDo?Nes(4E3_@n?`YA+=DP5C z0K9()Y){t?@Bx>yDKd2N8Breada{si+}^CaJzh2`Nd=ypv49Q9N*KI!pnT!nH2>WL6%m;FLq;G zVzf3x4~;LSw!g?KF(sw!OmHZA>QZqy%E(L)r~b6D5gBPQsRoemGIE1ig0KJ3!Ci)F zi5_KS##9a8$)Jrh53hK*_t9+3pwG-xD_|6*&rK~WH|TsEM!lItA|;W$4#QksuTRs) z=nWa5kIFh98M!cFs6oatWmQYXQz14+Yo3uctz)Jc#5fZ*XN)dG3x73wc>hpLf_W+$ zn*omsWRU8bhat>beM(G5Y#F(MOarG(c*dfPj98(G&C-~!tx!AirYp0lVMCTKv#erF zWQ2Y%RvG&Yny1%-IRd6jG~7*F_ErKzcpbSeBiAgfQlsEaR%wZ8W~x|BqFHJM;tES( z*?XSm^CJ`K7mW^Jh9g+US}}77x(RH+7-(fy85t5$r5A;=a!QGSYNcmtGjiR_&Wc|8 z%+O;c^ffK|Wv!j*3IH5q(sDIrT~J|K;)&;&6ga(Z23{a+saivJk~vyR9zZA~BSvhq zQ_E~&F`Ux$329L=NoEi<=2d0dvd<*4PU_*AI`ecEJerrPO*V%;0K%26%Wm6-)*5B3 z9ZIUsESyRXWt%eAi{XYE!=NwC<}sg3n~YD4nqiivMtiuH(rWWnG%F?}6P{}Y#bPcE z4~nI9Z{B>Bj!FUDk6y}u+BH3YQpzu`?7&GM12e)5$_PB;l(L4Ln2BJPDGHN4(*W=H zFiXe@P1%er(6^=8EasCRy&*OlB7Fa;^!!jje^GQWN|R~Ol~UJVWCZgPWYA2$UZO6> zP+I@}Vx1s@njDp79@hX3n$o;7^N9^Tq^>TBsb*+;3`V)iII7G%&NhqxK}=TURK`l7 zLV$Y+vP)CWzakz?<1knjTh_Qj2@5|v#yqX0!+2?Qci{yS`Ut3VtS&;J)h8KrX%KbD ziqNMCW>|Vap3Gom!+X8Vp{a16Ed?2wK?X?ZAT`+xJ|&nj+6;2BkJ*%z zAr@ZKR#r&>;fyk9nf>dsGBZ(98ncAi86A_D8Wmf1bA&aK%phdNy3Z^}5mLzMfwJ~~ zN)>QYhPjlN zKFbVy=eV7uhjr%%D%E_>9>fTHq?o~$_z(0M+T>=@xB3KaGDdF7E-bJEK&%}&IA9ij zAjNQNlirX3N19^IbEF5)ZX}qcaw+1h|^%E z`2rgcWo#LU5lj?=HU)xXx@28^@d1@jAmY49`oJ#_+JUmohM5STgP`i1#k=ann*!V!{%sFkblLS`$^D>GJKlUU z49^mnWiy!3Z!jXz0dY|&iOIR842${doo(iN6Rm8%h!?sh5PybS(EmU5MXGuGLLZwH z8=C}Yx&PAv)c>T?<`WZbPE4upnE6UD{G=VfuFmx6ahKBXzsQN!L#2fg&DZcW^EEsz zL!VGq7l%00wOy*SPSdb9Khi}~uEW3GCeZeT#b4~b+IZ{{4LZ|z0S!GHz zx+Z+WpUU{>EB&SF&i$fMkZI5!OTxhqNVVYCiVB2JxDF2flfq|3@}CuaVx7*xZ#yc` z4*nQ_qTxTJcZ1&?s4M-`pT6sz5o?V;5ke#G@NTY7hE||%;3JS2K1o-iT>r}9vJot<0{_q!j2d)|D zkIfdqU+h64{H@QVH-^6=_>O&pIJjm7ZeYh=#VX-{6)1Q-ok@!{rX?HG(u`@RjA=Lu zbY6G_p2_>nm}b$KLp5$=MOi@w@dw+&{-6YKC~O7&AIcck9o{nv;~GJQPJmWVi!b?*o(Sj|KxGnc5x_SC(y}0zf$)olZw4xbd{2Pa`XoR-vnVdr34XEnuodvu z#+rXjZ@a~A<7of2Tq@W$fZ}@b0@sxI|;6H!qOLwrp9gEF}UrRYF|1vZhHB8;;O>hXZH<@n$q8IUVO{z zp_MnJO?}{IF~_k{0aSzh_+dQHB{6o&2rG-PU$L+K;;z&n)S2V2CkKp86e<3gSQbW&leCH!(M9*ro8fE&gP+8l#ZN-Cx!ca8(tWvp{b2B=Tl*FN6AdI=JfkNj(j)#_>oKT!g$mAjz$|a*X zmkr6agrP5Nkn@u6AxvPZ11|!?G}Bx-8;Wb#VCIv%#kme(R`@{-5iWv_@T!SEq-Jezxom~p(J2p6n@0w nhYmk{-Tf%02&rG7NXiT5i>0K9EJF4qpH2dK@i$jLs>1&RqxydV literal 0 HcmV?d00001 diff --git a/vendor/flac/m4/Makefile.am b/vendor/flac/m4/Makefile.am new file mode 100644 index 0000000..1a25b7a --- /dev/null +++ b/vendor/flac/m4/Makefile.am @@ -0,0 +1,26 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2006-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This file is part the FLAC project. FLAC is comprised of several +# components distributed under different licenses. The codec libraries +# are distributed under Xiph.Org's BSD-like license (see the file +# COPYING.Xiph in this distribution). All other programs, libraries, and +# plugins are distributed under the GPL (see COPYING.GPL). The documentation +# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the +# FLAC distribution contains at the top the terms under which it may be +# distributed. +# +# Since this particular file is relevant to all components of FLAC, +# it may be distributed under the Xiph.Org license, which is the least +# restrictive of those mentioned above. See the file COPYING.Xiph in this +# distribution. + +EXTRA_DIST = \ + add_cflags.m4 \ + add_cxxflags.m4 \ + bswap.m4 \ + endian.m4 \ + gcc_version.m4 \ + ogg.m4 \ + stack_protect.m4 diff --git a/vendor/flac/m4/add_cflags.m4 b/vendor/flac/m4/add_cflags.m4 new file mode 100644 index 0000000..d9b633c --- /dev/null +++ b/vendor/flac/m4/add_cflags.m4 @@ -0,0 +1,15 @@ +dnl @synopsis XIPH_ADD_CFLAGS +dnl +dnl Add the given option to CFLAGS, if it doesn't break the compiler + +AC_DEFUN([XIPH_ADD_CFLAGS], +[AC_MSG_CHECKING([if $CC accepts $1]) + ac_add_cflags__old_cflags="$CFLAGS" + CFLAGS="$1" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[puts("Hello, World!"); return 0;]])],[AC_MSG_RESULT(yes) + CFLAGS="$ac_add_cflags__old_cflags $1"],[AC_MSG_RESULT(no) + CFLAGS="$ac_add_cflags__old_cflags" + ]) +])# XIPH_ADD_CFLAGS diff --git a/vendor/flac/m4/add_cxxflags.m4 b/vendor/flac/m4/add_cxxflags.m4 new file mode 100644 index 0000000..b76e710 --- /dev/null +++ b/vendor/flac/m4/add_cxxflags.m4 @@ -0,0 +1,16 @@ +dnl @synopsis XIPH_ADD_CXXFLAGS +dnl +dnl Add the given option to CXXFLAGS, if it doesn't break the compiler + +AC_DEFUN([XIPH_ADD_CXXFLAGS], +[AC_MSG_CHECKING([if $CXX accepts $1]) + AC_LANG_ASSERT([C++]) + ac_add_cxxflags__old_cxxflags="$CXXFLAGS" + CXXFLAGS="$1" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[puts("Hello, World!"); return 0;]])],[AC_MSG_RESULT(yes) + CXXFLAGS="$ac_add_cxxflags__old_cxxflags $1"],[AC_MSG_RESULT(no) + CXXFLAGS="$ac_add_cxxflags__old_cxxflags" + ]) +])# XIPH_ADD_CXXFLAGS diff --git a/vendor/flac/m4/ax_add_fortify_source.m4 b/vendor/flac/m4/ax_add_fortify_source.m4 new file mode 100644 index 0000000..d443814 --- /dev/null +++ b/vendor/flac/m4/ax_add_fortify_source.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_ADD_FORTIFY_SOURCE +# +# DESCRIPTION +# +# Check whether -D_FORTIFY_SOURCE=2 can be added to CPPFLAGS without macro +# redefinition warnings. Some distributions (such as Gentoo Linux) enable +# _FORTIFY_SOURCE globally in their compilers, leading to unnecessary +# warnings in the form of +# +# :0:0: error: "_FORTIFY_SOURCE" redefined [-Werror] +# : note: this is the location of the previous definition +# +# which is a problem if -Werror is enabled. This macro checks whether +# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2 +# to CPPFLAGS. +# +# LICENSE +# +# Copyright (c) 2017 David Seifert +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[ + AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CPPFLAGS]) + AC_LINK_IFELSE([ + AC_LANG_SOURCE( + [[ + int main() { + #ifndef _FORTIFY_SOURCE + return 0; + #else + this_is_an_error; + #endif + } + ]] + )], [ + AC_MSG_RESULT([yes]) + CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" + ], [ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/vendor/flac/m4/ax_check_compile_flag.m4 b/vendor/flac/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000..bd753b3 --- /dev/null +++ b/vendor/flac/m4/ax_check_compile_flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/vendor/flac/m4/ax_check_enable_debug.m4 b/vendor/flac/m4/ax_check_enable_debug.m4 new file mode 100644 index 0000000..f99d75f --- /dev/null +++ b/vendor/flac/m4/ax_check_enable_debug.m4 @@ -0,0 +1,124 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE]) +# +# DESCRIPTION +# +# Check for the presence of an --enable-debug option to configure, with +# the specified default value used when the option is not present. Return +# the value in the variable $ax_enable_debug. +# +# Specifying 'yes' adds '-g -O0' to the compilation flags for all +# languages. Specifying 'info' adds '-g' to the compilation flags. +# Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to +# the linking flags. Otherwise, nothing is added. +# +# Define the variables listed in the second argument if debug is enabled, +# defaulting to no variables. Defines the variables listed in the third +# argument if debug is disabled, defaulting to NDEBUG. All lists of +# variables should be space-separated. +# +# If debug is not enabled, ensure AC_PROG_* will not add debugging flags. +# Should be invoked prior to any AC_PROG_* compiler checks. +# +# IS-RELEASE can be used to change the default to 'no' when making a +# release. Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it +# uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE +# macro, there is no need to pass this parameter. +# +# AX_IS_RELEASE([git-directory]) +# AX_CHECK_ENABLE_DEBUG() +# +# LICENSE +# +# Copyright (c) 2011 Rhys Ulerich +# Copyright (c) 2014, 2015 Philip Withnall +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +#serial 5 + +AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ + AC_BEFORE([$0],[AC_PROG_CC])dnl + AC_BEFORE([$0],[AC_PROG_CXX])dnl + AC_BEFORE([$0],[AC_PROG_F77])dnl + AC_BEFORE([$0],[AC_PROG_FC])dnl + + AC_MSG_CHECKING(whether to enable debugging) + + ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1]))) + ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],, + [$ax_is_release], + [$4]))) + + # If this is a release, override the default. + AS_IF([test "$ax_enable_debug_is_release" = "yes"], + [ax_enable_debug_default="no"]) + + m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))]) + m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))]) + + AC_ARG_ENABLE(debug, + [AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])], + [],enable_debug=$ax_enable_debug_default) + + # empty mean debug yes + AS_IF([test "x$enable_debug" = "x"], + [enable_debug="yes"]) + + # case of debug + AS_CASE([$enable_debug], + [yes],[ + AC_MSG_RESULT(yes) + CFLAGS="${CFLAGS} -g -O0" + CXXFLAGS="${CXXFLAGS} -g -O0" + FFLAGS="${FFLAGS} -g -O0" + FCFLAGS="${FCFLAGS} -g -O0" + OBJCFLAGS="${OBJCFLAGS} -g -O0" + ], + [info],[ + AC_MSG_RESULT(info) + CFLAGS="${CFLAGS} -g" + CXXFLAGS="${CXXFLAGS} -g" + FFLAGS="${FFLAGS} -g" + FCFLAGS="${FCFLAGS} -g" + OBJCFLAGS="${OBJCFLAGS} -g" + ], + [profile],[ + AC_MSG_RESULT(profile) + CFLAGS="${CFLAGS} -g -pg" + CXXFLAGS="${CXXFLAGS} -g -pg" + FFLAGS="${FFLAGS} -g -pg" + FCFLAGS="${FCFLAGS} -g -pg" + OBJCFLAGS="${OBJCFLAGS} -g -pg" + LDFLAGS="${LDFLAGS} -pg" + ], + [ + AC_MSG_RESULT(no) + dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags + dnl by setting any unset environment flag variables + AS_IF([test "x${CFLAGS+set}" != "xset"], + [CFLAGS=""]) + AS_IF([test "x${CXXFLAGS+set}" != "xset"], + [CXXFLAGS=""]) + AS_IF([test "x${FFLAGS+set}" != "xset"], + [FFLAGS=""]) + AS_IF([test "x${FCFLAGS+set}" != "xset"], + [FCFLAGS=""]) + AS_IF([test "x${OBJCFLAGS+set}" != "xset"], + [OBJCFLAGS=""]) + ]) + + dnl Define various variables if debugging is disabled. + dnl assert.h is a NOP if NDEBUG is defined, so define it by default. + AS_IF([test "x$enable_debug" = "xyes"], + [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])], + [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])]) + ax_enable_debug=$enable_debug +]) diff --git a/vendor/flac/m4/bswap.m4 b/vendor/flac/m4/bswap.m4 new file mode 100644 index 0000000..b1abae9 --- /dev/null +++ b/vendor/flac/m4/bswap.m4 @@ -0,0 +1,66 @@ +dnl Copyright (C) 2012-2023 Xiph.Org Foundation +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that the following conditions +dnl are met: +dnl +dnl - Redistributions of source code must retain the above copyright +dnl notice, this list of conditions and the following disclaimer. +dnl +dnl - Redistributions in binary form must reproduce the above copyright +dnl notice, this list of conditions and the following disclaimer in the +dnl documentation and/or other materials provided with the distribution. +dnl +dnl - Neither the name of the Xiph.org Foundation nor the names of its +dnl contributors may be used to endorse or promote products derived from +dnl this software without specific prior written permission. +dnl +dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +dnl @synopsis XIPH_C_BSWAP32 +dnl +dnl @author Erik de Castro Lopo +dnl +dnl Dtermine whether the compiler has the __builtin_bswap32() intrinsic which +dnl is likely to be present for most versions of GCC as well as Clang. + +AC_DEFUN([XIPH_C_BSWAP32], +[AC_CACHE_CHECK(for bswap32 intrinsic, + ac_cv_c_bswap32, + + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[return __builtin_bswap32 (0) ;]])],[ac_cv_c_bswap32=yes],[ac_cv_c_bswap32=no]) + if test $ac_cv_c_bswap32 = yes; then + AC_DEFINE_UNQUOTED(HAVE_BSWAP32, [1], [Compiler has the __builtin_bswap32 intrinsic]) + fi + )] +)# XIPH_C_BSWAP32 + + +dnl @synopsis XIPH_C_BSWAP16 +dnl +dnl @author Erik de Castro Lopo +dnl +dnl Dtermine whether the compiler has the __builtin_bswap16() intrinsic which +dnl is likely to be present for most versions of GCC as well as Clang. + +AC_DEFUN([XIPH_C_BSWAP16], +[AC_CACHE_CHECK(for bswap16 intrinsic, + ac_cv_c_bswap16, + + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[return __builtin_bswap16 (0) ;]])],[ac_cv_c_bswap16=yes],[ac_cv_c_bswap16=no]) + if test $ac_cv_c_bswap16 = yes; then + AC_DEFINE_UNQUOTED(HAVE_BSWAP16, [1], [Compiler has the __builtin_bswap16 intrinsic]) + fi + )] +)# XIPH_C_BSWAP16 diff --git a/vendor/flac/m4/c_attribute.m4 b/vendor/flac/m4/c_attribute.m4 new file mode 100644 index 0000000..48aa622 --- /dev/null +++ b/vendor/flac/m4/c_attribute.m4 @@ -0,0 +1,18 @@ +# +# Check for supported __attribute__ features +# +# AC_C_ATTRIBUTE(FEATURE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +AC_DEFUN([AC_C_ATTRIBUTE], +[AS_VAR_PUSHDEF([CACHEVAR], [ax_cv_c_attribute_$1])dnl +AC_CACHE_CHECK([for __attribute__ (($1))], + CACHEVAR,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [[ void foo(void) __attribute__ (($1)); ]])], + [AS_VAR_SET(CACHEVAR, [yes])], + [AS_VAR_SET(CACHEVAR, [no])])]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl diff --git a/vendor/flac/m4/clang.m4 b/vendor/flac/m4/clang.m4 new file mode 100644 index 0000000..11326a4 --- /dev/null +++ b/vendor/flac/m4/clang.m4 @@ -0,0 +1,28 @@ +dnl @synopsis XIPH_C_COMPILER_IS_CLANG +dnl +dnl Find out if a compiler claiming to be gcc really is gcc (clang lies). +dnl @version 1.0 Oct 31 2013 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. +dnl + + +AC_DEFUN([XIPH_C_COMPILER_IS_CLANG], +[AC_CACHE_CHECK(whether we are using the CLANG C compiler, + xiph_cv_c_compiler_clang, + [ AC_LANG_ASSERT(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[ + #ifndef __clang__ + This is not clang! + #endif + ]])],[xiph_cv_c_compiler_clang=yes],[xiph_cv_c_compiler_clang=no + ])] + )] +) diff --git a/vendor/flac/m4/codeset.m4 b/vendor/flac/m4/codeset.m4 new file mode 100644 index 0000000..cf53d24 --- /dev/null +++ b/vendor/flac/m4/codeset.m4 @@ -0,0 +1,23 @@ +# codeset.m4 serial 5 (gettext-0.18.2) +dnl Copyright (C) 2000-2002, 2006, 2008-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], [am_cv_langinfo_codeset], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[char* cs = nl_langinfo(CODESET); return !cs;]])], + [am_cv_langinfo_codeset=yes], + [am_cv_langinfo_codeset=no]) + ]) + if test $am_cv_langinfo_codeset = yes; then + AC_DEFINE([HAVE_LANGINFO_CODESET], [1], + [Define if you have and nl_langinfo(CODESET).]) + fi +]) diff --git a/vendor/flac/m4/endian.m4 b/vendor/flac/m4/endian.m4 new file mode 100644 index 0000000..28fbf32 --- /dev/null +++ b/vendor/flac/m4/endian.m4 @@ -0,0 +1,169 @@ +dnl Copyright (C) 2012-2023 Xiph.Org Foundation +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that the following conditions +dnl are met: +dnl +dnl - Redistributions of source code must retain the above copyright +dnl notice, this list of conditions and the following disclaimer. +dnl +dnl - Redistributions in binary form must reproduce the above copyright +dnl notice, this list of conditions and the following disclaimer in the +dnl documentation and/or other materials provided with the distribution. +dnl +dnl - Neither the name of the Xiph.org Foundation nor the names of its +dnl contributors may be used to endorse or promote products derived from +dnl this software without specific prior written permission. +dnl +dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +dnl @synopsis XIPH_C_FIND_ENDIAN +dnl +dnl Determine endian-ness of target processor. +dnl @version 1.1 Mar 03 2002 +dnl @author Erik de Castro Lopo +dnl +dnl Majority written from scratch to replace the standard autoconf macro +dnl AC_C_BIGENDIAN. Only part remaining from the original is the invocation +dnl of the AC_RUN_IFELSE([AC_LANG_SOURCE([[]])],[],[],[]) macro. +dnl +dnl Find endian-ness in the following way: +dnl 1) Look in . +dnl 2) If 1) fails, look in and . +dnl 3) If 1) and 2) fails and not cross compiling run a test program. +dnl 4) If 1) and 2) fails and cross compiling then guess based on target. + +AC_DEFUN([XIPH_C_FIND_ENDIAN], +[AC_CACHE_CHECK(processor byte ordering, + ac_cv_c_byte_order, + +# Initialize to unknown +ac_cv_c_byte_order=unknown + +if test x$ac_cv_header_endian_h = xyes ; then + + # First try which should set BYTE_ORDER. + + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #if BYTE_ORDER != LITTLE_ENDIAN + not big endian + #endif + ]], [[return 0 ;]])],[ac_cv_c_byte_order=little + ],[])] + + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + ]], [[return 0 ;]])],[ac_cv_c_byte_order=big + ],[])] + + fi + +if test $ac_cv_c_byte_order = unknown ; then + + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros + #endif + ]], [[return 0 ;]])],[_au_m4_changequote([,])AC_TRY_LINK([ + #include + #include + #if BYTE_ORDER != LITTLE_ENDIAN + not big endian + #endif + ], return 0 ;, + ac_cv_c_byte_order=little + ) + + _au_m4_changequote([,])AC_TRY_LINK([ + #include + #include + #if BYTE_ORDER != LITTLE_ENDIAN + not big endian + #endif + ], return 0 ;, + ac_cv_c_byte_order=little + ) + + ],[])] + + fi + +if test $ac_cv_c_byte_order = unknown ; then + if test $cross_compiling = yes ; then + # This is the last resort. Try to guess the target processor endian-ness + # by looking at the target CPU type. + [ + case "$target_cpu" in + alpha* | i?86* | mipsel* | ia64*) + ac_cv_c_byte_order=little + ;; + + m68* | mips* | powerpc* | hppa* | sparc*) + ac_cv_c_byte_order=big + ;; + + esac + ] + else + AC_RUN_IFELSE([AC_LANG_SOURCE([[[ + int main (void) + { /* Are we little or big endian? From Harbison&Steele. */ + union + { long l ; + char c [sizeof (long)] ; + } u ; + u.l = 1 ; + return (u.c [sizeof (long) - 1] == 1); + } + ]]])],[],[ac_cv_c_byte_order=big],[]) + + AC_RUN_IFELSE([AC_LANG_SOURCE([[[int main (void) + { /* Are we little or big endian? From Harbison&Steele. */ + union + { long l ; + char c [sizeof (long)] ; + } u ; + u.l = 1 ; + return (u.c [0] == 1); + }]]])],[],[ac_cv_c_byte_order=little],[]) + fi + fi + +) + +if test $ac_cv_c_byte_order = big ; then + ac_cv_c_big_endian=1 + ac_cv_c_little_endian=0 +elif test $ac_cv_c_byte_order = little ; then + ac_cv_c_big_endian=0 + ac_cv_c_little_endian=1 +else + ac_cv_c_big_endian=0 + ac_cv_c_little_endian=0 + + AC_MSG_WARN([[*****************************************************************]]) + AC_MSG_WARN([[*** Not able to determine endian-ness of target processor. ]]) + AC_MSG_WARN([[*** The constants CPU_IS_BIG_ENDIAN and CPU_IS_LITTLE_ENDIAN in ]]) + AC_MSG_WARN([[*** config.h may need to be hand editied. ]]) + AC_MSG_WARN([[*****************************************************************]]) + fi + +] +)# XIPH_C_FIND_ENDIAN diff --git a/vendor/flac/m4/gcc_version.m4 b/vendor/flac/m4/gcc_version.m4 new file mode 100644 index 0000000..e6aaa60 --- /dev/null +++ b/vendor/flac/m4/gcc_version.m4 @@ -0,0 +1,34 @@ +dnl @synopsis XIPH_GCC_VERSION +dnl +dnl Find the version of gcc. +dnl @version 1.0 Nov 05 2007 +dnl @version 1.1 Mar 10 2013 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. +dnl + +AC_DEFUN([XIPH_GCC_VERSION], +[ +if test "x$ac_cv_c_compiler_gnu" = "xyes" ; then + + AC_MSG_CHECKING([for version of $CC]) + GCC_VERSION=`$CC -dumpversion` + AC_MSG_RESULT($GCC_VERSION) + + GCC_MAJOR_VERSION=`echo $GCC_VERSION | cut -d. -f 1` + GCC_MINOR_VERSION=`echo $GCC_VERSION | cut -d. -f 2` +else + GCC_MAJOR_VERSION=0 + GCC_MINOR_VERSION=0 + fi + +AC_SUBST(GCC_VERSION) +AC_SUBST(GCC_MAJOR_VERSION) +AC_SUBST(GCC_MINOR_VERSION) + +])# XIPH_GCC_VERSION diff --git a/vendor/flac/m4/iconv.m4 b/vendor/flac/m4/iconv.m4 new file mode 100644 index 0000000..6a47236 --- /dev/null +++ b/vendor/flac/m4/iconv.m4 @@ -0,0 +1,268 @@ +# iconv.m4 serial 18 (gettext-0.18.2) +dnl Copyright (C) 2000-2002, 2007-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_func_iconv=yes]) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_lib_iconv=yes] + [am_cv_func_iconv=yes]) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ + dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, + dnl Solaris 10. + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +int main () +{ + int result = 0; + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static const char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 1; + iconv_close (cd_utf8_to_88591); + } + } + /* Test against Solaris 10 bug: Failures are not distinguishable from + successful returns. */ + { + iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); + if (cd_ascii_to_88591 != (iconv_t)(-1)) + { + static const char input[] = "\263"; + char buf[10]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_ascii_to_88591, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 2; + iconv_close (cd_ascii_to_88591); + } + } + /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static const char input[] = "\304"; + static char buf[2] = { (char)0xDE, (char)0xAD }; + const char *inptr = input; + size_t inbytesleft = 1; + char *outptr = buf; + size_t outbytesleft = 1; + size_t res = iconv (cd_88591_to_utf8, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) + result |= 4; + iconv_close (cd_88591_to_utf8); + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + const char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + (char **) &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + result |= 8; + iconv_close (cd_88591_to_utf8); + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + if (/* Try standardized names. */ + iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) + /* Try IRIX, OSF/1 names. */ + && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) + /* Try AIX names. */ + && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) + /* Try HP-UX names. */ + && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) + result |= 16; + return result; +}]])], + [am_cv_func_iconv_works=yes], + [am_cv_func_iconv_works=no], + [ +changequote(,)dnl + case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac +changequote([,])dnl + ]) + LIBS="$am_save_LIBS" + ]) + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + AC_DEFINE([HAVE_ICONV], [1], + [Define if you have the iconv() function and it works.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST([LIBICONV]) + AC_SUBST([LTLIBICONV]) +]) + +dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to +dnl avoid warnings like +dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". +dnl This is tricky because of the way 'aclocal' is implemented: +dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. +dnl Otherwise aclocal's initial scan pass would miss the macro definition. +dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. +dnl Otherwise aclocal would emit many "Use of uninitialized value $1" +dnl warnings. +m4_define([gl_iconv_AC_DEFUN], + m4_version_prereq([2.64], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [m4_ifdef([gl_00GNULIB], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [[AC_DEFUN( + [$1], [$2])]])])) +gl_iconv_AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL([am_cv_proto_iconv], [ + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + ]], + [[]])], + [am_cv_proto_iconv_arg1=""], + [am_cv_proto_iconv_arg1="const"]) + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([ + $am_cv_proto_iconv]) + AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], + [Define as const if the declaration of iconv() needs const.]) + dnl Also substitute ICONV_CONST in the gnulib generated . + m4_ifdef([gl_ICONV_H_DEFAULTS], + [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) + if test -n "$am_cv_proto_iconv_arg1"; then + ICONV_CONST="const" + fi + ]) + fi +]) diff --git a/vendor/flac/m4/lib-ld.m4 b/vendor/flac/m4/lib-ld.m4 new file mode 100644 index 0000000..e1feab5 --- /dev/null +++ b/vendor/flac/m4/lib-ld.m4 @@ -0,0 +1,119 @@ +# lib-ld.m4 serial 6 +dnl Copyright (C) 1996-2003, 2009-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Subroutines of libtool.m4, +dnl with replacements s/_*LT_PATH/AC_LIB_PROG/ and s/lt_/acl_/ to avoid +dnl collision with libtool.m4. + +dnl From libtool-2.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], +[# I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 /dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` + while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL([acl_cv_path_LD], +[if test -z "$LD"; then + acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$acl_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 = 1.10 to complain if config.rpath is missing. + m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE([rpath], + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_FROMPACKAGE(name, package) +dnl declares that libname comes from the given package. The configure file +dnl will then not have a --with-libname-prefix option but a +dnl --with-package-prefix option. Several libraries can come from the same +dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar +dnl macro call that searches for libname. +AC_DEFUN([AC_LIB_FROMPACKAGE], +[ + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + define([acl_frompackage_]NAME, [$2]) + popdef([NAME]) + pushdef([PACK],[$2]) + pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + define([acl_libsinpackage_]PACKUP, + m4_ifdef([acl_libsinpackage_]PACKUP, [m4_defn([acl_libsinpackage_]PACKUP)[, ]],)[lib$1]) + popdef([PACKUP]) + popdef([PACK]) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found +dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) + pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) + dnl Autoconf >= 2.61 supports dots in --with options. + pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_ARG_WITH(P_A_C_K[-prefix], +[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib + --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + LIB[]NAME[]_PREFIX= + dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been + dnl computed. So it has to be reset here. + HAVE_LIB[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + dnl The same code as in the loop below: + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$acl_hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi + popdef([P_A_C_K]) + popdef([PACKLIBS]) + popdef([PACKUP]) + popdef([PACK]) + popdef([NAME]) +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +dnl For those cases where a variable contains several -L and -l options +dnl referring to unknown libraries and directories, this macro determines the +dnl necessary additional linker options for the runtime path. +dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) +dnl sets LDADDVAR to linker options needed together with LIBSVALUE. +dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, +dnl otherwise linking without libtool is assumed. +AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], +[ + AC_REQUIRE([AC_LIB_RPATH]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + $1= + if test "$enable_rpath" != no; then + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode directories into the resulting + dnl binary. + rpathdirs= + next= + for opt in $2; do + if test -n "$next"; then + dir="$next" + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= + else + case $opt in + -L) next=yes ;; + -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= ;; + *) next= ;; + esac + fi + done + if test "X$rpathdirs" != "X"; then + if test -n ""$3""; then + dnl libtool is used for linking. Use -R options. + for dir in $rpathdirs; do + $1="${$1}${$1:+ }-R$dir" + done + else + dnl The linker is used for linking directly. + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user + dnl must pass all path elements in one option. + alldirs= + for dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="$flag" + else + dnl The -rpath options are cumulative. + for dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="${$1}${$1:+ }$flag" + done + fi + fi + fi + fi + fi + AC_SUBST([$1]) +]) diff --git a/vendor/flac/m4/lib-prefix.m4 b/vendor/flac/m4/lib-prefix.m4 new file mode 100644 index 0000000..51687d3 --- /dev/null +++ b/vendor/flac/m4/lib-prefix.m4 @@ -0,0 +1,224 @@ +# lib-prefix.m4 serial 7 (gettext-0.18) +dnl Copyright (C) 2001-2005, 2008-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AS_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_PREPARE_MULTILIB creates +dnl - a variable acl_libdirstem, containing the basename of the libdir, either +dnl "lib" or "lib64" or "lib/64", +dnl - a variable acl_libdirstem2, as a secondary possible value for +dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or +dnl "lib/amd64". +AC_DEFUN([AC_LIB_PREPARE_MULTILIB], +[ + dnl There is no formal standard regarding lib and lib64. + dnl On glibc systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine + dnl the compiler's default mode by looking at the compiler's library search + dnl path. If at least one of its elements ends in /lib64 or points to a + dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. + dnl Otherwise we use the default, namely "lib". + dnl On Solaris systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or + dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. + AC_REQUIRE([AC_CANONICAL_HOST]) + acl_libdirstem=lib + acl_libdirstem2= + case "$host_os" in + solaris*) + dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment + dnl . + dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." + dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the + dnl symlink is missing, so we set acl_libdirstem2 too. + AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], + [AC_EGREP_CPP([sixtyfour bits], [ +#ifdef _LP64 +sixtyfour bits +#endif + ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) + ]) + if test $gl_cv_solaris_64bit = yes; then + acl_libdirstem=lib/64 + case "$host_cpu" in + sparc*) acl_libdirstem2=lib/sparcv9 ;; + i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; + esac + fi + ;; + *) + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + */../ | */.. ) + # Better ignore directories of this form. They are misleading. + ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + ;; + esac + test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" +]) diff --git a/vendor/flac/m4/ogg.m4 b/vendor/flac/m4/ogg.m4 new file mode 100644 index 0000000..3b1a28a --- /dev/null +++ b/vendor/flac/m4/ogg.m4 @@ -0,0 +1,114 @@ +# Configure paths for libogg +# Jack Moffitt 10-21-2000 +# Shamelessly stolen from Owen Taylor and Manish Singh + +dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS +dnl +AC_DEFUN([XIPH_PATH_OGG], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(ogg,AS_HELP_STRING([--with-ogg=PFX],[Prefix where libogg is installed (optional)]), ogg_prefix="$withval", ogg_prefix="") +AC_ARG_WITH(ogg-libraries,AS_HELP_STRING([--with-ogg-libraries=DIR],[Directory where libogg library is installed (optional)]), ogg_libraries="$withval", ogg_libraries="") +AC_ARG_WITH(ogg-includes,AS_HELP_STRING([--with-ogg-includes=DIR],[Directory where libogg header files are installed (optional)]), ogg_includes="$withval", ogg_includes="") +AC_ARG_ENABLE(oggtest,AS_HELP_STRING([--disable-oggtest],[Do not try to compile and run a test Ogg program]),, enable_oggtest=yes) + + if test "x$ogg_libraries" != "x" ; then + OGG_LIBS="-L$ogg_libraries" + elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then + OGG_LIBS="" + elif test "x$ogg_prefix" != "x" ; then + OGG_LIBS="-L$ogg_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + OGG_LIBS="-L$prefix/lib" + fi + + if test "x$ogg_prefix" != "xno" ; then + OGG_LIBS="$OGG_LIBS -logg" + fi + + if test "x$ogg_includes" != "x" ; then + OGG_CFLAGS="-I$ogg_includes" + elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then + OGG_CFLAGS="" + elif test "x$ogg_prefix" != "x" ; then + OGG_CFLAGS="-I$ogg_prefix/include" + elif test "x$prefix" != "xNONE"; then + OGG_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for Ogg) + if test "x$ogg_prefix" = "xno" ; then + no_ogg="disabled" + enable_oggtest="no" + else + no_ogg="" + fi + + + if test "x$enable_oggtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $OGG_CFLAGS" + LIBS="$LIBS $OGG_LIBS" +dnl +dnl Now check if the installed Ogg is sufficiently new. +dnl + rm -f conf.oggtest + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +#include + +int main () +{ + system("touch conf.oggtest"); + return 0; +} + +]])],[],[no_ogg=yes],[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_ogg" = "xdisabled" ; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + elif test "x$no_ogg" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.oggtest ; then + : + else + echo "*** Could not run Ogg test program, checking why..." + CFLAGS="$CFLAGS $OGG_CFLAGS" + LIBS="$LIBS $OGG_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +]], [[ return 0; ]])],[ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Ogg or finding the wrong" + echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],[ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means Ogg was incorrectly installed" + echo "*** or that you have moved Ogg since it was installed." ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + OGG_CFLAGS="" + OGG_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(OGG_CFLAGS) + AC_SUBST(OGG_LIBS) + rm -f conf.oggtest +]) diff --git a/vendor/flac/m4/really_gcc.m4 b/vendor/flac/m4/really_gcc.m4 new file mode 100644 index 0000000..8bc94d5 --- /dev/null +++ b/vendor/flac/m4/really_gcc.m4 @@ -0,0 +1,29 @@ +dnl @synopsis XIPH_GCC_REALLY_IS_GCC +dnl +dnl Find out if a compiler claiming to be gcc really is gcc (clang lies). +dnl @version 1.0 Oct 31 2013 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. +dnl + +# If the configure script has already detected GNU GCC, then make sure it +# isn't CLANG masquerading as GCC. + +AC_DEFUN([XIPH_GCC_REALLY_IS_GCC], +[ AC_LANG_ASSERT(C) + if test "x$ac_cv_c_compiler_gnu" = "xyes" ; then + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[ + #ifdef __clang__ + This is clang! + #endif + ]])],[ac_cv_c_compiler_gnu=yes],[ac_cv_c_compiler_gnu=no + ]) + fi +]) diff --git a/vendor/flac/m4/stack_protect.m4 b/vendor/flac/m4/stack_protect.m4 new file mode 100644 index 0000000..cf8af66 --- /dev/null +++ b/vendor/flac/m4/stack_protect.m4 @@ -0,0 +1,67 @@ +dnl Copyright (C) 2013-2023 Xiph.Org Foundation +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that the following conditions +dnl are met: +dnl +dnl - Redistributions of source code must retain the above copyright +dnl notice, this list of conditions and the following disclaimer. +dnl +dnl - Redistributions in binary form must reproduce the above copyright +dnl notice, this list of conditions and the following disclaimer in the +dnl documentation and/or other materials provided with the distribution. +dnl +dnl - Neither the name of the Xiph.org Foundation nor the names of its +dnl contributors may be used to endorse or promote products derived from +dnl this software without specific prior written permission. +dnl +dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +dnl We want to know if GCC stack protector works, for the C and for the C++ +dnl compiler. +dnl +dnl Just checking if the compiler accepts the required CFLAGSs is not enough +dnl because we have seen at least one instance where this check was +dnl in-sufficient. +dnl +dnl Instead, try to compile and link a test program with the stack protector +dnl flags. If that works, we use it. + +AC_DEFUN([XIPH_GCC_STACK_PROTECTOR], +[AC_LANG_ASSERT(C) + AC_MSG_CHECKING([if $CC supports stack smash protection]) + xiph_stack_check_old_cflags="$CFLAGS" + SSP_FLAGS="-fstack-protector-strong" + CFLAGS=$SSP_FLAGS + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[puts("Hello, World!"); return 0;]])],[AC_MSG_RESULT(yes) + CFLAGS="$xiph_stack_check_old_cflags $SSP_FLAGS"],[AC_MSG_RESULT(no) + CFLAGS="$xiph_stack_check_old_cflags" + ]) +])# XIPH_GCC_STACK_PROTECTOR + +AC_DEFUN([XIPH_GXX_STACK_PROTECTOR], +[AC_LANG_PUSH([C++]) + AC_MSG_CHECKING([if $CXX supports stack smash protection]) + xiph_stack_check_old_cxxflags="$CXXFLAGS" + SSP_FLAGS="-fstack-protector-strong" + CXXFLAGS=$SSP_FLAGS + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[puts("Hello, World!"); return 0;]])],[AC_MSG_RESULT(yes) + CXXFLAGS="$xiph_stack_check_old_cxxflags $SSP_FLAGS"],[AC_MSG_RESULT(no) + CXXFLAGS="$xiph_stack_check_old_cxxflags" + ]) + AC_LANG_POP([C++]) +])# XIPH_GXX_STACK_PROTECTOR diff --git a/vendor/flac/man/Makefile.am b/vendor/flac/man/Makefile.am new file mode 100644 index 0000000..50bacae --- /dev/null +++ b/vendor/flac/man/Makefile.am @@ -0,0 +1,34 @@ +# flac - Command-line FLAC encoder/decoder +# Copyright (C) 2000-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +if FLaC__HAS_PANDOC +flac.1: flac.md + pandoc --standalone --to man $? > $@ + +metaflac.1: metaflac.md + pandoc --standalone --to man $? > $@ + +man_MANS = flac.1 metaflac.1 + +else +if FLaC__HAS_PREBUILT_MANPAGES +man_MANS = flac.1 metaflac.1 +endif +endif + +EXTRA_DIST = flac.1 metaflac.1 flac.md metaflac.md diff --git a/vendor/flac/man/flac.md b/vendor/flac/man/flac.md new file mode 100644 index 0000000..b51ac69 --- /dev/null +++ b/vendor/flac/man/flac.md @@ -0,0 +1,760 @@ +% flac(1) Version 1.4.3 | Free Lossless Audio Codec conversion tool + +# NAME + +flac - Free Lossless Audio Codec + +# SYNOPSIS + +**flac** \[ *OPTIONS* \] \[ *infile.wav* \| *infile.rf64* \| +*infile.aiff* \| *infile.raw* \| *infile.flac* \| *infile.oga* \| +*infile.ogg* \| **-** *...* \] + +**flac** \[ **-d** \| **\--decode** \| **-t** \| **\--test** \| **-a** \| +**\--analyze** \] \[ *OPTIONS* \] \[ *infile.flac* \| *infile.oga* \| +*infile.ogg* \| **-** *...* \] + +# DESCRIPTION + +**flac** is a command-line tool for encoding, decoding, testing and +analyzing FLAC streams. + +# GENERAL USAGE + +**flac** supports as input RIFF WAVE, Wave64, RF64, AIFF, FLAC or Ogg +FLAC format, or raw interleaved samples. The decoder currently can output +to RIFF WAVE, Wave64, RF64, or AIFF format, or raw interleaved samples. +flac only supports linear PCM samples (in other words, no A-LAW, uLAW, +etc.), and the input must be between 4 and 32 bits per sample. + +flac assumes that files ending in ".wav" or that have the RIFF WAVE +header present are WAVE files, files ending in ".w64" or have the Wave64 +header present are Wave64 files, files ending in ".rf64" or have the +RF64 header present are RF64 files, files ending in ".aif" or ".aiff" or +have the AIFF header present are AIFF files, files ending in ".flac" +or have the FLAC header present are FLAC files and files ending in ".oga" +or ".ogg" or have the Ogg FLAC header present are Ogg FLAC files. + +Other than this, flac makes no assumptions about file extensions, though +the convention is that FLAC files have the extension ".flac" +(or ".fla" on ancient "8.3" file systems like FAT-16). + +Before going into the full command-line description, a few other things +help to sort it out: +1. flac encodes by default, so you must use -d to decode +2. the options -0 .. -8 (or --fast and --best) that control the + compression level actually are just synonyms for different groups of + specific encoding options (described later) and you can get the same + effect by using the same options. When specific options are specified + they take priority over the compression level no matter the order +3. flac behaves similarly to gzip in the way it handles input and output + files +4. the order in which options are specified is generally not important + +Skip to the examples below for examples of some common tasks. + +flac will be invoked one of four ways, depending on whether you are +encoding, decoding, testing, or analyzing. Encoding is the default +invocation, but can be switch to decoding with **-d**, analysis with +**-a** or testing with **-t**. Depending on which way is chosen, +encoding, decoding, analysis or testing options can be used, see section +OPTIONS for details. General options can be used for all. + +If only one inputfile is specified, it may be "-" for stdin. When stdin +is used as input, flac will write to stdout. Otherwise flac will perform +the desired operation on each input file to similarly named output files +(meaning for encoding, the extension will be replaced with ".flac", or +appended with ".flac" if the input file has no extension, and for +decoding, the extension will be ".wav" for WAVE output and ".raw" for raw +output). The original file is not deleted unless --delete-input-file is +specified. + +If you are encoding/decoding from stdin to a file, you should use the -o +option like so: + + flac [options] -o outputfile + flac -d [options] -o outputfile + +which are better than: + + flac [options] > outputfile + flac -d [options] > outputfile + +since the former allows flac to seek backwards to write the STREAMINFO or +RIFF WAVE header contents when necessary. + +Also, you can force output data to go to stdout using -c. + +To encode or decode files that start with a dash, use -- to signal the +end of options, to keep the filenames themselves from being treated as +options: + + flac -V -- -01-filename.wav + +The encoding options affect the compression ratio and encoding speed. The +format options are used to tell flac the arrangement of samples if the +input file (or output file when decoding) is a raw file. If it is a RIFF +WAVE, Wave64, RF64, or AIFF file the format options are not needed since +they are read from the file's header. + +In test mode, flac acts just like in decode mode, except no output file +is written. Both decode and test modes detect errors in the stream, but +they also detect when the MD5 signature of the decoded audio does not +match the stored MD5 signature, even when the bitstream is valid. + +flac can also re-encode FLAC files. In other words, you can specify a +FLAC or Ogg FLAC file as an input to the encoder and it will decoder it +and re-encode it according to the options you specify. It will also +preserve all the metadata unless you override it with other options (e.g. +specifying new tags, seekpoints, cuesheet, padding, etc.). + +flac has been tuned so that the default settings yield a good speed vs. +compression tradeoff for many kinds of input. However, if you are looking +to maximize the compression rate or speed, or want to use the full power +of FLAC's metadata system, see the page titled 'About the FLAC Format' on +the FLAC website. + +# EXAMPLES + +Some common **encoding** tasks using flac: + +`flac abc.wav` +: Encode abc.wav to abc.flac using the default compression setting. abc.wav is not deleted. + +`flac --delete-input-file abc.wav` +: Like above, except abc.wav is deleted if there were no errors. + +`flac --delete-input-file -w abc.wav` +: Like above, except abc.wav is deleted if there were no errors or warnings. + +`flac --best abc.wav` +: Encode abc.wav to abc.flac using the highest compression setting. + +`flac --verify abc.wav` +: Encode abc.wav to abc.flac and internally decode abc.flac to make sure it matches abc.wav. + +`flac -o my.flac abc.wav` +: Encode abc.wav to my.flac. + +`flac -T "TITLE=Bohemian Rhapsody" -T "ARTIST=Queen" abc.wav` +: Encode abc.wav and add some tags at the same time to abc.flac. + +`flac *.wav` +: Encode all .wav files in the current directory. + +`flac abc.aiff` +: Encode abc.aiff to abc.flac. + +`flac abc.rf64` +: Encode abc.rf64 to abc.flac. + +`flac abc.w64` +: Encode abc.w64 to abc.flac. + +`flac abc.flac --force` +: This one's a little tricky: notice that flac is in encode mode by + default (you have to specify -d to decode) so this command actually + recompresses abc.flac back to abc.flac. --force is needed to make + sure you really want to overwrite abc.flac with a new version. Why + would you want to do this? It allows you to recompress an existing + FLAC file with (usually) higher compression options or a newer + version of FLAC and preserve all the metadata like tags too. + +Some common **decoding** tasks using flac: + +`flac -d abc.flac` +: Decode abc.flac to abc.wav. abc.flac is not deleted. NOTE: Without + -d it means re-encode abc.flac to abc.flac (see above). + +`flac -d --force-aiff-format abc.flac` +`flac -d -o abc.aiff abc.flac` +: Two different ways of decoding abc.flac to abc.aiff (AIFF format). + abc.flac is not deleted. + +`flac -d --force-rf64-format abc.flac` +`flac -d -o abc.rf64 abc.flac` +: Two different ways of decoding abc.flac to abc.rf64 (RF64 format). + abc.flac is not deleted. + +`flac -d --force-wave64-format abc.flac` +`flac -d -o abc.w64 abc.flac` +: Two different ways of decoding abc.flac to abc.w64 (Wave64 format). + abc.flac is not deleted. + +`flac -d -F abc.flac` +: Decode abc.flac to abc.wav and don't abort if errors are found + (useful for recovering as much as possible from corrupted files). + + +# OPTIONS + +A summary of options is included below. For a complete description, see +the HTML documentation. + +## GENERAL OPTIONS + +**-v, \--version** +: Show the flac version number + +**-h, \--help** +: Show basic usage and a list of all options + +**-H, \--explain** +: Show detailed explanation of usage and all options + +**-d, \--decode** +: Decode (the default behavior is to encode) + +**-t, \--test** +: Test a flac encoded file (same as -d except no decoded file is written) + +**-a, \--analyze** +: Analyze a FLAC encoded file (same as -d except an analysis file is + written) + +**-c, \--stdout** +: Write output to stdout + +**-s, \--silent** +: Silent mode (do not write runtime encode/decode statistics to stderr) + +**\--totally-silent** +: Do not print anything of any kind, including warnings or errors. The + exit code will be the only way to determine successful completion. + +**\--no-utf8-convert** +: Do not convert tags from local charset to UTF-8. This is useful for + scripts, and setting tags in situations where the locale is wrong. + This option must appear before any tag options! + +**-w, \--warnings-as-errors** +: Treat all warnings as errors (which cause flac to terminate with a + non-zero exit code). + +**-f, \--force** +: Force overwriting of output files. By default, flac warns that the + output file already exists and continues to the next file. + +**-o** *filename***, \--output-name=***filename* +: Force the output file name (usually flac just changes the extension). + May only be used when encoding a single file. May not be used in + conjunction with \--output-prefix. + +**\--output-prefix=***string* +: Prefix each output file name with the given string. This can be + useful for encoding or decoding files to a different directory. Make + sure if your string is a path name that it ends with a trailing \`/' + (slash). + +**\--delete-input-file** +: Automatically delete the input file after a successful encode or + decode. If there was an error (including a verify error) the input + file is left intact. + +**\--preserve-modtime** +: Output files have their timestamps/permissions set to match those of + their inputs (this is default). Use \--no-preserve-modtime to make + output files have the current time and default permissions. + +**\--keep-foreign-metadata** +: If encoding, save WAVE, RF64, or AIFF non-audio chunks in FLAC + metadata. If decoding, restore any saved non-audio chunks from FLAC + metadata when writing the decoded file. Foreign metadata cannot be + transcoded, e.g. WAVE chunks saved in a FLAC file cannot be restored + when decoding to AIFF. Input and output must be regular files (not + stdin or stdout). With this option, FLAC will pick the right output + format on decoding. + +**\--keep-foreign-metadata-if-present** +: Like \--keep-foreign-metadata, but without throwing an error if + foreign metadata cannot be found or restored, instead printing a + warning. + +**\--skip={***\#***\|***mm:ss.ss***}** +: Skip over the first number of samples of the input. This works for + both encoding and decoding, but not testing. The alternative form + mm:ss.ss can be used to specify minutes, seconds, and fractions of a + second. + +**\--until={***\#***\|\[***+***\|***-***\]***mm:ss.ss***}** +: Stop at the given sample number for each input file. This works for + both encoding and decoding, but not testing. The given sample number + is not included in the decoded output. The alternative form mm:ss.ss + can be used to specify minutes, seconds, and fractions of a second. + If a \`+' (plus) sign is at the beginning, the \--until point is + relative to the \--skip point. If a \`-' (minus) sign is at the + beginning, the \--until point is relative to end of the audio. + +**\--ogg** +: When encoding, generate Ogg FLAC output instead of native FLAC. Ogg + FLAC streams are FLAC streams wrapped in an Ogg transport layer. The + resulting file should have an '.oga' extension and will still be + decodable by flac. When decoding, force the input to be treated as + Ogg FLAC. This is useful when piping input from stdin or when the + filename does not end in '.oga' or '.ogg'. + +**\--serial-number=***\#* +: When used with \--ogg, specifies the serial number to use for the + first Ogg FLAC stream, which is then incremented for each additional + stream. When encoding and no serial number is given, flac uses a + random number for the first stream, then increments it for each + additional stream. When decoding and no number is given, flac uses + the serial number of the first page. + +## ANALYSIS OPTIONS + +**\--residual-text** +: Includes the residual signal in the analysis file. This will make the + file very big, much larger than even the decoded file. + +**\--residual-gnuplot** +: Generates a gnuplot file for every subframe; each file will contain + the residual distribution of the subframe. This will create a lot of + files. + +## DECODING OPTIONS + +**\--cue=\[***\#.#***\]\[-\[***\#.#***\]\]** +: Set the beginning and ending cuepoints to decode. The optional first + \#.# is the track and index point at which decoding will start; the + default is the beginning of the stream. The optional second \#.# is + the track and index point at which decoding will end; the default is + the end of the stream. If the cuepoint does not exist, the closest + one before it (for the start point) or after it (for the end point) + will be used. If those don't exist, the start of the stream (for the + start point) or end of the stream (for the end point) will be used. + The cuepoints are merely translated into sample numbers then used as + \--skip and \--until. A CD track can always be cued by, for example, + \--cue=9.1-10.1 for track 9, even if the CD has no 10th track. + +**-F, \--decode-through-errors** +: By default flac stops decoding with an error and removes the + partially decoded file if it encounters a bitstream error. With -F, + errors are still printed but flac will continue decoding to + completion. Note that errors may cause the decoded audio to be + missing some samples or have silent sections. + +**\--apply-replaygain-which-is-not-lossless\[=\\]** +: Applies ReplayGain values while decoding. **WARNING: THIS IS NOT + LOSSLESS. DECODED AUDIO WILL NOT BE IDENTICAL TO THE ORIGINAL WITH + THIS OPTION.** This option is useful for example in transcoding + media servers, where the client does not support ReplayGain. For + details on the use of this option, see the section **ReplayGain + application specification**. + +## ENCODING OPTIONS + +**-V, \--verify** +: Verify a correct encoding by decoding the output in parallel and + comparing to the original + +**\--lax** +: Allow encoder to generate non-Subset files. The resulting FLAC file + may not be streamable or might have trouble being played in all + players (especially hardware devices), so you should only use this + option in combination with custom encoding options meant for + archival. + +**\--replay-gain** +: Calculate ReplayGain values and store them as FLAC tags, similar to + vorbisgain. Title gains/peaks will be computed for each input file, + and an album gain/peak will be computed for all files. All input + files must have the same resolution, sample rate, and number of + channels. Only mono and stereo files are allowed, and the sample + rate must be 8, 11.025, 12, 16, 18.9, 22.05, 24, 28, 32, 36, 37.8, + 44.1, 48, 56, 64, 72, 75.6, 88.2, 96, 112, 128, 144, 151.2, 176.4, + 192, 224, 256, 288, 302.4, 352.8, 384, 448, 512, 576, or 604.8 kHz. + Also note that this option may leave a few extra bytes in a PADDING + block as the exact size of the tags is not known until all files + are processed. Note that this option cannot be used when encoding + to standard output (stdout). + +**\--cuesheet=***filename* +: Import the given cuesheet file and store it in a CUESHEET metadata + block. This option may only be used when encoding a single file. A + seekpoint will be added for each index point in the cuesheet to the + SEEKTABLE unless \--no-cued-seekpoints is specified. + +**\--picture={***FILENAME***\|***SPECIFICATION***}** +: Import a picture and store it in a PICTURE metadata block. More than + one \--picture option can be specified. Either a filename for the + picture file or a more complete specification form can be used. The + SPECIFICATION is a string whose parts are separated by \| (pipe) + characters. Some parts may be left empty to invoke default values. + FILENAME is just shorthand for "\|\|\|\|FILENAME". For the format of + SPECIFICATION, see the section **picture specification**. + +**\--ignore-chunk-sizes** +: When encoding to flac, ignore the file size headers in WAV and AIFF + files to attempt to work around problems with over-sized or malformed + files. WAV and AIFF files both have an unsigned 32 bit numbers in + the file header which specifes the length of audio data. Since this + number is unsigned 32 bits, that limits the size of a valid file to + being just over 4 Gigabytes. Files larger than this are mal-formed, + but should be read correctly using this option. + +**-S {***\#***\|***X***\|***\#x***\|***\#s***}, \--seekpoint={***\#***\|***X***\|***\#x***\|***\#s***}** +: Include a point or points in a SEEKTABLE. Using \#, a seek point at + that sample number is added. Using X, a placeholder point is added at + the end of a the table. Using \#x, \# evenly spaced seek points will + be added, the first being at sample 0. Using \#s, a seekpoint will be + added every \# seconds (# does not have to be a whole number; it can + be, for example, 9.5, meaning a seekpoint every 9.5 seconds). You may + use many -S options; the resulting SEEKTABLE will be the unique-ified + union of all such values. With no -S options, flac defaults to + '-S 10s'. Use \--no-seektable for no SEEKTABLE. Note: '-S \#x' and + '-S \#s' will not work if the encoder can't determine the input size + before starting. Note: if you use '-S \#' and \# is \>= samples in + the input, there will be either no seek point entered (if the input + size is determinable before encoding starts) or a placeholder point + (if input size is not determinable). + +**-P** *\#***, \--padding=***\#* +: Tell the encoder to write a PADDING metadata block of the given + length (in bytes) after the STREAMINFO block. This is useful if you + plan to tag the file later with an APPLICATION block; instead of + having to rewrite the entire file later just to insert your block, + you can write directly over the PADDING block. Note that the total + length of the PADDING block will be 4 bytes longer than the length + given because of the 4 metadata block header bytes. You can force no + PADDING block at all to be written with \--no-padding. The encoder + writes a PADDING block of 8192 bytes by default (or 65536 bytes if + the input audio stream is more that 20 minutes long). + +**-T** *FIELD=VALUE***, \--tag=***FIELD=VALUE* +: Add a FLAC tag. The comment must adhere to the Vorbis comment spec; + i.e. the FIELD must contain only legal characters, terminated by an + 'equals' sign. Make sure to quote the comment if necessary. This + option may appear more than once to add several comments. NOTE: all + tags will be added to all encoded files. + +**\--tag-from-file=***FIELD=FILENAME* +: Like \--tag, except FILENAME is a file whose contents will be read + verbatim to set the tag value. The contents will be converted to + UTF-8 from the local charset. This can be used to store a cuesheet + in a tag (e.g. \--tag-from-file="CUESHEET=image.cue"). Do not try to + store binary data in tag fields! Use APPLICATION blocks for that. + +**-b** *\#***, \--blocksize=***\#* +: Specify the blocksize in samples. The default is 1152 for -l 0, + else 4096. For subset streams this must be \<= 4608 if the samplerate + \<= 48kHz, for subset streams with higher samplerates it must be \<= + 16384. + +**-m, \--mid-side** +: Try mid-side coding for each frame (stereo input only) + +**-M, \--adaptive-mid-side** +: Adaptive mid-side coding for all frames (stereo input only) + +**-0..-8, \--compression-level-0..\--compression-level-8** +: Fastest compression..highest compression (default is -5). These are + synonyms for other options: + +**-0, \--compression-level-0** +: Synonymous with -l 0 -b 1152 -r 3 \--no-mid-side + +**-1, \--compression-level-1** +: Synonymous with -l 0 -b 1152 -M -r 3 + +**-2, \--compression-level-2** +: Synonymous with -l 0 -b 1152 -m -r 3 + +**-3, \--compression-level-3** +: Synonymous with -l 6 -b 4096 -r 4 \--no-mid-side + +**-4, \--compression-level-4** +: Synonymous with -l 8 -b 4096 -M -r 4 + +**-5, \--compression-level-5** +: Synonymous with -l 8 -b 4096 -m -r 5 + +**-6, \--compression-level-6** +: Synonymous with -l 8 -b 4096 -m -r 6 -A subdivide_tukey(2) + +**-7, \--compression-level-7** +: Synonymous with -l 12 -b 4096 -m -r 6 -A subdivide_tukey(2) + +**-8, \--compression-level-8** +: Synonymous with -l 12 -b 4096 -m -r 6 -A subdivide_tukey(3) + +**\--fast** +: Fastest compression. Currently synonymous with -0. + +**\--best** +: Highest compression. Currently synonymous with -8. + +**-e, \--exhaustive-model-search** +: Do exhaustive model search (expensive!) + +**-A** *function***, \--apodization=***function* +: Window audio data with given the apodization function. See section + **Apodization functions** for details. + +**-l** *\#***, \--max-lpc-order=***\#* +: Specifies the maximum LPC order. This number must be \<= 32. For + subset streams, it must be \<=12 if the sample rate is \<=48kHz. If + 0, the encoder will not attempt generic linear prediction, and use + only fixed predictors. Using fixed predictors is faster but usually + results in files being 5-10% larger. + +**-p, \--qlp-coeff-precision-search** +: Do exhaustive search of LP coefficient quantization (expensive!). + Overrides -q; does nothing if using -l 0 + +**-q** *\#***, \--qlp-coeff-precision=***\#* +: Precision of the quantized linear-predictor coefficients, 0 =\> let + encoder decide (min is 5, default is 0) + +**-r \[***\#***,\]***\#***, \--rice-partition-order=\[***\#***,\]***\#* +: Set the \[min,\]max residual partition order (0..15). min defaults to + 0 if unspecified. Default is -r 5. + +## FORMAT OPTIONS + +**\--endian={***big***\|***little***}** +: Set the byte order for samples + +**\--channels=***\#* +: Set number of channels. + +**\--bps=***\#* +: Set bits per sample. + +**\--sample-rate=***\#* +: Set sample rate (in Hz). + +**\--sign={***signed***\|***unsigned***}** +: Set the sign of samples. + +**\--input-size=***\#* +: Specify the size of the raw input in bytes. If you are encoding raw + samples from stdin, you must set this option in order to be able to + use \--skip, \--until, \--cuesheet, or other options that need to + know the size of the input beforehand. If the size given is greater + than what is found in the input stream, the encoder will complain + about an unexpected end-of-file. If the size given is less, samples + will be truncated. + +**\--force-raw-format** +: Force input (when encoding) or output (when decoding) to be treated + as raw samples (even if filename ends in *.wav*). + +**\--force-aiff-format** +**\--force-rf64-format** +**\--force-wave64-format** +: Force the decoder to output AIFF/RF64/WAVE64 format respectively. + This option is not needed if the output filename (as set by -o) + ends with *.aif* or *.aiff*, *.rf64* and *.w64* respectively. Also, + this option has no effect when encoding since input is + auto-detected. When none of these options nor + --keep-foreign-metadata are given and no output filename is set, + the output format is WAV by default. + +**\--force-legacy-wave-format** +**\--force-extensible-wave-format** +: Instruct the decoder to output a WAVE file with WAVE_FORMAT_PCM and + WAVE_FORMAT_EXTENSIBLE respectively. If none of these options nor + --keep-foreign-metadata are given, FLAC outputs WAVE_FORMAT_PCM + for mono or stereo with a bit depth of 8 or 16 bits, and + WAVE_FORMAT_EXTENSIBLE for all other audio formats. + +**\--force-aiff-c-none-format** +**\--force-aiff-c-sowt-format** +: Instruct the decoder to output an AIFF-C file with format NONE and + sowt respectively. + +## NEGATIVE OPTIONS + +**\--no-adaptive-mid-side** +**\--no-cued-seekpoints** +**\--no-decode-through-errors** +**\--no-delete-input-file** +**\--no-preserve-modtime** +**\--no-keep-foreign-metadata** +**\--no-exhaustive-model-search** +**\--no-force** +**\--no-lax** +**\--no-mid-side** +**\--no-ogg** +**\--no-padding** +**\--no-qlp-coeff-prec-search** +**\--no-replay-gain** +**\--no-residual-gnuplot** +**\--no-residual-text** +**\--no-seektable** +**\--no-silent** +**\--no-verify** +**\--no-warnings-as-errors** + +These flags can be used to invert the sense of the corresponding normal +option. + +## ReplayGain application specification +The option \--apply-replaygain-which-is-not-lossless\[=\\]** +applies ReplayGain values while decoding. **WARNING: THIS IS NOT +LOSSLESS. DECODED AUDIO WILL NOT BE IDENTICAL TO THE ORIGINAL WITH THIS +OPTION.** This option is useful for example in transcoding media servers, +where the client does not support ReplayGain. + +The equals sign and \ is optional. If omitted, the +default specification is 0aLn1. + +The \ is a shorthand notation for describing how to apply +ReplayGain. All components are optional but order is important. '\[\]' +means 'optional'. '\|' means 'or'. '{}' means required. The format is: + +\[\\]\[a\|t\]\[l\|L\]\[n{0\|1\|2\|3}\] + +In which the following parameters are used: + +- **preamp**: A floating point number in dB. This is added to the + existing gain value. + +- **a\|t**: Specify 'a' to use the album gain, or 't' to use the track + gain. If tags for the preferred kind (album/track) do not exist but + tags for the other (track/album) do, those will be used instead. + +- **l\|L**: Specify 'l' to peak-limit the output, so that the + ReplayGain peak value is full-scale. Specify 'L' to use a 6dB hard + limiter that kicks in when the signal approaches full-scale. + +- **n{0\|1\|2\|3}**: Specify the amount of noise shaping. ReplayGain + synthesis happens in floating point; the result is dithered before + converting back to integer. This quantization adds noise. Noise + shaping tries to move the noise where you won't hear it as much. + 0 means no noise shaping, 1 means 'low', 2 means 'medium', 3 means + 'high'. + +For example, the default of 0aLn1 means 0dB preamp, use album gain, 6dB +hard limit, low noise shaping. \--apply-replaygain-which-is-not-lossless=3 +means 3dB preamp, use album gain, no limiting, no noise shaping. + +flac uses the ReplayGain tags for the calculation. If a stream does +not have the required tags or they can't be parsed, decoding will +continue with a warning, and no ReplayGain is applied to that stream. + +## Picture specification +This described the specification used for the **\--picture** option. +\[TYPE\]\|\[MIME-TYPE\]\|\[DESCRIPTION\]\|\[WIDTHxHEIGHTxDEPTH\[/COLORS\]\]\|FILE + +TYPE is optional; it is a number from one of: + +0. Other +1. 32x32 pixels 'file icon' (PNG only) +2. Other file icon +3. Cover (front) +4. Cover (back) +5. Leaflet page +6. Media (e.g. label side of CD) +7. Lead artist/lead performer/soloist +8. Artist/performer +9. Conductor +10. Band/Orchestra +11. Composer +12. Lyricist/text writer +13. Recording Location +14. During recording +15. During performance +16. Movie/video screen capture +17. A bright coloured fish +18. Illustration +19. Band/artist logotype +20. Publisher/Studio logotype + +The default is 3 (front cover). There may only be one picture each of +type 1 and 2 in a file. + +MIME-TYPE is optional; if left blank, it will be detected from the file. +For best compatibility with players, use pictures with MIME type +image/jpeg or image/png. The MIME type can also be \--\> to mean that +FILE is actually a URL to an image, though this use is discouraged. + +DESCRIPTION is optional; the default is an empty string. + +The next part specifies the resolution and color information. If the +MIME-TYPE is image/jpeg, image/png, or image/gif, you can usually leave +this empty and they can be detected from the file. Otherwise, you must +specify the width in pixels, height in pixels, and color depth in +bits-per-pixel. If the image has indexed colors you should also specify +the number of colors used. When manually specified, it is not checked +against the file for accuracy. + +FILE is the path to the picture file to be imported, or the URL if MIME +type is \--\> + +For example, "\|image/jpeg\|\|\|../cover.jpg" will embed the JPEG file +at ../cover.jpg, defaulting to type 3 (front cover) and an empty +description. The resolution and color info will be retrieved from the +file itself. + +The specification +"4\|\--\>\|CD\|320x300x24/173\|http://blah.blah/backcover.tiff" will +embed the given URL, with type 4 (back cover), description "CD", and a +manually specified resolution of 320x300, 24 bits-per-pixel, and 173 +colors. The file at the URL will not be fetched; the URL itself is +stored in the PICTURE metadata block. + +## Apodization functions +To improve LPC analysis, audio data is windowed . The window can be +selected with one or more **-A** options. Possible functions are: +bartlett, bartlett_hann, blackman, blackman_harris_4term_92db, +connes, flattop, gauss(STDDEV), hamming, hann, kaiser_bessel, nuttall, +rectangle, triangle, tukey(P), partial_tukey(n\[/ov\[/P\]\]), +punchout_tukey(n\[/ov\[/P\]\]), subdivide_tukey(n\[/P\]) welch. + +- For gauss(STDDEV), STDDEV is the standard deviation (0\ for the Debian GNU/Linux system (but may be used by +others). It has been kept up-to-date by the Xiph.org Foundation. diff --git a/vendor/flac/man/metaflac.md b/vendor/flac/man/metaflac.md new file mode 100644 index 0000000..8c049d7 --- /dev/null +++ b/vendor/flac/man/metaflac.md @@ -0,0 +1,299 @@ +% metaflac(1) Version 1.4.3 | Free Lossless Audio Codec metadata tool + +# NAME + +metaflac - program to list, add, remove, or edit metadata in one or more +FLAC files. + +# SYNOPSIS + +**metaflac** \[ *options* \] \[ *operations* \] *FLACfile ...* + +# DESCRIPTION + +Use **metaflac** to list, add, remove, or edit metadata in one or more +FLAC files. You may perform one major operation, or many shorthand +operations at a time. + +# GENERAL USAGE + +metaflac is the command-line .flac file metadata editor. You can use it +to list the contents of metadata blocks, edit, delete or insert blocks, +and manage padding. + +metaflac takes a set of "options" (though some are not optional) and a +set of FLAC files to operate on. There are three kinds of "options": + +- Major operations, which specify a mode of operation like listing + blocks, removing blocks, etc. These will have sub-operations describing + exactly what is to be done. + +- Shorthand operations, which are convenient synonyms for major + operations. For example, there is a shorthand operation + --show-sample-rate that shows just the sample rate field from the + STREAMINFO metadata block. + +- Global options, which affect all the operations. + +All of these are described in the tables below. At least one shorthand +or major operation must be supplied. You can use multiple shorthand +operations to do more than one thing to a file or set of files. Most of +the common things to do to metadata have shorthand operations. As an +example, here is how to show the MD5 signatures for a set of three FLAC +files: + +`metaflac --show-md5sum file1.flac file2.flac file3.flac` + +Another example; this removes all DESCRIPTION and COMMENT tags in a set +of FLAC files, and uses the --preserve-modtime global option to keep the +FLAC file modification times the same (usually when files are edited the +modification time is set to the current time): + +`metaflac --preserve-modtime --remove-tag=DESCRIPTION --remove-tag=COMMENT file1.flac file2.flac file3.flac` + +# OPTIONS + +**\--preserve-modtime** +: Preserve the original modification time in spite of edits. + +**\--with-filename** +: Prefix each output line with the FLAC file name (the default if more + than one FLAC file is specified). This option has no effect for + options exporting to a file, like --export-tags-to. + +**\--no-filename** +: Do not prefix each output line with the FLAC file name (the default + if only one FLAC file is specified). + +**\--no-utf8-convert** +: Do not convert tags from UTF-8 to local charset, or vice versa. This + is useful for scripts, and setting tags in situations where the + locale is wrong. + +**\--dont-use-padding** +: By default metaflac tries to use padding where possible to avoid + rewriting the entire file if the metadata size changes. Use this + option to tell metaflac to not take advantage of padding this way. + +# SHORTHAND OPERATIONS + +**\--show-md5sum** +: Show the MD5 signature from the STREAMINFO block. + +**\--show-min-blocksize** +: Show the minimum block size from the STREAMINFO block. + +**\--show-max-blocksize** +: Show the maximum block size from the STREAMINFO block. + +**\--show-min-framesize** +: Show the minimum frame size from the STREAMINFO block. + +**\--show-max-framesize** +: Show the maximum frame size from the STREAMINFO block. + +**\--show-sample-rate** +: Show the sample rate from the STREAMINFO block. + +**\--show-channels** +: Show the number of channels from the STREAMINFO block. + +**\--show-bps** +: Show the \# of bits per sample from the STREAMINFO block. + +**\--show-total-samples** +: Show the total \# of samples from the STREAMINFO block. + +**\--show-vendor-tag** +: Show the vendor string from the VORBIS_COMMENT block. + +**\--show-tag=name** +: Show all tags where the field name matches 'name'. + +**\--show-all-tags** +: Show all tags. This is an alias for --export-tags-to=-. + +**\--remove-tag=name** +: Remove all tags whose field name is 'name'. + +**\--remove-first-tag=name** +: Remove first tag whose field name is 'name'. + +**\--remove-all-tags** +: Remove all tags, leaving only the vendor string. + +**\--remove-all-tags-except=NAME1\[=NAME2\[=...\]\]** +: Remove all tags, except the vendor string and the tag names + specified. Tag names must be separated by an = character. + +**\--set-tag=field** +: Add a tag. The field must comply with the Vorbis comment spec, of the + form "NAME=VALUE". If there is currently no tag block, one will be + created. + +**\--set-tag-from-file=field** +: Like \--set-tag, except the VALUE is a filename whose contents will + be read verbatim to set the tag value. Unless \--no-utf8-convert is + specified, the contents will be converted to UTF-8 from the local + charset. This can be used to store a cuesheet in a tag (e.g. + \--set-tag-from-file="CUESHEET=image.cue"). Do not try to store + binary data in tag fields! Use APPLICATION blocks for that. + +**\--import-tags-from=file** +: Import tags from a file. Use '-' for stdin. Each line should be of + the form NAME=VALUE. Multi-line comments are currently not supported. + Specify \--remove-all-tags and/or \--no-utf8-convert before + \--import-tags-from if necessary. If FILE is '-' (stdin), only one + FLAC file may be specified. + +**\--export-tags-to=file** +: Export tags to a file. Use '-' for stdout. Each line will be of the + form NAME=VALUE. Specify \--no-utf8-convert if necessary. + +**\--import-cuesheet-from=file** +: Import a cuesheet from a file. Use '-' for stdin. Only one FLAC file + may be specified. A seekpoint will be added for each index point in + the cuesheet to the SEEKTABLE unless \--no-cued-seekpoints is + specified. + +**\--export-cuesheet-to=file** +: Export CUESHEET block to a cuesheet file, suitable for use by CD + authoring software. Use '-' for stdout. Only one FLAC file may be + specified on the command line. + +**\--import-picture-from={***FILENAME***\|***SPECIFICATION***}** +: Import a picture and store it in a PICTURE metadata block. More than + one \--import-picture-from command can be specified. Either a filename + for the picture file or a more complete specification form can be + used. The SPECIFICATION is a string whose parts are separated by \| + (pipe) characters. Some parts may be left empty to invoke default + values. FILENAME is just shorthand for "\|\|\|\|FILENAME". For + details on the specification, see the section **Picture + specification** in the **flac(1)** man page. + +**\--export-picture-to=file** +: Export PICTURE block to a file. Use '-' for stdout. Only one FLAC + file may be specified on the command line. The first PICTURE block + will be exported unless \--export-picture-to is preceded by a + \--block-number=# option to specify the exact metadata block to + extract. Note that the block number is the one shown by \--list. + +**\--add-replay-gain** +: Calculates the title and album gains/peaks of the given FLAC files as + if all the files were part of one album, then stores them as FLAC + tags. The tags are the same as those used by vorbisgain. Existing + ReplayGain tags will be replaced. If only one FLAC file is given, + the album and title gains will be the same. Since this operation + requires two passes, it is always executed last, after all other + operations have been completed and written to disk. All FLAC files + specified must have the same resolution, sample rate, and number of + channels. Only mono and stereo files are allowed, and the sample + rate must be 8, 11.025, 12, 16, 18.9, 22.05, 24, 28, 32, 36, 37.8, + 44.1, 48, 56, 64, 72, 75.6, 88.2, 96, 112, 128, 144, 151.2, 176.4, + 192, 224, 256, 288, 302.4, 352.8, 384, 448, 512, 576, or 604.8 kHz. + +**\--scan-replay-gain** +: Like \--add-replay-gain, but only analyzes the files rather than + writing them to the tags. + +**\--remove-replay-gain** +: Removes the ReplayGain tags. + +**\--add-seekpoint={***\#***\|***X***\|***\#x***\|***\#s***}** +: Add seek points to a SEEKTABLE block. Using \#, a seek point at that + sample number is added. Using X, a placeholder point is added at the + end of a the table. Using \#x, \# evenly spaced seek points will be + added, the first being at sample 0. Using \#s, a seekpoint will be + added every \# seconds (# does not have to be a whole number; it can + be, for example, 9.5, meaning a seekpoint every 9.5 seconds). If no + SEEKTABLE block exists, one will be created. If one already exists, + points will be added to the existing table, and any duplicates will + be turned into placeholder points. You may use many \--add-seekpoint + options; the resulting SEEKTABLE will be the unique-ified union of + all such values. Example: \--add-seekpoint=100x \--add-seekpoint=3.5s + will add 100 evenly spaced seekpoints and a seekpoint every 3.5 + seconds. + +**\--add-padding=length** +: Add a padding block of the given length (in bytes). The overall + length of the new block will be 4 + length; the extra 4 bytes is for + the metadata block header. + +# MAJOR OPERATIONS + +**\--list** +: List the contents of one or more metadata blocks to stdout. By + default, all metadata blocks are listed in text format. Use the + options **\--block-number**, **\--block-type** or + **\--except-block-type** to change this behavior. + +**\--remove** +: Remove one or more metadata blocks from the metadata. Use the options + **\--block-number**, **\--block-type** or **\--except-block-type** + to specify which blocks should be removed. Note that if both + \--block-number and \--[except-]block-type are specified, the result + is the logical AND of both arguments. Unless \--dont-use-padding + is specified, the blocks will be replaced with padding. You may not + remove the STREAMINFO block. + +**\--block-number=#\[,#\[...\]\]** +: An optional comma-separated list of block numbers to display. The + first block, the STREAMINFO block, is block 0. + +**\--block-type=type\[,type\[...\]\]** + +**\--except-block-type=type\[,type\[...\]\]** +: An optional comma-separated list of block types to be included or + ignored with this option. Use only one of \--block-type or + \--except-block-type. The valid block types are: STREAMINFO, PADDING, + APPLICATION, SEEKTABLE, VORBIS_COMMENT, PICTURE. You may narrow down + the types of APPLICATION blocks selected by appending APPLICATION + with a colon and the ID of the APPLICATION block in either ASCII + or hexadecimal representation. E.g. APPLICATION:abcd for the + APPLICATION block(s) whose textual representation of the 4-byte ID + is "abcd" or APPLICATION:0xXXXXXXXX for the APPLICATION block(s) + whose hexadecimal big- endian representation of the 4-byte ID + is "0xXXXXXXXX". For the example "abcd" above the hexadecimal + equivalalent is 0x61626364 + +**\--application-data-format=hexdump\|text** +: If the application block you are displaying contains binary data but + your \--data-format=text, you can display a hex dump of the + application data contents instead using + \--application-data-format=hexdump. + +**\--data-format=binary\|binary-headerless\|text** +: For use with --list. By default a human-readable text + representation of the data is isplayed. You may specify + --data-format=binary to dump the raw binary form of each metadata + block. Specify --data-format=binary-headerless to omit output of + metadata block headers, including the id of APPLICATION metadata + blocks. + +**\--append** +: Insert a metadata block from a file. This must be a binary block as + exported with --list --data-format=binary. The insertion point is + defined with --block-number=#. The new block will be added after the + given block number. This prevents the illegal insertion of a block + before the first STREAMINFO block. You may not --append another + STREAMINFO block. It is possible to copy a metadata block from one + file to another with this option. For example use + `metaflac --list --data-format=binary --block-number=6 file.flac > block` + to export the block, and then import it with + `metaflac --append anotherfile.flac < block` + +**\--remove-all** +: Remove all metadata blocks (except the STREAMINFO block) from the + metadata. Unless \--dont-use-padding is specified, the blocks will be + replaced with padding. + +**\--merge-padding** +: Merge adjacent PADDING blocks into single blocks. + +**\--sort-padding** +: Move all PADDING blocks to the end of the metadata and merge them + into a single block. + +# SEE ALSO + +**flac(1)** diff --git a/vendor/flac/microbench/CMakeLists.txt b/vendor/flac/microbench/CMakeLists.txt new file mode 100644 index 0000000..639915b --- /dev/null +++ b/vendor/flac/microbench/CMakeLists.txt @@ -0,0 +1,17 @@ +if(MSVC) + return() +endif() + +set(CMAKE_REQUIRED_LIBRARIES rt) +check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) + +if(APPLE) + add_definitions(-DFLAC__SYS_DARWIN) +endif() + +add_executable(benchmark_residual benchmark_residual.c util.c) +target_include_directories(benchmark_residual PRIVATE + "$/include") +target_link_libraries(benchmark_residual + FLAC + $<$:rt>) diff --git a/vendor/flac/microbench/Makefile.am b/vendor/flac/microbench/Makefile.am new file mode 100644 index 0000000..81de3ad --- /dev/null +++ b/vendor/flac/microbench/Makefile.am @@ -0,0 +1,42 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2015-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/libFLAC/include + +noinst_HEADERS = util.h + +noinst_PROGRAMS = benchmark_residual + +benchmark_residual_SOURCES = benchmark_residual.c util.c + +benchmark_residual_LDADD = @LIB_CLOCK_GETTIME@ + +EXTRA_DIST = CMakeLists.txt diff --git a/vendor/flac/microbench/benchmark_residual.c b/vendor/flac/microbench/benchmark_residual.c new file mode 100644 index 0000000..d9b19d7 --- /dev/null +++ b/vendor/flac/microbench/benchmark_residual.c @@ -0,0 +1,151 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include "FLAC/ordinals.h" +#include "share/compat.h" +#include "private/bitmath.h" +#include "private/fixed.h" +#include "private/macros.h" +#include "FLAC/assert.h" + +#include "util.h" + +static void FLAC__fixed_compute_residual_shift(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]) +{ + const int idata_len = (int) data_len; + int i; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(residual, data, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - (data[i-1] << 1) + data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +static void FLAC__fixed_compute_residual_mult(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]) +{ + const int idata_len = (int)data_len; + int i; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(residual, data, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 2*data[i-1] + data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +static FLAC__int32 data [200000] ; +static FLAC__int32 residual [200000] ; + +static unsigned bench_order = 0 ; + +static void +bench_shift (void) +{ FLAC__fixed_compute_residual_shift (data, ARRAY_LEN (data), bench_order, residual) ; +} + +static void +bench_mult (void) +{ FLAC__fixed_compute_residual_mult (data, ARRAY_LEN (data), bench_order, residual) ; +} + +int +main (void) +{ bench_stats stats ; + + puts ("") ; + + for (bench_order = 2 ; bench_order <= 4 ; bench_order ++) { + memset (&stats, 0, sizeof (stats)) ; + stats.testfunc = bench_shift ; + stats.run_count = 100 ; + stats.loop_count = 10 ; + + benchmark_stats (&stats) ; + printf ("shift order %u : %f %f %f %f\n", bench_order, stats.min_time, stats.median_time, stats.mean_time, stats.max_time) ; + + memset (&stats, 0, sizeof (stats)) ; + stats.testfunc = bench_mult ; + stats.run_count = 100 ; + stats.loop_count = 10 ; + + benchmark_stats (&stats) ; + printf ("mult order %u : %f %f %f %f\n\n", bench_order, stats.min_time, stats.median_time, stats.mean_time, stats.max_time) ; + } + + return 0 ; +} diff --git a/vendor/flac/microbench/util.c b/vendor/flac/microbench/util.c new file mode 100644 index 0000000..2ecd4a3 --- /dev/null +++ b/vendor/flac/microbench/util.c @@ -0,0 +1,205 @@ +/* FLAC - Free Lossless Audio Codec + * Copyright (C) 2015-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "util.h" + +#if defined _WIN32 + +#include + +static double +counter_diff (const LARGE_INTEGER * start, const LARGE_INTEGER * end) +{ + LARGE_INTEGER diff, freq; + + QueryPerformanceFrequency(&freq); + diff.QuadPart = end->QuadPart - start->QuadPart; + + return (double)diff.QuadPart/(double)freq.QuadPart; +} + +double +benchmark_function (void (*testfunc) (void), unsigned count) +{ + LARGE_INTEGER start, end; + unsigned k; + + QueryPerformanceCounter (&start) ; + + for (k = 0 ; k < count ; k++) + testfunc(); + + QueryPerformanceCounter (&end) ; + + return counter_diff (&start, &end) / count ; +} /* benchmark_function */ + +#elif defined FLAC__SYS_DARWIN + +#include + +static double +counter_diff (const uint64_t * start, const uint64_t * end) +{ + mach_timebase_info_data_t t_info; + mach_timebase_info(&t_info); + uint64_t duration = *end - *start; + + return duration * ((double)t_info.numer/(double)t_info.denom); +} + +double +benchmark_function (void (*testfunc) (void), unsigned count) +{ + uint64_t start, end; + unsigned k; + + start = mach_absolute_time(); + + for (k = 0 ; k < count ; k++) + testfunc(); + + end = mach_absolute_time(); + + return counter_diff (&start, &end) / count ; +} /* benchmark_function */ + +#elif defined HAVE_CLOCK_GETTIME + +#include +#include + +static double +timespec_diff (const struct timespec * start, const struct timespec * end) +{ struct timespec diff; + + if (end->tv_nsec - start->tv_nsec < 0) + { diff.tv_sec = end->tv_sec - start->tv_sec - 1 ; + diff.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec ; + } + else + { diff.tv_sec = end->tv_sec - start->tv_sec ; + diff.tv_nsec = end->tv_nsec-start->tv_nsec ; + } ; + + return diff.tv_sec + 1e-9 * diff.tv_nsec ; +} + +double +benchmark_function (void (*testfunc) (void), unsigned count) +{ struct timespec start, end; + unsigned k ; + + clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &start) ; + + for (k = 0 ; k < count ; k++) + testfunc () ; + + clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &end) ; + + return timespec_diff (&start, &end) / count ; +} /* benchmark_function */ + +#else + +#include +#include + +static double +timeval_diff (const struct timeval * start, const struct timeval * end) +{ struct timeval diff; + + if (end->tv_usec - start->tv_usec < 0) + { diff.tv_sec = end->tv_sec - start->tv_sec - 1 ; + diff.tv_usec = 1000000 + end->tv_usec - start->tv_usec ; + } + else + { diff.tv_sec = end->tv_sec - start->tv_sec ; + diff.tv_usec = end->tv_usec-start->tv_usec ; + } ; + + return diff.tv_sec + 1e-6 * diff.tv_usec ; +} + +double +benchmark_function (void (*testfunc) (void), unsigned count) +{ struct timeval start, end; + unsigned k ; + + gettimeofday(&start, NULL); + + for (k = 0 ; k < count ; k++) + testfunc () ; + + gettimeofday(&end, NULL); + + return timeval_diff (&start, &end) / count ; +} /* benchmark_function */ + +#endif + +static int +double_cmp (const void * a, const void * b) +{ const double * pa = (double *) a ; + const double * pb = (double *) b ; + return pa [0] < pb [0] ; +} /* double_cmp */ + +void +benchmark_stats (bench_stats * stats) +{ double sum, times [stats->run_count] ; + unsigned k ; + + for (k = 0 ; k < stats->run_count ; k++) + times [k] = benchmark_function (stats->testfunc, stats->loop_count) ; + + qsort (times, stats->run_count, sizeof (times [0]), double_cmp) ; + + sum = 0.0 ; + stats->min_time = stats->max_time = times [0] ; + for (k = 0 ; k < stats->run_count ; k++) + { stats->min_time = stats->min_time < times [k] ? stats->min_time : times [k] ; + stats->max_time = stats->max_time > times [k] ? stats->max_time : times [k] ; + sum += times [k] ; + } + stats->mean_time = sum / stats->run_count ; + if (stats->run_count & 1) + stats->median_time = times [(stats->run_count + 1) / 2] ; + else + stats->median_time = 0.5 * (times [stats->run_count / 2] + times [(stats->run_count / 2) + 1]) ; + + return ; +} /* benchmark_stats */ diff --git a/vendor/flac/microbench/util.h b/vendor/flac/microbench/util.h new file mode 100644 index 0000000..1fba446 --- /dev/null +++ b/vendor/flac/microbench/util.h @@ -0,0 +1,43 @@ +/* FLAC - Free Lossless Audio Codec + * Copyright (C) 2015-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define ARRAY_LEN(x) ((sizeof (x) / sizeof (x [0]))) + +typedef struct bench_stats +{ void (*testfunc) (void) ; + unsigned run_count ; + unsigned loop_count ; + double min_time, mean_time, median_time, max_time ; +} bench_stats ; + +double benchmark_function (void (*testfunc) (void), unsigned count) ; + +void benchmark_stats (bench_stats * stats) ; diff --git a/vendor/flac/oss-fuzz/Makefile.am b/vendor/flac/oss-fuzz/Makefile.am new file mode 100644 index 0000000..bf669aa --- /dev/null +++ b/vendor/flac/oss-fuzz/Makefile.am @@ -0,0 +1,104 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2019-2023 Xiph.Org Foundation +# +# This file is part the FLAC project. FLAC is comprised of several +# components distributed under different licenses. The codec libraries +# are distributed under Xiph.Org's BSD-like license (see the file +# COPYING.Xiph in this distribution). All other programs, libraries, and +# plugins are distributed under the GPL (see COPYING.GPL). The documentation +# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the +# FLAC distribution contains at the top the terms under which it may be +# distributed. +# +# Since this particular file is relevant to all components of FLAC, +# it may be distributed under the Xiph.Org license, which is the least +# restrictive of those mentioned above. See the file COPYING.Xiph in this +# distribution. + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/oss-fuzz + +AM_CFLAGS = ${LIB_FUZZING_ENGINE} +AM_CXXFLAGS = -std=c++11 $(LIB_FUZZING_ENGINE) +LDADD = $(flac_libs) + + +EXTRA_DIST = \ + fuzzer_encoder.dict \ + common.h \ + Readme.md \ + fuzzing/datasource/datasource.hpp \ + fuzzing/datasource/id.hpp \ + fuzzing/exception.hpp \ + fuzzing/memory.hpp \ + fuzzing/types.hpp + +noinst_PROGRAMS = + +if USE_OSSFUZZERS +noinst_PROGRAMS += fuzzer_encoder fuzzer_encoder_v2 fuzzer_decoder fuzzer_seek fuzzer_metadata fuzzer_reencoder fuzzer_tool_flac fuzzer_tool_metaflac +endif + +fuzzer_encoder_SOURCES = encoder.cc +fuzzer_encoder_v2_SOURCES = encoder_v2.cc +fuzzer_decoder_SOURCES = decoder.cc +fuzzer_seek_SOURCES = seek.cc +fuzzer_metadata_SOURCES = metadata.cc +fuzzer_reencoder_SOURCES = reencoder.cc +fuzzer_tool_flac_SOURCES = ${flac_SOURCES} empty.cc tool_flac.c # empty.cc is to force use of C++ linker, which is mandated by oss-fuzz +fuzzer_tool_flac_LDADD = \ + $(top_builddir)/src/share/utf8/libutf8.la \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/getopt/libgetopt.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + @LTLIBICONV@ \ + -lm +fuzzer_tool_metaflac_SOURCES = ${metaflac_SOURCES} empty.cc tool_metaflac.c # empty.cc is to force use of C++ linker, which is mandated by oss-fuzz +fuzzer_tool_metaflac_LDADD = \ + $(top_builddir)/src/share/utf8/libutf8.la \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/getopt/libgetopt.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + @LTLIBICONV@ \ + -lm + +flac_libs = \ + $(top_builddir)/src/libFLAC/libFLAC-static.la \ + $(top_builddir)/src/libFLAC++/libFLAC++-static.la \ + @OGG_LIBS@ \ + -lm + +flac_SOURCES = \ + ${top_builddir}/src/flac/analyze.c \ + ${top_builddir}/src/flac/decode.c \ + ${top_builddir}/src/flac/encode.c \ + ${top_builddir}/src/flac/foreign_metadata.c \ + ${top_builddir}/src/flac/local_string_utils.c \ + ${top_builddir}/src/flac/utils.c \ + ${top_builddir}/src/flac/vorbiscomment.c \ + ${top_builddir}/src/flac/analyze.h \ + ${top_builddir}/src/flac/decode.h \ + ${top_builddir}/src/flac/encode.h \ + ${top_builddir}/src/flac/foreign_metadata.h \ + ${top_builddir}/src/flac/local_string_utils.h \ + ${top_builddir}/src/flac/utils.h \ + ${top_builddir}/src/flac/vorbiscomment.h + +metaflac_SOURCES = \ + ${top_builddir}/src/metaflac/operations.c \ + ${top_builddir}/src/metaflac/operations_shorthand_cuesheet.c \ + ${top_builddir}/src/metaflac/operations_shorthand_picture.c \ + ${top_builddir}/src/metaflac/operations_shorthand_seektable.c \ + ${top_builddir}/src/metaflac/operations_shorthand_streaminfo.c \ + ${top_builddir}/src/metaflac/operations_shorthand_vorbiscomment.c \ + ${top_builddir}/src/metaflac/options.c \ + ${top_builddir}/src/metaflac/usage.c \ + ${top_builddir}/src/metaflac/utils.c \ + ${top_builddir}/src/metaflac/operations.h \ + ${top_builddir}/src/metaflac/operations_shorthand.h \ + ${top_builddir}/src/metaflac/options.h \ + ${top_builddir}/src/metaflac/usage.h \ + ${top_builddir}/src/metaflac/utils.h diff --git a/vendor/flac/oss-fuzz/Readme.md b/vendor/flac/oss-fuzz/Readme.md new file mode 100644 index 0000000..90f2763 --- /dev/null +++ b/vendor/flac/oss-fuzz/Readme.md @@ -0,0 +1,13 @@ +Fuzzers fuzzer_decoder.cc and fuzzer_encoder.cc were taken from + + https://github.com/guidovranken/flac-fuzzers + +The header files in the directory fuzzing and below were taken from: + + https://github.com/guidovranken/fuzzing-headers.git + +Some minor modifications were made to make them build with the default C++ +warning flags. + +The code mentioned above, contributed by Guido Vranken, is licensed under +the MIT license. See the files themselves for details diff --git a/vendor/flac/oss-fuzz/common.h b/vendor/flac/oss-fuzz/common.h new file mode 100644 index 0000000..9545f95 --- /dev/null +++ b/vendor/flac/oss-fuzz/common.h @@ -0,0 +1,2 @@ +extern int alloc_check_threshold, alloc_check_counter; +int alloc_check_threshold = INT32_MAX, alloc_check_counter = 0; diff --git a/vendor/flac/oss-fuzz/decoder.cc b/vendor/flac/oss-fuzz/decoder.cc new file mode 100644 index 0000000..b7ddf21 --- /dev/null +++ b/vendor/flac/oss-fuzz/decoder.cc @@ -0,0 +1,408 @@ +/* Copyright 2019 Guido Vranken + * + * 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 +#include + +#include +#include + +#include "FLAC++/decoder.h" +#include "FLAC++/metadata.h" +#include "common.h" + +template <> FLAC__MetadataType fuzzing::datasource::Base::Get(const uint64_t id) { + (void)id; + switch ( Get() ) { + case 0: + return FLAC__METADATA_TYPE_STREAMINFO; + case 1: + return FLAC__METADATA_TYPE_PADDING; + case 2: + return FLAC__METADATA_TYPE_APPLICATION; + case 3: + return FLAC__METADATA_TYPE_SEEKTABLE; + case 4: + return FLAC__METADATA_TYPE_VORBIS_COMMENT; + case 5: + return FLAC__METADATA_TYPE_CUESHEET; + case 6: + return FLAC__METADATA_TYPE_PICTURE; + case 7: + return FLAC__METADATA_TYPE_UNDEFINED; + case 8: + return FLAC__MAX_METADATA_TYPE; + default: + return FLAC__METADATA_TYPE_STREAMINFO; + } +} + +namespace FLAC { + namespace Decoder { + class FuzzerStream : public Stream { + private: + fuzzing::datasource::Datasource& ds; + public: + FuzzerStream(fuzzing::datasource::Datasource& dsrc) : + Stream(), ds(dsrc) { } + + ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override { + try { + const size_t maxCopySize = *bytes; + + if ( maxCopySize > 0 ) { + /* memset just to test if this overwrites anything, and triggers ASAN */ + memset(buffer, 0, maxCopySize); + } + + const auto data = ds.GetData(0); + const auto dataSize = data.size(); + const auto copySize = std::min(maxCopySize, dataSize); + + if ( copySize > 0 ) { + memcpy(buffer, data.data(), copySize); + } + + *bytes = copySize; + + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } catch ( ... ) { + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + } + + ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override { + { + fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header)); + fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer)); + } + + { + const auto numChannels = get_channels(); + const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32); + for (size_t i = 0; i < numChannels; i++) { + fuzzing::memory::memory_test(buffer[i], bytesPerChannel); + } + } + + try { + if ( ds.Get() == true ) { + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } catch ( ... ) { } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + + void error_callback(::FLAC__StreamDecoderErrorStatus status) override { + fuzzing::memory::memory_test(status); + } + + void metadata_callback(const ::FLAC__StreamMetadata *metadata) override { + Metadata::Prototype * cloned_object = nullptr; + fuzzing::memory::memory_test(metadata->type); + fuzzing::memory::memory_test(metadata->is_last); + fuzzing::memory::memory_test(metadata->length); + fuzzing::memory::memory_test(metadata->data); + if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) + cloned_object = new Metadata::StreamInfo(metadata); + else if (metadata->type == FLAC__METADATA_TYPE_PADDING) + cloned_object = new Metadata::Padding(metadata); + else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) + cloned_object = new Metadata::Application(metadata); + else if (metadata->type == FLAC__METADATA_TYPE_SEEKTABLE) + cloned_object = new Metadata::SeekTable(metadata); + else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + cloned_object = new Metadata::VorbisComment(metadata); + else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET) + cloned_object = new Metadata::CueSheet(metadata); + else if (metadata->type == FLAC__METADATA_TYPE_PICTURE) + cloned_object = new Metadata::Picture(metadata); + else + return; + if (0 != cloned_object && *cloned_object == *metadata && cloned_object->is_valid()) { + if (cloned_object->get_type() == FLAC__METADATA_TYPE_SEEKTABLE) + dynamic_cast(cloned_object)->is_legal(); + if (cloned_object->get_type() == FLAC__METADATA_TYPE_PICTURE) + dynamic_cast(cloned_object)->is_legal(NULL); + if (cloned_object->get_type() == FLAC__METADATA_TYPE_CUESHEET) + dynamic_cast(cloned_object)->is_legal(true,NULL); + } + delete cloned_object; + } + + ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override { + fuzzing::memory::memory_test(absolute_byte_offset); + + try { + if ( ds.Get() == true ) { + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; + } else { + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + } catch ( ... ) { + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; + } + } +#if 0 + ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override { + fuzzing::memory::memory_test(*absolute_byte_offset); + + try { + if ( ds.Get() == true ) { + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } else { + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + } + } catch ( ... ) { + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } + } + + ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override { + fuzzing::memory::memory_test(*stream_length); + + try { + if ( ds.Get() == true ) { + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } else { + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + } + } catch ( ... ) { + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } + } +#endif + }; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + fuzzing::datasource::Datasource ds(data, size); + FLAC::Decoder::FuzzerStream decoder(ds); + bool use_ogg = true; + + try { + if ( ds.Get() ) { + use_ogg = false; + } + if ( ds.Get() ) { +#ifdef FUZZER_DEBUG + printf("set_ogg_serial_number\n"); +#endif + decoder.set_ogg_serial_number(ds.Get()); + } + if ( ds.Get() ) { +#ifdef FUZZER_DEBUG + printf("set_md5_checking\n"); +#endif + decoder.set_md5_checking(ds.Get()); + } + if ( ds.Get() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_respond\n"); +#endif + decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>()); + } + if ( ds.Get() ) { + const auto idVector = ds.GetData(0); + unsigned char id[4]; + if ( idVector.size() >= sizeof(id) ) { + memcpy(id, idVector.data(), sizeof(id)); +#ifdef FUZZER_DEBUG + printf("set_metadata_respond_application\n"); +#endif + decoder.set_metadata_respond_application(id); + } + } + if ( ds.Get() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_respond_all\n"); +#endif + decoder.set_metadata_respond_all(); + } + if ( ds.Get() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_ignore\n"); +#endif + decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>()); + } + if ( ds.Get() ) { + const auto idVector = ds.GetData(0); + unsigned char id[4]; + if ( idVector.size() >= sizeof(id) ) { + memcpy(id, idVector.data(), sizeof(id)); +#ifdef FUZZER_DEBUG + printf("set_metadata_ignore_application\n"); +#endif + decoder.set_metadata_ignore_application(id); + } + } + if ( ds.Get() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_ignore_all\n"); +#endif + decoder.set_metadata_ignore_all(); + } + { + ::FLAC__StreamDecoderInitStatus ret; + if ( !use_ogg ) { + ret = decoder.init(); + } else { + ret = decoder.init_ogg(); + } + + if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) { + goto end; + } + } + + while ( ds.Get() ) { + switch ( ds.Get() ) { + case 0: + { +#ifdef FUZZER_DEBUG + printf("flush\n"); +#endif + const bool res = decoder.flush(); + fuzzing::memory::memory_test(res); + } + break; + case 1: + { +#ifdef FUZZER_DEBUG + printf("reset\n"); +#endif + const bool res = decoder.reset(); + fuzzing::memory::memory_test(res); + } + break; + case 2: + { +#ifdef FUZZER_DEBUG + printf("process_single\n"); +#endif + const bool res = decoder.process_single(); + fuzzing::memory::memory_test(res); + } + break; + case 3: + { +#ifdef FUZZER_DEBUG + printf("process_until_end_of_metadata\n"); +#endif + const bool res = decoder.process_until_end_of_metadata(); + fuzzing::memory::memory_test(res); + } + break; + case 4: + { +#ifdef FUZZER_DEBUG + printf("process_until_end_of_stream\n"); +#endif + const bool res = decoder.process_until_end_of_stream(); + fuzzing::memory::memory_test(res); + } + break; + case 5: + { +#ifdef FUZZER_DEBUG + printf("skip_single_frame\n"); +#endif + const bool res = decoder.skip_single_frame(); + fuzzing::memory::memory_test(res); + } + break; + case 6: + { +#ifdef FUZZER_DEBUG + printf("seek_absolute\n"); +#endif + const bool res = decoder.seek_absolute(ds.Get()); + fuzzing::memory::memory_test(res); + } + break; + case 7: + { +#ifdef FUZZER_DEBUG + printf("get_md5_checking\n"); +#endif + const bool res = decoder.get_md5_checking(); + fuzzing::memory::memory_test(res); + } + break; + case 8: + { +#ifdef FUZZER_DEBUG + printf("get_total_samples\n"); +#endif + const bool res = decoder.get_total_samples(); + fuzzing::memory::memory_test(res); + } + break; + case 9: + { +#ifdef FUZZER_DEBUG + printf("get_channels\n"); +#endif + const bool res = decoder.get_channels(); + fuzzing::memory::memory_test(res); + } + break; + case 10: + { +#ifdef FUZZER_DEBUG + printf("get_bits_per_sample\n"); +#endif + const bool res = decoder.get_bits_per_sample(); + fuzzing::memory::memory_test(res); + } + break; + case 11: + { +#ifdef FUZZER_DEBUG + printf("get_sample_rate\n"); +#endif + const bool res = decoder.get_sample_rate(); + fuzzing::memory::memory_test(res); + } + break; + case 12: + { +#ifdef FUZZER_DEBUG + printf("get_blocksize\n"); +#endif + const bool res = decoder.get_blocksize(); + fuzzing::memory::memory_test(res); + } + break; + } + } + } catch ( ... ) { } + +end: + { + const bool res = decoder.finish(); + fuzzing::memory::memory_test(res); + } + return 0; +} diff --git a/vendor/flac/oss-fuzz/empty.cc b/vendor/flac/oss-fuzz/empty.cc new file mode 100644 index 0000000..e69de29 diff --git a/vendor/flac/oss-fuzz/encoder.cc b/vendor/flac/oss-fuzz/encoder.cc new file mode 100644 index 0000000..23cb397 --- /dev/null +++ b/vendor/flac/oss-fuzz/encoder.cc @@ -0,0 +1,257 @@ +/* Copyright 2019 Guido Vranken + * + * 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 +#include +#include + +#include +#include + +#include "FLAC++/encoder.h" +#include "common.h" + +namespace FLAC { + namespace Encoder { + class FuzzerStream : public Stream { + private: + // fuzzing::datasource::Datasource& ds; + public: + FuzzerStream(fuzzing::datasource::Datasource&) : + Stream() { } + + ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override { + fuzzing::memory::memory_test(buffer, bytes); +#if 0 + try { + if ( ds.Get() == true ) { + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + } catch ( ... ) { } +#endif + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; + } + }; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + fuzzing::datasource::Datasource ds(data, size); + FLAC::Encoder::FuzzerStream encoder(ds); + + try { + const int channels = ds.Get(); + const int bps = ds.Get(); + encoder.set_channels(channels); + encoder.set_bits_per_sample(bps); + + { + const bool res = encoder.set_streamable_subset(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_ogg_serial_number(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_verify(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_compression_level(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_do_exhaustive_model_search(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_do_mid_side_stereo(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_loose_mid_side_stereo(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const auto s = ds.Get(); + const bool res = encoder.set_apodization(s.data()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_max_lpc_order(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_qlp_coeff_precision(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_do_qlp_coeff_prec_search(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_do_escape_coding(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_min_residual_partition_order(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_max_residual_partition_order(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_rice_parameter_search_dist(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_total_samples_estimate(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_blocksize(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_limit_min_bitrate(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_sample_rate(ds.Get()); + fuzzing::memory::memory_test(res); + } + + if ( size > 2 * 65535 * 4 ) { + /* With large inputs and expensive options enabled, the fuzzer can get *really* slow. + * Some combinations can make the fuzzer timeout (>60 seconds). However, while combining + * options makes the fuzzer slower, most options do not expose new code when combined. + * Therefore, combining slow options is disabled for large inputs. Any input containing + * more than 65536 * 2 samples of 32 bits each (max blocksize, stereo) is considered large + */ + encoder.set_do_qlp_coeff_prec_search(false); + encoder.set_do_exhaustive_model_search(false); + } + if ( size > 2 * 4096 * 4 + 250 ) { + /* With subdivide_tukey in the mix testing apodizations can get really expensive. Therefore + * this is disabled for inputs of more than one whole stereo block of 32-bit inputs plus a + * bit of overhead */ + encoder.set_apodization(""); + } + + { + ::FLAC__StreamEncoderInitStatus ret; + if ( ds.Get() ) { + ret = encoder.init(); + } else { + ret = encoder.init_ogg(); + } + + if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) { + goto end; + } + } + + /* These sets must fail, because encoder is already initialized */ + { + bool res = false; + res = res || encoder.set_streamable_subset(true); + res = res || encoder.set_ogg_serial_number(0); + res = res || encoder.set_verify(true); + res = res || encoder.set_compression_level(0); + res = res || encoder.set_do_exhaustive_model_search(true); + res = res || encoder.set_do_mid_side_stereo(true); + res = res || encoder.set_loose_mid_side_stereo(true); + res = res || encoder.set_apodization("test"); + res = res || encoder.set_max_lpc_order(0); + res = res || encoder.set_qlp_coeff_precision(0); + res = res || encoder.set_do_qlp_coeff_prec_search(true); + res = res || encoder.set_do_escape_coding(true); + res = res || encoder.set_min_residual_partition_order(0); + res = res || encoder.set_max_residual_partition_order(0); + res = res || encoder.set_rice_parameter_search_dist(0); + res = res || encoder.set_total_samples_estimate(0); + res = res || encoder.set_channels(channels); + res = res || encoder.set_bits_per_sample(16); + res = res || encoder.set_limit_min_bitrate(true); + res = res || encoder.set_blocksize(3021); + res = res || encoder.set_sample_rate(44100); + fuzzing::memory::memory_test(res); + if(res) + abort(); + } + + + { + /* XORing values as otherwise compiler will optimize, apparently */ + bool res = false; + res = res != encoder.get_streamable_subset(); + res = res != encoder.get_verify(); + res = res != encoder.get_do_exhaustive_model_search(); + res = res != encoder.get_do_mid_side_stereo(); + res = res != encoder.get_loose_mid_side_stereo(); + res = res != encoder.get_max_lpc_order(); + res = res != encoder.get_qlp_coeff_precision(); + res = res != encoder.get_do_qlp_coeff_prec_search(); + res = res != encoder.get_do_escape_coding(); + res = res != encoder.get_min_residual_partition_order(); + res = res != encoder.get_max_residual_partition_order(); + res = res != encoder.get_rice_parameter_search_dist(); + res = res != encoder.get_total_samples_estimate(); + res = res != encoder.get_channels(); + res = res != encoder.get_bits_per_sample(); + res = res != encoder.get_limit_min_bitrate(); + res = res != encoder.get_blocksize(); + res = res != encoder.get_sample_rate(); + fuzzing::memory::memory_test(res); + } + + + while ( ds.Get() ) { + { + auto dat = ds.GetVector(); + + if( ds.Get() ) + /* Mask */ + for (size_t i = 0; i < dat.size(); i++) + /* If we get here, bps is 4 or larger, or init will have failed */ + dat[i] = (int32_t)(((uint32_t)(dat[i]) << (32-bps)) >> (32-bps)); + + const uint32_t samples = dat.size() / channels; + if ( samples > 0 ) { + const int32_t* ptr = dat.data(); + const bool res = encoder.process_interleaved(ptr, samples); + fuzzing::memory::memory_test(res); + } + } + } + } catch ( ... ) { } + +end: + { + const bool res = encoder.finish(); + fuzzing::memory::memory_test(res); + } + return 0; +} diff --git a/vendor/flac/oss-fuzz/encoder_v2.cc b/vendor/flac/oss-fuzz/encoder_v2.cc new file mode 100644 index 0000000..6448346 --- /dev/null +++ b/vendor/flac/oss-fuzz/encoder_v2.cc @@ -0,0 +1,352 @@ +/* fuzzer_encoder_v2 + * Copyright (C) 2022-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include /* for memcpy */ +#include "FLAC/stream_encoder.h" +#include "FLAC/metadata.h" +extern "C" { +#include "share/private.h" +} +#include "common.h" + +/* This C++ fuzzer uses the FLAC and not FLAC++ because the latter lacks a few + * hidden functions like FLAC__stream_encoder_disable_constant_subframes. It + * is still processed by a C++ compiler because that's what oss-fuzz expects */ + + +static FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data) +{ + (void)encoder, (void)buffer, (void)bytes, (void)samples, (void)current_frame, (void)client_data; + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + FLAC__bool encoder_valid = true; + FLAC__StreamEncoder *encoder = 0; + FLAC__StreamEncoderState state; + FLAC__StreamMetadata *metadata[16] = {NULL}; + unsigned num_metadata = 0; + FLAC__StreamMetadata_VorbisComment_Entry VorbisCommentField; + + unsigned sample_rate, channels, bps; + uint64_t samples_estimate, samples_in_input; + unsigned compression_level, input_data_width, blocksize, max_lpc_order, qlp_coeff_precision, min_residual_partition_order, max_residual_partition_order, metadata_mask, instruction_set_disable_mask; + FLAC__bool ogg, write_to_file, interleaved; + + FLAC__bool data_bools[24]; + + /* Set alloc threshold. This check was added later and no spare config + * bytes were left, so we're reusing the sample rate as that of little + * consequence to the encoder and decoder except reading the frame header */ + + if(size < 3) + return 0; + alloc_check_threshold = data[2]; + alloc_check_counter = 0; + + /* allocate the encoder */ + if((encoder = FLAC__stream_encoder_new()) == NULL) { + fprintf(stderr, "ERROR: allocating encoder\n"); + return 1; + } + + /* Use first 20 byte for configuration */ + if(size < 20){ + FLAC__stream_encoder_delete(encoder); + return 0; + } + + /* First 3 byte for sample rate, 4th byte for channels, 5th byte for bps */ + sample_rate = ((unsigned)data[0] << 16) + ((unsigned)data[1] << 8) + data[2]; + channels = data[3]; + bps = data[4]; + + /* Number of samples estimate, format accepts 36-bit max */ + samples_estimate = ((uint64_t)data[5] << 32) + ((unsigned)data[6] << 24) + ((unsigned)data[7] << 16) + ((unsigned)data[8] << 8) + data[9]; + + compression_level = data[10]&0b1111; + input_data_width = 1 + (data[10]>>4)%4; + samples_in_input = (size-20)/input_data_width; + blocksize = ((unsigned)data[11] << 8) + (unsigned)data[12]; + max_lpc_order = data[13]; + qlp_coeff_precision = data[14]; + min_residual_partition_order = data[15] & 0b1111; + max_residual_partition_order = data[15] & 0b11110000; + metadata_mask = data[16]; + instruction_set_disable_mask = data[17]; + + /* Get array of bools from configuration */ + for(int i = 0; i < 16; i++) + data_bools[i] = data[18+i/8] & (1 << (i % 8)); + + ogg = data_bools[0]; + interleaved = data_bools[1]; + write_to_file = data_bools[13]; + + /* Set input and process parameters */ + encoder_valid &= FLAC__stream_encoder_set_verify(encoder, data_bools[2]); + encoder_valid &= FLAC__stream_encoder_set_channels(encoder, channels); + encoder_valid &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps); + encoder_valid &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate); + encoder_valid &= FLAC__stream_encoder_set_total_samples_estimate(encoder, samples_estimate); + encoder_valid &= FLAC__stream_encoder_disable_instruction_set(encoder, instruction_set_disable_mask); + encoder_valid &= FLAC__stream_encoder_set_limit_min_bitrate(encoder, data_bools[15]); + + /* Set compression related parameters */ + encoder_valid &= FLAC__stream_encoder_set_compression_level(encoder, compression_level); + if(data_bools[3]){ + /* Bias towards regular compression levels */ + encoder_valid &= FLAC__stream_encoder_set_blocksize(encoder, blocksize); + encoder_valid &= FLAC__stream_encoder_set_max_lpc_order(encoder, max_lpc_order); + encoder_valid &= FLAC__stream_encoder_set_qlp_coeff_precision(encoder, qlp_coeff_precision); + encoder_valid &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, min_residual_partition_order); + + /* With large inputs and expensive options enabled, the fuzzer can get *really* slow. + * Some combinations can make the fuzzer timeout (>60 seconds). However, while combining + * options makes the fuzzer slower, most options do not expose new code when combined. + * Therefore, combining slow options is disabled for large inputs. Any input containing + * more than 65536 * 2 samples (max blocksize, stereo) is considered large + */ + if(samples_in_input < (2*65536)) { + encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, data_bools[4]); + encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, data_bools[5]); + encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, data_bools[6]); + encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, data_bools[7]); + /* Combining model search, precision search and a high residual partition order is especially + * expensive, so limit that even further. This high partition order can only be set on + * large blocksize and with streamable subset disabled */ + if(samples_in_input < (2 * 4609) || data_bools[4] || !data_bools[7] || !data_bools[5] || max_residual_partition_order < 9 || blocksize < 4609) + encoder_valid &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, max_residual_partition_order); + } + else { + if(!data_bools[4]) + encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, false); + else if(data_bools[6]) + encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, true); + else if(data_bools[7]) + encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, true); + else if(data_bools[5]) + encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, true); + } + encoder_valid &= FLAC__stream_encoder_set_do_mid_side_stereo(encoder, data_bools[8]); + encoder_valid &= FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, data_bools[9]); + + encoder_valid &= FLAC__stream_encoder_disable_constant_subframes(encoder, data_bools[10]); + encoder_valid &= FLAC__stream_encoder_disable_fixed_subframes(encoder, data_bools[11]); + encoder_valid &= FLAC__stream_encoder_disable_verbatim_subframes(encoder, data_bools[12]); + } + + /* Disable alloc check if requested */ + if(encoder_valid && data_bools[14]) + alloc_check_threshold = INT32_MAX; + + /* add metadata */ + if(encoder_valid && (metadata_mask & 1)) { + if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO)) == NULL) + encoder_valid = false; + else + num_metadata++; + } + if(encoder_valid && (metadata_mask & 2) && size > 21){ + if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL) + encoder_valid = false; + else { + metadata[num_metadata++]->length = (((unsigned)data[20]) << 8) + (unsigned)(data[21]); + } + } + if(encoder_valid && (metadata_mask & 4) && size > 20){ + FLAC__byte * application_data = (FLAC__byte *)malloc(size-20); + if(0 != application_data && ((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)) == NULL)) + encoder_valid = false; + else { + memcpy(application_data,data+20,size-20); + FLAC__metadata_object_application_set_data(metadata[num_metadata++], application_data, size-20, 0); + } + } + if(encoder_valid && (metadata_mask & 8) && size > 25){ + if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE)) == NULL) + encoder_valid = false; + else { + unsigned seekpoint_spacing = ((unsigned)data[22] << 8) + data[23]; + unsigned total_samples_for_seekpoints = ((unsigned)data[24] << 8) + data[25]; + FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(metadata[num_metadata++], seekpoint_spacing, total_samples_for_seekpoints); + } + } + if(encoder_valid && (metadata_mask & 16)){ + if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) != NULL) { + bool vorbiscomment_valid = true; + /* Append a vorbis comment */ + if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Nothing to 🤔 report")) + vorbiscomment_valid = false; + else { + if(FLAC__metadata_object_vorbiscomment_append_comment(metadata[num_metadata], VorbisCommentField, false)) { + + /* Insert a vorbis comment at the first index */ + if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Still nothing to report 🤔🤣")) + vorbiscomment_valid = false; + else + if(!FLAC__metadata_object_vorbiscomment_insert_comment(metadata[num_metadata], 0, VorbisCommentField, false)) { + free(VorbisCommentField.entry); + vorbiscomment_valid = false; + } + } + else { + free(VorbisCommentField.entry); + vorbiscomment_valid = false; + } + } + if(!vorbiscomment_valid) { + FLAC__metadata_object_delete(metadata[num_metadata]); + metadata[num_metadata] = 0; + } + else + num_metadata++; + } + } + if(encoder_valid && (metadata_mask & 32)){ + if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)) != NULL) { + if(!FLAC__metadata_object_cuesheet_insert_blank_track(metadata[num_metadata],0)) { + FLAC__metadata_object_delete(metadata[num_metadata]); + metadata[num_metadata] = 0; + } + else { + if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(metadata[num_metadata],0,0)) { + FLAC__metadata_object_delete(metadata[num_metadata]); + metadata[num_metadata] = 0; + } + else { + metadata[num_metadata]->data.cue_sheet.tracks[0].number = 1; + num_metadata++; + } + } + } + } + if(encoder_valid && (metadata_mask & 64)){ + if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) != NULL) { + num_metadata++; + } + } + if(encoder_valid && (metadata_mask & 128)){ + if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_UNDEFINED)) != NULL) { + metadata[num_metadata]->length = 24; + metadata[num_metadata]->data.unknown.data = (FLAC__byte *)calloc(24, 1); + num_metadata++; + } + } + + if(num_metadata && encoder_valid) + encoder_valid = FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata); + + /* initialize encoder */ + if(encoder_valid) { + FLAC__StreamEncoderInitStatus init_status; + if(ogg) + if(write_to_file) + init_status = FLAC__stream_encoder_init_ogg_file(encoder, "/tmp/tmp.flac", NULL, NULL); + else + init_status = FLAC__stream_encoder_init_ogg_stream(encoder, NULL, write_callback, NULL, NULL, NULL, NULL); + else + if(write_to_file) + init_status = FLAC__stream_encoder_init_file(encoder, "/tmp/tmp.flac", NULL, NULL); + else + init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, NULL); + if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + encoder_valid = false; + } + } + + + /* send samples to encoder */ + if(encoder_valid && size > (input_data_width*channels+26)) { + unsigned samples = (size - 26)/input_data_width/channels; + const uint8_t * pcm_data = data + 26; + int32_t * data_as_int32 = (int32_t *)malloc(4*samples*channels); + if(0 != data_as_int32){ + for(unsigned i = 0; i < samples*channels; i++) + if(input_data_width == 1) + data_as_int32[i] = (int32_t)pcm_data[i] - 0x80; + else if(input_data_width == 2) + data_as_int32[i] = (((int32_t)pcm_data[i*2] << 8) + pcm_data[i*2+1]) - 0x8000; + else if(input_data_width == 3) + data_as_int32[i] = (((int32_t)pcm_data[i*3] << 16) + ((int32_t)pcm_data[i*3+1] << 8) + pcm_data[i*3+2]) - 0x800000; + else if(input_data_width == 4) + data_as_int32[i] = (((int64_t)pcm_data[i*4] << 24) + ((int32_t)pcm_data[i*4+1] << 16) + ((int32_t)pcm_data[i*4+2] << 8) + pcm_data[i*4+3]) - 0x80000000; + + /* feed samples to encoder */ + if(interleaved) + encoder_valid = FLAC__stream_encoder_process_interleaved(encoder, data_as_int32, samples); + else { + encoder_valid = FLAC__stream_encoder_process(encoder, (const int32_t*[]){data_as_int32, + data_as_int32+samples, + data_as_int32+samples*2, + data_as_int32+samples*3, + data_as_int32+samples*4, data_as_int32+samples*5, data_as_int32+samples*6, data_as_int32+samples*7}, samples); + } + free(data_as_int32); + } + else { + encoder_valid = false; + } + } + + state = FLAC__stream_encoder_get_state(encoder); + if(!(state == FLAC__STREAM_ENCODER_OK || + state == FLAC__STREAM_ENCODER_UNINITIALIZED || + state == FLAC__STREAM_ENCODER_CLIENT_ERROR || + ((state == FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR || + state == FLAC__STREAM_ENCODER_FRAMING_ERROR || + (state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR && + FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR)) && + alloc_check_threshold < INT32_MAX))) { + fprintf(stderr,"-----\nERROR: stream encoder returned %s\n-----\n",FLAC__stream_encoder_get_resolved_state_string(encoder)); + if(state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) { + uint32_t frame_number, channel, sample_number; + FLAC__int32 expected, got; + FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, NULL, &frame_number, &channel, &sample_number, &expected, &got); + fprintf(stderr,"Frame number %d\nChannel %d\n Sample number %d\nExpected value %d\nGot %d\n", frame_number, channel, sample_number, expected, got); + } + abort(); + } + + FLAC__stream_encoder_finish(encoder); + + /* now that encoding is finished, the metadata can be freed */ + for(unsigned i = 0; i < 16; i++) + if(0 != metadata[i]) + FLAC__metadata_object_delete(metadata[i]); + + FLAC__stream_encoder_delete(encoder); + + return 0; +} + diff --git a/vendor/flac/oss-fuzz/fuzzer_decoder.dict b/vendor/flac/oss-fuzz/fuzzer_decoder.dict new file mode 100644 index 0000000..0e79191 --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzer_decoder.dict @@ -0,0 +1,6 @@ +flac_stream_marker="fLaC" +ogg_stream_marker="OggS" +flac_in_ogg_marker="\x7fFLAC" + +synccode_fixed_blocksize="\xFF\xF8" +synccode_variable_blocksize="\xFF\xF9" diff --git a/vendor/flac/oss-fuzz/fuzzer_encoder.dict b/vendor/flac/oss-fuzz/fuzzer_encoder.dict new file mode 100644 index 0000000..9662137 --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzer_encoder.dict @@ -0,0 +1,18 @@ +"bartlett" +"bartlett_hann" +"blackman" +"blackman_harris_4term_92db" +"connes" +"flattop" +"gauss()" +"hamming" +"hann" +"kaiser_bessel" +"nuttall" +"rectangle" +"triangle" +"tukey(0)" +"partial_tukey(0)" +"punchout_tukey(0)" +"subdivide_tukey(0)" +"welch" diff --git a/vendor/flac/oss-fuzz/fuzzer_reencoder.dict b/vendor/flac/oss-fuzz/fuzzer_reencoder.dict new file mode 100644 index 0000000..0e79191 --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzer_reencoder.dict @@ -0,0 +1,6 @@ +flac_stream_marker="fLaC" +ogg_stream_marker="OggS" +flac_in_ogg_marker="\x7fFLAC" + +synccode_fixed_blocksize="\xFF\xF8" +synccode_variable_blocksize="\xFF\xF9" diff --git a/vendor/flac/oss-fuzz/fuzzer_tool_flac.dict b/vendor/flac/oss-fuzz/fuzzer_tool_flac.dict new file mode 100644 index 0000000..3ef9be5 --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzer_tool_flac.dict @@ -0,0 +1,19 @@ +"--keep-foreign-metadata-if-present" +"--replay-gain" +"--apply-replaygain-which-is-not-lossless" + +"--force-raw-format" +"--force-aiff-format" +"--force-rf64-format" +"--force-wave64-format" +"--force-aiff-c-sowt-format" +"--force-aiff-c-none-format" +"--force-legacy-wave-format" +"--force-extensible-wave-format" + +"--endian=big" +"--sample-rate=1" +"--channels=1" +"--bps=32" +"--sign=unsigned" + diff --git a/vendor/flac/oss-fuzz/fuzzing/datasource/datasource.hpp b/vendor/flac/oss-fuzz/fuzzing/datasource/datasource.hpp new file mode 100644 index 0000000..3c9484e --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzing/datasource/datasource.hpp @@ -0,0 +1,190 @@ +/* Copyright 2019 Guido Vranken + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fuzzing { +namespace datasource { + +class Base +{ + protected: + virtual std::vector get(const size_t min, const size_t max, const uint64_t id = 0) = 0; + public: + Base(void) = default; + virtual ~Base(void) = default; + + template T Get(const uint64_t id = 0); + uint16_t GetChoice(const uint64_t id = 0); + std::vector GetData(const uint64_t id, const size_t min = 0, const size_t max = 0); + template std::vector GetVector(const uint64_t id = 0); + + class OutOfData : public fuzzing::exception::FlowException { + public: + OutOfData() = default; + }; + + class DeserializationFailure : public fuzzing::exception::FlowException { + public: + DeserializationFailure() = default; + }; +}; + +#ifndef FUZZING_HEADERS_NO_IMPL +template T Base::Get(const uint64_t id) +{ + T ret; + const auto v = get(sizeof(ret), sizeof(ret), id); + memcpy(&ret, v.data(), sizeof(ret)); + return ret; +} + +template <> bool Base::Get(const uint64_t id) +{ + uint8_t ret; + const auto v = get(sizeof(ret), sizeof(ret), id); + memcpy(&ret, v.data(), sizeof(ret)); + return (ret % 2) ? true : false; +} + +template <> std::string Base::Get(const uint64_t id) +{ + auto data = GetData(id); + return std::string(data.data(), data.data() + data.size()); +} + +template <> std::vector Base::Get>(const uint64_t id) +{ + std::vector ret; + while ( true ) { + auto data = GetData(id); + ret.push_back( std::string(data.data(), data.data() + data.size()) ); + if ( Get(id) == false ) { + break; + } + } + return ret; +} + +uint16_t Base::GetChoice(const uint64_t id) +{ + return Get(id); +} + +std::vector Base::GetData(const uint64_t id, const size_t min, const size_t max) +{ + return get(min, max, id); +} + + +template <> types::String<> Base::Get>(const uint64_t id) { + const auto data = GetData(id); + types::String<> ret(data.data(), data.size()); + return ret; +} + +template <> types::Data<> Base::Get>(const uint64_t id) { + const auto data = GetData(id); + types::Data<> ret(data.data(), data.size()); + return ret; +} + +template +std::vector Base::GetVector(const uint64_t id) { + std::vector ret; + + while ( Get(id) == true ) { + ret.push_back( Get(id) ); + } + + return ret; +} +#endif + +class Datasource : public Base +{ + private: + const uint8_t* data; + const size_t size; + size_t idx; + size_t left; + std::vector get(const size_t min, const size_t max, const uint64_t id = 0) override; + + // Make copy constructor and assignment operator private. + Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {} + Datasource& operator=(const Datasource &) { return *this; } + public: + Datasource(const uint8_t* _data, const size_t _size); +}; + +#ifndef FUZZING_HEADERS_NO_IMPL +Datasource::Datasource(const uint8_t* _data, const size_t _size) : + Base(), data(_data), size(_size), idx(0), left(size) +{ +} + +std::vector Datasource::get(const size_t min, const size_t max, const uint64_t id) { + (void)id; + + uint32_t getSize; + if ( left < sizeof(getSize) ) { + throw OutOfData(); + } + memcpy(&getSize, data + idx, sizeof(getSize)); + idx += sizeof(getSize); + left -= sizeof(getSize); + + if ( getSize < min ) { + getSize = min; + } + if ( max && getSize > max ) { + getSize = max; + } + + if ( left < getSize ) { + throw OutOfData(); + } + + std::vector ret(getSize); + + if ( getSize > 0 ) { + memcpy(ret.data(), data + idx, getSize); + } + idx += getSize; + left -= getSize; + + return ret; +} +#endif + +} /* namespace datasource */ +} /* namespace fuzzing */ diff --git a/vendor/flac/oss-fuzz/fuzzing/datasource/id.hpp b/vendor/flac/oss-fuzz/fuzzing/datasource/id.hpp new file mode 100644 index 0000000..457c984 --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzing/datasource/id.hpp @@ -0,0 +1,75 @@ +/* Copyright 2019 Guido Vranken + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace fuzzing { +namespace datasource { + +/* From: https://gist.github.com/underscorediscovery/81308642d0325fd386237cfa3b44785c */ +inline uint64_t hash_64_fnv1a(const void* key, const uint64_t len) { + + const char* data = (char*)key; + uint64_t hash = 0xcbf29ce484222325; + uint64_t prime = 0x100000001b3; + + for(uint64_t i = 0; i < len; ++i) { + uint8_t value = data[i]; + hash = hash ^ value; + hash *= prime; + } + + return hash; + +} //hash_64_fnv1a + +// FNV1a c++11 constexpr compile time hash functions, 32 and 64 bit +// str should be a null terminated string literal, value should be left out +// e.g hash_32_fnv1a_const("example") +// code license: public domain or equivalent +// post: https://notes.underscorediscovery.com/constexpr-fnv1a/ + +constexpr uint32_t val_32_const = 0x811c9dc5; +constexpr uint32_t prime_32_const = 0x1000193; +constexpr uint64_t val_64_const = 0xcbf29ce484222325; +constexpr uint64_t prime_64_const = 0x100000001b3; + + +inline constexpr uint64_t ID(const char* const str, const uint64_t value = val_64_const) noexcept { + auto ret = (str[0] == '\0') ? value : ID(&str[1], (value ^ uint64_t(str[0])) * prime_64_const); + return ret; +} + +inline constexpr std::pair IDPair(const char* const str, const uint64_t value = val_64_const) noexcept { + return {str, ID(str, value)}; +} + +using IDMap = std::map; + +} /* namespace datasource */ +} /* namespace fuzzing */ diff --git a/vendor/flac/oss-fuzz/fuzzing/exception.hpp b/vendor/flac/oss-fuzz/fuzzing/exception.hpp new file mode 100644 index 0000000..d1ec580 --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzing/exception.hpp @@ -0,0 +1,67 @@ +/* Copyright 2019 Guido Vranken + * + * 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. + */ + +#pragma once + +#include +#include + +namespace fuzzing { +namespace exception { + +class ExceptionBase : public std::exception { + public: + ExceptionBase(void) = default; + /* typeid(T).name */ +}; + +/* Recoverable exception */ +class FlowException : public ExceptionBase { + public: + FlowException(void) : ExceptionBase() { } +}; + +/* Error in this library, should never happen */ +class LogicException : public ExceptionBase { + private: + std::string reason; + public: + LogicException(const std::string r) : ExceptionBase(), reason(r) { } + virtual const char* what(void) const throw() { + return reason.c_str(); + } +}; + +/* Error in target application */ +class TargetException : public ExceptionBase { + private: + std::string reason; + public: + TargetException(const std::string r) : ExceptionBase(), reason(r) { } + virtual const char* what(void) const throw() { + return reason.c_str(); + } +}; + +} /* namespace exception */ +} /* namespace fuzzing */ diff --git a/vendor/flac/oss-fuzz/fuzzing/memory.hpp b/vendor/flac/oss-fuzz/fuzzing/memory.hpp new file mode 100644 index 0000000..b324c36 --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzing/memory.hpp @@ -0,0 +1,96 @@ +/* Copyright 2019 Guido Vranken + * + * 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. + */ + +#pragma once + +#include +#include + +#ifndef ASAN +#define ASAN 0 +#endif + +#ifndef MSAN +#define MSAN 0 +#endif + +namespace fuzzing { +namespace memory { + +#ifndef FUZZING_HEADERS_NO_IMPL +#if ASAN == 1 +extern "C" void *__asan_region_is_poisoned(const void *beg, size_t size); +#endif + +#if MSAN == 1 +extern "C" void __msan_check_mem_is_initialized(const volatile void *x, size_t size); +#endif + +void memory_test_asan(const void* data, const size_t size) +{ + (void)data; + (void)size; + +#if ASAN == 1 + if ( __asan_region_is_poisoned(data, size) != NULL ) { + abort(); + } +#endif +} + +void memory_test_msan(const void* data, const size_t size) +{ + (void)data; + (void)size; + +#if MSAN == 1 + __msan_check_mem_is_initialized(data, size); +#endif +} + +void memory_test(const void* data, const size_t size) +{ + memory_test_asan(data, size); + memory_test_msan(data, size); +} + +template +void memory_test(const T& t) +{ + (void)t; +} + +template <> +void memory_test(const std::string& s) +{ + (void)s; + +#if MSAN == 1 + memory_test(s.data(), s.size()); +#endif +} + +#endif + +} /* namespace memory */ +} /* namespace fuzzing */ diff --git a/vendor/flac/oss-fuzz/fuzzing/types.hpp b/vendor/flac/oss-fuzz/fuzzing/types.hpp new file mode 100644 index 0000000..914e64f --- /dev/null +++ b/vendor/flac/oss-fuzz/fuzzing/types.hpp @@ -0,0 +1,158 @@ +/* Copyright 2019 Guido Vranken + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace fuzzing { +namespace types { + +template +class Container { + private: + CoreType* InvalidAddress = (CoreType*)0x12; + + CoreType* _data = InvalidAddress; + size_t _size = 0; + +#ifndef FUZZING_HEADERS_NO_IMPL + void copy(const void* data, size_t size) { + if ( size > 0 ) { + std::memcpy(_data, data, size); + } + } + + void allocate(size_t size) { + if ( size > 0 ) { + _data = static_cast(malloc(size * sizeof(CoreType))); + } else { + _data = InvalidAddress; + } + }; + + void allocate_and_copy(const void* data, size_t size) { + allocate(size); + copy(data, size); + } + + void allocate_plus_1_and_copy(const void* data, size_t size) { + allocate(size+1); + copy(data, size); + } + + void access_hook(void) const { + if ( UseMSAN == true ) { + memory::memory_test_msan(_data, _size); + } + } + + void free(void) { + access_hook(); + + if ( _data != InvalidAddress ) { + std::free(_data); + _data = InvalidAddress; + _size = 0; + } + } + +#endif + + public: +#ifndef FUZZING_HEADERS_NO_IMPL + CoreType* data(void) { + access_hook(); + return _data; + } + + size_t size(void) const { + access_hook(); + return _size; + } +#endif + + Container(void) +#ifndef FUZZING_HEADERS_NO_IMPL + = default +#endif + ; + + Container(const void* data, const size_t size) +#ifndef FUZZING_HEADERS_NO_IMPL + { + if ( NullTerminated == false ) { + allocate_and_copy(data, size); + } else { + allocate_plus_1_and_copy(data, size); + _data[size] = 0; + } + + access_hook(); + } +#endif + ; + + template + Container(const T& t) +#ifndef FUZZING_HEADERS_NO_IMPL + { + Container(t.data(), t.size()); + } +#endif + ; + + ~Container(void) +#ifndef FUZZING_HEADERS_NO_IMPL + { + this->free(); + } +#endif + ; + + + + // The copy constructor was not originally explicitly supplied + // so it must have been incorrectly just copying the pointers. + Container(const Container &c) { + InvalidAddress = c.InvalidAddress; + allocate_and_copy(c._data, c._size); + } + + Container& operator=(Container &c) { + InvalidAddress = c.InvalidAddress; + allocate_and_copy(c._data, c._size); + } + +}; + +template using String = Container; +template using Data = Container; + +} /* namespace types */ +} /* namespace fuzzing */ diff --git a/vendor/flac/oss-fuzz/metadata.cc b/vendor/flac/oss-fuzz/metadata.cc new file mode 100644 index 0000000..ad27fe9 --- /dev/null +++ b/vendor/flac/oss-fuzz/metadata.cc @@ -0,0 +1,526 @@ +/* fuzzer_metadata + * Copyright (C) 2022-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include /* for memcpy */ +#include +#include "FLAC++/metadata.h" +#include "common.h" + +#define CONFIG_LENGTH 2 + +#define min(x,y) (x> 4; + + if(0)//data[1] < 128) /* Use MSB as on/off */ + alloc_check_threshold = data[1]; + else + alloc_check_threshold = INT32_MAX; + alloc_check_counter = 0; + + + /* Leave at least one byte as input */ + if(command_length >= size - 1 - CONFIG_LENGTH) + command_length = size - 1 - CONFIG_LENGTH; + + /* Dump input to file */ + { + int file_to_fuzz = mkstemps(filename, 5); + + if (file_to_fuzz < 0) + abort(); + write(file_to_fuzz,data+CONFIG_LENGTH+command_length,size-CONFIG_LENGTH-command_length); + close(file_to_fuzz); + } + + run_tests_with_level_0_interface(filename); + run_tests_with_level_1_interface(filename, init_bools[1], init_bools[2], data+CONFIG_LENGTH, command_length/2); + + /* Dump input to file, to start fresh for level 2 */ + if(!init_bools[1]){ + FILE * file_to_fuzz = fopen(filename,"w"); + fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_fuzz); + fclose(file_to_fuzz); + } + + run_tests_with_level_2_interface(filename, init_bools[0], init_bools[3], data+command_length/2+CONFIG_LENGTH, command_length/2); + + remove(filename); + + return 0; +} + +static void run_tests_with_level_0_interface(char filename[]) { + FLAC::Metadata::StreamInfo streaminfo; + FLAC::Metadata::VorbisComment vorbis_comment; + FLAC::Metadata::CueSheet cue_sheet; + FLAC::Metadata::Picture picture; + + FLAC::Metadata::get_streaminfo(filename,streaminfo); + FLAC::Metadata::get_tags(filename,vorbis_comment); + FLAC::Metadata::get_cuesheet(filename,cue_sheet); + FLAC::Metadata::get_picture(filename,picture, (FLAC__StreamMetadata_Picture_Type)(1), NULL, NULL, -1, -1, -1, -1); +} + +static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size) { + FLAC::Metadata::SimpleIterator iterator; + FLAC::Metadata::Prototype *metadata_block = nullptr; + uint8_t id[4] = {0}; + + if(!iterator.is_valid()) + return; + + if(!iterator.init(filename,readonly,preservestats)) + return; + + for(size_t i = 0; i < size && iterator.status() == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; i++) { + switch(data[i] & 7) { + case 0: + iterator.get_block_type(); + iterator.get_block_offset(); + iterator.get_block_length(); + iterator.get_application_id(id); + break; + case 1: + iterator.next(); + break; + case 2: + iterator.prev(); + break; + case 3: + iterator.delete_block(data[i] & 8); + break; + case 4: + if(metadata_block != 0) { + delete metadata_block; + metadata_block = nullptr; + } + metadata_block = iterator.get_block(); + break; + case 5: + if(metadata_block != 0) + iterator.set_block(metadata_block,data[i] & 8); + break; + case 6: + if(metadata_block != 0) + iterator.insert_block_after(metadata_block, data[i] & 8); + break; + case 7: + iterator.status(); + iterator.is_last(); + iterator.is_writable(); + break; + } + } + if(metadata_block != 0) { + delete metadata_block; + metadata_block = nullptr; + } + + +} + + +static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size) { + FLAC::Metadata::Chain chain; + FLAC::Metadata::Iterator iterator; + FLAC::Metadata::Prototype *metadata_block_get = nullptr; + FLAC::Metadata::Prototype *metadata_block_transfer = nullptr; + FLAC::Metadata::Prototype *metadata_block_put = nullptr; + + if(!chain.is_valid()) + return; + + if(!chain.read(filename, ogg)) + return; + + iterator.init(chain); + + for(size_t i = 0; i < size; i++) { + switch(data[i] & 15) { + case 0: + iterator.get_block_type(); + break; + case 1: + iterator.next(); + break; + case 2: + iterator.prev(); + break; + case 3: + iterator.delete_block(data[i] & 16); + break; + case 4: + metadata_block_get = iterator.get_block(); + if(metadata_block_get != 0 && metadata_block_get->is_valid()) { + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + if(metadata_block_transfer != metadata_block_get) { + delete metadata_block_transfer; + metadata_block_transfer = nullptr; + metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get); + } + } + else { + metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get); + } + } + delete metadata_block_get; + break; + case 5: + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer); + if(metadata_block_put != 0 && metadata_block_put->is_valid()) { + if(!iterator.insert_block_before(metadata_block_put)) + delete metadata_block_put; + } + else + if(metadata_block_put != 0) + delete metadata_block_put; + } + break; + case 6: + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer); + if(metadata_block_put != 0 && metadata_block_put->is_valid()) { + if(!iterator.insert_block_after(metadata_block_put)) + delete metadata_block_put; + } + else + if(metadata_block_put != 0) + delete metadata_block_put; + } + break; + case 7: + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer); + if(metadata_block_put != 0 && metadata_block_put->is_valid()) { + if(!iterator.set_block(metadata_block_put)) + delete metadata_block_put; + } + else + if(metadata_block_put != 0) + delete metadata_block_put; + } + break; + case 8: /* Examine block */ + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + switch(metadata_block_transfer->get_type()) { + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + { + uint32_t num_comments; + ::FLAC__StreamMetadata_VorbisComment_Entry entry; + FLAC::Metadata::VorbisComment::Entry entry_cpp; + FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast(metadata_block_transfer); + const ::FLAC__StreamMetadata * metadata_c = *metadata_block_transfer; + if(vorbiscomment == 0) + abort(); + vorbiscomment->get_vendor_string(); + num_comments = vorbiscomment->get_num_comments(); + if(num_comments > 0) { + entry = metadata_c->data.vorbis_comment.comments[min(data[i]>>4,num_comments-1)]; + if(entry.entry == 0) + abort(); + if(vorbiscomment->get_comment(min(data[i]>>4,num_comments-1)).is_valid()) { + entry_cpp = vorbiscomment->get_comment(min(data[i]>>4,num_comments-1)); + if(entry_cpp.is_valid() && entry_cpp.get_field() == 0) + abort(); + vorbiscomment->find_entry_from(0,"TEST"); + } + } + + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + { + uint32_t num_tracks, num_indices; + FLAC::Metadata::CueSheet * cuesheet = dynamic_cast(metadata_block_transfer); + if(cuesheet == 0 || !cuesheet->is_legal()) + break; + cuesheet->is_legal(true); /* check CDDA subset */ + cuesheet->calculate_cddb_id(); + cuesheet->get_media_catalog_number(); + cuesheet->get_lead_in(); + cuesheet->get_is_cd(); + num_tracks = cuesheet->get_num_tracks(); + if(num_tracks > 0) { + FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1)); + track.get_offset(); + track.get_number(); + track.get_isrc(); + track.get_pre_emphasis(); + num_indices = track.get_num_indices(); + if(num_indices > 0) { + FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1)); + (void)index; + } + } + } + break; + case FLAC__METADATA_TYPE_PICTURE: + { + char * violation = nullptr; + FLAC::Metadata::Picture * picture = dynamic_cast(metadata_block_transfer); + if(picture == 0 || !picture->is_legal((const char **)&violation)) + break; + picture->get_data(); + } + break; + default: + break; + } + + } + break; + case 9: /* Replace or add in block */ + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + switch(metadata_block_transfer->get_type()) { + case FLAC__METADATA_TYPE_SEEKTABLE: + { + uint32_t num_seekpoints; + FLAC__StreamMetadata_SeekPoint seekpoint; + FLAC::Metadata::SeekTable * seektable = dynamic_cast(metadata_block_transfer); + if(seektable == 0) + break; + if(seektable->is_valid() && seektable->is_legal()) { + num_seekpoints = seektable->get_num_points(); + if(num_seekpoints > 0) { + seekpoint = seektable->get_point(min(data[i]>>5,num_seekpoints-1)); + seektable->set_point(0,seekpoint); + seektable->insert_point(min(data[i]>>5,num_seekpoints-1),seekpoint); + } + seektable->template_append_placeholders(4); + seektable->template_append_point(111111); + seektable->template_append_points((FLAC__uint64[]){222222, 333333, 444444}, 3); + seektable->template_append_spaced_points(data[i]>>5, 1234567); + seektable->template_append_spaced_points_by_samples(data[i]>>5, 2468000); + seektable->template_sort(data[i] & 16); + } + } + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + { + uint32_t num_comments; + FLAC::Metadata::VorbisComment::Entry entry; + FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast(metadata_block_transfer); + if(vorbiscomment == 0) + break; + num_comments = vorbiscomment->get_num_comments(); + if(num_comments > 0 && entry.is_valid()) { + if(vorbiscomment->get_comment(min(data[i]>>5,num_comments-1)).is_valid()) { + entry = vorbiscomment->get_comment(min(data[i]>>5,num_comments-1)); + if(entry.is_valid()) { + vorbiscomment->replace_comment(entry,data[i] & 16); + vorbiscomment->set_comment(0,entry); + vorbiscomment->append_comment(entry); + vorbiscomment->insert_comment(0,entry); + } + } + } + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + { + uint32_t num_tracks, num_indices; + FLAC::Metadata::CueSheet * cuesheet = dynamic_cast(metadata_block_transfer); + if(cuesheet == 0 || !cuesheet->is_legal()) + break; + num_tracks = cuesheet->get_num_tracks(); + if(num_tracks > 0) { + FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1)); + num_indices = track.get_num_indices(); + if(num_indices > 0) { + FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1)); + track.set_index(0,index); + cuesheet->insert_index(0,0,index); + cuesheet->insert_blank_index(0,0); + } + cuesheet->insert_blank_track(0); + cuesheet->insert_track(0,track); + cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4); + } + } + break; + case FLAC__METADATA_TYPE_PICTURE: + { + FLAC::Metadata::Picture * picture = dynamic_cast(metadata_block_transfer); + const char testtext[] = "TEST"; + if(picture == 0 || !picture->is_legal(NULL)) + break; + picture->set_description((FLAC__byte *)&testtext); + picture->set_mime_type((const char *)&testtext); + picture->set_data((FLAC__byte *)&testtext,4); + } + break; + default: + break; + } + + } + break; + case 10: /* Delete from block */ + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + switch(metadata_block_transfer->get_type()) { + case FLAC__METADATA_TYPE_SEEKTABLE: + { + uint32_t num_seekpoints; + FLAC::Metadata::SeekTable * seektable = dynamic_cast(metadata_block_transfer); + if(seektable == 0) + break; + if(seektable->is_valid() && seektable->is_legal()) { + num_seekpoints = seektable->get_num_points(); + if(num_seekpoints > 0) + seektable->delete_point(min(data[i]>>4,num_seekpoints-1)); + } + } + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + { + uint32_t num_comments; + FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast(metadata_block_transfer); + if(vorbiscomment == 0) + break; + num_comments = vorbiscomment->get_num_comments(); + if(num_comments > 0) + vorbiscomment->delete_comment(min(data[i]>>4,num_comments-1)); + vorbiscomment->remove_entry_matching("TEST"); + vorbiscomment->remove_entries_matching("TEST"); + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + { + uint32_t num_tracks; + FLAC::Metadata::CueSheet * cuesheet = dynamic_cast(metadata_block_transfer); + if(cuesheet == 0 || !cuesheet->is_legal()) + break; + num_tracks = cuesheet->get_num_tracks(); + if(num_tracks > 0) { + FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1)); + if(track.get_num_indices() > 0) + cuesheet->delete_index(min(data[i]>>4,num_tracks-1),0); + cuesheet->delete_track(0); + } + } + break; + default: + break; + } + + } + break; + case 11: /* Resize block */ + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + switch(metadata_block_transfer->get_type()) { + case FLAC__METADATA_TYPE_PADDING: + { + FLAC::Metadata::Padding * padding = dynamic_cast(metadata_block_transfer); + if(padding == 0) + break; + padding->set_length(data[i]>>4); + } + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + { + FLAC::Metadata::SeekTable * seektable = dynamic_cast(metadata_block_transfer); + if(seektable == 0) + break; + seektable->resize_points(data[i]>>4); + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + { + FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast(metadata_block_transfer); + if(vorbiscomment == 0) + break; + vorbiscomment->resize_comments(data[i]>>4); + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + { + uint32_t num_tracks; + FLAC::Metadata::CueSheet * cuesheet = dynamic_cast(metadata_block_transfer); + if(cuesheet == 0 || !cuesheet->is_legal()) + break; + num_tracks = cuesheet->get_num_tracks(); + if(num_tracks > 0) { + cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4); + } + cuesheet->resize_tracks(data[i]<<4); + } + break; + default: + break; + } + + } + break; + case 12: /* Prototype functions */ + if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) { + const ::FLAC__StreamMetadata * metadata_compare = *metadata_block_transfer; + metadata_block_transfer->get_is_last(); + metadata_block_transfer->get_length(); + metadata_block_transfer->set_is_last(data[i] & 16); + FLAC__metadata_object_is_equal(metadata_compare, metadata_compare); + } + break; + } + } + if(metadata_block_transfer != 0) { + delete metadata_block_transfer; + metadata_block_transfer = nullptr; + } + + chain.status(); + chain.sort_padding(); + chain.merge_padding(); + + chain.check_if_tempfile_needed(!use_padding); + chain.write(use_padding); + +} diff --git a/vendor/flac/oss-fuzz/reencoder.cc b/vendor/flac/oss-fuzz/reencoder.cc new file mode 100644 index 0000000..457fbd4 --- /dev/null +++ b/vendor/flac/oss-fuzz/reencoder.cc @@ -0,0 +1,304 @@ +/* Copyright 2019 Guido Vranken + * + * 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 +#include +#include + +#include +#include + +#include "FLAC++/encoder.h" +#include "FLAC++/decoder.h" +#include "FLAC++/metadata.h" +#include "common.h" + +#define MAX_NUM_METADATA_BLOCKS 2048 + +namespace FLAC { + namespace Encoder { + class FuzzerStream : public Stream { + private: + // fuzzing::datasource::Datasource& ds; + public: + FuzzerStream(fuzzing::datasource::Datasource&) : + Stream() { } + + ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override { + fuzzing::memory::memory_test(buffer, bytes); + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; + } + }; + } + namespace Decoder { + class FuzzerDecoder : public Stream { + private: + fuzzing::datasource::Datasource& ds; + FLAC::Encoder::FuzzerStream& encoder; + public: + FuzzerDecoder(fuzzing::datasource::Datasource& dsrc, FLAC::Encoder::FuzzerStream& encoder_arg) : + Stream(), ds(dsrc), encoder(encoder_arg) { } + + ::FLAC__StreamMetadata * metadata_blocks[MAX_NUM_METADATA_BLOCKS] = {0}; + int num_metadata_blocks = 0; + + void metadata_callback(const ::FLAC__StreamMetadata *metadata) override { + if(num_metadata_blocks < MAX_NUM_METADATA_BLOCKS) + if((metadata_blocks[num_metadata_blocks] = FLAC__metadata_object_clone(metadata)) != NULL) + num_metadata_blocks++; + } + + ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override { + try { + const size_t maxCopySize = *bytes; + + if ( maxCopySize > 0 ) { + /* memset just to test if this overwrites anything, and triggers ASAN */ + memset(buffer, 0, maxCopySize); + } + + const auto data = ds.GetData(0); + const auto dataSize = data.size(); + const auto copySize = std::min(maxCopySize, dataSize); + + if ( copySize > 0 ) { + memcpy(buffer, data.data(), copySize); + } + + *bytes = copySize; + + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } catch ( ... ) { + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + } + + ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override { + { + fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header)); + fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer)); + } + + { + const auto numChannels = get_channels(); + const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32); + for (size_t i = 0; i < numChannels; i++) { + fuzzing::memory::memory_test(buffer[i], bytesPerChannel); + } + } + + /* Data is checked, now pass it towards encoder */ + if(encoder.get_state() == FLAC__STREAM_ENCODER_OK) { + if(encoder.get_channels() != get_channels()) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + if(encoder.get_bits_per_sample() != get_bits_per_sample()) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + encoder.process(buffer, frame->header.blocksize); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + void error_callback(::FLAC__StreamDecoderErrorStatus status) override { + fuzzing::memory::memory_test(status); + } + }; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + fuzzing::datasource::Datasource ds(data, size); + FLAC::Encoder::FuzzerStream encoder(ds); + FLAC::Decoder::FuzzerDecoder decoder(ds, encoder); + + try { + const int channels = ds.Get(); + const int bps = ds.Get(); + encoder.set_channels(channels); + encoder.set_bits_per_sample(bps); + + { + const bool res = encoder.set_streamable_subset(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_ogg_serial_number(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_verify(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_compression_level(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_do_mid_side_stereo(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_loose_mid_side_stereo(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_max_lpc_order(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_qlp_coeff_precision(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_do_escape_coding(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_min_residual_partition_order(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_max_residual_partition_order(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_total_samples_estimate(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_blocksize(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_limit_min_bitrate(ds.Get()); + fuzzing::memory::memory_test(res); + } + { + const bool res = encoder.set_sample_rate(ds.Get()); + fuzzing::memory::memory_test(res); + } + + decoder.set_metadata_respond_all(); + + { + ::FLAC__StreamDecoderInitStatus ret; + if ( ds.Get() ) { + ret = decoder.init(); + } else { + ret = decoder.init_ogg(); + } + + if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) { + goto end; + } + + decoder.process_until_end_of_metadata(); + if(decoder.num_metadata_blocks > 0) + encoder.set_metadata(decoder.metadata_blocks, decoder.num_metadata_blocks); + } + + { + ::FLAC__StreamEncoderInitStatus ret; + if ( ds.Get() ) { + ret = encoder.init(); + } else { + ret = encoder.init_ogg(); + } + + if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) { + goto end; + } + } + + /* These sets must fail, because encoder is already initialized */ + { + bool res = false; + res = res || encoder.set_streamable_subset(true); + res = res || encoder.set_ogg_serial_number(0); + res = res || encoder.set_verify(true); + res = res || encoder.set_compression_level(0); + res = res || encoder.set_do_exhaustive_model_search(true); + res = res || encoder.set_do_mid_side_stereo(true); + res = res || encoder.set_loose_mid_side_stereo(true); + res = res || encoder.set_apodization("test"); + res = res || encoder.set_max_lpc_order(0); + res = res || encoder.set_qlp_coeff_precision(0); + res = res || encoder.set_do_qlp_coeff_prec_search(true); + res = res || encoder.set_do_escape_coding(true); + res = res || encoder.set_min_residual_partition_order(0); + res = res || encoder.set_max_residual_partition_order(0); + res = res || encoder.set_rice_parameter_search_dist(0); + res = res || encoder.set_total_samples_estimate(0); + res = res || encoder.set_channels(channels); + res = res || encoder.set_bits_per_sample(16); + res = res || encoder.set_limit_min_bitrate(true); + res = res || encoder.set_blocksize(3021); + res = res || encoder.set_sample_rate(44100); + fuzzing::memory::memory_test(res); + if(res) + abort(); + } + + + { + /* XORing values as otherwise compiler will optimize, apparently */ + bool res = false; + res = res != encoder.get_streamable_subset(); + res = res != encoder.get_verify(); + res = res != encoder.get_do_exhaustive_model_search(); + res = res != encoder.get_do_mid_side_stereo(); + res = res != encoder.get_loose_mid_side_stereo(); + res = res != encoder.get_max_lpc_order(); + res = res != encoder.get_qlp_coeff_precision(); + res = res != encoder.get_do_qlp_coeff_prec_search(); + res = res != encoder.get_do_escape_coding(); + res = res != encoder.get_min_residual_partition_order(); + res = res != encoder.get_max_residual_partition_order(); + res = res != encoder.get_rice_parameter_search_dist(); + res = res != encoder.get_total_samples_estimate(); + res = res != encoder.get_channels(); + res = res != encoder.get_bits_per_sample(); + res = res != encoder.get_limit_min_bitrate(); + res = res != encoder.get_blocksize(); + res = res != encoder.get_sample_rate(); + fuzzing::memory::memory_test(res); + } + + decoder.process_until_end_of_stream(); + + } catch ( ... ) { } + +end: + { + const bool res = encoder.finish(); + fuzzing::memory::memory_test(res); + } + { + const bool res = decoder.finish(); + fuzzing::memory::memory_test(res); + } + for(int i = 0; i < decoder.num_metadata_blocks; i++) + FLAC__metadata_object_delete(decoder.metadata_blocks[i]); + + return 0; +} diff --git a/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/aiff-with-foreign-metadata-8bps.fuzz b/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/aiff-with-foreign-metadata-8bps.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..944c775a3914da040492eda056520cdbbe8cb2ec GIT binary patch literal 475 zcmbu5%}T>S5XU#I1*KBKL!k;XM-PqEwp0&AvL+2Jwu!XsS=Ks@!88foMZstC349ho z5D%V;c+k@SoTd>fekQs!QSuTEJWZo;EH5JD zp664wEv`@@Xc;JwGXzor8kG*?Ad53a@T~}xPG&Md2xD;j+=kJ}%T(+TpLXu-Rf@*^ z_4(=XW&XBUE|$whKHqa1K<#((E6k#e0?O76DCF0U%DZA{pHQA7YQpwC@dVgkMwfkX$yz{#KQ-FH8H@6Kgoj|}6fNNV^=CSed8`%*_>xIH z6OO`ZZ)n-v+-h%`Y&J}@3Fx#1qN)mgzvqreM5VXZpw|Ppra9Xkfx{O{c-QDuXZcN6 z=ghON>j=jh?ZT{2!dN!B-EQ=sZ*psU`{oYkYCnx6N3FV!wC;O-L@ql?!B(0^;Y>{< zfww>RI*tqPE$^}9!i5TQR+%s+!-eEU7zg^Sr^LUf#CefqDi981p5G0%R&=e&#L-=@ z0doQWUGsx(i$Q#aUZf808o)YR;!64S?b?Pnw(r75Ff}~eb)c63eKCHf4kY)wW4)9L zfcdq4&87oW%YQWP-P>)V!a3mNa6D^x2jnVXCs8D`B1~dVeEy@Ufv2~43HbX8=mq{I hMEpa3d#tvZK3qDydi>Jb`3YPio(2E_ literal 0 HcmV?d00001 diff --git a/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/flac-foreign-metadata-wav-8bps.fuzz b/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/flac-foreign-metadata-wav-8bps.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..6f4ed9c59427f1ae44cfe4f7670b0bc05bb0dab3 GIT binary patch literal 715 zcmbtSL2DC16n^P8qHWMnFlg=J(NhlHl4L_w5XpA8(WS{IYzMtMO=h=)o84u1R1kzx z?XT#;LJvjoroTY^1A6f$_!IOXp42xHksS2m?0(Gq-n{qb%{OD1V=&G8LS$x`=0Zk^ zIT4DFx#AG^xB~#IRjAT*h5m)Nos7(ydUx{b>xCl<0F` z!W1Pqt8*%PT{m0%RpX=PJ#UA-C+_*(f#=)(6|#3^BG$0oZrpynhStW$wX0b0NfwKO z;)a2{OfgOx$6};pnqV5D&cH|f;WWYynC`$&71~)A%Mss=1!X#Yc7yzEPZRUE$;JZGd z99#H>Jf3UKLx+@!h*U~gHqPCw)mh+d6Q8CqXW)~)NcdBdxq-geGC}X^4ElXCI|M!c z<1lQv)uaj+2(wZ#ySGWs%Y?tF%si%F0zI>TUDl6patse6IqM1$p8QV literal 0 HcmV?d00001 diff --git a/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/replaygain-which-is-not-lossless-ogg.fuzz b/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/replaygain-which-is-not-lossless-ogg.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..e211fc6eae3c056933bb58ada15dc8e8b3217707 GIT binary patch literal 15406 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 Xp!(>_0lwf%N8kfz^rP_cKV$v_UpVLs literal 0 HcmV?d00001 diff --git a/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/replaygain-which-is-not-lossless.fuzz b/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/replaygain-which-is-not-lossless.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..9d97430ba5e9581907bda48c5306033c15696d56 GIT binary patch literal 15852 zcmeI#`#TfY3ir4B$NN9Hugm+#*Y$q?^0=<&b-iEvG&KApB0>{1q6iV8{s|ZS ziD4RXLB#Vx8pLRgu<#g-(D3N!P(pMxpGE**AlBcKkB?7DfKPyrZ=V6*J}==ufKQN*52o_5}6>_5}6>_5}6>_5}6>_5}6>_5}6>_5}6> z_5}6>_5}6>_5}6>_5}6>_5}6>_5}6>_5}6>{(l$P-6)Xe`-7a9kLcIkDmKUN-iptQzDyC=`SaI8QbZ2V=v=#gfY6|T!6kZi* zcZg|!{hVG)C zz3$QVXhO3sz$Vh@u$98zpm|Y z>IZVvJ2GRkCkDGLc3|sFY~wujWw>dnGv+z#1ztMg)3K4vh8Xw(BYKlA8hm&nU~}Y< za@3RsdLT~QG6$YU=r#e|Vy}s}4b-t59qA)ZItrD2@rPHER5Lk3sYgXh`|XYZ8m z#T3PJD^r+<`=Ofs6~`7McYkEI($m8X=?2TNmP5DB-4To2XS5>v=GN`T{^9PEF9d~b zsBE{ZT@O`O&q@9Mcs58ZTTH(6kB;b1DUDeUwed2b6c<6uQ0+fP8Mq-JB<2tGkuA41Ca7UM2Ylsc-5i1n ziYpuxd_k7lGe1QRHqfv;MKw>KZ}D9W5puqHyYu63aT5)(9f5x>@lPSwul=61Z#Qd>(v2Uef&C585f0<(E6j=z3=nh>5q%}LLFsM#3QOJtCO2kw$| z-IO7NIg*kje+;BY6x@5K0WJczB9mEUTKDPhn@H^jX+ zw7@9S+B!e4X<7VqT($E|c2vru?){}B`)$hxhF=`bdR|dUd-doFhBHX||ddJGkQT4I}AeYWact^SbcNnIw|&Hh3}U?aH;F-uTSB^3ajBsBoiz{=0`s`zvsizb`&etB^JKd=KNN=Dm|uDmjxHT`YPagEbn$^^sNVL z6;no{yB34nf1+k=ra-ALz0%r$I^OxcYR^%;eOsl9Xm*|f^7{OsK4UN-J&tya3H^S(*2zwhuZPSvgce)a6%70?hY zAxgr!C{=gq*hl5Y6&JNmO0ssz?Aw?Qg#Fsj47PHD!N)0!CGn$pEjQP8R70qXWV656 z=+~t8OaICem_r>bKBy*I&&yRTlFSgqK<>0!i}beJXGE6of65 zVk)txWPzMMwhoBQ06VLQaTy*^8Ul(#G-J!4sPPn|+}>5nAQKZ&<*dqZrXh8m;yL+V zX?@MK{sR1{Ee4-WB~QD;Y6(ZAJoT}@b{;itN{v=JM_}1HlHha|FqtRJ1GAin`9%^( zsM(`AUJ@>6$_d zN-D4*_?jv;aUy9qB(9)eswbGLgpd%Nm9`wwj85jGdEXw)HuaXd1~)8y_3q&_F>+g? z;(C8l*U{-;SscN?x`j+8fmlL9PtpXR9jKR2_MIc=g9&)QGtJkn`C^ zk>qR2kfJmx&Kum=LAj(g`dPy?@aZn?_Qx2uj*!OL`8l_@C0FOV0fl6joodq)3RX3t{mO<{=wJ_zp{zT3QCbihzl?rk(eIS)qKcakNon0ybwq)72 zlRlT6jozQt+|4XF(eUiQdEu3vnnAy3h4C}m>CoJ?P0>kvxAy*hp$t{wfcOISdxI7N zQ9OVbBvLbFo859P4A29c5^2@xR~DKAZ#?`YJCjH*KmOO0+QkS|dD{2T^;?H{s@1ZU zvUA*V9T{8Q>KNw=X@Py?Jw)=2EqzmGMW6imm@^`&g=? zqFcfCy6*M%h#nJn-35a>hnTB&+bMdcbj{Rd`n@;>^7&SxVv|U`s={meZy&R-&YO81 zc{=~b^Mbz|NStumv7{(2&}|baB~ff`q`AvweIA5=d`Mn=W2HxK=DU{BB^Q-N554&^ z)2G7a{2VGPq(4xg*eEh575~b@fie|fnWfWT>JqQ&-jA%&trFTfsxDiR73lh}o_#;i zVoHZM4)-2TIc&x#^I`bX$VNC}~J6%96SB)zY+5XP>(a>?h)`DOp5&D+B@J^o^$-4@qb5ccPr<+c{Z$C>1fu zz)gAbo;j*ja|Mkv-3*3T-s#3O2xDzGZm&5gUd+aCcFigr8b61&Evi!e^rtJKd3N`x z8-80+wp^2#>LRCz=6~5Q^Vpbn$_bj81XDn-=Gar;B<;F`_@4JZe{54ODp}yJhPBzX zrDza2@%5|Q7V_aZqqo+?;-HbiZ=i@?X$|lJy?YS%7O+MZWn4-Gm0554j!^1gvmFiB06G2<`bZ2UPVm%`&O2DZN=&@i$Oq(P`3=1 zUz1m~2i`pGxv!R{)2#RQ8HHULBpAU0K)w_tW6t&3W`5oOUem27%?IE?j^Hb){nwG; z77EA_S{5?+TGz{W{ZWLtii#wHsa7?r8%(^n^`8$DTVSBB0nKh73Gm=rk!dP|4KNK5 zimDitZl&ZOm80f~t98}zj13r(_N}6361okE&9*`6XQAXqj{3Io2A-=Iy`kjfS3 zjLs1P=s9I&&X_VQ7B9z24eo5`tXx?jAt~I8AN9bpxD5oBmuF-YC!oj$)Hj{WDPyq^ zjlDXMM$)L16^oVaXH^Eb!V?B_h%vne0rMdPRgKg5$OyU`T#CeFK}0u19`Uls<>|+X z;`jWw_bUcEG_M?en=xK|&Q{CsUe8l6Rd-~orM||H6xt6Y>;OVpmjIK4HTKV!mws~_cHJmE${t_j3`3Lf)5$w$ zE}27ng?Mo;9c5jWSyx}XKAXj!qcpQ#DYVKm+~_tf_CvP-_D3fL-`8R;sBjL$6#PDH zCu~|wm$*nCdfuBQ(TShDeUxnT5b)+#siA9tMq)C=22{gcM~{VpCx%$vPn!u1e0JL50KWLc^Om#fYorS4^9SeKZe zdDKGW{_$K>Qf;)G5J6Thh=tw^7km0};UGw}Dq*9#TI;s2n-c%Gzj@|fo-=+hGeO>N z9!&mzryQoT?$hqs%?sXn1Uvl1c>C*aPelz>kJZa+>OrD@p^A~$f&1V7xZaBAm7(S| zTAtWw1Wg1paNks1T`+-LLYes{xSHYhS&J>h1_Go zuuYR!LwQi9RE-}K`&J?*c{ zjRa=pYbcR9wy<ThL8-rIIc4p?rMuXM)lO7JhZe*0YX?WfF5=62U4&?xGg ze%FF2aoPaj{HjKNn^d5Z6{tx&{LryPW=BSTsLFkoxP&*Z2P~FBPWZYVD7Sh`SS_Dc z7+lwNZtD!V`tu6KbyM1-)$!8Bj6_e(g{?&wIjbh%bB3P~{@KLJ(t9mXU2}Kh1fXtl z6uaT$lSt01_FNto=;+z?V;T1U`BR?rNbN`0eY3c=tMKuy6O}7mrpkD>gIQ36#1;|e zuc(zSBR$)9SvKXu@YTyJ7h~=8gB0YdIv#Smo-&S4P#4DxhvP1*hN{8sBzhh67KYlp zF1nRrz7{nu74LL&=1%534?WTQ7cvN#aKGu~?5@ z0495TRCrZ^WApNsxo`W_)NG!v0A+Kd_OCtmk6k@a2W@L`QNqBU@}$2+{YFwTa|MVhR9H#X(!2Gr%Fpc^=1A)=iX-n3 zExvnb+=U)kIC1{v|-haXS#7(Bx!d*|QOh4X<)KX5{|QRD6R>k0?W$3=KXE7!P| zpDEZbr>&F4XpfehM@<&sOJ%jP?N#Q2E~c?akCWkrD7%m?cykO}amxYUFzHbF{QFYV z@1T$OuWy|}XUyU}3L2j@cTXMa5%4V5)~fgy(Ec@)n3ot)ESOu7Em6_~f^pQqWDX`M zhc>{`u~uts3-+Ff1~Ffy`=jLSrkl?WMfS>}>CP-^F>&!r=%v z3_-ZBuhEvy6!y0z2Q@^hsx_fnz=3pbTC?*gs*mdhrh(X2;@TXjiV!amuHwvT zLpVs}4ca@0SbG(!@ob%0Y!nBBLZdnV3s;*Z1qVA1rw_PN#x<&2Ot!}GW;cEBMh2@% zfJh7o7>S0Zq(GDumB2_O4As{Wn4H%1q3YV?rtECzVDpI&%4IK;@*ohB?6 zZ7Xb7n!8?XHKJI4|E}+yD%j!kF7Xd+9wjWBY%^6E5t{mgJ=pOE(UGBi!QA02(j)fb zA%GES_};4Z{JX(rO$a%#LoFbzy;@cs%%*vaf=|&ren`9CV6Uf!Hnp>ipVJ)2Bu}cC zE7<;(V`+Rh7WT}}s5rLKV%|Io-fE_ex_O(nZ3Xn+=yYsc5UgeU6v~2c`@f0(KF6|K z-#w?LFM-(V_S1htA|`?~@8Z@9JY;&K{7n8oQ2z%ZSp#SayZrlg(a zn=X<~sqWtHKpU^SrX>c5%xv)QIKiJ+uBMN0Bjgp;B>gR=k60zl_}^@73^#yg`Q3C} zQKY$7SF$64FELtzxu0F0gQiXg*=hDI9y^%(*X_4^rh8I8=y6Z}^($$xGY5tFMckDy ztj`o)P^hN#BR9(51!cW@1SlTTwqAC&0QZQN>WLF5b#_lP@58_3HrddM$-Dd-eYs-n zhM9K^aKPC7Y4A!KzpwumH;BQ?zp0#1F7&ZfiL3g;`N00}Swq23U*6A5DWv&FFHE&- zB>*b?`4B?D^J~b!Fi~W=$~6Udf-<4}m>?k8bMtKF#hG6s)7ejZ6O0lmI;)UFMT)0I zJpzk2)DBo1Ax`}Z=fF?Y-U0MVHsonLZ1P&^%fnUc;J464j;ZuDYc@MR-9P6R3j#RGde zI}vd{B7K8>1dMKugz$hfITuY=13RPhIoY`ZSZ-@&i&HEiYIL@inC;7IOt(^jWmAz9 z7KAE}rXqbS_*y5;1gs1C^D3qKtXmK|r;kh^=>++V#{-2|Z;I?hLTx3Ao_RgtwJlG8 z`pVb%n=#b@_w<|ehEr`0QO`s5g_T$*o|PI$NKKg-R(-gHXi?Y|+UIO$A_#u-Vl1)t zg}>;<+Lxv>#J8MMHu@t$t#<#{)B5J4IiY=x2&S%eUQGjn=JIu*%CWWN2QWWbOwX=V zTs%muDLLu4jM}*+HM10Hi=x?j%V7AE6NSA*3(HRkxtO@6RpWIprgG8OjQAfvB{%3` zd<^pT6+z+p5*HpRe|2)ng&R&@gq@arDxja9ni!+!~XfwkL<^1Iz^ z1I(i&-7RyBl#eF|T@jKU^(#Ek`R3Yjt=GCaBuDuh;Z9q18&i);#Zuxi$E}o~*O+Lw zey&6~^j0!VHAU7YroIS1(ea1JUI~`}t0X)NOoV5rm@05iE>@kI?fw+hf9*cd`mHU+ zN_+n6#{2<~=4Q~55DvA%E_2{smrlL+>~#Pu6n(pe&*$ZAiq( zR9XSm>X*D)?vCn{hyvPltYwT({7qQN(N9qjzoQ>i?pT@Y0W1ub)@mG$t2UQYTkglq1DEg2{VhF4yI~RCC99<6 zIAdJ>JN_OEY(VN*iiZ;geLoX95=C0t;|1?JaPqxPu0MSxt>eOve^U4%@^|b`m=CVX z04E*Adhp=TAUVauwSV5QHKKAOu!~2m^#*AP9uS@yK&BHZW+8*?c>< zmiV!M(QEp)6q%-kf*=)1NEGCMTl*b0n8Lk#1XeiPIDePHY+*Cq)uFzgkzp_nSOthg zIc8PDK_Cjp*%K~WhO2^}ai*7oCsd(Y8fx6;HZBIQ3`F*G;7U%CU|TX=g`s=bT@&YU z#N*y++XIIW1%esFa6Lt26f$dO^{8qQ^`J2`jWnEwfspqp_Jc`x995K}$)Fu={t@}4 z4Xdtc>#kMrI#r7?zAI9PNB6B|iub?Z7W^KUIE<3f+r{4Z7`kx^Gp8q2Ykl%f!QMEfP3rjj(TQ0v2*IN%6qvN@=Usii0u47;t1I@64Ol z1eS#1U{Cpm+@Rm*-{#VeH?B%MD%U(;ahpUP{JFu&1S=cF%}Mzy4PO}ox5s?$EH&3> zp1mS7crA8p##;8NXBV5bW_J|NUkWuT>yN3Y(X1VSjZI+*U2=qq> zb1rkOI7fRFhZ5$VLREY8PXkhD9vAUf<*u>#XSpJ0e+iSsmMhtaQ~MK|ts`~+ zldtK|Rrl;i%Uh@($2hLOU zyfj!82QdLaV4@9u)qA1b(X$)tUTW(w z7ZDs%!xaH;Pb^hwbdC7aL)a*vzaZP@dhm&X(*VPN*mW;a(@^d7^=B`z> nXZ=`pY7TmgC@kT&=1FbBG6&Zv9N!`#$-(s8lfz1U2Rr@`SaQ~x literal 0 HcmV?d00001 diff --git a/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/wav-with-foreign-metadata-8bps.fuzz b/vendor/flac/oss-fuzz/seedcorpus/fuzzer_tool_flac/wav-with-foreign-metadata-8bps.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..d708a3cb80863e1cbb14be14f1dca30e42992491 GIT binary patch literal 559 zcmbtRO-sW-5ZzWQibXvY{5TArJTy?7Qay+?CXI$RscaWLuk9uV(mUaQegq}4)P^;C$14wu;4n%^wb82j%MvsC(bfh1J5V??6z#YGxDKyH`cQ}y*Esg`f z!>|ywvDugNY_7_VCVIHbXZ5skBDi_6HIO*ew!|{SQ(GE5r2Hr7r2*{od5s; literal 0 HcmV?d00001 diff --git a/vendor/flac/oss-fuzz/seek.cc b/vendor/flac/oss-fuzz/seek.cc new file mode 100644 index 0000000..d3ccbe8 --- /dev/null +++ b/vendor/flac/oss-fuzz/seek.cc @@ -0,0 +1,195 @@ +/* fuzzer_seek + * Copyright (C) 2022-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include /* for memcpy */ +#include "FLAC/stream_decoder.h" +#include "common.h" + +int write_abort_check_counter = -1; + +#if 0 /* set to 1 to debug */ +#define FPRINTF_DEBUG_ONLY(...) fprintf(__VA_ARGS__) +#else +#define FPRINTF_DEBUG_ONLY(...) +#endif + +#define CONFIG_LENGTH 2 + +static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) +{ + (void)decoder, (void)frame, (void)buffer, (void)client_data; + if(write_abort_check_counter > 0) { + write_abort_check_counter--; + if(write_abort_check_counter == 0) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } else if(write_abort_check_counter == 0) + /* This must not happen: write callback called after abort is returned */ + abort(); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus error, void *client_data) +{ + (void)decoder, (void)error, (void)client_data; +} + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + FLAC__bool decoder_valid = true; + FLAC__StreamDecoder *decoder; + uint8_t command_length; + FLAC__bool init_bools[16], ogg; + + if(size > 2 && data[1] < 128) /* Use MSB as on/off */ + alloc_check_threshold = data[1]; + else + alloc_check_threshold = INT32_MAX; + alloc_check_counter = 0; + + write_abort_check_counter = -1; + + /* allocate the decoder */ + if((decoder = FLAC__stream_decoder_new()) == NULL) { + fprintf(stderr, "ERROR: allocating decoder\n"); + return 1; + } + + /* Use first byte for configuration, leave at least one byte of input */ + if(size < 1 + CONFIG_LENGTH){ + FLAC__stream_decoder_delete(decoder); + return 0; + } + + /* First 4 bits for configuration bools, next 4 for length of command section */ + for(int i = 0; i < 4; i++) + init_bools[i] = data[i/8] & (1 << (i % 8)); + + command_length = data[0] >> 4; + + /* Leave at least one byte as input */ + if(command_length >= size - 1 - CONFIG_LENGTH) + command_length = size - 1 - CONFIG_LENGTH; + + /* Dump decoder input to file */ + { + FILE * file_to_decode = fopen("/tmp/tmp.flac","w"); + fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_decode); + fclose(file_to_decode); + } + + ogg = init_bools[0]; + + FLAC__stream_decoder_set_md5_checking(decoder,init_bools[1]); + if(init_bools[2]) + FLAC__stream_decoder_set_metadata_respond_all(decoder); + if(init_bools[3]) + FLAC__stream_decoder_set_metadata_ignore_all(decoder); + + /* initialize decoder */ + if(decoder_valid) { + FLAC__StreamDecoderInitStatus init_status; + if(ogg) + init_status = FLAC__stream_decoder_init_ogg_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL); + else + init_status = FLAC__stream_decoder_init_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL); + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + decoder_valid = false; + } + } + + /* Run commands */ + for(uint8_t i = 0; decoder_valid && (i < command_length); i++){ + const uint8_t * command = data+CONFIG_LENGTH+i; + uint8_t shift = 1u << (command[0] >> 3); + FLAC__uint64 seekpos; + + switch(command[0] & 15){ + case 0: + FPRINTF_DEBUG_ONLY(stderr,"end_of_stream\n"); + decoder_valid = FLAC__stream_decoder_process_until_end_of_stream(decoder); + break; + case 1: + FPRINTF_DEBUG_ONLY(stderr,"end_of_metadata\n"); + decoder_valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder); + break; + case 2: + FPRINTF_DEBUG_ONLY(stderr,"single\n"); + decoder_valid = FLAC__stream_decoder_process_single(decoder); + break; + case 3: + FPRINTF_DEBUG_ONLY(stderr,"skip_single\n"); + decoder_valid = FLAC__stream_decoder_skip_single_frame(decoder); + break; + case 4: + FPRINTF_DEBUG_ONLY(stderr,"reset\n"); + decoder_valid = FLAC__stream_decoder_reset(decoder); + break; + case 5: + FPRINTF_DEBUG_ONLY(stderr,"flush\n"); + decoder_valid = FLAC__stream_decoder_flush(decoder); + break; + case 6: + case 14: + shift = 1u << (command[0] >> 3); + FPRINTF_DEBUG_ONLY(stderr,"seek short %hhu\n",shift); + decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,shift); + break; + case 7: + if(i+8 >= command_length) /* Not enough data available to do this */ + break; + seekpos = ((FLAC__uint64)command[1] << 56) + + ((FLAC__uint64)command[2] << 48) + + ((FLAC__uint64)command[3] << 40) + + ((FLAC__uint64)command[4] << 32) + + ((FLAC__uint64)command[5] << 24) + + ((FLAC__uint64)command[6] << 16) + + ((FLAC__uint64)command[7] << 8) + + command[8]; + i+=8; + FPRINTF_DEBUG_ONLY(stderr,"seek long %lu\n",seekpos); + decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,seekpos); + break; + case 8: + /* Set abort on write callback */ + write_abort_check_counter = (command[0] >> 4) + 1; + break; + } + } + + FLAC__stream_decoder_finish(decoder); + + FLAC__stream_decoder_delete(decoder); + + return 0; +} + diff --git a/vendor/flac/oss-fuzz/tool_flac.c b/vendor/flac/oss-fuzz/tool_flac.c new file mode 100644 index 0000000..ce10a07 --- /dev/null +++ b/vendor/flac/oss-fuzz/tool_flac.c @@ -0,0 +1,117 @@ +/* fuzzer_tool_flac + * Copyright (C) 2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include /* for memcpy */ +#define FUZZ_TOOL_FLAC +#define fprintf(...) +#define printf(...) +#include "../src/flac/main.c" +#include "common.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + size_t size_left = size; + size_t arglen; + char * argv[67]; + char exename[] = "flac"; + char filename[] = "/tmp/fuzzXXXXXX"; + int numarg = 0, maxarg; + int file_to_fuzz; + int tmp_stdout, tmp_stdin; + fpos_t pos_stdout; + bool use_stdin = false; + + /* reset global vars */ + flac__utils_verbosity_ = 0; + share__opterr = 0; + share__optind = 0; + + if(size < 2) + return 0; + + maxarg = data[0] & 63; + use_stdin = data[0] & 64; + size_left--; + + argv[0] = exename; + numarg++; + + /* Check whether input is zero delimited */ + while((arglen = strnlen((char *)data+(size-size_left),size_left)) < size_left && numarg < maxarg) { + argv[numarg++] = (char *)data+(size-size_left); + size_left -= arglen + 1; + } + + file_to_fuzz = mkstemp(filename); + + if (file_to_fuzz < 0) + abort(); + write(file_to_fuzz,data+(size-size_left),size_left); + close(file_to_fuzz); + + /* redirect stdout */ + fflush(stdout); + fgetpos(stdout,&pos_stdout); + tmp_stdout = dup(fileno(stdout)); + freopen("/dev/null","w",stdout); + + /* redirect stdin */ + tmp_stdin = dup(fileno(stdin)); + + if(use_stdin) + freopen(filename,"r",stdin); + else { + freopen("/dev/null","r",stdin); + argv[numarg++] = filename; + } + + main_to_fuzz(numarg,argv); + + /* restore stdout */ + fflush(stdout); + dup2(tmp_stdout, fileno(stdout)); + close(tmp_stdout); + clearerr(stdout); + fsetpos(stdout,&pos_stdout); + + /* restore stdin */ + dup2(tmp_stdin, fileno(stdin)); + close(tmp_stdin); + clearerr(stdin); + + unlink(filename); + + return 0; +} + diff --git a/vendor/flac/oss-fuzz/tool_metaflac.c b/vendor/flac/oss-fuzz/tool_metaflac.c new file mode 100644 index 0000000..a6fafa2 --- /dev/null +++ b/vendor/flac/oss-fuzz/tool_metaflac.c @@ -0,0 +1,136 @@ +/* fuzzer_tool_flac + * Copyright (C) 2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include /* for memcpy */ +#define FUZZ_TOOL_METAFLAC +#define fprintf(...) +#define printf(...) +#include "../src/metaflac/main.c" +#include "common.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + size_t size_left = size; + size_t arglen; + char * argv[64]; + char exename[] = "metaflac"; + char filename[] = "/tmp/fuzzXXXXXX"; + char filename_stdin[] = "/tmp/fuzzXXXXXX"; + int numarg = 0, maxarg; + int file_to_fuzz; + int tmp_stdout, tmp_stdin; + fpos_t pos_stdout; + bool use_stdin = false; + + share__opterr = 0; + share__optind = 0; + + + if(size < 2) + return 0; + + maxarg = data[0] & 15; + use_stdin = data[0] & 16; + size_left--; + + argv[0] = exename; + numarg++; + + /* Check whether input is zero delimited */ + while((arglen = strnlen((char *)data+(size-size_left),size_left)) < size_left && numarg < maxarg) { + argv[numarg++] = (char *)data+(size-size_left); + size_left -= arglen + 1; + } + + /* Create file to feed directly */ + file_to_fuzz = mkstemp(filename); + if (file_to_fuzz < 0) + abort(); + if(use_stdin) { + write(file_to_fuzz,data+(size-size_left),size_left/2); + size_left -= size_left/2; + } + else + write(file_to_fuzz,data+(size-size_left),size_left); + close(file_to_fuzz); + + argv[numarg++] = filename; + + /* Create file to feed to stdin */ + if(use_stdin) { + file_to_fuzz = mkstemp(filename_stdin); + if (file_to_fuzz < 0) + abort(); + write(file_to_fuzz,data+(size-size_left),size_left); + close(file_to_fuzz); + } + + /* redirect stdout */ + fflush(stdout); + fgetpos(stdout,&pos_stdout); + tmp_stdout = dup(fileno(stdout)); + freopen("/dev/null","w",stdout); + + /* redirect stdin */ + tmp_stdin = dup(fileno(stdin)); + if(use_stdin) + freopen(filename_stdin,"r",stdin); + else { + freopen("/dev/null","r",stdin); + argv[numarg++] = filename; + } + + main_to_fuzz(numarg,argv); + + /* restore stdout */ + fflush(stdout); + dup2(tmp_stdout, fileno(stdout)); + close(tmp_stdout); + clearerr(stdout); + fsetpos(stdout,&pos_stdout); + + /* restore stdin */ + dup2(tmp_stdin, fileno(stdin)); + close(tmp_stdin); + clearerr(stdin); + + unlink(filename); + + if(use_stdin) + unlink(filename_stdin); + + return 0; +} + diff --git a/vendor/flac/src/CMakeLists.txt b/vendor/flac/src/CMakeLists.txt new file mode 100644 index 0000000..262feea --- /dev/null +++ b/vendor/flac/src/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.11) + +option(ENABLE_64_BIT_WORDS "Set FLAC__BYTES_PER_WORD to 8, for 64-bit machines. For 32-bit machines, turning this off might give a tiny speed improvement" ON) +option(BUILD_UTILS "Build utils" OFF) + +add_subdirectory("libFLAC") +if(BUILD_CXXLIBS) + add_subdirectory("libFLAC++") +endif() +add_subdirectory("share/replaygain_analysis") +add_subdirectory("share/replaygain_synthesis") +add_subdirectory("share/getopt") +add_subdirectory("share/utf8") +add_subdirectory("share/grabbag") + +if(BUILD_PROGRAMS) + add_subdirectory("flac") + add_subdirectory("metaflac") +endif() +if(BUILD_UTILS) + add_subdirectory(utils/flacdiff) + if(WIN32) + add_subdirectory(utils/flactimer) + endif() +endif() + +if(BUILD_TESTING) + add_subdirectory("test_libs_common") + add_subdirectory("test_libFLAC") + if(BUILD_CXXLIBS) + add_subdirectory("test_libFLAC++") + endif() + add_subdirectory("test_grabbag") + add_subdirectory("test_seeking") + add_subdirectory("test_streams") +endif() diff --git a/vendor/flac/src/Makefile.am b/vendor/flac/src/Makefile.am new file mode 100644 index 0000000..e9d60a9 --- /dev/null +++ b/vendor/flac/src/Makefile.am @@ -0,0 +1,40 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2001-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This file is part the FLAC project. FLAC is comprised of several +# components distributed under different licenses. The codec libraries +# are distributed under Xiph.Org's BSD-like license (see the file +# COPYING.Xiph in this distribution). All other programs, libraries, and +# plugins are distributed under the GPL (see COPYING.GPL). The documentation +# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the +# FLAC distribution contains at the top the terms under which it may be +# distributed. +# +# Since this particular file is relevant to all components of FLAC, +# it may be distributed under the Xiph.Org license, which is the least +# restrictive of those mentioned above. See the file COPYING.Xiph in this +# distribution. + +if FLaC__WITH_CPPLIBS +CPPLIBS_DIRS = libFLAC++ test_libFLAC++ +endif + +if FLaC__WITH_PROGRAMS +PROGRAMS_DIRS = flac metaflac +endif + +SUBDIRS = \ + libFLAC \ + share \ + $(PROGRAMS_DIRS) \ + test_grabbag \ + test_libs_common \ + test_libFLAC \ + test_seeking \ + test_streams \ + utils \ + $(CPPLIBS_DIRS) + +EXTRA_DIST = \ + CMakeLists.txt diff --git a/vendor/flac/src/flac/CMakeLists.txt b/vendor/flac/src/flac/CMakeLists.txt new file mode 100644 index 0000000..da7ce8d --- /dev/null +++ b/vendor/flac/src/flac/CMakeLists.txt @@ -0,0 +1,25 @@ +check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) +check_include_file("termios.h" HAVE_TERMIOS_H) + +add_executable(flacapp + analyze.c + decode.c + encode.c + foreign_metadata.c + main.c + local_string_utils.c + utils.c + vorbiscomment.c + version.rc + $<$:../../include/share/win_utf8_io.h> + $<$:../share/win_utf8_io/win_utf8_io.c>) +set_property(TARGET flacapp PROPERTY RUNTIME_OUTPUT_NAME flac) +set_property(TARGET flacapp PROPERTY PROJECT_LABEL "flac") +target_link_libraries(flacapp + FLAC + getopt + replaygain_synthesis + utf8) + +install(TARGETS flacapp EXPORT targets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") diff --git a/vendor/flac/src/flac/Makefile.am b/vendor/flac/src/flac/Makefile.am new file mode 100644 index 0000000..279a7cb --- /dev/null +++ b/vendor/flac/src/flac/Makefile.am @@ -0,0 +1,69 @@ +# flac - Command-line FLAC encoder/decoder +# Copyright (C) 2000-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +if OS_IS_WINDOWS +win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la +if HAVE_WINDRES +flac_DEPENDENCIES = version.o +windows_resource_link = -Wl,version.o +endif +endif + +bin_PROGRAMS = flac + +AM_CFLAGS = @OGG_CFLAGS@ +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +EXTRA_DIST = \ + CMakeLists.txt \ + iffscan.c \ + version.rc + +flac_SOURCES = \ + analyze.c \ + decode.c \ + encode.c \ + foreign_metadata.c \ + main.c \ + local_string_utils.c \ + utils.c \ + vorbiscomment.c \ + analyze.h \ + decode.h \ + encode.h \ + foreign_metadata.h \ + local_string_utils.h \ + utils.h \ + vorbiscomment.h + +flac_LDADD = \ + $(top_builddir)/src/share/utf8/libutf8.la \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/getopt/libgetopt.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + $(win_utf8_lib) \ + @LTLIBICONV@ \ + -lm + +flac_LDFLAGS = $(AM_LDFLAGS) $(windows_resource_link) + +CLEANFILES = flac.exe + +.rc.o: + $(RC) $(AM_CPPFLAGS) $< $@ diff --git a/vendor/flac/src/flac/analyze.c b/vendor/flac/src/flac/analyze.c new file mode 100644 index 0000000..0a85565 --- /dev/null +++ b/vendor/flac/src/flac/analyze.c @@ -0,0 +1,252 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "FLAC/all.h" +#include "analyze.h" + +#include "share/compat.h" + +typedef struct { + FLAC__int32 residual; + uint32_t count; +} pair_t; + +typedef struct { + pair_t buckets[FLAC__MAX_BLOCK_SIZE]; + int peak_index; + uint32_t nbuckets; + uint32_t nsamples; + double sum, sos; + double variance; + double mean; + double stddev; +} subframe_stats_t; + +static subframe_stats_t all_; + +static void init_stats(subframe_stats_t *stats); +static void update_stats(subframe_stats_t *stats, FLAC__int32 residual, uint32_t incr); +static void compute_stats(subframe_stats_t *stats); +static FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename); + +void flac__analyze_init(analysis_options aopts) +{ + if(aopts.do_residual_gnuplot) { + init_stats(&all_); + } +} + +void flac__analyze_frame(const FLAC__Frame *frame, uint32_t frame_number, FLAC__uint64 frame_offset, FLAC__uint64 frame_bytes, analysis_options aopts, FILE *fout) +{ + const uint32_t channels = frame->header.channels; + char outfilename[1024]; + subframe_stats_t stats; + uint32_t i, channel, partitions; + + /* do the human-readable part first */ + fprintf(fout, "frame=%u\toffset=%" PRIu64 "\tbits=%" PRIu64 "\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", frame_number, frame_offset, frame_bytes*8, frame->header.blocksize, frame->header.sample_rate, channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]); + for(channel = 0; channel < channels; channel++) { + const FLAC__Subframe *subframe = frame->subframes+channel; + const FLAC__bool is_rice2 = subframe->data.fixed.entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2; + const uint32_t pesc = is_rice2? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + fprintf(fout, "\tsubframe=%u\twasted_bits=%u\ttype=%s", channel, subframe->wasted_bits, FLAC__SubframeTypeString[subframe->type]); + switch(subframe->type) { + case FLAC__SUBFRAME_TYPE_CONSTANT: + fprintf(fout, "\tvalue=%" PRId64 "\n", subframe->data.constant.value); + break; + case FLAC__SUBFRAME_TYPE_FIXED: + FLAC__ASSERT(subframe->data.fixed.entropy_coding_method.type <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2); + fprintf(fout, "\torder=%u\tresidual_type=%s\tpartition_order=%u\n", subframe->data.fixed.order, is_rice2? "RICE2":"RICE", subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order); + for(i = 0; i < subframe->data.fixed.order; i++) + fprintf(fout, "\t\twarmup[%u]=%" PRId64 "\n", i, subframe->data.fixed.warmup[i]); + partitions = (1u << subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order); + for(i = 0; i < partitions; i++) { + uint32_t parameter = subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->parameters[i]; + if(parameter == pesc) + fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]); + else + fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter); + } + if(aopts.do_residual_text) { + for(i = 0; i < frame->header.blocksize-subframe->data.fixed.order; i++) + fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.fixed.residual[i]); + } + break; + case FLAC__SUBFRAME_TYPE_LPC: + FLAC__ASSERT(subframe->data.lpc.entropy_coding_method.type <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2); + fprintf(fout, "\torder=%u\tqlp_coeff_precision=%u\tquantization_level=%d\tresidual_type=%s\tpartition_order=%u\n", subframe->data.lpc.order, subframe->data.lpc.qlp_coeff_precision, subframe->data.lpc.quantization_level, is_rice2? "RICE2":"RICE", subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order); + for(i = 0; i < subframe->data.lpc.order; i++) + fprintf(fout, "\t\tqlp_coeff[%u]=%d\n", i, subframe->data.lpc.qlp_coeff[i]); + for(i = 0; i < subframe->data.lpc.order; i++) + fprintf(fout, "\t\twarmup[%u]=%" PRId64 "\n", i, subframe->data.lpc.warmup[i]); + partitions = (1u << subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order); + for(i = 0; i < partitions; i++) { + uint32_t parameter = subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->parameters[i]; + if(parameter == pesc) + fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]); + else + fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter); + } + if(aopts.do_residual_text) { + for(i = 0; i < frame->header.blocksize-subframe->data.lpc.order; i++) + fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.lpc.residual[i]); + } + break; + case FLAC__SUBFRAME_TYPE_VERBATIM: + fprintf(fout, "\n"); + break; + } + } + + /* now do the residual distributions if requested */ + if(aopts.do_residual_gnuplot) { + for(channel = 0; channel < channels; channel++) { + const FLAC__Subframe *subframe = frame->subframes+channel; + uint32_t residual_samples; + + init_stats(&stats); + + switch(subframe->type) { + case FLAC__SUBFRAME_TYPE_FIXED: + residual_samples = frame->header.blocksize - subframe->data.fixed.order; + for(i = 0; i < residual_samples; i++) + update_stats(&stats, subframe->data.fixed.residual[i], 1); + break; + case FLAC__SUBFRAME_TYPE_LPC: + residual_samples = frame->header.blocksize - subframe->data.lpc.order; + for(i = 0; i < residual_samples; i++) + update_stats(&stats, subframe->data.lpc.residual[i], 1); + break; + default: + break; + } + + /* update all_ */ + for(i = 0; i < stats.nbuckets; i++) { + update_stats(&all_, stats.buckets[i].residual, stats.buckets[i].count); + } + + if(stats.nsamples > 0) { + /* write the subframe */ + flac_snprintf(outfilename, sizeof (outfilename), "f%06u.s%u.gp", frame_number, channel); + compute_stats(&stats); + + (void)dump_stats(&stats, outfilename); + } + } + } +} + +void flac__analyze_finish(analysis_options aopts) +{ + if(aopts.do_residual_gnuplot && all_.nsamples > 0) { + compute_stats(&all_); + (void)dump_stats(&all_, "all"); + } +} + +void init_stats(subframe_stats_t *stats) +{ + stats->peak_index = -1; + stats->nbuckets = 0; + stats->nsamples = 0; + stats->sum = 0.0; + stats->sos = 0.0; +} + +void update_stats(subframe_stats_t *stats, FLAC__int32 residual, uint32_t incr) +{ + uint32_t i; + const double r = (double)residual, a = r*incr; + + stats->nsamples += incr; + stats->sum += a; + stats->sos += (a*r); + + for(i = 0; i < stats->nbuckets; i++) { + if(stats->buckets[i].residual == residual) { + stats->buckets[i].count += incr; + goto find_peak; + } + } + /* not found, make a new bucket */ + i = stats->nbuckets; + stats->buckets[i].residual = residual; + stats->buckets[i].count = incr; + stats->nbuckets++; +find_peak: + if(stats->peak_index < 0 || stats->buckets[i].count > stats->buckets[stats->peak_index].count) + stats->peak_index = i; +} + +void compute_stats(subframe_stats_t *stats) +{ + stats->mean = stats->sum / (double)stats->nsamples; + stats->variance = (stats->sos - (stats->sum * stats->sum / stats->nsamples)) / stats->nsamples; + stats->stddev = sqrt(stats->variance); +} + +FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename) +{ + FILE *outfile; + uint32_t i; + const double m = stats->mean; + const double s1 = stats->stddev, s2 = s1*2, s3 = s1*3, s4 = s1*4, s5 = s1*5, s6 = s1*6; + const double p = stats->buckets[stats->peak_index].count; + + outfile = flac_fopen(filename, "w"); + + if(0 == outfile) { + fprintf(stderr, "ERROR opening %s: %s\n", filename, strerror(errno)); + return false; + } + + fprintf(outfile, "plot '-' title 'PDF', '-' title 'mean' with impulses, '-' title '1-stddev' with histeps, '-' title '2-stddev' with histeps, '-' title '3-stddev' with histeps, '-' title '4-stddev' with histeps, '-' title '5-stddev' with histeps, '-' title '6-stddev' with histeps\n"); + + for(i = 0; i < stats->nbuckets; i++) { + fprintf(outfile, "%d %u\n", stats->buckets[i].residual, stats->buckets[i].count); + } + fprintf(outfile, "e\n"); + + fprintf(outfile, "%f %f\ne\n", stats->mean, p); + fprintf(outfile, "%f %f\n%f %f\ne\n", m-s1, p*0.8, m+s1, p*0.8); + fprintf(outfile, "%f %f\n%f %f\ne\n", m-s2, p*0.7, m+s2, p*0.7); + fprintf(outfile, "%f %f\n%f %f\ne\n", m-s3, p*0.6, m+s3, p*0.6); + fprintf(outfile, "%f %f\n%f %f\ne\n", m-s4, p*0.5, m+s4, p*0.5); + fprintf(outfile, "%f %f\n%f %f\ne\n", m-s5, p*0.4, m+s5, p*0.4); + fprintf(outfile, "%f %f\n%f %f\ne\n", m-s6, p*0.3, m+s6, p*0.3); + + fprintf(outfile, "pause -1 'waiting...'\n"); + + fclose(outfile); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + unlink(filename); +#endif + return true; +} diff --git a/vendor/flac/src/flac/analyze.h b/vendor/flac/src/flac/analyze.h new file mode 100644 index 0000000..ce07b14 --- /dev/null +++ b/vendor/flac/src/flac/analyze.h @@ -0,0 +1,32 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef flac__analyze_h +#define flac__analyze_h + +typedef struct { + FLAC__bool do_residual_text; + FLAC__bool do_residual_gnuplot; +} analysis_options; + +void flac__analyze_init(analysis_options aopts); +void flac__analyze_frame(const FLAC__Frame *frame, uint32_t frame_number, FLAC__uint64 frame_offset, FLAC__uint64 frame_bytes, analysis_options aopts, FILE *fout); +void flac__analyze_finish(analysis_options aopts); + +#endif diff --git a/vendor/flac/src/flac/decode.c b/vendor/flac/src/flac/decode.c new file mode 100644 index 0000000..90f7a6c --- /dev/null +++ b/vendor/flac/src/flac/decode.c @@ -0,0 +1,1674 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for floor() */ +#include /* for FILE etc. */ +#include /* for strcmp(), strerror() */ +#include /* for clock() */ +#include "FLAC/all.h" +#include "share/grabbag.h" +#include "share/replaygain_synthesis.h" +#include "share/compat.h" +#include "decode.h" + +typedef struct { +#if FLAC__HAS_OGG + FLAC__bool is_ogg; + FLAC__bool use_first_serial_number; + long serial_number; +#endif + + FileFormat format; + FileSubFormat subformat; + FLAC__bool treat_warnings_as_errors; + FLAC__bool continue_through_decode_errors; + FLAC__bool channel_map_none; + FLAC__bool relaxed_foreign_metadata_handling; + + struct { + replaygain_synthesis_spec_t spec; + FLAC__bool apply; /* 'spec.apply' is just a request; this 'apply' means we actually parsed the RG tags and are ready to go */ + double scale; + DitherContext dither_context; + } replaygain; + + FLAC__bool test_only; + FLAC__bool analysis_mode; + analysis_options aopts; + utils__SkipUntilSpecification *skip_specification; + utils__SkipUntilSpecification *until_specification; /* a canonicalized value of 0 mean end-of-stream (i.e. --until=-0) */ + utils__CueSpecification *cue_specification; + + const char *inbasefilename; + const char *infilename; + const char *outfilename; + + FLAC__uint64 samples_processed; + uint32_t frame_counter; + FLAC__bool abort_flag; + FLAC__bool aborting_due_to_until; /* true if we intentionally abort decoding prematurely because we hit the --until point */ + FLAC__bool aborting_due_to_unparseable; /* true if we abort decoding because we hit an unparseable frame */ + FLAC__bool error_callback_suppress_messages; /* turn on to prevent repeating messages from the error callback */ + FLAC__bool warn_user_about_foreign_metadata; /* to prevent more than one warning message per file */ + + FLAC__bool iff_headers_need_fixup; + + FLAC__bool is_big_endian; + FLAC__bool is_unsigned_samples; + FLAC__bool got_stream_info; + FLAC__bool has_md5sum; + FLAC__uint64 total_samples; + uint32_t bps; + uint32_t channels; + uint32_t sample_rate; + FLAC__uint32 channel_mask; + + /* these are used only in analyze mode */ + FLAC__uint64 decode_position; + + FLAC__StreamDecoder *decoder; + + FILE *fout; + + foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */ + FLAC__off_t fm_offset1, fm_offset2, fm_offset3; + + clock_t old_clock_t; +} DecoderSession; + + +static FLAC__bool is_big_endian_host_; + + +/* + * local routines + */ +static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename); +static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred); +static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, const char *infilename); +static FLAC__bool DecoderSession_process(DecoderSession *d); +static int DecoderSession_finish_ok(DecoderSession *d); +static int DecoderSession_finish_error(DecoderSession *d); +static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input); +static FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples); +static FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, uint32_t bps, uint32_t channels, uint32_t sample_rate, FLAC__uint32 channel_mask); +static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat, FLAC__uint32 comm_length); +static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val); +static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val); +static FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 val); +static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val); +static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val); +static FLAC__bool write_sane_extended(FILE *f, uint32_t val); +static FLAC__bool fixup_iff_headers(DecoderSession *d); +static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); +static void print_error_with_init_status(const DecoderSession *d, const char *message, FLAC__StreamDecoderInitStatus init_status); +static void print_error_with_state(const DecoderSession *d, const char *message); +static void print_stats(const DecoderSession *decoder_session); + + +/* + * public routines + */ +int flac__decode_file(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, decode_options_t options) +{ + DecoderSession decoder_session; + + FLAC__ASSERT( + options.format == FORMAT_WAVE || + options.format == FORMAT_WAVE64 || + options.format == FORMAT_RF64 || + options.format == FORMAT_AIFF || + options.format == FORMAT_AIFF_C || + options.format == FORMAT_RAW + ); + + if(options.format == FORMAT_RAW) { + decoder_session.is_big_endian = options.format_options.raw.is_big_endian; + decoder_session.is_unsigned_samples = options.format_options.raw.is_unsigned_samples; + } + + if(! + DecoderSession_construct( + &decoder_session, +#if FLAC__HAS_OGG + options.is_ogg, + options.use_first_serial_number, + options.serial_number, +#else + /*is_ogg=*/false, + /*use_first_serial_number=*/false, + /*serial_number=*/0, +#endif + options.format, + options.force_subformat, + options.treat_warnings_as_errors, + options.continue_through_decode_errors, + options.channel_map_none, + options.relaxed_foreign_metadata_handling, + options.replaygain_synthesis_spec, + analysis_mode, + aopts, + &options.skip_specification, + &options.until_specification, + options.has_cue_specification? &options.cue_specification : 0, + options.format == FORMAT_RAW? NULL : options.format_options.iff.foreign_metadata, + infilename, + outfilename + ) + ) + return 1; + + stats_new_file(); + if(!DecoderSession_init_decoder(&decoder_session, infilename)) + return DecoderSession_finish_error(&decoder_session); + + if(!DecoderSession_process(&decoder_session)) + return DecoderSession_finish_error(&decoder_session); + + return DecoderSession_finish_ok(&decoder_session); +} + +FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename) +{ +#if FLAC__HAS_OGG + d->is_ogg = is_ogg; + d->use_first_serial_number = use_first_serial_number; + d->serial_number = serial_number; +#else + (void)is_ogg; + (void)use_first_serial_number; + (void)serial_number; +#endif + + d->format = format; + d->subformat = subformat; + d->treat_warnings_as_errors = treat_warnings_as_errors; + d->continue_through_decode_errors = continue_through_decode_errors; + d->channel_map_none = channel_map_none; + d->relaxed_foreign_metadata_handling = relaxed_foreign_metadata_handling; + d->replaygain.spec = replaygain_synthesis_spec; + d->replaygain.apply = false; + d->replaygain.scale = 0.0; + /* d->replaygain.dither_context gets initialized later once we know the sample resolution */ + d->test_only = (0 == outfilename); + d->analysis_mode = analysis_mode; + d->aopts = aopts; + d->skip_specification = skip_specification; + d->until_specification = until_specification; + d->cue_specification = cue_specification; + + d->inbasefilename = grabbag__file_get_basename(infilename); + d->infilename = infilename; + d->outfilename = outfilename; + + d->samples_processed = 0; + d->frame_counter = 0; + d->abort_flag = false; + d->aborting_due_to_until = false; + d->aborting_due_to_unparseable = false; + d->error_callback_suppress_messages = false; + if(relaxed_foreign_metadata_handling) + d->warn_user_about_foreign_metadata = false; + else + d->warn_user_about_foreign_metadata = true; + + d->iff_headers_need_fixup = false; + + d->total_samples = 0; + d->got_stream_info = false; + d->has_md5sum = false; + d->bps = 0; + d->channels = 0; + d->sample_rate = UINT32_MAX; + d->channel_mask = 0; + + d->decode_position = 0; + + d->decoder = 0; + + d->fout = 0; /* initialized with an open file later if necessary */ + + d->foreign_metadata = foreign_metadata; + + d->old_clock_t = 0; + + FLAC__ASSERT(!(d->test_only && d->analysis_mode)); + + if(!d->test_only) { + if(0 == strcmp(outfilename, "-")) { + d->fout = grabbag__file_get_binary_stdout(); + } + else { + if(0 == (d->fout = flac_fopen(outfilename, "wb"))) { + flac__utils_printf(stderr, 1, "%s: ERROR: can't open output file %s: %s\n", d->inbasefilename, outfilename, strerror(errno)); + DecoderSession_destroy(d, /*error_occurred=*/true); + return false; + } + } + } + + if(analysis_mode) + flac__analyze_init(aopts); + + return true; +} + +void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred) +{ + if(0 != d->fout && d->fout != stdout) { +#if defined _WIN32 && !defined __CYGWIN__ + if(!error_occurred) { + FLAC__off_t written_size = ftello(d->fout); + if(written_size > 0) { + HANDLE fh = CreateFile_utf8(d->outfilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(fh != INVALID_HANDLE_VALUE) { + if(GetFileType(fh) == FILE_TYPE_DISK) { + LARGE_INTEGER size; + size.QuadPart = written_size; + if(SetFilePointerEx(fh, size, NULL, FILE_CURRENT)) /* correct the file size */ + SetEndOfFile(fh); + } + CloseHandle(fh); + } + } + } +#endif + fclose(d->fout); + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Always delete output file when fuzzing */ + if(error_occurred) +#endif + flac_unlink(d->outfilename); + } +} + +FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const char *infilename) +{ + FLAC__StreamDecoderInitStatus init_status; + FLAC__uint32 test = 1; + + is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true; + + if(decoder_session->test_only && strcmp(infilename, "-") != 0) { + /* When testing, we can be a little more pedantic, as long + * as we can seek properly */ + FLAC__byte buffer[3]; + FILE * f; + + if(0 == (f = flac_fopen(infilename, "rb"))) { + flac__utils_printf(stderr, 1, "ERROR: can't open input file %s: %s\n", infilename, strerror(errno)); + return false; + } + + if(fread(buffer, 1, 3, f) < 3) { + flac__utils_printf(stderr, 1, "%s: ERROR checking for ID3v2 tag\n", decoder_session->inbasefilename); + fclose(f); + return false; + } + if(memcmp(buffer, "ID3", 3) == 0){ + flac__utils_printf(stderr, 1, "%s: WARNING, ID3v2 tag found. This is non-standard and strongly discouraged\n", decoder_session->inbasefilename); + if(decoder_session->treat_warnings_as_errors) { + fclose(f); + return false; + } + } + fclose(f); + } + + decoder_session->decoder = FLAC__stream_decoder_new(); + + if(0 == decoder_session->decoder) { + flac__utils_printf(stderr, 1, "%s: ERROR creating the decoder instance\n", decoder_session->inbasefilename); + return false; + } + + FLAC__stream_decoder_set_md5_checking(decoder_session->decoder, true); + if (0 != decoder_session->cue_specification) + FLAC__stream_decoder_set_metadata_respond(decoder_session->decoder, FLAC__METADATA_TYPE_CUESHEET); + if (decoder_session->replaygain.spec.apply || !decoder_session->channel_map_none) + FLAC__stream_decoder_set_metadata_respond(decoder_session->decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); + + if(!decoder_session->analysis_mode && !decoder_session->test_only && decoder_session->foreign_metadata == NULL) { + /* Warn user if foreign metadata is found */ + uint32_t i; + for(i = 0; i < FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS; i++) + FLAC__stream_decoder_set_metadata_respond_application(decoder_session->decoder, (FLAC__byte *)FLAC__FOREIGN_METADATA_APPLICATION_ID[i]); + } + +#if FLAC__HAS_OGG + if(decoder_session->is_ogg) { + if(!decoder_session->use_first_serial_number) + FLAC__stream_decoder_set_ogg_serial_number(decoder_session->decoder, decoder_session->serial_number); + init_status = FLAC__stream_decoder_init_ogg_file(decoder_session->decoder, strcmp(infilename, "-")? infilename : 0, write_callback, metadata_callback, error_callback, /*client_data=*/decoder_session); + } + else +#endif + { + init_status = FLAC__stream_decoder_init_file(decoder_session->decoder, strcmp(infilename, "-")? infilename : 0, write_callback, metadata_callback, error_callback, /*client_data=*/decoder_session); + } + + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + print_error_with_init_status(decoder_session, "ERROR initializing decoder", init_status); + return false; + } + + return true; +} + +FLAC__bool DecoderSession_process(DecoderSession *d) +{ + if(!FLAC__stream_decoder_process_until_end_of_metadata(d->decoder)) { + flac__utils_printf(stderr, 2, "\n"); + print_error_with_state(d, "ERROR while decoding metadata"); + return false; + } + if(FLAC__stream_decoder_get_state(d->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM) { + flac__utils_printf(stderr, 2, "\n"); + print_error_with_state(d, "ERROR during metadata decoding"); + if(!d->continue_through_decode_errors) + return false; + } + + if(d->analysis_mode) + FLAC__stream_decoder_get_decode_position(d->decoder, &d->decode_position); + + if(d->abort_flag) + return false; + + /* set channel mapping */ + /* currently FLAC order matches SMPTE/WAVEFORMATEXTENSIBLE order, so no reordering is necessary; see encode.c */ + /* only the channel mask must be set if it was not already picked up from the WAVEFORMATEXTENSIBLE_CHANNEL_MASK tag */ + if(!d->channel_map_none && d->channel_mask == 0) { + if(d->channels == 1) { + d->channel_mask = 0x0004; + } + else if(d->channels == 2) { + d->channel_mask = 0x0003; + } + else if(d->channels == 3) { + d->channel_mask = 0x0007; + } + else if(d->channels == 4) { + d->channel_mask = 0x0033; + } + else if(d->channels == 5) { + d->channel_mask = 0x0607; + } + else if(d->channels == 6) { + d->channel_mask = 0x060f; + } + else if(d->channels == 7) { + d->channel_mask = 0x070f; + } + else if(d->channels == 8) { + d->channel_mask = 0x063f; + } + } + +#if defined _WIN32 && !defined __CYGWIN__ + if(!d->analysis_mode && !d->test_only && d->total_samples > 0 && d->fout != stdout) { + HANDLE fh = CreateFile_utf8(d->outfilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(fh != INVALID_HANDLE_VALUE) { + if (GetFileType(fh) == FILE_TYPE_DISK) { + LARGE_INTEGER size; + size.QuadPart = d->total_samples * d->channels * ((d->bps+7)/8); + if(d->format != FORMAT_RAW) { + size.QuadPart += 512; + if(d->foreign_metadata) { + size_t i; + for(i = d->format==FORMAT_RF64?2:1; i < d->foreign_metadata->num_blocks; i++) { + if(i != d->foreign_metadata->format_block && i != d->foreign_metadata->audio_block) + size.QuadPart += d->foreign_metadata->blocks[i].size; + } + } + } + + if(SetFilePointerEx(fh, size, NULL, FILE_CURRENT)) /* tell filesystem the expected filesize to eliminate fragmentation */ + SetEndOfFile(fh); + } + CloseHandle(fh); + } + } +#endif + + /* write the WAVE/AIFF headers if necessary */ + if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) { + if(!write_iff_headers(d->fout, d, d->total_samples)) { + d->abort_flag = true; + return false; + } + } + + if(d->skip_specification->value.samples > 0) { + const FLAC__uint64 skip = (FLAC__uint64)d->skip_specification->value.samples; + + if(!FLAC__stream_decoder_seek_absolute(d->decoder, skip)) { + print_error_with_state(d, "ERROR seeking while skipping bytes"); + return false; + } + } + if(!FLAC__stream_decoder_process_until_end_of_stream(d->decoder) && !d->aborting_due_to_until) { + flac__utils_printf(stderr, 2, "\n"); + print_error_with_state(d, "ERROR while decoding data"); + if(!d->continue_through_decode_errors) + return false; + } + if( + (d->abort_flag && !(d->aborting_due_to_until || d->continue_through_decode_errors)) || + (FLAC__stream_decoder_get_state(d->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM && !d->aborting_due_to_until) + ) { + flac__utils_printf(stderr, 2, "\n"); + print_error_with_state(d, "ERROR during decoding"); + return false; + } + + /* write padding bytes for alignment if necessary */ + if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) { + const FLAC__uint64 data_size = d->total_samples * d->channels * ((d->bps+7)/8); + uint32_t padding; + if(d->format != FORMAT_WAVE64) { + padding = (uint32_t)(data_size & 1); + } + else { + /* 8-byte alignment for Wave64 */ + padding = (8 - (uint32_t)(data_size & 7)) & 7; + } + for( ; padding > 0; --padding) { + if(flac__utils_fwrite("\000", 1, 1, d->fout) != 1) { + print_error_with_state( + d, + d->format == FORMAT_WAVE? "ERROR writing pad byte to WAVE data chunk" : + d->format == FORMAT_WAVE64? "ERROR writing pad bytes to WAVE64 data chunk" : + d->format == FORMAT_RF64? "ERROR writing pad byte to RF64 data chunk" : + "ERROR writing pad byte to AIFF SSND chunk" + ); + return false; + } + } + } + + return true; +} + +int DecoderSession_finish_ok(DecoderSession *d) +{ + FLAC__bool ok = true, md5_failure = false; + + if(d->decoder) { + md5_failure = !FLAC__stream_decoder_finish(d->decoder) && !d->aborting_due_to_until; + print_stats(d); + FLAC__stream_decoder_delete(d->decoder); + } + if(d->analysis_mode) + flac__analyze_finish(d->aopts); + if(md5_failure) { + stats_print_name(1, d->inbasefilename); + flac__utils_printf(stderr, 1, "ERROR, MD5 signature mismatch\n"); + ok = d->continue_through_decode_errors; + } + else if(d->got_stream_info && d->total_samples && (d->total_samples > d->samples_processed)){ + stats_print_name(1, d->inbasefilename); + flac__utils_printf(stderr, 1, "ERROR, decoded number of samples is smaller than the total number of samples set in the STREAMINFO\n"); + ok = d->continue_through_decode_errors; + } + else { + if(!d->got_stream_info) { + stats_print_name(1, d->inbasefilename); + flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since there was no STREAMINFO\n"); + ok = !d->treat_warnings_as_errors; + } + else if(!d->has_md5sum) { + stats_print_name(1, d->inbasefilename); + flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since it was unset in the STREAMINFO\n"); + ok = !d->treat_warnings_as_errors; + } + else if(!d->total_samples) { + stats_print_name(1, d->inbasefilename); + flac__utils_printf(stderr, 1, "WARNING, cannot check total number of samples since it was unset in the STREAMINFO\n"); + ok = !d->treat_warnings_as_errors; + } + stats_print_name(2, d->inbasefilename); + flac__utils_printf(stderr, 2, "%s \n", d->test_only? "ok ":d->analysis_mode?"done ":"done"); + } + DecoderSession_destroy(d, /*error_occurred=*/!ok); + if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) { + if(d->iff_headers_need_fixup || (!d->got_stream_info && strcmp(d->outfilename, "-"))) { + if(!fixup_iff_headers(d)) + return 1; + } + if(d->foreign_metadata) { + const char *error; + if(!flac__foreign_metadata_write_to_iff(d->foreign_metadata, d->infilename, d->outfilename, d->fm_offset1, d->fm_offset2, d->fm_offset3, &error)) { + flac__utils_printf(stderr, 1, "ERROR updating foreign metadata from %s to %s: %s\n", d->infilename, d->outfilename, error); + return 1; + } + if(!flac__foreign_metadata_compare_with_iff(d->foreign_metadata, d->infilename, d->outfilename, d->fm_offset3, &error)) { + flac__utils_printf(stderr, 1, "ERROR verifying foreign metadata restore from %s to %s: %s\n", d->infilename, d->outfilename, error); + return 1; + } + } + } + return ok? 0 : 1; +} + +int DecoderSession_finish_error(DecoderSession *d) +{ + if(d->decoder) { + (void)FLAC__stream_decoder_finish(d->decoder); + FLAC__stream_decoder_delete(d->decoder); + } + if(d->analysis_mode) + flac__analyze_finish(d->aopts); + DecoderSession_destroy(d, /*error_occurred=*/true); + return 1; +} + +FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input) +{ + /* convert from mm:ss.sss to sample number if necessary */ + if(!flac__utils_canonicalize_skip_until_specification(spec, sample_rate)) { + flac__utils_printf(stderr, 1, "%s: ERROR, value of --until is too large\n", inbasefilename); + return false; + } + + /* special case: if "--until=-0", use the special value '0' to mean "end-of-stream" */ + if(spec->is_relative && spec->value.samples == 0) { + spec->is_relative = false; + return true; + } + + /* in any other case the total samples in the input must be known */ + if(total_samples_in_input == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until when FLAC metadata has total sample count of 0\n", inbasefilename); + return false; + } + + FLAC__ASSERT(spec->value_is_samples); + + /* convert relative specifications to absolute */ + if(spec->is_relative) { + if(spec->value.samples <= 0) + spec->value.samples += (FLAC__int64)total_samples_in_input; + else + spec->value.samples += skip; + spec->is_relative = false; + } + + /* error check */ + if(spec->value.samples < 0) { + flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before beginning of input\n", inbasefilename); + return false; + } + if((FLAC__uint64)spec->value.samples <= skip) { + flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before --skip point\n", inbasefilename); + return false; + } + if((FLAC__uint64)spec->value.samples > total_samples_in_input) { + flac__utils_printf(stderr, 1, "%s: ERROR, --until value is after end of input\n", inbasefilename); + return false; + } + + return true; +} + +FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples) +{ + const FileFormat format = decoder_session->format; + const FileSubFormat subformat = decoder_session->subformat; + const char *fmt_desc = + format==FORMAT_WAVE? "WAVE" : + format==FORMAT_WAVE64? "Wave64" : + format==FORMAT_RF64? "RF64" : + format==FORMAT_AIFF? "AIFF" : + "AIFC"; + const FLAC__bool is_waveformatextensible = + subformat == SUBFORMAT_WAVE_EXTENSIBLE || ( + (format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) && + subformat != SUBFORMAT_WAVE_PCM && + ( + (decoder_session->channel_mask != 0 && decoder_session->channel_mask != 0x0004 && decoder_session->channel_mask != 0x0003) || + (decoder_session->bps != 8 && decoder_session->bps != 16) || + decoder_session->channels > 2 + )); + const FLAC__uint64 data_size = samples * decoder_session->channels * ((decoder_session->bps+7)/8); + const FLAC__uint64 aligned_data_size = + format == FORMAT_WAVE64? + (data_size+7) & (~(FLAC__uint64)7) : + (data_size+1) & (~(FLAC__uint64)1); + + FLAC__uint64 iff_size; + uint32_t foreign_metadata_size = 0; /* size of all non-audio non-fmt/COMM foreign metadata chunks */ + foreign_metadata_t *fm = decoder_session->foreign_metadata; + size_t i; + + FLAC__ASSERT( + format == FORMAT_WAVE || + format == FORMAT_WAVE64 || + format == FORMAT_RF64 || + format == FORMAT_AIFF || + format == FORMAT_AIFF_C + ); + + if(samples == 0) { + if(f == stdout) { + flac__utils_printf(stderr, 1, "%s: WARNING, don't have accurate sample count available for %s header.\n", decoder_session->inbasefilename, fmt_desc); + flac__utils_printf(stderr, 1, " Generated %s file will have a data chunk size of 0. Try\n", fmt_desc); + flac__utils_printf(stderr, 1, " decoding directly to a file instead.\n"); + if(decoder_session->treat_warnings_as_errors) + return false; + } + else { + decoder_session->iff_headers_need_fixup = true; + } + } + + if(fm) { + FLAC__ASSERT(fm->format_block); + FLAC__ASSERT(fm->audio_block); + FLAC__ASSERT(fm->format_block < fm->audio_block); + /* calc foreign metadata size; we always skip the first chunk, ds64 chunk, format chunk, and sound chunk since we write our own */ + for(i = format==FORMAT_RF64?2:1; i < fm->num_blocks; i++) { + if(i != fm->format_block && i != fm->audio_block) + foreign_metadata_size += fm->blocks[i].size; + } + } + + if(samples == 0) + iff_size = 0; + else if(format == FORMAT_WAVE || format == FORMAT_RF64) + /* 4 for WAVE form bytes */ + /* +{36,0} for ds64 chunk */ + /* +8+{40,16} for fmt chunk header and body */ + /* +8 for data chunk header */ + iff_size = 4 + (format==FORMAT_RF64?36:0) + 8+(is_waveformatextensible?40:16) + 8 + foreign_metadata_size + aligned_data_size; + else if(format == FORMAT_WAVE64) + /* 16+8 for RIFF GUID and size field */ + /* +16 for WAVE GUID */ + /* +16+8+{40,16} for fmt chunk header (GUID and size field) and body */ + /* +16+8 for data chunk header (GUID and size field) */ + iff_size = 16+8 + 16 + 16+8+(is_waveformatextensible?40:16) + 16+8 + foreign_metadata_size + aligned_data_size; + else if(format == FORMAT_AIFF) + iff_size = 46 + foreign_metadata_size + aligned_data_size; + else /* AIFF-C */ + iff_size = 16 + foreign_metadata_size + aligned_data_size + (fm?fm->aifc_comm_length:0); + + if(format != FORMAT_WAVE64 && format != FORMAT_RF64 && iff_size >= 0xFFFFFFF4) { + flac__utils_printf(stderr, 1, "%s: ERROR: stream is too big to fit in a single %s file\n", decoder_session->inbasefilename, fmt_desc); + return false; + } + + if(format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) { + /* RIFF header */ + switch(format) { + case FORMAT_WAVE: + if(flac__utils_fwrite("RIFF", 1, 4, f) != 4) + return false; + if(!write_little_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */ + return false; + if(flac__utils_fwrite("WAVE", 1, 4, f) != 4) + return false; + break; + case FORMAT_WAVE64: + /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */ + if(flac__utils_fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 1, 16, f) != 16) + return false; + if(!write_little_endian_uint64(f, iff_size)) + return false; + /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ + if(flac__utils_fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16) + return false; + break; + case FORMAT_RF64: + if(flac__utils_fwrite("RF64", 1, 4, f) != 4) + return false; + if(!write_little_endian_uint32(f, 0xffffffff)) + return false; + if(flac__utils_fwrite("WAVE", 1, 4, f) != 4) + return false; + break; + default: + return false; + } + + /* ds64 chunk for RF64 */ + if(format == FORMAT_RF64) { + if(flac__utils_fwrite("ds64", 1, 4, f) != 4) + return false; + + if(!write_little_endian_uint32(f, 28)) /* chunk size */ + return false; + + if(!write_little_endian_uint64(f, iff_size)) + return false; + + if(!write_little_endian_uint64(f, data_size)) + return false; + + if(!write_little_endian_uint64(f, samples)) /*@@@@@@ correct? */ + return false; + + if(!write_little_endian_uint32(f, 0)) /* table size */ + return false; + } + + decoder_session->fm_offset1 = ftello(f); + + if(fm) { + /* seek forward to {allocate} or {skip over already-written chunks} before "fmt " */ + for(i = format==FORMAT_RF64?2:1; i < fm->format_block; i++) { + if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata before \"fmt \"\n", decoder_session->inbasefilename); + return false; + } + } + } + + if(format != FORMAT_WAVE64) { + if(flac__utils_fwrite("fmt ", 1, 4, f) != 4) + return false; + if(!write_little_endian_uint32(f, is_waveformatextensible? 40 : 16)) /* chunk size */ + return false; + } + else { /* Wave64 */ + /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ + if(flac__utils_fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16) + return false; + /* chunk size (+16+8 for GUID and size fields) */ + if(!write_little_endian_uint64(f, 16+8+(is_waveformatextensible?40:16))) + return false; + } + + if(!write_riff_wave_fmt_chunk_body(f, is_waveformatextensible, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, decoder_session->channel_mask)) + return false; + + decoder_session->fm_offset2 = ftello(f); + + if(fm) { + /* seek forward to {allocate} or {skip over already-written chunks} after "fmt " but before "data" */ + for(i = fm->format_block+1; i < fm->audio_block; i++) { + if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata after \"fmt \"\n", decoder_session->inbasefilename); + return false; + } + } + } + + if(format != FORMAT_WAVE64) { + if(flac__utils_fwrite("data", 1, 4, f) != 4) + return false; + if(!write_little_endian_uint32(f, format==FORMAT_RF64? 0xffffffff : (FLAC__uint32)data_size)) + return false; + } + else { /* Wave64 */ + /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ + if(flac__utils_fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16) + return false; + /* +16+8 for GUID and size fields */ + if(!write_little_endian_uint64(f, 16+8 + data_size)) + return false; + } + + decoder_session->fm_offset3 = ftello(f) + aligned_data_size; + } + else { + if(flac__utils_fwrite("FORM", 1, 4, f) != 4) + return false; + + if(!write_big_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */ + return false; + + if(format == FORMAT_AIFF) { + if(flac__utils_fwrite("AIFF", 1, 4, f) != 4) + return false; + } + else + if(flac__utils_fwrite("AIFC", 1, 4, f) != 4) + return false; + + decoder_session->fm_offset1 = ftello(f); + + if(fm) { + /* seek forward to {allocate} or {skip over already-written chunks} before "COMM" */ + for(i = 1; i < fm->format_block; i++) { + if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata before \"COMM\"\n", decoder_session->inbasefilename); + return false; + } + } + } + + if(!write_aiff_form_comm_chunk(f, samples, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, format, subformat, fm?fm->aifc_comm_length:0)) + return false; + + decoder_session->fm_offset2 = ftello(f); + + if(fm) { + /* seek forward to {allocate} or {skip over already-written chunks} after "COMM" but before "SSND" */ + for(i = fm->format_block+1; i < fm->audio_block; i++) { + if(fseeko(f, fm->blocks[i].size, SEEK_CUR) < 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping foreign metadata after \"COMM\"\n", decoder_session->inbasefilename); + return false; + } + } + } + + if(flac__utils_fwrite("SSND", 1, 4, f) != 4) + return false; + + if(!write_big_endian_uint32(f, (FLAC__uint32)data_size + 8)) /* data size */ + return false; + + if(!write_big_endian_uint32(f, 0/*offset_size*/)) + return false; + + if(!write_big_endian_uint32(f, 0/*block_size*/)) + return false; + + decoder_session->fm_offset3 = ftello(f) + aligned_data_size; + } + + return true; +} + +FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, uint32_t bps, uint32_t channels, uint32_t sample_rate, FLAC__uint32 channel_mask) +{ + if(!write_little_endian_uint16(f, (FLAC__uint16)(is_waveformatextensible? 65534 : 1))) /* compression code */ + return false; + + if(!write_little_endian_uint16(f, (FLAC__uint16)channels)) + return false; + + if(!write_little_endian_uint32(f, sample_rate)) + return false; + + if(!write_little_endian_uint32(f, sample_rate * channels * ((bps+7) / 8))) + return false; + + if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * ((bps+7) / 8)))) /* block align */ + return false; + + if(!write_little_endian_uint16(f, (FLAC__uint16)(((bps+7)/8)*8))) /* bits per sample */ + return false; + + if(is_waveformatextensible) { + if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */ + return false; + + if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */ + return false; + + if(!write_little_endian_uint32(f, channel_mask)) + return false; + + /* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */ + if(flac__utils_fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16) + return false; + } + + return true; +} + +FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat, FLAC__uint32 comm_length) +{ + FLAC__uint32 i; + FLAC__ASSERT(samples <= 0xffffffff); + + if(comm_length == 0) { + if(format == FORMAT_AIFF) + comm_length = 30; + else + comm_length = 36; + } + + if(flac__utils_fwrite("COMM", 1, 4, f) != 4) + return false; + + if(!write_big_endian_uint32(f, comm_length-12)) /* chunk size = 18 */ + return false; + + if(!write_big_endian_uint16(f, (FLAC__uint16)channels)) + return false; + + if(!write_big_endian_uint32(f, (FLAC__uint32)samples)) + return false; + + if(!write_big_endian_uint16(f, (FLAC__uint16)bps)) + return false; + + if(!write_sane_extended(f, sample_rate)) + return false; + + if(format == FORMAT_AIFF_C) { + if(subformat == SUBFORMAT_AIFF_C_NONE) { + if(flac__utils_fwrite("NONE", 1, 4, f) != 4) + return false; + } + else if(subformat == SUBFORMAT_AIFF_C_SOWT) { + if(flac__utils_fwrite("sowt", 1, 4, f) != 4) + return false; + } + for(i = 34; i < comm_length; i++) { + if(flac__utils_fwrite("\x00", 1, 1, f) != 1) + return false; + } + } + + + + return true; +} + +FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val) +{ + FLAC__byte *b = (FLAC__byte*)(&val); + if(is_big_endian_host_) { + FLAC__byte tmp; + tmp = b[1]; b[1] = b[0]; b[0] = tmp; + } + return flac__utils_fwrite(b, 1, 2, f) == 2; +} + +FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val) +{ + FLAC__byte *b = (FLAC__byte*)(&val); + if(is_big_endian_host_) { + FLAC__byte tmp; + tmp = b[3]; b[3] = b[0]; b[0] = tmp; + tmp = b[2]; b[2] = b[1]; b[1] = tmp; + } + return flac__utils_fwrite(b, 1, 4, f) == 4; +} + +FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 val) +{ + FLAC__byte *b = (FLAC__byte*)(&val); + if(is_big_endian_host_) { + FLAC__byte tmp; + tmp = b[7]; b[7] = b[0]; b[0] = tmp; + tmp = b[6]; b[6] = b[1]; b[1] = tmp; + tmp = b[5]; b[5] = b[2]; b[2] = tmp; + tmp = b[4]; b[4] = b[3]; b[3] = tmp; + } + return flac__utils_fwrite(b, 1, 8, f) == 8; +} + +FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val) +{ + FLAC__byte *b = (FLAC__byte*)(&val); + if(!is_big_endian_host_) { + FLAC__byte tmp; + tmp = b[1]; b[1] = b[0]; b[0] = tmp; + } + return flac__utils_fwrite(b, 1, 2, f) == 2; +} + +FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val) +{ + FLAC__byte *b = (FLAC__byte*)(&val); + if(!is_big_endian_host_) { + FLAC__byte tmp; + tmp = b[3]; b[3] = b[0]; b[0] = tmp; + tmp = b[2]; b[2] = b[1]; b[1] = tmp; + } + return flac__utils_fwrite(b, 1, 4, f) == 4; +} + +FLAC__bool write_sane_extended(FILE *f, uint32_t val) + /* Write to 'f' a SANE extended representation of 'val'. Return false if + * the write succeeds; return true otherwise. + * + * SANE extended is an 80-bit IEEE-754 representation with sign bit, 15 bits + * of exponent, and 64 bits of significand (mantissa). Unlike most IEEE-754 + * representations, it does not imply a 1 above the MSB of the significand. + * + */ +{ + uint32_t shift, exponent; + + if(val == 0U) { + if(!write_big_endian_uint16(f, 0)) + return false; + if(!write_big_endian_uint32(f, 0)) + return false; + if(!write_big_endian_uint32(f, 0)) + return false; + return true; + } + + for(shift= 0U; (val>>(31-shift))==0U; ++shift) + ; + val<<= shift; + exponent= 63U-(shift+32U); /* add 32 for unused second word */ + + if(!write_big_endian_uint16(f, (FLAC__uint16)(exponent+0x3FFF))) + return false; + if(!write_big_endian_uint32(f, val)) + return false; + if(!write_big_endian_uint32(f, 0)) /* unused second word */ + return false; + + return true; +} + +FLAC__bool fixup_iff_headers(DecoderSession *d) +{ + const char *fmt_desc = + d->format==FORMAT_WAVE? "WAVE" : + d->format==FORMAT_WAVE64? "Wave64" : + d->format==FORMAT_RF64? "RF64" : + "AIFF"; + FILE *f = flac_fopen(d->outfilename, "r+b"); /* stream is positioned at beginning of file */ + + if(0 == f) { + flac__utils_printf(stderr, 1, "ERROR, couldn't open file %s while fixing up %s chunk size: %s\n", d->outfilename, fmt_desc, strerror(errno)); + return false; + } + + if(!write_iff_headers(f, d, d->samples_processed)) { + fclose(f); + return false; + } + + fclose(f); + return true; +} + +FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + DecoderSession *decoder_session = (DecoderSession*)client_data; + FILE *fout = decoder_session->fout; + const uint32_t bps = frame->header.bits_per_sample, channels = frame->header.channels; + const uint32_t shift = (bps%8)? 8-(bps%8): 0; + FLAC__bool is_big_endian = ( + (decoder_session->format == FORMAT_AIFF || (decoder_session->format == FORMAT_AIFF_C && decoder_session->subformat == SUBFORMAT_AIFF_C_NONE)) ? true : ( + decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 || (decoder_session->format == FORMAT_AIFF_C && decoder_session->subformat == SUBFORMAT_AIFF_C_SOWT) ? false : + decoder_session->is_big_endian + )); + FLAC__bool is_unsigned_samples = ( + decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? false : ( + decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? bps<=8 : + decoder_session->is_unsigned_samples + )); + uint32_t wide_samples = frame->header.blocksize, wide_sample, sample, channel; + FLAC__uint64 frame_bytes = 0; + + static union + { /* The arrays defined within this union are all the same size. */ + FLAC__int8 s8buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; /* WATCHOUT: can be up to 2 megs */ + FLAC__uint8 u8buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; + FLAC__int16 s16buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int16)]; + FLAC__uint16 u16buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int16)]; + FLAC__int32 s32buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS]; + FLAC__uint32 u32buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS]; + } ubuf; + + size_t bytes_to_write = 0; + + (void)decoder; + + if(decoder_session->abort_flag) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + /* sanity-check the bits-per-sample */ + if(decoder_session->bps) { + if(bps != decoder_session->bps) { + if(decoder_session->got_stream_info) + flac__utils_printf(stderr, 1, "%s: ERROR, bits-per-sample is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, bps, decoder_session->bps); + else + flac__utils_printf(stderr, 1, "%s: ERROR, bits-per-sample is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, bps, decoder_session->bps); + if(!decoder_session->continue_through_decode_errors) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + else { + /* must not have gotten STREAMINFO, save the bps from the frame header */ + FLAC__ASSERT(!decoder_session->got_stream_info); + if(decoder_session->format == FORMAT_RAW && ((decoder_session->bps % 8) != 0 || decoder_session->bps < 4)) { + flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 8/16/24/32 for raw format output\n", decoder_session->inbasefilename, decoder_session->bps); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + decoder_session->bps = bps; + } + + /* sanity-check the #channels */ + if(decoder_session->channels) { + if(channels != decoder_session->channels) { + if(decoder_session->got_stream_info) + flac__utils_printf(stderr, 1, "%s: ERROR, channels is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, channels, decoder_session->channels); + else + flac__utils_printf(stderr, 1, "%s: ERROR, channels is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, channels, decoder_session->channels); + if(!decoder_session->continue_through_decode_errors) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + else { + /* must not have gotten STREAMINFO, save the #channels from the frame header */ + FLAC__ASSERT(!decoder_session->got_stream_info); + decoder_session->channels = channels; + } + + /* sanity-check the sample rate */ + if(decoder_session->sample_rate < UINT32_MAX) { + if(frame->header.sample_rate != decoder_session->sample_rate) { + if(decoder_session->got_stream_info) + flac__utils_printf(stderr, 1, "%s: ERROR, sample rate is %u in frame but %u in STREAMINFO\n", decoder_session->inbasefilename, frame->header.sample_rate, decoder_session->sample_rate); + else + flac__utils_printf(stderr, 1, "%s: ERROR, sample rate is %u in this frame but %u in previous frames\n", decoder_session->inbasefilename, frame->header.sample_rate, decoder_session->sample_rate); + if(!decoder_session->continue_through_decode_errors) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + else { + /* must not have gotten STREAMINFO, save the sample rate from the frame header */ + FLAC__ASSERT(!decoder_session->got_stream_info); + decoder_session->sample_rate = frame->header.sample_rate; + } + + /* + * limit the number of samples to accept based on --until + */ + /* if we never got the total_samples from the metadata, the skip and until specs would never have been canonicalized, so protect against that: */ + if(decoder_session->skip_specification->is_relative || !decoder_session->got_stream_info) { + if(decoder_session->skip_specification->value.samples == 0) /* special case for when no --skip was given */ + decoder_session->skip_specification->is_relative = false; /* convert to our meaning of beginning-of-stream */ + else { + flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --skip because the total sample count was not found in the metadata\n", decoder_session->inbasefilename); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + if(decoder_session->until_specification->is_relative || !decoder_session->got_stream_info) { + if(decoder_session->until_specification->value.samples == 0) /* special case for when no --until was given */ + decoder_session->until_specification->is_relative = false; /* convert to our meaning of end-of-stream */ + else { + flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until because the total sample count was not found in the metadata\n", decoder_session->inbasefilename); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0); + FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0); + if(decoder_session->until_specification->value.samples > 0) { + const FLAC__uint64 skip = (FLAC__uint64)decoder_session->skip_specification->value.samples; + const FLAC__uint64 until = (FLAC__uint64)decoder_session->until_specification->value.samples; + const FLAC__uint64 input_samples_passed = skip + decoder_session->samples_processed; + FLAC__ASSERT(until >= input_samples_passed); + if(input_samples_passed + wide_samples > until) + wide_samples = (uint32_t)(until - input_samples_passed); + if (wide_samples == 0) { + decoder_session->abort_flag = true; + decoder_session->aborting_due_to_until = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + + if(decoder_session->analysis_mode) { + FLAC__uint64 dpos; + FLAC__stream_decoder_get_decode_position(decoder_session->decoder, &dpos); + frame_bytes = (dpos-decoder_session->decode_position); + decoder_session->decode_position = dpos; + } + + if(wide_samples > 0) { + decoder_session->samples_processed += wide_samples; + decoder_session->frame_counter++; + +#if 0 /* in case time.h with clock() isn't available for some reason */ + if(!(decoder_session->frame_counter & 0x1ff)) + print_stats(decoder_session); +#else + if((clock() - decoder_session->old_clock_t) > (CLOCKS_PER_SEC/4)) { + print_stats(decoder_session); + decoder_session->old_clock_t = clock(); + } +#endif + + + if(decoder_session->analysis_mode) { + flac__analyze_frame(frame, decoder_session->frame_counter-1, decoder_session->decode_position-frame_bytes, frame_bytes, decoder_session->aopts, fout); + } + else if(!decoder_session->test_only) { + if(shift && !decoder_session->replaygain.apply) { + for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++) + ((uint32_t **)buffer)[channel][wide_sample] <<= shift;/*@@@@@@un-const'ing the buffer is hacky but safe*/ + } + if(decoder_session->replaygain.apply) { + bytes_to_write = FLAC__replaygain_synthesis__apply_gain( + ubuf.u8buffer, + !is_big_endian, + is_unsigned_samples, + buffer, + wide_samples, + channels, + bps, /* source_bps */ + bps+shift, /* target_bps */ + decoder_session->replaygain.scale, + decoder_session->replaygain.spec.limiter == RGSS_LIMIT__HARD, /* hard_limit */ + decoder_session->replaygain.spec.noise_shaping != NOISE_SHAPING_NONE, /* do_dithering */ + &decoder_session->replaygain.dither_context + ); + } + /* first some special code for common cases */ + else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 2 && bps+shift == 16) { + FLAC__int16 *buf1_ = ubuf.s16buffer + 1; + if(is_big_endian) + memcpy(ubuf.s16buffer, ((FLAC__byte*)(buffer[0]))+2, sizeof(FLAC__int32) * wide_samples - 2); + else + memcpy(ubuf.s16buffer, buffer[0], sizeof(FLAC__int32) * wide_samples); + for(sample = 0; sample < wide_samples; sample++, buf1_+=2) + *buf1_ = (FLAC__int16)buffer[1][sample]; + bytes_to_write = 4 * sample; + } + else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 1 && bps+shift == 16) { + FLAC__int16 *buf1_ = ubuf.s16buffer; + for(sample = 0; sample < wide_samples; sample++) + *buf1_++ = (FLAC__int16)buffer[0][sample]; + bytes_to_write = 2 * sample; + } + /* generic code for the rest */ + else if(bps+shift == 16) { + if(is_unsigned_samples) { + if(channels == 2) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000); + ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[1][wide_sample] + 0x8000); + } + } + else if(channels == 1) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000); + } + else { /* works for any 'channels' but above flavors are faster for 1 and 2 */ + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.u16buffer[sample] = (FLAC__uint16)(buffer[channel][wide_sample] + 0x8000); + } + } + else { + if(channels == 2) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]); + ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[1][wide_sample]); + } + } + else if(channels == 1) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]); + } + else { /* works for any 'channels' but above flavors are faster for 1 and 2 */ + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]); + } + } + if(is_big_endian != is_big_endian_host_) { + uint8_t tmp; + const uint32_t bytes = sample * 2; + uint32_t b; + for(b = 0; b < bytes; b += 2) { + tmp = ubuf.u8buffer[b]; + ubuf.u8buffer[b] = ubuf.u8buffer[b+1]; + ubuf.u8buffer[b+1] = tmp; + } + } + bytes_to_write = 2 * sample; + } + else if(bps+shift == 24) { + if(is_unsigned_samples) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.u32buffer[sample] = buffer[channel][wide_sample] + 0x800000; + } + else { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.s32buffer[sample] = buffer[channel][wide_sample]; + } + if(is_big_endian != is_big_endian_host_) { + uint8_t tmp; + const uint32_t bytes = sample * 4; + uint32_t b; + for(b = 0; b < bytes; b += 4) { + tmp = ubuf.u8buffer[b]; + ubuf.u8buffer[b] = ubuf.u8buffer[b+3]; + ubuf.u8buffer[b+3] = tmp; + tmp = ubuf.u8buffer[b+1]; + ubuf.u8buffer[b+1] = ubuf.u8buffer[b+2]; + ubuf.u8buffer[b+2] = tmp; + } + } + if(is_big_endian) { + uint32_t b, lbyte; + const uint32_t bytes = sample * 4; + for(lbyte = b = 0; b < bytes; ) { + b++; + ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++]; + ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++]; + ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++]; + } + } + else { + uint32_t b, lbyte; + const uint32_t bytes = sample * 4; + for(lbyte = b = 0; b < bytes; ) { + ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++]; + ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++]; + ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++]; + b++; + } + } + bytes_to_write = 3 * sample; + } + else if(bps+shift == 8) { + if(is_unsigned_samples) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.u8buffer[sample] = (FLAC__uint8)(buffer[channel][wide_sample] + 0x80); + } + else { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.s8buffer[sample] = (FLAC__int8)(buffer[channel][wide_sample]); + } + bytes_to_write = sample; + } + else if(bps+shift == 32) { + if(is_unsigned_samples) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.u32buffer[sample] = buffer[channel][wide_sample]; + } + else { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ubuf.s32buffer[sample] = buffer[channel][wide_sample]; + } + if(is_big_endian != is_big_endian_host_) { + uint8_t tmp; + const uint32_t bytes = sample * 4; + uint32_t b; + for(b = 0; b < bytes; b += 4) { + tmp = ubuf.u8buffer[b]; + ubuf.u8buffer[b] = ubuf.u8buffer[b+3]; + ubuf.u8buffer[b+3] = tmp; + tmp = ubuf.u8buffer[b+1]; + ubuf.u8buffer[b+1] = ubuf.u8buffer[b+2]; + ubuf.u8buffer[b+2] = tmp; + } + } + bytes_to_write = 4 * sample; + } + else { + FLAC__ASSERT(0); + /* double protection */ + decoder_session->abort_flag = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + } + if(bytes_to_write > 0) { + if(flac__utils_fwrite(ubuf.u8buffer, 1, bytes_to_write, fout) != bytes_to_write) { + /* if a pipe closed when writing to stdout, we let it go without an error message */ + if(errno == EPIPE && decoder_session->fout == stdout) + decoder_session->aborting_due_to_until = true; + decoder_session->abort_flag = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + DecoderSession *decoder_session = (DecoderSession*)client_data; + + (void)decoder; + + if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + FLAC__uint64 skip, until; + + if(decoder_session->got_stream_info){ + /* There was already a STREAMINFO received */ + flac__utils_printf(stderr, 1, "%s: ERROR, more than one STREAMINFO found\n", decoder_session->inbasefilename); + if(!decoder_session->continue_through_decode_errors) + decoder_session->abort_flag = true; + return; + } + + decoder_session->got_stream_info = true; + decoder_session->has_md5sum = memcmp(metadata->data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) != 0; + decoder_session->bps = metadata->data.stream_info.bits_per_sample; + decoder_session->channels = metadata->data.stream_info.channels; + decoder_session->sample_rate = metadata->data.stream_info.sample_rate; + + if(!flac__utils_canonicalize_skip_until_specification(decoder_session->skip_specification, decoder_session->sample_rate)) { + flac__utils_printf(stderr, 1, "%s: ERROR, value of --skip is too large\n", decoder_session->inbasefilename); + decoder_session->abort_flag = true; + return; + } + FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0); + skip = (FLAC__uint64)decoder_session->skip_specification->value.samples; + + /* remember, metadata->data.stream_info.total_samples can be 0, meaning 'unknown' */ + if(metadata->data.stream_info.total_samples > 0 && skip >= metadata->data.stream_info.total_samples) { + flac__utils_printf(stderr, 1, "%s: ERROR trying to --skip more samples than in stream\n", decoder_session->inbasefilename); + decoder_session->abort_flag = true; + return; + } + else if(metadata->data.stream_info.total_samples == 0 && skip > 0) { + flac__utils_printf(stderr, 1, "%s: ERROR, can't --skip when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename); + decoder_session->abort_flag = true; + return; + } + FLAC__ASSERT(skip == 0 || 0 == decoder_session->cue_specification); + decoder_session->total_samples = metadata->data.stream_info.total_samples - skip; + + /* note that we use metadata->data.stream_info.total_samples instead of decoder_session->total_samples */ + if(!canonicalize_until_specification(decoder_session->until_specification, decoder_session->inbasefilename, decoder_session->sample_rate, skip, metadata->data.stream_info.total_samples)) { + decoder_session->abort_flag = true; + return; + } + FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0); + until = (FLAC__uint64)decoder_session->until_specification->value.samples; + + if(until > 0) { + FLAC__ASSERT(decoder_session->total_samples != 0); + FLAC__ASSERT(0 == decoder_session->cue_specification); + decoder_session->total_samples -= (metadata->data.stream_info.total_samples - until); + } + + if(decoder_session->format == FORMAT_RAW && ((decoder_session->bps % 8) != 0 || decoder_session->bps < 4)) { + flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 8/16/24/32 for raw format output\n", decoder_session->inbasefilename, decoder_session->bps); + decoder_session->abort_flag = true; + return; + } + + if(decoder_session->bps < 4 || decoder_session->bps > 32) { + flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 4-32\n", decoder_session->inbasefilename, decoder_session->bps); + decoder_session->abort_flag = true; + return; + } + } + else if(metadata->type == FLAC__METADATA_TYPE_CUESHEET) { + /* remember, at this point, decoder_session->total_samples can be 0, meaning 'unknown' */ + if(decoder_session->total_samples == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR can't use --cue when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename); + decoder_session->abort_flag = true; + return; + } + + flac__utils_canonicalize_cue_specification(decoder_session->cue_specification, &metadata->data.cue_sheet, decoder_session->total_samples, decoder_session->skip_specification, decoder_session->until_specification); + + FLAC__ASSERT(!decoder_session->skip_specification->is_relative); + FLAC__ASSERT(decoder_session->skip_specification->value_is_samples); + + FLAC__ASSERT(!decoder_session->until_specification->is_relative); + FLAC__ASSERT(decoder_session->until_specification->value_is_samples); + + FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0); + FLAC__ASSERT(decoder_session->until_specification->value.samples >= 0); + FLAC__ASSERT((FLAC__uint64)decoder_session->until_specification->value.samples <= decoder_session->total_samples); + FLAC__ASSERT(decoder_session->skip_specification->value.samples <= decoder_session->until_specification->value.samples); + + decoder_session->total_samples = decoder_session->until_specification->value.samples - decoder_session->skip_specification->value.samples; + } + else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + if (decoder_session->replaygain.spec.apply) { + double reference, gain, peak; + if (!(decoder_session->replaygain.apply = grabbag__replaygain_load_from_vorbiscomment(metadata, decoder_session->replaygain.spec.use_album_gain, /*strict=*/false, &reference, &gain, &peak))) { + flac__utils_printf(stderr, 1, "%s: WARNING: can't get %s (or even %s) ReplayGain tags\n", decoder_session->inbasefilename, decoder_session->replaygain.spec.use_album_gain? "album":"track", decoder_session->replaygain.spec.use_album_gain? "track":"album"); + if(decoder_session->treat_warnings_as_errors) { + decoder_session->abort_flag = true; + return; + } + } + else if(decoder_session->bps == 0) { + flac__utils_printf(stderr, 1, "%s: WARNING: can't apply ReplayGain, bit-per-sample value is invalid\n", decoder_session->inbasefilename); + if(decoder_session->treat_warnings_as_errors) { + decoder_session->abort_flag = true; + return; + } + } + else { + const char *ls[] = { "no", "peak", "hard" }; + const char *ns[] = { "no", "low", "medium", "high" }; + decoder_session->replaygain.scale = grabbag__replaygain_compute_scale_factor(peak, gain, decoder_session->replaygain.spec.preamp, decoder_session->replaygain.spec.limiter == RGSS_LIMIT__PEAK); + FLAC__ASSERT(decoder_session->bps > 0 && decoder_session->bps <= 32); + FLAC__replaygain_synthesis__init_dither_context(&decoder_session->replaygain.dither_context, decoder_session->bps, decoder_session->replaygain.spec.noise_shaping); + flac__utils_printf(stderr, 1, "%s: INFO: applying %s ReplayGain (gain=%0.2fdB+preamp=%0.1fdB, %s noise shaping, %s limiting) to output\n", decoder_session->inbasefilename, decoder_session->replaygain.spec.use_album_gain? "album":"track", gain, decoder_session->replaygain.spec.preamp, ns[decoder_session->replaygain.spec.noise_shaping], ls[decoder_session->replaygain.spec.limiter]); + flac__utils_printf(stderr, 1, "%s: WARNING: applying ReplayGain is not lossless\n", decoder_session->inbasefilename); + /* don't check if(decoder_session->treat_warnings_as_errors) because the user explicitly asked for it */ + } + } + (void)flac__utils_get_channel_mask_tag(metadata, &decoder_session->channel_mask); + } + else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && decoder_session->warn_user_about_foreign_metadata) { + /* Foreign metadata signalling */ + flac__utils_printf(stderr, 1, "%s: WARNING: found foreign metadata, use --keep-foreign-metadata to restore\n", decoder_session->inbasefilename); + decoder_session->warn_user_about_foreign_metadata = false; + } +} + +void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + DecoderSession *decoder_session = (DecoderSession*)client_data; + (void)decoder; + if(!decoder_session->error_callback_suppress_messages) { + stats_print_name(1, decoder_session->inbasefilename); + flac__utils_printf(stderr, 1, "*** Got error code %d:%s\n", status, FLAC__StreamDecoderErrorStatusString[status]); + } + if(!decoder_session->continue_through_decode_errors) { + /* if we got a sync error while looking for metadata, either it's not a FLAC file (more likely) or the file is corrupted */ + if( + !decoder_session->error_callback_suppress_messages && + status == FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC && + FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + ) { + flac__utils_printf(stderr, 1, + "\n" + "The input file is either not a FLAC file or is corrupted. If you are\n" + "convinced it is a FLAC file, you can rerun the same command and add the\n" + "-F parameter to try and recover as much as possible from the file.\n" + ); + decoder_session->error_callback_suppress_messages = true; + } + else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM) + decoder_session->aborting_due_to_unparseable = true; + decoder_session->abort_flag = true; + } +} + +void print_error_with_init_status(const DecoderSession *d, const char *message, FLAC__StreamDecoderInitStatus init_status) +{ + const int ilen = strlen(d->inbasefilename) + 1; + + flac__utils_printf(stderr, 1, "\n%s: %s\n", d->inbasefilename, message); + + flac__utils_printf(stderr, 1, "%*s init status = %s\n", ilen, "", FLAC__StreamDecoderInitStatusString[init_status]); + + /* print out some more info for some errors: */ + if (init_status == FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE) { + flac__utils_printf(stderr, 1, + "\n" +#ifdef _WIN32 + "An error occurred opening the input file; it is likely that it does not exist,\n" + "is not readable or has a filename that exceeds the path length limit.\n" +#else + "An error occurred opening the input file; it is likely that it does not exist\n" + "or is not readable.\n" +#endif + ); + } +} + +void print_error_with_state(const DecoderSession *d, const char *message) +{ + const int ilen = strlen(d->inbasefilename) + 1; + + flac__utils_printf(stderr, 1, "\n%s: %s\n", d->inbasefilename, message); + flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", FLAC__stream_decoder_get_resolved_state_string(d->decoder)); + + /* print out some more info for some errors: */ + if (d->aborting_due_to_unparseable) { + flac__utils_printf(stderr, 1, + "\n" + "The FLAC stream may have been created by a more advanced encoder. Try\n" + " metaflac --show-vendor-tag %s\n" + "If the version number is greater than %s, this decoder is probably\n" + "not able to decode the file. If the version number is not, the file\n" + "may be corrupted, or you may have found a bug. In this case please\n" + "submit a bug report to\n" + " https://github.com/xiph/flac/issues\n" + "Make sure to use the \"Monitor\" feature to monitor the bug status.\n", + d->inbasefilename, FLAC__VERSION_STRING + ); + } +} + +void print_stats(const DecoderSession *decoder_session) +{ + if(flac__utils_verbosity_ >= 2) { + const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0; + + if(decoder_session->total_samples > 0) { + if ((uint32_t)floor(progress + 0.5) == 100) + return; + + stats_print_name(2, decoder_session->inbasefilename); + stats_print_info(2, "%s%u%% complete", + decoder_session->test_only? "testing, " : decoder_session->analysis_mode? "analyzing, " : "", + (uint32_t)floor(progress + 0.5) + ); + } + else { + stats_print_name(2, decoder_session->inbasefilename); + stats_print_info(2, "%s %" PRIu64 " samples", + decoder_session->test_only? "tested" : decoder_session->analysis_mode? "analyzed" : "wrote", + decoder_session->samples_processed + ); + } + } +} diff --git a/vendor/flac/src/flac/decode.h b/vendor/flac/src/flac/decode.h new file mode 100644 index 0000000..24f5723 --- /dev/null +++ b/vendor/flac/src/flac/decode.h @@ -0,0 +1,73 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef flac__decode_h +#define flac__decode_h + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "analyze.h" +#include "foreign_metadata.h" +#include "utils.h" +#include "share/replaygain_synthesis.h" + + +typedef struct { + FLAC__bool apply; + FLAC__bool use_album_gain; /* false => use track gain */ + enum { RGSS_LIMIT__NONE, RGSS_LIMIT__PEAK, RGSS_LIMIT__HARD} limiter; + NoiseShaping noise_shaping; + double preamp; +} replaygain_synthesis_spec_t; + +typedef struct { + FLAC__bool treat_warnings_as_errors; + FLAC__bool continue_through_decode_errors; + replaygain_synthesis_spec_t replaygain_synthesis_spec; +#if FLAC__HAS_OGG + FLAC__bool is_ogg; + FLAC__bool use_first_serial_number; + long serial_number; +#endif + utils__SkipUntilSpecification skip_specification; + utils__SkipUntilSpecification until_specification; + FLAC__bool has_cue_specification; + utils__CueSpecification cue_specification; + FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */ + FLAC__bool relaxed_foreign_metadata_handling; + FileSubFormat force_subformat; + + FileFormat format; + union { + struct { + FLAC__bool is_big_endian; + FLAC__bool is_unsigned_samples; + } raw; + struct { + foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */ + } iff; + } format_options; +} decode_options_t; + +/* outfile == 0 => test only */ +int flac__decode_file(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, decode_options_t options); + +#endif diff --git a/vendor/flac/src/flac/encode.c b/vendor/flac/src/flac/encode.c new file mode 100644 index 0000000..a945b35 --- /dev/null +++ b/vendor/flac/src/flac/encode.c @@ -0,0 +1,2852 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for LONG_MAX */ +#include /* for floor() */ +#include /* for FILE etc. */ +#include /* for malloc */ +#include /* for strcmp(), strerror() */ +#include /* for clock() */ +#include +#include "FLAC/all.h" +#include "share/alloc.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "share/private.h" +#include "share/safe_str.h" +#include "share/endswap.h" +#include "encode.h" + +#ifdef min +#undef min +#endif +#define min(x,y) ((x)<(y)?(x):(y)) +#ifdef max +#undef max +#endif +#define max(x,y) ((x)>(y)?(x):(y)) + +/* this MUST be < 2^sizeof(size_t) / ( FLAC__MAX_CHANNELS * (FLAC__MAX_BITS_PER_SAMPLE/8) ) */ +#define CHUNK_OF_SAMPLES 2048 + +typedef struct { + uint32_t sample_rate; + uint32_t channels; + uint32_t bits_per_sample; /* width of sample point, including 'shift' bits, valid bps is bits_per_sample-shift */ + uint32_t shift; /* # of LSBs samples have been shifted left by */ + uint32_t bytes_per_wide_sample; /* for convenience, always == channels*((bps+7)/8), or 0 if N/A to input format (like FLAC) */ + FLAC__bool is_unsigned_samples; + FLAC__bool is_big_endian; + FLAC__uint32 channel_mask; +} SampleInfo; + +/* this is the client_data attached to the FLAC decoder when encoding from a FLAC file */ +typedef struct { + FLAC__off_t filesize; + const FLAC__byte *lookahead; + uint32_t lookahead_length; + size_t num_metadata_blocks; + FLAC__StreamMetadata *metadata_blocks[1024]; /*@@@ BAD MAGIC number */ + FLAC__uint64 samples_left_to_process; + FLAC__bool fatal_error; +} FLACDecoderData; + +typedef struct { +#if FLAC__HAS_OGG + FLAC__bool use_ogg; +#endif + FLAC__bool verify; + FLAC__bool is_stdout; + FLAC__bool outputfile_opened; /* true if we successfully opened the output file and we want it to be deleted if there is an error */ + const char *inbasefilename; + const char *infilename; + const char *outfilename; + + FLAC__bool treat_warnings_as_errors; + FLAC__bool continue_through_decode_errors; + FLAC__bool replay_gain; + FLAC__uint64 total_samples_to_encode; /* (i.e. "wide samples" aka "sample frames") WATCHOUT: may be 0 to mean 'unknown' */ + FLAC__uint64 unencoded_size; /* an estimate of the input size, only used in the progress indicator */ + FLAC__uint64 bytes_written; + FLAC__uint64 samples_written; +#if 0 /* in case time.h with clock() isn't available for some reason */ + uint32_t stats_frames_interval; + uint32_t old_frames_written; +#else + clock_t old_clock_t; +#endif + + SampleInfo info; + + FileFormat format; + union { + struct { + FLAC__uint64 data_bytes; + } iff; + struct { + FLAC__StreamDecoder *decoder; + FLACDecoderData client_data; + } flac; + } fmt; + + FLAC__StreamEncoder *encoder; + + FILE *fin; + FLAC__StreamMetadata *seek_table_template; + double progress, compression_ratio; +} EncoderSession; + +const int FLAC_ENCODE__DEFAULT_PADDING = 8192; + +static FLAC__bool is_big_endian_host_; + +#define UBUFFER_INT8_SIZE 0x10000 + +static union { + FLAC__int8 s8[UBUFFER_INT8_SIZE]; + FLAC__uint8 u8[UBUFFER_INT8_SIZE]; + FLAC__int16 s16[UBUFFER_INT8_SIZE/2]; + FLAC__uint16 u16[UBUFFER_INT8_SIZE/2]; + FLAC__int32 s32[UBUFFER_INT8_SIZE/4]; + FLAC__uint32 u32[UBUFFER_INT8_SIZE/4]; +} ubuffer; + + +static FLAC__int32 in_[FLAC__MAX_CHANNELS][CHUNK_OF_SAMPLES]; +static FLAC__int32 *input_[FLAC__MAX_CHANNELS]; + + +/* + * local routines + */ +static FLAC__bool EncoderSession_construct(EncoderSession *e, encode_options_t options, FLAC__off_t infilesize, FILE *infile, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length); +static void EncoderSession_destroy(EncoderSession *e); +static int EncoderSession_finish_ok(EncoderSession *e, foreign_metadata_t *foreign_metadata, FLAC__bool error_on_compression_fail); +static int EncoderSession_finish_error(EncoderSession *e); +static FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options); +static FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], uint32_t samples); +static FLAC__bool EncoderSession_format_is_iff(const EncoderSession *e); +static FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e); +static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input); +static FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, uint32_t num_metadata); +static FLAC__bool format_input(FLAC__int32 *dest[], uint32_t wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, uint32_t channels, uint32_t bps, uint32_t shift, size_t *channel_map); +static void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data); +static FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); +static FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data); +static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); +static FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors); +static void print_stats(const EncoderSession *encoder_session); +static void print_error_with_init_status(const EncoderSession *e, const char *message, FLAC__StreamEncoderInitStatus init_status); +static void print_error_with_state(const EncoderSession *e, const char *message); +static void print_verify_error(EncoderSession *e); +static FLAC__bool read_bytes(FILE *f, FLAC__byte *buf, size_t n, FLAC__bool eof_ok, const char *fn); +static FLAC__bool read_uint16(FILE *f, FLAC__bool big_endian, FLAC__uint16 *val, const char *fn); +static FLAC__bool read_uint32(FILE *f, FLAC__bool big_endian, FLAC__uint32 *val, const char *fn); +static FLAC__bool read_uint64(FILE *f, FLAC__bool big_endian, FLAC__uint64 *val, const char *fn); +static FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, const char *fn); +static FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset); +static uint32_t count_channel_mask_bits(FLAC__uint32 mask); + +static FLAC__bool get_sample_info_raw(EncoderSession *e, encode_options_t options) +{ + e->info.sample_rate = options.format_options.raw.sample_rate; + e->info.channels = options.format_options.raw.channels; + e->info.bits_per_sample = options.format_options.raw.bps; + e->info.shift = 0; + e->info.bytes_per_wide_sample = options.format_options.raw.channels * ((options.format_options.raw.bps+7)/8); + e->info.is_unsigned_samples = options.format_options.raw.is_unsigned_samples; + e->info.is_big_endian = options.format_options.raw.is_big_endian; + e->info.channel_mask = 0; + + return true; +} + +static FLAC__bool get_sample_info_wave(EncoderSession *e, encode_options_t options) +{ + FLAC__bool got_fmt_chunk = false, got_data_chunk = false, got_ds64_chunk = false; + uint32_t sample_rate = 0, channels = 0, bps = 0, shift = 0, block_align = 0; + FLAC__uint32 channel_mask = 0; + FLAC__uint64 ds64_data_size = 0; + + e->info.is_unsigned_samples = false; + e->info.is_big_endian = false; + + if(e->format == FORMAT_WAVE64) { + /* + * lookahead[] already has "riff\x2E\x91\xCF\x11\xA5\xD6\x28\xDB", skip over remaining header + */ + if(!fskip_ahead(e->fin, 16+8+16-12)) { /* riff GUID + riff size + WAVE GUID - lookahead */ + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over remaining \"riff\" header\n", e->inbasefilename); + return false; + } + } + /* else lookahead[] already has "RIFFxxxxWAVE" or "RF64xxxxWAVE" */ + + while(!feof(e->fin) && !got_data_chunk) { + /* chunk IDs are 4 bytes for WAVE/RF64, 16 for Wave64 */ + /* for WAVE/RF64 we want the 5th char zeroed so we can treat it like a C string */ + char chunk_id[16] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; + + if(!read_bytes(e->fin, (FLAC__byte*)chunk_id, e->format==FORMAT_WAVE64?16:4, /*eof_ok=*/true, e->inbasefilename)) { + flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", e->inbasefilename); + return false; + } + if(feof(e->fin)) + break; + + if(e->format == FORMAT_RF64 && !memcmp(chunk_id, "ds64", 4)) { /* RF64 64-bit sizes chunk */ + FLAC__uint32 xx, data_bytes; + + if(got_ds64_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'ds64' chunks\n", e->inbasefilename); + return false; + } + if(got_fmt_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: 'ds64' chunk appears after 'fmt ' or 'data' chunk\n", e->inbasefilename); + return false; + } + + /* ds64 chunk size */ + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + data_bytes = xx; + if(data_bytes < 28) { + flac__utils_printf(stderr, 1, "%s: ERROR: non-standard 'ds64' chunk has length = %u\n", e->inbasefilename, (uint32_t)data_bytes); + return false; + } + if(data_bytes & 1) /* should never happen, but enforce WAVE alignment rules */ + data_bytes++; + + /* RIFF 64-bit size, lo/hi */ + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + + /* 'data' 64-bit size */ + if(!read_uint64(e->fin, /*big_endian=*/false, &ds64_data_size, e->inbasefilename)) + return false; + + data_bytes -= 16; + + /* skip any extra data in the ds64 chunk */ + if(!fskip_ahead(e->fin, data_bytes)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'ds64' data\n", e->inbasefilename); + return false; + } + + got_ds64_chunk = true; + } + else if( + !memcmp(chunk_id, "fmt ", 4) && + (e->format!=FORMAT_WAVE64 || !memcmp(chunk_id, "fmt \xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) + ) { /* format chunk */ + FLAC__uint16 x; + FLAC__uint32 xx, data_bytes; + FLAC__uint16 wFormatTag; /* wFormatTag word from the 'fmt ' chunk */ + + if(got_fmt_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'fmt ' chunks\n", e->inbasefilename); + return false; + } + + /* see + * http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html + * http://windowssdk.msdn.microsoft.com/en-us/library/ms713497.aspx + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/audio_r/hh/Audio_r/aud-prop_d40f094e-44f9-4baa-8a15-03e4fb369501.xml.asp + * + * WAVEFORMAT is + * 4 byte: chunk size + * 2 byte: format type: 1 for WAVE_FORMAT_PCM, 65534 for WAVE_FORMAT_EXTENSIBLE + * 2 byte: # channels + * 4 byte: sample rate (Hz) + * 4 byte: avg bytes per sec + * 2 byte: block align + * 2 byte: bits per sample (not necessarily all significant) + * WAVEFORMATEX adds + * 2 byte: extension size in bytes (usually 0 for WAVEFORMATEX and 22 for WAVEFORMATEXTENSIBLE with PCM) + * WAVEFORMATEXTENSIBLE adds + * 2 byte: valid bits per sample + * 4 byte: channel mask + * 16 byte: subformat GUID, first 2 bytes have format type, 1 being PCM + * + * Current spec says WAVEFORMATEX with PCM must have bps == 8 or 16, or any multiple of 8 for WAVEFORMATEXTENSIBLE. + * Lots of old broken WAVEs/apps have don't follow it, e.g. 20 bps but a block align of 3/6 for mono/stereo. + * + * Block align for WAVE_FORMAT_PCM or WAVE_FORMAT_EXTENSIBLE is also supposed to be channels*bps/8 + * + * If the channel mask has more set bits than # of channels, the extra MSBs are ignored. + * If the channel mask has less set bits than # of channels, the extra channels are unassigned to any speaker. + * + * Data is supposed to be uint32_t for bps <= 8 else signed. + */ + + /* fmt chunk size */ + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + data_bytes = xx; + if(e->format == FORMAT_WAVE64) { + /* other half of the size field should be 0 */ + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + if(xx) { + flac__utils_printf(stderr, 1, "%s: ERROR: freakishly large Wave64 'fmt ' chunk has length = 0x%08X%08X\n", e->inbasefilename, (uint32_t)xx, (uint32_t)data_bytes); + return false; + } + /* subtract size of header */ + if (data_bytes < 16+8) { + flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 'fmt ' chunk has length = 0x%08X%08X\n", e->inbasefilename, (uint32_t)xx, (uint32_t)data_bytes); + return false; + } + data_bytes -= (16+8); + } + if(data_bytes < 16 || data_bytes > (UINT32_MAX-8)) { + flac__utils_printf(stderr, 1, "%s: ERROR: non-standard 'fmt ' chunk has length = %u\n", e->inbasefilename, (uint32_t)data_bytes); + return false; + } + if(e->format != FORMAT_WAVE64) { + if(data_bytes & 1) /* should never happen, but enforce WAVE alignment rules */ + data_bytes++; + } + else { /* Wave64 */ + data_bytes = (data_bytes+7) & (~7u); /* should never happen, but enforce Wave64 alignment rules */ + } + + /* format code */ + if(!read_uint16(e->fin, /*big_endian=*/false, &wFormatTag, e->inbasefilename)) + return false; + if(wFormatTag != 1 /*WAVE_FORMAT_PCM*/ && wFormatTag != 65534 /*WAVE_FORMAT_EXTENSIBLE*/) { + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported format type %u\n", e->inbasefilename, (uint32_t)wFormatTag); + return false; + } + + /* number of channels */ + if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename)) + return false; + channels = (uint32_t)x; + + /* sample rate */ + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + sample_rate = xx; + + /* avg bytes per second (ignored) */ + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + /* block align */ + if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename)) + return false; + block_align = x; + /* bits per sample */ + if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename)) + return false; + bps = (uint32_t)x; + + e->info.is_unsigned_samples = (bps <= 8); + + if(wFormatTag == 1) { + if(bps != 8 && bps != 16) { + if(bps == 24 || bps == 32) { + /* let these slide with a warning since they're unambiguous */ + flac__utils_printf(stderr, 1, "%s: WARNING: legacy WAVE file has format type %u but bits-per-sample=%u\n", e->inbasefilename, (uint32_t)wFormatTag, bps); + if(e->treat_warnings_as_errors) + return false; + } + else { + /* @@@ we could add an option to specify left- or right-justified blocks so we knew how to set 'shift' */ + flac__utils_printf(stderr, 1, "%s: ERROR: legacy WAVE file has format type %u but bits-per-sample=%u\n", e->inbasefilename, (uint32_t)wFormatTag, bps); + return false; + } + } + if((bps+7)/8 * channels != block_align) { + flac__utils_printf(stderr, 1, "%s: ERROR: legacy WAVE file has block alignment=%u, bits-per-sample=%u, channels=%u\n", e->inbasefilename, (uint32_t)wFormatTag, block_align, bps, channels); + return false; + } + if(channels > 2 && !options.channel_map_none) { + flac__utils_printf(stderr, 1, "%s: ERROR: WAVE has >2 channels but is not WAVE_FORMAT_EXTENSIBLE; cannot assign channels\n", e->inbasefilename); + return false; + } + FLAC__ASSERT(data_bytes >= 16); + data_bytes -= 16; + } + else { + if(data_bytes < 40) { + flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with size %u\n", e->inbasefilename, (uint32_t)data_bytes); + return false; + } + /* cbSize */ + if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename)) + return false; + if(x < 22) { + flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with cbSize %u\n", e->inbasefilename, (uint32_t)x); + return false; + } + /* valid bps */ + if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename)) + return false; + if((uint32_t)x > bps) { + flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with wValidBitsPerSample (%u) > wBitsPerSample (%u)\n", e->inbasefilename, (uint32_t)x, bps); + return false; + } + shift = bps - (uint32_t)x; + /* channel mask */ + if(!read_uint32(e->fin, /*big_endian=*/false, &channel_mask, e->inbasefilename)) + return false; + + if(count_channel_mask_bits(channel_mask) > channels) { + flac__utils_printf(stderr, 1, "%s: WARNING: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has extra bits for non-existant channels (#channels=%u)\n", e->inbasefilename, (uint32_t)channel_mask, channels); + if(e->treat_warnings_as_errors) + return false; + } + /* first part of GUID */ + if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename)) + return false; + if(x != 1) { + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported WAVEFORMATEXTENSIBLE chunk with non-PCM format %u\n", e->inbasefilename, (uint32_t)x); + return false; + } + data_bytes -= 26; + } + + e->info.bytes_per_wide_sample = channels * (bps / 8); + + /* skip any extra data in the fmt chunk */ + if(!fskip_ahead(e->fin, data_bytes)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'fmt' data\n", e->inbasefilename); + return false; + } + + got_fmt_chunk = true; + } + else if( + !memcmp(chunk_id, "data", 4) && + (e->format!=FORMAT_WAVE64 || !memcmp(chunk_id, "data\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) + ) { /* data chunk */ + FLAC__uint32 xx; + FLAC__uint64 data_bytes; + + if(!got_fmt_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: got 'data' chunk before 'fmt' chunk\n", e->inbasefilename); + return false; + } + + /* data size */ + if(e->format != FORMAT_WAVE64) { + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + data_bytes = xx; + } + else { /* Wave64 */ + if(!read_uint64(e->fin, /*big_endian=*/false, &data_bytes, e->inbasefilename)) + return false; + /* subtract size of header */ + if (data_bytes < 16+8) { + flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 'data' chunk has length = 0x00000000%08X\n", e->inbasefilename, (uint32_t)data_bytes); + return false; + } + data_bytes -= (16+8); + } + if(e->format == FORMAT_RF64) { + if(!got_ds64_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: RF64 file has no 'ds64' chunk before 'data' chunk\n", e->inbasefilename); + return false; + } + if(data_bytes == 0xffffffff) + data_bytes = ds64_data_size; + } + if(options.ignore_chunk_sizes) { + if(data_bytes) { + flac__utils_printf(stderr, 1, "%s: WARNING: 'data' chunk has non-zero size, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id); + if(e->treat_warnings_as_errors) + return false; + } + data_bytes = (FLAC__uint64)0 - (FLAC__uint64)e->info.bytes_per_wide_sample; /* max out data_bytes; we'll use EOF as signal to stop reading */ + } + else if(0 == data_bytes) { + flac__utils_printf(stderr, 1, "%s: ERROR: 'data' chunk has size of 0\n", e->inbasefilename); + return false; + } + + e->fmt.iff.data_bytes = data_bytes; + + got_data_chunk = true; + break; + } + else { + FLAC__uint32 xx; + FLAC__uint64 skip; + if(!options.format_options.iff.foreign_metadata) { + if(e->format != FORMAT_WAVE64) + flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", e->inbasefilename, chunk_id); + else + flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X (use --keep-foreign-metadata to keep)\n", + e->inbasefilename, + (uint32_t)((const uint8_t *)chunk_id)[3], + (uint32_t)((const uint8_t *)chunk_id)[2], + (uint32_t)((const uint8_t *)chunk_id)[1], + (uint32_t)((const uint8_t *)chunk_id)[0], + (uint32_t)((const uint8_t *)chunk_id)[5], + (uint32_t)((const uint8_t *)chunk_id)[4], + (uint32_t)((const uint8_t *)chunk_id)[7], + (uint32_t)((const uint8_t *)chunk_id)[6], + (uint32_t)((const uint8_t *)chunk_id)[9], + (uint32_t)((const uint8_t *)chunk_id)[8], + (uint32_t)((const uint8_t *)chunk_id)[10], + (uint32_t)((const uint8_t *)chunk_id)[11], + (uint32_t)((const uint8_t *)chunk_id)[12], + (uint32_t)((const uint8_t *)chunk_id)[13], + (uint32_t)((const uint8_t *)chunk_id)[14], + (uint32_t)((const uint8_t *)chunk_id)[15] + ); + if(e->treat_warnings_as_errors) + return false; + } + + /* chunk size */ + if(e->format != FORMAT_WAVE64) { + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; + skip = xx; + skip += skip & 1; + } + else { /* Wave64 */ + if(!read_uint64(e->fin, /*big_endian=*/false, &skip, e->inbasefilename)) + return false; + skip = (skip+7) & (~(FLAC__uint64)7); + /* subtract size of header */ + if (skip < 16+8) { + flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 chunk has length = 0x00000000%08X\n", e->inbasefilename, (uint32_t)skip); + return false; + } + skip -= (16+8); + } + if(skip) { + if(!fskip_ahead(e->fin, skip)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over chunk\n", e->inbasefilename); + return false; + } + } + } + } + + if(!got_fmt_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: didn't find fmt chunk\n", e->inbasefilename); + return false; + } + if(!got_data_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: didn't find data chunk\n", e->inbasefilename); + return false; + } + + e->info.sample_rate = sample_rate; + e->info.channels = channels; + e->info.bits_per_sample = bps; + e->info.shift = shift; + e->info.channel_mask = channel_mask; + + return true; +} + +static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t options) +{ + FLAC__bool got_comm_chunk = false, got_ssnd_chunk = false; + uint32_t sample_rate = 0, channels = 0, bps = 0, shift = 0; + FLAC__uint64 sample_frames = 0; + FLAC__uint32 channel_mask = 0; + + e->info.is_unsigned_samples = false; + e->info.is_big_endian = true; + + /* + * lookahead[] already has "FORMxxxxAIFF", do chunks + */ + while(!feof(e->fin) && !got_ssnd_chunk) { + char chunk_id[5] = { '\0', '\0', '\0', '\0', '\0' }; /* one extra byte for terminating NUL so we can also treat it like a C string */ + if(!read_bytes(e->fin, (FLAC__byte*)chunk_id, 4, /*eof_ok=*/true, e->inbasefilename)) { + flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", e->inbasefilename); + return false; + } + if(feof(e->fin)) + break; + + if(!memcmp(chunk_id, "COMM", 4)) { /* common chunk */ + FLAC__uint16 x; + FLAC__uint32 xx; + uint64_t skip; + const FLAC__bool is_aifc = e->format == FORMAT_AIFF_C; + const FLAC__uint32 minimum_comm_size = (is_aifc? 22 : 18); + + if(got_comm_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'COMM' chunks\n", e->inbasefilename); + return false; + } + + /* COMM chunk size */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + else if(xx < minimum_comm_size) { + flac__utils_printf(stderr, 1, "%s: ERROR: non-standard %s 'COMM' chunk has length = %u\n", e->inbasefilename, is_aifc? "AIFF-C" : "AIFF", (uint32_t)xx); + return false; + } + else if(!is_aifc && xx != minimum_comm_size) { + flac__utils_printf(stderr, 1, "%s: WARNING: non-standard %s 'COMM' chunk has length = %u, expected %u\n", e->inbasefilename, is_aifc? "AIFF-C" : "AIFF", (uint32_t)xx, minimum_comm_size); + if(e->treat_warnings_as_errors) + return false; + } + skip = (xx-minimum_comm_size)+(xx & 1); + + /* number of channels */ + if(!read_uint16(e->fin, /*big_endian=*/true, &x, e->inbasefilename)) + return false; + channels = (uint32_t)x; + if(channels > 2 && !options.channel_map_none) { + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u for AIFF\n", e->inbasefilename, channels); + return false; + } + + /* number of sample frames */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + sample_frames = xx; + + /* bits per sample */ + if(!read_uint16(e->fin, /*big_endian=*/true, &x, e->inbasefilename)) + return false; + bps = (uint32_t)x; + shift = (bps%8)? 8-(bps%8) : 0; /* SSND data is always byte-aligned, left-justified but format_input() will double-check */ + bps += shift; + + /* sample rate */ + if(!read_sane_extended(e->fin, &xx, e->inbasefilename)) + return false; + sample_rate = xx; + + /* check compression type for AIFF-C */ + if(is_aifc) { + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + if(xx == 0x736F7774) /* "sowt" */ + e->info.is_big_endian = false; + else if(xx == 0x4E4F4E45) /* "NONE" */ + ; /* nothing to do, we already default to big-endian */ + else { + flac__utils_printf(stderr, 1, "%s: ERROR: can't handle AIFF-C compression type \"%c%c%c%c\"\n", e->inbasefilename, (char)(xx>>24), (char)((xx>>16)&8), (char)((xx>>8)&8), (char)(xx&8)); + return false; + } + } + + /* set channel mapping */ + /* FLAC order follows SMPTE and WAVEFORMATEXTENSIBLE but with fewer channels, which are: */ + /* front left, front right, center, LFE, back left, back right, surround left, surround right */ + /* specs say the channel ordering is: + * 1 2 3 4 5 6 + * ___________________________________________________ + * 2 stereo l r + * 3 l r c + * 4 l c r S + * quad (ambiguous with 4ch) Fl Fr Bl Br + * 5 Fl Fr Fc Sl Sr + * 6 l lc c r rc S + * l:left r:right c:center Fl:front-left Fr:front-right Bl:back-left Br:back-right Lc:left-center Rc:right-center S:surround + * so we only have unambiguous mappings for 2, 3, and 5 channels + */ + if( + options.channel_map_none || + channels == 1 || /* 1 channel: (mono) */ + channels == 2 || /* 2 channels: left, right */ + channels == 3 || /* 3 channels: left, right, center */ + channels == 5 /* 5 channels: front left, front right, center, surround left, surround right */ + ) { + /* keep default channel order */ + } + else { + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u for AIFF\n", e->inbasefilename, channels); + return false; + } + + e->info.bytes_per_wide_sample = channels * (bps / 8); + + /* skip any extra data in the COMM chunk */ + if(!fskip_ahead(e->fin, skip)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra COMM data\n", e->inbasefilename); + return false; + } + + got_comm_chunk = true; + } + else if(!memcmp(chunk_id, "SSND", 4) && !got_ssnd_chunk) { /* sound data chunk */ + FLAC__uint32 xx; + FLAC__uint64 data_bytes; + uint32_t offset = 0; + + if(!got_comm_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: got 'SSND' chunk before 'COMM' chunk\n", e->inbasefilename); + return false; + } + + /* SSND chunk size */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + data_bytes = xx; + if(options.ignore_chunk_sizes) { + if(data_bytes) { + flac__utils_printf(stderr, 1, "%s: WARNING: 'SSND' chunk has non-zero size, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id); + if(e->treat_warnings_as_errors) + return false; + } + data_bytes = (FLAC__uint64)0 - (FLAC__uint64)e->info.bytes_per_wide_sample; /* max out data_bytes; we'll use EOF as signal to stop reading */ + } + else if(data_bytes <= 8) { + flac__utils_printf(stderr, 1, "%s: ERROR: 'SSND' chunk has size <= 8\n", e->inbasefilename); + return false; + } + else { + data_bytes -= 8; /* discount the offset and block size fields */ + } + + /* offset */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + offset = xx; + data_bytes -= offset; + + /* block size */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + if(xx && !options.ignore_chunk_sizes) + data_bytes -= (xx - (data_bytes % xx)); + if(options.ignore_chunk_sizes) { + if(xx) { + flac__utils_printf(stderr, 1, "%s: WARNING: 'SSND' chunk has non-zero blocksize, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id); + if(e->treat_warnings_as_errors) + return false; + } + } + + /* skip any SSND offset bytes */ + if(!fskip_ahead(e->fin, offset)) { + flac__utils_printf(stderr, 1, "%s: ERROR: skipping offset in SSND chunk\n", e->inbasefilename); + return false; + } + + e->fmt.iff.data_bytes = data_bytes; + + got_ssnd_chunk = true; + } + else { + FLAC__uint32 xx; + if(!options.format_options.iff.foreign_metadata) { + flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", e->inbasefilename, chunk_id); + if(e->treat_warnings_as_errors) + return false; + } + + /* chunk size */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + else { + uint64_t skip = xx + (xx & 1); + + FLAC__ASSERT(skip <= LONG_MAX); + if(!fskip_ahead(e->fin, skip)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over chunk\n", e->inbasefilename); + return false; + } + } + } + } + + if(!got_comm_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: didn't find COMM chunk\n", e->inbasefilename); + return false; + } + if(!got_ssnd_chunk && sample_frames) { + flac__utils_printf(stderr, 1, "%s: ERROR: didn't find SSND chunk\n", e->inbasefilename); + return false; + } + + e->info.sample_rate = sample_rate; + e->info.channels = channels; + e->info.bits_per_sample = bps; + e->info.shift = shift; + e->info.channel_mask = channel_mask; + + return true; +} + +static FLAC__bool get_sample_info_flac(EncoderSession *e) +{ + if (!( + FLAC__stream_decoder_set_md5_checking(e->fmt.flac.decoder, false) && + FLAC__stream_decoder_set_metadata_respond_all(e->fmt.flac.decoder) + )) { + flac__utils_printf(stderr, 1, "%s: ERROR: setting up decoder for FLAC input\n", e->inbasefilename); + return false; + } + + if (e->format == FORMAT_OGGFLAC) { + if (FLAC__stream_decoder_init_ogg_stream(e->fmt.flac.decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/e) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for Ogg FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder)); + return false; + } + } + else if (FLAC__stream_decoder_init_stream(e->fmt.flac.decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/e) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder)); + return false; + } + + if (!FLAC__stream_decoder_process_until_end_of_metadata(e->fmt.flac.decoder) || e->fmt.flac.client_data.fatal_error) { + if (e->fmt.flac.client_data.fatal_error) + flac__utils_printf(stderr, 1, "%s: ERROR: out of memory or too many metadata blocks while reading metadata in FLAC input\n", e->inbasefilename); + else + flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder)); + return false; + } + + if (e->fmt.flac.client_data.num_metadata_blocks == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, got no metadata blocks\n", e->inbasefilename); + return false; + } + else if (e->fmt.flac.client_data.metadata_blocks[0]->type != FLAC__METADATA_TYPE_STREAMINFO) { + flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, first metadata block is not STREAMINFO\n", e->inbasefilename); + return false; + } + else if (e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.total_samples == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: FLAC input has STREAMINFO with unknown total samples which is not supported\n", e->inbasefilename); + return false; + } + + e->info.sample_rate = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.sample_rate; + e->info.channels = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.channels; + e->info.bits_per_sample = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.bits_per_sample; + e->info.shift = 0; + e->info.bytes_per_wide_sample = 0; + e->info.is_unsigned_samples = false; /* not applicable for FLAC input */ + e->info.is_big_endian = false; /* not applicable for FLAC input */ + e->info.channel_mask = 0; + + return true; +} + +/* + * public routines + */ +int flac__encode_file(FILE *infile, FLAC__off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length, encode_options_t options) +{ + EncoderSession encoder_session; + size_t channel_map[FLAC__MAX_CHANNELS]; + + if(!EncoderSession_construct(&encoder_session, options, infilesize, infile, infilename, outfilename, lookahead, lookahead_length)) + return 1; + + /* initialize default channel map that preserves channel order */ + { + size_t i; + for(i = 0; i < sizeof(channel_map)/sizeof(channel_map[0]); i++) + channel_map[i] = i; + } + + /* read foreign metadata if requested */ + if(EncoderSession_format_is_iff(&encoder_session) && options.format_options.iff.foreign_metadata) { + const char *error; + if(!( + options.format == FORMAT_WAVE || options.format == FORMAT_RF64? + flac__foreign_metadata_read_from_wave(options.format_options.iff.foreign_metadata, infilename, &error) : + options.format == FORMAT_WAVE64? + flac__foreign_metadata_read_from_wave64(options.format_options.iff.foreign_metadata, infilename, &error) : + flac__foreign_metadata_read_from_aiff(options.format_options.iff.foreign_metadata, infilename, &error) + )) { + if(options.relaxed_foreign_metadata_handling) { + flac__utils_printf(stderr, 1, "%s: WARNING reading foreign metadata: %s\n", encoder_session.inbasefilename, error); + if(encoder_session.treat_warnings_as_errors) + return EncoderSession_finish_error(&encoder_session); + } + else { + flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", encoder_session.inbasefilename, error); + return EncoderSession_finish_error(&encoder_session); + } + } + } + + /* initialize encoder session with info about the audio (channels/bps/resolution/endianness/etc) */ + switch(options.format) { + case FORMAT_RAW: + if(!get_sample_info_raw(&encoder_session, options)) + return EncoderSession_finish_error(&encoder_session); + break; + case FORMAT_WAVE: + case FORMAT_WAVE64: + case FORMAT_RF64: + if(!get_sample_info_wave(&encoder_session, options)) + return EncoderSession_finish_error(&encoder_session); + break; + case FORMAT_AIFF: + case FORMAT_AIFF_C: + if(!get_sample_info_aiff(&encoder_session, options)) + return EncoderSession_finish_error(&encoder_session); + break; + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + /* + * set up FLAC decoder for the input + */ + if (0 == (encoder_session.fmt.flac.decoder = FLAC__stream_decoder_new())) { + flac__utils_printf(stderr, 1, "%s: ERROR: creating decoder for FLAC input\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + if(!get_sample_info_flac(&encoder_session)) + return EncoderSession_finish_error(&encoder_session); + break; + default: + FLAC__ASSERT(0); + /* double protection */ + return EncoderSession_finish_error(&encoder_session); + } + + /* some more checks */ + if(encoder_session.info.channels == 0 || encoder_session.info.channels > FLAC__MAX_CHANNELS) { + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u\n", encoder_session.inbasefilename, encoder_session.info.channels); + return EncoderSession_finish_error(&encoder_session); + } + if(!FLAC__format_sample_rate_is_valid(encoder_session.info.sample_rate)) { + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, encoder_session.info.sample_rate); + return EncoderSession_finish_error(&encoder_session); + } + if(encoder_session.info.bits_per_sample-encoder_session.info.shift < 4 || encoder_session.info.bits_per_sample-encoder_session.info.shift > 32) { + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits-per-sample %u\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift); + return EncoderSession_finish_error(&encoder_session); + } + + { + FLAC__uint64 total_samples_in_input; /* WATCHOUT: may be 0 to mean "unknown" */ + FLAC__uint64 skip; + FLAC__uint64 until; /* a value of 0 mean end-of-stream (i.e. --until=-0) */ + uint32_t consecutive_eos_count = 0; + + switch(options.format) { + case FORMAT_RAW: + if(infilesize < 0) + total_samples_in_input = 0; + else + total_samples_in_input = (FLAC__uint64)infilesize / encoder_session.info.bytes_per_wide_sample; + break; + case FORMAT_WAVE: + case FORMAT_WAVE64: + case FORMAT_RF64: + case FORMAT_AIFF: + case FORMAT_AIFF_C: + /* truncation in the division removes any padding byte that was counted in encoder_session.fmt.iff.data_bytes */ + total_samples_in_input = encoder_session.fmt.iff.data_bytes / encoder_session.info.bytes_per_wide_sample; + + /* check for chunks trailing the audio data */ + if(!options.ignore_chunk_sizes && !options.format_options.iff.foreign_metadata + && infilesize != (FLAC__off_t)(-1)) { + FLAC__off_t current_position = ftello(encoder_session.fin); + if(current_position > 0) { + FLAC__uint64 end_of_data_chunk = current_position + encoder_session.fmt.iff.data_bytes; + if(end_of_data_chunk < (FLAC__uint64)infilesize) { + flac__utils_printf(stderr, 1, "%s: WARNING: there is data trailing the audio data. Use --keep-foreign-metadata or --ignore-chunk-sizes to keep it\n", encoder_session.inbasefilename); + if(encoder_session.treat_warnings_as_errors) + return EncoderSession_finish_error(&encoder_session); + } + else if(end_of_data_chunk > (FLAC__uint64)infilesize) { + flac__utils_printf(stderr, 1, "%s: WARNING: the length of the data chunk overruns the end of the file. Please consult the manual on the --ignore-chunk-sizes option\n", encoder_session.inbasefilename); + if(encoder_session.treat_warnings_as_errors) + return EncoderSession_finish_error(&encoder_session); + } + } + } + break; + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + total_samples_in_input = encoder_session.fmt.flac.client_data.metadata_blocks[0]->data.stream_info.total_samples; + break; + default: + FLAC__ASSERT(0); + /* double protection */ + return EncoderSession_finish_error(&encoder_session); + } + + /* + * now that we know the sample rate, canonicalize the + * --skip string to an absolute sample number: + */ + if(!flac__utils_canonicalize_skip_until_specification(&options.skip_specification, encoder_session.info.sample_rate)) { + flac__utils_printf(stderr, 1, "%s: ERROR: value of --skip is too large\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift); + return EncoderSession_finish_error(&encoder_session); + } + FLAC__ASSERT(options.skip_specification.value.samples >= 0); + skip = (FLAC__uint64)options.skip_specification.value.samples; + + /* + * now that we possibly know the input size, canonicalize the + * --until string to an absolute sample number: + */ + if(!canonicalize_until_specification(&options.until_specification, encoder_session.inbasefilename, encoder_session.info.sample_rate, skip, total_samples_in_input)) + return EncoderSession_finish_error(&encoder_session); + until = (FLAC__uint64)options.until_specification.value.samples; + + /* adjust encoding parameters based on skip and until values */ + switch(options.format) { + case FORMAT_RAW: + FLAC__ASSERT(sizeof(FLAC__off_t) == 8); + if(skip >= INT64_MAX / encoder_session.info.bytes_per_wide_sample) { + flac__utils_printf(stderr, 1, "%s: ERROR: value of --skip is too large\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift); + return EncoderSession_finish_error(&encoder_session); + } + infilesize -= (FLAC__off_t)skip * encoder_session.info.bytes_per_wide_sample; + encoder_session.total_samples_to_encode = total_samples_in_input - skip; + break; + case FORMAT_WAVE: + case FORMAT_WAVE64: + case FORMAT_RF64: + case FORMAT_AIFF: + case FORMAT_AIFF_C: + FLAC__ASSERT(sizeof(FLAC__off_t) == 8); + if(skip >= INT64_MAX / encoder_session.info.bytes_per_wide_sample) { + flac__utils_printf(stderr, 1, "%s: ERROR: value of --skip is too large\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift); + return EncoderSession_finish_error(&encoder_session); + } + encoder_session.fmt.iff.data_bytes -= skip * encoder_session.info.bytes_per_wide_sample; + if(options.ignore_chunk_sizes) { + encoder_session.total_samples_to_encode = 0; + FLAC__ASSERT(0 == until); + } + else { + encoder_session.total_samples_to_encode = total_samples_in_input - skip; + } + break; + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + encoder_session.total_samples_to_encode = total_samples_in_input - skip; + break; + default: + FLAC__ASSERT(0); + /* double protection */ + return EncoderSession_finish_error(&encoder_session); + } + if(until > 0) { + const FLAC__uint64 trim = total_samples_in_input - until; + FLAC__ASSERT(total_samples_in_input > 0); + if(options.format == FORMAT_RAW) + infilesize -= (FLAC__off_t)trim * encoder_session.info.bytes_per_wide_sample; + else if(EncoderSession_format_is_iff(&encoder_session)) + encoder_session.fmt.iff.data_bytes -= trim * encoder_session.info.bytes_per_wide_sample; + encoder_session.total_samples_to_encode -= trim; + } + switch(options.format) { + case FORMAT_RAW: + encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample; + break; + case FORMAT_WAVE: + /* +44 for the size of the WAVE headers; this is just an estimate for the progress indicator and doesn't need to be exact */ + encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 44; + break; + case FORMAT_WAVE64: + /* +44 for the size of the WAVE headers; this is just an estimate for the progress indicator and doesn't need to be exact */ + encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 104; + break; + case FORMAT_RF64: + /* +72 for the size of the RF64 headers; this is just an estimate for the progress indicator and doesn't need to be exact */ + encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 80; + break; + case FORMAT_AIFF: + case FORMAT_AIFF_C: + /* +54 for the size of the AIFF headers; this is just an estimate for the progress indicator and doesn't need to be exact */ + encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample + 54; + break; + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + if(infilesize < 0) + /* if we don't know, use 0 as hint to progress indicator (which is the only place this is used): */ + encoder_session.unencoded_size = 0; + else if(skip == 0 && until == 0) + encoder_session.unencoded_size = (FLAC__uint64)infilesize; + else if(total_samples_in_input) + encoder_session.unencoded_size = (FLAC__uint64)infilesize * encoder_session.total_samples_to_encode / total_samples_in_input; + else + encoder_session.unencoded_size = (FLAC__uint64)infilesize; + break; + default: + FLAC__ASSERT(0); + /* double protection */ + return EncoderSession_finish_error(&encoder_session); + } + + if(encoder_session.total_samples_to_encode == 0) { + encoder_session.unencoded_size = 0; + flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n"); + } + + if(options.format == FORMAT_FLAC || options.format == FORMAT_OGGFLAC) + encoder_session.fmt.flac.client_data.samples_left_to_process = encoder_session.total_samples_to_encode; + + stats_new_file(); + /* init the encoder */ + if(!EncoderSession_init_encoder(&encoder_session, options)) + return EncoderSession_finish_error(&encoder_session); + + /* skip over any samples as requested */ + if(skip > 0) { + switch(options.format) { + case FORMAT_RAW: + { + uint32_t skip_bytes = encoder_session.info.bytes_per_wide_sample * (uint32_t)skip; + if(skip_bytes > lookahead_length) { + skip_bytes -= lookahead_length; + lookahead_length = 0; + if(!fskip_ahead(encoder_session.fin, skip_bytes)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + } + else { + lookahead += skip_bytes; + lookahead_length -= skip_bytes; + } + } + break; + case FORMAT_WAVE: + case FORMAT_WAVE64: + case FORMAT_RF64: + case FORMAT_AIFF: + case FORMAT_AIFF_C: + if(!fskip_ahead(encoder_session.fin, skip * encoder_session.info.bytes_per_wide_sample)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + break; + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + /* + * have to wait until the FLAC encoder is set up for writing + * before any seeking in the input FLAC file, because the seek + * itself will usually call the decoder's write callback, and + * our decoder's write callback passes samples to our FLAC + * encoder + */ + if(!FLAC__stream_decoder_seek_absolute(encoder_session.fmt.flac.decoder, skip)) { + flac__utils_printf(stderr, 1, "%s: ERROR while skipping samples, FLAC decoder state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(encoder_session.fmt.flac.decoder)); + return EncoderSession_finish_error(&encoder_session); + } + break; + default: + FLAC__ASSERT(0); + /* double protection */ + return EncoderSession_finish_error(&encoder_session); + } + } + + /* + * now do samples from the file + */ + switch(options.format) { + case FORMAT_RAW: + if(infilesize < 0) { + size_t bytes_read; + while(!feof(infile)) { + if(lookahead_length > 0) { + FLAC__ASSERT(lookahead_length < CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample); + memcpy(ubuffer.u8, lookahead, lookahead_length); + bytes_read = fread(ubuffer.u8+lookahead_length, sizeof(uint8_t), CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample - lookahead_length, infile) + lookahead_length; + if(ferror(infile)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + lookahead_length = 0; + } + else + bytes_read = fread(ubuffer.u8, sizeof(uint8_t), CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample, infile); + + if(bytes_read == 0) { + if(ferror(infile)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + } + else if(bytes_read % encoder_session.info.bytes_per_wide_sample != 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + else { + uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample; + if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.shift, channel_map)) + return EncoderSession_finish_error(&encoder_session); + + if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) { + print_error_with_state(&encoder_session, "ERROR during encoding"); + return EncoderSession_finish_error(&encoder_session); + } + } + } + } + else { + size_t bytes_read; + const FLAC__uint64 max_input_bytes = infilesize; + FLAC__uint64 total_input_bytes_read = 0; + while(total_input_bytes_read < max_input_bytes) { + { + size_t wanted = (CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample); + wanted = (size_t) min((FLAC__uint64)wanted, max_input_bytes - total_input_bytes_read); + + if(lookahead_length > 0) { + if(lookahead_length <= wanted) { + memcpy(ubuffer.u8, lookahead, lookahead_length); + wanted -= lookahead_length; + bytes_read = lookahead_length; + } + else { + /* This happens when --until is used on a very short file */ + FLAC__ASSERT(lookahead_length < CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample); + memcpy(ubuffer.u8, lookahead, wanted); + wanted = 0; + bytes_read = wanted; + } + if(wanted > 0) { + bytes_read += fread(ubuffer.u8+lookahead_length, sizeof(uint8_t), wanted, infile); + if(ferror(infile)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + } + lookahead_length = 0; + } + else + bytes_read = fread(ubuffer.u8, sizeof(uint8_t), wanted, infile); + } + + if(bytes_read == 0) { + if(ferror(infile)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + else if(feof(infile)) { + flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %" PRIu64 " samples, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.total_samples_to_encode, encoder_session.samples_written); + if(encoder_session.treat_warnings_as_errors) + return EncoderSession_finish_error(&encoder_session); + total_input_bytes_read = max_input_bytes; + } + } + else { + if(bytes_read % encoder_session.info.bytes_per_wide_sample != 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + else { + uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample; + if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.shift, channel_map)) + return EncoderSession_finish_error(&encoder_session); + + if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) { + print_error_with_state(&encoder_session, "ERROR during encoding"); + return EncoderSession_finish_error(&encoder_session); + } + total_input_bytes_read += bytes_read; + } + } + } + } + break; + case FORMAT_WAVE: + case FORMAT_WAVE64: + case FORMAT_RF64: + case FORMAT_AIFF: + case FORMAT_AIFF_C: + while(encoder_session.fmt.iff.data_bytes > 0) { + const size_t bytes_to_read = + (size_t) min (sizeof (ubuffer.u8), + min (encoder_session.fmt.iff.data_bytes, + CHUNK_OF_SAMPLES * (uint64_t) encoder_session.info.bytes_per_wide_sample)); + size_t bytes_read = fread(ubuffer.u8, sizeof(uint8_t), bytes_to_read, infile); + if(bytes_read == 0) { + if(ferror(infile)) { + flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + else if(feof(infile)) { + if(options.ignore_chunk_sizes) { + flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.samples_written); + } + else { + flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %" PRIu64 " samples, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.total_samples_to_encode, encoder_session.samples_written); + if(encoder_session.treat_warnings_as_errors) + return EncoderSession_finish_error(&encoder_session); + } + encoder_session.fmt.iff.data_bytes = 0; + } + } + else { + if(bytes_read % encoder_session.info.bytes_per_wide_sample != 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + else { + uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample; + if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.shift, channel_map)) + return EncoderSession_finish_error(&encoder_session); + + if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) { + print_error_with_state(&encoder_session, "ERROR during encoding"); + return EncoderSession_finish_error(&encoder_session); + } + encoder_session.fmt.iff.data_bytes -= bytes_read; + } + } + } + break; + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + consecutive_eos_count = 0; + while(!encoder_session.fmt.flac.client_data.fatal_error && encoder_session.fmt.flac.client_data.samples_left_to_process > 0) { + FLAC__StreamDecoderState decoder_state; + /* We can also hit the end of stream without samples_left_to_process + * going to 0 if there are errors and continue_through_decode_errors + * is on, so we want to break in that case too: + */ + decoder_state = FLAC__stream_decoder_get_state(encoder_session.fmt.flac.decoder); + if(encoder_session.continue_through_decode_errors && decoder_state == FLAC__STREAM_DECODER_END_OF_STREAM) + break; + + consecutive_eos_count = decoder_state == FLAC__STREAM_DECODER_END_OF_STREAM ? consecutive_eos_count + 1 : 0; + + /* Exit loop if we get two or more consecutive FLAC__STREAM_DECODER_END_OF_STREAM events. */ + if(consecutive_eos_count >= 2) { + flac__utils_printf(stderr, 1, "%s: ERROR: %d consecutive FLAC__STREAM_DECODER_END_OF_STREAM events.\n", encoder_session.inbasefilename, consecutive_eos_count); + break; + } + + if(decoder_state == FLAC__STREAM_DECODER_ABORTED || !FLAC__stream_decoder_process_single(encoder_session.fmt.flac.decoder)) { + flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(encoder_session.fmt.flac.decoder)); + return EncoderSession_finish_error(&encoder_session); + } + } + if(encoder_session.fmt.flac.client_data.fatal_error) { + flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(encoder_session.fmt.flac.decoder)); + return EncoderSession_finish_error(&encoder_session); + } + break; + default: + FLAC__ASSERT(0); + /* double protection */ + return EncoderSession_finish_error(&encoder_session); + } + + } + + return EncoderSession_finish_ok( + &encoder_session, + EncoderSession_format_is_iff(&encoder_session)? options.format_options.iff.foreign_metadata : 0, + options.error_on_compression_fail + ); +} + +FLAC__bool EncoderSession_construct(EncoderSession *e, encode_options_t options, FLAC__off_t infilesize, FILE *infile, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length) +{ + uint32_t i; + FLAC__uint32 test = 1; + + /* + * initialize globals + */ + + is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true; + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) + input_[i] = &(in_[i][0]); + + + /* + * initialize instance + */ + +#if FLAC__HAS_OGG + e->use_ogg = options.use_ogg; +#endif + e->verify = options.verify; + e->treat_warnings_as_errors = options.treat_warnings_as_errors; + e->continue_through_decode_errors = options.continue_through_decode_errors; + + e->is_stdout = (0 == strcmp(outfilename, "-")); + e->outputfile_opened = false; + + e->inbasefilename = grabbag__file_get_basename(infilename); + e->infilename = infilename; + e->outfilename = outfilename; + + e->total_samples_to_encode = 0; + e->unencoded_size = 0; + e->bytes_written = 0; + e->samples_written = 0; +#if 0 /* in case time.h with clock() isn't available for some reason */ + e->stats_frames_interval = 0; + e->old_frames_written = 0; +#else + e->old_clock_t = 0; +#endif + e->compression_ratio = 0.0; + + memset(&e->info, 0, sizeof(e->info)); + + e->format = options.format; + + switch(options.format) { + case FORMAT_RAW: + break; + case FORMAT_WAVE: + case FORMAT_WAVE64: + case FORMAT_RF64: + case FORMAT_AIFF: + case FORMAT_AIFF_C: + e->fmt.iff.data_bytes = 0; + break; + case FORMAT_FLAC: + case FORMAT_OGGFLAC: + e->fmt.flac.decoder = 0; + e->fmt.flac.client_data.filesize = infilesize; + e->fmt.flac.client_data.lookahead = lookahead; + e->fmt.flac.client_data.lookahead_length = lookahead_length; + e->fmt.flac.client_data.num_metadata_blocks = 0; + e->fmt.flac.client_data.samples_left_to_process = 0; + e->fmt.flac.client_data.fatal_error = false; + break; + default: +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + FLAC__ASSERT(0); +#endif + /* double protection */ + return false; + } + + e->encoder = 0; + + e->fin = infile; + e->seek_table_template = 0; + + if(0 == (e->seek_table_template = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE))) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for seek table\n", e->inbasefilename); + return false; + } + + e->encoder = FLAC__stream_encoder_new(); + if(0 == e->encoder) { + flac__utils_printf(stderr, 1, "%s: ERROR creating the encoder instance\n", e->inbasefilename); + EncoderSession_destroy(e); + return false; + } + + return true; +} + +void EncoderSession_destroy(EncoderSession *e) +{ + if(e->format == FORMAT_FLAC || e->format == FORMAT_OGGFLAC) { + size_t i; + if(e->fmt.flac.decoder) + FLAC__stream_decoder_delete(e->fmt.flac.decoder); + e->fmt.flac.decoder = 0; + for(i = 0; i < e->fmt.flac.client_data.num_metadata_blocks; i++) + FLAC__metadata_object_delete(e->fmt.flac.client_data.metadata_blocks[i]); + e->fmt.flac.client_data.num_metadata_blocks = 0; + } + + if(e->fin != stdin) + fclose(e->fin); + + if(0 != e->encoder) { + FLAC__stream_encoder_delete(e->encoder); + e->encoder = 0; + } + + if(0 != e->seek_table_template) { + FLAC__metadata_object_delete(e->seek_table_template); + e->seek_table_template = 0; + } +} + +int EncoderSession_finish_ok(EncoderSession *e, foreign_metadata_t *foreign_metadata, FLAC__bool error_on_compression_fail) +{ + FLAC__StreamEncoderState fse_state = FLAC__STREAM_ENCODER_OK; + int ret = 0; + FLAC__bool verify_error = false; + + if(e->encoder) { + fse_state = FLAC__stream_encoder_get_state(e->encoder); + ret = FLAC__stream_encoder_finish(e->encoder)? 0 : 1; + verify_error = + fse_state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA || + FLAC__stream_encoder_get_state(e->encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA + ; + } + /* all errors except verify errors should interrupt the stats */ + if(ret && !verify_error) + print_error_with_state(e, "ERROR during encoding"); + else if(e->total_samples_to_encode > 0) { + print_stats(e); + flac__utils_printf(stderr, 2, "\n"); + } + + if(verify_error) { + print_verify_error(e); + ret = 1; + } + + /*@@@@@@ should this go here or somewhere else? */ + if(ret == 0 && foreign_metadata) { + const char *error; + if(!flac__foreign_metadata_write_to_flac(foreign_metadata, e->infilename, e->outfilename, &error)) { + flac__utils_printf(stderr, 1, "%s: ERROR: updating foreign metadata in FLAC file: %s\n", e->inbasefilename, error); + ret = 1; + } + } + + if (e->compression_ratio >= 1.0 && error_on_compression_fail) { + flac__utils_printf(stderr, 1, + "FAILURE: Compression failed (ratio %0.3f, should be < 1.0).\n" + "This happens for some files for one or more of the following reasons:\n" + " * Recompressing an existing FLAC from a higher to a lower compression setting.\n" + " * Insufficient input data (e.g. very short files, < 10000 frames).\n" + " * The audio data is not compressible (e.g. a full range white noise signal).\n" + , e->compression_ratio); + ret = 1; + } + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Always delete output file when fuzzing */ + flac_unlink(e->outfilename); +#endif + + EncoderSession_destroy(e); + + return ret; +} + +int EncoderSession_finish_error(EncoderSession *e) +{ + FLAC__ASSERT(e->encoder); + + if(e->total_samples_to_encode > 0) + flac__utils_printf(stderr, 2, "\n"); + + if(FLAC__stream_encoder_get_state(e->encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) { + print_verify_error(e); + EncoderSession_destroy(e); + } + else if(e->outputfile_opened) { + /* only want to delete the file if we opened it; otherwise it could be an existing file and our overwrite failed */ + /* Windows cannot unlink an open file, so close it first */ + EncoderSession_destroy(e); + flac_unlink(e->outfilename); + } + else + EncoderSession_destroy(e); + + return 1; +} + +typedef struct { + uint32_t num_metadata; + FLAC__bool *needs_delete; + FLAC__StreamMetadata **metadata; + FLAC__StreamMetadata *cuesheet; /* always needs to be deleted */ +} static_metadata_t; + +static void static_metadata_init(static_metadata_t *m) +{ + m->num_metadata = 0; + m->needs_delete = 0; + m->metadata = 0; + m->cuesheet = 0; +} + +static void static_metadata_clear(static_metadata_t *m) +{ + uint32_t i; + for(i = 0; i < m->num_metadata; i++) + if(m->needs_delete[i]) + FLAC__metadata_object_delete(m->metadata[i]); + if(m->metadata) + free(m->metadata); + if(m->needs_delete) + free(m->needs_delete); + if(m->cuesheet) + FLAC__metadata_object_delete(m->cuesheet); + static_metadata_init(m); +} + +static FLAC__bool static_metadata_append(static_metadata_t *m, FLAC__StreamMetadata *d, FLAC__bool needs_delete) +{ + void *x; + if(0 == (x = safe_realloc_nofree_muladd2_(m->metadata, sizeof(*m->metadata), /*times (*/m->num_metadata, /*+*/1/*)*/))) + return false; + m->metadata = (FLAC__StreamMetadata**)x; + if(0 == (x = safe_realloc_nofree_muladd2_(m->needs_delete, sizeof(*m->needs_delete), /*times (*/m->num_metadata, /*+*/1/*)*/))) + return false; + m->needs_delete = (FLAC__bool*)x; + m->metadata[m->num_metadata] = d; + m->needs_delete[m->num_metadata] = needs_delete; + m->num_metadata++; + return true; +} + +FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options) +{ + const uint32_t channels = e->info.channels; + const uint32_t bps = e->info.bits_per_sample - e->info.shift; + const uint32_t sample_rate = e->info.sample_rate; + FLACDecoderData *flac_decoder_data = (e->format == FORMAT_FLAC || e->format == FORMAT_OGGFLAC)? &e->fmt.flac.client_data : 0; + FLAC__StreamMetadata padding; + FLAC__StreamMetadata **metadata = 0; + static_metadata_t static_metadata; + uint32_t num_metadata = 0, ic; + FLAC__StreamEncoderInitStatus init_status; + const FLAC__bool is_cdda = (channels == 1 || channels == 2) && (bps == 16) && (sample_rate == 44100); + char apodizations[2000]; + + FLAC__ASSERT(sizeof(options.pictures)/sizeof(options.pictures[0]) <= 64); + + static_metadata_init(&static_metadata); + + e->replay_gain = options.replay_gain; + + apodizations[0] = '\0'; + + if(e->replay_gain) { + if(channels != 1 && channels != 2) { + flac__utils_printf(stderr, 1, "%s: ERROR, number of channels (%u) must be 1 or 2 for --replay-gain\n", e->inbasefilename, channels); + return false; + } + if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) { + flac__utils_printf(stderr, 1, "%s: ERROR, invalid sample rate (%u) for --replay-gain\n", e->inbasefilename, sample_rate); + return false; + } + if(options.is_first_file) { + if(!grabbag__replaygain_init(sample_rate)) { + flac__utils_printf(stderr, 1, "%s: ERROR initializing ReplayGain stage\n", e->inbasefilename); + return false; + } + } + } + + if(!parse_cuesheet(&static_metadata.cuesheet, options.cuesheet_filename, e->inbasefilename, sample_rate, is_cdda, e->total_samples_to_encode, e->treat_warnings_as_errors)) + return false; + + if(!convert_to_seek_table_template(options.requested_seek_points, options.num_requested_seek_points, options.cued_seekpoints? static_metadata.cuesheet : 0, e)) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for seek table\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + + /* build metadata */ + if(flac_decoder_data) { + /* + * we're encoding from FLAC so we will use the FLAC file's + * metadata as the basis for the encoded file + */ + { + uint32_t i; + /* + * first handle pictures: simple append any --pictures + * specified. + */ + for(i = 0; i < options.num_pictures; i++) { + FLAC__StreamMetadata *pic = FLAC__metadata_object_clone(options.pictures[i]); + if(0 == pic) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for PICTURE block\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks++] = pic; + } + } + { + /* + * next handle vorbis comment: if any tags were specified + * or there is no existing vorbis comment, we create a + * new vorbis comment (discarding any existing one); else + * we keep the existing one. also need to make sure to + * propagate any channel mask tag. + */ + /* @@@ change to append -T values from options.vorbis_comment if input has VC already? */ + size_t i, j; + FLAC__bool vc_found = false; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + vc_found = true; + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && options.vorbis_comment->data.vorbis_comment.num_comments > 0) { + (void) flac__utils_get_channel_mask_tag(flac_decoder_data->metadata_blocks[i], &e->info.channel_mask); + flac__utils_printf(stderr, 1, "%s: WARNING, replacing tags from input FLAC file with those given on the command-line\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if((!vc_found || options.vorbis_comment->data.vorbis_comment.num_comments > 0) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + /* prepend ours */ + FLAC__StreamMetadata *vc = FLAC__metadata_object_clone(options.vorbis_comment); + if(0 == vc || (e->info.channel_mask && !flac__utils_set_channel_mask_tag(vc, e->info.channel_mask))) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for VORBIS_COMMENT block\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--) + flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1]; + flac_decoder_data->metadata_blocks[1] = vc; + flac_decoder_data->num_metadata_blocks++; + } + } + { + /* + * next handle cuesheet: if --cuesheet was specified, use + * it; else if file has existing CUESHEET and cuesheet's + * lead-out offset is correct, keep it; else no CUESHEET + */ + size_t i, j; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + FLAC__bool existing_cuesheet_is_bad = false; + /* check if existing cuesheet matches the input audio */ + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && 0 == static_metadata.cuesheet) { + const FLAC__StreamMetadata_CueSheet *cs = &flac_decoder_data->metadata_blocks[i]->data.cue_sheet; + if(e->total_samples_to_encode == 0) { + flac__utils_printf(stderr, 1, "%s: WARNING, cuesheet in input FLAC file cannot be kept if input size is not known, dropping it...\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + existing_cuesheet_is_bad = true; + } + else if(cs->num_tracks > 0 && e->total_samples_to_encode != cs->tracks[cs->num_tracks-1].offset) { + flac__utils_printf(stderr, 1, "%s: WARNING, lead-out offset of cuesheet in input FLAC file does not match input length, dropping existing cuesheet...\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + existing_cuesheet_is_bad = true; + } + } + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && (existing_cuesheet_is_bad || 0 != static_metadata.cuesheet)) { + if(0 != static_metadata.cuesheet) { + flac__utils_printf(stderr, 1, "%s: WARNING, replacing cuesheet in input FLAC file with the one given on the command-line\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + } + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if(0 != static_metadata.cuesheet && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + /* prepend ours */ + FLAC__StreamMetadata *cs = FLAC__metadata_object_clone(static_metadata.cuesheet); + if(0 == cs) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for CUESHEET block\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--) + flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1]; + flac_decoder_data->metadata_blocks[1] = cs; + flac_decoder_data->num_metadata_blocks++; + } + } + { + /* + * next handle seektable: if -S- was specified, no + * SEEKTABLE; else if -S was specified, use it/them; + * else if file has existing SEEKTABLE and input size is + * preserved (no --skip/--until/etc specified), keep it; + * else use default seektable options + * + * note: meanings of num_requested_seek_points: + * -1 : no -S option given, default to some value + * 0 : -S- given (no seektable) + * >0 : one or more -S options given + */ + size_t i, j; + FLAC__bool existing_seektable = false; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) + existing_seektable = true; + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE && (e->total_samples_to_encode != flac_decoder_data->metadata_blocks[0]->data.stream_info.total_samples || options.num_requested_seek_points >= 0)) { + if(options.num_requested_seek_points > 0) { + flac__utils_printf(stderr, 1, "%s: WARNING, replacing seektable in input FLAC file with the one given on the command-line\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + } + else if(options.num_requested_seek_points == 0) + ; /* no warning, silently delete existing SEEKTABLE since user specified --no-seektable (-S-) */ + else { + flac__utils_printf(stderr, 1, "%s: WARNING, can't use existing seektable in input FLAC since the input size is changing or unknown, dropping existing SEEKTABLE block...\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + } + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + existing_seektable = false; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if((options.num_requested_seek_points > 0 || (options.num_requested_seek_points < 0 && !existing_seektable)) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + /* prepend ours */ + FLAC__StreamMetadata *st = FLAC__metadata_object_clone(e->seek_table_template); + if(0 == st) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for SEEKTABLE block\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--) + flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1]; + flac_decoder_data->metadata_blocks[1] = st; + flac_decoder_data->num_metadata_blocks++; + } + } + { + /* + * finally handle padding: if --no-padding was specified, + * then delete all padding; else if -P was specified, + * use that instead of existing padding (if any); else + * if existing file has padding, move all existing + * padding blocks to one padding block at the end; else + * use default padding. + */ + int p = -1; + size_t i, j; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_PADDING) { + if(p < 0) + p = 0; + p += flac_decoder_data->metadata_blocks[i]->length; + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if(options.padding > 0) + p = options.padding; + if(p < 0) { + if(sample_rate == 0) + p = FLAC_ENCODE__DEFAULT_PADDING; + else + p = e->total_samples_to_encode / sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8; + } + if(p > 0) + p += (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0); + p = min(p, (int)((1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1)); + if(options.padding != 0) { + if(p > 0 && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); + if(0 == flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for PADDING block\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->is_last = false; /* the encoder will set this for us */ + flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->length = p; + flac_decoder_data->num_metadata_blocks++; + } + } + } + metadata = &flac_decoder_data->metadata_blocks[1]; /* don't include STREAMINFO */ + num_metadata = flac_decoder_data->num_metadata_blocks - 1; + } + else { + /* + * we're not encoding from FLAC so we will build the metadata + * from scratch + */ + const foreign_metadata_t *foreign_metadata = EncoderSession_format_is_iff(e)? options.format_options.iff.foreign_metadata : 0; + uint32_t i; + + if(e->seek_table_template->data.seek_table.num_points > 0) { + e->seek_table_template->is_last = false; /* the encoder will set this for us */ + static_metadata_append(&static_metadata, e->seek_table_template, /*needs_delete=*/false); + } + if(0 != static_metadata.cuesheet) + static_metadata_append(&static_metadata, static_metadata.cuesheet, /*needs_delete=*/false); + if(e->info.channel_mask) { + options.vorbis_comment_with_channel_mask_tag = FLAC__metadata_object_clone(options.vorbis_comment); + if(!flac__utils_set_channel_mask_tag(options.vorbis_comment_with_channel_mask_tag, e->info.channel_mask)) { + flac__utils_printf(stderr, 1, "%s: ERROR adding channel mask tag\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + static_metadata_append(&static_metadata, options.vorbis_comment_with_channel_mask_tag, /*needs_delete=*/true); + } + else + static_metadata_append(&static_metadata, options.vorbis_comment, /*needs_delete=*/false); + for(i = 0; i < options.num_pictures; i++) + static_metadata_append(&static_metadata, options.pictures[i], /*needs_delete=*/false); + if(foreign_metadata) { + for(i = 0; i < foreign_metadata->num_blocks; i++) { + FLAC__StreamMetadata *p = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); + if(!p) { + flac__utils_printf(stderr, 1, "%s: ERROR: out of memory\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + static_metadata_append(&static_metadata, p, /*needs_delete=*/true); + static_metadata.metadata[static_metadata.num_metadata-1]->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8 + foreign_metadata->blocks[i].size; + } + } + if(options.padding != 0) { + padding.is_last = false; /* the encoder will set this for us */ + padding.type = FLAC__METADATA_TYPE_PADDING; + if(sample_rate == 0) + padding.length = (uint32_t)(options.padding>0? options.padding : FLAC_ENCODE__DEFAULT_PADDING) + (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0); + else + padding.length = (uint32_t)(options.padding>0? options.padding : (e->total_samples_to_encode / sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8)) + (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0); + padding.length = min(padding.length, (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1); + static_metadata_append(&static_metadata, &padding, /*needs_delete=*/false); + } + metadata = static_metadata.metadata; + num_metadata = static_metadata.num_metadata; + } + + /* check for a few things that have not already been checked. the + * FLAC__stream_encoder_init*() will check it but only return + * FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA so we check some + * up front to give a better error message. + */ + if(!verify_metadata(e, metadata, num_metadata)) { + static_metadata_clear(&static_metadata); + return false; + } + + FLAC__stream_encoder_set_verify(e->encoder, options.verify); + FLAC__stream_encoder_set_streamable_subset(e->encoder, !options.lax); + FLAC__stream_encoder_set_channels(e->encoder, channels); + FLAC__stream_encoder_set_bits_per_sample(e->encoder, bps); + FLAC__stream_encoder_set_sample_rate(e->encoder, sample_rate); + for(ic = 0; ic < options.num_compression_settings; ic++) { + switch(options.compression_settings[ic].type) { + case CST_BLOCKSIZE: + FLAC__stream_encoder_set_blocksize(e->encoder, options.compression_settings[ic].value.t_unsigned); + break; + case CST_COMPRESSION_LEVEL: + FLAC__stream_encoder_set_compression_level(e->encoder, options.compression_settings[ic].value.t_unsigned); + apodizations[0] = '\0'; + break; + case CST_DO_MID_SIDE: + FLAC__stream_encoder_set_do_mid_side_stereo(e->encoder, options.compression_settings[ic].value.t_bool); + break; + case CST_LOOSE_MID_SIDE: + FLAC__stream_encoder_set_loose_mid_side_stereo(e->encoder, options.compression_settings[ic].value.t_bool); + break; + case CST_APODIZATION: + if(strlen(apodizations)+strlen(options.compression_settings[ic].value.t_string)+2 >= sizeof(apodizations)) { + flac__utils_printf(stderr, 1, "%s: ERROR: too many apodization functions requested\n", e->inbasefilename); + static_metadata_clear(&static_metadata); + return false; + } + else { + safe_strncat(apodizations, options.compression_settings[ic].value.t_string, sizeof(apodizations)); + safe_strncat(apodizations, ";", sizeof(apodizations)); + } + break; + case CST_MAX_LPC_ORDER: +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + FLAC__stream_encoder_set_max_lpc_order(e->encoder, options.compression_settings[ic].value.t_unsigned); +#endif + break; + case CST_QLP_COEFF_PRECISION: + FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder, options.compression_settings[ic].value.t_unsigned); + break; + case CST_DO_QLP_COEFF_PREC_SEARCH: +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder, options.compression_settings[ic].value.t_bool); +#endif + break; + case CST_DO_ESCAPE_CODING: + FLAC__stream_encoder_set_do_escape_coding(e->encoder, options.compression_settings[ic].value.t_bool); + break; + case CST_DO_EXHAUSTIVE_MODEL_SEARCH: +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + FLAC__stream_encoder_set_do_exhaustive_model_search(e->encoder, options.compression_settings[ic].value.t_bool); +#endif + break; + case CST_MIN_RESIDUAL_PARTITION_ORDER: + FLAC__stream_encoder_set_min_residual_partition_order(e->encoder, options.compression_settings[ic].value.t_unsigned); + break; + case CST_MAX_RESIDUAL_PARTITION_ORDER: + FLAC__stream_encoder_set_max_residual_partition_order(e->encoder, options.compression_settings[ic].value.t_unsigned); + break; + case CST_RICE_PARAMETER_SEARCH_DIST: + FLAC__stream_encoder_set_rice_parameter_search_dist(e->encoder, options.compression_settings[ic].value.t_unsigned); + break; + } + } +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if(*apodizations) + FLAC__stream_encoder_set_apodization(e->encoder, apodizations); +#endif + FLAC__stream_encoder_set_total_samples_estimate(e->encoder, e->total_samples_to_encode); + FLAC__stream_encoder_set_metadata(e->encoder, (num_metadata > 0)? metadata : 0, num_metadata); + FLAC__stream_encoder_set_limit_min_bitrate(e->encoder, options.limit_min_bitrate); + + FLAC__stream_encoder_disable_constant_subframes(e->encoder, options.debug.disable_constant_subframes); + FLAC__stream_encoder_disable_fixed_subframes(e->encoder, options.debug.disable_fixed_subframes); + FLAC__stream_encoder_disable_verbatim_subframes(e->encoder, options.debug.disable_verbatim_subframes); + if(!options.debug.do_md5) { + flac__utils_printf(stderr, 1, "%s: WARNING, MD5 computation disabled, resulting file will not have MD5 sum\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + FLAC__stream_encoder_set_do_md5(e->encoder, false); + } + else if(e->is_stdout) { + flac__utils_printf(stderr, 1, "%s: WARNING, cannot write back MD5 sum when encoding to stdout\n", e->inbasefilename); + if(e->treat_warnings_as_errors) { + static_metadata_clear(&static_metadata); + return false; + } + } + +#if FLAC__HAS_OGG + if(e->use_ogg) { + FLAC__stream_encoder_set_ogg_serial_number(e->encoder, options.serial_number); + + init_status = FLAC__stream_encoder_init_ogg_file(e->encoder, e->is_stdout? 0 : e->outfilename, encoder_progress_callback, /*client_data=*/e); + } + else +#endif + { + init_status = FLAC__stream_encoder_init_file(e->encoder, e->is_stdout? 0 : e->outfilename, encoder_progress_callback, /*client_data=*/e); + } + + if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + print_error_with_init_status(e, "ERROR initializing encoder", init_status); + if(FLAC__stream_encoder_get_state(e->encoder) != FLAC__STREAM_ENCODER_IO_ERROR) + e->outputfile_opened = true; + static_metadata_clear(&static_metadata); + return false; + } + else + e->outputfile_opened = true; + +#if 0 /* in case time.h with clock() isn't available for some reason */ + e->stats_frames_interval = + (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) && FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x1f : + (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) || FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x3f : + 0xff; +#endif + + static_metadata_clear(&static_metadata); + + return true; +} + +FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], uint32_t samples) +{ + if(e->replay_gain) { + if(!grabbag__replaygain_analyze(buffer, e->info.channels==2, e->info.bits_per_sample, samples)) { + flac__utils_printf(stderr, 1, "%s: WARNING, error while calculating ReplayGain\n", e->inbasefilename); + if(e->treat_warnings_as_errors) + return false; + } + } + + return FLAC__stream_encoder_process(e->encoder, buffer, samples); +} + +FLAC__bool EncoderSession_format_is_iff(const EncoderSession *e) +{ + return + e->format == FORMAT_WAVE || + e->format == FORMAT_WAVE64 || + e->format == FORMAT_RF64 || + e->format == FORMAT_AIFF || + e->format == FORMAT_AIFF_C; +} + +FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e) +{ + const FLAC__bool only_placeholders = e->is_stdout; + FLAC__bool has_real_points; + + if(num_requested_seek_points == 0 && 0 == cuesheet) + return true; + +#if FLAC__HAS_OGG + if(e->use_ogg) + return true; +#endif + + if(num_requested_seek_points < 0) { + requested_seek_points = "10s;"; + num_requested_seek_points = 1; + } + + if(num_requested_seek_points > 0) { + if(!grabbag__seektable_convert_specification_to_template(requested_seek_points, only_placeholders, e->total_samples_to_encode, e->info.sample_rate, e->seek_table_template, &has_real_points)) + return false; + } + + if(0 != cuesheet) { + uint32_t i, j; + const FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet; + for(i = 0; i < cs->num_tracks; i++) { + const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+i; + for(j = 0; j < tr->num_indices; j++) { + if(!FLAC__metadata_object_seektable_template_append_point(e->seek_table_template, tr->offset + tr->indices[j].offset)) + return false; + has_real_points = true; + } + } + if(has_real_points) + if(!FLAC__metadata_object_seektable_template_sort(e->seek_table_template, /*compact=*/true)) + return false; + } + + if(has_real_points) { + if(e->is_stdout) { + flac__utils_printf(stderr, 1, "%s: WARNING, cannot write back seekpoints when encoding to stdout\n", e->inbasefilename); + if(e->treat_warnings_as_errors) + return false; + } + } + + return true; +} + +FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input) +{ + /* convert from mm:ss.sss to sample number if necessary */ + if(!flac__utils_canonicalize_skip_until_specification(spec, sample_rate)) { + flac__utils_printf(stderr, 1, "%s: ERROR, value of --until is too large\n", inbasefilename); + return false; + } + + /* special case: if "--until=-0", use the special value '0' to mean "end-of-stream" */ + if(spec->is_relative && spec->value.samples == 0) { + spec->is_relative = false; + return true; + } + + /* in any other case the total samples in the input must be known */ + if(total_samples_in_input == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR, cannot use --until when input length is unknown\n", inbasefilename); + return false; + } + + FLAC__ASSERT(spec->value_is_samples); + + /* convert relative specifications to absolute */ + if(spec->is_relative) { + if(spec->value.samples <= 0) + spec->value.samples += (FLAC__int64)total_samples_in_input; + else + spec->value.samples += skip; + spec->is_relative = false; + } + + /* error check */ + if(spec->value.samples < 0) { + flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before beginning of input\n", inbasefilename); + return false; + } + if((FLAC__uint64)spec->value.samples <= skip) { + flac__utils_printf(stderr, 1, "%s: ERROR, --until value is before --skip point\n", inbasefilename); + return false; + } + if((FLAC__uint64)spec->value.samples > total_samples_in_input) { + flac__utils_printf(stderr, 1, "%s: ERROR, --until value is after end of input\n", inbasefilename); + return false; + } + + return true; +} + +FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, uint32_t num_metadata) +{ + FLAC__bool metadata_picture_has_type1 = false; + FLAC__bool metadata_picture_has_type2 = false; + uint32_t i; + + FLAC__ASSERT(0 != metadata); + for(i = 0; i < num_metadata; i++) { + const FLAC__StreamMetadata *m = metadata[i]; + if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) { + if(!FLAC__format_seektable_is_legal(&m->data.seek_table)) { + flac__utils_printf(stderr, 1, "%s: ERROR: SEEKTABLE metadata block is invalid\n", e->inbasefilename); + return false; + } + } + else if(m->type == FLAC__METADATA_TYPE_CUESHEET) { + if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0)) { + flac__utils_printf(stderr, 1, "%s: ERROR: CUESHEET metadata block is invalid\n", e->inbasefilename); + return false; + } + } + else if(m->type == FLAC__METADATA_TYPE_PICTURE) { + const char *error = 0; + if(!FLAC__format_picture_is_legal(&m->data.picture, &error)) { + flac__utils_printf(stderr, 1, "%s: ERROR: PICTURE metadata block is invalid: %s\n", e->inbasefilename, error); + return false; + } + if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) { + if(metadata_picture_has_type1) { + flac__utils_printf(stderr, 1, "%s: ERROR: there may only be one picture of type 1 (32x32 icon) in the file\n", e->inbasefilename); + return false; + } + metadata_picture_has_type1 = true; + } + else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) { + if(metadata_picture_has_type2) { + flac__utils_printf(stderr, 1, "%s: ERROR: there may only be one picture of type 2 (icon) in the file\n", e->inbasefilename); + return false; + } + metadata_picture_has_type2 = true; + } + } + } + + return true; +} + +FLAC__bool format_input(FLAC__int32 *dest[], uint32_t wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, uint32_t channels, uint32_t bps, uint32_t shift, size_t *channel_map) +{ + uint32_t wide_sample, sample, channel; + FLAC__int32 *out[FLAC__MAX_CHANNELS]; + + if(0 == channel_map) { + for(channel = 0; channel < channels; channel++) + out[channel] = dest[channel]; + } + else { + for(channel = 0; channel < channels; channel++) + out[channel] = dest[channel_map[channel]]; + } + + if(bps == 8) { + if(is_unsigned_samples) { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = (FLAC__int32)ubuffer.u8[sample] - 0x80; + } + else { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = (FLAC__int32)ubuffer.s8[sample]; + } + } + else if(bps == 16) { + if(is_unsigned_samples) { + if(is_big_endian != is_big_endian_host_) { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = (FLAC__int32)(ENDSWAP_16(ubuffer.u16[sample])) - 0x8000; + } + else { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = (FLAC__int32)ubuffer.u16[sample] - 0x8000; + } + } + else { + if(is_big_endian != is_big_endian_host_) { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = (int16_t)(ENDSWAP_16(ubuffer.s16[sample])); + + } + else { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = ubuffer.s16[sample]; + } + } + } + else if(bps == 24) { + if(!is_big_endian) { + if(is_unsigned_samples) { + for(channel = 0; channel < channels; channel++) { + uint32_t b = 3*channel; + for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + uint32_t t; + t = ubuffer.u8[b]; + t |= (uint32_t)(ubuffer.u8[b+1]) << 8; + t |= (uint32_t)(ubuffer.u8[b+2]) << 16; + out[channel][wide_sample] = (FLAC__int32)t - 0x800000; + b += 3*channels; + } + } + } + else { + for(channel = 0; channel < channels; channel++) { + uint32_t b = 3*channel; + for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + uint32_t t; + t = ubuffer.u8[b]; + t |= (uint32_t)(ubuffer.u8[b+1]) << 8; + t |= (uint32_t)((int32_t)(ubuffer.s8[b+2])) << 16; + out[channel][wide_sample] = t; + b += 3*channels; + } + } + } + } + else { + if(is_unsigned_samples) { + for(channel = 0; channel < channels; channel++) { + uint32_t b = 3*channel; + for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + uint32_t t; + t = ubuffer.u8[b]; t <<= 8; + t |= ubuffer.u8[b+1]; t <<= 8; + t |= ubuffer.u8[b+2]; + out[channel][wide_sample] = (FLAC__int32)t - 0x800000; + b += 3*channels; + } + } + } + else { + for(channel = 0; channel < channels; channel++) { + uint32_t b = 3*channel; + for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + uint32_t t; + t = ubuffer.s8[b]; t <<= 8; + t |= ubuffer.u8[b+1]; t <<= 8; + t |= ubuffer.u8[b+2]; + out[channel][wide_sample] = t; + b += 3*channels; + } + } + } + } + } + else if(bps == 32) { + if(is_unsigned_samples) { + if(is_big_endian != is_big_endian_host_) { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = ENDSWAP_32(ubuffer.u32[sample]) - 0x80000000; + } + else { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = ubuffer.u32[sample] - 0x80000000; + } + } + else { + if(is_big_endian != is_big_endian_host_) { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = ENDSWAP_32(ubuffer.s32[sample]); + } + else { + for(channel = 0; channel < channels; channel++) + for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels) + out[channel][wide_sample] = ubuffer.s32[sample]; + } + } + } + else { + flac__utils_printf(stderr, 1, "ERROR: unsupported input format\n"); + return false; + } + if(shift > 0) { + FLAC__int32 mask = (1<>= shift; + } + } + return true; +} + +void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data) +{ + EncoderSession *e = (EncoderSession*)client_data; + + const FLAC__uint64 uesize = e->unencoded_size; + + (void)encoder, (void)total_frames_estimate, (void) frames_written; + + e->bytes_written = bytes_written; + e->samples_written = samples_written; + + e->progress = e->total_samples_to_encode ? (double)samples_written / (double)e->total_samples_to_encode : 0; + e->compression_ratio = (e->progress && uesize) ? (double)e->bytes_written / ((double)uesize * min(1.0, e->progress)) : 0; + +#if 0 /* in case time.h with clock() isn't available for some reason */ + if(e->total_samples_to_encode > 0 && frames_written - e->old_frames_written > e->stats_frames_interval) { + print_stats(e); + e->old_frames_written = frames_written; + } +#else + if(e->total_samples_to_encode > 0 && (clock() - e->old_clock_t) > (CLOCKS_PER_SEC/4)) { + print_stats(e); + e->old_clock_t = clock(); + } + +#endif +} + +FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + size_t n = 0; + EncoderSession *e = (EncoderSession*)client_data; + FLACDecoderData *data = &e->fmt.flac.client_data; + + (void)decoder; + + if (data->fatal_error) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + + /* use up lookahead first */ + if (data->lookahead_length) { + n = min(data->lookahead_length, *bytes); + memcpy(buffer, data->lookahead, n); + buffer += n; + data->lookahead += n; + data->lookahead_length -= n; + } + + /* get the rest from file */ + if (*bytes > n) { + *bytes = n + fread(buffer, 1, *bytes-n, e->fin); + if(ferror(e->fin)) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + else if(0 == *bytes) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} + +FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + EncoderSession *e = (EncoderSession*)client_data; + (void)decoder; + + if(fseeko(e->fin, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +FLAC__StreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + EncoderSession *e = (EncoderSession*)client_data; + FLAC__off_t pos; + (void)decoder; + + if((pos = ftello(e->fin)) < 0) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } +} + +FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + const EncoderSession *e = (EncoderSession*)client_data; + const FLACDecoderData *data = &e->fmt.flac.client_data; + (void)decoder; + + if(data->filesize < 0) + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + else { + *stream_length = (FLAC__uint64)data->filesize; + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } +} + +FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data) +{ + EncoderSession *e = (EncoderSession*)client_data; + (void)decoder; + + return feof(e->fin)? true : false; +} + +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + EncoderSession *e = (EncoderSession*)client_data; + FLACDecoderData *data = &e->fmt.flac.client_data; + FLAC__uint64 n = min(data->samples_left_to_process, frame->header.blocksize); + (void)decoder; + + /* Do some checks */ + if(frame->header.channels != e->info.channels) { + print_error_with_state(e, "ERROR: number of channels of input changed mid-stream"); + data->fatal_error = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + if(frame->header.bits_per_sample > e->info.bits_per_sample) { + print_error_with_state(e, "ERROR: bits-per-sample of input changed mid-stream"); + data->fatal_error = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + if(!EncoderSession_process(e, buffer, (uint32_t)n)) { + print_error_with_state(e, "ERROR during encoding"); + data->fatal_error = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + data->samples_left_to_process -= n; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + EncoderSession *e = (EncoderSession*)client_data; + FLACDecoderData *data = &e->fmt.flac.client_data; + (void)decoder; + + if (data->fatal_error) + return; + + if ( + data->num_metadata_blocks == sizeof(data->metadata_blocks)/sizeof(data->metadata_blocks[0]) || + 0 == (data->metadata_blocks[data->num_metadata_blocks] = FLAC__metadata_object_clone(metadata)) + ) + data->fatal_error = true; + else + data->num_metadata_blocks++; +} + +void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + EncoderSession *e = (EncoderSession*)client_data; + FLACDecoderData *data = &e->fmt.flac.client_data; + (void)decoder; + + stats_print_name(1, e->inbasefilename); + flac__utils_printf(stderr, 1, "ERROR got %s while decoding FLAC input\n", FLAC__StreamDecoderErrorStatusString[status]); + if(!e->continue_through_decode_errors) + data->fatal_error = true; +} + +FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors) +{ + FILE *f; + uint32_t last_line_read; + const char *error_message; + + if(0 == cuesheet_filename) + return true; + + if(lead_out_offset == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR cannot import cuesheet when the number of input samples to encode is unknown\n", inbasefilename); + return false; + } + + if(0 == (f = flac_fopen(cuesheet_filename, "r"))) { + flac__utils_printf(stderr, 1, "%s: ERROR opening cuesheet \"%s\" for reading: %s\n", inbasefilename, cuesheet_filename, strerror(errno)); + return false; + } + + *cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset); + + fclose(f); + + if(0 == *cuesheet) { + flac__utils_printf(stderr, 1, "%s: ERROR parsing cuesheet \"%s\" on line %u: %s\n", inbasefilename, cuesheet_filename, last_line_read, error_message); + return false; + } + + if(!FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/false, &error_message)) { + flac__utils_printf(stderr, 1, "%s: ERROR parsing cuesheet \"%s\": %s\n", inbasefilename, cuesheet_filename, error_message); + return false; + } + + /* if we're expecting CDDA, warn about non-compliance */ + if(is_cdda && !FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/true, &error_message)) { + flac__utils_printf(stderr, 1, "%s: WARNING cuesheet \"%s\" is not audio CD compliant: %s\n", inbasefilename, cuesheet_filename, error_message); + if(treat_warnings_as_errors) + return false; + (*cuesheet)->data.cue_sheet.is_cd = false; + } + + return true; +} + +static void print_stats(const EncoderSession *encoder_session) +{ + if(flac__utils_verbosity_ >= 2) { + char ratiostr[16]; + + FLAC__ASSERT(encoder_session->total_samples_to_encode > 0); + + if (encoder_session->compression_ratio > 0.0) + flac_snprintf(ratiostr, sizeof(ratiostr), "%0.3f", encoder_session->compression_ratio); + else + flac_snprintf(ratiostr, sizeof(ratiostr), "N/A"); + + if(encoder_session->samples_written == encoder_session->total_samples_to_encode) { + stats_print_name(2, encoder_session->inbasefilename); + stats_print_info(2, "%swrote %" PRIu64 " bytes, ratio=%s", + encoder_session->verify? "Verify OK, " : "", + encoder_session->bytes_written, + ratiostr + ); + } + else { + stats_print_name(2, encoder_session->inbasefilename); + stats_print_info(2, "%u%% complete, ratio=%s", (uint32_t)floor(encoder_session->progress * 100.0 + 0.5), ratiostr); + } + } +} + +void print_error_with_init_status(const EncoderSession *e, const char *message, FLAC__StreamEncoderInitStatus init_status) +{ + const int ilen = strlen(e->inbasefilename) + 1; + const char *state_string = ""; + + flac__utils_printf(stderr, 1, "\n%s: %s\n", e->inbasefilename, message); + + flac__utils_printf(stderr, 1, "%*s init_status = %s\n", ilen, "", FLAC__StreamEncoderInitStatusString[init_status]); + + if(init_status == FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR) { + state_string = FLAC__stream_encoder_get_resolved_state_string(e->encoder); + + flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", state_string); + + /* print out some more info for some errors: */ + if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_CLIENT_ERROR])) { + flac__utils_printf(stderr, 1, + "\n" + "An error occurred while writing; the most common cause is that the disk is full.\n" + ); + } + else if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_IO_ERROR])) { + flac__utils_printf(stderr, 1, + "\n" + "An error occurred opening the output file; it is likely that the output\n" + "directory does not exist or is not writable, the output file already exists and\n" +#ifdef _WIN32 + "is not writeable, the disk is full or the file has a filename that exceeds the\n" + "path length limit.\n" +#else + "is not writable, or the disk is full.\n" +#endif + ); + } + } + else if(init_status == FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE) { + flac__utils_printf(stderr, 1, + "\n" + "The encoding parameters specified do not conform to the FLAC Subset and may not\n" + "be streamable or playable in hardware devices. If you really understand the\n" + "consequences, you can add --lax to the command-line options to encode with\n" + "these parameters anyway. See http://xiph.org/flac/format.html#subset\n" + ); + } +} + +void print_error_with_state(const EncoderSession *e, const char *message) +{ + const int ilen = strlen(e->inbasefilename) + 1; + const char *state_string; + + flac__utils_printf(stderr, 1, "\n%s: %s\n", e->inbasefilename, message); + + state_string = FLAC__stream_encoder_get_resolved_state_string(e->encoder); + + flac__utils_printf(stderr, 1, "%*s state = %s\n", ilen, "", state_string); + + /* print out some more info for some errors: */ + if(0 == strcmp(state_string, FLAC__StreamEncoderStateString[FLAC__STREAM_ENCODER_CLIENT_ERROR])) { + flac__utils_printf(stderr, 1, + "\n" + "An error occurred while writing; the most common cause is that the disk is full.\n" + ); + } +} + +void print_verify_error(EncoderSession *e) +{ + FLAC__uint64 absolute_sample; + uint32_t frame_number; + uint32_t channel; + uint32_t sample; + FLAC__int32 expected; + FLAC__int32 got; + + FLAC__stream_encoder_get_verify_decoder_error_stats(e->encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got); + + flac__utils_printf(stderr, 1, "%s: ERROR: mismatch in decoded data, verify FAILED!\n", e->inbasefilename); + flac__utils_printf(stderr, 1, " Absolute sample=%" PRIu64 ", frame=%u, channel=%u, sample=%u, expected %d, got %d\n", absolute_sample, frame_number, channel, sample, expected, got); + flac__utils_printf(stderr, 1, " In all known cases, verify errors are caused by hardware problems,\n"); + flac__utils_printf(stderr, 1, " usually overclocking or bad RAM. Delete %s\n", e->outfilename); + flac__utils_printf(stderr, 1, " and repeat the flac command exactly as before. If it does not give a\n"); + flac__utils_printf(stderr, 1, " verify error in the exact same place each time you try it, then there is\n"); + flac__utils_printf(stderr, 1, " a problem with your hardware; please see the FAQ:\n"); + flac__utils_printf(stderr, 1, " http://xiph.org/flac/faq.html#tools__hardware_prob\n"); + flac__utils_printf(stderr, 1, " If it does fail in the exact same place every time, keep\n"); + flac__utils_printf(stderr, 1, " %s and submit a bug report to:\n", e->outfilename); + flac__utils_printf(stderr, 1, " https://github.com/xiph/flac/issues\n"); + flac__utils_printf(stderr, 1, " Make sure to upload the FLAC file and use the \"Monitor\" feature to\n"); + flac__utils_printf(stderr, 1, " monitor the bug status.\n"); + flac__utils_printf(stderr, 1, "Verify FAILED! Do not trust %s\n", e->outfilename); +} + +FLAC__bool read_bytes(FILE *f, FLAC__byte *buf, size_t n, FLAC__bool eof_ok, const char *fn) +{ + size_t bytes_read = fread(buf, 1, n, f); + + if(bytes_read == 0) { + if(!eof_ok) { + flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); + return false; + } + else + return true; + } + if(bytes_read < n) { + flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); + return false; + } + return true; +} + +FLAC__bool read_uint16(FILE *f, FLAC__bool big_endian, FLAC__uint16 *val, const char *fn) +{ + if(!read_bytes(f, (FLAC__byte*)val, 2, /*eof_ok=*/false, fn)) + return false; + if(is_big_endian_host_ != big_endian) { + FLAC__byte tmp, *b = (FLAC__byte*)val; + tmp = b[1]; b[1] = b[0]; b[0] = tmp; + } + return true; +} + +FLAC__bool read_uint32(FILE *f, FLAC__bool big_endian, FLAC__uint32 *val, const char *fn) +{ + if(!read_bytes(f, (FLAC__byte*)val, 4, /*eof_ok=*/false, fn)) + return false; + if(is_big_endian_host_ != big_endian) { + FLAC__byte tmp, *b = (FLAC__byte*)val; + tmp = b[3]; b[3] = b[0]; b[0] = tmp; + tmp = b[2]; b[2] = b[1]; b[1] = tmp; + } + return true; +} + +FLAC__bool read_uint64(FILE *f, FLAC__bool big_endian, FLAC__uint64 *val, const char *fn) +{ + if(!read_bytes(f, (FLAC__byte*)val, 8, /*eof_ok=*/false, fn)) + return false; + if(is_big_endian_host_ != big_endian) { + FLAC__byte tmp, *b = (FLAC__byte*)val; + tmp = b[7]; b[7] = b[0]; b[0] = tmp; + tmp = b[6]; b[6] = b[1]; b[1] = tmp; + tmp = b[5]; b[5] = b[2]; b[2] = tmp; + tmp = b[4]; b[4] = b[3]; b[3] = tmp; + } + return true; +} + +FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, const char *fn) + /* Read an IEEE 754 80-bit (aka SANE) extended floating point value from 'f', + * convert it into an integral value and store in 'val'. Return false if only + * between 1 and 9 bytes remain in 'f', if 0 bytes remain in 'f', or if the + * value is negative, between zero and one, or too large to be represented by + * 'val'; return true otherwise. + */ +{ + uint32_t i; + FLAC__byte buf[10]; + FLAC__uint64 p = 0; + FLAC__int16 e; + FLAC__int16 shift; + + if(!read_bytes(f, buf, sizeof(buf), /*eof_ok=*/false, fn)) + return false; + e = ((FLAC__uint16)(buf[0])<<8 | (FLAC__uint16)(buf[1]))-0x3FFF; + shift = 63-e; + if((buf[0]>>7)==1U || e<0 || e>=63) { + flac__utils_printf(stderr, 1, "%s: ERROR: invalid floating-point value\n", fn); + return false; + } + + for(i = 0; i < 8; ++i) + p |= (FLAC__uint64)(buf[i+2])<<(56U-i*8); + *val = (FLAC__uint32)((p>>shift)+(p>>(shift-1) & 0x1)); + + return true; +} + +FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset) +{ + static uint8_t dump[8192]; + struct flac_stat_s stb; + + if(flac_fstat(fileno(f), &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFREG) + { + if(fseeko(f, offset, SEEK_CUR) == 0) + return true; + } + while(offset > 0) { + const long need = (long)min(offset, sizeof(dump)); + if((long)fread(dump, 1, need, f) < need) + return false; + offset -= need; + } + return true; +} + +uint32_t count_channel_mask_bits(FLAC__uint32 mask) +{ + uint32_t count = 0; + while(mask) { + if(mask & 1) + count++; + mask >>= 1; + } + return count; +} + diff --git a/vendor/flac/src/flac/encode.h b/vendor/flac/src/flac/encode.h new file mode 100644 index 0000000..2d65c50 --- /dev/null +++ b/vendor/flac/src/flac/encode.h @@ -0,0 +1,116 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef flac__encode_h +#define flac__encode_h + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/metadata.h" +#include "foreign_metadata.h" +#include "utils.h" +#include "share/compat.h" + +extern const int FLAC_ENCODE__DEFAULT_PADDING; + +typedef enum { + CST_BLOCKSIZE, + CST_COMPRESSION_LEVEL, + CST_DO_MID_SIDE, + CST_LOOSE_MID_SIDE, + CST_APODIZATION, + CST_MAX_LPC_ORDER, + CST_QLP_COEFF_PRECISION, + CST_DO_QLP_COEFF_PREC_SEARCH, + CST_DO_ESCAPE_CODING, + CST_DO_EXHAUSTIVE_MODEL_SEARCH, + CST_MIN_RESIDUAL_PARTITION_ORDER, + CST_MAX_RESIDUAL_PARTITION_ORDER, + CST_RICE_PARAMETER_SEARCH_DIST +} compression_setting_type_t; + +typedef struct { + compression_setting_type_t type; + union { + FLAC__bool t_bool; + unsigned t_unsigned; + const char *t_string; + } value; +} compression_setting_t; + +typedef struct { + utils__SkipUntilSpecification skip_specification; + utils__SkipUntilSpecification until_specification; + FLAC__bool verify; +#if FLAC__HAS_OGG + FLAC__bool use_ogg; + long serial_number; +#endif + FLAC__bool lax; + int padding; + size_t num_compression_settings; + compression_setting_t compression_settings[64]; + char *requested_seek_points; + int num_requested_seek_points; + const char *cuesheet_filename; + FLAC__bool treat_warnings_as_errors; + FLAC__bool continue_through_decode_errors; /* currently only obeyed when encoding from FLAC or Ogg FLAC */ + FLAC__bool cued_seekpoints; + FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */ + + FLAC__bool is_first_file; + FLAC__bool is_last_file; + FLAC__bool replay_gain; + FLAC__bool ignore_chunk_sizes; + FLAC__bool error_on_compression_fail; + FLAC__bool limit_min_bitrate; + FLAC__bool relaxed_foreign_metadata_handling; + + FLAC__StreamMetadata *vorbis_comment; + FLAC__StreamMetadata *vorbis_comment_with_channel_mask_tag; + FLAC__StreamMetadata *pictures[64]; + unsigned num_pictures; + + FileFormat format; + union { + struct { + FLAC__bool is_big_endian; + FLAC__bool is_unsigned_samples; + unsigned channels; + unsigned bps; + unsigned sample_rate; + } raw; + struct { + foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */ + } iff; + } format_options; + + struct { + FLAC__bool disable_constant_subframes; + FLAC__bool disable_fixed_subframes; + FLAC__bool disable_verbatim_subframes; + FLAC__bool do_md5; + } debug; +} encode_options_t; + +int flac__encode_file(FILE *infile, FLAC__off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length, encode_options_t options); + +#endif diff --git a/vendor/flac/src/flac/foreign_metadata.c b/vendor/flac/src/flac/foreign_metadata.c new file mode 100644 index 0000000..f63fc3e --- /dev/null +++ b/vendor/flac/src/flac/foreign_metadata.c @@ -0,0 +1,952 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include /* for FILE etc. */ +#include /* for calloc() etc. */ +#include /* for memcmp() etc. */ +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "foreign_metadata.h" + +#ifdef min +#undef min +#endif +#define min(x,y) ((x)<(y)?(x):(y)) + +const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS] = { "aiff" , "riff", "w64 " }; + +static FLAC__uint32 unpack32be_(const FLAC__byte *b) +{ + return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3]; +} + +static FLAC__uint32 unpack32le_(const FLAC__byte *b) +{ + return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24); +} + +static FLAC__uint64 unpack64le_(const FLAC__byte *b) +{ + return (FLAC__uint64)b[0] + ((FLAC__uint64)b[1]<<8) + ((FLAC__uint64)b[2]<<16) + ((FLAC__uint64)b[3]<<24) + ((FLAC__uint64)b[4]<<32) + ((FLAC__uint64)b[5]<<40) + ((FLAC__uint64)b[6]<<48) + ((FLAC__uint64)b[7]<<56); +} + +/* copies 'size' bytes from file 'fin' to 'fout', filling in *error with 'read_error' or 'write_error' as necessary */ +static FLAC__bool copy_data_(FILE *fin, FILE *fout, size_t size, const char **error, const char * const read_error, const char * const write_error) +{ + FLAC__byte buffer[4096]; + size_t left; + for(left = size; left > 0; ) { + size_t need = min(sizeof(buffer), left); + if(fread(buffer, 1, need, fin) < need) { + if(error) *error = read_error; + return false; + } + if(fwrite(buffer, 1, need, fout) < need) { + if(error) *error = write_error; + return false; + } + left -= need; + } + return true; +} + +/* compare 'size' bytes from file 'fin' to 'fout', filling in *error with 'read_error' or 'write_error' as necessary */ +static FLAC__bool compare_data_(FILE *fin, FILE *fout, size_t size, const char **error, const char * const read_error, const char * const write_error, const char * const compare_error) +{ + FLAC__byte buffer_in[4096]; + FLAC__byte buffer_out[4096]; /* sizes need to be the same */ + size_t left; + for(left = size; left > 0; ) { + size_t need = min(sizeof(buffer_in), left); + if(fread(buffer_in, 1, need, fin) < need) { + if(error) *error = read_error; + return false; + } + if(fread(buffer_out, 1, need, fout) < need) { + if(error) *error = write_error; + return false; + } + if(memcmp(buffer_in, buffer_out, need)) { + if(error) *error = compare_error; + return false; + } + left -= need; + } + return true; +} + +static FLAC__bool append_block_(foreign_metadata_t *fm, FLAC__off_t offset, FLAC__uint32 size, const char **error) +{ + foreign_block_t *fb; + if(size >= ((1u << FLAC__STREAM_METADATA_LENGTH_LEN) - FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) { + if(error) *error = "found foreign metadata chunk is too large (max is 16MiB per chunk)"; + return false; + } + fb = safe_realloc_nofree_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/); + if(fb) { + fb[fm->num_blocks].offset = offset; + fb[fm->num_blocks].size = size; + fm->num_blocks++; + fm->blocks = fb; + return true; + } + if(error) *error = "out of memory"; + return false; +} + +static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char **error) +{ + FLAC__byte buffer[12]; + FLAC__off_t offset, eof_offset; + if((offset = ftello(f)) < 0) { + if(error) *error = "ftello() error (001)"; + return false; + } + if(fread(buffer, 1, 12, f) < 12 || memcmp(buffer, "FORM", 4) || (memcmp(buffer+8, "AIFF", 4) && memcmp(buffer+8, "AIFC", 4))) { + if(error) *error = "unsupported FORM layout (002)"; + return false; + } + if(!append_block_(fm, offset, 12, error)) + return false; + eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32be_(buffer+4); + while(!feof(f)) { + FLAC__uint32 size; + if((offset = ftello(f)) < 0) { + if(error) *error = "ftello() error (003)"; + return false; + } + if((size = fread(buffer, 1, 8, f)) < 8) { + if(size == 0 && feof(f)) + break; + if(error) *error = "invalid AIFF file (004)"; + return false; + } + size = unpack32be_(buffer+4); + /* check if pad byte needed */ + if(size & 1) + size++; + if(!memcmp(buffer, "COMM", 4)) { + if(fm->format_block) { + if(error) *error = "invalid AIFF file: multiple \"COMM\" chunks (005)"; + return false; + } + if(fm->audio_block) { + if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (006)"; + return false; + } + fm->format_block = fm->num_blocks; + } + else if(!memcmp(buffer, "SSND", 4)) { + if(fm->audio_block) { + if(error) *error = "invalid AIFF file: multiple \"SSND\" chunks (007)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid AIFF file: \"SSND\" chunk before \"COMM\" chunk (008)"; + return false; + } + fm->audio_block = fm->num_blocks; + /* read #offset bytes */ + if(fread(buffer+8, 1, 4, f) < 4) { + if(error) *error = "invalid AIFF file (009)"; + return false; + } + fm->ssnd_offset_size = unpack32be_(buffer+8); + if(fseeko(f, -4, SEEK_CUR) < 0) { + if(error) *error = "invalid AIFF file: seek error (010)"; + return false; + } + /* WATCHOUT: For SSND we ignore the blockSize and are not saving any + * unaligned part at the end of the chunk. In retrospect it is pretty + * pointless to save the unaligned data before the PCM but now it is + * done and cast in stone. + */ + } + if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error)) + return false; + /* skip to next chunk */ + if(fseeko(f, size, SEEK_CUR) < 0) { + if(error) *error = "invalid AIFF file: seek error (011)"; + return false; + } + } + if(eof_offset != ftello(f)) { + if(error) *error = "invalid AIFF file: unexpected EOF (012)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid AIFF file: missing \"COMM\" chunk (013)"; + return false; + } + if(!fm->audio_block) { + if(error) *error = "invalid AIFF file: missing \"SSND\" chunk (014)"; + return false; + } + return true; +} + +static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error) +{ + FLAC__byte buffer[12]; + FLAC__off_t offset, eof_offset = -1, ds64_data_size = -1; + if((offset = ftello(f)) < 0) { + if(error) *error = "ftello() error (001)"; + return false; + } + if(fread(buffer, 1, 12, f) < 12 || (memcmp(buffer, "RIFF", 4) && memcmp(buffer, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) { + if(error) *error = "unsupported RIFF layout (002)"; + return false; + } + if(!memcmp(buffer, "RF64", 4)) + fm->is_rf64 = true; + if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) { + if(error) *error = "RF64 is not supported on this compile (r00)"; + return false; + } + if(!append_block_(fm, offset, 12, error)) + return false; + if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffff) { + eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4); + if(eof_offset & 1) /* fix odd RIFF size */ + eof_offset++; + } + while(!feof(f)) { + FLAC__off_t size; + if((offset = ftello(f)) < 0) { + if(error) *error = "ftello() error (003)"; + return false; + } + if((size = fread(buffer, 1, 8, f)) < 8) { + if(size == 0 && feof(f)) + break; + if(error) *error = "invalid WAVE file (004)"; + return false; + } + size = unpack32le_(buffer+4); + /* check if pad byte needed */ + if(size & 1) + size++; + if(!memcmp(buffer, "fmt ", 4)) { + if(fm->format_block) { + if(error) *error = "invalid WAVE file: multiple \"fmt \" chunks (005)"; + return false; + } + if(fm->audio_block) { + if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (006)"; + return false; + } + fm->format_block = fm->num_blocks; + } + else if(!memcmp(buffer, "data", 4)) { + if(fm->audio_block) { + if(error) *error = "invalid WAVE file: multiple \"data\" chunks (007)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid WAVE file: \"data\" chunk before \"fmt \" chunk (008)"; + return false; + } + fm->audio_block = fm->num_blocks; + if(fm->is_rf64 && fm->num_blocks < 2) { + if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)"; + return false; + } + } + if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error)) + return false; + /* parse ds64 chunk if necessary */ + if(fm->is_rf64 && fm->num_blocks == 2) { + FLAC__byte buffer2[7*4]; + if(memcmp(buffer, "ds64", 4)) { + if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)"; + return false; + } + /* unpack the size again since we don't want the padding byte effect */ + size = unpack32le_(buffer+4); + if(size < (FLAC__off_t)sizeof(buffer2)) { + if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)"; + return false; + } + if(size > (FLAC__off_t)sizeof(buffer2)) { + if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)"; + return false; + } + if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) { + if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)"; + return false; + } + ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8); + if(ds64_data_size == (FLAC__off_t)(-1)) { + if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)"; + return false; + } + /* check if pad byte needed */ + if(ds64_data_size & 1) + ds64_data_size++; + /* @@@ [2^63 limit] */ + if(ds64_data_size < 0) { + if(error) *error = "RF64 file too large (r09)"; + return false; + } + if(unpack32le_(buffer2+24)) { + if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)"; + return false; + } + eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2); + /* @@@ [2^63 limit] */ + if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) { + if(error) *error = "RF64 file too large (r07)"; + return false; + } + } + else { /* skip to next chunk */ + if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffff) { + if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) { + if(error) *error = "invalid RF64 file: seek error (r10)"; + return false; + } + } + else { + if(fseeko(f, size, SEEK_CUR) < 0) { + if(error) *error = "invalid WAVE file: seek error (009)"; + return false; + } + } + } + } + if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) { + if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)"; + return false; + } + if(eof_offset != ftello(f)) { + if(error) *error = "invalid WAVE file: unexpected EOF (010)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid WAVE file: missing \"fmt \" chunk (011)"; + return false; + } + if(!fm->audio_block) { + if(error) *error = "invalid WAVE file: missing \"data\" chunk (012)"; + return false; + } + return true; +} + +static FLAC__bool read_from_wave64_(foreign_metadata_t *fm, FILE *f, const char **error) +{ + FLAC__byte buffer[40]; + FLAC__off_t offset, eof_offset = -1; + if((offset = ftello(f)) < 0) { + if(error) *error = "ftello() error (001)"; + return false; + } + if( + fread(buffer, 1, 40, f) < 40 || + /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */ + memcmp(buffer, "\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 16) || + /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ + memcmp(buffer+24, "\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16) + ) { + if(error) *error = "unsupported Wave64 layout (002)"; + return false; + } + if(sizeof(FLAC__off_t) < 8) { + if(error) *error = "Wave64 is not supported on this compile (r00)"; + return false; + } + if(!append_block_(fm, offset, 40, error)) + return false; + eof_offset = (FLAC__off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */ + while(!feof(f)) { + FLAC__uint64 size; + if((offset = ftello(f)) < 0) { + if(error) *error = "ftello() error (003)"; + return false; + } + if((size = fread(buffer, 1, 24, f)) < 24) { + if(size == 0 && feof(f)) + break; + if(error) *error = "invalid Wave64 file (004)"; + return false; + } + size = unpack64le_(buffer+16); + /* check if pad bytes needed */ + if(size & 7) + size = (size+7) & (~((FLAC__uint64)7)); + /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ + if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) { + if(fm->format_block) { + if(error) *error = "invalid Wave64 file: multiple \"fmt \" chunks (005)"; + return false; + } + if(fm->audio_block) { + if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)"; + return false; + } + fm->format_block = fm->num_blocks; + } + /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ + else if(!memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) { + if(fm->audio_block) { + if(error) *error = "invalid Wave64 file: multiple \"data\" chunks (007)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)"; + return false; + } + fm->audio_block = fm->num_blocks; + } + if(!append_block_(fm, offset, memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)? (FLAC__uint32)size : 16+8, error)) + return false; + /* skip to next chunk */ + if(fseeko(f, size-24, SEEK_CUR) < 0) { + if(error) *error = "invalid Wave64 file: seek error (009)"; + return false; + } + } + if(eof_offset != ftello(f)) { + if(error) *error = "invalid Wave64 file: unexpected EOF (010)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)"; + return false; + } + if(!fm->audio_block) { + if(error) *error = "invalid Wave64 file: missing \"data\" chunk (012)"; + return false; + } + return true; +} + +static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__Metadata_SimpleIterator *it, const char **error) +{ + FLAC__byte buffer[4]; + const uint32_t ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8; + size_t block_num = 0; + FLAC__ASSERT(sizeof(buffer) >= ID_LEN); + while(block_num < fm->num_blocks) { + /* find next matching padding block */ + do { + /* even on the first chunk's loop there will be a skippable STREAMINFO block, on subsequent loops we are first moving past the PADDING we just used */ + if(!FLAC__metadata_simple_iterator_next(it)) { + if(error) *error = "no matching PADDING block found (004)"; + return false; + } + } while(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_PADDING); + if(FLAC__metadata_simple_iterator_get_block_length(it) != ID_LEN+fm->blocks[block_num].size) { + if(error) *error = "PADDING block with wrong size found (005)"; + return false; + } + /* transfer chunk into APPLICATION block */ + /* first set up the file pointers */ + if(fseeko(fin, fm->blocks[block_num].offset, SEEK_SET) < 0) { + if(error) *error = "seek failed in WAVE/AIFF file (006)"; + return false; + } + if(fseeko(fout, FLAC__metadata_simple_iterator_get_block_offset(it), SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file (007)"; + return false; + } + /* update the type */ + buffer[0] = FLAC__METADATA_TYPE_APPLICATION; + if(FLAC__metadata_simple_iterator_is_last(it)) + buffer[0] |= 0x80; /*MAGIC number*/ + if(fwrite(buffer, 1, 1, fout) < 1) { + if(error) *error = "write failed in FLAC file (008)"; + return false; + } + /* length stays the same so skip over it */ + if(fseeko(fout, FLAC__STREAM_METADATA_LENGTH_LEN/8, SEEK_CUR) < 0) { + if(error) *error = "seek failed in FLAC file (009)"; + return false; + } + /* write the APPLICATION ID */ + memcpy(buffer, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], ID_LEN); + if(fwrite(buffer, 1, ID_LEN, fout) < ID_LEN) { + if(error) *error = "write failed in FLAC file (010)"; + return false; + } + /* transfer the foreign metadata */ + if(!copy_data_(fin, fout, fm->blocks[block_num].size, error, "read failed in WAVE/AIFF file (011)", "write failed in FLAC file (012)")) + return false; + block_num++; + } + return true; +} + +static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadata_SimpleIterator *it, const char **error) +{ + FLAC__byte id[4], buffer[32]; + FLAC__off_t offset; + FLAC__uint32 length; + FLAC__bool first_block = true, type_found = false, ds64_found = false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8); + + while(FLAC__metadata_simple_iterator_next(it)) { + if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION) + continue; + if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) { + if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)"; + return false; + } + if(first_block) { + uint32_t i; + for(i = 0; i < FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS; i++) + if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[i], sizeof(id)) == 0) { + fm->type = i; + first_block = false; + } + if(first_block) /* means no first foreign metadata block was found yet */ + continue; + } + else if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id))) + continue; + offset = FLAC__metadata_simple_iterator_get_block_offset(it); + length = FLAC__metadata_simple_iterator_get_block_length(it); + /* skip over header and app ID */ + offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8; + offset += sizeof(id); + /* look for format or audio blocks */ + if(fseeko(f, offset, SEEK_SET) < 0) { + if(error) *error = "seek error (003)"; + return false; + } + if(fread(buffer, 1, 4, f) != 4) { + if(error) *error = "read error (004)"; + return false; + } + if(fm->num_blocks == 0) { /* first block? */ + /* Initialize bools */ + fm->is_wavefmtex = 0; + fm->is_aifc = 0; + fm->is_sowt = 0; + fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4); + + if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64)) + type_found = true; + else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */ + type_found = true; + else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4)) { + type_found = true; + if(fread(buffer+4, 1, 8, f) != 8) { + if(error) *error = "read error (020)"; + return false; + } + fm->is_aifc = 0 == memcmp(buffer+8, "AIFC", 4); + } + else { + if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (005)"; + return false; + } + } + else if(!type_found) { + FLAC__ASSERT(0); + /* double protection: */ + if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (006)"; + return false; + } + else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF) { + if(!memcmp(buffer, "fmt ", 4)) { + if(fm->format_block) { + if(error) *error = "invalid WAVE metadata: multiple \"fmt \" chunks (007)"; + return false; + } + if(fm->audio_block) { + if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (008)"; + return false; + } + fm->format_block = fm->num_blocks; + if(fread(buffer+4, 1, 8, f) != 8) { + if(error) *error = "read error (020)"; + return false; + } + fm->is_wavefmtex = 0 == memcmp(buffer+8, "\xfe\xff", 2); + } + else if(!memcmp(buffer, "data", 4)) { + if(fm->audio_block) { + if(error) *error = "invalid WAVE metadata: multiple \"data\" chunks (009)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid WAVE metadata: \"data\" chunk before \"fmt \" chunk (010)"; + return false; + } + fm->audio_block = fm->num_blocks; + } + else if(fm->is_rf64 && fm->num_blocks == 1) { + if(memcmp(buffer, "ds64", 4)) { + if(error) *error = "invalid RF64 metadata: second chunk is not \"ds64\" (011)"; + return false; + } + ds64_found = true; + } + } + else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) { + if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */ + if(fm->format_block) { + if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)"; + return false; + } + if(fm->audio_block) { + if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)"; + return false; + } + fm->format_block = fm->num_blocks; + } + else if(!memcmp(buffer, "data", 4)) { /* use first 4 bytes instead of whole GUID */ + if(fm->audio_block) { + if(error) *error = "invalid Wave64 metadata: multiple \"data\" chunks (014)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)"; + return false; + } + fm->audio_block = fm->num_blocks; + } + } + else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) { + if(!memcmp(buffer, "COMM", 4)) { + if(fm->format_block) { + if(error) *error = "invalid AIFF metadata: multiple \"COMM\" chunks (016)"; + return false; + } + if(fm->audio_block) { + if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)"; + return false; + } + fm->format_block = fm->num_blocks; + if(fm->is_aifc) { + if(fread(buffer+4, 1, 26, f) != 26) { + if(error) *error = "read error (020)"; + return false; + } + fm->is_sowt = 0 == memcmp(buffer+26, "sowt", 2); + fm->aifc_comm_length = length; + } + } + else if(!memcmp(buffer, "SSND", 4)) { + if(fm->audio_block) { + if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (018)"; + return false; + } + if(!fm->format_block) { + if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)"; + return false; + } + fm->audio_block = fm->num_blocks; + /* read SSND offset size */ + if(fread(buffer+4, 1, 8, f) != 8) { + if(error) *error = "read error (020)"; + return false; + } + fm->ssnd_offset_size = unpack32be_(buffer+8); + } + } + else { + FLAC__ASSERT(0); + /* double protection: */ + if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (021)"; + return false; + } + if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error)) + return false; + } + if(fm->is_rf64 && !ds64_found) { + if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)"; + return false; + } + if(!fm->format_block) { + if(error) + *error = + fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" : + fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" : + "invalid AIFF file: missing \"COMM\" chunk (026)"; + return false; + } + if(!fm->audio_block) { + if(error) + *error = + fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" : + fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" : + "invalid AIFF file: missing \"SSND\" chunk (029)"; + return false; + } + return true; +} + +static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error) +{ + size_t i; + if(fseeko(fout, offset1, SEEK_SET) < 0) { + if(error) *error = "seek failed in WAVE/AIFF file"; + return false; + } + + /* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64 */ + for(i = fm->is_rf64?2:1; i < fm->format_block; i++) { + if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file"; + return false; + } + if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file")) + return false; + } + + if(fm->is_aifc) { + /* Need to restore compression type name */ + if(fseeko(fout, 30, SEEK_CUR) < 0) { + if(error) *error = "seek failed in AIFF-C file"; + return false; + } + if(fseeko(fin, fm->blocks[i].offset+30, SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file"; + return false; + } + if(!copy_data_(fin, fout, fm->aifc_comm_length-34, error, "read failed in FLAC file", "write failed in WAVE/AIFF file")) + return false; + /* Now seek back */ + if(fseeko(fout, ((FLAC__int32)(fm->aifc_comm_length) * -1) + 4, SEEK_CUR) < 0) { + if(error) *error = "seek failed in AIFF-C file"; + return false; + } + } + if(fseeko(fout, offset2, SEEK_SET) < 0) { + if(error) *error = "seek failed in WAVE/AIFF file (006)"; + return false; + } + for(i = fm->format_block+1; i < fm->audio_block; i++) { + if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file"; + return false; + } + if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file")) + return false; + } + if(fseeko(fout, offset3, SEEK_SET) < 0) { + if(error) *error = "seek failed in WAVE/AIFF file"; + return false; + } + for(i = fm->audio_block+1; i < fm->num_blocks; i++) { + if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file"; + return false; + } + if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file")) + return false; + } + return true; +} + +static FLAC__bool compare_with_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__off_t offset3, const char **error) +{ + size_t i; + + /* Compare blocks before audio data */ + for(i = 0; i <= (fm->audio_block); i++) { + if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file"; + return false; + } + if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file", + i==0?"stored main chunk length differs from written length":( + i==fm->format_block?"stored foreign format block differs from written block. Perhaps the file is being restored to a different format than that of the original file":( + i==fm->audio_block?"stored audio length differs from written length. Perhaps the file changed in length after being originally encoded":"restore of foreign metadata failed")))) + return false; + } + + /* Seek beyond audio */ + if(fseeko(fout, offset3, SEEK_SET) < 0) { + if(error) *error = "seek failed in WAVE/AIFF file"; + return false; + } + for(; i < fm->num_blocks; i++) { + if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) { + if(error) *error = "seek failed in FLAC file"; + return false; + } + if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file", "restore of foreign metadata failed")) + return false; + } + return true; +} + +foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type) +{ + /* calloc() to zero all the member variables */ + foreign_metadata_t *x = calloc(sizeof(foreign_metadata_t), 1); + if(x) { + x->type = type; + x->is_rf64 = false; + } + return x; +} + +void flac__foreign_metadata_delete(foreign_metadata_t *fm) +{ + if(fm) { + if(fm->blocks) + free(fm->blocks); + free(fm); + } +} + +FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error) +{ + FLAC__bool ok; + FILE *f = flac_fopen(filename, "rb"); + if(!f) { + if(error) *error = "can't open AIFF file for reading (000)"; + return false; + } + ok = read_from_aiff_(fm, f, error); + fclose(f); + return ok; +} + +FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error) +{ + FLAC__bool ok; + FILE *f = flac_fopen(filename, "rb"); + if(!f) { + if(error) *error = "can't open WAVE file for reading (000)"; + return false; + } + ok = read_from_wave_(fm, f, error); + fclose(f); + return ok; +} + +FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error) +{ + FLAC__bool ok; + FILE *f = flac_fopen(filename, "rb"); + if(!f) { + if(error) *error = "can't open Wave64 file for reading (000)"; + return false; + } + ok = read_from_wave64_(fm, f, error); + fclose(f); + return ok; +} + +FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error) +{ + FLAC__bool ok; + FILE *fin, *fout; + FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new(); + if(!it) { + if(error) *error = "out of memory (000)"; + return false; + } + if(!FLAC__metadata_simple_iterator_init(it, outfilename, /*read_only=*/true, /*preserve_file_stats=*/false)) { + if(error) *error = "can't initialize iterator (001)"; + FLAC__metadata_simple_iterator_delete(it); + return false; + } + if(0 == (fin = flac_fopen(infilename, "rb"))) { + if(error) *error = "can't open WAVE/AIFF file for reading (002)"; + FLAC__metadata_simple_iterator_delete(it); + return false; + } + if(0 == (fout = flac_fopen(outfilename, "r+b"))) { + if(error) *error = "can't open FLAC file for updating (003)"; + FLAC__metadata_simple_iterator_delete(it); + fclose(fin); + return false; + } + ok = write_to_flac_(fm, fin, fout, it, error); + FLAC__metadata_simple_iterator_delete(it); + fclose(fin); + fclose(fout); + return ok; +} + +FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error) +{ + FLAC__bool ok; + FILE *f; + FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new(); + if(!it) { + if(error) *error = "out of memory (000)"; + return false; + } + if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/false)) { + if(error) *error = "can't initialize iterator (001)"; + FLAC__metadata_simple_iterator_delete(it); + return false; + } + if(0 == (f = flac_fopen(filename, "rb"))) { + if(error) *error = "can't open FLAC file for reading (002)"; + FLAC__metadata_simple_iterator_delete(it); + return false; + } + ok = read_from_flac_(fm, f, it, error); + FLAC__metadata_simple_iterator_delete(it); + fclose(f); + return ok; +} + +FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error) +{ + FLAC__bool ok; + FILE *fin, *fout; + if(0 == (fin = flac_fopen(infilename, "rb"))) { + if(error) *error = "can't open FLAC file for reading (000)"; + return false; + } + if(0 == (fout = flac_fopen(outfilename, "r+b"))) { + if(error) *error = "can't open WAVE/AIFF file for updating (001)"; + fclose(fin); + return false; + } + ok = write_to_iff_(fm, fin, fout, offset1, offset2, offset3, error); + fclose(fin); + fclose(fout); + return ok; +} + +FLAC__bool flac__foreign_metadata_compare_with_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset3, const char **error) +{ + FLAC__bool ok; + FILE *fin, *fout; + if(0 == (fin = flac_fopen(infilename, "rb"))) { + if(error) *error = "can't open FLAC file for reading"; + return false; + } + if(0 == (fout = flac_fopen(outfilename, "rb"))) { + if(error) *error = "can't open WAVE/AIFF file for comparing"; + fclose(fin); + return false; + } + ok = compare_with_iff_(fm, fin, fout, offset3, error); + fclose(fin); + fclose(fout); + return ok; +} diff --git a/vendor/flac/src/flac/foreign_metadata.h b/vendor/flac/src/flac/foreign_metadata.h new file mode 100644 index 0000000..fa68d46 --- /dev/null +++ b/vendor/flac/src/flac/foreign_metadata.h @@ -0,0 +1,83 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef flac__foreign_metadata_h +#define flac__foreign_metadata_h + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/metadata.h" +#include "utils.h" +#include "share/compat.h" + +#define FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS 3 + +extern const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS]; + +/* WATCHOUT: these enums are used to index internal arrays */ +typedef enum { + FOREIGN_BLOCK_TYPE__AIFF = 0, /* for AIFF and AIFF-C */ + FOREIGN_BLOCK_TYPE__RIFF = 1, /* for WAVE and RF64 */ + FOREIGN_BLOCK_TYPE__WAVE64 = 2 /* only for Sony's flavor */ +} foreign_block_type_t; + +typedef struct { + /* for encoding, this will be the offset in the WAVE/AIFF file of the chunk */ + /* for decoding, this will be the offset in the FLAC file of the chunk data inside the APPLICATION block */ + FLAC__off_t offset; + /* size is the actual size in bytes of the chunk to be stored/recreated. */ + /* It includes the 8 bytes of chunk type and size, and any padding byte for alignment. */ + /* For 'data'/'SSND' chunks, the size does not include the actual sound or padding bytes */ + /* because these are not stored, they are recreated from the compressed FLAC stream. */ + /* So for RIFF 'data', size is 8, and for AIFF 'SSND', size is 8 + 8 + ssnd_offset_size */ + /* 32 bit size is OK because we only care about the non-sound data and FLAC metadata */ + /* only supports a few megs anyway. */ + FLAC__uint32 size; +} foreign_block_t; + +typedef struct { + foreign_block_type_t type; /* currently we don't support multiple foreign types in a stream (and maybe never will) */ + foreign_block_t *blocks; + size_t num_blocks; + size_t format_block; /* block number of 'fmt ' or 'COMM' chunk */ + size_t audio_block; /* block number of 'data' or 'SSND' chunk */ + FLAC__bool is_rf64; /* always false if type!=RIFF */ + FLAC__bool is_wavefmtex; /* always false if type!=RIFF */ + FLAC__bool is_aifc; /* always false if type!=AIFF */ + FLAC__bool is_sowt; /* always false if type!=AIFF */ + FLAC__uint32 aifc_comm_length; + FLAC__uint32 ssnd_offset_size; /* 0 if type!=AIFF */ +} foreign_metadata_t; + +foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type); + +void flac__foreign_metadata_delete(foreign_metadata_t *fm); + +FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const char *filename, const char **error); +FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error); +FLAC__bool flac__foreign_metadata_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error); +FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const char *infilename, const char *outfilename, const char **error); + +FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const char *filename, const char **error); +FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error); +FLAC__bool flac__foreign_metadata_compare_with_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset3, const char **error); + +#endif diff --git a/vendor/flac/src/flac/iffscan.c b/vendor/flac/src/flac/iffscan.c new file mode 100644 index 0000000..a5472e0 --- /dev/null +++ b/vendor/flac/src/flac/iffscan.c @@ -0,0 +1,129 @@ +/* iffscan - Simple AIFF/RIFF chunk scanner + * Copyright (C) 2007-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include "share/compat.h" +#include "foreign_metadata.h" + +static FLAC__uint32 unpack32be_(const FLAC__byte *b) +{ + return ((FLAC__uint32)b[0]<<24) + ((FLAC__uint32)b[1]<<16) + ((FLAC__uint32)b[2]<<8) + (FLAC__uint32)b[3]; +} + +static FLAC__uint32 unpack32le_(const FLAC__byte *b) +{ + return (FLAC__uint32)b[0] + ((FLAC__uint32)b[1]<<8) + ((FLAC__uint32)b[2]<<16) + ((FLAC__uint32)b[3]<<24); +} + +static FLAC__uint64 unpack64le_(const FLAC__byte *b) +{ + return (FLAC__uint64)b[0] + ((FLAC__uint64)b[1]<<8) + ((FLAC__uint64)b[2]<<16) + ((FLAC__uint64)b[3]<<24) + ((FLAC__uint64)b[4]<<32) + ((FLAC__uint64)b[5]<<40) + ((FLAC__uint64)b[6]<<48) + ((FLAC__uint64)b[7]<<56); +} + +static FLAC__uint32 unpack32_(const FLAC__byte *b, foreign_block_type_t type) +{ + if(type == FOREIGN_BLOCK_TYPE__AIFF) + return unpack32be_(b); + else + return unpack32le_(b); +} + +int main(int argc, char *argv[]) +{ + FILE *f; + char buf[36]; + foreign_metadata_t *fm; + const char *fn, *error; + size_t i; + FLAC__uint32 size; + +#ifdef _WIN32 + if (get_utf8_argv(&argc, &argv) != 0) { + fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n"); + return 1; + } +#endif + + if(argc != 2) { + flac_fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]); + return 1; + } + fn = argv[1]; + if(0 == (f = flac_fopen(fn, "rb")) || fread(buf, 1, 4, f) != 4) { + flac_fprintf(stderr, "ERROR opening %s for reading\n", fn); + return 1; + } + fclose(f); + if(0 == (fm = flac__foreign_metadata_new(memcmp(buf, "RIFF", 4) && memcmp(buf, "RF64", 4)? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) { + flac_fprintf(stderr, "ERROR: out of memory\n"); + return 1; + } + if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) { + if(!flac__foreign_metadata_read_from_aiff(fm, fn, &error)) { + flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error); + return 1; + } + } + else { + if(!flac__foreign_metadata_read_from_wave(fm, fn, &error)) { + flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error); + return 1; + } + } + if(0 == (f = flac_fopen(fn, "rb"))) { + flac_fprintf(stderr, "ERROR opening %s for reading\n", fn); + return 1; + } + for(i = 0; i < fm->num_blocks; i++) { + if(fseeko(f, fm->blocks[i].offset, SEEK_SET) < 0) { + flac_fprintf(stderr, "ERROR seeking in %s\n", fn); + return 1; + } + if(fread(buf, 1, i==0?12:8, f) != (i==0?12:8)) { + flac_fprintf(stderr, "ERROR reading %s\n", fn); + return 1; + } + size = unpack32_((FLAC__byte*)buf+4, fm->type); + printf("block:[%c%c%c%c] size=%08x=(%10u)", buf[0], buf[1], buf[2], buf[3], size, size); + if(i == 0) + printf(" type:[%c%c%c%c]", buf[8], buf[9], buf[10], buf[11]); + else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && i == fm->audio_block) + printf(" offset size=%08x=(%10u)", fm->ssnd_offset_size, fm->ssnd_offset_size); + else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && i == 1 && !memcmp(buf, "ds64", 4)) { + if(fread(buf+8, 1, 36-8, f) != 36-8) { + flac_fprintf(stderr, "ERROR reading %s\n", fn); + return 1; + } + printf("\n RIFF size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+8), unpack64le_((FLAC__byte*)buf+8)); + printf("\n data size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+16), unpack64le_((FLAC__byte*)buf+16)); + printf("\n sample count=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+24), unpack64le_((FLAC__byte*)buf+24)); + printf("\n table size=%08x=(%10u)", unpack32le_((FLAC__byte*)buf+32), unpack32le_((FLAC__byte*)buf+32)); + } + printf("\n"); + } + fclose(f); + flac__foreign_metadata_delete(fm); + return 0; +} diff --git a/vendor/flac/src/flac/local_string_utils.c b/vendor/flac/src/flac/local_string_utils.c new file mode 100644 index 0000000..7e25233 --- /dev/null +++ b/vendor/flac/src/flac/local_string_utils.c @@ -0,0 +1,109 @@ +/* flac - Command-line FLAC encoder/decoder + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "utils.h" +#include "local_string_utils.h" + +/* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ + * + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +flac__strlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +/* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ + * + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +flac__strlcat(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/vendor/flac/src/flac/local_string_utils.h b/vendor/flac/src/flac/local_string_utils.h new file mode 100644 index 0000000..01f891f --- /dev/null +++ b/vendor/flac/src/flac/local_string_utils.h @@ -0,0 +1,28 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef flac__local_string_utils_h +#define flac__local_string_utils_h + +#include /* for size_t */ + +size_t flac__strlcpy(char *dst, const char *src, size_t siz); +size_t flac__strlcat(char *dst, const char *src, size_t siz); + +#endif diff --git a/vendor/flac/src/flac/main.c b/vendor/flac/src/flac/main.c new file mode 100644 index 0000000..c22e602 --- /dev/null +++ b/vendor/flac/src/flac/main.c @@ -0,0 +1,2442 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined _MSC_VER && !defined __MINGW32__ +/* unlink is in stdio.h in VC++ */ +#include /* for unlink() */ +#endif +#include "FLAC/all.h" +#include "share/alloc.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "share/endswap.h" +#include "share/safe_str.h" +#include "analyze.h" +#include "decode.h" +#include "encode.h" +#include "local_string_utils.h" /* for flac__strlcat() and flac__strlcpy() */ +#include "utils.h" +#include "vorbiscomment.h" + +#if 0 +/*[JEC] was:#if HAVE_GETOPT_LONG*/ +/*[JEC] see flac/include/share/getopt.h as to why the change */ +# include +#else +# include "share/getopt.h" +#endif + +static int do_it(void); + +static FLAC__bool init_options(void); +static int parse_options(int argc, char *argv[]); +static int parse_option(int short_option, const char *long_option, const char *option_argument); +static void free_options(void); +static void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value); +static void add_compression_setting_string(compression_setting_type_t type, const char *value); +static void add_compression_setting_uint32_t(compression_setting_type_t type, uint32_t value); + +static int usage_error(const char *message, ...); +static void short_usage(void); +static void show_version(void); +static void show_help(void); +static void show_explain(void); +static void format_mistake(const char *infilename, FileFormat wrong, FileFormat right); + +static int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file); +static int decode_file(const char *infilename); + +static const char *get_encoded_outfilename(const char *infilename); +static const char *get_decoded_outfilename(const char *infilename, const FileFormat format); +static const char *get_outfilename(const char *infilename, const char *suffix); + +static void die(const char *message); +static int conditional_fclose(FILE *f); +static char *local_strdup(const char *source); + +/* + * share__getopt format struct; note that for long options with no + * short option equivalent we just set the 'val' field to 0. + */ +static struct share__option long_options_[] = { + /* + * general options + */ + { "help" , share__no_argument, 0, 'h' }, + { "explain" , share__no_argument, 0, 'H' }, + { "version" , share__no_argument, 0, 'v' }, + { "decode" , share__no_argument, 0, 'd' }, + { "analyze" , share__no_argument, 0, 'a' }, + { "test" , share__no_argument, 0, 't' }, + { "stdout" , share__no_argument, 0, 'c' }, + { "silent" , share__no_argument, 0, 's' }, + { "totally-silent" , share__no_argument, 0, 0 }, + { "warnings-as-errors" , share__no_argument, 0, 'w' }, + { "force" , share__no_argument, 0, 'f' }, + { "delete-input-file" , share__no_argument, 0, 0 }, + { "preserve-modtime" , share__no_argument, 0, 0 }, + { "keep-foreign-metadata" , share__no_argument, 0, 0 }, + { "keep-foreign-metadata-if-present" , share__no_argument, 0, 0 }, + { "output-prefix" , share__required_argument, 0, 0 }, + { "output-name" , share__required_argument, 0, 'o' }, + { "skip" , share__required_argument, 0, 0 }, + { "until" , share__required_argument, 0, 0 }, + { "channel-map" , share__required_argument, 0, 0 }, /* undocumented */ + + /* + * decoding options + */ + { "decode-through-errors", share__no_argument, 0, 'F' }, + { "cue" , share__required_argument, 0, 0 }, + { "apply-replaygain-which-is-not-lossless", share__optional_argument, 0, 0 }, /* undocumented */ + + /* + * encoding options + */ + { "cuesheet" , share__required_argument, 0, 0 }, + { "no-cued-seekpoints" , share__no_argument, 0, 0 }, + { "picture" , share__required_argument, 0, 0 }, + { "tag" , share__required_argument, 0, 'T' }, + { "tag-from-file" , share__required_argument, 0, 0 }, + { "compression-level-0" , share__no_argument, 0, '0' }, + { "compression-level-1" , share__no_argument, 0, '1' }, + { "compression-level-2" , share__no_argument, 0, '2' }, + { "compression-level-3" , share__no_argument, 0, '3' }, + { "compression-level-4" , share__no_argument, 0, '4' }, + { "compression-level-5" , share__no_argument, 0, '5' }, + { "compression-level-6" , share__no_argument, 0, '6' }, + { "compression-level-7" , share__no_argument, 0, '7' }, + { "compression-level-8" , share__no_argument, 0, '8' }, + { "compression-level-9" , share__no_argument, 0, '9' }, + { "best" , share__no_argument, 0, '8' }, + { "fast" , share__no_argument, 0, '0' }, + { "verify" , share__no_argument, 0, 'V' }, + { "force-raw-format" , share__no_argument, 0, 0 }, + { "force-aiff-format" , share__no_argument, 0, 0 }, + { "force-rf64-format" , share__no_argument, 0, 0 }, + { "force-wave64-format" , share__no_argument, 0, 0 }, + { "force-legacy-wave-format" , share__no_argument, 0, 0 }, + { "force-extensible-wave-format",share__no_argument,0, 0 }, + { "force-aiff-c-none-format" , share__no_argument, 0, 0 }, + { "force-aiff-c-sowt-format" , share__no_argument, 0, 0 }, + { "lax" , share__no_argument, 0, 0 }, + { "replay-gain" , share__no_argument, 0, 0 }, + { "ignore-chunk-sizes" , share__no_argument, 0, 0 }, + { "seekpoint" , share__required_argument, 0, 'S' }, + { "padding" , share__required_argument, 0, 'P' }, +#if FLAC__HAS_OGG + { "ogg" , share__no_argument, 0, 0 }, + { "serial-number" , share__required_argument, 0, 0 }, +#endif + { "blocksize" , share__required_argument, 0, 'b' }, + { "exhaustive-model-search" , share__no_argument, 0, 'e' }, + { "max-lpc-order" , share__required_argument, 0, 'l' }, + { "apodization" , share__required_argument, 0, 'A' }, + { "mid-side" , share__no_argument, 0, 'm' }, + { "adaptive-mid-side" , share__no_argument, 0, 'M' }, + { "qlp-coeff-precision-search", share__no_argument, 0, 'p' }, + { "qlp-coeff-precision" , share__required_argument, 0, 'q' }, + { "rice-partition-order" , share__required_argument, 0, 'r' }, + { "endian" , share__required_argument, 0, 0 }, + { "channels" , share__required_argument, 0, 0 }, + { "bps" , share__required_argument, 0, 0 }, + { "sample-rate" , share__required_argument, 0, 0 }, + { "sign" , share__required_argument, 0, 0 }, + { "input-size" , share__required_argument, 0, 0 }, + { "error-on-compression-fail" , share__no_argument, 0, 0 }, + { "limit-min-bitrate" , share__no_argument, 0, 0 }, + + /* + * analysis options + */ + { "residual-gnuplot", share__no_argument, 0, 0 }, + { "residual-text", share__no_argument, 0, 0 }, + + /* + * negatives + */ + { "no-preserve-modtime" , share__no_argument, 0, 0 }, + { "no-decode-through-errors" , share__no_argument, 0, 0 }, + { "no-silent" , share__no_argument, 0, 0 }, + { "no-force" , share__no_argument, 0, 0 }, + { "no-seektable" , share__no_argument, 0, 0 }, + { "no-delete-input-file" , share__no_argument, 0, 0 }, + { "no-keep-foreign-metadata" , share__no_argument, 0, 0 }, + { "no-replay-gain" , share__no_argument, 0, 0 }, + { "no-ignore-chunk-sizes" , share__no_argument, 0, 0 }, + { "no-utf8-convert" , share__no_argument, 0, 0 }, + { "no-lax" , share__no_argument, 0, 0 }, +#if FLAC__HAS_OGG + { "no-ogg" , share__no_argument, 0, 0 }, +#endif + { "no-exhaustive-model-search", share__no_argument, 0, 0 }, + { "no-mid-side" , share__no_argument, 0, 0 }, + { "no-adaptive-mid-side" , share__no_argument, 0, 0 }, + { "no-qlp-coeff-prec-search" , share__no_argument, 0, 0 }, + { "no-padding" , share__no_argument, 0, 0 }, + { "no-verify" , share__no_argument, 0, 0 }, + { "no-warnings-as-errors" , share__no_argument, 0, 0 }, + { "no-residual-gnuplot" , share__no_argument, 0, 0 }, + { "no-residual-text" , share__no_argument, 0, 0 }, + { "no-error-on-compression-fail", share__no_argument, 0, 0 }, + /* + * undocumented debugging options for the test suite + */ + { "disable-constant-subframes", share__no_argument, 0, 0 }, + { "disable-fixed-subframes" , share__no_argument, 0, 0 }, + { "disable-verbatim-subframes", share__no_argument, 0, 0 }, + { "no-md5-sum" , share__no_argument, 0, 0 }, + + {0, 0, 0, 0} +}; + + +/* + * global to hold command-line option values + */ + +static struct { + FLAC__bool show_help; + FLAC__bool show_explain; + FLAC__bool show_version; + FLAC__bool mode_decode; + FLAC__bool verify; + FLAC__bool treat_warnings_as_errors; + FLAC__bool force_file_overwrite; + FLAC__bool continue_through_decode_errors; + replaygain_synthesis_spec_t replaygain_synthesis_spec; + FLAC__bool lax; + FLAC__bool test_only; + FLAC__bool analyze; + FLAC__bool use_ogg; + FLAC__bool has_serial_number; /* true iff --serial-number was used */ + long serial_number; /* this is the Ogg serial number and is unused for native FLAC */ + FLAC__bool force_to_stdout; + FLAC__bool force_raw_format; + FLAC__bool force_aiff_format; + FLAC__bool force_rf64_format; + FLAC__bool force_wave64_format; + FLAC__bool force_legacy_wave_format; + FLAC__bool force_extensible_wave_format; + FLAC__bool force_aiff_c_none_format; + FLAC__bool force_aiff_c_sowt_format; + FLAC__bool delete_input; + FLAC__bool preserve_modtime; + FLAC__bool keep_foreign_metadata; + FLAC__bool keep_foreign_metadata_if_present; + FLAC__bool replay_gain; + FLAC__bool ignore_chunk_sizes; + FLAC__bool utf8_convert; /* true by default, to convert tag strings from locale to utf-8, false if --no-utf8-convert used */ + const char *cmdline_forced_outfilename; + const char *output_prefix; + analysis_options aopts; + int padding; /* -1 => no -P options were given, 0 => -P- was given, else -P value */ + size_t num_compression_settings; + compression_setting_t compression_settings[64]; /* bad MAGIC NUMBER but buffer overflow is checked */ + const char *skip_specification; + const char *until_specification; + const char *cue_specification; + int format_is_big_endian; + int format_is_unsigned_samples; + int format_channels; + int format_bps; + int format_sample_rate; + FLAC__off_t format_input_size; + char requested_seek_points[5000]; /* bad MAGIC NUMBER but buffer overflow is checked */ + int num_requested_seek_points; /* -1 => no -S options were given, 0 => -S- was given */ + const char *cuesheet_filename; + FLAC__bool cued_seekpoints; + FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */ + FLAC__bool error_on_compression_fail; + FLAC__bool limit_min_bitrate; + + uint32_t num_files; + char **filenames; + + FLAC__StreamMetadata *vorbis_comment; + FLAC__StreamMetadata *pictures[64]; + uint32_t num_pictures; + + struct { + FLAC__bool disable_constant_subframes; + FLAC__bool disable_fixed_subframes; + FLAC__bool disable_verbatim_subframes; + FLAC__bool do_md5; + } debug; +} option_values; + + +/* + * miscellaneous globals + */ + + +#ifndef FUZZ_TOOL_FLAC +int main(int argc, char *argv[]) +#else +static int main_to_fuzz(int argc, char *argv[]) +#endif +{ + int retval = 0; + +#ifdef __EMX__ + _response(&argc, &argv); + _wildcard(&argc, &argv); +#endif +#ifdef _WIN32 + if (get_utf8_argv(&argc, &argv) != 0) { + fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n"); + return 1; + } +#endif + + srand((uint32_t)time(0)); +#ifdef _WIN32 + { + const char *var; + var = getenv("LC_ALL"); + if (!var) + var = getenv("LC_NUMERIC"); + if (!var) + var = getenv("LANG"); + if (!var || strcmp(var, "C") != 0) + setlocale(LC_ALL, ""); + } +#else + setlocale(LC_ALL, ""); +#endif + if(!init_options()) { + flac__utils_printf(stderr, 1, "ERROR: allocating memory\n"); + retval = 1; + } + else { + if((retval = parse_options(argc, argv)) == 0) + retval = do_it(); + } + + free_options(); + + return retval; +} + +int do_it(void) +{ + int retval = 0; + + if(option_values.show_version) { + show_version(); + return 0; + } + else if(option_values.show_explain) { + show_explain(); + return 0; + } + else if(option_values.show_help) { + show_help(); + return 0; + } + else { + if(option_values.num_files == 0) { + if(flac__utils_verbosity_ >= 1) + short_usage(); + return 0; + } + + /* + * tweak options; validate the values + */ + if(!option_values.mode_decode) { + if(0 != option_values.cue_specification) + return usage_error("ERROR: --cue is not allowed in test mode\n"); + } + else { + if(option_values.test_only) { + if(0 != option_values.skip_specification) + return usage_error("ERROR: --skip is not allowed in test mode\n"); + if(0 != option_values.until_specification) + return usage_error("ERROR: --until is not allowed in test mode\n"); + if(0 != option_values.cue_specification) + return usage_error("ERROR: --cue is not allowed in test mode\n"); + if(0 != option_values.analyze) + return usage_error("ERROR: analysis mode (-a/--analyze) and test mode (-t/--test) cannot be used together\n"); + } + } + + if(0 != option_values.cue_specification && (0 != option_values.skip_specification || 0 != option_values.until_specification)) + return usage_error("ERROR: --cue may not be combined with --skip or --until\n"); + + if(option_values.format_channels >= 0) { + if(option_values.format_channels == 0 || (uint32_t)option_values.format_channels > FLAC__MAX_CHANNELS) + return usage_error("ERROR: invalid number of channels '%u', must be > 0 and <= %u\n", option_values.format_channels, FLAC__MAX_CHANNELS); + } + if(option_values.format_bps >= 0) { + if(option_values.format_bps != 8 && option_values.format_bps != 16 && option_values.format_bps != 24 && option_values.format_bps != 32) + return usage_error("ERROR: invalid bits per sample '%u' (must be 8/16/24/32)\n", option_values.format_bps); + } + if(option_values.format_sample_rate >= 0) { + if(!FLAC__format_sample_rate_is_valid(option_values.format_sample_rate)) + return usage_error("ERROR: invalid sample rate '%u', must be > 0 and <= %u\n", option_values.format_sample_rate, FLAC__MAX_SAMPLE_RATE); + } + if((option_values.force_raw_format?1:0) + + (option_values.force_aiff_format?1:0) + + (option_values.force_rf64_format?1:0) + + (option_values.force_wave64_format?1:0) + + (option_values.force_legacy_wave_format?1:0) + + (option_values.force_extensible_wave_format?1:0) + + (option_values.force_aiff_c_none_format?1:0) + + (option_values.force_aiff_c_sowt_format?1:0) + > 1) + return usage_error("ERROR: only one of force format options allowed\n"); + if(option_values.mode_decode) { + if(!option_values.force_raw_format) { + if(option_values.format_is_big_endian >= 0) + return usage_error("ERROR: --endian only allowed with --force-raw-format\n"); + if(option_values.format_is_unsigned_samples >= 0) + return usage_error("ERROR: --sign only allowed with --force-raw-format\n"); + } + if(option_values.format_channels >= 0) + return usage_error("ERROR: --channels not allowed with --decode\n"); + if(option_values.format_bps >= 0) + return usage_error("ERROR: --bps not allowed with --decode\n"); + if(option_values.format_sample_rate >= 0) + return usage_error("ERROR: --sample-rate not allowed with --decode\n"); + } + + if(option_values.ignore_chunk_sizes) { + if(option_values.mode_decode) + return usage_error("ERROR: --ignore-chunk-sizes only allowed for encoding\n"); + if(0 != option_values.until_specification) + return usage_error("ERROR: --ignore-chunk-sizes not allowed with --until\n"); + if(0 != option_values.cue_specification) + return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cue\n"); + if(0 != option_values.cuesheet_filename) + return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cuesheet\n"); + } + if(option_values.replay_gain) { + if(option_values.force_to_stdout) + return usage_error("ERROR: --replay-gain not allowed with -c/--stdout\n"); + if(option_values.mode_decode) + return usage_error("ERROR: --replay-gain only allowed for encoding\n"); + if(option_values.format_channels > 2) + return usage_error("ERROR: --replay-gain can only be done with mono/stereo input\n"); + if(option_values.format_sample_rate >= 0 && !grabbag__replaygain_is_valid_sample_frequency(option_values.format_sample_rate)) + return usage_error("ERROR: invalid sample rate used with --replay-gain\n"); + if( + (option_values.padding >= 0 && option_values.padding < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED) || + (option_values.padding < 0 && FLAC_ENCODE__DEFAULT_PADDING < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED) + ) { + flac__utils_printf(stderr, 1, "NOTE: --replay-gain may leave a small PADDING block even with --no-padding\n"); + } + } + if(option_values.num_files > 1 && option_values.cmdline_forced_outfilename) { + return usage_error("ERROR: -o/--output-name cannot be used with multiple files\n"); + } + if(option_values.cmdline_forced_outfilename && option_values.output_prefix) { + return usage_error("ERROR: --output-prefix conflicts with -o/--output-name\n"); + } + if(!option_values.mode_decode && 0 != option_values.cuesheet_filename && option_values.num_files > 1) { + return usage_error("ERROR: --cuesheet cannot be used when encoding multiple files\n"); + } + if(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present) { + /* we're not going to try and support the re-creation of broken WAVE files */ + if(option_values.ignore_chunk_sizes) + return usage_error("ERROR: using --keep-foreign-metadata cannot be used with --ignore-chunk-sizes\n"); + if(option_values.test_only) + return usage_error("ERROR: --keep-foreign-metadata is not allowed in test mode\n"); + if(option_values.analyze) + return usage_error("ERROR: --keep-foreign-metadata is not allowed in analyis mode\n"); + flac__utils_printf(stderr, 1, "NOTE: --keep-foreign-metadata is a new feature; make sure to test the output file before deleting the original.\n"); + } + } + + flac__utils_printf(stderr, 2, "\n"); + flac__utils_printf(stderr, 2, "flac %s\n", FLAC__VERSION_STRING); + flac__utils_printf(stderr, 2, "Copyright (C) 2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation\n"); + flac__utils_printf(stderr, 2, "flac comes with ABSOLUTELY NO WARRANTY. This is free software, and you are\n"); + flac__utils_printf(stderr, 2, "welcome to redistribute it under certain conditions. Type `flac' for details.\n\n"); + + if(option_values.mode_decode) { + FLAC__bool first = true; + + if(option_values.num_files == 0) { + retval = decode_file("-"); + } + else { + uint32_t i; + if(option_values.num_files > 1) + option_values.cmdline_forced_outfilename = 0; + for(i = 0, retval = 0; i < option_values.num_files; i++) { + if(0 == strcmp(option_values.filenames[i], "-") && !first) + continue; + retval |= decode_file(option_values.filenames[i]); + first = false; + } + } + } + else { /* encode */ + FLAC__bool first = true; + + if(option_values.ignore_chunk_sizes) + flac__utils_printf(stderr, 1, "INFO: Make sure you know what you're doing when using --ignore-chunk-sizes.\n Improper use can cause flac to encode non-audio data as audio.\n"); + + if(option_values.num_files == 0) { + retval = encode_file("-", first, true); + } + else { + uint32_t i; + if(option_values.num_files > 1) + option_values.cmdline_forced_outfilename = 0; + for(i = 0, retval = 0; i < option_values.num_files; i++) { + if(0 == strcmp(option_values.filenames[i], "-") && !first) + continue; + if(encode_file(option_values.filenames[i], first, i == (option_values.num_files-1))) + retval = 1; + else + first = false; + } + if(option_values.replay_gain && retval == 0) { + float album_gain, album_peak; + grabbag__replaygain_get_album(&album_gain, &album_peak); + for(i = 0; i < option_values.num_files; i++) { + const char *error, *outfilename = get_encoded_outfilename(option_values.filenames[i]); + if(0 == outfilename) { + flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", option_values.filenames[i]); + return 1; + } + if(0 != (error = grabbag__replaygain_store_to_file_album(outfilename, album_gain, album_peak, option_values.preserve_modtime))) { + flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain album tags (%s)\n", outfilename, error); + retval = 1; + } + } + } + } + } + + return retval; +} + +FLAC__bool init_options(void) +{ + option_values.show_help = false; + option_values.show_explain = false; + option_values.show_version = false; + option_values.mode_decode = false; + option_values.verify = false; + option_values.treat_warnings_as_errors = false; + option_values.force_file_overwrite = false; + option_values.continue_through_decode_errors = false; + option_values.replaygain_synthesis_spec.apply = false; + option_values.replaygain_synthesis_spec.use_album_gain = true; + option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__HARD; + option_values.replaygain_synthesis_spec.noise_shaping = NOISE_SHAPING_LOW; + option_values.replaygain_synthesis_spec.preamp = 0.0; + option_values.lax = false; + option_values.test_only = false; + option_values.analyze = false; + option_values.use_ogg = false; + option_values.has_serial_number = false; + option_values.serial_number = 0; + option_values.force_to_stdout = false; + option_values.force_raw_format = false; + option_values.force_aiff_format = false; + option_values.force_rf64_format = false; + option_values.force_wave64_format = false; + option_values.force_legacy_wave_format = false; + option_values.force_extensible_wave_format = false; + option_values.force_aiff_c_none_format = false; + option_values.force_aiff_c_sowt_format = false; + option_values.delete_input = false; + option_values.preserve_modtime = true; + option_values.keep_foreign_metadata = false; + option_values.keep_foreign_metadata_if_present = false; + option_values.replay_gain = false; + option_values.ignore_chunk_sizes = false; + option_values.utf8_convert = true; + option_values.cmdline_forced_outfilename = 0; + option_values.output_prefix = 0; + option_values.aopts.do_residual_text = false; + option_values.aopts.do_residual_gnuplot = false; + option_values.padding = -1; + option_values.num_compression_settings = 1; + option_values.compression_settings[0].type = CST_COMPRESSION_LEVEL; + option_values.compression_settings[0].value.t_unsigned = 5; + option_values.skip_specification = 0; + option_values.until_specification = 0; + option_values.cue_specification = 0; + option_values.format_is_big_endian = -1; + option_values.format_is_unsigned_samples = -1; + option_values.format_channels = -1; + option_values.format_bps = -1; + option_values.format_sample_rate = -1; + option_values.format_input_size = (FLAC__off_t)(-1); + option_values.requested_seek_points[0] = '\0'; + option_values.num_requested_seek_points = -1; + option_values.cuesheet_filename = 0; + option_values.cued_seekpoints = true; + option_values.channel_map_none = false; + option_values.error_on_compression_fail = false; + option_values.limit_min_bitrate = false; + + option_values.num_files = 0; + option_values.filenames = 0; + + if(0 == (option_values.vorbis_comment = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT))) + return false; + option_values.num_pictures = 0; + + option_values.debug.disable_constant_subframes = false; + option_values.debug.disable_fixed_subframes = false; + option_values.debug.disable_verbatim_subframes = false; + option_values.debug.do_md5 = true; + + return true; +} + +int parse_options(int argc, char *argv[]) +{ + int short_option; + int option_index = 1; + FLAC__bool had_error = false; + const char *short_opts = "0123456789aA:b:cdefFhHl:mMo:pP:q:r:sS:tT:vVw"; + + while ((short_option = share__getopt_long(argc, argv, short_opts, long_options_, &option_index)) != -1) { + switch (short_option) { + case 0: /* long option with no equivalent short option */ + had_error |= (parse_option(short_option, long_options_[option_index].name, share__optarg) != 0); + break; + case '?': + case ':': + had_error = true; + break; + default: /* short option */ + had_error |= (parse_option(short_option, 0, share__optarg) != 0); + break; + } + } + + if(had_error) { + return 1; + } + + FLAC__ASSERT(share__optind <= argc); + + option_values.num_files = argc - share__optind; + + if(option_values.num_files > 0) { + uint32_t i = 0; + if(0 == (option_values.filenames = malloc(sizeof(char*) * option_values.num_files))) + die("out of memory allocating space for file names list"); + while(share__optind < argc) + option_values.filenames[i++] = local_strdup(argv[share__optind++]); + } + + return 0; +} + +int parse_option(int short_option, const char *long_option, const char *option_argument) +{ + const char *violation; + + if(short_option == 0) { + FLAC__ASSERT(0 != long_option); + if(0 == strcmp(long_option, "totally-silent")) { + flac__utils_verbosity_ = 0; + } + else if(0 == strcmp(long_option, "delete-input-file")) { + option_values.delete_input = true; + } + else if(0 == strcmp(long_option, "preserve-modtime")) { + option_values.preserve_modtime = true; + } + else if(0 == strcmp(long_option, "keep-foreign-metadata")) { + option_values.keep_foreign_metadata = true; + } + else if(0 == strcmp(long_option, "keep-foreign-metadata-if-present")) { + option_values.keep_foreign_metadata_if_present = true; + } + else if(0 == strcmp(long_option, "output-prefix")) { + FLAC__ASSERT(0 != option_argument); + option_values.output_prefix = option_argument; + } + else if(0 == strcmp(long_option, "skip")) { + FLAC__ASSERT(0 != option_argument); + option_values.skip_specification = option_argument; + } + else if(0 == strcmp(long_option, "until")) { + FLAC__ASSERT(0 != option_argument); + option_values.until_specification = option_argument; + } + else if(0 == strcmp(long_option, "input-size")) { + FLAC__ASSERT(0 != option_argument); + { + char *end; + FLAC__int64 ix; + ix = strtoll(option_argument, &end, 10); + if(0 == strlen(option_argument) || *end) + return usage_error("ERROR: --%s must be a number\n", long_option); + option_values.format_input_size = (FLAC__off_t)ix; + if(option_values.format_input_size != ix) /* check if FLAC__off_t is smaller than long long */ + return usage_error("ERROR: --%s too large; this build of flac does not support filesizes over 2GB\n", long_option); + if(option_values.format_input_size <= 0) + return usage_error("ERROR: --%s must be > 0\n", long_option); + } + } + else if(0 == strcmp(long_option, "cue")) { + FLAC__ASSERT(0 != option_argument); + option_values.cue_specification = option_argument; + } + else if(0 == strcmp(long_option, "apply-replaygain-which-is-not-lossless")) { + option_values.replaygain_synthesis_spec.apply = true; + if (0 != option_argument) { + char *p; + option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__NONE; + option_values.replaygain_synthesis_spec.noise_shaping = NOISE_SHAPING_NONE; + option_values.replaygain_synthesis_spec.preamp = strtod(option_argument, &p); + for ( ; *p; p++) { + if (*p == 'a') + option_values.replaygain_synthesis_spec.use_album_gain = true; + else if (*p == 't') + option_values.replaygain_synthesis_spec.use_album_gain = false; + else if (*p == 'l') + option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__PEAK; + else if (*p == 'L') + option_values.replaygain_synthesis_spec.limiter = RGSS_LIMIT__HARD; + else if (*p == 'n' && p[1] >= '0' && p[1] <= '3') { + option_values.replaygain_synthesis_spec.noise_shaping = p[1] - '0'; + p++; + } + else + return usage_error("ERROR: bad specification string \"%s\" for --%s\n", option_argument, long_option); + } + } + } + else if(0 == strcmp(long_option, "channel-map")) { + if (0 == option_argument || strcmp(option_argument, "none")) + return usage_error("ERROR: only --channel-map=none currently supported\n"); + option_values.channel_map_none = true; + } + else if(0 == strcmp(long_option, "cuesheet")) { + FLAC__ASSERT(0 != option_argument); + option_values.cuesheet_filename = option_argument; + } + else if(0 == strcmp(long_option, "picture")) { + const uint32_t max_pictures = sizeof(option_values.pictures)/sizeof(option_values.pictures[0]); + FLAC__ASSERT(0 != option_argument); + if(option_values.num_pictures >= max_pictures) + return usage_error("ERROR: too many --picture arguments, only %u allowed\n", max_pictures); + if(0 == (option_values.pictures[option_values.num_pictures] = grabbag__picture_parse_specification(option_argument, &violation))) + return usage_error("ERROR: (--picture) %s\n", violation); + option_values.num_pictures++; + } + else if(0 == strcmp(long_option, "tag-from-file")) { + FLAC__ASSERT(0 != option_argument); + if(!flac__vorbiscomment_add(option_values.vorbis_comment, option_argument, /*value_from_file=*/true, /*raw=*/!option_values.utf8_convert, &violation)) + return usage_error("ERROR: (--tag-from-file) %s\n", violation); + } + else if(0 == strcmp(long_option, "no-cued-seekpoints")) { + option_values.cued_seekpoints = false; + } + else if(0 == strcmp(long_option, "force-raw-format")) { + option_values.force_raw_format = true; + } + else if(0 == strcmp(long_option, "force-aiff-format")) { + option_values.force_aiff_format = true; + } + else if(0 == strcmp(long_option, "force-rf64-format")) { + option_values.force_rf64_format = true; + } + else if(0 == strcmp(long_option, "force-wave64-format")) { + option_values.force_wave64_format = true; + } + else if(0 == strcmp(long_option, "force-legacy-wave-format")) { + option_values.force_legacy_wave_format = true; + } + else if(0 == strcmp(long_option, "force-extensible-wave-format")) { + option_values.force_extensible_wave_format = true; + } + else if(0 == strcmp(long_option, "force-aiff-c-none-format")) { + option_values.force_aiff_c_none_format = true; + } + else if(0 == strcmp(long_option, "force-aiff-c-sowt-format")) { + option_values.force_aiff_c_sowt_format = true; + } + else if(0 == strcmp(long_option, "lax")) { + option_values.lax = true; + } + else if(0 == strcmp(long_option, "replay-gain")) { + option_values.replay_gain = true; + } + else if(0 == strcmp(long_option, "ignore-chunk-sizes")) { + option_values.ignore_chunk_sizes = true; + } +#if FLAC__HAS_OGG + else if(0 == strcmp(long_option, "ogg")) { + option_values.use_ogg = true; + } + else if(0 == strcmp(long_option, "serial-number")) { + option_values.has_serial_number = true; + option_values.serial_number = atol(option_argument); + } +#endif + else if(0 == strcmp(long_option, "endian")) { + FLAC__ASSERT(0 != option_argument); + if(0 == strncmp(option_argument, "big", strlen(option_argument))) + option_values.format_is_big_endian = true; + else if(0 == strncmp(option_argument, "little", strlen(option_argument))) + option_values.format_is_big_endian = false; + else + return usage_error("ERROR: argument to --endian must be \"big\" or \"little\"\n"); + } + else if(0 == strcmp(long_option, "channels")) { + FLAC__ASSERT(0 != option_argument); + option_values.format_channels = atoi(option_argument); + } + else if(0 == strcmp(long_option, "bps")) { + FLAC__ASSERT(0 != option_argument); + option_values.format_bps = atoi(option_argument); + } + else if(0 == strcmp(long_option, "sample-rate")) { + FLAC__ASSERT(0 != option_argument); + option_values.format_sample_rate = atoi(option_argument); + } + else if(0 == strcmp(long_option, "sign")) { + FLAC__ASSERT(0 != option_argument); + if(0 == strncmp(option_argument, "signed", strlen(option_argument))) + option_values.format_is_unsigned_samples = false; + else if(0 == strncmp(option_argument, "unsigned", strlen(option_argument))) + option_values.format_is_unsigned_samples = true; + else + return usage_error("ERROR: argument to --sign must be \"signed\" or \"unsigned\"\n"); + } + else if(0 == strcmp(long_option, "residual-gnuplot")) { + option_values.aopts.do_residual_gnuplot = true; + } + else if(0 == strcmp(long_option, "residual-text")) { + option_values.aopts.do_residual_text = true; + } + else if(0 == strcmp(long_option, "limit-min-bitrate")) { + option_values.limit_min_bitrate = true; + } + /* + * negatives + */ + else if(0 == strcmp(long_option, "no-preserve-modtime")) { + option_values.preserve_modtime = false; + } + else if(0 == strcmp(long_option, "no-decode-through-errors")) { + option_values.continue_through_decode_errors = false; + } + else if(0 == strcmp(long_option, "no-silent")) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + flac__utils_verbosity_ = 2; +#endif + } + else if(0 == strcmp(long_option, "no-force")) { + option_values.force_file_overwrite = false; + } + else if(0 == strcmp(long_option, "no-seektable")) { + option_values.num_requested_seek_points = 0; + option_values.requested_seek_points[0] = '\0'; + } + else if(0 == strcmp(long_option, "no-delete-input-file")) { + option_values.delete_input = false; + } + else if(0 == strcmp(long_option, "no-keep-foreign-metadata")) { + option_values.keep_foreign_metadata = false; + option_values.keep_foreign_metadata_if_present = false; + } + else if(0 == strcmp(long_option, "no-replay-gain")) { + option_values.replay_gain = false; + } + else if(0 == strcmp(long_option, "no-ignore-chunk-sizes")) { + option_values.ignore_chunk_sizes = false; + } + else if(0 == strcmp(long_option, "no-utf8-convert")) { + option_values.utf8_convert = false; + } + else if(0 == strcmp(long_option, "no-lax")) { + option_values.lax = false; + } +#if FLAC__HAS_OGG + else if(0 == strcmp(long_option, "no-ogg")) { + option_values.use_ogg = false; + } +#endif + else if(0 == strcmp(long_option, "no-exhaustive-model-search")) { + add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, false); + } + else if(0 == strcmp(long_option, "no-mid-side")) { + add_compression_setting_bool(CST_DO_MID_SIDE, false); + add_compression_setting_bool(CST_LOOSE_MID_SIDE, false); + } + else if(0 == strcmp(long_option, "no-adaptive-mid-side")) { + add_compression_setting_bool(CST_DO_MID_SIDE, false); + add_compression_setting_bool(CST_LOOSE_MID_SIDE, false); + } + else if(0 == strcmp(long_option, "no-qlp-coeff-prec-search")) { + add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, false); + } + else if(0 == strcmp(long_option, "no-padding")) { + option_values.padding = 0; + } + else if(0 == strcmp(long_option, "no-verify")) { + option_values.verify = false; + } + else if(0 == strcmp(long_option, "no-warnings-as-errors")) { + option_values.treat_warnings_as_errors = false; + } + else if(0 == strcmp(long_option, "no-residual-gnuplot")) { + option_values.aopts.do_residual_gnuplot = false; + } + else if(0 == strcmp(long_option, "no-residual-text")) { + option_values.aopts.do_residual_text = false; + } + else if(0 == strcmp(long_option, "disable-constant-subframes")) { + option_values.debug.disable_constant_subframes = true; + } + else if(0 == strcmp(long_option, "disable-fixed-subframes")) { + option_values.debug.disable_fixed_subframes = true; + } + else if(0 == strcmp(long_option, "disable-verbatim-subframes")) { + option_values.debug.disable_verbatim_subframes = true; + } + else if(0 == strcmp(long_option, "no-md5-sum")) { + option_values.debug.do_md5 = false; + } + else if(0 == strcmp(long_option, "no-error-on-compression-fail")) { + option_values.error_on_compression_fail = false; + } + else if(0 == strcmp(long_option, "error-on-compression-fail")) { + option_values.error_on_compression_fail = true; + } + } + else { + switch(short_option) { + case 'h': + option_values.show_help = true; + break; + case 'H': + option_values.show_explain = true; + break; + case 'v': + option_values.show_version = true; + break; + case 'd': + option_values.mode_decode = true; + break; + case 'a': + option_values.mode_decode = true; + option_values.analyze = true; + break; + case 't': + option_values.mode_decode = true; + option_values.test_only = true; + break; + case 'c': + option_values.force_to_stdout = true; + break; + case 's': +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + flac__utils_verbosity_ = 1; +#endif + break; + case 'f': + option_values.force_file_overwrite = true; + break; + case 'o': + FLAC__ASSERT(0 != option_argument); + option_values.cmdline_forced_outfilename = option_argument; + break; + case 'F': + option_values.continue_through_decode_errors = true; + break; + case 'T': + FLAC__ASSERT(0 != option_argument); + if(!flac__vorbiscomment_add(option_values.vorbis_comment, option_argument, /*value_from_file=*/false, /*raw=*/!option_values.utf8_convert, &violation)) + return usage_error("ERROR: (-T/--tag) %s\n", violation); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + add_compression_setting_uint32_t(CST_COMPRESSION_LEVEL, short_option-'0'); + break; + case '9': + return usage_error("ERROR: compression level '9' is reserved\n"); + case 'V': + option_values.verify = true; + break; + case 'w': + option_values.treat_warnings_as_errors = true; + break; + case 'S': + FLAC__ASSERT(0 != option_argument); + if(0 == strcmp(option_argument, "-")) { + option_values.num_requested_seek_points = 0; + option_values.requested_seek_points[0] = '\0'; + } + else { + if(option_values.num_requested_seek_points < 0) + option_values.num_requested_seek_points = 0; + option_values.num_requested_seek_points++; + if(strlen(option_values.requested_seek_points)+strlen(option_argument)+2 >= sizeof(option_values.requested_seek_points)) { + return usage_error("ERROR: too many seekpoints requested\n"); + } + else { + size_t len = strlen(option_values.requested_seek_points); + flac_snprintf(option_values.requested_seek_points+len, sizeof(option_values.requested_seek_points) - len, "%s;", option_argument); + } + } + break; + case 'P': + FLAC__ASSERT(0 != option_argument); + option_values.padding = atoi(option_argument); + if(option_values.padding < 0) + return usage_error("ERROR: argument to -%c must be >= 0; for no padding use -%c-\n", short_option, short_option); + break; + case 'b': + { + uint32_t i ; + FLAC__ASSERT(0 != option_argument); + i = atoi(option_argument); + if((i < (int)FLAC__MIN_BLOCK_SIZE || i > (int)FLAC__MAX_BLOCK_SIZE)) + return usage_error("ERROR: invalid blocksize (-%c) '%d', must be >= %u and <= %u\n", short_option, i, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE); + add_compression_setting_uint32_t(CST_BLOCKSIZE, (uint32_t)i); + } + break; + case 'e': + add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, true); + break; + case 'E': + add_compression_setting_bool(CST_DO_ESCAPE_CODING, true); + break; + case 'l': + { + uint32_t i ; + FLAC__ASSERT(0 != option_argument); + i = atoi(option_argument); + if(i > FLAC__MAX_LPC_ORDER) + return usage_error("ERROR: invalid LPC order (-%c) '%d', must be >= %u and <= %u\n", short_option, i, 0, FLAC__MAX_LPC_ORDER); + add_compression_setting_uint32_t(CST_MAX_LPC_ORDER, i); + } + break; + case 'A': + FLAC__ASSERT(0 != option_argument); + add_compression_setting_string(CST_APODIZATION, option_argument); + break; + case 'm': + add_compression_setting_bool(CST_DO_MID_SIDE, true); + add_compression_setting_bool(CST_LOOSE_MID_SIDE, false); + break; + case 'M': + add_compression_setting_bool(CST_DO_MID_SIDE, true); + add_compression_setting_bool(CST_LOOSE_MID_SIDE, true); + break; + case 'p': + add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, true); + break; + case 'q': + { + uint32_t i ; + FLAC__ASSERT(0 != option_argument); + i = atoi(option_argument); + if((i > 0 && (i < FLAC__MIN_QLP_COEFF_PRECISION || i > FLAC__MAX_QLP_COEFF_PRECISION))) + return usage_error("ERROR: invalid value '%d' for qlp coeff precision (-%c), must be 0 or between %u and %u, inclusive\n", i, short_option, FLAC__MIN_QLP_COEFF_PRECISION, FLAC__MAX_QLP_COEFF_PRECISION); + add_compression_setting_uint32_t(CST_QLP_COEFF_PRECISION, i); + } + break; + case 'r': + { + uint32_t i; + char * p; + FLAC__ASSERT(0 != option_argument); + p = strchr(option_argument, ','); + if(0 == p) { + add_compression_setting_uint32_t(CST_MIN_RESIDUAL_PARTITION_ORDER, 0); + i = atoi(option_argument); + if(i > FLAC__MAX_RICE_PARTITION_ORDER) + return usage_error("ERROR: invalid value '%d' for residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER); + add_compression_setting_uint32_t(CST_MAX_RESIDUAL_PARTITION_ORDER, i); + } + else { + i = atoi(option_argument); + if(i > FLAC__MAX_RICE_PARTITION_ORDER) + return usage_error("ERROR: invalid value '%d' for min residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER); + add_compression_setting_uint32_t(CST_MIN_RESIDUAL_PARTITION_ORDER, i); + i = atoi(++p); + if(i > FLAC__MAX_RICE_PARTITION_ORDER) + return usage_error("ERROR: invalid value '%d' for max residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER); + add_compression_setting_uint32_t(CST_MAX_RESIDUAL_PARTITION_ORDER, i); + } + } + break; + case 'R': + { + uint32_t i; + i = atoi(option_argument); + add_compression_setting_uint32_t(CST_RICE_PARAMETER_SEARCH_DIST, i); + } + break; + default: + FLAC__ASSERT(0); + } + } + + return 0; +} + +void free_options(void) +{ + uint32_t i; + if(0 != option_values.filenames) { + for(i = 0; i < option_values.num_files; i++) { + if(0 != option_values.filenames[i]) + free(option_values.filenames[i]); + } + free(option_values.filenames); + } + if(0 != option_values.vorbis_comment) + FLAC__metadata_object_delete(option_values.vorbis_comment); + for(i = 0; i < option_values.num_pictures; i++) + FLAC__metadata_object_delete(option_values.pictures[i]); +} + +void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value) +{ + if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0])) +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + die("too many compression settings"); +#else + return; +#endif + option_values.compression_settings[option_values.num_compression_settings].type = type; + option_values.compression_settings[option_values.num_compression_settings].value.t_bool = value; + option_values.num_compression_settings++; +} + +void add_compression_setting_string(compression_setting_type_t type, const char *value) +{ + if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0])) +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + die("too many compression settings"); +#else + return; +#endif + option_values.compression_settings[option_values.num_compression_settings].type = type; + option_values.compression_settings[option_values.num_compression_settings].value.t_string = value; + option_values.num_compression_settings++; +} + +void add_compression_setting_uint32_t(compression_setting_type_t type, uint32_t value) +{ + if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0])) +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + die("too many compression settings"); +#else + return; +#endif + if(type == CST_COMPRESSION_LEVEL) { + /* Compression level always goes first */ + option_values.compression_settings[0].type = type; + option_values.compression_settings[0].value.t_unsigned = value; + } + else { + option_values.compression_settings[option_values.num_compression_settings].type = type; + option_values.compression_settings[option_values.num_compression_settings].value.t_unsigned = value; + option_values.num_compression_settings++; + } +} + +int usage_error(const char *message, ...) +{ + if(flac__utils_verbosity_ >= 1) { + va_list args; + + FLAC__ASSERT(0 != message); + + va_start(args, message); + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + (void) vfprintf(stderr, message, args); +#endif + + va_end(args); + + printf("Type \"flac\" for a usage summary or \"flac --help\" for all options\n"); + } + + return 1; +} + +void show_version(void) +{ + printf("flac %s\n", FLAC__VERSION_STRING); +} + +static void usage_header(void) +{ + printf("===============================================================================\n"); + printf("flac - Command-line FLAC encoder/decoder version %s\n", FLAC__VERSION_STRING); + printf("Copyright (C) 2000-2009 Josh Coalson\n"); + printf("Copyright (C) 2011-2023 Xiph.Org Foundation\n"); + printf("\n"); + printf("This program is free software; you can redistribute it and/or\n"); + printf("modify it under the terms of the GNU General Public License\n"); + printf("as published by the Free Software Foundation; either version 2\n"); + printf("of the License, or (at your option) any later version.\n"); + printf("\n"); + printf("This program is distributed in the hope that it will be useful,\n"); + printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + printf("GNU General Public License for more details.\n"); + printf("\n"); + printf("You should have received a copy of the GNU General Public License along\n"); + printf("with this program; if not, write to the Free Software Foundation, Inc.,\n"); + printf("51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n"); + printf("===============================================================================\n"); +} + +static void usage_summary(void) +{ + printf("Usage:\n"); + printf("\n"); + printf(" Encoding: flac [] [INPUTFILE [...]]\n"); + printf(" Decoding: flac -d [] [FLACFILE [...]]\n"); + printf(" Testing: flac -t [] [FLACFILE [...]]\n"); + printf("Analyzing: flac -a [] [FLACFILE [...]]\n"); + printf("\n"); + printf("Be sure to read the list of known bugs at:\n"); + printf("http://xiph.org/flac/documentation_bugs.html\n"); + printf("\n"); +} + +void short_usage(void) +{ + usage_header(); + printf("\n"); + printf("This is the short help; for all options use 'flac --help'; for even more\n"); + printf("instructions use 'flac --explain'\n"); + printf("\n"); + printf("Be sure to read the list of known bugs at:\n"); + printf("http://xiph.org/flac/documentation_bugs.html\n"); + printf("\n"); + printf("To encode:\n"); + printf(" flac [-#] [INPUTFILE [...]]\n"); + printf("\n"); + printf(" -# is -0 (fastest compression) to -8 (highest compression); -5 is the default\n"); + printf("\n"); + printf("To decode:\n"); + printf(" flac -d [INPUTFILE [...]]\n"); + printf("\n"); + printf("To test:\n"); + printf(" flac -t [INPUTFILE [...]]\n"); +} + +void show_help(void) +{ + usage_header(); + usage_summary(); + printf("general options:\n"); + printf(" -v, --version Show the flac version number\n"); + printf(" -h, --help Show this screen\n"); + printf(" -H, --explain Show detailed explanation of usage and options\n"); + printf(" -d, --decode Decode (the default behavior is to encode)\n"); + printf(" -t, --test Same as -d except no decoded file is written\n"); + printf(" -a, --analyze Same as -d except an analysis file is written\n"); + printf(" -c, --stdout Write output to stdout\n"); + printf(" -s, --silent Do not write runtime encode/decode statistics\n"); + printf(" --totally-silent Do not print anything, including errors\n"); + printf(" --no-utf8-convert Do not convert tags from local charset to UTF-8\n"); + printf(" -w, --warnings-as-errors Treat all warnings as errors\n"); + printf(" -f, --force Force overwriting of output files\n"); + printf(" -o, --output-name=FILENAME Force the output file name\n"); + printf(" --output-prefix=STRING Prepend STRING to output names\n"); + printf(" --delete-input-file Deletes after a successful encode/decode\n"); + printf(" --preserve-modtime Output files keep timestamp of input (default)\n"); + printf(" --keep-foreign-metadata Save/restore WAVE or AIFF non-audio chunks\n"); + printf(" --keep-foreign-metadata-if-present Save/restore WAVE or AIFF non-audio\n"); + printf(" but not return an error when no such chunks are found\n"); + printf(" --skip={#|mm:ss.ss} Skip the given initial samples for each input\n"); + printf(" --until={#|[+|-]mm:ss.ss} Stop at the given sample for each input file\n"); +#if FLAC__HAS_OGG + printf(" --ogg Use Ogg as transport layer\n"); + printf(" --serial-number Serial number to use for the FLAC stream\n"); +#endif + printf("analysis options:\n"); + printf(" --residual-text Include residual signal in text output\n"); + printf(" --residual-gnuplot Generate gnuplot files of residual distribution\n"); + printf("decoding options:\n"); + printf(" -F, --decode-through-errors Continue decoding through stream errors\n"); + printf(" --cue=[#.#][-[#.#]] Set the beginning and ending cuepoints to decode\n"); + printf("encoding options:\n"); + printf(" -V, --verify Verify a correct encoding\n"); + printf(" --lax Allow encoder to generate non-Subset files\n"); + printf(" --ignore-chunk-sizes Ignore data chunk sizes in WAVE/AIFF files\n"); + printf(" --replay-gain Calculate ReplayGain & store in FLAC tags\n"); + printf(" --cuesheet=FILENAME Import cuesheet and store in CUESHEET block\n"); + printf(" --picture=SPECIFICATION Import picture and store in PICTURE block\n"); + printf(" -T, --tag=FIELD=VALUE Add a FLAC tag; may appear multiple times\n"); + printf(" --tag-from-file=FIELD=FILENAME Like --tag but gets value from file\n"); + printf(" -S, --seekpoint={#|X|#x|#s} Add seek point(s)\n"); + printf(" -P, --padding=# Write a PADDING block of length #\n"); + printf(" -0, --compression-level-0, --fast Synonymous with -l 0 -b 1152 -r 3\n"); + printf(" -1, --compression-level-1 Synonymous with -l 0 -b 1152 -M -r 3\n"); + printf(" -2, --compression-level-2 Synonymous with -l 0 -b 1152 -m -r 3\n"); + printf(" -3, --compression-level-3 Synonymous with -l 6 -b 4096 -r 4\n"); + printf(" -4, --compression-level-4 Synonymous with -l 8 -b 4096 -M -r 4\n"); + printf(" -5, --compression-level-5 Synonymous with -l 8 -b 4096 -m -r 5\n"); + printf(" -6, --compression-level-6 Synonymous with -l 8 -b 4096 -m -r 6\n"); + printf(" -A subdivide_tukey(2)\n"); + printf(" -7, --compression-level-7 Synonymous with -l 12 -b 4096 -m -r 6\n"); + printf(" -A subdivide_tukey(2)\n"); + printf(" -8, --compression-level-8, --best Synonymous with -l 12 -b 4096 -m -r 6\n"); + printf(" -A subdivide_tukey(3)\n"); + printf(" -b, --blocksize=# Specify blocksize in samples\n"); + printf(" -m, --mid-side Try mid-side coding for each frame\n"); + printf(" -M, --adaptive-mid-side Adaptive mid-side coding for all frames\n"); + printf(" -e, --exhaustive-model-search Do exhaustive model search (expensive!)\n"); + printf(" -A, --apodization=\"function\" Window audio data with given the function\n"); + printf(" -l, --max-lpc-order=# Max LPC order; 0 => only fixed predictors\n"); + printf(" -p, --qlp-coeff-precision-search Exhaustively search LP coeff quantization\n"); + printf(" -q, --qlp-coeff-precision=# Specify precision in bits\n"); + printf(" -r, --rice-partition-order=[#,]# Set [min,]max residual partition order\n"); + printf(" --limit-min-bitrate Limit minimum bitrate (for streaming)\n"); + printf("format options:\n"); + printf(" --force-raw-format Treat input or output as raw samples\n"); + printf(" --force-aiff-format Decode to AIFF format\n"); + printf(" --force-rf64-format Decode to RF64 format\n"); + printf(" --force-wave64-format Decode to Wave64 format\n"); + printf(" --force-legacy-wave-format Decode to legacy wave format\n"); + printf(" --force-extensible-wave-format Decode to extensible wave format\n"); + printf(" --force-aiff-c-none-format Decode to AIFF-C NONE format\n"); + printf(" --force-aiff-c-sowt-format Decode to AIFF-C sowt format\n"); + printf("raw format options:\n"); + printf(" --endian={big|little} Set byte order for samples\n"); + printf(" --channels=# Number of channels\n"); + printf(" --bps=# Number of bits per sample\n"); + printf(" --sample-rate=# Sample rate in Hz\n"); + printf(" --sign={signed|unsigned} Sign of samples\n"); + printf(" --input-size=# Size of the raw input in bytes\n"); + printf("negative options:\n"); + printf(" --no-adaptive-mid-side\n"); + printf(" --no-cued-seekpoints\n"); + printf(" --no-decode-through-errors\n"); + printf(" --no-delete-input-file\n"); + printf(" --no-error-on-compression-fail\n"); + printf(" --no-preserve-modtime\n"); + printf(" --no-keep-foreign-metadata\n"); + printf(" --no-exhaustive-model-search\n"); + printf(" --no-lax\n"); + printf(" --no-mid-side\n"); +#if FLAC__HAS_OGG + printf(" --no-ogg\n"); +#endif + printf(" --no-padding\n"); + printf(" --no-qlp-coeff-prec-search\n"); + printf(" --no-replay-gain\n"); + printf(" --no-residual-gnuplot\n"); + printf(" --no-residual-text\n"); + printf(" --no-ignore-chunk-sizes\n"); + printf(" --no-seektable\n"); + printf(" --no-silent\n"); + printf(" --no-force\n"); + printf(" --no-verify\n"); + printf(" --no-warnings-as-errors\n"); +} + +void show_explain(void) +{ + usage_header(); + usage_summary(); + printf("For encoding:\n"); + printf(" The input file(s) may be a PCM WAVE, Wave64, RF64 file, AIFF (or uncompressed\n"); + printf(" AIFF-C) file, or raw samples. The output file(s) will be in native FLAC\n"); + printf(" or Ogg FLAC format\n"); + printf("For decoding, the reverse is true.\n"); + printf("\n"); + printf("A single INPUTFILE may be - for stdin. No INPUTFILE implies stdin. Use of\n"); + printf("stdin implies -c (write to stdout). Normally you should use:\n"); + printf(" flac [options] -o outfilename or flac -d [options] -o outfilename\n"); + printf("instead of:\n"); + printf(" flac [options] > outfilename or flac -d [options] > outfilename\n"); + printf("since the former allows flac to seek backwards to write the STREAMINFO or\n"); + printf("WAVE/AIFF header contents when necessary.\n"); + printf("\n"); + printf("general options:\n"); + printf(" -v, --version Show the flac version number\n"); + printf(" -h, --help Show basic usage a list of all options\n"); + printf(" -H, --explain Show this screen\n"); + printf(" -d, --decode Decode (the default behavior is to encode)\n"); + printf(" -t, --test Same as -d except no decoded file is written\n"); + printf(" -a, --analyze Same as -d except an analysis file is written\n"); + printf(" -c, --stdout Write output to stdout\n"); + printf(" -s, --silent Do not write runtime encode/decode statistics\n"); + printf(" --totally-silent Do not print anything of any kind, including\n"); + printf(" warnings or errors. The exit code will be the\n"); + printf(" only way to determine successful completion.\n"); + printf(" --no-utf8-convert Do not convert tags from local charset to UTF-8.\n"); + printf(" This is useful for scripts, and setting tags in\n"); + printf(" situations where the locale is wrong. This\n"); + printf(" option must appear before any tag options!\n"); + printf(" -w, --warnings-as-errors Treat all warnings as errors\n"); + printf(" -f, --force Force overwriting of output files\n"); + printf(" -o, --output-name=FILENAME Force the output file name; usually flac just\n"); + printf(" changes the extension. May only be used when\n"); + printf(" encoding a single file. May not be used in\n"); + printf(" conjunction with --output-prefix.\n"); + printf(" --output-prefix=STRING Prefix each output file name with the given\n"); + printf(" STRING. This can be useful for encoding or\n"); + printf(" decoding files to a different directory. Make\n"); + printf(" sure if your STRING is a path name that it ends\n"); + printf(" with a '/' slash.\n"); + printf(" --delete-input-file Automatically delete the input file after a\n"); + printf(" successful encode or decode. If there was an\n"); + printf(" error (including a verify error) the input file\n"); + printf(" is left intact.\n"); + printf(" --preserve-modtime Output files have their timestamps/permissions\n"); + printf(" set to match those of their inputs (this is\n"); + printf(" default). Use --no-preserve-modtime to make\n"); + printf(" output files have the current time and default\n"); + printf(" permissions.\n"); + printf(" --keep-foreign-metadata If encoding, save WAVE or AIFF non-audio chunks\n"); + printf(" in FLAC metadata. If decoding, restore any saved\n"); + printf(" non-audio chunks from FLAC metadata when writing\n"); + printf(" the decoded file. Foreign metadata cannot be\n"); + printf(" transcoded, e.g. WAVE chunks saved in a FLAC file\n"); + printf(" cannot be restored when decoding to AIFF. Input\n"); + printf(" and output must be regular files, not stdin/out.\n"); + printf(" With this option, FLAC will pick the right\n"); + printf(" output format on decoding.\n"); + printf(" --keep-foreign-metadata-if-present As previous option, but do not throw\n"); + printf(" an error in case no foreign metadata is found,\n"); + printf(" the wrong kind of foreign metadata is found (on\n"); + printf(" decoding) or if the foreign could not be parsed,\n"); + printf(" i.e. all foreign metadata related errors are\n"); + printf(" treated as warnings.\n"); + printf(" --skip={#|mm:ss.ss} Skip the first # samples of each input file; can\n"); + printf(" be used both for encoding and decoding. The\n"); + printf(" alternative form mm:ss.ss can be used to specify\n"); + printf(" minutes, seconds, and fractions of a second.\n"); + printf(" --until={#|[+|-]mm:ss.ss} Stop at the given sample number for each input\n"); + printf(" file. The given sample number is not included\n"); + printf(" in the decoded output. The alternative form\n"); + printf(" mm:ss.ss can be used to specify minutes,\n"); + printf(" seconds, and fractions of a second. If a `+'\n"); + printf(" sign is at the beginning, the --until point is\n"); + printf(" relative to the --skip point. If a `-' sign is\n"); + printf(" at the beginning, the --until point is relative\n"); + printf(" to end of the audio.\n"); +#if FLAC__HAS_OGG + printf(" --ogg When encoding, generate Ogg FLAC output instead\n"); + printf(" of native FLAC. Ogg FLAC streams are FLAC\n"); + printf(" streams wrapped in an Ogg transport layer. The\n"); + printf(" resulting file should have an '.oga' extension\n"); + printf(" and will still be decodable by flac. When\n"); + printf(" decoding, force the input to be treated as\n"); + printf(" Ogg FLAC. This is useful when piping input\n"); + printf(" from stdin or when the filename does not end in\n"); + printf(" '.oga' or '.ogg'.\n"); + printf(" --serial-number Serial number to use for the FLAC stream. When\n"); + printf(" encoding and no serial number is given, flac\n"); + printf(" uses a random one. If encoding to multiple files\n"); + printf(" the serial number is incremented for each file.\n"); + printf(" When decoding and no number is given, flac uses\n"); + printf(" the serial number of the first page.\n"); +#endif + printf("analysis options:\n"); + printf(" --residual-text Include residual signal in text output. This\n"); + printf(" will make the file very big, much larger than\n"); + printf(" even the decoded file.\n"); + printf(" --residual-gnuplot Generate gnuplot files of residual distribution\n"); + printf(" of each subframe\n"); + printf("decoding options:\n"); + printf(" -F, --decode-through-errors By default flac stops decoding with an error\n"); + printf(" and removes the partially decoded file if it\n"); + printf(" encounters a bitstream error. With -F, errors\n"); + printf(" are still printed but flac will continue\n"); + printf(" decoding to completion. Note that errors may\n"); + printf(" cause the decoded audio to be missing some\n"); + printf(" samples or have silent sections.\n"); + printf(" --cue=[#.#][-[#.#]] Set the beginning and ending cuepoints to\n"); + printf(" decode. The optional first #.# is the track and\n"); + printf(" index point at which decoding will start; the\n"); + printf(" default is the beginning of the stream. The\n"); + printf(" optional second #.# is the track and index point\n"); + printf(" at which decoding will end; the default is the\n"); + printf(" end of the stream. If the cuepoint does not\n"); + printf(" exist, the closest one before it (for the start\n"); + printf(" point) or after it (for the end point) will be\n"); + printf(" used. The cuepoints are merely translated into\n"); + printf(" sample numbers then used as --skip and --until.\n"); + printf(" A CD track can always be cued by, for example,\n"); + printf(" --cue=9.1-10.1 for track 9, even if the CD has\n"); + printf(" no 10th track.\n"); + printf("encoding options:\n"); + printf(" -V, --verify Verify a correct encoding by decoding the\n"); + printf(" output in parallel and comparing to the\n"); + printf(" original\n"); + printf(" --lax Allow encoder to generate non-Subset files\n"); + printf(" --ignore-chunk-sizes Ignore data chunk sizes in WAVE/AIFF files;\n"); + printf(" useful when piping data from programs which\n"); + printf(" generate bogus data chunk sizes.\n"); + printf(" --replay-gain Calculate ReplayGain values and store them as\n"); + printf(" FLAC tags. Title gains/peaks will be computed\n"); + printf(" for each file, and an album gain/peak will be\n"); + printf(" computed for all files. All input files must\n"); + printf(" have the same resolution, sample rate, and\n"); + printf(" number of channels. Only mono and stereo files\n"); + printf(" are allowed, and the sample rate must be 8,\n"); + printf(" 11.025, 12, 16, 18.9, 22.05, 24, 28, 32, 36,\n"); + printf(" 37.8, 44.1, 48, 56, 64, 72, 75.6, 88.2, 96, 112,\n"); + printf(" 128, 144, 151.2, 176.4, 192, 224, 256, 288,\n"); + printf(" 302.4, 352.8, 384, 448, 512, 576, or 604.8 kHz.\n"); + printf(" NOTE: this option may also leave a few extra\n"); + printf(" bytes in the PADDING block.\n"); + printf(" --cuesheet=FILENAME Import the given cuesheet file and store it in\n"); + printf(" a CUESHEET metadata block. This option may only\n"); + printf(" be used when encoding a single file. A\n"); + printf(" seekpoint will be added for each index point in\n"); + printf(" the cuesheet to the SEEKTABLE unless\n"); + printf(" --no-cued-seekpoints is specified.\n"); + printf(" --picture=SPECIFICATION Import a picture and store it in a PICTURE block.\n"); + printf(" More than one --picture command can be specified.\n"); + printf(" The SPECIFICATION can either be a simple filename\n"); + printf(" for the picture file, or a complete specification\n"); + printf(" whose parts are separated by | characters. Some\n"); + printf(" parts may be left empty to invoke default values.\n"); + printf(" Using a filename is shorthand for \"||||FILE\".\n"); + printf(" The SPECIFICATION format is:\n"); + printf(" [TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE\n"); + printf(" TYPE is optional; it is a number from one of:\n"); + printf(" 0: Other\n"); + printf(" 1: 32x32 pixels 'file icon' (PNG only)\n"); + printf(" 2: Other file icon\n"); + printf(" 3: Cover (front)\n"); + printf(" 4: Cover (back)\n"); + printf(" 5: Leaflet page\n"); + printf(" 6: Media (e.g. label side of CD)\n"); + printf(" 7: Lead artist/lead performer/soloist\n"); + printf(" 8: Artist/performer\n"); + printf(" 9: Conductor\n"); + printf(" 10: Band/Orchestra\n"); + printf(" 11: Composer\n"); + printf(" 12: Lyricist/text writer\n"); + printf(" 13: Recording Location\n"); + printf(" 14: During recording\n"); + printf(" 15: During performance\n"); + printf(" 16: Movie/video screen capture\n"); + printf(" 17: A bright coloured fish\n"); + printf(" 18: Illustration\n"); + printf(" 19: Band/artist logotype\n"); + printf(" 20: Publisher/Studio logotype\n"); + printf(" The default is 3 (front cover). There may only be one picture each\n"); + printf(" of type 1 and 2 in a file.\n"); + printf(" MIME-TYPE is optional; if left blank, it will be detected from the\n"); + printf(" file. For best compatibility with players, use pictures with MIME\n"); + printf(" type image/jpeg or image/png. The MIME type can also be --> to\n"); + printf(" mean that FILE is actually a URL to an image, though this use is\n"); + printf(" discouraged.\n"); + printf(" DESCRIPTION is optional; the default is an empty string\n"); + printf(" The next part specifies the resolution and color information. If\n"); + printf(" the MIME-TYPE is image/jpeg, image/png, or image/gif, you can\n"); + printf(" usually leave this empty and they can be detected from the file.\n"); + printf(" Otherwise, you must specify the width in pixels, height in pixels,\n"); + printf(" and color depth in bits-per-pixel. If the image has indexed colors\n"); + printf(" you should also specify the number of colors used.\n"); + printf(" FILE is the path to the picture file to be imported, or the URL if\n"); + printf(" MIME type is -->\n"); + printf(" -T, --tag=FIELD=VALUE Add a FLAC tag. Make sure to quote the\n"); + printf(" comment if necessary. This option may appear\n"); + printf(" more than once to add several comments. NOTE:\n"); + printf(" all tags will be added to all encoded files.\n"); + printf(" --tag-from-file=FIELD=FILENAME Like --tag, except FILENAME is a file\n"); + printf(" whose contents will be read verbatim to set the\n"); + printf(" tag value. The contents will be converted to\n"); + printf(" UTF-8 from the local charset. This can be used\n"); + printf(" to store a cuesheet in a tag (e.g.\n"); + printf(" --tag-from-file=\"CUESHEET=image.cue\"). Do not\n"); + printf(" try to store binary data in tag fields! Use\n"); + printf(" APPLICATION blocks for that.\n"); + printf(" -S, --seekpoint={#|X|#x|#s} Include a point or points in a SEEKTABLE\n"); + printf(" # : a specific sample number for a seek point\n"); + printf(" X : a placeholder point (always goes at the end of the SEEKTABLE)\n"); + printf(" #x : # evenly spaced seekpoints, the first being at sample 0\n"); + printf(" #s : a seekpoint every # seconds; # does not have to be a whole number\n"); + printf(" You may use many -S options; the resulting SEEKTABLE will be the unique-\n"); + printf(" ified union of all such values.\n"); + printf(" With no -S options, flac defaults to '-S 10s'. Use -S- for no SEEKTABLE.\n"); + printf(" Note: -S #x and -S #s will not work if the encoder can't determine the\n"); + printf(" input size before starting.\n"); + printf(" Note: if you use -S # and # is >= samples in the input, there will be\n"); + printf(" either no seek point entered (if the input size is determinable\n"); + printf(" before encoding starts) or a placeholder point (if input size is not\n"); + printf(" determinable)\n"); + printf(" -P, --padding=# Tell the encoder to write a PADDING metadata\n"); + printf(" block of the given length (in bytes) after the\n"); + printf(" STREAMINFO block. This is useful if you plan\n"); + printf(" to tag the file later with an APPLICATION\n"); + printf(" block; instead of having to rewrite the entire\n"); + printf(" file later just to insert your block, you can\n"); + printf(" write directly over the PADDING block. Note\n"); + printf(" that the total length of the PADDING block will\n"); + printf(" be 4 bytes longer than the length given because\n"); + printf(" of the 4 metadata block header bytes. You can\n"); + printf(" force no PADDING block at all to be written with\n"); + printf(" --no-padding. The encoder writes a PADDING\n"); + printf(" block of 8192 bytes by default, or 65536 bytes\n"); + printf(" if the input audio is more than 20 minutes long.\n"); + printf(" -b, --blocksize=# Specify the blocksize in samples; the default is\n"); + printf(" 1152 for -l 0, else 4096; for subset streams this\n"); + printf(" must be <= 4608 if the samplerate <= 48kHz,\n"); + printf(" for subset streams with a higher samplerates it\n"); + printf(" must be <= 16384.\n"); + printf(" -0, --compression-level-0, --fast Synonymous with -l 0 -b 1152 -r 3\n"); + printf(" --no-mid-side\n"); + printf(" -1, --compression-level-1 Synonymous with -l 0 -b 1152 -M -r 3\n"); + printf(" -2, --compression-level-2 Synonymous with -l 0 -b 1152 -m -r 3\n"); + printf(" -3, --compression-level-3 Synonymous with -l 6 -b 4096 -r 4\n"); + printf(" --no-mid-side\n"); + printf(" -4, --compression-level-4 Synonymous with -l 8 -b 4096 -M -r 4\n"); + printf(" -5, --compression-level-5 Synonymous with -l 8 -b 4096 -m -r 5\n"); + printf(" -5 is the default setting\n"); + printf(" -6, --compression-level-6 Synonymous with -l 8 -b 4096 -m -r 6\n"); + printf(" -A subdivide_tukey(2)\n"); + printf(" -7, --compression-level-7 Synonymous with -l 12 -b 4096 -m -r 6\n"); + printf(" -A subdivide_tukey(2)\n"); + printf(" -8, --compression-level-8, --best Synonymous with -l 12 -b 4096 -m -r 6\n"); + printf(" -A subdivide_tukey(3)\n"); + printf(" -m, --mid-side Try mid-side coding for each frame\n"); + printf(" (stereo only)\n"); + printf(" -M, --adaptive-mid-side Adaptive mid-side coding for all frames\n"); + printf(" (stereo only)\n"); + printf(" -e, --exhaustive-model-search Do exhaustive model search (expensive!)\n"); + printf(" -A, --apodization=\"function\" Window audio data with given the function.\n"); + printf(" The functions are: bartlett, bartlett_hann,\n"); + printf(" blackman, blackman_harris_4term_92db,\n"); + printf(" connes, flattop, gauss(STDDEV), hamming,\n"); + printf(" hann, kaiser_bessel, nuttall, rectangle,\n"); + printf(" triangle, tukey(P), welch, partial_tukey(n)\n"); + printf(" punchout_tukey(n) and subdivide_tukey(n).\n"); + printf(" More than one may be specified but encoding\n"); + printf(" time is a multiple of the number of\n"); + printf(" functions since they are each tried in \n"); + printf(" turn. The encoder chooses suitable\n"); + printf(" defaults in the absence of any -A options.\n"); + printf(" -l, --max-lpc-order=# Max LPC order; 0 => only fixed predictors.\n"); + printf(" Must be <= 12 for Subset streams if sample\n"); + printf(" rate is <=48kHz.\n"); + printf(" -p, --qlp-coeff-precision-search Do exhaustive search of LP coefficient\n"); + printf(" quantization (expensive!); overrides -q;\n"); + printf(" does nothing if using -l 0\n"); + printf(" -q, --qlp-coeff-precision=# Specify precision in bits of quantized\n"); + printf(" linear-predictor coefficients; 0 => let\n"); + printf(" encoder decide (the minimum is %u, the\n", FLAC__MIN_QLP_COEFF_PRECISION); + printf(" default is -q 0)\n"); + printf(" -r, --rice-partition-order=[#,]# Set [min,]max residual partition order\n"); + printf(" (# is 0 to 15 inclusive; min defaults to 0;\n"); + printf(" the default is -r 0; above 4 does not\n"); + printf(" usually help much)\n"); + printf(" --limit-min-bitrate Limit minimum bitrate by not allowing\n"); + printf(" frames consisting of only constant\n"); + printf(" subframes. This ensures a bitrate of at\n"); + printf(" least 1 bit/sample, for example 48kbit/s\n"); + printf(" for 48kHz input. This is mostly beneficial\n"); + printf(" for internet streaming.\n"); + printf("format options:\n"); + printf(" --force-raw-format Force input (when encoding) or output (when\n"); + printf(" decoding) to be treated as raw samples\n"); + printf(" --force-aiff-format\n"); + printf(" --force-rf64-format\n"); + printf(" --force-wave64-format\n"); + printf(" Force the decoder to output AIFF/RF64/WAVE64 format respectively.\n"); + printf(" This option is not needed if the output filename (as set by -o)\n"); + printf(" ends with *.aif* or *.aiff*, *.rf64* and *.w64* respectively. Also,\n"); + printf(" this option has no effect when encoding since input is\n"); + printf(" auto-detected. When none of these options nor\n"); + printf(" --keep-foreign-metadata are given and no output filename is set,\n"); + printf(" the output format is WAV by default.\n"); + printf(" --force-legacy-wave-format\n"); + printf(" --force-extensible-wave-format\n"); + printf(" Instruct the decoder to output a WAVE file with WAVE_FORMAT_PCM and\n"); + printf(" WAVE_FORMAT_EXTENSIBLE respectively. If none of these options nor\n"); + printf(" --keep-foreign-metadata are given, FLAC outputs WAVE_FORMAT_PCM\n"); + printf(" for mono or stereo with a bit depth of 8 or 16 bits, and\n"); + printf(" WAVE_FORMAT_EXTENSIBLE for all other audio formats.\n"); + printf(" --force-aiff-c-none-format\n"); + printf(" --force-aiff-c-sowt-format\n"); + printf(" Instruct the decoder to output an AIFF-C file with format NONE and\n"); + printf(" sowt respectively.\n"); + printf("raw format options:\n"); + printf(" --endian={big|little} Set byte order for samples\n"); + printf(" --channels=# Number of channels\n"); + printf(" --bps=# Number of bits per sample\n"); + printf(" --sample-rate=# Sample rate in Hz\n"); + printf(" --sign={signed|unsigned} Sign of samples\n"); + printf(" --input-size=# Size of the raw input in bytes. If you are\n"); + printf(" encoding raw samples from stdin, you must set\n"); + printf(" this option in order to be able to use --skip,\n"); + printf(" --until, --cuesheet, or other options that need\n"); + printf(" to know the size of the input beforehand. If\n"); + printf(" the size given is greater than what is found in\n"); + printf(" the input stream, the encoder will complain\n"); + printf(" about an unexpected end-of-file. If the size\n"); + printf(" given is less, samples will be truncated.\n"); + printf("negative options:\n"); + printf(" --no-adaptive-mid-side\n"); + printf(" --no-cued-seekpoints\n"); + printf(" --no-decode-through-errors\n"); + printf(" --no-delete-input-file\n"); + printf(" --no-preserve-modtime\n"); + printf(" --no-keep-foreign-metadata\n"); + printf(" --no-exhaustive-model-search\n"); + printf(" --no-lax\n"); + printf(" --no-mid-side\n"); +#if FLAC__HAS_OGG + printf(" --no-ogg\n"); +#endif + printf(" --no-padding\n"); + printf(" --no-qlp-coeff-prec-search\n"); + printf(" --no-residual-gnuplot\n"); + printf(" --no-residual-text\n"); + printf(" --no-ignore-chunk-sizes\n"); + printf(" --no-seektable\n"); + printf(" --no-silent\n"); + printf(" --no-force\n"); + printf(" --no-verify\n"); + printf(" --no-warnings-as-errors\n"); +} + +void format_mistake(const char *infilename, FileFormat wrong, FileFormat right) +{ + /* WATCHOUT: indexed by FileFormat */ + flac__utils_printf(stderr, 1, "WARNING: %s is not a%s file; treating as a%s file\n", infilename, FileFormatString[wrong], FileFormatString[right]); +} + +int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file) +{ + FILE *encode_infile; + FLAC__byte lookahead[12]; + uint32_t lookahead_length = 0, master_chunk_size = 0; + FileFormat input_format = FORMAT_RAW; + int retval; + FLAC__off_t infilesize; + encode_options_t encode_options; + const char *outfilename = get_encoded_outfilename(infilename); /* the final name of the encoded file */ + /* internal_outfilename is the file we will actually write to; it will be a temporary name if infilename==outfilename */ + char *internal_outfilename = 0; /* NULL implies 'use outfilename' */ + size_t infilename_length; + + if(0 == outfilename) { + flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename); + return 1; + } + + if(0 == strcmp(infilename, "-")) { + infilesize = (FLAC__off_t)(-1); + encode_infile = grabbag__file_get_binary_stdin(); + } + else + { + infilesize = grabbag__file_get_filesize(infilename); + if(0 == (encode_infile = flac_fopen(infilename, "rb"))) { + flac__utils_printf(stderr, 1, "ERROR: can't open input file %s: %s\n", infilename, strerror(errno)); + return 1; + } + } + + if(!option_values.force_raw_format) { + /* first set format based on name */ + infilename_length = strlen(infilename); + if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".wav")) + input_format = FORMAT_WAVE; + else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".rf64")) + input_format = FORMAT_RF64; + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".w64")) + input_format = FORMAT_WAVE64; + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".aif")) + input_format = FORMAT_AIFF; + else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".aiff")) + input_format = FORMAT_AIFF; + else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".flac")) + input_format = FORMAT_FLAC; + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".oga")) + input_format = FORMAT_OGGFLAC; + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".ogg")) + input_format = FORMAT_OGGFLAC; + + /* attempt to guess the file type based on the first 12 bytes */ + if((lookahead_length = fread(lookahead, 1, 12, encode_infile)) < 12) { + /* all supported non-raw formats have at least 12 bytes of header to read */ + if(input_format != FORMAT_RAW) { + format_mistake(infilename, input_format, FORMAT_RAW); + if(option_values.treat_warnings_as_errors) { + conditional_fclose(encode_infile); + return 1; + } + } + /* force to raw */ + input_format = FORMAT_RAW; + } + else { + if(!memcmp(lookahead, "ID3", 3)) { + flac__utils_printf(stderr, 1, "ERROR: input file %s has an ID3v2 tag\n", infilename); + conditional_fclose(encode_infile); + return 1; + } + else if(!memcmp(lookahead, "RIFF", 4) && !memcmp(lookahead+8, "WAVE", 4)) + input_format = FORMAT_WAVE; + else if(!memcmp(lookahead, "RF64", 4) && !memcmp(lookahead+8, "WAVE", 4)) + input_format = FORMAT_RF64; + else if(!memcmp(lookahead, "riff\x2E\x91\xCF\x11\xA5\xD6\x28\xDB", 12)) /* just check 1st 12 bytes of GUID */ + input_format = FORMAT_WAVE64; + else if(!memcmp(lookahead, "FORM", 4) && !memcmp(lookahead+8, "AIFF", 4)) + input_format = FORMAT_AIFF; + else if(!memcmp(lookahead, "FORM", 4) && !memcmp(lookahead+8, "AIFC", 4)) + input_format = FORMAT_AIFF_C; + else if(!memcmp(lookahead, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) + input_format = FORMAT_FLAC; + /*@@@ this could be made more accurate by looking at the first packet to make sure it's Ogg FLAC and not, say, Ogg Vorbis. we do catch such problems later though. */ + else if(!memcmp(lookahead, "OggS", 4)) + input_format = FORMAT_OGGFLAC; + else { + /* didn't find header of any supported format */ + if(input_format != FORMAT_RAW) { + format_mistake(infilename, input_format, FORMAT_RAW); + if(option_values.treat_warnings_as_errors) { + conditional_fclose(encode_infile); + return 1; + } + } + /* force to raw */ + input_format = FORMAT_RAW; + } + } + } + + if(!option_values.ignore_chunk_sizes + && (input_format == FORMAT_WAVE || input_format == FORMAT_AIFF || input_format == FORMAT_AIFF_C) + && infilesize >= UINT32_MAX) { + conditional_fclose(encode_infile); + return usage_error("ERROR: file %s is too large to be valid.\n" + "Please consult the manual on the --ignore-chunk-sizes option\n\n", infilename); + } + + if(input_format == FORMAT_WAVE || input_format == FORMAT_AIFF || input_format == FORMAT_AIFF_C) { + memcpy(&master_chunk_size,lookahead+4,sizeof(master_chunk_size)); + if((input_format != FORMAT_WAVE) != CPU_IS_BIG_ENDIAN /* logical xor */) + /* true for WAVE on big endian CPUs or AIFF/AIFF-C on little endian CPUs */ + master_chunk_size = ENDSWAP_32(master_chunk_size); + + if(infilesize != (FLAC__off_t)(-1) && infilesize > 8 && (infilesize - 8) != master_chunk_size) { + flac__utils_printf(stderr, 1, "WARNING: %s chunk size of file %s does not agree with filesize\n", (input_format == FORMAT_WAVE)?"RIFF":"FORM", infilename); + if(option_values.treat_warnings_as_errors) + return 1; + } + } + + if(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present) { + if(encode_infile == stdin || option_values.force_to_stdout) { + conditional_fclose(encode_infile); + return usage_error("ERROR: --keep-foreign-metadata cannot be used when encoding from stdin or to stdout\n"); + } + if(input_format != FORMAT_WAVE && input_format != FORMAT_WAVE64 && input_format != FORMAT_RF64 && input_format != FORMAT_AIFF && input_format != FORMAT_AIFF_C) { + conditional_fclose(encode_infile); + return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE, Wave64, RF64, or AIFF input\n"); + } + } + + /* + * Error if output file already exists (and -f not used). + * Use grabbag__file_get_filesize() as a cheap way to check. + */ + if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (FLAC__off_t)(-1)) { + if(input_format == FORMAT_FLAC) { + /* need more detailed error message when re-flac'ing to avoid confusing the user */ + flac__utils_printf(stderr, 1, + "ERROR: output file %s already exists.\n\n" + "By default flac encodes files to FLAC format; if you meant to decode this file\n" + "from FLAC to something else, use -d. If you meant to re-encode this file from\n" + "FLAC to FLAC again, use -f to force writing to the same file, or -o to specify\n" + "a different output filename.\n", + outfilename + ); + } + else if(input_format == FORMAT_OGGFLAC) { + /* need more detailed error message when re-flac'ing to avoid confusing the user */ + flac__utils_printf(stderr, 1, + "ERROR: output file %s already exists.\n\n" + "By default 'flac -ogg' encodes files to Ogg FLAC format; if you meant to decode\n" + "this file from Ogg FLAC to something else, use -d. If you meant to re-encode\n" + "this file from Ogg FLAC to Ogg FLAC again, use -f to force writing to the same\n" + "file, or -o to specify a different output filename.\n", + outfilename + ); + } + else + flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename); + conditional_fclose(encode_infile); + return 1; + } + + if(option_values.format_input_size >= 0) { + if (input_format != FORMAT_RAW || infilesize >= 0) { + flac__utils_printf(stderr, 1, "ERROR: can only use --input-size when encoding raw samples from stdin\n"); + conditional_fclose(encode_infile); + return 1; + } + else { + infilesize = option_values.format_input_size; + } + } + + if(input_format == FORMAT_RAW) { + if(option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0 || option_values.format_channels < 0 || option_values.format_bps < 0 || option_values.format_sample_rate < 0) { + conditional_fclose(encode_infile); + return usage_error("ERROR: for encoding a raw file you must specify a value for --endian, --sign, --channels, --bps, and --sample-rate\n"); + } + } + else { + if(option_values.format_is_big_endian >= 0 || option_values.format_is_unsigned_samples >= 0 || option_values.format_channels >= 0 || option_values.format_bps >= 0 || option_values.format_sample_rate >= 0) { + conditional_fclose(encode_infile); + return usage_error("ERROR: raw format options (--endian, --sign, --channels, --bps, and --sample-rate) are not allowed for non-raw input\n"); + } + } + + if(option_values.force_to_stdout) { + if(option_values.replay_gain) { + conditional_fclose(encode_infile); + return usage_error("ERROR: --replay-gain cannot be used when encoding to stdout\n"); + } + } + if(option_values.replay_gain && option_values.use_ogg) { + conditional_fclose(encode_infile); + return usage_error("ERROR: --replay-gain cannot be used when encoding to Ogg FLAC yet\n"); + } + + if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &encode_options.skip_specification) || encode_options.skip_specification.is_relative) { + conditional_fclose(encode_infile); + return usage_error("ERROR: invalid value for --skip\n"); + } + + if(!flac__utils_parse_skip_until_specification(option_values.until_specification, &encode_options.until_specification)) { /*@@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */ + conditional_fclose(encode_infile); + return usage_error("ERROR: invalid value for --until\n"); + } + /* if there is no "--until" we want to default to "--until=-0" */ + if(0 == option_values.until_specification) + encode_options.until_specification.is_relative = true; + + encode_options.verify = option_values.verify; + encode_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors; +#if FLAC__HAS_OGG + encode_options.use_ogg = option_values.use_ogg; + /* set a random serial number if one has not yet been specified */ + if(!option_values.has_serial_number) { + option_values.serial_number = rand(); + option_values.has_serial_number = true; + } + encode_options.serial_number = option_values.serial_number++; +#endif + encode_options.lax = option_values.lax; + encode_options.padding = option_values.padding; + encode_options.num_compression_settings = option_values.num_compression_settings; + FLAC__ASSERT(sizeof(encode_options.compression_settings) >= sizeof(option_values.compression_settings)); + memcpy(encode_options.compression_settings, option_values.compression_settings, sizeof(option_values.compression_settings)); + encode_options.requested_seek_points = option_values.requested_seek_points; + encode_options.num_requested_seek_points = option_values.num_requested_seek_points; + encode_options.cuesheet_filename = option_values.cuesheet_filename; + encode_options.continue_through_decode_errors = option_values.continue_through_decode_errors; + encode_options.cued_seekpoints = option_values.cued_seekpoints; + encode_options.channel_map_none = option_values.channel_map_none; + encode_options.is_first_file = is_first_file; + encode_options.is_last_file = is_last_file; + encode_options.replay_gain = option_values.replay_gain; + encode_options.ignore_chunk_sizes = option_values.ignore_chunk_sizes; + encode_options.vorbis_comment = option_values.vorbis_comment; + FLAC__ASSERT(sizeof(encode_options.pictures) >= sizeof(option_values.pictures)); + memcpy(encode_options.pictures, option_values.pictures, sizeof(option_values.pictures)); + encode_options.num_pictures = option_values.num_pictures; + encode_options.format = input_format; + encode_options.debug.disable_constant_subframes = option_values.debug.disable_constant_subframes; + encode_options.debug.disable_fixed_subframes = option_values.debug.disable_fixed_subframes; + encode_options.debug.disable_verbatim_subframes = option_values.debug.disable_verbatim_subframes; + encode_options.debug.do_md5 = option_values.debug.do_md5; + encode_options.error_on_compression_fail = option_values.error_on_compression_fail; + encode_options.limit_min_bitrate = option_values.limit_min_bitrate; + encode_options.relaxed_foreign_metadata_handling = option_values.keep_foreign_metadata_if_present; + + /* if infilename and outfilename point to the same file, we need to write to a temporary file */ + if(encode_infile != stdin && grabbag__file_are_same(infilename, outfilename)) { + static const char *tmp_suffix = ".tmp,fl-ac+en'c"; + size_t dest_len = strlen(outfilename) + strlen(tmp_suffix) + 1; + /*@@@@ still a remote possibility that a file with this filename exists */ + if((internal_outfilename = safe_malloc_(dest_len)) == NULL) { + flac__utils_printf(stderr, 1, "ERROR allocating memory for tempfile name\n"); + conditional_fclose(encode_infile); + return 1; + } + flac_snprintf(internal_outfilename, dest_len, "%s%s", outfilename, tmp_suffix); + } + + if(input_format == FORMAT_RAW) { + encode_options.format_options.raw.is_big_endian = option_values.format_is_big_endian; + encode_options.format_options.raw.is_unsigned_samples = option_values.format_is_unsigned_samples; + encode_options.format_options.raw.channels = option_values.format_channels; + encode_options.format_options.raw.bps = option_values.format_bps; + encode_options.format_options.raw.sample_rate = option_values.format_sample_rate; + + retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options); + } + else if(input_format == FORMAT_FLAC || input_format == FORMAT_OGGFLAC) { + retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options); + } + else if(input_format == FORMAT_WAVE || input_format == FORMAT_WAVE64 || input_format == FORMAT_RF64 || input_format == FORMAT_AIFF || input_format == FORMAT_AIFF_C) { + encode_options.format_options.iff.foreign_metadata = 0; + + /* initialize foreign metadata if requested */ + if(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present) { + encode_options.format_options.iff.foreign_metadata = + flac__foreign_metadata_new( + input_format==FORMAT_WAVE || input_format==FORMAT_RF64? + FOREIGN_BLOCK_TYPE__RIFF : + input_format==FORMAT_WAVE64? + FOREIGN_BLOCK_TYPE__WAVE64 : + FOREIGN_BLOCK_TYPE__AIFF + ); + if(0 == encode_options.format_options.iff.foreign_metadata) { + flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n"); + conditional_fclose(encode_infile); + if(internal_outfilename != 0) + free(internal_outfilename); + return 1; + } + } + + retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options); + + if(encode_options.format_options.iff.foreign_metadata) + flac__foreign_metadata_delete(encode_options.format_options.iff.foreign_metadata); + } + else { + FLAC__ASSERT(0); + retval = 1; /* double protection */ + } + + if(retval == 0) { + if(strcmp(outfilename, "-")) { + if(option_values.replay_gain) { + float title_gain, title_peak; + const char *error; + grabbag__replaygain_get_title(&title_gain, &title_peak); + if( + 0 != (error = grabbag__replaygain_store_to_file_reference(internal_outfilename? internal_outfilename : outfilename, option_values.preserve_modtime)) || + 0 != (error = grabbag__replaygain_store_to_file_title(internal_outfilename? internal_outfilename : outfilename, title_gain, title_peak, option_values.preserve_modtime)) + ) { + flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain reference/title tags (%s)\n", outfilename, error); + retval = 1; + } + } + if(option_values.preserve_modtime && strcmp(infilename, "-")) + grabbag__file_copy_metadata(infilename, internal_outfilename? internal_outfilename : outfilename); + } + } + + /* rename temporary file if necessary */ + if(retval == 0 && internal_outfilename != 0) { + if(flac_rename(internal_outfilename, outfilename) < 0) { +#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ + /* on some flavors of windows, flac_rename() will fail if the destination already exists, so we unlink and try again */ + if(flac_unlink(outfilename) < 0) { + flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, keeping both\n", internal_outfilename, outfilename); + retval = 1; + } + else if(flac_rename(internal_outfilename, outfilename) < 0) { + flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, you must do it\n", internal_outfilename, outfilename); + retval = 1; + } +#else + flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, keeping both\n", internal_outfilename, outfilename); + retval = 1; +#endif + } + } + + /* handle --delete-input-file, but don't want to delete if piping from stdin, or if input filename and output filename are the same */ + if(retval == 0 && option_values.delete_input && strcmp(infilename, "-") && internal_outfilename == 0) + flac_unlink(infilename); + + if(internal_outfilename != 0) + free(internal_outfilename); + + return retval; +} + +int decode_file(const char *infilename) +{ + int retval; + FLAC__bool treat_as_ogg = false; + FileFormat output_format = FORMAT_WAVE; + FileSubFormat output_subformat = SUBFORMAT_UNSPECIFIED; + decode_options_t decode_options; + foreign_metadata_t *foreign_metadata = 0; + const char *outfilename = get_outfilename(infilename, ". "); /* Placeholder until we know what the actual suffix is */ + size_t infilename_length; + + if(0 == outfilename) { + flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename); + return 1; + } + + if(!option_values.analyze && !option_values.test_only &&(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present)) { + const char *error; + if(0 == strcmp(infilename, "-") || 0 == strcmp(outfilename, "-")) + return usage_error("ERROR: --keep-foreign-metadata cannot be used when decoding from stdin or to stdout\n"); + if(output_format == FORMAT_RAW) + return usage_error("ERROR: --keep-foreign-metadata cannot be used with raw output\n"); + decode_options.format_options.iff.foreign_metadata = 0; + /* initialize foreign metadata structure */ + foreign_metadata = flac__foreign_metadata_new(FOREIGN_BLOCK_TYPE__RIFF); /* RIFF is just a placeholder */ + if(0 == foreign_metadata) { + flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n"); + return 1; + } + if(!flac__foreign_metadata_read_from_flac(foreign_metadata, infilename, &error)) { + if(option_values.keep_foreign_metadata_if_present) { + flac__utils_printf(stderr, 1, "%s: WARNING reading foreign metadata: %s\n", infilename, error); + if(option_values.treat_warnings_as_errors) { + flac__foreign_metadata_delete(foreign_metadata); + return 1; + } + else { + /* Couldn't find foreign metadata, stop processing */ + flac__foreign_metadata_delete(foreign_metadata); + foreign_metadata = 0; + } + } + else { + flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", infilename, error); + flac__foreign_metadata_delete(foreign_metadata); + return 1; + } + } + } + + if(option_values.force_raw_format) + output_format = FORMAT_RAW; + else if( + option_values.force_aiff_format || + (strlen(outfilename) >= 4 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-4), ".aif")) || + (strlen(outfilename) >= 5 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-5), ".aiff")) + ) + output_format = FORMAT_AIFF; + else if( + option_values.force_rf64_format || + (strlen(outfilename) >= 5 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-5), ".rf64")) + ) + output_format = FORMAT_RF64; + else if( + option_values.force_wave64_format || + (strlen(outfilename) >= 4 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-4), ".w64")) + ) + output_format = FORMAT_WAVE64; + else if(foreign_metadata != NULL) { + /* Pick a format based on what the foreign metadata contains */ + if(foreign_metadata->type == FOREIGN_BLOCK_TYPE__WAVE64) + output_format = FORMAT_WAVE64; + else if(foreign_metadata->is_rf64) + output_format = FORMAT_RF64; + else if(foreign_metadata->type == FOREIGN_BLOCK_TYPE__AIFF) { + output_format = FORMAT_AIFF; + if(foreign_metadata->is_aifc) { + output_format = FORMAT_AIFF_C; + } + } + else + output_format = FORMAT_WAVE; + } + else + output_format = FORMAT_WAVE; + + /* Now do subformats */ + if(option_values.force_legacy_wave_format) + output_subformat = SUBFORMAT_WAVE_PCM; + else if(option_values.force_extensible_wave_format) + output_subformat = SUBFORMAT_WAVE_EXTENSIBLE; + else if(option_values.force_aiff_c_none_format) { + output_format = FORMAT_AIFF_C; + output_subformat = SUBFORMAT_AIFF_C_NONE; + } + else if(option_values.force_aiff_c_sowt_format) { + output_format = FORMAT_AIFF_C; + output_subformat = SUBFORMAT_AIFF_C_SOWT; + } + else if(foreign_metadata != NULL) { + if(foreign_metadata->is_wavefmtex) + output_subformat = SUBFORMAT_WAVE_EXTENSIBLE; + else if(output_format == FORMAT_WAVE) + output_subformat = SUBFORMAT_WAVE_PCM; + else if(foreign_metadata->is_aifc) { + if(foreign_metadata->is_sowt) + output_subformat = SUBFORMAT_AIFF_C_SOWT; + else + output_subformat = SUBFORMAT_AIFF_C_NONE; + } + } + + + /* Check whether output format agrees with foreign metadata */ + if(foreign_metadata != NULL) { + if((output_format != FORMAT_WAVE && output_format != FORMAT_RF64) && foreign_metadata->type == FOREIGN_BLOCK_TYPE__RIFF) { + flac__foreign_metadata_delete(foreign_metadata); + return usage_error("ERROR: foreign metadata type RIFF cannot be restored to a%s file, only to WAVE and RF64\n",FileFormatString[output_format]); + } + if((output_format != FORMAT_AIFF && output_format != FORMAT_AIFF_C) && foreign_metadata->type == FOREIGN_BLOCK_TYPE__AIFF) { + flac__foreign_metadata_delete(foreign_metadata); + return usage_error("ERROR: foreign metadata type AIFF cannot be restored to a%s file, only to AIFF and AIFF-C\n",FileFormatString[output_format]); + } + if(output_format != FORMAT_WAVE64 && foreign_metadata->type == FOREIGN_BLOCK_TYPE__WAVE64) { + flac__foreign_metadata_delete(foreign_metadata); + return usage_error("ERROR: foreign metadata type Wave64 cannot be restored to a%s file, only to Wave64\n",FileFormatString[output_format]); + } + } + + /* Now reassemble outfilename */ + get_decoded_outfilename(infilename, output_format); + + /* + * Error if output file already exists (and -f not used). + * Use grabbag__file_get_filesize() as a cheap way to check. + */ + if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (FLAC__off_t)(-1)) { + flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename); + flac__foreign_metadata_delete(foreign_metadata); + return 1; + } + + if(!option_values.test_only && !option_values.analyze) { + if(output_format == FORMAT_RAW && (option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0)) { + flac__foreign_metadata_delete(foreign_metadata); + return usage_error("ERROR: for decoding to a raw file you must specify a value for --endian and --sign\n"); + } + } + + infilename_length = strlen(infilename); + if(option_values.use_ogg) + treat_as_ogg = true; + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".oga")) + treat_as_ogg = true; + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".ogg")) + treat_as_ogg = true; + else + treat_as_ogg = false; + +#if !FLAC__HAS_OGG + if(treat_as_ogg) { + flac__utils_printf(stderr, 1, "%s: Ogg support has not been built into this copy of flac\n", infilename); + flac__foreign_metadata_delete(foreign_metadata); + return 1; + } +#endif + + if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &decode_options.skip_specification) || decode_options.skip_specification.is_relative) { + flac__foreign_metadata_delete(foreign_metadata); + return usage_error("ERROR: invalid value for --skip\n"); + } + + if(!flac__utils_parse_skip_until_specification(option_values.until_specification, &decode_options.until_specification)) { /*@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */ + flac__foreign_metadata_delete(foreign_metadata); + return usage_error("ERROR: invalid value for --until\n"); + } + /* if there is no "--until" we want to default to "--until=-0" */ + if(0 == option_values.until_specification) + decode_options.until_specification.is_relative = true; + + if(option_values.cue_specification) { + if(!flac__utils_parse_cue_specification(option_values.cue_specification, &decode_options.cue_specification)) { + flac__foreign_metadata_delete(foreign_metadata); + return usage_error("ERROR: invalid value for --cue\n"); + } + decode_options.has_cue_specification = true; + } + else + decode_options.has_cue_specification = false; + + decode_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors; + decode_options.continue_through_decode_errors = option_values.continue_through_decode_errors; + decode_options.relaxed_foreign_metadata_handling = option_values.keep_foreign_metadata_if_present; + decode_options.replaygain_synthesis_spec = option_values.replaygain_synthesis_spec; + decode_options.force_subformat = output_subformat; +#if FLAC__HAS_OGG + decode_options.is_ogg = treat_as_ogg; + decode_options.use_first_serial_number = !option_values.has_serial_number; + decode_options.serial_number = option_values.serial_number; +#endif + decode_options.channel_map_none = option_values.channel_map_none; + decode_options.format = output_format; + + if(output_format == FORMAT_RAW) { + decode_options.format_options.raw.is_big_endian = option_values.format_is_big_endian; + decode_options.format_options.raw.is_unsigned_samples = option_values.format_is_unsigned_samples; + + retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options); + } + else { + decode_options.format_options.iff.foreign_metadata = foreign_metadata; + + retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options); + + } + + if(foreign_metadata) + flac__foreign_metadata_delete(foreign_metadata); + + if(retval == 0 && strcmp(infilename, "-")) { + if(option_values.preserve_modtime && strcmp(outfilename, "-")) + grabbag__file_copy_metadata(infilename, outfilename); + if(option_values.delete_input && !option_values.test_only && !option_values.analyze) + flac_unlink(infilename); + } + + return retval; +} + +const char *get_encoded_outfilename(const char *infilename) +{ + const char *suffix = (option_values.use_ogg? ".oga" : ".flac"); + const char *p; + + if(option_values.output_prefix) { + p = grabbag__file_get_basename(infilename); + } + else { + p = infilename; + } + + return get_outfilename(p, suffix); +} + +const char *get_decoded_outfilename(const char *infilename, const FileFormat format) +{ + const char *suffix; + const char *p; + + if(option_values.output_prefix) { + p = grabbag__file_get_basename(infilename); + } + else { + p = infilename; + } + + if(option_values.analyze) { + suffix = ".ana"; + } + else if(format == FORMAT_RAW) { + suffix = ".raw"; + } + else if(format == FORMAT_AIFF) { + suffix = ".aiff"; + } + else if(format == FORMAT_AIFF_C) { + suffix = ".aifc"; + } + else if(format == FORMAT_RF64) { + suffix = ".rf64"; + } + else if(format == FORMAT_WAVE64) { + suffix = ".w64"; + } + else { + suffix = ".wav"; + } + return get_outfilename(p, suffix); +} + +const char *get_outfilename(const char *infilename, const char *suffix) +{ + if(0 == option_values.cmdline_forced_outfilename) { + static char buffer[4096]; + + if(0 == strcmp(infilename, "-") || option_values.force_to_stdout) { + buffer [0] = '-'; + buffer [1] = 0; + } + else { + char *p; + if (flac__strlcpy(buffer, option_values.output_prefix? option_values.output_prefix : "", sizeof buffer) >= sizeof buffer) + return 0; + if (flac__strlcat(buffer, infilename, sizeof buffer) >= sizeof buffer) + return 0; + /* the . must come after any / to avoid problems with, e.g. "some.directory/extensionless-filename" */ + if(0 == (p = strrchr(buffer, '.')) || strchr(p, '/')) { + if (flac__strlcat(buffer, suffix, sizeof buffer) >= sizeof buffer) + return 0; + } + else { + *p = '\0'; + if (flac__strlcat(buffer, suffix, sizeof buffer) >= sizeof buffer) + return 0; + } + } + return buffer; + } + else + return option_values.cmdline_forced_outfilename; +} + +void die(const char *message) +{ + FLAC__ASSERT(0 != message); + flac__utils_printf(stderr, 1, "ERROR: %s\n", message); + exit(1); +} + +int conditional_fclose(FILE *f) +{ + if(f == 0 || f == stdin || f == stdout) + return 0; + else + return fclose(f); +} + +char *local_strdup(const char *source) +{ + char *ret; + FLAC__ASSERT(0 != source); + if(0 == (ret = strdup(source))) + die("out of memory during strdup()"); + return ret; +} diff --git a/vendor/flac/src/flac/utils.c b/vendor/flac/src/flac/utils.c new file mode 100644 index 0000000..446150d --- /dev/null +++ b/vendor/flac/src/flac/utils.c @@ -0,0 +1,439 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include "utils.h" +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "share/compat.h" +#ifndef _WIN32 +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE +#endif +#include +#ifdef HAVE_TERMIOS_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#endif + +const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK"; + +int flac__utils_verbosity_ = 2; + +static FLAC__bool local__parse_uint64_(const char *s, FLAC__uint64 *value) +{ + FLAC__uint64 ret = 0; + char c; + + if(*s == '\0') + return false; + + while('\0' != (c = *s++)) + if(c >= '0' && c <= '9') { + if(ret > UINT64_MAX / 10) /* check for overflow */ + return false; + else if(ret == UINT64_MAX / 10) { + FLAC__uint64 tmp = ret; + ret = ret * 10 + (c - '0'); + if(ret < tmp) + return false; + } + else + ret = ret * 10 + (c - '0'); + } + else + return false; + + *value = ret; + return true; +} + +static FLAC__bool local__parse_timecode_(const char *s, double *value) +{ + double ret; + uint32_t i; + char c, *endptr; + + /* parse [0-9][0-9]*: */ + c = *s++; + if(c >= '0' && c <= '9') + i = (c - '0'); + else + return false; + while(':' != (c = *s++)) { + if(c >= '0' && c <= '9') + i = i * 10 + (c - '0'); + else + return false; + } + ret = (double)i * 60.; + + /* parse [0-9]*[.,]?[0-9]* i.e. a sign-less rational number (. or , OK for fractional seconds, to support different locales) */ + if(strspn(s, "1234567890.,") != strlen(s)) + return false; + ret += strtod(s, &endptr); + if (endptr == s || *endptr) + return false; + + *value = ret; + return true; +} + +static FLAC__bool local__parse_cue_(const char *s, const char *end, uint32_t *track, uint32_t *indx) +{ + FLAC__bool got_track = false, got_index = false; + uint32_t t = 0, i = 0; + char c; + + while(end? s < end : *s != '\0') { + c = *s++; + if(c >= '0' && c <= '9') { + t = t * 10 + (c - '0'); + got_track = true; + } + else if(c == '.') + break; + else + return false; + } + while(end? s < end : *s != '\0') { + c = *s++; + if(c >= '0' && c <= '9') { + i = i * 10 + (c - '0'); + got_index = true; + } + else + return false; + } + *track = t; + *indx = i; + return got_track && got_index; +} + +/* + * this only works with sorted cuesheets (the spec strongly recommends but + * does not require sorted cuesheets). but if it's not sorted, picking a + * nearest cue point has no significance. + */ +static FLAC__uint64 local__find_closest_cue_(const FLAC__StreamMetadata_CueSheet *cuesheet, uint32_t track, uint32_t indx, FLAC__uint64 total_samples, FLAC__bool look_forward) +{ + int t, i; + if(look_forward) { + for(t = 0; t < (int)cuesheet->num_tracks; t++) + for(i = 0; i < (int)cuesheet->tracks[t].num_indices; i++) + if(cuesheet->tracks[t].number > track || (cuesheet->tracks[t].number == track && cuesheet->tracks[t].indices[i].number >= indx)) + return cuesheet->tracks[t].offset + cuesheet->tracks[t].indices[i].offset; + return total_samples; + } + else { + for(t = (int)cuesheet->num_tracks - 1; t >= 0; t--) + for(i = (int)cuesheet->tracks[t].num_indices - 1; i >= 0; i--) + if(cuesheet->tracks[t].number < track || (cuesheet->tracks[t].number == track && cuesheet->tracks[t].indices[i].number <= indx)) + return cuesheet->tracks[t].offset + cuesheet->tracks[t].indices[i].offset; + return 0; + } +} + +void flac__utils_printf(FILE *stream, int level, const char *format, ...) +{ + if(flac__utils_verbosity_ >= level) { + va_list args; + + FLAC__ASSERT(0 != format); + + va_start(args, format); + + (void) flac_vfprintf(stream, format, args); + + va_end(args); + +#ifdef _MSC_VER + if(stream == stderr) + fflush(stream); /* for some reason stderr is buffered in at least some if not all MSC libs */ +#endif + } +} + +/* variables and functions for console status output */ +static FLAC__bool is_name_printed; +static int stats_char_count = 0; +static int console_width; +static int console_chars_left; + +int get_console_width(void) +{ + int width = 0; +#if defined _WIN32 + width = win_get_console_width(); +#elif defined __EMX__ + int s[2]; + _scrsize (s); + width = s[0]; +#elif defined TIOCGWINSZ + struct winsize w; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) + width = w.ws_col; +#endif + if (width <= 0) + width = 80; + return width; +} + +size_t strlen_console(const char *text) +{ +#ifdef _WIN32 + return strlen_utf8(text); +#elif defined(__DJGPP__) /* workaround for DJGPP missing wcswidth() */ + return strlen(text); +#else + size_t len; + wchar_t *wtmp; + + len = strlen(text)+1; + wtmp = (wchar_t *)malloc(len*sizeof(wchar_t)); + if (wtmp == NULL) return len-1; + mbstowcs(wtmp, text, len); + len = wcswidth(wtmp, len); + free(wtmp); + + return len; +#endif +} + +void stats_new_file(void) +{ + is_name_printed = false; +} + +void stats_clear(void) +{ + while (stats_char_count > 0 && stats_char_count--) + fprintf(stderr, "\b"); +} + +void stats_print_name(int level, const char *name) +{ + int len; + + if (flac__utils_verbosity_ >= level) { + stats_clear(); + if(is_name_printed) return; + + console_width = get_console_width(); + len = strlen_console(name)+2; + console_chars_left = console_width - (len % console_width); + flac_fprintf(stderr, "%s: ", name); + is_name_printed = true; + } +} + +void stats_print_info(int level, const char *format, ...) +{ + char tmp[80]; + int len, clear_len; + + if (flac__utils_verbosity_ >= level) { + va_list args; + va_start(args, format); + len = flac_vsnprintf(tmp, sizeof(tmp), format, args); + va_end(args); + stats_clear(); + if (len >= console_chars_left) { + clear_len = console_chars_left; + while (clear_len > 0 && clear_len--) fprintf(stderr, " "); + fprintf(stderr, "\n"); + console_chars_left = console_width; + } + stats_char_count = fprintf(stderr, "%s", tmp); + fflush(stderr); + } +} + +#ifdef FLAC__VALGRIND_TESTING +size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#endif + +FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec) +{ + FLAC__uint64 val; + FLAC__bool is_negative = false; + + FLAC__ASSERT(0 != spec); + + spec->is_relative = false; + spec->value_is_samples = true; + spec->value.samples = 0; + + if(0 != s) { + if(s[0] == '-') { + is_negative = true; + spec->is_relative = true; + s++; + } + else if(s[0] == '+') { + spec->is_relative = true; + s++; + } + + if(local__parse_uint64_(s, &val)) { + spec->value_is_samples = true; + if(val > INT64_MAX) + return false; + spec->value.samples = (FLAC__int64)val; + if(is_negative) + spec->value.samples = -(spec->value.samples); + } + else { + double d; + if(!local__parse_timecode_(s, &d)) + return false; + spec->value_is_samples = false; + spec->value.seconds = d; + if(is_negative) + spec->value.seconds = -(spec->value.seconds); + } + } + + return true; +} + +FLAC__bool flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, uint32_t sample_rate) +{ + FLAC__ASSERT(0 != spec); + if(!spec->value_is_samples) { + double samples = spec->value.seconds * (double)sample_rate; + if(samples >= (double)INT64_MAX || samples <= (double)INT64_MIN) + return false; + spec->value.samples = (FLAC__int64)(samples); + spec->value_is_samples = true; + } + return true; +} + +FLAC__bool flac__utils_parse_cue_specification(const char *s, utils__CueSpecification *spec) +{ + const char *start = s, *end = 0; + + FLAC__ASSERT(0 != spec); + + spec->has_start_point = spec->has_end_point = false; + + s = strchr(s, '-'); + + if(0 != s) { + if(s == start) + start = 0; + end = s+1; + if(*end == '\0') + end = 0; + } + + if(start) { + if(!local__parse_cue_(start, s, &spec->start_track, &spec->start_index)) + return false; + spec->has_start_point = true; + } + + if(end) { + if(!local__parse_cue_(end, 0, &spec->end_track, &spec->end_index)) + return false; + spec->has_end_point = true; + } + + return true; +} + +void flac__utils_canonicalize_cue_specification(const utils__CueSpecification *cue_spec, const FLAC__StreamMetadata_CueSheet *cuesheet, FLAC__uint64 total_samples, utils__SkipUntilSpecification *skip_spec, utils__SkipUntilSpecification *until_spec) +{ + FLAC__ASSERT(0 != cue_spec); + FLAC__ASSERT(0 != cuesheet); + FLAC__ASSERT(0 != total_samples); + FLAC__ASSERT(0 != skip_spec); + FLAC__ASSERT(0 != until_spec); + + skip_spec->is_relative = false; + skip_spec->value_is_samples = true; + + until_spec->is_relative = false; + until_spec->value_is_samples = true; + + if(cue_spec->has_start_point) + skip_spec->value.samples = local__find_closest_cue_(cuesheet, cue_spec->start_track, cue_spec->start_index, total_samples, /*look_forward=*/false); + else + skip_spec->value.samples = 0; + + if(cue_spec->has_end_point) + until_spec->value.samples = local__find_closest_cue_(cuesheet, cue_spec->end_track, cue_spec->end_index, total_samples, /*look_forward=*/true); + else + until_spec->value.samples = total_samples; +} + +FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__uint32 channel_mask) +{ + FLAC__StreamMetadata_VorbisComment_Entry entry = { 0, 0 }; + char tag[128]; + + FLAC__ASSERT(object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(strlen(CHANNEL_MASK_TAG)+1+2+16+1 <= sizeof(tag)); /* +1 for =, +2 for 0x, +16 for digits, +1 for NUL */ + entry.entry = (FLAC__byte*)tag; + if((entry.length = flac_snprintf(tag, sizeof(tag), "%s=0x%04X", CHANNEL_MASK_TAG, (uint32_t)channel_mask)) >= sizeof(tag)) + return false; + if(!FLAC__metadata_object_vorbiscomment_replace_comment(object, entry, /*all=*/true, /*copy=*/true)) + return false; + return true; +} + +FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask) +{ + int offset; + uint32_t val; + char *p; + FLAC__ASSERT(object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 > (offset = FLAC__metadata_object_vorbiscomment_find_entry_from(object, /*offset=*/0, CHANNEL_MASK_TAG))) + return false; + if(object->data.vorbis_comment.comments[offset].length < strlen(CHANNEL_MASK_TAG)+4) + return false; + if(0 == (p = strchr((const char *)object->data.vorbis_comment.comments[offset].entry, '='))) /* should never happen, but just in case */ + return false; + if(FLAC__STRNCASECMP(p, "=0x", 3)) + return false; + if(sscanf(p+3, "%x", &val) != 1) + return false; + *channel_mask = val; + return true; +} diff --git a/vendor/flac/src/flac/utils.h b/vendor/flac/src/flac/utils.h new file mode 100644 index 0000000..931b4a6 --- /dev/null +++ b/vendor/flac/src/flac/utils.h @@ -0,0 +1,77 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef flac__utils_h +#define flac__utils_h + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/ordinals.h" +#include "FLAC/format.h" /* for FLAC__StreamMetadata_CueSheet */ +#include /* for FILE */ + +typedef enum { FORMAT_RAW, FORMAT_WAVE, FORMAT_WAVE64, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C, FORMAT_FLAC, FORMAT_OGGFLAC } FileFormat; +static const char * const FileFormatString[] = { " raw", " WAVE", " Wave64", "n RF64", "n AIFF", "n AIFF-C", " FLAC", "n Ogg FLAC" }; + +typedef enum { SUBFORMAT_UNSPECIFIED = 0, SUBFORMAT_WAVE_PCM, SUBFORMAT_WAVE_EXTENSIBLE, SUBFORMAT_AIFF_C_NONE, SUBFORMAT_AIFF_C_SOWT } FileSubFormat; + + +typedef struct { + FLAC__bool is_relative; /* i.e. specification string started with + or - */ + FLAC__bool value_is_samples; + union { + double seconds; + FLAC__int64 samples; + } value; +} utils__SkipUntilSpecification; + +typedef struct { + FLAC__bool has_start_point, has_end_point; + unsigned start_track, start_index; + unsigned end_track, end_index; +} utils__CueSpecification; + +#ifdef FLAC__VALGRIND_TESTING +size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +#else +#define flac__utils_fwrite fwrite +#endif + +extern int flac__utils_verbosity_; +void flac__utils_printf(FILE *stream, int level, const char *format, ...); + +int get_console_width(void); +size_t strlen_console(const char *text); +void stats_new_file(void); +void stats_clear(void); +void stats_print_name(int level, const char *name); +void stats_print_info(int level, const char *format, ...); + +FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec); +FLAC__bool flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, uint32_t sample_rate); + +FLAC__bool flac__utils_parse_cue_specification(const char *s, utils__CueSpecification *spec); +void flac__utils_canonicalize_cue_specification(const utils__CueSpecification *cue_spec, const FLAC__StreamMetadata_CueSheet *cuesheet, FLAC__uint64 total_samples, utils__SkipUntilSpecification *skip_spec, utils__SkipUntilSpecification *until_spec); + +FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__uint32 channel_mask); +FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask); + +#endif diff --git a/vendor/flac/src/flac/version.rc b/vendor/flac/src/flac/version.rc new file mode 100644 index 0000000..00842b9 --- /dev/null +++ b/vendor/flac/src/flac/version.rc @@ -0,0 +1,38 @@ +#include +#include "config.h" + +#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE) +# ifdef GIT_COMMIT_TAG +# define VERSIONSTRING GIT_COMMIT_TAG +# else +# define VERSIONSTRING "git-" GIT_COMMIT_HASH +# endif +#else +# define VERSIONSTRING PACKAGE_VERSION +#endif + +#define xstr(s) str(s) +#define str(s) #s + +VS_VERSION_INFO VERSIONINFO +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "flac command line tool for Windows" + VALUE "ProductName", "Free Lossless Audio Codec" + VALUE "ProductVersion", VERSIONSTRING + VALUE "CompanyName", "Xiph.Org" + VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/vendor/flac/src/flac/vorbiscomment.c b/vendor/flac/src/flac/vorbiscomment.c new file mode 100644 index 0000000..3941ec2 --- /dev/null +++ b/vendor/flac/src/flac/vorbiscomment.c @@ -0,0 +1,254 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "vorbiscomment.h" +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "share/grabbag.h" /* for grabbag__file_get_filesize() */ +#include "share/utf8.h" +#include +#include +#include +#include +#include "share/compat.h" + + +/* + * This struct and the following 4 static functions are copied from + * ../metaflac/. Maybe someday there will be a convenience + * library for Vorbis comment parsing. + */ +typedef struct { + char *field; /* the whole field as passed on the command line, i.e. "NAME=VALUE" */ + char *field_name; + /* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */ + uint32_t field_value_length; + char *field_value; + FLAC__bool field_value_from_file; /* true if field_value holds a filename for the value, false for plain value */ +} Argument_VcField; + +static void die(const char *message) +{ + FLAC__ASSERT(0 != message); + fprintf(stderr, "ERROR: %s\n", message); + exit(1); +} + +static char *local_strdup(const char *source) +{ + char *ret; + FLAC__ASSERT(0 != source); + if(0 == (ret = strdup(source))) + die("out of memory during strdup()"); + return ret; +} + +static FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, uint32_t *length, const char **violation) +{ + static const char * const violations[] = { + "field name contains invalid character", + "field contains no '=' character" + }; + + char *p, *q, *s; + + if(0 != field) + *field = local_strdup(field_ref); + + s = local_strdup(field_ref); + + if(0 == (p = strchr(s, '='))) { + free(s); + *violation = violations[1]; + return false; + } + *p++ = '\0'; + + for(q = s; *q; q++) { + if(*q < 0x20 || *q > 0x7d || *q == 0x3d) { + free(s); + *violation = violations[0]; + return false; + } + } + + *name = local_strdup(s); + *value = local_strdup(p); + *length = strlen(p); + + free(s); + return true; +} + +/* slight modification: no 'filename' arg, and errors are passed back in 'violation' instead of printed to stderr */ +static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw, const char **violation) +{ + FLAC__StreamMetadata_VorbisComment_Entry entry; + char *converted = NULL; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != field); + FLAC__ASSERT(0 != needs_write); + + if(field->field_value_from_file) { + /* read the file into 'data' */ + FILE *f = 0; + char *data = 0; + const FLAC__off_t size = grabbag__file_get_filesize(field->field_value); + if(size < 0) { + *violation = "can't open file for tag value"; + return false; + } + if(size >= 0x100000) { /* magic arbitrary limit, actual format limit is near 16MB */ + *violation = "file for tag value is too large"; + return false; + } + if(0 == (data = malloc(size+1))) + die("out of memory allocating tag value"); + data[size] = '\0'; + if(0 == (f = flac_fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) { + free(data); + if(f) + fclose(f); + *violation = "error while reading file for tag value"; + return false; + } + fclose(f); + if(strlen(data) != (size_t)size) { + free(data); + *violation = "file for tag value has embedded NULs"; + return false; + } + + /* move 'data' into 'converted', converting to UTF-8 if necessary */ + if(raw) { + converted = data; + } + else if(utf8_encode(data, &converted) >= 0) { + free(data); + } + else { + free(data); + *violation = "error converting file contents to UTF-8 for tag value"; + return false; + } + + /* create and entry and append it */ + if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) { + free(converted); + *violation = "file for tag value is not valid UTF-8"; + return false; + } + free(converted); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) { + *violation = "memory allocation failure"; + return false; + } + + *needs_write = true; + return true; + } + else { + FLAC__bool needs_free = false; +#ifdef _WIN32 /* everything in UTF-8 already. Must not alter */ + entry.entry = (FLAC__byte *)field->field; +#else + if(raw) { + entry.entry = (FLAC__byte *)field->field; + } + else if(utf8_encode(field->field, &converted) >= 0) { + entry.entry = (FLAC__byte *)converted; + needs_free = true; + } + else { + *violation = "error converting comment to UTF-8"; + return false; + } +#endif + entry.length = strlen((const char *)entry.entry); + if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) { + if(needs_free) + free(converted); + /* + * our previous parsing has already established that the field + * name is OK, so it must be the field value + */ + *violation = "tag value is not valid UTF-8"; + return false; + } + + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { + if(needs_free) + free(converted); + *violation = "memory allocation failure"; + return false; + } + + *needs_write = true; + if(needs_free) + free(converted); + return true; + } +} + +/* + * The rest of the code is novel + */ + +static void free_field(Argument_VcField *obj) +{ + if(0 != obj->field) + free(obj->field); + if(0 != obj->field_name) + free(obj->field_name); + if(0 != obj->field_value) + free(obj->field_value); +} + +FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comment, FLAC__bool value_from_file, FLAC__bool raw, const char **violation) +{ + Argument_VcField parsed; + FLAC__bool dummy; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != comment); + + memset(&parsed, 0, sizeof(parsed)); + + parsed.field_value_from_file = value_from_file; + if(!parse_vorbis_comment_field(comment, &(parsed.field), &(parsed.field_name), &(parsed.field_value), &(parsed.field_value_length), violation)) { + free_field(&parsed); + return false; + } + + if(parsed.field_value_length > 0 && !set_vc_field(block, &parsed, &dummy, raw, violation)) { + free_field(&parsed); + return false; + } + else { + free_field(&parsed); + return true; + } +} diff --git a/vendor/flac/src/flac/vorbiscomment.h b/vendor/flac/src/flac/vorbiscomment.h new file mode 100644 index 0000000..a6dcb16 --- /dev/null +++ b/vendor/flac/src/flac/vorbiscomment.h @@ -0,0 +1,27 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef flac__vorbiscomment_h +#define flac__vorbiscomment_h + +#include "FLAC/metadata.h" + +FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comment, FLAC__bool value_from_file, FLAC__bool raw, const char **violation); + +#endif diff --git a/vendor/flac/src/libFLAC++/CMakeLists.txt b/vendor/flac/src/libFLAC++/CMakeLists.txt new file mode 100644 index 0000000..3be43ba --- /dev/null +++ b/vendor/flac/src/libFLAC++/CMakeLists.txt @@ -0,0 +1,41 @@ +add_library(FLAC++ + metadata.cpp + stream_decoder.cpp + stream_encoder.cpp + version.rc) +set_property(TARGET FLAC++ PROPERTY PROJECT_LABEL "libFLAC++") +target_compile_definitions(FLAC++ + PRIVATE $<$:FLACPP_API_EXPORTS> + PUBLIC $<$>:FLAC__NO_DLL>) +if(NOT WIN32) + target_compile_definitions(FLAC++ PRIVATE $<$:FLAC__USE_VISIBILITY_ATTR>) +endif() +target_include_directories(FLAC++ INTERFACE + "$" + "$") +target_link_libraries(FLAC++ PUBLIC FLAC) +if(BUILD_SHARED_LIBS) + set_target_properties(FLAC++ PROPERTIES + VERSION 10.0.1 + SOVERSION 10) + if(NOT WIN32) + set_target_properties(FLAC++ PROPERTIES CXX_VISIBILITY_PRESET hidden) + endif() +endif() + +add_library(FLAC::FLAC++ ALIAS FLAC++) + +install(TARGETS FLAC++ EXPORT targets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/") + +if(INSTALL_PKGCONFIG_MODULES) + set(prefix "${CMAKE_INSTALL_PREFIX}") + set(exec_prefix "${CMAKE_INSTALL_PREFIX}") + set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") + set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") + configure_file(flac++.pc.in flac++.pc @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/flac++.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +endif() diff --git a/vendor/flac/src/libFLAC++/Makefile.am b/vendor/flac/src/libFLAC++/Makefile.am new file mode 100644 index 0000000..0b2853b --- /dev/null +++ b/vendor/flac/src/libFLAC++/Makefile.am @@ -0,0 +1,68 @@ +# libFLAC++ - Free Lossless Audio Codec library +# Copyright (C) 2002-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +lib_LTLIBRARIES = libFLAC++.la +noinst_LTLIBRARIES = libFLAC++-static.la + +m4datadir = $(datadir)/aclocal +m4data_DATA = libFLAC++.m4 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = flac++.pc +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +EXTRA_DIST = \ + CMakeLists.txt \ + flac++.pc.in \ + libFLAC++.m4 \ + version.rc + +libFLAC___sources = \ + metadata.cpp \ + stream_decoder.cpp \ + stream_encoder.cpp + +if OS_IS_WINDOWS +if HAVE_WINDRES +libFLAC___la_DEPENDENCIES = version.o +windows_resource_link = -Wl,version.o +endif +endif + +# see 'http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning' for numbering convention +libFLAC___la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 10:1:0 $(windows_resource_link) +libFLAC___la_LIBADD = ../libFLAC/libFLAC.la +libFLAC___la_SOURCES = $(libFLAC___sources) + +libFLAC___static_la_SOURCES = $(libFLAC___sources) +libFLAC___static_la_LIBADD = ../libFLAC/libFLAC-static.la + +.rc.o: + $(RC) $(AM_CPPFLAGS) $< $@ diff --git a/vendor/flac/src/libFLAC++/flac++.pc.in b/vendor/flac/src/libFLAC++/flac++.pc.in new file mode 100644 index 0000000..f09c251 --- /dev/null +++ b/vendor/flac/src/libFLAC++/flac++.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: FLAC++ +Description: Free Lossless Audio Codec Library (C++ API) +Version: @VERSION@ +Requires: flac +Libs: -L${libdir} -lFLAC++ +Cflags: -I${includedir} diff --git a/vendor/flac/src/libFLAC++/libFLAC++.m4 b/vendor/flac/src/libFLAC++/libFLAC++.m4 new file mode 100644 index 0000000..e5e1345 --- /dev/null +++ b/vendor/flac/src/libFLAC++/libFLAC++.m4 @@ -0,0 +1,114 @@ +# Configure paths for libFLAC++ +# "Inspired" by ogg.m4 +# Caller must first run AM_PATH_LIBFLAC + +dnl AM_PATH_LIBFLACPP([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libFLAC++, and define LIBFLACPP_CFLAGS, LIBFLACPP_LIBS, LIBFLACPP_LIBDIR +dnl +AC_DEFUN([AM_PATH_LIBFLACPP], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(libFLACPP,[ --with-libFLACPP=PFX Prefix where libFLAC++ is installed (optional)], libFLACPP_prefix="$withval", libFLACPP_prefix="") +AC_ARG_WITH(libFLACPP-libraries,[ --with-libFLACPP-libraries=DIR Directory where libFLAC++ library is installed (optional)], libFLACPP_libraries="$withval", libFLACPP_libraries="") +AC_ARG_WITH(libFLACPP-includes,[ --with-libFLACPP-includes=DIR Directory where libFLAC++ header files are installed (optional)], libFLACPP_includes="$withval", libFLACPP_includes="") +AC_ARG_ENABLE(libFLACPPtest, [ --disable-libFLACPPtest Do not try to compile and run a test libFLAC++ program],, enable_libFLACPPtest=yes) + + if test "x$libFLACPP_libraries" != "x" ; then + LIBFLACPP_LIBDIR="$libFLACPP_libraries" + elif test "x$libFLACPP_prefix" != "x" ; then + LIBFLACPP_LIBDIR="$libFLACPP_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + LIBFLACPP_LIBDIR="$libdir" + fi + + LIBFLACPP_LIBS="-L$LIBFLACPP_LIBDIR -lFLAC++ $LIBFLAC_LIBS" + + if test "x$libFLACPP_includes" != "x" ; then + LIBFLACPP_CFLAGS="-I$libFLACPP_includes" + elif test "x$libFLACPP_prefix" != "x" ; then + LIBFLACPP_CFLAGS="-I$libFLACPP_prefix/include" + elif test "$prefix" != "xNONE"; then + LIBFLACPP_CFLAGS="" + fi + + LIBFLACPP_CFLAGS="$LIBFLACPP_CFLAGS $LIBFLAC_CFLAGS" + + AC_MSG_CHECKING(for libFLAC++) + no_libFLACPP="" + + + if test "x$enable_libFLACPPtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_CXXFLAGS="$CXXFLAGS" + ac_save_LIBS="$LIBS" + ac_save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" + CFLAGS="$CFLAGS $LIBFLACPP_CFLAGS" + CXXFLAGS="$CXXFLAGS $LIBFLACPP_CFLAGS" + LIBS="$LIBS $LIBFLACPP_LIBS" + LD_LIBRARY_PATH="$LIBFLACPP_LIBDIR:$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH" +dnl +dnl Now check if the installed libFLAC++ is sufficiently new. +dnl + rm -f conf.libFLAC++test + AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +#include +]],[[ + system("touch conf.libFLAC++test"); + return 0; +]])],[],[no_libFLACPP=yes],[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH" + fi + + if test "x$no_libFLACPP" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.libFLAC++test ; then + : + else + echo "*** Could not run libFLAC++ test program, checking why..." + CFLAGS="$CFLAGS $LIBFLACPP_CFLAGS" + CXXFLAGS="$CXXFLAGS $LIBFLACPP_CFLAGS" + LIBS="$LIBS $LIBFLACPP_LIBS" + LD_LIBRARY_PATH="$LIBFLACPP_LIBDIR:$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding libFLAC++ or finding the wrong" + echo "*** version of libFLAC++. If it is not finding libFLAC++, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means libFLAC++ was incorrectly installed" + echo "*** or that you have moved libFLAC++ since it was installed. In the latter case, you" + echo "*** may want to edit the libFLAC++-config script: $LIBFLACPP_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH" + fi + LIBFLACPP_CFLAGS="" + LIBFLACPP_LIBDIR="" + LIBFLACPP_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(LIBFLACPP_CFLAGS) + AC_SUBST(LIBFLACPP_LIBDIR) + AC_SUBST(LIBFLACPP_LIBS) + rm -f conf.libFLAC++test +]) diff --git a/vendor/flac/src/libFLAC++/metadata.cpp b/vendor/flac/src/libFLAC++/metadata.cpp new file mode 100644 index 0000000..beab110 --- /dev/null +++ b/vendor/flac/src/libFLAC++/metadata.cpp @@ -0,0 +1,1745 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define __STDC_LIMIT_MACROS 1 /* otherwise SIZE_MAX is not defined for c++ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "share/alloc.h" +#include "FLAC++/metadata.h" +#include "FLAC/assert.h" +#include // for malloc(), free() +#include // for memcpy() etc. + +#ifdef _MSC_VER +// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning) +#pragma warning ( disable : 4800 ) +#endif + +namespace FLAC { + namespace Metadata { + + // local utility routines + + namespace local { + + Prototype *construct_block(::FLAC__StreamMetadata *object) + { + if (0 == object) + return 0; + + Prototype *ret = 0; + switch(object->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + ret = new StreamInfo(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_PADDING: + ret = new Padding(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_APPLICATION: + ret = new Application(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + ret = new SeekTable(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + ret = new VorbisComment(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_CUESHEET: + ret = new CueSheet(object, /*copy=*/false); + break; + case FLAC__METADATA_TYPE_PICTURE: + ret = new Picture(object, /*copy=*/false); + break; + default: + ret = new Unknown(object, /*copy=*/false); + break; + } + return ret; + } + + } // namespace local + + FLACPP_API Prototype *clone(const Prototype *object) + { + FLAC__ASSERT(0 != object); + + const StreamInfo *streaminfo = dynamic_cast(object); + const Padding *padding = dynamic_cast(object); + const Application *application = dynamic_cast(object); + const SeekTable *seektable = dynamic_cast(object); + const VorbisComment *vorbiscomment = dynamic_cast(object); + const CueSheet *cuesheet = dynamic_cast(object); + const Picture *picture = dynamic_cast(object); + const Unknown *unknown = dynamic_cast(object); + + if(0 != streaminfo) + return new StreamInfo(*streaminfo); + if(0 != padding) + return new Padding(*padding); + if(0 != application) + return new Application(*application); + if(0 != seektable) + return new SeekTable(*seektable); + if(0 != vorbiscomment) + return new VorbisComment(*vorbiscomment); + if(0 != cuesheet) + return new CueSheet(*cuesheet); + if(0 != picture) + return new Picture(*picture); + if(0 != unknown) + return new Unknown(*unknown); + + FLAC__ASSERT(0); + return 0; + } + + // + // Prototype + // + + Prototype::Prototype(const Prototype &object): + object_(::FLAC__metadata_object_clone(object.object_)), + is_reference_(false) + { + FLAC__ASSERT(object.is_valid()); + } + + Prototype::Prototype(const ::FLAC__StreamMetadata &object): + object_(::FLAC__metadata_object_clone(&object)), + is_reference_(false) + { + } + + Prototype::Prototype(const ::FLAC__StreamMetadata *object): + object_(::FLAC__metadata_object_clone(object)), + is_reference_(false) + { + FLAC__ASSERT(0 != object); + } + + Prototype::Prototype(::FLAC__StreamMetadata *object, bool copy): + object_(copy? ::FLAC__metadata_object_clone(object) : object), + is_reference_(false) + { + FLAC__ASSERT(0 != object); + } + + Prototype::~Prototype() + { + clear(); + } + + void Prototype::clear() + { + if(0 != object_ && !is_reference_) + FLAC__metadata_object_delete(object_); + object_ = 0; + } + + Prototype &Prototype::operator=(const Prototype &object) + { + FLAC__ASSERT(object.is_valid()); + clear(); + is_reference_ = false; + object_ = ::FLAC__metadata_object_clone(object.object_); + return *this; + } + + Prototype &Prototype::operator=(const ::FLAC__StreamMetadata &object) + { + clear(); + is_reference_ = false; + object_ = ::FLAC__metadata_object_clone(&object); + return *this; + } + + Prototype &Prototype::operator=(const ::FLAC__StreamMetadata *object) + { + FLAC__ASSERT(0 != object); + clear(); + is_reference_ = false; + object_ = ::FLAC__metadata_object_clone(object); + return *this; + } + + Prototype &Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy) + { + FLAC__ASSERT(0 != object); + clear(); + object_ = (copy? ::FLAC__metadata_object_clone(object) : object); + is_reference_ = false; + return *this; + } + + bool Prototype::get_is_last() const + { + FLAC__ASSERT(is_valid()); + return static_cast(object_->is_last); + } + + FLAC__MetadataType Prototype::get_type() const + { + FLAC__ASSERT(is_valid()); + return object_->type; + } + + uint32_t Prototype::get_length() const + { + FLAC__ASSERT(is_valid()); + return object_->length; + } + + void Prototype::set_is_last(bool value) + { + FLAC__ASSERT(is_valid()); + object_->is_last = value; + } + + + // + // StreamInfo + // + + StreamInfo::StreamInfo(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false) + { } + + StreamInfo::~StreamInfo() + { } + + uint32_t StreamInfo::get_min_blocksize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.min_blocksize; + } + + uint32_t StreamInfo::get_max_blocksize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.max_blocksize; + } + + uint32_t StreamInfo::get_min_framesize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.min_framesize; + } + + uint32_t StreamInfo::get_max_framesize() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.max_framesize; + } + + uint32_t StreamInfo::get_sample_rate() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.sample_rate; + } + + uint32_t StreamInfo::get_channels() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.channels; + } + + uint32_t StreamInfo::get_bits_per_sample() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.bits_per_sample; + } + + FLAC__uint64 StreamInfo::get_total_samples() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.total_samples; + } + + const FLAC__byte *StreamInfo::get_md5sum() const + { + FLAC__ASSERT(is_valid()); + return object_->data.stream_info.md5sum; + } + + void StreamInfo::set_min_blocksize(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE); + FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE); + object_->data.stream_info.min_blocksize = value; + } + + void StreamInfo::set_max_blocksize(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE); + FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE); + object_->data.stream_info.max_blocksize = value; + } + + void StreamInfo::set_min_framesize(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)); + object_->data.stream_info.min_framesize = value; + } + + void StreamInfo::set_max_framesize(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)); + object_->data.stream_info.max_framesize = value; + } + + void StreamInfo::set_sample_rate(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value)); + object_->data.stream_info.sample_rate = value; + } + + void StreamInfo::set_channels(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value > 0); + FLAC__ASSERT(value <= FLAC__MAX_CHANNELS); + object_->data.stream_info.channels = value; + } + + void StreamInfo::set_bits_per_sample(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE); + FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE); + object_->data.stream_info.bits_per_sample = value; + } + + void StreamInfo::set_total_samples(FLAC__uint64 value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value < (((FLAC__uint64)1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)); + object_->data.stream_info.total_samples = value; + } + + void StreamInfo::set_md5sum(const FLAC__byte value[16]) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != value); + std::memcpy(object_->data.stream_info.md5sum, value, 16); + } + + + // + // Padding + // + + Padding::Padding(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false) + { } + + Padding::Padding(uint32_t length): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false) + { + set_length(length); + } + + Padding::~Padding() + { } + + void Padding::set_length(uint32_t length) + { + FLAC__ASSERT(is_valid()); + object_->length = length; + } + + + // + // Application + // + + Application::Application(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false) + { } + + Application::~Application() + { } + + const FLAC__byte *Application::get_id() const + { + FLAC__ASSERT(is_valid()); + return object_->data.application.id; + } + + const FLAC__byte *Application::get_data() const + { + FLAC__ASSERT(is_valid()); + return object_->data.application.data; + } + + void Application::set_id(const FLAC__byte value[4]) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != value); + std::memcpy(object_->data.application.id, value, 4); + } + + bool Application::set_data(const FLAC__byte *data, uint32_t length) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_application_set_data(object_, const_cast(data), length, true)); + } + + bool Application::set_data(FLAC__byte *data, uint32_t length, bool copy) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_application_set_data(object_, data, length, copy)); + } + + + // + // SeekTable + // + + SeekTable::SeekTable(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false) + { } + + SeekTable::~SeekTable() + { } + + uint32_t SeekTable::get_num_points() const + { + FLAC__ASSERT(is_valid()); + return object_->data.seek_table.num_points; + } + + ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(uint32_t indx) const + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx < object_->data.seek_table.num_points); + return object_->data.seek_table.points[indx]; + } + + bool SeekTable::resize_points(uint32_t new_num_points) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_resize_points(object_, new_num_points)); + } + + void SeekTable::set_point(uint32_t indx, const ::FLAC__StreamMetadata_SeekPoint &point) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx < object_->data.seek_table.num_points); + ::FLAC__metadata_object_seektable_set_point(object_, indx, point); + } + + bool SeekTable::insert_point(uint32_t indx, const ::FLAC__StreamMetadata_SeekPoint &point) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx <= object_->data.seek_table.num_points); + return static_cast(::FLAC__metadata_object_seektable_insert_point(object_, indx, point)); + } + + bool SeekTable::delete_point(uint32_t indx) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx < object_->data.seek_table.num_points); + return static_cast(::FLAC__metadata_object_seektable_delete_point(object_, indx)); + } + + bool SeekTable::is_legal() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_is_legal(object_)); + } + + bool SeekTable::template_append_placeholders(uint32_t num) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_template_append_placeholders(object_, num)); + } + + bool SeekTable::template_append_point(FLAC__uint64 sample_number) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_template_append_point(object_, sample_number)); + } + + bool SeekTable::template_append_points(FLAC__uint64 sample_numbers[], uint32_t num) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_template_append_points(object_, sample_numbers, num)); + } + + bool SeekTable::template_append_spaced_points(uint32_t num, FLAC__uint64 total_samples) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_template_append_spaced_points(object_, num, total_samples)); + } + + bool SeekTable::template_append_spaced_points_by_samples(uint32_t samples, FLAC__uint64 total_samples) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(object_, samples, total_samples)); + } + + bool SeekTable::template_sort(bool compact) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_seektable_template_sort(object_, compact)); + } + + + // + // VorbisComment::Entry + // + + VorbisComment::Entry::Entry() : + is_valid_(true), + entry_(), + field_name_(0), + field_name_length_(0), + field_value_(0), + field_value_length_(0) + { + zero(); + } + + VorbisComment::Entry::Entry(const char *field, uint32_t field_length) : + is_valid_(true), + entry_(), + field_name_(0), + field_name_length_(0), + field_value_(0), + field_value_length_(0) + { + zero(); + construct(field, field_length); + } + + VorbisComment::Entry::Entry(const char *field) : + is_valid_(true), + entry_(), + field_name_(0), + field_name_length_(0), + field_value_(0), + field_value_length_(0) + { + zero(); + construct(field); + } + + VorbisComment::Entry::Entry(const char *field_name, const char *field_value, uint32_t field_value_length) : + is_valid_(true), + entry_(), + field_name_(0), + field_name_length_(0), + field_value_(0), + field_value_length_(0) + { + zero(); + construct(field_name, field_value, field_value_length); + } + + VorbisComment::Entry::Entry(const char *field_name, const char *field_value) : + is_valid_(true), + entry_(), + field_name_(0), + field_name_length_(0), + field_value_(0), + field_value_length_(0) + { + zero(); + construct(field_name, field_value); + } + + VorbisComment::Entry::Entry(const Entry &entry) : + is_valid_(true), + entry_(), + field_name_(0), + field_name_length_(0), + field_value_(0), + field_value_length_(0) + { + FLAC__ASSERT(entry.is_valid()); + zero(); + construct(reinterpret_cast(entry.entry_.entry), entry.entry_.length); + } + + VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry) + { + FLAC__ASSERT(entry.is_valid()); + clear(); + construct(reinterpret_cast(entry.entry_.entry), entry.entry_.length); + return *this; + } + + VorbisComment::Entry::~Entry() + { + clear(); + } + + bool VorbisComment::Entry::is_valid() const + { + return is_valid_; + } + + uint32_t VorbisComment::Entry::get_field_length() const + { + FLAC__ASSERT(is_valid()); + return entry_.length; + } + + uint32_t VorbisComment::Entry::get_field_name_length() const + { + FLAC__ASSERT(is_valid()); + return field_name_length_; + } + + uint32_t VorbisComment::Entry::get_field_value_length() const + { + FLAC__ASSERT(is_valid()); + return field_value_length_; + } + + ::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const + { + FLAC__ASSERT(is_valid()); + return entry_; + } + + const char *VorbisComment::Entry::get_field() const + { + FLAC__ASSERT(is_valid()); + return reinterpret_cast(entry_.entry); + } + + const char *VorbisComment::Entry::get_field_name() const + { + FLAC__ASSERT(is_valid()); + return field_name_; + } + + const char *VorbisComment::Entry::get_field_value() const + { + FLAC__ASSERT(is_valid()); + return field_value_; + } + + bool VorbisComment::Entry::set_field(const char *field, uint32_t field_length) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != field); + + if(!::FLAC__format_vorbiscomment_entry_is_legal(reinterpret_cast(field), field_length)) + return is_valid_ = false; + + clear_entry(); + + if(0 == (entry_.entry = static_cast(safe_malloc_add_2op_(field_length, /*+*/1)))) { + is_valid_ = false; + } + else { + entry_.length = field_length; + std::memcpy(entry_.entry, field, field_length); + entry_.entry[field_length] = '\0'; + (void) parse_field(); + } + + return is_valid_; + } + + bool VorbisComment::Entry::set_field(const char *field) + { + return set_field(field, std::strlen(field)); + } + + bool VorbisComment::Entry::set_field_name(const char *field_name) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != field_name); + + if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name)) + return is_valid_ = false; + + clear_field_name(); + + if(0 == (field_name_ = strdup(field_name))) { + is_valid_ = false; + } + else { + field_name_length_ = std::strlen(field_name_); + compose_field(); + } + + return is_valid_; + } + + bool VorbisComment::Entry::set_field_value(const char *field_value, uint32_t field_value_length) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != field_value); + + if(!::FLAC__format_vorbiscomment_entry_value_is_legal(reinterpret_cast(field_value), field_value_length)) + return is_valid_ = false; + + clear_field_value(); + + if(0 == (field_value_ = static_cast(safe_malloc_add_2op_(field_value_length, /*+*/1)))) { + is_valid_ = false; + } + else { + field_value_length_ = field_value_length; + std::memcpy(field_value_, field_value, field_value_length); + field_value_[field_value_length] = '\0'; + compose_field(); + } + + return is_valid_; + } + + bool VorbisComment::Entry::set_field_value(const char *field_value) + { + return set_field_value(field_value, std::strlen(field_value)); + } + + void VorbisComment::Entry::zero() + { + is_valid_ = true; + entry_.length = 0; + entry_.entry = 0; + field_name_ = 0; + field_name_length_ = 0; + field_value_ = 0; + field_value_length_ = 0; + } + + void VorbisComment::Entry::clear() + { + clear_entry(); + clear_field_name(); + clear_field_value(); + is_valid_ = true; + } + + void VorbisComment::Entry::clear_entry() + { + if(0 != entry_.entry) { + std::free(entry_.entry); + entry_.entry = 0; + entry_.length = 0; + } + } + + void VorbisComment::Entry::clear_field_name() + { + if(0 != field_name_) { + std::free(field_name_); + field_name_ = 0; + field_name_length_ = 0; + } + } + + void VorbisComment::Entry::clear_field_value() + { + if(0 != field_value_) { + std::free(field_value_); + field_value_ = 0; + field_value_length_ = 0; + } + } + + void VorbisComment::Entry::construct(const char *field, uint32_t field_length) + { + if(set_field(field, field_length)) + parse_field(); + } + + void VorbisComment::Entry::construct(const char *field) + { + construct(field, std::strlen(field)); + } + + void VorbisComment::Entry::construct(const char *field_name, const char *field_value, uint32_t field_value_length) + { + if(set_field_name(field_name) && set_field_value(field_value, field_value_length)) + compose_field(); + } + + void VorbisComment::Entry::construct(const char *field_name, const char *field_value) + { + construct(field_name, field_value, std::strlen(field_value)); + } + + void VorbisComment::Entry::compose_field() + { + clear_entry(); + + if(0 == (entry_.entry = static_cast(safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1)))) { + is_valid_ = false; + } + else { + std::memcpy(entry_.entry, field_name_, field_name_length_); + entry_.length += field_name_length_; + std::memcpy(entry_.entry + entry_.length, "=", 1); + entry_.length += 1; + if (field_value_length_ > 0) + std::memcpy(entry_.entry + entry_.length, field_value_, field_value_length_); + entry_.length += field_value_length_; + entry_.entry[entry_.length] = '\0'; + is_valid_ = true; + } + } + + void VorbisComment::Entry::parse_field() + { + clear_field_name(); + clear_field_value(); + + const char *p = static_cast(std::memchr(entry_.entry, '=', entry_.length)); + + if(0 == p) + p = reinterpret_cast(entry_.entry) + entry_.length; + + field_name_length_ = static_cast(p - reinterpret_cast(entry_.entry)); + if(0 == (field_name_ = static_cast(safe_malloc_add_2op_(field_name_length_, /*+*/1)))) { // +1 for the trailing \0 + is_valid_ = false; + return; + } + std::memcpy(field_name_, entry_.entry, field_name_length_); + field_name_[field_name_length_] = '\0'; + + if(entry_.length - field_name_length_ == 0) { + field_value_length_ = 0; + if(0 == (field_value_ = static_cast(safe_malloc_(0)))) { + is_valid_ = false; + return; + } + } + else { + field_value_length_ = entry_.length - field_name_length_ - 1; + if(0 == (field_value_ = static_cast(safe_malloc_add_2op_(field_value_length_, /*+*/1)))) { // +1 for the trailing \0 + is_valid_ = false; + return; + } + std::memcpy(field_value_, ++p, field_value_length_); + field_value_[field_value_length_] = '\0'; + } + + is_valid_ = true; + } + + + // + // VorbisComment + // + + VorbisComment::VorbisComment(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false) + { } + + VorbisComment::~VorbisComment() + { } + + uint32_t VorbisComment::get_num_comments() const + { + FLAC__ASSERT(is_valid()); + return object_->data.vorbis_comment.num_comments; + } + + const FLAC__byte *VorbisComment::get_vendor_string() const + { + FLAC__ASSERT(is_valid()); + return object_->data.vorbis_comment.vendor_string.entry; + } + + VorbisComment::Entry VorbisComment::get_comment(uint32_t indx) const + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments); + return Entry(reinterpret_cast(object_->data.vorbis_comment.comments[indx].entry), object_->data.vorbis_comment.comments[indx].length); + } + + bool VorbisComment::set_vendor_string(const FLAC__byte *string) + { + FLAC__ASSERT(is_valid()); + // vendor_string is a special kind of entry + const ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string = { static_cast(std::strlen(reinterpret_cast(string))), const_cast(string) }; // we can cheat on const-ness because we make a copy below: + return static_cast(::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true)); + } + + bool VorbisComment::resize_comments(uint32_t new_num_comments) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_vorbiscomment_resize_comments(object_, new_num_comments)); + } + + bool VorbisComment::set_comment(uint32_t indx, const VorbisComment::Entry &entry) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments); + return static_cast(::FLAC__metadata_object_vorbiscomment_set_comment(object_, indx, entry.get_entry(), /*copy=*/true)); + } + + bool VorbisComment::insert_comment(uint32_t indx, const VorbisComment::Entry &entry) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx <= object_->data.vorbis_comment.num_comments); + return static_cast(::FLAC__metadata_object_vorbiscomment_insert_comment(object_, indx, entry.get_entry(), /*copy=*/true)); + } + + bool VorbisComment::append_comment(const VorbisComment::Entry &entry) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true)); + } + + bool VorbisComment::replace_comment(const VorbisComment::Entry &entry, bool all) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_vorbiscomment_replace_comment(object_, entry.get_entry(), static_cast(all), /*copy=*/true)); + } + + bool VorbisComment::delete_comment(uint32_t indx) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments); + return static_cast(::FLAC__metadata_object_vorbiscomment_delete_comment(object_, indx)); + } + + int VorbisComment::find_entry_from(uint32_t offset, const char *field_name) + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_object_vorbiscomment_find_entry_from(object_, offset, field_name); + } + + int VorbisComment::remove_entry_matching(const char *field_name) + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_object_vorbiscomment_remove_entry_matching(object_, field_name); + } + + int VorbisComment::remove_entries_matching(const char *field_name) + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_object_vorbiscomment_remove_entries_matching(object_, field_name); + } + + + // + // CueSheet::Track + // + + CueSheet::Track::Track(): + object_(::FLAC__metadata_object_cuesheet_track_new()) + { } + + CueSheet::Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track *track): + object_(::FLAC__metadata_object_cuesheet_track_clone(track)) + { } + + CueSheet::Track::Track(const Track &track): + object_(::FLAC__metadata_object_cuesheet_track_clone(track.object_)) + { } + + CueSheet::Track &CueSheet::Track::operator=(const Track &track) + { + if(0 != object_) + ::FLAC__metadata_object_cuesheet_track_delete(object_); + object_ = ::FLAC__metadata_object_cuesheet_track_clone(track.object_); + return *this; + } + + CueSheet::Track::~Track() + { + if(0 != object_) + ::FLAC__metadata_object_cuesheet_track_delete(object_); + } + + bool CueSheet::Track::is_valid() const + { + return(0 != object_); + } + + ::FLAC__StreamMetadata_CueSheet_Index CueSheet::Track::get_index(uint32_t i) const + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(i < object_->num_indices); + return object_->indices[i]; + } + + void CueSheet::Track::set_isrc(const char value[12]) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != value); + std::memcpy(object_->isrc, value, 12); + object_->isrc[12] = '\0'; + } + + void CueSheet::Track::set_type(uint32_t value) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(value <= 1); + object_->type = value; + } + + void CueSheet::Track::set_index(uint32_t i, const ::FLAC__StreamMetadata_CueSheet_Index &indx) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(i < object_->num_indices); + object_->indices[i] = indx; + } + + + // + // CueSheet + // + + CueSheet::CueSheet(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false) + { } + + CueSheet::~CueSheet() + { } + + const char *CueSheet::get_media_catalog_number() const + { + FLAC__ASSERT(is_valid()); + return object_->data.cue_sheet.media_catalog_number; + } + + FLAC__uint64 CueSheet::get_lead_in() const + { + FLAC__ASSERT(is_valid()); + return object_->data.cue_sheet.lead_in; + } + + bool CueSheet::get_is_cd() const + { + FLAC__ASSERT(is_valid()); + return object_->data.cue_sheet.is_cd? true : false; + } + + uint32_t CueSheet::get_num_tracks() const + { + FLAC__ASSERT(is_valid()); + return object_->data.cue_sheet.num_tracks; + } + + CueSheet::Track CueSheet::get_track(uint32_t i) const + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks); + return Track(object_->data.cue_sheet.tracks + i); + } + + void CueSheet::set_media_catalog_number(const char value[128]) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(0 != value); + std::memcpy(object_->data.cue_sheet.media_catalog_number, value, 128); + object_->data.cue_sheet.media_catalog_number[128] = '\0'; + } + + void CueSheet::set_lead_in(FLAC__uint64 value) + { + FLAC__ASSERT(is_valid()); + object_->data.cue_sheet.lead_in = value; + } + + void CueSheet::set_is_cd(bool value) + { + FLAC__ASSERT(is_valid()); + object_->data.cue_sheet.is_cd = value; + } + + void CueSheet::set_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &indx) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices); + object_->data.cue_sheet.tracks[track_num].indices[index_num] = indx; + } + + bool CueSheet::resize_indices(uint32_t track_num, uint32_t new_num_indices) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks); + return static_cast(::FLAC__metadata_object_cuesheet_track_resize_indices(object_, track_num, new_num_indices)); + } + + bool CueSheet::insert_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &indx) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices); + return static_cast(::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, indx)); + } + + bool CueSheet::insert_blank_index(uint32_t track_num, uint32_t index_num) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num <= object_->data.cue_sheet.tracks[track_num].num_indices); + return static_cast(::FLAC__metadata_object_cuesheet_track_insert_blank_index(object_, track_num, index_num)); + } + + bool CueSheet::delete_index(uint32_t track_num, uint32_t index_num) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num < object_->data.cue_sheet.tracks[track_num].num_indices); + return static_cast(::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num)); + } + + bool CueSheet::resize_tracks(uint32_t new_num_tracks) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_cuesheet_resize_tracks(object_, new_num_tracks)); + } + + bool CueSheet::set_track(uint32_t i, const CueSheet::Track &track) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks); + // We can safely const_cast since copy=true + return static_cast(::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true)); + } + + bool CueSheet::insert_track(uint32_t i, const CueSheet::Track &track) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks); + // We can safely const_cast since copy=true + return static_cast(::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true)); + } + + bool CueSheet::insert_blank_track(uint32_t i) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks); + return static_cast(::FLAC__metadata_object_cuesheet_insert_blank_track(object_, i)); + } + + bool CueSheet::delete_track(uint32_t i) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks); + return static_cast(::FLAC__metadata_object_cuesheet_delete_track(object_, i)); + } + + bool CueSheet::is_legal(bool check_cd_da_subset, const char **violation) const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation)); + } + + FLAC__uint32 CueSheet::calculate_cddb_id() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_); + } + + + // + // Picture + // + + Picture::Picture(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false) + { } + + Picture::~Picture() + { } + + ::FLAC__StreamMetadata_Picture_Type Picture::get_type() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.type; + } + + const char *Picture::get_mime_type() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.mime_type; + } + + const FLAC__byte *Picture::get_description() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.description; + } + + FLAC__uint32 Picture::get_width() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.width; + } + + FLAC__uint32 Picture::get_height() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.height; + } + + FLAC__uint32 Picture::get_depth() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.depth; + } + + FLAC__uint32 Picture::get_colors() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.colors; + } + + FLAC__uint32 Picture::get_data_length() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.data_length; + } + + const FLAC__byte *Picture::get_data() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.data; + } + + void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type) + { + FLAC__ASSERT(is_valid()); + object_->data.picture.type = type; + } + + bool Picture::set_mime_type(const char *string) + { + FLAC__ASSERT(is_valid()); + // We can safely const_cast since copy=true + return static_cast(::FLAC__metadata_object_picture_set_mime_type(object_, const_cast(string), /*copy=*/true)); + } + + bool Picture::set_description(const FLAC__byte *string) + { + FLAC__ASSERT(is_valid()); + // We can safely const_cast since copy=true + return static_cast(::FLAC__metadata_object_picture_set_description(object_, const_cast(string), /*copy=*/true)); + } + + void Picture::set_width(FLAC__uint32 value) const + { + FLAC__ASSERT(is_valid()); + object_->data.picture.width = value; + } + + void Picture::set_height(FLAC__uint32 value) const + { + FLAC__ASSERT(is_valid()); + object_->data.picture.height = value; + } + + void Picture::set_depth(FLAC__uint32 value) const + { + FLAC__ASSERT(is_valid()); + object_->data.picture.depth = value; + } + + void Picture::set_colors(FLAC__uint32 value) const + { + FLAC__ASSERT(is_valid()); + object_->data.picture.colors = value; + } + + bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length) + { + FLAC__ASSERT(is_valid()); + // We can safely const_cast since copy=true + return static_cast(::FLAC__metadata_object_picture_set_data(object_, const_cast(data), data_length, /*copy=*/true)); + } + + bool Picture::is_legal(const char **violation) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_picture_is_legal(object_, violation)); + } + + + // + // Unknown + // + + Unknown::Unknown(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false) + { } + + Unknown::~Unknown() + { } + + const FLAC__byte *Unknown::get_data() const + { + FLAC__ASSERT(is_valid()); + return object_->data.application.data; + } + + bool Unknown::set_data(const FLAC__byte *data, uint32_t length) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_application_set_data(object_, const_cast(data), length, true)); + } + + bool Unknown::set_data(FLAC__byte *data, uint32_t length, bool copy) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_object_application_set_data(object_, data, length, copy)); + } + + + // ============================================================ + // + // Level 0 + // + // ============================================================ + + FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata object; + + if(::FLAC__metadata_get_streaminfo(filename, &object)) { + streaminfo = object; + return true; + } + else + return false; + } + + FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + tags = 0; + + if(::FLAC__metadata_get_tags(filename, &object)) { + tags = new VorbisComment(object, /*copy=*/false); + return true; + } + else + return false; + } + + FLACPP_API bool get_tags(const char *filename, VorbisComment &tags) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + if(::FLAC__metadata_get_tags(filename, &object)) { + tags.assign(object, /*copy=*/false); + return true; + } + else + return false; + } + + FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + cuesheet = 0; + + if(::FLAC__metadata_get_cuesheet(filename, &object)) { + cuesheet = new CueSheet(object, /*copy=*/false); + return true; + } + else + return false; + } + + FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + if(::FLAC__metadata_get_cuesheet(filename, &object)) { + cuesheet.assign(object, /*copy=*/false); + return true; + } + else + return false; + } + + FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + picture = 0; + + if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) { + picture = new Picture(object, /*copy=*/false); + return true; + } + else + return false; + } + + FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)) { + picture.assign(object, /*copy=*/false); + return true; + } + else + return false; + } + + + // ============================================================ + // + // Level 1 + // + // ============================================================ + + SimpleIterator::SimpleIterator(): + iterator_(::FLAC__metadata_simple_iterator_new()) + { } + + SimpleIterator::~SimpleIterator() + { + clear(); + } + + void SimpleIterator::clear() + { + if(0 != iterator_) + FLAC__metadata_simple_iterator_delete(iterator_); + iterator_ = 0; + } + + bool SimpleIterator::init(const char *filename, bool read_only, bool preserve_file_stats) + { + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats)); + } + + bool SimpleIterator::is_valid() const + { + return 0 != iterator_; + } + + SimpleIterator::Status SimpleIterator::status() + { + FLAC__ASSERT(is_valid()); + return Status(::FLAC__metadata_simple_iterator_status(iterator_)); + } + + bool SimpleIterator::is_writable() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_is_writable(iterator_)); + } + + bool SimpleIterator::next() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_next(iterator_)); + } + + bool SimpleIterator::prev() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_prev(iterator_)); + } + + //@@@@ add to tests + bool SimpleIterator::is_last() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_is_last(iterator_)); + } + + //@@@@ add to tests + off_t SimpleIterator::get_block_offset() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_); + } + + ::FLAC__MetadataType SimpleIterator::get_block_type() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_simple_iterator_get_block_type(iterator_); + } + + //@@@@ add to tests + uint32_t SimpleIterator::get_block_length() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_simple_iterator_get_block_length(iterator_); + } + + //@@@@ add to tests + bool SimpleIterator::get_application_id(FLAC__byte *id) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_get_application_id(iterator_, id)); + } + + Prototype *SimpleIterator::get_block() + { + FLAC__ASSERT(is_valid()); + return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_)); + } + + bool SimpleIterator::set_block(Prototype *block, bool use_padding) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding)); + } + + bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding)); + } + + bool SimpleIterator::delete_block(bool use_padding) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding)); + } + + + // ============================================================ + // + // Level 2 + // + // ============================================================ + + Chain::Chain(): + chain_(::FLAC__metadata_chain_new()) + { } + + Chain::~Chain() + { + clear(); + } + + void Chain::clear() + { + if(0 != chain_) + FLAC__metadata_chain_delete(chain_); + chain_ = 0; + } + + bool Chain::is_valid() const + { + return 0 != chain_; + } + + Chain::Status Chain::status() + { + FLAC__ASSERT(is_valid()); + return Status(::FLAC__metadata_chain_status(chain_)); + } + + bool Chain::read(const char *filename, bool is_ogg) + { + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(is_valid()); + return is_ogg? + static_cast(::FLAC__metadata_chain_read_ogg(chain_, filename)) : + static_cast(::FLAC__metadata_chain_read(chain_, filename)) + ; + } + + bool Chain::read(FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, bool is_ogg) + { + FLAC__ASSERT(is_valid()); + return is_ogg? + static_cast(::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks)) : + static_cast(::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks)) + ; + } + + bool Chain::check_if_tempfile_needed(bool use_padding) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding)); + } + + bool Chain::write(bool use_padding, bool preserve_file_stats) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats)); + } + + bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks)); + } + + bool Chain::write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks)); + } + + void Chain::merge_padding() + { + FLAC__ASSERT(is_valid()); + ::FLAC__metadata_chain_merge_padding(chain_); + } + + void Chain::sort_padding() + { + FLAC__ASSERT(is_valid()); + ::FLAC__metadata_chain_sort_padding(chain_); + } + + + Iterator::Iterator(): + iterator_(::FLAC__metadata_iterator_new()) + { } + + Iterator::~Iterator() + { + clear(); + } + + void Iterator::clear() + { + if(0 != iterator_) + FLAC__metadata_iterator_delete(iterator_); + iterator_ = 0; + } + + bool Iterator::is_valid() const + { + return 0 != iterator_; + } + + void Iterator::init(Chain &chain) + { + FLAC__ASSERT(is_valid()); + FLAC__ASSERT(chain.is_valid()); + ::FLAC__metadata_iterator_init(iterator_, chain.chain_); + } + + bool Iterator::next() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_iterator_next(iterator_)); + } + + bool Iterator::prev() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_iterator_prev(iterator_)); + } + + ::FLAC__MetadataType Iterator::get_block_type() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__metadata_iterator_get_block_type(iterator_); + } + + Prototype *Iterator::get_block() + { + FLAC__ASSERT(is_valid()); + Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_)); + if(0 != block) + block->set_reference(true); + return block; + } + + bool Iterator::set_block(Prototype *block) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + bool ret = static_cast(::FLAC__metadata_iterator_set_block(iterator_, block->object_)); + if(ret) { + block->set_reference(true); + delete block; + } + return ret; + } + + bool Iterator::delete_block(bool replace_with_padding) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding)); + } + + bool Iterator::insert_block_before(Prototype *block) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + bool ret = static_cast(::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_)); + if(ret) { + block->set_reference(true); + delete block; + } + return ret; + } + + bool Iterator::insert_block_after(Prototype *block) + { + FLAC__ASSERT(0 != block); + FLAC__ASSERT(is_valid()); + bool ret = static_cast(::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_)); + if(ret) { + block->set_reference(true); + delete block; + } + return ret; + } + + } // namespace Metadata +} // namespace FLAC diff --git a/vendor/flac/src/libFLAC++/stream_decoder.cpp b/vendor/flac/src/libFLAC++/stream_decoder.cpp new file mode 100644 index 0000000..6e351d9 --- /dev/null +++ b/vendor/flac/src/libFLAC++/stream_decoder.cpp @@ -0,0 +1,394 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "FLAC++/decoder.h" +#include "FLAC/assert.h" + +#ifdef _MSC_VER +// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning) +#pragma warning ( disable : 4800 ) +#endif + +namespace FLAC { + namespace Decoder { + + // ------------------------------------------------------------ + // + // Stream + // + // ------------------------------------------------------------ + + Stream::Stream(): + decoder_(::FLAC__stream_decoder_new()) + { } + + Stream::~Stream() + { + if(0 != decoder_) { + (void)::FLAC__stream_decoder_finish(decoder_); + ::FLAC__stream_decoder_delete(decoder_); + } + } + + bool Stream::is_valid() const + { + return 0 != decoder_; + } + + bool Stream::set_ogg_serial_number(long value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_ogg_serial_number(decoder_, value)); + } + + bool Stream::set_md5_checking(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_md5_checking(decoder_, value)); + } + + bool Stream::set_metadata_respond(::FLAC__MetadataType type) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_metadata_respond(decoder_, type)); + } + + bool Stream::set_metadata_respond_application(const FLAC__byte id[4]) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_metadata_respond_application(decoder_, id)); + } + + bool Stream::set_metadata_respond_all() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_metadata_respond_all(decoder_)); + } + + bool Stream::set_metadata_ignore(::FLAC__MetadataType type) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_metadata_ignore(decoder_, type)); + } + + bool Stream::set_metadata_ignore_application(const FLAC__byte id[4]) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_metadata_ignore_application(decoder_, id)); + } + + bool Stream::set_metadata_ignore_all() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_set_metadata_ignore_all(decoder_)); + } + + Stream::State Stream::get_state() const + { + FLAC__ASSERT(is_valid()); + return State(::FLAC__stream_decoder_get_state(decoder_)); + } + + bool Stream::get_md5_checking() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_get_md5_checking(decoder_)); + } + + FLAC__uint64 Stream::get_total_samples() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_get_total_samples(decoder_); + } + + uint32_t Stream::get_channels() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_get_channels(decoder_); + } + + ::FLAC__ChannelAssignment Stream::get_channel_assignment() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_get_channel_assignment(decoder_); + } + + uint32_t Stream::get_bits_per_sample() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_get_bits_per_sample(decoder_); + } + + uint32_t Stream::get_sample_rate() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_get_sample_rate(decoder_); + } + + uint32_t Stream::get_blocksize() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_get_blocksize(decoder_); + } + + bool Stream::get_decode_position(FLAC__uint64 *position) const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_get_decode_position(decoder_, position); + } + + ::FLAC__StreamDecoderInitStatus Stream::init() + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_init_stream(decoder_, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamDecoderInitStatus Stream::init_ogg() + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_decoder_init_ogg_stream(decoder_, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this); + } + + bool Stream::finish() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_finish(decoder_)); + } + + bool Stream::flush() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_flush(decoder_)); + } + + bool Stream::reset() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_reset(decoder_)); + } + + bool Stream::process_single() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_process_single(decoder_)); + } + + bool Stream::process_until_end_of_metadata() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_process_until_end_of_metadata(decoder_)); + } + + bool Stream::process_until_end_of_stream() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_process_until_end_of_stream(decoder_)); + } + + bool Stream::skip_single_frame() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_skip_single_frame(decoder_)); + } + + bool Stream::seek_absolute(FLAC__uint64 sample) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_decoder_seek_absolute(decoder_, sample)); + } + + ::FLAC__StreamDecoderSeekStatus Stream::seek_callback(FLAC__uint64 absolute_byte_offset) + { + (void)absolute_byte_offset; + return ::FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; + } + + ::FLAC__StreamDecoderTellStatus Stream::tell_callback(FLAC__uint64 *absolute_byte_offset) + { + (void)absolute_byte_offset; + return ::FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; + } + + ::FLAC__StreamDecoderLengthStatus Stream::length_callback(FLAC__uint64 *stream_length) + { + (void)stream_length; + return ::FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; + } + + bool Stream::eof_callback() + { + return false; + } + + void Stream::metadata_callback(const ::FLAC__StreamMetadata *metadata) + { + (void)metadata; + } + + ::FLAC__StreamDecoderReadStatus Stream::read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) + { + (void)decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->read_callback(buffer, bytes); + } + + ::FLAC__StreamDecoderSeekStatus Stream::seek_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) + { + (void) decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->seek_callback(absolute_byte_offset); + } + + ::FLAC__StreamDecoderTellStatus Stream::tell_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) + { + (void) decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->tell_callback(absolute_byte_offset); + } + + ::FLAC__StreamDecoderLengthStatus Stream::length_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) + { + (void) decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->length_callback(stream_length); + } + + FLAC__bool Stream::eof_callback_(const ::FLAC__StreamDecoder *decoder, void *client_data) + { + (void) decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->eof_callback(); + } + + ::FLAC__StreamDecoderWriteStatus Stream::write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) + { + (void)decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->write_callback(frame, buffer); + } + + void Stream::metadata_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data) + { + (void)decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + instance->metadata_callback(metadata); + } + + void Stream::error_callback_(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data) + { + (void)decoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + instance->error_callback(status); + } + + // ------------------------------------------------------------ + // + // File + // + // ------------------------------------------------------------ + + File::File(): + Stream() + { } + + File::~File() + { + } + + ::FLAC__StreamDecoderInitStatus File::init(FILE *file) + { + FLAC__ASSERT(0 != decoder_); + return ::FLAC__stream_decoder_init_FILE(decoder_, file, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamDecoderInitStatus File::init(const char *filename) + { + FLAC__ASSERT(0 != decoder_); + return ::FLAC__stream_decoder_init_file(decoder_, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamDecoderInitStatus File::init(const std::string &filename) + { + return init(filename.c_str()); + } + + ::FLAC__StreamDecoderInitStatus File::init_ogg(FILE *file) + { + FLAC__ASSERT(0 != decoder_); + return ::FLAC__stream_decoder_init_ogg_FILE(decoder_, file, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamDecoderInitStatus File::init_ogg(const char *filename) + { + FLAC__ASSERT(0 != decoder_); + return ::FLAC__stream_decoder_init_ogg_file(decoder_, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamDecoderInitStatus File::init_ogg(const std::string &filename) + { + return init_ogg(filename.c_str()); + } + + // This is a dummy to satisfy the pure virtual from Stream; the + // read callback will never be called since we are initializing + // with FLAC__stream_decoder_init_FILE() or + // FLAC__stream_decoder_init_file() and those supply the read + // callback internally. + ::FLAC__StreamDecoderReadStatus File::read_callback(FLAC__byte buffer[], size_t *bytes) + { + (void)buffer, (void)bytes; + FLAC__ASSERT(false); + return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; // double protection + } + + } // namespace Decoder +} // namespace FLAC diff --git a/vendor/flac/src/libFLAC++/stream_encoder.cpp b/vendor/flac/src/libFLAC++/stream_encoder.cpp new file mode 100644 index 0000000..8377129 --- /dev/null +++ b/vendor/flac/src/libFLAC++/stream_encoder.cpp @@ -0,0 +1,519 @@ +/* libFLAC++ - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "FLAC++/encoder.h" +#include "FLAC++/metadata.h" +#include "FLAC/assert.h" + +#ifdef _MSC_VER +// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning) +#pragma warning ( disable : 4800 ) +#endif + +namespace FLAC { + namespace Encoder { + + // ------------------------------------------------------------ + // + // Stream + // + // ------------------------------------------------------------ + + Stream::Stream(): + encoder_(::FLAC__stream_encoder_new()) + { } + + Stream::~Stream() + { + if(0 != encoder_) { + (void)::FLAC__stream_encoder_finish(encoder_); + ::FLAC__stream_encoder_delete(encoder_); + } + } + + bool Stream::is_valid() const + { + return 0 != encoder_; + } + + bool Stream::set_ogg_serial_number(long value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_ogg_serial_number(encoder_, value)); + } + + bool Stream::set_verify(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_verify(encoder_, value)); + } + + bool Stream::set_streamable_subset(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_streamable_subset(encoder_, value)); + } + + bool Stream::set_channels(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_channels(encoder_, value)); + } + + bool Stream::set_bits_per_sample(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_bits_per_sample(encoder_, value)); + } + + bool Stream::set_sample_rate(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_sample_rate(encoder_, value)); + } + + bool Stream::set_compression_level(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_compression_level(encoder_, value)); + } + + bool Stream::set_blocksize(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_blocksize(encoder_, value)); + } + + bool Stream::set_do_mid_side_stereo(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_do_mid_side_stereo(encoder_, value)); + } + + bool Stream::set_loose_mid_side_stereo(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_loose_mid_side_stereo(encoder_, value)); + } + + bool Stream::set_apodization(const char *specification) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_apodization(encoder_, specification)); + } + + bool Stream::set_max_lpc_order(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_max_lpc_order(encoder_, value)); + } + + bool Stream::set_qlp_coeff_precision(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_qlp_coeff_precision(encoder_, value)); + } + + bool Stream::set_do_qlp_coeff_prec_search(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder_, value)); + } + + bool Stream::set_do_escape_coding(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_do_escape_coding(encoder_, value)); + } + + bool Stream::set_do_exhaustive_model_search(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_do_exhaustive_model_search(encoder_, value)); + } + + bool Stream::set_min_residual_partition_order(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_min_residual_partition_order(encoder_, value)); + } + + bool Stream::set_max_residual_partition_order(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_max_residual_partition_order(encoder_, value)); + } + + bool Stream::set_rice_parameter_search_dist(uint32_t value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_rice_parameter_search_dist(encoder_, value)); + } + + bool Stream::set_total_samples_estimate(FLAC__uint64 value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_total_samples_estimate(encoder_, value)); + } + + bool Stream::set_metadata(::FLAC__StreamMetadata **metadata, uint32_t num_blocks) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_metadata(encoder_, metadata, num_blocks)); + } + + bool Stream::set_metadata(FLAC::Metadata::Prototype **metadata, uint32_t num_blocks) + { + FLAC__ASSERT(is_valid()); + // because C++ doesn't have VLA's (variable length arrays) + // this ugly workaround is needed + ::FLAC__StreamMetadata **m = new ::FLAC__StreamMetadata*[num_blocks]; + for(uint32_t i = 0; i < num_blocks; i++) { + // we can get away with the const_cast since we know the encoder will only correct the is_last flags + m[i] = const_cast< ::FLAC__StreamMetadata*>(static_cast(*metadata[i])); + } + // complete the hack + const bool ok = static_cast(::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks)); + delete [] m; + return ok; + } + + bool Stream::set_limit_min_bitrate(bool value) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_set_limit_min_bitrate(encoder_, value)); + } + + Stream::State Stream::get_state() const + { + FLAC__ASSERT(is_valid()); + return State(::FLAC__stream_encoder_get_state(encoder_)); + } + + Decoder::Stream::State Stream::get_verify_decoder_state() const + { + FLAC__ASSERT(is_valid()); + return Decoder::Stream::State(::FLAC__stream_encoder_get_verify_decoder_state(encoder_)); + } + + void Stream::get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got) + { + FLAC__ASSERT(is_valid()); + ::FLAC__stream_encoder_get_verify_decoder_error_stats(encoder_, absolute_sample, frame_number, channel, sample, expected, got); + } + + bool Stream::get_verify() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_verify(encoder_)); + } + + bool Stream::get_streamable_subset() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_streamable_subset(encoder_)); + } + + bool Stream::get_do_mid_side_stereo() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_do_mid_side_stereo(encoder_)); + } + + bool Stream::get_loose_mid_side_stereo() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_loose_mid_side_stereo(encoder_)); + } + + uint32_t Stream::get_channels() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_channels(encoder_); + } + + uint32_t Stream::get_bits_per_sample() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_bits_per_sample(encoder_); + } + + uint32_t Stream::get_sample_rate() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_sample_rate(encoder_); + } + + uint32_t Stream::get_blocksize() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_blocksize(encoder_); + } + + uint32_t Stream::get_max_lpc_order() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_max_lpc_order(encoder_); + } + + uint32_t Stream::get_qlp_coeff_precision() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_qlp_coeff_precision(encoder_); + } + + bool Stream::get_do_qlp_coeff_prec_search() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder_)); + } + + bool Stream::get_do_escape_coding() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_do_escape_coding(encoder_)); + } + + bool Stream::get_do_exhaustive_model_search() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_do_exhaustive_model_search(encoder_)); + } + + uint32_t Stream::get_min_residual_partition_order() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_min_residual_partition_order(encoder_); + } + + uint32_t Stream::get_max_residual_partition_order() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_max_residual_partition_order(encoder_); + } + + uint32_t Stream::get_rice_parameter_search_dist() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_rice_parameter_search_dist(encoder_); + } + + FLAC__uint64 Stream::get_total_samples_estimate() const + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_get_total_samples_estimate(encoder_); + } + + bool Stream::get_limit_min_bitrate() const + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_get_limit_min_bitrate(encoder_)); + } + + ::FLAC__StreamEncoderInitStatus Stream::init() + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_init_stream(encoder_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamEncoderInitStatus Stream::init_ogg() + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_init_ogg_stream(encoder_, read_callback_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*)this); + } + + bool Stream::finish() + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_finish(encoder_)); + } + + bool Stream::process(const FLAC__int32 * const buffer[], uint32_t samples) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_process(encoder_, buffer, samples)); + } + + bool Stream::process_interleaved(const FLAC__int32 buffer[], uint32_t samples) + { + FLAC__ASSERT(is_valid()); + return static_cast(::FLAC__stream_encoder_process_interleaved(encoder_, buffer, samples)); + } + + ::FLAC__StreamEncoderReadStatus Stream::read_callback(FLAC__byte buffer[], size_t *bytes) + { + (void)buffer, (void)bytes; + return ::FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED; + } + + ::FLAC__StreamEncoderSeekStatus Stream::seek_callback(FLAC__uint64 absolute_byte_offset) + { + (void)absolute_byte_offset; + return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; + } + + ::FLAC__StreamEncoderTellStatus Stream::tell_callback(FLAC__uint64 *absolute_byte_offset) + { + (void)absolute_byte_offset; + return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; + } + + void Stream::metadata_callback(const ::FLAC__StreamMetadata *metadata) + { + (void)metadata; + } + + ::FLAC__StreamEncoderReadStatus Stream::read_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) + { + (void)encoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->read_callback(buffer, bytes); + } + + ::FLAC__StreamEncoderWriteStatus Stream::write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data) + { + (void)encoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->write_callback(buffer, bytes, samples, current_frame); + } + + ::FLAC__StreamEncoderSeekStatus Stream::seek_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) + { + (void)encoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->seek_callback(absolute_byte_offset); + } + + ::FLAC__StreamEncoderTellStatus Stream::tell_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) + { + (void)encoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + return instance->tell_callback(absolute_byte_offset); + } + + void Stream::metadata_callback_(const ::FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data) + { + (void)encoder; + FLAC__ASSERT(0 != client_data); + Stream *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + instance->metadata_callback(metadata); + } + + // ------------------------------------------------------------ + // + // File + // + // ------------------------------------------------------------ + + File::File(): + Stream() + { } + + File::~File() + { + } + + ::FLAC__StreamEncoderInitStatus File::init(FILE *file) + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_init_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamEncoderInitStatus File::init(const char *filename) + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_init_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamEncoderInitStatus File::init(const std::string &filename) + { + return init(filename.c_str()); + } + + ::FLAC__StreamEncoderInitStatus File::init_ogg(FILE *file) + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_init_ogg_FILE(encoder_, file, progress_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamEncoderInitStatus File::init_ogg(const char *filename) + { + FLAC__ASSERT(is_valid()); + return ::FLAC__stream_encoder_init_ogg_file(encoder_, filename, progress_callback_, /*client_data=*/(void*)this); + } + + ::FLAC__StreamEncoderInitStatus File::init_ogg(const std::string &filename) + { + return init_ogg(filename.c_str()); + } + + // This is a dummy to satisfy the pure virtual from Stream; the + // read callback will never be called since we are initializing + // with FLAC__stream_decoder_init_FILE() or + // FLAC__stream_decoder_init_file() and those supply the read + // callback internally. + ::FLAC__StreamEncoderWriteStatus File::write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame) + { + (void)buffer, (void)bytes, (void)samples, (void)current_frame; + FLAC__ASSERT(false); + return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; // double protection + } + + void File::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate) + { + (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate; + } + + void File::progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data) + { + (void)encoder; + FLAC__ASSERT(0 != client_data); + File *instance = reinterpret_cast(client_data); + FLAC__ASSERT(0 != instance); + instance->progress_callback(bytes_written, samples_written, frames_written, total_frames_estimate); + } + + } // namespace Encoder +} // namespace FLAC diff --git a/vendor/flac/src/libFLAC++/version.rc b/vendor/flac/src/libFLAC++/version.rc new file mode 100644 index 0000000..14efba0 --- /dev/null +++ b/vendor/flac/src/libFLAC++/version.rc @@ -0,0 +1,40 @@ +#include +#include "config.h" +#include "FLAC++/export.h" + +#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE) +# ifdef GIT_COMMIT_TAG +# define VERSIONSTRING GIT_COMMIT_TAG +# else +# define VERSIONSTRING "git-" GIT_COMMIT_HASH +# endif +#else +# define VERSIONSTRING PACKAGE_VERSION +#endif + +#define xstr(s) str(s) +#define str(s) #s + +VS_VERSION_INFO VERSIONINFO +FILEVERSION FLACPP_API_VERSION_CURRENT,FLACPP_API_VERSION_REVISION,0,0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "libFLAC++ for Windows" + VALUE "ProductName", "Free Lossless Audio Codec" + VALUE "ProductVersion", VERSIONSTRING + VALUE "CompanyName", "Xiph.Org" + VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/vendor/flac/src/libFLAC/CMakeLists.txt b/vendor/flac/src/libFLAC/CMakeLists.txt new file mode 100644 index 0000000..cf7368f --- /dev/null +++ b/vendor/flac/src/libFLAC/CMakeLists.txt @@ -0,0 +1,126 @@ +option(WITH_ASM "Use any assembly optimization routines" ON) + +check_include_file("cpuid.h" HAVE_CPUID_H) +check_include_file("sys/param.h" HAVE_SYS_PARAM_H) + +set(CMAKE_REQUIRED_LIBRARIES m) +check_function_exists(lround HAVE_LROUND) + +include(CheckCSourceCompiles) +include(CheckCPUArch) +include(CheckA64NEON) + +check_cpu_arch_x64(FLAC__CPU_X86_64) +if(NOT FLAC__CPU_X86_64) + check_cpu_arch_x86(FLAC__CPU_IA32) +endif() + +if(FLAC__CPU_X86_64 OR FLAC__CPU_IA32) + set(FLAC__ALIGN_MALLOC_DATA 1) + option(WITH_AVX "Enable AVX, AVX2 optimizations (with runtime detection, resulting binary does not require AVX2, so only necessary when a compiler doesn't know about AVX)" ON) + if(WITH_AVX AND MSVC) + set_source_files_properties(fixed_intrin_avx2.c lpc_intrin_avx2.c stream_encoder_intrin_avx2.c lpc_intrin_fma.c PROPERTIES COMPILE_FLAGS /arch:AVX2) + endif() +else() + check_cpu_arch_arm64(FLAC__CPU_ARM64) + if(FLAC__CPU_ARM64) + check_a64neon(FLAC__HAS_A64NEONINTRIN) + endif() +endif() + +if(NOT WITH_ASM) + add_definitions(-DFLAC__NO_ASM) +endif() + +include_directories("include") + +add_library(FLAC + bitmath.c + bitreader.c + bitwriter.c + cpu.c + crc.c + fixed.c + fixed_intrin_sse2.c + fixed_intrin_ssse3.c + fixed_intrin_sse42.c + fixed_intrin_avx2.c + float.c + format.c + lpc.c + lpc_intrin_neon.c + lpc_intrin_sse2.c + lpc_intrin_sse41.c + lpc_intrin_avx2.c + lpc_intrin_fma.c + md5.c + memory.c + metadata_iterators.c + metadata_object.c + stream_decoder.c + stream_encoder.c + stream_encoder_intrin_sse2.c + stream_encoder_intrin_ssse3.c + stream_encoder_intrin_avx2.c + stream_encoder_framing.c + version.rc + window.c + $<$:../../include/share/win_utf8_io.h> + $<$:../share/win_utf8_io/win_utf8_io.c> + $<$:ogg_decoder_aspect.c> + $<$:ogg_encoder_aspect.c> + $<$:ogg_helper.c> + $<$:ogg_mapping.c>) +set_property(TARGET FLAC PROPERTY PROJECT_LABEL "libFLAC") +if(TARGET FLAC-asm) + target_sources(FLAC PRIVATE $) +endif() + +target_compile_definitions(FLAC + PRIVATE $<$:FLAC_API_EXPORTS> + PUBLIC $<$>:FLAC__NO_DLL>) +if(NOT WIN32) + target_compile_definitions(FLAC PRIVATE $<$:FLAC__USE_VISIBILITY_ATTR>) +endif() +target_include_directories(FLAC INTERFACE + "$" + "$") +target_link_libraries(FLAC PUBLIC $<$:m>) +if(TARGET Ogg::ogg) + target_link_libraries(FLAC PUBLIC Ogg::ogg) +endif() +if(BUILD_SHARED_LIBS) + set_target_properties(FLAC PROPERTIES + VERSION 12.1.0 + SOVERSION 12) + if(NOT WIN32) + set_target_properties(FLAC PROPERTIES C_VISIBILITY_PRESET hidden) + endif() +endif() + +check_c_compiler_flag("-fassociative-math -fno-signed-zeros -fno-trapping-math -freciprocal-math" HAVE_ASSOC_MATH) + +if(MSVC) + target_compile_options(FLAC BEFORE PRIVATE "/fp:fast") +else() + if(HAVE_ASSOC_MATH) + target_compile_options(FLAC BEFORE PRIVATE -fassociative-math -fno-signed-zeros -fno-trapping-math -freciprocal-math) + endif() +endif() + +add_library(FLAC::FLAC ALIAS FLAC) + +install(TARGETS FLAC EXPORT targets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/") + +if(INSTALL_PKGCONFIG_MODULES) + set(prefix "${CMAKE_INSTALL_PREFIX}") + set(exec_prefix "${CMAKE_INSTALL_PREFIX}") + set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") + set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") + configure_file(flac.pc.in flac.pc @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/flac.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +endif() diff --git a/vendor/flac/src/libFLAC/Makefile.am b/vendor/flac/src/libFLAC/Makefile.am new file mode 100644 index 0000000..618939d --- /dev/null +++ b/vendor/flac/src/libFLAC/Makefile.am @@ -0,0 +1,123 @@ +# libFLAC - Free Lossless Audio Codec library +# Copyright (C) 2001-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +lib_LTLIBRARIES = libFLAC.la +noinst_LTLIBRARIES = libFLAC-static.la +if DEBUG +DEBUGCFLAGS = -DFLAC__OVERFLOW_DETECT +else +if ASSOC_MATH_AVAILABLE +ASSOCMATHCFLAGS = -fassociative-math -fno-signed-zeros -fno-trapping-math -freciprocal-math +endif +endif + +AM_CFLAGS = $(DEBUGCFLAGS) ${ASSOCMATHCFLAGS} @OGG_CFLAGS@ + +libFLAC_la_LIBADD = @OGG_LIBS@ -lm + +SUBDIRS = include . + +m4datadir = $(datadir)/aclocal +m4data_DATA = libFLAC.m4 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = flac.pc + +EXTRA_DIST = \ + CMakeLists.txt \ + flac.pc.in \ + libFLAC.m4 \ + version.rc \ + deduplication/bitreader_read_rice_signed_block.c \ + deduplication/lpc_compute_autocorrelation_intrin.c \ + deduplication/lpc_compute_autocorrelation_intrin_sse2.c \ + deduplication/lpc_compute_autocorrelation_intrin_neon.c + +if OS_IS_WINDOWS +windows_unicode_compat = ../share/win_utf8_io/win_utf8_io.c +if HAVE_WINDRES +libFLAC_la_DEPENDENCIES = version.o +windows_resource_link = -Wl,version.o +endif +endif + +if FLaC__HAS_OGG +extra_ogg_sources = \ + ogg_decoder_aspect.c \ + ogg_encoder_aspect.c \ + ogg_helper.c \ + ogg_mapping.c +endif + +# see 'http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning' for numbering convention +libFLAC_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 13:0:1 $(windows_resource_link) + +libFLAC_sources = \ + bitmath.c \ + bitreader.c \ + bitwriter.c \ + cpu.c \ + crc.c \ + fixed.c \ + fixed_intrin_sse2.c \ + fixed_intrin_ssse3.c \ + fixed_intrin_sse42.c \ + fixed_intrin_avx2.c \ + float.c \ + format.c \ + lpc.c \ + lpc_intrin_sse2.c \ + lpc_intrin_sse41.c \ + lpc_intrin_avx2.c \ + lpc_intrin_fma.c \ + lpc_intrin_neon.c \ + md5.c \ + memory.c \ + metadata_iterators.c \ + metadata_object.c \ + stream_decoder.c \ + stream_encoder.c \ + stream_encoder_intrin_sse2.c \ + stream_encoder_intrin_ssse3.c \ + stream_encoder_intrin_avx2.c \ + stream_encoder_framing.c \ + window.c \ + $(windows_unicode_compat) \ + $(extra_ogg_sources) + +libFLAC_la_SOURCES = $(libFLAC_sources) + +# needed for test_libFLAC +libFLAC_static_la_SOURCES = $(libFLAC_sources) + +.rc.o: + $(RC) $(AM_CPPFLAGS) $< $@ diff --git a/vendor/flac/src/libFLAC/bitmath.c b/vendor/flac/src/libFLAC/bitmath.c new file mode 100644 index 0000000..077486b --- /dev/null +++ b/vendor/flac/src/libFLAC/bitmath.c @@ -0,0 +1,73 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/bitmath.h" + +/* An example of what FLAC__bitmath_silog2() computes: + * + * silog2(-10) = 5 + * silog2(- 9) = 5 + * silog2(- 8) = 4 + * silog2(- 7) = 4 + * silog2(- 6) = 4 + * silog2(- 5) = 4 + * silog2(- 4) = 3 + * silog2(- 3) = 3 + * silog2(- 2) = 2 + * silog2(- 1) = 2 + * silog2( 0) = 0 + * silog2( 1) = 2 + * silog2( 2) = 3 + * silog2( 3) = 3 + * silog2( 4) = 4 + * silog2( 5) = 4 + * silog2( 6) = 4 + * silog2( 7) = 4 + * silog2( 8) = 5 + * silog2( 9) = 5 + * silog2( 10) = 5 + */ +uint32_t FLAC__bitmath_silog2(FLAC__int64 v) +{ + if(v == 0) + return 0; + + if(v == -1) + return 2; + + v = (v < 0) ? (-(v+1)) : v; + return FLAC__bitmath_ilog2_wide(v)+2; +} diff --git a/vendor/flac/src/libFLAC/bitreader.c b/vendor/flac/src/libFLAC/bitreader.c new file mode 100644 index 0000000..829b308 --- /dev/null +++ b/vendor/flac/src/libFLAC/bitreader.c @@ -0,0 +1,1052 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "private/bitmath.h" +#include "private/bitreader.h" +#include "private/crc.h" +#include "private/cpu.h" +#include "private/macros.h" +#include "FLAC/assert.h" +#include "share/compat.h" +#include "share/endswap.h" + +/* Things should be fastest when this matches the machine word size */ +/* WATCHOUT: if you change this you must also change the following #defines down to COUNT_ZERO_MSBS2 below to match */ +/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */ +/* also, some sections currently only have fast versions for 4 or 8 bytes per word */ + +#if (ENABLE_64_BIT_WORDS == 0) + +typedef FLAC__uint32 brword; +#define FLAC__BYTES_PER_WORD 4 /* sizeof brword */ +#define FLAC__BITS_PER_WORD 32 +#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff) +/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */ +#if WORDS_BIGENDIAN +#define SWAP_BE_WORD_TO_HOST(x) (x) +#else +#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x) +#endif +/* counts the # of zero MSBs in a word */ +#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word) +#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word) + +#else + +typedef FLAC__uint64 brword; +#define FLAC__BYTES_PER_WORD 8 /* sizeof brword */ +#define FLAC__BITS_PER_WORD 64 +#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff)) +/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */ +#if WORDS_BIGENDIAN +#define SWAP_BE_WORD_TO_HOST(x) (x) +#else +#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x) +#endif +/* counts the # of zero MSBs in a word */ +#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word) +#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word) + +#endif + +/* + * This should be at least twice as large as the largest number of words + * required to represent any 'number' (in any encoding) you are going to + * read. With FLAC this is on the order of maybe a few hundred bits. + * If the buffer is smaller than that, the decoder won't be able to read + * in a whole number that is in a variable length encoding (e.g. Rice). + * But to be practical it should be at least 1K bytes. + * + * Increase this number to decrease the number of read callbacks, at the + * expense of using more memory. Or decrease for the reverse effect, + * keeping in mind the limit from the first paragraph. The optimal size + * also depends on the CPU cache size and other factors; some twiddling + * may be necessary to squeeze out the best performance. + */ +static const uint32_t FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */ + +struct FLAC__BitReader { + /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */ + /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */ + brword *buffer; + uint32_t capacity; /* in words */ + uint32_t words; /* # of completed words in buffer */ + uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */ + uint32_t consumed_words; /* #words ... */ + uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */ + uint32_t read_crc16; /* the running frame CRC */ + uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */ + uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */ + FLAC__bool read_limit_set; /* whether reads are limited */ + uint32_t read_limit; /* the remaining size of what can be read */ + uint32_t last_seen_framesync; /* the location of the last seen framesync, if it is in the buffer, in bits from front of buffer */ + FLAC__BitReaderReadCallback read_callback; + void *client_data; +}; + +static inline void crc16_update_word_(FLAC__BitReader *br, brword word) +{ + register uint32_t crc = br->read_crc16; + + for ( ; br->crc16_align < FLAC__BITS_PER_WORD ; br->crc16_align += 8) { + uint32_t shift = FLAC__BITS_PER_WORD - 8 - br->crc16_align ; + crc = FLAC__CRC16_UPDATE ((uint32_t) (shift < FLAC__BITS_PER_WORD ? (word >> shift) & 0xff : 0), crc); + } + + br->read_crc16 = crc; + br->crc16_align = 0; +} + +static inline void crc16_update_block_(FLAC__BitReader *br) +{ + if(br->consumed_words > br->crc16_offset && br->crc16_align) + crc16_update_word_(br, br->buffer[br->crc16_offset++]); + + /* Prevent OOB read due to wrap-around. */ + if (br->consumed_words > br->crc16_offset) { +#if FLAC__BYTES_PER_WORD == 4 + br->read_crc16 = FLAC__crc16_update_words32(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16); +#elif FLAC__BYTES_PER_WORD == 8 + br->read_crc16 = FLAC__crc16_update_words64(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16); +#else + unsigned i; + + for (i = br->crc16_offset; i < br->consumed_words; i++) + crc16_update_word_(br, br->buffer[i]); +#endif + } + + br->crc16_offset = 0; +} + +static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br) +{ + uint32_t start, end; + size_t bytes; + FLAC__byte *target; +#if WORDS_BIGENDIAN +#else + brword preswap_backup; +#endif + + /* first shift the unconsumed buffer data toward the front as much as possible */ + if(br->consumed_words > 0) { + /* invalidate last seen framesync */ + br->last_seen_framesync = -1; + + crc16_update_block_(br); /* CRC consumed words */ + + start = br->consumed_words; + end = br->words + (br->bytes? 1:0); + memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start)); + + br->words -= start; + br->consumed_words = 0; + } + + /* + * set the target for reading, taking into account word alignment and endianness + */ + bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes; + if(bytes == 0) + return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY */ + target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes; + + /* before reading, if the existing reader looks like this (say brword is 32 bits wide) + * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 (partial tail word is left-justified) + * buffer[BE]: 11 22 33 44 55 ?? ?? ?? (shown laid out as bytes sequentially in memory) + * buffer[LE]: 44 33 22 11 ?? ?? ?? 55 (?? being don't-care) + * ^^-------target, bytes=3 + * on LE machines, have to byteswap the odd tail word so nothing is + * overwritten: + */ +#if WORDS_BIGENDIAN +#else + preswap_backup = br->buffer[br->words]; + if(br->bytes) + br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]); +#endif + + /* now it looks like: + * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 + * buffer[BE]: 11 22 33 44 55 ?? ?? ?? + * buffer[LE]: 44 33 22 11 55 ?? ?? ?? + * ^^-------target, bytes=3 + */ + + /* read in the data; note that the callback may return a smaller number of bytes */ + if(!br->read_callback(target, &bytes, br->client_data)){ + /* Despite the read callback failing, the data in the target + * might be used later, when the buffer is rewound. Therefore + * we revert the swap that was just done */ +#if WORDS_BIGENDIAN +#else + br->buffer[br->words] = preswap_backup; +#endif + return false; + } + + /* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client: + * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF + * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? + * buffer[LE]: 44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ?? + * now have to byteswap on LE machines: + */ +#if WORDS_BIGENDIAN +#else + end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD; + for(start = br->words; start < end; start++) + br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]); +#endif + + /* now it looks like: + * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF + * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? + * buffer[LE]: 44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD + * finally we'll update the reader values: + */ + end = br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes; + br->words = end / FLAC__BYTES_PER_WORD; + br->bytes = end % FLAC__BYTES_PER_WORD; + + return true; +} + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC__BitReader *FLAC__bitreader_new(void) +{ + FLAC__BitReader *br = calloc(1, sizeof(FLAC__BitReader)); + + /* calloc() implies: + memset(br, 0, sizeof(FLAC__BitReader)); + br->buffer = 0; + br->capacity = 0; + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + br->read_callback = 0; + br->client_data = 0; + */ + return br; +} + +void FLAC__bitreader_delete(FLAC__BitReader *br) +{ + FLAC__ASSERT(0 != br); + + FLAC__bitreader_free(br); + free(br); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd) +{ + FLAC__ASSERT(0 != br); + + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY; + br->buffer = malloc(sizeof(brword) * br->capacity); + if(br->buffer == 0) + return false; + br->read_callback = rcb; + br->client_data = cd; + br->read_limit_set = false; + br->read_limit = -1; + br->last_seen_framesync = -1; + + return true; +} + +void FLAC__bitreader_free(FLAC__BitReader *br) +{ + FLAC__ASSERT(0 != br); + + if(0 != br->buffer) + free(br->buffer); + br->buffer = 0; + br->capacity = 0; + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + br->read_callback = 0; + br->client_data = 0; + br->read_limit_set = false; + br->read_limit = -1; + br->last_seen_framesync = -1; +} + +FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br) +{ + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + br->read_limit_set = false; + br->read_limit = -1; + br->last_seen_framesync = -1; + return true; +} + +void FLAC__bitreader_set_framesync_location(FLAC__BitReader *br) +{ + br->last_seen_framesync = br->consumed_words * FLAC__BYTES_PER_WORD + br->consumed_bits / 8; +} + +FLAC__bool FLAC__bitreader_rewind_to_after_last_seen_framesync(FLAC__BitReader *br) +{ + if(br->last_seen_framesync == (uint32_t)-1) { + br->consumed_words = br->consumed_bits = 0; + return false; + } + else { + br->consumed_words = (br->last_seen_framesync + 1) / FLAC__BYTES_PER_WORD; + br->consumed_bits = ((br->last_seen_framesync + 1) % FLAC__BYTES_PER_WORD) * 8; + return true; + } +} + +void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed) +{ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT((br->consumed_bits & 7) == 0); + + br->read_crc16 = (uint32_t)seed; + br->crc16_offset = br->consumed_words; + br->crc16_align = br->consumed_bits; +} + +FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br) +{ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + /* CRC consumed words up to here */ + crc16_update_block_(br); + + FLAC__ASSERT((br->consumed_bits & 7) == 0); + FLAC__ASSERT(br->crc16_align <= br->consumed_bits); + + /* CRC any tail bytes in a partially-consumed word */ + if(br->consumed_bits) { + const brword tail = br->buffer[br->consumed_words]; + for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8) + br->read_crc16 = FLAC__CRC16_UPDATE((uint32_t)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16); + } + return br->read_crc16; +} + +inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br) +{ + return ((br->consumed_bits & 7) == 0); +} + +inline uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br) +{ + return 8 - (br->consumed_bits & 7); +} + +inline uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br) +{ + return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits; +} + +void FLAC__bitreader_set_limit(FLAC__BitReader *br, uint32_t limit) +{ + br->read_limit = limit; + br->read_limit_set = true; +} + +void FLAC__bitreader_remove_limit(FLAC__BitReader *br) +{ + br->read_limit_set = false; + br->read_limit = -1; +} + +uint32_t FLAC__bitreader_limit_remaining(FLAC__BitReader *br) +{ + FLAC__ASSERT(br->read_limit_set); + return br->read_limit; +} +void FLAC__bitreader_limit_invalidate(FLAC__BitReader *br) +{ + br->read_limit = -1; +} + +FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits) +{ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + FLAC__ASSERT(bits <= 32); + FLAC__ASSERT((br->capacity*FLAC__BITS_PER_WORD) * 2 >= bits); + FLAC__ASSERT(br->consumed_words <= br->words); + + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); + + if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */ + *val = 0; + return true; + } + + if(br->read_limit_set && br->read_limit < (uint32_t)-1){ + if(br->read_limit < bits) { + br->read_limit = -1; + return false; + } + else + br->read_limit -= bits; + } + + while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) { + if(!bitreader_read_from_client_(br)) + return false; + } + if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ + /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ + if(br->consumed_bits) { + /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ + const uint32_t n = FLAC__BITS_PER_WORD - br->consumed_bits; + const brword word = br->buffer[br->consumed_words]; + const brword mask = br->consumed_bits < FLAC__BITS_PER_WORD ? FLAC__WORD_ALL_ONES >> br->consumed_bits : 0; + if(bits < n) { + uint32_t shift = n - bits; + *val = shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)((word & mask) >> shift) : 0; /* The result has <= 32 non-zero bits */ + br->consumed_bits += bits; + return true; + } + /* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */ + *val = (FLAC__uint32)(word & mask); + bits -= n; + br->consumed_words++; + br->consumed_bits = 0; + if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */ + uint32_t shift = FLAC__BITS_PER_WORD - bits; + *val = bits < 32 ? *val << bits : 0; + *val |= shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)(br->buffer[br->consumed_words] >> shift) : 0; + br->consumed_bits = bits; + } + return true; + } + else { /* br->consumed_bits == 0 */ + const brword word = br->buffer[br->consumed_words]; + if(bits < FLAC__BITS_PER_WORD) { + *val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits)); + br->consumed_bits = bits; + return true; + } + /* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */ + *val = (FLAC__uint32)word; + br->consumed_words++; + return true; + } + } + else { + /* in this case we're starting our read at a partial tail word; + * the reader has guaranteed that we have at least 'bits' bits + * available to read, which makes this case simpler. + */ + /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ + if(br->consumed_bits) { + /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ + FLAC__ASSERT(br->consumed_bits + bits <= br->bytes*8); + *val = (FLAC__uint32)((br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits)); + br->consumed_bits += bits; + return true; + } + else { + *val = (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits)); + br->consumed_bits += bits; + return true; + } + } +} + +FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits) +{ + FLAC__uint32 uval, mask; + /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */ + if (bits < 1 || ! FLAC__bitreader_read_raw_uint32(br, &uval, bits)) + return false; + /* sign-extend *val assuming it is currently bits wide. */ + /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */ + mask = bits >= 33 ? 0 : 1lu << (bits - 1); + *val = (uval ^ mask) - mask; + return true; +} + +FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits) +{ + FLAC__uint32 hi, lo; + + if(bits > 32) { + if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32)) + return false; + if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32)) + return false; + *val = hi; + *val <<= 32; + *val |= lo; + } + else { + if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits)) + return false; + *val = lo; + } + return true; +} + +FLAC__bool FLAC__bitreader_read_raw_int64(FLAC__BitReader *br, FLAC__int64 *val, uint32_t bits) +{ + FLAC__uint64 uval, mask; + /* OPT: inline raw uint64 code here, or make into a macro if possible in the .h file */ + if (bits < 1 || ! FLAC__bitreader_read_raw_uint64(br, &uval, bits)) + return false; + /* sign-extend *val assuming it is currently bits wide. */ + /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */ + mask = bits >= 65 ? 0 : 1llu << (bits - 1); + *val = (uval ^ mask) - mask; + return true; +} + +inline FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val) +{ + FLAC__uint32 x8, x32 = 0; + + /* this doesn't need to be that fast as currently it is only used for vorbis comments */ + + if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8)) + return false; + + if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) + return false; + x32 |= (x8 << 8); + + if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) + return false; + x32 |= (x8 << 16); + + if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) + return false; + x32 |= (x8 << 24); + + *val = x32; + return true; +} + +FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits) +{ + /* + * OPT: a faster implementation is possible but probably not that useful + * since this is only called a couple of times in the metadata readers. + */ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + if(bits > 0) { + const uint32_t n = br->consumed_bits & 7; + uint32_t m; + FLAC__uint32 x; + + if(n != 0) { + m = flac_min(8-n, bits); + if(!FLAC__bitreader_read_raw_uint32(br, &x, m)) + return false; + bits -= m; + } + m = bits / 8; + if(m > 0) { + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m)) + return false; + bits %= 8; + } + if(bits > 0) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, bits)) + return false; + } + } + + return true; +} + +FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals) +{ + FLAC__uint32 x; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); + + if(br->read_limit_set && br->read_limit < (uint32_t)-1){ + if(br->read_limit < nvals*8){ + br->read_limit = -1; + return false; + } + } + + /* step 1: skip over partial head word to get word aligned */ + while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + nvals--; + } + if(0 == nvals) + return true; + + /* step 2: skip whole words in chunks */ + while(nvals >= FLAC__BYTES_PER_WORD) { + if(br->consumed_words < br->words) { + br->consumed_words++; + nvals -= FLAC__BYTES_PER_WORD; + if(br->read_limit_set) + br->read_limit -= FLAC__BITS_PER_WORD; + } + else if(!bitreader_read_from_client_(br)) + return false; + } + /* step 3: skip any remainder from partial tail bytes */ + while(nvals) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + nvals--; + } + + return true; +} + +FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals) +{ + FLAC__uint32 x; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); + + if(br->read_limit_set && br->read_limit < (uint32_t)-1){ + if(br->read_limit < nvals*8){ + br->read_limit = -1; + return false; + } + } + + /* step 1: read from partial head word to get word aligned */ + while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + *val++ = (FLAC__byte)x; + nvals--; + } + if(0 == nvals) + return true; + /* step 2: read whole words in chunks */ + while(nvals >= FLAC__BYTES_PER_WORD) { + if(br->consumed_words < br->words) { + const brword word = br->buffer[br->consumed_words++]; +#if FLAC__BYTES_PER_WORD == 4 + val[0] = (FLAC__byte)(word >> 24); + val[1] = (FLAC__byte)(word >> 16); + val[2] = (FLAC__byte)(word >> 8); + val[3] = (FLAC__byte)word; +#elif FLAC__BYTES_PER_WORD == 8 + val[0] = (FLAC__byte)(word >> 56); + val[1] = (FLAC__byte)(word >> 48); + val[2] = (FLAC__byte)(word >> 40); + val[3] = (FLAC__byte)(word >> 32); + val[4] = (FLAC__byte)(word >> 24); + val[5] = (FLAC__byte)(word >> 16); + val[6] = (FLAC__byte)(word >> 8); + val[7] = (FLAC__byte)word; +#else + for(x = 0; x < FLAC__BYTES_PER_WORD; x++) + val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1))); +#endif + val += FLAC__BYTES_PER_WORD; + nvals -= FLAC__BYTES_PER_WORD; + if(br->read_limit_set) + br->read_limit -= FLAC__BITS_PER_WORD; + } + else if(!bitreader_read_from_client_(br)) + return false; + } + /* step 3: read any remainder from partial tail bytes */ + while(nvals) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + *val++ = (FLAC__byte)x; + nvals--; + } + + return true; +} + +FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val) +#if 0 /* slow but readable version */ +{ + uint32_t bit; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + *val = 0; + while(1) { + if(!FLAC__bitreader_read_bit(br, &bit)) + return false; + if(bit) + break; + else + *val++; + } + return true; +} +#else +{ + uint32_t i; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + *val = 0; + while(1) { + while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ + brword b = br->consumed_bits < FLAC__BITS_PER_WORD ? br->buffer[br->consumed_words] << br->consumed_bits : 0; + if(b) { + i = COUNT_ZERO_MSBS(b); + *val += i; + i++; + br->consumed_bits += i; + if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */ + br->consumed_words++; + br->consumed_bits = 0; + } + return true; + } + else { + *val += FLAC__BITS_PER_WORD - br->consumed_bits; + br->consumed_words++; + br->consumed_bits = 0; + /* didn't find stop bit yet, have to keep going... */ + } + } + /* at this point we've eaten up all the whole words; have to try + * reading through any tail bytes before calling the read callback. + * this is a repeat of the above logic adjusted for the fact we + * don't have a whole word. note though if the client is feeding + * us data a byte at a time (unlikely), br->consumed_bits may not + * be zero. + */ + if(br->bytes*8 > br->consumed_bits) { + const uint32_t end = br->bytes * 8; + brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits; + if(b) { + i = COUNT_ZERO_MSBS(b); + *val += i; + i++; + br->consumed_bits += i; + FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); + return true; + } + else { + *val += end - br->consumed_bits; + br->consumed_bits = end; + FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); + /* didn't find stop bit yet, have to keep going... */ + } + } + if(!bitreader_read_from_client_(br)) + return false; + } +} +#endif + +#if 0 /* unused */ +FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter) +{ + FLAC__uint32 lsbs = 0, msbs = 0; + uint32_t uval; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT(parameter <= 31); + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter)) + return false; + + /* compose the value */ + uval = (msbs << parameter) | lsbs; + if(uval & 1) + *val = -((int)(uval >> 1)) - 1; + else + *val = (int)(uval >> 1); + + return true; +} +#endif + +/* this is by far the most heavily used reader call. it ain't pretty but it's fast */ +FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter) +#include "deduplication/bitreader_read_rice_signed_block.c" + +#ifdef FLAC__BMI2_SUPPORTED +FLAC__SSE_TARGET("bmi2") +FLAC__bool FLAC__bitreader_read_rice_signed_block_bmi2(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter) +#include "deduplication/bitreader_read_rice_signed_block.c" +#endif + +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter) +{ + FLAC__uint32 lsbs = 0, msbs = 0; + uint32_t bit, uval, k; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + k = FLAC__bitmath_ilog2(parameter); + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) + return false; + + if(parameter == 1u<= d) { + if(!FLAC__bitreader_read_bit(br, &bit)) + return false; + lsbs <<= 1; + lsbs |= bit; + lsbs -= d; + } + /* compose the value */ + uval = msbs * parameter + lsbs; + } + + /* unfold uint32_t to signed */ + if(uval & 1) + *val = -((int)(uval >> 1)) - 1; + else + *val = (int)(uval >> 1); + + return true; +} + +FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter) +{ + FLAC__uint32 lsbs, msbs = 0; + uint32_t bit, k; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + k = FLAC__bitmath_ilog2(parameter); + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) + return false; + + if(parameter == 1u<= d) { + if(!FLAC__bitreader_read_bit(br, &bit)) + return false; + lsbs <<= 1; + lsbs |= bit; + lsbs -= d; + } + /* compose the value */ + *val = msbs * parameter + lsbs; + } + + return true; +} +#endif /* UNUSED */ + +/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */ +FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen) +{ + FLAC__uint32 v = 0; + FLAC__uint32 x; + uint32_t i; + + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80)) { /* 0xxxxxxx */ + v = x; + i = 0; + } + else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ + v = x & 0x1F; + i = 1; + } + else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ + v = x & 0x0F; + i = 2; + } + else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ + v = x & 0x07; + i = 3; + } + else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ + v = x & 0x03; + i = 4; + } + else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ + v = x & 0x01; + i = 5; + } + else { + *val = 0xffffffff; + return true; + } + for( ; i; i--) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ + *val = 0xffffffff; + return true; + } + v <<= 6; + v |= (x & 0x3F); + } + *val = v; + return true; +} + +/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */ +FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen) +{ + FLAC__uint64 v = 0; + FLAC__uint32 x; + uint32_t i; + + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80)) { /* 0xxxxxxx */ + v = x; + i = 0; + } + else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ + v = x & 0x1F; + i = 1; + } + else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ + v = x & 0x0F; + i = 2; + } + else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ + v = x & 0x07; + i = 3; + } + else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ + v = x & 0x03; + i = 4; + } + else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ + v = x & 0x01; + i = 5; + } + else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */ + v = 0; + i = 6; + } + else { + *val = FLAC__U64L(0xffffffffffffffff); + return true; + } + for( ; i; i--) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ + *val = FLAC__U64L(0xffffffffffffffff); + return true; + } + v <<= 6; + v |= (x & 0x3F); + } + *val = v; + return true; +} + +/* These functions are declared inline in this file but are also callable as + * externs from elsewhere. + * According to the C99 spec, section 6.7.4, simply providing a function + * prototype in a header file without 'inline' and making the function inline + * in this file should be sufficient. + * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To + * fix that we add extern declarations here. + */ +extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); +extern uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); +extern uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); +extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); diff --git a/vendor/flac/src/libFLAC/bitwriter.c b/vendor/flac/src/libFLAC/bitwriter.c new file mode 100644 index 0000000..1d7be80 --- /dev/null +++ b/vendor/flac/src/libFLAC/bitwriter.c @@ -0,0 +1,955 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "private/bitwriter.h" +#include "private/crc.h" +#include "private/format.h" +#include "private/macros.h" +#include "private/stream_encoder.h" +#include "FLAC/assert.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "share/endswap.h" + +/* Things should be fastest when this matches the machine word size */ +/* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */ +/* WATCHOUT: there are a few places where the code will not work unless bwword is >= 32 bits wide */ + +#if (ENABLE_64_BIT_WORDS == 0) + +typedef FLAC__uint32 bwword; +typedef FLAC__uint64 FLAC__bwtemp; +#define FLAC__BYTES_PER_WORD 4 /* sizeof bwword */ +#define FLAC__BITS_PER_WORD 32 +#define FLAC__TEMP_BITS 64 +#define FLAC__HALF_TEMP_BITS 32 +/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */ +#if WORDS_BIGENDIAN +#define SWAP_BE_WORD_TO_HOST(x) (x) +#else +#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x) +#endif + +#else + +typedef FLAC__uint64 bwword; +typedef FLAC__uint64 FLAC__bwtemp; +#define FLAC__BYTES_PER_WORD 8 /* sizeof bwword */ +#define FLAC__BITS_PER_WORD 64 +#define FLAC__TEMP_BITS 64 +#define FLAC__HALF_TEMP_BITS 32 +/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */ +#if WORDS_BIGENDIAN +#define SWAP_BE_WORD_TO_HOST(x) (x) +#else +#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x) +#endif + +#endif + +/* + * The default capacity here doesn't matter too much. The buffer always grows + * to hold whatever is written to it. Usually the encoder will stop adding at + * a frame or metadata block, then write that out and clear the buffer for the + * next one. + */ +static const uint32_t FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */ +/* When growing, increment 4K at a time */ +static const uint32_t FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* size in words */ + +#define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD) +#define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits) + +struct FLAC__BitWriter { + bwword *buffer; + bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */ + uint32_t capacity; /* capacity of buffer in words */ + uint32_t words; /* # of complete words in buffer */ + uint32_t bits; /* # of used bits in accum */ +}; + +/* * WATCHOUT: The current implementation only grows the buffer. */ +#ifndef __SUNPRO_C +static +#endif +FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, uint32_t bits_to_add) +{ + uint32_t new_capacity; + bwword *new_buffer; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + /* calculate total words needed to store 'bits_to_add' additional bits */ + new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD); + + /* it's possible (due to pessimism in the growth estimation that + * leads to this call) that we don't actually need to grow + */ + if(bw->capacity >= new_capacity) + return true; + + if(new_capacity * sizeof(bwword) > (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) + /* Requested new capacity is larger than the largest possible metadata block, + * which is also larger than the largest sane framesize. That means something + * went very wrong somewhere and previous checks failed. + * To prevent chrashing, give up */ + return false; + + /* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */ + if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT) + new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); + /* make sure we got everything right */ + FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); + FLAC__ASSERT(new_capacity > bw->capacity); + FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD)); + + new_buffer = safe_realloc_nofree_mul_2op_(bw->buffer, sizeof(bwword), /*times*/new_capacity); + if(new_buffer == 0) + return false; + bw->buffer = new_buffer; + bw->capacity = new_capacity; + return true; +} + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC__BitWriter *FLAC__bitwriter_new(void) +{ + FLAC__BitWriter *bw = calloc(1, sizeof(FLAC__BitWriter)); + /* note that calloc() sets all members to 0 for us */ + return bw; +} + +void FLAC__bitwriter_delete(FLAC__BitWriter *bw) +{ + FLAC__ASSERT(0 != bw); + + FLAC__bitwriter_free(bw); + free(bw); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw) +{ + FLAC__ASSERT(0 != bw); + + bw->words = bw->bits = 0; + bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY; + bw->buffer = malloc(sizeof(bwword) * bw->capacity); + if(bw->buffer == 0) + return false; + + return true; +} + +void FLAC__bitwriter_free(FLAC__BitWriter *bw) +{ + FLAC__ASSERT(0 != bw); + + if(0 != bw->buffer) + free(bw->buffer); + bw->buffer = 0; + bw->capacity = 0; + bw->words = bw->bits = 0; +} + +void FLAC__bitwriter_clear(FLAC__BitWriter *bw) +{ + bw->words = bw->bits = 0; +} + +FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc) +{ + const FLAC__byte *buffer; + size_t bytes; + + FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ + + if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) + return false; + + *crc = (FLAC__uint16)FLAC__crc16(buffer, bytes); + FLAC__bitwriter_release_buffer(bw); + return true; +} + +FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc) +{ + const FLAC__byte *buffer; + size_t bytes; + + FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ + + if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) + return false; + + *crc = FLAC__crc8(buffer, bytes); + FLAC__bitwriter_release_buffer(bw); + return true; +} + +FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw) +{ + return ((bw->bits & 7) == 0); +} + +uint32_t FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw) +{ + return FLAC__TOTAL_BITS(bw); +} + +FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes) +{ + FLAC__ASSERT((bw->bits & 7) == 0); + /* double protection */ + if(bw->bits & 7) + return false; + /* if we have bits in the accumulator we have to flush those to the buffer first */ + if(bw->bits) { + FLAC__ASSERT(bw->words <= bw->capacity); + if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD)) + return false; + /* append bits as complete word to buffer, but don't change bw->accum or bw->bits */ + bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits)); + } + /* now we can just return what we have */ + *buffer = (FLAC__byte*)bw->buffer; + *bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3); + return true; +} + +void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw) +{ + /* nothing to do. in the future, strict checking of a 'writer-is-in- + * get-mode' flag could be added everywhere and then cleared here + */ + (void)bw; +} + +inline FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits) +{ + uint32_t n; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + if(bits == 0) + return true; + /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ + if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) + return false; + /* first part gets to word alignment */ + if(bw->bits) { + n = flac_min(FLAC__BITS_PER_WORD - bw->bits, bits); + bw->accum <<= n; + bits -= n; + bw->bits += n; + if(bw->bits == FLAC__BITS_PER_WORD) { + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); + bw->bits = 0; + } + else + return true; + } + /* do whole words */ + while(bits >= FLAC__BITS_PER_WORD) { + bw->buffer[bw->words++] = 0; + bits -= FLAC__BITS_PER_WORD; + } + /* do any leftovers */ + if(bits > 0) { + bw->accum = 0; + bw->bits = bits; + } + return true; +} + +static inline FLAC__bool FLAC__bitwriter_write_raw_uint32_nocheck(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits) +{ + register uint32_t left; + + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); + + if(bw == 0 || bw->buffer == 0) + return false; + + if (bits > 32) + return false; + + if(bits == 0) + return true; + + FLAC__ASSERT((bits == 32) || (val>>bits == 0)); + + /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ + if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) + return false; + + left = FLAC__BITS_PER_WORD - bw->bits; + if(bits < left) { + bw->accum <<= bits; + bw->accum |= val; + bw->bits += bits; + } + else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */ + bw->accum <<= left; + bw->accum |= val >> (bw->bits = bits - left); + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); + bw->accum = val; /* unused top bits can contain garbage */ + } + else { /* at this point bits == FLAC__BITS_PER_WORD == 32 and bw->bits == 0 */ + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST((bwword)val); + } + + return true; +} + +inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits) +{ + /* check that unused bits are unset */ + if((bits < 32) && (val>>bits != 0)) + return false; + + return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, bits); +} + +inline FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits) +{ + /* zero-out unused bits */ + if(bits < 32) + val &= (~(0xffffffff << bits)); + + return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, bits); +} + +inline FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits) +{ + /* this could be a little faster but it's not used for much */ + if(bits > 32) { + return + FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) && + FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, 32); + } + else + return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits); +} + +inline FLAC__bool FLAC__bitwriter_write_raw_int64(FLAC__BitWriter *bw, FLAC__int64 val, uint32_t bits) +{ + FLAC__uint64 uval = val; + /* zero-out unused bits */ + if(bits < 64) + uval &= (~(UINT64_MAX << bits)); + return FLAC__bitwriter_write_raw_uint64(bw, uval, bits); +} + +inline FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val) +{ + /* this doesn't need to be that fast as currently it is only used for vorbis comments */ + + if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, val & 0xff, 8)) + return false; + if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>8) & 0xff, 8)) + return false; + if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>16) & 0xff, 8)) + return false; + if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, val>>24, 8)) + return false; + + return true; +} + +inline FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals) +{ + uint32_t i; + + /* grow capacity upfront to prevent constant reallocation during writes */ + if(bw->capacity <= bw->words + nvals / (FLAC__BITS_PER_WORD / 8) + 1 && !bitwriter_grow_(bw, nvals * 8)) + return false; + + /* this could be faster but currently we don't need it to be since it's only used for writing metadata */ + for(i = 0; i < nvals; i++) { + if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)(vals[i]), 8)) + return false; + } + + return true; +} + +FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val) +{ + if(val < 32) + return FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, ++val); + else + return + FLAC__bitwriter_write_zeroes(bw, val) && + FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, 1); +} + +#if 0 /* UNUSED */ +uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter) +{ + FLAC__uint32 uval; + + FLAC__ASSERT(parameter < 32); + + /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */ + uval = val; + uval <<= 1; + uval ^= (val>>31); + + return 1 + parameter + (uval >> parameter); +} + +uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter) +{ + uint32_t bits, msbs, uval; + uint32_t k; + + FLAC__ASSERT(parameter > 0); + + /* fold signed to uint32_t */ + if(val < 0) + uval = (uint32_t)(((-(++val)) << 1) + 1); + else + uval = (uint32_t)(val << 1); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<> k; + bits = 1 + k + msbs; + } + else { + uint32_t q, r, d; + + d = (1 << (k+1)) - parameter; + q = uval / parameter; + r = uval - (q * parameter); + + bits = 1 + q + k; + if(r >= d) + bits++; + } + return bits; +} + +uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t uval, uint32_t parameter) +{ + uint32_t bits, msbs; + uint32_t k; + + FLAC__ASSERT(parameter > 0); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<> k; + bits = 1 + k + msbs; + } + else { + uint32_t q, r, d; + + d = (1 << (k+1)) - parameter; + q = uval / parameter; + r = uval - (q * parameter); + + bits = 1 + q + k; + if(r >= d) + bits++; + } + return bits; +} + +FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t parameter) +{ + uint32_t total_bits, interesting_bits, msbs; + FLAC__uint32 uval, pattern; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter < 32); + + /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */ + uval = val; + uval <<= 1; + uval ^= (val>>31); + + msbs = uval >> parameter; + interesting_bits = 1 + parameter; + total_bits = interesting_bits + msbs; + pattern = 1 << parameter; /* the unary end bit */ + pattern |= (uval & ((1<accum = wide_accum >> FLAC__HALF_TEMP_BITS; \ + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); \ + wide_accum <<= FLAC__HALF_TEMP_BITS; \ + bitpointer += FLAC__HALF_TEMP_BITS; \ +} + +#else + +#define WIDE_ACCUM_TO_BW { \ + FLAC__ASSERT(bw->bits % FLAC__HALF_TEMP_BITS == 0); \ + if(bw->bits == 0) { \ + bw->accum = wide_accum >> FLAC__HALF_TEMP_BITS; \ + wide_accum <<= FLAC__HALF_TEMP_BITS; \ + bw->bits = FLAC__HALF_TEMP_BITS; \ + } \ + else { \ + bw->accum <<= FLAC__HALF_TEMP_BITS; \ + bw->accum += wide_accum >> FLAC__HALF_TEMP_BITS; \ + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); \ + wide_accum <<= FLAC__HALF_TEMP_BITS; \ + bw->bits = 0; \ + } \ + bitpointer += FLAC__HALF_TEMP_BITS; \ +} + +#endif + +FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, uint32_t nvals, uint32_t parameter) +{ + const FLAC__uint32 mask1 = (FLAC__uint32)0xffffffff << parameter; /* we val|=mask1 to set the stop bit above it... */ + const FLAC__uint32 mask2 = (FLAC__uint32)0xffffffff >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2 */ + FLAC__uint32 uval; + const uint32_t lsbits = 1 + parameter; + uint32_t msbits, total_bits; + FLAC__bwtemp wide_accum = 0; + FLAC__uint32 bitpointer = FLAC__TEMP_BITS; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter < 31); + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); +#if (ENABLE_64_BIT_WORDS == 0) + if(bw->bits > 0) { + bitpointer -= bw->bits; + wide_accum = (FLAC__bwtemp)(bw->accum) << bitpointer; + bw->bits = 0; + } +#else + if(bw->bits > 0 && bw->bits < FLAC__HALF_TEMP_BITS) { + bitpointer -= bw->bits; + wide_accum = bw->accum << bitpointer; + bw->bits = 0; + } + else if(bw->bits > FLAC__HALF_TEMP_BITS) { + bitpointer -= (bw->bits - FLAC__HALF_TEMP_BITS); + wide_accum = bw->accum << bitpointer; + bw->accum >>= (bw->bits - FLAC__HALF_TEMP_BITS); + bw->bits = FLAC__HALF_TEMP_BITS; + } +#endif + + /* Reserve one FLAC__TEMP_BITS per symbol, so checks for space are only necessary when very large symbols are encountered + * this might be considered wasteful, but is only at most 8kB more than necessary for a blocksize of 4096 */ + if(bw->capacity * FLAC__BITS_PER_WORD <= bw->words * FLAC__BITS_PER_WORD + nvals * FLAC__TEMP_BITS + bw->bits && !bitwriter_grow_(bw, nvals * FLAC__TEMP_BITS)) + return false; + + while(nvals) { + /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */ + uval = *vals; + uval <<= 1; + uval ^= (*vals>>31); + + msbits = uval >> parameter; + total_bits = lsbits + msbits; + + uval |= mask1; /* set stop bit */ + uval &= mask2; /* mask off unused top bits */ + + + if(total_bits <= bitpointer) { + /* There is room enough to store the symbol whole at once */ + wide_accum |= (FLAC__bwtemp)(uval) << (bitpointer - total_bits); + bitpointer -= total_bits; + if(bitpointer <= FLAC__HALF_TEMP_BITS) { + /* A word is finished, copy the upper 32 bits of the wide_accum */ + WIDE_ACCUM_TO_BW + } + } + else { + /* The symbol needs to be split. This code isn't used often */ + /* First check for space in the bitwriter */ + if(total_bits > FLAC__TEMP_BITS) { + FLAC__uint32 oversize_in_bits = total_bits - FLAC__TEMP_BITS; + FLAC__uint32 capacity_needed = bw->words * FLAC__BITS_PER_WORD + bw->bits + nvals * FLAC__TEMP_BITS + oversize_in_bits; + if(bw->capacity * FLAC__BITS_PER_WORD <= capacity_needed && !bitwriter_grow_(bw, nvals * FLAC__TEMP_BITS + oversize_in_bits)) + return false; + } + if(msbits > bitpointer) { + /* We have a lot of 0 bits to write, first align with bitwriter word */ + msbits -= bitpointer - FLAC__HALF_TEMP_BITS; + bitpointer = FLAC__HALF_TEMP_BITS; + WIDE_ACCUM_TO_BW + while(msbits > bitpointer) { + /* As the accumulator is already zero, we only need to + * assign zeroes to the bitbuffer */ + WIDE_ACCUM_TO_BW + bitpointer -= FLAC__HALF_TEMP_BITS; + msbits -= FLAC__HALF_TEMP_BITS; + } + /* The remaining bits are zero, and the accumulator already is zero, + * so just subtract the number of bits from bitpointer. When storing, + * we can also just store 0 */ + bitpointer -= msbits; + if(bitpointer <= FLAC__HALF_TEMP_BITS) + WIDE_ACCUM_TO_BW + } + else { + bitpointer -= msbits; + if(bitpointer <= FLAC__HALF_TEMP_BITS) + WIDE_ACCUM_TO_BW + } + /* The lsbs + stop bit always fit 32 bit, so this code mirrors the code above */ + wide_accum |= (FLAC__bwtemp)(uval) << (bitpointer - lsbits); + bitpointer -= lsbits; + if(bitpointer <= FLAC__HALF_TEMP_BITS) { + /* A word is finished, copy the upper 32 bits of the wide_accum */ + WIDE_ACCUM_TO_BW + } + } + vals++; + nvals--; + } + /* Now fixup remainder of wide_accum */ +#if (ENABLE_64_BIT_WORDS == 0) + if(bitpointer < FLAC__TEMP_BITS) { + bw->accum = wide_accum >> bitpointer; + bw->bits = FLAC__TEMP_BITS - bitpointer; + } +#else + if(bitpointer < FLAC__TEMP_BITS) { + if(bw->bits == 0) { + bw->accum = wide_accum >> bitpointer; + bw->bits = FLAC__TEMP_BITS - bitpointer; + } + else if (bw->bits == FLAC__HALF_TEMP_BITS) { + bw->accum <<= FLAC__TEMP_BITS - bitpointer; + bw->accum |= (wide_accum >> bitpointer); + bw->bits = FLAC__HALF_TEMP_BITS + FLAC__TEMP_BITS - bitpointer; + } + else { + FLAC__ASSERT(0); + } + } +#endif + + + return true; +} + +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter) +{ + uint32_t total_bits, msbs, uval; + uint32_t k; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter > 0); + + /* fold signed to uint32_t */ + if(val < 0) + uval = (uint32_t)(((-(++val)) << 1) + 1); + else + uval = (uint32_t)(val << 1); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<> k; + total_bits = 1 + k + msbs; + pattern = 1 << k; /* the unary end bit */ + pattern |= (uval & ((1u<= d) { + if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) + return false; + } + else { + if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) + return false; + } + } + return true; +} + +FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, uint32_t uval, uint32_t parameter) +{ + uint32_t total_bits, msbs; + uint32_t k; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter > 0); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<> k; + total_bits = 1 + k + msbs; + pattern = 1 << k; /* the unary end bit */ + pattern |= (uval & ((1u<= d) { + if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) + return false; + } + else { + if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) + return false; + } + } + return true; +} +#endif /* UNUSED */ + +FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val) +{ + FLAC__bool ok = 1; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + if((val & 0x80000000) != 0) /* this version only handles 31 bits */ + return false; + + if(val < 0x80) { + return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, 8); + } + else if(val < 0x800) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (val>>6), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); + } + else if(val < 0x10000) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (val>>12), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); + } + else if(val < 0x200000) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (val>>18), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); + } + else if(val < 0x4000000) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (val>>24), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); + } + else { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (val>>30), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>24)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); + } + + return ok; +} + +FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val) +{ + FLAC__bool ok = 1; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + if((val & FLAC__U64L(0xFFFFFFF000000000)) != 0) /* this version only handles 36 bits */ + return false; + + if(val < 0x80) { + return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, 8); + } + else if(val < 0x800) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (FLAC__uint32)(val>>6), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x10000) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (FLAC__uint32)(val>>12), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x200000) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (FLAC__uint32)(val>>18), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x4000000) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (FLAC__uint32)(val>>24), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x80000000) { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (FLAC__uint32)(val>>30), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else { + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFE, 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + + return ok; +} + +FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw) +{ + /* 0-pad to byte boundary */ + if(bw->bits & 7u) + return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u)); + else + return true; +} + +/* These functions are declared inline in this file but are also callable as + * externs from elsewhere. + * According to the C99 spec, section 6.7.4, simply providing a function + * prototype in a header file without 'inline' and making the function inline + * in this file should be sufficient. + * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To + * fix that we add extern declarations here. + */ +extern FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits); +extern FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits); +extern FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits); +extern FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits); +extern FLAC__bool FLAC__bitwriter_write_raw_int64(FLAC__BitWriter *bw, FLAC__int64 val, uint32_t bits); +extern FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); +extern FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals); diff --git a/vendor/flac/src/libFLAC/cpu.c b/vendor/flac/src/libFLAC/cpu.c new file mode 100644 index 0000000..d088e3c --- /dev/null +++ b/vendor/flac/src/libFLAC/cpu.c @@ -0,0 +1,255 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" +#include "share/compat.h" +#include +#include + +#if defined _MSC_VER +#include /* for __cpuid() and _xgetbv() */ +#elif defined __GNUC__ && defined HAVE_CPUID_H +#include /* for __get_cpuid() and __get_cpuid_max() */ +#endif + +#ifndef NDEBUG +#include +#define dfprintf fprintf +#else +/* This is bad practice, it should be a static void empty function */ +#define dfprintf(file, format, ...) +#endif + +#if defined(HAVE_SYS_AUXV_H) +#include +#endif + +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM + +/* these are flags in EDX of CPUID AX=00000001 */ +static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV = 0x00008000; +static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX = 0x00800000; +static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE = 0x02000000; +static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2 = 0x04000000; + +/* these are flags in ECX of CPUID AX=00000001 */ +static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3 = 0x00000001; +static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3 = 0x00000200; +static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41 = 0x00080000; +static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42 = 0x00100000; +static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE = 0x08000000; +static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX = 0x10000000; +static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA = 0x00001000; + +/* these are flags in EBX of CPUID AX=00000007 */ +static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2 = 0x00000020; +static const uint32_t FLAC__CPUINFO_X86_CPUID_BMI2 = 0x00000100; + +static uint32_t +cpu_xgetbv_x86(void) +{ +#if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED + return (uint32_t)_xgetbv(0); +#elif defined __GNUC__ + uint32_t lo, hi; + __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0)); + return lo; +#else + return 0; +#endif +} + +static uint32_t +cpu_have_cpuid(void) +{ +#if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0) + /* target CPU does have CPUID instruction */ + return 1; +#elif defined __GNUC__ && defined HAVE_CPUID_H + if (__get_cpuid_max(0, 0) != 0) + return 1; + else + return 0; +#elif defined _MSC_VER + FLAC__uint32 flags1, flags2; + __asm { + pushfd + pushfd + pop eax + mov flags1, eax + xor eax, 0x200000 + push eax + popfd + pushfd + pop eax + mov flags2, eax + popfd + } + if (((flags1^flags2) & 0x200000) != 0) + return 1; + else + return 0; +#else + return 0; +#endif +} + +static void +cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx) +{ +#if defined _MSC_VER + int cpuinfo[4]; + int ext = level & 0x80000000; + __cpuid(cpuinfo, ext); + if ((uint32_t)cpuinfo[0] >= level) { +#if FLAC__AVX_SUPPORTED + __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */ +#else + __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */ +#endif + *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3]; + return; + } +#elif defined __GNUC__ && defined HAVE_CPUID_H + FLAC__uint32 ext = level & 0x80000000; + __cpuid(ext, *eax, *ebx, *ecx, *edx); + if (*eax >= level) { + __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx); + return; + } +#endif + *eax = *ebx = *ecx = *edx = 0; +} + +#endif + +static void +x86_cpu_info (FLAC__CPUInfo *info) +{ +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM + FLAC__bool x86_osxsave = false; + FLAC__bool os_avx = false; + FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx; + + info->use_asm = true; /* we assume a minimum of 80386 */ + if (!cpu_have_cpuid()) + return; + + cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); + info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */ + cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); + + info->x86.cmov = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false; + info->x86.mmx = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX ) ? true : false; + info->x86.sse = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE ) ? true : false; + info->x86.sse2 = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false; + info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false; + info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false; + info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false; + info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false; + + if (FLAC__AVX_SUPPORTED) { + x86_osxsave = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false; + info->x86.avx = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX ) ? true : false; + info->x86.fma = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA ) ? true : false; + cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); + info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2 ) ? true : false; + info->x86.bmi2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_BMI2 ) ? true : false; + } + +#if defined FLAC__CPU_IA32 + dfprintf(stderr, "CPU info (IA-32):\n"); +#else + dfprintf(stderr, "CPU info (x86-64):\n"); +#endif + dfprintf(stderr, " CMOV ....... %c\n", info->x86.cmov ? 'Y' : 'n'); + dfprintf(stderr, " MMX ........ %c\n", info->x86.mmx ? 'Y' : 'n'); + dfprintf(stderr, " SSE ........ %c\n", info->x86.sse ? 'Y' : 'n'); + dfprintf(stderr, " SSE2 ....... %c\n", info->x86.sse2 ? 'Y' : 'n'); + dfprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n'); + dfprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n'); + dfprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n'); + dfprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n'); + + if (FLAC__AVX_SUPPORTED) { + dfprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n'); + dfprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n'); + dfprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n'); + dfprintf(stderr, " BMI2 ....... %c\n", info->x86.bmi2 ? 'Y' : 'n'); + } + + /* + * now have to check for OS support of AVX instructions + */ + if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) { + os_avx = true; + } + if (os_avx) { + dfprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n'); + } + if (!os_avx) { + /* no OS AVX support */ + info->x86.avx = false; + info->x86.avx2 = false; + info->x86.fma = false; + } +#else + info->use_asm = false; +#endif +} + +void FLAC__cpu_info (FLAC__CPUInfo *info) +{ + memset(info, 0, sizeof(*info)); + +#ifdef FLAC__CPU_IA32 + info->type = FLAC__CPUINFO_TYPE_IA32; +#elif defined FLAC__CPU_X86_64 + info->type = FLAC__CPUINFO_TYPE_X86_64; +#else + info->type = FLAC__CPUINFO_TYPE_UNKNOWN; +#endif + + switch (info->type) { + case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */ + case FLAC__CPUINFO_TYPE_X86_64: + x86_cpu_info (info); + break; + default: + info->use_asm = false; + break; + } +} diff --git a/vendor/flac/src/libFLAC/crc.c b/vendor/flac/src/libFLAC/crc.c new file mode 100644 index 0000000..9e488e9 --- /dev/null +++ b/vendor/flac/src/libFLAC/crc.c @@ -0,0 +1,436 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/crc.h" + +/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ + +FLAC__uint8 const FLAC__crc8_table[256] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */ + +FLAC__uint16 const FLAC__crc16_table[8][256] = { + { 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, + 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, + 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, + 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, + 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, + 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 }, + + { 0x0000, 0x8603, 0x8c03, 0x0a00, 0x9803, 0x1e00, 0x1400, 0x9203, + 0xb003, 0x3600, 0x3c00, 0xba03, 0x2800, 0xae03, 0xa403, 0x2200, + 0xe003, 0x6600, 0x6c00, 0xea03, 0x7800, 0xfe03, 0xf403, 0x7200, + 0x5000, 0xd603, 0xdc03, 0x5a00, 0xc803, 0x4e00, 0x4400, 0xc203, + 0x4003, 0xc600, 0xcc00, 0x4a03, 0xd800, 0x5e03, 0x5403, 0xd200, + 0xf000, 0x7603, 0x7c03, 0xfa00, 0x6803, 0xee00, 0xe400, 0x6203, + 0xa000, 0x2603, 0x2c03, 0xaa00, 0x3803, 0xbe00, 0xb400, 0x3203, + 0x1003, 0x9600, 0x9c00, 0x1a03, 0x8800, 0x0e03, 0x0403, 0x8200, + 0x8006, 0x0605, 0x0c05, 0x8a06, 0x1805, 0x9e06, 0x9406, 0x1205, + 0x3005, 0xb606, 0xbc06, 0x3a05, 0xa806, 0x2e05, 0x2405, 0xa206, + 0x6005, 0xe606, 0xec06, 0x6a05, 0xf806, 0x7e05, 0x7405, 0xf206, + 0xd006, 0x5605, 0x5c05, 0xda06, 0x4805, 0xce06, 0xc406, 0x4205, + 0xc005, 0x4606, 0x4c06, 0xca05, 0x5806, 0xde05, 0xd405, 0x5206, + 0x7006, 0xf605, 0xfc05, 0x7a06, 0xe805, 0x6e06, 0x6406, 0xe205, + 0x2006, 0xa605, 0xac05, 0x2a06, 0xb805, 0x3e06, 0x3406, 0xb205, + 0x9005, 0x1606, 0x1c06, 0x9a05, 0x0806, 0x8e05, 0x8405, 0x0206, + 0x8009, 0x060a, 0x0c0a, 0x8a09, 0x180a, 0x9e09, 0x9409, 0x120a, + 0x300a, 0xb609, 0xbc09, 0x3a0a, 0xa809, 0x2e0a, 0x240a, 0xa209, + 0x600a, 0xe609, 0xec09, 0x6a0a, 0xf809, 0x7e0a, 0x740a, 0xf209, + 0xd009, 0x560a, 0x5c0a, 0xda09, 0x480a, 0xce09, 0xc409, 0x420a, + 0xc00a, 0x4609, 0x4c09, 0xca0a, 0x5809, 0xde0a, 0xd40a, 0x5209, + 0x7009, 0xf60a, 0xfc0a, 0x7a09, 0xe80a, 0x6e09, 0x6409, 0xe20a, + 0x2009, 0xa60a, 0xac0a, 0x2a09, 0xb80a, 0x3e09, 0x3409, 0xb20a, + 0x900a, 0x1609, 0x1c09, 0x9a0a, 0x0809, 0x8e0a, 0x840a, 0x0209, + 0x000f, 0x860c, 0x8c0c, 0x0a0f, 0x980c, 0x1e0f, 0x140f, 0x920c, + 0xb00c, 0x360f, 0x3c0f, 0xba0c, 0x280f, 0xae0c, 0xa40c, 0x220f, + 0xe00c, 0x660f, 0x6c0f, 0xea0c, 0x780f, 0xfe0c, 0xf40c, 0x720f, + 0x500f, 0xd60c, 0xdc0c, 0x5a0f, 0xc80c, 0x4e0f, 0x440f, 0xc20c, + 0x400c, 0xc60f, 0xcc0f, 0x4a0c, 0xd80f, 0x5e0c, 0x540c, 0xd20f, + 0xf00f, 0x760c, 0x7c0c, 0xfa0f, 0x680c, 0xee0f, 0xe40f, 0x620c, + 0xa00f, 0x260c, 0x2c0c, 0xaa0f, 0x380c, 0xbe0f, 0xb40f, 0x320c, + 0x100c, 0x960f, 0x9c0f, 0x1a0c, 0x880f, 0x0e0c, 0x040c, 0x820f }, + + { 0x0000, 0x8017, 0x802b, 0x003c, 0x8053, 0x0044, 0x0078, 0x806f, + 0x80a3, 0x00b4, 0x0088, 0x809f, 0x00f0, 0x80e7, 0x80db, 0x00cc, + 0x8143, 0x0154, 0x0168, 0x817f, 0x0110, 0x8107, 0x813b, 0x012c, + 0x01e0, 0x81f7, 0x81cb, 0x01dc, 0x81b3, 0x01a4, 0x0198, 0x818f, + 0x8283, 0x0294, 0x02a8, 0x82bf, 0x02d0, 0x82c7, 0x82fb, 0x02ec, + 0x0220, 0x8237, 0x820b, 0x021c, 0x8273, 0x0264, 0x0258, 0x824f, + 0x03c0, 0x83d7, 0x83eb, 0x03fc, 0x8393, 0x0384, 0x03b8, 0x83af, + 0x8363, 0x0374, 0x0348, 0x835f, 0x0330, 0x8327, 0x831b, 0x030c, + 0x8503, 0x0514, 0x0528, 0x853f, 0x0550, 0x8547, 0x857b, 0x056c, + 0x05a0, 0x85b7, 0x858b, 0x059c, 0x85f3, 0x05e4, 0x05d8, 0x85cf, + 0x0440, 0x8457, 0x846b, 0x047c, 0x8413, 0x0404, 0x0438, 0x842f, + 0x84e3, 0x04f4, 0x04c8, 0x84df, 0x04b0, 0x84a7, 0x849b, 0x048c, + 0x0780, 0x8797, 0x87ab, 0x07bc, 0x87d3, 0x07c4, 0x07f8, 0x87ef, + 0x8723, 0x0734, 0x0708, 0x871f, 0x0770, 0x8767, 0x875b, 0x074c, + 0x86c3, 0x06d4, 0x06e8, 0x86ff, 0x0690, 0x8687, 0x86bb, 0x06ac, + 0x0660, 0x8677, 0x864b, 0x065c, 0x8633, 0x0624, 0x0618, 0x860f, + 0x8a03, 0x0a14, 0x0a28, 0x8a3f, 0x0a50, 0x8a47, 0x8a7b, 0x0a6c, + 0x0aa0, 0x8ab7, 0x8a8b, 0x0a9c, 0x8af3, 0x0ae4, 0x0ad8, 0x8acf, + 0x0b40, 0x8b57, 0x8b6b, 0x0b7c, 0x8b13, 0x0b04, 0x0b38, 0x8b2f, + 0x8be3, 0x0bf4, 0x0bc8, 0x8bdf, 0x0bb0, 0x8ba7, 0x8b9b, 0x0b8c, + 0x0880, 0x8897, 0x88ab, 0x08bc, 0x88d3, 0x08c4, 0x08f8, 0x88ef, + 0x8823, 0x0834, 0x0808, 0x881f, 0x0870, 0x8867, 0x885b, 0x084c, + 0x89c3, 0x09d4, 0x09e8, 0x89ff, 0x0990, 0x8987, 0x89bb, 0x09ac, + 0x0960, 0x8977, 0x894b, 0x095c, 0x8933, 0x0924, 0x0918, 0x890f, + 0x0f00, 0x8f17, 0x8f2b, 0x0f3c, 0x8f53, 0x0f44, 0x0f78, 0x8f6f, + 0x8fa3, 0x0fb4, 0x0f88, 0x8f9f, 0x0ff0, 0x8fe7, 0x8fdb, 0x0fcc, + 0x8e43, 0x0e54, 0x0e68, 0x8e7f, 0x0e10, 0x8e07, 0x8e3b, 0x0e2c, + 0x0ee0, 0x8ef7, 0x8ecb, 0x0edc, 0x8eb3, 0x0ea4, 0x0e98, 0x8e8f, + 0x8d83, 0x0d94, 0x0da8, 0x8dbf, 0x0dd0, 0x8dc7, 0x8dfb, 0x0dec, + 0x0d20, 0x8d37, 0x8d0b, 0x0d1c, 0x8d73, 0x0d64, 0x0d58, 0x8d4f, + 0x0cc0, 0x8cd7, 0x8ceb, 0x0cfc, 0x8c93, 0x0c84, 0x0cb8, 0x8caf, + 0x8c63, 0x0c74, 0x0c48, 0x8c5f, 0x0c30, 0x8c27, 0x8c1b, 0x0c0c }, + + { 0x0000, 0x9403, 0xa803, 0x3c00, 0xd003, 0x4400, 0x7800, 0xec03, + 0x2003, 0xb400, 0x8800, 0x1c03, 0xf000, 0x6403, 0x5803, 0xcc00, + 0x4006, 0xd405, 0xe805, 0x7c06, 0x9005, 0x0406, 0x3806, 0xac05, + 0x6005, 0xf406, 0xc806, 0x5c05, 0xb006, 0x2405, 0x1805, 0x8c06, + 0x800c, 0x140f, 0x280f, 0xbc0c, 0x500f, 0xc40c, 0xf80c, 0x6c0f, + 0xa00f, 0x340c, 0x080c, 0x9c0f, 0x700c, 0xe40f, 0xd80f, 0x4c0c, + 0xc00a, 0x5409, 0x6809, 0xfc0a, 0x1009, 0x840a, 0xb80a, 0x2c09, + 0xe009, 0x740a, 0x480a, 0xdc09, 0x300a, 0xa409, 0x9809, 0x0c0a, + 0x801d, 0x141e, 0x281e, 0xbc1d, 0x501e, 0xc41d, 0xf81d, 0x6c1e, + 0xa01e, 0x341d, 0x081d, 0x9c1e, 0x701d, 0xe41e, 0xd81e, 0x4c1d, + 0xc01b, 0x5418, 0x6818, 0xfc1b, 0x1018, 0x841b, 0xb81b, 0x2c18, + 0xe018, 0x741b, 0x481b, 0xdc18, 0x301b, 0xa418, 0x9818, 0x0c1b, + 0x0011, 0x9412, 0xa812, 0x3c11, 0xd012, 0x4411, 0x7811, 0xec12, + 0x2012, 0xb411, 0x8811, 0x1c12, 0xf011, 0x6412, 0x5812, 0xcc11, + 0x4017, 0xd414, 0xe814, 0x7c17, 0x9014, 0x0417, 0x3817, 0xac14, + 0x6014, 0xf417, 0xc817, 0x5c14, 0xb017, 0x2414, 0x1814, 0x8c17, + 0x803f, 0x143c, 0x283c, 0xbc3f, 0x503c, 0xc43f, 0xf83f, 0x6c3c, + 0xa03c, 0x343f, 0x083f, 0x9c3c, 0x703f, 0xe43c, 0xd83c, 0x4c3f, + 0xc039, 0x543a, 0x683a, 0xfc39, 0x103a, 0x8439, 0xb839, 0x2c3a, + 0xe03a, 0x7439, 0x4839, 0xdc3a, 0x3039, 0xa43a, 0x983a, 0x0c39, + 0x0033, 0x9430, 0xa830, 0x3c33, 0xd030, 0x4433, 0x7833, 0xec30, + 0x2030, 0xb433, 0x8833, 0x1c30, 0xf033, 0x6430, 0x5830, 0xcc33, + 0x4035, 0xd436, 0xe836, 0x7c35, 0x9036, 0x0435, 0x3835, 0xac36, + 0x6036, 0xf435, 0xc835, 0x5c36, 0xb035, 0x2436, 0x1836, 0x8c35, + 0x0022, 0x9421, 0xa821, 0x3c22, 0xd021, 0x4422, 0x7822, 0xec21, + 0x2021, 0xb422, 0x8822, 0x1c21, 0xf022, 0x6421, 0x5821, 0xcc22, + 0x4024, 0xd427, 0xe827, 0x7c24, 0x9027, 0x0424, 0x3824, 0xac27, + 0x6027, 0xf424, 0xc824, 0x5c27, 0xb024, 0x2427, 0x1827, 0x8c24, + 0x802e, 0x142d, 0x282d, 0xbc2e, 0x502d, 0xc42e, 0xf82e, 0x6c2d, + 0xa02d, 0x342e, 0x082e, 0x9c2d, 0x702e, 0xe42d, 0xd82d, 0x4c2e, + 0xc028, 0x542b, 0x682b, 0xfc28, 0x102b, 0x8428, 0xb828, 0x2c2b, + 0xe02b, 0x7428, 0x4828, 0xdc2b, 0x3028, 0xa42b, 0x982b, 0x0c28 }, + + { 0x0000, 0x807b, 0x80f3, 0x0088, 0x81e3, 0x0198, 0x0110, 0x816b, + 0x83c3, 0x03b8, 0x0330, 0x834b, 0x0220, 0x825b, 0x82d3, 0x02a8, + 0x8783, 0x07f8, 0x0770, 0x870b, 0x0660, 0x861b, 0x8693, 0x06e8, + 0x0440, 0x843b, 0x84b3, 0x04c8, 0x85a3, 0x05d8, 0x0550, 0x852b, + 0x8f03, 0x0f78, 0x0ff0, 0x8f8b, 0x0ee0, 0x8e9b, 0x8e13, 0x0e68, + 0x0cc0, 0x8cbb, 0x8c33, 0x0c48, 0x8d23, 0x0d58, 0x0dd0, 0x8dab, + 0x0880, 0x88fb, 0x8873, 0x0808, 0x8963, 0x0918, 0x0990, 0x89eb, + 0x8b43, 0x0b38, 0x0bb0, 0x8bcb, 0x0aa0, 0x8adb, 0x8a53, 0x0a28, + 0x9e03, 0x1e78, 0x1ef0, 0x9e8b, 0x1fe0, 0x9f9b, 0x9f13, 0x1f68, + 0x1dc0, 0x9dbb, 0x9d33, 0x1d48, 0x9c23, 0x1c58, 0x1cd0, 0x9cab, + 0x1980, 0x99fb, 0x9973, 0x1908, 0x9863, 0x1818, 0x1890, 0x98eb, + 0x9a43, 0x1a38, 0x1ab0, 0x9acb, 0x1ba0, 0x9bdb, 0x9b53, 0x1b28, + 0x1100, 0x917b, 0x91f3, 0x1188, 0x90e3, 0x1098, 0x1010, 0x906b, + 0x92c3, 0x12b8, 0x1230, 0x924b, 0x1320, 0x935b, 0x93d3, 0x13a8, + 0x9683, 0x16f8, 0x1670, 0x960b, 0x1760, 0x971b, 0x9793, 0x17e8, + 0x1540, 0x953b, 0x95b3, 0x15c8, 0x94a3, 0x14d8, 0x1450, 0x942b, + 0xbc03, 0x3c78, 0x3cf0, 0xbc8b, 0x3de0, 0xbd9b, 0xbd13, 0x3d68, + 0x3fc0, 0xbfbb, 0xbf33, 0x3f48, 0xbe23, 0x3e58, 0x3ed0, 0xbeab, + 0x3b80, 0xbbfb, 0xbb73, 0x3b08, 0xba63, 0x3a18, 0x3a90, 0xbaeb, + 0xb843, 0x3838, 0x38b0, 0xb8cb, 0x39a0, 0xb9db, 0xb953, 0x3928, + 0x3300, 0xb37b, 0xb3f3, 0x3388, 0xb2e3, 0x3298, 0x3210, 0xb26b, + 0xb0c3, 0x30b8, 0x3030, 0xb04b, 0x3120, 0xb15b, 0xb1d3, 0x31a8, + 0xb483, 0x34f8, 0x3470, 0xb40b, 0x3560, 0xb51b, 0xb593, 0x35e8, + 0x3740, 0xb73b, 0xb7b3, 0x37c8, 0xb6a3, 0x36d8, 0x3650, 0xb62b, + 0x2200, 0xa27b, 0xa2f3, 0x2288, 0xa3e3, 0x2398, 0x2310, 0xa36b, + 0xa1c3, 0x21b8, 0x2130, 0xa14b, 0x2020, 0xa05b, 0xa0d3, 0x20a8, + 0xa583, 0x25f8, 0x2570, 0xa50b, 0x2460, 0xa41b, 0xa493, 0x24e8, + 0x2640, 0xa63b, 0xa6b3, 0x26c8, 0xa7a3, 0x27d8, 0x2750, 0xa72b, + 0xad03, 0x2d78, 0x2df0, 0xad8b, 0x2ce0, 0xac9b, 0xac13, 0x2c68, + 0x2ec0, 0xaebb, 0xae33, 0x2e48, 0xaf23, 0x2f58, 0x2fd0, 0xafab, + 0x2a80, 0xaafb, 0xaa73, 0x2a08, 0xab63, 0x2b18, 0x2b90, 0xabeb, + 0xa943, 0x2938, 0x29b0, 0xa9cb, 0x28a0, 0xa8db, 0xa853, 0x2828 }, + + { 0x0000, 0xf803, 0x7003, 0x8800, 0xe006, 0x1805, 0x9005, 0x6806, + 0x4009, 0xb80a, 0x300a, 0xc809, 0xa00f, 0x580c, 0xd00c, 0x280f, + 0x8012, 0x7811, 0xf011, 0x0812, 0x6014, 0x9817, 0x1017, 0xe814, + 0xc01b, 0x3818, 0xb018, 0x481b, 0x201d, 0xd81e, 0x501e, 0xa81d, + 0x8021, 0x7822, 0xf022, 0x0821, 0x6027, 0x9824, 0x1024, 0xe827, + 0xc028, 0x382b, 0xb02b, 0x4828, 0x202e, 0xd82d, 0x502d, 0xa82e, + 0x0033, 0xf830, 0x7030, 0x8833, 0xe035, 0x1836, 0x9036, 0x6835, + 0x403a, 0xb839, 0x3039, 0xc83a, 0xa03c, 0x583f, 0xd03f, 0x283c, + 0x8047, 0x7844, 0xf044, 0x0847, 0x6041, 0x9842, 0x1042, 0xe841, + 0xc04e, 0x384d, 0xb04d, 0x484e, 0x2048, 0xd84b, 0x504b, 0xa848, + 0x0055, 0xf856, 0x7056, 0x8855, 0xe053, 0x1850, 0x9050, 0x6853, + 0x405c, 0xb85f, 0x305f, 0xc85c, 0xa05a, 0x5859, 0xd059, 0x285a, + 0x0066, 0xf865, 0x7065, 0x8866, 0xe060, 0x1863, 0x9063, 0x6860, + 0x406f, 0xb86c, 0x306c, 0xc86f, 0xa069, 0x586a, 0xd06a, 0x2869, + 0x8074, 0x7877, 0xf077, 0x0874, 0x6072, 0x9871, 0x1071, 0xe872, + 0xc07d, 0x387e, 0xb07e, 0x487d, 0x207b, 0xd878, 0x5078, 0xa87b, + 0x808b, 0x7888, 0xf088, 0x088b, 0x608d, 0x988e, 0x108e, 0xe88d, + 0xc082, 0x3881, 0xb081, 0x4882, 0x2084, 0xd887, 0x5087, 0xa884, + 0x0099, 0xf89a, 0x709a, 0x8899, 0xe09f, 0x189c, 0x909c, 0x689f, + 0x4090, 0xb893, 0x3093, 0xc890, 0xa096, 0x5895, 0xd095, 0x2896, + 0x00aa, 0xf8a9, 0x70a9, 0x88aa, 0xe0ac, 0x18af, 0x90af, 0x68ac, + 0x40a3, 0xb8a0, 0x30a0, 0xc8a3, 0xa0a5, 0x58a6, 0xd0a6, 0x28a5, + 0x80b8, 0x78bb, 0xf0bb, 0x08b8, 0x60be, 0x98bd, 0x10bd, 0xe8be, + 0xc0b1, 0x38b2, 0xb0b2, 0x48b1, 0x20b7, 0xd8b4, 0x50b4, 0xa8b7, + 0x00cc, 0xf8cf, 0x70cf, 0x88cc, 0xe0ca, 0x18c9, 0x90c9, 0x68ca, + 0x40c5, 0xb8c6, 0x30c6, 0xc8c5, 0xa0c3, 0x58c0, 0xd0c0, 0x28c3, + 0x80de, 0x78dd, 0xf0dd, 0x08de, 0x60d8, 0x98db, 0x10db, 0xe8d8, + 0xc0d7, 0x38d4, 0xb0d4, 0x48d7, 0x20d1, 0xd8d2, 0x50d2, 0xa8d1, + 0x80ed, 0x78ee, 0xf0ee, 0x08ed, 0x60eb, 0x98e8, 0x10e8, 0xe8eb, + 0xc0e4, 0x38e7, 0xb0e7, 0x48e4, 0x20e2, 0xd8e1, 0x50e1, 0xa8e2, + 0x00ff, 0xf8fc, 0x70fc, 0x88ff, 0xe0f9, 0x18fa, 0x90fa, 0x68f9, + 0x40f6, 0xb8f5, 0x30f5, 0xc8f6, 0xa0f0, 0x58f3, 0xd0f3, 0x28f0 }, + + { 0x0000, 0x8113, 0x8223, 0x0330, 0x8443, 0x0550, 0x0660, 0x8773, + 0x8883, 0x0990, 0x0aa0, 0x8bb3, 0x0cc0, 0x8dd3, 0x8ee3, 0x0ff0, + 0x9103, 0x1010, 0x1320, 0x9233, 0x1540, 0x9453, 0x9763, 0x1670, + 0x1980, 0x9893, 0x9ba3, 0x1ab0, 0x9dc3, 0x1cd0, 0x1fe0, 0x9ef3, + 0xa203, 0x2310, 0x2020, 0xa133, 0x2640, 0xa753, 0xa463, 0x2570, + 0x2a80, 0xab93, 0xa8a3, 0x29b0, 0xaec3, 0x2fd0, 0x2ce0, 0xadf3, + 0x3300, 0xb213, 0xb123, 0x3030, 0xb743, 0x3650, 0x3560, 0xb473, + 0xbb83, 0x3a90, 0x39a0, 0xb8b3, 0x3fc0, 0xbed3, 0xbde3, 0x3cf0, + 0xc403, 0x4510, 0x4620, 0xc733, 0x4040, 0xc153, 0xc263, 0x4370, + 0x4c80, 0xcd93, 0xcea3, 0x4fb0, 0xc8c3, 0x49d0, 0x4ae0, 0xcbf3, + 0x5500, 0xd413, 0xd723, 0x5630, 0xd143, 0x5050, 0x5360, 0xd273, + 0xdd83, 0x5c90, 0x5fa0, 0xdeb3, 0x59c0, 0xd8d3, 0xdbe3, 0x5af0, + 0x6600, 0xe713, 0xe423, 0x6530, 0xe243, 0x6350, 0x6060, 0xe173, + 0xee83, 0x6f90, 0x6ca0, 0xedb3, 0x6ac0, 0xebd3, 0xe8e3, 0x69f0, + 0xf703, 0x7610, 0x7520, 0xf433, 0x7340, 0xf253, 0xf163, 0x7070, + 0x7f80, 0xfe93, 0xfda3, 0x7cb0, 0xfbc3, 0x7ad0, 0x79e0, 0xf8f3, + 0x0803, 0x8910, 0x8a20, 0x0b33, 0x8c40, 0x0d53, 0x0e63, 0x8f70, + 0x8080, 0x0193, 0x02a3, 0x83b0, 0x04c3, 0x85d0, 0x86e0, 0x07f3, + 0x9900, 0x1813, 0x1b23, 0x9a30, 0x1d43, 0x9c50, 0x9f60, 0x1e73, + 0x1183, 0x9090, 0x93a0, 0x12b3, 0x95c0, 0x14d3, 0x17e3, 0x96f0, + 0xaa00, 0x2b13, 0x2823, 0xa930, 0x2e43, 0xaf50, 0xac60, 0x2d73, + 0x2283, 0xa390, 0xa0a0, 0x21b3, 0xa6c0, 0x27d3, 0x24e3, 0xa5f0, + 0x3b03, 0xba10, 0xb920, 0x3833, 0xbf40, 0x3e53, 0x3d63, 0xbc70, + 0xb380, 0x3293, 0x31a3, 0xb0b0, 0x37c3, 0xb6d0, 0xb5e0, 0x34f3, + 0xcc00, 0x4d13, 0x4e23, 0xcf30, 0x4843, 0xc950, 0xca60, 0x4b73, + 0x4483, 0xc590, 0xc6a0, 0x47b3, 0xc0c0, 0x41d3, 0x42e3, 0xc3f0, + 0x5d03, 0xdc10, 0xdf20, 0x5e33, 0xd940, 0x5853, 0x5b63, 0xda70, + 0xd580, 0x5493, 0x57a3, 0xd6b0, 0x51c3, 0xd0d0, 0xd3e0, 0x52f3, + 0x6e03, 0xef10, 0xec20, 0x6d33, 0xea40, 0x6b53, 0x6863, 0xe970, + 0xe680, 0x6793, 0x64a3, 0xe5b0, 0x62c3, 0xe3d0, 0xe0e0, 0x61f3, + 0xff00, 0x7e13, 0x7d23, 0xfc30, 0x7b43, 0xfa50, 0xf960, 0x7873, + 0x7783, 0xf690, 0xf5a0, 0x74b3, 0xf3c0, 0x72d3, 0x71e3, 0xf0f0 }, + + { 0x0000, 0x1006, 0x200c, 0x300a, 0x4018, 0x501e, 0x6014, 0x7012, + 0x8030, 0x9036, 0xa03c, 0xb03a, 0xc028, 0xd02e, 0xe024, 0xf022, + 0x8065, 0x9063, 0xa069, 0xb06f, 0xc07d, 0xd07b, 0xe071, 0xf077, + 0x0055, 0x1053, 0x2059, 0x305f, 0x404d, 0x504b, 0x6041, 0x7047, + 0x80cf, 0x90c9, 0xa0c3, 0xb0c5, 0xc0d7, 0xd0d1, 0xe0db, 0xf0dd, + 0x00ff, 0x10f9, 0x20f3, 0x30f5, 0x40e7, 0x50e1, 0x60eb, 0x70ed, + 0x00aa, 0x10ac, 0x20a6, 0x30a0, 0x40b2, 0x50b4, 0x60be, 0x70b8, + 0x809a, 0x909c, 0xa096, 0xb090, 0xc082, 0xd084, 0xe08e, 0xf088, + 0x819b, 0x919d, 0xa197, 0xb191, 0xc183, 0xd185, 0xe18f, 0xf189, + 0x01ab, 0x11ad, 0x21a7, 0x31a1, 0x41b3, 0x51b5, 0x61bf, 0x71b9, + 0x01fe, 0x11f8, 0x21f2, 0x31f4, 0x41e6, 0x51e0, 0x61ea, 0x71ec, + 0x81ce, 0x91c8, 0xa1c2, 0xb1c4, 0xc1d6, 0xd1d0, 0xe1da, 0xf1dc, + 0x0154, 0x1152, 0x2158, 0x315e, 0x414c, 0x514a, 0x6140, 0x7146, + 0x8164, 0x9162, 0xa168, 0xb16e, 0xc17c, 0xd17a, 0xe170, 0xf176, + 0x8131, 0x9137, 0xa13d, 0xb13b, 0xc129, 0xd12f, 0xe125, 0xf123, + 0x0101, 0x1107, 0x210d, 0x310b, 0x4119, 0x511f, 0x6115, 0x7113, + 0x8333, 0x9335, 0xa33f, 0xb339, 0xc32b, 0xd32d, 0xe327, 0xf321, + 0x0303, 0x1305, 0x230f, 0x3309, 0x431b, 0x531d, 0x6317, 0x7311, + 0x0356, 0x1350, 0x235a, 0x335c, 0x434e, 0x5348, 0x6342, 0x7344, + 0x8366, 0x9360, 0xa36a, 0xb36c, 0xc37e, 0xd378, 0xe372, 0xf374, + 0x03fc, 0x13fa, 0x23f0, 0x33f6, 0x43e4, 0x53e2, 0x63e8, 0x73ee, + 0x83cc, 0x93ca, 0xa3c0, 0xb3c6, 0xc3d4, 0xd3d2, 0xe3d8, 0xf3de, + 0x8399, 0x939f, 0xa395, 0xb393, 0xc381, 0xd387, 0xe38d, 0xf38b, + 0x03a9, 0x13af, 0x23a5, 0x33a3, 0x43b1, 0x53b7, 0x63bd, 0x73bb, + 0x02a8, 0x12ae, 0x22a4, 0x32a2, 0x42b0, 0x52b6, 0x62bc, 0x72ba, + 0x8298, 0x929e, 0xa294, 0xb292, 0xc280, 0xd286, 0xe28c, 0xf28a, + 0x82cd, 0x92cb, 0xa2c1, 0xb2c7, 0xc2d5, 0xd2d3, 0xe2d9, 0xf2df, + 0x02fd, 0x12fb, 0x22f1, 0x32f7, 0x42e5, 0x52e3, 0x62e9, 0x72ef, + 0x8267, 0x9261, 0xa26b, 0xb26d, 0xc27f, 0xd279, 0xe273, 0xf275, + 0x0257, 0x1251, 0x225b, 0x325d, 0x424f, 0x5249, 0x6243, 0x7245, + 0x0202, 0x1204, 0x220e, 0x3208, 0x421a, 0x521c, 0x6216, 0x7210, + 0x8232, 0x9234, 0xa23e, 0xb238, 0xc22a, 0xd22c, 0xe226, 0xf220 } +}; + +#if 0 +void FLAC__crc16_init_table(void) +{ + int i, j; + FLAC__uint16 polynomial, crc; + polynomial = 0x8005; + + for(i = 0; i <= 0xFF; i++){ + crc = i << 8; + + for(j = 0; j < 8; j++) + crc = (crc << 1) ^ (crc & (1 << 15) ? polynomial : 0); + + FLAC__crc16_table[0][i] = crc; + } + + for(i = 0; i <= 0xFF; i++) + for(j = 1; j < 8; j++) + FLAC__crc16_table[j][i] = FLAC__crc16_table[0][FLAC__crc16_table[j - 1][i] >> 8] ^ (FLAC__crc16_table[j - 1][i] << 8); +} +#endif + +FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len) +{ + FLAC__uint8 crc = 0; + + while(len--) + crc = FLAC__crc8_table[crc ^ *data++]; + + return crc; +} + +FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len) +{ + FLAC__uint16 crc = 0; + + while(len >= 8){ + crc ^= data[0] << 8 | data[1]; + + crc = FLAC__crc16_table[7][crc >> 8] ^ FLAC__crc16_table[6][crc & 0xFF] ^ + FLAC__crc16_table[5][data[2] ] ^ FLAC__crc16_table[4][data[3] ] ^ + FLAC__crc16_table[3][data[4] ] ^ FLAC__crc16_table[2][data[5] ] ^ + FLAC__crc16_table[1][data[6] ] ^ FLAC__crc16_table[0][data[7] ]; + + data += 8; + len -= 8; + } + + while(len--) + crc = (crc<<8) ^ FLAC__crc16_table[0][(crc>>8) ^ *data++]; + + return crc; +} + +FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc) +{ + while (len >= 2) { + crc ^= words[0] >> 16; + + crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^ + FLAC__crc16_table[5][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[4][ words[0] & 0xFF] ^ + FLAC__crc16_table[3][ words[1] >> 24 ] ^ FLAC__crc16_table[2][(words[1] >> 16) & 0xFF] ^ + FLAC__crc16_table[1][(words[1] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[1] & 0xFF]; + + words += 2; + len -= 2; + } + + if (len) { + crc ^= words[0] >> 16; + + crc = FLAC__crc16_table[3][crc >> 8 ] ^ FLAC__crc16_table[2][crc & 0xFF ] ^ + FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][words[0] & 0xFF]; + } + + return crc; +} + +FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc) +{ + while (len--) { + crc ^= words[0] >> 48; + + crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^ + FLAC__crc16_table[5][(words[0] >> 40) & 0xFF] ^ FLAC__crc16_table[4][(words[0] >> 32) & 0xFF] ^ + FLAC__crc16_table[3][(words[0] >> 24) & 0xFF] ^ FLAC__crc16_table[2][(words[0] >> 16) & 0xFF] ^ + FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[0] & 0xFF]; + + words++; + } + + return crc; +} diff --git a/vendor/flac/src/libFLAC/deduplication/bitreader_read_rice_signed_block.c b/vendor/flac/src/libFLAC/deduplication/bitreader_read_rice_signed_block.c new file mode 100644 index 0000000..75ed47f --- /dev/null +++ b/vendor/flac/src/libFLAC/deduplication/bitreader_read_rice_signed_block.c @@ -0,0 +1,143 @@ +{ + /* try and get br->consumed_words and br->consumed_bits into register; + * must remember to flush them back to *br before calling other + * bitreader functions that use them, and before returning */ + uint32_t cwords, words, lsbs, msbs, x, y, limit; + uint32_t ucbits; /* keep track of the number of unconsumed bits in word */ + brword b; + int *val, *end; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); + FLAC__ASSERT(parameter < 32); + /* the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it */ + + limit = UINT32_MAX >> parameter; /* Maximal msbs that can occur with residual bounded to int32_t */ + + val = vals; + end = vals + nvals; + + if(parameter == 0) { + while(val < end) { + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + /* Checking limit here would be overzealous: coding UINT32_MAX + * with parameter == 0 would take 4GiB */ + *val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1); + } + + return true; + } + + FLAC__ASSERT(parameter > 0); + + cwords = br->consumed_words; + words = br->words; + + /* if we've not consumed up to a partial tail word... */ + if(cwords >= words) { + x = 0; + goto process_tail; + } + + ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; + b = br->buffer[cwords] << br->consumed_bits; /* keep unconsumed bits aligned to left */ + + while(val < end) { + /* read the unary MSBs and end bit */ + x = y = COUNT_ZERO_MSBS2(b); + if(x == FLAC__BITS_PER_WORD) { + x = ucbits; + do { + /* didn't find stop bit yet, have to keep going... */ + cwords++; + if (cwords >= words) + goto incomplete_msbs; + b = br->buffer[cwords]; + y = COUNT_ZERO_MSBS2(b); + x += y; + } while(y == FLAC__BITS_PER_WORD); + } + b <<= y; + b <<= 1; /* account for stop bit */ + ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD; + msbs = x; + + if(x > limit) + return false; + + /* read the binary LSBs */ + x = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit uint32_t */ + if(parameter <= ucbits) { + ucbits -= parameter; + b <<= parameter; + } else { + /* there are still bits left to read, they will all be in the next word */ + cwords++; + if (cwords >= words) + goto incomplete_lsbs; + b = br->buffer[cwords]; + ucbits += FLAC__BITS_PER_WORD - parameter; + x |= (FLAC__uint32)(b >> ucbits); + b <<= FLAC__BITS_PER_WORD - ucbits; + } + lsbs = x; + + /* compose the value */ + x = (msbs << parameter) | lsbs; + *val++ = (int)(x >> 1) ^ -(int)(x & 1); + + continue; + + /* at this point we've eaten up all the whole words */ +process_tail: + do { + if(0) { +incomplete_msbs: + br->consumed_bits = 0; + br->consumed_words = cwords; + } + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + msbs += x; + x = ucbits = 0; + + if(0) { +incomplete_lsbs: + br->consumed_bits = 0; + br->consumed_words = cwords; + } + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits)) + return false; + lsbs = x | lsbs; + + /* compose the value */ + x = (msbs << parameter) | lsbs; + *val++ = (int)(x >> 1) ^ -(int)(x & 1); + x = 0; + + cwords = br->consumed_words; + words = br->words; + ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; + b = cwords < br->capacity ? br->buffer[cwords] << br->consumed_bits : 0; + } while(cwords >= words && val < end); + } + + if(ucbits == 0 && cwords < words) { + /* don't leave the head word with no unconsumed bits */ + cwords++; + ucbits = FLAC__BITS_PER_WORD; + } + + br->consumed_bits = FLAC__BITS_PER_WORD - ucbits; + br->consumed_words = cwords; + + return true; +} diff --git a/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c b/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c new file mode 100644 index 0000000..76419db --- /dev/null +++ b/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c @@ -0,0 +1,14 @@ + int i, j; + (void) lag; + FLAC__ASSERT(lag <= MAX_LAG); + + for(i = 0; i < MAX_LAG; i++) + autoc[i] = 0.0; + + for(i = 0; i < MAX_LAG; i++) + for(j = 0; j <= i; j++) + autoc[j] += (double)data[i] * (double)data[i-j]; + + for(i = MAX_LAG; i < (int)data_len; i++) + for(j = 0; j < MAX_LAG; j++) + autoc[j] += (double)data[i] * (double)data[i-j]; diff --git a/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c b/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c new file mode 100644 index 0000000..4df3aee --- /dev/null +++ b/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c @@ -0,0 +1,70 @@ + int i; + float64x2_t sum0 = vdupq_n_f64(0.0f); + float64x2_t sum1 = vdupq_n_f64(0.0f); + float64x2_t sum2 = vdupq_n_f64(0.0f); + float64x2_t sum3 = vdupq_n_f64(0.0f); + float64x2_t d0 = vdupq_n_f64(0.0f); + float64x2_t d1 = vdupq_n_f64(0.0f); + float64x2_t d2 = vdupq_n_f64(0.0f); + float64x2_t d3 = vdupq_n_f64(0.0f); +#if MAX_LAG > 8 + float64x2_t sum4 = vdupq_n_f64(0.0f); + float64x2_t d4 = vdupq_n_f64(0.0f); +#endif +#if MAX_LAG > 10 + float64x2_t sum5 = vdupq_n_f64(0.0f); + float64x2_t sum6 = vdupq_n_f64(0.0f); + float64x2_t d5 = vdupq_n_f64(0.0f); + float64x2_t d6 = vdupq_n_f64(0.0f); +#endif + float64x2_t d; + + (void)lag; + FLAC__ASSERT(lag <= MAX_LAG); + + // Loop backwards through samples from data_len to 0 + for (i = data_len - 1; i >= 0; i--) + { + d = vdupq_n_f64(data[i]); // Create vector with 2 entries data[i] + + // The next 6 lines of code right-shift the elements through the 7 vectors d0..d6. + // The 7th line adds the newly loaded element to d0. This works like a stack, where + // data[i] is pushed onto the stack every time and the 9th element falls off +#if MAX_LAG > 10 + d6 = vextq_f64(d5,d6,1); + d5 = vextq_f64(d4,d5,1); +#endif +#if MAX_LAG > 8 + d4 = vextq_f64(d3,d4,1); +#endif + d3 = vextq_f64(d2,d3,1); + d2 = vextq_f64(d1,d2,1); + d1 = vextq_f64(d0,d1,1); + d0 = vextq_f64(d,d0,1); + + // Fused multiply-add sum += d * d0..d6 + sum0 = vfmaq_f64(sum0, d, d0); + sum1 = vfmaq_f64(sum1, d, d1); + sum2 = vfmaq_f64(sum2, d, d2); + sum3 = vfmaq_f64(sum3, d, d3); +#if MAX_LAG > 8 + sum4 = vfmaq_f64(sum4, d, d4); +#endif +#if MAX_LAG > 10 + sum5 = vfmaq_f64(sum5, d, d5); + sum6 = vfmaq_f64(sum6, d, d6); +#endif + } + + // Store sum0..sum6 in autoc[0..14] + vst1q_f64(autoc, sum0); + vst1q_f64(autoc + 2, sum1); + vst1q_f64(autoc + 4, sum2); + vst1q_f64(autoc + 6, sum3); +#if MAX_LAG > 8 + vst1q_f64(autoc + 8, sum4); +#endif +#if MAX_LAG > 10 + vst1q_f64(autoc + 10, sum5); + vst1q_f64(autoc + 12, sum6); +#endif diff --git a/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c b/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c new file mode 100644 index 0000000..607b42f --- /dev/null +++ b/vendor/flac/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c @@ -0,0 +1,81 @@ +/* This code is imported several times in lpc_intrin_sse2.c with different + * values for MAX_LAG. Comments are for MAX_LAG == 14 */ + int i; + __m128d sum0, sum1, sum2, sum3; + __m128d d0, d1, d2, d3; +#if MAX_LAG > 8 + __m128d d4; + __m128d sum4; +#endif +#if MAX_LAG > 10 + __m128d d5, d6; + __m128d sum5, sum6; +#endif + + (void) lag; + FLAC__ASSERT(lag <= MAX_LAG); + + /* Initialize all sum vectors with zero */ + sum0 = _mm_setzero_pd(); + sum1 = _mm_setzero_pd(); + sum2 = _mm_setzero_pd(); + sum3 = _mm_setzero_pd(); + d0 = _mm_setzero_pd(); + d1 = _mm_setzero_pd(); + d2 = _mm_setzero_pd(); + d3 = _mm_setzero_pd(); +#if MAX_LAG > 8 + sum4 = _mm_setzero_pd(); + d4 = _mm_setzero_pd(); +#endif +#if MAX_LAG > 10 + sum5 = _mm_setzero_pd(); + sum6 = _mm_setzero_pd(); + d5 = _mm_setzero_pd(); + d6 = _mm_setzero_pd(); +#endif + + /* Loop backwards through samples from data_len to limit */ + for(i = data_len-1; i >= 0; i--) { + __m128d d = _mm_set1_pd(data[i]); + + /* The next lines of code work like a queue. For more + * information see the lag8 version of this function */ +#if MAX_LAG > 10 + d6 = _mm_shuffle_pd(d5, d6, _MM_SHUFFLE(0,0,0,1)); + d5 = _mm_shuffle_pd(d4, d5, _MM_SHUFFLE(0,0,0,1)); +#endif +#if MAX_LAG > 8 + d4 = _mm_shuffle_pd(d3, d4, _MM_SHUFFLE(0,0,0,1)); +#endif + d3 = _mm_shuffle_pd(d2, d3, _MM_SHUFFLE(0,0,0,1)); + d2 = _mm_shuffle_pd(d1, d2, _MM_SHUFFLE(0,0,0,1)); + d1 = _mm_shuffle_pd(d0, d1, _MM_SHUFFLE(0,0,0,1)); + d0 = _mm_shuffle_pd(d, d0, _MM_SHUFFLE(0,0,0,1)); + + /* sumn += d*dn */ + sum0 = _mm_add_pd(sum0, _mm_mul_pd(d, d0)); + sum1 = _mm_add_pd(sum1, _mm_mul_pd(d, d1)); + sum2 = _mm_add_pd(sum2, _mm_mul_pd(d, d2)); + sum3 = _mm_add_pd(sum3, _mm_mul_pd(d, d3)); +#if MAX_LAG > 8 + sum4 = _mm_add_pd(sum4, _mm_mul_pd(d, d4)); +#endif +#if MAX_LAG > 10 + sum5 = _mm_add_pd(sum5, _mm_mul_pd(d, d5)); + sum6 = _mm_add_pd(sum6, _mm_mul_pd(d, d6)); +#endif + } + + /* Store sum0..sum6 in autoc[0..14] */ + _mm_storeu_pd(autoc, sum0); + _mm_storeu_pd(autoc+2, sum1); + _mm_storeu_pd(autoc+4, sum2); + _mm_storeu_pd(autoc+6 ,sum3); +#if MAX_LAG > 8 + _mm_storeu_pd(autoc+8, sum4); +#endif +#if MAX_LAG > 10 + _mm_storeu_pd(autoc+10,sum5); + _mm_storeu_pd(autoc+12,sum6); +#endif diff --git a/vendor/flac/src/libFLAC/fixed.c b/vendor/flac/src/libFLAC/fixed.c new file mode 100644 index 0000000..5c42570 --- /dev/null +++ b/vendor/flac/src/libFLAC/fixed.c @@ -0,0 +1,667 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "share/compat.h" +#include "private/bitmath.h" +#include "private/fixed.h" +#include "private/macros.h" +#include "FLAC/assert.h" + +#ifdef local_abs +#undef local_abs +#endif +#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x))) + +#ifdef local_abs64 +#undef local_abs64 +#endif +#define local_abs64(x) ((uint64_t)((x)<0? -(x) : (x))) + +#ifdef FLAC__INTEGER_ONLY_LIBRARY +/* rbps stands for residual bits per sample + * + * (ln(2) * err) + * rbps = log (-----------) + * 2 ( n ) + */ +static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n) +{ + FLAC__uint32 rbps; + uint32_t bits; /* the number of bits required to represent a number */ + int fracbits; /* the number of bits of rbps that comprise the fractional part */ + + FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); + FLAC__ASSERT(err > 0); + FLAC__ASSERT(n > 0); + + FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); + if(err <= n) + return 0; + /* + * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. + * These allow us later to know we won't lose too much precision in the + * fixed-point division (err< 0); + bits = FLAC__bitmath_ilog2(err)+1; + if(bits > 16) { + err >>= (bits-16); + fracbits -= (bits-16); + } + rbps = (FLAC__uint32)err; + + /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ + rbps *= FLAC__FP_LN2; + fracbits += 16; + FLAC__ASSERT(fracbits >= 0); + + /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ + { + const int f = fracbits & 3; + if(f) { + rbps >>= f; + fracbits -= f; + } + } + + rbps = FLAC__fixedpoint_log2(rbps, fracbits, (uint32_t)(-1)); + + if(rbps == 0) + return 0; + + /* + * The return value must have 16 fractional bits. Since the whole part + * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits + * must be >= -3, these assertion allows us to be able to shift rbps + * left if necessary to get 16 fracbits without losing any bits of the + * whole part of rbps. + * + * There is a slight chance due to accumulated error that the whole part + * will require 6 bits, so we use 6 in the assertion. Really though as + * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. + */ + FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); + FLAC__ASSERT(fracbits >= -3); + + /* now shift the decimal point into place */ + if(fracbits < 16) + return rbps << (16-fracbits); + else if(fracbits > 16) + return rbps >> (fracbits-16); + else + return rbps; +} + +static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n) +{ + FLAC__uint32 rbps; + uint32_t bits; /* the number of bits required to represent a number */ + int fracbits; /* the number of bits of rbps that comprise the fractional part */ + + FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); + FLAC__ASSERT(err > 0); + FLAC__ASSERT(n > 0); + + FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); + if(err <= n) + return 0; + /* + * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. + * These allow us later to know we won't lose too much precision in the + * fixed-point division (err< 0); + bits = FLAC__bitmath_ilog2_wide(err)+1; + if(bits > 16) { + err >>= (bits-16); + fracbits -= (bits-16); + } + rbps = (FLAC__uint32)err; + + /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ + rbps *= FLAC__FP_LN2; + fracbits += 16; + FLAC__ASSERT(fracbits >= 0); + + /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ + { + const int f = fracbits & 3; + if(f) { + rbps >>= f; + fracbits -= f; + } + } + + rbps = FLAC__fixedpoint_log2(rbps, fracbits, (uint32_t)(-1)); + + if(rbps == 0) + return 0; + + /* + * The return value must have 16 fractional bits. Since the whole part + * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits + * must be >= -3, these assertion allows us to be able to shift rbps + * left if necessary to get 16 fracbits without losing any bits of the + * whole part of rbps. + * + * There is a slight chance due to accumulated error that the whole part + * will require 6 bits, so we use 6 in the assertion. Really though as + * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. + */ + FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); + FLAC__ASSERT(fracbits >= -3); + + /* now shift the decimal point into place */ + if(fracbits < 16) + return rbps << (16-fracbits); + else if(fracbits > 16) + return rbps >> (fracbits-16); + else + return rbps; +} +#endif + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#else +uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#endif +{ + FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; + uint32_t order; +#if 0 + /* This code has been around a long time, and was written when compilers weren't able + * to vectorize code. These days, compilers are better in optimizing the next block + * which is also much more readable + */ + FLAC__int32 last_error_0 = data[-1]; + FLAC__int32 last_error_1 = data[-1] - data[-2]; + FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); + FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); + FLAC__int32 error, save; + uint32_t i; + /* total_error_* are 64-bits to avoid overflow when encoding + * erratic signals when the bits-per-sample and blocksize are + * large. + */ + for(i = 0; i < data_len; i++) { + error = data[i] ; total_error_0 += local_abs(error); save = error; + error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; + error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; + error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; + error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; + } +#else + int i; + for(i = 0; i < (int)data_len; i++) { + total_error_0 += local_abs(data[i]); + total_error_1 += local_abs(data[i] - data[i-1]); + total_error_2 += local_abs(data[i] - 2 * data[i-1] + data[i-2]); + total_error_3 += local_abs(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]); + total_error_4 += local_abs(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]); + } +#endif + + + /* prefer lower order */ + if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) + order = 0; + else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 <= flac_min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 <= total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + FLAC__ASSERT(data_len > 0 || total_error_0 == 0); + FLAC__ASSERT(data_len > 0 || total_error_1 == 0); + FLAC__ASSERT(data_len > 0 || total_error_2 == 0); + FLAC__ASSERT(data_len > 0 || total_error_3 == 0); + FLAC__ASSERT(data_len > 0 || total_error_4 == 0); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); +#else + residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0; + residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0; + residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0; + residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0; + residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0; +#endif + + return order; +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#else +uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#endif +{ + FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; + uint32_t order; + int i; + + for(i = 0; i < (int)data_len; i++) { + total_error_0 += local_abs(data[i]); + total_error_1 += local_abs(data[i] - data[i-1]); + total_error_2 += local_abs(data[i] - 2 * data[i-1] + data[i-2]); + total_error_3 += local_abs(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]); + total_error_4 += local_abs(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]); + } + + /* prefer lower order */ + if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) + order = 0; + else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 <= flac_min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 <= total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + FLAC__ASSERT(data_len > 0 || total_error_0 == 0); + FLAC__ASSERT(data_len > 0 || total_error_1 == 0); + FLAC__ASSERT(data_len > 0 || total_error_2 == 0); + FLAC__ASSERT(data_len > 0 || total_error_3 == 0); + FLAC__ASSERT(data_len > 0 || total_error_4 == 0); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); +#else + residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0; + residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0; + residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0; + residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0; + residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0; +#endif + + return order; +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#define CHECK_ORDER_IS_VALID(macro_order) \ +if(order_##macro_order##_is_valid && total_error_##macro_order < smallest_error) { \ + order = macro_order; \ + smallest_error = total_error_##macro_order ; \ + residual_bits_per_sample[ macro_order ] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); \ +} \ +else \ + residual_bits_per_sample[ macro_order ] = 34.0f; +#else +#define CHECK_ORDER_IS_VALID(macro_order) \ +if(order_##macro_order##_is_valid && total_error_##macro_order < smallest_error) { \ + order = macro_order; \ + smallest_error = total_error_##macro_order ; \ + residual_bits_per_sample[ macro_order ] = (total_error_##macro_order > 0) ? local__compute_rbps_wide_integerized(total_error_##macro_order, data_len) : 0; \ +} \ +else \ + residual_bits_per_sample[ macro_order ] = 34 * FLAC__FP_ONE; +#endif + + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#else +uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#endif +{ + FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX; + FLAC__uint64 error_0, error_1, error_2, error_3, error_4; + FLAC__bool order_0_is_valid = true, order_1_is_valid = true, order_2_is_valid = true, order_3_is_valid = true, order_4_is_valid = true; + uint32_t order = 0; + int i; + + for(i = -4; i < (int)data_len; i++) { + error_0 = local_abs64((FLAC__int64)data[i]); + error_1 = (i > -4) ? local_abs64((FLAC__int64)data[i] - data[i-1]) : 0 ; + error_2 = (i > -3) ? local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]) : 0; + error_3 = (i > -2) ? local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]) : 0; + error_4 = (i > -1) ? local_abs64((FLAC__int64)data[i] - 4 * (FLAC__int64)data[i-1] + 6 * (FLAC__int64)data[i-2] - 4 * (FLAC__int64)data[i-3] + data[i-4]) : 0; + + total_error_0 += error_0; + total_error_1 += error_1; + total_error_2 += error_2; + total_error_3 += error_3; + total_error_4 += error_4; + + /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ + if(error_0 > INT32_MAX) + order_0_is_valid = false; + if(error_1 > INT32_MAX) + order_1_is_valid = false; + if(error_2 > INT32_MAX) + order_2_is_valid = false; + if(error_3 > INT32_MAX) + order_3_is_valid = false; + if(error_4 > INT32_MAX) + order_4_is_valid = false; + } + + CHECK_ORDER_IS_VALID(0); + CHECK_ORDER_IS_VALID(1); + CHECK_ORDER_IS_VALID(2); + CHECK_ORDER_IS_VALID(3); + CHECK_ORDER_IS_VALID(4); + + return order; +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#else +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#endif +{ + FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX; + FLAC__uint64 error_0, error_1, error_2, error_3, error_4; + FLAC__bool order_0_is_valid = true, order_1_is_valid = true, order_2_is_valid = true, order_3_is_valid = true, order_4_is_valid = true; + uint32_t order = 0; + int i; + + for(i = -4; i < (int)data_len; i++) { + error_0 = local_abs64(data[i]); + error_1 = (i > -4) ? local_abs64(data[i] - data[i-1]) : 0 ; + error_2 = (i > -3) ? local_abs64(data[i] - 2 * data[i-1] + data[i-2]) : 0; + error_3 = (i > -2) ? local_abs64(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]) : 0; + error_4 = (i > -1) ? local_abs64(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]) : 0; + + total_error_0 += error_0; + total_error_1 += error_1; + total_error_2 += error_2; + total_error_3 += error_3; + total_error_4 += error_4; + + /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ + if(error_0 > INT32_MAX) + order_0_is_valid = false; + if(error_1 > INT32_MAX) + order_1_is_valid = false; + if(error_2 > INT32_MAX) + order_2_is_valid = false; + if(error_3 > INT32_MAX) + order_3_is_valid = false; + if(error_4 > INT32_MAX) + order_4_is_valid = false; + } + + CHECK_ORDER_IS_VALID(0); + CHECK_ORDER_IS_VALID(1); + CHECK_ORDER_IS_VALID(2); + CHECK_ORDER_IS_VALID(3); + CHECK_ORDER_IS_VALID(4); + + return order; +} + +void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]) +{ + const int idata_len = (int)data_len; + int i; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(residual, data, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 2*data[i-1] + data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +void FLAC__fixed_compute_residual_wide(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]) +{ + const int idata_len = (int)data_len; + int i; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(residual, data, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + residual[i] = (FLAC__int64)data[i] - data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + residual[i] = (FLAC__int64)data[i] - 2*(FLAC__int64)data[i-1] + data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + residual[i] = (FLAC__int64)data[i] - 3*(FLAC__int64)data[i-1] + 3*(FLAC__int64)data[i-2] - data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + residual[i] = (FLAC__int64)data[i] - 4*(FLAC__int64)data[i-1] + 6*(FLAC__int64)data[i-2] - 4*(FLAC__int64)data[i-3] + data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +void FLAC__fixed_compute_residual_wide_33bit(const FLAC__int64 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]) +{ + const int idata_len = (int)data_len; + int i; + + switch(order) { + case 0: + for(i = 0; i < idata_len; i++) + residual[i] = data[i]; + break; + case 1: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 2*data[i-1] + data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) +/* The attribute below is to silence the undefined sanitizer of oss-fuzz. + * Because fuzzing feeds bogus predictors and residual samples to the + * decoder, having overflows in this section is unavoidable. Also, + * because the calculated values are audio path only, there is no + * potential for security problems */ +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]) +{ + int i, idata_len = (int)data_len; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(data, residual, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + data[i] = residual[i] + data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + data[i] = residual[i] + 2*data[i-1] - data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +void FLAC__fixed_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]) +{ + int i, idata_len = (int)data_len; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(data, residual, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + (FLAC__int64)data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + 2*(FLAC__int64)data[i-1] - (FLAC__int64)data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + 3*(FLAC__int64)data[i-1] - 3*(FLAC__int64)data[i-2] + (FLAC__int64)data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + 4*(FLAC__int64)data[i-1] - 6*(FLAC__int64)data[i-2] + 4*(FLAC__int64)data[i-3] - (FLAC__int64)data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) +/* The attribute below is to silence the undefined sanitizer of oss-fuzz. + * Because fuzzing feeds bogus predictors and residual samples to the + * decoder, having overflows in this section is unavoidable. Also, + * because the calculated values are audio path only, there is no + * potential for security problems */ +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +void FLAC__fixed_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int64 data[]) +{ + int i, idata_len = (int)data_len; + + switch(order) { + case 0: + for(i = 0; i < idata_len; i++) + data[i] = residual[i]; + break; + case 1: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + 2*data[i-1] - data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + data[i] = (FLAC__int64)residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} diff --git a/vendor/flac/src/libFLAC/fixed_intrin_avx2.c b/vendor/flac/src/libFLAC/fixed_intrin_avx2.c new file mode 100644 index 0000000..85fc4a6 --- /dev/null +++ b/vendor/flac/src/libFLAC/fixed_intrin_avx2.c @@ -0,0 +1,343 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/fixed.h" +#ifdef FLAC__AVX2_SUPPORTED + +#include +#include +#include "private/macros.h" +#include "share/compat.h" +#include "FLAC/assert.h" + +#ifdef local_abs +#undef local_abs +#endif +#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x))) + +FLAC__SSE_TARGET("avx2") +uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]) +{ + FLAC__uint64 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4; + FLAC__int32 i, data_len_int; + uint32_t order; + __m256i total_err0, total_err1, total_err2, total_err3, total_err4; + __m256i prev_err0, prev_err1, prev_err2, prev_err3; + __m256i tempA, tempB, bitmask; + FLAC__int64 data_scalar[4]; + FLAC__int64 prev_err0_scalar[4]; + FLAC__int64 prev_err1_scalar[4]; + FLAC__int64 prev_err2_scalar[4]; + FLAC__int64 prev_err3_scalar[4]; + total_err0 = _mm256_setzero_si256(); + total_err1 = _mm256_setzero_si256(); + total_err2 = _mm256_setzero_si256(); + total_err3 = _mm256_setzero_si256(); + total_err4 = _mm256_setzero_si256(); + data_len_int = data_len; + + for(i = 0; i < 4; i++){ + prev_err0_scalar[i] = data[-1+i*(data_len_int/4)]; + prev_err1_scalar[i] = data[-1+i*(data_len_int/4)] - data[-2+i*(data_len_int/4)]; + prev_err2_scalar[i] = prev_err1_scalar[i] - (data[-2+i*(data_len_int/4)] - data[-3+i*(data_len_int/4)]); + prev_err3_scalar[i] = prev_err2_scalar[i] - (data[-2+i*(data_len_int/4)] - 2*data[-3+i*(data_len_int/4)] + data[-4+i*(data_len_int/4)]); + } + prev_err0 = _mm256_loadu_si256((const __m256i*)(void*)prev_err0_scalar); + prev_err1 = _mm256_loadu_si256((const __m256i*)(void*)prev_err1_scalar); + prev_err2 = _mm256_loadu_si256((const __m256i*)(void*)prev_err2_scalar); + prev_err3 = _mm256_loadu_si256((const __m256i*)(void*)prev_err3_scalar); + for(i = 0; i < data_len_int / 4; i++){ + data_scalar[0] = data[i]; + data_scalar[1] = data[i+data_len/4]; + data_scalar[2] = data[i+2*data_len/4]; + data_scalar[3] = data[i+3*data_len/4]; + tempA = _mm256_loadu_si256((const __m256i*)(void*)data_scalar); + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA); + tempB = _mm256_xor_si256(tempA, bitmask); + tempB = _mm256_sub_epi64(tempB, bitmask); + total_err0 = _mm256_add_epi64(total_err0,tempB); + tempB = _mm256_sub_epi64(tempA,prev_err0); + prev_err0 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB); + tempA = _mm256_xor_si256(tempB, bitmask); + tempA = _mm256_sub_epi64(tempA, bitmask); + total_err1 = _mm256_add_epi64(total_err1,tempA); + tempA = _mm256_sub_epi64(tempB,prev_err1); + prev_err1 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA); + tempB = _mm256_xor_si256(tempA, bitmask); + tempB = _mm256_sub_epi64(tempB, bitmask); + total_err2 = _mm256_add_epi64(total_err2,tempB); + tempB = _mm256_sub_epi64(tempA,prev_err2); + prev_err2 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB); + tempA = _mm256_xor_si256(tempB, bitmask); + tempA = _mm256_sub_epi64(tempA, bitmask); + total_err3 = _mm256_add_epi64(total_err3,tempA); + tempA = _mm256_sub_epi64(tempB,prev_err3); + prev_err3 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA); + tempB = _mm256_xor_si256(tempA, bitmask); + tempB = _mm256_sub_epi64(tempB, bitmask); + total_err4 = _mm256_add_epi64(total_err4,tempB); + } + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err0); + total_error_0 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err1); + total_error_1 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err2); + total_error_2 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err3); + total_error_3 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err4); + total_error_4 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + + /* Ignore the remainder, we're ignore the first few samples too */ + + /* prefer lower order */ + if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) + order = 0; + else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 <= flac_min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 <= total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + FLAC__ASSERT(data_len > 0 || total_error_0 == 0); + FLAC__ASSERT(data_len > 0 || total_error_1 == 0); + FLAC__ASSERT(data_len > 0 || total_error_2 == 0); + FLAC__ASSERT(data_len > 0 || total_error_3 == 0); + FLAC__ASSERT(data_len > 0 || total_error_4 == 0); + + residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); + + return order; +} + +#ifdef local_abs64 +#undef local_abs64 +#endif +#define local_abs64(x) ((uint64_t)((x)<0? -(x) : (x))) + +#define CHECK_ORDER_IS_VALID(macro_order) \ +if(shadow_error_##macro_order <= INT32_MAX) { \ + if(total_error_##macro_order < smallest_error) { \ + order = macro_order; \ + smallest_error = total_error_##macro_order ; \ + } \ + residual_bits_per_sample[ macro_order ] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); \ +} \ +else \ + residual_bits_per_sample[ macro_order ] = 34.0f; + +FLAC__SSE_TARGET("avx2") +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]) +{ + FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX; + FLAC__uint64 shadow_error_0 = 0, shadow_error_1 = 0, shadow_error_2 = 0, shadow_error_3 = 0, shadow_error_4 = 0; + FLAC__uint64 error_0, error_1, error_2, error_3, error_4; + FLAC__int32 i, data_len_int; + uint32_t order = 0; + __m256i total_err0, total_err1, total_err2, total_err3, total_err4; + __m256i shadow_err0, shadow_err1, shadow_err2, shadow_err3, shadow_err4; + __m256i prev_err0, prev_err1, prev_err2, prev_err3; + __m256i tempA, tempB, bitmask; + FLAC__int64 data_scalar[4]; + FLAC__int64 prev_err0_scalar[4]; + FLAC__int64 prev_err1_scalar[4]; + FLAC__int64 prev_err2_scalar[4]; + FLAC__int64 prev_err3_scalar[4]; + total_err0 = _mm256_setzero_si256(); + total_err1 = _mm256_setzero_si256(); + total_err2 = _mm256_setzero_si256(); + total_err3 = _mm256_setzero_si256(); + total_err4 = _mm256_setzero_si256(); + shadow_err0 = _mm256_setzero_si256(); + shadow_err1 = _mm256_setzero_si256(); + shadow_err2 = _mm256_setzero_si256(); + shadow_err3 = _mm256_setzero_si256(); + shadow_err4 = _mm256_setzero_si256(); + data_len_int = data_len; + + /* First take care of preceding samples */ + for(i = -4; i < 0; i++) { + error_0 = local_abs64((FLAC__int64)data[i]); + error_1 = (i > -4) ? local_abs64((FLAC__int64)data[i] - data[i-1]) : 0 ; + error_2 = (i > -3) ? local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]) : 0; + error_3 = (i > -2) ? local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]) : 0; + + total_error_0 += error_0; + total_error_1 += error_1; + total_error_2 += error_2; + total_error_3 += error_3; + + shadow_error_0 |= error_0; + shadow_error_1 |= error_1; + shadow_error_2 |= error_2; + shadow_error_3 |= error_3; + } + + for(i = 0; i < 4; i++){ + prev_err0_scalar[i] = data[-1+i*(data_len_int/4)]; + prev_err1_scalar[i] = (FLAC__int64)(data[-1+i*(data_len_int/4)]) - data[-2+i*(data_len_int/4)]; + prev_err2_scalar[i] = prev_err1_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/4)]) - data[-3+i*(data_len_int/4)]); + prev_err3_scalar[i] = prev_err2_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/4)]) - 2*(FLAC__int64)(data[-3+i*(data_len_int/4)]) + data[-4+i*(data_len_int/4)]); + } + prev_err0 = _mm256_loadu_si256((const __m256i*)(void*)prev_err0_scalar); + prev_err1 = _mm256_loadu_si256((const __m256i*)(void*)prev_err1_scalar); + prev_err2 = _mm256_loadu_si256((const __m256i*)(void*)prev_err2_scalar); + prev_err3 = _mm256_loadu_si256((const __m256i*)(void*)prev_err3_scalar); + for(i = 0; i < data_len_int / 4; i++){ + data_scalar[0] = data[i]; + data_scalar[1] = data[i+data_len/4]; + data_scalar[2] = data[i+2*data_len/4]; + data_scalar[3] = data[i+3*data_len/4]; + tempA = _mm256_loadu_si256((const __m256i*)(void*)data_scalar); + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA); + tempB = _mm256_xor_si256(tempA, bitmask); + tempB = _mm256_sub_epi64(tempB, bitmask); + total_err0 = _mm256_add_epi64(total_err0,tempB); + shadow_err0 = _mm256_or_si256(shadow_err0,tempB); + tempB = _mm256_sub_epi64(tempA,prev_err0); + prev_err0 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB); + tempA = _mm256_xor_si256(tempB, bitmask); + tempA = _mm256_sub_epi64(tempA, bitmask); + total_err1 = _mm256_add_epi64(total_err1,tempA); + shadow_err1 = _mm256_or_si256(shadow_err1,tempA); + tempA = _mm256_sub_epi64(tempB,prev_err1); + prev_err1 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA); + tempB = _mm256_xor_si256(tempA, bitmask); + tempB = _mm256_sub_epi64(tempB, bitmask); + total_err2 = _mm256_add_epi64(total_err2,tempB); + shadow_err2 = _mm256_or_si256(shadow_err2,tempB); + tempB = _mm256_sub_epi64(tempA,prev_err2); + prev_err2 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB); + tempA = _mm256_xor_si256(tempB, bitmask); + tempA = _mm256_sub_epi64(tempA, bitmask); + total_err3 = _mm256_add_epi64(total_err3,tempA); + shadow_err3 = _mm256_or_si256(shadow_err3,tempA); + tempA = _mm256_sub_epi64(tempB,prev_err3); + prev_err3 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA); + tempB = _mm256_xor_si256(tempA, bitmask); + tempB = _mm256_sub_epi64(tempB, bitmask); + total_err4 = _mm256_add_epi64(total_err4,tempB); + shadow_err4 = _mm256_or_si256(shadow_err4,tempB); + } + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err0); + total_error_0 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err1); + total_error_1 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err2); + total_error_2 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err3); + total_error_3 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err4); + total_error_4 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err0); + shadow_error_0 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err1); + shadow_error_1 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err2); + shadow_error_2 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err3); + shadow_error_3 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3]; + _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err4); + shadow_error_4 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3]; + + /* Take care of remaining sample */ + for(i = (data_len/4)*4; i < data_len_int; i++) { + error_0 = local_abs64((FLAC__int64)data[i]); + error_1 = local_abs64((FLAC__int64)data[i] - data[i-1]); + error_2 = local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]); + error_3 = local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]); + error_4 = local_abs64((FLAC__int64)data[i] - 4 * (FLAC__int64)data[i-1] + 6 * (FLAC__int64)data[i-2] - 4 * (FLAC__int64)data[i-3] + data[i-4]); + + total_error_0 += error_0; + total_error_1 += error_1; + total_error_2 += error_2; + total_error_3 += error_3; + total_error_4 += error_4; + + shadow_error_0 |= error_0; + shadow_error_1 |= error_1; + shadow_error_2 |= error_2; + shadow_error_3 |= error_3; + shadow_error_4 |= error_4; + } + + + CHECK_ORDER_IS_VALID(0); + CHECK_ORDER_IS_VALID(1); + CHECK_ORDER_IS_VALID(2); + CHECK_ORDER_IS_VALID(3); + CHECK_ORDER_IS_VALID(4); + + return order; +} + +#endif /* FLAC__AVX2_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/fixed_intrin_sse2.c b/vendor/flac/src/libFLAC/fixed_intrin_sse2.c new file mode 100644 index 0000000..b92c13c --- /dev/null +++ b/vendor/flac/src/libFLAC/fixed_intrin_sse2.c @@ -0,0 +1,194 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +#include "private/fixed.h" +#ifdef FLAC__SSE2_SUPPORTED + +#include /* SSE2 */ +#include +#include "private/macros.h" +#include "share/compat.h" +#include "FLAC/assert.h" + +#ifdef FLAC__CPU_IA32 +#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src) +#else +#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src) +#endif + +#ifdef local_abs +#undef local_abs +#endif +#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x))) + +FLAC__SSE_TARGET("sse2") +uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]) +{ + FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4; + FLAC__int32 i, data_len_int; + uint32_t order; + __m128i total_err0, total_err1, total_err2, total_err3, total_err4; + __m128i prev_err0, prev_err1, prev_err2, prev_err3; + __m128i tempA, tempB, bitmask; + FLAC__int32 data_scalar[4]; + FLAC__int32 prev_err0_scalar[4]; + FLAC__int32 prev_err1_scalar[4]; + FLAC__int32 prev_err2_scalar[4]; + FLAC__int32 prev_err3_scalar[4]; + total_err0 = _mm_setzero_si128(); + total_err1 = _mm_setzero_si128(); + total_err2 = _mm_setzero_si128(); + total_err3 = _mm_setzero_si128(); + total_err4 = _mm_setzero_si128(); + data_len_int = data_len; + + for(i = 0; i < 4; i++){ + prev_err0_scalar[i] = data[-1+i*(data_len_int/4)]; + prev_err1_scalar[i] = data[-1+i*(data_len_int/4)] - data[-2+i*(data_len_int/4)]; + prev_err2_scalar[i] = prev_err1_scalar[i] - (data[-2+i*(data_len_int/4)] - data[-3+i*(data_len_int/4)]); + prev_err3_scalar[i] = prev_err2_scalar[i] - (data[-2+i*(data_len_int/4)] - 2*data[-3+i*(data_len_int/4)] + data[-4+i*(data_len_int/4)]); + } + prev_err0 = _mm_loadu_si128((const __m128i*)prev_err0_scalar); + prev_err1 = _mm_loadu_si128((const __m128i*)prev_err1_scalar); + prev_err2 = _mm_loadu_si128((const __m128i*)prev_err2_scalar); + prev_err3 = _mm_loadu_si128((const __m128i*)prev_err3_scalar); + for(i = 0; i < data_len_int / 4; i++){ + data_scalar[0] = data[i]; + data_scalar[1] = data[i+data_len/4]; + data_scalar[2] = data[i+2*(data_len/4)]; + data_scalar[3] = data[i+3*(data_len/4)]; + tempA = _mm_loadu_si128((const __m128i*)data_scalar); + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm_srai_epi32(tempA, 31); + tempB = _mm_xor_si128(tempA, bitmask); + tempB = _mm_sub_epi32(tempB, bitmask); + total_err0 = _mm_add_epi32(total_err0,tempB); + tempB = _mm_sub_epi32(tempA,prev_err0); + prev_err0 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm_srai_epi32(tempB, 31); + tempA = _mm_xor_si128(tempB, bitmask); + tempA = _mm_sub_epi32(tempA, bitmask); + total_err1 = _mm_add_epi32(total_err1,tempA); + tempA = _mm_sub_epi32(tempB,prev_err1); + prev_err1 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm_srai_epi32(tempA, 31); + tempB = _mm_xor_si128(tempA, bitmask); + tempB = _mm_sub_epi32(tempB, bitmask); + total_err2 = _mm_add_epi32(total_err2,tempB); + tempB = _mm_sub_epi32(tempA,prev_err2); + prev_err2 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm_srai_epi32(tempB, 31); + tempA = _mm_xor_si128(tempB, bitmask); + tempA = _mm_sub_epi32(tempA, bitmask); + total_err3 = _mm_add_epi32(total_err3,tempA); + tempA = _mm_sub_epi32(tempB,prev_err3); + prev_err3 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm_srai_epi32(tempA, 31); + tempB = _mm_xor_si128(tempA, bitmask); + tempB = _mm_sub_epi32(tempB, bitmask); + total_err4 = _mm_add_epi32(total_err4,tempB); + } + _mm_storeu_si128((__m128i*)data_scalar,total_err0); + total_error_0 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err1); + total_error_1 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err2); + total_error_2 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err3); + total_error_3 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err4); + total_error_4 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + + /* Now the remainder of samples needs to be processed */ + i *= 4; + if(data_len % 4 > 0){ + FLAC__int32 last_error_0 = data[i-1]; + FLAC__int32 last_error_1 = data[i-1] - data[i-2]; + FLAC__int32 last_error_2 = last_error_1 - (data[i-2] - data[i-3]); + FLAC__int32 last_error_3 = last_error_2 - (data[i-2] - 2*data[i-3] + data[i-4]); + FLAC__int32 error, save; + for(; i < data_len_int; i++) { + error = data[i] ; total_error_0 += local_abs(error); save = error; + error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; + error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; + error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; + error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; + } + } + + /* prefer lower order */ + if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) + order = 0; + else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 <= flac_min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 <= total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + FLAC__ASSERT(data_len > 0 || total_error_0 == 0); + FLAC__ASSERT(data_len > 0 || total_error_1 == 0); + FLAC__ASSERT(data_len > 0 || total_error_2 == 0); + FLAC__ASSERT(data_len > 0 || total_error_3 == 0); + FLAC__ASSERT(data_len > 0 || total_error_4 == 0); + + residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); + + return order; +} + +#endif /* FLAC__SSE2_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/fixed_intrin_sse42.c b/vendor/flac/src/libFLAC/fixed_intrin_sse42.c new file mode 100644 index 0000000..0556eaa --- /dev/null +++ b/vendor/flac/src/libFLAC/fixed_intrin_sse42.c @@ -0,0 +1,223 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/fixed.h" +#ifdef FLAC__SSE4_2_SUPPORTED + +#include /* SSE4.2 */ +#include +#include "private/macros.h" +#include "share/compat.h" +#include "FLAC/assert.h" + +#ifdef local_abs64 +#undef local_abs64 +#endif +#define local_abs64(x) ((uint64_t)((x)<0? -(x) : (x))) + +#define CHECK_ORDER_IS_VALID(macro_order) \ +if(shadow_error_##macro_order <= INT32_MAX) { \ + if(total_error_##macro_order < smallest_error) { \ + order = macro_order; \ + smallest_error = total_error_##macro_order ; \ + } \ + residual_bits_per_sample[ macro_order ] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); \ +} \ +else \ + residual_bits_per_sample[ macro_order ] = 34.0f; + +FLAC__SSE_TARGET("sse4.2") +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]) +{ + FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX; + FLAC__uint64 shadow_error_0 = 0, shadow_error_1 = 0, shadow_error_2 = 0, shadow_error_3 = 0, shadow_error_4 = 0; + FLAC__uint64 error_0, error_1, error_2, error_3, error_4; + FLAC__int32 i, data_len_int; + uint32_t order = 0; + __m128i total_err0, total_err1, total_err2, total_err3, total_err4; + __m128i shadow_err0, shadow_err1, shadow_err2, shadow_err3, shadow_err4; + __m128i prev_err0, prev_err1, prev_err2, prev_err3; + __m128i tempA, tempB, bitmask; + FLAC__int64 data_scalar[2]; + FLAC__int64 prev_err0_scalar[2]; + FLAC__int64 prev_err1_scalar[2]; + FLAC__int64 prev_err2_scalar[2]; + FLAC__int64 prev_err3_scalar[2]; + total_err0 = _mm_setzero_si128(); + total_err1 = _mm_setzero_si128(); + total_err2 = _mm_setzero_si128(); + total_err3 = _mm_setzero_si128(); + total_err4 = _mm_setzero_si128(); + shadow_err0 = _mm_setzero_si128(); + shadow_err1 = _mm_setzero_si128(); + shadow_err2 = _mm_setzero_si128(); + shadow_err3 = _mm_setzero_si128(); + shadow_err4 = _mm_setzero_si128(); + data_len_int = data_len; + + /* First take care of preceding samples */ + for(i = -4; i < 0; i++) { + error_0 = local_abs64((FLAC__int64)data[i]); + error_1 = (i > -4) ? local_abs64((FLAC__int64)data[i] - data[i-1]) : 0 ; + error_2 = (i > -3) ? local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]) : 0; + error_3 = (i > -2) ? local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]) : 0; + + total_error_0 += error_0; + total_error_1 += error_1; + total_error_2 += error_2; + total_error_3 += error_3; + + shadow_error_0 |= error_0; + shadow_error_1 |= error_1; + shadow_error_2 |= error_2; + shadow_error_3 |= error_3; + } + + for(i = 0; i < 2; i++){ + prev_err0_scalar[i] = data[-1+i*(data_len_int/2)]; + prev_err1_scalar[i] = (FLAC__int64)(data[-1+i*(data_len_int/2)]) - data[-2+i*(data_len_int/2)]; + prev_err2_scalar[i] = prev_err1_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/2)]) - data[-3+i*(data_len_int/2)]); + prev_err3_scalar[i] = prev_err2_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/2)]) - 2*(FLAC__int64)(data[-3+i*(data_len_int/2)]) + data[-4+i*(data_len_int/2)]); + } + prev_err0 = _mm_loadu_si128((const __m128i*)prev_err0_scalar); + prev_err1 = _mm_loadu_si128((const __m128i*)prev_err1_scalar); + prev_err2 = _mm_loadu_si128((const __m128i*)prev_err2_scalar); + prev_err3 = _mm_loadu_si128((const __m128i*)prev_err3_scalar); + for(i = 0; i < data_len_int / 2; i++){ + data_scalar[0] = data[i]; + data_scalar[1] = data[i+data_len/2]; + tempA = _mm_loadu_si128((const __m128i*)data_scalar); + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempA); + tempB = _mm_xor_si128(tempA, bitmask); + tempB = _mm_sub_epi64(tempB, bitmask); + total_err0 = _mm_add_epi64(total_err0,tempB); + shadow_err0 = _mm_or_si128(shadow_err0,tempB); + tempB = _mm_sub_epi64(tempA,prev_err0); + prev_err0 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempB); + tempA = _mm_xor_si128(tempB, bitmask); + tempA = _mm_sub_epi64(tempA, bitmask); + total_err1 = _mm_add_epi64(total_err1,tempA); + shadow_err1 = _mm_or_si128(shadow_err1,tempA); + tempA = _mm_sub_epi64(tempB,prev_err1); + prev_err1 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempA); + tempB = _mm_xor_si128(tempA, bitmask); + tempB = _mm_sub_epi64(tempB, bitmask); + total_err2 = _mm_add_epi64(total_err2,tempB); + shadow_err2 = _mm_or_si128(shadow_err2,tempB); + tempB = _mm_sub_epi64(tempA,prev_err2); + prev_err2 = tempA; + /* Next three intrinsics calculate tempA as abs of tempB */ + bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempB); + tempA = _mm_xor_si128(tempB, bitmask); + tempA = _mm_sub_epi64(tempA, bitmask); + total_err3 = _mm_add_epi64(total_err3,tempA); + shadow_err3 = _mm_or_si128(shadow_err3,tempA); + tempA = _mm_sub_epi64(tempB,prev_err3); + prev_err3 = tempB; + /* Next three intrinsics calculate tempB as abs of tempA */ + bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempA); + tempB = _mm_xor_si128(tempA, bitmask); + tempB = _mm_sub_epi64(tempB, bitmask); + total_err4 = _mm_add_epi64(total_err4,tempB); + shadow_err4 = _mm_or_si128(shadow_err4,tempB); + } + _mm_storeu_si128((__m128i*)data_scalar,total_err0); + total_error_0 += data_scalar[0] + data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,total_err1); + total_error_1 += data_scalar[0] + data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,total_err2); + total_error_2 += data_scalar[0] + data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,total_err3); + total_error_3 += data_scalar[0] + data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,total_err4); + total_error_4 += data_scalar[0] + data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,shadow_err0); + shadow_error_0 |= data_scalar[0] | data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,shadow_err1); + shadow_error_1 |= data_scalar[0] | data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,shadow_err2); + shadow_error_2 |= data_scalar[0] | data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,shadow_err3); + shadow_error_3 |= data_scalar[0] | data_scalar[1]; + _mm_storeu_si128((__m128i*)data_scalar,shadow_err4); + shadow_error_4 |= data_scalar[0] | data_scalar[1]; + + /* Take care of remaining sample */ + if(data_len_int % 2 > 0) { + i += data_len/2; + error_0 = local_abs64((FLAC__int64)data[i]); + error_1 = local_abs64((FLAC__int64)data[i] - data[i-1]); + error_2 = local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]); + error_3 = local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]); + error_4 = local_abs64((FLAC__int64)data[i] - 4 * (FLAC__int64)data[i-1] + 6 * (FLAC__int64)data[i-2] - 4 * (FLAC__int64)data[i-3] + data[i-4]); + + total_error_0 += error_0; + total_error_1 += error_1; + total_error_2 += error_2; + total_error_3 += error_3; + total_error_4 += error_4; + + shadow_error_0 |= error_0; + shadow_error_1 |= error_1; + shadow_error_2 |= error_2; + shadow_error_3 |= error_3; + shadow_error_4 |= error_4; + } + + + CHECK_ORDER_IS_VALID(0); + CHECK_ORDER_IS_VALID(1); + CHECK_ORDER_IS_VALID(2); + CHECK_ORDER_IS_VALID(3); + CHECK_ORDER_IS_VALID(4); + + return order; +} + +#endif /* FLAC__SSE4_2_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/fixed_intrin_ssse3.c b/vendor/flac/src/libFLAC/fixed_intrin_ssse3.c new file mode 100644 index 0000000..551693b --- /dev/null +++ b/vendor/flac/src/libFLAC/fixed_intrin_ssse3.c @@ -0,0 +1,179 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/fixed.h" +#ifdef FLAC__SSSE3_SUPPORTED + +#include /* SSSE3 */ +#include +#include "private/macros.h" +#include "share/compat.h" +#include "FLAC/assert.h" + +#ifdef FLAC__CPU_IA32 +#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src) +#else +#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src) +#endif + +#ifdef local_abs +#undef local_abs +#endif +#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x))) + +FLAC__SSE_TARGET("ssse3") +uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]) +{ + FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4; + FLAC__int32 i, data_len_int; + uint32_t order; + __m128i total_err0, total_err1, total_err2, total_err3, total_err4; + __m128i prev_err0, prev_err1, prev_err2, prev_err3; + __m128i tempA, tempB; + FLAC__int32 data_scalar[4]; + FLAC__int32 prev_err0_scalar[4]; + FLAC__int32 prev_err1_scalar[4]; + FLAC__int32 prev_err2_scalar[4]; + FLAC__int32 prev_err3_scalar[4]; + total_err0 = _mm_setzero_si128(); + total_err1 = _mm_setzero_si128(); + total_err2 = _mm_setzero_si128(); + total_err3 = _mm_setzero_si128(); + total_err4 = _mm_setzero_si128(); + data_len_int = data_len; + + for(i = 0; i < 4; i++){ + prev_err0_scalar[i] = data[-1+i*(data_len_int/4)]; + prev_err1_scalar[i] = data[-1+i*(data_len_int/4)] - data[-2+i*(data_len_int/4)]; + prev_err2_scalar[i] = prev_err1_scalar[i] - (data[-2+i*(data_len_int/4)] - data[-3+i*(data_len_int/4)]); + prev_err3_scalar[i] = prev_err2_scalar[i] - (data[-2+i*(data_len_int/4)] - 2*data[-3+i*(data_len_int/4)] + data[-4+i*(data_len_int/4)]); + } + prev_err0 = _mm_loadu_si128((const __m128i*)prev_err0_scalar); + prev_err1 = _mm_loadu_si128((const __m128i*)prev_err1_scalar); + prev_err2 = _mm_loadu_si128((const __m128i*)prev_err2_scalar); + prev_err3 = _mm_loadu_si128((const __m128i*)prev_err3_scalar); + for(i = 0; i < data_len_int / 4; i++){ + data_scalar[0] = data[i]; + data_scalar[1] = data[i+data_len/4]; + data_scalar[2] = data[i+2*(data_len/4)]; + data_scalar[3] = data[i+3*(data_len/4)]; + tempA = _mm_loadu_si128((const __m128i*)data_scalar); + tempB = _mm_abs_epi32(tempA); + total_err0 = _mm_add_epi32(total_err0,tempB); + tempB = _mm_sub_epi32(tempA,prev_err0); + prev_err0 = tempA; + tempA = _mm_abs_epi32(tempB); + total_err1 = _mm_add_epi32(total_err1,tempA); + tempA = _mm_sub_epi32(tempB,prev_err1); + prev_err1 = tempB; + tempB = _mm_abs_epi32(tempA); + total_err2 = _mm_add_epi32(total_err2,tempB); + tempB = _mm_sub_epi32(tempA,prev_err2); + prev_err2 = tempA; + tempA = _mm_abs_epi32(tempB); + total_err3 = _mm_add_epi32(total_err3,tempA); + tempA = _mm_sub_epi32(tempB,prev_err3); + prev_err3 = tempB; + tempB = _mm_abs_epi32(tempA); + total_err4 = _mm_add_epi32(total_err4,tempB); + } + _mm_storeu_si128((__m128i*)data_scalar,total_err0); + total_error_0 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err1); + total_error_1 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err2); + total_error_2 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err3); + total_error_3 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + _mm_storeu_si128((__m128i*)data_scalar,total_err4); + total_error_4 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3]; + + /* Now the remainder of samples needs to be processed */ + i *= 4; + if(data_len % 4 > 0){ + FLAC__int32 last_error_0 = data[i-1]; + FLAC__int32 last_error_1 = data[i-1] - data[i-2]; + FLAC__int32 last_error_2 = last_error_1 - (data[i-2] - data[i-3]); + FLAC__int32 last_error_3 = last_error_2 - (data[i-2] - 2*data[i-3] + data[i-4]); + FLAC__int32 error, save; + for(; i < data_len_int; i++) { + error = data[i] ; total_error_0 += local_abs(error); save = error; + error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; + error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; + error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; + error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; + } + } + + /* prefer lower order */ + if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) + order = 0; + else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 <= flac_min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 <= total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + FLAC__ASSERT(data_len > 0 || total_error_0 == 0); + FLAC__ASSERT(data_len > 0 || total_error_1 == 0); + FLAC__ASSERT(data_len > 0 || total_error_2 == 0); + FLAC__ASSERT(data_len > 0 || total_error_3 == 0); + FLAC__ASSERT(data_len > 0 || total_error_4 == 0); + + residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); + + return order; +} + +#endif /* FLAC__SSSE3_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/flac.pc.in b/vendor/flac/src/libFLAC/flac.pc.in new file mode 100644 index 0000000..56e8594 --- /dev/null +++ b/vendor/flac/src/libFLAC/flac.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: FLAC +Description: Free Lossless Audio Codec Library +Version: @VERSION@ +Requires.private: @OGG_PACKAGE@ +Libs: -L${libdir} -lFLAC +Libs.private: -lm +Cflags: -I${includedir} diff --git a/vendor/flac/src/libFLAC/float.c b/vendor/flac/src/libFLAC/float.c new file mode 100644 index 0000000..a06ad28 --- /dev/null +++ b/vendor/flac/src/libFLAC/float.c @@ -0,0 +1,302 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/assert.h" +#include "share/compat.h" +#include "private/float.h" + +#ifdef FLAC__INTEGER_ONLY_LIBRARY + +const FLAC__fixedpoint FLAC__FP_ZERO = 0; +const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000; +const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000; +const FLAC__fixedpoint FLAC__FP_LN2 = 45426; +const FLAC__fixedpoint FLAC__FP_E = 178145; + +/* Lookup tables for Knuth's logarithm algorithm */ +#define LOG2_LOOKUP_PRECISION 16 +static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = { + { + /* + * 0 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00000001, + /* lg(4/3) = */ 0x00000000, + /* lg(8/7) = */ 0x00000000, + /* lg(16/15) = */ 0x00000000, + /* lg(32/31) = */ 0x00000000, + /* lg(64/63) = */ 0x00000000, + /* lg(128/127) = */ 0x00000000, + /* lg(256/255) = */ 0x00000000, + /* lg(512/511) = */ 0x00000000, + /* lg(1024/1023) = */ 0x00000000, + /* lg(2048/2047) = */ 0x00000000, + /* lg(4096/4095) = */ 0x00000000, + /* lg(8192/8191) = */ 0x00000000, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 4 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00000010, + /* lg(4/3) = */ 0x00000007, + /* lg(8/7) = */ 0x00000003, + /* lg(16/15) = */ 0x00000001, + /* lg(32/31) = */ 0x00000001, + /* lg(64/63) = */ 0x00000000, + /* lg(128/127) = */ 0x00000000, + /* lg(256/255) = */ 0x00000000, + /* lg(512/511) = */ 0x00000000, + /* lg(1024/1023) = */ 0x00000000, + /* lg(2048/2047) = */ 0x00000000, + /* lg(4096/4095) = */ 0x00000000, + /* lg(8192/8191) = */ 0x00000000, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 8 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00000100, + /* lg(4/3) = */ 0x0000006a, + /* lg(8/7) = */ 0x00000031, + /* lg(16/15) = */ 0x00000018, + /* lg(32/31) = */ 0x0000000c, + /* lg(64/63) = */ 0x00000006, + /* lg(128/127) = */ 0x00000003, + /* lg(256/255) = */ 0x00000001, + /* lg(512/511) = */ 0x00000001, + /* lg(1024/1023) = */ 0x00000000, + /* lg(2048/2047) = */ 0x00000000, + /* lg(4096/4095) = */ 0x00000000, + /* lg(8192/8191) = */ 0x00000000, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 12 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00001000, + /* lg(4/3) = */ 0x000006a4, + /* lg(8/7) = */ 0x00000315, + /* lg(16/15) = */ 0x0000017d, + /* lg(32/31) = */ 0x000000bc, + /* lg(64/63) = */ 0x0000005d, + /* lg(128/127) = */ 0x0000002e, + /* lg(256/255) = */ 0x00000017, + /* lg(512/511) = */ 0x0000000c, + /* lg(1024/1023) = */ 0x00000006, + /* lg(2048/2047) = */ 0x00000003, + /* lg(4096/4095) = */ 0x00000001, + /* lg(8192/8191) = */ 0x00000001, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 16 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00010000, + /* lg(4/3) = */ 0x00006a40, + /* lg(8/7) = */ 0x00003151, + /* lg(16/15) = */ 0x000017d6, + /* lg(32/31) = */ 0x00000bba, + /* lg(64/63) = */ 0x000005d1, + /* lg(128/127) = */ 0x000002e6, + /* lg(256/255) = */ 0x00000172, + /* lg(512/511) = */ 0x000000b9, + /* lg(1024/1023) = */ 0x0000005c, + /* lg(2048/2047) = */ 0x0000002e, + /* lg(4096/4095) = */ 0x00000017, + /* lg(8192/8191) = */ 0x0000000c, + /* lg(16384/16383) = */ 0x00000006, + /* lg(32768/32767) = */ 0x00000003 + }, + { + /* + * 20 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00100000, + /* lg(4/3) = */ 0x0006a3fe, + /* lg(8/7) = */ 0x00031513, + /* lg(16/15) = */ 0x00017d60, + /* lg(32/31) = */ 0x0000bb9d, + /* lg(64/63) = */ 0x00005d10, + /* lg(128/127) = */ 0x00002e59, + /* lg(256/255) = */ 0x00001721, + /* lg(512/511) = */ 0x00000b8e, + /* lg(1024/1023) = */ 0x000005c6, + /* lg(2048/2047) = */ 0x000002e3, + /* lg(4096/4095) = */ 0x00000171, + /* lg(8192/8191) = */ 0x000000b9, + /* lg(16384/16383) = */ 0x0000005c, + /* lg(32768/32767) = */ 0x0000002e + }, + { + /* + * 24 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x01000000, + /* lg(4/3) = */ 0x006a3fe6, + /* lg(8/7) = */ 0x00315130, + /* lg(16/15) = */ 0x0017d605, + /* lg(32/31) = */ 0x000bb9ca, + /* lg(64/63) = */ 0x0005d0fc, + /* lg(128/127) = */ 0x0002e58f, + /* lg(256/255) = */ 0x0001720e, + /* lg(512/511) = */ 0x0000b8d8, + /* lg(1024/1023) = */ 0x00005c61, + /* lg(2048/2047) = */ 0x00002e2d, + /* lg(4096/4095) = */ 0x00001716, + /* lg(8192/8191) = */ 0x00000b8b, + /* lg(16384/16383) = */ 0x000005c5, + /* lg(32768/32767) = */ 0x000002e3 + }, + { + /* + * 28 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x10000000, + /* lg(4/3) = */ 0x06a3fe5c, + /* lg(8/7) = */ 0x03151301, + /* lg(16/15) = */ 0x017d6049, + /* lg(32/31) = */ 0x00bb9ca6, + /* lg(64/63) = */ 0x005d0fba, + /* lg(128/127) = */ 0x002e58f7, + /* lg(256/255) = */ 0x001720da, + /* lg(512/511) = */ 0x000b8d87, + /* lg(1024/1023) = */ 0x0005c60b, + /* lg(2048/2047) = */ 0x0002e2d7, + /* lg(4096/4095) = */ 0x00017160, + /* lg(8192/8191) = */ 0x0000b8ad, + /* lg(16384/16383) = */ 0x00005c56, + /* lg(32768/32767) = */ 0x00002e2b + } +}; + +#if 0 +static const FLAC__uint64 log2_lookup_wide[] = { + { + /* + * 32 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ FLAC__U64L(0x100000000), + /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6), + /* lg(8/7) = */ FLAC__U64L(0x31513015), + /* lg(16/15) = */ FLAC__U64L(0x17d60497), + /* lg(32/31) = */ FLAC__U64L(0x0bb9ca65), + /* lg(64/63) = */ FLAC__U64L(0x05d0fba2), + /* lg(128/127) = */ FLAC__U64L(0x02e58f74), + /* lg(256/255) = */ FLAC__U64L(0x01720d9c), + /* lg(512/511) = */ FLAC__U64L(0x00b8d875), + /* lg(1024/1023) = */ FLAC__U64L(0x005c60aa), + /* lg(2048/2047) = */ FLAC__U64L(0x002e2d72), + /* lg(4096/4095) = */ FLAC__U64L(0x00171600), + /* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2), + /* lg(16384/16383) = */ FLAC__U64L(0x0005c55d), + /* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac) + }, + { + /* + * 48 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ FLAC__U64L(0x1000000000000), + /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429), + /* lg(8/7) = */ FLAC__U64L(0x315130157f7a), + /* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb), + /* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac), + /* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd), + /* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee), + /* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8), + /* lg(512/511) = */ FLAC__U64L(0xb8d8752173), + /* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e), + /* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8), + /* lg(4096/4095) = */ FLAC__U64L(0x1716001719), + /* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b), + /* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d), + /* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52) + } +}; +#endif + +FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, uint32_t fracbits, uint32_t precision) +{ + const FLAC__uint32 ONE = (1u << fracbits); + const FLAC__uint32 *table = log2_lookup[fracbits >> 2]; + + FLAC__ASSERT(fracbits < 32); + FLAC__ASSERT((fracbits & 0x3) == 0); + + if(x < ONE) + return 0; + + if(precision > LOG2_LOOKUP_PRECISION) + precision = LOG2_LOOKUP_PRECISION; + + /* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */ + { + FLAC__uint32 y = 0; + FLAC__uint32 z = x >> 1, k = 1; + while (x > ONE && k < precision) { + if (x - z >= ONE) { + x -= z; + z = x >> k; + y += table[k]; + } + else { + z >>= 1; + k++; + } + } + return y; + } +} + +#endif /* defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/format.c b/vendor/flac/src/libFLAC/format.c new file mode 100644 index 0000000..8bbffbe --- /dev/null +++ b/vendor/flac/src/libFLAC/format.c @@ -0,0 +1,608 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for qsort() */ +#include /* for memset() */ +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "private/format.h" +#include "private/macros.h" + +#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE) +# ifdef GIT_COMMIT_TAG +FLAC_API const char *FLAC__VERSION_STRING = GIT_COMMIT_TAG; +FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " GIT_COMMIT_TAG " " GIT_COMMIT_DATE; +# else +FLAC_API const char *FLAC__VERSION_STRING = "git-" GIT_COMMIT_HASH " " GIT_COMMIT_DATE; +FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC git-" GIT_COMMIT_HASH " " GIT_COMMIT_DATE; +# endif +#else +/* PACKAGE_VERSION should come from configure */ +FLAC_API const char *FLAC__VERSION_STRING = PACKAGE_VERSION; +FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " PACKAGE_VERSION " 20230623"; +#endif + +FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; +FLAC_API const uint32_t FLAC__STREAM_SYNC = 0x664C6143; +FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN = 32; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */ + +FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff); + +FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */ + +FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */ +FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */ + +FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC = 0x3ffe; +FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */ +FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */ + +FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */ + +FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */ +FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */ +FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */ +FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */ +FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */ + +FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1< FLAC__MAX_SAMPLE_RATE) { + return false; + } + else + return true; +} + +FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate) +{ + if(blocksize > 16384) + return false; + else if(sample_rate <= 48000 && blocksize > 4608) + return false; + else + return true; +} + +FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate) +{ + if( // sample rate is not subset if + !FLAC__format_sample_rate_is_valid(sample_rate) || // sample rate is invalid or + sample_rate >= ((1u << 16) * 10) || // sample rate is larger then or equal to 655360 or + (sample_rate >= (1u << 16) && sample_rate % 10 != 0) //sample rate is >= 65536 and not divisible by 10 + ) { + return false; + } + else + return true; +} + +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table) +{ + uint32_t i; + FLAC__uint64 prev_sample_number = 0; + FLAC__bool got_prev = false; + + FLAC__ASSERT(0 != seek_table); + + if((FLAC__uint64)(seek_table->num_points) * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; + + for(i = 0; i < seek_table->num_points; i++) { + if(got_prev) { + if( + seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && + seek_table->points[i].sample_number <= prev_sample_number + ) + return false; + } + prev_sample_number = seek_table->points[i].sample_number; + got_prev = true; + } + + return true; +} + +/* used as the sort predicate for qsort() */ +static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r) +{ + /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */ + if(l->sample_number == r->sample_number) + return 0; + else if(l->sample_number < r->sample_number) + return -1; + else + return 1; +} + +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table) +{ + uint32_t i, j; + FLAC__bool first; + + FLAC__ASSERT(0 != seek_table); + + if (seek_table->num_points == 0) + return 0; + + /* sort the seekpoints */ + qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_); + + /* uniquify the seekpoints */ + first = true; + for(i = j = 0; i < seek_table->num_points; i++) { + if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) { + if(!first) { + if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number) + continue; + } + } + first = false; + seek_table->points[j++] = seek_table->points[i]; + } + + for(i = j; i < seek_table->num_points; i++) { + seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + seek_table->points[i].stream_offset = 0; + seek_table->points[i].frame_samples = 0; + } + + return j; +} + +/* + * also disallows non-shortest-form encodings, c.f. + * http://www.unicode.org/versions/corrigendum1.html + * and a more clear explanation at the end of this section: + * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + */ +static uint32_t utf8len_(const FLAC__byte *utf8) +{ + FLAC__ASSERT(0 != utf8); + if ((utf8[0] & 0x80) == 0) { + return 1; + } + else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) { + if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */ + return 0; + return 2; + } + else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) { + if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */ + return 0; + /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */ + if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */ + return 0; + if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */ + return 0; + return 3; + } + else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) { + if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */ + return 0; + return 4; + } + else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) { + if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */ + return 0; + return 5; + } + else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) { + if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */ + return 0; + return 6; + } + else { + return 0; + } +} + +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name) +{ + char c; + for(c = *name; c; c = *(++name)) + if(c < 0x20 || c == 0x3d || c > 0x7d) + return false; + return true; +} + +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length) +{ + if(length == (uint32_t)(-1)) { + while(*value) { + uint32_t n = utf8len_(value); + if(n == 0) + return false; + value += n; + } + } + else { + const FLAC__byte *end = value + length; + while(value < end) { + uint32_t n = utf8len_(value); + if(n == 0) + return false; + value += n; + } + if(value != end) + return false; + } + return true; +} + +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length) +{ + const FLAC__byte *s, *end; + + for(s = entry, end = s + length; s < end && *s != '='; s++) { + if(*s < 0x20 || *s > 0x7D) + return false; + } + if(s == end) + return false; + + s++; /* skip '=' */ + + while(s < end) { + uint32_t n = utf8len_(s); + if(n == 0) + return false; + s += n; + } + if(s != end) + return false; + + return true; +} + +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation) +{ + uint32_t i, j; + + if(check_cd_da_subset) { + if(cue_sheet->lead_in < 2 * 44100) { + if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds"; + return false; + } + if(cue_sheet->lead_in % 588 != 0) { + if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples"; + return false; + } + } + + if(cue_sheet->num_tracks == 0) { + if(violation) *violation = "cue sheet must have at least one track (the lead-out)"; + return false; + } + + if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) { + if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)"; + return false; + } + + for(i = 0; i < cue_sheet->num_tracks; i++) { + if(cue_sheet->tracks[i].number == 0) { + if(violation) *violation = "cue sheet may not have a track number 0"; + return false; + } + + if(check_cd_da_subset) { + if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) { + if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170"; + return false; + } + } + + if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) { + if(violation) { + if(i == cue_sheet->num_tracks-1) /* the lead-out track... */ + *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples"; + else + *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples"; + } + return false; + } + + if(i < cue_sheet->num_tracks - 1) { + if(cue_sheet->tracks[i].num_indices == 0) { + if(violation) *violation = "cue sheet track must have at least one index point"; + return false; + } + + if(cue_sheet->tracks[i].indices[0].number > 1) { + if(violation) *violation = "cue sheet track's first index number must be 0 or 1"; + return false; + } + } + + for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) { + if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) { + if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples"; + return false; + } + + if(j > 0) { + if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) { + if(violation) *violation = "cue sheet track index numbers must increase by 1"; + return false; + } + } + } + } + + return true; +} + +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation) +{ + char *p; + FLAC__byte *b; + + for(p = picture->mime_type; *p; p++) { + if(*p < 0x20 || *p > 0x7e) { + if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)"; + return false; + } + } + + for(b = picture->description; *b; ) { + uint32_t n = utf8len_(b); + if(n == 0) { + if(violation) *violation = "description string must be valid UTF-8"; + return false; + } + b += n; + } + + return true; +} + +/* + * These routines are private to libFLAC + */ +#if 0 /* UNUSED */ +uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order) +{ + return + FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order( + FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize), + blocksize, + predictor_order + ); +} +#endif + +uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize) +{ + uint32_t max_rice_partition_order = 0; + while(!(blocksize & 1)) { + max_rice_partition_order++; + blocksize >>= 1; + } + return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order); +} + +uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order) +{ + uint32_t max_rice_partition_order = limit; + + while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order) + max_rice_partition_order--; + + FLAC__ASSERT( + (max_rice_partition_order == 0 && blocksize >= predictor_order) || + (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order) + ); + + return max_rice_partition_order; +} + +void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) +{ + FLAC__ASSERT(0 != object); + + object->parameters = 0; + object->raw_bits = 0; + object->capacity_by_order = 0; +} + +void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) +{ + FLAC__ASSERT(0 != object); + + if(0 != object->parameters) + free(object->parameters); + if(0 != object->raw_bits) + free(object->raw_bits); + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object); +} + +#if defined(_MSC_VER) +// silence three MSVC warnings 'result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)' +#pragma warning ( disable : 4334 ) +#endif + +FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order) +{ + FLAC__ASSERT(0 != object); + + if(object->capacity_by_order < max_partition_order || object->parameters == NULL || object->raw_bits == NULL) { + if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(uint32_t)*(1 << max_partition_order)))) + return false; + if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(uint32_t)*(1 << max_partition_order)))) + return false; + memset(object->raw_bits, 0, sizeof(uint32_t)*(1 << max_partition_order)); + object->capacity_by_order = max_partition_order; + } + + return true; +} + +#if defined(_MSC_VER) +#pragma warning ( default : 4334 ) +#endif diff --git a/vendor/flac/src/libFLAC/include/Makefile.am b/vendor/flac/src/libFLAC/include/Makefile.am new file mode 100644 index 0000000..8484d12 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/Makefile.am @@ -0,0 +1,32 @@ +# libFLAC - Free Lossless Audio Codec library +# Copyright (C) 2001-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +SUBDIRS = private protected diff --git a/vendor/flac/src/libFLAC/include/private/Makefile.am b/vendor/flac/src/libFLAC/include/private/Makefile.am new file mode 100644 index 0000000..3e63d31 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/Makefile.am @@ -0,0 +1,53 @@ +# libFLAC - Free Lossless Audio Codec library +# Copyright (C) 2001-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +noinst_HEADERS = \ + all.h \ + bitmath.h \ + bitreader.h \ + bitwriter.h \ + cpu.h \ + crc.h \ + fixed.h \ + float.h \ + format.h \ + lpc.h \ + macros.h \ + md5.h \ + memory.h \ + metadata.h \ + ogg_decoder_aspect.h \ + ogg_encoder_aspect.h \ + ogg_helper.h \ + ogg_mapping.h \ + stream_encoder.h \ + stream_encoder_framing.h \ + window.h diff --git a/vendor/flac/src/libFLAC/include/private/all.h b/vendor/flac/src/libFLAC/include/private/all.h new file mode 100644 index 0000000..10b6949 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/all.h @@ -0,0 +1,50 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__ALL_H +#define FLAC__PRIVATE__ALL_H + +#include "bitmath.h" +#include "bitreader.h" +#include "bitwriter.h" +#include "cpu.h" +#include "crc.h" +#include "fixed.h" +#include "float.h" +#include "format.h" +#include "lpc.h" +#include "md5.h" +#include "memory.h" +#include "metadata.h" +#include "stream_encoder_framing.h" + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/bitmath.h b/vendor/flac/src/libFLAC/include/private/bitmath.h new file mode 100644 index 0000000..12e062f --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/bitmath.h @@ -0,0 +1,210 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__BITMATH_H +#define FLAC__PRIVATE__BITMATH_H + +#include "FLAC/ordinals.h" +#include "FLAC/assert.h" + +#include "share/compat.h" + +#if defined(_MSC_VER) +#include /* for _BitScanReverse* */ +#endif + +/* Will never be emitted for MSVC, GCC, Intel compilers */ +static inline uint32_t FLAC__clz_soft_uint32(FLAC__uint32 word) +{ + static const uint8_t byte_to_unary_table[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + return word > 0xffffff ? byte_to_unary_table[word >> 24] : + word > 0xffff ? byte_to_unary_table[word >> 16] + 8 : + word > 0xff ? byte_to_unary_table[word >> 8] + 16 : + byte_to_unary_table[word] + 24; +} + +static inline uint32_t FLAC__clz_uint32(FLAC__uint32 v) +{ +/* Never used with input 0 */ + FLAC__ASSERT(v > 0); +#if defined(__INTEL_COMPILER) + return _bit_scan_reverse(v) ^ 31U; +#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on + * -march= setting or to a software routine in exotic machines. */ + return __builtin_clz(v); +#elif defined(_MSC_VER) + { + uint32_t idx; + _BitScanReverse(&idx, v); + return idx ^ 31U; + } +#else + return FLAC__clz_soft_uint32(v); +#endif +} + +/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */ +static inline uint32_t FLAC__clz_soft_uint64(FLAC__uint64 word) +{ + return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) : + FLAC__clz_uint32((FLAC__uint32)word) + 32; +} + +static inline uint32_t FLAC__clz_uint64(FLAC__uint64 v) +{ + /* Never used with input 0 */ + FLAC__ASSERT(v > 0); +#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) + return __builtin_clzll(v); +#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64)) + { + uint32_t idx; + _BitScanReverse64(&idx, v); + return idx ^ 63U; + } +#else + return FLAC__clz_soft_uint64(v); +#endif +} + +/* These two functions work with input 0 */ +static inline uint32_t FLAC__clz2_uint32(FLAC__uint32 v) +{ + if (!v) + return 32; + return FLAC__clz_uint32(v); +} + +static inline uint32_t FLAC__clz2_uint64(FLAC__uint64 v) +{ + if (!v) + return 64; + return FLAC__clz_uint64(v); +} + +/* An example of what FLAC__bitmath_ilog2() computes: + * + * ilog2( 0) = assertion failure + * ilog2( 1) = 0 + * ilog2( 2) = 1 + * ilog2( 3) = 1 + * ilog2( 4) = 2 + * ilog2( 5) = 2 + * ilog2( 6) = 2 + * ilog2( 7) = 2 + * ilog2( 8) = 3 + * ilog2( 9) = 3 + * ilog2(10) = 3 + * ilog2(11) = 3 + * ilog2(12) = 3 + * ilog2(13) = 3 + * ilog2(14) = 3 + * ilog2(15) = 3 + * ilog2(16) = 4 + * ilog2(17) = 4 + * ilog2(18) = 4 + */ + +static inline uint32_t FLAC__bitmath_ilog2(FLAC__uint32 v) +{ + FLAC__ASSERT(v > 0); +#if defined(__INTEL_COMPILER) + return _bit_scan_reverse(v); +#elif defined(_MSC_VER) + { + uint32_t idx; + _BitScanReverse(&idx, v); + return idx; + } +#else + return FLAC__clz_uint32(v) ^ 31U; +#endif +} + +static inline uint32_t FLAC__bitmath_ilog2_wide(FLAC__uint64 v) +{ + FLAC__ASSERT(v > 0); +#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) + return __builtin_clzll(v) ^ 63U; +/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */ +#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64)) + { + uint32_t idx; + _BitScanReverse64(&idx, v); + return idx; + } +#else +/* Brain-damaged compilers will use the fastest possible way that is, + de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf) + (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain). +*/ + { + static const uint8_t DEBRUIJN_IDX64[64]={ + 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40, + 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57, + 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56, + 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58 + }; + v|= v>>1; + v|= v>>2; + v|= v>>4; + v|= v>>8; + v|= v>>16; + v|= v>>32; + v= (v>>1)+1; + return DEBRUIJN_IDX64[v*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F]; + } +#endif +} + +uint32_t FLAC__bitmath_silog2(FLAC__int64 v); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/bitreader.h b/vendor/flac/src/libFLAC/include/private/bitreader.h new file mode 100644 index 0000000..c36c926 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/bitreader.h @@ -0,0 +1,101 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__BITREADER_H +#define FLAC__PRIVATE__BITREADER_H + +#include /* for FILE */ +#include "FLAC/ordinals.h" +#include "cpu.h" + +/* + * opaque structure definition + */ +struct FLAC__BitReader; +typedef struct FLAC__BitReader FLAC__BitReader; + +typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data); + +/* + * construction, deletion, initialization, etc functions + */ +FLAC__BitReader *FLAC__bitreader_new(void); +void FLAC__bitreader_delete(FLAC__BitReader *br); +FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd); +void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */ +FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br); +void FLAC__bitreader_set_framesync_location(FLAC__BitReader *br); +FLAC__bool FLAC__bitreader_rewind_to_after_last_seen_framesync(FLAC__BitReader *br); + +/* + * CRC functions + */ +void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed); +FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br); + +/* + * info functions + */ +FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); +uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); +uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); +void FLAC__bitreader_set_limit(FLAC__BitReader *br, uint32_t limit); +void FLAC__bitreader_remove_limit(FLAC__BitReader *br); +uint32_t FLAC__bitreader_limit_remaining(FLAC__BitReader *br); +void FLAC__bitreader_limit_invalidate(FLAC__BitReader *br); + +/* + * read functions + */ + +FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits); +FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits); +FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits); +FLAC__bool FLAC__bitreader_read_raw_int64(FLAC__BitReader *br, FLAC__int64 *val, uint32_t bits); +FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/ +FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */ +FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */ +FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */ +FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val); +FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter); +FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); +#ifdef FLAC__BMI2_SUPPORTED +FLAC__bool FLAC__bitreader_read_rice_signed_block_bmi2(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); +#endif + +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter); +FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter); +#endif +FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen); +FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen); +#endif diff --git a/vendor/flac/src/libFLAC/include/private/bitwriter.h b/vendor/flac/src/libFLAC/include/private/bitwriter.h new file mode 100644 index 0000000..39bcf25 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/bitwriter.h @@ -0,0 +1,104 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__BITWRITER_H +#define FLAC__PRIVATE__BITWRITER_H + +#include /* for FILE */ +#include "FLAC/ordinals.h" + +/* + * opaque structure definition + */ +struct FLAC__BitWriter; +typedef struct FLAC__BitWriter FLAC__BitWriter; + +/* + * construction, deletion, initialization, etc functions + */ +FLAC__BitWriter *FLAC__bitwriter_new(void); +void FLAC__bitwriter_delete(FLAC__BitWriter *bw); +FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw); +void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */ +void FLAC__bitwriter_clear(FLAC__BitWriter *bw); + +/* + * CRC functions + * + * non-const *bw because they have to cal FLAC__bitwriter_get_buffer() + */ +FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc); +FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc); + +/* + * info functions + */ +FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw); +uint32_t FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */ + +/* + * direct buffer access + * + * there may be no calls on the bitwriter between get and release. + * the bitwriter continues to own the returned buffer. + * before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned() + */ +FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes); +void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw); + +/* + * write functions + */ +FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits); +FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits); +FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits); +FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits); +FLAC__bool FLAC__bitwriter_write_raw_int64(FLAC__BitWriter *bw, FLAC__int64 val, uint32_t bits); +FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/ +FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals); +FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val); +#if 0 /* UNUSED */ +uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter); +uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter); +uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t val, uint32_t parameter); +FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t parameter); +#endif +FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, uint32_t nvals, uint32_t parameter); +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter); +FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, uint32_t val, uint32_t parameter); +#endif +FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val); +FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val); +FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/cpu.h b/vendor/flac/src/libFLAC/include/private/cpu.h new file mode 100644 index 0000000..8843c74 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/cpu.h @@ -0,0 +1,198 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__CPU_H +#define FLAC__PRIVATE__CPU_H + +#include "FLAC/ordinals.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef FLAC__CPU_X86_64 + +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) +#define FLAC__CPU_X86_64 +#endif + +#endif + +#ifndef FLAC__CPU_IA32 + +#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86) +#define FLAC__CPU_IA32 +#endif + +#endif + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#if FLAC__HAS_X86INTRIN +/* SSE intrinsics support by ICC/MSVC/GCC */ +#if defined __INTEL_COMPILER + #define FLAC__SSE_TARGET(x) + #define FLAC__SSE_SUPPORTED 1 + #define FLAC__SSE2_SUPPORTED 1 + #if (__INTEL_COMPILER >= 1000) /* Intel C++ Compiler 10.0 */ + #define FLAC__SSSE3_SUPPORTED 1 + #define FLAC__SSE4_1_SUPPORTED 1 + #define FLAC__SSE4_2_SUPPORTED 1 + #endif + #ifdef FLAC__USE_AVX + #if (__INTEL_COMPILER >= 1110) /* Intel C++ Compiler 11.1 */ + #define FLAC__AVX_SUPPORTED 1 + #endif + #if (__INTEL_COMPILER >= 1300) /* Intel C++ Compiler 13.0 */ + #define FLAC__AVX2_SUPPORTED 1 + #define FLAC__FMA_SUPPORTED 1 + #endif + #endif +#elif defined __clang__ && __has_attribute(__target__) /* clang */ + #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x))) + #define FLAC__SSE_SUPPORTED 1 + #define FLAC__SSE2_SUPPORTED 1 + #define FLAC__SSSE3_SUPPORTED 1 + #define FLAC__SSE4_1_SUPPORTED 1 + #define FLAC__SSE4_2_SUPPORTED 1 + #ifdef FLAC__USE_AVX + #define FLAC__AVX_SUPPORTED 1 + #define FLAC__AVX2_SUPPORTED 1 + #define FLAC__FMA_SUPPORTED 1 + #define FLAC__BMI2_SUPPORTED 1 + #endif +#elif defined __GNUC__ && !defined __clang__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* GCC 4.9+ */ + #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x))) + #define FLAC__SSE_SUPPORTED 1 + #define FLAC__SSE2_SUPPORTED 1 + #define FLAC__SSSE3_SUPPORTED 1 + #define FLAC__SSE4_1_SUPPORTED 1 + #define FLAC__SSE4_2_SUPPORTED 1 + #ifdef FLAC__USE_AVX + #define FLAC__AVX_SUPPORTED 1 + #define FLAC__AVX2_SUPPORTED 1 + #define FLAC__FMA_SUPPORTED 1 + #define FLAC__BMI2_SUPPORTED 1 + #endif +#elif defined _MSC_VER + #define FLAC__SSE_TARGET(x) + #define FLAC__SSE_SUPPORTED 1 + #define FLAC__SSE2_SUPPORTED 1 + #if (_MSC_VER >= 1500) /* MS Visual Studio 2008 */ + #define FLAC__SSSE3_SUPPORTED 1 + #define FLAC__SSE4_1_SUPPORTED 1 + #define FLAC__SSE4_2_SUPPORTED 1 + #endif + #ifdef FLAC__USE_AVX + #if (_MSC_FULL_VER >= 160040219) /* MS Visual Studio 2010 SP1 */ + #define FLAC__AVX_SUPPORTED 1 + #endif + #if (_MSC_VER >= 1700) /* MS Visual Studio 2012 */ + #define FLAC__AVX2_SUPPORTED 1 + #define FLAC__FMA_SUPPORTED 1 + #endif + #endif +#else + #define FLAC__SSE_TARGET(x) + #ifdef __SSE__ + #define FLAC__SSE_SUPPORTED 1 + #endif + #ifdef __SSE2__ + #define FLAC__SSE2_SUPPORTED 1 + #endif + #ifdef __SSSE3__ + #define FLAC__SSSE3_SUPPORTED 1 + #endif + #ifdef __SSE4_1__ + #define FLAC__SSE4_1_SUPPORTED 1 + #endif + #ifdef __SSE4_2__ + #define FLAC__SSE4_2_SUPPORTED 1 + #endif + #ifdef FLAC__USE_AVX + #ifdef __AVX__ + #define FLAC__AVX_SUPPORTED 1 + #endif + #ifdef __AVX2__ + #define FLAC__AVX2_SUPPORTED 1 + #endif + #ifdef __FMA__ + #define FLAC__FMA_SUPPORTED 1 + #endif + #endif +#endif /* compiler version */ +#endif /* intrinsics support */ + + +#ifndef FLAC__AVX_SUPPORTED +#define FLAC__AVX_SUPPORTED 0 +#endif + +typedef enum { + FLAC__CPUINFO_TYPE_IA32, + FLAC__CPUINFO_TYPE_X86_64, + FLAC__CPUINFO_TYPE_UNKNOWN +} FLAC__CPUInfo_Type; + +typedef struct { + FLAC__bool intel; + + FLAC__bool cmov; + FLAC__bool mmx; + FLAC__bool sse; + FLAC__bool sse2; + + FLAC__bool sse3; + FLAC__bool ssse3; + FLAC__bool sse41; + FLAC__bool sse42; + FLAC__bool avx; + FLAC__bool avx2; + FLAC__bool fma; + FLAC__bool bmi2; +} FLAC__CPUInfo_x86; + +typedef struct { + FLAC__bool use_asm; + FLAC__CPUInfo_Type type; + FLAC__CPUInfo_x86 x86; +} FLAC__CPUInfo; + +void FLAC__cpu_info(FLAC__CPUInfo *info); + +FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void); + +void FLAC__cpu_info_asm_ia32(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/crc.h b/vendor/flac/src/libFLAC/include/private/crc.h new file mode 100644 index 0000000..fe44502 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/crc.h @@ -0,0 +1,60 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__CRC_H +#define FLAC__PRIVATE__CRC_H + +#include "FLAC/ordinals.h" + +/* 8 bit CRC generator, MSB shifted first +** polynomial = x^8 + x^2 + x^1 + x^0 +** init = 0 +*/ +FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len); + +/* 16 bit CRC generator, MSB shifted first +** polynomial = x^16 + x^15 + x^2 + x^0 +** init = 0 +*/ +extern FLAC__uint16 const FLAC__crc16_table[8][256]; + +#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) +/* this alternate may be faster on some systems/compilers */ +#if 0 +#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) & 0xffff) +#endif + +FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len); +FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc); +FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/fixed.h b/vendor/flac/src/libFLAC/include/private/fixed.h new file mode 100644 index 0000000..c4efecd --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/fixed.h @@ -0,0 +1,117 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__FIXED_H +#define FLAC__PRIVATE__FIXED_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "private/cpu.h" +#include "private/float.h" +#include "FLAC/format.h" + +/* + * FLAC__fixed_compute_best_predictor() + * -------------------------------------------------------------------- + * Compute the best fixed predictor and the expected bits-per-sample + * of the residual signal for each order. The _wide() version uses + * 64-bit integers which is statistically necessary when bits-per- + * sample + log2(blocksize) > 30 + * + * IN data[0,data_len-1] + * IN data_len + * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER] + */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY +uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +# ifndef FLAC__NO_ASM +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED +uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); +# endif +# ifdef FLAC__SSSE3_SUPPORTED +uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +# endif +# ifdef FLAC__SSE4_2_SUPPORTED +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +# endif +# ifdef FLAC__AVX2_SUPPORTED +uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +# endif +# endif +# endif +#else +uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +#endif + +/* + * FLAC__fixed_compute_residual() + * -------------------------------------------------------------------- + * Compute the residual signal obtained from sutracting the predicted + * signal from the original. + * + * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) + * IN data_len length of original signal + * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order + * OUT residual[0,data_len-1] residual signal + */ +void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]); +void FLAC__fixed_compute_residual_wide(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]); +void FLAC__fixed_compute_residual_wide_33bit(const FLAC__int64 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]); + +/* + * FLAC__fixed_restore_signal() + * -------------------------------------------------------------------- + * Restore the original signal by summing the residual and the + * predictor. + * + * IN residual[0,data_len-1] residual signal + * IN data_len length of original signal + * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order + * *** IMPORTANT: the caller must pass in the historical samples: + * IN data[-order,-1] previously-reconstructed historical samples + * OUT data[0,data_len-1] original signal + */ +void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]); +void FLAC__fixed_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]); +void FLAC__fixed_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int64 data[]); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/float.h b/vendor/flac/src/libFLAC/include/private/float.h new file mode 100644 index 0000000..bec2634 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/float.h @@ -0,0 +1,95 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__FLOAT_H +#define FLAC__PRIVATE__FLOAT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "FLAC/ordinals.h" + +/* + * All the code in libFLAC that uses float and double + * should be protected by checks of the macro + * FLAC__INTEGER_ONLY_LIBRARY. + * + */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY +/* + * FLAC__real is the basic floating point type used in LPC analysis. + * + * WATCHOUT: changing FLAC__real will change the signatures of many + * functions that have assembly language equivalents and break them. + */ +typedef float FLAC__real; +#else +/* + * The convention for FLAC__fixedpoint is to use the upper 16 bits + * for the integer part and lower 16 bits for the fractional part. + */ +typedef FLAC__int32 FLAC__fixedpoint; +extern const FLAC__fixedpoint FLAC__FP_ZERO; +extern const FLAC__fixedpoint FLAC__FP_ONE_HALF; +extern const FLAC__fixedpoint FLAC__FP_ONE; +extern const FLAC__fixedpoint FLAC__FP_LN2; +extern const FLAC__fixedpoint FLAC__FP_E; + +#define FLAC__fixedpoint_trunc(x) ((x)>>16) + +#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) ) + +#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) ) + +/* + * FLAC__fixedpoint_log2() + * -------------------------------------------------------------------- + * Returns the base-2 logarithm of the fixed-point number 'x' using an + * algorithm by Knuth for x >= 1.0 + * + * 'fracbits' is the number of fractional bits of 'x'. 'fracbits' must + * be < 32 and evenly divisible by 4 (0 is OK but not very precise). + * + * 'precision' roughly limits the number of iterations that are done; + * use (uint32_t)(-1) for maximum precision. + * + * If 'x' is less than one -- that is, x < (1< +#endif + +#include "private/cpu.h" +#include "private/float.h" +#include "FLAC/format.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +/* + * FLAC__lpc_window_data() + * -------------------------------------------------------------------- + * Applies the given window to the data. + * OPT: asm implementation + * + * IN in[0,data_len-1] + * IN window[0,data_len-1] + * OUT out[0,lag-1] + * IN data_len + */ +void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len); +void FLAC__lpc_window_data_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len); +void FLAC__lpc_window_data_partial(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift); +void FLAC__lpc_window_data_partial_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift); + +/* + * FLAC__lpc_compute_autocorrelation() + * -------------------------------------------------------------------- + * Compute the autocorrelation for lags between 0 and lag-1. + * Assumes data[] outside of [0,data_len-1] == 0. + * Asserts that lag > 0. + * + * IN data[0,data_len-1] + * IN data_len + * IN 0 < lag <= data_len + * OUT autoc[0,lag-1] + */ +void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +#ifndef FLAC__NO_ASM +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED +void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +# endif +# endif +# if defined FLAC__CPU_X86_64 && FLAC__HAS_X86INTRIN +# ifdef FLAC__FMA_SUPPORTED +void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +# endif +# endif +#if defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN && FLAC__HAS_A64NEONINTRIN +void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); +#endif +#endif /* FLAC__NO_ASM */ + +/* + * FLAC__lpc_compute_lp_coefficients() + * -------------------------------------------------------------------- + * Computes LP coefficients for orders 1..max_order. + * Do not call if autoc[0] == 0.0. This means the signal is zero + * and there is no point in calculating a predictor. + * + * IN autoc[0,max_order] autocorrelation values + * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute + * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order + * *** IMPORTANT: + * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched + * OUT error[0,max_order-1] error for each order (more + * specifically, the variance of + * the error signal times # of + * samples in the signal) + * + * Example: if max_order is 9, the LP coefficients for order 9 will be + * in lp_coeff[8][0,8], the LP coefficients for order 8 will be + * in lp_coeff[7][0,7], etc. + */ +void FLAC__lpc_compute_lp_coefficients(const double autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]); + +/* + * FLAC__lpc_quantize_coefficients() + * -------------------------------------------------------------------- + * Quantizes the LP coefficients. NOTE: precision + bits_per_sample + * must be less than 32 (sizeof(FLAC__int32)*8). + * + * IN lp_coeff[0,order-1] LP coefficients + * IN order LP order + * IN FLAC__MIN_QLP_COEFF_PRECISION < precision + * desired precision (in bits, including sign + * bit) of largest coefficient + * OUT qlp_coeff[0,order-1] quantized coefficients + * OUT shift # of bits to shift right to get approximated + * LP coefficients. NOTE: could be negative. + * RETURN 0 => quantization OK + * 1 => coefficients require too much shifting for *shift to + * fit in the LPC subframe header. 'shift' is unset. + * 2 => coefficients are all zero, which is bad. 'shift' is + * unset. + */ +int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift); + +/* + * FLAC__lpc_compute_residual_from_qlp_coefficients() + * -------------------------------------------------------------------- + * Compute the residual signal obtained from sutracting the predicted + * signal from the original. + * + * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) + * IN data_len length of original signal + * IN qlp_coeff[0,order-1] quantized LP coefficients + * IN order > 0 LP order + * IN lp_quantization quantization of LP coefficients in bits + * OUT residual[0,data_len-1] residual signal + */ +void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(const FLAC__int64 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +#ifndef FLAC__NO_ASM +# ifdef FLAC__CPU_ARM64 +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +# endif + +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED +void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +# endif +# ifdef FLAC__SSE4_1_SUPPORTED +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +# endif +# ifdef FLAC__AVX2_SUPPORTED +void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +# endif +# endif +#endif + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + +uint32_t FLAC__lpc_max_prediction_before_shift_bps(uint32_t subframe_bps, const FLAC__int32 qlp_coeff[], uint32_t order); +uint32_t FLAC__lpc_max_residual_bps(uint32_t subframe_bps, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization); + +/* + * FLAC__lpc_restore_signal() + * -------------------------------------------------------------------- + * Restore the original signal by summing the residual and the + * predictor. + * + * IN residual[0,data_len-1] residual signal + * IN data_len length of original signal + * IN qlp_coeff[0,order-1] quantized LP coefficients + * IN order > 0 LP order + * IN lp_quantization quantization of LP coefficients in bits + * *** IMPORTANT: the caller must pass in the historical samples: + * IN data[-order,-1] previously-reconstructed historical samples + * OUT data[0,data_len-1] original signal + */ +void FLAC__lpc_restore_signal(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); +void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); +void FLAC__lpc_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int64 data[]); + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +/* + * FLAC__lpc_compute_expected_bits_per_residual_sample() + * -------------------------------------------------------------------- + * Compute the expected number of bits per residual signal sample + * based on the LP error (which is related to the residual variance). + * + * IN lpc_error >= 0.0 error returned from calculating LP coefficients + * IN total_samples > 0 # of samples in residual signal + * RETURN expected bits per sample + */ +double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples); +double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale); + +/* + * FLAC__lpc_compute_best_order() + * -------------------------------------------------------------------- + * Compute the best order from the array of signal errors returned + * during coefficient computation. + * + * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients + * IN max_order > 0 max LP order + * IN total_samples > 0 # of samples in residual signal + * IN overhead_bits_per_order # of bits overhead for each increased LP order + * (includes warmup sample size and quantized LP coefficient) + * RETURN [1,max_order] best order + */ +uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order); + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/macros.h b/vendor/flac/src/libFLAC/include/private/macros.h new file mode 100644 index 0000000..8204ed5 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/macros.h @@ -0,0 +1,74 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2012-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__MACROS_H +#define FLAC__PRIVATE__MACROS_H + +#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + +#define flac_max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +#define MIN_PASTE(A,B) A##B +#define MIN_IMPL(A,B,L) ({ \ + __typeof__(A) MIN_PASTE(__a,L) = (A); \ + __typeof__(B) MIN_PASTE(__b,L) = (B); \ + MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \ + }) + +#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__) + +/* Whatever other unix that has sys/param.h */ +#elif defined(HAVE_SYS_PARAM_H) +#include +#if defined(MIN) && defined(MAX) +#define flac_max(a,b) MAX(a,b) +#define flac_min(a,b) MIN(a,b) +#endif + +/* Windows VS has them in stdlib.h.. XXX:Untested */ +#elif defined(_MSC_VER) +#include +#define flac_max(a,b) __max(a,b) +#define flac_min(a,b) __min(a,b) +#endif + +#ifndef flac_min +#define flac_min(x,y) ((x) <= (y) ? (x) : (y)) +#endif + +#ifndef flac_max +#define flac_max(x,y) ((x) >= (y) ? (x) : (y)) +#endif + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/md5.h b/vendor/flac/src/libFLAC/include/private/md5.h new file mode 100644 index 0000000..f9d79c3 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/md5.h @@ -0,0 +1,50 @@ +#ifndef FLAC__PRIVATE__MD5_H +#define FLAC__PRIVATE__MD5_H + +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson . + * Still in the public domain. + * + * Josh Coalson: made some changes to integrate with libFLAC. + * Still in the public domain, with no warranty. + */ + +#include "FLAC/ordinals.h" + +typedef union { + FLAC__byte *p8; + FLAC__int16 *p16; + FLAC__int32 *p32; +} FLAC__multibyte; + +typedef struct { + FLAC__uint32 in[16]; + FLAC__uint32 buf[4]; + FLAC__uint32 bytes[2]; + FLAC__multibyte internal_buf; + size_t capacity; +} FLAC__MD5Context; + +void FLAC__MD5Init(FLAC__MD5Context *context); +void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context); + +FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/memory.h b/vendor/flac/src/libFLAC/include/private/memory.h new file mode 100644 index 0000000..4221bcf --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/memory.h @@ -0,0 +1,58 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__MEMORY_H +#define FLAC__PRIVATE__MEMORY_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include /* for size_t */ + +#include "private/float.h" +#include "FLAC/ordinals.h" /* for FLAC__bool */ + +/* Returns the unaligned address returned by malloc. + * Use free() on this address to deallocate. + */ +void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address); +FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer); +FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer); +FLAC__bool FLAC__memory_alloc_aligned_int64_array(size_t elements, FLAC__int64 **unaligned_pointer, FLAC__int64 **aligned_pointer); +FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer); +#ifndef FLAC__INTEGER_ONLY_LIBRARY +FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer); +#endif +void *safe_malloc_mul_2op_p(size_t size1, size_t size2); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/metadata.h b/vendor/flac/src/libFLAC/include/private/metadata.h new file mode 100644 index 0000000..d3ceb53 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/metadata.h @@ -0,0 +1,46 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__METADATA_H +#define FLAC__PRIVATE__METADATA_H + +#include "FLAC/metadata.h" + +/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not + * be a consistent state (e.g. PICTURE) or equivalent to the initial + * state after FLAC__metadata_object_new() + */ +void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object); + +void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/ogg_decoder_aspect.h b/vendor/flac/src/libFLAC/include/private/ogg_decoder_aspect.h new file mode 100644 index 0000000..c923641 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/ogg_decoder_aspect.h @@ -0,0 +1,80 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__OGG_DECODER_ASPECT_H +#define FLAC__PRIVATE__OGG_DECODER_ASPECT_H + +#include + +#include "FLAC/ordinals.h" +#include "FLAC/stream_decoder.h" /* for FLAC__StreamDecoderReadStatus */ + +typedef struct FLAC__OggDecoderAspect { + /* these are storage for values that can be set through the API */ + FLAC__bool use_first_serial_number; + long serial_number; + + /* these are for internal state related to Ogg decoding */ + ogg_stream_state stream_state; + ogg_sync_state sync_state; + uint32_t version_major, version_minor; + FLAC__bool need_serial_number; + FLAC__bool end_of_stream; + FLAC__bool have_working_page; /* only if true will the following vars be valid */ + ogg_page working_page; + FLAC__bool have_working_packet; /* only if true will the following vars be valid */ + ogg_packet working_packet; /* as we work through the packet we will move working_packet.packet forward and working_packet.bytes down */ +} FLAC__OggDecoderAspect; + +void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value); +void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect); +FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect); +void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect); +void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect); +void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect); + +typedef enum { + FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR +} FLAC__OggDecoderAspectReadStatus; + +typedef FLAC__OggDecoderAspectReadStatus (*FLAC__OggDecoderAspectReadCallbackProxy)(const void *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + +FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/ogg_encoder_aspect.h b/vendor/flac/src/libFLAC/include/private/ogg_encoder_aspect.h new file mode 100644 index 0000000..0e9bb4b --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/ogg_encoder_aspect.h @@ -0,0 +1,63 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__OGG_ENCODER_ASPECT_H +#define FLAC__PRIVATE__OGG_ENCODER_ASPECT_H + +#include + +#include "FLAC/ordinals.h" +#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoderWriteStatus */ + +typedef struct FLAC__OggEncoderAspect { + /* these are storage for values that can be set through the API */ + long serial_number; + uint32_t num_metadata; + + /* these are for internal state related to Ogg encoding */ + ogg_stream_state stream_state; + ogg_page page; + FLAC__bool seen_magic; /* true if we've seen the fLaC magic in the write callback yet */ + FLAC__bool is_first_packet; + FLAC__uint64 samples_written; +} FLAC__OggEncoderAspect; + +void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value); +FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, uint32_t value); +void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect); +FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect); +void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect); + +typedef FLAC__StreamEncoderWriteStatus (*FLAC__OggEncoderAspectWriteCallbackProxy)(const void *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); + +FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data); +#endif diff --git a/vendor/flac/src/libFLAC/include/private/ogg_helper.h b/vendor/flac/src/libFLAC/include/private/ogg_helper.h new file mode 100644 index 0000000..6768578 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/ogg_helper.h @@ -0,0 +1,44 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__OGG_HELPER_H +#define FLAC__PRIVATE__OGG_HELPER_H + +#include +#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoder */ + +void simple_ogg_page__init(ogg_page *page); +void simple_ogg_page__clear(ogg_page *page); +FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data); +FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/ogg_mapping.h b/vendor/flac/src/libFLAC/include/private/ogg_mapping.h new file mode 100644 index 0000000..1a213a4 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/ogg_mapping.h @@ -0,0 +1,64 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__OGG_MAPPING_H +#define FLAC__PRIVATE__OGG_MAPPING_H + +#include "FLAC/ordinals.h" + +/** The length of the packet type field in bytes. */ +#define FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH (1u) + +extern const uint32_t FLAC__OGG_MAPPING_PACKET_TYPE_LEN; /* = 8 bits */ + +extern const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; /* = 0x7f */ + +/** The length of the 'FLAC' magic in bytes. */ +#define FLAC__OGG_MAPPING_MAGIC_LENGTH (4u) + +extern const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC; /* = "FLAC" */ + +extern const uint32_t FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */ +extern const uint32_t FLAC__OGG_MAPPING_VERSION_MINOR_LEN; /* = 8 bits */ + +/** The length of the Ogg FLAC mapping major version number in bytes. */ +#define FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH (1u) + +/** The length of the Ogg FLAC mapping minor version number in bytes. */ +#define FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH (1u) + +extern const uint32_t FLAC__OGG_MAPPING_NUM_HEADERS_LEN; /* = 16 bits */ + +/** The length of the #-of-header-packets number bytes. */ +#define FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH (2u) + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/stream_encoder.h b/vendor/flac/src/libFLAC/include/private/stream_encoder.h new file mode 100644 index 0000000..0a1b672 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/stream_encoder.h @@ -0,0 +1,67 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__STREAM_ENCODER_H +#define FLAC__PRIVATE__STREAM_ENCODER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* + * This is used to avoid overflow with unusual signals in 32-bit + * accumulator in the *precompute_partition_info_sums_* functions. + */ +#define FLAC__MAX_EXTRA_RESIDUAL_BPS 4 + +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +#include "private/cpu.h" +#include "FLAC/format.h" + +#ifdef FLAC__SSE2_SUPPORTED +extern void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); +#endif + +#ifdef FLAC__SSSE3_SUPPORTED +extern void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); +#endif + +#ifdef FLAC__AVX2_SUPPORTED +extern void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); +#endif + +#endif + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/stream_encoder_framing.h b/vendor/flac/src/libFLAC/include/private/stream_encoder_framing.h new file mode 100644 index 0000000..705965a --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/stream_encoder_framing.h @@ -0,0 +1,46 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H +#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H + +#include "FLAC/format.h" +#include "bitwriter.h" + +FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw, FLAC__bool update_vendor_string); +FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, uint32_t samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); + +#endif diff --git a/vendor/flac/src/libFLAC/include/private/window.h b/vendor/flac/src/libFLAC/include/private/window.h new file mode 100644 index 0000000..87a3fdf --- /dev/null +++ b/vendor/flac/src/libFLAC/include/private/window.h @@ -0,0 +1,74 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2006-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PRIVATE__WINDOW_H +#define FLAC__PRIVATE__WINDOW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "private/float.h" +#include "FLAC/format.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +/* + * FLAC__window_*() + * -------------------------------------------------------------------- + * Calculates window coefficients according to different apodization + * functions. + * + * OUT window[0,L-1] + * IN L (number of points in window) + */ +void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */ +void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p); +void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); +void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); +void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L); + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + +#endif diff --git a/vendor/flac/src/libFLAC/include/protected/Makefile.am b/vendor/flac/src/libFLAC/include/protected/Makefile.am new file mode 100644 index 0000000..97e85a8 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/protected/Makefile.am @@ -0,0 +1,35 @@ +# libFLAC - Free Lossless Audio Codec library +# Copyright (C) 2001-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the Xiph.org Foundation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +noinst_HEADERS = \ + all.h \ + stream_decoder.h \ + stream_encoder.h diff --git a/vendor/flac/src/libFLAC/include/protected/all.h b/vendor/flac/src/libFLAC/include/protected/all.h new file mode 100644 index 0000000..9f6de97 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/protected/all.h @@ -0,0 +1,39 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PROTECTED__ALL_H +#define FLAC__PROTECTED__ALL_H + +#include "stream_decoder.h" +#include "stream_encoder.h" + +#endif diff --git a/vendor/flac/src/libFLAC/include/protected/stream_decoder.h b/vendor/flac/src/libFLAC/include/protected/stream_decoder.h new file mode 100644 index 0000000..4a9c768 --- /dev/null +++ b/vendor/flac/src/libFLAC/include/protected/stream_decoder.h @@ -0,0 +1,60 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PROTECTED__STREAM_DECODER_H +#define FLAC__PROTECTED__STREAM_DECODER_H + +#include "FLAC/stream_decoder.h" +#if FLAC__HAS_OGG +#include "private/ogg_decoder_aspect.h" +#endif + +typedef struct FLAC__StreamDecoderProtected { + FLAC__StreamDecoderState state; + FLAC__StreamDecoderInitStatus initstate; + uint32_t channels; + FLAC__ChannelAssignment channel_assignment; + uint32_t bits_per_sample; + uint32_t sample_rate; /* in Hz */ + uint32_t blocksize; /* in samples (per channel) */ + FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */ +#if FLAC__HAS_OGG + FLAC__OggDecoderAspect ogg_decoder_aspect; +#endif +} FLAC__StreamDecoderProtected; + +/* + * Return the number of input bytes consumed + */ +uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder); + +#endif diff --git a/vendor/flac/src/libFLAC/include/protected/stream_encoder.h b/vendor/flac/src/libFLAC/include/protected/stream_encoder.h new file mode 100644 index 0000000..863e43b --- /dev/null +++ b/vendor/flac/src/libFLAC/include/protected/stream_encoder.h @@ -0,0 +1,124 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FLAC__PROTECTED__STREAM_ENCODER_H +#define FLAC__PROTECTED__STREAM_ENCODER_H + +#include "FLAC/stream_encoder.h" +#if FLAC__HAS_OGG +#include "private/ogg_encoder_aspect.h" +#endif + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +#include "private/float.h" + +#define FLAC__MAX_APODIZATION_FUNCTIONS 32 + +typedef enum { + FLAC__APODIZATION_BARTLETT, + FLAC__APODIZATION_BARTLETT_HANN, + FLAC__APODIZATION_BLACKMAN, + FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE, + FLAC__APODIZATION_CONNES, + FLAC__APODIZATION_FLATTOP, + FLAC__APODIZATION_GAUSS, + FLAC__APODIZATION_HAMMING, + FLAC__APODIZATION_HANN, + FLAC__APODIZATION_KAISER_BESSEL, + FLAC__APODIZATION_NUTTALL, + FLAC__APODIZATION_RECTANGLE, + FLAC__APODIZATION_TRIANGLE, + FLAC__APODIZATION_TUKEY, + FLAC__APODIZATION_PARTIAL_TUKEY, + FLAC__APODIZATION_PUNCHOUT_TUKEY, + FLAC__APODIZATION_SUBDIVIDE_TUKEY, + FLAC__APODIZATION_WELCH +} FLAC__ApodizationFunction; + +typedef struct { + FLAC__ApodizationFunction type; + union { + struct { + FLAC__real stddev; + } gauss; + struct { + FLAC__real p; + } tukey; + struct { + FLAC__real p; + FLAC__real start; + FLAC__real end; + } multiple_tukey; + struct { + FLAC__real p; + FLAC__int32 parts; + } subdivide_tukey; + } parameters; +} FLAC__ApodizationSpecification; + +#endif // #ifndef FLAC__INTEGER_ONLY_LIBRARY + +typedef struct FLAC__StreamEncoderProtected { + FLAC__StreamEncoderState state; + FLAC__bool verify; + FLAC__bool streamable_subset; + FLAC__bool do_md5; + FLAC__bool do_mid_side_stereo; + FLAC__bool loose_mid_side_stereo; + uint32_t channels; + uint32_t bits_per_sample; + uint32_t sample_rate; + uint32_t blocksize; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + uint32_t num_apodizations; + FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS]; +#endif + uint32_t max_lpc_order; + uint32_t qlp_coeff_precision; + FLAC__bool do_qlp_coeff_prec_search; + FLAC__bool do_exhaustive_model_search; + FLAC__bool do_escape_coding; + uint32_t min_residual_partition_order; + uint32_t max_residual_partition_order; + uint32_t rice_parameter_search_dist; + FLAC__uint64 total_samples_estimate; + FLAC__bool limit_min_bitrate; + FLAC__StreamMetadata **metadata; + uint32_t num_metadata_blocks; + FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset; +#if FLAC__HAS_OGG + FLAC__OggEncoderAspect ogg_encoder_aspect; +#endif +} FLAC__StreamEncoderProtected; + +#endif diff --git a/vendor/flac/src/libFLAC/libFLAC.m4 b/vendor/flac/src/libFLAC/libFLAC.m4 new file mode 100644 index 0000000..5dfc5ea --- /dev/null +++ b/vendor/flac/src/libFLAC/libFLAC.m4 @@ -0,0 +1,114 @@ +# Configure paths for libFLAC +# "Inspired" by ogg.m4 + +dnl AM_PATH_LIBFLAC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libFLAC, and define LIBFLAC_CFLAGS, LIBFLAC_LIBS, LIBFLAC_LIBDIR +dnl +AC_DEFUN([AM_PATH_LIBFLAC], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(libFLAC,[ --with-libFLAC=PFX Prefix where libFLAC is installed (optional)], libFLAC_prefix="$withval", libFLAC_prefix="") +AC_ARG_WITH(libFLAC-libraries,[ --with-libFLAC-libraries=DIR Directory where libFLAC library is installed (optional)], libFLAC_libraries="$withval", libFLAC_libraries="") +AC_ARG_WITH(libFLAC-includes,[ --with-libFLAC-includes=DIR Directory where libFLAC header files are installed (optional)], libFLAC_includes="$withval", libFLAC_includes="") +AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile and run a test libFLAC program],, enable_libFLACtest=yes) + + if test "x$libFLAC_libraries" != "x" ; then + LIBFLAC_LIBS="-L$libFLAC_libraries" + elif test "x$libFLAC_prefix" = "xno" || test "x$libFLAC_prefix" = "xyes" ; then + LIBFLAC_LIBS="" + elif test "x$libFLAC_prefix" != "x" ; then + LIBFLAC_LIBS="-L$libFLAC_prefix/lib" + elif test "x$prefix" != "xNONE"; then + LIBFLAC_LIBS="-L$prefix/lib" + fi + + if test "x$libFLAC_prefix" != "xno" ; then + LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC $OGG_LIBS -lm" + fi + + if test "x$libFLAC_includes" != "x" ; then + LIBFLAC_CFLAGS="-I$libFLAC_includes" + elif test "x$libFLAC_prefix" != "x" ; then + LIBFLAC_CFLAGS="-I$libFLAC_prefix/include" + elif test "$prefix" != "xNONE"; then + LIBFLAC_CFLAGS="" + fi + + AC_MSG_CHECKING(for libFLAC) + no_libFLAC="" + + + if test "x$enable_libFLACtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_CXXFLAGS="$CXXFLAGS" + ac_save_LIBS="$LIBS" + ac_save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" + CFLAGS="$CFLAGS $LIBFLAC_CFLAGS" + CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS" + LIBS="$LIBS $LIBFLAC_LIBS" + LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH" +dnl +dnl Now check if the installed libFLAC is sufficiently new. +dnl + rm -f conf.libFLACtest + AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +#include +]],[[ + system("touch conf.libFLACtest"); + return 0; +]])],[],[no_libFLAC=yes],[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH" + fi + + if test "x$no_libFLAC" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.libFLACtest ; then + : + else + echo "*** Could not run libFLAC test program, checking why..." + CFLAGS="$CFLAGS $LIBFLAC_CFLAGS" + CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS" + LIBS="$LIBS $LIBFLAC_LIBS" + LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding libFLAC or finding the wrong" + echo "*** version of libFLAC. If it is not finding libFLAC, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means libFLAC was incorrectly installed" + echo "*** or that you have moved libFLAC since it was installed. In the latter case, you" + echo "*** may want to edit the libFLAC-config script: $LIBFLAC_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH" + fi + LIBFLAC_CFLAGS="" + LIBFLAC_LIBDIR="" + LIBFLAC_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(LIBFLAC_CFLAGS) + AC_SUBST(LIBFLAC_LIBDIR) + AC_SUBST(LIBFLAC_LIBS) + rm -f conf.libFLACtest +]) diff --git a/vendor/flac/src/libFLAC/lpc.c b/vendor/flac/src/libFLAC/lpc.c new file mode 100644 index 0000000..bcb8673 --- /dev/null +++ b/vendor/flac/src/libFLAC/lpc.c @@ -0,0 +1,1629 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "share/compat.h" +#include "private/bitmath.h" +#include "private/lpc.h" +#include "private/macros.h" + +#if !defined(NDEBUG) || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE +#include +#endif + +/* OPT: #undef'ing this may improve the speed on some architectures */ +#define FLAC__LPC_UNROLLED_FILTER_LOOPS + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +#if defined(_MSC_VER) && (_MSC_VER < 1800) +#include +static inline long int lround(double x) { + return (long)(x + _copysign(0.5, x)); +} +#elif !defined(HAVE_LROUND) && defined(__GNUC__) +static inline long int lround(double x) { + return (long)(x + __builtin_copysign(0.5, x)); +} +/* If this fails, we are in the presence of a mid 90's compiler, move along... */ +#endif + +void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len) +{ + uint32_t i; + for(i = 0; i < data_len; i++) + out[i] = in[i] * window[i]; +} + +void FLAC__lpc_window_data_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len) +{ + uint32_t i; + for(i = 0; i < data_len; i++) + out[i] = in[i] * window[i]; +} + +void FLAC__lpc_window_data_partial(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift) +{ + uint32_t i, j; + if((part_size + data_shift) < data_len){ + for(i = 0; i < part_size; i++) + out[i] = in[data_shift+i] * window[i]; + i = flac_min(i,data_len - part_size - data_shift); + for(j = data_len - part_size; j < data_len; i++, j++) + out[i] = in[data_shift+i] * window[j]; + if(i < data_len) + out[i] = 0.0f; + } +} + +void FLAC__lpc_window_data_partial_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift) +{ + uint32_t i, j; + if((part_size + data_shift) < data_len){ + for(i = 0; i < part_size; i++) + out[i] = in[data_shift+i] * window[i]; + i = flac_min(i,data_len - part_size - data_shift); + for(j = data_len - part_size; j < data_len; i++, j++) + out[i] = in[data_shift+i] * window[j]; + if(i < data_len) + out[i] = 0.0f; + } +} + +void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ + /* a readable, but slower, version */ +#if 0 + double d; + uint32_t i; + + FLAC__ASSERT(lag > 0); + FLAC__ASSERT(lag <= data_len); + + /* + * Technically we should subtract the mean first like so: + * for(i = 0; i < data_len; i++) + * data[i] -= mean; + * but it appears not to make enough of a difference to matter, and + * most signals are already closely centered around zero + */ + while(lag--) { + for(i = lag, d = 0.0; i < data_len; i++) + d += data[i] * (double)data[i - lag]; + autoc[lag] = d; + } +#endif + if (data_len < FLAC__MAX_LPC_ORDER || lag > 16) { + /* + * this version tends to run faster because of better data locality + * ('data_len' is usually much larger than 'lag') + */ + double d; + uint32_t sample, coeff; + const uint32_t limit = data_len - lag; + + FLAC__ASSERT(lag > 0); + FLAC__ASSERT(lag <= data_len); + + for(coeff = 0; coeff < lag; coeff++) + autoc[coeff] = 0.0; + for(sample = 0; sample <= limit; sample++) { + d = data[sample]; + for(coeff = 0; coeff < lag; coeff++) + autoc[coeff] += d * data[sample+coeff]; + } + for(; sample < data_len; sample++) { + d = data[sample]; + for(coeff = 0; coeff < data_len - sample; coeff++) + autoc[coeff] += d * data[sample+coeff]; + } + } + else if(lag <= 8) { + #undef MAX_LAG + #define MAX_LAG 8 + #include "deduplication/lpc_compute_autocorrelation_intrin.c" + } + else if(lag <= 12) { + #undef MAX_LAG + #define MAX_LAG 12 + #include "deduplication/lpc_compute_autocorrelation_intrin.c" + } + else if(lag <= 16) { + #undef MAX_LAG + #define MAX_LAG 16 + #include "deduplication/lpc_compute_autocorrelation_intrin.c" + } + +} + +void FLAC__lpc_compute_lp_coefficients(const double autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]) +{ + uint32_t i, j; + double r, err, lpc[FLAC__MAX_LPC_ORDER]; + + FLAC__ASSERT(0 != max_order); + FLAC__ASSERT(0 < *max_order); + FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER); + FLAC__ASSERT(autoc[0] != 0.0); + + err = autoc[0]; + + for(i = 0; i < *max_order; i++) { + /* Sum up this iteration's reflection coefficient. */ + r = -autoc[i+1]; + for(j = 0; j < i; j++) + r -= lpc[j] * autoc[i-j]; + r /= err; + + /* Update LPC coefficients and total error. */ + lpc[i]=r; + for(j = 0; j < (i>>1); j++) { + double tmp = lpc[j]; + lpc[j] += r * lpc[i-1-j]; + lpc[i-1-j] += r * tmp; + } + if(i & 1) + lpc[j] += lpc[j] * r; + + err *= (1.0 - r * r); + + /* save this order */ + for(j = 0; j <= i; j++) + lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */ + error[i] = err; + + /* see SF bug https://sourceforge.net/p/flac/bugs/234/ */ + if(err == 0.0) { + *max_order = i+1; + return; + } + } +} + +int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift) +{ + uint32_t i; + double cmax; + FLAC__int32 qmax, qmin; + + FLAC__ASSERT(precision > 0); + FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION); + + /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */ + precision--; + qmax = 1 << precision; + qmin = -qmax; + qmax--; + + /* calc cmax = max( |lp_coeff[i]| ) */ + cmax = 0.0; + for(i = 0; i < order; i++) { + const double d = fabs(lp_coeff[i]); + if(d > cmax) + cmax = d; + } + + if(cmax <= 0.0) { + /* => coefficients are all 0, which means our constant-detect didn't work */ + return 2; + } + else { + const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1; + const int min_shiftlimit = -max_shiftlimit - 1; + int log2cmax; + + (void)frexp(cmax, &log2cmax); + log2cmax--; + *shift = (int)precision - log2cmax - 1; + + if(*shift > max_shiftlimit) + *shift = max_shiftlimit; + else if(*shift < min_shiftlimit) + return 1; + } + + if(*shift >= 0) { + double error = 0.0; + FLAC__int32 q; + for(i = 0; i < order; i++) { + error += lp_coeff[i] * (1 << *shift); + q = lround(error); + +#ifdef FLAC__OVERFLOW_DETECT + if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); + else if(q < qmin) + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q qmax) + q = qmax; + else if(q < qmin) + q = qmin; + error -= q; + qlp_coeff[i] = q; + } + } + /* negative shift is very rare but due to design flaw, negative shift is + * not allowed in the decoder, so it must be handled specially by scaling + * down coeffs + */ + else { + const int nshift = -(*shift); + double error = 0.0; + FLAC__int32 q; +#ifndef NDEBUG + fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax); +#endif + for(i = 0; i < order; i++) { + error += lp_coeff[i] / (1 << nshift); + q = lround(error); +#ifdef FLAC__OVERFLOW_DETECT + if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); + else if(q < qmin) + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q qmax) + q = qmax; + else if(q < qmin) + q = qmin; + error -= q; + qlp_coeff[i] = q; + } + *shift = 0; + } + + return 0; +} + +#if defined(_MSC_VER) +// silence MSVC warnings about __restrict modifier +#pragma warning ( disable : 4028 ) +#endif + +void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) +{ + FLAC__int64 sumo; + uint32_t i, j; + FLAC__int32 sum; + const FLAC__int32 *history; + +#ifdef FLAC__OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i 0); + + for(i = 0; i < data_len; i++) { + sumo = 0; + sum = 0; + history = data; + for(j = 0; j < order; j++) { + sum += qlp_coeff[j] * (*(--history)); + sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); + if(sumo > 2147483647ll || sumo < -2147483648ll) + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); + } + *(residual++) = *(data++) - (sum >> lp_quantization); + } + + /* Here's a slower but clearer version: + for(i = 0; i < data_len; i++) { + sum = 0; + for(j = 0; j < order; j++) + sum += qlp_coeff[j] * data[i-j-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + */ +} +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int32 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } +} +#endif + +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) +{ + uint32_t i, j; + FLAC__int64 sum; + const FLAC__int32 *history; + +#ifdef FLAC__OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i 0); + + for(i = 0; i < data_len; i++) { + sum = 0; + history = data; + for(j = 0; j < order; j++) + sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); + if(FLAC__bitmath_silog2((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) { + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization))); + break; + } + *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization); + } +} +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int64 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + residual[i] = data[i] - ((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; + sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; + sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; + sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; + sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; + sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; + sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; + sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; + sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } +} +#endif + +FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) +{ + int i; + FLAC__int64 sum, residual_to_check; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; /* Falls through. */ + case 12: sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + residual_to_check = data[i] - (sum >> lp_quantization); + /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ + if(residual_to_check <= INT32_MIN || residual_to_check > INT32_MAX) + return false; + else + residual[i] = residual_to_check; + } + return true; +} + +FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(const FLAC__int64 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) +{ + int i; + FLAC__int64 sum, residual_to_check; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; /* Falls through. */ + case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * data[i- 1]; + } + residual_to_check = data[i] - (sum >> lp_quantization); + /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ + if(residual_to_check <= INT32_MIN || residual_to_check > INT32_MAX) + return false; + else + residual[i] = residual_to_check; + } + return true; +} + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + +uint32_t FLAC__lpc_max_prediction_before_shift_bps(uint32_t subframe_bps, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order) +{ + /* This used to be subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) + * but that treats both the samples as well as the predictor as unknown. The + * predictor is known however, so taking the log2 of the sum of the absolute values + * of all coefficients is a more accurate representation of the predictor */ + FLAC__int32 abs_sum_of_qlp_coeff = 0; + uint32_t i; + for(i = 0; i < order; i++) + abs_sum_of_qlp_coeff += abs(qlp_coeff[i]); + if(abs_sum_of_qlp_coeff == 0) + abs_sum_of_qlp_coeff = 1; + return subframe_bps + FLAC__bitmath_silog2(abs_sum_of_qlp_coeff); +} + + +uint32_t FLAC__lpc_max_residual_bps(uint32_t subframe_bps, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization) +{ + FLAC__int32 predictor_sum_bps = FLAC__lpc_max_prediction_before_shift_bps(subframe_bps, qlp_coeff, order) - lp_quantization; + if((int)subframe_bps > predictor_sum_bps) + return subframe_bps + 1; + else + return predictor_sum_bps + 1; +} + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) +/* The attribute below is to silence the undefined sanitizer of oss-fuzz. + * Because fuzzing feeds bogus predictors and residual samples to the + * decoder, having overflows in this section is unavoidable. Also, + * because the calculated values are audio path only, there is no + * potential for security problems */ +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) +{ + FLAC__int64 sumo; + uint32_t i, j; + FLAC__int32 sum; + const FLAC__int32 *r = residual, *history; + +#ifdef FLAC__OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i 0); + + for(i = 0; i < data_len; i++) { + sumo = 0; + sum = 0; + history = data; + for(j = 0; j < order; j++) { + sum += qlp_coeff[j] * (*(--history)); + sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); +#ifdef FLAC__OVERFLOW_DETECT + if(sumo > 2147483647ll || sumo < -2147483648ll) + fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); +#endif + } + *(data++) = *(r++) + (sum >> lp_quantization); + } + + /* Here's a slower but clearer version: + for(i = 0; i < data_len; i++) { + sum = 0; + for(j = 0; j < order; j++) + sum += qlp_coeff[j] * data[i-j-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + */ +} +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int32 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + data[i] = residual[i] + (sum >> lp_quantization); + } + } +} +#endif + +void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) +{ + uint32_t i, j; + FLAC__int64 sum; + const FLAC__int32 *r = residual, *history; + +#ifdef FLAC__OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i 0); + + for(i = 0; i < data_len; i++) { + sum = 0; + history = data; + for(j = 0; j < order; j++) + sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); +#ifdef FLAC__OVERFLOW_DETECT + if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) { + fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization))); + break; + } +#endif + *(data++) = (FLAC__int32)(*(r++) + (sum >> lp_quantization)); + } +} +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int64 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + data[i] = (FLAC__int32)(residual[i] + ((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization)); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; + sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; + sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; + sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; + sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; + sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; + sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; + sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; + sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); + } + } +} +#endif + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) +/* The attribute below is to silence the undefined sanitizer of oss-fuzz. + * Because fuzzing feeds bogus predictors and residual samples to the + * decoder, having overflows in this section is unavoidable. Also, + * because the calculated values are audio path only, there is no + * potential for security problems */ +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +void FLAC__lpc_restore_signal_wide_33bit(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int64 * flac_restrict data) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) +{ + uint32_t i, j; + FLAC__int64 sum; + const FLAC__int32 *r = residual; + const FLAC__int64 *history; + + FLAC__ASSERT(order > 0); + + for(i = 0; i < data_len; i++) { + sum = 0; + history = data; + for(j = 0; j < order; j++) + sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); +#ifdef FLAC__OVERFLOW_DETECT + if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 33) { + fprintf(stderr,"FLAC__lpc_restore_signal_33bit: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization))); + break; + } +#endif + *(data++) = (FLAC__int64)(*(r++)) + (sum >> lp_quantization); + } +} +#else /* unrolled version for normal use */ +{ + int i; + FLAC__int64 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; /* Falls through. */ + case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * data[i- 1]; + } + data[i] = residual[i] + (sum >> lp_quantization); + } +} +#endif + +#if defined(_MSC_VER) +#pragma warning ( default : 4028 ) +#endif + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples) +{ + double error_scale; + + FLAC__ASSERT(total_samples > 0); + + error_scale = 0.5 / (double)total_samples; + + return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale); +} + +double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale) +{ + if(lpc_error > 0.0) { + double bps = (double)0.5 * log(error_scale * lpc_error) / M_LN2; + if(bps >= 0.0) + return bps; + else + return 0.0; + } + else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */ + return 1e32; + } + else { + return 0.0; + } +} + +uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order) +{ + uint32_t order, indx, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */ + double bits, best_bits, error_scale; + + FLAC__ASSERT(max_order > 0); + FLAC__ASSERT(total_samples > 0); + + error_scale = 0.5 / (double)total_samples; + + best_index = 0; + best_bits = (uint32_t)(-1); + + for(indx = 0, order = 1; indx < max_order; indx++, order++) { + bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order); + if(bits < best_bits) { + best_index = indx; + best_bits = bits; + } + } + + return best_index+1; /* +1 since indx of lpc_error[] is order-1 */ +} + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/lpc_intrin_avx2.c b/vendor/flac/src/libFLAC/lpc_intrin_avx2.c new file mode 100644 index 0000000..7f1c03e --- /dev/null +++ b/vendor/flac/src/libFLAC/lpc_intrin_avx2.c @@ -0,0 +1,1122 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/lpc.h" +#ifdef FLAC__AVX2_SUPPORTED + +#include "FLAC/assert.h" +#include "FLAC/format.h" + +#include /* AVX2 */ + +FLAC__SSE_TARGET("avx2") +void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + FLAC__int32 sum; + const __m128i cnt = _mm_cvtsi32_si128(lp_quantization); + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]); + q9 = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]); + q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]); + q11 = _mm256_set1_epi32(0xffff & qlp_coeff[11]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q11, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-12))); + mull = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 11 */ + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]); + q9 = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]); + q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11))); + mull = _mm256_madd_epi16(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 10) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]); + q9 = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); + mull = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 9 */ + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 ))); + mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); + mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 7 */ + __m256i q0, q1, q2, q3, q4, q5, q6; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); + mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 6) { + __m256i q0, q1, q2, q3, q4, q5; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); + mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 5 */ + __m256i q0, q1, q2, q3, q4; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); + mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + __m256i q0, q1, q2, q3; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); + mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 3 */ + __m256i q0, q1, q2; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); + mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 2) { + __m256i q0, q1; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); + mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 1 */ + __m256i q0; + q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ; + summ = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + } + for(; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + _mm256_zeroupper(); +} + +FLAC__SSE_TARGET("avx2") +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + FLAC__int32 sum; + const __m128i cnt = _mm_cvtsi32_si128(lp_quantization); + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(qlp_coeff[8 ]); + q9 = _mm256_set1_epi32(qlp_coeff[9 ]); + q10 = _mm256_set1_epi32(qlp_coeff[10]); + q11 = _mm256_set1_epi32(qlp_coeff[11]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q11, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-12))); + mull = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 11 */ + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(qlp_coeff[8 ]); + q9 = _mm256_set1_epi32(qlp_coeff[9 ]); + q10 = _mm256_set1_epi32(qlp_coeff[10]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11))); + mull = _mm256_mullo_epi32(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 10) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(qlp_coeff[8 ]); + q9 = _mm256_set1_epi32(qlp_coeff[9 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); + mull = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 9 */ + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(qlp_coeff[7 ]); + q8 = _mm256_set1_epi32(qlp_coeff[8 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9))); + mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(qlp_coeff[6 ]); + q7 = _mm256_set1_epi32(qlp_coeff[7 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); + mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 7 */ + __m256i q0, q1, q2, q3, q4, q5, q6; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(qlp_coeff[5 ]); + q6 = _mm256_set1_epi32(qlp_coeff[6 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); + mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 6) { + __m256i q0, q1, q2, q3, q4, q5; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + q5 = _mm256_set1_epi32(qlp_coeff[5 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); + mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 5 */ + __m256i q0, q1, q2, q3, q4; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + q4 = _mm256_set1_epi32(qlp_coeff[4 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); + mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + __m256i q0, q1, q2, q3; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + q3 = _mm256_set1_epi32(qlp_coeff[3 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); + mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 3 */ + __m256i q0, q1, q2; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + q2 = _mm256_set1_epi32(qlp_coeff[2 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); + mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 2) { + __m256i q0, q1; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + q1 = _mm256_set1_epi32(qlp_coeff[1 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ, mull; + summ = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); + mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 1 */ + __m256i q0; + q0 = _mm256_set1_epi32(qlp_coeff[0 ]); + + for(i = 0; i < (int)data_len-7; i+=8) { + __m256i summ; + summ = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); + summ = _mm256_sra_epi32(summ, cnt); + _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ)); + } + } + } + } + for(; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + _mm256_zeroupper(); +} + +static FLAC__int32 pack_arr[8] = { 0, 2, 4, 6, 1, 3, 5, 7 }; + +FLAC__SSE_TARGET("avx2") +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + FLAC__int64 sum; + const __m128i cnt = _mm_cvtsi32_si128(lp_quantization); + const __m256i pack = _mm256_loadu_si256((const __m256i *)(const void*)pack_arr); + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm256_sra_epi64() so we have to use _mm256_srl_epi64() */ + + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ])); + q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ])); + q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ])); + q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ])); + q9 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ])); + q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10])); + q11 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[11])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q11, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-12)))); + mull = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-11)))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q9, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + else { /* order == 11 */ + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ])); + q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ])); + q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ])); + q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ])); + q9 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ])); + q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-11)))); + mull = _mm256_mul_epi32(q9, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + } + else { + if(order == 10) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ])); + q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ])); + q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ])); + q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ])); + q9 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q9, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-10)))); + mull = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + else { /* order == 9 */ + __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ])); + q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ])); + q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ])); + q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 )))); + mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + __m256i q0, q1, q2, q3, q4, q5, q6, q7; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ])); + q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ])); + q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); + mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + else { /* order == 7 */ + __m256i q0, q1, q2, q3, q4, q5, q6; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ])); + q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); + mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + } + else { + if(order == 6) { + __m256i q0, q1, q2, q3, q4, q5; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); + mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + else { /* order == 5 */ + __m256i q0, q1, q2, q3, q4; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); + mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + __m256i q0, q1, q2, q3; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); + mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + else { /* order == 3 */ + __m256i q0, q1, q2; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); + mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + } + else { + if(order == 2) { + __m256i q0, q1; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ, mull; + summ = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); + mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + else { /* order == 1 */ + __m256i q0; + q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ])); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m256i summ; + summ = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); + summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ))); + } + } + } + } + for(; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 12: sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; + sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; + sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; + sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; + sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; + sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; + sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; + sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; + sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + _mm256_zeroupper(); +} + +#endif /* FLAC__AVX2_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/lpc_intrin_fma.c b/vendor/flac/src/libFLAC/lpc_intrin_fma.c new file mode 100644 index 0000000..c0740a8 --- /dev/null +++ b/vendor/flac/src/libFLAC/lpc_intrin_fma.c @@ -0,0 +1,73 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2022-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if defined FLAC__CPU_X86_64 && FLAC__HAS_X86INTRIN +#include "private/lpc.h" +#ifdef FLAC__FMA_SUPPORTED + +#include "FLAC/assert.h" + +FLAC__SSE_TARGET("fma") +void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 8 +#include "deduplication/lpc_compute_autocorrelation_intrin.c" +} + +FLAC__SSE_TARGET("fma") +void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 12 +#include "deduplication/lpc_compute_autocorrelation_intrin.c" +} +FLAC__SSE_TARGET("fma") +void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 16 +#include "deduplication/lpc_compute_autocorrelation_intrin.c" + +} + +#endif /* FLAC__FMA_SUPPORTED */ +#endif /* FLAC__CPU_X86_64 && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/lpc_intrin_neon.c b/vendor/flac/src/libFLAC/lpc_intrin_neon.c new file mode 100644 index 0000000..b9945d5 --- /dev/null +++ b/vendor/flac/src/libFLAC/lpc_intrin_neon.c @@ -0,0 +1,1273 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN +#include "private/lpc.h" +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "private/macros.h" +#include + +#if FLAC__HAS_A64NEONINTRIN +void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 14 +#include "deduplication/lpc_compute_autocorrelation_intrin_neon.c" +} + +void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 10 +#include "deduplication/lpc_compute_autocorrelation_intrin_neon.c" +} + +void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 8 +#include "deduplication/lpc_compute_autocorrelation_intrin_neon.c" +} + +#endif /* ifdef FLAC__HAS_A64NEONINTRIN */ + + +#define MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_vec, lane) \ + summ_0 = vmulq_laneq_s32(tmp_vec[0], qlp_coeff_vec, lane); \ + summ_1 = vmulq_laneq_s32(tmp_vec[4], qlp_coeff_vec, lane); \ + summ_2 = vmulq_laneq_s32(tmp_vec[8], qlp_coeff_vec, lane); + + +#define MACC_32BIT_LOOP_UNROOL_3(tmp_vec_ind, qlp_coeff_vec, lane) \ + summ_0 = vmlaq_laneq_s32(summ_0,tmp_vec[tmp_vec_ind] ,qlp_coeff_vec, lane); \ + summ_1 = vmlaq_laneq_s32(summ_1,tmp_vec[tmp_vec_ind+4] ,qlp_coeff_vec, lane); \ + summ_2 = vmlaq_laneq_s32(summ_2,tmp_vec[tmp_vec_ind+8] ,qlp_coeff_vec, lane); + +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + FLAC__int32 sum; + int32x4_t tmp_vec[20]; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + // Using prologue reads is valid as encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order,....) + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if (order == 12) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], qlp_coeff[10], qlp_coeff[11]}; + + tmp_vec[0] = vld1q_s32(data - 12); + tmp_vec[1] = vld1q_s32(data - 11); + tmp_vec[2] = vld1q_s32(data - 10); + tmp_vec[3] = vld1q_s32(data - 9); + tmp_vec[4] = vld1q_s32(data - 8); + tmp_vec[5] = vld1q_s32(data - 7); + tmp_vec[6] = vld1q_s32(data - 6); + tmp_vec[7] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + + tmp_vec[8] = vld1q_s32(data + i - 4); + tmp_vec[9] = vld1q_s32(data+i-3); + tmp_vec[10] = vld1q_s32(data+i-2); + tmp_vec[11] = vld1q_s32(data+i-1); + tmp_vec[12] = vld1q_s32(data+i); + tmp_vec[13] = vld1q_s32(data+i+1); + tmp_vec[14] = vld1q_s32(data+i+2); + tmp_vec[15] = vld1q_s32(data+i+3); + tmp_vec[16] = vld1q_s32(data + i + 4); + tmp_vec[17] = vld1q_s32(data + i + 5); + tmp_vec[18] = vld1q_s32(data + i + 6); + tmp_vec[19] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 3) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 2) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 1) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_2, 0) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 3) + MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 2) + MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 1) + MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(10, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(11, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + tmp_vec[5] = tmp_vec[17]; + tmp_vec[6] = tmp_vec[18]; + tmp_vec[7] = tmp_vec[19]; + } + } + + else { /* order == 11 */ + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], qlp_coeff[10], 0}; + + tmp_vec[0] = vld1q_s32(data - 11); + tmp_vec[1] = vld1q_s32(data - 10); + tmp_vec[2] = vld1q_s32(data - 9); + tmp_vec[3] = vld1q_s32(data - 8); + tmp_vec[4] = vld1q_s32(data - 7); + tmp_vec[5] = vld1q_s32(data - 6); + tmp_vec[6] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[7] = vld1q_s32(data + i - 4); + tmp_vec[8] = vld1q_s32(data + i - 3); + tmp_vec[9] = vld1q_s32(data + i - 2); + tmp_vec[10] = vld1q_s32(data + i - 1); + tmp_vec[11] = vld1q_s32(data + i - 0); + tmp_vec[12] = vld1q_s32(data + i + 1); + tmp_vec[13] = vld1q_s32(data + i + 2); + tmp_vec[14] = vld1q_s32(data + i + 3); + tmp_vec[15] = vld1q_s32(data + i + 4); + tmp_vec[16] = vld1q_s32(data + i + 5); + tmp_vec[17] = vld1q_s32(data + i + 6); + tmp_vec[18] = vld1q_s32(data + i + 7); + + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 2) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 1) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 0) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 3) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 2) + MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 1) + MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(10, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + tmp_vec[5] = tmp_vec[17]; + tmp_vec[6] = tmp_vec[18]; + } + } + } + else { + if(order == 10) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 10); + tmp_vec[1] = vld1q_s32(data - 9); + tmp_vec[2] = vld1q_s32(data - 8); + tmp_vec[3] = vld1q_s32(data - 7); + tmp_vec[4] = vld1q_s32(data - 6); + tmp_vec[5] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[6] = vld1q_s32(data + i - 4); + tmp_vec[7] = vld1q_s32(data + i - 3); + tmp_vec[8] = vld1q_s32(data + i - 2); + tmp_vec[9] = vld1q_s32(data + i - 1); + tmp_vec[10] = vld1q_s32(data + i - 0); + tmp_vec[11] = vld1q_s32(data + i + 1); + tmp_vec[12] = vld1q_s32(data + i + 2); + tmp_vec[13] = vld1q_s32(data + i + 3); + tmp_vec[14] = vld1q_s32(data + i + 4); + tmp_vec[15] = vld1q_s32(data + i + 5); + tmp_vec[16] = vld1q_s32(data + i + 6); + tmp_vec[17] = vld1q_s32(data + i + 7); + + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 1) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 0) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 3) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 2) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 1) + MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + tmp_vec[5] = tmp_vec[17]; + } + } + else { /* order == 9 */ + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8], 0, 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 9); + tmp_vec[1] = vld1q_s32(data - 8); + tmp_vec[2] = vld1q_s32(data - 7); + tmp_vec[3] = vld1q_s32(data - 6); + tmp_vec[4] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[5] = vld1q_s32(data + i - 4); + tmp_vec[6] = vld1q_s32(data + i - 3); + tmp_vec[7] = vld1q_s32(data + i - 2); + tmp_vec[8] = vld1q_s32(data + i - 1); + tmp_vec[9] = vld1q_s32(data + i - 0); + tmp_vec[10] = vld1q_s32(data + i + 1); + tmp_vec[11] = vld1q_s32(data + i + 2); + tmp_vec[12] = vld1q_s32(data + i + 3); + tmp_vec[13] = vld1q_s32(data + i + 4); + tmp_vec[14] = vld1q_s32(data + i + 5); + tmp_vec[15] = vld1q_s32(data + i + 6); + tmp_vec[16] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 0) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 3) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 2) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 1) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + + tmp_vec[0] = vld1q_s32(data - 8); + tmp_vec[1] = vld1q_s32(data - 7); + tmp_vec[2] = vld1q_s32(data - 6); + tmp_vec[3] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[4] = vld1q_s32(data + i - 4); + tmp_vec[5] = vld1q_s32(data + i - 3); + tmp_vec[6] = vld1q_s32(data + i - 2); + tmp_vec[7] = vld1q_s32(data + i - 1); + tmp_vec[8] = vld1q_s32(data + i - 0); + tmp_vec[9] = vld1q_s32(data + i + 1); + tmp_vec[10] = vld1q_s32(data + i + 2); + tmp_vec[11] = vld1q_s32(data + i + 3); + tmp_vec[12] = vld1q_s32(data + i + 4); + tmp_vec[13] = vld1q_s32(data + i + 5); + tmp_vec[14] = vld1q_s32(data + i + 6); + tmp_vec[15] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 3) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 2) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 1) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + } + } + else { /* order == 7 */ + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], 0}; + + tmp_vec[0] = vld1q_s32(data - 7); + tmp_vec[1] = vld1q_s32(data - 6); + tmp_vec[2] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[3] = vld1q_s32(data + i - 4); + tmp_vec[4] = vld1q_s32(data + i - 3); + tmp_vec[5] = vld1q_s32(data + i - 2); + tmp_vec[6] = vld1q_s32(data + i - 1); + tmp_vec[7] = vld1q_s32(data + i - 0); + tmp_vec[8] = vld1q_s32(data + i + 1); + tmp_vec[9] = vld1q_s32(data + i + 2); + tmp_vec[10] = vld1q_s32(data + i + 3); + tmp_vec[11] = vld1q_s32(data + i + 4); + tmp_vec[12] = vld1q_s32(data + i + 5); + tmp_vec[13] = vld1q_s32(data + i + 6); + tmp_vec[14] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 2) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 1) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + } + } + } + else { + if(order == 6) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 6); + tmp_vec[1] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[2] = vld1q_s32(data + i - 4); + tmp_vec[3] = vld1q_s32(data + i - 3); + tmp_vec[4] = vld1q_s32(data + i - 2); + tmp_vec[5] = vld1q_s32(data + i - 1); + tmp_vec[6] = vld1q_s32(data + i - 0); + tmp_vec[7] = vld1q_s32(data + i + 1); + tmp_vec[8] = vld1q_s32(data + i + 2); + tmp_vec[9] = vld1q_s32(data + i + 3); + tmp_vec[10] = vld1q_s32(data + i + 4); + tmp_vec[11] = vld1q_s32(data + i + 5); + tmp_vec[12] = vld1q_s32(data + i + 6); + tmp_vec[13] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 1) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + } + } + else { /* order == 5 */ + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], 0, 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + + tmp_vec[1] = vld1q_s32(data + i - 4); + tmp_vec[2] = vld1q_s32(data + i - 3); + tmp_vec[3] = vld1q_s32(data + i - 2); + tmp_vec[4] = vld1q_s32(data + i - 1); + tmp_vec[5] = vld1q_s32(data + i - 0); + tmp_vec[6] = vld1q_s32(data + i + 1); + tmp_vec[7] = vld1q_s32(data + i + 2); + tmp_vec[8] = vld1q_s32(data + i + 3); + tmp_vec[9] = vld1q_s32(data + i + 4); + tmp_vec[10] = vld1q_s32(data + i + 5); + tmp_vec[11] = vld1q_s32(data + i + 6); + tmp_vec[12] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 0) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + + tmp_vec[0] = tmp_vec[12]; + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[0] = vld1q_s32(data + i - 4); + tmp_vec[1] = vld1q_s32(data + i - 3); + tmp_vec[2] = vld1q_s32(data + i - 2); + tmp_vec[3] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i - 0); + tmp_vec[5] = vld1q_s32(data + i + 1); + tmp_vec[6] = vld1q_s32(data + i + 2); + tmp_vec[7] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 4); + tmp_vec[9] = vld1q_s32(data + i + 5); + tmp_vec[10] = vld1q_s32(data + i + 6); + tmp_vec[11] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_0, 3) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + } + } + else { /* order == 3 */ + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], 0}; + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[0] = vld1q_s32(data + i - 3); + tmp_vec[1] = vld1q_s32(data + i - 2); + tmp_vec[2] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i + 1); + tmp_vec[5] = vld1q_s32(data + i + 2); + tmp_vec[6] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 5); + tmp_vec[9] = vld1q_s32(data + i + 6); + tmp_vec[10] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_0, 2) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + } + } + } + else { + if(order == 2) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], 0, 0}; + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[0] = vld1q_s32(data + i - 2); + tmp_vec[1] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i + 2); + tmp_vec[5] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 6); + tmp_vec[9] = vld1q_s32(data + i + 7); + + MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_0, 1) + MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 0) + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + } + } + else { /* order == 1 */ + int32x4_t qlp_coeff_0 = vdupq_n_s32(qlp_coeff[0]); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int32x4_t summ_0, summ_1, summ_2; + tmp_vec[0] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 7); + + summ_0 = vmulq_s32(tmp_vec[0], qlp_coeff_0); + summ_1 = vmulq_s32(tmp_vec[4], qlp_coeff_0); + summ_2 = vmulq_s32(tmp_vec[8], qlp_coeff_0); + + vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization)))); + vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization)))); + } + } + } + } + for(; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } +} + + + +#define MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_vec, lane) \ + summ_l_0 = vmull_laneq_s32(vget_low_s32(tmp_vec[0]),qlp_coeff_vec, lane); \ + summ_h_0 = vmull_high_laneq_s32(tmp_vec[0], qlp_coeff_vec, lane);\ + summ_l_1 = vmull_laneq_s32(vget_low_s32(tmp_vec[4]),qlp_coeff_vec, lane); \ + summ_h_1 = vmull_high_laneq_s32(tmp_vec[4], qlp_coeff_vec, lane);\ + summ_l_2 = vmull_laneq_s32(vget_low_s32(tmp_vec[8]),qlp_coeff_vec, lane);\ + summ_h_2 = vmull_high_laneq_s32(tmp_vec[8], qlp_coeff_vec, lane); + + +#define MACC_64_BIT_LOOP_UNROOL_3(tmp_vec_ind, qlp_coeff_vec, lane) \ + summ_l_0 = vmlal_laneq_s32(summ_l_0,vget_low_s32(tmp_vec[tmp_vec_ind]),qlp_coeff_vec, lane); \ + summ_h_0 = vmlal_high_laneq_s32(summ_h_0, tmp_vec[tmp_vec_ind], qlp_coeff_vec, lane); \ + summ_l_1 = vmlal_laneq_s32(summ_l_1, vget_low_s32(tmp_vec[tmp_vec_ind+4]),qlp_coeff_vec, lane); \ + summ_h_1 = vmlal_high_laneq_s32(summ_h_1, tmp_vec[tmp_vec_ind+4], qlp_coeff_vec, lane); \ + summ_l_2 = vmlal_laneq_s32(summ_l_2, vget_low_s32(tmp_vec[tmp_vec_ind+8]),qlp_coeff_vec, lane);\ + summ_h_2 = vmlal_high_laneq_s32(summ_h_2,tmp_vec[tmp_vec_ind+8], qlp_coeff_vec, lane); + +#define SHIFT_SUMS_64BITS_AND_STORE_SUB() \ + res0 = vuzp1q_s32(vreinterpretq_s32_s64(vshlq_s64(summ_l_0,lp_quantization_vec)), vreinterpretq_s32_s64(vshlq_s64(summ_h_0,lp_quantization_vec))); \ + res1 = vuzp1q_s32(vreinterpretq_s32_s64(vshlq_s64(summ_l_1,lp_quantization_vec)), vreinterpretq_s32_s64(vshlq_s64(summ_h_1,lp_quantization_vec))); \ + res2 = vuzp1q_s32(vreinterpretq_s32_s64(vshlq_s64(summ_l_2,lp_quantization_vec)), vreinterpretq_s32_s64(vshlq_s64(summ_h_2,lp_quantization_vec))); \ + vst1q_s32(residual+i+0, vsubq_s32(vld1q_s32(data+i+0), res0));\ + vst1q_s32(residual+i+4, vsubq_s32(vld1q_s32(data+i+4), res1));\ + vst1q_s32(residual+i+8, vsubq_s32(vld1q_s32(data+i+8), res2)); + +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) { + int i; + FLAC__int64 sum; + + int32x4_t tmp_vec[20]; + int32x4_t res0, res1, res2; + int64x2_t lp_quantization_vec = vdupq_n_s64(-lp_quantization); + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + // Using prologue reads is valid as encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order,....) + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4],qlp_coeff[5],qlp_coeff[6],qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8],qlp_coeff[9],qlp_coeff[10],qlp_coeff[11]}; + + tmp_vec[0] = vld1q_s32(data - 12); + tmp_vec[1] = vld1q_s32(data - 11); + tmp_vec[2] = vld1q_s32(data - 10); + tmp_vec[3] = vld1q_s32(data - 9); + tmp_vec[4] = vld1q_s32(data - 8); + tmp_vec[5] = vld1q_s32(data - 7); + tmp_vec[6] = vld1q_s32(data - 6); + tmp_vec[7] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + + tmp_vec[8] = vld1q_s32(data+i-4); + tmp_vec[9] = vld1q_s32(data+i-3); + tmp_vec[10] = vld1q_s32(data+i-2); + tmp_vec[11] = vld1q_s32(data+i-1); + tmp_vec[12] = vld1q_s32(data+i); + tmp_vec[13] = vld1q_s32(data+i+1); + tmp_vec[14] = vld1q_s32(data+i+2); + tmp_vec[15] = vld1q_s32(data+i+3); + tmp_vec[16] = vld1q_s32(data + i + 4); + tmp_vec[17] = vld1q_s32(data + i + 5); + tmp_vec[18] = vld1q_s32(data + i + 6); + tmp_vec[19] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 3) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 2) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 1) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_2, 0) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 3) + MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 2) + MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 1) + MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(10,qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(11,qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + tmp_vec[5] = tmp_vec[17]; + tmp_vec[6] = tmp_vec[18]; + tmp_vec[7] = tmp_vec[19]; + } + } + else { /* order == 11 */ + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4],qlp_coeff[5],qlp_coeff[6],qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8],qlp_coeff[9],qlp_coeff[10],0}; + + tmp_vec[0] = vld1q_s32(data - 11); + tmp_vec[1] = vld1q_s32(data - 10); + tmp_vec[2] = vld1q_s32(data - 9); + tmp_vec[3] = vld1q_s32(data - 8); + tmp_vec[4] = vld1q_s32(data - 7); + tmp_vec[5] = vld1q_s32(data - 6); + tmp_vec[6] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + + tmp_vec[7] = vld1q_s32(data+i-4); + tmp_vec[8] = vld1q_s32(data+i-3); + tmp_vec[9] = vld1q_s32(data+i-2); + tmp_vec[10] = vld1q_s32(data+i-1); + tmp_vec[11] = vld1q_s32(data+i); + tmp_vec[12] = vld1q_s32(data+i+1); + tmp_vec[13] = vld1q_s32(data+i+2); + tmp_vec[14] = vld1q_s32(data+i+3); + tmp_vec[15] = vld1q_s32(data + i + 4); + tmp_vec[16] = vld1q_s32(data + i + 5); + tmp_vec[17] = vld1q_s32(data + i + 6); + tmp_vec[18] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 2) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 1) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 0) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 3) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 2) + MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 1) + MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(10,qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + tmp_vec[5] = tmp_vec[17]; + tmp_vec[6] = tmp_vec[18]; + } + } + } + else + { + if (order == 10) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 10); + tmp_vec[1] = vld1q_s32(data - 9); + tmp_vec[2] = vld1q_s32(data - 8); + tmp_vec[3] = vld1q_s32(data - 7); + tmp_vec[4] = vld1q_s32(data - 6); + tmp_vec[5] = vld1q_s32(data - 5); + + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + + tmp_vec[6] = vld1q_s32(data + i - 4); + tmp_vec[7] = vld1q_s32(data + i - 3); + tmp_vec[8] = vld1q_s32(data + i - 2); + tmp_vec[9] = vld1q_s32(data + i - 1); + tmp_vec[10] = vld1q_s32(data + i - 0); + tmp_vec[11] = vld1q_s32(data + i + 1); + tmp_vec[12] = vld1q_s32(data + i + 2); + tmp_vec[13] = vld1q_s32(data + i + 3); + tmp_vec[14] = vld1q_s32(data + i + 4); + tmp_vec[15] = vld1q_s32(data + i + 5); + tmp_vec[16] = vld1q_s32(data + i + 6); + tmp_vec[17] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 1) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 0) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 3) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 2) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 1) + MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + tmp_vec[5] = tmp_vec[17]; + } + } + + else /* order == 9 */ { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + int32x4_t qlp_coeff_2 = {qlp_coeff[8], 0, 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 9); + tmp_vec[1] = vld1q_s32(data - 8); + tmp_vec[2] = vld1q_s32(data - 7); + tmp_vec[3] = vld1q_s32(data - 6); + tmp_vec[4] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + + tmp_vec[5] = vld1q_s32(data + i - 4); + tmp_vec[6] = vld1q_s32(data + i - 3); + tmp_vec[7] = vld1q_s32(data + i - 2); + tmp_vec[8] = vld1q_s32(data + i - 1); + tmp_vec[9] = vld1q_s32(data + i - 0); + tmp_vec[10] = vld1q_s32(data + i + 1); + tmp_vec[11] = vld1q_s32(data + i + 2); + tmp_vec[12] = vld1q_s32(data + i + 3); + tmp_vec[13] = vld1q_s32(data + i + 4); + tmp_vec[14] = vld1q_s32(data + i + 5); + tmp_vec[15] = vld1q_s32(data + i + 6); + tmp_vec[16] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 0) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 3) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 2) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 1) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + tmp_vec[4] = tmp_vec[16]; + } + } + } + } + else if (order > 4) + { + if (order > 6) + { + if (order == 8) + { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]}; + + tmp_vec[0] = vld1q_s32(data - 8); + tmp_vec[1] = vld1q_s32(data - 7); + tmp_vec[2] = vld1q_s32(data - 6); + tmp_vec[3] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + + tmp_vec[4] = vld1q_s32(data + i - 4); + tmp_vec[5] = vld1q_s32(data + i - 3); + tmp_vec[6] = vld1q_s32(data + i - 2); + tmp_vec[7] = vld1q_s32(data + i - 1); + tmp_vec[8] = vld1q_s32(data + i - 0); + tmp_vec[9] = vld1q_s32(data + i + 1); + tmp_vec[10] = vld1q_s32(data + i + 2); + tmp_vec[11] = vld1q_s32(data + i + 3); + tmp_vec[12] = vld1q_s32(data + i + 4); + tmp_vec[13] = vld1q_s32(data + i + 5); + tmp_vec[14] = vld1q_s32(data + i + 6); + tmp_vec[15] = vld1q_s32(data + i + 7); + + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 3) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 2) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 1) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + tmp_vec[3] = tmp_vec[15]; + } + } + else /* order == 7 */ + { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], 0}; + + tmp_vec[0] = vld1q_s32(data - 7); + tmp_vec[1] = vld1q_s32(data - 6); + tmp_vec[2] = vld1q_s32(data - 5); + + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + tmp_vec[3] = vld1q_s32(data +i - 4); + tmp_vec[4] = vld1q_s32(data + i - 3); + tmp_vec[5] = vld1q_s32(data + i - 2); + tmp_vec[6] = vld1q_s32(data + i - 1); + tmp_vec[7] = vld1q_s32(data + i - 0); + tmp_vec[8] = vld1q_s32(data + i + 1); + tmp_vec[9] = vld1q_s32(data + i + 2); + tmp_vec[10] = vld1q_s32(data + i + 3); + tmp_vec[11] = vld1q_s32(data + i + 4); + tmp_vec[12] = vld1q_s32(data + i + 5); + tmp_vec[13] = vld1q_s32(data + i + 6); + tmp_vec[14] = vld1q_s32(data + i + 7); + + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 2) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 1) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + tmp_vec[2] = tmp_vec[14]; + } + } + } + else + { + if (order == 6) { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 6); + tmp_vec[1] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + + tmp_vec[2] = vld1q_s32(data + i - 4); + tmp_vec[3] = vld1q_s32(data + i - 3); + tmp_vec[4] = vld1q_s32(data + i - 2); + tmp_vec[5] = vld1q_s32(data + i - 1); + tmp_vec[6] = vld1q_s32(data + i - 0); + tmp_vec[7] = vld1q_s32(data + i + 1); + tmp_vec[8] = vld1q_s32(data + i + 2); + tmp_vec[9] = vld1q_s32(data + i + 3); + tmp_vec[10] = vld1q_s32(data + i + 4); + tmp_vec[11] = vld1q_s32(data + i + 5); + tmp_vec[12] = vld1q_s32(data + i + 6); + tmp_vec[13] = vld1q_s32(data + i + 7); + + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 1) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + tmp_vec[1] = tmp_vec[13]; + } + } + + else + { /* order == 5 */ + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + int32x4_t qlp_coeff_1 = {qlp_coeff[4], 0, 0, 0}; + + tmp_vec[0] = vld1q_s32(data - 5); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + tmp_vec[1] = vld1q_s32(data + i - 4); + tmp_vec[2] = vld1q_s32(data + i - 3); + tmp_vec[3] = vld1q_s32(data + i - 2); + tmp_vec[4] = vld1q_s32(data + i - 1); + tmp_vec[5] = vld1q_s32(data + i - 0); + tmp_vec[6] = vld1q_s32(data + i + 1); + tmp_vec[7] = vld1q_s32(data + i + 2); + tmp_vec[8] = vld1q_s32(data + i + 3); + tmp_vec[9] = vld1q_s32(data + i + 4); + tmp_vec[10] = vld1q_s32(data + i + 5); + tmp_vec[11] = vld1q_s32(data + i + 6); + tmp_vec[12] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 0) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + + tmp_vec[0] = tmp_vec[12]; + } + } + } + } + else + { + if (order > 2) + { + if (order == 4) + { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]}; + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + tmp_vec[0] = vld1q_s32(data + i - 4); + tmp_vec[1] = vld1q_s32(data + i - 3); + tmp_vec[2] = vld1q_s32(data + i - 2); + tmp_vec[3] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i - 0); + tmp_vec[5] = vld1q_s32(data + i + 1); + tmp_vec[6] = vld1q_s32(data + i + 2); + tmp_vec[7] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 4); + tmp_vec[9] = vld1q_s32(data + i + 5); + tmp_vec[10] = vld1q_s32(data + i + 6); + tmp_vec[11] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_0, 3) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + } + } + else + { /* order == 3 */ + + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], 0}; + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + tmp_vec[0] = vld1q_s32(data + i - 3); + tmp_vec[1] = vld1q_s32(data + i - 2); + tmp_vec[2] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i + 1); + tmp_vec[5] = vld1q_s32(data + i + 2); + tmp_vec[6] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 5); + tmp_vec[9] = vld1q_s32(data + i + 6); + tmp_vec[10] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_0, 2) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + } + } + } + else + { + if (order == 2) + { + int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], 0, 0}; + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + tmp_vec[0] = vld1q_s32(data + i - 2); + tmp_vec[1] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i + 2); + tmp_vec[5] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 6); + tmp_vec[9] = vld1q_s32(data + i + 7); + + MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_0, 1) + MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 0) + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + } + } + + else + { /* order == 1 */ + + int32x2_t qlp_coeff_0_2 = vdup_n_s32(qlp_coeff[0]); + int32x4_t qlp_coeff_0_4 = vdupq_n_s32(qlp_coeff[0]); + + for (i = 0; i < (int)data_len - 11; i += 12) + { + int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2; + tmp_vec[0] = vld1q_s32(data + i - 1); + tmp_vec[4] = vld1q_s32(data + i + 3); + tmp_vec[8] = vld1q_s32(data + i + 7); + + summ_l_0 = vmull_s32(vget_low_s32(tmp_vec[0]), qlp_coeff_0_2); + summ_h_0 = vmull_high_s32(tmp_vec[0], qlp_coeff_0_4); + + summ_l_1 = vmull_s32(vget_low_s32(tmp_vec[4]), qlp_coeff_0_2); + summ_h_1 = vmull_high_s32(tmp_vec[4], qlp_coeff_0_4); + + summ_l_2 = vmull_s32(vget_low_s32(tmp_vec[8]), qlp_coeff_0_2); + summ_h_2 = vmull_high_s32(tmp_vec[8], qlp_coeff_0_4); + + SHIFT_SUMS_64BITS_AND_STORE_SUB() + } + } + } + } + for (; i < (int)data_len; i++) + { + sum = 0; + switch (order) + { + case 12: + sum += qlp_coeff[11] * (FLAC__int64)data[i - 12]; /* Falls through. */ + case 11: + sum += qlp_coeff[10] * (FLAC__int64)data[i - 11]; /* Falls through. */ + case 10: + sum += qlp_coeff[9] * (FLAC__int64)data[i - 10]; /* Falls through. */ + case 9: + sum += qlp_coeff[8] * (FLAC__int64)data[i - 9]; /* Falls through. */ + case 8: + sum += qlp_coeff[7] * (FLAC__int64)data[i - 8]; /* Falls through. */ + case 7: + sum += qlp_coeff[6] * (FLAC__int64)data[i - 7]; /* Falls through. */ + case 6: + sum += qlp_coeff[5] * (FLAC__int64)data[i - 6]; /* Falls through. */ + case 5: + sum += qlp_coeff[4] * (FLAC__int64)data[i - 5]; /* Falls through. */ + case 4: + sum += qlp_coeff[3] * (FLAC__int64)data[i - 4]; /* Falls through. */ + case 3: + sum += qlp_coeff[2] * (FLAC__int64)data[i - 3]; /* Falls through. */ + case 2: + sum += qlp_coeff[1] * (FLAC__int64)data[i - 2]; /* Falls through. */ + case 1: + sum += qlp_coeff[0] * (FLAC__int64)data[i - 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else + { /* order > 12 */ + for (i = 0; i < (int)data_len; i++) + { + sum = 0; + switch (order) + { + case 32: + sum += qlp_coeff[31] * (FLAC__int64)data[i - 32]; /* Falls through. */ + case 31: + sum += qlp_coeff[30] * (FLAC__int64)data[i - 31]; /* Falls through. */ + case 30: + sum += qlp_coeff[29] * (FLAC__int64)data[i - 30]; /* Falls through. */ + case 29: + sum += qlp_coeff[28] * (FLAC__int64)data[i - 29]; /* Falls through. */ + case 28: + sum += qlp_coeff[27] * (FLAC__int64)data[i - 28]; /* Falls through. */ + case 27: + sum += qlp_coeff[26] * (FLAC__int64)data[i - 27]; /* Falls through. */ + case 26: + sum += qlp_coeff[25] * (FLAC__int64)data[i - 26]; /* Falls through. */ + case 25: + sum += qlp_coeff[24] * (FLAC__int64)data[i - 25]; /* Falls through. */ + case 24: + sum += qlp_coeff[23] * (FLAC__int64)data[i - 24]; /* Falls through. */ + case 23: + sum += qlp_coeff[22] * (FLAC__int64)data[i - 23]; /* Falls through. */ + case 22: + sum += qlp_coeff[21] * (FLAC__int64)data[i - 22]; /* Falls through. */ + case 21: + sum += qlp_coeff[20] * (FLAC__int64)data[i - 21]; /* Falls through. */ + case 20: + sum += qlp_coeff[19] * (FLAC__int64)data[i - 20]; /* Falls through. */ + case 19: + sum += qlp_coeff[18] * (FLAC__int64)data[i - 19]; /* Falls through. */ + case 18: + sum += qlp_coeff[17] * (FLAC__int64)data[i - 18]; /* Falls through. */ + case 17: + sum += qlp_coeff[16] * (FLAC__int64)data[i - 17]; /* Falls through. */ + case 16: + sum += qlp_coeff[15] * (FLAC__int64)data[i - 16]; /* Falls through. */ + case 15: + sum += qlp_coeff[14] * (FLAC__int64)data[i - 15]; /* Falls through. */ + case 14: + sum += qlp_coeff[13] * (FLAC__int64)data[i - 14]; /* Falls through. */ + case 13: + sum += qlp_coeff[12] * (FLAC__int64)data[i - 13]; + sum += qlp_coeff[11] * (FLAC__int64)data[i - 12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i - 11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i - 10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i - 9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i - 8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i - 7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i - 6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i - 5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i - 4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i - 3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i - 2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i - 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + + return; +} + +#endif /* FLAC__CPU_ARM64 && FLAC__HAS_ARCH64INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/lpc_intrin_sse2.c b/vendor/flac/src/libFLAC/lpc_intrin_sse2.c new file mode 100644 index 0000000..d16a085 --- /dev/null +++ b/vendor/flac/src/libFLAC/lpc_intrin_sse2.c @@ -0,0 +1,966 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/lpc.h" +#ifdef FLAC__SSE2_SUPPORTED + +#include "FLAC/assert.h" +#include "FLAC/format.h" + +#include /* SSE2 */ + +#define RESIDUAL32_RESULT(xmmN) residual[i] = data[i] - (_mm_cvtsi128_si32(xmmN) >> lp_quantization); +#define DATA32_RESULT(xmmN) data[i] = residual[i] + (_mm_cvtsi128_si32(xmmN) >> lp_quantization); + + +FLAC__SSE_TARGET("sse2") +void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 8 +#include "deduplication/lpc_compute_autocorrelation_intrin_sse2.c" +} + +FLAC__SSE_TARGET("sse2") +void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 10 +#include "deduplication/lpc_compute_autocorrelation_intrin_sse2.c" +} + + +FLAC__SSE_TARGET("sse2") +void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) +{ +#undef MAX_LAG +#define MAX_LAG 14 +#include "deduplication/lpc_compute_autocorrelation_intrin_sse2.c" +} + +FLAC__SSE_TARGET("sse2") +void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + FLAC__int32 sum; + const __m128i cnt = _mm_cvtsi32_si128(lp_quantization); + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0)); + q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0)); + q11 = _mm_cvtsi32_si128(0xffff & qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q11, _mm_loadu_si128((const __m128i*)(const void*)(data+i-12))); + mull = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 11 */ + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0)); + q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11))); + mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 10) { + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); + mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 9 */ + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); + mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + __m128i q0, q1, q2, q3, q4, q5, q6, q7; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); + mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 7 */ + __m128i q0, q1, q2, q3, q4, q5, q6; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); + mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 6) { + __m128i q0, q1, q2, q3, q4, q5; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); + mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 5 */ + __m128i q0, q1, q2, q3, q4; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); + mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + __m128i q0, q1, q2, q3; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); + mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 3 */ + __m128i q0, q1, q2; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); + mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 2) { + __m128i q0, q1; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); + mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 1 */ + __m128i q0; + q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ; + summ = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + } + for(; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } +} + +#if defined FLAC__CPU_IA32 /* unused for x86_64 */ + +FLAC__SSE_TARGET("sse2") +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + if(order <= 12) { + if(order > 8) { /* order == 9, 10, 11, 12 */ + if(order > 10) { /* order == 11, 12 */ + if(order == 12) { + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); // 0 0 q[1] q[0] + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); // 0 0 q[3] q[2] + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); // 0 0 q[5] q[4] + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); // 0 0 q[7] q[6] + xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); // 0 0 q[9] q[8] + xmm5 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+10)); // 0 0 q[11] q[10] + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0 q[1] 0 q[0] + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0 q[3] 0 q[2] + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0 q[5] 0 q[4] + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0 q[7] 0 q[6] + xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0 q[9] 0 q[8] + xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0 q[11] 0 q[10] + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[11] * data[i-12]; + //sum += qlp_coeff[10] * data[i-11]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-12)); // 0 0 d[i-11] d[i-12] + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0 d[i-12] 0 d[i-11] + xmm7 = _mm_mul_epu32(xmm7, xmm5); /* we use _unsigned_ multiplication and discard high dword of the result values */ + + //sum += qlp_coeff[9] * data[i-10]; + //sum += qlp_coeff[8] * data[i-9]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm4); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[7] * data[i-8]; + //sum += qlp_coeff[6] * data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm3); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[5] * data[i-6]; + //sum += qlp_coeff[4] * data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm2); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + else { /* order == 11 */ + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); + xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[10] * data[i-11]; + xmm7 = _mm_cvtsi32_si128(data[i-11]); + xmm7 = _mm_mul_epu32(xmm7, xmm5); + + //sum += qlp_coeff[9] * data[i-10]; + //sum += qlp_coeff[8] * data[i-9]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm4); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[7] * data[i-8]; + //sum += qlp_coeff[6] * data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm3); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[5] * data[i-6]; + //sum += qlp_coeff[4] * data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm2); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + } + else { /* order == 9, 10 */ + if(order == 10) { + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[9] * data[i-10]; + //sum += qlp_coeff[8] * data[i-9]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epu32(xmm7, xmm4); + + //sum += qlp_coeff[7] * data[i-8]; + //sum += qlp_coeff[6] * data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm3); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[5] * data[i-6]; + //sum += qlp_coeff[4] * data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm2); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + else { /* order == 9 */ + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[8] * data[i-9]; + xmm7 = _mm_cvtsi32_si128(data[i-9]); + xmm7 = _mm_mul_epu32(xmm7, xmm4); + + //sum += qlp_coeff[7] * data[i-8]; + //sum += qlp_coeff[6] * data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm3); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[5] * data[i-6]; + //sum += qlp_coeff[4] * data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm2); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + } + } + else if(order > 4) { /* order == 5, 6, 7, 8 */ + if(order > 6) { /* order == 7, 8 */ + if(order == 8) { + __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[7] * data[i-8]; + //sum += qlp_coeff[6] * data[i-7]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epu32(xmm7, xmm3); + + //sum += qlp_coeff[5] * data[i-6]; + //sum += qlp_coeff[4] * data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm2); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + else { /* order == 7 */ + __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[6] * data[i-7]; + xmm7 = _mm_cvtsi32_si128(data[i-7]); + xmm7 = _mm_mul_epu32(xmm7, xmm3); + + //sum += qlp_coeff[5] * data[i-6]; + //sum += qlp_coeff[4] * data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm2); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + } + else { /* order == 5, 6 */ + if(order == 6) { + __m128i xmm0, xmm1, xmm2, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[5] * data[i-6]; + //sum += qlp_coeff[4] * data[i-5]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epu32(xmm7, xmm2); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + else { /* order == 5 */ + __m128i xmm0, xmm1, xmm2, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[4] * data[i-5]; + xmm7 = _mm_cvtsi32_si128(data[i-5]); + xmm7 = _mm_mul_epu32(xmm7, xmm2); + + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm1); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + } + } + else { /* order == 1, 2, 3, 4 */ + if(order > 2) { /* order == 3, 4 */ + if(order == 4) { + __m128i xmm0, xmm1, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[3] * data[i-4]; + //sum += qlp_coeff[2] * data[i-3]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epu32(xmm7, xmm1); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + else { /* order == 3 */ + __m128i xmm0, xmm1, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[2] * data[i-3]; + xmm7 = _mm_cvtsi32_si128(data[i-3]); + xmm7 = _mm_mul_epu32(xmm7, xmm1); + + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epu32(xmm6, xmm0); + xmm7 = _mm_add_epi32(xmm7, xmm6); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + } + else { /* order == 1, 2 */ + if(order == 2) { + __m128i xmm0, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[1] * data[i-2]; + //sum += qlp_coeff[0] * data[i-1]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epu32(xmm7, xmm0); + + xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL32_RESULT(xmm7); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + FLAC__int32 sum; + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } +} + +#endif /* FLAC__CPU_IA32 */ +#endif /* FLAC__SSE2_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/lpc_intrin_sse41.c b/vendor/flac/src/libFLAC/lpc_intrin_sse41.c new file mode 100644 index 0000000..756c5dd --- /dev/null +++ b/vendor/flac/src/libFLAC/lpc_intrin_sse41.c @@ -0,0 +1,950 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/lpc.h" +#ifdef FLAC__SSE4_1_SUPPORTED + +#include "FLAC/assert.h" +#include "FLAC/format.h" + +#include /* SSE4.1 */ + +#if defined FLAC__CPU_IA32 /* unused for x64 */ + +#define RESIDUAL64_RESULT(xmmN) residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srl_epi64(xmmN, cnt)) +#define RESIDUAL64_RESULT1(xmmN) residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srli_epi64(xmmN, lp_quantization)) + +FLAC__SSE_TARGET("sse4.1") +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + const __m128i cnt = _mm_cvtsi32_si128(lp_quantization); + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm_sra_epi64() so we have to use _mm_srl_epi64() */ + + if(order <= 12) { + if(order > 8) { /* order == 9, 10, 11, 12 */ + if(order > 10) { /* order == 11, 12 */ + if(order == 12) { + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); // 0 0 q[1] q[0] + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); // 0 0 q[3] q[2] + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); // 0 0 q[5] q[4] + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); // 0 0 q[7] q[6] + xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); // 0 0 q[9] q[8] + xmm5 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+10)); // 0 0 q[11] q[10] + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0 q[1] 0 q[0] + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0 q[3] 0 q[2] + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0 q[5] 0 q[4] + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0 q[7] 0 q[6] + xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0 q[9] 0 q[8] + xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0 q[11] 0 q[10] + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + //sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-12)); // 0 0 d[i-11] d[i-12] + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0 d[i-12] 0 d[i-11] + xmm7 = _mm_mul_epi32(xmm7, xmm5); + + //sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + //sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm4); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + //sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm3); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + //sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm2); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT1(xmm7); + } + } + else { /* order == 11 */ + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); + xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[10] * (FLAC__int64)data[i-11]; + xmm7 = _mm_cvtsi32_si128(data[i-11]); + xmm7 = _mm_mul_epi32(xmm7, xmm5); + + //sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + //sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm4); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + //sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm3); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + //sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm2); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT1(xmm7); + } + } + } + else { /* order == 9, 10 */ + if(order == 10) { + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + //sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epi32(xmm7, xmm4); + + //sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + //sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm3); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + //sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm2); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + else { /* order == 9 */ + __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[8] * (FLAC__int64)data[i-9]; + xmm7 = _mm_cvtsi32_si128(data[i-9]); + xmm7 = _mm_mul_epi32(xmm7, xmm4); + + //sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + //sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm3); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + //sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm2); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + } + } + else if(order > 4) { /* order == 5, 6, 7, 8 */ + if(order > 6) { /* order == 7, 8 */ + if(order == 8) { + __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + //sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epi32(xmm7, xmm3); + + //sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + //sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm2); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + else { /* order == 7 */ + __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[6] * (FLAC__int64)data[i-7]; + xmm7 = _mm_cvtsi32_si128(data[i-7]); + xmm7 = _mm_mul_epi32(xmm7, xmm3); + + //sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + //sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm2); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + } + else { /* order == 5, 6 */ + if(order == 6) { + __m128i xmm0, xmm1, xmm2, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + //sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epi32(xmm7, xmm2); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + else { /* order == 5 */ + __m128i xmm0, xmm1, xmm2, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[4] * (FLAC__int64)data[i-5]; + xmm7 = _mm_cvtsi32_si128(data[i-5]); + xmm7 = _mm_mul_epi32(xmm7, xmm2); + + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm1); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + } + } + else { /* order == 1, 2, 3, 4 */ + if(order > 2) { /* order == 3, 4 */ + if(order == 4) { + __m128i xmm0, xmm1, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + //sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epi32(xmm7, xmm1); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + else { /* order == 3 */ + __m128i xmm0, xmm1, xmm6, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]); + + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum = qlp_coeff[2] * (FLAC__int64)data[i-3]; + xmm7 = _mm_cvtsi32_si128(data[i-3]); + xmm7 = _mm_mul_epi32(xmm7, xmm1); + + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1)); + xmm6 = _mm_mul_epi32(xmm6, xmm0); + xmm7 = _mm_add_epi64(xmm7, xmm6); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + } + else { /* order == 1, 2 */ + if(order == 2) { + __m128i xmm0, xmm7; + xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); + xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); + + for(i = 0; i < (int)data_len; i++) { + //sum = 0; + //sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + //sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2)); + xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); + xmm7 = _mm_mul_epi32(xmm7, xmm0); + + xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8)); + RESIDUAL64_RESULT(xmm7); + } + } + else { /* order == 1 */ + __m128i xmm0, xmm7; + xmm0 = _mm_cvtsi32_si128(qlp_coeff[0]); + + for(i = 0; i < (int)data_len; i++) { + //sum = qlp_coeff[0] * (FLAC__int64)data[i-1]; + xmm7 = _mm_cvtsi32_si128(data[i-1]); + xmm7 = _mm_mul_epi32(xmm7, xmm0); + RESIDUAL64_RESULT(xmm7); + } + } + } + } + } + else { /* order > 12 */ + FLAC__int64 sum; + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; + sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; + sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; + sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; + sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; + sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; + sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; + sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; + sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } +} + +#endif /* defined FLAC__CPU_IA32 */ + +FLAC__SSE_TARGET("sse4.1") +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) +{ + int i; + FLAC__int32 sum; + const __m128i cnt = _mm_cvtsi32_si128(lp_quantization); + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0)); + q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0)); + q11 = _mm_cvtsi32_si128(qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q11, _mm_loadu_si128((const __m128i*)(const void*)(data+i-12))); + mull = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 11 */ + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0)); + q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11))); + mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 10) { + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); + mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 9 */ + __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); + mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + __m128i q0, q1, q2, q3, q4, q5, q6, q7; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); + mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 7 */ + __m128i q0, q1, q2, q3, q4, q5, q6; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); + mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 6) { + __m128i q0, q1, q2, q3, q4, q5; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); + mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 5 */ + __m128i q0, q1, q2, q3, q4; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); + mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + __m128i q0, q1, q2, q3; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); + mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 3 */ + __m128i q0, q1, q2; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); + mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + else { + if(order == 2) { + __m128i q0, q1; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ, mull; + summ = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); + mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + else { /* order == 1 */ + __m128i q0; + q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0)); + + for(i = 0; i < (int)data_len-3; i+=4) { + __m128i summ; + summ = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); + summ = _mm_sra_epi32(summ, cnt); + _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ)); + } + } + } + } + for(; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ + case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ + case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ + case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ + case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ + case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ + case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ + case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ + case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ + case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ + case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ + case 1: sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ + case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ + case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ + case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ + case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ + case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ + case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ + case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ + case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ + case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ + case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ + case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ + case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ + case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ + case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ + case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ + case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ + case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ + case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } +} + +#endif /* FLAC__SSE4_1_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/libFLAC/md5.c b/vendor/flac/src/libFLAC/md5.c new file mode 100644 index 0000000..09933d7 --- /dev/null +++ b/vendor/flac/src/libFLAC/md5.c @@ -0,0 +1,517 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include /* for malloc() */ +#include /* for memcpy() */ + +#include "private/md5.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "share/endswap.h" + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + * + * Josh Coalson: made some changes to integrate with libFLAC. + * Still in the public domain. + */ + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]) +{ + register FLAC__uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#if WORDS_BIGENDIAN +//@@@@@@ OPT: use bswap/intrinsics +static void byteSwap(FLAC__uint32 *buf, uint32_t words) +{ + register FLAC__uint32 x; + do { + x = *buf; + x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); + *buf++ = (x >> 16) | (x << 16); + } while (--words); +} +static void byteSwapX16(FLAC__uint32 *buf) +{ + register FLAC__uint32 x; + + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf = (x >> 16) | (x << 16); +} +#else +#define byteSwap(buf, words) +#define byteSwapX16(buf) +#endif + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, uint32_t len) +{ + FLAC__uint32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t); + byteSwapX16(ctx->in); + FLAC__MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwapX16(ctx->in); + FLAC__MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void FLAC__MD5Init(FLAC__MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; + + ctx->internal_buf.p8 = 0; + ctx->capacity = 0; +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + FLAC__byte *p = (FLAC__byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwapX16(ctx->in); + FLAC__MD5Transform(ctx->buf, ctx->in); + p = (FLAC__byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + FLAC__MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + if (0 != ctx->internal_buf.p8) { + free(ctx->internal_buf.p8); + ctx->internal_buf.p8 = 0; + ctx->capacity = 0; + } + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +/* + * Convert the incoming audio signal to a byte stream + */ +static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample) +{ + FLAC__byte *buf_ = mbuf->p8; + FLAC__int16 *buf16 = mbuf->p16; + FLAC__int32 *buf32 = mbuf->p32; + FLAC__int32 a_word; + uint32_t channel, sample; + + /* Storage in the output buffer, buf, is little endian. */ + +#define BYTES_CHANNEL_SELECTOR(bytes, channels) (bytes * 100 + channels) + + /* First do the most commonly used combinations. */ + switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) { + /* One byte per sample. */ + case (BYTES_CHANNEL_SELECTOR (1, 1)): + for (sample = 0; sample < samples; sample++) + *buf_++ = signal[0][sample]; + return; + + case (BYTES_CHANNEL_SELECTOR (1, 2)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + } + return; + + case (BYTES_CHANNEL_SELECTOR (1, 4)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + *buf_++ = signal[2][sample]; + *buf_++ = signal[3][sample]; + } + return; + + case (BYTES_CHANNEL_SELECTOR (1, 6)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + *buf_++ = signal[2][sample]; + *buf_++ = signal[3][sample]; + *buf_++ = signal[4][sample]; + *buf_++ = signal[5][sample]; + } + return; + + case (BYTES_CHANNEL_SELECTOR (1, 8)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + *buf_++ = signal[2][sample]; + *buf_++ = signal[3][sample]; + *buf_++ = signal[4][sample]; + *buf_++ = signal[5][sample]; + *buf_++ = signal[6][sample]; + *buf_++ = signal[7][sample]; + } + return; + + /* Two bytes per sample. */ + case (BYTES_CHANNEL_SELECTOR (2, 1)): + for (sample = 0; sample < samples; sample++) + *buf16++ = H2LE_16(signal[0][sample]); + return; + + case (BYTES_CHANNEL_SELECTOR (2, 2)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (2, 4)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + *buf16++ = H2LE_16(signal[2][sample]); + *buf16++ = H2LE_16(signal[3][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (2, 6)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + *buf16++ = H2LE_16(signal[2][sample]); + *buf16++ = H2LE_16(signal[3][sample]); + *buf16++ = H2LE_16(signal[4][sample]); + *buf16++ = H2LE_16(signal[5][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (2, 8)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + *buf16++ = H2LE_16(signal[2][sample]); + *buf16++ = H2LE_16(signal[3][sample]); + *buf16++ = H2LE_16(signal[4][sample]); + *buf16++ = H2LE_16(signal[5][sample]); + *buf16++ = H2LE_16(signal[6][sample]); + *buf16++ = H2LE_16(signal[7][sample]); + } + return; + + /* Three bytes per sample. */ + case (BYTES_CHANNEL_SELECTOR (3, 1)): + for (sample = 0; sample < samples; sample++) { + a_word = signal[0][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + } + return; + + case (BYTES_CHANNEL_SELECTOR (3, 2)): + for (sample = 0; sample < samples; sample++) { + a_word = signal[0][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + a_word = signal[1][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + } + return; + + /* Four bytes per sample. */ + case (BYTES_CHANNEL_SELECTOR (4, 1)): + for (sample = 0; sample < samples; sample++) + *buf32++ = H2LE_32(signal[0][sample]); + return; + + case (BYTES_CHANNEL_SELECTOR (4, 2)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (4, 4)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + *buf32++ = H2LE_32(signal[2][sample]); + *buf32++ = H2LE_32(signal[3][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (4, 6)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + *buf32++ = H2LE_32(signal[2][sample]); + *buf32++ = H2LE_32(signal[3][sample]); + *buf32++ = H2LE_32(signal[4][sample]); + *buf32++ = H2LE_32(signal[5][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (4, 8)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + *buf32++ = H2LE_32(signal[2][sample]); + *buf32++ = H2LE_32(signal[3][sample]); + *buf32++ = H2LE_32(signal[4][sample]); + *buf32++ = H2LE_32(signal[5][sample]); + *buf32++ = H2LE_32(signal[6][sample]); + *buf32++ = H2LE_32(signal[7][sample]); + } + return; + + default: + break; + } + + /* General version. */ + switch (bytes_per_sample) { + case 1: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) + *buf_++ = signal[channel][sample]; + return; + + case 2: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) + *buf16++ = H2LE_16(signal[channel][sample]); + return; + + case 3: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) { + a_word = signal[channel][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + } + return; + + case 4: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) + *buf32++ = H2LE_32(signal[channel][sample]); + return; + + default: + break; + } +} + +/* + * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it. + */ +FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample) +{ + const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample; + + /* overflow check */ + if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample) + return false; + if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples) + return false; + + if (ctx->capacity < bytes_needed) { + if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) { + if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) { + ctx->capacity = 0; + return false; + } + } + ctx->capacity = bytes_needed; + } + + format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample); + + FLAC__MD5Update(ctx, ctx->internal_buf.p8, bytes_needed); + + return true; +} diff --git a/vendor/flac/src/libFLAC/memory.c b/vendor/flac/src/libFLAC/memory.c new file mode 100644 index 0000000..ad5371e --- /dev/null +++ b/vendor/flac/src/libFLAC/memory.c @@ -0,0 +1,219 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#include "private/memory.h" +#include "FLAC/assert.h" +#include "share/compat.h" +#include "share/alloc.h" + +void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) +{ + void *x; + + FLAC__ASSERT(0 != aligned_address); + +#ifdef FLAC__ALIGN_MALLOC_DATA + /* align on 32-byte (256-bit) boundary */ + x = safe_malloc_add_2op_(bytes, /*+*/31L); + *aligned_address = (void*)(((uintptr_t)x + 31L) & -32L); +#else + x = safe_malloc_(bytes); + *aligned_address = x; +#endif + return x; +} + +FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer) +{ + FLAC__int32 *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__int32 *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; + + FLAC__ASSERT(elements > 0); + FLAC__ASSERT(0 != unaligned_pointer); + FLAC__ASSERT(0 != aligned_pointer); + FLAC__ASSERT(unaligned_pointer != aligned_pointer); + + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer) +{ + FLAC__uint32 *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__uint32 *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; + + FLAC__ASSERT(elements > 0); + FLAC__ASSERT(0 != unaligned_pointer); + FLAC__ASSERT(0 != aligned_pointer); + FLAC__ASSERT(unaligned_pointer != aligned_pointer); + + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +FLAC__bool FLAC__memory_alloc_aligned_int64_array(size_t elements, FLAC__int64 **unaligned_pointer, FLAC__int64 **aligned_pointer) +{ + FLAC__int64 *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__int64 *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; + + FLAC__ASSERT(elements > 0); + FLAC__ASSERT(0 != unaligned_pointer); + FLAC__ASSERT(0 != aligned_pointer); + FLAC__ASSERT(unaligned_pointer != aligned_pointer); + + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer) +{ + FLAC__uint64 *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__uint64 *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; + + FLAC__ASSERT(elements > 0); + FLAC__ASSERT(0 != unaligned_pointer); + FLAC__ASSERT(0 != aligned_pointer); + FLAC__ASSERT(unaligned_pointer != aligned_pointer); + + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer) +{ + FLAC__real *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__real *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; + + FLAC__ASSERT(elements > 0); + FLAC__ASSERT(0 != unaligned_pointer); + FLAC__ASSERT(0 != aligned_pointer); + FLAC__ASSERT(unaligned_pointer != aligned_pointer); + + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +#endif + +void *safe_malloc_mul_2op_p(size_t size1, size_t size2) +{ + if(!size1 || !size2) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(size1 > SIZE_MAX / size2) + return 0; + return malloc(size1*size2); +} diff --git a/vendor/flac/src/libFLAC/metadata_iterators.c b/vendor/flac/src/libFLAC/metadata_iterators.c new file mode 100644 index 0000000..20e926b --- /dev/null +++ b/vendor/flac/src/libFLAC/metadata_iterators.c @@ -0,0 +1,3554 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include /* for stat(), maybe chmod() */ + +#include "private/metadata.h" + +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "share/macros.h" +#include "private/macros.h" +#include "private/memory.h" + +/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ +#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p + +/**************************************************************************** + * + * Local function declarations + * + ***************************************************************************/ + +static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes); +static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes); +static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes); +static FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes); +static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes); +static FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes); + +static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator); +static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block); +static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length); + +static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block); +static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length); +static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length); +static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block); +static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block); +static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block); +static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block); +static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length); + +static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last); +static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append); + +static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator); +static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator); + +static uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb); +static uint32_t seek_to_first_metadata_block_(FILE *f); + +static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append); +static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup); + +static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status); +static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status); +static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status); +static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status); + +static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status); +static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status); +static void cleanup_tempfile_(FILE **tempfile, char **tempfilename); + +static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats); +static void set_file_stats_(const char *filename, struct flac_stat_s *stats); + +static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence); +static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle); + +static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status); + + +#ifdef FLAC__VALGRIND_TESTING +static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#else +#define local__fwrite fwrite +#endif + +/**************************************************************************** + * + * Level 0 implementation + * + ***************************************************************************/ + +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +typedef struct { + FLAC__bool got_error; + FLAC__StreamMetadata *object; +} level0_client_data; + +static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type) +{ + level0_client_data cd; + FLAC__StreamDecoder *decoder; + + FLAC__ASSERT(0 != filename); + + cd.got_error = false; + cd.object = 0; + + decoder = FLAC__stream_decoder_new(); + + if(0 == decoder) + return 0; + + FLAC__stream_decoder_set_md5_checking(decoder, false); + FLAC__stream_decoder_set_metadata_ignore_all(decoder); + FLAC__stream_decoder_set_metadata_respond(decoder, type); + + if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + return 0; + } + + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + if(0 != cd.object) + FLAC__metadata_object_delete(cd.object); + return 0; + } + + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + + return cd.object; +} + +FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo) +{ + FLAC__StreamMetadata *object; + + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != streaminfo); + + object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO); + + if (object) { + /* can just copy the contents since STREAMINFO has no internal structure */ + *streaminfo = *object; + FLAC__metadata_object_delete(object); + return true; + } + else { + return false; + } +} + +FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != tags); + + *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT); + + return 0 != *tags; +} + +FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != cuesheet); + + *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET); + + return 0 != *cuesheet; +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + (void)decoder, (void)frame, (void)buffer, (void)client_data; + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + level0_client_data *cd = (level0_client_data *)client_data; + (void)decoder; + + /* + * we assume we only get here when the one metadata block we were + * looking for was passed to us + */ + if(!cd->got_error && 0 == cd->object) { + if(0 == (cd->object = FLAC__metadata_object_clone(metadata))) + cd->got_error = true; + } +} + +void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + level0_client_data *cd = (level0_client_data *)client_data; + (void)decoder; + + if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) + cd->got_error = true; +} + +FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors) +{ + FLAC__Metadata_SimpleIterator *it; + FLAC__uint64 max_area_seen = 0; + FLAC__uint64 max_depth_seen = 0; + + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != picture); + + *picture = 0; + + it = FLAC__metadata_simple_iterator_new(); + if(0 == it) + return false; + if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) { + FLAC__metadata_simple_iterator_delete(it); + return false; + } + do { + if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) { + FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it); + if(0 != obj) { + FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height; + + /* check constraints */ + if( + (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) && + (mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) && + (description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) && + obj->data.picture.width <= max_width && + obj->data.picture.height <= max_height && + obj->data.picture.depth <= max_depth && + obj->data.picture.colors <= max_colors && + (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen)) + ) { + if(*picture) + FLAC__metadata_object_delete(*picture); + *picture = obj; + max_area_seen = area; + max_depth_seen = obj->data.picture.depth; + } + else { + FLAC__metadata_object_delete(obj); + } + } + else + break; + } + } while(FLAC__metadata_simple_iterator_next(it)); + + FLAC__metadata_simple_iterator_delete(it); + + return (0 != *picture); +} + + +/**************************************************************************** + * + * Level 1 implementation + * + ***************************************************************************/ + +#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4) +/* 1 for initial offset, +4 for our own personal use */ + +struct FLAC__Metadata_SimpleIterator { + FILE *file; + char *filename, *tempfile_path_prefix; + struct flac_stat_s stats; + FLAC__bool has_stats; + FLAC__bool is_writable; + FLAC__Metadata_SimpleIteratorStatus status; + FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH]; + FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */ + uint32_t depth; + /* this is the metadata block header of the current block we are pointing to: */ + FLAC__bool is_last; + FLAC__MetadataType type; + uint32_t length; +}; + +FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = { + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR" +}; + + +FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void) +{ + FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator)); + + if(0 != iterator) { + iterator->file = 0; + iterator->filename = 0; + iterator->tempfile_path_prefix = 0; + iterator->has_stats = false; + iterator->is_writable = false; + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; + iterator->first_offset = iterator->offset[0] = -1; + iterator->depth = 0; + } + + return iterator; +} + +static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + if(0 != iterator->file) { + fclose(iterator->file); + iterator->file = 0; + if(iterator->has_stats) + set_file_stats_(iterator->filename, &iterator->stats); + } + if(0 != iterator->filename) { + free(iterator->filename); + iterator->filename = 0; + } + if(0 != iterator->tempfile_path_prefix) { + free(iterator->tempfile_path_prefix); + iterator->tempfile_path_prefix = 0; + } +} + +FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + simple_iterator_free_guts_(iterator); + free(iterator); +} + +FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__Metadata_SimpleIteratorStatus status; + + FLAC__ASSERT(0 != iterator); + + status = iterator->status; + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; + return status; +} + +static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only) +{ + uint32_t ret; + + FLAC__ASSERT(0 != iterator); + + if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) { + iterator->is_writable = false; + if(read_only || errno == EACCES) { + if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; + return false; + } + } + else { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; + return false; + } + } + else { + iterator->is_writable = true; + } + + ret = seek_to_first_metadata_block_(iterator->file); + switch(ret) { + case 0: + iterator->depth = 0; + iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file); + ret = read_metadata_block_header_(iterator); + /* The first metadata block must be a streaminfo. If this is not the + * case, the file is invalid and assumptions made elsewhere in the + * code are invalid */ + if(iterator->type != FLAC__METADATA_TYPE_STREAMINFO) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + return false; + } + return ret; + case 1: + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + case 2: + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + case 3: + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE; + return false; + default: + FLAC__ASSERT(0); + return false; + } +} + +#if 0 +@@@ If we decide to finish implementing this, put this comment back in metadata.h +/* + * The 'tempfile_path_prefix' allows you to specify a directory where + * tempfiles should go. Remember that if your metadata edits cause the + * FLAC file to grow, the entire file will have to be rewritten. If + * 'tempfile_path_prefix' is NULL, the temp file will be written in the + * same directory as the original FLAC file. This makes replacing the + * original with the tempfile fast but requires extra space in the same + * partition for the tempfile. If space is a problem, you can pass a + * directory name belonging to a different partition in + * 'tempfile_path_prefix'. Note that you should use the forward slash + * '/' as the directory separator. A trailing slash is not needed; it + * will be added automatically. + */ +FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix); +#endif + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats) +{ + const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */ + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != filename); + + simple_iterator_free_guts_(iterator); + + if(!read_only && preserve_file_stats) + iterator->has_stats = get_file_stats_(filename, &iterator->stats); + + if(0 == (iterator->filename = strdup(filename))) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + return simple_iterator_prime_input_(iterator, read_only); +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + return iterator->is_writable; +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + if(iterator->is_last) + return false; + + if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + iterator->offset[iterator->depth] = ftello(iterator->file); + + return read_metadata_block_header_(iterator); +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__off_t this_offset; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + if(iterator->offset[iterator->depth] == iterator->first_offset) + return false; + + if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + this_offset = iterator->first_offset; + if(!read_metadata_block_header_(iterator)) + return false; + + /* we ignore any error from ftello() and catch it in fseeko() */ + while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator->offset[iterator->depth]) { + if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + this_offset = ftello(iterator->file); + if(!read_metadata_block_header_(iterator)) + return false; + } + + iterator->offset[iterator->depth] = this_offset; + + return true; +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + return iterator->is_last; +} + +/*@@@@add to tests*/ +FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + return (off_t)iterator->offset[iterator->depth]; +} + +FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + return iterator->type; +} + +/*@@@@add to tests*/ +FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + return iterator->length; +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id) +{ + const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(0 != id); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + + if(fread(id, 1, id_bytes, iterator->file) != id_bytes) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + + /* back up */ + if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return true; +} + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type); + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + if(0 != block) { + block->is_last = iterator->is_last; + block->length = iterator->length; + + if(!read_metadata_block_data_(iterator, block)) { + FLAC__metadata_object_delete(block); + return 0; + } + + /* back up to the beginning of the block data to stay consistent */ + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + FLAC__metadata_object_delete(block); + return 0; + } + } + else + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + return block; +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding) +{ + FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];) + FLAC__bool ret; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(0 != block); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + if(!iterator->is_writable) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; + return false; + } + + if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) { + if(iterator->type != block->type) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + } + + block->is_last = iterator->is_last; + + if(iterator->length == block->length) + return write_metadata_block_stationary_(iterator, block); + else if(iterator->length > block->length) { + if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) { + ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last); + FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + return ret; + } + else { + if((ret = rewrite_whole_file_(iterator, block, /*append=*/false))) { + FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + } + return ret; + } + } + else /* iterator->length < block->length */ { + uint32_t padding_leftover = 0; + FLAC__bool padding_is_last = false; + if(use_padding) { + /* first see if we can even use padding */ + if(iterator->is_last) { + use_padding = false; + } + else { + const uint32_t extra_padding_bytes_required = block->length - iterator->length; + simple_iterator_push_(iterator); + if(!FLAC__metadata_simple_iterator_next(iterator)) { + (void)simple_iterator_pop_(iterator); + return false; + } + if(iterator->type != FLAC__METADATA_TYPE_PADDING) { + use_padding = false; + } + else { + if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) { + padding_leftover = 0; + block->is_last = iterator->is_last; + } + else if(iterator->length < extra_padding_bytes_required) + use_padding = false; + else { + padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required; + padding_is_last = iterator->is_last; + block->is_last = false; + } + } + if(!simple_iterator_pop_(iterator)) + return false; + } + } + if(use_padding) { + if(padding_leftover == 0) { + ret = write_metadata_block_stationary_(iterator, block); + FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + return ret; + } + else { + FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH); + ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last); + FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + return ret; + } + } + else { + if((ret = rewrite_whole_file_(iterator, block, /*append=*/false))) { + FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + } + return ret; + } + } +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding) +{ + uint32_t padding_leftover = 0; + FLAC__bool padding_is_last = false; + + FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;) + FLAC__bool ret; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(0 != block); + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + if(!iterator->is_writable) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; + return false; + } + + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + + block->is_last = iterator->is_last; + + if(use_padding) { + /* first see if we can even use padding */ + if(iterator->is_last) { + use_padding = false; + } + else { + simple_iterator_push_(iterator); + if(!FLAC__metadata_simple_iterator_next(iterator)) { + (void)simple_iterator_pop_(iterator); + return false; + } + if(iterator->type != FLAC__METADATA_TYPE_PADDING) { + use_padding = false; + } + else { + if(iterator->length == block->length) { + padding_leftover = 0; + block->is_last = iterator->is_last; + } + else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) + use_padding = false; + else { + padding_leftover = iterator->length - block->length; + padding_is_last = iterator->is_last; + block->is_last = false; + } + } + if(!simple_iterator_pop_(iterator)) + return false; + } + } + if(use_padding) { + /* move to the next block, which is suitable padding */ + if(!FLAC__metadata_simple_iterator_next(iterator)) + return false; + if(padding_leftover == 0) { + ret = write_metadata_block_stationary_(iterator, block); + FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + return ret; + } + else { + FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH); + ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last); + FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + return ret; + } + } + else { + if((ret = rewrite_whole_file_(iterator, block, /*append=*/true))) { + FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); + FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + } + return ret; + } +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding) +{ + FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];) + FLAC__bool ret; + + FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); + + if(!iterator->is_writable) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; + return false; + } + + if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + + if(use_padding) { + FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); + if(0 == padding) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + padding->length = iterator->length; + if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) { + FLAC__metadata_object_delete(padding); + return false; + } + FLAC__metadata_object_delete(padding); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return false; + FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset); + FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset); + return true; + } + else { + if((ret = rewrite_whole_file_(iterator, 0, /*append=*/false))) { + FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset); + FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset); + } + return ret; + } +} + + + +/**************************************************************************** + * + * Level 2 implementation + * + ***************************************************************************/ + + +typedef struct FLAC__Metadata_Node { + FLAC__StreamMetadata *data; + struct FLAC__Metadata_Node *prev, *next; +} FLAC__Metadata_Node; + +struct FLAC__Metadata_Chain { + char *filename; /* will be NULL if using callbacks */ + FLAC__bool is_ogg; + FLAC__Metadata_Node *head; + FLAC__Metadata_Node *tail; + uint32_t nodes; + FLAC__Metadata_ChainStatus status; + FLAC__off_t first_offset, last_offset; + /* + * This is the length of the chain initially read from the FLAC file. + * it is used to compare against the current length to decide whether + * or not the whole file has to be rewritten. + */ + FLAC__off_t initial_length; + /* @@@ hacky, these are currently only needed by ogg reader */ + FLAC__IOHandle handle; + FLAC__IOCallback_Read read_cb; +}; + +struct FLAC__Metadata_Iterator { + FLAC__Metadata_Chain *chain; + FLAC__Metadata_Node *current; +}; + +FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = { + "FLAC__METADATA_CHAIN_STATUS_OK", + "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT", + "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE", + "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE", + "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE", + "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA", + "FLAC__METADATA_CHAIN_STATUS_READ_ERROR", + "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR", + "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR", + "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR", + "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR", + "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR", + "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR", + "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS", + "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", + "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL" +}; + + +static FLAC__Metadata_Node *node_new_(void) +{ + return calloc(1, sizeof(FLAC__Metadata_Node)); +} + +static void node_delete_(FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != node); + if(0 != node->data) + FLAC__metadata_object_delete(node->data); + free(node); +} + +static void chain_init_(FLAC__Metadata_Chain *chain) +{ + FLAC__ASSERT(0 != chain); + + chain->filename = 0; + chain->is_ogg = false; + chain->head = chain->tail = 0; + chain->nodes = 0; + chain->status = FLAC__METADATA_CHAIN_STATUS_OK; + chain->initial_length = 0; + chain->read_cb = 0; +} + +static void chain_clear_(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_Node *node, *next; + + FLAC__ASSERT(0 != chain); + + for(node = chain->head; node; ) { + next = node->next; + node_delete_(node); + node = next; + } + + if(0 != chain->filename) + free(chain->filename); + + chain_init_(chain); +} + +static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != node); + FLAC__ASSERT(0 != node->data); + + node->next = node->prev = 0; + node->data->is_last = true; + if(0 != chain->tail) + chain->tail->data->is_last = false; + + if(0 == chain->head) + chain->head = node; + else { + FLAC__ASSERT(0 != chain->tail); + chain->tail->next = node; + node->prev = chain->tail; + } + chain->tail = node; + chain->nodes++; +} + +static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != node); + + if(node == chain->head) + chain->head = node->next; + else + node->prev->next = node->next; + + if(node == chain->tail) + chain->tail = node->prev; + else + node->next->prev = node->prev; + + if(0 != chain->tail) + chain->tail->data->is_last = true; + + chain->nodes--; +} + +static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + chain_remove_node_(chain, node); + node_delete_(node); +} + +static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain) +{ + const FLAC__Metadata_Node *node; + FLAC__off_t length = 0; + for(node = chain->head; node; node = node->next) + length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); + return length; +} + +static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != node); + FLAC__ASSERT(0 != node->data); + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != iterator->chain); + FLAC__ASSERT(0 != iterator->chain->head); + FLAC__ASSERT(0 != iterator->chain->tail); + + node->data->is_last = false; + + node->prev = iterator->current->prev; + node->next = iterator->current; + + if(0 == node->prev) + iterator->chain->head = node; + else + node->prev->next = node; + + iterator->current->prev = node; + + iterator->chain->nodes++; +} + +static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != node); + FLAC__ASSERT(0 != node->data); + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != iterator->chain); + FLAC__ASSERT(0 != iterator->chain->head); + FLAC__ASSERT(0 != iterator->chain->tail); + + iterator->current->data->is_last = false; + + node->prev = iterator->current; + node->next = iterator->current->next; + + if(0 == node->next) + iterator->chain->tail = node; + else + node->next->prev = node; + + node->prev->next = node; + + iterator->chain->tail->data->is_last = true; + + iterator->chain->nodes++; +} + +/* return true iff node and node->next are both padding */ +static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) { + const uint32_t growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length; + node->data->length += growth; /* new block size can be greater than max metadata block size, but it'll be fixed later in chain_prepare_for_write_() */ + + chain_delete_node_(chain, node->next); + return true; + } + else + return false; +} + +#if defined(_MSC_VER) +// silence three MSVC warnings 'conversion from 'conversion from 'const __int64' to 'uint32_t', possible loss of data' +#pragma warning ( disable : 4244 ) +#endif + +/* Returns the new length of the chain, or 0 if there was an error. */ +/* WATCHOUT: This can get called multiple times before a write, so + * it should still work when this happens. + */ +/* WATCHOUT: Make sure to also update the logic in + * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes. + */ +static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) +{ + FLAC__off_t current_length = chain_calculate_length_(chain); + FLAC__Metadata_Node * i; + + /* Check all is_last settings on the blocks */ + for(i = chain->head; i->next != NULL; i = i->next) + i->data->is_last = 0; + chain->tail->data->is_last = 1; + + if(use_padding) { + /* if the metadata shrank and the last block is padding, we just extend the last padding block */ + if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) { + const FLAC__off_t delta = chain->initial_length - current_length; + chain->tail->data->length += delta; + current_length += delta; + FLAC__ASSERT(current_length == chain->initial_length); + } + /* if the metadata shrank more than 4 bytes then there's room to add another padding block */ + else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) { + FLAC__StreamMetadata *padding; + FLAC__Metadata_Node *node; + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return 0; + } + padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length); + if(0 == (node = node_new_())) { + FLAC__metadata_object_delete(padding); + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return 0; + } + node->data = padding; + chain_append_node_(chain, node); + current_length = chain_calculate_length_(chain); + FLAC__ASSERT(current_length == chain->initial_length); + } + /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */ + else if(current_length > chain->initial_length) { + const FLAC__off_t delta = current_length - chain->initial_length; + if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) { + /* if the delta is exactly the size of the last padding block, remove the padding block */ + if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) { + chain_delete_node_(chain, chain->tail); + current_length = chain_calculate_length_(chain); + FLAC__ASSERT(current_length == chain->initial_length); + } + /* if there is at least 'delta' bytes of padding, trim the padding down */ + else if((FLAC__off_t)chain->tail->data->length >= delta) { + chain->tail->data->length -= delta; + current_length -= delta; + FLAC__ASSERT(current_length == chain->initial_length); + } + } + } + } + + /* check sizes of all metadata blocks; reduce padding size if necessary */ + { + FLAC__Metadata_Node *node; + for (node = chain->head; node; node = node->next) { + if(node->data->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) { + if(node->data->type == FLAC__METADATA_TYPE_PADDING) { + node->data->length = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1; + current_length = chain_calculate_length_(chain); + } else { + chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA; + return 0; + } + } + } + } + + return current_length; +} + +#if defined(_MSC_VER) +#pragma warning ( default : 4244 ) +#endif + +static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + + /* we assume we're already at the beginning of the file */ + + switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) { + case 0: + break; + case 1: + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + case 2: + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + case 3: + chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE; + return false; + default: + FLAC__ASSERT(0); + return false; + } + + { + FLAC__int64 pos = tell_cb(handle); + if(pos < 0) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + } + chain->first_offset = (FLAC__off_t)pos; + } + + { + FLAC__bool is_last; + FLAC__MetadataType type; + uint32_t length; + + do { + node = node_new_(); + if(0 == node) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) { + node_delete_(node); + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + } + + node->data = FLAC__metadata_object_new(type); + if(0 == node->data) { + node_delete_(node); + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + node->data->is_last = is_last; + node->data->length = length; + + chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data)); + if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) { + node_delete_(node); + return false; + } + chain_append_node_(chain, node); + } while(!is_last); + } + + { + FLAC__int64 pos = tell_cb(handle); + if(pos < 0) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + } + chain->last_offset = (FLAC__off_t)pos; + } + + if(chain->head->data->type != FLAC__METADATA_TYPE_STREAMINFO) { + chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA; + return false; + } + + chain->initial_length = chain_calculate_length_(chain); + + return true; +} + +static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; + (void)decoder; + if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) { + *bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle); + if(*bytes == 0) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; +} + +static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + (void)decoder, (void)frame, (void)buffer, (void)client_data; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; +} + +static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; + FLAC__Metadata_Node *node; + + (void)decoder; + + node = node_new_(); + if(0 == node) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return; + } + + node->data = FLAC__metadata_object_clone(metadata); + if(0 == node->data) { + node_delete_(node); + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return; + } + + chain_append_node_(chain, node); +} + +static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; + (void)decoder, (void)status; + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ +} + +static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb) +{ + FLAC__StreamDecoder *decoder; + + FLAC__ASSERT(0 != chain); + + /* we assume we're already at the beginning of the file */ + + chain->handle = handle; + chain->read_cb = read_cb; + if(0 == (decoder = FLAC__stream_decoder_new())) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + FLAC__stream_decoder_set_metadata_respond_all(decoder); + if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + FLAC__stream_decoder_delete(decoder); + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ + return false; + } + + chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */ + + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ + if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) { + FLAC__stream_decoder_delete(decoder); + return false; + } + + FLAC__stream_decoder_delete(decoder); + + chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */ + + chain->initial_length = chain_calculate_length_(chain); + + if(chain->initial_length == 0 || chain->head->data->type != FLAC__METADATA_TYPE_STREAMINFO) { + /* Ogg FLAC file must have at least streaminfo and vorbis comment */ + chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA; + return false; + } + + return true; +} + +static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != chain->head); + + if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + + for(node = chain->head; node; node = node->next) { + if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + } + + /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ + + chain->status = FLAC__METADATA_CHAIN_STATUS_OK; + return true; +} + +static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain) +{ + FILE *file; + FLAC__bool ret; + + FLAC__ASSERT(0 != chain->filename); + + if(0 == (file = flac_fopen(chain->filename, "r+b"))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; + return false; + } + + /* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */ + ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_); + + fclose(file); + + return ret; +} + +static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix) +{ + FILE *f, *tempfile = NULL; + char *tempfilename; + FLAC__Metadata_SimpleIteratorStatus status; + const FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != chain->filename); + FLAC__ASSERT(0 != chain->head); + + /* copy the file prefix (data up to first metadata block */ + if(0 == (f = flac_fopen(chain->filename, "rb"))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; + return false; + } + if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) { + chain->status = get_equivalent_status_(status); + goto err; + } + if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) { + chain->status = get_equivalent_status_(status); + goto err; + } + + /* write the metadata */ + for(node = chain->head; node; node = node->next) { + if(!write_metadata_block_header_(tempfile, &status, node->data)) { + chain->status = get_equivalent_status_(status); + goto err; + } + if(!write_metadata_block_data_(tempfile, &status, node->data)) { + chain->status = get_equivalent_status_(status); + goto err; + } + } + /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ + + /* copy the file postfix (everything after the metadata) */ + if(0 != fseeko(f, chain->last_offset, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + goto err; + } + if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) { + chain->status = get_equivalent_status_(status); + goto err; + } + + /* move the tempfile on top of the original */ + (void)fclose(f); + if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status)) + return false; + + return true; + +err: + (void)fclose(f); + cleanup_tempfile_(&tempfile, &tempfilename); + return false; +} + +/* assumes 'handle' is already at beginning of file */ +static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb) +{ + FLAC__Metadata_SimpleIteratorStatus status; + const FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 == chain->filename); + FLAC__ASSERT(0 != chain->head); + + /* copy the file prefix (data up to first metadata block */ + if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) { + chain->status = get_equivalent_status_(status); + return false; + } + + /* write the metadata */ + for(node = chain->head; node; node = node->next) { + if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + } + /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ + + /* copy the file postfix (everything after the metadata) */ + if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) { + chain->status = get_equivalent_status_(status); + return false; + } + + return true; +} + +FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void) +{ + FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain)); + + if(0 != chain) + chain_init_(chain); + + return chain; +} + +FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain) +{ + FLAC__ASSERT(0 != chain); + + chain_clear_(chain); + + free(chain); +} + +FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_ChainStatus status; + + FLAC__ASSERT(0 != chain); + + status = chain->status; + chain->status = FLAC__METADATA_CHAIN_STATUS_OK; + return status; +} + +static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg) +{ + FILE *file; + FLAC__bool ret; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != filename); + + chain_clear_(chain); + + if(0 == (chain->filename = strdup(filename))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + chain->is_ogg = is_ogg; + + if(0 == (file = flac_fopen(filename, "rb"))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; + return false; + } + + /* the function also sets chain->status for us */ + ret = is_ogg? + chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) : + chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_) + ; + + fclose(file); + + return ret; +} + +FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename) +{ + return chain_read_(chain, filename, /*is_ogg=*/false); +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename) +{ + return chain_read_(chain, filename, /*is_ogg=*/true); +} + +static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg) +{ + FLAC__bool ret; + + FLAC__ASSERT(0 != chain); + + chain_clear_(chain); + + if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + + chain->is_ogg = is_ogg; + + /* rewind */ + if(0 != callbacks.seek(handle, 0, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + + /* the function also sets chain->status for us */ + ret = is_ogg? + chain_read_ogg_cb_(chain, handle, callbacks.read) : + chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell) + ; + + return ret; +} + +FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) +{ + return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false); +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) +{ + return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true); +} + +typedef enum { + LBS_NONE = 0, + LBS_SIZE_CHANGED, + LBS_BLOCK_ADDED, + LBS_BLOCK_REMOVED +} LastBlockState; + +#if defined(_MSC_VER) +// silence three MSVC warnings 'conversion from 'conversion from 'const __int64' to 'uint32_t', possible loss of data' +#pragma warning ( disable : 4244 ) +#endif + +FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) +{ + /* This does all the same checks that are in chain_prepare_for_write_() + * but doesn't actually alter the chain. Make sure to update the logic + * here if chain_prepare_for_write_() changes. + */ + FLAC__off_t current_length; + LastBlockState lbs_state = LBS_NONE; + uint32_t lbs_size = 0; + + FLAC__ASSERT(0 != chain); + + current_length = chain_calculate_length_(chain); + + if(use_padding) { + const FLAC__Metadata_Node * const node = chain->tail; + /* if the metadata shrank and the last block is padding, we just extend the last padding block */ + if(current_length < chain->initial_length && node->data->type == FLAC__METADATA_TYPE_PADDING) { + lbs_state = LBS_SIZE_CHANGED; + lbs_size = node->data->length + (chain->initial_length - current_length); + } + /* if the metadata shrank more than 4 bytes then there's room to add another padding block */ + else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) { + lbs_state = LBS_BLOCK_ADDED; + lbs_size = chain->initial_length - (current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); + } + /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */ + else if(current_length > chain->initial_length) { + const FLAC__off_t delta = current_length - chain->initial_length; + if(node->data->type == FLAC__METADATA_TYPE_PADDING) { + /* if the delta is exactly the size of the last padding block, remove the padding block */ + if((FLAC__off_t)node->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) { + lbs_state = LBS_BLOCK_REMOVED; + lbs_size = 0; + } + /* if there is at least 'delta' bytes of padding, trim the padding down */ + else if((FLAC__off_t)node->data->length >= delta) { + lbs_state = LBS_SIZE_CHANGED; + lbs_size = node->data->length - delta; + } + } + } + } + + current_length = 0; + /* check sizes of all metadata blocks; reduce padding size if necessary */ + { + const FLAC__Metadata_Node *node; + for(node = chain->head; node; node = node->next) { + uint32_t block_len = node->data->length; + if(node == chain->tail) { + if(lbs_state == LBS_BLOCK_REMOVED) + continue; + else if(lbs_state == LBS_SIZE_CHANGED) + block_len = lbs_size; + } + if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) { + if(node->data->type == FLAC__METADATA_TYPE_PADDING) + block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1; + else + return false /* the return value doesn't matter */; + } + current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len); + } + + if(lbs_state == LBS_BLOCK_ADDED) { + /* test added padding block */ + uint32_t block_len = lbs_size; + if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) + block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1; + current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len); + } + } + + return (current_length != chain->initial_length); +} + +#if defined(_MSC_VER) +#pragma warning ( default : 4244 ) +#endif + +FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats) +{ + struct flac_stat_s stats; + const char *tempfile_path_prefix = 0; + FLAC__off_t current_length; + + FLAC__ASSERT(0 != chain); + + if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + return false; + } + + if (0 == chain->filename) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; + return false; + } + + current_length = chain_prepare_for_write_(chain, use_padding); + + /* a return value of 0 means there was an error; chain->status is already set */ + if (0 == current_length) + return false; + + if(preserve_file_stats) + get_file_stats_(chain->filename, &stats); + + if(current_length == chain->initial_length) { + if(!chain_rewrite_metadata_in_place_(chain)) + return false; + } + else { + if(!chain_rewrite_file_(chain, tempfile_path_prefix)) + return false; + + /* recompute lengths and offsets */ + { + const FLAC__Metadata_Node *node; + chain->initial_length = current_length; + chain->last_offset = chain->first_offset; + for(node = chain->head; node; node = node->next) + chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); + } + } + + if(preserve_file_stats) + set_file_stats_(chain->filename, &stats); + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) +{ + FLAC__off_t current_length; + + FLAC__ASSERT(0 != chain); + + if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + return false; + } + + if (0 != chain->filename) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; + return false; + } + + if (0 == callbacks.write || 0 == callbacks.seek) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + + if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL; + return false; + } + + current_length = chain_prepare_for_write_(chain, use_padding); + + /* a return value of 0 means there was an error; chain->status is already set */ + if (0 == current_length) + return false; + + FLAC__ASSERT(current_length == chain->initial_length); + + return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek); +} + +FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks) +{ + FLAC__off_t current_length; + + FLAC__ASSERT(0 != chain); + + if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + return false; + } + + if (0 != chain->filename) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; + return false; + } + + if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + if (0 == temp_callbacks.write) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + + if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL; + return false; + } + + current_length = chain_prepare_for_write_(chain, use_padding); + + /* a return value of 0 means there was an error; chain->status is already set */ + if (0 == current_length) + return false; + + FLAC__ASSERT(current_length != chain->initial_length); + + /* rewind */ + if(0 != callbacks.seek(handle, 0, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + + if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write)) + return false; + + /* recompute lengths and offsets */ + { + const FLAC__Metadata_Node *node; + chain->initial_length = current_length; + chain->last_offset = chain->first_offset; + for(node = chain->head; node; node = node->next) + chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); + } + + return true; +} + +FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + + for(node = chain->head; node; ) { + if(!chain_merge_adjacent_padding_(chain, node)) + node = node->next; + } +} + +FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_Node *node, *save; + uint32_t i; + + FLAC__ASSERT(0 != chain); + + /* + * Don't try and be too smart... this simple algo is good enough for + * the small number of nodes that we deal with. + */ + for(i = 0, node = chain->head; i < chain->nodes; i++) { + if(node->data->type == FLAC__METADATA_TYPE_PADDING) { + save = node->next; + chain_remove_node_(chain, node); + chain_append_node_(chain, node); + node = save; + } + else { + node = node->next; + } + } + + FLAC__metadata_chain_merge_padding(chain); +} + + +FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void) +{ + FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator)); + + /* calloc() implies: + iterator->current = 0; + iterator->chain = 0; + */ + + return iterator; +} + +FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + free(iterator); +} + +FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != chain->head); + + iterator->chain = chain; + iterator->current = chain->head; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + if(0 == iterator->current || 0 == iterator->current->next) + return false; + + iterator->current = iterator->current->next; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + if(0 == iterator->current || 0 == iterator->current->prev) + return false; + + iterator->current = iterator->current->prev; + return true; +} + +FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != iterator->current->data); + + return iterator->current->data->type; +} + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + + return iterator->current->data; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != block); + return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block); +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding) +{ + FLAC__Metadata_Node *save; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + + if(0 == iterator->current->prev) { + FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO); + return false; + } + + save = iterator->current->prev; + + if(replace_with_padding) { + FLAC__metadata_object_delete_data(iterator->current->data); + iterator->current->data->type = FLAC__METADATA_TYPE_PADDING; + } + else { + chain_delete_node_(iterator->chain, iterator->current); + } + + iterator->current = save; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != block); + + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) + return false; + + if(0 == iterator->current->prev) { + FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO); + return false; + } + + if(0 == (node = node_new_())) + return false; + + node->data = block; + iterator_insert_node_(iterator, node); + iterator->current = node; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != block); + + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) + return false; + + if(0 == (node = node_new_())) + return false; + + node->data = block; + iterator_insert_node_after_(iterator, node); + iterator->current = node; + return true; +} + + +/**************************************************************************** + * + * Local function definitions + * + ***************************************************************************/ + +void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes) +{ + uint32_t i; + + b += bytes; + + for(i = 0; i < bytes; i++) { + *(--b) = (FLAC__byte)(val & 0xff); + val >>= 8; + } +} + +void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes) +{ + uint32_t i; + + for(i = 0; i < bytes; i++) { + *(b++) = (FLAC__byte)(val & 0xff); + val >>= 8; + } +} + +void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes) +{ + uint32_t i; + + b += bytes; + + for(i = 0; i < bytes; i++) { + *(--b) = (FLAC__byte)(val & 0xff); + val >>= 8; + } +} + +FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes) +{ + FLAC__uint32 ret = 0; + uint32_t i; + + for(i = 0; i < bytes; i++) + ret = (ret << 8) | (FLAC__uint32)(*b++); + + return ret; +} + +FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes) +{ + FLAC__uint32 ret = 0; + uint32_t i; + + b += bytes; + + for(i = 0; i < bytes; i++) + ret = (ret << 8) | (FLAC__uint32)(*--b); + + return ret; +} + +FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes) +{ + FLAC__uint64 ret = 0; + uint32_t i; + + for(i = 0; i < bytes; i++) + ret = (ret << 8) | (FLAC__uint64)(*b++); + + return ret; +} + +FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + + return true; +} + +FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block); + + return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); +} + +FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length) +{ + FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH]; + + if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH) + return false; + + *is_last = raw_header[0] & 0x80? true : false; + *type = (FLAC__MetadataType)(raw_header[0] & 0x7f); + *length = unpack_uint32_(raw_header + 1, 3); + + /* Note that we don't check: + * if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED) + * we just will read in an opaque block + */ + + return true; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block) +{ + switch(block->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info); + case FLAC__METADATA_TYPE_PADDING: + return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length); + case FLAC__METADATA_TYPE_APPLICATION: + return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length); + case FLAC__METADATA_TYPE_SEEKTABLE: + return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length); + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, seek_cb, &block->data.vorbis_comment, block->length); + case FLAC__METADATA_TYPE_CUESHEET: + return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture); + default: + return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length); + } +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block) +{ + FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b; + + if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + b = buffer; + + /* we are using hardcoded numbers for simplicity but we should + * probably eventually write a bit-level unpacker and use the + * _STREAMINFO_ constants. + */ + block->min_blocksize = unpack_uint32_(b, 2); b += 2; + block->max_blocksize = unpack_uint32_(b, 2); b += 2; + block->min_framesize = unpack_uint32_(b, 3); b += 3; + block->max_framesize = unpack_uint32_(b, 3); b += 3; + block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((uint32_t)(b[2] & 0xf0) >> 4); + block->channels = (uint32_t)((b[2] & 0x0e) >> 1) + 1; + block->bits_per_sample = ((((uint32_t)(b[2] & 0x01)) << 4) | (((uint32_t)(b[3] & 0xf0)) >> 4)) + 1; + block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4); + memcpy(block->md5sum, b+8, 16); + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length) +{ + (void)block; /* nothing to do; we don't care about reading the padding bytes */ + + if(0 != seek_cb(handle, block_length, SEEK_CUR)) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length) +{ + const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + + if(read_cb(block->id, 1, id_bytes, handle) != id_bytes) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + if(block_length < id_bytes) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + block_length -= id_bytes; + + if(block_length == 0) { + block->data = 0; + } + else { + if(0 == (block->data = malloc(block_length))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(read_cb(block->data, 1, block_length, handle) != block_length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length) +{ + uint32_t i; + FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH]; + + if(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH != 0) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + + block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; + + if(block->num_points == 0) + block->points = 0; + else if(0 == (block->points = safe_malloc_mul_2op_p(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + for(i = 0; i < block->num_points; i++) { + if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + /* some MAGIC NUMBERs here */ + block->points[i].sample_number = unpack_uint64_(buffer, 8); + block->points[i].stream_offset = unpack_uint64_(buffer+8, 8); + block->points[i].frame_samples = unpack_uint32_(buffer+16, 2); + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length) +{ + const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; + FLAC__byte buffer[4]; /* magic number is asserted below */ + + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer)); + + if(max_length < entry_length_len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + + max_length -= entry_length_len; + if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + entry->length = unpack_uint32_little_endian_(buffer, entry_length_len); + if(max_length < entry->length) { + entry->length = 0; + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + } + + if(0 != entry->entry) + free(entry->entry); + + if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+*/1))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(entry->length > 0 && read_cb(entry->entry, 1, entry->length, handle) != entry->length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + entry->entry[entry->length] = '\0'; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length) +{ + uint32_t i; + FLAC__Metadata_SimpleIteratorStatus status; + const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; + FLAC__byte buffer[4]; /* magic number is asserted below */ + + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer)); + + status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string), block_length); + if(block_length >= 4) + block_length -= 4; + if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) + goto skip; + else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + block_length -= block->vendor_string.length; + + if(block_length < num_comments_len) goto skip; else block_length -= num_comments_len; + if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len); + + if(block->num_comments == 0) { + block->comments = 0; + } + else if(block->num_comments > (block_length >> 2)) { /* each comment needs at least 4 byte */ + block->num_comments = 0; + status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + goto skip; + } + else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { + block->num_comments = 0; + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + } + + for(i = 0; i < block->num_comments; i++) { + status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i, block_length); + if(block_length >= 4) block_length -= 4; + if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) { + block->num_comments = i; + goto skip; + } + else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status; + block_length -= block->comments[i].length; + } + + skip: + if(block_length > 0) { + /* bad metadata */ + if(0 != seek_cb(handle, block_length, SEEK_CUR)) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + } + + return status; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track) +{ + uint32_t i, len; + FLAC__byte buffer[32]; /* asserted below that this is big enough */ + + FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64)); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->offset = unpack_uint64_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->number = (FLAC__byte)unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8; + if(read_cb(track->isrc, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1); + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1); + track->type = buffer[0] >> 7; + track->pre_emphasis = (buffer[0] >> 6) & 1; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len); + + if(track->num_indices == 0) { + track->indices = 0; + } + else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + for(i = 0; i < track->num_indices; i++) { + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->indices[i].offset = unpack_uint64_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block) +{ + uint32_t i, len; + FLAC__Metadata_SimpleIteratorStatus status; + FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */ + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer)); + FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer)); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8; + if(read_cb(block->media_catalog_number, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->lead_in = unpack_uint64_(buffer, len); + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->is_cd = buffer[0]&0x80? true : false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->num_tracks = unpack_uint32_(buffer, len); + + if(block->num_tracks == 0) { + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + } + else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + for(i = 0; i < block->num_tracks; i++) { + if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i))) + return status; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len) +{ + FLAC__byte buffer[sizeof(FLAC__uint32)]; + + FLAC__ASSERT(0 != data); + FLAC__ASSERT(length_len%8 == 0); + + length_len /= 8; /* convert to bytes */ + + FLAC__ASSERT(sizeof(buffer) >= length_len); + + if(read_cb(buffer, 1, length_len, handle) != length_len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + *length = unpack_uint32_(buffer, length_len); + + if(*length > (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) /* data cannot be larger than FLAC metadata block */ + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + + if(0 != *data) + free(*data); + + if(0 == (*data = safe_malloc_add_2op_(*length, /*+*/1))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(*length > 0) { + if(read_cb(*data, 1, *length, handle) != *length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + (*data)[*length] = '\0'; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block) +{ + FLAC__Metadata_SimpleIteratorStatus status; + FLAC__byte buffer[4]; /* asserted below that this is big enough */ + FLAC__uint32 len; + + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len); + + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->width = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->height = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->depth = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->colors = unpack_uint32_(buffer, len); + + /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */ + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length) +{ + if(block_length == 0) { + block->data = 0; + } + else { + if(0 == (block->data = malloc(block_length))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(read_cb(block->data, 1, block_length, handle) != block_length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != file); + FLAC__ASSERT(0 != status); + + if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + + return true; +} + +FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != file); + FLAC__ASSERT(0 != status); + + if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; + return true; + } + else { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } +} + +FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block) +{ + FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH]; + + FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); + /* double protection */ + if(block->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; + + buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type; + pack_uint32_(block->length, buffer + 1, 3); + + if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != block); + + switch(block->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info); + case FLAC__METADATA_TYPE_PADDING: + return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length); + case FLAC__METADATA_TYPE_APPLICATION: + return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length); + case FLAC__METADATA_TYPE_SEEKTABLE: + return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table); + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment); + case FLAC__METADATA_TYPE_CUESHEET: + return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture); + default: + return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length); + } +} + +FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block) +{ + FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH]; + const uint32_t channels1 = block->channels - 1; + const uint32_t bps1 = block->bits_per_sample - 1; + + /* we are using hardcoded numbers for simplicity but we should + * probably eventually write a bit-level packer and use the + * _STREAMINFO_ constants. + */ + pack_uint32_(block->min_blocksize, buffer, 2); + pack_uint32_(block->max_blocksize, buffer+2, 2); + pack_uint32_(block->min_framesize, buffer+4, 3); + pack_uint32_(block->max_framesize, buffer+7, 3); + buffer[10] = (block->sample_rate >> 12) & 0xff; + buffer[11] = (block->sample_rate >> 4) & 0xff; + buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4); + buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f)); + pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4); + memcpy(buffer+18, block->md5sum, 16); + + if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length) +{ + uint32_t i, n = block_length; + FLAC__byte buffer[1024]; + + (void)block; + + memset(buffer, 0, 1024); + + for(i = 0; i < n/1024; i++) + if(write_cb(buffer, 1, 1024, handle) != 1024) + return false; + + n %= 1024; + + if(write_cb(buffer, 1, n, handle) != n) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length) +{ + const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + + if(write_cb(block->id, 1, id_bytes, handle) != id_bytes) + return false; + + block_length -= id_bytes; + + if(write_cb(block->data, 1, block_length, handle) != block_length) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block) +{ + uint32_t i; + FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH]; + + for(i = 0; i < block->num_points; i++) { + /* some MAGIC NUMBERs here */ + pack_uint64_(block->points[i].sample_number, buffer, 8); + pack_uint64_(block->points[i].stream_offset, buffer+8, 8); + pack_uint32_(block->points[i].frame_samples, buffer+16, 2); + if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) + return false; + } + + return true; +} + +FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block) +{ + uint32_t i; + const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; + const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; + FLAC__byte buffer[4]; /* magic number is asserted below */ + + FLAC__ASSERT(flac_max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer)); + + pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len); + if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) + return false; + if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length) + return false; + + pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len); + if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len) + return false; + + for(i = 0; i < block->num_comments; i++) { + pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len); + if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) + return false; + if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length) + return false; + } + + return true; +} + +FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block) +{ + uint32_t i, j, len; + FLAC__byte buffer[1024]; /* asserted below that this is big enough */ + + FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64)); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8; + if(write_cb(block->media_catalog_number, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8; + pack_uint64_(block->lead_in, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8; + memset(buffer, 0, len); + if(block->is_cd) + buffer[0] |= 0x80; + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8; + pack_uint32_(block->num_tracks, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + for(i = 0; i < block->num_tracks; i++) { + FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8; + pack_uint64_(track->offset, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8; + pack_uint32_(track->number, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8; + if(write_cb(track->isrc, 1, len, handle) != len) + return false; + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8; + memset(buffer, 0, len); + buffer[0] = (track->type << 7) | (track->pre_emphasis << 6); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8; + pack_uint32_(track->num_indices, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + for(j = 0; j < track->num_indices; j++) { + FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8; + pack_uint64_(indx->offset, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8; + pack_uint32_(indx->number, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8; + memset(buffer, 0, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + } + } + + return true; +} + +FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block) +{ + uint32_t len; + size_t slen; + FLAC__byte buffer[4]; /* magic number is asserted below */ + + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8); + + len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8; + pack_uint32_(block->type, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8; + slen = strlen(block->mime_type); + pack_uint32_(slen, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->mime_type, 1, slen, handle) != slen) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8; + slen = strlen((const char *)block->description); + pack_uint32_(slen, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->description, 1, slen, handle) != slen) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8; + pack_uint32_(block->width, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8; + pack_uint32_(block->height, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8; + pack_uint32_(block->depth, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8; + pack_uint32_(block->colors, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8; + pack_uint32_(block->data_length, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->data, 1, block->data_length, handle) != block->data_length) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length) +{ + if(write_cb(block->data, 1, block_length, handle) != block_length) + return false; + + return true; +} + +FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block) +{ + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + if(!write_metadata_block_header_(iterator->file, &iterator->status, block)) + return false; + + if(!write_metadata_block_data_(iterator->file, &iterator->status, block)) + return false; + + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return read_metadata_block_header_(iterator); +} + +FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last) +{ + FLAC__StreamMetadata *padding; + + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + block->is_last = false; + + if(!write_metadata_block_header_(iterator->file, &iterator->status, block)) + return false; + + if(!write_metadata_block_data_(iterator->file, &iterator->status, block)) + return false; + + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + padding->is_last = padding_is_last; + padding->length = padding_length; + + if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) { + FLAC__metadata_object_delete(padding); + return false; + } + + if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) { + FLAC__metadata_object_delete(padding); + return false; + } + + FLAC__metadata_object_delete(padding); + + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return read_metadata_block_header_(iterator); +} + +FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append) +{ + FILE *tempfile = NULL; + char *tempfilename = NULL; + int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */ + FLAC__off_t fixup_is_last_flag_offset = -1; + + FLAC__ASSERT(0 != block || append == false); + + if(iterator->is_last) { + if(append) { + fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */ + fixup_is_last_flag_offset = iterator->offset[iterator->depth]; + } + else if(0 == block) { + simple_iterator_push_(iterator); + if(!FLAC__metadata_simple_iterator_prev(iterator)) { + (void)simple_iterator_pop_(iterator); + return false; + } + fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */ + fixup_is_last_flag_offset = iterator->offset[iterator->depth]; + if(!simple_iterator_pop_(iterator)) + return false; + } + } + + if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append)) + return false; + + if(0 != block) { + if(!write_metadata_block_header_(tempfile, &iterator->status, block)) { + cleanup_tempfile_(&tempfile, &tempfilename); + return false; + } + + if(!write_metadata_block_data_(tempfile, &iterator->status, block)) { + cleanup_tempfile_(&tempfile, &tempfilename); + return false; + } + } + + if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0)) + return false; + + if(append) + return FLAC__metadata_simple_iterator_next(iterator); + + return true; +} + +void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH); + iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth]; + iterator->depth++; +} + +FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(iterator->depth > 0); + iterator->depth--; + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return read_metadata_block_header_(iterator); +} + +/* return meanings: + * 0: ok + * 1: read error + * 2: seek error + * 3: not a FLAC file + */ +uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb) +{ + FLAC__byte buffer[4]; + size_t n; + uint32_t i; + + FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer)); + + /* skip any id3v2 tag */ + errno = 0; + n = read_cb(buffer, 1, 4, handle); + if(errno) + return 1; + else if(n != 4) + return 3; + else if(0 == memcmp(buffer, "ID3", 3)) { + uint32_t tag_length = 0; + + /* skip to the tag length */ + if(seek_cb(handle, 2, SEEK_CUR) < 0) + return 2; + + /* read the length */ + for(i = 0; i < 4; i++) { + if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80) + return 1; + tag_length <<= 7; + tag_length |= (buffer[0] & 0x7f); + } + + /* skip the rest of the tag */ + if(seek_cb(handle, tag_length, SEEK_CUR) < 0) + return 2; + + /* read the stream sync code */ + errno = 0; + n = read_cb(buffer, 1, 4, handle); + if(errno) + return 1; + else if(n != 4) + return 3; + } + + /* check for the fLaC signature */ + if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH)) + return 0; + else + return 3; +} + +uint32_t seek_to_first_metadata_block_(FILE *f) +{ + return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_); +} + +FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append) +{ + const FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length : iterator->offset[iterator->depth]; + + if(0 != fseeko(iterator->file, 0, SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + + return true; +} + +FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup) +{ + FLAC__off_t save_offset = iterator->offset[iterator->depth]; + FLAC__ASSERT(0 != *tempfile); + + if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length, SEEK_SET)) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + + if(fixup_is_last_code != 0) { + /* + * if code == 1, it means a block was appended to the end so + * we have to clear the is_last flag of the previous block + * if code == -1, it means the last block was deleted so + * we have to set the is_last flag of the previous block + */ + /* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */ + FLAC__byte x; + if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(fread(&x, 1, 1, *tempfile) != 1) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(fixup_is_last_code > 0) { + FLAC__ASSERT(x & 0x80); + x &= 0x7f; + } + else { + FLAC__ASSERT(!(x & 0x80)); + x |= 0x80; + } + if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(local__fwrite(&x, 1, 1, *tempfile) != 1) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + } + + (void)fclose(iterator->file); + + if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status)) + return false; + + if(iterator->has_stats) + set_file_stats_(iterator->filename, &iterator->stats); + + if(!simple_iterator_prime_input_(iterator, !iterator->is_writable)) + return false; + if(backup) { + while(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length < save_offset) + if(!FLAC__metadata_simple_iterator_next(iterator)) + return false; + return true; + } + else { + /* move the iterator to it's original block faster by faking a push, then doing a pop_ */ + FLAC__ASSERT(iterator->depth == 0); + iterator->offset[0] = save_offset; + iterator->depth++; + return simple_iterator_pop_(iterator); + } +} + +FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__byte buffer[8192]; + size_t n; + + FLAC__ASSERT(bytes >= 0); + while(bytes > 0) { + n = flac_min(sizeof(buffer), (size_t)bytes); + if(fread(buffer, 1, n, file) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(local__fwrite(buffer, 1, n, tempfile) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + bytes -= n; + } + + return true; +} + +FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__byte buffer[8192]; + size_t n; + + FLAC__ASSERT(bytes >= 0); + while(bytes > 0) { + n = flac_min(sizeof(buffer), (size_t)bytes); + if(read_cb(buffer, 1, n, handle) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(temp_write_cb(buffer, 1, n, temp_handle) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + bytes -= n; + } + + return true; +} + +FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__byte buffer[8192]; + size_t n; + + while(!feof(file)) { + n = fread(buffer, 1, sizeof(buffer), file); + if(n == 0 && !feof(file)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + } + + return true; +} + +FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__byte buffer[8192]; + size_t n; + + while(!eof_cb(handle)) { + n = read_cb(buffer, 1, sizeof(buffer), handle); + if(n == 0 && !eof_cb(handle)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + } + + return true; +} + +static int +local_snprintf(char *str, size_t size, const char *fmt, ...) +{ + va_list va; + int rc; + +#if defined _MSC_VER + if (size == 0) + return 1024; +#endif + + va_start (va, fmt); + +#if defined _MSC_VER + rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va); + if (rc < 0) + rc = size - 1; +#elif defined __MINGW32__ + rc = __mingw_vsnprintf (str, size, fmt, va); +#else + rc = vsnprintf (str, size, fmt, va); +#endif + va_end (va); + + return rc; +} + +FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status) +{ + static const char *tempfile_suffix = ".metadata_edit"; + if(0 == tempfile_path_prefix) { + size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1; + if(0 == (*tempfilename = safe_malloc_(dest_len))) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfile_suffix); + } + else { + const char *p = strrchr(filename, '/'); + size_t dest_len; + if(0 == p) + p = filename; + else + p++; + + dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tempfile_suffix) + 2; + + if(0 == (*tempfilename = safe_malloc_(dest_len))) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix); + } + + if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; + return false; + } + + return true; +} + +FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != tempfile); + FLAC__ASSERT(0 != *tempfile); + FLAC__ASSERT(0 != tempfilename); + FLAC__ASSERT(0 != *tempfilename); + FLAC__ASSERT(0 != status); + + (void)fclose(*tempfile); + *tempfile = 0; + +#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__ + /* on some flavors of windows, flac_rename() will fail if the destination already exists */ + if(flac_unlink(filename) < 0) { + cleanup_tempfile_(tempfile, tempfilename); + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR; + return false; + } +#endif + + /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just flac_rename(): */ + if(0 != flac_rename(*tempfilename, filename)) { + cleanup_tempfile_(tempfile, tempfilename); + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR; + return false; + } + + cleanup_tempfile_(tempfile, tempfilename); + + return true; +} + +void cleanup_tempfile_(FILE **tempfile, char **tempfilename) +{ + if(0 != *tempfile) { + (void)fclose(*tempfile); + *tempfile = 0; + } + + if(0 != *tempfilename) { + (void)flac_unlink(*tempfilename); + free(*tempfilename); + *tempfilename = 0; + } +} + +FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + return (0 == flac_stat(filename, stats)); +} + +void set_file_stats_(const char *filename, struct flac_stat_s *stats) +{ +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32) + struct timespec srctime[2] = {}; + srctime[0].tv_sec = stats->st_atime; + srctime[1].tv_sec = stats->st_mtime; +#else + struct utimbuf srctime; + srctime.actime = stats->st_atime; + srctime.modtime = stats->st_mtime; +#endif + + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + + (void)flac_chmod(filename, stats->st_mode); + (void)flac_utime(filename, &srctime); +#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__ + FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1)); + FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid)); +#endif +} + +int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence) +{ + return fseeko((FILE*)handle, (FLAC__off_t)offset, whence); +} + +FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle) +{ + return ftello((FILE*)handle); +} + +FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status) +{ + switch(status) { + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK: + return FLAC__METADATA_CHAIN_STATUS_OK; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT: + return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE: + return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE: + return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE: + return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA: + return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR: + return FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR: + return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR: + return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR: + return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR: + return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR: + return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR: + default: + return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + } +} diff --git a/vendor/flac/src/libFLAC/metadata_object.c b/vendor/flac/src/libFLAC/metadata_object.c new file mode 100644 index 0000000..73e7607 --- /dev/null +++ b/vendor/flac/src/libFLAC/metadata_object.c @@ -0,0 +1,2018 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "private/metadata.h" +#include "private/memory.h" +#include "private/stream_encoder_framing.h" + +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "share/alloc.h" +#include "share/compat.h" + +/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ +#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p + + +/**************************************************************************** + * + * Local routines + * + ***************************************************************************/ + +/* copy bytes: + * from = NULL && bytes = 0 + * to <- NULL + * from != NULL && bytes > 0 + * to <- copy of from + * else ASSERT + * malloc error leaves 'to' unchanged + */ +static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes) +{ + FLAC__ASSERT(to != NULL); + if (bytes > 0 && from != NULL) { + FLAC__byte *x; + if ((x = safe_malloc_(bytes)) == NULL) + return false; + memcpy(x, from, bytes); + *to = x; + } + else { + *to = 0; + } + return true; +} + +#if 0 /* UNUSED */ +/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */ +static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes) +{ + FLAC__byte *copy; + FLAC__ASSERT(to != NULL); + if (copy_bytes_(©, from, bytes)) { + free(*to); + *to = copy; + return true; + } + else + return false; +} +#endif + +/* reallocate entry to 1 byte larger and add a terminating NUL */ +/* realloc() failure leaves entry unchanged */ +static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length) +{ + FLAC__byte *x = safe_realloc_nofree_add_2op_(*entry, length, /*+*/1); + if (x != NULL) { + x[length] = '\0'; + *entry = x; + return true; + } + else + return false; +} + +/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to' + * unchanged if malloc fails, free()ing the original '*to' if it + * succeeds and the original '*to' was not NULL + */ +static FLAC__bool copy_cstring_(char **to, const char *from) +{ + char *copy = strdup(from); + FLAC__ASSERT(to != NULL); + if (copy) { + free(*to); + *to = copy; + return true; + } + else + return false; +} + +static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from) +{ + to->length = from->length; + if (from->entry == 0) { + FLAC__ASSERT(from->length == 0); + if ((to->entry = safe_malloc_(1)) == NULL) + return false; + to->entry[0] = '\0'; + } + else { + FLAC__byte *x; + if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL) + return false; + memcpy(x, from->entry, from->length); + x[from->length] = '\0'; + to->entry = x; + } + return true; +} + +static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from) +{ + memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track)); + if (from->indices == 0) { + FLAC__ASSERT(from->num_indices == 0); + } + else { + FLAC__StreamMetadata_CueSheet_Index *x; + FLAC__ASSERT(from->num_indices > 0); + if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL) + return false; + memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); + to->indices = x; + } + return true; +} + +static void seektable_calculate_length_(FLAC__StreamMetadata *object) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; +} + +static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points) +{ + FLAC__StreamMetadata_SeekPoint *object_array; + + FLAC__ASSERT(num_points > 0); + + object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)); + + if (object_array != NULL) { + uint32_t i; + for (i = 0; i < num_points; i++) { + object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + object_array[i].stream_offset = 0; + object_array[i].frame_samples = 0; + } + } + + return object_array; +} + +static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object) +{ + uint32_t i; + + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8; + object->length += object->data.vorbis_comment.vendor_string.length; + object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8; + for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { + object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8); + object->length += object->data.vorbis_comment.comments[i].length; + } +} + +static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments) +{ + FLAC__ASSERT(num_comments > 0); + + return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); +} + +static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) +{ + uint32_t i; + + FLAC__ASSERT(object_array != NULL); + + for (i = 0; i < num_comments; i++) + free(object_array[i].entry); + + free(object_array); +} + +static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) +{ + FLAC__StreamMetadata_VorbisComment_Entry *return_array; + + FLAC__ASSERT(object_array != NULL); + FLAC__ASSERT(num_comments > 0); + + return_array = vorbiscomment_entry_array_new_(num_comments); + + if (return_array != NULL) { + uint32_t i; + + for (i = 0; i < num_comments; i++) { + if (!copy_vcentry_(return_array+i, object_array+i)) { + vorbiscomment_entry_array_delete_(return_array, num_comments); + return 0; + } + } + } + + return return_array; +} + +static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy) +{ + FLAC__byte *save; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(dest != NULL); + FLAC__ASSERT(src != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0)); + + save = dest->entry; + + if (src->entry != NULL) { + if (copy) { + /* do the copy first so that if we fail we leave the dest object untouched */ + if (!copy_vcentry_(dest, src)) + return false; + } + else { + /* we have to make sure that the string we're taking over is null-terminated */ + + /* + * Stripping the const from src->entry is OK since we're taking + * ownership of the pointer. This is a hack around a deficiency + * in the API where the same function is used for 'copy' and + * 'own', but the source entry is a const pointer. If we were + * precise, the 'own' flavor would be a separate function with a + * non-const source pointer. But it's not, so we hack away. + */ + if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length)) + return false; + *dest = *src; + } + } + else { + /* the src is null */ + *dest = *src; + } + + free(save); + + vorbiscomment_calculate_length_(object); + return true; +} + +static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length) +{ + uint32_t i; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(field_name != NULL); + + for (i = offset; i < object->data.vorbis_comment.num_comments; i++) { + if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) + return (int)i; + } + + return -1; +} + +static void cuesheet_calculate_length_(FLAC__StreamMetadata *object) +{ + uint32_t i; + + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + object->length = ( + FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN + ) / 8; + + object->length += object->data.cue_sheet.num_tracks * ( + FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN + ) / 8; + + for (i = 0; i < object->data.cue_sheet.num_tracks; i++) { + object->length += object->data.cue_sheet.tracks[i].num_indices * ( + FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN + ) / 8; + } +} + +static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices) +{ + FLAC__ASSERT(num_indices > 0); + + return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)); +} + +static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks) +{ + FLAC__ASSERT(num_tracks > 0); + + return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); +} + +static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) +{ + uint32_t i; + + FLAC__ASSERT(object_array != NULL && num_tracks > 0); + + for (i = 0; i < num_tracks; i++) { + if (object_array[i].indices != 0) { + FLAC__ASSERT(object_array[i].num_indices > 0); + free(object_array[i].indices); + } + } + + free(object_array); +} + +static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) +{ + FLAC__StreamMetadata_CueSheet_Track *return_array; + + FLAC__ASSERT(object_array != NULL); + FLAC__ASSERT(num_tracks > 0); + + return_array = cuesheet_track_array_new_(num_tracks); + + if (return_array != NULL) { + uint32_t i; + + for (i = 0; i < num_tracks; i++) { + if (!copy_track_(return_array+i, object_array+i)) { + cuesheet_track_array_delete_(return_array, num_tracks); + return 0; + } + } + } + + return return_array; +} + +static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy) +{ + FLAC__StreamMetadata_CueSheet_Index *save; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(dest != NULL); + FLAC__ASSERT(src != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && src->num_indices == 0)); + + save = dest->indices; + + /* do the copy first so that if we fail we leave the object untouched */ + if (copy) { + if (!copy_track_(dest, src)) + return false; + } + else { + *dest = *src; + } + + free(save); + + cuesheet_calculate_length_(object); + return true; +} + + +/**************************************************************************** + * + * Metadata object routines + * + ***************************************************************************/ + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type) +{ + FLAC__StreamMetadata *object; + + if (type > FLAC__MAX_METADATA_TYPE) + return 0; + + object = calloc(1, sizeof(FLAC__StreamMetadata)); + if (object != NULL) { + object->is_last = false; + object->type = type; + switch(type) { + case FLAC__METADATA_TYPE_STREAMINFO: + object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + break; + case FLAC__METADATA_TYPE_PADDING: + /* calloc() took care of this for us: + object->length = 0; + */ + break; + case FLAC__METADATA_TYPE_APPLICATION: + object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + /* calloc() took care of this for us: + object->data.application.data = 0; + */ + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + /* calloc() took care of this for us: + object->length = 0; + object->data.seek_table.num_points = 0; + object->data.seek_table.points = 0; + */ + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING); + if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { + free(object); + return 0; + } + vorbiscomment_calculate_length_(object); + break; + case FLAC__METADATA_TYPE_CUESHEET: + cuesheet_calculate_length_(object); + break; + case FLAC__METADATA_TYPE_PICTURE: + object->length = ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + + 0 /* no data */ + ) / 8; + object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; + object->data.picture.mime_type = 0; + object->data.picture.description = 0; + /* calloc() took care of this for us: + object->data.picture.width = 0; + object->data.picture.height = 0; + object->data.picture.depth = 0; + object->data.picture.colors = 0; + object->data.picture.data_length = 0; + object->data.picture.data = 0; + */ + /* now initialize mime_type and description with empty strings to make things easier on the client */ + if (!copy_cstring_(&object->data.picture.mime_type, "")) { + free(object); + return 0; + } + if (!copy_cstring_((char**)(&object->data.picture.description), "")) { + free(object->data.picture.mime_type); + free(object); + return 0; + } + break; + default: + /* calloc() took care of this for us: + object->length = 0; + object->data.unknown.data = 0; + */ + break; + } + } + + return object; +} + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object) +{ + FLAC__StreamMetadata *to; + + FLAC__ASSERT(object != NULL); + + if ((to = FLAC__metadata_object_new(object->type)) != NULL) { + to->is_last = object->is_last; + to->type = object->type; + to->length = object->length; + switch(to->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo)); + break; + case FLAC__METADATA_TYPE_PADDING: + break; + case FLAC__METADATA_TYPE_APPLICATION: + if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */ + FLAC__metadata_object_delete(to); + return 0; + } + memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8); + if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) { + FLAC__metadata_object_delete(to); + return 0; + } + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + to->data.seek_table.num_points = object->data.seek_table.num_points; + if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */ + FLAC__metadata_object_delete(to); + return 0; + } + if (!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) { + FLAC__metadata_object_delete(to); + return 0; + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if (to->data.vorbis_comment.vendor_string.entry != NULL) { + free(to->data.vorbis_comment.vendor_string.entry); + to->data.vorbis_comment.vendor_string.entry = 0; + } + if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) { + FLAC__metadata_object_delete(to); + return 0; + } + if (object->data.vorbis_comment.num_comments == 0) { + to->data.vorbis_comment.comments = 0; + } + else { + to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); + if (to->data.vorbis_comment.comments == NULL) { + to->data.vorbis_comment.num_comments = 0; + FLAC__metadata_object_delete(to); + return 0; + } + } + to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments; + break; + case FLAC__METADATA_TYPE_CUESHEET: + memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet)); + if (object->data.cue_sheet.num_tracks == 0) { + FLAC__ASSERT(object->data.cue_sheet.tracks == NULL); + } + else { + FLAC__ASSERT(object->data.cue_sheet.tracks != 0); + to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); + if (to->data.cue_sheet.tracks == NULL) { + FLAC__metadata_object_delete(to); + return 0; + } + } + break; + case FLAC__METADATA_TYPE_PICTURE: + to->data.picture.type = object->data.picture.type; + if (!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) { + FLAC__metadata_object_delete(to); + return 0; + } + if (!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) { + FLAC__metadata_object_delete(to); + return 0; + } + to->data.picture.width = object->data.picture.width; + to->data.picture.height = object->data.picture.height; + to->data.picture.depth = object->data.picture.depth; + to->data.picture.colors = object->data.picture.colors; + to->data.picture.data_length = object->data.picture.data_length; + if (!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) { + FLAC__metadata_object_delete(to); + return 0; + } + break; + default: + if (!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) { + FLAC__metadata_object_delete(to); + return 0; + } + break; + } + } + + return to; +} + +void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object) +{ + FLAC__ASSERT(object != NULL); + + switch(object->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + case FLAC__METADATA_TYPE_PADDING: + break; + case FLAC__METADATA_TYPE_APPLICATION: + if (object->data.application.data != NULL) { + free(object->data.application.data); + object->data.application.data = NULL; + } + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + if (object->data.seek_table.points != NULL) { + free(object->data.seek_table.points); + object->data.seek_table.points = NULL; + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if (object->data.vorbis_comment.vendor_string.entry != NULL) { + free(object->data.vorbis_comment.vendor_string.entry); + object->data.vorbis_comment.vendor_string.entry = 0; + } + if (object->data.vorbis_comment.comments != NULL) { + vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); + object->data.vorbis_comment.comments = NULL; + object->data.vorbis_comment.num_comments = 0; + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + if (object->data.cue_sheet.tracks != NULL) { + FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); + cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); + object->data.cue_sheet.tracks = NULL; + object->data.cue_sheet.num_tracks = 0; + } + break; + case FLAC__METADATA_TYPE_PICTURE: + if (object->data.picture.mime_type != NULL) { + free(object->data.picture.mime_type); + object->data.picture.mime_type = NULL; + } + if (object->data.picture.description != NULL) { + free(object->data.picture.description); + object->data.picture.description = NULL; + } + if (object->data.picture.data != NULL) { + free(object->data.picture.data); + object->data.picture.data = NULL; + } + break; + default: + if (object->data.unknown.data != NULL) { + free(object->data.unknown.data); + object->data.unknown.data = NULL; + } + break; + } +} + +FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object) +{ + FLAC__metadata_object_delete_data(object); + free(object); +} + +static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2) +{ + if (block1->min_blocksize != block2->min_blocksize) + return false; + if (block1->max_blocksize != block2->max_blocksize) + return false; + if (block1->min_framesize != block2->min_framesize) + return false; + if (block1->max_framesize != block2->max_framesize) + return false; + if (block1->sample_rate != block2->sample_rate) + return false; + if (block1->channels != block2->channels) + return false; + if (block1->bits_per_sample != block2->bits_per_sample) + return false; + if (block1->total_samples != block2->total_samples) + return false; + if (memcmp(block1->md5sum, block2->md5sum, 16) != 0) + return false; + return true; +} + +static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length) +{ + FLAC__ASSERT(block1 != NULL); + FLAC__ASSERT(block2 != NULL); + FLAC__ASSERT(block_length >= sizeof(block1->id)); + + if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0) + return false; + if (block1->data != NULL && block2->data != NULL) + return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0; + else + return block1->data == block2->data; +} + +static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2) +{ + uint32_t i; + + FLAC__ASSERT(block1 != NULL); + FLAC__ASSERT(block2 != NULL); + + if (block1->num_points != block2->num_points) + return false; + + if (block1->points != NULL && block2->points != NULL) { + for (i = 0; i < block1->num_points; i++) { + if (block1->points[i].sample_number != block2->points[i].sample_number) + return false; + if (block1->points[i].stream_offset != block2->points[i].stream_offset) + return false; + if (block1->points[i].frame_samples != block2->points[i].frame_samples) + return false; + } + return true; + } + else + return block1->points == block2->points; +} + +static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2) +{ + uint32_t i; + + if (block1->vendor_string.length != block2->vendor_string.length) + return false; + + if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) { + if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0) + return false; + } + else if (block1->vendor_string.entry != block2->vendor_string.entry) + return false; + + if (block1->num_comments != block2->num_comments) + return false; + + for (i = 0; i < block1->num_comments; i++) { + if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) { + if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0) + return false; + } + else if (block1->comments[i].entry != block2->comments[i].entry) + return false; + } + return true; +} + +static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2) +{ + uint32_t i, j; + + if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0) + return false; + + if (block1->lead_in != block2->lead_in) + return false; + + if (block1->is_cd != block2->is_cd) + return false; + + if (block1->num_tracks != block2->num_tracks) + return false; + + if (block1->tracks != NULL && block2->tracks != NULL) { + FLAC__ASSERT(block1->num_tracks > 0); + for (i = 0; i < block1->num_tracks; i++) { + if (block1->tracks[i].offset != block2->tracks[i].offset) + return false; + if (block1->tracks[i].number != block2->tracks[i].number) + return false; + if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0) + return false; + if (block1->tracks[i].type != block2->tracks[i].type) + return false; + if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis) + return false; + if (block1->tracks[i].num_indices != block2->tracks[i].num_indices) + return false; + if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) { + FLAC__ASSERT(block1->tracks[i].num_indices > 0); + for (j = 0; j < block1->tracks[i].num_indices; j++) { + if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset) + return false; + if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number) + return false; + } + } + else if (block1->tracks[i].indices != block2->tracks[i].indices) + return false; + } + } + else if (block1->tracks != block2->tracks) + return false; + return true; +} + +static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2) +{ + if (block1->type != block2->type) + return false; + if (block1->mime_type != block2->mime_type && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type))) + return false; + if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || strcmp((const char *)block1->description, (const char *)block2->description))) + return false; + if (block1->width != block2->width) + return false; + if (block1->height != block2->height) + return false; + if (block1->depth != block2->depth) + return false; + if (block1->colors != block2->colors) + return false; + if (block1->data_length != block2->data_length) + return false; + if (block1->data != block2->data && (block1->data == NULL || block2->data == NULL || memcmp(block1->data, block2->data, block1->data_length))) + return false; + return true; +} + +static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, uint32_t block_length) +{ + FLAC__ASSERT(block1 != NULL); + FLAC__ASSERT(block2 != NULL); + + if (block1->data != NULL && block2->data != NULL) + return memcmp(block1->data, block2->data, block_length) == 0; + else + return block1->data == block2->data; +} + +FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2) +{ + FLAC__ASSERT(block1 != NULL); + FLAC__ASSERT(block2 != NULL); + + if (block1->type != block2->type) { + return false; + } + if (block1->is_last != block2->is_last) { + return false; + } + if (block1->length != block2->length) { + return false; + } + switch(block1->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info); + case FLAC__METADATA_TYPE_PADDING: + return true; /* we don't compare the padding guts */ + case FLAC__METADATA_TYPE_APPLICATION: + return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length); + case FLAC__METADATA_TYPE_SEEKTABLE: + return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table); + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment); + case FLAC__METADATA_TYPE_CUESHEET: + return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return compare_block_data_picture_(&block1->data.picture, &block2->data.picture); + default: + return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length); + } +} + +FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy) +{ + FLAC__byte *save; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION); + FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); + + save = object->data.application.data; + + /* do the copy first so that if we fail we leave the object untouched */ + if (copy) { + if (!copy_bytes_(&object->data.application.data, data, length)) + return false; + } + else { + object->data.application.data = data; + } + + free(save); + + object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if((FLAC__uint64)(new_num_points) * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; + + if (object->data.seek_table.points == 0) { + FLAC__ASSERT(object->data.seek_table.num_points == 0); + if (new_num_points == 0) + return true; + else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0) + return false; + } + else { + const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint); + const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint); + + /* overflow check */ + if (new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) + return false; + + FLAC__ASSERT(object->data.seek_table.num_points > 0); + + if (new_size == 0) { + free(object->data.seek_table.points); + object->data.seek_table.points = 0; + } + else { + /* Leave object->data.seek_table.points untouched if realloc fails */ + FLAC__StreamMetadata_SeekPoint *tmpptr; + if ((tmpptr = realloc(object->data.seek_table.points, new_size)) == NULL) + return false; + object->data.seek_table.points = tmpptr; + } + + /* if growing, set new elements to placeholders */ + if (new_size > old_size) { + uint32_t i; + for (i = object->data.seek_table.num_points; i < new_num_points; i++) { + object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + object->data.seek_table.points[i].stream_offset = 0; + object->data.seek_table.points[i].frame_samples = 0; + } + } + } + + object->data.seek_table.num_points = new_num_points; + + seektable_calculate_length_(object); + return true; +} + +FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(point_num < object->data.seek_table.num_points); + + object->data.seek_table.points[point_num] = point; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) +{ + int i; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(point_num <= object->data.seek_table.num_points); + + if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1)) + return false; + + /* move all points >= point_num forward one space */ + for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--) + object->data.seek_table.points[i] = object->data.seek_table.points[i-1]; + + FLAC__metadata_object_seektable_set_point(object, point_num, point); + seektable_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num) +{ + uint32_t i; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(point_num < object->data.seek_table.num_points); + + /* move all points > point_num backward one space */ + for (i = point_num; i < object->data.seek_table.num_points-1; i++) + object->data.seek_table.points[i] = object->data.seek_table.points[i+1]; + + return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1); +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + return FLAC__format_seektable_is_legal(&object->data.seek_table); +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if (num > 0) + /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */ + return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num); + else + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number) +{ + FLAC__StreamMetadata_SeekTable *seek_table; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + seek_table = &object->data.seek_table; + + if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1)) + return false; + + seek_table->points[seek_table->num_points - 1].sample_number = sample_number; + seek_table->points[seek_table->num_points - 1].stream_offset = 0; + seek_table->points[seek_table->num_points - 1].frame_samples = 0; + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(sample_numbers != 0 || num == 0); + + if (num > 0) { + FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; + uint32_t i, j; + + i = seek_table->num_points; + + if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) + return false; + + for (j = 0; j < num; i++, j++) { + seek_table->points[i].sample_number = sample_numbers[j]; + seek_table->points[i].stream_offset = 0; + seek_table->points[i].frame_samples = 0; + } + } + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if (num > 0 && total_samples > 0) { + FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; + uint32_t i, j; + + i = seek_table->num_points; + + if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) + return false; + + for (j = 0; j < num; i++, j++) { + seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num; + seek_table->points[i].stream_offset = 0; + seek_table->points[i].frame_samples = 0; + } + } + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if (samples > 0 && total_samples > 0) { + FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; + uint32_t i, j; + FLAC__uint64 num, sample; + + num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */ + /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */ + if (total_samples % samples == 0) + num--; + + /* Put a strict upper bound on the number of allowed seek points. */ + if (num > 32768) { + /* Set the bound and recalculate samples accordingly. */ + num = 32768; + samples = (uint32_t)(total_samples / num); + } + + i = seek_table->num_points; + + if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)num)) + return false; + + sample = 0; + for (j = 0; j < num; i++, j++, sample += samples) { + seek_table->points[i].sample_number = sample; + seek_table->points[i].stream_offset = 0; + seek_table->points[i].frame_samples = 0; + } + } + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact) +{ + uint32_t unique; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + unique = FLAC__format_seektable_sort(&object->data.seek_table); + + return !compact || FLAC__metadata_object_seektable_resize_points(object, unique); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) +{ + if (!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length)) + return false; + return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + if (object->data.vorbis_comment.comments == NULL) { + FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0); + if (new_num_comments == 0) + return true; + else { + uint32_t i; + if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL) + return false; + for (i = 0; i < new_num_comments; i++) { + object->data.vorbis_comment.comments[i].length = 0; + if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) { + object->data.vorbis_comment.num_comments = i+1; + return false; + } + object->data.vorbis_comment.comments[i].entry[0] = '\0'; + } + } + } + else { + const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); + const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); + + /* overflow check */ + if (new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry)) + return false; + + FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); + + /* if shrinking, free the truncated entries */ + if (new_num_comments < object->data.vorbis_comment.num_comments) { + uint32_t i; + for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++) + if (object->data.vorbis_comment.comments[i].entry != NULL) + free(object->data.vorbis_comment.comments[i].entry); + } + + if (new_size == 0) { + free(object->data.vorbis_comment.comments); + object->data.vorbis_comment.comments = 0; + } + else { + /* Leave object->data.vorbis_comment.comments untouched if realloc fails */ + FLAC__StreamMetadata_VorbisComment_Entry *tmpptr; + if ((tmpptr = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) + return false; + object->data.vorbis_comment.comments = tmpptr; + } + + /* if growing, zero all the length/pointers of new elements */ + if (new_size > old_size) { + uint32_t i; + for (i = object->data.vorbis_comment.num_comments; i < new_num_comments; i++) { + object->data.vorbis_comment.comments[i].length = 0; + if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) { + object->data.vorbis_comment.num_comments = i+1; + return false; + } + object->data.vorbis_comment.comments[i].entry[0] = '\0'; + } + } + } + + object->data.vorbis_comment.num_comments = new_num_comments; + + vorbiscomment_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); + + if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; + return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) +{ + FLAC__StreamMetadata_VorbisComment *vc; + FLAC__StreamMetadata_VorbisComment_Entry temp; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments); + + if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; + + vc = &object->data.vorbis_comment; + + if (!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1)) + return false; + + /* move all comments >= comment_num forward one space */ + /* reuse newly added empty comment */ + temp = vc->comments[vc->num_comments-1]; + memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num)); + vc->comments[comment_num] = temp; + + return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy) +{ + FLAC__ASSERT(entry.entry != NULL); + + if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; + + { + int i; + size_t field_name_length; + const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); + + if (eq == NULL) + return false; /* double protection */ + + field_name_length = eq-entry.entry; + + i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length); + if (i >= 0) { + uint32_t indx = (uint32_t)i; + if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy)) + return false; + entry = object->data.vorbis_comment.comments[indx]; + indx++; /* skip over replaced comment */ + if (all && indx < object->data.vorbis_comment.num_comments) { + i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); + while (i >= 0) { + indx = (uint32_t)i; + if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx)) + return false; + if (indx < object->data.vorbis_comment.num_comments) + i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); + else + i = -1; + } + } + return true; + } + else + return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy); + } +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num) +{ + FLAC__StreamMetadata_VorbisComment *vc; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); + + vc = &object->data.vorbis_comment; + + /* free the comment at comment_num */ + free(vc->comments[comment_num].entry); + + /* move all comments > comment_num backward one space */ + memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1)); + vc->comments[vc->num_comments-1].length = 0; + vc->comments[vc->num_comments-1].entry = 0; + + return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value) +{ + FLAC__ASSERT(entry != NULL); + FLAC__ASSERT(field_name != NULL); + FLAC__ASSERT(field_value != NULL); + + if (!FLAC__format_vorbiscomment_entry_name_is_legal(field_name)) + return false; + if (!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (uint32_t)(-1))) + return false; + + { + const size_t nn = strlen(field_name); + const size_t nv = strlen(field_value); + entry->length = nn + 1 /*=*/ + nv; + if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL) + return false; + memcpy(entry->entry, field_name, nn); + entry->entry[nn] = '='; + memcpy(entry->entry+nn+1, field_value, nv); + entry->entry[entry->length] = '\0'; + } + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value) +{ + FLAC__ASSERT(entry.entry != NULL); + FLAC__ASSERT(field_name != NULL); + FLAC__ASSERT(field_value != NULL); + + if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; + + { + const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); + const size_t nn = eq-entry.entry; + const size_t nv = entry.length-nn-1; /* -1 for the '=' */ + + if (eq == NULL) + return false; /* double protection */ + if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL) + return false; + if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) { + free(*field_name); + return false; + } + memcpy(*field_name, entry.entry, nn); + memcpy(*field_value, entry.entry+nn+1, nv); + (*field_name)[nn] = '\0'; + (*field_value)[nv] = '\0'; + } + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length) +{ + FLAC__ASSERT(entry.entry != NULL); + { + const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); + return (eq != NULL && (uint32_t)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0); + } +} + +FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name) +{ + FLAC__ASSERT(field_name != NULL); + + return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name)); +} + +FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name) +{ + const uint32_t field_name_length = strlen(field_name); + uint32_t i; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { + if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { + if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i)) + return -1; + else + return 1; + } + } + + return 0; +} + +FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name) +{ + FLAC__bool ok = true; + uint32_t matching = 0; + const uint32_t field_name_length = strlen(field_name); + int i; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + /* must delete from end to start otherwise it will interfere with our iteration */ + for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) { + if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { + matching++; + ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (uint32_t)i); + } + } + + return ok? (int)matching : -1; +} + +FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void) +{ + return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track)); +} + +FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object) +{ + FLAC__StreamMetadata_CueSheet_Track *to; + + FLAC__ASSERT(object != NULL); + + if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) { + if (!copy_track_(to, object)) { + FLAC__metadata_object_cuesheet_track_delete(to); + return 0; + } + } + + return to; +} + +void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object) +{ + FLAC__ASSERT(object != NULL); + + if (object->indices != NULL) { + FLAC__ASSERT(object->num_indices > 0); + free(object->indices); + } +} + +FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object) +{ + FLAC__metadata_object_cuesheet_track_delete_data(object); + free(object); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices) +{ + FLAC__StreamMetadata_CueSheet_Track *track; + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + + track = &object->data.cue_sheet.tracks[track_num]; + + if (track->indices == NULL) { + FLAC__ASSERT(track->num_indices == 0); + if (new_num_indices == 0) + return true; + else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL) + return false; + } + else { + const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); + const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); + + /* overflow check */ + if (new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index)) + return false; + + FLAC__ASSERT(track->num_indices > 0); + + if (new_size == 0) { + free(track->indices); + track->indices = 0; + } + else { + /* Leave track->indices untouched if realloc fails */ + FLAC__StreamMetadata_CueSheet_Index *tmpptr; + if ((tmpptr = realloc(track->indices, new_size)) == NULL) + return false; + track->indices = tmpptr; + } + + /* if growing, zero all the lengths/pointers of new elements */ + if (new_size > old_size) + memset(track->indices + track->num_indices, 0, new_size - old_size); + } + + track->num_indices = new_num_indices; + + cuesheet_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index indx) +{ + FLAC__StreamMetadata_CueSheet_Track *track; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices); + + track = &object->data.cue_sheet.tracks[track_num]; + + if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1)) + return false; + + /* move all indices >= index_num forward one space */ + memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num)); + + track->indices[index_num] = indx; + cuesheet_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num) +{ + FLAC__StreamMetadata_CueSheet_Index indx; + memset(&indx, 0, sizeof(indx)); + return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num) +{ + FLAC__StreamMetadata_CueSheet_Track *track; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices); + + track = &object->data.cue_sheet.tracks[track_num]; + + /* move all indices > index_num backward one space */ + memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1)); + + FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1); + cuesheet_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + if (object->data.cue_sheet.tracks == NULL) { + FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0); + if (new_num_tracks == 0) + return true; + else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL) + return false; + } + else { + const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); + const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); + + /* overflow check */ + if (new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track)) + return false; + + FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); + + /* if shrinking, free the truncated entries */ + if (new_num_tracks < object->data.cue_sheet.num_tracks) { + uint32_t i; + for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++) + free(object->data.cue_sheet.tracks[i].indices); + } + + if (new_size == 0) { + free(object->data.cue_sheet.tracks); + object->data.cue_sheet.tracks = 0; + } + else { + /* Leave object->data.cue_sheet.tracks untouched if realloc fails */ + FLAC__StreamMetadata_CueSheet_Track *tmpptr; + if ((tmpptr = realloc(object->data.cue_sheet.tracks, new_size)) == NULL) + return false; + object->data.cue_sheet.tracks = tmpptr; + } + + /* if growing, zero all the lengths/pointers of new elements */ + if (new_size > old_size) + memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size); + } + + object->data.cue_sheet.num_tracks = new_num_tracks; + + cuesheet_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + + return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy) +{ + FLAC__StreamMetadata_CueSheet *cs; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks); + + cs = &object->data.cue_sheet; + + if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1)) + return false; + + /* move all tracks >= track_num forward one space */ + memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num)); + cs->tracks[track_num].num_indices = 0; + cs->tracks[track_num].indices = 0; + + return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num) +{ + FLAC__StreamMetadata_CueSheet_Track track; + memset(&track, 0, sizeof(track)); + return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num) +{ + FLAC__StreamMetadata_CueSheet *cs; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + + cs = &object->data.cue_sheet; + + /* free the track at track_num */ + free(cs->tracks[track_num].indices); + + /* move all tracks > track_num backward one space */ + memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1)); + cs->tracks[cs->num_tracks-1].num_indices = 0; + cs->tracks[cs->num_tracks-1].indices = 0; + + return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation); +} + +static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, uint32_t track) +{ + if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1) + return 0; + else if (cs->tracks[track].indices[0].number == 1) + return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in; + else if (cs->tracks[track].num_indices < 2) + return 0; + else if (cs->tracks[track].indices[1].number == 1) + return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in; + else + return 0; +} + +static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x) +{ + FLAC__uint32 n = 0; + while (x) { + n += (x%10); + x /= 10; + } + return n; +} + +/*@@@@add to tests*/ +FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object) +{ + const FLAC__StreamMetadata_CueSheet *cs; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + cs = &object->data.cue_sheet; + + if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */ + return 0; + + { + FLAC__uint32 i, length, sum = 0; + for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */ + sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100)); + length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100); + + return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1); + } +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy) +{ + char *old; + size_t old_length, new_length; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT(mime_type != NULL); + + old = object->data.picture.mime_type; + old_length = old? strlen(old) : 0; + new_length = strlen(mime_type); + + /* do the copy first so that if we fail we leave the object untouched */ + if (copy) { + if (new_length >= SIZE_MAX) /* overflow check */ + return false; + if (!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1)) + return false; + } + else { + object->data.picture.mime_type = mime_type; + } + + free(old); + + object->length -= old_length; + object->length += new_length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy) +{ + FLAC__byte *old; + size_t old_length, new_length; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT(description != NULL); + + old = object->data.picture.description; + old_length = old? strlen((const char *)old) : 0; + new_length = strlen((const char *)description); + + /* do the copy first so that if we fail we leave the object untouched */ + if (copy) { + if (new_length >= SIZE_MAX) /* overflow check */ + return false; + if (!copy_bytes_(&object->data.picture.description, description, new_length+1)) + return false; + } + else { + object->data.picture.description = description; + } + + free(old); + + object->length -= old_length; + object->length += new_length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy) +{ + FLAC__byte *old; + + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); + + old = object->data.picture.data; + + /* do the copy first so that if we fail we leave the object untouched */ + if (copy) { + if (!copy_bytes_(&object->data.picture.data, data, length)) + return false; + } + else { + object->data.picture.data = data; + } + + free(old); + + object->length -= object->data.picture.data_length; + object->data.picture.data_length = length; + object->length += length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation) +{ + FLAC__ASSERT(object != NULL); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + + return FLAC__format_picture_is_legal(&object->data.picture, violation); +} + +FLAC_API FLAC__byte * FLAC__metadata_object_get_raw(const FLAC__StreamMetadata *object) +{ + FLAC__BitWriter *bw; + const FLAC__byte * buffer; + FLAC__byte * output; + size_t bytes; + + FLAC__ASSERT(object != NULL); + + if((bw = FLAC__bitwriter_new()) == NULL) + return 0; + if(!FLAC__bitwriter_init(bw)) { + FLAC__bitwriter_delete(bw); + return 0; + } + if(!FLAC__add_metadata_block(object, bw, false)) { + FLAC__bitwriter_delete(bw); + return 0; + } + + if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) { + FLAC__bitwriter_delete(bw); + return 0; + } + + /* Extra check whether length of bitwriter agrees with length of metadata block */ + if(bytes != (object->length+FLAC__STREAM_METADATA_HEADER_LENGTH)) { + FLAC__bitwriter_delete(bw); + return 0; + } + + output = safe_malloc_(bytes); + if(output == 0) { + FLAC__bitwriter_delete(bw); + return 0; + } + + memcpy(output,buffer,bytes); + FLAC__bitwriter_delete(bw); + return output; +} + +/* The following callbacks are for FLAC__metadata_object_set_raw */ + +static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte *buffer, size_t *bytes, void *client_data); +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +typedef struct { + FLAC__StreamMetadata *object; + FLAC__bool got_error; + FLAC__byte *buffer; + FLAC__int32 length; + FLAC__int32 tell; +} set_raw_client_data; + +FLAC_API FLAC__StreamMetadata * FLAC__metadata_object_set_raw(FLAC__byte *buffer, FLAC__uint32 length) +{ + set_raw_client_data cd; + FLAC__StreamDecoder * decoder; + + cd.buffer = buffer; + cd.length = length; + cd.got_error = false; + cd.object = 0; + cd.tell = -4; + + decoder = FLAC__stream_decoder_new(); + + if(0 == decoder) + return 0; + + FLAC__stream_decoder_set_md5_checking(decoder, false); + FLAC__stream_decoder_set_metadata_respond_all(decoder); + + if(FLAC__stream_decoder_init_stream(decoder, read_callback_, NULL, NULL, NULL, NULL, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + return 0; + } + + if((!FLAC__stream_decoder_process_until_end_of_metadata(decoder) && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM) || cd.got_error) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + if(0 != cd.object) + FLAC__metadata_object_delete(cd.object); + return 0; + } + + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + + return cd.object; + +} + +FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte *buffer, size_t *bytes, void *client_data) +{ + set_raw_client_data *cd = (set_raw_client_data *)client_data; + (void)decoder; + + if(cd->tell == -4) { + if(*bytes < 4) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + buffer[0] = 'f'; + buffer[1] = 'L'; + buffer[2] = 'a'; + buffer[3] = 'C'; + *bytes = 4; + cd->tell = 0; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else if(cd->tell < 0) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + else if(cd->tell == cd->length) { + *bytes = 0; + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + else { + if((FLAC__int32)(*bytes) > (cd->length - cd->tell)) + *bytes = cd->length - cd->tell; + memcpy(buffer, cd->buffer+cd->tell, *bytes); + cd->tell += *bytes; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + (void)decoder, (void)frame, (void)buffer, (void)client_data; + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + set_raw_client_data *cd = (set_raw_client_data *)client_data; + (void)decoder; + + /* + * we assume we only get here when the one metadata block we were + * looking for was passed to us + */ + if(!cd->got_error && 0 == cd->object) { + if(0 == (cd->object = FLAC__metadata_object_clone(metadata))) + cd->got_error = true; + } +} + +void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + set_raw_client_data *cd = (set_raw_client_data *)client_data; + (void)decoder; + + if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) + cd->got_error = true; +} diff --git a/vendor/flac/src/libFLAC/ogg_decoder_aspect.c b/vendor/flac/src/libFLAC/ogg_decoder_aspect.c new file mode 100644 index 0000000..58a2934 --- /dev/null +++ b/vendor/flac/src/libFLAC/ogg_decoder_aspect.c @@ -0,0 +1,251 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include /* for memcpy() */ +#include "FLAC/assert.h" +#include "private/ogg_decoder_aspect.h" +#include "private/ogg_mapping.h" +#include "private/macros.h" + + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect) +{ + /* we will determine the serial number later if necessary */ + if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0) + return false; + + if(ogg_sync_init(&aspect->sync_state) != 0) + return false; + + aspect->version_major = ~(0u); + aspect->version_minor = ~(0u); + + aspect->need_serial_number = aspect->use_first_serial_number; + + aspect->end_of_stream = false; + aspect->have_working_page = false; + + return true; +} + +void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect) +{ + (void)ogg_sync_clear(&aspect->sync_state); + (void)ogg_stream_clear(&aspect->stream_state); +} + +void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value) +{ + aspect->use_first_serial_number = false; + aspect->serial_number = value; +} + +void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect) +{ + aspect->use_first_serial_number = true; +} + +void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect) +{ + (void)ogg_stream_reset(&aspect->stream_state); + (void)ogg_sync_reset(&aspect->sync_state); + aspect->end_of_stream = false; + aspect->have_working_page = false; +} + +void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect) +{ + FLAC__ogg_decoder_aspect_flush(aspect); + + if(aspect->use_first_serial_number) + aspect->need_serial_number = true; +} + +FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data) +{ + static const size_t OGG_BYTES_CHUNK = 8192; + const size_t bytes_requested = *bytes; + + /* + * The FLAC decoding API uses pull-based reads, whereas Ogg decoding + * is push-based. In libFLAC, when you ask to decode a frame, the + * decoder will eventually call the read callback to supply some data, + * but how much it asks for depends on how much free space it has in + * its internal buffer. It does not try to grow its internal buffer + * to accommodate a whole frame because then the internal buffer size + * could not be limited, which is necessary in embedded applications. + * + * Ogg however grows its internal buffer until a whole page is present; + * only then can you get decoded data out. So we can't just ask for + * the same number of bytes from Ogg, then pass what's decoded down to + * libFLAC. If what libFLAC is asking for will not contain a whole + * page, then we will get no data from ogg_sync_pageout(), and at the + * same time cannot just read more data from the client for the purpose + * of getting a whole decoded page because the decoded size might be + * larger than libFLAC's internal buffer. + * + * Instead, whenever this read callback wrapper is called, we will + * continually request data from the client until we have at least one + * page, and manage pages internally so that we can send pieces of + * pages down to libFLAC in such a way that we obey its size + * requirement. To limit the amount of callbacks, we will always try + * to read in enough pages to return the full number of bytes + * requested. + */ + *bytes = 0; + while (*bytes < bytes_requested && !aspect->end_of_stream) { + if (aspect->have_working_page) { + if (aspect->have_working_packet) { + size_t n = bytes_requested - *bytes; + if ((size_t)aspect->working_packet.bytes <= n) { + /* the rest of the packet will fit in the buffer */ + n = aspect->working_packet.bytes; + memcpy(buffer, aspect->working_packet.packet, n); + *bytes += n; + buffer += n; + aspect->have_working_packet = false; + } + else { + /* only n bytes of the packet will fit in the buffer */ + memcpy(buffer, aspect->working_packet.packet, n); + *bytes += n; + buffer += n; + aspect->working_packet.packet += n; + aspect->working_packet.bytes -= n; + } + } + else { + /* try and get another packet */ + const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet); + if (ret > 0) { + aspect->have_working_packet = true; + /* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */ + if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) { + const FLAC__byte *b = aspect->working_packet.packet; + const uint32_t header_length = + FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + + FLAC__OGG_MAPPING_MAGIC_LENGTH + + FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + + FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + + FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH; + if (aspect->working_packet.bytes < (long)header_length) + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC; + b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH; + if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH)) + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC; + b += FLAC__OGG_MAPPING_MAGIC_LENGTH; + aspect->version_major = (uint32_t)(*b); + b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH; + aspect->version_minor = (uint32_t)(*b); + if (aspect->version_major != 1) + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION; + aspect->working_packet.packet += header_length; + aspect->working_packet.bytes -= header_length; + } + } + else if (ret == 0) { + aspect->have_working_page = false; + } + else { /* ret < 0 */ + /* lost sync, we'll leave the working page for the next call */ + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC; + } + } + } + else { + /* try and get another page */ + const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page); + if (ret > 0) { + /* got a page, grab the serial number if necessary */ + if(aspect->need_serial_number) { + aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page); + aspect->need_serial_number = false; + } + if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) { + aspect->have_working_page = true; + aspect->have_working_packet = false; + } + /* else do nothing, could be a page from another stream */ + } + else if (ret == 0) { + /* need more data */ + const size_t ogg_bytes_to_read = flac_max(bytes_requested - *bytes, OGG_BYTES_CHUNK); + char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read); + + if(0 == oggbuf) { + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR; + } + else { + size_t ogg_bytes_read = ogg_bytes_to_read; + + switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) { + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK: + break; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM: + aspect->end_of_stream = true; + break; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; + default: + FLAC__ASSERT(0); + } + + if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) { + /* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */ + FLAC__ASSERT(0); + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR; + } + } + } + else { /* ret < 0 */ + /* lost sync, bail out */ + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC; + } + } + } + + if (aspect->end_of_stream && *bytes == 0) { + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM; + } + + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK; +} diff --git a/vendor/flac/src/libFLAC/ogg_encoder_aspect.c b/vendor/flac/src/libFLAC/ogg_encoder_aspect.c new file mode 100644 index 0000000..a88713b --- /dev/null +++ b/vendor/flac/src/libFLAC/ogg_encoder_aspect.c @@ -0,0 +1,228 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include /* for memset() */ +#include "FLAC/assert.h" +#include "private/ogg_encoder_aspect.h" +#include "private/ogg_mapping.h" + +static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MAJOR = 1; +static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MINOR = 0; + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect) +{ + /* we will determine the serial number later if necessary */ + if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0) + return false; + + aspect->seen_magic = false; + aspect->is_first_packet = true; + aspect->samples_written = 0; + + return true; +} + +void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect) +{ + (void)ogg_stream_clear(&aspect->stream_state); + /*@@@ what about the page? */ +} + +void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value) +{ + aspect->serial_number = value; +} + +FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, uint32_t value) +{ + if(value < (1u << FLAC__OGG_MAPPING_NUM_HEADERS_LEN)) { + aspect->num_metadata = value; + return true; + } + else + return false; +} + +void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect) +{ + aspect->serial_number = 0; + aspect->num_metadata = 0; +} + +/* + * The basic FLAC -> Ogg mapping goes like this: + * + * - 'fLaC' magic and STREAMINFO block get combined into the first + * packet. The packet is prefixed with + * + the one-byte packet type 0x7F + * + 'FLAC' magic + * + the 2 byte Ogg FLAC mapping version number + * + tne 2 byte big-endian # of header packets + * - The first packet is flushed to the first page. + * - Each subsequent metadata block goes into its own packet. + * - Each metadata packet is flushed to page (this is not required, + * the mapping only requires that a flush must occur after all + * metadata is written). + * - Each subsequent FLAC audio frame goes into its own packet. + * + * WATCHOUT: + * This depends on the behavior of FLAC__StreamEncoder that we get a + * separate write callback for the fLaC magic, and then separate write + * callbacks for each metadata block and audio frame. + */ +FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data) +{ + /* WATCHOUT: + * This depends on the behavior of FLAC__StreamEncoder that 'samples' + * will be 0 for metadata writes. + */ + const FLAC__bool is_metadata = (samples == 0); + + /* + * Treat fLaC magic packet specially. We will note when we see it, then + * wait until we get the STREAMINFO and prepend it in that packet + */ + if(aspect->seen_magic) { + ogg_packet packet; + FLAC__byte synthetic_first_packet_body[ + FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + + FLAC__OGG_MAPPING_MAGIC_LENGTH + + FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + + FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + + FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH + + FLAC__STREAM_SYNC_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + FLAC__STREAM_METADATA_STREAMINFO_LENGTH + ]; + + memset(&packet, 0, sizeof(packet)); + packet.granulepos = aspect->samples_written + samples; + + if(aspect->is_first_packet) { + FLAC__byte *b = synthetic_first_packet_body; + if(bytes != FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH) { + /* + * If we get here, our assumption about the way write callbacks happen + * (explained above) is wrong + */ + FLAC__ASSERT(0); + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + /* add first header packet type */ + *b = FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; + b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH; + /* add 'FLAC' mapping magic */ + memcpy(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH); + b += FLAC__OGG_MAPPING_MAGIC_LENGTH; + /* add Ogg FLAC mapping major version number */ + memcpy(b, &FLAC__OGG_MAPPING_VERSION_MAJOR, FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH); + b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH; + /* add Ogg FLAC mapping minor version number */ + memcpy(b, &FLAC__OGG_MAPPING_VERSION_MINOR, FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH); + b += FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH; + /* add number of header packets */ + *b = (FLAC__byte)(aspect->num_metadata >> 8); + b++; + *b = (FLAC__byte)(aspect->num_metadata); + b++; + /* add native FLAC 'fLaC' magic */ + memcpy(b, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH); + b += FLAC__STREAM_SYNC_LENGTH; + /* add STREAMINFO */ + memcpy(b, buffer, bytes); + FLAC__ASSERT(b + bytes - synthetic_first_packet_body == sizeof(synthetic_first_packet_body)); + packet.packet = (uint8_t *)synthetic_first_packet_body; + packet.bytes = sizeof(synthetic_first_packet_body); + + packet.b_o_s = 1; + aspect->is_first_packet = false; + } + else { + packet.packet = (uint8_t *)buffer; + packet.bytes = bytes; + } + + if(is_last_block) { + /* we used to check: + * FLAC__ASSERT(total_samples_estimate == 0 || total_samples_estimate == aspect->samples_written + samples); + * but it's really not useful since total_samples_estimate is an estimate and can be inexact + */ + packet.e_o_s = 1; + } + + if(ogg_stream_packetin(&aspect->stream_state, &packet) != 0) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + + /*@@@ can't figure out a way to pass a useful number for 'samples' to the write_callback, so we'll just pass 0 */ + if(is_metadata) { + while(ogg_stream_flush(&aspect->stream_state, &aspect->page) != 0) { + if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + } + else { + while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) { + if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + } + } + else if(is_metadata && current_frame == 0 && samples == 0 && bytes == 4 && 0 == memcmp(buffer, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) { + aspect->seen_magic = true; + } + else { + /* + * If we get here, our assumption about the way write callbacks happen + * explained above is wrong + */ + FLAC__ASSERT(0); + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + + aspect->samples_written += samples; + + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} diff --git a/vendor/flac/src/libFLAC/ogg_helper.c b/vendor/flac/src/libFLAC/ogg_helper.c new file mode 100644 index 0000000..a4be34d --- /dev/null +++ b/vendor/flac/src/libFLAC/ogg_helper.c @@ -0,0 +1,210 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include /* for malloc() */ +#include /* for memcmp(), memcpy() */ +#include "FLAC/assert.h" +#include "share/alloc.h" +#include "private/ogg_helper.h" +#include "protected/stream_encoder.h" + + +static FLAC__bool full_read_(FLAC__StreamEncoder *encoder, FLAC__byte *buffer, size_t bytes, FLAC__StreamEncoderReadCallback read_callback, void *client_data) +{ + while(bytes > 0) { + size_t bytes_read = bytes; + switch(read_callback(encoder, buffer, &bytes_read, client_data)) { + case FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE: + bytes -= bytes_read; + buffer += bytes_read; + break; + case FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM: + if(bytes_read == 0) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + bytes -= bytes_read; + buffer += bytes_read; + break; + case FLAC__STREAM_ENCODER_READ_STATUS_ABORT: + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + case FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED: + return false; + default: + /* double protection: */ + FLAC__ASSERT(0); + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + } + + return true; +} + +void simple_ogg_page__init(ogg_page *page) +{ + page->header = 0; + page->header_len = 0; + page->body = 0; + page->body_len = 0; +} + +void simple_ogg_page__clear(ogg_page *page) +{ + if(page->header) + free(page->header); + if(page->body) + free(page->body); + simple_ogg_page__init(page); +} + +FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data) +{ + static const uint32_t OGG_HEADER_FIXED_PORTION_LEN = 27; + static const uint32_t OGG_MAX_HEADER_LEN = 27/*OGG_HEADER_FIXED_PORTION_LEN*/ + 255; + FLAC__byte crc[4]; + FLAC__StreamEncoderSeekStatus seek_status; + + FLAC__ASSERT(page->header == 0); + FLAC__ASSERT(page->header_len == 0); + FLAC__ASSERT(page->body == 0); + FLAC__ASSERT(page->body_len == 0); + + /* move the stream pointer to the supposed beginning of the page */ + if(0 == seek_callback) + return false; + if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + + /* allocate space for the page header */ + if(0 == (page->header = safe_malloc_(OGG_MAX_HEADER_LEN))) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* read in the fixed part of the page header (up to but not including + * the segment table */ + if(!full_read_(encoder, page->header, OGG_HEADER_FIXED_PORTION_LEN, read_callback, client_data)) + return false; + + page->header_len = OGG_HEADER_FIXED_PORTION_LEN + page->header[26]; + + /* check to see if it's a correct, "simple" page (one packet only) */ + if( + memcmp(page->header, "OggS", 4) || /* doesn't start with OggS */ + (page->header[5] & 0x01) || /* continued packet */ + memcmp(page->header+6, "\0\0\0\0\0\0\0\0", 8) || /* granulepos is non-zero */ + page->header[26] == 0 /* packet is 0-size */ + ) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + + /* read in the segment table */ + if(!full_read_(encoder, page->header + OGG_HEADER_FIXED_PORTION_LEN, page->header[26], read_callback, client_data)) + return false; + + { + uint32_t i; + + /* check to see that it specifies a single packet */ + for(i = 0; i < (uint32_t)page->header[26] - 1; i++) { + if(page->header[i + OGG_HEADER_FIXED_PORTION_LEN] != 255) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + } + + page->body_len = 255 * i + page->header[i + OGG_HEADER_FIXED_PORTION_LEN]; + } + + /* allocate space for the page body */ + if(0 == (page->body = safe_malloc_(page->body_len))) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* read in the page body */ + if(!full_read_(encoder, page->body, page->body_len, read_callback, client_data)) + return false; + + /* check the CRC */ + memcpy(crc, page->header+22, 4); + ogg_page_checksum_set(page); + if(memcmp(crc, page->header+22, 4)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + + return true; +} + +FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data) +{ + FLAC__StreamEncoderSeekStatus seek_status; + + FLAC__ASSERT(page->header != 0); + FLAC__ASSERT(page->header_len != 0); + FLAC__ASSERT(page->body != 0); + FLAC__ASSERT(page->body_len != 0); + + /* move the stream pointer to the supposed beginning of the page */ + if(0 == seek_callback) + return false; + if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + + ogg_page_checksum_set(page); + + /* re-write the page */ + if(write_callback((FLAC__StreamEncoder*)encoder, page->header, page->header_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + if(write_callback((FLAC__StreamEncoder*)encoder, page->body, page->body_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + + return true; +} diff --git a/vendor/flac/src/libFLAC/ogg_mapping.c b/vendor/flac/src/libFLAC/ogg_mapping.c new file mode 100644 index 0000000..756c716 --- /dev/null +++ b/vendor/flac/src/libFLAC/ogg_mapping.c @@ -0,0 +1,48 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/ogg_mapping.h" + +const uint32_t FLAC__OGG_MAPPING_PACKET_TYPE_LEN = 8; /* bits */ + +const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE = 0x7f; + +const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC = (const FLAC__byte * const)"FLAC"; + +const uint32_t FLAC__OGG_MAPPING_VERSION_MAJOR_LEN = 8; /* bits */ +const uint32_t FLAC__OGG_MAPPING_VERSION_MINOR_LEN = 8; /* bits */ + +const uint32_t FLAC__OGG_MAPPING_NUM_HEADERS_LEN = 16; /* bits */ diff --git a/vendor/flac/src/libFLAC/stream_decoder.c b/vendor/flac/src/libFLAC/stream_decoder.c new file mode 100644 index 0000000..18d8dd3 --- /dev/null +++ b/vendor/flac/src/libFLAC/stream_decoder.c @@ -0,0 +1,3731 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for malloc() */ +#include /* for memset/memcpy() */ +#include /* for off_t */ +#include /* for stat() */ +#include "share/compat.h" +#include "FLAC/assert.h" +#include "share/alloc.h" +#include "protected/stream_decoder.h" +#include "private/bitreader.h" +#include "private/bitmath.h" +#include "private/cpu.h" +#include "private/crc.h" +#include "private/fixed.h" +#include "private/format.h" +#include "private/lpc.h" +#include "private/md5.h" +#include "private/memory.h" +#include "private/macros.h" + + +/* technically this should be in an "export.c" but this is convenient enough */ +FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = FLAC__HAS_OGG; + + +/*********************************************************************** + * + * Private static data + * + ***********************************************************************/ + +static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +static void set_defaults_(FLAC__StreamDecoder *decoder); +static FILE *get_binary_stdin_(void); +static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels, uint32_t bps); +static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id); +static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder); +static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder); +static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length); +static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length); +static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length); +static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj); +static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj); +static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder); +static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder); +static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode); +static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder); +static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); +static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); +static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode); +static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode); +static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); +static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended); +static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder); +static void undo_channel_coding(FLAC__StreamDecoder *decoder); +static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data); +#if FLAC__HAS_OGG +static FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes); +static FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +#endif +static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); +static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status); +static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); +#if FLAC__HAS_OGG +static FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); +#endif +static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); +static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data); + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +typedef struct FLAC__StreamDecoderPrivate { + FLAC__bool is_ogg; + FLAC__StreamDecoderReadCallback read_callback; + FLAC__StreamDecoderSeekCallback seek_callback; + FLAC__StreamDecoderTellCallback tell_callback; + FLAC__StreamDecoderLengthCallback length_callback; + FLAC__StreamDecoderEofCallback eof_callback; + FLAC__StreamDecoderWriteCallback write_callback; + FLAC__StreamDecoderMetadataCallback metadata_callback; + FLAC__StreamDecoderErrorCallback error_callback; + void *client_data; + FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */ + FLAC__BitReader *input; + FLAC__int32 *output[FLAC__MAX_CHANNELS]; + FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */ + FLAC__int64 *side_subframe; + FLAC__bool side_subframe_in_use; + FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS]; + uint32_t output_capacity, output_channels; + FLAC__uint32 fixed_block_size, next_fixed_block_size; + FLAC__uint64 samples_decoded; + FLAC__bool has_stream_info, has_seek_table; + FLAC__StreamMetadata stream_info; + FLAC__StreamMetadata seek_table; + FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */ + FLAC__byte *metadata_filter_ids; + size_t metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */ + FLAC__Frame frame; + FLAC__bool cached; /* true if there is a byte in lookahead */ + FLAC__CPUInfo cpuinfo; + FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */ + FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */ + /* unaligned (original) pointers to allocated data */ + FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS]; + FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */ + FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */ + FLAC__bool is_seeking; + FLAC__MD5Context md5context; + FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */ + /* (the rest of these are only used for seeking) */ + FLAC__Frame last_frame; /* holds the info of the last frame we decoded or seeked to */ + FLAC__bool last_frame_is_set; + FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */ + FLAC__uint64 last_seen_framesync; /* if tell callback works, the location of the last seen frame sync code, to rewind to if needed */ + FLAC__uint64 target_sample; + uint32_t unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */ + FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */ + FLAC__bool (*local_bitreader_read_rice_signed_block)(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); +} FLAC__StreamDecoderPrivate; + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +FLAC_API const char * const FLAC__StreamDecoderStateString[] = { + "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA", + "FLAC__STREAM_DECODER_READ_METADATA", + "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC", + "FLAC__STREAM_DECODER_READ_FRAME", + "FLAC__STREAM_DECODER_END_OF_STREAM", + "FLAC__STREAM_DECODER_OGG_ERROR", + "FLAC__STREAM_DECODER_SEEK_ERROR", + "FLAC__STREAM_DECODER_ABORTED", + "FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR", + "FLAC__STREAM_DECODER_UNINITIALIZED" +}; + +FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = { + "FLAC__STREAM_DECODER_INIT_STATUS_OK", + "FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER", + "FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS", + "FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR", + "FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE", + "FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED" +}; + +FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = { + "FLAC__STREAM_DECODER_READ_STATUS_CONTINUE", + "FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM", + "FLAC__STREAM_DECODER_READ_STATUS_ABORT" +}; + +FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = { + "FLAC__STREAM_DECODER_SEEK_STATUS_OK", + "FLAC__STREAM_DECODER_SEEK_STATUS_ERROR", + "FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = { + "FLAC__STREAM_DECODER_TELL_STATUS_OK", + "FLAC__STREAM_DECODER_TELL_STATUS_ERROR", + "FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = { + "FLAC__STREAM_DECODER_LENGTH_STATUS_OK", + "FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR", + "FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = { + "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE", + "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT" +}; + +FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = { + "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC", + "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER", + "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH", + "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM", + "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA" +}; + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ +FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void) +{ + FLAC__StreamDecoder *decoder; + uint32_t i; + + FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ + + decoder = calloc(1, sizeof(FLAC__StreamDecoder)); + if(decoder == 0) { + return 0; + } + + decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected)); + if(decoder->protected_ == 0) { + free(decoder); + return 0; + } + + decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate)); + if(decoder->private_ == 0) { + free(decoder->protected_); + free(decoder); + return 0; + } + + decoder->private_->input = FLAC__bitreader_new(); + if(decoder->private_->input == 0) { + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + decoder->private_->metadata_filter_ids_capacity = 16; + if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) { + FLAC__bitreader_delete(decoder->private_->input); + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + decoder->private_->output[i] = 0; + decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; + } + + decoder->private_->side_subframe = 0; + + decoder->private_->output_capacity = 0; + decoder->private_->output_channels = 0; + decoder->private_->has_seek_table = false; + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]); + + decoder->private_->file = 0; + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; + + return decoder; +} + +FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder) +{ + uint32_t i; + + if (decoder == NULL) + return ; + + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->private_->input); + + (void)FLAC__stream_decoder_finish(decoder); + + if(0 != decoder->private_->metadata_filter_ids) + free(decoder->private_->metadata_filter_ids); + + FLAC__bitreader_delete(decoder->private_->input); + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]); + + free(decoder->private_); + free(decoder->protected_); + free(decoder); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +static FLAC__StreamDecoderInitStatus init_stream_internal_( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FLAC__ASSERT(0 != decoder); + + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; + + if(FLAC__HAS_OGG == 0 && is_ogg) + return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER; + + if( + 0 == read_callback || + 0 == write_callback || + 0 == error_callback || + (seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback)) + ) + return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; + +#if FLAC__HAS_OGG + decoder->private_->is_ogg = is_ogg; + if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect)) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; +#endif + + FLAC__cpu_info(&decoder->private_->cpuinfo); + decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block; + +#ifdef FLAC__BMI2_SUPPORTED + if (decoder->private_->cpuinfo.x86.bmi2) { + decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block_bmi2; + } +#endif + + /* from here on, errors are fatal */ + + if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; + } + + decoder->private_->read_callback = read_callback; + decoder->private_->seek_callback = seek_callback; + decoder->private_->tell_callback = tell_callback; + decoder->private_->length_callback = length_callback; + decoder->private_->eof_callback = eof_callback; + decoder->private_->write_callback = write_callback; + decoder->private_->metadata_callback = metadata_callback; + decoder->private_->error_callback = error_callback; + decoder->private_->client_data = client_data; + decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; + decoder->private_->samples_decoded = 0; + decoder->private_->has_stream_info = false; + decoder->private_->cached = false; + + decoder->private_->do_md5_checking = decoder->protected_->md5_checking; + decoder->private_->is_seeking = false; + + decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */ + if(!FLAC__stream_decoder_reset(decoder)) { + /* above call sets the state for us */ + return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; + } + + return FLAC__STREAM_DECODER_INIT_STATUS_OK; +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_stream_internal_( + decoder, + read_callback, + seek_callback, + tell_callback, + length_callback, + eof_callback, + write_callback, + metadata_callback, + error_callback, + client_data, + /*is_ogg=*/false + ); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_stream_internal_( + decoder, + read_callback, + seek_callback, + tell_callback, + length_callback, + eof_callback, + write_callback, + metadata_callback, + error_callback, + client_data, + /*is_ogg=*/true + ); +} + +static FLAC__StreamDecoderInitStatus init_FILE_internal_( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != file); + + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; + + if(0 == write_callback || 0 == error_callback) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; + + /* + * To make sure that our file does not go unclosed after an error, we + * must assign the FILE pointer before any further error can occur in + * this routine. + */ + if(file == stdin) + file = get_binary_stdin_(); /* just to be safe */ + + decoder->private_->file = file; + + return init_stream_internal_( + decoder, + file_read_callback_, + decoder->private_->file == stdin? 0: file_seek_callback_, + decoder->private_->file == stdin? 0: file_tell_callback_, + decoder->private_->file == stdin? 0: file_length_callback_, + file_eof_callback_, + write_callback, + metadata_callback, + error_callback, + client_data, + is_ogg + ); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); +} + +static FLAC__StreamDecoderInitStatus init_file_internal_( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FILE *file; + + FLAC__ASSERT(0 != decoder); + + /* + * To make sure that our file does not go unclosed after an error, we + * have to do the same entrance checks here that are later performed + * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned. + */ + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; + + if(0 == write_callback || 0 == error_callback) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; + + file = filename? flac_fopen(filename, "rb") : stdin; + + if(0 == file) + return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; + + return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); +} + +FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) +{ + FLAC__bool md5_failed = false; + uint32_t i; + + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) + return true; + + /* see the comment in FLAC__stream_decoder_reset() as to why we + * always call FLAC__MD5Final() + */ + FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); + + free(decoder->private_->seek_table.data.seek_table.points); + decoder->private_->seek_table.data.seek_table.points = 0; + decoder->private_->has_seek_table = false; + + FLAC__bitreader_free(decoder->private_->input); + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + /* WATCHOUT: + * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN() + * require that the output arrays have a buffer of up to 3 zeroes + * in front (at negative indices) for alignment purposes; + * we use 4 to keep the data well-aligned. + */ + if(0 != decoder->private_->output[i]) { + free(decoder->private_->output[i]-4); + decoder->private_->output[i] = 0; + } + if(0 != decoder->private_->residual_unaligned[i]) { + free(decoder->private_->residual_unaligned[i]); + decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; + } + } + if(0 != decoder->private_->side_subframe) { + free(decoder->private_->side_subframe); + decoder->private_->side_subframe = 0; + } + decoder->private_->output_capacity = 0; + decoder->private_->output_channels = 0; + +#if FLAC__HAS_OGG + if(decoder->private_->is_ogg) + FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect); +#endif + + if(0 != decoder->private_->file) { + if(decoder->private_->file != stdin) + fclose(decoder->private_->file); + decoder->private_->file = 0; + } + + if(decoder->private_->do_md5_checking) { + if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16)) + md5_failed = true; + } + decoder->private_->is_seeking = false; + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; + + return !md5_failed; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; +#if FLAC__HAS_OGG + /* can't check decoder->private_->is_ogg since that's not set until init time */ + FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value); + return true; +#else + (void)value; + return false; +#endif +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->protected_->md5_checking = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE); + /* double protection */ + if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE) + return false; + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_filter[type] = true; + if(type == FLAC__METADATA_TYPE_APPLICATION) + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != id); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + + if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) + return true; + + FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); + + if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { + if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->private_->metadata_filter_ids_capacity *= 2; + } + + memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + decoder->private_->metadata_filter_ids_count++; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder) +{ + uint32_t i; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++) + decoder->private_->metadata_filter[i] = true; + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE); + /* double protection */ + if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE) + return false; + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_filter[type] = false; + if(type == FLAC__METADATA_TYPE_APPLICATION) + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != id); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + + if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) + return true; + + FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); + + if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { + if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->private_->metadata_filter_ids_capacity *= 2; + } + + memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + decoder->private_->metadata_filter_ids_count++; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->state; +} + +FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder) +{ + return FLAC__StreamDecoderStateString[decoder->protected_->state]; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->md5_checking; +} + +FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0; +} + +FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->channels; +} + +FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->channel_assignment; +} + +FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->bits_per_sample; +} + +FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->sample_rate; +} + +FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->blocksize; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != position); + + if(FLAC__HAS_OGG && decoder->private_->is_ogg) + return false; + + if(0 == decoder->private_->tell_callback) + return false; + if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK) + return false; + /* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */ + if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) + return false; + FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder)); + *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder); + return true; +} + +FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder) +{ + return decoder->private_->client_data; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + + decoder->private_->samples_decoded = 0; + decoder->private_->do_md5_checking = false; + decoder->private_->last_seen_framesync = 0; + decoder->private_->last_frame_is_set = false; + +#if FLAC__HAS_OGG + if(decoder->private_->is_ogg) + FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect); +#endif + + if(!FLAC__bitreader_clear(decoder->private_->input)) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(!FLAC__stream_decoder_flush(decoder)) { + /* above call sets the state for us */ + return false; + } + +#if FLAC__HAS_OGG + /*@@@ could go in !internal_reset_hack block below */ + if(decoder->private_->is_ogg) + FLAC__ogg_decoder_aspect_reset(&decoder->protected_->ogg_decoder_aspect); +#endif + + /* Rewind if necessary. If FLAC__stream_decoder_init() is calling us, + * (internal_reset_hack) don't try to rewind since we are already at + * the beginning of the stream and don't want to fail if the input is + * not seekable. + */ + if(!decoder->private_->internal_reset_hack) { + if(decoder->private_->file == stdin) + return false; /* can't rewind stdin, reset fails */ + if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR) + return false; /* seekable and seek fails, reset fails */ + } + + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; + + decoder->private_->has_stream_info = false; + + free(decoder->private_->seek_table.data.seek_table.points); + decoder->private_->seek_table.data.seek_table.points = 0; + decoder->private_->has_seek_table = false; + + decoder->private_->do_md5_checking = decoder->protected_->md5_checking; + /* + * This goes in reset() and not flush() because according to the spec, a + * fixed-blocksize stream must stay that way through the whole stream. + */ + decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; + + /* We initialize the FLAC__MD5Context even though we may never use it. This + * is because md5 checking may be turned on to start and then turned off if + * a seek occurs. So we init the context here and finalize it in + * FLAC__stream_decoder_finish() to make sure things are always cleaned up + * properly. + */ + if(!decoder->private_->internal_reset_hack) { + /* Only finish MD5 context when it has been initialized + * (i.e. when internal_reset_hack is not set) */ + FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); + } + else + decoder->private_->internal_reset_hack = false; + FLAC__MD5Init(&decoder->private_->md5context); + + decoder->private_->first_frame_offset = 0; + decoder->private_->unparseable_frame_count = 0; + decoder->private_->last_seen_framesync = 0; + decoder->private_->last_frame_is_set = false; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder) +{ + FLAC__bool got_a_frame; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + else + return true; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true)) + return false; /* above function sets the status for us */ + if(got_a_frame) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + return false; + } + } +} + +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + case FLAC__STREAM_DECODER_READ_FRAME: + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + return false; + } + } +} + +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder) +{ + FLAC__bool dummy; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + return false; + } + } +} + +FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder) +{ + FLAC__bool got_a_frame; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + case FLAC__STREAM_DECODER_READ_METADATA: + return false; /* above function sets the status for us */ + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false)) + return false; /* above function sets the status for us */ + if(got_a_frame) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + return false; + } + } +} + +FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample) +{ + FLAC__uint64 length; + + FLAC__ASSERT(0 != decoder); + + if( + decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && + decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA && + decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && + decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME && + decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM + ) + return false; + + if(0 == decoder->private_->seek_callback) + return false; + + FLAC__ASSERT(decoder->private_->seek_callback); + FLAC__ASSERT(decoder->private_->tell_callback); + FLAC__ASSERT(decoder->private_->length_callback); + FLAC__ASSERT(decoder->private_->eof_callback); + + if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) + return false; + + decoder->private_->is_seeking = true; + + /* turn off md5 checking if a seek is attempted */ + decoder->private_->do_md5_checking = false; + + /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */ + if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) { + decoder->private_->is_seeking = false; + return false; + } + + /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */ + if( + decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA || + decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA + ) { + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) { + /* above call sets the state for us */ + decoder->private_->is_seeking = false; + return false; + } + /* check this again in case we didn't know total_samples the first time */ + if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) { + decoder->private_->is_seeking = false; + return false; + } + } + + { + const FLAC__bool ok = +#if FLAC__HAS_OGG + decoder->private_->is_ogg? + seek_to_absolute_sample_ogg_(decoder, length, sample) : +#endif + seek_to_absolute_sample_(decoder, length, sample) + ; + decoder->private_->is_seeking = false; + return ok; + } +} + +/*********************************************************************** + * + * Protected class methods + * + ***********************************************************************/ + +uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7)); + return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8; +} + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +void set_defaults_(FLAC__StreamDecoder *decoder) +{ + decoder->private_->is_ogg = false; + decoder->private_->read_callback = 0; + decoder->private_->seek_callback = 0; + decoder->private_->tell_callback = 0; + decoder->private_->length_callback = 0; + decoder->private_->eof_callback = 0; + decoder->private_->write_callback = 0; + decoder->private_->metadata_callback = 0; + decoder->private_->error_callback = 0; + decoder->private_->client_data = 0; + + memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); + decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true; + decoder->private_->metadata_filter_ids_count = 0; + + decoder->protected_->md5_checking = false; + +#if FLAC__HAS_OGG + FLAC__ogg_decoder_aspect_set_defaults(&decoder->protected_->ogg_decoder_aspect); +#endif +} + +/* + * This will forcibly set stdin to binary mode (for OSes that require it) + */ +FILE *get_binary_stdin_(void) +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdin), _O_BINARY); +#elif defined __EMX__ + setmode(fileno(stdin), O_BINARY); +#endif + + return stdin; +} + +FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels, uint32_t bps) +{ + uint32_t i; + FLAC__int32 *tmp; + + if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels && + (bps < 32 || decoder->private_->side_subframe != 0)) + return true; + + /* simply using realloc() is not practical because the number of channels may change mid-stream */ + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + if(0 != decoder->private_->output[i]) { + free(decoder->private_->output[i]-4); + decoder->private_->output[i] = 0; + } + if(0 != decoder->private_->residual_unaligned[i]) { + free(decoder->private_->residual_unaligned[i]); + decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; + } + } + + if(0 != decoder->private_->side_subframe) { + free(decoder->private_->side_subframe); + decoder->private_->side_subframe = 0; + } + + for(i = 0; i < channels; i++) { + /* WATCHOUT: + * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN() + * require that the output arrays have a buffer of up to 3 zeroes + * in front (at negative indices) for alignment purposes; + * we use 4 to keep the data well-aligned. + */ + tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/); + if(tmp == 0) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + memset(tmp, 0, sizeof(FLAC__int32)*4); + decoder->private_->output[i] = tmp + 4; + + if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + } + + if(bps == 32) { + decoder->private_->side_subframe = safe_malloc_mul_2op_p(sizeof(FLAC__int64), /*times (*/size); + if(decoder->private_->side_subframe == NULL) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + } + + decoder->private_->output_capacity = size; + decoder->private_->output_channels = channels; + + return true; +} + +FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id) +{ + size_t i; + + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + + for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++) + if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))) + return true; + + return false; +} + +FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) +{ + FLAC__uint32 x; + uint32_t i, id; + FLAC__bool first = true; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + for(i = id = 0; i < 4; ) { + if(decoder->private_->cached) { + x = (FLAC__uint32)decoder->private_->lookahead; + decoder->private_->cached = false; + } + else { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + } + if(x == FLAC__STREAM_SYNC_STRING[i]) { + first = true; + i++; + id = 0; + continue; + } + + if(id >= 3) + return false; + + if(x == ID3V2_TAG_[id]) { + id++; + i = 0; + if(id == 3) { + if(!skip_id3v2_tag_(decoder)) + return false; /* skip_id3v2_tag_ sets the state for us */ + } + continue; + } + id = 0; + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + decoder->private_->header_warmup[0] = (FLAC__byte)x; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + + /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ + /* else we have to check if the second byte is the end of a sync code */ + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + decoder->private_->lookahead = (FLAC__byte)x; + decoder->private_->cached = true; + } + else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ + decoder->private_->header_warmup[1] = (FLAC__byte)x; + decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; + return true; + } + } + i = 0; + if(first) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + first = false; + } + } + + decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA; + return true; +} + +FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) +{ + FLAC__bool is_last; + FLAC__uint32 i, x, type, length; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN)) + return false; /* read_callback_ sets the state for us */ + is_last = x? true : false; + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ + + if(type == FLAC__METADATA_TYPE_STREAMINFO) { + if(!read_metadata_streaminfo_(decoder, is_last, length)) + return false; + + decoder->private_->has_stream_info = true; + if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) + decoder->private_->do_md5_checking = false; + if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback) + decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data); + } + else if(type == FLAC__METADATA_TYPE_SEEKTABLE) { + /* just in case we already have a seek table, and reading the next one fails: */ + decoder->private_->has_seek_table = false; + + if(length > 0) { + if(!read_metadata_seektable_(decoder, is_last, length)) + return false; + + decoder->private_->has_seek_table = true; + if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback) + decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data); + } + } + else { + FLAC__bool skip_it = !decoder->private_->metadata_filter[type]; + uint32_t real_length = length; + FLAC__StreamMetadata block; + + memset(&block, 0, sizeof(block)); + block.is_last = is_last; + block.type = (FLAC__MetadataType)type; + block.length = length; + + if(type == FLAC__METADATA_TYPE_APPLICATION) { + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) + return false; /* read_callback_ sets the state for us */ + + if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */ + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/ + return false; + } + + real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8; + + if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id)) + skip_it = !skip_it; + } + + if(skip_it) { + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) + return false; /* read_callback_ sets the state for us */ + } + else { + FLAC__bool ok = true; + FLAC__bitreader_set_limit(decoder->private_->input, real_length*8); + switch(type) { + case FLAC__METADATA_TYPE_PADDING: + /* skip the padding bytes */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) + ok = false; /* read_callback_ sets the state for us */ + break; + case FLAC__METADATA_TYPE_APPLICATION: + /* remember, we read the ID already */ + if(real_length > 0) { + if(0 == (block.data.application.data = malloc(real_length))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + ok = false; + } + else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length)) + ok = false; /* read_callback_ sets the state for us */ + } + else + block.data.application.data = 0; + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length)) + ok = false; + break; + case FLAC__METADATA_TYPE_CUESHEET: + if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet)) + ok = false; + break; + case FLAC__METADATA_TYPE_PICTURE: + if(!read_metadata_picture_(decoder, &block.data.picture)) + ok = false; + break; + case FLAC__METADATA_TYPE_STREAMINFO: + case FLAC__METADATA_TYPE_SEEKTABLE: + FLAC__ASSERT(0); + break; + default: + if(real_length > 0) { + if(0 == (block.data.unknown.data = malloc(real_length))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + ok = false; + } + else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length)) + ok = false; /* read_callback_ sets the state for us */ + } + else + block.data.unknown.data = 0; + break; + } + if(FLAC__bitreader_limit_remaining(decoder->private_->input) > 0) { + /* Content in metadata block didn't fit in block length + * We cannot know whether the length or the content was + * corrupt, so stop parsing metadata */ + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA); + if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA) + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + ok = false; + } + FLAC__bitreader_remove_limit(decoder->private_->input); + if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback) + decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data); + + /* now we have to free any malloc()ed data in the block */ + switch(type) { + case FLAC__METADATA_TYPE_PADDING: + break; + case FLAC__METADATA_TYPE_APPLICATION: + if(0 != block.data.application.data) + free(block.data.application.data); + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(0 != block.data.vorbis_comment.vendor_string.entry) + free(block.data.vorbis_comment.vendor_string.entry); + if(block.data.vorbis_comment.num_comments > 0) + for(i = 0; i < block.data.vorbis_comment.num_comments; i++) + if(0 != block.data.vorbis_comment.comments[i].entry) + free(block.data.vorbis_comment.comments[i].entry); + if(0 != block.data.vorbis_comment.comments) + free(block.data.vorbis_comment.comments); + break; + case FLAC__METADATA_TYPE_CUESHEET: + if(block.data.cue_sheet.num_tracks > 0 && 0 != block.data.cue_sheet.tracks) + for(i = 0; i < block.data.cue_sheet.num_tracks; i++) + if(0 != block.data.cue_sheet.tracks[i].indices) + free(block.data.cue_sheet.tracks[i].indices); + if(0 != block.data.cue_sheet.tracks) + free(block.data.cue_sheet.tracks); + break; + case FLAC__METADATA_TYPE_PICTURE: + if(0 != block.data.picture.mime_type) + free(block.data.picture.mime_type); + if(0 != block.data.picture.description) + free(block.data.picture.description); + if(0 != block.data.picture.data) + free(block.data.picture.data); + break; + case FLAC__METADATA_TYPE_STREAMINFO: + case FLAC__METADATA_TYPE_SEEKTABLE: + FLAC__ASSERT(0); + default: + if(0 != block.data.unknown.data) + free(block.data.unknown.data); + break; + } + + if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */ + return false; + } + } + + if(is_last) { + /* if this fails, it's OK, it's just a hint for the seek routine */ + if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset)) + decoder->private_->first_frame_offset = 0; + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + } + + return true; +} + +FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length) +{ + FLAC__uint32 x; + uint32_t bits, used_bits = 0; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO; + decoder->private_->stream_info.is_last = is_last; + decoder->private_->stream_info.length = length; + + bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->stream_info.data.stream_info.min_blocksize = x; + used_bits += bits; + + bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->stream_info.data.stream_info.max_blocksize = x; + used_bits += bits; + + bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->stream_info.data.stream_info.min_framesize = x; + used_bits += bits; + + bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->stream_info.data.stream_info.max_framesize = x; + used_bits += bits; + + bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->stream_info.data.stream_info.sample_rate = x; + used_bits += bits; + + bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->stream_info.data.stream_info.channels = x+1; + used_bits += bits; + + bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1; + used_bits += bits; + + bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) + return false; /* read_callback_ sets the state for us */ + used_bits += bits; + + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16)) + return false; /* read_callback_ sets the state for us */ + used_bits += 16*8; + + /* skip the rest of the block */ + FLAC__ASSERT(used_bits % 8 == 0); + if (length < (used_bits / 8)) + return false; /* read_callback_ sets the state for us */ + length -= (used_bits / 8); + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) + return false; /* read_callback_ sets the state for us */ + + return true; +} + +FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length) +{ + FLAC__uint32 i, x; + FLAC__uint64 xx; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE; + decoder->private_->seek_table.is_last = is_last; + decoder->private_->seek_table.length = length; + + if(length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) { + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + + decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; + + /* use realloc since we may pass through here several times (e.g. after seeking) */ + if(0 == (decoder->private_->seek_table.data.seek_table.points = safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) { + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx; + + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx; + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x; + } + length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH); + + FLAC__ASSERT(length == 0); + + return true; +} + +FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length) +{ + FLAC__uint32 i; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + /* read vendor string */ + if (length >= 8) { + length -= 8; /* vendor string length + num comments entries alone take 8 bytes */ + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); + if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length)) + return false; /* read_callback_ sets the state for us */ + if (length < obj->vendor_string.length) { + obj->vendor_string.length = 0; + obj->vendor_string.entry = 0; + goto skip; + } + else + length -= obj->vendor_string.length; + if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length)) + return false; /* read_callback_ sets the state for us */ + obj->vendor_string.entry[obj->vendor_string.length] = '\0'; + + /* read num comments */ + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32); + if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments)) + return false; /* read_callback_ sets the state for us */ + + /* read comments */ + if (obj->num_comments > 100000) { + /* Possibly malicious file. */ + obj->num_comments = 0; + return false; + } + if (obj->num_comments > 0) { + if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { + obj->num_comments = 0; + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + for (i = 0; i < obj->num_comments; i++) { + /* Initialize here just to make sure. */ + obj->comments[i].length = 0; + obj->comments[i].entry = 0; + + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); + if (length < 4) { + obj->num_comments = i; + goto skip; + } + else + length -= 4; + if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) { + obj->num_comments = i; + return false; /* read_callback_ sets the state for us */ + } + if (length < obj->comments[i].length) { + obj->num_comments = i; + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + else + length -= obj->comments[i].length; + if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + obj->num_comments = i; + return false; + } + memset (obj->comments[i].entry, 0, obj->comments[i].length) ; + if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) { + /* Current i-th entry is bad, so we delete it. */ + free (obj->comments[i].entry) ; + obj->comments[i].entry = NULL ; + obj->num_comments = i; + goto skip; + } + obj->comments[i].entry[obj->comments[i].length] = '\0'; + } + } + } + else { + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + + skip: + if (length > 0) { + /* length > 0 can only happen on files with invalid data in comments */ + if(obj->num_comments < 1) { + free(obj->comments); + obj->comments = NULL; + } + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + + return true; +} + +FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj) +{ + FLAC__uint32 i, j, x; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet)); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) + return false; /* read_callback_ sets the state for us */ + obj->is_cd = x? true : false; + + if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) + return false; /* read_callback_ sets the state for us */ + obj->num_tracks = x; + + if(obj->num_tracks > 0) { + if(0 == (obj->tracks = safe_calloc_(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + for(i = 0; i < obj->num_tracks; i++) { + FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i]; + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) + return false; /* read_callback_ sets the state for us */ + track->number = (FLAC__byte)x; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ + track->type = x; + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) + return false; /* read_callback_ sets the state for us */ + track->pre_emphasis = x; + + if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) + return false; /* read_callback_ sets the state for us */ + track->num_indices = (FLAC__byte)x; + + if(track->num_indices > 0) { + if(0 == (track->indices = safe_calloc_(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + for(j = 0; j < track->num_indices; j++) { + FLAC__StreamMetadata_CueSheet_Index *indx = &track->indices[j]; + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) + return false; /* read_callback_ sets the state for us */ + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) + return false; /* read_callback_ sets the state for us */ + indx->number = (FLAC__byte)x; + + if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) + return false; /* read_callback_ sets the state for us */ + } + } + } + } + else { /* obj->num_tracks == 0 */ + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + + return true; +} + +FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj) +{ + FLAC__uint32 x; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + /* read type */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ + if(x < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED) + obj->type = x; + else + obj->type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; + + /* read MIME type */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ + if(FLAC__bitreader_limit_remaining(decoder->private_->input) < x){ + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + if(0 == (obj->mime_type = safe_malloc_add_2op_(x, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(x > 0) { + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x)) + return false; /* read_callback_ sets the state for us */ + } + obj->mime_type[x] = '\0'; + + /* read description */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ + if(FLAC__bitreader_limit_remaining(decoder->private_->input) < x){ + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + if(0 == (obj->description = safe_malloc_add_2op_(x, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(x > 0) { + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x)) + return false; /* read_callback_ sets the state for us */ + } + obj->description[x] = '\0'; + + /* read width */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read height */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read depth */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read colors */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read data */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ + if(FLAC__bitreader_limit_remaining(decoder->private_->input) < obj->data_length){ + FLAC__bitreader_limit_invalidate(decoder->private_->input); + return false; + } + if(0 == (obj->data = safe_malloc_(obj->data_length))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(obj->data_length > 0) { + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length)) + return false; /* read_callback_ sets the state for us */ + } + + return true; +} + +FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder) +{ + FLAC__uint32 x; + uint32_t i, skip; + + /* skip the version and flags bytes */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24)) + return false; /* read_callback_ sets the state for us */ + /* get the size (in bytes) to skip */ + skip = 0; + for(i = 0; i < 4; i++) { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + skip <<= 7; + skip |= (x & 0x7f); + } + /* skip the rest of the tag */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip)) + return false; /* read_callback_ sets the state for us */ + return true; +} + +FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) +{ + FLAC__uint32 x; + FLAC__bool first = true; + + /* make sure we're byte aligned */ + if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) + return false; /* read_callback_ sets the state for us */ + } + + while(1) { + if(decoder->private_->cached) { + x = (FLAC__uint32)decoder->private_->lookahead; + decoder->private_->cached = false; + } + else { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + } + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + decoder->private_->header_warmup[0] = (FLAC__byte)x; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + + /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ + /* else we have to check if the second byte is the end of a sync code */ + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + decoder->private_->lookahead = (FLAC__byte)x; + decoder->private_->cached = true; + } + else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ + decoder->private_->header_warmup[1] = (FLAC__byte)x; + decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; + + /* Save location so we can rewind in case the frame turns + * out to be invalid after the header */ + FLAC__bitreader_set_framesync_location(decoder->private_->input); + if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->last_seen_framesync)) + decoder->private_->last_seen_framesync = 0; + return true; + } + } + if(first) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + first = false; + } + } + + return true; +} + +FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode) +{ + uint32_t channel; + uint32_t i; + uint32_t frame_crc; /* the one we calculate from the input stream */ + FLAC__uint32 x; + + *got_a_frame = false; + decoder->private_->side_subframe_in_use = false; + + /* init the CRC */ + frame_crc = 0; + frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc); + frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc); + FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc); + + if(!read_frame_header_(decoder)) + return false; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */ + return true; + if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels, decoder->private_->frame.header.bits_per_sample)) + return false; + for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { + /* + * first figure the correct bits-per-sample of the subframe + */ + uint32_t bps = decoder->private_->frame.header.bits_per_sample; + switch(decoder->private_->frame.header.channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + /* no adjustment needed */ + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + if(channel == 1) + bps++; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + if(channel == 0) + bps++; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + if(channel == 1) + bps++; + break; + default: + FLAC__ASSERT(0); + } + /* + * now read it + */ + if(!read_subframe_(decoder, channel, bps, do_full_decode)){ + /* read_callback_ sets the state for us */ + if(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) + break; + else + return false; + } + if(decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME) + break; + } + + if(decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM) + if(!read_zero_padding_(decoder)) + return false; + + /* + * Read the frame CRC-16 from the footer and check + */ + if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) { + frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input); + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN)) { + /* read_callback_ sets the state for us */ + if(decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM) + return false; + } +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + } + if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME && frame_crc == x) { +#endif + if(do_full_decode) { + /* Undo any special channel coding */ + undo_channel_coding(decoder); + /* Check whether decoded data actually fits bps */ + for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { + int shift_bits = 32 - decoder->private_->frame.header.bits_per_sample; + /* Check whether shift_bits MSBs are 'empty' by shifting up and down */ + if((decoder->private_->output[channel][i] < (INT32_MIN >> shift_bits)) || + (decoder->private_->output[channel][i] > (INT32_MAX >> shift_bits))) { + /* Bad frame, emit error */ + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + break; + } + } + } + } + } +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + else if (decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) { + /* Bad frame, emit error */ + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + } +#endif + + /* Check whether frames are missing, if so, add silence to compensate */ + if(decoder->private_->last_frame_is_set && decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME && !decoder->private_->is_seeking && do_full_decode) { + FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + if(decoder->private_->last_frame.header.number.sample_number + decoder->private_->last_frame.header.blocksize < decoder->private_->frame.header.number.sample_number) { + uint32_t padding_samples_needed = decoder->private_->frame.header.number.sample_number - (decoder->private_->last_frame.header.number.sample_number + decoder->private_->last_frame.header.blocksize); + + /* Do some extra validation to assure last frame an current frame + * header are both valid before adding silence inbetween + * Technically both frames could be valid with differing sample_rates, + * channels and bits_per_sample, but it is quite rare */ + if(decoder->private_->last_frame.header.sample_rate == decoder->private_->frame.header.sample_rate && + decoder->private_->last_frame.header.channels == decoder->private_->frame.header.channels && + decoder->private_->last_frame.header.bits_per_sample == decoder->private_->frame.header.bits_per_sample && + decoder->private_->last_frame.header.blocksize >= 16) { + FLAC__Frame empty_frame; + FLAC__int32 * empty_buffer[FLAC__MAX_CHANNELS] = {NULL}; + empty_frame.header = decoder->private_->last_frame.header; + empty_frame.footer.crc = 0; + for(i = 0; i < empty_frame.header.channels; i++) { + empty_buffer[i] = safe_calloc_(empty_frame.header.blocksize, sizeof(FLAC__int32)); + if(empty_buffer[i] == NULL) { + for(i = 0; i < empty_frame.header.channels; i++) + if(empty_buffer[i] != NULL) + free(empty_buffer[i]); + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + } + /* No repairs larger than 5 seconds or 50 frames are made, to not + * unexpectedly create enormous files when one of the headers was + * corrupt after all */ + if(padding_samples_needed > (5*empty_frame.header.sample_rate)) + padding_samples_needed = 5*empty_frame.header.sample_rate; + if(padding_samples_needed > (50*empty_frame.header.blocksize)) + padding_samples_needed = 50*empty_frame.header.blocksize; + while(padding_samples_needed){ + empty_frame.header.number.sample_number += empty_frame.header.blocksize; + if(padding_samples_needed < empty_frame.header.blocksize) + empty_frame.header.blocksize = padding_samples_needed; + padding_samples_needed -= empty_frame.header.blocksize; + decoder->protected_->blocksize = empty_frame.header.blocksize; + + FLAC__ASSERT(empty_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + decoder->private_->samples_decoded = empty_frame.header.number.sample_number + empty_frame.header.blocksize; + + for(channel = 0; channel < empty_frame.header.channels; channel++) { + empty_frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT; + empty_frame.subframes[channel].data.constant.value = 0; + empty_frame.subframes[channel].wasted_bits = 0; + } + + if(write_audio_frame_to_client_(decoder, &empty_frame, (const FLAC__int32 * const *)empty_buffer) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) { + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + for(i = 0; i < empty_frame.header.channels; i++) + if(empty_buffer[i] != NULL) + free(empty_buffer[i]); + return false; + } + } + for(i = 0; i < empty_frame.header.channels; i++) + if(empty_buffer[i] != NULL) + free(empty_buffer[i]); + + } + } + } + + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC || decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) { + /* Got corruption, rewind if possible. Return value of seek + * isn't checked, if the seek fails the decoder will continue anyway */ + if(!FLAC__bitreader_rewind_to_after_last_seen_framesync(decoder->private_->input)){ +#ifndef NDEBUG + fprintf(stderr, "Rewinding, seeking necessary\n"); +#endif + if(decoder->private_->seek_callback && decoder->private_->last_seen_framesync){ + /* Last framesync isn't in bitreader anymore, rewind with seek if possible */ +#ifndef NDEBUG + FLAC__uint64 current_decode_position; + if(FLAC__stream_decoder_get_decode_position(decoder, ¤t_decode_position)) + fprintf(stderr, "Bitreader was %" PRIu64 " bytes short\n", current_decode_position-decoder->private_->last_seen_framesync); +#endif + if(decoder->private_->seek_callback(decoder, decoder->private_->last_seen_framesync, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__bitreader_clear(decoder->private_->input)) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + } + } +#ifndef NDEBUG + else{ + fprintf(stderr, "Rewinding, seeking not necessary\n"); + } +#endif + } + else { + *got_a_frame = true; + + /* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */ + if(decoder->private_->next_fixed_block_size) + decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size; + + /* put the latest values into the public section of the decoder instance */ + decoder->protected_->channels = decoder->private_->frame.header.channels; + decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment; + decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample; + decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate; + decoder->protected_->blocksize = decoder->private_->frame.header.blocksize; + + FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize; + + /* write it */ + if(do_full_decode) { + if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) { + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + return false; + } + } + } + + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; +} + +FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) +{ + FLAC__uint32 x; + FLAC__uint64 xx; + uint32_t i, blocksize_hint = 0, sample_rate_hint = 0; + FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */ + uint32_t raw_header_len; + FLAC__bool is_unparseable = false; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + /* init the raw header with the saved bits from synchronization */ + raw_header[0] = decoder->private_->header_warmup[0]; + raw_header[1] = decoder->private_->header_warmup[1]; + raw_header_len = 2; + + /* check to make sure that reserved bit is 0 */ + if(raw_header[1] & 0x02) /* MAGIC NUMBER */ + is_unparseable = true; + + /* + * Note that along the way as we read the header, we look for a sync + * code inside. If we find one it would indicate that our original + * sync was bad since there cannot be a sync code in a valid header. + * + * Three kinds of things can go wrong when reading the frame header: + * 1) We may have sync'ed incorrectly and not landed on a frame header. + * If we don't find a sync code, it can end up looking like we read + * a valid but unparseable header, until getting to the frame header + * CRC. Even then we could get a false positive on the CRC. + * 2) We may have sync'ed correctly but on an unparseable frame (from a + * future encoder). + * 3) We may be on a damaged frame which appears valid but unparseable. + * + * For all these reasons, we try and read a complete frame header as + * long as it seems valid, even if unparseable, up until the frame + * header CRC. + */ + + /* + * read in the raw header as bytes so we can CRC it, and parse it on the way + */ + for(i = 0; i < 2; i++) { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */ + decoder->private_->lookahead = (FLAC__byte)x; + decoder->private_->cached = true; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + raw_header[raw_header_len++] = (FLAC__byte)x; + } + + switch(x = raw_header[2] >> 4) { + case 0: + is_unparseable = true; + break; + case 1: + decoder->private_->frame.header.blocksize = 192; + break; + case 2: + case 3: + case 4: + case 5: + decoder->private_->frame.header.blocksize = 576 << (x-2); + break; + case 6: + case 7: + blocksize_hint = x; + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + decoder->private_->frame.header.blocksize = 256 << (x-8); + break; + default: + FLAC__ASSERT(0); + break; + } + + switch(x = raw_header[2] & 0x0f) { + case 0: + if(decoder->private_->has_stream_info) + decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate; + else + is_unparseable = true; + break; + case 1: + decoder->private_->frame.header.sample_rate = 88200; + break; + case 2: + decoder->private_->frame.header.sample_rate = 176400; + break; + case 3: + decoder->private_->frame.header.sample_rate = 192000; + break; + case 4: + decoder->private_->frame.header.sample_rate = 8000; + break; + case 5: + decoder->private_->frame.header.sample_rate = 16000; + break; + case 6: + decoder->private_->frame.header.sample_rate = 22050; + break; + case 7: + decoder->private_->frame.header.sample_rate = 24000; + break; + case 8: + decoder->private_->frame.header.sample_rate = 32000; + break; + case 9: + decoder->private_->frame.header.sample_rate = 44100; + break; + case 10: + decoder->private_->frame.header.sample_rate = 48000; + break; + case 11: + decoder->private_->frame.header.sample_rate = 96000; + break; + case 12: + case 13: + case 14: + sample_rate_hint = x; + break; + case 15: + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + default: + FLAC__ASSERT(0); + } + + x = (uint32_t)(raw_header[3] >> 4); + if(x & 8) { + decoder->private_->frame.header.channels = 2; + switch(x & 7) { + case 0: + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE; + break; + case 1: + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE; + break; + case 2: + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE; + break; + default: + is_unparseable = true; + break; + } + } + else { + decoder->private_->frame.header.channels = (uint32_t)x + 1; + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; + } + + switch(x = (uint32_t)(raw_header[3] & 0x0e) >> 1) { + case 0: + if(decoder->private_->has_stream_info) + decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample; + else + is_unparseable = true; + break; + case 1: + decoder->private_->frame.header.bits_per_sample = 8; + break; + case 2: + decoder->private_->frame.header.bits_per_sample = 12; + break; + case 3: + is_unparseable = true; + break; + case 4: + decoder->private_->frame.header.bits_per_sample = 16; + break; + case 5: + decoder->private_->frame.header.bits_per_sample = 20; + break; + case 6: + decoder->private_->frame.header.bits_per_sample = 24; + break; + case 7: + decoder->private_->frame.header.bits_per_sample = 32; + break; + default: + FLAC__ASSERT(0); + break; + } + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* check to make sure that reserved bit is 0 */ + if(raw_header[3] & 0x01) /* MAGIC NUMBER */ + is_unparseable = true; +#endif + + /* read the frame's starting sample number (or frame number as the case may be) */ + if( + raw_header[1] & 0x01 || + /*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */ + (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize) + ) { /* variable blocksize */ + if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len)) + return false; /* read_callback_ sets the state for us */ + if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */ + decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ + decoder->private_->cached = true; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; + decoder->private_->frame.header.number.sample_number = xx; + } + else { /* fixed blocksize */ + if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len)) + return false; /* read_callback_ sets the state for us */ + if(x == 0xffffffff) { /* i.e. non-UTF8 code... */ + decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ + decoder->private_->cached = true; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER; + decoder->private_->frame.header.number.frame_number = x; + } + + if(blocksize_hint) { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (FLAC__byte)x; + if(blocksize_hint == 7) { + FLAC__uint32 _x; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) + return false; /* read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (FLAC__byte)_x; + x = (x << 8) | _x; + } + decoder->private_->frame.header.blocksize = x+1; + if(decoder->private_->frame.header.blocksize > 65535) { /* invalid blocksize (65536) specified */ + decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ + decoder->private_->cached = true; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + + } + + if(sample_rate_hint) { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (FLAC__byte)x; + if(sample_rate_hint != 12) { + FLAC__uint32 _x; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) + return false; /* read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (FLAC__byte)_x; + x = (x << 8) | _x; + } + if(sample_rate_hint == 12) + decoder->private_->frame.header.sample_rate = x*1000; + else if(sample_rate_hint == 13) + decoder->private_->frame.header.sample_rate = x; + else + decoder->private_->frame.header.sample_rate = x*10; + } + + /* read the CRC-8 byte */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ + crc8 = (FLAC__byte)x; + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if(FLAC__crc8(raw_header, raw_header_len) != crc8) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } +#endif + + /* calculate the sample number from the frame number if needed */ + decoder->private_->next_fixed_block_size = 0; + if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { + x = decoder->private_->frame.header.number.frame_number; + decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; + if(decoder->private_->fixed_block_size) + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x; + else if(decoder->private_->has_stream_info) { + if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) { + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x; + decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize; + } + else + is_unparseable = true; + } + else if(x == 0) { + decoder->private_->frame.header.number.sample_number = 0; + decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize; + } + else { + /* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */ + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x; + } + } + + if(is_unparseable) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + + return true; +} + +FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) +{ + FLAC__uint32 x; + FLAC__bool wasted_bits; + uint32_t i; + + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */ + return false; /* read_callback_ sets the state for us */ + + wasted_bits = (x & 1); + x &= 0xfe; + + if(wasted_bits) { + uint32_t u; + if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u)) + return false; /* read_callback_ sets the state for us */ + decoder->private_->frame.subframes[channel].wasted_bits = u+1; + if (decoder->private_->frame.subframes[channel].wasted_bits >= bps) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + bps -= decoder->private_->frame.subframes[channel].wasted_bits; + } + else + decoder->private_->frame.subframes[channel].wasted_bits = 0; + + /* + * Lots of magic numbers here + */ + if(x & 0x80) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + else if(x == 0) { + if(!read_subframe_constant_(decoder, channel, bps, do_full_decode)) + return false; + } + else if(x == 2) { + if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode)) + return false; + } + else if(x < 16) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + else if(x <= 24) { + uint32_t predictor_order = (x>>1)&7; + if(decoder->private_->frame.header.blocksize <= predictor_order){ + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + if(!read_subframe_fixed_(decoder, channel, bps, predictor_order, do_full_decode)) + return false; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ + return true; + } + else if(x < 64) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + else { + uint32_t predictor_order = ((x>>1)&31)+1; + if(decoder->private_->frame.header.blocksize <= predictor_order){ + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + if(!read_subframe_lpc_(decoder, channel, bps, predictor_order, do_full_decode)) + return false; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ + return true; + } + + if(wasted_bits && do_full_decode) { + x = decoder->private_->frame.subframes[channel].wasted_bits; + if((bps + x) < 33) { + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { + uint32_t val = decoder->private_->output[channel][i]; + decoder->private_->output[channel][i] = (val << x); + } + } + else { + /* When there are wasted bits, bps is never 33 and so + * side_subframe is never already in use */ + FLAC__ASSERT(!decoder->private_->side_subframe_in_use); + decoder->private_->side_subframe_in_use = true; + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { + uint64_t val = decoder->private_->output[channel][i]; + decoder->private_->side_subframe[i] = (val << x); + } + } + } + + return true; +} + +FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) +{ + FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant; + FLAC__int64 x; + uint32_t i; + + decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT; + + if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &x, bps)) + return false; /* read_callback_ sets the state for us */ + + subframe->value = x; + + /* decode the subframe */ + if(do_full_decode) { + if(bps <= 32) { + FLAC__int32 *output = decoder->private_->output[channel]; + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) + output[i] = x; + } else { + FLAC__int64 *output = decoder->private_->side_subframe; + decoder->private_->side_subframe_in_use = true; + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) + output[i] = x; + } + } + + return true; +} + +FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode) +{ + FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed; + FLAC__int64 i64; + FLAC__uint32 u32; + uint32_t u; + + decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED; + + subframe->residual = decoder->private_->residual[channel]; + subframe->order = order; + + /* read warm-up samples */ + for(u = 0; u < order; u++) { + if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &i64, bps)) + return false; /* read_callback_ sets the state for us */ + subframe->warmup[u] = i64; + } + + /* read entropy coding method info */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ + subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; + switch(subframe->entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + return false; /* read_callback_ sets the state for us */ + if((decoder->private_->frame.header.blocksize >> u32 < order) || + (decoder->private_->frame.header.blocksize % (1 << u32) > 0)) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + subframe->entropy_coding_method.data.partitioned_rice.order = u32; + subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; + break; + default: + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + + /* read residual */ + switch(subframe->entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) + return false; + break; + default: + FLAC__ASSERT(0); + } + + /* decode the subframe */ + if(do_full_decode) { + if(bps < 33){ + uint32_t i; + for(i = 0; i < order; i++) + decoder->private_->output[channel][i] = subframe->warmup[i]; + if(bps+order <= 32) + FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order); + else + FLAC__fixed_restore_signal_wide(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order); + } + else { + decoder->private_->side_subframe_in_use = true; + memcpy(decoder->private_->side_subframe, subframe->warmup, sizeof(FLAC__int64) * order); + FLAC__fixed_restore_signal_wide_33bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->side_subframe+order); + } + } + + return true; +} + +FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode) +{ + FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc; + FLAC__int32 i32; + FLAC__int64 i64; + FLAC__uint32 u32; + uint32_t u; + + decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC; + + subframe->residual = decoder->private_->residual[channel]; + subframe->order = order; + + /* read warm-up samples */ + for(u = 0; u < order; u++) { + if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &i64, bps)) + return false; /* read_callback_ sets the state for us */ + subframe->warmup[u] = i64; + } + + /* read qlp coeff precision */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) + return false; /* read_callback_ sets the state for us */ + if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + subframe->qlp_coeff_precision = u32+1; + + /* read qlp shift */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) + return false; /* read_callback_ sets the state for us */ + if(i32 < 0) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + subframe->quantization_level = i32; + + /* read quantized lp coefficiencts */ + for(u = 0; u < order; u++) { + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision)) + return false; /* read_callback_ sets the state for us */ + subframe->qlp_coeff[u] = i32; + } + + /* read entropy coding method info */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ + subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; + switch(subframe->entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + return false; /* read_callback_ sets the state for us */ + if((decoder->private_->frame.header.blocksize >> u32 < order) || + (decoder->private_->frame.header.blocksize % (1 << u32) > 0)) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + subframe->entropy_coding_method.data.partitioned_rice.order = u32; + subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; + break; + default: + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + + /* read residual */ + switch(subframe->entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) + return false; + break; + default: + FLAC__ASSERT(0); + } + + /* decode the subframe */ + if(do_full_decode) { + if(bps <= 32) { + uint32_t i; + for(i = 0; i < order; i++) + decoder->private_->output[channel][i] = subframe->warmup[i]; + if(FLAC__lpc_max_residual_bps(bps, subframe->qlp_coeff, order, subframe->quantization_level) <= 32 && + FLAC__lpc_max_prediction_before_shift_bps(bps, subframe->qlp_coeff, order) <= 32) + FLAC__lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); + else + FLAC__lpc_restore_signal_wide(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); + } + else { + decoder->private_->side_subframe_in_use = true; + memcpy(decoder->private_->side_subframe, subframe->warmup, sizeof(FLAC__int64) * order); + FLAC__lpc_restore_signal_wide_33bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->side_subframe+order); + } + } + + return true; +} + +FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) +{ + FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim; + uint32_t i; + + decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM; + + if(bps < 33) { + FLAC__int32 x, *residual = decoder->private_->residual[channel]; + + subframe->data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32; + subframe->data.int32 = residual; + + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps)) + return false; /* read_callback_ sets the state for us */ + residual[i] = x; + } + + /* decode the subframe */ + if(do_full_decode) + memcpy(decoder->private_->output[channel], subframe->data.int32, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize); + } + else { + FLAC__int64 x, *side = decoder->private_->side_subframe; + + subframe->data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64; + subframe->data.int64 = side; + decoder->private_->side_subframe_in_use = true; + + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { + if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &x, bps)) + return false; /* read_callback_ sets the state for us */ + side[i] = x; + } + } + + return true; +} + +FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended) +{ + FLAC__uint32 rice_parameter; + int i; + uint32_t partition, sample, u; + const uint32_t partitions = 1u << partition_order; + const uint32_t partition_samples = decoder->private_->frame.header.blocksize >> partition_order; + const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; + const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + + /* invalid predictor and partition orders mush be handled in the callers */ + FLAC__ASSERT(partition_order > 0? partition_samples >= predictor_order : decoder->private_->frame.header.blocksize >= predictor_order); + + if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + sample = 0; + for(partition = 0; partition < partitions; partition++) { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen)) + return false; /* read_callback_ sets the state for us */ + partitioned_rice_contents->parameters[partition] = rice_parameter; + if(rice_parameter < pesc) { + partitioned_rice_contents->raw_bits[partition] = 0; + u = (partition == 0) ? partition_samples - predictor_order : partition_samples; + if(!decoder->private_->local_bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)){ + if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) { + /* no error was set, read_callback_ didn't set it, so + * invalid rice symbol was found */ + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + else + return false; /* read_callback_ sets the state for us */ + } + sample += u; + } + else { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) + return false; /* read_callback_ sets the state for us */ + partitioned_rice_contents->raw_bits[partition] = rice_parameter; + if(rice_parameter == 0) { + for(u = (partition == 0)? predictor_order : 0; u < partition_samples; u++, sample++) + residual[sample] = 0; + } + else{ + for(u = (partition == 0)? predictor_order : 0; u < partition_samples; u++, sample++) { + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter)) + return false; /* read_callback_ sets the state for us */ + residual[sample] = i; + } + } + } + } + + return true; +} + +FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder) +{ + if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { + FLAC__uint32 zero = 0; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) + return false; /* read_callback_ sets the state for us */ +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if(zero != 0) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + } +#endif + } + return true; +} + +FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data; + + if( +#if FLAC__HAS_OGG + /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ + !decoder->private_->is_ogg && +#endif + decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) + ) { + *bytes = 0; + decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; + return false; + } + else if(*bytes > 0) { + /* While seeking, it is possible for our seek to land in the + * middle of audio data that looks exactly like a frame header + * from a future version of an encoder. When that happens, our + * error callback will get an + * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its + * unparseable_frame_count. But there is a remote possibility + * that it is properly synced at such a "future-codec frame", + * so to make sure, we wait to see many "unparseable" errors in + * a row before bailing out. + */ + if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) { + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + return false; + } + else { + const FLAC__StreamDecoderReadStatus status = +#if FLAC__HAS_OGG + decoder->private_->is_ogg? + read_callback_ogg_aspect_(decoder, buffer, bytes) : +#endif + decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data) + ; + if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) { + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + return false; + } + else if(*bytes == 0) { + if( + status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM || + ( +#if FLAC__HAS_OGG + /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ + !decoder->private_->is_ogg && +#endif + decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) + ) + ) { + decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; + return false; + } + else + return true; + } + else + return true; + } + } + else { + /* abort to avoid a deadlock */ + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + return false; + } + /* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around + * for Ogg FLAC. This is because the ogg decoder aspect can lose sync + * and at the same time hit the end of the stream (for example, seeking + * to a point that is after the beginning of the last Ogg page). There + * is no way to report an Ogg sync loss through the callbacks (see note + * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0. + * So to keep the decoder from stopping at this point we gate the call + * to the eof_callback and let the Ogg decoder aspect set the + * end-of-stream state when it is needed. + */ +} + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) +/* The attribute below is to silence the undefined sanitizer of oss-fuzz. + * Because fuzzing feeds bogus predictors and residual samples to the + * decoder, having overflows in this section is unavoidable. Also, + * because the calculated values are audio path only, there is no + * potential for security problems */ +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +void undo_channel_coding(FLAC__StreamDecoder *decoder) { + uint32_t i; + switch(decoder->private_->frame.header.channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + /* do nothing */ + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32)); + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) + if(decoder->private_->side_subframe_in_use) + decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->side_subframe[i]; + else + decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i]; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32)); + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) + if(decoder->private_->side_subframe_in_use) + decoder->private_->output[0][i] = decoder->private_->output[1][i] + decoder->private_->side_subframe[i]; + else + decoder->private_->output[0][i] += decoder->private_->output[1][i]; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32)); + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { + if(!decoder->private_->side_subframe_in_use){ + FLAC__int32 mid, side; + mid = decoder->private_->output[0][i]; + side = decoder->private_->output[1][i]; + mid = ((uint32_t) mid) << 1; + mid |= (side & 1); /* i.e. if 'side' is odd... */ + decoder->private_->output[0][i] = (mid + side) >> 1; + decoder->private_->output[1][i] = (mid - side) >> 1; + } + else { /* bps == 32 */ + FLAC__int64 mid; + mid = ((uint64_t)decoder->private_->output[0][i]) << 1; + mid |= (decoder->private_->side_subframe[i] & 1); /* i.e. if 'side' is odd... */ + decoder->private_->output[0][i] = (mid + decoder->private_->side_subframe[i]) >> 1; + decoder->private_->output[1][i] = (mid - decoder->private_->side_subframe[i]) >> 1; + } + } + break; + default: + FLAC__ASSERT(0); + break; + } +} + +#if FLAC__HAS_OGG +FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes) +{ + switch(FLAC__ogg_decoder_aspect_read_callback_wrapper(&decoder->protected_->ogg_decoder_aspect, buffer, bytes, read_callback_proxy_, decoder, decoder->private_->client_data)) { + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK: + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + /* we don't really have a way to handle lost sync via read + * callback so we'll let it pass and let the underlying + * FLAC decoder catch the error + */ + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC: + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM: + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR: + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + default: + FLAC__ASSERT(0); + /* double protection */ + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } +} + +FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)void_decoder; + + switch(decoder->private_->read_callback(decoder, buffer, bytes, client_data)) { + case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK; + case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM; + case FLAC__STREAM_DECODER_READ_STATUS_ABORT: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; + default: + /* double protection: */ + FLAC__ASSERT(0); + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; + } +} +#endif + +FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + decoder->private_->last_frame = *frame; /* save the frame */ + decoder->private_->last_frame_is_set = true; + if(decoder->private_->is_seeking) { + FLAC__uint64 this_frame_sample = frame->header.number.sample_number; + FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize; + FLAC__uint64 target_sample = decoder->private_->target_sample; + + FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + +#if FLAC__HAS_OGG + decoder->private_->got_a_frame = true; +#endif + if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */ + uint32_t delta = (uint32_t)(target_sample - this_frame_sample); + /* kick out of seek mode */ + decoder->private_->is_seeking = false; + /* shift out the samples before target_sample */ + if(delta > 0) { + uint32_t channel; + const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS]; + for(channel = 0; channel < frame->header.channels; channel++) { + newbuffer[channel] = buffer[channel] + delta; + decoder->private_->last_frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM; + decoder->private_->last_frame.subframes[channel].data.verbatim.data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32; + decoder->private_->last_frame.subframes[channel].data.verbatim.data.int32 = newbuffer[channel]; + } + decoder->private_->last_frame.header.blocksize -= delta; + decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta; + /* write the relevant samples */ + return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data); + } + else { + /* write the relevant samples */ + return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); + } + } + else { + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + } + else { + /* + * If we never got STREAMINFO, turn off MD5 checking to save + * cycles since we don't have a sum to compare to anyway + */ + if(!decoder->private_->has_stream_info) + decoder->private_->do_md5_checking = false; + if(decoder->private_->do_md5_checking) { + if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8)) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); + } +} + +void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status) +{ + if(!decoder->private_->is_seeking) + decoder->private_->error_callback(decoder, status, decoder->private_->client_data); + else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM) + decoder->private_->unparseable_frame_count++; +} + +FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) +{ + FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample; + FLAC__int64 pos = -1; + int i; + uint32_t approx_bytes_per_frame; + FLAC__bool first_seek = true, seek_from_lower_bound = false; + const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder); + const uint32_t min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize; + const uint32_t max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize; + const uint32_t max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize; + const uint32_t min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize; + /* take these from the current frame in case they've changed mid-stream */ + uint32_t channels = FLAC__stream_decoder_get_channels(decoder); + uint32_t bps = FLAC__stream_decoder_get_bits_per_sample(decoder); + const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0; + + /* use values from stream info if we didn't decode a frame */ + if(channels == 0) + channels = decoder->private_->stream_info.data.stream_info.channels; + if(bps == 0) + bps = decoder->private_->stream_info.data.stream_info.bits_per_sample; + + /* we are just guessing here */ + if(max_framesize > 0) + approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1; + /* + * Check if it's a known fixed-blocksize stream. Note that though + * the spec doesn't allow zeroes in the STREAMINFO block, we may + * never get a STREAMINFO block when decoding so the value of + * min_blocksize might be zero. + */ + else if(min_blocksize == max_blocksize && min_blocksize > 0) { + /* note there are no () around 'bps/8' to keep precision up since it's an integer calculation */ + approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64; + } + else + approx_bytes_per_frame = 4096 * channels * bps/8 + 64; + + /* + * First, we set an upper and lower bound on where in the + * stream we will search. For now we take the current position + * as one bound and, depending on where the target position lies, + * the beginning of the first frame or the end of the stream as + * the other bound. + */ + lower_bound = first_frame_offset; + lower_bound_sample = 0; + upper_bound = stream_length; + upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/; + + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && + decoder->private_->samples_decoded != 0) { + if(target_sample < decoder->private_->samples_decoded) { + if(FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) + upper_bound_sample = decoder->private_->samples_decoded; + } else { + if(FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) + lower_bound_sample = decoder->private_->samples_decoded; + } + } + + /* + * Now we refine the bounds if we have a seektable with + * suitable points. Note that according to the spec they + * must be ordered by ascending sample number. + * + * Note: to protect against invalid seek tables we will ignore points + * that have frame_samples==0 or sample_number>=total_samples. Also, + * because math is limited to 64-bit ints, seekpoints with an offset + * larger than 2^63 (8 exbibyte) are rejected. + */ + if(seek_table) { + FLAC__uint64 new_lower_bound = lower_bound; + FLAC__uint64 new_upper_bound = upper_bound; + FLAC__uint64 new_lower_bound_sample = lower_bound_sample; + FLAC__uint64 new_upper_bound_sample = upper_bound_sample; + + /* find the closest seek point <= target_sample, if it exists */ + for(i = (int)seek_table->num_points - 1; i >= 0; i--) { + if( + seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && + seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ + (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ + seek_table->points[i].sample_number <= target_sample + ) + break; + } + if(i >= 0) { /* i.e. we found a suitable seek point... */ + new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset; + new_lower_bound_sample = seek_table->points[i].sample_number; + } + + /* find the closest seek point > target_sample, if it exists */ + for(i = 0; i < (int)seek_table->num_points; i++) { + if( + seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && + seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ + (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ + seek_table->points[i].sample_number > target_sample + ) + break; + } + if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */ + new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset; + new_upper_bound_sample = seek_table->points[i].sample_number; + } + /* final protection against unsorted seek tables; keep original values if bogus */ + if(new_upper_bound >= new_lower_bound) { + lower_bound = new_lower_bound; + upper_bound = new_upper_bound; + lower_bound_sample = new_lower_bound_sample; + upper_bound_sample = new_upper_bound_sample; + } + } + + FLAC__ASSERT(upper_bound_sample >= lower_bound_sample); + /* there are 2 insidious ways that the following equality occurs, which + * we need to fix: + * 1) total_samples is 0 (unknown) and target_sample is 0 + * 2) total_samples is 0 (unknown) and target_sample happens to be + * exactly equal to the last seek point in the seek table; this + * means there is no seek point above it, and upper_bound_samples + * remains equal to the estimate (of target_samples) we made above + * in either case it does not hurt to move upper_bound_sample up by 1 + */ + if(upper_bound_sample == lower_bound_sample) + upper_bound_sample++; + + decoder->private_->target_sample = target_sample; + while(1) { + /* check whether decoder is still valid so bad state isn't overwritten + * with seek error */ + if(decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || + decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) + return false; + /* check if the bounds are still ok */ + if (lower_bound_sample >= upper_bound_sample || + lower_bound > upper_bound || + upper_bound >= INT64_MAX) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(seek_from_lower_bound) { + pos = lower_bound; + } + else { +#ifndef FLAC__INTEGER_ONLY_LIBRARY + pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (double)(upper_bound - lower_bound)) - approx_bytes_per_frame; +#else + /* a little less accurate: */ + if(upper_bound - lower_bound < 0xffffffff) + pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame; + else { /* @@@ WATCHOUT, ~2TB limit */ + FLAC__uint64 ratio = (1<<16) / (upper_bound_sample - lower_bound_sample); + pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8) * ratio)) - approx_bytes_per_frame; + } +#endif + } + if(pos >= (FLAC__int64)upper_bound) + pos = (FLAC__int64)upper_bound - 1; + if(pos < (FLAC__int64)lower_bound) + pos = (FLAC__int64)lower_bound; + if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_flush(decoder)) { + /* above call sets the state for us */ + return false; + } + /* Now we need to get a frame. First we need to reset our + * unparseable_frame_count; if we get too many unparseable + * frames in a row, the read callback will return + * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing + * FLAC__stream_decoder_process_single() to return false. + */ + decoder->private_->unparseable_frame_count = 0; + if(!FLAC__stream_decoder_process_single(decoder) || decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED || 0 == decoder->private_->samples_decoded) { + /* No frame could be decoded */ + if(decoder->protected_->state != FLAC__STREAM_DECODER_ABORTED && decoder->private_->eof_callback(decoder, decoder->private_->client_data) && !seek_from_lower_bound){ + /* decoder has hit end of stream while processing corrupt + * frame. To remedy this, try decoding a frame at the lower + * bound so the seek after that hopefully ends up somewhere + * else */ + seek_from_lower_bound = true; + continue; + } + else { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + } + seek_from_lower_bound = false; + + /* our write callback will change the state when it gets to the target frame */ + /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */ + if(!decoder->private_->is_seeking) + break; + + FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + this_frame_sample = decoder->private_->last_frame.header.number.sample_number; + + if(this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek) { + if (pos == (FLAC__int64)lower_bound) { + /* can't move back any more than the first frame, something is fatally wrong */ + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + /* our last move backwards wasn't big enough, try again */ + approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16; + continue; + } + /* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */ + first_seek = false; + + /* make sure we are not seeking in corrupted stream */ + if (this_frame_sample < lower_bound_sample) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + + /* we need to narrow the search */ + if(target_sample < this_frame_sample) { + upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; +/*@@@@@@ what will decode position be if at end of stream? */ + if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + approx_bytes_per_frame = (uint32_t)(2 * (upper_bound - pos) / 3 + 16); + } + else { /* target_sample >= this_frame_sample + this frame's blocksize */ + lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; + if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + approx_bytes_per_frame = (uint32_t)(2 * (lower_bound - pos) / 3 + 16); + } + } + + return true; +} + +#if FLAC__HAS_OGG +FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) +{ + FLAC__uint64 left_pos = 0, right_pos = stream_length; + FLAC__uint64 left_sample = 0, right_sample = FLAC__stream_decoder_get_total_samples(decoder); + FLAC__uint64 this_frame_sample = (FLAC__uint64)0 - 1; + FLAC__uint64 pos = 0; /* only initialized to avoid compiler warning */ + FLAC__bool did_a_seek; + uint32_t iteration = 0; + + /* In the first iterations, we will calculate the target byte position + * by the distance from the target sample to left_sample and + * right_sample (let's call it "proportional search"). After that, we + * will switch to binary search. + */ + uint32_t BINARY_SEARCH_AFTER_ITERATION = 2; + + /* We will switch to a linear search once our current sample is less + * than this number of samples ahead of the target sample + */ + static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2; + + /* If the total number of samples is unknown, use a large value, and + * force binary search immediately. + */ + if(right_sample == 0) { + right_sample = (FLAC__uint64)(-1); + BINARY_SEARCH_AFTER_ITERATION = 0; + } + + decoder->private_->target_sample = target_sample; + for( ; ; iteration++) { + /* Do sanity checks on bounds */ + if(right_pos <= left_pos || right_pos - left_pos < 9) { + /* FLAC frame is at least 9 byte in size */ + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if (iteration == 0 || this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) { + if (iteration >= BINARY_SEARCH_AFTER_ITERATION) { + pos = (right_pos + left_pos) / 2; + } + else { +#ifndef FLAC__INTEGER_ONLY_LIBRARY + pos = (FLAC__uint64)((double)(target_sample - left_sample) / (double)(right_sample - left_sample) * (double)(right_pos - left_pos)); +#else + /* a little less accurate: */ + if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff)) + pos = (FLAC__int64)(((target_sample-left_sample) * (right_pos-left_pos)) / (right_sample-left_sample)); + else /* @@@ WATCHOUT, ~2TB limit */ + pos = (FLAC__int64)((((target_sample-left_sample)>>8) * ((right_pos-left_pos)>>8)) / ((right_sample-left_sample)>>16)); +#endif + /* @@@ TODO: might want to limit pos to some distance + * before EOF, to make sure we land before the last frame, + * thereby getting a this_frame_sample and so having a better + * estimate. + */ + } + + /* physical seek */ + if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_flush(decoder)) { + /* above call sets the state for us */ + return false; + } + did_a_seek = true; + } + else + did_a_seek = false; + + decoder->private_->got_a_frame = false; + if(!FLAC__stream_decoder_process_single(decoder) || + decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!decoder->private_->got_a_frame) { + if(did_a_seek) { + /* this can happen if we seek to a point after the last frame; we drop + * to binary search right away in this case to avoid any wasted + * iterations of proportional search. + */ + right_pos = pos; + BINARY_SEARCH_AFTER_ITERATION = 0; + } + else { + /* this can probably only happen if total_samples is unknown and the + * target_sample is past the end of the stream + */ + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + } + /* our write callback will change the state when it gets to the target frame */ + else if(!decoder->private_->is_seeking) { + break; + } + else { + this_frame_sample = decoder->private_->last_frame.header.number.sample_number; + FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + + if (did_a_seek) { + if (this_frame_sample <= target_sample) { + /* The 'equal' case should not happen, since + * FLAC__stream_decoder_process_single() + * should recognize that it has hit the + * target sample and we would exit through + * the 'break' above. + */ + FLAC__ASSERT(this_frame_sample != target_sample); + + left_sample = this_frame_sample; + /* sanity check to avoid infinite loop */ + if (left_pos == pos) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + left_pos = pos; + } + else { + right_sample = this_frame_sample; + /* sanity check to avoid infinite loop */ + if (right_pos == pos) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + right_pos = pos; + } + } + } + } + + return true; +} +#endif + +FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + (void)client_data; + + if(*bytes > 0) { + *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file); + if(ferror(decoder->private_->file)) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + else if(*bytes == 0) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ +} + +FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + (void)client_data; + + if(decoder->private_->file == stdin) + return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; + else if(fseeko(decoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FLAC__off_t pos; + (void)client_data; + + if(decoder->private_->file == stdin) + return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; + else if((pos = ftello(decoder->private_->file)) < 0) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } +} + +FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + struct flac_stat_s filestats; + (void)client_data; + + if(decoder->private_->file == stdin) + return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; + +#ifndef FLAC__USE_FILELENGTHI64 + if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0) +#else + filestats.st_size = _filelengthi64(fileno(decoder->private_->file)); + if(filestats.st_size < 0) +#endif + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + else { + *stream_length = (FLAC__uint64)filestats.st_size; + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } +} + +FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data) +{ + (void)client_data; + + return feof(decoder->private_->file)? true : false; +} diff --git a/vendor/flac/src/libFLAC/stream_encoder.c b/vendor/flac/src/libFLAC/stream_encoder.c new file mode 100644 index 0000000..c1c03e4 --- /dev/null +++ b/vendor/flac/src/libFLAC/stream_encoder.c @@ -0,0 +1,4738 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include /* for malloc() */ +#include /* for memcpy() */ +#include /* for off_t */ +#ifdef _WIN32 +#include /* for GetFileType() */ +#include /* for _get_osfhandle() */ +#endif +#include "share/compat.h" +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "protected/stream_encoder.h" +#include "private/bitwriter.h" +#include "private/bitmath.h" +#include "private/crc.h" +#include "private/cpu.h" +#include "private/fixed.h" +#include "private/format.h" +#include "private/lpc.h" +#include "private/md5.h" +#include "private/memory.h" +#include "private/macros.h" +#if FLAC__HAS_OGG +#include "private/ogg_helper.h" +#include "private/ogg_mapping.h" +#endif +#include "private/stream_encoder.h" +#include "private/stream_encoder_framing.h" +#include "private/window.h" +#include "share/alloc.h" +#include "share/private.h" + + +/* Exact Rice codeword length calculation is off by default. The simple + * (and fast) estimation (of how many bits a residual value will be + * encoded with) in this encoder is very good, almost always yielding + * compression within 0.1% of exact calculation. + */ +#undef EXACT_RICE_BITS_CALCULATION +/* Rice parameter searching is off by default. The simple (and fast) + * parameter estimation in this encoder is very good, almost always + * yielding compression within 0.1% of the optimal parameters. + */ +#undef ENABLE_RICE_PARAMETER_SEARCH + + +typedef struct { + FLAC__int32 *data[FLAC__MAX_CHANNELS]; + uint32_t size; /* of each data[] in samples */ + uint32_t tail; +} verify_input_fifo; + +typedef struct { + const FLAC__byte *data; + uint32_t capacity; + uint32_t bytes; +} verify_output; + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +typedef struct { + uint32_t a, b, c; + FLAC__ApodizationSpecification * current_apodization; + double autoc_root[FLAC__MAX_LPC_ORDER+1]; + double autoc[FLAC__MAX_LPC_ORDER+1]; +} apply_apodization_state_struct; +#endif + +typedef enum { + ENCODER_IN_MAGIC = 0, + ENCODER_IN_METADATA = 1, + ENCODER_IN_AUDIO = 2 +} EncoderStateHint; + +static const struct CompressionLevels { + FLAC__bool do_mid_side_stereo; + FLAC__bool loose_mid_side_stereo; + uint32_t max_lpc_order; + uint32_t qlp_coeff_precision; + FLAC__bool do_qlp_coeff_prec_search; + FLAC__bool do_escape_coding; + FLAC__bool do_exhaustive_model_search; + uint32_t min_residual_partition_order; + uint32_t max_residual_partition_order; + uint32_t rice_parameter_search_dist; + const char *apodization; +} compression_levels_[] = { + { false, false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, + { true , true , 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, + { true , false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, + { false, false, 6, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, + { true , true , 8, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, + { true , false, 8, 0, false, false, false, 0, 5, 0, "tukey(5e-1)" }, + { true , false, 8, 0, false, false, false, 0, 6, 0, "subdivide_tukey(2)" }, + { true , false, 12, 0, false, false, false, 0, 6, 0, "subdivide_tukey(2)" }, + { true , false, 12, 0, false, false, false, 0, 6, 0, "subdivide_tukey(3)" } + /* here we use locale-independent 5e-1 instead of 0.5 or 0,5 */ +}; + + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +static void set_defaults_(FLAC__StreamEncoder *encoder); +static void free_(FLAC__StreamEncoder *encoder); +static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, uint32_t new_blocksize); +static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t samples, FLAC__bool is_last_block); +static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, FLAC__bool is_last_block); +static void update_metadata_(const FLAC__StreamEncoder *encoder); +#if FLAC__HAS_OGG +static void update_ogg_metadata_(FLAC__StreamEncoder *encoder); +#endif +static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_block); +static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder); + +static FLAC__bool process_subframe_( + FLAC__StreamEncoder *encoder, + uint32_t min_partition_order, + uint32_t max_partition_order, + const FLAC__FrameHeader *frame_header, + uint32_t subframe_bps, + const void *integer_signal, + FLAC__Subframe *subframe[2], + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], + FLAC__int32 *residual[2], + uint32_t *best_subframe, + uint32_t *best_bits +); + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +static FLAC__bool apply_apodization_( + FLAC__StreamEncoder *encoder, + apply_apodization_state_struct *apply_apodization_state, + uint32_t blocksize, + double *lpc_error, + uint32_t *max_lpc_order_this_apodization, + uint32_t subframe_bps, + const void *integer_signal, + uint32_t *guess_lpc_order +); +#endif + +static FLAC__bool add_subframe_( + FLAC__StreamEncoder *encoder, + uint32_t blocksize, + uint32_t subframe_bps, + const FLAC__Subframe *subframe, + FLAC__BitWriter *frame +); + +static uint32_t evaluate_constant_subframe_( + FLAC__StreamEncoder *encoder, + const FLAC__int64 signal, + uint32_t blocksize, + uint32_t subframe_bps, + FLAC__Subframe *subframe +); + +static uint32_t evaluate_fixed_subframe_( + FLAC__StreamEncoder *encoder, + const void *signal, + FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t raw_bits_per_partition[], + uint32_t blocksize, + uint32_t subframe_bps, + uint32_t order, + uint32_t rice_parameter_limit, + uint32_t min_partition_order, + uint32_t max_partition_order, + FLAC__bool do_escape_coding, + uint32_t rice_parameter_search_dist, + FLAC__Subframe *subframe, + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents +); + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +static uint32_t evaluate_lpc_subframe_( + FLAC__StreamEncoder *encoder, + const void *signal, + FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t raw_bits_per_partition[], + const FLAC__real lp_coeff[], + uint32_t blocksize, + uint32_t subframe_bps, + uint32_t order, + uint32_t qlp_coeff_precision, + uint32_t rice_parameter_limit, + uint32_t min_partition_order, + uint32_t max_partition_order, + FLAC__bool do_escape_coding, + uint32_t rice_parameter_search_dist, + FLAC__Subframe *subframe, + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents +); +#endif + +static uint32_t evaluate_verbatim_subframe_( + FLAC__StreamEncoder *encoder, + const void *signal, + uint32_t blocksize, + uint32_t subframe_bps, + FLAC__Subframe *subframe +); + +static uint32_t find_best_partition_order_( + struct FLAC__StreamEncoderPrivate *private_, + const FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t raw_bits_per_partition[], + uint32_t residual_samples, + uint32_t predictor_order, + uint32_t rice_parameter_limit, + uint32_t min_partition_order, + uint32_t max_partition_order, + uint32_t bps, + FLAC__bool do_escape_coding, + uint32_t rice_parameter_search_dist, + FLAC__EntropyCodingMethod *best_ecm +); + +static void precompute_partition_info_sums_( + const FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, + uint32_t predictor_order, + uint32_t min_partition_order, + uint32_t max_partition_order, + uint32_t bps +); + +static void precompute_partition_info_escapes_( + const FLAC__int32 residual[], + uint32_t raw_bits_per_partition[], + uint32_t residual_samples, + uint32_t predictor_order, + uint32_t min_partition_order, + uint32_t max_partition_order +); + +static FLAC__bool set_partitioned_rice_( +#ifdef EXACT_RICE_BITS_CALCULATION + const FLAC__int32 residual[], +#endif + const FLAC__uint64 abs_residual_partition_sums[], + const uint32_t raw_bits_per_partition[], + const uint32_t residual_samples, + const uint32_t predictor_order, + const uint32_t rice_parameter_limit, + const uint32_t rice_parameter_search_dist, + const uint32_t partition_order, + const FLAC__bool search_for_escapes, + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, + uint32_t *bits +); + +static uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples); +static uint32_t get_wasted_bits_wide_(FLAC__int64 signal_wide[], FLAC__int32 signal[], uint32_t samples); + +/* verify-related routines: */ +static void append_to_verify_fifo_( + verify_input_fifo *fifo, + const FLAC__int32 * const input[], + uint32_t input_offset, + uint32_t channels, + uint32_t wide_samples +); + +static void append_to_verify_fifo_interleaved_( + verify_input_fifo *fifo, + const FLAC__int32 input[], + uint32_t input_offset, + uint32_t channels, + uint32_t wide_samples +); + +static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +static FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); +static FILE *get_binary_stdout_(void); + + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +typedef struct FLAC__StreamEncoderPrivate { + uint32_t input_capacity; /* current size (in samples) of the signal and residual buffers */ + FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS]; /* the integer version of the input signal */ + FLAC__int32 *integer_signal_mid_side[2]; /* the integer version of the mid-side input signal (stereo only) */ + FLAC__int64 *integer_signal_33bit_side; /* 33-bit side for 32-bit stereo decorrelation */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__real *real_signal[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) the floating-point version of the input signal */ + FLAC__real *real_signal_mid_side[2]; /* (@@@ currently unused) the floating-point version of the mid-side input signal (stereo only) */ + FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */ + FLAC__real *windowed_signal; /* the integer_signal[] * current window[] */ +#endif + uint32_t subframe_bps[FLAC__MAX_CHANNELS]; /* the effective bits per sample of the input signal (stream bps - wasted bits) */ + uint32_t subframe_bps_mid_side[2]; /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */ + FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */ + FLAC__int32 *residual_workspace_mid_side[2][2]; + FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2]; + FLAC__Subframe subframe_workspace_mid_side[2][2]; + FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2]; + FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2]; + FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2]; + FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2]; + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2]; + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2]; + uint32_t best_subframe[FLAC__MAX_CHANNELS]; /* index (0 or 1) into 2nd dimension of the above workspaces */ + uint32_t best_subframe_mid_side[2]; + uint32_t best_subframe_bits[FLAC__MAX_CHANNELS]; /* size in bits of the best subframe for each channel */ + uint32_t best_subframe_bits_mid_side[2]; + FLAC__uint64 *abs_residual_partition_sums; /* workspace where the sum of abs(candidate residual) for each partition is stored */ + uint32_t *raw_bits_per_partition; /* workspace where the sum of silog2(candidate residual) for each partition is stored */ + FLAC__BitWriter *frame; /* the current frame being worked on */ + uint32_t loose_mid_side_stereo_frames; /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */ + uint32_t loose_mid_side_stereo_frame_count; /* number of frames using the current channel assignment */ + FLAC__ChannelAssignment last_channel_assignment; + FLAC__StreamMetadata streaminfo; /* scratchpad for STREAMINFO as it is built */ + FLAC__StreamMetadata_SeekTable *seek_table; /* pointer into encoder->protected_->metadata_ where the seek table is */ + uint32_t current_sample_number; + uint32_t current_frame_number; + FLAC__MD5Context md5context; + FLAC__CPUInfo cpuinfo; + void (*local_precompute_partition_info_sums)(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + uint32_t (*local_fixed_compute_best_predictor_limit_residual)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +#else + uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + uint32_t (*local_fixed_compute_best_predictor_limit_residual)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +#endif +#ifndef FLAC__INTEGER_ONLY_LIBRARY + void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); + void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); + void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); + void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); +#endif + FLAC__bool disable_mmx; + FLAC__bool disable_sse2; + FLAC__bool disable_ssse3; + FLAC__bool disable_sse41; + FLAC__bool disable_sse42; + FLAC__bool disable_avx2; + FLAC__bool disable_fma; + FLAC__bool disable_constant_subframes; + FLAC__bool disable_fixed_subframes; + FLAC__bool disable_verbatim_subframes; + FLAC__bool is_ogg; + FLAC__StreamEncoderReadCallback read_callback; /* currently only needed for Ogg FLAC */ + FLAC__StreamEncoderSeekCallback seek_callback; + FLAC__StreamEncoderTellCallback tell_callback; + FLAC__StreamEncoderWriteCallback write_callback; + FLAC__StreamEncoderMetadataCallback metadata_callback; + FLAC__StreamEncoderProgressCallback progress_callback; + void *client_data; + uint32_t first_seekpoint_to_check; + FILE *file; /* only used when encoding to a file */ + FLAC__uint64 bytes_written; + FLAC__uint64 samples_written; + uint32_t frames_written; + uint32_t total_frames_estimate; + /* unaligned (original) pointers to allocated data */ + FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS]; + FLAC__int32 *integer_signal_mid_side_unaligned[2]; + FLAC__int64 *integer_signal_33bit_side_unaligned; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) */ + FLAC__real *real_signal_mid_side_unaligned[2]; /* (@@@ currently unused) */ + FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS]; + FLAC__real *windowed_signal_unaligned; +#endif + FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2]; + FLAC__int32 *residual_workspace_mid_side_unaligned[2][2]; + FLAC__uint64 *abs_residual_partition_sums_unaligned; + uint32_t *raw_bits_per_partition_unaligned; + /* + * These fields have been moved here from private function local + * declarations merely to save stack space during encoding. + */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */ +#endif + FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */ + /* + * The data for the verify section + */ + struct { + FLAC__StreamDecoder *decoder; + EncoderStateHint state_hint; + FLAC__bool needs_magic_hack; + verify_input_fifo input_fifo; + verify_output output; + struct { + FLAC__uint64 absolute_sample; + uint32_t frame_number; + uint32_t channel; + uint32_t sample; + FLAC__int32 expected; + FLAC__int32 got; + } error_stats; + } verify; + FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */ +} FLAC__StreamEncoderPrivate; + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +FLAC_API const char * const FLAC__StreamEncoderStateString[] = { + "FLAC__STREAM_ENCODER_OK", + "FLAC__STREAM_ENCODER_UNINITIALIZED", + "FLAC__STREAM_ENCODER_OGG_ERROR", + "FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR", + "FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA", + "FLAC__STREAM_ENCODER_CLIENT_ERROR", + "FLAC__STREAM_ENCODER_IO_ERROR", + "FLAC__STREAM_ENCODER_FRAMING_ERROR", + "FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR" +}; + +FLAC_API const char * const FLAC__StreamEncoderInitStatusString[] = { + "FLAC__STREAM_ENCODER_INIT_STATUS_OK", + "FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR", + "FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION", + "FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER", + "FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA", + "FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED" +}; + +FLAC_API const char * const FLAC__StreamEncoderReadStatusString[] = { + "FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE", + "FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM", + "FLAC__STREAM_ENCODER_READ_STATUS_ABORT", + "FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = { + "FLAC__STREAM_ENCODER_WRITE_STATUS_OK", + "FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR" +}; + +FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[] = { + "FLAC__STREAM_ENCODER_SEEK_STATUS_OK", + "FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR", + "FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamEncoderTellStatusString[] = { + "FLAC__STREAM_ENCODER_TELL_STATUS_OK", + "FLAC__STREAM_ENCODER_TELL_STATUS_ERROR", + "FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED" +}; + +/* Number of samples that will be overread to watch for end of stream. By + * 'overread', we mean that the FLAC__stream_encoder_process*() calls will + * always try to read blocksize+1 samples before encoding a block, so that + * even if the stream has a total sample count that is an integral multiple + * of the blocksize, we will still notice when we are encoding the last + * block. This is needed, for example, to correctly set the end-of-stream + * marker in Ogg FLAC. + * + * WATCHOUT: some parts of the code assert that OVERREAD_ == 1 and there's + * not really any reason to change it. + */ +static const uint32_t OVERREAD_ = 1; + +/*********************************************************************** + * + * Class constructor/destructor + * + */ +FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void) +{ + FLAC__StreamEncoder *encoder; + uint32_t i; + + FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ + + encoder = calloc(1, sizeof(FLAC__StreamEncoder)); + if(encoder == 0) { + return 0; + } + + encoder->protected_ = calloc(1, sizeof(FLAC__StreamEncoderProtected)); + if(encoder->protected_ == 0) { + free(encoder); + return 0; + } + + encoder->private_ = calloc(1, sizeof(FLAC__StreamEncoderPrivate)); + if(encoder->private_ == 0) { + free(encoder->protected_); + free(encoder); + return 0; + } + + encoder->private_->frame = FLAC__bitwriter_new(); + if(encoder->private_->frame == 0) { + free(encoder->private_); + free(encoder->protected_); + free(encoder); + return 0; + } + + encoder->private_->file = 0; + + encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; + + set_defaults_(encoder); + + encoder->private_->is_being_deleted = false; + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0]; + encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1]; + } + for(i = 0; i < 2; i++) { + encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0]; + encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1]; + } + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0]; + encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1]; + } + for(i = 0; i < 2; i++) { + encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]; + encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]; + } + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]); + } + for(i = 0; i < 2; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]); + } + for(i = 0; i < 2; i++) + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]); + + return encoder; +} + +FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder) +{ + uint32_t i; + + if (encoder == NULL) + return ; + + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->private_->frame); + + encoder->private_->is_being_deleted = true; + + (void)FLAC__stream_encoder_finish(encoder); + + if(0 != encoder->private_->verify.decoder) + FLAC__stream_decoder_delete(encoder->private_->verify.decoder); + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]); + } + for(i = 0; i < 2; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]); + } + for(i = 0; i < 2; i++) + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]); + + FLAC__bitwriter_delete(encoder->private_->frame); + free(encoder->private_); + free(encoder->protected_); + free(encoder); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +static FLAC__StreamEncoderInitStatus init_stream_internal_( + FLAC__StreamEncoder *encoder, + FLAC__StreamEncoderReadCallback read_callback, + FLAC__StreamEncoderWriteCallback write_callback, + FLAC__StreamEncoderSeekCallback seek_callback, + FLAC__StreamEncoderTellCallback tell_callback, + FLAC__StreamEncoderMetadataCallback metadata_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + uint32_t i; + FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment, metadata_picture_has_type1, metadata_picture_has_type2; + + FLAC__ASSERT(0 != encoder); + + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; + + if(FLAC__HAS_OGG == 0 && is_ogg) + return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER; + + if(0 == write_callback || (seek_callback && 0 == tell_callback)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS; + + if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS; + + if(encoder->protected_->channels != 2) { + encoder->protected_->do_mid_side_stereo = false; + encoder->protected_->loose_mid_side_stereo = false; + } + else if(!encoder->protected_->do_mid_side_stereo) + encoder->protected_->loose_mid_side_stereo = false; + + if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__MAX_BITS_PER_SAMPLE) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE; + + if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE; + + if(encoder->protected_->blocksize == 0) { + if(encoder->protected_->max_lpc_order == 0) + encoder->protected_->blocksize = 1152; + else + encoder->protected_->blocksize = 4096; + } + + if(encoder->protected_->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->protected_->blocksize > FLAC__MAX_BLOCK_SIZE) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE; + + if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER; + + if(encoder->protected_->blocksize < encoder->protected_->max_lpc_order) + return FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER; + + if(encoder->protected_->qlp_coeff_precision == 0) { + if(encoder->protected_->bits_per_sample < 16) { + /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */ + /* @@@ until then we'll make a guess */ + encoder->protected_->qlp_coeff_precision = flac_max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2); + } + else if(encoder->protected_->bits_per_sample == 16) { + if(encoder->protected_->blocksize <= 192) + encoder->protected_->qlp_coeff_precision = 7; + else if(encoder->protected_->blocksize <= 384) + encoder->protected_->qlp_coeff_precision = 8; + else if(encoder->protected_->blocksize <= 576) + encoder->protected_->qlp_coeff_precision = 9; + else if(encoder->protected_->blocksize <= 1152) + encoder->protected_->qlp_coeff_precision = 10; + else if(encoder->protected_->blocksize <= 2304) + encoder->protected_->qlp_coeff_precision = 11; + else if(encoder->protected_->blocksize <= 4608) + encoder->protected_->qlp_coeff_precision = 12; + else + encoder->protected_->qlp_coeff_precision = 13; + } + else { + if(encoder->protected_->blocksize <= 384) + encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2; + else if(encoder->protected_->blocksize <= 1152) + encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1; + else + encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; + } + FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION); + } + else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION; + + if(encoder->protected_->streamable_subset) { + if(!FLAC__format_blocksize_is_subset(encoder->protected_->blocksize, encoder->protected_->sample_rate)) + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + if(!FLAC__format_sample_rate_is_subset(encoder->protected_->sample_rate)) + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + if( + encoder->protected_->bits_per_sample != 8 && + encoder->protected_->bits_per_sample != 12 && + encoder->protected_->bits_per_sample != 16 && + encoder->protected_->bits_per_sample != 20 && + encoder->protected_->bits_per_sample != 24 && + encoder->protected_->bits_per_sample != 32 + ) + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER) + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + if( + encoder->protected_->sample_rate <= 48000 && + ( + encoder->protected_->blocksize > FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ || + encoder->protected_->max_lpc_order > FLAC__SUBSET_MAX_LPC_ORDER_48000HZ + ) + ) { + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + } + } + + if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1; + if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order) + encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order; + +#if FLAC__HAS_OGG + /* drop any seektable for ogg */ + if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) { + uint32_t i1; + for(i1 = 0; i1 < encoder->protected_->num_metadata_blocks; i1++) { + if(0 != encoder->protected_->metadata[i1] && encoder->protected_->metadata[i1]->type == FLAC__METADATA_TYPE_SEEKTABLE) { + encoder->protected_->num_metadata_blocks--; + for( ; i1 < encoder->protected_->num_metadata_blocks; i1++) + encoder->protected_->metadata[i1] = encoder->protected_->metadata[i1+1]; + break; + } + } + } + /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */ + if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 1) { + uint32_t i1; + for(i1 = 1; i1 < encoder->protected_->num_metadata_blocks; i1++) { + if(0 != encoder->protected_->metadata[i1] && encoder->protected_->metadata[i1]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + FLAC__StreamMetadata *vc = encoder->protected_->metadata[i1]; + for( ; i1 > 0; i1--) + encoder->protected_->metadata[i1] = encoder->protected_->metadata[i1-1]; + encoder->protected_->metadata[0] = vc; + break; + } + } + } +#endif + /* keep track of any SEEKTABLE block */ + if(0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) { + uint32_t i2; + for(i2 = 0; i2 < encoder->protected_->num_metadata_blocks; i2++) { + if(0 != encoder->protected_->metadata[i2] && encoder->protected_->metadata[i2]->type == FLAC__METADATA_TYPE_SEEKTABLE) { + encoder->private_->seek_table = &encoder->protected_->metadata[i2]->data.seek_table; + break; /* take only the first one */ + } + } + } + + /* validate metadata */ + if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + metadata_has_seektable = false; + metadata_has_vorbis_comment = false; + metadata_picture_has_type1 = false; + metadata_picture_has_type2 = false; + for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) { + const FLAC__StreamMetadata *m = encoder->protected_->metadata[i]; + if(m->type == FLAC__METADATA_TYPE_STREAMINFO) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + else if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) { + if(metadata_has_seektable) /* only one is allowed */ + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + metadata_has_seektable = true; + if(!FLAC__format_seektable_is_legal(&m->data.seek_table)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + } + else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + if(metadata_has_vorbis_comment) /* only one is allowed */ + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + metadata_has_vorbis_comment = true; + } + else if(m->type == FLAC__METADATA_TYPE_CUESHEET) { + if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + } + else if(m->type == FLAC__METADATA_TYPE_PICTURE) { + if(!FLAC__format_picture_is_legal(&m->data.picture, /*violation=*/0)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) { + if(metadata_picture_has_type1) /* there should only be 1 per stream */ + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + metadata_picture_has_type1 = true; + /* standard icon must be 32x32 pixel PNG */ + if( + m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && + ( + (strcmp(m->data.picture.mime_type, "image/png") && strcmp(m->data.picture.mime_type, "-->")) || + m->data.picture.width != 32 || + m->data.picture.height != 32 + ) + ) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + } + else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) { + if(metadata_picture_has_type2) /* there should only be 1 per stream */ + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + metadata_picture_has_type2 = true; + } + } + } + + encoder->private_->input_capacity = 0; + for(i = 0; i < encoder->protected_->channels; i++) { + encoder->private_->integer_signal_unaligned[i] = encoder->private_->integer_signal[i] = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0; +#endif + } + for(i = 0; i < 2; i++) { + encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0; +#endif + } + encoder->private_->integer_signal_33bit_side_unaligned = encoder->private_->integer_signal_33bit_side = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + for(i = 0; i < encoder->protected_->num_apodizations; i++) + encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0; + encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0; +#endif + for(i = 0; i < encoder->protected_->channels; i++) { + encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0; + encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0; + encoder->private_->best_subframe[i] = 0; + } + for(i = 0; i < 2; i++) { + encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0; + encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0; + encoder->private_->best_subframe_mid_side[i] = 0; + } + encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0; + encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->loose_mid_side_stereo_frames = (uint32_t)((double)encoder->protected_->sample_rate * 0.4 / (double)encoder->protected_->blocksize + 0.5); +#else + /* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */ + /* sample rate can be up to 1048575 Hz, and thus use 20 bits, so we do the multiply÷ by hand */ + FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 1048575); + FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535); + FLAC__ASSERT(encoder->protected_->sample_rate <= 1048575); + FLAC__ASSERT(encoder->protected_->blocksize <= 65535); + encoder->private_->loose_mid_side_stereo_frames = (uint32_t)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF); +#endif + if(encoder->private_->loose_mid_side_stereo_frames == 0) + encoder->private_->loose_mid_side_stereo_frames = 1; + encoder->private_->loose_mid_side_stereo_frame_count = 0; + encoder->private_->current_sample_number = 0; + encoder->private_->current_frame_number = 0; + + /* + * get the CPU info and set the function pointers + */ + FLAC__cpu_info(&encoder->private_->cpuinfo); + /* remove cpu info as requested by + * FLAC__stream_encoder_disable_instruction_set */ + if(encoder->private_->disable_mmx) + encoder->private_->cpuinfo.x86.mmx = false; + if(encoder->private_->disable_sse2) + encoder->private_->cpuinfo.x86.sse2 = false; + if(encoder->private_->disable_ssse3) + encoder->private_->cpuinfo.x86.ssse3 = false; + if(encoder->private_->disable_sse41) + encoder->private_->cpuinfo.x86.sse41 = false; + if(encoder->private_->disable_sse42) + encoder->private_->cpuinfo.x86.sse42 = false; + if(encoder->private_->disable_avx2) + encoder->private_->cpuinfo.x86.avx2 = false; + if(encoder->private_->disable_fma) + encoder->private_->cpuinfo.x86.fma = false; + /* first default to the non-asm routines */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; +#endif + encoder->private_->local_precompute_partition_info_sums = precompute_partition_info_sums_; + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor; + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide; + encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients; +#endif + /* now override with asm where appropriate */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY +# ifndef FLAC__NO_ASM +#if defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN +#if FLAC__HAS_A64NEONINTRIN + if(encoder->protected_->max_lpc_order < 8) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_neon_lag_8; + else if(encoder->protected_->max_lpc_order < 10) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_neon_lag_10; + else if(encoder->protected_->max_lpc_order < 14) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_neon_lag_14; + else + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; +#endif + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_neon; +#endif /* defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN */ + + if(encoder->private_->cpuinfo.use_asm) { +# ifdef FLAC__CPU_IA32 + FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); +# if FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED + if (encoder->private_->cpuinfo.x86.sse2) { + if(encoder->protected_->max_lpc_order < 8) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8; + else if(encoder->protected_->max_lpc_order < 10) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10; + else if(encoder->protected_->max_lpc_order < 14) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14; + + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; + } +# endif +# ifdef FLAC__SSE4_1_SUPPORTED + if (encoder->private_->cpuinfo.x86.sse41) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41; + } +# endif +# ifdef FLAC__AVX2_SUPPORTED + if (encoder->private_->cpuinfo.x86.avx2) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; + } +# endif + +# ifdef FLAC__SSE2_SUPPORTED + if (encoder->private_->cpuinfo.x86.sse2) { + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; + } +# endif +# ifdef FLAC__SSSE3_SUPPORTED + if (encoder->private_->cpuinfo.x86.ssse3) { + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; + } +# endif +# ifdef FLAC__SSE4_2_SUPPORTED + if (encoder->private_->cpuinfo.x86.sse42) { + encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42; + } +# endif +# ifdef FLAC__AVX2_SUPPORTED + if (encoder->private_->cpuinfo.x86.avx2) { + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_avx2; + encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2; + } +# endif +# endif /* FLAC__HAS_X86INTRIN */ +# elif defined FLAC__CPU_X86_64 + FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64); +# if FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED + if(encoder->private_->cpuinfo.x86.sse2) { /* For fuzzing */ + if(encoder->protected_->max_lpc_order < 8) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8; + else if(encoder->protected_->max_lpc_order < 10) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10; + else if(encoder->protected_->max_lpc_order < 14) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14; + + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; + } +# endif +# ifdef FLAC__SSE4_1_SUPPORTED + if(encoder->private_->cpuinfo.x86.sse41) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; + } +# endif +# ifdef FLAC__AVX2_SUPPORTED + if(encoder->private_->cpuinfo.x86.avx2) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; + } +# endif +# ifdef FLAC__FMA_SUPPORTED + if(encoder->private_->cpuinfo.x86.fma) { + if(encoder->protected_->max_lpc_order < 8) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_fma_lag_8; + else if(encoder->protected_->max_lpc_order < 12) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_fma_lag_12; + else if(encoder->protected_->max_lpc_order < 16) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_fma_lag_16; + } +# endif + + +# ifdef FLAC__SSE2_SUPPORTED + if(encoder->private_->cpuinfo.x86.sse2) { /* For fuzzing */ + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; + } +# endif +# ifdef FLAC__SSSE3_SUPPORTED + if (encoder->private_->cpuinfo.x86.ssse3) { + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; + } +# endif +# ifdef FLAC__SSE4_2_SUPPORTED + if (encoder->private_->cpuinfo.x86.sse42) { + encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42; + } +# endif +# ifdef FLAC__AVX2_SUPPORTED + if (encoder->private_->cpuinfo.x86.avx2) { + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_avx2; + encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2; + } +# endif +# endif /* FLAC__HAS_X86INTRIN */ +# endif /* FLAC__CPU_... */ + } +# endif /* !FLAC__NO_ASM */ + +#endif /* !FLAC__INTEGER_ONLY_LIBRARY */ +#if !defined FLAC__NO_ASM && FLAC__HAS_X86INTRIN + if(encoder->private_->cpuinfo.use_asm) { +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) +# ifdef FLAC__SSE2_SUPPORTED + if (encoder->private_->cpuinfo.x86.sse2) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2; +# endif +# ifdef FLAC__SSSE3_SUPPORTED + if (encoder->private_->cpuinfo.x86.ssse3) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3; +# endif +# ifdef FLAC__AVX2_SUPPORTED + if (encoder->private_->cpuinfo.x86.avx2) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2; +# endif +# endif /* FLAC__CPU_... */ + } +#endif /* !FLAC__NO_ASM && FLAC__HAS_X86INTRIN */ + + /* set state to OK; from here on, errors are fatal and we'll override the state then */ + encoder->protected_->state = FLAC__STREAM_ENCODER_OK; + +#if FLAC__HAS_OGG + encoder->private_->is_ogg = is_ogg; + if(is_ogg && !FLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } +#endif + + encoder->private_->read_callback = read_callback; + encoder->private_->write_callback = write_callback; + encoder->private_->seek_callback = seek_callback; + encoder->private_->tell_callback = tell_callback; + encoder->private_->metadata_callback = metadata_callback; + encoder->private_->client_data = client_data; + + if(!resize_buffers_(encoder, encoder->protected_->blocksize)) { + /* the above function sets the state for us in case of an error */ + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + if(!FLAC__bitwriter_init(encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + /* + * Set up the verify stuff if necessary + */ + if(encoder->protected_->verify) { + /* + * First, set up the fifo which will hold the + * original signal to compare against + */ + encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_; + for(i = 0; i < encoder->protected_->channels; i++) { + if(0 == (encoder->private_->verify.input_fifo.data[i] = safe_malloc_mul_2op_p(sizeof(FLAC__int32), /*times*/encoder->private_->verify.input_fifo.size))) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + } + encoder->private_->verify.input_fifo.tail = 0; + + /* + * Now set up a stream decoder for verification + */ + if(0 == encoder->private_->verify.decoder) { + encoder->private_->verify.decoder = FLAC__stream_decoder_new(); + if(0 == encoder->private_->verify.decoder) { + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + } + + if(FLAC__stream_decoder_init_stream(encoder->private_->verify.decoder, verify_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, verify_write_callback_, verify_metadata_callback_, verify_error_callback_, /*client_data=*/encoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + } + encoder->private_->verify.error_stats.absolute_sample = 0; + encoder->private_->verify.error_stats.frame_number = 0; + encoder->private_->verify.error_stats.channel = 0; + encoder->private_->verify.error_stats.sample = 0; + encoder->private_->verify.error_stats.expected = 0; + encoder->private_->verify.error_stats.got = 0; + + /* + * These must be done before we write any metadata, because that + * calls the write_callback, which uses these values. + */ + encoder->private_->first_seekpoint_to_check = 0; + encoder->private_->samples_written = 0; + encoder->protected_->streaminfo_offset = 0; + encoder->protected_->seektable_offset = 0; + encoder->protected_->audio_offset = 0; + + /* + * write the stream header + */ + if(encoder->protected_->verify) + encoder->private_->verify.state_hint = ENCODER_IN_MAGIC; + if(!FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { + /* the above function sets the state for us in case of an error */ + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + /* + * write the STREAMINFO metadata block + */ + if(encoder->protected_->verify) + encoder->private_->verify.state_hint = ENCODER_IN_METADATA; + encoder->private_->streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO; + encoder->private_->streaminfo.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */ + encoder->private_->streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + encoder->private_->streaminfo.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */ + encoder->private_->streaminfo.data.stream_info.max_blocksize = encoder->protected_->blocksize; + encoder->private_->streaminfo.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */ + encoder->private_->streaminfo.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */ + encoder->private_->streaminfo.data.stream_info.sample_rate = encoder->protected_->sample_rate; + encoder->private_->streaminfo.data.stream_info.channels = encoder->protected_->channels; + encoder->private_->streaminfo.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample; + encoder->private_->streaminfo.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */ + memset(encoder->private_->streaminfo.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */ + if(encoder->protected_->do_md5) + FLAC__MD5Init(&encoder->private_->md5context); + if(!FLAC__add_metadata_block(&encoder->private_->streaminfo, encoder->private_->frame, true)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { + /* the above function sets the state for us in case of an error */ + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + /* + * Now that the STREAMINFO block is written, we can init this to an + * absurdly-high value... + */ + encoder->private_->streaminfo.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1; + /* ... and clear this to 0 */ + encoder->private_->streaminfo.data.stream_info.total_samples = 0; + + /* + * Check to see if the supplied metadata contains a VORBIS_COMMENT; + * if not, we will write an empty one (FLAC__add_metadata_block() + * automatically supplies the vendor string). + * + * WATCHOUT: the Ogg FLAC mapping requires us to write this block after + * the STREAMINFO. (In the case that metadata_has_vorbis_comment is + * true it will have already insured that the metadata list is properly + * ordered.) + */ + if(!metadata_has_vorbis_comment) { + FLAC__StreamMetadata vorbis_comment; + vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT; + vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0); + vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */ + vorbis_comment.data.vorbis_comment.vendor_string.length = 0; + vorbis_comment.data.vorbis_comment.vendor_string.entry = 0; + vorbis_comment.data.vorbis_comment.num_comments = 0; + vorbis_comment.data.vorbis_comment.comments = 0; + if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame, true)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { + /* the above function sets the state for us in case of an error */ + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + } + + /* + * write the user's metadata blocks + */ + for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) { + encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1); + if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame, true)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { + /* the above function sets the state for us in case of an error */ + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + } + + /* now that all the metadata is written, we save the stream offset */ + if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */ + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + if(encoder->protected_->verify) + encoder->private_->verify.state_hint = ENCODER_IN_AUDIO; + + return FLAC__STREAM_ENCODER_INIT_STATUS_OK; +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream( + FLAC__StreamEncoder *encoder, + FLAC__StreamEncoderWriteCallback write_callback, + FLAC__StreamEncoderSeekCallback seek_callback, + FLAC__StreamEncoderTellCallback tell_callback, + FLAC__StreamEncoderMetadataCallback metadata_callback, + void *client_data +) +{ + return init_stream_internal_( + encoder, + /*read_callback=*/0, + write_callback, + seek_callback, + tell_callback, + metadata_callback, + client_data, + /*is_ogg=*/false + ); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream( + FLAC__StreamEncoder *encoder, + FLAC__StreamEncoderReadCallback read_callback, + FLAC__StreamEncoderWriteCallback write_callback, + FLAC__StreamEncoderSeekCallback seek_callback, + FLAC__StreamEncoderTellCallback tell_callback, + FLAC__StreamEncoderMetadataCallback metadata_callback, + void *client_data +) +{ + return init_stream_internal_( + encoder, + read_callback, + write_callback, + seek_callback, + tell_callback, + metadata_callback, + client_data, + /*is_ogg=*/true + ); +} + +static FLAC__StreamEncoderInitStatus init_FILE_internal_( + FLAC__StreamEncoder *encoder, + FILE *file, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FLAC__StreamEncoderInitStatus init_status; + + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != file); + + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; + + /* double protection */ + if(file == 0) { + encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + /* + * To make sure that our file does not go unclosed after an error, we + * must assign the FILE pointer before any further error can occur in + * this routine. + */ + if(file == stdout) + file = get_binary_stdout_(); /* just to be safe */ + +#ifdef _WIN32 + /* + * Windows can suffer quite badly from disk fragmentation. This can be + * reduced significantly by setting the output buffer size to be 10MB. + */ + if(GetFileType((HANDLE)_get_osfhandle(_fileno(file))) == FILE_TYPE_DISK) + setvbuf(file, NULL, _IOFBF, 10*1024*1024); +#endif + encoder->private_->file = file; + + encoder->private_->progress_callback = progress_callback; + encoder->private_->bytes_written = 0; + encoder->private_->samples_written = 0; + encoder->private_->frames_written = 0; + + init_status = init_stream_internal_( + encoder, + encoder->private_->file == stdout? 0 : is_ogg? file_read_callback_ : 0, + file_write_callback_, + encoder->private_->file == stdout? 0 : file_seek_callback_, + encoder->private_->file == stdout? 0 : file_tell_callback_, + /*metadata_callback=*/0, + client_data, + is_ogg + ); + if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + /* the above function sets the state for us in case of an error */ + return init_status; + } + + { + uint32_t blocksize = FLAC__stream_encoder_get_blocksize(encoder); + + FLAC__ASSERT(blocksize != 0); + encoder->private_->total_frames_estimate = (uint32_t)((FLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize); + } + + return init_status; +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE( + FLAC__StreamEncoder *encoder, + FILE *file, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE( + FLAC__StreamEncoder *encoder, + FILE *file, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/true); +} + +static FLAC__StreamEncoderInitStatus init_file_internal_( + FLAC__StreamEncoder *encoder, + const char *filename, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FILE *file; + + FLAC__ASSERT(0 != encoder); + + /* + * To make sure that our file does not go unclosed after an error, we + * have to do the same entrance checks here that are later performed + * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned. + */ + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; + + file = filename? flac_fopen(filename, "w+b") : stdout; + + if(file == 0) { + encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + return init_FILE_internal_(encoder, file, progress_callback, client_data, is_ogg); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file( + FLAC__StreamEncoder *encoder, + const char *filename, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file( + FLAC__StreamEncoder *encoder, + const char *filename, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/true); +} + +FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder) +{ + FLAC__bool error = false; + + if (encoder == NULL) + return false; + + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + + if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED){ + if(encoder->protected_->metadata){ // True in case FLAC__stream_encoder_set_metadata was used but init failed + free(encoder->protected_->metadata); + encoder->protected_->metadata = 0; + encoder->protected_->num_metadata_blocks = 0; + } + if(0 != encoder->private_->file) { + if(encoder->private_->file != stdout) + fclose(encoder->private_->file); + encoder->private_->file = 0; + } + return true; + } + + if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) { + if(encoder->private_->current_sample_number != 0) { + encoder->protected_->blocksize = encoder->private_->current_sample_number; + if(!resize_buffers_(encoder, encoder->protected_->blocksize)) { + /* the above function sets the state for us in case of an error */ + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!process_frame_(encoder, /*is_last_block=*/true)) + error = true; + } + } + + if(encoder->protected_->do_md5) + FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context); + + if(!encoder->private_->is_being_deleted) { + if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK) { + if(encoder->private_->seek_callback) { +#if FLAC__HAS_OGG + if(encoder->private_->is_ogg) + update_ogg_metadata_(encoder); + else +#endif + update_metadata_(encoder); + + /* check if an error occurred while updating metadata */ + if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK) + error = true; + } + if(encoder->private_->metadata_callback) + encoder->private_->metadata_callback(encoder, &encoder->private_->streaminfo, encoder->private_->client_data); + } + + if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder && !FLAC__stream_decoder_finish(encoder->private_->verify.decoder)) { + if(!error) + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA; + error = true; + } + } + + if(0 != encoder->private_->file) { + if(encoder->private_->file != stdout) + fclose(encoder->private_->file); + encoder->private_->file = 0; + } + +#if FLAC__HAS_OGG + if(encoder->private_->is_ogg) + FLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect); +#endif + + free_(encoder); + set_defaults_(encoder); + + if(!error) + encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; + + return !error; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#if FLAC__HAS_OGG + /* can't check encoder->private_->is_ogg since that's not set until init time */ + FLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value); + return true; +#else + (void)value; + return false; +#endif +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING + encoder->protected_->verify = value; +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->streamable_subset = value; + return true; +} + +/* + * The following routine was intended as debug routine and is not in the + * public headers, but SHOULD NOT CHANGE! It is known is is used in + * some non-audio projects needing every last bit of performance. + * See https://github.com/xiph/flac/issues/547 for details. These projects + * provide their own prototype, so changing the signature of this function + * would break building. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->do_md5 = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->channels = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->bits_per_sample = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->sample_rate = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__bool ok = true; + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + if(value >= sizeof(compression_levels_)/sizeof(compression_levels_[0])) + value = sizeof(compression_levels_)/sizeof(compression_levels_[0]) - 1; + ok &= FLAC__stream_encoder_set_do_mid_side_stereo (encoder, compression_levels_[value].do_mid_side_stereo); + ok &= FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, compression_levels_[value].loose_mid_side_stereo); +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#if 1 + ok &= FLAC__stream_encoder_set_apodization (encoder, compression_levels_[value].apodization); +#else + /* equivalent to -A tukey(0.5) */ + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; + encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; +#endif +#endif + ok &= FLAC__stream_encoder_set_max_lpc_order (encoder, compression_levels_[value].max_lpc_order); + ok &= FLAC__stream_encoder_set_qlp_coeff_precision (encoder, compression_levels_[value].qlp_coeff_precision); + ok &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search (encoder, compression_levels_[value].do_qlp_coeff_prec_search); + ok &= FLAC__stream_encoder_set_do_escape_coding (encoder, compression_levels_[value].do_escape_coding); + ok &= FLAC__stream_encoder_set_do_exhaustive_model_search (encoder, compression_levels_[value].do_exhaustive_model_search); + ok &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, compression_levels_[value].min_residual_partition_order); + ok &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, compression_levels_[value].max_residual_partition_order); + ok &= FLAC__stream_encoder_set_rice_parameter_search_dist (encoder, compression_levels_[value].rice_parameter_search_dist); + return ok; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->blocksize = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->do_mid_side_stereo = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->loose_mid_side_stereo = value; + return true; +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != specification); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#ifdef FLAC__INTEGER_ONLY_LIBRARY + (void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */ +#else + encoder->protected_->num_apodizations = 0; + while(1) { + const char *s = strchr(specification, ';'); + const size_t n = s? (size_t)(s - specification) : strlen(specification); + if (n==8 && 0 == strncmp("bartlett" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT; + else if(n==13 && 0 == strncmp("bartlett_hann", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN; + else if(n==8 && 0 == strncmp("blackman" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN; + else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE; + else if(n==6 && 0 == strncmp("connes" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES; + else if(n==7 && 0 == strncmp("flattop" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP; + else if(n>7 && 0 == strncmp("gauss(" , specification, 6)) { + FLAC__real stddev = (FLAC__real)strtod(specification+6, 0); + if (stddev > 0.0 && stddev <= 0.5) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS; + } + } + else if(n==7 && 0 == strncmp("hamming" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING; + else if(n==4 && 0 == strncmp("hann" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN; + else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL; + else if(n==7 && 0 == strncmp("nuttall" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL; + else if(n==9 && 0 == strncmp("rectangle" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE; + else if(n==8 && 0 == strncmp("triangle" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE; + else if(n>7 && 0 == strncmp("tukey(" , specification, 6)) { + FLAC__real p = (FLAC__real)strtod(specification+6, 0); + if (p >= 0.0 && p <= 1.0) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; + } + } + else if(n>15 && 0 == strncmp("partial_tukey(", specification, 14)) { + FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+14, 0); + const char *si_1 = strchr(specification, '/'); + FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.1f; + FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; + const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); + FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; + + if (tukey_parts <= 1) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; + }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ + FLAC__int32 m; + for(m = 0; m < tukey_parts; m++){ + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PARTIAL_TUKEY; + } + } + } + else if(n>16 && 0 == strncmp("punchout_tukey(", specification, 15)) { + FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+15, 0); + const char *si_1 = strchr(specification, '/'); + FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.2f; + FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; + const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); + FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; + + if (tukey_parts <= 1) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; + }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ + FLAC__int32 m; + for(m = 0; m < tukey_parts; m++){ + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PUNCHOUT_TUKEY; + } + } + } + else if(n>17 && 0 == strncmp("subdivide_tukey(", specification, 16)){ + FLAC__int32 parts = (FLAC__int32)strtod(specification+16, 0); + if(parts > 1){ + const char *si_1 = strchr(specification, '/'); + FLAC__real p = si_1?(FLAC__real)strtod(si_1+1, 0):5e-1; + if(p > 1) + p = 1; + else if(p < 0) + p = 0; + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.subdivide_tukey.parts = parts; + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.subdivide_tukey.p = p/parts; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_SUBDIVIDE_TUKEY; + } + } + else if(n==5 && 0 == strncmp("welch" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH; + if (encoder->protected_->num_apodizations == 32) + break; + if (s) + specification = s+1; + else + break; + } + if(encoder->protected_->num_apodizations == 0) { + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; + encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; + } +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->max_lpc_order = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->qlp_coeff_precision = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->do_qlp_coeff_prec_search = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* was deprecated since FLAC 1.0.4 (24-Sep-2002), but is needed for + * full spec coverage, so this should be reenabled at some point. + * For now only enable while fuzzing */ + encoder->protected_->do_escape_coding = value; +#else + (void)value; +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->do_exhaustive_model_search = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->min_residual_partition_order = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->max_residual_partition_order = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#if 0 + /*@@@ deprecated: */ + encoder->protected_->rice_parameter_search_dist = value; +#else + (void)value; +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + value = flac_min(value, (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN) - 1); + encoder->protected_->total_samples_estimate = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + if(0 == metadata) + num_blocks = 0; + if(0 == num_blocks) + metadata = 0; + /* realloc() does not do exactly what we want so... */ + if(encoder->protected_->metadata) { + free(encoder->protected_->metadata); + encoder->protected_->metadata = 0; + encoder->protected_->num_metadata_blocks = 0; + } + if(num_blocks) { + FLAC__StreamMetadata **m; + if(0 == (m = safe_malloc_mul_2op_p(sizeof(m[0]), /*times*/num_blocks))) + return false; + memcpy(m, metadata, sizeof(m[0]) * num_blocks); + encoder->protected_->metadata = m; + encoder->protected_->num_metadata_blocks = num_blocks; + } +#if FLAC__HAS_OGG + if(!FLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks)) + return false; +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_limit_min_bitrate(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->limit_min_bitrate = value; + return true; +} + +/* + * These four functions are not static, but not publicly exposed in + * include/FLAC/ either. They are used by the test suite and in fuzzing + */ +FLAC_API FLAC__bool FLAC__stream_encoder_disable_instruction_set(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->disable_mmx = value & 1; + encoder->private_->disable_sse2 = value & 2; + encoder->private_->disable_ssse3 = value & 4; + encoder->private_->disable_sse41 = value & 8; + encoder->private_->disable_avx2 = value & 16; + encoder->private_->disable_fma = value & 32; + encoder->private_->disable_sse42 = value & 64; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->disable_constant_subframes = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->disable_fixed_subframes = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->disable_verbatim_subframes = value; + return true; +} + +FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->state; +} + +FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->verify) + return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder); + else + return FLAC__STREAM_DECODER_UNINITIALIZED; +} + +FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) + return FLAC__StreamEncoderStateString[encoder->protected_->state]; + else + return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder); +} + +FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(0 != absolute_sample) + *absolute_sample = encoder->private_->verify.error_stats.absolute_sample; + if(0 != frame_number) + *frame_number = encoder->private_->verify.error_stats.frame_number; + if(0 != channel) + *channel = encoder->private_->verify.error_stats.channel; + if(0 != sample) + *sample = encoder->private_->verify.error_stats.sample; + if(0 != expected) + *expected = encoder->private_->verify.error_stats.expected; + if(0 != got) + *got = encoder->private_->verify.error_stats.got; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->verify; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->streamable_subset; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->do_md5; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->channels; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->bits_per_sample; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->sample_rate; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->blocksize; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->do_mid_side_stereo; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->loose_mid_side_stereo; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->max_lpc_order; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->qlp_coeff_precision; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->do_qlp_coeff_prec_search; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->do_escape_coding; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->do_exhaustive_model_search; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->min_residual_partition_order; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->max_residual_partition_order; +} + +FLAC_API uint32_t FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->rice_parameter_search_dist; +} + +FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->total_samples_estimate; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_limit_min_bitrate(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->limit_min_bitrate; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples) +{ + uint32_t i, j = 0, k = 0, channel; + const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; + const FLAC__int32 sample_max = INT32_MAX >> (32 - encoder->protected_->bits_per_sample); + const FLAC__int32 sample_min = INT32_MIN >> (32 - encoder->protected_->bits_per_sample); + + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + + if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK) + return false; + + do { + const uint32_t n = flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j); + + if(encoder->protected_->verify) + append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n); + + for(channel = 0; channel < channels; channel++) { + if (buffer[channel] == NULL) { + return false; + } + for(i = encoder->private_->current_sample_number, k = j; i <= blocksize && k < samples; i++, k++) { + if(buffer[channel][k] < sample_min || buffer[channel][k] > sample_max){ + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + } + memcpy(&encoder->private_->integer_signal[channel][encoder->private_->current_sample_number], &buffer[channel][j], sizeof(buffer[channel][0]) * n); + } + j += n; + encoder->private_->current_sample_number += n; + + /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ + if(encoder->private_->current_sample_number > blocksize) { + FLAC__ASSERT(encoder->private_->current_sample_number == blocksize+OVERREAD_); + FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ + if(!process_frame_(encoder, /*is_last_block=*/false)) + return false; + /* move unprocessed overread samples to beginnings of arrays */ + for(channel = 0; channel < channels; channel++) + encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize]; + encoder->private_->current_sample_number = 1; + } + } while(j < samples); + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples) +{ + uint32_t i, j, k, channel; + const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; + const FLAC__int32 sample_max = INT32_MAX >> (32 - encoder->protected_->bits_per_sample); + const FLAC__int32 sample_min = INT32_MIN >> (32 - encoder->protected_->bits_per_sample); + + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + + if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK) + return false; + + j = k = 0; + do { + if(encoder->protected_->verify) + append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j)); + + /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */ + for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) { + for(channel = 0; channel < channels; channel++){ + if(buffer[k] < sample_min || buffer[k] > sample_max){ + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + encoder->private_->integer_signal[channel][i] = buffer[k++]; + } + } + encoder->private_->current_sample_number = i; + /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ + if(i > blocksize) { + if(!process_frame_(encoder, /*is_last_block=*/false)) + return false; + /* move unprocessed overread samples to beginnings of arrays */ + FLAC__ASSERT(i == blocksize+OVERREAD_); + FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ + for(channel = 0; channel < channels; channel++) + encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize]; + encoder->private_->current_sample_number = 1; + } + } while(j < samples); + + return true; +} + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +void set_defaults_(FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + +#ifdef FLAC__MANDATORY_VERIFY_WHILE_ENCODING + encoder->protected_->verify = true; +#else + encoder->protected_->verify = false; +#endif + encoder->protected_->streamable_subset = true; + encoder->protected_->do_md5 = true; + encoder->protected_->do_mid_side_stereo = false; + encoder->protected_->loose_mid_side_stereo = false; + encoder->protected_->channels = 2; + encoder->protected_->bits_per_sample = 16; + encoder->protected_->sample_rate = 44100; + encoder->protected_->blocksize = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; + encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; +#endif + encoder->protected_->max_lpc_order = 0; + encoder->protected_->qlp_coeff_precision = 0; + encoder->protected_->do_qlp_coeff_prec_search = false; + encoder->protected_->do_exhaustive_model_search = false; + encoder->protected_->do_escape_coding = false; + encoder->protected_->min_residual_partition_order = 0; + encoder->protected_->max_residual_partition_order = 0; + encoder->protected_->rice_parameter_search_dist = 0; + encoder->protected_->total_samples_estimate = 0; + encoder->protected_->limit_min_bitrate = false; + encoder->protected_->metadata = 0; + encoder->protected_->num_metadata_blocks = 0; + + encoder->private_->seek_table = 0; + encoder->private_->disable_mmx = false; + encoder->private_->disable_sse2 = false; + encoder->private_->disable_ssse3 = false; + encoder->private_->disable_sse41 = false; + encoder->private_->disable_sse42 = false; + encoder->private_->disable_avx2 = false; + encoder->private_->disable_constant_subframes = false; + encoder->private_->disable_fixed_subframes = false; + encoder->private_->disable_verbatim_subframes = false; + encoder->private_->is_ogg = false; + encoder->private_->read_callback = 0; + encoder->private_->write_callback = 0; + encoder->private_->seek_callback = 0; + encoder->private_->tell_callback = 0; + encoder->private_->metadata_callback = 0; + encoder->private_->progress_callback = 0; + encoder->private_->client_data = 0; + +#if FLAC__HAS_OGG + FLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect); +#endif + + FLAC__stream_encoder_set_compression_level(encoder, 5); +} + +void free_(FLAC__StreamEncoder *encoder) +{ + uint32_t i, channel; + + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->metadata) { + free(encoder->protected_->metadata); + encoder->protected_->metadata = 0; + encoder->protected_->num_metadata_blocks = 0; + } + for(i = 0; i < encoder->protected_->channels; i++) { + if(0 != encoder->private_->integer_signal_unaligned[i]) { + free(encoder->private_->integer_signal_unaligned[i]); + encoder->private_->integer_signal_unaligned[i] = 0; + } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(0 != encoder->private_->real_signal_unaligned[i]) { + free(encoder->private_->real_signal_unaligned[i]); + encoder->private_->real_signal_unaligned[i] = 0; + } +#endif + } + for(i = 0; i < 2; i++) { + if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) { + free(encoder->private_->integer_signal_mid_side_unaligned[i]); + encoder->private_->integer_signal_mid_side_unaligned[i] = 0; + } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(0 != encoder->private_->real_signal_mid_side_unaligned[i]) { + free(encoder->private_->real_signal_mid_side_unaligned[i]); + encoder->private_->real_signal_mid_side_unaligned[i] = 0; + } +#endif + } + if(0 != encoder->private_->integer_signal_33bit_side_unaligned){ + free(encoder->private_->integer_signal_33bit_side_unaligned); + encoder->private_->integer_signal_33bit_side_unaligned = 0; + } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + for(i = 0; i < encoder->protected_->num_apodizations; i++) { + if(0 != encoder->private_->window_unaligned[i]) { + free(encoder->private_->window_unaligned[i]); + encoder->private_->window_unaligned[i] = 0; + } + } + if(0 != encoder->private_->windowed_signal_unaligned) { + free(encoder->private_->windowed_signal_unaligned); + encoder->private_->windowed_signal_unaligned = 0; + } +#endif + for(channel = 0; channel < encoder->protected_->channels; channel++) { + for(i = 0; i < 2; i++) { + if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) { + free(encoder->private_->residual_workspace_unaligned[channel][i]); + encoder->private_->residual_workspace_unaligned[channel][i] = 0; + } + } + } + for(channel = 0; channel < 2; channel++) { + for(i = 0; i < 2; i++) { + if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) { + free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]); + encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0; + } + } + } + if(0 != encoder->private_->abs_residual_partition_sums_unaligned) { + free(encoder->private_->abs_residual_partition_sums_unaligned); + encoder->private_->abs_residual_partition_sums_unaligned = 0; + } + if(0 != encoder->private_->raw_bits_per_partition_unaligned) { + free(encoder->private_->raw_bits_per_partition_unaligned); + encoder->private_->raw_bits_per_partition_unaligned = 0; + } + if(encoder->protected_->verify) { + for(i = 0; i < encoder->protected_->channels; i++) { + if(0 != encoder->private_->verify.input_fifo.data[i]) { + free(encoder->private_->verify.input_fifo.data[i]); + encoder->private_->verify.input_fifo.data[i] = 0; + } + } + } + FLAC__bitwriter_free(encoder->private_->frame); +} + +FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, uint32_t new_blocksize) +{ + FLAC__bool ok; + uint32_t i, channel; + + FLAC__ASSERT(new_blocksize > 0); + FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); + + ok = true; + + /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */ + if(new_blocksize > encoder->private_->input_capacity) { + + /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() and ..._intrin_sse2() + * require that the input arrays (in our case the integer signals) + * have a buffer of up to 3 zeroes in front (at negative indices) for + * alignment purposes; we use 4 in front to keep the data well-aligned. + */ + + for(i = 0; ok && i < encoder->protected_->channels; i++) { + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]); + if(ok) { + memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4); + encoder->private_->integer_signal[i] += 4; + } + } + for(i = 0; ok && i < 2; i++) { + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]); + if(ok) { + memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4); + encoder->private_->integer_signal_mid_side[i] += 4; + } + } + ok = ok && FLAC__memory_alloc_aligned_int64_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_33bit_side_unaligned, &encoder->private_->integer_signal_33bit_side); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(ok && encoder->protected_->max_lpc_order > 0) { + for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) + ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]); + ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal); + } +#endif + for(channel = 0; ok && channel < encoder->protected_->channels; channel++) { + for(i = 0; ok && i < 2; i++) { + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]); + } + } + + + for(channel = 0; ok && channel < encoder->protected_->channels; channel++) { + for(i = 0; ok && i < 2; i++) { + ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_workspace[channel][i], encoder->protected_->max_residual_partition_order); + ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_workspace[channel][i], encoder->protected_->max_residual_partition_order); + } + } + + for(channel = 0; ok && channel < 2; channel++) { + for(i = 0; ok && i < 2; i++) { + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]); + } + } + + for(channel = 0; ok && channel < 2; channel++) { + for(i = 0; ok && i < 2; i++) { + ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_workspace_mid_side[channel][i], encoder->protected_->max_residual_partition_order); + } + } + + for(i = 0; ok && i < 2; i++) { + ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_extra[i], encoder->protected_->max_residual_partition_order); + } + + + /* the *2 is an approximation to the series 1 + 1/2 + 1/4 + ... that sums tree occupies in a flat array */ + /*@@@ new_blocksize*2 is too pessimistic, but to fix, we need smarter logic because a smaller new_blocksize can actually increase the # of partitions; would require moving this out into a separate function, then checking its capacity against the need of the current blocksize&min/max_partition_order (and maybe predictor order) */ + ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_blocksize * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums); + if(encoder->protected_->do_escape_coding) + ok = ok && FLAC__memory_alloc_aligned_uint32_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition); +} + if(ok) + encoder->private_->input_capacity = new_blocksize; + else { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return ok; + } + + + /* now adjust the windows if the blocksize has changed */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(encoder->protected_->max_lpc_order > 0 && new_blocksize > 1) { + for(i = 0; i < encoder->protected_->num_apodizations; i++) { + switch(encoder->protected_->apodizations[i].type) { + case FLAC__APODIZATION_BARTLETT: + FLAC__window_bartlett(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_BARTLETT_HANN: + FLAC__window_bartlett_hann(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_BLACKMAN: + FLAC__window_blackman(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE: + FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_CONNES: + FLAC__window_connes(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_FLATTOP: + FLAC__window_flattop(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_GAUSS: + FLAC__window_gauss(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.gauss.stddev); + break; + case FLAC__APODIZATION_HAMMING: + FLAC__window_hamming(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_HANN: + FLAC__window_hann(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_KAISER_BESSEL: + FLAC__window_kaiser_bessel(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_NUTTALL: + FLAC__window_nuttall(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_RECTANGLE: + FLAC__window_rectangle(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_TRIANGLE: + FLAC__window_triangle(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_TUKEY: + FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p); + break; + case FLAC__APODIZATION_PARTIAL_TUKEY: + FLAC__window_partial_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); + break; + case FLAC__APODIZATION_PUNCHOUT_TUKEY: + FLAC__window_punchout_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); + break; + case FLAC__APODIZATION_SUBDIVIDE_TUKEY: + FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p); + break; + case FLAC__APODIZATION_WELCH: + FLAC__window_welch(encoder->private_->window[i], new_blocksize); + break; + default: + FLAC__ASSERT(0); + /* double protection */ + FLAC__window_hann(encoder->private_->window[i], new_blocksize); + break; + } + } + } + if (new_blocksize <= FLAC__MAX_LPC_ORDER) { + /* intrinsics autocorrelation routines do not all handle cases in which lag might be + * larger than data_len. Lag is one larger than the LPC order */ + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; + } +#endif + + return true; +} + +FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t samples, FLAC__bool is_last_block) +{ + const FLAC__byte *buffer; + size_t bytes; + + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame)); + + if(!FLAC__bitwriter_get_buffer(encoder->private_->frame, &buffer, &bytes)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + if(encoder->protected_->verify) { + encoder->private_->verify.output.data = buffer; + encoder->private_->verify.output.bytes = bytes; + if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) { + encoder->private_->verify.needs_magic_hack = true; + } + else { + if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder) + || (!is_last_block + && (FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_END_OF_STREAM)) + || encoder->protected_->state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR /* Happens when error callback was used */) { + FLAC__bitwriter_release_buffer(encoder->private_->frame); + FLAC__bitwriter_clear(encoder->private_->frame); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; + return false; + } + } + } + + if(write_frame_(encoder, buffer, bytes, samples, is_last_block) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + FLAC__bitwriter_release_buffer(encoder->private_->frame); + FLAC__bitwriter_clear(encoder->private_->frame); + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + + FLAC__bitwriter_release_buffer(encoder->private_->frame); + FLAC__bitwriter_clear(encoder->private_->frame); + + if(samples > 0) { + encoder->private_->streaminfo.data.stream_info.min_framesize = flac_min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize); + encoder->private_->streaminfo.data.stream_info.max_framesize = flac_max(bytes, encoder->private_->streaminfo.data.stream_info.max_framesize); + } + + return true; +} + +FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, FLAC__bool is_last_block) +{ + FLAC__StreamEncoderWriteStatus status; + FLAC__uint64 output_position = 0; + +#if FLAC__HAS_OGG == 0 + (void)is_last_block; +#endif + + /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */ + if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + + /* + * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets. + */ + if(samples == 0) { + FLAC__MetadataType type = (buffer[0] & 0x7f); + if(type == FLAC__METADATA_TYPE_STREAMINFO) + encoder->protected_->streaminfo_offset = output_position; + else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0) + encoder->protected_->seektable_offset = output_position; + } + + /* + * Mark the current seek point if hit (if audio_offset == 0 that + * means we're still writing metadata and haven't hit the first + * frame yet) + */ + if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) { + const uint32_t blocksize = FLAC__stream_encoder_get_blocksize(encoder); + const FLAC__uint64 frame_first_sample = encoder->private_->samples_written; + const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1; + FLAC__uint64 test_sample; + uint32_t i; + for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) { + test_sample = encoder->private_->seek_table->points[i].sample_number; + if(test_sample > frame_last_sample) { + break; + } + else if(test_sample >= frame_first_sample) { + encoder->private_->seek_table->points[i].sample_number = frame_first_sample; + encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset; + encoder->private_->seek_table->points[i].frame_samples = blocksize; + encoder->private_->first_seekpoint_to_check++; + /* DO NOT: "break;" and here's why: + * The seektable template may contain more than one target + * sample for any given frame; we will keep looping, generating + * duplicate seekpoints for them, and we'll clean it up later, + * just before writing the seektable back to the metadata. + */ + } + else { + encoder->private_->first_seekpoint_to_check++; + } + } + } + +#if FLAC__HAS_OGG + if(encoder->private_->is_ogg) { + status = FLAC__ogg_encoder_aspect_write_callback_wrapper( + &encoder->protected_->ogg_encoder_aspect, + buffer, + bytes, + samples, + encoder->private_->current_frame_number, + is_last_block, + (FLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback, + encoder, + encoder->private_->client_data + ); + } + else +#endif + status = encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data); + + if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->private_->bytes_written += bytes; + encoder->private_->samples_written += samples; + /* we keep a high watermark on the number of frames written because + * when the encoder goes back to write metadata, 'current_frame' + * will drop back to 0. + */ + encoder->private_->frames_written = flac_max(encoder->private_->frames_written, encoder->private_->current_frame_number+1); + } + else + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + + return status; +} + +/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */ +void update_metadata_(const FLAC__StreamEncoder *encoder) +{ + FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)]; + const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo; + FLAC__uint64 samples = metadata->data.stream_info.total_samples; + const uint32_t min_framesize = metadata->data.stream_info.min_framesize; + const uint32_t max_framesize = metadata->data.stream_info.max_framesize; + const uint32_t bps = metadata->data.stream_info.bits_per_sample; + FLAC__StreamEncoderSeekStatus seek_status; + + FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); + + /* All this is based on intimate knowledge of the stream header + * layout, but a change to the header format that would break this + * would also break all streams encoded in the previous format. + */ + + /* + * Write MD5 signature + */ + { + const uint32_t md5_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN + ) / 8; + + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + + /* + * Write total samples + */ + { + const uint32_t total_samples_byte_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - 4 + ) / 8; + if(samples > (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) + samples = 0; + + b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F); + b[1] = (FLAC__byte)((samples >> 24) & 0xFF); + b[2] = (FLAC__byte)((samples >> 16) & 0xFF); + b[3] = (FLAC__byte)((samples >> 8) & 0xFF); + b[4] = (FLAC__byte)(samples & 0xFF); + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + + /* + * Write min/max framesize + */ + { + const uint32_t min_framesize_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + ) / 8; + + b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); + b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); + b[2] = (FLAC__byte)(min_framesize & 0xFF); + b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); + b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); + b[5] = (FLAC__byte)(max_framesize & 0xFF); + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + + /* + * Write seektable + */ + if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) { + uint32_t i; + + FLAC__format_seektable_sort(encoder->private_->seek_table); + + FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table)); + + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + + for(i = 0; i < encoder->private_->seek_table->num_points; i++) { + FLAC__uint64 xx; + uint32_t x; + xx = encoder->private_->seek_table->points[i].sample_number; + b[7] = (FLAC__byte)xx; xx >>= 8; + b[6] = (FLAC__byte)xx; xx >>= 8; + b[5] = (FLAC__byte)xx; xx >>= 8; + b[4] = (FLAC__byte)xx; xx >>= 8; + b[3] = (FLAC__byte)xx; xx >>= 8; + b[2] = (FLAC__byte)xx; xx >>= 8; + b[1] = (FLAC__byte)xx; xx >>= 8; + b[0] = (FLAC__byte)xx; xx >>= 8; + xx = encoder->private_->seek_table->points[i].stream_offset; + b[15] = (FLAC__byte)xx; xx >>= 8; + b[14] = (FLAC__byte)xx; xx >>= 8; + b[13] = (FLAC__byte)xx; xx >>= 8; + b[12] = (FLAC__byte)xx; xx >>= 8; + b[11] = (FLAC__byte)xx; xx >>= 8; + b[10] = (FLAC__byte)xx; xx >>= 8; + b[9] = (FLAC__byte)xx; xx >>= 8; + b[8] = (FLAC__byte)xx; xx >>= 8; + x = encoder->private_->seek_table->points[i].frame_samples; + b[17] = (FLAC__byte)x; x >>= 8; + b[16] = (FLAC__byte)x; x >>= 8; + if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + } +} + +#if FLAC__HAS_OGG +/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */ +void update_ogg_metadata_(FLAC__StreamEncoder *encoder) +{ + /* the # of bytes in the 1st packet that precede the STREAMINFO */ + static const uint32_t FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH = + FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + + FLAC__OGG_MAPPING_MAGIC_LENGTH + + FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + + FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + + FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH + + FLAC__STREAM_SYNC_LENGTH + ; + FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)]; + const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo; + const FLAC__uint64 samples = metadata->data.stream_info.total_samples; + const uint32_t min_framesize = metadata->data.stream_info.min_framesize; + const uint32_t max_framesize = metadata->data.stream_info.max_framesize; + ogg_page page; + + FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); + FLAC__ASSERT(0 != encoder->private_->seek_callback); + + /* Pre-check that client supports seeking, since we don't want the + * ogg_helper code to ever have to deal with this condition. + */ + if(encoder->private_->seek_callback(encoder, 0, encoder->private_->client_data) == FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED) + return; + + /* All this is based on intimate knowledge of the stream header + * layout, but a change to the header format that would break this + * would also break all streams encoded in the previous format. + */ + + /** + ** Write STREAMINFO stats + **/ + simple_ogg_page__init(&page); + if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) { + simple_ogg_page__clear(&page); + return; /* state already set */ + } + + /* + * Write MD5 signature + */ + { + const uint32_t md5_offset = + FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN + ) / 8; + + if(md5_offset + 16 > (uint32_t)page.body_len) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + simple_ogg_page__clear(&page); + return; + } + memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16); + } + + /* + * Write total samples + */ + { + const uint32_t total_samples_byte_offset = + FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - 4 + ) / 8; + + if(total_samples_byte_offset + 5 > (uint32_t)page.body_len) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + simple_ogg_page__clear(&page); + return; + } + b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0; + b[0] |= (FLAC__byte)((samples >> 32) & 0x0F); + b[1] = (FLAC__byte)((samples >> 24) & 0xFF); + b[2] = (FLAC__byte)((samples >> 16) & 0xFF); + b[3] = (FLAC__byte)((samples >> 8) & 0xFF); + b[4] = (FLAC__byte)(samples & 0xFF); + memcpy(page.body + total_samples_byte_offset, b, 5); + } + + /* + * Write min/max framesize + */ + { + const uint32_t min_framesize_offset = + FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + ) / 8; + + if(min_framesize_offset + 6 > (uint32_t)page.body_len) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + simple_ogg_page__clear(&page); + return; + } + b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); + b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); + b[2] = (FLAC__byte)(min_framesize & 0xFF); + b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); + b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); + b[5] = (FLAC__byte)(max_framesize & 0xFF); + memcpy(page.body + min_framesize_offset, b, 6); + } + if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) { + simple_ogg_page__clear(&page); + return; /* state already set */ + } + simple_ogg_page__clear(&page); +} +#endif + +FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_block) +{ + FLAC__uint16 crc; + FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); + + /* + * Accumulate raw signal to the MD5 signature + */ + if(encoder->protected_->do_md5 && !FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* + * Process the frame header and subframes into the frame bitbuffer + */ + if(!process_subframes_(encoder)) { + /* the above function sets the state for us in case of an error */ + return false; + } + + /* + * Zero-pad the frame to a byte_boundary + */ + if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* + * CRC-16 the whole thing + */ + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame)); + if( + !FLAC__bitwriter_get_write_crc16(encoder->private_->frame, &crc) || + !FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, crc, FLAC__FRAME_FOOTER_CRC_LEN) + ) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* + * Write it + */ + if(!write_bitbuffer_(encoder, encoder->protected_->blocksize, is_last_block)) { + /* the above function sets the state for us in case of an error */ + return false; + } + + /* + * Get ready for the next frame + */ + encoder->private_->current_sample_number = 0; + encoder->private_->current_frame_number++; + encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize; + + return true; +} + +FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder) +{ + FLAC__FrameHeader frame_header; + uint32_t channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order; + FLAC__bool do_independent, do_mid_side, backup_disable_constant_subframes = encoder->private_->disable_constant_subframes, all_subframes_constant = true; + + /* + * Calculate the min,max Rice partition orders + */ + + max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize); + max_partition_order = flac_min(max_partition_order, encoder->protected_->max_residual_partition_order); + min_partition_order = flac_min(min_partition_order, max_partition_order); + + /* + * Setup the frame + */ + frame_header.blocksize = encoder->protected_->blocksize; + frame_header.sample_rate = encoder->protected_->sample_rate; + frame_header.channels = encoder->protected_->channels; + frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */ + frame_header.bits_per_sample = encoder->protected_->bits_per_sample; + frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER; + frame_header.number.frame_number = encoder->private_->current_frame_number; + + /* + * Figure out what channel assignments to try + */ + if(encoder->protected_->do_mid_side_stereo) { + if(encoder->protected_->loose_mid_side_stereo) { + if(encoder->private_->loose_mid_side_stereo_frame_count == 0) { + do_independent = true; + do_mid_side = true; + } + else { + do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT); + do_mid_side = !do_independent; + } + } + else { + do_independent = true; + do_mid_side = true; + } + } + else { + do_independent = true; + do_mid_side = false; + } + + FLAC__ASSERT(do_independent || do_mid_side); + + /* + * Prepare mid-side signals if applicable + */ + if(do_mid_side) { + uint32_t i; + FLAC__ASSERT(encoder->protected_->channels == 2); + if(encoder->protected_->bits_per_sample < 32) + for(i = 0; i < encoder->protected_->blocksize; i++) { + encoder->private_->integer_signal_mid_side[1][i] = encoder->private_->integer_signal[0][i] - encoder->private_->integer_signal[1][i]; + encoder->private_->integer_signal_mid_side[0][i] = (encoder->private_->integer_signal[0][i] + encoder->private_->integer_signal[1][i]) >> 1; /* NOTE: not the same as 'mid = (signal[0][j] + signal[1][j]) / 2' ! */ + } + else + for(i = 0; i <= encoder->protected_->blocksize; i++) { + encoder->private_->integer_signal_33bit_side[i] = (FLAC__int64)encoder->private_->integer_signal[0][i] - (FLAC__int64)encoder->private_->integer_signal[1][i]; + encoder->private_->integer_signal_mid_side[0][i] = ((FLAC__int64)encoder->private_->integer_signal[0][i] + (FLAC__int64)encoder->private_->integer_signal[1][i]) >> 1; /* NOTE: not the same as 'mid = (signal[0][j] + signal[1][j]) / 2' ! */ + } + } + + + /* + * Check for wasted bits; set effective bps for each subframe + */ + if(do_independent) { + for(channel = 0; channel < encoder->protected_->channels; channel++) { + uint32_t w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize); + if (w > encoder->protected_->bits_per_sample) { + w = encoder->protected_->bits_per_sample; + } + encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w; + encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w; + } + } + if(do_mid_side) { + FLAC__ASSERT(encoder->protected_->channels == 2); + for(channel = 0; channel < 2; channel++) { + uint32_t w; + if(encoder->protected_->bits_per_sample < 32 || channel == 0) + w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize); + else + w = get_wasted_bits_wide_(encoder->private_->integer_signal_33bit_side, encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize); + + if (w > encoder->protected_->bits_per_sample) { + w = encoder->protected_->bits_per_sample; + } + encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w; + encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1); + } + } + + /* + * First do a normal encoding pass of each independent channel + */ + if(do_independent) { + for(channel = 0; channel < encoder->protected_->channels; channel++) { + if(encoder->protected_->limit_min_bitrate && all_subframes_constant && (channel + 1) == encoder->protected_->channels){ + /* This frame contains only constant subframes at this point. + * To prevent the frame from becoming too small, make sure + * the last subframe isn't constant */ + encoder->private_->disable_constant_subframes = true; + } + if(! + process_subframe_( + encoder, + min_partition_order, + max_partition_order, + &frame_header, + encoder->private_->subframe_bps[channel], + encoder->private_->integer_signal[channel], + encoder->private_->subframe_workspace_ptr[channel], + encoder->private_->partitioned_rice_contents_workspace_ptr[channel], + encoder->private_->residual_workspace[channel], + encoder->private_->best_subframe+channel, + encoder->private_->best_subframe_bits+channel + ) + ) + return false; + if(encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]].type != FLAC__SUBFRAME_TYPE_CONSTANT) + all_subframes_constant = false; + } + } + + /* + * Now do mid and side channels if requested + */ + if(do_mid_side) { + FLAC__ASSERT(encoder->protected_->channels == 2); + + for(channel = 0; channel < 2; channel++) { + void *integer_signal_; + if(encoder->private_->subframe_bps_mid_side[channel] <= 32) + integer_signal_ = encoder->private_->integer_signal_mid_side[channel]; + else + integer_signal_ = encoder->private_->integer_signal_33bit_side; + if(! + process_subframe_( + encoder, + min_partition_order, + max_partition_order, + &frame_header, + encoder->private_->subframe_bps_mid_side[channel], + integer_signal_, + encoder->private_->subframe_workspace_ptr_mid_side[channel], + encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel], + encoder->private_->residual_workspace_mid_side[channel], + encoder->private_->best_subframe_mid_side+channel, + encoder->private_->best_subframe_bits_mid_side+channel + ) + ) + return false; + } + } + + /* + * Compose the frame bitbuffer + */ + if(do_mid_side) { + uint32_t left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */ + FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */ + FLAC__ChannelAssignment channel_assignment; + + FLAC__ASSERT(encoder->protected_->channels == 2); + + if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) { + channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE); + } + else { + uint32_t bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */ + uint32_t min_bits; + int ca; + + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT == 0); + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE == 1); + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE == 2); + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE == 3); + FLAC__ASSERT(do_independent && do_mid_side); + + /* We have to figure out which channel assignent results in the smallest frame */ + bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits [1]; + bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE ] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits_mid_side[1]; + bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits [1] + encoder->private_->best_subframe_bits_mid_side[1]; + bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1]; + + channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; + min_bits = bits[channel_assignment]; + + /* When doing loose mid-side stereo, ignore left-side + * and right-side options */ + ca = encoder->protected_->loose_mid_side_stereo ? 3 : 1; + for( ; ca <= 3; ca++) { + if(bits[ca] < min_bits) { + min_bits = bits[ca]; + channel_assignment = (FLAC__ChannelAssignment)ca; + } + } + } + + frame_header.channel_assignment = channel_assignment; + + if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return false; + } + + switch(channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; + right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; + right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + left_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; + right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + left_subframe = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]]; + right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; + break; + default: + FLAC__ASSERT(0); + } + + switch(channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + left_bps = encoder->private_->subframe_bps [0]; + right_bps = encoder->private_->subframe_bps [1]; + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + left_bps = encoder->private_->subframe_bps [0]; + right_bps = encoder->private_->subframe_bps_mid_side[1]; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + left_bps = encoder->private_->subframe_bps_mid_side[1]; + right_bps = encoder->private_->subframe_bps [1]; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + left_bps = encoder->private_->subframe_bps_mid_side[0]; + right_bps = encoder->private_->subframe_bps_mid_side[1]; + break; + default: + FLAC__ASSERT(0); + } + + /* note that encoder_add_subframe_ sets the state for us in case of an error */ + if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame)) + return false; + if(!add_subframe_(encoder, frame_header.blocksize, right_bps, right_subframe, encoder->private_->frame)) + return false; + } + else { + if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return false; + } + + for(channel = 0; channel < encoder->protected_->channels; channel++) { + if(!add_subframe_(encoder, frame_header.blocksize, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) { + /* the above function sets the state for us in case of an error */ + return false; + } + } + } + + if(encoder->protected_->loose_mid_side_stereo) { + encoder->private_->loose_mid_side_stereo_frame_count++; + if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames) + encoder->private_->loose_mid_side_stereo_frame_count = 0; + } + + encoder->private_->last_channel_assignment = frame_header.channel_assignment; + encoder->private_->disable_constant_subframes = backup_disable_constant_subframes; + + return true; +} + +FLAC__bool process_subframe_( + FLAC__StreamEncoder *encoder, + uint32_t min_partition_order, + uint32_t max_partition_order, + const FLAC__FrameHeader *frame_header, + uint32_t subframe_bps, + const void *integer_signal, + FLAC__Subframe *subframe[2], + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], + FLAC__int32 *residual[2], + uint32_t *best_subframe, + uint32_t *best_bits +) +{ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + float fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; +#else + FLAC__fixedpoint fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; +#endif +#ifndef FLAC__INTEGER_ONLY_LIBRARY + double lpc_residual_bits_per_sample; + apply_apodization_state_struct apply_apodization_state; + double lpc_error[FLAC__MAX_LPC_ORDER]; + uint32_t min_lpc_order, max_lpc_order, lpc_order, guess_lpc_order; + uint32_t min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision; +#endif + uint32_t min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order; + uint32_t _candidate_bits, _best_bits; + uint32_t _best_subframe; + /* only use RICE2 partitions if stream bps > 16 */ + const uint32_t rice_parameter_limit = FLAC__stream_encoder_get_bits_per_sample(encoder) > 16? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + + FLAC__ASSERT(frame_header->blocksize > 0); + + /* verbatim subframe is the baseline against which we measure other compressed subframes */ + _best_subframe = 0; + if(encoder->private_->disable_verbatim_subframes && frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) + _best_bits = UINT32_MAX; + else + _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); + *best_bits = _best_bits; + + if(frame_header->blocksize > FLAC__MAX_FIXED_ORDER) { + uint32_t signal_is_constant = false; + /* The next formula determines when to use a 64-bit accumulator + * for the error of a fixed predictor, and when a 32-bit one. As + * the error of a 4th order predictor for a given sample is the + * sum of 17 sample values (1+4+6+4+1) and there are blocksize - + * order error values to be summed, the maximum total error is + * maximum_sample_value * (blocksize - order) * 17. As ilog2(x) + * calculates floor(2log(x)), the result must be 31 or lower + */ + if(subframe_bps < 28){ + if(subframe_bps + FLAC__bitmath_ilog2((frame_header->blocksize-FLAC__MAX_FIXED_ORDER)*17) < 32) + guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(((FLAC__int32 *)integer_signal)+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); + else + guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor_wide(((FLAC__int32 *)integer_signal)+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); + } + else + if(subframe_bps <= 32) + guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor_limit_residual(((FLAC__int32 *)integer_signal+FLAC__MAX_FIXED_ORDER),frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); + else + guess_fixed_order = FLAC__fixed_compute_best_predictor_limit_residual_33bit(((FLAC__int64 *)integer_signal+FLAC__MAX_FIXED_ORDER),frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); + + /* check for constant subframe */ + if( + !encoder->private_->disable_constant_subframes && +#ifndef FLAC__INTEGER_ONLY_LIBRARY + fixed_residual_bits_per_sample[1] == 0.0 +#else + fixed_residual_bits_per_sample[1] == FLAC__FP_ZERO +#endif + ) { + /* the above means it's possible all samples are the same value; now double-check it: */ + uint32_t i; + signal_is_constant = true; + if(subframe_bps <= 32){ + const FLAC__int32 *integer_signal_ = integer_signal; + for(i = 1; i < frame_header->blocksize; i++) { + if(integer_signal_[0] != integer_signal_[i]) { + signal_is_constant = false; + break; + } + } + } + else { + const FLAC__int64 *integer_signal_ = integer_signal; + for(i = 1; i < frame_header->blocksize; i++) { + if(integer_signal_[0] != integer_signal_[i]) { + signal_is_constant = false; + break; + } + } + } + } + if(signal_is_constant) { + if(subframe_bps <= 32) + _candidate_bits = evaluate_constant_subframe_(encoder, ((FLAC__int32 *)integer_signal)[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]); + else + _candidate_bits = evaluate_constant_subframe_(encoder, ((FLAC__int64 *)integer_signal)[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]); + + if(_candidate_bits < _best_bits) { + _best_subframe = !_best_subframe; + _best_bits = _candidate_bits; + } + } + else { + if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) { + /* encode fixed */ + if(encoder->protected_->do_exhaustive_model_search) { + min_fixed_order = 0; + max_fixed_order = FLAC__MAX_FIXED_ORDER; + } + else { + min_fixed_order = max_fixed_order = guess_fixed_order; + } + if(max_fixed_order >= frame_header->blocksize) + max_fixed_order = frame_header->blocksize - 1; + for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) { +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(fixed_residual_bits_per_sample[fixed_order] >= (float)subframe_bps) + continue; /* don't even try */ +#else + if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps) + continue; /* don't even try */ +#endif + _candidate_bits = + evaluate_fixed_subframe_( + encoder, + integer_signal, + residual[!_best_subframe], + encoder->private_->abs_residual_partition_sums, + encoder->private_->raw_bits_per_partition, + frame_header->blocksize, + subframe_bps, + fixed_order, + rice_parameter_limit, + min_partition_order, + max_partition_order, + encoder->protected_->do_escape_coding, + encoder->protected_->rice_parameter_search_dist, + subframe[!_best_subframe], + partitioned_rice_contents[!_best_subframe] + ); + if(_candidate_bits < _best_bits) { + _best_subframe = !_best_subframe; + _best_bits = _candidate_bits; + } + } + } + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + /* encode lpc */ + if(encoder->protected_->max_lpc_order > 0) { + if(encoder->protected_->max_lpc_order >= frame_header->blocksize) + max_lpc_order = frame_header->blocksize-1; + else + max_lpc_order = encoder->protected_->max_lpc_order; + if(max_lpc_order > 0) { + apply_apodization_state.a = 0; + apply_apodization_state.b = 1; + apply_apodization_state.c = 0; + while (apply_apodization_state.a < encoder->protected_->num_apodizations) { + uint32_t max_lpc_order_this_apodization = max_lpc_order; + + if(!apply_apodization_(encoder, &apply_apodization_state, + frame_header->blocksize, lpc_error, + &max_lpc_order_this_apodization, + subframe_bps, integer_signal, + &guess_lpc_order)) + /* If apply_apodization_ fails, try next apodization */ + continue; + + if(encoder->protected_->do_exhaustive_model_search) { + min_lpc_order = 1; + } + else { + min_lpc_order = max_lpc_order_this_apodization = guess_lpc_order; + } + for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order_this_apodization; lpc_order++) { + lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order); + if(lpc_residual_bits_per_sample >= (double)subframe_bps) + continue; /* don't even try */ + if(encoder->protected_->do_qlp_coeff_prec_search) { + min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; + /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */ + if(subframe_bps <= 17) { + max_qlp_coeff_precision = flac_min(32 - subframe_bps - FLAC__bitmath_ilog2(lpc_order), FLAC__MAX_QLP_COEFF_PRECISION); + max_qlp_coeff_precision = flac_max(max_qlp_coeff_precision, min_qlp_coeff_precision); + } + else + max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; + } + else { + min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision; + } + for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) { + _candidate_bits = + evaluate_lpc_subframe_( + encoder, + integer_signal, + residual[!_best_subframe], + encoder->private_->abs_residual_partition_sums, + encoder->private_->raw_bits_per_partition, + encoder->private_->lp_coeff[lpc_order-1], + frame_header->blocksize, + subframe_bps, + lpc_order, + qlp_coeff_precision, + rice_parameter_limit, + min_partition_order, + max_partition_order, + encoder->protected_->do_escape_coding, + encoder->protected_->rice_parameter_search_dist, + subframe[!_best_subframe], + partitioned_rice_contents[!_best_subframe] + ); + if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */ + if(_candidate_bits < _best_bits) { + _best_subframe = !_best_subframe; + _best_bits = _candidate_bits; + } + } + } + } + } + } + } +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + } + } + + /* under rare circumstances this can happen when all but lpc subframe types are disabled: */ + if(_best_bits == UINT32_MAX) { + FLAC__ASSERT(_best_subframe == 0); + _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); + } + + *best_subframe = _best_subframe; + *best_bits = _best_bits; + + return true; +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +static inline void set_next_subdivide_tukey(FLAC__int32 parts, uint32_t * apodizations, uint32_t * current_depth, uint32_t * current_part){ + // current_part is interleaved: even are partial, odd are punchout + if(*current_depth == 2){ + // For depth 2, we only do partial, no punchout as that is almost redundant + if(*current_part == 0){ + *current_part = 2; + }else{ /* *current_path == 2 */ + *current_part = 0; + (*current_depth)++; + } + }else if((*current_part) < (2*(*current_depth)-1)){ + (*current_part)++; + }else{ /* (*current_part) >= (2*(*current_depth)-1) */ + *current_part = 0; + (*current_depth)++; + } + + /* Now check if we are done with this SUBDIVIDE_TUKEY apodization */ + if(*current_depth > (uint32_t) parts){ + (*apodizations)++; + *current_depth = 1; + *current_part = 0; + } +} + +FLAC__bool apply_apodization_(FLAC__StreamEncoder *encoder, + apply_apodization_state_struct *apply_apodization_state, + uint32_t blocksize, + double *lpc_error, + uint32_t *max_lpc_order_this_apodization, + uint32_t subframe_bps, + const void *integer_signal, + uint32_t *guess_lpc_order) +{ + apply_apodization_state->current_apodization = &encoder->protected_->apodizations[apply_apodization_state->a]; + + if(apply_apodization_state->b == 1) { + /* window full subblock */ + if(subframe_bps <= 32) + FLAC__lpc_window_data(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize); + else + FLAC__lpc_window_data_wide(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize); + encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, blocksize, (*max_lpc_order_this_apodization)+1, apply_apodization_state->autoc); + if(apply_apodization_state->current_apodization->type == FLAC__APODIZATION_SUBDIVIDE_TUKEY){ + uint32_t i; + for(i = 0; i < *max_lpc_order_this_apodization; i++) + memcpy(apply_apodization_state->autoc_root, apply_apodization_state->autoc, *max_lpc_order_this_apodization*sizeof(apply_apodization_state->autoc[0])); + + (apply_apodization_state->b)++; + }else{ + (apply_apodization_state->a)++; + } + } + else { + /* window part of subblock */ + if(blocksize/apply_apodization_state->b <= FLAC__MAX_LPC_ORDER) { + /* intrinsics autocorrelation routines do not all handle cases in which lag might be + * larger than data_len, and some routines round lag up to the nearest multiple of 4 + * As little gain is expected from using LPC on part of a signal as small as 32 samples + * and to enable widening this rounding up to larger values in the future, windowing + * parts smaller than or equal to FLAC__MAX_LPC_ORDER (which is 32) samples is not supported */ + set_next_subdivide_tukey(apply_apodization_state->current_apodization->parameters.subdivide_tukey.parts, &apply_apodization_state->a, &apply_apodization_state->b, &apply_apodization_state->c); + return false; + } + if(!(apply_apodization_state->c % 2)) { + /* on even c, evaluate the (c/2)th partial window of size blocksize/b */ + if(subframe_bps <= 32) + FLAC__lpc_window_data_partial(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize, blocksize/apply_apodization_state->b/2, (apply_apodization_state->c/2*blocksize)/apply_apodization_state->b); + else + FLAC__lpc_window_data_partial_wide(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize, blocksize/apply_apodization_state->b/2, (apply_apodization_state->c/2*blocksize)/apply_apodization_state->b); + encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, blocksize/apply_apodization_state->b, (*max_lpc_order_this_apodization)+1, apply_apodization_state->autoc); + } + else { + /* on uneven c, evaluate the root window (over the whole block) minus the previous partial window + * similar to tukey_punchout apodization but more efficient */ + uint32_t i; + for(i = 0; i < *max_lpc_order_this_apodization; i++) + apply_apodization_state->autoc[i] = apply_apodization_state->autoc_root[i] - apply_apodization_state->autoc[i]; + } + /* Next function sets a, b and c appropriate for next iteration */ + set_next_subdivide_tukey(apply_apodization_state->current_apodization->parameters.subdivide_tukey.parts, &apply_apodization_state->a, &apply_apodization_state->b, &apply_apodization_state->c); + } + + if(apply_apodization_state->autoc[0] == 0.0) /* Signal seems to be constant, so we can't do lp. Constant detection is probably disabled */ + return false; + FLAC__lpc_compute_lp_coefficients(apply_apodization_state->autoc, max_lpc_order_this_apodization, encoder->private_->lp_coeff, lpc_error); + *guess_lpc_order = + FLAC__lpc_compute_best_order( + lpc_error, + *max_lpc_order_this_apodization, + blocksize, + subframe_bps + ( + encoder->protected_->do_qlp_coeff_prec_search? + FLAC__MIN_QLP_COEFF_PRECISION : /* have to guess; use the min possible size to avoid accidentally favoring lower orders */ + encoder->protected_->qlp_coeff_precision + ) + ); + return true; +} +#endif + +FLAC__bool add_subframe_( + FLAC__StreamEncoder *encoder, + uint32_t blocksize, + uint32_t subframe_bps, + const FLAC__Subframe *subframe, + FLAC__BitWriter *frame +) +{ + switch(subframe->type) { + case FLAC__SUBFRAME_TYPE_CONSTANT: + if(!FLAC__subframe_add_constant(&(subframe->data.constant), subframe_bps, subframe->wasted_bits, frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return false; + } + break; + case FLAC__SUBFRAME_TYPE_FIXED: + if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return false; + } + break; + case FLAC__SUBFRAME_TYPE_LPC: + if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return false; + } + break; + case FLAC__SUBFRAME_TYPE_VERBATIM: + if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), blocksize, subframe_bps, subframe->wasted_bits, frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return false; + } + break; + default: + FLAC__ASSERT(0); + } + + return true; +} + +#define SPOTCHECK_ESTIMATE 0 +#if SPOTCHECK_ESTIMATE +static void spotcheck_subframe_estimate_( + FLAC__StreamEncoder *encoder, + uint32_t blocksize, + uint32_t subframe_bps, + const FLAC__Subframe *subframe, + uint32_t estimate +) +{ + FLAC__bool ret; + FLAC__BitWriter *frame = FLAC__bitwriter_new(); + if(frame == 0) { + fprintf(stderr, "EST: can't allocate frame\n"); + return; + } + if(!FLAC__bitwriter_init(frame)) { + fprintf(stderr, "EST: can't init frame\n"); + return; + } + ret = add_subframe_(encoder, blocksize, subframe_bps, subframe, frame); + FLAC__ASSERT(ret); + { + const uint32_t actual = FLAC__bitwriter_get_input_bits_unconsumed(frame); + if(estimate != actual) + fprintf(stderr, "EST: bad, frame#%u sub#%%d type=%8s est=%u, actual=%u, delta=%d\n", encoder->private_->current_frame_number, FLAC__SubframeTypeString[subframe->type], estimate, actual, (int)actual-(int)estimate); + } + FLAC__bitwriter_delete(frame); +} +#endif + +uint32_t evaluate_constant_subframe_( + FLAC__StreamEncoder *encoder, + const FLAC__int64 signal, + uint32_t blocksize, + uint32_t subframe_bps, + FLAC__Subframe *subframe +) +{ + uint32_t estimate; + subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT; + subframe->data.constant.value = signal; + + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + subframe_bps; + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#else + (void)encoder, (void)blocksize; +#endif + + return estimate; +} + +uint32_t evaluate_fixed_subframe_( + FLAC__StreamEncoder *encoder, + const void *signal, + FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t raw_bits_per_partition[], + uint32_t blocksize, + uint32_t subframe_bps, + uint32_t order, + uint32_t rice_parameter_limit, + uint32_t min_partition_order, + uint32_t max_partition_order, + FLAC__bool do_escape_coding, + uint32_t rice_parameter_search_dist, + FLAC__Subframe *subframe, + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents +) +{ + uint32_t i, residual_bits, estimate; + const uint32_t residual_samples = blocksize - order; + + if((subframe_bps + order) <= 32) + FLAC__fixed_compute_residual(((FLAC__int32 *)signal)+order, residual_samples, order, residual); + else if(subframe_bps <= 32) + FLAC__fixed_compute_residual_wide(((FLAC__int32 *)signal)+order, residual_samples, order, residual); + else + FLAC__fixed_compute_residual_wide_33bit(((FLAC__int64 *)signal)+order, residual_samples, order, residual); + + subframe->type = FLAC__SUBFRAME_TYPE_FIXED; + + subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; + subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents; + subframe->data.fixed.residual = residual; + + residual_bits = + find_best_partition_order_( + encoder->private_, + residual, + abs_residual_partition_sums, + raw_bits_per_partition, + residual_samples, + order, + rice_parameter_limit, + min_partition_order, + max_partition_order, + subframe_bps, + do_escape_coding, + rice_parameter_search_dist, + &subframe->data.fixed.entropy_coding_method + ); + + subframe->data.fixed.order = order; + if(subframe_bps <= 32) + for(i = 0; i < order; i++) + subframe->data.fixed.warmup[i] = ((FLAC__int32 *)signal)[i]; + else + for(i = 0; i < order; i++) + subframe->data.fixed.warmup[i] = ((FLAC__int64 *)signal)[i]; + + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (order * subframe_bps); + if(residual_bits < UINT32_MAX - estimate) // To make sure estimate doesn't overflow + estimate += residual_bits; + else + estimate = UINT32_MAX; + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#endif + + return estimate; +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +uint32_t evaluate_lpc_subframe_( + FLAC__StreamEncoder *encoder, + const void *signal, + FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t raw_bits_per_partition[], + const FLAC__real lp_coeff[], + uint32_t blocksize, + uint32_t subframe_bps, + uint32_t order, + uint32_t qlp_coeff_precision, + uint32_t rice_parameter_limit, + uint32_t min_partition_order, + uint32_t max_partition_order, + FLAC__bool do_escape_coding, + uint32_t rice_parameter_search_dist, + FLAC__Subframe *subframe, + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents +) +{ + FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* WATCHOUT: the size is important; some x86 intrinsic routines need more than lpc order elements */ + uint32_t i, residual_bits, estimate; + int quantization, ret; + const uint32_t residual_samples = blocksize - order; + + /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */ + if(subframe_bps <= 17) { + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER); + qlp_coeff_precision = flac_min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order)); + } + + ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization); + if(ret != 0) + return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */ + + if(FLAC__lpc_max_residual_bps(subframe_bps, qlp_coeff, order, quantization) > 32) { + if(subframe_bps <= 32){ + if(!FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(((FLAC__int32 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual)) + return 0; + } + else + if(!FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(((FLAC__int64 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual)) + return 0; + } + else + if(FLAC__lpc_max_prediction_before_shift_bps(subframe_bps, qlp_coeff, order) <= 32) + if(subframe_bps <= 16 && qlp_coeff_precision <= 16) + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(((FLAC__int32 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual); + else + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(((FLAC__int32 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual); + else + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(((FLAC__int32 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual); + + subframe->type = FLAC__SUBFRAME_TYPE_LPC; + + subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; + subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents; + subframe->data.lpc.residual = residual; + + residual_bits = + find_best_partition_order_( + encoder->private_, + residual, + abs_residual_partition_sums, + raw_bits_per_partition, + residual_samples, + order, + rice_parameter_limit, + min_partition_order, + max_partition_order, + subframe_bps, + do_escape_coding, + rice_parameter_search_dist, + &subframe->data.lpc.entropy_coding_method + ); + + subframe->data.lpc.order = order; + subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision; + subframe->data.lpc.quantization_level = quantization; + memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER); + if(subframe_bps <= 32) + for(i = 0; i < order; i++) + subframe->data.lpc.warmup[i] = ((FLAC__int32 *)signal)[i]; + else + for(i = 0; i < order; i++) + subframe->data.lpc.warmup[i] = ((FLAC__int64 *)signal)[i]; + + + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)); + if(residual_bits < UINT32_MAX - estimate) // To make sure estimate doesn't overflow + estimate += residual_bits; + else + estimate = UINT32_MAX; + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#endif + + return estimate; +} +#endif + +uint32_t evaluate_verbatim_subframe_( + FLAC__StreamEncoder *encoder, + const void *signal, + uint32_t blocksize, + uint32_t subframe_bps, + FLAC__Subframe *subframe +) +{ + uint32_t estimate; + + subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM; + + if(subframe_bps <= 32){ + subframe->data.verbatim.data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32; + subframe->data.verbatim.data.int32 = signal; + } + else { + subframe->data.verbatim.data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64; + subframe->data.verbatim.data.int64 = signal; + } + + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (blocksize * subframe_bps); + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#else + (void)encoder; +#endif + + return estimate; +} + +uint32_t find_best_partition_order_( + FLAC__StreamEncoderPrivate *private_, + const FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t raw_bits_per_partition[], + uint32_t residual_samples, + uint32_t predictor_order, + uint32_t rice_parameter_limit, + uint32_t min_partition_order, + uint32_t max_partition_order, + uint32_t bps, + FLAC__bool do_escape_coding, + uint32_t rice_parameter_search_dist, + FLAC__EntropyCodingMethod *best_ecm +) +{ + uint32_t residual_bits, best_residual_bits = 0; + uint32_t best_parameters_index = 0; + uint32_t best_partition_order = 0; + const uint32_t blocksize = residual_samples + predictor_order; + + max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order); + min_partition_order = flac_min(min_partition_order, max_partition_order); + + private_->local_precompute_partition_info_sums(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps); + + if(do_escape_coding) + precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order); + + { + int partition_order; + uint32_t sum; + + for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) { + if(! + set_partitioned_rice_( +#ifdef EXACT_RICE_BITS_CALCULATION + residual, +#endif + abs_residual_partition_sums+sum, + raw_bits_per_partition+sum, + residual_samples, + predictor_order, + rice_parameter_limit, + rice_parameter_search_dist, + (uint32_t)partition_order, + do_escape_coding, + &private_->partitioned_rice_contents_extra[!best_parameters_index], + &residual_bits + ) + ) + { + FLAC__ASSERT(best_residual_bits != 0); + break; + } + sum += 1u << partition_order; + if(best_residual_bits == 0 || residual_bits < best_residual_bits) { + best_residual_bits = residual_bits; + best_parameters_index = !best_parameters_index; + best_partition_order = partition_order; + } + } + } + + best_ecm->data.partitioned_rice.order = best_partition_order; + + { + /* + * We are allowed to de-const the pointer based on our special + * knowledge; it is const to the outside world. + */ + FLAC__EntropyCodingMethod_PartitionedRiceContents* prc = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_ecm->data.partitioned_rice.contents; + uint32_t partition; + + /* save best parameters and raw_bits */ + memcpy(prc->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, (uint32_t)sizeof(uint32_t)*(1<<(best_partition_order))); + if(do_escape_coding) + memcpy(prc->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, (uint32_t)sizeof(uint32_t)*(1<<(best_partition_order))); + /* + * Now need to check if the type should be changed to + * FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 based on the + * size of the rice parameters. + */ + for(partition = 0; partition < (1u<parameters[partition] >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { + best_ecm->type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2; + break; + } + } + } + + return best_residual_bits; +} + +void precompute_partition_info_sums_( + const FLAC__int32 residual[], + FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, + uint32_t predictor_order, + uint32_t min_partition_order, + uint32_t max_partition_order, + uint32_t bps +) +{ + const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order; + uint32_t partitions = 1u << max_partition_order; + + FLAC__ASSERT(default_partition_samples > predictor_order); + + /* first do max_partition_order */ + { + const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples); + uint32_t partition, residual_sample, end = (uint32_t)(-(int)predictor_order); + /* WATCHOUT: "bps + FLAC__MAX_EXTRA_RESIDUAL_BPS" is the maximum assumed size of the average residual magnitude */ + if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) { + for(partition = residual_sample = 0; partition < partitions; partition++) { + FLAC__uint32 abs_residual_partition_sum = 0; + end += default_partition_samples; + for( ; residual_sample < end; residual_sample++) + abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */ + abs_residual_partition_sums[partition] = abs_residual_partition_sum; + } + } + else { /* have to pessimistically use 64 bits for accumulator */ + for(partition = residual_sample = 0; partition < partitions; partition++) { + FLAC__uint64 abs_residual_partition_sum64 = 0; + end += default_partition_samples; + for( ; residual_sample < end; residual_sample++) + abs_residual_partition_sum64 += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */ + abs_residual_partition_sums[partition] = abs_residual_partition_sum64; + } + } + } + + /* now merge partitions for lower orders */ + { + uint32_t from_partition = 0, to_partition = partitions; + int partition_order; + for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) { + uint32_t i; + partitions >>= 1; + for(i = 0; i < partitions; i++) { + abs_residual_partition_sums[to_partition++] = + abs_residual_partition_sums[from_partition ] + + abs_residual_partition_sums[from_partition+1]; + from_partition += 2; + } + } + } +} + +void precompute_partition_info_escapes_( + const FLAC__int32 residual[], + uint32_t raw_bits_per_partition[], + uint32_t residual_samples, + uint32_t predictor_order, + uint32_t min_partition_order, + uint32_t max_partition_order +) +{ + int partition_order; + uint32_t from_partition, to_partition = 0; + const uint32_t blocksize = residual_samples + predictor_order; + + /* first do max_partition_order */ + for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) { + FLAC__int32 r; + FLAC__uint32 rmax; + uint32_t partition, partition_sample, partition_samples, residual_sample; + const uint32_t partitions = 1u << partition_order; + const uint32_t default_partition_samples = blocksize >> partition_order; + + FLAC__ASSERT(default_partition_samples > predictor_order); + + for(partition = residual_sample = 0; partition < partitions; partition++) { + partition_samples = default_partition_samples; + if(partition == 0) + partition_samples -= predictor_order; + rmax = 0; + for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) { + r = residual[residual_sample++]; + /* OPT: maybe faster: rmax |= r ^ (r>>31) */ + if(r < 0) + rmax |= ~r; + else + rmax |= r; + } + /* now we know all residual values are in the range [-rmax-1,rmax] */ + raw_bits_per_partition[partition] = rmax? FLAC__bitmath_ilog2(rmax) + 2 : 1; + } + to_partition = partitions; + break; /*@@@ yuck, should remove the 'for' loop instead */ + } + + /* now merge partitions for lower orders */ + for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) { + uint32_t m; + uint32_t i; + const uint32_t partitions = 1u << partition_order; + for(i = 0; i < partitions; i++) { + m = raw_bits_per_partition[from_partition]; + from_partition++; + raw_bits_per_partition[to_partition] = flac_max(m, raw_bits_per_partition[from_partition]); + from_partition++; + to_partition++; + } + } +} + +#ifdef EXACT_RICE_BITS_CALCULATION +static inline uint32_t count_rice_bits_in_partition_( + const uint32_t rice_parameter, + const uint32_t partition_samples, + const FLAC__int32 *residual +) +{ + uint32_t i; + uint64_t partition_bits = + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */ + (1+rice_parameter) * partition_samples /* 1 for unary stop bit + rice_parameter for the binary portion */ + ; + for(i = 0; i < partition_samples; i++) + partition_bits += ( (FLAC__uint32)((residual[i]<<1)^(residual[i]>>31)) >> rice_parameter ); + return (uint32_t)(flac_min(partition_bits,UINT32_MAX)); // To make sure the return value doesn't overflow +} +#else +static inline uint32_t count_rice_bits_in_partition_( + const uint32_t rice_parameter, + const uint32_t partition_samples, + const FLAC__uint64 abs_residual_partition_sum +) +{ + return (uint32_t)(flac_min( // To make sure the return value doesn't overflow + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */ + (1+rice_parameter) * partition_samples + /* 1 for unary stop bit + rice_parameter for the binary portion */ + ( + rice_parameter? + (abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */ + : (abs_residual_partition_sum << 1) /* can't shift by negative number, so reverse */ + ) + - (partition_samples >> 1),UINT32_MAX)); + /* -(partition_samples>>1) to subtract out extra contributions to the abs_residual_partition_sum. + * The actual number of bits used is closer to the sum(for all i in the partition) of abs(residual[i])>>(rice_parameter-1) + * By using the abs_residual_partition sum, we also add in bits in the LSBs that would normally be shifted out. + * So the subtraction term tries to guess how many extra bits were contributed. + * If the LSBs are randomly distributed, this should average to 0.5 extra bits per sample. + */ + ; +} +#endif + +FLAC__bool set_partitioned_rice_( +#ifdef EXACT_RICE_BITS_CALCULATION + const FLAC__int32 residual[], +#endif + const FLAC__uint64 abs_residual_partition_sums[], + const uint32_t raw_bits_per_partition[], + const uint32_t residual_samples, + const uint32_t predictor_order, + const uint32_t rice_parameter_limit, + const uint32_t rice_parameter_search_dist, + const uint32_t partition_order, + const FLAC__bool search_for_escapes, + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, + uint32_t *bits +) +{ + uint32_t rice_parameter, partition_bits; + uint32_t best_partition_bits, best_rice_parameter = 0; + uint32_t bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; + uint32_t *parameters, *raw_bits; + uint32_t partition, residual_sample; + uint32_t partition_samples, partition_samples_base; + uint32_t partition_samples_fixed_point_divisor, partition_samples_fixed_point_divisor_base; + const uint32_t partitions = 1u << partition_order; + FLAC__uint64 mean; +#ifdef ENABLE_RICE_PARAMETER_SEARCH + uint32_t min_rice_parameter, max_rice_parameter; +#else + (void)rice_parameter_search_dist; +#endif + + FLAC__ASSERT(rice_parameter_limit <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER); + + parameters = partitioned_rice_contents->parameters; + raw_bits = partitioned_rice_contents->raw_bits; + + partition_samples_base = (residual_samples+predictor_order) >> partition_order; + + /* Integer division is slow. To speed up things, precalculate a fixed point + * divisor, as all partitions except the first are the same size. 18 bits + * are taken because maximum block size is 65535, max partition size for + * partitions other than 0 is 32767 (15 bit), max abs residual is 2^31, + * which leaves 18 bit */ + partition_samples_fixed_point_divisor_base = 0x40000 / partition_samples_base; + + for(partition = residual_sample = 0; partition < partitions; partition++) { + partition_samples = partition_samples_base; + if(partition > 0) { + partition_samples_fixed_point_divisor = partition_samples_fixed_point_divisor_base; + } + else { + if(partition_samples <= predictor_order) + return false; + else + partition_samples -= predictor_order; + partition_samples_fixed_point_divisor = 0x40000 / partition_samples; + } + mean = abs_residual_partition_sums[partition]; + /* 'mean' is not a good name for the variable, it is + * actually the sum of magnitudes of all residual values + * in the partition, so the actual mean is + * mean/partition_samples + */ + if(mean < 2 || (((mean - 1)*partition_samples_fixed_point_divisor)>>18) == 0) + rice_parameter = 0; + else + rice_parameter = FLAC__bitmath_ilog2_wide(((mean - 1)*partition_samples_fixed_point_divisor)>>18) + 1; + + if(rice_parameter >= rice_parameter_limit) { +#ifndef NDEBUG + fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, rice_parameter_limit - 1); +#endif + rice_parameter = rice_parameter_limit - 1; + } + + best_partition_bits = UINT32_MAX; +#ifdef ENABLE_RICE_PARAMETER_SEARCH + if(rice_parameter_search_dist) { + if(rice_parameter < rice_parameter_search_dist) + min_rice_parameter = 0; + else + min_rice_parameter = rice_parameter - rice_parameter_search_dist; + max_rice_parameter = rice_parameter + rice_parameter_search_dist; + if(max_rice_parameter >= rice_parameter_limit) { +#ifndef NDEBUG + fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, rice_parameter_limit - 1); +#endif + max_rice_parameter = rice_parameter_limit - 1; + } + } + else + min_rice_parameter = max_rice_parameter = rice_parameter; + + for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) { +#endif +#ifdef EXACT_RICE_BITS_CALCULATION + partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample); +#else + partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]); +#endif + if(partition_bits < best_partition_bits) { + best_rice_parameter = rice_parameter; + best_partition_bits = partition_bits; + } +#ifdef ENABLE_RICE_PARAMETER_SEARCH + } +#endif + if(search_for_escapes) { + partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples; + if(partition_bits <= best_partition_bits && raw_bits_per_partition[partition] < 32) { + raw_bits[partition] = raw_bits_per_partition[partition]; + best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */ + best_partition_bits = partition_bits; + } + else + raw_bits[partition] = 0; + } + parameters[partition] = best_rice_parameter; + if(best_partition_bits < UINT32_MAX - bits_) // To make sure _bits doesn't overflow + bits_ += best_partition_bits; + else + bits_ = UINT32_MAX; + residual_sample += partition_samples; + } + + *bits = bits_; + return true; +} + +uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples) +{ + uint32_t i, shift; + FLAC__int32 x = 0; + + for(i = 0; i < samples && !(x&1); i++) + x |= signal[i]; + + if(x == 0) { + shift = 0; + } + else { + for(shift = 0; !(x&1); shift++) + x >>= 1; + } + + if(shift > 0) { + for(i = 0; i < samples; i++) + signal[i] >>= shift; + } + + return shift; +} + +uint32_t get_wasted_bits_wide_(FLAC__int64 signal_wide[], FLAC__int32 signal[], uint32_t samples) +{ + uint32_t i, shift; + FLAC__int64 x = 0; + + for(i = 0; i < samples && !(x&1); i++) + x |= signal_wide[i]; + + if(x == 0) { + shift = 1; + } + else { + for(shift = 0; !(x&1); shift++) + x >>= 1; + } + + if(shift > 0) { + for(i = 0; i < samples; i++) + signal[i] = (FLAC__int32)(signal_wide[i] >> shift); + } + + return shift; +} + + +void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples) +{ + uint32_t channel; + + for(channel = 0; channel < channels; channel++) + memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples); + + fifo->tail += wide_samples; + + FLAC__ASSERT(fifo->tail <= fifo->size); +} + +void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples) +{ + uint32_t channel; + uint32_t sample, wide_sample; + uint32_t tail = fifo->tail; + + sample = input_offset * channels; + for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + for(channel = 0; channel < channels; channel++) + fifo->data[channel][tail] = input[sample++]; + tail++; + } + fifo->tail = tail; + + FLAC__ASSERT(fifo->tail <= fifo->size); +} + +FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data; + const size_t encoded_bytes = encoder->private_->verify.output.bytes; + (void)decoder; + + if(encoder->private_->verify.needs_magic_hack) { + FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH); + *bytes = FLAC__STREAM_SYNC_LENGTH; + memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes); + encoder->private_->verify.needs_magic_hack = false; + } + else { + if(encoded_bytes == 0) { + /* + * If we get here, a FIFO underflow has occurred, + * which means there is a bug somewhere. + */ + FLAC__ASSERT(0); + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + else if(encoded_bytes < *bytes) + *bytes = encoded_bytes; + memcpy(buffer, encoder->private_->verify.output.data, *bytes); + encoder->private_->verify.output.data += *bytes; + encoder->private_->verify.output.bytes -= *bytes; + } + + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} + +FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data; + uint32_t channel; + const uint32_t channels = frame->header.channels; + const uint32_t blocksize = frame->header.blocksize; + const uint32_t bytes_per_block = sizeof(FLAC__int32) * blocksize; + + (void)decoder; + + if(encoder->protected_->state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) { + /* This is set when verify_error_callback_ was called */ + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + for(channel = 0; channel < channels; channel++) { + if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) { + uint32_t i, sample = 0; + FLAC__int32 expect = 0, got = 0; + + for(i = 0; i < blocksize; i++) { + if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) { + sample = i; + expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i]; + got = (FLAC__int32)buffer[channel][i]; + break; + } + } + FLAC__ASSERT(i < blocksize); + FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample; + encoder->private_->verify.error_stats.frame_number = (uint32_t)(frame->header.number.sample_number / blocksize); + encoder->private_->verify.error_stats.channel = channel; + encoder->private_->verify.error_stats.sample = sample; + encoder->private_->verify.error_stats.expected = expect; + encoder->private_->verify.error_stats.got = got; + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + /* dequeue the frame from the fifo */ + encoder->private_->verify.input_fifo.tail -= blocksize; + FLAC__ASSERT(encoder->private_->verify.input_fifo.tail <= OVERREAD_); + for(channel = 0; channel < channels; channel++) + memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail * sizeof(encoder->private_->verify.input_fifo.data[0][0])); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + (void)decoder, (void)metadata, (void)client_data; +} + +void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data; + (void)decoder, (void)status; + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; +} + +FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + (void)client_data; + + *bytes = fread(buffer, 1, *bytes, encoder->private_->file); + if (*bytes == 0) { + if (feof(encoder->private_->file)) + return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; + else if (ferror(encoder->private_->file)) + return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + } + return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; +} + +FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + (void)client_data; + + if(fseeko(encoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; +} + +FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FLAC__off_t offset; + + (void)client_data; + + offset = ftello(encoder->private_->file); + + if(offset < 0) { + return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + } + else { + *absolute_byte_offset = (FLAC__uint64)offset; + return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + } +} + +#ifdef FLAC__VALGRIND_TESTING +static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#else +#define local__fwrite fwrite +#endif + +FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data) +{ + (void)client_data, (void)current_frame; + + if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) { + FLAC__bool call_it = 0 != encoder->private_->progress_callback && ( +#if FLAC__HAS_OGG + /* We would like to be able to use 'samples > 0' in the + * clause here but currently because of the nature of our + * Ogg writing implementation, 'samples' is always 0 (see + * ogg_encoder_aspect.c). The downside is extra progress + * callbacks. + */ + encoder->private_->is_ogg? true : +#endif + samples > 0 + ); + if(call_it) { + /* NOTE: We have to add +bytes, +samples, and +1 to the stats + * because at this point in the callback chain, the stats + * have not been updated. Only after we return and control + * gets back to write_frame_() are the stats updated + */ + encoder->private_->progress_callback(encoder, encoder->private_->bytes_written+bytes, encoder->private_->samples_written+samples, encoder->private_->frames_written+(samples?1:0), encoder->private_->total_frames_estimate, encoder->private_->client_data); + } + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; + } + else + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; +} + +/* + * This will forcibly set stdout to binary mode (for OSes that require it) + */ +FILE *get_binary_stdout_(void) +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdout), _O_BINARY); +#elif defined __EMX__ + setmode(fileno(stdout), O_BINARY); +#endif + + return stdout; +} diff --git a/vendor/flac/src/libFLAC/stream_encoder_framing.c b/vendor/flac/src/libFLAC/stream_encoder_framing.c new file mode 100644 index 0000000..0e07a31 --- /dev/null +++ b/vendor/flac/src/libFLAC/stream_encoder_framing.c @@ -0,0 +1,594 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for strlen() */ +#include "private/stream_encoder_framing.h" +#include "private/crc.h" +#include "FLAC/assert.h" +#include "share/compat.h" + +static FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method); +static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended); + +FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw, FLAC__bool update_vendor_string) +{ + uint32_t i, j, metadata_length; + const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING); + const uint32_t start_bits = FLAC__bitwriter_get_input_bits_unconsumed(bw); + + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); + + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN)) + return false; + + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN)) + return false; + + /* + * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string + */ + metadata_length = metadata->length; + if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && update_vendor_string) { + FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry); + metadata_length -= metadata->data.vorbis_comment.vendor_string.length; + metadata_length += vendor_string_length; + } + FLAC__ASSERT(metadata_length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); + /* double protection */ + if(metadata_length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata_length, FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; + + switch(metadata->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)); + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)) + return false; + FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)); + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) + return false; + FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)); + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) + return false; + FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)); + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) + return false; + FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate)); + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) + return false; + FLAC__ASSERT(metadata->data.stream_info.channels > 0); + FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)); + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) + return false; + FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0); + FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) + return false; + if(metadata->data.stream_info.total_samples >= (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)){ + if(!FLAC__bitwriter_write_raw_uint64(bw, 0, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) + return false; + }else{ + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) + return false; + } + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16)) + return false; + break; + case FLAC__METADATA_TYPE_PADDING: + if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8)) + return false; + break; + case FLAC__METADATA_TYPE_APPLICATION: + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))) + return false; + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + for(i = 0; i < metadata->data.seek_table.num_points; i++) { + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) + return false; + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(update_vendor_string) { + if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length)) + return false; + } + else { + if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.vendor_string.length)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.vendor_string.entry, metadata->data.vorbis_comment.vendor_string.length)) + return false; + } + if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.num_comments)) + return false; + for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) { + if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length)) + return false; + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) + return false; + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) + return false; + if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) + return false; + for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) { + const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i; + + if(!FLAC__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) + return false; + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) + return false; + if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) + return false; + for(j = 0; j < track->num_indices; j++) { + const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j; + + if(!FLAC__bitwriter_write_raw_uint64(bw, indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, indx->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) + return false; + if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) + return false; + } + } + break; + case FLAC__METADATA_TYPE_PICTURE: + { + size_t len; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) + return false; + len = strlen(metadata->data.picture.mime_type); + if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len)) + return false; + len = strlen((const char *)metadata->data.picture.description); + if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length)) + return false; + } + break; + default: + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length)) + return false; + break; + } + + /* Now check whether metadata block length was correct */ + { + uint32_t length_in_bits = FLAC__bitwriter_get_input_bits_unconsumed(bw); + if(length_in_bits < start_bits) + return false; + length_in_bits -= start_bits; + if(length_in_bits % 8 != 0 || length_in_bits != (metadata_length*8+32)) + return false; + } + + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); + return true; +} + +FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw) +{ + uint32_t u, blocksize_hint, sample_rate_hint; + FLAC__byte crc; + + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); + + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN)) + return false; + + if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN)) + return false; + + if(!FLAC__bitwriter_write_raw_uint32(bw, (header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)? 0 : 1, FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN)) + return false; + + FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE); + /* when this assertion holds true, any legal blocksize can be expressed in the frame header */ + FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u); + blocksize_hint = 0; + switch(header->blocksize) { + case 192: u = 1; break; + case 576: u = 2; break; + case 1152: u = 3; break; + case 2304: u = 4; break; + case 4608: u = 5; break; + case 256: u = 8; break; + case 512: u = 9; break; + case 1024: u = 10; break; + case 2048: u = 11; break; + case 4096: u = 12; break; + case 8192: u = 13; break; + case 16384: u = 14; break; + case 32768: u = 15; break; + default: + if(header->blocksize <= 0x100) + blocksize_hint = u = 6; + else + blocksize_hint = u = 7; + break; + } + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN)) + return false; + + FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate)); + sample_rate_hint = 0; + switch(header->sample_rate) { + case 88200: u = 1; break; + case 176400: u = 2; break; + case 192000: u = 3; break; + case 8000: u = 4; break; + case 16000: u = 5; break; + case 22050: u = 6; break; + case 24000: u = 7; break; + case 32000: u = 8; break; + case 44100: u = 9; break; + case 48000: u = 10; break; + case 96000: u = 11; break; + default: + if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0) + sample_rate_hint = u = 12; + else if(header->sample_rate <= 655350 && header->sample_rate % 10 == 0) + sample_rate_hint = u = 14; + else if(header->sample_rate <= 0xffff) + sample_rate_hint = u = 13; + else + u = 0; + break; + } + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN)) + return false; + + FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS); + switch(header->channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + u = header->channels - 1; + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + FLAC__ASSERT(header->channels == 2); + u = 8; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + FLAC__ASSERT(header->channels == 2); + u = 9; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + FLAC__ASSERT(header->channels == 2); + u = 10; + break; + default: + FLAC__ASSERT(0); + } + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN)) + return false; + + FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); + switch(header->bits_per_sample) { + case 8 : u = 1; break; + case 12: u = 2; break; + case 16: u = 4; break; + case 20: u = 5; break; + case 24: u = 6; break; + case 32: u = 7; break; + default: u = 0; break; + } + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN)) + return false; + + if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN)) + return false; + + if(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { + if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number)) + return false; + } + else { + if(!FLAC__bitwriter_write_utf8_uint64(bw, header->number.sample_number)) + return false; + } + + if(blocksize_hint) + if(!FLAC__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16)) + return false; + + switch(sample_rate_hint) { + case 12: + if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8)) + return false; + break; + case 13: + if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16)) + return false; + break; + case 14: + if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16)) + return false; + break; + } + + /* write the CRC */ + if(!FLAC__bitwriter_get_write_crc8(bw, &crc)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, crc, FLAC__FRAME_HEADER_CRC_LEN)) + return false; + + return true; +} + +FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) +{ + FLAC__bool ok; + + ok = + FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) && + (wasted_bits? FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) && + FLAC__bitwriter_write_raw_int64(bw, subframe->value, subframe_bps) + ; + + return ok; +} + +FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) +{ + uint32_t i; + + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) + return false; + if(wasted_bits) + if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) + return false; + + for(i = 0; i < subframe->order; i++) + if(!FLAC__bitwriter_write_raw_int64(bw, subframe->warmup[i], subframe_bps)) + return false; + + if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) + return false; + switch(subframe->entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!add_residual_partitioned_rice_( + bw, + subframe->residual, + residual_samples, + subframe->order, + subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, + subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, + subframe->entropy_coding_method.data.partitioned_rice.order, + /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 + )) + return false; + break; + default: + FLAC__ASSERT(0); + } + + return true; +} + +FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) +{ + uint32_t i; + + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) + return false; + if(wasted_bits) + if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) + return false; + + for(i = 0; i < subframe->order; i++) + if(!FLAC__bitwriter_write_raw_int64(bw, subframe->warmup[i], subframe_bps)) + return false; + + if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_int32(bw, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) + return false; + for(i = 0; i < subframe->order; i++) + if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision)) + return false; + + if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) + return false; + switch(subframe->entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!add_residual_partitioned_rice_( + bw, + subframe->residual, + residual_samples, + subframe->order, + subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, + subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, + subframe->entropy_coding_method.data.partitioned_rice.order, + /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 + )) + return false; + break; + default: + FLAC__ASSERT(0); + } + + return true; +} + +FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, uint32_t samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) +{ + uint32_t i; + + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) + return false; + if(wasted_bits) + if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) + return false; + + if(subframe->data_type == FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32) { + const FLAC__int32 *signal = subframe->data.int32; + + FLAC__ASSERT(subframe_bps < 33); + + for(i = 0; i < samples; i++) + if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps)) + return false; + } + else { + const FLAC__int64 *signal = subframe->data.int64; + + FLAC__ASSERT(subframe_bps == 33); + + for(i = 0; i < samples; i++) + if(!FLAC__bitwriter_write_raw_int64(bw, (FLAC__int64)signal[i], subframe_bps)) + return false; + } + + return true; +} + +FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method) +{ + if(!FLAC__bitwriter_write_raw_uint32(bw, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) + return false; + switch(method->type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + return false; + break; + default: + FLAC__ASSERT(0); + } + return true; +} + +FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended) +{ + const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; + const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + + if(partition_order == 0) { + uint32_t i; + + if(raw_bits[0] == 0) { + if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], plen)) + return false; + if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0])) + return false; + } + else { + FLAC__ASSERT(rice_parameters[0] == 0); + if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) + return false; + for(i = 0; i < residual_samples; i++) { + if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0])) + return false; + } + } + return true; + } + else { + uint32_t i, j, k = 0, k_last = 0; + uint32_t partition_samples; + const uint32_t default_partition_samples = (residual_samples+predictor_order) >> partition_order; + for(i = 0; i < (1u< +#endif + +#include "private/cpu.h" + +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/stream_encoder.h" +#include "private/bitmath.h" +#ifdef FLAC__AVX2_SUPPORTED + +#include /* for abs() */ +#include /* AVX2 */ +#include "FLAC/assert.h" + +FLAC__SSE_TARGET("avx2") +void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps) +{ + const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order; + uint32_t partitions = 1u << max_partition_order; + + FLAC__ASSERT(default_partition_samples > predictor_order); + + /* first do max_partition_order */ + { + const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples); + uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order); + + if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) { + for(partition = residual_sample = 0; partition < partitions; partition++) { + __m256i sum256 = _mm256_setzero_si256(); + __m128i sum128; + end += default_partition_samples; + + for( ; (int)residual_sample < (int)end-7; residual_sample+=8) { + __m256i res256 = _mm256_abs_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(residual+residual_sample))); + sum256 = _mm256_add_epi32(sum256, res256); + } + + sum128 = _mm_add_epi32(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256)); + + for( ; (int)residual_sample < (int)end-3; residual_sample+=4) { + __m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample))); + sum128 = _mm_add_epi32(sum128, res128); + } + + for( ; residual_sample < end; residual_sample++) { + __m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + sum128 = _mm_add_epi32(sum128, res128); + } + + sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_SHUFFLE(1,0,3,2))); + sum128 = _mm_add_epi32(sum128, _mm_shufflelo_epi16(sum128, _MM_SHUFFLE(1,0,3,2))); + abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(sum128); +/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */ +#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64) + abs_residual_partition_sums[partition] &= 0xFFFFFFFF; /**/ +#endif + } + } + else { /* have to pessimistically use 64 bits for accumulator */ + for(partition = residual_sample = 0; partition < partitions; partition++) { + __m256i sum256 = _mm256_setzero_si256(); + __m128i sum128; + end += default_partition_samples; + + for( ; (int)residual_sample < (int)end-3; residual_sample+=4) { + __m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample))); + __m256i res256 = _mm256_cvtepu32_epi64(res128); + sum256 = _mm256_add_epi64(sum256, res256); + } + + sum128 = _mm_add_epi64(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256)); + + for( ; (int)residual_sample < (int)end-1; residual_sample+=2) { + __m128i res128 = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(const void*)(residual+residual_sample))); + res128 = _mm_cvtepu32_epi64(res128); + sum128 = _mm_add_epi64(sum128, res128); + } + + for( ; residual_sample < end; residual_sample++) { + __m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + sum128 = _mm_add_epi64(sum128, res128); + } + + sum128 = _mm_add_epi64(sum128, _mm_srli_si128(sum128, 8)); + _mm_storel_epi64((__m128i*)(void*)(abs_residual_partition_sums+partition), sum128); + } + } + } + + /* now merge partitions for lower orders */ + { + uint32_t from_partition = 0, to_partition = partitions; + int partition_order; + for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) { + uint32_t i; + partitions >>= 1; + for(i = 0; i < partitions; i++) { + abs_residual_partition_sums[to_partition++] = + abs_residual_partition_sums[from_partition ] + + abs_residual_partition_sums[from_partition+1]; + from_partition += 2; + } + } + } + _mm256_zeroupper(); +} + +#endif /* FLAC__AVX2_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ diff --git a/vendor/flac/src/libFLAC/stream_encoder_intrin_sse2.c b/vendor/flac/src/libFLAC/stream_encoder_intrin_sse2.c new file mode 100644 index 0000000..dd25fa6 --- /dev/null +++ b/vendor/flac/src/libFLAC/stream_encoder_intrin_sse2.c @@ -0,0 +1,159 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/stream_encoder.h" +#include "private/bitmath.h" +#ifdef FLAC__SSE2_SUPPORTED + +#include /* for abs() */ +#include /* SSE2 */ +#include "FLAC/assert.h" +#include "share/compat.h" + +FLAC__SSE_TARGET("sse2") +static inline __m128i local_abs_epi32(__m128i val) +{ + __m128i mask = _mm_srai_epi32(val, 31); + val = _mm_xor_si128(val, mask); + val = _mm_sub_epi32(val, mask); + return val; +} + + +FLAC__SSE_TARGET("sse2") +void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps) +{ + const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order; + uint32_t partitions = 1u << max_partition_order; + + FLAC__ASSERT(default_partition_samples > predictor_order); + + /* first do max_partition_order */ + { + const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples); + uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order); + + if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) { + for(partition = residual_sample = 0; partition < partitions; partition++) { + __m128i mm_sum = _mm_setzero_si128(); + uint32_t e1, e3; + end += default_partition_samples; + + e1 = (residual_sample + 3) & ~3; e3 = end & ~3; + if(e1 > end) + e1 = end; /* try flac -l 1 -b 16 and you'll be here */ + + /* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */ + for( ; residual_sample < e1; residual_sample++) { + __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + mm_sum = _mm_add_epi32(mm_sum, mm_res); + } + + for( ; residual_sample < e3; residual_sample+=4) { + __m128i mm_res = local_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample))); + mm_sum = _mm_add_epi32(mm_sum, mm_res); + } + + for( ; residual_sample < end; residual_sample++) { + __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + mm_sum = _mm_add_epi32(mm_sum, mm_res); + } + + mm_sum = _mm_add_epi32(mm_sum, _mm_shuffle_epi32(mm_sum, _MM_SHUFFLE(1,0,3,2))); + mm_sum = _mm_add_epi32(mm_sum, _mm_shufflelo_epi16(mm_sum, _MM_SHUFFLE(1,0,3,2))); + abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum); +/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */ +#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64) + abs_residual_partition_sums[partition] &= 0xFFFFFFFF; +#endif + } + } + else { /* have to pessimistically use 64 bits for accumulator */ + for(partition = residual_sample = 0; partition < partitions; partition++) { + __m128i mm_sum = _mm_setzero_si128(); + uint32_t e1, e3; + end += default_partition_samples; + + e1 = (residual_sample + 1) & ~1; e3 = end & ~1; + FLAC__ASSERT(e1 <= end); + + for( ; residual_sample < e1; residual_sample++) { + __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /* 0 0 0 |r0| == 00 |r0_64| */ + mm_sum = _mm_add_epi64(mm_sum, mm_res); + } + + for( ; residual_sample < e3; residual_sample+=2) { + __m128i mm_res = local_abs_epi32(_mm_loadl_epi64((const __m128i*)(const void*)(residual+residual_sample))); /* 0 0 |r1| |r0| */ + mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0 |r1| 0 |r0| == |r1_64| |r0_64| */ + mm_sum = _mm_add_epi64(mm_sum, mm_res); + } + + for( ; residual_sample < end; residual_sample++) { + __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + mm_sum = _mm_add_epi64(mm_sum, mm_res); + } + + mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8)); + _mm_storel_epi64((__m128i*)(void*)(abs_residual_partition_sums+partition), mm_sum); + } + } + } + + /* now merge partitions for lower orders */ + { + uint32_t from_partition = 0, to_partition = partitions; + int partition_order; + for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) { + uint32_t i; + partitions >>= 1; + for(i = 0; i < partitions; i++) { + abs_residual_partition_sums[to_partition++] = + abs_residual_partition_sums[from_partition ] + + abs_residual_partition_sums[from_partition+1]; + from_partition += 2; + } + } + } +} + +#endif /* FLAC__SSE2_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ diff --git a/vendor/flac/src/libFLAC/stream_encoder_intrin_ssse3.c b/vendor/flac/src/libFLAC/stream_encoder_intrin_ssse3.c new file mode 100644 index 0000000..241f723 --- /dev/null +++ b/vendor/flac/src/libFLAC/stream_encoder_intrin_ssse3.c @@ -0,0 +1,148 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "private/cpu.h" + +#ifndef FLAC__NO_ASM +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN +#include "private/stream_encoder.h" +#include "private/bitmath.h" +#ifdef FLAC__SSSE3_SUPPORTED + +#include /* for abs() */ +#include /* SSSE3 */ +#include "FLAC/assert.h" + +FLAC__SSE_TARGET("ssse3") +void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps) +{ + const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order; + uint32_t partitions = 1u << max_partition_order; + + FLAC__ASSERT(default_partition_samples > predictor_order); + + /* first do max_partition_order */ + { + const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples); + uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order); + + if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) { + for(partition = residual_sample = 0; partition < partitions; partition++) { + __m128i mm_sum = _mm_setzero_si128(); + uint32_t e1, e3; + end += default_partition_samples; + + e1 = (residual_sample + 3) & ~3; e3 = end & ~3; + if(e1 > end) + e1 = end; /* try flac -l 1 -b 16 and you'll be here */ + + /* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */ + for( ; residual_sample < e1; residual_sample++) { + __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + mm_sum = _mm_add_epi32(mm_sum, mm_res); + } + + for( ; residual_sample < e3; residual_sample+=4) { + __m128i mm_res = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample))); + mm_sum = _mm_add_epi32(mm_sum, mm_res); + } + + for( ; residual_sample < end; residual_sample++) { + __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + mm_sum = _mm_add_epi32(mm_sum, mm_res); + } + + mm_sum = _mm_add_epi32(mm_sum, _mm_shuffle_epi32(mm_sum, _MM_SHUFFLE(1,0,3,2))); + mm_sum = _mm_add_epi32(mm_sum, _mm_shufflelo_epi16(mm_sum, _MM_SHUFFLE(1,0,3,2))); + abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum); +/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */ +#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64) + abs_residual_partition_sums[partition] &= 0xFFFFFFFF; +#endif + } + } + else { /* have to pessimistically use 64 bits for accumulator */ + for(partition = residual_sample = 0; partition < partitions; partition++) { + __m128i mm_sum = _mm_setzero_si128(); + uint32_t e1, e3; + end += default_partition_samples; + + e1 = (residual_sample + 1) & ~1; e3 = end & ~1; + FLAC__ASSERT(e1 <= end); + + for( ; residual_sample < e1; residual_sample++) { + __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /* 0 0 0 |r0| == 00 |r0_64| */ + mm_sum = _mm_add_epi64(mm_sum, mm_res); + } + + for( ; residual_sample < e3; residual_sample+=2) { + __m128i mm_res = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(const void*)(residual+residual_sample))); /* 0 0 |r1| |r0| */ + mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0 |r1| 0 |r0| == |r1_64| |r0_64| */ + mm_sum = _mm_add_epi64(mm_sum, mm_res); + } + + for( ; residual_sample < end; residual_sample++) { + __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); + mm_sum = _mm_add_epi64(mm_sum, mm_res); + } + + mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8)); + _mm_storel_epi64((__m128i*)(void*)(abs_residual_partition_sums+partition), mm_sum); + } + } + } + + /* now merge partitions for lower orders */ + { + uint32_t from_partition = 0, to_partition = partitions; + int partition_order; + for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) { + uint32_t i; + partitions >>= 1; + for(i = 0; i < partitions; i++) { + abs_residual_partition_sums[to_partition++] = + abs_residual_partition_sums[from_partition ] + + abs_residual_partition_sums[from_partition+1]; + from_partition += 2; + } + } + } +} + +#endif /* FLAC__SSSE3_SUPPORTED */ +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ +#endif /* FLAC__NO_ASM */ diff --git a/vendor/flac/src/libFLAC/version.rc b/vendor/flac/src/libFLAC/version.rc new file mode 100644 index 0000000..019da1d --- /dev/null +++ b/vendor/flac/src/libFLAC/version.rc @@ -0,0 +1,40 @@ +#include +#include "config.h" +#include "FLAC/export.h" + +#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE) +# ifdef GIT_COMMIT_TAG +# define VERSIONSTRING GIT_COMMIT_TAG +# else +# define VERSIONSTRING "git-" GIT_COMMIT_HASH +# endif +#else +# define VERSIONSTRING PACKAGE_VERSION +#endif + +#define xstr(s) str(s) +#define str(s) #s + +VS_VERSION_INFO VERSIONINFO +FILEVERSION FLAC_API_VERSION_CURRENT,FLAC_API_VERSION_REVISION,0,0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "libFLAC for Windows" + VALUE "ProductName", "Free Lossless Audio Codec" + VALUE "ProductVersion", VERSIONSTRING + VALUE "CompanyName", "Xiph.Org" + VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/vendor/flac/src/libFLAC/window.c b/vendor/flac/src/libFLAC/window.c new file mode 100644 index 0000000..69d5464 --- /dev/null +++ b/vendor/flac/src/libFLAC/window.c @@ -0,0 +1,308 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2006-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "share/compat.h" +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "private/window.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +#if defined(_MSC_VER) +// silence 25 MSVC warnings 'conversion from 'double' to 'float', possible loss of data' +#pragma warning ( disable : 4244 ) +#endif + +void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + if (L & 1) { + for (n = 0; n <= N/2; n++) + window[n] = 2.0f * n / (float)N; + for (; n <= N; n++) + window[n] = 2.0f - 2.0f * n / (float)N; + } + else { + for (n = 0; n <= L/2-1; n++) + window[n] = 2.0f * n / (float)N; + for (; n <= N; n++) + window[n] = 2.0f - 2.0f * n / (float)N; + } +} + +void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.62f - 0.48f * fabsf((float)n/(float)N-0.5f) - 0.38f * cosf(2.0f * M_PI * ((float)n/(float)N))); +} + +void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.42f - 0.5f * cosf(2.0f * M_PI * n / N) + 0.08f * cosf(4.0f * M_PI * n / N)); +} + +/* 4-term -92dB side-lobe */ +void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n <= N; n++) + window[n] = (FLAC__real)(0.35875f - 0.48829f * cosf(2.0f * M_PI * n / N) + 0.14128f * cosf(4.0f * M_PI * n / N) - 0.01168f * cosf(6.0f * M_PI * n / N)); +} + +void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + const double N2 = (double)N / 2.; + FLAC__int32 n; + + for (n = 0; n <= N; n++) { + double k = ((double)n - N2) / N2; + k = 1.0f - k * k; + window[n] = (FLAC__real)(k * k); + } +} + +void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.21557895f - 0.41663158f * cosf(2.0f * M_PI * n / N) + 0.277263158f * cosf(4.0f * M_PI * n / N) - 0.083578947f * cosf(6.0f * M_PI * n / N) + 0.006947368f * cosf(8.0f * M_PI * n / N)); +} + +void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev) +{ + const FLAC__int32 N = L - 1; + const double N2 = (double)N / 2.; + FLAC__int32 n; + + if(!(stddev > 0.0f && stddev <= 0.5f)) + /* stddev is not between 0 and 0.5, might be NaN. + * Default to 0.5 */ + FLAC__window_gauss(window, L, 0.25f); + else { + for (n = 0; n <= N; n++) { + const double k = ((double)n - N2) / (stddev * N2); + window[n] = (FLAC__real)exp(-0.5f * k * k); + } + } +} + +void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.54f - 0.46f * cosf(2.0f * M_PI * n / N)); +} + +void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(2.0f * M_PI * n / N)); +} + +void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.402f - 0.498f * cosf(2.0f * M_PI * n / N) + 0.098f * cosf(4.0f * M_PI * n / N) - 0.001f * cosf(6.0f * M_PI * n / N)); +} + +void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cosf(2.0f*M_PI*n/N) + 0.1365995f*cosf(4.0f*M_PI*n/N) - 0.0106411f*cosf(6.0f*M_PI*n/N)); +} + +void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L) +{ + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = 1.0f; +} + +void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L) +{ + FLAC__int32 n; + + if (L & 1) { + for (n = 1; n <= (L+1)/2; n++) + window[n-1] = 2.0f * n / ((float)L + 1.0f); + for (; n <= L; n++) + window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); + } + else { + for (n = 1; n <= L/2; n++) + window[n-1] = 2.0f * n / ((float)L + 1.0f); + for (; n <= L; n++) + window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); + } +} + +void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p) +{ + if (p <= 0.0) + FLAC__window_rectangle(window, L); + else if (p >= 1.0) + FLAC__window_hann(window, L); + else if (!(p > 0.0f && p < 1.0f)) + /* p is not between 0 and 1, probably NaN. + * Default to 0.5 */ + FLAC__window_tukey(window, L, 0.5f); + else { + const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1; + FLAC__int32 n; + /* start with rectangle... */ + FLAC__window_rectangle(window, L); + /* ...replace ends with hann */ + if (Np > 0) { + for (n = 0; n <= Np; n++) { + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * n / Np)); + window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * (n+Np) / Np)); + } + } + } +} + +void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) +{ + const FLAC__int32 start_n = (FLAC__int32)(start * L); + const FLAC__int32 end_n = (FLAC__int32)(end * L); + const FLAC__int32 N = end_n - start_n; + FLAC__int32 Np, n, i; + + if (p <= 0.0f) + FLAC__window_partial_tukey(window, L, 0.05f, start, end); + else if (p >= 1.0f) + FLAC__window_partial_tukey(window, L, 0.95f, start, end); + else if (!(p > 0.0f && p < 1.0f)) + /* p is not between 0 and 1, probably NaN. + * Default to 0.5 */ + FLAC__window_partial_tukey(window, L, 0.5f, start, end); + else { + + Np = (FLAC__int32)(p / 2.0f * N); + + for (n = 0; n < start_n && n < L; n++) + window[n] = 0.0f; + for (i = 1; n < (start_n+Np) && n < L; n++, i++) + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Np)); + for (; n < (end_n-Np) && n < L; n++) + window[n] = 1.0f; + for (i = Np; n < end_n && n < L; n++, i--) + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Np)); + for (; n < L; n++) + window[n] = 0.0f; + } +} + +void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) +{ + const FLAC__int32 start_n = (FLAC__int32)(start * L); + const FLAC__int32 end_n = (FLAC__int32)(end * L); + FLAC__int32 Ns, Ne, n, i; + + if (p <= 0.0f) + FLAC__window_punchout_tukey(window, L, 0.05f, start, end); + else if (p >= 1.0f) + FLAC__window_punchout_tukey(window, L, 0.95f, start, end); + else if (!(p > 0.0f && p < 1.0f)) + /* p is not between 0 and 1, probably NaN. + * Default to 0.5 */ + FLAC__window_punchout_tukey(window, L, 0.5f, start, end); + else { + + Ns = (FLAC__int32)(p / 2.0f * start_n); + Ne = (FLAC__int32)(p / 2.0f * (L - end_n)); + + for (n = 0, i = 1; n < Ns && n < L; n++, i++) + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ns)); + for (; n < start_n-Ns && n < L; n++) + window[n] = 1.0f; + for (i = Ns; n < start_n && n < L; n++, i--) + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ns)); + for (; n < end_n && n < L; n++) + window[n] = 0.0f; + for (i = 1; n < end_n+Ne && n < L; n++, i++) + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ne)); + for (; n < L - (Ne) && n < L; n++) + window[n] = 1.0f; + for (i = Ne; n < L; n++, i--) + window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ne)); + } +} + +void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + const double N2 = (double)N / 2.; + FLAC__int32 n; + + for (n = 0; n <= N; n++) { + const double k = ((double)n - N2) / N2; + window[n] = (FLAC__real)(1.0f - k * k); + } +} + +#if defined(_MSC_VER) +#pragma warning ( default : 4244 ) +#endif + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/vendor/flac/src/metaflac/CMakeLists.txt b/vendor/flac/src/metaflac/CMakeLists.txt new file mode 100644 index 0000000..b8af705 --- /dev/null +++ b/vendor/flac/src/metaflac/CMakeLists.txt @@ -0,0 +1,18 @@ +add_executable(metaflac + main.c + operations.c + operations_shorthand_cuesheet.c + operations_shorthand_picture.c + operations_shorthand_seektable.c + operations_shorthand_streaminfo.c + operations_shorthand_vorbiscomment.c + options.c + usage.c + utils.c + version.rc + $<$:../../include/share/win_utf8_io.h> + $<$:../share/win_utf8_io/win_utf8_io.c>) +target_link_libraries(metaflac FLAC getopt utf8) + +install(TARGETS metaflac EXPORT targets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") diff --git a/vendor/flac/src/metaflac/Makefile.am b/vendor/flac/src/metaflac/Makefile.am new file mode 100644 index 0000000..8c212ff --- /dev/null +++ b/vendor/flac/src/metaflac/Makefile.am @@ -0,0 +1,65 @@ +# metaflac - Command-line FLAC metadata editor +# Copyright (C) 2000-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +if OS_IS_WINDOWS +win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la +if HAVE_WINDRES +metaflac_DEPENDENCIES = version.o +windows_resource_link = -Wl,version.o +endif +endif + +bin_PROGRAMS = metaflac + +AM_CFLAGS = @OGG_CFLAGS@ +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +EXTRA_DIST = \ + CMakeLists.txt \ + version.rc + +metaflac_SOURCES = \ + main.c \ + operations.c \ + operations_shorthand_cuesheet.c \ + operations_shorthand_picture.c \ + operations_shorthand_seektable.c \ + operations_shorthand_streaminfo.c \ + operations_shorthand_vorbiscomment.c \ + options.c \ + usage.c \ + utils.c \ + operations.h \ + operations_shorthand.h \ + options.h \ + usage.h \ + utils.h +metaflac_LDFLAGS = $(AM_LDFLAGS) $(windows_resource_link) + +metaflac_LDADD = \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/share/getopt/libgetopt.la \ + $(top_builddir)/src/share/utf8/libutf8.la \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + $(win_utf8_lib) \ + @LTLIBICONV@ + +CLEANFILES = metaflac.exe + +.rc.o: + $(RC) $(AM_CPPFLAGS) $< $@ diff --git a/vendor/flac/src/metaflac/main.c b/vendor/flac/src/metaflac/main.c new file mode 100644 index 0000000..bb66293 --- /dev/null +++ b/vendor/flac/src/metaflac/main.c @@ -0,0 +1,75 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "operations.h" +#include "options.h" +#include +#include +#include +#include "share/compat.h" + +#ifndef FUZZ_TOOL_METAFLAC +int main(int argc, char *argv[]) +#else +static int main_to_fuzz(int argc, char *argv[]) +#endif +{ + CommandLineOptions options; + int ret = 0; + +#ifdef __EMX__ + _response(&argc, &argv); + _wildcard(&argc, &argv); +#endif +#ifdef _WIN32 + if (get_utf8_argv(&argc, &argv) != 0) { + fputs("ERROR: failed to convert command line parameters to UTF-8\n", stderr); + return 1; + } +#endif + +#ifdef _WIN32 + { + const char *var; + var = getenv("LC_ALL"); + if (!var) + var = getenv("LC_NUMERIC"); + if (!var) + var = getenv("LANG"); + if (!var || strcmp(var, "C") != 0) + setlocale(LC_ALL, ""); + } +#else + setlocale(LC_ALL, ""); +#endif + init_options(&options); + + if ((ret = parse_options(argc, argv, &options)) == 0) + ret = !do_operations(&options); + else + ret = 1; + + free_options(&options); + + return ret; +} diff --git a/vendor/flac/src/metaflac/operations.c b/vendor/flac/src/metaflac/operations.c new file mode 100644 index 0000000..d81d87a --- /dev/null +++ b/vendor/flac/src/metaflac/operations.c @@ -0,0 +1,823 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "operations.h" +#include "usage.h" +#include "utils.h" +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "share/alloc.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include +#include +#include +#include "operations_shorthand.h" + +static void show_version(void); +static FLAC__bool do_major_operation(const CommandLineOptions *options); +static FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options); +static FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options); +static FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options); +static FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options); +static FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options); +static FLAC__bool do_shorthand_operations(const CommandLineOptions *options); +static FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options); +static FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert); +static FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime, FLAC__bool scan); +static FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write); + +static FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number); +static void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application); +static void write_metadata_binary(FLAC__StreamMetadata *block, FLAC__byte *block_raw, FLAC__bool headerless); + +/* from operations_shorthand_seektable.c */ +extern FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write); + +/* from operations_shorthand_streaminfo.c */ +extern FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write); + +/* from operations_shorthand_vorbiscomment.c */ +extern FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw); + +/* from operations_shorthand_cuesheet.c */ +extern FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write); + +/* from operations_shorthand_picture.c */ +extern FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write); + + +FLAC__bool do_operations(const CommandLineOptions *options) +{ + FLAC__bool ok = true; + + if(options->show_long_help) { + long_usage(0); + } + if(options->show_version) { + show_version(); + } + else if(options->args.checks.num_major_ops > 0) { + FLAC__ASSERT(options->args.checks.num_shorthand_ops == 0); + FLAC__ASSERT(options->args.checks.num_major_ops == 1); + FLAC__ASSERT(options->args.checks.num_major_ops == options->ops.num_operations); + ok = do_major_operation(options); + } + else if(options->args.checks.num_shorthand_ops > 0) { + FLAC__ASSERT(options->args.checks.num_shorthand_ops == options->ops.num_operations); + ok = do_shorthand_operations(options); + } + + return ok; +} + +/* + * local routines + */ + +void show_version(void) +{ + printf("metaflac %s\n", FLAC__VERSION_STRING); +} + +FLAC__bool do_major_operation(const CommandLineOptions *options) +{ + unsigned i; + FLAC__bool ok = true; + + /* to die after first error, v--- add '&& ok' here */ + for(i = 0; i < options->num_files; i++) + ok &= do_major_operation_on_file(options->filenames[i], options); + + return ok; +} + +FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options) +{ + FLAC__bool ok = true, needs_write = false, is_ogg = false; + FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new(); + + if(0 == chain) + die("out of memory allocating chain"); + + /*@@@@ lame way of guessing the file type */ + if(strlen(filename) >= 4 && (0 == strcmp(filename+strlen(filename)-4, ".oga") || 0 == strcmp(filename+strlen(filename)-4, ".ogg"))) + is_ogg = true; + + if(! (is_ogg? FLAC__metadata_chain_read_ogg(chain, filename) : FLAC__metadata_chain_read(chain, filename)) ) { + print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename); + FLAC__metadata_chain_delete(chain); + return false; + } + + switch(options->ops.operations[0].type) { + case OP__LIST: + ok = do_major_operation__list(options->prefix_with_filename? filename : 0, chain, options); + break; + case OP__APPEND: + ok = do_major_operation__append(chain, options); + needs_write = true; + break; + case OP__REMOVE: + ok = do_major_operation__remove(chain, options); + needs_write = true; + break; + case OP__REMOVE_ALL: + ok = do_major_operation__remove_all(chain, options); + needs_write = true; + break; + case OP__MERGE_PADDING: + FLAC__metadata_chain_merge_padding(chain); + needs_write = true; + break; + case OP__SORT_PADDING: + FLAC__metadata_chain_sort_padding(chain); + needs_write = true; + break; + default: + FLAC__ASSERT(0); + return false; + } + + if(ok && needs_write) { + if(options->use_padding) + FLAC__metadata_chain_sort_padding(chain); + ok = FLAC__metadata_chain_write(chain, options->use_padding, options->preserve_modtime); + if(!ok) + print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename); + } + + FLAC__metadata_chain_delete(chain); + + return ok; +} + +FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options) +{ + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + FLAC__StreamMetadata *block; + FLAC__bool ok = true; + unsigned block_number; + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + block_number = 0; + do { + block = FLAC__metadata_iterator_get_block(iterator); + ok &= (0 != block); + if(!ok) + flac_fprintf(stderr, "%s: ERROR: couldn't get block from chain\n", filename); + else if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number)) { + if(!options->data_format_is_binary && !options->data_format_is_binary_headerless) + write_metadata(filename, block, block_number, !options->utf8_convert, options->application_data_format_is_hexdump); + else { + FLAC__byte * block_raw = FLAC__metadata_object_get_raw(block); + if(block_raw == 0) { + flac_fprintf(stderr, "%s: ERROR: couldn't get block in raw form\n", filename); + FLAC__metadata_iterator_delete(iterator); + return false; + } + write_metadata_binary(block, block_raw, options->data_format_is_binary_headerless); + free(block_raw); + } + } + block_number++; + } while(ok && FLAC__metadata_iterator_next(iterator)); + + FLAC__metadata_iterator_delete(iterator); + + return ok; +} + +FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options) +{ + FLAC__byte header[FLAC__STREAM_METADATA_HEADER_LENGTH]; + FLAC__byte *buffer; + FLAC__uint32 buffer_size, num_objects = 0, i, append_after = UINT32_MAX; + FLAC__StreamMetadata *object; + FLAC__Metadata_Iterator *iterator = 0; + FLAC__bool has_vorbiscomment = false; + + /* First, find out after which block appending should take place */ + for(i = 0; i < options->args.num_arguments; i++) { + if(options->args.arguments[i].type == ARG__BLOCK_NUMBER) { + if(append_after != UINT32_MAX || options->args.arguments[i].value.block_number.num_entries > 1) { + flac_fprintf(stderr, "ERROR: more than one block number specified with --append\n"); + return false; + } + append_after = options->args.arguments[i].value.block_number.entries[0]; + } + } + + iterator = FLAC__metadata_iterator_new(); + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + /* Find out whether there is already a vorbis comment block present */ + do { + FLAC__MetadataType type = FLAC__metadata_iterator_get_block_type(iterator); + if(type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + has_vorbiscomment = true; + } + while(FLAC__metadata_iterator_next(iterator)); + + /* Reset iterator */ + FLAC__metadata_iterator_init(iterator, chain); + + /* Go to requested block */ + for(i = 0; i < append_after; i++) { + if(!FLAC__metadata_iterator_next(iterator)) + break; + } + +#ifdef _WIN32 + _setmode(fileno(stdin),_O_BINARY); +#endif + + /* Read header from stdin */ + while(fread(header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, stdin) == FLAC__STREAM_METADATA_HEADER_LENGTH) { + + buffer_size = ((FLAC__uint32)(header[1]) << 16) + ((FLAC__uint32)(header[2]) << 8) + header[3]; + buffer = safe_malloc_(buffer_size + FLAC__STREAM_METADATA_HEADER_LENGTH); + if(0 == buffer) + die("out of memory allocating read buffer"); + memcpy(buffer, header, FLAC__STREAM_METADATA_HEADER_LENGTH); + + num_objects++; + + if(fread(buffer+FLAC__STREAM_METADATA_HEADER_LENGTH, 1, buffer_size, stdin) < buffer_size) { + flac_fprintf(stderr, "ERROR: couldn't read metadata block #%u from stdin\n",(num_objects)); + free(buffer); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + if((object = FLAC__metadata_object_set_raw(buffer, buffer_size + FLAC__STREAM_METADATA_HEADER_LENGTH)) == NULL) { + flac_fprintf(stderr, "ERROR: couldn't parse supplied metadata block #%u\n",(num_objects)); + free(buffer); + FLAC__metadata_iterator_delete(iterator); + return false; + } + free(buffer); + + if(has_vorbiscomment && object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + flac_fprintf(stderr, "ERROR: can't add another vorbis comment block to file, it already has one\n"); + FLAC__metadata_object_delete(object); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + + if(object->type == FLAC__METADATA_TYPE_STREAMINFO) { + flac_fprintf(stderr, "ERROR: can't add streaminfo to file\n"); + FLAC__metadata_object_delete(object); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + if(object->type == FLAC__METADATA_TYPE_SEEKTABLE) { + flac_fprintf(stderr, "ERROR: can't add seektable to file, please use --add-seekpoint instead\n"); + FLAC__metadata_object_delete(object); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + if(!FLAC__metadata_iterator_insert_block_after(iterator, object)) { + flac_fprintf(stderr, "ERROR: couldn't add supplied metadata block #%u to file\n",(num_objects)); + FLAC__metadata_object_delete(object); + FLAC__metadata_iterator_delete(iterator); + return false; + } + /* Now check whether what type of block was added */ + { + FLAC__MetadataType type = FLAC__metadata_iterator_get_block_type(iterator); + if(type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + has_vorbiscomment = true; + } + } + +#ifdef _WIN32 + _setmode(fileno(stdin),_O_TEXT); +#endif + + if(num_objects == 0) + flac_fprintf(stderr, "ERROR: unable to find a metadata block in the supplied input\n"); + + FLAC__metadata_iterator_delete(iterator); + + return true; +} + +FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options) +{ + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + FLAC__bool ok = true; + unsigned block_number; + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + block_number = 0; + while(ok && FLAC__metadata_iterator_next(iterator)) { + block_number++; + if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number)) { + ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding); + if(options->use_padding) + ok &= FLAC__metadata_iterator_next(iterator); + } + } + + FLAC__metadata_iterator_delete(iterator); + + return ok; +} + +FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options) +{ + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + FLAC__bool ok = true; + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + while(ok && FLAC__metadata_iterator_next(iterator)) { + ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding); + if(options->use_padding) + ok &= FLAC__metadata_iterator_next(iterator); + } + + FLAC__metadata_iterator_delete(iterator); + + return ok; +} + +FLAC__bool do_shorthand_operations(const CommandLineOptions *options) +{ + unsigned i; + FLAC__bool ok = true; + + /* to die after first error, v--- add '&& ok' here */ + for(i = 0; i < options->num_files; i++) + ok &= do_shorthand_operations_on_file(options->filenames[i], options); + + /* check if OP__ADD_REPLAY_GAIN requested */ + if(ok && options->num_files > 0) { + for(i = 0; i < options->ops.num_operations; i++) { + if(options->ops.operations[i].type == OP__ADD_REPLAY_GAIN) + ok = do_shorthand_operation__add_replay_gain(options->filenames, options->num_files, options->preserve_modtime, false); + else if(options->ops.operations[i].type == OP__SCAN_REPLAY_GAIN) + ok = do_shorthand_operation__add_replay_gain(options->filenames, options->num_files, options->preserve_modtime, true); + } + } + + return ok; +} + +FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options) +{ + unsigned i; + FLAC__bool ok = true, needs_write = false, use_padding = options->use_padding; + FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new(); + + if(0 == chain) + die("out of memory allocating chain"); + + if(!FLAC__metadata_chain_read(chain, filename)) { + print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename); + ok = false; + goto cleanup; + } + + for(i = 0; i < options->ops.num_operations && ok; i++) { + /* + * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both + * --add-seekpoint and --import-cuesheet-from are used. + */ + if(options->ops.operations[i].type != OP__ADD_SEEKPOINT) + ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert); + + /* The following seems counterintuitive but the meaning + * of 'use_padding' is 'try to keep the overall metadata + * to its original size, adding or truncating extra + * padding if necessary' which is why we need to turn it + * off in this case. If we don't, the extra padding block + * will just be truncated. + */ + if(options->ops.operations[i].type == OP__ADD_PADDING) + use_padding = false; + } + + /* + * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both + * --add-seekpoint and --import-cuesheet-from are used. + */ + for(i = 0; i < options->ops.num_operations && ok; i++) { + if(options->ops.operations[i].type == OP__ADD_SEEKPOINT) + ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert); + } + + if(ok && needs_write) { + if(use_padding) + FLAC__metadata_chain_sort_padding(chain); + ok = FLAC__metadata_chain_write(chain, use_padding, options->preserve_modtime); + if(!ok) + print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename); + } + + cleanup : + FLAC__metadata_chain_delete(chain); + + return ok; +} + +FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert) +{ + FLAC__bool ok = true; + + switch(operation->type) { + case OP__SHOW_MD5SUM: + case OP__SHOW_MIN_BLOCKSIZE: + case OP__SHOW_MAX_BLOCKSIZE: + case OP__SHOW_MIN_FRAMESIZE: + case OP__SHOW_MAX_FRAMESIZE: + case OP__SHOW_SAMPLE_RATE: + case OP__SHOW_CHANNELS: + case OP__SHOW_BPS: + case OP__SHOW_TOTAL_SAMPLES: + case OP__SET_MD5SUM: + case OP__SET_MIN_BLOCKSIZE: + case OP__SET_MAX_BLOCKSIZE: + case OP__SET_MIN_FRAMESIZE: + case OP__SET_MAX_FRAMESIZE: + case OP__SET_SAMPLE_RATE: + case OP__SET_CHANNELS: + case OP__SET_BPS: + case OP__SET_TOTAL_SAMPLES: + ok = do_shorthand_operation__streaminfo(filename, prefix_with_filename, chain, operation, needs_write); + break; + case OP__SHOW_VC_VENDOR: + case OP__SHOW_VC_FIELD: + case OP__REMOVE_VC_ALL: + case OP__REMOVE_VC_ALL_EXCEPT: + case OP__REMOVE_VC_FIELD: + case OP__REMOVE_VC_FIRSTFIELD: + case OP__SET_VC_FIELD: + case OP__IMPORT_VC_FROM: + case OP__EXPORT_VC_TO: + ok = do_shorthand_operation__vorbis_comment(filename, prefix_with_filename, chain, operation, needs_write, !utf8_convert); + break; + case OP__IMPORT_CUESHEET_FROM: + case OP__EXPORT_CUESHEET_TO: + ok = do_shorthand_operation__cuesheet(filename, chain, operation, needs_write); + break; + case OP__IMPORT_PICTURE_FROM: + case OP__EXPORT_PICTURE_TO: + ok = do_shorthand_operation__picture(filename, chain, operation, needs_write); + break; + case OP__ADD_SEEKPOINT: + ok = do_shorthand_operation__add_seekpoints(filename, chain, operation->argument.add_seekpoint.specification, needs_write); + break; + case OP__ADD_REPLAY_GAIN: + case OP__SCAN_REPLAY_GAIN: + /* these commands are always executed last */ + ok = true; + break; + case OP__ADD_PADDING: + ok = do_shorthand_operation__add_padding(filename, chain, operation->argument.add_padding.length, needs_write); + break; + default: + ok = false; + FLAC__ASSERT(0); + break; + }; + + return ok; +} + +FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime, FLAC__bool scan) +{ + FLAC__StreamMetadata streaminfo; + float *title_gains = 0, *title_peaks = 0; + float album_gain, album_peak; + unsigned sample_rate = 0; + unsigned bits_per_sample = 0; + unsigned channels = 0; + unsigned i; + const char *error; + FLAC__bool first = true; + + FLAC__ASSERT(num_files > 0); + + for(i = 0; i < num_files; i++) { + FLAC__ASSERT(0 != filenames[i]); + if(!FLAC__metadata_get_streaminfo(filenames[i], &streaminfo)) { + flac_fprintf(stderr, "%s: ERROR: can't open file or get STREAMINFO block\n", filenames[i]); + return false; + } + if(first) { + first = false; + sample_rate = streaminfo.data.stream_info.sample_rate; + bits_per_sample = streaminfo.data.stream_info.bits_per_sample; + channels = streaminfo.data.stream_info.channels; + } + else { + if(sample_rate != streaminfo.data.stream_info.sample_rate) { + flac_fprintf(stderr, "%s: ERROR: sample rate of %u Hz does not match previous files' %u Hz\n", filenames[i], streaminfo.data.stream_info.sample_rate, sample_rate); + return false; + } + if(bits_per_sample != streaminfo.data.stream_info.bits_per_sample) { + flac_fprintf(stderr, "%s: ERROR: resolution of %u bps does not match previous files' %u bps\n", filenames[i], streaminfo.data.stream_info.bits_per_sample, bits_per_sample); + return false; + } + if(channels != streaminfo.data.stream_info.channels) { + flac_fprintf(stderr, "%s: ERROR: # channels (%u) does not match previous files' (%u)\n", filenames[i], streaminfo.data.stream_info.channels, channels); + return false; + } + } + if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) { + flac_fprintf(stderr, "%s: ERROR: sample rate of %u Hz is not supported\n", filenames[i], sample_rate); + return false; + } + if(channels != 1 && channels != 2) { + flac_fprintf(stderr, "%s: ERROR: # of channels (%u) is not supported, must be 1 or 2\n", filenames[i], channels); + return false; + } + if(bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || bits_per_sample > FLAC__MAX_BITS_PER_SAMPLE) { + flac_fprintf(stderr, "%s: ERROR: resolution (%u) is not supported, must be between %u and %u\n", filenames[i], bits_per_sample, FLAC__MIN_BITS_PER_SAMPLE, FLAC__MAX_BITS_PER_SAMPLE); + return false; + } + } + + if(!grabbag__replaygain_init(sample_rate)) { + FLAC__ASSERT(0); + /* double protection */ + flac_fprintf(stderr, "internal error\n"); + return false; + } + + if( + 0 == (title_gains = safe_malloc_mul_2op_(sizeof(float), /*times*/num_files)) || + 0 == (title_peaks = safe_malloc_mul_2op_(sizeof(float), /*times*/num_files)) + ) + die("out of memory allocating space for title gains/peaks"); + + for(i = 0; i < num_files; i++) { + if(0 != (error = grabbag__replaygain_analyze_file(filenames[i], title_gains+i, title_peaks+i))) { + flac_fprintf(stderr, "%s: ERROR: during analysis (%s)\n", filenames[i], error); + free(title_gains); + free(title_peaks); + return false; + } + } + grabbag__replaygain_get_album(&album_gain, &album_peak); + + for(i = 0; i < num_files; i++) { + if(!scan) { + if(0 != (error = grabbag__replaygain_store_to_file(filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i], preserve_modtime))) { + flac_fprintf(stderr, "%s: ERROR: writing tags (%s)\n", filenames[i], error); + free(title_gains); + free(title_peaks); + return false; + } + } else { + flac_fprintf(stdout, "%s: %f %f %f %f\n", filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i]); + } + } + + free(title_gains); + free(title_peaks); + return true; +} + +FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write) +{ + FLAC__StreamMetadata *padding = 0; + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + while(FLAC__metadata_iterator_next(iterator)) + ; + + padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); + if(0 == padding) + die("out of memory allocating PADDING block"); + + padding->length = length; + + if(!FLAC__metadata_iterator_insert_block_after(iterator, padding)) { + print_error_with_chain_status(chain, "%s: ERROR: adding new PADDING block to metadata", filename); + FLAC__metadata_object_delete(padding); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + FLAC__metadata_iterator_delete(iterator); + *needs_write = true; + return true; +} + +FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number) +{ + unsigned i, j; + FLAC__bool matches_number = false, matches_type = false; + FLAC__bool has_block_number_arg = false; + + for(i = 0; i < options->args.num_arguments; i++) { + if(options->args.arguments[i].type == ARG__BLOCK_TYPE || options->args.arguments[i].type == ARG__EXCEPT_BLOCK_TYPE) { + for(j = 0; j < options->args.arguments[i].value.block_type.num_entries; j++) { + if(options->args.arguments[i].value.block_type.entries[j].type == block->type) { + if(block->type != FLAC__METADATA_TYPE_APPLICATION || !options->args.arguments[i].value.block_type.entries[j].filter_application_by_id || 0 == memcmp(options->args.arguments[i].value.block_type.entries[j].application_id, block->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) + matches_type = true; + } + } + } + else if(options->args.arguments[i].type == ARG__BLOCK_NUMBER) { + has_block_number_arg = true; + for(j = 0; j < options->args.arguments[i].value.block_number.num_entries; j++) { + if(options->args.arguments[i].value.block_number.entries[j] == block_number) + matches_number = true; + } + } + } + + if(!has_block_number_arg) + matches_number = true; + + if(options->args.checks.has_block_type) { + FLAC__ASSERT(!options->args.checks.has_except_block_type); + } + else if(options->args.checks.has_except_block_type) + matches_type = !matches_type; + else + matches_type = true; + + return matches_number && matches_type; +} + +void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application) +{ + unsigned i, j; + +/*@@@ yuck, should do this with a varargs function or something: */ +#define PPR if(filename) { if(raw) printf("%s:",filename); else flac_printf("%s:",filename); } + PPR; printf("METADATA block #%u\n", block_number); + PPR; printf(" type: %u (%s)\n", (unsigned)block->type, block->type < FLAC__METADATA_TYPE_UNDEFINED? FLAC__MetadataTypeString[block->type] : "UNKNOWN"); + PPR; printf(" is last: %s\n", block->is_last? "true":"false"); + PPR; printf(" length: %u\n", block->length); + + switch(block->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + PPR; printf(" minimum blocksize: %u samples\n", block->data.stream_info.min_blocksize); + PPR; printf(" maximum blocksize: %u samples\n", block->data.stream_info.max_blocksize); + PPR; printf(" minimum framesize: %u bytes\n", block->data.stream_info.min_framesize); + PPR; printf(" maximum framesize: %u bytes\n", block->data.stream_info.max_framesize); + PPR; printf(" sample_rate: %u Hz\n", block->data.stream_info.sample_rate); + PPR; printf(" channels: %u\n", block->data.stream_info.channels); + PPR; printf(" bits-per-sample: %u\n", block->data.stream_info.bits_per_sample); + PPR; printf(" total samples: %" PRIu64 "\n", block->data.stream_info.total_samples); + PPR; printf(" MD5 signature: "); + for(i = 0; i < 16; i++) { + printf("%02x", (unsigned)block->data.stream_info.md5sum[i]); + } + printf("\n"); + break; + case FLAC__METADATA_TYPE_PADDING: + /* nothing to print */ + break; + case FLAC__METADATA_TYPE_APPLICATION: + PPR; printf(" application ID: "); + for(i = 0; i < 4; i++) + printf("%02x", block->data.application.id[i]); + printf("\n"); + PPR; printf(" data contents:\n"); + if(0 != block->data.application.data) { + if(hexdump_application) + hexdump(filename, block->data.application.data, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, " "); + else + (void) local_fwrite(block->data.application.data, 1, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, stdout); + } + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + PPR; printf(" seek points: %u\n", block->data.seek_table.num_points); + for(i = 0; i < block->data.seek_table.num_points; i++) { + if(block->data.seek_table.points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) { + PPR; printf(" point %u: sample_number=%" PRIu64 ", stream_offset=%" PRIu64 ", frame_samples=%u\n", i, block->data.seek_table.points[i].sample_number, block->data.seek_table.points[i].stream_offset, block->data.seek_table.points[i].frame_samples); + } + else { + PPR; printf(" point %u: PLACEHOLDER\n", i); + } + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + PPR; printf(" vendor string: "); + write_vc_field(0, &block->data.vorbis_comment.vendor_string, raw, stdout); + PPR; printf(" comments: %u\n", block->data.vorbis_comment.num_comments); + for(i = 0; i < block->data.vorbis_comment.num_comments; i++) { + PPR; printf(" comment[%u]: ", i); + write_vc_field(0, &block->data.vorbis_comment.comments[i], raw, stdout); + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + PPR; printf(" media catalog number: %s\n", block->data.cue_sheet.media_catalog_number); + PPR; printf(" lead-in: %" PRIu64 "\n", block->data.cue_sheet.lead_in); + PPR; printf(" is CD: %s\n", block->data.cue_sheet.is_cd? "true":"false"); + PPR; printf(" number of tracks: %u\n", block->data.cue_sheet.num_tracks); + for(i = 0; i < block->data.cue_sheet.num_tracks; i++) { + const FLAC__StreamMetadata_CueSheet_Track *track = block->data.cue_sheet.tracks+i; + const FLAC__bool is_last = (i == block->data.cue_sheet.num_tracks-1); + const FLAC__bool is_leadout = is_last && track->num_indices == 0; + PPR; printf(" track[%u]\n", i); + PPR; printf(" offset: %" PRIu64 "\n", track->offset); + if(is_last) { + PPR; printf(" number: %u (%s)\n", (unsigned)track->number, is_leadout? "LEAD-OUT" : "INVALID"); + } + else { + PPR; printf(" number: %u\n", (unsigned)track->number); + } + if(!is_leadout) { + PPR; printf(" ISRC: %s\n", track->isrc); + PPR; printf(" type: %s\n", track->type == 1? "DATA" : "AUDIO"); + PPR; printf(" pre-emphasis: %s\n", track->pre_emphasis? "true":"false"); + PPR; printf(" number of index points: %u\n", track->num_indices); + for(j = 0; j < track->num_indices; j++) { + const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices+j; + PPR; printf(" index[%u]\n", j); + PPR; printf(" offset: %" PRIu64 "\n", indx->offset); + PPR; printf(" number: %u\n", (unsigned)indx->number); + } + } + } + break; + case FLAC__METADATA_TYPE_PICTURE: + PPR; printf(" type: %u (%s)\n", block->data.picture.type, block->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED? FLAC__StreamMetadata_Picture_TypeString[block->data.picture.type] : "UNDEFINED"); + PPR; printf(" MIME type: %s\n", block->data.picture.mime_type); + PPR; printf(" description: %s\n", block->data.picture.description); + PPR; printf(" width: %u\n", (unsigned)block->data.picture.width); + PPR; printf(" height: %u\n", (unsigned)block->data.picture.height); + PPR; printf(" depth: %u\n", (unsigned)block->data.picture.depth); + PPR; printf(" colors: %u%s\n", (unsigned)block->data.picture.colors, block->data.picture.colors? "" : " (unindexed)"); + PPR; printf(" data length: %u\n", (unsigned)block->data.picture.data_length); + PPR; printf(" data:\n"); + if(0 != block->data.picture.data) + hexdump(filename, block->data.picture.data, block->data.picture.data_length, " "); + break; + default: + PPR; printf(" data contents:\n"); + if(0 != block->data.unknown.data) + hexdump(filename, block->data.unknown.data, block->length, " "); + break; + } +#undef PPR +} + +void write_metadata_binary(FLAC__StreamMetadata *block, FLAC__byte *block_raw, FLAC__bool headerless) +{ +#ifdef _WIN32 + fflush(stdout); + _setmode(fileno(stdout),_O_BINARY); +#endif + if(!headerless) + local_fwrite(block_raw, 1, block->length+FLAC__STREAM_METADATA_HEADER_LENGTH, stdout); + else if(block->type == FLAC__METADATA_TYPE_APPLICATION && block->length > 3) + local_fwrite(block_raw+FLAC__STREAM_METADATA_HEADER_LENGTH+4, 1, block->length-4, stdout); + else + local_fwrite(block_raw+FLAC__STREAM_METADATA_HEADER_LENGTH, 1, block->length, stdout); +#ifdef _WIN32 + fflush(stdout); + _setmode(fileno(stdout),_O_TEXT); +#endif +} diff --git a/vendor/flac/src/metaflac/operations.h b/vendor/flac/src/metaflac/operations.h new file mode 100644 index 0000000..79e1c3b --- /dev/null +++ b/vendor/flac/src/metaflac/operations.h @@ -0,0 +1,27 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef metaflac__operations_h +#define metaflac__operations_h + +#include "options.h" + +FLAC__bool do_operations(const CommandLineOptions *options); + +#endif diff --git a/vendor/flac/src/metaflac/operations_shorthand.h b/vendor/flac/src/metaflac/operations_shorthand.h new file mode 100644 index 0000000..1877c26 --- /dev/null +++ b/vendor/flac/src/metaflac/operations_shorthand.h @@ -0,0 +1,26 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "options.h" + +FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write); +FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write); +FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write); +FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write); +FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw); diff --git a/vendor/flac/src/metaflac/operations_shorthand_cuesheet.c b/vendor/flac/src/metaflac/operations_shorthand_cuesheet.c new file mode 100644 index 0000000..13c4ded --- /dev/null +++ b/vendor/flac/src/metaflac/operations_shorthand_cuesheet.c @@ -0,0 +1,226 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "options.h" +#include "utils.h" +#include "FLAC/assert.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "operations_shorthand.h" + +static FLAC__bool import_cs_from(const char *filename, FLAC__StreamMetadata **cuesheet, const char *cs_filename, FLAC__bool *needs_write, FLAC__uint64 lead_out_offset, unsigned sample_rate, FLAC__bool is_cdda, Argument_AddSeekpoint *add_seekpoint_link); +static FLAC__bool export_cs_to(const char *filename, const FLAC__StreamMetadata *cuesheet, const char *cs_filename); + +FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write) +{ + FLAC__bool ok = true; + FLAC__StreamMetadata *cuesheet = 0; + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + FLAC__uint64 lead_out_offset = 0; + FLAC__bool is_cdda = false; + unsigned sample_rate = 0; + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + do { + FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator); + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) { + lead_out_offset = block->data.stream_info.total_samples; + if(lead_out_offset == 0) { + flac_fprintf(stderr, "%s: ERROR: FLAC file must have total_samples set in STREAMINFO in order to import/export cuesheet\n", filename); + FLAC__metadata_iterator_delete(iterator); + return false; + } + sample_rate = block->data.stream_info.sample_rate; + is_cdda = (block->data.stream_info.channels == 1 || block->data.stream_info.channels == 2) && (block->data.stream_info.bits_per_sample == 16) && (sample_rate == 44100); + } + else if(block->type == FLAC__METADATA_TYPE_CUESHEET) + cuesheet = block; + } while(FLAC__metadata_iterator_next(iterator)); + + if(lead_out_offset == 0) { + flac_fprintf(stderr, "%s: ERROR: FLAC stream has no STREAMINFO block\n", filename); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + if(sample_rate == 0) { + flac_fprintf(stderr, "%s: ERROR: cannot parse cuesheet when sample rate is unknown\n", filename); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + switch(operation->type) { + case OP__IMPORT_CUESHEET_FROM: + if(0 != cuesheet) { + flac_fprintf(stderr, "%s: ERROR: FLAC file already has CUESHEET block\n", filename); + ok = false; + } + else { + ok = import_cs_from(filename, &cuesheet, operation->argument.import_cuesheet_from.filename, needs_write, lead_out_offset, sample_rate, is_cdda, operation->argument.import_cuesheet_from.add_seekpoint_link); + if(ok) { + /* append CUESHEET block */ + while(FLAC__metadata_iterator_next(iterator)) + ; + if(!FLAC__metadata_iterator_insert_block_after(iterator, cuesheet)) { + print_error_with_chain_status(chain, "%s: ERROR: adding new CUESHEET block to metadata", filename); + FLAC__metadata_object_delete(cuesheet); + ok = false; + } + } + } + break; + case OP__EXPORT_CUESHEET_TO: + if(0 == cuesheet) { + flac_fprintf(stderr, "%s: ERROR: FLAC file has no CUESHEET block\n", filename); + ok = false; + } + else + ok = export_cs_to(filename, cuesheet, operation->argument.filename.value); + break; + default: + ok = false; + FLAC__ASSERT(0); + break; + }; + + FLAC__metadata_iterator_delete(iterator); + return ok; +} + +/* + * local routines + */ + +FLAC__bool import_cs_from(const char *filename, FLAC__StreamMetadata **cuesheet, const char *cs_filename, FLAC__bool *needs_write, FLAC__uint64 lead_out_offset, unsigned sample_rate, FLAC__bool is_cdda, Argument_AddSeekpoint *add_seekpoint_link) +{ + FILE *f; + const char *error_message; + char **seekpoint_specification = add_seekpoint_link? &(add_seekpoint_link->specification) : 0; + unsigned last_line_read; + + if(0 == cs_filename || strlen(cs_filename) == 0) { + flac_fprintf(stderr, "%s: ERROR: empty import file name\n", filename); + return false; + } + if(0 == strcmp(cs_filename, "-")) + f = stdin; + else + f = flac_fopen(cs_filename, "r"); + + if(0 == f) { + flac_fprintf(stderr, "%s: ERROR: can't open import file %s: %s\n", filename, cs_filename, strerror(errno)); + return false; + } + + *cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset); + + if(f != stdin) + fclose(f); + + if(0 == *cuesheet) { + flac_fprintf(stderr, "%s: ERROR: while parsing cuesheet \"%s\" on line %u: %s\n", filename, cs_filename, last_line_read, error_message); + return false; + } + + if(!FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/false, &error_message)) { + flac_fprintf(stderr, "%s: ERROR parsing cuesheet \"%s\": %s\n", filename, cs_filename, error_message); + FLAC__metadata_object_delete(*cuesheet); + return false; + } + + /* if we're expecting CDDA, warn about non-compliance */ + if(is_cdda && !FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/true, &error_message)) { + flac_fprintf(stderr, "%s: WARNING cuesheet \"%s\" is not audio CD compliant: %s\n", filename, cs_filename, error_message); + (*cuesheet)->data.cue_sheet.is_cd = false; + } + + /* add seekpoints for each index point if required */ + if(0 != seekpoint_specification) { + char spec[128]; + unsigned track, indx; + const FLAC__StreamMetadata_CueSheet *cs = &(*cuesheet)->data.cue_sheet; + if(0 == *seekpoint_specification) + *seekpoint_specification = local_strdup(""); + for(track = 0; track < cs->num_tracks; track++) { + const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+track; + for(indx = 0; indx < tr->num_indices; indx++) { + flac_snprintf(spec, sizeof (spec), "%" PRIu64 ";", (tr->offset + tr->indices[indx].offset)); + local_strcat(seekpoint_specification, spec); + } + } + } + + *needs_write = true; + return true; +} + +FLAC__bool export_cs_to(const char *filename, const FLAC__StreamMetadata *cuesheet, const char *cs_filename) +{ + FILE *f; + char *ref = 0; + size_t reflen; + + if(0 == cs_filename || strlen(cs_filename) == 0) { + flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename); + return false; + } + if(0 == strcmp(cs_filename, "-")) + f = stdout; + else + f = flac_fopen(cs_filename, "w"); + + if(0 == f) { + flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, cs_filename, strerror(errno)); + return false; + } + + reflen = strlen(filename) + 7 + 1; + if(0 == (ref = malloc(reflen))) { + flac_fprintf(stderr, "%s: ERROR: allocating memory\n", filename); + if(f != stdout) + fclose(f); + return false; + } + + flac_snprintf(ref, reflen, "\"%s\" FLAC", filename); + + grabbag__cuesheet_emit(f, cuesheet, ref); + + free(ref); + + if(f != stdout) + fclose(f); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Delete output file when fuzzing */ + if(f != stdout) + flac_unlink(cs_filename); +#endif + + return true; +} diff --git a/vendor/flac/src/metaflac/operations_shorthand_picture.c b/vendor/flac/src/metaflac/operations_shorthand_picture.c new file mode 100644 index 0000000..6bb459b --- /dev/null +++ b/vendor/flac/src/metaflac/operations_shorthand_picture.c @@ -0,0 +1,184 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "options.h" +#include "utils.h" +#include "FLAC/assert.h" +#include "share/grabbag.h" /* for grabbag__picture_parse_specification() etc */ + +#include "operations_shorthand.h" + +static FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write); +static FLAC__bool export_pic_to(const char *filename, const FLAC__StreamMetadata *picture, const char *pic_filename); + +FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write) +{ + FLAC__bool ok = true, has_type1 = false, has_type2 = false; + FLAC__StreamMetadata *picture = 0; + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + switch(operation->type) { + case OP__IMPORT_PICTURE_FROM: + ok = import_pic_from(filename, &picture, operation->argument.specification.value, needs_write); + if(ok) { + /* append PICTURE block */ + while(FLAC__metadata_iterator_next(iterator)) + ; + if(!FLAC__metadata_iterator_insert_block_after(iterator, picture)) { + print_error_with_chain_status(chain, "%s: ERROR: adding new PICTURE block to metadata", filename); + FLAC__metadata_object_delete(picture); + ok = false; + } + } + if(ok) { + /* check global PICTURE constraints (max 1 block each of type=1 and type=2) */ + while(FLAC__metadata_iterator_prev(iterator)) + ; + do { + FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator); + if(block->type == FLAC__METADATA_TYPE_PICTURE) { + if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) { + if(has_type1) { + print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one 32x32 standard icon (type=1) PICTURE block", filename); + ok = false; + } + has_type1 = true; + } + else if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) { + if(has_type2) { + print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one icon (type=2) PICTURE block", filename); + ok = false; + } + has_type2 = true; + } + } + } while(FLAC__metadata_iterator_next(iterator)); + } + break; + case OP__EXPORT_PICTURE_TO: + { + const Argument_BlockNumber *a = operation->argument.export_picture_to.block_number_link; + int block_number = (a && a->num_entries > 0)? (int)a->entries[0] : -1; + unsigned i = 0; + do { + FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator); + if(block->type == FLAC__METADATA_TYPE_PICTURE && (block_number < 0 || i == (unsigned)block_number)) + picture = block; + i++; + } while(FLAC__metadata_iterator_next(iterator) && 0 == picture); + if(0 == picture) { + if(block_number < 0) + flac_fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block\n", filename); + else + flac_fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block at block #%d\n", filename, block_number); + ok = false; + } + else + ok = export_pic_to(filename, picture, operation->argument.filename.value); + } + break; + default: + ok = false; + FLAC__ASSERT(0); + break; + }; + + FLAC__metadata_iterator_delete(iterator); + return ok; +} + +/* + * local routines + */ + +FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write) +{ + const char *error_message; + + if(0 == specification || strlen(specification) == 0) { + flac_fprintf(stderr, "%s: ERROR: empty picture specification\n", filename); + return false; + } + + *picture = grabbag__picture_parse_specification(specification, &error_message); + + if(0 == *picture) { + flac_fprintf(stderr, "%s: ERROR: while parsing picture specification \"%s\": %s\n", filename, specification, error_message); + return false; + } + + if(!FLAC__format_picture_is_legal(&(*picture)->data.picture, &error_message)) { + flac_fprintf(stderr, "%s: ERROR: new PICTURE block for \"%s\" is illegal: %s\n", filename, specification, error_message); + FLAC__metadata_object_delete(*picture); + *picture = 0; + return false; + } + + *needs_write = true; + return true; +} + +FLAC__bool export_pic_to(const char *filename, const FLAC__StreamMetadata *picture, const char *pic_filename) +{ + FILE *f; + const FLAC__uint32 len = picture->data.picture.data_length; + + if(0 == pic_filename || strlen(pic_filename) == 0) { + flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename); + return false; + } + if(0 == strcmp(pic_filename, "-")) + f = grabbag__file_get_binary_stdout(); + else + f = flac_fopen(pic_filename, "wb"); + + if(0 == f) { + flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, pic_filename, strerror(errno)); + return false; + } + + if(fwrite(picture->data.picture.data, 1, len, f) != len) { + flac_fprintf(stderr, "%s: ERROR: writing PICTURE data to file\n", filename); + if(f != stdout) + fclose(f); + return false; + } + + if(f != stdout) + fclose(f); + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Delete output file when fuzzing */ + if(f != stdout) + flac_unlink(pic_filename); +#endif + + return true; +} diff --git a/vendor/flac/src/metaflac/operations_shorthand_seektable.c b/vendor/flac/src/metaflac/operations_shorthand_seektable.c new file mode 100644 index 0000000..c9175b3 --- /dev/null +++ b/vendor/flac/src/metaflac/operations_shorthand_seektable.c @@ -0,0 +1,220 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "utils.h" +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "FLAC/metadata.h" +#include "share/grabbag.h" +#include "operations_shorthand.h" + +static FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write); + +FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write) +{ + FLAC__bool ok = true, found_seektable_block = false; + FLAC__StreamMetadata *block = 0; + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + FLAC__uint64 total_samples = 0; + unsigned sample_rate = 0; + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + do { + block = FLAC__metadata_iterator_get_block(iterator); + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) { + sample_rate = block->data.stream_info.sample_rate; + total_samples = block->data.stream_info.total_samples; + } + else if(block->type == FLAC__METADATA_TYPE_SEEKTABLE) + found_seektable_block = true; + } while(!found_seektable_block && FLAC__metadata_iterator_next(iterator)); + + if(total_samples == 0) { + flac_fprintf(stderr, "%s: ERROR: cannot add seekpoints because STREAMINFO block does not specify total_samples\n", filename); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + if(!found_seektable_block) { + /* create a new block */ + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE); + if(0 == block) + die("out of memory allocating SEEKTABLE block"); + while(FLAC__metadata_iterator_prev(iterator)) + ; + if(!FLAC__metadata_iterator_insert_block_after(iterator, block)) { + print_error_with_chain_status(chain, "%s: ERROR: adding new SEEKTABLE block to metadata", filename); + FLAC__metadata_object_delete(block); + FLAC__metadata_iterator_delete(iterator); + return false; + } + /* iterator is left pointing to new block */ + FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == block); + } + + FLAC__metadata_iterator_delete(iterator); + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if(!grabbag__seektable_convert_specification_to_template(specification, /*only_explicit_placeholders=*/false, total_samples, sample_rate, block, /*spec_has_real_points=*/0)) { + flac_fprintf(stderr, "%s: ERROR (internal) preparing seektable with seekpoints\n", filename); + return false; + } + + ok = populate_seekpoint_values(filename, block, needs_write); + + if(ok) + (void) FLAC__format_seektable_sort(&block->data.seek_table); + + return ok; +} + +/* + * local routines + */ + +typedef struct { + FLAC__StreamMetadata_SeekTable *seektable_template; + FLAC__uint64 samples_written; + FLAC__uint64 audio_offset, last_offset; + unsigned first_seekpoint_to_check; + FLAC__bool error_occurred; + FLAC__StreamDecoderErrorStatus error_status; +} ClientData; + +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + ClientData *cd = (ClientData*)client_data; + + (void)buffer; + FLAC__ASSERT(0 != cd); + + if(!cd->error_occurred) { + const unsigned blocksize = frame->header.blocksize; + const FLAC__uint64 frame_first_sample = cd->samples_written; + const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1; + FLAC__uint64 test_sample; + unsigned i; + for(i = cd->first_seekpoint_to_check; i < cd->seektable_template->num_points; i++) { + test_sample = cd->seektable_template->points[i].sample_number; + if(test_sample > frame_last_sample) { + break; + } + else if(test_sample >= frame_first_sample) { + cd->seektable_template->points[i].sample_number = frame_first_sample; + cd->seektable_template->points[i].stream_offset = cd->last_offset - cd->audio_offset; + cd->seektable_template->points[i].frame_samples = blocksize; + cd->first_seekpoint_to_check++; + /* DO NOT: "break;" and here's why: + * The seektable template may contain more than one target + * sample for any given frame; we will keep looping, generating + * duplicate seekpoints for them, and we'll clean it up later, + * just before writing the seektable back to the metadata. + */ + } + else { + cd->first_seekpoint_to_check++; + } + } + cd->samples_written += blocksize; + if(!FLAC__stream_decoder_get_decode_position(decoder, &cd->last_offset)) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; +} + +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + ClientData *cd = (ClientData*)client_data; + + (void)decoder; + FLAC__ASSERT(0 != cd); + + if(!cd->error_occurred) { /* don't let multiple errors overwrite the first one */ + cd->error_occurred = true; + cd->error_status = status; + } +} + +FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write) +{ + FLAC__StreamDecoder *decoder; + ClientData client_data; + FLAC__bool ok = true; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE); + + client_data.seektable_template = &block->data.seek_table; + client_data.samples_written = 0; + /* client_data.audio_offset must be determined later */ + client_data.first_seekpoint_to_check = 0; + client_data.error_occurred = false; + + decoder = FLAC__stream_decoder_new(); + + if(0 == decoder) { + flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) creating the decoder instance\n", filename); + return false; + } + + FLAC__stream_decoder_set_md5_checking(decoder, false); + FLAC__stream_decoder_set_metadata_ignore_all(decoder); + + if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, /*metadata_callback=*/0, error_callback_, &client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) initializing the decoder instance (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder)); + ok = false; + } + + if(ok && !FLAC__stream_decoder_process_until_end_of_metadata(decoder)) { + flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder)); + ok = false; + } + + if(ok && !FLAC__stream_decoder_get_decode_position(decoder, &client_data.audio_offset)) { + flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file\n", filename); + ok = false; + } + client_data.last_offset = client_data.audio_offset; + + if(ok && !FLAC__stream_decoder_process_until_end_of_stream(decoder)) { + flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)\n", filename, FLAC__stream_decoder_get_resolved_state_string(decoder)); + ok = false; + } + + if(ok && client_data.error_occurred) { + flac_fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%u:%s)\n", filename, (unsigned)client_data.error_status, FLAC__StreamDecoderErrorStatusString[client_data.error_status]); + ok = false; + } + + *needs_write = true; + FLAC__stream_decoder_delete(decoder); + return ok; +} diff --git a/vendor/flac/src/metaflac/operations_shorthand_streaminfo.c b/vendor/flac/src/metaflac/operations_shorthand_streaminfo.c new file mode 100644 index 0000000..3219841 --- /dev/null +++ b/vendor/flac/src/metaflac/operations_shorthand_streaminfo.c @@ -0,0 +1,127 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "options.h" +#include "utils.h" +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "share/compat.h" +#include +#include "operations_shorthand.h" + +FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write) +{ + unsigned i; + FLAC__bool ok = true; + FLAC__StreamMetadata *block; + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + block = FLAC__metadata_iterator_get_block(iterator); + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO); + + if(prefix_with_filename) + flac_printf("%s:", filename); + + switch(operation->type) { + case OP__SHOW_MD5SUM: + for(i = 0; i < 16; i++) + printf("%02x", block->data.stream_info.md5sum[i]); + printf("\n"); + break; + case OP__SHOW_MIN_BLOCKSIZE: + printf("%u\n", block->data.stream_info.min_blocksize); + break; + case OP__SHOW_MAX_BLOCKSIZE: + printf("%u\n", block->data.stream_info.max_blocksize); + break; + case OP__SHOW_MIN_FRAMESIZE: + printf("%u\n", block->data.stream_info.min_framesize); + break; + case OP__SHOW_MAX_FRAMESIZE: + printf("%u\n", block->data.stream_info.max_framesize); + break; + case OP__SHOW_SAMPLE_RATE: + printf("%u\n", block->data.stream_info.sample_rate); + break; + case OP__SHOW_CHANNELS: + printf("%u\n", block->data.stream_info.channels); + break; + case OP__SHOW_BPS: + printf("%u\n", block->data.stream_info.bits_per_sample); + break; + case OP__SHOW_TOTAL_SAMPLES: + printf("%" PRIu64 "\n", block->data.stream_info.total_samples); + break; + case OP__SET_MD5SUM: + memcpy(block->data.stream_info.md5sum, operation->argument.streaminfo_md5.value, 16); + *needs_write = true; + break; + case OP__SET_MIN_BLOCKSIZE: + block->data.stream_info.min_blocksize = operation->argument.streaminfo_uint32.value; + *needs_write = true; + break; + case OP__SET_MAX_BLOCKSIZE: + block->data.stream_info.max_blocksize = operation->argument.streaminfo_uint32.value; + *needs_write = true; + break; + case OP__SET_MIN_FRAMESIZE: + block->data.stream_info.min_framesize = operation->argument.streaminfo_uint32.value; + *needs_write = true; + break; + case OP__SET_MAX_FRAMESIZE: + block->data.stream_info.max_framesize = operation->argument.streaminfo_uint32.value; + *needs_write = true; + break; + case OP__SET_SAMPLE_RATE: + block->data.stream_info.sample_rate = operation->argument.streaminfo_uint32.value; + *needs_write = true; + break; + case OP__SET_CHANNELS: + block->data.stream_info.channels = operation->argument.streaminfo_uint32.value; + *needs_write = true; + break; + case OP__SET_BPS: + block->data.stream_info.bits_per_sample = operation->argument.streaminfo_uint32.value; + *needs_write = true; + break; + case OP__SET_TOTAL_SAMPLES: + block->data.stream_info.total_samples = operation->argument.streaminfo_uint64.value; + *needs_write = true; + break; + default: + ok = false; + FLAC__ASSERT(0); + break; + }; + + FLAC__metadata_iterator_delete(iterator); + + return ok; +} diff --git a/vendor/flac/src/metaflac/operations_shorthand_vorbiscomment.c b/vendor/flac/src/metaflac/operations_shorthand_vorbiscomment.c new file mode 100644 index 0000000..27c9e4c --- /dev/null +++ b/vendor/flac/src/metaflac/operations_shorthand_vorbiscomment.c @@ -0,0 +1,430 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "options.h" +#include "utils.h" +#include "FLAC/assert.h" +#include "share/grabbag.h" /* for grabbag__file_get_filesize() */ +#include "share/utf8.h" +#include +#include +#include +#include "operations_shorthand.h" +#include "share/compat.h" + +static FLAC__bool remove_vc_all(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write); +static FLAC__bool remove_vc_all_except(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write); +static FLAC__bool remove_vc_field(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write); +static FLAC__bool remove_vc_firstfield(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write); +static FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw); +static FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw); +static FLAC__bool export_vc_to(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool raw); + +FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw) +{ + FLAC__bool ok = true, found_vc_block = false; + FLAC__StreamMetadata *block = 0; + FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new(); + + if(0 == iterator) + die("out of memory allocating iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + do { + block = FLAC__metadata_iterator_get_block(iterator); + if(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + found_vc_block = true; + } while(!found_vc_block && FLAC__metadata_iterator_next(iterator)); + + if(!found_vc_block) { + /* create a new block if necessary */ + if(operation->type == OP__SET_VC_FIELD || operation->type == OP__IMPORT_VC_FROM) { + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 == block) + die("out of memory allocating VORBIS_COMMENT block"); + while(FLAC__metadata_iterator_next(iterator)) + ; + if(!FLAC__metadata_iterator_insert_block_after(iterator, block)) { + print_error_with_chain_status(chain, "%s: ERROR: adding new VORBIS_COMMENT block to metadata", filename); + return false; + } + /* iterator is left pointing to new block */ + FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == block); + } + else { + FLAC__metadata_iterator_delete(iterator); + return ok; + } + } + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + switch(operation->type) { + case OP__SHOW_VC_VENDOR: + write_vc_field(prefix_with_filename? filename : 0, &block->data.vorbis_comment.vendor_string, raw, stdout); + break; + case OP__SHOW_VC_FIELD: + write_vc_fields(prefix_with_filename? filename : 0, operation->argument.vc_field_name.value, block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, raw, stdout); + break; + case OP__REMOVE_VC_ALL: + ok = remove_vc_all(filename, block, needs_write); + break; + case OP__REMOVE_VC_ALL_EXCEPT: + ok = remove_vc_all_except(filename, block, operation->argument.vc_field_name.value, needs_write); + break; + case OP__REMOVE_VC_FIELD: + ok = remove_vc_field(filename, block, operation->argument.vc_field_name.value, needs_write); + break; + case OP__REMOVE_VC_FIRSTFIELD: + ok = remove_vc_firstfield(filename, block, operation->argument.vc_field_name.value, needs_write); + break; + case OP__SET_VC_FIELD: +#ifdef _WIN32 /* do not convert anything or things will break */ + ok = set_vc_field(filename, block, &operation->argument.vc_field, needs_write, true); +#else + ok = set_vc_field(filename, block, &operation->argument.vc_field, needs_write, raw); +#endif + break; + case OP__IMPORT_VC_FROM: + ok = import_vc_from(filename, block, &operation->argument.filename, needs_write, raw); + break; + case OP__EXPORT_VC_TO: + ok = export_vc_to(filename, block, &operation->argument.filename, raw); + break; + default: + ok = false; + FLAC__ASSERT(0); + break; + }; + + FLAC__metadata_iterator_delete(iterator); + return ok; +} + +/* + * local routines + */ + +FLAC__bool remove_vc_all(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write) +{ + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != needs_write); + + if(0 != block->data.vorbis_comment.comments) { + FLAC__ASSERT(block->data.vorbis_comment.num_comments > 0); + if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, 0)) { + flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename); + return false; + } + *needs_write = true; + } + else { + FLAC__ASSERT(block->data.vorbis_comment.num_comments == 0); + } + + return true; +} + +FLAC__bool remove_vc_all_except(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write) +{ + char * field_names[200]; + uint32_t field_name_length, i; + int j, num_field_names; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != needs_write); + + field_name_length = strlen(field_name); + field_names[0] = (void *)field_name; + + for(num_field_names = 1; num_field_names < 200; num_field_names++) { + char * separator = strchr(field_names[num_field_names-1], '='); + if(separator == 0 || separator >= field_name + field_name_length) + break; + field_names[num_field_names] = separator+1; + } + + if(num_field_names > 200) { + flac_fprintf(stderr, "%s: ERROR: too many field names\n", filename); + return false; + } + + for(i = 0; i < block->data.vorbis_comment.num_comments; ) { + int field_name_found = false; + for(j = 0; j < num_field_names; j++) { + const uint32_t length = (j == (num_field_names - 1))?(uint32_t)strlen(field_names[j]):(uint32_t)(strchr(field_names[j],'=')-field_names[j]); + if(FLAC__metadata_object_vorbiscomment_entry_matches(block->data.vorbis_comment.comments[i], field_names[j], length)) { + field_name_found = true; + break; + } + } + if(!field_name_found) { + FLAC__metadata_object_vorbiscomment_delete_comment(block, i); + *needs_write = true; + } + else + i++; + } + + return true; +} + +FLAC__bool remove_vc_field(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write) +{ + int n; + + FLAC__ASSERT(0 != needs_write); + + n = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, field_name); + + if(n < 0) { + flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename); + return false; + } + else if(n > 0) + *needs_write = true; + + return true; +} + +FLAC__bool remove_vc_firstfield(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write) +{ + int n; + + FLAC__ASSERT(0 != needs_write); + + n = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, field_name); + + if(n < 0) { + flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename); + return false; + } + else if(n > 0) + *needs_write = true; + + return true; +} + +FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const Argument_VcField *field, FLAC__bool *needs_write, FLAC__bool raw) +{ + FLAC__StreamMetadata_VorbisComment_Entry entry; + char *converted; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != field); + FLAC__ASSERT(0 != needs_write); + + if(field->field_value_from_file) { + /* read the file into 'data' */ + FILE *f = 0; + char *data = 0; + const FLAC__off_t size = grabbag__file_get_filesize(field->field_value); + if(size < 0) { + flac_fprintf(stderr, "%s: ERROR: can't open file '%s' for '%s' tag value\n", filename, field->field_value, field->field_name); + return false; + } + if(size >= 0x100000) { /* magic arbitrary limit, actual format limit is near 16MB */ + flac_fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value is too large\n", filename, field->field_value, field->field_name); + return false; + } + if(0 == (data = malloc(size+1))) + die("out of memory allocating tag value"); + data[size] = '\0'; + if(0 == (f = flac_fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) { + flac_fprintf(stderr, "%s: ERROR: while reading file '%s' for '%s' tag value: %s\n", filename, field->field_value, field->field_name, strerror(errno)); + free(data); + if(f) + fclose(f); + return false; + } + fclose(f); + if(strlen(data) != (size_t)size) { + free(data); + flac_fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value has embedded NULs\n", filename, field->field_value, field->field_name); + return false; + } + + /* move 'data' into 'converted', converting to UTF-8 if necessary */ + if(raw) { + converted = data; + } + else if(utf8_encode(data, &converted) >= 0) { + free(data); + } + else { + free(data); + flac_fprintf(stderr, "%s: ERROR: converting file '%s' contents to UTF-8 for tag value\n", filename, field->field_value); + return false; + } + + /* create and entry and append it */ + if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field->field_name, converted)) { + free(converted); + flac_fprintf(stderr, "%s: ERROR: file '%s' for '%s' tag value is not valid UTF-8\n", filename, field->field_value, field->field_name); + return false; + } + free(converted); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) { + flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename); + return false; + } + + *needs_write = true; + return true; + } + else { + FLAC__bool needs_free = false; + entry.entry = (FLAC__byte *)field->field; + if(raw) { + entry.entry = (FLAC__byte *)field->field; + } + else if(utf8_encode(field->field, &converted) >= 0) { + entry.entry = (FLAC__byte *)converted; + needs_free = true; + } + else { + flac_fprintf(stderr, "%s: ERROR: converting comment '%s' to UTF-8\n", filename, field->field); + return false; + } + entry.length = strlen((const char *)entry.entry); + if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) { + if(needs_free) + free(converted); + /* + * our previous parsing has already established that the field + * name is OK, so it must be the field value + */ + flac_fprintf(stderr, "%s: ERROR: tag value for '%s' is not valid UTF-8\n", filename, field->field_name); + return false; + } + + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { + if(needs_free) + free(converted); + flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename); + return false; + } + + *needs_write = true; + if(needs_free) + free(converted); + return true; + } +} + +FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw) +{ + FILE *f; + char line[65536]; + FLAC__bool ret; + + if(0 == vc_filename->value || strlen(vc_filename->value) == 0) { + flac_fprintf(stderr, "%s: ERROR: empty import file name\n", filename); + return false; + } + if(0 == strcmp(vc_filename->value, "-")) + f = stdin; + else + f = flac_fopen(vc_filename->value, "r"); + + if(0 == f) { + flac_fprintf(stderr, "%s: ERROR: can't open import file %s: %s\n", filename, vc_filename->value, strerror(errno)); + return false; + } + + ret = true; + while(ret && !feof(f) && fgets(line, sizeof(line), f) != NULL) { + if(!feof(f)) { + char *p = strchr(line, '\n'); + if(0 == p) { + flac_fprintf(stderr, "%s: ERROR: line too long, aborting\n", vc_filename->value); + ret = false; + } + else { + const char *violation; + Argument_VcField field; + *p = '\0'; + memset(&field, 0, sizeof(Argument_VcField)); + field.field_value_from_file = false; + if(!parse_vorbis_comment_field(line, &field.field, &field.field_name, &field.field_value, &field.field_value_length, &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "%s: ERROR: malformed vorbis comment field \"%s\",\n %s\n", vc_filename->value, line, violation); + ret = false; + } + else { + ret = set_vc_field(filename, block, &field, needs_write, raw); + } + if(0 != field.field) + free(field.field); + if(0 != field.field_name) + free(field.field_name); + if(0 != field.field_value) + free(field.field_value); + } + } + }; + + if(f != stdin) + fclose(f); + return ret; +} + +FLAC__bool export_vc_to(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool raw) +{ + FILE *f; + FLAC__bool ret; + + if(0 == vc_filename->value || strlen(vc_filename->value) == 0) { + flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename); + return false; + } + if(0 == strcmp(vc_filename->value, "-")) + f = stdout; + else + f = flac_fopen(vc_filename->value, "w"); + + if(0 == f) { + flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, vc_filename->value, strerror(errno)); + return false; + } + + ret = true; + + write_vc_fields(0, 0, block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, raw, f); + + if(f != stdout) + fclose(f); + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Delete output file when fuzzing */ + if(f != stdout) + flac_unlink(vc_filename->value); +#endif + + return ret; +} diff --git a/vendor/flac/src/metaflac/options.c b/vendor/flac/src/metaflac/options.c new file mode 100644 index 0000000..1b4b6f6 --- /dev/null +++ b/vendor/flac/src/metaflac/options.c @@ -0,0 +1,1146 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "options.h" +#include "usage.h" +#include "utils.h" +#include "FLAC/assert.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "share/grabbag/replaygain.h" +#include +#include +#include +#include + +/* + share__getopt format struct; note we don't use short options so we just + set the 'val' field to 0 everywhere to indicate a valid option. +*/ +struct share__option long_options_[] = { + /* global options */ + { "preserve-modtime", 0, 0, 0 }, + { "with-filename", 0, 0, 0 }, + { "no-filename", 0, 0, 0 }, + { "no-utf8-convert", 0, 0, 0 }, + { "dont-use-padding", 0, 0, 0 }, + { "no-cued-seekpoints", 0, 0, 0 }, + /* shorthand operations */ + { "show-md5sum", 0, 0, 0 }, + { "show-min-blocksize", 0, 0, 0 }, + { "show-max-blocksize", 0, 0, 0 }, + { "show-min-framesize", 0, 0, 0 }, + { "show-max-framesize", 0, 0, 0 }, + { "show-sample-rate", 0, 0, 0 }, + { "show-channels", 0, 0, 0 }, + { "show-bps", 0, 0, 0 }, + { "show-total-samples", 0, 0, 0 }, + { "set-md5sum", 1, 0, 0 }, /* undocumented */ + { "set-min-blocksize", 1, 0, 0 }, /* undocumented */ + { "set-max-blocksize", 1, 0, 0 }, /* undocumented */ + { "set-min-framesize", 1, 0, 0 }, /* undocumented */ + { "set-max-framesize", 1, 0, 0 }, /* undocumented */ + { "set-sample-rate", 1, 0, 0 }, /* undocumented */ + { "set-channels", 1, 0, 0 }, /* undocumented */ + { "set-bps", 1, 0, 0 }, /* undocumented */ + { "set-total-samples", 1, 0, 0 }, /* undocumented */ /* WATCHOUT: used by test/test_flac.sh on windows */ + { "show-vendor-tag", 0, 0, 0 }, + { "show-all-tags", 0, 0, 0 }, + { "show-tag", 1, 0, 0 }, + { "remove-all-tags", 0, 0, 0 }, + { "remove-all-tags-except", 1, 0, 0 }, + { "remove-tag", 1, 0, 0 }, + { "remove-first-tag", 1, 0, 0 }, + { "set-tag", 1, 0, 0 }, + { "set-tag-from-file", 1, 0, 0 }, + { "import-tags-from", 1, 0, 0 }, + { "export-tags-to", 1, 0, 0 }, + { "import-cuesheet-from", 1, 0, 0 }, + { "export-cuesheet-to", 1, 0, 0 }, + { "import-picture-from", 1, 0, 0 }, + { "export-picture-to", 1, 0, 0 }, + { "add-seekpoint", 1, 0, 0 }, + { "add-replay-gain", 0, 0, 0 }, + { "scan-replay-gain", 0, 0, 0 }, + { "remove-replay-gain", 0, 0, 0 }, + { "add-padding", 1, 0, 0 }, + /* major operations */ + { "help", 0, 0, 0 }, + { "version", 0, 0, 0 }, + { "list", 0, 0, 0 }, + { "append", 0, 0, 0 }, + { "remove", 0, 0, 0 }, + { "remove-all", 0, 0, 0 }, + { "merge-padding", 0, 0, 0 }, + { "sort-padding", 0, 0, 0 }, + /* major operation arguments */ + { "block-number", 1, 0, 0 }, + { "block-type", 1, 0, 0 }, + { "except-block-type", 1, 0, 0 }, + { "data-format", 1, 0, 0 }, + { "application-data-format", 1, 0, 0 }, + { "from-file", 1, 0, 0 }, + {0, 0, 0, 0} +}; + +static FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options); +static void append_new_operation(CommandLineOptions *options, Operation operation); +static void append_new_argument(CommandLineOptions *options, Argument argument); +static Operation *append_major_operation(CommandLineOptions *options, OperationType type); +static Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type); +static Argument *find_argument(CommandLineOptions *options, ArgumentType type); +static Operation *find_shorthand_operation(CommandLineOptions *options, OperationType type); +static Argument *append_argument(CommandLineOptions *options, ArgumentType type); +static FLAC__bool parse_md5(const char *src, FLAC__byte dest[16]); +static FLAC__bool parse_uint32(const char *src, FLAC__uint32 *dest); +static FLAC__bool parse_uint64(const char *src, FLAC__uint64 *dest); +static FLAC__bool parse_string(const char *src, char **dest); +static FLAC__bool parse_vorbis_comment_field_name(const char *field_ref, char **name, const char **violation); +static FLAC__bool parse_vorbis_comment_field_names(const char *field_ref, char **names, const char **violation); +static FLAC__bool parse_add_seekpoint(const char *in, char **out, const char **violation); +static FLAC__bool parse_add_padding(const char *in, unsigned *out); +static FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out); +static FLAC__bool parse_block_type(const char *in, Argument_BlockType *out); +static FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out); +static FLAC__bool parse_application_data_format(const char *in, FLAC__bool *out); +static void undocumented_warning(const char *opt); + + +void init_options(CommandLineOptions *options) +{ + options->preserve_modtime = false; + + /* '2' is a hack to mean "use default if not forced on command line" */ + FLAC__ASSERT(true != 2); + options->prefix_with_filename = 2; + + options->utf8_convert = true; + options->use_padding = true; + options->cued_seekpoints = true; + options->show_long_help = false; + options->show_version = false; + options->data_format_is_binary = false; + options->data_format_is_binary_headerless = false; + options->application_data_format_is_hexdump = false; + + options->ops.operations = 0; + options->ops.num_operations = 0; + options->ops.capacity = 0; + + options->args.arguments = 0; + options->args.num_arguments = 0; + options->args.capacity = 0; + + options->args.checks.num_shorthand_ops = 0; + options->args.checks.num_major_ops = 0; + options->args.checks.has_block_type = false; + options->args.checks.has_except_block_type = false; + + options->num_files = 0; + options->filenames = 0; +} + +FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options) +{ + int ret; + int option_index = 1; + FLAC__bool had_error = false; + + while ((ret = share__getopt_long(argc, argv, "", long_options_, &option_index)) != -1) { + switch (ret) { + case 0: + had_error |= !parse_option(option_index, share__optarg, options); + break; + case '?': + case ':': + had_error = true; + break; + default: + FLAC__ASSERT(0); + break; + } + } + + if(options->prefix_with_filename == 2) + options->prefix_with_filename = (argc - share__optind > 1); + + if(share__optind >= argc && !options->show_long_help && !options->show_version) { + flac_fprintf(stderr,"ERROR: you must specify at least one FLAC file;\n"); + flac_fprintf(stderr," metaflac cannot be used as a pipe\n"); + had_error = true; + } + + options->num_files = argc - share__optind; + + if(options->num_files > 0) { + unsigned i = 0; + if(0 == (options->filenames = safe_malloc_mul_2op_(sizeof(char*), /*times*/options->num_files))) + die("out of memory allocating space for file names list"); + while(share__optind < argc) + options->filenames[i++] = local_strdup(argv[share__optind++]); + } + + if(options->args.checks.num_major_ops > 0) { + if(options->args.checks.num_major_ops > 1) { + flac_fprintf(stderr, "ERROR: you may only specify one major operation at a time\n"); + had_error = true; + } + else if(options->args.checks.num_shorthand_ops > 0) { + flac_fprintf(stderr, "ERROR: you may not mix shorthand and major operations\n"); + had_error = true; + } + } + + /* check for only one FLAC file used with certain options */ + if(!had_error && options->num_files > 1) { + if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) { + flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-cuesheet-from'\n"); + had_error = true; + } + if(0 != find_shorthand_operation(options, OP__EXPORT_CUESHEET_TO)) { + flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-cuesheet-to'\n"); + had_error = true; + } + if(0 != find_shorthand_operation(options, OP__EXPORT_PICTURE_TO)) { + flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-picture-to'\n"); + had_error = true; + } + if( + 0 != find_shorthand_operation(options, OP__IMPORT_VC_FROM) && + 0 == strcmp(find_shorthand_operation(options, OP__IMPORT_VC_FROM)->argument.filename.value, "-") + ) { + flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-tags-from=-'\n"); + had_error = true; + } + } + + if(options->args.checks.has_block_type && options->args.checks.has_except_block_type) { + flac_fprintf(stderr, "ERROR: you may not specify both '--block-type' and '--except-block-type'\n"); + had_error = true; + } + + if(had_error) + short_usage(0); + + /* + * We need to create an OP__ADD_SEEKPOINT operation if there is + * not one already, and --import-cuesheet-from was specified but + * --no-cued-seekpoints was not: + */ + if(options->cued_seekpoints) { + Operation *op = find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM); + if(0 != op) { + Operation *op2 = find_shorthand_operation(options, OP__ADD_SEEKPOINT); + if(0 == op2) + op2 = append_shorthand_operation(options, OP__ADD_SEEKPOINT); + op->argument.import_cuesheet_from.add_seekpoint_link = &(op2->argument.add_seekpoint); + } + } + + return had_error; +} + +void free_options(CommandLineOptions *options) +{ + unsigned i; + Operation *op; + Argument *arg; + + FLAC__ASSERT(0 == options->ops.operations || options->ops.num_operations > 0); + FLAC__ASSERT(0 == options->args.arguments || options->args.num_arguments > 0); + + for(i = 0, op = options->ops.operations; i < options->ops.num_operations; i++, op++) { + switch(op->type) { + case OP__SHOW_VC_FIELD: + case OP__REMOVE_VC_FIELD: + case OP__REMOVE_VC_FIRSTFIELD: + case OP__REMOVE_VC_ALL_EXCEPT: + if(0 != op->argument.vc_field_name.value) + free(op->argument.vc_field_name.value); + break; + case OP__SET_VC_FIELD: + if(0 != op->argument.vc_field.field) + free(op->argument.vc_field.field); + if(0 != op->argument.vc_field.field_name) + free(op->argument.vc_field.field_name); + if(0 != op->argument.vc_field.field_value) + free(op->argument.vc_field.field_value); + break; + case OP__IMPORT_VC_FROM: + case OP__EXPORT_VC_TO: + case OP__EXPORT_CUESHEET_TO: + if(0 != op->argument.filename.value) + free(op->argument.filename.value); + break; + case OP__IMPORT_CUESHEET_FROM: + if(0 != op->argument.import_cuesheet_from.filename) + free(op->argument.import_cuesheet_from.filename); + break; + case OP__IMPORT_PICTURE_FROM: + if(0 != op->argument.specification.value) + free(op->argument.specification.value); + break; + case OP__EXPORT_PICTURE_TO: + if(0 != op->argument.export_picture_to.filename) + free(op->argument.export_picture_to.filename); + break; + case OP__ADD_SEEKPOINT: + if(0 != op->argument.add_seekpoint.specification) + free(op->argument.add_seekpoint.specification); + break; + default: + break; + } + } + + for(i = 0, arg = options->args.arguments; i < options->args.num_arguments; i++, arg++) { + switch(arg->type) { + case ARG__BLOCK_NUMBER: + if(0 != arg->value.block_number.entries) + free(arg->value.block_number.entries); + break; + case ARG__BLOCK_TYPE: + case ARG__EXCEPT_BLOCK_TYPE: + if(0 != arg->value.block_type.entries) + free(arg->value.block_type.entries); + break; + case ARG__FROM_FILE: + if(0 != arg->value.from_file.file_name) + free(arg->value.from_file.file_name); + break; + default: + break; + } + } + + if(0 != options->ops.operations) + free(options->ops.operations); + + if(0 != options->args.arguments) + free(options->args.arguments); + + if(0 != options->filenames) { + for(i = 0; i < options->num_files; i++) { + if(0 != options->filenames[i]) + free(options->filenames[i]); + } + free(options->filenames); + } +} + +/* + * local routines + */ + +FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options) +{ + const char *opt = long_options_[option_index].name; + Operation *op; + Argument *arg; + FLAC__bool ok = true; + + if(0 == strcmp(opt, "preserve-modtime")) { + options->preserve_modtime = true; + } + else if(0 == strcmp(opt, "with-filename")) { + options->prefix_with_filename = true; + } + else if(0 == strcmp(opt, "no-filename")) { + options->prefix_with_filename = false; + } + else if(0 == strcmp(opt, "no-utf8-convert")) { + options->utf8_convert = false; + } + else if(0 == strcmp(opt, "dont-use-padding")) { + options->use_padding = false; + } + else if(0 == strcmp(opt, "no-cued-seekpoints")) { + options->cued_seekpoints = false; + } + else if(0 == strcmp(opt, "show-md5sum")) { + (void) append_shorthand_operation(options, OP__SHOW_MD5SUM); + } + else if(0 == strcmp(opt, "show-min-blocksize")) { + (void) append_shorthand_operation(options, OP__SHOW_MIN_BLOCKSIZE); + } + else if(0 == strcmp(opt, "show-max-blocksize")) { + (void) append_shorthand_operation(options, OP__SHOW_MAX_BLOCKSIZE); + } + else if(0 == strcmp(opt, "show-min-framesize")) { + (void) append_shorthand_operation(options, OP__SHOW_MIN_FRAMESIZE); + } + else if(0 == strcmp(opt, "show-max-framesize")) { + (void) append_shorthand_operation(options, OP__SHOW_MAX_FRAMESIZE); + } + else if(0 == strcmp(opt, "show-sample-rate")) { + (void) append_shorthand_operation(options, OP__SHOW_SAMPLE_RATE); + } + else if(0 == strcmp(opt, "show-channels")) { + (void) append_shorthand_operation(options, OP__SHOW_CHANNELS); + } + else if(0 == strcmp(opt, "show-bps")) { + (void) append_shorthand_operation(options, OP__SHOW_BPS); + } + else if(0 == strcmp(opt, "show-total-samples")) { + (void) append_shorthand_operation(options, OP__SHOW_TOTAL_SAMPLES); + } + else if(0 == strcmp(opt, "set-md5sum")) { + op = append_shorthand_operation(options, OP__SET_MD5SUM); + FLAC__ASSERT(0 != option_argument); + if(!parse_md5(option_argument, op->argument.streaminfo_md5.value)) { + flac_fprintf(stderr, "ERROR (--%s): bad MD5 sum\n", opt); + ok = false; + } + else + undocumented_warning(opt); + } + else if(0 == strcmp(opt, "set-min-blocksize")) { + op = append_shorthand_operation(options, OP__SET_MIN_BLOCKSIZE); + if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) { + flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE); + ok = false; + } + else + undocumented_warning(opt); + } + else if(0 == strcmp(opt, "set-max-blocksize")) { + op = append_shorthand_operation(options, OP__SET_MAX_BLOCKSIZE); + if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) { + flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE); + ok = false; + } + else + undocumented_warning(opt); + } + else if(0 == strcmp(opt, "set-min-framesize")) { + op = append_shorthand_operation(options, OP__SET_MIN_FRAMESIZE); + if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<argument.streaminfo_uint32.value)) || !FLAC__format_sample_rate_is_valid(op->argument.streaminfo_uint32.value)) { + flac_fprintf(stderr, "ERROR (--%s): invalid sample rate\n", opt); + ok = false; + } + else + undocumented_warning(opt); + } + else if(0 == strcmp(opt, "set-channels")) { + op = append_shorthand_operation(options, OP__SET_CHANNELS); + if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value > FLAC__MAX_CHANNELS) { + flac_fprintf(stderr, "ERROR (--%s): value must be > 0 and <= %u\n", opt, FLAC__MAX_CHANNELS); + ok = false; + } + else + undocumented_warning(opt); + } + else if(0 == strcmp(opt, "set-bps")) { + op = append_shorthand_operation(options, OP__SET_BPS); + if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BITS_PER_SAMPLE || op->argument.streaminfo_uint32.value > FLAC__MAX_BITS_PER_SAMPLE) { + flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BITS_PER_SAMPLE, FLAC__MAX_BITS_PER_SAMPLE); + ok = false; + } + else + undocumented_warning(opt); + } + else if(0 == strcmp(opt, "set-total-samples")) { + op = append_shorthand_operation(options, OP__SET_TOTAL_SAMPLES); + if(!parse_uint64(option_argument, &(op->argument.streaminfo_uint64.value)) || op->argument.streaminfo_uint64.value >= (((FLAC__uint64)1)<argument.vc_field_name.value), &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n %s\n", opt, option_argument, violation); + ok = false; + } + } + else if(0 == strcmp(opt, "show-all-tags")) { + op = append_shorthand_operation(options, OP__EXPORT_VC_TO); + parse_string("-",&op->argument.filename.value); + } + else if(0 == strcmp(opt, "remove-all-tags")) { + (void) append_shorthand_operation(options, OP__REMOVE_VC_ALL); + } + else if(0 == strcmp(opt, "remove-all-tags-except")) { + const char *violation; + op = append_shorthand_operation(options, OP__REMOVE_VC_ALL_EXCEPT); + FLAC__ASSERT(0 != option_argument); + if(!parse_vorbis_comment_field_names(option_argument, &(op->argument.vc_field_name.value), &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n %s\n", opt, option_argument, violation); + ok = false; + } + } + else if(0 == strcmp(opt, "remove-tag")) { + const char *violation; + op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD); + FLAC__ASSERT(0 != option_argument); + if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n %s\n", opt, option_argument, violation); + ok = false; + } + } + else if(0 == strcmp(opt, "remove-first-tag")) { + const char *violation; + op = append_shorthand_operation(options, OP__REMOVE_VC_FIRSTFIELD); + FLAC__ASSERT(0 != option_argument); + if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n %s\n", opt, option_argument, violation); + ok = false; + } + } + else if(0 == strcmp(opt, "set-tag")) { + const char *violation; + op = append_shorthand_operation(options, OP__SET_VC_FIELD); + FLAC__ASSERT(0 != option_argument); + op->argument.vc_field.field_value_from_file = false; + if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n %s\n", opt, option_argument, violation); + ok = false; + } + } + else if(0 == strcmp(opt, "set-tag-from-file")) { + const char *violation; + op = append_shorthand_operation(options, OP__SET_VC_FIELD); + FLAC__ASSERT(0 != option_argument); + op->argument.vc_field.field_value_from_file = true; + if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n %s\n", opt, option_argument, violation); + ok = false; + } + } + else if(0 == strcmp(opt, "import-tags-from")) { + op = append_shorthand_operation(options, OP__IMPORT_VC_FROM); + FLAC__ASSERT(0 != option_argument); + if(!parse_string(option_argument, &(op->argument.filename.value))) { + flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt); + ok = false; + } + } + else if(0 == strcmp(opt, "export-tags-to")) { + op = append_shorthand_operation(options, OP__EXPORT_VC_TO); + FLAC__ASSERT(0 != option_argument); + if(!parse_string(option_argument, &(op->argument.filename.value))) { + flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt); + ok = false; + } + } + else if(0 == strcmp(opt, "import-cuesheet-from")) { + if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) { + flac_fprintf(stderr, "ERROR (--%s): may be specified only once\n", opt); + ok = false; + } + op = append_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM); + FLAC__ASSERT(0 != option_argument); + if(!parse_string(option_argument, &(op->argument.import_cuesheet_from.filename))) { + flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt); + ok = false; + } + } + else if(0 == strcmp(opt, "export-cuesheet-to")) { + op = append_shorthand_operation(options, OP__EXPORT_CUESHEET_TO); + FLAC__ASSERT(0 != option_argument); + if(!parse_string(option_argument, &(op->argument.filename.value))) { + flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt); + ok = false; + } + } + else if(0 == strcmp(opt, "import-picture-from")) { + op = append_shorthand_operation(options, OP__IMPORT_PICTURE_FROM); + FLAC__ASSERT(0 != option_argument); + if(!parse_string(option_argument, &(op->argument.specification.value))) { + flac_fprintf(stderr, "ERROR (--%s): missing specification\n", opt); + ok = false; + } + } + else if(0 == strcmp(opt, "export-picture-to")) { + arg = find_argument(options, ARG__BLOCK_NUMBER); + op = append_shorthand_operation(options, OP__EXPORT_PICTURE_TO); + FLAC__ASSERT(0 != option_argument); + if(!parse_string(option_argument, &(op->argument.export_picture_to.filename))) { + flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt); + ok = false; + } + op->argument.export_picture_to.block_number_link = arg? &(arg->value.block_number) : 0; + } + else if(0 == strcmp(opt, "add-seekpoint")) { + const char *violation; + char *spec; + FLAC__ASSERT(0 != option_argument); + if(!parse_add_seekpoint(option_argument, &spec, &violation)) { + FLAC__ASSERT(0 != violation); + flac_fprintf(stderr, "ERROR (--%s): malformed seekpoint specification \"%s\",\n %s\n", opt, option_argument, violation); + ok = false; + } + else { + op = find_shorthand_operation(options, OP__ADD_SEEKPOINT); + if(0 == op) + op = append_shorthand_operation(options, OP__ADD_SEEKPOINT); + local_strcat(&(op->argument.add_seekpoint.specification), spec); + local_strcat(&(op->argument.add_seekpoint.specification), ";"); + free(spec); + } + } + else if(0 == strcmp(opt, "add-replay-gain")) { + (void) append_shorthand_operation(options, OP__ADD_REPLAY_GAIN); + } + else if(0 == strcmp(opt, "scan-replay-gain")) { + (void) append_shorthand_operation(options, OP__SCAN_REPLAY_GAIN); + } + else if(0 == strcmp(opt, "remove-replay-gain")) { + const FLAC__byte * const tags[5] = { + GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, + GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, + GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, + GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, + GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK + }; + size_t i; + for(i = 0; i < sizeof(tags)/sizeof(tags[0]); i++) { + op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD); + op->argument.vc_field_name.value = local_strdup((const char *)tags[i]); + } + } + else if(0 == strcmp(opt, "add-padding")) { + op = append_shorthand_operation(options, OP__ADD_PADDING); + FLAC__ASSERT(0 != option_argument); + if(!parse_add_padding(option_argument, &(op->argument.add_padding.length))) { + flac_fprintf(stderr, "ERROR (--%s): illegal length \"%s\", length must be >= 0 and < 2^%u\n", opt, option_argument, FLAC__STREAM_METADATA_LENGTH_LEN); + ok = false; + } + } + else if(0 == strcmp(opt, "help")) { + options->show_long_help = true; + } + else if(0 == strcmp(opt, "version")) { + options->show_version = true; + } + else if(0 == strcmp(opt, "list")) { + (void) append_major_operation(options, OP__LIST); + } + else if(0 == strcmp(opt, "append")) { + (void) append_major_operation(options, OP__APPEND); + } + else if(0 == strcmp(opt, "remove")) { + (void) append_major_operation(options, OP__REMOVE); + } + else if(0 == strcmp(opt, "remove-all")) { + (void) append_major_operation(options, OP__REMOVE_ALL); + } + else if(0 == strcmp(opt, "merge-padding")) { + (void) append_major_operation(options, OP__MERGE_PADDING); + } + else if(0 == strcmp(opt, "sort-padding")) { + (void) append_major_operation(options, OP__SORT_PADDING); + } + else if(0 == strcmp(opt, "block-number")) { + arg = append_argument(options, ARG__BLOCK_NUMBER); + FLAC__ASSERT(0 != option_argument); + if(!parse_block_number(option_argument, &(arg->value.block_number))) { + flac_fprintf(stderr, "ERROR: malformed block number specification \"%s\"\n", option_argument); + ok = false; + } + } + else if(0 == strcmp(opt, "block-type")) { + arg = append_argument(options, ARG__BLOCK_TYPE); + FLAC__ASSERT(0 != option_argument); + if(!parse_block_type(option_argument, &(arg->value.block_type))) { + flac_fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument); + ok = false; + } + options->args.checks.has_block_type = true; + } + else if(0 == strcmp(opt, "except-block-type")) { + arg = append_argument(options, ARG__EXCEPT_BLOCK_TYPE); + FLAC__ASSERT(0 != option_argument); + if(!parse_block_type(option_argument, &(arg->value.block_type))) { + flac_fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument); + ok = false; + } + options->args.checks.has_except_block_type = true; + } + else if(0 == strcmp(opt, "data-format")) { + arg = append_argument(options, ARG__DATA_FORMAT); + FLAC__ASSERT(0 != option_argument); + if(!parse_data_format(option_argument, &(arg->value.data_format))) { + flac_fprintf(stderr, "ERROR (--%s): illegal data format \"%s\"\n", opt, option_argument); + ok = false; + } + options->data_format_is_binary = arg->value.data_format.is_binary; + options->data_format_is_binary_headerless = arg->value.data_format.is_headerless; + } + else if(0 == strcmp(opt, "application-data-format")) { + FLAC__ASSERT(0 != option_argument); + if(!parse_application_data_format(option_argument, &(options->application_data_format_is_hexdump))) { + flac_fprintf(stderr, "ERROR (--%s): illegal application data format \"%s\"\n", opt, option_argument); + ok = false; + } + } + else if(0 == strcmp(opt, "from-file")) { + arg = append_argument(options, ARG__FROM_FILE); + FLAC__ASSERT(0 != option_argument); + arg->value.from_file.file_name = local_strdup(option_argument); + } + else { + FLAC__ASSERT(0); + } + + return ok; +} + +void append_new_operation(CommandLineOptions *options, Operation operation) +{ + if(options->ops.capacity == 0) { + options->ops.capacity = 50; + if(0 == (options->ops.operations = malloc(sizeof(Operation) * options->ops.capacity))) + die("out of memory allocating space for option list"); + memset(options->ops.operations, 0, sizeof(Operation) * options->ops.capacity); + } + if(options->ops.capacity <= options->ops.num_operations) { + unsigned original_capacity = options->ops.capacity; + if(options->ops.capacity > UINT32_MAX / 2) /* overflow check */ + die("out of memory allocating space for option list"); + options->ops.capacity *= 2; + if(0 == (options->ops.operations = safe_realloc_mul_2op_(options->ops.operations, sizeof(Operation), /*times*/options->ops.capacity))) + die("out of memory allocating space for option list"); + memset(options->ops.operations + original_capacity, 0, sizeof(Operation) * (options->ops.capacity - original_capacity)); + } + + options->ops.operations[options->ops.num_operations++] = operation; +} + +void append_new_argument(CommandLineOptions *options, Argument argument) +{ + if(options->args.capacity == 0) { + options->args.capacity = 50; + if(0 == (options->args.arguments = malloc(sizeof(Argument) * options->args.capacity))) + die("out of memory allocating space for option list"); + memset(options->args.arguments, 0, sizeof(Argument) * options->args.capacity); + } + if(options->args.capacity <= options->args.num_arguments) { + unsigned original_capacity = options->args.capacity; + if(options->args.capacity > UINT32_MAX / 2) /* overflow check */ + die("out of memory allocating space for option list"); + options->args.capacity *= 2; + if(0 == (options->args.arguments = safe_realloc_mul_2op_(options->args.arguments, sizeof(Argument), /*times*/options->args.capacity))) + die("out of memory allocating space for option list"); + memset(options->args.arguments + original_capacity, 0, sizeof(Argument) * (options->args.capacity - original_capacity)); + } + + options->args.arguments[options->args.num_arguments++] = argument; +} + +Operation *append_major_operation(CommandLineOptions *options, OperationType type) +{ + Operation op; + memset(&op, 0, sizeof(op)); + op.type = type; + append_new_operation(options, op); + options->args.checks.num_major_ops++; + return options->ops.operations + (options->ops.num_operations - 1); +} + +Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type) +{ + Operation op; + memset(&op, 0, sizeof(op)); + op.type = type; + append_new_operation(options, op); + options->args.checks.num_shorthand_ops++; + return options->ops.operations + (options->ops.num_operations - 1); +} + +Argument *find_argument(CommandLineOptions *options, ArgumentType type) +{ + unsigned i; + for(i = 0; i < options->args.num_arguments; i++) + if(options->args.arguments[i].type == type) + return &options->args.arguments[i]; + return 0; +} + +Operation *find_shorthand_operation(CommandLineOptions *options, OperationType type) +{ + unsigned i; + for(i = 0; i < options->ops.num_operations; i++) + if(options->ops.operations[i].type == type) + return &options->ops.operations[i]; + return 0; +} + +Argument *append_argument(CommandLineOptions *options, ArgumentType type) +{ + Argument arg; + memset(&arg, 0, sizeof(arg)); + arg.type = type; + append_new_argument(options, arg); + return options->args.arguments + (options->args.num_arguments - 1); +} + +FLAC__bool parse_md5(const char *src, FLAC__byte dest[16]) +{ + unsigned i, d; + int c; + FLAC__ASSERT(0 != src); + if(strlen(src) != 32) + return false; + /* strtoul() accepts negative numbers which we do not want, so we do it the hard way */ + for(i = 0; i < 16; i++) { + c = (int)(*src++); + if(isdigit(c)) + d = (unsigned)(c - '0'); + else if(c >= 'a' && c <= 'f') + d = (unsigned)(c - 'a') + 10u; + else if(c >= 'A' && c <= 'F') + d = (unsigned)(c - 'A') + 10u; + else + return false; + d <<= 4; + c = (int)(*src++); + if(isdigit(c)) + d |= (unsigned)(c - '0'); + else if(c >= 'a' && c <= 'f') + d |= (unsigned)(c - 'a') + 10u; + else if(c >= 'A' && c <= 'F') + d |= (unsigned)(c - 'A') + 10u; + else + return false; + dest[i] = (FLAC__byte)d; + } + return true; +} + +FLAC__bool parse_uint32(const char *src, FLAC__uint32 *dest) +{ + FLAC__ASSERT(0 != src); + if(strlen(src) == 0 || strspn(src, "0123456789") != strlen(src)) + return false; + *dest = strtoul(src, 0, 10); + return true; +} + +FLAC__bool parse_uint64(const char *src, FLAC__uint64 *dest) +{ + FLAC__ASSERT(0 != src); + if(strlen(src) == 0 || strspn(src, "0123456789") != strlen(src)) + return false; + *dest = strtoull(src, 0, 10); + return true; +} + +FLAC__bool parse_string(const char *src, char **dest) +{ + if(0 == src || strlen(src) == 0) + return false; + *dest = strdup(src); + return true; +} + +FLAC__bool parse_vorbis_comment_field_name(const char *field_ref, char **name, const char **violation) +{ + static const char * const violations[] = { + "field name contains invalid character" + }; + + char *q, *s; + + s = local_strdup(field_ref); + + for(q = s; *q; q++) { + if(*q < 0x20 || *q > 0x7d || *q == 0x3d) { + free(s); + *violation = violations[0]; + return false; + } + } + + *name = s; + + return true; +} + +FLAC__bool parse_vorbis_comment_field_names(const char *field_ref, char **names, const char **violation) +{ + static const char * const violations[] = { + "field name contains invalid character" + }; + + char *q, *s; + + s = local_strdup(field_ref); + + for(q = s; *q; q++) { + if(*q < 0x20 || *q > 0x7d) { + free(s); + *violation = violations[0]; + return false; + } + } + + *names = s; + + return true; +} + +FLAC__bool parse_add_seekpoint(const char *in, char **out, const char **violation) +{ + static const char *garbled_ = "garbled specification"; + const unsigned n = strlen(in); + + FLAC__ASSERT(0 != in); + FLAC__ASSERT(0 != out); + + if(n == 0) { + *violation = "specification is empty"; + return false; + } + + if(n > strspn(in, "0123456789.Xsx")) { + *violation = "specification contains invalid character"; + return false; + } + + if(in[n-1] == 'X') { + if(n > 1) { + *violation = garbled_; + return false; + } + } + else if(in[n-1] == 's') { + if(n-1 > strspn(in, "0123456789.")) { + *violation = garbled_; + return false; + } + } + else if(in[n-1] == 'x') { + if(n-1 > strspn(in, "0123456789")) { + *violation = garbled_; + return false; + } + } + else { + if(n > strspn(in, "0123456789")) { + *violation = garbled_; + return false; + } + } + + *out = local_strdup(in); + return true; +} + +FLAC__bool parse_add_padding(const char *in, unsigned *out) +{ + FLAC__ASSERT(0 != in); + FLAC__ASSERT(0 != out); + *out = (unsigned)strtoul(in, 0, 10); + return *out < (1u << FLAC__STREAM_METADATA_LENGTH_LEN); +} + +FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out) +{ + char *p, *q, *s, *end; + long i; + unsigned entry; + + if(*in == '\0') + return false; + + s = local_strdup(in); + + /* first count the entries */ + for(out->num_entries = 1, p = strchr(s, ','); p; out->num_entries++, p = strchr(++p, ',')) + ; + + /* make space */ + FLAC__ASSERT(out->num_entries > 0); + if(0 == (out->entries = safe_malloc_mul_2op_(sizeof(unsigned), /*times*/out->num_entries))) + die("out of memory allocating space for option list"); + + /* load 'em up */ + entry = 0; + q = s; + while(q) { + FLAC__ASSERT(entry < out->num_entries); + if(0 != (p = strchr(q, ','))) + *p++ = '\0'; + if(!isdigit((int)(*q)) || (i = strtol(q, &end, 10)) < 0 || *end) { + free(s); + return false; + } + out->entries[entry++] = (unsigned)i; + q = p; + } + FLAC__ASSERT(entry == out->num_entries); + + free(s); + return true; +} + +FLAC__bool parse_block_type(const char *in, Argument_BlockType *out) +{ + char *p, *q, *r, *s; + unsigned entry; + + if(*in == '\0') + return false; + + s = local_strdup(in); + + /* first count the entries */ + for(out->num_entries = 1, p = strchr(s, ','); p; out->num_entries++, p = strchr(++p, ',')) + ; + + /* make space */ + FLAC__ASSERT(out->num_entries > 0); + if(0 == (out->entries = safe_malloc_mul_2op_(sizeof(Argument_BlockTypeEntry), /*times*/out->num_entries))) + die("out of memory allocating space for option list"); + + /* load 'em up */ + entry = 0; + q = s; + while(q) { + FLAC__ASSERT(entry < out->num_entries); + if(0 != (p = strchr(q, ','))) + *p++ = 0; + r = strchr(q, ':'); + if(r) + *r++ = '\0'; + if(0 != r && 0 != strcmp(q, "APPLICATION")) { + free(s); + return false; + } + if(0 == strcmp(q, "STREAMINFO")) { + out->entries[entry++].type = FLAC__METADATA_TYPE_STREAMINFO; + } + else if(0 == strcmp(q, "PADDING")) { + out->entries[entry++].type = FLAC__METADATA_TYPE_PADDING; + } + else if(0 == strcmp(q, "APPLICATION")) { + out->entries[entry].type = FLAC__METADATA_TYPE_APPLICATION; + out->entries[entry].filter_application_by_id = (0 != r); + if(0 != r) { + if(strlen(r) == sizeof (out->entries[entry].application_id)) { + memcpy(out->entries[entry].application_id, r, sizeof (out->entries[entry].application_id)); + } + else if(strlen(r) == 10 && FLAC__STRNCASECMP(r, "0x", 2) == 0 && strspn(r+2, "0123456789ABCDEFabcdef") == 8) { + FLAC__uint32 x = strtoul(r+2, 0, 16); + out->entries[entry].application_id[3] = (FLAC__byte)(x & 0xff); + out->entries[entry].application_id[2] = (FLAC__byte)((x>>=8) & 0xff); + out->entries[entry].application_id[1] = (FLAC__byte)((x>>=8) & 0xff); + out->entries[entry].application_id[0] = (FLAC__byte)((x>>=8) & 0xff); + } + else { + free(s); + return false; + } + } + entry++; + } + else if(0 == strcmp(q, "SEEKTABLE")) { + out->entries[entry++].type = FLAC__METADATA_TYPE_SEEKTABLE; + } + else if(0 == strcmp(q, "VORBIS_COMMENT")) { + out->entries[entry++].type = FLAC__METADATA_TYPE_VORBIS_COMMENT; + } + else if(0 == strcmp(q, "CUESHEET")) { + out->entries[entry++].type = FLAC__METADATA_TYPE_CUESHEET; + } + else if(0 == strcmp(q, "PICTURE")) { + out->entries[entry++].type = FLAC__METADATA_TYPE_PICTURE; + } + else { + free(s); + return false; + } + q = p; + } + FLAC__ASSERT(entry == out->num_entries); + + free(s); + return true; +} + +FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out) +{ + if(0 == strcmp(in, "binary-headerless")) { + out->is_binary = false; + out->is_headerless = true; + } + else if(0 == strcmp(in, "binary")) { + out->is_binary = true; + out->is_headerless = false; + } + else if(0 == strcmp(in, "text")) { + out->is_binary = false; + out->is_headerless = false; + } + else + return false; + return true; +} + +FLAC__bool parse_application_data_format(const char *in, FLAC__bool *out) +{ + if(0 == strcmp(in, "hexdump")) + *out = true; + else if(0 == strcmp(in, "text")) + *out = false; + else + return false; + return true; +} + +void undocumented_warning(const char *opt) +{ + flac_fprintf(stderr, "WARNING: undocumented option --%s should be used with caution,\n only for repairing a damaged STREAMINFO block\n", opt); +} diff --git a/vendor/flac/src/metaflac/options.h b/vendor/flac/src/metaflac/options.h new file mode 100644 index 0000000..984f2e1 --- /dev/null +++ b/vendor/flac/src/metaflac/options.h @@ -0,0 +1,221 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef metaflac__options_h +#define metaflac__options_h + +#include "FLAC/format.h" + +#if 0 +/*[JEC] was:#if HAVE_GETOPT_LONG*/ +/*[JEC] see flac/include/share/getopt.h as to why the change */ +# include +#else +# include "share/getopt.h" +#endif + +extern struct share__option long_options_[]; + +typedef enum { + OP__SHOW_MD5SUM, + OP__SHOW_MIN_BLOCKSIZE, + OP__SHOW_MAX_BLOCKSIZE, + OP__SHOW_MIN_FRAMESIZE, + OP__SHOW_MAX_FRAMESIZE, + OP__SHOW_SAMPLE_RATE, + OP__SHOW_CHANNELS, + OP__SHOW_BPS, + OP__SHOW_TOTAL_SAMPLES, + OP__SET_MD5SUM, + OP__SET_MIN_BLOCKSIZE, + OP__SET_MAX_BLOCKSIZE, + OP__SET_MIN_FRAMESIZE, + OP__SET_MAX_FRAMESIZE, + OP__SET_SAMPLE_RATE, + OP__SET_CHANNELS, + OP__SET_BPS, + OP__SET_TOTAL_SAMPLES, + OP__SHOW_VC_VENDOR, + OP__SHOW_VC_FIELD, + OP__REMOVE_VC_ALL, + OP__REMOVE_VC_ALL_EXCEPT, + OP__REMOVE_VC_FIELD, + OP__REMOVE_VC_FIRSTFIELD, + OP__SET_VC_FIELD, + OP__IMPORT_VC_FROM, + OP__EXPORT_VC_TO, + OP__IMPORT_CUESHEET_FROM, + OP__EXPORT_CUESHEET_TO, + OP__IMPORT_PICTURE_FROM, + OP__EXPORT_PICTURE_TO, + OP__ADD_SEEKPOINT, + OP__ADD_REPLAY_GAIN, + OP__SCAN_REPLAY_GAIN, + OP__ADD_PADDING, + OP__LIST, + OP__APPEND, + OP__REMOVE, + OP__REMOVE_ALL, + OP__MERGE_PADDING, + OP__SORT_PADDING +} OperationType; + +typedef enum { + ARG__BLOCK_NUMBER, + ARG__BLOCK_TYPE, + ARG__EXCEPT_BLOCK_TYPE, + ARG__DATA_FORMAT, + ARG__FROM_FILE +} ArgumentType; + +typedef struct { + FLAC__byte value[16]; +} Argument_StreaminfoMD5; + +typedef struct { + FLAC__uint32 value; +} Argument_StreaminfoUInt32; + +typedef struct { + FLAC__uint64 value; +} Argument_StreaminfoUInt64; + +typedef struct { + char *value; +} Argument_VcFieldName; + +typedef struct { + char *field; /* the whole field as passed on the command line, i.e. "NAME=VALUE" */ + char *field_name; + /* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */ + unsigned field_value_length; + char *field_value; + FLAC__bool field_value_from_file; /* true if field_value holds a filename for the value, false for plain value */ +} Argument_VcField; + +typedef struct { + char *value; +} Argument_String; + +typedef struct { + unsigned num_entries; + unsigned *entries; +} Argument_BlockNumber; + +typedef struct { + FLAC__MetadataType type; + char application_id[4]; /* only relevant if type == FLAC__STREAM_METADATA_TYPE_APPLICATION */ + FLAC__bool filter_application_by_id; +} Argument_BlockTypeEntry; + +typedef struct { + unsigned num_entries; + Argument_BlockTypeEntry *entries; +} Argument_BlockType; + +typedef struct { + FLAC__bool is_binary; + FLAC__bool is_headerless; +} Argument_DataFormat; + +typedef struct { + char *file_name; +} Argument_FromFile; + +typedef struct { + char *specification; +} Argument_AddSeekpoint; + +typedef struct { + char *filename; + Argument_AddSeekpoint *add_seekpoint_link; +} Argument_ImportCuesheetFrom; + +typedef struct { + char *filename; + const Argument_BlockNumber *block_number_link; /* may be NULL to mean 'first PICTURE block' */ +} Argument_ExportPictureTo; + +typedef struct { + unsigned length; +} Argument_AddPadding; + +typedef struct { + OperationType type; + union { + Argument_StreaminfoMD5 streaminfo_md5; + Argument_StreaminfoUInt32 streaminfo_uint32; + Argument_StreaminfoUInt64 streaminfo_uint64; + Argument_VcFieldName vc_field_name; + Argument_VcField vc_field; + Argument_String filename; + Argument_String specification; + Argument_ImportCuesheetFrom import_cuesheet_from; + Argument_ExportPictureTo export_picture_to; + Argument_AddSeekpoint add_seekpoint; + Argument_AddPadding add_padding; + } argument; +} Operation; + +typedef struct { + ArgumentType type; + union { + Argument_BlockNumber block_number; + Argument_BlockType block_type; + Argument_DataFormat data_format; + Argument_FromFile from_file; + } value; +} Argument; + +typedef struct { + FLAC__bool preserve_modtime; + FLAC__bool prefix_with_filename; + FLAC__bool utf8_convert; + FLAC__bool use_padding; + FLAC__bool cued_seekpoints; + FLAC__bool show_long_help; + FLAC__bool show_version; + FLAC__bool data_format_is_binary; + FLAC__bool data_format_is_binary_headerless; + FLAC__bool application_data_format_is_hexdump; + struct { + Operation *operations; + unsigned num_operations; + unsigned capacity; + } ops; + struct { + struct { + unsigned num_shorthand_ops; + unsigned num_major_ops; + FLAC__bool has_block_type; + FLAC__bool has_except_block_type; + } checks; + Argument *arguments; + unsigned num_arguments; + unsigned capacity; + } args; + unsigned num_files; + char **filenames; +} CommandLineOptions; + +void init_options(CommandLineOptions *options); +FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options); +void free_options(CommandLineOptions *options); + +#endif diff --git a/vendor/flac/src/metaflac/usage.c b/vendor/flac/src/metaflac/usage.c new file mode 100644 index 0000000..58afc0e --- /dev/null +++ b/vendor/flac/src/metaflac/usage.c @@ -0,0 +1,349 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "utils.h" +#include "usage.h" +#include "FLAC/format.h" +#include +#include +#include "share/compat.h" + +static void usage_header(FILE *out) +{ + fprintf(out, "==============================================================================\n"); + fprintf(out, "metaflac - Command-line FLAC metadata editor version %s\n", FLAC__VERSION_STRING); + fprintf(out, "Copyright (C) 2001-2009 Josh Coalson\n"); + fprintf(out, "Copyright (C) 2011-2023 Xiph.Org Foundation\n"); + fprintf(out, "\n"); + fprintf(out, "This program is free software; you can redistribute it and/or\n"); + fprintf(out, "modify it under the terms of the GNU General Public License\n"); + fprintf(out, "as published by the Free Software Foundation; either version 2\n"); + fprintf(out, "of the License, or (at your option) any later version.\n"); + fprintf(out, "\n"); + fprintf(out, "This program is distributed in the hope that it will be useful,\n"); + fprintf(out, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + fprintf(out, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + fprintf(out, "GNU General Public License for more details.\n"); + fprintf(out, "\n"); + fprintf(out, "You should have received a copy of the GNU General Public License along\n"); + fprintf(out, "with this program; if not, write to the Free Software Foundation, Inc.,\n"); + fprintf(out, "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n"); + fprintf(out, "==============================================================================\n"); +} + +static void usage_summary(FILE *out) +{ + fprintf(out, "Usage:\n"); + fprintf(out, " metaflac [options] [operations] FLACfile [FLACfile ...]\n"); + fprintf(out, "\n"); + fprintf(out, "Use metaflac to list, add, remove, or edit metadata in one or more FLAC files.\n"); + fprintf(out, "You may perform one major operation, or many shorthand operations at a time.\n"); + fprintf(out, "\n"); + fprintf(out, "Options:\n"); + fprintf(out, "--preserve-modtime Preserve the original modification time in spite of edits\n"); + fprintf(out, "--with-filename Prefix each output line with the FLAC file name\n"); + fprintf(out, " (the default if more than one FLAC file is specified).\n"); + fprintf(out, " This option has no effect for options exporting to a\n"); + fprintf(out, " file, like --export-tags-to.\n"); + fprintf(out, "--no-filename Do not prefix each output line with the FLAC file name\n"); + fprintf(out, " (the default if only one FLAC file is specified)\n"); + fprintf(out, "--no-utf8-convert Do not convert tags from UTF-8 to local charset,\n"); + fprintf(out, " or vice versa. This is useful for scripts, and setting\n"); + fprintf(out, " tags in situations where the locale is wrong.\n"); + fprintf(out, "--dont-use-padding By default metaflac tries to use padding where possible\n"); + fprintf(out, " to avoid rewriting the entire file if the metadata size\n"); + fprintf(out, " changes. Use this option to tell metaflac to not take\n"); + fprintf(out, " advantage of padding this way.\n"); +} + +int short_usage(const char *message, ...) +{ + va_list args; + + if(message) { + va_start(args, message); + + (void) vfprintf(stderr, message, args); + + va_end(args); + + } + usage_header(stderr); + flac_fprintf(stderr, "\n"); + flac_fprintf(stderr, "This is the short help; for full help use 'metaflac --help'\n"); + flac_fprintf(stderr, "\n"); + usage_summary(stderr); + + return message? 1 : 0; +} + +int long_usage(const char *message, ...) +{ + FILE *out = (message? stderr : stdout); + va_list args; + + if(message) { + va_start(args, message); + + (void) vfprintf(stderr, message, args); + + va_end(args); + + } + usage_header(out); + fprintf(out, "\n"); + usage_summary(out); + fprintf(out, "\n"); + fprintf(out, "Shorthand operations:\n"); + fprintf(out, "--show-md5sum Show the MD5 signature from the STREAMINFO block.\n"); + fprintf(out, "--show-min-blocksize Show the minimum block size from the STREAMINFO block.\n"); + fprintf(out, "--show-max-blocksize Show the maximum block size from the STREAMINFO block.\n"); + fprintf(out, "--show-min-framesize Show the minimum frame size from the STREAMINFO block.\n"); + fprintf(out, "--show-max-framesize Show the maximum frame size from the STREAMINFO block.\n"); + fprintf(out, "--show-sample-rate Show the sample rate from the STREAMINFO block.\n"); + fprintf(out, "--show-channels Show the number of channels from the STREAMINFO block.\n"); + fprintf(out, "--show-bps Show the # of bits per sample from the STREAMINFO block.\n"); + fprintf(out, "--show-total-samples Show the total # of samples from the STREAMINFO block.\n"); + fprintf(out, "\n"); + fprintf(out, "--show-vendor-tag Show the vendor string from the VORBIS_COMMENT block.\n"); + fprintf(out, "--show-tag=NAME Show all tags where the field name matches 'NAME'.\n"); + fprintf(out, "--show-all-tags Show all tags. This is an alias for --export-tags-to=-.\n"); + fprintf(out, "--remove-tag=NAME Remove all tags whose field name is 'NAME'.\n"); + fprintf(out, "--remove-first-tag=NAME Remove first tag whose field name is 'NAME'.\n"); + fprintf(out, "--remove-all-tags Remove all tags, leaving only the vendor string.\n"); + fprintf(out, "--remove-all-tags-except=NAME1[=NAME2[=...]] Remove all tags, except the vendor\n"); + fprintf(out, " string and the tag names specified. Tag names must be\n"); + fprintf(out, " separated by an = character.\n"); + fprintf(out, "--set-tag=FIELD Add a tag. The FIELD must comply with the Vorbis comment\n"); + fprintf(out, " spec, of the form \"NAME=VALUE\". If there is currently\n"); + fprintf(out, " no tag block, one will be created.\n"); + fprintf(out, "--set-tag-from-file=FIELD Like --set-tag, except the VALUE is a filename\n"); + fprintf(out, " whose contents will be read verbatim to set the tag value.\n"); + fprintf(out, " Unless --no-utf8-convert is specified, the contents will\n"); + fprintf(out, " be converted to UTF-8 from the local charset. This can\n"); + fprintf(out, " be used to store a cuesheet in a tag (e.g.\n"); + fprintf(out, " --set-tag-from-file=\"CUESHEET=image.cue\"). Do not try\n"); + fprintf(out, " to store binary data in tag fields! Use APPLICATION\n"); + fprintf(out, " blocks for that.\n"); + fprintf(out, "--import-tags-from=FILE Import tags from a file. Use '-' for stdin. Each line\n"); + fprintf(out, " should be of the form NAME=VALUE. Multi-line comments\n"); + fprintf(out, " are currently not supported. Specify --remove-all-tags\n"); + fprintf(out, " and/or --no-utf8-convert before --import-tags-from if\n"); + fprintf(out, " necessary. If FILE is '-' (stdin), only one FLAC file\n"); + fprintf(out, " may be specified.\n"); + fprintf(out, "--export-tags-to=FILE Export tags to a file. Use '-' for stdout. Each line\n"); + fprintf(out, " will be of the form NAME=VALUE. Specify\n"); + fprintf(out, " --no-utf8-convert if necessary.\n"); + fprintf(out, "--import-cuesheet-from=FILE Import a cuesheet from a file. Use '-' for stdin.\n"); + fprintf(out, " Only one FLAC file may be specified. A seekpoint will be\n"); + fprintf(out, " added for each index point in the cuesheet to the\n"); + fprintf(out, " SEEKTABLE unless --no-cued-seekpoints is specified.\n"); + fprintf(out, "--export-cuesheet-to=FILE Export CUESHEET block to a cuesheet file, suitable\n"); + fprintf(out, " for use by CD authoring software. Use '-' for stdout.\n"); + fprintf(out, " Only one FLAC file may be specified on the command line.\n"); + fprintf(out, "--import-picture-from=FILENAME|SPECIFICATION Import a picture and store it in a\n"); + fprintf(out, " PICTURE block. Either a filename for the picture file or\n"); + fprintf(out, " a more complete specification form can be used. The\n"); + fprintf(out, " SPECIFICATION is a string whose parts are separated by |\n"); + fprintf(out, " characters. Some parts may be left empty to invoke\n"); + fprintf(out, " default values. FILENAME is just shorthand for\n"); + fprintf(out, " \"||||FILENAME\". The format of SPECIFICATION is:\n"); + fprintf(out, " [TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE\n"); + fprintf(out, " TYPE is optional; it is a number from one of:\n"); + fprintf(out, " 0: Other\n"); + fprintf(out, " 1: 32x32 pixels 'file icon' (PNG only)\n"); + fprintf(out, " 2: Other file icon\n"); + fprintf(out, " 3: Cover (front)\n"); + fprintf(out, " 4: Cover (back)\n"); + fprintf(out, " 5: Leaflet page\n"); + fprintf(out, " 6: Media (e.g. label side of CD)\n"); + fprintf(out, " 7: Lead artist/lead performer/soloist\n"); + fprintf(out, " 8: Artist/performer\n"); + fprintf(out, " 9: Conductor\n"); + fprintf(out, " 10: Band/Orchestra\n"); + fprintf(out, " 11: Composer\n"); + fprintf(out, " 12: Lyricist/text writer\n"); + fprintf(out, " 13: Recording Location\n"); + fprintf(out, " 14: During recording\n"); + fprintf(out, " 15: During performance\n"); + fprintf(out, " 16: Movie/video screen capture\n"); + fprintf(out, " 17: A bright coloured fish\n"); + fprintf(out, " 18: Illustration\n"); + fprintf(out, " 19: Band/artist logotype\n"); + fprintf(out, " 20: Publisher/Studio logotype\n"); + fprintf(out, " The default is 3 (front cover). There may only be one picture each\n"); + fprintf(out, " of type 1 and 2 in a file.\n"); + fprintf(out, " MIME-TYPE is optional; if left blank, it will be detected from the\n"); + fprintf(out, " file. For best compatibility with players, use pictures with MIME\n"); + fprintf(out, " type image/jpeg or image/png. The MIME type can also be --> to\n"); + fprintf(out, " mean that FILE is actually a URL to an image, though this use is\n"); + fprintf(out, " discouraged.\n"); + fprintf(out, " DESCRIPTION is optional; the default is an empty string\n"); + fprintf(out, " The next part specifies the resolution and color information. If\n"); + fprintf(out, " the MIME-TYPE is image/jpeg, image/png, or image/gif, you can\n"); + fprintf(out, " usually leave this empty and they can be detected from the file.\n"); + fprintf(out, " Otherwise, you must specify the width in pixels, height in pixels,\n"); + fprintf(out, " and color depth in bits-per-pixel. If the image has indexed colors\n"); + fprintf(out, " you should also specify the number of colors used.\n"); + fprintf(out, " FILE is the path to the picture file to be imported, or the URL if\n"); + fprintf(out, " MIME type is -->\n"); + fprintf(out, "--export-picture-to=FILE Export PICTURE block to a file. Use '-' for stdout.\n"); + fprintf(out, " Only one FLAC file may be specified. The first PICTURE\n"); + fprintf(out, " block will be exported unless --export-picture-to is\n"); + fprintf(out, " preceded by a --block-number=# option to specify the exact\n"); + fprintf(out, " metadata block to extract. Note that the block number is\n"); + fprintf(out, " the one shown by --list.\n"); + fprintf(out, "--add-replay-gain Calculates the title and album gains/peaks of the given\n"); + fprintf(out, " FLAC files as if all the files were part of one album,\n"); + fprintf(out, " then stores them in the VORBIS_COMMENT block. The tags\n"); + fprintf(out, " are the same as those used by vorbisgain. Existing\n"); + fprintf(out, " ReplayGain tags will be replaced. If only one FLAC file\n"); + fprintf(out, " is given, the album and title gains will be the same.\n"); + fprintf(out, " Since this operation requires two passes, it is always\n"); + fprintf(out, " executed last, after all other operations have been\n"); + fprintf(out, " completed and written to disk. All FLAC files specified\n"); + fprintf(out, " must have the same resolution, sample rate, and number\n"); + fprintf(out, " of channels. Only mono and stereo files are allowed,\n"); + fprintf(out, " and the sample rate must be 8, 11.025, 12, 16, 18.9,\n"); + fprintf(out, " 22.05, 24, 28, 32, 36, 37.8, 44.1, 48, 56, 64, 72, 75.6,\n"); + fprintf(out, " 88.2, 96, 112, 128, 144, 151.2, 176.4, 192, 224, 256,\n"); + fprintf(out, " 288, 302.4, 352.8, 384, 448, 512, 576, or 604.8 kHz.\n"); + fprintf(out, "--scan-replay-gain Like --add-replay-gain, but only analyzes the files\n"); + fprintf(out, " rather than writing them to tags.\n"); + fprintf(out, "--remove-replay-gain Removes the ReplayGain tags.\n"); + fprintf(out, "--add-seekpoint={#|X|#x|#s} Add seek points to a SEEKTABLE block\n"); + fprintf(out, " # : a specific sample number for a seek point\n"); + fprintf(out, " X : a placeholder point (always goes at the end of the SEEKTABLE)\n"); + fprintf(out, " #x : # evenly spaced seekpoints, the first being at sample 0\n"); + fprintf(out, " #s : a seekpoint every # seconds; # does not have to be a whole number\n"); + fprintf(out, " If no SEEKTABLE block exists, one will be created. If\n"); + fprintf(out, " one already exists, points will be added to the existing\n"); + fprintf(out, " table, and any duplicates will be turned into placeholder\n"); + fprintf(out, " points. You may use many --add-seekpoint options; the\n"); + fprintf(out, " resulting SEEKTABLE will be the unique-ified union of\n"); + fprintf(out, " all such values. Example: --add-seekpoint=100x\n"); + fprintf(out, " --add-seekpoint=3.5s will add 100 evenly spaced\n"); + fprintf(out, " seekpoints and a seekpoint every 3.5 seconds.\n"); + fprintf(out, "--add-padding=length Add a padding block of the given length (in bytes).\n"); + fprintf(out, " The overall length of the new block will be 4 + length;\n"); + fprintf(out, " the extra 4 bytes is for the metadata block header.\n"); + fprintf(out, "\n"); + fprintf(out, "Major operations:\n"); + fprintf(out, "--version\n"); + fprintf(out, " Show the metaflac version number.\n"); + fprintf(out, "--list\n"); + fprintf(out, " List the contents of one or more metadata blocks to stdout. By default,\n"); + fprintf(out, " all metadata blocks are listed in text format. Use the following options\n"); + fprintf(out, " to change this behavior:\n"); + fprintf(out, "\n"); + fprintf(out, " --block-number=#[,#[...]]\n"); + fprintf(out, " An optional comma-separated list of block numbers to display. The first\n"); + fprintf(out, " block, the STREAMINFO block, is block 0.\n"); + fprintf(out, "\n"); + fprintf(out, " --block-type=type[,type[...]]\n"); + fprintf(out, " --except-block-type=type[,type[...]]\n"); + fprintf(out, " An optional comma-separated list of block types to be included or ignored\n"); + fprintf(out, " with this option. Use only one of --block-type or --except-block-type.\n"); + fprintf(out, " The valid block types are: STREAMINFO, PADDING, APPLICATION, SEEKTABLE,\n"); + fprintf(out, " VORBIS_COMMENT. You may narrow down the types of APPLICATION blocks\n"); + fprintf(out, " displayed as follows:\n"); + fprintf(out, " APPLICATION:abcd The APPLICATION block(s) whose textual repre-\n"); + fprintf(out, " sentation of the 4-byte ID is \"abcd\"\n"); + fprintf(out, " APPLICATION:0xXXXXXXXX The APPLICATION block(s) whose hexadecimal big-\n"); + fprintf(out, " endian representation of the 4-byte ID is\n"); + fprintf(out, " \"0xXXXXXXXX\". For the example \"abcd\" above the\n"); + fprintf(out, " hexadecimal equivalalent is 0x61626364\n"); + fprintf(out, "\n"); + fprintf(out, " NOTE: if both --block-number and --[except-]block-type are specified,\n"); + fprintf(out, " the result is the logical AND of both arguments.\n"); + fprintf(out, "\n"); + fprintf(out, " --data-format=binary|binary-headerless|text\n"); + fprintf(out, " By default a human-readable text representation of the data is displayed.\n"); + fprintf(out, " You may specify --data-format=binary to dump the raw binary form of each\n"); + fprintf(out, " metadata block. Specify --data-format=binary-headerless to omit output of\n"); + fprintf(out, " metadata block headers, including the id of APPLICATION metadata blocks.\n"); + fprintf(out, " The output can be read in using a subsequent call to\n"); + fprintf(out, " \"metaflac --append\"\n"); + fprintf(out, "\n"); + fprintf(out, " --application-data-format=hexdump|text\n"); + fprintf(out, " If the application block you are displaying contains binary data but your\n"); + fprintf(out, " --data-format=text, you can display a hex dump of the application data\n"); + fprintf(out, " contents instead using --application-data-format=hexdump\n"); + fprintf(out, "\n"); + fprintf(out, "--append\n"); + fprintf(out, " Insert a metadata block from a file. This must be a binary block as\n"); + fprintf(out, " exported with --list --data-format=binary. The insertion point is\n"); + fprintf(out, " defined with --block-number=#. The new block will be added after the\n"); + fprintf(out, " given block number. This prevents the illegal insertion of a block\n"); + fprintf(out, " before the first STREAMINFO block. You may not --append another\n"); + fprintf(out, " STREAMINFO block. It is possible to copy a metadata block from one\n"); + fprintf(out, " file to another with this option. For example use\n"); + fprintf(out, " metaflac --list --data-format=binary --block-number=6 file.flac > block\n"); + fprintf(out, " to export the block, and then import it with\n"); + fprintf(out, " metaflac --append anotherfile.flac < block\n"); + fprintf(out, " Insert a metadata block from a file. The input file must be in the same\n"); + fprintf(out, " format as generated with --list.\n"); + fprintf(out, "\n"); + fprintf(out, " --block-number=#\n"); + fprintf(out, " Specify the insertion point (defaults to last block). The new block will\n"); + fprintf(out, " be added after the given block number. This prevents the illegal insertion\n"); + fprintf(out, " of a block before the first STREAMINFO block. You may not --append another\n"); + fprintf(out, " STREAMINFO block.\n"); + fprintf(out, "\n"); +#if 0 + /*@@@ not implemented yet */ + fprintf(out, " --from-file=filename\n"); + fprintf(out, " Mandatory 'option' to specify the input file containing the block contents.\n"); + fprintf(out, "\n"); + fprintf(out, " --data-format=binary|text\n"); + fprintf(out, " By default the block contents are assumed to be in binary format. You can\n"); + fprintf(out, " override this by specifying --data-format=text\n"); + fprintf(out, "\n"); +#endif + fprintf(out, "--remove\n"); + fprintf(out, " Remove one or more metadata blocks from the metadata. Unless\n"); + fprintf(out, " --dont-use-padding is specified, the blocks will be replaced with padding.\n"); + fprintf(out, " You may not remove the STREAMINFO block.\n"); + fprintf(out, "\n"); + fprintf(out, " --block-number=#[,#[...]]\n"); + fprintf(out, " --block-type=type[,type[...]]\n"); + fprintf(out, " --except-block-type=type[,type[...]]\n"); + fprintf(out, " See --list above for usage.\n"); + fprintf(out, "\n"); + fprintf(out, " NOTE: if both --block-number and --[except-]block-type are specified,\n"); + fprintf(out, " the result is the logical AND of both arguments.\n"); + fprintf(out, "\n"); + fprintf(out, "--remove-all\n"); + fprintf(out, " Remove all metadata blocks (except the STREAMINFO block) from the\n"); + fprintf(out, " metadata. Unless --dont-use-padding is specified, the blocks will be\n"); + fprintf(out, " replaced with padding.\n"); + fprintf(out, "\n"); + fprintf(out, "--merge-padding\n"); + fprintf(out, " Merge adjacent PADDING blocks into single blocks.\n"); + fprintf(out, "\n"); + fprintf(out, "--sort-padding\n"); + fprintf(out, " Move all PADDING blocks to the end of the metadata and merge them into a\n"); + fprintf(out, " single block.\n"); + + return message? 1 : 0; +} diff --git a/vendor/flac/src/metaflac/usage.h b/vendor/flac/src/metaflac/usage.h new file mode 100644 index 0000000..1366417 --- /dev/null +++ b/vendor/flac/src/metaflac/usage.h @@ -0,0 +1,26 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef metaflac__usage_h +#define metaflac__usage_h + +int short_usage(const char *message, ...); +int long_usage(const char *message, ...); + +#endif diff --git a/vendor/flac/src/metaflac/utils.c b/vendor/flac/src/metaflac/utils.c new file mode 100644 index 0000000..045719a --- /dev/null +++ b/vendor/flac/src/metaflac/utils.c @@ -0,0 +1,282 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include "utils.h" +#include "FLAC/assert.h" +#include "share/alloc.h" +#include "share/safe_str.h" +#include "share/utf8.h" +#include "share/compat.h" + +void die(const char *message) +{ + FLAC__ASSERT(0 != message); + flac_fprintf(stderr, "ERROR: %s\n", message); + exit(1); +} + +#ifdef FLAC__VALGRIND_TESTING +size_t local_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#endif + +char *local_strdup(const char *source) +{ + char *ret; + FLAC__ASSERT(0 != source); + if(0 == (ret = strdup(source))) + die("out of memory during strdup()"); + return ret; +} + +void local_strcat(char **dest, const char *source) +{ + size_t ndest, nsource, outlen; + + FLAC__ASSERT(0 != dest); + FLAC__ASSERT(0 != source); + + ndest = *dest ? strlen(*dest) : 0; + nsource = strlen(source); + outlen = ndest + nsource + 1; + + if(nsource == 0) + return; + + *dest = safe_realloc_add_3op_(*dest, ndest, /*+*/nsource, /*+*/1); + if(*dest == NULL) + die("out of memory growing string"); + /* If ndest == 0, strlen in safe_strncat reads + * uninitialized data. To prevent that, set first character + * to zero */ + if(ndest == 0) + *dest[0] = 0; + safe_strncat(*dest, source, outlen); +} + +static inline int local_isprint(int c) +{ + if (c < 32) return 0; + if (c > 127) return 0; + return isprint(c); +} + +void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent) +{ + unsigned i, left = bytes; + const FLAC__byte *b = buf; + + for(i = 0; i < bytes; i += 16) { + flac_printf("%s%s", filename? filename:"", filename? ":":""); + printf("%s%08X: " + "%02X %02X %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X %02X %02X %02X %02X " + "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + indent, i, + left > 0? (unsigned char)b[ 0] : 0, + left > 1? (unsigned char)b[ 1] : 0, + left > 2? (unsigned char)b[ 2] : 0, + left > 3? (unsigned char)b[ 3] : 0, + left > 4? (unsigned char)b[ 4] : 0, + left > 5? (unsigned char)b[ 5] : 0, + left > 6? (unsigned char)b[ 6] : 0, + left > 7? (unsigned char)b[ 7] : 0, + left > 8? (unsigned char)b[ 8] : 0, + left > 9? (unsigned char)b[ 9] : 0, + left > 10? (unsigned char)b[10] : 0, + left > 11? (unsigned char)b[11] : 0, + left > 12? (unsigned char)b[12] : 0, + left > 13? (unsigned char)b[13] : 0, + left > 14? (unsigned char)b[14] : 0, + left > 15? (unsigned char)b[15] : 0, + (left > 0) ? (local_isprint(b[ 0]) ? b[ 0] : '.') : ' ', + (left > 1) ? (local_isprint(b[ 1]) ? b[ 1] : '.') : ' ', + (left > 2) ? (local_isprint(b[ 2]) ? b[ 2] : '.') : ' ', + (left > 3) ? (local_isprint(b[ 3]) ? b[ 3] : '.') : ' ', + (left > 4) ? (local_isprint(b[ 4]) ? b[ 4] : '.') : ' ', + (left > 5) ? (local_isprint(b[ 5]) ? b[ 5] : '.') : ' ', + (left > 6) ? (local_isprint(b[ 6]) ? b[ 6] : '.') : ' ', + (left > 7) ? (local_isprint(b[ 7]) ? b[ 7] : '.') : ' ', + (left > 8) ? (local_isprint(b[ 8]) ? b[ 8] : '.') : ' ', + (left > 9) ? (local_isprint(b[ 9]) ? b[ 9] : '.') : ' ', + (left > 10) ? (local_isprint(b[10]) ? b[10] : '.') : ' ', + (left > 11) ? (local_isprint(b[11]) ? b[11] : '.') : ' ', + (left > 12) ? (local_isprint(b[12]) ? b[12] : '.') : ' ', + (left > 13) ? (local_isprint(b[13]) ? b[13] : '.') : ' ', + (left > 14) ? (local_isprint(b[14]) ? b[14] : '.') : ' ', + (left > 15) ? (local_isprint(b[15]) ? b[15] : '.') : ' ' + ); + left -= 16; + b += 16; + } +} + +void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *format, ...) +{ + const FLAC__Metadata_ChainStatus status = FLAC__metadata_chain_status(chain); + va_list args; + + FLAC__ASSERT(0 != format); + + va_start(args, format); + + (void) flac_vfprintf(stderr, format, args); + + va_end(args); + + flac_fprintf(stderr, ", status = \"%s\"\n", FLAC__Metadata_ChainStatusString[status]); + + if(status == FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE) { + flac_fprintf(stderr, "\n" + "The FLAC file could not be opened. Most likely the file does not exist\n" + "or is not readable.\n" + ); + } + else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE) { + flac_fprintf(stderr, "\n" + "The file does not appear to be a FLAC file.\n" + ); + } + else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE) { + flac_fprintf(stderr, "\n" + "The FLAC file does not have write permissions.\n" + ); + } + else if(status == FLAC__METADATA_CHAIN_STATUS_BAD_METADATA) { + flac_fprintf(stderr, "\n" + "The metadata to be written does not conform to the FLAC metadata\n" + "specifications.\n" + ); + } + else if(status == FLAC__METADATA_CHAIN_STATUS_READ_ERROR) { + flac_fprintf(stderr, "\n" + "There was an error while reading the FLAC file.\n" + ); + } + else if(status == FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR) { + flac_fprintf(stderr, "\n" + "There was an error while writing FLAC file; most probably the disk is\n" + "full.\n" + ); + } + else if(status == FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR) { + flac_fprintf(stderr, "\n" + "There was an error removing the temporary FLAC file.\n" + ); + } +} + +FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation) +{ + static const char * const violations[] = { + "field name contains invalid character", + "field contains no '=' character" + }; + + char *p, *q, *s; + + if(0 != field) + *field = local_strdup(field_ref); + + s = local_strdup(field_ref); + + if(0 == (p = strchr(s, '='))) { + free(s); + *violation = violations[1]; + return false; + } + *p++ = '\0'; + + for(q = s; *q; q++) { + if(*q < 0x20 || *q > 0x7d || *q == 0x3d) { + free(s); + *violation = violations[0]; + return false; + } + } + + *name = local_strdup(s); + *value = local_strdup(p); + *length = strlen(p); + + free(s); + return true; +} + +void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f) +{ + if(0 != entry->entry) { + if(filename) + flac_fprintf(f, "%s:", filename); + + if(!raw) { + /* + * WATCHOUT: comments that contain an embedded null will + * be truncated by utf_decode(). + */ +#ifdef _WIN32 /* if we are outputting to console, we need to use proper print functions to show unicode characters */ + if (f == stdout || f == stderr) { + flac_fprintf(f, "%s", entry->entry); + } else { +#endif + char *converted; + + if(utf8_decode((const char *)entry->entry, &converted) >= 0) { + (void) local_fwrite(converted, 1, strlen(converted), f); + free(converted); + } + else { + (void) local_fwrite(entry->entry, 1, entry->length, f); + } +#ifdef _WIN32 + } +#endif + } + else { + (void) local_fwrite(entry->entry, 1, entry->length, f); + } + } + + putc('\n', f); +} + +void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f) +{ + unsigned i; + const unsigned field_name_length = (0 != field_name)? strlen(field_name) : 0; + + for(i = 0; i < num_entries; i++) { + if(0 == field_name || FLAC__metadata_object_vorbiscomment_entry_matches(entry[i], field_name, field_name_length)) + write_vc_field(filename, entry + i, raw, f); + } +} diff --git a/vendor/flac/src/metaflac/utils.h b/vendor/flac/src/metaflac/utils.h new file mode 100644 index 0000000..972a450 --- /dev/null +++ b/vendor/flac/src/metaflac/utils.h @@ -0,0 +1,47 @@ +/* metaflac - Command-line FLAC metadata editor + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef metaflac__utils_h +#define metaflac__utils_h + +#include "FLAC/metadata.h" +#include /* for FILE */ + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +#undef stderr +#define stderr stdout +#endif + +void die(const char *message); +#ifdef FLAC__VALGRIND_TESTING +size_t local_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +#else +#define local_fwrite fwrite +#endif +char *local_strdup(const char *source); +void local_strcat(char **dest, const char *source); +void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent); +void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *format, ...); + +FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation); + +void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f); +void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f); + +#endif diff --git a/vendor/flac/src/metaflac/version.rc b/vendor/flac/src/metaflac/version.rc new file mode 100644 index 0000000..5117202 --- /dev/null +++ b/vendor/flac/src/metaflac/version.rc @@ -0,0 +1,38 @@ +#include +#include "config.h" + +#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE) +# ifdef GIT_COMMIT_TAG +# define VERSIONSTRING GIT_COMMIT_TAG +# else +# define VERSIONSTRING "git-" GIT_COMMIT_HASH +# endif +#else +# define VERSIONSTRING PACKAGE_VERSION +#endif + +#define xstr(s) str(s) +#define str(s) #s + +VS_VERSION_INFO VERSIONINFO +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "metaflac command line tool for Windows" + VALUE "ProductName", "Free Lossless Audio Codec" + VALUE "ProductVersion", VERSIONSTRING + VALUE "CompanyName", "Xiph.Org" + VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/vendor/flac/src/share/Makefile.am b/vendor/flac/src/share/Makefile.am new file mode 100644 index 0000000..caf6122 --- /dev/null +++ b/vendor/flac/src/share/Makefile.am @@ -0,0 +1,73 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2002-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This file is part the FLAC project. FLAC is comprised of several +# components distributed under different licenses. The codec libraries +# are distributed under Xiph.Org's BSD-like license (see the file +# COPYING.Xiph in this distribution). All other programs, libraries, and +# plugins are distributed under the GPL (see COPYING.GPL). The documentation +# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the +# FLAC distribution contains at the top the terms under which it may be +# distributed. +# +# Since this particular file is relevant to all components of FLAC, +# it may be distributed under the Xiph.Org license, which is the least +# restrictive of those mentioned above. See the file COPYING.Xiph in this +# distribution. + +AUTOMAKE_OPTIONS = subdir-objects + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include + +EXTRA_DIST = \ + README \ + getopt/CMakeLists.txt \ + grabbag/CMakeLists.txt \ + replaygain_analysis/CMakeLists.txt \ + replaygain_synthesis/CMakeLists.txt \ + utf8/CMakeLists.txt \ + utf8/charmaps.h \ + utf8/makemap.c \ + utf8/charset_test.c + + +noinst_LTLIBRARIES = \ + getopt/libgetopt.la \ + grabbag/libgrabbag.la \ + utf8/libutf8.la \ + $(libwin_utf8_io) \ + replaygain_analysis/libreplaygain_analysis.la \ + replaygain_synthesis/libreplaygain_synthesis.la + + +if OS_IS_WINDOWS +win_utf8_io_libwin_utf8_io_la_SOURCES = win_utf8_io/win_utf8_io.c +libwin_utf8_io = win_utf8_io/libwin_utf8_io.la +else +win_utf8_io_libwin_utf8_io_la_SOURCES = +libwin_utf8_io = +endif + +getopt_libgetopt_la_SOURCES = getopt/getopt.c getopt/getopt1.c + +grabbag_libgrabbag_la_SOURCES = \ + grabbag/alloc.c \ + grabbag/cuesheet.c \ + grabbag/file.c \ + grabbag/picture.c \ + grabbag/replaygain.c \ + grabbag/seektable.c \ + grabbag/snprintf.c + +utf8_libutf8_la_SOURCES = \ + utf8/charset.c \ + utf8/charset.h \ + utf8/iconvert.c \ + utf8/iconvert.h \ + utf8/utf8.c + +replaygain_analysis_libreplaygain_analysis_la_SOURCES = replaygain_analysis/replaygain_analysis.c + +replaygain_synthesis_libreplaygain_synthesis_la_CFLAGS = -I $(top_srcdir)/src/share/replaygain_synthesis/include +replaygain_synthesis_libreplaygain_synthesis_la_SOURCES = replaygain_synthesis/replaygain_synthesis.c diff --git a/vendor/flac/src/share/README b/vendor/flac/src/share/README new file mode 100644 index 0000000..1d4fede --- /dev/null +++ b/vendor/flac/src/share/README @@ -0,0 +1,5 @@ +This directory contains several convenience libraries used by the rest of the +tools and plugins. Two of them (getopt and utf8) are shamelessly copied from +vorbistools, one for manipulating UTF-8 strings (GPL) and one for implementing +getopt (LGPL). libFLAC does not link to either; the only FLAC tools that do +are GPL'ed. diff --git a/vendor/flac/src/share/getopt/CMakeLists.txt b/vendor/flac/src/share/getopt/CMakeLists.txt new file mode 100644 index 0000000..d905615 --- /dev/null +++ b/vendor/flac/src/share/getopt/CMakeLists.txt @@ -0,0 +1,13 @@ +check_include_file("string.h" HAVE_STRING_H) + +if(NOT WIN32) + find_package(Intl) +endif() + +add_library(getopt STATIC getopt.c getopt1.c) + +if(Intl_FOUND) + target_include_directories(getopt PRIVATE ${Intl_INCLUDE_DIRS}) + target_link_libraries(getopt PUBLIC ${Intl_LIBRARIES}) + target_compile_definitions(getopt PRIVATE HAVE_LIBINTL_H) +endif() diff --git a/vendor/flac/src/share/getopt/getopt.c b/vendor/flac/src/share/getopt/getopt.c new file mode 100644 index 0000000..39fab80 --- /dev/null +++ b/vendor/flac/src/share/getopt/getopt.c @@ -0,0 +1,1053 @@ +/* + NOTE: + I cannot get the vanilla getopt code to work (i.e. compile only what + is needed and not duplicate symbols found in the standard library) + on all the platforms that FLAC supports. In particular the gating + of code with the ELIDE_CODE #define is not accurate enough on systems + that are POSIX but not glibc. If someone has a patch that works on + GNU/Linux, Darwin, AND Solaris please submit it on the project page: + https://sourceforge.net/p/flac/patches/ + + In the meantime I have munged the global symbols and removed gates + around code, while at the same time trying to touch the original as + little as possible. +*/ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 + Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#if 1 +/*[JEC] was:#ifndef ELIDE_CODE*/ + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# ifdef HAVE_STRING_H +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `share__getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `share__getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "share/getopt.h" +/*[JEC] was:#include "getopt.h"*/ + +/* For communication from `share__getopt' to the caller. + When `share__getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *share__optarg = 0; /*[JEC] initialize to avoid being a 'Common' symbol */ + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `share__getopt'. + + On entry to `share__getopt', zero means this is the first call; initialize. + + When `share__getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `share__optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int share__optind = 1; + +/* Formerly, initialization of getopt depended on share__optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +static int share____getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int share__opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int share__optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `share__getopt' to return -1 with `share__optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +#include + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (const char * name); +#endif + +static char * +my_index (const char *str, int chr) +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,share__optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (char **argv) +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = share__optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (share__optind - last_nonopt); + last_nonopt = share__optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *share___getopt_initialize (int, char *const *, const char *); +#endif +static const char * +share___getopt_initialize (int argc, char *const *argv, const char *optstring ) +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = share__optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#else + (void)argc, (void)argv; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `share__getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `share__getopt' finds another option character, it returns that character, + updating `share__optind' and `nextchar' so that the next call to `share__getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `share__getopt' returns -1. + Then `share__optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `share__opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `share__optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `share__optarg', otherwise `share__optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `share__getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct share__option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +share___getopt_internal ( + int argc, + char *const *argv, + const char *optstring, + const struct share__option *longopts, + int *longind, + int long_only ) +{ + share__optarg = NULL; + + if (share__optind == 0 || !share____getopt_initialized) + { + if (share__optind == 0) + share__optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = share___getopt_initialize (argc, argv, optstring); + share____getopt_initialized = 1; + } + + /* Test whether ARGV[share__optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0' \ + || (share__optind < nonoption_flags_len \ + && __getopt_nonoption_flags[share__optind] == '1')) +#else +# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > share__optind) + last_nonopt = share__optind; + if (first_nonopt > share__optind) + first_nonopt = share__optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != share__optind) + exchange ((char **) argv); + else if (last_nonopt != share__optind) + first_nonopt = share__optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (share__optind < argc && NONOPTION_P) + share__optind++; + last_nonopt = share__optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (share__optind != argc && !strcmp (argv[share__optind], "--")) + { + share__optind++; + + if (first_nonopt != last_nonopt && last_nonopt != share__optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = share__optind; + last_nonopt = argc; + + share__optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (share__optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + share__optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + share__optarg = argv[share__optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[share__optind] + 1 + + (longopts != NULL && argv[share__optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[share__optind][1] == '-' + || (long_only && (argv[share__optind][2] || !my_index (optstring, argv[share__optind][1]))))) + { + char *nameend; + const struct share__option *p; + const struct share__option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((size_t) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (share__opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[share__optind]); + nextchar += strlen (nextchar); + share__optind++; + share__optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + share__optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + share__optarg = nameend + 1; + else + { + if (share__opterr) + { + if (argv[share__optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[share__optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + share__optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (share__optind < argc) + share__optarg = argv[share__optind++]; + else + { + if (share__opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[share__optind - 1]); + nextchar += strlen (nextchar); + share__optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not share__getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[share__optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (share__opterr) + { + if (argv[share__optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[share__optind][0], nextchar); + } + nextchar = (char *) ""; + share__optind++; + share__optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `share__optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++share__optind; + + if (temp == NULL || c == ':') + { + if (share__opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + share__optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct share__option *p; + const struct share__option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + share__optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + share__optind++; + } + else if (share__optind == argc) + { + if (share__opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + share__optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `share__optind' once; + increment it again when taking next ARGV-elt as argument. */ + share__optarg = argv[share__optind++]; + + /* share__optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = share__optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((size_t) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (share__opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[share__optind]); + nextchar += strlen (nextchar); + share__optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + share__optarg = nameend + 1; + else + { + if (share__opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (share__optind < argc) + share__optarg = argv[share__optind++]; + else + { + if (share__opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[share__optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + share__optarg = nextchar; + share__optind++; + } + else + share__optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + share__optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + share__optind++; + } + else if (share__optind == argc) + { + if (share__opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + share__optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `share__optind' once; + increment it again when taking next ARGV-elt as argument. */ + share__optarg = argv[share__optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +share__getopt (int argc, char *const *argv, const char *optstring) +{ + return share___getopt_internal (argc, argv, optstring, + (const struct share__option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `share__getopt'. */ + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = share__optind ? share__optind : 1; + + c = share__getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", share__optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (share__optind < argc) + { + printf ("non-option ARGV-elements: "); + while (share__optind < argc) + printf ("%s ", argv[share__optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/vendor/flac/src/share/getopt/getopt1.c b/vendor/flac/src/share/getopt/getopt1.c new file mode 100644 index 0000000..fc52678 --- /dev/null +++ b/vendor/flac/src/share/getopt/getopt1.c @@ -0,0 +1,189 @@ +/* + NOTE: + I cannot get the vanilla getopt code to work (i.e. compile only what + is needed and not duplicate symbols found in the standard library) + on all the platforms that FLAC supports. In particular the gating + of code with the ELIDE_CODE #define is not accurate enough on systems + that are POSIX but not glibc. If someone has a patch that works on + GNU/Linux, Darwin, AND Solaris please submit it on the project page: + https://sourceforge.net/p/flac/patches/ + + In the meantime I have munged the global symbols and removed gates + around code, while at the same time trying to touch the original as + little as possible. +*/ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +#include "share/getopt.h" +/*[JEC] was:#include "getopt.h"*/ + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#if 1 +/*[JEC] was:#ifndef ELIDE_CODE*/ + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int share__getopt_long(int argc, char *const *argv, const char *options, const struct share__option *long_options, int *opt_index) +{ + return share___getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like share__getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int share__getopt_long_only(int argc, char *const *argv, const char *options, const struct share__option *long_options, int *opt_index) +{ + return share___getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int main(int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = share__optind ? share__optind : 1; + int option_index = 0; + static struct share__option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = share__getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (share__optarg) + printf (" with arg %s", share__optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", share__optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", share__optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (share__optind < argc) + { + printf ("non-option ARGV-elements: "); + while (share__optind < argc) + printf ("%s ", argv[share__optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/vendor/flac/src/share/grabbag/CMakeLists.txt b/vendor/flac/src/share/grabbag/CMakeLists.txt new file mode 100644 index 0000000..203ae3f --- /dev/null +++ b/vendor/flac/src/share/grabbag/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(grabbag STATIC + alloc.c + cuesheet.c + file.c + picture.c + replaygain.c + seektable.c + snprintf.c) +target_link_libraries(grabbag PUBLIC + FLAC + replaygain_analysis) +if(TARGET win_utf8_io) + target_link_libraries(grabbag PUBLIC win_utf8_io) +endif() diff --git a/vendor/flac/src/share/grabbag/alloc.c b/vendor/flac/src/share/grabbag/alloc.c new file mode 100644 index 0000000..4e5fb60 --- /dev/null +++ b/vendor/flac/src/share/grabbag/alloc.c @@ -0,0 +1,48 @@ +/* alloc - Convenience routines for safely allocating memory + * Copyright (C) 2007-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "share/alloc.h" + +void *safe_malloc_mul_2op_(size_t size1, size_t size2) +{ + if(!size1 || !size2) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(size1 > SIZE_MAX / size2) + return 0; + return malloc(size1*size2); +} diff --git a/vendor/flac/src/share/grabbag/cuesheet.c b/vendor/flac/src/share/grabbag/cuesheet.c new file mode 100644 index 0000000..0d19ee7 --- /dev/null +++ b/vendor/flac/src/share/grabbag/cuesheet.c @@ -0,0 +1,681 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "FLAC/assert.h" +#include "share/compat.h" +#include "share/grabbag.h" +#include "share/safe_str.h" + +uint32_t grabbag__cuesheet_msf_to_frame(uint32_t minutes, uint32_t seconds, uint32_t frames) +{ + return ((minutes * 60) + seconds) * 75 + frames; +} + +void grabbag__cuesheet_frame_to_msf(uint32_t frame, uint32_t *minutes, uint32_t *seconds, uint32_t *frames) +{ + *frames = frame % 75; + frame /= 75; + *seconds = frame % 60; + frame /= 60; + *minutes = frame; +} + +/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */ +static FLAC__int64 local__parse_int64_(const char *s) +{ + FLAC__int64 ret = 0; + char c; + + if(*s == '\0') + return -1; + + while('\0' != (c = *s++)) + if(c >= '0' && c <= '9') { + if(ret >= (INT64_MAX / 10)) + return -1; + else + ret = ret * 10 + (c - '0'); + } + else + return -1; + + return ret; +} + +/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */ +static int local__parse_int_(const char *s) +{ + FLAC__int64 ret64 = local__parse_int64_(s); + if(ret64 < 0 || ret64 > INT_MAX) + return -1; + return ret64; +} + +/* accept minute:second:frame syntax of '[0-9]+:[0-9][0-9]?:[0-9][0-9]?', but max second of 59 and max frame of 74, e.g. 0:0:0, 123:45:67 + * return sample number or <0 for error + * WATCHOUT: if sample rate is not evenly divisible by 75, the resulting sample number will be approximate + */ +static FLAC__int64 local__parse_msf_(const char *s, uint32_t sample_rate) +{ + FLAC__int64 ret, field; + char c; + + if(sample_rate == 0) + return -1; + + c = *s++; + if(c >= '0' && c <= '9') + field = (c - '0'); + else + return -1; + while(':' != (c = *s++)) { + if(c >= '0' && c <= '9') { + if(field >= (INT64_MAX / 10)) + return -1; + else + field = field * 10 + (c - '0'); + } + else + return -1; + } + + if(field >= INT64_MAX / (60 * sample_rate)) + return -1; + ret = field * 60 * sample_rate; + + c = *s++; + if(c >= '0' && c <= '9') + field = (c - '0'); + else + return -1; + if(':' != (c = *s++)) { + if(c >= '0' && c <= '9') { + field = field * 10 + (c - '0'); + c = *s++; + if(c != ':') + return -1; + } + else + return -1; + } + + if(field >= 60) + return -1; + + { + FLAC__int64 tmp = ret; + ret += field * sample_rate; + if(ret < tmp) + return -1; + } + + c = *s++; + if(c >= '0' && c <= '9') + field = (c - '0'); + else + return -1; + if('\0' != (c = *s++)) { + if(c >= '0' && c <= '9') { + field = field * 10 + (c - '0'); + c = *s++; + } + else + return -1; + } + + if(c != '\0') + return -1; + + if(field >= 75) + return -1; + + { + FLAC__int64 tmp = ret; + ret += field * (sample_rate / 75); + if(ret < tmp) + return -1; + } + + return ret; +} + +/* accept minute:second syntax of '[0-9]+:[0-9][0-9]?{,.[0-9]+}', but second < 60, e.g. 0:0.0, 3:5, 15:31.731 + * return sample number or <0 for error + * WATCHOUT: depending on the sample rate, the resulting sample number may be approximate with fractional seconds + */ +static FLAC__int64 local__parse_ms_(const char *s, uint32_t sample_rate) +{ + FLAC__int64 ret, field; + double x; + char c, *end; + + if(sample_rate == 0) + return -1; + + c = *s++; + if(c >= '0' && c <= '9') + field = (c - '0'); + else + return -1; + while(':' != (c = *s++)) { + if(c >= '0' && c <= '9') { + if(field >= (INT64_MAX / 10)) + return -1; + else + field = field * 10 + (c - '0'); + } + else + return -1; + } + + if(field >= INT64_MAX / (60 * sample_rate)) + return -1; + ret = field * 60 * sample_rate; + + if(strspn(s, "0123456789.") != strlen(s)) + return -1; + x = strtod(s, &end); + if(*end || end == s) + return -1; + if(x < 0.0 || x >= 60.0) + return -1; + + ret += (FLAC__int64)(x * sample_rate); + + return ret; +} + +static char *local__get_field_(char **s, FLAC__bool allow_quotes) +{ + FLAC__bool has_quote = false; + char *p; + + FLAC__ASSERT(0 != s); + + if(0 == *s) + return 0; + + /* skip leading whitespace */ + while(**s && 0 != strchr(" \t\r\n", **s)) + (*s)++; + + if(**s == 0) { + *s = 0; + return 0; + } + + if(allow_quotes && (**s == '"')) { + has_quote = true; + (*s)++; + if(**s == 0) { + *s = 0; + return 0; + } + } + + p = *s; + + if(has_quote) { + *s = strchr(*s, '\"'); + /* if there is no matching end quote, it's an error */ + if(0 == *s) + p = *s = 0; + else { + **s = '\0'; + (*s)++; + } + } + else { + while(**s && 0 == strchr(" \t\r\n", **s)) + (*s)++; + if(**s) { + **s = '\0'; + (*s)++; + } + else + *s = 0; + } + + return p; +} + +static FLAC__bool local__cuesheet_parse_(FILE *file, const char **error_message, uint32_t *last_line_read, FLAC__StreamMetadata *cuesheet, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset) +{ + char buffer[4096], *line, *field; + uint32_t forced_leadout_track_num = 0; + FLAC__uint64 forced_leadout_track_offset = 0; + int in_track_num = -1, in_index_num = -1; + FLAC__bool disc_has_catalog = false, track_has_flags = false, track_has_isrc = false, has_forced_leadout = false; + FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet; + + FLAC__ASSERT(!is_cdda || sample_rate == 44100); + /* double protection */ + if(is_cdda && sample_rate != 44100) { + *error_message = "CD-DA cuesheet only allowed with 44.1kHz sample rate"; + return false; + } + + cs->lead_in = is_cdda? 2 * 44100 /* The default lead-in size for CD-DA */ : 0; + cs->is_cd = is_cdda; + + while(0 != fgets(buffer, sizeof(buffer), file)) { + (*last_line_read)++; + line = buffer; + + { + size_t linelen = strlen(line); + if((linelen == sizeof(buffer)-1) && line[linelen-1] != '\n') { + *error_message = "line too long"; + return false; + } + } + + if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) { + if(0 == FLAC__STRCASECMP(field, "CATALOG")) { + if(disc_has_catalog) { + *error_message = "found multiple CATALOG commands"; + return false; + } + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/true))) { + *error_message = "CATALOG is missing catalog number"; + return false; + } + if(strlen(field) >= sizeof(cs->media_catalog_number)) { + *error_message = "CATALOG number is too long"; + return false; + } + if(is_cdda && (strlen(field) != 13 || strspn(field, "0123456789") != 13)) { + *error_message = "CD-DA CATALOG number must be 13 decimal digits"; + return false; + } + safe_strncpy(cs->media_catalog_number, field, sizeof(cs->media_catalog_number)); + disc_has_catalog = true; + } + else if(0 == FLAC__STRCASECMP(field, "FLAGS")) { + if(track_has_flags) { + *error_message = "found multiple FLAGS commands"; + return false; + } + if(in_track_num < 0 || in_index_num >= 0) { + *error_message = "FLAGS command must come after TRACK but before INDEX"; + return false; + } + while(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) { + if(0 == FLAC__STRCASECMP(field, "PRE")) + cs->tracks[cs->num_tracks-1].pre_emphasis = 1; + } + track_has_flags = true; + } + else if(0 == FLAC__STRCASECMP(field, "INDEX")) { + FLAC__int64 xx; + FLAC__StreamMetadata_CueSheet_Track *track = &cs->tracks[cs->num_tracks-1]; + if(in_track_num < 0) { + *error_message = "found INDEX before any TRACK"; + return false; + } + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) { + *error_message = "INDEX is missing index number"; + return false; + } + in_index_num = local__parse_int_(field); + if(in_index_num < 0) { + *error_message = "INDEX has invalid index number"; + return false; + } + FLAC__ASSERT(cs->num_tracks > 0); + if(track->num_indices == 0) { + /* it's the first index point of the track */ + if(in_index_num > 1) { + *error_message = "first INDEX number of a TRACK must be 0 or 1"; + return false; + } + } + else { + if(in_index_num != track->indices[track->num_indices-1].number + 1) { + *error_message = "INDEX numbers must be sequential"; + return false; + } + } + if(is_cdda && in_index_num > 99) { + *error_message = "CD-DA INDEX number must be between 0 and 99, inclusive"; + return false; + } + /*@@@ search for duplicate track number? */ + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) { + *error_message = "INDEX is missing an offset after the index number"; + return false; + } + /* first parse as minute:second:frame format */ + xx = local__parse_msf_(field, sample_rate); + if(xx < 0) { + /* CD-DA must use only MM:SS:FF format */ + if(is_cdda) { + *error_message = "illegal INDEX offset (not of the form MM:SS:FF)"; + return false; + } + /* as an extension for non-CD-DA we allow MM:SS.SS or raw sample number */ + xx = local__parse_ms_(field, sample_rate); + if(xx < 0) { + xx = local__parse_int64_(field); + if(xx < 0) { + *error_message = "illegal INDEX offset"; + return false; + } + } + } + else if(sample_rate % 75 && xx) { + /* only sample zero is exact */ + *error_message = "illegal INDEX offset (MM:SS:FF form not allowed if sample rate is not a multiple of 75)"; + return false; + } + if(is_cdda && cs->num_tracks == 1 && cs->tracks[0].num_indices == 0 && xx != 0) { + *error_message = "first INDEX of first TRACK must have an offset of 00:00:00"; + return false; + } + if(is_cdda && track->num_indices > 0 && (FLAC__uint64)xx <= track->indices[track->num_indices-1].offset) { + *error_message = "CD-DA INDEX offsets must increase in time"; + return false; + } + /* fill in track offset if it's the first index of the track */ + if(track->num_indices == 0) + track->offset = (FLAC__uint64)xx; + if(is_cdda && cs->num_tracks > 1) { + const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-2]; + if((FLAC__uint64)xx <= prev->offset + prev->indices[prev->num_indices-1].offset) { + *error_message = "CD-DA INDEX offsets must increase in time"; + return false; + } + } + if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, cs->num_tracks-1, track->num_indices)) { + *error_message = "memory allocation error"; + return false; + } + track->indices[track->num_indices-1].offset = (FLAC__uint64)xx - track->offset; + track->indices[track->num_indices-1].number = in_index_num; + } + else if(0 == FLAC__STRCASECMP(field, "ISRC")) { + char *l, *r; + if(track_has_isrc) { + *error_message = "found multiple ISRC commands"; + return false; + } + if(in_track_num < 0 || in_index_num >= 0) { + *error_message = "ISRC command must come after TRACK but before INDEX"; + return false; + } + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/true))) { + *error_message = "ISRC is missing ISRC number"; + return false; + } + /* strip out dashes */ + for(l = r = field; *r; r++) { + if(*r != '-') + *l++ = *r; + } + *l = '\0'; + if(strlen(field) != 12 || strspn(field, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") < 5 || strspn(field+5, "1234567890") != 7) { + *error_message = "invalid ISRC number"; + return false; + } + safe_strncpy(cs->tracks[cs->num_tracks-1].isrc, field, sizeof(cs->tracks[cs->num_tracks-1].isrc)); + track_has_isrc = true; + } + else if(0 == FLAC__STRCASECMP(field, "TRACK")) { + if(cs->num_tracks > 0) { + const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1]; + if( + prev->num_indices == 0 || + ( + is_cdda && + ( + (prev->num_indices == 1 && prev->indices[0].number != 1) || + (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1) + ) + ) + ) { + *error_message = is_cdda? + "previous TRACK must specify at least one INDEX 01" : + "previous TRACK must specify at least one INDEX"; + return false; + } + } + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) { + *error_message = "TRACK is missing track number"; + return false; + } + in_track_num = local__parse_int_(field); + if(in_track_num < 0) { + *error_message = "TRACK has invalid track number"; + return false; + } + if(in_track_num == 0) { + *error_message = "TRACK number must be greater than 0"; + return false; + } + if(is_cdda) { + if(in_track_num > 99) { + *error_message = "CD-DA TRACK number must be between 1 and 99, inclusive"; + return false; + } + } + else { + if(in_track_num == 255) { + *error_message = "TRACK number 255 is reserved for the lead-out"; + return false; + } + else if(in_track_num > 255) { + *error_message = "TRACK number must be between 1 and 254, inclusive"; + return false; + } + } + if(is_cdda && cs->num_tracks > 0 && in_track_num != cs->tracks[cs->num_tracks-1].number + 1) { + *error_message = "CD-DA TRACK numbers must be sequential"; + return false; + } + /*@@@ search for duplicate track number? */ + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) { + *error_message = "TRACK is missing a track type after the track number"; + return false; + } + if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) { + *error_message = "memory allocation error"; + return false; + } + cs->tracks[cs->num_tracks-1].number = in_track_num; + cs->tracks[cs->num_tracks-1].type = (0 == FLAC__STRCASECMP(field, "AUDIO"))? 0 : 1; /*@@@ should we be more strict with the value here? */ + in_index_num = -1; + track_has_flags = false; + track_has_isrc = false; + } + else if(0 == FLAC__STRCASECMP(field, "REM")) { + if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) { + if(0 == strcmp(field, "FLAC__lead-in")) { + FLAC__int64 xx; + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) { + *error_message = "FLAC__lead-in is missing offset"; + return false; + } + xx = local__parse_int64_(field); + if(xx < 0) { + *error_message = "illegal FLAC__lead-in offset"; + return false; + } + if(is_cdda && xx % 588 != 0) { + *error_message = "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples"; + return false; + } + cs->lead_in = (FLAC__uint64)xx; + } + else if(0 == strcmp(field, "FLAC__lead-out")) { + int track_num; + FLAC__int64 offset; + if(has_forced_leadout) { + *error_message = "multiple FLAC__lead-out commands"; + return false; + } + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) { + *error_message = "FLAC__lead-out is missing track number"; + return false; + } + track_num = local__parse_int_(field); + if(track_num < 0) { + *error_message = "illegal FLAC__lead-out track number"; + return false; + } + forced_leadout_track_num = (uint32_t)track_num; + /*@@@ search for duplicate track number? */ + if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) { + *error_message = "FLAC__lead-out is missing offset"; + return false; + } + offset = local__parse_int64_(field); + if(offset < 0) { + *error_message = "illegal FLAC__lead-out offset"; + return false; + } + forced_leadout_track_offset = (FLAC__uint64)offset; + if(forced_leadout_track_offset != lead_out_offset) { + *error_message = "FLAC__lead-out offset does not match end-of-stream offset"; + return false; + } + has_forced_leadout = true; + } + } + } + } + } + + if(cs->num_tracks == 0) { + *error_message = "there must be at least one TRACK command"; + return false; + } + else { + const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1]; + if( + prev->num_indices == 0 || + ( + is_cdda && + ( + (prev->num_indices == 1 && prev->indices[0].number != 1) || + (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1) + ) + ) + ) { + *error_message = is_cdda? + "previous TRACK must specify at least one INDEX 01" : + "previous TRACK must specify at least one INDEX"; + return false; + } + } + + if(!has_forced_leadout) { + forced_leadout_track_num = is_cdda? 170 : 255; + forced_leadout_track_offset = lead_out_offset; + } + if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) { + *error_message = "memory allocation error"; + return false; + } + cs->tracks[cs->num_tracks-1].number = forced_leadout_track_num; + cs->tracks[cs->num_tracks-1].offset = forced_leadout_track_offset; + + if(!feof(file)) { + *error_message = "read error"; + return false; + } + return true; +} + +FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, uint32_t *last_line_read, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset) +{ + FLAC__StreamMetadata *cuesheet; + + FLAC__ASSERT(0 != file); + FLAC__ASSERT(0 != error_message); + FLAC__ASSERT(0 != last_line_read); + + *last_line_read = 0; + cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET); + + if(0 == cuesheet) { + *error_message = "memory allocation error"; + return 0; + } + + if(!local__cuesheet_parse_(file, error_message, last_line_read, cuesheet, sample_rate, is_cdda, lead_out_offset)) { + FLAC__metadata_object_delete(cuesheet); + return 0; + } + + return cuesheet; +} + +void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference) +{ + const FLAC__StreamMetadata_CueSheet *cs; + uint32_t track_num, index_num; + + FLAC__ASSERT(0 != file); + FLAC__ASSERT(0 != cuesheet); + FLAC__ASSERT(cuesheet->type == FLAC__METADATA_TYPE_CUESHEET); + + cs = &cuesheet->data.cue_sheet; + + if(*(cs->media_catalog_number)) + fprintf(file, "CATALOG %s\n", cs->media_catalog_number); + fprintf(file, "FILE %s\n", file_reference); + + FLAC__ASSERT(cs->num_tracks > 0); + + for(track_num = 0; track_num < cs->num_tracks-1; track_num++) { + const FLAC__StreamMetadata_CueSheet_Track *track = cs->tracks + track_num; + + fprintf(file, " TRACK %02u %s\n", (uint32_t)track->number, track->type == 0? "AUDIO" : "DATA"); + + if(track->pre_emphasis) + fprintf(file, " FLAGS PRE\n"); + if(*(track->isrc)) + fprintf(file, " ISRC %s\n", track->isrc); + + for(index_num = 0; index_num < track->num_indices; index_num++) { + const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + index_num; + + fprintf(file, " INDEX %02u ", (uint32_t)indx->number); + if(cs->is_cd) { + const uint32_t logical_frame = (uint32_t)((track->offset + indx->offset) / (44100 / 75)); + uint32_t m, s, f; + grabbag__cuesheet_frame_to_msf(logical_frame, &m, &s, &f); + fprintf(file, "%02u:%02u:%02u\n", m, s, f); + } + else + fprintf(file, "%" PRIu64 "\n", (track->offset + indx->offset)); + } + } + + fprintf(file, "REM FLAC__lead-in %" PRIu64 "\n", cs->lead_in); + fprintf(file, "REM FLAC__lead-out %u %" PRIu64 "\n", (uint32_t)cs->tracks[track_num].number, cs->tracks[track_num].offset); +} diff --git a/vendor/flac/src/share/grabbag/file.c b/vendor/flac/src/share/grabbag/file.c new file mode 100644 index 0000000..307645f --- /dev/null +++ b/vendor/flac/src/share/grabbag/file.c @@ -0,0 +1,207 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined _MSC_VER || defined __MINGW32__ +#include /* for utime() */ +#include /* for chmod(), _setmode(), unlink() */ +#include /* for _O_BINARY */ +#else +#include /* some flavors of BSD (like OS X) require this to get time_t */ +#endif +#if defined __EMX__ +#include /* for setmode(), O_BINARY */ +#include /* for _O_BINARY */ +#endif +#include /* for stat(), maybe chmod() */ +#if defined _WIN32 && !defined __CYGWIN__ +#else +#include /* for unlink() */ +#endif +#include +#include +#include /* for strrchr() */ +#if defined _WIN32 && !defined __CYGWIN__ +// for GetFileInformationByHandle() etc +#include +#include +#endif +#include "share/grabbag.h" +#include "share/compat.h" + + +void grabbag__file_copy_metadata(const char *srcpath, const char *destpath) +{ + struct flac_stat_s srcstat; + + if(0 == flac_stat(srcpath, &srcstat)) { +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32) + struct timespec srctime[2] = {}; + srctime[0].tv_sec = srcstat.st_atime; + srctime[1].tv_sec = srcstat.st_mtime; +#else + struct utimbuf srctime; + srctime.actime = srcstat.st_atime; + srctime.modtime = srcstat.st_mtime; +#endif + (void)flac_chmod(destpath, srcstat.st_mode); + (void)flac_utime(destpath, &srctime); + } +} + +FLAC__off_t grabbag__file_get_filesize(const char *srcpath) +{ + struct flac_stat_s srcstat; + + if(0 == flac_stat(srcpath, &srcstat)) + return srcstat.st_size; + else + return -1; +} + +const char *grabbag__file_get_basename(const char *srcpath) +{ + const char *p; + + p = strrchr(srcpath, '/'); + if(0 == p) { +#if defined _WIN32 && !defined __CYGWIN__ + p = strrchr(srcpath, '\\'); + if(0 == p) +#endif + return srcpath; + } + return ++p; +} + +FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only) +{ + struct flac_stat_s stats; + + if(0 == flac_stat(filename, &stats)) { +#if !defined _MSC_VER && !defined __MINGW32__ + if(read_only) { + stats.st_mode &= ~S_IWUSR; + stats.st_mode &= ~S_IWGRP; + stats.st_mode &= ~S_IWOTH; + } + else { + stats.st_mode |= S_IWUSR; + } +#else + if(read_only) + stats.st_mode &= ~S_IWRITE; + else + stats.st_mode |= S_IWRITE; +#endif + if(0 != flac_chmod(filename, stats.st_mode)) + return false; + } + else + return false; + + return true; +} + +FLAC__bool grabbag__file_are_same(const char *f1, const char *f2) +{ +#if defined _WIN32 && !defined __CYGWIN__ +#if !defined(WINAPI_FAMILY_PARTITION) +#define WINAPI_FAMILY_PARTITION(x) x +#define WINAPI_PARTITION_DESKTOP 1 +#endif + /* see + * http://www.hydrogenaudio.org/forums/index.php?showtopic=49439&pid=444300&st=0 + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getfileinformationbyhandle.asp + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/by_handle_file_information_str.asp + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/createfile.asp + * apparently both the files have to be open at the same time for the comparison to work + */ + FLAC__bool same = false; + BY_HANDLE_FILE_INFORMATION info1, info2; + HANDLE h1, h2; + BOOL ok = 1; + h1 = CreateFile_utf8(f1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + h2 = CreateFile_utf8(f2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE) + ok = 0; +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + ok &= GetFileInformationByHandle(h1, &info1); + ok &= GetFileInformationByHandle(h2, &info2); + if(ok) + same = + info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && + info1.nFileIndexHigh == info2.nFileIndexHigh && + info1.nFileIndexLow == info2.nFileIndexLow + ; +#else // !WINAPI_PARTITION_DESKTOP + FILE_ID_INFO id_info1, id_info2; + same = GetFileInformationByHandleEx(h1, FileIdInfo, &id_info1, sizeof (id_info1)) && + GetFileInformationByHandleEx(h2, FileIdInfo, &id_info2, sizeof (id_info2)) && + id_info1.VolumeSerialNumber == id_info2.VolumeSerialNumber && + memcmp(&id_info1.FileId, &id_info2.FileId, sizeof(id_info1.FileId)) == 0; +#endif // !WINAPI_PARTITION_DESKTOP + if(h1 != INVALID_HANDLE_VALUE) + CloseHandle(h1); + if(h2 != INVALID_HANDLE_VALUE) + CloseHandle(h2); + return same; +#else + struct flac_stat_s s1, s2; + return f1 && f2 && flac_stat(f1, &s1) == 0 && flac_stat(f2, &s2) == 0 && s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev; +#endif +} + +FLAC__bool grabbag__file_remove_file(const char *filename) +{ + return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == flac_unlink(filename); +} + +FILE *grabbag__file_get_binary_stdin(void) +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdin), _O_BINARY); +#elif defined __EMX__ + setmode(fileno(stdin), O_BINARY); +#endif + + return stdin; +} + +FILE *grabbag__file_get_binary_stdout(void) +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdout), _O_BINARY); +#elif defined __EMX__ + setmode(fileno(stdout), O_BINARY); +#endif + + return stdout; +} diff --git a/vendor/flac/src/share/grabbag/picture.c b/vendor/flac/src/share/grabbag/picture.c new file mode 100644 index 0000000..9a4aafe --- /dev/null +++ b/vendor/flac/src/share/grabbag/picture.c @@ -0,0 +1,515 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2006-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "share/alloc.h" +#include "share/grabbag.h" +#include "FLAC/assert.h" +#include +#include +#include +#include "share/compat.h" +#include "share/safe_str.h" + +/* slightly different that strndup(): this always copies 'size' bytes starting from s into a NUL-terminated string. */ +static char *local__strndup_(const char *s, size_t size) +{ + char *x = safe_malloc_add_2op_(size, /*+*/1); + if(x) { + memcpy(x, s, size); + x[size] = '\0'; + } + return x; +} + +static FLAC__bool local__parse_type_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture) +{ + size_t i; + FLAC__uint32 val = 0; + + picture->type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + + if(len == 0) + return true; /* empty string implies default to 'front cover' */ + + for(i = 0; i < len; i++) { + if(s[i] >= '0' && s[i] <= '9') + val = 10*val + (FLAC__uint32)(s[i] - '0'); + else + return false; + } + + if(i == len) + picture->type = val; + else + return false; + + return true; +} + +static FLAC__bool local__parse_resolution_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture) +{ + int state = 0; + size_t i; + FLAC__uint32 val = 0; + + picture->width = picture->height = picture->depth = picture->colors = 0; + + if(len == 0) + return true; /* empty string implies client wants to get info from the file itself */ + + for(i = 0; i < len; i++) { + if(s[i] == 'x') { + if(state == 0) + picture->width = val; + else if(state == 1) + picture->height = val; + else + return false; + state++; + val = 0; + } + else if(s[i] == '/') { + if(state == 2) + picture->depth = val; + else + return false; + state++; + val = 0; + } + else if(s[i] >= '0' && s[i] <= '9') + val = 10*val + (FLAC__uint32)(s[i] - '0'); + else + return false; + } + + if(state < 2) + return false; + else if(state == 2) + picture->depth = val; + else if(state == 3) + picture->colors = val; + else + return false; + if(picture->depth < 32 && 1u<depth < picture->colors) + return false; + + return true; +} + +static FLAC__bool local__extract_mime_type_(FLAC__StreamMetadata *obj) +{ + if(obj->data.picture.data_length >= 8 && 0 == memcmp(obj->data.picture.data, "\x89PNG\x0d\x0a\x1a\x0a", 8)) + return FLAC__metadata_object_picture_set_mime_type(obj, "image/png", /*copy=*/true); + else if(obj->data.picture.data_length >= 6 && (0 == memcmp(obj->data.picture.data, "GIF87a", 6) || 0 == memcmp(obj->data.picture.data, "GIF89a", 6))) + return FLAC__metadata_object_picture_set_mime_type(obj, "image/gif", /*copy=*/true); + else if(obj->data.picture.data_length >= 2 && 0 == memcmp(obj->data.picture.data, "\xff\xd8", 2)) + return FLAC__metadata_object_picture_set_mime_type(obj, "image/jpeg", /*copy=*/true); + return false; +} + +static FLAC__bool local__extract_resolution_color_info_(FLAC__StreamMetadata_Picture *picture) +{ + const FLAC__byte *data = picture->data; + FLAC__uint32 len = picture->data_length; + + if(0 == strcmp(picture->mime_type, "image/png")) { + /* c.f. http://www.w3.org/TR/PNG/ */ + FLAC__bool need_palette = false; /* if IHDR has color_type=3, we need to also read the PLTE chunk to get the #colors */ + if(len < 8 || memcmp(data, "\x89PNG\x0d\x0a\x1a\x0a", 8)) + return false; + /* try to find IHDR chunk */ + data += 8; + len -= 8; + while(len > 12) { /* every PNG chunk must be at least 12 bytes long */ + const FLAC__uint32 clen = (FLAC__uint32)data[0] << 24 | (FLAC__uint32)data[1] << 16 | (FLAC__uint32)data[2] << 8 | (FLAC__uint32)data[3]; + /* First check whether clen makes sense or causes overflow in this bit of code */ + if(clen + 12 <= clen || clen + 12 > len) + return false; + else if(0 == memcmp(data+4, "IHDR", 4) && clen == 13) { + uint32_t color_type = data[17]; + picture->width = (FLAC__uint32)data[8] << 24 | (FLAC__uint32)data[9] << 16 | (FLAC__uint32)data[10] << 8 | (FLAC__uint32)data[11]; + picture->height = (FLAC__uint32)data[12] << 24 | (FLAC__uint32)data[13] << 16 | (FLAC__uint32)data[14] << 8 | (FLAC__uint32)data[15]; + if(color_type == 3) { + /* even though the bit depth for color_type==3 can be 1,2,4,or 8, + * the spec in 11.2.2 of http://www.w3.org/TR/PNG/ says that the + * sample depth is always 8 + */ + picture->depth = 8 * 3u; + need_palette = true; + data += 12 + clen; + len -= 12 + clen; + } + else { + if(color_type == 0) /* greyscale, 1 sample per pixel */ + picture->depth = (FLAC__uint32)data[16]; + if(color_type == 2) /* truecolor, 3 samples per pixel */ + picture->depth = (FLAC__uint32)data[16] * 3u; + if(color_type == 4) /* greyscale+alpha, 2 samples per pixel */ + picture->depth = (FLAC__uint32)data[16] * 2u; + if(color_type == 6) /* truecolor+alpha, 4 samples per pixel */ + picture->depth = (FLAC__uint32)data[16] * 4u; + picture->colors = 0; + return true; + } + } + else if(need_palette && 0 == memcmp(data+4, "PLTE", 4)) { + picture->colors = clen / 3u; + return true; + } + else { + data += 12 + clen; + len -= 12 + clen; + } + } + } + else if(0 == strcmp(picture->mime_type, "image/jpeg")) { + /* c.f. http://www.w3.org/Graphics/JPEG/itu-t81.pdf and Q22 of http://www.faqs.org/faqs/jpeg-faq/part1/ */ + if(len < 2 || memcmp(data, "\xff\xd8", 2)) + return false; + data += 2; + len -= 2; + while(1) { + /* look for sync FF byte */ + for( ; len > 0; data++, len--) { + if(*data == 0xff) + break; + } + if(len == 0) + return false; + /* eat any extra pad FF bytes before marker */ + for( ; len > 0; data++, len--) { + if(*data != 0xff) + break; + } + if(len == 0) + return false; + /* if we hit SOS or EOI, bail */ + if(*data == 0xda || *data == 0xd9) + return false; + /* looking for some SOFn */ + else if(memchr("\xc0\xc1\xc2\xc3\xc5\xc6\xc7\xc9\xca\xcb\xcd\xce\xcf", *data, 13)) { + data++; len--; /* skip marker byte */ + if(len < 2) + return false; + else { + const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1]; + if(clen < 8 || len < clen) + return false; + picture->width = (FLAC__uint32)data[5] << 8 | (FLAC__uint32)data[6]; + picture->height = (FLAC__uint32)data[3] << 8 | (FLAC__uint32)data[4]; + picture->depth = (FLAC__uint32)data[2] * (FLAC__uint32)data[7]; + picture->colors = 0; + return true; + } + } + /* else skip it */ + else { + data++; len--; /* skip marker byte */ + if(len < 2) + return false; + else { + const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1]; + if(clen < 2 || len < clen) + return false; + data += clen; + len -= clen; + } + } + } + } + else if(0 == strcmp(picture->mime_type, "image/gif")) { + /* c.f. http://www.w3.org/Graphics/GIF/spec-gif89a.txt */ + if(len < 14) + return false; + if(memcmp(data, "GIF87a", 6) && memcmp(data, "GIF89a", 6)) + return false; +#if 0 + /* according to the GIF spec, even if the GCTF is 0, the low 3 bits should still tell the total # colors used */ + if(data[10] & 0x80 == 0) + return false; +#endif + picture->width = (FLAC__uint32)data[6] | ((FLAC__uint32)data[7] << 8); + picture->height = (FLAC__uint32)data[8] | ((FLAC__uint32)data[9] << 8); +#if 0 + /* this value doesn't seem to be reliable... */ + picture->depth = (((FLAC__uint32)(data[10] & 0x70) >> 4) + 1) * 3u; +#else + /* ...just pessimistically assume it's 24-bit color without scanning all the color tables */ + picture->depth = 8u * 3u; +#endif + picture->colors = 1u << ((FLAC__uint32)(data[10] & 0x07) + 1u); + return true; + } + return false; +} + +static const char *error_messages[] = { + "memory allocation error", + "invalid picture specification", + "invalid picture specification: can't parse resolution/color part", + "unable to extract resolution and color info from URL, user must set explicitly", + "unable to extract resolution and color info from file, user must set explicitly", + "error opening picture file", + "error reading picture file", + "invalid picture type", + "unable to guess MIME type from file, user must set explicitly", + "type 1 icon must be a 32x32 pixel PNG", + "file not found", /* currently unused */ + "file is too large", + "empty file" +}; + +static const char * read_file (const char * filepath, FLAC__StreamMetadata * obj) +{ + const FLAC__off_t size = grabbag__file_get_filesize(filepath); + FLAC__byte *buffer; + FILE *file; + const char *error_message=NULL; + + if (size < 0) + return error_messages[5]; + + if (size == 0) + return error_messages[12]; + + if (size >= (FLAC__off_t)(1u << FLAC__STREAM_METADATA_LENGTH_LEN)) /* actual limit is less because of other fields in the PICTURE metadata block */ + return error_messages[11]; + + if ((buffer = safe_malloc_(size)) == NULL) + return error_messages[0]; + + if ((file = flac_fopen(filepath, "rb")) == NULL) { + free(buffer); + return error_messages[5]; + } + + if (fread(buffer, 1, size, file) != (size_t) size) { + fclose(file); + free(buffer); + return error_messages[6]; + } + fclose(file); + + if (!FLAC__metadata_object_picture_set_data(obj, buffer, (FLAC__uint32)size, /*copy=*/false)) + error_message = error_messages[6]; + /* try to extract MIME type if user left it blank */ + else if (*obj->data.picture.mime_type == '\0' && !local__extract_mime_type_(obj)) + error_message = error_messages[8]; + /* try to extract resolution/color info if user left it blank */ + else if ((obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) && !local__extract_resolution_color_info_(&obj->data.picture)) + error_message = error_messages[4]; + /* check metadata block size */ + else if (obj->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) + error_message = error_messages[11]; + + return error_message; +} + +FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message) +{ + FLAC__StreamMetadata *obj; + int state = 0; + + FLAC__ASSERT(0 != spec); + FLAC__ASSERT(0 != error_message); + + /* double protection */ + if(0 == spec) + return 0; + if(0 == error_message) + return 0; + + *error_message = 0; + + if(0 == (obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE))) { + *error_message = error_messages[0]; + return obj; + } + + if(strchr(spec, '|')) { /* full format */ + const char *p; + char *q; + for(p = spec; *error_message==0 && *p; ) { + if(*p == '|') { + switch(state) { + case 0: /* type */ + if(!local__parse_type_(spec, p-spec, &obj->data.picture)) + *error_message = error_messages[7]; + break; + case 1: /* mime type */ + if(p-spec) { /* if blank, we'll try to guess later from the picture data */ + if(0 == (q = local__strndup_(spec, p-spec))) + *error_message = error_messages[0]; + else if(!FLAC__metadata_object_picture_set_mime_type(obj, q, /*copy=*/false)) + *error_message = error_messages[0]; + } + break; + case 2: /* description */ + if(0 == (q = local__strndup_(spec, p-spec))) + *error_message = error_messages[0]; + else if(!FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*)q, /*copy=*/false)) + *error_message = error_messages[0]; + break; + case 3: /* resolution/color (e.g. [300x300x16[/1234]] */ + if(!local__parse_resolution_(spec, p-spec, &obj->data.picture)) + *error_message = error_messages[2]; + break; + default: + *error_message = error_messages[1]; + break; + } + p++; + spec = p; + state++; + } + else + p++; + } + } + else { /* simple format, filename only, everything else guessed */ + if(!local__parse_type_("", 0, &obj->data.picture)) /* use default picture type */ + *error_message = error_messages[7]; + /* leave MIME type to be filled in later */ + /* leave description empty */ + /* leave the rest to be filled in later: */ + else if(!local__parse_resolution_("", 0, &obj->data.picture)) + *error_message = error_messages[2]; + else + state = 4; + } + + /* parse filename, read file, try to extract resolution/color info if needed */ + if(*error_message == 0) { + if(state != 4) + *error_message = error_messages[1]; + else { /* 'spec' points to filename/URL */ + if(0 == strcmp(obj->data.picture.mime_type, "-->")) { /* magic MIME type means URL */ + if(strlen(spec) == 0) + *error_message = error_messages[1]; + else if(!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)spec, strlen(spec), /*copy=*/true)) + *error_message = error_messages[0]; + else if(obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) + *error_message = error_messages[3]; + } + else { /* regular picture file */ + *error_message = read_file (spec, obj); + } + } + } + + if(*error_message == 0) { + if( + obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && + ( + (strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) || + obj->data.picture.width != 32 || + obj->data.picture.height != 32 + ) + ) + *error_message = error_messages[9]; + } + + if(*error_message && obj) { + FLAC__metadata_object_delete(obj); + obj = 0; + } + + return obj; +} + +FLAC__StreamMetadata *grabbag__picture_from_specification(int type, const char *mime_type_in, const char * description, + const PictureResolution * res, const char * filepath, const char **error_message) +{ + + FLAC__StreamMetadata *obj; + char mime_type [64] ; + + if (error_message == 0) + return 0; + + safe_strncpy(mime_type, mime_type_in, sizeof (mime_type)); + + *error_message = 0; + + if ((obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) == 0) { + *error_message = error_messages[0]; + return obj; + } + + /* Picture type if known. */ + obj->data.picture.type = type >= 0 ? type : FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + + /* Mime type if known. */ + if (mime_type_in && ! FLAC__metadata_object_picture_set_mime_type(obj, mime_type, /*copy=*/true)) { + *error_message = error_messages[0]; + return obj; + } + + /* Description if present. */ + if (description && ! FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*) description, /*copy=*/true)) { + *error_message = error_messages[0]; + return obj; + } + + if (res == NULL) { + obj->data.picture.width = 0; + obj->data.picture.height = 0; + obj->data.picture.depth = 0; + obj->data.picture.colors = 0; + } + else { + obj->data.picture.width = res->width; + obj->data.picture.height = res->height; + obj->data.picture.depth = res->depth; + obj->data.picture.colors = res->colors; + } + + if (strcmp(obj->data.picture.mime_type, "-->") == 0) { /* magic MIME type means URL */ + if (!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)filepath, strlen(filepath), /*copy=*/true)) + *error_message = error_messages[0]; + else if (obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) + *error_message = error_messages[3]; + } + else { + *error_message = read_file (filepath, obj); + } + + if (*error_message == NULL) { + if ( + obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && + ( + (strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) || + obj->data.picture.width != 32 || + obj->data.picture.height != 32 + ) + ) + *error_message = error_messages[9]; + } + + if (*error_message && obj) { + FLAC__metadata_object_delete(obj); + obj = 0; + } + + return obj; +} diff --git a/vendor/flac/src/share/grabbag/replaygain.c b/vendor/flac/src/share/grabbag/replaygain.c new file mode 100644 index 0000000..32c9603 --- /dev/null +++ b/vendor/flac/src/share/grabbag/replaygain.c @@ -0,0 +1,669 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#if defined _MSC_VER || defined __MINGW32__ +#include /* for chmod() */ +#endif +#include /* for stat(), maybe chmod() */ + +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "FLAC/stream_decoder.h" +#include "share/grabbag.h" +#include "share/replaygain_analysis.h" +#include "share/safe_str.h" + +#ifdef local_min +#undef local_min +#endif +#define local_min(a,b) ((a)<(b)?(a):(b)) + +#ifdef local_max +#undef local_max +#endif +#define local_max(a,b) ((a)>(b)?(a):(b)) + +#ifdef abs32 +#undef abs32 +#endif +#define abs32(a) (((a)==INT32_MIN)?INT32_MAX:abs(a)) + +static const char *reference_format_ = "%s=%2.1f dB"; +static const char *gain_format_ = "%s=%+2.2f dB"; +static const char *peak_format_ = "%s=%1.8f"; + +static double album_peak_, title_peak_; + +const uint32_t GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 190; +/* + FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 29 + 1 + 8 + + FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 + + FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 + + FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 + + FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 +*/ + +const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS = (const FLAC__byte * const)"REPLAYGAIN_REFERENCE_LOUDNESS"; +const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN = (const FLAC__byte * const)"REPLAYGAIN_TRACK_GAIN"; +const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK = (const FLAC__byte * const)"REPLAYGAIN_TRACK_PEAK"; +const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_GAIN"; +const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_PEAK"; + + +static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + return (0 == flac_stat(filename, stats)); +} + +static void set_file_stats_(const char *filename, struct flac_stat_s *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + + (void)flac_chmod(filename, stats->st_mode); +} + +static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value) +{ + char buffer[256]; + char *saved_locale; + FLAC__StreamMetadata_VorbisComment_Entry entry; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != format); + FLAC__ASSERT(0 != name); + + buffer[sizeof(buffer)-1] = '\0'; + /* + * We need to save the old locale and switch to "C" because the locale + * influences the formatting of %f and we want it a certain way. + */ + saved_locale = strdup(setlocale(LC_ALL, 0)); + if (0 == saved_locale) + return false; + setlocale(LC_ALL, "C"); + flac_snprintf(buffer, sizeof(buffer), format, name, value); + setlocale(LC_ALL, saved_locale); + free(saved_locale); + + entry.entry = (FLAC__byte *)buffer; + entry.length = strlen(buffer); + + return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true); +} + +FLAC__bool grabbag__replaygain_is_valid_sample_frequency(uint32_t sample_frequency) +{ + return ValidGainFrequency( sample_frequency ); +} + +FLAC__bool grabbag__replaygain_init(uint32_t sample_frequency) +{ + title_peak_ = album_peak_ = 0.0; + return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK; +} + +FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, uint32_t bps, uint32_t samples) +{ + /* using a small buffer improves data locality; we'd like it to fit easily in the dcache */ + static flac_float_t lbuffer[2048], rbuffer[2048]; + static const uint32_t nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]); + FLAC__int32 block_peak = 0, s; + uint32_t i, j; + + FLAC__ASSERT(bps >= FLAC__MIN_BITS_PER_SAMPLE && bps <= FLAC__MAX_BITS_PER_SAMPLE); + FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4 && FLAC__MAX_BITS_PER_SAMPLE == 32); + + if(bps == 16) { + if(is_stereo) { + j = 0; + while(samples > 0) { + const uint32_t n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (flac_float_t)s; + s = abs(s); + block_peak = local_max(block_peak, s); + + s = input[1][j]; + rbuffer[i] = (flac_float_t)s; + s = abs(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK) + return false; + } + } + else { + j = 0; + while(samples > 0) { + const uint32_t n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (flac_float_t)s; + s = abs(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK) + return false; + } + } + } + else { + const double scale = ( + (bps > 16)? + (double)1. / (double)(1u << (bps - 16)) : + (double)(1u << (16 - bps)) + ); + + if(is_stereo) { + j = 0; + while(samples > 0) { + const uint32_t n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (flac_float_t)(scale * (double)s); + s = abs32(s); + block_peak = local_max(block_peak, s); + + s = input[1][j]; + rbuffer[i] = (flac_float_t)(scale * (double)s); + s = abs32(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK) + return false; + } + } + else { + j = 0; + while(samples > 0) { + const uint32_t n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (flac_float_t)(scale * (double)s); + s = abs32(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK) + return false; + } + } + } + + { + const double peak_scale = (double)(1u << (bps - 1)); + double peak = (double)block_peak / peak_scale; + if(peak > title_peak_) + title_peak_ = peak; + if(peak > album_peak_) + album_peak_ = peak; + } + + return true; +} + +void grabbag__replaygain_get_album(float *gain, float *peak) +{ + *gain = (float)GetAlbumGain(); + *peak = (float)album_peak_; + album_peak_ = 0.0; +} + +void grabbag__replaygain_get_title(float *gain, float *peak) +{ + *gain = (float)GetTitleGain(); + *peak = (float)title_peak_; + title_peak_ = 0.0; +} + + +typedef struct { + uint32_t channels; + uint32_t bits_per_sample; + uint32_t sample_rate; + FLAC__bool error; +} DecoderInstance; + +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + DecoderInstance *instance = (DecoderInstance*)client_data; + const uint32_t bits_per_sample = frame->header.bits_per_sample; + const uint32_t channels = frame->header.channels; + const uint32_t sample_rate = frame->header.sample_rate; + const uint32_t samples = frame->header.blocksize; + + (void)decoder; + + if( + !instance->error && + (channels == 2 || channels == 1) && + bits_per_sample == instance->bits_per_sample && + channels == instance->channels && + sample_rate == instance->sample_rate + ) { + instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples); + } + else { + instance->error = true; + } + + if(!instance->error) + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + else + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; +} + +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + DecoderInstance *instance = (DecoderInstance*)client_data; + + (void)decoder; + + if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + instance->bits_per_sample = metadata->data.stream_info.bits_per_sample; + instance->channels = metadata->data.stream_info.channels; + instance->sample_rate = metadata->data.stream_info.sample_rate; + + if(instance->channels != 1 && instance->channels != 2) { + instance->error = true; + return; + } + + if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) { + instance->error = true; + return; + } + } +} + +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + DecoderInstance *instance = (DecoderInstance*)client_data; + + (void)decoder, (void)status; + + instance->error = true; +} + +const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak) +{ + DecoderInstance instance; + FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); + + if(0 == decoder) + return "memory allocation error"; + + instance.error = false; + + /* It does these three by default but lets be explicit: */ + FLAC__stream_decoder_set_md5_checking(decoder, false); + FLAC__stream_decoder_set_metadata_ignore_all(decoder); + FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO); + + if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &instance) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + FLAC__stream_decoder_delete(decoder); + return "initializing decoder"; + } + + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder) || instance.error) { + FLAC__stream_decoder_delete(decoder); + return "decoding file"; + } + + FLAC__stream_decoder_delete(decoder); + + grabbag__replaygain_get_title(title_gain, title_peak); + + return 0; +} + +const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak) +{ + const char *error; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) + return error; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) + return error; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) + return error; + + return 0; +} + +const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + if(FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS) < 0) + return "memory allocation error"; + + if(!append_tag_(block, reference_format_, GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, ReplayGainReferenceLoudness)) + return "memory allocation error"; + + return 0; +} + +const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak) +{ + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + if( + FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN) < 0 || + FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK) < 0 + ) + return "memory allocation error"; + + if( + !append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, album_gain) || + !append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK, album_peak) + ) + return "memory allocation error"; + + return 0; +} + +const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak) +{ + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + if( + FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN) < 0 || + FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK) < 0 + ) + return "memory allocation error"; + + if( + !append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, title_gain) || + !append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, title_peak) + ) + return "memory allocation error"; + + return 0; +} + +static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block) +{ + FLAC__Metadata_Iterator *iterator; + const char *error; + FLAC__bool found_vc_block = false; + + if(0 == (*chain = FLAC__metadata_chain_new())) + return "memory allocation error"; + + if(!FLAC__metadata_chain_read(*chain, filename)) { + error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; + FLAC__metadata_chain_delete(*chain); + return error; + } + + if(0 == (iterator = FLAC__metadata_iterator_new())) { + FLAC__metadata_chain_delete(*chain); + return "memory allocation error"; + } + + FLAC__metadata_iterator_init(iterator, *chain); + + do { + *block = FLAC__metadata_iterator_get_block(iterator); + if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + found_vc_block = true; + } while(!found_vc_block && FLAC__metadata_iterator_next(iterator)); + + if(!found_vc_block) { + /* create a new block */ + *block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 == *block) { + FLAC__metadata_chain_delete(*chain); + FLAC__metadata_iterator_delete(iterator); + return "memory allocation error"; + } + while(FLAC__metadata_iterator_next(iterator)) + ; + if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) { + error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; + FLAC__metadata_chain_delete(*chain); + FLAC__metadata_iterator_delete(iterator); + return error; + } + /* iterator is left pointing to new block */ + FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block); + } + + FLAC__metadata_iterator_delete(iterator); + + FLAC__ASSERT(0 != *block); + FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + return 0; +} + +static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime) +{ + struct flac_stat_s stats; + const FLAC__bool have_stats = get_file_stats_(filename, &stats); + + (void)grabbag__file_change_stats(filename, /*read_only=*/false); + + FLAC__metadata_chain_sort_padding(chain); + if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) { + const char *error; + error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)]; + FLAC__metadata_chain_delete(chain); + return error; + } + + FLAC__metadata_chain_delete(chain); + + if(have_stats) + set_file_stats_(filename, &stats); + + return 0; +} + +const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime) +{ + FLAC__Metadata_Chain *chain; + FLAC__StreamMetadata *block = NULL; + const char *error; + + if(0 != (error = store_to_file_pre_(filename, &chain, &block))) + return error; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment(block, album_gain, album_peak, title_gain, title_peak))) { + FLAC__metadata_chain_delete(chain); + return error; + } + + if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) + return error; + + return 0; +} + +const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime) +{ + FLAC__Metadata_Chain *chain; + FLAC__StreamMetadata *block = NULL; + const char *error; + + if(0 != (error = store_to_file_pre_(filename, &chain, &block))) + return error; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) { + FLAC__metadata_chain_delete(chain); + return error; + } + + if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) + return error; + + return 0; +} + +const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime) +{ + FLAC__Metadata_Chain *chain; + FLAC__StreamMetadata *block = NULL; + const char *error; + + if(0 != (error = store_to_file_pre_(filename, &chain, &block))) + return error; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) { + FLAC__metadata_chain_delete(chain); + return error; + } + + if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) + return error; + + return 0; +} + +const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime) +{ + FLAC__Metadata_Chain *chain; + FLAC__StreamMetadata *block = NULL; + const char *error; + + if(0 != (error = store_to_file_pre_(filename, &chain, &block))) + return error; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) { + FLAC__metadata_chain_delete(chain); + return error; + } + + if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) + return error; + + return 0; +} + +static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val) +{ + char s[32], *end; + const char *p, *q; + double v; + + FLAC__ASSERT(0 != entry); + FLAC__ASSERT(0 != val); + + p = (const char *)entry->entry; + q = strchr(p, '='); + if(0 == q) + return false; + q++; + safe_strncpy(s, q, local_min(sizeof(s), (size_t) (entry->length - (q-p)))); + + v = strtod(s, &end); + if(end == s) + return false; + + *val = v; + return true; +} + +FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak) +{ + int reference_offset, gain_offset, peak_offset; + char *saved_locale; + FLAC__bool res = true; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(0 != reference); + FLAC__ASSERT(0 != gain); + FLAC__ASSERT(0 != peak); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + /* Default to current level until overridden by a detected tag; this + * will always be true until we change replaygain_analysis.c + */ + *reference = ReplayGainReferenceLoudness; + + /* + * We need to save the old locale and switch to "C" because the locale + * influences the behaviour of strtod and we want it a certain way. + */ + saved_locale = strdup(setlocale(LC_ALL, 0)); + if (0 == saved_locale) + return false; + setlocale(LC_ALL, "C"); + + if(0 <= (reference_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS))) + (void)parse_double_(block->data.vorbis_comment.comments + reference_offset, reference); + + if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN : GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN)))) + res = false; + if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK : GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK)))) + res = false; + + if(res && !parse_double_(block->data.vorbis_comment.comments + gain_offset, gain)) + res = false; + if(res && !parse_double_(block->data.vorbis_comment.comments + peak_offset, peak)) + res = false; + if(res && *peak < 0.0) + res = false; + + setlocale(LC_ALL, saved_locale); + free(saved_locale); + + /* something failed; retry with strict */ + if (!res && !strict) + res = grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak); + + return res; +} + +double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping) +{ + double scale; + FLAC__ASSERT(peak >= 0.0); + gain += preamp; + scale = (float) pow(10.0, gain * 0.05); + if(prevent_clipping && peak > 0.0) { + const double max_scale = (float)(1.0 / peak); + if(scale > max_scale) + scale = max_scale; + } + return scale; +} diff --git a/vendor/flac/src/share/grabbag/seektable.c b/vendor/flac/src/share/grabbag/seektable.c new file mode 100644 index 0000000..01caa99 --- /dev/null +++ b/vendor/flac/src/share/grabbag/seektable.c @@ -0,0 +1,105 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "share/grabbag.h" +#include "share/compat.h" +#include "FLAC/assert.h" +#include /* for atoi() */ +#include + +FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, uint32_t sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points) +{ + uint32_t i; + const char *pt; + + FLAC__ASSERT(0 != spec); + FLAC__ASSERT(0 != seektable_template); + FLAC__ASSERT(seektable_template->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if(0 != spec_has_real_points) + *spec_has_real_points = false; + + for(pt = spec, i = 0; pt && *pt; i++) { + const char *q = strchr(pt, ';'); + FLAC__ASSERT(0 != q); + + if(q > pt) { + if(0 == strncmp(pt, "X;", 2)) { /* -S X */ + if(!FLAC__metadata_object_seektable_template_append_placeholders(seektable_template, 1)) + return false; + } + else if(q[-1] == 'x') { /* -S #x */ + if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */ + if(0 != spec_has_real_points) + *spec_has_real_points = true; + if(!only_explicit_placeholders) { + const int n = (uint32_t)atoi(pt); + if(n > 0) + if(!FLAC__metadata_object_seektable_template_append_spaced_points(seektable_template, (uint32_t)n, total_samples_to_encode)) + return false; + } + } + } + else if(q[-1] == 's') { /* -S #s */ + if(total_samples_to_encode > 0 && sample_rate > 0) { /* we can only do these if we know the number of samples and sample rate to encode up front */ + if(0 != spec_has_real_points) + *spec_has_real_points = true; + if(!only_explicit_placeholders) { + const double sec = atof(pt); + if(sec > 0.0) { + uint32_t samples = (uint32_t)(sec * (double)sample_rate); + /* Restrict seekpoints to two per second of audio. */ + samples = samples < sample_rate / 2 ? sample_rate / 2 : samples; + if(samples > 0) { + /* +1 for the initial point at sample 0 */ + if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(seektable_template, samples, total_samples_to_encode)) + return false; + } + } + } + } + } + else { /* -S # */ + if(0 != spec_has_real_points) + *spec_has_real_points = true; + if(!only_explicit_placeholders) { + char *endptr; + const FLAC__int64 n = (FLAC__int64)strtoll(pt, &endptr, 10); + if( + (n > 0 || (endptr > pt && *endptr == ';')) && /* is a valid number (extra check needed for "0") */ + (total_samples_to_encode == 0 || (FLAC__uint64)n < total_samples_to_encode) /* number is not >= the known total_samples_to_encode */ + ) + if(!FLAC__metadata_object_seektable_template_append_point(seektable_template, (FLAC__uint64)n)) + return false; + } + } + } + + pt = ++q; + } + + if(!FLAC__metadata_object_seektable_template_sort(seektable_template, /*compact=*/true)) + return false; + + return true; +} diff --git a/vendor/flac/src/share/grabbag/snprintf.c b/vendor/flac/src/share/grabbag/snprintf.c new file mode 100644 index 0000000..bd7ffba --- /dev/null +++ b/vendor/flac/src/share/grabbag/snprintf.c @@ -0,0 +1,101 @@ +/* grabbag - Convenience lib for various routines common to several tools + * Copyright (C) 2013-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "share/compat.h" + +/* + * FLAC needs to compile and work correctly on systems with a normal ISO C99 + * snprintf as well as Microsoft Visual Studio which has an non-standards + * conformant snprint_s function. + * + * The important difference occurs when the resultant string (plus string + * terminator) would have been longer than the supplied size parameter. When + * this happens, ISO C's snprintf returns the length of resultant string, but + * does not over-write the end of the buffer. MS's snprintf_s in this case + * returns -1. + * + * The _MSC_VER code below attempts to modify the return code for vsnprintf_s + * to something that is more compatible with the behaviour of the ISO C version. + */ + +int +flac_snprintf(char *str, size_t size, const char *fmt, ...) +{ + va_list va; + int rc; + +#if defined _MSC_VER + if (size == 0) + return 1024; +#endif + + va_start (va, fmt); + +#if defined _MSC_VER + rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va); + if (rc < 0) + rc = size - 1; +#elif defined __MINGW32__ + rc = __mingw_vsnprintf (str, size, fmt, va); +#else + rc = vsnprintf (str, size, fmt, va); +#endif + va_end (va); + + return rc; +} + +int +flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va) +{ + int rc; + +#if defined _MSC_VER + if (size == 0) + return 1024; + rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va); + if (rc < 0) + rc = size - 1; +#elif defined __MINGW32__ + rc = __mingw_vsnprintf (str, size, fmt, va); +#else + rc = vsnprintf (str, size, fmt, va); +#endif + + return rc; +} diff --git a/vendor/flac/src/share/replaygain_analysis/CMakeLists.txt b/vendor/flac/src/share/replaygain_analysis/CMakeLists.txt new file mode 100644 index 0000000..4362b90 --- /dev/null +++ b/vendor/flac/src/share/replaygain_analysis/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(replaygain_analysis STATIC + replaygain_analysis.c) diff --git a/vendor/flac/src/share/replaygain_analysis/replaygain_analysis.c b/vendor/flac/src/share/replaygain_analysis/replaygain_analysis.c new file mode 100644 index 0000000..37b77ab --- /dev/null +++ b/vendor/flac/src/share/replaygain_analysis/replaygain_analysis.c @@ -0,0 +1,575 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * original coding by Glen Sawyer (glensawyer@hotmail.com) + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) + * -- credit him for all the _good_ programming ;) + * + * minor cosmetic tweaks to integrate with FLAC by Josh Coalson + * + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +/* + * Here's the deal. Call + * + * InitGainAnalysis ( long samplefreq ); + * + * to initialize everything. Call + * + * AnalyzeSamples ( const flac_float_t* left_samples, + * const flac_float_t* right_samples, + * size_t num_samples, + * int num_channels ); + * + * as many times as you want, with as many or as few samples as you want. + * If mono, pass the sample buffer in through left_samples, leave + * right_samples NULL, and make sure num_channels = 1. + * + * GetTitleGain() + * + * will return the recommended dB level change for all samples analyzed + * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis(). + * + * GetAlbumGain() + * + * will return the recommended dB level change for all samples analyzed + * since InitGainAnalysis() was called and finalized with GetTitleGain(). + * + * Pseudo-code to process an album: + * + * flac_float_t l_samples [4096]; + * flac_float_t r_samples [4096]; + * size_t num_samples; + * uint32_t num_songs; + * uint32_t i; + * + * InitGainAnalysis ( 44100 ); + * for ( i = 1; i <= num_songs; i++ ) { + * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 ) + * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 ); + * fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() ); + * } + * fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() ); + */ + +/* + * So here's the main source of potential code confusion: + * + * The filters applied to the incoming samples are IIR filters, + * meaning they rely on up to number of previous samples + * AND up to number of previous filtered samples. + * + * I set up the AnalyzeSamples routine to minimize memory usage and interface + * complexity. The speed isn't compromised too much (I don't think), but the + * internal complexity is higher than it should be for such a relatively + * simple routine. + * + * Optimization/clarity suggestions are welcome. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "share/alloc.h" +#include "share/compat.h" +#include "share/replaygain_analysis.h" + +flac_float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */ + +#define YULE_ORDER 10 +#define BUTTER_ORDER 2 +#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */ +#define RMS_WINDOW_TIME 50 /* Time slice size [ms] */ +#define STEPS_per_dB 100. /* Table entries per dB */ +#define MAX_dB 120. /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */ + +#define MAX_ORDER (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) +#define PINK_REF 64.82 /* 298640883795 */ /* calibration value */ + +static flac_float_t linprebuf [MAX_ORDER * 2]; +static flac_float_t* linpre; /* left input samples, with pre-buffer */ +static flac_float_t* lstepbuf; +static flac_float_t* lstep; /* left "first step" (i.e. post first filter) samples */ +static flac_float_t* loutbuf; +static flac_float_t* lout; /* left "out" (i.e. post second filter) samples */ +static flac_float_t rinprebuf [MAX_ORDER * 2]; +static flac_float_t* rinpre; /* right input samples ... */ +static flac_float_t* rstepbuf; +static flac_float_t* rstep; +static flac_float_t* routbuf; +static flac_float_t* rout; +static uint32_t sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */ +static uint64_t totsamp; +static double lsum; +static double rsum; +#if 0 +static uint32_t A [(size_t)(STEPS_per_dB * MAX_dB)]; +static uint32_t B [(size_t)(STEPS_per_dB * MAX_dB)]; +#else +/* [JEC] Solaris Forte compiler doesn't like float calc in array indices */ +static uint32_t A [120 * 100]; +static uint32_t B [120 * 100]; +#endif + +#ifdef _MSC_VER +#pragma warning ( disable : 4305 ) +#endif + +struct ReplayGainFilter { + long rate; + uint32_t downsample; + flac_float_t BYule[YULE_ORDER+1]; + flac_float_t AYule[YULE_ORDER+1]; + flac_float_t BButter[BUTTER_ORDER+1]; + flac_float_t AButter[BUTTER_ORDER+1]; +}; + +static struct ReplayGainFilter *replaygainfilter; + +static const struct ReplayGainFilter ReplayGainFilters[] = { + + { + 48000, 0, /* ORIGINAL */ + { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619, 0.02161526843274, -0.02074045215285, 0.00594298065125, 0.00306428023191, 0.00012025322027, 0.00288463683916 }, + { 1.00000000000000, -3.84664617118067, 7.81501653005538, -11.34170355132042, 13.05504219327545, -12.28759895145294, 9.48293806319790, -5.87257861775999, 2.75465861874613, -0.86984376593551, 0.13919314567432 }, + { 0.98621192462708, -1.97242384925416, 0.98621192462708 }, + { 1.00000000000000, -1.97223372919527, 0.97261396931306 }, + }, + + { + 44100, 0, /* ORIGINAL */ + { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936, 0.02245293253339, -0.02596338512915, 0.01624864962975, -0.00240879051584, 0.00674613682247, -0.00187763777362 }, + { 1.00000000000000, -3.47845948550071, 6.36317777566148, -8.54751527471874, 9.47693607801280, -8.81498681370155, 6.85401540936998, -4.39470996079559, 2.19611684890774, -0.75104302451432, 0.13149317958808 }, + { 0.98500175787242, -1.97000351574484, 0.98500175787242 }, + { 1.00000000000000, -1.96977855582618, 0.97022847566350 }, + }, + + { + 37800, 0, + { 0.10296717174470, -0.04877975583256, -0.02878009075237, -0.03519509188311, 0.02888717172493, -0.00609872684844, 0.00209851217112, 0.00911704668543, 0.01154404718589, -0.00630293688700, 0.00107527155228 }, + { 1.00000000000000, -2.64848054923531, 3.58406058405771, -3.83794914179161, 3.90142345804575, -3.50179818637243, 2.67085284083076, -1.82581142372418, 1.09530368139801, -0.47689017820395, 0.11171431535905 }, + { 0.98252400815195, -1.96504801630391, 0.98252400815195 }, + { 1.00000000000000, -1.96474258269041, 0.96535344991740 }, + }, + + { + 36000, 0, + { 0.11572297028613, -0.04120916051252, -0.04977731768022, -0.01047308680426, 0.00750863219157, 0.00055507694408, 0.00140344192886, 0.01286095246036, 0.00998223033885, -0.00725013810661, 0.00326503346879 }, + { 1.00000000000000, -2.43606802820871, 3.01907406973844, -2.90372016038192, 2.67947188094303, -2.17606479220391, 1.44912956803015, -0.87785765549050, 0.53592202672557, -0.26469344817509, 0.07495878059717 }, + { 0.98165826840326, -1.96331653680652, 0.98165826840326 }, + { 1.00000000000000, -1.96298008938934, 0.96365298422371 }, + }, + + { + 32000, 0, /* ORIGINAL */ + { 0.15457299681924, -0.09331049056315, -0.06247880153653, 0.02163541888798, -0.05588393329856, 0.04781476674921, 0.00222312597743, 0.03174092540049, -0.01390589421898, 0.00651420667831, -0.00881362733839 }, + { 1.00000000000000, -2.37898834973084, 2.84868151156327, -2.64577170229825, 2.23697657451713, -1.67148153367602, 1.00595954808547, -0.45953458054983, 0.16378164858596, -0.05032077717131, 0.02347897407020 }, + { 0.97938932735214, -1.95877865470428, 0.97938932735214 }, + { 1.00000000000000, -1.95835380975398, 0.95920349965459 }, + }, + + { + 28000, 0, + { 0.23882392323383, -0.22007791534089, -0.06014581950332, 0.05004458058021, -0.03293111254977, 0.02348678189717, 0.04290549799671, -0.00938141862174, 0.00015095146303, -0.00712601540885, -0.00626520210162 }, + { 1.00000000000000, -2.06894080899139, 1.76944699577212, -0.81404732584187, 0.25418286850232, -0.30340791669762, 0.35616884070937, -0.14967310591258, -0.07024154183279, 0.11078404345174, -0.03551838002425 }, + { 0.97647981663949, -1.95295963327897, 0.97647981663949 }, + { 1.00000000000000, -1.95240635772520, 0.95351290883275 }, + + }, + + { + 24000, 0, /* ORIGINAL */ + { 0.30296907319327, -0.22613988682123, -0.08587323730772, 0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913, 0.06276101321749, -0.00000828086748, 0.00205861885564, -0.02950134983287 }, + { 1.00000000000000, -1.61273165137247, 1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906, 0.39120800788284, -0.22138138954925, 0.04500235387352, 0.02005851806501, 0.00302439095741 }, + { 0.97531843204928, -1.95063686409857, 0.97531843204928 }, + { 1.00000000000000, -1.95002759149878, 0.95124613669835 }, + }, + + { + 22050, 0, /* ORIGINAL */ + { 0.33642304856132, -0.25572241425570, -0.11828570177555, 0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440, 0.05724228140351, 0.00832043980773, -0.01635381384540, -0.01760176568150 }, + { 1.00000000000000, -1.49858979367799, 0.87350271418188, 0.12205022308084, -0.80774944671438, 0.47854794562326, -0.12453458140019, -0.04067510197014, 0.08333755284107, -0.04237348025746, 0.02977207319925 }, + { 0.97316523498161, -1.94633046996323, 0.97316523498161 }, + { 1.00000000000000, -1.94561023566527, 0.94705070426118 }, + }, + + { + 18900, 0, + { 0.38412657295385, -0.44533729608120, 0.20426638066221, -0.28031676047946, 0.31484202614802, -0.26078311203207, 0.12925201224848, -0.01141164696062, 0.03036522115769, -0.03776339305406, 0.00692036603586 }, + { 1.00000000000000, -1.74403915585708, 1.96686095832499, -2.10081452941881, 1.90753918182846, -1.83814263754422, 1.36971352214969, -0.77883609116398, 0.39266422457649, -0.12529383592986, 0.05424760697665 }, + { 0.96535326815829, -1.93070653631658, 0.96535326815829 }, + { 1.00000000000000, -1.92950577983524, 0.93190729279793 }, + }, + + { + 16000, 0, /* ORIGINAL */ + { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551, 0.04078262797139, -0.12398163381748, 0.04097565135648, 0.10478503600251, -0.01863887810927, -0.03193428438915, 0.00541907748707 }, + { 1.00000000000000, -0.62820619233671, 0.29661783706366, -0.37256372942400, 0.00213767857124, -0.42029820170918, 0.22199650564824, 0.00613424350682, 0.06747620744683, 0.05784820375801, 0.03222754072173 }, + { 0.96454515552826, -1.92909031105652, 0.96454515552826 }, + { 1.00000000000000, -1.92783286977036, 0.93034775234268 }, + }, + + { + 12000, 0, /* ORIGINAL */ + { 0.56619470757641, -0.75464456939302, 0.16242137742230, 0.16744243493672, -0.18901604199609, 0.30931782841830, -0.27562961986224, 0.00647310677246, 0.08647503780351, -0.03788984554840, -0.00588215443421 }, + { 1.00000000000000, -1.04800335126349, 0.29156311971249, -0.26806001042947, 0.00819999645858, 0.45054734505008, -0.33032403314006, 0.06739368333110, -0.04784254229033, 0.01639907836189, 0.01807364323573 }, + { 0.96009142950541, -1.92018285901082, 0.96009142950541 }, + { 1.00000000000000, -1.91858953033784, 0.92177618768381 }, + }, + + { + 11025, 0, /* ORIGINAL */ + { 0.58100494960553, -0.53174909058578, -0.14289799034253, 0.17520704835522, 0.02377945217615, 0.15558449135573, -0.25344790059353, 0.01628462406333, 0.06920467763959, -0.03721611395801, -0.00749618797172 }, + { 1.00000000000000, -0.51035327095184, -0.31863563325245, -0.20256413484477, 0.14728154134330, 0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053, 0.02442357316099, 0.01818801111503 }, + { 0.95856916599601, -1.91713833199203, 0.95856916599601 }, + { 1.00000000000000, -1.91542108074780, 0.91885558323625 }, + }, + + { + 8000, 0, /* ORIGINAL */ + { 0.53648789255105, -0.42163034350696, -0.00275953611929, 0.04267842219415, -0.10214864179676, 0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000, 0.04788665548180, -0.02217936801134 }, + { 1.00000000000000, -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242, 0.26408300200955, 0.15113130533216, -0.17556493366449, -0.18823009262115, 0.05477720428674, 0.04704409688120 }, + { 0.94597685600279, -1.89195371200558, 0.94597685600279 }, + { 1.00000000000000, -1.88903307939452, 0.89487434461664 }, + }, + +}; + +#ifdef _MSC_VER +#pragma warning ( default : 4305 ) +#endif + +/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */ + +static void +filter ( const flac_float_t* input, flac_float_t* output, size_t nSamples, const flac_float_t* a, const flac_float_t* b, size_t order, uint32_t downsample ) +{ + double y; + size_t i; + size_t k; + + const flac_float_t* input_head = input; + const flac_float_t* input_tail; + + flac_float_t* output_head = output; + flac_float_t* output_tail; + + for ( i = 0; i < nSamples; i++, input_head += downsample, ++output_head ) { + + input_tail = input_head; + output_tail = output_head; + + y = *input_head * b[0]; + + for ( k = 1; k <= order; k++ ) { + input_tail -= downsample; + --output_tail; + y += *input_tail * b[k] - *output_tail * a[k]; + } + + output[i] = (flac_float_t)y; + } +} + +/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */ + +static struct ReplayGainFilter* +CreateGainFilter ( long samplefreq ) +{ + uint32_t i; + long maxrate = 0; + uint32_t downsample = 1; + struct ReplayGainFilter* gainfilter = malloc(sizeof(*gainfilter)); + + if ( !gainfilter ) + return 0; + + while (1) { + for ( i = 0; i < sizeof(ReplayGainFilters)/sizeof(ReplayGainFilters[0]); ++i ) { + if (maxrate < ReplayGainFilters[i].rate) + maxrate = ReplayGainFilters[i].rate; + + if ( ReplayGainFilters[i].rate == samplefreq ) { + *gainfilter = ReplayGainFilters[i]; + gainfilter->downsample = downsample; + return gainfilter; + } + } + + if (samplefreq < maxrate) + break; + + while (samplefreq > maxrate) { + downsample *= 2; + samplefreq /= 2; + } + } + + free(gainfilter); + + return 0; +} + +static void* +ReallocateWindowBuffer(uint32_t window_size, flac_float_t **window_buffer) +{ + *window_buffer = safe_realloc_(*window_buffer, sizeof(**window_buffer) * (window_size + MAX_ORDER)); + return *window_buffer; +} + +static int +ResetSampleFrequency ( long samplefreq ) { + int i; + + free(replaygainfilter); + + replaygainfilter = CreateGainFilter( samplefreq ); + + if ( ! replaygainfilter) + return INIT_GAIN_ANALYSIS_ERROR; + + sampleWindow = + (replaygainfilter->rate * RMS_WINDOW_TIME + 1000-1) / 1000; + + if ( ! ReallocateWindowBuffer(sampleWindow, &lstepbuf) || + ! ReallocateWindowBuffer(sampleWindow, &rstepbuf) || + ! ReallocateWindowBuffer(sampleWindow, &loutbuf) || + ! ReallocateWindowBuffer(sampleWindow, &routbuf) ) { + + return INIT_GAIN_ANALYSIS_ERROR; + } + + /* zero out initial values */ + for ( i = 0; i < MAX_ORDER; i++ ) + linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.; + + lsum = 0.; + rsum = 0.; + totsamp = 0; + + memset ( A, 0, sizeof(A) ); + + return INIT_GAIN_ANALYSIS_OK; +} + +int +ValidGainFrequency ( long samplefreq ) +{ + struct ReplayGainFilter* gainfilter = CreateGainFilter( samplefreq ); + + if (gainfilter == 0) { + return 0; + } else { + free(gainfilter); + return 1; + } +} + +int +InitGainAnalysis ( long samplefreq ) +{ + if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) { + return INIT_GAIN_ANALYSIS_ERROR; + } + + linpre = linprebuf + MAX_ORDER; + rinpre = rinprebuf + MAX_ORDER; + lstep = lstepbuf + MAX_ORDER; + rstep = rstepbuf + MAX_ORDER; + lout = loutbuf + MAX_ORDER; + rout = routbuf + MAX_ORDER; + + memset ( B, 0, sizeof(B) ); + + return INIT_GAIN_ANALYSIS_OK; +} + +/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */ + +int +AnalyzeSamples ( const flac_float_t* left_samples, const flac_float_t* right_samples, size_t num_samples, int num_channels ) +{ + uint32_t downsample = replaygainfilter->downsample; + const flac_float_t* curleft; + const flac_float_t* curright; + long prebufsamples; + long batchsamples; + long cursamples; + long cursamplepos; + int i; + + num_samples /= downsample; + + if ( num_samples == 0 ) + return GAIN_ANALYSIS_OK; + + cursamplepos = 0; + batchsamples = num_samples; + + switch ( num_channels) { + case 1: right_samples = left_samples; + case 2: break; + default: return GAIN_ANALYSIS_ERROR; + } + + prebufsamples = MAX_ORDER; + if ((size_t) prebufsamples > num_samples) + prebufsamples = num_samples; + + for ( i = 0; i < prebufsamples; ++i ) { + linprebuf[i+MAX_ORDER] = left_samples [i * downsample]; + rinprebuf[i+MAX_ORDER] = right_samples[i * downsample]; + } + + while ( batchsamples > 0 ) { + cursamples = batchsamples > (long)(sampleWindow-totsamp) ? (long)(sampleWindow - totsamp) : batchsamples; + if ( cursamplepos < MAX_ORDER ) { + downsample = 1; + curleft = linpre+cursamplepos; + curright = rinpre+cursamplepos; + if (cursamples > MAX_ORDER - cursamplepos ) + cursamples = MAX_ORDER - cursamplepos; + } + else { + downsample = replaygainfilter->downsample; + curleft = left_samples + cursamplepos * downsample; + curright = right_samples + cursamplepos * downsample; + } + + filter ( curleft , lstep + totsamp, cursamples, replaygainfilter->AYule, replaygainfilter->BYule, YULE_ORDER, downsample ); + filter ( curright, rstep + totsamp, cursamples, replaygainfilter->AYule, replaygainfilter->BYule, YULE_ORDER, downsample ); + + filter ( lstep + totsamp, lout + totsamp, cursamples, replaygainfilter->AButter, replaygainfilter->BButter, BUTTER_ORDER, 1 ); + filter ( rstep + totsamp, rout + totsamp, cursamples, replaygainfilter->AButter, replaygainfilter->BButter, BUTTER_ORDER, 1 ); + + for ( i = 0; i < cursamples; i++ ) { /* Get the squared values */ + lsum += lout [totsamp+i] * lout [totsamp+i]; + rsum += rout [totsamp+i] * rout [totsamp+i]; + } + + batchsamples -= cursamples; + cursamplepos += cursamples; + totsamp += cursamples; + if ( totsamp == sampleWindow ) { /* Get the Root Mean Square (RMS) for this set of samples */ + double val = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 ); + int ival = (int) val; + if ( ival < 0 ) ival = 0; + if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1; + A [ival]++; + lsum = rsum = 0.; + memmove ( loutbuf , loutbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) ); + memmove ( routbuf , routbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) ); + memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) ); + memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) ); + totsamp = 0; + } + if ( totsamp > sampleWindow ) /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */ + return GAIN_ANALYSIS_ERROR; + } + + if ( num_samples < MAX_ORDER ) { + memmove ( linprebuf, linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(flac_float_t) ); + memmove ( rinprebuf, rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(flac_float_t) ); + memcpy ( linprebuf + MAX_ORDER - num_samples, left_samples, num_samples * sizeof(flac_float_t) ); + memcpy ( rinprebuf + MAX_ORDER - num_samples, right_samples, num_samples * sizeof(flac_float_t) ); + } + else { + downsample = replaygainfilter->downsample; + + left_samples += (num_samples - MAX_ORDER) * downsample; + right_samples += (num_samples - MAX_ORDER) * downsample; + + for ( i = 0; i < MAX_ORDER; ++i ) { + linprebuf[i] = left_samples [i * downsample]; + rinprebuf[i] = right_samples[i * downsample]; + } + } + + return GAIN_ANALYSIS_OK; +} + + +static flac_float_t +analyzeResult ( uint32_t* Array, size_t len ) +{ + uint32_t elems; + int32_t upper; + size_t i; + + elems = 0; + for ( i = 0; i < len; i++ ) + elems += Array[i]; + if ( elems == 0 ) + return GAIN_NOT_ENOUGH_SAMPLES; + +/* workaround for GCC bug #61423: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61423 */ +#if 0 + upper = (int32_t) ceil (elems * (1. - RMS_PERCENTILE)); +#else + upper = (int32_t) (elems / 20 + ((elems % 20) ? 1 : 0)); +#endif + for ( i = len; i-- > 0; ) { + if ( (upper -= Array[i]) <= 0 ) + break; + } + + return (flac_float_t) ((flac_float_t)PINK_REF - (flac_float_t)i / (flac_float_t)STEPS_per_dB); +} + + +flac_float_t +GetTitleGain ( void ) +{ + flac_float_t retval; + uint32_t i; + + retval = analyzeResult ( A, sizeof(A)/sizeof(*A) ); + + for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) { + B[i] += A[i]; + A[i] = 0; + } + + for ( i = 0; i < MAX_ORDER; i++ ) + linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f; + + totsamp = 0; + lsum = rsum = 0.; + return retval; +} + + +flac_float_t +GetAlbumGain ( void ) +{ + return analyzeResult ( B, sizeof(B)/sizeof(*B) ); +} + +/* end of replaygain_analysis.c */ diff --git a/vendor/flac/src/share/replaygain_synthesis/CMakeLists.txt b/vendor/flac/src/share/replaygain_synthesis/CMakeLists.txt new file mode 100644 index 0000000..0736f4f --- /dev/null +++ b/vendor/flac/src/share/replaygain_synthesis/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(replaygain_synthesis STATIC + replaygain_synthesis.c) diff --git a/vendor/flac/src/share/replaygain_synthesis/replaygain_synthesis.c b/vendor/flac/src/share/replaygain_synthesis/replaygain_synthesis.c new file mode 100644 index 0000000..8d4fda6 --- /dev/null +++ b/vendor/flac/src/share/replaygain_synthesis/replaygain_synthesis.c @@ -0,0 +1,429 @@ +/* replaygain_synthesis - Routines for applying ReplayGain to a signal + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +/* + * This is an aggregation of pieces of code from John Edwards' WaveGain + * program. Mostly cosmetic changes were made; otherwise, the dithering + * code is almost untouched and the gain processing was converted from + * processing a whole file to processing chunks of samples. + * + * The original copyright notices for WaveGain's dither.c and wavegain.c + * appear below: + */ +/* + * (c) 2002 John Edwards + * mostly lifted from work by Frank Klemm + * random functions for dithering. + */ +/* + * Copyright (C) 2002 John Edwards + * Additional code by Magnus Holmgren and Gian-Carlo Pascutto + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include /* for memset() */ +#include +#include "share/compat.h" +#include "share/replaygain_synthesis.h" +#include "FLAC/assert.h" + +#define FLAC__I64L(x) x##LL + + +/* + * the following is based on parts of dither.c + */ + + +/* + * This is a simple random number generator with good quality for audio purposes. + * It consists of two polycounters with opposite rotation direction and different + * periods. The periods are coprime, so the total period is the product of both. + * + * ------------------------------------------------------------------------------------------------- + * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| + * | ------------------------------------------------------------------------------------------------- + * | | | | | | | + * | +--+--+--+-XOR-+--------+ + * | | + * +--------------------------------------------------------------------------------------+ + * + * ------------------------------------------------------------------------------------------------- + * |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+ + * ------------------------------------------------------------------------------------------------- | + * | | | | | + * +--+----XOR----+--+ | + * | | + * +----------------------------------------------------------------------------------------+ + * + * + * The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481, + * which gives a period of 18.410.713.077.675.721.215. The result is the + * XORed values of both generators. + */ + +static uint32_t random_int_(void) +{ + static const uint8_t parity_[256] = { + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0 + }; + static uint32_t r1_ = 1; + static uint32_t r2_ = 1; + + uint32_t t1, t2, t3, t4; + + /* Parity calculation is done via table lookup, this is also available + * on CPUs without parity, can be implemented in C and avoid unpredictable + * jumps and slow rotate through the carry flag operations. + */ + t3 = t1 = r1_; t4 = t2 = r2_; + t1 &= 0xF5; t2 >>= 25; + t1 = parity_[t1]; t2 &= 0x63; + t1 <<= 31; t2 = parity_[t2]; + + return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 ); +} + +/* gives a equal distributed random number */ +/* between -2^31*mult and +2^31*mult */ +static double random_equi_(double mult) +{ + return mult * (int) random_int_(); +} + +/* gives a triangular distributed random number */ +/* between -2^32*mult and +2^32*mult */ +static double random_triangular_(double mult) +{ + return mult * ( (double) (int) random_int_() + (double) (int) random_int_() ); +} + + +static const float F44_0 [16 + 32] = { + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0 +}; + + +static const float F44_1 [16 + 32] = { /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */ + (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, + (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, + (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, + (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, + + (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, + (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, + (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, + (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, + + (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, + (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, + (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, + (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, +}; + + +static const float F44_2 [16 + 32] = { /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */ + (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, + (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, + (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, + (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, + + (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, + (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, + (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, + (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, + + (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, + (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, + (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, + (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, +}; + + +static const float F44_3 [16 + 32] = { /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */ + (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, + (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, + (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, + (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099, + + (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, + (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, + (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, + (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099, + + (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, + (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, + (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, + (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099 +}; + + +static double scalar16_(const float* x, const float* y) +{ + return + x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] + + x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] + + x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] + + x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15]; +} + + +void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype) +{ + static uint8_t default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67, 0, 0 }; + static const float* F [] = { F44_0, F44_1, F44_2, F44_3 }; + + int indx; + + if (shapingtype < 0) shapingtype = 0; + if (shapingtype > 3) shapingtype = 3; + d->ShapingType = (NoiseShaping)shapingtype; + indx = bits - 11 - shapingtype; + if (indx < 0) indx = 0; + if (indx > 9) indx = 9; + + memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) ); + memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) ); + + d->FilterCoeff = F [shapingtype]; + d->Mask = ((FLAC__uint64)-1) << (32 - bits); + d->Add = 0.5 * ((1L << (32 - bits)) - 1); + d->Dither = 0.01f*default_dither[indx] / (((FLAC__int64)1) << bits); + d->LastHistoryIndex = 0; +} + +static inline int64_t +ROUND64 (DitherContext *d, double x) +{ + union { + double d; + int64_t i; + } doubletmp; + + doubletmp.d = x + d->Add + (int64_t)FLAC__I64L(0x001FFFFD80000000); + + return doubletmp.i - (int64_t)FLAC__I64L(0x433FFFFD80000000); +} + +/* + * the following is based on parts of wavegain.c + */ + +static int64_t dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k) +{ + double Sum2; + int64_t val; + + if(do_dithering) { + if(shapingtype == 0) { + double tmp = random_equi_(d->Dither); + Sum2 = tmp - d->LastRandomNumber [k]; + d->LastRandomNumber [k] = (int)tmp; + Sum2 = Sum += Sum2; + val = ROUND64(d, Sum2) & d->Mask; + } + else { + Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i); + Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2; + Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i); + val = ROUND64(d, Sum2) & d->Mask; + d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val); + } + return val; + } + + return ROUND64(d, Sum); +} + +#if 0 + float peak = 0.f, + new_peak, + factor_clip + double scale, + dB; + + ... + + peak is in the range -32768.0 .. 32767.0 + + /* calculate factors for ReplayGain and ClippingPrevention */ + *track_gain = GetTitleGain() + settings->man_gain; + scale = (float) pow(10., *track_gain * 0.05); + if(settings->clip_prev) { + factor_clip = (float) (32767./( peak + 1)); + if(scale < factor_clip) + factor_clip = 1.f; + else + factor_clip /= scale; + scale *= factor_clip; + } + new_peak = (float) peak * scale; + + dB = 20. * log10(scale); + *track_gain = (float) dB; + + const double scale = pow(10., (double)gain * 0.05); +#endif + + +size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool uint32_t_data_out, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, const uint32_t source_bps, const uint32_t target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context) +{ + static const FLAC__int64 hard_clip_factors_[33] = { + 0, /* 0 bits-per-sample (not supported) */ + 0, /* 1 bits-per-sample (not supported) */ + 0, /* 2 bits-per-sample (not supported) */ + 0, /* 3 bits-per-sample (not supported) */ + -8, /* 4 bits-per-sample */ + -16, /* 5 bits-per-sample */ + -32, /* 6 bits-per-sample */ + -64, /* 7 bits-per-sample */ + -128, /* 8 bits-per-sample */ + -256, /* 9 bits-per-sample */ + -512, /* 10 bits-per-sample */ + -1024, /* 11 bits-per-sample */ + -2048, /* 12 bits-per-sample */ + -4096, /* 13 bits-per-sample */ + -8192, /* 14 bits-per-sample */ + -16384, /* 15 bits-per-sample */ + -32768, /* 16 bits-per-sample */ + -65536, /* 17 bits-per-sample */ + -131072, /* 18 bits-per-sample */ + -262144, /* 19 bits-per-sample */ + -524288, /* 20 bits-per-sample */ + -1048576, /* 21 bits-per-sample */ + -2097152, /* 22 bits-per-sample */ + -4194304, /* 23 bits-per-sample */ + -8388608, /* 24 bits-per-sample */ + -16777216, /* 25 bits-per-sample */ + -33554432, /* 26 bits-per-sample */ + -67108864, /* 27 bits-per-sample */ + -134217728, /* 28 bits-per-sample */ + -268435456, /* 29 bits-per-sample */ + -536870912, /* 30 bits-per-sample */ + -1073741824, /* 31 bits-per-sample */ + (FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */ + }; + const FLAC__int32 conv_shift = 32 - target_bps; + const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps]; + /* + * The integer input coming in has a varying range based on the + * source_bps. We want to normalize it to [-1.0, 1.0) so instead + * of doing two multiplies on each sample, we just multiple + * 'scale' by 1/(2^(source_bps-1)) + */ + const double multi_scale = scale / (double)(1u << (source_bps-1)); + + FLAC__byte * const start = data_out; + uint32_t i, channel; + const FLAC__int32 *input_; + double sample; + const uint32_t bytes_per_sample = target_bps / 8; + const uint32_t last_history_index = dither_context->LastHistoryIndex; + NoiseShaping noise_shaping = dither_context->ShapingType; + FLAC__int64 val64; + FLAC__int32 val32; + FLAC__int32 uval32; + const FLAC__uint32 twiggle = 1u << (target_bps - 1); + + FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS); + FLAC__ASSERT(source_bps >= 4); + FLAC__ASSERT(target_bps >= 4); + FLAC__ASSERT(source_bps <= 32); + FLAC__ASSERT(target_bps < 32); + FLAC__ASSERT((target_bps & 7) == 0); + + for(channel = 0; channel < channels; channel++) { + const uint32_t incr = bytes_per_sample * channels; + data_out = start + bytes_per_sample * channel; + input_ = input[channel]; + for(i = 0; i < wide_samples; i++, data_out += incr) { + sample = (double)input_[i] * multi_scale; + + if(hard_limit) { + /* hard 6dB limiting */ + if(sample < -0.5) + sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5; + else if(sample > 0.5) + sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5; + } + sample *= 2147483647.; + + val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) >> conv_shift; + + val32 = (FLAC__int32)val64; + if(val64 >= -hard_clip_factor) + val32 = (FLAC__int32)(-(hard_clip_factor+1)); + else if(val64 < hard_clip_factor) + val32 = (FLAC__int32)hard_clip_factor; + + uval32 = (FLAC__uint32)val32; + if (uint32_t_data_out) + uval32 ^= twiggle; + + if (little_endian_data_out) { + switch(target_bps) { + case 24: + data_out[2] = (FLAC__byte)(uval32 >> 16); + /* fall through */ + case 16: + data_out[1] = (FLAC__byte)(uval32 >> 8); + /* fall through */ + case 8: + data_out[0] = (FLAC__byte)uval32; + break; + } + } + else { + switch(target_bps) { + case 24: + data_out[0] = (FLAC__byte)(uval32 >> 16); + data_out[1] = (FLAC__byte)(uval32 >> 8); + data_out[2] = (FLAC__byte)uval32; + break; + case 16: + data_out[0] = (FLAC__byte)(uval32 >> 8); + data_out[1] = (FLAC__byte)uval32; + break; + case 8: + data_out[0] = (FLAC__byte)uval32; + break; + } + } + } + } + dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32; + + return wide_samples * channels * (target_bps/8); +} diff --git a/vendor/flac/src/share/utf8/CMakeLists.txt b/vendor/flac/src/share/utf8/CMakeLists.txt new file mode 100644 index 0000000..389b09e --- /dev/null +++ b/vendor/flac/src/share/utf8/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.12) + +add_library(utf8 STATIC + charset.c + iconvert.c + utf8.c) + +target_link_libraries(utf8 PUBLIC grabbag $) diff --git a/vendor/flac/src/share/utf8/charmaps.h b/vendor/flac/src/share/utf8/charmaps.h new file mode 100644 index 0000000..16d049a --- /dev/null +++ b/vendor/flac/src/share/utf8/charmaps.h @@ -0,0 +1,57 @@ + +/* + * If you need to generate more maps, use makemap.c on a system + * with a decent iconv. + */ + +static const uint16_t mapping_iso_8859_2[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7, + 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b, + 0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7, + 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, + 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, + 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e, + 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, + 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df, + 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, + 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f, + 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, + 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9 +}; + +static struct { + const char *name; + const uint16_t *map; + struct charset *charset; +} maps[] = { + { "ISO-8859-2", mapping_iso_8859_2, 0 }, + { 0, 0, 0 } +}; + +static const struct { + const char *bad; + const char *good; +} names[] = { + { "ANSI_X3.4-1968", "us-ascii" }, + { 0, 0 } +}; diff --git a/vendor/flac/src/share/utf8/charset.c b/vendor/flac/src/share/utf8/charset.c new file mode 100644 index 0000000..5c5693d --- /dev/null +++ b/vendor/flac/src/share/utf8/charset.c @@ -0,0 +1,534 @@ +/* + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * See the corresponding header file for a description of the functions + * that this file provides. + * + * This was first written for Ogg Vorbis but could be of general use. + * + * The only deliberate assumption about data sizes is that a short has + * at least 16 bits, but this code has only been tested on systems with + * 8-bit char, 16-bit short and 32-bit int. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined _WIN32 && !defined HAVE_ICONV /* should be && defined USE_CHARSET_CONVERT */ + +#include + +#include "share/alloc.h" +#include "charset.h" + +#include "charmaps.h" + +/* + * This is like the standard strcasecmp, but it does not depend + * on the locale. Locale-dependent functions can be dangerous: + * we once had a bug involving strcasecmp("iso", "ISO") in a + * Turkish locale! + * + * (I'm not really sure what the official standard says + * about the sign of strcasecmp("Z", "["), but usually + * we're only interested in whether it's zero.) + */ + +static int ascii_strcasecmp(const char *s1, const char *s2) +{ + char c1, c2; + + for (;; s1++, s2++) { + if (!*s1 || !*s2) + break; + if (*s1 == *s2) + continue; + c1 = *s1; + if ('a' <= c1 && c1 <= 'z') + c1 += 'A' - 'a'; + c2 = *s2; + if ('a' <= c2 && c2 <= 'z') + c2 += 'A' - 'a'; + if (c1 != c2) + break; + } + return (uint8_t)*s1 - (uint8_t)*s2; +} + +/* + * UTF-8 equivalents of the C library's wctomb() and mbtowc(). + */ + +int utf8_mbtowc(int *pwc, const char *s, size_t n) +{ + uint8_t c; + int wc, i, k; + + if (!n || !s) + return 0; + + c = *s; + if (c < 0x80) { + if (pwc) + *pwc = c; + return c ? 1 : 0; + } + else if (c < 0xc2) + return -1; + else if (c < 0xe0) { + if (n >= 2 && (s[1] & 0xc0) == 0x80) { + if (pwc) + *pwc = ((c & 0x1f) << 6) | (s[1] & 0x3f); + return 2; + } + else + return -1; + } + else if (c < 0xf0) + k = 3; + else if (c < 0xf8) + k = 4; + else if (c < 0xfc) + k = 5; + else if (c < 0xfe) + k = 6; + else + return -1; + + if (n < (size_t)k) + return -1; + wc = *s++ & ((1 << (7 - k)) - 1); + for (i = 1; i < k; i++) { + if ((*s & 0xc0) != 0x80) + return -1; + wc = (wc << 6) | (*s++ & 0x3f); + } + if (wc < (1 << (5 * k - 4))) + return -1; + if (pwc) + *pwc = wc; + return k; +} + +int utf8_wctomb(char *s, int wc1) +{ + uint32_t wc = wc1; + + if (!s) + return 0; + if (wc < (1u << 7)) { + *s++ = wc; + return 1; + } + else if (wc < (1u << 11)) { + *s++ = 0xc0 | (wc >> 6); + *s++ = 0x80 | (wc & 0x3f); + return 2; + } + else if (wc < (1u << 16)) { + *s++ = 0xe0 | (wc >> 12); + *s++ = 0x80 | ((wc >> 6) & 0x3f); + *s++ = 0x80 | (wc & 0x3f); + return 3; + } + else if (wc < (1u << 21)) { + *s++ = 0xf0 | (wc >> 18); + *s++ = 0x80 | ((wc >> 12) & 0x3f); + *s++ = 0x80 | ((wc >> 6) & 0x3f); + *s++ = 0x80 | (wc & 0x3f); + return 4; + } + else if (wc < (1u << 26)) { + *s++ = 0xf8 | (wc >> 24); + *s++ = 0x80 | ((wc >> 18) & 0x3f); + *s++ = 0x80 | ((wc >> 12) & 0x3f); + *s++ = 0x80 | ((wc >> 6) & 0x3f); + *s++ = 0x80 | (wc & 0x3f); + return 5; + } + else if (wc < (1u << 31)) { + *s++ = 0xfc | (wc >> 30); + *s++ = 0x80 | ((wc >> 24) & 0x3f); + *s++ = 0x80 | ((wc >> 18) & 0x3f); + *s++ = 0x80 | ((wc >> 12) & 0x3f); + *s++ = 0x80 | ((wc >> 6) & 0x3f); + *s++ = 0x80 | (wc & 0x3f); + return 6; + } + else + return -1; +} + +/* + * The charset "object" and methods. + */ + +struct charset { + int max; + int (*mbtowc)(void *table, int *pwc, const char *s, size_t n); + int (*wctomb)(void *table, char *s, int wc); + void *map; +}; + +int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n) +{ + return (*charset->mbtowc)(charset->map, pwc, s, n); +} + +int charset_wctomb(struct charset *charset, char *s, int wc) +{ + return (*charset->wctomb)(charset->map, s, wc); +} + +int charset_max(struct charset *charset) +{ + return charset->max; +} + +/* + * Implementation of UTF-8. + */ + +static int mbtowc_utf8(void *map, int *pwc, const char *s, size_t n) +{ + (void)map; + return utf8_mbtowc(pwc, s, n); +} + +static int wctomb_utf8(void *map, char *s, int wc) +{ + (void)map; + return utf8_wctomb(s, wc); +} + +/* + * Implementation of US-ASCII. + * Probably on most architectures this compiles to less than 256 bytes + * of code, so we can save space by not having a table for this one. + */ + +static int mbtowc_ascii(void *map, int *pwc, const char *s, size_t n) +{ + int wc; + + (void)map; + if (!n || !s) + return 0; + wc = (uint8_t)*s; + if (wc & ~0x7f) + return -1; + if (pwc) + *pwc = wc; + return wc ? 1 : 0; +} + +static int wctomb_ascii(void *map, char *s, int wc) +{ + (void)map; + if (!s) + return 0; + if (wc & ~0x7f) + return -1; + *s = wc; + return 1; +} + +/* + * Implementation of ISO-8859-1. + * Probably on most architectures this compiles to less than 256 bytes + * of code, so we can save space by not having a table for this one. + */ + +static int mbtowc_iso1(void *map, int *pwc, const char *s, size_t n) +{ + int wc; + + (void)map; + if (!n || !s) + return 0; + wc = (uint8_t)*s; + if (wc & ~0xff) + return -1; + if (pwc) + *pwc = wc; + return wc ? 1 : 0; +} + +static int wctomb_iso1(void *map, char *s, int wc) +{ + (void)map; + if (!s) + return 0; + if (wc & ~0xff) + return -1; + *s = wc; + return 1; +} + +/* + * Implementation of any 8-bit charset. + */ + +struct map { + const uint16_t *from; + struct inverse_map *to; +}; + +static int mbtowc_8bit(void *map1, int *pwc, const char *s, size_t n) +{ + struct map *map = map1; + uint16_t wc; + + if (!n || !s) + return 0; + wc = map->from[(uint8_t)*s]; + if (wc == 0xffff) + return -1; + if (pwc) + *pwc = (int)wc; + return wc ? 1 : 0; +} + +/* + * For the inverse map we use a hash table, which has the advantages + * of small constant memory requirement and simple memory allocation, + * but the disadvantage of slow conversion in the worst case. + * If you need real-time performance while letting a potentially + * malicious user define their own map, then the method used in + * linux/drivers/char/consolemap.c would be more appropriate. + */ + +struct inverse_map { + uint8_t first[256]; + uint8_t next[256]; +}; + +/* + * The simple hash is good enough for this application. + * Use the alternative trivial hashes for testing. + */ +#define HASH(i) ((i) & 0xff) +/* #define HASH(i) 0 */ +/* #define HASH(i) 99 */ + +static struct inverse_map *make_inverse_map(const uint16_t *from) +{ + struct inverse_map *to; + char used[256]; + int i, j, k; + + to = malloc(sizeof(struct inverse_map)); + if (!to) + return 0; + for (i = 0; i < 256; i++) + to->first[i] = to->next[i] = used[i] = 0; + for (i = 255; i >= 0; i--) + if (from[i] != 0xffff) { + k = HASH(from[i]); + to->next[i] = to->first[k]; + to->first[k] = i; + used[k] = 1; + } + + /* Point the empty buckets at an empty list. */ + for (i = 0; i < 256; i++) + if (!to->next[i]) + break; + if (i < 256) + for (j = 0; j < 256; j++) + if (!used[j]) + to->first[j] = i; + + return to; +} + +static int wctomb_8bit(void *map1, char *s, int wc1) +{ + struct map *map = map1; + uint16_t wc = wc1; + int i; + + if (!s) + return 0; + + if (wc1 & ~0xffff) + return -1; + + if (1) /* Change 1 to 0 to test the case where malloc fails. */ + if (!map->to) + map->to = make_inverse_map(map->from); + + if (map->to) { + /* Use the inverse map. */ + i = map->to->first[HASH(wc)]; + for (;;) { + if (map->from[i] == wc) { + *s = i; + return 1; + } + if (!(i = map->to->next[i])) + break; + } + } + else { + /* We don't have an inverse map, so do a linear search. */ + for (i = 0; i < 256; i++) + if (map->from[i] == wc) { + *s = i; + return 1; + } + } + + return -1; +} + +/* + * The "constructor" charset_find(). + */ + +struct charset charset_utf8 = { + 6, + &mbtowc_utf8, + &wctomb_utf8, + 0 +}; + +struct charset charset_iso1 = { + 1, + &mbtowc_iso1, + &wctomb_iso1, + 0 +}; + +struct charset charset_ascii = { + 1, + &mbtowc_ascii, + &wctomb_ascii, + 0 +}; + +struct charset *charset_find(const char *code) +{ + int i; + + /* Find good (MIME) name. */ + for (i = 0; names[i].bad; i++) + if (!ascii_strcasecmp(code, names[i].bad)) { + code = names[i].good; + break; + } + + /* Recognise some charsets for which we avoid using a table. */ + if (!ascii_strcasecmp(code, "UTF-8")) + return &charset_utf8; + if (!ascii_strcasecmp(code, "US-ASCII")) + return &charset_ascii; + if (!ascii_strcasecmp(code, "ISO-8859-1")) + return &charset_iso1; + + /* Look for a mapping for a simple 8-bit encoding. */ + for (i = 0; maps[i].name; i++) + if (!ascii_strcasecmp(code, maps[i].name)) { + if (!maps[i].charset) { + maps[i].charset = malloc(sizeof(struct charset)); + if (maps[i].charset) { + struct map *map = malloc(sizeof(struct map)); + if (!map) { + free(maps[i].charset); + maps[i].charset = 0; + } + else { + maps[i].charset->max = 1; + maps[i].charset->mbtowc = &mbtowc_8bit; + maps[i].charset->wctomb = &wctomb_8bit; + maps[i].charset->map = map; + map->from = maps[i].map; + map->to = 0; /* inverse mapping is created when required */ + } + } + } + return maps[i].charset; + } + + return 0; +} + +/* + * Function to convert a buffer from one encoding to another. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * Each of TO and TOLEN may be zero, if the result is not needed. + * The output buffer is null-terminated, so it is all right to + * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0). + */ + +int charset_convert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) +{ + int ret = 0; + struct charset *charset1, *charset2; + char *tobuf, *p; + int i, j, wc; + + charset1 = charset_find(fromcode); + charset2 = charset_find(tocode); + if (!charset1 || !charset2 ) + return -1; + + tobuf = safe_malloc_mul2add_(fromlen, /*times*/charset2->max, /*+*/1); + if (!tobuf) + return -2; + + for (p = tobuf; fromlen; from += i, fromlen -= i, p += j) { + i = charset_mbtowc(charset1, &wc, from, fromlen); + if (!i) + i = 1; + else if (i == -1) { + i = 1; + wc = '#'; + ret = 2; + } + j = charset_wctomb(charset2, p, wc); + if (j == -1) { + if (!ret) + ret = 1; + j = charset_wctomb(charset2, p, '?'); + if (j == -1) + j = 0; + } + } + + if (tolen) + *tolen = p - tobuf; + *p++ = '\0'; + if (to) { + char *tobuf_saved = tobuf; + *to = realloc(tobuf, p - tobuf); + if (*to == NULL) + *to = tobuf_saved; + } + else + free(tobuf); + + return ret; +} + +#endif /* USE_CHARSET_ICONV */ diff --git a/vendor/flac/src/share/utf8/charset.h b/vendor/flac/src/share/utf8/charset.h new file mode 100644 index 0000000..ea8e31e --- /dev/null +++ b/vendor/flac/src/share/utf8/charset.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* + * These functions are like the C library's mbtowc() and wctomb(), + * but instead of depending on the locale they always work in UTF-8, + * and they use int instead of wchar_t. + */ + +int utf8_mbtowc(int *pwc, const char *s, size_t n); +int utf8_wctomb(char *s, int wc); + +/* + * This is an object-oriented version of mbtowc() and wctomb(). + * The caller first uses charset_find() to get a pointer to struct + * charset, then uses the mbtowc() and wctomb() methods on it. + * The function charset_max() gives the maximum length of a + * multibyte character in that encoding. + * This API is only appropriate for stateless encodings like UTF-8 + * or ISO-8859-3, but I have no intention of implementing anything + * other than UTF-8 and 8-bit encodings. + * + * MINOR BUG: If there is no memory charset_find() may return 0 and + * there is no way to distinguish this case from an unknown encoding. + */ + +struct charset; + +struct charset *charset_find(const char *code); + +int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n); +int charset_wctomb(struct charset *charset, char *s, int wc); +int charset_max(struct charset *charset); + +/* + * Function to convert a buffer from one encoding to another. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * Each of TO and TOLEN may be zero if the result is not wanted. + * The input or output may contain null bytes, but the output + * buffer is also null-terminated, so it is all right to + * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0). + * + * Return value: + * + * -2 : memory allocation failed + * -1 : unknown encoding + * 0 : data was converted exactly + * 1 : valid data was converted approximately (using '?') + * 2 : input was invalid (but still converted, using '#') + */ + +int charset_convert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen); diff --git a/vendor/flac/src/share/utf8/charset_test.c b/vendor/flac/src/share/utf8/charset_test.c new file mode 100644 index 0000000..6761100 --- /dev/null +++ b/vendor/flac/src/share/utf8/charset_test.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "charset.h" + +void test_any(struct charset *charset) +{ + int wc; + char s[2]; + + assert(charset); + + /* Decoder */ + + assert(charset_mbtowc(charset, 0, 0, 0) == 0); + assert(charset_mbtowc(charset, 0, 0, 1) == 0); + assert(charset_mbtowc(charset, 0, (char *)(-1), 0) == 0); + + assert(charset_mbtowc(charset, 0, "a", 0) == 0); + assert(charset_mbtowc(charset, 0, "", 1) == 0); + assert(charset_mbtowc(charset, 0, "b", 1) == 1); + assert(charset_mbtowc(charset, 0, "", 2) == 0); + assert(charset_mbtowc(charset, 0, "c", 2) == 1); + + wc = 'x'; + assert(charset_mbtowc(charset, &wc, "a", 0) == 0 && wc == 'x'); + assert(charset_mbtowc(charset, &wc, "", 1) == 0 && wc == 0); + assert(charset_mbtowc(charset, &wc, "b", 1) == 1 && wc == 'b'); + assert(charset_mbtowc(charset, &wc, "", 2) == 0 && wc == 0); + assert(charset_mbtowc(charset, &wc, "c", 2) == 1 && wc == 'c'); + + /* Encoder */ + + assert(charset_wctomb(charset, 0, 0) == 0); + + s[0] = s[1] = '.'; + assert(charset_wctomb(charset, s, 0) == 1 && + s[0] == '\0' && s[1] == '.'); + assert(charset_wctomb(charset, s, 'x') == 1 && + s[0] == 'x' && s[1] == '.'); +} + +void test_utf8() +{ + struct charset *charset; + int wc; + char s[8]; + + charset = charset_find("UTF-8"); + test_any(charset); + + /* Decoder */ + wc = 0; + assert(charset_mbtowc(charset, &wc, "\177", 1) == 1 && wc == 127); + assert(charset_mbtowc(charset, &wc, "\200", 2) == -1); + assert(charset_mbtowc(charset, &wc, "\301\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\302\200", 1) == -1); + assert(charset_mbtowc(charset, &wc, "\302\200", 2) == 2 && wc == 128); + assert(charset_mbtowc(charset, &wc, "\302\200", 3) == 2 && wc == 128); + assert(charset_mbtowc(charset, &wc, "\340\237\200", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\340\240\200", 9) == 3 && + wc == 1 << 11); + assert(charset_mbtowc(charset, &wc, "\360\217\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\360\220\200\200", 9) == 4 && + wc == 1 << 16); + assert(charset_mbtowc(charset, &wc, "\370\207\277\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\370\210\200\200\200", 9) == 5 && + wc == 1 << 21); + assert(charset_mbtowc(charset, &wc, "\374\203\277\277\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\374\204\200\200\200\200", 9) == 6 && + wc == 1 << 26); + assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\277", 9) == 6 && + wc == 0x7fffffff); + + assert(charset_mbtowc(charset, &wc, "\302\000", 2) == -1); + assert(charset_mbtowc(charset, &wc, "\302\300", 2) == -1); + assert(charset_mbtowc(charset, &wc, "\340\040\200", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\340\340\200", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\340\240\000", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\340\240\300", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\360\020\200\200", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\360\320\200\200", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\360\220\000\200", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\360\220\300\200", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\360\220\200\000", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\360\220\200\300", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\077\277\277\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\377\277\277\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\277\077\277\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\277\377\277\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\277\277\277\077\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\277\277\277\377\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\077", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\377", 9) == -1); + + assert(charset_mbtowc(charset, &wc, "\376\277\277\277\277\277", 9) == -1); + assert(charset_mbtowc(charset, &wc, "\377\277\277\277\277\277", 9) == -1); + + /* Encoder */ + safe_strncpy(s, ".......", sizeof(s)); + assert(charset_wctomb(charset, s, 1u << 31) == -1 && + !strcmp(s, ".......")); + assert(charset_wctomb(charset, s, 127) == 1 && + !strcmp(s, "\177......")); + assert(charset_wctomb(charset, s, 128) == 2 && + !strcmp(s, "\302\200.....")); + assert(charset_wctomb(charset, s, 0x7ff) == 2 && + !strcmp(s, "\337\277.....")); + assert(charset_wctomb(charset, s, 0x800) == 3 && + !strcmp(s, "\340\240\200....")); + assert(charset_wctomb(charset, s, 0xffff) == 3 && + !strcmp(s, "\357\277\277....")); + assert(charset_wctomb(charset, s, 0x10000) == 4 && + !strcmp(s, "\360\220\200\200...")); + assert(charset_wctomb(charset, s, 0x1fffff) == 4 && + !strcmp(s, "\367\277\277\277...")); + assert(charset_wctomb(charset, s, 0x200000) == 5 && + !strcmp(s, "\370\210\200\200\200..")); + assert(charset_wctomb(charset, s, 0x3ffffff) == 5 && + !strcmp(s, "\373\277\277\277\277..")); + assert(charset_wctomb(charset, s, 0x4000000) == 6 && + !strcmp(s, "\374\204\200\200\200\200.")); + assert(charset_wctomb(charset, s, 0x7fffffff) == 6 && + !strcmp(s, "\375\277\277\277\277\277.")); +} + +void test_ascii() +{ + struct charset *charset; + int wc; + char s[3]; + + charset = charset_find("us-ascii"); + test_any(charset); + + /* Decoder */ + wc = 0; + assert(charset_mbtowc(charset, &wc, "\177", 2) == 1 && wc == 127); + assert(charset_mbtowc(charset, &wc, "\200", 2) == -1); + + /* Encoder */ + safe_strncpy(s, "..", sizeof(s)); + assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, "..")); + assert(charset_wctomb(charset, s, 255) == -1); + assert(charset_wctomb(charset, s, 128) == -1); + assert(charset_wctomb(charset, s, 127) == 1 && !strcmp(s, "\177.")); +} + +void test_iso1() +{ + struct charset *charset; + int wc; + char s[3]; + + charset = charset_find("iso-8859-1"); + test_any(charset); + + /* Decoder */ + wc = 0; + assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2); + + /* Encoder */ + safe_strncpy(s, "..", sizeof(s)); + assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, "..")); + assert(charset_wctomb(charset, s, 255) == 1 && !strcmp(s, "\377.")); + assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200.")); +} + +void test_iso2() +{ + struct charset *charset; + int wc; + char s[3]; + + charset = charset_find("iso-8859-2"); + test_any(charset); + + /* Decoder */ + wc = 0; + assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2); + assert(charset_mbtowc(charset, &wc, "\377", 2) == 1 && wc == 0x2d9); + + /* Encoder */ + safe_strncpy(s, "..", sizeof(s)); + assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, "..")); + assert(charset_wctomb(charset, s, 255) == -1 && !strcmp(s, "..")); + assert(charset_wctomb(charset, s, 258) == 1 && !strcmp(s, "\303.")); + assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200.")); +} + +void test_convert() +{ + const char *p; + char *q, *r; + char s[256]; + size_t n, n2; + int i; + + p = "\000x\302\200\375\277\277\277\277\277"; + assert(charset_convert("UTF-8", "UTF-8", p, 10, &q, &n) == 0 && + n == 10 && !strcmp(p, q)); + assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, &n) == 2 && + n == 4 && !strcmp(q, "x##y")); + assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, 0, &n) == 2 && + n == 4); + assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, 0) == 2 && + !strcmp(q, "x##y")); + assert(charset_convert("UTF-8", "iso-8859-1", + "\302\200\304\200x", 5, &q, &n) == 1 && + n == 3 && !strcmp(q, "\200?x")); + assert(charset_convert("iso-8859-1", "UTF-8", + "\000\200\377", 3, &q, &n) == 0 && + n == 5 && !memcmp(q, "\000\302\200\303\277", 5)); + assert(charset_convert("iso-8859-1", "iso-8859-1", + "\000\200\377", 3, &q, &n) == 0 && + n == 3 && !memcmp(q, "\000\200\377", 3)); + + assert(charset_convert("iso-8859-2", "utf-8", "\300", 1, &q, &n) == 0 && + n == 2 && !strcmp(q, "\305\224")); + assert(charset_convert("utf-8", "iso-8859-2", "\305\224", 2, &q, &n) == 0 && + n == 1 && !strcmp(q, "\300")); + + for (i = 0; i < 256; i++) + s[i] = i; + + assert(charset_convert("iso-8859-2", "utf-8", s, 256, &q, &n) == 0); + assert(charset_convert("utf-8", "iso-8859-2", q, n, &r, &n2) == 0); + assert(n2 == 256 && !memcmp(r, s, n2)); +} + +int main() +{ + test_utf8(); + test_ascii(); + test_iso1(); + test_iso2(); + + test_convert(); + + return 0; +} diff --git a/vendor/flac/src/share/utf8/iconvert.c b/vendor/flac/src/share/utf8/iconvert.c new file mode 100644 index 0000000..9a1e3f6 --- /dev/null +++ b/vendor/flac/src/share/utf8/iconvert.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined _WIN32 && defined HAVE_ICONV + +#include +#include +#include +#include +#include +#include + +#include "iconvert.h" +#include "share/alloc.h" +#include "share/safe_str.h" + +/* + * Convert data from one encoding to another. Return: + * + * -2 : memory allocation failed + * -1 : unknown encoding + * 0 : data was converted exactly + * 1 : data was converted inexactly + * 2 : data was invalid (but still converted) + * + * We convert in two steps, via UTF-8, as this is the only + * reliable way of distinguishing between invalid input + * and valid input which iconv refuses to transliterate. + * We convert from UTF-8 twice, because we have no way of + * knowing whether the conversion was exact if iconv returns + * E2BIG (due to a bug in the specification of iconv). + * An alternative approach is to assume that the output of + * iconv is never more than 4 times as long as the input, + * but I prefer to avoid that assumption if possible. + */ + +int iconvert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) +{ + int ret = 0; + iconv_t cd1, cd2; + char *ib; + char *ob; + char *utfbuf = 0, *outbuf, *newbuf; + size_t utflen, outlen, ibl, obl, obp, k; + char tbuf[2048]; + + cd1 = iconv_open("UTF-8", fromcode); + if (cd1 == (iconv_t)(-1)) + return -1; + + cd2 = (iconv_t)(-1); + /* Don't use strcasecmp() as it's locale-dependent. */ + if (!strchr("Uu", tocode[0]) || + !strchr("Tt", tocode[1]) || + !strchr("Ff", tocode[2]) || + tocode[3] != '-' || + tocode[4] != '8' || + tocode[5] != '\0') { + char *tocode1; + int rc; + /* + * Try using this non-standard feature of glibc and libiconv. + * This is deliberately not a config option as people often + * change their iconv library without rebuilding applications. + */ + + rc = asprintf(&tocode1, "%s//TRANSLIT", tocode); + if (rc < 0 || ! tocode1) + goto fail; + + cd2 = iconv_open(tocode1, "UTF-8"); + free(tocode1); + + if (cd2 == (iconv_t)(-1)) + cd2 = iconv_open(tocode, fromcode); + + if (cd2 == (iconv_t)(-1)) { + iconv_close(cd1); + return -1; + } + } + + utflen = 1; /*fromlen * 2 + 1; XXX */ + utfbuf = malloc(utflen); + if (!utfbuf) + goto fail; + + /* Convert to UTF-8 */ + ib = (char *)from; + ibl = fromlen; + ob = utfbuf; + obl = utflen; + for (;;) { + k = iconv(cd1, &ib, &ibl, &ob, &obl); + assert((!k && !ibl) || + (k == (size_t)(-1) && errno == E2BIG && ibl && obl < 6) || + (k == (size_t)(-1) && + (errno == EILSEQ || errno == EINVAL) && ibl)); + if (!ibl) + break; + if (obl < 6) { + /* Enlarge the buffer */ + if(utflen*2 < utflen) /* overflow check */ + goto fail; + utflen *= 2; + obp = ob - utfbuf; /* save position */ + newbuf = realloc(utfbuf, utflen); + if (!newbuf) + goto fail; + ob = newbuf + obp; + obl = utflen - obp; + utfbuf = newbuf; + } + else { + /* Invalid input */ + ib++, ibl--; + *ob++ = '#', obl--; + ret = 2; + iconv(cd1, 0, 0, 0, 0); + } + } + + if (cd2 == (iconv_t)(-1)) { + /* The target encoding was UTF-8 */ + if (tolen) + *tolen = ob - utfbuf; + if (!to) { + free(utfbuf); + iconv_close(cd1); + return ret; + } + newbuf = safe_realloc_nofree_add_2op_(utfbuf, (ob - utfbuf), /*+*/1); + if (!newbuf) + goto fail; + ob = (ob - utfbuf) + newbuf; + *ob = '\0'; + *to = newbuf; + iconv_close(cd1); + return ret; + } + + /* Truncate the buffer to be tidy */ + utflen = ob - utfbuf; + if (utflen == 0) + goto fail; + newbuf = realloc(utfbuf, utflen); + if (!newbuf) + goto fail; + utfbuf = newbuf; + + /* Convert from UTF-8 to discover how long the output is */ + outlen = 0; + ib = utfbuf; + ibl = utflen; + while (ibl) { + ob = tbuf; + obl = sizeof(tbuf); + k = iconv(cd2, &ib, &ibl, &ob, &obl); + assert((k != (size_t)(-1) && !ibl) || + (k == (size_t)(-1) && errno == E2BIG && ibl) || + (k == (size_t)(-1) && errno == EILSEQ && ibl)); + if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) { + /* Replace one character */ + char *tb = "?"; + size_t tbl = 1; + + outlen += ob - tbuf; + ob = tbuf; + obl = sizeof(tbuf); + k = iconv(cd2, &tb, &tbl, &ob, &obl); + assert((!k && !tbl) || + (k == (size_t)(-1) && errno == EILSEQ && tbl)); + for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--) + ; + } + outlen += ob - tbuf; + } + ob = tbuf; + obl = sizeof(tbuf); + k = iconv(cd2, 0, 0, &ob, &obl); + assert(!k); + outlen += ob - tbuf; + + /* Convert from UTF-8 for real */ + outbuf = safe_malloc_add_2op_(outlen, /*+*/1); + if (!outbuf) + goto fail; + ib = utfbuf; + ibl = utflen; + ob = outbuf; + obl = outlen; + while (ibl) { + k = iconv(cd2, &ib, &ibl, &ob, &obl); + assert((k != (size_t)(-1) && !ibl) || + (k == (size_t)(-1) && errno == EILSEQ && ibl)); + if (k && !ret) + ret = 1; + if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) { + /* Replace one character */ + char *tb = "?"; + size_t tbl = 1; + + k = iconv(cd2, &tb, &tbl, &ob, &obl); + assert((!k && !tbl) || + (k == (size_t)(-1) && errno == EILSEQ && tbl)); + for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--) + ; + } + } + k = iconv(cd2, 0, 0, &ob, &obl); + assert(!k); + assert(!obl); + *ob = '\0'; + + free(utfbuf); + iconv_close(cd1); + iconv_close(cd2); + if (tolen) + *tolen = outlen; + if (!to) { + free(outbuf); + return ret; + } + *to = outbuf; + return ret; + + fail: + if(0 != utfbuf) + free(utfbuf); + iconv_close(cd1); + if (cd2 != (iconv_t)(-1)) + iconv_close(cd2); + return -2; +} + +#endif /* HAVE_ICONV */ diff --git a/vendor/flac/src/share/utf8/iconvert.h b/vendor/flac/src/share/utf8/iconvert.h new file mode 100644 index 0000000..a2d75a2 --- /dev/null +++ b/vendor/flac/src/share/utf8/iconvert.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_ICONV + +/* + * Convert data from one encoding to another. Return: + * + * -2 : memory allocation failed + * -1 : unknown encoding + * 0 : data was converted exactly + * 1 : data was converted inexactly + * 2 : data was invalid (but still converted) + * + * We convert in two steps, via UTF-8, as this is the only + * reliable way of distinguishing between invalid input + * and valid input which iconv refuses to transliterate. + * We convert from UTF-8 twice, because we have no way of + * knowing whether the conversion was exact if iconv returns + * E2BIG (due to a bug in the specification of iconv). + * An alternative approach is to assume that the output of + * iconv is never more than 4 times as long as the input, + * but I prefer to avoid that assumption if possible. + */ + +int iconvert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) ; + +#endif /* HAVE_ICONV */ diff --git a/vendor/flac/src/share/utf8/makemap.c b/vendor/flac/src/share/utf8/makemap.c new file mode 100644 index 0000000..790021c --- /dev/null +++ b/vendor/flac/src/share/utf8/makemap.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + iconv_t cd; + const char *ib; + char *ob; + size_t ibl, obl, k; + uint8_t c, buf[4]; + int i, wc; + + if (argc != 2) { + printf("Usage: %s ENCODING\n", argv[0]); + printf("Output a charset map for the 8-bit ENCODING.\n"); + return 1; + } + + cd = iconv_open("UCS-4", argv[1]); + if (cd == (iconv_t)(-1)) { + perror("iconv_open"); + return 1; + } + + for (i = 0; i < 256; i++) { + c = i; + ib = &c; + ibl = 1; + ob = buf; + obl = 4; + k = iconv(cd, &ib, &ibl, &ob, &obl); + if (!k && !ibl && !obl) { + wc = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; + if (wc >= 0xffff) { + printf("Dodgy value.\n"); + return 1; + } + } + else if (k == (size_t)(-1) && errno == EILSEQ) + wc = 0xffff; + else { + printf("Non-standard iconv.\n"); + return 1; + } + + if (i % 8 == 0) + printf(" "); + printf("0x%04x", wc); + if (i == 255) + printf("\n"); + else if (i % 8 == 7) + printf(",\n"); + else + printf(", "); + } + + return 0; +} diff --git a/vendor/flac/src/share/utf8/utf8.c b/vendor/flac/src/share/utf8/utf8.c new file mode 100644 index 0000000..34af187 --- /dev/null +++ b/vendor/flac/src/share/utf8/utf8.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2001 Peter Harris + * Copyright (C) 2001 Edmund Grimley Evans + * + * Buffer overflow checking added: Josh Coalson, 9/9/2007 + * + * Win32 part rewritten: lvqcl, 2/2/2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Convert a string between UTF-8 and the locale's charset. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "share/alloc.h" +#include "share/utf8.h" + +#ifdef _WIN32 + +#include + +int utf8_encode(const char *from, char **to) +{ + wchar_t *unicode = NULL; + char *utf8 = NULL; + int ret = -1; + + do { + int len; + + len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, NULL, 0); + if(len == 0) break; + unicode = (wchar_t*) safe_malloc_mul_2op_((size_t)len, sizeof(wchar_t)); + if(unicode == NULL) break; + len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, unicode, len); + if(len == 0) break; + + len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL); + if(len == 0) break; + utf8 = (char*) safe_malloc_mul_2op_((size_t)len, sizeof(char)); + if(utf8 == NULL) break; + len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len, NULL, NULL); + if(len == 0) break; + + ret = 0; + + } while(0); + + free(unicode); + + if(ret == 0) { + *to = utf8; + } else { + free(utf8); + *to = NULL; + } + + return ret; +} + +int utf8_decode(const char *from, char **to) +{ + wchar_t *unicode = NULL; + char *acp = NULL; + int ret = -1; + + do { + int len; + + len = MultiByteToWideChar(CP_UTF8, 0, from, -1, NULL, 0); + if(len == 0) break; + unicode = (wchar_t*) safe_malloc_mul_2op_((size_t)len, sizeof(wchar_t)); + if(unicode == NULL) break; + len = MultiByteToWideChar(CP_UTF8, 0, from, -1, unicode, len); + if(len == 0) break; + + len = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL); + if(len == 0) break; + acp = (char*) safe_malloc_mul_2op_((size_t)len, sizeof(char)); + if(acp == NULL) break; + len = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, acp, len, NULL, NULL); + if(len == 0) break; + + ret = 0; + + } while(0); + + free(unicode); + + if(ret == 0) { + *to = acp; + } else { + free(acp); + *to = NULL; + } + + return ret; +} + +#else /* End win32. Rest is for real operating systems */ + + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +#include + +#include "share/safe_str.h" +#include "iconvert.h" +#include "charset.h" + +static const char *current_charset(void) +{ + const char *c = 0; +#ifdef HAVE_LANGINFO_CODESET + c = nl_langinfo(CODESET); +#endif + + if (!c) + c = getenv("CHARSET"); + + return c? c : "US-ASCII"; +} + +static int convert_buffer(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) +{ + int ret = -1; + +#ifdef HAVE_ICONV + ret = iconvert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + +#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */ + ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + + return ret; +} + +static int convert_string(const char *fromcode, const char *tocode, + const char *from, char **to, char replace) +{ + int ret; + size_t fromlen; + char *s; + + fromlen = strlen(from); + ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0); + if (ret == -2) + return -1; + if (ret != -1) + return ret; + + s = safe_malloc_add_2op_(fromlen, /*+*/1); + if (!s) + return -1; + snprintf(s, fromlen + 1, "%s", from); + *to = s; + for (; *s; s++) + if (*s & ~0x7f) + *s = replace; + return 3; +} + +int utf8_encode(const char *from, char **to) +{ + return convert_string(current_charset(), "UTF-8", from, to, '#'); +} + +int utf8_decode(const char *from, char **to) +{ + return convert_string("UTF-8", current_charset(), from, to, '?'); +} + +#endif diff --git a/vendor/flac/src/share/win_utf8_io/win_utf8_io.c b/vendor/flac/src/share/win_utf8_io/win_utf8_io.c new file mode 100644 index 0000000..3ae35b3 --- /dev/null +++ b/vendor/flac/src/share/win_utf8_io/win_utf8_io.c @@ -0,0 +1,398 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2013-2023 Xiph.Org Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Xiph.org Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "share/win_utf8_io.h" + +#define UTF8_BUFFER_SIZE 32768 + +/* detect whether it is Windows APP (UWP) or standard Win32 envionment */ +#ifdef WINAPI_FAMILY_PARTITION + #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + #define FLAC_WINDOWS_APP 1 + #else + #define FLAC_WINDOWS_APP 0 + #endif +#else + #define FLAC_WINDOWS_APP 0 +#endif + +static int local_vsnprintf(char *str, size_t size, const char *fmt, va_list va) +{ + int rc; + +#if defined _MSC_VER + if (size == 0) + return 1024; + rc = vsnprintf_s(str, size, _TRUNCATE, fmt, va); + if (rc < 0) + rc = size - 1; +#elif defined __MINGW32__ + rc = __mingw_vsnprintf(str, size, fmt, va); +#else + rc = vsnprintf(str, size, fmt, va); +#endif + + return rc; +} + +/* convert WCHAR stored Unicode string to UTF-8. Caller is responsible for freeing memory */ +static char *utf8_from_wchar(const wchar_t *wstr) +{ + char *utf8str; + int len; + + if (!wstr) + return NULL; + if ((len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL)) == 0) + return NULL; + if ((utf8str = (char *)malloc(len)) == NULL) + return NULL; + if (WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8str, len, NULL, NULL) == 0) { + free(utf8str); + utf8str = NULL; + } + + return utf8str; +} + +/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */ +static wchar_t *wchar_from_utf8(const char *str) +{ + wchar_t *widestr; + int len; + + if (!str) + return NULL; + if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0) + return NULL; + if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) == NULL) + return NULL; + if (MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) { + free(widestr); + widestr = NULL; + } + + return widestr; +} + +/* retrieve WCHAR commandline, expand wildcards and convert everything to UTF-8 */ +int get_utf8_argv(int *argc, char ***argv) +{ +#if !FLAC_WINDOWS_APP + typedef int (__cdecl *wgetmainargs_t)(int*, wchar_t***, wchar_t***, int, int*); + wgetmainargs_t wgetmainargs; + HMODULE handle; +#endif // !FLAC_WINDOWS_APP + int wargc; + wchar_t **wargv; + wchar_t **wenv; + char **utf8argv; + int ret, i; + +#if FLAC_WINDOWS_APP + wargc = __argc; + wargv = __wargv; + wenv = _wenviron; +#else // !FLAC_WINDOWS_APP + if ((handle = LoadLibraryW(L"msvcrt.dll")) == NULL) return 1; + if ((wgetmainargs = (wgetmainargs_t)GetProcAddress(handle, "__wgetmainargs")) == NULL) { + FreeLibrary(handle); + return 1; + } + i = 0; + /* when the 4th argument is 1, __wgetmainargs expands wildcards but also erroneously converts \\?\c:\path\to\file.flac to \\file.flac */ + if (wgetmainargs(&wargc, &wargv, &wenv, 1, &i) != 0) { + FreeLibrary(handle); + return 1; + } +#endif // !FLAC_WINDOWS_APP + if ((utf8argv = (char **)calloc(wargc, sizeof(char*))) == NULL) { + #if !FLAC_WINDOWS_APP + FreeLibrary(handle); + #endif // !FLAC_WINDOWS_APP + return 1; + } + + ret = 0; + for (i=0; iactime; + ut.modtime = times->modtime; + ret = _wutime64(wname, &ut); + free(wname); + + return ret; +} + +int unlink_utf8(const char *filename) +{ + wchar_t *wname; + int ret; + + if (!(wname = wchar_from_utf8(filename))) return -1; + ret = _wunlink(wname); + free(wname); + + return ret; +} + +int rename_utf8(const char *oldname, const char *newname) +{ + wchar_t *wold = NULL; + wchar_t *wnew = NULL; + int ret = -1; + + do { + if (!(wold = wchar_from_utf8(oldname))) break; + if (!(wnew = wchar_from_utf8(newname))) break; + ret = _wrename(wold, wnew); + } while(0); + + free(wold); + free(wnew); + + return ret; +} diff --git a/vendor/flac/src/test_grabbag/CMakeLists.txt b/vendor/flac/src/test_grabbag/CMakeLists.txt new file mode 100644 index 0000000..56abe81 --- /dev/null +++ b/vendor/flac/src/test_grabbag/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(cuesheet) +add_subdirectory(picture) diff --git a/vendor/flac/src/test_grabbag/Makefile.am b/vendor/flac/src/test_grabbag/Makefile.am new file mode 100644 index 0000000..ea71009 --- /dev/null +++ b/vendor/flac/src/test_grabbag/Makefile.am @@ -0,0 +1,22 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2002-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This file is part the FLAC project. FLAC is comprised of several +# components distributed under different licenses. The codec libraries +# are distributed under Xiph.Org's BSD-like license (see the file +# COPYING.Xiph in this distribution). All other programs, libraries, and +# plugins are distributed under the GPL (see COPYING.GPL). The documentation +# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the +# FLAC distribution contains at the top the terms under which it may be +# distributed. +# +# Since this particular file is relevant to all components of FLAC, +# it may be distributed under the Xiph.Org license, which is the least +# restrictive of those mentioned above. See the file COPYING.Xiph in this +# distribution. + +SUBDIRS = cuesheet picture + +EXTRA_DIST = \ + CMakeLists.txt diff --git a/vendor/flac/src/test_grabbag/cuesheet/CMakeLists.txt b/vendor/flac/src/test_grabbag/cuesheet/CMakeLists.txt new file mode 100644 index 0000000..5f9a646 --- /dev/null +++ b/vendor/flac/src/test_grabbag/cuesheet/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_cuesheet + main.c + $<$:../../../include/share/win_utf8_io.h> + $<$:../../share/win_utf8_io/win_utf8_io.c>) +target_link_libraries(test_cuesheet FLAC grabbag) diff --git a/vendor/flac/src/test_grabbag/cuesheet/Makefile.am b/vendor/flac/src/test_grabbag/cuesheet/Makefile.am new file mode 100644 index 0000000..1cee370 --- /dev/null +++ b/vendor/flac/src/test_grabbag/cuesheet/Makefile.am @@ -0,0 +1,37 @@ +# test_cuesheet - Simple tester for cuesheet routines in grabbag +# Copyright (C) 2002-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +check_PROGRAMS = test_cuesheet +test_cuesheet_SOURCES = \ + main.c + +if OS_IS_WINDOWS +win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la +endif + +test_cuesheet_LDADD = \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + $(win_utf8_lib) + +CLEANFILES = test_cuesheet.exe diff --git a/vendor/flac/src/test_grabbag/cuesheet/main.c b/vendor/flac/src/test_grabbag/cuesheet/main.c new file mode 100644 index 0000000..b3d0e9a --- /dev/null +++ b/vendor/flac/src/test_grabbag/cuesheet/main.c @@ -0,0 +1,147 @@ +/* test_cuesheet - Simple tester for cuesheet routines in grabbag + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "share/grabbag.h" + +static int do_cuesheet(const char *infilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset) +{ + FILE *fin, *fout; + const char *error_message, *tmpfilenamebase; + char tmpfilename[4096]; + uint32_t last_line_read; + FLAC__StreamMetadata *cuesheet; + + FLAC__ASSERT(strlen(infilename) + 2 < sizeof(tmpfilename)); + + /* + * pass 1 + */ + if(0 == strcmp(infilename, "-")) { + fin = stdin; + } + else if(0 == (fin = flac_fopen(infilename, "r"))) { + fprintf(stderr, "can't open file %s for reading: %s\n", infilename, strerror(errno)); + return 255; + } + if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset))) { + if(fin != stdin) + fclose(fin); + } + else { + printf("pass1: parse error, line %u: \"%s\"\n", last_line_read, error_message); + if(fin != stdin) + fclose(fin); + return 1; + } + if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) { + printf("pass1: illegal cuesheet: \"%s\"\n", error_message); + FLAC__metadata_object_delete(cuesheet); + return 1; + } + + tmpfilenamebase = strstr(infilename, "cuesheets/"); + tmpfilenamebase = tmpfilenamebase == NULL ? infilename : tmpfilenamebase; + + flac_snprintf(tmpfilename, sizeof (tmpfilename), "%s.1", tmpfilenamebase); + if(0 == (fout = flac_fopen(tmpfilename, "w"))) { + fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno)); + FLAC__metadata_object_delete(cuesheet); + return 255; + } + grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE"); + FLAC__metadata_object_delete(cuesheet); + fclose(fout); + + /* + * pass 2 + */ + if(0 == (fin = flac_fopen(tmpfilename, "r"))) { + fprintf(stderr, "can't open file %s for reading: %s\n", tmpfilename, strerror(errno)); + return 255; + } + if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset))) { + if(fin != stdin) + fclose(fin); + } + else { + printf("pass2: parse error, line %u: \"%s\"\n", last_line_read, error_message); + if(fin != stdin) + fclose(fin); + return 1; + } + if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) { + printf("pass2: illegal cuesheet: \"%s\"\n", error_message); + FLAC__metadata_object_delete(cuesheet); + return 1; + } + flac_snprintf(tmpfilename, sizeof (tmpfilename), "%s.2", tmpfilenamebase); + if(0 == (fout = flac_fopen(tmpfilename, "w"))) { + fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno)); + FLAC__metadata_object_delete(cuesheet); + return 255; + } + grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE"); + FLAC__metadata_object_delete(cuesheet); + fclose(fout); + + return 0; +} + +int main(int argc, char *argv[]) +{ + FLAC__uint64 lead_out_offset; + uint32_t sample_rate = 48000; + FLAC__bool is_cdda = false; + const char *usage = "usage: test_cuesheet cuesheet_file lead_out_offset [ [ sample_rate ] cdda ]\n"; + + if(argc > 1 && 0 == strcmp(argv[1], "-h")) { + puts(usage); + return 0; + } + + if(argc < 3 || argc > 5) { + fputs(usage, stderr); + return 255; + } + + lead_out_offset = (FLAC__uint64)strtoul(argv[2], 0, 10); + if(argc >= 4) { + sample_rate = (uint32_t)atoi(argv[3]); + if(argc >= 5) { + if(0 == strcmp(argv[4], "cdda")) + is_cdda = true; + else { + fputs(usage, stderr); + return 255; + } + } + } + + return do_cuesheet(argv[1], sample_rate, is_cdda, lead_out_offset); +} diff --git a/vendor/flac/src/test_grabbag/picture/CMakeLists.txt b/vendor/flac/src/test_grabbag/picture/CMakeLists.txt new file mode 100644 index 0000000..77f1a38 --- /dev/null +++ b/vendor/flac/src/test_grabbag/picture/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_picture + main.c + $<$:../../../include/share/win_utf8_io.h> + $<$:../../share/win_utf8_io/win_utf8_io.c>) +target_link_libraries(test_picture FLAC grabbag) diff --git a/vendor/flac/src/test_grabbag/picture/Makefile.am b/vendor/flac/src/test_grabbag/picture/Makefile.am new file mode 100644 index 0000000..45e1457 --- /dev/null +++ b/vendor/flac/src/test_grabbag/picture/Makefile.am @@ -0,0 +1,37 @@ +# test_picture - Simple tester for picture routines in grabbag +# Copyright (C) 2006-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +check_PROGRAMS = test_picture +test_picture_SOURCES = \ + main.c + +if OS_IS_WINDOWS +win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la +endif + +test_picture_LDADD = \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + $(win_utf8_lib) + +CLEANFILES = test_picture.exe diff --git a/vendor/flac/src/test_grabbag/picture/main.c b/vendor/flac/src/test_grabbag/picture/main.c new file mode 100644 index 0000000..fe43be9 --- /dev/null +++ b/vendor/flac/src/test_grabbag/picture/main.c @@ -0,0 +1,222 @@ +/* test_picture - Simple tester for picture routines in grabbag + * Copyright (C) 2006-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "FLAC/assert.h" +#include "share/grabbag.h" + +typedef struct { + const char *path; + const char *mime_type; + const char *description; + FLAC__uint32 width; + FLAC__uint32 height; + FLAC__uint32 depth; + FLAC__uint32 colors; + FLAC__StreamMetadata_Picture_Type type; +} PictureFile; + +PictureFile picturefiles[] = { + { "0.gif", "image/gif" , "", 24, 24, 24, 2, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "1.gif", "image/gif" , "", 12, 8, 24, 256, FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER }, + { "2.gif", "image/gif" , "", 16, 14, 24, 128, FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER }, + { "0.jpg", "image/jpeg", "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "4.jpg", "image/jpeg", "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "0.png", "image/png" , "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "1.png", "image/png" , "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "2.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "3.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "4.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "5.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "6.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "7.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER }, + { "8.png", "image/png" , "", 32, 32, 32, 0, 999 } +}; + +static FLAC__bool debug_ = false; + +static FLAC__bool failed_(const char *msg) +{ + if(msg) + printf("FAILED, %s\n", msg); + else + printf("FAILED\n"); + + return false; +} + +static FLAC__bool test_one_picture(const char *prefix, const PictureFile *pf, const PictureResolution * res, FLAC__bool fn_only) +{ + FLAC__StreamMetadata *obj; + const char *error; + char s[4096]; + if(fn_only) + flac_snprintf(s, sizeof(s), "pictures/%s", pf->path); + else if (res == NULL) + flac_snprintf(s, sizeof(s), "%u|%s|%s||pictures/%s", (uint32_t)pf->type, pf->mime_type, pf->description, pf->path); + else + flac_snprintf(s, sizeof(s), "%u|%s|%s|%dx%dx%d/%d|pictures/%s", (uint32_t)pf->type, pf->mime_type, pf->description, res->width, res->height, res->depth, res->colors, pf->path); + + printf("testing grabbag__picture_parse_specification(\"%s\")... ", s); + + flac_snprintf(s, sizeof(s), "%s/%s", prefix, pf->path); + if((obj = grabbag__picture_from_specification(fn_only? FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER : pf->type, pf->mime_type, pf->description, res, s, &error)) == 0) + return failed_(error); + if(debug_) { + printf("\ntype=%u (%s)\nmime_type=%s\ndescription=%s\nwidth=%u\nheight=%u\ndepth=%u\ncolors=%u\ndata_length=%u\n", + obj->data.picture.type, + obj->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED? + FLAC__StreamMetadata_Picture_TypeString[obj->data.picture.type] : "UNDEFINED", + obj->data.picture.mime_type, + obj->data.picture.description, + obj->data.picture.width, + obj->data.picture.height, + obj->data.picture.depth, + obj->data.picture.colors, + obj->data.picture.data_length + ); + } + if(obj->data.picture.type != (fn_only? FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER : pf->type)) + return failed_("picture type mismatch"); + if(strcmp(obj->data.picture.mime_type, pf->mime_type)) + return failed_("picture MIME type mismatch"); + if(strcmp((const char *)obj->data.picture.description, (const char *)pf->description)) + return failed_("picture description mismatch"); + if(obj->data.picture.width != pf->width) + return failed_("picture width mismatch"); + if(obj->data.picture.height != pf->height) + return failed_("picture height mismatch"); + if(obj->data.picture.depth != pf->depth) + return failed_("picture depth mismatch"); + if(obj->data.picture.colors != pf->colors) + return failed_("picture colors mismatch"); + printf("OK\n"); + FLAC__metadata_object_delete(obj); + return true; +} + +static FLAC__bool do_picture(const char *prefix) +{ + FLAC__StreamMetadata *obj; + PictureResolution res; + const char *error; + size_t i; + + printf("\n+++ grabbag unit test: picture\n\n"); + + /* invalid spec: no filename */ + printf("testing grabbag__picture_parse_specification(\"\")... "); + if(0 != (obj = grabbag__picture_parse_specification("", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected, error: %s)\n", error); + + /* invalid spec: no filename */ + printf("testing grabbag__picture_parse_specification(\"||||\")... "); + if(0 != (obj = grabbag__picture_parse_specification("||||", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + /* invalid spec: no filename */ + printf("testing grabbag__picture_parse_specification(\"|image/gif|||\")... "); + if(0 != (obj = grabbag__picture_parse_specification("|image/gif|||", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + /* invalid spec: bad resolution */ + printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320|0.gif\")... "); + if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320|0.gif", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + /* invalid spec: bad resolution */ + printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240|0.gif\")... "); + if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240|0.gif", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + /* invalid spec: no filename */ + printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9|\")... "); + if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9|", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + /* invalid spec: #colors exceeds color depth */ + printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9/2345|0.gif\")... "); + if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9/2345|0.gif", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + /* invalid spec: standard icon has to be 32x32 PNG */ + printf("testing grabbag__picture_parse_specification(\"1|-->|desc|32x24x9|0.gif\")... "); + if(0 != (obj = grabbag__picture_parse_specification("1|-->|desc|32x24x9|0.gif", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + /* invalid spec: need resolution for linked URL */ + printf("testing grabbag__picture_parse_specification(\"|-->|desc||http://blah.blah.blah/z.gif\")... "); + if(0 != (obj = grabbag__picture_parse_specification("|-->|desc||http://blah.blah.blah/z.gif", &error))) + return failed_("expected error, got object"); + printf("OK (failed as expected: %s)\n", error); + + printf("testing grabbag__picture_parse_specification(\"|-->|desc|320x240x9|http://blah.blah.blah/z.gif\")... "); + if(0 == (obj = grabbag__picture_parse_specification("|-->|desc|320x240x9|http://blah.blah.blah/z.gif", &error))) + return failed_(error); + printf("OK\n"); + FLAC__metadata_object_delete(obj); + + /* test automatic parsing of picture files from only the file name */ + for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++) + if(!test_one_picture(prefix, picturefiles+i, NULL, /*fn_only=*/true)) + return false; + + /* test automatic parsing of picture files to get resolution/color info */ + for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++) + if(!test_one_picture(prefix, picturefiles+i, NULL, /*fn_only=*/false)) + return false; + + res.width = picturefiles[0].width = 320; + res.height = picturefiles[0].height = 240; + res.depth = picturefiles[0].depth = 3; + res.colors = picturefiles[0].colors = 2; + if(!test_one_picture(prefix, picturefiles+0, &res, /*fn_only=*/false)) + return false; + + return true; +} + +int main(int argc, char *argv[]) +{ + const char *usage = "usage: test_pictures path_prefix\n"; + + if(argc > 1 && 0 == strcmp(argv[1], "-h")) { + puts(usage); + return 0; + } + + if(argc != 2) { + fputs(usage, stderr); + return 255; + } + + return do_picture(argv[1])? 0 : 1; +} diff --git a/vendor/flac/src/test_libFLAC++/CMakeLists.txt b/vendor/flac/src/test_libFLAC++/CMakeLists.txt new file mode 100644 index 0000000..2fa7b1e --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/CMakeLists.txt @@ -0,0 +1,10 @@ +add_executable(test_libFLAC++ + decoders.cpp + encoders.cpp + main.cpp + metadata.cpp + metadata_manip.cpp + metadata_object.cpp + $<$:../../include/share/win_utf8_io.h> + $<$:../share/win_utf8_io/win_utf8_io.c>) +target_link_libraries(test_libFLAC++ FLAC++ test_libs_common grabbag) diff --git a/vendor/flac/src/test_libFLAC++/Makefile.am b/vendor/flac/src/test_libFLAC++/Makefile.am new file mode 100644 index 0000000..8bf746f --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/Makefile.am @@ -0,0 +1,50 @@ +# test_libFLAC++ - Unit tester for libFLAC++ +# Copyright (C) 2002-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +check_PROGRAMS = test_libFLAC++ + +if OS_IS_WINDOWS +win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la +endif + +test_libFLAC___LDADD = \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/test_libs_common/libtest_libs_common.la \ + $(top_builddir)/src/libFLAC++/libFLAC++.la \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + $(win_utf8_lib) \ + @OGG_LIBS@ \ + -lm + +test_libFLAC___SOURCES = \ + decoders.cpp \ + encoders.cpp \ + main.cpp \ + metadata.cpp \ + metadata_manip.cpp \ + metadata_object.cpp \ + decoders.h \ + encoders.h \ + metadata.h + +CLEANFILES = test_libFLAC++.exe diff --git a/vendor/flac/src/test_libFLAC++/decoders.cpp b/vendor/flac/src/test_libFLAC++/decoders.cpp new file mode 100644 index 0000000..9f375f3 --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/decoders.cpp @@ -0,0 +1,1179 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "decoders.h" +#include "FLAC/assert.h" +#include "FLAC/metadata.h" // for ::FLAC__metadata_object_is_equal() +#include "FLAC++/decoder.h" +#include "share/grabbag.h" +#include "share/compat.h" +extern "C" { +#include "test_libs_common/file_utils_flac.h" +#include "test_libs_common/metadata_utils.h" +} + +#ifdef _MSC_VER +// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning) +#pragma warning ( disable : 4800 ) +#endif + +typedef enum { + LAYER_STREAM = 0, /* FLAC__stream_decoder_init_stream() without seeking */ + LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_stream() with seeking */ + LAYER_FILE, /* FLAC__stream_decoder_init_FILE() */ + LAYER_FILENAME /* FLAC__stream_decoder_init_file() */ +} Layer; + +static const char * const LayerString[] = { + "Stream", + "Seekable Stream", + "FILE*", + "Filename" +}; + +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static ::FLAC__StreamMetadata *expected_metadata_sequence_[9]; +static uint32_t num_expected_; +static FLAC__off_t flacfilesize_; + +static const char *flacfilename(bool is_ogg) +{ + return is_ogg? "metadata.oga" : "metadata.flac"; +} + +static bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static FLAC__bool die_s_(const char *msg, const FLAC::Decoder::Stream *decoder) +{ + FLAC::Decoder::Stream::State state = decoder->get_state(); + + if(msg) + printf("FAILED, %s", msg); + else + printf("FAILED"); + + printf(", state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring()); + + return false; +} + +static void init_metadata_blocks_() +{ + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static void free_metadata_blocks_() +{ + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static bool generate_file_(FLAC__bool is_ogg) +{ + printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":""); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + /* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */ + + if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_)) + return die_("creating the encoded file"); + + return true; +} + + +class DecoderCommon { +public: + Layer layer_; + uint32_t current_metadata_number_; + bool ignore_errors_; + bool error_occurred_; + + DecoderCommon(Layer layer): layer_(layer), current_metadata_number_(0), ignore_errors_(false), error_occurred_(false) { } + virtual ~DecoderCommon(void) { } + ::FLAC__StreamDecoderWriteStatus common_write_callback_(const ::FLAC__Frame *frame); + void common_metadata_callback_(const ::FLAC__StreamMetadata *metadata); + void common_error_callback_(::FLAC__StreamDecoderErrorStatus status); +}; + +::FLAC__StreamDecoderWriteStatus DecoderCommon::common_write_callback_(const ::FLAC__Frame *frame) +{ + if(error_occurred_) + return ::FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + if( + (frame->header.number_type == ::FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) || + (frame->header.number_type == ::FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0) + ) { + printf("content... "); + fflush(stdout); + } + + return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void DecoderCommon::common_metadata_callback_(const ::FLAC__StreamMetadata *metadata) +{ + if(error_occurred_) + return; + + printf("%u... ", current_metadata_number_); + fflush(stdout); + + if(current_metadata_number_ >= num_expected_) { + (void)die_("got more metadata blocks than expected"); + error_occurred_ = true; + } + else { + if(!::FLAC__metadata_object_is_equal(expected_metadata_sequence_[current_metadata_number_], metadata)) { + (void)die_("metadata block mismatch"); + error_occurred_ = true; + } + } + current_metadata_number_++; +} + +void DecoderCommon::common_error_callback_(::FLAC__StreamDecoderErrorStatus status) +{ + if(!ignore_errors_) { + printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, ::FLAC__StreamDecoderErrorStatusString[status]); + error_occurred_ = true; + } +} + +class StreamDecoder : public FLAC::Decoder::Stream, public DecoderCommon { +public: + FILE *file_; + + StreamDecoder(Layer layer): FLAC::Decoder::Stream(), DecoderCommon(layer), file_(0) { } + ~StreamDecoder() { } + + // from FLAC::Decoder::Stream + ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes); + ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); + ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length); + bool eof_callback(); + ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); + void metadata_callback(const ::FLAC__StreamMetadata *metadata); + void error_callback(::FLAC__StreamDecoderErrorStatus status); + + bool test_respond(bool is_ogg); +private: + StreamDecoder(const StreamDecoder&); + StreamDecoder&operator=(const StreamDecoder&); +}; + +::FLAC__StreamDecoderReadStatus StreamDecoder::read_callback(FLAC__byte buffer[], size_t *bytes) +{ + const size_t requested_bytes = *bytes; + + if(error_occurred_) + return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; + + if(feof(file_)) { + *bytes = 0; + return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + else if(requested_bytes > 0) { + *bytes = ::fread(buffer, 1, requested_bytes, file_); + if(*bytes == 0) { + if(feof(file_)) + return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else { + return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + } + else + return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ +} + +::FLAC__StreamDecoderSeekStatus StreamDecoder::seek_callback(FLAC__uint64 absolute_byte_offset) +{ + if(layer_ == LAYER_STREAM) + return ::FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; + + if(error_occurred_) + return ::FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + + if(fseeko(file_, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) { + error_occurred_ = true; + return ::FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + + return ::FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +::FLAC__StreamDecoderTellStatus StreamDecoder::tell_callback(FLAC__uint64 *absolute_byte_offset) +{ + if(layer_ == LAYER_STREAM) + return ::FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; + + if(error_occurred_) + return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + + FLAC__off_t offset = ftello(file_); + *absolute_byte_offset = (FLAC__uint64)offset; + + if(offset < 0) { + error_occurred_ = true; + return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + } + + return ::FLAC__STREAM_DECODER_TELL_STATUS_OK; +} + +::FLAC__StreamDecoderLengthStatus StreamDecoder::length_callback(FLAC__uint64 *stream_length) +{ + if(layer_ == LAYER_STREAM) + return ::FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; + + if(error_occurred_) + return ::FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + + *stream_length = (FLAC__uint64)flacfilesize_; + return ::FLAC__STREAM_DECODER_LENGTH_STATUS_OK; +} + +bool StreamDecoder::eof_callback() +{ + if(layer_ == LAYER_STREAM) + return false; + + if(error_occurred_) + return true; + + return (bool)feof(file_); +} + +::FLAC__StreamDecoderWriteStatus StreamDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + (void)buffer; + + return common_write_callback_(frame); +} + +void StreamDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata) +{ + common_metadata_callback_(metadata); +} + +void StreamDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status) +{ + common_error_callback_(status); +} + +bool StreamDecoder::test_respond(bool is_ogg) +{ + ::FLAC__StreamDecoderInitStatus init_status; + + if(!set_md5_checking(true)) { + printf("FAILED at set_md5_checking(), returned false\n"); + return false; + } + + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? init_ogg() : init(); + if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, this); + printf("OK\n"); + + current_metadata_number_ = 0; + + if(fseeko(file_, 0, SEEK_SET) < 0) { + printf("FAILED rewinding input, errno = %d\n", errno); + return false; + } + + printf("testing process_until_end_of_stream()... "); + if(!process_until_end_of_stream()) { + State state = get_state(); + printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring()); + return false; + } + printf("OK\n"); + + printf("testing finish()... "); + if(!finish()) { + State state = get_state(); + printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring()); + return false; + } + printf("OK\n"); + + return true; +} + +class FileDecoder : public FLAC::Decoder::File, public DecoderCommon { +public: + FileDecoder(Layer layer): FLAC::Decoder::File(), DecoderCommon(layer) { } + ~FileDecoder() { } + + // from FLAC::Decoder::Stream + ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); + void metadata_callback(const ::FLAC__StreamMetadata *metadata); + void error_callback(::FLAC__StreamDecoderErrorStatus status); + + bool test_respond(bool is_ogg); +}; + +::FLAC__StreamDecoderWriteStatus FileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + (void)buffer; + return common_write_callback_(frame); +} + +void FileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata) +{ + common_metadata_callback_(metadata); +} + +void FileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status) +{ + common_error_callback_(status); +} + +bool FileDecoder::test_respond(bool is_ogg) +{ + ::FLAC__StreamDecoderInitStatus init_status; + + if(!set_md5_checking(true)) { + printf("FAILED at set_md5_checking(), returned false\n"); + return false; + } + + switch(layer_) { + case LAYER_FILE: + { + printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); + FILE *file = ::flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? init_ogg(file) : init(file); + } + break; + case LAYER_FILENAME: + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? init_ogg(flacfilename(is_ogg)) : init(flacfilename(is_ogg)); + break; + default: + die_("internal error 001"); + return false; + } + if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, this); + printf("OK\n"); + + current_metadata_number_ = 0; + + printf("testing process_until_end_of_stream()... "); + if(!process_until_end_of_stream()) { + State state = get_state(); + printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring()); + return false; + } + printf("OK\n"); + + printf("testing finish()... "); + if(!finish()) { + State state = get_state(); + printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring()); + return false; + } + printf("OK\n"); + + return true; +} + + +static FLAC::Decoder::Stream *new_by_layer(Layer layer) +{ + if(layer < LAYER_FILE) + return new StreamDecoder(layer); + else + return new FileDecoder(layer); +} + +static bool test_stream_decoder(Layer layer, bool is_ogg) +{ + FLAC::Decoder::Stream *decoder; + ::FLAC__StreamDecoderInitStatus init_status; + bool expect; + + printf("\n+++ libFLAC++ unit test: FLAC::Decoder::%s (layer: %s, format: %s)\n\n", layer delete + // + printf("allocating decoder instance... "); + decoder = new_by_layer(layer); + if(0 == decoder) { + printf("FAILED, new returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing is_valid()... "); + if(!decoder->is_valid()) { + printf("FAILED, returned false\n"); + delete decoder; + return false; + } + printf("OK\n"); + + printf("freeing decoder instance... "); + delete decoder; + printf("OK\n"); + + // + // test new -> init -> delete + // + printf("allocating decoder instance... "); + decoder = new_by_layer(layer); + if(0 == decoder) { + printf("FAILED, new returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing is_valid()... "); + if(!decoder->is_valid()) { + printf("FAILED, returned false\n"); + delete decoder; + return false; + } + printf("OK\n"); + + printf("testing init%s()... ", is_ogg? "_ogg":""); + switch(layer) { + case LAYER_STREAM: + case LAYER_SEEKABLE_STREAM: + dynamic_cast(decoder)->file_ = stdin; + init_status = is_ogg? decoder->init_ogg() : decoder->init(); + break; + case LAYER_FILE: + init_status = is_ogg? + dynamic_cast(decoder)->init_ogg(stdin) : + dynamic_cast(decoder)->init(stdin); + break; + case LAYER_FILENAME: + init_status = is_ogg? + dynamic_cast(decoder)->init_ogg(flacfilename(is_ogg)) : + dynamic_cast(decoder)->init(flacfilename(is_ogg)); + break; + default: + die_("internal error 006"); + delete decoder; + return false; + } + if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, decoder); + printf("OK\n"); + + printf("freeing decoder instance... "); + delete decoder; + printf("OK\n"); + + // + // test normal usage + // + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + + printf("allocating decoder instance... "); + decoder = new_by_layer(layer); + if(0 == decoder) { + printf("FAILED, new returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing is_valid()... "); + if(!decoder->is_valid()) { + printf("FAILED, returned false\n"); + delete decoder; + return false; + } + printf("OK\n"); + + if(is_ogg) { + printf("testing set_ogg_serial_number()... "); + if(!decoder->set_ogg_serial_number(file_utils__ogg_serial_number)) + return die_s_("returned false", decoder); + printf("OK\n"); + } + + if(!decoder->set_md5_checking(true)) { + printf("FAILED at set_md5_checking(), returned false\n"); + return false; + } + + switch(layer) { + case LAYER_STREAM: + case LAYER_SEEKABLE_STREAM: + printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); + dynamic_cast(decoder)->file_ = ::flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == dynamic_cast(decoder)->file_) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? decoder->init_ogg() : decoder->init(); + break; + case LAYER_FILE: + { + printf("opening FLAC file... "); + FILE *file = ::flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? + dynamic_cast(decoder)->init_ogg(file) : + dynamic_cast(decoder)->init(file); + } + break; + case LAYER_FILENAME: + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? + dynamic_cast(decoder)->init_ogg(flacfilename(is_ogg)) : + dynamic_cast(decoder)->init(flacfilename(is_ogg)); + break; + default: + die_("internal error 009"); + return false; + } + if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, decoder); + printf("OK\n"); + + printf("testing get_state()... "); + FLAC::Decoder::Stream::State state = decoder->get_state(); + printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring()); + + dynamic_cast(decoder)->current_metadata_number_ = 0; + dynamic_cast(decoder)->ignore_errors_ = false; + dynamic_cast(decoder)->error_occurred_ = false; + + printf("testing get_md5_checking()... "); + if(!decoder->get_md5_checking()) { + printf("FAILED, returned false, expected true\n"); + return false; + } + printf("OK\n"); + + printf("testing process_until_end_of_metadata()... "); + if(!decoder->process_until_end_of_metadata()) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing process_single()... "); + if(!decoder->process_single()) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing skip_single_frame()... "); + if(!decoder->skip_single_frame()) + return die_s_("returned false", decoder); + printf("OK\n"); + + if(layer < LAYER_FILE) { + printf("testing flush()... "); + if(!decoder->flush()) + return die_s_("returned false", decoder); + printf("OK\n"); + + dynamic_cast(decoder)->ignore_errors_ = true; + printf("testing process_single()... "); + if(!decoder->process_single()) + return die_s_("returned false", decoder); + printf("OK\n"); + dynamic_cast(decoder)->ignore_errors_ = false; + } + + expect = (layer != LAYER_STREAM); + printf("testing seek_absolute()... "); + if(decoder->seek_absolute(0) != expect) + return die_s_(expect? "returned false" : "returned true", decoder); + printf("OK\n"); + + printf("testing process_until_end_of_stream()... "); + if(!decoder->process_until_end_of_stream()) + return die_s_("returned false", decoder); + printf("OK\n"); + + expect = (layer != LAYER_STREAM); + printf("testing seek_absolute()... "); + if(decoder->seek_absolute(0) != expect) + return die_s_(expect? "returned false" : "returned true", decoder); + printf("OK\n"); + + printf("testing get_channels()... "); + { + uint32_t channels = decoder->get_channels(); + if(channels != streaminfo_.data.stream_info.channels) { + printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels); + return false; + } + } + printf("OK\n"); + + printf("testing get_bits_per_sample()... "); + { + uint32_t bits_per_sample = decoder->get_bits_per_sample(); + if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) { + printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample); + return false; + } + } + printf("OK\n"); + + printf("testing get_sample_rate()... "); + { + uint32_t sample_rate = decoder->get_sample_rate(); + if(sample_rate != streaminfo_.data.stream_info.sample_rate) { + printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate); + return false; + } + } + printf("OK\n"); + + printf("testing get_blocksize()... "); + { + uint32_t blocksize = decoder->get_blocksize(); + /* value could be anything since we're at the last block, so accept any reasonable answer */ + printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED"); + if(blocksize == 0) + return false; + } + + printf("testing get_channel_assignment()... "); + { + ::FLAC__ChannelAssignment ca = decoder->get_channel_assignment(); + printf("returned %u (%s)... OK\n", (uint32_t)ca, ::FLAC__ChannelAssignmentString[ca]); + } + + if(layer < LAYER_FILE) { + printf("testing reset()... "); + if(!decoder->reset()) + return die_s_("returned false", decoder); + printf("OK\n"); + + if(layer == LAYER_STREAM) { + /* after a reset() we have to rewind the input ourselves */ + printf("rewinding input... "); + if(fseeko(dynamic_cast(decoder)->file_, 0, SEEK_SET) < 0) { + printf("FAILED, errno = %d\n", errno); + return false; + } + printf("OK\n"); + } + + dynamic_cast(decoder)->current_metadata_number_ = 0; + + printf("testing process_until_end_of_stream()... "); + if(!decoder->process_until_end_of_stream()) + return die_s_("returned false", decoder); + printf("OK\n"); + } + + printf("testing finish()... "); + if(!decoder->finish()) { + state = decoder->get_state(); + printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring()); + return false; + } + printf("OK\n"); + + /* + * respond all + */ + + printf("testing set_metadata_respond_all()... "); + if(!decoder->set_metadata_respond_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * ignore all + */ + + printf("testing set_metadata_ignore_all()... "); + if(!decoder->set_metadata_ignore_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * respond all, ignore VORBIS_COMMENT + */ + + printf("testing set_metadata_respond_all()... "); + if(!decoder->set_metadata_respond_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_ignore(VORBIS_COMMENT)... "); + if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_VORBIS_COMMENT)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + if(!is_ogg) /* encoder removes seektable for ogg */ + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * respond all, ignore APPLICATION + */ + + printf("testing set_metadata_respond_all()... "); + if(!decoder->set_metadata_respond_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_ignore(APPLICATION)... "); + if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_APPLICATION)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * respond all, ignore APPLICATION id of app#1 + */ + + printf("testing set_metadata_respond_all()... "); + if(!decoder->set_metadata_respond_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_ignore_application(of app block #1)... "); + if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * respond all, ignore APPLICATION id of app#1 & app#2 + */ + + printf("testing set_metadata_respond_all()... "); + if(!decoder->set_metadata_respond_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_ignore_application(of app block #1)... "); + if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_ignore_application(of app block #2)... "); + if(!decoder->set_metadata_ignore_application(application2_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * ignore all, respond VORBIS_COMMENT + */ + + printf("testing set_metadata_ignore_all()... "); + if(!decoder->set_metadata_ignore_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_respond(VORBIS_COMMENT)... "); + if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_VORBIS_COMMENT)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * ignore all, respond APPLICATION + */ + + printf("testing set_metadata_ignore_all()... "); + if(!decoder->set_metadata_ignore_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_respond(APPLICATION)... "); + if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_APPLICATION)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * ignore all, respond APPLICATION id of app#1 + */ + + printf("testing set_metadata_ignore_all()... "); + if(!decoder->set_metadata_ignore_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_respond_application(of app block #1)... "); + if(!decoder->set_metadata_respond_application(application1_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * ignore all, respond APPLICATION id of app#1 & app#2 + */ + + printf("testing set_metadata_ignore_all()... "); + if(!decoder->set_metadata_ignore_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_respond_application(of app block #1)... "); + if(!decoder->set_metadata_respond_application(application1_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_respond_application(of app block #2)... "); + if(!decoder->set_metadata_respond_application(application2_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * respond all, ignore APPLICATION, respond APPLICATION id of app#1 + */ + + printf("testing set_metadata_respond_all()... "); + if(!decoder->set_metadata_respond_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_ignore(APPLICATION)... "); + if(!decoder->set_metadata_ignore(FLAC__METADATA_TYPE_APPLICATION)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_respond_application(of app block #1)... "); + if(!decoder->set_metadata_respond_application(application1_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + /* + * ignore all, respond APPLICATION, ignore APPLICATION id of app#1 + */ + + printf("testing set_metadata_ignore_all()... "); + if(!decoder->set_metadata_ignore_all()) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_respond(APPLICATION)... "); + if(!decoder->set_metadata_respond(FLAC__METADATA_TYPE_APPLICATION)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing set_metadata_ignore_application(of app block #1)... "); + if(!decoder->set_metadata_ignore_application(application1_.data.application.id)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond(is_ogg) : dynamic_cast(decoder)->test_respond(is_ogg))) + return false; + + if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */ + ::fclose(dynamic_cast(decoder)->file_); + + printf("freeing decoder instance... "); + delete decoder; + printf("OK\n"); + + printf("\nPASSED!\n"); + + return true; +} + +bool test_decoders() +{ + FLAC__bool is_ogg = false; + + while(1) { + init_metadata_blocks_(); + + if(!generate_file_(is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_STREAM, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_FILE, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_FILENAME, is_ogg)) + return false; + + (void) grabbag__file_remove_file(flacfilename(is_ogg)); + + free_metadata_blocks_(); + + if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg) + break; + is_ogg = true; + } + + return true; +} diff --git a/vendor/flac/src/test_libFLAC++/decoders.h b/vendor/flac/src/test_libFLAC++/decoders.h new file mode 100644 index 0000000..4bbce13 --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/decoders.h @@ -0,0 +1,25 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLACPP_DECODERS_H +#define FLAC__TEST_LIBFLACPP_DECODERS_H + +bool test_decoders(); + +#endif diff --git a/vendor/flac/src/test_libFLAC++/encoders.cpp b/vendor/flac/src/test_libFLAC++/encoders.cpp new file mode 100644 index 0000000..0e356af --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/encoders.cpp @@ -0,0 +1,576 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "encoders.h" +#include "FLAC/assert.h" +#include "FLAC++/encoder.h" +#include "share/grabbag.h" +extern "C" { +#include "test_libs_common/file_utils_flac.h" +#include "test_libs_common/metadata_utils.h" +} +#include +#include +#include +#include +#include "share/compat.h" + +#ifdef _MSC_VER +// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning) +#pragma warning ( disable : 4800 ) +#endif + +typedef enum { + LAYER_STREAM = 0, /* FLAC__stream_encoder_init_stream() without seeking */ + LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_stream() with seeking */ + LAYER_FILE, /* FLAC__stream_encoder_init_FILE() */ + LAYER_FILENAME /* FLAC__stream_encoder_init_file() */ +} Layer; + +static const char * const LayerString[] = { + "Stream", + "Seekable Stream", + "FILE*", + "Filename" +}; + +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ }; +static const uint32_t num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]); + +static const char *flacfilename(bool is_ogg) +{ + return is_ogg? "metadata.oga" : "metadata.flac"; +} + +static bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static bool die_s_(const char *msg, const FLAC::Encoder::Stream *encoder) +{ + FLAC::Encoder::Stream::State state = encoder->get_state(); + + if(msg) + printf("FAILED, %s", msg); + else + printf("FAILED"); + + printf(", state = %u (%s)\n", (uint32_t)((::FLAC__StreamEncoderState)state), state.as_cstring()); + if(state == ::FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) { + FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state(); + printf(" verify decoder state = %u (%s)\n", (uint32_t)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring()); + } + + return false; +} + +static void init_metadata_blocks_() +{ + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static void free_metadata_blocks_() +{ + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +class StreamEncoder : public FLAC::Encoder::Stream { +public: + Layer layer_; + FILE *file_; + + StreamEncoder(Layer layer): FLAC::Encoder::Stream(), layer_(layer), file_(0) { } + ~StreamEncoder() { } + + // from FLAC::Encoder::Stream + ::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes); + ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame); + ::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + ::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); + void metadata_callback(const ::FLAC__StreamMetadata *metadata); +private: + StreamEncoder(const StreamEncoder&); + StreamEncoder&operator=(const StreamEncoder&); +}; + +::FLAC__StreamEncoderReadStatus StreamEncoder::read_callback(FLAC__byte buffer[], size_t *bytes) +{ + if(*bytes > 0) { + *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file_); + if(ferror(file_)) + return ::FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + else if(*bytes == 0) + return ::FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; + else + return ::FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; + } + else + return ::FLAC__STREAM_ENCODER_READ_STATUS_ABORT; +} + +::FLAC__StreamEncoderWriteStatus StreamEncoder::write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame) +{ + (void)samples, (void)current_frame; + + if(fwrite(buffer, 1, bytes, file_) != bytes) + return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + else + return ::FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} + +::FLAC__StreamEncoderSeekStatus StreamEncoder::seek_callback(FLAC__uint64 absolute_byte_offset) +{ + if(layer_==LAYER_STREAM) + return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; + else if(fseeko(file_, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; +} + +::FLAC__StreamEncoderTellStatus StreamEncoder::tell_callback(FLAC__uint64 *absolute_byte_offset) +{ + FLAC__off_t pos; + if(layer_==LAYER_STREAM) + return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; + else if((pos = ftello(file_)) < 0) + return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + } +} + +void StreamEncoder::metadata_callback(const ::FLAC__StreamMetadata *metadata) +{ + (void)metadata; +} + +class FileEncoder : public FLAC::Encoder::File { +public: + Layer layer_; + + FileEncoder(Layer layer): FLAC::Encoder::File(), layer_(layer) { } + ~FileEncoder() { } + + // from FLAC::Encoder::File + void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate); +}; + +void FileEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate) +{ + (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate; +} + +static FLAC::Encoder::Stream *new_by_layer(Layer layer) +{ + if(layer < LAYER_FILE) + return new StreamEncoder(layer); + else + return new FileEncoder(layer); +} + +static bool test_stream_encoder(Layer layer, bool is_ogg) +{ + FLAC::Encoder::Stream *encoder; + ::FLAC__StreamEncoderInitStatus init_status; + FILE *file = 0; + FLAC__int32 samples[1024]; + FLAC__int32 *samples_array[1] = { samples }; + uint32_t i; + + printf("\n+++ libFLAC++ unit test: FLAC::Encoder::%s (layer: %s, format: %s)\n\n", layeris_valid()) { + printf("FAILED, returned false\n"); + delete encoder; + return false; + } + printf("OK\n"); + + if(is_ogg) { + printf("testing set_ogg_serial_number()... "); + if(!encoder->set_ogg_serial_number(file_utils__ogg_serial_number)) + return die_s_("returned false", encoder); + printf("OK\n"); + } + + printf("testing set_verify()... "); + if(!encoder->set_verify(true)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_streamable_subset()... "); + if(!encoder->set_streamable_subset(true)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_channels()... "); + if(!encoder->set_channels(streaminfo_.data.stream_info.channels)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_bits_per_sample()... "); + if(!encoder->set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_sample_rate()... "); + if(!encoder->set_sample_rate(streaminfo_.data.stream_info.sample_rate)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_compression_level()... "); + if(!encoder->set_compression_level((uint32_t)(-1))) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_blocksize()... "); + if(!encoder->set_blocksize(streaminfo_.data.stream_info.min_blocksize)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_do_mid_side_stereo()... "); + if(!encoder->set_do_mid_side_stereo(false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_loose_mid_side_stereo()... "); + if(!encoder->set_loose_mid_side_stereo(false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_max_lpc_order()... "); + if(!encoder->set_max_lpc_order(0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_qlp_coeff_precision()... "); + if(!encoder->set_qlp_coeff_precision(0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_do_qlp_coeff_prec_search()... "); + if(!encoder->set_do_qlp_coeff_prec_search(false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_do_escape_coding()... "); + if(!encoder->set_do_escape_coding(false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_do_exhaustive_model_search()... "); + if(!encoder->set_do_exhaustive_model_search(false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_min_residual_partition_order()... "); + if(!encoder->set_min_residual_partition_order(0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_max_residual_partition_order()... "); + if(!encoder->set_max_residual_partition_order(0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_rice_parameter_search_dist()... "); + if(!encoder->set_rice_parameter_search_dist(0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_total_samples_estimate()... "); + if(!encoder->set_total_samples_estimate(streaminfo_.data.stream_info.total_samples)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_metadata()... "); + if(!encoder->set_metadata(metadata_sequence_, num_metadata_)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing set_limit_min_bitrate()... "); + if(!encoder->set_limit_min_bitrate(true)) + return die_s_("returned false", encoder); + printf("OK\n"); + + if(layer < LAYER_FILENAME) { + printf("opening file for FLAC output... "); + file = ::flac_fopen(flacfilename(is_ogg), "w+b"); + if(0 == file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + if(layer < LAYER_FILE) + dynamic_cast(encoder)->file_ = file; + } + + switch(layer) { + case LAYER_STREAM: + case LAYER_SEEKABLE_STREAM: + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? encoder->init_ogg() : encoder->init(); + break; + case LAYER_FILE: + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? + dynamic_cast(encoder)->init_ogg(file) : + dynamic_cast(encoder)->init(file); + break; + case LAYER_FILENAME: + printf("testing init%s()... ", is_ogg? "_ogg":""); + init_status = is_ogg? + dynamic_cast(encoder)->init_ogg(flacfilename(is_ogg)) : + dynamic_cast(encoder)->init(flacfilename(is_ogg)); + break; + default: + die_("internal error 001"); + return false; + } + if(init_status != ::FLAC__STREAM_ENCODER_INIT_STATUS_OK) + return die_s_(0, encoder); + printf("OK\n"); + + printf("testing get_state()... "); + FLAC::Encoder::Stream::State state = encoder->get_state(); + printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamEncoderState)state), state.as_cstring()); + + printf("testing get_verify_decoder_state()... "); + FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state(); + printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring()); + + { + FLAC__uint64 absolute_sample; + uint32_t frame_number; + uint32_t channel; + uint32_t sample; + FLAC__int32 expected; + FLAC__int32 got; + + printf("testing get_verify_decoder_error_stats()... "); + encoder->get_verify_decoder_error_stats(&absolute_sample, &frame_number, &channel, &sample, &expected, &got); + printf("OK\n"); + } + + printf("testing get_verify()... "); + if(encoder->get_verify() != true) { + printf("FAILED, expected true, got false\n"); + return false; + } + printf("OK\n"); + + printf("testing get_streamable_subset()... "); + if(encoder->get_streamable_subset() != true) { + printf("FAILED, expected true, got false\n"); + return false; + } + printf("OK\n"); + + printf("testing get_do_mid_side_stereo()... "); + if(encoder->get_do_mid_side_stereo() != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing get_loose_mid_side_stereo()... "); + if(encoder->get_loose_mid_side_stereo() != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing get_channels()... "); + if(encoder->get_channels() != streaminfo_.data.stream_info.channels) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, encoder->get_channels()); + return false; + } + printf("OK\n"); + + printf("testing get_bits_per_sample()... "); + if(encoder->get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, encoder->get_bits_per_sample()); + return false; + } + printf("OK\n"); + + printf("testing get_sample_rate()... "); + if(encoder->get_sample_rate() != streaminfo_.data.stream_info.sample_rate) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, encoder->get_sample_rate()); + return false; + } + printf("OK\n"); + + printf("testing get_blocksize()... "); + if(encoder->get_blocksize() != streaminfo_.data.stream_info.min_blocksize) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, encoder->get_blocksize()); + return false; + } + printf("OK\n"); + + printf("testing get_max_lpc_order()... "); + if(encoder->get_max_lpc_order() != 0) { + printf("FAILED, expected %d, got %u\n", 0, encoder->get_max_lpc_order()); + return false; + } + printf("OK\n"); + + printf("testing get_qlp_coeff_precision()... "); + (void)encoder->get_qlp_coeff_precision(); + /* we asked the encoder to auto select this so we accept anything */ + printf("OK\n"); + + printf("testing get_do_qlp_coeff_prec_search()... "); + if(encoder->get_do_qlp_coeff_prec_search() != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing get_do_escape_coding()... "); + if(encoder->get_do_escape_coding() != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing get_do_exhaustive_model_search()... "); + if(encoder->get_do_exhaustive_model_search() != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing get_min_residual_partition_order()... "); + if(encoder->get_min_residual_partition_order() != 0) { + printf("FAILED, expected %d, got %u\n", 0, encoder->get_min_residual_partition_order()); + return false; + } + printf("OK\n"); + + printf("testing get_max_residual_partition_order()... "); + if(encoder->get_max_residual_partition_order() != 0) { + printf("FAILED, expected %d, got %u\n", 0, encoder->get_max_residual_partition_order()); + return false; + } + printf("OK\n"); + + printf("testing get_rice_parameter_search_dist()... "); + if(encoder->get_rice_parameter_search_dist() != 0) { + printf("FAILED, expected %d, got %u\n", 0, encoder->get_rice_parameter_search_dist()); + return false; + } + printf("OK\n"); + + printf("testing get_total_samples_estimate()... "); + if(encoder->get_total_samples_estimate() != streaminfo_.data.stream_info.total_samples) { + printf("FAILED, expected %" PRIu64 ", got %" PRIu64 "\n", streaminfo_.data.stream_info.total_samples, encoder->get_total_samples_estimate()); + return false; + } + printf("OK\n"); + + printf("testing get_limit_min_bitrate()... "); + if(encoder->get_limit_min_bitrate() != true) { + printf("FAILED, expected true, got false\n"); + return false; + } + printf("OK\n"); + + /* init the dummy sample buffer */ + for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++) + samples[i] = i & 7; + + printf("testing process()... "); + if(!encoder->process(samples_array, sizeof(samples) / sizeof(FLAC__int32))) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing process_interleaved()... "); + if(!encoder->process_interleaved(samples, sizeof(samples) / sizeof(FLAC__int32))) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing finish()... "); + if(!encoder->finish()) { + state = encoder->get_state(); + printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::FLAC__StreamEncoderState)state), state.as_cstring()); + return false; + } + printf("OK\n"); + + if(layer < LAYER_FILE) + ::fclose(dynamic_cast(encoder)->file_); + + printf("freeing encoder instance... "); + delete encoder; + printf("OK\n"); + + printf("\nPASSED!\n"); + + return true; +} + +bool test_encoders() +{ + FLAC__bool is_ogg = false; + + while(1) { + init_metadata_blocks_(); + + if(!test_stream_encoder(LAYER_STREAM, is_ogg)) + return false; + + if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg)) + return false; + + if(!test_stream_encoder(LAYER_FILE, is_ogg)) + return false; + + if(!test_stream_encoder(LAYER_FILENAME, is_ogg)) + return false; + + (void) grabbag__file_remove_file(flacfilename(is_ogg)); + + free_metadata_blocks_(); + + if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg) + break; + is_ogg = true; + } + + return true; +} diff --git a/vendor/flac/src/test_libFLAC++/encoders.h b/vendor/flac/src/test_libFLAC++/encoders.h new file mode 100644 index 0000000..9da415c --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/encoders.h @@ -0,0 +1,25 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLACPP_ENCODERS_H +#define FLAC__TEST_LIBFLACPP_ENCODERS_H + +bool test_encoders(); + +#endif diff --git a/vendor/flac/src/test_libFLAC++/main.cpp b/vendor/flac/src/test_libFLAC++/main.cpp new file mode 100644 index 0000000..7183def --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/main.cpp @@ -0,0 +1,42 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "decoders.h" +#include "encoders.h" +#include "metadata.h" + +int main(int argc, char *argv[]) +{ + (void)argc, (void)argv; + + if(!test_encoders()) + return 1; + + if(!test_decoders()) + return 1; + + if(!test_metadata()) + return 1; + + return 0; +} diff --git a/vendor/flac/src/test_libFLAC++/metadata.cpp b/vendor/flac/src/test_libFLAC++/metadata.cpp new file mode 100644 index 0000000..a31031b --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/metadata.cpp @@ -0,0 +1,41 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "metadata.h" +#include + +extern bool test_metadata_object(); +extern bool test_metadata_file_manipulation(); + +bool test_metadata() +{ + if(!test_metadata_object()) + return false; + + if(!test_metadata_file_manipulation()) + return false; + + printf("\nPASSED!\n"); + + return true; +} diff --git a/vendor/flac/src/test_libFLAC++/metadata.h b/vendor/flac/src/test_libFLAC++/metadata.h new file mode 100644 index 0000000..8c45bc0 --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/metadata.h @@ -0,0 +1,25 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLACPP_METADATA_H +#define FLAC__TEST_LIBFLACPP_METADATA_H + +bool test_metadata(); + +#endif diff --git a/vendor/flac/src/test_libFLAC++/metadata_manip.cpp b/vendor/flac/src/test_libFLAC++/metadata_manip.cpp new file mode 100644 index 0000000..5d395db --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/metadata_manip.cpp @@ -0,0 +1,2241 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for malloc() */ +#include /* for memcpy()/memset() */ +#include /* some flavors of BSD (like OS X) require this to get time_t */ +#ifdef _MSC_VER +#include +#endif +#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__ +#include /* for chown(), unlink() */ +#endif +#include /* for stat(), maybe chmod() */ +#include "FLAC/assert.h" +#include "FLAC++/decoder.h" +#include "FLAC++/metadata.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "share/macros.h" +#include "share/safe_str.h" +extern "C" { +#include "test_libs_common/file_utils_flac.h" +} + +/****************************************************************************** + The general strategy of these tests (for interface levels 1 and 2) is + to create a dummy FLAC file with a known set of initial metadata + blocks, then keep a mirror locally of what we expect the metadata to be + after each operation. Then testing becomes a simple matter of running + a FLAC::Decoder::File over the dummy file after each operation, comparing + the decoded metadata to what's in our local copy. If there are any + differences in the metadata, or the actual audio data is corrupted, we + will catch it while decoding. +******************************************************************************/ + +class OurFileDecoder: public FLAC::Decoder::File { +public: + inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { } + + bool ignore_metadata_; + bool error_occurred_; +protected: + ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); + void metadata_callback(const ::FLAC__StreamMetadata *metadata); + void error_callback(::FLAC__StreamDecoderErrorStatus status); +}; + +struct OurMetadata { + FLAC::Metadata::Prototype *blocks[64]; + uint32_t num_blocks; +}; + +/* our copy of the metadata in flacfilename() */ +static OurMetadata our_metadata_; + +/* the current block number that corresponds to the position of the iterator we are testing */ +static uint32_t mc_our_block_number_ = 0; + +static const char *flacfilename(bool is_ogg) +{ + return is_ogg? "metadata.oga" : "metadata.flac"; +} + +static bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status) +{ + printf("ERROR: %s\n", msg); + printf(" status=%u (%s)\n", (uint32_t)((::FLAC__Metadata_ChainStatus)status), status.as_cstring()); + return false; +} + +static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator) +{ + const FLAC::Metadata::SimpleIterator::Status status = iterator.status(); + printf("ERROR: %s\n", msg); + printf(" status=%u (%s)\n", (uint32_t)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring()); + return false; +} + +static void *malloc_or_die_(size_t size) +{ + void *x = malloc(size); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size); + exit(1); + } + return x; +} + +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + +/* functions for working with our metadata copy */ + +static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, uint32_t position, bool copy) +{ + uint32_t i; + FLAC::Metadata::Prototype *obj = block; + FLAC__ASSERT(position < our_metadata_.num_blocks); + if(copy) { + if(0 == (obj = FLAC::Metadata::clone(block))) + return die_("during FLAC::Metadata::clone()"); + } + delete our_metadata_.blocks[position]; + our_metadata_.blocks[position] = obj; + + /* set the is_last flags */ + for(i = 0; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i]->set_is_last(false); + our_metadata_.blocks[i]->set_is_last(true); + + return true; +} + +static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, uint32_t position, bool copy) +{ + uint32_t i; + FLAC::Metadata::Prototype *obj = block; + if(copy) { + if(0 == (obj = FLAC::Metadata::clone(block))) + return die_("during FLAC::Metadata::clone()"); + } + if(position > our_metadata_.num_blocks) { + position = our_metadata_.num_blocks; + } + else { + for(i = our_metadata_.num_blocks; i > position; i--) + our_metadata_.blocks[i] = our_metadata_.blocks[i-1]; + } + our_metadata_.blocks[position] = obj; + our_metadata_.num_blocks++; + + /* set the is_last flags */ + for(i = 0; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i]->set_is_last(false); + our_metadata_.blocks[i]->set_is_last(true); + + return true; +} + +static void delete_from_our_metadata_(uint32_t position) +{ + uint32_t i; + FLAC__ASSERT(position < our_metadata_.num_blocks); + delete our_metadata_.blocks[position]; + for(i = position; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i] = our_metadata_.blocks[i+1]; + our_metadata_.num_blocks--; + + /* set the is_last flags */ + if(our_metadata_.num_blocks > 0) { + for(i = 0; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i]->set_is_last(false); + our_metadata_.blocks[i]->set_is_last(true); + } +} + +void add_to_padding_length_(uint32_t indx, int delta) +{ + FLAC::Metadata::Padding *padding = dynamic_cast(our_metadata_.blocks[indx]); + FLAC__ASSERT(0 != padding); + padding->set_length((uint32_t)((int)padding->get_length() + delta)); +} + +/* + * This wad of functions supports filename- and callback-based chain reading/writing. + * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c + */ +bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename) +{ + static const char *tempfile_suffix = ".metadata_edit"; + size_t destlen = strlen(filename) + strlen(tempfile_suffix) + 1; + + *tempfilename = (char*)malloc(destlen); + if (*tempfilename == 0) + return false; + flac_snprintf(*tempfilename, destlen, "%s%s", filename, tempfile_suffix); + + *tempfile = flac_fopen(*tempfilename, "wb"); + if (*tempfile == 0) + return false; + + return true; +} + +void cleanup_tempfile_(FILE **tempfile, char **tempfilename) +{ + if (*tempfile != 0) { + (void)fclose(*tempfile); + *tempfile = 0; + } + + if (*tempfilename != 0) { + (void)flac_unlink(*tempfilename); + free(*tempfilename); + *tempfilename = 0; + } +} + +bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != tempfile); + FLAC__ASSERT(0 != tempfilename); + FLAC__ASSERT(0 != *tempfilename); + + if(0 != *tempfile) { + (void)fclose(*tempfile); + *tempfile = 0; + } + +#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ + /* on some flavors of windows, flac_rename() will fail if the destination already exists */ + if(flac_unlink(filename) < 0) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } +#endif + + if(0 != flac_rename(*tempfilename, filename)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + + cleanup_tempfile_(tempfile, tempfilename); + + return true; +} + +bool get_file_stats_(const char *filename, struct flac_stat_s *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + return (0 == flac_stat(filename, stats)); +} + +void set_file_stats_(const char *filename, struct flac_stat_s *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32) + struct timespec srctime[2] = {}; + srctime[0].tv_sec = stats->st_atime; + srctime[1].tv_sec = stats->st_mtime; +#else + struct utimbuf srctime; + srctime.actime = stats->st_atime; + srctime.modtime = stats->st_mtime; +#endif + (void)flac_chmod(filename, stats->st_mode); + (void)flac_utime(filename, &srctime); +#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__ + FLAC_CHECK_RETURN(chown(filename, stats->st_uid, (gid_t)(-1))); + FLAC_CHECK_RETURN(chown(filename, (uid_t)(-1), stats->st_gid)); +#endif +} + +#ifdef FLAC__VALGRIND_TESTING +static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle) +{ + FILE *stream = (FILE*)handle; + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#endif + +static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence) +{ + FLAC__off_t o = (FLAC__off_t)offset; + FLAC__ASSERT(offset == o); + return fseeko((FILE*)handle, o, whence); +} + +static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle) +{ + return ftello((FILE*)handle); +} + +static int chain_eof_cb_(::FLAC__IOHandle handle) +{ + return feof((FILE*)handle); +} + +static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename) +{ + if(filename_based) + return chain.write(use_padding, preserve_file_stats); + else { + ::FLAC__IOCallbacks callbacks; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.read = (::FLAC__IOCallback_Read)fread; +#ifdef FLAC__VALGRIND_TESTING + callbacks.write = chain_write_cb_; +#else + callbacks.write = (::FLAC__IOCallback_Write)fwrite; +#endif + callbacks.seek = chain_seek_cb_; + callbacks.eof = chain_eof_cb_; + + if(chain.check_if_tempfile_needed(use_padding)) { + struct flac_stat_s stats; + FILE *file, *tempfile; + char *tempfilename; + if(preserve_file_stats) { + if(!get_file_stats_(filename, &stats)) + return false; + } + if(0 == (file = flac_fopen(filename, "rb"))) + return false; /*@@@@ chain status still says OK though */ + if(!open_tempfile_(filename, &tempfile, &tempfilename)) { + fclose(file); + cleanup_tempfile_(&tempfile, &tempfilename); + return false; /*@@@@ chain status still says OK though */ + } + if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) { + fclose(file); + fclose(tempfile); + return false; + } + fclose(file); + fclose(tempfile); + file = tempfile = 0; + if(!transport_tempfile_(filename, &tempfile, &tempfilename)) + return false; + if(preserve_file_stats) + set_file_stats_(filename, &stats); + } + else { + FILE *file = flac_fopen(filename, "r+b"); + if(0 == file) + return false; /*@@@@ chain status still says OK though */ + if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks)) { + fclose(file); + return false; + } + fclose(file); + } + } + + return true; +} + +static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based, bool is_ogg) +{ + if(filename_based) + return chain.read(filename, is_ogg); + else { + ::FLAC__IOCallbacks callbacks; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.read = (::FLAC__IOCallback_Read)fread; + callbacks.seek = chain_seek_cb_; + callbacks.tell = chain_tell_cb_; + + { + bool ret; + FILE *file = flac_fopen(filename, "rb"); + if(0 == file) + return false; /*@@@@ chain status still says OK though */ + ret = chain.read((::FLAC__IOHandle)file, callbacks, is_ogg); + fclose(file); + return ret; + } + } +} + +/* function for comparing our metadata to a FLAC::Metadata::Chain */ + +static bool compare_chain_(FLAC::Metadata::Chain &chain, uint32_t current_position, FLAC::Metadata::Prototype *current_block) +{ + uint32_t i; + FLAC::Metadata::Iterator iterator; + bool next_ok = true; + + printf("\tcomparing chain... "); + fflush(stdout); + + if(!iterator.is_valid()) + return die_("allocating memory for iterator"); + + iterator.init(chain); + + i = 0; + do { + FLAC::Metadata::Prototype *block; + + printf("%u... ", i); + fflush(stdout); + + if(0 == (block = iterator.get_block())) + return die_("getting block from iterator"); + + if(*block != *our_metadata_.blocks[i]) + return die_("metadata block mismatch"); + + delete block; + i++; + next_ok = iterator.next(); + } while(i < our_metadata_.num_blocks && next_ok); + + if(next_ok) + return die_("chain has more blocks than expected"); + + if(i < our_metadata_.num_blocks) + return die_("short block count in chain"); + + if(0 != current_block) { + printf("CURRENT_POSITION... "); + fflush(stdout); + + if(*current_block != *our_metadata_.blocks[current_position]) + return die_("metadata block mismatch"); + } + + printf("PASSED\n"); + + return true; +} + +::FLAC__StreamDecoderWriteStatus OurFileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + (void)buffer; + + if( + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) || + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0) + ) { + printf("content... "); + fflush(stdout); + } + + return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void OurFileDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata) +{ + /* don't bother checking if we've already hit an error */ + if(error_occurred_) + return; + + printf("%u... ", mc_our_block_number_); + fflush(stdout); + + if(!ignore_metadata_) { + if(mc_our_block_number_ >= our_metadata_.num_blocks) { + (void)die_("got more metadata blocks than expected"); + error_occurred_ = true; + } + else { + if(*our_metadata_.blocks[mc_our_block_number_] != metadata) { + (void)die_("metadata block mismatch"); + error_occurred_ = true; + } + } + } + + mc_our_block_number_++; +} + +void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status) +{ + error_occurred_ = true; + printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (uint32_t)status); +} + +static bool generate_file_(bool include_extras, bool is_ogg) +{ + ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding; + ::FLAC__StreamMetadata *metadata[4]; + uint32_t i = 0, n = 0; + + printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : ""); + + while(our_metadata_.num_blocks > 0) + delete_from_our_metadata_(0); + + streaminfo.is_last = false; + streaminfo.type = ::FLAC__METADATA_TYPE_STREAMINFO; + streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + streaminfo.data.stream_info.min_blocksize = 576; + streaminfo.data.stream_info.max_blocksize = 576; + streaminfo.data.stream_info.min_framesize = 0; + streaminfo.data.stream_info.max_framesize = 0; + streaminfo.data.stream_info.sample_rate = 44100; + streaminfo.data.stream_info.channels = 1; + streaminfo.data.stream_info.bits_per_sample = 8; + streaminfo.data.stream_info.total_samples = 0; + memset(streaminfo.data.stream_info.md5sum, 0, 16); + + { + const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING); + vorbiscomment.is_last = false; + vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT; + vorbiscomment.length = (4 + vendor_string_length) + 4; + vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length; + vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1); + memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1); + vorbiscomment.data.vorbis_comment.num_comments = 0; + vorbiscomment.data.vorbis_comment.comments = 0; + } + + { + if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET))) + return die_("priming our metadata"); + cuesheet->is_last = false; + safe_strncpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN", sizeof(cuesheet->data.cue_sheet.media_catalog_number)); + cuesheet->data.cue_sheet.lead_in = 123; + cuesheet->data.cue_sheet.is_cd = false; + if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0)) + return die_("priming our metadata"); + cuesheet->data.cue_sheet.tracks[0].number = 1; + if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0)) + return die_("priming our metadata"); + } + + { + picture.is_last = false; + picture.type = ::FLAC__METADATA_TYPE_PICTURE; + picture.length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture.data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture.length += strlen(picture.data.picture.mime_type); + picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture.length += strlen((const char *)picture.data.picture.description); + picture.data.picture.width = 300; + picture.data.picture.height = 300; + picture.data.picture.depth = 24; + picture.data.picture.colors = 0; + picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture.data.picture.data_length = strlen((const char *)picture.data.picture.data); + picture.length += picture.data.picture.data_length; + } + + padding.is_last = true; + padding.type = ::FLAC__METADATA_TYPE_PADDING; + padding.length = 1234; + + metadata[n++] = &vorbiscomment; + if(include_extras) { + metadata[n++] = cuesheet; + metadata[n++] = &picture; + } + metadata[n++] = &padding; + + FLAC::Metadata::StreamInfo s(&streaminfo); + FLAC::Metadata::VorbisComment v(&vorbiscomment); + FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false); + FLAC::Metadata::Picture pi(&picture); + FLAC::Metadata::Padding p(&padding); + if( + !insert_to_our_metadata_(&s, i++, /*copy=*/true) || + !insert_to_our_metadata_(&v, i++, /*copy=*/true) || + (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) || + (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) || + !insert_to_our_metadata_(&p, i++, /*copy=*/true) + ) + return die_("priming our metadata"); + + if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n)) + return die_("creating the encoded file"); + + free(vorbiscomment.data.vorbis_comment.vendor_string.entry); + free(picture.data.picture.mime_type); + free(picture.data.picture.description); + free(picture.data.picture.data); + + return true; +} + +static bool test_file_(bool is_ogg, bool ignore_metadata) +{ + const char *filename = flacfilename(is_ogg); + OurFileDecoder decoder(ignore_metadata); + + mc_our_block_number_ = 0; + decoder.error_occurred_ = false; + + printf("\ttesting '%s'... ", filename); + fflush(stdout); + + if(!decoder.is_valid()) + return die_("couldn't allocate decoder instance"); + + decoder.set_md5_checking(true); + decoder.set_metadata_respond_all(); + if((is_ogg? decoder.init_ogg(filename) : decoder.init(filename)) != ::FLAC__STREAM_DECODER_INIT_STATUS_OK) { + (void)decoder.finish(); + return die_("initializing decoder\n"); + } + if(!decoder.process_until_end_of_stream()) { + (void)decoder.finish(); + return die_("decoding file\n"); + } + + (void)decoder.finish(); + + if(decoder.error_occurred_) + return false; + + if(mc_our_block_number_ != our_metadata_.num_blocks) + return die_("short metadata block count"); + + printf("PASSED\n"); + return true; +} + +static bool change_stats_(const char *filename, bool read_only) +{ + if(!grabbag__file_change_stats(filename, read_only)) + return die_("during grabbag__file_change_stats()"); + + return true; +} + +static bool remove_file_(const char *filename) +{ + while(our_metadata_.num_blocks > 0) + delete_from_our_metadata_(0); + + if(!grabbag__file_remove_file(filename)) + return die_("removing file"); + + return true; +} + +static bool test_level_0_() +{ + FLAC::Metadata::StreamInfo streaminfo; + + printf("\n\n++++++ testing level 0 interface\n"); + + if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false)) + return false; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true)) + return false; + + printf("testing FLAC::Metadata::get_streaminfo()... "); + + if(!FLAC::Metadata::get_streaminfo(flacfilename(/*is_ogg=*/false), streaminfo)) + return die_("during FLAC::Metadata::get_streaminfo()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(streaminfo.get_channels() != 1) + return die_("mismatch in streaminfo.get_channels()"); + if(streaminfo.get_bits_per_sample() != 8) + return die_("mismatch in streaminfo.get_bits_per_sample()"); + if(streaminfo.get_sample_rate() != 44100) + return die_("mismatch in streaminfo.get_sample_rate()"); + if(streaminfo.get_min_blocksize() != 576) + return die_("mismatch in streaminfo.get_min_blocksize()"); + if(streaminfo.get_max_blocksize() != 576) + return die_("mismatch in streaminfo.get_max_blocksize()"); + + printf("OK\n"); + + { + printf("testing FLAC::Metadata::get_tags(VorbisComment *&)... "); + + FLAC::Metadata::VorbisComment *tags = 0; + + if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags)) + return die_("during FLAC::Metadata::get_tags()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(tags->get_num_comments() != 0) + return die_("mismatch in tags->get_num_comments()"); + + printf("OK\n"); + + delete tags; + } + + { + printf("testing FLAC::Metadata::get_tags(VorbisComment &)... "); + + FLAC::Metadata::VorbisComment tags; + + if(!FLAC::Metadata::get_tags(flacfilename(/*is_ogg=*/false), tags)) + return die_("during FLAC::Metadata::get_tags()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(tags.get_num_comments() != 0) + return die_("mismatch in tags.get_num_comments()"); + + printf("OK\n"); + } + + { + printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... "); + + FLAC::Metadata::CueSheet *cuesheet = 0; + + if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet)) + return die_("during FLAC::Metadata::get_cuesheet()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(cuesheet->get_lead_in() != 123) + return die_("mismatch in cuesheet->get_lead_in()"); + + printf("OK\n"); + + delete cuesheet; + } + + { + printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... "); + + FLAC::Metadata::CueSheet cuesheet; + + if(!FLAC::Metadata::get_cuesheet(flacfilename(/*is_ogg=*/false), cuesheet)) + return die_("during FLAC::Metadata::get_cuesheet()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(cuesheet.get_lead_in() != 123) + return die_("mismatch in cuesheet.get_lead_in()"); + + printf("OK\n"); + } + + { + printf("testing FLAC::Metadata::get_picture(Picture *&)... "); + + FLAC::Metadata::Picture *picture = 0; + + if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-1))) + return die_("during FLAC::Metadata::get_picture()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER) + return die_("mismatch in picture->get_type ()"); + + printf("OK\n"); + + delete picture; + } + + { + printf("testing FLAC::Metadata::get_picture(Picture &)... "); + + FLAC::Metadata::Picture picture; + + if(!FLAC::Metadata::get_picture(flacfilename(/*is_ogg=*/false), picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-1))) + return die_("during FLAC::Metadata::get_picture()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER) + return die_("mismatch in picture->get_type ()"); + + printf("OK\n"); + } + + if(!remove_file_(flacfilename(/*is_ogg=*/false))) + return false; + + return true; +} + +static bool test_level_1_() +{ + FLAC::Metadata::Prototype *block; + FLAC::Metadata::StreamInfo *streaminfo; + FLAC::Metadata::Padding *padding; + FLAC::Metadata::Application *app; + FLAC__byte data[1000]; + uint32_t our_current_position = 0; + + // initialize 'data' to avoid Valgrind errors + memset(data, 0, sizeof(data)); + + printf("\n\n++++++ testing level 1 interface\n"); + + /************************************************************/ + { + printf("simple iterator on read-only file\n"); + + if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false)) + return false; + + if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/true)) + return false; + + FLAC::Metadata::SimpleIterator iterator; + + if(!iterator.is_valid()) + return die_("iterator.is_valid() returned false"); + + if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false)) + return die_("iterator.init() returned false"); + + printf("is writable = %u\n", (uint32_t)iterator.is_writable()); + if(iterator.is_writable()) + return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n"); + + printf("iterate forwards\n"); + + if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_STREAMINFO) + return die_("expected STREAMINFO type from iterator.get_block_type()"); + if(0 == (block = iterator.get_block())) + return die_("getting block 0"); + if(block->get_type() != ::FLAC__METADATA_TYPE_STREAMINFO) + return die_("expected STREAMINFO type"); + if(block->get_is_last()) + return die_("expected is_last to be false"); + if(block->get_length() != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) + return die_("bad STREAMINFO length"); + /* check to see if some basic data matches (c.f. generate_file_()) */ + streaminfo = dynamic_cast(block); + FLAC__ASSERT(0 != streaminfo); + if(streaminfo->get_channels() != 1) + return die_("mismatch in channels"); + if(streaminfo->get_bits_per_sample() != 8) + return die_("mismatch in bits_per_sample"); + if(streaminfo->get_sample_rate() != 44100) + return die_("mismatch in sample_rate"); + if(streaminfo->get_min_blocksize() != 576) + return die_("mismatch in min_blocksize"); + if(streaminfo->get_max_blocksize() != 576) + return die_("mismatch in max_blocksize"); + // we will delete streaminfo a little later when we're really done with it... + + if(!iterator.next()) + return die_("forward iterator ended early"); + our_current_position++; + + if(!iterator.next()) + return die_("forward iterator ended early"); + our_current_position++; + + if(iterator.get_block_type() != ::FLAC__METADATA_TYPE_PADDING) + return die_("expected PADDING type from iterator.get_block_type()"); + if(0 == (block = iterator.get_block())) + return die_("getting block 1"); + if(block->get_type() != ::FLAC__METADATA_TYPE_PADDING) + return die_("expected PADDING type"); + if(!block->get_is_last()) + return die_("expected is_last to be true"); + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(block->get_length() != 1234) + return die_("bad PADDING length"); + delete block; + + if(iterator.next()) + return die_("forward iterator returned true but should have returned false"); + + printf("iterate backwards\n"); + if(!iterator.prev()) + return die_("reverse iterator ended early"); + if(!iterator.prev()) + return die_("reverse iterator ended early"); + if(iterator.prev()) + return die_("reverse iterator returned true but should have returned false"); + + printf("testing iterator.set_block() on read-only file...\n"); + + if(!iterator.set_block(streaminfo, false)) + printf("PASSED. iterator.set_block() returned false like it should\n"); + else + return die_("iterator.set_block() returned true but shouldn't have"); + delete streaminfo; + } + + /************************************************************/ + { + printf("simple iterator on writable file\n"); + + if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false)) + return false; + + printf("creating APPLICATION block\n"); + + if(0 == (app = new FLAC::Metadata::Application())) + return die_("new FLAC::Metadata::Application()"); + app->set_id((const uint8_t *)"duh"); + + printf("creating PADDING block\n"); + + if(0 == (padding = new FLAC::Metadata::Padding())) { + delete app; + return die_("new FLAC::Metadata::Padding()"); + } + padding->set_length(20); + + FLAC::Metadata::SimpleIterator iterator; + + if(!iterator.is_valid()) { + delete app; + delete padding; + return die_("iterator.is_valid() returned false"); + } + + if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false)) { + delete app; + delete padding; + return die_("iterator.init() returned false"); + } + our_current_position = 0; + + printf("is writable = %u\n", (uint32_t)iterator.is_writable()); + + printf("[S]VP\ttry to write over STREAMINFO block...\n"); + if(!iterator.set_block(app, false)) + printf("\titerator.set_block() returned false like it should\n"); + else { + delete app; + delete padding; + return die_("iterator.set_block() returned true but shouldn't have"); + } + + if(iterator.status() != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT) + return die_("iterator.status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT"); + + printf("[S]VP\tnext\n"); + if(!iterator.next()) { + delete app; + delete padding; + return die_("iterator ended early\n"); + } + our_current_position++; + + printf("S[V]P\tnext\n"); + if(!iterator.next()) { + delete app; + delete padding; + return die_("iterator ended early\n"); + } + our_current_position++; + + printf("SV[P]\tinsert PADDING after, don't expand into padding\n"); + padding->set_length(25); + if(!iterator.insert_block_after(padding, false)) + return die_ss_("iterator.insert_block_after(padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + printf("SVP[P]\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SV[P]P\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]PP\tinsert PADDING after, don't expand into padding\n"); + padding->set_length(30); + if(!iterator.insert_block_after(padding, false)) + return die_ss_("iterator.insert_block_after(padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[P]PP\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]PPP\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n"); + if(iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false) should have returned false", iterator); + + if(iterator.status() != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT) + return die_("iterator.status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT"); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("[S]VPPP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]PPP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]PP\tdelete (middle block), replace with padding\n"); + if(!iterator.delete_block(true)) + return die_ss_("iterator.delete_block(true)", iterator); + our_current_position--; + + printf("S[V]PPP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]PP\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("S[V]PP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVP[P]\tdelete (last block), replace with padding\n"); + if(!iterator.delete_block(true)) + return die_ss_("iterator.delete_block(false)", iterator); + our_current_position--; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[P]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVP[P]\tdelete (last block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[P]\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]P\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]VP\tset STREAMINFO (change sample rate)\n"); + FLAC__ASSERT(our_current_position == 0); + block = iterator.get_block(); + streaminfo = dynamic_cast(block); + FLAC__ASSERT(0 != streaminfo); + streaminfo->set_sample_rate(32000); + if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(block, false)) + return die_ss_("iterator.set_block(block, false)", iterator); + delete block; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("[S]VP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n"); + app->set_id((const uint8_t *)"euh"); /* twiddle the id so that our comparison doesn't miss transposition */ + if(!iterator.insert_block_after(app, true)) + return die_ss_("iterator.insert_block_after(app, true)", iterator); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return false; + add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length())); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n"); + app->set_id((const uint8_t *)"fuh"); /* twiddle the id */ + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true)) + return false; + add_to_padding_length_(our_current_position+1, -((int)(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + (int)app->get_length())); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n"); + app->set_id((const uint8_t *)"guh"); /* twiddle the id */ + if(!app->set_data(data, sizeof(data), true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app, false)) + return die_ss_("iterator.set_block(app, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n"); + app->set_id((const uint8_t *)"huh"); /* twiddle the id */ + if(!app->set_data(data, 12, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app, false)) + return die_ss_("iterator.set_block(app, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n"); + app->set_id((const uint8_t *)"iuh"); /* twiddle the id */ + if(!app->set_data(data, sizeof(data), true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + add_to_padding_length_(our_current_position+1, -((int)sizeof(data) - 12)); + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n"); + app->set_id((const uint8_t *)"juh"); /* twiddle the id */ + if(!app->set_data(data, 23, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true)) + return die_("copying object"); + dynamic_cast(our_metadata_.blocks[our_current_position+1])->set_length(sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH); + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVA[A]PP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVAA[P]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n"); + padding->set_length(5); + if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(padding, false)) + return die_ss_("iterator.set_block(padding, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVAAP[P]\tset APPLICATION (grow)\n"); + app->set_id((const uint8_t *)"kuh"); /* twiddle the id */ + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app, false)) + return die_ss_("iterator.set_block(app, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVAAP[A]\tset PADDING (equal)\n"); + padding->set_length(27); + if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(padding, false)) + return die_ss_("iterator.set_block(padding, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVAAP[P]\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVA[A]P\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVA[P]\tinsert PADDING after\n"); + padding->set_length(5); + if(!iterator.insert_block_after(padding, false)) + return die_ss_("iterator.insert_block_after(padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVAP[P]\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SVA[P]P\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n"); + if(!app->set_data(data, 32, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n"); + if(!app->set_data(data, 60, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n"); + if(!app->set_data(data, 87, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + dynamic_cast(our_metadata_.blocks[our_current_position+1])->set_length(0); + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n"); + if(!app->set_data(data, 91, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n"); + if(!app->set_data(data, 100, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + our_metadata_.blocks[our_current_position]->set_is_last(true); + if(!iterator.set_block(app, true)) + return die_ss_("iterator.set_block(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]\tset PADDING (equal size)\n"); + padding->set_length(app->get_length()); + if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(padding, true)) + return die_ss_("iterator.set_block(padding, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[P]\tinsert PADDING after\n"); + if(!iterator.insert_block_after(padding, false)) + return die_ss_("iterator.insert_block_after(padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVP[P]\tinsert PADDING after\n"); + padding->set_length(5); + if(!iterator.insert_block_after(padding, false)) + return die_ss_("iterator.insert_block_after(padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SVPP[P]\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SVP[P]P\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SV[P]PP\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n"); + if(!app->set_data(data, 101, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.insert_block_after(app, true)) + return die_ss_("iterator.insert_block_after(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n"); + if(!app->set_data(data, 97, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.insert_block_after(app, true)) + return die_ss_("iterator.insert_block_after(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n"); + if(!app->set_data(data, 100, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!iterator.insert_block_after(app, true)) + return die_ss_("iterator.insert_block_after(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]PP\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n"); + if(!app->set_data(data, 96, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + dynamic_cast(our_metadata_.blocks[our_current_position+1])->set_length(0); + if(!iterator.insert_block_after(app, true)) + return die_ss_("iterator.insert_block_after(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]PP\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("S[V]PP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]P\tdelete (middle block), don't replace with padding\n"); + if(!iterator.delete_block(false)) + return die_ss_("iterator.delete_block(false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + + printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n"); + if(!app->set_data(data, 1, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!iterator.insert_block_after(app, true)) + return die_ss_("iterator.insert_block_after(app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, /*ignore_metadata=*/false)) + return false; + } + + delete app; + delete padding; + + if(!remove_file_(flacfilename(/*is_ogg=*/false))) + return false; + + return true; +} + +static bool test_level_2_(bool filename_based, bool is_ogg) +{ + FLAC::Metadata::Prototype *block; + FLAC::Metadata::StreamInfo *streaminfo; + FLAC::Metadata::Application *app; + FLAC::Metadata::Padding *padding; + FLAC__byte data[2000]; + uint32_t our_current_position; + + // initialize 'data' to avoid Valgrind errors + memset(data, 0, sizeof(data)); + + printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native"); + + printf("generate read-only file\n"); + + if(!generate_file_(/*include_extras=*/false, is_ogg)) + return false; + + if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true)) + return false; + + printf("create chain\n"); + FLAC::Metadata::Chain chain; + if(!chain.is_valid()) + return die_("allocating memory for chain"); + + printf("read chain\n"); + + if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg)) + return die_c_("reading chain", chain.status()); + + printf("[S]VP\ttest initial metadata\n"); + + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + if(is_ogg) + goto end; + + printf("switch file to read-write\n"); + + if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false)) + return false; + + printf("create iterator\n"); + { + FLAC::Metadata::Iterator iterator; + if(!iterator.is_valid()) + return die_("allocating memory for iterator"); + + our_current_position = 0; + + iterator.init(chain); + + if(0 == (block = iterator.get_block())) + return die_("getting block from iterator"); + + FLAC__ASSERT(block->get_type() == FLAC__METADATA_TYPE_STREAMINFO); + + printf("[S]VP\tmodify STREAMINFO, write\n"); + + streaminfo = dynamic_cast(block); + FLAC__ASSERT(0 != streaminfo); + streaminfo->set_sample_rate(32000); + if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true)) + return die_("copying object"); + delete block; + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(false, true)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("[S]VP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]\treplace PADDING with identical-size APPLICATION\n"); + if(0 == (block = iterator.get_block())) + return die_("getting block from iterator"); + if(0 == (app = new FLAC::Metadata::Application())) + return die_("new FLAC::Metadata::Application()"); + app->set_id((const uint8_t *)"duh"); + if(!app->set_data(data, block->get_length()-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true)) + return die_("setting APPLICATION data"); + delete block; + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(false, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]\tshrink APPLICATION, don't use padding\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 26, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(false, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]\tgrow APPLICATION, don't use padding\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 28, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(false, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 36, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(false, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 33, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n"); + if(0 == (padding = new FLAC::Metadata::Padding())) + return die_("creating PADDING block"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 29, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + padding->set_length(0); + if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false)) + return die_("internal error"); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 16, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + dynamic_cast(our_metadata_.blocks[our_current_position+1])->set_length(13); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 50, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 56, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + add_to_padding_length_(our_current_position+1, -(56 - 50)); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n"); + if(0 == (app = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("copying object"); + if(!app->set_data(data, 67, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!iterator.set_block(app)) + return die_c_("iterator.set_block(app)", chain.status()); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV[A]\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]A\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n"); + if(0 == (padding = new FLAC::Metadata::Padding())) + return die_("creating PADDING block"); + padding->set_length(30); + if(!iterator.insert_block_before(padding)) + printf("\titerator.insert_block_before() returned false like it should\n"); + else + return die_("iterator.insert_block_before() should have returned false"); + + printf("[S]VA\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]A\tinsert PADDING after\n"); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!iterator.insert_block_after(padding)) + return die_("iterator.insert_block_after(padding)"); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("SV[P]A\tinsert PADDING before\n"); + if(0 == (padding = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("creating PADDING block"); + padding->set_length(17); + if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!iterator.insert_block_before(padding)) + return die_("iterator.insert_block_before(padding)"); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("SV[P]PA\tinsert PADDING before\n"); + if(0 == (padding = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[our_current_position])))) + return die_("creating PADDING block"); + padding->set_length(0); + if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!iterator.insert_block_before(padding)) + return die_("iterator.insert_block_before(padding)"); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("SV[P]PPA\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVP[P]PA\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVPP[P]A\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVPPP[A]\tinsert PADDING after\n"); + if(0 == (padding = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[2])))) + return die_("creating PADDING block"); + padding->set_length(57); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!iterator.insert_block_after(padding)) + return die_("iterator.insert_block_after(padding)"); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("SVPPPA[P]\tinsert PADDING before\n"); + if(0 == (padding = dynamic_cast(FLAC::Metadata::clone(our_metadata_.blocks[2])))) + return die_("creating PADDING block"); + padding->set_length(99); + if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!iterator.insert_block_before(padding)) + return die_("iterator.insert_block_before(padding)"); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + } + our_current_position = 0; + + printf("SVPPPAPP\tmerge padding\n"); + chain.merge_padding(); + add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->get_length()); + add_to_padding_length_(2, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->get_length()); + add_to_padding_length_(6, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->get_length()); + delete_from_our_metadata_(7); + delete_from_our_metadata_(4); + delete_from_our_metadata_(3); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SVPAP\tsort padding\n"); + chain.sort_padding(); + add_to_padding_length_(4, FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->get_length()); + delete_from_our_metadata_(2); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(true, false)", chain.status()); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("create iterator\n"); + { + FLAC::Metadata::Iterator iterator; + if(!iterator.is_valid()) + return die_("allocating memory for iterator"); + + our_current_position = 0; + + iterator.init(chain); + + printf("[S]VAP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]AP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[A]P\tdelete middle block, replace with padding\n"); + if(0 == (padding = new FLAC::Metadata::Padding())) + return die_("creating PADDING block"); + padding->set_length(71); + if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false)) + return die_("copying object"); + if(!iterator.delete_block(/*replace_with_padding=*/true)) + return die_c_("iterator.delete_block(true)", chain.status()); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("S[V]PP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]P\tdelete middle block, don't replace with padding\n"); + delete_from_our_metadata_(our_current_position--); + if(!iterator.delete_block(/*replace_with_padding=*/false)) + return die_c_("iterator.delete_block(false)", chain.status()); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("S[V]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]\tdelete last block, replace with padding\n"); + if(0 == (padding = new FLAC::Metadata::Padding())) + return die_("creating PADDING block"); + padding->set_length(219); + if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false)) + return die_("copying object"); + if(!iterator.delete_block(/*replace_with_padding=*/true)) + return die_c_("iterator.delete_block(true)", chain.status()); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("S[V]P\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]\tdelete last block, don't replace with padding\n"); + delete_from_our_metadata_(our_current_position--); + if(!iterator.delete_block(/*replace_with_padding=*/false)) + return die_c_("iterator.delete_block(false)", chain.status()); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + printf("S[V]\tprev\n"); + if(!iterator.prev()) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]V\tdelete STREAMINFO block, should fail\n"); + if(iterator.delete_block(/*replace_with_padding=*/false)) + return die_("iterator.delete_block() on STREAMINFO should have failed but didn't"); + + block = iterator.get_block(); + if(!compare_chain_(chain, our_current_position, block)) + return false; + delete block; + + } // delete iterator + our_current_position = 0; + + printf("SV\tmerge padding\n"); + chain.merge_padding(); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(false, false)", chain.status()); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + + printf("SV\tsort padding\n"); + chain.sort_padding(); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during chain.write(false, false)", chain.status()); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, /*ignore_metadata=*/false)) + return false; + +end: + if(!remove_file_(flacfilename(is_ogg))) + return false; + + return true; +} + +static bool test_level_2_misc_(bool is_ogg) +{ + ::FLAC__IOCallbacks callbacks; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.read = (::FLAC__IOCallback_Read)fread; +#ifdef FLAC__VALGRIND_TESTING + callbacks.write = chain_write_cb_; +#else + callbacks.write = (::FLAC__IOCallback_Write)fwrite; +#endif + callbacks.seek = chain_seek_cb_; + callbacks.tell = chain_tell_cb_; + callbacks.eof = chain_eof_cb_; + + printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n"); + + printf("generate file\n"); + + if(!generate_file_(/*include_extras=*/false, is_ogg)) + return false; + + printf("create chain\n"); + FLAC::Metadata::Chain chain; + if(!chain.is_valid()) + return die_("allocating chain"); + + printf("read chain (filename-based)\n"); + + if(!chain.read(flacfilename(is_ogg))) + return die_c_("reading chain", chain.status()); + + printf("write chain with wrong method Chain::write(with callbacks)\n"); + { + if(chain.write(/*use_padding=*/false, 0, callbacks)) + return die_c_("mismatched write should have failed", chain.status()); + if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status()); + printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n"); + } + + printf("read chain (filename-based)\n"); + + if(!chain.read(flacfilename(is_ogg))) + return die_c_("reading chain", chain.status()); + + printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n"); + { + if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks)) + return die_c_("mismatched write should have failed", chain.status()); + if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status()); + printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n"); + } + + printf("read chain (callback-based)\n"); + { + FILE *file = flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) + return die_("opening file"); + if(!chain.read((::FLAC__IOHandle)file, callbacks)) { + fclose(file); + return die_c_("reading chain", chain.status()); + } + fclose(file); + } + + printf("write chain with wrong method write()\n"); + { + if(chain.write(/*use_padding=*/false, /*preserve_file_stats=*/false)) + return die_c_("mismatched write should have failed", chain.status()); + if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", chain.status()); + printf(" OK: write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n"); + } + + printf("read chain (callback-based)\n"); + { + FILE *file = flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) + return die_("opening file"); + if(!chain.read((::FLAC__IOHandle)file, callbacks)) { + fclose(file); + return die_c_("reading chain", chain.status()); + } + fclose(file); + } + + printf("testing Chain::check_if_tempfile_needed()... "); + + if(!chain.check_if_tempfile_needed(/*use_padding=*/false)) + printf("OK: Chain::check_if_tempfile_needed() returned false like it should\n"); + else + return die_("Chain::check_if_tempfile_needed() returned true but shouldn't have"); + + printf("write chain with wrong method Chain::write(with callbacks and tempfile)\n"); + { + if(chain.write(/*use_padding=*/false, 0, callbacks, 0, callbacks)) + return die_c_("mismatched write should have failed", chain.status()); + if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status()); + printf(" OK: Chain::write(with callbacks and tempfile) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n"); + } + + printf("read chain (callback-based)\n"); + { + FILE *file = flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) + return die_("opening file"); + if(!chain.read((::FLAC__IOHandle)file, callbacks)) { + fclose(file); + return die_c_("reading chain", chain.status()); + } + fclose(file); + } + + printf("create iterator\n"); + { + FLAC::Metadata::Iterator iterator; + if(!iterator.is_valid()) + return die_("allocating memory for iterator"); + + iterator.init(chain); + + printf("[S]VP\tnext\n"); + if(!iterator.next()) + return die_("iterator ended early\n"); + + printf("S[V]P\tdelete VORBIS_COMMENT, write\n"); + if(!iterator.delete_block(/*replace_with_padding=*/false)) + return die_c_("block delete failed\n", chain.status()); + + printf("testing Chain::check_if_tempfile_needed()... "); + + if(chain.check_if_tempfile_needed(/*use_padding=*/false)) + printf("OK: Chain::check_if_tempfile_needed() returned true like it should\n"); + else + return die_("Chain::check_if_tempfile_needed() returned false but shouldn't have"); + + printf("write chain with wrong method Chain::write(with callbacks)\n"); + { + if(chain.write(/*use_padding=*/false, 0, callbacks)) + return die_c_("mismatched write should have failed", chain.status()); + if(chain.status() != ::FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", chain.status()); + printf(" OK: Chain::write(with callbacks) returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n"); + } + + } // delete iterator + + if(!remove_file_(flacfilename(is_ogg))) + return false; + + return true; +} + +bool test_metadata_file_manipulation() +{ + printf("\n+++ libFLAC++ unit test: metadata manipulation\n\n"); + + our_metadata_.num_blocks = 0; + + if(!test_level_0_()) + return false; + + if(!test_level_1_()) + return false; + + if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */ + return false; + if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */ + return false; + if(!test_level_2_misc_(/*is_ogg=*/false)) + return false; + + if(FLAC_API_SUPPORTS_OGG_FLAC) { + if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */ + return false; + if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */ + return false; +#if 0 + /* when ogg flac write is supported, will have to add this: */ + if(!test_level_2_misc_(/*is_ogg=*/true)) + return false; +#endif + } + + return true; +} diff --git a/vendor/flac/src/test_libFLAC++/metadata_object.cpp b/vendor/flac/src/test_libFLAC++/metadata_object.cpp new file mode 100644 index 0000000..ab4cfbf --- /dev/null +++ b/vendor/flac/src/test_libFLAC++/metadata_object.cpp @@ -0,0 +1,2099 @@ +/* test_libFLAC++ - Unit tester for libFLAC++ + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include /* for malloc() */ +#include /* for memcmp() */ +#include "FLAC/assert.h" +#include "FLAC++/metadata.h" +#include "share/safe_str.h" + +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application_, vorbiscomment_, cuesheet_, picture_; + +static bool die_(const char *msg) +{ + printf("FAILED, %s\n", msg); + return false; +} + +static void *malloc_or_die_(size_t size) +{ + void *x = malloc(size); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size); + exit(1); + } + return x; +} + +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + +static bool index_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Index &indx, const ::FLAC__StreamMetadata_CueSheet_Index &indxcopy) +{ + if(indxcopy.offset != indx.offset) + return false; + if(indxcopy.number != indx.number) + return false; + return true; +} + +static bool track_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Track *track, const ::FLAC__StreamMetadata_CueSheet_Track *trackcopy) +{ + uint32_t i; + + if(trackcopy->offset != track->offset) + return false; + if(trackcopy->number != track->number) + return false; + if(0 != strcmp(trackcopy->isrc, track->isrc)) + return false; + if(trackcopy->type != track->type) + return false; + if(trackcopy->pre_emphasis != track->pre_emphasis) + return false; + if(trackcopy->num_indices != track->num_indices) + return false; + if(0 == track->indices || 0 == trackcopy->indices) { + if(track->indices != trackcopy->indices) + return false; + } + else { + for(i = 0; i < track->num_indices; i++) { + if(!index_is_equal_(trackcopy->indices[i], track->indices[i])) + return false; + } + } + return true; +} + +static void init_metadata_blocks_() +{ + streaminfo_.is_last = false; + streaminfo_.type = ::FLAC__METADATA_TYPE_STREAMINFO; + streaminfo_.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + streaminfo_.data.stream_info.min_blocksize = 576; + streaminfo_.data.stream_info.max_blocksize = 576; + streaminfo_.data.stream_info.min_framesize = 0; + streaminfo_.data.stream_info.max_framesize = 0; + streaminfo_.data.stream_info.sample_rate = 44100; + streaminfo_.data.stream_info.channels = 1; + streaminfo_.data.stream_info.bits_per_sample = 8; + streaminfo_.data.stream_info.total_samples = 0; + memset(streaminfo_.data.stream_info.md5sum, 0, 16); + + padding_.is_last = false; + padding_.type = ::FLAC__METADATA_TYPE_PADDING; + padding_.length = 1234; + + seektable_.is_last = false; + seektable_.type = ::FLAC__METADATA_TYPE_SEEKTABLE; + seektable_.data.seek_table.num_points = 2; + seektable_.length = seektable_.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; + seektable_.data.seek_table.points = (::FLAC__StreamMetadata_SeekPoint*)malloc_or_die_(seektable_.data.seek_table.num_points * sizeof(::FLAC__StreamMetadata_SeekPoint)); + seektable_.data.seek_table.points[0].sample_number = 0; + seektable_.data.seek_table.points[0].stream_offset = 0; + seektable_.data.seek_table.points[0].frame_samples = streaminfo_.data.stream_info.min_blocksize; + seektable_.data.seek_table.points[1].sample_number = ::FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + seektable_.data.seek_table.points[1].stream_offset = 1000; + seektable_.data.seek_table.points[1].frame_samples = streaminfo_.data.stream_info.min_blocksize; + + application_.is_last = false; + application_.type = ::FLAC__METADATA_TYPE_APPLICATION; + application_.length = 8; + memcpy(application_.data.application.id, "\xfe\xdc\xba\x98", 4); + application_.data.application.data = (FLAC__byte*)malloc_or_die_(4); + memcpy(application_.data.application.data, "\xf0\xe1\xd2\xc3", 4); + + vorbiscomment_.is_last = false; + vorbiscomment_.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT; + vorbiscomment_.length = (4 + 5) + 4 + (4 + 12) + (4 + 12); + vorbiscomment_.data.vorbis_comment.vendor_string.length = 5; + vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(5+1); + memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "name0", 5+1); + vorbiscomment_.data.vorbis_comment.num_comments = 2; + vorbiscomment_.data.vorbis_comment.comments = (::FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment_.data.vorbis_comment.num_comments * sizeof(::FLAC__StreamMetadata_VorbisComment_Entry)); + vorbiscomment_.data.vorbis_comment.comments[0].length = 12; + vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(12+1); + memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "name2=value2", 12+1); + vorbiscomment_.data.vorbis_comment.comments[1].length = 12; + vorbiscomment_.data.vorbis_comment.comments[1].entry = (FLAC__byte*)malloc_or_die_(12+1); + memcpy(vorbiscomment_.data.vorbis_comment.comments[1].entry, "name3=value3", 12+1); + + cuesheet_.is_last = false; + cuesheet_.type = ::FLAC__METADATA_TYPE_CUESHEET; + cuesheet_.length = + /* cuesheet guts */ + ( + FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN + ) / 8 + + /* 2 tracks */ + 2 * ( + FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN + ) / 8 + + /* 3 index points */ + 3 * ( + FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN + ) / 8 + ; + memset(cuesheet_.data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet_.data.cue_sheet.media_catalog_number)); + cuesheet_.data.cue_sheet.media_catalog_number[0] = 'j'; + cuesheet_.data.cue_sheet.media_catalog_number[1] = 'C'; + cuesheet_.data.cue_sheet.lead_in = 159; + cuesheet_.data.cue_sheet.is_cd = true; + cuesheet_.data.cue_sheet.num_tracks = 2; + cuesheet_.data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)malloc_or_die_(cuesheet_.data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track)); + cuesheet_.data.cue_sheet.tracks[0].offset = 1; + cuesheet_.data.cue_sheet.tracks[0].number = 1; + memcpy(cuesheet_.data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet_.data.cue_sheet.tracks[0].isrc)); + cuesheet_.data.cue_sheet.tracks[0].type = 0; + cuesheet_.data.cue_sheet.tracks[0].pre_emphasis = 1; + cuesheet_.data.cue_sheet.tracks[0].num_indices = 2; + cuesheet_.data.cue_sheet.tracks[0].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); + cuesheet_.data.cue_sheet.tracks[0].indices[0].offset = 0; + cuesheet_.data.cue_sheet.tracks[0].indices[0].number = 0; + cuesheet_.data.cue_sheet.tracks[0].indices[1].offset = 1234567890; + cuesheet_.data.cue_sheet.tracks[0].indices[1].number = 1; + cuesheet_.data.cue_sheet.tracks[1].offset = 2345678901u; + cuesheet_.data.cue_sheet.tracks[1].number = 2; + memcpy(cuesheet_.data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet_.data.cue_sheet.tracks[1].isrc)); + cuesheet_.data.cue_sheet.tracks[1].type = 1; + cuesheet_.data.cue_sheet.tracks[1].pre_emphasis = 0; + cuesheet_.data.cue_sheet.tracks[1].num_indices = 1; + cuesheet_.data.cue_sheet.tracks[1].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); + cuesheet_.data.cue_sheet.tracks[1].indices[0].offset = 0; + cuesheet_.data.cue_sheet.tracks[1].indices[0].number = 1; + + picture_.is_last = true; + picture_.type = FLAC__METADATA_TYPE_PICTURE; + picture_.length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture_.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture_.data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture_.length += strlen(picture_.data.picture.mime_type); + picture_.data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture_.length += strlen((const char *)picture_.data.picture.description); + picture_.data.picture.width = 300; + picture_.data.picture.height = 300; + picture_.data.picture.depth = 24; + picture_.data.picture.colors = 0; + picture_.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture_.data.picture.data_length = strlen((const char *)picture_.data.picture.data); + picture_.length += picture_.data.picture.data_length; +} + +static void free_metadata_blocks_() +{ + free(seektable_.data.seek_table.points); + free(application_.data.application.data); + free(vorbiscomment_.data.vorbis_comment.vendor_string.entry); + free(vorbiscomment_.data.vorbis_comment.comments[0].entry); + free(vorbiscomment_.data.vorbis_comment.comments[1].entry); + free(vorbiscomment_.data.vorbis_comment.comments); + free(cuesheet_.data.cue_sheet.tracks[0].indices); + free(cuesheet_.data.cue_sheet.tracks[1].indices); + free(cuesheet_.data.cue_sheet.tracks); + free(picture_.data.picture.mime_type); + free(picture_.data.picture.description); + free(picture_.data.picture.data); +} + +bool test_metadata_object_streaminfo() +{ + uint32_t expected_length; + + printf("testing class FLAC::Metadata::StreamInfo\n"); + + printf("testing StreamInfo::StreamInfo()... "); + FLAC::Metadata::StreamInfo block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing StreamInfo::StreamInfo(const StreamInfo &)... +\n"); + printf(" StreamInfo::operator!=(const StreamInfo &)... "); + { + FLAC::Metadata::StreamInfo blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing StreamInfo::~StreamInfo()... "); + } + printf("OK\n"); + + printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata &)... +\n"); + printf(" StreamInfo::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::StreamInfo blockcopy(streaminfo_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != streaminfo_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *)... +\n"); + printf(" StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::StreamInfo blockcopy(&streaminfo_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != streaminfo_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::StreamInfo blockcopy(&streaminfo_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != streaminfo_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::StreamInfo(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_); + FLAC::Metadata::StreamInfo blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != streaminfo_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::StreamInfo blockcopy; + blockcopy.assign(&streaminfo_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != streaminfo_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" StreamInfo::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_); + FLAC::Metadata::StreamInfo blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != streaminfo_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::operator=(const StreamInfo &)... +\n"); + printf(" StreamInfo::operator==(const StreamInfo &)... "); + { + FLAC::Metadata::StreamInfo blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" StreamInfo::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::StreamInfo blockcopy = streaminfo_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == streaminfo_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" StreamInfo::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::StreamInfo blockcopy = &streaminfo_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == streaminfo_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing StreamInfo::set_min_blocksize()... "); + block.set_min_blocksize(streaminfo_.data.stream_info.min_blocksize); + printf("OK\n"); + + printf("testing StreamInfo::set_max_blocksize()... "); + block.set_max_blocksize(streaminfo_.data.stream_info.max_blocksize); + printf("OK\n"); + + printf("testing StreamInfo::set_min_framesize()... "); + block.set_min_framesize(streaminfo_.data.stream_info.min_framesize); + printf("OK\n"); + + printf("testing StreamInfo::set_max_framesize()... "); + block.set_max_framesize(streaminfo_.data.stream_info.max_framesize); + printf("OK\n"); + + printf("testing StreamInfo::set_sample_rate()... "); + block.set_sample_rate(streaminfo_.data.stream_info.sample_rate); + printf("OK\n"); + + printf("testing StreamInfo::set_channels()... "); + block.set_channels(streaminfo_.data.stream_info.channels); + printf("OK\n"); + + printf("testing StreamInfo::set_bits_per_sample()... "); + block.set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample); + printf("OK\n"); + + printf("testing StreamInfo::set_total_samples()... "); + block.set_total_samples(streaminfo_.data.stream_info.total_samples); + printf("OK\n"); + + printf("testing StreamInfo::set_md5sum()... "); + block.set_md5sum(streaminfo_.data.stream_info.md5sum); + printf("OK\n"); + + printf("testing StreamInfo::get_min_blocksize()... "); + if(block.get_min_blocksize() != streaminfo_.data.stream_info.min_blocksize) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_max_blocksize()... "); + if(block.get_max_blocksize() != streaminfo_.data.stream_info.max_blocksize) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_min_framesize()... "); + if(block.get_min_framesize() != streaminfo_.data.stream_info.min_framesize) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_max_framesize()... "); + if(block.get_max_framesize() != streaminfo_.data.stream_info.max_framesize) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_sample_rate()... "); + if(block.get_sample_rate() != streaminfo_.data.stream_info.sample_rate) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_channels()... "); + if(block.get_channels() != streaminfo_.data.stream_info.channels) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_bits_per_sample()... "); + if(block.get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_total_samples()... "); + if(block.get_total_samples() != streaminfo_.data.stream_info.total_samples) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing StreamInfo::get_md5sum()... "); + if(0 != memcmp(block.get_md5sum(), streaminfo_.data.stream_info.md5sum, 16)) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing StreamInfo::~StreamInfo()... "); + delete clone_; + printf("OK\n"); + + + printf("PASSED\n\n"); + return true; +} + +bool test_metadata_object_padding() +{ + uint32_t expected_length; + + printf("testing class FLAC::Metadata::Padding\n"); + + printf("testing Padding::Padding()... "); + FLAC::Metadata::Padding block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = 0; + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing Padding::Padding(const Padding &)... +\n"); + printf(" Padding::operator!=(const Padding &)... "); + { + FLAC::Metadata::Padding blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing Padding::~Padding()... "); + } + printf("OK\n"); + + printf("testing Padding::Padding(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Padding::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Padding blockcopy(padding_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != padding_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::Padding(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Padding::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Padding blockcopy(&padding_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != padding_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::Padding(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Padding::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Padding blockcopy(&padding_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != padding_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::Padding(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Padding::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_); + FLAC::Metadata::Padding blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != padding_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Padding::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Padding blockcopy; + blockcopy.assign(&padding_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != padding_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Padding::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_); + FLAC::Metadata::Padding blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != padding_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::operator=(const Padding &)... +\n"); + printf(" Padding::operator==(const Padding &)... "); + { + FLAC::Metadata::Padding blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Padding::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Padding blockcopy = padding_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == padding_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Padding::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Padding blockcopy = &padding_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == padding_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Padding::set_length()... "); + block.set_length(padding_.length); + printf("OK\n"); + + printf("testing Prototype::get_length()... "); + if(block.get_length() != padding_.length) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing Padding::~Padding()... "); + delete clone_; + printf("OK\n"); + + + printf("PASSED\n\n"); + return true; +} + +bool test_metadata_object_application() +{ + uint32_t expected_length; + + printf("testing class FLAC::Metadata::Application\n"); + + printf("testing Application::Application()... "); + FLAC::Metadata::Application block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing Application::Application(const Application &)... +\n"); + printf(" Application::operator!=(const Application &)... "); + { + FLAC::Metadata::Application blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing Application::~Application()... "); + } + printf("OK\n"); + + printf("testing Application::Application(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Application::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Application blockcopy(application_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != application_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::Application(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Application::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Application blockcopy(&application_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != application_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::Application(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Application::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Application blockcopy(&application_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != application_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::Application(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Application::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_); + FLAC::Metadata::Application blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != application_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Application::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Application blockcopy; + blockcopy.assign(&application_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != application_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Application::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_); + FLAC::Metadata::Application blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != application_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::operator=(const Application &)... +\n"); + printf(" Application::operator==(const Application &)... "); + { + FLAC::Metadata::Application blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Application::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Application blockcopy = application_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == application_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Application::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Application blockcopy = &application_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == application_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Application::set_id()... "); + block.set_id(application_.data.application.id); + printf("OK\n"); + + printf("testing Application::set_data()... "); + block.set_data(application_.data.application.data, application_.length - sizeof(application_.data.application.id), /*copy=*/true); + printf("OK\n"); + + printf("testing Application::get_id()... "); + if(0 != memcmp(block.get_id(), application_.data.application.id, sizeof(application_.data.application.id))) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing Application::get_data()... "); + if(0 != memcmp(block.get_data(), application_.data.application.data, application_.length - sizeof(application_.data.application.id))) + return die_("value mismatch, doesn't match previously set value"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing Application::~Application()... "); + delete clone_; + printf("OK\n"); + + + printf("PASSED\n\n"); + return true; +} + +bool test_metadata_object_seektable() +{ + uint32_t expected_length; + + printf("testing class FLAC::Metadata::SeekTable\n"); + + printf("testing SeekTable::SeekTable()... "); + FLAC::Metadata::SeekTable block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = 0; + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing SeekTable::SeekTable(const SeekTable &)... +\n"); + printf(" SeekTable::operator!=(const SeekTable &)... "); + { + FLAC::Metadata::SeekTable blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing SeekTable::~SeekTable()... "); + } + printf("OK\n"); + + printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata &)... +\n"); + printf(" SeekTable::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::SeekTable blockcopy(seektable_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != seektable_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *)... +\n"); + printf(" SeekTable::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::SeekTable blockcopy(&seektable_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != seektable_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" SeekTable::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::SeekTable blockcopy(&seektable_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != seektable_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::SeekTable(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" SeekTable::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_); + FLAC::Metadata::SeekTable blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != seektable_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" SeekTable::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::SeekTable blockcopy; + blockcopy.assign(&seektable_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != seektable_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" SeekTable::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_); + FLAC::Metadata::SeekTable blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != seektable_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::operator=(const SeekTable &)... +\n"); + printf(" SeekTable::operator==(const SeekTable &)... "); + { + FLAC::Metadata::SeekTable blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" SeekTable::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::SeekTable blockcopy = seektable_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == seektable_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" SeekTable::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::SeekTable blockcopy = &seektable_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == seektable_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing SeekTable::insert_point() x 3... "); + if(!block.insert_point(0, seektable_.data.seek_table.points[1])) + return die_("returned false"); + if(!block.insert_point(0, seektable_.data.seek_table.points[1])) + return die_("returned false"); + if(!block.insert_point(1, seektable_.data.seek_table.points[0])) + return die_("returned false"); + printf("OK\n"); + + printf("testing SeekTable::is_legal()... "); + if(block.is_legal()) + return die_("returned true"); + printf("OK\n"); + + printf("testing SeekTable::set_point()... "); + block.set_point(0, seektable_.data.seek_table.points[0]); + printf("OK\n"); + + printf("testing SeekTable::delete_point()... "); + if(!block.delete_point(0)) + return die_("returned false"); + printf("OK\n"); + + printf("testing SeekTable::is_legal()... "); + if(!block.is_legal()) + return die_("returned false"); + printf("OK\n"); + + printf("testing SeekTable::get_num_points()... "); + if(block.get_num_points() != seektable_.data.seek_table.num_points) + return die_("number mismatch"); + printf("OK\n"); + + printf("testing SeekTable::operator!=(const ::FLAC__StreamMetadata &)... "); + if(block != seektable_) + return die_("data mismatch"); + printf("OK\n"); + + printf("testing SeekTable::get_point()... "); + if( + block.get_point(1).sample_number != seektable_.data.seek_table.points[1].sample_number || + block.get_point(1).stream_offset != seektable_.data.seek_table.points[1].stream_offset || + block.get_point(1).frame_samples != seektable_.data.seek_table.points[1].frame_samples + ) + return die_("point mismatch"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing SeekTable::~SeekTable()... "); + delete clone_; + printf("OK\n"); + + + printf("PASSED\n\n"); + return true; +} + +bool test_metadata_object_vorbiscomment() +{ + uint32_t expected_length; + + printf("testing class FLAC::Metadata::VorbisComment::Entry\n"); + + printf("testing Entry::Entry()... "); + { + FLAC::Metadata::VorbisComment::Entry entry1; + if(!entry1.is_valid()) + return die_("!is_valid()"); + printf("OK\n"); + + printf("testing Entry::~Entry()... "); + } + printf("OK\n"); + + printf("testing Entry::Entry(const char *field, uint32_t field_length)... "); + FLAC::Metadata::VorbisComment::Entry entry2("name2=value2", strlen("name2=value2")); + if(!entry2.is_valid()) + return die_("!is_valid()"); + printf("OK\n"); + + { + printf("testing Entry::Entry(const char *field)... "); + FLAC::Metadata::VorbisComment::Entry entry2z("name2=value2"); + if(!entry2z.is_valid()) + return die_("!is_valid()"); + if(strcmp(entry2.get_field(), entry2z.get_field())) + return die_("bad value"); + printf("OK\n"); + } + + printf("testing Entry::Entry(const char *field_name, const char *field_value, uint32_t field_value_length)... "); + FLAC::Metadata::VorbisComment::Entry entry3("name3", "value3", strlen("value3")); + if(!entry3.is_valid()) + return die_("!is_valid()"); + printf("OK\n"); + + { + printf("testing Entry::Entry(const char *field_name, const char *field_value)... "); + FLAC::Metadata::VorbisComment::Entry entry3z("name3", "value3"); + if(!entry3z.is_valid()) + return die_("!is_valid()"); + if(strcmp(entry3.get_field(), entry3z.get_field())) + return die_("bad value"); + printf("OK\n"); + } + + printf("testing Entry::Entry(const Entry &entry)... "); + { + FLAC::Metadata::VorbisComment::Entry entry2copy(entry2); + if(!entry2copy.is_valid()) + return die_("!is_valid()"); + printf("OK\n"); + + printf("testing Entry::~Entry()... "); + } + printf("OK\n"); + + printf("testing Entry::operator=(const Entry &entry)... "); + FLAC::Metadata::VorbisComment::Entry entry1 = entry2; + if(!entry2.is_valid()) + return die_("!is_valid()"); + printf("OK\n"); + + printf("testing Entry::get_field_length()... "); + if(entry1.get_field_length() != strlen("name2=value2")) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Entry::get_field_name_length()... "); + if(entry1.get_field_name_length() != strlen("name2")) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Entry::get_field_value_length()... "); + if(entry1.get_field_value_length() != strlen("value2")) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Entry::get_entry()... "); + { + ::FLAC__StreamMetadata_VorbisComment_Entry entry = entry1.get_entry(); + if(entry.length != strlen("name2=value2")) + return die_("entry length mismatch"); + if(0 != memcmp(entry.entry, "name2=value2", entry.length)) + return die_("entry value mismatch"); + } + printf("OK\n"); + + printf("testing Entry::get_field()... "); + if(0 != memcmp(entry1.get_field(), "name2=value2", strlen("name2=value2"))) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Entry::get_field_name()... "); + if(0 != memcmp(entry1.get_field_name(), "name2", strlen("name2"))) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Entry::get_field_value()... "); + if(0 != memcmp(entry1.get_field_value(), "value2", strlen("value2"))) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Entry::set_field_name()... "); + if(!entry1.set_field_name("name1")) + return die_("returned false"); + if(0 != memcmp(entry1.get_field_name(), "name1", strlen("name1"))) + return die_("value mismatch"); + if(0 != memcmp(entry1.get_field(), "name1=value2", strlen("name1=value2"))) + return die_("entry mismatch"); + printf("OK\n"); + + printf("testing Entry::set_field_value(const char *field_value, uint32_t field_value_length)... "); + if(!entry1.set_field_value("value1", strlen("value1"))) + return die_("returned false"); + if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1"))) + return die_("value mismatch"); + if(0 != memcmp(entry1.get_field(), "name1=value1", strlen("name1=value1"))) + return die_("entry mismatch"); + printf("OK\n"); + + printf("testing Entry::set_field_value(const char *field_value)... "); + if(!entry1.set_field_value("value1")) + return die_("returned false"); + if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1"))) + return die_("value mismatch"); + if(0 != memcmp(entry1.get_field(), "name1=value1", strlen("name1=value1"))) + return die_("entry mismatch"); + printf("OK\n"); + + printf("testing Entry::set_field(const char *field, uint32_t field_length)... "); + if(!entry1.set_field("name0=value0", strlen("name0=value0"))) + return die_("returned false"); + if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0"))) + return die_("value mismatch"); + if(0 != memcmp(entry1.get_field_value(), "value0", strlen("value0"))) + return die_("value mismatch"); + if(0 != memcmp(entry1.get_field(), "name0=value0", strlen("name0=value0"))) + return die_("entry mismatch"); + printf("OK\n"); + + printf("testing Entry::set_field(const char *field)... "); + if(!entry1.set_field("name0=value0")) + return die_("returned false"); + if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0"))) + return die_("value mismatch"); + if(0 != memcmp(entry1.get_field_value(), "value0", strlen("value0"))) + return die_("value mismatch"); + if(0 != memcmp(entry1.get_field(), "name0=value0", strlen("name0=value0"))) + return die_("entry mismatch"); + printf("OK\n"); + + printf("PASSED\n\n"); + + + printf("testing class FLAC::Metadata::VorbisComment\n"); + + printf("testing VorbisComment::VorbisComment()... "); + FLAC::Metadata::VorbisComment block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + strlen(::FLAC__VENDOR_STRING) + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8); + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing VorbisComment::VorbisComment(const VorbisComment &)... +\n"); + printf(" VorbisComment::operator!=(const VorbisComment &)... "); + { + FLAC::Metadata::VorbisComment blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing VorbisComment::~VorbisComment()... "); + } + printf("OK\n"); + + printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata &)... +\n"); + printf(" VorbisComment::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::VorbisComment blockcopy(vorbiscomment_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != vorbiscomment_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *)... +\n"); + printf(" VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != vorbiscomment_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != vorbiscomment_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::VorbisComment(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_); + FLAC::Metadata::VorbisComment blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != vorbiscomment_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::VorbisComment blockcopy; + blockcopy.assign(&vorbiscomment_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != vorbiscomment_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" VorbisComment::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_); + FLAC::Metadata::VorbisComment blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != vorbiscomment_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::operator=(const VorbisComment &)... +\n"); + printf(" VorbisComment::operator==(const VorbisComment &)... "); + { + FLAC::Metadata::VorbisComment blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" VorbisComment::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::VorbisComment blockcopy = vorbiscomment_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == vorbiscomment_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" VorbisComment::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::VorbisComment blockcopy = &vorbiscomment_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == vorbiscomment_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing VorbisComment::get_num_comments()... "); + if(block.get_num_comments() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing VorbisComment::set_vendor_string()... "); + if(!block.set_vendor_string((const FLAC__byte *)"mame0")) + return die_("returned false"); + printf("OK\n"); + vorbiscomment_.data.vorbis_comment.vendor_string.entry[0] = 'm'; + + printf("testing VorbisComment::get_vendor_string()... "); + if(strlen((const char *)block.get_vendor_string()) != vorbiscomment_.data.vorbis_comment.vendor_string.length) + return die_("length mismatch"); + if(0 != memcmp(block.get_vendor_string(), vorbiscomment_.data.vorbis_comment.vendor_string.entry, vorbiscomment_.data.vorbis_comment.vendor_string.length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::append_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.append_comment(entry3)) + return die_("returned false"); + if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length) + return die_("length mismatch"); + if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::append_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.append_comment(entry2)) + return die_("returned false"); + if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length) + return die_("length mismatch"); + if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::delete_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.delete_comment(0)) + return die_("returned false"); + if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length) + return die_("length[0] mismatch"); + if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length)) + return die_("value[0] mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::delete_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.delete_comment(0)) + return die_("returned false"); + if(block.get_num_comments() != 0) + return die_("block mismatch, expected num_comments = 0"); + printf("OK\n"); + + printf("testing VorbisComment::insert_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.insert_comment(0, entry3)) + return die_("returned false"); + if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length) + return die_("length mismatch"); + if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::insert_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.insert_comment(0, entry3)) + return die_("returned false"); + if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length) + return die_("length mismatch"); + if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::insert_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.insert_comment(1, entry2)) + return die_("returned false"); + if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length) + return die_("length mismatch"); + if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::set_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.set_comment(0, entry2)) + return die_("returned false"); + if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length) + return die_("length mismatch"); + if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing VorbisComment::delete_comment()... +\n"); + printf(" VorbisComment::get_comment()... "); + if(!block.delete_comment(0)) + return die_("returned false"); + if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length) + return die_("length[0] mismatch"); + if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length)) + return die_("value[0] mismatch"); + if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length) + return die_("length[1] mismatch"); + if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length)) + return die_("value[0] mismatch"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing VorbisComment::~VorbisComment()... "); + delete clone_; + printf("OK\n"); + + + printf("PASSED\n\n"); + return true; +} + +bool test_metadata_object_cuesheet() +{ + uint32_t expected_length; + + printf("testing class FLAC::Metadata::CueSheet::Track\n"); + + printf("testing Track::Track()... "); + FLAC::Metadata::CueSheet::Track track0; + if(!track0.is_valid()) + return die_("!is_valid()"); + printf("OK\n"); + + { + printf("testing Track::get_track()... "); + const ::FLAC__StreamMetadata_CueSheet_Track *trackp = track0.get_track(); + if(0 == trackp) + return die_("returned pointer is NULL"); + printf("OK\n"); + + printf("testing Track::Track(const ::FLAC__StreamMetadata_CueSheet_Track*)... "); + FLAC::Metadata::CueSheet::Track track2(trackp); + if(!track2.is_valid()) + return die_("!is_valid()"); + if(!track_is_equal_(track2.get_track(), trackp)) + return die_("copy is not equal"); + printf("OK\n"); + + printf("testing Track::~Track()... "); + } + printf("OK\n"); + + printf("testing Track::Track(const Track &track)... "); + { + FLAC::Metadata::CueSheet::Track track0copy(track0); + if(!track0copy.is_valid()) + return die_("!is_valid()"); + if(!track_is_equal_(track0copy.get_track(), track0.get_track())) + return die_("copy is not equal"); + printf("OK\n"); + + printf("testing Track::~Track()... "); + } + printf("OK\n"); + + printf("testing Track::operator=(const Track &track)... "); + FLAC::Metadata::CueSheet::Track track1 = track0; + if(!track0.is_valid()) + return die_("!is_valid()"); + if(!track_is_equal_(track1.get_track(), track0.get_track())) + return die_("copy is not equal"); + printf("OK\n"); + + printf("testing Track::get_offset()... "); + if(track1.get_offset() != 0) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::get_number()... "); + if(track1.get_number() != 0) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::get_isrc()... "); + if(0 != memcmp(track1.get_isrc(), "\0\0\0\0\0\0\0\0\0\0\0\0\0", 13)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::get_type()... "); + if(track1.get_type() != 0) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::get_pre_emphasis()... "); + if(track1.get_pre_emphasis() != 0) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::get_num_indices()... "); + if(track1.get_num_indices() != 0) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::set_offset()... "); + track1.set_offset(588); + if(track1.get_offset() != 588) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::set_number()... "); + track1.set_number(1); + if(track1.get_number() != 1) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::set_isrc()... "); + track1.set_isrc("ABCDE1234567"); + if(0 != memcmp(track1.get_isrc(), "ABCDE1234567", 13)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::set_type()... "); + track1.set_type(1); + if(track1.get_type() != 1) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Track::set_pre_emphasis()... "); + track1.set_pre_emphasis(1); + if(track1.get_pre_emphasis() != 1) + return die_("value mismatch"); + printf("OK\n"); + + printf("PASSED\n\n"); + + printf("testing class FLAC::Metadata::CueSheet\n"); + + printf("testing CueSheet::CueSheet()... "); + FLAC::Metadata::CueSheet block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = ( + FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN + ) / 8; + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing CueSheet::CueSheet(const CueSheet &)... +\n"); + printf(" CueSheet::operator!=(const CueSheet &)... "); + { + FLAC::Metadata::CueSheet blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing CueSheet::~CueSheet()... "); + } + printf("OK\n"); + + printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata &)... +\n"); + printf(" CueSheet::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::CueSheet blockcopy(cuesheet_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != cuesheet_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *)... +\n"); + printf(" CueSheet::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::CueSheet blockcopy(&cuesheet_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != cuesheet_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" CueSheet::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::CueSheet blockcopy(&cuesheet_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != cuesheet_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::CueSheet(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" CueSheet::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_); + FLAC::Metadata::CueSheet blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != cuesheet_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" CueSheet::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::CueSheet blockcopy; + blockcopy.assign(&cuesheet_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != cuesheet_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" CueSheet::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_); + FLAC::Metadata::CueSheet blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != cuesheet_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::operator=(const CueSheet &)... +\n"); + printf(" CueSheet::operator==(const CueSheet &)... "); + { + FLAC::Metadata::CueSheet blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" CueSheet::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::CueSheet blockcopy = cuesheet_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == cuesheet_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" CueSheet::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::CueSheet blockcopy = &cuesheet_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == cuesheet_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing CueSheet::get_media_catalog_number()... "); + if(0 != strcmp(block.get_media_catalog_number(), "")) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing CueSheet::get_lead_in()... "); + if(block.get_lead_in() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing CueSheet::get_is_cd()... "); + if(block.get_is_cd()) + return die_("value mismatch, expected false"); + printf("OK\n"); + + printf("testing CueSheet::get_num_tracks()... "); + if(block.get_num_tracks() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing CueSheet::set_media_catalog_number()... "); + { + char mcn[129]; + memset(mcn, 0, sizeof(mcn)); + safe_strncpy(mcn, "1234567890123", sizeof(mcn)); + block.set_media_catalog_number(mcn); + if(0 != memcmp(block.get_media_catalog_number(), mcn, sizeof(mcn))) + return die_("value mismatch"); + } + printf("OK\n"); + + printf("testing CueSheet::set_lead_in()... "); + block.set_lead_in(588); + if(block.get_lead_in() != 588) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing CueSheet::set_is_cd()... "); + block.set_is_cd(true); + if(!block.get_is_cd()) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing CueSheet::insert_track()... +\n"); + printf(" CueSheet::get_track()... "); + if(!block.insert_track(0, track0)) + return die_("returned false"); + if(!track_is_equal_(block.get_track(0).get_track(), track0.get_track())) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing CueSheet::insert_track()... +\n"); + printf(" CueSheet::get_track()... "); + if(!block.insert_track(1, track1)) + return die_("returned false"); + if(!track_is_equal_(block.get_track(1).get_track(), track1.get_track())) + return die_("value mismatch"); + printf("OK\n"); + + ::FLAC__StreamMetadata_CueSheet_Index index0; + index0.offset = 588*4; + index0.number = 1; + + printf("testing CueSheet::insert_index(0)... +\n"); + printf(" CueSheet::get_track()... +\n"); + printf(" CueSheet::Track::get_index()... "); + if(!block.insert_index(0, 0, index0)) + return die_("returned false"); + if(!index_is_equal_(block.get_track(0).get_index(0), index0)) + return die_("value mismatch"); + printf("OK\n"); + + index0.offset = 588*5; + printf("testing CueSheet::Track::set_index()... "); + { + FLAC::Metadata::CueSheet::Track track_ = block.get_track(0); + track_.set_index(0, index0); + if(!index_is_equal_(track_.get_index(0), index0)) + return die_("value mismatch"); + } + printf("OK\n"); + + index0.offset = 588*6; + printf("testing CueSheet::set_index()... "); + block.set_index(0, 0, index0); + if(!index_is_equal_(block.get_track(0).get_index(0), index0)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing CueSheet::delete_index()... "); + if(!block.delete_index(0, 0)) + return die_("returned false"); + if(block.get_track(0).get_num_indices() != 0) + return die_("num_indices mismatch"); + printf("OK\n"); + + + printf("testing CueSheet::set_track()... +\n"); + printf(" CueSheet::get_track()... "); + if(!block.set_track(0, track1)) + return die_("returned false"); + if(!track_is_equal_(block.get_track(0).get_track(), track1.get_track())) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing CueSheet::delete_track()... "); + if(!block.delete_track(0)) + return die_("returned false"); + if(block.get_num_tracks() != 1) + return die_("num_tracks mismatch"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing CueSheet::~CueSheet()... "); + delete clone_; + printf("OK\n"); + + printf("PASSED\n\n"); + return true; +} + +bool test_metadata_object_picture() +{ + uint32_t expected_length; + + printf("testing class FLAC::Metadata::Picture\n"); + + printf("testing Picture::Picture()... "); + FLAC::Metadata::Picture block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + ) / 8; + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing Picture::Picture(const Picture &)... +\n"); + printf(" Picture::operator!=(const Picture &)... "); + { + FLAC::Metadata::Picture blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing Picture::~Picture()... "); + } + printf("OK\n"); + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Picture blockcopy(picture_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy(&picture_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy(&picture_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_); + FLAC::Metadata::Picture blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy; + blockcopy.assign(&picture_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_); + FLAC::Metadata::Picture blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::operator=(const Picture &)... +\n"); + printf(" Picture::operator==(const Picture &)... "); + { + FLAC::Metadata::Picture blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Picture::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Picture blockcopy = picture_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == picture_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Picture::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy = &picture_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == picture_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::get_type()... "); + if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER) + return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER"); + printf("OK\n"); + + printf("testing Picture::set_type()... +\n"); + printf(" Picture::get_type()... "); + block.set_type(::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA); + if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA) + return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA"); + printf("OK\n"); + + printf("testing Picture::set_mime_type()... "); + if(!block.set_mime_type("qmage/jpeg")) + return die_("returned false"); + printf("OK\n"); + picture_.data.picture.mime_type[0] = 'q'; + + printf("testing Picture::get_mime_type()... "); + if(0 != strcmp(block.get_mime_type(), picture_.data.picture.mime_type)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Picture::set_description()... "); + if(!block.set_description((const FLAC__byte*)"qesc")) + return die_("returned false"); + printf("OK\n"); + picture_.data.picture.description[0] = 'q'; + + printf("testing Picture::get_description()... "); + if(0 != strcmp((const char *)block.get_description(), (const char *)picture_.data.picture.description)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Picture::get_width()... "); + if(block.get_width() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_width()... +\n"); + printf(" Picture::get_width()... "); + block.set_width(400); + if(block.get_width() != 400) + return die_("value mismatch, expected 400"); + printf("OK\n"); + + printf("testing Picture::get_height()... "); + if(block.get_height() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_height()... +\n"); + printf(" Picture::get_height()... "); + block.set_height(200); + if(block.get_height() != 200) + return die_("value mismatch, expected 200"); + printf("OK\n"); + + printf("testing Picture::get_depth()... "); + if(block.get_depth() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_depth()... +\n"); + printf(" Picture::get_depth()... "); + block.set_depth(16); + if(block.get_depth() != 16) + return die_("value mismatch, expected 16"); + printf("OK\n"); + + printf("testing Picture::get_colors()... "); + if(block.get_colors() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_colors()... +\n"); + printf(" Picture::get_colors()... "); + block.set_colors(1u>16); + if(block.get_colors() != (1u>16)) + return die_("value mismatch, expected 2^16"); + printf("OK\n"); + + printf("testing Picture::get_data_length()... "); + if(block.get_data_length() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_data()... "); + if(!block.set_data((const FLAC__byte*)"qOMEJPEGDATA", strlen("qOMEJPEGDATA"))) + return die_("returned false"); + printf("OK\n"); + picture_.data.picture.data[0] = 'q'; + + printf("testing Picture::get_data()... "); + if(block.get_data_length() != picture_.data.picture.data_length) + return die_("length mismatch"); + if(0 != memcmp(block.get_data(), picture_.data.picture.data, picture_.data.picture.data_length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing Picture::~Picture()... "); + delete clone_; + printf("OK\n"); + + + printf("PASSED\n\n"); + return true; +} + +bool test_metadata_object() +{ + printf("\n+++ libFLAC++ unit test: metadata objects\n\n"); + + init_metadata_blocks_(); + + if(!test_metadata_object_streaminfo()) + return false; + + if(!test_metadata_object_padding()) + return false; + + if(!test_metadata_object_application()) + return false; + + if(!test_metadata_object_seektable()) + return false; + + if(!test_metadata_object_vorbiscomment()) + return false; + + if(!test_metadata_object_cuesheet()) + return false; + + if(!test_metadata_object_picture()) + return false; + + free_metadata_blocks_(); + + return true; +} diff --git a/vendor/flac/src/test_libFLAC/CMakeLists.txt b/vendor/flac/src/test_libFLAC/CMakeLists.txt new file mode 100644 index 0000000..36a5820 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/CMakeLists.txt @@ -0,0 +1,25 @@ +add_executable(test_libFLAC + bitreader.c + bitwriter.c + crc.c + decoders.c + encoders.c + endswap.c + format.c + main.c + metadata.c + metadata_manip.c + metadata_object.c + md5.c + "$/bitreader.c" + "$/bitwriter.c" + "$/crc.c" + "$/md5.c" + $<$:../../include/share/win_utf8_io.h> + $<$:../share/win_utf8_io/win_utf8_io.c>) + +target_compile_definitions(test_libFLAC PRIVATE + $<$:ENABLE_64_BIT_WORDS>) +target_include_directories(test_libFLAC PRIVATE + "$/include") +target_link_libraries(test_libFLAC FLAC grabbag test_libs_common) diff --git a/vendor/flac/src/test_libFLAC/Makefile.am b/vendor/flac/src/test_libFLAC/Makefile.am new file mode 100644 index 0000000..c77f87e --- /dev/null +++ b/vendor/flac/src/test_libFLAC/Makefile.am @@ -0,0 +1,63 @@ +# test_libFLAC - Unit tester for libFLAC +# Copyright (C) 2000-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt + +check_PROGRAMS = test_libFLAC + +if OS_IS_WINDOWS +win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la +flac__no_dll = -DFLAC__NO_DLL +endif + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src/libFLAC/include $(flac__no_dll) + +test_libFLAC_LDADD = \ + $(top_builddir)/src/share/grabbag/libgrabbag.la \ + $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ + $(top_builddir)/src/test_libs_common/libtest_libs_common.la \ + $(top_builddir)/src/libFLAC/libFLAC-static.la \ + $(win_utf8_lib) \ + @OGG_LIBS@ \ + -lm + +test_libFLAC_SOURCES = \ + bitreader.c \ + bitwriter.c \ + crc.c \ + decoders.c \ + encoders.c \ + endswap.c \ + format.c \ + main.c \ + metadata.c \ + metadata_manip.c \ + metadata_object.c \ + md5.c \ + bitreader.h \ + bitwriter.h \ + crc.h \ + decoders.h \ + encoders.h \ + endswap.h \ + format.h \ + metadata.h \ + md5.h + +CLEANFILES = test_libFLAC.exe diff --git a/vendor/flac/src/test_libFLAC/bitreader.c b/vendor/flac/src/test_libFLAC/bitreader.c new file mode 100644 index 0000000..d40bd1f --- /dev/null +++ b/vendor/flac/src/test_libFLAC/bitreader.c @@ -0,0 +1,355 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/assert.h" +#include "share/compat.h" +#include "private/bitreader.h" /* from the libFLAC private include area */ +#include "bitreader.h" +#include +#include /* for memcpy() */ + +/* + * WATCHOUT! Since FLAC__BitReader is a private structure, we use a copy of + * the definition here to get at the internals. Make sure this is kept up + * to date with what is in ../libFLAC/bitreader.c + */ +#if (ENABLE_64_BIT_WORDS == 0) + +typedef FLAC__uint32 brword; +#define FLAC__BYTES_PER_WORD 4 +#define FLAC__BITS_PER_WORD 32 + +#else + +typedef FLAC__uint64 brword; +#define FLAC__BYTES_PER_WORD 8 +#define FLAC__BITS_PER_WORD 64 + +#endif + +struct FLAC__BitReader { + /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */ + /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */ + brword *buffer; + uint32_t capacity; /* in words */ + uint32_t words; /* # of completed words in buffer */ + uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */ + uint32_t consumed_words; /* #words ... */ + uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */ + uint32_t read_crc16; /* the running frame CRC */ + uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */ + uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */ + FLAC__bool read_limit_set; /* whether reads are limited */ + uint32_t read_limit; /* the remaining size of what can be read */ + uint32_t last_seen_framesync; /* the location of the last seen framesync, if it is in the buffer, in bits from front of buffer */ + FLAC__BitReaderReadCallback read_callback; + void *client_data; +}; + +static FLAC__bool read_callback(FLAC__byte buffer[], size_t *bytes, void *data); + +static void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out) +{ + uint32_t i, j; + if(br == 0) { + fprintf(out, "bitreader is NULL\n"); + } + else { + fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits); + + for(i = 0; i < br->words; i++) { + fprintf(out, "%08X: ", i); + for(j = 0; j < FLAC__BITS_PER_WORD; j++) + if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits)) + fprintf(out, "."); + else + fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0); + fprintf(out, "\n"); + } + if(br->bytes > 0) { + fprintf(out, "%08X: ", i); + for(j = 0; j < br->bytes*8; j++) + if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits)) + fprintf(out, "."); + else + fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (br->bytes*8-j-1)) ? 1:0); + fprintf(out, "\n"); + } + } +} + +FLAC__bool test_bitreader(void) +{ + FLAC__BitReader *br; + FLAC__bool ok; + uint32_t i; + uint32_t words, bits; /* what we think br->consumed_words and br->consumed_bits should be */ + + FLAC__uint16 crc,expected_crcs[4] = { 0x5e4c, 0x7f6b, 0x2272, 0x42bf }; + FLAC__byte data[32]; + + FLAC__uint32 val_uint32; + FLAC__uint64 val_uint64; + + for (i = 0; i < 32; i++) + data[i] = i * 8 + 7; + + printf("\n+++ libFLAC unit test: bitreader\n\n"); + + /* + * test new -> delete + */ + printf("testing new... "); + br = FLAC__bitreader_new(); + if(0 == br) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitreader_delete(br); + printf("OK\n"); + + /* + * test new -> init -> delete + */ + printf("testing new... "); + br = FLAC__bitreader_new(); + if(0 == br) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing init... "); + if(!FLAC__bitreader_init(br, read_callback, data)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitreader_delete(br); + printf("OK\n"); + + /* + * test new -> init -> clear -> delete + */ + printf("testing new... "); + br = FLAC__bitreader_new(); + if(0 == br) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing init... "); + if(!FLAC__bitreader_init(br, read_callback, data)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing clear... "); + if(!FLAC__bitreader_clear(br)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitreader_delete(br); + printf("OK\n"); + + /* + * test normal usage + */ + printf("testing new... "); + br = FLAC__bitreader_new(); + if(0 == br) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing init... "); + if(!FLAC__bitreader_init(br, read_callback, data)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing clear... "); + if(!FLAC__bitreader_clear(br)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + words = bits = 0; + + printf("capacity = %u\n", br->capacity); + + printf("testing raw reads... "); + ok = + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 10) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 4) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 4) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) && + FLAC__bitreader_read_raw_uint64(br, &val_uint64, 64) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 12) + ; + if(!ok) { + printf("FAILED\n"); + FLAC__bitreader_dump(br, stdout); + return false; + } + /* we read 152 bits (=19 bytes) from the bitreader */ + words = 152 / FLAC__BITS_PER_WORD; + bits = 152 - words*FLAC__BITS_PER_WORD; + + if(br->consumed_words != words) { + printf("FAILED word count %u != %u\n", br->consumed_words, words); + FLAC__bitreader_dump(br, stdout); + return false; + } + if(br->consumed_bits != bits) { + printf("FAILED bit count %u != %u\n", br->consumed_bits, bits); + FLAC__bitreader_dump(br, stdout); + return false; + } + crc = FLAC__bitreader_get_read_crc16(br); + if(crc != expected_crcs[0]) { + printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[0]); + FLAC__bitreader_dump(br, stdout); + return false; + } + printf("OK\n"); + FLAC__bitreader_dump(br, stdout); + + printf("testing CRC reset... "); + FLAC__bitreader_clear(br); + FLAC__bitreader_reset_read_crc16(br, 0xFFFF); + crc = FLAC__bitreader_get_read_crc16(br); + if(crc != 0xFFFF) { + printf("FAILED reported CRC 0x%04x does not match expected 0xFFFF\n", crc); + FLAC__bitreader_dump(br, stdout); + return false; + } + FLAC__bitreader_reset_read_crc16(br, 0); + crc = FLAC__bitreader_get_read_crc16(br); + if(crc != 0) { + printf("FAILED reported CRC 0x%04x does not match expected 0x0000\n", crc); + FLAC__bitreader_dump(br, stdout); + return false; + } + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 16); + FLAC__bitreader_reset_read_crc16(br, 0); + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32); + crc = FLAC__bitreader_get_read_crc16(br); + if(crc != expected_crcs[1]) { + printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[1]); + FLAC__bitreader_dump(br, stdout); + return false; + } + printf("OK\n"); + + printf("testing unaligned < 32 bit reads... "); + FLAC__bitreader_clear(br); + FLAC__bitreader_skip_bits_no_crc(br, 8); + FLAC__bitreader_reset_read_crc16(br, 0); + ok = + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) + ; + if(!ok) { + printf("FAILED\n"); + FLAC__bitreader_dump(br, stdout); + return false; + } + crc = FLAC__bitreader_get_read_crc16(br); + if(crc != expected_crcs[2]) { + printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[2]); + FLAC__bitreader_dump(br, stdout); + return false; + } + printf("OK\n"); + FLAC__bitreader_dump(br, stdout); + + printf("testing unaligned < 64 bit reads... "); + FLAC__bitreader_clear(br); + FLAC__bitreader_skip_bits_no_crc(br, 8); + FLAC__bitreader_reset_read_crc16(br, 0); + ok = + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) && + FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32) + ; + if(!ok) { + printf("FAILED\n"); + FLAC__bitreader_dump(br, stdout); + return false; + } + crc = FLAC__bitreader_get_read_crc16(br); + if(crc != expected_crcs[3]) { + printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[3]); + FLAC__bitreader_dump(br, stdout); + return false; + } + printf("OK\n"); + FLAC__bitreader_dump(br, stdout); + + printf("testing free... "); + FLAC__bitreader_free(br); + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitreader_delete(br); + printf("OK\n"); + + printf("\nPASSED!\n"); + return true; +} + +/*----------------------------------------------------------------------------*/ + +static FLAC__bool read_callback(FLAC__byte buffer[], size_t *bytes, void *data) +{ + if (*bytes > 32) + *bytes = 32; + + memcpy(buffer, data, *bytes); + + return true; +} diff --git a/vendor/flac/src/test_libFLAC/bitreader.h b/vendor/flac/src/test_libFLAC/bitreader.h new file mode 100644 index 0000000..f497acf --- /dev/null +++ b/vendor/flac/src/test_libFLAC/bitreader.h @@ -0,0 +1,27 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_BITREADER_H +#define FLAC__TEST_LIBFLAC_BITREADER_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_bitreader(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/bitwriter.c b/vendor/flac/src/test_libFLAC/bitwriter.c new file mode 100644 index 0000000..0aafff2 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/bitwriter.c @@ -0,0 +1,688 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/assert.h" +#include "share/compat.h" +#include "private/bitwriter.h" /* from the libFLAC private include area */ +#include "bitwriter.h" +#include +#include /* for memcmp() */ + +/* + * WATCHOUT! Since FLAC__BitWriter is a private structure, we use a copy of + * the definition here to get at the internals. Make sure this is kept up + * to date with what is in ../libFLAC/bitwriter.c + */ +#if (ENABLE_64_BIT_WORDS == 0) + +typedef FLAC__uint32 bwword; +#define FLAC__BYTES_PER_WORD 4 +#define FLAC__BITS_PER_WORD 32 +#define PRI_BWWORD "08x" + +#else + +typedef FLAC__uint64 bwword; +#define FLAC__BYTES_PER_WORD 8 +#define FLAC__BITS_PER_WORD 64 +#define PRI_BWWORD "016" PRIx64 + +#endif + +struct FLAC__BitWriter { + bwword *buffer; + bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */ + uint32_t capacity; /* capacity of buffer in words */ + uint32_t words; /* # of complete words in buffer */ + uint32_t bits; /* # of used bits in accum */ +}; + +#define WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD) +#define TOTAL_BITS(bw) (WORDS_TO_BITS((bw)->words) + (bw)->bits) + +static void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out) +{ + uint32_t i, j; + if(bw == 0) { + fprintf(out, "bitwriter is NULL\n"); + } + else { + fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, TOTAL_BITS(bw)); + + for(i = 0; i < bw->words; i++) { + fprintf(out, "%08X: ", i); + for(j = 0; j < FLAC__BITS_PER_WORD; j++) + fprintf(out, "%01d", bw->buffer[i] & ((bwword)1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0); + fprintf(out, "\n"); + } + if(bw->bits > 0) { + fprintf(out, "%08X: ", i); + for(j = 0; j < bw->bits; j++) + fprintf(out, "%01d", bw->accum & ((bwword)1 << (bw->bits-j-1)) ? 1:0); + fprintf(out, "\n"); + } + } +} + +FLAC__bool test_bitwriter(void) +{ + FLAC__BitWriter *bw; + FLAC__bool ok; + uint32_t i, j; +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + static bwword test_pattern1[5] = { 0xaaf0aabe, 0xaaaaaaa8, 0x300aaaaa, 0xaaadeadb, 0x00eeface }; +#else + static bwword test_pattern1[5] = { 0xbeaaf0aa, 0xa8aaaaaa, 0xaaaa0a30, 0xdbeaadaa, 0x00eeface }; +#endif +#elif FLAC__BYTES_PER_WORD == 8 +#if WORDS_BIGENDIAN + static bwword test_pattern1[3] = { FLAC__U64L(0xaaf0aabeaaaaaaa8), FLAC__U64L(0x300aaaaaaaadeadb), FLAC__U64L(0x0000000000eeface) }; +#else + static bwword test_pattern1[3] = { FLAC__U64L(0xa8aaaaaabeaaf0aa), FLAC__U64L(0xdbeaadaaaaaa0a30), FLAC__U64L(0x0000000000eeface) }; +#endif +#else +#error FLAC__BYTES_PER_WORD is neither 4 nor 8 -- not implemented +#endif + uint32_t words, bits; /* what we think bw->words and bw->bits should be */ + + printf("\n+++ libFLAC unit test: bitwriter\n\n"); + + /* + * test new -> delete + */ + printf("testing new... "); + bw = FLAC__bitwriter_new(); + if(0 == bw) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitwriter_delete(bw); + printf("OK\n"); + + /* + * test new -> init -> delete + */ + printf("testing new... "); + bw = FLAC__bitwriter_new(); + if(0 == bw) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing init... "); + if(!FLAC__bitwriter_init(bw)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitwriter_delete(bw); + printf("OK\n"); + + /* + * test new -> init -> clear -> delete + */ + printf("testing new... "); + bw = FLAC__bitwriter_new(); + if(0 == bw) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing init... "); + if(!FLAC__bitwriter_init(bw)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing clear... "); + FLAC__bitwriter_clear(bw); + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitwriter_delete(bw); + printf("OK\n"); + + /* + * test normal usage + */ + printf("testing new... "); + bw = FLAC__bitwriter_new(); + if(0 == bw) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing init... "); + if(!FLAC__bitwriter_init(bw)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing clear... "); + FLAC__bitwriter_clear(bw); + printf("OK\n"); + + words = bits = 0; + + printf("capacity = %u\n", bw->capacity); + + printf("testing zeroes, raw_uint32*... "); + ok = + FLAC__bitwriter_write_raw_uint32(bw, 0x1, 1) && + FLAC__bitwriter_write_raw_uint32(bw, 0x1, 2) && + FLAC__bitwriter_write_raw_uint32(bw, 0xa, 5) && + FLAC__bitwriter_write_raw_uint32(bw, 0xf0, 8) && + FLAC__bitwriter_write_raw_uint32(bw, 0x2aa, 10) && + FLAC__bitwriter_write_raw_uint32(bw, 0xf, 4) && + FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32) && + FLAC__bitwriter_write_zeroes(bw, 4) && + FLAC__bitwriter_write_raw_uint32(bw, 0x3, 2) && + FLAC__bitwriter_write_zeroes(bw, 8) && + FLAC__bitwriter_write_raw_uint64(bw, FLAC__U64L(0xaaaaaaaadeadbeef), 64) && + FLAC__bitwriter_write_raw_uint32(bw, 0xace, 12) + ; + if(!ok) { + printf("FAILED\n"); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + /* we wrote 152 bits (=19 bytes) to the bitwriter */ + words = 152 / FLAC__BITS_PER_WORD; + bits = 152 - words*FLAC__BITS_PER_WORD; + + if(bw->words != words) { + printf("FAILED word count %u != %u\n", bw->words, words); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + if(bw->bits != bits) { + printf("FAILED bit count %u != %u\n", bw->bits, bits); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) { + printf("FAILED pattern match (buffer)\n"); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + if((bw->accum & 0x00ffffff) != test_pattern1[words]) { + printf("FAILED pattern match (bw->accum=%" PRI_BWWORD " != %" PRI_BWWORD ")\n", bw->accum&0x00ffffff, test_pattern1[words]); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + printf("OK\n"); + FLAC__bitwriter_dump(bw, stdout); + + printf("testing raw_uint32 some more... "); + ok = FLAC__bitwriter_write_raw_uint32(bw, 0x3d, 6); + if(!ok) { + printf("FAILED\n"); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + bits += 6; + test_pattern1[words] <<= 6; + test_pattern1[words] |= 0x3d; + if(bw->words != words) { + printf("FAILED word count %u != %u\n", bw->words, words); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + if(bw->bits != bits) { + printf("FAILED bit count %u != %u\n", bw->bits, bits); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) { + printf("FAILED pattern match (buffer)\n"); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + if((bw->accum & 0x3fffffff) != test_pattern1[words]) { + printf("FAILED pattern match (bw->accum=%" PRI_BWWORD " != %" PRI_BWWORD ")\n", bw->accum&0x3fffffff, test_pattern1[words]); + FLAC__bitwriter_dump(bw, stdout); + return false; + } + printf("OK\n"); + FLAC__bitwriter_dump(bw, stdout); + + printf("testing utf8_uint32(0x00000000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x00000000); + ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x0000007F)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x0000007F); + ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x00000080)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x00000080); + ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x000007FF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x000007FF); + ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x00000800)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x00000800); + ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x0000FFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x0000FFFF); + ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x00010000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x00010000); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080; +#else + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF0908080; +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x001FFFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x001FFFFF); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF; +#else + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF7BFBFBF; +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x00200000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x00200000); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80; +#else + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xF888808080); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x03FFFFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x03FFFFFF); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF; +#else + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xFBBFBFBFBF); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x04000000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x04000000); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080; +#else + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFC8480808080); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint32(0x7FFFFFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint32(bw, 0x7FFFFFFF); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF; +#else + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFDBFBFBFBFBF); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000000000000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000000000)); + ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x000000000000007F)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x000000000000007F)); + ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000000000080)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000000080)); + ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x00000000000007FF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x00000000000007FF)); + ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000000000800)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000000800)); + ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x000000000000FFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x000000000000FFFF)); + ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000000010000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000010000)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080; +#else + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF0908080; +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x00000000001FFFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x00000000001FFFFF)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF; +#else + ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF7BFBFBF; +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000000200000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000000200000)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80; +#else + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xF888808080); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000003FFFFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000003FFFFFF)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF; +#else + ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xFBBFBFBFBF); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000004000000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000004000000)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080; +#else + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFC8480808080); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x000000007FFFFFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x000000007FFFFFFF)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF; +#else + ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFDBFBFBFBFBF); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000080000000)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000080000000)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFE828080 && (bw->accum & 0xffffff) == 0x808080; +#else + ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0x808082FE && (bw->accum & 0xffffff) == 0x808080; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 56 && (bw->accum & FLAC__U64L(0xffffffffffffff)) == FLAC__U64L(0xFE828080808080); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing utf8_uint64(0x0000000FFFFFFFFF)... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000FFFFFFFFF)); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFEBFBFBF && (bw->accum & 0xffffff) == 0xBFBFBF; +#else + ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xBFBFBFFE && (bw->accum & 0xffffff) == 0xBFBFBF; +#endif +#elif FLAC__BYTES_PER_WORD == 8 + ok = TOTAL_BITS(bw) == 56 && (bw->accum & FLAC__U64L(0xffffffffffffff)) == FLAC__U64L(0xFEBFBFBFBFBFBF); +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + + printf("testing grow... "); + FLAC__bitwriter_clear(bw); + FLAC__bitwriter_write_raw_uint32(bw, 0x5, 4); + j = bw->capacity; + for(i = 0; i < j; i++) + FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32); +#if FLAC__BYTES_PER_WORD == 4 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0x5aaaaaaa && (bw->accum & 0xf) == 0xa; +#else + ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0xaaaaaa5a && (bw->accum & 0xf) == 0xa; +#endif +#elif FLAC__BYTES_PER_WORD == 8 +#if WORDS_BIGENDIAN + ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == FLAC__U64L(0x5aaaaaaaaaaaaaaa) && (bw->accum & 0xf) == 0xa; +#else + ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == FLAC__U64L(0xaaaaaaaaaaaaaa5a) && (bw->accum & 0xf) == 0xa; +#endif +#endif + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitwriter_dump(bw, stdout); + return false; + } + printf("capacity = %u\n", bw->capacity); + + printf("testing free... "); + FLAC__bitwriter_free(bw); + printf("OK\n"); + + printf("testing delete... "); + FLAC__bitwriter_delete(bw); + printf("OK\n"); + + printf("\nPASSED!\n"); + return true; +} diff --git a/vendor/flac/src/test_libFLAC/bitwriter.h b/vendor/flac/src/test_libFLAC/bitwriter.h new file mode 100644 index 0000000..9b6a824 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/bitwriter.h @@ -0,0 +1,27 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_BITBUFFER_H +#define FLAC__TEST_LIBFLAC_BITBUFFER_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_bitwriter(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/crc.c b/vendor/flac/src/test_libFLAC/crc.c new file mode 100644 index 0000000..8b87671 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/crc.c @@ -0,0 +1,274 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2014-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "FLAC/assert.h" +#include "share/compat.h" +#include "private/crc.h" +#include "crc.h" + +static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc); +static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc); + +static FLAC__bool test_crc8(const FLAC__byte *data, size_t size); +static FLAC__bool test_crc16(const FLAC__byte *data, size_t size); +static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size); +static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size); +static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size); + +#define DATA_SIZE 32768 + +FLAC__bool test_crc(void) +{ + uint32_t i; + FLAC__byte data[DATA_SIZE] = { 0 }; + + /* Initialize data reproducibly with pseudo-random values. */ + for (i = 1; i < DATA_SIZE; i++) + data[i] = crc8_update_ref(i % 256, data[i - 1]); + + printf("\n+++ libFLAC unit test: crc\n\n"); + + if (! test_crc8(data, DATA_SIZE)) + return false; + + if (! test_crc16(data, DATA_SIZE)) + return false; + + if (! test_crc16_update(data, DATA_SIZE)) + return false; + + if (! test_crc16_32bit_words((FLAC__uint32 *)data, DATA_SIZE / 4)) + return false; + + if (! test_crc16_64bit_words((FLAC__uint64 *)data, DATA_SIZE / 8)) + return false; + + printf("\nPASSED!\n"); + return true; +} + +/*----------------------------------------------------------------------------*/ + +/* Reference implementations of CRC-8 and CRC-16 to check against. */ + +#define CRC8_POLYNOMIAL 0x07 + +static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc) +{ + uint32_t i; + + crc ^= byte; + + for (i = 0; i < 8; i++) { + crc = (crc << 1) ^ ((crc >> 7) ? CRC8_POLYNOMIAL : 0); + } + + return crc; +} + +#define CRC16_POLYNOMIAL 0x8005 + +static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc) +{ + uint32_t i; + + crc ^= byte << 8; + + for (i = 0; i < 8; i++) { + crc = (crc << 1) ^ ((crc >> 15) ? CRC16_POLYNOMIAL : 0); + } + + return crc; +} + +/*----------------------------------------------------------------------------*/ + +static FLAC__bool test_crc8(const FLAC__byte *data, size_t size) +{ + uint32_t i; + FLAC__uint8 crc0,crc1; + + printf("testing FLAC__crc8 ... "); + + crc0 = 0; + crc1 = FLAC__crc8(data, 0); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc8 returned non-zero CRC for zero bytes of data\n"); + return false; + } + + for (i = 0; i < size; i++) { + crc0 = crc8_update_ref(data[i], crc0); + crc1 = FLAC__crc8(data, i + 1); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc8 result did not match reference CRC for %u bytes of test data\n", i + 1); + return false; + } + } + + printf("OK\n"); + + return true; +} + +static FLAC__bool test_crc16(const FLAC__byte *data, size_t size) +{ + uint32_t i; + FLAC__uint16 crc0,crc1; + + printf("testing FLAC__crc16 ... "); + + crc0 = 0; + crc1 = FLAC__crc16(data, 0); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc16 returned non-zero CRC for zero bytes of data\n"); + return false; + } + + for (i = 0; i < size; i++) { + crc0 = crc16_update_ref(data[i], crc0); + crc1 = FLAC__crc16(data, i + 1); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc16 result did not match reference CRC for %u bytes of test data\n", i + 1); + return false; + } + } + + printf("OK\n"); + + return true; +} + +static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size) +{ + uint32_t i; + FLAC__uint16 crc0,crc1; + + printf("testing FLAC__CRC16_UPDATE macro ... "); + + crc0 = 0; + crc1 = 0; + + for (i = 0; i < size; i++) { + crc0 = crc16_update_ref(data[i], crc0); + crc1 = FLAC__CRC16_UPDATE(data[i], crc1); + + if (crc1 != crc0) { + printf("FAILED, FLAC__CRC16_UPDATE result did not match reference CRC after %u bytes of test data\n", i + 1); + return false; + } + } + + printf("OK\n"); + + return true; +} + +static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size) +{ + uint32_t n,i,k; + FLAC__uint16 crc0,crc1; + + for (n = 1; n <= 16; n++) { + printf("testing FLAC__crc16_update_words32 (length=%i) ... ", n); + + crc0 = 0; + crc1 = 0; + + for (i = 0; i <= size - n; i += n) { + for (k = 0; k < n; k++) { + crc0 = crc16_update_ref( words[i + k] >> 24, crc0); + crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0); + crc0 = crc16_update_ref((words[i + k] >> 8) & 0xFF, crc0); + crc0 = crc16_update_ref( words[i + k] & 0xFF, crc0); + } + + crc1 = FLAC__crc16_update_words32(words + i, n, crc1); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc16_update_words32 result did not match reference CRC after %u words of test data\n", i + n); + return false; + } + } + + crc1 = FLAC__crc16_update_words32(words, 0, crc1); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc16_update_words32 called with zero bytes changed CRC value\n"); + return false; + } + + printf("OK\n"); + } + + return true; +} + +static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size) +{ + uint32_t n,i,k; + FLAC__uint16 crc0,crc1; + + for (n = 1; n <= 16; n++) { + printf("testing FLAC__crc16_update_words64 (length=%i) ... ", n); + + crc0 = 0; + crc1 = 0; + + for (i = 0; i <= size - n; i += n) { + for (k = 0; k < n; k++) { + crc0 = crc16_update_ref( words[i + k] >> 56, crc0); + crc0 = crc16_update_ref((words[i + k] >> 48) & 0xFF, crc0); + crc0 = crc16_update_ref((words[i + k] >> 40) & 0xFF, crc0); + crc0 = crc16_update_ref((words[i + k] >> 32) & 0xFF, crc0); + crc0 = crc16_update_ref((words[i + k] >> 24) & 0xFF, crc0); + crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0); + crc0 = crc16_update_ref((words[i + k] >> 8) & 0xFF, crc0); + crc0 = crc16_update_ref( words[i + k] & 0xFF, crc0); + } + + crc1 = FLAC__crc16_update_words64(words + i, n, crc1); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc16_update_words64 result did not match reference CRC after %u words of test data\n", i + n); + return false; + } + } + + crc1 = FLAC__crc16_update_words64(words, 0, crc1); + + if (crc1 != crc0) { + printf("FAILED, FLAC__crc16_update_words64 called with zero bytes changed CRC value\n"); + return false; + } + + printf("OK\n"); + } + + return true; +} diff --git a/vendor/flac/src/test_libFLAC/crc.h b/vendor/flac/src/test_libFLAC/crc.h new file mode 100644 index 0000000..11523cd --- /dev/null +++ b/vendor/flac/src/test_libFLAC/crc.h @@ -0,0 +1,26 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2014-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_CRC_H +#define FLAC__TEST_LIBFLAC_CRC_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_crc(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/decoders.c b/vendor/flac/src/test_libFLAC/decoders.c new file mode 100644 index 0000000..ae114ce --- /dev/null +++ b/vendor/flac/src/test_libFLAC/decoders.c @@ -0,0 +1,1054 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "decoders.h" +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "share/safe_str.h" +#include "test_libs_common/file_utils_flac.h" +#include "test_libs_common/metadata_utils.h" + +typedef enum { + LAYER_STREAM = 0, /* FLAC__stream_decoder_init_[ogg_]stream() without seeking */ + LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_[ogg_]stream() with seeking */ + LAYER_FILE, /* FLAC__stream_decoder_init_[ogg_]FILE() */ + LAYER_FILENAME /* FLAC__stream_decoder_init_[ogg_]file() */ +} Layer; + +static const char * const LayerString[] = { + "Stream", + "Seekable Stream", + "FILE*", + "Filename" +}; + +typedef struct { + Layer layer; + FILE *file; + char filename[512]; + uint32_t current_metadata_number; + FLAC__bool ignore_errors; + FLAC__bool error_occurred; +} StreamDecoderClientData; + +static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static FLAC__StreamMetadata *expected_metadata_sequence_[9]; +static uint32_t num_expected_; +static FLAC__off_t flacfilesize_; + +static const char *flacfilename(FLAC__bool is_ogg) +{ + return is_ogg? "metadata.oga" : "metadata.flac"; +} + +static FLAC__bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder) +{ + FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder); + + if(msg) + printf("FAILED, %s", msg); + else + printf("FAILED"); + + printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamDecoderStateString[state]); + + return false; +} + +static void open_test_file(StreamDecoderClientData * pdcd, int is_ogg, const char * mode) +{ + pdcd->file = flac_fopen(flacfilename(is_ogg), mode); + safe_strncpy(pdcd->filename, flacfilename(is_ogg), sizeof (pdcd->filename)); +} + +static void init_metadata_blocks_(void) +{ + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static void free_metadata_blocks_(void) +{ + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static FLAC__bool generate_file_(FLAC__bool is_ogg) +{ + printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":""); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + /* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */ + + if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_)) + return die_("creating the encoded file"); + + return true; +} + +static FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + const size_t requested_bytes = *bytes; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in read callback is NULL\n"); + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + + if(feof(dcd->file)) { + *bytes = 0; + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + else if(requested_bytes > 0) { + *bytes = fread(buffer, 1, requested_bytes, dcd->file); + if(*bytes == 0) { + if(feof(dcd->file)) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + else { + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ +} + +static FLAC__StreamDecoderSeekStatus stream_decoder_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in seek callback is NULL\n"); + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + + if(fseeko(dcd->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) { + dcd->error_occurred = true; + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +static FLAC__StreamDecoderTellStatus stream_decoder_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + FLAC__off_t offset; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in tell callback is NULL\n"); + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + + offset = ftello(dcd->file); + *absolute_byte_offset = (FLAC__uint64)offset; + + if(offset < 0) { + dcd->error_occurred = true; + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + } + + return FLAC__STREAM_DECODER_TELL_STATUS_OK; +} + +static FLAC__StreamDecoderLengthStatus stream_decoder_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in length callback is NULL\n"); + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + + *stream_length = (FLAC__uint64)flacfilesize_; + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; +} + +static FLAC__bool stream_decoder_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in eof callback is NULL\n"); + return true; + } + + if(dcd->error_occurred) + return true; + + return feof(dcd->file); +} + +static FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder, (void)buffer; + + if(0 == dcd) { + printf("ERROR: client_data in write callback is NULL\n"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + if( + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) || + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0) + ) { + printf("content... "); + fflush(stdout); + } + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in metadata callback is NULL\n"); + return; + } + + if(dcd->error_occurred) + return; + + if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) { + printf ("%u ('%c%c%c%c')... ", dcd->current_metadata_number, metadata->data.application.id [0], metadata->data.application.id [1], metadata->data.application.id [2], metadata->data.application.id [3]); + } + else { + printf("%u... ", dcd->current_metadata_number); + } + fflush(stdout); + + + if(dcd->current_metadata_number >= num_expected_) { + (void)die_("got more metadata blocks than expected"); + dcd->error_occurred = true; + } + else { + if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) { + (void)die_("metadata block mismatch"); + dcd->error_occurred = true; + } + } + dcd->current_metadata_number++; +} + +static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in error callback is NULL\n"); + return; + } + + if(!dcd->ignore_errors) { + printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, FLAC__StreamDecoderErrorStatusString[status]); + dcd->error_occurred = true; + } +} + +static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg) +{ + FLAC__StreamDecoderInitStatus init_status; + + if(!FLAC__stream_decoder_set_md5_checking(decoder, true)) + return die_s_("at FLAC__stream_decoder_set_md5_checking(), returned false", decoder); + + /* for FLAC__stream_encoder_init_FILE(), the FLAC__stream_encoder_finish() closes the file so we have to keep re-opening: */ + if(dcd->layer == LAYER_FILE) { + printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); + open_test_file(dcd, is_ogg, "rb"); + if(0 == dcd->file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + } + + switch(dcd->layer) { + case LAYER_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) + ; + break; + case LAYER_SEEKABLE_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd); + break; + case LAYER_FILE: + printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd); + break; + case LAYER_FILENAME: + printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) : + FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd); + break; + default: + die_("internal error 000"); + return false; + } + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, decoder); + printf("OK\n"); + + dcd->current_metadata_number = 0; + + if(dcd->layer < LAYER_FILE && fseeko(dcd->file, 0, SEEK_SET) < 0) { + printf("FAILED rewinding input, errno = %d\n", errno); + return false; + } + + printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_finish()... "); + if(!FLAC__stream_decoder_finish(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + return true; +} + +static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg) +{ + FLAC__StreamDecoder *decoder; + FLAC__StreamDecoderInitStatus init_status; + FLAC__StreamDecoderState state; + StreamDecoderClientData decoder_client_data; + FLAC__bool expect; + + decoder_client_data.layer = layer; + + printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC"); + + printf("testing FLAC__stream_decoder_new()... "); + decoder = FLAC__stream_decoder_new(); + if(0 == decoder) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_delete()... "); + FLAC__stream_decoder_delete(decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_new()... "); + decoder = FLAC__stream_decoder_new(); + if(0 == decoder) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + switch(layer) { + case LAYER_STREAM: + case LAYER_SEEKABLE_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) : + FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case LAYER_FILE: + printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) : + FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0); + break; + case LAYER_FILENAME: + printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) : + FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0); + break; + default: + die_("internal error 003"); + return false; + } + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS) + return die_s_(0, decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_delete()... "); + FLAC__stream_decoder_delete(decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + + printf("testing FLAC__stream_decoder_new()... "); + decoder = FLAC__stream_decoder_new(); + if(0 == decoder) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + if(is_ogg) { + printf("testing FLAC__stream_decoder_set_ogg_serial_number()... "); + if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number)) + return die_s_("returned false", decoder); + printf("OK\n"); + } + + printf("testing FLAC__stream_decoder_set_md5_checking()... "); + if(!FLAC__stream_decoder_set_md5_checking(decoder, true)) + return die_s_("returned false", decoder); + printf("OK\n"); + + if(layer < LAYER_FILENAME) { + printf("opening %sFLAC file... ", is_ogg? "Ogg ":""); + open_test_file(&decoder_client_data, is_ogg, "rb"); + if(0 == decoder_client_data.file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + } + + switch(layer) { + case LAYER_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + case LAYER_SEEKABLE_STREAM: + printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + case LAYER_FILE: + printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + case LAYER_FILENAME: + printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data); + break; + default: + die_("internal error 009"); + return false; + } + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_(0, decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_state()... "); + state = FLAC__stream_decoder_get_state(decoder); + printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]); + + decoder_client_data.current_metadata_number = 0; + decoder_client_data.ignore_errors = false; + decoder_client_data.error_occurred = false; + + printf("testing FLAC__stream_decoder_get_md5_checking()... "); + if(!FLAC__stream_decoder_get_md5_checking(decoder)) { + printf("FAILED, returned false, expected true\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... "); + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_process_single()... "); + if(!FLAC__stream_decoder_process_single(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_skip_single_frame()... "); + if(!FLAC__stream_decoder_skip_single_frame(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + if(layer < LAYER_FILE) { + printf("testing FLAC__stream_decoder_flush()... "); + if(!FLAC__stream_decoder_flush(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + decoder_client_data.ignore_errors = true; + printf("testing FLAC__stream_decoder_process_single()... "); + if(!FLAC__stream_decoder_process_single(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + decoder_client_data.ignore_errors = false; + } + + expect = (layer != LAYER_STREAM); + printf("testing FLAC__stream_decoder_seek_absolute()... "); + if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) + return die_s_(expect? "returned false" : "returned true", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + expect = (layer != LAYER_STREAM); + printf("testing FLAC__stream_decoder_seek_absolute()... "); + if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect) + return die_s_(expect? "returned false" : "returned true", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_channels()... "); + { + uint32_t channels = FLAC__stream_decoder_get_channels(decoder); + if(channels != streaminfo_.data.stream_info.channels) { + printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels); + return false; + } + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_bits_per_sample()... "); + { + uint32_t bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder); + if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) { + printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample); + return false; + } + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_sample_rate()... "); + { + uint32_t sample_rate = FLAC__stream_decoder_get_sample_rate(decoder); + if(sample_rate != streaminfo_.data.stream_info.sample_rate) { + printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate); + return false; + } + } + printf("OK\n"); + + printf("testing FLAC__stream_decoder_get_blocksize()... "); + { + uint32_t blocksize = FLAC__stream_decoder_get_blocksize(decoder); + /* value could be anything since we're at the last block, so accept any reasonable answer */ + printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED"); + if(blocksize == 0) + return false; + } + + printf("testing FLAC__stream_decoder_get_channel_assignment()... "); + { + FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder); + printf("returned %u (%s)... OK\n", (uint32_t)ca, FLAC__ChannelAssignmentString[ca]); + } + + if(layer < LAYER_FILE) { + printf("testing FLAC__stream_decoder_reset()... "); + if(!FLAC__stream_decoder_reset(decoder)) { + state = FLAC__stream_decoder_get_state(decoder); + printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]); + return false; + } + printf("OK\n"); + + if(layer == LAYER_STREAM) { + /* after a reset() we have to rewind the input ourselves */ + printf("rewinding input... "); + if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) { + printf("FAILED, errno = %d\n", errno); + return false; + } + printf("OK\n"); + } + + decoder_client_data.current_metadata_number = 0; + + printf("testing FLAC__stream_decoder_process_until_end_of_stream()... "); + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + } + + printf("testing FLAC__stream_decoder_finish()... "); + if(!FLAC__stream_decoder_finish(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + /* + * respond all + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore VORBIS_COMMENT + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... "); + if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + if(!is_ogg) /* encoder removes seektable for ogg */ + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application2_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION id of app#1 & app#2 + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #2)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond VORBIS_COMMENT + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... "); + if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION id of app#1 & app#2 + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #2)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * respond all, ignore APPLICATION, respond APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_respond_all()... "); + if(!FLAC__stream_decoder_set_metadata_respond_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */ + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + else { + expected_metadata_sequence_[num_expected_++] = &streaminfo_; + expected_metadata_sequence_[num_expected_++] = &padding_; + expected_metadata_sequence_[num_expected_++] = &seektable_; + expected_metadata_sequence_[num_expected_++] = &application1_; + expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; + expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; + expected_metadata_sequence_[num_expected_++] = &unknown_; + } + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + /* + * ignore all, respond APPLICATION, ignore APPLICATION id of app#1 + */ + + printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... "); + if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... "); + if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION)) + return die_s_("returned false", decoder); + printf("OK\n"); + + printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... "); + if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id)) + return die_s_("returned false", decoder); + printf("OK\n"); + + num_expected_ = 0; + expected_metadata_sequence_[num_expected_++] = &application2_; + + if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg)) + return false; + + if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */ + fclose(decoder_client_data.file); + + printf("testing FLAC__stream_decoder_delete()... "); + FLAC__stream_decoder_delete(decoder); + printf("OK\n"); + + printf("\nPASSED!\n"); + + return true; +} + +FLAC__bool test_decoders(void) +{ + FLAC__bool is_ogg = false; + + while(1) { + init_metadata_blocks_(); + + if(!generate_file_(is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_STREAM, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_FILE, is_ogg)) + return false; + + if(!test_stream_decoder(LAYER_FILENAME, is_ogg)) + return false; + + (void) grabbag__file_remove_file(flacfilename(is_ogg)); + + free_metadata_blocks_(); + + if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg) + break; + is_ogg = true; + } + + return true; +} diff --git a/vendor/flac/src/test_libFLAC/decoders.h b/vendor/flac/src/test_libFLAC/decoders.h new file mode 100644 index 0000000..431eb17 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/decoders.h @@ -0,0 +1,27 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_DECODERS_H +#define FLAC__TEST_LIBFLAC_DECODERS_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_decoders(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/encoders.c b/vendor/flac/src/test_libFLAC/encoders.c new file mode 100644 index 0000000..d3fd39d --- /dev/null +++ b/vendor/flac/src/test_libFLAC/encoders.c @@ -0,0 +1,530 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "encoders.h" +#include "FLAC/assert.h" +#include "FLAC/stream_encoder.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "test_libs_common/file_utils_flac.h" +#include "test_libs_common/metadata_utils.h" + +typedef enum { + LAYER_STREAM = 0, /* FLAC__stream_encoder_init_[ogg_]stream() without seeking */ + LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_[ogg_]stream() with seeking */ + LAYER_FILE, /* FLAC__stream_encoder_init_[ogg_]FILE() */ + LAYER_FILENAME /* FLAC__stream_encoder_init_[ogg_]file() */ +} Layer; + +static const char * const LayerString[] = { + "Stream", + "Seekable Stream", + "FILE*", + "Filename" +}; + +static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ }; +static const uint32_t num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]); + +static const char *flacfilename(FLAC__bool is_ogg) +{ + return is_ogg? "metadata.oga" : "metadata.flac"; +} + +static FLAC__bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static FLAC__bool die_s_(const char *msg, const FLAC__StreamEncoder *encoder) +{ + FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(encoder); + + if(msg) + printf("FAILED, %s", msg); + else + printf("FAILED"); + + printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamEncoderStateString[state]); + if(state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) { + FLAC__StreamDecoderState dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder); + printf(" verify decoder state = %u (%s)\n", (uint32_t)dstate, FLAC__StreamDecoderStateString[dstate]); + } + + return false; +} + +static void init_metadata_blocks_(void) +{ + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static void free_metadata_blocks_(void) +{ + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); +} + +static FLAC__StreamEncoderReadStatus stream_encoder_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + FILE *f = (FILE*)client_data; + (void)encoder; + if(*bytes > 0) { + *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, f); + if(ferror(f)) + return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + else if(*bytes == 0) + return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; + } + else + return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; +} + +static FLAC__StreamEncoderWriteStatus stream_encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data) +{ + FILE *f = (FILE*)client_data; + (void)encoder, (void)samples, (void)current_frame; + if(fwrite(buffer, 1, bytes, f) != bytes) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + else + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} + +static FLAC__StreamEncoderSeekStatus stream_encoder_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + FILE *f = (FILE*)client_data; + (void)encoder; + if(fseeko(f, (long)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; +} + +static FLAC__StreamEncoderTellStatus stream_encoder_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FILE *f = (FILE*)client_data; + FLAC__off_t pos; + (void)encoder; + if((pos = ftello(f)) < 0) + return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + } +} + +static void stream_encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + (void)encoder, (void)metadata, (void)client_data; +} + +static void stream_encoder_progress_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data) +{ + (void)encoder, (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate, (void)client_data; +} + +static FLAC__bool test_stream_encoder(Layer layer, FLAC__bool is_ogg) +{ + FLAC__StreamEncoder *encoder; + FLAC__StreamEncoderInitStatus init_status; + FLAC__StreamEncoderState state; + FLAC__StreamDecoderState dstate; + FILE *file = 0; + FLAC__int32 samples[1024]; + FLAC__int32 *samples_array[1]; + uint32_t i; + + samples_array[0] = samples; + + printf("\n+++ libFLAC unit test: FLAC__StreamEncoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC":"FLAC"); + + printf("testing FLAC__stream_encoder_new()... "); + encoder = FLAC__stream_encoder_new(); + if(0 == encoder) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + if(is_ogg) { + printf("testing FLAC__stream_encoder_set_ogg_serial_number()... "); + if(!FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number)) + return die_s_("returned false", encoder); + printf("OK\n"); + } + + printf("testing FLAC__stream_encoder_set_verify()... "); + if(!FLAC__stream_encoder_set_verify(encoder, true)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_streamable_subset()... "); + if(!FLAC__stream_encoder_set_streamable_subset(encoder, true)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_channels()... "); + if(!FLAC__stream_encoder_set_channels(encoder, streaminfo_.data.stream_info.channels)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_bits_per_sample()... "); + if(!FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo_.data.stream_info.bits_per_sample)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_sample_rate()... "); + if(!FLAC__stream_encoder_set_sample_rate(encoder, streaminfo_.data.stream_info.sample_rate)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_compression_level()... "); + if(!FLAC__stream_encoder_set_compression_level(encoder, (uint32_t)(-1))) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_blocksize()... "); + if(!FLAC__stream_encoder_set_blocksize(encoder, streaminfo_.data.stream_info.min_blocksize)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_do_mid_side_stereo()... "); + if(!FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_loose_mid_side_stereo()... "); + if(!FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_max_lpc_order()... "); + if(!FLAC__stream_encoder_set_max_lpc_order(encoder, 0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_qlp_coeff_precision()... "); + if(!FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_do_qlp_coeff_prec_search()... "); + if(!FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_do_escape_coding()... "); + if(!FLAC__stream_encoder_set_do_escape_coding(encoder, false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_do_exhaustive_model_search()... "); + if(!FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_min_residual_partition_order()... "); + if(!FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_max_residual_partition_order()... "); + if(!FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_rice_parameter_search_dist()... "); + if(!FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_total_samples_estimate()... "); + if(!FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo_.data.stream_info.total_samples)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_metadata()... "); + if(!FLAC__stream_encoder_set_metadata(encoder, metadata_sequence_, num_metadata_)) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_set_limit_min_bitrate()... "); + if(!FLAC__stream_encoder_set_limit_min_bitrate(encoder, true)) + return die_s_("returned false", encoder); + printf("OK\n"); + + if(layer < LAYER_FILENAME) { + printf("opening file for FLAC output... "); + file = flac_fopen(flacfilename(is_ogg), "w+b"); + if(0 == file) { + printf("ERROR (%s)\n", strerror(errno)); + return false; + } + printf("OK\n"); + } + + switch(layer) { + case LAYER_STREAM: + printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file) : + FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file); + break; + case LAYER_SEEKABLE_STREAM: + printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_encoder_init_ogg_stream(encoder, stream_encoder_read_callback_, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file) : + FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file); + break; + case LAYER_FILE: + printf("testing FLAC__stream_encoder_init_%sFILE()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_encoder_init_ogg_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0) : + FLAC__stream_encoder_init_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0); + break; + case LAYER_FILENAME: + printf("testing FLAC__stream_encoder_init_%sfile()... ", is_ogg? "ogg_":""); + init_status = is_ogg? + FLAC__stream_encoder_init_ogg_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0) : + FLAC__stream_encoder_init_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0); + break; + default: + die_("internal error 001"); + return false; + } + if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) + return die_s_(0, encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_state()... "); + state = FLAC__stream_encoder_get_state(encoder); + printf("returned state = %u (%s)... OK\n", (uint32_t)state, FLAC__StreamEncoderStateString[state]); + + printf("testing FLAC__stream_encoder_get_verify_decoder_state()... "); + dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder); + printf("returned state = %u (%s)... OK\n", (uint32_t)dstate, FLAC__StreamDecoderStateString[dstate]); + + { + FLAC__uint64 absolute_sample; + uint32_t frame_number; + uint32_t channel; + uint32_t sample; + FLAC__int32 expected; + FLAC__int32 got; + + printf("testing FLAC__stream_encoder_get_verify_decoder_error_stats()... "); + FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got); + printf("OK\n"); + } + + printf("testing FLAC__stream_encoder_get_verify()... "); + if(FLAC__stream_encoder_get_verify(encoder) != true) { + printf("FAILED, expected true, got false\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_streamable_subset()... "); + if(FLAC__stream_encoder_get_streamable_subset(encoder) != true) { + printf("FAILED, expected true, got false\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_do_mid_side_stereo()... "); + if(FLAC__stream_encoder_get_do_mid_side_stereo(encoder) != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_loose_mid_side_stereo()... "); + if(FLAC__stream_encoder_get_loose_mid_side_stereo(encoder) != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_channels()... "); + if(FLAC__stream_encoder_get_channels(encoder) != streaminfo_.data.stream_info.channels) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, FLAC__stream_encoder_get_channels(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_bits_per_sample()... "); + if(FLAC__stream_encoder_get_bits_per_sample(encoder) != streaminfo_.data.stream_info.bits_per_sample) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, FLAC__stream_encoder_get_bits_per_sample(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_sample_rate()... "); + if(FLAC__stream_encoder_get_sample_rate(encoder) != streaminfo_.data.stream_info.sample_rate) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, FLAC__stream_encoder_get_sample_rate(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_blocksize()... "); + if(FLAC__stream_encoder_get_blocksize(encoder) != streaminfo_.data.stream_info.min_blocksize) { + printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, FLAC__stream_encoder_get_blocksize(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_max_lpc_order()... "); + if(FLAC__stream_encoder_get_max_lpc_order(encoder) != 0) { + printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_max_lpc_order(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_qlp_coeff_precision()... "); + (void)FLAC__stream_encoder_get_qlp_coeff_precision(encoder); + /* we asked the encoder to auto select this so we accept anything */ + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_do_qlp_coeff_prec_search()... "); + if(FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder) != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_do_escape_coding()... "); + if(FLAC__stream_encoder_get_do_escape_coding(encoder) != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_do_exhaustive_model_search()... "); + if(FLAC__stream_encoder_get_do_exhaustive_model_search(encoder) != false) { + printf("FAILED, expected false, got true\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_min_residual_partition_order()... "); + if(FLAC__stream_encoder_get_min_residual_partition_order(encoder) != 0) { + printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_min_residual_partition_order(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_max_residual_partition_order()... "); + if(FLAC__stream_encoder_get_max_residual_partition_order(encoder) != 0) { + printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_max_residual_partition_order(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_rice_parameter_search_dist()... "); + if(FLAC__stream_encoder_get_rice_parameter_search_dist(encoder) != 0) { + printf("FAILED, expected %d, got %u\n", 0, FLAC__stream_encoder_get_rice_parameter_search_dist(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_total_samples_estimate()... "); + if(FLAC__stream_encoder_get_total_samples_estimate(encoder) != streaminfo_.data.stream_info.total_samples) { + printf("FAILED, expected %" PRIu64 ", got %" PRIu64 "\n", streaminfo_.data.stream_info.total_samples, FLAC__stream_encoder_get_total_samples_estimate(encoder)); + return false; + } + printf("OK\n"); + + printf("testing FLAC__stream_encoder_get_limit_min_bitrate()... "); + if(FLAC__stream_encoder_get_limit_min_bitrate(encoder) != true) { + printf("FAILED, expected true, got false\n"); + return false; + } + + /* init the dummy sample buffer */ + for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++) + samples[i] = i & 7; + + printf("testing FLAC__stream_encoder_process()... "); + if(!FLAC__stream_encoder_process(encoder, (const FLAC__int32 * const *)samples_array, sizeof(samples) / sizeof(FLAC__int32))) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_process_interleaved()... "); + if(!FLAC__stream_encoder_process_interleaved(encoder, samples, sizeof(samples) / sizeof(FLAC__int32))) + return die_s_("returned false", encoder); + printf("OK\n"); + + printf("testing FLAC__stream_encoder_finish()... "); + if(!FLAC__stream_encoder_finish(encoder)) + return die_s_("returned false", encoder); + printf("OK\n"); + + if(layer < LAYER_FILE) + fclose(file); + + printf("testing FLAC__stream_encoder_delete()... "); + FLAC__stream_encoder_delete(encoder); + printf("OK\n"); + + printf("\nPASSED!\n"); + + return true; +} + +FLAC__bool test_encoders(void) +{ + FLAC__bool is_ogg = false; + + while(1) { + init_metadata_blocks_(); + + if(!test_stream_encoder(LAYER_STREAM, is_ogg)) + return false; + + if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg)) + return false; + + if(!test_stream_encoder(LAYER_FILE, is_ogg)) + return false; + + if(!test_stream_encoder(LAYER_FILENAME, is_ogg)) + return false; + + (void) grabbag__file_remove_file(flacfilename(is_ogg)); + + free_metadata_blocks_(); + + if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg) + break; + is_ogg = true; + } + + return true; +} diff --git a/vendor/flac/src/test_libFLAC/encoders.h b/vendor/flac/src/test_libFLAC/encoders.h new file mode 100644 index 0000000..7bdcaf5 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/encoders.h @@ -0,0 +1,27 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_ENCODERS_H +#define FLAC__TEST_LIBFLAC_ENCODERS_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_encoders(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/endswap.c b/vendor/flac/src/test_libFLAC/endswap.c new file mode 100644 index 0000000..808f81f --- /dev/null +++ b/vendor/flac/src/test_libFLAC/endswap.c @@ -0,0 +1,111 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2014-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "share/compat.h" +#include "FLAC/assert.h" +#include "share/endswap.h" +#include "private/md5.h" +#include "endswap.h" + + +FLAC__bool test_endswap(void) +{ + int16_t i16 = 0x1234; + uint16_t u16 = 0xabcd; + int32_t i32 = 0x12345678; + uint32_t u32 = 0xabcdef01; + + union { + uint8_t bytes[4]; + uint16_t u16; + uint32_t u32; + } data; + + printf("\n+++ libFLAC unit test: endswap (%s endian host)\n\n", CPU_IS_BIG_ENDIAN ? "big" : "little"); + + printf("testing ENDSWAP_16 on int16_t ... "); + if (((int16_t) ENDSWAP_16(i16)) == i16) { + printf("\nFAILED, ENDSWAP_16(0x%04x) -> 0x%04x == 0x%04x\n", i16, ENDSWAP_16(i16), i16); + return false; + } + if (((int16_t) ENDSWAP_16(ENDSWAP_16(i16))) != i16) { + printf("\nFAILED, ENDSWAP_16(ENDSWAP_16(0x%04x)) -> 0x%04x != 0x%04x\n", i16, ENDSWAP_16(ENDSWAP_16(i16)), i16); + return false; + } + puts("OK"); + + printf("testing ENDSWAP_16 on uint16_t ... "); + if (((uint16_t) ENDSWAP_16(u16)) == u16) { + printf("\nFAILED, ENDSWAP_16(0x%04x) -> 0x%04x == 0x%04x\n", u16, ENDSWAP_16(u16), u16); + return false; + } + if (((uint16_t) ENDSWAP_16(ENDSWAP_16(u16))) != u16) { + printf("\nFAILED, ENDSWAP_16(ENDSWAP_16(0x%04x)) -> 0x%04x != 0x%04x\n", u16, ENDSWAP_16(ENDSWAP_16(u16)), u16); + return false; + } + puts("OK"); + + printf("testing ENDSWAP_32 on int32_t ... "); + if (((int32_t) ENDSWAP_32 (i32)) == i32) { + printf("\nFAILED, ENDSWAP_32(0x%08x) -> 0x%08x == 0x%08x\n", i32, (uint32_t) ENDSWAP_32 (i32), i32); + return false; + } + if (((int32_t) ENDSWAP_32 (ENDSWAP_32 (i32))) != i32) { + printf("\nFAILED, ENDSWAP_32(ENDSWAP_32(0x%08x)) -> 0x%08x != 0x%08x\n", i32, (uint32_t) ENDSWAP_32(ENDSWAP_32 (i32)), i32); + return false; + } + puts("OK"); + + printf("testing ENDSWAP_32 on uint32_t ... "); + if (((uint32_t) ENDSWAP_32(u32)) == u32) { + printf("\nFAILED, ENDSWAP_32(0x%08x) -> 0x%08x == 0x%08x\n", u32, (uint32_t) ENDSWAP_32(u32), u32); + return false; + } + if (((uint32_t) ENDSWAP_32 (ENDSWAP_32(u32))) != u32) { + printf("\nFAILED, ENDSWAP_32(ENDSWAP_32(0x%08x)) -> 0x%08x != 0%08x\n", u32, (uint32_t) ENDSWAP_32(ENDSWAP_32(u32)), u32); + return false; + } + puts("OK"); + + printf("testing H2LE_16 on uint16_t ... "); + data.u16 = H2LE_16(0x1234); + if (data.bytes [0] != 0x34 || data.bytes [1] != 0x12) { + printf("\nFAILED, H2LE_16(0x%04x) -> { 0x%02x, 0x%02x }\n", data.u16, data.bytes [0] & 0xff, data.bytes [1] & 0xff); + return false; + } + puts("OK"); + + printf("testing H2LE_32 on uint32_t ... "); + data.u32 = H2LE_32(0x12345678); + if (data.bytes [0] != 0x78 || data.bytes [1] != 0x56 || data.bytes [2] != 0x34 || data.bytes [3] != 0x12) { + printf("\nFAILED, H2LE_32(0x%08x) -> { 0x%02x, 0x%02x, 0x%02x, 0x%02x }\n", + data.u32, data.bytes [0] & 0xff, data.bytes [1] & 0xff, data.bytes [2] & 0xff, data.bytes [3] & 0xff); + return false; + } + puts("OK"); + + printf("\nPASSED!\n"); + return true; +} diff --git a/vendor/flac/src/test_libFLAC/endswap.h b/vendor/flac/src/test_libFLAC/endswap.h new file mode 100644 index 0000000..952b17f --- /dev/null +++ b/vendor/flac/src/test_libFLAC/endswap.h @@ -0,0 +1,26 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2014-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_ENDSWAP_H +#define FLAC__TEST_LIBFLAC_ENDSWAP_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_endswap(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/format.c b/vendor/flac/src/test_libFLAC/format.c new file mode 100644 index 0000000..c5e8bf2 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/format.c @@ -0,0 +1,260 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "format.h" +#include + +static const char *true_false_string_[2] = { "false", "true" }; + +static struct { + uint32_t rate; + FLAC__bool valid; + FLAC__bool subset; +} SAMPLE_RATES[] = { + { 0 , true , true }, + { 1 , true , true }, + { 9 , true , true }, + { 10 , true , true }, + { 4000 , true , true }, + { 8000 , true , true }, + { 11025 , true , true }, + { 12000 , true , true }, + { 16000 , true , true }, + { 22050 , true , true }, + { 24000 , true , true }, + { 32000 , true , true }, + { 32768 , true , true }, + { 44100 , true , true }, + { 48000 , true , true }, + { 65000 , true , true }, + { 65535 , true , true }, + { 65536 , true , false }, + { 65540 , true , true }, + { 65550 , true , true }, + { 65555 , true , false }, + { 66000 , true , true }, + { 66001 , true , false }, + { 96000 , true , true }, + { 100000 , true , true }, + { 100001 , true , false }, + { 192000 , true , true }, + { 500000 , true , true }, + { 500001 , true , false }, + { 500010 , true , true }, + { 655349 , true , false }, + { 655350 , true , true }, + { 655351 , true , false }, + { 655360 , true , false }, + { 700000 , true , false }, + { 700010 , true , false }, + { 705600 , true , false }, + { 768000 , true , false }, + { 1000000, true , false }, + { 1048575, true , false }, + { 1100000, false, false } +}; + +static struct { + const char *string; + FLAC__bool valid; +} VCENTRY_NAMES[] = { + { "" , true }, + { "a" , true }, + { "=" , false }, + { "a=" , false }, + { "\x01", false }, + { "\x1f", false }, + { "\x7d", true }, + { "\x7e", false }, + { "\xff", false } +}; + +static struct { + uint32_t length; + const FLAC__byte *string; + FLAC__bool valid; +} VCENTRY_VALUES[] = { + { 0, (const FLAC__byte*)"" , true }, + { 1, (const FLAC__byte*)"" , true }, + { 1, (const FLAC__byte*)"\x01" , true }, + { 1, (const FLAC__byte*)"\x7f" , true }, + { 1, (const FLAC__byte*)"\x80" , false }, + { 1, (const FLAC__byte*)"\x81" , false }, + { 1, (const FLAC__byte*)"\xc0" , false }, + { 1, (const FLAC__byte*)"\xe0" , false }, + { 1, (const FLAC__byte*)"\xf0" , false }, + { 2, (const FLAC__byte*)"\xc0\x41" , false }, + { 2, (const FLAC__byte*)"\xc1\x41" , false }, + { 2, (const FLAC__byte*)"\xc0\x85" , false }, /* non-shortest form */ + { 2, (const FLAC__byte*)"\xc1\x85" , false }, /* non-shortest form */ + { 2, (const FLAC__byte*)"\xc2\x85" , true }, + { 2, (const FLAC__byte*)"\xe0\x41" , false }, + { 2, (const FLAC__byte*)"\xe1\x41" , false }, + { 2, (const FLAC__byte*)"\xe0\x85" , false }, + { 2, (const FLAC__byte*)"\xe1\x85" , false }, + { 3, (const FLAC__byte*)"\xe0\x85\x41", false }, + { 3, (const FLAC__byte*)"\xe1\x85\x41", false }, + { 3, (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */ + { 3, (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */ + { 3, (const FLAC__byte*)"\xe0\xa5\x80", true }, + { 3, (const FLAC__byte*)"\xe1\x85\x80", true }, + { 3, (const FLAC__byte*)"\xe1\x95\x80", true }, + { 3, (const FLAC__byte*)"\xe1\xa5\x80", true } +}; + +static struct { + const FLAC__byte *string; + FLAC__bool valid; +} VCENTRY_VALUES_NT[] = { + { (const FLAC__byte*)"" , true }, + { (const FLAC__byte*)"\x01" , true }, + { (const FLAC__byte*)"\x7f" , true }, + { (const FLAC__byte*)"\x80" , false }, + { (const FLAC__byte*)"\x81" , false }, + { (const FLAC__byte*)"\xc0" , false }, + { (const FLAC__byte*)"\xe0" , false }, + { (const FLAC__byte*)"\xf0" , false }, + { (const FLAC__byte*)"\xc0\x41" , false }, + { (const FLAC__byte*)"\xc1\x41" , false }, + { (const FLAC__byte*)"\xc0\x85" , false }, /* non-shortest form */ + { (const FLAC__byte*)"\xc1\x85" , false }, /* non-shortest form */ + { (const FLAC__byte*)"\xc2\x85" , true }, + { (const FLAC__byte*)"\xe0\x41" , false }, + { (const FLAC__byte*)"\xe1\x41" , false }, + { (const FLAC__byte*)"\xe0\x85" , false }, + { (const FLAC__byte*)"\xe1\x85" , false }, + { (const FLAC__byte*)"\xe0\x85\x41", false }, + { (const FLAC__byte*)"\xe1\x85\x41", false }, + { (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */ + { (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */ + { (const FLAC__byte*)"\xe0\xa5\x80", true }, + { (const FLAC__byte*)"\xe1\x85\x80", true }, + { (const FLAC__byte*)"\xe1\x95\x80", true }, + { (const FLAC__byte*)"\xe1\xa5\x80", true } +}; + +static struct { + uint32_t length; + const FLAC__byte *string; + FLAC__bool valid; +} VCENTRIES[] = { + { 0, (const FLAC__byte*)"" , false }, + { 1, (const FLAC__byte*)"a" , false }, + { 1, (const FLAC__byte*)"=" , true }, + { 2, (const FLAC__byte*)"a=" , true }, + { 2, (const FLAC__byte*)"\x01=" , false }, + { 2, (const FLAC__byte*)"\x1f=" , false }, + { 2, (const FLAC__byte*)"\x7d=" , true }, + { 2, (const FLAC__byte*)"\x7e=" , false }, + { 2, (const FLAC__byte*)"\xff=" , false }, + { 3, (const FLAC__byte*)"a=\x01" , true }, + { 3, (const FLAC__byte*)"a=\x7f" , true }, + { 3, (const FLAC__byte*)"a=\x80" , false }, + { 3, (const FLAC__byte*)"a=\x81" , false }, + { 3, (const FLAC__byte*)"a=\xc0" , false }, + { 3, (const FLAC__byte*)"a=\xe0" , false }, + { 3, (const FLAC__byte*)"a=\xf0" , false }, + { 4, (const FLAC__byte*)"a=\xc0\x41" , false }, + { 4, (const FLAC__byte*)"a=\xc1\x41" , false }, + { 4, (const FLAC__byte*)"a=\xc0\x85" , false }, /* non-shortest form */ + { 4, (const FLAC__byte*)"a=\xc1\x85" , false }, /* non-shortest form */ + { 4, (const FLAC__byte*)"a=\xc2\x85" , true }, + { 4, (const FLAC__byte*)"a=\xe0\x41" , false }, + { 4, (const FLAC__byte*)"a=\xe1\x41" , false }, + { 4, (const FLAC__byte*)"a=\xe0\x85" , false }, + { 4, (const FLAC__byte*)"a=\xe1\x85" , false }, + { 5, (const FLAC__byte*)"a=\xe0\x85\x41", false }, + { 5, (const FLAC__byte*)"a=\xe1\x85\x41", false }, + { 5, (const FLAC__byte*)"a=\xe0\x85\x80", false }, /* non-shortest form */ + { 5, (const FLAC__byte*)"a=\xe0\x95\x80", false }, /* non-shortest form */ + { 5, (const FLAC__byte*)"a=\xe0\xa5\x80", true }, + { 5, (const FLAC__byte*)"a=\xe1\x85\x80", true }, + { 5, (const FLAC__byte*)"a=\xe1\x95\x80", true }, + { 5, (const FLAC__byte*)"a=\xe1\xa5\x80", true } +}; + +FLAC__bool test_format(void) +{ + uint32_t i; + + printf("\n+++ libFLAC unit test: format\n\n"); + + for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) { + printf("testing FLAC__format_sample_rate_is_valid(%u)... ", SAMPLE_RATES[i].rate); + if(FLAC__format_sample_rate_is_valid(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].valid) { + printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].valid], true_false_string_[!SAMPLE_RATES[i].valid]); + return false; + } + printf("OK\n"); + } + + for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) { + printf("testing FLAC__format_sample_rate_is_subset(%u)... ", SAMPLE_RATES[i].rate); + if(FLAC__format_sample_rate_is_subset(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].subset) { + printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].subset], true_false_string_[!SAMPLE_RATES[i].subset]); + return false; + } + printf("OK\n"); + } + + for(i = 0; i < sizeof(VCENTRY_NAMES)/sizeof(VCENTRY_NAMES[0]); i++) { + printf("testing FLAC__format_vorbiscomment_entry_name_is_legal(\"%s\")... ", VCENTRY_NAMES[i].string); + if(FLAC__format_vorbiscomment_entry_name_is_legal(VCENTRY_NAMES[i].string) != VCENTRY_NAMES[i].valid) { + printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_NAMES[i].valid], true_false_string_[!VCENTRY_NAMES[i].valid]); + return false; + } + printf("OK\n"); + } + + for(i = 0; i < sizeof(VCENTRY_VALUES)/sizeof(VCENTRY_VALUES[0]); i++) { + printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", %u)... ", VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length); + if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length) != VCENTRY_VALUES[i].valid) { + printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES[i].valid], true_false_string_[!VCENTRY_VALUES[i].valid]); + return false; + } + printf("OK\n"); + } + + for(i = 0; i < sizeof(VCENTRY_VALUES_NT)/sizeof(VCENTRY_VALUES_NT[0]); i++) { + printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", -1)... ", VCENTRY_VALUES_NT[i].string); + if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES_NT[i].string, (uint32_t)(-1)) != VCENTRY_VALUES_NT[i].valid) { + printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES_NT[i].valid], true_false_string_[!VCENTRY_VALUES_NT[i].valid]); + return false; + } + printf("OK\n"); + } + + for(i = 0; i < sizeof(VCENTRIES)/sizeof(VCENTRIES[0]); i++) { + printf("testing FLAC__format_vorbiscomment_entry_is_legal(\"%s\", %u)... ", VCENTRIES[i].string, VCENTRIES[i].length); + if(FLAC__format_vorbiscomment_entry_is_legal(VCENTRIES[i].string, VCENTRIES[i].length) != VCENTRIES[i].valid) { + printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRIES[i].valid], true_false_string_[!VCENTRIES[i].valid]); + return false; + } + printf("OK\n"); + } + + printf("\nPASSED!\n"); + return true; +} diff --git a/vendor/flac/src/test_libFLAC/format.h b/vendor/flac/src/test_libFLAC/format.h new file mode 100644 index 0000000..f78d55d --- /dev/null +++ b/vendor/flac/src/test_libFLAC/format.h @@ -0,0 +1,27 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_FORMAT_H +#define FLAC__TEST_LIBFLAC_FORMAT_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_format(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/main.c b/vendor/flac/src/test_libFLAC/main.c new file mode 100644 index 0000000..a4be0fe --- /dev/null +++ b/vendor/flac/src/test_libFLAC/main.c @@ -0,0 +1,64 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "bitreader.h" +#include "bitwriter.h" +#include "crc.h" +#include "decoders.h" +#include "encoders.h" +#include "endswap.h" +#include "format.h" +#include "metadata.h" +#include "md5.h" + +int main(void) +{ + if(!test_endswap()) + return 1; + + if(!test_crc()) + return 1; + + if(!test_md5()) + return 1; + + if(!test_bitreader()) + return 1; + + if(!test_bitwriter()) + return 1; + + if(!test_format()) + return 1; + + if(!test_encoders()) + return 1; + + if(!test_decoders()) + return 1; + + if(!test_metadata()) + return 1; + + return 0; +} diff --git a/vendor/flac/src/test_libFLAC/matrix b/vendor/flac/src/test_libFLAC/matrix new file mode 100644 index 0000000..a78ecf3 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/matrix @@ -0,0 +1,69 @@ +#if 0 +level 1 + +4 delete middle block nopad +1 delete middle block pad +1 delete last block nopad +1 delete last block pad +1 insert middle block nopad +1 insert middle block equalpad +1 insert middle block smallpad +1 insert middle block smallpad+1 +1 insert middle block biggerpad +1 insert last block X +1 set middle block smaller nopad +1 set middle block smaller pad +1 set last block smaller nopad +1 set last block smaller pad +1 set middle block bigger nopad +1 set middle block bigger equalpad +1 set middle block bigger smallpad +1 set middle block bigger smallpad+1 +1 set middle block bigger biggerpad +1 set last block bigger nopad +1 set middle block equal X +2 set last block equal X + +level 2 + +FLAC__bool FLAC__metadata_chain_write() + +1 newsize==oldsize + newsize>oldsize +b no use_padding +c use_padding, last block is not padding +g use_padding, last block is padding of insufficient length +h use_padding, last block is padding, but padding header straddles border (can't do it) +j use_padding, last block is padding of exact sufficient length (padding totally consumed) +i use_padding, last block is padding of abundant length (padding is reduced) + newsize= 4 +f use_padding, last block is padding + +void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain); +void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain); + +S:34 A:1234 +a:shrink A->30 write nopad +S:34 A:30 +b:grow A->32 write nopad +S:34 A:32 +c:grow A->40 write pad +S:34 A:40 +d:shrink A->37 write pad +S:34 A:37 +e:shrink A->33 write pad +S:34 A:33 P:0 +f:shrink A->20 write pad +S:34 A:20 P:13 +g:grow A->40 write pad +S:34 A:40 P:13 +h:grow A->54 write pad +S:34 A:54 P:13 +i:grow A->60 write pad +S:34 A:60 P:7 +j:grow A->71 write pad +S:34 A:71 +#endif diff --git a/vendor/flac/src/test_libFLAC/md5.c b/vendor/flac/src/test_libFLAC/md5.c new file mode 100644 index 0000000..bac4a74 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/md5.c @@ -0,0 +1,221 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2014-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "FLAC/assert.h" +#include "share/compat.h" +#include "private/md5.h" +#include "md5.h" + + +static FLAC__bool test_md5_clear_context(void); +static FLAC__bool test_md5_codec(void); +static FLAC__bool test_md5_accumulate(const FLAC__int32 * const * signal,uint32_t channels, uint32_t samples, uint32_t bytes_per_sample, const FLAC__byte target_digest [16]); + +FLAC__bool test_md5(void) +{ + printf("\n+++ libFLAC unit test: md5\n\n"); + + if (! test_md5_clear_context()) + return false; + + if (! test_md5_codec()) + return false; + + printf("\nPASSED!\n"); + return true; +} + +/*----------------------------------------------------------------------------*/ + +static FLAC__bool test_md5_clear_context(void) +{ + FLAC__MD5Context ctx; + FLAC__byte digest[16]; + FLAC__byte target[16] = { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e }; + uint32_t k ; + char * cptr; + + printf("testing FLAC__MD5Init ... "); + FLAC__MD5Init (&ctx); + if (ctx.buf[0] != 0x67452301) { + printf("FAILED!\n"); + return false; + } + printf("OK\n"); + + printf("testing that FLAC__MD5Final clears the MD5Context ... "); + FLAC__MD5Final(digest, &ctx); + cptr = (char*) &ctx ; + for (k = 0 ; k < sizeof (ctx) ; k++) { + if (cptr [k]) { + printf("FAILED, MD5 ctx has not been cleared after FLAC__MD5Final\n"); + return false; + } + } + printf("OK\n"); + + printf("testing digest correct for zero data ... "); + if (memcmp(digest, target, sizeof (digest))) { + printf("\nFAILED, expected MD5 sum "); + for (k = 0 ; k < 16 ; k++) + printf("%02x", (target [k] & 0xff)); + printf (" but got "); + for (k = 0 ; k < 16 ; k++) + printf("%02x", (digest [k] & 0xff)); + puts("\n"); + return false; + } + puts("OK"); + + return true; +} + +static FLAC__byte target_digests [8][4][16] = +{ /* 1 channel */ + { /* 1 byte per sample */ + { 0xc1, 0x9a, 0x5b, 0xeb, 0x57, 0x8f, 0x26, 0xeb, 0xfb, 0x34, 0x7c, 0xef, 0x04, 0x31, 0x6d, 0x7d }, + /* 2 bytes per sample */ + { 0xd4, 0x78, 0x90, 0xd3, 0xa9, 0x17, 0x4e, 0x76, 0xca, 0x4d, 0x27, 0x20, 0x98, 0x36, 0x8b, 0x2e }, + /* 3 bytes per sample */ + { 0x5a, 0x4b, 0xd6, 0xac, 0xa1, 0x70, 0x84, 0x19, 0x7c, 0x0d, 0xfb, 0x5b, 0xa9, 0x7b, 0xcb, 0x54 }, + /* 4 bytes per sample */ + { 0x79, 0xd5, 0x7a, 0x32, 0x06, 0x0b, 0xfe, 0x46, 0xa3, 0xe7, 0xba, 0xc5, 0xf7, 0x48, 0x6f, 0x50 } + }, + + /* 2 channels */ + { + { 0x89, 0xac, 0xcf, 0x91, 0xf1, 0x8c, 0xea, 0xab, 0x46, 0x12, 0x74, 0xbc, 0x4e, 0x82, 0xbe, 0x7d }, + { 0xb9, 0x17, 0x16, 0x5b, 0xd8, 0x1c, 0xc8, 0x4e, 0x5a, 0x28, 0xfb, 0xba, 0x87, 0x74, 0x76, 0x44 }, + { 0xec, 0x63, 0x92, 0xca, 0x4f, 0x6b, 0x9e, 0xb1, 0x9f, 0xec, 0x3b, 0x2c, 0x15, 0x30, 0xfd, 0x2a }, + { 0x05, 0x4d, 0xfd, 0xb8, 0x9d, 0x8a, 0xa2, 0xdd, 0x26, 0x47, 0xc6, 0xfb, 0x4f, 0x23, 0x67, 0x6d } + }, + + /* 3 channels */ + { + { 0xad, 0x05, 0xda, 0xf3, 0x7a, 0xa1, 0x94, 0xdb, 0x0c, 0x61, 0x06, 0xb2, 0x94, 0x39, 0x6c, 0xa9 }, + { 0x8b, 0xcc, 0x41, 0x4d, 0xe9, 0xe3, 0xc2, 0x61, 0x61, 0x8a, 0x8b, 0x22, 0xc6, 0x4e, 0xac, 0xa7 }, + { 0x8a, 0xce, 0x97, 0xc1, 0x86, 0xae, 0xbc, 0x73, 0x88, 0x8b, 0x35, 0x5a, 0x37, 0x33, 0xf9, 0xcf }, + { 0x69, 0x59, 0xe8, 0x38, 0x29, 0x80, 0x80, 0x21, 0xb1, 0xd2, 0xba, 0xf6, 0x28, 0xd6, 0x6a, 0x83 } + }, + + /* 4 channels */ + { + { 0x61, 0x40, 0x75, 0xef, 0x22, 0xf1, 0x0f, 0xa6, 0x08, 0x6c, 0x88, 0xff, 0x2c, 0x4e, 0x98, 0x0b }, + { 0xa0, 0x77, 0x3a, 0x59, 0x4a, 0xbf, 0xd0, 0x5c, 0xcc, 0xe3, 0xb9, 0x83, 0x2b, 0xf3, 0xdf, 0x1a }, + { 0xdb, 0xd7, 0xf1, 0x82, 0x13, 0x60, 0x42, 0x7c, 0x84, 0xe6, 0xcf, 0x30, 0xab, 0xa2, 0x64, 0xf1 }, + { 0x4a, 0x9a, 0xad, 0x53, 0x05, 0x74, 0xb1, 0x1c, 0xb8, 0xd4, 0xae, 0x78, 0x13, 0xf6, 0x2a, 0x11 } + }, + + /* 5 channels */ + { + { 0xcc, 0xca, 0x44, 0xc0, 0x54, 0xe2, 0xc9, 0xba, 0x99, 0x32, 0xc9, 0x65, 0xf3, 0x3e, 0x44, 0x34}, + { 0x40, 0x38, 0x6a, 0xdd, 0xde, 0x89, 0x10, 0x3c, 0x8e, 0xec, 0xdf, 0x15, 0x53, 0x4c, 0x2c, 0x92 }, + { 0xc8, 0x95, 0x0a, 0x7c, 0x17, 0x30, 0xc0, 0xac, 0x8e, 0x34, 0xdb, 0x79, 0x76, 0x64, 0x7c, 0x6e }, + { 0x3f, 0x06, 0x11, 0x8a, 0x8d, 0x80, 0xb5, 0x4f, 0x8b, 0xb5, 0x8e, 0xb3, 0x27, 0x3e, 0x41, 0xe8 } + }, + + /* 6 channels */ + { + { 0x61, 0xe4, 0xbd, 0xb1, 0xc0, 0x2f, 0xf4, 0x4c, 0x6e, 0x09, 0x5a, 0xbd, 0x90, 0x18, 0x8b, 0x62 }, + { 0x47, 0xe7, 0x6e, 0x3b, 0x18, 0x86, 0x60, 0x1b, 0x09, 0x62, 0xc6, 0xc9, 0x7c, 0x4c, 0x03, 0xb5 }, + { 0x70, 0x57, 0xbf, 0x67, 0x66, 0x0f, 0xe3, 0x0a, 0x6c, 0xd2, 0x97, 0x66, 0xa2, 0xd2, 0xe4, 0x79 }, + { 0xaa, 0x3f, 0xc7, 0xf5, 0x7a, 0xa5, 0x46, 0xf7, 0xea, 0xe3, 0xd5, 0x1a, 0xa4, 0x62, 0xbe, 0xfa } + }, + + /* 7 channels */ + { + { 0x7c, 0x8d, 0xd2, 0x8c, 0xfd, 0x91, 0xbb, 0x77, 0x6f, 0x0e, 0xf0, 0x39, 0x1f, 0x39, 0xc4, 0xac }, + { 0xfb, 0xab, 0x18, 0x3f, 0x1e, 0x1d, 0xa5, 0x77, 0xe0, 0x5c, 0xea, 0x45, 0x6f, 0x64, 0xa4, 0x64 }, + { 0xe3, 0xac, 0x33, 0x50, 0xc1, 0xb1, 0x93, 0xfb, 0xca, 0x4b, 0x15, 0xcb, 0x2d, 0xcd, 0xd5, 0xef }, + { 0x10, 0xfb, 0x02, 0x83, 0x76, 0x0d, 0xe5, 0xd2, 0x3b, 0xb1, 0x4c, 0x78, 0x3b, 0x73, 0xf7, 0x1a } + }, + + /* 8 channels */ + { + { 0x65, 0x7b, 0xe5, 0x92, 0xe2, 0x1c, 0x95, 0x3e, 0xd7, 0x2f, 0x64, 0xa0, 0x86, 0xec, 0x1a, 0xed }, + { 0x9d, 0x04, 0x8f, 0xa4, 0xea, 0x10, 0xec, 0xb8, 0xa3, 0x88, 0xe2, 0x5d, 0x3c, 0xe2, 0xfb, 0x94 }, + { 0x5a, 0xd3, 0xd2, 0x75, 0x6a, 0xfa, 0xa7, 0x42, 0xf3, 0xbf, 0x0e, 0xbc, 0x90, 0x2a, 0xf8, 0x5f }, + { 0x76, 0xe1, 0xe5, 0xf6, 0xe3, 0x44, 0x08, 0x29, 0xae, 0x79, 0x19, 0xeb, 0xa8, 0x57, 0x16, 0x2a } + } +}; + +#define MAX_CHANNEL_COUNT 8 +#define MD5_SAMPLE_COUNT 64 + +static FLAC__bool test_md5_codec(void) +{ + FLAC__int32 arrays[MAX_CHANNEL_COUNT][MD5_SAMPLE_COUNT], *pointer[MAX_CHANNEL_COUNT], **signal; + uint32_t chan, byte_size, seed = 0x12345679; + + /* Set up signal data using a trivial Linear Congruent PRNG. */ + signal = &pointer[0]; + for (chan = 0 ; chan < MAX_CHANNEL_COUNT ; chan ++) { + uint32_t k; + pointer[chan] = arrays [chan]; + for (k = 0 ; k < MD5_SAMPLE_COUNT ; k++) { + seed = seed * 1103515245 + 12345; + arrays[chan][k] = seed; + } + } + + for (chan = 1 ; chan <= MAX_CHANNEL_COUNT ; chan ++) { + for (byte_size = 1 ; byte_size <= 4 ; byte_size ++) { + if (! test_md5_accumulate((const FLAC__int32 * const *) signal, chan, MD5_SAMPLE_COUNT, byte_size, target_digests[chan-1][byte_size-1])) + return false; + } + } + + return true; +} + +static FLAC__bool test_md5_accumulate(const FLAC__int32 * const * signal, uint32_t channels, uint32_t samples, uint32_t bytes_per_sample, const FLAC__byte target_digest [16]) +{ + FLAC__MD5Context ctx; + FLAC__byte digest[16]; + + memset(&ctx, 0, sizeof (ctx)); + + printf("testing FLAC__MD5Accumulate (samples=%u, channels=%u, bytes_per_sample=%u) ... ", samples, channels, bytes_per_sample); + + FLAC__MD5Init(&ctx); + FLAC__MD5Accumulate(&ctx, signal, channels, samples, bytes_per_sample); + FLAC__MD5Final(digest, &ctx); + + if (memcmp(digest, target_digest, sizeof (digest))) { + int k ; + + printf("\nFAILED, expected MD5 sum "); + for (k = 0 ; k < 16 ; k++) + printf("%02x", (target_digest [k] & 0xff)); + printf (" but got "); + for (k = 0 ; k < 16 ; k++) + printf("%02x", (digest [k] & 0xff)); + puts("\n"); + return false; + } + + printf("OK\n"); + return true; +} diff --git a/vendor/flac/src/test_libFLAC/md5.h b/vendor/flac/src/test_libFLAC/md5.h new file mode 100644 index 0000000..6863268 --- /dev/null +++ b/vendor/flac/src/test_libFLAC/md5.h @@ -0,0 +1,26 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2014-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_MD5_H +#define FLAC__TEST_LIBFLAC_MD5_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_md5(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/metadata.c b/vendor/flac/src/test_libFLAC/metadata.c new file mode 100644 index 0000000..0347f6d --- /dev/null +++ b/vendor/flac/src/test_libFLAC/metadata.c @@ -0,0 +1,41 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "metadata.h" +#include + +extern FLAC__bool test_metadata_object(void); +extern FLAC__bool test_metadata_file_manipulation(void); + +FLAC__bool test_metadata(void) +{ + if(!test_metadata_object()) + return false; + + if(!test_metadata_file_manipulation()) + return false; + + printf("\nPASSED!\n"); + + return true; +} diff --git a/vendor/flac/src/test_libFLAC/metadata.h b/vendor/flac/src/test_libFLAC/metadata.h new file mode 100644 index 0000000..51bdf7a --- /dev/null +++ b/vendor/flac/src/test_libFLAC/metadata.h @@ -0,0 +1,29 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FLAC__TEST_LIBFLAC_METADATA_H +#define FLAC__TEST_LIBFLAC_METADATA_H + +#include "FLAC/ordinals.h" + +FLAC__bool test_metadata(void); +FLAC__bool test_metadata_file_manipulation(void); +FLAC__bool test_metadata_object(void); + +#endif diff --git a/vendor/flac/src/test_libFLAC/metadata_manip.c b/vendor/flac/src/test_libFLAC/metadata_manip.c new file mode 100644 index 0000000..334dc3a --- /dev/null +++ b/vendor/flac/src/test_libFLAC/metadata_manip.c @@ -0,0 +1,2146 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for malloc() */ +#include /* for memcpy()/memset() */ +#if defined _MSC_VER || defined __MINGW32__ +#include /* for utime() */ +#include /* for chmod() */ +#else +#include /* some flavors of BSD (like OS X) require this to get time_t */ +#include /* for chown(), unlink() */ +#endif +#include /* for stat(), maybe chmod() */ +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "FLAC/metadata.h" +#include "share/grabbag.h" +#include "share/compat.h" +#include "share/macros.h" +#include "share/safe_str.h" +#include "test_libs_common/file_utils_flac.h" +#include "test_libs_common/metadata_utils.h" +#include "metadata.h" + + +/****************************************************************************** + The general strategy of these tests (for interface levels 1 and 2) is + to create a dummy FLAC file with a known set of initial metadata + blocks, then keep a mirror locally of what we expect the metadata to be + after each operation. Then testing becomes a simple matter of running + a FLAC__StreamDecoder over the dummy file after each operation, comparing + the decoded metadata to what's in our local copy. If there are any + differences in the metadata, or the actual audio data is corrupted, we + will catch it while decoding. +******************************************************************************/ + +typedef struct { + FLAC__bool error_occurred; +} decoder_client_struct; + +typedef struct { + FLAC__StreamMetadata *blocks[64]; + uint32_t num_blocks; +} our_metadata_struct; + +/* our copy of the metadata in flacfilename() */ +static our_metadata_struct our_metadata_; + +/* the current block number that corresponds to the position of the iterator we are testing */ +static uint32_t mc_our_block_number_ = 0; + +static const char *flacfilename(FLAC__bool is_ogg) +{ + return is_ogg? "metadata.oga" : "metadata.flac"; +} + +static FLAC__bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static FLAC__bool die_c_(const char *msg, FLAC__Metadata_ChainStatus status) +{ + printf("ERROR: %s\n", msg); + printf(" status=%s\n", FLAC__Metadata_ChainStatusString[status]); + return false; +} + +static FLAC__bool die_ss_(const char *msg, FLAC__Metadata_SimpleIterator *iterator) +{ + printf("ERROR: %s\n", msg); + printf(" status=%s\n", FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iterator)]); + return false; +} + +static void *malloc_or_die_(size_t size) +{ + void *x = malloc(size); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size); + exit(1); + } + return x; +} + +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + +/* functions for working with our metadata copy */ + +static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, uint32_t position, FLAC__bool copy) +{ + uint32_t i; + FLAC__StreamMetadata *obj = block; + FLAC__ASSERT(position < our_metadata_.num_blocks); + if(copy) { + if(0 == (obj = FLAC__metadata_object_clone(block))) + return die_("during FLAC__metadata_object_clone()"); + } + FLAC__metadata_object_delete(our_metadata_.blocks[position]); + our_metadata_.blocks[position] = obj; + + /* set the is_last flags */ + for(i = 0; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i]->is_last = false; + our_metadata_.blocks[i]->is_last = true; + + return true; +} + +static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetadata *block, uint32_t position, FLAC__bool copy) +{ + uint32_t i; + FLAC__StreamMetadata *obj = block; + if(copy) { + if(0 == (obj = FLAC__metadata_object_clone(block))) + return die_("during FLAC__metadata_object_clone()"); + } + if(position > our_metadata_.num_blocks) { + position = our_metadata_.num_blocks; + } + else { + for(i = our_metadata_.num_blocks; i > position; i--) + our_metadata_.blocks[i] = our_metadata_.blocks[i-1]; + } + our_metadata_.blocks[position] = obj; + our_metadata_.num_blocks++; + + /* set the is_last flags */ + for(i = 0; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i]->is_last = false; + our_metadata_.blocks[i]->is_last = true; + + return true; +} + +static void delete_from_our_metadata_(uint32_t position) +{ + uint32_t i; + FLAC__ASSERT(position < our_metadata_.num_blocks); + FLAC__metadata_object_delete(our_metadata_.blocks[position]); + for(i = position; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i] = our_metadata_.blocks[i+1]; + our_metadata_.num_blocks--; + + /* set the is_last flags */ + if(our_metadata_.num_blocks > 0) { + for(i = 0; i < our_metadata_.num_blocks - 1; i++) + our_metadata_.blocks[i]->is_last = false; + our_metadata_.blocks[i]->is_last = true; + } +} + +/* + * This wad of functions supports filename- and callback-based chain reading/writing. + * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c + */ +static FLAC__bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename) +{ + static const char *tempfile_suffix = ".metadata_edit"; + size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1; + + *tempfilename = malloc(dest_len); + if (*tempfilename == NULL) + return false; + safe_strncpy(*tempfilename, filename, dest_len); + safe_strncat(*tempfilename, tempfile_suffix, dest_len); + + *tempfile = flac_fopen(*tempfilename, "wb"); + if (*tempfile == NULL) + return false; + + return true; +} + +static void cleanup_tempfile_(FILE **tempfile, char **tempfilename) +{ + if (*tempfile != NULL) { + (void)fclose(*tempfile); + *tempfile = 0; + } + + if (*tempfilename != NULL) { + (void)flac_unlink(*tempfilename); + free(*tempfilename); + *tempfilename = 0; + } +} + +static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != tempfile); + FLAC__ASSERT(0 != tempfilename); + FLAC__ASSERT(0 != *tempfilename); + + if(0 != *tempfile) { + (void)fclose(*tempfile); + *tempfile = 0; + } + +#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ + /* on some flavors of windows, flac_rename() will fail if the destination already exists */ + if(flac_unlink(filename) < 0) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } +#endif + + if(0 != flac_rename(*tempfilename, filename)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + + cleanup_tempfile_(tempfile, tempfilename); + + return true; +} + +static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + return (0 == flac_stat(filename, stats)); +} + +static void set_file_stats_(const char *filename, struct flac_stat_s *stats) +{ +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32) + struct timespec srctime[2] = {}; + srctime[0].tv_sec = stats->st_atime; + srctime[1].tv_sec = stats->st_mtime; +#else + struct utimbuf srctime; + srctime.actime = stats->st_atime; + srctime.modtime = stats->st_mtime; +#endif + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + + (void)flac_chmod(filename, stats->st_mode); + (void)flac_utime(filename, &srctime); +#if !defined _MSC_VER && !defined __MINGW32__ + FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1)); + FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid)); +#endif +} + +#ifdef FLAC__VALGRIND_TESTING +static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle) +{ + FILE *stream = (FILE*)handle; + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#endif + +static int chain_seek_cb_(FLAC__IOHandle handle, FLAC__int64 offset, int whence) +{ + FLAC__off_t o = (FLAC__off_t)offset; + FLAC__ASSERT(offset == o); + return fseeko((FILE*)handle, o, whence); +} + +static FLAC__int64 chain_tell_cb_(FLAC__IOHandle handle) +{ + return ftello((FILE*)handle); +} + +static int chain_eof_cb_(FLAC__IOHandle handle) +{ + return feof((FILE*)handle); +} + +static FLAC__bool write_chain_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats, FLAC__bool filename_based, const char *filename) +{ + if(filename_based) + return FLAC__metadata_chain_write(chain, use_padding, preserve_file_stats); + else { + FLAC__IOCallbacks callbacks; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.read = (FLAC__IOCallback_Read)fread; +#ifdef FLAC__VALGRIND_TESTING + callbacks.write = chain_write_cb_; +#else + callbacks.write = (FLAC__IOCallback_Write)fwrite; +#endif + callbacks.seek = chain_seek_cb_; + callbacks.eof = chain_eof_cb_; + + if(FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) { + struct flac_stat_s stats; + FILE *file, *tempfile = 0; + char *tempfilename; + if(preserve_file_stats) { + if(!get_file_stats_(filename, &stats)) + return false; + } + if(0 == (file = flac_fopen(filename, "rb"))) + return false; /*@@@@ chain status still says OK though */ + if(!open_tempfile_(filename, &tempfile, &tempfilename)) { + fclose(file); + cleanup_tempfile_(&tempfile, &tempfilename); + return false; /*@@@@ chain status still says OK though */ + } + if(!FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, use_padding, (FLAC__IOHandle)file, callbacks, (FLAC__IOHandle)tempfile, callbacks)) { + fclose(file); + fclose(tempfile); + return false; + } + fclose(file); + fclose(tempfile); + file = tempfile = 0; + if(!transport_tempfile_(filename, &tempfile, &tempfilename)) + return false; + if(preserve_file_stats) + set_file_stats_(filename, &stats); + } + else { + FILE *file = flac_fopen(filename, "r+b"); + if(0 == file) + return false; /*@@@@ chain status still says OK though */ + if(!FLAC__metadata_chain_write_with_callbacks(chain, use_padding, (FLAC__IOHandle)file, callbacks)) + return false; + fclose(file); + } + } + + return true; +} + +static FLAC__bool read_chain_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool filename_based, FLAC__bool is_ogg) +{ + if(filename_based) + return is_ogg? + FLAC__metadata_chain_read_ogg(chain, flacfilename(is_ogg)) : + FLAC__metadata_chain_read(chain, flacfilename(is_ogg)) + ; + else { + FLAC__IOCallbacks callbacks; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.read = (FLAC__IOCallback_Read)fread; + callbacks.seek = chain_seek_cb_; + callbacks.tell = chain_tell_cb_; + + { + FLAC__bool ret; + FILE *file = flac_fopen(filename, "rb"); + if(0 == file) + return false; /*@@@@ chain status still says OK though */ + ret = is_ogg? + FLAC__metadata_chain_read_ogg_with_callbacks(chain, (FLAC__IOHandle)file, callbacks) : + FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks) + ; + fclose(file); + return ret; + } + } +} + +/* function for comparing our metadata to a FLAC__Metadata_Chain */ + +static FLAC__bool compare_chain_(FLAC__Metadata_Chain *chain, uint32_t current_position, FLAC__StreamMetadata *current_block) +{ + uint32_t i; + FLAC__Metadata_Iterator *iterator; + FLAC__StreamMetadata *block; + FLAC__bool next_ok = true; + + FLAC__ASSERT(0 != chain); + + printf("\tcomparing chain... "); + fflush(stdout); + + if(0 == (iterator = FLAC__metadata_iterator_new())) + return die_("allocating memory for iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + i = 0; + do { + printf("%u... ", i); + fflush(stdout); + + if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) { + FLAC__metadata_iterator_delete(iterator); + return die_("getting block from iterator"); + } + + if(!mutils__compare_block(our_metadata_.blocks[i], block)) { + FLAC__metadata_iterator_delete(iterator); + return die_("metadata block mismatch"); + } + + i++; + next_ok = FLAC__metadata_iterator_next(iterator); + } while(i < our_metadata_.num_blocks && next_ok); + + FLAC__metadata_iterator_delete(iterator); + + if(next_ok) + return die_("chain has more blocks than expected"); + + if(i < our_metadata_.num_blocks) + return die_("short block count in chain"); + + if(0 != current_block) { + printf("CURRENT_POSITION... "); + fflush(stdout); + + if(!mutils__compare_block(our_metadata_.blocks[current_position], current_block)) + return die_("metadata block mismatch"); + } + + printf("PASSED\n"); + + return true; +} + +/* decoder callbacks for checking the file */ + +static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + (void)decoder, (void)buffer, (void)client_data; + + if( + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) || + (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0) + ) { + printf("content... "); + fflush(stdout); + } + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +/* this version pays no attention to the metadata */ +static void decoder_metadata_callback_null_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + (void)decoder, (void)metadata, (void)client_data; + + printf("%u... ", mc_our_block_number_); + fflush(stdout); + + mc_our_block_number_++; +} + +/* this version is used when we want to compare to our metadata copy */ +static void decoder_metadata_callback_compare_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + decoder_client_struct *dcd = (decoder_client_struct*)client_data; + + (void)decoder; + + /* don't bother checking if we've already hit an error */ + if(dcd->error_occurred) + return; + + printf("%u... ", mc_our_block_number_); + fflush(stdout); + + if(mc_our_block_number_ >= our_metadata_.num_blocks) { + (void)die_("got more metadata blocks than expected"); + dcd->error_occurred = true; + } + else { + if(!mutils__compare_block(our_metadata_.blocks[mc_our_block_number_], metadata)) { + (void)die_("metadata block mismatch"); + dcd->error_occurred = true; + } + } + mc_our_block_number_++; +} + +static void decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + decoder_client_struct *dcd = (decoder_client_struct*)client_data; + (void)decoder; + + dcd->error_occurred = true; + printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (uint32_t)status); +} + +static FLAC__bool generate_file_(FLAC__bool include_extras, FLAC__bool is_ogg) +{ + FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding; + FLAC__StreamMetadata *metadata[4]; + uint32_t i = 0, n = 0; + + printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : ""); + + while(our_metadata_.num_blocks > 0) + delete_from_our_metadata_(0); + + streaminfo.is_last = false; + streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO; + streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + streaminfo.data.stream_info.min_blocksize = 576; + streaminfo.data.stream_info.max_blocksize = 576; + streaminfo.data.stream_info.min_framesize = 0; + streaminfo.data.stream_info.max_framesize = 0; + streaminfo.data.stream_info.sample_rate = 44100; + streaminfo.data.stream_info.channels = 1; + streaminfo.data.stream_info.bits_per_sample = 8; + streaminfo.data.stream_info.total_samples = 0; + memset(streaminfo.data.stream_info.md5sum, 0, 16); + + { + const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING); + vorbiscomment.is_last = false; + vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT; + vorbiscomment.length = (4 + vendor_string_length) + 4; + vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length; + vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1); + memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1); + vorbiscomment.data.vorbis_comment.num_comments = 0; + vorbiscomment.data.vorbis_comment.comments = 0; + } + + { + if (0 == (cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET))) + return die_("priming our metadata"); + cuesheet->is_last = false; + safe_strncpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN", sizeof(cuesheet->data.cue_sheet.media_catalog_number)); + cuesheet->data.cue_sheet.lead_in = 123; + cuesheet->data.cue_sheet.is_cd = false; + if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0)) + return die_("priming our metadata"); + cuesheet->data.cue_sheet.tracks[0].number = 1; + if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0)) + return die_("priming our metadata"); + } + + { + picture.is_last = false; + picture.type = FLAC__METADATA_TYPE_PICTURE; + picture.length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture.data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture.length += strlen(picture.data.picture.mime_type); + picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture.length += strlen((const char *)picture.data.picture.description); + picture.data.picture.width = 300; + picture.data.picture.height = 300; + picture.data.picture.depth = 24; + picture.data.picture.colors = 0; + picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture.data.picture.data_length = strlen((const char *)picture.data.picture.data); + picture.length += picture.data.picture.data_length; + } + + padding.is_last = true; + padding.type = FLAC__METADATA_TYPE_PADDING; + padding.length = 1234; + + metadata[n++] = &vorbiscomment; + if(include_extras) { + metadata[n++] = cuesheet; + metadata[n++] = &picture; + } + metadata[n++] = &padding; + + if( + !insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) || + !insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) || + (include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) || + (include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) || + !insert_to_our_metadata_(&padding, i++, /*copy=*/true) + ) + return die_("priming our metadata"); + + if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n)) + return die_("creating the encoded file"); + + free(vorbiscomment.data.vorbis_comment.vendor_string.entry); + free(picture.data.picture.mime_type); + free(picture.data.picture.description); + free(picture.data.picture.data); + if(!include_extras) + FLAC__metadata_object_delete(cuesheet); + + return true; +} + +static FLAC__bool test_file_(FLAC__bool is_ogg, FLAC__StreamDecoderMetadataCallback metadata_callback) +{ + const char *filename = flacfilename(is_ogg); + FLAC__StreamDecoder *decoder; + decoder_client_struct decoder_client_data; + + FLAC__ASSERT(0 != metadata_callback); + + mc_our_block_number_ = 0; + decoder_client_data.error_occurred = false; + + printf("\ttesting '%s'... ", filename); + fflush(stdout); + + if(0 == (decoder = FLAC__stream_decoder_new())) + return die_("couldn't allocate decoder instance"); + + FLAC__stream_decoder_set_md5_checking(decoder, true); + FLAC__stream_decoder_set_metadata_respond_all(decoder); + if( + (is_ogg? + FLAC__stream_decoder_init_ogg_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data) : + FLAC__stream_decoder_init_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data) + ) != FLAC__STREAM_DECODER_INIT_STATUS_OK + ) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + return die_("initializing decoder\n"); + } + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + return die_("decoding file\n"); + } + + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + + if(decoder_client_data.error_occurred) + return false; + + if(mc_our_block_number_ != our_metadata_.num_blocks) + return die_("short metadata block count"); + + printf("PASSED\n"); + return true; +} + +static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only) +{ + if(!grabbag__file_change_stats(filename, read_only)) + return die_("during grabbag__file_change_stats()"); + + return true; +} + +static FLAC__bool remove_file_(const char *filename) +{ + while(our_metadata_.num_blocks > 0) + delete_from_our_metadata_(0); + + if(!grabbag__file_remove_file(filename)) + return die_("removing file"); + + return true; +} + +static FLAC__bool test_level_0_(void) +{ + FLAC__StreamMetadata streaminfo; + FLAC__StreamMetadata *tags = 0; + FLAC__StreamMetadata *cuesheet = 0; + FLAC__StreamMetadata *picture = 0; + + printf("\n\n++++++ testing level 0 interface\n"); + + if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false)) + return false; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_)) + return false; + + printf("testing FLAC__metadata_get_streaminfo()... "); + + if(!FLAC__metadata_get_streaminfo(flacfilename(/*is_ogg=*/false), &streaminfo)) + return die_("during FLAC__metadata_get_streaminfo()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(streaminfo.data.stream_info.channels != 1) + return die_("mismatch in streaminfo.data.stream_info.channels"); + if(streaminfo.data.stream_info.bits_per_sample != 8) + return die_("mismatch in streaminfo.data.stream_info.bits_per_sample"); + if(streaminfo.data.stream_info.sample_rate != 44100) + return die_("mismatch in streaminfo.data.stream_info.sample_rate"); + if(streaminfo.data.stream_info.min_blocksize != 576) + return die_("mismatch in streaminfo.data.stream_info.min_blocksize"); + if(streaminfo.data.stream_info.max_blocksize != 576) + return die_("mismatch in streaminfo.data.stream_info.max_blocksize"); + + printf("OK\n"); + + printf("testing FLAC__metadata_get_tags()... "); + + if(!FLAC__metadata_get_tags(flacfilename(/*is_ogg=*/false), &tags)) + return die_("during FLAC__metadata_get_tags()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(tags->data.vorbis_comment.num_comments != 0) + return die_("mismatch in tags->data.vorbis_comment.num_comments"); + + printf("OK\n"); + + FLAC__metadata_object_delete(tags); + + printf("testing FLAC__metadata_get_cuesheet()... "); + + if(!FLAC__metadata_get_cuesheet(flacfilename(/*is_ogg=*/false), &cuesheet)) + return die_("during FLAC__metadata_get_cuesheet()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(cuesheet->data.cue_sheet.lead_in != 123) + return die_("mismatch in cuesheet->data.cue_sheet.lead_in"); + + printf("OK\n"); + + FLAC__metadata_object_delete(cuesheet); + + printf("testing FLAC__metadata_get_picture()... "); + + if(!FLAC__metadata_get_picture(flacfilename(/*is_ogg=*/false), &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-1))) + return die_("during FLAC__metadata_get_picture()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER) + return die_("mismatch in picture->data.picture.type"); + + printf("OK\n"); + + FLAC__metadata_object_delete(picture); + + if(!remove_file_(flacfilename(/*is_ogg=*/false))) + return false; + + return true; +} + +static FLAC__bool test_level_1_(void) +{ + FLAC__Metadata_SimpleIterator *iterator; + FLAC__StreamMetadata *block, *app, *padding; + FLAC__byte data[1000]; + uint32_t our_current_position = 0; + + /* initialize 'data' to avoid Valgrind errors */ + memset(data, 0, sizeof(data)); + + printf("\n\n++++++ testing level 1 interface\n"); + + /************************************************************/ + + printf("simple iterator on read-only file\n"); + + if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false)) + return false; + + if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_)) + return false; + + if(0 == (iterator = FLAC__metadata_simple_iterator_new())) + return die_("FLAC__metadata_simple_iterator_new()"); + + if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false)) + return die_("FLAC__metadata_simple_iterator_init() returned false"); + + printf("is writable = %u\n", (uint32_t)FLAC__metadata_simple_iterator_is_writable(iterator)); + if(FLAC__metadata_simple_iterator_is_writable(iterator)) + return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n"); + + printf("iterate forwards\n"); + + if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_STREAMINFO) + return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()"); + if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator))) + return die_("getting block 0"); + if(block->type != FLAC__METADATA_TYPE_STREAMINFO) + return die_("expected STREAMINFO type"); + if(block->is_last) + return die_("expected is_last to be false"); + if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) + return die_("bad STREAMINFO length"); + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(block->data.stream_info.channels != 1) + return die_("mismatch in channels"); + if(block->data.stream_info.bits_per_sample != 8) + return die_("mismatch in bits_per_sample"); + if(block->data.stream_info.sample_rate != 44100) + return die_("mismatch in sample_rate"); + if(block->data.stream_info.min_blocksize != 576) + return die_("mismatch in min_blocksize"); + if(block->data.stream_info.max_blocksize != 576) + return die_("mismatch in max_blocksize"); + FLAC__metadata_object_delete(block); + + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("forward iterator ended early"); + our_current_position++; + + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("forward iterator ended early"); + our_current_position++; + + if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_PADDING) + return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()"); + if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator))) + return die_("getting block 2"); + if(block->type != FLAC__METADATA_TYPE_PADDING) + return die_("expected PADDING type"); + if(!block->is_last) + return die_("expected is_last to be true"); + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(block->length != 1234) + return die_("bad PADDING length"); + FLAC__metadata_object_delete(block); + + if(FLAC__metadata_simple_iterator_next(iterator)) + return die_("forward iterator returned true but should have returned false"); + + printf("iterate backwards\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("reverse iterator ended early"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("reverse iterator ended early"); + if(FLAC__metadata_simple_iterator_prev(iterator)) + return die_("reverse iterator returned true but should have returned false"); + + printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n"); + + if(!FLAC__metadata_simple_iterator_set_block(iterator, (FLAC__StreamMetadata*)99, false)) + printf("OK: FLAC__metadata_simple_iterator_set_block() returned false like it should\n"); + else + return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have"); + + FLAC__metadata_simple_iterator_delete(iterator); + + /************************************************************/ + + printf("simple iterator on writable file\n"); + + if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false)) + return false; + + printf("creating APPLICATION block\n"); + + if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION))) + return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)"); + memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + + printf("creating PADDING block\n"); + + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) + return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)"); + padding->length = 20; + + if(0 == (iterator = FLAC__metadata_simple_iterator_new())) + return die_("FLAC__metadata_simple_iterator_new()"); + + if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false)) + return die_("FLAC__metadata_simple_iterator_init() returned false"); + our_current_position = 0; + + printf("is writable = %u\n", (uint32_t)FLAC__metadata_simple_iterator_is_writable(iterator)); + + printf("[S]VP\ttry to write over STREAMINFO block...\n"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false)) + printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n"); + else + return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have"); + + if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT) + return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT"); + + printf("[S]VP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]P\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]\tinsert PADDING after, don't expand into padding\n"); + padding->length = 25; + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + printf("SVP[P]\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SV[P]P\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]PP\tinsert PADDING after, don't expand into padding\n"); + padding->length = 30; + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[P]PP\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]PPP\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n"); + if(FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator); + + if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT) + return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT"); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("[S]VPPP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]PPP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]PP\tdelete (middle block), replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, true)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator); + our_current_position--; + + printf("S[V]PPP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]PP\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("S[V]PP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]P\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVP[P]\tdelete (last block), replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, true)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + our_current_position--; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[P]P\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVP[P]\tdelete (last block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[P]\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]P\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]VP\tset STREAMINFO (change sample rate)\n"); + FLAC__ASSERT(our_current_position == 0); + block = FLAC__metadata_simple_iterator_get_block(iterator); + block->data.stream_info.sample_rate = 32000; + if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator); + FLAC__metadata_object_delete(block); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("[S]VP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n"); + app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */ + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return false; + our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]P\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n"); + app->data.application.id[0] = 'f'; /* twiddle the id */ + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true)) + return false; + our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n"); + app->data.application.id[0] = 'g'; /* twiddle the id */ + if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n"); + app->data.application.id[0] = 'h'; /* twiddle the id */ + if(!FLAC__metadata_object_application_set_data(app, data, 12, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n"); + app->data.application.id[0] = 'i'; /* twiddle the id */ + if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n"); + app->data.application.id[0] = 'j'; /* twiddle the id */ + if(!FLAC__metadata_object_application_set_data(app, data, 23, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true)) + return die_("copying object"); + our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH; + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVA[A]PP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVAA[P]P\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n"); + padding->length = 5; + if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVAAP[P]\tset APPLICATION (grow)\n"); + app->data.application.id[0] = 'k'; /* twiddle the id */ + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVAAP[A]\tset PADDING (equal)\n"); + padding->length = 27; + if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVAAP[P]\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVA[A]P\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]P\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVA[P]\tinsert PADDING after\n"); + padding->length = 5; + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVAP[P]\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SVA[P]P\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 32, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 60, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 87, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + our_metadata_.blocks[our_current_position+1]->length = 0; + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 91, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 100, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + our_metadata_.blocks[our_current_position]->is_last = true; + if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]\tset PADDING (equal size)\n"); + padding->length = app->length; + if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true)) + return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[P]\tinsert PADDING after\n"); + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVP[P]\tinsert PADDING after\n"); + padding->length = 5; + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return false; + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SVPP[P]\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SVP[P]P\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("SV[P]PP\tprev\n"); + if(!FLAC__metadata_simple_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 101, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 97, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 100, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]PP\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 96, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + our_metadata_.blocks[our_current_position+1]->length = 0; + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]PP\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("S[V]PP\tnext\n"); + if(!FLAC__metadata_simple_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]P\tdelete (middle block), don't replace with padding\n"); + if(!FLAC__metadata_simple_iterator_delete_block(iterator, false)) + return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator); + delete_from_our_metadata_(our_current_position--); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n"); + if(!FLAC__metadata_object_application_set_data(app, data, 1, true)) + return die_("setting APPLICATION data"); + if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)) + return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator); + + if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_)) + return false; + + printf("delete simple iterator\n"); + + FLAC__metadata_simple_iterator_delete(iterator); + + FLAC__metadata_object_delete(app); + FLAC__metadata_object_delete(padding); + + if(!remove_file_(flacfilename(/*is_ogg=*/false))) + return false; + + return true; +} + +static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg) +{ + FLAC__Metadata_Iterator *iterator; + FLAC__Metadata_Chain *chain; + FLAC__StreamMetadata *block, *app, *padding; + FLAC__byte data[2000]; + uint32_t our_current_position; + + /* initialize 'data' to avoid Valgrind errors */ + memset(data, 0, sizeof(data)); + + printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native"); + + printf("generate read-only file\n"); + + if(!generate_file_(/*include_extras=*/false, is_ogg)) + return false; + + if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true)) + return false; + + printf("create chain\n"); + + if(0 == (chain = FLAC__metadata_chain_new())) + return die_("allocating chain"); + + printf("read chain\n"); + + if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg)) + return die_c_("reading chain", FLAC__metadata_chain_status(chain)); + + printf("[S]VP\ttest initial metadata\n"); + + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + if(is_ogg) + goto end; + + printf("switch file to read-write\n"); + + if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false)) + return false; + + printf("create iterator\n"); + if(0 == (iterator = FLAC__metadata_iterator_new())) + return die_("allocating memory for iterator"); + + our_current_position = 0; + + FLAC__metadata_iterator_init(iterator, chain); + + if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) + return die_("getting block from iterator"); + + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO); + + printf("[S]VP\tmodify STREAMINFO, write\n"); + + block->data.stream_info.sample_rate = 32000; + if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true)) + return die_("copying object"); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("[S]VP\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]P\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]\treplace PADDING with identical-size APPLICATION\n"); + if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) + return die_("getting block from iterator"); + if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION))) + return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)"); + memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]\tshrink APPLICATION, don't use padding\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 26, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]\tgrow APPLICATION, don't use padding\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 28, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 36, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 33, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n"); + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) + return die_("creating PADDING block"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 29, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + padding->length = 0; + if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false)) + return die_("internal error"); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 16, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + our_metadata_.blocks[our_current_position+1]->length = 13; + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 50, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 56, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + our_metadata_.blocks[our_current_position+1]->length -= (56 - 50); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n"); + if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("copying object"); + if(!FLAC__metadata_object_application_set_data(app, data, 67, true)) + return die_("setting APPLICATION data"); + if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true)) + return die_("copying object"); + delete_from_our_metadata_(our_current_position+1); + if(!FLAC__metadata_iterator_set_block(iterator, app)) + return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain)); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV[A]\tprev\n"); + if(!FLAC__metadata_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("S[V]A\tprev\n"); + if(!FLAC__metadata_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n"); + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) + return die_("creating PADDING block"); + padding->length = 30; + if(!FLAC__metadata_iterator_insert_block_before(iterator, padding)) + printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n"); + else + return die_("FLAC__metadata_iterator_insert_block_before() should have returned false"); + + printf("[S]VP\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]A\tinsert PADDING after\n"); + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!FLAC__metadata_iterator_insert_block_after(iterator, padding)) + return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)"); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("SV[P]A\tinsert PADDING before\n"); + if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("creating PADDING block"); + padding->length = 17; + if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!FLAC__metadata_iterator_insert_block_before(iterator, padding)) + return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)"); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("SV[P]PA\tinsert PADDING before\n"); + if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position]))) + return die_("creating PADDING block"); + padding->length = 0; + if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!FLAC__metadata_iterator_insert_block_before(iterator, padding)) + return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)"); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("SV[P]PPA\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVP[P]PA\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVPP[P]A\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SVPPP[A]\tinsert PADDING after\n"); + if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2]))) + return die_("creating PADDING block"); + padding->length = 57; + if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!FLAC__metadata_iterator_insert_block_after(iterator, padding)) + return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)"); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("SVPPPA[P]\tinsert PADDING before\n"); + if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2]))) + return die_("creating PADDING block"); + padding->length = 99; + if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true)) + return die_("copying metadata"); + if(!FLAC__metadata_iterator_insert_block_before(iterator, padding)) + return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)"); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("delete iterator\n"); + FLAC__metadata_iterator_delete(iterator); + our_current_position = 0; + + printf("SVPPPAPP\tmerge padding\n"); + FLAC__metadata_chain_merge_padding(chain); + our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length); + our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length); + our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length); + delete_from_our_metadata_(7); + delete_from_our_metadata_(4); + delete_from_our_metadata_(3); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SVPAP\tsort padding\n"); + FLAC__metadata_chain_sort_padding(chain); + our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length); + delete_from_our_metadata_(2); + + if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("create iterator\n"); + if(0 == (iterator = FLAC__metadata_iterator_new())) + return die_("allocating memory for iterator"); + + our_current_position = 0; + + FLAC__metadata_iterator_init(iterator, chain); + + printf("[S]VAP\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("S[V]AP\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[A]P\tdelete middle block, replace with padding\n"); + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) + return die_("creating PADDING block"); + padding->length = 71; + if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false)) + return die_("copying object"); + if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true)) + return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain)); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("S[V]PP\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]P\tdelete middle block, don't replace with padding\n"); + delete_from_our_metadata_(our_current_position--); + if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false)) + return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain)); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("S[V]P\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]\tdelete last block, replace with padding\n"); + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) + return die_("creating PADDING block"); + padding->length = 219; + if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false)) + return die_("copying object"); + if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true)) + return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain)); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("S[V]P\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + our_current_position++; + + printf("SV[P]\tdelete last block, don't replace with padding\n"); + delete_from_our_metadata_(our_current_position--); + if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false)) + return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain)); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("S[V]\tprev\n"); + if(!FLAC__metadata_iterator_prev(iterator)) + return die_("iterator ended early\n"); + our_current_position--; + + printf("[S]V\tdelete STREAMINFO block, should fail\n"); + if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false)) + return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't"); + + if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator))) + return false; + + printf("delete iterator\n"); + FLAC__metadata_iterator_delete(iterator); + our_current_position = 0; + + printf("SV\tmerge padding\n"); + FLAC__metadata_chain_merge_padding(chain); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + + printf("SV\tsort padding\n"); + FLAC__metadata_chain_sort_padding(chain); + + if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg))) + return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain)); + if(!compare_chain_(chain, 0, 0)) + return false; + if(!test_file_(is_ogg, decoder_metadata_callback_compare_)) + return false; + +end: + printf("delete chain\n"); + + FLAC__metadata_chain_delete(chain); + + if(!remove_file_(flacfilename(is_ogg))) + return false; + + return true; +} + +static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg) +{ + FLAC__Metadata_Iterator *iterator; + FLAC__Metadata_Chain *chain; + FLAC__IOCallbacks callbacks; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.read = (FLAC__IOCallback_Read)fread; +#ifdef FLAC__VALGRIND_TESTING + callbacks.write = chain_write_cb_; +#else + callbacks.write = (FLAC__IOCallback_Write)fwrite; +#endif + callbacks.seek = chain_seek_cb_; + callbacks.tell = chain_tell_cb_; + callbacks.eof = chain_eof_cb_; + + printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n"); + + printf("generate file\n"); + + if(!generate_file_(/*include_extras=*/false, is_ogg)) + return false; + + printf("create chain\n"); + + if(0 == (chain = FLAC__metadata_chain_new())) + return die_("allocating chain"); + + printf("read chain (filename-based)\n"); + + if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg))) + return die_c_("reading chain", FLAC__metadata_chain_status(chain)); + + printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n"); + { + if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks)) + return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain)); + if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain)); + printf(" OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n"); + } + + printf("read chain (filename-based)\n"); + + if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg))) + return die_c_("reading chain", FLAC__metadata_chain_status(chain)); + + printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n"); + { + if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks)) + return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain)); + if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain)); + printf(" OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n"); + } + + printf("read chain (callback-based)\n"); + { + FILE *file = flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) + return die_("opening file"); + if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) { + fclose(file); + return die_c_("reading chain", FLAC__metadata_chain_status(chain)); + } + fclose(file); + } + + printf("write chain with wrong method FLAC__metadata_chain_write()\n"); + { + if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false)) + return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain)); + if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain)); + printf(" OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n"); + } + + printf("read chain (callback-based)\n"); + { + FILE *file = flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) + return die_("opening file"); + if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) { + fclose(file); + return die_c_("reading chain", FLAC__metadata_chain_status(chain)); + } + fclose(file); + } + + printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... "); + + if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false)) + printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n"); + else + return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have"); + + printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n"); + { + if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks)) + return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain)); + if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain)); + printf(" OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n"); + } + + printf("read chain (callback-based)\n"); + { + FILE *file = flac_fopen(flacfilename(is_ogg), "rb"); + if(0 == file) + return die_("opening file"); + if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) { + fclose(file); + return die_c_("reading chain", FLAC__metadata_chain_status(chain)); + } + fclose(file); + } + + printf("create iterator\n"); + if(0 == (iterator = FLAC__metadata_iterator_new())) + return die_("allocating memory for iterator"); + + FLAC__metadata_iterator_init(iterator, chain); + + printf("[S]VP\tnext\n"); + if(!FLAC__metadata_iterator_next(iterator)) + return die_("iterator ended early\n"); + + printf("S[V]P\tdelete VORBIS_COMMENT, write\n"); + if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false)) + return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain)); + + printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... "); + + if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false)) + printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n"); + else + return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have"); + + printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n"); + { + if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks)) + return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain)); + if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL) + return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain)); + printf(" OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n"); + } + + printf("delete iterator\n"); + + FLAC__metadata_iterator_delete(iterator); + + printf("delete chain\n"); + + FLAC__metadata_chain_delete(chain); + + if(!remove_file_(flacfilename(is_ogg))) + return false; + + return true; +} + +FLAC__bool test_metadata_file_manipulation(void) +{ + printf("\n+++ libFLAC unit test: metadata manipulation\n\n"); + + our_metadata_.num_blocks = 0; + + if(!test_level_0_()) + return false; + + if(!test_level_1_()) + return false; + + if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */ + return false; + if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */ + return false; + if(!test_level_2_misc_(/*is_ogg=*/false)) + return false; + + if(FLAC_API_SUPPORTS_OGG_FLAC) { + if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */ + return false; + if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */ + return false; +#if 0 + /* when ogg flac write is supported, will have to add this: */ + if(!test_level_2_misc_(/*is_ogg=*/true)) + return false; +#endif + } + + return true; +} diff --git a/vendor/flac/src/test_libFLAC/metadata_object.c b/vendor/flac/src/test_libFLAC/metadata_object.c new file mode 100644 index 0000000..ea6b69f --- /dev/null +++ b/vendor/flac/src/test_libFLAC/metadata_object.c @@ -0,0 +1,2291 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "test_libs_common/metadata_utils.h" +#include "share/compat.h" +#include "metadata.h" +#include +#include /* for malloc() */ +#include /* for memcmp() */ + +static FLAC__byte *make_dummydata_(FLAC__byte *dummydata, uint32_t len) +{ + FLAC__byte *ret; + + if(0 == (ret = malloc(len))) { + printf("FAILED, malloc error\n"); + exit(1); + } + else + memcpy(ret, dummydata, len); + + return ret; +} + +static FLAC__bool compare_track_(const FLAC__StreamMetadata_CueSheet_Track *from, const FLAC__StreamMetadata_CueSheet_Track *to) +{ + uint32_t i; + + if(from->offset != to->offset) { + printf("FAILED, track offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", to->offset, from->offset); + return false; + } + if(from->number != to->number) { + printf("FAILED, track number mismatch, expected %u, got %u\n", (uint32_t)to->number, (uint32_t)from->number); + return false; + } + if(0 != strcmp(from->isrc, to->isrc)) { + printf("FAILED, track number mismatch, expected %s, got %s\n", to->isrc, from->isrc); + return false; + } + if(from->type != to->type) { + printf("FAILED, track type mismatch, expected %u, got %u\n", (uint32_t)to->type, (uint32_t)from->type); + return false; + } + if(from->pre_emphasis != to->pre_emphasis) { + printf("FAILED, track pre_emphasis mismatch, expected %u, got %u\n", (uint32_t)to->pre_emphasis, (uint32_t)from->pre_emphasis); + return false; + } + if(from->num_indices != to->num_indices) { + printf("FAILED, track num_indices mismatch, expected %u, got %u\n", (uint32_t)to->num_indices, (uint32_t)from->num_indices); + return false; + } + if(0 == to->indices || 0 == from->indices) { + if(to->indices != from->indices) { + printf("FAILED, track indices mismatch\n"); + return false; + } + } + else { + for(i = 0; i < to->num_indices; i++) { + if(from->indices[i].offset != to->indices[i].offset) { + printf("FAILED, track indices[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to->indices[i].offset, from->indices[i].offset); + return false; + } + if(from->indices[i].number != to->indices[i].number) { + printf("FAILED, track indices[%u].number mismatch, expected %u, got %u\n", i, (uint32_t)to->indices[i].number, (uint32_t)from->indices[i].number); + return false; + } + } + } + + return true; +} + +static FLAC__bool compare_seekpoint_array_(const FLAC__StreamMetadata_SeekPoint *from, const FLAC__StreamMetadata_SeekPoint *to, uint32_t n) +{ + uint32_t i; + + FLAC__ASSERT(0 != from); + FLAC__ASSERT(0 != to); + + for(i = 0; i < n; i++) { + if(from[i].sample_number != to[i].sample_number) { + printf("FAILED, point[%u].sample_number mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to[i].sample_number, from[i].sample_number); + return false; + } + if(from[i].stream_offset != to[i].stream_offset) { + printf("FAILED, point[%u].stream_offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to[i].stream_offset, from[i].stream_offset); + return false; + } + if(from[i].frame_samples != to[i].frame_samples) { + printf("FAILED, point[%u].frame_samples mismatch, expected %u, got %u\n", i, to[i].frame_samples, from[i].frame_samples); + return false; + } + } + + return true; +} + +static FLAC__bool check_seektable_(const FLAC__StreamMetadata *block, uint32_t num_points, const FLAC__StreamMetadata_SeekPoint *array) +{ + const uint32_t expected_length = num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; + + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + if(block->data.seek_table.num_points != num_points) { + printf("FAILED, expected %u point, got %u\n", num_points, block->data.seek_table.num_points); + return false; + } + if(0 == array) { + if(0 != block->data.seek_table.points) { + printf("FAILED, 'points' pointer is not null\n"); + return false; + } + } + else { + if(!compare_seekpoint_array_(block->data.seek_table.points, array, num_points)) + return false; + } + printf("OK\n"); + + return true; +} + +static void entry_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field) +{ + entry->length = strlen(field); + entry->entry = malloc(entry->length+1); + FLAC__ASSERT(0 != entry->entry); + memcpy(entry->entry, field, entry->length); + entry->entry[entry->length] = '\0'; +} + +static void entry_clone_(FLAC__StreamMetadata_VorbisComment_Entry *entry) +{ + FLAC__byte *x = malloc(entry->length+1); + FLAC__ASSERT(0 != x); + memcpy(x, entry->entry, entry->length); + x[entry->length] = '\0'; + entry->entry = x; +} + +static void vc_calc_len_(FLAC__StreamMetadata *block) +{ + const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment; + uint32_t i; + + block->length = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; + block->length += vc->vendor_string.length; + block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; + for(i = 0; i < vc->num_comments; i++) { + block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; + block->length += vc->comments[i].length; + } +} + +static void vc_resize_(FLAC__StreamMetadata *block, uint32_t num) +{ + FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment; + + if(vc->num_comments != 0) { + FLAC__ASSERT(0 != vc->comments); + if(num < vc->num_comments) { + uint32_t i; + for(i = num; i < vc->num_comments; i++) { + if(0 != vc->comments[i].entry) + free(vc->comments[i].entry); + } + } + } + if(num == 0) { + if(0 != vc->comments) { + free(vc->comments); + vc->comments = 0; + } + } + else { + uint32_t i; + vc->comments = realloc(vc->comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*num); + FLAC__ASSERT(0 != vc->comments); + for(i = vc->num_comments; i < num; i++) { + vc->comments[i].length = 0; + vc->comments[i].entry = malloc(1); + vc->comments[i].entry[0] = '\0'; + } + } + + vc->num_comments = num; + vc_calc_len_(block); +} + +static int vc_find_from_(FLAC__StreamMetadata *block, const char *name, uint32_t start) +{ + const uint32_t n = strlen(name); + uint32_t i; + for(i = start; i < block->data.vorbis_comment.num_comments; i++) { + const FLAC__StreamMetadata_VorbisComment_Entry *entry = &block->data.vorbis_comment.comments[i]; + if(entry->length > n && 0 == strncmp((const char *)entry->entry, name, n) && entry->entry[n] == '=') + return (int)i; + } + return -1; +} + +static void vc_set_vs_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field) +{ + if(0 != block->data.vorbis_comment.vendor_string.entry) + free(block->data.vorbis_comment.vendor_string.entry); + entry_new_(entry, field); + block->data.vorbis_comment.vendor_string = *entry; + vc_calc_len_(block); +} + +static void vc_set_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, uint32_t pos, const char *field) +{ + if(0 != block->data.vorbis_comment.comments[pos].entry) + free(block->data.vorbis_comment.comments[pos].entry); + entry_new_(entry, field); + block->data.vorbis_comment.comments[pos] = *entry; + vc_calc_len_(block); +} + +static void vc_insert_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, uint32_t pos, const char *field) +{ + FLAC__StreamMetadata_VorbisComment_Entry temp; + vc_resize_(block, block->data.vorbis_comment.num_comments+1); + temp = block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1]; + memmove(&block->data.vorbis_comment.comments[pos+1], &block->data.vorbis_comment.comments[pos], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-1-pos)); + block->data.vorbis_comment.comments[pos] = temp; + vc_set_new_(entry, block, pos, field); + vc_calc_len_(block); +} + +static void vc_delete_(FLAC__StreamMetadata *block, uint32_t pos) +{ + if(0 != block->data.vorbis_comment.comments[pos].entry) + free(block->data.vorbis_comment.comments[pos].entry); + memmove(&block->data.vorbis_comment.comments[pos], &block->data.vorbis_comment.comments[pos+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-pos-1)); + block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].entry = 0; + block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].length = 0; + vc_resize_(block, block->data.vorbis_comment.num_comments-1); + vc_calc_len_(block); +} + +static void vc_replace_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field, FLAC__bool all) +{ + int indx; + char field_name[256]; + const char *eq = strchr(field, '='); + FLAC__ASSERT(eq>field && (uint32_t)(eq-field) < sizeof(field_name)); + memcpy(field_name, field, eq-field); + field_name[eq-field]='\0'; + + indx = vc_find_from_(block, field_name, 0); + if(indx < 0) + vc_insert_new_(entry, block, block->data.vorbis_comment.num_comments, field); + else { + vc_set_new_(entry, block, (uint32_t)indx, field); + if(all) { + for(indx = indx+1; indx >= 0 && (uint32_t)indx < block->data.vorbis_comment.num_comments; ) + if((indx = vc_find_from_(block, field_name, (uint32_t)indx)) >= 0) + vc_delete_(block, (uint32_t)indx); + } + } + + vc_calc_len_(block); +} + +static void track_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em) +{ + track->offset = offset; + track->number = number; + memcpy(track->isrc, isrc, sizeof(track->isrc)); + track->type = data; + track->pre_emphasis = pre_em; + track->num_indices = 0; + track->indices = 0; +} + +static void track_clone_(FLAC__StreamMetadata_CueSheet_Track *track) +{ + if(track->num_indices > 0) { + size_t bytes = sizeof(FLAC__StreamMetadata_CueSheet_Index) * track->num_indices; + FLAC__StreamMetadata_CueSheet_Index *x = malloc(bytes); + FLAC__ASSERT(0 != x); + memcpy(x, track->indices, bytes); + track->indices = x; + } +} + +static void cs_calc_len_(FLAC__StreamMetadata *block) +{ + const FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet; + uint32_t i; + + block->length = ( + FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN + ) / 8; + block->length += cs->num_tracks * ( + FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN + ) / 8; + for(i = 0; i < cs->num_tracks; i++) { + block->length += cs->tracks[i].num_indices * ( + FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN + ) / 8; + } +} + +static void tr_resize_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t num) +{ + FLAC__StreamMetadata_CueSheet_Track *tr; + + FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks); + + tr = &block->data.cue_sheet.tracks[track_num]; + + if(tr->num_indices != 0) { + FLAC__ASSERT(0 != tr->indices); + } + if(num == 0) { + if(0 != tr->indices) { + free(tr->indices); + tr->indices = 0; + } + } + else { + tr->indices = realloc(tr->indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)*num); + FLAC__ASSERT(0 != tr->indices); + if(num > tr->num_indices) + memset(tr->indices+tr->num_indices, 0, sizeof(FLAC__StreamMetadata_CueSheet_Index)*(num-tr->num_indices)); + } + + tr->num_indices = num; + cs_calc_len_(block); +} + +static void tr_set_new_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t pos, FLAC__StreamMetadata_CueSheet_Index indx) +{ + FLAC__StreamMetadata_CueSheet_Track *tr; + + FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks); + + tr = &block->data.cue_sheet.tracks[track_num]; + + FLAC__ASSERT(pos < tr->num_indices); + + tr->indices[pos] = indx; + + cs_calc_len_(block); +} + +static void tr_insert_new_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t pos, FLAC__StreamMetadata_CueSheet_Index indx) +{ + FLAC__StreamMetadata_CueSheet_Track *tr; + + FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks); + + tr = &block->data.cue_sheet.tracks[track_num]; + + FLAC__ASSERT(pos <= tr->num_indices); + + tr_resize_(block, track_num, tr->num_indices+1); + memmove(&tr->indices[pos+1], &tr->indices[pos], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-1-pos)); + tr_set_new_(block, track_num, pos, indx); + cs_calc_len_(block); +} + +static void tr_delete_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t pos) +{ + FLAC__StreamMetadata_CueSheet_Track *tr; + + FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks); + + tr = &block->data.cue_sheet.tracks[track_num]; + + FLAC__ASSERT(pos <= tr->num_indices); + + memmove(&tr->indices[pos], &tr->indices[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-pos-1)); + tr_resize_(block, track_num, tr->num_indices-1); + cs_calc_len_(block); +} + +static void cs_resize_(FLAC__StreamMetadata *block, uint32_t num) +{ + FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet; + + if(cs->num_tracks != 0) { + FLAC__ASSERT(0 != cs->tracks); + if(num < cs->num_tracks) { + uint32_t i; + for(i = num; i < cs->num_tracks; i++) { + if(0 != cs->tracks[i].indices) + free(cs->tracks[i].indices); + } + } + } + if(num == 0) { + if(0 != cs->tracks) { + free(cs->tracks); + cs->tracks = 0; + } + } + else { + cs->tracks = realloc(cs->tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)*num); + FLAC__ASSERT(0 != cs->tracks); + if(num > cs->num_tracks) + memset(cs->tracks+cs->num_tracks, 0, sizeof(FLAC__StreamMetadata_CueSheet_Track)*(num-cs->num_tracks)); + } + + cs->num_tracks = num; + cs_calc_len_(block); +} + +static void cs_set_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, uint32_t pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em) +{ + track_new_(track, offset, number, isrc, data, pre_em); + block->data.cue_sheet.tracks[pos] = *track; + cs_calc_len_(block); +} + +static void cs_insert_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, uint32_t pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em) +{ + cs_resize_(block, block->data.cue_sheet.num_tracks+1); + memmove(&block->data.cue_sheet.tracks[pos+1], &block->data.cue_sheet.tracks[pos], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-1-pos)); + cs_set_new_(track, block, pos, offset, number, isrc, data, pre_em); + cs_calc_len_(block); +} + +static void cs_delete_(FLAC__StreamMetadata *block, uint32_t pos) +{ + if(0 != block->data.cue_sheet.tracks[pos].indices) + free(block->data.cue_sheet.tracks[pos].indices); + memmove(&block->data.cue_sheet.tracks[pos], &block->data.cue_sheet.tracks[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-pos-1)); + block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].indices = 0; + block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].num_indices = 0; + cs_resize_(block, block->data.cue_sheet.num_tracks-1); + cs_calc_len_(block); +} + +static void pi_set_mime_type(FLAC__StreamMetadata *block, const char *s) +{ + if(block->data.picture.mime_type) { + block->length -= strlen(block->data.picture.mime_type); + free(block->data.picture.mime_type); + } + block->data.picture.mime_type = strdup(s); + FLAC__ASSERT(block->data.picture.mime_type); + block->length += strlen(block->data.picture.mime_type); +} + +static void pi_set_description(FLAC__StreamMetadata *block, const FLAC__byte *s) +{ + if(block->data.picture.description) { + block->length -= strlen((const char *)block->data.picture.description); + free(block->data.picture.description); + } + block->data.picture.description = (FLAC__byte*)strdup((const char *)s); + FLAC__ASSERT(block->data.picture.description); + block->length += strlen((const char *)block->data.picture.description); +} + +static void pi_set_data(FLAC__StreamMetadata *block, const FLAC__byte *data, FLAC__uint32 len) +{ + if(block->data.picture.data) { + block->length -= block->data.picture.data_length; + free(block->data.picture.data); + } + block->data.picture.data = (FLAC__byte*)strdup((const char *)data); + FLAC__ASSERT(block->data.picture.data); + block->data.picture.data_length = len; + block->length += len; +} + +FLAC__bool test_metadata_object(void) +{ + FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet, *picture; + FLAC__StreamMetadata_SeekPoint seekpoint_array[14]; + FLAC__StreamMetadata_VorbisComment_Entry entry; + FLAC__StreamMetadata_CueSheet_Index indx; + FLAC__StreamMetadata_CueSheet_Track track; + uint32_t i, expected_length, seekpoints; + int j; + static FLAC__byte dummydata[4] = { 'a', 'b', 'c', 'd' }; + + printf("\n+++ libFLAC unit test: metadata objects\n\n"); + + + printf("testing STREAMINFO\n"); + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + expected_length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing PADDING\n"); + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + expected_length = 0; + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing APPLICATION\n"); + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + expected_length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + printf("testing FLAC__metadata_object_application_set_data(copy)... "); + if(!FLAC__metadata_object_application_set_data(block, dummydata, sizeof(dummydata), true/*copy*/)) { + printf("FAILED, returned false\n"); + return false; + } + expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata); + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) { + printf("FAILED, data mismatch\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + printf("testing FLAC__metadata_object_application_set_data(own)... "); + if(!FLAC__metadata_object_application_set_data(block, make_dummydata_(dummydata, sizeof(dummydata)), sizeof(dummydata), false/*own*/)) { + printf("FAILED, returned false\n"); + return false; + } + expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata); + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) { + printf("FAILED, data mismatch\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing SEEKTABLE\n"); + + for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) { + seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + seekpoint_array[i].stream_offset = 0; + seekpoint_array[i].frame_samples = 0; + } + + seekpoints = 0; + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!check_seektable_(block, seekpoints, 0)) + return false; + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + seekpoints = 2; + printf("testing FLAC__metadata_object_seektable_resize_points(grow to %u)...", seekpoints); + if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoints = 1; + printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints); + if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + printf("testing FLAC__metadata_object_seektable_is_legal()..."); + if(!FLAC__metadata_object_seektable_is_legal(block)) { + printf("FAILED, returned false\n"); + return false; + } + printf("OK\n"); + + seekpoints = 0; + printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints); + if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, 0)) + return false; + + seekpoints++; + printf("testing FLAC__metadata_object_seektable_insert_point() on empty array..."); + if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoint_array[0].sample_number = 1; + seekpoints++; + printf("testing FLAC__metadata_object_seektable_insert_point() on beginning of non-empty array..."); + if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoint_array[1].sample_number = 2; + seekpoints++; + printf("testing FLAC__metadata_object_seektable_insert_point() on middle of non-empty array..."); + if(!FLAC__metadata_object_seektable_insert_point(block, 1, seekpoint_array[1])) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoint_array[3].sample_number = 3; + seekpoints++; + printf("testing FLAC__metadata_object_seektable_insert_point() on end of non-empty array..."); + if(!FLAC__metadata_object_seektable_insert_point(block, 3, seekpoint_array[3])) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + seekpoint_array[2].sample_number = seekpoint_array[3].sample_number; + seekpoints--; + printf("testing FLAC__metadata_object_seektable_delete_point() on middle of array..."); + if(!FLAC__metadata_object_seektable_delete_point(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoints--; + printf("testing FLAC__metadata_object_seektable_delete_point() on end of array..."); + if(!FLAC__metadata_object_seektable_delete_point(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoints--; + printf("testing FLAC__metadata_object_seektable_delete_point() on beginning of array..."); + if(!FLAC__metadata_object_seektable_delete_point(block, 0)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array+1)) + return false; + + printf("testing FLAC__metadata_object_seektable_set_point()..."); + FLAC__metadata_object_seektable_set_point(block, 0, seekpoint_array[0]); + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + /* seektable template functions */ + + for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) { + seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + seekpoint_array[i].stream_offset = 0; + seekpoint_array[i].frame_samples = 0; + } + + seekpoints = 0; + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!check_seektable_(block, seekpoints, 0)) + return false; + + seekpoints += 2; + printf("testing FLAC__metadata_object_seekpoint_template_append_placeholders()... "); + if(!FLAC__metadata_object_seektable_template_append_placeholders(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoint_array[seekpoints++].sample_number = 7; + printf("testing FLAC__metadata_object_seekpoint_template_append_point()... "); + if(!FLAC__metadata_object_seektable_template_append_point(block, 7)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + { + FLAC__uint64 nums[2] = { 3, 7 }; + seekpoint_array[seekpoints++].sample_number = nums[0]; + seekpoint_array[seekpoints++].sample_number = nums[1]; + printf("testing FLAC__metadata_object_seekpoint_template_append_points()... "); + if(!FLAC__metadata_object_seektable_template_append_points(block, nums, sizeof(nums)/sizeof(FLAC__uint64))) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + } + + seekpoint_array[seekpoints++].sample_number = 0; + seekpoint_array[seekpoints++].sample_number = 10; + seekpoint_array[seekpoints++].sample_number = 20; + printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points()... "); + if(!FLAC__metadata_object_seektable_template_append_spaced_points(block, 3, 30)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoints--; + seekpoint_array[0].sample_number = 0; + seekpoint_array[1].sample_number = 3; + seekpoint_array[2].sample_number = 7; + seekpoint_array[3].sample_number = 10; + seekpoint_array[4].sample_number = 20; + seekpoint_array[5].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + seekpoint_array[6].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=true)... "); + if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!FLAC__metadata_object_seektable_is_legal(block)) { + printf("FAILED, seek table is illegal\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=false)... "); + if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!FLAC__metadata_object_seektable_is_legal(block)) { + printf("FAILED, seek table is illegal\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoint_array[seekpoints++].sample_number = 0; + seekpoint_array[seekpoints++].sample_number = 10; + seekpoint_array[seekpoints++].sample_number = 20; + printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... "); + if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 10, 30)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + seekpoint_array[seekpoints++].sample_number = 0; + seekpoint_array[seekpoints++].sample_number = 11; + seekpoint_array[seekpoints++].sample_number = 22; + printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... "); + if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 11, 30)) { + printf("FAILED, returned false\n"); + return false; + } + if(!check_seektable_(block, seekpoints, seekpoint_array)) + return false; + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing VORBIS_COMMENT\n"); + + { + FLAC__StreamMetadata_VorbisComment_Entry entry_; + char *field_name, *field_value; + + printf("testing FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair()... "); + if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry_, "name", "value")) { + printf("FAILED, returned false\n"); + return false; + } + if(strcmp((const char *)entry_.entry, "name=value")) { + printf("FAILED, field mismatch\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair()... "); + if(!FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(entry_, &field_name, &field_value)) { + printf("FAILED, returned false\n"); + return false; + } + if(strcmp(field_name, "name")) { + printf("FAILED, field name mismatch\n"); + return false; + } + if(strcmp(field_value, "value")) { + printf("FAILED, field value mismatch\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... "); + if(!FLAC__metadata_object_vorbiscomment_entry_matches(entry_, field_name, strlen(field_name))) { + printf("FAILED, expected true, returned false\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... "); + if(FLAC__metadata_object_vorbiscomment_entry_matches(entry_, "blah", strlen("blah"))) { + printf("FAILED, expected false, returned true\n"); + return false; + } + printf("OK\n"); + + free(entry_.entry); + free(field_name); + free(field_value); + } + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + expected_length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + strlen(FLAC__VENDOR_STRING) + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8); + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + vorbiscomment = FLAC__metadata_object_clone(block); + if(0 == vorbiscomment) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + vc_resize_(vorbiscomment, 2); + printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(grow to %u)...", vorbiscomment->data.vorbis_comment.num_comments); + if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + vc_resize_(vorbiscomment, 1); + printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments); + if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + vc_resize_(vorbiscomment, 0); + printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments); + if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on empty array..."); + vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1"); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2"); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + vc_resize_(vorbiscomment, 0); + printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments); + if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on empty array..."); + vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1"); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on beginning of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2"); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on middle of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3"); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4"); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1"); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1"); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()..."); + if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name3")) != 1) { + printf("FAILED, expected 1, got %d\n", j); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()..."); + if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 4) { + printf("FAILED, expected 4, got %d\n", j); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()..."); + if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 5) { + printf("FAILED, expected 5, got %d\n", j); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()..."); + if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name2")) != 0) { + printf("FAILED, expected 0, got %d\n", j); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()..."); + if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name2")) != -1) { + printf("FAILED, expected -1, got %d\n", j); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()..."); + if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "blah")) != -1) { + printf("FAILED, expected -1, got %d\n", j); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, copy)..."); + vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false); + if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + if(block->data.vorbis_comment.num_comments != 6) { + printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, copy)..."); + vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true); + if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + if(block->data.vorbis_comment.num_comments != 4) { + printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array..."); + vc_delete_(vorbiscomment, 2); + if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array..."); + vc_delete_(vorbiscomment, 2); + if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array..."); + vc_delete_(vorbiscomment, 0); + if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 1, "rem0=val0"); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 2, "rem0=val1"); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 3, "rem0=val2"); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"blah\")..."); + if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "blah")) != 0) { + printf("FAILED, expected 0, got %d\n", j); + return false; + } + if(block->data.vorbis_comment.num_comments != 4) { + printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"rem0\")..."); + vc_delete_(vorbiscomment, 1); + if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "rem0")) != 1) { + printf("FAILED, expected 1, got %d\n", j); + return false; + } + if(block->data.vorbis_comment.num_comments != 3) { + printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"blah\")..."); + if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "blah")) != 0) { + printf("FAILED, expected 0, got %d\n", j); + return false; + } + if(block->data.vorbis_comment.num_comments != 3) { + printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"rem0\")..."); + vc_delete_(vorbiscomment, 1); + vc_delete_(vorbiscomment, 1); + if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "rem0")) != 2) { + printf("FAILED, expected 2, got %d\n", j); + return false; + } + if(block->data.vorbis_comment.num_comments != 1) { + printf("FAILED, expected 1 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_set_comment(copy)..."); + vc_set_new_(&entry, vorbiscomment, 0, "name5=field5"); + FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/true); + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(copy)..."); + vc_set_vs_new_(&entry, vorbiscomment, "name6=field6"); + FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/true); + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(vorbiscomment); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + vorbiscomment = FLAC__metadata_object_clone(block); + if(0 == vorbiscomment) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on empty array..."); + vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(vorbiscomment); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + vorbiscomment = FLAC__metadata_object_clone(block); + if(0 == vorbiscomment) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on empty array..."); + vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on beginning of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on middle of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array..."); + vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1"); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, own)..."); + vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + if(block->data.vorbis_comment.num_comments != 6) { + printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, own)..."); + vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true); + entry_clone_(&entry); + if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + if(block->data.vorbis_comment.num_comments != 4) { + printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array..."); + vc_delete_(vorbiscomment, 2); + if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array..."); + vc_delete_(vorbiscomment, 2); + if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array..."); + vc_delete_(vorbiscomment, 0); + if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_set_comment(own)..."); + vc_set_new_(&entry, vorbiscomment, 0, "name5=field5"); + entry_clone_(&entry); + FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/false); + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(own)..."); + vc_set_vs_new_(&entry, vorbiscomment, "name6=field6"); + entry_clone_(&entry); + FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/false); + if(!mutils__compare_block(vorbiscomment, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(vorbiscomment); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing CUESHEET\n"); + + { + FLAC__StreamMetadata_CueSheet_Track *track_, *trackcopy_; + + printf("testing FLAC__metadata_object_cuesheet_track_new()... "); + track_ = FLAC__metadata_object_cuesheet_track_new(); + if(0 == track_) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_track_clone()... "); + trackcopy_ = FLAC__metadata_object_cuesheet_track_clone(track_); + if(0 == trackcopy_) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!compare_track_(trackcopy_, track_)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_track_delete()... "); + FLAC__metadata_object_cuesheet_track_delete(trackcopy_); + FLAC__metadata_object_cuesheet_track_delete(track_); + printf("OK\n"); + } + + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + expected_length = ( + FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN + ) / 8; + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + cuesheet = FLAC__metadata_object_clone(block); + if(0 == cuesheet) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + cs_resize_(cuesheet, 2); + printf("testing FLAC__metadata_object_cuesheet_resize_tracks(grow to %u)...", cuesheet->data.cue_sheet.num_tracks); + if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + cs_resize_(cuesheet, 1); + printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks); + if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + cs_resize_(cuesheet, 0); + printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks); + if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on empty array..."); + cs_insert_new_(&track, cuesheet, 0, 0, 1, "ABCDE1234567", false, false); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on beginning of non-empty array..."); + cs_insert_new_(&track, cuesheet, 0, 10, 2, "BBCDE1234567", false, false); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on middle of non-empty array..."); + cs_insert_new_(&track, cuesheet, 1, 20, 3, "CBCDE1234567", false, false); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on end of non-empty array..."); + cs_insert_new_(&track, cuesheet, 3, 30, 4, "DBCDE1234567", false, false); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_blank_track() on end of non-empty array..."); + cs_insert_new_(&track, cuesheet, 4, 0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0", false, false); + if(!FLAC__metadata_object_cuesheet_insert_blank_track(block, 4)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array..."); + cs_delete_(cuesheet, 4); + if(!FLAC__metadata_object_cuesheet_delete_track(block, 4)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array..."); + cs_delete_(cuesheet, 2); + if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array..."); + cs_delete_(cuesheet, 2); + if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array..."); + cs_delete_(cuesheet, 0); + if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_set_track(copy)..."); + cs_set_new_(&track, cuesheet, 0, 40, 5, "EBCDE1234567", false, false); + FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/true); + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + tr_resize_(cuesheet, 0, 2); + printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(grow to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices); + if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + tr_resize_(cuesheet, 0, 1); + printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices); + if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + tr_resize_(cuesheet, 0, 0); + printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices); + if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + indx.offset = 0; + indx.number = 1; + printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on empty array..."); + tr_insert_new_(cuesheet, 0, 0, indx); + if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + indx.offset = 10; + indx.number = 2; + printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on beginning of non-empty array..."); + tr_insert_new_(cuesheet, 0, 0, indx); + if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + indx.offset = 20; + indx.number = 3; + printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on middle of non-empty array..."); + tr_insert_new_(cuesheet, 0, 1, indx); + if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 1, indx)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + indx.offset = 30; + indx.number = 4; + printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on end of non-empty array..."); + tr_insert_new_(cuesheet, 0, 3, indx); + if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 3, indx)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + indx.offset = 0; + indx.number = 0; + printf("testing FLAC__metadata_object_cuesheet_track_insert_blank_index() on end of non-empty array..."); + tr_insert_new_(cuesheet, 0, 4, indx); + if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(block, 0, 4)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array..."); + tr_delete_(cuesheet, 0, 4); + if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 4)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on middle of array..."); + tr_delete_(cuesheet, 0, 2); + if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array..."); + tr_delete_(cuesheet, 0, 2); + if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on beginning of array..."); + tr_delete_(cuesheet, 0, 0); + if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 0)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(cuesheet); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + cuesheet = FLAC__metadata_object_clone(block); + if(0 == cuesheet) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on empty array..."); + cs_insert_new_(&track, cuesheet, 0, 60, 7, "GBCDE1234567", false, false); + track_clone_(&track); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on beginning of non-empty array..."); + cs_insert_new_(&track, cuesheet, 0, 70, 8, "HBCDE1234567", false, false); + track_clone_(&track); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on middle of non-empty array..."); + cs_insert_new_(&track, cuesheet, 1, 80, 9, "IBCDE1234567", false, false); + track_clone_(&track); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on end of non-empty array..."); + cs_insert_new_(&track, cuesheet, 3, 90, 10, "JBCDE1234567", false, false); + track_clone_(&track); + if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array..."); + cs_delete_(cuesheet, 2); + if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array..."); + cs_delete_(cuesheet, 2); + if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array..."); + cs_delete_(cuesheet, 0); + if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_set_track(own)..."); + cs_set_new_(&track, cuesheet, 0, 100, 11, "KBCDE1234567", false, false); + track_clone_(&track); + FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/false); + if(!mutils__compare_block(cuesheet, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_cuesheet_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_cuesheet_is_legal(block, /*check_cd_da_subset=*/true, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(cuesheet); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + printf("testing PICTURE\n"); + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + expected_length = ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + ) / 8; + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + picture = FLAC__metadata_object_clone(block); + if(0 == picture) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + pi_set_mime_type(picture, "image/png\t"); + printf("testing FLAC__metadata_object_picture_set_mime_type(copy)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png\t", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_mime_type(picture, "image/png"); + printf("testing FLAC__metadata_object_picture_set_mime_type(copy)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff"); + printf("testing FLAC__metadata_object_picture_set_description(copy)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION\xff", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION"); + printf("testing FLAC__metadata_object_picture_set_description(copy)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + + pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA")); + printf("testing FLAC__metadata_object_picture_set_data(copy)..."); + if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)"PNGDATA", strlen("PNGDATA"), /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + pi_set_mime_type(picture, "image/png\t"); + printf("testing FLAC__metadata_object_picture_set_mime_type(own)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png\t"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_mime_type(picture, "image/png"); + printf("testing FLAC__metadata_object_picture_set_mime_type(own)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff"); + printf("testing FLAC__metadata_object_picture_set_description(own)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION\xff"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION"); + printf("testing FLAC__metadata_object_picture_set_description(own)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA")); + printf("testing FLAC__metadata_object_picture_set_data(own)..."); + if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)strdup("PNGDATA"), strlen("PNGDATA"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(picture); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + + return true; +} diff --git a/vendor/flac/src/test_libs_common/CMakeLists.txt b/vendor/flac/src/test_libs_common/CMakeLists.txt new file mode 100644 index 0000000..8a0c871 --- /dev/null +++ b/vendor/flac/src/test_libs_common/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(test_libs_common STATIC + file_utils_flac.c + metadata_utils.c) +target_link_libraries(test_libs_common PUBLIC FLAC) diff --git a/vendor/flac/src/test_libs_common/Makefile.am b/vendor/flac/src/test_libs_common/Makefile.am new file mode 100644 index 0000000..30e1f15 --- /dev/null +++ b/vendor/flac/src/test_libs_common/Makefile.am @@ -0,0 +1,29 @@ +# test_libs_common - Common code to library unit tests +# Copyright (C) 2000-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include + +noinst_LTLIBRARIES = libtest_libs_common.la + +libtest_libs_common_la_SOURCES = \ + file_utils_flac.c \ + metadata_utils.c + +EXTRA_DIST = \ + CMakeLists.txt \ + README diff --git a/vendor/flac/src/test_libs_common/README b/vendor/flac/src/test_libs_common/README new file mode 100644 index 0000000..6a704c2 --- /dev/null +++ b/vendor/flac/src/test_libs_common/README @@ -0,0 +1,2 @@ +This directory contains a convenience library of routines that are +common to the library unit testers. diff --git a/vendor/flac/src/test_libs_common/file_utils_flac.c b/vendor/flac/src/test_libs_common/file_utils_flac.c new file mode 100644 index 0000000..3cc8c30 --- /dev/null +++ b/vendor/flac/src/test_libs_common/file_utils_flac.c @@ -0,0 +1,155 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/assert.h" +#include "FLAC/stream_encoder.h" +#include "test_libs_common/file_utils_flac.h" +#include +#include +#include /* for stat() */ +#include "share/compat.h" + +#ifdef min +#undef min +#endif +#define min(a,b) ((a)<(b)?(a):(b)) + +const long file_utils__ogg_serial_number = 12345; + +#ifdef FLAC__VALGRIND_TESTING +static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#else +#define local__fwrite fwrite +#endif + +typedef struct { + FILE *file; +} encoder_client_struct; + +static FLAC__StreamEncoderWriteStatus encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data) +{ + encoder_client_struct *ecd = (encoder_client_struct*)client_data; + + (void)encoder, (void)samples, (void)current_frame; + + if(local__fwrite(buffer, 1, bytes, ecd->file) != bytes) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + else + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} + +static void encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + (void)encoder, (void)metadata, (void)client_data; +} + +FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, FLAC__off_t *output_filesize, uint32_t length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, uint32_t num_metadata) +{ + FLAC__int32 samples[1024]; + FLAC__StreamEncoder *encoder; + FLAC__StreamEncoderInitStatus init_status; + encoder_client_struct encoder_client_data; + uint32_t i, n; + + FLAC__ASSERT(0 != output_filename); + FLAC__ASSERT(0 != streaminfo); + FLAC__ASSERT(streaminfo->type == FLAC__METADATA_TYPE_STREAMINFO); + FLAC__ASSERT((streaminfo->is_last && num_metadata == 0) || (!streaminfo->is_last && num_metadata > 0)); + + if(0 == (encoder_client_data.file = flac_fopen(output_filename, "wb"))) + return false; + + encoder = FLAC__stream_encoder_new(); + if(0 == encoder) { + fclose(encoder_client_data.file); + return false; + } + + FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number); + FLAC__stream_encoder_set_verify(encoder, true); + FLAC__stream_encoder_set_streamable_subset(encoder, true); + FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false); + FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false); + FLAC__stream_encoder_set_channels(encoder, streaminfo->data.stream_info.channels); + FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo->data.stream_info.bits_per_sample); + FLAC__stream_encoder_set_sample_rate(encoder, streaminfo->data.stream_info.sample_rate); + FLAC__stream_encoder_set_blocksize(encoder, streaminfo->data.stream_info.min_blocksize); + FLAC__stream_encoder_set_max_lpc_order(encoder, 0); + FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0); + FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false); + FLAC__stream_encoder_set_do_escape_coding(encoder, false); + FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false); + FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0); + FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0); + FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0); + FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo->data.stream_info.total_samples); + FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata); + + if(is_ogg) + init_status = FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data); + else + init_status = FLAC__stream_encoder_init_stream(encoder, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data); + + if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + fclose(encoder_client_data.file); + return false; + } + + /* init the dummy sample buffer */ + for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++) + samples[i] = i & 7; + + while(length > 0) { + n = min(length, sizeof(samples) / sizeof(FLAC__int32)); + + if(!FLAC__stream_encoder_process_interleaved(encoder, samples, n)) { + fclose(encoder_client_data.file); + return false; + } + + length -= n; + } + + (void)FLAC__stream_encoder_finish(encoder); + + fclose(encoder_client_data.file); + + FLAC__stream_encoder_delete(encoder); + + if(0 != output_filesize) { + struct flac_stat_s filestats; + + if(flac_stat(output_filename, &filestats) != 0) + return false; + else + *output_filesize = filestats.st_size; + } + + return true; +} diff --git a/vendor/flac/src/test_libs_common/metadata_utils.c b/vendor/flac/src/test_libs_common/metadata_utils.c new file mode 100644 index 0000000..929ca63 --- /dev/null +++ b/vendor/flac/src/test_libs_common/metadata_utils.c @@ -0,0 +1,636 @@ +/* test_libFLAC - Unit tester for libFLAC + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * These are not tests, just utility functions used by the metadata tests + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "FLAC/metadata.h" +#include "test_libs_common/metadata_utils.h" +#include "share/compat.h" +#include +#include /* for malloc() */ +#include /* for memcmp() */ + +FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy) +{ + if(blockcopy->min_blocksize != block->min_blocksize) { + printf("FAILED, min_blocksize mismatch, expected %u, got %u\n", block->min_blocksize, blockcopy->min_blocksize); + return false; + } + if(blockcopy->max_blocksize != block->max_blocksize) { + printf("FAILED, max_blocksize mismatch, expected %u, got %u\n", block->max_blocksize, blockcopy->max_blocksize); + return false; + } + if(blockcopy->min_framesize != block->min_framesize) { + printf("FAILED, min_framesize mismatch, expected %u, got %u\n", block->min_framesize, blockcopy->min_framesize); + return false; + } + if(blockcopy->max_framesize != block->max_framesize) { + printf("FAILED, max_framesize mismatch, expected %u, got %u\n", block->max_framesize, blockcopy->max_framesize); + return false; + } + if(blockcopy->sample_rate != block->sample_rate) { + printf("FAILED, sample_rate mismatch, expected %u, got %u\n", block->sample_rate, blockcopy->sample_rate); + return false; + } + if(blockcopy->channels != block->channels) { + printf("FAILED, channels mismatch, expected %u, got %u\n", block->channels, blockcopy->channels); + return false; + } + if(blockcopy->bits_per_sample != block->bits_per_sample) { + printf("FAILED, bits_per_sample mismatch, expected %u, got %u\n", block->bits_per_sample, blockcopy->bits_per_sample); + return false; + } + if(blockcopy->total_samples != block->total_samples) { + printf("FAILED, total_samples mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->total_samples, blockcopy->total_samples); + return false; + } + if(0 != memcmp(blockcopy->md5sum, block->md5sum, sizeof(block->md5sum))) { + printf("FAILED, md5sum mismatch, expected %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X, got %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", + (uint32_t)block->md5sum[0], + (uint32_t)block->md5sum[1], + (uint32_t)block->md5sum[2], + (uint32_t)block->md5sum[3], + (uint32_t)block->md5sum[4], + (uint32_t)block->md5sum[5], + (uint32_t)block->md5sum[6], + (uint32_t)block->md5sum[7], + (uint32_t)block->md5sum[8], + (uint32_t)block->md5sum[9], + (uint32_t)block->md5sum[10], + (uint32_t)block->md5sum[11], + (uint32_t)block->md5sum[12], + (uint32_t)block->md5sum[13], + (uint32_t)block->md5sum[14], + (uint32_t)block->md5sum[15], + (uint32_t)blockcopy->md5sum[0], + (uint32_t)blockcopy->md5sum[1], + (uint32_t)blockcopy->md5sum[2], + (uint32_t)blockcopy->md5sum[3], + (uint32_t)blockcopy->md5sum[4], + (uint32_t)blockcopy->md5sum[5], + (uint32_t)blockcopy->md5sum[6], + (uint32_t)blockcopy->md5sum[7], + (uint32_t)blockcopy->md5sum[8], + (uint32_t)blockcopy->md5sum[9], + (uint32_t)blockcopy->md5sum[10], + (uint32_t)blockcopy->md5sum[11], + (uint32_t)blockcopy->md5sum[12], + (uint32_t)blockcopy->md5sum[13], + (uint32_t)blockcopy->md5sum[14], + (uint32_t)blockcopy->md5sum[15] + ); + return false; + } + return true; +} + +FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, uint32_t block_length) +{ + /* we don't compare the padding guts */ + (void)block, (void)blockcopy, (void)block_length; + return true; +} + +FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, uint32_t block_length) +{ + if(block_length < sizeof(block->id)) { + printf("FAILED, bad block length = %u\n", block_length); + return false; + } + if(0 != memcmp(blockcopy->id, block->id, sizeof(block->id))) { + printf("FAILED, id mismatch, expected %02X%02X%02X%02X, got %02X%02X%02X%02X\n", + (uint32_t)block->id[0], + (uint32_t)block->id[1], + (uint32_t)block->id[2], + (uint32_t)block->id[3], + (uint32_t)blockcopy->id[0], + (uint32_t)blockcopy->id[1], + (uint32_t)blockcopy->id[2], + (uint32_t)blockcopy->id[3] + ); + return false; + } + if(0 == block->data || 0 == blockcopy->data) { + if(block->data != blockcopy->data) { + printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy"); + return false; + } + else if(block_length - sizeof(block->id) > 0) { + printf("FAILED, data pointer is null but block length is not 0\n"); + return false; + } + } + else { + if(block_length - sizeof(block->id) == 0) { + printf("FAILED, data pointer is not null but block length is 0\n"); + return false; + } + else if(0 != memcmp(blockcopy->data, block->data, block_length - sizeof(block->id))) { + printf("FAILED, data mismatch\n"); + return false; + } + } + return true; +} + +FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy) +{ + uint32_t i; + if(blockcopy->num_points != block->num_points) { + printf("FAILED, num_points mismatch, expected %u, got %u\n", block->num_points, blockcopy->num_points); + return false; + } + for(i = 0; i < block->num_points; i++) { + if(blockcopy->points[i].sample_number != block->points[i].sample_number) { + printf("FAILED, points[%u].sample_number mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].sample_number, blockcopy->points[i].sample_number); + return false; + } + if(blockcopy->points[i].stream_offset != block->points[i].stream_offset) { + printf("FAILED, points[%u].stream_offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].stream_offset, blockcopy->points[i].stream_offset); + return false; + } + if(blockcopy->points[i].frame_samples != block->points[i].frame_samples) { + printf("FAILED, points[%u].frame_samples mismatch, expected %u, got %u\n", i, block->points[i].frame_samples, blockcopy->points[i].frame_samples); + return false; + } + } + return true; +} + +FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy) +{ + uint32_t i; + if(blockcopy->vendor_string.length != block->vendor_string.length) { + printf("FAILED, vendor_string.length mismatch, expected %u, got %u\n", block->vendor_string.length, blockcopy->vendor_string.length); + return false; + } + if(0 == block->vendor_string.entry || 0 == blockcopy->vendor_string.entry) { + if(block->vendor_string.entry != blockcopy->vendor_string.entry) { + printf("FAILED, vendor_string.entry mismatch\n"); + return false; + } + } + else if(0 != memcmp(blockcopy->vendor_string.entry, block->vendor_string.entry, block->vendor_string.length)) { + printf("FAILED, vendor_string.entry mismatch\n"); + return false; + } + if(blockcopy->num_comments != block->num_comments) { + printf("FAILED, num_comments mismatch, expected %u, got %u\n", block->num_comments, blockcopy->num_comments); + return false; + } + for(i = 0; i < block->num_comments; i++) { + if(blockcopy->comments[i].length != block->comments[i].length) { + printf("FAILED, comments[%u].length mismatch, expected %u, got %u\n", i, block->comments[i].length, blockcopy->comments[i].length); + return false; + } + if(0 == block->comments[i].entry || 0 == blockcopy->comments[i].entry) { + if(block->comments[i].entry != blockcopy->comments[i].entry) { + printf("FAILED, comments[%u].entry mismatch\n", i); + return false; + } + } + else { + if(0 != memcmp(blockcopy->comments[i].entry, block->comments[i].entry, block->comments[i].length)) { + printf("FAILED, comments[%u].entry mismatch\n", i); + return false; + } + } + } + return true; +} + +FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy) +{ + uint32_t i, j; + + if(0 != strcmp(blockcopy->media_catalog_number, block->media_catalog_number)) { + printf("FAILED, media_catalog_number mismatch, expected %s, got %s\n", block->media_catalog_number, blockcopy->media_catalog_number); + return false; + } + if(blockcopy->lead_in != block->lead_in) { + printf("FAILED, lead_in mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->lead_in, blockcopy->lead_in); + return false; + } + if(blockcopy->is_cd != block->is_cd) { + printf("FAILED, is_cd mismatch, expected %u, got %u\n", (uint32_t)block->is_cd, (uint32_t)blockcopy->is_cd); + return false; + } + if(blockcopy->num_tracks != block->num_tracks) { + printf("FAILED, num_tracks mismatch, expected %u, got %u\n", block->num_tracks, blockcopy->num_tracks); + return false; + } + for(i = 0; i < block->num_tracks; i++) { + if(blockcopy->tracks[i].offset != block->tracks[i].offset) { + printf("FAILED, tracks[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->tracks[i].offset, blockcopy->tracks[i].offset); + return false; + } + if(blockcopy->tracks[i].number != block->tracks[i].number) { + printf("FAILED, tracks[%u].number mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].number, (uint32_t)blockcopy->tracks[i].number); + return false; + } + if(blockcopy->tracks[i].num_indices != block->tracks[i].num_indices) { + printf("FAILED, tracks[%u].num_indices mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].num_indices, (uint32_t)blockcopy->tracks[i].num_indices); + return false; + } + /* num_indices == 0 means lead-out track so only the track offset and number are valid */ + if(block->tracks[i].num_indices > 0) { + if(0 != strcmp(blockcopy->tracks[i].isrc, block->tracks[i].isrc)) { + printf("FAILED, tracks[%u].isrc mismatch, expected %s, got %s\n", i, block->tracks[i].isrc, blockcopy->tracks[i].isrc); + return false; + } + if(blockcopy->tracks[i].type != block->tracks[i].type) { + printf("FAILED, tracks[%u].type mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].type, (uint32_t)blockcopy->tracks[i].type); + return false; + } + if(blockcopy->tracks[i].pre_emphasis != block->tracks[i].pre_emphasis) { + printf("FAILED, tracks[%u].pre_emphasis mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].pre_emphasis, (uint32_t)blockcopy->tracks[i].pre_emphasis); + return false; + } + if(0 == block->tracks[i].indices || 0 == blockcopy->tracks[i].indices) { + if(block->tracks[i].indices != blockcopy->tracks[i].indices) { + printf("FAILED, tracks[%u].indices mismatch\n", i); + return false; + } + } + else { + for(j = 0; j < block->tracks[i].num_indices; j++) { + if(blockcopy->tracks[i].indices[j].offset != block->tracks[i].indices[j].offset) { + printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, j, block->tracks[i].indices[j].offset, blockcopy->tracks[i].indices[j].offset); + return false; + } + if(blockcopy->tracks[i].indices[j].number != block->tracks[i].indices[j].number) { + printf("FAILED, tracks[%u].indices[%u].number mismatch, expected %u, got %u\n", i, j, (uint32_t)block->tracks[i].indices[j].number, (uint32_t)blockcopy->tracks[i].indices[j].number); + return false; + } + } + } + } + } + return true; +} + +FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy) +{ + size_t len, lencopy; + if(blockcopy->type != block->type) { + printf("FAILED, type mismatch, expected %u, got %u\n", (uint32_t)block->type, (uint32_t)blockcopy->type); + return false; + } + len = strlen(block->mime_type); + lencopy = strlen(blockcopy->mime_type); + if(lencopy != len) { + printf("FAILED, mime_type length mismatch, expected %u, got %u\n", (uint32_t)len, (uint32_t)lencopy); + return false; + } + if(strcmp(blockcopy->mime_type, block->mime_type)) { + printf("FAILED, mime_type mismatch, expected %s, got %s\n", block->mime_type, blockcopy->mime_type); + return false; + } + len = strlen((const char *)block->description); + lencopy = strlen((const char *)blockcopy->description); + if(lencopy != len) { + printf("FAILED, description length mismatch, expected %u, got %u\n", (uint32_t)len, (uint32_t)lencopy); + return false; + } + if(strcmp((const char *)blockcopy->description, (const char *)block->description)) { + printf("FAILED, description mismatch, expected %s, got %s\n", block->description, blockcopy->description); + return false; + } + if(blockcopy->width != block->width) { + printf("FAILED, width mismatch, expected %u, got %u\n", block->width, blockcopy->width); + return false; + } + if(blockcopy->height != block->height) { + printf("FAILED, height mismatch, expected %u, got %u\n", block->height, blockcopy->height); + return false; + } + if(blockcopy->depth != block->depth) { + printf("FAILED, depth mismatch, expected %u, got %u\n", block->depth, blockcopy->depth); + return false; + } + if(blockcopy->colors != block->colors) { + printf("FAILED, colors mismatch, expected %u, got %u\n", block->colors, blockcopy->colors); + return false; + } + if(blockcopy->data_length != block->data_length) { + printf("FAILED, data_length mismatch, expected %u, got %u\n", block->data_length, blockcopy->data_length); + return false; + } + if(block->data_length > 0 && memcmp(blockcopy->data, block->data, block->data_length)) { + printf("FAILED, data mismatch\n"); + return false; + } + return true; +} + +FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, uint32_t block_length) +{ + if(0 == block->data || 0 == blockcopy->data) { + if(block->data != blockcopy->data) { + printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy"); + return false; + } + else if(block_length > 0) { + printf("FAILED, data pointer is null but block length is not 0\n"); + return false; + } + } + else { + if(block_length == 0) { + printf("FAILED, data pointer is not null but block length is 0\n"); + return false; + } + else if(0 != memcmp(blockcopy->data, block->data, block_length)) { + printf("FAILED, data mismatch\n"); + return false; + } + } + return true; +} + +FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy) +{ + if(blockcopy->type != block->type) { + printf("FAILED, type mismatch, expected %s, got %s\n", FLAC__MetadataTypeString[block->type], FLAC__MetadataTypeString[blockcopy->type]); + return false; + } + if(blockcopy->is_last != block->is_last) { + printf("FAILED, is_last mismatch, expected %u, got %u\n", (uint32_t)block->is_last, (uint32_t)blockcopy->is_last); + return false; + } + if(blockcopy->length != block->length) { + printf("FAILED, length mismatch, expected %u, got %u\n", block->length, blockcopy->length); + return false; + } + switch(block->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + return mutils__compare_block_data_streaminfo(&block->data.stream_info, &blockcopy->data.stream_info); + case FLAC__METADATA_TYPE_PADDING: + return mutils__compare_block_data_padding(&block->data.padding, &blockcopy->data.padding, block->length); + case FLAC__METADATA_TYPE_APPLICATION: + return mutils__compare_block_data_application(&block->data.application, &blockcopy->data.application, block->length); + case FLAC__METADATA_TYPE_SEEKTABLE: + return mutils__compare_block_data_seektable(&block->data.seek_table, &blockcopy->data.seek_table); + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + return mutils__compare_block_data_vorbiscomment(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment); + case FLAC__METADATA_TYPE_CUESHEET: + return mutils__compare_block_data_cuesheet(&block->data.cue_sheet, &blockcopy->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return mutils__compare_block_data_picture(&block->data.picture, &blockcopy->data.picture); + default: + return mutils__compare_block_data_unknown(&block->data.unknown, &blockcopy->data.unknown, block->length); + } +} + +static void *malloc_or_die_(size_t size) +{ + void *x = malloc(size); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)size); + exit(1); + } + return x; +} + +static void *calloc_or_die_(size_t n, size_t size) +{ + void *x = calloc(n, size); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (uint32_t)n * (uint32_t)size); + exit(1); + } + return x; +} + +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + +void mutils__init_metadata_blocks( + FLAC__StreamMetadata *streaminfo, + FLAC__StreamMetadata *padding, + FLAC__StreamMetadata *seektable, + FLAC__StreamMetadata *application1, + FLAC__StreamMetadata *application2, + FLAC__StreamMetadata *vorbiscomment, + FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, + FLAC__StreamMetadata *unknown +) +{ + /* + most of the actual numbers and data in the blocks don't matter, + we just want to make sure the decoder parses them correctly + + remember, the metadata interface gets tested after the decoders, + so we do all the metadata manipulation here without it. + */ + + /* min/max_framesize and md5sum don't get written at first, so we have to leave them 0 */ + streaminfo->is_last = false; + streaminfo->type = FLAC__METADATA_TYPE_STREAMINFO; + streaminfo->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + streaminfo->data.stream_info.min_blocksize = 576; + streaminfo->data.stream_info.max_blocksize = 576; + streaminfo->data.stream_info.min_framesize = 0; + streaminfo->data.stream_info.max_framesize = 0; + streaminfo->data.stream_info.sample_rate = 44100; + streaminfo->data.stream_info.channels = 1; + streaminfo->data.stream_info.bits_per_sample = 8; + streaminfo->data.stream_info.total_samples = 0; + memset(streaminfo->data.stream_info.md5sum, 0, 16); + + padding->is_last = false; + padding->type = FLAC__METADATA_TYPE_PADDING; + padding->length = 1234; + + seektable->is_last = false; + seektable->type = FLAC__METADATA_TYPE_SEEKTABLE; + seektable->data.seek_table.num_points = 2; + seektable->length = seektable->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; + seektable->data.seek_table.points = malloc_or_die_(seektable->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint)); + seektable->data.seek_table.points[0].sample_number = 0; + seektable->data.seek_table.points[0].stream_offset = 0; + seektable->data.seek_table.points[0].frame_samples = streaminfo->data.stream_info.min_blocksize; + seektable->data.seek_table.points[1].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + seektable->data.seek_table.points[1].stream_offset = 1000; + seektable->data.seek_table.points[1].frame_samples = streaminfo->data.stream_info.min_blocksize; + + application1->is_last = false; + application1->type = FLAC__METADATA_TYPE_APPLICATION; + application1->length = 8; + memcpy(application1->data.application.id, "This", 4); + application1->data.application.data = malloc_or_die_(4); + memcpy(application1->data.application.data, "\xf0\xe1\xd2\xc3", 4); + + application2->is_last = false; + application2->type = FLAC__METADATA_TYPE_APPLICATION; + application2->length = 4; + memcpy(application2->data.application.id, "Here", 4); + application2->data.application.data = 0; + + { + const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING); + vorbiscomment->is_last = false; + vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT; + vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0); + vorbiscomment->data.vorbis_comment.vendor_string.length = vendor_string_length; + vorbiscomment->data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1); + memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1); + vorbiscomment->data.vorbis_comment.num_comments = 2; + vorbiscomment->data.vorbis_comment.comments = malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); + vorbiscomment->data.vorbis_comment.comments[0].length = 5; + vorbiscomment->data.vorbis_comment.comments[0].entry = malloc_or_die_(5+1); + memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1); + vorbiscomment->data.vorbis_comment.comments[1].length = 0; + vorbiscomment->data.vorbis_comment.comments[1].entry = malloc_or_die_(1); + vorbiscomment->data.vorbis_comment.comments[1].entry[0] = '\0'; + } + + cuesheet->is_last = false; + cuesheet->type = FLAC__METADATA_TYPE_CUESHEET; + cuesheet->length = + /* cuesheet guts */ + ( + FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN + ) / 8 + + /* 2 tracks */ + 3 * ( + FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN + ) / 8 + + /* 3 index points */ + 3 * ( + FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN + ) / 8 + ; + memset(cuesheet->data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet->data.cue_sheet.media_catalog_number)); + cuesheet->data.cue_sheet.media_catalog_number[0] = 'j'; + cuesheet->data.cue_sheet.media_catalog_number[1] = 'C'; + cuesheet->data.cue_sheet.lead_in = 2 * 44100; + cuesheet->data.cue_sheet.is_cd = true; + cuesheet->data.cue_sheet.num_tracks = 3; + cuesheet->data.cue_sheet.tracks = calloc_or_die_(cuesheet->data.cue_sheet.num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); + cuesheet->data.cue_sheet.tracks[0].offset = 0; + cuesheet->data.cue_sheet.tracks[0].number = 1; + memcpy(cuesheet->data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet->data.cue_sheet.tracks[0].isrc)); + cuesheet->data.cue_sheet.tracks[0].type = 0; + cuesheet->data.cue_sheet.tracks[0].pre_emphasis = 1; + cuesheet->data.cue_sheet.tracks[0].num_indices = 2; + cuesheet->data.cue_sheet.tracks[0].indices = malloc_or_die_(cuesheet->data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); + cuesheet->data.cue_sheet.tracks[0].indices[0].offset = 0; + cuesheet->data.cue_sheet.tracks[0].indices[0].number = 0; + cuesheet->data.cue_sheet.tracks[0].indices[1].offset = 123 * 588; + cuesheet->data.cue_sheet.tracks[0].indices[1].number = 1; + cuesheet->data.cue_sheet.tracks[1].offset = 1234 * 588; + cuesheet->data.cue_sheet.tracks[1].number = 2; + memcpy(cuesheet->data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet->data.cue_sheet.tracks[1].isrc)); + cuesheet->data.cue_sheet.tracks[1].type = 1; + cuesheet->data.cue_sheet.tracks[1].pre_emphasis = 0; + cuesheet->data.cue_sheet.tracks[1].num_indices = 1; + cuesheet->data.cue_sheet.tracks[1].indices = malloc_or_die_(cuesheet->data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); + cuesheet->data.cue_sheet.tracks[1].indices[0].offset = 0; + cuesheet->data.cue_sheet.tracks[1].indices[0].number = 1; + cuesheet->data.cue_sheet.tracks[2].offset = 12345 * 588; + cuesheet->data.cue_sheet.tracks[2].number = 170; + cuesheet->data.cue_sheet.tracks[2].num_indices = 0; + + picture->is_last = false; + picture->type = FLAC__METADATA_TYPE_PICTURE; + picture->length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture->data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture->length += strlen(picture->data.picture.mime_type); + picture->data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture->length += strlen((const char *)picture->data.picture.description); + picture->data.picture.width = 300; + picture->data.picture.height = 300; + picture->data.picture.depth = 24; + picture->data.picture.colors = 0; + picture->data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture->data.picture.data_length = strlen((const char *)picture->data.picture.data); + picture->length += picture->data.picture.data_length; + + unknown->is_last = true; + unknown->type = 126; + unknown->length = 8; + unknown->data.unknown.data = malloc_or_die_(unknown->length); + memcpy(unknown->data.unknown.data, "\xfe\xdc\xba\x98\xf0\xe1\xd2\xc3", unknown->length); +} + +void mutils__free_metadata_blocks( + FLAC__StreamMetadata *streaminfo, + FLAC__StreamMetadata *padding, + FLAC__StreamMetadata *seektable, + FLAC__StreamMetadata *application1, + FLAC__StreamMetadata *application2, + FLAC__StreamMetadata *vorbiscomment, + FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, + FLAC__StreamMetadata *unknown +) +{ + (void)streaminfo, (void)padding, (void)application2; + free(seektable->data.seek_table.points); + free(application1->data.application.data); + free(vorbiscomment->data.vorbis_comment.vendor_string.entry); + free(vorbiscomment->data.vorbis_comment.comments[0].entry); + free(vorbiscomment->data.vorbis_comment.comments); + free(cuesheet->data.cue_sheet.tracks[0].indices); + free(cuesheet->data.cue_sheet.tracks[1].indices); + free(cuesheet->data.cue_sheet.tracks); + free(picture->data.picture.mime_type); + free(picture->data.picture.description); + free(picture->data.picture.data); + free(unknown->data.unknown.data); +} diff --git a/vendor/flac/src/test_seeking/CMakeLists.txt b/vendor/flac/src/test_seeking/CMakeLists.txt new file mode 100644 index 0000000..5144291 --- /dev/null +++ b/vendor/flac/src/test_seeking/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_seeking + main.c + $<$:../../include/share/win_utf8_io.h> + $<$:../share/win_utf8_io/win_utf8_io.c>) +target_link_libraries(test_seeking FLAC) diff --git a/vendor/flac/src/test_seeking/Makefile.am b/vendor/flac/src/test_seeking/Makefile.am new file mode 100644 index 0000000..9c9b8da --- /dev/null +++ b/vendor/flac/src/test_seeking/Makefile.am @@ -0,0 +1,39 @@ +# test_seeking - Seeking tester for libFLAC +# Copyright (C) 2004-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt + +AM_CFLAGS = @OGG_CFLAGS@ + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include + +check_PROGRAMS = test_seeking + +if OS_IS_WINDOWS +win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la +endif + +test_seeking_LDADD = \ + $(top_builddir)/src/libFLAC/libFLAC.la \ + $(win_utf8_lib) + +test_seeking_SOURCES = \ + main.c + +CLEANFILES = test_seeking.exe diff --git a/vendor/flac/src/test_seeking/main.c b/vendor/flac/src/test_seeking/main.c new file mode 100644 index 0000000..16ab9f4 --- /dev/null +++ b/vendor/flac/src/test_seeking/main.c @@ -0,0 +1,473 @@ +/* test_seeking - Seeking tester for libFLAC + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#if defined _MSC_VER || defined __MINGW32__ +#include +#else +#include +#endif +#include /* for stat() */ +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "FLAC/stream_decoder.h" +#include "share/compat.h" + +typedef struct { + FLAC__int32 **pcm; + FLAC__bool got_data; + FLAC__uint64 total_samples; + uint32_t channels; + uint32_t bits_per_sample; + FLAC__bool quiet; + FLAC__bool ignore_errors; + FLAC__bool error_occurred; +} DecoderClientData; + +static FLAC__bool stop_signal_ = false; + +static void our_sigint_handler_(int signum) +{ + (void)signum; + printf("(caught SIGINT) "); + fflush(stdout); + stop_signal_ = true; +} + +static FLAC__bool die_(const char *msg) +{ + printf("ERROR: %s\n", msg); + return false; +} + +static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder) +{ + FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder); + + if(msg) + printf("FAILED, %s", msg); + else + printf("FAILED"); + + printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamDecoderStateString[state]); + + return false; +} + +static uint32_t local_rand_(void) +{ +#if !defined _MSC_VER && !defined __MINGW32__ +#define RNDFUNC random +#else +#define RNDFUNC rand +#endif + /* every RAND_MAX I've ever seen is 2^15-1 or 2^31-1, so a little hackery here: */ + if (RAND_MAX > 32767) + return RNDFUNC(); + else /* usually MSVC, some solaris */ + return (RNDFUNC()<<15) | RNDFUNC(); +#undef RNDFUNC +} + +static FLAC__off_t get_filesize_(const char *srcpath) +{ + struct flac_stat_s srcstat; + + if(0 == flac_stat(srcpath, &srcstat)) + return srcstat.st_size; + else + return -1; +} + +static FLAC__bool read_pcm_(FLAC__int32 *pcm[], const char *rawfilename, const char *flacfilename) +{ + FILE *f; + uint32_t channels = 0, bps = 0, samples, i, j; + + FLAC__off_t rawfilesize = get_filesize_(rawfilename); + if (rawfilesize < 0) { + fprintf(stderr, "ERROR: can't determine filesize for %s\n", rawfilename); + return false; + } + /* get sample format from flac file; would just use FLAC__metadata_get_streaminfo() except it doesn't work for Ogg FLAC yet */ + { +#if 0 + FLAC__StreamMetadata streaminfo; + if(!FLAC__metadata_get_streaminfo(flacfilename, &streaminfo)) { + printf("ERROR: getting STREAMINFO from %s\n", flacfilename); + return false; + } + channels = streaminfo.data.stream_info.channels; + bps = streaminfo.data.stream_info.bits_per_sample; +#else + FLAC__bool ok = true; + FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new(); + FLAC__Metadata_Iterator *it = 0; + ok = ok && chain && (FLAC__metadata_chain_read(chain, flacfilename) || FLAC__metadata_chain_read_ogg(chain, flacfilename)); + ok = ok && (it = FLAC__metadata_iterator_new()); + if(ok) FLAC__metadata_iterator_init(it, chain); + ok = ok && (FLAC__metadata_iterator_get_block(it)->type == FLAC__METADATA_TYPE_STREAMINFO); + ok = ok && (channels = FLAC__metadata_iterator_get_block(it)->data.stream_info.channels); + ok = ok && (bps = FLAC__metadata_iterator_get_block(it)->data.stream_info.bits_per_sample); + if(it) FLAC__metadata_iterator_delete(it); + if(chain) FLAC__metadata_chain_delete(chain); + if(!ok) { + printf("ERROR: getting STREAMINFO from %s\n", flacfilename); + return false; + } +#endif + } + if(channels > 2) { + printf("ERROR: PCM verification requires 1 or 2 channels, got %u\n", channels); + return false; + } + if(bps != 8 && bps != 16) { + printf("ERROR: PCM verification requires 8 or 16 bps, got %u\n", bps); + return false; + } + samples = (uint32_t)(rawfilesize / channels / (bps>>3)); + if (samples > 10000000) { + fprintf(stderr, "ERROR: %s is too big\n", rawfilename); + return false; + } + for(i = 0; i < channels; i++) { + if(0 == (pcm[i] = malloc(sizeof(FLAC__int32)*samples))) { + printf("ERROR: allocating space for PCM samples\n"); + return false; + } + } + if(0 == (f = flac_fopen(rawfilename, "rb"))) { + printf("ERROR: opening %s for reading\n", rawfilename); + return false; + } + /* assumes signed big-endian data */ + if(bps == 8) { + signed char c; + for(i = 0; i < samples; i++) { + for(j = 0; j < channels; j++) { + if (fread(&c, 1, 1, f) == 1) + pcm[j][i] = c; + } + } + } + else { /* bps == 16 */ + uint8_t c[2]; + uint16_t value; + for(i = 0; i < samples; i++) { + for(j = 0; j < channels; j++) { + if (fread(&c, 1, 2, f) == 2) { + value = (c[0] << 8) | c[1]; + pcm[j][i] = value & 0x8000 ? 0xffff0000 | value : value; + } + } + } + } + fclose(f); + return true; +} + +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + DecoderClientData *dcd = (DecoderClientData*)client_data; + + (void)decoder, (void)buffer; + + if(0 == dcd) { + printf("ERROR: client_data in write callback is NULL\n"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + if(dcd->error_occurred) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); /* decoder guarantees this */ + if (!dcd->quiet) + printf("frame@%" PRIu64 "(%u)... ", frame->header.number.sample_number, frame->header.blocksize); + fflush(stdout); + + /* check against PCM data if we have it */ + if (dcd->pcm) { + uint32_t c, i, j; + for (c = 0; c < frame->header.channels; c++) + for (i = (uint32_t)frame->header.number.sample_number, j = 0; j < frame->header.blocksize; i++, j++) + if (buffer[c][j] != dcd->pcm[c][i]) { + printf("ERROR: sample mismatch at sample#%u(%u), channel=%u, expected %d, got %d\n", i, j, c, buffer[c][j], dcd->pcm[c][i]); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + DecoderClientData *dcd = (DecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in metadata callback is NULL\n"); + return; + } + + if(dcd->error_occurred) + return; + + if (!dcd->got_data && metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + dcd->got_data = true; + dcd->total_samples = metadata->data.stream_info.total_samples; + dcd->channels = metadata->data.stream_info.channels; + dcd->bits_per_sample = metadata->data.stream_info.bits_per_sample; + } +} + +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + DecoderClientData *dcd = (DecoderClientData*)client_data; + + (void)decoder; + + if(0 == dcd) { + printf("ERROR: client_data in error callback is NULL\n"); + return; + } + + if(!dcd->ignore_errors) { + printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, FLAC__StreamDecoderErrorStatusString[status]); + dcd->error_occurred = true; + } +} + +/* read mode: + * 0 - no read after seek + * 1 - read 2 frames + * 2 - read until end + */ +static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, FLAC__off_t filesize, uint32_t count, FLAC__int64 total_samples, uint32_t read_mode, FLAC__int32 **pcm) +{ + FLAC__StreamDecoder *decoder; + DecoderClientData decoder_client_data; + uint32_t i; + long int n; + + decoder_client_data.pcm = pcm; + decoder_client_data.got_data = false; + decoder_client_data.total_samples = 0; + decoder_client_data.quiet = false; + decoder_client_data.ignore_errors = false; + decoder_client_data.error_occurred = false; + + printf("\n+++ seek test: FLAC__StreamDecoder (%s FLAC, read_mode=%u)\n\n", is_ogg? "Ogg":"native", read_mode); + + decoder = FLAC__stream_decoder_new(); + if(0 == decoder) + return die_("FLAC__stream_decoder_new() FAILED, returned NULL\n"); + + if(is_ogg) { + if(FLAC__stream_decoder_init_ogg_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder); + } + else { + if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder); + } + + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + return die_s_("FLAC__stream_decoder_process_until_end_of_metadata() FAILED", decoder); + + if(!is_ogg) { /* not necessary to do this for Ogg because of its seeking method */ + /* process until end of stream to make sure we can still seek in that state */ + decoder_client_data.quiet = true; + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder); + decoder_client_data.quiet = false; + + printf("stream decoder state is %s\n", FLAC__stream_decoder_get_resolved_state_string(decoder)); + if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM) + return die_s_("expected FLAC__STREAM_DECODER_END_OF_STREAM", decoder); + } + + printf("file's total_samples is %" PRIu64 "\n", decoder_client_data.total_samples); + n = (long int)decoder_client_data.total_samples; + + if(n == 0 && total_samples >= 0) + n = (long int)total_samples; + + /* if we don't have a total samples count, just guess based on the file size */ + /* @@@ for is_ogg we should get it from last page's granulepos */ + if(n == 0) { + /* 8 would imply no compression, 9 guarantees that we will get some samples off the end of the stream to test that case */ + n = (long int)(9 * filesize / (decoder_client_data.channels * decoder_client_data.bits_per_sample)); + } + + printf("Begin seek barrage, count=%u\n", count); + + for (i = 0; !stop_signal_ && (count == 0 || i < count); i++) { + FLAC__uint64 pos; + + /* for the first 10, seek to the first 10 samples */ + if (n >= 10 && i < 10) { + pos = i; + } + /* for the second 10, seek to the last 10 samples */ + else if (n >= 10 && i < 20) { + pos = n - 1 - (i-10); + } + /* for the third 10, seek past the end and make sure we fail properly as expected */ + else if (i < 30) { + pos = n + (i-20); + } + else { + pos = (FLAC__uint64)(local_rand_() % n); + } + + printf("#%u:seek(%" PRIu64 ")... ", i, pos); + fflush(stdout); + if(!FLAC__stream_decoder_seek_absolute(decoder, pos)) { + if(pos >= (FLAC__uint64)n) + printf("seek past end failed as expected... "); + else if(decoder_client_data.total_samples == 0 && total_samples <= 0) + printf("seek failed, assuming it was past EOF... "); + else + return die_s_("FLAC__stream_decoder_seek_absolute() FAILED", decoder); + if(!FLAC__stream_decoder_flush(decoder)) + return die_s_("FLAC__stream_decoder_flush() FAILED", decoder); + } + else if(read_mode == 1) { + printf("decode_frame... "); + fflush(stdout); + if(!FLAC__stream_decoder_process_single(decoder)) + return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder); + + printf("decode_frame... "); + fflush(stdout); + if(!FLAC__stream_decoder_process_single(decoder)) + return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder); + } + else if(read_mode == 2) { + printf("decode_all... "); + fflush(stdout); + decoder_client_data.quiet = true; + if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) + return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder); + decoder_client_data.quiet = false; + } + + printf("OK\n"); + fflush(stdout); + } + stop_signal_ = false; + + if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) { + if(!FLAC__stream_decoder_finish(decoder)) + return die_s_("FLAC__stream_decoder_finish() FAILED", decoder); + } + + FLAC__stream_decoder_delete(decoder); + printf("\nPASSED!\n"); + + return true; +} + + +int main(int argc, char *argv[]) +{ + const char *flacfilename, *rawfilename = 0; + uint32_t count = 0, read_mode; + FLAC__int64 samples = -1; + FLAC__off_t flacfilesize; + FLAC__int32 *pcm[2] = { 0, 0 }; + FLAC__bool ok = true; + + static const char * const usage = "usage: test_seeking file.flac [#seeks] [#samples-in-file.flac] [file.raw]\n"; + + if (argc < 2 || argc > 5) { + fputs(usage, stderr); + return 1; + } + + flacfilename = argv[1]; + + if (argc > 2) + count = strtoul(argv[2], 0, 10); + if (argc > 3) + samples = strtoull(argv[3], 0, 10); + if (argc > 4) + rawfilename = argv[4]; + + if (count < 30) + fprintf(stderr, "WARNING: random seeks don't kick in until after 30 preprogrammed ones\n"); + +#if !defined _MSC_VER && !defined __MINGW32__ + { + struct timeval tv; + + if (gettimeofday(&tv, 0) < 0) { + fprintf(stderr, "WARNING: couldn't seed RNG with time\n"); + tv.tv_usec = 4321; + } + srandom(tv.tv_usec); + } +#else + srand((uint32_t)time(0)); +#endif + + flacfilesize = get_filesize_(flacfilename); + if (flacfilesize < 0) { + fprintf(stderr, "ERROR: can't determine filesize for %s\n", flacfilename); + return 1; + } + + if (rawfilename && !read_pcm_(pcm, rawfilename, flacfilename)) { + free(pcm[0]); + free(pcm[1]); + return 1; + } + + (void) signal(SIGINT, our_sigint_handler_); + + for (read_mode = 0; ok && read_mode <= 2; read_mode++) { + /* no need to do "decode all" read_mode if PCM checking is available */ + if (rawfilename && read_mode > 1) + continue; + if (strlen(flacfilename) > 4 && (0 == strcmp(flacfilename+strlen(flacfilename)-4, ".oga") || 0 == strcmp(flacfilename+strlen(flacfilename)-4, ".ogg"))) { +#if FLAC__HAS_OGG + ok = seek_barrage(/*is_ogg=*/true, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0); +#else + fprintf(stderr, "ERROR: Ogg FLAC not supported\n"); + ok = false; +#endif + } + else { + ok = seek_barrage(/*is_ogg=*/false, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0); + } + } + + free(pcm[0]); + free(pcm[1]); + + return ok? 0 : 2; +} diff --git a/vendor/flac/src/test_streams/CMakeLists.txt b/vendor/flac/src/test_streams/CMakeLists.txt new file mode 100644 index 0000000..f9fafb9 --- /dev/null +++ b/vendor/flac/src/test_streams/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(test_streams main.c) +target_link_libraries(test_streams FLAC grabbag) diff --git a/vendor/flac/src/test_streams/Makefile.am b/vendor/flac/src/test_streams/Makefile.am new file mode 100644 index 0000000..9aa4b02 --- /dev/null +++ b/vendor/flac/src/test_streams/Makefile.am @@ -0,0 +1,29 @@ +# test_streams - Simple test pattern generator +# Copyright (C) 2000-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt + +AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include +check_PROGRAMS = test_streams +test_streams_SOURCES = \ + main.c + +test_streams_LDADD = $(top_builddir)/src/share/grabbag/libgrabbag.la -lm + +CLEANFILES = test_streams.exe diff --git a/vendor/flac/src/test_streams/main.c b/vendor/flac/src/test_streams/main.c new file mode 100644 index 0000000..466bf8e --- /dev/null +++ b/vendor/flac/src/test_streams/main.c @@ -0,0 +1,1398 @@ +/* test_streams - Simple test pattern generator + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include "share/compat.h" +#if defined _MSC_VER || defined __MINGW32__ +#include +#else +#include +#endif +#include "FLAC/assert.h" +#include "FLAC/ordinals.h" +#include "share/compat.h" + +#if !defined _MSC_VER && !defined __MINGW32__ +#define GET_RANDOM_BYTE (((unsigned)random()) & 0xff) +#else +#define GET_RANDOM_BYTE (((unsigned)rand()) & 0xff) +#endif + +static FLAC__bool is_big_endian_host; + + +static FLAC__bool write_little_endian_unsigned(FILE *f, FLAC__uint32 x, size_t bytes) +{ + while(bytes) { + if(fputc(x, f) == EOF) + return false; + x >>= 8; + bytes--; + } + return true; +} + +static FLAC__bool write_little_endian_signed(FILE *f, FLAC__int32 x, size_t bytes) +{ + return write_little_endian_unsigned(f, (FLAC__uint32) x, bytes); +} + +static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 x) +{ + return + fputc(x, f) != EOF && + fputc(x >> 8, f) != EOF + ; +} + +static FLAC__bool write_little_endian_int16(FILE *f, FLAC__int16 x) +{ + return write_little_endian_uint16(f, (FLAC__uint16)x); +} + +static FLAC__bool write_little_endian_uint24(FILE *f, FLAC__uint32 x) +{ + return + fputc(x, f) != EOF && + fputc(x >> 8, f) != EOF && + fputc(x >> 16, f) != EOF + ; +} + +static FLAC__bool write_little_endian_int24(FILE *f, FLAC__int32 x) +{ + return write_little_endian_uint24(f, (FLAC__uint32)x); +} + +static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 x) +{ + return + fputc(x, f) != EOF && + fputc(x >> 8, f) != EOF && + fputc(x >> 16, f) != EOF && + fputc(x >> 24, f) != EOF + ; +} + +static FLAC__bool write_little_endian_int32(FILE *f, FLAC__int32 x) +{ + return write_little_endian_uint32(f, (FLAC__uint32)x); +} + +#if defined(_MSC_VER) +// silence 4 MSVC warnings 'conversion from 'FLAC__uint64' to 'int', possible loss of data' +#pragma warning ( disable : 4244 ) +#endif +static FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 x) +{ + return + fputc(x, f) != EOF && + fputc(x >> 8, f) != EOF && + fputc(x >> 16, f) != EOF && + fputc(x >> 24, f) != EOF && + fputc(x >> 32, f) != EOF && + fputc(x >> 40, f) != EOF && + fputc(x >> 48, f) != EOF && + fputc(x >> 56, f) != EOF + ; +} +#if defined(_MSC_VER) +#pragma warning ( default : 4244 ) +#endif + +static FLAC__bool write_big_endian(FILE *f, FLAC__int32 x, size_t bytes) +{ + if(bytes < 4) + x <<= 8*(4-bytes); + while(bytes) { + if(fputc(x>>24, f) == EOF) + return false; + x <<= 8; + bytes--; + } + return true; +} + +static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 x) +{ + return + fputc(x >> 8, f) != EOF && + fputc(x, f) != EOF + ; +} + +#if 0 +/* @@@ not used (yet) */ +static FLAC__bool write_big_endian_int16(FILE *f, FLAC__int16 x) +{ + return write_big_endian_uint16(f, (FLAC__uint16)x); +} +#endif + +#if 0 +/* @@@ not used (yet) */ +static FLAC__bool write_big_endian_uint24(FILE *f, FLAC__uint32 x) +{ + return + fputc(x >> 16, f) != EOF && + fputc(x >> 8, f) != EOF && + fputc(x, f) != EOF + ; +} +#endif + +#if 0 +/* @@@ not used (yet) */ +static FLAC__bool write_big_endian_int24(FILE *f, FLAC__int32 x) +{ + return write_big_endian_uint24(f, (FLAC__uint32)x); +} +#endif + +static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 x) +{ + return + fputc(x >> 24, f) != EOF && + fputc(x >> 16, f) != EOF && + fputc(x >> 8, f) != EOF && + fputc(x, f) != EOF + ; +} + +#if 0 +/* @@@ not used (yet) */ +static FLAC__bool write_big_endian_int32(FILE *f, FLAC__int32 x) +{ + return write_big_endian_uint32(f, (FLAC__uint32)x); +} +#endif + +static FLAC__bool write_sane_extended(FILE *f, unsigned val) + /* Write to 'f' a SANE extended representation of 'val'. Return false if + * the write succeeds; return true otherwise. + * + * SANE extended is an 80-bit IEEE-754 representation with sign bit, 15 bits + * of exponent, and 64 bits of significand (mantissa). Unlike most IEEE-754 + * representations, it does not imply a 1 above the MSB of the significand. + * + * Preconditions: + * val!=0U + */ +{ + unsigned int shift, exponent; + + FLAC__ASSERT(val!=0U); /* handling 0 would require a special case */ + + for(shift= 0U; (val>>(31-shift))==0U; ++shift) + ; + val<<= shift; + exponent= 63U-(shift+32U); /* add 32 for unused second word */ + + if(!write_big_endian_uint16(f, (FLAC__uint16)(exponent+0x3FFF))) + return false; + if(!write_big_endian_uint32(f, val)) + return false; + if(!write_big_endian_uint32(f, 0)) /* unused second word */ + return false; + + return true; +} + +/* a mono one-sample 16bps stream */ +static FLAC__bool generate_01(void) +{ + FILE *f; + FLAC__int16 x = -32768; + + if(0 == (f = fopen("test01.raw", "wb"))) + return false; + + if(!write_little_endian_int16(f, x)) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo one-sample 16bps stream */ +static FLAC__bool generate_02(void) +{ + FILE *f; + FLAC__int16 xl = -32768, xr = 32767; + + if(0 == (f = fopen("test02.raw", "wb"))) + return false; + + if(!write_little_endian_int16(f, xl)) + goto foo; + if(!write_little_endian_int16(f, xr)) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono five-sample 16bps stream */ +static FLAC__bool generate_03(void) +{ + FILE *f; + FLAC__int16 x[] = { -25, 0, 25, 50, 100 }; + unsigned i; + + if(0 == (f = fopen("test03.raw", "wb"))) + return false; + + for(i = 0; i < 5; i++) + if(!write_little_endian_int16(f, x[i])) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo five-sample 16bps stream */ +static FLAC__bool generate_04(void) +{ + FILE *f; + FLAC__int16 x[] = { -25, 500, 0, 400, 25, 300, 50, 200, 100, 100 }; + unsigned i; + + if(0 == (f = fopen("test04.raw", "wb"))) + return false; + + for(i = 0; i < 10; i++) + if(!write_little_endian_int16(f, x[i])) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono full-scale deflection 8bps stream */ +static FLAC__bool generate_fsd8(const char *fn, const int pattern[], unsigned reps) +{ + FILE *f; + unsigned rep, p; + + FLAC__ASSERT(pattern != 0); + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(rep = 0; rep < reps; rep++) { + for(p = 0; pattern[p]; p++) { + signed char x = pattern[p] > 0? 127 : -128; + if(fwrite(&x, sizeof(x), 1, f) < 1) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono full-scale deflection 16bps stream */ +static FLAC__bool generate_fsd16(const char *fn, const int pattern[], unsigned reps) +{ + FILE *f; + unsigned rep, p; + + FLAC__ASSERT(pattern != 0); + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(rep = 0; rep < reps; rep++) { + for(p = 0; pattern[p]; p++) { + FLAC__int16 x = pattern[p] > 0? 32767 : -32768; + if(!write_little_endian_int16(f, x)) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo wasted-bits-per-sample 16bps stream */ +static FLAC__bool generate_wbps16(const char *fn, unsigned samples) +{ + FILE *f; + unsigned sample; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(sample = 0; sample < samples; sample++) { + FLAC__int16 l = (sample % 2000) << 2; + FLAC__int16 r = (sample % 1000) << 3; + if(!write_little_endian_int16(f, l)) + goto foo; + if(!write_little_endian_int16(f, r)) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono full-scale deflection 24bps stream */ +static FLAC__bool generate_fsd24(const char *fn, const int pattern[], unsigned reps) +{ + FILE *f; + unsigned rep, p; + + FLAC__ASSERT(pattern != 0); + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(rep = 0; rep < reps; rep++) { + for(p = 0; pattern[p]; p++) { + FLAC__int32 x = pattern[p] > 0? 8388607 : -8388608; + if(!write_little_endian_int24(f, x)) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono full-scale deflection 32bps stream */ +static FLAC__bool generate_fsd32(const char *fn, const int pattern[], unsigned reps) +{ + FILE *f; + unsigned rep, p; + + FLAC__ASSERT(pattern != 0); + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(rep = 0; rep < reps; rep++) { + for(p = 0; pattern[p]; p++) { + FLAC__int32 x = pattern[p] > 0? 2147483647 : -2147483648; + if(!write_little_endian_int32(f, x)) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono sine-wave 8bps stream */ +static FLAC__bool generate_sine8_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2) +{ + const FLAC__int8 full_scale = 127; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int8 v = (FLAC__int8)(val + 0.5); + if(fwrite(&v, sizeof(v), 1, f) < 1) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo sine-wave 8bps stream */ +static FLAC__bool generate_sine8_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult) +{ + const FLAC__int8 full_scale = 127; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int8 v = (FLAC__int8)(val + 0.5); + if(fwrite(&v, sizeof(v), 1, f) < 1) + goto foo; + val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale; + v = (FLAC__int8)(val + 0.5); + if(fwrite(&v, sizeof(v), 1, f) < 1) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono sine-wave 16bps stream */ +static FLAC__bool generate_sine16_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2) +{ + const FLAC__int16 full_scale = 32767; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int16 v = (FLAC__int16)(val + 0.5); + if(!write_little_endian_int16(f, v)) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo sine-wave 16bps stream */ +static FLAC__bool generate_sine16_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult) +{ + const FLAC__int16 full_scale = 32767; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int16 v = (FLAC__int16)(val + 0.5); + if(!write_little_endian_int16(f, v)) + goto foo; + val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale; + v = (FLAC__int16)(val + 0.5); + if(!write_little_endian_int16(f, v)) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono sine-wave 24bps stream */ +static FLAC__bool generate_sine24_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2) +{ + const FLAC__int32 full_scale = 0x7fffff; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = (FLAC__int32)(val + 0.5); + if(!write_little_endian_int24(f, v)) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo sine-wave 24bps stream */ +static FLAC__bool generate_sine24_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult) +{ + const FLAC__int32 full_scale = 0x7fffff; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = (FLAC__int32)(val + 0.5); + if(!write_little_endian_int24(f, v)) + goto foo; + val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale; + v = (FLAC__int32)(val + 0.5); + if(!write_little_endian_int24(f, v)) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono sine-wave 32bps stream */ +static FLAC__bool generate_sine32_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2) +{ + const FLAC__int32 full_scale = 0x7fffffff; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = (FLAC__int32)(val + 0.5); + if(!write_little_endian_int32(f, v)) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo sine-wave 32bps stream */ +static FLAC__bool generate_sine32_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult) +{ + const FLAC__int32 full_scale = 0x7fffffff; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = (FLAC__int32)(val + 0.5); + if(!write_little_endian_int32(f, v)) + goto foo; + val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale; + v = (FLAC__int32)(val + 0.5); + if(!write_little_endian_int32(f, v)) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_noise(const char *fn, unsigned bytes) +{ + FILE *f; + unsigned b; + + if(0 == (f = fopen(fn, "wb"))) + return false; + + for(b = 0; b < bytes; b++) { +#if !defined _MSC_VER && !defined __MINGW32__ + FLAC__byte x = (FLAC__byte)(((unsigned)random()) & 0xff); +#else + FLAC__byte x = (FLAC__byte)(((unsigned)rand()) & 0xff); +#endif + if(fwrite(&x, sizeof(x), 1, f) < 1) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_signed_raw(const char *filename, unsigned channels, unsigned bytes_per_sample, unsigned samples) +{ + const FLAC__int32 full_scale = (1 << (bytes_per_sample*8-1)) - 1; + const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37; + const double delta1 = 2.0 * M_PI / ( 44100.0 / f1); + const double delta2 = 2.0 * M_PI / ( 44100.0 / f2); + double theta1, theta2; + FILE *f; + unsigned i, j; + + if(0 == (f = fopen(filename, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + for(j = 0; j < channels; j++) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = (FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8); + if(!write_little_endian_signed(f, v, bytes_per_sample)) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_unsigned_raw(const char *filename, unsigned channels, unsigned bytes_per_sample, unsigned samples) +{ + const FLAC__int32 full_scale = (1 << (bytes_per_sample*8-1)) - 1; + const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37; + const double delta1 = 2.0 * M_PI / ( 44100.0 / f1); + const double delta2 = 2.0 * M_PI / ( 44100.0 / f2); + const double half_scale = 0.5 * full_scale; + double theta1, theta2; + FILE *f; + unsigned i, j; + + if(0 == (f = fopen(filename, "wb"))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + for(j = 0; j < channels; j++) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = (FLAC__int32)(half_scale + val + 0.5) + ((GET_RANDOM_BYTE>>4)-8); + if(!write_little_endian_unsigned(f, v, bytes_per_sample)) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples) +{ + const unsigned bytes_per_sample = (bps+7)/8; + const unsigned true_size = channels * bytes_per_sample * samples; + const unsigned padded_size = (true_size + 1) & (~1u); + const unsigned shift = (bps%8)? 8 - (bps%8) : 0; + const FLAC__int32 full_scale = (1 << (bps-1)) - 1; + const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + double theta1, theta2; + FILE *f; + unsigned i, j; + + if(0 == (f = fopen(filename, "wb"))) + return false; + if(fwrite("FORM", 1, 4, f) < 4) + goto foo; + if(!write_big_endian_uint32(f, padded_size + 46)) + goto foo; + if(fwrite("AIFFCOMM\000\000\000\022", 1, 12, f) < 12) + goto foo; + if(!write_big_endian_uint16(f, (FLAC__uint16)channels)) + goto foo; + if(!write_big_endian_uint32(f, samples)) + goto foo; + if(!write_big_endian_uint16(f, (FLAC__uint16)bps)) + goto foo; + if(!write_sane_extended(f, sample_rate)) + goto foo; + if(fwrite("SSND", 1, 4, f) < 4) + goto foo; + if(!write_big_endian_uint32(f, true_size + 8)) + goto foo; + if(fwrite("\000\000\000\000\000\000\000\000", 1, 8, f) < 8) + goto foo; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + for(j = 0; j < channels; j++) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift; + if(!write_big_endian(f, v, bytes_per_sample)) + goto foo; + } + } + for(i = true_size; i < padded_size; i++) + if(fputc(0, f) == EOF) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* flavor is: 0:WAVE, 1:RF64, 2:WAVE64 */ +static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict, int flavor) +{ + const FLAC__bool waveformatextensible = strict && (channels > 2 || (bps != 8 && bps != 16)); + + const unsigned bytes_per_sample = (bps+7)/8; + const unsigned shift = (bps%8)? 8 - (bps%8) : 0; + /* this rig is not going over 4G so we're ok with 32-bit sizes here */ + const FLAC__uint32 true_size = channels * bytes_per_sample * samples; + const FLAC__uint32 padded_size = flavor<2? (true_size + 1) & (~1u) : (true_size + 7) & (~7u); + const FLAC__int32 full_scale = (1 << (bps-1)) - 1; + const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + double theta1, theta2; + FILE *f; + unsigned i, j; + + if(0 == (f = fopen(filename, "wb"))) + return false; + /* RIFFxxxxWAVE or equivalent: */ + switch(flavor) { + case 0: + if(fwrite("RIFF", 1, 4, f) < 4) + goto foo; + /* +4 for WAVE */ + /* +8+{40,16} for fmt chunk */ + /* +8 for data chunk header */ + if(!write_little_endian_uint32(f, 4 + 8+(waveformatextensible?40:16) + 8 + padded_size)) + goto foo; + if(fwrite("WAVE", 1, 4, f) < 4) + goto foo; + break; + case 1: + if(fwrite("RF64", 1, 4, f) < 4) + goto foo; + if(!write_little_endian_uint32(f, 0xffffffff)) + goto foo; + if(fwrite("WAVE", 1, 4, f) < 4) + goto foo; + break; + case 2: + /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */ + if(fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 1, 16, f) < 16) + goto foo; + /* +(16+8) for RIFF GUID + size */ + /* +16 for WAVE GUID */ + /* +16+8+{40,16} for fmt chunk */ + /* +16+8 for data chunk header */ + if(!write_little_endian_uint64(f, (16+8) + 16 + 16+8+(waveformatextensible?40:16) + (16+8) + padded_size)) + goto foo; + /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ + if(fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16) + goto foo; + break; + default: + goto foo; + } + if(flavor == 1) { /* rf64 */ + if(fwrite("ds64", 1, 4, f) < 4) + goto foo; + if(!write_little_endian_uint32(f, 28)) /* ds64 chunk size */ + goto foo; + if(!write_little_endian_uint64(f, 36 + padded_size + (waveformatextensible?60:36))) + goto foo; + if(!write_little_endian_uint64(f, true_size)) + goto foo; + if(!write_little_endian_uint64(f, samples)) + goto foo; + if(!write_little_endian_uint32(f, 0)) /* table size */ + goto foo; + } + /* fmt chunk */ + if(flavor < 2) { + if(fwrite("fmt ", 1, 4, f) < 4) + goto foo; + /* chunk size */ + if(!write_little_endian_uint32(f, waveformatextensible?40:16)) + goto foo; + } + else { /* wave64 */ + /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ + if(fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16) + goto foo; + /* chunk size (+16+8 for GUID and size fields) */ + if(!write_little_endian_uint64(f, 16+8+(waveformatextensible?40:16))) + goto foo; + } + if(!write_little_endian_uint16(f, (FLAC__uint16)(waveformatextensible?65534:1))) + goto foo; + if(!write_little_endian_uint16(f, (FLAC__uint16)channels)) + goto foo; + if(!write_little_endian_uint32(f, sample_rate)) + goto foo; + if(!write_little_endian_uint32(f, sample_rate * channels * bytes_per_sample)) + goto foo; + if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * bytes_per_sample))) /* block align */ + goto foo; + if(!write_little_endian_uint16(f, (FLAC__uint16)(bps+shift))) + goto foo; + if(waveformatextensible) { + if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */ + goto foo; + if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */ + goto foo; + if(!write_little_endian_uint32(f, 0)) /* channelMask */ + goto foo; + /* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */ + if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16) + goto foo; + } + /* data chunk */ + if(flavor < 2) { + if(fwrite("data", 1, 4, f) < 4) + goto foo; + if(!write_little_endian_uint32(f, flavor==1? 0xffffffff : true_size)) + goto foo; + } + else { /* wave64 */ + /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ + if(fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16) + goto foo; + /* +16+8 for GUID and size fields */ + if(!write_little_endian_uint64(f, 16+8 + true_size)) + goto foo; + } + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + for(j = 0; j < channels; j++) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift; + if(!write_little_endian_signed(f, v, bytes_per_sample)) + goto foo; + } + } + for(i = true_size; i < padded_size; i++) + if(fputc(0, f) == EOF) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_wackywavs(void) +{ + FILE *f; + FLAC__byte wav[] = { + 'R', 'I', 'F', 'F', 76, 0, 0, 0, + 'W', 'A', 'V', 'E', 'j', 'u', 'n', 'k', + 4, 0, 0, 0 , 'b', 'l', 'a', 'h', + 'p', 'a', 'd', ' ', 4, 0, 0, 0, + 'B', 'L', 'A', 'H', 'f', 'm', 't', ' ', + 16, 0, 0, 0, 1, 0, 1, 0, + 0x44,0xAC, 0, 0,0x88,0x58,0x01, 0, + 2, 0, 16, 0, 'd', 'a', 't', 'a', + 16, 0, 0, 0, 0, 0, 1, 0, + 4, 0, 9, 0, 16, 0, 25, 0, + 36, 0, 49, 0, 'p', 'a', 'd', ' ', + 4, 0, 0, 0, 'b', 'l', 'a', 'h' + }; + + if(0 == (f = fopen("wacky1.wav", "wb"))) + return false; + if(fwrite(wav, 1, 84, f) < 84) + goto foo; + fclose(f); + + wav[4] += 12; + if(0 == (f = fopen("wacky2.wav", "wb"))) + return false; + if(fwrite(wav, 1, 96, f) < 96) + goto foo; + fclose(f); + + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool write_simple_wavex_header (FILE * f, unsigned samplerate, unsigned channels, unsigned bytespersample, unsigned frames) +{ + unsigned datalen = channels * bytespersample * frames ; + + if (fwrite("RIFF", 1, 4, f) != 4) + return false; + if (!write_little_endian_uint32(f, 60 + datalen)) + return false; + + if (fwrite("WAVEfmt ", 8, 1, f) != 1) + return false; + if (!write_little_endian_uint32(f, 40)) + return false; + + if(!write_little_endian_uint16(f, 65534)) /* WAVEFORMATEXTENSIBLE tag */ + return false; + if(!write_little_endian_uint16(f, channels)) + return false; + if(!write_little_endian_uint32(f, samplerate)) + return false; + if(!write_little_endian_uint32(f, samplerate * channels * bytespersample)) + return false; + if(!write_little_endian_uint16(f, channels * bytespersample)) /* block align */ + return false; + if(!write_little_endian_uint16(f, bytespersample * 8)) + return false; + + if(!write_little_endian_uint16(f, 22)) /* cbSize */ + return false; + if(!write_little_endian_uint16(f, bytespersample * 8)) /* validBitsPerSample */ + return false; + if(!write_little_endian_uint32(f, 0)) /* channelMask */ + return false; + /* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */ + if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16) + return false; + + if (fwrite("data", 1, 4, f) != 4) + return false; + if (!write_little_endian_uint32(f, datalen)) + return false; + + return true; +} + +static FLAC__bool generate_noisy_sine(void) +{ + FILE *f; + int64_t randstate = 0x1243456; + double sample, last_val = 0.0; + int k; + int seconds = 300; + + if(0 == (f = fopen("noisy-sine.wav", "wb"))) + return false; + + if(!write_simple_wavex_header (f, 44100, 1, 2, 44100*seconds)) + goto foo; + + for (k = 0 ; k < seconds * 44100 ; k++) { + /* Obvioulsy not a crypto quality RNG. */ + randstate = 11117 * randstate + 211231; + randstate = 11117 * randstate + 211231; + randstate = 11117 * randstate + 211231; + + sample = ((int32_t) randstate) / (0x7fffffff * 1.000001); + sample = 0.2 * sample - 0.9 * last_val; + + last_val = sample; + + sample += sin (2.0 * k * M_PI * 1.0 / 32.0); + sample *= 0.4; +#if !defined _MSC_VER + write_little_endian_int16(f, lrintf(sample * 32700.0)); +#else + write_little_endian_int16(f, (FLAC__int16)(sample * 32700.0)); +#endif + }; + + fclose(f); + + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_wackywav64s(void) +{ + FILE *f; + FLAC__byte wav[] = { + 0x72,0x69,0x66,0x66,0x2E,0x91,0xCF,0x11, /* RIFF GUID */ + 0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00, + 152, 0, 0, 0, 0, 0, 0, 0, + 0x77,0x61,0x76,0x65,0xF3,0xAC,0xD3,0x11, /* WAVE GUID */ + 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A, + 0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */ + 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A, + 32, 0, 0, 0 , 0, 0, 0, 0, + 'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h', + 0x66,0x6D,0x74,0x20,0xF3,0xAC,0xD3,0x11, /* fmt GUID */ + 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A, + 40, 0, 0, 0 , 0, 0, 0, 0, + 1, 0, 1, 0,0x44,0xAC, 0, 0, + 0x88,0x58,0x01, 0, 2, 0, 16, 0, + 0x64,0x61,0x74,0x61,0xF3,0xAC,0xD3,0x11, /* data GUID */ + 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A, + 40, 0, 0, 0 , 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 9, 0, + 16, 0, 25, 0, 36, 0, 49, 0, + 0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */ + 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A, + 32, 0, 0, 0 , 0, 0, 0, 0, + 'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h' + }; + + if(0 == (f = fopen("wacky1.w64", "wb"))) + return false; + if(fwrite(wav, 1, wav[16], f) < wav[16]) + goto foo; + fclose(f); + + wav[16] += 32; + if(0 == (f = fopen("wacky2.w64", "wb"))) + return false; + if(fwrite(wav, 1, wav[16], f) < wav[16]) + goto foo; + fclose(f); + + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_wackyrf64s(void) +{ + FILE *f; + FLAC__byte wav[] = { + 'R', 'F', '6', '4', 255, 255, 255, 255, + 'W', 'A', 'V', 'E', 'd', 's', '6', '4', + 28, 0, 0, 0, 112, 0, 0, 0, + 0, 0, 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 'j', 'u', 'n', 'k', + 4, 0, 0, 0, 'b', 'l', 'a', 'h', + 'p', 'a', 'd', ' ', 4, 0, 0, 0, + 'B', 'L', 'A', 'H', 'f', 'm', 't', ' ', + 16, 0, 0, 0, 1, 0, 1, 0, + 0x44,0xAC, 0, 0,0x88,0x58,0x01, 0, + 2, 0, 16, 0, 'd', 'a', 't', 'a', + 255, 255, 255, 255, 0, 0, 1, 0, + 4, 0, 9, 0, 16, 0, 25, 0, + 36, 0, 49, 0, 'p', 'a', 'd', ' ', + 4, 0, 0, 0, 'b', 'l', 'a', 'h' + }; + + if(0 == (f = fopen("wacky1.rf64", "wb"))) + return false; + if(fwrite(wav, 1, 120, f) < 120) + goto foo; + fclose(f); + + wav[20] += 12; + if(0 == (f = fopen("wacky2.rf64", "wb"))) + return false; + if(fwrite(wav, 1, 132, f) < 132) + goto foo; + fclose(f); + + return true; +foo: + fclose(f); + return false; +} + +static FLAC__bool generate_replaygain_tone (unsigned samplerate) +{ + FILE *f; + char fname [256] ; + double tone, sample, samplerange; + int k; + + flac_snprintf(fname, sizeof(fname), "rpg-tone-%u.wav", samplerate); + + if(0 == (f = fopen(fname, "wb"))) + return false; + + if(!write_simple_wavex_header (f, samplerate, 1, 3, 220500)) + goto foo; + + + samplerange = 0x7fffff; /* Largest sample value allowed for a 24 bit PCM file. */ + tone = 1000.0; /* 1 kHz */ + + for (k = 0 ; k < 5 * 44100 ; k++) { + sample = sin(2 * M_PI * tone * k / samplerate); + sample *= samplerange; + if (!write_little_endian_uint24(f, (FLAC__int32) sample)) + goto foo; + }; + + fclose(f); + + return true; +foo: + fclose(f); + return false; +} + +int main(int argc, char *argv[]) +{ + FLAC__uint32 test = 1; + unsigned channels; + + int pattern01[] = { 1, -1, 0 }; + int pattern02[] = { 1, 1, -1, 0 }; + int pattern03[] = { 1, -1, -1, 0 }; + int pattern04[] = { 1, -1, 1, -1, 0 }; + int pattern05[] = { 1, -1, -1, 1, 0 }; + int pattern06[] = { 1, -1, 1, 1, -1, 0 }; + int pattern07[] = { 1, -1, -1, 1, -1, 0 }; + + (void)argc; + (void)argv; + is_big_endian_host = (*((FLAC__byte*)(&test)))? false : true; + +#if !defined _MSC_VER && !defined __MINGW32__ + { + struct timeval tv; + + if(gettimeofday(&tv, 0) < 0) { + fprintf(stderr, "WARNING: couldn't seed RNG with time\n"); + tv.tv_usec = 4321; + } + srandom(tv.tv_usec); + } +#else + srand((unsigned)time(0)); +#endif + + if(!generate_01()) return 1; + if(!generate_02()) return 1; + if(!generate_03()) return 1; + if(!generate_04()) return 1; + + if(!generate_fsd8("fsd8-01.raw", pattern01, 100)) return 1; + if(!generate_fsd8("fsd8-02.raw", pattern02, 100)) return 1; + if(!generate_fsd8("fsd8-03.raw", pattern03, 100)) return 1; + if(!generate_fsd8("fsd8-04.raw", pattern04, 100)) return 1; + if(!generate_fsd8("fsd8-05.raw", pattern05, 100)) return 1; + if(!generate_fsd8("fsd8-06.raw", pattern06, 100)) return 1; + if(!generate_fsd8("fsd8-07.raw", pattern07, 100)) return 1; + + if(!generate_fsd16("fsd16-01.raw", pattern01, 100)) return 1; + if(!generate_fsd16("fsd16-02.raw", pattern02, 100)) return 1; + if(!generate_fsd16("fsd16-03.raw", pattern03, 100)) return 1; + if(!generate_fsd16("fsd16-04.raw", pattern04, 100)) return 1; + if(!generate_fsd16("fsd16-05.raw", pattern05, 100)) return 1; + if(!generate_fsd16("fsd16-06.raw", pattern06, 100)) return 1; + if(!generate_fsd16("fsd16-07.raw", pattern07, 100)) return 1; + + if(!generate_fsd24("fsd24-01.raw", pattern01, 100)) return 1; + if(!generate_fsd24("fsd24-02.raw", pattern02, 100)) return 1; + if(!generate_fsd24("fsd24-03.raw", pattern03, 100)) return 1; + if(!generate_fsd24("fsd24-04.raw", pattern04, 100)) return 1; + if(!generate_fsd24("fsd24-05.raw", pattern05, 100)) return 1; + if(!generate_fsd24("fsd24-06.raw", pattern06, 100)) return 1; + if(!generate_fsd24("fsd24-07.raw", pattern07, 100)) return 1; + + if(!generate_fsd32("fsd32-01.raw", pattern01, 100)) return 1; + if(!generate_fsd32("fsd32-02.raw", pattern02, 100)) return 1; + if(!generate_fsd32("fsd32-03.raw", pattern03, 100)) return 1; + if(!generate_fsd32("fsd32-04.raw", pattern04, 100)) return 1; + if(!generate_fsd32("fsd32-05.raw", pattern05, 100)) return 1; + if(!generate_fsd32("fsd32-06.raw", pattern06, 100)) return 1; + if(!generate_fsd32("fsd32-07.raw", pattern07, 100)) return 1; + + if(!generate_wbps16("wbps16-01.raw", 1000)) return 1; + + if(!generate_sine8_1("sine8-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1; + if(!generate_sine8_1("sine8-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1; + if(!generate_sine8_1("sine8-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1; + if(!generate_sine8_1("sine8-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1; + if(!generate_sine8_1("sine8-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1; + + if(!generate_sine8_2("sine8-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1; + if(!generate_sine8_2("sine8-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1; + if(!generate_sine8_2("sine8-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1; + if(!generate_sine8_2("sine8-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1; + if(!generate_sine8_2("sine8-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1; + if(!generate_sine8_2("sine8-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1; + if(!generate_sine8_2("sine8-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1; + if(!generate_sine8_2("sine8-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1; + if(!generate_sine8_2("sine8-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1; + if(!generate_sine8_2("sine8-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1; + + if(!generate_sine16_1("sine16-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1; + if(!generate_sine16_1("sine16-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1; + if(!generate_sine16_1("sine16-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1; + if(!generate_sine16_1("sine16-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1; + if(!generate_sine16_1("sine16-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1; + + if(!generate_sine16_2("sine16-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1; + if(!generate_sine16_2("sine16-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1; + if(!generate_sine16_2("sine16-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1; + if(!generate_sine16_2("sine16-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1; + if(!generate_sine16_2("sine16-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1; + if(!generate_sine16_2("sine16-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1; + if(!generate_sine16_2("sine16-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1; + if(!generate_sine16_2("sine16-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1; + if(!generate_sine16_2("sine16-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1; + if(!generate_sine16_2("sine16-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1; + + if(!generate_sine24_1("sine24-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1; + if(!generate_sine24_1("sine24-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1; + if(!generate_sine24_1("sine24-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1; + if(!generate_sine24_1("sine24-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1; + if(!generate_sine24_1("sine24-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1; + + if(!generate_sine24_2("sine24-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1; + if(!generate_sine24_2("sine24-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1; + if(!generate_sine24_2("sine24-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1; + if(!generate_sine24_2("sine24-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1; + if(!generate_sine24_2("sine24-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1; + if(!generate_sine24_2("sine24-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1; + if(!generate_sine24_2("sine24-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1; + if(!generate_sine24_2("sine24-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1; + if(!generate_sine24_2("sine24-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1; + if(!generate_sine24_2("sine24-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1; + + if(!generate_sine32_1("sine32-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1; + if(!generate_sine32_1("sine32-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1; + if(!generate_sine32_1("sine32-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1; + if(!generate_sine32_1("sine32-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1; + if(!generate_sine32_1("sine32-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1; + + if(!generate_sine32_2("sine32-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1; + if(!generate_sine32_2("sine32-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1; + if(!generate_sine32_2("sine32-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1; + if(!generate_sine32_2("sine32-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1; + if(!generate_sine32_2("sine32-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1; + if(!generate_sine32_2("sine32-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1; + if(!generate_sine32_2("sine32-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1; + if(!generate_sine32_2("sine32-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1; + if(!generate_sine32_2("sine32-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1; + if(!generate_sine32_2("sine32-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1; + + if(!generate_replaygain_tone(8000)) return 1; + if(!generate_replaygain_tone(11025)) return 1; + if(!generate_replaygain_tone(12000)) return 1; + if(!generate_replaygain_tone(16000)) return 1; + if(!generate_replaygain_tone(18900)) return 1; + if(!generate_replaygain_tone(22050)) return 1; + if(!generate_replaygain_tone(24000)) return 1; + if(!generate_replaygain_tone(28000)) return 1; + if(!generate_replaygain_tone(32000)) return 1; + if(!generate_replaygain_tone(36000)) return 1; + if(!generate_replaygain_tone(37800)) return 1; + if(!generate_replaygain_tone(44100)) return 1; + if(!generate_replaygain_tone(48000)) return 1; + if(!generate_replaygain_tone(96000)) return 1; + if(!generate_replaygain_tone(192000)) return 1; + + /* WATCHOUT: the size of noise.raw is hardcoded into test/test_flac.sh */ + if(!generate_noise("noise.raw", 65536 * 8 * 3)) return 1; + if(!generate_noise("noise8m32.raw", 32)) return 1; + if(!generate_wackywavs()) return 1; + if(!generate_wackywav64s()) return 1; + if(!generate_wackyrf64s()) return 1; + if(!generate_noisy_sine()) return 1; + for(channels = 1; channels <= 8; channels *= 2) { + unsigned bits_per_sample; + for(bits_per_sample = 8; bits_per_sample <= 24; bits_per_sample += 4) { + static const unsigned nsamples[] = { 1, 111, 4777 } ; + unsigned samples; + for(samples = 0; samples < sizeof(nsamples)/sizeof(nsamples[0]); samples++) { + char fn[64]; + + flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.aiff", channels, bits_per_sample, nsamples[samples]); + if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples])) + return 1; + + flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.wav", channels, bits_per_sample, nsamples[samples]); + if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/0)) + return 1; + + flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.rf64", channels, bits_per_sample, nsamples[samples]); + if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/1)) + return 1; + + flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.w64", channels, bits_per_sample, nsamples[samples]); + if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/2)) + return 1; + + if(bits_per_sample % 8 == 0) { + flac_snprintf(fn, sizeof (fn), "rt-%u-%u-signed-%u.raw", channels, bits_per_sample, nsamples[samples]); + if(!generate_signed_raw(fn, channels, bits_per_sample/8, nsamples[samples])) + return 1; + flac_snprintf(fn, sizeof (fn), "rt-%u-%u-unsigned-%u.raw", channels, bits_per_sample, nsamples[samples]); + if(!generate_unsigned_raw(fn, channels, bits_per_sample/8, nsamples[samples])) + return 1; + } + } + } + } + + return 0; +} diff --git a/vendor/flac/src/utils/Makefile.am b/vendor/flac/src/utils/Makefile.am new file mode 100644 index 0000000..5207b13 --- /dev/null +++ b/vendor/flac/src/utils/Makefile.am @@ -0,0 +1,19 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2001-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This file is part the FLAC project. FLAC is comprised of several +# components distributed under different licenses. The codec libraries +# are distributed under Xiph.Org's BSD-like license (see the file +# COPYING.Xiph in this distribution). All other programs, libraries, and +# plugins are distributed under the GPL (see COPYING.GPL). The documentation +# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the +# FLAC distribution contains at the top the terms under which it may be +# distributed. +# +# Since this particular file is relevant to all components of FLAC, +# it may be distributed under the Xiph.Org license, which is the least +# restrictive of those mentioned above. See the file COPYING.Xiph in this +# distribution. + +SUBDIRS = flacdiff flactimer diff --git a/vendor/flac/src/utils/flacdiff/CMakeLists.txt b/vendor/flac/src/utils/flacdiff/CMakeLists.txt new file mode 100644 index 0000000..ec9f771 --- /dev/null +++ b/vendor/flac/src/utils/flacdiff/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(flacdiff + main.cpp + $<$:../../../include/share/win_utf8_io.h> + $<$:../../share/win_utf8_io/win_utf8_io.c>) +target_link_libraries(flacdiff FLAC++) diff --git a/vendor/flac/src/utils/flacdiff/Makefile.am b/vendor/flac/src/utils/flacdiff/Makefile.am new file mode 100644 index 0000000..b181d98 --- /dev/null +++ b/vendor/flac/src/utils/flacdiff/Makefile.am @@ -0,0 +1,21 @@ +# flacdiff - Displays where two FLAC streams differ +# Copyright (C) 2007-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt \ + main.cpp diff --git a/vendor/flac/src/utils/flacdiff/main.cpp b/vendor/flac/src/utils/flacdiff/main.cpp new file mode 100644 index 0000000..358fe04 --- /dev/null +++ b/vendor/flac/src/utils/flacdiff/main.cpp @@ -0,0 +1,230 @@ +/* flacdiff - Displays where two FLAC streams differ + * Copyright (C) 2007-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "FLAC++/decoder.h" +#include "share/compat.h" + +#ifdef _MSC_VER +// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning) +#pragma warning ( disable : 4800 ) +#endif + +class AutoFILE { +protected: + ::FILE *f_; +public: + inline AutoFILE(const char *path, const char *mode): f_(::fopen(path, mode)) { } + inline virtual ~AutoFILE() { if (f_) (void)::fclose(f_); } + + inline operator bool() const { return 0 != f_; } + inline operator const ::FILE *() const { return f_; } + inline operator ::FILE *() { return f_; } +private: + AutoFILE(); + AutoFILE(const AutoFILE &); + void operator=(const AutoFILE &); +}; + +class Decoder: public FLAC::Decoder::Stream { +public: + Decoder(AutoFILE &f, FLAC__off_t tgt): tgtpos_((FLAC__uint64)tgt), curpos_(0), go_(true), err_(false), frame_(), f_(f) { memset(&frame_, 0, sizeof(::FLAC__Frame)); } + FLAC__uint64 tgtpos_, curpos_; + bool go_, err_; + ::FLAC__Frame frame_; +protected: + AutoFILE &f_; + // from FLAC::Decoder::Stream + virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) + { + *bytes = fread(buffer, 1, *bytes, f_); + if(ferror((FILE*)f_)) + return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT; + else if(*bytes == 0 && feof((FILE*)f_)) + return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + + virtual ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) + { + FLAC__off_t off = ftello(f_); + if(off < 0) + return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + *absolute_byte_offset = off; + return ::FLAC__STREAM_DECODER_TELL_STATUS_OK; + } + + virtual bool eof_callback() + { + return (bool)feof((FILE*)f_); + } + + virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const /*buffer*/[]) + { + FLAC__uint64 pos; + if(!get_decode_position(&pos)) { + go_ = false; + err_ = true; + return ::FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + if(pos > tgtpos_) { + go_ = false; + frame_ = *frame; + } + else + curpos_ = pos; + return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + + virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) + { + fprintf(stderr, "got error %d:%s\n", status, ::FLAC__StreamDecoderErrorStatusString[status]); + go_ = false; + err_ = true; + } +}; + +static bool show_diff(AutoFILE &f1, AutoFILE &f2, FLAC__off_t off) +{ + Decoder d1(f1, off), d2(f2, off); + if(!d1) { + fprintf(stderr, "ERROR: setting up decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1)); + return false; + } + if(!d2) { + fprintf(stderr, "ERROR: setting up decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2)); + return false; + } + ::FLAC__StreamDecoderInitStatus is; + if((is = d1.init()) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + fprintf(stderr, "ERROR: initializing decoder1, status=%s state=%s\n", FLAC__StreamDecoderInitStatusString[is], d1.get_state().resolved_as_cstring(d1)); + return false; + } + if((is = d2.init()) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + fprintf(stderr, "ERROR: initializing decoder2, status=%s state=%s\n", FLAC__StreamDecoderInitStatusString[is], d2.get_state().resolved_as_cstring(d2)); + return false; + } + if(!d1.process_until_end_of_metadata()) { + fprintf(stderr, "ERROR: skipping metadata in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1)); + return false; + } + if(!d2.process_until_end_of_metadata()) { + fprintf(stderr, "ERROR: skipping metadata in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2)); + return false; + } + while(d1.go_ && d2.go_) { + if(!d1.process_single()) { + fprintf(stderr, "ERROR: decoding frame in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1)); + return false; + } + if(!d2.process_single()) { + fprintf(stderr, "ERROR: decoding frame in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2)); + return false; + } + } + if(d1.err_) { + fprintf(stderr, "ERROR: got err_ in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1)); + return false; + } + if(d2.err_) { + fprintf(stderr, "ERROR: got err_ in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2)); + return false; + } + if(d1.go_ != d2.go_) { + fprintf(stderr, "ERROR: d1.go_(%s) != d2.go_(%s)\n", d1.go_?"true":"false", d2.go_?"true":"false"); + return false; + } + fprintf(stdout, "pos1 = %" PRIu64 " blocksize=%u sample#%" PRIu64 " frame#%" PRIu64 "\n", d1.curpos_, d1.frame_.header.blocksize, d1.frame_.header.number.sample_number, d1.frame_.header.number.sample_number / d1.frame_.header.blocksize); + fprintf(stdout, "pos2 = %" PRIu64 " blocksize=%u sample#%" PRIu64 " frame#%" PRIu64 "\n", d2.curpos_, d2.frame_.header.blocksize, d2.frame_.header.number.sample_number, d2.frame_.header.number.sample_number / d2.frame_.header.blocksize); + + return true; +} + +static FLAC__off_t get_diff_offset(AutoFILE &f1, AutoFILE &f2) +{ + FLAC__off_t off = 0; + while(1) { + if(feof((FILE*)f1) && feof((FILE*)f2)) { + fprintf(stderr, "ERROR: files are identical\n"); + return -1; + } + if(feof((FILE*)f1)) { + fprintf(stderr, "ERROR: file1 EOF\n"); + return -1; + } + if(feof((FILE*)f2)) { + fprintf(stderr, "ERROR: file2 EOF\n"); + return -1; + } + if(fgetc(f1) != fgetc(f2)) + return off; + off++; + } +} + +static bool run(const char *fn1, const char *fn2) +{ + FLAC__off_t off; + AutoFILE f1(fn1, "rb"), f2(fn2, "rb"); + + if(!f1) { + flac_fprintf(stderr, "ERROR: opening %s for reading\n", fn1); + return false; + } + if(!f2) { + flac_fprintf(stderr, "ERROR: opening %s for reading\n", fn2); + return false; + } + + if((off = get_diff_offset(f1, f2)) < 0) + return false; + + fprintf(stdout, "got diff offset = %" PRId64 "\n", off); + + return show_diff(f1, f2, off); +} + +int main(int argc, char *argv[]) +{ + const char *usage = "usage: flacdiff flacfile1 flacfile2\n"; + +#ifdef _WIN32 + if (get_utf8_argv(&argc, &argv) != 0) { + fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n"); + return 1; + } +#endif + + if(argc > 1 && 0 == strcmp(argv[1], "-h")) { + printf("%s", usage); + return 0; + } + else if(argc != 3) { + fprintf(stderr, "%s", usage); + return 255; + } + + return run(argv[1], argv[2])? 0 : 1; +} diff --git a/vendor/flac/src/utils/flactimer/CMakeLists.txt b/vendor/flac/src/utils/flactimer/CMakeLists.txt new file mode 100644 index 0000000..47bf1e5 --- /dev/null +++ b/vendor/flac/src/utils/flactimer/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(flactimer main.cpp) +target_link_libraries(flactimer FLAC++) diff --git a/vendor/flac/src/utils/flactimer/Makefile.am b/vendor/flac/src/utils/flactimer/Makefile.am new file mode 100644 index 0000000..0737863 --- /dev/null +++ b/vendor/flac/src/utils/flactimer/Makefile.am @@ -0,0 +1,21 @@ +# flactimer - Runs a command and prints timing information +# Copyright (C) 2007-2009 Josh Coalson +# Copyright (C) 2011-2023 Xiph.Org Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +EXTRA_DIST = \ + CMakeLists.txt \ + main.cpp diff --git a/vendor/flac/src/utils/flactimer/main.cpp b/vendor/flac/src/utils/flactimer/main.cpp new file mode 100644 index 0000000..120a37f --- /dev/null +++ b/vendor/flac/src/utils/flactimer/main.cpp @@ -0,0 +1,175 @@ +/* flactimer - Runs a command and prints timing information + * Copyright (C) 2007-2009 Josh Coalson + * Copyright (C) 2011-2023 Xiph.Org Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "share/compat.h" +#include "share/safe_str.h" + +static inline uint64_t time2nsec(const FILETIME &t) +{ + uint64_t n = t.dwHighDateTime; + n <<= 32; + n |= (uint64_t)t.dwLowDateTime; + return n * 100; +} + +static void printtime(FILE *fout, uint64_t nsec, uint64_t total) +{ + uint32_t pct = (uint32_t)(100.0 * ((double)nsec / (double)total)); + uint64_t msec = nsec / 1000000; nsec -= msec * 1000000; + uint64_t sec = msec / 1000; msec -= sec * 1000; + uint64_t min = sec / 60; sec -= min * 60; + uint64_t hour = min / 60; min -= hour * 60; + fprintf(fout, " %5u.%03u = %02u:%02u:%02u.%03u = %3u%%\n", + (uint32_t)((hour*60+min)*60+sec), + (uint32_t)msec, + (uint32_t)hour, + (uint32_t)min, + (uint32_t)sec, + (uint32_t)msec, + pct + ); +} + +int main(int argc, char *argv[]) +{ + const char *usage = "usage: flactimer [-1 | -2 | -o outputfile] command\n"; + FILE *fout = stderr; + + if(argc == 1 || (argc > 1 && 0 == strcmp(argv[1], "-h"))) { + fprintf(stderr, usage); + return 0; + } + argv++; + argc--; + if(0 == strcmp(argv[0], "-1") || 0 == strcmp(argv[0], "/1")) { + fout = stdout; + argv++; + argc--; + } + else if(0 == strcmp(argv[0], "-2") || 0 == strcmp(argv[0], "/2")) { + fout = stdout; + argv++; + argc--; + } + else if(0 == strcmp(argv[0], "-o")) { + if(argc < 2) { + fprintf(stderr, usage); + return 1; + } + fout = fopen(argv[1], "w"); + if(!fout) { + fprintf(stderr, "ERROR opening file %s for writing\n", argv[1]); + return 1; + } + argv += 2; + argc -= 2; + } + if(argc <= 0) { + fprintf(fout, "ERROR, no command!\n\n"); + fprintf(fout, usage); + fclose(fout); + return 1; + } + + // improvement: double-quote all args + int i, n = 0; + for(i = 0; i < argc; i++) { + if(i > 0) + n++; + n += strlen(argv[i]); + } + char *args = (char*)malloc(n+1); + if(!args) { + fprintf(fout, "ERROR, no memory\n"); + fclose(fout); + return 1; + } + args[0] = '\0'; + for(i = 0; i < argc; i++) { + if(i > 0) + safe_strncat(args, " ", sizeof(args)); + safe_strncat(args, argv[i], sizeof(args)); + } + + //fprintf(stderr, "@@@ cmd=[%s] args=[%s]\n", argv[0], args); + + STARTUPINFOA si; + GetStartupInfoA(&si); + + DWORD wallclock_msec = GetTickCount(); + + PROCESS_INFORMATION pi; + BOOL ok = CreateProcessA( + argv[0], // lpApplicationName + args, // lpCommandLine + NULL, // lpProcessAttributes + NULL, // lpThreadAttributes + FALSE, // bInheritHandles + 0, // dwCreationFlags + NULL, // lpEnvironment + NULL, // lpCurrentDirectory + &si, // lpStartupInfo (inherit from this proc?) + &pi // lpProcessInformation + ); + + if(!ok) { + fprintf(fout, "ERROR running command\n"); + free(args); //@@@ ok to free here or have to wait to wait till process is reaped? + fclose(fout); + return 1; + } + + //fprintf(stderr, "@@@ waiting...\n"); + WaitForSingleObject(pi.hProcess, INFINITE); + //fprintf(stderr, "@@@ done\n"); + + wallclock_msec = GetTickCount() - wallclock_msec; + + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + if(!GetProcessTimes(pi.hProcess, &creation_time, &exit_time, &kernel_time, &user_time)) { + fprintf(fout, "ERROR getting time info\n"); + free(args); //@@@ ok to free here or have to wait to wait till process is reaped? + fclose(fout); + return 1; + } + uint64_t kernel_nsec = time2nsec(kernel_time); + uint64_t user_nsec = time2nsec(user_time); + + fprintf(fout, "Kernel Time = "); printtime(fout, kernel_nsec, (uint64_t)wallclock_msec * 1000000); + fprintf(fout, "User Time = "); printtime(fout, user_nsec, (uint64_t)wallclock_msec * 1000000); + fprintf(fout, "Process Time = "); printtime(fout, kernel_nsec+user_nsec, (uint64_t)wallclock_msec * 1000000); + fprintf(fout, "Global Time = "); printtime(fout, (uint64_t)wallclock_msec * 1000000, (uint64_t)wallclock_msec * 1000000); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + free(args); //@@@ always causes crash, maybe CreateProcess takes ownership? + fclose(fout); + return 0; +} diff --git a/vendor/flac/src/utils/loudness/loudness.sci b/vendor/flac/src/utils/loudness/loudness.sci new file mode 100644 index 0000000..a476a17 --- /dev/null +++ b/vendor/flac/src/utils/loudness/loudness.sci @@ -0,0 +1,115 @@ +// Equal Loudness Filter +// +// Adapted from original MATLAB code written by David Robinson +// +// http://replaygain.hydrogenaudio.org/proposal/equal_loudness.html +// http://replaygain.hydrogenaudio.org/proposal/mfiles/equalloudfilt.m + +// ***************************************************************************** +// Print Filter Coefficients +// +// This function takes a vector of filter tap settings, and prints +// each tap setting from least significant to most significant. + +function c=printcoeff(p) + + c=coeff(p); + c=c($:-1:1); + + for ix = 1:1:length(c) + if ix > 1 + printf(" ") + end + printf("%.14f", c(ix)); + end + +endfunction + +// ***************************************************************************** +// Equal Loudness Filter +// +// This function is adapted from David Robison's original MATLAB code. +// Apart from changes to port it to scilab, the other change is to +// use a single specification of the frequency points in the 80dB Equal +// Loudness curve. +// +// The original code had different curves for different sampling +// frequencies. This code dynamically computes the current data +// points to use as determined by the Nyquist frequency. + +function [a1,b1,a2,b2]=equalloudfilt(fs); +// Design a filter to match equal loudness curves +// 9/7/2001 + +[%nargout,%nargin]=argn(0); + +// If the user hasn't specified a sampling frequency, use the CD default +if %nargin<1 then + fs=44100; +end + +// Specify the 80 dB Equal Loudness curve +EL80=[0,120;20,113;30,103;40,97;50,93;60,91;70,89;80,87;90,86; .. + .. + 100,85;200,78;300,76;400,76;500,76;600,76;700,77;800,78;900,79.5; .. + .. + 1000,80;1500,79;2000,77;2500,74;3000,71.5;3700,70;4000,70.5; .. + 5000,74;6000,79;7000,84;8000,86;9000,86; .. + .. + 10000,85;12000,95;15000,110;20000,125;24000,140]; + +for ex = 1:1:length(EL80(:,1)) + if EL80(ex,1) > fs/2 + EL80 = [ EL80(1:ex-1,:); fs/2, EL80(ex-1,2) ]; + break + elseif EL80(ex,1) == fs/2 + EL80 = EL80(1:ex,:); + break + end + if ex == length(EL80(:,1)) + EL80 = [ EL80(1:$, :); fs/2, EL80($,2) ]; + end +end + +// convert frequency and amplitude of the equal loudness curve into format suitable for yulewalk +f=EL80(:,1)./(fs/2); +m=10.^((70-EL80(:,2))/20); + +// Use a MATLAB utility to design a best bit IIR filter +[b1,a1]=yulewalk(10,f,m); + +// Add a 2nd order high pass filter at 150Hz to finish the job +hz=iir(2,'hp','butt',[150/fs,0],[1e-3 1e-3]); +b2=numer(hz); // b2=b2($:-1:1); +a2=denom(hz); // a2=a2($:-1:1); + +endfunction + +// ***************************************************************************** +// Generate Filter Taps +// +// Generate the filter taps for each of the desired frequencies. + +format('v', 16); + +freqs = [ 8000 11025 12000 16000 18900 22050 24000 .. + 28000 32000 36000 37800 44100 48000 ]; + +for fx = 1:1:length(freqs) + + printf("\n%d\n", freqs(fx)); + + [a1,b1,a2,b2] = equalloudfilt(freqs(fx)); + + printf("{ "); bb=printcoeff(b1); printf(" }\n"); + printf("{ "); aa=printcoeff(a1); printf(" }\n"); + + printf("{ "); printcoeff(b2); printf(" }\n"); + printf("{ "); printcoeff(a2); printf(" }\n"); + +// freqz_fwd(bb,aa,1024,freqs(fx)); + +end + + +quit diff --git a/vendor/freetype/LICENSE.TXT b/vendor/freetype/LICENSE.TXT new file mode 100644 index 0000000..8b9ce9e --- /dev/null +++ b/vendor/freetype/LICENSE.TXT @@ -0,0 +1,46 @@ +FREETYPE LICENSES +----------------- + +The FreeType 2 font engine is copyrighted work and cannot be used +legally without a software license. In order to make this project +usable to a vast majority of developers, we distribute it under two +mutually exclusive open-source licenses. + +This means that *you* must choose *one* of the two licenses described +below, then obey all its terms and conditions when using FreeType 2 in +any of your projects or products. + + - The FreeType License, found in the file `docs/FTL.TXT`, which is + similar to the original BSD license *with* an advertising clause + that forces you to explicitly cite the FreeType project in your + product's documentation. All details are in the license file. + This license is suited to products which don't use the GNU General + Public License. + + Note that this license is compatible to the GNU General Public + License version 3, but not version 2. + + - The GNU General Public License version 2, found in + `docs/GPLv2.TXT` (any later version can be used also), for + programs which already use the GPL. Note that the FTL is + incompatible with GPLv2 due to its advertisement clause. + +The contributed BDF and PCF drivers come with a license similar to +that of the X Window System. It is compatible to the above two +licenses (see files `src/bdf/README` and `src/pcf/README`). The same +holds for the source code files `src/base/fthash.c` and +`include/freetype/internal/fthash.h`; they were part of the BDF driver +in earlier FreeType versions. + +The gzip module uses the zlib license (see `src/gzip/zlib.h`) which +too is compatible to the above two licenses. + +The files `src/autofit/ft-hb.c` and `src/autofit/ft-hb.h` contain code +taken almost verbatim from the HarfBuzz file `hb-ft.cc`, which uses +the 'Old MIT' license, compatible to the above two licenses. + +The MD5 checksum support (only used for debugging in development +builds) is in the public domain. + + +--- end of LICENSE.TXT --- diff --git a/vendor/freetype/README b/vendor/freetype/README new file mode 100644 index 0000000..cd4c1d7 --- /dev/null +++ b/vendor/freetype/README @@ -0,0 +1,107 @@ +FreeType 2.13.2 +=============== + +Homepage: https://www.freetype.org + +FreeType is a freely available software library to render fonts. + +It is written in C, designed to be small, efficient, highly +customizable, and portable while capable of producing high-quality +output (glyph images) of most vector and bitmap font formats. + +Please read the `docs/CHANGES` file, it contains IMPORTANT +INFORMATION. + +Read the files `docs/INSTALL*` for installation instructions; see the +file `docs/LICENSE.TXT` for the available licenses. + +For using FreeType's git repository instead of a distribution bundle, +please read file `README.git`. Note that you have to actually clone +the repository; using a snapshot will not work (in other words, don't +use gitlab's 'Download' button). + +The FreeType 2 API reference is located in directory `docs/reference`; +use the file `index.html` as the top entry point. [Please note that +currently the search function for locally installed documentation +doesn't work due to cross-site scripting issues.] + +Additional documentation is available as a separate package from our +sites. Go to + + https://download.savannah.gnu.org/releases/freetype/ + +and download one of the following files. + + freetype-doc-2.13.2.tar.xz + freetype-doc-2.13.2.tar.gz + ftdoc2132.zip + +To view the documentation online, go to + + https://www.freetype.org/freetype2/docs/ + + +Mailing Lists +------------- + +The preferred way of communication with the FreeType team is using +e-mail lists. + + general use and discussion: freetype@nongnu.org + engine internals, porting, etc.: freetype-devel@nongnu.org + announcements: freetype-announce@nongnu.org + git repository tracker: freetype-commit@nongnu.org + +The lists are moderated; see + + https://www.freetype.org/contact.html + +how to subscribe. + + +Bugs +---- + +Please submit bug reports at + + https://gitlab.freedesktop.org/freetype/freetype/-/issues + +Alternatively, you might report bugs by e-mail to +`freetype-devel@nongnu.org`. Don't forget to send a detailed +explanation of the problem -- there is nothing worse than receiving a +terse message that only says 'it doesn't work'. + + +Patches +------- + +For larger changes please provide merge requests at + + https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests + +Alternatively, you can send patches to the `freetype-devel@nongnu.org` +mailing list -- and thank you in advance for your work on improving +FreeType! + +Details on the process can be found here: + + https://www.freetype.org/developer.html#patches + + +Enjoy! + + The FreeType Team + +---------------------------------------------------------------------- + +Copyright (C) 2006-2023 by +David Turner, Robert Wilhelm, and Werner Lemberg. + +This file is part of the FreeType project, and may only be used, +modified, and distributed under the terms of the FreeType project +license, LICENSE.TXT. By continuing to use, modify, or distribute +this file you indicate that you have read the license and understand +and accept it fully. + + +--- end of README --- diff --git a/vendor/freetype/README.git b/vendor/freetype/README.git new file mode 100644 index 0000000..117d74f --- /dev/null +++ b/vendor/freetype/README.git @@ -0,0 +1,102 @@ +README.git +========== + + +repository issues +----------------- + +FreeType's official repository site is + + https://gitlab.freedesktop.org/freetype , + +from which the 'freetype.git' and 'freetype-demos.git' repositories +can be cloned in the usual way. + + git clone https://gitlab.freedesktop.org/freetype/freetype.git + git clone https://gitlab.freedesktop.org/freetype/freetype-demos.git + +If you want to use the Savannah mirror instead, you have to do a +slightly different incantation because the repository names contain +digit '2' for historical reasons. + + git clone \ + https://git.savannah.nongnu.org/git/freetype/freetype2.git \ + freetype + git clone \ + https://git.savannah.nongnu.org/git/freetype/freetype2-demos.git \ + freetype-demos + + +standard builds with `configure` +-------------------------------- + +The git repository doesn't contain pre-built configuration scripts for +UNIXish platforms. To generate them say + + sh autogen.sh + +which in turn depends on the following packages: + + automake (1.10.1) + libtool (2.2.4) + autoconf (2.62) + +The versions given in parentheses are known to work. Newer versions +should work too, of course. Note that `autogen.sh` also sets up +proper file permissions for the `configure` and auxiliary scripts. + +The `autogen.sh` script checks whether the versions of the above three +tools match the numbers above. Otherwise it will complain and suggest +either upgrading or using environment variables to point to more +recent versions of the required tools. + +Note that `aclocal` is provided by the 'automake' package on Linux, +and that `libtoolize` is called `glibtoolize` on Darwin (OS X). + + +alternative build methods +------------------------- + +For static builds that don't use platform-specific optimizations, no +configure script is necessary at all; saying + + make setup ansi + make + +should work on all platforms that have GNU `make` (or `makepp`). + +A build with `cmake` or `meson` can be done directly from the git +repository. However, if you want to use the `FT_DEBUG_LOGGING` macro +(see file `docs/DEBUG` for more information) it is currently mandatory +to execute `autogen.sh` in advance; this script clones the 'dlg' git +submodule and copies some files into FreeType's source tree. + + +Code of Conduct +--------------- + +Please note that this project is released with a Contributor Code of +Conduct (CoC). By participating in this project you agree to abide by +its terms, which you can find in the following link: + + https://www.freedesktop.org/wiki/CodeOfConduct + +CoC issues may be raised to the project maintainers at the following +address: + + wl@gnu.org + apodtele@gmail.com + +---------------------------------------------------------------------- + +Copyright (C) 2005-2023 by +David Turner, Robert Wilhelm, and Werner Lemberg. + +This file is part of the FreeType project, and may only be used, +modified, and distributed under the terms of the FreeType project +license, LICENSE.TXT. By continuing to use, modify, or distribute +this file you indicate that you have read the license and understand +and accept it fully. + + +--- end of README.git --- diff --git a/vendor/freetype/build-freetype.lua b/vendor/freetype/build-freetype.lua new file mode 100644 index 0000000..a2b2648 --- /dev/null +++ b/vendor/freetype/build-freetype.lua @@ -0,0 +1,71 @@ +project"freetype" + kind"staticLib" + cppdialect"c++17" + targetdir"lib" + staticruntime "off" + + defines"FT2_BUILD_LIBRARY" + + includedirs "include" + + files + { + "src/autofit/autofit.c", + "src/base/ftbase.c", + "src/base/ftbbox.c", + "src/base/ftbdf.c", + "src/base/ftbitmap.c", + "src/base/ftcid.c", + "src/base/ftfstype.c", + "src/base/ftgasp.c", + "src/base/ftglyph.c", + "src/base/ftgxval.c", + "src/base/ftinit.c", + "src/base/ftmm.c", + "src/base/ftotval.c", + "src/base/ftpatent.c", + "src/base/ftpfr.c", + "src/base/ftstroke.c", + "src/base/ftsynth.c", + "src/base/fttype1.c", + "src/base/ftwinfnt.c", + "src/bdf/bdf.c", + "src/bzip2/ftbzip2.c", + "src/cache/ftcache.c", + "src/cff/cff.c", + "src/cid/type1cid.c", + "src/gzip/ftgzip.c", + "src/lzw/ftlzw.c", + "src/pcf/pcf.c", + "src/pfr/pfr.c", + "src/psaux/psaux.c", + "src/pshinter/pshinter.c", + "src/psnames/psnames.c", + "src/raster/raster.c", + "src/sdf/sdf.c", + "src/sfnt/sfnt.c", + "src/smooth/smooth.c", + "src/svg/svg.c", + "src/truetype/truetype.c", + "src/type1/type1.c", + "src/type42/type42.c", + "src/winfonts/winfnt.c", + } + + filter"system:windows" + files + { + "builds/windows/ftsystem.c", + "builds/windows/ftdebug.c" + } + + filter"system:linux" + files{"builds/unix/ftsystem.c"} + + filter "configurations:Debug" + runtime "Debug" + symbols "on" + + filter "configurations:Release" + runtime "Release" + optimize "Speed" \ No newline at end of file diff --git a/vendor/freetype/builds/amiga/README b/vendor/freetype/builds/amiga/README new file mode 100644 index 0000000..5b2abef --- /dev/null +++ b/vendor/freetype/builds/amiga/README @@ -0,0 +1,110 @@ + +README for the builds/amiga subdirectory. + +Copyright (C) 2005-2023 by +Werner Lemberg and Detlef Würkner. + +This file is part of the FreeType project, and may only be used, modified, +and distributed under the terms of the FreeType project license, +LICENSE.TXT. By continuing to use, modify, or distribute this file you +indicate that you have read the license and understand and accept it +fully. + + +The makefile.os4 is for the AmigaOS4 SDK. To use it, type +"make -f makefile.os4", it produces a link library libft2_ppc.a. + +The makefile is for ppc-morphos-gcc-2.95.3-bin.tgz (gcc 2.95.3 hosted on +68k-Amiga producing MorphOS-PPC-binaries from http://www.morphos.de). +To use it, type "make assign", then "make"; it produces a link library +libft2_ppc.a. + +The smakefile is a makefile for Amiga SAS/C 6.58 (no longer available, +latest sold version was 6.50, updates can be found in Aminet). It is +based on the version found in the sourcecode of ttf.library 0.83b for +FreeType 1.3.1 from Richard Griffith (ragriffi@sprynet.com, +http://ragriffi.home.sprynet.com). + +You will also need the latest include files and amiga.lib from the +Amiga web site (https://os.amigaworld.de/download.php?id=3) for +AmigaOS 3.9; the generated code should work under AmigaOS 2.04 and up. + +To use it, call "smake assign" and then "smake" from the builds/amiga +directory. The results are: + +- A link library "ft2_680x0.lib" (where x depends on the setting of + the CPU entry in the smakefile) containing all FreeType2 parts + except of the init code, debugging code, and the system interface + code. + +- ftsystem.o, an object module containing the standard version of the + system interface code which uses fopen() fclose() fread() fseek() + ftell() malloc() realloc() and free() from lib:sc.lib (not pure). + +- ftsystempure.o, an object module containing the pure version of the + system interface code which uses Open() Close() Read() Seek() + ExamineFH() AsmAllocPooled() AsmFreePooled() etc. This version can + be used in both normal programs and in Amiga run-time shared system + librarys (can be linked with lib:libinit.o, no copying of DATA and + BSS hunks for each OpenLibrary() necessary). Source code is in + src/base/ftsystem.c. + +- ftdebug.o, an object module containing the standard version of the + debugging code which uses vprintf() and exit() (not pure). + Debugging can be turned on in FT:include/freetype/config/ftoption.h + and with FT_SetTraceLevel(). + +- ftdebugpure.o, an object module containing the pure version of the + debugging code which uses KVPrintf() from lib:debug.lib and no + exit(). For debugging of Amiga run-time shared system libraries. + Source code is in src/base/ftdebug.c. + +- NO ftinit.o. Because linking with a link library should result in + linking only the needed object modules in it, but standard + ftsystem.o would force ALL FreeType2 modules to be linked to your + program, I decided to use a different scheme: You must #include + FT:src/base/ftinit.c in your sourcecode and specify with #define + statements which modules you need. See + include/freetype/config/ftmodule.h. + + +To use in your own programs: + +- Insert the #define and #include statements from top of + include/freetype/config/ftmodule.h in your source code and + uncomment the #define statements for the FreeType2 modules you need. + +- You can use either PARAMETERS=REGISTER or PARAMETERS=STACK for + calling the FreeType2 functions, because the link library and the + object files are compiled with PARAMETERS=BOTH. + +- "smake assign" (assign "FT:" to the FreeType2 main directory). + +- Compile your program. + +- Link with either ftsystem.o or ftsystempure.o, if debugging enabled + with either ftdebug.o or (ftdebugpure.o and lib:debug.lib), and with + ft2_680x0.lib as link library. + + +To adapt to other compilers: + +- The standard ANSI C maximum length of 31 significant characters in + identifiers is not enough for FreeType2. Check if your compiler has + a minimum length of 40 significant characters or can be switched to + it. "idlen=40" is the option for SAS/C. Setting #define + HAVE_LIMIT_ON_IDENTS in an include file may also work (not tested). + +- Make sure that the include directory in builds/amiga is searched + before the normal FreeType2 include directory, so you are able to + replace problematic include files with your own version (same may be + useful for the src directory). + +- An example of how to replace/workaround a problematic include file + is include/freetype/config/ftconfig.h; it changes a #define that + would prevent SAS/C from generating XDEF's where it should do that and + then includes the standard FreeType2 include file. + +Local Variables: +coding: latin-1 +End: diff --git a/vendor/freetype/builds/amiga/include/config/ftconfig.h b/vendor/freetype/builds/amiga/include/config/ftconfig.h new file mode 100644 index 0000000..de074bf --- /dev/null +++ b/vendor/freetype/builds/amiga/include/config/ftconfig.h @@ -0,0 +1,55 @@ +/***************************************************************************/ +/* */ +/* ftconfig.h */ +/* */ +/* Amiga-specific configuration file (specification only). */ +/* */ +/* Copyright (C) 2005-2023 by */ +/* Werner Lemberg and Detlef Würkner. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/* + * This is an example how to override the default FreeType2 header files + * with Amiga-specific changes. When the compiler searches this directory + * before the default directory, we can do some modifications. + * + * Here we must change FT_EXPORT_DEF so that SAS/C does + * generate the needed XDEFs. + */ + +#if 0 +#define FT_EXPORT_DEF( x ) extern x +#endif + +#undef FT_EXPORT_DEF +#define FT_EXPORT_DEF( x ) x + +/* Now include the original file */ +#ifndef __MORPHOS__ +#ifdef __SASC +#include "FT:include/freetype/config/ftconfig.h" +#else +#include "/FT/include/freetype/config/ftconfig.h" +#endif +#else +/* We must define that, it seems that + * lib/gcc-lib/ppc-morphos/2.95.3/include/syslimits.h is missing in + * ppc-morphos-gcc-2.95.3-bin.tgz (gcc for 68k producing MorphOS PPC elf + * binaries from http://www.morphos.de) + */ +#define _LIBC_LIMITS_H_ +#include "/FT/include/freetype/config/ftconfig.h" +#endif + +/* +Local Variables: +coding: latin-1 +End: +*/ diff --git a/vendor/freetype/builds/amiga/include/config/ftmodule.h b/vendor/freetype/builds/amiga/include/config/ftmodule.h new file mode 100644 index 0000000..bf33367 --- /dev/null +++ b/vendor/freetype/builds/amiga/include/config/ftmodule.h @@ -0,0 +1,158 @@ +/***************************************************************************/ +/* */ +/* ftmodule.h */ +/* */ +/* Amiga-specific FreeType module selection. */ +/* */ +/* Copyright (C) 2005-2023 by */ +/* Werner Lemberg and Detlef Würkner. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/* + * To avoid that all your programs include all FreeType modules, + * you copy the following piece of source code into your own + * source file and specify which modules you really need in your + * application by uncommenting the appropriate lines. + */ +/* +//#define FT_USE_AUTOFIT // autofitter +//#define FT_USE_RASTER // monochrome rasterizer +//#define FT_USE_SMOOTH // anti-aliasing rasterizer +//#define FT_USE_TT // truetype font driver +//#define FT_USE_T1 // type1 font driver +//#define FT_USE_T42 // type42 font driver +//#define FT_USE_T1CID // cid-keyed type1 font driver // no cmap support +//#define FT_USE_CFF // opentype font driver +//#define FT_USE_BDF // bdf bitmap font driver +//#define FT_USE_PCF // pcf bitmap font driver +//#define FT_USE_PFR // pfr font driver +//#define FT_USE_WINFNT // windows .fnt|.fon bitmap font driver +//#define FT_USE_OTV // opentype validator +//#define FT_USE_GXV // truetype gx validator +#include "FT:src/base/ftinit.c" +*/ + +/* Make sure that the needed support modules are built in. + * Dependencies can be found by searching for FT_Get_Module. + */ + +#ifdef FT_USE_T42 +#define FT_USE_TT +#endif + +#ifdef FT_USE_TT +#define FT_USE_SFNT +#endif + +#ifdef FT_USE_CFF +#define FT_USE_SFNT +#define FT_USE_PSHINT +#define FT_USE_PSNAMES +#endif + +#ifdef FT_USE_T1 +#define FT_USE_PSAUX +#define FT_USE_PSHINT +#define FT_USE_PSNAMES +#endif + +#ifdef FT_USE_T1CID +#define FT_USE_PSAUX +#define FT_USE_PSHINT +#define FT_USE_PSNAMES +#endif + +#ifdef FT_USE_PSAUX +#define FT_USE_PSNAMES +#endif + +#ifdef FT_USE_SFNT +#define FT_USE_PSNAMES +#endif + +/* Now include the modules */ + +#ifdef FT_USE_AUTOFIT +FT_USE_MODULE( FT_Module_Class, autofit_module_class ) +#endif + +#ifdef FT_USE_TT +FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) +#endif + +#ifdef FT_USE_T1 +FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class ) +#endif + +#ifdef FT_USE_CFF +FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class ) +#endif + +#ifdef FT_USE_T1CID +FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class ) +#endif + +#ifdef FT_USE_PFR +FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) +#endif + +#ifdef FT_USE_T42 +FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) +#endif + +#ifdef FT_USE_WINFNT +FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) +#endif + +#ifdef FT_USE_PCF +FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +#endif + +#ifdef FT_USE_PSAUX +FT_USE_MODULE( FT_Module_Class, psaux_module_class ) +#endif + +#ifdef FT_USE_PSNAMES +FT_USE_MODULE( FT_Module_Class, psnames_module_class ) +#endif + +#ifdef FT_USE_PSHINT +FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) +#endif + +#ifdef FT_USE_RASTER +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +#endif + +#ifdef FT_USE_SFNT +FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) +#endif + +#ifdef FT_USE_SMOOTH +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) +#endif + +#ifdef FT_USE_OTV +FT_USE_MODULE( FT_Module_Class, otv_module_class ) +#endif + +#ifdef FT_USE_BDF +FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +#endif + +#ifdef FT_USE_GXV +FT_USE_MODULE( FT_Module_Class, gxv_module_class ) +#endif + +/* +Local Variables: +coding: latin-1 +End: +*/ diff --git a/vendor/freetype/builds/amiga/makefile.os4 b/vendor/freetype/builds/amiga/makefile.os4 new file mode 100644 index 0000000..dfc3e9f --- /dev/null +++ b/vendor/freetype/builds/amiga/makefile.os4 @@ -0,0 +1,297 @@ +# +# Makefile for FreeType2 link library using gcc 4.0.3 from the +# AmigaOS4 SDK +# + + +# Copyright (C) 2005-2023 by +# Werner Lemberg and Detlef Würkner. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# to build from the builds/amiga directory call +# +# make -f makefile.os4 +# +# Your programs source code should start with this +# (uncomment the parts you do not need to keep the program small): +# ---8<--- +#define FT_USE_AUTOFIT // autofitter +#define FT_USE_RASTER // monochrome rasterizer +#define FT_USE_SMOOTH // anti-aliasing rasterizer +#define FT_USE_TT // truetype font driver +#define FT_USE_T1 // type1 font driver +#define FT_USE_T42 // type42 font driver +#define FT_USE_T1CID // cid-keyed type1 font driver +#define FT_USE_CFF // opentype font driver +#define FT_USE_BDF // bdf bitmap font driver +#define FT_USE_PCF // pcf bitmap font driver +#define FT_USE_PFR // pfr font driver +#define FT_USE_WINFNT // windows .fnt|.fon bitmap font driver +#define FT_USE_OTV // opentype validator +#define FT_USE_GXV // truetype gx validator +#include "FT:src/base/ftinit.c" +# ---8<--- +# +# link your programs with libft2_ppc.a and either ftsystem.ppc.o or ftsystempure.ppc.o +# (and either ftdebug.ppc.o or ftdebugpure.ppc.o if you enabled FT_DEBUG_LEVEL_ERROR or +# FT_DEBUG_LEVEL_TRACE in include/freetype/config/ftoption.h). + +all: assign libft2_ppc.a ftsystem.ppc.o ftsystempure.ppc.o + +assign: + assign FT: // + +CC = ppc-amigaos-gcc +AR = ppc-amigaos-ar +RANLIB = ppc-amigaos-ranlib + +DIRFLAGS = -Iinclude -I/FT/src -I/FT/include -I/SDK/include + +WARNINGS = -Wall -W -Wundef -Wpointer-arith -Wbad-function-cast \ + -Waggregate-return -Wwrite-strings -Wshadow + +OPTIONS = -DFT2_BUILD_LIBRARY -DNDEBUG -fno-builtin +OPTIMIZE = -O2 -fomit-frame-pointer -fstrength-reduce -finline-functions + +CFLAGS = -mcrt=clib2 $(DIRFLAGS) $(WARNINGS) $(FT2FLAGS) $(OPTIONS) $(OPTIMIZE) + +# +# FreeType2 library base +# +ftbase.ppc.o: FT:src/base/ftbase.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftbase.c + +ftinit.ppc.o: FT:src/base/ftinit.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftinit.c + +ftsystem.ppc.o: FT:src/base/ftsystem.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftsystem.c + +# pure version for use in run-time library etc +ftsystempure.ppc.o: src/base/ftsystem.c + $(CC) -c $(CFLAGS) -o $@ src/base/ftsystem.c + +# +# FreeType2 library base extensions +# +ftbbox.ppc.o: FT:src/base/ftbbox.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftbbox.c + +ftbdf.ppc.o: FT:src/base/ftbdf.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftbdf.c + +ftbitmap.ppc.o: FT:src/base/ftbitmap.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftbitmap.c + +ftcid.ppc.o: FT:src/base/ftcid.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftcid.c + +ftdebug.ppc.o: FT:src/base/ftdebug.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftdebug.c + +# pure version for use in run-time library etc +ftdebugpure.ppc.o: src/base/ftdebug.c + $(CC) -c $(CFLAGS) -o $@ src/base/ftdebug.c + +ftfstype.ppc.o: FT:src/base/ftfstype.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftfstype.c + +ftgasp.ppc.o: FT:src/base/ftgasp.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftgasp.c + +ftglyph.ppc.o: FT:src/base/ftglyph.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftglyph.c + +ftgxval.ppc.o: FT:src/base/ftgxval.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftgxval.c + +ftmm.ppc.o: FT:src/base/ftmm.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftmm.c + +ftotval.ppc.o: FT:src/base/ftotval.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftotval.c + +ftpatent.ppc.o: FT:src/base/ftpatent.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftpatent.c + +ftpfr.ppc.o: FT:src/base/ftpfr.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftpfr.c + +ftstroke.ppc.o: FT:src/base/ftstroke.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftstroke.c + +ftsynth.ppc.o: FT:src/base/ftsynth.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftsynth.c + +fttype1.ppc.o: FT:src/base/fttype1.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/fttype1.c + +ftwinfnt.ppc.o: FT:src/base/ftwinfnt.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/base/ftwinfnt.c + +# +# FreeType2 library autofitting module +# +autofit.ppc.o: FT:src/autofit/autofit.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/autofit/autofit.c + +# +# FreeType2 library postscript hinting module +# +pshinter.ppc.o: FT:src/pshinter/pshinter.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/pshinter/pshinter.c + +# +# FreeType2 library PS support module +# +psaux.ppc.o: FT:src/psaux/psaux.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/psaux/psaux.c + +# +# FreeType2 library PS glyph names module +# +psnames.ppc.o: FT:src/psnames/psnames.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/psnames/psnames.c + +# +# FreeType2 library monochrome raster module +# +raster.ppc.o: FT:src/raster/raster.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/raster/raster.c + +# +# FreeType2 library anti-aliasing raster module +# +smooth.ppc.o: FT:src/smooth/smooth.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/smooth/smooth.c + +# +# FreeType2 library 'sfnt' module +# +sfnt.ppc.o: FT:src/sfnt/sfnt.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/sfnt/sfnt.c + +# +# FreeType2 library glyph and image caching system +# +ftcache.ppc.o: FT:src/cache/ftcache.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/cache/ftcache.c + +# +# FreeType2 library OpenType font driver +# +cff.ppc.o: FT:src/cff/cff.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/cff/cff.c + +# +# FreeType2 library TrueType font driver +# +truetype.ppc.o: FT:src/truetype/truetype.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/truetype/truetype.c + +# +# FreeType2 library Type1 font driver +# +type1.ppc.o: FT:src/type1/type1.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/type1/type1.c + +# +# FreeType2 library Type42 font driver +# +type42.ppc.o: FT:src/type42/type42.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/type42/type42.c + +# +# FreeType2 library CID-keyed Type1 font driver +# +type1cid.ppc.o: FT:src/cid/type1cid.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/cid/type1cid.c + +# +# FreeType2 library BDF bitmap font driver +# +bdf.ppc.o: FT:src/bdf/bdf.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/bdf/bdf.c + +# +# FreeType2 library PCF bitmap font driver +# +pcf.ppc.o: FT:src/pcf/pcf.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/pcf/pcf.c + +# +# FreeType2 library gzip support for compressed PCF bitmap fonts +# +gzip.ppc.o: FT:src/gzip/ftgzip.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/gzip/ftgzip.c + +# +# FreeType2 library bzip2 support for compressed PCF bitmap fonts +# +bzip2.ppc.o: FT:src/bzip2/ftbzip2.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/bzip2/ftbzip2.c + +# +# FreeType2 library compress support for compressed PCF bitmap fonts +# +lzw.ppc.o: FT:src/lzw/ftlzw.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/lzw/ftlzw.c + +# +# FreeType2 library PFR font driver +# +pfr.ppc.o: FT:src/pfr/pfr.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/pfr/pfr.c + +# +# FreeType2 library Windows FNT/FON bitmap font driver +# +winfnt.ppc.o: FT:src/winfonts/winfnt.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/winfonts/winfnt.c + +# +# FreeType2 library TrueTypeGX Validator +# +gxvalid.ppc.o: FT:src/gxvalid/gxvalid.c + $(CC) -c $(CFLAGS) -Wno-aggregate-return -o $@ /FT/src/gxvalid/gxvalid.c + +# +# FreeType2 library OpenType validator +# +otvalid.ppc.o: FT:src/otvalid/otvalid.c + $(CC) -c $(CFLAGS) -o $@ /FT/src/otvalid/otvalid.c + +BASE = ftbase.ppc.o ftbbox.ppc.o ftbdf.ppc.o ftbitmap.ppc.o ftcid.ppc.o \ + ftfstype.ppc.o ftgasp.ppc.o ftglyph.ppc.o \ + ftgxval.ppc.o ftmm.ppc.o ftotval.ppc.o \ + ftpatent.ppc.o ftpfr.ppc.o ftstroke.ppc.o ftsynth.ppc.o \ + fttype1.ppc.o ftwinfnt.ppc.o + +DEBUG = ftdebug.ppc.o ftdebugpure.ppc.o + +AFIT = autofit.ppc.o + +GXV = gxvalid.ppc.o + +OTV = otvalid.ppc.o + +PS = psaux.ppc.o psnames.ppc.o pshinter.ppc.o + +RASTER = raster.ppc.o smooth.ppc.o + +FONTD = cff.ppc.o type1.ppc.o type42.ppc.o type1cid.ppc.o truetype.ppc.o\ + bdf.ppc.o pcf.ppc.o pfr.ppc.o winfnt.ppc.o + +libft2_ppc.a: $(BASE) $(AFIT) $(GXV) $(OTV) $(PS) $(RASTER) sfnt.ppc.o ftcache.ppc.o $(FONTD) gzip.ppc.o lzw.ppc.o + $(AR) r $@ $(BASE) $(AFIT) $(GXV) $(OTV) $(PS) $(RASTER) sfnt.ppc.o ftcache.ppc.o $(FONTD) gzip.ppc.o lzw.ppc.o + $(RANLIB) $@ + +#Local Variables: +#coding: latin-1 +#End: diff --git a/vendor/freetype/builds/amiga/smakefile b/vendor/freetype/builds/amiga/smakefile new file mode 100644 index 0000000..ca3da66 --- /dev/null +++ b/vendor/freetype/builds/amiga/smakefile @@ -0,0 +1,299 @@ +# +# Makefile for FreeType2 link library using Amiga SAS/C 6.58 +# + + +# Copyright (C) 2005-2023 by +# Werner Lemberg and Detlef Würkner. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# to build from the builds/amiga directory call +# +# smake assign +# smake +# +# Your programs source code should start with this +# (uncomment the parts you do not need to keep the program small): +# ---8<--- +#define FT_USE_AUTOFIT // autofitter +#define FT_USE_RASTER // monochrome rasterizer +#define FT_USE_SMOOTH // anti-aliasing rasterizer +#define FT_USE_TT // truetype font driver +#define FT_USE_T1 // type1 font driver +#define FT_USE_T42 // type42 font driver +#define FT_USE_T1CID // cid-keyed type1 font driver +#define FT_USE_CFF // opentype font driver +#define FT_USE_BDF // bdf bitmap font driver +#define FT_USE_PCF // pcf bitmap font driver +#define FT_USE_PFR // pfr font driver +#define FT_USE_WINFNT // windows .fnt|.fon bitmap font driver +#define FT_USE_OTV // opentype validator +#define FT_USE_GXV // truetype gx validator +#include "FT:src/base/ftinit.c" +# ---8<--- +# +# link your programs with ft2_680x0.lib and either ftsystem.o or ftsystempure.o +# (and either ftdebug.o or ftdebugpure.o if you enabled FT_DEBUG_LEVEL_ERROR or +# FT_DEBUG_LEVEL_TRACE in include/freetype/config/ftoption.h). + +OBJBASE = ftbase.o ftbbox.o ftbdf.o ftbitmap.o ftcid.o ftfstype.o \ + ftgasp.o ftglyph.o ftgxval.o ftmm.o ftotval.o \ + ftpatent.o ftpfr.o ftstroke.o ftsynth.o fttype1.o ftwinfnt.o + +OBJSYSTEM = ftsystem.o ftsystempure.o + +OBJDEBUG = ftdebug.o ftdebugpure.o + +OBJAFIT = autofit.o + +OBJGXV = gxvalid.o + +OBJOTV = otvalid.o + +OBJPS = psaux.o psnames.o pshinter.o + +OBJRASTER = raster.o smooth.o + +OBJSFNT = sfnt.o + +OBJCACHE = ftcache.o + +OBJFONTD = cff.o type1.o type42.o type1cid.o\ + truetype.o winfnt.o bdf.o pcf.o pfr.o + +CORE = FT:src/ + +CPU = 68000 +#CPU = 68020 +#CPU = 68030 +#CPU = 68040 +#CPU = 68060 + +OPTIMIZER = optinlocal + +SCFLAGS = optimize opttime optsched strmerge data=faronly idlen=50 cpu=$(CPU)\ + idir=include/ idir=$(CORE) idir=FT:include/ nostackcheck nochkabort\ + noicons ignore=79,85,110,306 parameters=both define=FT2_BUILD_LIBRARY + +LIB = ft2_$(CPU).lib + +# sample linker options +OPTS = link lib=$(LIB),lib:sc.lib,lib:amiga.lib,lib:debug.lib\ + smallcode smalldata noicons utillib + +# sample program entry +#myprog: myprog.c ftsystem.o $(LIB) +# sc $< programname=$@ ftsystem.o $(SCFLAGS) $(OPTS) + +all: $(LIB) $(OBJSYSTEM) $(OBJDEBUG) + +assign: + assign FT: // + +# uses separate object modules in lib to make for easier debugging +# also, can make smaller programs if entire engine is not used +ft2_$(CPU).lib: $(OBJBASE) $(OBJAFIT) $(OBJOTV) $(OBJPS) $(OBJRASTER) $(OBJSFNT) $(OBJCACHE) $(OBJFONTD) lzw.o gzip.o bzip2.o + oml $@ r $(OBJBASE) $(OBJAFIT) $(OBJOTV) $(OBJPS) $(OBJRASTER) $(OBJSFNT) $(OBJCACHE) $(OBJFONTD) lzw.o gzip.o bzip2.o + +clean: + -delete \#?.o + +realclean: clean + -delete ft2$(CPU).lib + +# +# freetype library base +# +ftbase.o: $(CORE)base/ftbase.c + sc $(SCFLAGS) objname=$@ $< +ftinit.o: $(CORE)base/ftinit.c + sc $(SCFLAGS) objname=$@ $< +ftsystem.o: $(CORE)base/ftsystem.c + sc $(SCFLAGS) objname=$@ $< +ftsystempure.o: src/base/ftsystem.c ## pure version for use in run-time library etc + sc $(SCFLAGS) objname=$@ $< +ftdebug.o: $(CORE)base/ftdebug.c + sc $(SCFLAGS) objname=$@ $< +ftdebugpure.o: src/base/ftdebug.c ## pure version for use in run-time library etc + sc $(SCFLAGS) objname=$@ $< +# +# freetype library base extensions +# +ftbbox.o: $(CORE)base/ftbbox.c + sc $(SCFLAGS) objname=$@ $< +ftbdf.o: $(CORE)base/ftbdf.c + sc $(SCFLAGS) objname=$@ $< +ftbitmap.o: $(CORE)base/ftbitmap.c + sc $(SCFLAGS) objname=$@ $< +ftcid.o: $(CORE)base/ftcid.c + sc $(SCFLAGS) objname=$@ $< +ftfstype.o: $(CORE)base/ftfstype.c + sc $(SCFLAGS) objname=$@ $< +ftgasp.o: $(CORE)base/ftgasp.c + sc $(SCFLAGS) objname=$@ $< +ftglyph.o: $(CORE)base/ftglyph.c + sc $(SCFLAGS) objname=$@ $< +ftgxval.o: $(CORE)base/ftgxval.c + sc $(SCFLAGS) objname=$@ $< +ftmm.o: $(CORE)base/ftmm.c + sc $(SCFLAGS) objname=$@ $< +ftotval.o: $(CORE)base/ftotval.c + sc $(SCFLAGS) objname=$@ $< +ftpatent.o: $(CORE)base/ftpatent.c + sc $(SCFLAGS) objname=$@ $< +ftpfr.o: $(CORE)base/ftpfr.c + sc $(SCFLAGS) objname=$@ $< +ftstroke.o: $(CORE)base/ftstroke.c + sc $(SCFLAGS) objname=$@ $< +ftsynth.o: $(CORE)base/ftsynth.c + sc $(SCFLAGS) objname=$@ $< +fttype1.o: $(CORE)base/fttype1.c + sc $(SCFLAGS) objname=$@ $< +ftwinfnt.o: $(CORE)base/ftwinfnt.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library autofitter module +# +autofit.o: $(CORE)autofit/autofit.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library PS hinting module +# +pshinter.o: $(CORE)pshinter/pshinter.c + sc $(SCFLAGS) objname=$@ $< +# +# freetype library PS support module +# +psaux.o: $(CORE)psaux/psaux.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library PS glyph names module +# +psnames.o: $(CORE)psnames/psnames.c + sc $(SCFLAGS) code=far objname=$@ $< + +# +# freetype library monochrome raster module +# +raster.o: $(CORE)raster/raster.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library anti-aliasing raster module +# +smooth.o: $(CORE)smooth/smooth.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library 'sfnt' module +# +sfnt.o: $(CORE)sfnt/sfnt.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library glyph and image caching system (still experimental) +# +ftcache.o: $(CORE)cache/ftcache.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library OpenType font driver +# +cff.o: $(CORE)cff/cff.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library TrueType font driver +# +truetype.o: $(CORE)truetype/truetype.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library Type1 font driver +# +type1.o: $(CORE)type1/type1.c + sc $(SCFLAGS) objname=$@ $< + +# +# FreeType2 library Type42 font driver +# +type42.o: $(CORE)type42/type42.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library CID-keyed Type1 font driver +# +type1cid.o: $(CORE)cid/type1cid.c + sc $(SCFLAGS) objname=$@ $< +# +# freetype library CID-keyed Type1 font driver extensions +# +#cidafm.o: $(CORE)cid/cidafm.c +# sc $(SCFLAGS) objname=$@ $< + +# +# freetype library BDF bitmap font driver +# +bdf.o: $(CORE)bdf/bdf.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library PCF bitmap font driver +# +pcf.o: $(CORE)pcf/pcf.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library gzip support for compressed PCF bitmap fonts +# +gzip.o: $(CORE)gzip/ftgzip.c + sc $(SCFLAGS) define FAR objname=$@ $< + +# +# freetype library bzip2 support for compressed PCF bitmap fonts +# +bzip2.o: $(CORE)bzip2/ftbzip2.c + sc $(SCFLAGS) define FAR objname=$@ $< + +# +# freetype library compress support for compressed PCF bitmap fonts +# +lzw.o: $(CORE)lzw/ftlzw.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library PFR font driver +# +pfr.o: $(CORE)pfr/pfr.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library Windows FNT/FON bitmap font driver +# +winfnt.o: $(CORE)winfonts/winfnt.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library TrueTypeGX validator +# +gxvalid.o: $(CORE)gxvalid/gxvalid.c + sc $(SCFLAGS) objname=$@ $< + +# +# freetype library OpenType validator +# +otvalid.o: $(CORE)otvalid/otvalid.c + sc $(SCFLAGS) objname=$@ $< + +#Local Variables: +#coding: latin-1 +#End: diff --git a/vendor/freetype/builds/amiga/src/base/ftdebug.c b/vendor/freetype/builds/amiga/src/base/ftdebug.c new file mode 100644 index 0000000..a209297 --- /dev/null +++ b/vendor/freetype/builds/amiga/src/base/ftdebug.c @@ -0,0 +1,348 @@ +/**************************************************************************** + * + * ftdebug.c + * + * Debugging and logging component for amiga (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Detlef Wuerkner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component contains various macros and functions used to ease the + * debugging of the FreeType engine. Its main purpose is in assertion + * checking, tracing, and error detection. + * + * There are now three debugging modes: + * + * - trace mode + * + * Error and trace messages are sent to the log file (which can be the + * standard error output). + * + * - error mode + * + * Only error messages are generated. + * + * - release mode: + * + * No error message is sent or generated. The code is free from any + * debugging parts. + * + */ + + + /* + * Based on the default `ftdebug.c' file, + * replaced `vprintf' with `KVPrintF', + * commented out `exit', + * replaced `getenv' with `GetVar'. + */ + +#include +#include +#include +#include + +#define __NOLIBBASE__ +#define __NOLOBALIFACE__ +#define __USE_INLINE__ + +#include +#include + +#ifndef __amigaos4__ + extern struct Library* DOSBase; +#else + extern struct DOSIFace* IDOS; +#endif + + +#include +#include +#include + + +#ifdef FT_DEBUG_LEVEL_ERROR + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Message( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + KVPrintF( fmt, ap ); + va_end( ap ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Panic( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + KVPrintF( fmt, ap ); + va_end( ap ); + + /* exit( EXIT_FAILURE ); */ + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( int ) + FT_Throw( FT_Error error, + int line, + const char* file ) + { +#if 0 + /* activating the code in this block makes FreeType very chatty */ + fprintf( stderr, + "%s:%d: error 0x%02x: %s\n", + file, + line, + error, + FT_Error_String( error ) ); +#else + FT_UNUSED( error ); + FT_UNUSED( line ); + FT_UNUSED( file ); +#endif + + return 0; + } + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* array of trace levels, initialized to 0; */ + /* this gets adjusted at run-time */ + static int ft_trace_levels_enabled[trace_count]; + + /* array of trace levels, always initialized to 0 */ + static int ft_trace_levels_disabled[trace_count]; + + /* a pointer to either `ft_trace_levels_enabled' */ + /* or `ft_trace_levels_disabled' */ + int* ft_trace_levels; + + /* define array of trace toggle names */ +#define FT_TRACE_DEF( x ) #x , + + static const char* ft_trace_toggles[trace_count + 1] = + { +#include + NULL + }; + +#undef FT_TRACE_DEF + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return trace_count; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + int max = FT_Trace_Get_Count(); + + + if ( idx < max ) + return ft_trace_toggles[idx]; + else + return NULL; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + ft_trace_levels = ft_trace_levels_disabled; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + ft_trace_levels = ft_trace_levels_enabled; + } + + + /************************************************************************** + * + * Initialize the tracing sub-system. This is done by retrieving the + * value of the `FT2_DEBUG' environment variable. It must be a list of + * toggles, separated by spaces, `;', or `,'. Example: + * + * export FT2_DEBUG="any:3 memory:7 stream:5" + * + * This requests that all levels be set to 3, except the trace level for + * the memory and stream components which are set to 7 and 5, + * respectively. + * + * See the file `include/freetype/internal/fttrace.h' for details of + * the available toggle names. + * + * The level must be between 0 and 7; 0 means quiet (except for serious + * runtime errors), and 7 means _very_ verbose. + */ + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + /* const char* ft2_debug = ft_getenv( "FT2_DEBUG" ); */ + char buf[256]; + const char* ft2_debug = &buf[0]; + + + /* if ( ft2_debug ) */ + if ( GetVar( "FT2_DEBUG", (STRPTR)ft2_debug, 256, LV_VAR ) > 0 ) + { + const char* p = ft2_debug; + const char* q; + + + for ( ; *p; p++ ) + { + /* skip leading whitespace and separators */ + if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' ) + continue; + + /* read toggle name, followed by ':' */ + q = p; + while ( *p && *p != ':' ) + p++; + + if ( !*p ) + break; + + if ( *p == ':' && p > q ) + { + FT_Int n, i, len = (FT_Int)( p - q ); + FT_Int level = -1, found = -1; + + + for ( n = 0; n < trace_count; n++ ) + { + const char* toggle = ft_trace_toggles[n]; + + + for ( i = 0; i < len; i++ ) + { + if ( toggle[i] != q[i] ) + break; + } + + if ( i == len && toggle[i] == 0 ) + { + found = n; + break; + } + } + + /* read level */ + p++; + if ( *p ) + { + level = *p - '0'; + if ( level < 0 || level > 7 ) + level = -1; + } + + if ( found >= 0 && level >= 0 ) + { + if ( found == trace_any ) + { + /* special case for `any' */ + for ( n = 0; n < trace_count; n++ ) + ft_trace_levels_enabled[n] = level; + } + else + ft_trace_levels_enabled[found] = level; + } + } + } + } + + ft_trace_levels = ft_trace_levels_enabled; + } + + +#else /* !FT_DEBUG_LEVEL_TRACE */ + + + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + /* nothing */ + } + + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return 0; + } + + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + FT_UNUSED( idx ); + + return NULL; + } + + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + /* nothing */ + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + /* nothing */ + } + + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +/* END */ diff --git a/vendor/freetype/builds/amiga/src/base/ftsystem.c b/vendor/freetype/builds/amiga/src/base/ftsystem.c new file mode 100644 index 0000000..d85845c --- /dev/null +++ b/vendor/freetype/builds/amiga/src/base/ftsystem.c @@ -0,0 +1,530 @@ +/***************************************************************************/ +/* */ +/* ftsystem.c */ +/* */ +/* Amiga-specific FreeType low-level system interface (body). */ +/* */ +/* Copyright (C) 1996-2023 by */ +/* David Turner, Robert Wilhelm, Werner Lemberg and Detlef Würkner. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This file contains the Amiga interface used by FreeType to access */ + /* low-level, i.e. memory management, i/o access as well as thread */ + /* synchronisation. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Maintained by Detlef Würkner */ + /* */ + /* Based on the original ftsystem.c, */ + /* modified to avoid fopen(), fclose(), fread(), fseek(), ftell(), */ + /* malloc(), realloc(), and free(). */ + /* */ + /* Those C library functions are often not thread-safe or cant be */ + /* used in a shared Amiga library. If that's not a problem for you, */ + /* you can of course use the default ftsystem.c with C library calls */ + /* instead. */ + /* */ + /* This implementation needs exec V39+ because it uses AllocPooled() etc */ + /* */ + /*************************************************************************/ + +#define __NOLIBBASE__ +#define __NOGLOBALIFACE__ +#define __USE_INLINE__ +#include +#include +#include +#ifdef __amigaos4__ +extern struct ExecIFace *IExec; +extern struct DOSIFace *IDOS; +#else +extern struct Library *SysBase; +extern struct Library *DOSBase; +#endif + +#define IOBUF_SIZE 512 + +/* structure that helps us to avoid + * useless calls of Seek() and Read() + */ +struct SysFile +{ + BPTR file; + ULONG iobuf_start; + ULONG iobuf_end; + UBYTE iobuf[IOBUF_SIZE]; +}; + +#ifndef __amigaos4__ +/* C implementation of AllocVecPooled (see autodoc exec/AllocPooled) */ +APTR +Alloc_VecPooled( APTR poolHeader, + ULONG memSize ) +{ + ULONG newSize = memSize + sizeof ( ULONG ); + ULONG *mem = AllocPooled( poolHeader, newSize ); + + if ( !mem ) + return NULL; + *mem = newSize; + return mem + 1; +} + +/* C implementation of FreeVecPooled (see autodoc exec/AllocPooled) */ +void +Free_VecPooled( APTR poolHeader, + APTR memory ) +{ + ULONG *realmem = (ULONG *)memory - 1; + + FreePooled( poolHeader, realmem, *realmem ); +} +#endif + +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* MEMORY MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* It is not necessary to do any error checking for the */ + /* allocation-related functions. This is done by the higher level */ + /* routines like ft_mem_alloc() or ft_mem_realloc(). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* ft_alloc */ + /* */ + /* */ + /* The memory allocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* size :: The requested size in bytes. */ + /* */ + /* */ + /* The address of newly allocated block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { +#ifdef __amigaos4__ + return AllocVecPooled( memory->user, size ); +#else + return Alloc_VecPooled( memory->user, size ); +#endif + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_realloc */ + /* */ + /* */ + /* The memory reallocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* cur_size :: The current size of the allocated memory block. */ + /* */ + /* new_size :: The newly requested size in bytes. */ + /* */ + /* block :: The current address of the block in memory. */ + /* */ + /* */ + /* The address of the reallocated memory block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + void* new_block; + +#ifdef __amigaos4__ + new_block = AllocVecPooled ( memory->user, new_size ); +#else + new_block = Alloc_VecPooled ( memory->user, new_size ); +#endif + if ( new_block != NULL ) + { + CopyMem ( block, new_block, + ( new_size > cur_size ) ? cur_size : new_size ); +#ifdef __amigaos4__ + FreeVecPooled ( memory->user, block ); +#else + Free_VecPooled ( memory->user, block ); +#endif + } + return new_block; + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_free */ + /* */ + /* */ + /* The memory release function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* block :: The address of block in memory to be freed. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { +#ifdef __amigaos4__ + FreeVecPooled( memory->user, block ); +#else + Free_VecPooled( memory->user, block ); +#endif + } + + + /*************************************************************************/ + /* */ + /* RESOURCE MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (struct SysFile *)stream->descriptor.pointer ) + + + /*************************************************************************/ + /* */ + /* */ + /* ft_amiga_stream_close */ + /* */ + /* */ + /* The function to close a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_amiga_stream_close( FT_Stream stream ) + { + struct SysFile* sysfile; + + sysfile = STREAM_FILE( stream ); + Close ( sysfile->file ); + FreeMem ( sysfile, sizeof ( struct SysFile )); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_amiga_stream_io */ + /* */ + /* */ + /* The function to open a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + /* offset :: The position in the data stream to start reading. */ + /* */ + /* buffer :: The address of buffer to store the read data. */ + /* */ + /* count :: The number of bytes to read from the stream. */ + /* */ + /* */ + /* The number of bytes actually read. */ + /* */ + FT_CALLBACK_DEF( unsigned long ) + ft_amiga_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + struct SysFile* sysfile; + unsigned long read_bytes; + + if ( count != 0 ) + { + sysfile = STREAM_FILE( stream ); + + /* handle the seek */ + if ( (offset < sysfile->iobuf_start) || (offset + count > sysfile->iobuf_end) ) + { + /* requested offset implies we need a buffer refill */ + if ( !sysfile->iobuf_end || offset != sysfile->iobuf_end ) + { + /* a physical seek is necessary */ + Seek( sysfile->file, offset, OFFSET_BEGINNING ); + } + sysfile->iobuf_start = offset; + sysfile->iobuf_end = 0; /* trigger a buffer refill */ + } + + /* handle the read */ + if ( offset + count <= sysfile->iobuf_end ) + { + /* we have buffer and requested bytes are all inside our buffer */ + CopyMem( &sysfile->iobuf[offset - sysfile->iobuf_start], buffer, count ); + read_bytes = count; + } + else + { + /* (re)fill buffer */ + if ( count <= IOBUF_SIZE ) + { + /* requested bytes is a subset of the buffer */ + read_bytes = Read( sysfile->file, sysfile->iobuf, IOBUF_SIZE ); + if ( read_bytes == -1UL ) + { + /* error */ + read_bytes = 0; + } + else + { + sysfile->iobuf_end = offset + read_bytes; + CopyMem( sysfile->iobuf, buffer, count ); + if ( read_bytes > count ) + { + read_bytes = count; + } + } + } + else + { + /* we actually need more than our buffer can hold, so we decide + ** to do a single big read, and then copy the last IOBUF_SIZE + ** bytes of that to our internal buffer for later use */ + read_bytes = Read( sysfile->file, buffer, count ); + if ( read_bytes == -1UL ) + { + /* error */ + read_bytes = 0; + } + else + { + ULONG bufsize; + + bufsize = ( read_bytes > IOBUF_SIZE ) ? IOBUF_SIZE : read_bytes; + sysfile->iobuf_end = offset + read_bytes; + sysfile->iobuf_start = sysfile->iobuf_end - bufsize; + CopyMem( &buffer[read_bytes - bufsize] , sysfile->iobuf, bufsize ); + } + } + } + } + else + { + read_bytes = 0; + } + + return read_bytes; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + struct FileInfoBlock* fib; + struct SysFile* sysfile; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + +#ifdef __amigaos4__ + sysfile = AllocMem ( sizeof (struct SysFile ), MEMF_SHARED ); +#else + sysfile = AllocMem ( sizeof (struct SysFile ), MEMF_PUBLIC ); +#endif + if ( !sysfile ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + + return FT_THROW( Cannot_Open_Resource ); + } + sysfile->file = Open( (STRPTR)filepathname, MODE_OLDFILE ); + if ( !sysfile->file ) + { + FreeMem ( sysfile, sizeof ( struct SysFile )); + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + + return FT_THROW( Cannot_Open_Resource ); + } + + fib = AllocDosObject( DOS_FIB, NULL ); + if ( !fib ) + { + Close ( sysfile->file ); + FreeMem ( sysfile, sizeof ( struct SysFile )); + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + + return FT_THROW( Cannot_Open_Resource ); + } + if ( !( ExamineFH( sysfile->file, fib ) ) ) + { + FreeDosObject( DOS_FIB, fib ); + Close ( sysfile->file ); + FreeMem ( sysfile, sizeof ( struct SysFile )); + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + + return FT_THROW( Cannot_Open_Resource ); + } + stream->size = fib->fib_Size; + FreeDosObject( DOS_FIB, fib ); + + stream->descriptor.pointer = (void *)sysfile; + stream->pathname.pointer = (char*)filepathname; + sysfile->iobuf_start = 0; + sysfile->iobuf_end = 0; + stream->pos = 0; + + stream->read = ft_amiga_stream_io; + stream->close = ft_amiga_stream_close; + + if ( !stream->size ) + { + ft_amiga_stream_close( stream ); + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " opened `%s' but zero-sized\n", filepathname )); + return FT_THROW( Cannot_Open_Stream ); + } + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + } + + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + + +#ifdef __amigaos4__ + memory = (FT_Memory)AllocVec( sizeof ( *memory ), MEMF_SHARED ); +#else + memory = (FT_Memory)AllocVec( sizeof ( *memory ), MEMF_PUBLIC ); +#endif + if ( memory ) + { +#ifdef __amigaos4__ + memory->user = CreatePool( MEMF_SHARED, 16384, 16384 ); +#else + memory->user = CreatePool( MEMF_PUBLIC, 16384, 16384 ); +#endif + if ( memory->user == NULL ) + { + FreeVec( memory ); + memory = NULL; + } + else + { + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif + + DeletePool( memory->user ); + FreeVec( memory ); + } + +/* +Local Variables: +coding: latin-1 +End: +*/ +/* END */ diff --git a/vendor/freetype/builds/ansi/ansi-def.mk b/vendor/freetype/builds/ansi/ansi-def.mk new file mode 100644 index 0000000..8217893 --- /dev/null +++ b/vendor/freetype/builds/ansi/ansi-def.mk @@ -0,0 +1,77 @@ +# +# FreeType 2 configuration rules for a `normal' ANSI system +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DELETE := rm -f +CAT := cat +SEP := / +PLATFORM_DIR := $(TOP_DIR)/builds/ansi +PLATFORM := ansi + +# This is used for `make refdoc' and `make refdoc-venv' +# +BIN := bin + +# The directory where all library files are placed. +# +# By default, this is the same as $(OBJ_DIR); however, this can be changed +# to suit particular needs. +# +LIB_DIR := $(OBJ_DIR) + + +# The name of the final library file. Note that the DOS-specific Makefile +# uses a shorter (8.3) name. +# +LIBRARY := lib$(PROJECT) + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= + + +# EOF diff --git a/vendor/freetype/builds/ansi/ansi.mk b/vendor/freetype/builds/ansi/ansi.mk new file mode 100644 index 0000000..ad40939 --- /dev/null +++ b/vendor/freetype/builds/ansi/ansi.mk @@ -0,0 +1,21 @@ +# +# FreeType 2 configuration rules for a `normal' pseudo ANSI compiler/system +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +include $(TOP_DIR)/builds/ansi/ansi-def.mk +include $(TOP_DIR)/builds/compiler/ansi-cc.mk +include $(TOP_DIR)/builds/link_std.mk + + +# EOF diff --git a/vendor/freetype/builds/atari/ATARI.H b/vendor/freetype/builds/atari/ATARI.H new file mode 100644 index 0000000..4ddd2eb --- /dev/null +++ b/vendor/freetype/builds/atari/ATARI.H @@ -0,0 +1,20 @@ +#if defined( GXVALID_H_ ) +#pragma warn -aus /* too many unevaluated variables in gxvalid */ +#endif + +#ifndef ATARI_H +#define ATARI_H + +#pragma warn -stu + +/* PureC doesn't like 32bit enumerations */ + +#ifndef FT_IMAGE_TAG +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value +#endif /* FT_IMAGE_TAG */ + +#ifndef FT_ENC_TAG +#define FT_ENC_TAG( value, a, b, c, d ) value +#endif /* FT_ENC_TAG */ + +#endif /* ATARI_H */ diff --git a/vendor/freetype/builds/atari/FNames.SIC b/vendor/freetype/builds/atari/FNames.SIC new file mode 100644 index 0000000..f365717 --- /dev/null +++ b/vendor/freetype/builds/atari/FNames.SIC @@ -0,0 +1,37 @@ +/* the following changes file names for PureC projects */ + +if (argc > 0) +{ + ordner = argv[0]; + if (basename(ordner) == "") /* ist Ordner */ + { + ChangeFilenames(ordner); + } +} + +proc ChangeFilenames(folder) +local i,entries,directory,file; +{ + entries = filelist(directory,folder); + for (i = 0; i < entries; ++i) + { + file = directory[i,0]; + if ((directory[i,3]&16) > 0) /* subdirectory */ + { + ChangeFilenames(folder+file+"\\"); + } + else + { + if ((stricmp(suffix(file),".h")==0)|(stricmp(suffix(file),".c")==0)) + ChangeFilename(folder,file); + } + } +} + +proc ChangeFilename(path,datei) +local newfile,err; +{ + newfile=datei; + newfile[0]=(newfile[0] | 32) ^ 32; + err=files.rename("-q",path+datei,newfile); +} diff --git a/vendor/freetype/builds/atari/FREETYPE.PRJ b/vendor/freetype/builds/atari/FREETYPE.PRJ new file mode 100644 index 0000000..4776a5b --- /dev/null +++ b/vendor/freetype/builds/atari/FREETYPE.PRJ @@ -0,0 +1,32 @@ +;FreeType project file + +FREETYPE.LIB + +.C [-K -P -R -A] +.L [-J -V] +.S + += + +..\..\src\base\ftsystem.c +..\..\src\base\ftdebug.c + +..\..\src\base\ftinit.c +..\..\src\base\ftglyph.c +..\..\src\base\ftmm +..\..\src\base\ftbbox + +..\..\src\base\ftbase.c +..\..\src\autohint\autohint.c +;..\..\src\cache\ftcache.c +..\..\src\cff\cff.c +..\..\src\cid\type1cid.c +..\..\src\psaux\psaux.c +..\..\src\pshinter\pshinter.c +..\..\src\psnames\psnames.c +..\..\src\raster\raster.c +..\..\src\sfnt\sfnt.c +..\..\src\smooth\smooth.c +..\..\src\truetype\truetype.c +..\..\src\type1\type1.c +..\..\src\type42\type42.c diff --git a/vendor/freetype/builds/atari/README.TXT b/vendor/freetype/builds/atari/README.TXT new file mode 100644 index 0000000..1300817 --- /dev/null +++ b/vendor/freetype/builds/atari/README.TXT @@ -0,0 +1,51 @@ +Compiling FreeType 2 with PureC compiler +======================================== + +[See below for a German version.] + +To compile FreeType 2 as a library the following changes must be applied: + +- All *.c files must start with an uppercase letter. + (In case GEMSCRIPT is available: + Simply drag the whole FreeType 2 directory to the file `FNames.SIC'.) + +- You have to change the INCLUDE directory in PureC's compiler options + to contain both the `INCLUDE' and `freetype2\include' directory. + Example: + + INCLUDE;E:\freetype2\include + +- The file `freetype/include/Ft2build.h' must be patched as follows to + include ATARI.H: + + #ifndef FT2_BUILD_GENERIC_H_ + #define FT2_BUILD_GENERIC_H_ + + #include "ATARI.H" + + + +Compilieren von FreeType 2 mit PureC +==================================== + +Um FreeType 2 als eine Bibliothek (library) zu compilieren, muss folgendes +ge„ndert werden: + +- Alle *.c-files mssen mit einem GROSSBUCHSTABEN beginnen. + (Falls GEMSCRIPT zur Verfgung steht: + Den kompletten Ordner freetype2 auf die Datei `FNames.SIC' draggen.) + +- In den Compiler-Optionen von PureC muss das INCLUDE directory auf INCLUDE + und freetype2\include verweisen. Z.B.: + + INCLUDE;E:\freetype2\include + +- In der Datei freetype/include/Ft2build.h muss zu Beginn + ein #include "ATARI.H" wie folgt eingefgt werden: + + #ifndef FT2_BUILD_GENERIC_H_ + #define FT2_BUILD_GENERIC_H_ + + #include "ATARI.H" + +--- end of README.TXT --- diff --git a/vendor/freetype/builds/atari/deflinejoiner.awk b/vendor/freetype/builds/atari/deflinejoiner.awk new file mode 100644 index 0000000..16d9e6d --- /dev/null +++ b/vendor/freetype/builds/atari/deflinejoiner.awk @@ -0,0 +1,181 @@ +#!/usr/bin/env awk + + +function shift( array, \ + junk, elm0, l ) +{ + elm0 = array[0] + for ( l = 0; l < asorti( array, junk ) - 1; l++ ) + array[l] = array[l+1]; + delete array[l] + return elm0 +} + + +function init_cpp_src_line() +{ + logical_line = "" + delete break_pos +} + + +function shift_valid_bp( array, \ + junk, elm ) +{ + elm = -1 + + if ( 0 < asorti( array, junk ) ) + do { + elm = shift( array ) + } while ( 0 > elm ); + + return elm +} + + +function check_cpp_src_line_break_pos( \ + i, junk ) +{ + printf( "break_pos:" ) + for ( i = 0; i < asorti( break_pos, junk ); i++ ) + printf( " %d", break_pos[i] ); + printf( "\n" ) +} + + +function check_cpp_src_line() +{ + printf( "logical_line[%s]\n", logical_line ) + check_cpp_src_line_break_pos() +} + + +function append_line( phys_line, \ + filt_line, bp_len ) +{ + filt_line = phys_line + sub( /\\$/, " ", filt_line ) + logical_line = logical_line filt_line + bp_len = asorti( break_pos, junk ) + break_pos[bp_len] = length( logical_line ) - 1 +} + + +function print_line( \ + c0, c1, i, junk, part_str ) +{ + c0 = 0 + + while( asorti( break_pos, junk ) > 1 ) + { + if ( ( c1 = shift_valid_bp( break_pos ) ) < 1 ) + { + part_str = substr( logical_line, c0 + 1 ) + printf( "%s\n", part_str ) + return + } + + part_str = substr( logical_line, c0 + 1, c1 - c0 + 1 ) + gsub( / $/, "\\", part_str ) + printf( "%s\n", part_str ) + c0 = c1 + 1 + } + + part_str = substr( logical_line, c0 + 1 ) + printf( "%s\n", part_str ) +} + + +function shrink_spaces( pos, \ + tail, removed_length, k ) +{ + tail = substr( logical_line, pos ) + sub( /^[ \t]+/, " ", tail ) + removed_length = length( logical_line ) - pos - length( tail ) + 1 + logical_line = substr( logical_line, 0, pos - 1 ) tail + + + for ( k = 0; k < asorti( break_pos, junk ); k++ ) + if ( ( pos + removed_length ) <= break_pos[k] ) + break_pos[k] = break_pos[k] - removed_length; + else if ( pos <= break_pos[k] ) + break_pos[k] = -1; + + return removed_length +} + + +function shrink_spaces_to_linebreak( pos, \ + junk, part_str, removed_length, i ) +{ + for ( i = 0; i < asorti( break_pos, junk ) && break_pos[i] < pos ; i++ ) + ; + + if ( break_pos[i] < 1 ) + return; + + part_str = substr( logical_line, pos, break_pos[i] - pos + 1 ) + sub( /^[ \t]+/, " ", part_str ) + removed_length = ( break_pos[i] - pos + 1 ) - length( part_str ) + + tail = substr( logical_line, pos + removed_length ) + logical_line = substr( logical_line, 0, pos - 1 ) tail + + for ( ; i < asorti( break_pos, junk ); i++ ) + break_pos[i] -= removed_length; + + return removed_length +} + + +function delete_linebreaks_in_2nd_token( \ + tail, paren_depth, junk, i, j, k, l ) +{ + if ( logical_line ~ /^[ \t]*#[ \t]*define[ \t]+[0-9A-Za-z_]+\(/ ) + { + tail = logical_line + sub( /^[ \t]*#[ \t]*define[ \t]+[0-9A-Za-z_]+/, "", tail ) + + paren_depth = 0 + l = 0 + i = length( logical_line ) - length( tail ) + 1 # seek to the 1st op paren + j = i + do { + if ( substr( logical_line, j, 2 ) ~ /[ \t][ \t]/ ) + l = shrink_spaces( j ); + else if ( substr( logical_line, j, 1 ) == "(" ) + paren_depth += 1; + else if ( substr( logical_line, j, 1 ) == ")" ) + paren_depth -= 1; + j += 1 + } while ( j < length( logical_line ) && paren_depth != 0 ) + + for ( k = 0; k < asorti( break_pos, junk ); k++ ) + if ( i <= break_pos[k] && break_pos[k] < j ) + break_pos[k] = -1; + + if ( l > 0 ) + shrink_spaces_to_linebreak( j ); + } +} + + +BEGIN{ + init_cpp_src_line() +} +{ + append_line( $0 ) + if ( $0 !~ /\\$/ ) + { + delete_linebreaks_in_2nd_token() + print_line() + init_cpp_src_line() + } +} +END{ + if ( 0 < length( logical_line ) ) + { + delete_linebreaks_in_2nd_token() + print_line() + } +} diff --git a/vendor/freetype/builds/atari/gen-purec-patch.sh b/vendor/freetype/builds/atari/gen-purec-patch.sh new file mode 100644 index 0000000..1ec050c --- /dev/null +++ b/vendor/freetype/builds/atari/gen-purec-patch.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +TOP_DIR=. +OBJ_DIR=. + +for x in "$@" +do + case x"$x" in + x--srcdir=* | x--topdir=* ) + TOP_DIR=`echo $x | sed 's/^--[a-z]*dir=//'` + ;; + x--builddir=* | x--objdir=* ) + OBJ_DIR=`echo $x | sed 's/^--[a-z]*dir=//'` + ;; + esac +done + +mkdir -p ${OBJ_DIR}/builds/atari/tmp/orig + +( cd ${TOP_DIR} && find . -name '*.[CHch]' -type f | fgrep -v builds/atari/tmp | cpio -o ) | \ +( cd ${OBJ_DIR}/builds/atari/tmp/orig && cpio -idum ) +cp ${TOP_DIR}/builds/atari/deflinejoiner.awk ${OBJ_DIR}/builds/atari/tmp + +pushd ${OBJ_DIR}/builds/atari/tmp + + cp -pr orig purec + for f in `cd orig && find . -type f` + do + echo filter $f + env LANG=C awk -f deflinejoiner.awk < orig/$f > purec/$f + done + + echo '#define FT2_BUILD_LIBRARY' > purec/include/ft2build.h + echo '#include "ATARI.H"' >> purec/include/ft2build.h + env LANG=C awk -f deflinejoiner.awk < orig/include/ft2build.h >> purec/include/ft2build.h + + env LANG=C diff -ur orig purec > ../purec.diff + +popd +rm -rf ${OBJ_DIR}/builds/atari/tmp diff --git a/vendor/freetype/builds/beos/beos-def.mk b/vendor/freetype/builds/beos/beos-def.mk new file mode 100644 index 0000000..1cca80c --- /dev/null +++ b/vendor/freetype/builds/beos/beos-def.mk @@ -0,0 +1,79 @@ +# +# FreeType 2 configuration rules for a BeOS system +# +# this is similar to the "ansi-def.mk" file, except for BUILD and PLATFORM +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DELETE := rm -f +CAT := cat +SEP := / +PLATFORM_DIR := $(TOP_DIR)/builds/beos +PLATFORM := beos + +# This is used for `make refdoc' and `make refdoc-venv' +# +BIN := bin + +# The directory where all library files are placed. +# +# By default, this is the same as $(OBJ_DIR); however, this can be changed +# to suit particular needs. +# +LIB_DIR := $(OBJ_DIR) + + +# The name of the final library file. Note that the DOS-specific Makefile +# uses a shorter (8.3) name. +# +LIBRARY := lib$(PROJECT) + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= + + +# EOF diff --git a/vendor/freetype/builds/beos/beos.mk b/vendor/freetype/builds/beos/beos.mk new file mode 100644 index 0000000..69ca1f1 --- /dev/null +++ b/vendor/freetype/builds/beos/beos.mk @@ -0,0 +1,19 @@ +# +# FreeType 2 configuration rules for a BeOS system +# + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +include $(TOP_DIR)/builds/beos/beos-def.mk +include $(TOP_DIR)/builds/compiler/ansi-cc.mk +include $(TOP_DIR)/builds/link_std.mk + + +# EOF diff --git a/vendor/freetype/builds/beos/detect.mk b/vendor/freetype/builds/beos/detect.mk new file mode 100644 index 0000000..dd1b5a6 --- /dev/null +++ b/vendor/freetype/builds/beos/detect.mk @@ -0,0 +1,41 @@ +# +# FreeType 2 configuration file to detect an BeOS host platform. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +.PHONY: setup + + +ifeq ($(PLATFORM),ansi) + + ifdef BE_HOST_CPU + + PLATFORM := beos + + endif # test MACHTYPE beos +endif + +ifeq ($(PLATFORM),beos) + + DELETE := rm -f + CAT := cat + SEP := / + PLATFORM_DIR := $(TOP_DIR)/builds/beos + CONFIG_FILE := beos.mk + + setup: std_setup + +endif # test PLATFORM beos + + +# EOF diff --git a/vendor/freetype/builds/cmake/FindBrotliDec.cmake b/vendor/freetype/builds/cmake/FindBrotliDec.cmake new file mode 100644 index 0000000..81036cb --- /dev/null +++ b/vendor/freetype/builds/cmake/FindBrotliDec.cmake @@ -0,0 +1,52 @@ +# FindBrotliDec.cmake +# +# Copyright (C) 2019-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# Written by Werner Lemberg +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. +# +# +# Try to find libbrotlidec include and library directories. +# +# If found, the following variables are set. +# +# BROTLIDEC_INCLUDE_DIRS +# BROTLIDEC_LIBRARIES + +find_package(PkgConfig QUIET) + +pkg_check_modules(PC_BROTLIDEC QUIET libbrotlidec) + +if (PC_BROTLIDEC_VERSION) + set(BROTLIDEC_VERSION "${PC_BROTLIDEC_VERSION}") +endif () + + +find_path(BROTLIDEC_INCLUDE_DIRS + NAMES brotli/decode.h + HINTS ${PC_BROTLIDEC_INCLUDEDIR} + ${PC_BROTLIDEC_INCLUDE_DIRS} + PATH_SUFFIXES brotli) + +find_library(BROTLIDEC_LIBRARIES + NAMES brotlidec + HINTS ${PC_BROTLIDEC_LIBDIR} + ${PC_BROTLIDEC_LIBRARY_DIRS}) + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + BrotliDec + REQUIRED_VARS BROTLIDEC_INCLUDE_DIRS BROTLIDEC_LIBRARIES + FOUND_VAR BROTLIDEC_FOUND + VERSION_VAR BROTLIDEC_VERSION) + +mark_as_advanced( + BROTLIDEC_INCLUDE_DIRS + BROTLIDEC_LIBRARIES) diff --git a/vendor/freetype/builds/cmake/FindHarfBuzz.cmake b/vendor/freetype/builds/cmake/FindHarfBuzz.cmake new file mode 100644 index 0000000..b481fa4 --- /dev/null +++ b/vendor/freetype/builds/cmake/FindHarfBuzz.cmake @@ -0,0 +1,203 @@ +# Copyright (c) 2012, Intel Corporation +# Copyright (c) 2019 Sony Interactive Entertainment Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# Try to find Harfbuzz include and library directories. +# +# After successful discovery, this will set for inclusion where needed: +# HarfBuzz_INCLUDE_DIRS - containg the HarfBuzz headers +# HarfBuzz_LIBRARIES - containg the HarfBuzz library + +#[=======================================================================[.rst: +FindHarfBuzz +-------------- + +Find HarfBuzz headers and libraries. + +Imported Targets +^^^^^^^^^^^^^^^^ + +``HarfBuzz::HarfBuzz`` + The HarfBuzz library, if found. + +``HarfBuzz::ICU`` + The HarfBuzz ICU library, if found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables in your project: + +``HarfBuzz_FOUND`` + true if (the requested version of) HarfBuzz is available. +``HarfBuzz_VERSION`` + the version of HarfBuzz. +``HarfBuzz_LIBRARIES`` + the libraries to link against to use HarfBuzz. +``HarfBuzz_INCLUDE_DIRS`` + where to find the HarfBuzz headers. +``HarfBuzz_COMPILE_OPTIONS`` + this should be passed to target_compile_options(), if the + target is not used for linking + +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_HARFBUZZ QUIET harfbuzz) +set(HarfBuzz_COMPILE_OPTIONS ${PC_HARFBUZZ_CFLAGS_OTHER}) +set(HarfBuzz_VERSION ${PC_HARFBUZZ_CFLAGS_VERSION}) + +find_path(HarfBuzz_INCLUDE_DIR + NAMES hb.h + HINTS ${PC_HARFBUZZ_INCLUDEDIR} ${PC_HARFBUZZ_INCLUDE_DIRS} + PATH_SUFFIXES harfbuzz +) + +find_library(HarfBuzz_LIBRARY + NAMES ${HarfBuzz_NAMES} harfbuzz + HINTS ${PC_HARFBUZZ_LIBDIR} ${PC_HARFBUZZ_LIBRARY_DIRS} +) + +if (HarfBuzz_INCLUDE_DIR AND NOT HarfBuzz_VERSION) + if (EXISTS "${HarfBuzz_INCLUDE_DIR}/hb-version.h") + file(READ "${HarfBuzz_INCLUDE_DIR}/hb-version.h" _harfbuzz_version_content) + + string(REGEX MATCH "#define +HB_VERSION_STRING +\"([0-9]+\\.[0-9]+\\.[0-9]+)\"" _dummy "${_harfbuzz_version_content}") + set(HarfBuzz_VERSION "${CMAKE_MATCH_1}") + endif () +endif () + +if ("${HarfBuzz_FIND_VERSION}" VERSION_GREATER "${HarfBuzz_VERSION}") + if (HarfBuzz_FIND_REQUIRED) + message(FATAL_ERROR + "Required version (" ${HarfBuzz_FIND_VERSION} ")" + " is higher than found version (" ${HarfBuzz_VERSION} ")") + else () + message(WARNING + "Required version (" ${HarfBuzz_FIND_VERSION} ")" + " is higher than found version (" ${HarfBuzz_VERSION} ")") + unset(HarfBuzz_VERSION) + unset(HarfBuzz_INCLUDE_DIRS) + unset(HarfBuzz_LIBRARIES) + return () + endif () +endif () + +# Find components +if (HarfBuzz_INCLUDE_DIR AND HarfBuzz_LIBRARY) + set(_HarfBuzz_REQUIRED_LIBS_FOUND ON) + set(HarfBuzz_LIBS_FOUND "HarfBuzz (required): ${HarfBuzz_LIBRARY}") +else () + set(_HarfBuzz_REQUIRED_LIBS_FOUND OFF) + set(HarfBuzz_LIBS_NOT_FOUND "HarfBuzz (required)") +endif () + +if (NOT CMAKE_VERSION VERSION_LESS 3.3) + if ("ICU" IN_LIST HarfBuzz_FIND_COMPONENTS) + pkg_check_modules(PC_HARFBUZZ_ICU QUIET harfbuzz-icu) + set(HarfBuzz_ICU_COMPILE_OPTIONS ${PC_HARFBUZZ_ICU_CFLAGS_OTHER}) + + find_path(HarfBuzz_ICU_INCLUDE_DIR + NAMES hb-icu.h + HINTS ${PC_HARFBUZZ_ICU_INCLUDEDIR} ${PC_HARFBUZZ_ICU_INCLUDE_DIRS} + PATH_SUFFIXES harfbuzz + ) + + find_library(HarfBuzz_ICU_LIBRARY + NAMES ${HarfBuzz_ICU_NAMES} harfbuzz-icu + HINTS ${PC_HARFBUZZ_ICU_LIBDIR} ${PC_HARFBUZZ_ICU_LIBRARY_DIRS} + ) + + if (HarfBuzz_ICU_LIBRARY) + if (HarfBuzz_FIND_REQUIRED_ICU) + list(APPEND HarfBuzz_LIBS_FOUND "ICU (required): ${HarfBuzz_ICU_LIBRARY}") + else () + list(APPEND HarfBuzz_LIBS_FOUND "ICU (optional): ${HarfBuzz_ICU_LIBRARY}") + endif () + else () + if (HarfBuzz_FIND_REQUIRED_ICU) + set(_HarfBuzz_REQUIRED_LIBS_FOUND OFF) + list(APPEND HarfBuzz_LIBS_NOT_FOUND "ICU (required)") + else () + list(APPEND HarfBuzz_LIBS_NOT_FOUND "ICU (optional)") + endif () + endif () + endif () +endif () + +if (NOT HarfBuzz_FIND_QUIETLY) + if (HarfBuzz_LIBS_FOUND) + message(STATUS "Found the following HarfBuzz libraries:") + foreach (found ${HarfBuzz_LIBS_FOUND}) + message(STATUS " ${found}") + endforeach () + endif () + if (HarfBuzz_LIBS_NOT_FOUND) + message(STATUS "The following HarfBuzz libraries were not found:") + foreach (found ${HarfBuzz_LIBS_NOT_FOUND}) + message(STATUS " ${found}") + endforeach () + endif () +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(HarfBuzz + FOUND_VAR HarfBuzz_FOUND + REQUIRED_VARS HarfBuzz_INCLUDE_DIR HarfBuzz_LIBRARY _HarfBuzz_REQUIRED_LIBS_FOUND + VERSION_VAR HarfBuzz_VERSION +) + +if (NOT CMAKE_VERSION VERSION_LESS 3.1) + if (HarfBuzz_LIBRARY AND NOT TARGET HarfBuzz::HarfBuzz) + add_library(HarfBuzz::HarfBuzz UNKNOWN IMPORTED GLOBAL) + set_target_properties(HarfBuzz::HarfBuzz PROPERTIES + IMPORTED_LOCATION "${HarfBuzz_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${HarfBuzz_COMPILE_OPTIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${HarfBuzz_INCLUDE_DIR}" + ) + endif () + + if (HarfBuzz_ICU_LIBRARY AND NOT TARGET HarfBuzz::ICU) + add_library(HarfBuzz::ICU UNKNOWN IMPORTED GLOBAL) + set_target_properties(HarfBuzz::ICU PROPERTIES + IMPORTED_LOCATION "${HarfBuzz_ICU_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${HarfBuzz_ICU_COMPILE_OPTIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${HarfBuzz_ICU_INCLUDE_DIR}" + ) + endif () +endif () + +mark_as_advanced( + HarfBuzz_INCLUDE_DIR + HarfBuzz_ICU_INCLUDE_DIR + HarfBuzz_LIBRARY + HarfBuzz_ICU_LIBRARY +) + +if (HarfBuzz_FOUND) + set(HarfBuzz_LIBRARIES ${HarfBuzz_LIBRARY} ${HarfBuzz_ICU_LIBRARY}) + set(HarfBuzz_INCLUDE_DIRS ${HarfBuzz_INCLUDE_DIR} ${HarfBuzz_ICU_INCLUDE_DIR}) +endif () diff --git a/vendor/freetype/builds/cmake/iOS.cmake b/vendor/freetype/builds/cmake/iOS.cmake new file mode 100644 index 0000000..7aba7c5 --- /dev/null +++ b/vendor/freetype/builds/cmake/iOS.cmake @@ -0,0 +1,270 @@ +# iOS.cmake +# +# Copyright (C) 2014-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# Written by David Wimsey +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. +# +# +# This file is derived from the files `Platform/Darwin.cmake' and +# `Platform/UnixPaths.cmake', which are part of CMake 2.8.4. It has been +# altered for iOS development. + + +# Options +# ------- +# +# IOS_PLATFORM = OS | SIMULATOR +# +# This decides whether SDKS are selected from the `iPhoneOS.platform' or +# `iPhoneSimulator.platform' folders. +# +# OS - the default, used to build for iPhone and iPad physical devices, +# which have an ARM architecture. +# SIMULATOR - used to build for the Simulator platforms, which have an +# x86 architecture. +# +# CMAKE_IOS_DEVELOPER_ROOT = /path/to/platform/Developer folder +# +# By default, this location is automatically chosen based on the +# IOS_PLATFORM value above. If you manually set this variable, it +# overrides the default location and forces the use of a particular +# Developer Platform. +# +# CMAKE_IOS_SDK_ROOT = /path/to/platform/Developer/SDKs/SDK folder +# +# By default, this location is automatically chosen based on the +# CMAKE_IOS_DEVELOPER_ROOT value. In this case it is always the most +# up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. If you +# manually set this variable, it forces the use of a specific SDK +# version. +# +# +# Macros +# ------ +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) +# +# A convenience macro for setting Xcode specific properties on targets. +# +# Example: +# +# set_xcode_property(myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") +# +# find_host_package (PROGRAM ARGS) +# +# A macro to find executable programs on the host system, not within the +# iOS environment. Thanks to the `android-cmake' project for providing +# the command. + + +# standard settings +set(CMAKE_SYSTEM_NAME Darwin) +set(CMAKE_SYSTEM_VERSION 1) +set(UNIX True) +set(APPLE True) +set(IOS True) + +# required as of cmake 2.8.10 +set(CMAKE_OSX_DEPLOYMENT_TARGET "" + CACHE STRING "Force unset of the deployment target for iOS" FORCE +) + +# determine the cmake host system version so we know where to find the iOS +# SDKs +find_program(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) +if (CMAKE_UNAME) + exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" + DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") +endif (CMAKE_UNAME) + +# skip the platform compiler checks for cross compiling +set(CMAKE_CXX_COMPILER_WORKS TRUE) +set(CMAKE_C_COMPILER_WORKS TRUE) + +# all iOS/Darwin specific settings - some may be redundant +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set(CMAKE_SHARED_MODULE_PREFIX "lib") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") +set(CMAKE_MODULE_EXISTS 1) +set(CMAKE_DL_LIBS "") + +set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG + "-compatibility_version ") +set(CMAKE_C_OSX_CURRENT_VERSION_FLAG + "-current_version ") +set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG + "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG + "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +# hidden visibility is required for cxx on iOS +set(CMAKE_C_FLAGS_INIT "") +set(CMAKE_CXX_FLAGS_INIT + "-headerpad_max_install_names -fvisibility=hidden -fvisibility-inlines-hidden") + +set(CMAKE_C_LINK_FLAGS + "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") +set(CMAKE_CXX_LINK_FLAGS + "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") + +set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS + "-dynamiclib -headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS + "-bundle -headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_LOADER_C_FLAG + "-Wl,-bundle_loader,") +set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG + "-Wl,-bundle_loader,") +set(CMAKE_FIND_LIBRARY_SUFFIXES + ".dylib" ".so" ".a") + +# hack: If a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old +# build tree (where `install_name_tool' was hardcoded), and where +# CMAKE_INSTALL_NAME_TOOL isn't in the cache and still cmake didn't +# fail in `CMakeFindBinUtils.cmake' (because it isn't rerun), hardcode +# CMAKE_INSTALL_NAME_TOOL here to `install_name_tool' so it behaves as +# it did before. +if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) +endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + +# set up iOS platform unless specified manually with IOS_PLATFORM +if (NOT DEFINED IOS_PLATFORM) + set(IOS_PLATFORM "OS") +endif (NOT DEFINED IOS_PLATFORM) + +set(IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") + +# check the platform selection and setup for developer root +if (${IOS_PLATFORM} STREQUAL "OS") + set(IOS_PLATFORM_LOCATION "iPhoneOS.platform") + + # this causes the installers to properly locate the output libraries + set(CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") + +elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") + set(IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") + + # this causes the installers to properly locate the output libraries + set(CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") + +else (${IOS_PLATFORM} STREQUAL "OS") + message(FATAL_ERROR + "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR.") + +endif (${IOS_PLATFORM} STREQUAL "OS") + +# set up iOS developer location unless specified manually with +# CMAKE_IOS_DEVELOPER_ROOT -- +# note that Xcode 4.3 changed the installation location; choose the most +# recent one available +set(XCODE_POST_43_ROOT + "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") +set(XCODE_PRE_43_ROOT + "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") + +if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) + if (EXISTS ${XCODE_POST_43_ROOT}) + set(CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) + elseif (EXISTS ${XCODE_PRE_43_ROOT}) + set(CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) + endif (EXISTS ${XCODE_POST_43_ROOT}) +endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) + +set(CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} + CACHE PATH "Location of iOS Platform" +) + +# find and use the most recent iOS SDK unless specified manually with +# CMAKE_IOS_SDK_ROOT +if (NOT DEFINED CMAKE_IOS_SDK_ROOT) + file(GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") + if (_CMAKE_IOS_SDKS) + list(SORT _CMAKE_IOS_SDKS) + list(REVERSE _CMAKE_IOS_SDKS) + list(GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) + else (_CMAKE_IOS_SDKS) + message(FATAL_ERROR + "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") + endif (_CMAKE_IOS_SDKS) + + message(STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") +endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) + +set(CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} + CACHE PATH "Location of the selected iOS SDK" +) + +# set the sysroot default to the most recent SDK +set(CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} + CACHE PATH "Sysroot used for iOS support" +) + +# set the architecture for iOS -- +# note that currently both ARCHS_STANDARD_32_BIT and +# ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually +if (${IOS_PLATFORM} STREQUAL "OS") + set(IOS_ARCH $(ARCHS_STANDARD_32_64_BIT)) +else (${IOS_PLATFORM} STREQUAL "OS") + set(IOS_ARCH i386) +endif (${IOS_PLATFORM} STREQUAL "OS") + +set(CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} + CACHE string "Build architecture for iOS" +) + +# set the find root to the iOS developer roots and to user defined paths +set(CMAKE_FIND_ROOT_PATH + ${CMAKE_IOS_DEVELOPER_ROOT} + ${CMAKE_IOS_SDK_ROOT} + ${CMAKE_PREFIX_PATH} + CACHE string "iOS find search path root" +) + +# default to searching for frameworks first +set(CMAKE_FIND_FRAMEWORK FIRST) + +# set up the default search directories for frameworks +set(CMAKE_SYSTEM_FRAMEWORK_PATH + ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks + ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks + ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks +) + +# only search the iOS SDKs, not the remainder of the host filesystem +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# this little macro lets you set any Xcode specific property +macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) + set_property(TARGET ${TARGET} + PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) +endmacro(set_xcode_property) + +# this macro lets you find executable programs on the host system +macro(find_host_package) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set(IOS FALSE) + + find_package(${ARGN}) + + set(IOS TRUE) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endmacro(find_host_package) + +# eof diff --git a/vendor/freetype/builds/cmake/testbuild.sh b/vendor/freetype/builds/cmake/testbuild.sh new file mode 100644 index 0000000..007170b --- /dev/null +++ b/vendor/freetype/builds/cmake/testbuild.sh @@ -0,0 +1,157 @@ +#!/bin/sh -e + +# Copyright (C) 2015-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# This script tests the CMake build. Simply run +# +# builds/cmake/testbuild.sh +# +# or +# +# BUILD_SHARED_LIBS=1 builds/cmake/testbuild.sh +# +# The script: +# +# - builds the main CMakeLists.txt +# - builds and runs a small test app in a separate build tree so +# the config-module is tested, too +# +# Options (environment variables): +# +# - The variable BUILD_SHARED_LIBS will be forwarded to the CMake project +# that builds the library. +# + + +# prepare temporary dir + +cd `dirname $0`/../.. +ftdir=`pwd` +tmpdir=/tmp/freetype-cmake-testbuild +rm -rf $tmpdir +mkdir -p $tmpdir + + +# build and install freetype + +if test -n "$BUILD_SHARED_LIBS"; then + bsl=-DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS +else + bsl=-UBUILD_SHARED_LIBS +fi + +build_opts="-DWITH_ZLIB=0 \ + -DWITH_BZip2=0 \ + -DWITH_PNG=0 \ + -DWITH_HarfBuzz=0 \ + $bsl \ + -DCMAKE_INSTALL_PREFIX=$tmpdir/out" + +(set -x; cmake -H$ftdir \ + -B$tmpdir/ftb \ + -DCMAKE_BUILD_TYPE=Debug \ + $build_opts) +(set -x; cmake --build $tmpdir/ftb \ + --config Debug \ + --target install) + +(set -x; cmake $tmpdir/ftb \ + -DCMAKE_BUILD_TYPE=Release) +(set -x; cmake --build $tmpdir/ftb \ + --config Release \ + --target install \ + --clean-first) + + +# create test project CMakeLists.txt + +cat >$tmpdir/CMakeLists.txt << END +cmake_minimum_required(VERSION 2.6) +project(freetype-cmake-testbuild) + +find_package(Freetype REQUIRED CONFIG) + +add_executable(freetype-cmake-test main.c) +target_link_libraries(freetype-cmake-test freetype) + +enable_testing() +add_test(freetype-cmake-test freetype-cmake-test) +END + + +# create test project main.c + +cat >$tmpdir/main.c << END +#include +#include + +#include +#include + + +FT_Library library; + + +int main(int argc, + char*argv[]) +{ + FT_Error error; + FT_Int major = 0; + FT_Int minor = 0; + FT_Int patch = 0; + + error = FT_Init_FreeType(&library); + if (error) + return EXIT_FAILURE; + + FT_Library_Version(library, &major, &minor, &patch); + if (major != FREETYPE_MAJOR + || minor != FREETYPE_MINOR + || patch != FREETYPE_PATCH) + return EXIT_FAILURE; + + printf("FT_Library_Version: %d.%d.%d\n", major, minor, patch); + + error = FT_Done_FreeType(library); + if (error) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} +END + + +# build and test + +mkdir -p $tmpdir/tb +cd $tmpdir/tb + +LD_LIBRARY_PATH=$tmpdir/out/lib:$LD_LIBRARY_PATH +DYLD_LIBRARY_PATH=$tmpdir/out/lib:$DYLD_LIBRARY_PATH +export LD_LIBRARY_PATH +export DYLD_LIBRARY_PATH + +(set -x; cmake $tmpdir \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_PREFIX_PATH=$tmpdir/out) +(set -x; cmake --build . \ + --config Debug) +(set -x; ctest -V -C Debug) + +(set -x; cmake . \ + -DCMAKE_BUILD_TYPE=Release) +(set -x; cmake --build . \ + --config Release \ + --clean-first) +(set -x; ctest -V -C Release) + +rm -rf $tmpdir + +# EOF diff --git a/vendor/freetype/builds/compiler/ansi-cc.mk b/vendor/freetype/builds/compiler/ansi-cc.mk new file mode 100644 index 0000000..f8386f6 --- /dev/null +++ b/vendor/freetype/builds/compiler/ansi-cc.mk @@ -0,0 +1,80 @@ +# +# FreeType 2 generic pseudo ANSI compiler +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Compiler command line name +# +CC := cc +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := o +SO := o + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := a +SA := a + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +# we assume the compiler is already strictly ANSI +# +ANSIFLAGS ?= + + +# Library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY)) +LINK_LIBRARY = $(AR) -r $@ $(subst /,$(COMPILER_SEP),$(OBJECTS_LIST)) + + +# EOF diff --git a/vendor/freetype/builds/compiler/bcc-dev.mk b/vendor/freetype/builds/compiler/bcc-dev.mk new file mode 100644 index 0000000..d01ed7c --- /dev/null +++ b/vendor/freetype/builds/compiler/bcc-dev.mk @@ -0,0 +1,86 @@ +# +# FreeType 2 Borland C++-specific with NO OPTIMIZATIONS + DEBUGGING +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Compiler command line name +# +CC := bcc32 +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := obj +SO := obj + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := lib +SA := lib + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := + + +# Target flag -- no trailing space. +# +T := -o +TE := -e + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -q -c -y -d -v -Od -w-par -w-ccc -w-rch -w-pro -w-aus + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= -A + + +# Library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY)) +LINK_LIBRARY = tlib /u /P128 $(subst /,$(COMPILER_SEP),$@ $(OBJECTS_LIST:%=+%)) + + +# Borland C++ specific temporary files +# +CLEAN += \ + $(subst /,$(SEP),$(TOP_DIR)/apinames.$(O)) \ + $(subst /,$(SEP),$(OBJ_DIR)/apinames.tds) + + +# EOF diff --git a/vendor/freetype/builds/compiler/bcc.mk b/vendor/freetype/builds/compiler/bcc.mk new file mode 100644 index 0000000..a484bba --- /dev/null +++ b/vendor/freetype/builds/compiler/bcc.mk @@ -0,0 +1,86 @@ +# +# FreeType 2 Borland C++-specific rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Compiler command line name +# +CC := bcc32 +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := obj +SO := obj + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := lib +SA := lib + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := + + +# Target flag -- no trailing space. +# +T := -o +TE := -e + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c -q -y -d -v -Od -w-par -w-ccc -w-rch -w-pro -w-aus + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= -A + + +# Library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY)) +LINK_LIBRARY = tlib /u /P128 $(subst /,$(COMPILER_SEP),$@ $(OBJECTS_LIST:%=+%)) + + +# Borland C++ specific temporary files +# +CLEAN += \ + $(subst /,$(SEP),$(TOP_DIR)/apinames.$(O)) \ + $(subst /,$(SEP),$(OBJ_DIR)/apinames.tds) + + +# EOF diff --git a/vendor/freetype/builds/compiler/emx.mk b/vendor/freetype/builds/compiler/emx.mk new file mode 100644 index 0000000..34d06b2 --- /dev/null +++ b/vendor/freetype/builds/compiler/emx.mk @@ -0,0 +1,77 @@ +# +# FreeType 2 emx-specific definitions +# + + +# Copyright (C) 2003-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Compiler command line name +# +CC := set GCCOPT="-ansi -pedantic"; gcc +COMPILER_SEP := / + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := o +SO := o + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := a +SA := a + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c -g -O6 -Wall + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= + + +# Library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY)) +LINK_LIBRARY = $(foreach m,$(OBJECTS_LIST),$(AR) -r $@ $(m);) echo > nul + + +# EOF diff --git a/vendor/freetype/builds/compiler/gcc-dev.mk b/vendor/freetype/builds/compiler/gcc-dev.mk new file mode 100644 index 0000000..a6ded52 --- /dev/null +++ b/vendor/freetype/builds/compiler/gcc-dev.mk @@ -0,0 +1,96 @@ +# +# FreeType 2 gcc-specific with NO OPTIMIZATIONS + DEBUGGING +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Compiler command line name +# +CC := gcc +COMPILER_SEP := / + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := o +SO := o + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := a +SA := a + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +ifndef CFLAGS + ifeq ($(findstring g++,$(CC)),) + nested_externs := -Wnested-externs + strict_prototypes := -Wstrict-prototypes + endif + + CFLAGS := -c -g -O0 \ + -Wall \ + -W \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wwrite-strings \ + -Wredundant-decls \ + -Wno-long-long \ + $(nested_externs) \ + $(strict_prototypes) +endif + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# You can override this on the command line. +# +ANSIFLAGS ?= -std=c99 -pedantic + + +# Library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY)) +LINK_LIBRARY = $(AR) -r $@ $(OBJECTS_LIST) + + +# EOF diff --git a/vendor/freetype/builds/compiler/gcc.mk b/vendor/freetype/builds/compiler/gcc.mk new file mode 100644 index 0000000..20ca969 --- /dev/null +++ b/vendor/freetype/builds/compiler/gcc.mk @@ -0,0 +1,77 @@ +# +# FreeType 2 gcc-specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Compiler command line name +# +CC := gcc +COMPILER_SEP := / + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := o +SO := o + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := a +SA := a + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c -g -O3 -Wall + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= -std=c99 -pedantic + + +# Library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY)) +LINK_LIBRARY = $(AR) -r $@ $(OBJECTS_LIST) + + +# EOF diff --git a/vendor/freetype/builds/compiler/intelc.mk b/vendor/freetype/builds/compiler/intelc.mk new file mode 100644 index 0000000..1f72493 --- /dev/null +++ b/vendor/freetype/builds/compiler/intelc.mk @@ -0,0 +1,85 @@ +# +# FreeType 2 Intel C/C++ definitions (VC++ compatibility mode) +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# compiler command line name +# +CC := icl +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := obj +SO := obj + + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := lib +SA := lib + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := /I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := /D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := /Fl + + +# Target flag. +# +T := /Fo +TE := /Fe + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +# Note that the Intel C/C++ compiler version 4.5 complains about +# the use of FT_FIELD_OFFSET with "value must be arithmetic type"! +# This really looks like a bug in the compiler because the macro +# _does_ compute an arithmetic value, so we disable this warning +# with "/Qwd32". +# +CFLAGS ?= /nologo /c /Ox /G5 /W3 /Qwd32 + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= /Qansi_alias /Za + +# Library linking +# +#CLEAN_LIBRARY = +LINK_LIBRARY = lib /nologo /out:$(subst /,$(COMPILER_SEP),$@ $(OBJECTS_LIST)) + + +# EOF diff --git a/vendor/freetype/builds/compiler/unix-lcc.mk b/vendor/freetype/builds/compiler/unix-lcc.mk new file mode 100644 index 0000000..af11d17 --- /dev/null +++ b/vendor/freetype/builds/compiler/unix-lcc.mk @@ -0,0 +1,83 @@ +# +# FreeType 2 Unix LCC specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Command line name +# +CC := lcc +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := o +SO := o + + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := a +SA := a + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c -g + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +# LCC is pure ANSI anyway! +# +# the "-A" flag simply increments verbosity about non ANSI code +# +ANSIFLAGS ?= -A + + +# library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(PROJECT_LIBRARY) +LINK_LIBRARY = $(AR) -r $@ $(OBJECTS_LIST) + + +# EOF diff --git a/vendor/freetype/builds/compiler/visualage.mk b/vendor/freetype/builds/compiler/visualage.mk new file mode 100644 index 0000000..75e9023 --- /dev/null +++ b/vendor/freetype/builds/compiler/visualage.mk @@ -0,0 +1,76 @@ +# +# FreeType 2 Visual Age C++ specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# command line compiler name +# +CC := icc +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := obj +SO := obj + + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := lib +SA := lib + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := /I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := /D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := /Fl + + +# Target flag. +# +T := /Fo + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +CFLAGS ?= /Q- /Gd+ /O2 /G5 /W3 /C + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSI_FLAGS := /Sa + + +# Library linking +# +#CLEAN_LIBRARY := +LINK_LIBRARY = lib /nologo /out:$(subst /,$(COMPILER_SEP),$@ $(OBJECTS_LIST)) + + +# EOF diff --git a/vendor/freetype/builds/compiler/visualc.mk b/vendor/freetype/builds/compiler/visualc.mk new file mode 100644 index 0000000..30b03fc --- /dev/null +++ b/vendor/freetype/builds/compiler/visualc.mk @@ -0,0 +1,82 @@ +# +# FreeType 2 Visual C++ definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# compiler command line name +# +CC := cl +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := obj +SO := obj + + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := lib +SA := lib + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := /I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := /D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := /Fl + + +# Target flag. +# +T := /Fo + +# Target executable flag +# +TE := /Fe + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= /nologo /c /Ox /W3 /WX + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= /Za /D_CRT_SECURE_NO_DEPRECATE + + +# Library linking +# +#CLEAN_LIBRARY = +LINK_LIBRARY = lib /nologo /out:$(subst /,$(COMPILER_SEP),$@ $(OBJECTS_LIST)) + + +# EOF diff --git a/vendor/freetype/builds/compiler/watcom.mk b/vendor/freetype/builds/compiler/watcom.mk new file mode 100644 index 0000000..61f8cd7 --- /dev/null +++ b/vendor/freetype/builds/compiler/watcom.mk @@ -0,0 +1,81 @@ +# +# FreeType 2 Watcom-specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Compiler command line name +# +CC := wcc386 +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := obj +SO := obj + + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := lib +SA := lib + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I= + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -FO= + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -zq + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS ?= -za + + +# Library linking +# +CLEAN_LIBRARY ?= $(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY)) +LINK_LIBRARY = $(subst /,$(COMPILER_SEP), \ + wlib -q -n $@; \ + $(foreach m, $(OBJECTS_LIST), wlib -q $@ +$(m);) \ + echo > nul) + +# EOF diff --git a/vendor/freetype/builds/compiler/win-lcc.mk b/vendor/freetype/builds/compiler/win-lcc.mk new file mode 100644 index 0000000..92f653e --- /dev/null +++ b/vendor/freetype/builds/compiler/win-lcc.mk @@ -0,0 +1,81 @@ +# +# FreeType 2 Win32-LCC specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Command line name +# +CC := lcc +COMPILER_SEP := $(SEP) + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := obj +SO := obj + + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := lib +SA := lib + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -Fl + + +# Target flag. +# +T := -Fo + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +CFLAGS ?= -c -g2 -O + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +# LCC is pure ANSI anyway! +# +ANSIFLAGS ?= + + +# library linking +# +#CLEAN_LIBRARY := +LINK_LIBRARY = lcclib /out:$(subst /,$(COMPILER_SEP),$@ $(OBJECTS_LIST)) + + +# EOF diff --git a/vendor/freetype/builds/detect.mk b/vendor/freetype/builds/detect.mk new file mode 100644 index 0000000..d5cddb0 --- /dev/null +++ b/vendor/freetype/builds/detect.mk @@ -0,0 +1,128 @@ +# +# FreeType 2 host platform detection rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# This sub-Makefile is in charge of detecting the current platform. It sets +# the following variables: +# +# PLATFORM_DIR The configuration and system-specific directory. Usually +# `builds/$(PLATFORM)' but can be different for custom builds +# of the library. +# +# The following variables must be defined in system specific `detect.mk' +# files: +# +# PLATFORM The detected platform. This will default to `ansi' if +# auto-detection fails. +# CONFIG_FILE The configuration sub-makefile to use. This usually depends +# on the compiler defined in the `CC' environment variable. +# DELETE The shell command used to remove a given file. +# COPY The shell command used to copy one file. +# SEP The platform-specific directory separator. +# COMPILER_SEP The separator used in arguments of the compilation tools. +# CC The compiler to use. +# +# You need to set the following variable(s) before calling it: +# +# TOP_DIR The top-most directory in the FreeType library source +# hierarchy. If not defined, it will default to `.'. + +# Set auto-detection default to `ansi' resp. UNIX-like operating systems. +# +PLATFORM := ansi +DELETE := $(RM) +COPY := cp +CAT := cat +SEP := / + +BUILD_CONFIG := $(TOP_DIR)/builds + +# These two assignments must be delayed. +PLATFORM_DIR = $(BUILD_CONFIG)/$(PLATFORM) +CONFIG_RULES = $(PLATFORM_DIR)/$(CONFIG_FILE) + +# We define the BACKSLASH variable to hold a single back-slash character. +# This is needed because a line like +# +# SEP := \ +# +# does not work with GNU Make (the backslash is interpreted as a line +# continuation). While a line like +# +# SEP := \\ +# +# really defines $(SEP) as `\' on Unix, and `\\' on Dos and Windows! +# +BACKSLASH := $(strip \ ) + +# Find all auto-detectable platforms. +# +PLATFORMS := $(notdir $(subst /detect.mk,,$(wildcard $(BUILD_CONFIG)/*/detect.mk))) +.PHONY: $(PLATFORMS) ansi + +# Filter out platform specified as setup target. +# +PLATFORM := $(firstword $(filter $(MAKECMDGOALS),$(PLATFORMS))) + +# If no setup target platform was specified, enable auto-detection/ +# default platform. +# +ifeq ($(PLATFORM),) + PLATFORM := ansi +endif + +# If the user has explicitly asked for `ansi' on the command line, +# disable auto-detection. +# +ifeq ($(findstring ansi,$(MAKECMDGOALS)),) + # Now, include all detection rule files found in the `builds/' + # directories. Note that the calling order of the various `detect.mk' + # files isn't predictable. + # + include $(wildcard $(BUILD_CONFIG)/*/detect.mk) +endif + +# In case no detection rule file was successful, use the default. +# +ifndef CONFIG_FILE + CONFIG_FILE := ansi.mk + setup: std_setup + .PHONY: setup +endif + +# Flash out and copy rules. +# +.PHONY: std_setup + +std_setup: + $(info ) + $(info $(PROJECT_TITLE) build system -- automatic system detection) + $(info ) + $(info The following settings are used:) + $(info ) + $(info $(empty) platform $(PLATFORM)) + $(info $(empty) compiler $(CC)) + $(info $(empty) configuration directory $(subst /,$(SEP),$(PLATFORM_DIR))) + $(info $(empty) configuration rules $(subst /,$(SEP),$(CONFIG_RULES))) + $(info ) + $(info If this does not correspond to your system or settings please remove the file) + $(info `$(CONFIG_MK)' from this directory then read the INSTALL file for help.) + $(info ) + $(info Otherwise, simply type `$(MAKE)' again to build the library,) + $(info or `$(MAKE) refdoc' to build the API reference (this needs Python >= 3.5).) + $(info ) + @$(COPY) $(subst /,$(SEP),$(CONFIG_RULES) $(CONFIG_MK)) + + +# EOF diff --git a/vendor/freetype/builds/dos/detect.mk b/vendor/freetype/builds/dos/detect.mk new file mode 100644 index 0000000..8ed148b --- /dev/null +++ b/vendor/freetype/builds/dos/detect.mk @@ -0,0 +1,152 @@ +# +# FreeType 2 configuration file to detect a DOS host platform. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +.PHONY: setup + + +ifeq ($(PLATFORM),ansi) + + # Test for DJGPP by checking the DJGPP environment variable, which must be + # set in order to use the system (ie. it will always be present when the + # `make' utility is run). + # + # We test for the COMSPEC environment variable, then run the `ver' + # command-line program to see if its output contains the word `Dos' or + # `DOS'. + # + # If this is true, we are running a Dos-ish platform (or an emulation). + # + ifdef DJGPP + PLATFORM := dos + else + ifdef COMSPEC + is_dos := $(findstring DOS,$(subst Dos,DOS,$(shell ver))) + + # We try to recognize a Dos session under OS/2. The `ver' command + # returns `Operating System/2 ...' there, so `is_dos' should be empty. + # + # To recognize a Dos session under OS/2, we check COMSPEC for the + # substring `MDOS\COMMAND' + # + ifeq ($(is_dos),) + is_dos := $(findstring MDOS\COMMAND,$(COMSPEC)) + endif + + # We also try to recognize Dos 7.x without Windows 9X launched. + # See builds/windows/detect.mk for explanations about the logic. + # + ifeq ($(is_dos),) + ifdef winbootdir +#ifneq ($(OS),Windows_NT) + # If windows is available, do not trigger this test. + ifndef windir + is_dos := $(findstring Windows,$(strip $(shell ver))) + endif +#endif + endif + endif + + endif # test COMSPEC + + ifneq ($(is_dos),) + + PLATFORM := dos + + endif # test Dos + endif # test DJGPP +endif # test PLATFORM ansi + +ifeq ($(PLATFORM),dos) + + # Use DJGPP (i.e. gcc) by default. + # + CONFIG_FILE := dos-gcc.mk + CC ?= gcc + + # additionally, we provide hooks for various other compilers + # + ifneq ($(findstring emx,$(MAKECMDGOALS)),) # EMX gcc + CONFIG_FILE := dos-emx.mk + CC := gcc + + .PHONY: emx + emx: setup + @cd . + endif + + ifneq ($(findstring turboc,$(MAKECMDGOALS)),) # Turbo C + CONFIG_FILE := dos-tcc.mk + CC := tcc + + .PHONY: turboc + turboc: setup + @cd . + endif + + ifneq ($(findstring watcom,$(MAKECMDGOALS)),) # Watcom C/C++ + CONFIG_FILE := dos-wat.mk + CC := wcc386 + + .PHONY: watcom + watcom: setup + @cd . + endif + + ifneq ($(findstring borlandc,$(MAKECMDGOALS)),) # Borland C/C++ 32-bit + CONFIG_FILE := dos-bcc.mk + CC := bcc32 + + .PHONY: borlandc + borlandc: setup + @cd . + endif + + ifneq ($(findstring borlandc16,$(MAKECMDGOALS)),) # Borland C/C++ 16-bit + CONFIG_FILE := dos-bcc.mk + CC := bcc + + .PHONY: borlandc16 + borlandc16: setup + @cd . + endif + + ifneq ($(findstring bash,$(SHELL)),) # check for bash + SEP := / + DELETE := rm + COPY := cp + CAT := cat + setup: std_setup + else + SEP := $(BACKSLASH) + DELETE := del + CAT := type + + # Setting COPY is a bit trickier. We can be running DJGPP on some + # Windows NT derivatives, like XP. See builds/windows/detect.mk for + # explanations why we need hacking here. + # + ifeq ($(OS),Windows_NT) + COPY := cmd.exe /c copy + else + COPY := copy + endif # test NT + + setup: std_setup + endif + +endif # test PLATFORM dos + + +# EOF diff --git a/vendor/freetype/builds/dos/dos-def.mk b/vendor/freetype/builds/dos/dos-def.mk new file mode 100644 index 0000000..37cb2c1 --- /dev/null +++ b/vendor/freetype/builds/dos/dos-def.mk @@ -0,0 +1,48 @@ +# +# FreeType 2 DOS specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DELETE := del +CAT := type +SEP := $(strip \ ) +PLATFORM_DIR := $(TOP_DIR)/builds/dos +PLATFORM := dos + +# This is used for `make refdoc' and `make refdoc-venv' +# +BIN := Scripts + +# The executable file extension (for tools), *with* leading dot. +# +E := .exe + +# The directory where all library files are placed. +# +# By default, this is the same as $(OBJ_DIR); however, this can be changed +# to suit particular needs. +# +LIB_DIR := $(OBJ_DIR) + +# The name of the final library file. Note that the DOS-specific Makefile +# uses a shorter (8.3) name. +# +LIBRARY := $(PROJECT) + + +# The NO_OUTPUT macro is used to ignore the output of commands. +# +NO_OUTPUT = > nul + + +# EOF diff --git a/vendor/freetype/builds/dos/dos-emx.mk b/vendor/freetype/builds/dos/dos-emx.mk new file mode 100644 index 0000000..23181d7 --- /dev/null +++ b/vendor/freetype/builds/dos/dos-emx.mk @@ -0,0 +1,21 @@ +# +# FreeType 2 configuration rules for the EMX gcc compiler +# + + +# Copyright (C) 2003-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +include $(TOP_DIR)/builds/dos/dos-def.mk +include $(TOP_DIR)/builds/compiler/emx.mk +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/dos/dos-gcc.mk b/vendor/freetype/builds/dos/dos-gcc.mk new file mode 100644 index 0000000..cd695db --- /dev/null +++ b/vendor/freetype/builds/dos/dos-gcc.mk @@ -0,0 +1,21 @@ +# +# FreeType 2 configuration rules for the DJGPP compiler +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +include $(TOP_DIR)/builds/dos/dos-def.mk +include $(TOP_DIR)/builds/compiler/gcc.mk +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/dos/dos-wat.mk b/vendor/freetype/builds/dos/dos-wat.mk new file mode 100644 index 0000000..a6b65cb --- /dev/null +++ b/vendor/freetype/builds/dos/dos-wat.mk @@ -0,0 +1,20 @@ +# +# FreeType 2 configuration rules for the Watcom C/C++ compiler +# + + +# Copyright (C) 2003-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +include $(TOP_DIR)/builds/dos/dos-def.mk +include $(TOP_DIR)/builds/compiler/watcom.mk +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/exports.mk b/vendor/freetype/builds/exports.mk new file mode 100644 index 0000000..b10924a --- /dev/null +++ b/vendor/freetype/builds/exports.mk @@ -0,0 +1,80 @@ +# +# FreeType 2 exports sub-Makefile +# + + +# Copyright (C) 2005-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# DO NOT INVOKE THIS MAKEFILE DIRECTLY! IT IS MEANT TO BE INCLUDED BY +# OTHER MAKEFILES. + + +# This sub-Makefile is used to compute the list of exported symbols whenever +# the EXPORTS_LIST variable is defined by one of the platform or compiler +# specific build files. +# +# EXPORTS_LIST contains the name of the `list' file, for example a Windows +# .DEF file. +# +ifneq ($(EXPORTS_LIST),) + + # CCexe is the compiler used to compile the `apinames' tool program + # on the host machine. This isn't necessarily the same as the compiler + # which can be a cross-compiler for a different architecture, for example. + # + ifeq ($(CCexe),) + CCexe := $(CC) + endif + + # TE acts like T, but for executables instead of object files. + ifeq ($(TE),) + TE := $T + endif + + # The list of public headers we're going to parse. + PUBLIC_HEADERS := $(filter-out $(PUBLIC_DIR)/ftmac.h, \ + $(wildcard $(PUBLIC_DIR)/*.h)) + ifneq ($(ftmac_c),) + PUBLIC_HEADERS += $(PUBLIC_DIR)/ftmac.h + endif + + # The `apinames' source and executable. We use $E_BUILD as the host + # executable suffix, which *includes* the final dot. + # + # Note that $(APINAMES_OPTIONS) is empty, except for Windows compilers. + # + APINAMES_SRC := $(subst /,$(SEP),$(TOP_DIR)/src/tools/apinames.c) + APINAMES_EXE := $(subst /,$(SEP),$(OBJ_DIR)/apinames$(E_BUILD)) + + $(APINAMES_EXE): $(APINAMES_SRC) + $(CCexe) $(CCexe_CFLAGS) $(TE)$@ $< $(CCexe_LDFLAGS) + + .PHONY: symbols_list + + symbols_list: $(EXPORTS_LIST) + + # We manually add TT_New_Context and TT_RunIns, which are needed by TT + # debuggers, to the EXPORTS_LIST. + # + $(EXPORTS_LIST): $(APINAMES_EXE) $(PUBLIC_HEADERS) + $(subst /,$(SEP),$(APINAMES_EXE)) -o$@ $(APINAMES_OPTIONS) $(PUBLIC_HEADERS) + @echo TT_New_Context >> $(EXPORTS_LIST) + @echo TT_RunIns >> $(EXPORTS_LIST) + + $(PROJECT_LIBRARY): $(EXPORTS_LIST) + + CLEAN += $(EXPORTS_LIST) \ + $(APINAMES_EXE) + +endif + + +# EOF diff --git a/vendor/freetype/builds/freetype.mk b/vendor/freetype/builds/freetype.mk new file mode 100644 index 0000000..b3fac80 --- /dev/null +++ b/vendor/freetype/builds/freetype.mk @@ -0,0 +1,385 @@ +# +# FreeType 2 library sub-Makefile +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# DO NOT INVOKE THIS MAKEFILE DIRECTLY! IT IS MEANT TO BE INCLUDED BY +# OTHER MAKEFILES. + + +# The following variables (set by other Makefile components, in the +# environment, or on the command line) are used: +# +# PLATFORM_DIR The architecture-dependent directory, +# e.g., `$(TOP_DIR)/builds/unix'. Added to INCLUDES also. +# +# OBJ_DIR The directory in which object files are created. +# +# LIB_DIR The directory in which the library is created. +# +# DOC_DIR The directory in which the API reference is created. +# +# INCLUDES A list of directories to be included additionally. +# +# DEVEL_DIR Development directory which is added to the INCLUDES +# variable before the standard include directories. +# +# CFLAGS Compilation flags. This overrides the default settings +# in the platform-specific configuration files. +# +# FTSYS_SRC If set, its value is used as the name of a replacement +# file for `src/base/ftsystem.c'. +# +# FTDEBUG_SRC If set, its value is used as the name of a replacement +# file for `src/base/ftdebug.c'. [For a normal build, this +# file does nothing.] +# +# FTMODULE_H The file which contains the list of module classes for +# the current build. Usually, this is automatically +# created by `modules.mk'. +# +# BASE_OBJ_S +# BASE_OBJ_M A list of base objects (for single object and multiple +# object builds, respectively). Set up in +# `src/base/rules.mk'. +# +# BASE_EXT_OBJ A list of base extension objects. Set up in +# `src/base/rules.mk'. +# +# DRV_OBJ_S +# DRV_OBJ_M A list of driver objects (for single object and multiple +# object builds, respectively). Set up cumulatively in +# `src//rules.mk'. +# +# CLEAN +# DISTCLEAN The sub-makefiles can append additional stuff to these two +# variables which is to be removed for the `clean' resp. +# `distclean' target. +# +# TOP_DIR, SEP, +# COMPILER_SEP, +# LIBRARY, CC, +# A, I, O, T Check `config.mk' for details. + + +# The targets `objects' and `library' are defined at the end of this +# Makefile after all other rules have been included. +# +.PHONY: single multi objects library refdoc refdoc-venv + +# default target -- build single objects and library +# +single: objects library + +# `multi' target -- build multiple objects and library +# +multi: objects library + + +# The FreeType source directory, usually `./src'. +# +SRC_DIR := $(TOP_DIR)/src + +# The directory where the base layer components are placed, usually +# `./src/base'. +# +BASE_DIR := $(SRC_DIR)/base + +# Other derived directories. +# +PUBLIC_DIR := $(TOP_DIR)/include/freetype +INTERNAL_DIR := $(PUBLIC_DIR)/internal +SERVICES_DIR := $(INTERNAL_DIR)/services +CONFIG_DIR := $(PUBLIC_DIR)/config + +# The documentation directory. +# +DOC_DIR ?= $(TOP_DIR)/docs + +# The final name of the library file. +# +PROJECT_LIBRARY := $(LIB_DIR)/$(LIBRARY).$A + + +# include paths +# +# IMPORTANT NOTE: The architecture-dependent directory must ALWAYS be placed +# before the standard include list. Porters are then able to +# put their own version of some of the FreeType components +# in the `builds/' directory, as these files will +# override the default sources. +# +INCLUDES := $(subst /,$(COMPILER_SEP),$(OBJ_DIR) \ + $(DEVEL_DIR) \ + $(PLATFORM_DIR) \ + $(TOP_DIR)/include) + +INCLUDE_FLAGS := $(INCLUDES:%=$I%) + +# For a development build, we assume that the external library dependencies +# defined in `ftoption.h' are fulfilled, so we directly access the necessary +# include directory information using `pkg-config'. +# +ifdef DEVEL_DIR + INCLUDE_FLAGS += $(shell pkg-config --cflags libpng) + INCLUDE_FLAGS += $(shell pkg-config --cflags harfbuzz) + INCLUDE_FLAGS += $(shell pkg-config --cflags libbrotlidec) +endif + + +# C flags used for the compilation of an object file. This must include at +# least the paths for the `base' and `builds/' directories; +# debug/optimization/warning flags + ansi compliance if needed. +# +# $(INCLUDE_FLAGS) should come before $(CFLAGS) to avoid problems with +# old FreeType versions. +# +# Note what we also define the macro FT2_BUILD_LIBRARY when building +# FreeType. This is required to let our sources include the internal +# headers (something forbidden by clients). +# +# `CPPFLAGS' might be specified by the user in the environment. +# +FT_CFLAGS = $(CPPFLAGS) \ + $(CFLAGS) \ + $DFT2_BUILD_LIBRARY + +FT_COMPILE := $(CC) $(ANSIFLAGS) $(INCLUDE_FLAGS) $(FT_CFLAGS) + + +# Include the `exports' rules file. +# +include $(TOP_DIR)/builds/exports.mk + + +# Initialize the list of objects. +# +OBJECTS_LIST := + + +# Define $(PUBLIC_H) as the list of all public header files located in +# `$(TOP_DIR)/include/freetype'. $(INTERNAL_H), and $(CONFIG_H) are defined +# similarly. $(FTOPTION_H) is the option file used in the compilation. +# +# This is used to simplify the dependency rules -- if one of these files +# changes, the whole library is recompiled. +# +ifneq ($(wildcard $(OBJ_DIR)/ftoption.h),) + FTOPTION_H := $(OBJ_DIR)/ftoption.h +else ifneq ($(wildcard $(PLATFORM_DIR)/ftoption.h),) + FTOPTION_H := $(PLATFORM_DIR)/ftoption.h +endif + +PUBLIC_H := $(wildcard $(PUBLIC_DIR)/*.h) +INTERNAL_H := $(wildcard $(INTERNAL_DIR)/*.h) \ + $(wildcard $(SERVICES_DIR)/*.h) +CONFIG_H := $(wildcard $(CONFIG_DIR)/*.h) \ + $(wildcard $(PLATFORM_DIR)/config/*.h) \ + $(FTMODULE_H) \ + $(FTOPTION_H) +DEVEL_H := $(wildcard $(TOP_DIR)/devel/*.h) + +FREETYPE_H := $(PUBLIC_H) $(INTERNAL_H) $(CONFIG_H) $(DEVEL_H) + + +# ftsystem component +# +FTSYS_SRC ?= $(BASE_DIR)/ftsystem.c + +FTSYS_OBJ := $(OBJ_DIR)/ftsystem.$O + +OBJECTS_LIST += $(FTSYS_OBJ) + +$(FTSYS_OBJ): $(FTSYS_SRC) $(FREETYPE_H) + $(FT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# ftdebug component +# +FTDEBUG_SRC ?= $(BASE_DIR)/ftdebug.c + +FTDEBUG_OBJ := $(OBJ_DIR)/ftdebug.$O + +OBJECTS_LIST += $(FTDEBUG_OBJ) + +$(FTDEBUG_OBJ): $(FTDEBUG_SRC) $(FREETYPE_H) + $(FT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# Include all rule files from FreeType components. +# +include $(SRC_DIR)/base/rules.mk +include $(patsubst %,$(SRC_DIR)/%/rules.mk,$(MODULES)) +include $(SRC_DIR)/dlg/rules.mk + + +# ftinit component +# +# The C source `ftinit.c' contains the FreeType initialization routines. +# It is able to automatically register one or more drivers when the API +# function FT_Init_FreeType() is called. +# +# The set of initial drivers is determined by the driver Makefiles +# includes above. Each driver Makefile updates the FTINIT_xxx lists +# which contain additional include paths and macros used to compile the +# single `ftinit.c' source. +# +FTINIT_SRC := $(BASE_DIR)/ftinit.c +FTINIT_OBJ := $(OBJ_DIR)/ftinit.$O + +OBJECTS_LIST += $(FTINIT_OBJ) + +$(FTINIT_OBJ): $(FTINIT_SRC) $(FREETYPE_H) + $(FT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# ftver component +# +# The VERSIONINFO resource `ftver.rc' contains version and copyright +# to be compiled by windres and tagged into DLL usually. +# +ifneq ($(RC),) + FTVER_SRC := $(BASE_DIR)/ftver.rc + FTVER_OBJ := $(OBJ_DIR)/ftver.$O + + OBJECTS_LIST += $(FTVER_OBJ) + + $(FTVER_OBJ): $(FTVER_SRC) + $(RC) -o $@ $< +endif + + +# All FreeType library objects. +# +OBJ_M := $(BASE_OBJ_M) $(BASE_EXT_OBJ) $(DRV_OBJS_M) $(DLG_OBJS_M) +OBJ_S := $(BASE_OBJ_S) $(BASE_EXT_OBJ) $(DRV_OBJS_S) $(DLG_OBJS_S) + + +# The target `multi' on the Make command line indicates that we want to +# compile each source file independently. +# +# Otherwise, each module/driver is compiled in a single object file through +# source file inclusion (see `src/base/ftbase.c' or +# `src/truetype/truetype.c' for examples). +# +BASE_OBJECTS := $(OBJECTS_LIST) + +ifneq ($(findstring multi,$(MAKECMDGOALS)),) + OBJECTS_LIST += $(OBJ_M) +else + OBJECTS_LIST += $(OBJ_S) +endif + +objects: $(OBJECTS_LIST) + +library: $(PROJECT_LIBRARY) + +# Run `docwriter' in the current Python environment. +# +PYTHON ?= python + +refdoc: + @echo Running docwriter... + $(PYTHON) -m docwriter \ + --prefix=ft2 \ + --title=FreeType-$(version) \ + --site=reference \ + --output=$(DOC_DIR) \ + $(PUBLIC_DIR)/*.h \ + $(PUBLIC_DIR)/config/*.h \ + $(PUBLIC_DIR)/cache/*.h + @echo Building static site... + cd $(DOC_DIR) && $(PYTHON) -m mkdocs build + @echo Done. + +# Variables for running `refdoc' with Python's `virtualenv'. The +# environment is created in `DOC_DIR/env' and is gitignored. +# +# We still need to cd into `DOC_DIR' to build `mkdocs' because paths in +# `mkdocs.yml' are relative to the current working directory. +# +VENV_NAME := env +VENV_DIR := $(DOC_DIR)$(SEP)$(VENV_NAME) +ENV_PYTHON := $(VENV_DIR)$(SEP)$(BIN)$(SEP)$(PYTHON) + +refdoc-venv: + @echo Setting up virtualenv for Python... + virtualenv --python=$(PYTHON) $(VENV_DIR) + @echo Installing docwriter... + $(ENV_PYTHON) -m pip install docwriter + @echo Running docwriter... + $(ENV_PYTHON) -m docwriter \ + --prefix=ft2 \ + --title=FreeType-$(version) \ + --site=reference \ + --output=$(DOC_DIR) \ + $(PUBLIC_DIR)/*.h \ + $(PUBLIC_DIR)/config/*.h \ + $(PUBLIC_DIR)/cache/*.h + @echo Building static site... + cd $(DOC_DIR) && $(VENV_NAME)$(SEP)$(BIN)$(SEP)python -m mkdocs build + @echo Done. + +.PHONY: clean_project_std distclean_project_std + +# Standard cleaning and distclean rules. These are not accepted +# on all systems though. +# +clean_project_std: + -$(DELETE) $(BASE_OBJECTS) $(OBJ_M) $(OBJ_S) $(CLEAN) + +distclean_project_std: clean_project_std + -$(DELETE) $(PROJECT_LIBRARY) + -$(DELETE) *.orig *~ core *.core $(DISTCLEAN) + + +.PHONY: clean_project_dos distclean_project_dos + +# The Dos command shell does not support very long list of arguments, so +# we are stuck with wildcards. +# +# Don't break the command lines with \; this prevents the "del" command from +# working correctly on Win9x. +# +clean_project_dos: + -$(DELETE) $(subst /,$(SEP),$(OBJ_DIR)/*.$O $(CLEAN) $(NO_OUTPUT)) + +distclean_project_dos: clean_project_dos + -$(DELETE) $(subst /,$(SEP),$(PROJECT_LIBRARY) $(DISTCLEAN) $(NO_OUTPUT)) + + +.PHONY: remove_config_mk remove_ftmodule_h + +# Remove configuration file (used for distclean). +# +remove_config_mk: + -$(DELETE) $(subst /,$(SEP),$(CONFIG_MK) $(NO_OUTPUT)) + +# Remove module list (used for distclean). +# +remove_ftmodule_h: + -$(DELETE) $(subst /,$(SEP),$(FTMODULE_H) $(NO_OUTPUT)) + + +.PHONY: clean distclean + +# The `config.mk' file must define `clean_project' and `distclean_project'. +# Implementations may use to relay these to either the `std' or `dos' +# versions from above, or simply provide their own implementation. +# +clean: clean_project +distclean: distclean_project remove_config_mk remove_ftmodule_h + -$(DELETE) $(subst /,$(SEP),$(DOC_DIR)/*.html $(NO_OUTPUT)) + + +# EOF diff --git a/vendor/freetype/builds/link_dos.mk b/vendor/freetype/builds/link_dos.mk new file mode 100644 index 0000000..b3dc451 --- /dev/null +++ b/vendor/freetype/builds/link_dos.mk @@ -0,0 +1,42 @@ +# +# Link instructions for Dos-like systems (Dos, Win32, OS/2) +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +ifdef BUILD_PROJECT + + .PHONY: clean_project distclean_project + + # Now include the main sub-makefile. It contains all the rules used to + # build the library with the previous variables defined. + # + include $(TOP_DIR)/builds/$(PROJECT).mk + + # The cleanup targets. + # + clean_project: clean_project_dos + distclean_project: distclean_project_dos + + # This final rule is used to link all object files into a single library. + # this is compiler-specific + # + $(PROJECT_LIBRARY): $(OBJECTS_LIST) + ifdef CLEAN_LIBRARY + -$(CLEAN_LIBRARY) $(NO_OUTPUT) + endif + $(LINK_LIBRARY) + +endif + + +# EOF diff --git a/vendor/freetype/builds/link_std.mk b/vendor/freetype/builds/link_std.mk new file mode 100644 index 0000000..aca8ec4 --- /dev/null +++ b/vendor/freetype/builds/link_std.mk @@ -0,0 +1,42 @@ +# +# Link instructions for standard systems +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +ifdef BUILD_PROJECT + + .PHONY: clean_project distclean_project + + # Now include the main sub-makefile. It contains all the rules used to + # build the library with the previous variables defined. + # + include $(TOP_DIR)/builds/$(PROJECT).mk + + # The cleanup targets. + # + clean_project: clean_project_std + distclean_project: distclean_project_std + + # This final rule is used to link all object files into a single library. + # this is compiler-specific + # + $(PROJECT_LIBRARY): $(OBJECTS_LIST) + ifdef CLEAN_LIBRARY + -$(CLEAN_LIBRARY) $(NO_OUTPUT) + endif + $(LINK_LIBRARY) + +endif + + +# EOF diff --git a/vendor/freetype/builds/mac/FreeType.m68k_cfm.make.txt b/vendor/freetype/builds/mac/FreeType.m68k_cfm.make.txt new file mode 100644 index 0000000..b74565f --- /dev/null +++ b/vendor/freetype/builds/mac/FreeType.m68k_cfm.make.txt @@ -0,0 +1,209 @@ +# File: FreeType.m68k_cfm.make +# Target: FreeType.m68k_cfm +# Created: Thursday, October 27, 2005 09:23:25 PM + + +MAKEFILE = FreeType.m68k_cfm.make +\xA5MondoBuild\xA5 = {MAKEFILE} # Make blank to avoid rebuilds when makefile is modified + +ObjDir = :objs: +Includes = \xB6 + -ansi strict \xB6 + -includes unix \xB6 + -i :include: \xB6 + -i :src: \xB6 + -i :include:freetype:config: + +Sym-68K = -sym off + +COptions = \xB6 + -d FT_MACINTOSH=1 \xB6 + -d HAVE_FSSPEC=1 \xB6 + -d HAVE_FSREF=0 \xB6 + -d HAVE_QUICKDRAW_TOOLBOX=1 \xB6 + -d HAVE_QUICKDRAW_CARBON=0 \xB6 + -d HAVE_ATS=0 \xB6 + -d FT2_BUILD_LIBRARY \xB6 + -d FT_CONFIG_CONFIG_H="" \xB6 + -d FT_CONFIG_MODULES_H="" \xB6 + {Includes} {Sym-68K} -model cfmseg + + +### Source Files ### + +SrcFiles = \xB6 + :src:autofit:autofit.c \xB6 + :builds:mac:ftbase.c \xB6 + :src:base:ftbbox.c \xB6 + :src:base:ftbdf.c \xB6 + :src:base:ftbitmap.c \xB6 + :src:base:ftdebug.c \xB6 + :src:base:ftfstype.c \xB6 + :src:base:ftglyph.c \xB6 + :src:base:ftgxval.c \xB6 + :src:base:ftinit.c \xB6 + :src:base:ftmm.c \xB6 + :src:base:ftotval.c \xB6 + :src:base:ftpfr.c \xB6 + :src:base:ftstroke.c \xB6 + :src:base:ftsynth.c \xB6 + :src:base:ftsystem.c \xB6 + :src:base:fttype1.c \xB6 + :src:base:ftwinfnt.c \xB6 + :src:cache:ftcache.c \xB6 + :src:bdf:bdf.c \xB6 + :src:cff:cff.c \xB6 + :src:cid:type1cid.c \xB6 +# :src:gxvalid:gxvalid.c \xB6 + :src:gzip:ftgzip.c \xB6 + :src:bzip2:ftbzip2.c \xB6 + :src:lzw:ftlzw.c \xB6 + :src:otvalid:otvalid.c \xB6 + :src:pcf:pcf.c \xB6 + :src:pfr:pfr.c \xB6 + :src:psaux:psaux.c \xB6 + :src:pshinter:pshinter.c \xB6 + :src:psnames:psmodule.c \xB6 + :src:raster:raster.c \xB6 + :src:sfnt:sfnt.c \xB6 + :src:smooth:smooth.c \xB6 + :src:truetype:truetype.c \xB6 + :src:type1:type1.c \xB6 + :src:type42:type42.c \xB6 + :src:winfonts:winfnt.c + + +### Object Files ### + +ObjFiles-68K = \xB6 + "{ObjDir}autofit.c.o" \xB6 + "{ObjDir}ftbase.c.o" \xB6 + "{ObjDir}ftbbox.c.o" \xB6 + "{ObjDir}ftbdf.c.o" \xB6 + "{ObjDir}ftbitmap.c.o" \xB6 + "{ObjDir}ftdebug.c.o" \xB6 + "{ObjDir}ftfstype.c.o" \xB6 + "{ObjDir}ftglyph.c.o" \xB6 + "{ObjDir}ftgxval.c.o" \xB6 + "{ObjDir}ftinit.c.o" \xB6 + "{ObjDir}ftmm.c.o" \xB6 + "{ObjDir}ftotval.c.o" \xB6 + "{ObjDir}ftpfr.c.o" \xB6 + "{ObjDir}ftstroke.c.o" \xB6 + "{ObjDir}ftsynth.c.o" \xB6 + "{ObjDir}ftsystem.c.o" \xB6 + "{ObjDir}fttype1.c.o" \xB6 + "{ObjDir}ftwinfnt.c.o" \xB6 + "{ObjDir}ftcache.c.o" \xB6 + "{ObjDir}bdf.c.o" \xB6 + "{ObjDir}cff.c.o" \xB6 + "{ObjDir}type1cid.c.o" \xB6 +# "{ObjDir}gxvalid.c.o" \xB6 + "{ObjDir}ftgzip.c.o" \xB6 + "{ObjDir}ftbzip2.c.o" \xB6 + "{ObjDir}ftlzw.c.o" \xB6 + "{ObjDir}otvalid.c.o" \xB6 + "{ObjDir}pcf.c.o" \xB6 + "{ObjDir}pfr.c.o" \xB6 + "{ObjDir}psaux.c.o" \xB6 + "{ObjDir}pshinter.c.o" \xB6 + "{ObjDir}psmodule.c.o" \xB6 + "{ObjDir}raster.c.o" \xB6 + "{ObjDir}sfnt.c.o" \xB6 + "{ObjDir}smooth.c.o" \xB6 + "{ObjDir}truetype.c.o" \xB6 + "{ObjDir}type1.c.o" \xB6 + "{ObjDir}type42.c.o" \xB6 + "{ObjDir}winfnt.c.o" + + +### Libraries ### + +LibFiles-68K = + + +### Default Rules ### + +.c.o \xC4 .c {\xA5MondoBuild\xA5} + {C} {depDir}{default}.c -o {targDir}{default}.c.o {COptions} + + +### Build Rules ### + +:builds:mac:ftbase.c \xC4\xC4 :src:base:ftbase.c + Duplicate :src:base:ftbase.c :builds:mac:ftbase.c + +"{ObjDir}ftbase.c.o" \xC4\xC4 :builds:mac:ftbase.c + {C} :builds:mac:ftbase.c -o "{ObjDir}ftbase.c.o" \xB6 + -i :builds:mac: \xB6 + -i :src:base: \xB6 + {COptions} + +FreeType.m68k_cfm \xC4\xC4 FreeType.m68k_cfm.o + +FreeType.m68k_cfm.o \xC4\xC4 {ObjFiles-68K} {LibFiles-68K} {\xA5MondoBuild\xA5} + Lib \xB6 + -o {Targ} \xB6 + {ObjFiles-68K} \xB6 + {LibFiles-68K} \xB6 + {Sym-68K} \xB6 + -mf -d + + + +### Required Dependencies ### + +"{ObjDir}autofit.c.o" \xC4 :src:autofit:autofit.c +# "{ObjDir}ftbase.c.o" \xC4 :src:base:ftbase.c +"{ObjDir}ftbbox.c.o" \xC4 :src:base:ftbbox.c +"{ObjDir}ftbdf.c.o" \xC4 :src:base:ftbdf.c +"{ObjDir}ftbitmap.c.o" \xC4 :src:base:ftbitmap.c +"{ObjDir}ftdebug.c.o" \xC4 :src:base:ftdebug.c +"{ObjDir}ftfstype.c.o" \xC4 :src:base:ftfstype.c +"{ObjDir}ftglyph.c.o" \xC4 :src:base:ftglyph.c +"{ObjDir}ftgxval.c.o" \xC4 :src:base:ftgxval.c +"{ObjDir}ftinit.c.o" \xC4 :src:base:ftinit.c +"{ObjDir}ftmm.c.o" \xC4 :src:base:ftmm.c +"{ObjDir}ftotval.c.o" \xC4 :src:base:ftotval.c +"{ObjDir}ftpfr.c.o" \xC4 :src:base:ftpfr.c +"{ObjDir}ftstroke.c.o" \xC4 :src:base:ftstroke.c +"{ObjDir}ftsynth.c.o" \xC4 :src:base:ftsynth.c +"{ObjDir}ftsystem.c.o" \xC4 :src:base:ftsystem.c +"{ObjDir}fttype1.c.o" \xC4 :src:base:fttype1.c +"{ObjDir}ftwinfnt.c.o" \xC4 :src:base:ftwinfnt.c +"{ObjDir}ftcache.c.o" \xC4 :src:cache:ftcache.c +"{ObjDir}bdf.c.o" \xC4 :src:bdf:bdf.c +"{ObjDir}cff.c.o" \xC4 :src:cff:cff.c +"{ObjDir}type1cid.c.o" \xC4 :src:cid:type1cid.c +# "{ObjDir}gxvalid.c.o" \xC4 :src:gxvalid:gxvalid.c +"{ObjDir}ftgzip.c.o" \xC4 :src:gzip:ftgzip.c +"{ObjDir}ftbzip2.c.o" \xC4 :src:bzip2:ftbzip2.c +"{ObjDir}ftlzw.c.o" \xC4 :src:lzw:ftlzw.c +"{ObjDir}otvalid.c.o" \xC4 :src:otvalid:otvalid.c +"{ObjDir}pcf.c.o" \xC4 :src:pcf:pcf.c +"{ObjDir}pfr.c.o" \xC4 :src:pfr:pfr.c +"{ObjDir}psaux.c.o" \xC4 :src:psaux:psaux.c +"{ObjDir}pshinter.c.o" \xC4 :src:pshinter:pshinter.c +"{ObjDir}psmodule.c.o" \xC4 :src:psnames:psmodule.c +"{ObjDir}raster.c.o" \xC4 :src:raster:raster.c +"{ObjDir}sfnt.c.o" \xC4 :src:sfnt:sfnt.c +"{ObjDir}smooth.c.o" \xC4 :src:smooth:smooth.c +"{ObjDir}truetype.c.o" \xC4 :src:truetype:truetype.c +"{ObjDir}type1.c.o" \xC4 :src:type1:type1.c +"{ObjDir}type42.c.o" \xC4 :src:type42:type42.c +"{ObjDir}winfnt.c.o" \xC4 :src:winfonts:winfnt.c + + +### Optional Dependencies ### +### Build this target to generate "include file" dependencies. ### + +Dependencies \xC4 $OutOfDate + MakeDepend \xB6 + -append {MAKEFILE} \xB6 + -ignore "{CIncludes}" \xB6 + -objdir "{ObjDir}" \xB6 + -objext .o \xB6 + {Includes} \xB6 + {SrcFiles} + + diff --git a/vendor/freetype/builds/mac/FreeType.m68k_far.make.txt b/vendor/freetype/builds/mac/FreeType.m68k_far.make.txt new file mode 100644 index 0000000..d880ddb --- /dev/null +++ b/vendor/freetype/builds/mac/FreeType.m68k_far.make.txt @@ -0,0 +1,208 @@ +# File: FreeType.m68k_far.make +# Target: FreeType.m68k_far +# Created: Tuesday, October 25, 2005 03:34:05 PM + + +MAKEFILE = FreeType.m68k_far.make +\xA5MondoBuild\xA5 = {MAKEFILE} # Make blank to avoid rebuilds when makefile is modified + +ObjDir = :objs: +Includes = \xB6 + -includes unix \xB6 + -i :include: \xB6 + -i :src: \xB6 + -i :include:freetype:config: + +Sym-68K = -sym off + +COptions = \xB6 + -d FT_MACINTOSH=1 \xB6 + -d HAVE_FSSPEC=1 \xB6 + -d HAVE_FSREF=0 \xB6 + -d HAVE_QUICKDRAW_TOOLBOX=1 \xB6 + -d HAVE_QUICKDRAW_CARBON=0 \xB6 + -d HAVE_ATS=0 \xB6 + -d FT2_BUILD_LIBRARY \xB6 + -d FT_CONFIG_CONFIG_H="" \xB6 + -d FT_CONFIG_MODULES_H="" \xB6 + {Includes} {Sym-68K} -model far + + +### Source Files ### + +SrcFiles = \xB6 + :src:autofit:autofit.c \xB6 + :builds:mac:ftbase.c \xB6 + :src:base:ftbbox.c \xB6 + :src:base:ftbdf.c \xB6 + :src:base:ftbitmap.c \xB6 + :src:base:ftdebug.c \xB6 + :src:base:ftfstype.c \xB6 + :src:base:ftglyph.c \xB6 + :src:base:ftgxval.c \xB6 + :src:base:ftinit.c \xB6 + :src:base:ftmm.c \xB6 + :src:base:ftotval.c \xB6 + :src:base:ftpfr.c \xB6 + :src:base:ftstroke.c \xB6 + :src:base:ftsynth.c \xB6 + :src:base:ftsystem.c \xB6 + :src:base:fttype1.c \xB6 + :src:base:ftwinfnt.c \xB6 + :src:cache:ftcache.c \xB6 + :src:bdf:bdf.c \xB6 + :src:cff:cff.c \xB6 + :src:cid:type1cid.c \xB6 + :src:gxvalid:gxvalid.c \xB6 + :src:gzip:ftgzip.c \xB6 + :src:bzip2:ftbzip2.c \xB6 + :src:lzw:ftlzw.c \xB6 + :src:otvalid:otvalid.c \xB6 + :src:pcf:pcf.c \xB6 + :src:pfr:pfr.c \xB6 + :src:psaux:psaux.c \xB6 + :src:pshinter:pshinter.c \xB6 + :src:psnames:psmodule.c \xB6 + :src:raster:raster.c \xB6 + :src:sfnt:sfnt.c \xB6 + :src:smooth:smooth.c \xB6 + :src:truetype:truetype.c \xB6 + :src:type1:type1.c \xB6 + :src:type42:type42.c \xB6 + :src:winfonts:winfnt.c + + +### Object Files ### + +ObjFiles-68K = \xB6 + "{ObjDir}autofit.c.o" \xB6 + "{ObjDir}ftbase.c.o" \xB6 + "{ObjDir}ftbbox.c.o" \xB6 + "{ObjDir}ftbdf.c.o" \xB6 + "{ObjDir}ftbitmap.c.o" \xB6 + "{ObjDir}ftdebug.c.o" \xB6 + "{ObjDir}ftfstype.c.o" \xB6 + "{ObjDir}ftglyph.c.o" \xB6 + "{ObjDir}ftgxval.c.o" \xB6 + "{ObjDir}ftinit.c.o" \xB6 + "{ObjDir}ftmm.c.o" \xB6 + "{ObjDir}ftotval.c.o" \xB6 + "{ObjDir}ftpfr.c.o" \xB6 + "{ObjDir}ftstroke.c.o" \xB6 + "{ObjDir}ftsynth.c.o" \xB6 + "{ObjDir}ftsystem.c.o" \xB6 + "{ObjDir}fttype1.c.o" \xB6 + "{ObjDir}ftwinfnt.c.o" \xB6 + "{ObjDir}ftcache.c.o" \xB6 + "{ObjDir}bdf.c.o" \xB6 + "{ObjDir}cff.c.o" \xB6 + "{ObjDir}type1cid.c.o" \xB6 + "{ObjDir}gxvalid.c.o" \xB6 + "{ObjDir}ftgzip.c.o" \xB6 + "{ObjDir}ftbzip2.c.o" \xB6 + "{ObjDir}ftlzw.c.o" \xB6 + "{ObjDir}otvalid.c.o" \xB6 + "{ObjDir}pcf.c.o" \xB6 + "{ObjDir}pfr.c.o" \xB6 + "{ObjDir}psaux.c.o" \xB6 + "{ObjDir}pshinter.c.o" \xB6 + "{ObjDir}psmodule.c.o" \xB6 + "{ObjDir}raster.c.o" \xB6 + "{ObjDir}sfnt.c.o" \xB6 + "{ObjDir}smooth.c.o" \xB6 + "{ObjDir}truetype.c.o" \xB6 + "{ObjDir}type1.c.o" \xB6 + "{ObjDir}type42.c.o" \xB6 + "{ObjDir}winfnt.c.o" + + +### Libraries ### + +LibFiles-68K = + + +### Default Rules ### + +.c.o \xC4 .c {\xA5MondoBuild\xA5} + {C} {depDir}{default}.c -o {targDir}{default}.c.o {COptions} \xB6 + -ansi strict + +### Build Rules ### + +:builds:mac:ftbase.c \xC4\xC4 :src:base:ftbase.c + Duplicate :src:base:ftbase.c :builds:mac:ftbase.c + +"{ObjDir}ftbase.c.o" \xC4\xC4 :builds:mac:ftbase.c + {C} :builds:mac:ftbase.c -o "{ObjDir}ftbase.c.o" \xB6 + -i :builds:mac: \xB6 + -i :src:base: \xB6 + {COptions} + +FreeType.m68k_far \xC4\xC4 FreeType.m68k_far.o + +FreeType.m68k_far.o \xC4\xC4 {ObjFiles-68K} {LibFiles-68K} {\xA5MondoBuild\xA5} + Lib \xB6 + -o {Targ} \xB6 + {ObjFiles-68K} \xB6 + {LibFiles-68K} \xB6 + {Sym-68K} \xB6 + -mf -d + + + +### Required Dependencies ### + +"{ObjDir}autofit.c.o" \xC4 :src:autofit:autofit.c +# "{ObjDir}ftbase.c.o" \xC4 :src:base:ftbase.c +"{ObjDir}ftbbox.c.o" \xC4 :src:base:ftbbox.c +"{ObjDir}ftbdf.c.o" \xC4 :src:base:ftbdf.c +"{ObjDir}ftbitmap.c.o" \xC4 :src:base:ftbitmap.c +"{ObjDir}ftdebug.c.o" \xC4 :src:base:ftdebug.c +"{ObjDir}ftfstype.c.o" \xC4 :src:base:ftfstype.c +"{ObjDir}ftglyph.c.o" \xC4 :src:base:ftglyph.c +"{ObjDir}ftgxval.c.o" \xC4 :src:base:ftgxval.c +"{ObjDir}ftinit.c.o" \xC4 :src:base:ftinit.c +"{ObjDir}ftmm.c.o" \xC4 :src:base:ftmm.c +"{ObjDir}ftotval.c.o" \xC4 :src:base:ftotval.c +"{ObjDir}ftpfr.c.o" \xC4 :src:base:ftpfr.c +"{ObjDir}ftstroke.c.o" \xC4 :src:base:ftstroke.c +"{ObjDir}ftsynth.c.o" \xC4 :src:base:ftsynth.c +"{ObjDir}ftsystem.c.o" \xC4 :src:base:ftsystem.c +"{ObjDir}fttype1.c.o" \xC4 :src:base:fttype1.c +"{ObjDir}ftwinfnt.c.o" \xC4 :src:base:ftwinfnt.c +"{ObjDir}ftcache.c.o" \xC4 :src:cache:ftcache.c +"{ObjDir}bdf.c.o" \xC4 :src:bdf:bdf.c +"{ObjDir}cff.c.o" \xC4 :src:cff:cff.c +"{ObjDir}type1cid.c.o" \xC4 :src:cid:type1cid.c +"{ObjDir}gxvalid.c.o" \xC4 :src:gxvalid:gxvalid.c +"{ObjDir}ftgzip.c.o" \xC4 :src:gzip:ftgzip.c +"{ObjDir}ftbzip2.c.o" \xC4 :src:bzip2:ftbzip2.c +"{ObjDir}ftlzw.c.o" \xC4 :src:lzw:ftlzw.c +"{ObjDir}otvalid.c.o" \xC4 :src:otvalid:otvalid.c +"{ObjDir}pcf.c.o" \xC4 :src:pcf:pcf.c +"{ObjDir}pfr.c.o" \xC4 :src:pfr:pfr.c +"{ObjDir}psaux.c.o" \xC4 :src:psaux:psaux.c +"{ObjDir}pshinter.c.o" \xC4 :src:pshinter:pshinter.c +"{ObjDir}psmodule.c.o" \xC4 :src:psnames:psmodule.c +"{ObjDir}raster.c.o" \xC4 :src:raster:raster.c +"{ObjDir}sfnt.c.o" \xC4 :src:sfnt:sfnt.c +"{ObjDir}smooth.c.o" \xC4 :src:smooth:smooth.c +"{ObjDir}truetype.c.o" \xC4 :src:truetype:truetype.c +"{ObjDir}type1.c.o" \xC4 :src:type1:type1.c +"{ObjDir}type42.c.o" \xC4 :src:type42:type42.c +"{ObjDir}winfnt.c.o" \xC4 :src:winfonts:winfnt.c + + +### Optional Dependencies ### +### Build this target to generate "include file" dependencies. ### + +Dependencies \xC4 $OutOfDate + MakeDepend \xB6 + -append {MAKEFILE} \xB6 + -ignore "{CIncludes}" \xB6 + -objdir "{ObjDir}" \xB6 + -objext .o \xB6 + {Includes} \xB6 + {SrcFiles} + + diff --git a/vendor/freetype/builds/mac/FreeType.ppc_carbon.make.txt b/vendor/freetype/builds/mac/FreeType.ppc_carbon.make.txt new file mode 100644 index 0000000..1fa8c30 --- /dev/null +++ b/vendor/freetype/builds/mac/FreeType.ppc_carbon.make.txt @@ -0,0 +1,212 @@ +# File: FreeType.ppc_carbon.make +# Target: FreeType.ppc_carbon +# Created: Friday, October 28, 2005 03:40:06 PM + + +MAKEFILE = FreeType.ppc_carbon.make +\xA5MondoBuild\xA5 = {MAKEFILE} # Make blank to avoid rebuilds when makefile is modified + +ObjDir = :objs: +Includes = \xB6 + -ansi strict \xB6 + -includes unix \xB6 + -i :include: \xB6 + -i :src: \xB6 + -i :include:freetype:config: + +Sym-PPC = -sym off + +PPCCOptions = \xB6 + -d FT_MACINTOSH=1 \xB6 + -d HAVE_FSSPEC=1 \xB6 + -d HAVE_FSREF=1 \xB6 + -d HAVE_QUICKDRAW_TOOLBOX=1 \xB6 + -d HAVE_QUICKDRAW_CARBON=1 \xB6 + -d HAVE_ATS=0 \xB6 + -d FT2_BUILD_LIBRARY \xB6 + -d FT_CONFIG_CONFIG_H="" \xB6 + -d FT_CONFIG_MODULES_H="" \xB6 + {Includes} {Sym-PPC} -d TARGET_API_MAC_CARBON=1 + + +### Source Files ### + +SrcFiles = \xB6 + :src:autofit:autofit.c \xB6 + :builds:mac:ftbase.c \xB6 + :src:base:ftbbox.c \xB6 + :src:base:ftbdf.c \xB6 + :src:base:ftbitmap.c \xB6 + :src:base:ftdebug.c \xB6 + :src:base:ftfstype.c \xB6 + :src:base:ftglyph.c \xB6 + :src:base:ftgxval.c \xB6 + :src:base:ftinit.c \xB6 + :src:base:ftmm.c \xB6 + :src:base:ftotval.c \xB6 + :src:base:ftpfr.c \xB6 + :src:base:ftstroke.c \xB6 + :src:base:ftsynth.c \xB6 + :src:base:ftsystem.c \xB6 + :src:base:fttype1.c \xB6 + :src:base:ftwinfnt.c \xB6 + :src:cache:ftcache.c \xB6 + :src:bdf:bdf.c \xB6 + :src:cff:cff.c \xB6 + :src:cid:type1cid.c \xB6 + :src:gxvalid:gxvalid.c \xB6 + :src:gzip:ftgzip.c \xB6 + :src:bzip2:ftbzip2.c \xB6 + :src:lzw:ftlzw.c \xB6 + :src:otvalid:otvalid.c \xB6 + :src:pcf:pcf.c \xB6 + :src:pfr:pfr.c \xB6 + :src:psaux:psaux.c \xB6 + :src:pshinter:pshinter.c \xB6 + :src:psnames:psmodule.c \xB6 + :src:raster:raster.c \xB6 + :src:sfnt:sfnt.c \xB6 + :src:smooth:smooth.c \xB6 + :src:truetype:truetype.c \xB6 + :src:type1:type1.c \xB6 + :src:type42:type42.c \xB6 + :src:winfonts:winfnt.c + + +### Object Files ### + +ObjFiles-PPC = \xB6 + "{ObjDir}autofit.c.x" \xB6 + "{ObjDir}ftbase.c.x" \xB6 + "{ObjDir}ftbbox.c.x" \xB6 + "{ObjDir}ftbdf.c.x" \xB6 + "{ObjDir}ftbitmap.c.x" \xB6 + "{ObjDir}ftdebug.c.x" \xB6 + "{ObjDir}ftfstype.c.x" \xB6 + "{ObjDir}ftglyph.c.x" \xB6 + "{ObjDir}ftgxval.c.x" \xB6 + "{ObjDir}ftinit.c.x" \xB6 + "{ObjDir}ftmm.c.x" \xB6 + "{ObjDir}ftotval.c.x" \xB6 + "{ObjDir}ftpfr.c.x" \xB6 + "{ObjDir}ftstroke.c.x" \xB6 + "{ObjDir}ftsynth.c.x" \xB6 + "{ObjDir}ftsystem.c.x" \xB6 + "{ObjDir}fttype1.c.x" \xB6 + "{ObjDir}ftwinfnt.c.x" \xB6 + "{ObjDir}ftcache.c.x" \xB6 + "{ObjDir}bdf.c.x" \xB6 + "{ObjDir}cff.c.x" \xB6 + "{ObjDir}type1cid.c.x" \xB6 + "{ObjDir}gxvalid.c.x" \xB6 + "{ObjDir}ftgzip.c.x" \xB6 + "{ObjDir}ftbzip2.c.x" \xB6 + "{ObjDir}ftlzw.c.x" \xB6 + "{ObjDir}otvalid.c.x" \xB6 + "{ObjDir}pcf.c.x" \xB6 + "{ObjDir}pfr.c.x" \xB6 + "{ObjDir}psaux.c.x" \xB6 + "{ObjDir}pshinter.c.x" \xB6 + "{ObjDir}psmodule.c.x" \xB6 + "{ObjDir}raster.c.x" \xB6 + "{ObjDir}sfnt.c.x" \xB6 + "{ObjDir}smooth.c.x" \xB6 + "{ObjDir}truetype.c.x" \xB6 + "{ObjDir}type1.c.x" \xB6 + "{ObjDir}type42.c.x" \xB6 + "{ObjDir}winfnt.c.x" + + +### Libraries ### + +LibFiles-PPC = + + +### Default Rules ### + +.c.x \xC4 .c {\xA5MondoBuild\xA5} + {PPCC} {depDir}{default}.c -o {targDir}{default}.c.x {PPCCOptions} + + +### Build Rules ### + +:builds:mac:ftbase.c \xC4\xC4 :src:base:ftbase.c + Duplicate :src:base:ftbase.c :builds:mac:ftbase.c + +"{ObjDir}ftbase.c.x" \xC4\xC4 :builds:mac:ftbase.c + {PPCC} :builds:mac:ftbase.c -o {ObjDir}ftbase.c.x \xB6 + -i :builds:mac: \xB6 + -i :src:base: \xB6 + {PPCCOptions} + +FreeType.ppc_carbon \xC4\xC4 FreeType.ppc_carbon.o + +FreeType.ppc_carbon.o \xC4\xC4 {ObjFiles-PPC} {LibFiles-PPC} {\xA5MondoBuild\xA5} + PPCLink \xB6 + -o {Targ} \xB6 + {ObjFiles-PPC} \xB6 + {LibFiles-PPC} \xB6 + {Sym-PPC} \xB6 + -mf -d \xB6 + -t 'XCOF' \xB6 + -c 'MPS ' \xB6 + -xm l + + + +### Required Dependencies ### + +"{ObjDir}autofit.c.x" \xC4 :src:autofit:autofit.c +# "{ObjDir}ftbase.c.x" \xC4 :builds:mac:ftbase.c +"{ObjDir}ftbbox.c.x" \xC4 :src:base:ftbbox.c +"{ObjDir}ftbdf.c.x" \xC4 :src:base:ftbdf.c +"{ObjDir}ftbitmap.c.x" \xC4 :src:base:ftbitmap.c +"{ObjDir}ftdebug.c.x" \xC4 :src:base:ftdebug.c +"{ObjDir}ftfstype.c.x" \xC4 :src:base:ftfstype.c +"{ObjDir}ftglyph.c.x" \xC4 :src:base:ftglyph.c +"{ObjDir}ftgxval.c.x" \xC4 :src:base:ftgxval.c +"{ObjDir}ftinit.c.x" \xC4 :src:base:ftinit.c +"{ObjDir}ftmm.c.x" \xC4 :src:base:ftmm.c +"{ObjDir}ftotval.c.x" \xC4 :src:base:ftotval.c +"{ObjDir}ftpfr.c.x" \xC4 :src:base:ftpfr.c +"{ObjDir}ftstroke.c.x" \xC4 :src:base:ftstroke.c +"{ObjDir}ftsynth.c.x" \xC4 :src:base:ftsynth.c +"{ObjDir}ftsystem.c.x" \xC4 :src:base:ftsystem.c +"{ObjDir}fttype1.c.x" \xC4 :src:base:fttype1.c +"{ObjDir}ftwinfnt.c.x" \xC4 :src:base:ftwinfnt.c +"{ObjDir}ftcache.c.x" \xC4 :src:cache:ftcache.c +"{ObjDir}bdf.c.x" \xC4 :src:bdf:bdf.c +"{ObjDir}cff.c.x" \xC4 :src:cff:cff.c +"{ObjDir}type1cid.c.x" \xC4 :src:cid:type1cid.c +"{ObjDir}gxvalid.c.x" \xC4 :src:gxvalid:gxvalid.c +"{ObjDir}ftgzip.c.x" \xC4 :src:gzip:ftgzip.c +"{ObjDir}ftbzip2.c.x" \xC4 :src:bzip2:ftbzip2.c +"{ObjDir}ftlzw.c.x" \xC4 :src:lzw:ftlzw.c +"{ObjDir}otvalid.c.x" \xC4 :src:otvalid:otvalid.c +"{ObjDir}pcf.c.x" \xC4 :src:pcf:pcf.c +"{ObjDir}pfr.c.x" \xC4 :src:pfr:pfr.c +"{ObjDir}psaux.c.x" \xC4 :src:psaux:psaux.c +"{ObjDir}pshinter.c.x" \xC4 :src:pshinter:pshinter.c +"{ObjDir}psmodule.c.x" \xC4 :src:psnames:psmodule.c +"{ObjDir}raster.c.x" \xC4 :src:raster:raster.c +"{ObjDir}sfnt.c.x" \xC4 :src:sfnt:sfnt.c +"{ObjDir}smooth.c.x" \xC4 :src:smooth:smooth.c +"{ObjDir}truetype.c.x" \xC4 :src:truetype:truetype.c +"{ObjDir}type1.c.x" \xC4 :src:type1:type1.c +"{ObjDir}type42.c.x" \xC4 :src:type42:type42.c +"{ObjDir}winfnt.c.x" \xC4 :src:winfonts:winfnt.c + + +### Optional Dependencies ### +### Build this target to generate "include file" dependencies. ### + +Dependencies \xC4 $OutOfDate + MakeDepend \xB6 + -append {MAKEFILE} \xB6 + -ignore "{CIncludes}" \xB6 + -objdir "{ObjDir}" \xB6 + -objext .x \xB6 + {Includes} \xB6 + {SrcFiles} + + diff --git a/vendor/freetype/builds/mac/FreeType.ppc_classic.make.txt b/vendor/freetype/builds/mac/FreeType.ppc_classic.make.txt new file mode 100644 index 0000000..2550190 --- /dev/null +++ b/vendor/freetype/builds/mac/FreeType.ppc_classic.make.txt @@ -0,0 +1,213 @@ +# File: FreeType.ppc_classic.make +# Target: FreeType.ppc_classic +# Created: Thursday, October 27, 2005 07:42:43 PM + + +MAKEFILE = FreeType.ppc_classic.make +\xA5MondoBuild\xA5 = {MAKEFILE} # Make blank to avoid rebuilds when makefile is modified + +ObjDir = :objs: +Includes = \xB6 + -ansi strict \xB6 + -includes unix \xB6 + -i :include: \xB6 + -i :src: \xB6 + -i :include:freetype:config: + +Sym-PPC = -sym off + +PPCCOptions = \xB6 + -d FT_MACINTOSH=1 \xB6 + -d HAVE_FSSPEC=1 \xB6 + -d HAVE_FSREF=0 \xB6 + -d HAVE_QUICKDRAW_TOOLBOX=1 \xB6 + -d HAVE_QUICKDRAW_CARBON=0 \xB6 + -d HAVE_ATS=0 \xB6 + -d FT2_BUILD_LIBRARY \xB6 + -d FT_CONFIG_CONFIG_H="" \xB6 + -d FT_CONFIG_MODULES_H="" \xB6 + {Includes} {Sym-PPC} + + +### Source Files ### + +SrcFiles = \xB6 + :src:autofit:autofit.c \xB6 + :builds:mac:ftbase.c \xB6 + :src:base:ftbbox.c \xB6 + :src:base:ftbdf.c \xB6 + :src:base:ftbitmap.c \xB6 + :src:base:ftdebug.c \xB6 + :src:base:ftfstype.c \xB6 + :src:base:ftglyph.c \xB6 + :src:base:ftgxval.c \xB6 + :src:base:ftinit.c \xB6 + :src:base:ftmm.c \xB6 + :src:base:ftotval.c \xB6 + :src:base:ftpfr.c \xB6 + :src:base:ftstroke.c \xB6 + :src:base:ftsynth.c \xB6 + :src:base:ftsystem.c \xB6 + :src:base:fttype1.c \xB6 + :src:base:ftwinfnt.c \xB6 + :src:cache:ftcache.c \xB6 + :src:bdf:bdf.c \xB6 + :src:cff:cff.c \xB6 + :src:cid:type1cid.c \xB6 + :src:gxvalid:gxvalid.c \xB6 + :src:gzip:ftgzip.c \xB6 + :src:bzip2:ftbzip2.c \xB6 + :src:lzw:ftlzw.c \xB6 + :src:otvalid:otvalid.c \xB6 + :src:pcf:pcf.c \xB6 + :src:pfr:pfr.c \xB6 + :src:psaux:psaux.c \xB6 + :src:pshinter:pshinter.c \xB6 + :src:psnames:psmodule.c \xB6 + :src:raster:raster.c \xB6 + :src:sfnt:sfnt.c \xB6 + :src:smooth:smooth.c \xB6 + :src:truetype:truetype.c \xB6 + :src:type1:type1.c \xB6 + :src:type42:type42.c \xB6 + :src:winfonts:winfnt.c + + +### Object Files ### + +ObjFiles-PPC = \xB6 + "{ObjDir}autofit.c.x" \xB6 + "{ObjDir}ftbase.c.x" \xB6 + "{ObjDir}ftbbox.c.x" \xB6 + "{ObjDir}ftbdf.c.x" \xB6 + "{ObjDir}ftbitmap.c.x" \xB6 + "{ObjDir}ftdebug.c.x" \xB6 + "{ObjDir}ftfstype.c.x" \xB6 + "{ObjDir}ftglyph.c.x" \xB6 + "{ObjDir}ftgxval.c.x" \xB6 + "{ObjDir}ftinit.c.x" \xB6 + "{ObjDir}ftmm.c.x" \xB6 + "{ObjDir}ftotval.c.x" \xB6 + "{ObjDir}ftpfr.c.x" \xB6 + "{ObjDir}ftstroke.c.x" \xB6 + "{ObjDir}ftsynth.c.x" \xB6 + "{ObjDir}ftsystem.c.x" \xB6 + "{ObjDir}fttype1.c.x" \xB6 + "{ObjDir}ftwinfnt.c.x" \xB6 + "{ObjDir}ftcache.c.x" \xB6 + "{ObjDir}bdf.c.x" \xB6 + "{ObjDir}cff.c.x" \xB6 + "{ObjDir}type1cid.c.x" \xB6 + "{ObjDir}gxvalid.c.x" \xB6 + "{ObjDir}ftgzip.c.x" \xB6 + "{ObjDir}ftbzip2.c.x" \xB6 + "{ObjDir}ftlzw.c.x" \xB6 + "{ObjDir}otvalid.c.x" \xB6 + "{ObjDir}pcf.c.x" \xB6 + "{ObjDir}pfr.c.x" \xB6 + "{ObjDir}psaux.c.x" \xB6 + "{ObjDir}pshinter.c.x" \xB6 + "{ObjDir}psmodule.c.x" \xB6 + "{ObjDir}raster.c.x" \xB6 + "{ObjDir}sfnt.c.x" \xB6 + "{ObjDir}smooth.c.x" \xB6 + "{ObjDir}truetype.c.x" \xB6 + "{ObjDir}type1.c.x" \xB6 + "{ObjDir}type42.c.x" \xB6 + "{ObjDir}winfnt.c.x" + + +### Libraries ### + +LibFiles-PPC = + + +### Default Rules ### + +.c.x \xC4 .c {\xA5MondoBuild\xA5} + {PPCC} {depDir}{default}.c -o {targDir}{default}.c.x {PPCCOptions} + + +### Build Rules ### + +:builds:mac:ftbase.c \xC4\xC4 :src:base:ftbase.c + Duplicate :src:base:ftbase.c :builds:mac:ftbase.c + +"{ObjDir}ftbase.c.x" \xC4\xC4 :builds:mac:ftbase.c + {PPCC} :builds:mac:ftbase.c -o "{ObjDir}ftbase.c.x" \xB6 + -i :builds:mac: \xB6 + -i :src:base: \xB6 + {PPCCOptions} + +FreeType.ppc_classic \xC4\xC4 FreeType.ppc_classic.o + +FreeType.ppc_classic.o \xC4\xC4 {ObjFiles-PPC} {LibFiles-PPC} {\xA5MondoBuild\xA5} + PPCLink \xB6 + -o {Targ} \xB6 + {ObjFiles-PPC} \xB6 + {LibFiles-PPC} \xB6 + {Sym-PPC} \xB6 + -mf -d \xB6 + -t 'XCOF' \xB6 + -c 'MPS ' \xB6 + -xm l + + + +### Required Dependencies ### + +"{ObjDir}autofit.c.x" \xC4 :src:autofit:autofit.c +# "{ObjDir}ftbase.c.x" \xC4 :builds:mac:ftbase.c +"{ObjDir}ftbbox.c.x" \xC4 :src:base:ftbbox.c +"{ObjDir}ftbdf.c.x" \xC4 :src:base:ftbdf.c +"{ObjDir}ftbitmap.c.x" \xC4 :src:base:ftbitmap.c +"{ObjDir}ftdebug.c.x" \xC4 :src:base:ftdebug.c +"{ObjDir}ftfstype.c.x" \xC4 :src:base:ftfstype.c +"{ObjDir}ftglyph.c.x" \xC4 :src:base:ftglyph.c +"{ObjDir}ftgxval.c.x" \xC4 :src:base:ftgxval.c +"{ObjDir}ftinit.c.x" \xC4 :src:base:ftinit.c +"{ObjDir}ftmm.c.x" \xC4 :src:base:ftmm.c +"{ObjDir}ftotval.c.x" \xC4 :src:base:ftotval.c +"{ObjDir}ftpfr.c.x" \xC4 :src:base:ftpfr.c +"{ObjDir}ftstroke.c.x" \xC4 :src:base:ftstroke.c +"{ObjDir}ftsynth.c.x" \xC4 :src:base:ftsynth.c +"{ObjDir}ftsystem.c.x" \xC4 :src:base:ftsystem.c +"{ObjDir}fttype1.c.x" \xC4 :src:base:fttype1.c +"{ObjDir}ftwinfnt.c.x" \xC4 :src:base:ftwinfnt.c +"{ObjDir}ftcache.c.x" \xC4 :src:cache:ftcache.c +"{ObjDir}bdf.c.x" \xC4 :src:bdf:bdf.c +"{ObjDir}cff.c.x" \xC4 :src:cff:cff.c +"{ObjDir}type1cid.c.x" \xC4 :src:cid:type1cid.c +"{ObjDir}gxvalid.c.x" \xC4 :src:gxvalid:gxvalid.c +"{ObjDir}ftgzip.c.x" \xC4 :src:gzip:ftgzip.c +"{ObjDir}ftbzip2.c.x" \xC4 :src:bzip2:ftbzip2.c +"{ObjDir}ftlzw.c.x" \xC4 :src:lzw:ftlzw.c +"{ObjDir}otvalid.c.x" \xC4 :src:otvalid:otvalid.c +"{ObjDir}pcf.c.x" \xC4 :src:pcf:pcf.c +"{ObjDir}pfr.c.x" \xC4 :src:pfr:pfr.c +"{ObjDir}psaux.c.x" \xC4 :src:psaux:psaux.c +"{ObjDir}pshinter.c.x" \xC4 :src:pshinter:pshinter.c +"{ObjDir}psmodule.c.x" \xC4 :src:psnames:psmodule.c +"{ObjDir}raster.c.x" \xC4 :src:raster:raster.c +"{ObjDir}sfnt.c.x" \xC4 :src:sfnt:sfnt.c +"{ObjDir}smooth.c.x" \xC4 :src:smooth:smooth.c +"{ObjDir}truetype.c.x" \xC4 :src:truetype:truetype.c +"{ObjDir}type1.c.x" \xC4 :src:type1:type1.c +"{ObjDir}type42.c.x" \xC4 :src:type42:type42.c +"{ObjDir}winfnt.c.x" \xC4 :src:winfonts:winfnt.c + + + +### Optional Dependencies ### +### Build this target to generate "include file" dependencies. ### + +Dependencies \xC4 $OutOfDate + MakeDepend \xB6 + -append {MAKEFILE} \xB6 + -ignore "{CIncludes}" \xB6 + -objdir "{ObjDir}" \xB6 + -objext .x \xB6 + {Includes} \xB6 + {SrcFiles} + + diff --git a/vendor/freetype/builds/mac/README b/vendor/freetype/builds/mac/README new file mode 100644 index 0000000..06e3d51 --- /dev/null +++ b/vendor/freetype/builds/mac/README @@ -0,0 +1,393 @@ +This folder contains + + * Makefile skeletons for Apple MPW (Macintosh's Programmer's Workshop) + + * Python script to generate MPW makefile from skeleton + + * Metrowerks CodeWarrior 9.0 project file in XML format + +------------------------------------------------------------ + +1. What is this +--------------- + +Files in this directory are designed to build FreeType +running on classic MacOS. To build FreeType running on +Mac OS X, build as the system is UNIX. + +However, Mac OS X is most useful to manipulate files in +vanilla FreeType to fit classic MacOS. + +The information about MacOS specific API is written in +appendix of this document. + +2. Requirement +-------------- + +You can use MPW: a free-charged developer environment +by Apple, or CodeWarrior: a commercial developer +environment by Metrowerks. GCC for MPW and Symantec +"Think C" are not tested at present. + + + 2-1. Apple MPW + -------------- + + Following C compilers are tested: + + m68k target: Apple SC 8.9.0d3e1 + ppc target: Apple MrC 5.0.0d3c1 + + The final MPW-GM (official release on 1999/Dec) is too + old and cannot compile FreeType, because bundled C + compilers cannot search header files in sub directories. + Updating by the final MPW-PR (pre-release on 2001/Feb) + is required. + + Required files are downloadable from: + + http://macintoshgarden.org/apps/macintosh-programmers-workshop + + Also you can find documents how to update by MPW-PR. + + Python is required to restore MPW makefiles from the + skeletons. Python bundled to Mac OS X is enough. For + classic MacOS, MacPython is available: + + https://homepages.cwi.nl/~jack/macpython/ + + MPW requires all files are typed by resource fork. + ResEdit bundled to MPW is enough. In Mac OS X, + /Developer/Tools/SetFile of DevTool is useful to + manipulate from commandline. + + 2-2. Metrowerks CodeWarrior + --------------------------- + + XML project file is generated and tested by + CodeWarrior 9.0. Older versions are not tested + at all. At present, static library for ppc target + is available in the project file. + + +3. How to build +--------------- + + 3-1. Apple MPW + -------------- + Detailed building procedure by Apple MPW is + described in following. + + 3-1-1. Generate MPW makefiles from the skeletons + ------------------------------------------------ + + Here are 4 skeletons for following targets are + included. + + - FreeType.m68k_far.make.txt + Ancient 32bit binary executable format for + m68k MacOS: System 6, with 32bit addressing + mode (far-pointer-model) So-called "Toolbox" + API is used. + + - FreeType.m68k_cfm.make.txt + CFM binary executable format for m68k MacOS: + System 7. So-called "Toolbox" API is used. + + - FreeType.ppc_classic.make.txt + CFM binary executable format for ppc MacOS: + System 7, MacOS 8, MacOS 9. So-called "Toolbox" + API is used. + + - FreeType.ppc_carbon.make.txt + CFM binary executable format for ppc MacOS: + MacOS 9. Carbon API is used. + + At present, static library is only supported, + although targets except of m68k_far are capable + to use shared library. + + MPW makefile syntax uses 8bit characters. To keep + from violating them during version control, here + we store skeletons in pure ASCII format. You must + generate MPW makefile by Python script ascii2mpw.py. + + In Mac OS X terminal, you can convert as: + + python builds/mac/ascii2mpw.py \ + < builds/mac/FreeType.m68k_far.make.txt \ + > FreeType.m68k_far.make + + The skeletons are designed to use in the top + directory where there are builds, include, src etc. + You must name the generated MPW makefile by removing + ".txt" from source skeleton name. + + 3-1-2. Add resource forks to related files + ------------------------------------------ + + MPW's Make and C compilers cannot recognize files + without resource fork. You have to add resource + fork to the files that MPW uses. In Mac OS X + terminal of the system, you can do as: + + find . -name '*.[ch]' -exec \ + /Developer/Tools/SetFile -a l -c "MPS " -t TEXT \{\} \; + + find . -name '*.make' -exec \ + /Developer/Tools/SetFile -a l -c "MPS " -t TEXT \{\} \; + + + 3-1-3. Open MPW shell and build + ------------------------------- + + Open MPW shell and go to the top directory that + FreeType sources are extracted (MPW makefile must + be located in there), from "Set Directory" in + "Directory" menu. + + Choose "Build" from "Build" menu, and type the + name of project by removing ".make" from MPW + makefile, as: FreeType.m68k_far + + If building is successfully finished, you can find + built library in objs/ directory. + + + 3-2. Metrowerks CodeWarrior + --------------------------- + + Detailed building procedure by Metrowerks + CodeWarrior (CW) 9.0 is described in following. + + 3-2-1. Import XML project file + ------------------------------ + + CW XML project file is not ready for double- + click. Start CodeWarrior IDE, and choose + "Import project" in "File" menu. Choose XML + project file: builds/mac/ftlib.prj.xml. + In next, you will be asked where to save CW + native project file: you must choose + "builds/mac/ftlib.prj". The project file is + designed with relative path from there. After + CW native project file is generated, it is + automatically loaded, small project window + titled "ftlib.prj" is displayed. + + 3-2-2. Building + --------------- + Choose "Make" from "Project" menu. If building + is successfully finished, you can find built + library at objs/FreeTypeLib. + +4. TODO +------- + + 4-1. All modules should be included + ----------------------------------- + + At present, MPW makefiles and CW project file are + just updated versions of these by Leonard. Some + modules are added after the last maintenance, they + are not included. + + 4-2. Working test with ftdemos + ------------------------------ + + At present, MPW makefiles and CW project file can + build FreeType for classic MacOS. But their working + behaviours are not tested at all. Building ftdemos + for classic MacOS and working test is required. + + +APPENDIX I +---------- + + A-1. Framework dependencies + --------------------------- + + src/base/ftmac.c adds two Mac-specific features to + FreeType. These features are based on MacOS libraries. + + * accessing resource-fork font + The fonts for classic MacOS store their graphical data + in resource forks which cannot be accessed via ANSI C + functions. FreeType2 provides functions to handle such + resource fork fonts, they are based on File Manager + framework of MacOS. In addition, HFS and HFS+ file + system driver of Linux is supported. Following + functions are for this purpose. + + FT_New_Face_From_Resource() + FT_New_Face_From_FSSpec() + FT_New_Face_From_FSRef() + + * resolving font name to font file + The font menu of MacOS application prefers font name + written in FOND resource than sfnt resource. FreeType2 + provides functions to find font file by name in MacOS + application, they are based on QuickDraw Font Manager + and Apple Type Service framework of MacOS. + + FT_GetFile_From_Mac_Name() + FT_GetFile_From_Mac_ATS_Name() + + Working functions for each MacOS are summarized as + following. + + upto MacOS 6: + not tested (you have to obtain MPW 2.x) + + MacOS 7.x, 8.x, 9.x (without CarbonLib): + FT_GetFile_From_Mac_Name() + FT_New_Face_From_Resource() + FT_New_Face_From_FSSpec() + + MacOS 9.x (with CarbonLib): + FT_GetFile_From_Mac_Name() + FT_New_Face_From_Resource() + FT_New_Face_From_FSSpec() + FT_New_Face_From_FSRef() + + Mac OS X upto 10.4.x: + FT_GetFile_From_Mac_Name() deprecated + FT_New_Face_From_FSSpec() deprecated + FT_GetFile_From_Mac_ATS_Name() deprecated? + FT_New_Face_From_FSRef() + + A-2. Deprecated Functions + ------------------------- + + A-2-1. FileManager + ------------------ + + For convenience to write MacOS application, ftmac.c + provides functions to specify a file by FSSpec and FSRef, + because the file identification pathname had ever been + unrecommended method in MacOS programming. + + Toward to MacOS X 10.4 & 5, Carbon functions using FSSpec + datatype is noticed as deprecated, and recommended to + migrate to FSRef datatype. The big differences of FSRef + against FSSpec are explained in Apple TechNotes 2078. + + https://developer.apple.com/library/archive/technotes/tn2078/ + + - filename length: the max length of file + name of FSRef is 255 chars (it is limit of HFS+), + that of FSSpec is 31 chars (it is limit of HFS). + + - filename encoding: FSSpec is localized by + legacy encoding for each language system, + FSRef is Unicode enabled. + + A-2-2. FontManager + ------------------ + + Following functions receive QuickDraw fontname: + + FT_GetFile_From_Mac_Name() + + QuickDraw is deprecated and replaced by Quartz + since Mac OS X 10.4. They are still kept for + backward compatibility. By undefinition of + HAVE_QUICKDRAW in building, you can change these + functions to return FT_Err_Unimplemented always. + + Replacement functions are added for migration. + + FT_GetFile_From_Mac_ATS_Name() + + They are usable on Mac OS X only. On older systems, + these functions return FT_Err_Unimplemented always. + + The detailed incompatibilities and possibility + of FontManager emulation without QuickDraw is + explained in + + http://gyvern.ipc.hiroshima-u.ac.jp/~mpsuzuki/ats_benchmark.html + + A-3. Framework Availabilities + ----------------------------- + + The framework of MacOS are often revised, especially + when new format of binary executable is introduced. + Following table is the minimum version of frameworks + to use functions used in FreeType2. The table is + extracted from MPW header files for assembly language. + + *** NOTE *** + The conditional definition of available data type + in MPW compiler is insufficient. You can compile + program using FSRef data type for older systems + (MacOS 7, 8) that don't know FSRef data type. + + + +-------------------+-----------------------------+ + CPU | mc680x0 | PowerPC | + +---------+---------+---------+---------+---------+ + Binary Executable Format | Classic | 68K-CFM | CFM | CFM | Mach-O | + +---------+---------+---------+---------+---------+ + Framework API | Toolbox | Toolbox | Toolbox | Carbon | Carbon | + +---------+---------+---------+---------+---------+ + + +---------+---------+---------+---------+---------+ + | ?(*) |Interface|Interface|CarbonLib|Mac OS X | + | |Lib |Lib | | | +* Files.h +---------+---------+---------+---------+---------+ +PBGetFCBInfoSync() | o | 7.1- | 7.1- | 1.0- | o | +FSMakeFSSpec() | o | 7.1- | 7.1- | 1.0- | o | +FSGetForkCBInfo() | o | (**) | 9.0- | 1.0- | o | +FSpMakeFSRef() | o | (**) | 9.0- | 1.0- | o | +FSGetCatalogInfo() | o | (**) | 9.0- | 1.0- | -10.3 | +FSPathMakeRef() | x | x | x | 1.1- | -10.3 | + +---------+---------+---------+---------+---------+ + + +---------+---------+---------+---------+---------+ + | ?(*) |Font |Font |CarbonLib|Mac OS X | + | |Manager |Manager | | | +* Fonts.h +---------+---------+---------+---------+---------+ +FMCreateFontFamilyIterator() | x | x | 9.0- | 1.0- | -10.3 | +FMDisposeFontFamilyIterator() | x | x | 9.0- | 1.0- | -10.3 | +FMGetNextFontFamily() | x | x | 9.0- | 1.0- | -10.3 | +FMGetFontFamilyName() | x | x | 9.0- | 1.0- | -10.3 | +FMCreateFontFamilyInstanceIterator() | x | x | 9.0- | 1.0- | -10.3 | +FMDisposeFontFamilyInstanceIterator() | x | x | 9.0- | 1.0- | -10.3 | +FMGetNextFontFamilyInstance() | x | x | 9.0- | 1.0- | -10.3 | + +---------+---------+---------+---------+---------+ + + +---------+---------+---------+---------+---------+ + | - | - | - |CarbonLib|Mac OS X | +* ATSFont.h (***) +---------+---------+---------+---------+---------+ +ATSFontFindFromName() | x | x | x | x | o | +ATSFontGetFileSpecification() | x | x | x | x | o | + +---------+---------+---------+---------+---------+ + + (*) + In the "Classic": the original binary executable + format, these framework functions are directly + transformed to MacOS system call. Therefore, the + exact availability should be checked by running + system. + + (**) + InterfaceLib is bundled to MacOS and its version + is usually equal to MacOS. There's no separate + update for InterfaceLib. It is supposed that + there's no InterfaceLib 9.x for m68k platforms. + In fact, these functions are FSRef dependent. + + (***) + ATSUI framework is available on ATSUnicode 8.5 on + ppc Toolbox CFM, CarbonLib 1.0 too. But its base: + ATS font manager is not published in these versions. + +------------------------------------------------------------ +Last update: 2013-Nov-03. + +Currently maintained by + suzuki toshiya, +Originally prepared by + Leonard Rosenthol, + Just van Rossum, diff --git a/vendor/freetype/builds/mac/ascii2mpw.py b/vendor/freetype/builds/mac/ascii2mpw.py new file mode 100644 index 0000000..ad32b21 --- /dev/null +++ b/vendor/freetype/builds/mac/ascii2mpw.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +import sys +import string + +if len( sys.argv ) == 1 : + for asc_line in sys.stdin.readlines(): + mpw_line = string.replace(asc_line, "\\xA5", "\245") + mpw_line = string.replace(mpw_line, "\\xB6", "\266") + mpw_line = string.replace(mpw_line, "\\xC4", "\304") + mpw_line = string.replace(mpw_line, "\\xC5", "\305") + mpw_line = string.replace(mpw_line, "\\xFF", "\377") + mpw_line = string.replace(mpw_line, "\n", "\r") + mpw_line = string.replace(mpw_line, "\\n", "\n") + sys.stdout.write(mpw_line) +elif sys.argv[1] == "-r" : + for mpw_line in sys.stdin.readlines(): + asc_line = string.replace(mpw_line, "\n", "\\n") + asc_line = string.replace(asc_line, "\r", "\n") + asc_line = string.replace(asc_line, "\245", "\\xA5") + asc_line = string.replace(asc_line, "\266", "\\xB6") + asc_line = string.replace(asc_line, "\304", "\\xC4") + asc_line = string.replace(asc_line, "\305", "\\xC5") + asc_line = string.replace(asc_line, "\377", "\\xFF") + sys.stdout.write(asc_line) diff --git a/vendor/freetype/builds/mac/freetype-Info.plist b/vendor/freetype/builds/mac/freetype-Info.plist new file mode 100644 index 0000000..344e5ac --- /dev/null +++ b/vendor/freetype/builds/mac/freetype-Info.plist @@ -0,0 +1,36 @@ + + + + + + + CFBundleDevelopmentRegion + English + + CFBundleExecutable + freetype + + CFBundleGetInfoString + FreeType ${PROJECT_VERSION} + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundleName + FreeType + + CFBundlePackageType + FMWK + + CFBundleShortVersionString + ${PROJECT_VERSION} + + CFBundleSignature + ???? + + CFBundleVersion + ${PROJECT_VERSION} + + + diff --git a/vendor/freetype/builds/mac/ftlib.prj.xml b/vendor/freetype/builds/mac/ftlib.prj.xml new file mode 100644 index 0000000..cbbc45e --- /dev/null +++ b/vendor/freetype/builds/mac/ftlib.prj.xml @@ -0,0 +1,1194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + + FreeTypeLib + + + + UserSourceTrees + + + AlwaysSearchUserPathstrue + InterpretDOSAndUnixPathstrue + RequireFrameworkStyleIncludesfalse + SourceRelativeIncludesfalse + UserSearchPaths + + SearchPath + Path: + PathFormatMacOS + PathRootProject + + Recursivetrue + FrameworkPathfalse + HostFlagsAll + + + SearchPath + Path:::include: + PathFormatMacOS + PathRootProject + + Recursivetrue + FrameworkPathfalse + HostFlagsAll + + + SearchPath + Path:::src: + PathFormatMacOS + PathRootProject + + Recursivetrue + FrameworkPathfalse + HostFlagsAll + + + SearchPath + Path:: + PathFormatMacOS + PathRootProject + + Recursivetrue + FrameworkPathfalse + HostFlagsAll + + + SystemSearchPaths + + SearchPath + Path: + PathFormatMacOS + PathRootCodeWarrior + + Recursivetrue + FrameworkPathfalse + HostFlagsAll + + + + + MWRuntimeSettings_WorkingDirectory + MWRuntimeSettings_CommandLine + MWRuntimeSettings_HostApplication + Path + PathFormatGeneric + PathRootAbsolute + + MWRuntimeSettings_EnvVars + + + LinkerMacOS PPC Linker + PreLinker + PostLinker + TargetnameFreeTypeLib + OutputDirectory + Path:::objs: + PathFormatMacOS + PathRootProject + + SaveEntriesUsingRelativePathsfalse + + + FileMappings + + FileTypeAPPL + FileExtension + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeAppl + FileExtension + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeMMLB + FileExtension + CompilerLib Import PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeMPLF + FileExtension + CompilerLib Import PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeMWCD + FileExtension + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeRSRC + FileExtension + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.bh + CompilerBalloon Help + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.c + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.c++ + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cc + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cp + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cpp + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.exp + Compiler + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.h + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMaketrue + + + FileTypeTEXT + FileExtension.p + CompilerMW Pascal PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pas + CompilerMW Pascal PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pch + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pch++ + CompilerMW C/C++ PPC + EditLanguageC/C++ + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.ppu + CompilerMW Pascal PPC + EditLanguage + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.r + CompilerRez + EditLanguageRez + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.s + CompilerPPCAsm + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeXCOF + FileExtension + CompilerXCOFF Import PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypedocu + FileExtension + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypersrc + FileExtension + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeshlb + FileExtension + CompilerPEF Import PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypestub + FileExtension + CompilerPEF Import PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileExtension.doc + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFilefalse + IgnoredByMaketrue + + + FileExtension.o + CompilerXCOFF Import PPC + EditLanguage + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileExtension.ppob + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileExtension.rsrc + Compiler + EditLanguage + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + + + CacheModDatestrue + DumpBrowserInfofalse + CacheSubprojectstrue + UseThirdPartyDebuggerfalse + BrowserGenerator1 + DebuggerAppPath + Path + PathFormatGeneric + PathRootAbsolute + + DebuggerCmdLineArgs + DebuggerWorkingDir + Path + PathFormatGeneric + PathRootAbsolute + + CodeCompletionPrefixFileNameMacHeaders.c + CodeCompletionMacroFileNameMacOS_Carbon_C++_Macros.h + + + ConsoleEncoding0 + LogSystemMessagestrue + AutoTargetDLLsfalse + StopAtWatchpointstrue + PauseWhileRunningfalse + PauseInterval5 + PauseUIFlags0 + AltExePath + Path + PathFormatGeneric + PathRootAbsolute + + StopAtTempBPOnLaunchtrue + CacheSymbolicstrue + TempBPFunctionNamemain + TempBPType0 + + + Enabledfalse + ConnectionName + DownloadPath + LaunchRemoteAppfalse + RemoteAppPath + CoreID0 + JTAGClockSpeed8000 + IsMultiCorefalse + OSDownloadfalse + UseGlobalOSDownloadfalse + OSDownloadConnectionName + OSDownloadPath + AltDownloadfalse + AltDownloadConnectionName + + + OtherExecutables + + + AnalyzerConnectionName + + + CustomColor1 + Red0 + Green32767 + Blue0 + + CustomColor2 + Red0 + Green32767 + Blue0 + + CustomColor3 + Red0 + Green32767 + Blue0 + + CustomColor4 + Red0 + Green32767 + Blue0 + + + + MWFrontEnd_C_cplusplus0 + MWFrontEnd_C_checkprotos1 + MWFrontEnd_C_arm0 + MWFrontEnd_C_trigraphs0 + MWFrontEnd_C_onlystdkeywords0 + MWFrontEnd_C_enumsalwaysint0 + MWFrontEnd_C_ansistrict1 + MWFrontEnd_C_wchar_type1 + MWFrontEnd_C_enableexceptions1 + MWFrontEnd_C_dontreusestrings0 + MWFrontEnd_C_poolstrings0 + MWFrontEnd_C_dontinline0 + MWFrontEnd_C_useRTTI1 + MWFrontEnd_C_unsignedchars0 + MWFrontEnd_C_autoinline0 + MWFrontEnd_C_booltruefalse1 + MWFrontEnd_C_inlinelevel0 + MWFrontEnd_C_ecplusplus0 + MWFrontEnd_C_defer_codegen0 + MWFrontEnd_C_templateparser0 + MWFrontEnd_C_c990 + MWFrontEnd_C_bottomupinline1 + MWFrontEnd_C_gcc_extensions0 + MWFrontEnd_C_instance_manager0 + + + C_CPP_Preprocessor_EmitFiletrue + C_CPP_Preprocessor_EmitLinefalse + C_CPP_Preprocessor_EmitFullPathfalse + C_CPP_Preprocessor_KeepCommentsfalse + C_CPP_Preprocessor_PCHUsesPrefixTextfalse + C_CPP_Preprocessor_EmitPragmastrue + C_CPP_Preprocessor_KeepWhiteSpacefalse + C_CPP_Preprocessor_MultiByteEncodingencASCII_Unicode + C_CPP_Preprocessor_PrefixText/* settings imported from old "C/C++ Language" panel */ + +#if !__option(precompile) +#include "ftoption.h" /* was "Prefix file" */ +#endif + + + + MWWarning_C_warn_illpragma0 + MWWarning_C_warn_emptydecl0 + MWWarning_C_warn_possunwant0 + MWWarning_C_warn_unusedvar1 + MWWarning_C_warn_unusedarg1 + MWWarning_C_warn_extracomma0 + MWWarning_C_pedantic0 + MWWarning_C_warningerrors0 + MWWarning_C_warn_hidevirtual0 + MWWarning_C_warn_implicitconv0 + MWWarning_C_warn_notinlined0 + MWWarning_C_warn_structclass0 + MWWarning_C_warn_missingreturn0 + MWWarning_C_warn_no_side_effect0 + MWWarning_C_warn_resultnotused0 + MWWarning_C_warn_padding0 + MWWarning_C_warn_impl_i2f_conv0 + MWWarning_C_warn_impl_f2i_conv0 + MWWarning_C_warn_impl_s2u_conv0 + MWWarning_C_warn_illtokenpasting0 + MWWarning_C_warn_filenamecaps0 + MWWarning_C_warn_filenamecapssystem0 + MWWarning_C_warn_undefmacro0 + MWWarning_C_warn_ptrintconv0 + + + MWMerge_MacOS_projectTypeApplication + MWMerge_MacOS_outputNameMerge Out + MWMerge_MacOS_outputCreator???? + MWMerge_MacOS_outputTypeAPPL + MWMerge_MacOS_suppressWarning0 + MWMerge_MacOS_copyFragments1 + MWMerge_MacOS_copyResources1 + MWMerge_MacOS_flattenResource0 + MWMerge_MacOS_flatFileNamea.rsrc + MWMerge_MacOS_flatFileOutputPath + Path: + PathFormatMacOS + PathRootProject + + MWMerge_MacOS_skipResources + DLGX + ckid + Proj + WSPC + + + + FileLockedfalse + ResourcesMapIsReadOnlyfalse + PrinterDriverIsMultiFinderCompatiblefalse + Invisiblefalse + HasBundlefalse + NameLockedfalse + Stationeryfalse + HasCustomIconfalse + Sharedfalse + HasBeenInitedfalse + Label0 + Comments + HasCustomBadgefalse + HasRoutingInfofalse + + + MWCodeGen_PPC_structalignmentPPC_mw + MWCodeGen_PPC_tracebacktablesNone + MWCodeGen_PPC_processorGeneric + MWCodeGen_PPC_function_align4 + MWCodeGen_PPC_tocdata1 + MWCodeGen_PPC_largetoc0 + MWCodeGen_PPC_profiler0 + MWCodeGen_PPC_vectortocdata0 + MWCodeGen_PPC_poolconst0 + MWCodeGen_PPC_peephole0 + MWCodeGen_PPC_readonlystrings0 + MWCodeGen_PPC_linkerpoolsstrings0 + MWCodeGen_PPC_volatileasm0 + MWCodeGen_PPC_schedule0 + MWCodeGen_PPC_altivec0 + MWCodeGen_PPC_altivec_move_block0 + MWCodeGen_PPC_strictIEEEfp0 + MWCodeGen_PPC_fpcontract1 + MWCodeGen_PPC_genfsel0 + MWCodeGen_PPC_orderedfpcmp0 + + + MWCodeGen_MachO_structalignmentPPC_mw + MWCodeGen_MachO_profiler_enumOff + MWCodeGen_MachO_processorGeneric + MWCodeGen_MachO_function_align4 + MWCodeGen_MachO_common0 + MWCodeGen_MachO_boolisint0 + MWCodeGen_MachO_peephole1 + MWCodeGen_MachO_readonlystrings0 + MWCodeGen_MachO_linkerpoolsstrings1 + MWCodeGen_MachO_volatileasm0 + MWCodeGen_MachO_schedule0 + MWCodeGen_MachO_altivec0 + MWCodeGen_MachO_vecmove0 + MWCodeGen_MachO_fp_ieee_strict0 + MWCodeGen_MachO_fpcontract1 + MWCodeGen_MachO_genfsel0 + MWCodeGen_MachO_fp_cmps_ordered0 + + + MWDisassembler_PPC_showcode1 + MWDisassembler_PPC_extended1 + MWDisassembler_PPC_mix0 + MWDisassembler_PPC_nohex0 + MWDisassembler_PPC_showdata1 + MWDisassembler_PPC_showexceptions1 + MWDisassembler_PPC_showsym0 + MWDisassembler_PPC_shownames1 + + + GlobalOptimizer_PPC_optimizationlevelLevel0 + GlobalOptimizer_PPC_optforSpeed + + + MWLinker_PPC_linksym1 + MWLinker_PPC_symfullpath1 + MWLinker_PPC_linkmap0 + MWLinker_PPC_nolinkwarnings0 + MWLinker_PPC_dontdeadstripinitcode0 + MWLinker_PPC_permitmultdefs0 + MWLinker_PPC_linkmodeFast + MWLinker_PPC_code_foldingNone + MWLinker_PPC_initname + MWLinker_PPC_mainname + MWLinker_PPC_termname + + + MWLinker_MacOSX_linksym1 + MWLinker_MacOSX_symfullpath0 + MWLinker_MacOSX_nolinkwarnings0 + MWLinker_MacOSX_linkmap0 + MWLinker_MacOSX_dontdeadstripinitcode0 + MWLinker_MacOSX_permitmultdefs0 + MWLinker_MacOSX_use_objectivec_semantics0 + MWLinker_MacOSX_strip_debug_symbols0 + MWLinker_MacOSX_split_segs0 + MWLinker_MacOSX_report_msl_overloads0 + MWLinker_MacOSX_objects_follow_linkorder0 + MWLinker_MacOSX_linkmodeNormal + MWLinker_MacOSX_exportsReferencedGlobals + MWLinker_MacOSX_sortcodeNone + MWLinker_MacOSX_mainname + MWLinker_MacOSX_initname + MWLinker_MacOSX_code_foldingNone + MWLinker_MacOSX_stabsgenNone + + + MWProject_MacOSX_typeExecutable + MWProject_MacOSX_outfile + MWProject_MacOSX_filecreator???? + MWProject_MacOSX_filetypeMEXE + MWProject_MacOSX_vmaddress4096 + MWProject_MacOSX_usedefaultvmaddr1 + MWProject_MacOSX_flatrsrc0 + MWProject_MacOSX_flatrsrcfilename + MWProject_MacOSX_flatrsrcoutputdir + Path: + PathFormatMacOS + PathRootProject + + MWProject_MacOSX_installpath./ + MWProject_MacOSX_dont_prebind0 + MWProject_MacOSX_flat_namespace0 + MWProject_MacOSX_frameworkversionA + MWProject_MacOSX_currentversion0 + MWProject_MacOSX_flat_oldimpversion0 + MWProject_MacOSX_AddrMode1 + + + MWPEF_exportsNone + MWPEF_libfolder0 + MWPEF_sortcodeNone + MWPEF_expandbss0 + MWPEF_sharedata0 + MWPEF_olddefversion0 + MWPEF_oldimpversion0 + MWPEF_currentversion0 + MWPEF_fragmentname + MWPEF_collapsereloads0 + + + MWProject_PPC_typeLibrary + MWProject_PPC_outfileFreeTypeLib + MWProject_PPC_filecreator???? + MWProject_PPC_filetype???? + MWProject_PPC_size0 + MWProject_PPC_minsize0 + MWProject_PPC_stacksize0 + MWProject_PPC_flags0 + MWProject_PPC_symfilename + MWProject_PPC_rsrcname + MWProject_PPC_rsrcheaderNative + MWProject_PPC_rsrctype???? + MWProject_PPC_rsrcid0 + MWProject_PPC_rsrcflags0 + MWProject_PPC_rsrcstore0 + MWProject_PPC_rsrcmerge0 + MWProject_PPC_flatrsrc0 + MWProject_PPC_flatrsrcoutputdir + Path: + PathFormatMacOS + PathRootProject + + MWProject_PPC_flatrsrcfilename + + + MWAssembler_PPC_auxheader0 + MWAssembler_PPC_symmodeMac + MWAssembler_PPC_dialectPPC + MWAssembler_PPC_prefixfile + MWAssembler_PPC_typecheck0 + MWAssembler_PPC_warnings0 + MWAssembler_PPC_casesensitive0 + + + PList_OutputTypeFile + PList_OutputEncodingUTF-8 + PList_PListVersion1.0 + PList_Prefix + PList_FileFilenameInfo.plist + PList_FileDirectory + Path: + PathFormatMacOS + PathRootProject + + PList_ResourceTypeplst + PList_ResourceID0 + PList_ResourceName + + + MWRez_Language_maxwidth80 + MWRez_Language_scriptRoman + MWRez_Language_alignmentAlign1 + MWRez_Language_filtermodeFilterSkip + MWRez_Language_suppresswarnings0 + MWRez_Language_escapecontrolchars1 + MWRez_Language_prefixname + MWRez_Language_filteredtypes'CODE' 'DATA' 'PICT' + + + + Name + ftsystem.c + MacOS + Text + Debug + + + Name + ftbase.c + MacOS + Text + Debug + + + Name + ftinit.c + MacOS + Text + Debug + + + Name + sfnt.c + MacOS + Text + Debug + + + Name + psnames.c + MacOS + Text + Debug + + + Name + ftdebug.c + MacOS + Text + Debug + + + Name + type1cid.c + MacOS + Text + Debug + + + Name + cff.c + MacOS + Text + Debug + + + Name + smooth.c + MacOS + Text + Debug + + + Name + winfnt.c + MacOS + Text + Debug + + + Name + truetype.c + MacOS + Text + Debug + + + Name + ftmac.c + MacOS + Text + Debug + + + Name + psaux.c + MacOS + Text + + + + Name + ftcache.c + MacOS + Text + + + + Name + ftglyph.c + MacOS + Text + + + + Name + type1.c + MacOS + Text + Debug + + + Name + pshinter.c + MacOS + Text + Debug + + + Name + pcf.c + MacOS + Text + Debug + + + Name + ftraster.c + MacOS + Text + Debug + + + Name + ftrend1.c + MacOS + Text + Debug + + + + + Name + ftsystem.c + MacOS + + + Name + ftbase.c + MacOS + + + Name + ftinit.c + MacOS + + + Name + sfnt.c + MacOS + + + Name + psnames.c + MacOS + + + Name + ftdebug.c + MacOS + + + Name + type1cid.c + MacOS + + + Name + cff.c + MacOS + + + Name + smooth.c + MacOS + + + Name + winfnt.c + MacOS + + + Name + truetype.c + MacOS + + + Name + ftmac.c + MacOS + + + Name + psaux.c + MacOS + + + Name + ftcache.c + MacOS + + + Name + ftglyph.c + MacOS + + + Name + type1.c + MacOS + + + Name + pshinter.c + MacOS + + + Name + pcf.c + MacOS + + + Name + ftraster.c + MacOS + + + Name + ftrend1.c + MacOS + + + + + + + FreeTypeLib + + + + base + + FreeTypeLib + Name + ftbase.c + MacOS + + + FreeTypeLib + Name + ftdebug.c + MacOS + + + FreeTypeLib + Name + ftglyph.c + MacOS + + + FreeTypeLib + Name + ftinit.c + MacOS + + + FreeTypeLib + Name + ftsystem.c + MacOS + + + FreeTypeLib + Name + ftmac.c + MacOS + + + ftmodules + + FreeTypeLib + Name + cff.c + MacOS + + + FreeTypeLib + Name + ftcache.c + MacOS + + + FreeTypeLib + Name + psaux.c + MacOS + + + FreeTypeLib + Name + psnames.c + MacOS + + + FreeTypeLib + Name + sfnt.c + MacOS + + + FreeTypeLib + Name + smooth.c + MacOS + + + FreeTypeLib + Name + truetype.c + MacOS + + + FreeTypeLib + Name + type1cid.c + MacOS + + + FreeTypeLib + Name + winfnt.c + MacOS + + + FreeTypeLib + Name + type1.c + MacOS + + + FreeTypeLib + Name + pshinter.c + MacOS + + + FreeTypeLib + Name + pcf.c + MacOS + + + FreeTypeLib + Name + ftraster.c + MacOS + + + FreeTypeLib + Name + ftrend1.c + MacOS + + + + + diff --git a/vendor/freetype/builds/mac/ftmac.c b/vendor/freetype/builds/mac/ftmac.c new file mode 100644 index 0000000..8fe5565 --- /dev/null +++ b/vendor/freetype/builds/mac/ftmac.c @@ -0,0 +1,1542 @@ +/***************************************************************************/ +/* */ +/* ftmac.c */ +/* */ +/* Mac FOND support. Written by just@letterror.com. */ +/* Heavily Fixed by mpsuzuki, George Williams and Sean McBride */ +/* */ +/* Copyright (C) 1996-2023 by */ +/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /* + Notes + + Mac suitcase files can (and often do!) contain multiple fonts. To + support this I use the face_index argument of FT_(Open|New)_Face() + functions, and pretend the suitcase file is a collection. + + Warning: fbit and NFNT bitmap resources are not supported yet. In old + sfnt fonts, bitmap glyph data for each size is stored in each `NFNT' + resources instead of the `bdat' table in the sfnt resource. Therefore, + face->num_fixed_sizes is set to 0, because bitmap data in `NFNT' + resource is unavailable at present. + + The Mac FOND support works roughly like this: + + - Check whether the offered stream points to a Mac suitcase file. This + is done by checking the file type: it has to be 'FFIL' or 'tfil'. The + stream that gets passed to our init_face() routine is a stdio stream, + which isn't usable for us, since the FOND resources live in the + resource fork. So we just grab the stream->pathname field. + + - Read the FOND resource into memory, then check whether there is a + TrueType font and/or(!) a Type 1 font available. + + - If there is a Type 1 font available (as a separate `LWFN' file), read + its data into memory, massage it slightly so it becomes PFB data, wrap + it into a memory stream, load the Type 1 driver and delegate the rest + of the work to it by calling FT_Open_Face(). (XXX TODO: after this + has been done, the kerning data from the FOND resource should be + appended to the face: On the Mac there are usually no AFM files + available. However, this is tricky since we need to map Mac char + codes to ps glyph names to glyph ID's...) + + - If there is a TrueType font (an `sfnt' resource), read it into memory, + wrap it into a memory stream, load the TrueType driver and delegate + the rest of the work to it, by calling FT_Open_Face(). + + - Some suitcase fonts (notably Onyx) might point the `LWFN' file to + itself, even though it doesn't contains `POST' resources. To handle + this special case without opening the file an extra time, we just + ignore errors from the `LWFN' and fallback to the `sfnt' if both are + available. + */ + + +#include +#include +#include +#include "ftbase.h" + +#if defined( __GNUC__ ) || defined( __IBMC__ ) + /* This is for Mac OS X. Without redefinition, OS_INLINE */ + /* expands to `static inline' which doesn't survive the */ + /* -ansi compilation flag of GCC. */ +#if !HAVE_ANSI_OS_INLINE +#undef OS_INLINE +#define OS_INLINE static __inline__ +#endif +#include +#include +#include /* PATH_MAX */ +#else +#include +#include +#include +#include +#include +#include +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */ +#endif + +#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO +#include +#endif + +#define FT_DEPRECATED_ATTRIBUTE + +#include + + /* undefine blocking-macros in ftmac.h */ +#undef FT_GetFile_From_Mac_Name +#undef FT_GetFile_From_Mac_ATS_Name +#undef FT_New_Face_From_FOND +#undef FT_New_Face_From_FSSpec +#undef FT_New_Face_From_FSRef + + + /* FSSpec functions are deprecated since Mac OS X 10.4 */ +#ifndef HAVE_FSSPEC +#if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON +#define HAVE_FSSPEC 1 +#else +#define HAVE_FSSPEC 0 +#endif +#endif + + /* most FSRef functions were introduced since Mac OS 9 */ +#ifndef HAVE_FSREF +#if TARGET_API_MAC_OSX +#define HAVE_FSREF 1 +#else +#define HAVE_FSREF 0 +#endif +#endif + + /* QuickDraw is deprecated since Mac OS X 10.4 */ +#ifndef HAVE_QUICKDRAW_CARBON +#if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON +#define HAVE_QUICKDRAW_CARBON 1 +#else +#define HAVE_QUICKDRAW_CARBON 0 +#endif +#endif + + /* AppleTypeService is available since Mac OS X */ +#ifndef HAVE_ATS +#if TARGET_API_MAC_OSX +#define HAVE_ATS 1 +#ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */ +#define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault +#endif +#else +#define HAVE_ATS 0 +#endif +#endif + + /* `configure' checks the availability of `ResourceIndex' strictly */ + /* and sets HAVE_TYPE_RESOURCE_INDEX to 1 or 0 always. If it is */ + /* not set (e.g., a build without `configure'), the availability */ + /* is guessed from the SDK version. */ +#ifndef HAVE_TYPE_RESOURCE_INDEX +#if !defined( MAC_OS_X_VERSION_10_5 ) || \ + ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 ) +#define HAVE_TYPE_RESOURCE_INDEX 0 +#else +#define HAVE_TYPE_RESOURCE_INDEX 1 +#endif +#endif /* !HAVE_TYPE_RESOURCE_INDEX */ + +#if ( HAVE_TYPE_RESOURCE_INDEX == 0 ) +typedef short ResourceIndex; +#endif + + /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over + TrueType in case *both* are available (this is not common, + but it *is* possible). */ +#ifndef PREFER_LWFN +#define PREFER_LWFN 1 +#endif + +#ifdef FT_MACINTOSH + +#if !HAVE_QUICKDRAW_CARBON /* QuickDraw is deprecated since Mac OS X 10.4 */ + + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_THROW( Unimplemented_Feature ); + } + +#else + + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + OptionBits options = kFMUseGlobalScopeOption; + + FMFontFamilyIterator famIter; + OSStatus status = FMCreateFontFamilyIterator( NULL, NULL, + options, + &famIter ); + FMFont the_font = 0; + FMFontFamily family = 0; + + + if ( !fontName || !face_index ) + return FT_THROW( Invalid_Argument ); + + *face_index = 0; + while ( status == 0 && !the_font ) + { + status = FMGetNextFontFamily( &famIter, &family ); + if ( status == 0 ) + { + int stat2; + FMFontFamilyInstanceIterator instIter; + Str255 famNameStr; + char famName[256]; + + + /* get the family name */ + FMGetFontFamilyName( family, famNameStr ); + CopyPascalStringToC( famNameStr, famName ); + + /* iterate through the styles */ + FMCreateFontFamilyInstanceIterator( family, &instIter ); + + *face_index = 0; + stat2 = 0; + + while ( stat2 == 0 && !the_font ) + { + FMFontStyle style; + FMFontSize size; + FMFont font; + + + stat2 = FMGetNextFontFamilyInstance( &instIter, &font, + &style, &size ); + if ( stat2 == 0 && size == 0 ) + { + char fullName[256]; + + + /* build up a complete face name */ + ft_strcpy( fullName, famName ); + if ( style & bold ) + ft_strcat( fullName, " Bold" ); + if ( style & italic ) + ft_strcat( fullName, " Italic" ); + + /* compare with the name we are looking for */ + if ( ft_strcmp( fullName, fontName ) == 0 ) + { + /* found it! */ + the_font = font; + } + else + ++(*face_index); + } + } + + FMDisposeFontFamilyInstanceIterator( &instIter ); + } + } + + FMDisposeFontFamilyIterator( &famIter ); + + if ( the_font ) + { + FMGetFontContainer( the_font, pathSpec ); + return FT_Err_Ok; + } + else + return FT_THROW( Unknown_File_Format ); + } + +#endif /* HAVE_QUICKDRAW_CARBON */ + + +#if HAVE_ATS + + /* Private function. */ + /* The FSSpec type has been discouraged for a long time, */ + /* unfortunately an FSRef replacement API for */ + /* ATSFontGetFileSpecification() is only available in */ + /* Mac OS X 10.5 and later. */ + static OSStatus + FT_ATSFontGetFileReference( ATSFontRef ats_font_id, + FSRef* ats_font_ref ) + { + OSStatus err; + +#if !defined( MAC_OS_X_VERSION_10_5 ) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + FSSpec spec; + + + err = ATSFontGetFileSpecification( ats_font_id, &spec ); + if ( noErr == err ) + err = FSpMakeFSRef( &spec, ats_font_ref ); +#else + err = ATSFontGetFileReference( ats_font_id, ats_font_ref ); +#endif + + return err; + } + + + static FT_Error + FT_GetFileRef_From_Mac_ATS_Name( const char* fontName, + FSRef* ats_font_ref, + FT_Long* face_index ) + { + CFStringRef cf_fontName; + ATSFontRef ats_font_id; + + + *face_index = 0; + + cf_fontName = CFStringCreateWithCString( NULL, fontName, + kCFStringEncodingMacRoman ); + ats_font_id = ATSFontFindFromName( cf_fontName, + kATSOptionFlagsUnRestrictedScope ); + CFRelease( cf_fontName ); + + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + return FT_THROW( Unknown_File_Format ); + + if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) ) + return FT_THROW( Unknown_File_Format ); + + /* face_index calculation by searching preceding fontIDs */ + /* with same FSRef */ + { + ATSFontRef id2 = ats_font_id - 1; + FSRef ref2; + + + while ( id2 > 0 ) + { + if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) ) + break; + if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) ) + break; + + id2--; + } + *face_index = ats_font_id - ( id2 + 1 ); + } + + return FT_Err_Ok; + } + +#endif + +#if !HAVE_ATS + + FT_EXPORT_DEF( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + { + FT_UNUSED( fontName ); + FT_UNUSED( path ); + FT_UNUSED( maxPathSize ); + FT_UNUSED( face_index ); + + return FT_THROW( Unimplemented_Feature ); + } + +#else + + FT_EXPORT_DEF( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + { + FSRef ref; + FT_Error err; + + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( err ) + return err; + + if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) ) + return FT_THROW( Unknown_File_Format ); + + return FT_Err_Ok; + } + +#endif /* HAVE_ATS */ + + +#if !HAVE_FSSPEC || !HAVE_ATS + + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_THROW( Unimplemented_Feature ); + } + +#else + + /* This function is deprecated because FSSpec is deprecated in Mac OS X. */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + FSRef ref; + FT_Error err; + + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( err ) + return err; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, + pathSpec, NULL ) ) + return FT_THROW( Unknown_File_Format ); + + return FT_Err_Ok; + } + +#endif + + +#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO + +#define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer ) + + + FT_CALLBACK_DEF( void ) + ft_FSp_stream_close( FT_Stream stream ) + { + ft_fclose( STREAM_FILE( stream ) ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + FT_CALLBACK_DEF( unsigned long ) + ft_FSp_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_FILE* file; + + + file = STREAM_FILE( stream ); + + ft_fseek( file, offset, SEEK_SET ); + + return (unsigned long)ft_fread( buffer, 1, count, file ); + } + +#endif /* __MWERKS__ && !TARGET_RT_MAC_MACHO */ + + +#if HAVE_FSSPEC && !HAVE_FSREF + + /* isDirectory is a dummy to synchronize API with FSPathMakeRef() */ + static OSErr + FT_FSPathMakeSpec( const UInt8* pathname, + FSSpec* spec_p, + Boolean isDirectory ) + { + const char *p, *q; + short vRefNum; + long dirID; + Str255 nodeName; + OSErr err; + FT_UNUSED( isDirectory ); + + + p = q = (const char *)pathname; + dirID = 0; + vRefNum = 0; + + while ( 1 ) + { + int len = ft_strlen( p ); + + + if ( len > 255 ) + len = 255; + + q = p + len; + + if ( q == p ) + return 0; + + if ( 255 < ft_strlen( (char *)pathname ) ) + { + while ( p < q && *q != ':' ) + q--; + } + + if ( p < q ) + *(char *)nodeName = q - p; + else if ( ft_strlen( p ) < 256 ) + *(char *)nodeName = ft_strlen( p ); + else + return errFSNameTooLong; + + ft_strncpy( (char *)nodeName + 1, (char *)p, *(char *)nodeName ); + err = FSMakeFSSpec( vRefNum, dirID, nodeName, spec_p ); + if ( err || '\0' == *q ) + return err; + + vRefNum = spec_p->vRefNum; + dirID = spec_p->parID; + + p = q; + } + } + + + static OSErr + FT_FSpMakePath( const FSSpec* spec_p, + UInt8* path, + UInt32 maxPathSize ) + { + OSErr err; + FSSpec spec = *spec_p; + short vRefNum; + long dirID; + Str255 parDir_name; + + + FT_MEM_SET( path, 0, maxPathSize ); + while ( 1 ) + { + int child_namelen = ft_strlen( (char *)path ); + unsigned char node_namelen = spec.name[0]; + unsigned char* node_name = spec.name + 1; + + + if ( node_namelen + child_namelen > maxPathSize ) + return errFSNameTooLong; + + FT_MEM_MOVE( path + node_namelen + 1, path, child_namelen ); + FT_MEM_COPY( path, node_name, node_namelen ); + if ( child_namelen > 0 ) + path[node_namelen] = ':'; + + vRefNum = spec.vRefNum; + dirID = spec.parID; + parDir_name[0] = '\0'; + err = FSMakeFSSpec( vRefNum, dirID, parDir_name, &spec ); + if ( noErr != err || dirID == spec.parID ) + break; + } + return noErr; + } + +#endif /* HAVE_FSSPEC && !HAVE_FSREF */ + + + static OSErr + FT_FSPathMakeRes( const UInt8* pathname, + ResFileRefNum* res ) + { + +#if HAVE_FSREF + + OSErr err; + FSRef ref; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + /* at present, no support for dfont format */ + err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res ); + if ( noErr == err ) + return err; + + /* fallback to original resource-fork font */ + *res = FSOpenResFile( &ref, fsRdPerm ); + err = ResError(); + +#else + + OSErr err; + FSSpec spec; + + + if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + /* at present, no support for dfont format without FSRef */ + /* (see above), try original resource-fork font */ + *res = FSpOpenResFile( &spec, fsRdPerm ); + err = ResError(); + +#endif /* HAVE_FSREF */ + + return err; + } + + + /* Return the file type for given pathname */ + static OSType + get_file_type_from_path( const UInt8* pathname ) + { + +#if HAVE_FSREF + + FSRef ref; + FSCatalogInfo info; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return ( OSType ) 0; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info, + NULL, NULL, NULL ) ) + return ( OSType ) 0; + + return ((FInfo *)(info.finderInfo))->fdType; + +#else + + FSSpec spec; + FInfo finfo; + + + if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) ) + return ( OSType ) 0; + + if ( noErr != FSpGetFInfo( &spec, &finfo ) ) + return ( OSType ) 0; + + return finfo.fdType; + +#endif /* HAVE_FSREF */ + + } + + + /* Given a PostScript font name, create the Macintosh LWFN file name. */ + static void + create_lwfn_name( char* ps_name, + Str255 lwfn_file_name ) + { + int max = 5, count = 0; + FT_Byte* p = lwfn_file_name; + FT_Byte* q = (FT_Byte*)ps_name; + + + lwfn_file_name[0] = 0; + + while ( *q ) + { + if ( ft_isupper( *q ) ) + { + if ( count ) + max = 3; + count = 0; + } + if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) + { + *++p = *q; + lwfn_file_name[0]++; + count++; + } + q++; + } + } + + + static short + count_faces_sfnt( char* fond_data ) + { + /* The count is 1 greater than the value in the FOND. */ + /* Isn't that cute? :-) */ + + return EndianS16_BtoN( *( (short*)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + } + + + static short + count_faces_scalable( char* fond_data ) + { + AsscEntry* assoc; + short i, face, face_all; + + + face_all = EndianS16_BtoN( *( (short *)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + face = 0; + + for ( i = 0; i < face_all; i++ ) + { + if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) ) + face++; + } + return face; + } + + + /* Look inside the FOND data, answer whether there should be an SFNT + resource, and answer the name of a possible LWFN Type 1 file. + + Thanks to Paul Miller (paulm@profoundeffects.com) for the fix + to load a face OTHER than the first one in the FOND! + */ + + static void + parse_fond( char* fond_data, + short* have_sfnt, + ResID* sfnt_id, + Str255 lwfn_file_name, + short face_index ) + { + AsscEntry* assoc; + AsscEntry* base_assoc; + FamRec* fond; + + + *sfnt_id = 0; + *have_sfnt = 0; + lwfn_file_name[0] = 0; + + fond = (FamRec*)fond_data; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + base_assoc = assoc; + + /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */ + if ( 47 < face_index ) + return; + + /* Let's do a little range checking before we get too excited here */ + if ( face_index < count_faces_sfnt( fond_data ) ) + { + assoc += face_index; /* add on the face_index! */ + + /* if the face at this index is not scalable, + fall back to the first one (old behavior) */ + if ( EndianS16_BtoN( assoc->fontSize ) == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( assoc->fontID ); + } + else if ( base_assoc->fontSize == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( base_assoc->fontID ); + } + } + + if ( EndianS32_BtoN( fond->ffStylOff ) ) + { + unsigned char* p = (unsigned char*)fond_data; + StyleTable* style; + unsigned short string_count; + char ps_name[256]; + unsigned char* names[64]; + int i; + + + p += EndianS32_BtoN( fond->ffStylOff ); + style = (StyleTable*)p; + p += sizeof ( StyleTable ); + string_count = EndianS16_BtoN( *(short*)(p) ); + string_count = FT_MIN( 64, string_count ); + p += sizeof ( short ); + + for ( i = 0; i < string_count; i++ ) + { + names[i] = p; + p += names[i][0]; + p++; + } + + { + size_t ps_name_len = (size_t)names[0][0]; + + + if ( ps_name_len != 0 ) + { + ft_memcpy(ps_name, names[0] + 1, ps_name_len); + ps_name[ps_name_len] = 0; + } + if ( style->indexes[face_index] > 1 && + style->indexes[face_index] <= string_count ) + { + unsigned char* suffixes = names[style->indexes[face_index] - 1]; + + + for ( i = 1; i <= suffixes[0]; i++ ) + { + unsigned char* s; + size_t j = suffixes[i] - 1; + + + if ( j < string_count && ( s = names[j] ) != NULL ) + { + size_t s_len = (size_t)s[0]; + + + if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) + { + ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); + ps_name_len += s_len; + ps_name[ps_name_len] = 0; + } + } + } + } + } + + create_lwfn_name( ps_name, lwfn_file_name ); + } + } + + + static FT_Error + lookup_lwfn_by_fond( const UInt8* path_fond, + ConstStr255Param base_lwfn, + UInt8* path_lwfn, + int path_size ) + { + +#if HAVE_FSREF + + FSRef ref, par_ref; + int dirname_len; + + + /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ + /* We should not extract parent directory by string manipulation. */ + + if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) + return FT_THROW( Invalid_Argument ); + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, &par_ref ) ) + return FT_THROW( Invalid_Argument ); + + if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) + return FT_THROW( Invalid_Argument ); + + if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) + return FT_THROW( Invalid_Argument ); + + /* now we have absolute dirname in path_lwfn */ + if ( path_lwfn[0] == '/' ) + ft_strcat( (char *)path_lwfn, "/" ); + else + ft_strcat( (char *)path_lwfn, ":" ); + + dirname_len = ft_strlen( (char *)path_lwfn ); + ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); + path_lwfn[dirname_len + base_lwfn[0]] = '\0'; + + if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, NULL ) ) + return FT_THROW( Cannot_Open_Resource ); + + return FT_Err_Ok; + +#else + + int i; + FSSpec spec; + + + /* pathname for FSSpec is always HFS format */ + if ( ft_strlen( (char *)path_fond ) > path_size ) + return FT_THROW( Invalid_Argument ); + + ft_strcpy( (char *)path_lwfn, (char *)path_fond ); + + i = ft_strlen( (char *)path_lwfn ) - 1; + while ( i > 0 && ':' != path_lwfn[i] ) + i--; + + if ( i + 1 + base_lwfn[0] > path_size ) + return FT_THROW( Invalid_Argument ); + + if ( ':' == path_lwfn[i] ) + { + ft_strcpy( (char *)path_lwfn + i + 1, (char *)base_lwfn + 1 ); + path_lwfn[i + 1 + base_lwfn[0]] = '\0'; + } + else + { + ft_strcpy( (char *)path_lwfn, (char *)base_lwfn + 1 ); + path_lwfn[base_lwfn[0]] = '\0'; + } + + if ( noErr != FT_FSPathMakeSpec( path_lwfn, &spec, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + return FT_Err_Ok; + +#endif /* HAVE_FSREF */ + + } + + + static short + count_faces( Handle fond, + const UInt8* pathname ) + { + ResID sfnt_id; + short have_sfnt, have_lwfn; + Str255 lwfn_file_name; + UInt8 buff[PATH_MAX]; + FT_Error err; + short num_faces; + + + have_sfnt = have_lwfn = 0; + + HLock( fond ); + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); + + if ( lwfn_file_name[0] ) + { + err = lookup_lwfn_by_fond( pathname, lwfn_file_name, + buff, sizeof ( buff ) ); + if ( !err ) + have_lwfn = 1; + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + num_faces = 1; + else + num_faces = count_faces_scalable( *fond ); + + HUnlock( fond ); + return num_faces; + } + + + /* Read Type 1 data from the POST resources inside the LWFN file, + return a PFB buffer. This is somewhat convoluted because the FT2 + PFB parser wants the ASCII header as one chunk, and the LWFN + chunks are often not organized that way, so we glue chunks + of the same type together. */ + static FT_Error + read_lwfn( FT_Memory memory, + ResFileRefNum res, + FT_Byte** pfb_data, + FT_ULong* size ) + { + FT_Error error = FT_Err_Ok; + ResID res_id; + unsigned char *buffer, *p, *size_p = NULL; + FT_ULong total_size = 0; + FT_ULong old_total_size = 0; + FT_ULong post_size, pfb_chunk_size; + Handle post_data; + char code, last_code; + + + UseResFile( res ); + + /* First pass: load all POST resources, and determine the size of */ + /* the output buffer. */ + res_id = 501; + last_code = -1; + + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( post_data == NULL ) + break; /* we are done */ + + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( code == 5 ) + total_size += 2; /* just the end code */ + else + total_size += 6; /* code + 4 bytes chunk length */ + } + + total_size += GetHandleSize( post_data ) - 2; + last_code = code; + + /* detect integer overflows */ + if ( total_size < old_total_size ) + { + error = FT_ERR( Array_Too_Large ); + goto Error; + } + + old_total_size = total_size; + } + + if ( FT_QALLOC( buffer, (FT_Long)total_size ) ) + goto Error; + + /* Second pass: append all POST data to the buffer, add PFB fields. */ + /* Glue all consecutive chunks of the same type together. */ + p = buffer; + res_id = 501; + last_code = -1; + pfb_chunk_size = 0; + + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( post_data == NULL ) + break; /* we are done */ + + post_size = (FT_ULong)GetHandleSize( post_data ) - 2; + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( last_code != -1 ) + { + /* we are done adding a chunk, fill in the size field */ + if ( size_p != NULL ) + { + *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); + } + pfb_chunk_size = 0; + } + + *p++ = 0x80; + if ( code == 5 ) + *p++ = 0x03; /* the end */ + else if ( code == 2 ) + *p++ = 0x02; /* binary segment */ + else + *p++ = 0x01; /* ASCII segment */ + + if ( code != 5 ) + { + size_p = p; /* save for later */ + p += 4; /* make space for size field */ + } + } + + ft_memcpy( p, *post_data + 2, post_size ); + pfb_chunk_size += post_size; + p += post_size; + last_code = code; + } + + *pfb_data = buffer; + *size = total_size; + + Error: + CloseResFile( res ); + return error; + } + + + /* Create a new FT_Face from a file spec to an LWFN file. */ + static FT_Error + FT_New_Face_From_LWFN( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Byte* pfb_data; + FT_ULong pfb_size; + FT_Error error; + ResFileRefNum res; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res ) ) + return FT_THROW( Cannot_Open_Resource ); + + pfb_data = NULL; + pfb_size = 0; + error = read_lwfn( library->memory, res, &pfb_data, &pfb_size ); + CloseResFile( res ); /* PFB is already loaded, useless anymore */ + if ( error ) + return error; + + return open_face_from_buffer( library, + pfb_data, + pfb_size, + face_index, + "type1", + aface ); + } + + + /* Create a new FT_Face from an SFNT resource, specified by res ID. */ + static FT_Error + FT_New_Face_From_SFNT( FT_Library library, + ResID sfnt_id, + FT_Long face_index, + FT_Face* aface ) + { + Handle sfnt = NULL; + FT_Byte* sfnt_data; + size_t sfnt_size; + FT_Error error = FT_Err_Ok; + FT_Memory memory = library->memory; + int is_cff, is_sfnt_ps; + + + sfnt = GetResource( TTAG_sfnt, sfnt_id ); + if ( sfnt == NULL ) + return FT_THROW( Invalid_Handle ); + + sfnt_size = (FT_ULong)GetHandleSize( sfnt ); + if ( FT_QALLOC( sfnt_data, (FT_Long)sfnt_size ) ) + { + ReleaseResource( sfnt ); + return error; + } + + HLock( sfnt ); + ft_memcpy( sfnt_data, *sfnt, sfnt_size ); + HUnlock( sfnt ); + ReleaseResource( sfnt ); + + is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); + is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 ); + + if ( is_sfnt_ps ) + { + FT_Stream stream; + + + if ( FT_NEW( stream ) ) + goto Try_OpenType; + + FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size ); + if ( !open_face_PS_from_sfnt_stream( library, + stream, + face_index, + 0, NULL, + aface ) ) + { + FT_Stream_Close( stream ); + FT_FREE( stream ); + FT_FREE( sfnt_data ); + goto Exit; + } + + FT_FREE( stream ); + } + Try_OpenType: + error = open_face_from_buffer( library, + sfnt_data, + sfnt_size, + face_index, + is_cff ? "cff" : "truetype", + aface ); + Exit: + return error; + } + + + /* Create a new FT_Face from a file spec to a suitcase file. */ + static FT_Error + FT_New_Face_From_Suitcase( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error = FT_ERR( Cannot_Open_Resource ); + ResFileRefNum res_ref; + ResourceIndex res_index; + Handle fond; + short num_faces_in_res; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) + return FT_THROW( Cannot_Open_Resource ); + + UseResFile( res_ref ); + if ( ResError() ) + return FT_THROW( Cannot_Open_Resource ); + + num_faces_in_res = 0; + for ( res_index = 1; ; ++res_index ) + { + short num_faces_in_fond; + + + fond = Get1IndResource( TTAG_FOND, res_index ); + if ( ResError() ) + break; + + num_faces_in_fond = count_faces( fond, pathname ); + num_faces_in_res += num_faces_in_fond; + + if ( 0 <= face_index && face_index < num_faces_in_fond && error ) + error = FT_New_Face_From_FOND( library, fond, face_index, aface ); + + face_index -= num_faces_in_fond; + } + + CloseResFile( res_ref ); + if ( !error && aface ) + (*aface)->num_faces = num_faces_in_res; + return error; + } + + + /* documentation is in ftmac.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face* aface ) + { + short have_sfnt, have_lwfn = 0; + ResID sfnt_id, fond_id; + OSType fond_type; + Str255 fond_name; + Str255 lwfn_file_name; + UInt8 path_lwfn[PATH_MAX]; + OSErr err; + FT_Error error = FT_Err_Ok; + + + /* test for valid `aface' and `library' delayed to */ + /* `FT_New_Face_From_XXX' */ + + GetResInfo( fond, &fond_id, &fond_type, fond_name ); + if ( ResError() != noErr || fond_type != TTAG_FOND ) + return FT_THROW( Invalid_File_Format ); + + HLock( fond ); + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index ); + HUnlock( fond ); + + if ( lwfn_file_name[0] ) + { + ResFileRefNum res; + + + res = HomeResFile( fond ); + if ( noErr != ResError() ) + goto found_no_lwfn_file; + +#if HAVE_FSREF + + { + UInt8 path_fond[PATH_MAX]; + FSRef ref; + + + err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum, + NULL, NULL, NULL, &ref, NULL ); + if ( noErr != err ) + goto found_no_lwfn_file; + + err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) ); + if ( noErr != err ) + goto found_no_lwfn_file; + + error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, + path_lwfn, sizeof ( path_lwfn ) ); + if ( !error ) + have_lwfn = 1; + } + +#elif HAVE_FSSPEC + + { + UInt8 path_fond[PATH_MAX]; + FCBPBRec pb; + Str255 fond_file_name; + FSSpec spec; + + + FT_MEM_SET( &spec, 0, sizeof ( FSSpec ) ); + FT_MEM_SET( &pb, 0, sizeof ( FCBPBRec ) ); + + pb.ioNamePtr = fond_file_name; + pb.ioVRefNum = 0; + pb.ioRefNum = res; + pb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync( &pb ); + if ( noErr != err ) + goto found_no_lwfn_file; + + err = FSMakeFSSpec( pb.ioFCBVRefNum, pb.ioFCBParID, + fond_file_name, &spec ); + if ( noErr != err ) + goto found_no_lwfn_file; + + err = FT_FSpMakePath( &spec, path_fond, sizeof ( path_fond ) ); + if ( noErr != err ) + goto found_no_lwfn_file; + + error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, + path_lwfn, sizeof ( path_lwfn ) ); + if ( !error ) + have_lwfn = 1; + } + +#endif /* HAVE_FSREF, HAVE_FSSPEC */ + + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + error = FT_New_Face_From_LWFN( library, + path_lwfn, + face_index, + aface ); + else + error = FT_ERR( Unknown_File_Format ); + + found_no_lwfn_file: + if ( have_sfnt && error ) + error = FT_New_Face_From_SFNT( library, + sfnt_id, + face_index, + aface ); + + return error; + } + + + /* Common function to load a new FT_Face from a resource file. */ + static FT_Error + FT_New_Face_From_Resource( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + OSType file_type; + FT_Error error; + + + /* LWFN is a (very) specific file format, check for it explicitly */ + file_type = get_file_type_from_path( pathname ); + if ( file_type == TTAG_LWFN ) + return FT_New_Face_From_LWFN( library, pathname, face_index, aface ); + + /* Otherwise the file type doesn't matter (there are more than */ + /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */ + /* if it works, fine. */ + + error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface ); + if ( !error ) + return error; + + /* let it fall through to normal loader (.ttf, .otf, etc.); */ + /* we signal this by returning no error and no FT_Face */ + *aface = NULL; + return 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face */ + /* */ + /* */ + /* This is the Mac-specific implementation of FT_New_Face. In */ + /* addition to the standard FT_New_Face() functionality, it also */ + /* accepts pathnames to Mac suitcase files. For further */ + /* documentation see the original FT_New_Face() in freetype.h. */ + /* */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Open_Args args; + FT_Error error; + + + /* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_THROW( Invalid_Argument ); + + *aface = NULL; + + /* try resourcefork based font: LWFN, FFIL */ + error = FT_New_Face_From_Resource( library, (UInt8 *)pathname, + face_index, aface ); + if ( error || *aface ) + return error; + + /* let it fall through to normal loader (.ttf, .otf, etc.) */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face_From_FSRef */ + /* */ + /* */ + /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */ + /* accepts an FSRef instead of a path. */ + /* */ + /* This function is deprecated because Carbon data types (FSRef) */ + /* are not cross-platform, and thus not suitable for the FreeType API. */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef* ref, + FT_Long face_index, + FT_Face* aface ) + { + +#if !HAVE_FSREF + + FT_UNUSED( library ); + FT_UNUSED( ref ); + FT_UNUSED( face_index ); + FT_UNUSED( aface ); + + return FT_THROW( Unimplemented_Feature ); + +#else + + FT_Error error; + FT_Open_Args args; + OSErr err; + UInt8 pathname[PATH_MAX]; + + + /* test for valid `library' and `aface' delayed to `FT_Open_Face' */ + + if ( !ref ) + return FT_THROW( Invalid_Argument ); + + err = FSRefMakePath( ref, pathname, sizeof ( pathname ) ); + if ( err ) + error = FT_ERR( Cannot_Open_Resource ); + + error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); + if ( error || *aface ) + return error; + + /* fallback to datafork font */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + +#endif /* HAVE_FSREF */ + + } + + + /*************************************************************************/ + /* */ + /* */ + /* FT_New_Face_From_FSSpec */ + /* */ + /* */ + /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */ + /* accepts an FSSpec instead of a path. */ + /* */ + /* This function is deprecated because Carbon data types (FSSpec) */ + /* are not cross-platform, and thus not suitable for the FreeType API. */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec* spec, + FT_Long face_index, + FT_Face* aface ) + { + +#if HAVE_FSREF + + FSRef ref; + + + if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr ) + return FT_THROW( Invalid_Argument ); + else + return FT_New_Face_From_FSRef( library, &ref, face_index, aface ); + +#elif HAVE_FSSPEC + + FT_Error error; + FT_Open_Args args; + OSErr err; + UInt8 pathname[PATH_MAX]; + + + if ( !spec ) + return FT_THROW( Invalid_Argument ); + + err = FT_FSpMakePath( spec, pathname, sizeof ( pathname ) ); + if ( err ) + error = FT_ERR( Cannot_Open_Resource ); + + error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); + if ( error || *aface ) + return error; + + /* fallback to datafork font */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + +#else + + FT_UNUSED( library ); + FT_UNUSED( spec ); + FT_UNUSED( face_index ); + FT_UNUSED( aface ); + + return FT_THROW( Unimplemented_Feature ); + +#endif /* HAVE_FSREF, HAVE_FSSPEC */ + + } + +#endif /* FT_MACINTOSH */ + + +/* END */ diff --git a/vendor/freetype/builds/meson/extract_freetype_version.py b/vendor/freetype/builds/meson/extract_freetype_version.py new file mode 100644 index 0000000..c4c60e7 --- /dev/null +++ b/vendor/freetype/builds/meson/extract_freetype_version.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +"""Extract the FreeType version numbers from ``. + +This script parses the header to extract the version number defined there. +By default, the full dotted version number is printed, but `--major`, +`--minor` or `--patch` can be used to only print one of these values +instead. +""" + +from __future__ import print_function + +import argparse +import os +import re +import sys + +# Expected input: +# +# ... +# #define FREETYPE_MAJOR 2 +# #define FREETYPE_MINOR 10 +# #define FREETYPE_PATCH 2 +# ... + +RE_MAJOR = re.compile(r"^ \#define \s+ FREETYPE_MAJOR \s+ (.*) $", re.X) +RE_MINOR = re.compile(r"^ \#define \s+ FREETYPE_MINOR \s+ (.*) $", re.X) +RE_PATCH = re.compile(r"^ \#define \s+ FREETYPE_PATCH \s+ (.*) $", re.X) + + +def parse_freetype_header(header): + major = None + minor = None + patch = None + + for line in header.splitlines(): + line = line.rstrip() + m = RE_MAJOR.match(line) + if m: + assert major == None, "FREETYPE_MAJOR appears more than once!" + major = m.group(1) + continue + + m = RE_MINOR.match(line) + if m: + assert minor == None, "FREETYPE_MINOR appears more than once!" + minor = m.group(1) + continue + + m = RE_PATCH.match(line) + if m: + assert patch == None, "FREETYPE_PATCH appears more than once!" + patch = m.group(1) + continue + + assert ( + major and minor and patch + ), "This header is missing one of FREETYPE_MAJOR, FREETYPE_MINOR or FREETYPE_PATCH!" + + return (major, minor, patch) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + group = parser.add_mutually_exclusive_group() + group.add_argument( + "--major", + action="store_true", + help="Only print the major version number.", + ) + group.add_argument( + "--minor", + action="store_true", + help="Only print the minor version number.", + ) + group.add_argument( + "--patch", + action="store_true", + help="Only print the patch version number.", + ) + + parser.add_argument( + "input", + metavar="FREETYPE_H", + help="The input freetype.h header to parse.", + ) + + args = parser.parse_args() + with open(args.input) as f: + header = f.read() + + version = parse_freetype_header(header) + + if args.major: + print(version[0]) + elif args.minor: + print(version[1]) + elif args.patch: + print(version[2]) + else: + print("%s.%s.%s" % version) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vendor/freetype/builds/meson/extract_libtool_version.py b/vendor/freetype/builds/meson/extract_libtool_version.py new file mode 100644 index 0000000..6fac74c --- /dev/null +++ b/vendor/freetype/builds/meson/extract_libtool_version.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +"""Extract the libtool version from `configure.raw`. + +This script parses the `configure.raw` file to extract the libtool version +number. By default, the full dotted version number is printed, but +`--major`, `--minor` or `--patch` can be used to only print one of these +values instead. +""" + +from __future__ import print_function + +import argparse +import os +import re +import sys + +# Expected input: +# +# ... +# version_info='23:2:17' +# ... + +RE_VERSION_INFO = re.compile(r"^version_info='(\d+):(\d+):(\d+)'") + + +def parse_configure_raw(header): + major = None + minor = None + patch = None + + for line in header.splitlines(): + line = line.rstrip() + m = RE_VERSION_INFO.match(line) + if m: + assert major == None, "version_info appears more than once!" + major = m.group(1) + minor = m.group(2) + patch = m.group(3) + continue + + assert ( + major and minor and patch + ), "This input file is missing a version_info definition!" + + return (major, minor, patch) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + group = parser.add_mutually_exclusive_group() + group.add_argument( + "--major", + action="store_true", + help="Only print the major version number.", + ) + group.add_argument( + "--minor", + action="store_true", + help="Only print the minor version number.", + ) + group.add_argument( + "--patch", + action="store_true", + help="Only print the patch version number.", + ) + group.add_argument( + "--soversion", + action="store_true", + help="Only print the libtool library suffix.", + ) + + parser.add_argument( + "input", + metavar="CONFIGURE_RAW", + help="The input configure.raw file to parse.", + ) + + args = parser.parse_args() + with open(args.input) as f: + raw_file = f.read() + + version = parse_configure_raw(raw_file) + + if args.major: + print(version[0]) + elif args.minor: + print(version[1]) + elif args.patch: + print(version[2]) + elif args.soversion: + # Convert libtool version_info to the library suffix. + # (current,revision, age) -> (current - age, age, revision) + print( + "%d.%s.%s" + % (int(version[0]) - int(version[2]), version[2], version[1]) + ) + else: + print("%s.%s.%s" % version) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vendor/freetype/builds/meson/generate_reference_docs.py b/vendor/freetype/builds/meson/generate_reference_docs.py new file mode 100644 index 0000000..4208bb6 --- /dev/null +++ b/vendor/freetype/builds/meson/generate_reference_docs.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +"""Generate FreeType reference documentation.""" + +from __future__ import print_function + +import argparse +import glob +import os +import subprocess +import sys + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + parser.add_argument( + "--input-dir", + required=True, + help="Top-level FreeType source directory.", + ) + + parser.add_argument( + "--version", required=True, help='FreeType version (e.g. "2.x.y").' + ) + + parser.add_argument( + "--output-dir", required=True, help="Output directory." + ) + + args = parser.parse_args() + + # Get the list of input files of interest. + include_dir = os.path.join(args.input_dir, "include") + include_config_dir = os.path.join(include_dir, "config") + include_cache_dir = os.path.join(include_dir, "cache") + + all_headers = ( + glob.glob(os.path.join(args.input_dir, "include", "freetype", "*.h")) + + glob.glob( + os.path.join( + args.input_dir, "include", "freetype", "config", "*.h" + ) + ) + + glob.glob( + os.path.join( + args.input_dir, "include", "freetype", "cache", "*.h" + ) + ) + ) + + if not os.path.exists(args.output_dir): + os.makedirs(args.output_dir) + else: + assert os.path.isdir(args.output_dir), ( + "Not a directory: " + args.output_dir + ) + + cmds = [ + sys.executable, + "-m", + "docwriter", + "--prefix=ft2", + "--title=FreeType-" + args.version, + "--site=reference", + "--output=" + args.output_dir, + ] + all_headers + + print("Running docwriter...") + subprocess.check_call(cmds) + + print("Building static site...") + subprocess.check_call( + [sys.executable, "-m", "mkdocs", "build"], cwd=args.output_dir + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vendor/freetype/builds/meson/parse_modules_cfg.py b/vendor/freetype/builds/meson/parse_modules_cfg.py new file mode 100644 index 0000000..d48129f --- /dev/null +++ b/vendor/freetype/builds/meson/parse_modules_cfg.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +"""Parse modules.cfg and dump its output either as ftmodule.h or a list of +base extensions. +""" + +from __future__ import print_function + +import argparse +import os +import re +import sys + +# Expected input: +# +# ... +# FONT_MODULES += +# HINTING_MODULES += +# RASTER_MODULES += +# AUX_MODULES += +# BASE_EXTENSIONS += +# ... + + +def parse_modules_cfg(input_file): + + lists = { + "FONT_MODULES": [], + "HINTING_MODULES": [], + "RASTER_MODULES": [], + "AUX_MODULES": [], + "BASE_EXTENSIONS": [], + } + + for line in input_file.splitlines(): + line = line.rstrip() + # Ignore empty lines and those that start with a comment. + if not line or line[0] == "#": + continue + + items = line.split() + assert len(items) == 3 and items[1] == "+=", ( + "Unexpected input line [%s]" % line + ) + assert items[0] in lists, ( + "Unexpected configuration variable name " + items[0] + ) + + lists[items[0]].append(items[2]) + + return lists + + +def generate_ftmodule(lists): + result = "/* This is a generated file. */\n" + for driver in lists["FONT_MODULES"]: + if driver == "sfnt": # Special case for the sfnt 'driver'. + result += "FT_USE_MODULE( FT_Module_Class, sfnt_module_class )\n" + continue + + name = { + "truetype": "tt", + "type1": "t1", + "cid": "t1cid", + "type42": "t42", + "winfonts": "winfnt", + }.get(driver, driver) + result += ( + "FT_USE_MODULE( FT_Driver_ClassRec, %s_driver_class )\n" % name + ) + + for module in lists["HINTING_MODULES"]: + result += ( + "FT_USE_MODULE( FT_Module_Class, %s_module_class )\n" % module + ) + + for module in lists["RASTER_MODULES"]: + names = { + "raster": ("ft_raster1",), + "smooth": ("ft_smooth",), + "svg": ("ft_svg",), + "sdf": ("ft_sdf", "ft_bitmap_sdf"), + }.get(module) + for name in names: + result += ( + "FT_USE_MODULE( FT_Renderer_Class, %s_renderer_class )\n" % name + ) + + for module in lists["AUX_MODULES"]: + if module in ("psaux", "psnames", "otvalid", "gxvalid"): + name = { + "gxvalid": "gxv", + "otvalid": "otv", + }.get(module, module) + result += ( + "FT_USE_MODULE( FT_Module_Class, %s_module_class )\n" % name + ) + + result += "/* EOF */\n" + return result + + +def generate_main_modules(lists): + return "\n".join( + lists["FONT_MODULES"] + + lists["HINTING_MODULES"] + + lists["RASTER_MODULES"] + ) + + +def generate_aux_modules(lists): + return "\n".join(lists["AUX_MODULES"]) + + +def generate_base_extensions(lists): + return "\n".join(lists["BASE_EXTENSIONS"]) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + parser.add_argument( + "--format", + required=True, + choices=( + "ftmodule.h", + "main-modules", + "aux-modules", + "base-extensions-list", + ), + help="Select output format.", + ) + + parser.add_argument( + "input", + metavar="CONFIGURE_RAW", + help="The input configure.raw file to parse.", + ) + + parser.add_argument("--output", help="Output file (default is stdout).") + + args = parser.parse_args() + with open(args.input) as f: + input_data = f.read() + + lists = parse_modules_cfg(input_data) + + if args.format == "ftmodule.h": + result = generate_ftmodule(lists) + elif args.format == "main-modules": + result = generate_main_modules(lists) + elif args.format == "aux-modules": + result = generate_aux_modules(lists) + elif args.format == "base-extensions-list": + result = generate_base_extensions(lists) + else: + assert False, "Invalid output format!" + + if args.output: + with open(args.output, "w") as f: + f.write(result) + else: + print(result) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vendor/freetype/builds/meson/process_ftoption_h.py b/vendor/freetype/builds/meson/process_ftoption_h.py new file mode 100644 index 0000000..98daa8c --- /dev/null +++ b/vendor/freetype/builds/meson/process_ftoption_h.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +"""Toggle settings in `ftoption.h` file based on command-line arguments. + +This script takes an `ftoption.h` file as input and rewrites +`#define`/`#undef` lines in it based on `--enable=CONFIG_VARNAME` or +`--disable=CONFIG_VARNAME` arguments passed to it, where `CONFIG_VARNAME` is +configuration variable name, such as `FT_CONFIG_OPTION_USE_LZW`, that may +appear in the file. + +Note that if one of `CONFIG_VARNAME` is not found in the input file, this +script exits with an error message listing the missing variable names. +""" + +import argparse +import os +import re +import sys + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + parser.add_argument( + "input", metavar="FTOPTION_H", help="Path to input ftoption.h file." + ) + + parser.add_argument("--output", help="Output to file instead of stdout.") + + parser.add_argument( + "--enable", + action="append", + default=[], + help="Enable a given build option (e.g. FT_CONFIG_OPTION_USE_LZW).", + ) + + parser.add_argument( + "--disable", + action="append", + default=[], + help="Disable a given build option.", + ) + + args = parser.parse_args() + + common_options = set(args.enable) & set(args.disable) + if common_options: + parser.error( + "Options cannot be both enabled and disabled: %s" + % sorted(common_options) + ) + return 1 + + with open(args.input) as f: + input_file = f.read() + + options_seen = set() + + new_lines = [] + for line in input_file.splitlines(): + # Expected formats: + # #define + # /* #define */ + # #undef + line = line.rstrip() + if line.startswith("/* #define ") and line.endswith(" */"): + option_name = line[11:-3].strip() + option_enabled = False + elif line.startswith("#define "): + option_name = line[8:].strip() + option_enabled = True + elif line.startswith("#undef "): + option_name = line[7:].strip() + option_enabled = False + else: + new_lines.append(line) + continue + + options_seen.add(option_name) + if option_enabled and option_name in args.disable: + line = "#undef " + option_name + elif not option_enabled and option_name in args.enable: + line = "#define " + option_name + new_lines.append(line) + + result = "\n".join(new_lines) + "\n" + + # Sanity check that all command-line options were actually processed. + cmdline_options = set(args.enable) | set(args.disable) + assert cmdline_options.issubset( + options_seen + ), "Could not find options in input file: " + ", ".join( + sorted(cmdline_options - options_seen) + ) + + if args.output: + with open(args.output, "w") as f: + f.write(result) + else: + print(result) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vendor/freetype/builds/modules.mk b/vendor/freetype/builds/modules.mk new file mode 100644 index 0000000..a75baaf --- /dev/null +++ b/vendor/freetype/builds/modules.mk @@ -0,0 +1,79 @@ +# +# FreeType 2 modules sub-Makefile +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# DO NOT INVOKE THIS MAKEFILE DIRECTLY! IT IS MEANT TO BE INCLUDED BY +# OTHER MAKEFILES. + + +# This file is in charge of handling the generation of the modules list +# file. + + +# Build the modules list. +# +$(FTMODULE_H): $(MODULES_CFG) + $(FTMODULE_H_INIT) + $(FTMODULE_H_CREATE) + $(FTMODULE_H_DONE) + +ifneq ($(findstring $(PLATFORM),dos windows os2),) + OPEN_MODULE := @echo$(space) + CLOSE_MODULE := >> $(subst /,$(SEP),$(FTMODULE_H)) + REMOVE_MODULE := @-$(DELETE) $(subst /,$(SEP),$(FTMODULE_H)) +else + OPEN_MODULE := @echo " + CLOSE_MODULE := " >> $(FTMODULE_H) + REMOVE_MODULE := @-$(DELETE) $(FTMODULE_H) +endif + + +define FTMODULE_H_INIT +$(REMOVE_MODULE) +$(info Generating modules list in $(FTMODULE_H)...) +$(OPEN_MODULE)/* This is a generated file. */$(CLOSE_MODULE) +endef + +# It is no mistake that the final closing parenthesis is on the +# next line -- it produces proper newlines during the expansion +# of `foreach'. +# +define FTMODULE_H_CREATE +$(foreach COMMAND,$(FTMODULE_H_COMMANDS),$($(COMMAND)) +) +endef + +define FTMODULE_H_DONE +$(OPEN_MODULE)/* EOF */$(CLOSE_MODULE) +$(info done.) +endef + + +# $(OPEN_DRIVER) & $(CLOSE_DRIVER) are used to specify a given font driver +# in the `module.mk' rules file. +# +OPEN_DRIVER := $(OPEN_MODULE)FT_USE_MODULE( +CLOSE_DRIVER := )$(CLOSE_MODULE) + +ECHO_DRIVER := @echo "* module:$(space) +ECHO_DRIVER_DESC := ( +ECHO_DRIVER_DONE := )" + +# Each `module.mk' in the `src/*' subdirectories adds a variable with +# commands to $(FTMODULE_H_COMMANDS). Note that we can't use SRC_DIR here. +# +-include $(patsubst %,$(TOP_DIR)/src/%/module.mk,$(MODULES)) + + +# EOF diff --git a/vendor/freetype/builds/os2/detect.mk b/vendor/freetype/builds/os2/detect.mk new file mode 100644 index 0000000..afdba74 --- /dev/null +++ b/vendor/freetype/builds/os2/detect.mk @@ -0,0 +1,81 @@ +# +# FreeType 2 configuration file to detect an OS/2 host platform. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +.PHONY: setup + + +ifeq ($(PLATFORM),ansi) + + ifdef OS2_SHELL + + PLATFORM := os2 + + endif # test OS2_SHELL +endif + +ifeq ($(PLATFORM),os2) + + COPY := copy + DELETE := del + CAT := type + SEP := $(BACKSLASH) + + # gcc-emx by default + CONFIG_FILE := os2-gcc.mk + + # additionally, we provide hooks for various other compilers + # + ifneq ($(findstring visualage,$(MAKECMDGOALS)),) # Visual Age C++ + CONFIG_FILE := os2-icc.mk + CC := icc + + .PHONY: visualage + visualage: setup + @cd . + endif + + ifneq ($(findstring watcom,$(MAKECMDGOALS)),) # Watcom C/C++ + CONFIG_FILE := os2-wat.mk + CC := wcc386 + + .PHONY: watcom + watcom: setup + @cd . + endif + + ifneq ($(findstring borlandc,$(MAKECMDGOALS)),) # Borland C++ 32-bit + CONFIG_FILE := os2-bcc.mk + CC := bcc32 + + .PHONY: borlandc + borlandc: setup + @cd . + endif + + ifneq ($(findstring devel,$(MAKECMDGOALS)),) # development target + CONFIG_FILE := os2-dev.mk + CC := gcc + + .PHONY: devel + devel: setup + @cd . + endif + + setup: std_setup + +endif # test PLATFORM os2 + + +# EOF diff --git a/vendor/freetype/builds/os2/os2-def.mk b/vendor/freetype/builds/os2/os2-def.mk new file mode 100644 index 0000000..917ef2d --- /dev/null +++ b/vendor/freetype/builds/os2/os2-def.mk @@ -0,0 +1,48 @@ +# +# FreeType 2 OS/2 specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DELETE := del +CAT := type +SEP := $(strip \ ) +PLATFORM_DIR := $(TOP_DIR)/builds/os2 +PLATFORM := os2 + +# This is used for `make refdoc' and `make refdoc-venv' +# +BIN := Scripts + +# The executable file extension (for tools), *with* leading dot. +# +E := .exe + +# The directory where all library files are placed. +# +# By default, this is the same as $(OBJ_DIR); however, this can be changed +# to suit particular needs. +# +LIB_DIR := $(OBJ_DIR) + +# The name of the final library file. Note that the DOS-specific Makefile +# uses a shorter (8.3) name. +# +LIBRARY := $(PROJECT) + + +# The NO_OUTPUT macro is used to ignore the output of commands. +# +NO_OUTPUT = 2> nul + + +# EOF diff --git a/vendor/freetype/builds/os2/os2-dev.mk b/vendor/freetype/builds/os2/os2-dev.mk new file mode 100644 index 0000000..3584fb6 --- /dev/null +++ b/vendor/freetype/builds/os2/os2-dev.mk @@ -0,0 +1,30 @@ +# +# FreeType 2 configuration rules for OS/2 + GCC +# +# Development version without optimizations. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DEVEL_DIR := $(TOP_DIR)/devel + +# include OS/2-specific definitions +include $(TOP_DIR)/builds/os2/os2-def.mk + +# include gcc-specific definitions +include $(TOP_DIR)/builds/compiler/gcc-dev.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/os2/os2-gcc.mk b/vendor/freetype/builds/os2/os2-gcc.mk new file mode 100644 index 0000000..e17c5be --- /dev/null +++ b/vendor/freetype/builds/os2/os2-gcc.mk @@ -0,0 +1,26 @@ +# +# FreeType 2 configuration rules for the OS/2 + gcc +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# include OS/2-specific definitions +include $(TOP_DIR)/builds/os2/os2-def.mk + +# include gcc-specific definitions +include $(TOP_DIR)/builds/compiler/gcc.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/symbian/bld.inf b/vendor/freetype/builds/symbian/bld.inf new file mode 100644 index 0000000..6168922 --- /dev/null +++ b/vendor/freetype/builds/symbian/bld.inf @@ -0,0 +1,72 @@ +// +// FreeType 2 project for the symbian platform +// + +// Copyright (C) 2008-2023 by +// David Turner, Robert Wilhelm, and Werner Lemberg. +// +// This file is part of the FreeType project, and may only be used, modified, +// and distributed under the terms of the FreeType project license, +// LICENSE.TXT. By continuing to use, modify, or distribute this file you +// indicate that you have read the license and understand and accept it +// fully. + +PRJ_PLATFORMS +DEFAULT + +PRJ_MMPFILES +freetype.mmp + +PRJ_EXPORTS +../../include/freetype/ft2build.h +../../include/freetype/config/ftconfig.h config/ftconfig.h +../../include/freetype/config/ftheader.h config/ftheader.h +../../include/freetype/config/ftmodule.h config/ftmodule.h +../../include/freetype/config/ftoption.h config/ftoption.h +../../include/freetype/config/ftstdlib.h config/ftstdlib.h +../../include/freetype/freetype.h freetype.h +../../include/freetype/ftadvanc.h ftadvanc.h +../../include/freetype/ftautoh.h ftautoh.h +../../include/freetype/ftbbox.h ftbbox.h +../../include/freetype/ftbdf.h ftbdf.h +../../include/freetype/ftbitmap.h ftbitmap.h +../../include/freetype/ftbzip2.h ftbzip2.h +../../include/freetype/ftcache.h ftcache.h +../../include/freetype/ftcffdrv.h ftcffdrv.h +../../include/freetype/ftcid.h ftcid.h +../../include/freetype/fterrdef.h fterrdef.h +../../include/freetype/fterrors.h fterrors.h +../../include/freetype/ftfntfmt.h ftfntfmt.h +../../include/freetype/ftgasp.h ftgasp.h +../../include/freetype/ftglyph.h ftglyph.h +../../include/freetype/ftgxval.h ftgxval.h +../../include/freetype/ftgzip.h ftgzip.h +../../include/freetype/ftimage.h ftimage.h +../../include/freetype/ftincrem.h ftincrem.h +../../include/freetype/ftlcdfil.h ftlcdfil.h +../../include/freetype/ftlist.h ftlist.h +../../include/freetype/ftlzw.h ftlzw.h +../../include/freetype/ftmac.h ftmac.h +../../include/freetype/ftmm.h ftmm.h +../../include/freetype/ftmodapi.h ftmodapi.h +../../include/freetype/ftmoderr.h ftmoderr.h +../../include/freetype/ftotval.h ftotval.h +../../include/freetype/ftoutln.h ftoutln.h +../../include/freetype/ftparams.h ftparams.h +../../include/freetype/ftpcfdrv.h ftpcfdrv.h +../../include/freetype/ftpfr.h ftpfr.h +../../include/freetype/ftrender.h ftrender.h +../../include/freetype/ftsizes.h ftsizes.h +../../include/freetype/ftsnames.h ftsnames.h +../../include/freetype/ftstroke.h ftstroke.h +../../include/freetype/ftsynth.h ftsynth.h +../../include/freetype/ftsystem.h ftsystem.h +../../include/freetype/ftt1drv.h ftt1drv.h +../../include/freetype/fttrigon.h fttrigon.h +../../include/freetype/ftttdrv.h ftttdrv.h +../../include/freetype/fttypes.h fttypes.h +../../include/freetype/ftwinfnt.h ftwinfnt.h +../../include/freetype/t1tables.h t1tables.h +../../include/freetype/ttnameid.h ttnameid.h +../../include/freetype/tttables.h tttables.h +../../include/freetype/tttags.h tttags.h diff --git a/vendor/freetype/builds/symbian/freetype.mmp b/vendor/freetype/builds/symbian/freetype.mmp new file mode 100644 index 0000000..297678e --- /dev/null +++ b/vendor/freetype/builds/symbian/freetype.mmp @@ -0,0 +1,146 @@ +// +// FreeType 2 makefile for the symbian platform +// + +// Copyright (C) 2008-2023 by +// David Turner, Robert Wilhelm, and Werner Lemberg. +// +// This file is part of the FreeType project, and may only be used, modified, +// and distributed under the terms of the FreeType project license, +// LICENSE.TXT. By continuing to use, modify, or distribute this file you +// indicate that you have read the license and understand and accept it +// fully. + +target freetype.lib +targettype lib + +macro NDEBUG +macro FT2_BUILD_LIBRARY + +sourcepath ..\..\src\autofit + +source autofit.c + +sourcepath ..\..\src\base + +source ftbase.c +source ftbbox.c +source ftbdf.c +source ftbitmap.c +source ftcid.c +source ftfstype.c +source ftgasp.c +source ftglyph.c +source ftgxval.c +source ftinit.c +source ftmm.c +source ftotval.c +source ftpatent.c +source ftpfr.c +source ftstroke.c +source ftsynth.c +source ftsystem.c +source fttype1.c +source ftwinfnt.c + +sourcepath ..\..\src\bdf + +source bdf.c + +sourcepath ..\..\src\bzip2 + +source ftbzip2.c + +sourcepath ..\..\src\cache + +source ftcache.c + +sourcepath ..\..\src\cff + +source cff.c + +sourcepath ..\..\src\cid + +source type1cid.c + +sourcepath ..\..\src\gzip + +source ftgzip.c + +sourcepath ..\..\src\lzw + +source ftlzw.c + +sourcepath ..\..\src\pcf + +source pcf.c + +sourcepath ..\..\src\pfr + +source pfr.c + +sourcepath ..\..\src\psaux + +source psaux.c + +sourcepath ..\..\src\pshinter + +source pshinter.c + +sourcepath ..\..\src\psnames + +source psmodule.c + +sourcepath ..\..\src\raster + +source raster.c + +sourcepath ..\..\src\sfnt + +source sfnt.c + +sourcepath ..\..\src\smooth + +source smooth.c + +sourcepath ..\..\src\truetype + +source truetype.c + +sourcepath ..\..\src\type1 + +source type1.c + +sourcepath ..\..\src\type42 + +source type42.c + +sourcepath ..\..\src\winfonts + +source winfnt.c + + +systeminclude ..\..\include +systeminclude \epoc32\include\stdapis +userinclude ..\..\src\autofit +userinclude ..\..\src\bdf +userinclude ..\..\src\bzip2 +userinclude ..\..\src\cache +userinclude ..\..\src\cff +userinclude ..\..\src\cid +userinclude ..\..\src\gxvalid +userinclude ..\..\src\gzip +userinclude ..\..\src\lzw +userinclude ..\..\src\otvalid +userinclude ..\..\src\pcf +userinclude ..\..\src\pfr +userinclude ..\..\src\psaux +userinclude ..\..\src\pshinter +userinclude ..\..\src\psnames +userinclude ..\..\src\raster +userinclude ..\..\src\sfnt +userinclude ..\..\src\smooth +userinclude ..\..\src\truetype +userinclude ..\..\src\type1 +userinclude ..\..\src\type42 +userinclude ..\..\src\winfonts diff --git a/vendor/freetype/builds/toplevel.mk b/vendor/freetype/builds/toplevel.mk new file mode 100644 index 0000000..8d5063e --- /dev/null +++ b/vendor/freetype/builds/toplevel.mk @@ -0,0 +1,317 @@ +# +# FreeType build system -- top-level sub-Makefile +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# This file is designed for GNU Make, do not use it with another Make tool! +# +# It works as follows: +# +# - When invoked for the first time, this Makefile includes the rules found +# in `PROJECT/builds/detect.mk'. They are in charge of detecting the +# current platform. +# +# A summary of the detection is displayed, and the file `config.mk' is +# created in the current directory. +# +# - When invoked later, this Makefile includes the rules found in +# `config.mk'. This sub-Makefile defines some system-specific variables +# (like compiler, compilation flags, object suffix, etc.), then includes +# the rules found in `PROJECT/builds/PROJECT.mk', used to build the +# library. +# +# See the comments in `builds/detect.mk' and `builds/PROJECT.mk' for more +# details on host platform detection and library builds. + + +# First of all, check whether we have `$(value ...)'. We do this by testing +# for `$(eval ...)' which has been introduced in the same GNU make version. + +eval_available := +$(eval eval_available := T) +ifneq ($(eval_available),T) + $(error FreeType's build system needs a Make program which supports $$(value)) +endif + + +.PHONY: all dist distclean modules setup + + +# The `space' variable is used to avoid trailing spaces in defining the +# `T' variable later. +# +empty := +space := $(empty) $(empty) + + +# The main configuration file, defining the `XXX_MODULES' variables. We +# prefer a `modules.cfg' file in OBJ_DIR over TOP_DIR. +# +ifndef MODULES_CFG + MODULES_CFG := $(TOP_DIR)/modules.cfg + ifneq ($(wildcard $(OBJ_DIR)/modules.cfg),) + MODULES_CFG := $(OBJ_DIR)/modules.cfg + endif +endif + + +# FTMODULE_H, as its name suggests, indicates where the FreeType module +# class file resides. +# +FTMODULE_H ?= $(OBJ_DIR)/ftmodule.h + + +include $(MODULES_CFG) + + +# The list of modules we are using. +# +MODULES := $(FONT_MODULES) \ + $(HINTING_MODULES) \ + $(RASTER_MODULES) \ + $(AUX_MODULES) + + +CONFIG_MK ?= config.mk + +# If no configuration sub-makefile is present, or if `setup' is the target +# to be built, run the auto-detection rules to figure out which +# configuration rules file to use. +# +# Note that the configuration file is put in the current directory, which is +# not necessarily $(TOP_DIR). + +# If `config.mk' is not present, set `check_platform'. +# +ifeq ($(wildcard $(CONFIG_MK)),) + check_platform := 1 +endif + +# If `setup' is one of the targets requested, set `check_platform'. +# +ifneq ($(findstring setup,$(MAKECMDGOALS)),) + check_platform := 1 +endif + + +# Include the automatic host platform detection rules when we need to +# check the platform. +# +ifdef check_platform + + all modules: setup + + include $(TOP_DIR)/builds/detect.mk + + # For builds directly from the git repository we need to copy files + # from `subprojects/dlg' to `src/dlg' and `include/dlg'. + # + ifeq ($(wildcard $(TOP_DIR)/src/dlg/dlg.*),) + ifeq ($(wildcard $(TOP_DIR)/subprojects/dlg/*),) + copy_submodule: check_out_submodule + endif + + setup: copy_submodule + endif + + # This rule makes sense for Unix only to remove files created by a run of + # the configure script which hasn't been successful (so that no + # `config.mk' has been created). It uses the built-in $(RM) command of + # GNU make. Similarly, `nul' is created if e.g. `make setup windows' has + # been erroneously used. + # + # Note: This test is duplicated in `builds/unix/detect.mk'. + # + is_unix := $(strip $(wildcard /sbin/init) \ + $(wildcard /usr/sbin/init) \ + $(wildcard /dev/null) \ + $(wildcard /hurd/auth)) + ifneq ($(is_unix),) + + distclean: + $(RM) $(TOP_DIR)/builds/unix/config.cache + $(RM) $(TOP_DIR)/builds/unix/config.log + $(RM) $(TOP_DIR)/builds/unix/config.status + $(RM) $(TOP_DIR)/builds/unix/unix-def.mk + $(RM) $(TOP_DIR)/builds/unix/unix-cc.mk + $(RM) $(TOP_DIR)/builds/unix/freetype2.pc + $(RM) nul + + endif # test is_unix + + # IMPORTANT: + # + # `setup' must be defined by the host platform detection rules to create + # the `config.mk' file in the current directory. + +else + + # A configuration sub-Makefile is present -- simply run it. + # + all: single + + BUILD_PROJECT := yes + include $(CONFIG_MK) + +endif # test check_platform + + +.PHONY: check_out_submodule copy_submodule + +check_out_submodule: + $(info Checking out submodule in `subprojects/dlg') + git --git-dir=$(TOP_DIR) submodule init + git --git-dir=$(TOP_DIR) submodule update + +copy_submodule: + $(info Copying files from `subprojects/dlg' to `src/dlg' and `include/dlg') + ifeq ($(wildcard $(TOP_DIR)/include/dlg),) + mkdir $(subst /,$(SEP),$(TOP_DIR)/include/dlg) + endif + $(COPY) $(subst /,$(SEP),$(TOP_DIR)/subprojects/dlg/include/dlg/output.h $(TOP_DIR)/include/dlg) + $(COPY) $(subst /,$(SEP),$(TOP_DIR)/subprojects/dlg/include/dlg/dlg.h $(TOP_DIR)/include/dlg) + $(COPY) $(subst /,$(SEP),$(TOP_DIR)/subprojects/dlg/src/dlg/dlg.c $(TOP_DIR)/src/dlg) + + +# We always need the list of modules in ftmodule.h. +# +all setup: $(FTMODULE_H) + + +# The `modules' target unconditionally rebuilds the module list. +# +modules: + $(FTMODULE_H_INIT) + $(FTMODULE_H_CREATE) + $(FTMODULE_H_DONE) + +include $(TOP_DIR)/builds/modules.mk + + +# get FreeType version string using built-in string functions +# +hash := \# + +work := $(strip $(shell $(CAT) \ + $(subst /,$(SEP),$(TOP_DIR)/include/freetype/freetype.h))) + +work := $(subst $(hash)define$(space)FREETYPE_MAJOR$(space),MAjOR=,$(work)) +work := $(subst $(hash)define$(space)FREETYPE_MINOR$(space),MInOR=,$(work)) +work := $(subst $(hash)define$(space)FREETYPE_PATCH$(space),PAtCH=,$(work)) + +major := $(subst MAjOR=,,$(filter MAjOR=%,$(work))) +minor := $(subst MInOR=,,$(filter MInOR=%,$(work))) +patch := $(subst PAtCH=,,$(filter PAtCH=%,$(work))) + +work := + +# ifneq ($(findstring x0x,x$(patch)x),) +# version := $(major).$(minor) +# winversion := $(major)$(minor) +# else + version := $(major).$(minor).$(patch) + winversion := $(major)$(minor)$(patch) + version_tag := VER-$(major)-$(minor)-$(patch) +# endif + + +# This target builds the tarballs. +# +# Not to be run by a normal user -- there are no attempts to make it +# generic. + +dist: + -rm -rf tmp + rm -f freetype-$(version).tar.gz + rm -f freetype-$(version).tar.xz + rm -f ft$(winversion).zip + + for d in `find . -wholename '*/.git' -prune \ + -o -type f \ + -o -print` ; do \ + mkdir -p tmp/$$d ; \ + done ; + + currdir=`pwd` ; \ + for f in `find . -wholename '*/.git' -prune \ + -o -name .gitattributes \ + -o -name .gitignore \ + -o -name .gitlab-ci.yml \ + -o -name .gitmodules \ + -o -name .mailmap \ + -o -type d \ + -o -print` ; do \ + ln -s $$currdir/$$f tmp/$$f ; \ + done + + cd tmp ; \ + $(MAKE) devel ; \ + $(MAKE) do-dist + + mv tmp freetype-$(version) + + tar -H ustar -chf - freetype-$(version) \ + | gzip -9 -c > freetype-$(version).tar.gz + tar -H ustar -chf - freetype-$(version) \ + | xz -c > freetype-$(version).tar.xz + + @# Use CR/LF for zip files. + zip -lr9 ft$(winversion).zip freetype-$(version) + + rm -fr freetype-$(version) + + +# The locations of the latest `config.guess' and `config.sub' versions (from +# GNU `config' git repository), relative to the `tmp' directory used during +# `make dist'. +# +CONFIG_GUESS = ~/git/config/config.guess +CONFIG_SUB = ~/git/config/config.sub + +# We also use this repository to access the gnulib script that converts git +# commit messages to a ChangeLog file. +CHANGELOG_SCRIPT = ~/git/config/gitlog-to-changelog + + +# Don't say `make do-dist'. Always use `make dist' instead. +# +.PHONY: do-dist + +do-dist: distclean refdoc + @# Without removing the files, `autoconf' and friends follow links. + rm -f $(TOP_DIR)/builds/unix/aclocal.m4 + rm -f $(TOP_DIR)/builds/unix/configure.ac + rm -f $(TOP_DIR)/builds/unix/configure + + sh autogen.sh + rm -rf $(TOP_DIR)/builds/unix/autom4te.cache + + cp $(CONFIG_GUESS) $(TOP_DIR)/builds/unix + cp $(CONFIG_SUB) $(TOP_DIR)/builds/unix + + @# Generate `ChangeLog' file with commits since release 2.11.0 + @# (when we stopped creating this file manually). + $(CHANGELOG_SCRIPT) \ + --format='%B%n' \ + --no-cluster \ + -- VER-2-11-0..$(version_tag) \ + > ChangeLog + + @# Remove intermediate files created by the `refdoc' target. + rm -rf $(TOP_DIR)/docs/markdown + rm -f $(TOP_DIR)/docs/mkdocs.yml + + @# Remove more stuff related to git. + rm -rf $(TOP_DIR)/subprojects/dlg + +# EOF diff --git a/vendor/freetype/builds/unix/.gitignore b/vendor/freetype/builds/unix/.gitignore new file mode 100644 index 0000000..f89b226 --- /dev/null +++ b/vendor/freetype/builds/unix/.gitignore @@ -0,0 +1,18 @@ +aclocal.m4 +autom4te.cache +config.cache +config.guess +config.log +config.status +config.sub +configure +configure.ac +freetype2.pc +freetype-config +ftconfig.h +ftoption.h +install-sh +libtool +ltmain.sh +unix-cc.mk +unix-def.mk diff --git a/vendor/freetype/builds/unix/ax_compare_version.m4 b/vendor/freetype/builds/unix/ax_compare_version.m4 new file mode 100644 index 0000000..ffb4997 --- /dev/null +++ b/vendor/freetype/builds/unix/ax_compare_version.m4 @@ -0,0 +1,177 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compare_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# This macro compares two version strings. Due to the various number of +# minor-version numbers that can exist, and the fact that string +# comparisons are not compatible with numeric comparisons, this is not +# necessarily trivial to do in a autoconf script. This macro makes doing +# these comparisons easy. +# +# The six basic comparisons are available, as well as checking equality +# limited to a certain number of minor-version levels. +# +# The operator OP determines what type of comparison to do, and can be one +# of: +# +# eq - equal (test A == B) +# ne - not equal (test A != B) +# le - less than or equal (test A <= B) +# ge - greater than or equal (test A >= B) +# lt - less than (test A < B) +# gt - greater than (test A > B) +# +# Additionally, the eq and ne operator can have a number after it to limit +# the test to that number of minor versions. +# +# eq0 - equal up to the length of the shorter version +# ne0 - not equal up to the length of the shorter version +# eqN - equal up to N sub-version levels +# neN - not equal up to N sub-version levels +# +# When the condition is true, shell commands ACTION-IF-TRUE are run, +# otherwise shell commands ACTION-IF-FALSE are run. The environment +# variable 'ax_compare_version' is always set to either 'true' or 'false' +# as well. +# +# Examples: +# +# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) +# +# would both be true. +# +# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) +# +# would both be false. +# +# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) +# +# would be true because it is only comparing two minor versions. +# +# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) +# +# would be true because it is only comparing the lesser number of minor +# versions of the two values. +# +# Note: The characters that separate the version numbers do not matter. An +# empty string is the same as version 0. OP is evaluated by autoconf, not +# configure, so must be a string, not a variable. +# +# The author would like to acknowledge Guido Draheim whose advice about +# the m4_case and m4_ifvaln functions make this macro only include the +# portions necessary to perform the specific comparison specified by the +# OP argument in the final configure script. +# +# LICENSE +# +# Copyright (c) 2008 Tim Toolan +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +dnl ######################################################################### +AC_DEFUN([AX_COMPARE_VERSION], [ + AC_REQUIRE([AC_PROG_AWK]) + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + AS_VAR_PUSHDEF([A],[ax_compare_version_A]) + A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + AS_VAR_PUSHDEF([B],[ax_compare_version_B]) + B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary + dnl # then the first line is used to determine if the condition is true. + dnl # The sed right after the echo is to remove any indented white space. + m4_case(m4_tolower($2), + [lt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [gt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [le],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ], + [ge],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ],[ + dnl Split the operator from the subversion count if present. + m4_bmatch(m4_substr($2,2), + [0],[ + # A count of zero means use the length of the shorter version. + # Determine the number of characters in A and B. + ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` + ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` + + # Set A to no more than B's length and B to no more than A's length. + A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` + B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` + ], + [[0-9]+],[ + # A count greater than zero means use only that many subversions + A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + ], + [.+],[ + AC_WARNING( + [invalid OP numeric parameter: $2]) + ],[]) + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" + B="$B`echo $A | sed 's/./0/g'`" + A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + m4_case(m4_tolower(m4_substr($2,0,2)), + [eq],[ + test "x$A" = "x$B" && ax_compare_version=true + ], + [ne],[ + test "x$A" != "x$B" && ax_compare_version=true + ],[ + AC_WARNING([invalid OP parameter: $2]) + ]) + ]) + + AS_VAR_POPDEF([A])dnl + AS_VAR_POPDEF([B])dnl + + dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. + if test "$ax_compare_version" = "true" ; then + m4_ifvaln([$4],[$4],[:])dnl + m4_ifvaln([$5],[else $5])dnl + fi +]) dnl AX_COMPARE_VERSION diff --git a/vendor/freetype/builds/unix/ax_prog_python_version.m4 b/vendor/freetype/builds/unix/ax_prog_python_version.m4 new file mode 100644 index 0000000..dbc3dbf --- /dev/null +++ b/vendor/freetype/builds/unix/ax_prog_python_version.m4 @@ -0,0 +1,66 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_prog_python_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_PYTHON_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# Makes sure that python supports the version indicated. If true the shell +# commands in ACTION-IF-TRUE are executed. If not the shell commands in +# ACTION-IF-FALSE are run. Note if $PYTHON is not set (for example by +# running AC_CHECK_PROG or AC_PATH_PROG) the macro will fail. +# +# Example: +# +# AC_PATH_PROG([PYTHON],[python]) +# AX_PROG_PYTHON_VERSION([2.4.4],[ ... ],[ ... ]) +# +# This will check to make sure that the python you have supports at least +# version 2.4.4. +# +# NOTE: This macro uses the $PYTHON variable to perform the check. +# AX_WITH_PYTHON can be used to set that variable prior to running this +# macro. The $PYTHON_VERSION variable will be valorized with the detected +# version. +# +# LICENSE +# +# Copyright (c) 2009 Francesco Salvestrini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 12 + +AC_DEFUN([AX_PROG_PYTHON_VERSION],[ + AC_REQUIRE([AC_PROG_SED]) + AC_REQUIRE([AC_PROG_GREP]) + + AS_IF([test -n "$PYTHON"],[ + ax_python_version="$1" + + AC_MSG_CHECKING([for python version]) + changequote(<<,>>) + python_version=`$PYTHON -V 2>&1 | $GREP "^Python " | $SED -e 's/^.* \([0-9]*\.[0-9]*\.[0-9]*\)/\1/'` + changequote([,]) + AC_MSG_RESULT($python_version) + + AC_SUBST([PYTHON_VERSION],[$python_version]) + + AX_COMPARE_VERSION([$ax_python_version],[le],[$python_version],[ + : + $2 + ],[ + : + $3 + ]) + ],[ + AC_MSG_WARN([could not find the python interpreter]) + $3 + ]) +]) diff --git a/vendor/freetype/builds/unix/ax_pthread.m4 b/vendor/freetype/builds/unix/ax_pthread.m4 new file mode 100644 index 0000000..e5858e5 --- /dev/null +++ b/vendor/freetype/builds/unix/ax_pthread.m4 @@ -0,0 +1,522 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is +# needed for multi-threaded programs (defaults to the value of CC +# respectively CXX otherwise). (This is necessary on e.g. AIX to use the +# special cc_r/CC_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also to link with them as well. For example, you might link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threaded programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# CXX="$PTHREAD_CXX" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. +# Copyright (c) 2019 Marc Stevens +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 30 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_TARGET]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items with a "," contain both +# C compiler flags (before ",") and linker flags (after ","). Other items +# starting with a "-" are C compiler flags, and remaining items are +# library names, except for "none" which indicates that we try without +# any flags at all, and "pthread-config" which is a program returning +# the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $target_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" + ;; +esac + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +# Note that for GCC and Clang -pthread generally implies -lpthread, +# except when -nostdlib is passed. +# This is problematic using libtool to build C++ shared libraries with pthread: +# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 +# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 +# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 +# To solve this, first try -pthread together with -lpthread for GCC + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"]) + +# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first + +AS_IF([test "x$ax_pthread_clang" = "xyes"], + [ax_pthread_flags="-pthread,-lpthread -pthread"]) + + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $target_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + *,*) + PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` + PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` + AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void *some_global = NULL; + static void routine(void *a) + { + /* To avoid any unused-parameter or + unused-but-set-parameter warning. */ + some_global = a; + } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + + + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $target_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT; + return i;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $target_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [ + AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"]) + AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])]) + ], + [ + AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC]) + AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])]) + ] + ) + ]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" +test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) +AC_SUBST([PTHREAD_CXX]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff --git a/vendor/freetype/builds/unix/configure.raw b/vendor/freetype/builds/unix/configure.raw new file mode 100644 index 0000000..dc7426e --- /dev/null +++ b/vendor/freetype/builds/unix/configure.raw @@ -0,0 +1,1179 @@ +# This file is part of the FreeType project. +# +# Process this file with autoconf to produce a configure script. +# +# Copyright (C) 2001-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +AC_INIT([FreeType], [@VERSION@], [freetype@nongnu.org], [freetype]) +AC_CONFIG_SRCDIR([ftconfig.h.in]) + + +# Don't forget to update `docs/VERSIONS.TXT'! + +version_info='26:1:20' +AC_SUBST([version_info]) +ft_version=`echo $version_info | tr : .` +AC_SUBST([ft_version]) + + +# checks for system type + +AC_CANONICAL_HOST + + +# checks for programs + +AC_PROG_CC +AC_PROG_CPP +AC_SUBST(EXEEXT) + +PKG_PROG_PKG_CONFIG([0.24]) + +LT_INIT(win32-dll) +AC_CHECK_HEADER([windows.h], [LT_PROG_RC]) + + +# checks for native programs to generate building tool + +if test ${cross_compiling} = yes; then + AC_CHECK_PROG(CC_BUILD, ${build}-gcc, ${build}-gcc) + test -z "${CC_BUILD}" && AC_CHECK_PROG(CC_BUILD, gcc, gcc) + test -z "${CC_BUILD}" && AC_CHECK_PROG(CC_BUILD, cc, cc, , , /usr/ucb/cc) + test -z "${CC_BUILD}" && AC_MSG_ERROR([cannot find native C compiler]) + + AC_MSG_CHECKING([for suffix of native executables]) + rm -f a.* b.* a_out.exe conftest.* + echo > conftest.c "int main(void) { return 0;}" + ${CC_BUILD} conftest.c || AC_MSG_ERROR([native C compiler is not working]) + rm -f conftest.c + if test -x a.out -o -x b.out -o -x conftest; then + EXEEXT_BUILD="" + elif test -x a_out.exe -o -x conftest.exe; then + EXEEXT_BUILD=".exe" + elif test -x conftest.*; then + EXEEXT_BUILD=`echo conftest.* | sed -n '1s/^.*\././'` + fi + rm -f a.* b.* a_out.exe conftest.* + AC_MSG_RESULT($EXEEXT_BUILD) +else + CC_BUILD=${CC} + EXEEXT_BUILD=${EXEEXT} +fi + +AC_SUBST(CC_BUILD) +AC_SUBST(EXEEXT_BUILD) + + +# Since these files will be eventually called from another directory (namely +# from the top level) we make the path of the scripts absolute. +# +# This small code snippet has been taken from automake's `ylwrap' script. + +AC_PROG_INSTALL +case "$INSTALL" in +[[\\/]]* | ?:[[\\/]]*) + ;; +*[[\\/]]*) + INSTALL="`pwd`/$INSTALL" + ;; +esac + +AC_PROG_MKDIR_P +case "$MKDIR_P" in +[[\\/]]* | ?:[[\\/]]*) + ;; +*[[\\/]]*) + MKDIR_P="`pwd`/$MKDIR_P" + ;; +esac + + +# checks for header files + +AC_CHECK_HEADERS([fcntl.h unistd.h]) + + +# checks for typedefs, structures, and compiler characteristics + +AC_C_CONST + +AC_ARG_ENABLE([freetype-config], + AS_HELP_STRING([--enable-freetype-config], [install freetype-config]), + [case "${enableval}" in + yes) enable_freetype_config="TRUE" ;; + no) enable_freetype_config="FALSE" ;; + *) AC_MSG_ERROR([unknown value '${enableval}' passed with --enable-freetype-config]) ;; + esac], [enable_freetype_config="FALSE"]) + +AC_SUBST(INSTALL_FT2_CONFIG, [$enable_freetype_config]) + +# checks for library functions + +AC_SYS_LARGEFILE + +# Here we check whether we can use our mmap file component. +# +# Note that `ftsystem.c` for Windows has its own mmap-like implementation +# not covered by `AC_FUNC_MMAP` and/or `FT_UNMAP_PARAM`. + +AC_ARG_ENABLE([mmap], + AS_HELP_STRING([--disable-mmap], + [do not check mmap() and do not use]), + [enable_mmap="no"], [enable_mmap="yes"]) +if test "x${enable_mmap}" != "xno"; then + case "$host" in + *-*-mingw*) + AC_MSG_CHECKING([for working mmap]) + AC_MSG_RESULT([using MapViewOfFile in Windows]) + FTSYS_SRC='$(TOP_DIR)/builds/windows/ftsystem.c' + ;; + *) + AC_FUNC_MMAP + if test "$ac_cv_func_mmap_fixed_mapped" = "yes"; then + FTSYS_SRC='$(PLATFORM_DIR)/ftsystem.c' + + AC_CHECK_DECLS([munmap], + [], + [], + [ + +#ifdef HAVE_UNISTD_H +#include +#endif +#include + + ]) + + FT_MUNMAP_PARAM + fi + ;; + esac +fi + +if test -z "$FTSYS_SRC"; then + FTSYS_SRC='$(BASE_DIR)/ftsystem.c' +fi +AC_SUBST([FTSYS_SRC]) + + +# get compiler flags right +# +# We try to make the compiler work for C99-strict source. Even if the +# C compiler is gcc and C99 flags are available, some system headers +# might be broken in C99 mode. We have to check whether compilation +# finishes successfully. +# +if test "x$GCC" = xyes; then + XX_CFLAGS="-Wall" + case "$host" in + *-*-mingw*) + XX_ANSIFLAGS="-pedantic" + ;; + *-*-aix*) + XX_ANSIFLAGS="-pedantic" + ;; + *) + XX_ANSIFLAGS="" + + for a in "-pedantic" "-std=c99" + do + AC_MSG_CHECKING([$CC compiler flag ${a} to assure ANSI C99 works correctly]) + orig_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} ${XX_ANSIFLAGS} ${a}" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + +#include + + ], + [ + + { + puts( "" ); + return 0; + } + + ])], + [AC_MSG_RESULT([ok, adding to XX_ANSIFLAGS]) + XX_ANSIFLAGS="${XX_ANSIFLAGS} ${a}" + ], + [AC_MSG_RESULT([no])]) + CFLAGS="${orig_CFLAGS}" + done + ;; + esac +else + case "$host" in + *-dec-osf*) + CFLAGS= + XX_CFLAGS="-std1 -g3" + XX_ANSIFLAGS= + ;; + *) + XX_CFLAGS= + XX_ANSIFLAGS= + ;; + esac +fi +AC_SUBST([XX_CFLAGS]) +AC_SUBST([XX_ANSIFLAGS]) + + +# It is recommended that shared libraries hide symbols except those with +# explicit __attribute__((visibility("default"))). +# +found_visibility_flag=no +AC_MSG_CHECKING([for -fvisibility=hidden compiler flag]) +orig_CFLAGS="${CFLAGS}" +CFLAGS="${CFLAGS} -fvisibility=hidden" +AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], + [found_visibility_flag=yes + AC_MSG_RESULT(yes)], + [CFLAGS="${orig_CFLAGS}" + AC_MSG_RESULT(no)]) + +if test "${found_visibility_flag}" = "no"; then + AC_MSG_CHECKING([for -xldscope=hidden compiler flag]) + orig_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} -xldscope=hidden" + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], + [found_visibility_flag=yes + AC_MSG_RESULT(yes)], + [CFLAGS="${orig_CFLAGS}" + AC_MSG_RESULT(no)]) +fi + +# All library tests below try `pkg-config' first. If that fails, a function +# from the library is tested in the traditional autoconf way (zlib, bzip2), +# or a config script is called (libpng). +# +# The `xxx_reqpriv' variables are for the `Requires.private' field in +# `freetype2.pc'. The `xxx_libspriv' variables are for the `Libs.private' +# field in `freetype2.pc' if pkg-config doesn't find a proper .pc file. +# +# The `xxx_libsstaticconf' variables are for the `freetype-config' script. +# +# Note that a call to PKG_CHECK_MODULES(XXX, ...) sets and creates the +# output variables `XXX_CFLAGS' and `XXX_LIBS'. In case one or both are set +# for a library by the user, no entry for this library is added to +# `Requires.private'. Instead, it gets added to `Libs.private' + + +# check for system zlib + +AC_ARG_WITH([zlib], + [AS_HELP_STRING([--with-zlib=@<:@yes|no|auto@:>@], + [use system zlib instead of internal library @<:@default=auto@:>@])], + [], [with_zlib=auto]) + +have_zlib=no +if test x"$with_zlib" = xyes -o x"$with_zlib" = xauto; then + zlib_pkg="zlib" + have_zlib_pkg=no + + if test x"$ZLIB_CFLAGS" = x -a x"$ZLIB_LIBS" = x; then + PKG_CHECK_EXISTS([$zlib_pkg], [have_zlib_pkg=yes]) + fi + PKG_CHECK_MODULES([ZLIB], [$zlib_pkg], + [have_zlib="yes (pkg-config)"], [:]) + + if test $have_zlib_pkg = yes; then + # we have zlib.pc + zlib_reqpriv="$zlib_pkg" + zlib_libspriv= + zlib_libsstaticconf=`$PKG_CONFIG --static --libs "$zlib_pkg"` + else + zlib_reqpriv= + + if test "$have_zlib" != no; then + # ZLIB_CFLAGS and ZLIB_LIBS are set by the user + zlib_libspriv="$ZLIB_LIBS" + zlib_libsstaticconf="$ZLIB_LIBS" + have_zlib="yes (ZLIB_CFLAGS and ZLIB_LIBS)" + else + # fall back to standard autoconf test + AC_CHECK_LIB([z], + [gzsetparams], + [AC_CHECK_HEADER([zlib.h], + [have_zlib="yes (autoconf test)" + zlib_libspriv="-lz" + zlib_libsstaticconf="$zlib_libspriv" + ZLIB_LIBS="$zlib_libspriv"])]) + fi + fi +fi + +if test x"$with_zlib" = xyes -a "$have_zlib" = no; then + AC_MSG_ERROR([external zlib support requested but library not found]) +fi + +SYSTEM_ZLIB= +if test "$have_zlib" != no; then + SYSTEM_ZLIB=yes +fi +AC_SUBST([SYSTEM_ZLIB]) + + +# check for system libbz2 + +AC_ARG_WITH([bzip2], + [AS_HELP_STRING([--with-bzip2=@<:@yes|no|auto@:>@], + [support bzip2 compressed fonts @<:@default=auto@:>@])], + [], [with_bzip2=auto]) + +have_bzip2=no +if test x"$with_bzip2" = xyes -o x"$with_bzip2" = xauto; then + bzip2_pkg="bzip2" + have_bzip2_pkg=no + + if test x"$BZIP2_CFLAGS" = x -a x"$BZIP2_LIBS" = x; then + PKG_CHECK_EXISTS([$bzip2_pkg], [have_bzip2_pkg=yes]) + fi + PKG_CHECK_MODULES([BZIP2], [$bzip2_pkg], + [have_bzip2="yes (pkg-config)"], [:]) + + if test $have_bzip2_pkg = yes; then + # we have bzip2.pc + bzip2_reqpriv="$bzip2_pkg" + bzip2_libspriv= + bzip2_libsstaticconf=`$PKG_CONFIG --static --libs "$bzip2_pkg"` + else + bzip2_reqpriv= + + if test "$have_bzip2" != no; then + # BZIP2_CFLAGS and BZIP2_LIBS are set by the user + bzip2_libspriv="$BZIP2_LIBS" + bzip2_libsstaticconf="$BZIP2_LIBS" + have_bzip2="yes (BZIP2_CFLAGS and BZIP2_LIBS)" + else + # fall back to standard autoconf test + AC_CHECK_LIB([bz2], + [BZ2_bzDecompress], + [AC_CHECK_HEADER([bzlib.h], + [have_bzip2="yes (autoconf test)" + bzip2_libspriv="-lbz2" + bzip2_libsstaticconf="$bzip2_libspriv" + BZIP2_LIBS="$bzip2_libspriv"])]) + fi + fi +fi + +if test x"$with_bzip2" = xyes -a "$have_bzip2" = no; then + AC_MSG_ERROR([bzip2 support requested but library not found]) +fi + + +# check for system libpng + +AC_ARG_WITH([png], + [AS_HELP_STRING([--with-png=@<:@yes|no|auto@:>@], + [support png compressed OpenType embedded bitmaps @<:@default=auto@:>@])], + [], [with_png=auto]) + +have_libpng=no +if test x"$with_png" = xyes -o x"$with_png" = xauto; then + libpng_pkg="libpng" + have_libpng_pkg=no + + if test x"$LIBPNG_CFLAGS" = x -a x"$LIBPNG_LIBS" = x; then + PKG_CHECK_EXISTS([$libpng_pkg], [have_libpng_pkg=yes]) + fi + PKG_CHECK_MODULES([LIBPNG], [$libpng_pkg], + [have_libpng="yes (pkg-config)"], [:]) + + if test $have_libpng_pkg = yes; then + # we have libpng.pc + libpng_reqpriv="$libpng_pkg" + libpng_libspriv= + libpng_libsstaticconf=`$PKG_CONFIG --static --libs "$libpng_pkg"` + else + libpng_reqpriv= + + if test "$have_libpng" != no; then + # LIBPNG_CFLAGS and LIBPNG_LIBS are set by the user + libpng_libspriv="$LIBPNG_LIBS" + libpng_libsstaticconf="$LIBPNG_LIBS" + have_libpng="yes (LIBPNG_CFLAGS and LIBPNG_LIBS)" + else + # fall back to config script + AC_CHECK_PROG(have_libpng, [libpng-config], [yes (libpng-config)], [no]) + if test "$have_libpng" != no; then + LIBPNG_CFLAGS=`libpng-config --cflags` + LIBPNG_LIBS=`libpng-config --ldflags` + libpng_libspriv=`libpng-config --static --ldflags` + libpng_libsstaticconf="$libpng_libspriv" + fi + fi + fi +fi + +if test x"$with_png" = xyes -a "$have_libpng" = no; then + AC_MSG_ERROR([libpng support requested but library not found]) +fi + + +# check for system libharfbuzz + +AC_ARG_WITH([harfbuzz], + [AS_HELP_STRING([--with-harfbuzz=@<:@yes|no|auto@:>@], + [improve auto-hinting of OpenType fonts @<:@default=auto@:>@])], + [], [with_harfbuzz=auto]) + +have_harfbuzz=no +if test x"$with_harfbuzz" = xyes -o x"$with_harfbuzz" = xauto; then + harfbuzz_pkg="harfbuzz >= 2.0.0" + have_harfbuzz_pkg=no + + if test x"$HARFBUZZ_CFLAGS" = x -a x"$HARFBUZZ_LIBS" = x; then + PKG_CHECK_EXISTS([$harfbuzz_pkg], [have_harfbuzz_pkg=yes]) + fi + PKG_CHECK_MODULES([HARFBUZZ], [$harfbuzz_pkg], + [have_harfbuzz="yes (pkg-config)"], [:]) + + if test $have_harfbuzz_pkg = yes; then + # we have harfbuzz.pc + harfbuzz_reqpriv="$harfbuzz_pkg" + harfbuzz_libspriv= + harfbuzz_libsstaticconf=`$PKG_CONFIG --static --libs "$harfbuzz_pkg"` + else + harfbuzz_reqpriv= + + if test "$have_harfbuzz" != no; then + # HARFBUZZ_CFLAGS and HARFBUZZ_LIBS are set by the user + harfbuzz_libspriv="$HARFBUZZ_LIBS" + harfbuzz_libsstaticconf="$HARFBUZZ_LIBS" + have_harfbuzz="yes (HARFBUZZ_CFLAGS and HARFBUZZ_LIBS)" + else + # since HarfBuzz is quite a new library we don't fall back to a + # different test; additionally, it has too many dependencies + : + fi + fi +fi + +if test x"$with_harfbuzz" = xyes -a "$have_harfbuzz" = no; then + AC_MSG_ERROR([harfbuzz support requested but library not found]) +fi + + +# check for system libbrotlidec + +AC_ARG_WITH([brotli], + [AS_HELP_STRING([--with-brotli=@<:@yes|no|auto@:>@], + [support decompression of WOFF2 streams @<:@default=auto@:>@])], + [], [with_brotli=auto]) + +have_brotli=no +if test x"$with_brotli" = xyes -o x"$with_brotli" = xauto; then + brotli_pkg="libbrotlidec" + have_brotli_pkg=no + + if test x"$BROTLI_CFLAGS" = x -a x"$BROTLI_LIBS" = x; then + PKG_CHECK_EXISTS([$brotli_pkg], [have_brotli_pkg=yes]) + fi + PKG_CHECK_MODULES([BROTLI], [$brotli_pkg], + [have_brotli="yes (pkg-config)"], [:]) + + if test $have_brotli_pkg = yes; then + # we have libbrotlidec.pc + brotli_reqpriv="$brotli_pkg" + brotli_libspriv= + brotli_libsstaticconf=`$PKG_CONFIG --static --libs "$brotli_pkg"` + else + brotli_reqpriv= + + if test "$have_brotli" != no; then + # BROTLI_CFLAGS and BROTLI_LIBS are set by the user + brotli_libspriv="$BROTLI_LIBS" + brotli_libsstaticconf="$BROTLI_LIBS" + have_brotli="yes (BROTLI_CFLAGS and BROTLI_LIBS)" + else + # since Brotli is quite a new library we don't fall back to a + # different test + : + fi + fi +fi + +if test x"$with_brotli" = xyes -a "$have_brotli" = no; then + AC_MSG_ERROR([brotli support requested but library not found]) +fi + + +# Checks for the demo programs. +# +# FreeType doesn't need this. However, since the demo program repository +# doesn't come with a `configure` script of its own, we integrate the tests +# here for simplicity. + +# We need `clock_gettime` from 'librt' for the `ftbench` demo program. +# +# The code is modeled after gnulib's file `clock_time.m4`, ignoring +# very old Solaris systems. +LIB_CLOCK_GETTIME= +AC_SEARCH_LIBS([clock_gettime], + [rt], + [test "$ac_cv_search_clock_gettime" = "none required" \ + || LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime]) + +FT_DEMO_CFLAGS="" +FT_DEMO_LDFLAGS="$LIB_CLOCK_GETTIME" + +# 'librsvg' is needed to demonstrate SVG support. +AC_ARG_WITH([librsvg], + [AS_HELP_STRING([--with-librsvg=@<:@yes|no|auto@:>@], + [support OpenType SVG fonts in FreeType demo programs @<:@default=auto@:>@])], + [], [with_librsvg=auto]) + +have_librsvg=no +if test x"$with_librsvg" = xyes -o x"$with_librsvg" = xauto; then + PKG_CHECK_MODULES([LIBRSVG], [librsvg-2.0 >= 2.46.0], + [have_librsvg="yes (pkg-config)"], [:]) + + if test "$have_librsvg" != no; then + FT_DEMO_CFLAGS="$FT_DEMO_CFLAGS $LIBRSVG_CFLAGS -DHAVE_LIBRSVG" + FT_DEMO_LDFLAGS="$FT_DEMO_LDFLAGS $LIBRSVG_LIBS" + fi +fi + +if test x"$with_librsvg" = xyes -a "$have_librsvg" = no; then + AC_MSG_ERROR([librsvg support requested but library not found]) +fi + +AC_SUBST([FT_DEMO_CFLAGS]) +AC_SUBST([FT_DEMO_LDFLAGS]) + + +# Some options handling SDKs/archs in CFLAGS should be copied +# to LDFLAGS. Apple TechNote 2137 recommends to include these +# options in CFLAGS but not in LDFLAGS. + +save_config_args=$* +set dummy ${CFLAGS} +i=1 +while test $i -le $# +do + c=$1 + + case "${c}" in + -isysroot|-arch) # options taking 1 argument + a=$2 + AC_MSG_CHECKING([whether CFLAGS and LDFLAGS share ${c} ${a}]) + if expr " ${LDFLAGS} " : ".* ${c} *${a}.*" > /dev/null + then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no, copy to LDFLAGS]) + LDFLAGS="${LDFLAGS} ${c} ${a}" + fi + shift 1 + ;; + -m32|-m64|-march=*|-mcpu=*) # options taking no argument + AC_MSG_CHECKING([whether CFLAGS and LDFLAGS share ${c}]) + if expr " ${LDFLAGS} " : ".* ${c} *${a}.*" > /dev/null + then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no, copy to LDFLAGS]) + LDFLAGS="${LDFLAGS} ${c}" + fi + ;; + # *) + # AC_MSG_RESULT([${c} is not copied to LDFLAGS]) + # ;; + esac + + shift 1 +done +set ${save_config_args} + + +# Whether to use Mac OS resource-based fonts. + +ftmac_c="" # src/base/ftmac.c should not be included in makefiles by default + +AC_ARG_WITH([old-mac-fonts], + AS_HELP_STRING([--with-old-mac-fonts], + [allow Mac resource-based fonts to be used])) +if test x$with_old_mac_fonts = xyes; then + orig_LDFLAGS="${LDFLAGS}" + AC_MSG_CHECKING([CoreServices & ApplicationServices of Mac OS X]) + ft2_extra_libs="-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices" + LDFLAGS="$LDFLAGS $ft2_extra_libs" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +#endif + + ], + [ + + short res = 0; + + + UseResFile( res ); + + ])], + [AC_MSG_RESULT([ok]) + ftmac_c='ftmac.c' + AC_MSG_CHECKING([whether OS_INLINE macro is ANSI compatible]) + orig_CFLAGS="$CFLAGS -DFT_MACINTOSH" + CFLAGS="$CFLAGS $XX_CFLAGS $XX_ANSIFLAGS" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +#endif + + ], + [ + + /* OSHostByteOrder() is typed as OS_INLINE */ + int32_t os_byte_order = OSHostByteOrder(); + + + if ( OSBigEndian != os_byte_order ) + return 1; + + ])], + [AC_MSG_RESULT([ok]) + CFLAGS="$orig_CFLAGS" + CFLAGS="$CFLAGS -DHAVE_ANSI_OS_INLINE=1" + ], + [AC_MSG_RESULT([no, ANSI incompatible]) + CFLAGS="$orig_CFLAGS" + ]) + AC_MSG_CHECKING([type ResourceIndex]) + orig_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $XX_CFLAGS $XX_ANSIFLAGS" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +# include +#endif + + ], + [ + + ResourceIndex i = 0; + return i; + + ])], + [AC_MSG_RESULT([ok]) + CFLAGS="$orig_CFLAGS" + CFLAGS="$CFLAGS -DHAVE_TYPE_RESOURCE_INDEX=1" + ], + [AC_MSG_RESULT([no]) + CFLAGS="$orig_CFLAGS" + CFLAGS="$CFLAGS -DHAVE_TYPE_RESOURCE_INDEX=0" + ])], + [AC_MSG_RESULT([not found]) + ft2_extra_libs="" + LDFLAGS="${orig_LDFLAGS}" + CFLAGS="$CFLAGS -DDARWIN_NO_CARBON"]) +else + case x$host_os in + xdarwin*) + dnl AC_MSG_WARN([host system is MacOS but configured to build without Carbon]) + CFLAGS="$CFLAGS -DDARWIN_NO_CARBON" + ;; + *) + ;; + esac +fi + + +# Whether to use FileManager, which is deprecated since Mac OS X 10.4. + +AC_ARG_WITH([fsspec], + AS_HELP_STRING([--with-fsspec], + [use obsolete FSSpec API of MacOS, if available (default=yes)])) +if test x$with_fsspec = xno; then + CFLAGS="$CFLAGS -DHAVE_FSSPEC=0" +elif test x$with_old_mac_fonts = xyes -a x$with_fsspec != x; then + AC_MSG_CHECKING([FSSpec-based FileManager]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +#endif + + ], + [ + + FCBPBPtr paramBlock; + short vRefNum; + long dirID; + ConstStr255Param fileName; + FSSpec* spec; + + + /* FSSpec functions: deprecated since Mac OS X 10.4 */ + PBGetFCBInfoSync( paramBlock ); + FSMakeFSSpec( vRefNum, dirID, fileName, spec ); + + ])], + [AC_MSG_RESULT([ok]) + CFLAGS="$CFLAGS -DHAVE_FSSPEC=1"], + [AC_MSG_RESULT([not found]) + CFLAGS="$CFLAGS -DHAVE_FSSPEC=0"]) +fi + + +# Whether to use FileManager in Carbon since MacOS 9.x. + +AC_ARG_WITH([fsref], + AS_HELP_STRING([--with-fsref], + [use Carbon FSRef API of MacOS, if available (default=yes)])) +if test x$with_fsref = xno; then + AC_MSG_WARN([ +*** WARNING + FreeType2 built without FSRef API cannot load + data-fork fonts on MacOS, except of XXX.dfont. + ]) + CFLAGS="$CFLAGS -DHAVE_FSREF=0" +elif test x$with_old_mac_fonts = xyes -a x$with_fsref != x; then + AC_MSG_CHECKING([FSRef-based FileManager]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +#endif + + ], + [ + + short vRefNum; + long dirID; + ConstStr255Param fileName; + + Boolean* isDirectory; + UInt8* path; + SInt16 desiredRefNum; + SInt16* iterator; + SInt16* actualRefNum; + HFSUniStr255* outForkName; + FSVolumeRefNum volume; + FSCatalogInfoBitmap whichInfo; + FSCatalogInfo* catalogInfo; + FSForkInfo* forkInfo; + FSRef* ref; + +#if HAVE_FSSPEC + FSSpec* spec; +#endif + + /* FSRef functions: no need to check? */ + FSGetForkCBInfo( desiredRefNum, volume, iterator, + actualRefNum, forkInfo, ref, + outForkName ); + FSPathMakeRef( path, ref, isDirectory ); + +#if HAVE_FSSPEC + FSpMakeFSRef ( spec, ref ); + FSGetCatalogInfo( ref, whichInfo, catalogInfo, + outForkName, spec, ref ); +#endif + ])], + [AC_MSG_RESULT([ok]) + CFLAGS="$CFLAGS -DHAVE_FSREF=1"], + [AC_MSG_RESULT([not found]) + CFLAGS="$CFLAGS -DHAVE_FSREF=0"]) +fi + + +# Whether to use QuickDraw API in ToolBox, which is deprecated since +# Mac OS X 10.4. + +AC_ARG_WITH([quickdraw-toolbox], + AS_HELP_STRING([--with-quickdraw-toolbox], + [use MacOS QuickDraw in ToolBox, if available (default=yes)])) +if test x$with_quickdraw_toolbox = xno; then + CFLAGS="$CFLAGS -DHAVE_QUICKDRAW_TOOLBOX=0" +elif test x$with_old_mac_fonts = xyes -a x$with_quickdraw_toolbox != x; then + AC_MSG_CHECKING([QuickDraw FontManager functions in ToolBox]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +#endif + + ], + [ + + Str255 familyName; + SInt16 familyID = 0; + FMInput* fmIn = NULL; + FMOutput* fmOut = NULL; + + + GetFontName( familyID, familyName ); + GetFNum( familyName, &familyID ); + fmOut = FMSwapFont( fmIn ); + + ])], + [AC_MSG_RESULT([ok]) + CFLAGS="$CFLAGS -DHAVE_QUICKDRAW_TOOLBOX=1"], + [AC_MSG_RESULT([not found]) + CFLAGS="$CFLAGS -DHAVE_QUICKDRAW_TOOLBOX=0"]) +fi + + +# Whether to use QuickDraw API in Carbon, which is deprecated since +# Mac OS X 10.4. + +AC_ARG_WITH([quickdraw-carbon], + AS_HELP_STRING([--with-quickdraw-carbon], + [use MacOS QuickDraw in Carbon, if available (default=yes)])) +if test x$with_quickdraw_carbon = xno; then + CFLAGS="$CFLAGS -DHAVE_QUICKDRAW_CARBON=0" +elif test x$with_old_mac_fonts = xyes -a x$with_quickdraw_carbon != x; then + AC_MSG_CHECKING([QuickDraw FontManager functions in Carbon]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +#endif + + ], + [ + + FMFontFamilyIterator famIter; + FMFontFamily family; + Str255 famNameStr; + FMFontFamilyInstanceIterator instIter; + FMFontStyle style; + FMFontSize size; + FMFont font; + FSSpec* pathSpec; + + + FMCreateFontFamilyIterator( NULL, NULL, kFMUseGlobalScopeOption, + &famIter ); + FMGetNextFontFamily( &famIter, &family ); + FMGetFontFamilyName( family, famNameStr ); + FMCreateFontFamilyInstanceIterator( family, &instIter ); + FMGetNextFontFamilyInstance( &instIter, &font, &style, &size ); + FMDisposeFontFamilyInstanceIterator( &instIter ); + FMDisposeFontFamilyIterator( &famIter ); + FMGetFontContainer( font, pathSpec ); + + ])], + [AC_MSG_RESULT([ok]) + CFLAGS="$CFLAGS -DHAVE_QUICKDRAW_CARBON=1"], + [AC_MSG_RESULT([not found]) + CFLAGS="$CFLAGS -DHAVE_QUICKDRAW_CARBON=0"]) +fi + + +# Whether to use AppleTypeService since Mac OS X. + +AC_ARG_WITH([ats], + AS_HELP_STRING([--with-ats], + [use AppleTypeService, if available (default=yes)])) +if test x$with_ats = xno; then + CFLAGS="$CFLAGS -DHAVE_ATS=0" +elif test x$with_old_mac_fonts = xyes -a x$with_ats != x; then + AC_MSG_CHECKING([AppleTypeService functions]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + +#if defined(__GNUC__) && defined(__APPLE_CC__) +# include +# include +#else +# include +# include +#endif + + ], + [ + + FSSpec* pathSpec; + + + ATSFontFindFromName( NULL, kATSOptionFlagsUnRestrictedScope ); +#if HAVE_FSSPEC + ATSFontGetFileSpecification( 0, pathSpec ); +#endif + + ])], + [AC_MSG_RESULT([ok]) + CFLAGS="$CFLAGS -DHAVE_ATS=1"], + [AC_MSG_RESULT([not found]) + CFLAGS="$CFLAGS -DHAVE_ATS=0"]) +fi + +case "$CFLAGS" in + *HAVE_FSSPEC* | *HAVE_FSREF* | *HAVE_QUICKDRAW* | *HAVE_ATS* ) + AC_MSG_WARN([ +*** WARNING + FSSpec/FSRef/QuickDraw/ATS options are explicitly given, + thus it is recommended to replace src/base/ftmac.c by builds/mac/ftmac.c. + ]) + CFLAGS="$CFLAGS "'-I$(TOP_DIR)/builds/mac/' + ;; + *) + ;; +esac + +# Check for pthreads + +AX_PTHREAD([have_pthread=yes], [have_pthread=no]) + +# Check for Python and docwriter +PYTHON_MIN_VERSION=3.5 +have_py3=no +have_docwriter=no +PIP=pip + +AC_CHECK_PROGS([PYTHON], [python3 python], [missing]) +if test "x$PYTHON" != "xmissing"; then + AX_PROG_PYTHON_VERSION([$PYTHON_MIN_VERSION], [have_py3=yes], []) + + if test "x$have_py3" = "xyes"; then + PIP="$PYTHON -m $PIP" + AC_MSG_CHECKING([for `docwriter' Python module]) + $PYTHON -m docwriter -h > /dev/null 2>&1 + if test "x$?" = "x0"; then + have_docwriter=yes + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi +fi + + +# entries in Requires.private are separated by commas +PKGCONFIG_REQUIRES_PRIVATE="$zlib_reqpriv, \ + $bzip2_reqpriv, \ + $libpng_reqpriv, \ + $harfbuzz_reqpriv, \ + $brotli_reqpriv" +# beautify +PKGCONFIG_REQUIRES_PRIVATE=`echo "$PKGCONFIG_REQUIRES_PRIVATE" \ + | sed -e 's/^ *//' \ + -e 's/ *$//' \ + -e 's/, */,/g' \ + -e 's/,,*/,/g' \ + -e 's/^,*//' \ + -e 's/,*$//' \ + -e 's/,/, /g'` + +PKGCONFIG_LIBS_PRIVATE="$zlib_libspriv \ + $bzip2_libspriv \ + $libpng_libspriv \ + $harfbuzz_libspriv \ + $brotli_libspriv \ + $ft2_extra_libs" +# beautify +PKGCONFIG_LIBS_PRIVATE=`echo "$PKGCONFIG_LIBS_PRIVATE" \ + | sed -e 's/^ *//' \ + -e 's/ *$//' \ + -e 's/ */ /g'` + +LIBSSTATIC_CONFIG="-lfreetype \ + $zlib_libsstaticconf \ + $bzip2_libsstaticconf \ + $libpng_libsstaticconf \ + $harfbuzz_libsstaticconf \ + $brotli_libsstaticconf \ + $ft2_extra_libs" +# remove -L/usr/lib and -L/usr/lib64 since `freetype-config' adds them later +# on if necessary; also beautify +LIBSSTATIC_CONFIG=`echo "$LIBSSTATIC_CONFIG" \ + | sed -e 's|-L */usr/lib64/* | |g' \ + -e 's|-L */usr/lib/* | |g' \ + -e 's/^ *//' \ + -e 's/ *$//' \ + -e 's/ */ /g'` + +# If FreeType gets installed with `--disable-shared', don't use +# 'private' fields. `pkg-config' only looks into `.pc' files and is +# completely agnostic to whether shared libraries are actually present +# or not. As a consequence, the user had to specify `--static' while +# calling `pkg-config', which configure scripts are normally not +# prepared for. + +PKGCONFIG_REQUIRES= +PKGCONFIG_LIBS='-L${libdir} -lfreetype' + +if test $enable_shared = "no"; then + PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES $PKGCONFIG_REQUIRES_PRIVATE" + PKGCONFIG_REQUIRES_PRIVATE= + PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE" + PKGCONFIG_LIBS_PRIVATE= +fi + +AC_SUBST([ftmac_c]) +AC_SUBST([PKGCONFIG_REQUIRES]) +AC_SUBST([PKGCONFIG_LIBS]) +AC_SUBST([PKGCONFIG_REQUIRES_PRIVATE]) +AC_SUBST([PKGCONFIG_LIBS_PRIVATE]) +AC_SUBST([LIBSSTATIC_CONFIG]) + +AC_SUBST([hardcode_libdir_flag_spec]) +AC_SUBST([wl]) +AC_SUBST([build_libtool_libs]) + + +# changing LDFLAGS value should only be done after +# lt_cv_prog_compiler_static_works test + +ftoption_set() +{ + regexp="-e \\\"s|.*#.*def.*$1.*|#define $1|\\\"" + FTOPTION_H_SED="$FTOPTION_H_SED $regexp" +} + +ftoption_unset() +{ + regexp="-e \\\"s|.*#.*def.*$1.*|/* #undef $1 */|\\\"" + FTOPTION_H_SED="$FTOPTION_H_SED $regexp" +} + +if test "$have_zlib" != no; then + CFLAGS="$CFLAGS $ZLIB_CFLAGS" + LDFLAGS="$LDFLAGS $ZLIB_LIBS" + ftoption_set FT_CONFIG_OPTION_SYSTEM_ZLIB +else + ftoption_unset FT_CONFIG_OPTION_SYSTEM_ZLIB +fi +if test "$have_bzip2" != no; then + CFLAGS="$CFLAGS $BZIP2_CFLAGS" + LDFLAGS="$LDFLAGS $BZIP2_LIBS" + ftoption_set FT_CONFIG_OPTION_USE_BZIP2 +else + ftoption_unset FT_CONFIG_OPTION_USE_BZIP2 +fi +if test "$have_libpng" != no; then + CFLAGS="$CFLAGS $LIBPNG_CFLAGS" + LDFLAGS="$LDFLAGS $LIBPNG_LIBS" + ftoption_set FT_CONFIG_OPTION_USE_PNG +else + ftoption_unset FT_CONFIG_OPTION_USE_PNG +fi +if test "$have_harfbuzz" != no; then + CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS" + LDFLAGS="$LDFLAGS $HARFBUZZ_LIBS" + ftoption_set FT_CONFIG_OPTION_USE_HARFBUZZ +else + ftoption_unset FT_CONFIG_OPTION_USE_HARFBUZZ +fi +if test "$have_brotli" != no; then + CFLAGS="$CFLAGS $BROTLI_CFLAGS" + LDFLAGS="$LDFLAGS $BROTLI_LIBS" + ftoption_set FT_CONFIG_OPTION_USE_BROTLI +else + ftoption_unset FT_CONFIG_OPTION_USE_BROTLI +fi + +if test "$have_pthread" != no; then + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LDFLAGS="$LDFLAGS $PTHREAD_CFLAGS $PTHREAD_LIBS" +fi + +AC_SUBST([CFLAGS]) +AC_SUBST([LDFLAGS]) + +# We don't want to use a template file for `ftoption.h', since compilation +# should work without calling a configure script also. For this reason, we +# copy the `include/freetype/config/ftoption.h' file to the `unix/builds' +# directory (using a dummy `AC_CONFIG_FILES' call) and apply the just +# constructed $FTOPTION_H_SED regexp (using the post-action of +# `AC_CONFIG_FILES'); this is also the version that gets installed later on. +# +AC_CONFIG_FILES([ftoption.h:${srcdir}/../../include/freetype/config/ftoption.h], + [mv ftoption.h ftoption.tmp + eval "sed $FTOPTION_H_SED < ftoption.tmp > ftoption.h" + rm ftoption.tmp], + [FTOPTION_H_SED="$FTOPTION_H_SED"]) + +AC_CONFIG_HEADERS([ftconfig.h]) + +# create the Unix-specific sub-Makefiles `builds/unix/unix-def.mk' +# and `builds/unix/unix-cc.mk' that will be used by the build system +# +AC_CONFIG_FILES([unix-cc.mk:unix-cc.in + unix-def.mk:unix-def.in]) + +AC_OUTPUT + +AC_MSG_NOTICE([ + +Library configuration: + external zlib: $have_zlib + bzip2: $have_bzip2 + libpng: $have_libpng + harfbuzz: $have_harfbuzz + brotli: $have_brotli + pthread: $have_pthread +]) + +# Warn if docwriter is not installed + +if test $have_docwriter = no; then + AC_MSG_WARN([ + `make refdoc' will fail since pip package `docwriter' is not installed. + To install, run `$PIP install docwriter', or to use a Python + virtual environment, run `make refdoc-venv' (requires pip package + `virtualenv'). These operations require Python >= $PYTHON_MIN_VERSION. + ]) +fi + +# Warn if pthread is not available + +if test $have_pthread = no; then + AC_MSG_WARN([ + `FT_DEBUG_LOGGING' will not work since the `pthread' library is not + available. This warning can be safely ignored if you don't plan to use + this configuration macro. + ]) +fi + +# end of configure.raw diff --git a/vendor/freetype/builds/unix/detect.mk b/vendor/freetype/builds/unix/detect.mk new file mode 100644 index 0000000..6b87013 --- /dev/null +++ b/vendor/freetype/builds/unix/detect.mk @@ -0,0 +1,99 @@ +# +# FreeType 2 configuration file to detect a UNIX host platform. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +.PHONY: setup + +ifeq ($(PLATFORM),ansi) + + # Note: this test is duplicated in "builds/toplevel.mk". + # + is_unix := $(strip $(wildcard /sbin/init) \ + $(wildcard /usr/sbin/init) \ + $(wildcard /dev/null) \ + $(wildcard /hurd/auth)) + ifneq ($(is_unix),) + + PLATFORM := unix + + endif # test is_unix +endif # test PLATFORM ansi + +ifeq ($(PLATFORM),unix) + COPY := cp + DELETE := rm -f + CAT := cat + + # If `devel' is the requested target, we use a special configuration + # file named `unix-dev.mk'. It disables optimization and libtool. + # + ifneq ($(findstring devel,$(MAKECMDGOALS)),) + CONFIG_FILE := unix-dev.mk + CC := gcc + + .PHONY: devel + devel: setup + @: + else + + # If `lcc' is the requested target, we use a special configuration + # file named `unix-lcc.mk'. It disables libtool for LCC. + # + ifneq ($(findstring lcc,$(MAKECMDGOALS)),) + CONFIG_FILE := unix-lcc.mk + CC := lcc + + .PHONY: lcc + lcc: setup + @: + else + + # If a Unix platform is detected, the configure script is called and + # `unix-def.mk' together with `unix-cc.mk' is created. + # + # Arguments to `configure' should be in the CFG variable. Example: + # + # make CFG="--prefix=/usr --disable-static" + # + # If you need to set CFLAGS or LDFLAGS, do it here also. + # + # Feel free to add support for other platform specific compilers in + # this directory (e.g. solaris.mk + changes here to detect the + # platform). + # + CONFIG_FILE := unix.mk + must_configure := 1 + + .PHONY: unix + unix: setup + @: + endif + endif + + have_Makefile := $(wildcard $(OBJ_DIR)/Makefile) + + setup: std_setup + ifdef must_configure + ifneq ($(have_Makefile),) + # we are building FT2 not in the src tree + $(TOP_DIR)/builds/unix/configure $(value CFG) + else + cd builds/unix; \ + ./configure $(value CFG) + endif + endif + +endif # test PLATFORM unix + + +# EOF diff --git a/vendor/freetype/builds/unix/freetype-config.in b/vendor/freetype/builds/unix/freetype-config.in new file mode 100644 index 0000000..5856112 --- /dev/null +++ b/vendor/freetype/builds/unix/freetype-config.in @@ -0,0 +1,211 @@ +#! /bin/sh +# +# Copyright (C) 2000-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +LC_ALL=C +export LC_ALL + + +# if `pkg-config' is available, use values from `freetype2.pc' +%PKG_CONFIG% --atleast-pkgconfig-version 0.24 >/dev/null 2>&1 +if test $? -eq 0 ; then + # note that option `--variable' is not affected by the + # PKG_CONFIG_SYSROOT_DIR environment variable + if test "x$SYSROOT" != "x" ; then + PKG_CONFIG_SYSROOT_DIR="$SYSROOT" + export PKG_CONFIG_SYSROOT_DIR + fi + + prefix=`%PKG_CONFIG% --variable prefix freetype2` + exec_prefix=`%PKG_CONFIG% --variable exec_prefix freetype2` + + includedir=`%PKG_CONFIG% --variable includedir freetype2` + libdir=`%PKG_CONFIG% --variable libdir freetype2` + + version=`%PKG_CONFIG% --modversion freetype2` + + cflags=`%PKG_CONFIG% --cflags freetype2` + dynamic_libs=`%PKG_CONFIG% --libs freetype2` + static_libs=`%PKG_CONFIG% --static --libs freetype2` +else + prefix="%prefix%" + exec_prefix="%exec_prefix%" + + includedir="%includedir%" + libdir="%libdir%" + + version=%ft_version% + + cflags="-I${SYSROOT}$includedir/freetype2" + dynamic_libs="-lfreetype" + static_libs="%LIBSSTATIC_CONFIG%" + if test "${SYSROOT}$libdir" != "/usr/lib" && + test "${SYSROOT}$libdir" != "/usr/lib64" ; then + libs_L="-L${SYSROOT}$libdir" + fi +fi + +orig_prefix=$prefix +orig_exec_prefix=$exec_prefix + +orig_includedir=$includedir +orig_libdir=$libdir + +include_suffix=`echo $includedir | sed "s|$prefix||"` +lib_suffix=`echo $libdir | sed "s|$exec_prefix||"` + + +usage() +{ + cat <&2 +fi + + +while test $# -gt 0 ; do + case "$1" in + -*=*) + optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` + ;; + *) + optarg= + ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + local_prefix=yes + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + local_prefix=yes + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --version) + echo_version=yes + break + ;; + --ftversion) + echo_ft_version=yes + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + --libtool) + echo_libtool=yes + ;; + --static) + show_static=yes + ;; + --help) + usage 0 + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + + +if test "$local_prefix" = "yes" ; then + if test "$exec_prefix_set" != "yes" ; then + exec_prefix=$prefix + fi +fi + +if test "$local_prefix" = "yes" ; then + includedir=${prefix}${include_suffix} + if test "$exec_prefix_set" = "yes" ; then + libdir=${exec_prefix}${lib_suffix} + else + libdir=${prefix}${lib_suffix} + fi +fi + + +if test "$echo_version" = "yes" ; then + echo $version +fi + +if test "$echo_prefix" = "yes" ; then + echo ${SYSROOT}$prefix +fi + +if test "$echo_exec_prefix" = "yes" ; then + echo ${SYSROOT}$exec_prefix +fi + +if test "$echo_ft_version" = "yes" ; then + major=`grep define ${SYSROOT}$includedir/freetype2/freetype/freetype.h \ + | grep FREETYPE_MAJOR \ + | sed 's/.*[ ]\([0-9][0-9]*\).*/\1/'` + minor=`grep define ${SYSROOT}$includedir/freetype2/freetype/freetype.h \ + | grep FREETYPE_MINOR \ + | sed 's/.*[ ]\([0-9][0-9]*\).*/\1/'` + patch=`grep define ${SYSROOT}$includedir/freetype2/freetype/freetype.h \ + | grep FREETYPE_PATCH \ + | sed 's/.*[ ]\([0-9][0-9]*\).*/\1/'` + echo $major.$minor.$patch +fi + +if test "$echo_cflags" = "yes" ; then + echo $cflags | sed "s|$orig_includedir/freetype2|$includedir/freetype2|" +fi + +if test "$echo_libs" = "yes" ; then + if test "$show_static" = "yes" ; then + libs="$libs_L $static_libs" + else + libs="$libs_L $dynamic_libs" + fi + echo $libs | sed "s|$orig_libdir|$libdir|" +fi + +if test "$echo_libtool" = "yes" ; then + echo ${SYSROOT}$libdir/libfreetype.la +fi + +# EOF diff --git a/vendor/freetype/builds/unix/freetype2.in b/vendor/freetype/builds/unix/freetype2.in new file mode 100644 index 0000000..fe389f4 --- /dev/null +++ b/vendor/freetype/builds/unix/freetype2.in @@ -0,0 +1,14 @@ +prefix=%prefix% +exec_prefix=%exec_prefix% +libdir=%libdir% +includedir=%includedir% + +Name: FreeType 2 +URL: https://freetype.org +Description: A free, high-quality, and portable font engine. +Version: %ft_version% +Requires: %PKGCONFIG_REQUIRES% +Requires.private: %PKGCONFIG_REQUIRES_PRIVATE% +Libs: %PKGCONFIG_LIBS% +Libs.private: %PKGCONFIG_LIBS_PRIVATE% +Cflags: -I${includedir}/freetype2 diff --git a/vendor/freetype/builds/unix/freetype2.m4 b/vendor/freetype/builds/unix/freetype2.m4 new file mode 100644 index 0000000..09ead43 --- /dev/null +++ b/vendor/freetype/builds/unix/freetype2.m4 @@ -0,0 +1,194 @@ +# Configure paths for FreeType2 +# Marcelo Magallon 2001-10-26, based on `gtk.m4` by Owen Taylor +# +# Copyright (C) 2001-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. +# +# As a special exception to the FreeType project license, this file may be +# distributed as part of a program that contains a configuration script +# generated by Autoconf, under the same distribution terms as the rest of +# that program. +# +# serial 7 + +# AC_CHECK_FT2([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +# Test for FreeType 2, and define FT2_CFLAGS and FT2_LIBS. +# MINIMUM-VERSION is what libtool reports; the default is '7.0.1' (this is +# FreeType 2.0.4). +# +# To make this code work with older autoconf versions, `AS_HELP_STRING` is +# not quoted. +# +AC_DEFUN([AC_CHECK_FT2], + [# Get the cflags and libraries from the freetype-config script + # + AC_ARG_WITH([ft-prefix], + AS_HELP_STRING([--with-ft-prefix=PREFIX], + [Prefix where FreeType is installed (optional)]), + [ft_config_prefix="$withval"], + [ft_config_prefix=""]) + + AC_ARG_WITH([ft-exec-prefix], + AS_HELP_STRING([--with-ft-exec-prefix=PREFIX], + [Exec prefix where FreeType is installed (optional)]), + [ft_config_exec_prefix="$withval"], + [ft_config_exec_prefix=""]) + + AC_ARG_ENABLE([freetypetest], + AS_HELP_STRING([--disable-freetypetest], + [Do not try to compile and run a test FreeType program]), + [], + [enable_fttest=yes]) + + if test x$ft_config_exec_prefix != x ; then + ft_config_args="$ft_config_args --exec-prefix=$ft_config_exec_prefix" + if test x${FT2_CONFIG+set} != xset ; then + FT2_CONFIG=$ft_config_exec_prefix/bin/freetype-config + fi + fi + + if test x$ft_config_prefix != x ; then + ft_config_args="$ft_config_args --prefix=$ft_config_prefix" + if test x${FT2_CONFIG+set} != xset ; then + FT2_CONFIG=$ft_config_prefix/bin/freetype-config + fi + fi + + if test "x$FT2_CONFIG" = x ; then + AC_PATH_TOOL([FT2_CONFIG], [freetype-config], [no]) + fi + + min_ft_version=m4_if([$1], [], [7.0.1], [$1]) + AC_MSG_CHECKING([for FreeType -- version >= $min_ft_version]) + no_ft="" + if test "$FT2_CONFIG" = "no" ; then + no_ft=yes + else + FT2_CFLAGS=`$FT2_CONFIG $ft_config_args --cflags` + FT2_LIBS=`$FT2_CONFIG $ft_config_args --libs` + ft_config_major_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_config_minor_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_config_micro_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + ft_min_major_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_min_minor_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_min_micro_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test x$enable_fttest = xyes ; then + ft_config_is_lt="" + if test $ft_config_major_version -lt $ft_min_major_version ; then + ft_config_is_lt=yes + else + if test $ft_config_major_version -eq $ft_min_major_version ; then + if test $ft_config_minor_version -lt $ft_min_minor_version ; then + ft_config_is_lt=yes + else + if test $ft_config_minor_version -eq $ft_min_minor_version ; then + if test $ft_config_micro_version -lt $ft_min_micro_version ; then + ft_config_is_lt=yes + fi + fi + fi + fi + fi + if test x$ft_config_is_lt = xyes ; then + no_ft=yes + else + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $FT2_CFLAGS" + LIBS="$FT2_LIBS $LIBS" + + # + # Sanity checks for the results of freetype-config to some extent. + # + AC_RUN_IFELSE([ + AC_LANG_SOURCE([[ + +#include +#include +#include +#include + +int +main(void) +{ + FT_Library library; + FT_Error error; + + error = FT_Init_FreeType(&library); + + if (error) + return 1; + else + { + FT_Done_FreeType(library); + return 0; + } +} + + ]]) + ], + [], + [no_ft=yes], + [echo $ECHO_N "cross compiling; assuming OK... $ECHO_C"]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi # test $ft_config_version -lt $ft_min_version + fi # test x$enable_fttest = xyes + fi # test "$FT2_CONFIG" = "no" + + if test x$no_ft = x ; then + AC_MSG_RESULT([yes]) + m4_if([$2], [], [:], [$2]) + else + AC_MSG_RESULT([no]) + if test "$FT2_CONFIG" = "no" ; then + AC_MSG_WARN([ + + The freetype-config script installed by FreeType 2 could not be found. + If FreeType 2 was installed in PREFIX, make sure PREFIX/bin is in + your path, or set the FT2_CONFIG environment variable to the + full path to freetype-config. + ]) + else + if test x$ft_config_is_lt = xyes ; then + AC_MSG_WARN([ + + Your installed version of the FreeType 2 library is too old. + If you have different versions of FreeType 2, make sure that + correct values for --with-ft-prefix or --with-ft-exec-prefix + are used, or set the FT2_CONFIG environment variable to the + full path to freetype-config. + ]) + else + AC_MSG_WARN([ + + The FreeType test program failed to run. If your system uses + shared libraries and they are installed outside the normal + system library path, make sure the variable LD_LIBRARY_PATH + (or whatever is appropriate for your system) is correctly set. + ]) + fi + fi + + FT2_CFLAGS="" + FT2_LIBS="" + m4_if([$3], [], [:], [$3]) + fi + + AC_SUBST([FT2_CFLAGS]) + AC_SUBST([FT2_LIBS])]) + +# end of freetype2.m4 diff --git a/vendor/freetype/builds/unix/ft-munmap.m4 b/vendor/freetype/builds/unix/ft-munmap.m4 new file mode 100644 index 0000000..a0fcf35 --- /dev/null +++ b/vendor/freetype/builds/unix/ft-munmap.m4 @@ -0,0 +1,32 @@ +## FreeType specific autoconf tests +# +# Copyright (C) 2002-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# serial 2 + +AC_DEFUN([FT_MUNMAP_PARAM], + [AC_MSG_CHECKING([for munmap's first parameter type]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + +#include +#include +int munmap(void *, size_t); + + ]]) + ], + [AC_MSG_RESULT([void *]) + AC_DEFINE([MUNMAP_USES_VOIDP], + [], + [Define to 1 if the first argument of munmap is of type void *])], + [AC_MSG_RESULT([char *])]) + ]) + +# end of ft-munmap.m4 diff --git a/vendor/freetype/builds/unix/ftconfig.h.in b/vendor/freetype/builds/unix/ftconfig.h.in new file mode 100644 index 0000000..3dac561 --- /dev/null +++ b/vendor/freetype/builds/unix/ftconfig.h.in @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * ftconfig.h.in + * + * UNIX-specific configuration file (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This header file contains a number of macro definitions that are used by + * the rest of the engine. Most of the macros here are automatically + * determined at compile time, and you should not need to change it to port + * FreeType, except to compile the library with a non-ANSI compiler. + * + * Note however that if some specific modifications are needed, we advise + * you to place a modified copy in your build directory. + * + * The build directory is usually `builds/`, and contains + * system-specific files that are always included first when building the + * library. + * + */ + +#ifndef FTCONFIG_H_ +#define FTCONFIG_H_ + +#include +#include FT_CONFIG_OPTIONS_H +#include FT_CONFIG_STANDARD_LIBRARY_H + +#undef HAVE_UNISTD_H +#undef HAVE_FCNTL_H + +#include +#include +#include + +#endif /* FTCONFIG_H_ */ + + +/* END */ diff --git a/vendor/freetype/builds/unix/ftsystem.c b/vendor/freetype/builds/unix/ftsystem.c new file mode 100644 index 0000000..5927215 --- /dev/null +++ b/vendor/freetype/builds/unix/ftsystem.c @@ -0,0 +1,436 @@ +/**************************************************************************** + * + * ftsystem.c + * + * Unix-specific FreeType low-level system interface (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + /* we use our special ftconfig.h file, not the standard one */ +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include + + /* memory-mapping includes and definitions */ +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#ifndef MAP_FILE +#define MAP_FILE 0x00 +#endif + +#ifdef MUNMAP_USES_VOIDP +#define MUNMAP_ARG_CAST void * +#else +#define MUNMAP_ARG_CAST char * +#endif + +#ifdef NEED_MUNMAP_DECL + +#ifdef __cplusplus + extern "C" +#else + extern +#endif + int + munmap( char* addr, + int len ); + +#define MUNMAP_ARG_CAST char * + +#endif /* NEED_DECLARATION_MUNMAP */ + + +#include +#include + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include +#include +#include +#include + + + /************************************************************************** + * + * MEMORY MANAGEMENT INTERFACE + * + */ + + + /************************************************************************** + * + * It is not necessary to do any error checking for the + * allocation-related functions. This will be done by the higher level + * routines like ft_mem_alloc() or ft_mem_realloc(). + * + */ + + + /************************************************************************** + * + * @Function: + * ft_alloc + * + * @Description: + * The memory allocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * size :: + * The requested size in bytes. + * + * @Return: + * The address of newly allocated block. + */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return malloc( size ); + } + + + /************************************************************************** + * + * @Function: + * ft_realloc + * + * @Description: + * The memory reallocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * cur_size :: + * The current size of the allocated memory block. + * + * new_size :: + * The newly requested size in bytes. + * + * block :: + * The current address of the block in memory. + * + * @Return: + * The address of the reallocated memory block. + */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return realloc( block, new_size ); + } + + + /************************************************************************** + * + * @Function: + * ft_free + * + * @Description: + * The memory release function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * block :: + * The address of block in memory to be freed. + */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + free( block ); + } + + + /************************************************************************** + * + * RESOURCE MANAGEMENT INTERFACE + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) + + + /************************************************************************** + * + * @Function: + * ft_close_stream_by_munmap + * + * @Description: + * The function to close a stream which is opened by mmap. + * + * @Input: + * stream :: A pointer to the stream object. + */ + FT_CALLBACK_DEF( void ) + ft_close_stream_by_munmap( FT_Stream stream ) + { + munmap( (MUNMAP_ARG_CAST)stream->descriptor.pointer, stream->size ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /************************************************************************** + * + * @Function: + * ft_close_stream_by_free + * + * @Description: + * The function to close a stream which is created by ft_alloc. + * + * @Input: + * stream :: A pointer to the stream object. + */ + FT_CALLBACK_DEF( void ) + ft_close_stream_by_free( FT_Stream stream ) + { + ft_free( stream->memory, stream->descriptor.pointer ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + int file; + struct stat stat_buf; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + + /* open the file */ + file = open( filepathname, O_RDONLY ); + if ( file < 0 ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + return FT_THROW( Cannot_Open_Resource ); + } + + /* Here we ensure that a "fork" will _not_ duplicate */ + /* our opened input streams on Unix. This is critical */ + /* since it avoids some (possible) access control */ + /* issues and cleans up the kernel file table a bit. */ + /* */ +#ifdef F_SETFD +#ifdef FD_CLOEXEC + (void)fcntl( file, F_SETFD, FD_CLOEXEC ); +#else + (void)fcntl( file, F_SETFD, 1 ); +#endif /* FD_CLOEXEC */ +#endif /* F_SETFD */ + + if ( fstat( file, &stat_buf ) < 0 ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not `fstat' file `%s'\n", filepathname )); + goto Fail_Map; + } + + /* XXX: TODO -- real 64bit platform support */ + /* */ + /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */ + /* `stat_buf.st_size', however, is usually typedef'd to off_t */ + /* (in sys/stat.h). */ + /* On some platforms, the former is 32bit and the latter is 64bit. */ + /* To avoid overflow caused by fonts in huge files larger than */ + /* 2GB, do a test. Temporary fix proposed by Sean McBride. */ + /* */ + if ( stat_buf.st_size > LONG_MAX ) + { + FT_ERROR(( "FT_Stream_Open: file is too big\n" )); + goto Fail_Map; + } + else if ( stat_buf.st_size == 0 ) + { + FT_ERROR(( "FT_Stream_Open: zero-length file\n" )); + goto Fail_Map; + } + + /* This cast potentially truncates a 64bit to 32bit! */ + stream->size = (unsigned long)stat_buf.st_size; + stream->pos = 0; + stream->base = (unsigned char *)mmap( NULL, + stream->size, + PROT_READ, + MAP_FILE | MAP_PRIVATE, + file, + 0 ); + + if ( stream->base != MAP_FAILED ) + stream->close = ft_close_stream_by_munmap; + else + { + ssize_t total_read_count; + + + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); + + stream->base = (unsigned char*)ft_alloc( stream->memory, stream->size ); + + if ( !stream->base ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not `alloc' memory\n" )); + goto Fail_Map; + } + + total_read_count = 0; + do + { + ssize_t read_count; + + + read_count = read( file, + stream->base + total_read_count, + stream->size - total_read_count ); + + if ( read_count <= 0 ) + { + if ( read_count == -1 && errno == EINTR ) + continue; + + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); + goto Fail_Read; + } + + total_read_count += read_count; + + } while ( (unsigned long)total_read_count != stream->size ); + + stream->close = ft_close_stream_by_free; + } + + close( file ); + + stream->descriptor.pointer = stream->base; + stream->pathname.pointer = (char*)filepathname; + + stream->read = NULL; + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + + Fail_Read: + ft_free( stream->memory, stream->base ); + + Fail_Map: + close( file ); + + stream->base = NULL; + stream->size = 0; + stream->pos = 0; + + return FT_THROW( Cannot_Open_Stream ); + } + + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)malloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = NULL; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif + memory->free( memory, memory ); + } + + +/* END */ diff --git a/vendor/freetype/builds/unix/install.mk b/vendor/freetype/builds/unix/install.mk new file mode 100644 index 0000000..2f1729b --- /dev/null +++ b/vendor/freetype/builds/unix/install.mk @@ -0,0 +1,102 @@ +# +# FreeType 2 installation instructions for Unix systems +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# If you say +# +# make install DESTDIR=/tmp/somewhere/ +# +# don't forget the final backslash (this command is mainly for package +# maintainers). + + +.PHONY: install uninstall check + +# Unix installation and deinstallation targets. +# +# Note that we remove any data found in `$(includedir)/freetype2' before +# installing new files to avoid interferences with files installed by +# previous FreeType versions (which use slightly different locations). +# +# We also remove `$(includedir)/ft2build.h' for the same reason. +# +# Note that some header files get handled twice for simplicity; a special, +# configured version overwrites the generic one. +# +install: $(PROJECT_LIBRARY) + -$(DELDIR) $(DESTDIR)$(includedir)/freetype2 + -$(DELETE) $(DESTDIR)$(includedir)/ft2build.h + $(MKINSTALLDIRS) $(DESTDIR)$(libdir) \ + $(DESTDIR)$(libdir)/pkgconfig \ + $(DESTDIR)$(includedir)/freetype2/freetype/config \ + $(DESTDIR)$(datadir)/aclocal +ifeq ($(INSTALL_FT2_CONFIG),TRUE) + $(MKINSTALLDIRS) $(DESTDIR)$(bindir) \ + $(DESTDIR)$(mandir)/man1 +endif + $(LIBTOOL) --mode=install $(INSTALL) \ + $(PROJECT_LIBRARY) $(DESTDIR)$(libdir) + -for P in $(PUBLIC_H) ; do \ + $(INSTALL_DATA) \ + $$P $(DESTDIR)$(includedir)/freetype2/freetype ; \ + done + -for P in $(CONFIG_H) ; do \ + $(INSTALL_DATA) \ + $$P $(DESTDIR)$(includedir)/freetype2/freetype/config ; \ + done + $(INSTALL_DATA) $(TOP_DIR)/include/ft2build.h \ + $(DESTDIR)$(includedir)/freetype2/ft2build.h + $(INSTALL_DATA) $(OBJ_BUILD)/ftconfig.h \ + $(DESTDIR)$(includedir)/freetype2/freetype/config/ftconfig.h + $(INSTALL_DATA) $(OBJ_DIR)/ftmodule.h \ + $(DESTDIR)$(includedir)/freetype2/freetype/config/ftmodule.h + $(INSTALL_DATA) $(OBJ_BUILD)/ftoption.h \ + $(DESTDIR)$(includedir)/freetype2/freetype/config/ftoption.h + $(INSTALL_SCRIPT) -m 644 $(PLATFORM_DIR)/freetype2.m4 \ + $(DESTDIR)$(datadir)/aclocal/freetype2.m4 + $(INSTALL_SCRIPT) -m 644 $(OBJ_BUILD)/freetype2.pc \ + $(DESTDIR)$(libdir)/pkgconfig/freetype2.pc +ifeq ($(INSTALL_FT2_CONFIG),TRUE) + $(INSTALL_SCRIPT) -m 755 $(OBJ_BUILD)/freetype-config \ + $(DESTDIR)$(bindir)/freetype-config + $(INSTALL_DATA) $(TOP_DIR)/docs/freetype-config.1 \ + $(DESTDIR)$(mandir)/man1/freetype-config.1 +endif + + +uninstall: + -$(LIBTOOL) --mode=uninstall $(RM) $(DESTDIR)$(libdir)/$(LIBRARY).$A + -$(DELDIR) $(DESTDIR)$(includedir)/freetype2 + -$(DELETE) $(DESTDIR)$(bindir)/freetype-config + -$(DELETE) $(DESTDIR)$(datadir)/aclocal/freetype2.m4 + -$(DELETE) $(DESTDIR)$(libdir)/pkgconfig/freetype2.pc + -$(DELETE) $(DESTDIR)$(mandir)/man1/freetype-config.1 + + +check: + $(info There is no validation suite for this package.) + + +.PHONY: clean_project_unix distclean_project_unix + +# Unix cleaning and distclean rules. +# +clean_project_unix: + -$(LIBTOOL) --mode=clean $(RM) $(OBJECTS_LIST) + -$(DELETE) $(CLEAN) + +distclean_project_unix: clean_project_unix + -$(LIBTOOL) --mode=clean $(RM) $(PROJECT_LIBRARY) + -$(DELETE) *.orig *~ core *.core $(DISTCLEAN) + +# EOF diff --git a/vendor/freetype/builds/unix/pkg.m4 b/vendor/freetype/builds/unix/pkg.m4 new file mode 100644 index 0000000..260e1fb --- /dev/null +++ b/vendor/freetype/builds/unix/pkg.m4 @@ -0,0 +1,199 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurrence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + + +# PKG_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable pkgconfigdir as the location where a module +# should install pkg-config .pc files. By default the directory is +# $libdir/pkgconfig, but the default can be changed by passing +# DIRECTORY. The user can override through the --with-pkgconfigdir +# parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_INSTALLDIR + + +# PKG_NOARCH_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable noarch_pkgconfigdir as the location where a +# module should install arch-independent pkg-config .pc files. By +# default the directory is $datadir/pkgconfig, but the default can be +# changed by passing DIRECTORY. The user can override through the +# --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_NOARCH_INSTALLDIR diff --git a/vendor/freetype/builds/unix/unix-cc.in b/vendor/freetype/builds/unix/unix-cc.in new file mode 100644 index 0000000..802016d --- /dev/null +++ b/vendor/freetype/builds/unix/unix-cc.in @@ -0,0 +1,130 @@ +# +# FreeType 2 template for Unix-specific compiler definitions +# + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +CC := @CC@ +COMPILER_SEP := $(SEP) +FT_LIBTOOL_DIR ?= $(PLATFORM_DIR) + +LIBTOOL := $(FT_LIBTOOL_DIR)/libtool + + +# The object file extension (for standard and static libraries). This can be +# .o, .tco, .obj, etc., depending on the platform. +# +O := lo +SO := o + + +# The executable file extension. Although most Unix platforms use no +# extension, we copy the extension detected by autoconf. Useful for cross +# building on Unix systems for non-Unix systems. +# +E := @EXEEXT@ + + +# The library file extension (for standard and static libraries). This can +# be .a, .lib, etc., depending on the platform. +# +A := la +SA := a + + +# The name of the final library file. Note that the DOS-specific Makefile +# uses a shorter (8.3) name. +# +LIBRARY := lib$(PROJECT) + + +# Path inclusion flag. Some compilers use a different flag than `-I' to +# specify an additional include path. Examples are `/i=' or `-J'. +# +I := -I + + +# C flag used to define a macro before the compilation of a given source +# object. Usually it is `-D' like in `-DDEBUG'. +# +D := -D + + +# The link flag used to specify a given library file on link. Note that +# this is only used to compile the demo programs, not the library itself. +# +L := -l + + +# Target flag. +# +T := -o$(space) + + +# C flags +# +# These should concern: debug output, optimization & warnings. +# +# Use the ANSIFLAGS variable to define the compiler flags used to enforce +# ANSI compliance. +# +# We use our own FreeType configuration files overriding defaults. +# +CPPFLAGS := @CPPFLAGS@ +CFLAGS := -c @XX_CFLAGS@ @CFLAGS@ \ + $DFT_CONFIG_CONFIG_H="" \ + $DFT_CONFIG_MODULES_H="" \ + $DFT_CONFIG_OPTIONS_H="" + +# ANSIFLAGS: Put there the flags used to make your compiler ANSI-compliant. +# +ANSIFLAGS := @XX_ANSIFLAGS@ + +# C compiler to use -- we use libtool! +# +# CC might be set on the command line; we store this value in `CCraw'. +# Consequently, we use the `override' directive to ensure that the +# libtool call is always prepended. +# +CCraw := $(CC) +override CC := $(LIBTOOL) --mode=compile $(CCraw) + +# Resource compiler to use on Cygwin/MinGW, usually windres. +# +RCraw := @RC@ +ifneq ($(RCraw),) + RC := $(LIBTOOL) --tag=RC --mode=compile $(RCraw) +endif + +# Linker flags. +# +LDFLAGS := @LDFLAGS@ + +# export symbols +# +CCraw_build := @CC_BUILD@ # native CC of building system +E_BUILD := @EXEEXT_BUILD@ # extension for executable on building system +EXPORTS_LIST := $(OBJ_DIR)/ftexport.sym +CCexe := $(CCraw_build) # used to compile `apinames' only + + +# Library linking. +# +LINK_LIBRARY = $(LIBTOOL) --mode=link $(CCraw) -o $@ $(OBJECTS_LIST) \ + -rpath $(libdir) -version-info $(version_info) \ + $(LDFLAGS) -no-undefined \ + -export-symbols $(EXPORTS_LIST) + +# For the demo programs. +FT_DEMO_CFLAGS := @FT_DEMO_CFLAGS@ +FT_DEMO_LDFLAGS := @FT_DEMO_LDFLAGS@ + +# EOF diff --git a/vendor/freetype/builds/unix/unix-def.in b/vendor/freetype/builds/unix/unix-def.in new file mode 100644 index 0000000..d50994f --- /dev/null +++ b/vendor/freetype/builds/unix/unix-def.in @@ -0,0 +1,163 @@ +# +# FreeType 2 configuration rules templates for Unix + configure +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +SHELL := @SHELL@ + +TOP_DIR := $(shell cd $(TOP_DIR); pwd) + +DELETE := rm -f +DELDIR := rm -rf +CAT := cat +SEP := / + +# This is used for `make refdoc' and `make refdoc-venv' +# +PYTHON := @PYTHON@ +BIN := bin + +# this is used for `make distclean' and `make install' +OBJ_BUILD ?= $(PLATFORM_DIR) + +# don't use `:=' here since the path stuff will be included after this file +# +FTSYS_SRC = @FTSYS_SRC@ + +INSTALL := @INSTALL@ +INSTALL_DATA := @INSTALL_DATA@ +INSTALL_PROGRAM := @INSTALL_PROGRAM@ +INSTALL_SCRIPT := @INSTALL_SCRIPT@ +MKINSTALLDIRS := @MKDIR_P@ + +CLEAN += $(OBJ_BUILD)/freetype-config \ + $(OBJ_BUILD)/freetype2.pc + +DISTCLEAN += $(OBJ_BUILD)/config.cache \ + $(OBJ_BUILD)/config.log \ + $(OBJ_BUILD)/config.status \ + $(OBJ_BUILD)/unix-def.mk \ + $(OBJ_BUILD)/unix-cc.mk \ + $(OBJ_BUILD)/ftconfig.h \ + $(OBJ_BUILD)/ftoption.h \ + $(LIBTOOL) \ + $(OBJ_BUILD)/Makefile + + +# Standard installation variables. +# +prefix := @prefix@ +exec_prefix := @exec_prefix@ +libdir := @libdir@ +bindir := @bindir@ +includedir := @includedir@ +datarootdir := @datarootdir@ +datadir := @datadir@ +mandir := @mandir@ + +version_info := @version_info@ + +# Variables needed for `freetype-config' and `freetype.pc'. +# +PKG_CONFIG := @PKG_CONFIG@ +PKGCONFIG_REQUIRES := @PKGCONFIG_REQUIRES@ +PKGCONFIG_REQUIRES_PRIVATE := @PKGCONFIG_REQUIRES_PRIVATE@ +PKGCONFIG_LIBS := @PKGCONFIG_LIBS@ +PKGCONFIG_LIBS_PRIVATE := @PKGCONFIG_LIBS_PRIVATE@ +LIBSSTATIC_CONFIG := @LIBSSTATIC_CONFIG@ +build_libtool_libs := @build_libtool_libs@ +ft_version := @ft_version@ + +# The directory where all library files are placed. +# +# By default, this is the same as $(OBJ_DIR); however, this can be changed +# to suit particular needs. +# +LIB_DIR := $(OBJ_DIR) + +# The BASE_SRC macro lists all source files that should be included in +# src/base/ftbase.c. When configure sets up CFLAGS to build ftmac.c, +# ftmac.c should be added to BASE_SRC. +ftmac_c := @ftmac_c@ + +# The SYSTEM_ZLIB macro is defined if the user wishes to link dynamically +# with its system wide zlib. If SYSTEM_ZLIB is 'yes', the zlib part of the +# ftgzip module is not compiled in. +SYSTEM_ZLIB := @SYSTEM_ZLIB@ + + +# The NO_OUTPUT macro is appended to command lines in order to ignore +# the output of some programs. +# +NO_OUTPUT := 2> /dev/null + + +# To support calls like +# +# configure --includedir='${libdir}'/freetype2/include +# +# we generate `freetype-config' and `freetype.pc' at compile time so that +# those variables are properly expanded. + +$(OBJ_BUILD)/freetype-config: $(TOP_DIR)/builds/unix/freetype-config.in + rm -f $@ $@.tmp + sed -e 's|%LIBSSTATIC_CONFIG%|$(LIBSSTATIC_CONFIG)|' \ + -e 's|%PKG_CONFIG%|$(PKG_CONFIG)|' \ + -e 's|%build_libtool_libs%|$(build_libtool_libs)|' \ + -e 's|%exec_prefix%|$(exec_prefix)|' \ + -e 's|%ft_version%|$(ft_version)|' \ + -e 's|%includedir%|$(includedir)|' \ + -e 's|%libdir%|$(libdir)|' \ + -e 's|%prefix%|$(prefix)|' \ + $< \ + > $@.tmp + chmod +x $@.tmp + chmod go-w $@.tmp + mv $@.tmp $@ + +# To support directory names with spaces (as might easily happen on Windows +# platforms), the right solution would be to surround the pkg-variables in +# `freetype2.pc' with double quotes. However, doing so ironically disables +# the prefix override mechanism especially written for Windows. This is a +# bug in pkg-config version 0.28 and earlier. +# +# For this reason, we escape spaces with backslashes. + +exec_prefix_x := $(subst $(space),\\$(space),$(exec_prefix)) +includedir_x := $(subst $(space),\\$(space),$(includedir)) +libdir_x := $(subst $(space),\\$(space),$(libdir)) +prefix_x := $(subst $(space),\\$(space),$(prefix)) + +$(OBJ_BUILD)/freetype2.pc: $(TOP_DIR)/builds/unix/freetype2.in + rm -f $@ $@.tmp + sed -e 's|%PKGCONFIG_REQUIRES%|$(PKGCONFIG_REQUIRES)|' \ + -e 's|%PKGCONFIG_REQUIRES_PRIVATE%|$(PKGCONFIG_REQUIRES_PRIVATE)|' \ + -e 's|%PKGCONFIG_LIBS%|$(PKGCONFIG_LIBS)|' \ + -e 's|%PKGCONFIG_LIBS_PRIVATE%|$(PKGCONFIG_LIBS_PRIVATE)|' \ + -e 's|%build_libtool_libs%|$(build_libtool_libs)|' \ + -e 's|%exec_prefix%|$(exec_prefix_x)|' \ + -e 's|%ft_version%|$(ft_version)|' \ + -e 's|%includedir%|$(includedir_x)|' \ + -e 's|%libdir%|$(libdir_x)|' \ + -e 's|%prefix%|$(prefix_x)|' \ + $< \ + > $@.tmp + chmod a-w $@.tmp + mv $@.tmp $@ + +# defines whether we should install `freetype-config' or not +INSTALL_FT2_CONFIG = @INSTALL_FT2_CONFIG@ + +all install: $(OBJ_BUILD)/freetype-config \ + $(OBJ_BUILD)/freetype2.pc + +# EOF diff --git a/vendor/freetype/builds/unix/unix-dev.mk b/vendor/freetype/builds/unix/unix-dev.mk new file mode 100644 index 0000000..9dd8ad6 --- /dev/null +++ b/vendor/freetype/builds/unix/unix-dev.mk @@ -0,0 +1,26 @@ +# +# FreeType 2 Configuration rules for Unix + GCC +# +# Development version without optimizations & libtool +# and no installation. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DEVEL_DIR := $(TOP_DIR)/devel + +include $(TOP_DIR)/builds/unix/unixddef.mk +include $(TOP_DIR)/builds/compiler/gcc-dev.mk +include $(TOP_DIR)/builds/link_std.mk + + +# EOF diff --git a/vendor/freetype/builds/unix/unix-lcc.mk b/vendor/freetype/builds/unix/unix-lcc.mk new file mode 100644 index 0000000..ded24f4 --- /dev/null +++ b/vendor/freetype/builds/unix/unix-lcc.mk @@ -0,0 +1,24 @@ +# +# FreeType 2 Configuration rules for Unix + LCC +# +# Development version without optimizations & libtool +# and no installation. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +include $(TOP_DIR)/builds/unix/unixddef.mk +include $(TOP_DIR)/builds/compiler/unix-lcc.mk +include $(TOP_DIR)/builds/link_std.mk + + +# EOF diff --git a/vendor/freetype/builds/unix/unix.mk b/vendor/freetype/builds/unix/unix.mk new file mode 100644 index 0000000..3505175 --- /dev/null +++ b/vendor/freetype/builds/unix/unix.mk @@ -0,0 +1,62 @@ +# +# FreeType 2 configuration rules for UNIX platforms +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# We need these declarations here since unix-def.mk is a generated file. +PLATFORM_DIR := $(TOP_DIR)/builds/unix +PLATFORM := unix + +have_mk := $(wildcard $(OBJ_DIR)/unix-def.mk) +ifneq ($(have_mk),) + # We are building FreeType 2 not in the src tree. + include $(OBJ_DIR)/unix-def.mk + include $(OBJ_DIR)/unix-cc.mk +else + include $(PLATFORM_DIR)/unix-def.mk + include $(PLATFORM_DIR)/unix-cc.mk +endif + +ifdef BUILD_PROJECT + + .PHONY: clean_project distclean_project + + # Now include the main sub-makefile. It contains all the rules used to + # build the library with the previous variables defined. + # + include $(TOP_DIR)/builds/$(PROJECT).mk + + + # The cleanup targets. + # + clean_project: clean_project_unix + distclean_project: distclean_project_unix + + + # This final rule is used to link all object files into a single library. + # It is part of the system-specific sub-Makefile because not all + # librarians accept a simple syntax like + # + # librarian library_file {list of object files} + # + $(PROJECT_LIBRARY): $(OBJECTS_LIST) + ifdef CLEAN_LIBRARY + -$(CLEAN_LIBRARY) $(NO_OUTPUT) + endif + $(LINK_LIBRARY) + + include $(TOP_DIR)/builds/unix/install.mk + +endif + + +# EOF diff --git a/vendor/freetype/builds/unix/unixddef.mk b/vendor/freetype/builds/unix/unixddef.mk new file mode 100644 index 0000000..7197347 --- /dev/null +++ b/vendor/freetype/builds/unix/unixddef.mk @@ -0,0 +1,46 @@ +# +# FreeType 2 configuration rules templates for +# development under Unix with no configure script (gcc only) +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +TOP_DIR := $(shell cd $(TOP_DIR); pwd) +OBJ_DIR := $(shell cd $(OBJ_DIR); pwd) + +PLATFORM := unix + +DELETE := rm -f +CAT := cat +SEP := / + +# This is used for `make refdoc' and `make refdoc-venv' +# +BIN := bin + + +# library file name +# +LIBRARY := lib$(PROJECT) + + +# The directory where all library files are placed. +# +# By default, this is the same as $(OBJ_DIR); however, this can be changed +# to suit particular needs. +# +LIB_DIR := $(OBJ_DIR) + + +NO_OUTPUT := 2> /dev/null + +# EOF diff --git a/vendor/freetype/builds/vms/apinames_vms.bash b/vendor/freetype/builds/vms/apinames_vms.bash new file mode 100644 index 0000000..e9b1b72 --- /dev/null +++ b/vendor/freetype/builds/vms/apinames_vms.bash @@ -0,0 +1,2 @@ +src/tools/apinames -wV include/freetype/*.h > freetype_vms0.opt +mv freetype_vms0.opt freetype_vms.opt diff --git a/vendor/freetype/builds/vms/ftconfig.h b/vendor/freetype/builds/vms/ftconfig.h new file mode 100644 index 0000000..31dfcec --- /dev/null +++ b/vendor/freetype/builds/vms/ftconfig.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * + * ftconfig.h + * + * VMS-specific configuration file (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This header file contains a number of macro definitions that are used by + * the rest of the engine. Most of the macros here are automatically + * determined at compile time, and you should not need to change it to port + * FreeType, except to compile the library with a non-ANSI compiler. + * + * Note however that if some specific modifications are needed, we advise + * you to place a modified copy in your build directory. + * + * The build directory is usually `builds/`, and contains + * system-specific files that are always included first when building the + * library. + * + */ + +#ifndef FTCONFIG_H_ +#define FTCONFIG_H_ + +#include +#include FT_CONFIG_OPTIONS_H +#include FT_CONFIG_STANDARD_LIBRARY_H + +#define HAVE_UNISTD_H 1 +#define HAVE_FCNTL_H 1 + +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 + +#define FT_SIZEOF_INT 4 +#define FT_SIZEOF_LONG 4 + +#include +#include +#include + +#endif /* FTCONFIG_H_ */ + + +/* END */ diff --git a/vendor/freetype/builds/vms/ftsystem.c b/vendor/freetype/builds/vms/ftsystem.c new file mode 100644 index 0000000..0afd07d --- /dev/null +++ b/vendor/freetype/builds/vms/ftsystem.c @@ -0,0 +1,328 @@ +/***************************************************************************/ +/* */ +/* ftsystem.c */ +/* */ +/* VMS-specific FreeType low-level system interface (body). */ +/* */ +/* Copyright (C) 1996-2023 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include + /* we use our special ftconfig.h file, not the standard one */ +#include +#include +#include +#include +#include +#include + + /* memory-mapping includes and definitions */ +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#ifndef MAP_FILE +#define MAP_FILE 0x00 +#endif + +#ifdef MUNMAP_USES_VOIDP +#define MUNMAP_ARG_CAST void * +#else +#define MUNMAP_ARG_CAST char * +#endif + +#ifdef NEED_MUNMAP_DECL + +#ifdef __cplusplus + extern "C" +#else + extern +#endif + int + munmap( char* addr, + int len ); + +#define MUNMAP_ARG_CAST char * + +#endif /* NEED_DECLARATION_MUNMAP */ + + +#include +#include + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* MEMORY MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* ft_alloc */ + /* */ + /* */ + /* The memory allocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* size :: The requested size in bytes. */ + /* */ + /* */ + /* The address of newly allocated block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return malloc( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_realloc */ + /* */ + /* */ + /* The memory reallocation function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* cur_size :: The current size of the allocated memory block. */ + /* */ + /* new_size :: The newly requested size in bytes. */ + /* */ + /* block :: The current address of the block in memory. */ + /* */ + /* */ + /* The address of the reallocated memory block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return realloc( block, new_size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* ft_free */ + /* */ + /* */ + /* The memory release function. */ + /* */ + /* */ + /* memory :: A pointer to the memory object. */ + /* */ + /* block :: The address of block in memory to be freed. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + free( block ); + } + + + /*************************************************************************/ + /* */ + /* RESOURCE MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) + + + /*************************************************************************/ + /* */ + /* */ + /* ft_close_stream */ + /* */ + /* */ + /* The function to close a stream. */ + /* */ + /* */ + /* stream :: A pointer to the stream object. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_close_stream( FT_Stream stream ) + { + munmap( (MUNMAP_ARG_CAST)stream->descriptor.pointer, stream->size ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + int file; + struct stat stat_buf; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + + /* open the file */ + file = open( filepathname, O_RDONLY ); + if ( file < 0 ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + return FT_THROW( Cannot_Open_Resource ); + } + + if ( fstat( file, &stat_buf ) < 0 ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not `fstat' file `%s'\n", filepathname )); + goto Fail_Map; + } + + stream->size = stat_buf.st_size; + if ( !stream->size ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " opened `%s' but zero-sized\n", filepathname )); + goto Fail_Map; + } + + stream->pos = 0; + stream->base = (unsigned char *)mmap( NULL, + stream->size, + PROT_READ, + MAP_FILE | MAP_PRIVATE, + file, + 0 ); + + if ( stream->base == MAP_FAILED ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); + goto Fail_Map; + } + + close( file ); + + stream->descriptor.pointer = stream->base; + stream->pathname.pointer = (char*)filepathname; + + stream->close = ft_close_stream; + stream->read = NULL; + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + + Fail_Map: + close( file ); + + stream->base = NULL; + stream->size = 0; + stream->pos = 0; + + return FT_THROW( Cannot_Open_Stream ); + } + + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)malloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = NULL; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif + memory->free( memory, memory ); + } + + +/* END */ diff --git a/vendor/freetype/builds/wince/ftdebug.c b/vendor/freetype/builds/wince/ftdebug.c new file mode 100644 index 0000000..6453f8d --- /dev/null +++ b/vendor/freetype/builds/wince/ftdebug.c @@ -0,0 +1,353 @@ +/**************************************************************************** + * + * ftdebug.c + * + * Debugging and logging component for WinCE (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component contains various macros and functions used to ease the + * debugging of the FreeType engine. Its main purpose is in assertion + * checking, tracing, and error detection. + * + * There are now three debugging modes: + * + * - trace mode + * + * Error and trace messages are sent to the log file (which can be the + * standard error output). + * + * - error mode + * + * Only error messages are generated. + * + * - release mode: + * + * No error message is sent or generated. The code is free from any + * debugging parts. + * + */ + + +#include +#include + + +#ifdef FT_DEBUG_LEVEL_ERROR + +#include +#include +#include + +#include + + + static void + OutputDebugStringEx( const char* str ) + { + static WCHAR buf[8192]; + + int sz = MultiByteToWideChar( CP_ACP, 0, str, -1, buf, + sizeof ( buf ) / sizeof ( *buf ) ); + + + if ( !sz ) + lstrcpyW( buf, L"OutputDebugStringEx: MultiByteToWideChar failed" ); + + OutputDebugStringW( buf ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Message( const char* fmt, + ... ) + { + static char buf[8192]; + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + /* send the string to the debugger as well */ + vsprintf( buf, fmt, ap ); + OutputDebugStringEx( buf ); + va_end( ap ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Panic( const char* fmt, + ... ) + { + static char buf[8192]; + va_list ap; + + + va_start( ap, fmt ); + vsprintf( buf, fmt, ap ); + OutputDebugStringEx( buf ); + va_end( ap ); + + exit( EXIT_FAILURE ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( int ) + FT_Throw( FT_Error error, + int line, + const char* file ) + { +#if 0 + /* activating the code in this block makes FreeType very chatty */ + fprintf( stderr, + "%s:%d: error 0x%02x: %s\n", + file, + line, + error, + FT_Error_String( error ) ); +#else + FT_UNUSED( error ); + FT_UNUSED( line ); + FT_UNUSED( file ); +#endif + + return 0; + } + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* array of trace levels, initialized to 0; */ + /* this gets adjusted at run-time */ + static int ft_trace_levels_enabled[trace_count]; + + /* array of trace levels, always initialized to 0 */ + static int ft_trace_levels_disabled[trace_count]; + + /* a pointer to either `ft_trace_levels_enabled' */ + /* or `ft_trace_levels_disabled' */ + int* ft_trace_levels; + + /* define array of trace toggle names */ +#define FT_TRACE_DEF( x ) #x , + + static const char* ft_trace_toggles[trace_count + 1] = + { +#include + NULL + }; + +#undef FT_TRACE_DEF + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return trace_count; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + int max = FT_Trace_Get_Count(); + + + if ( idx < max ) + return ft_trace_toggles[idx]; + else + return NULL; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + ft_trace_levels = ft_trace_levels_disabled; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + ft_trace_levels = ft_trace_levels_enabled; + } + + + /************************************************************************** + * + * Initialize the tracing sub-system. This is done by retrieving the + * value of the `FT2_DEBUG' environment variable. It must be a list of + * toggles, separated by spaces, `;', or `,'. Example: + * + * export FT2_DEBUG="any:3 memory:7 stream:5" + * + * This requests that all levels be set to 3, except the trace level for + * the memory and stream components which are set to 7 and 5, + * respectively. + * + * See the file `include/freetype/internal/fttrace.h' for details of + * the available toggle names. + * + * The level must be between 0 and 7; 0 means quiet (except for serious + * runtime errors), and 7 means _very_ verbose. + */ + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + /* Windows Mobile doesn't have environment API: */ + /* GetEnvironmentStrings, GetEnvironmentVariable, getenv. */ + /* */ + /* FIXME!!! How to set debug mode? */ + + /* const char* ft2_debug = getenv( "FT2_DEBUG" ); */ + + const char* ft2_debug = NULL; + + + if ( ft2_debug ) + { + const char* p = ft2_debug; + const char* q; + + + for ( ; *p; p++ ) + { + /* skip leading whitespace and separators */ + if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' ) + continue; + + /* read toggle name, followed by ':' */ + q = p; + while ( *p && *p != ':' ) + p++; + + if ( !*p ) + break; + + if ( *p == ':' && p > q ) + { + FT_Int n, i, len = (FT_Int)( p - q ); + FT_Int level = -1, found = -1; + + + for ( n = 0; n < trace_count; n++ ) + { + const char* toggle = ft_trace_toggles[n]; + + + for ( i = 0; i < len; i++ ) + { + if ( toggle[i] != q[i] ) + break; + } + + if ( i == len && toggle[i] == 0 ) + { + found = n; + break; + } + } + + /* read level */ + p++; + if ( *p ) + { + level = *p - '0'; + if ( level < 0 || level > 7 ) + level = -1; + } + + if ( found >= 0 && level >= 0 ) + { + if ( found == trace_any ) + { + /* special case for `any' */ + for ( n = 0; n < trace_count; n++ ) + ft_trace_levels_enabled[n] = level; + } + else + ft_trace_levels_enabled[found] = level; + } + } + } + } + + ft_trace_levels = ft_trace_levels_enabled; + } + + +#else /* !FT_DEBUG_LEVEL_TRACE */ + + + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + /* nothing */ + } + + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return 0; + } + + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + FT_UNUSED( idx ); + + return NULL; + } + + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + /* nothing */ + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + /* nothing */ + } + + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +/* END */ diff --git a/vendor/freetype/builds/wince/vc2005-ce/freetype.vcproj b/vendor/freetype/builds/wince/vc2005-ce/freetype.vcproj new file mode 100644 index 0000000..238ffc6 --- /dev/null +++ b/vendor/freetype/builds/wince/vc2005-ce/freetype.vcproj @@ -0,0 +1,878 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/freetype/builds/wince/vc2005-ce/index.html b/vendor/freetype/builds/wince/vc2005-ce/index.html new file mode 100644 index 0000000..8ea6cfd --- /dev/null +++ b/vendor/freetype/builds/wince/vc2005-ce/index.html @@ -0,0 +1,47 @@ + +

    + + FreeType 2 Project Files for VS.NET 2005 + (Pocket PC) + + + +

    + FreeType 2 Project Files for VS.NET 2005 + (Pocket PC) +

    + +

    This directory contains project files for Visual C++, named +freetype.vcproj, and Visual Studio, called freetype.sln for +the following targets: + +

      +
    • PPC/SP 2003 (Pocket PC 2003)
    • +
    • PPC/SP WM5 (Windows Mobile 5)
    • +
    • PPC/SP WM6 (Windows Mobile 6)
    • +
    + +It compiles the following libraries from the FreeType 2.13.2 sources:

    + +
      +
      +    freetype.lib     - release build; single threaded
      +    freetype_D.lib   - debug build;   single threaded
      +    freetypeMT.lib   - release build; multi-threaded
      +    freetypeMT_D.lib - debug build;   multi-threaded
      +
    + +

    Be sure to extract the files with the Windows (CR+LF) line endings. ZIP +archives are already stored this way, so no further action is required. If +you use some .tar.*z archives, be sure to configure your extracting +tool to convert the line endings. For example, with WinZip, you should activate the TAR +file smart CR/LF Conversion option. Alternatively, you may consider +using the unix2dos or u2d utilities that are floating +around, which specifically deal with this particular problem. + +

    Build directories are placed in the top-level objs +directory.

    + + + diff --git a/vendor/freetype/builds/wince/vc2008-ce/freetype.vcproj b/vendor/freetype/builds/wince/vc2008-ce/freetype.vcproj new file mode 100644 index 0000000..8404684 --- /dev/null +++ b/vendor/freetype/builds/wince/vc2008-ce/freetype.vcproj @@ -0,0 +1,3517 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/freetype/builds/wince/vc2008-ce/index.html b/vendor/freetype/builds/wince/vc2008-ce/index.html new file mode 100644 index 0000000..a6e74f8 --- /dev/null +++ b/vendor/freetype/builds/wince/vc2008-ce/index.html @@ -0,0 +1,47 @@ + +
    + + FreeType 2 Project Files for VS.NET 2008 + (Pocket PC) + + + +

    + FreeType 2 Project Files for VS.NET 2008 + (Pocket PC) +

    + +

    This directory contains project files for Visual C++, named +freetype.dsp, and Visual Studio, called freetype.sln for +the following targets: + +

      +
    • PPC/SP 2003 (Pocket PC 2003)
    • +
    • PPC/SP WM5 (Windows Mobile 5)
    • +
    • PPC/SP WM6 (Windows Mobile 6)
    • +
    + +It compiles the following libraries from the FreeType 2.13.2 sources:

    + +
      +
      +    freetype.lib     - release build; single threaded
      +    freetype_D.lib   - debug build;   single threaded
      +    freetypeMT.lib   - release build; multi-threaded
      +    freetypeMT_D.lib - debug build;   multi-threaded
      +
    + +

    Be sure to extract the files with the Windows (CR+LF) line endings. ZIP +archives are already stored this way, so no further action is required. If +you use some .tar.*z archives, be sure to configure your extracting +tool to convert the line endings. For example, with WinZip, you should activate the TAR +file smart CR/LF Conversion option. Alternatively, you may consider +using the unix2dos or u2d utilities that are floating +around, which specifically deal with this particular problem. + +

    Build directories are placed in the top-level objs +directory.

    + + + diff --git a/vendor/freetype/builds/windows/.gitignore b/vendor/freetype/builds/windows/.gitignore new file mode 100644 index 0000000..41456a4 --- /dev/null +++ b/vendor/freetype/builds/windows/.gitignore @@ -0,0 +1,5 @@ +# user-specific cache/settings files +*.opensdf +*.sdf +*.suo +*.user diff --git a/vendor/freetype/builds/windows/detect.mk b/vendor/freetype/builds/windows/detect.mk new file mode 100644 index 0000000..d7908be --- /dev/null +++ b/vendor/freetype/builds/windows/detect.mk @@ -0,0 +1,202 @@ +# +# FreeType 2 configuration file to detect a Win32 host platform. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +.PHONY: setup + + +ifeq ($(PLATFORM),ansi) + + # Detecting Windows NT is easy, as the OS variable must be defined and + # contains `Windows_NT'. This also works with Windows 2000 and XP. + # + ifeq ($(OS),Windows_NT) + + PLATFORM := windows + + else + + # Detecting Windows 9X + + # We used to run the `ver' command to see if its output contains the + # word `Windows'. If this is true, we are running Windows 95 or later: + # + # ifdef COMSPEC + # # First, check if we have the COMSPEC environment variable, which + # # indicates we can use COMMAND.COM's internal commands + # is_windows := $(findstring Windows,$(strip $(shell ver))) + # endif + # + # Unfortunately, this also detects the case when one is running + # DOS 7.x (the MS-DOS version that lies below Windows) without actually + # launching the GUI. + # + # A better test is to check whether there are both the environment + # variables `winbootdir' and `windir'. The first indicates an + # underlying DOS 7.x, while the second is set only if windows is + # available. + # + # Note that on Windows NT, such an environment variable will not be seen + # from DOS-based tools like DJGPP's make; this is not actually a problem + # since NT is detected independently above. But do not try to be clever! + # + ifdef winbootdir + ifdef windir + + PLATFORM := windows + + endif + endif + + endif # test NT + +endif # test PLATFORM ansi + +ifeq ($(PLATFORM),windows) + + DELETE := del + CAT := type + SEP := $(BACKSLASH) + + # Setting COPY is a bit trickier. Plain COPY on NT will not work + # correctly, because it will uppercase 8.3 filenames, creating a + # `CONFIG.MK' file which isn't found later on by `make'. + # Since we do not want that, we need to force execution of CMD.EXE. + # Unfortunately, CMD.EXE is not available on Windows 9X. + # So we need to hack. + # + # Kudos to Eli Zaretskii (DJGPP guru) that helped debug it. + # Details are available in threads of the FreeType mailing list + # (2004-11-11), and then in the devel mailing list (2004-11-20 to -23). + # + ifeq ($(OS),Windows_NT) + COPY := >nul cmd.exe /c copy + else + COPY := >nul copy + endif # test NT + + + # gcc Makefile by default + CONFIG_FILE := w32-gcc.mk + ifeq ($(firstword $(CC)),cc) + CC := gcc + endif + + ifneq ($(findstring list,$(MAKECMDGOALS)),) # test for the "list" target + dump_target_list: + $(info ) + $(info $(PROJECT_TITLE) build system -- supported compilers) + $(info ) + $(info Several command-line compilers are supported on Win32:) + $(info ) + $(info $(empty) make setup gcc (with Mingw)) + $(info $(empty) make setup visualc Microsoft Visual C++) + $(info $(empty) make setup bcc32 Borland C/C++) + $(info $(empty) make setup lcc Win32-LCC) + $(info $(empty) make setup intelc Intel C/C++) + $(info ) + + setup: dump_target_list + .PHONY: dump_target_list list + else + setup: std_setup + endif + + # additionally, we provide hooks for various other compilers + # + ifneq ($(findstring visualc,$(MAKECMDGOALS)),) # Visual C/C++ + CONFIG_FILE := w32-vcc.mk + CC := cl + + .PHONY: visualc + visualc: setup + @cd . + endif + + ifneq ($(findstring intelc,$(MAKECMDGOALS)),) # Intel C/C++ + CONFIG_FILE := w32-intl.mk + CC := cl + + .PHONY: intelc + visualc: setup + @cd . + endif + + ifneq ($(findstring watcom,$(MAKECMDGOALS)),) # Watcom C/C++ + CONFIG_FILE := w32-wat.mk + CC := wcc386 + + .PHONY: watcom + watcom: setup + @cd . + endif + + ifneq ($(findstring visualage,$(MAKECMDGOALS)),) # Visual Age C++ + CONFIG_FILE := w32-icc.mk + CC := icc + + .PHONY: visualage + visualage: setup + @cd . + endif + + ifneq ($(findstring lcc,$(MAKECMDGOALS)),) # LCC-Win32 + CONFIG_FILE := w32-lcc.mk + CC := lcc + + .PHONY: lcc + lcc: setup + @cd . + endif + + ifneq ($(findstring mingw32,$(MAKECMDGOALS)),) # mingw32 + CONFIG_FILE := w32-mingw32.mk + CC := gcc + + .PHONY: mingw32 + mingw32: setup + @cd . + endif + + ifneq ($(findstring bcc32,$(MAKECMDGOALS)),) # Borland C++ + CONFIG_FILE := w32-bcc.mk + CC := bcc32 + + .PHONY: bcc32 + bcc32: setup + @cd . + endif + + ifneq ($(findstring devel-bcc,$(MAKECMDGOALS)),) # development target + CONFIG_FILE := w32-bccd.mk + CC := bcc32 + + .PHONY: devel-bcc + devel-bcc: setup + @cd . + endif + + ifneq ($(findstring devel-gcc,$(MAKECMDGOALS)),) # development target + CONFIG_FILE := w32-dev.mk + CC := gcc + + .PHONY: devel-gcc + devel-gcc: setup + @cd . + endif + +endif # test PLATFORM windows + + +# EOF diff --git a/vendor/freetype/builds/windows/ftdebug.c b/vendor/freetype/builds/windows/ftdebug.c new file mode 100644 index 0000000..360f8c7 --- /dev/null +++ b/vendor/freetype/builds/windows/ftdebug.c @@ -0,0 +1,698 @@ +/**************************************************************************** + * + * ftdebug.c + * + * Debugging and logging component for Win32 (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component contains various macros and functions used to ease the + * debugging of the FreeType engine. Its main purpose is in assertion + * checking, tracing, and error detection. + * + * There are now three debugging modes: + * + * - trace mode + * + * Error and trace messages are sent to the log file (which can be the + * standard error output). + * + * - error mode + * + * Only error messages are generated. + * + * - release mode: + * + * No error message is sent or generated. The code is free from any + * debugging parts. + * + */ + + +#include +#include +#include +#include + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Variables used to control logging. + * + * 1. `ft_default_trace_level` stores the value of trace levels, which are + * provided to FreeType using the `FT2_DEBUG` environment variable. + * + * 2. `ft_fileptr` stores the `FILE*` handle. + * + * 3. `ft_component` is a string that holds the name of `FT_COMPONENT`. + * + * 4. The flag `ft_component_flag` prints the name of `FT_COMPONENT` along + * with the actual log message if set to true. + * + * 5. The flag `ft_timestamp_flag` prints time along with the actual log + * message if set to ture. + * + * 6. `ft_have_newline_char` is used to differentiate between a log + * message with and without a trailing newline character. + * + * 7. `ft_custom_trace_level` stores the custom trace level value, which + * is provided by the user at run-time. + * + * We use `static` to avoid 'unused variable' warnings. + * + */ + static const char* ft_default_trace_level = NULL; + static FILE* ft_fileptr = NULL; + static const char* ft_component = NULL; + static FT_Bool ft_component_flag = FALSE; + static FT_Bool ft_timestamp_flag = FALSE; + static FT_Bool ft_have_newline_char = TRUE; + static const char* ft_custom_trace_level = NULL; + + /* declared in ftdebug.h */ + + dlg_handler ft_default_log_handler = NULL; + FT_Custom_Log_Handler custom_output_handler = NULL; + +#endif /* FT_DEBUG_LOGGING */ + + +#ifdef FT_DEBUG_LEVEL_ERROR + +#define WIN32_LEAN_AND_MEAN +#include + + +#ifdef _WIN32_WCE + + FT_LOACAL_DEF( void ) + OutputDebugStringA( LPCSTR lpOutputString ) + { + int len; + LPWSTR lpOutputStringW; + + + /* allocate memory space for converted string */ + len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, + lpOutputString, -1, NULL, 0 ); + + lpOutputStringW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) ); + + if ( !len || !lpOutputStringW ) + return; + + /* now it is safe to do the translation */ + MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, + lpOutputString, -1, lpOutputStringW, len ); + + OutputDebugStringW( lpOutputStringW ); + } + +#endif /* _WIN32_WCE */ + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Message( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); +#if ( defined( _WIN32_WINNT ) && _WIN32_WINNT >= 0x0400 ) || \ + ( defined( _WIN32_WCE ) && _WIN32_WCE >= 0x0600 ) + if ( IsDebuggerPresent() ) + { + static char buf[1024]; + + + vsnprintf( buf, sizeof buf, fmt, ap ); + OutputDebugStringA( buf ); + } +#endif + va_end( ap ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Panic( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); +#if ( defined( _WIN32_WINNT ) && _WIN32_WINNT >= 0x0400 ) || \ + ( defined( _WIN32_WCE ) && _WIN32_WCE >= 0x0600 ) + if ( IsDebuggerPresent() ) + { + static char buf[1024]; + + + vsnprintf( buf, sizeof buf, fmt, ap ); + OutputDebugStringA( buf ); + } +#endif + va_end( ap ); + + exit( EXIT_FAILURE ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( int ) + FT_Throw( FT_Error error, + int line, + const char* file ) + { +#if 0 + /* activating the code in this block makes FreeType very chatty */ + fprintf( stderr, + "%s:%d: error 0x%02x: %s\n", + file, + line, + error, + FT_Error_String( error ) ); +#else + FT_UNUSED( error ); + FT_UNUSED( line ); + FT_UNUSED( file ); +#endif + + return 0; + } + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* array of trace levels, initialized to 0; */ + /* this gets adjusted at run-time */ + static int ft_trace_levels_enabled[trace_count]; + + /* array of trace levels, always initialized to 0 */ + static int ft_trace_levels_disabled[trace_count]; + + /* a pointer to either `ft_trace_levels_enabled' */ + /* or `ft_trace_levels_disabled' */ + int* ft_trace_levels; + + /* define array of trace toggle names */ +#define FT_TRACE_DEF( x ) #x , + + static const char* ft_trace_toggles[trace_count + 1] = + { +#include + NULL + }; + +#undef FT_TRACE_DEF + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return trace_count; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + int max = FT_Trace_Get_Count(); + + + if ( idx < max ) + return ft_trace_toggles[idx]; + else + return NULL; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + ft_trace_levels = ft_trace_levels_disabled; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + ft_trace_levels = ft_trace_levels_enabled; + } + + + /************************************************************************** + * + * Initialize the tracing sub-system. This is done by retrieving the + * value of the `FT2_DEBUG' environment variable. It must be a list of + * toggles, separated by spaces, `;', or `,'. Example: + * + * export FT2_DEBUG="any:3 memory:7 stream:5" + * + * This requests that all levels be set to 3, except the trace level for + * the memory and stream components which are set to 7 and 5, + * respectively. + * + * See the file `include/freetype/internal/fttrace.h' for details of + * the available toggle names. + * + * The level must be between 0 and 7; 0 means quiet (except for serious + * runtime errors), and 7 means _very_ verbose. + */ + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + const char* ft2_debug = NULL; + + +#ifdef FT_DEBUG_LOGGING + if ( ft_custom_trace_level != NULL ) + ft2_debug = ft_custom_trace_level; + else + ft2_debug = ft_default_trace_level; +#else + ft2_debug = ft_getenv( "FT2_DEBUG" ); +#endif + + if ( ft2_debug ) + { + const char* p = ft2_debug; + const char* q; + + + for ( ; *p; p++ ) + { + /* skip leading whitespace and separators */ + if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' ) + continue; + +#ifdef FT_DEBUG_LOGGING + + /* check extra arguments for logging */ + if ( *p == '-' ) + { + const char* r = ++p; + + + if ( *r == 'v' ) + { + const char* s = ++r; + + + ft_component_flag = TRUE; + + if ( *s == 't' ) + { + ft_timestamp_flag = TRUE; + p++; + } + + p++; + } + + else if ( *r == 't' ) + { + const char* s = ++r; + + + ft_timestamp_flag = TRUE; + + if ( *s == 'v' ) + { + ft_component_flag = TRUE; + p++; + } + + p++; + } + } + +#endif /* FT_DEBUG_LOGGING */ + + /* read toggle name, followed by ':' */ + q = p; + while ( *p && *p != ':' ) + p++; + + if ( !*p ) + break; + + if ( *p == ':' && p > q ) + { + FT_Int n, i, len = (FT_Int)( p - q ); + FT_Int level = -1, found = -1; + + + for ( n = 0; n < trace_count; n++ ) + { + const char* toggle = ft_trace_toggles[n]; + + + for ( i = 0; i < len; i++ ) + { + if ( toggle[i] != q[i] ) + break; + } + + if ( i == len && toggle[i] == 0 ) + { + found = n; + break; + } + } + + /* read level */ + p++; + if ( *p ) + { + level = *p - '0'; + if ( level < 0 || level > 7 ) + level = -1; + } + + if ( found >= 0 && level >= 0 ) + { + if ( found == trace_any ) + { + /* special case for `any' */ + for ( n = 0; n < trace_count; n++ ) + ft_trace_levels_enabled[n] = level; + } + else + ft_trace_levels_enabled[found] = level; + } + } + } + } + + ft_trace_levels = ft_trace_levels_enabled; + } + + +#else /* !FT_DEBUG_LEVEL_TRACE */ + + + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + /* nothing */ + } + + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return 0; + } + + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + FT_UNUSED( idx ); + + return NULL; + } + + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + /* nothing */ + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Initialize and de-initialize 'dlg' library. + * + */ + + FT_BASE_DEF( void ) + ft_logging_init( void ) + { + ft_default_log_handler = ft_log_handler; + ft_default_trace_level = ft_getenv( "FT2_DEBUG" ); + + if ( ft_getenv( "FT_LOGGING_FILE" ) ) + ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" ); + else + ft_fileptr = stderr; + + ft_debug_init(); + + /* Set the default output handler for 'dlg'. */ + dlg_set_handler( ft_default_log_handler, NULL ); + } + + + FT_BASE_DEF( void ) + ft_logging_deinit( void ) + { + if ( ft_fileptr != stderr ) + ft_fclose( ft_fileptr ); + } + + + /************************************************************************** + * + * An output log handler for FreeType. + * + */ + FT_BASE_DEF( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ) + { + char features_buf[128]; + char* bufp = features_buf; + + FT_UNUSED( data ); + + + if ( ft_have_newline_char ) + { + const char* features = NULL; + size_t features_length = 0; + + +#define FEATURES_TIMESTAMP "[%h:%m] " +#define FEATURES_COMPONENT "[%t] " +#define FEATURES_TIMESTAMP_COMPONENT "[%h:%m %t] " + + if ( ft_timestamp_flag && ft_component_flag ) + { + features = FEATURES_TIMESTAMP_COMPONENT; + features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT ); + } + else if ( ft_timestamp_flag ) + { + features = FEATURES_TIMESTAMP; + features_length = sizeof ( FEATURES_TIMESTAMP ); + } + else if ( ft_component_flag ) + { + features = FEATURES_COMPONENT; + features_length = sizeof ( FEATURES_COMPONENT ); + } + + if ( ft_component_flag || ft_timestamp_flag ) + { + ft_strncpy( features_buf, features, features_length ); + bufp += features_length - 1; + } + + if ( ft_component_flag ) + { + size_t tag_length = ft_strlen( *origin->tags ); + size_t i; + + + /* To vertically align tracing messages we compensate the */ + /* different FT_COMPONENT string lengths by inserting an */ + /* appropriate amount of space characters. */ + for ( i = 0; + i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length; + i++ ) + *bufp++ = ' '; + } + } + + /* Finally add the format string for the tracing message. */ + *bufp++ = '%'; + *bufp++ = 'c'; + *bufp = '\0'; + + dlg_generic_outputf_stream( ft_fileptr, + (const char*)features_buf, + origin, + string, + dlg_default_output_styles, + true ); + + if ( ft_strrchr( string, '\n' ) ) + ft_have_newline_char = TRUE; + else + ft_have_newline_char = FALSE; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_add_tag( const char* tag ) + { + ft_component = tag; + + dlg_add_tag( tag, NULL ); + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_remove_tag( const char* tag ) + { + dlg_remove_tag( tag, NULL ); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = level; + + ft_debug_init(); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = NULL; + + ft_debug_init(); + } + + + /************************************************************************** + * + * Functions to handle a custom log handler. + * + */ + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + custom_output_handler = handler; + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + custom_output_handler = NULL; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + FT_Logging_Callback( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + custom_output_handler( ft_component, fmt, ap ); + va_end( ap ); + } + +#else /* !FT_DEBUG_LOGGING */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + FT_UNUSED( level ); + } + + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + /* nothing */ + } + + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + FT_UNUSED( handler ); + } + + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LOGGING */ + + +/* END */ diff --git a/vendor/freetype/builds/windows/ftsystem.c b/vendor/freetype/builds/windows/ftsystem.c new file mode 100644 index 0000000..418d799 --- /dev/null +++ b/vendor/freetype/builds/windows/ftsystem.c @@ -0,0 +1,499 @@ +/**************************************************************************** + * + * ftsystem.c + * + * Windows-specific FreeType low-level system interface (body). + * + * Copyright (C) 2021-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + /* we use our special ftconfig.h file, not the standard one */ +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include + + /* memory mapping and allocation includes and definitions */ +#define WIN32_LEAN_AND_MEAN +#include + + + /************************************************************************** + * + * MEMORY MANAGEMENT INTERFACE + * + */ + + + /************************************************************************** + * + * It is not necessary to do any error checking for the + * allocation-related functions. This will be done by the higher level + * routines like ft_mem_alloc() or ft_mem_realloc(). + * + */ + + + /************************************************************************** + * + * @Function: + * ft_alloc + * + * @Description: + * The memory allocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * size :: + * The requested size in bytes. + * + * @Return: + * The address of newly allocated block. + */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + return HeapAlloc( memory->user, 0, size ); + } + + + /************************************************************************** + * + * @Function: + * ft_realloc + * + * @Description: + * The memory reallocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * cur_size :: + * The current size of the allocated memory block. + * + * new_size :: + * The newly requested size in bytes. + * + * block :: + * The current address of the block in memory. + * + * @Return: + * The address of the reallocated memory block. + */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( cur_size ); + + return HeapReAlloc( memory->user, 0, block, new_size ); + } + + + /************************************************************************** + * + * @Function: + * ft_free + * + * @Description: + * The memory release function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * block :: + * The address of block in memory to be freed. + */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + HeapFree( memory->user, 0, block ); + } + + + /************************************************************************** + * + * RESOURCE MANAGEMENT INTERFACE + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) + + + /************************************************************************** + * + * @Function: + * ft_close_stream_by_munmap + * + * @Description: + * The function to close a stream which is opened by mmap. + * + * @Input: + * stream :: A pointer to the stream object. + */ + FT_CALLBACK_DEF( void ) + ft_close_stream_by_munmap( FT_Stream stream ) + { + UnmapViewOfFile( (LPCVOID)stream->descriptor.pointer ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /************************************************************************** + * + * @Function: + * ft_close_stream_by_free + * + * @Description: + * The function to close a stream which is created by ft_alloc. + * + * @Input: + * stream :: A pointer to the stream object. + */ + FT_CALLBACK_DEF( void ) + ft_close_stream_by_free( FT_Stream stream ) + { + ft_free( stream->memory, stream->descriptor.pointer ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /* non-desktop Universal Windows Platform */ +#if defined( WINAPI_FAMILY ) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP + +#define PACK_DWORD64( hi, lo ) ( ( (DWORD64)(hi) << 32 ) | (DWORD)(lo) ) + +#define CreateFileMapping( a, b, c, d, e, f ) \ + CreateFileMappingFromApp( a, b, c, PACK_DWORD64( d, e ), f ) +#define MapViewOfFile( a, b, c, d, e ) \ + MapViewOfFileFromApp( a, b, PACK_DWORD64( c, d ), e ) + + FT_LOCAL_DEF( HANDLE ) + CreateFileA( LPCSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile ) + { + int len; + LPWSTR lpFileNameW; + + CREATEFILE2_EXTENDED_PARAMETERS createExParams = { + sizeof ( CREATEFILE2_EXTENDED_PARAMETERS ), + dwFlagsAndAttributes & 0x0000FFFF, + dwFlagsAndAttributes & 0xFFF00000, + dwFlagsAndAttributes & 0x000F0000, + lpSecurityAttributes, + hTemplateFile }; + + + /* allocate memory space for converted path name */ + len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, + lpFileName, -1, NULL, 0 ); + + lpFileNameW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) ); + + if ( !len || !lpFileNameW ) + { + FT_ERROR(( "FT_Stream_Open: cannot convert file name to LPWSTR\n" )); + return INVALID_HANDLE_VALUE; + } + + /* now it is safe to do the translation */ + MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, + lpFileName, -1, lpFileNameW, len ); + + /* open the file */ + return CreateFile2( lpFileNameW, dwDesiredAccess, dwShareMode, + dwCreationDisposition, &createExParams ); + } + +#endif + + +#if defined( _WIN32_WCE ) + + /* malloc.h provides implementation of alloca()/_alloca() */ + #include + + FT_LOCAL_DEF( HANDLE ) + CreateFileA( LPCSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile ) + { + int len; + LPWSTR lpFileNameW; + + + /* allocate memory space for converted path name */ + len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, + lpFileName, -1, NULL, 0 ); + + lpFileNameW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) ); + + if ( !len || !lpFileNameW ) + { + FT_ERROR(( "FT_Stream_Open: cannot convert file name to LPWSTR\n" )); + return INVALID_HANDLE_VALUE; + } + + /* now it is safe to do the translation */ + MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, + lpFileName, -1, lpFileNameW, len ); + + /* open the file */ + return CreateFileW( lpFileNameW, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile ); + } + +#endif + + +#if defined( _WIN32_WCE ) || defined ( _WIN32_WINDOWS ) || \ + !defined( _WIN32_WINNT ) || _WIN32_WINNT <= 0x0400 + + FT_LOCAL_DEF( BOOL ) + GetFileSizeEx( HANDLE hFile, + PLARGE_INTEGER lpFileSize ) + { + lpFileSize->u.LowPart = GetFileSize( hFile, + (DWORD *)&lpFileSize->u.HighPart ); + + if ( lpFileSize->u.LowPart == INVALID_FILE_SIZE && + GetLastError() != NO_ERROR ) + return FALSE; + else + return TRUE; + } + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + HANDLE file; + HANDLE fm; + LARGE_INTEGER size; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + + /* open the file */ + file = CreateFileA( (LPCSTR)filepathname, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); + if ( file == INVALID_HANDLE_VALUE ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + return FT_THROW( Cannot_Open_Resource ); + } + + if ( GetFileSizeEx( file, &size ) == FALSE ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not retrieve size of file `%s'\n", filepathname )); + goto Fail_Open; + } + + /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */ + /* So avoid overflow caused by fonts in huge files larger than */ + /* 2GB, do a test. */ + if ( size.QuadPart > LONG_MAX ) + { + FT_ERROR(( "FT_Stream_Open: file is too big\n" )); + goto Fail_Open; + } + else if ( size.QuadPart == 0 ) + { + FT_ERROR(( "FT_Stream_Open: zero-length file\n" )); + goto Fail_Open; + } + + fm = CreateFileMapping( file, NULL, PAGE_READONLY, 0, 0, NULL ); + if ( fm == NULL ) + { + FT_ERROR(( "FT_Stream_Open: can not map file\n" )); + goto Fail_Open; + } + + /* Store only the low part of this 64 bits integer because long is */ + /* a 32 bits type. Anyway, a check has been done above to forbid */ + /* a size greater than LONG_MAX */ + stream->size = size.LowPart; + stream->pos = 0; + stream->base = (unsigned char *) + MapViewOfFile( fm, FILE_MAP_READ, 0, 0, 0 ); + + CloseHandle( fm ); + + if ( stream->base != NULL ) + stream->close = ft_close_stream_by_munmap; + else + { + DWORD total_read_count; + + + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); + + stream->base = (unsigned char*)ft_alloc( stream->memory, stream->size ); + + if ( !stream->base ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not `alloc' memory\n" )); + goto Fail_Open; + } + + total_read_count = 0; + do + { + DWORD read_count; + + + if ( ReadFile( file, + stream->base + total_read_count, + stream->size - total_read_count, + &read_count, NULL ) == FALSE ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); + goto Fail_Read; + } + + total_read_count += read_count; + + } while ( total_read_count != stream->size ); + + stream->close = ft_close_stream_by_free; + } + + CloseHandle( file ); + + stream->descriptor.pointer = stream->base; + stream->pathname.pointer = (char*)filepathname; + + stream->read = NULL; + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + + Fail_Read: + ft_free( stream->memory, stream->base ); + + Fail_Open: + CloseHandle( file ); + + stream->base = NULL; + stream->size = 0; + stream->pos = 0; + + return FT_THROW( Cannot_Open_Stream ); + } + + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + HANDLE heap; + FT_Memory memory; + + + heap = GetProcessHeap(); + memory = heap ? (FT_Memory)HeapAlloc( heap, 0, sizeof ( *memory ) ) + : NULL; + + if ( memory ) + { + memory->user = heap; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif + memory->free( memory, memory ); + } + + +/* END */ diff --git a/vendor/freetype/builds/windows/vc2010/freetype.user.props b/vendor/freetype/builds/windows/vc2010/freetype.user.props new file mode 100644 index 0000000..78310d4 --- /dev/null +++ b/vendor/freetype/builds/windows/vc2010/freetype.user.props @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/freetype/builds/windows/vc2010/index.html b/vendor/freetype/builds/windows/vc2010/index.html new file mode 100644 index 0000000..ee9b59a --- /dev/null +++ b/vendor/freetype/builds/windows/vc2010/index.html @@ -0,0 +1,40 @@ + +
    + + FreeType 2 Project Files for Visual C++ 2010 or newer + + + +

    + FreeType 2 Project Files for Visual C++ 2010 or newer +

    + +

    This directory contains solution and project files for +Visual C++ 2010 or newer, named freetype.sln, +and freetype.vcxproj. It compiles the following libraries +from the FreeType 2.13.2 sources:

    + +
      +
    • freetype.dll using 'Release' or 'Debug' configurations
    • +
    • freetype.lib using 'Release Static' or 'Debug Static' configurations
    • +
    + +

    Both Win32 and x64 builds are supported. Build directories and target +files are placed in the top-level objs directory.

    + +

    Customization of the FreeType library is done by editing the +ftoption.h header file in the top-level devel path. +Alternatively, you may copy the file to another directory and change the +include directory in freetype.users.props.

    + +

    To configure library dependencies like zlib and libpng, +edit the freetype.users.props file in this directory. It also +simplifies automated (command-line) builds using msbuild.

    + +

    To link your executable with FreeType DLL, you may want to define +DLL_IMPORT so that the imported functions are appropriately +attributed with dllimport.

    + + + diff --git a/vendor/freetype/builds/windows/visualc/freetype.dsp b/vendor/freetype/builds/windows/visualc/freetype.dsp new file mode 100644 index 0000000..451fab2 --- /dev/null +++ b/vendor/freetype/builds/windows/visualc/freetype.dsp @@ -0,0 +1,354 @@ +# Microsoft Developer Studio Project File - Name="freetype" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=freetype - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "freetype.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "freetype.mak" CFG="freetype - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "freetype - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "freetype - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "freetype - Win32 Release Static" (based on "Win32 (x86) Static Library") +!MESSAGE "freetype - Win32 Debug Static" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "freetype - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\objs\Win32\Release" +# PROP Intermediate_Dir "..\..\..\objs\Win32\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /Za /MD /W3 /O2 /Oi /D "WIN32" /I "..\..\..\include" /D "_CRT_SECURE_NO_WARNINGS" /D "NDEBUG" /D "FT2_BUILD_LIBRARY" /D "DLL_EXPORT" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" /d "DLL_EXPORT" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /dll /machine:I386 /opt:REF,ICF /out:"$(OutDir)\freetype.dll" + +!ELSEIF "$(CFG)" == "freetype - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\objs\Win32\Debug" +# PROP Intermediate_Dir "..\..\..\objs\Win32\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /Za /MDd /W3 /Gm /ZI /Od /I "..\..\..\include" /D "WIN32" /D "_CRT_SECURE_NO_WARNINGS" /D "_DEBUG" /D "FT_DEBUG_LEVEL_ERROR" /D "FT_DEBUG_LEVEL_TRACE" /D "FT2_BUILD_LIBRARY" /D "DLL_EXPORT" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "DLL_EXPORT" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /debug /machine:I386 /out:"$(OutDir)\freetype.dll" /pdbtype:sept + +!ELSEIF "$(CFG)" == "freetype - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release Static" +# PROP BASE Intermediate_Dir "Release Static" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\objs\Win32\Release Static" +# PROP Intermediate_Dir "..\..\..\objs\Win32\Release Static" +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /Za /MD /W3 /O2 /Oi /D "WIN32" /I "..\..\..\include" /D "_CRT_SECURE_NO_WARNINGS" /D "NDEBUG" /D "FT2_BUILD_LIBRARY" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"$(OutDir)\freetype.lib" + +!ELSEIF "$(CFG)" == "freetype - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug Static" +# PROP BASE Intermediate_Dir "Debug Static" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\objs\Win32\Debug Static" +# PROP Intermediate_Dir "..\..\..\objs\Win32\Debug Static" +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /Za /MDd /W3 /Gm /ZI /Od /I "..\..\..\include" /D "WIN32" /D "_CRT_SECURE_NO_WARNINGS" /D "_DEBUG" /D "FT_DEBUG_LEVEL_ERROR" /D "FT_DEBUG_LEVEL_TRACE" /D "FT2_BUILD_LIBRARY" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"$(OutDir)\freetype.lib" + +!ENDIF + +# Begin Target + +# Name "freetype - Win32 Release" +# Name "freetype - Win32 Debug" +# Name "freetype - Win32 Release Static" +# Name "freetype - Win32 Debug Static" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\autofit\autofit.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\bdf\bdf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cff\cff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbase.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbbox.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbdf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbitmap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftcid.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftpatent.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftfstype.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftgasp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cache\ftcache.c +# End Source File +# Begin Source File + +SOURCE=..\ftdebug.c +# ADD CPP /Ze +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftglyph.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftgxval.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\gzip\ftgzip.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftinit.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\lzw\ftlzw.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftmm.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftotval.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftpfr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftstroke.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftsynth.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftsystem.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\fttype1.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftwinfnt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pcf\pcf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pfr\pfr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\psaux\psaux.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pshinter\pshinter.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\psnames\psmodule.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\raster\raster.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\sfnt\sfnt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\smooth\smooth.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\truetype\truetype.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\type1\type1.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cid\type1cid.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\type42\type42.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\winfonts\winfnt.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\include\ft2build.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftconfig.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftheader.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftmodule.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftoption.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftstdlib.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" +# Begin Source File + +SOURCE=..\..\..\src\base\ftver.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/vendor/freetype/builds/windows/visualc/freetype.dsw b/vendor/freetype/builds/windows/visualc/freetype.dsw new file mode 100644 index 0000000..b1b375d --- /dev/null +++ b/vendor/freetype/builds/windows/visualc/freetype.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "freetype"=.\freetype.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/vendor/freetype/builds/windows/visualc/freetype.vcproj b/vendor/freetype/builds/windows/visualc/freetype.vcproj new file mode 100644 index 0000000..85c5f1c --- /dev/null +++ b/vendor/freetype/builds/windows/visualc/freetype.vcproj @@ -0,0 +1,587 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/freetype/builds/windows/visualc/index.html b/vendor/freetype/builds/windows/visualc/index.html new file mode 100644 index 0000000..816605e --- /dev/null +++ b/vendor/freetype/builds/windows/visualc/index.html @@ -0,0 +1,38 @@ + +
    + + FreeType 2 Project Files for Visual C++ 6.0 and 2002-2008 + + + +

    + FreeType 2 Project Files for Visual C++ 6.0 and 2002-2008 +

    + +

    This directory contains project files freetype.dsp for +Visual C++ 6.0, and freetype.vcproj for Visual C++ 2002 +through 2008, which you might need to upgrade automatically. +It compiles the following libraries from the FreeType 2.13.2 sources:

    + +
      +
    • freetype.dll using 'Release' or 'Debug' configurations
    • +
    • freetype.lib using 'Release Static' or 'Debug Static' configurations
    • +
    + +

    Build directories and target files are placed in the top-level +objs directory.

    + +

    Be sure to extract the files with the Windows (CR+LF) line endings. ZIP +archives are already stored this way, so no further action is required. If +you use some .tar.*z archives, be sure to configure your extracting +tool to convert the line endings. For example, with WinZip, you should activate the TAR +file smart CR/LF Conversion option. Alternatively, you may consider +using the unix2dos or u2d utilities that are floating +around, which specifically deal with this particular problem. + +

    Build directories are placed in the top-level objs +directory.

    + + + diff --git a/vendor/freetype/builds/windows/visualce/freetype.dsp b/vendor/freetype/builds/windows/visualce/freetype.dsp new file mode 100644 index 0000000..11d59f9 --- /dev/null +++ b/vendor/freetype/builds/windows/visualce/freetype.dsp @@ -0,0 +1,391 @@ +# Microsoft Developer Studio Project File - Name="freetype" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=freetype - Win32 Debug Singlethreaded +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "freetype.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "freetype.mak" CFG="freetype - Win32 Debug Singlethreaded" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "freetype - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "freetype - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "freetype - Win32 Debug Multithreaded" (based on "Win32 (x86) Static Library") +!MESSAGE "freetype - Win32 Release Multithreaded" (based on "Win32 (x86) Static Library") +!MESSAGE "freetype - Win32 Release Singlethreaded" (based on "Win32 (x86) Static Library") +!MESSAGE "freetype - Win32 Debug Singlethreaded" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "freetype - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\objs\release" +# PROP Intermediate_Dir "..\..\..\objs\release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /MD /Za /W4 /GX /O2 /I "..\..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT2_BUILD_LIBRARY" /FD /c +# SUBTRACT CPP /nologo /Z /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\objs\freetype.lib" + +!ELSEIF "$(CFG)" == "freetype - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\objs\debug" +# PROP Intermediate_Dir "..\..\..\objs\debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /MDd /Za /W4 /GX /Z7 /Od /I "..\..\..\include" /D "_DEBUG" /D "FT_DEBUG_LEVEL_ERROR" /D "FT_DEBUG_LEVEL_TRACE" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT2_BUILD_LIBRARY" /FD /GZ /c +# SUBTRACT CPP /nologo /X /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\objs\freetype_D.lib" + +!ELSEIF "$(CFG)" == "freetype - Win32 Debug Multithreaded" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "freetype___Win32_Debug_Multithreaded" +# PROP BASE Intermediate_Dir "freetype___Win32_Debug_Multithreaded" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\objs\debug_mt" +# PROP Intermediate_Dir "..\..\..\objs\debug_mt" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /Za /W3 /Gm /GX /ZI /Od /I "..\include\\" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT_FLAT_COMPILE" /YX /FD /GZ /c +# SUBTRACT BASE CPP /X +# ADD CPP /MTd /Za /W4 /GX /Z7 /Od /I "..\..\..\include" /D "_DEBUG" /D "FT_DEBUG_LEVEL_ERROR" /D "FT_DEBUG_LEVEL_TRACE" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT2_BUILD_LIBRARY" /FD /GZ /c +# SUBTRACT CPP /nologo /X /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"lib\freetype_D.lib" +# ADD LIB32 /nologo /out:"..\..\..\objs\freetypeMT_D.lib" + +!ELSEIF "$(CFG)" == "freetype - Win32 Release Multithreaded" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "freetype___Win32_Release_Multithreaded" +# PROP BASE Intermediate_Dir "freetype___Win32_Release_Multithreaded" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\objs\release_mt" +# PROP Intermediate_Dir "..\..\..\objs\release_mt" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /Za /W3 /GX /O2 /I "..\include\\" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT_FLAT_COMPILE" /YX /FD /c +# ADD CPP /MT /Za /W4 /GX /O2 /I "..\..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT2_BUILD_LIBRARY" /FD /c +# SUBTRACT CPP /nologo /Z /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"lib\freetype.lib" +# ADD LIB32 /nologo /out:"..\..\..\objs\freetypeMT.lib" + +!ELSEIF "$(CFG)" == "freetype - Win32 Release Singlethreaded" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "freetype___Win32_Release_Singlethreaded" +# PROP BASE Intermediate_Dir "freetype___Win32_Release_Singlethreaded" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\objs\release_st" +# PROP Intermediate_Dir "..\..\..\objs\release_st" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /Za /W4 /GX /Zi /O2 /I "..\..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /Za /W4 /GX /O2 /I "..\..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT2_BUILD_LIBRARY" /FD /c +# SUBTRACT CPP /nologo /Z /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\objs\freetype.lib" +# ADD LIB32 /out:"..\..\..\objs\freetypeST.lib" +# SUBTRACT LIB32 /nologo + +!ELSEIF "$(CFG)" == "freetype - Win32 Debug Singlethreaded" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "freetype___Win32_Debug_Singlethreaded" +# PROP BASE Intermediate_Dir "freetype___Win32_Debug_Singlethreaded" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\objs\debug_st" +# PROP Intermediate_Dir "..\..\..\objs\debug_st" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /Za /W4 /Gm /GX /Zi /Od /I "..\..\..\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT_DEBUG_LEVEL_ERROR" /D "FT_DEBUG_LEVEL_TRACE" /FD /GZ /c +# SUBTRACT BASE CPP /X /YX +# ADD CPP /Za /W4 /GX /Z7 /Od /I "..\..\..\include" /D "_DEBUG" /D "FT_DEBUG_LEVEL_ERROR" /D "FT_DEBUG_LEVEL_TRACE" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FT2_BUILD_LIBRARY" /FD /GZ /c +# SUBTRACT CPP /nologo /X /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\objs\freetype_D.lib" +# ADD LIB32 /nologo /out:"..\..\..\objs\freetypeST_D.lib" + +!ENDIF + +# Begin Target + +# Name "freetype - Win32 Release" +# Name "freetype - Win32 Debug" +# Name "freetype - Win32 Debug Multithreaded" +# Name "freetype - Win32 Release Multithreaded" +# Name "freetype - Win32 Release Singlethreaded" +# Name "freetype - Win32 Debug Singlethreaded" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\autofit\autofit.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\bdf\bdf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cff\cff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbase.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbbox.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbdf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftbitmap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftcid.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftfstype.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftgasp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cache\ftcache.c +# End Source File +# Begin Source File + +SOURCE=..\ftdebug.c +# ADD CPP /Ze +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftglyph.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftgxval.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\gzip\ftgzip.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftinit.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\lzw\ftlzw.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftmm.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftotval.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftpatent.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftpfr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftstroke.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftsynth.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftsystem.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\fttype1.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\base\ftwinfnt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pcf\pcf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pfr\pfr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\psaux\psaux.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pshinter\pshinter.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\psnames\psmodule.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\raster\raster.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\sfnt\sfnt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\smooth\smooth.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\truetype\truetype.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\type1\type1.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cid\type1cid.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\type42\type42.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\winfonts\winfnt.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\include\ft2build.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftconfig.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftheader.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftmodule.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftoption.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\freetype\config\ftstdlib.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" +# Begin Source File + +SOURCE=..\..\..\src\base\ftver.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/vendor/freetype/builds/windows/visualce/freetype.dsw b/vendor/freetype/builds/windows/visualce/freetype.dsw new file mode 100644 index 0000000..b1b375d --- /dev/null +++ b/vendor/freetype/builds/windows/visualce/freetype.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "freetype"=.\freetype.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/vendor/freetype/builds/windows/visualce/freetype.vcproj b/vendor/freetype/builds/windows/visualce/freetype.vcproj new file mode 100644 index 0000000..f0f74c7 --- /dev/null +++ b/vendor/freetype/builds/windows/visualce/freetype.vcproj @@ -0,0 +1,3706 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/freetype/builds/windows/visualce/index.html b/vendor/freetype/builds/windows/visualce/index.html new file mode 100644 index 0000000..d9c8fe4 --- /dev/null +++ b/vendor/freetype/builds/windows/visualce/index.html @@ -0,0 +1,47 @@ + +
    + + FreeType 2 Project Files for Visual C++ and VS.NET 2005 + (Pocket PC) + + + +

    + FreeType 2 Project Files for Visual C++ and VS.NET 2005 + (Pocket PC) +

    + +

    This directory contains project files for Visual C++, named +freetype.dsp, and Visual Studio, called freetype.sln for +the following targets: + +

      +
    • PPC/SP 2003 (Pocket PC 2003)
    • +
    • PPC/SP WM5 (Windows Mobile 5)
    • +
    • PPC/SP WM6 (Windows Mobile 6)
    • +
    + +It compiles the following libraries from the FreeType 2.13.2 sources:

    + +
      +
      +    freetype.lib     - release build; single threaded
      +    freetype_D.lib   - debug build;   single threaded
      +    freetypeMT.lib   - release build; multi-threaded
      +    freetypeMT_D.lib - debug build;   multi-threaded
      +
    + +

    Be sure to extract the files with the Windows (CR+LF) line endings. ZIP +archives are already stored this way, so no further action is required. If +you use some .tar.*z archives, be sure to configure your extracting +tool to convert the line endings. For example, with WinZip, you should activate the TAR +file smart CR/LF Conversion option. Alternatively, you may consider +using the unix2dos or u2d utilities that are floating +around, which specifically deal with this particular problem. + +

    Build directories are placed in the top-level objs +directory.

    + + + diff --git a/vendor/freetype/builds/windows/w32-bcc.mk b/vendor/freetype/builds/windows/w32-bcc.mk new file mode 100644 index 0000000..e7cf668 --- /dev/null +++ b/vendor/freetype/builds/windows/w32-bcc.mk @@ -0,0 +1,28 @@ +# +# FreeType 2 Borland C++ on Win32 +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# default definitions of the export list +# +EXPORTS_LIST = $(OBJ_DIR)/freetype.def +EXPORTS_OPTIONS = /DEF:$(EXPORTS_LIST) +APINAMES_OPTIONS := -dfreetype.dll -wB + +include $(TOP_DIR)/builds/windows/win32-def.mk +include $(TOP_DIR)/builds/compiler/bcc.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-bccd.mk b/vendor/freetype/builds/windows/w32-bccd.mk new file mode 100644 index 0000000..64dafdb --- /dev/null +++ b/vendor/freetype/builds/windows/w32-bccd.mk @@ -0,0 +1,26 @@ +# +# FreeType 2 Borland C++ on Win32 + debugging +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DEVEL_DIR := $(TOP_DIR)/devel + +include $(TOP_DIR)/builds/windows/win32-def.mk + +include $(TOP_DIR)/builds/compiler/bcc-dev.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-dev.mk b/vendor/freetype/builds/windows/w32-dev.mk new file mode 100644 index 0000000..7c89ad2 --- /dev/null +++ b/vendor/freetype/builds/windows/w32-dev.mk @@ -0,0 +1,32 @@ +# +# FreeType 2 configuration rules for Win32 + GCC +# +# Development version without optimizations. +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# NOTE: This version requires that GNU Make is invoked from the Windows +# Shell (_not_ Cygwin BASH)! +# + +DEVEL_DIR := $(TOP_DIR)/devel + +include $(TOP_DIR)/builds/windows/win32-def.mk + +include $(TOP_DIR)/builds/compiler/gcc-dev.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-gcc.mk b/vendor/freetype/builds/windows/w32-gcc.mk new file mode 100644 index 0000000..f37c185 --- /dev/null +++ b/vendor/freetype/builds/windows/w32-gcc.mk @@ -0,0 +1,31 @@ +# +# FreeType 2 configuration rules for Win32 + GCC +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# default definitions of the export list +# +EXPORTS_LIST = $(OBJ_DIR)/freetype.def +EXPORTS_OPTIONS = $(EXPORTS_LIST) +APINAMES_OPTIONS := -dfreetype.dll -w + +# include Win32-specific definitions +include $(TOP_DIR)/builds/windows/win32-def.mk + +# include gcc-specific definitions +include $(TOP_DIR)/builds/compiler/gcc.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-icc.mk b/vendor/freetype/builds/windows/w32-icc.mk new file mode 100644 index 0000000..cf51cce --- /dev/null +++ b/vendor/freetype/builds/windows/w32-icc.mk @@ -0,0 +1,28 @@ +# +# FreeType 2 configuration rules for Win32 + IBM Visual Age C++ +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# default definitions of the export list +# +EXPORTS_LIST = $(OBJ_DIR)/freetype.def +EXPORTS_OPTIONS = /DEF:$(EXPORTS_LIST) +APINAMES_OPTIONS := -dfreetype.dll -w + +include $(TOP_DIR)/builds/windows/win32-def.mk +include $(TOP_DIR)/builds/compiler/visualage.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-intl.mk b/vendor/freetype/builds/windows/w32-intl.mk new file mode 100644 index 0000000..0c16b4c --- /dev/null +++ b/vendor/freetype/builds/windows/w32-intl.mk @@ -0,0 +1,28 @@ +# +# FreeType 2 configuration rules for Intel C/C++ on Win32 +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# default definitions of the export list +# +EXPORTS_LIST = $(OBJ_DIR)/freetype.def +EXPORTS_OPTIONS = /DEF:$(EXPORTS_LIST) +APINAMES_OPTIONS := -dfreetype.dll -w + +include $(TOP_DIR)/builds/windows/win32-def.mk +include $(TOP_DIR)/builds/compiler/intelc.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-lcc.mk b/vendor/freetype/builds/windows/w32-lcc.mk new file mode 100644 index 0000000..0dd740e --- /dev/null +++ b/vendor/freetype/builds/windows/w32-lcc.mk @@ -0,0 +1,24 @@ +# +# FreeType 2 configuration rules for Win32 + LCC +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +SEP := / +include $(TOP_DIR)/builds/windows/win32-def.mk +include $(TOP_DIR)/builds/compiler/win-lcc.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + +# EOF + diff --git a/vendor/freetype/builds/windows/w32-mingw32.mk b/vendor/freetype/builds/windows/w32-mingw32.mk new file mode 100644 index 0000000..dc323bd --- /dev/null +++ b/vendor/freetype/builds/windows/w32-mingw32.mk @@ -0,0 +1,33 @@ +# +# FreeType 2 configuration rules for mingw32 +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# default definitions of the export list +# +EXPORTS_LIST = $(OBJ_DIR)/freetype.def +EXPORTS_OPTIONS = $(EXPORTS_LIST) +APINAMES_OPTIONS := -dfreetype.dll -w + +# include Win32-specific definitions +include $(TOP_DIR)/builds/windows/win32-def.mk + +LIBRARY := lib$(PROJECT) + +# include gcc-specific definitions +include $(TOP_DIR)/builds/compiler/gcc.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-vcc.mk b/vendor/freetype/builds/windows/w32-vcc.mk new file mode 100644 index 0000000..eea7db8 --- /dev/null +++ b/vendor/freetype/builds/windows/w32-vcc.mk @@ -0,0 +1,28 @@ +# +# FreeType 2 Visual C++ on Win32 +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# definitions of the export list +# +EXPORTS_LIST = $(OBJ_DIR)/freetype.def +EXPORTS_OPTIONS = /DEF:$(EXPORTS_LIST) +APINAMES_OPTIONS := -dfreetype.dll -w + +include $(TOP_DIR)/builds/windows/win32-def.mk +include $(TOP_DIR)/builds/compiler/visualc.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/w32-wat.mk b/vendor/freetype/builds/windows/w32-wat.mk new file mode 100644 index 0000000..5392d2a --- /dev/null +++ b/vendor/freetype/builds/windows/w32-wat.mk @@ -0,0 +1,28 @@ +# +# FreeType 2 configuration rules for Watcom C/C++ +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# redefine export symbol definitions +# +EXPORTS_LIST = $(OBJ_DIR)/watcom-ftexports.lbc +EXPORTS_OPTIONS = -\"export @$(EXPORTS_LIST)\"- +APINAMES_OPTIONS := -wW + +include $(TOP_DIR)/builds/windows/win32-def.mk +include $(TOP_DIR)/builds/compiler/watcom.mk + +# include linking instructions +include $(TOP_DIR)/builds/link_dos.mk + + +# EOF diff --git a/vendor/freetype/builds/windows/win32-def.mk b/vendor/freetype/builds/windows/win32-def.mk new file mode 100644 index 0000000..3242651 --- /dev/null +++ b/vendor/freetype/builds/windows/win32-def.mk @@ -0,0 +1,51 @@ +# +# FreeType 2 Win32 specific definitions +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +DELETE := del +CAT := type +SEP := $(strip \ ) +PLATFORM_DIR := $(TOP_DIR)/builds/windows +PLATFORM := windows + +# This is used for `make refdoc' and `make refdoc-venv' +# +BIN := Scripts + +# The executable file extension (for tools). NOTE: WE INCLUDE THE DOT HERE !! +# +E := .exe +E_BUILD := .exe + + +# The directory where all library files are placed. +# +# By default, this is the same as $(OBJ_DIR); however, this can be changed +# to suit particular needs. +# +LIB_DIR := $(OBJ_DIR) + + +# The name of the final library file. Note that the DOS-specific Makefile +# uses a shorter (8.3) name. +# +LIBRARY := $(PROJECT) + + +# The NO_OUTPUT macro is used to ignore the output of commands. +# +NO_OUTPUT = 2> nul + + +# EOF diff --git a/vendor/freetype/devel/ft2build.h b/vendor/freetype/devel/ft2build.h new file mode 100644 index 0000000..82fdb30 --- /dev/null +++ b/vendor/freetype/devel/ft2build.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * ft2build.h + * + * FreeType 2 build and setup macros (development version). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + * This is a development version of to build the library in + * debug mode. Its only difference to the default version is that it + * includes a local `ftoption.h' header file with different settings for + * many configuration macros. + * + * To use it, simply ensure that the directory containing this file is + * scanned by the compiler before the default FreeType header directory. + * + */ + +#ifndef FT2BUILD_H_ +#define FT2BUILD_H_ + +#define FT_CONFIG_MODULES_H +#define FT_CONFIG_OPTIONS_H + +#include + +#endif /* FT2BUILD_H_ */ + + +/* END */ diff --git a/vendor/freetype/devel/ftoption.h b/vendor/freetype/devel/ftoption.h new file mode 100644 index 0000000..da56abc --- /dev/null +++ b/vendor/freetype/devel/ftoption.h @@ -0,0 +1,1014 @@ +/**************************************************************************** + * + * ftoption.h (for development) + * + * User-selectable configuration macros (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTOPTION_H_ +#define FTOPTION_H_ + + +#include + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * USER-SELECTABLE CONFIGURATION MACROS + * + * This file contains the default configuration macro definitions for a + * standard build of the FreeType library. There are three ways to use + * this file to build project-specific versions of the library: + * + * - You can modify this file by hand, but this is not recommended in + * cases where you would like to build several versions of the library + * from a single source directory. + * + * - You can put a copy of this file in your build directory, more + * precisely in `$BUILD/freetype/config/ftoption.h`, where `$BUILD` is + * the name of a directory that is included _before_ the FreeType include + * path during compilation. + * + * The default FreeType Makefiles use the build directory + * `builds/` by default, but you can easily change that for your + * own projects. + * + * - Copy the file to `$BUILD/ft2build.h` and modify it + * slightly to pre-define the macro `FT_CONFIG_OPTIONS_H` used to locate + * this file during the build. For example, + * + * ``` + * #define FT_CONFIG_OPTIONS_H + * #include + * ``` + * + * will use `$BUILD/myftoptions.h` instead of this file for macro + * definitions. + * + * Note also that you can similarly pre-define the macro + * `FT_CONFIG_MODULES_H` used to locate the file listing of the modules + * that are statically linked to the library at compile time. By + * default, this file is ``. + * + * We highly recommend using the third method whenever possible. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*#************************************************************************ + * + * If you enable this configuration option, FreeType recognizes an + * environment variable called `FREETYPE_PROPERTIES`, which can be used to + * control the various font drivers and modules. The controllable + * properties are listed in the section @properties. + * + * You have to undefine this configuration option on platforms that lack + * the concept of environment variables (and thus don't have the `getenv` + * function), for example Windows CE. + * + * `FREETYPE_PROPERTIES` has the following syntax form (broken here into + * multiple lines for better readability). + * + * ``` + * + * ':' + * '=' + * + * ':' + * '=' + * ... + * ``` + * + * Example: + * + * ``` + * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ + * cff:no-stem-darkening=1 + * ``` + * + */ +#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + + /************************************************************************** + * + * Uncomment the line below if you want to activate LCD rendering + * technology similar to ClearType in this build of the library. This + * technology triples the resolution in the direction color subpixels. To + * mitigate color fringes inherent to this technology, you also need to + * explicitly set up LCD filtering. + * + * When this macro is not defined, FreeType offers alternative LCD + * rendering technology that produces excellent output. + */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + + /************************************************************************** + * + * Many compilers provide a non-ANSI 64-bit data type that can be used by + * FreeType to speed up some computations. However, this will create some + * problems when compiling the library in strict ANSI mode. + * + * For this reason, the use of 64-bit integers is normally disabled when + * the `__STDC__` macro is defined. You can however disable this by + * defining the macro `FT_CONFIG_OPTION_FORCE_INT64` here. + * + * For most compilers, this will only create compilation warnings when + * building the library. + * + * ObNote: The compiler-specific 64-bit integers are detected in the + * file `ftconfig.h` either statically or through the `configure` + * script on supported platforms. + */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /************************************************************************** + * + * If this macro is defined, do not try to use an assembler version of + * performance-critical functions (e.g., @FT_MulFix). You should only do + * that to verify that the assembler function works properly, or to execute + * benchmark tests of the various implementations. + */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ + + + /************************************************************************** + * + * If this macro is defined, try to use an inlined assembler version of the + * @FT_MulFix function, which is a 'hotspot' when loading and hinting + * glyphs, and which should be executed as fast as possible. + * + * Note that if your compiler or CPU is not supported, this will default to + * the standard and portable implementation found in `ftcalc.c`. + */ +#define FT_CONFIG_OPTION_INLINE_MULFIX + + + /************************************************************************** + * + * LZW-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `compress` program. This is mostly used to parse many of the PCF + * files that come with various X11 distributions. The implementation + * uses NetBSD's `zopen` to partially uncompress the file on the fly (see + * `src/lzw/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. + */ +#define FT_CONFIG_OPTION_USE_LZW + + + /************************************************************************** + * + * Gzip-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `gzip` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses 'zlib' to partially + * uncompress the file on the fly (see `src/gzip/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. See also the + * macro `FT_CONFIG_OPTION_SYSTEM_ZLIB` below. + */ +#define FT_CONFIG_OPTION_USE_ZLIB + + + /************************************************************************** + * + * ZLib library selection + * + * This macro is only used when `FT_CONFIG_OPTION_USE_ZLIB` is defined. + * It allows FreeType's 'ftgzip' component to link to the system's + * installation of the ZLib library. This is useful on systems like + * Unix or VMS where it generally is already available. + * + * If you let it undefined, the component will use its own copy of the + * zlib sources instead. These have been modified to be included + * directly within the component and **not** export external function + * names. This allows you to link any program with FreeType _and_ ZLib + * without linking conflicts. + * + * Do not `#undef` this macro here since the build system might define + * it for certain configurations only. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + * + * If you use the GNU make build system directly (that is, without the + * `configure` script) and you define this macro, you also have to pass + * `SYSTEM_ZLIB=yes` as an argument to make. + */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /************************************************************************** + * + * Bzip2-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `bzip2` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses `libbz2` to partially + * uncompress the file on the fly (see `src/bzip2/ftbzip2.c`). Contrary + * to gzip, bzip2 currently is not included and need to use the system + * available bzip2 implementation. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_BZIP2 + + + /************************************************************************** + * + * Define to disable the use of file stream functions and types, `FILE`, + * `fopen`, etc. Enables the use of smaller system libraries on embedded + * systems that have multiple system libraries, some with or without file + * stream support, in the cases where file stream support is not necessary + * such as memory loading of font files. + */ +/* #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ + + + /************************************************************************** + * + * PNG bitmap support. + * + * FreeType now handles loading color bitmap glyphs in the PNG format. + * This requires help from the external libpng library. Uncompressed + * color bitmaps do not need any external libraries and will be supported + * regardless of this configuration. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_PNG + + + /************************************************************************** + * + * HarfBuzz support. + * + * FreeType uses the HarfBuzz library to improve auto-hinting of OpenType + * fonts. If available, many glyphs not directly addressable by a font's + * character map will be hinted also. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_HARFBUZZ + + + /************************************************************************** + * + * Brotli support. + * + * FreeType uses the Brotli library to provide support for decompressing + * WOFF2 streams. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_BROTLI + + + /************************************************************************** + * + * Glyph Postscript Names handling + * + * By default, FreeType 2 is compiled with the 'psnames' module. This + * module is in charge of converting a glyph name string into a Unicode + * value, or return a Macintosh standard glyph name for the use with the + * TrueType 'post' table. + * + * Undefine this macro if you do not want 'psnames' compiled in your + * build of FreeType. This has the following effects: + * + * - The TrueType driver will provide its own set of glyph names, if you + * build it to support postscript names in the TrueType 'post' table, + * but will not synthesize a missing Unicode charmap. + * + * - The Type~1 driver will not be able to synthesize a Unicode charmap + * out of the glyphs found in the fonts. + * + * You would normally undefine this configuration macro when building a + * version of FreeType that doesn't contain a Type~1 or CFF driver. + */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Postscript Names to Unicode Values support + * + * By default, FreeType~2 is built with the 'psnames' module compiled in. + * Among other things, the module is used to convert a glyph name into a + * Unicode value. This is especially useful in order to synthesize on + * the fly a Unicode charmap from the CFF/Type~1 driver through a big + * table named the 'Adobe Glyph List' (AGL). + * + * Undefine this macro if you do not want the Adobe Glyph List compiled + * in your 'psnames' module. The Type~1 driver will not be able to + * synthesize a Unicode charmap out of the glyphs found in the fonts. + */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /************************************************************************** + * + * Support for Mac fonts + * + * Define this macro if you want support for outline fonts in Mac format + * (mac dfont, mac resource, macbinary containing a mac resource) on + * non-Mac platforms. + * + * Note that the 'FOND' resource isn't checked. + */ +#define FT_CONFIG_OPTION_MAC_FONTS + + + /************************************************************************** + * + * Guessing methods to access embedded resource forks + * + * Enable extra Mac fonts support on non-Mac platforms (e.g., GNU/Linux). + * + * Resource forks which include fonts data are stored sometimes in + * locations which users or developers don't expected. In some cases, + * resource forks start with some offset from the head of a file. In + * other cases, the actual resource fork is stored in file different from + * what the user specifies. If this option is activated, FreeType tries + * to guess whether such offsets or different file names must be used. + * + * Note that normal, direct access of resource forks is controlled via + * the `FT_CONFIG_OPTION_MAC_FONTS` option. + */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /************************************************************************** + * + * Allow the use of `FT_Incremental_Interface` to load typefaces that + * contain no glyph data, but supply it via a callback function. This is + * required by clients supporting document formats which supply font data + * incrementally as the document is parsed, such as the Ghostscript + * interpreter for the PostScript language. + */ +#define FT_CONFIG_OPTION_INCREMENTAL + + + /************************************************************************** + * + * The size in bytes of the render pool used by the scan-line converter to + * do all of its work. + */ +#define FT_RENDER_POOL_SIZE 16384L + + + /************************************************************************** + * + * FT_MAX_MODULES + * + * The maximum number of modules that can be registered in a single + * FreeType library object. 32~is the default. + */ +#define FT_MAX_MODULES 32 + + + /************************************************************************** + * + * Debug level + * + * FreeType can be compiled in debug or trace mode. In debug mode, + * errors are reported through the 'ftdebug' component. In trace mode, + * additional messages are sent to the standard output during execution. + * + * Define `FT_DEBUG_LEVEL_ERROR` to build the library in debug mode. + * Define `FT_DEBUG_LEVEL_TRACE` to build it in trace mode. + * + * Don't define any of these macros to compile in 'release' mode! + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +#define FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_TRACE + + + /************************************************************************** + * + * Logging + * + * Compiling FreeType in debug or trace mode makes FreeType write error + * and trace log messages to `stderr`. Enabling this macro + * automatically forces the `FT_DEBUG_LEVEL_ERROR` and + * `FT_DEBUG_LEVEL_TRACE` macros and allows FreeType to write error and + * trace log messages to a file instead of `stderr`. For writing logs + * to a file, FreeType uses an the external `dlg` library (the source + * code is in `src/dlg`). + * + * This option needs a C99 compiler. + */ +#define FT_DEBUG_LOGGING + + + /************************************************************************** + * + * Autofitter debugging + * + * If `FT_DEBUG_AUTOFIT` is defined, FreeType provides some means to + * control the autofitter behaviour for debugging purposes with global + * boolean variables (consequently, you should **never** enable this + * while compiling in 'release' mode): + * + * ``` + * af_debug_disable_horz_hints_ + * af_debug_disable_vert_hints_ + * af_debug_disable_blue_hints_ + * ``` + * + * Additionally, the following functions provide dumps of various + * internal autofit structures to stdout (using `printf`): + * + * ``` + * af_glyph_hints_dump_points + * af_glyph_hints_dump_segments + * af_glyph_hints_dump_edges + * af_glyph_hints_get_num_segments + * af_glyph_hints_get_segment_offset + * ``` + * + * As an argument, they use another global variable: + * + * ``` + * af_debug_hints_ + * ``` + * + * Please have a look at the `ftgrid` demo program to see how those + * variables and macros should be used. + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +#define FT_DEBUG_AUTOFIT + + + /************************************************************************** + * + * Memory Debugging + * + * FreeType now comes with an integrated memory debugger that is capable + * of detecting simple errors like memory leaks or double deletes. To + * compile it within your build of the library, you should define + * `FT_DEBUG_MEMORY` here. + * + * Note that the memory debugger is only activated at runtime when when + * the _environment_ variable `FT2_DEBUG_MEMORY` is defined also! + * + * Do not `#undef` this macro here since the build system might define it + * for certain configurations only. + */ +#define FT_DEBUG_MEMORY + + + /************************************************************************** + * + * Module errors + * + * If this macro is set (which is _not_ the default), the higher byte of + * an error code gives the module in which the error has occurred, while + * the lower byte is the real error code. + * + * Setting this macro makes sense for debugging purposes only, since it + * would break source compatibility of certain programs that use + * FreeType~2. + * + * More details can be found in the files `ftmoderr.h` and `fterrors.h`. + */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + /************************************************************************** + * + * OpenType SVG Glyph Support + * + * Setting this macro enables support for OpenType SVG glyphs. By + * default, FreeType can only fetch SVG documents. However, it can also + * render them if external rendering hook functions are plugged in at + * runtime. + * + * More details on the hooks can be found in file `otsvg.h`. + */ +#define FT_CONFIG_OPTION_SVG + + + /************************************************************************** + * + * Error Strings + * + * If this macro is set, `FT_Error_String` will return meaningful + * descriptions. This is not enabled by default to reduce the overall + * size of FreeType. + * + * More details can be found in the file `fterrors.h`. + */ +/* #define FT_CONFIG_OPTION_ERROR_STRINGS */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_EMBEDDED_BITMAPS` if you want to support + * embedded bitmaps in all formats using the 'sfnt' module (namely + * TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COLOR_LAYERS` if you want to support colored + * outlines (from the 'COLR'/'CPAL' tables) in all formats using the 'sfnt' + * module (namely TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_COLOR_LAYERS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_POSTSCRIPT_NAMES` if you want to be able to + * load and enumerate Postscript names of glyphs in a TrueType or OpenType + * file. + * + * Note that if you do not compile the 'psnames' module by undefining the + * above `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` macro, the 'sfnt' module will + * contain additional code to read the PostScript name table from a font. + * + * (By default, the module uses 'psnames' to extract glyph names.) + */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SFNT_NAMES` if your applications need to access + * the internal name table in a SFNT-based format like TrueType or + * OpenType. The name table contains various strings used to describe the + * font, like family name, copyright, version, etc. It does not contain + * any glyph name though. + * + * Accessing SFNT names is done through the functions declared in + * `ftsnames.h`. + */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /************************************************************************** + * + * TrueType CMap support + * + * Here you can fine-tune which TrueType CMap table format shall be + * supported. + */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` if you want to compile a + * bytecode interpreter in the TrueType driver. + * + * By undefining this, you will only compile the code necessary to load + * TrueType glyphs without hinting. + * + * Do not `#undef` this macro here, since the build system might define it + * for certain configurations only. + */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SUBPIXEL_HINTING` if you want to compile + * subpixel hinting support into the TrueType driver. This modifies the + * TrueType hinting mechanism when anything but `FT_RENDER_MODE_MONO` is + * requested. + * + * In particular, it modifies the bytecode interpreter to interpret (or + * not) instructions in a certain way so that all TrueType fonts look like + * they do in a Windows ClearType (DirectWrite) environment. See [1] for a + * technical overview on what this means. See `ttinterp.h` for more + * details on this option. + * + * The new default mode focuses on applying a minimal set of rules to all + * fonts indiscriminately so that modern and web fonts render well while + * legacy fonts render okay. The corresponding interpreter version is v40. + * The so-called Infinality mode (v38) is no longer available in FreeType. + * + * By undefining these, you get rendering behavior like on Windows without + * ClearType, i.e., Windows XP without ClearType enabled and Win9x + * (interpreter version v35). Or not, depending on how much hinting blood + * and testing tears the font designer put into a given font. If you + * define one or both subpixel hinting options, you can switch between + * between v35 and the ones you define (using `FT_Property_Set`). + * + * This option requires `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` to be + * defined. + * + * [1] + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED` to compile the + * TrueType glyph loader to use Apple's definition of how to handle + * component offsets in composite glyphs. + * + * Apple and MS disagree on the default behavior of component offsets in + * composites. Apple says that they should be scaled by the scaling + * factors in the transformation matrix (roughly, it's more complex) while + * MS says they should not. OpenType defines two bits in the composite + * flags array which can be used to disambiguate, but old fonts will not + * have them. + * + * https://www.microsoft.com/typography/otspec/glyf.htm + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html + */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_GX_VAR_SUPPORT` if you want to include support + * for Apple's distortable font technology ('fvar', 'gvar', 'cvar', and + * 'avar' tables). Tagged 'Font Variations', this is now part of OpenType + * also. This has many similarities to Type~1 Multiple Masters support. + */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_NO_BORING_EXPANSION` if you want to exclude + * support for 'boring' OpenType specification expansions. + * + * https://github.com/harfbuzz/boring-expansion-spec + * + * Right now, the following features are covered: + * + * - 'avar' version 2.0 + * + * Most likely, this is a temporary configuration option to be removed in + * the near future, since it is assumed that eventually those features are + * added to the OpenType standard. + */ +/* #define TT_CONFIG_OPTION_NO_BORING_EXPANSION */ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an + * embedded 'BDF~' table within SFNT-based bitmap formats. + */ +#define TT_CONFIG_OPTION_BDF + + + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES` controls the maximum + * number of bytecode instructions executed for a single run of the + * bytecode interpreter, needed to prevent infinite loops. You don't want + * to change this except for very special situations (e.g., making a + * library fuzzer spend less time to handle broken fonts). + * + * It is not expected that this value is ever modified by a configuring + * script; instead, it gets surrounded with `#ifndef ... #endif` so that + * the value can be set as a preprocessor option on the compiler's command + * line. + */ +#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES +#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * `T1_MAX_DICT_DEPTH` is the maximum depth of nest dictionaries and arrays + * in the Type~1 stream (see `t1load.c`). A minimum of~4 is required. + */ +#define T1_MAX_DICT_DEPTH 5 + + + /************************************************************************** + * + * `T1_MAX_SUBRS_CALLS` details the maximum number of nested sub-routine + * calls during glyph loading. + */ +#define T1_MAX_SUBRS_CALLS 16 + + + /************************************************************************** + * + * `T1_MAX_CHARSTRING_OPERANDS` is the charstring stack's capacity. A + * minimum of~16 is required. + * + * The Chinese font 'MingTiEG-Medium' (covering the CNS 11643 character + * set) needs 256. + */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the 't1afm' module, which is in charge of reading Type~1 AFM files + * into an existing face. Note that if set, the Type~1 driver will be + * unable to produce kerning distances. + */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the Multiple Masters font support in the Type~1 driver. + */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /************************************************************************** + * + * `T1_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe Type~1 + * engine gets compiled into FreeType. If defined, it is possible to + * switch between the two engines using the `hinting-engine` property of + * the 'type1' driver module. + */ +#define T1_CONFIG_OPTION_OLD_ENGINE + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** C F F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Using `CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4}` it is + * possible to set up the default values of the four control points that + * define the stem darkening behaviour of the (new) CFF engine. For more + * details please read the documentation of the `darkening-parameters` + * property (file `ftdriver.h`), which allows the control at run-time. + * + * Do **not** undefine these macros! + */ +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0 + + + /************************************************************************** + * + * `CFF_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe CFF engine + * gets compiled into FreeType. If defined, it is possible to switch + * between the two engines using the `hinting-engine` property of the 'cff' + * driver module. + */ +#define CFF_CONFIG_OPTION_OLD_ENGINE + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** P C F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * There are many PCF fonts just called 'Fixed' which look completely + * different, and which have nothing to do with each other. When selecting + * 'Fixed' in KDE or Gnome one gets results that appear rather random, the + * style changes often if one changes the size and one cannot select some + * fonts at all. This option makes the 'pcf' module prepend the foundry + * name (plus a space) to the family name. + * + * We also check whether we have 'wide' characters; all put together, we + * get family names like 'Sony Fixed' or 'Misc Fixed Wide'. + * + * If this option is activated, it can be controlled with the + * `no-long-family-names` property of the 'pcf' driver module. + */ +#define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Compile 'autofit' module with CJK (Chinese, Japanese, Korean) script + * support. + */ +#define AF_CONFIG_OPTION_CJK + + + /************************************************************************** + * + * Compile 'autofit' module with fallback Indic script support, covering + * some scripts that the 'latin' submodule of the 'autofit' module doesn't + * (yet) handle. Currently, this needs option `AF_CONFIG_OPTION_CJK`. + */ +#ifdef AF_CONFIG_OPTION_CJK +#define AF_CONFIG_OPTION_INDIC +#endif + + + /************************************************************************** + * + * Use TrueType-like size metrics for 'light' auto-hinting. + * + * It is strongly recommended to avoid this option, which exists only to + * help some legacy applications retain its appearance and behaviour with + * respect to auto-hinted TrueType fonts. + * + * The very reason this option exists at all are GNU/Linux distributions + * like Fedora that did not un-patch the following change (which was + * present in FreeType between versions 2.4.6 and 2.7.1, inclusive). + * + * ``` + * 2011-07-16 Steven Chu + * + * [truetype] Fix metrics on size request for scalable fonts. + * ``` + * + * This problematic commit is now reverted (more or less). + */ +/* #define AF_CONFIG_OPTION_TT_SIZE_METRICS */ + + /* */ + + + /* + * This macro is obsolete. Support has been removed in FreeType version + * 2.5. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * The next two macros are defined if native TrueType hinting is + * requested by the definitions above. Don't change this. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#endif +#endif + + + /* + * The TT_SUPPORT_COLRV1 macro is defined to indicate to clients that this + * version of FreeType has support for 'COLR' v1 API. This definition is + * useful to FreeType clients that want to build in support for 'COLR' v1 + * depending on a tip-of-tree checkout before it is officially released in + * FreeType, and while the feature cannot yet be tested against using + * version macros. Don't change this macro. This may be removed once the + * feature is in a FreeType release version and version macros can be used + * to test for availability. + */ +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define TT_SUPPORT_COLRV1 +#endif + + + /* + * Check CFF darkening parameters. The checks are the same as in function + * `cff_property_set` in file `cffdrivr.c`. + */ +#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500 +#error "Invalid CFF darkening parameters!" +#endif + + +FT_END_HEADER + +#endif /* FTOPTION_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/config/ftconfig.h b/vendor/freetype/include/freetype/config/ftconfig.h new file mode 100644 index 0000000..a851516 --- /dev/null +++ b/vendor/freetype/include/freetype/config/ftconfig.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * ftconfig.h + * + * ANSI-specific configuration file (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This header file contains a number of macro definitions that are used by + * the rest of the engine. Most of the macros here are automatically + * determined at compile time, and you should not need to change it to port + * FreeType, except to compile the library with a non-ANSI compiler. + * + * Note however that if some specific modifications are needed, we advise + * you to place a modified copy in your build directory. + * + * The build directory is usually `builds/`, and contains + * system-specific files that are always included first when building the + * library. + * + * This ANSI version should stay in `include/config/`. + * + */ + +#ifndef FTCONFIG_H_ +#define FTCONFIG_H_ + +#include +#include FT_CONFIG_OPTIONS_H +#include FT_CONFIG_STANDARD_LIBRARY_H + +#include +#include +#include + +#endif /* FTCONFIG_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/config/ftheader.h b/vendor/freetype/include/freetype/config/ftheader.h new file mode 100644 index 0000000..e607bce --- /dev/null +++ b/vendor/freetype/include/freetype/config/ftheader.h @@ -0,0 +1,836 @@ +/**************************************************************************** + * + * ftheader.h + * + * Build macros of the FreeType 2 library. + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTHEADER_H_ +#define FTHEADER_H_ + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_BEGIN_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_END_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }` block when included from a */ + /* C++ compiler. */ + /* */ +#ifndef FT_BEGIN_HEADER +# ifdef __cplusplus +# define FT_BEGIN_HEADER extern "C" { +# else +# define FT_BEGIN_HEADER /* nothing */ +# endif +#endif + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_END_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_BEGIN_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }` block when included from a */ + /* C++ compiler. */ + /* */ +#ifndef FT_END_HEADER +# ifdef __cplusplus +# define FT_END_HEADER } +# else +# define FT_END_HEADER /* nothing */ +# endif +#endif + + + /************************************************************************** + * + * Aliases for the FreeType 2 public and configuration files. + * + */ + + /************************************************************************** + * + * @section: + * header_file_macros + * + * @title: + * Header File Macros + * + * @abstract: + * Macro definitions used to `#include` specific header files. + * + * @description: + * In addition to the normal scheme of including header files like + * + * ``` + * #include + * #include + * #include + * ``` + * + * it is possible to used named macros instead. They can be used + * directly in `#include` statements as in + * + * ``` + * #include FT_FREETYPE_H + * #include FT_MULTIPLE_MASTERS_H + * #include FT_GLYPH_H + * ``` + * + * These macros were introduced to overcome the infamous 8.3~naming rule + * required by DOS (and `FT_MULTIPLE_MASTERS_H` is a lot more meaningful + * than `ftmm.h`). + * + */ + + + /* configuration files */ + + /************************************************************************** + * + * @macro: + * FT_CONFIG_CONFIG_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * FreeType~2 configuration data. + * + */ +#ifndef FT_CONFIG_CONFIG_H +#define FT_CONFIG_CONFIG_H +#endif + + + /************************************************************************** + * + * @macro: + * FT_CONFIG_STANDARD_LIBRARY_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * FreeType~2 interface to the standard C library functions. + * + */ +#ifndef FT_CONFIG_STANDARD_LIBRARY_H +#define FT_CONFIG_STANDARD_LIBRARY_H +#endif + + + /************************************************************************** + * + * @macro: + * FT_CONFIG_OPTIONS_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * FreeType~2 project-specific configuration options. + * + */ +#ifndef FT_CONFIG_OPTIONS_H +#define FT_CONFIG_OPTIONS_H +#endif + + + /************************************************************************** + * + * @macro: + * FT_CONFIG_MODULES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list of FreeType~2 modules that are statically linked to new library + * instances in @FT_Init_FreeType. + * + */ +#ifndef FT_CONFIG_MODULES_H +#define FT_CONFIG_MODULES_H +#endif + + /* */ + + /* public headers */ + + /************************************************************************** + * + * @macro: + * FT_FREETYPE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * base FreeType~2 API. + * + */ +#define FT_FREETYPE_H + + + /************************************************************************** + * + * @macro: + * FT_ERRORS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list of FreeType~2 error codes (and messages). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_ERRORS_H + + + /************************************************************************** + * + * @macro: + * FT_MODULE_ERRORS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list of FreeType~2 module error offsets (and messages). + * + */ +#define FT_MODULE_ERRORS_H + + + /************************************************************************** + * + * @macro: + * FT_SYSTEM_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 interface to low-level operations (i.e., memory management + * and stream i/o). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_SYSTEM_H + + + /************************************************************************** + * + * @macro: + * FT_IMAGE_H + * + * @description: + * A macro used in `#include` statements to name the file containing type + * definitions related to glyph images (i.e., bitmaps, outlines, + * scan-converter parameters). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_IMAGE_H + + + /************************************************************************** + * + * @macro: + * FT_TYPES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * basic data types defined by FreeType~2. + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_TYPES_H + + + /************************************************************************** + * + * @macro: + * FT_LIST_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list management API of FreeType~2. + * + * (Most applications will never need to include this file.) + * + */ +#define FT_LIST_H + + + /************************************************************************** + * + * @macro: + * FT_OUTLINE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * scalable outline management API of FreeType~2. + * + */ +#define FT_OUTLINE_H + + + /************************************************************************** + * + * @macro: + * FT_SIZES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API which manages multiple @FT_Size objects per face. + * + */ +#define FT_SIZES_H + + + /************************************************************************** + * + * @macro: + * FT_MODULE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * module management API of FreeType~2. + * + */ +#define FT_MODULE_H + + + /************************************************************************** + * + * @macro: + * FT_RENDER_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * renderer module management API of FreeType~2. + * + */ +#define FT_RENDER_H + + + /************************************************************************** + * + * @macro: + * FT_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the driver modules. + * + */ +#define FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_AUTOHINTER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the auto-hinting module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_AUTOHINTER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_CFF_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the CFF driver module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_CFF_DRIVER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the TrueType driver module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_TRUETYPE_DRIVER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_PCF_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the PCF driver module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_PCF_DRIVER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_TYPE1_TABLES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * types and API specific to the Type~1 format. + * + */ +#define FT_TYPE1_TABLES_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_IDS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * enumeration values which identify name strings, languages, encodings, + * etc. This file really contains a _large_ set of constant macro + * definitions, taken from the TrueType and OpenType specifications. + * + */ +#define FT_TRUETYPE_IDS_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_TABLES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * types and API specific to the TrueType (as well as OpenType) format. + * + */ +#define FT_TRUETYPE_TABLES_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_TAGS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of TrueType four-byte 'tags' which identify blocks in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_TRUETYPE_TAGS_H + + + /************************************************************************** + * + * @macro: + * FT_BDF_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which accesses BDF-specific strings from a face. + * + */ +#define FT_BDF_H + + + /************************************************************************** + * + * @macro: + * FT_CID_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which access CID font information from a face. + * + */ +#define FT_CID_H + + + /************************************************************************** + * + * @macro: + * FT_GZIP_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports gzip-compressed files. + * + */ +#define FT_GZIP_H + + + /************************************************************************** + * + * @macro: + * FT_LZW_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports LZW-compressed files. + * + */ +#define FT_LZW_H + + + /************************************************************************** + * + * @macro: + * FT_BZIP2_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports bzip2-compressed files. + * + */ +#define FT_BZIP2_H + + + /************************************************************************** + * + * @macro: + * FT_WINFONTS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports Windows FNT files. + * + */ +#define FT_WINFONTS_H + + + /************************************************************************** + * + * @macro: + * FT_GLYPH_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional glyph management component. + * + */ +#define FT_GLYPH_H + + + /************************************************************************** + * + * @macro: + * FT_BITMAP_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional bitmap conversion component. + * + */ +#define FT_BITMAP_H + + + /************************************************************************** + * + * @macro: + * FT_BBOX_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional exact bounding box computation routines. + * + */ +#define FT_BBOX_H + + + /************************************************************************** + * + * @macro: + * FT_CACHE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional FreeType~2 cache sub-system. + * + */ +#define FT_CACHE_H + + + /************************************************************************** + * + * @macro: + * FT_MAC_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * Macintosh-specific FreeType~2 API. The latter is used to access fonts + * embedded in resource forks. + * + * This header file must be explicitly included by client applications + * compiled on the Mac (note that the base API still works though). + * + */ +#define FT_MAC_H + + + /************************************************************************** + * + * @macro: + * FT_MULTIPLE_MASTERS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional multiple-masters management API of FreeType~2. + * + */ +#define FT_MULTIPLE_MASTERS_H + + + /************************************************************************** + * + * @macro: + * FT_SFNT_NAMES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional FreeType~2 API which accesses embedded 'name' strings in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_SFNT_NAMES_H + + + /************************************************************************** + * + * @macro: + * FT_OPENTYPE_VALIDATE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional FreeType~2 API which validates OpenType tables ('BASE', + * 'GDEF', 'GPOS', 'GSUB', 'JSTF'). + * + */ +#define FT_OPENTYPE_VALIDATE_H + + + /************************************************************************** + * + * @macro: + * FT_GX_VALIDATE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional FreeType~2 API which validates TrueTypeGX/AAT tables ('feat', + * 'mort', 'morx', 'bsln', 'just', 'kern', 'opbd', 'trak', 'prop'). + * + */ +#define FT_GX_VALIDATE_H + + + /************************************************************************** + * + * @macro: + * FT_PFR_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which accesses PFR-specific data. + * + */ +#define FT_PFR_H + + + /************************************************************************** + * + * @macro: + * FT_STROKER_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which provides functions to stroke outline paths. + */ +#define FT_STROKER_H + + + /************************************************************************** + * + * @macro: + * FT_SYNTHESIS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs artificial obliquing and emboldening. + */ +#define FT_SYNTHESIS_H + + + /************************************************************************** + * + * @macro: + * FT_FONT_FORMATS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which provides functions specific to font formats. + */ +#define FT_FONT_FORMATS_H + + /* deprecated */ +#define FT_XFREE86_H FT_FONT_FORMATS_H + + + /************************************************************************** + * + * @macro: + * FT_TRIGONOMETRY_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs trigonometric computations (e.g., + * cosines and arc tangents). + */ +#define FT_TRIGONOMETRY_H + + + /************************************************************************** + * + * @macro: + * FT_LCD_FILTER_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_LCD_FILTER_H + + + /************************************************************************** + * + * @macro: + * FT_INCREMENTAL_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs incremental glyph loading. + */ +#define FT_INCREMENTAL_H + + + /************************************************************************** + * + * @macro: + * FT_GASP_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which returns entries from the TrueType GASP table. + */ +#define FT_GASP_H + + + /************************************************************************** + * + * @macro: + * FT_ADVANCES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which returns individual and ranged glyph advances. + */ +#define FT_ADVANCES_H + + + /************************************************************************** + * + * @macro: + * FT_COLOR_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which handles the OpenType 'CPAL' table. + */ +#define FT_COLOR_H + + + /************************************************************************** + * + * @macro: + * FT_OTSVG_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which handles the OpenType 'SVG~' glyphs. + */ +#define FT_OTSVG_H + + + /* */ + + /* These header files don't need to be included by the user. */ +#define FT_ERROR_DEFINITIONS_H +#define FT_PARAMETER_TAGS_H + + /* Deprecated macros. */ +#define FT_UNPATENTED_HINTING_H +#define FT_TRUETYPE_UNPATENTED_H + + /* `FT_CACHE_H` is the only header file needed for the cache subsystem. */ +#define FT_CACHE_IMAGE_H FT_CACHE_H +#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H +#define FT_CACHE_CHARMAP_H FT_CACHE_H + + /* The internals of the cache sub-system are no longer exposed. We */ + /* default to `FT_CACHE_H` at the moment just in case, but we know */ + /* of no rogue client that uses them. */ + /* */ +#define FT_CACHE_MANAGER_H FT_CACHE_H +#define FT_CACHE_INTERNAL_MRU_H FT_CACHE_H +#define FT_CACHE_INTERNAL_MANAGER_H FT_CACHE_H +#define FT_CACHE_INTERNAL_CACHE_H FT_CACHE_H +#define FT_CACHE_INTERNAL_GLYPH_H FT_CACHE_H +#define FT_CACHE_INTERNAL_IMAGE_H FT_CACHE_H +#define FT_CACHE_INTERNAL_SBITS_H FT_CACHE_H + +/* TODO(david): Move this section below to a different header */ +#ifdef FT2_BUILD_LIBRARY +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + + /* We disable the warning `conditional expression is constant' here */ + /* in order to compile cleanly with the maximum level of warnings. */ + /* In particular, the warning complains about stuff like `while(0)' */ + /* which is very useful in macro definitions. There is no benefit */ + /* in having it enabled. */ +#pragma warning( disable : 4127 ) + +#endif /* _MSC_VER */ +#endif /* FT2_BUILD_LIBRARY */ + +#endif /* FTHEADER_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/config/ftmodule.h b/vendor/freetype/include/freetype/config/ftmodule.h new file mode 100644 index 0000000..b315bab --- /dev/null +++ b/vendor/freetype/include/freetype/config/ftmodule.h @@ -0,0 +1,33 @@ +/* + * This file registers the FreeType modules compiled into the library. + * + * If you use GNU make, this file IS NOT USED! Instead, it is created in + * the objects directory (normally `/objs/`) based on information + * from `/modules.cfg`. + * + * Please read `docs/INSTALL.ANY` and `docs/CUSTOMIZE` how to compile + * FreeType without GNU make. + * + */ + +FT_USE_MODULE( FT_Module_Class, autofit_module_class ) +FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +FT_USE_MODULE( FT_Module_Class, psaux_module_class ) +FT_USE_MODULE( FT_Module_Class, psnames_module_class ) +FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) +FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_bitmap_sdf_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_svg_renderer_class ) + +/* EOF */ diff --git a/vendor/freetype/include/freetype/config/ftoption.h b/vendor/freetype/include/freetype/config/ftoption.h new file mode 100644 index 0000000..1976b33 --- /dev/null +++ b/vendor/freetype/include/freetype/config/ftoption.h @@ -0,0 +1,1014 @@ +/**************************************************************************** + * + * ftoption.h + * + * User-selectable configuration macros (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTOPTION_H_ +#define FTOPTION_H_ + + +#include + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * USER-SELECTABLE CONFIGURATION MACROS + * + * This file contains the default configuration macro definitions for a + * standard build of the FreeType library. There are three ways to use + * this file to build project-specific versions of the library: + * + * - You can modify this file by hand, but this is not recommended in + * cases where you would like to build several versions of the library + * from a single source directory. + * + * - You can put a copy of this file in your build directory, more + * precisely in `$BUILD/freetype/config/ftoption.h`, where `$BUILD` is + * the name of a directory that is included _before_ the FreeType include + * path during compilation. + * + * The default FreeType Makefiles use the build directory + * `builds/` by default, but you can easily change that for your + * own projects. + * + * - Copy the file to `$BUILD/ft2build.h` and modify it + * slightly to pre-define the macro `FT_CONFIG_OPTIONS_H` used to locate + * this file during the build. For example, + * + * ``` + * #define FT_CONFIG_OPTIONS_H + * #include + * ``` + * + * will use `$BUILD/myftoptions.h` instead of this file for macro + * definitions. + * + * Note also that you can similarly pre-define the macro + * `FT_CONFIG_MODULES_H` used to locate the file listing of the modules + * that are statically linked to the library at compile time. By + * default, this file is ``. + * + * We highly recommend using the third method whenever possible. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*#************************************************************************ + * + * If you enable this configuration option, FreeType recognizes an + * environment variable called `FREETYPE_PROPERTIES`, which can be used to + * control the various font drivers and modules. The controllable + * properties are listed in the section @properties. + * + * You have to undefine this configuration option on platforms that lack + * the concept of environment variables (and thus don't have the `getenv` + * function), for example Windows CE. + * + * `FREETYPE_PROPERTIES` has the following syntax form (broken here into + * multiple lines for better readability). + * + * ``` + * + * ':' + * '=' + * + * ':' + * '=' + * ... + * ``` + * + * Example: + * + * ``` + * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ + * cff:no-stem-darkening=1 + * ``` + * + */ +#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + + /************************************************************************** + * + * Uncomment the line below if you want to activate LCD rendering + * technology similar to ClearType in this build of the library. This + * technology triples the resolution in the direction color subpixels. To + * mitigate color fringes inherent to this technology, you also need to + * explicitly set up LCD filtering. + * + * When this macro is not defined, FreeType offers alternative LCD + * rendering technology that produces excellent output. + */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + + /************************************************************************** + * + * Many compilers provide a non-ANSI 64-bit data type that can be used by + * FreeType to speed up some computations. However, this will create some + * problems when compiling the library in strict ANSI mode. + * + * For this reason, the use of 64-bit integers is normally disabled when + * the `__STDC__` macro is defined. You can however disable this by + * defining the macro `FT_CONFIG_OPTION_FORCE_INT64` here. + * + * For most compilers, this will only create compilation warnings when + * building the library. + * + * ObNote: The compiler-specific 64-bit integers are detected in the + * file `ftconfig.h` either statically or through the `configure` + * script on supported platforms. + */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /************************************************************************** + * + * If this macro is defined, do not try to use an assembler version of + * performance-critical functions (e.g., @FT_MulFix). You should only do + * that to verify that the assembler function works properly, or to execute + * benchmark tests of the various implementations. + */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ + + + /************************************************************************** + * + * If this macro is defined, try to use an inlined assembler version of the + * @FT_MulFix function, which is a 'hotspot' when loading and hinting + * glyphs, and which should be executed as fast as possible. + * + * Note that if your compiler or CPU is not supported, this will default to + * the standard and portable implementation found in `ftcalc.c`. + */ +#define FT_CONFIG_OPTION_INLINE_MULFIX + + + /************************************************************************** + * + * LZW-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `compress` program. This is mostly used to parse many of the PCF + * files that come with various X11 distributions. The implementation + * uses NetBSD's `zopen` to partially uncompress the file on the fly (see + * `src/lzw/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. + */ +#define FT_CONFIG_OPTION_USE_LZW + + + /************************************************************************** + * + * Gzip-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `gzip` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses 'zlib' to partially + * uncompress the file on the fly (see `src/gzip/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. See also the + * macro `FT_CONFIG_OPTION_SYSTEM_ZLIB` below. + */ +#define FT_CONFIG_OPTION_USE_ZLIB + + + /************************************************************************** + * + * ZLib library selection + * + * This macro is only used when `FT_CONFIG_OPTION_USE_ZLIB` is defined. + * It allows FreeType's 'ftgzip' component to link to the system's + * installation of the ZLib library. This is useful on systems like + * Unix or VMS where it generally is already available. + * + * If you let it undefined, the component will use its own copy of the + * zlib sources instead. These have been modified to be included + * directly within the component and **not** export external function + * names. This allows you to link any program with FreeType _and_ ZLib + * without linking conflicts. + * + * Do not `#undef` this macro here since the build system might define + * it for certain configurations only. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + * + * If you use the GNU make build system directly (that is, without the + * `configure` script) and you define this macro, you also have to pass + * `SYSTEM_ZLIB=yes` as an argument to make. + */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /************************************************************************** + * + * Bzip2-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `bzip2` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses `libbz2` to partially + * uncompress the file on the fly (see `src/bzip2/ftbzip2.c`). Contrary + * to gzip, bzip2 currently is not included and need to use the system + * available bzip2 implementation. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_BZIP2 */ + + + /************************************************************************** + * + * Define to disable the use of file stream functions and types, `FILE`, + * `fopen`, etc. Enables the use of smaller system libraries on embedded + * systems that have multiple system libraries, some with or without file + * stream support, in the cases where file stream support is not necessary + * such as memory loading of font files. + */ +/* #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ + + + /************************************************************************** + * + * PNG bitmap support. + * + * FreeType now handles loading color bitmap glyphs in the PNG format. + * This requires help from the external libpng library. Uncompressed + * color bitmaps do not need any external libraries and will be supported + * regardless of this configuration. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_PNG */ + + + /************************************************************************** + * + * HarfBuzz support. + * + * FreeType uses the HarfBuzz library to improve auto-hinting of OpenType + * fonts. If available, many glyphs not directly addressable by a font's + * character map will be hinted also. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + /************************************************************************** + * + * Brotli support. + * + * FreeType uses the Brotli library to provide support for decompressing + * WOFF2 streams. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_BROTLI */ + + + /************************************************************************** + * + * Glyph Postscript Names handling + * + * By default, FreeType 2 is compiled with the 'psnames' module. This + * module is in charge of converting a glyph name string into a Unicode + * value, or return a Macintosh standard glyph name for the use with the + * TrueType 'post' table. + * + * Undefine this macro if you do not want 'psnames' compiled in your + * build of FreeType. This has the following effects: + * + * - The TrueType driver will provide its own set of glyph names, if you + * build it to support postscript names in the TrueType 'post' table, + * but will not synthesize a missing Unicode charmap. + * + * - The Type~1 driver will not be able to synthesize a Unicode charmap + * out of the glyphs found in the fonts. + * + * You would normally undefine this configuration macro when building a + * version of FreeType that doesn't contain a Type~1 or CFF driver. + */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Postscript Names to Unicode Values support + * + * By default, FreeType~2 is built with the 'psnames' module compiled in. + * Among other things, the module is used to convert a glyph name into a + * Unicode value. This is especially useful in order to synthesize on + * the fly a Unicode charmap from the CFF/Type~1 driver through a big + * table named the 'Adobe Glyph List' (AGL). + * + * Undefine this macro if you do not want the Adobe Glyph List compiled + * in your 'psnames' module. The Type~1 driver will not be able to + * synthesize a Unicode charmap out of the glyphs found in the fonts. + */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /************************************************************************** + * + * Support for Mac fonts + * + * Define this macro if you want support for outline fonts in Mac format + * (mac dfont, mac resource, macbinary containing a mac resource) on + * non-Mac platforms. + * + * Note that the 'FOND' resource isn't checked. + */ +#define FT_CONFIG_OPTION_MAC_FONTS + + + /************************************************************************** + * + * Guessing methods to access embedded resource forks + * + * Enable extra Mac fonts support on non-Mac platforms (e.g., GNU/Linux). + * + * Resource forks which include fonts data are stored sometimes in + * locations which users or developers don't expected. In some cases, + * resource forks start with some offset from the head of a file. In + * other cases, the actual resource fork is stored in file different from + * what the user specifies. If this option is activated, FreeType tries + * to guess whether such offsets or different file names must be used. + * + * Note that normal, direct access of resource forks is controlled via + * the `FT_CONFIG_OPTION_MAC_FONTS` option. + */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /************************************************************************** + * + * Allow the use of `FT_Incremental_Interface` to load typefaces that + * contain no glyph data, but supply it via a callback function. This is + * required by clients supporting document formats which supply font data + * incrementally as the document is parsed, such as the Ghostscript + * interpreter for the PostScript language. + */ +#define FT_CONFIG_OPTION_INCREMENTAL + + + /************************************************************************** + * + * The size in bytes of the render pool used by the scan-line converter to + * do all of its work. + */ +#define FT_RENDER_POOL_SIZE 16384L + + + /************************************************************************** + * + * FT_MAX_MODULES + * + * The maximum number of modules that can be registered in a single + * FreeType library object. 32~is the default. + */ +#define FT_MAX_MODULES 32 + + + /************************************************************************** + * + * Debug level + * + * FreeType can be compiled in debug or trace mode. In debug mode, + * errors are reported through the 'ftdebug' component. In trace mode, + * additional messages are sent to the standard output during execution. + * + * Define `FT_DEBUG_LEVEL_ERROR` to build the library in debug mode. + * Define `FT_DEBUG_LEVEL_TRACE` to build it in trace mode. + * + * Don't define any of these macros to compile in 'release' mode! + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * Logging + * + * Compiling FreeType in debug or trace mode makes FreeType write error + * and trace log messages to `stderr`. Enabling this macro + * automatically forces the `FT_DEBUG_LEVEL_ERROR` and + * `FT_DEBUG_LEVEL_TRACE` macros and allows FreeType to write error and + * trace log messages to a file instead of `stderr`. For writing logs + * to a file, FreeType uses an the external `dlg` library (the source + * code is in `src/dlg`). + * + * This option needs a C99 compiler. + */ +/* #define FT_DEBUG_LOGGING */ + + + /************************************************************************** + * + * Autofitter debugging + * + * If `FT_DEBUG_AUTOFIT` is defined, FreeType provides some means to + * control the autofitter behaviour for debugging purposes with global + * boolean variables (consequently, you should **never** enable this + * while compiling in 'release' mode): + * + * ``` + * af_debug_disable_horz_hints_ + * af_debug_disable_vert_hints_ + * af_debug_disable_blue_hints_ + * ``` + * + * Additionally, the following functions provide dumps of various + * internal autofit structures to stdout (using `printf`): + * + * ``` + * af_glyph_hints_dump_points + * af_glyph_hints_dump_segments + * af_glyph_hints_dump_edges + * af_glyph_hints_get_num_segments + * af_glyph_hints_get_segment_offset + * ``` + * + * As an argument, they use another global variable: + * + * ``` + * af_debug_hints_ + * ``` + * + * Please have a look at the `ftgrid` demo program to see how those + * variables and macros should be used. + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +/* #define FT_DEBUG_AUTOFIT */ + + + /************************************************************************** + * + * Memory Debugging + * + * FreeType now comes with an integrated memory debugger that is capable + * of detecting simple errors like memory leaks or double deletes. To + * compile it within your build of the library, you should define + * `FT_DEBUG_MEMORY` here. + * + * Note that the memory debugger is only activated at runtime when when + * the _environment_ variable `FT2_DEBUG_MEMORY` is defined also! + * + * Do not `#undef` this macro here since the build system might define it + * for certain configurations only. + */ +/* #define FT_DEBUG_MEMORY */ + + + /************************************************************************** + * + * Module errors + * + * If this macro is set (which is _not_ the default), the higher byte of + * an error code gives the module in which the error has occurred, while + * the lower byte is the real error code. + * + * Setting this macro makes sense for debugging purposes only, since it + * would break source compatibility of certain programs that use + * FreeType~2. + * + * More details can be found in the files `ftmoderr.h` and `fterrors.h`. + */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + /************************************************************************** + * + * OpenType SVG Glyph Support + * + * Setting this macro enables support for OpenType SVG glyphs. By + * default, FreeType can only fetch SVG documents. However, it can also + * render them if external rendering hook functions are plugged in at + * runtime. + * + * More details on the hooks can be found in file `otsvg.h`. + */ +#define FT_CONFIG_OPTION_SVG + + + /************************************************************************** + * + * Error Strings + * + * If this macro is set, `FT_Error_String` will return meaningful + * descriptions. This is not enabled by default to reduce the overall + * size of FreeType. + * + * More details can be found in the file `fterrors.h`. + */ +/* #define FT_CONFIG_OPTION_ERROR_STRINGS */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_EMBEDDED_BITMAPS` if you want to support + * embedded bitmaps in all formats using the 'sfnt' module (namely + * TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COLOR_LAYERS` if you want to support colored + * outlines (from the 'COLR'/'CPAL' tables) in all formats using the 'sfnt' + * module (namely TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_COLOR_LAYERS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_POSTSCRIPT_NAMES` if you want to be able to + * load and enumerate Postscript names of glyphs in a TrueType or OpenType + * file. + * + * Note that if you do not compile the 'psnames' module by undefining the + * above `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` macro, the 'sfnt' module will + * contain additional code to read the PostScript name table from a font. + * + * (By default, the module uses 'psnames' to extract glyph names.) + */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SFNT_NAMES` if your applications need to access + * the internal name table in a SFNT-based format like TrueType or + * OpenType. The name table contains various strings used to describe the + * font, like family name, copyright, version, etc. It does not contain + * any glyph name though. + * + * Accessing SFNT names is done through the functions declared in + * `ftsnames.h`. + */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /************************************************************************** + * + * TrueType CMap support + * + * Here you can fine-tune which TrueType CMap table format shall be + * supported. + */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` if you want to compile a + * bytecode interpreter in the TrueType driver. + * + * By undefining this, you will only compile the code necessary to load + * TrueType glyphs without hinting. + * + * Do not `#undef` this macro here, since the build system might define it + * for certain configurations only. + */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SUBPIXEL_HINTING` if you want to compile + * subpixel hinting support into the TrueType driver. This modifies the + * TrueType hinting mechanism when anything but `FT_RENDER_MODE_MONO` is + * requested. + * + * In particular, it modifies the bytecode interpreter to interpret (or + * not) instructions in a certain way so that all TrueType fonts look like + * they do in a Windows ClearType (DirectWrite) environment. See [1] for a + * technical overview on what this means. See `ttinterp.h` for more + * details on this option. + * + * The new default mode focuses on applying a minimal set of rules to all + * fonts indiscriminately so that modern and web fonts render well while + * legacy fonts render okay. The corresponding interpreter version is v40. + * The so-called Infinality mode (v38) is no longer available in FreeType. + * + * By undefining these, you get rendering behavior like on Windows without + * ClearType, i.e., Windows XP without ClearType enabled and Win9x + * (interpreter version v35). Or not, depending on how much hinting blood + * and testing tears the font designer put into a given font. If you + * define one or both subpixel hinting options, you can switch between + * between v35 and the ones you define (using `FT_Property_Set`). + * + * This option requires `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` to be + * defined. + * + * [1] + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED` to compile the + * TrueType glyph loader to use Apple's definition of how to handle + * component offsets in composite glyphs. + * + * Apple and MS disagree on the default behavior of component offsets in + * composites. Apple says that they should be scaled by the scaling + * factors in the transformation matrix (roughly, it's more complex) while + * MS says they should not. OpenType defines two bits in the composite + * flags array which can be used to disambiguate, but old fonts will not + * have them. + * + * https://www.microsoft.com/typography/otspec/glyf.htm + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html + */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_GX_VAR_SUPPORT` if you want to include support + * for Apple's distortable font technology ('fvar', 'gvar', 'cvar', and + * 'avar' tables). Tagged 'Font Variations', this is now part of OpenType + * also. This has many similarities to Type~1 Multiple Masters support. + */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_NO_BORING_EXPANSION` if you want to exclude + * support for 'boring' OpenType specification expansions. + * + * https://github.com/harfbuzz/boring-expansion-spec + * + * Right now, the following features are covered: + * + * - 'avar' version 2.0 + * + * Most likely, this is a temporary configuration option to be removed in + * the near future, since it is assumed that eventually those features are + * added to the OpenType standard. + */ +/* #define TT_CONFIG_OPTION_NO_BORING_EXPANSION */ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an + * embedded 'BDF~' table within SFNT-based bitmap formats. + */ +#define TT_CONFIG_OPTION_BDF + + + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES` controls the maximum + * number of bytecode instructions executed for a single run of the + * bytecode interpreter, needed to prevent infinite loops. You don't want + * to change this except for very special situations (e.g., making a + * library fuzzer spend less time to handle broken fonts). + * + * It is not expected that this value is ever modified by a configuring + * script; instead, it gets surrounded with `#ifndef ... #endif` so that + * the value can be set as a preprocessor option on the compiler's command + * line. + */ +#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES +#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * `T1_MAX_DICT_DEPTH` is the maximum depth of nest dictionaries and arrays + * in the Type~1 stream (see `t1load.c`). A minimum of~4 is required. + */ +#define T1_MAX_DICT_DEPTH 5 + + + /************************************************************************** + * + * `T1_MAX_SUBRS_CALLS` details the maximum number of nested sub-routine + * calls during glyph loading. + */ +#define T1_MAX_SUBRS_CALLS 16 + + + /************************************************************************** + * + * `T1_MAX_CHARSTRING_OPERANDS` is the charstring stack's capacity. A + * minimum of~16 is required. + * + * The Chinese font 'MingTiEG-Medium' (covering the CNS 11643 character + * set) needs 256. + */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the 't1afm' module, which is in charge of reading Type~1 AFM files + * into an existing face. Note that if set, the Type~1 driver will be + * unable to produce kerning distances. + */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the Multiple Masters font support in the Type~1 driver. + */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /************************************************************************** + * + * `T1_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe Type~1 + * engine gets compiled into FreeType. If defined, it is possible to + * switch between the two engines using the `hinting-engine` property of + * the 'type1' driver module. + */ +/* #define T1_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** C F F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Using `CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4}` it is + * possible to set up the default values of the four control points that + * define the stem darkening behaviour of the (new) CFF engine. For more + * details please read the documentation of the `darkening-parameters` + * property (file `ftdriver.h`), which allows the control at run-time. + * + * Do **not** undefine these macros! + */ +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0 + + + /************************************************************************** + * + * `CFF_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe CFF engine + * gets compiled into FreeType. If defined, it is possible to switch + * between the two engines using the `hinting-engine` property of the 'cff' + * driver module. + */ +/* #define CFF_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** P C F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * There are many PCF fonts just called 'Fixed' which look completely + * different, and which have nothing to do with each other. When selecting + * 'Fixed' in KDE or Gnome one gets results that appear rather random, the + * style changes often if one changes the size and one cannot select some + * fonts at all. This option makes the 'pcf' module prepend the foundry + * name (plus a space) to the family name. + * + * We also check whether we have 'wide' characters; all put together, we + * get family names like 'Sony Fixed' or 'Misc Fixed Wide'. + * + * If this option is activated, it can be controlled with the + * `no-long-family-names` property of the 'pcf' driver module. + */ +/* #define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Compile 'autofit' module with CJK (Chinese, Japanese, Korean) script + * support. + */ +#define AF_CONFIG_OPTION_CJK + + + /************************************************************************** + * + * Compile 'autofit' module with fallback Indic script support, covering + * some scripts that the 'latin' submodule of the 'autofit' module doesn't + * (yet) handle. Currently, this needs option `AF_CONFIG_OPTION_CJK`. + */ +#ifdef AF_CONFIG_OPTION_CJK +#define AF_CONFIG_OPTION_INDIC +#endif + + + /************************************************************************** + * + * Use TrueType-like size metrics for 'light' auto-hinting. + * + * It is strongly recommended to avoid this option, which exists only to + * help some legacy applications retain its appearance and behaviour with + * respect to auto-hinted TrueType fonts. + * + * The very reason this option exists at all are GNU/Linux distributions + * like Fedora that did not un-patch the following change (which was + * present in FreeType between versions 2.4.6 and 2.7.1, inclusive). + * + * ``` + * 2011-07-16 Steven Chu + * + * [truetype] Fix metrics on size request for scalable fonts. + * ``` + * + * This problematic commit is now reverted (more or less). + */ +/* #define AF_CONFIG_OPTION_TT_SIZE_METRICS */ + + /* */ + + + /* + * This macro is obsolete. Support has been removed in FreeType version + * 2.5. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * The next two macros are defined if native TrueType hinting is + * requested by the definitions above. Don't change this. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#endif +#endif + + + /* + * The TT_SUPPORT_COLRV1 macro is defined to indicate to clients that this + * version of FreeType has support for 'COLR' v1 API. This definition is + * useful to FreeType clients that want to build in support for 'COLR' v1 + * depending on a tip-of-tree checkout before it is officially released in + * FreeType, and while the feature cannot yet be tested against using + * version macros. Don't change this macro. This may be removed once the + * feature is in a FreeType release version and version macros can be used + * to test for availability. + */ +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define TT_SUPPORT_COLRV1 +#endif + + + /* + * Check CFF darkening parameters. The checks are the same as in function + * `cff_property_set` in file `cffdrivr.c`. + */ +#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500 +#error "Invalid CFF darkening parameters!" +#endif + + +FT_END_HEADER + +#endif /* FTOPTION_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/config/ftstdlib.h b/vendor/freetype/include/freetype/config/ftstdlib.h new file mode 100644 index 0000000..f65148a --- /dev/null +++ b/vendor/freetype/include/freetype/config/ftstdlib.h @@ -0,0 +1,185 @@ +/**************************************************************************** + * + * ftstdlib.h + * + * ANSI-specific library and header configuration file (specification + * only). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to group all `#includes` to the ANSI~C library that + * FreeType normally requires. It also defines macros to rename the + * standard functions within the FreeType source code. + * + * Load a file which defines `FTSTDLIB_H_` before this one to override it. + * + */ + + +#ifndef FTSTDLIB_H_ +#define FTSTDLIB_H_ + + +#include + +#define ft_ptrdiff_t ptrdiff_t + + + /************************************************************************** + * + * integer limits + * + * `UINT_MAX` and `ULONG_MAX` are used to automatically compute the size of + * `int` and `long` in bytes at compile-time. So far, this works for all + * platforms the library has been tested on. We also check `ULLONG_MAX` + * to see whether we can use 64-bit `long long` later on. + * + * Note that on the extremely rare platforms that do not provide integer + * types that are _exactly_ 16 and 32~bits wide (e.g., some old Crays where + * `int` is 36~bits), we do not make any guarantee about the correct + * behaviour of FreeType~2 with all fonts. + * + * In these cases, `ftconfig.h` will refuse to compile anyway with a + * message like 'couldn't find 32-bit type' or something similar. + * + */ + + +#include + +#define FT_CHAR_BIT CHAR_BIT +#define FT_USHORT_MAX USHRT_MAX +#define FT_INT_MAX INT_MAX +#define FT_INT_MIN INT_MIN +#define FT_UINT_MAX UINT_MAX +#define FT_LONG_MIN LONG_MIN +#define FT_LONG_MAX LONG_MAX +#define FT_ULONG_MAX ULONG_MAX +#ifdef LLONG_MAX +#define FT_LLONG_MAX LLONG_MAX +#endif +#ifdef LLONG_MIN +#define FT_LLONG_MIN LLONG_MIN +#endif +#ifdef ULLONG_MAX +#define FT_ULLONG_MAX ULLONG_MAX +#endif + + + /************************************************************************** + * + * character and string processing + * + */ + + +#include + +#define ft_memchr memchr +#define ft_memcmp memcmp +#define ft_memcpy memcpy +#define ft_memmove memmove +#define ft_memset memset +#define ft_strcat strcat +#define ft_strcmp strcmp +#define ft_strcpy strcpy +#define ft_strlen strlen +#define ft_strncmp strncmp +#define ft_strncpy strncpy +#define ft_strrchr strrchr +#define ft_strstr strstr + + + /************************************************************************** + * + * file handling + * + */ + + +#include + +#define FT_FILE FILE +#define ft_fclose fclose +#define ft_fopen fopen +#define ft_fread fread +#define ft_fseek fseek +#define ft_ftell ftell +#define ft_snprintf snprintf + + + /************************************************************************** + * + * sorting + * + */ + + +#include + +#define ft_qsort qsort + + + /************************************************************************** + * + * memory allocation + * + */ + + +#define ft_scalloc calloc +#define ft_sfree free +#define ft_smalloc malloc +#define ft_srealloc realloc + + + /************************************************************************** + * + * miscellaneous + * + */ + + +#define ft_strtol strtol +#define ft_getenv getenv + + + /************************************************************************** + * + * execution control + * + */ + + +#include + +#define ft_jmp_buf jmp_buf /* note: this cannot be a typedef since */ + /* `jmp_buf` is defined as a macro */ + /* on certain platforms */ + +#define ft_longjmp longjmp +#define ft_setjmp( b ) setjmp( *(ft_jmp_buf*) &(b) ) /* same thing here */ + + + /* The following is only used for debugging purposes, i.e., if */ + /* `FT_DEBUG_LEVEL_ERROR` or `FT_DEBUG_LEVEL_TRACE` are defined. */ + +#include + + +#endif /* FTSTDLIB_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/config/integer-types.h b/vendor/freetype/include/freetype/config/integer-types.h new file mode 100644 index 0000000..7258b50 --- /dev/null +++ b/vendor/freetype/include/freetype/config/integer-types.h @@ -0,0 +1,250 @@ +/**************************************************************************** + * + * config/integer-types.h + * + * FreeType integer types definitions. + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ +#ifndef FREETYPE_CONFIG_INTEGER_TYPES_H_ +#define FREETYPE_CONFIG_INTEGER_TYPES_H_ + + /* There are systems (like the Texas Instruments 'C54x) where a `char` */ + /* has 16~bits. ANSI~C says that `sizeof(char)` is always~1. Since an */ + /* `int` has 16~bits also for this system, `sizeof(int)` gives~1 which */ + /* is probably unexpected. */ + /* */ + /* `CHAR_BIT` (defined in `limits.h`) gives the number of bits in a */ + /* `char` type. */ + +#ifndef FT_CHAR_BIT +#define FT_CHAR_BIT CHAR_BIT +#endif + +#ifndef FT_SIZEOF_INT + + /* The size of an `int` type. */ +#if FT_UINT_MAX == 0xFFFFUL +#define FT_SIZEOF_INT ( 16 / FT_CHAR_BIT ) +#elif FT_UINT_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_INT ( 32 / FT_CHAR_BIT ) +#elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_INT ( 64 / FT_CHAR_BIT ) +#else +#error "Unsupported size of `int' type!" +#endif + +#endif /* !defined(FT_SIZEOF_INT) */ + +#ifndef FT_SIZEOF_LONG + + /* The size of a `long` type. A five-byte `long` (as used e.g. on the */ + /* DM642) is recognized but avoided. */ +#if FT_ULONG_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_LONG ( 32 / FT_CHAR_BIT ) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFUL +#define FT_SIZEOF_LONG ( 32 / FT_CHAR_BIT ) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_LONG ( 64 / FT_CHAR_BIT ) +#else +#error "Unsupported size of `long' type!" +#endif + +#endif /* !defined(FT_SIZEOF_LONG) */ + +#ifndef FT_SIZEOF_LONG_LONG + + /* The size of a `long long` type if available */ +#if defined( FT_ULLONG_MAX ) && FT_ULLONG_MAX >= 0xFFFFFFFFFFFFFFFFULL +#define FT_SIZEOF_LONG_LONG ( 64 / FT_CHAR_BIT ) +#else +#define FT_SIZEOF_LONG_LONG 0 +#endif + +#endif /* !defined(FT_SIZEOF_LONG_LONG) */ + + + /************************************************************************** + * + * @section: + * basic_types + * + */ + + + /************************************************************************** + * + * @type: + * FT_Int16 + * + * @description: + * A typedef for a 16bit signed integer type. + */ + typedef signed short FT_Int16; + + + /************************************************************************** + * + * @type: + * FT_UInt16 + * + * @description: + * A typedef for a 16bit unsigned integer type. + */ + typedef unsigned short FT_UInt16; + + /* */ + + + /* this #if 0 ... #endif clause is for documentation purposes */ +#if 0 + + /************************************************************************** + * + * @type: + * FT_Int32 + * + * @description: + * A typedef for a 32bit signed integer type. The size depends on the + * configuration. + */ + typedef signed XXX FT_Int32; + + + /************************************************************************** + * + * @type: + * FT_UInt32 + * + * A typedef for a 32bit unsigned integer type. The size depends on the + * configuration. + */ + typedef unsigned XXX FT_UInt32; + + + /************************************************************************** + * + * @type: + * FT_Int64 + * + * A typedef for a 64bit signed integer type. The size depends on the + * configuration. Only defined if there is real 64bit support; + * otherwise, it gets emulated with a structure (if necessary). + */ + typedef signed XXX FT_Int64; + + + /************************************************************************** + * + * @type: + * FT_UInt64 + * + * A typedef for a 64bit unsigned integer type. The size depends on the + * configuration. Only defined if there is real 64bit support; + * otherwise, it gets emulated with a structure (if necessary). + */ + typedef unsigned XXX FT_UInt64; + + /* */ + +#endif + +#if FT_SIZEOF_INT == ( 32 / FT_CHAR_BIT ) + + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; + +#elif FT_SIZEOF_LONG == ( 32 / FT_CHAR_BIT ) + + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; + +#else +#error "no 32bit type found -- please check your configuration files" +#endif + + + /* look up an integer type that is at least 32~bits */ +#if FT_SIZEOF_INT >= ( 32 / FT_CHAR_BIT ) + + typedef int FT_Fast; + typedef unsigned int FT_UFast; + +#elif FT_SIZEOF_LONG >= ( 32 / FT_CHAR_BIT ) + + typedef long FT_Fast; + typedef unsigned long FT_UFast; + +#endif + + + /* determine whether we have a 64-bit integer type */ +#if FT_SIZEOF_LONG == ( 64 / FT_CHAR_BIT ) + +#define FT_INT64 long +#define FT_UINT64 unsigned long + +#elif FT_SIZEOF_LONG_LONG >= ( 64 / FT_CHAR_BIT ) + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + + /************************************************************************** + * + * A 64-bit data type may create compilation problems if you compile in + * strict ANSI mode. To avoid them, we disable other 64-bit data types if + * `__STDC__` is defined. You can however ignore this rule by defining the + * `FT_CONFIG_OPTION_FORCE_INT64` configuration macro. + */ +#elif !defined( __STDC__ ) || defined( FT_CONFIG_OPTION_FORCE_INT64 ) + +#if defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ + + /* this compiler provides the `__int64` type */ +#define FT_INT64 __int64 +#define FT_UINT64 unsigned __int64 + +#elif defined( __BORLANDC__ ) /* Borland C++ */ + + /* XXXX: We should probably check the value of `__BORLANDC__` in order */ + /* to test the compiler version. */ + + /* this compiler provides the `__int64` type */ +#define FT_INT64 __int64 +#define FT_UINT64 unsigned __int64 + +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1100 /* Watcom C++ */ + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */ + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#elif defined( __GNUC__ ) + + /* GCC provides the `long long` type */ +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#endif /* !__STDC__ */ + +#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ + +#ifdef FT_INT64 + typedef FT_INT64 FT_Int64; + typedef FT_UINT64 FT_UInt64; +#endif + + +#endif /* FREETYPE_CONFIG_INTEGER_TYPES_H_ */ diff --git a/vendor/freetype/include/freetype/config/mac-support.h b/vendor/freetype/include/freetype/config/mac-support.h new file mode 100644 index 0000000..b77b96d --- /dev/null +++ b/vendor/freetype/include/freetype/config/mac-support.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * config/mac-support.h + * + * Mac/OS X support configuration header. + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ +#ifndef FREETYPE_CONFIG_MAC_SUPPORT_H_ +#define FREETYPE_CONFIG_MAC_SUPPORT_H_ + + /************************************************************************** + * + * Mac support + * + * This is the only necessary change, so it is defined here instead + * providing a new configuration file. + */ +#if defined( __APPLE__ ) || ( defined( __MWERKS__ ) && defined( macintosh ) ) + /* No Carbon frameworks for 64bit 10.4.x. */ + /* `AvailabilityMacros.h` is available since Mac OS X 10.2, */ + /* so guess the system version by maximum errno before inclusion. */ +#include +#ifdef ECANCELED /* defined since 10.2 */ +#include "AvailabilityMacros.h" +#endif +#if defined( __LP64__ ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) +#undef FT_MACINTOSH +#endif + +#elif defined( __SC__ ) || defined( __MRC__ ) + /* Classic MacOS compilers */ +#include "ConditionalMacros.h" +#if TARGET_OS_MAC +#define FT_MACINTOSH 1 +#endif + +#endif /* Mac support */ + +#endif /* FREETYPE_CONFIG_MAC_SUPPORT_H_ */ diff --git a/vendor/freetype/include/freetype/config/public-macros.h b/vendor/freetype/include/freetype/config/public-macros.h new file mode 100644 index 0000000..23d0fa6 --- /dev/null +++ b/vendor/freetype/include/freetype/config/public-macros.h @@ -0,0 +1,138 @@ +/**************************************************************************** + * + * config/public-macros.h + * + * Define a set of compiler macros used in public FreeType headers. + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /* + * The definitions in this file are used by the public FreeType headers + * and thus should be considered part of the public API. + * + * Other compiler-specific macro definitions that are not exposed by the + * FreeType API should go into + * `include/freetype/internal/compiler-macros.h` instead. + */ +#ifndef FREETYPE_CONFIG_PUBLIC_MACROS_H_ +#define FREETYPE_CONFIG_PUBLIC_MACROS_H_ + + /* + * `FT_BEGIN_HEADER` and `FT_END_HEADER` might have already been defined + * by `freetype/config/ftheader.h`, but we don't want to include this + * header here, so redefine the macros here only when needed. Their + * definition is very stable, so keeping them in sync with the ones in the + * header should not be a maintenance issue. + */ +#ifndef FT_BEGIN_HEADER +#ifdef __cplusplus +#define FT_BEGIN_HEADER extern "C" { +#else +#define FT_BEGIN_HEADER /* empty */ +#endif +#endif /* FT_BEGIN_HEADER */ + +#ifndef FT_END_HEADER +#ifdef __cplusplus +#define FT_END_HEADER } +#else +#define FT_END_HEADER /* empty */ +#endif +#endif /* FT_END_HEADER */ + + +FT_BEGIN_HEADER + + /* + * Mark a function declaration as public. This ensures it will be + * properly exported to client code. Place this before a function + * declaration. + * + * NOTE: This macro should be considered an internal implementation + * detail, and not part of the FreeType API. It is only defined here + * because it is needed by `FT_EXPORT`. + */ + + /* Visual C, mingw */ +#if defined( _WIN32 ) + +#if defined( FT2_BUILD_LIBRARY ) && defined( DLL_EXPORT ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllexport ) +#elif defined( DLL_IMPORT ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllimport ) +#endif + + /* gcc, clang */ +#elif ( defined( __GNUC__ ) && __GNUC__ >= 4 ) || defined( __clang__ ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE \ + __attribute__(( visibility( "default" ) )) + + /* Sun */ +#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __global +#endif + + +#ifndef FT_PUBLIC_FUNCTION_ATTRIBUTE +#define FT_PUBLIC_FUNCTION_ATTRIBUTE /* empty */ +#endif + + + /* + * Define a public FreeType API function. This ensures it is properly + * exported or imported at build time. The macro parameter is the + * function's return type as in: + * + * FT_EXPORT( FT_Bool ) + * FT_Object_Method( FT_Object obj, + * ... ); + * + * NOTE: This requires that all `FT_EXPORT` uses are inside + * `FT_BEGIN_HEADER ... FT_END_HEADER` blocks. This guarantees that the + * functions are exported with C linkage, even when the header is included + * by a C++ source file. + */ +#define FT_EXPORT( x ) FT_PUBLIC_FUNCTION_ATTRIBUTE extern x + + + /* + * `FT_UNUSED` indicates that a given parameter is not used -- this is + * only used to get rid of unpleasant compiler warnings. + * + * Technically, this was not meant to be part of the public API, but some + * third-party code depends on it. + */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /* + * Support for casts in both C and C++. + */ +#ifdef __cplusplus +#define FT_STATIC_CAST( type, var ) static_cast(var) +#define FT_REINTERPRET_CAST( type, var ) reinterpret_cast(var) + +#define FT_STATIC_BYTE_CAST( type, var ) \ + static_cast( static_cast( var ) ) +#else +#define FT_STATIC_CAST( type, var ) (type)(var) +#define FT_REINTERPRET_CAST( type, var ) (type)(var) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) +#endif + + +FT_END_HEADER + +#endif /* FREETYPE_CONFIG_PUBLIC_MACROS_H_ */ diff --git a/vendor/freetype/include/freetype/freetype.h b/vendor/freetype/include/freetype/freetype.h new file mode 100644 index 0000000..92acf37 --- /dev/null +++ b/vendor/freetype/include/freetype/freetype.h @@ -0,0 +1,5337 @@ +/**************************************************************************** + * + * freetype.h + * + * FreeType high-level API and common types (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FREETYPE_H_ +#define FREETYPE_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include + + +FT_BEGIN_HEADER + + + + /************************************************************************** + * + * @section: + * preamble + * + * @title: + * Preamble + * + * @abstract: + * What FreeType is and isn't + * + * @description: + * FreeType is a library that provides access to glyphs in font files. It + * scales the glyph images and their metrics to a requested size, and it + * rasterizes the glyph images to produce pixel or subpixel alpha coverage + * bitmaps. + * + * Note that FreeType is _not_ a text layout engine. You have to use + * higher-level libraries like HarfBuzz, Pango, or ICU for that. + * + * Note also that FreeType does _not_ perform alpha blending or + * compositing the resulting bitmaps or pixmaps by itself. Use your + * favourite graphics library (for example, Cairo or Skia) to further + * process FreeType's output. + * + */ + + + /************************************************************************** + * + * @section: + * header_inclusion + * + * @title: + * FreeType's header inclusion scheme + * + * @abstract: + * How client applications should include FreeType header files. + * + * @description: + * To be as flexible as possible (and for historical reasons), you must + * load file `ft2build.h` first before other header files, for example + * + * ``` + * #include + * + * #include + * #include + * ``` + */ + + + /************************************************************************** + * + * @section: + * user_allocation + * + * @title: + * User allocation + * + * @abstract: + * How client applications should allocate FreeType data structures. + * + * @description: + * FreeType assumes that structures allocated by the user and passed as + * arguments are zeroed out except for the actual data. In other words, + * it is recommended to use `calloc` (or variants of it) instead of + * `malloc` for allocation. + * + */ + + + /************************************************************************** + * + * @section: + * font_testing_macros + * + * @title: + * Font Testing Macros + * + * @abstract: + * Macros to test various properties of fonts. + * + * @description: + * Macros to test the most important font properties. + * + * It is recommended to use these high-level macros instead of directly + * testing the corresponding flags, which are scattered over various + * structures. + * + * @order: + * FT_HAS_HORIZONTAL + * FT_HAS_VERTICAL + * FT_HAS_KERNING + * FT_HAS_FIXED_SIZES + * FT_HAS_GLYPH_NAMES + * FT_HAS_COLOR + * FT_HAS_MULTIPLE_MASTERS + * FT_HAS_SVG + * FT_HAS_SBIX + * FT_HAS_SBIX_OVERLAY + * + * FT_IS_SFNT + * FT_IS_SCALABLE + * FT_IS_FIXED_WIDTH + * FT_IS_CID_KEYED + * FT_IS_TRICKY + * FT_IS_NAMED_INSTANCE + * FT_IS_VARIATION + * + */ + + + /************************************************************************** + * + * @section: + * library_setup + * + * @title: + * Library Setup + * + * @abstract: + * Functions to start and end the usage of the FreeType library. + * + * @description: + * Functions to start and end the usage of the FreeType library. + * + * Note that @FT_Library_Version and @FREETYPE_XXX are of limited use + * because even a new release of FreeType with only documentation + * changes increases the version number. + * + * @order: + * FT_Library + * FT_Init_FreeType + * FT_Done_FreeType + * + * FT_Library_Version + * FREETYPE_XXX + * + */ + + + /************************************************************************** + * + * @section: + * face_creation + * + * @title: + * Face Creation + * + * @abstract: + * Functions to manage fonts. + * + * @description: + * The functions and structures collected in this section operate on + * fonts globally. + * + * @order: + * FT_Face + * FT_FaceRec + * FT_FACE_FLAG_XXX + * FT_STYLE_FLAG_XXX + * + * FT_New_Face + * FT_Done_Face + * FT_Reference_Face + * FT_New_Memory_Face + * FT_Face_Properties + * FT_Open_Face + * FT_Open_Args + * FT_OPEN_XXX + * FT_Parameter + * FT_Attach_File + * FT_Attach_Stream + * + */ + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + * @title: + * Sizing and Scaling + * + * @abstract: + * Functions to manage font sizes. + * + * @description: + * The functions and structures collected in this section are related to + * selecting and manipulating the size of a font globally. + * + * @order: + * FT_Size + * FT_SizeRec + * FT_Size_Metrics + * + * FT_Bitmap_Size + * + * FT_Set_Char_Size + * FT_Set_Pixel_Sizes + * FT_Request_Size + * FT_Select_Size + * FT_Size_Request_Type + * FT_Size_RequestRec + * FT_Size_Request + * + * FT_Set_Transform + * FT_Get_Transform + * + */ + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + * @title: + * Glyph Retrieval + * + * @abstract: + * Functions to manage glyphs. + * + * @description: + * The functions and structures collected in this section operate on + * single glyphs, of which @FT_Load_Glyph is most important. + * + * @order: + * FT_GlyphSlot + * FT_GlyphSlotRec + * FT_Glyph_Metrics + * + * FT_Load_Glyph + * FT_LOAD_XXX + * FT_LOAD_TARGET_MODE + * FT_LOAD_TARGET_XXX + * + * FT_Render_Glyph + * FT_Render_Mode + * FT_Get_Kerning + * FT_Kerning_Mode + * FT_Get_Track_Kerning + * + */ + + + /************************************************************************** + * + * @section: + * character_mapping + * + * @title: + * Character Mapping + * + * @abstract: + * Functions to manage character-to-glyph maps. + * + * @description: + * This section holds functions and structures that are related to + * mapping character input codes to glyph indices. + * + * Note that for many scripts the simplistic approach used by FreeType + * of mapping a single character to a single glyph is not valid or + * possible! In general, a higher-level library like HarfBuzz or ICU + * should be used for handling text strings. + * + * @order: + * FT_CharMap + * FT_CharMapRec + * FT_Encoding + * FT_ENC_TAG + * + * FT_Select_Charmap + * FT_Set_Charmap + * FT_Get_Charmap_Index + * + * FT_Get_Char_Index + * FT_Get_First_Char + * FT_Get_Next_Char + * FT_Load_Char + * + */ + + + /************************************************************************** + * + * @section: + * information_retrieval + * + * @title: + * Information Retrieval + * + * @abstract: + * Functions to retrieve font and glyph information. + * + * @description: + * Functions to retrieve font and glyph information. Only some very + * basic data is covered; see also the chapter on the format-specific + * API for more. + * + * + * @order: + * FT_Get_Name_Index + * FT_Get_Glyph_Name + * FT_Get_Postscript_Name + * FT_Get_FSType_Flags + * FT_FSTYPE_XXX + * FT_Get_SubGlyph_Info + * FT_SUBGLYPH_FLAG_XXX + * + */ + + + /************************************************************************** + * + * @section: + * other_api_data + * + * @title: + * Other API Data + * + * @abstract: + * Other structures, enumerations, and macros. + * + * @description: + * Other structures, enumerations, and macros. Deprecated functions are + * also listed here. + * + * @order: + * FT_Face_Internal + * FT_Size_Internal + * FT_Slot_Internal + * + * FT_SubGlyph + * + * FT_HAS_FAST_GLYPHS + * FT_Face_CheckTrueTypePatents + * FT_Face_SetUnpatentedHinting + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S I C T Y P E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @struct: + * FT_Glyph_Metrics + * + * @description: + * A structure to model the metrics of a single glyph. The values are + * expressed in 26.6 fractional pixel format; if the flag + * @FT_LOAD_NO_SCALE has been used while loading the glyph, values are + * expressed in font units instead. + * + * @fields: + * width :: + * The glyph's width. + * + * height :: + * The glyph's height. + * + * horiBearingX :: + * Left side bearing for horizontal layout. + * + * horiBearingY :: + * Top side bearing for horizontal layout. + * + * horiAdvance :: + * Advance width for horizontal layout. + * + * vertBearingX :: + * Left side bearing for vertical layout. + * + * vertBearingY :: + * Top side bearing for vertical layout. Larger positive values mean + * further below the vertical glyph origin. + * + * vertAdvance :: + * Advance height for vertical layout. Positive values mean the glyph + * has a positive advance downward. + * + * @note: + * If not disabled with @FT_LOAD_NO_HINTING, the values represent + * dimensions of the hinted glyph (in case hinting is applicable). + * + * Stroking a glyph with an outside border does not increase + * `horiAdvance` or `vertAdvance`; you have to manually adjust these + * values to account for the added width and height. + * + * FreeType doesn't use the 'VORG' table data for CFF fonts because it + * doesn't have an interface to quickly retrieve the glyph height. The + * y~coordinate of the vertical origin can be simply computed as + * `vertBearingY + height` after loading a glyph. + */ + typedef struct FT_Glyph_Metrics_ + { + FT_Pos width; + FT_Pos height; + + FT_Pos horiBearingX; + FT_Pos horiBearingY; + FT_Pos horiAdvance; + + FT_Pos vertBearingX; + FT_Pos vertBearingY; + FT_Pos vertAdvance; + + } FT_Glyph_Metrics; + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @struct: + * FT_Bitmap_Size + * + * @description: + * This structure models the metrics of a bitmap strike (i.e., a set of + * glyphs for a given point size and resolution) in a bitmap font. It is + * used for the `available_sizes` field of @FT_Face. + * + * @fields: + * height :: + * The vertical distance, in pixels, between two consecutive baselines. + * It is always positive. + * + * width :: + * The average width, in pixels, of all glyphs in the strike. + * + * size :: + * The nominal size of the strike in 26.6 fractional points. This + * field is not very useful. + * + * x_ppem :: + * The horizontal ppem (nominal width) in 26.6 fractional pixels. + * + * y_ppem :: + * The vertical ppem (nominal height) in 26.6 fractional pixels. + * + * @note: + * Windows FNT: + * The nominal size given in a FNT font is not reliable. If the driver + * finds it incorrect, it sets `size` to some calculated values, and + * `x_ppem` and `y_ppem` to the pixel width and height given in the + * font, respectively. + * + * TrueType embedded bitmaps: + * `size`, `width`, and `height` values are not contained in the bitmap + * strike itself. They are computed from the global font parameters. + */ + typedef struct FT_Bitmap_Size_ + { + FT_Short height; + FT_Short width; + + FT_Pos size; + + FT_Pos x_ppem; + FT_Pos y_ppem; + + } FT_Bitmap_Size; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @section: + * library_setup + * + */ + + /************************************************************************** + * + * @type: + * FT_Library + * + * @description: + * A handle to a FreeType library instance. Each 'library' is completely + * independent from the others; it is the 'root' of a set of objects like + * fonts, faces, sizes, etc. + * + * It also embeds a memory manager (see @FT_Memory), as well as a + * scan-line converter object (see @FT_Raster). + * + * [Since 2.5.6] In multi-threaded applications it is easiest to use one + * `FT_Library` object per thread. In case this is too cumbersome, a + * single `FT_Library` object across threads is possible also, as long as + * a mutex lock is used around @FT_New_Face and @FT_Done_Face. + * + * @note: + * Library objects are normally created by @FT_Init_FreeType, and + * destroyed with @FT_Done_FreeType. If you need reference-counting + * (cf. @FT_Reference_Library), use @FT_New_Library and @FT_Done_Library. + */ + typedef struct FT_LibraryRec_ *FT_Library; + + + /************************************************************************** + * + * @section: + * module_management + * + */ + + /************************************************************************** + * + * @type: + * FT_Module + * + * @description: + * A handle to a given FreeType module object. A module can be a font + * driver, a renderer, or anything else that provides services to the + * former. + */ + typedef struct FT_ModuleRec_* FT_Module; + + + /************************************************************************** + * + * @type: + * FT_Driver + * + * @description: + * A handle to a given FreeType font driver object. A font driver is a + * module capable of creating faces from font files. + */ + typedef struct FT_DriverRec_* FT_Driver; + + + /************************************************************************** + * + * @type: + * FT_Renderer + * + * @description: + * A handle to a given FreeType renderer. A renderer is a module in + * charge of converting a glyph's outline image to a bitmap. It supports + * a single glyph image format, and one or more target surface depths. + */ + typedef struct FT_RendererRec_* FT_Renderer; + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @type: + * FT_Face + * + * @description: + * A handle to a typographic face object. A face object models a given + * typeface, in a given style. + * + * @note: + * A face object also owns a single @FT_GlyphSlot object, as well as one + * or more @FT_Size objects. + * + * Use @FT_New_Face or @FT_Open_Face to create a new face object from a + * given filepath or a custom input stream. + * + * Use @FT_Done_Face to destroy it (along with its slot and sizes). + * + * An `FT_Face` object can only be safely used from one thread at a time. + * Similarly, creation and destruction of `FT_Face` with the same + * @FT_Library object can only be done from one thread at a time. On the + * other hand, functions like @FT_Load_Glyph and its siblings are + * thread-safe and do not need the lock to be held as long as the same + * `FT_Face` object is not used from multiple threads at the same time. + * + * @also: + * See @FT_FaceRec for the publicly accessible fields of a given face + * object. + */ + typedef struct FT_FaceRec_* FT_Face; + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @type: + * FT_Size + * + * @description: + * A handle to an object that models a face scaled to a given character + * size. + * + * @note: + * An @FT_Face has one _active_ `FT_Size` object that is used by + * functions like @FT_Load_Glyph to determine the scaling transformation + * that in turn is used to load and hint glyphs and metrics. + * + * A newly created `FT_Size` object contains only meaningless zero values. + * You must use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, @FT_Request_Size + * or even @FT_Select_Size to change the content (i.e., the scaling + * values) of the active `FT_Size`. Otherwise, the scaling and hinting + * will not be performed. + * + * You can use @FT_New_Size to create additional size objects for a given + * @FT_Face, but they won't be used by other functions until you activate + * it through @FT_Activate_Size. Only one size can be activated at any + * given time per face. + * + * @also: + * See @FT_SizeRec for the publicly accessible fields of a given size + * object. + */ + typedef struct FT_SizeRec_* FT_Size; + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @type: + * FT_GlyphSlot + * + * @description: + * A handle to a given 'glyph slot'. A slot is a container that can hold + * any of the glyphs contained in its parent face. + * + * In other words, each time you call @FT_Load_Glyph or @FT_Load_Char, + * the slot's content is erased by the new glyph data, i.e., the glyph's + * metrics, its image (bitmap or outline), and other control information. + * + * @also: + * See @FT_GlyphSlotRec for the publicly accessible glyph fields. + */ + typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; + + + /************************************************************************** + * + * @section: + * character_mapping + * + */ + + /************************************************************************** + * + * @type: + * FT_CharMap + * + * @description: + * A handle to a character map (usually abbreviated to 'charmap'). A + * charmap is used to translate character codes in a given encoding into + * glyph indexes for its parent's face. Some font formats may provide + * several charmaps per font. + * + * Each face object owns zero or more charmaps, but only one of them can + * be 'active', providing the data used by @FT_Get_Char_Index or + * @FT_Load_Char. + * + * The list of available charmaps in a face is available through the + * `face->num_charmaps` and `face->charmaps` fields of @FT_FaceRec. + * + * The currently active charmap is available as `face->charmap`. You + * should call @FT_Set_Charmap to change it. + * + * @note: + * When a new face is created (either through @FT_New_Face or + * @FT_Open_Face), the library looks for a Unicode charmap within the + * list and automatically activates it. If there is no Unicode charmap, + * FreeType doesn't set an 'active' charmap. + * + * @also: + * See @FT_CharMapRec for the publicly accessible fields of a given + * character map. + */ + typedef struct FT_CharMapRec_* FT_CharMap; + + + /************************************************************************** + * + * @macro: + * FT_ENC_TAG + * + * @description: + * This macro converts four-letter tags into an unsigned long. It is + * used to define 'encoding' identifiers (see @FT_Encoding). + * + * @note: + * Since many 16-bit compilers don't like 32-bit enumerations, you should + * redefine this macro in case of problems to something like this: + * + * ``` + * #define FT_ENC_TAG( value, a, b, c, d ) value + * ``` + * + * to get a simple enumeration without assigning special numbers. + */ + +#ifndef FT_ENC_TAG + +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( FT_STATIC_BYTE_CAST( FT_UInt32, a ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, b ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, c ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_UInt32, d ) ) + +#endif /* FT_ENC_TAG */ + + + /************************************************************************** + * + * @enum: + * FT_Encoding + * + * @description: + * An enumeration to specify character sets supported by charmaps. Used + * in the @FT_Select_Charmap API function. + * + * @note: + * Despite the name, this enumeration lists specific character + * repertoires (i.e., charsets), and not text encoding methods (e.g., + * UTF-8, UTF-16, etc.). + * + * Other encodings might be defined in the future. + * + * @values: + * FT_ENCODING_NONE :: + * The encoding value~0 is reserved for all formats except BDF, PCF, + * and Windows FNT; see below for more information. + * + * FT_ENCODING_UNICODE :: + * The Unicode character set. This value covers all versions of the + * Unicode repertoire, including ASCII and Latin-1. Most fonts include + * a Unicode charmap, but not all of them. + * + * For example, if you want to access Unicode value U+1F028 (and the + * font contains it), use value 0x1F028 as the input value for + * @FT_Get_Char_Index. + * + * FT_ENCODING_MS_SYMBOL :: + * Microsoft Symbol encoding, used to encode mathematical symbols and + * wingdings. For more information, see + * 'https://www.microsoft.com/typography/otspec/recom.htm#non-standard-symbol-fonts', + * 'http://www.kostis.net/charsets/symbol.htm', and + * 'http://www.kostis.net/charsets/wingding.htm'. + * + * This encoding uses character codes from the PUA (Private Unicode + * Area) in the range U+F020-U+F0FF. + * + * FT_ENCODING_SJIS :: + * Shift JIS encoding for Japanese. More info at + * 'https://en.wikipedia.org/wiki/Shift_JIS'. See note on multi-byte + * encodings below. + * + * FT_ENCODING_PRC :: + * Corresponds to encoding systems mainly for Simplified Chinese as + * used in People's Republic of China (PRC). The encoding layout is + * based on GB~2312 and its supersets GBK and GB~18030. + * + * FT_ENCODING_BIG5 :: + * Corresponds to an encoding system for Traditional Chinese as used in + * Taiwan and Hong Kong. + * + * FT_ENCODING_WANSUNG :: + * Corresponds to the Korean encoding system known as Extended Wansung + * (MS Windows code page 949). For more information see + * 'https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit949.txt'. + * + * FT_ENCODING_JOHAB :: + * The Korean standard character set (KS~C 5601-1992), which + * corresponds to MS Windows code page 1361. This character set + * includes all possible Hangul character combinations. + * + * FT_ENCODING_ADOBE_LATIN_1 :: + * Corresponds to a Latin-1 encoding as defined in a Type~1 PostScript + * font. It is limited to 256 character codes. + * + * FT_ENCODING_ADOBE_STANDARD :: + * Adobe Standard encoding, as found in Type~1, CFF, and OpenType/CFF + * fonts. It is limited to 256 character codes. + * + * FT_ENCODING_ADOBE_EXPERT :: + * Adobe Expert encoding, as found in Type~1, CFF, and OpenType/CFF + * fonts. It is limited to 256 character codes. + * + * FT_ENCODING_ADOBE_CUSTOM :: + * Corresponds to a custom encoding, as found in Type~1, CFF, and + * OpenType/CFF fonts. It is limited to 256 character codes. + * + * FT_ENCODING_APPLE_ROMAN :: + * Apple roman encoding. Many TrueType and OpenType fonts contain a + * charmap for this 8-bit encoding, since older versions of Mac OS are + * able to use it. + * + * FT_ENCODING_OLD_LATIN_2 :: + * This value is deprecated and was neither used nor reported by + * FreeType. Don't use or test for it. + * + * FT_ENCODING_MS_SJIS :: + * Same as FT_ENCODING_SJIS. Deprecated. + * + * FT_ENCODING_MS_GB2312 :: + * Same as FT_ENCODING_PRC. Deprecated. + * + * FT_ENCODING_MS_BIG5 :: + * Same as FT_ENCODING_BIG5. Deprecated. + * + * FT_ENCODING_MS_WANSUNG :: + * Same as FT_ENCODING_WANSUNG. Deprecated. + * + * FT_ENCODING_MS_JOHAB :: + * Same as FT_ENCODING_JOHAB. Deprecated. + * + * @note: + * When loading a font, FreeType makes a Unicode charmap active if + * possible (either if the font provides such a charmap, or if FreeType + * can synthesize one from PostScript glyph name dictionaries; in either + * case, the charmap is tagged with `FT_ENCODING_UNICODE`). If such a + * charmap is synthesized, it is placed at the first position of the + * charmap array. + * + * All other encodings are considered legacy and tagged only if + * explicitly defined in the font file. Otherwise, `FT_ENCODING_NONE` is + * used. + * + * `FT_ENCODING_NONE` is set by the BDF and PCF drivers if the charmap is + * neither Unicode nor ISO-8859-1 (otherwise it is set to + * `FT_ENCODING_UNICODE`). Use @FT_Get_BDF_Charset_ID to find out which + * encoding is really present. If, for example, the `cs_registry` field + * is 'KOI8' and the `cs_encoding` field is 'R', the font is encoded in + * KOI8-R. + * + * `FT_ENCODING_NONE` is always set (with a single exception) by the + * winfonts driver. Use @FT_Get_WinFNT_Header and examine the `charset` + * field of the @FT_WinFNT_HeaderRec structure to find out which encoding + * is really present. For example, @FT_WinFNT_ID_CP1251 (204) means + * Windows code page 1251 (for Russian). + * + * `FT_ENCODING_NONE` is set if `platform_id` is @TT_PLATFORM_MACINTOSH + * and `encoding_id` is not `TT_MAC_ID_ROMAN` (otherwise it is set to + * `FT_ENCODING_APPLE_ROMAN`). + * + * If `platform_id` is @TT_PLATFORM_MACINTOSH, use the function + * @FT_Get_CMap_Language_ID to query the Mac language ID that may be + * needed to be able to distinguish Apple encoding variants. See + * + * https://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt + * + * to get an idea how to do that. Basically, if the language ID is~0, + * don't use it, otherwise subtract 1 from the language ID. Then examine + * `encoding_id`. If, for example, `encoding_id` is `TT_MAC_ID_ROMAN` + * and the language ID (minus~1) is `TT_MAC_LANGID_GREEK`, it is the + * Greek encoding, not Roman. `TT_MAC_ID_ARABIC` with + * `TT_MAC_LANGID_FARSI` means the Farsi variant of the Arabic encoding. + */ + typedef enum FT_Encoding_ + { + FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ), + + FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ), + FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ), + + FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ), + FT_ENC_TAG( FT_ENCODING_PRC, 'g', 'b', ' ', ' ' ), + FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ), + FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ), + FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ), + + /* for backward compatibility */ + FT_ENCODING_GB2312 = FT_ENCODING_PRC, + FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, + FT_ENCODING_MS_GB2312 = FT_ENCODING_PRC, + FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, + FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, + FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, + + FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ), + + FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ), + + FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' ) + + } FT_Encoding; + + + /* these constants are deprecated; use the corresponding `FT_Encoding` */ + /* values instead */ +#define ft_encoding_none FT_ENCODING_NONE +#define ft_encoding_unicode FT_ENCODING_UNICODE +#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL +#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1 +#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2 +#define ft_encoding_sjis FT_ENCODING_SJIS +#define ft_encoding_gb2312 FT_ENCODING_PRC +#define ft_encoding_big5 FT_ENCODING_BIG5 +#define ft_encoding_wansung FT_ENCODING_WANSUNG +#define ft_encoding_johab FT_ENCODING_JOHAB + +#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD +#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT +#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM +#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN + + + /************************************************************************** + * + * @struct: + * FT_CharMapRec + * + * @description: + * The base charmap structure. + * + * @fields: + * face :: + * A handle to the parent face object. + * + * encoding :: + * An @FT_Encoding tag identifying the charmap. Use this with + * @FT_Select_Charmap. + * + * platform_id :: + * An ID number describing the platform for the following encoding ID. + * This comes directly from the TrueType specification and gets + * emulated for other formats. + * + * encoding_id :: + * A platform-specific encoding number. This also comes from the + * TrueType specification and gets emulated similarly. + */ + typedef struct FT_CharMapRec_ + { + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; + + } FT_CharMapRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S E O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @type: + * FT_Face_Internal + * + * @description: + * An opaque handle to an `FT_Face_InternalRec` structure that models the + * private data of a given @FT_Face object. + * + * This structure might change between releases of FreeType~2 and is not + * generally available to client applications. + */ + typedef struct FT_Face_InternalRec_* FT_Face_Internal; + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @struct: + * FT_FaceRec + * + * @description: + * FreeType root face class structure. A face object models a typeface + * in a font file. + * + * @fields: + * num_faces :: + * The number of faces in the font file. Some font formats can have + * multiple faces in a single font file. + * + * face_index :: + * This field holds two different values. Bits 0-15 are the index of + * the face in the font file (starting with value~0). They are set + * to~0 if there is only one face in the font file. + * + * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation + * fonts only, holding the named instance index for the current face + * index (starting with value~1; value~0 indicates font access without + * a named instance). For non-variation fonts, bits 16-30 are ignored. + * If we have the third named instance of face~4, say, `face_index` is + * set to 0x00030004. + * + * Bit 31 is always zero (that is, `face_index` is always a positive + * value). + * + * [Since 2.9] Changing the design coordinates with + * @FT_Set_Var_Design_Coordinates or @FT_Set_Var_Blend_Coordinates does + * not influence the named instance index value (only + * @FT_Set_Named_Instance does that). + * + * face_flags :: + * A set of bit flags that give important information about the face; + * see @FT_FACE_FLAG_XXX for the details. + * + * style_flags :: + * The lower 16~bits contain a set of bit flags indicating the style of + * the face; see @FT_STYLE_FLAG_XXX for the details. + * + * [Since 2.6.1] Bits 16-30 hold the number of named instances + * available for the current face if we have a GX or OpenType variation + * (sub)font. Bit 31 is always zero (that is, `style_flags` is always + * a positive value). Note that a variation font has always at least + * one named instance, namely the default instance. + * + * num_glyphs :: + * The number of glyphs in the face. If the face is scalable and has + * sbits (see `num_fixed_sizes`), it is set to the number of outline + * glyphs. + * + * For CID-keyed fonts (not in an SFNT wrapper) this value gives the + * highest CID used in the font. + * + * family_name :: + * The face's family name. This is an ASCII string, usually in + * English, that describes the typeface's family (like 'Times New + * Roman', 'Bodoni', 'Garamond', etc). This is a least common + * denominator used to list fonts. Some formats (TrueType & OpenType) + * provide localized and Unicode versions of this string. Applications + * should use the format-specific interface to access them. Can be + * `NULL` (e.g., in fonts embedded in a PDF file). + * + * In case the font doesn't provide a specific family name entry, + * FreeType tries to synthesize one, deriving it from other name + * entries. + * + * style_name :: + * The face's style name. This is an ASCII string, usually in English, + * that describes the typeface's style (like 'Italic', 'Bold', + * 'Condensed', etc). Not all font formats provide a style name, so + * this field is optional, and can be set to `NULL`. As for + * `family_name`, some formats provide localized and Unicode versions + * of this string. Applications should use the format-specific + * interface to access them. + * + * num_fixed_sizes :: + * The number of bitmap strikes in the face. Even if the face is + * scalable, there might still be bitmap strikes, which are called + * 'sbits' in that case. + * + * available_sizes :: + * An array of @FT_Bitmap_Size for all bitmap strikes in the face. It + * is set to `NULL` if there is no bitmap strike. + * + * Note that FreeType tries to sanitize the strike data since they are + * sometimes sloppy or incorrect, but this can easily fail. + * + * num_charmaps :: + * The number of charmaps in the face. + * + * charmaps :: + * An array of the charmaps of the face. + * + * generic :: + * A field reserved for client uses. See the @FT_Generic type + * description. + * + * bbox :: + * The font bounding box. Coordinates are expressed in font units (see + * `units_per_EM`). The box is large enough to contain any glyph from + * the font. Thus, `bbox.yMax` can be seen as the 'maximum ascender', + * and `bbox.yMin` as the 'minimum descender'. Only relevant for + * scalable formats. + * + * Note that the bounding box might be off by (at least) one pixel for + * hinted fonts. See @FT_Size_Metrics for further discussion. + * + * Note that the bounding box does not vary in OpenType variation fonts + * and should only be used in relation to the default instance. + * + * units_per_EM :: + * The number of font units per EM square for this face. This is + * typically 2048 for TrueType fonts, and 1000 for Type~1 fonts. Only + * relevant for scalable formats. + * + * ascender :: + * The typographic ascender of the face, expressed in font units. For + * font formats not having this information, it is set to `bbox.yMax`. + * Only relevant for scalable formats. + * + * descender :: + * The typographic descender of the face, expressed in font units. For + * font formats not having this information, it is set to `bbox.yMin`. + * Note that this field is negative for values below the baseline. + * Only relevant for scalable formats. + * + * height :: + * This value is the vertical distance between two consecutive + * baselines, expressed in font units. It is always positive. Only + * relevant for scalable formats. + * + * If you want the global glyph height, use `ascender - descender`. + * + * max_advance_width :: + * The maximum advance width, in font units, for all glyphs in this + * face. This can be used to make word wrapping computations faster. + * Only relevant for scalable formats. + * + * max_advance_height :: + * The maximum advance height, in font units, for all glyphs in this + * face. This is only relevant for vertical layouts, and is set to + * `height` for fonts that do not provide vertical metrics. Only + * relevant for scalable formats. + * + * underline_position :: + * The position, in font units, of the underline line for this face. + * It is the center of the underlining stem. Only relevant for + * scalable formats. + * + * underline_thickness :: + * The thickness, in font units, of the underline for this face. Only + * relevant for scalable formats. + * + * glyph :: + * The face's associated glyph slot(s). + * + * size :: + * The current active size for this face. + * + * charmap :: + * The current active charmap for this face. + * + * @note: + * Fields may be changed after a call to @FT_Attach_File or + * @FT_Attach_Stream. + * + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `ascender`, `descender`, `height`, + * `underline_position`, and `underline_thickness`. + * + * Especially for TrueType fonts see also the documentation for + * @FT_Size_Metrics. + */ + typedef struct FT_FaceRec_ + { + FT_Long num_faces; + FT_Long face_index; + + FT_Long face_flags; + FT_Long style_flags; + + FT_Long num_glyphs; + + FT_String* family_name; + FT_String* style_name; + + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + + FT_Int num_charmaps; + FT_CharMap* charmaps; + + FT_Generic generic; + + /* The following member variables (down to `underline_thickness`) */ + /* are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ + /* for bitmap fonts. */ + FT_BBox bbox; + + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + + FT_Short max_advance_width; + FT_Short max_advance_height; + + FT_Short underline_position; + FT_Short underline_thickness; + + FT_GlyphSlot glyph; + FT_Size size; + FT_CharMap charmap; + + /* private fields, internal to FreeType */ + + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + + FT_ListRec sizes_list; + + FT_Generic autohint; /* face-specific auto-hinter data */ + void* extensions; /* unused */ + + FT_Face_Internal internal; + + } FT_FaceRec; + + + /************************************************************************** + * + * @enum: + * FT_FACE_FLAG_XXX + * + * @description: + * A list of bit flags used in the `face_flags` field of the @FT_FaceRec + * structure. They inform client applications of properties of the + * corresponding face. + * + * @values: + * FT_FACE_FLAG_SCALABLE :: + * The face contains outline glyphs. Note that a face can contain + * bitmap strikes also, i.e., a face can have both this flag and + * @FT_FACE_FLAG_FIXED_SIZES set. + * + * FT_FACE_FLAG_FIXED_SIZES :: + * The face contains bitmap strikes. See also the `num_fixed_sizes` + * and `available_sizes` fields of @FT_FaceRec. + * + * FT_FACE_FLAG_FIXED_WIDTH :: + * The face contains fixed-width characters (like Courier, Lucida, + * MonoType, etc.). + * + * FT_FACE_FLAG_SFNT :: + * The face uses the SFNT storage scheme. For now, this means TrueType + * and OpenType. + * + * FT_FACE_FLAG_HORIZONTAL :: + * The face contains horizontal glyph metrics. This should be set for + * all common formats. + * + * FT_FACE_FLAG_VERTICAL :: + * The face contains vertical glyph metrics. This is only available in + * some formats, not all of them. + * + * FT_FACE_FLAG_KERNING :: + * The face contains kerning information. If set, the kerning distance + * can be retrieved using the function @FT_Get_Kerning. Otherwise the + * function always returns the vector (0,0). Note that FreeType + * doesn't handle kerning data from the SFNT 'GPOS' table (as present + * in many OpenType fonts). + * + * FT_FACE_FLAG_FAST_GLYPHS :: + * THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. + * + * FT_FACE_FLAG_MULTIPLE_MASTERS :: + * The face contains multiple masters and is capable of interpolating + * between them. Supported formats are Adobe MM, TrueType GX, and + * OpenType variation fonts. + * + * See section @multiple_masters for API details. + * + * FT_FACE_FLAG_GLYPH_NAMES :: + * The face contains glyph names, which can be retrieved using + * @FT_Get_Glyph_Name. Note that some TrueType fonts contain broken + * glyph name tables. Use the function @FT_Has_PS_Glyph_Names when + * needed. + * + * FT_FACE_FLAG_EXTERNAL_STREAM :: + * Used internally by FreeType to indicate that a face's stream was + * provided by the client application and should not be destroyed when + * @FT_Done_Face is called. Don't read or test this flag. + * + * FT_FACE_FLAG_HINTER :: + * The font driver has a hinting machine of its own. For example, with + * TrueType fonts, it makes sense to use data from the SFNT 'gasp' + * table only if the native TrueType hinting engine (with the bytecode + * interpreter) is available and active. + * + * FT_FACE_FLAG_CID_KEYED :: + * The face is CID-keyed. In that case, the face is not accessed by + * glyph indices but by CID values. For subsetted CID-keyed fonts this + * has the consequence that not all index values are a valid argument + * to @FT_Load_Glyph. Only the CID values for which corresponding + * glyphs in the subsetted font exist make `FT_Load_Glyph` return + * successfully; in all other cases you get an + * `FT_Err_Invalid_Argument` error. + * + * Note that CID-keyed fonts that are in an SFNT wrapper (that is, all + * OpenType/CFF fonts) don't have this flag set since the glyphs are + * accessed in the normal way (using contiguous indices); the + * 'CID-ness' isn't visible to the application. + * + * FT_FACE_FLAG_TRICKY :: + * The face is 'tricky', that is, it always needs the font format's + * native hinting engine to get a reasonable result. A typical example + * is the old Chinese font `mingli.ttf` (but not `mingliu.ttc`) that + * uses TrueType bytecode instructions to move and scale all of its + * subglyphs. + * + * It is not possible to auto-hint such fonts using + * @FT_LOAD_FORCE_AUTOHINT; it will also ignore @FT_LOAD_NO_HINTING. + * You have to set both @FT_LOAD_NO_HINTING and @FT_LOAD_NO_AUTOHINT to + * really disable hinting; however, you probably never want this except + * for demonstration purposes. + * + * Currently, there are about a dozen TrueType fonts in the list of + * tricky fonts; they are hard-coded in file `ttobjs.c`. + * + * FT_FACE_FLAG_COLOR :: + * [Since 2.5.1] The face has color glyph tables. See @FT_LOAD_COLOR + * for more information. + * + * FT_FACE_FLAG_VARIATION :: + * [Since 2.9] Set if the current face (or named instance) has been + * altered with @FT_Set_MM_Design_Coordinates, + * @FT_Set_Var_Design_Coordinates, @FT_Set_Var_Blend_Coordinates, or + * @FT_Set_MM_WeightVector to select a non-default instance. + * + * FT_FACE_FLAG_SVG :: + * [Since 2.12] The face has an 'SVG~' OpenType table. + * + * FT_FACE_FLAG_SBIX :: + * [Since 2.12] The face has an 'sbix' OpenType table *and* outlines. + * For such fonts, @FT_FACE_FLAG_SCALABLE is not set by default to + * retain backward compatibility. + * + * FT_FACE_FLAG_SBIX_OVERLAY :: + * [Since 2.12] The face has an 'sbix' OpenType table where outlines + * should be drawn on top of bitmap strikes. + * + */ +#define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) +#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) +#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) +#define FT_FACE_FLAG_SFNT ( 1L << 3 ) +#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) +#define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) +#define FT_FACE_FLAG_KERNING ( 1L << 6 ) +#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) +#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) +#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) +#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) +#define FT_FACE_FLAG_HINTER ( 1L << 11 ) +#define FT_FACE_FLAG_CID_KEYED ( 1L << 12 ) +#define FT_FACE_FLAG_TRICKY ( 1L << 13 ) +#define FT_FACE_FLAG_COLOR ( 1L << 14 ) +#define FT_FACE_FLAG_VARIATION ( 1L << 15 ) +#define FT_FACE_FLAG_SVG ( 1L << 16 ) +#define FT_FACE_FLAG_SBIX ( 1L << 17 ) +#define FT_FACE_FLAG_SBIX_OVERLAY ( 1L << 18 ) + + + /************************************************************************** + * + * @section: + * font_testing_macros + * + */ + + /************************************************************************** + * + * @macro: + * FT_HAS_HORIZONTAL + * + * @description: + * A macro that returns true whenever a face object contains horizontal + * metrics (this is true for all font formats though). + * + * @also: + * @FT_HAS_VERTICAL can be used to check for vertical metrics. + * + */ +#define FT_HAS_HORIZONTAL( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_HORIZONTAL ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_VERTICAL + * + * @description: + * A macro that returns true whenever a face object contains real + * vertical metrics (and not only synthesized ones). + * + */ +#define FT_HAS_VERTICAL( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_VERTICAL ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_KERNING + * + * @description: + * A macro that returns true whenever a face object contains kerning data + * that can be accessed with @FT_Get_Kerning. + * + */ +#define FT_HAS_KERNING( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_KERNING ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_SCALABLE + * + * @description: + * A macro that returns true whenever a face object contains a scalable + * font face (true for TrueType, Type~1, Type~42, CID, OpenType/CFF, and + * PFR font formats). + * + */ +#define FT_IS_SCALABLE( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SCALABLE ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_SFNT + * + * @description: + * A macro that returns true whenever a face object contains a font whose + * format is based on the SFNT storage scheme. This usually means: + * TrueType fonts, OpenType fonts, as well as SFNT-based embedded bitmap + * fonts. + * + * If this macro is true, all functions defined in @FT_SFNT_NAMES_H and + * @FT_TRUETYPE_TABLES_H are available. + * + */ +#define FT_IS_SFNT( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SFNT ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_FIXED_WIDTH + * + * @description: + * A macro that returns true whenever a face object contains a font face + * that contains fixed-width (or 'monospace', 'fixed-pitch', etc.) + * glyphs. + * + */ +#define FT_IS_FIXED_WIDTH( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_FIXED_SIZES + * + * @description: + * A macro that returns true whenever a face object contains some + * embedded bitmaps. See the `available_sizes` field of the @FT_FaceRec + * structure. + * + */ +#define FT_HAS_FIXED_SIZES( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @macro: + * FT_HAS_FAST_GLYPHS + * + * @description: + * Deprecated. + * + */ +#define FT_HAS_FAST_GLYPHS( face ) 0 + + + /************************************************************************** + * + * @section: + * font_testing_macros + * + */ + + /************************************************************************** + * + * @macro: + * FT_HAS_GLYPH_NAMES + * + * @description: + * A macro that returns true whenever a face object contains some glyph + * names that can be accessed through @FT_Get_Glyph_Name. + * + */ +#define FT_HAS_GLYPH_NAMES( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_MULTIPLE_MASTERS + * + * @description: + * A macro that returns true whenever a face object contains some + * multiple masters. The functions provided by @FT_MULTIPLE_MASTERS_H + * are then available to choose the exact design you want. + * + */ +#define FT_HAS_MULTIPLE_MASTERS( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_NAMED_INSTANCE + * + * @description: + * A macro that returns true whenever a face object is a named instance + * of a GX or OpenType variation font. + * + * [Since 2.9] Changing the design coordinates with + * @FT_Set_Var_Design_Coordinates or @FT_Set_Var_Blend_Coordinates does + * not influence the return value of this macro (only + * @FT_Set_Named_Instance does that). + * + * @since: + * 2.7 + * + */ +#define FT_IS_NAMED_INSTANCE( face ) \ + ( !!( (face)->face_index & 0x7FFF0000L ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_VARIATION + * + * @description: + * A macro that returns true whenever a face object has been altered by + * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates, + * @FT_Set_Var_Blend_Coordinates, or @FT_Set_MM_WeightVector. + * + * @since: + * 2.9 + * + */ +#define FT_IS_VARIATION( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_VARIATION ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_CID_KEYED + * + * @description: + * A macro that returns true whenever a face object contains a CID-keyed + * font. See the discussion of @FT_FACE_FLAG_CID_KEYED for more details. + * + * If this macro is true, all functions defined in @FT_CID_H are + * available. + * + */ +#define FT_IS_CID_KEYED( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_CID_KEYED ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_TRICKY + * + * @description: + * A macro that returns true whenever a face represents a 'tricky' font. + * See the discussion of @FT_FACE_FLAG_TRICKY for more details. + * + */ +#define FT_IS_TRICKY( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_TRICKY ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_COLOR + * + * @description: + * A macro that returns true whenever a face object contains tables for + * color glyphs. + * + * @since: + * 2.5.1 + * + */ +#define FT_HAS_COLOR( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_COLOR ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SVG + * + * @description: + * A macro that returns true whenever a face object contains an 'SVG~' + * OpenType table. + * + * @since: + * 2.12 + */ +#define FT_HAS_SVG( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SVG ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table *and* outline glyphs. + * + * Currently, FreeType only supports bitmap glyphs in PNG format for this + * table (i.e., JPEG and TIFF formats are unsupported, as are + * Apple-specific formats not part of the OpenType specification). + * + * @note: + * For backward compatibility, a font with an 'sbix' table is treated as + * a bitmap-only face. Using @FT_Open_Face with + * @FT_PARAM_TAG_IGNORE_SBIX, an application can switch off 'sbix' + * handling so that the face is treated as an ordinary outline font with + * scalable outlines. + * + * Here is some pseudo code that roughly illustrates how to implement + * 'sbix' handling according to the OpenType specification. + * + * ``` + * if ( FT_HAS_SBIX( face ) ) + * { + * // open font as a scalable one without sbix handling + * FT_Face face2; + * FT_Parameter param = { FT_PARAM_TAG_IGNORE_SBIX, NULL }; + * FT_Open_Args args = { FT_OPEN_PARAMS | ..., + * ..., + * 1, ¶m }; + * + * + * FT_Open_Face( library, &args, 0, &face2 ); + * + * available_size` as necessary into + * `preferred_sizes`[*]> + * + * for ( i = 0; i < face->num_fixed_sizes; i++ ) + * { + * size = preferred_sizes[i].size; + * + * error = FT_Set_Pixel_Sizes( face, size, size ); + * + * + * // check whether we have a glyph in a bitmap strike + * error = FT_Load_Glyph( face, + * glyph_index, + * FT_LOAD_SBITS_ONLY | + * FT_LOAD_BITMAP_METRICS_ONLY ); + * if ( error == FT_Err_Invalid_Argument ) + * continue; + * else if ( error ) + * + * else + * break; + * } + * + * if ( i != face->num_fixed_sizes ) + * + * + * if ( i == face->num_fixed_sizes || + * FT_HAS_SBIX_OVERLAY( face ) ) + * + * } + * ``` + * + * [*] Assuming a target value of 400dpi and available strike sizes 100, + * 200, 300, and 400dpi, a possible order might be [400, 200, 300, 100]: + * scaling 200dpi to 400dpi usually gives better results than scaling + * 300dpi to 400dpi; it is also much faster. However, scaling 100dpi to + * 400dpi can yield a too pixelated result, thus the preference might be + * 300dpi over 100dpi. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX_OVERLAY + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table with bit~1 in its `flags` field set, instructing the + * application to overlay the bitmap strike with the corresponding + * outline glyph. See @FT_HAS_SBIX for pseudo code how to use it. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX_OVERLAY( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX_OVERLAY ) ) + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @enum: + * FT_STYLE_FLAG_XXX + * + * @description: + * A list of bit flags to indicate the style of a given face. These are + * used in the `style_flags` field of @FT_FaceRec. + * + * @values: + * FT_STYLE_FLAG_ITALIC :: + * The face style is italic or oblique. + * + * FT_STYLE_FLAG_BOLD :: + * The face is bold. + * + * @note: + * The style information as provided by FreeType is very basic. More + * details are beyond the scope and should be done on a higher level (for + * example, by analyzing various fields of the 'OS/2' table in SFNT based + * fonts). + */ +#define FT_STYLE_FLAG_ITALIC ( 1 << 0 ) +#define FT_STYLE_FLAG_BOLD ( 1 << 1 ) + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @type: + * FT_Size_Internal + * + * @description: + * An opaque handle to an `FT_Size_InternalRec` structure, used to model + * private data of a given @FT_Size object. + */ + typedef struct FT_Size_InternalRec_* FT_Size_Internal; + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @struct: + * FT_Size_Metrics + * + * @description: + * The size metrics structure gives the metrics of a size object. + * + * @fields: + * x_ppem :: + * The width of the scaled EM square in pixels, hence the term 'ppem' + * (pixels per EM). It is also referred to as 'nominal width'. + * + * y_ppem :: + * The height of the scaled EM square in pixels, hence the term 'ppem' + * (pixels per EM). It is also referred to as 'nominal height'. + * + * x_scale :: + * A 16.16 fractional scaling value to convert horizontal metrics from + * font units to 26.6 fractional pixels. Only relevant for scalable + * font formats. + * + * y_scale :: + * A 16.16 fractional scaling value to convert vertical metrics from + * font units to 26.6 fractional pixels. Only relevant for scalable + * font formats. + * + * ascender :: + * The ascender in 26.6 fractional pixels, rounded up to an integer + * value. See @FT_FaceRec for the details. + * + * descender :: + * The descender in 26.6 fractional pixels, rounded down to an integer + * value. See @FT_FaceRec for the details. + * + * height :: + * The height in 26.6 fractional pixels, rounded to an integer value. + * See @FT_FaceRec for the details. + * + * max_advance :: + * The maximum advance width in 26.6 fractional pixels, rounded to an + * integer value. See @FT_FaceRec for the details. + * + * @note: + * The scaling values, if relevant, are determined first during a size + * changing operation. The remaining fields are then set by the driver. + * For scalable formats, they are usually set to scaled values of the + * corresponding fields in @FT_FaceRec. Some values like ascender or + * descender are rounded for historical reasons; more precise values (for + * outline fonts) can be derived by scaling the corresponding @FT_FaceRec + * values manually, with code similar to the following. + * + * ``` + * scaled_ascender = FT_MulFix( face->ascender, + * size_metrics->y_scale ); + * ``` + * + * Note that due to glyph hinting and the selected rendering mode these + * values are usually not exact; consequently, they must be treated as + * unreliable with an error margin of at least one pixel! + * + * Indeed, the only way to get the exact metrics is to render _all_ + * glyphs. As this would be a definite performance hit, it is up to + * client applications to perform such computations. + * + * The `FT_Size_Metrics` structure is valid for bitmap fonts also. + * + * + * **TrueType fonts with native bytecode hinting** + * + * All applications that handle TrueType fonts with native hinting must + * be aware that TTFs expect different rounding of vertical font + * dimensions. The application has to cater for this, especially if it + * wants to rely on a TTF's vertical data (for example, to properly align + * box characters vertically). + * + * Only the application knows _in advance_ that it is going to use native + * hinting for TTFs! FreeType, on the other hand, selects the hinting + * mode not at the time of creating an @FT_Size object but much later, + * namely while calling @FT_Load_Glyph. + * + * Here is some pseudo code that illustrates a possible solution. + * + * ``` + * font_format = FT_Get_Font_Format( face ); + * + * if ( !strcmp( font_format, "TrueType" ) && + * do_native_bytecode_hinting ) + * { + * ascender = ROUND( FT_MulFix( face->ascender, + * size_metrics->y_scale ) ); + * descender = ROUND( FT_MulFix( face->descender, + * size_metrics->y_scale ) ); + * } + * else + * { + * ascender = size_metrics->ascender; + * descender = size_metrics->descender; + * } + * + * height = size_metrics->height; + * max_advance = size_metrics->max_advance; + * ``` + */ + typedef struct FT_Size_Metrics_ + { + FT_UShort x_ppem; /* horizontal pixels per EM */ + FT_UShort y_ppem; /* vertical pixels per EM */ + + FT_Fixed x_scale; /* scaling values used to convert font */ + FT_Fixed y_scale; /* units to 26.6 fractional pixels */ + + FT_Pos ascender; /* ascender in 26.6 frac. pixels */ + FT_Pos descender; /* descender in 26.6 frac. pixels */ + FT_Pos height; /* text height in 26.6 frac. pixels */ + FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ + + } FT_Size_Metrics; + + + /************************************************************************** + * + * @struct: + * FT_SizeRec + * + * @description: + * FreeType root size class structure. A size object models a face + * object at a given size. + * + * @fields: + * face :: + * Handle to the parent face object. + * + * generic :: + * A typeless pointer, unused by the FreeType library or any of its + * drivers. It can be used by client applications to link their own + * data to each size object. + * + * metrics :: + * Metrics for this size object. This field is read-only. + */ + typedef struct FT_SizeRec_ + { + FT_Face face; /* parent face object */ + FT_Generic generic; /* generic pointer for client uses */ + FT_Size_Metrics metrics; /* size metrics */ + FT_Size_Internal internal; + + } FT_SizeRec; + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @struct: + * FT_SubGlyph + * + * @description: + * The subglyph structure is an internal object used to describe + * subglyphs (for example, in the case of composites). + * + * @note: + * The subglyph implementation is not part of the high-level API, hence + * the forward structure declaration. + * + * You can however retrieve subglyph information with + * @FT_Get_SubGlyph_Info. + */ + typedef struct FT_SubGlyphRec_* FT_SubGlyph; + + + /************************************************************************** + * + * @type: + * FT_Slot_Internal + * + * @description: + * An opaque handle to an `FT_Slot_InternalRec` structure, used to model + * private data of a given @FT_GlyphSlot object. + */ + typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @struct: + * FT_GlyphSlotRec + * + * @description: + * FreeType root glyph slot class structure. A glyph slot is a container + * where individual glyphs can be loaded, be they in outline or bitmap + * format. + * + * @fields: + * library :: + * A handle to the FreeType library instance this slot belongs to. + * + * face :: + * A handle to the parent face object. + * + * next :: + * In some cases (like some font tools), several glyph slots per face + * object can be a good thing. As this is rare, the glyph slots are + * listed through a direct, single-linked list using its `next` field. + * + * glyph_index :: + * [Since 2.10] The glyph index passed as an argument to @FT_Load_Glyph + * while initializing the glyph slot. + * + * generic :: + * A typeless pointer unused by the FreeType library or any of its + * drivers. It can be used by client applications to link their own + * data to each glyph slot object. + * + * metrics :: + * The metrics of the last loaded glyph in the slot. The returned + * values depend on the last load flags (see the @FT_Load_Glyph API + * function) and can be expressed either in 26.6 fractional pixels or + * font units. + * + * Note that even when the glyph image is transformed, the metrics are + * not. + * + * linearHoriAdvance :: + * The advance width of the unhinted glyph. Its value is expressed in + * 16.16 fractional pixels, unless @FT_LOAD_LINEAR_DESIGN is set when + * loading the glyph. This field can be important to perform correct + * WYSIWYG layout. Only relevant for scalable glyphs. + * + * linearVertAdvance :: + * The advance height of the unhinted glyph. Its value is expressed in + * 16.16 fractional pixels, unless @FT_LOAD_LINEAR_DESIGN is set when + * loading the glyph. This field can be important to perform correct + * WYSIWYG layout. Only relevant for scalable glyphs. + * + * advance :: + * This shorthand is, depending on @FT_LOAD_IGNORE_TRANSFORM, the + * transformed (hinted) advance width for the glyph, in 26.6 fractional + * pixel format. As specified with @FT_LOAD_VERTICAL_LAYOUT, it uses + * either the `horiAdvance` or the `vertAdvance` value of `metrics` + * field. + * + * format :: + * This field indicates the format of the image contained in the glyph + * slot. Typically @FT_GLYPH_FORMAT_BITMAP, @FT_GLYPH_FORMAT_OUTLINE, + * or @FT_GLYPH_FORMAT_COMPOSITE, but other values are possible. + * + * bitmap :: + * This field is used as a bitmap descriptor. Note that the address + * and content of the bitmap buffer can change between calls of + * @FT_Load_Glyph and a few other functions. + * + * bitmap_left :: + * The bitmap's left bearing expressed in integer pixels. + * + * bitmap_top :: + * The bitmap's top bearing expressed in integer pixels. This is the + * distance from the baseline to the top-most glyph scanline, upwards + * y~coordinates being **positive**. + * + * outline :: + * The outline descriptor for the current glyph image if its format is + * @FT_GLYPH_FORMAT_OUTLINE. Once a glyph is loaded, `outline` can be + * transformed, distorted, emboldened, etc. However, it must not be + * freed. + * + * [Since 2.10.1] If @FT_LOAD_NO_SCALE is set, outline coordinates of + * OpenType variation fonts for a selected instance are internally + * handled as 26.6 fractional font units but returned as (rounded) + * integers, as expected. To get unrounded font units, don't use + * @FT_LOAD_NO_SCALE but load the glyph with @FT_LOAD_NO_HINTING and + * scale it, using the font's `units_per_EM` value as the ppem. + * + * num_subglyphs :: + * The number of subglyphs in a composite glyph. This field is only + * valid for the composite glyph format that should normally only be + * loaded with the @FT_LOAD_NO_RECURSE flag. + * + * subglyphs :: + * An array of subglyph descriptors for composite glyphs. There are + * `num_subglyphs` elements in there. Currently internal to FreeType. + * + * control_data :: + * Certain font drivers can also return the control data for a given + * glyph image (e.g. TrueType bytecode, Type~1 charstrings, etc.). + * This field is a pointer to such data; it is currently internal to + * FreeType. + * + * control_len :: + * This is the length in bytes of the control data. Currently internal + * to FreeType. + * + * other :: + * Reserved. + * + * lsb_delta :: + * The difference between hinted and unhinted left side bearing while + * auto-hinting is active. Zero otherwise. + * + * rsb_delta :: + * The difference between hinted and unhinted right side bearing while + * auto-hinting is active. Zero otherwise. + * + * @note: + * If @FT_Load_Glyph is called with default flags (see @FT_LOAD_DEFAULT) + * the glyph image is loaded in the glyph slot in its native format + * (e.g., an outline glyph for TrueType and Type~1 formats). [Since 2.9] + * The prospective bitmap metrics are calculated according to + * @FT_LOAD_TARGET_XXX and other flags even for the outline glyph, even + * if @FT_LOAD_RENDER is not set. + * + * This image can later be converted into a bitmap by calling + * @FT_Render_Glyph. This function searches the current renderer for the + * native image's format, then invokes it. + * + * The renderer is in charge of transforming the native image through the + * slot's face transformation fields, then converting it into a bitmap + * that is returned in `slot->bitmap`. + * + * Note that `slot->bitmap_left` and `slot->bitmap_top` are also used to + * specify the position of the bitmap relative to the current pen + * position (e.g., coordinates (0,0) on the baseline). Of course, + * `slot->format` is also changed to @FT_GLYPH_FORMAT_BITMAP. + * + * Here is a small pseudo code fragment that shows how to use `lsb_delta` + * and `rsb_delta` to do fractional positioning of glyphs: + * + * ``` + * FT_GlyphSlot slot = face->glyph; + * FT_Pos origin_x = 0; + * + * + * for all glyphs do + * + * + * FT_Outline_Translate( slot->outline, origin_x & 63, 0 ); + * + * + * + * + * + * origin_x += slot->advance.x; + * origin_x += slot->lsb_delta - slot->rsb_delta; + * endfor + * ``` + * + * Here is another small pseudo code fragment that shows how to use + * `lsb_delta` and `rsb_delta` to improve integer positioning of glyphs: + * + * ``` + * FT_GlyphSlot slot = face->glyph; + * FT_Pos origin_x = 0; + * FT_Pos prev_rsb_delta = 0; + * + * + * for all glyphs do + * + * + * + * + * if ( prev_rsb_delta - slot->lsb_delta > 32 ) + * origin_x -= 64; + * else if ( prev_rsb_delta - slot->lsb_delta < -31 ) + * origin_x += 64; + * + * prev_rsb_delta = slot->rsb_delta; + * + * + * + * origin_x += slot->advance.x; + * endfor + * ``` + * + * If you use strong auto-hinting, you **must** apply these delta values! + * Otherwise you will experience far too large inter-glyph spacing at + * small rendering sizes in most cases. Note that it doesn't harm to use + * the above code for other hinting modes also, since the delta values + * are zero then. + */ + typedef struct FT_GlyphSlotRec_ + { + FT_Library library; + FT_Face face; + FT_GlyphSlot next; + FT_UInt glyph_index; /* new in 2.10; was reserved previously */ + FT_Generic generic; + + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + + FT_Glyph_Format format; + + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + + FT_Outline outline; + + FT_UInt num_subglyphs; + FT_SubGlyph subglyphs; + + void* control_data; + long control_len; + + FT_Pos lsb_delta; + FT_Pos rsb_delta; + + void* other; + + FT_Slot_Internal internal; + + } FT_GlyphSlotRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* F U N C T I O N S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * library_setup + * + */ + + /************************************************************************** + * + * @function: + * FT_Init_FreeType + * + * @description: + * Initialize a new FreeType library object. The set of modules that are + * registered by this function is determined at build time. + * + * @output: + * alibrary :: + * A handle to a new library object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * In case you want to provide your own memory allocating routines, use + * @FT_New_Library instead, followed by a call to @FT_Add_Default_Modules + * (or a series of calls to @FT_Add_Module) and + * @FT_Set_Default_Properties. + * + * See the documentation of @FT_Library and @FT_Face for multi-threading + * issues. + * + * If you need reference-counting (cf. @FT_Reference_Library), use + * @FT_New_Library and @FT_Done_Library. + * + * If compilation option `FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES` is + * set, this function reads the `FREETYPE_PROPERTIES` environment + * variable to control driver properties. See section @properties for + * more. + */ + FT_EXPORT( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ); + + + /************************************************************************** + * + * @function: + * FT_Done_FreeType + * + * @description: + * Destroy a given FreeType library object and all of its children, + * including resources, drivers, faces, sizes, etc. + * + * @input: + * library :: + * A handle to the target library object. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Done_FreeType( FT_Library library ); + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @enum: + * FT_OPEN_XXX + * + * @description: + * A list of bit field constants used within the `flags` field of the + * @FT_Open_Args structure. + * + * @values: + * FT_OPEN_MEMORY :: + * This is a memory-based stream. + * + * FT_OPEN_STREAM :: + * Copy the stream from the `stream` field. + * + * FT_OPEN_PATHNAME :: + * Create a new input stream from a C~path name. + * + * FT_OPEN_DRIVER :: + * Use the `driver` field. + * + * FT_OPEN_PARAMS :: + * Use the `num_params` and `params` fields. + * + * @note: + * The `FT_OPEN_MEMORY`, `FT_OPEN_STREAM`, and `FT_OPEN_PATHNAME` flags + * are mutually exclusive. + */ +#define FT_OPEN_MEMORY 0x1 +#define FT_OPEN_STREAM 0x2 +#define FT_OPEN_PATHNAME 0x4 +#define FT_OPEN_DRIVER 0x8 +#define FT_OPEN_PARAMS 0x10 + + + /* these constants are deprecated; use the corresponding `FT_OPEN_XXX` */ + /* values instead */ +#define ft_open_memory FT_OPEN_MEMORY +#define ft_open_stream FT_OPEN_STREAM +#define ft_open_pathname FT_OPEN_PATHNAME +#define ft_open_driver FT_OPEN_DRIVER +#define ft_open_params FT_OPEN_PARAMS + + + /************************************************************************** + * + * @struct: + * FT_Parameter + * + * @description: + * A simple structure to pass more or less generic parameters to + * @FT_Open_Face and @FT_Face_Properties. + * + * @fields: + * tag :: + * A four-byte identification tag. + * + * data :: + * A pointer to the parameter data. + * + * @note: + * The ID and function of parameters are driver-specific. See section + * @parameter_tags for more information. + */ + typedef struct FT_Parameter_ + { + FT_ULong tag; + FT_Pointer data; + + } FT_Parameter; + + + /************************************************************************** + * + * @struct: + * FT_Open_Args + * + * @description: + * A structure to indicate how to open a new font file or stream. A + * pointer to such a structure can be used as a parameter for the + * functions @FT_Open_Face and @FT_Attach_Stream. + * + * @fields: + * flags :: + * A set of bit flags indicating how to use the structure. + * + * memory_base :: + * The first byte of the file in memory. + * + * memory_size :: + * The size in bytes of the file in memory. + * + * pathname :: + * A pointer to an 8-bit file pathname, which must be a C~string (i.e., + * no null bytes except at the very end). The pointer is not owned by + * FreeType. + * + * stream :: + * A handle to a source stream object. + * + * driver :: + * This field is exclusively used by @FT_Open_Face; it simply specifies + * the font driver to use for opening the face. If set to `NULL`, + * FreeType tries to load the face with each one of the drivers in its + * list. + * + * num_params :: + * The number of extra parameters. + * + * params :: + * Extra parameters passed to the font driver when opening a new face. + * + * @note: + * The stream type is determined by the contents of `flags`: + * + * If the @FT_OPEN_MEMORY bit is set, assume that this is a memory file + * of `memory_size` bytes, located at `memory_address`. The data are not + * copied, and the client is responsible for releasing and destroying + * them _after_ the corresponding call to @FT_Done_Face. + * + * Otherwise, if the @FT_OPEN_STREAM bit is set, assume that a custom + * input stream `stream` is used. + * + * Otherwise, if the @FT_OPEN_PATHNAME bit is set, assume that this is a + * normal file and use `pathname` to open it. + * + * If none of the above bits are set or if multiple are set at the same + * time, the flags are invalid and @FT_Open_Face fails. + * + * If the @FT_OPEN_DRIVER bit is set, @FT_Open_Face only tries to open + * the file with the driver whose handler is in `driver`. + * + * If the @FT_OPEN_PARAMS bit is set, the parameters given by + * `num_params` and `params` is used. They are ignored otherwise. + * + * Ideally, both the `pathname` and `params` fields should be tagged as + * 'const'; this is missing for API backward compatibility. In other + * words, applications should treat them as read-only. + */ + typedef struct FT_Open_Args_ + { + FT_UInt flags; + const FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; + + } FT_Open_Args; + + + /************************************************************************** + * + * @function: + * FT_New_Face + * + * @description: + * Call @FT_Open_Face to open a font by its pathname. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * pathname :: + * A path to the font file. + * + * face_index :: + * See @FT_Open_Face for a detailed description of this parameter. + * + * @output: + * aface :: + * A handle to a new face object. If `face_index` is greater than or + * equal to zero, it must be non-`NULL`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `pathname` string should be recognizable as such by a standard + * `fopen` call on your system; in particular, this means that `pathname` + * must not contain null bytes. If that is not sufficient to address all + * file name possibilities (for example, to handle wide character file + * names on Windows in UTF-16 encoding) you might use @FT_Open_Face to + * pass a memory array or a stream object instead. + * + * Use @FT_Done_Face to destroy the created @FT_Face object (along with + * its slot and sizes). + */ + FT_EXPORT( FT_Error ) + FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *aface ); + + + /************************************************************************** + * + * @function: + * FT_New_Memory_Face + * + * @description: + * Call @FT_Open_Face to open a font that has been loaded into memory. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * file_base :: + * A pointer to the beginning of the font data. + * + * file_size :: + * The size of the memory chunk used by the font data. + * + * face_index :: + * See @FT_Open_Face for a detailed description of this parameter. + * + * @output: + * aface :: + * A handle to a new face object. If `face_index` is greater than or + * equal to zero, it must be non-`NULL`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You must not deallocate the memory before calling @FT_Done_Face. + */ + FT_EXPORT( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ); + + + /************************************************************************** + * + * @function: + * FT_Open_Face + * + * @description: + * Create a face object from a given resource described by @FT_Open_Args. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * args :: + * A pointer to an `FT_Open_Args` structure that must be filled by the + * caller. + * + * face_index :: + * This field holds two different values. Bits 0-15 are the index of + * the face in the font file (starting with value~0). Set it to~0 if + * there is only one face in the font file. + * + * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation + * fonts only, specifying the named instance index for the current face + * index (starting with value~1; value~0 makes FreeType ignore named + * instances). For non-variation fonts, bits 16-30 are ignored. + * Assuming that you want to access the third named instance in face~4, + * `face_index` should be set to 0x00030004. If you want to access + * face~4 without variation handling, simply set `face_index` to + * value~4. + * + * `FT_Open_Face` and its siblings can be used to quickly check whether + * the font format of a given font resource is supported by FreeType. + * In general, if the `face_index` argument is negative, the function's + * return value is~0 if the font format is recognized, or non-zero + * otherwise. The function allocates a more or less empty face handle + * in `*aface` (if `aface` isn't `NULL`); the only two useful fields in + * this special case are `face->num_faces` and `face->style_flags`. + * For any negative value of `face_index`, `face->num_faces` gives the + * number of faces within the font file. For the negative value + * '-(N+1)' (with 'N' a non-negative 16-bit value), bits 16-30 in + * `face->style_flags` give the number of named instances in face 'N' + * if we have a variation font (or zero otherwise). After examination, + * the returned @FT_Face structure should be deallocated with a call to + * @FT_Done_Face. + * + * @output: + * aface :: + * A handle to a new face object. If `face_index` is greater than or + * equal to zero, it must be non-`NULL`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Unlike FreeType 1.x, this function automatically creates a glyph slot + * for the face object that can be accessed directly through + * `face->glyph`. + * + * Each new face object created with this function also owns a default + * @FT_Size object, accessible as `face->size`. + * + * One @FT_Library instance can have multiple face objects, that is, + * @FT_Open_Face and its siblings can be called multiple times using the + * same `library` argument. + * + * See the discussion of reference counters in the description of + * @FT_Reference_Face. + * + * If `FT_OPEN_STREAM` is set in `args->flags`, the stream in + * `args->stream` is automatically closed before this function returns + * any error (including `FT_Err_Invalid_Argument`). + * + * @example: + * To loop over all faces, use code similar to the following snippet + * (omitting the error handling). + * + * ``` + * ... + * FT_Face face; + * FT_Long i, num_faces; + * + * + * error = FT_Open_Face( library, args, -1, &face ); + * if ( error ) { ... } + * + * num_faces = face->num_faces; + * FT_Done_Face( face ); + * + * for ( i = 0; i < num_faces; i++ ) + * { + * ... + * error = FT_Open_Face( library, args, i, &face ); + * ... + * FT_Done_Face( face ); + * ... + * } + * ``` + * + * To loop over all valid values for `face_index`, use something similar + * to the following snippet, again without error handling. The code + * accesses all faces immediately (thus only a single call of + * `FT_Open_Face` within the do-loop), with and without named instances. + * + * ``` + * ... + * FT_Face face; + * + * FT_Long num_faces = 0; + * FT_Long num_instances = 0; + * + * FT_Long face_idx = 0; + * FT_Long instance_idx = 0; + * + * + * do + * { + * FT_Long id = ( instance_idx << 16 ) + face_idx; + * + * + * error = FT_Open_Face( library, args, id, &face ); + * if ( error ) { ... } + * + * num_faces = face->num_faces; + * num_instances = face->style_flags >> 16; + * + * ... + * + * FT_Done_Face( face ); + * + * if ( instance_idx < num_instances ) + * instance_idx++; + * else + * { + * face_idx++; + * instance_idx = 0; + * } + * + * } while ( face_idx < num_faces ) + * ``` + */ + FT_EXPORT( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ); + + + /************************************************************************** + * + * @function: + * FT_Attach_File + * + * @description: + * Call @FT_Attach_Stream to attach a file. + * + * @inout: + * face :: + * The target face object. + * + * @input: + * filepathname :: + * The pathname. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ); + + + /************************************************************************** + * + * @function: + * FT_Attach_Stream + * + * @description: + * 'Attach' data to a face object. Normally, this is used to read + * additional information for the face object. For example, you can + * attach an AFM file that comes with a Type~1 font to get the kerning + * values and other metrics. + * + * @inout: + * face :: + * The target face object. + * + * @input: + * parameters :: + * A pointer to @FT_Open_Args that must be filled by the caller. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The meaning of the 'attach' (i.e., what really happens when the new + * file is read) is not fixed by FreeType itself. It really depends on + * the font format (and thus the font driver). + * + * Client applications are expected to know what they are doing when + * invoking this function. Most drivers simply do not implement file or + * stream attachments. + */ + FT_EXPORT( FT_Error ) + FT_Attach_Stream( FT_Face face, + const FT_Open_Args* parameters ); + + + /************************************************************************** + * + * @function: + * FT_Reference_Face + * + * @description: + * A counter gets initialized to~1 at the time an @FT_Face structure is + * created. This function increments the counter. @FT_Done_Face then + * only destroys a face if the counter is~1, otherwise it simply + * decrements the counter. + * + * This function helps in managing life-cycles of structures that + * reference @FT_Face objects. + * + * @input: + * face :: + * A handle to a target face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.4.2 + * + */ + FT_EXPORT( FT_Error ) + FT_Reference_Face( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Done_Face + * + * @description: + * Discard a given face object, as well as all of its child slots and + * sizes. + * + * @input: + * face :: + * A handle to a target face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * See the discussion of reference counters in the description of + * @FT_Reference_Face. + */ + FT_EXPORT( FT_Error ) + FT_Done_Face( FT_Face face ); + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @function: + * FT_Select_Size + * + * @description: + * Select a bitmap strike. To be more precise, this function sets the + * scaling factors of the active @FT_Size object in a face so that + * bitmaps from this particular strike are taken by @FT_Load_Glyph and + * friends. + * + * @inout: + * face :: + * A handle to a target face object. + * + * @input: + * strike_index :: + * The index of the bitmap strike in the `available_sizes` field of + * @FT_FaceRec structure. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * For bitmaps embedded in outline fonts it is common that only a subset + * of the available glyphs at a given ppem value is available. FreeType + * silently uses outlines if there is no bitmap for a given glyph index. + * + * For GX and OpenType variation fonts, a bitmap strike makes sense only + * if the default instance is active (that is, no glyph variation takes + * place); otherwise, FreeType simply ignores bitmap strikes. The same + * is true for all named instances that are different from the default + * instance. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ); + + + /************************************************************************** + * + * @enum: + * FT_Size_Request_Type + * + * @description: + * An enumeration type that lists the supported size request types, i.e., + * what input size (in font units) maps to the requested output size (in + * pixels, as computed from the arguments of @FT_Size_Request). + * + * @values: + * FT_SIZE_REQUEST_TYPE_NOMINAL :: + * The nominal size. The `units_per_EM` field of @FT_FaceRec is used + * to determine both scaling values. + * + * This is the standard scaling found in most applications. In + * particular, use this size request type for TrueType fonts if they + * provide optical scaling or something similar. Note, however, that + * `units_per_EM` is a rather abstract value which bears no relation to + * the actual size of the glyphs in a font. + * + * FT_SIZE_REQUEST_TYPE_REAL_DIM :: + * The real dimension. The sum of the `ascender` and (minus of) the + * `descender` fields of @FT_FaceRec is used to determine both scaling + * values. + * + * FT_SIZE_REQUEST_TYPE_BBOX :: + * The font bounding box. The width and height of the `bbox` field of + * @FT_FaceRec are used to determine the horizontal and vertical + * scaling value, respectively. + * + * FT_SIZE_REQUEST_TYPE_CELL :: + * The `max_advance_width` field of @FT_FaceRec is used to determine + * the horizontal scaling value; the vertical scaling value is + * determined the same way as @FT_SIZE_REQUEST_TYPE_REAL_DIM does. + * Finally, both scaling values are set to the smaller one. This type + * is useful if you want to specify the font size for, say, a window of + * a given dimension and 80x24 cells. + * + * FT_SIZE_REQUEST_TYPE_SCALES :: + * Specify the scaling values directly. + * + * @note: + * The above descriptions only apply to scalable formats. For bitmap + * formats, the behaviour is up to the driver. + * + * See the note section of @FT_Size_Metrics if you wonder how size + * requesting relates to scaling values. + */ + typedef enum FT_Size_Request_Type_ + { + FT_SIZE_REQUEST_TYPE_NOMINAL, + FT_SIZE_REQUEST_TYPE_REAL_DIM, + FT_SIZE_REQUEST_TYPE_BBOX, + FT_SIZE_REQUEST_TYPE_CELL, + FT_SIZE_REQUEST_TYPE_SCALES, + + FT_SIZE_REQUEST_TYPE_MAX + + } FT_Size_Request_Type; + + + /************************************************************************** + * + * @struct: + * FT_Size_RequestRec + * + * @description: + * A structure to model a size request. + * + * @fields: + * type :: + * See @FT_Size_Request_Type. + * + * width :: + * The desired width, given as a 26.6 fractional point value (with 72pt + * = 1in). + * + * height :: + * The desired height, given as a 26.6 fractional point value (with + * 72pt = 1in). + * + * horiResolution :: + * The horizontal resolution (dpi, i.e., pixels per inch). If set to + * zero, `width` is treated as a 26.6 fractional **pixel** value, which + * gets internally rounded to an integer. + * + * vertResolution :: + * The vertical resolution (dpi, i.e., pixels per inch). If set to + * zero, `height` is treated as a 26.6 fractional **pixel** value, + * which gets internally rounded to an integer. + * + * @note: + * If `width` is zero, the horizontal scaling value is set equal to the + * vertical scaling value, and vice versa. + * + * If `type` is `FT_SIZE_REQUEST_TYPE_SCALES`, `width` and `height` are + * interpreted directly as 16.16 fractional scaling values, without any + * further modification, and both `horiResolution` and `vertResolution` + * are ignored. + */ + typedef struct FT_Size_RequestRec_ + { + FT_Size_Request_Type type; + FT_Long width; + FT_Long height; + FT_UInt horiResolution; + FT_UInt vertResolution; + + } FT_Size_RequestRec; + + + /************************************************************************** + * + * @struct: + * FT_Size_Request + * + * @description: + * A handle to a size request structure. + */ + typedef struct FT_Size_RequestRec_ *FT_Size_Request; + + + /************************************************************************** + * + * @function: + * FT_Request_Size + * + * @description: + * Resize the scale of the active @FT_Size object in a face. + * + * @inout: + * face :: + * A handle to a target face object. + * + * @input: + * req :: + * A pointer to a @FT_Size_RequestRec. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Although drivers may select the bitmap strike matching the request, + * you should not rely on this if you intend to select a particular + * bitmap strike. Use @FT_Select_Size instead in that case. + * + * The relation between the requested size and the resulting glyph size + * is dependent entirely on how the size is defined in the source face. + * The font designer chooses the final size of each glyph relative to + * this size. For more information refer to + * 'https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html'. + * + * Contrary to @FT_Set_Char_Size, this function doesn't have special code + * to normalize zero-valued widths, heights, or resolutions, which are + * treated as @FT_LOAD_NO_SCALE. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ); + + + /************************************************************************** + * + * @function: + * FT_Set_Char_Size + * + * @description: + * Call @FT_Request_Size to request the nominal size (in points). + * + * @inout: + * face :: + * A handle to a target face object. + * + * @input: + * char_width :: + * The nominal width, in 26.6 fractional points. + * + * char_height :: + * The nominal height, in 26.6 fractional points. + * + * horz_resolution :: + * The horizontal resolution in dpi. + * + * vert_resolution :: + * The vertical resolution in dpi. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * While this function allows fractional points as input values, the + * resulting ppem value for the given resolution is always rounded to the + * nearest integer. + * + * If either the character width or height is zero, it is set equal to + * the other value. + * + * If either the horizontal or vertical resolution is zero, it is set + * equal to the other value. + * + * A character width or height smaller than 1pt is set to 1pt; if both + * resolution values are zero, they are set to 72dpi. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + + /************************************************************************** + * + * @function: + * FT_Set_Pixel_Sizes + * + * @description: + * Call @FT_Request_Size to request the nominal size (in pixels). + * + * @inout: + * face :: + * A handle to the target face object. + * + * @input: + * pixel_width :: + * The nominal width, in pixels. + * + * pixel_height :: + * The nominal height, in pixels. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should not rely on the resulting glyphs matching or being + * constrained to this pixel size. Refer to @FT_Request_Size to + * understand how requested sizes relate to actual sizes. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @function: + * FT_Load_Glyph + * + * @description: + * Load a glyph into the glyph slot of a face object. + * + * @inout: + * face :: + * A handle to the target face object where the glyph is loaded. + * + * @input: + * glyph_index :: + * The index of the glyph in the font file. For CID-keyed fonts + * (either in PS or in CFF format) this argument specifies the CID + * value. + * + * load_flags :: + * A flag indicating what to load for this glyph. The @FT_LOAD_XXX + * flags can be used to control the glyph loading process (e.g., + * whether the outline should be scaled, whether to load bitmaps or + * not, whether to hint the outline, etc). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * For proper scaling and hinting, the active @FT_Size object owned by + * the face has to be meaningfully initialized by calling + * @FT_Set_Char_Size before this function, for example. The loaded + * glyph may be transformed. See @FT_Set_Transform for the details. + * + * For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument` is returned + * for invalid CID values (that is, for CID values that don't have a + * corresponding glyph in the font). See the discussion of the + * @FT_FACE_FLAG_CID_KEYED flag for more details. + * + * If you receive `FT_Err_Glyph_Too_Big`, try getting the glyph outline + * at EM size, then scale it manually and fill it as a graphics + * operation. + */ + FT_EXPORT( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /************************************************************************** + * + * @section: + * character_mapping + * + */ + + /************************************************************************** + * + * @function: + * FT_Load_Char + * + * @description: + * Load a glyph into the glyph slot of a face object, accessed by its + * character code. + * + * @inout: + * face :: + * A handle to a target face object where the glyph is loaded. + * + * @input: + * char_code :: + * The glyph's character code, according to the current charmap used in + * the face. + * + * load_flags :: + * A flag indicating what to load for this glyph. The @FT_LOAD_XXX + * constants can be used to control the glyph loading process (e.g., + * whether the outline should be scaled, whether to load bitmaps or + * not, whether to hint the outline, etc). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function simply calls @FT_Get_Char_Index and @FT_Load_Glyph. + * + * Many fonts contain glyphs that can't be loaded by this function since + * its glyph indices are not listed in any of the font's charmaps. + * + * If no active cmap is set up (i.e., `face->charmap` is zero), the call + * to @FT_Get_Char_Index is omitted, and the function behaves identically + * to @FT_Load_Glyph. + */ + FT_EXPORT( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ); + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @enum: + * FT_LOAD_XXX + * + * @description: + * A list of bit field constants for @FT_Load_Glyph to indicate what kind + * of operations to perform during glyph loading. + * + * @values: + * FT_LOAD_DEFAULT :: + * Corresponding to~0, this value is used as the default glyph load + * operation. In this case, the following happens: + * + * 1. FreeType looks for a bitmap for the glyph corresponding to the + * face's current size. If one is found, the function returns. The + * bitmap data can be accessed from the glyph slot (see note below). + * + * 2. If no embedded bitmap is searched for or found, FreeType looks + * for a scalable outline. If one is found, it is loaded from the font + * file, scaled to device pixels, then 'hinted' to the pixel grid in + * order to optimize it. The outline data can be accessed from the + * glyph slot (see note below). + * + * Note that by default the glyph loader doesn't render outlines into + * bitmaps. The following flags are used to modify this default + * behaviour to more specific and useful cases. + * + * FT_LOAD_NO_SCALE :: + * Don't scale the loaded outline glyph but keep it in font units. + * This flag is also assumed if @FT_Size owned by the face was not + * properly initialized. + * + * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and + * unsets @FT_LOAD_RENDER. + * + * If the font is 'tricky' (see @FT_FACE_FLAG_TRICKY for more), using + * `FT_LOAD_NO_SCALE` usually yields meaningless outlines because the + * subglyphs must be scaled and positioned with hinting instructions. + * This can be solved by loading the font without `FT_LOAD_NO_SCALE` + * and setting the character size to `font->units_per_EM`. + * + * FT_LOAD_NO_HINTING :: + * Disable hinting. This generally generates 'blurrier' bitmap glyphs + * when the glyphs are rendered in any of the anti-aliased modes. See + * also the note below. + * + * This flag is implied by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_RENDER :: + * Call @FT_Render_Glyph after the glyph is loaded. By default, the + * glyph is rendered in @FT_RENDER_MODE_NORMAL mode. This can be + * overridden by @FT_LOAD_TARGET_XXX or @FT_LOAD_MONOCHROME. + * + * This flag is unset by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_NO_BITMAP :: + * Ignore bitmap strikes when loading. Bitmap-only fonts ignore this + * flag. + * + * @FT_LOAD_NO_SCALE always sets this flag. + * + * FT_LOAD_SBITS_ONLY :: + * [Since 2.12] This is the opposite of @FT_LOAD_NO_BITMAP, more or + * less: @FT_Load_Glyph returns `FT_Err_Invalid_Argument` if the face + * contains a bitmap strike for the given size (or the strike selected + * by @FT_Select_Size) but there is no glyph in the strike. + * + * Note that this load flag was part of FreeType since version 2.0.6 + * but previously tagged as internal. + * + * FT_LOAD_VERTICAL_LAYOUT :: + * Load the glyph for vertical text layout. In particular, the + * `advance` value in the @FT_GlyphSlotRec structure is set to the + * `vertAdvance` value of the `metrics` field. + * + * In case @FT_HAS_VERTICAL doesn't return true, you shouldn't use this + * flag currently. Reason is that in this case vertical metrics get + * synthesized, and those values are not always consistent across + * various font formats. + * + * FT_LOAD_FORCE_AUTOHINT :: + * Prefer the auto-hinter over the font's native hinter. See also the + * note below. + * + * FT_LOAD_PEDANTIC :: + * Make the font driver perform pedantic verifications during glyph + * loading and hinting. This is mostly used to detect broken glyphs in + * fonts. By default, FreeType tries to handle broken fonts also. + * + * In particular, errors from the TrueType bytecode engine are not + * passed to the application if this flag is not set; this might result + * in partially hinted or distorted glyphs in case a glyph's bytecode + * is buggy. + * + * FT_LOAD_NO_RECURSE :: + * Don't load composite glyphs recursively. Instead, the font driver + * fills the `num_subglyph` and `subglyphs` values of the glyph slot; + * it also sets `glyph->format` to @FT_GLYPH_FORMAT_COMPOSITE. The + * description of subglyphs can then be accessed with + * @FT_Get_SubGlyph_Info. + * + * Don't use this flag for retrieving metrics information since some + * font drivers only return rudimentary data. + * + * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM. + * + * FT_LOAD_IGNORE_TRANSFORM :: + * Ignore the transform matrix set by @FT_Set_Transform. + * + * FT_LOAD_MONOCHROME :: + * This flag is used with @FT_LOAD_RENDER to indicate that you want to + * render an outline glyph to a 1-bit monochrome bitmap glyph, with + * 8~pixels packed into each byte of the bitmap data. + * + * Note that this has no effect on the hinting algorithm used. You + * should rather use @FT_LOAD_TARGET_MONO so that the + * monochrome-optimized hinting algorithm is used. + * + * FT_LOAD_LINEAR_DESIGN :: + * Keep `linearHoriAdvance` and `linearVertAdvance` fields of + * @FT_GlyphSlotRec in font units. See @FT_GlyphSlotRec for details. + * + * FT_LOAD_NO_AUTOHINT :: + * Disable the auto-hinter. See also the note below. + * + * FT_LOAD_COLOR :: + * Load colored glyphs. FreeType searches in the following order; + * there are slight differences depending on the font format. + * + * [Since 2.5] Load embedded color bitmap images (provided + * @FT_LOAD_NO_BITMAP is not set). The resulting color bitmaps, if + * available, have the @FT_PIXEL_MODE_BGRA format, with pre-multiplied + * color channels. If the flag is not set and color bitmaps are found, + * they are converted to 256-level gray bitmaps, using the + * @FT_PIXEL_MODE_GRAY format. + * + * [Since 2.12] If the glyph index maps to an entry in the face's + * 'SVG~' table, load the associated SVG document from this table and + * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG + * ([since 2.13.1] provided @FT_LOAD_NO_SVG is not set). Note that + * FreeType itself can't render SVG documents; however, the library + * provides hooks to seamlessly integrate an external renderer. See + * sections @ot_svg_driver and @svg_fonts for more. + * + * [Since 2.10, experimental] If the glyph index maps to an entry in + * the face's 'COLR' table with a 'CPAL' palette table (as defined in + * the OpenType specification), make @FT_Render_Glyph provide a default + * blending of the color glyph layers associated with the glyph index, + * using the same bitmap format as embedded color bitmap images. This + * is mainly for convenience and works only for glyphs in 'COLR' v0 + * tables (or glyphs in 'COLR' v1 tables that exclusively use v0 + * features). For full control of color layers use + * @FT_Get_Color_Glyph_Layer and FreeType's color functions like + * @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering + * so that the client application can handle blending by itself. + * + * FT_LOAD_NO_SVG :: + * [Since 2.13.1] Ignore SVG glyph data when loading. + * + * FT_LOAD_COMPUTE_METRICS :: + * [Since 2.6.1] Compute glyph metrics from the glyph data, without the + * use of bundled metrics tables (for example, the 'hdmx' table in + * TrueType fonts). This flag is mainly used by font validating or + * font editing applications, which need to ignore, verify, or edit + * those tables. + * + * Currently, this flag is only implemented for TrueType fonts. + * + * FT_LOAD_BITMAP_METRICS_ONLY :: + * [Since 2.7.1] Request loading of the metrics and bitmap image + * information of a (possibly embedded) bitmap glyph without allocating + * or copying the bitmap image data itself. No effect if the target + * glyph is not a bitmap image. + * + * This flag unsets @FT_LOAD_RENDER. + * + * FT_LOAD_CROP_BITMAP :: + * Ignored. Deprecated. + * + * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: + * Ignored. Deprecated. + * + * @note: + * By default, hinting is enabled and the font's native hinter (see + * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can + * disable hinting by setting @FT_LOAD_NO_HINTING or change the + * precedence by setting @FT_LOAD_FORCE_AUTOHINT. You can also set + * @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be used + * at all. + * + * See the description of @FT_FACE_FLAG_TRICKY for a special exception + * (affecting only a handful of Asian fonts). + * + * Besides deciding which hinter to use, you can also decide which + * hinting algorithm to use. See @FT_LOAD_TARGET_XXX for details. + * + * Note that the auto-hinter needs a valid Unicode cmap (either a native + * one or synthesized by FreeType) for producing correct results. If a + * font provides an incorrect mapping (for example, assigning the + * character code U+005A, LATIN CAPITAL LETTER~Z, to a glyph depicting a + * mathematical integral sign), the auto-hinter might produce useless + * results. + * + */ +#define FT_LOAD_DEFAULT 0x0 +#define FT_LOAD_NO_SCALE ( 1L << 0 ) +#define FT_LOAD_NO_HINTING ( 1L << 1 ) +#define FT_LOAD_RENDER ( 1L << 2 ) +#define FT_LOAD_NO_BITMAP ( 1L << 3 ) +#define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) +#define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) +#define FT_LOAD_CROP_BITMAP ( 1L << 6 ) +#define FT_LOAD_PEDANTIC ( 1L << 7 ) +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) +#define FT_LOAD_NO_RECURSE ( 1L << 10 ) +#define FT_LOAD_IGNORE_TRANSFORM ( 1L << 11 ) +#define FT_LOAD_MONOCHROME ( 1L << 12 ) +#define FT_LOAD_LINEAR_DESIGN ( 1L << 13 ) +#define FT_LOAD_SBITS_ONLY ( 1L << 14 ) +#define FT_LOAD_NO_AUTOHINT ( 1L << 15 ) + /* Bits 16-19 are used by `FT_LOAD_TARGET_` */ +#define FT_LOAD_COLOR ( 1L << 20 ) +#define FT_LOAD_COMPUTE_METRICS ( 1L << 21 ) +#define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 ) +#define FT_LOAD_NO_SVG ( 1L << 24 ) + + /* */ + + /* used internally only by certain font drivers */ +#define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) +#define FT_LOAD_SVG_ONLY ( 1L << 23 ) + + + /************************************************************************** + * + * @enum: + * FT_LOAD_TARGET_XXX + * + * @description: + * A list of values to select a specific hinting algorithm for the + * hinter. You should OR one of these values to your `load_flags` when + * calling @FT_Load_Glyph. + * + * Note that a font's native hinters may ignore the hinting algorithm you + * have specified (e.g., the TrueType bytecode interpreter). You can set + * @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used. + * + * @values: + * FT_LOAD_TARGET_NORMAL :: + * The default hinting algorithm, optimized for standard gray-level + * rendering. For monochrome output, use @FT_LOAD_TARGET_MONO instead. + * + * FT_LOAD_TARGET_LIGHT :: + * A lighter hinting algorithm for gray-level modes. Many generated + * glyphs are fuzzier but better resemble their original shape. This + * is achieved by snapping glyphs to the pixel grid only vertically + * (Y-axis), as is done by FreeType's new CFF engine or Microsoft's + * ClearType font renderer. This preserves inter-glyph spacing in + * horizontal text. The snapping is done either by the native font + * driver, if the driver itself and the font support it, or by the + * auto-hinter. + * + * Advance widths are rounded to integer values; however, using the + * `lsb_delta` and `rsb_delta` fields of @FT_GlyphSlotRec, it is + * possible to get fractional advance widths for subpixel positioning + * (which is recommended to use). + * + * If configuration option `AF_CONFIG_OPTION_TT_SIZE_METRICS` is + * active, TrueType-like metrics are used to make this mode behave + * similarly as in unpatched FreeType versions between 2.4.6 and 2.7.1 + * (inclusive). + * + * FT_LOAD_TARGET_MONO :: + * Strong hinting algorithm that should only be used for monochrome + * output. The result is probably unpleasant if the glyph is rendered + * in non-monochrome modes. + * + * Note that for outline fonts only the TrueType font driver has proper + * monochrome hinting support, provided the TTFs contain hints for B/W + * rendering (which most fonts no longer provide). If these conditions + * are not met it is very likely that you get ugly results at smaller + * sizes. + * + * FT_LOAD_TARGET_LCD :: + * A variant of @FT_LOAD_TARGET_LIGHT optimized for horizontally + * decimated LCD displays. + * + * FT_LOAD_TARGET_LCD_V :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for vertically + * decimated LCD displays. + * + * @note: + * You should use only _one_ of the `FT_LOAD_TARGET_XXX` values in your + * `load_flags`. They can't be ORed. + * + * If @FT_LOAD_RENDER is also set, the glyph is rendered in the + * corresponding mode (i.e., the mode that matches the used algorithm + * best). An exception is `FT_LOAD_TARGET_MONO` since it implies + * @FT_LOAD_MONOCHROME. + * + * You can use a hinting algorithm that doesn't correspond to the same + * rendering mode. As an example, it is possible to use the 'light' + * hinting algorithm and have the results rendered in horizontal LCD + * pixel mode, with code like + * + * ``` + * FT_Load_Glyph( face, glyph_index, + * load_flags | FT_LOAD_TARGET_LIGHT ); + * + * FT_Render_Glyph( face->glyph, FT_RENDER_MODE_LCD ); + * ``` + * + * In general, you should stick with one rendering mode. For example, + * switching between @FT_LOAD_TARGET_NORMAL and @FT_LOAD_TARGET_MONO + * enforces a lot of recomputation for TrueType fonts, which is slow. + * Another reason is caching: Selecting a different mode usually causes + * changes in both the outlines and the rasterized bitmaps; it is thus + * necessary to empty the cache after a mode switch to avoid false hits. + * + */ +#define FT_LOAD_TARGET_( x ) ( FT_STATIC_CAST( FT_Int32, (x) & 15 ) << 16 ) + +#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) +#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) +#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) +#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) +#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) + + + /************************************************************************** + * + * @macro: + * FT_LOAD_TARGET_MODE + * + * @description: + * Return the @FT_Render_Mode corresponding to a given + * @FT_LOAD_TARGET_XXX value. + * + */ +#define FT_LOAD_TARGET_MODE( x ) \ + FT_STATIC_CAST( FT_Render_Mode, ( (x) >> 16 ) & 15 ) + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @function: + * FT_Set_Transform + * + * @description: + * Set the transformation that is applied to glyph images when they are + * loaded into a glyph slot through @FT_Load_Glyph. + * + * @inout: + * face :: + * A handle to the source face object. + * + * @input: + * matrix :: + * A pointer to the transformation's 2x2 matrix. Use `NULL` for the + * identity matrix. + * delta :: + * A pointer to the translation vector. Use `NULL` for the null + * vector. + * + * @note: + * This function is provided as a convenience, but keep in mind that + * @FT_Matrix coefficients are only 16.16 fixed-point values, which can + * limit the accuracy of the results. Using floating-point computations + * to perform the transform directly in client code instead will always + * yield better numbers. + * + * The transformation is only applied to scalable image formats after the + * glyph has been loaded. It means that hinting is unaltered by the + * transformation and is performed on the character size given in the + * last call to @FT_Set_Char_Size or @FT_Set_Pixel_Sizes. + * + * Note that this also transforms the `face.glyph.advance` field, but + * **not** the values in `face.glyph.metrics`. + */ + FT_EXPORT( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /************************************************************************** + * + * @function: + * FT_Get_Transform + * + * @description: + * Return the transformation that is applied to glyph images when they + * are loaded into a glyph slot through @FT_Load_Glyph. See + * @FT_Set_Transform for more details. + * + * @input: + * face :: + * A handle to the source face object. + * + * @output: + * matrix :: + * A pointer to a transformation's 2x2 matrix. Set this to NULL if you + * are not interested in the value. + * + * delta :: + * A pointer to a translation vector. Set this to NULL if you are not + * interested in the value. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @enum: + * FT_Render_Mode + * + * @description: + * Render modes supported by FreeType~2. Each mode corresponds to a + * specific type of scanline conversion performed on the outline. + * + * For bitmap fonts and embedded bitmaps the `bitmap->pixel_mode` field + * in the @FT_GlyphSlotRec structure gives the format of the returned + * bitmap. + * + * All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity, + * indicating pixel coverage. Use linear alpha blending and gamma + * correction to correctly render non-monochrome glyph bitmaps onto a + * surface; see @FT_Render_Glyph. + * + * The @FT_RENDER_MODE_SDF is a special render mode that uses up to 256 + * distance values, indicating the signed distance from the grid position + * to the nearest outline. + * + * @values: + * FT_RENDER_MODE_NORMAL :: + * Default render mode; it corresponds to 8-bit anti-aliased bitmaps. + * + * FT_RENDER_MODE_LIGHT :: + * This is equivalent to @FT_RENDER_MODE_NORMAL. It is only defined as + * a separate value because render modes are also used indirectly to + * define hinting algorithm selectors. See @FT_LOAD_TARGET_XXX for + * details. + * + * FT_RENDER_MODE_MONO :: + * This mode corresponds to 1-bit bitmaps (with 2~levels of opacity). + * + * FT_RENDER_MODE_LCD :: + * This mode corresponds to horizontal RGB and BGR subpixel displays + * like LCD screens. It produces 8-bit bitmaps that are 3~times the + * width of the original glyph outline in pixels, and which use the + * @FT_PIXEL_MODE_LCD mode. + * + * FT_RENDER_MODE_LCD_V :: + * This mode corresponds to vertical RGB and BGR subpixel displays + * (like PDA screens, rotated LCD displays, etc.). It produces 8-bit + * bitmaps that are 3~times the height of the original glyph outline in + * pixels and use the @FT_PIXEL_MODE_LCD_V mode. + * + * FT_RENDER_MODE_SDF :: + * This mode corresponds to 8-bit, single-channel signed distance field + * (SDF) bitmaps. Each pixel in the SDF grid is the value from the + * pixel's position to the nearest glyph's outline. The distances are + * calculated from the center of the pixel and are positive if they are + * filled by the outline (i.e., inside the outline) and negative + * otherwise. Check the note below on how to convert the output values + * to usable data. + * + * @note: + * The selected render mode only affects vector glyphs of a font. + * Embedded bitmaps often have a different pixel mode like + * @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform them + * into 8-bit pixmaps. + * + * For @FT_RENDER_MODE_SDF the output bitmap buffer contains normalized + * distances that are packed into unsigned 8-bit values. To get pixel + * values in floating point representation use the following pseudo-C + * code for the conversion. + * + * ``` + * // Load glyph and render using FT_RENDER_MODE_SDF, + * // then use the output buffer as follows. + * + * ... + * FT_Byte buffer = glyph->bitmap->buffer; + * + * + * for pixel in buffer + * { + * // `sd` is the signed distance and `spread` is the current spread; + * // the default spread is 2 and can be changed. + * + * float sd = (float)pixel - 128.0f; + * + * + * // Convert to pixel values. + * sd = ( sd / 128.0f ) * spread; + * + * // Store `sd` in a buffer or use as required. + * } + * + * ``` + * + * FreeType has two rasterizers for generating SDF, namely: + * + * 1. `sdf` for generating SDF directly from glyph's outline, and + * + * 2. `bsdf` for generating SDF from rasterized bitmaps. + * + * Depending on the glyph type (i.e., outline or bitmap), one of the two + * rasterizers is chosen at runtime and used for generating SDFs. To + * force the use of `bsdf` you should render the glyph with any of the + * FreeType's other rendering modes (e.g., `FT_RENDER_MODE_NORMAL`) and + * then re-render with `FT_RENDER_MODE_SDF`. + * + * There are some issues with stability and possible failures of the SDF + * renderers (specifically `sdf`). + * + * 1. The `sdf` rasterizer is sensitive to really small features (e.g., + * sharp turns that are less than 1~pixel) and imperfections in the + * glyph's outline, causing artifacts in the final output. + * + * 2. The `sdf` rasterizer has limited support for handling intersecting + * contours and *cannot* handle self-intersecting contours whatsoever. + * Self-intersection happens when a single connected contour + * intersects itself at some point; having these in your font + * definitely poses a problem to the rasterizer and cause artifacts, + * too. + * + * 3. Generating SDF for really small glyphs may result in undesirable + * output; the pixel grid (which stores distance information) becomes + * too coarse. + * + * 4. Since the output buffer is normalized, precision at smaller spreads + * is greater than precision at larger spread values because the + * output range of [0..255] gets mapped to a smaller SDF range. A + * spread of~2 should be sufficient in most cases. + * + * Points (1) and (2) can be avoided by using the `bsdf` rasterizer, + * which is more stable than the `sdf` rasterizer in general. + * + */ + typedef enum FT_Render_Mode_ + { + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + FT_RENDER_MODE_SDF, + + FT_RENDER_MODE_MAX + + } FT_Render_Mode; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Render_Mode` values instead */ +#define ft_render_mode_normal FT_RENDER_MODE_NORMAL +#define ft_render_mode_mono FT_RENDER_MODE_MONO + + + /************************************************************************** + * + * @function: + * FT_Render_Glyph + * + * @description: + * Convert a given glyph image to a bitmap. It does so by inspecting the + * glyph image format, finding the relevant renderer, and invoking it. + * + * @inout: + * slot :: + * A handle to the glyph slot containing the image to convert. + * + * @input: + * render_mode :: + * The render mode used to render the glyph image into a bitmap. See + * @FT_Render_Mode for a list of possible values. + * + * If @FT_RENDER_MODE_NORMAL is used, a previous call of @FT_Load_Glyph + * with flag @FT_LOAD_COLOR makes `FT_Render_Glyph` provide a default + * blending of colored glyph layers associated with the current glyph + * slot (provided the font contains such layers) instead of rendering + * the glyph slot's outline. This is an experimental feature; see + * @FT_LOAD_COLOR for more information. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * When FreeType outputs a bitmap of a glyph, it really outputs an alpha + * coverage map. If a pixel is completely covered by a filled-in + * outline, the bitmap contains 0xFF at that pixel, meaning that + * 0xFF/0xFF fraction of that pixel is covered, meaning the pixel is 100% + * black (or 0% bright). If a pixel is only 50% covered (value 0x80), + * the pixel is made 50% black (50% bright or a middle shade of grey). + * 0% covered means 0% black (100% bright or white). + * + * On high-DPI screens like on smartphones and tablets, the pixels are so + * small that their chance of being completely covered and therefore + * completely black are fairly good. On the low-DPI screens, however, + * the situation is different. The pixels are too large for most of the + * details of a glyph and shades of gray are the norm rather than the + * exception. + * + * This is relevant because all our screens have a second problem: they + * are not linear. 1~+~1 is not~2. Twice the value does not result in + * twice the brightness. When a pixel is only 50% covered, the coverage + * map says 50% black, and this translates to a pixel value of 128 when + * you use 8~bits per channel (0-255). However, this does not translate + * to 50% brightness for that pixel on our sRGB and gamma~2.2 screens. + * Due to their non-linearity, they dwell longer in the darks and only a + * pixel value of about 186 results in 50% brightness -- 128 ends up too + * dark on both bright and dark backgrounds. The net result is that dark + * text looks burnt-out, pixely and blotchy on bright background, bright + * text too frail on dark backgrounds, and colored text on colored + * background (for example, red on green) seems to have dark halos or + * 'dirt' around it. The situation is especially ugly for diagonal stems + * like in 'w' glyph shapes where the quality of FreeType's anti-aliasing + * depends on the correct display of grays. On high-DPI screens where + * smaller, fully black pixels reign supreme, this doesn't matter, but on + * our low-DPI screens with all the gray shades, it does. 0% and 100% + * brightness are the same things in linear and non-linear space, just + * all the shades in-between aren't. + * + * The blending function for placing text over a background is + * + * ``` + * dst = alpha * src + (1 - alpha) * dst , + * ``` + * + * which is known as the OVER operator. + * + * To correctly composite an anti-aliased pixel of a glyph onto a + * surface, + * + * 1. take the foreground and background colors (e.g., in sRGB space) + * and apply gamma to get them in a linear space, + * + * 2. use OVER to blend the two linear colors using the glyph pixel + * as the alpha value (remember, the glyph bitmap is an alpha coverage + * bitmap), and + * + * 3. apply inverse gamma to the blended pixel and write it back to + * the image. + * + * Internal testing at Adobe found that a target inverse gamma of~1.8 for + * step~3 gives good results across a wide range of displays with an sRGB + * gamma curve or a similar one. + * + * This process can cost performance. There is an approximation that + * does not need to know about the background color; see + * https://bel.fi/alankila/lcd/ and + * https://bel.fi/alankila/lcd/alpcor.html for details. + * + * **ATTENTION**: Linear blending is even more important when dealing + * with subpixel-rendered glyphs to prevent color-fringing! A + * subpixel-rendered glyph must first be filtered with a filter that + * gives equal weight to the three color primaries and does not exceed a + * sum of 0x100, see section @lcd_rendering. Then the only difference to + * gray linear blending is that subpixel-rendered linear blending is done + * 3~times per pixel: red foreground subpixel to red background subpixel + * and so on for green and blue. + */ + FT_EXPORT( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + + /************************************************************************** + * + * @enum: + * FT_Kerning_Mode + * + * @description: + * An enumeration to specify the format of kerning values returned by + * @FT_Get_Kerning. + * + * @values: + * FT_KERNING_DEFAULT :: + * Return grid-fitted kerning distances in 26.6 fractional pixels. + * + * FT_KERNING_UNFITTED :: + * Return un-grid-fitted kerning distances in 26.6 fractional pixels. + * + * FT_KERNING_UNSCALED :: + * Return the kerning vector in original font units. + * + * @note: + * `FT_KERNING_DEFAULT` returns full pixel values; it also makes FreeType + * heuristically scale down kerning distances at small ppem values so + * that they don't become too big. + * + * Both `FT_KERNING_DEFAULT` and `FT_KERNING_UNFITTED` use the current + * horizontal scaling factor (as set e.g. with @FT_Set_Char_Size) to + * convert font units to pixels. + */ + typedef enum FT_Kerning_Mode_ + { + FT_KERNING_DEFAULT = 0, + FT_KERNING_UNFITTED, + FT_KERNING_UNSCALED + + } FT_Kerning_Mode; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Kerning_Mode` values instead */ +#define ft_kerning_default FT_KERNING_DEFAULT +#define ft_kerning_unfitted FT_KERNING_UNFITTED +#define ft_kerning_unscaled FT_KERNING_UNSCALED + + + /************************************************************************** + * + * @function: + * FT_Get_Kerning + * + * @description: + * Return the kerning vector between two glyphs of the same face. + * + * @input: + * face :: + * A handle to a source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * kern_mode :: + * See @FT_Kerning_Mode for more information. Determines the scale and + * dimension of the returned kerning vector. + * + * @output: + * akerning :: + * The kerning vector. This is either in font units, fractional pixels + * (26.6 format), or pixels for scalable formats, and in pixels for + * fixed-sizes formats. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Only horizontal layouts (left-to-right & right-to-left) are supported + * by this method. Other layouts, or more sophisticated kernings, are + * out of the scope of this API function -- they can be implemented + * through format-specific interfaces. + * + * Kerning for OpenType fonts implemented in a 'GPOS' table is not + * supported; use @FT_HAS_KERNING to find out whether a font has data + * that can be extracted with `FT_Get_Kerning`. + */ + FT_EXPORT( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ); + + + /************************************************************************** + * + * @function: + * FT_Get_Track_Kerning + * + * @description: + * Return the track kerning for a given face object at a given size. + * + * @input: + * face :: + * A handle to a source face object. + * + * point_size :: + * The point size in 16.16 fractional points. + * + * degree :: + * The degree of tightness. Increasingly negative values represent + * tighter track kerning, while increasingly positive values represent + * looser track kerning. Value zero means no track kerning. + * + * @output: + * akerning :: + * The kerning in 16.16 fractional points, to be uniformly applied + * between all glyphs. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Currently, only the Type~1 font driver supports track kerning, using + * data from AFM files (if attached with @FT_Attach_File or + * @FT_Attach_Stream). + * + * Only very few AFM files come with track kerning data; please refer to + * Adobe's AFM specification for more details. + */ + FT_EXPORT( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + + /************************************************************************** + * + * @section: + * character_mapping + * + */ + + /************************************************************************** + * + * @function: + * FT_Select_Charmap + * + * @description: + * Select a given charmap by its encoding tag (as listed in + * `freetype.h`). + * + * @inout: + * face :: + * A handle to the source face object. + * + * @input: + * encoding :: + * A handle to the selected encoding. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function returns an error if no charmap in the face corresponds + * to the encoding queried here. + * + * Because many fonts contain more than a single cmap for Unicode + * encoding, this function has some special code to select the one that + * covers Unicode best ('best' in the sense that a UCS-4 cmap is + * preferred to a UCS-2 cmap). It is thus preferable to @FT_Set_Charmap + * in this case. + */ + FT_EXPORT( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ); + + + /************************************************************************** + * + * @function: + * FT_Set_Charmap + * + * @description: + * Select a given charmap for character code to glyph index mapping. + * + * @inout: + * face :: + * A handle to the source face object. + * + * @input: + * charmap :: + * A handle to the selected charmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function returns an error if the charmap is not part of the face + * (i.e., if it is not listed in the `face->charmaps` table). + * + * It also fails if an OpenType type~14 charmap is selected (which + * doesn't map character codes to glyph indices at all). + */ + FT_EXPORT( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ); + + + /************************************************************************** + * + * @function: + * FT_Get_Charmap_Index + * + * @description: + * Retrieve index of a given charmap. + * + * @input: + * charmap :: + * A handle to a charmap. + * + * @return: + * The index into the array of character maps within the face to which + * `charmap` belongs. If an error occurs, -1 is returned. + * + */ + FT_EXPORT( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ); + + + /************************************************************************** + * + * @function: + * FT_Get_Char_Index + * + * @description: + * Return the glyph index of a given character code. This function uses + * the currently selected charmap to do the mapping. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character code. + * + * @return: + * The glyph index. 0~means 'undefined character code'. + * + * @note: + * If you use FreeType to manipulate the contents of font files directly, + * be aware that the glyph index returned by this function doesn't always + * correspond to the internal indices used within the file. This is done + * to ensure that value~0 always corresponds to the 'missing glyph'. If + * the first glyph is not named '.notdef', then for Type~1 and Type~42 + * fonts, '.notdef' will be moved into the glyph ID~0 position, and + * whatever was there will be moved to the position '.notdef' had. For + * Type~1 fonts, if there is no '.notdef' glyph at all, then one will be + * created at index~0 and whatever was there will be moved to the last + * index -- Type~42 fonts are considered invalid under this condition. + */ + FT_EXPORT( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ); + + + /************************************************************************** + * + * @function: + * FT_Get_First_Char + * + * @description: + * Return the first character code in the current charmap of a given + * face, together with its corresponding glyph index. + * + * @input: + * face :: + * A handle to the source face object. + * + * @output: + * agindex :: + * Glyph index of first character code. 0~if charmap is empty. + * + * @return: + * The charmap's first character code. + * + * @note: + * You should use this function together with @FT_Get_Next_Char to parse + * all character codes available in a given charmap. The code should + * look like this: + * + * ``` + * FT_ULong charcode; + * FT_UInt gindex; + * + * + * charcode = FT_Get_First_Char( face, &gindex ); + * while ( gindex != 0 ) + * { + * ... do something with (charcode,gindex) pair ... + * + * charcode = FT_Get_Next_Char( face, charcode, &gindex ); + * } + * ``` + * + * Be aware that character codes can have values up to 0xFFFFFFFF; this + * might happen for non-Unicode or malformed cmaps. However, even with + * regular Unicode encoding, so-called 'last resort fonts' (using SFNT + * cmap format 13, see function @FT_Get_CMap_Format) normally have + * entries for all Unicode characters up to 0x1FFFFF, which can cause *a + * lot* of iterations. + * + * Note that `*agindex` is set to~0 if the charmap is empty. The result + * itself can be~0 in two cases: if the charmap is empty or if the + * value~0 is the first valid character code. + */ + FT_EXPORT( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ); + + + /************************************************************************** + * + * @function: + * FT_Get_Next_Char + * + * @description: + * Return the next character code in the current charmap of a given face + * following the value `char_code`, as well as the corresponding glyph + * index. + * + * @input: + * face :: + * A handle to the source face object. + * + * char_code :: + * The starting character code. + * + * @output: + * agindex :: + * Glyph index of next character code. 0~if charmap is empty. + * + * @return: + * The charmap's next character code. + * + * @note: + * You should use this function with @FT_Get_First_Char to walk over all + * character codes available in a given charmap. See the note for that + * function for a simple code example. + * + * Note that `*agindex` is set to~0 when there are no more codes in the + * charmap. + */ + FT_EXPORT( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong char_code, + FT_UInt *agindex ); + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @function: + * FT_Face_Properties + * + * @description: + * Set or override certain (library or module-wide) properties on a + * face-by-face basis. Useful for finer-grained control and avoiding + * locks on shared structures (threads can modify their own faces as they + * see fit). + * + * Contrary to @FT_Property_Set, this function uses @FT_Parameter so that + * you can pass multiple properties to the target face in one call. Note + * that only a subset of the available properties can be controlled. + * + * * @FT_PARAM_TAG_STEM_DARKENING (stem darkening, corresponding to the + * property `no-stem-darkening` provided by the 'autofit', 'cff', + * 'type1', and 't1cid' modules; see @no-stem-darkening). + * + * * @FT_PARAM_TAG_LCD_FILTER_WEIGHTS (LCD filter weights, corresponding + * to function @FT_Library_SetLcdFilterWeights). + * + * * @FT_PARAM_TAG_RANDOM_SEED (seed value for the CFF, Type~1, and CID + * 'random' operator, corresponding to the `random-seed` property + * provided by the 'cff', 'type1', and 't1cid' modules; see + * @random-seed). + * + * Pass `NULL` as `data` in @FT_Parameter for a given tag to reset the + * option and use the library or module default again. + * + * @input: + * face :: + * A handle to the source face object. + * + * num_properties :: + * The number of properties that follow. + * + * properties :: + * A handle to an @FT_Parameter array with `num_properties` elements. + * + * @return: + * FreeType error code. 0~means success. + * + * @example: + * Here is an example that sets three properties. You must define + * `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` to make the LCD filter examples + * work. + * + * ``` + * FT_Parameter property1; + * FT_Bool darken_stems = 1; + * + * FT_Parameter property2; + * FT_LcdFiveTapFilter custom_weight = + * { 0x11, 0x44, 0x56, 0x44, 0x11 }; + * + * FT_Parameter property3; + * FT_Int32 random_seed = 314159265; + * + * FT_Parameter properties[3] = { property1, + * property2, + * property3 }; + * + * + * property1.tag = FT_PARAM_TAG_STEM_DARKENING; + * property1.data = &darken_stems; + * + * property2.tag = FT_PARAM_TAG_LCD_FILTER_WEIGHTS; + * property2.data = custom_weight; + * + * property3.tag = FT_PARAM_TAG_RANDOM_SEED; + * property3.data = &random_seed; + * + * FT_Face_Properties( face, 3, properties ); + * ``` + * + * The next example resets a single property to its default value. + * + * ``` + * FT_Parameter property; + * + * + * property.tag = FT_PARAM_TAG_LCD_FILTER_WEIGHTS; + * property.data = NULL; + * + * FT_Face_Properties( face, 1, &property ); + * ``` + * + * @since: + * 2.8 + * + */ + FT_EXPORT( FT_Error ) + FT_Face_Properties( FT_Face face, + FT_UInt num_properties, + FT_Parameter* properties ); + + + /************************************************************************** + * + * @section: + * information_retrieval + * + */ + + /************************************************************************** + * + * @function: + * FT_Get_Name_Index + * + * @description: + * Return the glyph index of a given glyph name. This only works + * for those faces where @FT_HAS_GLYPH_NAMES returns true. + * + * @input: + * face :: + * A handle to the source face object. + * + * glyph_name :: + * The glyph name. + * + * @return: + * The glyph index. 0~means 'undefined character code'. + * + * @note: + * Acceptable glyph names might come from the [Adobe Glyph + * List](https://github.com/adobe-type-tools/agl-aglfn). See + * @FT_Get_Glyph_Name for the inverse functionality. + * + * This function has limited capabilities if the config macro + * `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` is not defined in `ftoption.h`: + * It then works only for fonts that actually embed glyph names (which + * many recent OpenType fonts do not). + */ + FT_EXPORT( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + const FT_String* glyph_name ); + + + /************************************************************************** + * + * @function: + * FT_Get_Glyph_Name + * + * @description: + * Retrieve the ASCII name of a given glyph in a face. This only works + * for those faces where @FT_HAS_GLYPH_NAMES returns true. + * + * @input: + * face :: + * A handle to a source face object. + * + * glyph_index :: + * The glyph index. + * + * buffer_max :: + * The maximum number of bytes available in the buffer. + * + * @output: + * buffer :: + * A pointer to a target buffer where the name is copied to. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * An error is returned if the face doesn't provide glyph names or if the + * glyph index is invalid. In all cases of failure, the first byte of + * `buffer` is set to~0 to indicate an empty name. + * + * The glyph name is truncated to fit within the buffer if it is too + * long. The returned string is always zero-terminated. + * + * Be aware that FreeType reorders glyph indices internally so that glyph + * index~0 always corresponds to the 'missing glyph' (called '.notdef'). + * + * This function has limited capabilities if the config macro + * `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` is not defined in `ftoption.h`: + * It then works only for fonts that actually embed glyph names (which + * many recent OpenType fonts do not). + */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + + /************************************************************************** + * + * @function: + * FT_Get_Postscript_Name + * + * @description: + * Retrieve the ASCII PostScript name of a given face, if available. + * This only works with PostScript, TrueType, and OpenType fonts. + * + * @input: + * face :: + * A handle to the source face object. + * + * @return: + * A pointer to the face's PostScript name. `NULL` if unavailable. + * + * @note: + * The returned pointer is owned by the face and is destroyed with it. + * + * For variation fonts, this string changes if you select a different + * instance, and you have to call `FT_Get_PostScript_Name` again to + * retrieve it. FreeType follows Adobe TechNote #5902, 'Generating + * PostScript Names for Fonts Using OpenType Font Variations'. + * + * https://download.macromedia.com/pub/developer/opentype/tech-notes/5902.AdobePSNameGeneration.html + * + * [Since 2.9] Special PostScript names for named instances are only + * returned if the named instance is set with @FT_Set_Named_Instance (and + * the font has corresponding entries in its 'fvar' table or is the + * default named instance). If @FT_IS_VARIATION returns true, the + * algorithmically derived PostScript name is provided, not looking up + * special entries for named instances. + */ + FT_EXPORT( const char* ) + FT_Get_Postscript_Name( FT_Face face ); + + + /************************************************************************** + * + * @enum: + * FT_SUBGLYPH_FLAG_XXX + * + * @description: + * A list of constants describing subglyphs. Please refer to the 'glyf' + * table description in the OpenType specification for the meaning of the + * various flags (which get synthesized for non-OpenType subglyphs). + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * + * @values: + * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: + * FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES :: + * FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID :: + * FT_SUBGLYPH_FLAG_SCALE :: + * FT_SUBGLYPH_FLAG_XY_SCALE :: + * FT_SUBGLYPH_FLAG_2X2 :: + * FT_SUBGLYPH_FLAG_USE_MY_METRICS :: + * + */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 + + + /************************************************************************** + * + * @function: + * FT_Get_SubGlyph_Info + * + * @description: + * Retrieve a description of a given subglyph. Only use it if + * `glyph->format` is @FT_GLYPH_FORMAT_COMPOSITE; an error is returned + * otherwise. + * + * @input: + * glyph :: + * The source glyph slot. + * + * sub_index :: + * The index of the subglyph. Must be less than + * `glyph->num_subglyphs`. + * + * @output: + * p_index :: + * The glyph index of the subglyph. + * + * p_flags :: + * The subglyph flags, see @FT_SUBGLYPH_FLAG_XXX. + * + * p_arg1 :: + * The subglyph's first argument (if any). + * + * p_arg2 :: + * The subglyph's second argument (if any). + * + * p_transform :: + * The subglyph transformation (if any). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The values of `*p_arg1`, `*p_arg2`, and `*p_transform` must be + * interpreted depending on the flags returned in `*p_flags`. See the + * OpenType specification for details. + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * + */ + FT_EXPORT( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ); + + + /************************************************************************** + * + * @enum: + * FT_FSTYPE_XXX + * + * @description: + * A list of bit flags used in the `fsType` field of the OS/2 table in a + * TrueType or OpenType font and the `FSType` entry in a PostScript font. + * These bit flags are returned by @FT_Get_FSType_Flags; they inform + * client applications of embedding and subsetting restrictions + * associated with a font. + * + * See + * https://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/FontPolicies.pdf + * for more details. + * + * @values: + * FT_FSTYPE_INSTALLABLE_EMBEDDING :: + * Fonts with no fsType bit set may be embedded and permanently + * installed on the remote system by an application. + * + * FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING :: + * Fonts that have only this bit set must not be modified, embedded or + * exchanged in any manner without first obtaining permission of the + * font software copyright owner. + * + * FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING :: + * The font may be embedded and temporarily loaded on the remote + * system. Documents containing Preview & Print fonts must be opened + * 'read-only'; no edits can be applied to the document. + * + * FT_FSTYPE_EDITABLE_EMBEDDING :: + * The font may be embedded but must only be installed temporarily on + * other systems. In contrast to Preview & Print fonts, documents + * containing editable fonts may be opened for reading, editing is + * permitted, and changes may be saved. + * + * FT_FSTYPE_NO_SUBSETTING :: + * The font may not be subsetted prior to embedding. + * + * FT_FSTYPE_BITMAP_EMBEDDING_ONLY :: + * Only bitmaps contained in the font may be embedded; no outline data + * may be embedded. If there are no bitmaps available in the font, + * then the font is unembeddable. + * + * @note: + * The flags are ORed together, thus more than a single value can be + * returned. + * + * While the `fsType` flags can indicate that a font may be embedded, a + * license with the font vendor may be separately required to use the + * font in this way. + */ +#define FT_FSTYPE_INSTALLABLE_EMBEDDING 0x0000 +#define FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING 0x0002 +#define FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING 0x0004 +#define FT_FSTYPE_EDITABLE_EMBEDDING 0x0008 +#define FT_FSTYPE_NO_SUBSETTING 0x0100 +#define FT_FSTYPE_BITMAP_EMBEDDING_ONLY 0x0200 + + + /************************************************************************** + * + * @function: + * FT_Get_FSType_Flags + * + * @description: + * Return the `fsType` flags for a font. + * + * @input: + * face :: + * A handle to the source face object. + * + * @return: + * The `fsType` flags, see @FT_FSTYPE_XXX. + * + * @note: + * Use this function rather than directly reading the `fs_type` field in + * the @PS_FontInfoRec structure, which is only guaranteed to return the + * correct results for Type~1 fonts. + * + * @since: + * 2.3.8 + * + */ + FT_EXPORT( FT_UShort ) + FT_Get_FSType_Flags( FT_Face face ); + + + /************************************************************************** + * + * @section: + * glyph_variants + * + * @title: + * Unicode Variation Sequences + * + * @abstract: + * The FreeType~2 interface to Unicode Variation Sequences (UVS), using + * the SFNT cmap format~14. + * + * @description: + * Many characters, especially for CJK scripts, have variant forms. They + * are a sort of grey area somewhere between being totally irrelevant and + * semantically distinct; for this reason, the Unicode consortium decided + * to introduce Variation Sequences (VS), consisting of a Unicode base + * character and a variation selector instead of further extending the + * already huge number of characters. + * + * Unicode maintains two different sets, namely 'Standardized Variation + * Sequences' and registered 'Ideographic Variation Sequences' (IVS), + * collected in the 'Ideographic Variation Database' (IVD). + * + * https://unicode.org/Public/UCD/latest/ucd/StandardizedVariants.txt + * https://unicode.org/reports/tr37/ https://unicode.org/ivd/ + * + * To date (January 2017), the character with the most ideographic + * variations is U+9089, having 32 such IVS. + * + * Three Mongolian Variation Selectors have the values U+180B-U+180D; 256 + * generic Variation Selectors are encoded in the ranges U+FE00-U+FE0F + * and U+E0100-U+E01EF. IVS currently use Variation Selectors from the + * range U+E0100-U+E01EF only. + * + * A VS consists of the base character value followed by a single + * Variation Selector. For example, to get the first variation of + * U+9089, you have to write the character sequence `U+9089 U+E0100`. + * + * Adobe and MS decided to support both standardized and ideographic VS + * with a new cmap subtable (format~14). It is an odd subtable because + * it is not a mapping of input code points to glyphs, but contains lists + * of all variations supported by the font. + * + * A variation may be either 'default' or 'non-default' for a given font. + * A default variation is the one you will get for that code point if you + * look it up in the standard Unicode cmap. A non-default variation is a + * different glyph. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Face_GetCharVariantIndex + * + * @description: + * Return the glyph index of a given character code as modified by the + * variation selector. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character code point in Unicode. + * + * variantSelector :: + * The Unicode code point of the variation selector. + * + * @return: + * The glyph index. 0~means either 'undefined character code', or + * 'undefined selector code', or 'no variation selector cmap subtable', + * or 'current CharMap is not Unicode'. + * + * @note: + * If you use FreeType to manipulate the contents of font files directly, + * be aware that the glyph index returned by this function doesn't always + * correspond to the internal indices used within the file. This is done + * to ensure that value~0 always corresponds to the 'missing glyph'. + * + * This function is only meaningful if + * a) the font has a variation selector cmap sub table, and + * b) the current charmap has a Unicode encoding. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt ) + FT_Face_GetCharVariantIndex( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetCharVariantIsDefault + * + * @description: + * Check whether this variation of this Unicode character is the one to + * be found in the charmap. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character codepoint in Unicode. + * + * variantSelector :: + * The Unicode codepoint of the variation selector. + * + * @return: + * 1~if found in the standard (Unicode) cmap, 0~if found in the variation + * selector cmap, or -1 if it is not a variation. + * + * @note: + * This function is only meaningful if the font has a variation selector + * cmap subtable. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_Int ) + FT_Face_GetCharVariantIsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetVariantSelectors + * + * @description: + * Return a zero-terminated list of Unicode variation selectors found in + * the font. + * + * @input: + * face :: + * A handle to the source face object. + * + * @return: + * A pointer to an array of selector code points, or `NULL` if there is + * no valid variation selector cmap subtable. + * + * @note: + * The last item in the array is~0; the array is owned by the @FT_Face + * object but can be overwritten or released on the next call to a + * FreeType function. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantSelectors( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetVariantsOfChar + * + * @description: + * Return a zero-terminated list of Unicode variation selectors found for + * the specified character code. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character codepoint in Unicode. + * + * @return: + * A pointer to an array of variation selector code points that are + * active for the given character, or `NULL` if the corresponding list is + * empty. + * + * @note: + * The last item in the array is~0; the array is owned by the @FT_Face + * object but can be overwritten or released on the next call to a + * FreeType function. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantsOfChar( FT_Face face, + FT_ULong charcode ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetCharsOfVariant + * + * @description: + * Return a zero-terminated list of Unicode character codes found for the + * specified variation selector. + * + * @input: + * face :: + * A handle to the source face object. + * + * variantSelector :: + * The variation selector code point in Unicode. + * + * @return: + * A list of all the code points that are specified by this selector + * (both default and non-default codes are returned) or `NULL` if there + * is no valid cmap or the variation selector is invalid. + * + * @note: + * The last item in the array is~0; the array is owned by the @FT_Face + * object but can be overwritten or released on the next call to a + * FreeType function. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetCharsOfVariant( FT_Face face, + FT_ULong variantSelector ); + + + /************************************************************************** + * + * @section: + * computations + * + * @title: + * Computations + * + * @abstract: + * Crunching fixed numbers and vectors. + * + * @description: + * This section contains various functions used to perform computations + * on 16.16 fixed-point numbers or 2D vectors. FreeType does not use + * floating-point data types. + * + * **Attention**: Most arithmetic functions take `FT_Long` as arguments. + * For historical reasons, FreeType was designed under the assumption + * that `FT_Long` is a 32-bit integer; results can thus be undefined if + * the arguments don't fit into 32 bits. + * + * @order: + * FT_MulDiv + * FT_MulFix + * FT_DivFix + * FT_RoundFix + * FT_CeilFix + * FT_FloorFix + * FT_Vector_Transform + * FT_Matrix_Multiply + * FT_Matrix_Invert + * + */ + + + /************************************************************************** + * + * @function: + * FT_MulDiv + * + * @description: + * Compute `(a*b)/c` with maximum accuracy, using a 64-bit intermediate + * integer whenever necessary. + * + * This function isn't necessarily as fast as some processor-specific + * operations, but is at least completely portable. + * + * @input: + * a :: + * The first multiplier. + * + * b :: + * The second multiplier. + * + * c :: + * The divisor. + * + * @return: + * The result of `(a*b)/c`. This function never traps when trying to + * divide by zero; it simply returns 'MaxInt' or 'MinInt' depending on + * the signs of `a` and `b`. + */ + FT_EXPORT( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ); + + + /************************************************************************** + * + * @function: + * FT_MulFix + * + * @description: + * Compute `(a*b)/0x10000` with maximum accuracy. Its main use is to + * multiply a given value by a 16.16 fixed-point factor. + * + * @input: + * a :: + * The first multiplier. + * + * b :: + * The second multiplier. Use a 16.16 factor here whenever possible + * (see note below). + * + * @return: + * The result of `(a*b)/0x10000`. + * + * @note: + * This function has been optimized for the case where the absolute value + * of `a` is less than 2048, and `b` is a 16.16 scaling factor. As this + * happens mainly when scaling from notional units to fractional pixels + * in FreeType, it resulted in noticeable speed improvements between + * versions 2.x and 1.x. + * + * As a conclusion, always try to place a 16.16 factor as the _second_ + * argument of this function; this can make a great difference. + */ + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); + + + /************************************************************************** + * + * @function: + * FT_DivFix + * + * @description: + * Compute `(a*0x10000)/b` with maximum accuracy. Its main use is to + * divide a given value by a 16.16 fixed-point factor. + * + * @input: + * a :: + * The numerator. + * + * b :: + * The denominator. Use a 16.16 factor here. + * + * @return: + * The result of `(a*0x10000)/b`. + */ + FT_EXPORT( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ); + + + /************************************************************************** + * + * @function: + * FT_RoundFix + * + * @description: + * Round a 16.16 fixed number. + * + * @input: + * a :: + * The number to be rounded. + * + * @return: + * `a` rounded to the nearest 16.16 fixed integer, halfway cases away + * from zero. + * + * @note: + * The function uses wrap-around arithmetic. + */ + FT_EXPORT( FT_Fixed ) + FT_RoundFix( FT_Fixed a ); + + + /************************************************************************** + * + * @function: + * FT_CeilFix + * + * @description: + * Compute the smallest following integer of a 16.16 fixed number. + * + * @input: + * a :: + * The number for which the ceiling function is to be computed. + * + * @return: + * `a` rounded towards plus infinity. + * + * @note: + * The function uses wrap-around arithmetic. + */ + FT_EXPORT( FT_Fixed ) + FT_CeilFix( FT_Fixed a ); + + + /************************************************************************** + * + * @function: + * FT_FloorFix + * + * @description: + * Compute the largest previous integer of a 16.16 fixed number. + * + * @input: + * a :: + * The number for which the floor function is to be computed. + * + * @return: + * `a` rounded towards minus infinity. + */ + FT_EXPORT( FT_Fixed ) + FT_FloorFix( FT_Fixed a ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Transform + * + * @description: + * Transform a single vector through a 2x2 matrix. + * + * @inout: + * vector :: + * The target vector to transform. + * + * @input: + * matrix :: + * A pointer to the source 2x2 matrix. + * + * @note: + * The result is undefined if either `vector` or `matrix` is invalid. + */ + FT_EXPORT( void ) + FT_Vector_Transform( FT_Vector* vector, + const FT_Matrix* matrix ); + + + /************************************************************************** + * + * @section: + * library_setup + * + */ + + /************************************************************************** + * + * @enum: + * FREETYPE_XXX + * + * @description: + * These three macros identify the FreeType source code version. Use + * @FT_Library_Version to access them at runtime. + * + * @values: + * FREETYPE_MAJOR :: + * The major version number. + * FREETYPE_MINOR :: + * The minor version number. + * FREETYPE_PATCH :: + * The patch level. + * + * @note: + * The version number of FreeType if built as a dynamic link library with + * the 'libtool' package is _not_ controlled by these three macros. + * + */ +#define FREETYPE_MAJOR 2 +#define FREETYPE_MINOR 13 +#define FREETYPE_PATCH 2 + + + /************************************************************************** + * + * @function: + * FT_Library_Version + * + * @description: + * Return the version of the FreeType library being used. This is useful + * when dynamically linking to the library, since one cannot use the + * macros @FREETYPE_MAJOR, @FREETYPE_MINOR, and @FREETYPE_PATCH. + * + * @input: + * library :: + * A source library handle. + * + * @output: + * amajor :: + * The major version number. + * + * aminor :: + * The minor version number. + * + * apatch :: + * The patch version number. + * + * @note: + * The reason why this function takes a `library` argument is because + * certain programs implement library initialization in a custom way that + * doesn't use @FT_Init_FreeType. + * + * In such cases, the library version might not be available before the + * library object has been created. + */ + FT_EXPORT( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ); + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @function: + * FT_Face_CheckTrueTypePatents + * + * @description: + * Deprecated, does nothing. + * + * @input: + * face :: + * A face handle. + * + * @return: + * Always returns false. + * + * @note: + * Since May 2010, TrueType hinting is no longer patented. + * + * @since: + * 2.3.5 + * + */ + FT_EXPORT( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Face_SetUnpatentedHinting + * + * @description: + * Deprecated, does nothing. + * + * @input: + * face :: + * A face handle. + * + * value :: + * New boolean setting. + * + * @return: + * Always returns false. + * + * @note: + * Since May 2010, TrueType hinting is no longer patented. + * + * @since: + * 2.3.5 + * + */ + FT_EXPORT( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ); + + /* */ + + +FT_END_HEADER + +#endif /* FREETYPE_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftadvanc.h b/vendor/freetype/include/freetype/ftadvanc.h new file mode 100644 index 0000000..4560ded --- /dev/null +++ b/vendor/freetype/include/freetype/ftadvanc.h @@ -0,0 +1,188 @@ +/**************************************************************************** + * + * ftadvanc.h + * + * Quick computation of advance widths (specification only). + * + * Copyright (C) 2008-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTADVANC_H_ +#define FTADVANC_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * quick_advance + * + * @title: + * Quick retrieval of advance values + * + * @abstract: + * Retrieve horizontal and vertical advance values without processing + * glyph outlines, if possible. + * + * @description: + * This section contains functions to quickly extract advance values + * without handling glyph outlines, if possible. + * + * @order: + * FT_Get_Advance + * FT_Get_Advances + * + */ + + + /************************************************************************** + * + * @enum: + * FT_ADVANCE_FLAG_FAST_ONLY + * + * @description: + * A bit-flag to be OR-ed with the `flags` parameter of the + * @FT_Get_Advance and @FT_Get_Advances functions. + * + * If set, it indicates that you want these functions to fail if the + * corresponding hinting mode or font driver doesn't allow for very quick + * advance computation. + * + * Typically, glyphs that are either unscaled, unhinted, bitmapped, or + * light-hinted can have their advance width computed very quickly. + * + * Normal and bytecode hinted modes that require loading, scaling, and + * hinting of the glyph outline, are extremely slow by comparison. + */ +#define FT_ADVANCE_FLAG_FAST_ONLY 0x20000000L + + + /************************************************************************** + * + * @function: + * FT_Get_Advance + * + * @description: + * Retrieve the advance value of a given glyph outline in an @FT_Face. + * + * @input: + * face :: + * The source @FT_Face handle. + * + * gindex :: + * The glyph index. + * + * load_flags :: + * A set of bit flags similar to those used when calling + * @FT_Load_Glyph, used to determine what kind of advances you need. + * + * @output: + * padvance :: + * The advance value. If scaling is performed (based on the value of + * `load_flags`), the advance value is in 16.16 format. Otherwise, it + * is in font units. + * + * If @FT_LOAD_VERTICAL_LAYOUT is set, this is the vertical advance + * corresponding to a vertical layout. Otherwise, it is the horizontal + * advance in a horizontal layout. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and if + * the corresponding font backend doesn't have a quick way to retrieve + * the advances. + * + * A scaled advance is returned in 16.16 format but isn't transformed by + * the affine transformation specified by @FT_Set_Transform. + */ + FT_EXPORT( FT_Error ) + FT_Get_Advance( FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags, + FT_Fixed *padvance ); + + + /************************************************************************** + * + * @function: + * FT_Get_Advances + * + * @description: + * Retrieve the advance values of several glyph outlines in an @FT_Face. + * + * @input: + * face :: + * The source @FT_Face handle. + * + * start :: + * The first glyph index. + * + * count :: + * The number of advance values you want to retrieve. + * + * load_flags :: + * A set of bit flags similar to those used when calling + * @FT_Load_Glyph. + * + * @output: + * padvance :: + * The advance values. This array, to be provided by the caller, must + * contain at least `count` elements. + * + * If scaling is performed (based on the value of `load_flags`), the + * advance values are in 16.16 format. Otherwise, they are in font + * units. + * + * If @FT_LOAD_VERTICAL_LAYOUT is set, these are the vertical advances + * corresponding to a vertical layout. Otherwise, they are the + * horizontal advances in a horizontal layout. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and if + * the corresponding font backend doesn't have a quick way to retrieve + * the advances. + * + * Scaled advances are returned in 16.16 format but aren't transformed by + * the affine transformation specified by @FT_Set_Transform. + */ + FT_EXPORT( FT_Error ) + FT_Get_Advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed *padvances ); + + /* */ + + +FT_END_HEADER + +#endif /* FTADVANC_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftbbox.h b/vendor/freetype/include/freetype/ftbbox.h new file mode 100644 index 0000000..fc21740 --- /dev/null +++ b/vendor/freetype/include/freetype/ftbbox.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * + * ftbbox.h + * + * FreeType exact bbox computation (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component has a _single_ role: to compute exact outline bounding + * boxes. + * + * It is separated from the rest of the engine for various technical + * reasons. It may well be integrated in 'ftoutln' later. + * + */ + + +#ifndef FTBBOX_H_ +#define FTBBOX_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * outline_processing + * + */ + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_BBox + * + * @description: + * Compute the exact bounding box of an outline. This is slower than + * computing the control box. However, it uses an advanced algorithm + * that returns _very_ quickly when the two boxes coincide. Otherwise, + * the outline Bezier arcs are traversed to extract their extrema. + * + * @input: + * outline :: + * A pointer to the source outline. + * + * @output: + * abbox :: + * The outline's exact bounding box. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the font is tricky and the glyph has been loaded with + * @FT_LOAD_NO_SCALE, the resulting BBox is meaningless. To get + * reasonable values for the BBox it is necessary to load the glyph at a + * large ppem value (so that the hinting instructions can properly shift + * and scale the subglyphs), then extracting the BBox, which can be + * eventually converted back to font units. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ); + + /* */ + + +FT_END_HEADER + +#endif /* FTBBOX_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/vendor/freetype/include/freetype/ftbdf.h b/vendor/freetype/include/freetype/ftbdf.h new file mode 100644 index 0000000..e8ce643 --- /dev/null +++ b/vendor/freetype/include/freetype/ftbdf.h @@ -0,0 +1,212 @@ +/**************************************************************************** + * + * ftbdf.h + * + * FreeType API for accessing BDF-specific strings (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBDF_H_ +#define FTBDF_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * bdf_fonts + * + * @title: + * BDF and PCF Files + * + * @abstract: + * BDF and PCF specific API. + * + * @description: + * This section contains the declaration of functions specific to BDF and + * PCF fonts. + * + */ + + + /************************************************************************** + * + * @enum: + * BDF_PropertyType + * + * @description: + * A list of BDF property types. + * + * @values: + * BDF_PROPERTY_TYPE_NONE :: + * Value~0 is used to indicate a missing property. + * + * BDF_PROPERTY_TYPE_ATOM :: + * Property is a string atom. + * + * BDF_PROPERTY_TYPE_INTEGER :: + * Property is a 32-bit signed integer. + * + * BDF_PROPERTY_TYPE_CARDINAL :: + * Property is a 32-bit unsigned integer. + */ + typedef enum BDF_PropertyType_ + { + BDF_PROPERTY_TYPE_NONE = 0, + BDF_PROPERTY_TYPE_ATOM = 1, + BDF_PROPERTY_TYPE_INTEGER = 2, + BDF_PROPERTY_TYPE_CARDINAL = 3 + + } BDF_PropertyType; + + + /************************************************************************** + * + * @type: + * BDF_Property + * + * @description: + * A handle to a @BDF_PropertyRec structure to model a given BDF/PCF + * property. + */ + typedef struct BDF_PropertyRec_* BDF_Property; + + + /************************************************************************** + * + * @struct: + * BDF_PropertyRec + * + * @description: + * This structure models a given BDF/PCF property. + * + * @fields: + * type :: + * The property type. + * + * u.atom :: + * The atom string, if type is @BDF_PROPERTY_TYPE_ATOM. May be + * `NULL`, indicating an empty string. + * + * u.integer :: + * A signed integer, if type is @BDF_PROPERTY_TYPE_INTEGER. + * + * u.cardinal :: + * An unsigned integer, if type is @BDF_PROPERTY_TYPE_CARDINAL. + */ + typedef struct BDF_PropertyRec_ + { + BDF_PropertyType type; + union { + const char* atom; + FT_Int32 integer; + FT_UInt32 cardinal; + + } u; + + } BDF_PropertyRec; + + + /************************************************************************** + * + * @function: + * FT_Get_BDF_Charset_ID + * + * @description: + * Retrieve a BDF font character set identity, according to the BDF + * specification. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * acharset_encoding :: + * Charset encoding, as a C~string, owned by the face. + * + * acharset_registry :: + * Charset registry, as a C~string, owned by the face. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with BDF faces, returning an error otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + + /************************************************************************** + * + * @function: + * FT_Get_BDF_Property + * + * @description: + * Retrieve a BDF property from a BDF or PCF font file. + * + * @input: + * face :: + * A handle to the input face. + * + * name :: + * The property name. + * + * @output: + * aproperty :: + * The property. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function works with BDF _and_ PCF fonts. It returns an error + * otherwise. It also returns an error if the property is not in the + * font. + * + * A 'property' is a either key-value pair within the STARTPROPERTIES + * ... ENDPROPERTIES block of a BDF font or a key-value pair from the + * `info->props` array within a `FontRec` structure of a PCF font. + * + * Integer properties are always stored as 'signed' within PCF fonts; + * consequently, @BDF_PROPERTY_TYPE_CARDINAL is a possible return value + * for BDF fonts only. + * + * In case of error, `aproperty->type` is always set to + * @BDF_PROPERTY_TYPE_NONE. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + /* */ + +FT_END_HEADER + +#endif /* FTBDF_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftbitmap.h b/vendor/freetype/include/freetype/ftbitmap.h new file mode 100644 index 0000000..eb6b4b1 --- /dev/null +++ b/vendor/freetype/include/freetype/ftbitmap.h @@ -0,0 +1,329 @@ +/**************************************************************************** + * + * ftbitmap.h + * + * FreeType utility functions for bitmaps (specification). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBITMAP_H_ +#define FTBITMAP_H_ + + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * bitmap_handling + * + * @title: + * Bitmap Handling + * + * @abstract: + * Handling FT_Bitmap objects. + * + * @description: + * This section contains functions for handling @FT_Bitmap objects, + * automatically adjusting the target's bitmap buffer size as needed. + * + * Note that none of the functions changes the bitmap's 'flow' (as + * indicated by the sign of the `pitch` field in @FT_Bitmap). + * + * To set the flow, assign an appropriate positive or negative value to + * the `pitch` field of the target @FT_Bitmap object after calling + * @FT_Bitmap_Init but before calling any of the other functions + * described here. + */ + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Init + * + * @description: + * Initialize a pointer to an @FT_Bitmap structure. + * + * @inout: + * abitmap :: + * A pointer to the bitmap structure. + * + * @note: + * A deprecated name for the same function is `FT_Bitmap_New`. + */ + FT_EXPORT( void ) + FT_Bitmap_Init( FT_Bitmap *abitmap ); + + + /* deprecated */ + FT_EXPORT( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Copy + * + * @description: + * Copy a bitmap into another one. + * + * @input: + * library :: + * A handle to a library object. + * + * source :: + * A handle to the source bitmap. + * + * @output: + * target :: + * A handle to the target bitmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * `source->buffer` and `target->buffer` must neither be equal nor + * overlap. + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Embolden + * + * @description: + * Embolden a bitmap. The new bitmap will be about `xStrength` pixels + * wider and `yStrength` pixels higher. The left and bottom borders are + * kept unchanged. + * + * @input: + * library :: + * A handle to a library object. + * + * xStrength :: + * How strong the glyph is emboldened horizontally. Expressed in 26.6 + * pixel format. + * + * yStrength :: + * How strong the glyph is emboldened vertically. Expressed in 26.6 + * pixel format. + * + * @inout: + * bitmap :: + * A handle to the target bitmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The current implementation restricts `xStrength` to be less than or + * equal to~8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. + * + * If you want to embolden the bitmap owned by a @FT_GlyphSlotRec, you + * should call @FT_GlyphSlot_Own_Bitmap on the slot first. + * + * Bitmaps in @FT_PIXEL_MODE_GRAY2 and @FT_PIXEL_MODE_GRAY@ format are + * converted to @FT_PIXEL_MODE_GRAY format (i.e., 8bpp). + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Convert + * + * @description: + * Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, 8bpp or 32bpp to + * a bitmap object with depth 8bpp, making the number of used bytes per + * line (a.k.a. the 'pitch') a multiple of `alignment`. + * + * @input: + * library :: + * A handle to a library object. + * + * source :: + * The source bitmap. + * + * alignment :: + * The pitch of the bitmap is a multiple of this argument. Common + * values are 1, 2, or 4. + * + * @output: + * target :: + * The target bitmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * It is possible to call @FT_Bitmap_Convert multiple times without + * calling @FT_Bitmap_Done (the memory is simply reallocated). + * + * Use @FT_Bitmap_Done to finally remove the bitmap object. + * + * The `library` argument is taken to have access to FreeType's memory + * handling functions. + * + * `source->buffer` and `target->buffer` must neither be equal nor + * overlap. + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Blend + * + * @description: + * Blend a bitmap onto another bitmap, using a given color. + * + * @input: + * library :: + * A handle to a library object. + * + * source :: + * The source bitmap, which can have any @FT_Pixel_Mode format. + * + * source_offset :: + * The offset vector to the upper left corner of the source bitmap in + * 26.6 pixel format. It should represent an integer offset; the + * function will set the lowest six bits to zero to enforce that. + * + * color :: + * The color used to draw `source` onto `target`. + * + * @inout: + * target :: + * A handle to an `FT_Bitmap` object. It should be either initialized + * as empty with a call to @FT_Bitmap_Init, or it should be of type + * @FT_PIXEL_MODE_BGRA. + * + * atarget_offset :: + * The offset vector to the upper left corner of the target bitmap in + * 26.6 pixel format. It should represent an integer offset; the + * function will set the lowest six bits to zero to enforce that. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function doesn't perform clipping. + * + * The bitmap in `target` gets allocated or reallocated as needed; the + * vector `atarget_offset` is updated accordingly. + * + * In case of allocation or reallocation, the bitmap's pitch is set to + * `4 * width`. Both `source` and `target` must have the same bitmap + * flow (as indicated by the sign of the `pitch` field). + * + * `source->buffer` and `target->buffer` must neither be equal nor + * overlap. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Blend( FT_Library library, + const FT_Bitmap* source, + const FT_Vector source_offset, + FT_Bitmap* target, + FT_Vector *atarget_offset, + FT_Color color ); + + + /************************************************************************** + * + * @function: + * FT_GlyphSlot_Own_Bitmap + * + * @description: + * Make sure that a glyph slot owns `slot->bitmap`. + * + * @input: + * slot :: + * The glyph slot. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function is to be used in combination with @FT_Bitmap_Embolden. + */ + FT_EXPORT( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Done + * + * @description: + * Destroy a bitmap object initialized with @FT_Bitmap_Init. + * + * @input: + * library :: + * A handle to a library object. + * + * bitmap :: + * The bitmap object to be freed. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `library` argument is taken to have access to FreeType's memory + * handling functions. + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTBITMAP_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftbzip2.h b/vendor/freetype/include/freetype/ftbzip2.h new file mode 100644 index 0000000..7d29f46 --- /dev/null +++ b/vendor/freetype/include/freetype/ftbzip2.h @@ -0,0 +1,102 @@ +/**************************************************************************** + * + * ftbzip2.h + * + * Bzip2-compressed stream support. + * + * Copyright (C) 2010-2023 by + * Joel Klinghed. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBZIP2_H_ +#define FTBZIP2_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * bzip2 + * + * @title: + * BZIP2 Streams + * + * @abstract: + * Using bzip2-compressed font files. + * + * @description: + * In certain builds of the library, bzip2 compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a bzip2 compressed + * stream from it and re-open the face with it. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * + * This section contains the declaration of Bzip2-specific functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Stream_OpenBzip2 + * + * @description: + * Open a new stream to parse bzip2-compressed font files. This is + * mainly used to support the compressed `*.pcf.bz2` fonts that come with + * XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close` on the new stream will + * **not** call `FT_Stream_Close` on the source stream. None of the + * stream objects will be released to the heap. + * + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with bzip2 support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* FTBZIP2_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftcache.h b/vendor/freetype/include/freetype/ftcache.h new file mode 100644 index 0000000..a2072e2 --- /dev/null +++ b/vendor/freetype/include/freetype/ftcache.h @@ -0,0 +1,1087 @@ +/**************************************************************************** + * + * ftcache.h + * + * FreeType Cache subsystem (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCACHE_H_ +#define FTCACHE_H_ + + +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * cache_subsystem + * + * @title: + * Cache Sub-System + * + * @abstract: + * How to cache face, size, and glyph data with FreeType~2. + * + * @description: + * This section describes the FreeType~2 cache sub-system, which is used + * to limit the number of concurrently opened @FT_Face and @FT_Size + * objects, as well as caching information like character maps and glyph + * images while limiting their maximum memory usage. + * + * Note that all types and functions begin with the `FTC_` prefix rather + * than the usual `FT_` prefix in the rest of FreeType. + * + * The cache is highly portable and, thus, doesn't know anything about + * the fonts installed on your system, or how to access them. Therefore, + * it requires the following. + * + * * @FTC_FaceID, an arbitrary non-zero value that uniquely identifies + * available or installed font faces, has to be provided to the + * cache by the client. Note that the cache only stores and compares + * these values and doesn't try to interpret them in any way, but they + * have to be persistent on the client side. + * + * * @FTC_Face_Requester, a method to convert an @FTC_FaceID into a new + * @FT_Face object when necessary, has to be provided to the cache by + * the client. The @FT_Face object is completely managed by the cache, + * including its termination through @FT_Done_Face. To monitor + * termination of face objects, the finalizer callback in the `generic` + * field of the @FT_Face object can be used, which might also be used + * to store the @FTC_FaceID of the face. + * + * Clients are free to map face IDs to anything useful. The most simple + * usage is, for example, to associate them to a `{pathname,face_index}` + * pair that is then used by @FTC_Face_Requester to call @FT_New_Face. + * However, more complex schemes are also possible. + * + * Note that for the cache to work correctly, the face ID values must be + * **persistent**, which means that the contents they point to should not + * change at runtime, or that their value should not become invalid. + * If this is unavoidable (e.g., when a font is uninstalled at runtime), + * you should call @FTC_Manager_RemoveFaceID as soon as possible to let + * the cache get rid of any references to the old @FTC_FaceID it may keep + * internally. Failure to do so will lead to incorrect behaviour or even + * crashes in @FTC_Face_Requester. + * + * To use the cache, start with calling @FTC_Manager_New to create a new + * @FTC_Manager object, which models a single cache instance. You can + * then look up @FT_Face and @FT_Size objects with + * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively, and + * use them in any FreeType work stream. You can also cache other + * FreeType objects as follows. + * + * * If you want to use the charmap caching, call @FTC_CMapCache_New, + * then later use @FTC_CMapCache_Lookup to perform the equivalent of + * @FT_Get_Char_Index, only much faster. + * + * * If you want to use the @FT_Glyph caching, call @FTC_ImageCache_New, + * then later use @FTC_ImageCache_Lookup to retrieve the corresponding + * @FT_Glyph objects from the cache. + * + * * If you need lots of small bitmaps, it is much more memory-efficient + * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This + * returns @FTC_SBitRec structures, which are used to store small + * bitmaps directly. (A small bitmap is one whose metrics and + * dimensions all fit into 8-bit integers). + * + * @order: + * FTC_Manager + * FTC_FaceID + * FTC_Face_Requester + * + * FTC_Manager_New + * FTC_Manager_Reset + * FTC_Manager_Done + * FTC_Manager_LookupFace + * FTC_Manager_LookupSize + * FTC_Manager_RemoveFaceID + * + * FTC_Node + * FTC_Node_Unref + * + * FTC_ImageCache + * FTC_ImageCache_New + * FTC_ImageCache_Lookup + * + * FTC_SBit + * FTC_SBitCache + * FTC_SBitCache_New + * FTC_SBitCache_Lookup + * + * FTC_CMapCache + * FTC_CMapCache_New + * FTC_CMapCache_Lookup + * + *************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC TYPE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @type: + * FTC_FaceID + * + * @description: + * An opaque pointer type that is used to identity face objects. The + * contents of such objects is application-dependent. + * + * These pointers are typically used to point to a user-defined structure + * containing a font file path, and face index. + * + * @note: + * Never use `NULL` as a valid @FTC_FaceID. + * + * Face IDs are passed by the client to the cache manager that calls, + * when needed, the @FTC_Face_Requester to translate them into new + * @FT_Face objects. + * + * If the content of a given face ID changes at runtime, or if the value + * becomes invalid (e.g., when uninstalling a font), you should + * immediately call @FTC_Manager_RemoveFaceID before any other cache + * function. + * + * Failure to do so will result in incorrect behaviour or even memory + * leaks and crashes. + */ + typedef FT_Pointer FTC_FaceID; + + + /************************************************************************** + * + * @functype: + * FTC_Face_Requester + * + * @description: + * A callback function provided by client applications. It is used by + * the cache manager to translate a given @FTC_FaceID into a new valid + * @FT_Face object, on demand. + * + * @input: + * face_id :: + * The face ID to resolve. + * + * library :: + * A handle to a FreeType library object. + * + * req_data :: + * Application-provided request data (see note below). + * + * @output: + * aface :: + * A new @FT_Face handle. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The third parameter `req_data` is the same as the one passed by the + * client when @FTC_Manager_New is called. + * + * The face requester should not perform funny things on the returned + * face object, like creating a new @FT_Size for it, or setting a + * transformation through @FT_Set_Transform! + */ + typedef FT_Error + (*FTC_Face_Requester)( FTC_FaceID face_id, + FT_Library library, + FT_Pointer req_data, + FT_Face* aface ); + + /* */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @type: + * FTC_Manager + * + * @description: + * This object corresponds to one instance of the cache-subsystem. It is + * used to cache one or more @FT_Face objects, along with corresponding + * @FT_Size objects. + * + * The manager intentionally limits the total number of opened @FT_Face + * and @FT_Size objects to control memory usage. See the `max_faces` and + * `max_sizes` parameters of @FTC_Manager_New. + * + * The manager is also used to cache 'nodes' of various types while + * limiting their total memory usage. + * + * All limitations are enforced by keeping lists of managed objects in + * most-recently-used order, and flushing old nodes to make room for new + * ones. + */ + typedef struct FTC_ManagerRec_* FTC_Manager; + + + /************************************************************************** + * + * @type: + * FTC_Node + * + * @description: + * An opaque handle to a cache node object. Each cache node is + * reference-counted. A node with a count of~0 might be flushed out of a + * full cache whenever a lookup request is performed. + * + * If you look up nodes, you have the ability to 'acquire' them, i.e., to + * increment their reference count. This will prevent the node from + * being flushed out of the cache until you explicitly 'release' it (see + * @FTC_Node_Unref). + * + * See also @FTC_SBitCache_Lookup and @FTC_ImageCache_Lookup. + */ + typedef struct FTC_NodeRec_* FTC_Node; + + + /************************************************************************** + * + * @function: + * FTC_Manager_New + * + * @description: + * Create a new cache manager. + * + * @input: + * library :: + * The parent FreeType library handle to use. + * + * max_faces :: + * Maximum number of opened @FT_Face objects managed by this cache + * instance. Use~0 for defaults. + * + * max_sizes :: + * Maximum number of opened @FT_Size objects managed by this cache + * instance. Use~0 for defaults. + * + * max_bytes :: + * Maximum number of bytes to use for cached data nodes. Use~0 for + * defaults. Note that this value does not account for managed + * @FT_Face and @FT_Size objects. + * + * requester :: + * An application-provided callback used to translate face IDs into + * real @FT_Face objects. + * + * req_data :: + * A generic pointer that is passed to the requester each time it is + * called (see @FTC_Face_Requester). + * + * @output: + * amanager :: + * A handle to a new manager object. 0~in case of failure. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_Reset + * + * @description: + * Empty a given cache manager. This simply gets rid of all the + * currently cached @FT_Face and @FT_Size objects within the manager. + * + * @inout: + * manager :: + * A handle to the manager. + */ + FT_EXPORT( void ) + FTC_Manager_Reset( FTC_Manager manager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_Done + * + * @description: + * Destroy a given manager after emptying it. + * + * @input: + * manager :: + * A handle to the target cache manager object. + */ + FT_EXPORT( void ) + FTC_Manager_Done( FTC_Manager manager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_LookupFace + * + * @description: + * Retrieve the @FT_Face object that corresponds to a given face ID + * through a cache manager. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * face_id :: + * The ID of the face object. + * + * @output: + * aface :: + * A handle to the face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned @FT_Face object is always owned by the manager. You + * should never try to discard it yourself. + * + * The @FT_Face object doesn't necessarily have a current size object + * (i.e., face->size can be~0). If you need a specific 'font size', use + * @FTC_Manager_LookupSize instead. + * + * Never change the face's transformation matrix (i.e., never call the + * @FT_Set_Transform function) on a returned face! If you need to + * transform glyphs, do it yourself after glyph loading. + * + * When you perform a lookup, out-of-memory errors are detected _within_ + * the lookup and force incremental flushes of the cache until enough + * memory is released for the lookup to succeed. + * + * If a lookup fails with `FT_Err_Out_Of_Memory` the cache has already + * been completely flushed, and still no memory was available for the + * operation. + */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + + /************************************************************************** + * + * @struct: + * FTC_ScalerRec + * + * @description: + * A structure used to describe a given character size in either pixels + * or points to the cache manager. See @FTC_Manager_LookupSize. + * + * @fields: + * face_id :: + * The source face ID. + * + * width :: + * The character width. + * + * height :: + * The character height. + * + * pixel :: + * A Boolean. If 1, the `width` and `height` fields are interpreted as + * integer pixel character sizes. Otherwise, they are expressed as + * 1/64 of points. + * + * x_res :: + * Only used when `pixel` is value~0 to indicate the horizontal + * resolution in dpi. + * + * y_res :: + * Only used when `pixel` is value~0 to indicate the vertical + * resolution in dpi. + * + * @note: + * This type is mainly used to retrieve @FT_Size objects through the + * cache manager. + */ + typedef struct FTC_ScalerRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int pixel; + FT_UInt x_res; + FT_UInt y_res; + + } FTC_ScalerRec; + + + /************************************************************************** + * + * @struct: + * FTC_Scaler + * + * @description: + * A handle to an @FTC_ScalerRec structure. + */ + typedef struct FTC_ScalerRec_* FTC_Scaler; + + + /************************************************************************** + * + * @function: + * FTC_Manager_LookupSize + * + * @description: + * Retrieve the @FT_Size object that corresponds to a given + * @FTC_ScalerRec pointer through a cache manager. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * scaler :: + * A scaler handle. + * + * @output: + * asize :: + * A handle to the size object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned @FT_Size object is always owned by the manager. You + * should never try to discard it by yourself. + * + * You can access the parent @FT_Face object simply as `size->face` if + * you need it. Note that this object is also owned by the manager. + * + * @note: + * When you perform a lookup, out-of-memory errors are detected _within_ + * the lookup and force incremental flushes of the cache until enough + * memory is released for the lookup to succeed. + * + * If a lookup fails with `FT_Err_Out_Of_Memory` the cache has already + * been completely flushed, and still no memory is available for the + * operation. + */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ); + + + /************************************************************************** + * + * @function: + * FTC_Node_Unref + * + * @description: + * Decrement a cache node's internal reference count. When the count + * reaches 0, it is not destroyed but becomes eligible for subsequent + * cache flushes. + * + * @input: + * node :: + * The cache node handle. + * + * manager :: + * The cache manager handle. + */ + FT_EXPORT( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_RemoveFaceID + * + * @description: + * A special function used to indicate to the cache manager that a given + * @FTC_FaceID is no longer valid, either because its content changed, or + * because it was deallocated or uninstalled. + * + * @input: + * manager :: + * The cache manager handle. + * + * face_id :: + * The @FTC_FaceID to be removed. + * + * @note: + * This function flushes all nodes from the cache corresponding to this + * `face_id`, with the exception of nodes with a non-null reference + * count. + * + * Such nodes are however modified internally so as to never appear in + * later lookups with the same `face_id` value, and to be immediately + * destroyed when released by all their users. + * + */ + FT_EXPORT( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ); + + + /************************************************************************** + * + * @type: + * FTC_CMapCache + * + * @description: + * An opaque handle used to model a charmap cache. This cache is to hold + * character codes -> glyph indices mappings. + * + */ + typedef struct FTC_CMapCacheRec_* FTC_CMapCache; + + + /************************************************************************** + * + * @function: + * FTC_CMapCache_New + * + * @description: + * Create a new charmap cache. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * @output: + * acache :: + * A new cache handle. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Like all other caches, this one will be destroyed with the cache + * manager. + * + */ + FT_EXPORT( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ); + + + /************************************************************************** + * + * @function: + * FTC_CMapCache_Lookup + * + * @description: + * Translate a character code into a glyph index, using the charmap + * cache. + * + * @input: + * cache :: + * A charmap cache handle. + * + * face_id :: + * The source face ID. + * + * cmap_index :: + * The index of the charmap in the source face. Any negative value + * means to use the cache @FT_Face's default charmap. + * + * char_code :: + * The character code (in the corresponding charmap). + * + * @return: + * Glyph index. 0~means 'no glyph'. + * + */ + FT_EXPORT( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMAGE CACHE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * FTC_ImageTypeRec + * + * @description: + * A structure used to model the type of images in a glyph cache. + * + * @fields: + * face_id :: + * The face ID. + * + * width :: + * The width in pixels. + * + * height :: + * The height in pixels. + * + * flags :: + * The load flags, as in @FT_Load_Glyph. + * + */ + typedef struct FTC_ImageTypeRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int32 flags; + + } FTC_ImageTypeRec; + + + /************************************************************************** + * + * @type: + * FTC_ImageType + * + * @description: + * A handle to an @FTC_ImageTypeRec structure. + * + */ + typedef struct FTC_ImageTypeRec_* FTC_ImageType; + + + /* */ + + +#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \ + ( (d1)->face_id == (d2)->face_id && \ + (d1)->width == (d2)->width && \ + (d1)->flags == (d2)->flags ) + + + /************************************************************************** + * + * @type: + * FTC_ImageCache + * + * @description: + * A handle to a glyph image cache object. They are designed to hold + * many distinct glyph images while not exceeding a certain memory + * threshold. + */ + typedef struct FTC_ImageCacheRec_* FTC_ImageCache; + + + /************************************************************************** + * + * @function: + * FTC_ImageCache_New + * + * @description: + * Create a new glyph image cache. + * + * @input: + * manager :: + * The parent manager for the image cache. + * + * @output: + * acache :: + * A handle to the new glyph image cache object. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ); + + + /************************************************************************** + * + * @function: + * FTC_ImageCache_Lookup + * + * @description: + * Retrieve a given glyph image from a glyph image cache. + * + * @input: + * cache :: + * A handle to the source glyph image cache. + * + * type :: + * A pointer to a glyph image type descriptor. + * + * gindex :: + * The glyph index to retrieve. + * + * @output: + * aglyph :: + * The corresponding @FT_Glyph object. 0~in case of failure. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned glyph is owned and managed by the glyph image cache. + * Never try to transform or discard it manually! You can however create + * a copy with @FT_Glyph_Copy and modify the new one. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the glyph image, after increasing its reference count. + * This ensures that the node (as well as the @FT_Glyph) will always be + * kept in the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the @FT_Glyph could be flushed out of the cache on the next call + * to one of the caching sub-system APIs. Don't assume that it is + * persistent! + */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /************************************************************************** + * + * @function: + * FTC_ImageCache_LookupScaler + * + * @description: + * A variant of @FTC_ImageCache_Lookup that uses an @FTC_ScalerRec to + * specify the face ID and its size. + * + * @input: + * cache :: + * A handle to the source glyph image cache. + * + * scaler :: + * A pointer to a scaler descriptor. + * + * load_flags :: + * The corresponding load flags. + * + * gindex :: + * The glyph index to retrieve. + * + * @output: + * aglyph :: + * The corresponding @FT_Glyph object. 0~in case of failure. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned glyph is owned and managed by the glyph image cache. + * Never try to transform or discard it manually! You can however create + * a copy with @FT_Glyph_Copy and modify the new one. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the glyph image, after increasing its reference count. + * This ensures that the node (as well as the @FT_Glyph) will always be + * kept in the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the @FT_Glyph could be flushed out of the cache on the next call + * to one of the caching sub-system APIs. Don't assume that it is + * persistent! + * + * Calls to @FT_Set_Char_Size and friends have no effect on cached + * glyphs; you should always use the FreeType cache API instead. + */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /************************************************************************** + * + * @type: + * FTC_SBit + * + * @description: + * A handle to a small bitmap descriptor. See the @FTC_SBitRec structure + * for details. + */ + typedef struct FTC_SBitRec_* FTC_SBit; + + + /************************************************************************** + * + * @struct: + * FTC_SBitRec + * + * @description: + * A very compact structure used to describe a small glyph bitmap. + * + * @fields: + * width :: + * The bitmap width in pixels. + * + * height :: + * The bitmap height in pixels. + * + * left :: + * The horizontal distance from the pen position to the left bitmap + * border (a.k.a. 'left side bearing', or 'lsb'). + * + * top :: + * The vertical distance from the pen position (on the baseline) to the + * upper bitmap border (a.k.a. 'top side bearing'). The distance is + * positive for upwards y~coordinates. + * + * format :: + * The format of the glyph bitmap (monochrome or gray). + * + * max_grays :: + * Maximum gray level value (in the range 1 to~255). + * + * pitch :: + * The number of bytes per bitmap line. May be positive or negative. + * + * xadvance :: + * The horizontal advance width in pixels. + * + * yadvance :: + * The vertical advance height in pixels. + * + * buffer :: + * A pointer to the bitmap pixels. + */ + typedef struct FTC_SBitRec_ + { + FT_Byte width; + FT_Byte height; + FT_Char left; + FT_Char top; + + FT_Byte format; + FT_Byte max_grays; + FT_Short pitch; + FT_Char xadvance; + FT_Char yadvance; + + FT_Byte* buffer; + + } FTC_SBitRec; + + + /************************************************************************** + * + * @type: + * FTC_SBitCache + * + * @description: + * A handle to a small bitmap cache. These are special cache objects + * used to store small glyph bitmaps (and anti-aliased pixmaps) in a much + * more efficient way than the traditional glyph image cache implemented + * by @FTC_ImageCache. + */ + typedef struct FTC_SBitCacheRec_* FTC_SBitCache; + + + /************************************************************************** + * + * @function: + * FTC_SBitCache_New + * + * @description: + * Create a new cache to store small glyph bitmaps. + * + * @input: + * manager :: + * A handle to the source cache manager. + * + * @output: + * acache :: + * A handle to the new sbit cache. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ); + + + /************************************************************************** + * + * @function: + * FTC_SBitCache_Lookup + * + * @description: + * Look up a given small glyph bitmap in a given sbit cache and 'lock' it + * to prevent its flushing from the cache until needed. + * + * @input: + * cache :: + * A handle to the source sbit cache. + * + * type :: + * A pointer to the glyph image type descriptor. + * + * gindex :: + * The glyph index. + * + * @output: + * sbit :: + * A handle to a small bitmap descriptor. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The small bitmap descriptor and its bit buffer are owned by the cache + * and should never be freed by the application. They might as well + * disappear from memory on the next cache lookup, so don't treat them as + * persistent data. + * + * The descriptor's `buffer` field is set to~0 to indicate a missing + * glyph bitmap. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the bitmap, after increasing its reference count. This + * ensures that the node (as well as the image) will always be kept in + * the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the bitmap could be flushed out of the cache on the next call to + * one of the caching sub-system APIs. Don't assume that it is + * persistent! + */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /************************************************************************** + * + * @function: + * FTC_SBitCache_LookupScaler + * + * @description: + * A variant of @FTC_SBitCache_Lookup that uses an @FTC_ScalerRec to + * specify the face ID and its size. + * + * @input: + * cache :: + * A handle to the source sbit cache. + * + * scaler :: + * A pointer to the scaler descriptor. + * + * load_flags :: + * The corresponding load flags. + * + * gindex :: + * The glyph index. + * + * @output: + * sbit :: + * A handle to a small bitmap descriptor. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The small bitmap descriptor and its bit buffer are owned by the cache + * and should never be freed by the application. They might as well + * disappear from memory on the next cache lookup, so don't treat them as + * persistent data. + * + * The descriptor's `buffer` field is set to~0 to indicate a missing + * glyph bitmap. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the bitmap, after increasing its reference count. This + * ensures that the node (as well as the image) will always be kept in + * the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the bitmap could be flushed out of the cache on the next call to + * one of the caching sub-system APIs. Don't assume that it is + * persistent! + */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + /* */ + + +FT_END_HEADER + +#endif /* FTCACHE_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftchapters.h b/vendor/freetype/include/freetype/ftchapters.h new file mode 100644 index 0000000..7566fbd --- /dev/null +++ b/vendor/freetype/include/freetype/ftchapters.h @@ -0,0 +1,168 @@ +/**************************************************************************** + * + * This file defines the structure of the FreeType reference. + * It is used by the python script that generates the HTML files. + * + */ + + + /************************************************************************** + * + * @chapter: + * general_remarks + * + * @title: + * General Remarks + * + * @sections: + * preamble + * header_inclusion + * user_allocation + * + */ + + + /************************************************************************** + * + * @chapter: + * core_api + * + * @title: + * Core API + * + * @sections: + * basic_types + * library_setup + * face_creation + * font_testing_macros + * sizing_and_scaling + * glyph_retrieval + * character_mapping + * information_retrieval + * other_api_data + * + */ + + + /************************************************************************** + * + * @chapter: + * extended_api + * + * @title: + * Extended API + * + * @sections: + * glyph_variants + * color_management + * layer_management + * glyph_management + * mac_specific + * sizes_management + * header_file_macros + * + */ + + + /************************************************************************** + * + * @chapter: + * format_specific + * + * @title: + * Format-Specific API + * + * @sections: + * multiple_masters + * truetype_tables + * type1_tables + * sfnt_names + * bdf_fonts + * cid_fonts + * pfr_fonts + * winfnt_fonts + * svg_fonts + * font_formats + * gasp_table + * + */ + + + /************************************************************************** + * + * @chapter: + * module_specific + * + * @title: + * Controlling FreeType Modules + * + * @sections: + * auto_hinter + * cff_driver + * t1_cid_driver + * tt_driver + * pcf_driver + * ot_svg_driver + * properties + * parameter_tags + * lcd_rendering + * + */ + + + /************************************************************************** + * + * @chapter: + * cache_subsystem + * + * @title: + * Cache Sub-System + * + * @sections: + * cache_subsystem + * + */ + + + /************************************************************************** + * + * @chapter: + * support_api + * + * @title: + * Support API + * + * @sections: + * computations + * list_processing + * outline_processing + * quick_advance + * bitmap_handling + * raster + * glyph_stroker + * system_interface + * module_management + * gzip + * lzw + * bzip2 + * debugging_apis + * + */ + + + /************************************************************************** + * + * @chapter: + * error_codes + * + * @title: + * Error Codes + * + * @sections: + * error_enumerations + * error_code_values + * + */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftcid.h b/vendor/freetype/include/freetype/ftcid.h new file mode 100644 index 0000000..ef22939 --- /dev/null +++ b/vendor/freetype/include/freetype/ftcid.h @@ -0,0 +1,167 @@ +/**************************************************************************** + * + * ftcid.h + * + * FreeType API for accessing CID font information (specification). + * + * Copyright (C) 2007-2023 by + * Dereg Clegg and Michael Toftdal. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCID_H_ +#define FTCID_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * cid_fonts + * + * @title: + * CID Fonts + * + * @abstract: + * CID-keyed font-specific API. + * + * @description: + * This section contains the declaration of CID-keyed font-specific + * functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Get_CID_Registry_Ordering_Supplement + * + * @description: + * Retrieve the Registry/Ordering/Supplement triple (also known as the + * "R/O/S") from a CID-keyed font. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * registry :: + * The registry, as a C~string, owned by the face. + * + * ordering :: + * The ordering, as a C~string, owned by the face. + * + * supplement :: + * The supplement. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces, returning an error + * otherwise. + * + * @since: + * 2.3.6 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Registry_Ordering_Supplement( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ); + + + /************************************************************************** + * + * @function: + * FT_Get_CID_Is_Internally_CID_Keyed + * + * @description: + * Retrieve the type of the input face, CID keyed or not. In contrast + * to the @FT_IS_CID_KEYED macro this function returns successfully also + * for CID-keyed fonts in an SFNT wrapper. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * is_cid :: + * The type of the face as an @FT_Bool. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, returning + * an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face, + FT_Bool *is_cid ); + + + /************************************************************************** + * + * @function: + * FT_Get_CID_From_Glyph_Index + * + * @description: + * Retrieve the CID of the input glyph index. + * + * @input: + * face :: + * A handle to the input face. + * + * glyph_index :: + * The input glyph index. + * + * @output: + * cid :: + * The CID as an @FT_UInt. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, returning + * an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_From_Glyph_Index( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); + + /* */ + + +FT_END_HEADER + +#endif /* FTCID_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftcolor.h b/vendor/freetype/include/freetype/ftcolor.h new file mode 100644 index 0000000..eae200f --- /dev/null +++ b/vendor/freetype/include/freetype/ftcolor.h @@ -0,0 +1,1667 @@ +/**************************************************************************** + * + * ftcolor.h + * + * FreeType's glyph color management (specification). + * + * Copyright (C) 2018-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCOLOR_H_ +#define FTCOLOR_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * color_management + * + * @title: + * Glyph Color Management + * + * @abstract: + * Retrieving and manipulating OpenType's 'CPAL' table data. + * + * @description: + * The functions described here allow access and manipulation of color + * palette entries in OpenType's 'CPAL' tables. + */ + + + /************************************************************************** + * + * @struct: + * FT_Color + * + * @description: + * This structure models a BGRA color value of a 'CPAL' palette entry. + * + * The used color space is sRGB; the colors are not pre-multiplied, and + * alpha values must be explicitly set. + * + * @fields: + * blue :: + * Blue value. + * + * green :: + * Green value. + * + * red :: + * Red value. + * + * alpha :: + * Alpha value, giving the red, green, and blue color's opacity. + * + * @since: + * 2.10 + */ + typedef struct FT_Color_ + { + FT_Byte blue; + FT_Byte green; + FT_Byte red; + FT_Byte alpha; + + } FT_Color; + + + /************************************************************************** + * + * @enum: + * FT_PALETTE_XXX + * + * @description: + * A list of bit field constants used in the `palette_flags` array of the + * @FT_Palette_Data structure to indicate for which background a palette + * with a given index is usable. + * + * @values: + * FT_PALETTE_FOR_LIGHT_BACKGROUND :: + * The palette is appropriate to use when displaying the font on a + * light background such as white. + * + * FT_PALETTE_FOR_DARK_BACKGROUND :: + * The palette is appropriate to use when displaying the font on a dark + * background such as black. + * + * @since: + * 2.10 + */ +#define FT_PALETTE_FOR_LIGHT_BACKGROUND 0x01 +#define FT_PALETTE_FOR_DARK_BACKGROUND 0x02 + + + /************************************************************************** + * + * @struct: + * FT_Palette_Data + * + * @description: + * This structure holds the data of the 'CPAL' table. + * + * @fields: + * num_palettes :: + * The number of palettes. + * + * palette_name_ids :: + * An optional read-only array of palette name IDs with `num_palettes` + * elements, corresponding to entries like 'dark' or 'light' in the + * font's 'name' table. + * + * An empty name ID in the 'CPAL' table gets represented as value + * 0xFFFF. + * + * `NULL` if the font's 'CPAL' table doesn't contain appropriate data. + * + * palette_flags :: + * An optional read-only array of palette flags with `num_palettes` + * elements. Possible values are an ORed combination of + * @FT_PALETTE_FOR_LIGHT_BACKGROUND and + * @FT_PALETTE_FOR_DARK_BACKGROUND. + * + * `NULL` if the font's 'CPAL' table doesn't contain appropriate data. + * + * num_palette_entries :: + * The number of entries in a single palette. All palettes have the + * same size. + * + * palette_entry_name_ids :: + * An optional read-only array of palette entry name IDs with + * `num_palette_entries`. In each palette, entries with the same index + * have the same function. For example, index~0 might correspond to + * string 'outline' in the font's 'name' table to indicate that this + * palette entry is used for outlines, index~1 might correspond to + * 'fill' to indicate the filling color palette entry, etc. + * + * An empty entry name ID in the 'CPAL' table gets represented as value + * 0xFFFF. + * + * `NULL` if the font's 'CPAL' table doesn't contain appropriate data. + * + * @note: + * Use function @FT_Get_Sfnt_Name to map name IDs and entry name IDs to + * name strings. + * + * Use function @FT_Palette_Select to get the colors associated with a + * palette entry. + * + * @since: + * 2.10 + */ + typedef struct FT_Palette_Data_ { + FT_UShort num_palettes; + const FT_UShort* palette_name_ids; + const FT_UShort* palette_flags; + + FT_UShort num_palette_entries; + const FT_UShort* palette_entry_name_ids; + + } FT_Palette_Data; + + + /************************************************************************** + * + * @function: + * FT_Palette_Data_Get + * + * @description: + * Retrieve the face's color palette data. + * + * @input: + * face :: + * The source face handle. + * + * @output: + * apalette :: + * A pointer to an @FT_Palette_Data structure. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * All arrays in the returned @FT_Palette_Data structure are read-only. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Data_Get( FT_Face face, + FT_Palette_Data *apalette ); + + + /************************************************************************** + * + * @function: + * FT_Palette_Select + * + * @description: + * This function has two purposes. + * + * (1) It activates a palette for rendering color glyphs, and + * + * (2) it retrieves all (unmodified) color entries of this palette. This + * function returns a read-write array, which means that a calling + * application can modify the palette entries on demand. + * + * A corollary of (2) is that calling the function, then modifying some + * values, then calling the function again with the same arguments resets + * all color entries to the original 'CPAL' values; all user modifications + * are lost. + * + * @input: + * face :: + * The source face handle. + * + * palette_index :: + * The palette index. + * + * @output: + * apalette :: + * An array of color entries for a palette with index `palette_index`, + * having `num_palette_entries` elements (as found in the + * `FT_Palette_Data` structure). If `apalette` is set to `NULL`, no + * array gets returned (and no color entries can be modified). + * + * In case the font doesn't support color palettes, `NULL` is returned. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The array pointed to by `apalette_entries` is owned and managed by + * FreeType. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Select( FT_Face face, + FT_UShort palette_index, + FT_Color* *apalette ); + + + /************************************************************************** + * + * @function: + * FT_Palette_Set_Foreground_Color + * + * @description: + * 'COLR' uses palette index 0xFFFF to indicate a 'text foreground + * color'. This function sets this value. + * + * @input: + * face :: + * The source face handle. + * + * foreground_color :: + * An `FT_Color` structure to define the text foreground color. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If this function isn't called, the text foreground color is set to + * white opaque (BGRA value 0xFFFFFFFF) if + * @FT_PALETTE_FOR_DARK_BACKGROUND is present for the current palette, + * and black opaque (BGRA value 0x000000FF) otherwise, including the case + * that no palette types are available in the 'CPAL' table. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Set_Foreground_Color( FT_Face face, + FT_Color foreground_color ); + + + /************************************************************************** + * + * @section: + * layer_management + * + * @title: + * Glyph Layer Management + * + * @abstract: + * Retrieving and manipulating OpenType's 'COLR' table data. + * + * @description: + * The functions described here allow access of colored glyph layer data + * in OpenType's 'COLR' tables. + */ + + + /************************************************************************** + * + * @struct: + * FT_LayerIterator + * + * @description: + * This iterator object is needed for @FT_Get_Color_Glyph_Layer. + * + * @fields: + * num_layers :: + * The number of glyph layers for the requested glyph index. Will be + * set by @FT_Get_Color_Glyph_Layer. + * + * layer :: + * The current layer. Will be set by @FT_Get_Color_Glyph_Layer. + * + * p :: + * An opaque pointer into 'COLR' table data. The caller must set this + * to `NULL` before the first call of @FT_Get_Color_Glyph_Layer. + */ + typedef struct FT_LayerIterator_ + { + FT_UInt num_layers; + FT_UInt layer; + FT_Byte* p; + + } FT_LayerIterator; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Layer + * + * @description: + * This is an interface to the 'COLR' table in OpenType fonts to + * iteratively retrieve the colored glyph layers associated with the + * current glyph slot. + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/colr + * + * The glyph layer data for a given glyph index, if present, provides an + * alternative, multi-color glyph representation: Instead of rendering + * the outline or bitmap with the given glyph index, glyphs with the + * indices and colors returned by this function are rendered layer by + * layer. + * + * The returned elements are ordered in the z~direction from bottom to + * top; the 'n'th element should be rendered with the associated palette + * color and blended on top of the already rendered layers (elements 0, + * 1, ..., n-1). + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @inout: + * iterator :: + * An @FT_LayerIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * aglyph_index :: + * The glyph index of the current layer. + * + * acolor_index :: + * The color index into the font face's color palette of the current + * layer. The value 0xFFFF is special; it doesn't reference a palette + * entry but indicates that the text foreground color should be used + * instead (to be set up by the application outside of FreeType). + * + * The color palette can be retrieved with @FT_Palette_Select. + * + * @return: + * Value~1 if everything is OK. If there are no more layers (or if there + * are no layers at all), value~0 gets returned. In case of an error, + * value~0 is returned also. + * + * @note: + * This function is necessary if you want to handle glyph layers by + * yourself. In particular, functions that operate with @FT_GlyphRec + * objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access + * to this information. + * + * Note that @FT_Render_Glyph is able to handle colored glyph layers + * automatically if the @FT_LOAD_COLOR flag is passed to a previous call + * to @FT_Load_Glyph. [This is an experimental feature.] + * + * @example: + * ``` + * FT_Color* palette; + * FT_LayerIterator iterator; + * + * FT_Bool have_layers; + * FT_UInt layer_glyph_index; + * FT_UInt layer_color_index; + * + * + * error = FT_Palette_Select( face, palette_index, &palette ); + * if ( error ) + * palette = NULL; + * + * iterator.p = NULL; + * have_layers = FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ); + * + * if ( palette && have_layers ) + * { + * do + * { + * FT_Color layer_color; + * + * + * if ( layer_color_index == 0xFFFF ) + * layer_color = text_foreground_color; + * else + * layer_color = palette[layer_color_index]; + * + * // Load and render glyph `layer_glyph_index', then + * // blend resulting pixmap (using color `layer_color') + * // with previously created pixmaps. + * + * } while ( FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ) ); + * } + * ``` + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Layer( FT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + + /************************************************************************** + * + * @enum: + * FT_PaintFormat + * + * @description: + * Enumeration describing the different paint format types of the v1 + * extensions to the 'COLR' table, see + * 'https://github.com/googlefonts/colr-gradients-spec'. + * + * The enumeration values loosely correspond with the format numbers of + * the specification: FreeType always returns a fully specified 'Paint' + * structure for the 'Transform', 'Translate', 'Scale', 'Rotate', and + * 'Skew' table types even though the specification has different formats + * depending on whether or not a center is specified, whether the scale + * is uniform in x and y~direction or not, etc. Also, only non-variable + * format identifiers are listed in this enumeration; as soon as support + * for variable 'COLR' v1 fonts is implemented, interpolation is + * performed dependent on axis coordinates, which are configured on the + * @FT_Face through @FT_Set_Var_Design_Coordinates. This implies that + * always static, readily interpolated values are returned in the 'Paint' + * structures. + * + * @since: + * 2.13 + */ + typedef enum FT_PaintFormat_ + { + FT_COLR_PAINTFORMAT_COLR_LAYERS = 1, + FT_COLR_PAINTFORMAT_SOLID = 2, + FT_COLR_PAINTFORMAT_LINEAR_GRADIENT = 4, + FT_COLR_PAINTFORMAT_RADIAL_GRADIENT = 6, + FT_COLR_PAINTFORMAT_SWEEP_GRADIENT = 8, + FT_COLR_PAINTFORMAT_GLYPH = 10, + FT_COLR_PAINTFORMAT_COLR_GLYPH = 11, + FT_COLR_PAINTFORMAT_TRANSFORM = 12, + FT_COLR_PAINTFORMAT_TRANSLATE = 14, + FT_COLR_PAINTFORMAT_SCALE = 16, + FT_COLR_PAINTFORMAT_ROTATE = 24, + FT_COLR_PAINTFORMAT_SKEW = 28, + FT_COLR_PAINTFORMAT_COMPOSITE = 32, + FT_COLR_PAINT_FORMAT_MAX = 33, + FT_COLR_PAINTFORMAT_UNSUPPORTED = 255 + + } FT_PaintFormat; + + + /************************************************************************** + * + * @struct: + * FT_ColorStopIterator + * + * @description: + * This iterator object is needed for @FT_Get_Colorline_Stops. It keeps + * state while iterating over the stops of an @FT_ColorLine, representing + * the `ColorLine` struct of the v1 extensions to 'COLR', see + * 'https://github.com/googlefonts/colr-gradients-spec'. Do not manually + * modify fields of this iterator. + * + * @fields: + * num_color_stops :: + * The number of color stops for the requested glyph index. Set by + * @FT_Get_Paint. + * + * current_color_stop :: + * The current color stop. Set by @FT_Get_Colorline_Stops. + * + * p :: + * An opaque pointer into 'COLR' table data. Set by @FT_Get_Paint. + * Updated by @FT_Get_Colorline_Stops. + * + * read_variable :: + * A boolean keeping track of whether variable color lines are to be + * read. Set by @FT_Get_Paint. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorStopIterator_ + { + FT_UInt num_color_stops; + FT_UInt current_color_stop; + + FT_Byte* p; + + FT_Bool read_variable; + + } FT_ColorStopIterator; + + + /************************************************************************** + * + * @struct: + * FT_ColorIndex + * + * @description: + * A structure representing a `ColorIndex` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * palette_index :: + * The palette index into a 'CPAL' palette. + * + * alpha :: + * Alpha transparency value multiplied with the value from 'CPAL'. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorIndex_ + { + FT_UInt16 palette_index; + FT_F2Dot14 alpha; + + } FT_ColorIndex; + + + /************************************************************************** + * + * @struct: + * FT_ColorStop + * + * @description: + * A structure representing a `ColorStop` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * stop_offset :: + * The stop offset along the gradient, expressed as a 16.16 fixed-point + * coordinate. + * + * color :: + * The color information for this stop, see @FT_ColorIndex. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorStop_ + { + FT_Fixed stop_offset; + FT_ColorIndex color; + + } FT_ColorStop; + + + /************************************************************************** + * + * @enum: + * FT_PaintExtend + * + * @description: + * An enumeration representing the 'Extend' mode of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes how the gradient fill continues at the other boundaries. + * + * @since: + * 2.13 + */ + typedef enum FT_PaintExtend_ + { + FT_COLR_PAINT_EXTEND_PAD = 0, + FT_COLR_PAINT_EXTEND_REPEAT = 1, + FT_COLR_PAINT_EXTEND_REFLECT = 2 + + } FT_PaintExtend; + + + /************************************************************************** + * + * @struct: + * FT_ColorLine + * + * @description: + * A structure representing a `ColorLine` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes a list of color stops along the defined gradient. + * + * @fields: + * extend :: + * The extend mode at the outer boundaries, see @FT_PaintExtend. + * + * color_stop_iterator :: + * The @FT_ColorStopIterator used to enumerate and retrieve the + * actual @FT_ColorStop's. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorLine_ + { + FT_PaintExtend extend; + FT_ColorStopIterator color_stop_iterator; + + } FT_ColorLine; + + + /************************************************************************** + * + * @struct: + * FT_Affine23 + * + * @description: + * A structure used to store a 2x3 matrix. Coefficients are in + * 16.16 fixed-point format. The computation performed is + * + * ``` + * x' = x*xx + y*xy + dx + * y' = x*yx + y*yy + dy + * ``` + * + * @fields: + * xx :: + * Matrix coefficient. + * + * xy :: + * Matrix coefficient. + * + * dx :: + * x translation. + * + * yx :: + * Matrix coefficient. + * + * yy :: + * Matrix coefficient. + * + * dy :: + * y translation. + * + * @since: + * 2.13 + */ + typedef struct FT_Affine_23_ + { + FT_Fixed xx, xy, dx; + FT_Fixed yx, yy, dy; + + } FT_Affine23; + + + /************************************************************************** + * + * @enum: + * FT_Composite_Mode + * + * @description: + * An enumeration listing the 'COLR' v1 composite modes used in + * @FT_PaintComposite. For more details on each paint mode, see + * 'https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators'. + * + * @since: + * 2.13 + */ + typedef enum FT_Composite_Mode_ + { + FT_COLR_COMPOSITE_CLEAR = 0, + FT_COLR_COMPOSITE_SRC = 1, + FT_COLR_COMPOSITE_DEST = 2, + FT_COLR_COMPOSITE_SRC_OVER = 3, + FT_COLR_COMPOSITE_DEST_OVER = 4, + FT_COLR_COMPOSITE_SRC_IN = 5, + FT_COLR_COMPOSITE_DEST_IN = 6, + FT_COLR_COMPOSITE_SRC_OUT = 7, + FT_COLR_COMPOSITE_DEST_OUT = 8, + FT_COLR_COMPOSITE_SRC_ATOP = 9, + FT_COLR_COMPOSITE_DEST_ATOP = 10, + FT_COLR_COMPOSITE_XOR = 11, + FT_COLR_COMPOSITE_PLUS = 12, + FT_COLR_COMPOSITE_SCREEN = 13, + FT_COLR_COMPOSITE_OVERLAY = 14, + FT_COLR_COMPOSITE_DARKEN = 15, + FT_COLR_COMPOSITE_LIGHTEN = 16, + FT_COLR_COMPOSITE_COLOR_DODGE = 17, + FT_COLR_COMPOSITE_COLOR_BURN = 18, + FT_COLR_COMPOSITE_HARD_LIGHT = 19, + FT_COLR_COMPOSITE_SOFT_LIGHT = 20, + FT_COLR_COMPOSITE_DIFFERENCE = 21, + FT_COLR_COMPOSITE_EXCLUSION = 22, + FT_COLR_COMPOSITE_MULTIPLY = 23, + FT_COLR_COMPOSITE_HSL_HUE = 24, + FT_COLR_COMPOSITE_HSL_SATURATION = 25, + FT_COLR_COMPOSITE_HSL_COLOR = 26, + FT_COLR_COMPOSITE_HSL_LUMINOSITY = 27, + FT_COLR_COMPOSITE_MAX = 28 + + } FT_Composite_Mode; + + + /************************************************************************** + * + * @struct: + * FT_OpaquePaint + * + * @description: + * A structure representing an offset to a `Paint` value stored in any + * of the paint tables of a 'COLR' v1 font. Compare Offset<24> there. + * When 'COLR' v1 paint tables represented by FreeType objects such as + * @FT_PaintColrLayers, @FT_PaintComposite, or @FT_PaintTransform + * reference downstream nested paint tables, we do not immediately + * retrieve them but encapsulate their location in this type. Use + * @FT_Get_Paint to retrieve the actual @FT_COLR_Paint object that + * describes the details of the respective paint table. + * + * @fields: + * p :: + * An internal offset to a Paint table, needs to be set to NULL before + * passing this struct as an argument to @FT_Get_Paint. + * + * insert_root_transform :: + * An internal boolean to track whether an initial root transform is + * to be provided. Do not set this value. + * + * @since: + * 2.13 + */ + typedef struct FT_Opaque_Paint_ + { + FT_Byte* p; + FT_Bool insert_root_transform; + } FT_OpaquePaint; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrLayers + * + * @description: + * A structure representing a `PaintColrLayers` table of a 'COLR' v1 + * font. This table describes a set of layers that are to be composited + * with composite mode `FT_COLR_COMPOSITE_SRC_OVER`. The return value + * of this function is an @FT_LayerIterator initialized so that it can + * be used with @FT_Get_Paint_Layers to retrieve the @FT_OpaquePaint + * objects as references to each layer. + * + * @fields: + * layer_iterator :: + * The layer iterator that describes the layers of this paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintColrLayers_ + { + FT_LayerIterator layer_iterator; + + } FT_PaintColrLayers; + + + /************************************************************************** + * + * @struct: + * FT_PaintSolid + * + * @description: + * A structure representing a `PaintSolid` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * Using a `PaintSolid` value means that the glyph layer filled with + * this paint is solid-colored and does not contain a gradient. + * + * @fields: + * color :: + * The color information for this solid paint, see @FT_ColorIndex. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSolid_ + { + FT_ColorIndex color; + + } FT_PaintSolid; + + + /************************************************************************** + * + * @struct: + * FT_PaintLinearGradient + * + * @description: + * A structure representing a `PaintLinearGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a linear gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * p0 :: + * The starting point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p1 :: + * The end point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p2 :: + * Optional point~p2 to rotate the gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * Otherwise equal to~p0. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintLinearGradient_ + { + FT_ColorLine colorline; + + /* TODO: Potentially expose those as x0, y0 etc. */ + FT_Vector p0; + FT_Vector p1; + FT_Vector p2; + + } FT_PaintLinearGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintRadialGradient + * + * @description: + * A structure representing a `PaintRadialGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a radial gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * c0 :: + * The center of the starting point of the radial gradient in font + * units represented as a 16.16 fixed-point `FT_Vector`. + * + * r0 :: + * The radius of the starting circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * c1 :: + * The center of the end point of the radial gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * r1 :: + * The radius of the end circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintRadialGradient_ + { + FT_ColorLine colorline; + + FT_Vector c0; + FT_Pos r0; + FT_Vector c1; + FT_Pos r1; + + } FT_PaintRadialGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintSweepGradient + * + * @description: + * A structure representing a `PaintSweepGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a sweep gradient + * from `start_angle` to `end_angle`. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * center :: + * The center of the sweep gradient in font units represented as a + * vector of 16.16 fixed-point values. + * + * start_angle :: + * The start angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * end_angle :: + * The end angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSweepGradient_ + { + FT_ColorLine colorline; + + FT_Vector center; + FT_Fixed start_angle; + FT_Fixed end_angle; + + } FT_PaintSweepGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintGlyph` paint table. + * + * @fields: + * paint :: + * An opaque paint object pointing to a `Paint` table that serves as + * the fill for the glyph ID. + * + * glyphID :: + * The glyph ID from the 'glyf' table, which serves as the contour + * information that is filled with paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintGlyph_ + { + FT_OpaquePaint paint; + FT_UInt glyphID; + + } FT_PaintGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintColorGlyph` paint table. + * + * @fields: + * glyphID :: + * The glyph ID from the `BaseGlyphV1List` table that is drawn for + * this paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintColrGlyph_ + { + FT_UInt glyphID; + + } FT_PaintColrGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintTransform + * + * @description: + * A structure representing a 'COLR' v1 `PaintTransform` paint table. + * + * @fields: + * paint :: + * An opaque paint that is subject to being transformed. + * + * affine :: + * A 2x3 transformation matrix in @FT_Affine23 format containing + * 16.16 fixed-point values. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintTransform_ + { + FT_OpaquePaint paint; + FT_Affine23 affine; + + } FT_PaintTransform; + + + /************************************************************************** + * + * @struct: + * FT_PaintTranslate + * + * @description: + * A structure representing a 'COLR' v1 `PaintTranslate` paint table. + * Used for translating downstream paints by a given x and y~delta. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * dx :: + * Translation in x~direction in font units represented as a + * 16.16 fixed-point value. + * + * dy :: + * Translation in y~direction in font units represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintTranslate_ + { + FT_OpaquePaint paint; + + FT_Fixed dx; + FT_Fixed dy; + + } FT_PaintTranslate; + + + /************************************************************************** + * + * @struct: + * FT_PaintScale + * + * @description: + * A structure representing all of the 'COLR' v1 'PaintScale*' paint + * tables. Used for scaling downstream paints by a given x and y~scale, + * with a given center. This structure is used for all 'PaintScale*' + * types that are part of specification; fields of this structure are + * filled accordingly. If there is a center, the center values are set, + * otherwise they are set to the zero coordinate. If the source font + * file has 'PaintScaleUniform*' set, the scale values are set + * accordingly to the same value. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * scaled. + * + * scale_x :: + * Scale factor in x~direction represented as a + * 16.16 fixed-point value. + * + * scale_y :: + * Scale factor in y~direction represented as a + * 16.16 fixed-point value. + * + * center_x :: + * x~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * center_y :: + * y~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintScale_ + { + FT_OpaquePaint paint; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintScale; + + + /************************************************************************** + * + * @struct: + * FT_PaintRotate + * + * @description: + * A structure representing a 'COLR' v1 `PaintRotate` paint table. Used + * for rotating downstream paints with a given center and angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * angle :: + * The rotation angle that is to be applied in degrees divided by + * 180.0 (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees value. + * + * center_x :: + * The x~coordinate of the pivot point of the rotation in font + * units represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the rotation in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + + typedef struct FT_PaintRotate_ + { + FT_OpaquePaint paint; + + FT_Fixed angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintRotate; + + + /************************************************************************** + * + * @struct: + * FT_PaintSkew + * + * @description: + * A structure representing a 'COLR' v1 `PaintSkew` paint table. Used + * for skewing or shearing downstream paints by a given center and + * angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * skewed. + * + * x_skew_angle :: + * The skewing angle in x~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * y_skew_angle :: + * The skewing angle in y~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * center_x :: + * The x~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSkew_ + { + FT_OpaquePaint paint; + + FT_Fixed x_skew_angle; + FT_Fixed y_skew_angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintSkew; + + + /************************************************************************** + * + * @struct: + * FT_PaintComposite + * + * @description: + * A structure representing a 'COLR' v1 `PaintComposite` paint table. + * Used for compositing two paints in a 'COLR' v1 directed acyclic graph. + * + * @fields: + * source_paint :: + * An @FT_OpaquePaint object referencing the source that is to be + * composited. + * + * composite_mode :: + * An @FT_Composite_Mode enum value determining the composition + * operation. + * + * backdrop_paint :: + * An @FT_OpaquePaint object referencing the backdrop paint that + * `source_paint` is composited onto. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintComposite_ + { + FT_OpaquePaint source_paint; + FT_Composite_Mode composite_mode; + FT_OpaquePaint backdrop_paint; + + } FT_PaintComposite; + + + /************************************************************************** + * + * @union: + * FT_COLR_Paint + * + * @description: + * A union object representing format and details of a paint table of a + * 'COLR' v1 font, see + * 'https://github.com/googlefonts/colr-gradients-spec'. Use + * @FT_Get_Paint to retrieve a @FT_COLR_Paint for an @FT_OpaquePaint + * object. + * + * @fields: + * format :: + * The gradient format for this Paint structure. + * + * u :: + * Union of all paint table types: + * + * * @FT_PaintColrLayers + * * @FT_PaintGlyph + * * @FT_PaintSolid + * * @FT_PaintLinearGradient + * * @FT_PaintRadialGradient + * * @FT_PaintSweepGradient + * * @FT_PaintTransform + * * @FT_PaintTranslate + * * @FT_PaintRotate + * * @FT_PaintSkew + * * @FT_PaintComposite + * * @FT_PaintColrGlyph + * + * @since: + * 2.13 + */ + typedef struct FT_COLR_Paint_ + { + FT_PaintFormat format; + + union + { + FT_PaintColrLayers colr_layers; + FT_PaintGlyph glyph; + FT_PaintSolid solid; + FT_PaintLinearGradient linear_gradient; + FT_PaintRadialGradient radial_gradient; + FT_PaintSweepGradient sweep_gradient; + FT_PaintTransform transform; + FT_PaintTranslate translate; + FT_PaintScale scale; + FT_PaintRotate rotate; + FT_PaintSkew skew; + FT_PaintComposite composite; + FT_PaintColrGlyph colr_glyph; + + } u; + + } FT_COLR_Paint; + + + /************************************************************************** + * + * @enum: + * FT_Color_Root_Transform + * + * @description: + * An enumeration to specify whether @FT_Get_Color_Glyph_Paint is to + * return a root transform to configure the client's graphics context + * matrix. + * + * @values: + * FT_COLOR_INCLUDE_ROOT_TRANSFORM :: + * Do include the root transform as the initial @FT_COLR_Paint object. + * + * FT_COLOR_NO_ROOT_TRANSFORM :: + * Do not output an initial root transform. + * + * @since: + * 2.13 + */ + typedef enum FT_Color_Root_Transform_ + { + FT_COLOR_INCLUDE_ROOT_TRANSFORM, + FT_COLOR_NO_ROOT_TRANSFORM, + + FT_COLOR_ROOT_TRANSFORM_MAX + + } FT_Color_Root_Transform; + + + /************************************************************************** + * + * @struct: + * FT_ClipBox + * + * @description: + * A structure representing a 'COLR' v1 'ClipBox' table. 'COLR' v1 + * glyphs may optionally define a clip box for aiding allocation or + * defining a maximum drawable region. Use @FT_Get_Color_Glyph_ClipBox + * to retrieve it. + * + * @fields: + * bottom_left :: + * The bottom left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_left :: + * The top left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_right :: + * The top right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * bottom_right :: + * The bottom right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * @since: + * 2.13 + */ + typedef struct FT_ClipBox_ + { + FT_Vector bottom_left; + FT_Vector top_left; + FT_Vector top_right; + FT_Vector bottom_right; + + } FT_ClipBox; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Paint + * + * @description: + * This is the starting point and interface to color gradient + * information in a 'COLR' v1 table in OpenType fonts to recursively + * retrieve the paint tables for the directed acyclic graph of a colored + * glyph, given a glyph ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * In a 'COLR' v1 font, each color glyph defines a directed acyclic + * graph of nested paint tables, such as `PaintGlyph`, `PaintSolid`, + * `PaintLinearGradient`, `PaintRadialGradient`, and so on. Using this + * function and specifying a glyph ID, one retrieves the root paint + * table for this glyph ID. + * + * This function allows control whether an initial root transform is + * returned to configure scaling, transform, and translation correctly + * on the client's graphics context. The initial root transform is + * computed and returned according to the values configured for @FT_Size + * and @FT_Set_Transform on the @FT_Face object, see below for details + * of the `root_transform` parameter. This has implications for a + * client 'COLR' v1 implementation: When this function returns an + * initially computed root transform, at the time of executing the + * @FT_PaintGlyph operation, the contours should be retrieved using + * @FT_Load_Glyph at unscaled, untransformed size. This is because the + * root transform applied to the graphics context will take care of + * correct scaling. + * + * Alternatively, to allow hinting of contours, at the time of executing + * @FT_Load_Glyph, the current graphics context transformation matrix + * can be decomposed into a scaling matrix and a remainder, and + * @FT_Load_Glyph can be used to retrieve the contours at scaled size. + * Care must then be taken to blit or clip to the graphics context with + * taking this remainder transformation into account. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the root paint table. + * + * root_transform :: + * Specifies whether an initially computed root is returned by the + * @FT_PaintTransform operation to account for the activated size + * (see @FT_Activate_Size) and the configured transform and translate + * (see @FT_Set_Transform). + * + * This root transform is returned before nodes of the glyph graph of + * the font are returned. Subsequent @FT_COLR_Paint structures + * contain unscaled and untransformed values. The inserted root + * transform enables the client application to apply an initial + * transform to its graphics context. When executing subsequent + * FT_COLR_Paint operations, values from @FT_COLR_Paint operations + * will ultimately be correctly scaled because of the root transform + * applied to the graphics context. Use + * @FT_COLOR_INCLUDE_ROOT_TRANSFORM to include the root transform, use + * @FT_COLOR_NO_ROOT_TRANSFORM to not include it. The latter may be + * useful when traversing the 'COLR' v1 glyph graph and reaching a + * @FT_PaintColrGlyph. When recursing into @FT_PaintColrGlyph and + * painting that inline, no additional root transform is needed as it + * has already been applied to the graphics context at the beginning + * of drawing this glyph. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_ClipBox + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @return: + * Value~1 if a clip box is found. If no clip box is found or an error + * occured, value~0 is returned. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint_Layers + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * If the root paint of a color glyph, or a nested paint of a 'COLR' + * glyph is a `PaintColrLayers` table, this function retrieves the + * layers of the `PaintColrLayers` table. + * + * The @FT_PaintColrLayers object contains an @FT_LayerIterator, which + * is used here to iterate over the layers. Each layer is returned as + * an @FT_OpaquePaint object, which then can be used with @FT_Get_Paint + * to retrieve the actual paint object. + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Colorline_Stops + * + * @description: + * This is an interface to color gradient information in a 'COLR' v1 + * table in OpenType fonts to iteratively retrieve the gradient and + * solid fill information for colored glyph layers for a specified glyph + * ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The retrieved @FT_ColorStopIterator, configured on an @FT_ColorLine, + * which in turn got retrieved via paint information in + * @FT_PaintLinearGradient or @FT_PaintRadialGradient. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Colorline_Stops( FT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint + * + * @description: + * Access the details of a paint using an @FT_OpaquePaint opaque paint + * object, which internally stores the offset to the respective `Paint` + * object in the 'COLR' table. + * + * @input: + * face :: + * A handle to the parent face object. + * + * opaque_paint :: + * The opaque paint object for which the underlying @FT_COLR_Paint + * data is to be retrieved. + * + * @output: + * paint :: + * The specific @FT_COLR_Paint object containing information coming + * from one of the font's `Paint*` tables. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occured. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + + /* */ + + +FT_END_HEADER + +#endif /* FTCOLOR_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftdriver.h b/vendor/freetype/include/freetype/ftdriver.h new file mode 100644 index 0000000..7af7465 --- /dev/null +++ b/vendor/freetype/include/freetype/ftdriver.h @@ -0,0 +1,1246 @@ +/**************************************************************************** + * + * ftdriver.h + * + * FreeType API for controlling driver modules (specification only). + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTDRIVER_H_ +#define FTDRIVER_H_ + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * auto_hinter + * + * @title: + * The auto-hinter + * + * @abstract: + * Controlling the auto-hinting module. + * + * @description: + * While FreeType's auto-hinter doesn't expose API functions by itself, + * it is possible to control its behaviour with @FT_Property_Set and + * @FT_Property_Get. The following lists the available properties + * together with the necessary macros and structures. + * + * Note that the auto-hinter's module name is 'autofitter' for historical + * reasons. + * + * Available properties are @increase-x-height, @no-stem-darkening + * (experimental), @darkening-parameters (experimental), + * @glyph-to-script-map (experimental), @fallback-script (experimental), + * and @default-script (experimental), as documented in the @properties + * section. + * + */ + + + /************************************************************************** + * + * @section: + * cff_driver + * + * @title: + * The CFF driver + * + * @abstract: + * Controlling the CFF driver module. + * + * @description: + * While FreeType's CFF driver doesn't expose API functions by itself, it + * is possible to control its behaviour with @FT_Property_Set and + * @FT_Property_Get. + * + * The CFF driver's module name is 'cff'. + * + * Available properties are @hinting-engine, @no-stem-darkening, + * @darkening-parameters, and @random-seed, as documented in the + * @properties section. + * + * + * **Hinting and anti-aliasing principles of the new engine** + * + * The rasterizer is positioning horizontal features (e.g., ascender + * height & x-height, or crossbars) on the pixel grid and minimizing the + * amount of anti-aliasing applied to them, while placing vertical + * features (vertical stems) on the pixel grid without hinting, thus + * representing the stem position and weight accurately. Sometimes the + * vertical stems may be only partially black. In this context, + * 'anti-aliasing' means that stems are not positioned exactly on pixel + * borders, causing a fuzzy appearance. + * + * There are two principles behind this approach. + * + * 1) No hinting in the horizontal direction: Unlike 'superhinted' + * TrueType, which changes glyph widths to accommodate regular + * inter-glyph spacing, Adobe's approach is 'faithful to the design' in + * representing both the glyph width and the inter-glyph spacing designed + * for the font. This makes the screen display as close as it can be to + * the result one would get with infinite resolution, while preserving + * what is considered the key characteristics of each glyph. Note that + * the distances between unhinted and grid-fitted positions at small + * sizes are comparable to kerning values and thus would be noticeable + * (and distracting) while reading if hinting were applied. + * + * One of the reasons to not hint horizontally is anti-aliasing for LCD + * screens: The pixel geometry of modern displays supplies three vertical + * subpixels as the eye moves horizontally across each visible pixel. On + * devices where we can be certain this characteristic is present a + * rasterizer can take advantage of the subpixels to add increments of + * weight. In Western writing systems this turns out to be the more + * critical direction anyway; the weights and spacing of vertical stems + * (see above) are central to Armenian, Cyrillic, Greek, and Latin type + * designs. Even when the rasterizer uses greyscale anti-aliasing instead + * of color (a necessary compromise when one doesn't know the screen + * characteristics), the unhinted vertical features preserve the design's + * weight and spacing much better than aliased type would. + * + * 2) Alignment in the vertical direction: Weights and spacing along the + * y~axis are less critical; what is much more important is the visual + * alignment of related features (like cap-height and x-height). The + * sense of alignment for these is enhanced by the sharpness of grid-fit + * edges, while the cruder vertical resolution (full pixels instead of + * 1/3 pixels) is less of a problem. + * + * On the technical side, horizontal alignment zones for ascender, + * x-height, and other important height values (traditionally called + * 'blue zones') as defined in the font are positioned independently, + * each being rounded to the nearest pixel edge, taking care of overshoot + * suppression at small sizes, stem darkening, and scaling. + * + * Hstems (that is, hint values defined in the font to help align + * horizontal features) that fall within a blue zone are said to be + * 'captured' and are aligned to that zone. Uncaptured stems are moved + * in one of four ways, top edge up or down, bottom edge up or down. + * Unless there are conflicting hstems, the smallest movement is taken to + * minimize distortion. + * + */ + + + /************************************************************************** + * + * @section: + * pcf_driver + * + * @title: + * The PCF driver + * + * @abstract: + * Controlling the PCF driver module. + * + * @description: + * While FreeType's PCF driver doesn't expose API functions by itself, it + * is possible to control its behaviour with @FT_Property_Set and + * @FT_Property_Get. Right now, there is a single property + * @no-long-family-names available if FreeType is compiled with + * PCF_CONFIG_OPTION_LONG_FAMILY_NAMES. + * + * The PCF driver's module name is 'pcf'. + * + */ + + + /************************************************************************** + * + * @section: + * t1_cid_driver + * + * @title: + * The Type 1 and CID drivers + * + * @abstract: + * Controlling the Type~1 and CID driver modules. + * + * @description: + * It is possible to control the behaviour of FreeType's Type~1 and + * Type~1 CID drivers with @FT_Property_Set and @FT_Property_Get. + * + * Behind the scenes, both drivers use the Adobe CFF engine for hinting; + * however, the used properties must be specified separately. + * + * The Type~1 driver's module name is 'type1'; the CID driver's module + * name is 't1cid'. + * + * Available properties are @hinting-engine, @no-stem-darkening, + * @darkening-parameters, and @random-seed, as documented in the + * @properties section. + * + * Please see the @cff_driver section for more details on the new hinting + * engine. + * + */ + + + /************************************************************************** + * + * @section: + * tt_driver + * + * @title: + * The TrueType driver + * + * @abstract: + * Controlling the TrueType driver module. + * + * @description: + * While FreeType's TrueType driver doesn't expose API functions by + * itself, it is possible to control its behaviour with @FT_Property_Set + * and @FT_Property_Get. + * + * The TrueType driver's module name is 'truetype'; a single property + * @interpreter-version is available, as documented in the @properties + * section. + * + * To help understand the differences between interpreter versions, we + * introduce a list of definitions, kindly provided by Greg Hitchcock. + * + * _Bi-Level Rendering_ + * + * Monochromatic rendering, exclusively used in the early days of + * TrueType by both Apple and Microsoft. Microsoft's GDI interface + * supported hinting of the right-side bearing point, such that the + * advance width could be non-linear. Most often this was done to + * achieve some level of glyph symmetry. To enable reasonable + * performance (e.g., not having to run hinting on all glyphs just to get + * the widths) there was a bit in the head table indicating if the side + * bearing was hinted, and additional tables, 'hdmx' and 'LTSH', to cache + * hinting widths across multiple sizes and device aspect ratios. + * + * _Font Smoothing_ + * + * Microsoft's GDI implementation of anti-aliasing. Not traditional + * anti-aliasing as the outlines were hinted before the sampling. The + * widths matched the bi-level rendering. + * + * _ClearType Rendering_ + * + * Technique that uses physical subpixels to improve rendering on LCD + * (and other) displays. Because of the higher resolution, many methods + * of improving symmetry in glyphs through hinting the right-side bearing + * were no longer necessary. This lead to what GDI calls 'natural + * widths' ClearType, see + * http://rastertragedy.com/RTRCh4.htm#Sec21. Since hinting + * has extra resolution, most non-linearity went away, but it is still + * possible for hints to change the advance widths in this mode. + * + * _ClearType Compatible Widths_ + * + * One of the earliest challenges with ClearType was allowing the + * implementation in GDI to be selected without requiring all UI and + * documents to reflow. To address this, a compatible method of + * rendering ClearType was added where the font hints are executed once + * to determine the width in bi-level rendering, and then re-run in + * ClearType, with the difference in widths being absorbed in the font + * hints for ClearType (mostly in the white space of hints); see + * http://rastertragedy.com/RTRCh4.htm#Sec20. Somewhat by + * definition, compatible width ClearType allows for non-linear widths, + * but only when the bi-level version has non-linear widths. + * + * _ClearType Subpixel Positioning_ + * + * One of the nice benefits of ClearType is the ability to more crisply + * display fractional widths; unfortunately, the GDI model of integer + * bitmaps did not support this. However, the WPF and Direct Write + * frameworks do support fractional widths. DWrite calls this 'natural + * mode', not to be confused with GDI's 'natural widths'. Subpixel + * positioning, in the current implementation of Direct Write, + * unfortunately does not support hinted advance widths, see + * http://rastertragedy.com/RTRCh4.htm#Sec22. Note that the + * TrueType interpreter fully allows the advance width to be adjusted in + * this mode, just the DWrite client will ignore those changes. + * + * _ClearType Backward Compatibility_ + * + * This is a set of exceptions made in the TrueType interpreter to + * minimize hinting techniques that were problematic with the extra + * resolution of ClearType; see + * http://rastertragedy.com/RTRCh4.htm#Sec1 and + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx. + * This technique is not to be confused with ClearType compatible widths. + * ClearType backward compatibility has no direct impact on changing + * advance widths, but there might be an indirect impact on disabling + * some deltas. This could be worked around in backward compatibility + * mode. + * + * _Native ClearType Mode_ + * + * (Not to be confused with 'natural widths'.) This mode removes all the + * exceptions in the TrueType interpreter when running with ClearType. + * Any issues on widths would still apply, though. + * + */ + + + /************************************************************************** + * + * @section: + * ot_svg_driver + * + * @title: + * The SVG driver + * + * @abstract: + * Controlling the external rendering of OT-SVG glyphs. + * + * @description: + * By default, FreeType can only load the 'SVG~' table of OpenType fonts + * if configuration macro `FT_CONFIG_OPTION_SVG` is defined. To make it + * render SVG glyphs, an external SVG rendering library is needed. All + * details on the interface between FreeType and the external library + * via function hooks can be found in section @svg_fonts. + * + * The OT-SVG driver's module name is 'ot-svg'; it supports a single + * property called @svg-hooks, documented below in the @properties + * section. + * + */ + + + /************************************************************************** + * + * @section: + * properties + * + * @title: + * Driver properties + * + * @abstract: + * Controlling driver modules. + * + * @description: + * Driver modules can be controlled by setting and unsetting properties, + * using the functions @FT_Property_Set and @FT_Property_Get. This + * section documents the available properties, together with auxiliary + * macros and structures. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_HINTING_XXX + * + * @description: + * A list of constants used for the @hinting-engine property to select + * the hinting engine for CFF, Type~1, and CID fonts. + * + * @values: + * FT_HINTING_FREETYPE :: + * Use the old FreeType hinting engine. + * + * FT_HINTING_ADOBE :: + * Use the hinting engine contributed by Adobe. + * + * @since: + * 2.9 + * + */ +#define FT_HINTING_FREETYPE 0 +#define FT_HINTING_ADOBE 1 + + /* these constants (introduced in 2.4.12) are deprecated */ +#define FT_CFF_HINTING_FREETYPE FT_HINTING_FREETYPE +#define FT_CFF_HINTING_ADOBE FT_HINTING_ADOBE + + + /************************************************************************** + * + * @property: + * hinting-engine + * + * @description: + * Thanks to Adobe, which contributed a new hinting (and parsing) engine, + * an application can select between 'freetype' and 'adobe' if compiled + * with `CFF_CONFIG_OPTION_OLD_ENGINE`. If this configuration macro + * isn't defined, 'hinting-engine' does nothing. + * + * The same holds for the Type~1 and CID modules if compiled with + * `T1_CONFIG_OPTION_OLD_ENGINE`. + * + * For the 'cff' module, the default engine is 'adobe'. For both the + * 'type1' and 't1cid' modules, the default engine is 'adobe', too. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values 'adobe' or 'freetype'). + * + * @example: + * The following example code demonstrates how to select Adobe's hinting + * engine for the 'cff' module (omitting the error handling). + * + * ``` + * FT_Library library; + * FT_UInt hinting_engine = FT_HINTING_ADOBE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "cff", + * "hinting-engine", &hinting_engine ); + * ``` + * + * @since: + * 2.4.12 (for 'cff' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * no-stem-darkening + * + * @description: + * All glyphs that pass through the auto-hinter will be emboldened unless + * this property is set to TRUE. The same is true for the CFF, Type~1, + * and CID font modules if the 'Adobe' engine is selected (which is the + * default). + * + * Stem darkening emboldens glyphs at smaller sizes to make them more + * readable on common low-DPI screens when using linear alpha blending + * and gamma correction, see @FT_Render_Glyph. When not using linear + * alpha blending and gamma correction, glyphs will appear heavy and + * fuzzy! + * + * Gamma correction essentially lightens fonts since shades of grey are + * shifted to higher pixel values (=~higher brightness) to match the + * original intention to the reality of our screens. The side-effect is + * that glyphs 'thin out'. Mac OS~X and Adobe's proprietary font + * rendering library implement a counter-measure: stem darkening at + * smaller sizes where shades of gray dominate. By emboldening a glyph + * slightly in relation to its pixel size, individual pixels get higher + * coverage of filled-in outlines and are therefore 'blacker'. This + * counteracts the 'thinning out' of glyphs, making text remain readable + * at smaller sizes. + * + * For the auto-hinter, stem-darkening is experimental currently and thus + * switched off by default (that is, `no-stem-darkening` is set to TRUE + * by default). Total consistency with the CFF driver is not achieved + * right now because the emboldening method differs and glyphs must be + * scaled down on the Y-axis to keep outline points inside their + * precomputed blue zones. The smaller the size (especially 9ppem and + * down), the higher the loss of emboldening versus the CFF driver. + * + * Note that stem darkening is never applied if @FT_LOAD_NO_SCALE is set. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values 1 and 0 for 'on' and 'off', respectively). It + * can also be set per face using @FT_Face_Properties with + * @FT_PARAM_TAG_STEM_DARKENING. + * + * @example: + * ``` + * FT_Library library; + * FT_Bool no_stem_darkening = TRUE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "cff", + * "no-stem-darkening", &no_stem_darkening ); + * ``` + * + * @since: + * 2.4.12 (for 'cff' module) + * + * 2.6.2 (for 'autofitter' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * darkening-parameters + * + * @description: + * By default, the Adobe hinting engine, as used by the CFF, Type~1, and + * CID font drivers, darkens stems as follows (if the `no-stem-darkening` + * property isn't set): + * + * ``` + * stem width <= 0.5px: darkening amount = 0.4px + * stem width = 1px: darkening amount = 0.275px + * stem width = 1.667px: darkening amount = 0.275px + * stem width >= 2.333px: darkening amount = 0px + * ``` + * + * and piecewise linear in-between. At configuration time, these four + * control points can be set with the macro + * `CFF_CONFIG_OPTION_DARKENING_PARAMETERS`; the CFF, Type~1, and CID + * drivers share these values. At runtime, the control points can be + * changed using the `darkening-parameters` property (see the example + * below that demonstrates this for the Type~1 driver). + * + * The x~values give the stem width, and the y~values the darkening + * amount. The unit is 1000th of pixels. All coordinate values must be + * positive; the x~values must be monotonically increasing; the y~values + * must be monotonically decreasing and smaller than or equal to 500 + * (corresponding to half a pixel); the slope of each linear piece must + * be shallower than -1 (e.g., -.4). + * + * The auto-hinter provides this property, too, as an experimental + * feature. See @no-stem-darkening for more. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable, using eight comma-separated integers without spaces. Here + * the above example, using `\` to break the line for readability. + * + * ``` + * FREETYPE_PROPERTIES=\ + * type1:darkening-parameters=500,300,1000,200,1500,100,2000,0 + * ``` + * + * @example: + * ``` + * FT_Library library; + * FT_Int darken_params[8] = { 500, 300, // x1, y1 + * 1000, 200, // x2, y2 + * 1500, 100, // x3, y3 + * 2000, 0 }; // x4, y4 + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "type1", + * "darkening-parameters", darken_params ); + * ``` + * + * @since: + * 2.5.1 (for 'cff' module) + * + * 2.6.2 (for 'autofitter' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * random-seed + * + * @description: + * By default, the seed value for the CFF 'random' operator and the + * similar '0 28 callothersubr pop' command for the Type~1 and CID + * drivers is set to a random value. However, mainly for debugging + * purposes, it is often necessary to use a known value as a seed so that + * the pseudo-random number sequences generated by 'random' are + * repeatable. + * + * The `random-seed` property does that. Its argument is a signed 32bit + * integer; if the value is zero or negative, the seed given by the + * `intitialRandomSeed` private DICT operator in a CFF file gets used (or + * a default value if there is no such operator). If the value is + * positive, use it instead of `initialRandomSeed`, which is consequently + * ignored. + * + * @note: + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable. It can also be set per face using @FT_Face_Properties with + * @FT_PARAM_TAG_RANDOM_SEED. + * + * @since: + * 2.8 (for 'cff' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * no-long-family-names + * + * @description: + * If `PCF_CONFIG_OPTION_LONG_FAMILY_NAMES` is active while compiling + * FreeType, the PCF driver constructs long family names. + * + * There are many PCF fonts just called 'Fixed' which look completely + * different, and which have nothing to do with each other. When + * selecting 'Fixed' in KDE or Gnome one gets results that appear rather + * random, the style changes often if one changes the size and one cannot + * select some fonts at all. The improve this situation, the PCF module + * prepends the foundry name (plus a space) to the family name. It also + * checks whether there are 'wide' characters; all put together, family + * names like 'Sony Fixed' or 'Misc Fixed Wide' are constructed. + * + * If `no-long-family-names` is set, this feature gets switched off. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values 1 and 0 for 'on' and 'off', respectively). + * + * @example: + * ``` + * FT_Library library; + * FT_Bool no_long_family_names = TRUE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "pcf", + * "no-long-family-names", + * &no_long_family_names ); + * ``` + * + * @since: + * 2.8 + */ + + + /************************************************************************** + * + * @enum: + * TT_INTERPRETER_VERSION_XXX + * + * @description: + * A list of constants used for the @interpreter-version property to + * select the hinting engine for Truetype fonts. + * + * The numeric value in the constant names represents the version number + * as returned by the 'GETINFO' bytecode instruction. + * + * @values: + * TT_INTERPRETER_VERSION_35 :: + * Version~35 corresponds to MS rasterizer v.1.7 as used e.g. in + * Windows~98; only grayscale and B/W rasterizing is supported. + * + * TT_INTERPRETER_VERSION_38 :: + * Version~38 is the same Version~40. The original 'Infinality' code is + * no longer available. + * + * TT_INTERPRETER_VERSION_40 :: + * Version~40 corresponds to MS rasterizer v.2.1; it is roughly + * equivalent to the hinting provided by DirectWrite ClearType (as can + * be found, for example, in Microsoft's Edge Browser on Windows~10). + * It is used in FreeType to select the 'minimal' subpixel hinting + * code, a stripped-down and higher performance version of the + * 'Infinality' code. + * + * @note: + * This property controls the behaviour of the bytecode interpreter and + * thus how outlines get hinted. It does **not** control how glyph get + * rasterized! In particular, it does not control subpixel color + * filtering. + * + * If FreeType has not been compiled with the configuration option + * `TT_CONFIG_OPTION_SUBPIXEL_HINTING`, selecting version~38 or~40 causes + * an `FT_Err_Unimplemented_Feature` error. + * + * Depending on the graphics framework, Microsoft uses different bytecode + * and rendering engines. As a consequence, the version numbers returned + * by a call to the 'GETINFO' bytecode instruction are more convoluted + * than desired. + * + * Here are two tables that try to shed some light on the possible values + * for the MS rasterizer engine, together with the additional features + * introduced by it. + * + * ``` + * GETINFO framework version feature + * ------------------------------------------------------------------- + * 3 GDI (Win 3.1), v1.0 16-bit, first version + * TrueImage + * 33 GDI (Win NT 3.1), v1.5 32-bit + * HP Laserjet + * 34 GDI (Win 95) v1.6 font smoothing, + * new SCANTYPE opcode + * 35 GDI (Win 98/2000) v1.7 (UN)SCALED_COMPONENT_OFFSET + * bits in composite glyphs + * 36 MGDI (Win CE 2) v1.6+ classic ClearType + * 37 GDI (XP and later), v1.8 ClearType + * GDI+ old (before Vista) + * 38 GDI+ old (Vista, Win 7), v1.9 subpixel ClearType, + * WPF Y-direction ClearType, + * additional error checking + * 39 DWrite (before Win 8) v2.0 subpixel ClearType flags + * in GETINFO opcode, + * bug fixes + * 40 GDI+ (after Win 7), v2.1 Y-direction ClearType flag + * DWrite (Win 8) in GETINFO opcode, + * Gray ClearType + * ``` + * + * The 'version' field gives a rough orientation only, since some + * applications provided certain features much earlier (as an example, + * Microsoft Reader used subpixel and Y-direction ClearType already in + * Windows 2000). Similarly, updates to a given framework might include + * improved hinting support. + * + * ``` + * version sampling rendering comment + * x y x y + * -------------------------------------------------------------- + * v1.0 normal normal B/W B/W bi-level + * v1.6 high high gray gray grayscale + * v1.8 high normal color-filter B/W (GDI) ClearType + * v1.9 high high color-filter gray Color ClearType + * v2.1 high normal gray B/W Gray ClearType + * v2.1 high high gray gray Gray ClearType + * ``` + * + * Color and Gray ClearType are the two available variants of + * 'Y-direction ClearType', meaning grayscale rasterization along the + * Y-direction; the name used in the TrueType specification for this + * feature is 'symmetric smoothing'. 'Classic ClearType' is the original + * algorithm used before introducing a modified version in Win~XP. + * Another name for v1.6's grayscale rendering is 'font smoothing', and + * 'Color ClearType' is sometimes also called 'DWrite ClearType'. To + * differentiate between today's Color ClearType and the earlier + * ClearType variant with B/W rendering along the vertical axis, the + * latter is sometimes called 'GDI ClearType'. + * + * 'Normal' and 'high' sampling describe the (virtual) resolution to + * access the rasterized outline after the hinting process. 'Normal' + * means 1 sample per grid line (i.e., B/W). In the current Microsoft + * implementation, 'high' means an extra virtual resolution of 16x16 (or + * 16x1) grid lines per pixel for bytecode instructions like 'MIRP'. + * After hinting, these 16 grid lines are mapped to 6x5 (or 6x1) grid + * lines for color filtering if Color ClearType is activated. + * + * Note that 'Gray ClearType' is essentially the same as v1.6's grayscale + * rendering. However, the GETINFO instruction handles it differently: + * v1.6 returns bit~12 (hinting for grayscale), while v2.1 returns + * bits~13 (hinting for ClearType), 18 (symmetrical smoothing), and~19 + * (Gray ClearType). Also, this mode respects bits 2 and~3 for the + * version~1 gasp table exclusively (like Color ClearType), while v1.6 + * only respects the values of version~0 (bits 0 and~1). + * + * Keep in mind that the features of the above interpreter versions might + * not map exactly to FreeType features or behavior because it is a + * fundamentally different library with different internals. + * + */ +#define TT_INTERPRETER_VERSION_35 35 +#define TT_INTERPRETER_VERSION_38 38 +#define TT_INTERPRETER_VERSION_40 40 + + + /************************************************************************** + * + * @property: + * interpreter-version + * + * @description: + * Currently, three versions are available, two representing the bytecode + * interpreter with subpixel hinting support (old 'Infinality' code and + * new stripped-down and higher performance 'minimal' code) and one + * without, respectively. The default is subpixel support if + * `TT_CONFIG_OPTION_SUBPIXEL_HINTING` is defined, and no subpixel + * support otherwise (since it isn't available then). + * + * If subpixel hinting is on, many TrueType bytecode instructions behave + * differently compared to B/W or grayscale rendering (except if 'native + * ClearType' is selected by the font). Microsoft's main idea is to + * render at a much increased horizontal resolution, then sampling down + * the created output to subpixel precision. However, many older fonts + * are not suited to this and must be specially taken care of by applying + * (hardcoded) tweaks in Microsoft's interpreter. + * + * Details on subpixel hinting and some of the necessary tweaks can be + * found in Greg Hitchcock's whitepaper at + * 'https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx'. + * Note that FreeType currently doesn't really 'subpixel hint' (6x1, 6x2, + * or 6x5 supersampling) like discussed in the paper. Depending on the + * chosen interpreter, it simply ignores instructions on vertical stems + * to arrive at very similar results. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values '35', '38', or '40'). + * + * @example: + * The following example code demonstrates how to deactivate subpixel + * hinting (omitting the error handling). + * + * ``` + * FT_Library library; + * FT_Face face; + * FT_UInt interpreter_version = TT_INTERPRETER_VERSION_35; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "truetype", + * "interpreter-version", + * &interpreter_version ); + * ``` + * + * @since: + * 2.5 + */ + + /************************************************************************** + * + * @property: + * svg-hooks + * + * @description: + * Set up the interface between FreeType and an extern SVG rendering + * library like 'librsvg'. All details on the function hooks can be + * found in section @svg_fonts. + * + * @example: + * The following example code expects that the four hook functions + * `svg_*` are defined elsewhere. Error handling is omitted, too. + * + * ``` + * FT_Library library; + * SVG_RendererHooks hooks = { + * (SVG_Lib_Init_Func)svg_init, + * (SVG_Lib_Free_Func)svg_free, + * (SVG_Lib_Render_Func)svg_render, + * (SVG_Lib_Preset_Slot_Func)svg_preset_slot }; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "ot-svg", + * "svg-hooks", &hooks ); + * ``` + * + * @since: + * 2.12 + */ + + + /************************************************************************** + * + * @property: + * glyph-to-script-map + * + * @description: + * **Experimental only** + * + * The auto-hinter provides various script modules to hint glyphs. + * Examples of supported scripts are Latin or CJK. Before a glyph is + * auto-hinted, the Unicode character map of the font gets examined, and + * the script is then determined based on Unicode character ranges, see + * below. + * + * OpenType fonts, however, often provide much more glyphs than character + * codes (small caps, superscripts, ligatures, swashes, etc.), to be + * controlled by so-called 'features'. Handling OpenType features can be + * quite complicated and thus needs a separate library on top of + * FreeType. + * + * The mapping between glyph indices and scripts (in the auto-hinter + * sense, see the @FT_AUTOHINTER_SCRIPT_XXX values) is stored as an array + * with `num_glyphs` elements, as found in the font's @FT_Face structure. + * The `glyph-to-script-map` property returns a pointer to this array, + * which can be modified as needed. Note that the modification should + * happen before the first glyph gets processed by the auto-hinter so + * that the global analysis of the font shapes actually uses the modified + * mapping. + * + * @example: + * The following example code demonstrates how to access it (omitting the + * error handling). + * + * ``` + * FT_Library library; + * FT_Face face; + * FT_Prop_GlyphToScriptMap prop; + * + * + * FT_Init_FreeType( &library ); + * FT_New_Face( library, "foo.ttf", 0, &face ); + * + * prop.face = face; + * + * FT_Property_Get( library, "autofitter", + * "glyph-to-script-map", &prop ); + * + * // adjust `prop.map' as needed right here + * + * FT_Load_Glyph( face, ..., FT_LOAD_FORCE_AUTOHINT ); + * ``` + * + * @since: + * 2.4.11 + * + */ + + + /************************************************************************** + * + * @enum: + * FT_AUTOHINTER_SCRIPT_XXX + * + * @description: + * **Experimental only** + * + * A list of constants used for the @glyph-to-script-map property to + * specify the script submodule the auto-hinter should use for hinting a + * particular glyph. + * + * @values: + * FT_AUTOHINTER_SCRIPT_NONE :: + * Don't auto-hint this glyph. + * + * FT_AUTOHINTER_SCRIPT_LATIN :: + * Apply the latin auto-hinter. For the auto-hinter, 'latin' is a very + * broad term, including Cyrillic and Greek also since characters from + * those scripts share the same design constraints. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * ``` + * U+0020 - U+007F // Basic Latin (no control characters) + * U+00A0 - U+00FF // Latin-1 Supplement (no control characters) + * U+0100 - U+017F // Latin Extended-A + * U+0180 - U+024F // Latin Extended-B + * U+0250 - U+02AF // IPA Extensions + * U+02B0 - U+02FF // Spacing Modifier Letters + * U+0300 - U+036F // Combining Diacritical Marks + * U+0370 - U+03FF // Greek and Coptic + * U+0400 - U+04FF // Cyrillic + * U+0500 - U+052F // Cyrillic Supplement + * U+1D00 - U+1D7F // Phonetic Extensions + * U+1D80 - U+1DBF // Phonetic Extensions Supplement + * U+1DC0 - U+1DFF // Combining Diacritical Marks Supplement + * U+1E00 - U+1EFF // Latin Extended Additional + * U+1F00 - U+1FFF // Greek Extended + * U+2000 - U+206F // General Punctuation + * U+2070 - U+209F // Superscripts and Subscripts + * U+20A0 - U+20CF // Currency Symbols + * U+2150 - U+218F // Number Forms + * U+2460 - U+24FF // Enclosed Alphanumerics + * U+2C60 - U+2C7F // Latin Extended-C + * U+2DE0 - U+2DFF // Cyrillic Extended-A + * U+2E00 - U+2E7F // Supplemental Punctuation + * U+A640 - U+A69F // Cyrillic Extended-B + * U+A720 - U+A7FF // Latin Extended-D + * U+FB00 - U+FB06 // Alphab. Present. Forms (Latin Ligatures) + * U+1D400 - U+1D7FF // Mathematical Alphanumeric Symbols + * U+1F100 - U+1F1FF // Enclosed Alphanumeric Supplement + * ``` + * + * FT_AUTOHINTER_SCRIPT_CJK :: + * Apply the CJK auto-hinter, covering Chinese, Japanese, Korean, old + * Vietnamese, and some other scripts. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * ``` + * U+1100 - U+11FF // Hangul Jamo + * U+2E80 - U+2EFF // CJK Radicals Supplement + * U+2F00 - U+2FDF // Kangxi Radicals + * U+2FF0 - U+2FFF // Ideographic Description Characters + * U+3000 - U+303F // CJK Symbols and Punctuation + * U+3040 - U+309F // Hiragana + * U+30A0 - U+30FF // Katakana + * U+3100 - U+312F // Bopomofo + * U+3130 - U+318F // Hangul Compatibility Jamo + * U+3190 - U+319F // Kanbun + * U+31A0 - U+31BF // Bopomofo Extended + * U+31C0 - U+31EF // CJK Strokes + * U+31F0 - U+31FF // Katakana Phonetic Extensions + * U+3200 - U+32FF // Enclosed CJK Letters and Months + * U+3300 - U+33FF // CJK Compatibility + * U+3400 - U+4DBF // CJK Unified Ideographs Extension A + * U+4DC0 - U+4DFF // Yijing Hexagram Symbols + * U+4E00 - U+9FFF // CJK Unified Ideographs + * U+A960 - U+A97F // Hangul Jamo Extended-A + * U+AC00 - U+D7AF // Hangul Syllables + * U+D7B0 - U+D7FF // Hangul Jamo Extended-B + * U+F900 - U+FAFF // CJK Compatibility Ideographs + * U+FE10 - U+FE1F // Vertical forms + * U+FE30 - U+FE4F // CJK Compatibility Forms + * U+FF00 - U+FFEF // Halfwidth and Fullwidth Forms + * U+1B000 - U+1B0FF // Kana Supplement + * U+1D300 - U+1D35F // Tai Xuan Hing Symbols + * U+1F200 - U+1F2FF // Enclosed Ideographic Supplement + * U+20000 - U+2A6DF // CJK Unified Ideographs Extension B + * U+2A700 - U+2B73F // CJK Unified Ideographs Extension C + * U+2B740 - U+2B81F // CJK Unified Ideographs Extension D + * U+2F800 - U+2FA1F // CJK Compatibility Ideographs Supplement + * ``` + * + * FT_AUTOHINTER_SCRIPT_INDIC :: + * Apply the indic auto-hinter, covering all major scripts from the + * Indian sub-continent and some other related scripts like Thai, Lao, + * or Tibetan. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * ``` + * U+0900 - U+0DFF // Indic Range + * U+0F00 - U+0FFF // Tibetan + * U+1900 - U+194F // Limbu + * U+1B80 - U+1BBF // Sundanese + * U+A800 - U+A82F // Syloti Nagri + * U+ABC0 - U+ABFF // Meetei Mayek + * U+11800 - U+118DF // Sharada + * ``` + * + * Note that currently Indic support is rudimentary only, missing blue + * zone support. + * + * @since: + * 2.4.11 + * + */ +#define FT_AUTOHINTER_SCRIPT_NONE 0 +#define FT_AUTOHINTER_SCRIPT_LATIN 1 +#define FT_AUTOHINTER_SCRIPT_CJK 2 +#define FT_AUTOHINTER_SCRIPT_INDIC 3 + + + /************************************************************************** + * + * @struct: + * FT_Prop_GlyphToScriptMap + * + * @description: + * **Experimental only** + * + * The data exchange structure for the @glyph-to-script-map property. + * + * @since: + * 2.4.11 + * + */ + typedef struct FT_Prop_GlyphToScriptMap_ + { + FT_Face face; + FT_UShort* map; + + } FT_Prop_GlyphToScriptMap; + + + /************************************************************************** + * + * @property: + * fallback-script + * + * @description: + * **Experimental only** + * + * If no auto-hinter script module can be assigned to a glyph, a fallback + * script gets assigned to it (see also the @glyph-to-script-map + * property). By default, this is @FT_AUTOHINTER_SCRIPT_CJK. Using the + * `fallback-script` property, this fallback value can be changed. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * It's important to use the right timing for changing this value: The + * creation of the glyph-to-script map that eventually uses the fallback + * script value gets triggered either by setting or reading a + * face-specific property like @glyph-to-script-map, or by auto-hinting + * any glyph from that face. In particular, if you have already created + * an @FT_Face structure but not loaded any glyph (using the + * auto-hinter), a change of the fallback script will affect this face. + * + * @example: + * ``` + * FT_Library library; + * FT_UInt fallback_script = FT_AUTOHINTER_SCRIPT_NONE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "autofitter", + * "fallback-script", &fallback_script ); + * ``` + * + * @since: + * 2.4.11 + * + */ + + + /************************************************************************** + * + * @property: + * default-script + * + * @description: + * **Experimental only** + * + * If FreeType gets compiled with `FT_CONFIG_OPTION_USE_HARFBUZZ` to make + * the HarfBuzz library access OpenType features for getting better glyph + * coverages, this property sets the (auto-fitter) script to be used for + * the default (OpenType) script data of a font's GSUB table. Features + * for the default script are intended for all scripts not explicitly + * handled in GSUB; an example is a 'dlig' feature, containing the + * combination of the characters 'T', 'E', and 'L' to form a 'TEL' + * ligature. + * + * By default, this is @FT_AUTOHINTER_SCRIPT_LATIN. Using the + * `default-script` property, this default value can be changed. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * It's important to use the right timing for changing this value: The + * creation of the glyph-to-script map that eventually uses the default + * script value gets triggered either by setting or reading a + * face-specific property like @glyph-to-script-map, or by auto-hinting + * any glyph from that face. In particular, if you have already created + * an @FT_Face structure but not loaded any glyph (using the + * auto-hinter), a change of the default script will affect this face. + * + * @example: + * ``` + * FT_Library library; + * FT_UInt default_script = FT_AUTOHINTER_SCRIPT_NONE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "autofitter", + * "default-script", &default_script ); + * ``` + * + * @since: + * 2.5.3 + * + */ + + + /************************************************************************** + * + * @property: + * increase-x-height + * + * @description: + * For ppem values in the range 6~<= ppem <= `increase-x-height`, round + * up the font's x~height much more often than normally. If the value is + * set to~0, which is the default, this feature is switched off. Use + * this property to improve the legibility of small font sizes if + * necessary. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * Set this value right after calling @FT_Set_Char_Size, but before + * loading any glyph (using the auto-hinter). + * + * @example: + * ``` + * FT_Library library; + * FT_Face face; + * FT_Prop_IncreaseXHeight prop; + * + * + * FT_Init_FreeType( &library ); + * FT_New_Face( library, "foo.ttf", 0, &face ); + * FT_Set_Char_Size( face, 10 * 64, 0, 72, 0 ); + * + * prop.face = face; + * prop.limit = 14; + * + * FT_Property_Set( library, "autofitter", + * "increase-x-height", &prop ); + * ``` + * + * @since: + * 2.4.11 + * + */ + + + /************************************************************************** + * + * @struct: + * FT_Prop_IncreaseXHeight + * + * @description: + * The data exchange structure for the @increase-x-height property. + * + */ + typedef struct FT_Prop_IncreaseXHeight_ + { + FT_Face face; + FT_UInt limit; + + } FT_Prop_IncreaseXHeight; + + + /************************************************************************** + * + * @property: + * warping + * + * @description: + * **Obsolete** + * + * This property was always experimental and probably never worked + * correctly. It was entirely removed from the FreeType~2 sources. This + * entry is only here for historical reference. + * + * Warping only worked in 'normal' auto-hinting mode replacing it. The + * idea of the code was to slightly scale and shift a glyph along the + * non-hinted dimension (which is usually the horizontal axis) so that as + * much of its segments were aligned (more or less) to the grid. To find + * out a glyph's optimal scaling and shifting value, various parameter + * combinations were tried and scored. + * + * @since: + * 2.6 + * + */ + + + /* */ + + +FT_END_HEADER + + +#endif /* FTDRIVER_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/fterrdef.h b/vendor/freetype/include/freetype/fterrdef.h new file mode 100644 index 0000000..d59b3cc --- /dev/null +++ b/vendor/freetype/include/freetype/fterrdef.h @@ -0,0 +1,283 @@ +/**************************************************************************** + * + * fterrdef.h + * + * FreeType error codes (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * @section: + * error_code_values + * + * @title: + * Error Code Values + * + * @abstract: + * All possible error codes returned by FreeType functions. + * + * @description: + * The list below is taken verbatim from the file `fterrdef.h` (loaded + * automatically by including `FT_FREETYPE_H`). The first argument of the + * `FT_ERROR_DEF_` macro is the error label; by default, the prefix + * `FT_Err_` gets added so that you get error names like + * `FT_Err_Cannot_Open_Resource`. The second argument is the error code, + * and the last argument an error string, which is not used by FreeType. + * + * Within your application you should **only** use error names and + * **never** its numeric values! The latter might (and actually do) + * change in forthcoming FreeType versions. + * + * Macro `FT_NOERRORDEF_` defines `FT_Err_Ok`, which is always zero. See + * the 'Error Enumerations' subsection how to automatically generate a + * list of error strings. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_Err_XXX + * + */ + + /* generic errors */ + + FT_NOERRORDEF_( Ok, 0x00, + "no error" ) + + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, + "missing property" ) + + /* glyph/character errors */ + + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, + "invalid pixel size" ) + FT_ERRORDEF_( Invalid_SVG_Document, 0x18, + "invalid SVG document" ) + + /* handle errors */ + + FT_ERRORDEF_( Invalid_Handle, 0x20, + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, + "invalid stream handle" ) + + /* driver errors */ + + FT_ERRORDEF_( Too_Many_Drivers, 0x30, + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, + "too many extensions" ) + + /* memory errors */ + + FT_ERRORDEF_( Out_Of_Memory, 0x40, + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, + "unlisted object" ) + + /* stream errors */ + + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, + "invalid frame read" ) + + /* raster errors */ + + FT_ERRORDEF_( Raster_Uninitialized, 0x60, + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, + "negative height while rastering" ) + + /* cache errors */ + + FT_ERRORDEF_( Too_Many_Caches, 0x70, + "too many registered caches" ) + + /* TrueType and SFNT errors */ + + FT_ERRORDEF_( Invalid_Opcode, 0x80, + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, + "invalid PostScript (post) table" ) + FT_ERRORDEF_( DEF_In_Glyf_Bytecode, 0x9C, + "found FDEF or IDEF opcode in glyf bytecode" ) + FT_ERRORDEF_( Missing_Bitmap, 0x9D, + "missing bitmap in strike" ) + FT_ERRORDEF_( Missing_SVG_Hooks, 0x9E, + "SVG hooks have not been set" ) + + /* CFF, CID, and Type 1 errors */ + + FT_ERRORDEF_( Syntax_Error, 0xA0, + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, + "no Unicode glyph name found" ) + FT_ERRORDEF_( Glyph_Too_Big, 0xA4, + "glyph too big for hinting" ) + + /* BDF errors */ + + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, + "Font glyphs corrupted or missing fields" ) + + /* */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/fterrors.h b/vendor/freetype/include/freetype/fterrors.h new file mode 100644 index 0000000..15ef3f7 --- /dev/null +++ b/vendor/freetype/include/freetype/fterrors.h @@ -0,0 +1,296 @@ +/**************************************************************************** + * + * fterrors.h + * + * FreeType error code handling (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * @section: + * error_enumerations + * + * @title: + * Error Enumerations + * + * @abstract: + * How to handle errors and error strings. + * + * @description: + * The header file `fterrors.h` (which is automatically included by + * `freetype.h`) defines the handling of FreeType's enumeration + * constants. It can also be used to generate error message strings + * with a small macro trick explained below. + * + * **Error Formats** + * + * The configuration macro `FT_CONFIG_OPTION_USE_MODULE_ERRORS` can be + * defined in `ftoption.h` in order to make the higher byte indicate the + * module where the error has happened (this is not compatible with + * standard builds of FreeType~2, however). See the file `ftmoderr.h` + * for more details. + * + * **Error Message Strings** + * + * Error definitions are set up with special macros that allow client + * applications to build a table of error message strings. The strings + * are not included in a normal build of FreeType~2 to save space (most + * client applications do not use them). + * + * To do so, you have to define the following macros before including + * this file. + * + * ``` + * FT_ERROR_START_LIST + * ``` + * + * This macro is called before anything else to define the start of the + * error list. It is followed by several `FT_ERROR_DEF` calls. + * + * ``` + * FT_ERROR_DEF( e, v, s ) + * ``` + * + * This macro is called to define one single error. 'e' is the error + * code identifier (e.g., `Invalid_Argument`), 'v' is the error's + * numerical value, and 's' is the corresponding error string. + * + * ``` + * FT_ERROR_END_LIST + * ``` + * + * This macro ends the list. + * + * Additionally, you have to undefine `FTERRORS_H_` before #including + * this file. + * + * Here is a simple example. + * + * ``` + * #undef FTERRORS_H_ + * #define FT_ERRORDEF( e, v, s ) { e, s }, + * #define FT_ERROR_START_LIST { + * #define FT_ERROR_END_LIST { 0, NULL } }; + * + * const struct + * { + * int err_code; + * const char* err_msg; + * } ft_errors[] = + * + * #include + * ``` + * + * An alternative to using an array is a switch statement. + * + * ``` + * #undef FTERRORS_H_ + * #define FT_ERROR_START_LIST switch ( error_code ) { + * #define FT_ERRORDEF( e, v, s ) case v: return s; + * #define FT_ERROR_END_LIST } + * ``` + * + * If you use `FT_CONFIG_OPTION_USE_MODULE_ERRORS`, `error_code` should + * be replaced with `FT_ERROR_BASE(error_code)` in the last example. + */ + + /* */ + + /* In previous FreeType versions we used `__FTERRORS_H__`. However, */ + /* using two successive underscores in a non-system symbol name */ + /* violates the C (and C++) standard, so it was changed to the */ + /* current form. In spite of this, we have to make */ + /* */ + /* ``` */ + /* #undefine __FTERRORS_H__ */ + /* ``` */ + /* */ + /* work for backward compatibility. */ + /* */ +#if !( defined( FTERRORS_H_ ) && defined ( __FTERRORS_H__ ) ) +#define FTERRORS_H_ +#define __FTERRORS_H__ + + + /* include module base error codes */ +#include + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + + + /* FT_ERR_PREFIX is used as a prefix for error identifiers. */ + /* By default, we use `FT_Err_`. */ + /* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif + + + /* FT_ERR_BASE is used as the base for module-specific errors. */ + /* */ +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS + +#ifndef FT_ERR_BASE +#define FT_ERR_BASE FT_Mod_Err_Base +#endif + +#else + +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 + +#endif /* FT_CONFIG_OPTION_USE_MODULE_ERRORS */ + + + /* If FT_ERRORDEF is not defined, we need to define a simple */ + /* enumeration type. */ + /* */ +#ifndef FT_ERRORDEF + +#define FT_INCLUDE_ERR_PROTOS + +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_ERRORDEF */ + + + /* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) + + /* this is only used for _Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) + + +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif + + + /* now include the error codes */ +#include + + +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SIMPLE CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST + +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ + +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE + + /* FT_ERR_PREFIX is needed internally */ +#ifndef FT2_BUILD_LIBRARY +#undef FT_ERR_PREFIX +#endif + + /* FT_INCLUDE_ERR_PROTOS: Control whether function prototypes should be */ + /* included with */ + /* */ + /* #include */ + /* */ + /* This is only true where `FT_ERRORDEF` is */ + /* undefined. */ + /* */ + /* FT_ERR_PROTOS_DEFINED: Actual multiple-inclusion protection of */ + /* `fterrors.h`. */ +#ifdef FT_INCLUDE_ERR_PROTOS +#undef FT_INCLUDE_ERR_PROTOS + +#ifndef FT_ERR_PROTOS_DEFINED +#define FT_ERR_PROTOS_DEFINED + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @function: + * FT_Error_String + * + * @description: + * Retrieve the description of a valid FreeType error code. + * + * @input: + * error_code :: + * A valid FreeType error code. + * + * @return: + * A C~string or `NULL`, if any error occurred. + * + * @note: + * FreeType has to be compiled with `FT_CONFIG_OPTION_ERROR_STRINGS` or + * `FT_DEBUG_LEVEL_ERROR` to get meaningful descriptions. + * 'error_string' will be `NULL` otherwise. + * + * Module identification will be ignored: + * + * ```c + * strcmp( FT_Error_String( FT_Err_Unknown_File_Format ), + * FT_Error_String( BDF_Err_Unknown_File_Format ) ) == 0; + * ``` + */ + FT_EXPORT( const char* ) + FT_Error_String( FT_Error error_code ); + + /* */ + +FT_END_HEADER + + +#endif /* FT_ERR_PROTOS_DEFINED */ + +#endif /* FT_INCLUDE_ERR_PROTOS */ + +#endif /* !(FTERRORS_H_ && __FTERRORS_H__) */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftfntfmt.h b/vendor/freetype/include/freetype/ftfntfmt.h new file mode 100644 index 0000000..c0018fc --- /dev/null +++ b/vendor/freetype/include/freetype/ftfntfmt.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * + * ftfntfmt.h + * + * Support functions for font formats. + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTFNTFMT_H_ +#define FTFNTFMT_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * font_formats + * + * @title: + * Font Formats + * + * @abstract: + * Getting the font format. + * + * @description: + * The single function in this section can be used to get the font format. + * Note that this information is not needed normally; however, there are + * special cases (like in PDF devices) where it is important to + * differentiate, in spite of FreeType's uniform API. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Get_Font_Format + * + * @description: + * Return a string describing the format of a given face. Possible values + * are 'TrueType', 'Type~1', 'BDF', 'PCF', 'Type~42', 'CID~Type~1', 'CFF', + * 'PFR', and 'Windows~FNT'. + * + * The return value is suitable to be used as an X11 FONT_PROPERTY. + * + * @input: + * face :: + * Input face handle. + * + * @return: + * Font format string. `NULL` in case of error. + * + * @note: + * A deprecated name for the same function is `FT_Get_X11_Font_Format`. + */ + FT_EXPORT( const char* ) + FT_Get_Font_Format( FT_Face face ); + + + /* deprecated */ + FT_EXPORT( const char* ) + FT_Get_X11_Font_Format( FT_Face face ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTFNTFMT_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftgasp.h b/vendor/freetype/include/freetype/ftgasp.h new file mode 100644 index 0000000..d5f19ad --- /dev/null +++ b/vendor/freetype/include/freetype/ftgasp.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * + * ftgasp.h + * + * Access of TrueType's 'gasp' table (specification). + * + * Copyright (C) 2007-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGASP_H_ +#define FTGASP_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * gasp_table + * + * @title: + * Gasp Table + * + * @abstract: + * Retrieving TrueType 'gasp' table entries. + * + * @description: + * The function @FT_Get_Gasp can be used to query a TrueType or OpenType + * font for specific entries in its 'gasp' table, if any. This is mainly + * useful when implementing native TrueType hinting with the bytecode + * interpreter to duplicate the Windows text rendering results. + */ + + /************************************************************************** + * + * @enum: + * FT_GASP_XXX + * + * @description: + * A list of values and/or bit-flags returned by the @FT_Get_Gasp + * function. + * + * @values: + * FT_GASP_NO_TABLE :: + * This special value means that there is no GASP table in this face. + * It is up to the client to decide what to do. + * + * FT_GASP_DO_GRIDFIT :: + * Grid-fitting and hinting should be performed at the specified ppem. + * This **really** means TrueType bytecode interpretation. If this bit + * is not set, no hinting gets applied. + * + * FT_GASP_DO_GRAY :: + * Anti-aliased rendering should be performed at the specified ppem. + * If not set, do monochrome rendering. + * + * FT_GASP_SYMMETRIC_SMOOTHING :: + * If set, smoothing along multiple axes must be used with ClearType. + * + * FT_GASP_SYMMETRIC_GRIDFIT :: + * Grid-fitting must be used with ClearType's symmetric smoothing. + * + * @note: + * The bit-flags `FT_GASP_DO_GRIDFIT` and `FT_GASP_DO_GRAY` are to be + * used for standard font rasterization only. Independently of that, + * `FT_GASP_SYMMETRIC_SMOOTHING` and `FT_GASP_SYMMETRIC_GRIDFIT` are to + * be used if ClearType is enabled (and `FT_GASP_DO_GRIDFIT` and + * `FT_GASP_DO_GRAY` are consequently ignored). + * + * 'ClearType' is Microsoft's implementation of LCD rendering, partly + * protected by patents. + * + * @since: + * 2.3.0 + */ +#define FT_GASP_NO_TABLE -1 +#define FT_GASP_DO_GRIDFIT 0x01 +#define FT_GASP_DO_GRAY 0x02 +#define FT_GASP_SYMMETRIC_GRIDFIT 0x04 +#define FT_GASP_SYMMETRIC_SMOOTHING 0x08 + + + /************************************************************************** + * + * @function: + * FT_Get_Gasp + * + * @description: + * For a TrueType or OpenType font file, return the rasterizer behaviour + * flags from the font's 'gasp' table corresponding to a given character + * pixel size. + * + * @input: + * face :: + * The source face handle. + * + * ppem :: + * The vertical character pixel size. + * + * @return: + * Bit flags (see @FT_GASP_XXX), or @FT_GASP_NO_TABLE if there is no + * 'gasp' table in the face. + * + * @note: + * If you want to use the MM functionality of OpenType variation fonts + * (i.e., using @FT_Set_Var_Design_Coordinates and friends), call this + * function **after** setting an instance since the return values can + * change. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGASP_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftglyph.h b/vendor/freetype/include/freetype/ftglyph.h new file mode 100644 index 0000000..4658895 --- /dev/null +++ b/vendor/freetype/include/freetype/ftglyph.h @@ -0,0 +1,750 @@ +/**************************************************************************** + * + * ftglyph.h + * + * FreeType convenience functions to handle glyphs (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file contains the definition of several convenience functions that + * can be used by client applications to easily retrieve glyph bitmaps and + * outlines from a given face. + * + * These functions should be optional if you are writing a font server or + * text layout engine on top of FreeType. However, they are pretty handy + * for many other simple uses of the library. + * + */ + + +#ifndef FTGLYPH_H_ +#define FTGLYPH_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * glyph_management + * + * @title: + * Glyph Management + * + * @abstract: + * Generic interface to manage individual glyph data. + * + * @description: + * This section contains definitions used to manage glyph data through + * generic @FT_Glyph objects. Each of them can contain a bitmap, + * a vector outline, or even images in other formats. These objects are + * detached from @FT_Face, contrary to @FT_GlyphSlot. + * + */ + + + /* forward declaration to a private type */ + typedef struct FT_Glyph_Class_ FT_Glyph_Class; + + + /************************************************************************** + * + * @type: + * FT_Glyph + * + * @description: + * Handle to an object used to model generic glyph images. It is a + * pointer to the @FT_GlyphRec structure and can contain a glyph bitmap + * or pointer. + * + * @note: + * Glyph objects are not owned by the library. You must thus release + * them manually (through @FT_Done_Glyph) _before_ calling + * @FT_Done_FreeType. + */ + typedef struct FT_GlyphRec_* FT_Glyph; + + + /************************************************************************** + * + * @struct: + * FT_GlyphRec + * + * @description: + * The root glyph structure contains a given glyph image plus its advance + * width in 16.16 fixed-point format. + * + * @fields: + * library :: + * A handle to the FreeType library object. + * + * clazz :: + * A pointer to the glyph's class. Private. + * + * format :: + * The format of the glyph's image. + * + * advance :: + * A 16.16 vector that gives the glyph's advance width. + */ + typedef struct FT_GlyphRec_ + { + FT_Library library; + const FT_Glyph_Class* clazz; + FT_Glyph_Format format; + FT_Vector advance; + + } FT_GlyphRec; + + + /************************************************************************** + * + * @type: + * FT_BitmapGlyph + * + * @description: + * A handle to an object used to model a bitmap glyph image. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. + */ + typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; + + + /************************************************************************** + * + * @struct: + * FT_BitmapGlyphRec + * + * @description: + * A structure used for bitmap glyph images. This really is a + * 'sub-class' of @FT_GlyphRec. + * + * @fields: + * root :: + * The root fields of @FT_Glyph. + * + * left :: + * The left-side bearing, i.e., the horizontal distance from the + * current pen position to the left border of the glyph bitmap. + * + * top :: + * The top-side bearing, i.e., the vertical distance from the current + * pen position to the top border of the glyph bitmap. This distance + * is positive for upwards~y! + * + * bitmap :: + * A descriptor for the bitmap. + * + * @note: + * You can typecast an @FT_Glyph to @FT_BitmapGlyph if you have + * `glyph->format == FT_GLYPH_FORMAT_BITMAP`. This lets you access the + * bitmap's contents easily. + * + * The corresponding pixel buffer is always owned by @FT_BitmapGlyph and + * is thus created and destroyed with it. + */ + typedef struct FT_BitmapGlyphRec_ + { + FT_GlyphRec root; + FT_Int left; + FT_Int top; + FT_Bitmap bitmap; + + } FT_BitmapGlyphRec; + + + /************************************************************************** + * + * @type: + * FT_OutlineGlyph + * + * @description: + * A handle to an object used to model an outline glyph image. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. + */ + typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; + + + /************************************************************************** + * + * @struct: + * FT_OutlineGlyphRec + * + * @description: + * A structure used for outline (vectorial) glyph images. This really is + * a 'sub-class' of @FT_GlyphRec. + * + * @fields: + * root :: + * The root @FT_Glyph fields. + * + * outline :: + * A descriptor for the outline. + * + * @note: + * You can typecast an @FT_Glyph to @FT_OutlineGlyph if you have + * `glyph->format == FT_GLYPH_FORMAT_OUTLINE`. This lets you access the + * outline's content easily. + * + * As the outline is extracted from a glyph slot, its coordinates are + * expressed normally in 26.6 pixels, unless the flag @FT_LOAD_NO_SCALE + * was used in @FT_Load_Glyph or @FT_Load_Char. + * + * The outline's tables are always owned by the object and are destroyed + * with it. + */ + typedef struct FT_OutlineGlyphRec_ + { + FT_GlyphRec root; + FT_Outline outline; + + } FT_OutlineGlyphRec; + + + /************************************************************************** + * + * @type: + * FT_SvgGlyph + * + * @description: + * A handle to an object used to model an SVG glyph. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_SvgGlyphRec. + * + * @since: + * 2.12 + */ + typedef struct FT_SvgGlyphRec_* FT_SvgGlyph; + + + /************************************************************************** + * + * @struct: + * FT_SvgGlyphRec + * + * @description: + * A structure used for OT-SVG glyphs. This is a 'sub-class' of + * @FT_GlyphRec. + * + * @fields: + * root :: + * The root @FT_GlyphRec fields. + * + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * glyph_index :: + * The index of the glyph to be rendered. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * Translation to apply to the glyph while rendering. + * + * @note: + * The Glyph Management API requires @FT_Glyph or its 'sub-class' to have + * all the information needed to completely define the glyph's rendering. + * Outline-based glyphs can directly apply transformations to the outline + * but this is not possible for an SVG document that hasn't been parsed. + * Therefore, the transformation is stored along with the document. In + * the absence of a 'ViewBox' or 'Width'/'Height' attribute, the size of + * the ViewPort should be assumed to be 'units_per_EM'. + */ + typedef struct FT_SvgGlyphRec_ + { + FT_GlyphRec root; + + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_UInt glyph_index; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SvgGlyphRec; + + + /************************************************************************** + * + * @function: + * FT_New_Glyph + * + * @description: + * A function used to create a new empty glyph image. Note that the + * created @FT_Glyph object must be released with @FT_Done_Glyph. + * + * @input: + * library :: + * A handle to the FreeType library object. + * + * format :: + * The format of the glyph's image. + * + * @output: + * aglyph :: + * A handle to the glyph object. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_New_Glyph( FT_Library library, + FT_Glyph_Format format, + FT_Glyph *aglyph ); + + + /************************************************************************** + * + * @function: + * FT_Get_Glyph + * + * @description: + * A function used to extract a glyph image from a slot. Note that the + * created @FT_Glyph object must be released with @FT_Done_Glyph. + * + * @input: + * slot :: + * A handle to the source glyph slot. + * + * @output: + * aglyph :: + * A handle to the glyph object. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Because `*aglyph->advance.x` and `*aglyph->advance.y` are 16.16 + * fixed-point numbers, `slot->advance.x` and `slot->advance.y` (which + * are in 26.6 fixed-point format) must be in the range ]-32768;32768[. + */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_Copy + * + * @description: + * A function used to copy a glyph image. Note that the created + * @FT_Glyph object must be released with @FT_Done_Glyph. + * + * @input: + * source :: + * A handle to the source glyph object. + * + * @output: + * target :: + * A handle to the target glyph object. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_Transform + * + * @description: + * Transform a glyph image if its format is scalable. + * + * @inout: + * glyph :: + * A handle to the target glyph object. + * + * @input: + * matrix :: + * A pointer to a 2x2 matrix to apply. + * + * delta :: + * A pointer to a 2d vector to apply. Coordinates are expressed in + * 1/64 of a pixel. + * + * @return: + * FreeType error code (if not 0, the glyph format is not scalable). + * + * @note: + * The 2x2 transformation matrix is also applied to the glyph's advance + * vector. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + + /************************************************************************** + * + * @enum: + * FT_Glyph_BBox_Mode + * + * @description: + * The mode how the values of @FT_Glyph_Get_CBox are returned. + * + * @values: + * FT_GLYPH_BBOX_UNSCALED :: + * Return unscaled font units. + * + * FT_GLYPH_BBOX_SUBPIXELS :: + * Return unfitted 26.6 coordinates. + * + * FT_GLYPH_BBOX_GRIDFIT :: + * Return grid-fitted 26.6 coordinates. + * + * FT_GLYPH_BBOX_TRUNCATE :: + * Return coordinates in integer pixels. + * + * FT_GLYPH_BBOX_PIXELS :: + * Return grid-fitted pixel coordinates. + */ + typedef enum FT_Glyph_BBox_Mode_ + { + FT_GLYPH_BBOX_UNSCALED = 0, + FT_GLYPH_BBOX_SUBPIXELS = 0, + FT_GLYPH_BBOX_GRIDFIT = 1, + FT_GLYPH_BBOX_TRUNCATE = 2, + FT_GLYPH_BBOX_PIXELS = 3 + + } FT_Glyph_BBox_Mode; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Glyph_BBox_Mode` values instead */ +#define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED +#define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS +#define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT +#define ft_glyph_bbox_truncate FT_GLYPH_BBOX_TRUNCATE +#define ft_glyph_bbox_pixels FT_GLYPH_BBOX_PIXELS + + + /************************************************************************** + * + * @function: + * FT_Glyph_Get_CBox + * + * @description: + * Return a glyph's 'control box'. The control box encloses all the + * outline's points, including Bezier control points. Though it + * coincides with the exact bounding box for most glyphs, it can be + * slightly larger in some situations (like when rotating an outline that + * contains Bezier outside arcs). + * + * Computing the control box is very fast, while getting the bounding box + * can take much more time as it needs to walk over all segments and arcs + * in the outline. To get the latter, you can use the 'ftbbox' + * component, which is dedicated to this single task. + * + * @input: + * glyph :: + * A handle to the source glyph object. + * + * mode :: + * The mode that indicates how to interpret the returned bounding box + * values. + * + * @output: + * acbox :: + * The glyph coordinate bounding box. Coordinates are expressed in + * 1/64 of pixels if it is grid-fitted. + * + * @note: + * Coordinates are relative to the glyph origin, using the y~upwards + * convention. + * + * If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode` must + * be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font units in 26.6 + * pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS is another name for + * this constant. + * + * If the font is tricky and the glyph has been loaded with + * @FT_LOAD_NO_SCALE, the resulting CBox is meaningless. To get + * reasonable values for the CBox it is necessary to load the glyph at a + * large ppem value (so that the hinting instructions can properly shift + * and scale the subglyphs), then extracting the CBox, which can be + * eventually converted back to font units. + * + * Note that the maximum coordinates are exclusive, which means that one + * can compute the width and height of the glyph image (be it in integer + * or 26.6 pixels) as: + * + * ``` + * width = bbox.xMax - bbox.xMin; + * height = bbox.yMax - bbox.yMin; + * ``` + * + * Note also that for 26.6 coordinates, if `bbox_mode` is set to + * @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, + * which corresponds to: + * + * ``` + * bbox.xMin = FLOOR(bbox.xMin); + * bbox.yMin = FLOOR(bbox.yMin); + * bbox.xMax = CEILING(bbox.xMax); + * bbox.yMax = CEILING(bbox.yMax); + * ``` + * + * To get the bbox in pixel coordinates, set `bbox_mode` to + * @FT_GLYPH_BBOX_TRUNCATE. + * + * To get the bbox in grid-fitted pixel coordinates, set `bbox_mode` to + * @FT_GLYPH_BBOX_PIXELS. + */ + FT_EXPORT( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_To_Bitmap + * + * @description: + * Convert a given glyph object to a bitmap glyph object. + * + * @inout: + * the_glyph :: + * A pointer to a handle to the target glyph. + * + * @input: + * render_mode :: + * An enumeration that describes how the data is rendered. + * + * origin :: + * A pointer to a vector used to translate the glyph image before + * rendering. Can be~0 (if no translation). The origin is expressed + * in 26.6 pixels. + * + * destroy :: + * A boolean that indicates that the original glyph image should be + * destroyed by this function. It is never destroyed in case of error. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function does nothing if the glyph format isn't scalable. + * + * The glyph image is translated with the `origin` vector before + * rendering. + * + * The first parameter is a pointer to an @FT_Glyph handle that will be + * _replaced_ by this function (with newly allocated data). Typically, + * you would do something like the following (omitting error handling). + * + * ``` + * FT_Glyph glyph; + * FT_BitmapGlyph glyph_bitmap; + * + * + * // load glyph + * error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAULT ); + * + * // extract glyph image + * error = FT_Get_Glyph( face->glyph, &glyph ); + * + * // convert to a bitmap (default render mode + destroying old) + * if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) + * { + * error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, + * 0, 1 ); + * if ( error ) // `glyph' unchanged + * ... + * } + * + * // access bitmap content by typecasting + * glyph_bitmap = (FT_BitmapGlyph)glyph; + * + * // do funny stuff with it, like blitting/drawing + * ... + * + * // discard glyph image (bitmap or not) + * FT_Done_Glyph( glyph ); + * ``` + * + * Here is another example, again without error handling. + * + * ``` + * FT_Glyph glyphs[MAX_GLYPHS] + * + * + * ... + * + * for ( idx = 0; i < MAX_GLYPHS; i++ ) + * error = FT_Load_Glyph( face, idx, FT_LOAD_DEFAULT ) || + * FT_Get_Glyph ( face->glyph, &glyphs[idx] ); + * + * ... + * + * for ( idx = 0; i < MAX_GLYPHS; i++ ) + * { + * FT_Glyph bitmap = glyphs[idx]; + * + * + * ... + * + * // after this call, `bitmap' no longer points into + * // the `glyphs' array (and the old value isn't destroyed) + * FT_Glyph_To_Bitmap( &bitmap, FT_RENDER_MODE_MONO, 0, 0 ); + * + * ... + * + * FT_Done_Glyph( bitmap ); + * } + * + * ... + * + * for ( idx = 0; i < MAX_GLYPHS; i++ ) + * FT_Done_Glyph( glyphs[idx] ); + * ``` + */ + FT_EXPORT( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ); + + + /************************************************************************** + * + * @function: + * FT_Done_Glyph + * + * @description: + * Destroy a given glyph. + * + * @input: + * glyph :: + * A handle to the target glyph object. Can be `NULL`. + */ + FT_EXPORT( void ) + FT_Done_Glyph( FT_Glyph glyph ); + + /* */ + + + /* other helpful functions */ + + /************************************************************************** + * + * @section: + * computations + * + */ + + + /************************************************************************** + * + * @function: + * FT_Matrix_Multiply + * + * @description: + * Perform the matrix operation `b = a*b`. + * + * @input: + * a :: + * A pointer to matrix `a`. + * + * @inout: + * b :: + * A pointer to matrix `b`. + * + * @note: + * The result is undefined if either `a` or `b` is zero. + * + * Since the function uses wrap-around arithmetic, results become + * meaningless if the arguments are very large. + */ + FT_EXPORT( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix* b ); + + + /************************************************************************** + * + * @function: + * FT_Matrix_Invert + * + * @description: + * Invert a 2x2 matrix. Return an error if it can't be inverted. + * + * @inout: + * matrix :: + * A pointer to the target matrix. Remains untouched in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGLYPH_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/vendor/freetype/include/freetype/ftgxval.h b/vendor/freetype/include/freetype/ftgxval.h new file mode 100644 index 0000000..e8de9a6 --- /dev/null +++ b/vendor/freetype/include/freetype/ftgxval.h @@ -0,0 +1,354 @@ +/**************************************************************************** + * + * ftgxval.h + * + * FreeType API for validating TrueTypeGX/AAT tables (specification). + * + * Copyright (C) 2004-2023 by + * Masatake YAMATO, Redhat K.K, + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef FTGXVAL_H_ +#define FTGXVAL_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * gx_validation + * + * @title: + * TrueTypeGX/AAT Validation + * + * @abstract: + * An API to validate TrueTypeGX/AAT tables. + * + * @description: + * This section contains the declaration of functions to validate some + * TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd, trak, + * prop, lcar). + * + * @order: + * FT_TrueTypeGX_Validate + * FT_TrueTypeGX_Free + * + * FT_ClassicKern_Validate + * FT_ClassicKern_Free + * + * FT_VALIDATE_GX_LENGTH + * FT_VALIDATE_GXXXX + * FT_VALIDATE_CKERNXXX + * + */ + + /************************************************************************** + * + * + * Warning: Use `FT_VALIDATE_XXX` to validate a table. + * Following definitions are for gxvalid developers. + * + * + */ + +#define FT_VALIDATE_feat_INDEX 0 +#define FT_VALIDATE_mort_INDEX 1 +#define FT_VALIDATE_morx_INDEX 2 +#define FT_VALIDATE_bsln_INDEX 3 +#define FT_VALIDATE_just_INDEX 4 +#define FT_VALIDATE_kern_INDEX 5 +#define FT_VALIDATE_opbd_INDEX 6 +#define FT_VALIDATE_trak_INDEX 7 +#define FT_VALIDATE_prop_INDEX 8 +#define FT_VALIDATE_lcar_INDEX 9 +#define FT_VALIDATE_GX_LAST_INDEX FT_VALIDATE_lcar_INDEX + + + /************************************************************************** + * + * @macro: + * FT_VALIDATE_GX_LENGTH + * + * @description: + * The number of tables checked in this module. Use it as a parameter + * for the `table-length` argument of function @FT_TrueTypeGX_Validate. + */ +#define FT_VALIDATE_GX_LENGTH ( FT_VALIDATE_GX_LAST_INDEX + 1 ) + + /* */ + + /* Up to 0x1000 is used by otvalid. + Ox2xxx is reserved for feature OT extension. */ +#define FT_VALIDATE_GX_START 0x4000 +#define FT_VALIDATE_GX_BITFIELD( tag ) \ + ( FT_VALIDATE_GX_START << FT_VALIDATE_##tag##_INDEX ) + + + /************************************************************************** + * + * @enum: + * FT_VALIDATE_GXXXX + * + * @description: + * A list of bit-field constants used with @FT_TrueTypeGX_Validate to + * indicate which TrueTypeGX/AAT Type tables should be validated. + * + * @values: + * FT_VALIDATE_feat :: + * Validate 'feat' table. + * + * FT_VALIDATE_mort :: + * Validate 'mort' table. + * + * FT_VALIDATE_morx :: + * Validate 'morx' table. + * + * FT_VALIDATE_bsln :: + * Validate 'bsln' table. + * + * FT_VALIDATE_just :: + * Validate 'just' table. + * + * FT_VALIDATE_kern :: + * Validate 'kern' table. + * + * FT_VALIDATE_opbd :: + * Validate 'opbd' table. + * + * FT_VALIDATE_trak :: + * Validate 'trak' table. + * + * FT_VALIDATE_prop :: + * Validate 'prop' table. + * + * FT_VALIDATE_lcar :: + * Validate 'lcar' table. + * + * FT_VALIDATE_GX :: + * Validate all TrueTypeGX tables (feat, mort, morx, bsln, just, kern, + * opbd, trak, prop and lcar). + * + */ + +#define FT_VALIDATE_feat FT_VALIDATE_GX_BITFIELD( feat ) +#define FT_VALIDATE_mort FT_VALIDATE_GX_BITFIELD( mort ) +#define FT_VALIDATE_morx FT_VALIDATE_GX_BITFIELD( morx ) +#define FT_VALIDATE_bsln FT_VALIDATE_GX_BITFIELD( bsln ) +#define FT_VALIDATE_just FT_VALIDATE_GX_BITFIELD( just ) +#define FT_VALIDATE_kern FT_VALIDATE_GX_BITFIELD( kern ) +#define FT_VALIDATE_opbd FT_VALIDATE_GX_BITFIELD( opbd ) +#define FT_VALIDATE_trak FT_VALIDATE_GX_BITFIELD( trak ) +#define FT_VALIDATE_prop FT_VALIDATE_GX_BITFIELD( prop ) +#define FT_VALIDATE_lcar FT_VALIDATE_GX_BITFIELD( lcar ) + +#define FT_VALIDATE_GX ( FT_VALIDATE_feat | \ + FT_VALIDATE_mort | \ + FT_VALIDATE_morx | \ + FT_VALIDATE_bsln | \ + FT_VALIDATE_just | \ + FT_VALIDATE_kern | \ + FT_VALIDATE_opbd | \ + FT_VALIDATE_trak | \ + FT_VALIDATE_prop | \ + FT_VALIDATE_lcar ) + + + /************************************************************************** + * + * @function: + * FT_TrueTypeGX_Validate + * + * @description: + * Validate various TrueTypeGX tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library that + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field that specifies the tables to be validated. See + * @FT_VALIDATE_GXXXX for possible values. + * + * table_length :: + * The size of the `tables` array. Normally, @FT_VALIDATE_GX_LENGTH + * should be passed. + * + * @output: + * tables :: + * The array where all validated sfnt tables are stored. The array + * itself must be allocated by a client. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with TrueTypeGX fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the buffers pointed to by + * each `tables` element, by calling @FT_TrueTypeGX_Free. A `NULL` value + * indicates that the table either doesn't exist in the font, the + * application hasn't asked for validation, or the validator doesn't have + * the ability to validate the sfnt table. + */ + FT_EXPORT( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + /************************************************************************** + * + * @function: + * FT_TrueTypeGX_Free + * + * @description: + * Free the buffer allocated by TrueTypeGX validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer allocated by @FT_TrueTypeGX_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_TrueTypeGX_Validate only. + */ + FT_EXPORT( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ); + + + /************************************************************************** + * + * @enum: + * FT_VALIDATE_CKERNXXX + * + * @description: + * A list of bit-field constants used with @FT_ClassicKern_Validate to + * indicate the classic kern dialect or dialects. If the selected type + * doesn't fit, @FT_ClassicKern_Validate regards the table as invalid. + * + * @values: + * FT_VALIDATE_MS :: + * Handle the 'kern' table as a classic Microsoft kern table. + * + * FT_VALIDATE_APPLE :: + * Handle the 'kern' table as a classic Apple kern table. + * + * FT_VALIDATE_CKERN :: + * Handle the 'kern' as either classic Apple or Microsoft kern table. + */ +#define FT_VALIDATE_MS ( FT_VALIDATE_GX_START << 0 ) +#define FT_VALIDATE_APPLE ( FT_VALIDATE_GX_START << 1 ) + +#define FT_VALIDATE_CKERN ( FT_VALIDATE_MS | FT_VALIDATE_APPLE ) + + + /************************************************************************** + * + * @function: + * FT_ClassicKern_Validate + * + * @description: + * Validate classic (16-bit format) kern table to assure that the + * offsets and indices are valid. The idea is that a higher-level + * library that actually does the text layout can access those tables + * without error checking (which can be quite time consuming). + * + * The 'kern' table validator in @FT_TrueTypeGX_Validate deals with both + * the new 32-bit format and the classic 16-bit format, while + * FT_ClassicKern_Validate only supports the classic 16-bit format. + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field that specifies the dialect to be validated. See + * @FT_VALIDATE_CKERNXXX for possible values. + * + * @output: + * ckern_table :: + * A pointer to the kern table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * After use, the application should deallocate the buffers pointed to by + * `ckern_table`, by calling @FT_ClassicKern_Free. A `NULL` value + * indicates that the table doesn't exist in the font. + */ + FT_EXPORT( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ); + + + /************************************************************************** + * + * @function: + * FT_ClassicKern_Free + * + * @description: + * Free the buffer allocated by classic Kern validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_ClassicKern_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_ClassicKern_Validate only. + */ + FT_EXPORT( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGXVAL_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftgzip.h b/vendor/freetype/include/freetype/ftgzip.h new file mode 100644 index 0000000..443ec29 --- /dev/null +++ b/vendor/freetype/include/freetype/ftgzip.h @@ -0,0 +1,151 @@ +/**************************************************************************** + * + * ftgzip.h + * + * Gzip-compressed stream support. + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGZIP_H_ +#define FTGZIP_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * gzip + * + * @title: + * GZIP Streams + * + * @abstract: + * Using gzip-compressed font files. + * + * @description: + * In certain builds of the library, gzip compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a gzipped stream from it + * and re-open the face with it. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * + * This section contains the declaration of Gzip-specific functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Stream_OpenGzip + * + * @description: + * Open a new stream to parse gzip-compressed font files. This is mainly + * used to support the compressed `*.pcf.gz` fonts that come with + * XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close` on the new stream will + * **not** call `FT_Stream_Close` on the source stream. None of the + * stream objects will be released to the heap. + * + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with zlib support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ); + + + /************************************************************************** + * + * @function: + * FT_Gzip_Uncompress + * + * @description: + * Decompress a zipped input buffer into an output buffer. This function + * is modeled after zlib's `uncompress` function. + * + * @input: + * memory :: + * A FreeType memory handle. + * + * input :: + * The input buffer. + * + * input_len :: + * The length of the input buffer. + * + * @output: + * output :: + * The output buffer. + * + * @inout: + * output_len :: + * Before calling the function, this is the total size of the output + * buffer, which must be large enough to hold the entire uncompressed + * data (so the size of the uncompressed data must be known in + * advance). After calling the function, `output_len` is the size of + * the used data in `output`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with zlib support. + * + * @since: + * 2.5.1 + */ + FT_EXPORT( FT_Error ) + FT_Gzip_Uncompress( FT_Memory memory, + FT_Byte* output, + FT_ULong* output_len, + const FT_Byte* input, + FT_ULong input_len ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGZIP_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftimage.h b/vendor/freetype/include/freetype/ftimage.h new file mode 100644 index 0000000..6baa812 --- /dev/null +++ b/vendor/freetype/include/freetype/ftimage.h @@ -0,0 +1,1284 @@ +/**************************************************************************** + * + * ftimage.h + * + * FreeType glyph image formats and default raster interface + * (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * Note: A 'raster' is simply a scan-line converter, used to render + * `FT_Outline`s into `FT_Bitmap`s. + * + */ + + +#ifndef FTIMAGE_H_ +#define FTIMAGE_H_ + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * basic_types + * + */ + + + /************************************************************************** + * + * @type: + * FT_Pos + * + * @description: + * The type FT_Pos is used to store vectorial coordinates. Depending on + * the context, these can represent distances in integer font units, or + * 16.16, or 26.6 fixed-point pixel coordinates. + */ + typedef signed long FT_Pos; + + + /************************************************************************** + * + * @struct: + * FT_Vector + * + * @description: + * A simple structure used to store a 2D vector; coordinates are of the + * FT_Pos type. + * + * @fields: + * x :: + * The horizontal coordinate. + * y :: + * The vertical coordinate. + */ + typedef struct FT_Vector_ + { + FT_Pos x; + FT_Pos y; + + } FT_Vector; + + + /************************************************************************** + * + * @struct: + * FT_BBox + * + * @description: + * A structure used to hold an outline's bounding box, i.e., the + * coordinates of its extrema in the horizontal and vertical directions. + * + * @fields: + * xMin :: + * The horizontal minimum (left-most). + * + * yMin :: + * The vertical minimum (bottom-most). + * + * xMax :: + * The horizontal maximum (right-most). + * + * yMax :: + * The vertical maximum (top-most). + * + * @note: + * The bounding box is specified with the coordinates of the lower left + * and the upper right corner. In PostScript, those values are often + * called (llx,lly) and (urx,ury), respectively. + * + * If `yMin` is negative, this value gives the glyph's descender. + * Otherwise, the glyph doesn't descend below the baseline. Similarly, + * if `ymax` is positive, this value gives the glyph's ascender. + * + * `xMin` gives the horizontal distance from the glyph's origin to the + * left edge of the glyph's bounding box. If `xMin` is negative, the + * glyph extends to the left of the origin. + */ + typedef struct FT_BBox_ + { + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; + + } FT_BBox; + + + /************************************************************************** + * + * @enum: + * FT_Pixel_Mode + * + * @description: + * An enumeration type used to describe the format of pixels in a given + * bitmap. Note that additional formats may be added in the future. + * + * @values: + * FT_PIXEL_MODE_NONE :: + * Value~0 is reserved. + * + * FT_PIXEL_MODE_MONO :: + * A monochrome bitmap, using 1~bit per pixel. Note that pixels are + * stored in most-significant order (MSB), which means that the + * left-most pixel in a byte has value 128. + * + * FT_PIXEL_MODE_GRAY :: + * An 8-bit bitmap, generally used to represent anti-aliased glyph + * images. Each pixel is stored in one byte. Note that the number of + * 'gray' levels is stored in the `num_grays` field of the @FT_Bitmap + * structure (it generally is 256). + * + * FT_PIXEL_MODE_GRAY2 :: + * A 2-bit per pixel bitmap, used to represent embedded anti-aliased + * bitmaps in font files according to the OpenType specification. We + * haven't found a single font using this format, however. + * + * FT_PIXEL_MODE_GRAY4 :: + * A 4-bit per pixel bitmap, representing embedded anti-aliased bitmaps + * in font files according to the OpenType specification. We haven't + * found a single font using this format, however. + * + * FT_PIXEL_MODE_LCD :: + * An 8-bit bitmap, representing RGB or BGR decimated glyph images used + * for display on LCD displays; the bitmap is three times wider than + * the original glyph image. See also @FT_RENDER_MODE_LCD. + * + * FT_PIXEL_MODE_LCD_V :: + * An 8-bit bitmap, representing RGB or BGR decimated glyph images used + * for display on rotated LCD displays; the bitmap is three times + * taller than the original glyph image. See also + * @FT_RENDER_MODE_LCD_V. + * + * FT_PIXEL_MODE_BGRA :: + * [Since 2.5] An image with four 8-bit channels per pixel, + * representing a color image (such as emoticons) with alpha channel. + * For each pixel, the format is BGRA, which means, the blue channel + * comes first in memory. The color channels are pre-multiplied and in + * the sRGB colorspace. For example, full red at half-translucent + * opacity will be represented as '00,00,80,80', not '00,00,FF,80'. + * See also @FT_LOAD_COLOR. + */ + typedef enum FT_Pixel_Mode_ + { + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, + FT_PIXEL_MODE_BGRA, + + FT_PIXEL_MODE_MAX /* do not remove */ + + } FT_Pixel_Mode; + + + /* these constants are deprecated; use the corresponding `FT_Pixel_Mode` */ + /* values instead. */ +#define ft_pixel_mode_none FT_PIXEL_MODE_NONE +#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO +#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY +#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 +#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + + /* */ + + /* For debugging, the @FT_Pixel_Mode enumeration must stay in sync */ + /* with the `pixel_modes` array in file `ftobjs.c`. */ + + + /************************************************************************** + * + * @struct: + * FT_Bitmap + * + * @description: + * A structure used to describe a bitmap or pixmap to the raster. Note + * that we now manage pixmaps of various depths through the `pixel_mode` + * field. + * + * @fields: + * rows :: + * The number of bitmap rows. + * + * width :: + * The number of pixels in bitmap row. + * + * pitch :: + * The pitch's absolute value is the number of bytes taken by one + * bitmap row, including padding. However, the pitch is positive when + * the bitmap has a 'down' flow, and negative when it has an 'up' flow. + * In all cases, the pitch is an offset to add to a bitmap pointer in + * order to go down one row. + * + * Note that 'padding' means the alignment of a bitmap to a byte + * border, and FreeType functions normally align to the smallest + * possible integer value. + * + * For the B/W rasterizer, `pitch` is always an even number. + * + * To change the pitch of a bitmap (say, to make it a multiple of 4), + * use @FT_Bitmap_Convert. Alternatively, you might use callback + * functions to directly render to the application's surface; see the + * file `example2.cpp` in the tutorial for a demonstration. + * + * buffer :: + * A typeless pointer to the bitmap buffer. This value should be + * aligned on 32-bit boundaries in most cases. + * + * num_grays :: + * This field is only used with @FT_PIXEL_MODE_GRAY; it gives the + * number of gray levels used in the bitmap. + * + * pixel_mode :: + * The pixel mode, i.e., how pixel bits are stored. See @FT_Pixel_Mode + * for possible values. + * + * palette_mode :: + * This field is intended for paletted pixel modes; it indicates how + * the palette is stored. Not used currently. + * + * palette :: + * A typeless pointer to the bitmap palette; this field is intended for + * paletted pixel modes. Not used currently. + * + * @note: + * `width` and `rows` refer to the *physical* size of the bitmap, not the + * *logical* one. For example, if @FT_Pixel_Mode is set to + * `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the + * physical one. + */ + typedef struct FT_Bitmap_ + { + unsigned int rows; + unsigned int width; + int pitch; + unsigned char* buffer; + unsigned short num_grays; + unsigned char pixel_mode; + unsigned char palette_mode; + void* palette; + + } FT_Bitmap; + + + /************************************************************************** + * + * @section: + * outline_processing + * + */ + + + /************************************************************************** + * + * @struct: + * FT_Outline + * + * @description: + * This structure is used to describe an outline to the scan-line + * converter. + * + * @fields: + * n_contours :: + * The number of contours in the outline. + * + * n_points :: + * The number of points in the outline. + * + * points :: + * A pointer to an array of `n_points` @FT_Vector elements, giving the + * outline's point coordinates. + * + * tags :: + * A pointer to an array of `n_points` chars, giving each outline + * point's type. + * + * If bit~0 is unset, the point is 'off' the curve, i.e., a Bezier + * control point, while it is 'on' if set. + * + * Bit~1 is meaningful for 'off' points only. If set, it indicates a + * third-order Bezier arc control point; and a second-order control + * point if unset. + * + * If bit~2 is set, bits 5-7 contain the drop-out mode (as defined in + * the OpenType specification; the value is the same as the argument to + * the 'SCANMODE' instruction). + * + * Bits 3 and~4 are reserved for internal purposes. + * + * contours :: + * An array of `n_contours` shorts, giving the end point of each + * contour within the outline. For example, the first contour is + * defined by the points '0' to `contours[0]`, the second one is + * defined by the points `contours[0]+1` to `contours[1]`, etc. + * + * flags :: + * A set of bit flags used to characterize the outline and give hints + * to the scan-converter and hinter on how to convert/grid-fit it. See + * @FT_OUTLINE_XXX. + * + * @note: + * The B/W rasterizer only checks bit~2 in the `tags` array for the first + * point of each contour. The drop-out mode as given with + * @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and + * @FT_OUTLINE_INCLUDE_STUBS in `flags` is then overridden. + */ + typedef struct FT_Outline_ + { + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ + + } FT_Outline; + + /* */ + + /* Following limits must be consistent with */ + /* FT_Outline.{n_contours,n_points} */ +#define FT_OUTLINE_CONTOURS_MAX SHRT_MAX +#define FT_OUTLINE_POINTS_MAX SHRT_MAX + + + /************************************************************************** + * + * @enum: + * FT_OUTLINE_XXX + * + * @description: + * A list of bit-field constants used for the flags in an outline's + * `flags` field. + * + * @values: + * FT_OUTLINE_NONE :: + * Value~0 is reserved. + * + * FT_OUTLINE_OWNER :: + * If set, this flag indicates that the outline's field arrays (i.e., + * `points`, `flags`, and `contours`) are 'owned' by the outline + * object, and should thus be freed when it is destroyed. + * + * FT_OUTLINE_EVEN_ODD_FILL :: + * By default, outlines are filled using the non-zero winding rule. If + * set to 1, the outline will be filled using the even-odd fill rule + * (only works with the smooth rasterizer). + * + * FT_OUTLINE_REVERSE_FILL :: + * By default, outside contours of an outline are oriented in + * clock-wise direction, as defined in the TrueType specification. + * This flag is set if the outline uses the opposite direction + * (typically for Type~1 fonts). This flag is ignored by the scan + * converter. + * + * FT_OUTLINE_IGNORE_DROPOUTS :: + * By default, the scan converter will try to detect drop-outs in an + * outline and correct the glyph bitmap to ensure consistent shape + * continuity. If set, this flag hints the scan-line converter to + * ignore such cases. See below for more information. + * + * FT_OUTLINE_SMART_DROPOUTS :: + * Select smart dropout control. If unset, use simple dropout control. + * Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for more + * information. + * + * FT_OUTLINE_INCLUDE_STUBS :: + * If set, turn pixels on for 'stubs', otherwise exclude them. Ignored + * if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for more + * information. + * + * FT_OUTLINE_OVERLAP :: + * [Since 2.10.3] This flag indicates that this outline contains + * overlapping contours and the anti-aliased renderer should perform + * oversampling to mitigate possible artifacts. This flag should _not_ + * be set for well designed glyphs without overlaps because it quadruples + * the rendering time. + * + * FT_OUTLINE_HIGH_PRECISION :: + * This flag indicates that the scan-line converter should try to + * convert this outline to bitmaps with the highest possible quality. + * It is typically set for small character sizes. Note that this is + * only a hint that might be completely ignored by a given + * scan-converter. + * + * FT_OUTLINE_SINGLE_PASS :: + * This flag is set to force a given scan-converter to only use a + * single pass over the outline to render a bitmap glyph image. + * Normally, it is set for very large character sizes. It is only a + * hint that might be completely ignored by a given scan-converter. + * + * @note: + * The flags @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and + * @FT_OUTLINE_INCLUDE_STUBS are ignored by the smooth rasterizer. + * + * There exists a second mechanism to pass the drop-out mode to the B/W + * rasterizer; see the `tags` field in @FT_Outline. + * + * Please refer to the description of the 'SCANTYPE' instruction in the + * OpenType specification (in file `ttinst1.doc`) how simple drop-outs, + * smart drop-outs, and stubs are defined. + */ +#define FT_OUTLINE_NONE 0x0 +#define FT_OUTLINE_OWNER 0x1 +#define FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define FT_OUTLINE_REVERSE_FILL 0x4 +#define FT_OUTLINE_IGNORE_DROPOUTS 0x8 +#define FT_OUTLINE_SMART_DROPOUTS 0x10 +#define FT_OUTLINE_INCLUDE_STUBS 0x20 +#define FT_OUTLINE_OVERLAP 0x40 + +#define FT_OUTLINE_HIGH_PRECISION 0x100 +#define FT_OUTLINE_SINGLE_PASS 0x200 + + + /* these constants are deprecated; use the corresponding */ + /* `FT_OUTLINE_XXX` values instead */ +#define ft_outline_none FT_OUTLINE_NONE +#define ft_outline_owner FT_OUTLINE_OWNER +#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL +#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL +#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS +#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION +#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS + + /* */ + +#define FT_CURVE_TAG( flag ) ( flag & 0x03 ) + + /* see the `tags` field in `FT_Outline` for a description of the values */ +#define FT_CURVE_TAG_ON 0x01 +#define FT_CURVE_TAG_CONIC 0x00 +#define FT_CURVE_TAG_CUBIC 0x02 + +#define FT_CURVE_TAG_HAS_SCANMODE 0x04 + +#define FT_CURVE_TAG_TOUCH_X 0x08 /* reserved for TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_Y 0x10 /* reserved for TrueType hinter */ + +#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ + FT_CURVE_TAG_TOUCH_Y ) + /* values 0x20, 0x40, and 0x80 are reserved */ + + + /* these constants are deprecated; use the corresponding */ + /* `FT_CURVE_TAG_XXX` values instead */ +#define FT_Curve_Tag_On FT_CURVE_TAG_ON +#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC +#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC +#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X +#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y + + + /************************************************************************** + * + * @functype: + * FT_Outline_MoveToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'move to' + * function during outline walking/decomposition. + * + * A 'move to' is emitted to start a new contour in an outline. + * + * @input: + * to :: + * A pointer to the target point of the 'move to'. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_MoveToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc + + + /************************************************************************** + * + * @functype: + * FT_Outline_LineToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'line to' + * function during outline walking/decomposition. + * + * A 'line to' is emitted to indicate a segment in the outline. + * + * @input: + * to :: + * A pointer to the target point of the 'line to'. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_LineToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_LineTo_Func FT_Outline_LineToFunc + + + /************************************************************************** + * + * @functype: + * FT_Outline_ConicToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'conic to' + * function during outline walking or decomposition. + * + * A 'conic to' is emitted to indicate a second-order Bezier arc in the + * outline. + * + * @input: + * control :: + * An intermediate control point between the last position and the new + * target in `to`. + * + * to :: + * A pointer to the target end point of the conic arc. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_ConicToFunc)( const FT_Vector* control, + const FT_Vector* to, + void* user ); + +#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc + + + /************************************************************************** + * + * @functype: + * FT_Outline_CubicToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'cubic to' + * function during outline walking or decomposition. + * + * A 'cubic to' is emitted to indicate a third-order Bezier arc. + * + * @input: + * control1 :: + * A pointer to the first Bezier control point. + * + * control2 :: + * A pointer to the second Bezier control point. + * + * to :: + * A pointer to the target end point. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_CubicToFunc)( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user ); + +#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc + + + /************************************************************************** + * + * @struct: + * FT_Outline_Funcs + * + * @description: + * A structure to hold various function pointers used during outline + * decomposition in order to emit segments, conic, and cubic Beziers. + * + * @fields: + * move_to :: + * The 'move to' emitter. + * + * line_to :: + * The segment emitter. + * + * conic_to :: + * The second-order Bezier arc emitter. + * + * cubic_to :: + * The third-order Bezier arc emitter. + * + * shift :: + * The shift that is applied to coordinates before they are sent to the + * emitter. + * + * delta :: + * The delta that is applied to coordinates before they are sent to the + * emitter, but after the shift. + * + * @note: + * The point coordinates sent to the emitters are the transformed version + * of the original coordinates (this is important for high accuracy + * during scan-conversion). The transformation is simple: + * + * ``` + * x' = (x << shift) - delta + * y' = (y << shift) - delta + * ``` + * + * Set the values of `shift` and `delta` to~0 to get the original point + * coordinates. + */ + typedef struct FT_Outline_Funcs_ + { + FT_Outline_MoveToFunc move_to; + FT_Outline_LineToFunc line_to; + FT_Outline_ConicToFunc conic_to; + FT_Outline_CubicToFunc cubic_to; + + int shift; + FT_Pos delta; + + } FT_Outline_Funcs; + + + /************************************************************************** + * + * @section: + * basic_types + * + */ + + + /************************************************************************** + * + * @macro: + * FT_IMAGE_TAG + * + * @description: + * This macro converts four-letter tags to an unsigned long type. + * + * @note: + * Since many 16-bit compilers don't like 32-bit enumerations, you should + * redefine this macro in case of problems to something like this: + * + * ``` + * #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value + * ``` + * + * to get a simple enumeration without assigning special numbers. + */ +#ifndef FT_IMAGE_TAG + +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( FT_STATIC_BYTE_CAST( unsigned long, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( unsigned long, _x4 ) ) + +#endif /* FT_IMAGE_TAG */ + + + /************************************************************************** + * + * @enum: + * FT_Glyph_Format + * + * @description: + * An enumeration type used to describe the format of a given glyph + * image. Note that this version of FreeType only supports two image + * formats, even though future font drivers will be able to register + * their own format. + * + * @values: + * FT_GLYPH_FORMAT_NONE :: + * The value~0 is reserved. + * + * FT_GLYPH_FORMAT_COMPOSITE :: + * The glyph image is a composite of several other images. This format + * is _only_ used with @FT_LOAD_NO_RECURSE, and is used to report + * compound glyphs (like accented characters). + * + * FT_GLYPH_FORMAT_BITMAP :: + * The glyph image is a bitmap, and can be described as an @FT_Bitmap. + * You generally need to access the `bitmap` field of the + * @FT_GlyphSlotRec structure to read it. + * + * FT_GLYPH_FORMAT_OUTLINE :: + * The glyph image is a vectorial outline made of line segments and + * Bezier arcs; it can be described as an @FT_Outline; you generally + * want to access the `outline` field of the @FT_GlyphSlotRec structure + * to read it. + * + * FT_GLYPH_FORMAT_PLOTTER :: + * The glyph image is a vectorial path with no inside and outside + * contours. Some Type~1 fonts, like those in the Hershey family, + * contain glyphs in this format. These are described as @FT_Outline, + * but FreeType isn't currently capable of rendering them correctly. + * + * FT_GLYPH_FORMAT_SVG :: + * [Since 2.12] The glyph is represented by an SVG document in the + * 'SVG~' table. + */ + typedef enum FT_Glyph_Format_ + { + FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ), + + FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_SVG, 'S', 'V', 'G', ' ' ) + + } FT_Glyph_Format; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Glyph_Format` values instead. */ +#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE +#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE +#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP +#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE +#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** R A S T E R D E F I N I T I O N S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + + /************************************************************************** + * + * @section: + * raster + * + * @title: + * Scanline Converter + * + * @abstract: + * How vectorial outlines are converted into bitmaps and pixmaps. + * + * @description: + * A raster or a rasterizer is a scan converter in charge of producing a + * pixel coverage bitmap that can be used as an alpha channel when + * compositing a glyph with a background. FreeType comes with two + * rasterizers: bilevel `raster1` and anti-aliased `smooth` are two + * separate modules. They are usually called from the high-level + * @FT_Load_Glyph or @FT_Render_Glyph functions and produce the entire + * coverage bitmap at once, while staying largely invisible to users. + * + * Instead of working with complete coverage bitmaps, it is also possible + * to intercept consecutive pixel runs on the same scanline with the same + * coverage, called _spans_, and process them individually. Only the + * `smooth` rasterizer permits this when calling @FT_Outline_Render with + * @FT_Raster_Params as described below. + * + * Working with either complete bitmaps or spans it is important to think + * of them as colorless coverage objects suitable as alpha channels to + * blend arbitrary colors with a background. For best results, it is + * recommended to use gamma correction, too. + * + * This section also describes the public API needed to set up alternative + * @FT_Renderer modules. + * + * @order: + * FT_Span + * FT_SpanFunc + * FT_Raster_Params + * FT_RASTER_FLAG_XXX + * + * FT_Raster + * FT_Raster_NewFunc + * FT_Raster_DoneFunc + * FT_Raster_ResetFunc + * FT_Raster_SetModeFunc + * FT_Raster_RenderFunc + * FT_Raster_Funcs + * + */ + + + /************************************************************************** + * + * @struct: + * FT_Span + * + * @description: + * A structure to model a single span of consecutive pixels when + * rendering an anti-aliased bitmap. + * + * @fields: + * x :: + * The span's horizontal start position. + * + * len :: + * The span's length in pixels. + * + * coverage :: + * The span color/coverage, ranging from 0 (background) to 255 + * (foreground). + * + * @note: + * This structure is used by the span drawing callback type named + * @FT_SpanFunc that takes the y~coordinate of the span as a parameter. + * + * The anti-aliased rasterizer produces coverage values from 0 to 255, + * that is, from completely transparent to completely opaque. + */ + typedef struct FT_Span_ + { + short x; + unsigned short len; + unsigned char coverage; + + } FT_Span; + + + /************************************************************************** + * + * @functype: + * FT_SpanFunc + * + * @description: + * A function used as a call-back by the anti-aliased renderer in order + * to let client applications draw themselves the pixel spans on each + * scan line. + * + * @input: + * y :: + * The scanline's upward y~coordinate. + * + * count :: + * The number of spans to draw on this scanline. + * + * spans :: + * A table of `count` spans to draw on the scanline. + * + * user :: + * User-supplied data that is passed to the callback. + * + * @note: + * This callback allows client applications to directly render the spans + * of the anti-aliased bitmap to any kind of surfaces. + * + * This can be used to write anti-aliased outlines directly to a given + * background bitmap using alpha compositing. It can also be used for + * oversampling and averaging. + */ + typedef void + (*FT_SpanFunc)( int y, + int count, + const FT_Span* spans, + void* user ); + +#define FT_Raster_Span_Func FT_SpanFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_BitTest_Func + * + * @description: + * Deprecated, unimplemented. + */ + typedef int + (*FT_Raster_BitTest_Func)( int y, + int x, + void* user ); + + + /************************************************************************** + * + * @functype: + * FT_Raster_BitSet_Func + * + * @description: + * Deprecated, unimplemented. + */ + typedef void + (*FT_Raster_BitSet_Func)( int y, + int x, + void* user ); + + + /************************************************************************** + * + * @enum: + * FT_RASTER_FLAG_XXX + * + * @description: + * A list of bit flag constants as used in the `flags` field of a + * @FT_Raster_Params structure. + * + * @values: + * FT_RASTER_FLAG_DEFAULT :: + * This value is 0. + * + * FT_RASTER_FLAG_AA :: + * This flag is set to indicate that an anti-aliased glyph image should + * be generated. Otherwise, it will be monochrome (1-bit). + * + * FT_RASTER_FLAG_DIRECT :: + * This flag is set to indicate direct rendering. In this mode, client + * applications must provide their own span callback. This lets them + * directly draw or compose over an existing bitmap. If this bit is + * _not_ set, the target pixmap's buffer _must_ be zeroed before + * rendering and the output will be clipped to its size. + * + * Direct rendering is only possible with anti-aliased glyphs. + * + * FT_RASTER_FLAG_CLIP :: + * This flag is only used in direct rendering mode. If set, the output + * will be clipped to a box specified in the `clip_box` field of the + * @FT_Raster_Params structure. Otherwise, the `clip_box` is + * effectively set to the bounding box and all spans are generated. + * + * FT_RASTER_FLAG_SDF :: + * This flag is set to indicate that a signed distance field glyph + * image should be generated. This is only used while rendering with + * the @FT_RENDER_MODE_SDF render mode. + */ +#define FT_RASTER_FLAG_DEFAULT 0x0 +#define FT_RASTER_FLAG_AA 0x1 +#define FT_RASTER_FLAG_DIRECT 0x2 +#define FT_RASTER_FLAG_CLIP 0x4 +#define FT_RASTER_FLAG_SDF 0x8 + + /* these constants are deprecated; use the corresponding */ + /* `FT_RASTER_FLAG_XXX` values instead */ +#define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT +#define ft_raster_flag_aa FT_RASTER_FLAG_AA +#define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT +#define ft_raster_flag_clip FT_RASTER_FLAG_CLIP + + + /************************************************************************** + * + * @struct: + * FT_Raster_Params + * + * @description: + * A structure to hold the parameters used by a raster's render function, + * passed as an argument to @FT_Outline_Render. + * + * @fields: + * target :: + * The target bitmap. + * + * source :: + * A pointer to the source glyph image (e.g., an @FT_Outline). + * + * flags :: + * The rendering flags. + * + * gray_spans :: + * The gray span drawing callback. + * + * black_spans :: + * Unused. + * + * bit_test :: + * Unused. + * + * bit_set :: + * Unused. + * + * user :: + * User-supplied data that is passed to each drawing callback. + * + * clip_box :: + * An optional span clipping box expressed in _integer_ pixels + * (not in 26.6 fixed-point units). + * + * @note: + * The @FT_RASTER_FLAG_AA bit flag must be set in the `flags` to + * generate an anti-aliased glyph bitmap, otherwise a monochrome bitmap + * is generated. The `target` should have appropriate pixel mode and its + * dimensions define the clipping region. + * + * If both @FT_RASTER_FLAG_AA and @FT_RASTER_FLAG_DIRECT bit flags + * are set in `flags`, the raster calls an @FT_SpanFunc callback + * `gray_spans` with `user` data as an argument ignoring `target`. This + * allows direct composition over a pre-existing user surface to perform + * the span drawing and composition. To optionally clip the spans, set + * the @FT_RASTER_FLAG_CLIP flag and `clip_box`. The monochrome raster + * does not support the direct mode. + * + * The gray-level rasterizer always uses 256 gray levels. If you want + * fewer gray levels, you have to use @FT_RASTER_FLAG_DIRECT and reduce + * the levels in the callback function. + */ + typedef struct FT_Raster_Params_ + { + const FT_Bitmap* target; + const void* source; + int flags; + FT_SpanFunc gray_spans; + FT_SpanFunc black_spans; /* unused */ + FT_Raster_BitTest_Func bit_test; /* unused */ + FT_Raster_BitSet_Func bit_set; /* unused */ + void* user; + FT_BBox clip_box; + + } FT_Raster_Params; + + + /************************************************************************** + * + * @type: + * FT_Raster + * + * @description: + * An opaque handle (pointer) to a raster object. Each object can be + * used independently to convert an outline into a bitmap or pixmap. + * + * @note: + * In FreeType 2, all rasters are now encapsulated within specific + * @FT_Renderer modules and only used in their context. + * + */ + typedef struct FT_RasterRec_* FT_Raster; + + + /************************************************************************** + * + * @functype: + * FT_Raster_NewFunc + * + * @description: + * A function used to create a new raster object. + * + * @input: + * memory :: + * A handle to the memory allocator. + * + * @output: + * raster :: + * A handle to the new raster object. + * + * @return: + * Error code. 0~means success. + * + * @note: + * The `memory` parameter is a typeless pointer in order to avoid + * un-wanted dependencies on the rest of the FreeType code. In practice, + * it is an @FT_Memory object, i.e., a handle to the standard FreeType + * memory allocator. However, this field can be completely ignored by a + * given raster implementation. + */ + typedef int + (*FT_Raster_NewFunc)( void* memory, + FT_Raster* raster ); + +#define FT_Raster_New_Func FT_Raster_NewFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_DoneFunc + * + * @description: + * A function used to destroy a given raster object. + * + * @input: + * raster :: + * A handle to the raster object. + */ + typedef void + (*FT_Raster_DoneFunc)( FT_Raster raster ); + +#define FT_Raster_Done_Func FT_Raster_DoneFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_ResetFunc + * + * @description: + * FreeType used to provide an area of memory called the 'render pool' + * available to all registered rasterizers. This was not thread safe, + * however, and now FreeType never allocates this pool. + * + * This function is called after a new raster object is created. + * + * @input: + * raster :: + * A handle to the new raster object. + * + * pool_base :: + * Previously, the address in memory of the render pool. Set this to + * `NULL`. + * + * pool_size :: + * Previously, the size in bytes of the render pool. Set this to 0. + * + * @note: + * Rasterizers should rely on dynamic or stack allocation if they want to + * (a handle to the memory allocator is passed to the rasterizer + * constructor). + */ + typedef void + (*FT_Raster_ResetFunc)( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); + +#define FT_Raster_Reset_Func FT_Raster_ResetFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_SetModeFunc + * + * @description: + * This function is a generic facility to change modes or attributes in a + * given raster. This can be used for debugging purposes, or simply to + * allow implementation-specific 'features' in a given raster module. + * + * @input: + * raster :: + * A handle to the new raster object. + * + * mode :: + * A 4-byte tag used to name the mode or property. + * + * args :: + * A pointer to the new mode/property to use. + */ + typedef int + (*FT_Raster_SetModeFunc)( FT_Raster raster, + unsigned long mode, + void* args ); + +#define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_RenderFunc + * + * @description: + * Invoke a given raster to scan-convert a given glyph image into a + * target bitmap. + * + * @input: + * raster :: + * A handle to the raster object. + * + * params :: + * A pointer to an @FT_Raster_Params structure used to store the + * rendering parameters. + * + * @return: + * Error code. 0~means success. + * + * @note: + * The exact format of the source image depends on the raster's glyph + * format defined in its @FT_Raster_Funcs structure. It can be an + * @FT_Outline or anything else in order to support a large array of + * glyph formats. + * + * Note also that the render function can fail and return a + * `FT_Err_Unimplemented_Feature` error code if the raster used does not + * support direct composition. + */ + typedef int + (*FT_Raster_RenderFunc)( FT_Raster raster, + const FT_Raster_Params* params ); + +#define FT_Raster_Render_Func FT_Raster_RenderFunc + + + /************************************************************************** + * + * @struct: + * FT_Raster_Funcs + * + * @description: + * A structure used to describe a given raster class to the library. + * + * @fields: + * glyph_format :: + * The supported glyph format for this raster. + * + * raster_new :: + * The raster constructor. + * + * raster_reset :: + * Used to reset the render pool within the raster. + * + * raster_render :: + * A function to render a glyph into a given bitmap. + * + * raster_done :: + * The raster destructor. + */ + typedef struct FT_Raster_Funcs_ + { + FT_Glyph_Format glyph_format; + + FT_Raster_NewFunc raster_new; + FT_Raster_ResetFunc raster_reset; + FT_Raster_SetModeFunc raster_set_mode; + FT_Raster_RenderFunc raster_render; + FT_Raster_DoneFunc raster_done; + + } FT_Raster_Funcs; + + /* */ + + +FT_END_HEADER + +#endif /* FTIMAGE_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/vendor/freetype/include/freetype/ftincrem.h b/vendor/freetype/include/freetype/ftincrem.h new file mode 100644 index 0000000..2d4f5de --- /dev/null +++ b/vendor/freetype/include/freetype/ftincrem.h @@ -0,0 +1,348 @@ +/**************************************************************************** + * + * ftincrem.h + * + * FreeType incremental loading (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTINCREM_H_ +#define FTINCREM_H_ + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * incremental + * + * @title: + * Incremental Loading + * + * @abstract: + * Custom Glyph Loading. + * + * @description: + * This section contains various functions used to perform so-called + * 'incremental' glyph loading. This is a mode where all glyphs loaded + * from a given @FT_Face are provided by the client application. + * + * Apart from that, all other tables are loaded normally from the font + * file. This mode is useful when FreeType is used within another + * engine, e.g., a PostScript Imaging Processor. + * + * To enable this mode, you must use @FT_Open_Face, passing an + * @FT_Parameter with the @FT_PARAM_TAG_INCREMENTAL tag and an + * @FT_Incremental_Interface value. See the comments for + * @FT_Incremental_InterfaceRec for an example. + * + */ + + + /************************************************************************** + * + * @type: + * FT_Incremental + * + * @description: + * An opaque type describing a user-provided object used to implement + * 'incremental' glyph loading within FreeType. This is used to support + * embedded fonts in certain environments (e.g., PostScript + * interpreters), where the glyph data isn't in the font file, or must be + * overridden by different values. + * + * @note: + * It is up to client applications to create and implement + * @FT_Incremental objects, as long as they provide implementations for + * the methods @FT_Incremental_GetGlyphDataFunc, + * @FT_Incremental_FreeGlyphDataFunc and + * @FT_Incremental_GetGlyphMetricsFunc. + * + * See the description of @FT_Incremental_InterfaceRec to understand how + * to use incremental objects with FreeType. + * + */ + typedef struct FT_IncrementalRec_* FT_Incremental; + + + /************************************************************************** + * + * @struct: + * FT_Incremental_MetricsRec + * + * @description: + * A small structure used to contain the basic glyph metrics returned by + * the @FT_Incremental_GetGlyphMetricsFunc method. + * + * @fields: + * bearing_x :: + * Left bearing, in font units. + * + * bearing_y :: + * Top bearing, in font units. + * + * advance :: + * Horizontal component of glyph advance, in font units. + * + * advance_v :: + * Vertical component of glyph advance, in font units. + * + * @note: + * These correspond to horizontal or vertical metrics depending on the + * value of the `vertical` argument to the function + * @FT_Incremental_GetGlyphMetricsFunc. + * + */ + typedef struct FT_Incremental_MetricsRec_ + { + FT_Long bearing_x; + FT_Long bearing_y; + FT_Long advance; + FT_Long advance_v; /* since 2.3.12 */ + + } FT_Incremental_MetricsRec; + + + /************************************************************************** + * + * @struct: + * FT_Incremental_Metrics + * + * @description: + * A handle to an @FT_Incremental_MetricsRec structure. + * + */ + typedef struct FT_Incremental_MetricsRec_* FT_Incremental_Metrics; + + + /************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphDataFunc + * + * @description: + * A function called by FreeType to access a given glyph's data bytes + * during @FT_Load_Glyph or @FT_Load_Char if incremental loading is + * enabled. + * + * Note that the format of the glyph's data bytes depends on the font + * file format. For TrueType, it must correspond to the raw bytes within + * the 'glyf' table. For PostScript formats, it must correspond to the + * **unencrypted** charstring bytes, without any `lenIV` header. It is + * undefined for any other format. + * + * @input: + * incremental :: + * Handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * @output: + * adata :: + * A structure describing the returned glyph data bytes (which will be + * accessed as a read-only byte block). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If this function returns successfully the method + * @FT_Incremental_FreeGlyphDataFunc will be called later to release the + * data bytes. + * + * Nested calls to @FT_Incremental_GetGlyphDataFunc can happen for + * compound glyphs. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphDataFunc)( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Data* adata ); + + + /************************************************************************** + * + * @type: + * FT_Incremental_FreeGlyphDataFunc + * + * @description: + * A function used to release the glyph data bytes returned by a + * successful call to @FT_Incremental_GetGlyphDataFunc. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * data :: + * A structure describing the glyph data bytes (which will be accessed + * as a read-only byte block). + * + */ + typedef void + (*FT_Incremental_FreeGlyphDataFunc)( FT_Incremental incremental, + FT_Data* data ); + + + /************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphMetricsFunc + * + * @description: + * A function used to retrieve the basic metrics of a given glyph index + * before accessing its data. This allows for handling font types such + * as PCL~XL Format~1, Class~2 downloaded TrueType fonts, where the glyph + * metrics (`hmtx` and `vmtx` tables) are permitted to be omitted from + * the font, and the relevant metrics included in the header of the glyph + * outline data. Importantly, this is not intended to allow custom glyph + * metrics (for example, Postscript Metrics dictionaries), because that + * conflicts with the requirements of outline hinting. Such custom + * metrics must be handled separately, by the calling application. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * vertical :: + * If true, return vertical metrics. + * + * ametrics :: + * This parameter is used for both input and output. The original + * glyph metrics, if any, in font units. If metrics are not available + * all the values must be set to zero. + * + * @output: + * ametrics :: + * The glyph metrics in font units. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphMetricsFunc) + ( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Bool vertical, + FT_Incremental_MetricsRec *ametrics ); + + + /************************************************************************** + * + * @struct: + * FT_Incremental_FuncsRec + * + * @description: + * A table of functions for accessing fonts that load data incrementally. + * Used in @FT_Incremental_InterfaceRec. + * + * @fields: + * get_glyph_data :: + * The function to get glyph data. Must not be null. + * + * free_glyph_data :: + * The function to release glyph data. Must not be null. + * + * get_glyph_metrics :: + * The function to get glyph metrics. May be null if the font does not + * require it. + * + */ + typedef struct FT_Incremental_FuncsRec_ + { + FT_Incremental_GetGlyphDataFunc get_glyph_data; + FT_Incremental_FreeGlyphDataFunc free_glyph_data; + FT_Incremental_GetGlyphMetricsFunc get_glyph_metrics; + + } FT_Incremental_FuncsRec; + + + /************************************************************************** + * + * @struct: + * FT_Incremental_InterfaceRec + * + * @description: + * A structure to be used with @FT_Open_Face to indicate that the user + * wants to support incremental glyph loading. You should use it with + * @FT_PARAM_TAG_INCREMENTAL as in the following example: + * + * ``` + * FT_Incremental_InterfaceRec inc_int; + * FT_Parameter parameter; + * FT_Open_Args open_args; + * + * + * // set up incremental descriptor + * inc_int.funcs = my_funcs; + * inc_int.object = my_object; + * + * // set up optional parameter + * parameter.tag = FT_PARAM_TAG_INCREMENTAL; + * parameter.data = &inc_int; + * + * // set up FT_Open_Args structure + * open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; + * open_args.pathname = my_font_pathname; + * open_args.num_params = 1; + * open_args.params = ¶meter; // we use one optional argument + * + * // open the font + * error = FT_Open_Face( library, &open_args, index, &face ); + * ... + * ``` + * + */ + typedef struct FT_Incremental_InterfaceRec_ + { + const FT_Incremental_FuncsRec* funcs; + FT_Incremental object; + + } FT_Incremental_InterfaceRec; + + + /************************************************************************** + * + * @type: + * FT_Incremental_Interface + * + * @description: + * A pointer to an @FT_Incremental_InterfaceRec structure. + * + */ + typedef FT_Incremental_InterfaceRec* FT_Incremental_Interface; + + + /* */ + + +FT_END_HEADER + +#endif /* FTINCREM_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftlcdfil.h b/vendor/freetype/include/freetype/ftlcdfil.h new file mode 100644 index 0000000..d3723e1 --- /dev/null +++ b/vendor/freetype/include/freetype/ftlcdfil.h @@ -0,0 +1,323 @@ +/**************************************************************************** + * + * ftlcdfil.h + * + * FreeType API for color filtering of subpixel bitmap glyphs + * (specification). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTLCDFIL_H_ +#define FTLCDFIL_H_ + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * lcd_rendering + * + * @title: + * Subpixel Rendering + * + * @abstract: + * API to control subpixel rendering. + * + * @description: + * FreeType provides two alternative subpixel rendering technologies. + * Should you define `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` in your + * `ftoption.h` file, this enables ClearType-style rendering. + * Otherwise, Harmony LCD rendering is enabled. These technologies are + * controlled differently and API described below, although always + * available, performs its function when appropriate method is enabled + * and does nothing otherwise. + * + * ClearType-style LCD rendering exploits the color-striped structure of + * LCD pixels, increasing the available resolution in the direction of + * the stripe (usually horizontal RGB) by a factor of~3. Using the + * subpixel coverages unfiltered can create severe color fringes + * especially when rendering thin features. Indeed, to produce + * black-on-white text, the nearby color subpixels must be dimmed + * evenly. Therefore, an equalizing 5-tap FIR filter should be applied + * to subpixel coverages regardless of pixel boundaries and should have + * these properties: + * + * 1. It should be symmetrical, like {~a, b, c, b, a~}, to avoid + * any shifts in appearance. + * + * 2. It should be color-balanced, meaning a~+ b~=~c, to reduce color + * fringes by distributing the computed coverage for one subpixel to + * all subpixels equally. + * + * 3. It should be normalized, meaning 2a~+ 2b~+ c~=~1.0 to maintain + * overall brightness. + * + * Boxy 3-tap filter {0, 1/3, 1/3, 1/3, 0} is sharper but is less + * forgiving of non-ideal gamma curves of a screen (and viewing angles), + * beveled filters are fuzzier but more tolerant. + * + * Use the @FT_Library_SetLcdFilter or @FT_Library_SetLcdFilterWeights + * API to specify a low-pass filter, which is then applied to + * subpixel-rendered bitmaps generated through @FT_Render_Glyph. + * + * Harmony LCD rendering is suitable to panels with any regular subpixel + * structure, not just monitors with 3 color striped subpixels, as long + * as the color subpixels have fixed positions relative to the pixel + * center. In this case, each color channel can be rendered separately + * after shifting the outline opposite to the subpixel shift so that the + * coverage maps are aligned. This method is immune to color fringes + * because the shifts do not change integral coverage. + * + * The subpixel geometry must be specified by xy-coordinates for each + * subpixel. By convention they may come in the RGB order: {{-1/3, 0}, + * {0, 0}, {1/3, 0}} for standard RGB striped panel or {{-1/6, 1/4}, + * {-1/6, -1/4}, {1/3, 0}} for a certain PenTile panel. + * + * Use the @FT_Library_SetLcdGeometry API to specify subpixel positions. + * If one follows the RGB order convention, the same order applies to the + * resulting @FT_PIXEL_MODE_LCD and @FT_PIXEL_MODE_LCD_V bitmaps. Note, + * however, that the coordinate frame for the latter must be rotated + * clockwise. Harmony with default LCD geometry is equivalent to + * ClearType with light filter. + * + * As a result of ClearType filtering or Harmony shifts, the resulting + * dimensions of LCD bitmaps can be slightly wider or taller than the + * dimensions the original outline with regard to the pixel grid. + * For example, for @FT_RENDER_MODE_LCD, the filter adds 2~subpixels to + * the left, and 2~subpixels to the right. The bitmap offset values are + * adjusted accordingly, so clients shouldn't need to modify their layout + * and glyph positioning code when enabling the filter. + * + * The ClearType and Harmony rendering is applicable to glyph bitmaps + * rendered through @FT_Render_Glyph, @FT_Load_Glyph, @FT_Load_Char, and + * @FT_Glyph_To_Bitmap, when @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V + * is specified. This API does not control @FT_Outline_Render and + * @FT_Outline_Get_Bitmap. + * + * The described algorithms can completely remove color artefacts when + * combined with gamma-corrected alpha blending in linear space. Each of + * the 3~alpha values (subpixels) must by independently used to blend one + * color channel. That is, red alpha blends the red channel of the text + * color with the red channel of the background pixel. + */ + + + /************************************************************************** + * + * @enum: + * FT_LcdFilter + * + * @description: + * A list of values to identify various types of LCD filters. + * + * @values: + * FT_LCD_FILTER_NONE :: + * Do not perform filtering. When used with subpixel rendering, this + * results in sometimes severe color fringes. + * + * FT_LCD_FILTER_DEFAULT :: + * This is a beveled, normalized, and color-balanced five-tap filter + * with weights of [0x08 0x4D 0x56 0x4D 0x08] in 1/256 units. + * + * FT_LCD_FILTER_LIGHT :: + * this is a boxy, normalized, and color-balanced three-tap filter with + * weights of [0x00 0x55 0x56 0x55 0x00] in 1/256 units. + * + * FT_LCD_FILTER_LEGACY :: + * FT_LCD_FILTER_LEGACY1 :: + * This filter corresponds to the original libXft color filter. It + * provides high contrast output but can exhibit really bad color + * fringes if glyphs are not extremely well hinted to the pixel grid. + * This filter is only provided for comparison purposes, and might be + * disabled or stay unsupported in the future. The second value is + * provided for compatibility with FontConfig, which historically used + * different enumeration, sometimes incorrectly forwarded to FreeType. + * + * @since: + * 2.3.0 (`FT_LCD_FILTER_LEGACY1` since 2.6.2) + */ + typedef enum FT_LcdFilter_ + { + FT_LCD_FILTER_NONE = 0, + FT_LCD_FILTER_DEFAULT = 1, + FT_LCD_FILTER_LIGHT = 2, + FT_LCD_FILTER_LEGACY1 = 3, + FT_LCD_FILTER_LEGACY = 16, + + FT_LCD_FILTER_MAX /* do not remove */ + + } FT_LcdFilter; + + + /************************************************************************** + * + * @function: + * FT_Library_SetLcdFilter + * + * @description: + * This function is used to change filter applied to LCD decimated + * bitmaps, like the ones used when calling @FT_Render_Glyph with + * @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V. + * + * @input: + * library :: + * A handle to the target library instance. + * + * filter :: + * The filter type. + * + * You can use @FT_LCD_FILTER_NONE here to disable this feature, or + * @FT_LCD_FILTER_DEFAULT to use a default filter that should work well + * on most LCD screens. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Since 2.10.3 the LCD filtering is enabled with @FT_LCD_FILTER_DEFAULT. + * It is no longer necessary to call this function explicitly except + * to choose a different filter or disable filtering altogether with + * @FT_LCD_FILTER_NONE. + * + * This function does nothing but returns `FT_Err_Unimplemented_Feature` + * if the configuration macro `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is + * not defined in your build of the library. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ); + + + /************************************************************************** + * + * @function: + * FT_Library_SetLcdFilterWeights + * + * @description: + * This function can be used to enable LCD filter with custom weights, + * instead of using presets in @FT_Library_SetLcdFilter. + * + * @input: + * library :: + * A handle to the target library instance. + * + * weights :: + * A pointer to an array; the function copies the first five bytes and + * uses them to specify the filter weights in 1/256 units. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function does nothing but returns `FT_Err_Unimplemented_Feature` + * if the configuration macro `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is + * not defined in your build of the library. + * + * LCD filter weights can also be set per face using @FT_Face_Properties + * with @FT_PARAM_TAG_LCD_FILTER_WEIGHTS. + * + * @since: + * 2.4.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ); + + + /************************************************************************** + * + * @type: + * FT_LcdFiveTapFilter + * + * @description: + * A typedef for passing the five LCD filter weights to + * @FT_Face_Properties within an @FT_Parameter structure. + * + * @since: + * 2.8 + * + */ +#define FT_LCD_FILTER_FIVE_TAPS 5 + + typedef FT_Byte FT_LcdFiveTapFilter[FT_LCD_FILTER_FIVE_TAPS]; + + + /************************************************************************** + * + * @function: + * FT_Library_SetLcdGeometry + * + * @description: + * This function can be used to modify default positions of color + * subpixels, which controls Harmony LCD rendering. + * + * @input: + * library :: + * A handle to the target library instance. + * + * sub :: + * A pointer to an array of 3 vectors in 26.6 fractional pixel format; + * the function modifies the default values, see the note below. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Subpixel geometry examples: + * + * - {{-21, 0}, {0, 0}, {21, 0}} is the default, corresponding to 3 color + * stripes shifted by a third of a pixel. This could be an RGB panel. + * + * - {{21, 0}, {0, 0}, {-21, 0}} looks the same as the default but can + * specify a BGR panel instead, while keeping the bitmap in the same + * RGB888 format. + * + * - {{0, 21}, {0, 0}, {0, -21}} is the vertical RGB, but the bitmap + * stays RGB888 as a result. + * + * - {{-11, 16}, {-11, -16}, {22, 0}} is a certain PenTile arrangement. + * + * This function does nothing and returns `FT_Err_Unimplemented_Feature` + * in the context of ClearType-style subpixel rendering when + * `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is defined in your build of the + * library. + * + * @since: + * 2.10.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdGeometry( FT_Library library, + FT_Vector sub[3] ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLCDFIL_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftlist.h b/vendor/freetype/include/freetype/ftlist.h new file mode 100644 index 0000000..b553131 --- /dev/null +++ b/vendor/freetype/include/freetype/ftlist.h @@ -0,0 +1,296 @@ +/**************************************************************************** + * + * ftlist.h + * + * Generic list support for FreeType (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file implements functions relative to list processing. Its data + * structures are defined in `freetype.h`. + * + */ + + +#ifndef FTLIST_H_ +#define FTLIST_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * list_processing + * + * @title: + * List Processing + * + * @abstract: + * Simple management of lists. + * + * @description: + * This section contains various definitions related to list processing + * using doubly-linked nodes. + * + * @order: + * FT_List + * FT_ListNode + * FT_ListRec + * FT_ListNodeRec + * + * FT_List_Add + * FT_List_Insert + * FT_List_Find + * FT_List_Remove + * FT_List_Up + * FT_List_Iterate + * FT_List_Iterator + * FT_List_Finalize + * FT_List_Destructor + * + */ + + + /************************************************************************** + * + * @function: + * FT_List_Find + * + * @description: + * Find the list node for a given listed object. + * + * @input: + * list :: + * A pointer to the parent list. + * data :: + * The address of the listed object. + * + * @return: + * List node. `NULL` if it wasn't found. + */ + FT_EXPORT( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ); + + + /************************************************************************** + * + * @function: + * FT_List_Add + * + * @description: + * Append an element to the end of a list. + * + * @inout: + * list :: + * A pointer to the parent list. + * node :: + * The node to append. + */ + FT_EXPORT( void ) + FT_List_Add( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @function: + * FT_List_Insert + * + * @description: + * Insert an element at the head of a list. + * + * @inout: + * list :: + * A pointer to parent list. + * node :: + * The node to insert. + */ + FT_EXPORT( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @function: + * FT_List_Remove + * + * @description: + * Remove a node from a list. This function doesn't check whether the + * node is in the list! + * + * @input: + * node :: + * The node to remove. + * + * @inout: + * list :: + * A pointer to the parent list. + */ + FT_EXPORT( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @function: + * FT_List_Up + * + * @description: + * Move a node to the head/top of a list. Used to maintain LRU lists. + * + * @inout: + * list :: + * A pointer to the parent list. + * node :: + * The node to move. + */ + FT_EXPORT( void ) + FT_List_Up( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @functype: + * FT_List_Iterator + * + * @description: + * An FT_List iterator function that is called during a list parse by + * @FT_List_Iterate. + * + * @input: + * node :: + * The current iteration list node. + * + * user :: + * A typeless pointer passed to @FT_List_Iterate. Can be used to point + * to the iteration's state. + */ + typedef FT_Error + (*FT_List_Iterator)( FT_ListNode node, + void* user ); + + + /************************************************************************** + * + * @function: + * FT_List_Iterate + * + * @description: + * Parse a list and calls a given iterator function on each element. + * Note that parsing is stopped as soon as one of the iterator calls + * returns a non-zero value. + * + * @input: + * list :: + * A handle to the list. + * iterator :: + * An iterator function, called on each node of the list. + * user :: + * A user-supplied field that is passed as the second argument to the + * iterator. + * + * @return: + * The result (a FreeType error code) of the last iterator call. + */ + FT_EXPORT( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ); + + + /************************************************************************** + * + * @functype: + * FT_List_Destructor + * + * @description: + * An @FT_List iterator function that is called during a list + * finalization by @FT_List_Finalize to destroy all elements in a given + * list. + * + * @input: + * system :: + * The current system object. + * + * data :: + * The current object to destroy. + * + * user :: + * A typeless pointer passed to @FT_List_Iterate. It can be used to + * point to the iteration's state. + */ + typedef void + (*FT_List_Destructor)( FT_Memory memory, + void* data, + void* user ); + + + /************************************************************************** + * + * @function: + * FT_List_Finalize + * + * @description: + * Destroy all elements in the list as well as the list itself. + * + * @input: + * list :: + * A handle to the list. + * + * destroy :: + * A list destructor that will be applied to each element of the list. + * Set this to `NULL` if not needed. + * + * memory :: + * The current memory object that handles deallocation. + * + * user :: + * A user-supplied field that is passed as the last argument to the + * destructor. + * + * @note: + * This function expects that all nodes added by @FT_List_Add or + * @FT_List_Insert have been dynamically allocated. + */ + FT_EXPORT( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLIST_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftlogging.h b/vendor/freetype/include/freetype/ftlogging.h new file mode 100644 index 0000000..53b8b89 --- /dev/null +++ b/vendor/freetype/include/freetype/ftlogging.h @@ -0,0 +1,184 @@ +/**************************************************************************** + * + * ftlogging.h + * + * Additional debugging APIs. + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTLOGGING_H_ +#define FTLOGGING_H_ + + +#include +#include FT_CONFIG_CONFIG_H + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * debugging_apis + * + * @title: + * External Debugging APIs + * + * @abstract: + * Public APIs to control the `FT_DEBUG_LOGGING` macro. + * + * @description: + * This section contains the declarations of public functions that + * enables fine control of what the `FT_DEBUG_LOGGING` macro outputs. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Level + * + * @description: + * Change the levels of tracing components of FreeType at run time. + * + * @input: + * tracing_level :: + * New tracing value. + * + * @example: + * The following call makes FreeType trace everything but the 'memory' + * component. + * + * ``` + * FT_Trace_Set_Level( "any:7 memory:0" ); + * ``` + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Level( const char* tracing_level ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Default_Level + * + * @description: + * Reset tracing value of FreeType's components to the default value + * (i.e., to the value of the `FT2_DEBUG` environment value or to NULL + * if `FT2_DEBUG` is not set). + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Default_Level( void ); + + + /************************************************************************** + * + * @functype: + * FT_Custom_Log_Handler + * + * @description: + * A function typedef that is used to handle the logging of tracing and + * debug messages on a file system. + * + * @input: + * ft_component :: + * The name of `FT_COMPONENT` from which the current debug or error + * message is produced. + * + * fmt :: + * Actual debug or tracing message. + * + * args:: + * Arguments of debug or tracing messages. + * + * @since: + * 2.11 + * + */ + typedef void + (*FT_Custom_Log_Handler)( const char* ft_component, + const char* fmt, + va_list args ); + + + /************************************************************************** + * + * @function: + * FT_Set_Log_Handler + * + * @description: + * A function to set a custom log handler. + * + * @input: + * handler :: + * New logging function. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ); + + + /************************************************************************** + * + * @function: + * FT_Set_Default_Log_Handler + * + * @description: + * A function to undo the effect of @FT_Set_Log_Handler, resetting the + * log handler to FreeType's built-in version. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Default_Log_Handler( void ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLOGGING_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftlzw.h b/vendor/freetype/include/freetype/ftlzw.h new file mode 100644 index 0000000..adfd172 --- /dev/null +++ b/vendor/freetype/include/freetype/ftlzw.h @@ -0,0 +1,100 @@ +/**************************************************************************** + * + * ftlzw.h + * + * LZW-compressed stream support. + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTLZW_H_ +#define FTLZW_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * lzw + * + * @title: + * LZW Streams + * + * @abstract: + * Using LZW-compressed font files. + * + * @description: + * In certain builds of the library, LZW compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a LZW stream from it and + * re-open the face with it. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * + * This section contains the declaration of LZW-specific functions. + * + */ + + /************************************************************************** + * + * @function: + * FT_Stream_OpenLZW + * + * @description: + * Open a new stream to parse LZW-compressed font files. This is mainly + * used to support the compressed `*.pcf.Z` fonts that come with XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close` on the new stream will + * **not** call `FT_Stream_Close` on the source stream. None of the + * stream objects will be released to the heap. + * + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with LZW support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLZW_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftmac.h b/vendor/freetype/include/freetype/ftmac.h new file mode 100644 index 0000000..a91e38f --- /dev/null +++ b/vendor/freetype/include/freetype/ftmac.h @@ -0,0 +1,289 @@ +/**************************************************************************** + * + * ftmac.h + * + * Additional Mac-specific API. + * + * Copyright (C) 1996-2023 by + * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +/**************************************************************************** + * + * NOTE: Include this file after `FT_FREETYPE_H` and after any + * Mac-specific headers (because this header uses Mac types such as + * 'Handle', 'FSSpec', 'FSRef', etc.) + * + */ + + +#ifndef FTMAC_H_ +#define FTMAC_H_ + + + + +FT_BEGIN_HEADER + + + /* gcc-3.1 and later can warn about functions tagged as deprecated */ +#ifndef FT_DEPRECATED_ATTRIBUTE +#if defined( __GNUC__ ) && \ + ( ( __GNUC__ >= 4 ) || \ + ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 1 ) ) ) +#define FT_DEPRECATED_ATTRIBUTE __attribute__(( deprecated )) +#else +#define FT_DEPRECATED_ATTRIBUTE +#endif +#endif + + + /************************************************************************** + * + * @section: + * mac_specific + * + * @title: + * Mac Specific Interface + * + * @abstract: + * Only available on the Macintosh. + * + * @description: + * The following definitions are only available if FreeType is compiled + * on a Macintosh. + * + */ + + + /************************************************************************** + * + * @function: + * FT_New_Face_From_FOND + * + * @description: + * Create a new face object from a FOND resource. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * fond :: + * A FOND resource. + * + * face_index :: + * Only supported for the -1 'sanity check' special case. + * + * @output: + * aface :: + * A handle to a new face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @example: + * This function can be used to create @FT_Face objects from fonts that + * are installed in the system as follows. + * + * ``` + * fond = GetResource( 'FOND', fontName ); + * error = FT_New_Face_From_FOND( library, fond, 0, &face ); + * ``` + */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_GetFile_From_Mac_Name + * + * @description: + * Return an FSSpec for the disk file containing the named font. + * + * @input: + * fontName :: + * Mac OS name of the font (e.g., Times New Roman Bold). + * + * @output: + * pathSpec :: + * FSSpec to the file. For passing to @FT_New_Face_From_FSSpec. + * + * face_index :: + * Index of the face. For passing to @FT_New_Face_From_FSSpec. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_GetFile_From_Mac_ATS_Name + * + * @description: + * Return an FSSpec for the disk file containing the named font. + * + * @input: + * fontName :: + * Mac OS name of the font in ATS framework. + * + * @output: + * pathSpec :: + * FSSpec to the file. For passing to @FT_New_Face_From_FSSpec. + * + * face_index :: + * Index of the face. For passing to @FT_New_Face_From_FSSpec. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_GetFilePath_From_Mac_ATS_Name + * + * @description: + * Return a pathname of the disk file and face index for given font name + * that is handled by ATS framework. + * + * @input: + * fontName :: + * Mac OS name of the font in ATS framework. + * + * @output: + * path :: + * Buffer to store pathname of the file. For passing to @FT_New_Face. + * The client must allocate this buffer before calling this function. + * + * maxPathSize :: + * Lengths of the buffer `path` that client allocated. + * + * face_index :: + * Index of the face. For passing to @FT_New_Face. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_New_Face_From_FSSpec + * + * @description: + * Create a new face object from a given resource and typeface index + * using an FSSpec to the font file. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * spec :: + * FSSpec to the font file. + * + * face_index :: + * The index of the face within the resource. The first face has + * index~0. + * @output: + * aface :: + * A handle to a new face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * @FT_New_Face_From_FSSpec is identical to @FT_New_Face except it + * accepts an FSSpec instead of a path. + */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec *spec, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_New_Face_From_FSRef + * + * @description: + * Create a new face object from a given resource and typeface index + * using an FSRef to the font file. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * spec :: + * FSRef to the font file. + * + * face_index :: + * The index of the face within the resource. The first face has + * index~0. + * @output: + * aface :: + * A handle to a new face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * @FT_New_Face_From_FSRef is identical to @FT_New_Face except it accepts + * an FSRef instead of a path. + */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef *ref, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + /* */ + + +FT_END_HEADER + + +#endif /* FTMAC_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftmm.h b/vendor/freetype/include/freetype/ftmm.h new file mode 100644 index 0000000..d145128 --- /dev/null +++ b/vendor/freetype/include/freetype/ftmm.h @@ -0,0 +1,805 @@ +/**************************************************************************** + * + * ftmm.h + * + * FreeType Multiple Master font interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMM_H_ +#define FTMM_H_ + + +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * multiple_masters + * + * @title: + * Multiple Masters + * + * @abstract: + * How to manage Multiple Masters fonts. + * + * @description: + * The following types and functions are used to manage Multiple Master + * fonts, i.e., the selection of specific design instances by setting + * design axis coordinates. + * + * Besides Adobe MM fonts, the interface supports Apple's TrueType GX and + * OpenType variation fonts. Some of the routines only work with Adobe + * MM fonts, others will work with all three types. They are similar + * enough that a consistent interface makes sense. + * + * For Adobe MM fonts, macro @FT_IS_SFNT returns false. For GX and + * OpenType variation fonts, it returns true. + * + */ + + + /************************************************************************** + * + * @struct: + * FT_MM_Axis + * + * @description: + * A structure to model a given axis in design space for Multiple Masters + * fonts. + * + * This structure can't be used for TrueType GX or OpenType variation + * fonts. + * + * @fields: + * name :: + * The axis's name. + * + * minimum :: + * The axis's minimum design coordinate. + * + * maximum :: + * The axis's maximum design coordinate. + */ + typedef struct FT_MM_Axis_ + { + FT_String* name; + FT_Long minimum; + FT_Long maximum; + + } FT_MM_Axis; + + + /************************************************************************** + * + * @struct: + * FT_Multi_Master + * + * @description: + * A structure to model the axes and space of a Multiple Masters font. + * + * This structure can't be used for TrueType GX or OpenType variation + * fonts. + * + * @fields: + * num_axis :: + * Number of axes. Cannot exceed~4. + * + * num_designs :: + * Number of designs; should be normally 2^num_axis even though the + * Type~1 specification strangely allows for intermediate designs to be + * present. This number cannot exceed~16. + * + * axis :: + * A table of axis descriptors. + */ + typedef struct FT_Multi_Master_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_MM_Axis axis[T1_MAX_MM_AXIS]; + + } FT_Multi_Master; + + + /************************************************************************** + * + * @struct: + * FT_Var_Axis + * + * @description: + * A structure to model a given axis in design space for Multiple + * Masters, TrueType GX, and OpenType variation fonts. + * + * @fields: + * name :: + * The axis's name. Not always meaningful for TrueType GX or OpenType + * variation fonts. + * + * minimum :: + * The axis's minimum design coordinate. + * + * def :: + * The axis's default design coordinate. FreeType computes meaningful + * default values for Adobe MM fonts. + * + * maximum :: + * The axis's maximum design coordinate. + * + * tag :: + * The axis's tag (the equivalent to 'name' for TrueType GX and + * OpenType variation fonts). FreeType provides default values for + * Adobe MM fonts if possible. + * + * strid :: + * The axis name entry in the font's 'name' table. This is another + * (and often better) version of the 'name' field for TrueType GX or + * OpenType variation fonts. Not meaningful for Adobe MM fonts. + * + * @note: + * The fields `minimum`, `def`, and `maximum` are 16.16 fractional values + * for TrueType GX and OpenType variation fonts. For Adobe MM fonts, the + * values are whole numbers (i.e., the fractional part is zero). + */ + typedef struct FT_Var_Axis_ + { + FT_String* name; + + FT_Fixed minimum; + FT_Fixed def; + FT_Fixed maximum; + + FT_ULong tag; + FT_UInt strid; + + } FT_Var_Axis; + + + /************************************************************************** + * + * @struct: + * FT_Var_Named_Style + * + * @description: + * A structure to model a named instance in a TrueType GX or OpenType + * variation font. + * + * This structure can't be used for Adobe MM fonts. + * + * @fields: + * coords :: + * The design coordinates for this instance. This is an array with one + * entry for each axis. + * + * strid :: + * The entry in 'name' table identifying this instance. + * + * psid :: + * The entry in 'name' table identifying a PostScript name for this + * instance. Value 0xFFFF indicates a missing entry. + */ + typedef struct FT_Var_Named_Style_ + { + FT_Fixed* coords; + FT_UInt strid; + FT_UInt psid; /* since 2.7.1 */ + + } FT_Var_Named_Style; + + + /************************************************************************** + * + * @struct: + * FT_MM_Var + * + * @description: + * A structure to model the axes and space of an Adobe MM, TrueType GX, + * or OpenType variation font. + * + * Some fields are specific to one format and not to the others. + * + * @fields: + * num_axis :: + * The number of axes. The maximum value is~4 for Adobe MM fonts; no + * limit in TrueType GX or OpenType variation fonts. + * + * num_designs :: + * The number of designs; should be normally 2^num_axis for Adobe MM + * fonts. Not meaningful for TrueType GX or OpenType variation fonts + * (where every glyph could have a different number of designs). + * + * num_namedstyles :: + * The number of named styles; a 'named style' is a tuple of design + * coordinates that has a string ID (in the 'name' table) associated + * with it. The font can tell the user that, for example, + * [Weight=1.5,Width=1.1] is 'Bold'. Another name for 'named style' is + * 'named instance'. + * + * For Adobe Multiple Masters fonts, this value is always zero because + * the format does not support named styles. + * + * axis :: + * An axis descriptor table. TrueType GX and OpenType variation fonts + * contain slightly more data than Adobe MM fonts. Memory management + * of this pointer is done internally by FreeType. + * + * namedstyle :: + * A named style (instance) table. Only meaningful for TrueType GX and + * OpenType variation fonts. Memory management of this pointer is done + * internally by FreeType. + */ + typedef struct FT_MM_Var_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_UInt num_namedstyles; + FT_Var_Axis* axis; + FT_Var_Named_Style* namedstyle; + + } FT_MM_Var; + + + /************************************************************************** + * + * @function: + * FT_Get_Multi_Master + * + * @description: + * Retrieve a variation descriptor of a given Adobe MM font. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @input: + * face :: + * A handle to the source face. + * + * @output: + * amaster :: + * The Multiple Masters descriptor. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ); + + + /************************************************************************** + * + * @function: + * FT_Get_MM_Var + * + * @description: + * Retrieve a variation descriptor for a given font. + * + * This function works with all supported variation formats. + * + * @input: + * face :: + * A handle to the source face. + * + * @output: + * amaster :: + * The variation descriptor. Allocates a data structure, which the + * user must deallocate with a call to @FT_Done_MM_Var after use. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ); + + + /************************************************************************** + * + * @function: + * FT_Done_MM_Var + * + * @description: + * Free the memory allocated by @FT_Get_MM_Var. + * + * @input: + * library :: + * A handle of the face's parent library object that was used in the + * call to @FT_Get_MM_Var to create `amaster`. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Done_MM_Var( FT_Library library, + FT_MM_Var *amaster ); + + + /************************************************************************** + * + * @function: + * FT_Set_MM_Design_Coordinates + * + * @description: + * For Adobe MM fonts, choose an interpolated font design through design + * coordinates. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * num_coords :: + * The number of available design coordinates. If it is larger than + * the number of axes, ignore the excess values. If it is smaller than + * the number of axes, use default values for the remaining axes. + * + * coords :: + * An array of design coordinates. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * [Since 2.8.1] To reset all axes to the default values, call the + * function with `num_coords` set to zero and `coords` set to `NULL`. + * + * [Since 2.9] If `num_coords` is larger than zero, this function sets + * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field + * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, + * this bit flag gets unset. + */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_Var_Design_Coordinates + * + * @description: + * Choose an interpolated font design through design coordinates. + * + * This function works with all supported variation formats. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * num_coords :: + * The number of available design coordinates. If it is larger than + * the number of axes, ignore the excess values. If it is smaller than + * the number of axes, use default values for the remaining axes. + * + * coords :: + * An array of design coordinates. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The design coordinates are 16.16 fractional values for TrueType GX and + * OpenType variation fonts. For Adobe MM fonts, the values are supposed + * to be whole numbers (i.e., the fractional part is zero). + * + * [Since 2.8.1] To reset all axes to the default values, call the + * function with `num_coords` set to zero and `coords` set to `NULL`. + * [Since 2.9] 'Default values' means the currently selected named + * instance (or the base font if no named instance is selected). + * + * [Since 2.9] If `num_coords` is larger than zero, this function sets + * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field + * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, + * this bit flag gets unset. + */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Get_Var_Design_Coordinates + * + * @description: + * Get the design coordinates of the currently selected interpolated + * font. + * + * This function works with all supported variation formats. + * + * @input: + * face :: + * A handle to the source face. + * + * num_coords :: + * The number of design coordinates to retrieve. If it is larger than + * the number of axes, set the excess values to~0. + * + * @output: + * coords :: + * The design coordinates array. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The design coordinates are 16.16 fractional values for TrueType GX and + * OpenType variation fonts. For Adobe MM fonts, the values are whole + * numbers (i.e., the fractional part is zero). + * + * @since: + * 2.7.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_MM_Blend_Coordinates + * + * @description: + * Choose an interpolated font design through normalized blend + * coordinates. + * + * This function works with all supported variation formats. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * num_coords :: + * The number of available design coordinates. If it is larger than + * the number of axes, ignore the excess values. If it is smaller than + * the number of axes, use default values for the remaining axes. + * + * coords :: + * The design coordinates array. Each element is a 16.16 fractional + * value and must be between 0 and 1.0 for Adobe MM fonts, and between + * -1.0 and 1.0 for TrueType GX and OpenType variation fonts. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * [Since 2.8.1] To reset all axes to the default values, call the + * function with `num_coords` set to zero and `coords` set to `NULL`. + * [Since 2.9] 'Default values' means the currently selected named + * instance (or the base font if no named instance is selected). + * + * [Since 2.9] If `num_coords` is larger than zero, this function sets + * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field + * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, + * this bit flag gets unset. + */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Get_MM_Blend_Coordinates + * + * @description: + * Get the normalized blend coordinates of the currently selected + * interpolated font. + * + * This function works with all supported variation formats. + * + * @input: + * face :: + * A handle to the source face. + * + * num_coords :: + * The number of normalized blend coordinates to retrieve. If it is + * larger than the number of axes, set the excess values to~0.5 for + * Adobe MM fonts, and to~0 for TrueType GX and OpenType variation + * fonts. + * + * @output: + * coords :: + * The normalized blend coordinates array (as 16.16 fractional values). + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.7.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_Var_Blend_Coordinates + * + * @description: + * This is another name of @FT_Set_MM_Blend_Coordinates. + */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Get_Var_Blend_Coordinates + * + * @description: + * This is another name of @FT_Get_MM_Blend_Coordinates. + * + * @since: + * 2.7.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_MM_WeightVector + * + * @description: + * For Adobe MM fonts, choose an interpolated font design by directly + * setting the weight vector. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * len :: + * The length of the weight vector array. If it is larger than the + * number of designs, the extra values are ignored. If it is less than + * the number of designs, the remaining values are set to zero. + * + * weightvector :: + * An array representing the weight vector. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Adobe Multiple Master fonts limit the number of designs, and thus the + * length of the weight vector to 16~elements. + * + * If `len` is larger than zero, this function sets the + * @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e., + * @FT_IS_VARIATION will return true). If `len` is zero, this bit flag + * is unset and the weight vector array is reset to the default values. + * + * The Adobe documentation also states that the values in the + * WeightVector array must total 1.0 +/-~0.001. In practice this does + * not seem to be enforced, so is not enforced here, either. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ); + + + /************************************************************************** + * + * @function: + * FT_Get_MM_WeightVector + * + * @description: + * For Adobe MM fonts, retrieve the current weight vector of the font. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * len :: + * A pointer to the size of the array to be filled. If the size of the + * array is less than the number of designs, `FT_Err_Invalid_Argument` + * is returned, and `len` is set to the required size (the number of + * designs). If the size of the array is greater than the number of + * designs, the remaining entries are set to~0. On successful + * completion, `len` is set to the number of designs (i.e., the number + * of values written to the array). + * + * @output: + * weightvector :: + * An array to be filled. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Adobe Multiple Master fonts limit the number of designs, and thus the + * length of the WeightVector to~16. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ); + + + /************************************************************************** + * + * @enum: + * FT_VAR_AXIS_FLAG_XXX + * + * @description: + * A list of bit flags used in the return value of + * @FT_Get_Var_Axis_Flags. + * + * @values: + * FT_VAR_AXIS_FLAG_HIDDEN :: + * The variation axis should not be exposed to user interfaces. + * + * @since: + * 2.8.1 + */ +#define FT_VAR_AXIS_FLAG_HIDDEN 1 + + + /************************************************************************** + * + * @function: + * FT_Get_Var_Axis_Flags + * + * @description: + * Get the 'flags' field of an OpenType Variation Axis Record. + * + * Not meaningful for Adobe MM fonts (`*flags` is always zero). + * + * @input: + * master :: + * The variation descriptor. + * + * axis_index :: + * The index of the requested variation axis. + * + * @output: + * flags :: + * The 'flags' field. See @FT_VAR_AXIS_FLAG_XXX for possible values. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.8.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Var_Axis_Flags( FT_MM_Var* master, + FT_UInt axis_index, + FT_UInt* flags ); + + + /************************************************************************** + * + * @function: + * FT_Set_Named_Instance + * + * @description: + * Set or change the current named instance. + * + * @input: + * face :: + * A handle to the source face. + * + * instance_index :: + * The index of the requested instance, starting with value 1. If set + * to value 0, FreeType switches to font access without a named + * instance. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The function uses the value of `instance_index` to set bits 16-30 of + * the face's `face_index` field. It also resets any variation applied + * to the font, and the @FT_FACE_FLAG_VARIATION bit of the face's + * `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION will + * return false). + * + * For Adobe MM fonts (which don't have named instances) this function + * simply resets the current face to the default instance. + * + * @since: + * 2.9 + */ + FT_EXPORT( FT_Error ) + FT_Set_Named_Instance( FT_Face face, + FT_UInt instance_index ); + + + /************************************************************************** + * + * @function: + * FT_Get_Default_Named_Instance + * + * @description: + * Retrieve the index of the default named instance, to be used with + * @FT_Set_Named_Instance. + * + * The default instance of a variation font is that instance for which + * the nth axis coordinate is equal to `axis[n].def` (as specified in the + * @FT_MM_Var structure), with~n covering all axes. + * + * FreeType synthesizes a named instance for the default instance if the + * font does not contain such an entry. + * + * @input: + * face :: + * A handle to the source face. + * + * @output: + * instance_index :: + * The index of the default named instance. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * For Adobe MM fonts (which don't have named instances) this function + * always returns zero for `instance_index`. + * + * @since: + * 2.13.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ); + + /* */ + + +FT_END_HEADER + +#endif /* FTMM_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftmodapi.h b/vendor/freetype/include/freetype/ftmodapi.h new file mode 100644 index 0000000..c8f0c2c --- /dev/null +++ b/vendor/freetype/include/freetype/ftmodapi.h @@ -0,0 +1,807 @@ +/**************************************************************************** + * + * ftmodapi.h + * + * FreeType modules public interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMODAPI_H_ +#define FTMODAPI_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * module_management + * + * @title: + * Module Management + * + * @abstract: + * How to add, upgrade, remove, and control modules from FreeType. + * + * @description: + * The definitions below are used to manage modules within FreeType. + * Internal and external modules can be added, upgraded, and removed at + * runtime. For example, an alternative renderer or proprietary font + * driver can be registered and prioritized. Additionally, some module + * properties can also be controlled. + * + * Here is a list of existing values of the `module_name` field in the + * @FT_Module_Class structure. + * + * ``` + * autofitter + * bdf + * cff + * gxvalid + * otvalid + * pcf + * pfr + * psaux + * pshinter + * psnames + * raster1 + * sfnt + * smooth + * truetype + * type1 + * type42 + * t1cid + * winfonts + * ``` + * + * Note that the FreeType Cache sub-system is not a FreeType module. + * + * @order: + * FT_Module + * FT_Module_Constructor + * FT_Module_Destructor + * FT_Module_Requester + * FT_Module_Class + * + * FT_Add_Module + * FT_Get_Module + * FT_Remove_Module + * FT_Add_Default_Modules + * + * FT_FACE_DRIVER_NAME + * FT_Property_Set + * FT_Property_Get + * FT_Set_Default_Properties + * + * FT_New_Library + * FT_Done_Library + * FT_Reference_Library + * + * FT_Renderer + * FT_Renderer_Class + * + * FT_Get_Renderer + * FT_Set_Renderer + * + * FT_Set_Debug_Hook + * + */ + + + /* module bit flags */ +#define FT_MODULE_FONT_DRIVER 1 /* this module is a font driver */ +#define FT_MODULE_RENDERER 2 /* this module is a renderer */ +#define FT_MODULE_HINTER 4 /* this module is a glyph hinter */ +#define FT_MODULE_STYLER 8 /* this module is a styler */ + +#define FT_MODULE_DRIVER_SCALABLE 0x100 /* the driver supports */ + /* scalable fonts */ +#define FT_MODULE_DRIVER_NO_OUTLINES 0x200 /* the driver does not */ + /* support vector outlines */ +#define FT_MODULE_DRIVER_HAS_HINTER 0x400 /* the driver provides its */ + /* own hinter */ +#define FT_MODULE_DRIVER_HINTS_LIGHTLY 0x800 /* the driver's hinter */ + /* produces LIGHT hints */ + + + /* deprecated values */ +#define ft_module_font_driver FT_MODULE_FONT_DRIVER +#define ft_module_renderer FT_MODULE_RENDERER +#define ft_module_hinter FT_MODULE_HINTER +#define ft_module_styler FT_MODULE_STYLER + +#define ft_module_driver_scalable FT_MODULE_DRIVER_SCALABLE +#define ft_module_driver_no_outlines FT_MODULE_DRIVER_NO_OUTLINES +#define ft_module_driver_has_hinter FT_MODULE_DRIVER_HAS_HINTER +#define ft_module_driver_hints_lightly FT_MODULE_DRIVER_HINTS_LIGHTLY + + + typedef FT_Pointer FT_Module_Interface; + + + /************************************************************************** + * + * @functype: + * FT_Module_Constructor + * + * @description: + * A function used to initialize (not create) a new module object. + * + * @input: + * module :: + * The module to initialize. + */ + typedef FT_Error + (*FT_Module_Constructor)( FT_Module module ); + + + /************************************************************************** + * + * @functype: + * FT_Module_Destructor + * + * @description: + * A function used to finalize (not destroy) a given module object. + * + * @input: + * module :: + * The module to finalize. + */ + typedef void + (*FT_Module_Destructor)( FT_Module module ); + + + /************************************************************************** + * + * @functype: + * FT_Module_Requester + * + * @description: + * A function used to query a given module for a specific interface. + * + * @input: + * module :: + * The module to be searched. + * + * name :: + * The name of the interface in the module. + */ + typedef FT_Module_Interface + (*FT_Module_Requester)( FT_Module module, + const char* name ); + + + /************************************************************************** + * + * @struct: + * FT_Module_Class + * + * @description: + * The module class descriptor. While being a public structure necessary + * for FreeType's module bookkeeping, most of the fields are essentially + * internal, not to be used directly by an application. + * + * @fields: + * module_flags :: + * Bit flags describing the module. + * + * module_size :: + * The size of one module object/instance in bytes. + * + * module_name :: + * The name of the module. + * + * module_version :: + * The version, as a 16.16 fixed number (major.minor). + * + * module_requires :: + * The version of FreeType this module requires, as a 16.16 fixed + * number (major.minor). Starts at version 2.0, i.e., 0x20000. + * + * module_interface :: + * A typeless pointer to a structure (which varies between different + * modules) that holds the module's interface functions. This is + * essentially what `get_interface` returns. + * + * module_init :: + * The initializing function. + * + * module_done :: + * The finalizing function. + * + * get_interface :: + * The interface requesting function. + */ + typedef struct FT_Module_Class_ + { + FT_ULong module_flags; + FT_Long module_size; + const FT_String* module_name; + FT_Fixed module_version; + FT_Fixed module_requires; + + const void* module_interface; + + FT_Module_Constructor module_init; + FT_Module_Destructor module_done; + FT_Module_Requester get_interface; + + } FT_Module_Class; + + + /************************************************************************** + * + * @function: + * FT_Add_Module + * + * @description: + * Add a new module to a given library instance. + * + * @inout: + * library :: + * A handle to the library object. + * + * @input: + * clazz :: + * A pointer to class descriptor for the module. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * An error will be returned if a module already exists by that name, or + * if the module requires a version of FreeType that is too great. + */ + FT_EXPORT( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ); + + + /************************************************************************** + * + * @function: + * FT_Get_Module + * + * @description: + * Find a module by its name. + * + * @input: + * library :: + * A handle to the library object. + * + * module_name :: + * The module's name (as an ASCII string). + * + * @return: + * A module handle. 0~if none was found. + * + * @note: + * FreeType's internal modules aren't documented very well, and you + * should look up the source code for details. + */ + FT_EXPORT( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ); + + + /************************************************************************** + * + * @function: + * FT_Remove_Module + * + * @description: + * Remove a given module from a library instance. + * + * @inout: + * library :: + * A handle to a library object. + * + * @input: + * module :: + * A handle to a module object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The module object is destroyed by the function in case of success. + */ + FT_EXPORT( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ); + + + /************************************************************************** + * + * @macro: + * FT_FACE_DRIVER_NAME + * + * @description: + * A macro that retrieves the name of a font driver from a face object. + * + * @note: + * The font driver name is a valid `module_name` for @FT_Property_Set + * and @FT_Property_Get. This is not the same as @FT_Get_Font_Format. + * + * @since: + * 2.11 + * + */ +#define FT_FACE_DRIVER_NAME( face ) \ + ( ( *FT_REINTERPRET_CAST( FT_Module_Class**, \ + ( face )->driver ) )->module_name ) + + + /************************************************************************** + * + * @function: + * FT_Property_Set + * + * @description: + * Set a property for a given module. + * + * @input: + * library :: + * A handle to the library the module is part of. + * + * module_name :: + * The module name. + * + * property_name :: + * The property name. Properties are described in section + * @properties. + * + * Note that only a few modules have properties. + * + * value :: + * A generic pointer to a variable or structure that gives the new + * value of the property. The exact definition of `value` is + * dependent on the property; see section @properties. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `module_name` isn't a valid module name, or `property_name` + * doesn't specify a valid property, or if `value` doesn't represent a + * valid value for the given property, an error is returned. + * + * The following example sets property 'bar' (a simple integer) in + * module 'foo' to value~1. + * + * ``` + * FT_UInt bar; + * + * + * bar = 1; + * FT_Property_Set( library, "foo", "bar", &bar ); + * ``` + * + * Note that the FreeType Cache sub-system doesn't recognize module + * property changes. To avoid glyph lookup confusion within the cache + * you should call @FTC_Manager_Reset to completely flush the cache if a + * module property gets changed after @FTC_Manager_New has been called. + * + * It is not possible to set properties of the FreeType Cache sub-system + * itself with FT_Property_Set; use @FTC_Property_Set instead. + * + * @since: + * 2.4.11 + * + */ + FT_EXPORT( FT_Error ) + FT_Property_Set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + const void* value ); + + + /************************************************************************** + * + * @function: + * FT_Property_Get + * + * @description: + * Get a module's property value. + * + * @input: + * library :: + * A handle to the library the module is part of. + * + * module_name :: + * The module name. + * + * property_name :: + * The property name. Properties are described in section + * @properties. + * + * @inout: + * value :: + * A generic pointer to a variable or structure that gives the value + * of the property. The exact definition of `value` is dependent on + * the property; see section @properties. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `module_name` isn't a valid module name, or `property_name` + * doesn't specify a valid property, or if `value` doesn't represent a + * valid value for the given property, an error is returned. + * + * The following example gets property 'baz' (a range) in module 'foo'. + * + * ``` + * typedef range_ + * { + * FT_Int32 min; + * FT_Int32 max; + * + * } range; + * + * range baz; + * + * + * FT_Property_Get( library, "foo", "baz", &baz ); + * ``` + * + * It is not possible to retrieve properties of the FreeType Cache + * sub-system with FT_Property_Get; use @FTC_Property_Get instead. + * + * @since: + * 2.4.11 + * + */ + FT_EXPORT( FT_Error ) + FT_Property_Get( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value ); + + + /************************************************************************** + * + * @function: + * FT_Set_Default_Properties + * + * @description: + * If compilation option `FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES` is + * set, this function reads the `FREETYPE_PROPERTIES` environment + * variable to control driver properties. See section @properties for + * more. + * + * If the compilation option is not set, this function does nothing. + * + * `FREETYPE_PROPERTIES` has the following syntax form (broken here into + * multiple lines for better readability). + * + * ``` + * + * ':' + * '=' + * + * ':' + * '=' + * ... + * ``` + * + * Example: + * + * ``` + * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ + * cff:no-stem-darkening=0 + * ``` + * + * @inout: + * library :: + * A handle to a new library object. + * + * @since: + * 2.8 + */ + FT_EXPORT( void ) + FT_Set_Default_Properties( FT_Library library ); + + + /************************************************************************** + * + * @function: + * FT_Reference_Library + * + * @description: + * A counter gets initialized to~1 at the time an @FT_Library structure + * is created. This function increments the counter. @FT_Done_Library + * then only destroys a library if the counter is~1, otherwise it simply + * decrements the counter. + * + * This function helps in managing life-cycles of structures that + * reference @FT_Library objects. + * + * @input: + * library :: + * A handle to a target library object. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.4.2 + */ + FT_EXPORT( FT_Error ) + FT_Reference_Library( FT_Library library ); + + + /************************************************************************** + * + * @function: + * FT_New_Library + * + * @description: + * This function is used to create a new FreeType library instance from a + * given memory object. It is thus possible to use libraries with + * distinct memory allocators within the same program. Note, however, + * that the used @FT_Memory structure is expected to remain valid for the + * life of the @FT_Library object. + * + * Normally, you would call this function (followed by a call to + * @FT_Add_Default_Modules or a series of calls to @FT_Add_Module, and a + * call to @FT_Set_Default_Properties) instead of @FT_Init_FreeType to + * initialize the FreeType library. + * + * Don't use @FT_Done_FreeType but @FT_Done_Library to destroy a library + * instance. + * + * @input: + * memory :: + * A handle to the original memory object. + * + * @output: + * alibrary :: + * A pointer to handle of a new library object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * See the discussion of reference counters in the description of + * @FT_Reference_Library. + */ + FT_EXPORT( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ); + + + /************************************************************************** + * + * @function: + * FT_Done_Library + * + * @description: + * Discard a given library object. This closes all drivers and discards + * all resource objects. + * + * @input: + * library :: + * A handle to the target library. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * See the discussion of reference counters in the description of + * @FT_Reference_Library. + */ + FT_EXPORT( FT_Error ) + FT_Done_Library( FT_Library library ); + + + /************************************************************************** + * + * @functype: + * FT_DebugHook_Func + * + * @description: + * A drop-in replacement (or rather a wrapper) for the bytecode or + * charstring interpreter's main loop function. + * + * Its job is essentially + * + * - to activate debug mode to enforce single-stepping, + * + * - to call the main loop function to interpret the next opcode, and + * + * - to show the changed context to the user. + * + * An example for such a main loop function is `TT_RunIns` (declared in + * FreeType's internal header file `src/truetype/ttinterp.h`). + * + * Have a look at the source code of the `ttdebug` FreeType demo program + * for an example of a drop-in replacement. + * + * @inout: + * arg :: + * A typeless pointer, to be cast to the main loop function's data + * structure (which depends on the font module). For TrueType fonts + * it is bytecode interpreter's execution context, `TT_ExecContext`, + * which is declared in FreeType's internal header file `tttypes.h`. + */ + typedef FT_Error + (*FT_DebugHook_Func)( void* arg ); + + + /************************************************************************** + * + * @enum: + * FT_DEBUG_HOOK_XXX + * + * @description: + * A list of named debug hook indices. + * + * @values: + * FT_DEBUG_HOOK_TRUETYPE:: + * This hook index identifies the TrueType bytecode debugger. + */ +#define FT_DEBUG_HOOK_TRUETYPE 0 + + + /************************************************************************** + * + * @function: + * FT_Set_Debug_Hook + * + * @description: + * Set a debug hook function for debugging the interpreter of a font + * format. + * + * While this is a public API function, an application needs access to + * FreeType's internal header files to do something useful. + * + * Have a look at the source code of the `ttdebug` FreeType demo program + * for an example of its usage. + * + * @inout: + * library :: + * A handle to the library object. + * + * @input: + * hook_index :: + * The index of the debug hook. You should use defined enumeration + * macros like @FT_DEBUG_HOOK_TRUETYPE. + * + * debug_hook :: + * The function used to debug the interpreter. + * + * @note: + * Currently, four debug hook slots are available, but only one (for the + * TrueType interpreter) is defined. + */ + FT_EXPORT( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ); + + + /************************************************************************** + * + * @function: + * FT_Add_Default_Modules + * + * @description: + * Add the set of default drivers to a given library object. This is + * only useful when you create a library object with @FT_New_Library + * (usually to plug a custom memory manager). + * + * @inout: + * library :: + * A handle to a new library object. + */ + FT_EXPORT( void ) + FT_Add_Default_Modules( FT_Library library ); + + + + /************************************************************************** + * + * @section: + * truetype_engine + * + * @title: + * The TrueType Engine + * + * @abstract: + * TrueType bytecode support. + * + * @description: + * This section contains a function used to query the level of TrueType + * bytecode support compiled in this version of the library. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_TrueTypeEngineType + * + * @description: + * A list of values describing which kind of TrueType bytecode engine is + * implemented in a given FT_Library instance. It is used by the + * @FT_Get_TrueType_Engine_Type function. + * + * @values: + * FT_TRUETYPE_ENGINE_TYPE_NONE :: + * The library doesn't implement any kind of bytecode interpreter. + * + * FT_TRUETYPE_ENGINE_TYPE_UNPATENTED :: + * Deprecated and removed. + * + * FT_TRUETYPE_ENGINE_TYPE_PATENTED :: + * The library implements a bytecode interpreter that covers the full + * instruction set of the TrueType virtual machine (this was governed + * by patents until May 2010, hence the name). + * + * @since: + * 2.2 + * + */ + typedef enum FT_TrueTypeEngineType_ + { + FT_TRUETYPE_ENGINE_TYPE_NONE = 0, + FT_TRUETYPE_ENGINE_TYPE_UNPATENTED, + FT_TRUETYPE_ENGINE_TYPE_PATENTED + + } FT_TrueTypeEngineType; + + + /************************************************************************** + * + * @function: + * FT_Get_TrueType_Engine_Type + * + * @description: + * Return an @FT_TrueTypeEngineType value to indicate which level of the + * TrueType virtual machine a given library instance supports. + * + * @input: + * library :: + * A library instance. + * + * @return: + * A value indicating which level is supported. + * + * @since: + * 2.2 + * + */ + FT_EXPORT( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ); + + /* */ + + +FT_END_HEADER + +#endif /* FTMODAPI_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftmoderr.h b/vendor/freetype/include/freetype/ftmoderr.h new file mode 100644 index 0000000..c8c892d --- /dev/null +++ b/vendor/freetype/include/freetype/ftmoderr.h @@ -0,0 +1,204 @@ +/**************************************************************************** + * + * ftmoderr.h + * + * FreeType module error offsets (specification). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the FreeType module error codes. + * + * If the macro `FT_CONFIG_OPTION_USE_MODULE_ERRORS` in `ftoption.h` is + * set, the lower byte of an error value identifies the error code as + * usual. In addition, the higher byte identifies the module. For + * example, the error `FT_Err_Invalid_File_Format` has value 0x0003, the + * error `TT_Err_Invalid_File_Format` has value 0x1303, the error + * `T1_Err_Invalid_File_Format` has value 0x1403, etc. + * + * Note that `FT_Err_Ok`, `TT_Err_Ok`, etc. are always equal to zero, + * including the high byte. + * + * If `FT_CONFIG_OPTION_USE_MODULE_ERRORS` isn't set, the higher byte of an + * error value is set to zero. + * + * To hide the various `XXX_Err_` prefixes in the source code, FreeType + * provides some macros in `fttypes.h`. + * + * FT_ERR( err ) + * + * Add current error module prefix (as defined with the `FT_ERR_PREFIX` + * macro) to `err`. For example, in the BDF module the line + * + * ``` + * error = FT_ERR( Invalid_Outline ); + * ``` + * + * expands to + * + * ``` + * error = BDF_Err_Invalid_Outline; + * ``` + * + * For simplicity, you can always use `FT_Err_Ok` directly instead of + * `FT_ERR( Ok )`. + * + * FT_ERR_EQ( errcode, err ) + * FT_ERR_NEQ( errcode, err ) + * + * Compare error code `errcode` with the error `err` for equality and + * inequality, respectively. Example: + * + * ``` + * if ( FT_ERR_EQ( error, Invalid_Outline ) ) + * ... + * ``` + * + * Using this macro you don't have to think about error prefixes. Of + * course, if module errors are not active, the above example is the + * same as + * + * ``` + * if ( error == FT_Err_Invalid_Outline ) + * ... + * ``` + * + * FT_ERROR_BASE( errcode ) + * FT_ERROR_MODULE( errcode ) + * + * Get base error and module error code, respectively. + * + * It can also be used to create a module error message table easily with + * something like + * + * ``` + * #undef FTMODERR_H_ + * #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, + * #define FT_MODERR_START_LIST { + * #define FT_MODERR_END_LIST { 0, 0 } }; + * + * const struct + * { + * int mod_err_offset; + * const char* mod_err_msg + * } ft_mod_errors[] = + * + * #include + * ``` + * + */ + + +#ifndef FTMODERR_H_ +#define FTMODERR_H_ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#ifndef FT_MODERRDEF + +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = v, +#else +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0, +#endif + +#define FT_MODERR_START_LIST enum { +#define FT_MODERR_END_LIST FT_Mod_Err_Max }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_MODERRDEF */ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST MODULE ERROR BASES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_MODERR_START_LIST + FT_MODERR_START_LIST +#endif + + + FT_MODERRDEF( Base, 0x000, "base module" ) + FT_MODERRDEF( Autofit, 0x100, "autofitter module" ) + FT_MODERRDEF( BDF, 0x200, "BDF module" ) + FT_MODERRDEF( Bzip2, 0x300, "Bzip2 module" ) + FT_MODERRDEF( Cache, 0x400, "cache module" ) + FT_MODERRDEF( CFF, 0x500, "CFF module" ) + FT_MODERRDEF( CID, 0x600, "CID module" ) + FT_MODERRDEF( Gzip, 0x700, "Gzip module" ) + FT_MODERRDEF( LZW, 0x800, "LZW module" ) + FT_MODERRDEF( OTvalid, 0x900, "OpenType validation module" ) + FT_MODERRDEF( PCF, 0xA00, "PCF module" ) + FT_MODERRDEF( PFR, 0xB00, "PFR module" ) + FT_MODERRDEF( PSaux, 0xC00, "PS auxiliary module" ) + FT_MODERRDEF( PShinter, 0xD00, "PS hinter module" ) + FT_MODERRDEF( PSnames, 0xE00, "PS names module" ) + FT_MODERRDEF( Raster, 0xF00, "raster module" ) + FT_MODERRDEF( SFNT, 0x1000, "SFNT module" ) + FT_MODERRDEF( Smooth, 0x1100, "smooth raster module" ) + FT_MODERRDEF( TrueType, 0x1200, "TrueType module" ) + FT_MODERRDEF( Type1, 0x1300, "Type 1 module" ) + FT_MODERRDEF( Type42, 0x1400, "Type 42 module" ) + FT_MODERRDEF( Winfonts, 0x1500, "Windows FON/FNT module" ) + FT_MODERRDEF( GXvalid, 0x1600, "GX validation module" ) + FT_MODERRDEF( Sdf, 0x1700, "Signed distance field raster module" ) + + +#ifdef FT_MODERR_END_LIST + FT_MODERR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_MODERR_START_LIST +#undef FT_MODERR_END_LIST +#undef FT_MODERRDEF +#undef FT_NEED_EXTERN_C + + +#endif /* FTMODERR_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftotval.h b/vendor/freetype/include/freetype/ftotval.h new file mode 100644 index 0000000..011bdfc --- /dev/null +++ b/vendor/freetype/include/freetype/ftotval.h @@ -0,0 +1,206 @@ +/**************************************************************************** + * + * ftotval.h + * + * FreeType API for validating OpenType tables (specification). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +/**************************************************************************** + * + * + * Warning: This module might be moved to a different library in the + * future to avoid a tight dependency between FreeType and the + * OpenType specification. + * + * + */ + + +#ifndef FTOTVAL_H_ +#define FTOTVAL_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * ot_validation + * + * @title: + * OpenType Validation + * + * @abstract: + * An API to validate OpenType tables. + * + * @description: + * This section contains the declaration of functions to validate some + * OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). + * + * @order: + * FT_OpenType_Validate + * FT_OpenType_Free + * + * FT_VALIDATE_OTXXX + * + */ + + + /************************************************************************** + * + * @enum: + * FT_VALIDATE_OTXXX + * + * @description: + * A list of bit-field constants used with @FT_OpenType_Validate to + * indicate which OpenType tables should be validated. + * + * @values: + * FT_VALIDATE_BASE :: + * Validate BASE table. + * + * FT_VALIDATE_GDEF :: + * Validate GDEF table. + * + * FT_VALIDATE_GPOS :: + * Validate GPOS table. + * + * FT_VALIDATE_GSUB :: + * Validate GSUB table. + * + * FT_VALIDATE_JSTF :: + * Validate JSTF table. + * + * FT_VALIDATE_MATH :: + * Validate MATH table. + * + * FT_VALIDATE_OT :: + * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). + * + */ +#define FT_VALIDATE_BASE 0x0100 +#define FT_VALIDATE_GDEF 0x0200 +#define FT_VALIDATE_GPOS 0x0400 +#define FT_VALIDATE_GSUB 0x0800 +#define FT_VALIDATE_JSTF 0x1000 +#define FT_VALIDATE_MATH 0x2000 + +#define FT_VALIDATE_OT ( FT_VALIDATE_BASE | \ + FT_VALIDATE_GDEF | \ + FT_VALIDATE_GPOS | \ + FT_VALIDATE_GSUB | \ + FT_VALIDATE_JSTF | \ + FT_VALIDATE_MATH ) + + + /************************************************************************** + * + * @function: + * FT_OpenType_Validate + * + * @description: + * Validate various OpenType tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library that + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field that specifies the tables to be validated. See + * @FT_VALIDATE_OTXXX for possible values. + * + * @output: + * BASE_table :: + * A pointer to the BASE table. + * + * GDEF_table :: + * A pointer to the GDEF table. + * + * GPOS_table :: + * A pointer to the GPOS table. + * + * GSUB_table :: + * A pointer to the GSUB table. + * + * JSTF_table :: + * A pointer to the JSTF table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with OpenType fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the five tables with + * @FT_OpenType_Free. A `NULL` value indicates that the table either + * doesn't exist in the font, or the application hasn't asked for + * validation. + */ + FT_EXPORT( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ); + + + /************************************************************************** + * + * @function: + * FT_OpenType_Free + * + * @description: + * Free the buffer allocated by OpenType validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_OpenType_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_OpenType_Validate only. + */ + FT_EXPORT( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTOTVAL_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftoutln.h b/vendor/freetype/include/freetype/ftoutln.h new file mode 100644 index 0000000..f9329ca --- /dev/null +++ b/vendor/freetype/include/freetype/ftoutln.h @@ -0,0 +1,588 @@ +/**************************************************************************** + * + * ftoutln.h + * + * Support for the FT_Outline type used to store glyph shapes of + * most scalable font formats (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTOUTLN_H_ +#define FTOUTLN_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * outline_processing + * + * @title: + * Outline Processing + * + * @abstract: + * Functions to create, transform, and render vectorial glyph images. + * + * @description: + * This section contains routines used to create and destroy scalable + * glyph images known as 'outlines'. These can also be measured, + * transformed, and converted into bitmaps and pixmaps. + * + * @order: + * FT_Outline + * FT_Outline_New + * FT_Outline_Done + * FT_Outline_Copy + * FT_Outline_Translate + * FT_Outline_Transform + * FT_Outline_Embolden + * FT_Outline_EmboldenXY + * FT_Outline_Reverse + * FT_Outline_Check + * + * FT_Outline_Get_CBox + * FT_Outline_Get_BBox + * + * FT_Outline_Get_Bitmap + * FT_Outline_Render + * FT_Outline_Decompose + * FT_Outline_Funcs + * FT_Outline_MoveToFunc + * FT_Outline_LineToFunc + * FT_Outline_ConicToFunc + * FT_Outline_CubicToFunc + * + * FT_Orientation + * FT_Outline_Get_Orientation + * + * FT_OUTLINE_XXX + * + */ + + + /************************************************************************** + * + * @function: + * FT_Outline_Decompose + * + * @description: + * Walk over an outline's structure to decompose it into individual + * segments and Bezier arcs. This function also emits 'move to' + * operations to indicate the start of new contours in the outline. + * + * @input: + * outline :: + * A pointer to the source target. + * + * func_interface :: + * A table of 'emitters', i.e., function pointers called during + * decomposition to indicate path operations. + * + * @inout: + * user :: + * A typeless pointer that is passed to each emitter during the + * decomposition. It can be used to store the state during the + * decomposition. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Degenerate contours, segments, and Bezier arcs may be reported. In + * most cases, it is best to filter these out before using the outline + * for stroking or other path modification purposes (which may cause + * degenerate segments to become non-degenrate and visible, like when + * stroke caps are used or the path is otherwise outset). Some glyph + * outlines may contain deliberate degenerate single points for mark + * attachement. + * + * Similarly, the function returns success for an empty outline also + * (doing nothing, that is, not calling any emitter); if necessary, you + * should filter this out, too. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ); + + + /************************************************************************** + * + * @function: + * FT_Outline_New + * + * @description: + * Create a new outline of a given size. + * + * @input: + * library :: + * A handle to the library object from where the outline is allocated. + * Note however that the new outline will **not** necessarily be + * **freed**, when destroying the library, by @FT_Done_FreeType. + * + * numPoints :: + * The maximum number of points within the outline. Must be smaller + * than or equal to 0xFFFF (65535). + * + * numContours :: + * The maximum number of contours within the outline. This value must + * be in the range 0 to `numPoints`. + * + * @output: + * anoutline :: + * A handle to the new outline. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The reason why this function takes a `library` parameter is simply to + * use the library's memory allocator. + */ + FT_EXPORT( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Done + * + * @description: + * Destroy an outline created with @FT_Outline_New. + * + * @input: + * library :: + * A handle of the library object used to allocate the outline. + * + * outline :: + * A pointer to the outline object to be discarded. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the outline's 'owner' field is not set, only the outline descriptor + * will be released. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Check + * + * @description: + * Check the contents of an outline descriptor. + * + * @input: + * outline :: + * A handle to a source outline. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * An empty outline, or an outline with a single point only is also + * valid. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Check( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_CBox + * + * @description: + * Return an outline's 'control box'. The control box encloses all the + * outline's points, including Bezier control points. Though it + * coincides with the exact bounding box for most glyphs, it can be + * slightly larger in some situations (like when rotating an outline that + * contains Bezier outside arcs). + * + * Computing the control box is very fast, while getting the bounding box + * can take much more time as it needs to walk over all segments and arcs + * in the outline. To get the latter, you can use the 'ftbbox' + * component, which is dedicated to this single task. + * + * @input: + * outline :: + * A pointer to the source outline descriptor. + * + * @output: + * acbox :: + * The outline's control box. + * + * @note: + * See @FT_Glyph_Get_CBox for a discussion of tricky fonts. + */ + FT_EXPORT( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Translate + * + * @description: + * Apply a simple translation to the points of an outline. + * + * @inout: + * outline :: + * A pointer to the target outline descriptor. + * + * @input: + * xOffset :: + * The horizontal offset. + * + * yOffset :: + * The vertical offset. + */ + FT_EXPORT( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Copy + * + * @description: + * Copy an outline into another one. Both objects must have the same + * sizes (number of points & number of contours) when this function is + * called. + * + * @input: + * source :: + * A handle to the source outline. + * + * @output: + * target :: + * A handle to the target outline. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Transform + * + * @description: + * Apply a simple 2x2 matrix to all of an outline's points. Useful for + * applying rotations, slanting, flipping, etc. + * + * @inout: + * outline :: + * A pointer to the target outline descriptor. + * + * @input: + * matrix :: + * A pointer to the transformation matrix. + * + * @note: + * You can use @FT_Outline_Translate if you need to translate the + * outline's points. + */ + FT_EXPORT( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Embolden + * + * @description: + * Embolden an outline. The new outline will be at most 4~times + * `strength` pixels wider and higher. You may think of the left and + * bottom borders as unchanged. + * + * Negative `strength` values to reduce the outline thickness are + * possible also. + * + * @inout: + * outline :: + * A handle to the target outline. + * + * @input: + * strength :: + * How strong the glyph is emboldened. Expressed in 26.6 pixel format. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The used algorithm to increase or decrease the thickness of the glyph + * doesn't change the number of points; this means that certain + * situations like acute angles or intersections are sometimes handled + * incorrectly. + * + * If you need 'better' metrics values you should call + * @FT_Outline_Get_CBox or @FT_Outline_Get_BBox. + * + * To get meaningful results, font scaling values must be set with + * functions like @FT_Set_Char_Size before calling FT_Render_Glyph. + * + * @example: + * ``` + * FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); + * + * if ( face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) + * FT_Outline_Embolden( &face->glyph->outline, strength ); + * ``` + * + */ + FT_EXPORT( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ); + + + /************************************************************************** + * + * @function: + * FT_Outline_EmboldenXY + * + * @description: + * Embolden an outline. The new outline will be `xstrength` pixels wider + * and `ystrength` pixels higher. Otherwise, it is similar to + * @FT_Outline_Embolden, which uses the same strength in both directions. + * + * @since: + * 2.4.10 + */ + FT_EXPORT( FT_Error ) + FT_Outline_EmboldenXY( FT_Outline* outline, + FT_Pos xstrength, + FT_Pos ystrength ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Reverse + * + * @description: + * Reverse the drawing direction of an outline. This is used to ensure + * consistent fill conventions for mirrored glyphs. + * + * @inout: + * outline :: + * A pointer to the target outline descriptor. + * + * @note: + * This function toggles the bit flag @FT_OUTLINE_REVERSE_FILL in the + * outline's `flags` field. + * + * It shouldn't be used by a normal client application, unless it knows + * what it is doing. + */ + FT_EXPORT( void ) + FT_Outline_Reverse( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_Bitmap + * + * @description: + * Render an outline within a bitmap. The outline's image is simply + * OR-ed to the target bitmap. + * + * @input: + * library :: + * A handle to a FreeType library object. + * + * outline :: + * A pointer to the source outline descriptor. + * + * @inout: + * abitmap :: + * A pointer to the target bitmap descriptor. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function does **not create** the bitmap, it only renders an + * outline image within the one you pass to it! Consequently, the + * various fields in `abitmap` should be set accordingly. + * + * It will use the raster corresponding to the default glyph format. + * + * The value of the `num_grays` field in `abitmap` is ignored. If you + * select the gray-level rasterizer, and you want less than 256 gray + * levels, you have to use @FT_Outline_Render directly. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Render + * + * @description: + * Render an outline within a bitmap using the current scan-convert. + * + * @input: + * library :: + * A handle to a FreeType library object. + * + * outline :: + * A pointer to the source outline descriptor. + * + * @inout: + * params :: + * A pointer to an @FT_Raster_Params structure used to describe the + * rendering operation. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This advanced function uses @FT_Raster_Params as an argument. + * The field `params.source` will be set to `outline` before the scan + * converter is called, which means that the value you give to it is + * actually ignored. Either `params.target` must point to preallocated + * bitmap, or @FT_RASTER_FLAG_DIRECT must be set in `params.flags` + * allowing FreeType rasterizer to be used for direct composition, + * translucency, etc. See @FT_Raster_Params for more details. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ); + + + /************************************************************************** + * + * @enum: + * FT_Orientation + * + * @description: + * A list of values used to describe an outline's contour orientation. + * + * The TrueType and PostScript specifications use different conventions + * to determine whether outline contours should be filled or unfilled. + * + * @values: + * FT_ORIENTATION_TRUETYPE :: + * According to the TrueType specification, clockwise contours must be + * filled, and counter-clockwise ones must be unfilled. + * + * FT_ORIENTATION_POSTSCRIPT :: + * According to the PostScript specification, counter-clockwise + * contours must be filled, and clockwise ones must be unfilled. + * + * FT_ORIENTATION_FILL_RIGHT :: + * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to + * remember that in TrueType, everything that is to the right of the + * drawing direction of a contour must be filled. + * + * FT_ORIENTATION_FILL_LEFT :: + * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to + * remember that in PostScript, everything that is to the left of the + * drawing direction of a contour must be filled. + * + * FT_ORIENTATION_NONE :: + * The orientation cannot be determined. That is, different parts of + * the glyph have different orientation. + * + */ + typedef enum FT_Orientation_ + { + FT_ORIENTATION_TRUETYPE = 0, + FT_ORIENTATION_POSTSCRIPT = 1, + FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, + FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, + FT_ORIENTATION_NONE + + } FT_Orientation; + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_Orientation + * + * @description: + * This function analyzes a glyph outline and tries to compute its fill + * orientation (see @FT_Orientation). This is done by integrating the + * total area covered by the outline. The positive integral corresponds + * to the clockwise orientation and @FT_ORIENTATION_POSTSCRIPT is + * returned. The negative integral corresponds to the counter-clockwise + * orientation and @FT_ORIENTATION_TRUETYPE is returned. + * + * Note that this will return @FT_ORIENTATION_TRUETYPE for empty + * outlines. + * + * @input: + * outline :: + * A handle to the source outline. + * + * @return: + * The orientation. + * + */ + FT_EXPORT( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTOUTLN_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/vendor/freetype/include/freetype/ftparams.h b/vendor/freetype/include/freetype/ftparams.h new file mode 100644 index 0000000..6a9f243 --- /dev/null +++ b/vendor/freetype/include/freetype/ftparams.h @@ -0,0 +1,218 @@ +/**************************************************************************** + * + * ftparams.h + * + * FreeType API for possible FT_Parameter tags (specification only). + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTPARAMS_H_ +#define FTPARAMS_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * parameter_tags + * + * @title: + * Parameter Tags + * + * @abstract: + * Macros for driver property and font loading parameter tags. + * + * @description: + * This section contains macros for the @FT_Parameter structure that are + * used with various functions to activate some special functionality or + * different behaviour of various components of FreeType. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore typographic + * family names in the 'name' table (introduced in OpenType version 1.4). + * Use this for backward compatibility with legacy systems that have a + * four-faces-per-family restriction. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY \ + FT_MAKE_TAG( 'i', 'g', 'p', 'f' ) + + + /* this constant is deprecated */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY \ + FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore typographic + * subfamily names in the 'name' table (introduced in OpenType version + * 1.4). Use this for backward compatibility with legacy systems that + * have a four-faces-per-family restriction. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY \ + FT_MAKE_TAG( 'i', 'g', 'p', 's' ) + + + /* this constant is deprecated */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY \ + FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_INCREMENTAL + * + * @description: + * An @FT_Parameter tag to be used with @FT_Open_Face to indicate + * incremental glyph loading. + * + */ +#define FT_PARAM_TAG_INCREMENTAL \ + FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_SBIX + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore an 'sbix' table + * while loading a font. Use this if @FT_FACE_FLAG_SBIX is set and you + * want to access the outline glyphs in the font. + * + */ +#define FT_PARAM_TAG_IGNORE_SBIX \ + FT_MAKE_TAG( 'i', 's', 'b', 'x' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_LCD_FILTER_WEIGHTS + * + * @description: + * An @FT_Parameter tag to be used with @FT_Face_Properties. The + * corresponding argument specifies the five LCD filter weights for a + * given face (if using @FT_LOAD_TARGET_LCD, for example), overriding the + * global default values or the values set up with + * @FT_Library_SetLcdFilterWeights. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_LCD_FILTER_WEIGHTS \ + FT_MAKE_TAG( 'l', 'c', 'd', 'f' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_RANDOM_SEED + * + * @description: + * An @FT_Parameter tag to be used with @FT_Face_Properties. The + * corresponding 32bit signed integer argument overrides the font + * driver's random seed value with a face-specific one; see @random-seed. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_RANDOM_SEED \ + FT_MAKE_TAG( 's', 'e', 'e', 'd' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_STEM_DARKENING + * + * @description: + * An @FT_Parameter tag to be used with @FT_Face_Properties. The + * corresponding Boolean argument specifies whether to apply stem + * darkening, overriding the global default values or the values set up + * with @FT_Property_Set (see @no-stem-darkening). + * + * This is a passive setting that only takes effect if the font driver or + * autohinter honors it, which the CFF, Type~1, and CID drivers always + * do, but the autohinter only in 'light' hinting mode (as of version + * 2.9). + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_STEM_DARKENING \ + FT_MAKE_TAG( 'd', 'a', 'r', 'k' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_UNPATENTED_HINTING + * + * @description: + * Deprecated, no effect. + * + * Previously: A constant used as the tag of an @FT_Parameter structure + * to indicate that unpatented methods only should be used by the + * TrueType bytecode interpreter for a typeface opened by @FT_Open_Face. + * + */ +#define FT_PARAM_TAG_UNPATENTED_HINTING \ + FT_MAKE_TAG( 'u', 'n', 'p', 'a' ) + + + /* */ + + +FT_END_HEADER + + +#endif /* FTPARAMS_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftpfr.h b/vendor/freetype/include/freetype/ftpfr.h new file mode 100644 index 0000000..7111d40 --- /dev/null +++ b/vendor/freetype/include/freetype/ftpfr.h @@ -0,0 +1,179 @@ +/**************************************************************************** + * + * ftpfr.h + * + * FreeType API for accessing PFR-specific data (specification only). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTPFR_H_ +#define FTPFR_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * pfr_fonts + * + * @title: + * PFR Fonts + * + * @abstract: + * PFR/TrueDoc-specific API. + * + * @description: + * This section contains the declaration of PFR-specific functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Get_PFR_Metrics + * + * @description: + * Return the outline and metrics resolutions of a given PFR face. + * + * @input: + * face :: + * Handle to the input face. It can be a non-PFR face. + * + * @output: + * aoutline_resolution :: + * Outline resolution. This is equivalent to `face->units_per_EM` for + * non-PFR fonts. Optional (parameter can be `NULL`). + * + * ametrics_resolution :: + * Metrics resolution. This is equivalent to `outline_resolution` for + * non-PFR fonts. Optional (parameter can be `NULL`). + * + * ametrics_x_scale :: + * A 16.16 fixed-point number used to scale distance expressed in + * metrics units to device subpixels. This is equivalent to + * `face->size->x_scale`, but for metrics only. Optional (parameter + * can be `NULL`). + * + * ametrics_y_scale :: + * Same as `ametrics_x_scale` but for the vertical direction. + * optional (parameter can be `NULL`). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the input face is not a PFR, this function will return an error. + * However, in all cases, it will return valid values. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ); + + + /************************************************************************** + * + * @function: + * FT_Get_PFR_Kerning + * + * @description: + * Return the kerning pair corresponding to two glyphs in a PFR face. + * The distance is expressed in metrics units, unlike the result of + * @FT_Get_Kerning. + * + * @input: + * face :: + * A handle to the input face. + * + * left :: + * Index of the left glyph. + * + * right :: + * Index of the right glyph. + * + * @output: + * avector :: + * A kerning vector. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function always return distances in original PFR metrics units. + * This is unlike @FT_Get_Kerning with the @FT_KERNING_UNSCALED mode, + * which always returns distances converted to outline units. + * + * You can use the value of the `x_scale` and `y_scale` parameters + * returned by @FT_Get_PFR_Metrics to scale these to device subpixels. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + + /************************************************************************** + * + * @function: + * FT_Get_PFR_Advance + * + * @description: + * Return a given glyph advance, expressed in original metrics units, + * from a PFR font. + * + * @input: + * face :: + * A handle to the input face. + * + * gindex :: + * The glyph index. + * + * @output: + * aadvance :: + * The glyph advance in metrics units. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You can use the `x_scale` or `y_scale` results of @FT_Get_PFR_Metrics + * to convert the advance to device subpixels (i.e., 1/64 of pixels). + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + /* */ + + +FT_END_HEADER + +#endif /* FTPFR_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftrender.h b/vendor/freetype/include/freetype/ftrender.h new file mode 100644 index 0000000..0b6fad3 --- /dev/null +++ b/vendor/freetype/include/freetype/ftrender.h @@ -0,0 +1,244 @@ +/**************************************************************************** + * + * ftrender.h + * + * FreeType renderer modules public interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTRENDER_H_ +#define FTRENDER_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * module_management + * + */ + + + /* create a new glyph object */ + typedef FT_Error + (*FT_Glyph_InitFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + + /* destroys a given glyph object */ + typedef void + (*FT_Glyph_DoneFunc)( FT_Glyph glyph ); + + typedef void + (*FT_Glyph_TransformFunc)( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + typedef void + (*FT_Glyph_GetBBoxFunc)( FT_Glyph glyph, + FT_BBox* abbox ); + + typedef FT_Error + (*FT_Glyph_CopyFunc)( FT_Glyph source, + FT_Glyph target ); + + typedef FT_Error + (*FT_Glyph_PrepareFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + +/* deprecated */ +#define FT_Glyph_Init_Func FT_Glyph_InitFunc +#define FT_Glyph_Done_Func FT_Glyph_DoneFunc +#define FT_Glyph_Transform_Func FT_Glyph_TransformFunc +#define FT_Glyph_BBox_Func FT_Glyph_GetBBoxFunc +#define FT_Glyph_Copy_Func FT_Glyph_CopyFunc +#define FT_Glyph_Prepare_Func FT_Glyph_PrepareFunc + + + struct FT_Glyph_Class_ + { + FT_Long glyph_size; + FT_Glyph_Format glyph_format; + + FT_Glyph_InitFunc glyph_init; + FT_Glyph_DoneFunc glyph_done; + FT_Glyph_CopyFunc glyph_copy; + FT_Glyph_TransformFunc glyph_transform; + FT_Glyph_GetBBoxFunc glyph_bbox; + FT_Glyph_PrepareFunc glyph_prepare; + }; + + + typedef FT_Error + (*FT_Renderer_RenderFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ); + + typedef FT_Error + (*FT_Renderer_TransformFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + + typedef void + (*FT_Renderer_GetCBoxFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_BBox* cbox ); + + + typedef FT_Error + (*FT_Renderer_SetModeFunc)( FT_Renderer renderer, + FT_ULong mode_tag, + FT_Pointer mode_ptr ); + +/* deprecated identifiers */ +#define FTRenderer_render FT_Renderer_RenderFunc +#define FTRenderer_transform FT_Renderer_TransformFunc +#define FTRenderer_getCBox FT_Renderer_GetCBoxFunc +#define FTRenderer_setMode FT_Renderer_SetModeFunc + + + /************************************************************************** + * + * @struct: + * FT_Renderer_Class + * + * @description: + * The renderer module class descriptor. + * + * @fields: + * root :: + * The root @FT_Module_Class fields. + * + * glyph_format :: + * The glyph image format this renderer handles. + * + * render_glyph :: + * A method used to render the image that is in a given glyph slot into + * a bitmap. + * + * transform_glyph :: + * A method used to transform the image that is in a given glyph slot. + * + * get_glyph_cbox :: + * A method used to access the glyph's cbox. + * + * set_mode :: + * A method used to pass additional parameters. + * + * raster_class :: + * For @FT_GLYPH_FORMAT_OUTLINE renderers only. This is a pointer to + * its raster's class. + */ + typedef struct FT_Renderer_Class_ + { + FT_Module_Class root; + + FT_Glyph_Format glyph_format; + + FT_Renderer_RenderFunc render_glyph; + FT_Renderer_TransformFunc transform_glyph; + FT_Renderer_GetCBoxFunc get_glyph_cbox; + FT_Renderer_SetModeFunc set_mode; + + const FT_Raster_Funcs* raster_class; + + } FT_Renderer_Class; + + + /************************************************************************** + * + * @function: + * FT_Get_Renderer + * + * @description: + * Retrieve the current renderer for a given glyph format. + * + * @input: + * library :: + * A handle to the library object. + * + * format :: + * The glyph format. + * + * @return: + * A renderer handle. 0~if none found. + * + * @note: + * An error will be returned if a module already exists by that name, or + * if the module requires a version of FreeType that is too great. + * + * To add a new renderer, simply use @FT_Add_Module. To retrieve a + * renderer by its name, use @FT_Get_Module. + */ + FT_EXPORT( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ); + + + /************************************************************************** + * + * @function: + * FT_Set_Renderer + * + * @description: + * Set the current renderer to use, and set additional mode. + * + * @inout: + * library :: + * A handle to the library object. + * + * @input: + * renderer :: + * A handle to the renderer object. + * + * num_params :: + * The number of additional parameters. + * + * parameters :: + * Additional parameters. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * In case of success, the renderer will be used to convert glyph images + * in the renderer's known format into bitmaps. + * + * This doesn't change the current renderer for other formats. + * + * Currently, no FreeType renderer module uses `parameters`; you should + * thus always pass `NULL` as the value. + */ + FT_EXPORT( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ); + + /* */ + + +FT_END_HEADER + +#endif /* FTRENDER_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftsizes.h b/vendor/freetype/include/freetype/ftsizes.h new file mode 100644 index 0000000..7bfb1ae --- /dev/null +++ b/vendor/freetype/include/freetype/ftsizes.h @@ -0,0 +1,159 @@ +/**************************************************************************** + * + * ftsizes.h + * + * FreeType size objects management (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * Typical application would normally not need to use these functions. + * However, they have been placed in a public API for the rare cases where + * they are needed. + * + */ + + +#ifndef FTSIZES_H_ +#define FTSIZES_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * sizes_management + * + * @title: + * Size Management + * + * @abstract: + * Managing multiple sizes per face. + * + * @description: + * When creating a new face object (e.g., with @FT_New_Face), an @FT_Size + * object is automatically created and used to store all pixel-size + * dependent information, available in the `face->size` field. + * + * It is however possible to create more sizes for a given face, mostly + * in order to manage several character pixel sizes of the same font + * family and style. See @FT_New_Size and @FT_Done_Size. + * + * Note that @FT_Set_Pixel_Sizes and @FT_Set_Char_Size only modify the + * contents of the current 'active' size; you thus need to use + * @FT_Activate_Size to change it. + * + * 99% of applications won't need the functions provided here, especially + * if they use the caching sub-system, so be cautious when using these. + * + */ + + + /************************************************************************** + * + * @function: + * FT_New_Size + * + * @description: + * Create a new size object from a given face object. + * + * @input: + * face :: + * A handle to a parent face object. + * + * @output: + * asize :: + * A handle to a new size object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You need to call @FT_Activate_Size in order to select the new size for + * upcoming calls to @FT_Set_Pixel_Sizes, @FT_Set_Char_Size, + * @FT_Load_Glyph, @FT_Load_Char, etc. + */ + FT_EXPORT( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size* size ); + + + /************************************************************************** + * + * @function: + * FT_Done_Size + * + * @description: + * Discard a given size object. Note that @FT_Done_Face automatically + * discards all size objects allocated with @FT_New_Size. + * + * @input: + * size :: + * A handle to a target size object. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Done_Size( FT_Size size ); + + + /************************************************************************** + * + * @function: + * FT_Activate_Size + * + * @description: + * Even though it is possible to create several size objects for a given + * face (see @FT_New_Size for details), functions like @FT_Load_Glyph or + * @FT_Load_Char only use the one that has been activated last to + * determine the 'current character pixel size'. + * + * This function can be used to 'activate' a previously created size + * object. + * + * @input: + * size :: + * A handle to a target size object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `face` is the size's parent face object, this function changes the + * value of `face->size` to the input size handle. + */ + FT_EXPORT( FT_Error ) + FT_Activate_Size( FT_Size size ); + + /* */ + + +FT_END_HEADER + +#endif /* FTSIZES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftsnames.h b/vendor/freetype/include/freetype/ftsnames.h new file mode 100644 index 0000000..9d5d22b --- /dev/null +++ b/vendor/freetype/include/freetype/ftsnames.h @@ -0,0 +1,272 @@ +/**************************************************************************** + * + * ftsnames.h + * + * Simple interface to access SFNT 'name' tables (which are used + * to hold font names, copyright info, notices, etc.) (specification). + * + * This is _not_ used to retrieve glyph names! + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSNAMES_H_ +#define FTSNAMES_H_ + + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * sfnt_names + * + * @title: + * SFNT Names + * + * @abstract: + * Access the names embedded in TrueType and OpenType files. + * + * @description: + * The TrueType and OpenType specifications allow the inclusion of a + * special names table ('name') in font files. This table contains + * textual (and internationalized) information regarding the font, like + * family name, copyright, version, etc. + * + * The definitions below are used to access them if available. + * + * Note that this has nothing to do with glyph names! + * + */ + + + /************************************************************************** + * + * @struct: + * FT_SfntName + * + * @description: + * A structure used to model an SFNT 'name' table entry. + * + * @fields: + * platform_id :: + * The platform ID for `string`. See @TT_PLATFORM_XXX for possible + * values. + * + * encoding_id :: + * The encoding ID for `string`. See @TT_APPLE_ID_XXX, @TT_MAC_ID_XXX, + * @TT_ISO_ID_XXX, @TT_MS_ID_XXX, and @TT_ADOBE_ID_XXX for possible + * values. + * + * language_id :: + * The language ID for `string`. See @TT_MAC_LANGID_XXX and + * @TT_MS_LANGID_XXX for possible values. + * + * Registered OpenType values for `language_id` are always smaller than + * 0x8000; values equal or larger than 0x8000 usually indicate a + * language tag string (introduced in OpenType version 1.6). Use + * function @FT_Get_Sfnt_LangTag with `language_id` as its argument to + * retrieve the associated language tag. + * + * name_id :: + * An identifier for `string`. See @TT_NAME_ID_XXX for possible + * values. + * + * string :: + * The 'name' string. Note that its format differs depending on the + * (platform,encoding) pair, being either a string of bytes (without a + * terminating `NULL` byte) or containing UTF-16BE entities. + * + * string_len :: + * The length of `string` in bytes. + * + * @note: + * Please refer to the TrueType or OpenType specification for more + * details. + */ + typedef struct FT_SfntName_ + { + FT_UShort platform_id; + FT_UShort encoding_id; + FT_UShort language_id; + FT_UShort name_id; + + FT_Byte* string; /* this string is *not* null-terminated! */ + FT_UInt string_len; /* in bytes */ + + } FT_SfntName; + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_Name_Count + * + * @description: + * Retrieve the number of name strings in the SFNT 'name' table. + * + * @input: + * face :: + * A handle to the source face. + * + * @return: + * The number of strings in the 'name' table. + * + * @note: + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_SFNT_NAMES` is not defined in `ftoption.h`. + */ + FT_EXPORT( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_Name + * + * @description: + * Retrieve a string of the SFNT 'name' table for a given index. + * + * @input: + * face :: + * A handle to the source face. + * + * idx :: + * The index of the 'name' string. + * + * @output: + * aname :: + * The indexed @FT_SfntName structure. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `string` array returned in the `aname` structure is not + * null-terminated. Note that you don't have to deallocate `string` by + * yourself; FreeType takes care of it if you call @FT_Done_Face. + * + * Use @FT_Get_Sfnt_Name_Count to get the total number of available + * 'name' table entries, then do a loop until you get the right platform, + * encoding, and name ID. + * + * 'name' table format~1 entries can use language tags also, see + * @FT_Get_Sfnt_LangTag. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_SFNT_NAMES` is not defined in `ftoption.h`. + */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ); + + + /************************************************************************** + * + * @struct: + * FT_SfntLangTag + * + * @description: + * A structure to model a language tag entry from an SFNT 'name' table. + * + * @fields: + * string :: + * The language tag string, encoded in UTF-16BE (without trailing + * `NULL` bytes). + * + * string_len :: + * The length of `string` in **bytes**. + * + * @note: + * Please refer to the TrueType or OpenType specification for more + * details. + * + * @since: + * 2.8 + */ + typedef struct FT_SfntLangTag_ + { + FT_Byte* string; /* this string is *not* null-terminated! */ + FT_UInt string_len; /* in bytes */ + + } FT_SfntLangTag; + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_LangTag + * + * @description: + * Retrieve the language tag associated with a language ID of an SFNT + * 'name' table entry. + * + * @input: + * face :: + * A handle to the source face. + * + * langID :: + * The language ID, as returned by @FT_Get_Sfnt_Name. This is always a + * value larger than 0x8000. + * + * @output: + * alangTag :: + * The language tag associated with the 'name' table entry's language + * ID. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `string` array returned in the `alangTag` structure is not + * null-terminated. Note that you don't have to deallocate `string` by + * yourself; FreeType takes care of it if you call @FT_Done_Face. + * + * Only 'name' table format~1 supports language tags. For format~0 + * tables, this function always returns FT_Err_Invalid_Table. For + * invalid format~1 language ID values, FT_Err_Invalid_Argument is + * returned. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_SFNT_NAMES` is not defined in `ftoption.h`. + * + * @since: + * 2.8 + */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_LangTag( FT_Face face, + FT_UInt langID, + FT_SfntLangTag *alangTag ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTSNAMES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftstroke.h b/vendor/freetype/include/freetype/ftstroke.h new file mode 100644 index 0000000..b3d9080 --- /dev/null +++ b/vendor/freetype/include/freetype/ftstroke.h @@ -0,0 +1,773 @@ +/**************************************************************************** + * + * ftstroke.h + * + * FreeType path stroker (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSTROKE_H_ +#define FTSTROKE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * glyph_stroker + * + * @title: + * Glyph Stroker + * + * @abstract: + * Generating bordered and stroked glyphs. + * + * @description: + * This component generates stroked outlines of a given vectorial glyph. + * It also allows you to retrieve the 'outside' and/or the 'inside' + * borders of the stroke. + * + * This can be useful to generate 'bordered' glyph, i.e., glyphs + * displayed with a colored (and anti-aliased) border around their + * shape. + * + * @order: + * FT_Stroker + * + * FT_Stroker_LineJoin + * FT_Stroker_LineCap + * FT_StrokerBorder + * + * FT_Outline_GetInsideBorder + * FT_Outline_GetOutsideBorder + * + * FT_Glyph_Stroke + * FT_Glyph_StrokeBorder + * + * FT_Stroker_New + * FT_Stroker_Set + * FT_Stroker_Rewind + * FT_Stroker_ParseOutline + * FT_Stroker_Done + * + * FT_Stroker_BeginSubPath + * FT_Stroker_EndSubPath + * + * FT_Stroker_LineTo + * FT_Stroker_ConicTo + * FT_Stroker_CubicTo + * + * FT_Stroker_GetBorderCounts + * FT_Stroker_ExportBorder + * FT_Stroker_GetCounts + * FT_Stroker_Export + * + */ + + + /************************************************************************** + * + * @type: + * FT_Stroker + * + * @description: + * Opaque handle to a path stroker object. + */ + typedef struct FT_StrokerRec_* FT_Stroker; + + + /************************************************************************** + * + * @enum: + * FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered in a + * stroker. + * + * @values: + * FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used to join + * two lines smoothly. + * + * FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins. The outer corner of the joined + * lines is filled by enclosing the triangular region of the corner + * with a straight line between the outer corners of each stroke. + * + * FT_STROKER_LINEJOIN_MITER_FIXED :: + * Used to render mitered line joins, with fixed bevels if the miter + * limit is exceeded. The outer edges of the strokes for the two + * segments are extended until they meet at an angle. A bevel join + * (see above) is used if the segments meet at too sharp an angle and + * the outer edges meet beyond a distance corresponding to the meter + * limit. This prevents long spikes being created. + * `FT_STROKER_LINEJOIN_MITER_FIXED` generates a miter line join as + * used in PostScript and PDF. + * + * FT_STROKER_LINEJOIN_MITER_VARIABLE :: + * FT_STROKER_LINEJOIN_MITER :: + * Used to render mitered line joins, with variable bevels if the miter + * limit is exceeded. The intersection of the strokes is clipped + * perpendicularly to the bisector, at a distance corresponding to + * the miter limit. This prevents long spikes being created. + * `FT_STROKER_LINEJOIN_MITER_VARIABLE` generates a mitered line join + * as used in XPS. `FT_STROKER_LINEJOIN_MITER` is an alias for + * `FT_STROKER_LINEJOIN_MITER_VARIABLE`, retained for backward + * compatibility. + */ + typedef enum FT_Stroker_LineJoin_ + { + FT_STROKER_LINEJOIN_ROUND = 0, + FT_STROKER_LINEJOIN_BEVEL = 1, + FT_STROKER_LINEJOIN_MITER_VARIABLE = 2, + FT_STROKER_LINEJOIN_MITER = FT_STROKER_LINEJOIN_MITER_VARIABLE, + FT_STROKER_LINEJOIN_MITER_FIXED = 3 + + } FT_Stroker_LineJoin; + + + /************************************************************************** + * + * @enum: + * FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are rendered in + * a stroke. + * + * @values: + * FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last point + * itself. + * + * FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the last point. + * + * FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the last point. + */ + typedef enum FT_Stroker_LineCap_ + { + FT_STROKER_LINECAP_BUTT = 0, + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINECAP_SQUARE + + } FT_Stroker_LineCap; + + + /************************************************************************** + * + * @enum: + * FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border in + * @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder. + * + * @values: + * FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the 'inside' and 'outside' + * borders. However, there is no direct mapping between these and the + * 'left' and 'right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @FT_Outline_GetInsideBorder and + * @FT_Outline_GetOutsideBorder to get these. + */ + typedef enum FT_StrokerBorder_ + { + FT_STROKER_BORDER_LEFT = 0, + FT_STROKER_BORDER_RIGHT + + } FT_StrokerBorder; + + + /************************************************************************** + * + * @function: + * FT_Outline_GetInsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the 'inside' + * borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_RIGHT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_GetOutsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the 'outside' + * borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The maximum reciprocal sine of half-angle at the miter join, + * expressed as 16.16 fixed-point value. + * + * @note: + * The `radius` is expressed in the same units as the outline + * coordinates. + * + * The `miter_limit` multiplied by the `radius` gives the maximum size + * of a miter spike, at which it is clipped for + * @FT_STROKER_LINEJOIN_MITER_VARIABLE or replaced with a bevel join for + * @FT_STROKER_LINEJOIN_MITER_FIXED. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Rewind + * + * @description: + * Reset a stroker object without changing its attributes. You should + * call this function before beginning a new series of calls to + * @FT_Stroker_BeginSubPath or @FT_Stroker_EndSubPath. + * + * @input: + * stroker :: + * The target stroker handle. + */ + FT_EXPORT( void ) + FT_Stroker_Rewind( FT_Stroker stroker ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with the stroker. + * The resulting outline(s) can be retrieved later by functions like + * @FT_Stroker_GetCounts and @FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * opened :: + * A boolean. If~1, the outline is treated as an open path instead of + * a closed one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `opened` is~0 (the default), the outline is treated as a closed + * path, and the stroker generates two distinct 'border' outlines. + * + * If `opened` is~1, the outline is processed as an open path, and the + * stroker generates a single 'stroke' outline. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_BeginSubPath + * + * @description: + * Start a new sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the start vector. + * + * open :: + * A boolean. If~1, the sub-path is treated as an open one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function is useful when you need to stroke a path that is not + * stored as an @FT_Outline object. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_EndSubPath + * + * @description: + * Close the current sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function after @FT_Stroker_BeginSubPath. If the + * subpath was not 'opened', this function 'draws' a single line segment + * to the start position when needed. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_LineTo + * + * @description: + * 'Draw' a single line segment in the stroker's current sub-path, from + * the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_ConicTo + * + * @description: + * 'Draw' a single quadratic Bezier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control :: + * A pointer to a Bezier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_CubicTo + * + * @description: + * 'Draw' a single cubic Bezier in the stroker's current sub-path, from + * the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control1 :: + * A pointer to the first Bezier control point. + * + * control2 :: + * A pointer to second Bezier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_GetBorderCounts + * + * @description: + * Call this function once you have finished parsing your paths with the + * stroker. It returns the number of points and contours necessary to + * export one of the 'border' or 'stroke' outlines generated by the + * stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * When an outline, or a sub-path, is 'closed', the stroker generates two + * independent 'border' outlines, named 'left' and 'right'. + * + * When the outline, or a sub-path, is 'opened', the stroker merges the + * 'border' outlines with caps. The 'left' border receives all points, + * while the 'right' border becomes empty. + * + * Use the function @FT_Stroker_GetCounts instead if you want to retrieve + * the counts associated to both borders. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_ExportBorder + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to export the + * corresponding border to your own @FT_Outline structure. + * + * Note that this function appends the border points and contours to your + * outline, but does not try to resize its arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * outline :: + * The target outline handle. + * + * @note: + * Always call this function after @FT_Stroker_GetBorderCounts to get + * sure that there is enough room in your @FT_Outline object to receive + * all new data. + * + * When an outline, or a sub-path, is 'closed', the stroker generates two + * independent 'border' outlines, named 'left' and 'right'. + * + * When the outline, or a sub-path, is 'opened', the stroker merges the + * 'border' outlines with caps. The 'left' border receives all points, + * while the 'right' border becomes empty. + * + * Use the function @FT_Stroker_Export instead if you want to retrieve + * all borders at once. + */ + FT_EXPORT( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths with the + * stroker. It returns the number of points and contours necessary to + * export all points/borders from the stroked outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Export + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to export all + * borders to your own @FT_Outline structure. + * + * Note that this function appends the border points and contours to your + * outline, but does not try to resize its arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ + FT_EXPORT( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be `NULL`. + */ + FT_EXPORT( void ) + FT_Stroker_Done( FT_Stroker stroker ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_Stroke + * + * @description: + * Stroke a given outline glyph object with a given stroker. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + * + * Adding stroke may yield a significantly wider and taller glyph + * depending on how large of a radius was used to stroke the glyph. You + * may need to manually adjust horizontal and vertical advance amounts to + * account for this added size. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_StrokeBorder + * + * @description: + * Stroke a given outline glyph object with a given stroker, but only + * return either its inside or outside border. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * inside :: + * A Boolean. If~1, return the inside border, otherwise the outside + * border. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + * + * Adding stroke may yield a significantly wider and taller glyph + * depending on how large of a radius was used to stroke the glyph. You + * may need to manually adjust horizontal and vertical advance amounts to + * account for this added size. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ); + + /* */ + +FT_END_HEADER + +#endif /* FTSTROKE_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/vendor/freetype/include/freetype/ftsynth.h b/vendor/freetype/include/freetype/ftsynth.h new file mode 100644 index 0000000..af90967 --- /dev/null +++ b/vendor/freetype/include/freetype/ftsynth.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * ftsynth.h + * + * FreeType synthesizing code for emboldening and slanting + * (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS ALPHA CODE! THIS API *********/ + /********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/ + /********* FREETYPE DEVELOPMENT TEAM *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Main reason for not lifting the functions in this module to a */ + /* 'standard' API is that the used parameters for emboldening and */ + /* slanting are not configurable. Consider the functions as a */ + /* code resource that should be copied into the application and */ + /* adapted to the particular needs. */ + + +#ifndef FTSYNTH_H_ +#define FTSYNTH_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /* Embolden a glyph by a 'reasonable' value (which is highly a matter of */ + /* taste). This function is actually a convenience function, providing */ + /* a wrapper for @FT_Outline_Embolden and @FT_Bitmap_Embolden. */ + /* */ + /* For emboldened outlines the height, width, and advance metrics are */ + /* increased by the strength of the emboldening -- this even affects */ + /* mono-width fonts! */ + /* */ + /* You can also call @FT_Outline_Get_CBox to get precise values. */ + FT_EXPORT( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ); + + /* Precisely adjust the glyph weight either horizontally or vertically. */ + /* The `xdelta` and `ydelta` values are fractions of the face Em size */ + /* (in fixed-point format). Considering that a regular face would have */ + /* stem widths on the order of 0.1 Em, a delta of 0.05 (0x0CCC) should */ + /* be very noticeable. To increase or decrease the weight, use positive */ + /* or negative values, respectively. */ + FT_EXPORT( void ) + FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot, + FT_Fixed xdelta, + FT_Fixed ydelta ); + + + /* Slant an outline glyph to the right by about 12 degrees. */ + FT_EXPORT( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ); + + /* Slant an outline glyph by a given sine of an angle. You can apply */ + /* slant along either x- or y-axis by choosing a corresponding non-zero */ + /* argument. If both slants are non-zero, some affine transformation */ + /* will result. */ + FT_EXPORT( void ) + FT_GlyphSlot_Slant( FT_GlyphSlot slot, + FT_Fixed xslant, + FT_Fixed yslant ); + + /* */ + + +FT_END_HEADER + +#endif /* FTSYNTH_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftsystem.h b/vendor/freetype/include/freetype/ftsystem.h new file mode 100644 index 0000000..3a08f49 --- /dev/null +++ b/vendor/freetype/include/freetype/ftsystem.h @@ -0,0 +1,350 @@ +/**************************************************************************** + * + * ftsystem.h + * + * FreeType low-level system interface definition (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSYSTEM_H_ +#define FTSYSTEM_H_ + + + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * system_interface + * + * @title: + * System Interface + * + * @abstract: + * How FreeType manages memory and i/o. + * + * @description: + * This section contains various definitions related to memory management + * and i/o access. You need to understand this information if you want to + * use a custom memory manager or you own i/o streams. + * + */ + + + /************************************************************************** + * + * M E M O R Y M A N A G E M E N T + * + */ + + + /************************************************************************** + * + * @type: + * FT_Memory + * + * @description: + * A handle to a given memory manager object, defined with an + * @FT_MemoryRec structure. + * + */ + typedef struct FT_MemoryRec_* FT_Memory; + + + /************************************************************************** + * + * @functype: + * FT_Alloc_Func + * + * @description: + * A function used to allocate `size` bytes from `memory`. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * size :: + * The size in bytes to allocate. + * + * @return: + * Address of new memory block. 0~in case of failure. + * + */ + typedef void* + (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + + /************************************************************************** + * + * @functype: + * FT_Free_Func + * + * @description: + * A function used to release a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * block :: + * The address of the target memory block. + * + */ + typedef void + (*FT_Free_Func)( FT_Memory memory, + void* block ); + + + /************************************************************************** + * + * @functype: + * FT_Realloc_Func + * + * @description: + * A function used to re-allocate a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * cur_size :: + * The block's current size in bytes. + * + * new_size :: + * The block's requested new size. + * + * block :: + * The block's current address. + * + * @return: + * New block address. 0~in case of memory shortage. + * + * @note: + * In case of error, the old block must still be available. + * + */ + typedef void* + (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + + /************************************************************************** + * + * @struct: + * FT_MemoryRec + * + * @description: + * A structure used to describe a given memory manager to FreeType~2. + * + * @fields: + * user :: + * A generic typeless pointer for user data. + * + * alloc :: + * A pointer type to an allocation function. + * + * free :: + * A pointer type to an memory freeing function. + * + * realloc :: + * A pointer type to a reallocation function. + * + */ + struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + }; + + + /************************************************************************** + * + * I / O M A N A G E M E N T + * + */ + + + /************************************************************************** + * + * @type: + * FT_Stream + * + * @description: + * A handle to an input stream. + * + * @also: + * See @FT_StreamRec for the publicly accessible fields of a given stream + * object. + * + */ + typedef struct FT_StreamRec_* FT_Stream; + + + /************************************************************************** + * + * @struct: + * FT_StreamDesc + * + * @description: + * A union type used to store either a long or a pointer. This is used + * to store a file descriptor or a `FILE*` in an input stream. + * + */ + typedef union FT_StreamDesc_ + { + long value; + void* pointer; + + } FT_StreamDesc; + + + /************************************************************************** + * + * @functype: + * FT_Stream_IoFunc + * + * @description: + * A function used to seek and read data from a given input stream. + * + * @input: + * stream :: + * A handle to the source stream. + * + * offset :: + * The offset from the start of the stream to seek to. + * + * buffer :: + * The address of the read buffer. + * + * count :: + * The number of bytes to read from the stream. + * + * @return: + * If count >~0, return the number of bytes effectively read by the + * stream (after seeking to `offset`). If count ==~0, return the status + * of the seek operation (non-zero indicates an error). + * + */ + typedef unsigned long + (*FT_Stream_IoFunc)( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ); + + + /************************************************************************** + * + * @functype: + * FT_Stream_CloseFunc + * + * @description: + * A function used to close a given input stream. + * + * @input: + * stream :: + * A handle to the target stream. + * + */ + typedef void + (*FT_Stream_CloseFunc)( FT_Stream stream ); + + + /************************************************************************** + * + * @struct: + * FT_StreamRec + * + * @description: + * A structure used to describe an input stream. + * + * @input: + * base :: + * For memory-based streams, this is the address of the first stream + * byte in memory. This field should always be set to `NULL` for + * disk-based streams. + * + * size :: + * The stream size in bytes. + * + * In case of compressed streams where the size is unknown before + * actually doing the decompression, the value is set to 0x7FFFFFFF. + * (Note that this size value can occur for normal streams also; it is + * thus just a hint.) + * + * pos :: + * The current position within the stream. + * + * descriptor :: + * This field is a union that can hold an integer or a pointer. It is + * used by stream implementations to store file descriptors or `FILE*` + * pointers. + * + * pathname :: + * This field is completely ignored by FreeType. However, it is often + * useful during debugging to use it to store the stream's filename + * (where available). + * + * read :: + * The stream's input function. + * + * close :: + * The stream's close function. + * + * memory :: + * The memory manager to use to preload frames. This is set internally + * by FreeType and shouldn't be touched by stream implementations. + * + * cursor :: + * This field is set and used internally by FreeType when parsing + * frames. In particular, the `FT_GET_XXX` macros use this instead of + * the `pos` field. + * + * limit :: + * This field is set and used internally by FreeType when parsing + * frames. + * + */ + typedef struct FT_StreamRec_ + { + unsigned char* base; + unsigned long size; + unsigned long pos; + + FT_StreamDesc descriptor; + FT_StreamDesc pathname; + FT_Stream_IoFunc read; + FT_Stream_CloseFunc close; + + FT_Memory memory; + unsigned char* cursor; + unsigned char* limit; + + } FT_StreamRec; + + /* */ + + +FT_END_HEADER + +#endif /* FTSYSTEM_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/fttrigon.h b/vendor/freetype/include/freetype/fttrigon.h new file mode 100644 index 0000000..294981a --- /dev/null +++ b/vendor/freetype/include/freetype/fttrigon.h @@ -0,0 +1,350 @@ +/**************************************************************************** + * + * fttrigon.h + * + * FreeType trigonometric functions (specification). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTTRIGON_H_ +#define FTTRIGON_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * computations + * + */ + + + /************************************************************************** + * + * @type: + * FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed-point value expressed in degrees. + * + */ + typedef FT_Fixed FT_Angle; + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI ( 180L << 16 ) + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_2PI ( FT_ANGLE_PI * 2 ) + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI2 ( FT_ANGLE_PI / 2 ) + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI4 ( FT_ANGLE_PI / 4 ) + + + /************************************************************************** + * + * @function: + * FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Sin( FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Cos( FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Tan( FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in the 2d + * plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ + FT_EXPORT( FT_Angle ) + FT_Atan2( FT_Fixed x, + FT_Fixed y ); + + + /************************************************************************** + * + * @function: + * FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `angle2-angle1`. + * + */ + FT_EXPORT( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x` will be `cos(angle)`, and the value of + * `vec.y` will be `sin(angle)`. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ); + + + /************************************************************************** + * + * @function: + * FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ); + + /* */ + + +FT_END_HEADER + +#endif /* FTTRIGON_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/fttypes.h b/vendor/freetype/include/freetype/fttypes.h new file mode 100644 index 0000000..5b109f0 --- /dev/null +++ b/vendor/freetype/include/freetype/fttypes.h @@ -0,0 +1,617 @@ +/**************************************************************************** + * + * fttypes.h + * + * FreeType simple types definitions (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTTYPES_H_ +#define FTTYPES_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include + +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * basic_types + * + * @title: + * Basic Data Types + * + * @abstract: + * The basic data types defined by the library. + * + * @description: + * This section contains the basic data types defined by FreeType~2, + * ranging from simple scalar types to bitmap descriptors. More + * font-specific structures are defined in a different section. Note + * that FreeType does not use floating-point data types. Fractional + * values are represented by fixed-point integers, with lower bits + * storing the fractional part. + * + * @order: + * FT_Byte + * FT_Bytes + * FT_Char + * FT_Int + * FT_UInt + * FT_Int16 + * FT_UInt16 + * FT_Int32 + * FT_UInt32 + * FT_Int64 + * FT_UInt64 + * FT_Short + * FT_UShort + * FT_Long + * FT_ULong + * FT_Bool + * FT_Offset + * FT_PtrDist + * FT_String + * FT_Tag + * FT_Error + * FT_Fixed + * FT_Pointer + * FT_Pos + * FT_Vector + * FT_BBox + * FT_Matrix + * FT_FWord + * FT_UFWord + * FT_F2Dot14 + * FT_UnitVector + * FT_F26Dot6 + * FT_Data + * + * FT_MAKE_TAG + * + * FT_Generic + * FT_Generic_Finalizer + * + * FT_Bitmap + * FT_Pixel_Mode + * FT_Palette_Mode + * FT_Glyph_Format + * FT_IMAGE_TAG + * + */ + + + /************************************************************************** + * + * @type: + * FT_Bool + * + * @description: + * A typedef of unsigned char, used for simple booleans. As usual, + * values 1 and~0 represent true and false, respectively. + */ + typedef unsigned char FT_Bool; + + + /************************************************************************** + * + * @type: + * FT_FWord + * + * @description: + * A signed 16-bit integer used to store a distance in original font + * units. + */ + typedef signed short FT_FWord; /* distance in FUnits */ + + + /************************************************************************** + * + * @type: + * FT_UFWord + * + * @description: + * An unsigned 16-bit integer used to store a distance in original font + * units. + */ + typedef unsigned short FT_UFWord; /* unsigned distance */ + + + /************************************************************************** + * + * @type: + * FT_Char + * + * @description: + * A simple typedef for the _signed_ char type. + */ + typedef signed char FT_Char; + + + /************************************************************************** + * + * @type: + * FT_Byte + * + * @description: + * A simple typedef for the _unsigned_ char type. + */ + typedef unsigned char FT_Byte; + + + /************************************************************************** + * + * @type: + * FT_Bytes + * + * @description: + * A typedef for constant memory areas. + */ + typedef const FT_Byte* FT_Bytes; + + + /************************************************************************** + * + * @type: + * FT_Tag + * + * @description: + * A typedef for 32-bit tags (as used in the SFNT format). + */ + typedef FT_UInt32 FT_Tag; + + + /************************************************************************** + * + * @type: + * FT_String + * + * @description: + * A simple typedef for the char type, usually used for strings. + */ + typedef char FT_String; + + + /************************************************************************** + * + * @type: + * FT_Short + * + * @description: + * A typedef for signed short. + */ + typedef signed short FT_Short; + + + /************************************************************************** + * + * @type: + * FT_UShort + * + * @description: + * A typedef for unsigned short. + */ + typedef unsigned short FT_UShort; + + + /************************************************************************** + * + * @type: + * FT_Int + * + * @description: + * A typedef for the int type. + */ + typedef signed int FT_Int; + + + /************************************************************************** + * + * @type: + * FT_UInt + * + * @description: + * A typedef for the unsigned int type. + */ + typedef unsigned int FT_UInt; + + + /************************************************************************** + * + * @type: + * FT_Long + * + * @description: + * A typedef for signed long. + */ + typedef signed long FT_Long; + + + /************************************************************************** + * + * @type: + * FT_ULong + * + * @description: + * A typedef for unsigned long. + */ + typedef unsigned long FT_ULong; + + + /************************************************************************** + * + * @type: + * FT_F2Dot14 + * + * @description: + * A signed 2.14 fixed-point type used for unit vectors. + */ + typedef signed short FT_F2Dot14; + + + /************************************************************************** + * + * @type: + * FT_F26Dot6 + * + * @description: + * A signed 26.6 fixed-point type used for vectorial pixel coordinates. + */ + typedef signed long FT_F26Dot6; + + + /************************************************************************** + * + * @type: + * FT_Fixed + * + * @description: + * This type is used to store 16.16 fixed-point values, like scaling + * values or matrix coefficients. + */ + typedef signed long FT_Fixed; + + + /************************************************************************** + * + * @type: + * FT_Error + * + * @description: + * The FreeType error code type. A value of~0 is always interpreted as a + * successful operation. + */ + typedef int FT_Error; + + + /************************************************************************** + * + * @type: + * FT_Pointer + * + * @description: + * A simple typedef for a typeless pointer. + */ + typedef void* FT_Pointer; + + + /************************************************************************** + * + * @type: + * FT_Offset + * + * @description: + * This is equivalent to the ANSI~C `size_t` type, i.e., the largest + * _unsigned_ integer type used to express a file size or position, or a + * memory block size. + */ + typedef size_t FT_Offset; + + + /************************************************************************** + * + * @type: + * FT_PtrDist + * + * @description: + * This is equivalent to the ANSI~C `ptrdiff_t` type, i.e., the largest + * _signed_ integer type used to express the distance between two + * pointers. + */ + typedef ft_ptrdiff_t FT_PtrDist; + + + /************************************************************************** + * + * @struct: + * FT_UnitVector + * + * @description: + * A simple structure used to store a 2D vector unit vector. Uses + * FT_F2Dot14 types. + * + * @fields: + * x :: + * Horizontal coordinate. + * + * y :: + * Vertical coordinate. + */ + typedef struct FT_UnitVector_ + { + FT_F2Dot14 x; + FT_F2Dot14 y; + + } FT_UnitVector; + + + /************************************************************************** + * + * @struct: + * FT_Matrix + * + * @description: + * A simple structure used to store a 2x2 matrix. Coefficients are in + * 16.16 fixed-point format. The computation performed is: + * + * ``` + * x' = x*xx + y*xy + * y' = x*yx + y*yy + * ``` + * + * @fields: + * xx :: + * Matrix coefficient. + * + * xy :: + * Matrix coefficient. + * + * yx :: + * Matrix coefficient. + * + * yy :: + * Matrix coefficient. + */ + typedef struct FT_Matrix_ + { + FT_Fixed xx, xy; + FT_Fixed yx, yy; + + } FT_Matrix; + + + /************************************************************************** + * + * @struct: + * FT_Data + * + * @description: + * Read-only binary data represented as a pointer and a length. + * + * @fields: + * pointer :: + * The data. + * + * length :: + * The length of the data in bytes. + */ + typedef struct FT_Data_ + { + const FT_Byte* pointer; + FT_UInt length; + + } FT_Data; + + + /************************************************************************** + * + * @functype: + * FT_Generic_Finalizer + * + * @description: + * Describe a function used to destroy the 'client' data of any FreeType + * object. See the description of the @FT_Generic type for details of + * usage. + * + * @input: + * The address of the FreeType object that is under finalization. Its + * client data is accessed through its `generic` field. + */ + typedef void (*FT_Generic_Finalizer)( void* object ); + + + /************************************************************************** + * + * @struct: + * FT_Generic + * + * @description: + * Client applications often need to associate their own data to a + * variety of FreeType core objects. For example, a text layout API + * might want to associate a glyph cache to a given size object. + * + * Some FreeType object contains a `generic` field, of type `FT_Generic`, + * which usage is left to client applications and font servers. + * + * It can be used to store a pointer to client-specific data, as well as + * the address of a 'finalizer' function, which will be called by + * FreeType when the object is destroyed (for example, the previous + * client example would put the address of the glyph cache destructor in + * the `finalizer` field). + * + * @fields: + * data :: + * A typeless pointer to any client-specified data. This field is + * completely ignored by the FreeType library. + * + * finalizer :: + * A pointer to a 'generic finalizer' function, which will be called + * when the object is destroyed. If this field is set to `NULL`, no + * code will be called. + */ + typedef struct FT_Generic_ + { + void* data; + FT_Generic_Finalizer finalizer; + + } FT_Generic; + + + /************************************************************************** + * + * @macro: + * FT_MAKE_TAG + * + * @description: + * This macro converts four-letter tags that are used to label TrueType + * tables into an `FT_Tag` type, to be used within FreeType. + * + * @note: + * The produced values **must** be 32-bit integers. Don't redefine this + * macro. + */ +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( FT_STATIC_BYTE_CAST( FT_Tag, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_Tag, _x4 ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* L I S T M A N A G E M E N T */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * list_processing + * + */ + + + /************************************************************************** + * + * @type: + * FT_ListNode + * + * @description: + * Many elements and objects in FreeType are listed through an @FT_List + * record (see @FT_ListRec). As its name suggests, an FT_ListNode is a + * handle to a single list element. + */ + typedef struct FT_ListNodeRec_* FT_ListNode; + + + /************************************************************************** + * + * @type: + * FT_List + * + * @description: + * A handle to a list record (see @FT_ListRec). + */ + typedef struct FT_ListRec_* FT_List; + + + /************************************************************************** + * + * @struct: + * FT_ListNodeRec + * + * @description: + * A structure used to hold a single list element. + * + * @fields: + * prev :: + * The previous element in the list. `NULL` if first. + * + * next :: + * The next element in the list. `NULL` if last. + * + * data :: + * A typeless pointer to the listed object. + */ + typedef struct FT_ListNodeRec_ + { + FT_ListNode prev; + FT_ListNode next; + void* data; + + } FT_ListNodeRec; + + + /************************************************************************** + * + * @struct: + * FT_ListRec + * + * @description: + * A structure used to hold a simple doubly-linked list. These are used + * in many parts of FreeType. + * + * @fields: + * head :: + * The head (first element) of doubly-linked list. + * + * tail :: + * The tail (last element) of doubly-linked list. + */ + typedef struct FT_ListRec_ + { + FT_ListNode head; + FT_ListNode tail; + + } FT_ListRec; + + /* */ + + +#define FT_IS_EMPTY( list ) ( (list).head == 0 ) +#define FT_BOOL( x ) FT_STATIC_CAST( FT_Bool, (x) != 0 ) + + /* concatenate C tokens */ +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + + /* see `ftmoderr.h` for descriptions of the following macros */ + +#define FT_ERR( e ) FT_ERR_CAT( FT_ERR_PREFIX, e ) + +#define FT_ERROR_BASE( x ) ( (x) & 0xFF ) +#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U ) + +#define FT_ERR_EQ( x, e ) \ + ( FT_ERROR_BASE( x ) == FT_ERROR_BASE( FT_ERR( e ) ) ) +#define FT_ERR_NEQ( x, e ) \ + ( FT_ERROR_BASE( x ) != FT_ERROR_BASE( FT_ERR( e ) ) ) + + +FT_END_HEADER + +#endif /* FTTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ftwinfnt.h b/vendor/freetype/include/freetype/ftwinfnt.h new file mode 100644 index 0000000..7b701ea --- /dev/null +++ b/vendor/freetype/include/freetype/ftwinfnt.h @@ -0,0 +1,276 @@ +/**************************************************************************** + * + * ftwinfnt.h + * + * FreeType API for accessing Windows fnt-specific data. + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTWINFNT_H_ +#define FTWINFNT_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * winfnt_fonts + * + * @title: + * Window FNT Files + * + * @abstract: + * Windows FNT-specific API. + * + * @description: + * This section contains the declaration of Windows FNT-specific + * functions. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_WinFNT_ID_XXX + * + * @description: + * A list of valid values for the `charset` byte in @FT_WinFNT_HeaderRec. + * Exact mapping tables for the various 'cpXXXX' encodings (except for + * 'cp1361') can be found at 'ftp://ftp.unicode.org/Public/' in the + * `MAPPINGS/VENDORS/MICSFT/WINDOWS` subdirectory. 'cp1361' is roughly a + * superset of `MAPPINGS/OBSOLETE/EASTASIA/KSC/JOHAB.TXT`. + * + * @values: + * FT_WinFNT_ID_DEFAULT :: + * This is used for font enumeration and font creation as a 'don't + * care' value. Valid font files don't contain this value. When + * querying for information about the character set of the font that is + * currently selected into a specified device context, this return + * value (of the related Windows API) simply denotes failure. + * + * FT_WinFNT_ID_SYMBOL :: + * There is no known mapping table available. + * + * FT_WinFNT_ID_MAC :: + * Mac Roman encoding. + * + * FT_WinFNT_ID_OEM :: + * From Michael Poettgen : + * + * The 'Windows Font Mapping' article says that `FT_WinFNT_ID_OEM` is + * used for the charset of vector fonts, like `modern.fon`, + * `roman.fon`, and `script.fon` on Windows. + * + * The 'CreateFont' documentation says: The `FT_WinFNT_ID_OEM` value + * specifies a character set that is operating-system dependent. + * + * The 'IFIMETRICS' documentation from the 'Windows Driver Development + * Kit' says: This font supports an OEM-specific character set. The + * OEM character set is system dependent. + * + * In general OEM, as opposed to ANSI (i.e., 'cp1252'), denotes the + * second default codepage that most international versions of Windows + * have. It is one of the OEM codepages from + * + * https://docs.microsoft.com/en-us/windows/desktop/intl/code-page-identifiers + * , + * + * and is used for the 'DOS boxes', to support legacy applications. A + * German Windows version for example usually uses ANSI codepage 1252 + * and OEM codepage 850. + * + * FT_WinFNT_ID_CP874 :: + * A superset of Thai TIS 620 and ISO 8859-11. + * + * FT_WinFNT_ID_CP932 :: + * A superset of Japanese Shift-JIS (with minor deviations). + * + * FT_WinFNT_ID_CP936 :: + * A superset of simplified Chinese GB 2312-1980 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP949 :: + * A superset of Korean Hangul KS~C 5601-1987 (with different ordering + * and minor deviations). + * + * FT_WinFNT_ID_CP950 :: + * A superset of traditional Chinese Big~5 ETen (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP1250 :: + * A superset of East European ISO 8859-2 (with slightly different + * ordering). + * + * FT_WinFNT_ID_CP1251 :: + * A superset of Russian ISO 8859-5 (with different ordering). + * + * FT_WinFNT_ID_CP1252 :: + * ANSI encoding. A superset of ISO 8859-1. + * + * FT_WinFNT_ID_CP1253 :: + * A superset of Greek ISO 8859-7 (with minor modifications). + * + * FT_WinFNT_ID_CP1254 :: + * A superset of Turkish ISO 8859-9. + * + * FT_WinFNT_ID_CP1255 :: + * A superset of Hebrew ISO 8859-8 (with some modifications). + * + * FT_WinFNT_ID_CP1256 :: + * A superset of Arabic ISO 8859-6 (with different ordering). + * + * FT_WinFNT_ID_CP1257 :: + * A superset of Baltic ISO 8859-13 (with some deviations). + * + * FT_WinFNT_ID_CP1258 :: + * For Vietnamese. This encoding doesn't cover all necessary + * characters. + * + * FT_WinFNT_ID_CP1361 :: + * Korean (Johab). + */ + +#define FT_WinFNT_ID_CP1252 0 +#define FT_WinFNT_ID_DEFAULT 1 +#define FT_WinFNT_ID_SYMBOL 2 +#define FT_WinFNT_ID_MAC 77 +#define FT_WinFNT_ID_CP932 128 +#define FT_WinFNT_ID_CP949 129 +#define FT_WinFNT_ID_CP1361 130 +#define FT_WinFNT_ID_CP936 134 +#define FT_WinFNT_ID_CP950 136 +#define FT_WinFNT_ID_CP1253 161 +#define FT_WinFNT_ID_CP1254 162 +#define FT_WinFNT_ID_CP1258 163 +#define FT_WinFNT_ID_CP1255 177 +#define FT_WinFNT_ID_CP1256 178 +#define FT_WinFNT_ID_CP1257 186 +#define FT_WinFNT_ID_CP1251 204 +#define FT_WinFNT_ID_CP874 222 +#define FT_WinFNT_ID_CP1250 238 +#define FT_WinFNT_ID_OEM 255 + + + /************************************************************************** + * + * @struct: + * FT_WinFNT_HeaderRec + * + * @description: + * Windows FNT Header info. + */ + typedef struct FT_WinFNT_HeaderRec_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_ULong reserved1[4]; + + } FT_WinFNT_HeaderRec; + + + /************************************************************************** + * + * @struct: + * FT_WinFNT_Header + * + * @description: + * A handle to an @FT_WinFNT_HeaderRec structure. + */ + typedef struct FT_WinFNT_HeaderRec_* FT_WinFNT_Header; + + + /************************************************************************** + * + * @function: + * FT_Get_WinFNT_Header + * + * @description: + * Retrieve a Windows FNT font info header. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * aheader :: + * The WinFNT header. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with Windows FNT faces, returning an error + * otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + /* */ + + +FT_END_HEADER + +#endif /* FTWINFNT_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/vendor/freetype/include/freetype/internal/autohint.h b/vendor/freetype/include/freetype/internal/autohint.h new file mode 100644 index 0000000..bf9c8b7 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/autohint.h @@ -0,0 +1,234 @@ +/**************************************************************************** + * + * autohint.h + * + * High-level 'autohint' module-specific interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * The auto-hinter is used to load and automatically hint glyphs if a + * format-specific hinter isn't available. + * + */ + + +#ifndef AUTOHINT_H_ +#define AUTOHINT_H_ + + + /************************************************************************** + * + * A small technical note regarding automatic hinting in order to clarify + * this module interface. + * + * An automatic hinter might compute two kinds of data for a given face: + * + * - global hints: Usually some metrics that describe global properties + * of the face. It is computed by scanning more or less + * aggressively the glyphs in the face, and thus can be + * very slow to compute (even if the size of global hints + * is really small). + * + * - glyph hints: These describe some important features of the glyph + * outline, as well as how to align them. They are + * generally much faster to compute than global hints. + * + * The current FreeType auto-hinter does a pretty good job while performing + * fast computations for both global and glyph hints. However, we might be + * interested in introducing more complex and powerful algorithms in the + * future, like the one described in the John D. Hobby paper, which + * unfortunately requires a lot more horsepower. + * + * Because a sufficiently sophisticated font management system would + * typically implement an LRU cache of opened face objects to reduce memory + * usage, it is a good idea to be able to avoid recomputing global hints + * every time the same face is re-opened. + * + * We thus provide the ability to cache global hints outside of the face + * object, in order to speed up font re-opening time. Of course, this + * feature is purely optional, so most client programs won't even notice + * it. + * + * I initially thought that it would be a good idea to cache the glyph + * hints too. However, my general idea now is that if you really need to + * cache these too, you are simply in need of a new font format, where all + * this information could be stored within the font file and decoded on the + * fly. + * + */ + + +#include + + +FT_BEGIN_HEADER + + + typedef struct FT_AutoHinterRec_ *FT_AutoHinter; + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlobalGetFunc + * + * @description: + * Retrieve the global hints computed for a given face object. The + * resulting data is dissociated from the face and will survive a call to + * FT_Done_Face(). It must be discarded through the API + * FT_AutoHinter_GlobalDoneFunc(). + * + * @input: + * hinter :: + * A handle to the source auto-hinter. + * + * face :: + * A handle to the source face object. + * + * @output: + * global_hints :: + * A typeless pointer to the global hints. + * + * global_len :: + * The size in bytes of the global hints. + */ + typedef void + (*FT_AutoHinter_GlobalGetFunc)( FT_AutoHinter hinter, + FT_Face face, + void** global_hints, + long* global_len ); + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlobalDoneFunc + * + * @description: + * Discard the global hints retrieved through + * FT_AutoHinter_GlobalGetFunc(). This is the only way these hints are + * freed from memory. + * + * @input: + * hinter :: + * A handle to the auto-hinter module. + * + * global :: + * A pointer to retrieved global hints to discard. + */ + typedef void + (*FT_AutoHinter_GlobalDoneFunc)( FT_AutoHinter hinter, + void* global ); + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlobalResetFunc + * + * @description: + * This function is used to recompute the global metrics in a given font. + * This is useful when global font data changes (e.g. Multiple Masters + * fonts where blend coordinates change). + * + * @input: + * hinter :: + * A handle to the source auto-hinter. + * + * face :: + * A handle to the face. + */ + typedef void + (*FT_AutoHinter_GlobalResetFunc)( FT_AutoHinter hinter, + FT_Face face ); + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlyphLoadFunc + * + * @description: + * This function is used to load, scale, and automatically hint a glyph + * from a given face. + * + * @input: + * face :: + * A handle to the face. + * + * glyph_index :: + * The glyph index. + * + * load_flags :: + * The load flags. + * + * @note: + * This function is capable of loading composite glyphs by hinting each + * sub-glyph independently (which improves quality). + * + * It will call the font driver with @FT_Load_Glyph, with + * @FT_LOAD_NO_SCALE set. + */ + typedef FT_Error + (*FT_AutoHinter_GlyphLoadFunc)( FT_AutoHinter hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /************************************************************************** + * + * @struct: + * FT_AutoHinter_InterfaceRec + * + * @description: + * The auto-hinter module's interface. + */ + typedef struct FT_AutoHinter_InterfaceRec_ + { + FT_AutoHinter_GlobalResetFunc reset_face; + FT_AutoHinter_GlobalGetFunc get_global_hints; + FT_AutoHinter_GlobalDoneFunc done_global_hints; + FT_AutoHinter_GlyphLoadFunc load_glyph; + + } FT_AutoHinter_InterfaceRec, *FT_AutoHinter_Interface; + + +#define FT_DECLARE_AUTOHINTER_INTERFACE( class_ ) \ + FT_CALLBACK_TABLE const FT_AutoHinter_InterfaceRec class_; + +#define FT_DEFINE_AUTOHINTER_INTERFACE( \ + class_, \ + reset_face_, \ + get_global_hints_, \ + done_global_hints_, \ + load_glyph_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_AutoHinter_InterfaceRec class_ = \ + { \ + reset_face_, \ + get_global_hints_, \ + done_global_hints_, \ + load_glyph_ \ + }; + + +FT_END_HEADER + +#endif /* AUTOHINT_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/cffotypes.h b/vendor/freetype/include/freetype/internal/cffotypes.h new file mode 100644 index 0000000..50d5353 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/cffotypes.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * + * cffotypes.h + * + * Basic OpenType/CFF object type definitions (specification). + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFOTYPES_H_ +#define CFFOTYPES_H_ + +#include +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + typedef TT_Face CFF_Face; + + + /************************************************************************** + * + * @type: + * CFF_Size + * + * @description: + * A handle to an OpenType size object. + */ + typedef struct CFF_SizeRec_ + { + FT_SizeRec root; + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ + + } CFF_SizeRec, *CFF_Size; + + + /************************************************************************** + * + * @type: + * CFF_GlyphSlot + * + * @description: + * A handle to an OpenType glyph slot object. + */ + typedef struct CFF_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } CFF_GlyphSlotRec, *CFF_GlyphSlot; + + + /************************************************************************** + * + * @type: + * CFF_Internal + * + * @description: + * The interface to the 'internal' field of `FT_Size`. + */ + typedef struct CFF_InternalRec_ + { + PSH_Globals topfont; + PSH_Globals subfonts[CFF_MAX_CID_FONTS]; + + } CFF_InternalRec, *CFF_Internal; + + + /************************************************************************** + * + * Subglyph transformation record. + */ + typedef struct CFF_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } CFF_Transform; + + +FT_END_HEADER + + +#endif /* CFFOTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/cfftypes.h b/vendor/freetype/include/freetype/internal/cfftypes.h new file mode 100644 index 0000000..c252176 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/cfftypes.h @@ -0,0 +1,416 @@ +/**************************************************************************** + * + * cfftypes.h + * + * Basic OpenType/CFF type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFTYPES_H_ +#define CFFTYPES_H_ + + +#include +#include +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * CFF_IndexRec + * + * @description: + * A structure used to model a CFF Index table. + * + * @fields: + * stream :: + * The source input stream. + * + * start :: + * The position of the first index byte in the input stream. + * + * count :: + * The number of elements in the index. + * + * off_size :: + * The size in bytes of object offsets in index. + * + * data_offset :: + * The position of first data byte in the index's bytes. + * + * data_size :: + * The size of the data table in this index. + * + * offsets :: + * A table of element offsets in the index. Must be loaded explicitly. + * + * bytes :: + * If the index is loaded in memory, its bytes. + */ + typedef struct CFF_IndexRec_ + { + FT_Stream stream; + FT_ULong start; + FT_UInt hdr_size; + FT_UInt count; + FT_Byte off_size; + FT_ULong data_offset; + FT_ULong data_size; + + FT_ULong* offsets; + FT_Byte* bytes; + + } CFF_IndexRec, *CFF_Index; + + + typedef struct CFF_EncodingRec_ + { + FT_UInt format; + FT_ULong offset; + + FT_UInt count; + FT_UShort sids [256]; /* avoid dynamic allocations */ + FT_UShort codes[256]; + + } CFF_EncodingRec, *CFF_Encoding; + + + typedef struct CFF_CharsetRec_ + { + + FT_UInt format; + FT_ULong offset; + + FT_UShort* sids; + FT_UShort* cids; /* the inverse mapping of `sids'; only needed */ + /* for CID-keyed fonts */ + FT_UInt max_cid; + FT_UInt num_glyphs; + + } CFF_CharsetRec, *CFF_Charset; + + + /* cf. similar fields in file `ttgxvar.h' from the `truetype' module */ + + typedef struct CFF_VarData_ + { +#if 0 + FT_UInt itemCount; /* not used; always zero */ + FT_UInt shortDeltaCount; /* not used; always zero */ +#endif + + FT_UInt regionIdxCount; /* number of region indexes */ + FT_UInt* regionIndices; /* array of `regionIdxCount' indices; */ + /* these index `varRegionList' */ + } CFF_VarData; + + + /* contribution of one axis to a region */ + typedef struct CFF_AxisCoords_ + { + FT_Fixed startCoord; + FT_Fixed peakCoord; /* zero peak means no effect (factor = 1) */ + FT_Fixed endCoord; + + } CFF_AxisCoords; + + + typedef struct CFF_VarRegion_ + { + CFF_AxisCoords* axisList; /* array of axisCount records */ + + } CFF_VarRegion; + + + typedef struct CFF_VStoreRec_ + { + FT_UInt dataCount; + CFF_VarData* varData; /* array of dataCount records */ + /* vsindex indexes this array */ + FT_UShort axisCount; + FT_UInt regionCount; /* total number of regions defined */ + CFF_VarRegion* varRegionList; + + } CFF_VStoreRec, *CFF_VStore; + + + /* forward reference */ + typedef struct CFF_FontRec_* CFF_Font; + + + /* This object manages one cached blend vector. */ + /* */ + /* There is a BlendRec for Private DICT parsing in each subfont */ + /* and a BlendRec for charstrings in CF2_Font instance data. */ + /* A cached BV may be used across DICTs or Charstrings if inputs */ + /* have not changed. */ + /* */ + /* `usedBV' is reset at the start of each parse or charstring. */ + /* vsindex cannot be changed after a BV is used. */ + /* */ + /* Note: NDV is long (32/64 bit), while BV is 16.16 (FT_Int32). */ + typedef struct CFF_BlendRec_ + { + FT_Bool builtBV; /* blendV has been built */ + FT_Bool usedBV; /* blendV has been used */ + CFF_Font font; /* top level font struct */ + FT_UInt lastVsindex; /* last vsindex used */ + FT_UInt lenNDV; /* normDV length (aka numAxes) */ + FT_Fixed* lastNDV; /* last NDV used */ + FT_UInt lenBV; /* BlendV length (aka numMasters) */ + FT_Int32* BV; /* current blendV (per DICT/glyph) */ + + } CFF_BlendRec, *CFF_Blend; + + + typedef struct CFF_FontRecDictRec_ + { + FT_UInt version; + FT_UInt notice; + FT_UInt copyright; + FT_UInt full_name; + FT_UInt family_name; + FT_UInt weight; + FT_Bool is_fixed_pitch; + FT_Fixed italic_angle; + FT_Fixed underline_position; + FT_Fixed underline_thickness; + FT_Int paint_type; + FT_Int charstring_type; + FT_Matrix font_matrix; + FT_Bool has_font_matrix; + FT_ULong units_per_em; /* temporarily used as scaling value also */ + FT_Vector font_offset; + FT_ULong unique_id; + FT_BBox font_bbox; + FT_Pos stroke_width; + FT_ULong charset_offset; + FT_ULong encoding_offset; + FT_ULong charstrings_offset; + FT_ULong private_offset; + FT_ULong private_size; + FT_Long synthetic_base; + FT_UInt embedded_postscript; + + /* these should only be used for the top-level font dictionary */ + FT_UInt cid_registry; + FT_UInt cid_ordering; + FT_Long cid_supplement; + + FT_Long cid_font_version; + FT_Long cid_font_revision; + FT_Long cid_font_type; + FT_ULong cid_count; + FT_ULong cid_uid_base; + FT_ULong cid_fd_array_offset; + FT_ULong cid_fd_select_offset; + FT_UInt cid_font_name; + + /* the next fields come from the data of the deprecated */ + /* `MultipleMaster' operator; they are needed to parse the (also */ + /* deprecated) `blend' operator in Type 2 charstrings */ + FT_UShort num_designs; + FT_UShort num_axes; + + /* fields for CFF2 */ + FT_ULong vstore_offset; + FT_UInt maxstack; + + } CFF_FontRecDictRec, *CFF_FontRecDict; + + + /* forward reference */ + typedef struct CFF_SubFontRec_* CFF_SubFont; + + + typedef struct CFF_PrivateRec_ + { + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Pos blue_values[14]; + FT_Pos other_blues[10]; + FT_Pos family_blues[14]; + FT_Pos family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Pos blue_shift; + FT_Pos blue_fuzz; + FT_Pos standard_width; + FT_Pos standard_height; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Pos snap_widths[13]; + FT_Pos snap_heights[13]; + FT_Bool force_bold; + FT_Fixed force_bold_threshold; + FT_Int lenIV; + FT_Int language_group; + FT_Fixed expansion_factor; + FT_Long initial_random_seed; + FT_ULong local_subrs_offset; + FT_Pos default_width; + FT_Pos nominal_width; + + /* fields for CFF2 */ + FT_UInt vsindex; + CFF_SubFont subfont; + + } CFF_PrivateRec, *CFF_Private; + + + typedef struct CFF_FDSelectRec_ + { + FT_Byte format; + FT_UInt range_count; + + /* that's the table, taken from the file `as is' */ + FT_Byte* data; + FT_UInt data_size; + + /* small cache for format 3 only */ + FT_UInt cache_first; + FT_UInt cache_count; + FT_Byte cache_fd; + + } CFF_FDSelectRec, *CFF_FDSelect; + + + /* A SubFont packs a font dict and a private dict together. They are */ + /* needed to support CID-keyed CFF fonts. */ + typedef struct CFF_SubFontRec_ + { + CFF_FontRecDictRec font_dict; + CFF_PrivateRec private_dict; + + /* fields for CFF2 */ + CFF_BlendRec blend; /* current blend vector */ + FT_UInt lenNDV; /* current length NDV or zero */ + FT_Fixed* NDV; /* ptr to current NDV or NULL */ + + /* `blend_stack' is a writable buffer to hold blend results. */ + /* This buffer is to the side of the normal cff parser stack; */ + /* `cff_parse_blend' and `cff_blend_doBlend' push blend results here. */ + /* The normal stack then points to these values instead of the DICT */ + /* because all other operators in Private DICT clear the stack. */ + /* `blend_stack' could be cleared at each operator other than blend. */ + /* Blended values are stored as 5-byte fixed-point values. */ + + FT_Byte* blend_stack; /* base of stack allocation */ + FT_Byte* blend_top; /* first empty slot */ + FT_UInt blend_used; /* number of bytes in use */ + FT_UInt blend_alloc; /* number of bytes allocated */ + + CFF_IndexRec local_subrs_index; + FT_Byte** local_subrs; /* array of pointers */ + /* into Local Subrs INDEX data */ + + FT_UInt32 random; + + } CFF_SubFontRec; + + +#define CFF_MAX_CID_FONTS 256 + + + typedef struct CFF_FontRec_ + { + FT_Library library; + FT_Stream stream; + FT_Memory memory; /* TODO: take this from stream->memory? */ + FT_ULong base_offset; /* offset to start of CFF */ + FT_UInt num_faces; + FT_UInt num_glyphs; + + FT_Byte version_major; + FT_Byte version_minor; + FT_Byte header_size; + + FT_UInt top_dict_length; /* cff2 only */ + + FT_Bool cff2; + + CFF_IndexRec name_index; + CFF_IndexRec top_dict_index; + CFF_IndexRec global_subrs_index; + + CFF_EncodingRec encoding; + CFF_CharsetRec charset; + + CFF_IndexRec charstrings_index; + CFF_IndexRec font_dict_index; + CFF_IndexRec private_index; + CFF_IndexRec local_subrs_index; + + FT_String* font_name; + + /* array of pointers into Global Subrs INDEX data */ + FT_Byte** global_subrs; + + /* array of pointers into String INDEX data stored at string_pool */ + FT_UInt num_strings; + FT_Byte** strings; + FT_Byte* string_pool; + FT_ULong string_pool_size; + + CFF_SubFontRec top_font; + FT_UInt num_subfonts; + CFF_SubFont subfonts[CFF_MAX_CID_FONTS]; + + CFF_FDSelectRec fd_select; + + /* interface to PostScript hinter */ + PSHinter_Service pshinter; + + /* interface to Postscript Names service */ + FT_Service_PsCMaps psnames; + + /* interface to CFFLoad service */ + const void* cffload; + + /* since version 2.3.0 */ + PS_FontInfoRec* font_info; /* font info dictionary */ + + /* since version 2.3.6 */ + FT_String* registry; + FT_String* ordering; + + /* since version 2.4.12 */ + FT_Generic cf2_instance; + + /* since version 2.7.1 */ + CFF_VStoreRec vstore; /* parsed vstore structure */ + + /* since version 2.9 */ + PS_FontExtraRec* font_extra; + + } CFF_FontRec; + + +FT_END_HEADER + +#endif /* CFFTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/compiler-macros.h b/vendor/freetype/include/freetype/internal/compiler-macros.h new file mode 100644 index 0000000..6f67650 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/compiler-macros.h @@ -0,0 +1,343 @@ +/**************************************************************************** + * + * internal/compiler-macros.h + * + * Compiler-specific macro definitions used internally by FreeType. + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef INTERNAL_COMPILER_MACROS_H_ +#define INTERNAL_COMPILER_MACROS_H_ + +#include + +FT_BEGIN_HEADER + + /* Fix compiler warning with sgi compiler. */ +#if defined( __sgi ) && !defined( __GNUC__ ) +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif +#endif + + /* Fix compiler warning with sgi compiler. */ +#if defined( __sgi ) && !defined( __GNUC__ ) +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif +#endif + + /* Newer compilers warn for fall-through case statements. */ +#ifndef FALL_THROUGH +# if ( defined( __STDC_VERSION__ ) && __STDC_VERSION__ > 201710L ) || \ + ( defined( __cplusplus ) && __cplusplus > 201402L ) +# define FALL_THROUGH [[__fallthrough__]] +# elif ( defined( __GNUC__ ) && __GNUC__ >= 7 ) || \ + ( defined( __clang__ ) && \ + ( defined( __apple_build_version__ ) \ + ? __apple_build_version__ >= 12000000 \ + : __clang_major__ >= 10 ) ) +# define FALL_THROUGH __attribute__(( __fallthrough__ )) +# else +# define FALL_THROUGH ( (void)0 ) +# endif +#endif + + /* + * When defining a macro that expands to a non-trivial C statement, use + * FT_BEGIN_STMNT and FT_END_STMNT to enclose the macro's body. This + * ensures there are no surprises when the macro is invoked in conditional + * branches. + * + * Example: + * + * #define LOG( ... ) \ + * FT_BEGIN_STMNT \ + * if ( logging_enabled ) \ + * log( __VA_ARGS__ ); \ + * FT_END_STMNT + */ +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) + + /* + * FT_DUMMY_STMNT expands to an empty C statement. Useful for + * conditionally defined statement macros. + * + * Example: + * + * #ifdef BUILD_CONFIG_LOGGING + * #define LOG( ... ) \ + * FT_BEGIN_STMNT \ + * if ( logging_enabled ) \ + * log( __VA_ARGS__ ); \ + * FT_END_STMNT + * #else + * # define LOG( ... ) FT_DUMMY_STMNT + * #endif + */ +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT + +#ifdef __UINTPTR_TYPE__ + /* + * GCC and Clang both provide a `__UINTPTR_TYPE__` that can be used to + * avoid a dependency on `stdint.h`. + */ +# define FT_UINT_TO_POINTER( x ) (void *)(__UINTPTR_TYPE__)(x) +#elif defined( _WIN64 ) + /* only 64bit Windows uses the LLP64 data model, i.e., */ + /* 32-bit integers, 64-bit pointers. */ +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned __int64)(x) +#else +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned long)(x) +#endif + + /* + * Use `FT_TYPEOF( type )` to cast a value to `type`. This is useful to + * suppress signedness compilation warnings in macros. + * + * Example: + * + * #define PAD_( x, n ) ( (x) & ~FT_TYPEOF( x )( (n) - 1 ) ) + * + * (The `typeof` condition is taken from gnulib's `intprops.h` header + * file.) + */ +#if ( ( defined( __GNUC__ ) && __GNUC__ >= 2 ) || \ + ( defined( __IBMC__ ) && __IBMC__ >= 1210 && \ + defined( __IBM__TYPEOF__ ) ) || \ + ( defined( __SUNPRO_C ) && __SUNPRO_C >= 0x5110 && !__STDC__ ) ) +#define FT_TYPEOF( type ) ( __typeof__ ( type ) ) +#else +#define FT_TYPEOF( type ) /* empty */ +#endif + + /* + * Mark a function declaration as internal to the library. This ensures + * that it will not be exposed by default to client code, and helps + * generate smaller and faster code on ELF-based platforms. Place this + * before a function declaration. + */ + + /* Visual C, mingw */ +#if defined( _WIN32 ) +#define FT_INTERNAL_FUNCTION_ATTRIBUTE /* empty */ + + /* gcc, clang */ +#elif ( defined( __GNUC__ ) && __GNUC__ >= 4 ) || defined( __clang__ ) +#define FT_INTERNAL_FUNCTION_ATTRIBUTE \ + __attribute__(( visibility( "hidden" ) )) + + /* Sun */ +#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 +#define FT_INTERNAL_FUNCTION_ATTRIBUTE __hidden + +#else +#define FT_INTERNAL_FUNCTION_ATTRIBUTE /* empty */ +#endif + + /* + * FreeType supports compilation of its C sources with a C++ compiler (in + * C++ mode); this introduces a number of subtle issues. + * + * The main one is that a C++ function declaration and its definition must + * have the same 'linkage'. Because all FreeType headers declare their + * functions with C linkage (i.e., within an `extern "C" { ... }` block + * due to the magic of FT_BEGIN_HEADER and FT_END_HEADER), their + * definition in FreeType sources should also be prefixed with `extern + * "C"` when compiled in C++ mode. + * + * The `FT_FUNCTION_DECLARATION` and `FT_FUNCTION_DEFINITION` macros are + * provided to deal with this case, as well as `FT_CALLBACK_DEF` and its + * siblings below. + */ + + /* + * `FT_FUNCTION_DECLARATION( type )` can be used to write a C function + * declaration to ensure it will have C linkage when the library is built + * with a C++ compiler. The parameter is the function's return type, so a + * declaration would look like + * + * FT_FUNCTION_DECLARATION( int ) + * foo( int x ); + * + * NOTE: This requires that all uses are inside of `FT_BEGIN_HEADER ... + * FT_END_HEADER` blocks, which guarantees that the declarations have C + * linkage when the headers are included by C++ sources. + * + * NOTE: Do not use directly. Use `FT_LOCAL`, `FT_BASE`, and `FT_EXPORT` + * instead. + */ +#define FT_FUNCTION_DECLARATION( x ) extern x + + /* + * Same as `FT_FUNCTION_DECLARATION`, but for function definitions instead. + * + * NOTE: Do not use directly. Use `FT_LOCAL_DEF`, `FT_BASE_DEF`, and + * `FT_EXPORT_DEF` instead. + */ +#ifdef __cplusplus +#define FT_FUNCTION_DEFINITION( x ) extern "C" x +#else +#define FT_FUNCTION_DEFINITION( x ) x +#endif + + /* + * Use `FT_LOCAL` and `FT_LOCAL_DEF` to declare and define, respectively, + * an internal FreeType function that is only used by the sources of a + * single `src/module/` directory. This ensures that the functions are + * turned into static ones at build time, resulting in smaller and faster + * code. + */ +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT + +#define FT_LOCAL( x ) static x +#define FT_LOCAL_DEF( x ) static x + +#else + +#define FT_LOCAL( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + FT_FUNCTION_DECLARATION( x ) +#define FT_LOCAL_DEF( x ) FT_FUNCTION_DEFINITION( x ) + +#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ + + /* + * Use `FT_LOCAL_ARRAY` and `FT_LOCAL_ARRAY_DEF` to declare and define, + * respectively, a constant array that must be accessed from several + * sources in the same `src/module/` sub-directory, and which are internal + * to the library. + */ +#define FT_LOCAL_ARRAY( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + extern const x +#define FT_LOCAL_ARRAY_DEF( x ) FT_FUNCTION_DEFINITION( const x ) + + /* + * `Use FT_BASE` and `FT_BASE_DEF` to declare and define, respectively, an + * internal library function that is used by more than a single module. + */ +#define FT_BASE( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_DEF( x ) FT_FUNCTION_DEFINITION( x ) + + + /* + * NOTE: Conditionally define `FT_EXPORT_VAR` due to its definition in + * `src/smooth/ftgrays.h` to make the header more portable. + */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) FT_FUNCTION_DECLARATION( x ) +#endif + + /* + * When compiling FreeType as a DLL or DSO with hidden visibility, + * some systems/compilers need a special attribute in front OR after + * the return type of function declarations. + * + * Two macros are used within the FreeType source code to define + * exported library functions: `FT_EXPORT` and `FT_EXPORT_DEF`. + * + * - `FT_EXPORT( return_type )` + * + * is used in a function declaration, as in + * + * ``` + * FT_EXPORT( FT_Error ) + * FT_Init_FreeType( FT_Library* alibrary ); + * ``` + * + * - `FT_EXPORT_DEF( return_type )` + * + * is used in a function definition, as in + * + * ``` + * FT_EXPORT_DEF( FT_Error ) + * FT_Init_FreeType( FT_Library* alibrary ) + * { + * ... some code ... + * return FT_Err_Ok; + * } + * ``` + * + * You can provide your own implementation of `FT_EXPORT` and + * `FT_EXPORT_DEF` here if you want. + * + * To export a variable, use `FT_EXPORT_VAR`. + */ + + /* See `freetype/config/public-macros.h` for the `FT_EXPORT` definition */ +#define FT_EXPORT_DEF( x ) FT_FUNCTION_DEFINITION( x ) + + /* + * The following macros are needed to compile the library with a + * C++ compiler and with 16bit compilers. + */ + + /* + * This is special. Within C++, you must specify `extern "C"` for + * functions which are used via function pointers, and you also + * must do that for structures which contain function pointers to + * assure C linkage -- it's not possible to have (local) anonymous + * functions which are accessed by (global) function pointers. + * + * + * FT_CALLBACK_DEF is used to _define_ a callback function, + * located in the same source code file as the structure that uses + * it. FT_COMPARE_DEF, in addition, ensures the `cdecl` calling + * convention on x86, required by the C library function `qsort`. + * + * FT_BASE_CALLBACK and FT_BASE_CALLBACK_DEF are used to declare + * and define a callback function, respectively, in a similar way + * as FT_BASE and FT_BASE_DEF work. + * + * FT_CALLBACK_TABLE is used to _declare_ a constant variable that + * contains pointers to callback functions. + * + * FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable + * that contains pointers to callback functions. + * + * + * Some 16bit compilers have to redefine these macros to insert + * the infamous `_cdecl` or `__fastcall` declarations. + */ +#ifdef __cplusplus +#define FT_CALLBACK_DEF( x ) extern "C" x +#else +#define FT_CALLBACK_DEF( x ) static x +#endif + +#if defined( __GNUC__ ) && defined( __i386__ ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __attribute__(( cdecl )) +#elif defined( _MSC_VER ) && defined( _M_IX86 ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __cdecl +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1240 +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __watcall +#else +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) +#endif + +#define FT_BASE_CALLBACK( x ) FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_CALLBACK_DEF( x ) FT_FUNCTION_DEFINITION( x ) + +#ifndef FT_CALLBACK_TABLE +#ifdef __cplusplus +#define FT_CALLBACK_TABLE extern "C" +#define FT_CALLBACK_TABLE_DEF extern "C" +#else +#define FT_CALLBACK_TABLE extern +#define FT_CALLBACK_TABLE_DEF /* nothing */ +#endif +#endif /* FT_CALLBACK_TABLE */ + +FT_END_HEADER + +#endif /* INTERNAL_COMPILER_MACROS_H_ */ diff --git a/vendor/freetype/include/freetype/internal/ftcalc.h b/vendor/freetype/include/freetype/internal/ftcalc.h new file mode 100644 index 0000000..d9aea23 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftcalc.h @@ -0,0 +1,581 @@ +/**************************************************************************** + * + * ftcalc.h + * + * Arithmetic computations (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCALC_H_ +#define FTCALC_H_ + + +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * FT_MulDiv() and FT_MulFix() are declared in freetype.h. + * + */ + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + /* Provide assembler fragments for performance-critical functions. */ + /* These must be defined `static __inline__' with GCC. */ + +#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ + +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 t, t2; + + + __asm + { + smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ + mov a, t, asr #31 /* a = (hi >> 31) */ + add a, a, #0x8000 /* a += 0x8000 */ + adds t2, t2, a /* t2 += a */ + adc t, t, #0 /* t += carry */ + mov a, t2, lsr #16 /* a = t2 >> 16 */ + orr a, a, t, lsl #16 /* a |= t << 16 */ + } + return a; + } + +#endif /* __CC_ARM || __ARMCC__ */ + + +#ifdef __GNUC__ + +#if defined( __arm__ ) && \ + ( !defined( __thumb__ ) || defined( __thumb2__ ) ) && \ + !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 t, t2; + + + __asm__ __volatile__ ( + "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ + "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ +#if defined( __clang__ ) && defined( __thumb2__ ) + "add.w %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ +#else + "add %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ +#endif + "adds %1, %1, %0\n\t" /* %1 += %0 */ + "adc %2, %2, #0\n\t" /* %2 += carry */ + "mov %0, %1, lsr #16\n\t" /* %0 = %1 >> 16 */ + "orr %0, %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */ + : "=r"(a), "=&r"(t2), "=&r"(t) + : "r"(a), "r"(b) + : "cc" ); + return a; + } + +#endif /* __arm__ && */ + /* ( __thumb2__ || !__thumb__ ) && */ + /* !( __CC_ARM || __ARMCC__ ) */ + + +#if defined( __i386__ ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 result; + + + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x8000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $16, %%eax\n" + "shll $16, %%edx\n" + "addl %%edx, %%eax\n" + : "=a"(result), "=d"(b) + : "a"(a), "d"(b) + : "%ecx", "cc" ); + return result; + } + +#endif /* i386 */ + +#endif /* __GNUC__ */ + + +#ifdef _MSC_VER /* Visual C++ */ + +#ifdef _M_IX86 + +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 + + /* documentation is in freetype.h */ + + static __inline FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 result; + + __asm + { + mov eax, a + mov edx, b + imul edx + mov ecx, edx + sar ecx, 31 + add ecx, 8000h + add eax, ecx + adc edx, 0 + shr eax, 16 + shl edx, 16 + add eax, edx + mov result, eax + } + return result; + } + +#endif /* _M_IX86 */ + +#endif /* _MSC_VER */ + + +#if defined( __GNUC__ ) && defined( __x86_64__ ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_x86_64 + + static __inline__ FT_Int32 + FT_MulFix_x86_64( FT_Int32 a, + FT_Int32 b ) + { + /* Temporarily disable the warning that C90 doesn't support */ + /* `long long'. */ +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wlong-long" +#endif + +#if 1 + /* Technically not an assembly fragment, but GCC does a really good */ + /* job at inlining it and generating good machine code for it. */ + long long ret, tmp; + + + ret = (long long)a * b; + tmp = ret >> 63; + ret += 0x8000 + tmp; + + return (FT_Int32)( ret >> 16 ); +#else + + /* For some reason, GCC 4.6 on Ubuntu 12.04 generates invalid machine */ + /* code from the lines below. The main issue is that `wide_a' is not */ + /* properly initialized by sign-extending `a'. Instead, the generated */ + /* machine code assumes that the register that contains `a' on input */ + /* can be used directly as a 64-bit value, which is wrong most of the */ + /* time. */ + long long wide_a = (long long)a; + long long wide_b = (long long)b; + long long result; + + + __asm__ __volatile__ ( + "imul %2, %1\n" + "mov %1, %0\n" + "sar $63, %0\n" + "lea 0x8000(%1, %0), %0\n" + "sar $16, %0\n" + : "=&r"(result), "=&r"(wide_a) + : "r"(wide_b) + : "cc" ); + + return (FT_Int32)result; +#endif + +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) +#pragma GCC diagnostic pop +#endif + } + +#endif /* __GNUC__ && __x86_64__ */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX +#ifdef FT_MULFIX_ASSEMBLER +#define FT_MulFix( a, b ) FT_MULFIX_ASSEMBLER( (FT_Int32)(a), (FT_Int32)(b) ) +#endif +#endif + + + /************************************************************************** + * + * @function: + * FT_MulDiv_No_Round + * + * @description: + * A very simple function used to perform the computation '(a*b)/c' + * (without rounding) with maximum accuracy (it uses a 64-bit + * intermediate integer whenever necessary). + * + * This function isn't necessarily as fast as some processor-specific + * operations, but is at least completely portable. + * + * @input: + * a :: + * The first multiplier. + * b :: + * The second multiplier. + * c :: + * The divisor. + * + * @return: + * The result of '(a*b)/c'. This function never traps when trying to + * divide by zero; it simply returns 'MaxInt' or 'MinInt' depending on + * the signs of 'a' and 'b'. + */ + FT_BASE( FT_Long ) + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ); + + + /************************************************************************** + * + * @function: + * FT_MulAddFix + * + * @description: + * Compute `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`, where `s[n]` is + * usually a 16.16 scalar. + * + * @input: + * s :: + * The array of scalars. + * f :: + * The array of factors. + * count :: + * The number of entries in the array. + * + * @return: + * The result of `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`. + * + * @note: + * This function is currently used for the scaled delta computation of + * variation stores. It internally uses 64-bit data types when + * available, otherwise it emulates 64-bit math by using 32-bit + * operations, which produce a correct result but most likely at a slower + * performance in comparison to the implementation base on `int64_t`. + * + */ + FT_BASE( FT_Int32 ) + FT_MulAddFix( FT_Fixed* s, + FT_Int32* f, + FT_UInt count ); + + + /* + * A variant of FT_Matrix_Multiply which scales its result afterwards. The + * idea is that both `a' and `b' are scaled by factors of 10 so that the + * values are as precise as possible to get a correct result during the + * 64bit multiplication. Let `sa' and `sb' be the scaling factors of `a' + * and `b', respectively, then the scaling factor of the result is `sa*sb'. + */ + FT_BASE( void ) + FT_Matrix_Multiply_Scaled( const FT_Matrix* a, + FT_Matrix *b, + FT_Long scaling ); + + + /* + * Check a matrix. If the transformation would lead to extreme shear or + * extreme scaling, for example, return 0. If everything is OK, return 1. + * + * Based on geometric considerations we use the following inequality to + * identify a degenerate matrix. + * + * 32 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2 + * + * Value 32 is heuristic. + */ + FT_BASE( FT_Bool ) + FT_Matrix_Check( const FT_Matrix* matrix ); + + + /* + * A variant of FT_Vector_Transform. See comments for + * FT_Matrix_Multiply_Scaled. + */ + FT_BASE( void ) + FT_Vector_Transform_Scaled( FT_Vector* vector, + const FT_Matrix* matrix, + FT_Long scaling ); + + + /* + * This function normalizes a vector and returns its original length. The + * normalized vector is a 16.16 fixed-point unit vector with length close + * to 0x10000. The accuracy of the returned length is limited to 16 bits + * also. The function utilizes quick inverse square root approximation + * without divisions and square roots relying on Newton's iterations + * instead. + */ + FT_BASE( FT_UInt32 ) + FT_Vector_NormLen( FT_Vector* vector ); + + + /* + * Return -1, 0, or +1, depending on the orientation of a given corner. We + * use the Cartesian coordinate system, with positive vertical values going + * upwards. The function returns +1 if the corner turns to the left, -1 to + * the right, and 0 for undecidable cases. + */ + FT_BASE( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + + /* + * Return TRUE if a corner is flat or nearly flat. This is equivalent to + * saying that the corner point is close to its neighbors, or inside an + * ellipse defined by the neighbor focal points to be more precise. + */ + FT_BASE( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + + /* + * Return the most significant bit index. + */ + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + +#if defined( __clang__ ) || ( defined( __GNUC__ ) && \ + ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) ) ) + +#if FT_SIZEOF_INT == 4 + +#define FT_MSB( x ) ( 31 - __builtin_clz( x ) ) + +#elif FT_SIZEOF_LONG == 4 + +#define FT_MSB( x ) ( 31 - __builtin_clzl( x ) ) + +#endif + +#elif defined( _MSC_VER ) && _MSC_VER >= 1400 + +#if defined( _WIN32_WCE ) + +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_ARM64 ) || defined( _M_ARM ) + +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_IX86 ) || defined( _M_AMD64 ) || defined( _M_IA64 ) + +#include +#pragma intrinsic( _BitScanReverse ) + + static __inline FT_Int32 + FT_MSB_i386( FT_UInt32 x ) + { + unsigned long where; + + + _BitScanReverse( &where, x ); + + return (FT_Int32)where; + } + +#define FT_MSB( x ) FT_MSB_i386( x ) + +#endif + +#elif defined( __WATCOMC__ ) && defined( __386__ ) + + extern __inline FT_Int32 + FT_MSB_i386( FT_UInt32 x ); + +#pragma aux FT_MSB_i386 = \ + "bsr eax, eax" \ + __parm [__eax] __nomemory \ + __value [__eax] \ + __modify __exact [__eax] __nomemory; + +#define FT_MSB( x ) FT_MSB_i386( x ) + +#elif defined( __DECC ) || defined( __DECCXX ) + +#include + +#define FT_MSB( x ) (FT_Int)( 63 - _leadz( x ) ) + +#elif defined( _CRAYC ) + +#include + +#define FT_MSB( x ) (FT_Int)( 31 - _leadz32( x ) ) + +#endif /* FT_MSB macro definitions */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#ifndef FT_MSB + + FT_BASE( FT_Int ) + FT_MSB( FT_UInt32 z ); + +#endif + + + /* + * Return sqrt(x*x+y*y), which is the same as `FT_Vector_Length' but uses + * two fixed-point arguments instead. + */ + FT_BASE( FT_Fixed ) + FT_Hypot( FT_Fixed x, + FT_Fixed y ); + + +#if 0 + + /************************************************************************** + * + * @function: + * FT_SqrtFixed + * + * @description: + * Computes the square root of a 16.16 fixed-point value. + * + * @input: + * x :: + * The value to compute the root for. + * + * @return: + * The result of 'sqrt(x)'. + * + * @note: + * This function is not very fast. + */ + FT_BASE( FT_Int32 ) + FT_SqrtFixed( FT_Int32 x ); + +#endif /* 0 */ + + +#define INT_TO_F26DOT6( x ) ( (FT_Long)(x) * 64 ) /* << 6 */ +#define INT_TO_F2DOT14( x ) ( (FT_Long)(x) * 16384 ) /* << 14 */ +#define INT_TO_FIXED( x ) ( (FT_Long)(x) * 65536 ) /* << 16 */ +#define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) * 4 ) /* << 2 */ +#define FIXED_TO_INT( x ) ( FT_RoundFix( x ) >> 16 ) + +#define ROUND_F26DOT6( x ) ( ( (x) + 32 - ( x < 0 ) ) & -64 ) + + /* + * The following macros have two purposes. + * + * - Tag places where overflow is expected and harmless. + * + * - Avoid run-time sanitizer errors. + * + * Use with care! + */ +#define ADD_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) ) +#define SUB_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) ) +#define MUL_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) ) +#define NEG_INT( a ) \ + (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) ) + +#define ADD_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) ) +#define SUB_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) ) +#define MUL_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) ) +#define NEG_LONG( a ) \ + (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) ) + +#define ADD_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) ) +#define SUB_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) ) +#define MUL_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) ) +#define NEG_INT32( a ) \ + (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) ) + +#ifdef FT_INT64 + +#define ADD_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) ) +#define SUB_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) ) +#define MUL_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) ) +#define NEG_INT64( a ) \ + (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) ) + +#endif /* FT_INT64 */ + + +FT_END_HEADER + +#endif /* FTCALC_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftdebug.h b/vendor/freetype/include/freetype/internal/ftdebug.h new file mode 100644 index 0000000..4e013ba --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftdebug.h @@ -0,0 +1,442 @@ +/**************************************************************************** + * + * ftdebug.h + * + * Debugging and logging component (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + * + * IMPORTANT: A description of FreeType's debugging support can be + * found in 'docs/DEBUG.TXT'. Read it if you need to use or + * understand this code. + * + */ + + +#ifndef FTDEBUG_H_ +#define FTDEBUG_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +#include "compiler-macros.h" + +#ifdef FT_DEBUG_LOGGING +#define DLG_STATIC +#include +#include + +#include +#endif /* FT_DEBUG_LOGGING */ + + +FT_BEGIN_HEADER + + /* force the definition of FT_DEBUG_LEVEL_TRACE if FT_DEBUG_LOGGING is */ + /* already defined. */ + /* */ +#ifdef FT_DEBUG_LOGGING +#undef FT_DEBUG_LEVEL_TRACE +#define FT_DEBUG_LEVEL_TRACE +#endif + + /* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */ + /* is already defined; this simplifies the following #ifdefs */ + /* */ +#ifdef FT_DEBUG_LEVEL_TRACE +#undef FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_ERROR +#endif + + + /************************************************************************** + * + * Define the trace enums as well as the trace levels array when they are + * needed. + * + */ + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define FT_TRACE_DEF( x ) trace_ ## x , + + /* defining the enumeration */ + typedef enum FT_Trace_ + { +#include + trace_count + + } FT_Trace; + + + /* a pointer to the array of trace levels, */ + /* provided by `src/base/ftdebug.c' */ + extern int* ft_trace_levels; + +#undef FT_TRACE_DEF + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * Define the FT_TRACE macro + * + * IMPORTANT! + * + * Each component must define the macro FT_COMPONENT to a valid FT_Trace + * value before using any TRACE macro. + * + * To get consistent logging output, there should be no newline character + * (i.e., '\n') or a single trailing one in the message string of + * `FT_TRACEx` and `FT_ERROR`. + */ + + + /************************************************************************* + * + * If FT_DEBUG_LOGGING is enabled, tracing messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, tracing messages are sent to + * `FT_Message` (defined in ftdebug.c). + */ +#ifdef FT_DEBUG_LOGGING + + /* we need two macros to convert the names of `FT_COMPONENT` to a string */ +#define FT_LOGGING_TAG( x ) FT_LOGGING_TAG_( x ) +#define FT_LOGGING_TAG_( x ) #x + + /* we need two macros to convert the component and the trace level */ + /* to a string that combines them */ +#define FT_LOGGING_TAGX( x, y ) FT_LOGGING_TAGX_( x, y ) +#define FT_LOGGING_TAGX_( x, y ) #x ":" #y + + +#define FT_LOG( level, varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAGX( FT_COMPONENT, level ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ + { \ + if ( custom_output_handler != NULL ) \ + FT_Logging_Callback varformat; \ + else \ + dlg_trace varformat; \ + } \ + ft_remove_tag( dlg_tag ); \ + } while( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_LOG( level, varformat ) \ + do \ + { \ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ + FT_Message varformat; \ + } while ( 0 ) + +#endif /* !FT_DEBUG_LOGGING */ + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* we need two macros here to make cpp expand `FT_COMPONENT' */ +#define FT_TRACE_COMP( x ) FT_TRACE_COMP_( x ) +#define FT_TRACE_COMP_( x ) trace_ ## x + +#define FT_TRACE( level, varformat ) FT_LOG( level, varformat ) + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define FT_TRACE( level, varformat ) do { } while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * @function: + * FT_Trace_Get_Count + * + * @description: + * Return the number of available trace components. + * + * @return: + * The number of trace components. 0 if FreeType 2 is not built with + * FT_DEBUG_LEVEL_TRACE definition. + * + * @note: + * This function may be useful if you want to access elements of the + * internal trace levels array by an index. + */ + FT_BASE( FT_Int ) + FT_Trace_Get_Count( void ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Get_Name + * + * @description: + * Return the name of a trace component. + * + * @input: + * The index of the trace component. + * + * @return: + * The name of the trace component. This is a statically allocated + * C~string, so do not free it after use. `NULL` if FreeType is not + * built with FT_DEBUG_LEVEL_TRACE definition. + * + * @note: + * Use @FT_Trace_Get_Count to get the number of available trace + * components. + */ + FT_BASE( const char* ) + FT_Trace_Get_Name( FT_Int idx ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Disable + * + * @description: + * Switch off tracing temporarily. It can be activated again with + * @FT_Trace_Enable. + */ + FT_BASE( void ) + FT_Trace_Disable( void ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Enable + * + * @description: + * Activate tracing. Use it after tracing has been switched off with + * @FT_Trace_Disable. + */ + FT_BASE( void ) + FT_Trace_Enable( void ); + + + /************************************************************************** + * + * You need two opening and closing parentheses! + * + * Example: FT_TRACE0(( "Value is %i", foo )) + * + * Output of the FT_TRACEX macros is sent to stderr. + * + */ + +#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat ) +#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat ) +#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat ) +#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat ) +#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat ) +#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat ) +#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat ) +#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat ) + + + /************************************************************************** + * + * Define the FT_ERROR macro. + * + * Output of this macro is sent to stderr. + * + */ + +#ifdef FT_DEBUG_LEVEL_ERROR + + /************************************************************************** + * + * If FT_DEBUG_LOGGING is enabled, error messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, error messages are sent to `FT_Message` + * (defined in ftdebug.c). + * + */ +#ifdef FT_DEBUG_LOGGING + +#define FT_ERROR( varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAG( FT_COMPONENT ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + dlg_trace varformat; \ + ft_remove_tag( dlg_tag ); \ + } while ( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_ERROR( varformat ) FT_Message varformat + +#endif /* !FT_DEBUG_LOGGING */ + + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ERROR( varformat ) do { } while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /************************************************************************** + * + * Define the FT_ASSERT and FT_THROW macros. The call to `FT_Throw` makes + * it possible to easily set a breakpoint at this function. + * + */ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#define FT_ASSERT( condition ) \ + do \ + { \ + if ( !( condition ) ) \ + FT_Panic( "assertion failed on line %d of file %s\n", \ + __LINE__, __FILE__ ); \ + } while ( 0 ) + +#define FT_THROW( e ) \ + ( FT_Throw( FT_ERR_CAT( FT_ERR_PREFIX, e ), \ + __LINE__, \ + __FILE__ ) | \ + FT_ERR_CAT( FT_ERR_PREFIX, e ) ) + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ASSERT( condition ) do { } while ( 0 ) + +#define FT_THROW( e ) FT_ERR_CAT( FT_ERR_PREFIX, e ) + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /************************************************************************** + * + * Define `FT_Message` and `FT_Panic` when needed. + * + */ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#include "stdio.h" /* for vfprintf() */ + + /* print a message */ + FT_BASE( void ) + FT_Message( const char* fmt, + ... ); + + /* print a message and exit */ + FT_BASE( void ) + FT_Panic( const char* fmt, + ... ); + + /* report file name and line number of an error */ + FT_BASE( int ) + FT_Throw( FT_Error error, + int line, + const char* file ); + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + + FT_BASE( void ) + ft_debug_init( void ); + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * 'dlg' uses output handlers to control how and where log messages are + * printed. Therefore we need to define a default output handler for + * FreeType. + */ + FT_BASE( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ); + + + /************************************************************************** + * + * 1. `ft_default_log_handler` stores the function pointer that is used + * internally by FreeType to print logs to a file. + * + * 2. `custom_output_handler` stores the function pointer to the callback + * function provided by the user. + * + * It is defined in `ftdebug.c`. + */ + extern dlg_handler ft_default_log_handler; + extern FT_Custom_Log_Handler custom_output_handler; + + + /************************************************************************** + * + * If FT_DEBUG_LOGGING macro is enabled, FreeType needs to initialize and + * un-initialize `FILE*`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_logging_init( void ); + + FT_BASE( void ) + ft_logging_deinit( void ); + + + /************************************************************************** + * + * For printing the name of `FT_COMPONENT` along with the actual log we + * need to add a tag with the name of `FT_COMPONENT`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_add_tag( const char* tag ); + + FT_BASE( void ) + ft_remove_tag( const char* tag ); + + + /************************************************************************** + * + * A function to print log data using a custom callback logging function + * (which is set using `FT_Set_Log_Handler`). + * + * This function is defined in `ftdebug.c`. + */ + FT_BASE( void ) + FT_Logging_Callback( const char* fmt, + ... ); + +#endif /* FT_DEBUG_LOGGING */ + + +FT_END_HEADER + +#endif /* FTDEBUG_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftdrv.h b/vendor/freetype/include/freetype/internal/ftdrv.h new file mode 100644 index 0000000..9001c07 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftdrv.h @@ -0,0 +1,289 @@ +/**************************************************************************** + * + * ftdrv.h + * + * FreeType internal font driver interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTDRV_H_ +#define FTDRV_H_ + + +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + typedef FT_Error + (*FT_Face_InitFunc)( FT_Stream stream, + FT_Face face, + FT_Int typeface_index, + FT_Int num_params, + FT_Parameter* parameters ); + + typedef void + (*FT_Face_DoneFunc)( FT_Face face ); + + + typedef FT_Error + (*FT_Size_InitFunc)( FT_Size size ); + + typedef void + (*FT_Size_DoneFunc)( FT_Size size ); + + + typedef FT_Error + (*FT_Slot_InitFunc)( FT_GlyphSlot slot ); + + typedef void + (*FT_Slot_DoneFunc)( FT_GlyphSlot slot ); + + + typedef FT_Error + (*FT_Size_RequestFunc)( FT_Size size, + FT_Size_Request req ); + + typedef FT_Error + (*FT_Size_SelectFunc)( FT_Size size, + FT_ULong size_index ); + + typedef FT_Error + (*FT_Slot_LoadFunc)( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + typedef FT_Error + (*FT_Face_GetKerningFunc)( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ); + + + typedef FT_Error + (*FT_Face_AttachFunc)( FT_Face face, + FT_Stream stream ); + + + typedef FT_Error + (*FT_Face_GetAdvancesFunc)( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Int32 flags, + FT_Fixed* advances ); + + + /************************************************************************** + * + * @struct: + * FT_Driver_ClassRec + * + * @description: + * The font driver class. This structure mostly contains pointers to + * driver methods. + * + * @fields: + * root :: + * The parent module. + * + * face_object_size :: + * The size of a face object in bytes. + * + * size_object_size :: + * The size of a size object in bytes. + * + * slot_object_size :: + * The size of a glyph object in bytes. + * + * init_face :: + * The format-specific face constructor. + * + * done_face :: + * The format-specific face destructor. + * + * init_size :: + * The format-specific size constructor. + * + * done_size :: + * The format-specific size destructor. + * + * init_slot :: + * The format-specific slot constructor. + * + * done_slot :: + * The format-specific slot destructor. + * + * + * load_glyph :: + * A function handle to load a glyph to a slot. This field is + * mandatory! + * + * get_kerning :: + * A function handle to return the unscaled kerning for a given pair of + * glyphs. Can be set to 0 if the format doesn't support kerning. + * + * attach_file :: + * This function handle is used to read additional data for a face from + * another file/stream. For example, this can be used to add data from + * AFM or PFM files on a Type 1 face, or a CIDMap on a CID-keyed face. + * + * get_advances :: + * A function handle used to return advance widths of 'count' glyphs + * (in font units), starting at 'first'. The 'vertical' flag must be + * set to get vertical advance heights. The 'advances' buffer is + * caller-allocated. The idea of this function is to be able to + * perform device-independent text layout without loading a single + * glyph image. + * + * request_size :: + * A handle to a function used to request the new character size. Can + * be set to 0 if the scaling done in the base layer suffices. + * + * select_size :: + * A handle to a function used to select a new fixed size. It is used + * only if @FT_FACE_FLAG_FIXED_SIZES is set. Can be set to 0 if the + * scaling done in the base layer suffices. + * + * @note: + * Most function pointers, with the exception of `load_glyph`, can be set + * to 0 to indicate a default behaviour. + */ + typedef struct FT_Driver_ClassRec_ + { + FT_Module_Class root; + + FT_Long face_object_size; + FT_Long size_object_size; + FT_Long slot_object_size; + + FT_Face_InitFunc init_face; + FT_Face_DoneFunc done_face; + + FT_Size_InitFunc init_size; + FT_Size_DoneFunc done_size; + + FT_Slot_InitFunc init_slot; + FT_Slot_DoneFunc done_slot; + + FT_Slot_LoadFunc load_glyph; + + FT_Face_GetKerningFunc get_kerning; + FT_Face_AttachFunc attach_file; + FT_Face_GetAdvancesFunc get_advances; + + /* since version 2.2 */ + FT_Size_RequestFunc request_size; + FT_Size_SelectFunc select_size; + + } FT_Driver_ClassRec, *FT_Driver_Class; + + + /************************************************************************** + * + * @macro: + * FT_DECLARE_DRIVER + * + * @description: + * Used to create a forward declaration of an FT_Driver_ClassRec struct + * instance. + * + * @macro: + * FT_DEFINE_DRIVER + * + * @description: + * Used to initialize an instance of FT_Driver_ClassRec struct. + * + * `ftinit.c` (ft_create_default_module_classes) already contains a + * mechanism to call these functions for the default modules described in + * `ftmodule.h`. + * + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DECLARE_DRIVER( class_ ) \ + FT_CALLBACK_TABLE \ + const FT_Driver_ClassRec class_; + +#define FT_DEFINE_DRIVER( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_, \ + face_object_size_, \ + size_object_size_, \ + slot_object_size_, \ + init_face_, \ + done_face_, \ + init_size_, \ + done_size_, \ + init_slot_, \ + done_slot_, \ + load_glyph_, \ + get_kerning_, \ + attach_file_, \ + get_advances_, \ + request_size_, \ + select_size_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Driver_ClassRec class_ = \ + { \ + FT_DEFINE_ROOT_MODULE( flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + \ + face_object_size_, \ + size_object_size_, \ + slot_object_size_, \ + \ + init_face_, \ + done_face_, \ + \ + init_size_, \ + done_size_, \ + \ + init_slot_, \ + done_slot_, \ + \ + load_glyph_, \ + \ + get_kerning_, \ + attach_file_, \ + get_advances_, \ + \ + request_size_, \ + select_size_ \ + }; + + +FT_END_HEADER + +#endif /* FTDRV_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftgloadr.h b/vendor/freetype/include/freetype/internal/ftgloadr.h new file mode 100644 index 0000000..36e5509 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftgloadr.h @@ -0,0 +1,147 @@ +/**************************************************************************** + * + * ftgloadr.h + * + * The FreeType glyph loader (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGLOADR_H_ +#define FTGLOADR_H_ + + +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * FT_GlyphLoader + * + * @description: + * The glyph loader is an internal object used to load several glyphs + * together (for example, in the case of composites). + */ + typedef struct FT_SubGlyphRec_ + { + FT_Int index; + FT_UShort flags; + FT_Int arg1; + FT_Int arg2; + FT_Matrix transform; + + } FT_SubGlyphRec; + + + typedef struct FT_GlyphLoadRec_ + { + FT_Outline outline; /* outline */ + FT_Vector* extra_points; /* extra points table */ + FT_Vector* extra_points2; /* second extra points table */ + FT_UInt num_subglyphs; /* number of subglyphs */ + FT_SubGlyph subglyphs; /* subglyphs */ + + } FT_GlyphLoadRec, *FT_GlyphLoad; + + + typedef struct FT_GlyphLoaderRec_ + { + FT_Memory memory; + FT_UInt max_points; + FT_UInt max_contours; + FT_UInt max_subglyphs; + FT_Bool use_extra; + + FT_GlyphLoadRec base; + FT_GlyphLoadRec current; + + void* other; /* for possible future extension? */ + + } FT_GlyphLoaderRec, *FT_GlyphLoader; + + + /* create new empty glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ); + + /* add an extra points table to a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ); + + /* destroy a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ); + + /* reset a glyph loader (frees everything int it) */ + FT_BASE( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ); + + /* rewind a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ); + + /* check that there is enough space to add `n_points' and `n_contours' */ + /* to the glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ); + + +#define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ + ( (_count) == 0 || \ + ( (FT_UInt)(_loader)->base.outline.n_points + \ + (FT_UInt)(_loader)->current.outline.n_points + \ + (FT_UInt)(_count) ) <= (_loader)->max_points ) + +#define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ + ( (_count) == 0 || \ + ( (FT_UInt)(_loader)->base.outline.n_contours + \ + (FT_UInt)(_loader)->current.outline.n_contours + \ + (FT_UInt)(_count) ) <= (_loader)->max_contours ) + +#define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points, _contours ) \ + ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ + FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ + ? 0 \ + : FT_GlyphLoader_CheckPoints( (_loader), \ + (FT_UInt)(_points), \ + (FT_UInt)(_contours) ) ) + + + /* check that there is enough space to add `n_subs' sub-glyphs to */ + /* a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ); + + /* prepare a glyph loader, i.e. empty the current glyph */ + FT_BASE( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ); + + /* add the current glyph to the base glyph */ + FT_BASE( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ); + + +FT_END_HEADER + +#endif /* FTGLOADR_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/fthash.h b/vendor/freetype/include/freetype/internal/fthash.h new file mode 100644 index 0000000..622ec76 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/fthash.h @@ -0,0 +1,135 @@ +/**************************************************************************** + * + * fthash.h + * + * Hashing functions (specification). + * + */ + +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2015 + * Francesco Zappa Nardelli + * + * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is based on code from bdf.c,v 1.22 2000/03/16 20:08:50 + * + * taken from Mark Leisher's xmbdfed package + * + */ + + +#ifndef FTHASH_H_ +#define FTHASH_H_ + + +#include + + +FT_BEGIN_HEADER + + + typedef union FT_Hashkey_ + { + FT_Int num; + const char* str; + + } FT_Hashkey; + + + typedef struct FT_HashnodeRec_ + { + FT_Hashkey key; + size_t data; + + } FT_HashnodeRec; + + typedef struct FT_HashnodeRec_ *FT_Hashnode; + + + typedef FT_ULong + (*FT_Hash_LookupFunc)( FT_Hashkey* key ); + + typedef FT_Bool + (*FT_Hash_CompareFunc)( FT_Hashkey* a, + FT_Hashkey* b ); + + + typedef struct FT_HashRec_ + { + FT_UInt limit; + FT_UInt size; + FT_UInt used; + + FT_Hash_LookupFunc lookup; + FT_Hash_CompareFunc compare; + + FT_Hashnode* table; + + } FT_HashRec; + + typedef struct FT_HashRec_ *FT_Hash; + + + FT_Error + ft_hash_str_init( FT_Hash hash, + FT_Memory memory ); + + FT_Error + ft_hash_num_init( FT_Hash hash, + FT_Memory memory ); + + void + ft_hash_str_free( FT_Hash hash, + FT_Memory memory ); + +#define ft_hash_num_free ft_hash_str_free + + FT_Error + ft_hash_str_insert( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ); + + FT_Error + ft_hash_num_insert( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ); + + size_t* + ft_hash_str_lookup( const char* key, + FT_Hash hash ); + + size_t* + ft_hash_num_lookup( FT_Int num, + FT_Hash hash ); + + +FT_END_HEADER + + +#endif /* FTHASH_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftmemory.h b/vendor/freetype/include/freetype/internal/ftmemory.h new file mode 100644 index 0000000..5eb1d21 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftmemory.h @@ -0,0 +1,398 @@ +/**************************************************************************** + * + * ftmemory.h + * + * The FreeType memory management macros (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMEMORY_H_ +#define FTMEMORY_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @macro: + * FT_SET_ERROR + * + * @description: + * This macro is used to set an implicit 'error' variable to a given + * expression's value (usually a function call), and convert it to a + * boolean which is set whenever the value is != 0. + */ +#undef FT_SET_ERROR +#define FT_SET_ERROR( expression ) \ + ( ( error = (expression) ) != 0 ) + + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M E M O R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* The calculation `NULL + n' is undefined in C. Even if the resulting */ + /* pointer doesn't get dereferenced, this causes warnings with */ + /* sanitizers. */ + /* */ + /* We thus provide a macro that should be used if `base' can be NULL. */ +#define FT_OFFSET( base, count ) ( (base) ? (base) + (count) : NULL ) + + + /* + * C++ refuses to handle statements like p = (void*)anything, with `p' a + * typed pointer. Since we don't have a `typeof' operator in standard C++, + * we have to use a template to emulate it. + */ + +#ifdef __cplusplus + +extern "C++" +{ + template inline T* + cplusplus_typeof( T*, + void *v ) + { + return static_cast ( v ); + } +} + +#define FT_ASSIGNP( p, val ) (p) = cplusplus_typeof( (p), (val) ) + +#else + +#define FT_ASSIGNP( p, val ) (p) = (val) + +#endif + + + +#ifdef FT_DEBUG_MEMORY + + FT_BASE( const char* ) ft_debug_file_; + FT_BASE( long ) ft_debug_lineno_; + +#define FT_DEBUG_INNER( exp ) ( ft_debug_file_ = __FILE__, \ + ft_debug_lineno_ = __LINE__, \ + (exp) ) + +#define FT_ASSIGNP_INNER( p, exp ) ( ft_debug_file_ = __FILE__, \ + ft_debug_lineno_ = __LINE__, \ + FT_ASSIGNP( p, exp ) ) + +#else /* !FT_DEBUG_MEMORY */ + +#define FT_DEBUG_INNER( exp ) (exp) +#define FT_ASSIGNP_INNER( p, exp ) FT_ASSIGNP( p, exp ) + +#endif /* !FT_DEBUG_MEMORY */ + + + /* + * The allocation functions return a pointer, and the error code is written + * to through the `p_error' parameter. + */ + + /* The `q' variants of the functions below (`q' for `quick') don't fill */ + /* the allocated or reallocated memory with zero bytes. */ + + FT_BASE( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( void ) + ft_mem_free( FT_Memory memory, + const void* P ); + + + /* The `Q' variants of the macros below (`Q' for `quick') don't fill */ + /* the allocated or reallocated memory with zero bytes. */ + +#define FT_MEM_ALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_alloc( memory, \ + (FT_Long)(size), \ + &error ) ) + +#define FT_MEM_FREE( ptr ) \ + FT_BEGIN_STMNT \ + FT_DEBUG_INNER( ft_mem_free( memory, (ptr) ) ); \ + (ptr) = NULL; \ + FT_END_STMNT + +#define FT_MEM_NEW( ptr ) \ + FT_MEM_ALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_REALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + 1, \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_MEM_QALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qalloc( memory, \ + (FT_Long)(size), \ + &error ) ) + +#define FT_MEM_QNEW( ptr ) \ + FT_MEM_QALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_QREALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + 1, \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_MEM_ALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + (FT_Long)(item_size), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + (FT_Long)(itmsz), \ + (FT_Long)(oldcnt), \ + (FT_Long)(newcnt), \ + (ptr), \ + &error ) ) + +#define FT_MEM_QALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + (FT_Long)(item_size), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + (FT_Long)(itmsz), \ + (FT_Long)(oldcnt), \ + (FT_Long)(newcnt), \ + (ptr), \ + &error ) ) + + +#define FT_MEM_SET_ERROR( cond ) ( (cond), error != 0 ) + + +#define FT_MEM_SET( dest, byte, count ) \ + ft_memset( dest, byte, (FT_Offset)(count) ) + +#define FT_MEM_COPY( dest, source, count ) \ + ft_memcpy( dest, source, (FT_Offset)(count) ) + +#define FT_MEM_MOVE( dest, source, count ) \ + ft_memmove( dest, source, (FT_Offset)(count) ) + + +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) + +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) + + +#define FT_ARRAY_ZERO( dest, count ) \ + FT_MEM_ZERO( dest, \ + (FT_Offset)(count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_COPY( dest, source, count ) \ + FT_MEM_COPY( dest, \ + source, \ + (FT_Offset)(count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_MOVE( dest, source, count ) \ + FT_MEM_MOVE( dest, \ + source, \ + (FT_Offset)(count) * sizeof ( *(dest) ) ) + + + /* + * Return the maximum number of addressable elements in an array. We limit + * ourselves to INT_MAX, rather than UINT_MAX, to avoid any problems. + */ +#define FT_ARRAY_MAX( ptr ) ( FT_INT_MAX / sizeof ( *(ptr) ) ) + +#define FT_ARRAY_CHECK( ptr, count ) ( (count) <= FT_ARRAY_MAX( ptr ) ) + + + /************************************************************************** + * + * The following functions macros expect that their pointer argument is + * _typed_ in order to automatically compute array element sizes. + */ + +#define FT_MEM_NEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + sizeof ( *(ptr) ), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_RENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + sizeof ( *(ptr) ), \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_MEM_QNEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + sizeof ( *(ptr) ), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + sizeof ( *(ptr) ), \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_ALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC( ptr, size ) ) + +#define FT_REALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC( ptr, cursz, newsz ) ) + +#define FT_ALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC_MULT( ptr, count, item_size ) ) + +#define FT_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_QALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC( ptr, size ) ) + +#define FT_QREALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC( ptr, cursz, newsz ) ) + +#define FT_QALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC_MULT( ptr, count, item_size ) ) + +#define FT_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_FREE( ptr ) FT_MEM_FREE( ptr ) + +#define FT_NEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_NEW( ptr ) ) + +#define FT_NEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) + +#define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) + +#define FT_QNEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) + +#define FT_QNEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW_ARRAY( ptr, count ) ) + +#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_QRENEW_ARRAY( ptr, curcnt, newcnt ) ) + + + FT_BASE( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ); + + +#define FT_MEM_STRDUP( dst, str ) \ + (dst) = (char*)ft_mem_strdup( memory, (const char*)(str), &error ) + +#define FT_STRDUP( dst, str ) \ + FT_MEM_SET_ERROR( FT_MEM_STRDUP( dst, str ) ) + +#define FT_MEM_DUP( dst, address, size ) \ + (dst) = ft_mem_dup( memory, (address), (FT_ULong)(size), &error ) + +#define FT_DUP( dst, address, size ) \ + FT_MEM_SET_ERROR( FT_MEM_DUP( dst, address, size ) ) + + + /* Return >= 1 if a truncation occurs. */ + /* Return 0 if the source string fits the buffer. */ + /* This is *not* the same as strlcpy(). */ + FT_BASE( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ); + +#define FT_STRCPYN( dst, src, size ) \ + ft_mem_strcpyn( (char*)dst, (const char*)(src), (FT_ULong)(size) ) + + +FT_END_HEADER + +#endif /* FTMEMORY_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftmmtypes.h b/vendor/freetype/include/freetype/internal/ftmmtypes.h new file mode 100644 index 0000000..c4b21d6 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftmmtypes.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * ftmmtypes.h + * + * OpenType Variations type definitions for internal use + * with the multi-masters service (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and + * Dominik Röttsches. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMMTYPES_H_ +#define FTMMTYPES_H_ + +FT_BEGIN_HEADER + + + typedef FT_Int32 FT_ItemVarDelta; + + typedef struct GX_ItemVarDataRec_ + { + FT_UInt itemCount; /* Number of delta sets per item. */ + FT_UInt regionIdxCount; /* Number of region indices. */ + FT_UInt* regionIndices; /* Array of `regionCount` indices; */ + /* these index `varRegionList`. */ + FT_Byte* deltaSet; /* Array of `itemCount` deltas; */ + /* use `innerIndex` for this array. */ + FT_UShort wordDeltaCount; /* Number of the first 32-bit ints */ + /* or 16-bit ints of `deltaSet` */ + /* depending on `longWords`. */ + FT_Bool longWords; /* If true, `deltaSet` is a 32-bit */ + /* array followed by a 16-bit */ + /* array, otherwise a 16-bit array */ + /* followed by an 8-bit array. */ + } GX_ItemVarDataRec, *GX_ItemVarData; + + + /* contribution of one axis to a region */ + typedef struct GX_AxisCoordsRec_ + { + FT_Fixed startCoord; + FT_Fixed peakCoord; /* zero means no effect (factor = 1) */ + FT_Fixed endCoord; + + } GX_AxisCoordsRec, *GX_AxisCoords; + + + typedef struct GX_VarRegionRec_ + { + GX_AxisCoords axisList; /* array of axisCount records */ + + } GX_VarRegionRec, *GX_VarRegion; + + + /* item variation store */ + typedef struct GX_ItemVarStoreRec_ + { + FT_UInt dataCount; + GX_ItemVarData varData; /* array of dataCount records; */ + /* use `outerIndex' for this array */ + FT_UShort axisCount; + FT_UInt regionCount; /* total number of regions defined */ + GX_VarRegion varRegionList; + + } GX_ItemVarStoreRec, *GX_ItemVarStore; + + + typedef struct GX_DeltaSetIdxMapRec_ + { + FT_ULong mapCount; + FT_UInt* outerIndex; /* indices to item var data */ + FT_UInt* innerIndex; /* indices to delta set */ + + } GX_DeltaSetIdxMapRec, *GX_DeltaSetIdxMap; + + +FT_END_HEADER + +#endif /* FTMMTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftobjs.h b/vendor/freetype/include/freetype/internal/ftobjs.h new file mode 100644 index 0000000..28bc9b6 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftobjs.h @@ -0,0 +1,1238 @@ +/**************************************************************************** + * + * ftobjs.h + * + * The FreeType private base classes (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file contains the definition of all internal FreeType classes. + * + */ + + +#ifndef FTOBJS_H_ +#define FTOBJS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef FT_CONFIG_OPTION_INCREMENTAL +#include +#endif + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * Some generic definitions. + */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + + + /************************************************************************** + * + * The min and max functions missing in C. As usual, be careful not to + * write things like FT_MIN( a++, b++ ) to avoid side effects. + */ +#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) + +#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + + /* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' algorithm. + * We use alpha = 1, beta = 3/8, giving us results with a largest error + * less than 7% compared to the exact value. + */ +#define FT_HYPOT( x, y ) \ + ( x = FT_ABS( x ), \ + y = FT_ABS( y ), \ + x > y ? x + ( 3 * y >> 3 ) \ + : y + ( 3 * x >> 3 ) ) + + /* we use FT_TYPEOF to suppress signedness compilation warnings */ +#define FT_PAD_FLOOR( x, n ) ( (x) & ~FT_TYPEOF( x )( (n) - 1 ) ) +#define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + (n) / 2, n ) +#define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + (n) - 1, n ) + +#define FT_PIX_FLOOR( x ) ( (x) & ~FT_TYPEOF( x )63 ) +#define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) +#define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) + + /* specialized versions (for signed values) */ + /* that don't produce run-time errors due to integer overflow */ +#define FT_PAD_ROUND_LONG( x, n ) FT_PAD_FLOOR( ADD_LONG( (x), (n) / 2 ), \ + n ) +#define FT_PAD_CEIL_LONG( x, n ) FT_PAD_FLOOR( ADD_LONG( (x), (n) - 1 ), \ + n ) +#define FT_PIX_ROUND_LONG( x ) FT_PIX_FLOOR( ADD_LONG( (x), 32 ) ) +#define FT_PIX_CEIL_LONG( x ) FT_PIX_FLOOR( ADD_LONG( (x), 63 ) ) + +#define FT_PAD_ROUND_INT32( x, n ) FT_PAD_FLOOR( ADD_INT32( (x), (n) / 2 ), \ + n ) +#define FT_PAD_CEIL_INT32( x, n ) FT_PAD_FLOOR( ADD_INT32( (x), (n) - 1 ), \ + n ) +#define FT_PIX_ROUND_INT32( x ) FT_PIX_FLOOR( ADD_INT32( (x), 32 ) ) +#define FT_PIX_CEIL_INT32( x ) FT_PIX_FLOOR( ADD_INT32( (x), 63 ) ) + + + /* + * character classification functions -- since these are used to parse font + * files, we must not use those in which are locale-dependent + */ +#define ft_isdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U ) + +#define ft_isxdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U || \ + ( (unsigned)(x) - 'a' ) < 6U || \ + ( (unsigned)(x) - 'A' ) < 6U ) + + /* the next two macros assume ASCII representation */ +#define ft_isupper( x ) ( ( (unsigned)(x) - 'A' ) < 26U ) +#define ft_islower( x ) ( ( (unsigned)(x) - 'a' ) < 26U ) + +#define ft_isalpha( x ) ( ft_isupper( x ) || ft_islower( x ) ) +#define ft_isalnum( x ) ( ft_isdigit( x ) || ft_isalpha( x ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** C H A R M A P S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to internal charmap object */ + typedef struct FT_CMapRec_* FT_CMap; + + /* handle to charmap class structure */ + typedef const struct FT_CMap_ClassRec_* FT_CMap_Class; + + /* internal charmap object structure */ + typedef struct FT_CMapRec_ + { + FT_CharMapRec charmap; + FT_CMap_Class clazz; + + } FT_CMapRec; + + /* typecast any pointer to a charmap handle */ +#define FT_CMAP( x ) ( (FT_CMap)( x ) ) + + /* obvious macros */ +#define FT_CMAP_PLATFORM_ID( x ) FT_CMAP( x )->charmap.platform_id +#define FT_CMAP_ENCODING_ID( x ) FT_CMAP( x )->charmap.encoding_id +#define FT_CMAP_ENCODING( x ) FT_CMAP( x )->charmap.encoding +#define FT_CMAP_FACE( x ) FT_CMAP( x )->charmap.face + + + /* class method definitions */ + typedef FT_Error + (*FT_CMap_InitFunc)( FT_CMap cmap, + FT_Pointer init_data ); + + typedef void + (*FT_CMap_DoneFunc)( FT_CMap cmap ); + + typedef FT_UInt + (*FT_CMap_CharIndexFunc)( FT_CMap cmap, + FT_UInt32 char_code ); + + typedef FT_UInt + (*FT_CMap_CharNextFunc)( FT_CMap cmap, + FT_UInt32 *achar_code ); + + typedef FT_UInt + (*FT_CMap_CharVarIndexFunc)( FT_CMap cmap, + FT_CMap unicode_cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + + typedef FT_Int + (*FT_CMap_CharVarIsDefaultFunc)( FT_CMap cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + + typedef FT_UInt32 * + (*FT_CMap_VariantListFunc)( FT_CMap cmap, + FT_Memory mem ); + + typedef FT_UInt32 * + (*FT_CMap_CharVariantListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 char_code ); + + typedef FT_UInt32 * + (*FT_CMap_VariantCharListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 variant_selector ); + + + typedef struct FT_CMap_ClassRec_ + { + FT_ULong size; + + FT_CMap_InitFunc init; + FT_CMap_DoneFunc done; + FT_CMap_CharIndexFunc char_index; + FT_CMap_CharNextFunc char_next; + + /* Subsequent entries are special ones for format 14 -- the variant */ + /* selector subtable which behaves like no other */ + + FT_CMap_CharVarIndexFunc char_var_index; + FT_CMap_CharVarIsDefaultFunc char_var_default; + FT_CMap_VariantListFunc variant_list; + FT_CMap_CharVariantListFunc charvariant_list; + FT_CMap_VariantCharListFunc variantchar_list; + + } FT_CMap_ClassRec; + + +#define FT_DECLARE_CMAP_CLASS( class_ ) \ + FT_CALLBACK_TABLE const FT_CMap_ClassRec class_; + +#define FT_DEFINE_CMAP_CLASS( \ + class_, \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_CMap_ClassRec class_ = \ + { \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ \ + }; + + + /* create a new charmap and add it to charmap->face */ + FT_BASE( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ); + + /* destroy a charmap and remove it from face's list */ + FT_BASE( void ) + FT_CMap_Done( FT_CMap cmap ); + + + /* add LCD padding to CBox */ + FT_BASE( void ) + ft_lcd_padding( FT_BBox* cbox, + FT_GlyphSlot slot, + FT_Render_Mode mode ); + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, + FT_Byte* weights ); + + + /* This is the default LCD filter, an in-place, 5-tap FIR filter. */ + FT_BASE( void ) + ft_lcd_filter_fir( FT_Bitmap* bitmap, + FT_LcdFiveTapFilter weights ); + +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /************************************************************************** + * + * @struct: + * FT_Face_InternalRec + * + * @description: + * This structure contains the internal fields of each FT_Face object. + * These fields may change between different releases of FreeType. + * + * @fields: + * max_points :: + * The maximum number of points used to store the vectorial outline of + * any glyph in this face. If this value cannot be known in advance, + * or if the face isn't scalable, this should be set to 0. Only + * relevant for scalable formats. + * + * max_contours :: + * The maximum number of contours used to store the vectorial outline + * of any glyph in this face. If this value cannot be known in + * advance, or if the face isn't scalable, this should be set to 0. + * Only relevant for scalable formats. + * + * transform_matrix :: + * A 2x2 matrix of 16.16 coefficients used to transform glyph outlines + * after they are loaded from the font. Only used by the convenience + * functions. + * + * transform_delta :: + * A translation vector used to transform glyph outlines after they are + * loaded from the font. Only used by the convenience functions. + * + * transform_flags :: + * Some flags used to classify the transform. Only used by the + * convenience functions. + * + * services :: + * A cache for frequently used services. It should be only accessed + * with the macro `FT_FACE_LOOKUP_SERVICE`. + * + * incremental_interface :: + * If non-null, the interface through which glyph data and metrics are + * loaded incrementally for faces that do not provide all of this data + * when first opened. This field exists only if + * @FT_CONFIG_OPTION_INCREMENTAL is defined. + * + * no_stem_darkening :: + * Overrides the module-level default, see @stem-darkening[cff], for + * example. FALSE and TRUE toggle stem darkening on and off, + * respectively, value~-1 means to use the module/driver default. + * + * random_seed :: + * If positive, override the seed value for the CFF 'random' operator. + * Value~0 means to use the font's value. Value~-1 means to use the + * CFF driver's default. + * + * lcd_weights :: + * lcd_filter_func :: + * These fields specify the LCD filtering weights and callback function + * for ClearType-style subpixel rendering. + * + * refcount :: + * A counter initialized to~1 at the time an @FT_Face structure is + * created. @FT_Reference_Face increments this counter, and + * @FT_Done_Face only destroys a face if the counter is~1, otherwise it + * simply decrements it. + */ + typedef struct FT_Face_InternalRec_ + { + FT_Matrix transform_matrix; + FT_Vector transform_delta; + FT_Int transform_flags; + + FT_ServiceCacheRec services; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec* incremental_interface; +#endif + + FT_Char no_stem_darkening; + FT_Int32 random_seed; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ +#endif + + FT_Int refcount; + + } FT_Face_InternalRec; + + + /************************************************************************** + * + * @struct: + * FT_Slot_InternalRec + * + * @description: + * This structure contains the internal fields of each FT_GlyphSlot + * object. These fields may change between different releases of + * FreeType. + * + * @fields: + * loader :: + * The glyph loader object used to load outlines into the glyph slot. + * + * flags :: + * Possible values are zero or FT_GLYPH_OWN_BITMAP. The latter + * indicates that the FT_GlyphSlot structure owns the bitmap buffer. + * + * glyph_transformed :: + * Boolean. Set to TRUE when the loaded glyph must be transformed + * through a specific font transformation. This is _not_ the same as + * the face transform set through FT_Set_Transform(). + * + * glyph_matrix :: + * The 2x2 matrix corresponding to the glyph transformation, if + * necessary. + * + * glyph_delta :: + * The 2d translation vector corresponding to the glyph transformation, + * if necessary. + * + * glyph_hints :: + * Format-specific glyph hints management. + * + * load_flags :: + * The load flags passed as an argument to @FT_Load_Glyph while + * initializing the glyph slot. + */ + +#define FT_GLYPH_OWN_BITMAP 0x1U +#define FT_GLYPH_OWN_GZIP_SVG 0x2U + + typedef struct FT_Slot_InternalRec_ + { + FT_GlyphLoader loader; + FT_UInt flags; + FT_Bool glyph_transformed; + FT_Matrix glyph_matrix; + FT_Vector glyph_delta; + void* glyph_hints; + + FT_Int32 load_flags; + + } FT_GlyphSlot_InternalRec; + + + /************************************************************************** + * + * @struct: + * FT_Size_InternalRec + * + * @description: + * This structure contains the internal fields of each FT_Size object. + * + * @fields: + * module_data :: + * Data specific to a driver module. + * + * autohint_mode :: + * The used auto-hinting mode. + * + * autohint_metrics :: + * Metrics used by the auto-hinter. + * + */ + + typedef struct FT_Size_InternalRec_ + { + void* module_data; + + FT_Render_Mode autohint_mode; + FT_Size_Metrics autohint_metrics; + + } FT_Size_InternalRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * FT_ModuleRec + * + * @description: + * A module object instance. + * + * @fields: + * clazz :: + * A pointer to the module's class. + * + * library :: + * A handle to the parent library object. + * + * memory :: + * A handle to the memory manager. + */ + typedef struct FT_ModuleRec_ + { + FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; + + } FT_ModuleRec; + + + /* typecast an object to an FT_Module */ +#define FT_MODULE( x ) ( (FT_Module)(x) ) + +#define FT_MODULE_CLASS( x ) FT_MODULE( x )->clazz +#define FT_MODULE_LIBRARY( x ) FT_MODULE( x )->library +#define FT_MODULE_MEMORY( x ) FT_MODULE( x )->memory + + +#define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_FONT_DRIVER ) + +#define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_RENDERER ) + +#define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_HINTER ) + +#define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_STYLER ) + +#define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_SCALABLE ) + +#define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_NO_OUTLINES ) + +#define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_HAS_HINTER ) + +#define FT_DRIVER_HINTS_LIGHTLY( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_HINTS_LIGHTLY ) + + + /************************************************************************** + * + * @function: + * FT_Get_Module_Interface + * + * @description: + * Finds a module and returns its specific interface as a typeless + * pointer. + * + * @input: + * library :: + * A handle to the library object. + * + * module_name :: + * The module's name (as an ASCII string). + * + * @return: + * A module-specific interface if available, 0 otherwise. + * + * @note: + * You should better be familiar with FreeType internals to know which + * module to look for, and what its interface is :-) + */ + FT_BASE( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ); + + FT_BASE( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id, + FT_Bool global ); + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_BASE( FT_Error ) + ft_property_string_set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + FT_String* value ); +#endif + + /* */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E, S I Z E & G L Y P H S L O T O B J E C T S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* a few macros used to perform easy typecasts with minimal brain damage */ + +#define FT_FACE( x ) ( (FT_Face)(x) ) +#define FT_SIZE( x ) ( (FT_Size)(x) ) +#define FT_SLOT( x ) ( (FT_GlyphSlot)(x) ) + +#define FT_FACE_DRIVER( x ) FT_FACE( x )->driver +#define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library +#define FT_FACE_MEMORY( x ) FT_FACE( x )->memory +#define FT_FACE_STREAM( x ) FT_FACE( x )->stream + +#define FT_SIZE_FACE( x ) FT_SIZE( x )->face +#define FT_SLOT_FACE( x ) FT_SLOT( x )->face + +#define FT_FACE_SLOT( x ) FT_FACE( x )->glyph +#define FT_FACE_SIZE( x ) FT_FACE( x )->size + + + /************************************************************************** + * + * @function: + * FT_New_GlyphSlot + * + * @description: + * It is sometimes useful to have more than one glyph slot for a given + * face object. This function is used to create additional slots. All + * of them are automatically discarded when the face is destroyed. + * + * @input: + * face :: + * A handle to a parent face object. + * + * @output: + * aslot :: + * A handle to a new glyph slot object. + * + * @return: + * FreeType error code. 0 means success. + */ + FT_BASE( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ); + + + /************************************************************************** + * + * @function: + * FT_Done_GlyphSlot + * + * @description: + * Destroys a given glyph slot. Remember however that all slots are + * automatically destroyed with its parent. Using this function is not + * always mandatory. + * + * @input: + * slot :: + * A handle to a target glyph slot. + */ + FT_BASE( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ); + + /* */ + +#define FT_REQUEST_WIDTH( req ) \ + ( (req)->horiResolution \ + ? ( (req)->width * (FT_Pos)(req)->horiResolution + 36 ) / 72 \ + : (req)->width ) + +#define FT_REQUEST_HEIGHT( req ) \ + ( (req)->vertResolution \ + ? ( (req)->height * (FT_Pos)(req)->vertResolution + 36 ) / 72 \ + : (req)->height ) + + + /* Set the metrics according to a bitmap strike. */ + FT_BASE( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ); + + + /* Set the metrics according to a size request. */ + FT_BASE( FT_Error ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ); + + + /* Match a size request against `available_sizes'. */ + FT_BASE( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ); + + + /* Use the horizontal metrics to synthesize the vertical metrics. */ + /* If `advance' is zero, it is also synthesized. */ + FT_BASE( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ); + + + /* Free the bitmap of a given glyphslot when needed (i.e., only when it */ + /* was allocated with ft_glyphslot_alloc_bitmap). */ + FT_BASE( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ); + + + /* Preset bitmap metrics of an outline glyphslot prior to rendering */ + /* and check whether the truncated bbox is too large for rendering. */ + FT_BASE( FT_Bool ) + ft_glyphslot_preset_bitmap( FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ); + + /* Allocate a new bitmap buffer in a glyph slot. */ + FT_BASE( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ); + + + /* Set the bitmap buffer in a glyph slot to a given pointer. The buffer */ + /* will not be freed by a later call to ft_glyphslot_free_bitmap. */ + FT_BASE( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define FT_RENDERER( x ) ( (FT_Renderer)(x) ) +#define FT_GLYPH( x ) ( (FT_Glyph)(x) ) +#define FT_BITMAP_GLYPH( x ) ( (FT_BitmapGlyph)(x) ) +#define FT_OUTLINE_GLYPH( x ) ( (FT_OutlineGlyph)(x) ) + + + typedef struct FT_RendererRec_ + { + FT_ModuleRec root; + FT_Renderer_Class* clazz; + FT_Glyph_Format glyph_format; + FT_Glyph_Class glyph_class; + + FT_Raster raster; + FT_Raster_Render_Func raster_render; + FT_Renderer_RenderFunc render; + + } FT_RendererRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F O N T D R I V E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* typecast a module into a driver easily */ +#define FT_DRIVER( x ) ( (FT_Driver)(x) ) + + /* typecast a module as a driver, and get its driver class */ +#define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz + + + /************************************************************************** + * + * @struct: + * FT_DriverRec + * + * @description: + * The root font driver class. A font driver is responsible for managing + * and loading font files of a given format. + * + * @fields: + * root :: + * Contains the fields of the root module class. + * + * clazz :: + * A pointer to the font driver's class. Note that this is NOT + * root.clazz. 'class' wasn't used as it is a reserved word in C++. + * + * faces_list :: + * The list of faces currently opened by this driver. + * + * glyph_loader :: + * Unused. Used to be glyph loader for all faces managed by this + * driver. + */ + typedef struct FT_DriverRec_ + { + FT_ModuleRec root; + FT_Driver_Class clazz; + FT_ListRec faces_list; + FT_GlyphLoader glyph_loader; + + } FT_DriverRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R I E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * FT_LibraryRec + * + * @description: + * The FreeType library class. This is the root of all FreeType data. + * Use FT_New_Library() to create a library object, and FT_Done_Library() + * to discard it and all child objects. + * + * @fields: + * memory :: + * The library's memory object. Manages memory allocation. + * + * version_major :: + * The major version number of the library. + * + * version_minor :: + * The minor version number of the library. + * + * version_patch :: + * The current patch level of the library. + * + * num_modules :: + * The number of modules currently registered within this library. + * This is set to 0 for new libraries. New modules are added through + * the FT_Add_Module() API function. + * + * modules :: + * A table used to store handles to the currently registered + * modules. Note that each font driver contains a list of its opened + * faces. + * + * renderers :: + * The list of renderers currently registered within the library. + * + * cur_renderer :: + * The current outline renderer. This is a shortcut used to avoid + * parsing the list on each call to FT_Outline_Render(). It is a + * handle to the current renderer for the FT_GLYPH_FORMAT_OUTLINE + * format. + * + * auto_hinter :: + * The auto-hinter module interface. + * + * debug_hooks :: + * An array of four function pointers that allow debuggers to hook into + * a font format's interpreter. Currently, only the TrueType bytecode + * debugger uses this. + * + * lcd_weights :: + * The LCD filter weights for ClearType-style subpixel rendering. + * + * lcd_filter_func :: + * The LCD filtering callback function for for ClearType-style subpixel + * rendering. + * + * lcd_geometry :: + * This array specifies LCD subpixel geometry and controls Harmony LCD + * rendering technique, alternative to ClearType. + * + * pic_container :: + * Contains global structs and tables, instead of defining them + * globally. + * + * refcount :: + * A counter initialized to~1 at the time an @FT_Library structure is + * created. @FT_Reference_Library increments this counter, and + * @FT_Done_Library only destroys a library if the counter is~1, + * otherwise it simply decrements it. + */ + typedef struct FT_LibraryRec_ + { + FT_Memory memory; /* library's memory manager */ + + FT_Int version_major; + FT_Int version_minor; + FT_Int version_patch; + + FT_UInt num_modules; + FT_Module modules[FT_MAX_MODULES]; /* module objects */ + + FT_ListRec renderers; /* list of renderers */ + FT_Renderer cur_renderer; /* current outline renderer */ + FT_Module auto_hinter; + + FT_DebugHook_Func debug_hooks[4]; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ +#else + FT_Vector lcd_geometry[3]; /* RGB subpixel positions */ +#endif + + FT_Int refcount; + + } FT_LibraryRec; + + + FT_BASE( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ); + + FT_BASE( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + typedef const char* + (*FT_Face_GetPostscriptNameFunc)( FT_Face face ); + + typedef FT_Error + (*FT_Face_GetGlyphNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_Face_GetGlyphNameIndexFunc)( FT_Face face, + const FT_String* glyph_name ); + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /************************************************************************** + * + * @function: + * FT_New_Memory + * + * @description: + * Creates a new memory object. + * + * @return: + * A pointer to the new memory object. 0 in case of error. + */ + FT_BASE( FT_Memory ) + FT_New_Memory( void ); + + + /************************************************************************** + * + * @function: + * FT_Done_Memory + * + * @description: + * Discards memory manager. + * + * @input: + * memory :: + * A handle to the memory manager. + */ + FT_BASE( void ) + FT_Done_Memory( FT_Memory memory ); + +#endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* Define default raster's interface. The default raster is located in */ + /* `src/base/ftraster.c'. */ + /* */ + /* Client applications can register new rasters through the */ + /* FT_Set_Raster() API. */ + +#ifndef FT_NO_DEFAULT_RASTER + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster; +#endif + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_OUTLINE_FUNCS + * + * @description: + * Used to initialize an instance of FT_Outline_Funcs struct. The struct + * will be allocated in the global scope (or the scope where the macro is + * used). + */ +#define FT_DEFINE_OUTLINE_FUNCS( \ + class_, \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ ) \ + static const FT_Outline_Funcs class_ = \ + { \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ \ + }; + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_RASTER_FUNCS + * + * @description: + * Used to initialize an instance of FT_Raster_Funcs struct. The struct + * will be allocated in the global scope (or the scope where the macro is + * used). + */ +#define FT_DEFINE_RASTER_FUNCS( \ + class_, \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; + + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_GLYPH + * + * @description: + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DECLARE_GLYPH( class_ ) \ + FT_CALLBACK_TABLE const FT_Glyph_Class class_; + +#define FT_DEFINE_GLYPH( \ + class_, \ + size_, \ + format_, \ + init_, \ + done_, \ + copy_, \ + transform_, \ + bbox_, \ + prepare_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Glyph_Class class_ = \ + { \ + size_, \ + format_, \ + init_, \ + done_, \ + copy_, \ + transform_, \ + bbox_, \ + prepare_ \ + }; + + + /************************************************************************** + * + * @macro: + * FT_DECLARE_RENDERER + * + * @description: + * Used to create a forward declaration of a FT_Renderer_Class struct + * instance. + * + * @macro: + * FT_DEFINE_RENDERER + * + * @description: + * Used to initialize an instance of FT_Renderer_Class struct. + * + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DECLARE_RENDERER( class_ ) \ + FT_EXPORT_VAR( const FT_Renderer_Class ) class_; + +#define FT_DEFINE_RENDERER( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_, \ + glyph_format_, \ + render_glyph_, \ + transform_glyph_, \ + get_glyph_cbox_, \ + set_mode_, \ + raster_class_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Renderer_Class class_ = \ + { \ + FT_DEFINE_ROOT_MODULE( flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + glyph_format_, \ + \ + render_glyph_, \ + transform_glyph_, \ + get_glyph_cbox_, \ + set_mode_, \ + \ + raster_class_ \ + }; + + + /************************************************************************** + * + * @macro: + * FT_DECLARE_MODULE + * + * @description: + * Used to create a forward declaration of a FT_Module_Class struct + * instance. + * + * @macro: + * FT_DEFINE_MODULE + * + * @description: + * Used to initialize an instance of an FT_Module_Class struct. + * + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + * + * @macro: + * FT_DEFINE_ROOT_MODULE + * + * @description: + * Used to initialize an instance of an FT_Module_Class struct inside + * another struct that contains it or in a function that initializes that + * containing struct. + */ +#define FT_DECLARE_MODULE( class_ ) \ + FT_CALLBACK_TABLE \ + const FT_Module_Class class_; + +#define FT_DEFINE_ROOT_MODULE( \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }, + +#define FT_DEFINE_MODULE( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Module_Class class_ = \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }; + + +FT_END_HEADER + +#endif /* FTOBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftpsprop.h b/vendor/freetype/include/freetype/internal/ftpsprop.h new file mode 100644 index 0000000..1d5b287 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftpsprop.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * ftpsprop.h + * + * Get and set properties of PostScript drivers (specification). + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTPSPROP_H_ +#define FTPSPROP_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_BASE_CALLBACK( FT_Error ) + ps_property_set( FT_Module module, /* PS_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ); + + FT_BASE_CALLBACK( FT_Error ) + ps_property_get( FT_Module module, /* PS_Driver */ + const char* property_name, + void* value ); + + +FT_END_HEADER + + +#endif /* FTPSPROP_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftrfork.h b/vendor/freetype/include/freetype/internal/ftrfork.h new file mode 100644 index 0000000..e964599 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftrfork.h @@ -0,0 +1,245 @@ +/**************************************************************************** + * + * ftrfork.h + * + * Embedded resource forks accessor (specification). + * + * Copyright (C) 2004-2023 by + * Masatake YAMATO and Redhat K.K. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * Development of the code in this file is support of + * Information-technology Promotion Agency, Japan. + */ + + +#ifndef FTRFORK_H_ +#define FTRFORK_H_ + + +#include + + +FT_BEGIN_HEADER + + + /* Number of guessing rules supported in `FT_Raccess_Guess'. */ + /* Don't forget to increment the number if you add a new guessing rule. */ +#define FT_RACCESS_N_RULES 9 + + + /* A structure to describe a reference in a resource by its resource ID */ + /* and internal offset. The `POST' resource expects to be concatenated */ + /* by the order of resource IDs instead of its appearance in the file. */ + + typedef struct FT_RFork_Ref_ + { + FT_Short res_id; + FT_Long offset; + + } FT_RFork_Ref; + + +#ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK + typedef FT_Error + (*ft_raccess_guess_func)( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + typedef enum FT_RFork_Rule_ { + FT_RFork_Rule_invalid = -2, + FT_RFork_Rule_uknown, /* -1 */ + FT_RFork_Rule_apple_double, + FT_RFork_Rule_apple_single, + FT_RFork_Rule_darwin_ufs_export, + FT_RFork_Rule_darwin_newvfs, + FT_RFork_Rule_darwin_hfsplus, + FT_RFork_Rule_vfat, + FT_RFork_Rule_linux_cap, + FT_RFork_Rule_linux_double, + FT_RFork_Rule_linux_netatalk + } FT_RFork_Rule; + + /* For fast translation between rule index and rule type, + * the macros FT_RFORK_xxx should be kept consistent with the + * raccess_guess_funcs table + */ + typedef struct ft_raccess_guess_rec_ { + ft_raccess_guess_func func; + FT_RFork_Rule type; + } ft_raccess_guess_rec; + + +#define CONST_FT_RFORK_RULE_ARRAY_BEGIN( name, type ) \ + static const type name[] = { +#define CONST_FT_RFORK_RULE_ARRAY_ENTRY( func_suffix, type_suffix ) \ + { raccess_guess_ ## func_suffix, \ + FT_RFork_Rule_ ## type_suffix }, + /* this array is a storage, thus a final `;' is needed */ +#define CONST_FT_RFORK_RULE_ARRAY_END }; + +#endif /* FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + + /************************************************************************** + * + * @function: + * FT_Raccess_Guess + * + * @description: + * Guess a file name and offset where the actual resource fork is stored. + * The macro FT_RACCESS_N_RULES holds the number of guessing rules; the + * guessed result for the Nth rule is represented as a triplet: a new + * file name (new_names[N]), a file offset (offsets[N]), and an error + * code (errors[N]). + * + * @input: + * library :: + * A FreeType library instance. + * + * stream :: + * A file stream containing the resource fork. + * + * base_name :: + * The (base) file name of the resource fork used for some guessing + * rules. + * + * @output: + * new_names :: + * An array of guessed file names in which the resource forks may + * exist. If 'new_names[N]' is `NULL`, the guessed file name is equal + * to `base_name`. + * + * offsets :: + * An array of guessed file offsets. 'offsets[N]' holds the file + * offset of the possible start of the resource fork in file + * 'new_names[N]'. + * + * errors :: + * An array of FreeType error codes. 'errors[N]' is the error code of + * Nth guessing rule function. If 'errors[N]' is not FT_Err_Ok, + * 'new_names[N]' and 'offsets[N]' are meaningless. + */ + FT_BASE( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char** new_names, + FT_Long* offsets, + FT_Error* errors ); + + + /************************************************************************** + * + * @function: + * FT_Raccess_Get_HeaderInfo + * + * @description: + * Get the information from the header of resource fork. The information + * includes the file offset where the resource map starts, and the file + * offset where the resource data starts. `FT_Raccess_Get_DataOffsets` + * requires these two data. + * + * @input: + * library :: + * A FreeType library instance. + * + * stream :: + * A file stream containing the resource fork. + * + * rfork_offset :: + * The file offset where the resource fork starts. + * + * @output: + * map_offset :: + * The file offset where the resource map starts. + * + * rdata_pos :: + * The file offset where the resource data starts. + * + * @return: + * FreeType error code. FT_Err_Ok means success. + */ + FT_BASE( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ); + + + /************************************************************************** + * + * @function: + * FT_Raccess_Get_DataOffsets + * + * @description: + * Get the data offsets for a tag in a resource fork. Offsets are stored + * in an array because, in some cases, resources in a resource fork have + * the same tag. + * + * @input: + * library :: + * A FreeType library instance. + * + * stream :: + * A file stream containing the resource fork. + * + * map_offset :: + * The file offset where the resource map starts. + * + * rdata_pos :: + * The file offset where the resource data starts. + * + * tag :: + * The resource tag. + * + * sort_by_res_id :: + * A Boolean to sort the fragmented resource by their ids. The + * fragmented resources for 'POST' resource should be sorted to restore + * Type1 font properly. For 'sfnt' resources, sorting may induce a + * different order of the faces in comparison to that by QuickDraw API. + * + * @output: + * offsets :: + * The stream offsets for the resource data specified by 'tag'. This + * array is allocated by the function, so you have to call @ft_mem_free + * after use. + * + * count :: + * The length of offsets array. + * + * @return: + * FreeType error code. FT_Err_Ok means success. + * + * @note: + * Normally you should use `FT_Raccess_Get_HeaderInfo` to get the value + * for `map_offset` and `rdata_pos`. + */ + FT_BASE( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Bool sort_by_res_id, + FT_Long **offsets, + FT_Long *count ); + + +FT_END_HEADER + +#endif /* FTRFORK_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftserv.h b/vendor/freetype/include/freetype/internal/ftserv.h new file mode 100644 index 0000000..1e85d6d --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftserv.h @@ -0,0 +1,495 @@ +/**************************************************************************** + * + * ftserv.h + * + * The FreeType services (specification only). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * Each module can export one or more 'services'. Each service is + * identified by a constant string and modeled by a pointer; the latter + * generally corresponds to a structure containing function pointers. + * + * Note that a service's data cannot be a mere function pointer because in + * C it is possible that function pointers might be implemented differently + * than data pointers (e.g. 48 bits instead of 32). + * + */ + + +#ifndef FTSERV_H_ +#define FTSERV_H_ + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @macro: + * FT_FACE_FIND_SERVICE + * + * @description: + * This macro is used to look up a service from a face's driver module. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's header + * files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * 'multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_`. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be `NULL` if not + * found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + + /************************************************************************** + * + * @macro: + * FT_FACE_FIND_GLOBAL_SERVICE + * + * @description: + * This macro is used to look up a service from all modules. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's header + * files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * 'multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_`. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be `NULL` if not + * found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id, 1 ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id, 1 ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E D E S C R I P T O R S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * The following structure is used to _describe_ a given service to the + * library. This is useful to build simple static service lists. + */ + typedef struct FT_ServiceDescRec_ + { + const char* serv_id; /* service name */ + const void* serv_data; /* service pointer/data */ + + } FT_ServiceDescRec; + + typedef const FT_ServiceDescRec* FT_ServiceDesc; + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_SERVICEDESCREC1 + * FT_DEFINE_SERVICEDESCREC2 + * FT_DEFINE_SERVICEDESCREC3 + * FT_DEFINE_SERVICEDESCREC4 + * FT_DEFINE_SERVICEDESCREC5 + * FT_DEFINE_SERVICEDESCREC6 + * FT_DEFINE_SERVICEDESCREC7 + * FT_DEFINE_SERVICEDESCREC8 + * FT_DEFINE_SERVICEDESCREC9 + * FT_DEFINE_SERVICEDESCREC10 + * + * @description: + * Used to initialize an array of FT_ServiceDescRec structures. + * + * The array will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DEFINE_SERVICEDESCREC1( class_, \ + serv_id_1, serv_data_1 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC2( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC3( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC4( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC5( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC6( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC7( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC8( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7, \ + serv_id_8, serv_data_8 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { serv_id_8, serv_data_8 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC9( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7, \ + serv_id_8, serv_data_8, \ + serv_id_9, serv_data_9 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { serv_id_8, serv_data_8 }, \ + { serv_id_9, serv_data_9 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC10( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7, \ + serv_id_8, serv_data_8, \ + serv_id_9, serv_data_9, \ + serv_id_10, serv_data_10 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { serv_id_8, serv_data_8 }, \ + { serv_id_9, serv_data_9 }, \ + { serv_id_10, serv_data_10 }, \ + { NULL, NULL } \ + }; + + + /* + * Parse a list of FT_ServiceDescRec descriptors and look for a specific + * service by ID. Note that the last element in the array must be { NULL, + * NULL }, and that the function should return NULL if the service isn't + * available. + * + * This function can be used by modules to implement their `get_service' + * method. + */ + FT_BASE( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E S C A C H E *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * This structure is used to store a cache for several frequently used + * services. It is the type of `face->internal->services'. You should + * only use FT_FACE_LOOKUP_SERVICE to access it. + * + * All fields should have the type FT_Pointer to relax compilation + * dependencies. We assume the developer isn't completely stupid. + * + * Each field must be named `service_XXXX' where `XXX' corresponds to the + * correct FT_SERVICE_ID_XXXX macro. See the definition of + * FT_FACE_LOOKUP_SERVICE below how this is implemented. + * + */ + typedef struct FT_ServiceCacheRec_ + { + FT_Pointer service_POSTSCRIPT_FONT_NAME; + FT_Pointer service_MULTI_MASTERS; + FT_Pointer service_METRICS_VARIATIONS; + FT_Pointer service_GLYPH_DICT; + FT_Pointer service_PFR_METRICS; + FT_Pointer service_WINFNT; + + } FT_ServiceCacheRec, *FT_ServiceCache; + + + /* + * A magic number used within the services cache. + */ + + /* ensure that value `1' has the same width as a pointer */ +#define FT_SERVICE_UNAVAILABLE ((FT_Pointer)~(FT_PtrDist)1) + + + /************************************************************************** + * + * @macro: + * FT_FACE_LOOKUP_SERVICE + * + * @description: + * This macro is used to look up a service from a face's driver module + * using its cache. + * + * @input: + * face :: + * The source face handle containing the cache. + * + * field :: + * The field name in the cache. + * + * id :: + * The service ID. + * + * @output: + * ptr :: + * A variable receiving the service data. `NULL` if not available. + */ +#ifdef __cplusplus + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + FT_Pointer* Pptr = (FT_Pointer*)&(ptr); \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + *Pptr = svc; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + ptr = svc; \ + FT_END_STMNT + +#endif /* !C++ */ + + /* + * A macro used to define new service structure types. + */ + +#define FT_DEFINE_SERVICE( name ) \ + typedef struct FT_Service_ ## name ## Rec_ \ + FT_Service_ ## name ## Rec ; \ + typedef struct FT_Service_ ## name ## Rec_ \ + const * FT_Service_ ## name ; \ + struct FT_Service_ ## name ## Rec_ + + /* */ + +FT_END_HEADER + +#endif /* FTSERV_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftstream.h b/vendor/freetype/include/freetype/internal/ftstream.h new file mode 100644 index 0000000..88e1928 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftstream.h @@ -0,0 +1,570 @@ +/**************************************************************************** + * + * ftstream.h + * + * Stream handling (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSTREAM_H_ +#define FTSTREAM_H_ + + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /* format of an 8-bit frame_op value: */ + /* */ + /* bit 76543210 */ + /* xxxxxxes */ + /* */ + /* s is set to 1 if the value is signed. */ + /* e is set to 1 if the value is little-endian. */ + /* xxx is a command. */ + +#define FT_FRAME_OP_SHIFT 2 +#define FT_FRAME_OP_SIGNED 1 +#define FT_FRAME_OP_LITTLE 2 +#define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT ) + +#define FT_MAKE_FRAME_OP( command, little, sign ) \ + ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign ) + +#define FT_FRAME_OP_END 0 +#define FT_FRAME_OP_START 1 /* start a new frame */ +#define FT_FRAME_OP_BYTE 2 /* read 1-byte value */ +#define FT_FRAME_OP_SHORT 3 /* read 2-byte value */ +#define FT_FRAME_OP_LONG 4 /* read 4-byte value */ +#define FT_FRAME_OP_OFF3 5 /* read 3-byte value */ +#define FT_FRAME_OP_BYTES 6 /* read a bytes sequence */ + + + typedef enum FT_Frame_Op_ + { + ft_frame_end = 0, + ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), + + ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), + ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), + + ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), + ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), + ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), + ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), + + ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), + ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), + ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), + ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), + + ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), + ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), + ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), + ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), + + ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ), + ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 ) + + } FT_Frame_Op; + + + typedef struct FT_Frame_Field_ + { + FT_Byte value; + FT_Byte size; + FT_UShort offset; + + } FT_Frame_Field; + + + /* Construct an FT_Frame_Field out of a structure type and a field name. */ + /* The structure type must be set in the FT_STRUCTURE macro before */ + /* calling the FT_FRAME_START() macro. */ + /* */ +#define FT_FIELD_SIZE( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f ) + +#define FT_FIELD_SIZE_DELTA( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f[0] ) + +#define FT_FIELD_OFFSET( f ) \ + (FT_UShort)( offsetof( FT_STRUCTURE, f ) ) + +#define FT_FRAME_FIELD( frame_op, field ) \ + { \ + frame_op, \ + FT_FIELD_SIZE( field ), \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } + +#define FT_FRAME_START( size ) { ft_frame_start, 0, size } +#define FT_FRAME_END { ft_frame_end, 0, 0 } + +#define FT_FRAME_LONG( f ) FT_FRAME_FIELD( ft_frame_long_be, f ) +#define FT_FRAME_ULONG( f ) FT_FRAME_FIELD( ft_frame_ulong_be, f ) +#define FT_FRAME_SHORT( f ) FT_FRAME_FIELD( ft_frame_short_be, f ) +#define FT_FRAME_USHORT( f ) FT_FRAME_FIELD( ft_frame_ushort_be, f ) +#define FT_FRAME_OFF3( f ) FT_FRAME_FIELD( ft_frame_off3_be, f ) +#define FT_FRAME_UOFF3( f ) FT_FRAME_FIELD( ft_frame_uoff3_be, f ) +#define FT_FRAME_BYTE( f ) FT_FRAME_FIELD( ft_frame_byte, f ) +#define FT_FRAME_CHAR( f ) FT_FRAME_FIELD( ft_frame_schar, f ) + +#define FT_FRAME_LONG_LE( f ) FT_FRAME_FIELD( ft_frame_long_le, f ) +#define FT_FRAME_ULONG_LE( f ) FT_FRAME_FIELD( ft_frame_ulong_le, f ) +#define FT_FRAME_SHORT_LE( f ) FT_FRAME_FIELD( ft_frame_short_le, f ) +#define FT_FRAME_USHORT_LE( f ) FT_FRAME_FIELD( ft_frame_ushort_le, f ) +#define FT_FRAME_OFF3_LE( f ) FT_FRAME_FIELD( ft_frame_off3_le, f ) +#define FT_FRAME_UOFF3_LE( f ) FT_FRAME_FIELD( ft_frame_uoff3_le, f ) + +#define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 } +#define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 } +#define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 } + +#define FT_FRAME_BYTES( field, count ) \ + { \ + ft_frame_bytes, \ + count, \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 } + + + /************************************************************************** + * + * Integer extraction macros -- the 'buffer' parameter must ALWAYS be of + * type 'char*' or equivalent (1-byte elements). + */ + +#define FT_BYTE_( p, i ) ( ((const FT_Byte*)(p))[(i)] ) + +#define FT_INT16( x ) ( (FT_Int16)(x) ) +#define FT_UINT16( x ) ( (FT_UInt16)(x) ) +#define FT_INT32( x ) ( (FT_Int32)(x) ) +#define FT_UINT32( x ) ( (FT_UInt32)(x) ) + + +#define FT_BYTE_U16( p, i, s ) ( FT_UINT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U32( p, i, s ) ( FT_UINT32( FT_BYTE_( p, i ) ) << (s) ) + + + /* + * function acts on increases does range for emits + * pointer checking frames error + * ------------------------------------------------------------------- + * FT_PEEK_XXX buffer pointer no no no no + * FT_NEXT_XXX buffer pointer yes no no no + * FT_GET_XXX stream->cursor yes yes yes no + * FT_READ_XXX stream->pos yes yes no yes + */ + + + /* + * `FT_PEEK_XXX' are generic macros to get data from a buffer position. No + * safety checks are performed. + */ +#define FT_PEEK_SHORT( p ) FT_INT16( FT_BYTE_U16( p, 0, 8 ) | \ + FT_BYTE_U16( p, 1, 0 ) ) + +#define FT_PEEK_USHORT( p ) FT_UINT16( FT_BYTE_U16( p, 0, 8 ) | \ + FT_BYTE_U16( p, 1, 0 ) ) + +#define FT_PEEK_LONG( p ) FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) | \ + FT_BYTE_U32( p, 3, 0 ) ) + +#define FT_PEEK_ULONG( p ) FT_UINT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) | \ + FT_BYTE_U32( p, 3, 0 ) ) + +#define FT_PEEK_OFF3( p ) ( FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) ) >> 8 ) + +#define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 2, 0 ) ) + +#define FT_PEEK_SHORT_LE( p ) FT_INT16( FT_BYTE_U16( p, 1, 8 ) | \ + FT_BYTE_U16( p, 0, 0 ) ) + +#define FT_PEEK_USHORT_LE( p ) FT_UINT16( FT_BYTE_U16( p, 1, 8 ) | \ + FT_BYTE_U16( p, 0, 0 ) ) + +#define FT_PEEK_LONG_LE( p ) FT_INT32( FT_BYTE_U32( p, 3, 24 ) | \ + FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + +#define FT_PEEK_ULONG_LE( p ) FT_UINT32( FT_BYTE_U32( p, 3, 24 ) | \ + FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + +#define FT_PEEK_OFF3_LE( p ) ( FT_INT32( FT_BYTE_U32( p, 2, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 0, 8 ) ) >> 8 ) + +#define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + + /* + * `FT_NEXT_XXX' are generic macros to get data from a buffer position + * which is then increased appropriately. No safety checks are performed. + */ +#define FT_NEXT_CHAR( buffer ) \ + ( (signed char)*buffer++ ) + +#define FT_NEXT_BYTE( buffer ) \ + ( (unsigned char)*buffer++ ) + +#define FT_NEXT_SHORT( buffer ) \ + ( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) + +#define FT_NEXT_USHORT( buffer ) \ + ( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) + +#define FT_NEXT_OFF3( buffer ) \ + ( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) + +#define FT_NEXT_UOFF3( buffer ) \ + ( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) + +#define FT_NEXT_LONG( buffer ) \ + ( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) + +#define FT_NEXT_ULONG( buffer ) \ + ( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) + + +#define FT_NEXT_SHORT_LE( buffer ) \ + ( buffer += 2, FT_PEEK_SHORT_LE( buffer - 2 ) ) + +#define FT_NEXT_USHORT_LE( buffer ) \ + ( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) + +#define FT_NEXT_OFF3_LE( buffer ) \ + ( buffer += 3, FT_PEEK_OFF3_LE( buffer - 3 ) ) + +#define FT_NEXT_UOFF3_LE( buffer ) \ + ( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) + +#define FT_NEXT_LONG_LE( buffer ) \ + ( buffer += 4, FT_PEEK_LONG_LE( buffer - 4 ) ) + +#define FT_NEXT_ULONG_LE( buffer ) \ + ( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) + + + /************************************************************************** + * + * The `FT_GET_XXX` macros use an implicit 'stream' variable. + * + * Note that a call to `FT_STREAM_SEEK` or `FT_STREAM_POS` has **no** + * effect on `FT_GET_XXX`! They operate on `stream->pos`, while + * `FT_GET_XXX` use `stream->cursor`. + */ +#if 0 +#define FT_GET_MACRO( type ) FT_NEXT_ ## type ( stream->cursor ) + +#define FT_GET_CHAR() FT_GET_MACRO( CHAR ) +#define FT_GET_BYTE() FT_GET_MACRO( BYTE ) +#define FT_GET_SHORT() FT_GET_MACRO( SHORT ) +#define FT_GET_USHORT() FT_GET_MACRO( USHORT ) +#define FT_GET_OFF3() FT_GET_MACRO( OFF3 ) +#define FT_GET_UOFF3() FT_GET_MACRO( UOFF3 ) +#define FT_GET_LONG() FT_GET_MACRO( LONG ) +#define FT_GET_ULONG() FT_GET_MACRO( ULONG ) +#define FT_GET_TAG4() FT_GET_MACRO( ULONG ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( SHORT_LE ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( USHORT_LE ) +#define FT_GET_LONG_LE() FT_GET_MACRO( LONG_LE ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( ULONG_LE ) + +#else +#define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) + +#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetByte, FT_Char ) +#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetByte, FT_Byte ) +#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Int16 ) +#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UInt16 ) +#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_UInt32 ) +#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Int32 ) +#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_UInt32 ) +#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_UInt32 ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Int16 ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UInt16 ) +#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_Int32 ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_UInt32 ) +#endif + + +#define FT_READ_MACRO( func, type, var ) \ + ( var = (type)func( stream, &error ), \ + error != FT_Err_Ok ) + + /* + * The `FT_READ_XXX' macros use implicit `stream' and `error' variables. + * + * `FT_READ_XXX' can be controlled with `FT_STREAM_SEEK' and + * `FT_STREAM_POS'. They use the full machinery to check whether a read is + * valid. + */ +#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Byte, var ) +#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Char, var ) +#define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_Int16, var ) +#define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_UInt16, var ) +#define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_UInt32, var ) +#define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_Int32, var ) +#define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_UInt32, var ) + +#define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_Int16, var ) +#define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_UInt16, var ) +#define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_Int32, var ) +#define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_UInt32, var ) + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /* initialize a stream for reading a regular system stream */ + FT_BASE( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ); + +#endif /* FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* create a new (input) stream from an FT_Open_Args structure */ + FT_BASE( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ); + + /* free a stream */ + FT_BASE( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ); + + /* initialize a stream for reading in-memory data */ + FT_BASE( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ); + + /* close a stream (does not destroy the stream structure) */ + FT_BASE( void ) + FT_Stream_Close( FT_Stream stream ); + + + /* seek within a stream. position is relative to start of stream */ + FT_BASE( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ); + + /* skip bytes in a stream */ + FT_BASE( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ); + + /* return current stream position */ + FT_BASE( FT_ULong ) + FT_Stream_Pos( FT_Stream stream ); + + /* read bytes from a stream into a user-allocated buffer, returns an */ + /* error if not all bytes could be read. */ + FT_BASE( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* read bytes from a stream at a given position */ + FT_BASE( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ); + + /* try to read bytes at the end of a stream; return number of bytes */ + /* really available */ + FT_BASE( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* Enter a frame of `count' consecutive bytes in a stream. Returns an */ + /* error if the frame could not be read/accessed. The caller can use */ + /* the `FT_Stream_GetXXX' functions to retrieve frame data without */ + /* error checks. */ + /* */ + /* You must _always_ call `FT_Stream_ExitFrame' once you have entered */ + /* a stream frame! */ + /* */ + /* Nested frames are not permitted. */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ); + + /* exit a stream frame */ + FT_BASE( void ) + FT_Stream_ExitFrame( FT_Stream stream ); + + + /* Extract a stream frame. If the stream is disk-based, a heap block */ + /* is allocated and the frame bytes are read into it. If the stream */ + /* is memory-based, this function simply sets a pointer to the data. */ + /* */ + /* Useful to optimize access to memory-based streams transparently. */ + /* */ + /* `FT_Stream_GetXXX' functions can't be used. */ + /* */ + /* An extracted frame must be `freed' with a call to the function */ + /* `FT_Stream_ReleaseFrame'. */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ); + + /* release an extract frame (see `FT_Stream_ExtractFrame') */ + FT_BASE( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ); + + + /* read a byte from an entered frame */ + FT_BASE( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ); + + /* read a 16-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt16 ) + FT_Stream_GetUShort( FT_Stream stream ); + + /* read a 24-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt32 ) + FT_Stream_GetUOffset( FT_Stream stream ); + + /* read a 32-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt32 ) + FT_Stream_GetULong( FT_Stream stream ); + + /* read a 16-bit little-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt16 ) + FT_Stream_GetUShortLE( FT_Stream stream ); + + /* read a 32-bit little-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt32 ) + FT_Stream_GetULongLE( FT_Stream stream ); + + + /* read a byte from a stream */ + FT_BASE( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit big-endian unsigned integer from a stream */ + FT_BASE( FT_UInt16 ) + FT_Stream_ReadUShort( FT_Stream stream, + FT_Error* error ); + + /* read a 24-bit big-endian unsigned integer from a stream */ + FT_BASE( FT_ULong ) + FT_Stream_ReadUOffset( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit big-endian integer from a stream */ + FT_BASE( FT_UInt32 ) + FT_Stream_ReadULong( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit little-endian unsigned integer from a stream */ + FT_BASE( FT_UInt16 ) + FT_Stream_ReadUShortLE( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit little-endian unsigned integer from a stream */ + FT_BASE( FT_UInt32 ) + FT_Stream_ReadULongLE( FT_Stream stream, + FT_Error* error ); + + /* Read a structure from a stream. The structure must be described */ + /* by an array of FT_Frame_Field records. */ + FT_BASE( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ); + + +#define FT_STREAM_POS() \ + FT_Stream_Pos( stream ) + +#define FT_STREAM_SEEK( position ) \ + FT_SET_ERROR( FT_Stream_Seek( stream, \ + (FT_ULong)(position) ) ) + +#define FT_STREAM_SKIP( distance ) \ + FT_SET_ERROR( FT_Stream_Skip( stream, \ + (FT_Long)(distance) ) ) + +#define FT_STREAM_READ( buffer, count ) \ + FT_SET_ERROR( FT_Stream_Read( stream, \ + (FT_Byte*)(buffer), \ + (FT_ULong)(count) ) ) + +#define FT_STREAM_READ_AT( position, buffer, count ) \ + FT_SET_ERROR( FT_Stream_ReadAt( stream, \ + (FT_ULong)(position), \ + (FT_Byte*)(buffer), \ + (FT_ULong)(count) ) ) + +#define FT_STREAM_READ_FIELDS( fields, object ) \ + FT_SET_ERROR( FT_Stream_ReadFields( stream, fields, object ) ) + + +#define FT_FRAME_ENTER( size ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_EnterFrame( stream, \ + (FT_ULong)(size) ) ) ) + +#define FT_FRAME_EXIT() \ + FT_DEBUG_INNER( FT_Stream_ExitFrame( stream ) ) + +#define FT_FRAME_EXTRACT( size, bytes ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_ExtractFrame( stream, \ + (FT_ULong)(size), \ + (FT_Byte**)&(bytes) ) ) ) + +#define FT_FRAME_RELEASE( bytes ) \ + FT_DEBUG_INNER( FT_Stream_ReleaseFrame( stream, \ + (FT_Byte**)&(bytes) ) ) + + +FT_END_HEADER + +#endif /* FTSTREAM_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/fttrace.h b/vendor/freetype/include/freetype/internal/fttrace.h new file mode 100644 index 0000000..319fe56 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/fttrace.h @@ -0,0 +1,172 @@ +/**************************************************************************** + * + * fttrace.h + * + * Tracing handling (specification only). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* definitions of trace levels for FreeType 2 */ + + /* the maximum string length (if the argument to `FT_TRACE_DEF` */ + /* gets used as a string) plus one charachter for ':' plus */ + /* another one for the trace level */ +#define FT_MAX_TRACE_LEVEL_LENGTH (9 + 1 + 1) + + /* the first level must always be `trace_any' */ +FT_TRACE_DEF( any ) + + /* base components */ +FT_TRACE_DEF( calc ) /* calculations (ftcalc.c) */ +FT_TRACE_DEF( gloader ) /* glyph loader (ftgloadr.c) */ +FT_TRACE_DEF( glyph ) /* glyph management (ftglyph.c) */ +FT_TRACE_DEF( memory ) /* memory manager (ftobjs.c) */ +FT_TRACE_DEF( init ) /* initialization (ftinit.c) */ +FT_TRACE_DEF( io ) /* i/o interface (ftsystem.c) */ +FT_TRACE_DEF( list ) /* list management (ftlist.c) */ +FT_TRACE_DEF( objs ) /* base objects (ftobjs.c) */ +FT_TRACE_DEF( outline ) /* outline management (ftoutln.c) */ +FT_TRACE_DEF( stream ) /* stream manager (ftstream.c) */ + +FT_TRACE_DEF( bitmap ) /* bitmap manipulation (ftbitmap.c) */ +FT_TRACE_DEF( checksum ) /* bitmap checksum (ftobjs.c) */ +FT_TRACE_DEF( mm ) /* MM interface (ftmm.c) */ +FT_TRACE_DEF( psprops ) /* PS driver properties (ftpsprop.c) */ +FT_TRACE_DEF( raccess ) /* resource fork accessor (ftrfork.c) */ +FT_TRACE_DEF( synth ) /* bold/slant synthesizer (ftsynth.c) */ + + /* rasterizers */ +FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */ +FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */ + + /* ot-svg module */ +FT_TRACE_DEF( otsvg ) /* OT-SVG renderer (ftsvg.c) */ + + /* cache sub-system */ +FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ + + /* SFNT driver components */ +FT_TRACE_DEF( sfdriver ) /* SFNT font driver (sfdriver.c) */ +FT_TRACE_DEF( sfobjs ) /* SFNT object handler (sfobjs.c) */ +FT_TRACE_DEF( sfwoff ) /* WOFF format handler (sfwoff.c) */ +FT_TRACE_DEF( sfwoff2 ) /* WOFF2 format handler (sfwoff2.c) */ +FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */ +FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */ +FT_TRACE_DEF( ttcolr ) /* glyph layer table (ttcolr.c) */ +FT_TRACE_DEF( ttcpal ) /* color palette table (ttcpal.c) */ +FT_TRACE_DEF( ttsvg ) /* OpenType SVG table (ttsvg.c) */ +FT_TRACE_DEF( ttkern ) /* kerning handler (ttkern.c) */ +FT_TRACE_DEF( ttload ) /* basic TrueType tables (ttload.c) */ +FT_TRACE_DEF( ttmtx ) /* metrics-related tables (ttmtx.c) */ +FT_TRACE_DEF( ttpost ) /* PS table processing (ttpost.c) */ +FT_TRACE_DEF( ttsbit ) /* TrueType sbit handling (ttsbit.c) */ + + /* TrueType driver components */ +FT_TRACE_DEF( ttdriver ) /* TT font driver (ttdriver.c) */ +FT_TRACE_DEF( ttgload ) /* TT glyph loader (ttgload.c) */ +FT_TRACE_DEF( ttgxvar ) /* TrueType GX var handler (ttgxvar.c) */ +FT_TRACE_DEF( ttinterp ) /* bytecode interpreter (ttinterp.c) */ +FT_TRACE_DEF( ttobjs ) /* TT objects manager (ttobjs.c) */ +FT_TRACE_DEF( ttpload ) /* TT data/program loader (ttpload.c) */ + + /* Type 1 driver components */ +FT_TRACE_DEF( t1afm ) +FT_TRACE_DEF( t1driver ) +FT_TRACE_DEF( t1gload ) +FT_TRACE_DEF( t1load ) +FT_TRACE_DEF( t1objs ) +FT_TRACE_DEF( t1parse ) + + /* PostScript helper module `psaux' */ +FT_TRACE_DEF( afmparse ) +FT_TRACE_DEF( cffdecode ) +FT_TRACE_DEF( psconv ) +FT_TRACE_DEF( psobjs ) +FT_TRACE_DEF( t1decode ) + + /* PostScript hinting module `pshinter' */ +FT_TRACE_DEF( pshalgo ) +FT_TRACE_DEF( pshrec ) + + /* Type 2 driver components */ +FT_TRACE_DEF( cffdriver ) +FT_TRACE_DEF( cffgload ) +FT_TRACE_DEF( cffload ) +FT_TRACE_DEF( cffobjs ) +FT_TRACE_DEF( cffparse ) + +FT_TRACE_DEF( cf2blues ) +FT_TRACE_DEF( cf2hints ) +FT_TRACE_DEF( cf2interp ) + + /* Type 42 driver component */ +FT_TRACE_DEF( t42 ) + + /* CID driver components */ +FT_TRACE_DEF( ciddriver ) +FT_TRACE_DEF( cidgload ) +FT_TRACE_DEF( cidload ) +FT_TRACE_DEF( cidobjs ) +FT_TRACE_DEF( cidparse ) + + /* Windows font component */ +FT_TRACE_DEF( winfnt ) + + /* PCF font components */ +FT_TRACE_DEF( pcfdriver ) +FT_TRACE_DEF( pcfread ) + + /* BDF font components */ +FT_TRACE_DEF( bdfdriver ) +FT_TRACE_DEF( bdflib ) + + /* PFR font component */ +FT_TRACE_DEF( pfr ) + + /* OpenType validation components */ +FT_TRACE_DEF( otvcommon ) +FT_TRACE_DEF( otvbase ) +FT_TRACE_DEF( otvgdef ) +FT_TRACE_DEF( otvgpos ) +FT_TRACE_DEF( otvgsub ) +FT_TRACE_DEF( otvjstf ) +FT_TRACE_DEF( otvmath ) +FT_TRACE_DEF( otvmodule ) + + /* TrueTypeGX/AAT validation components */ +FT_TRACE_DEF( gxvbsln ) +FT_TRACE_DEF( gxvcommon ) +FT_TRACE_DEF( gxvfeat ) +FT_TRACE_DEF( gxvjust ) +FT_TRACE_DEF( gxvkern ) +FT_TRACE_DEF( gxvmodule ) +FT_TRACE_DEF( gxvmort ) +FT_TRACE_DEF( gxvmorx ) +FT_TRACE_DEF( gxvlcar ) +FT_TRACE_DEF( gxvopbd ) +FT_TRACE_DEF( gxvprop ) +FT_TRACE_DEF( gxvtrak ) + + /* autofit components */ +FT_TRACE_DEF( afcjk ) +FT_TRACE_DEF( afglobal ) +FT_TRACE_DEF( afhints ) +FT_TRACE_DEF( afmodule ) +FT_TRACE_DEF( aflatin ) +FT_TRACE_DEF( afshaper ) + + /* SDF components */ +FT_TRACE_DEF( sdf ) /* signed distance raster for outlines (ftsdf.c) */ +FT_TRACE_DEF( bsdf ) /* signed distance raster for bitmaps (ftbsdf.c) */ + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/ftvalid.h b/vendor/freetype/include/freetype/internal/ftvalid.h new file mode 100644 index 0000000..e98ee4e --- /dev/null +++ b/vendor/freetype/include/freetype/internal/ftvalid.h @@ -0,0 +1,160 @@ +/**************************************************************************** + * + * ftvalid.h + * + * FreeType validation support (specification). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTVALID_H_ +#define FTVALID_H_ + +#include +#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_jmpbuf */ + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** V A L I D A T I O N ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to a validation object */ + typedef struct FT_ValidatorRec_ volatile* FT_Validator; + + + /************************************************************************** + * + * There are three distinct validation levels defined here: + * + * FT_VALIDATE_DEFAULT :: + * A table that passes this validation level can be used reliably by + * FreeType. It generally means that all offsets have been checked to + * prevent out-of-bound reads, that array counts are correct, etc. + * + * FT_VALIDATE_TIGHT :: + * A table that passes this validation level can be used reliably and + * doesn't contain invalid data. For example, a charmap table that + * returns invalid glyph indices will not pass, even though it can be + * used with FreeType in default mode (the library will simply return an + * error later when trying to load the glyph). + * + * It also checks that fields which must be a multiple of 2, 4, or 8, + * don't have incorrect values, etc. + * + * FT_VALIDATE_PARANOID :: + * Only for font debugging. Checks that a table follows the + * specification by 100%. Very few fonts will be able to pass this level + * anyway but it can be useful for certain tools like font + * editors/converters. + */ + typedef enum FT_ValidationLevel_ + { + FT_VALIDATE_DEFAULT = 0, + FT_VALIDATE_TIGHT, + FT_VALIDATE_PARANOID + + } FT_ValidationLevel; + + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `structure was padded due to */ + /* __declspec(align())' in order to compile cleanly with */ + /* the maximum level of warnings. */ +#pragma warning( push ) +#pragma warning( disable : 4324 ) +#endif /* _MSC_VER */ + + /* validator structure */ + typedef struct FT_ValidatorRec_ + { + ft_jmp_buf jump_buffer; /* used for exception handling */ + + const FT_Byte* base; /* address of table in memory */ + const FT_Byte* limit; /* `base' + sizeof(table) in memory */ + FT_ValidationLevel level; /* validation level */ + FT_Error error; /* error returned. 0 means success */ + + } FT_ValidatorRec; + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + +#define FT_VALIDATOR( x ) ( (FT_Validator)( x ) ) + + + FT_BASE( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ); + + /* Do not use this. It's broken and will cause your validator to crash */ + /* if you run it on an invalid font. */ + FT_BASE( FT_Int ) + ft_validator_run( FT_Validator valid ); + + /* Sets the error field in a validator, then calls `longjmp' to return */ + /* to high-level caller. Using `setjmp/longjmp' avoids many stupid */ + /* error checks within the validation routines. */ + /* */ + FT_BASE( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ); + + + /* Calls ft_validate_error. Assumes that the `valid' local variable */ + /* holds a pointer to the current validator object. */ + /* */ +#define FT_INVALID( _error ) FT_INVALID_( _error ) +#define FT_INVALID_( _error ) \ + ft_validator_error( valid, FT_THROW( _error ) ) + + /* called when a broken table is detected */ +#define FT_INVALID_TOO_SHORT \ + FT_INVALID( Invalid_Table ) + + /* called when an invalid offset is detected */ +#define FT_INVALID_OFFSET \ + FT_INVALID( Invalid_Offset ) + + /* called when an invalid format/value is detected */ +#define FT_INVALID_FORMAT \ + FT_INVALID( Invalid_Table ) + + /* called when an invalid glyph index is detected */ +#define FT_INVALID_GLYPH_ID \ + FT_INVALID( Invalid_Glyph_Index ) + + /* called when an invalid field value is detected */ +#define FT_INVALID_DATA \ + FT_INVALID( Invalid_Table ) + + +FT_END_HEADER + +#endif /* FTVALID_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/psaux.h b/vendor/freetype/include/freetype/internal/psaux.h new file mode 100644 index 0000000..dfb1987 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/psaux.h @@ -0,0 +1,1434 @@ +/**************************************************************************** + * + * psaux.h + * + * Auxiliary functions and data structures related to PostScript fonts + * (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSAUX_H_ +#define PSAUX_H_ + + +#include +#include +#include +#include +#include +#include +#include + + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * PostScript modules driver class. + */ + typedef struct PS_DriverRec_ + { + FT_DriverRec root; + + FT_UInt hinting_engine; + FT_Bool no_stem_darkening; + FT_Int darken_params[8]; + FT_Int32 random_seed; + + } PS_DriverRec, *PS_Driver; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct PS_TableRec_* PS_Table; + typedef const struct PS_Table_FuncsRec_* PS_Table_Funcs; + + + /************************************************************************** + * + * @struct: + * PS_Table_FuncsRec + * + * @description: + * A set of function pointers to manage PS_Table objects. + * + * @fields: + * table_init :: + * Used to initialize a table. + * + * table_done :: + * Finalizes resp. destroy a given table. + * + * table_add :: + * Adds a new object to a table. + * + * table_release :: + * Releases table data, then finalizes it. + */ + typedef struct PS_Table_FuncsRec_ + { + FT_Error + (*init)( PS_Table table, + FT_Int count, + FT_Memory memory ); + + void + (*done)( PS_Table table ); + + FT_Error + (*add)( PS_Table table, + FT_Int idx, + const void* object, + FT_UInt length ); + + void + (*release)( PS_Table table ); + + } PS_Table_FuncsRec; + + + /************************************************************************** + * + * @struct: + * PS_TableRec + * + * @description: + * A PS_Table is a simple object used to store an array of objects in a + * single memory block. + * + * @fields: + * block :: + * The address in memory of the growheap's block. This can change + * between two object adds, due to reallocation. + * + * cursor :: + * The current top of the grow heap within its block. + * + * capacity :: + * The current size of the heap block. Increments by 1kByte chunks. + * + * init :: + * Set to 0xDEADBEEF if 'elements' and 'lengths' have been allocated. + * + * max_elems :: + * The maximum number of elements in table. + * + * elements :: + * A table of element addresses within the block. + * + * lengths :: + * A table of element sizes within the block. + * + * memory :: + * The object used for memory operations (alloc/realloc). + * + * funcs :: + * A table of method pointers for this object. + */ + typedef struct PS_TableRec_ + { + FT_Byte* block; /* current memory block */ + FT_Offset cursor; /* current cursor in memory block */ + FT_Offset capacity; /* current size of memory block */ + FT_ULong init; + + FT_Int max_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_UInt* lengths; /* lengths of table elements */ + + FT_Memory memory; + PS_Table_FuncsRec funcs; + + } PS_TableRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 FIELDS & TOKENS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PS_ParserRec_* PS_Parser; + + typedef struct T1_TokenRec_* T1_Token; + + typedef struct T1_FieldRec_* T1_Field; + + + /* simple enumeration type used to identify token types */ + typedef enum T1_TokenType_ + { + T1_TOKEN_TYPE_NONE = 0, + T1_TOKEN_TYPE_ANY, + T1_TOKEN_TYPE_STRING, + T1_TOKEN_TYPE_ARRAY, + T1_TOKEN_TYPE_KEY, /* aka `name' */ + + /* do not remove */ + T1_TOKEN_TYPE_MAX + + } T1_TokenType; + + + /* a simple structure used to identify tokens */ + typedef struct T1_TokenRec_ + { + FT_Byte* start; /* first character of token in input stream */ + FT_Byte* limit; /* first character after the token */ + T1_TokenType type; /* type of token */ + + } T1_TokenRec; + + + /* enumeration type used to identify object fields */ + typedef enum T1_FieldType_ + { + T1_FIELD_TYPE_NONE = 0, + T1_FIELD_TYPE_BOOL, + T1_FIELD_TYPE_INTEGER, + T1_FIELD_TYPE_FIXED, + T1_FIELD_TYPE_FIXED_1000, + T1_FIELD_TYPE_STRING, + T1_FIELD_TYPE_KEY, + T1_FIELD_TYPE_BBOX, + T1_FIELD_TYPE_MM_BBOX, + T1_FIELD_TYPE_INTEGER_ARRAY, + T1_FIELD_TYPE_FIXED_ARRAY, + T1_FIELD_TYPE_CALLBACK, + + /* do not remove */ + T1_FIELD_TYPE_MAX + + } T1_FieldType; + + + typedef enum T1_FieldLocation_ + { + T1_FIELD_LOCATION_CID_INFO, + T1_FIELD_LOCATION_FONT_DICT, + T1_FIELD_LOCATION_FONT_EXTRA, + T1_FIELD_LOCATION_FONT_INFO, + T1_FIELD_LOCATION_PRIVATE, + T1_FIELD_LOCATION_BBOX, + T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE, + T1_FIELD_LOCATION_BLEND, + + /* do not remove */ + T1_FIELD_LOCATION_MAX + + } T1_FieldLocation; + + + typedef void + (*T1_Field_ParseFunc)( FT_Face face, + FT_Pointer parser ); + + + /* structure type used to model object fields */ + typedef struct T1_FieldRec_ + { + const char* ident; /* field identifier */ + T1_FieldLocation location; + T1_FieldType type; /* type of field */ + T1_Field_ParseFunc reader; + FT_UInt offset; /* offset of field in object */ + FT_Byte size; /* size of field in bytes */ + FT_UInt array_max; /* maximum number of elements for */ + /* array */ + FT_UInt count_offset; /* offset of element count for */ + /* arrays; must not be zero if in */ + /* use -- in other words, a */ + /* `num_FOO' element must not */ + /* start the used structure if we */ + /* parse a `FOO' array */ + FT_UInt dict; /* where we expect it */ + } T1_FieldRec; + +#define T1_FIELD_DICT_FONTDICT ( 1 << 0 ) /* also FontInfo and FDArray */ +#define T1_FIELD_DICT_PRIVATE ( 1 << 1 ) + + + +#define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE( _fname ), \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_CALLBACK_FIELD( _ident, _reader, _dict ) \ + { \ + _ident, T1CODE, T1_FIELD_TYPE_CALLBACK, \ + (T1_Field_ParseFunc)_reader, \ + 0, 0, \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, \ + FT_FIELD_OFFSET( num_ ## _fname ), \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, 0, \ + _dict \ + }, + + +#define T1_FIELD_BOOL( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BOOL, _fname, _dict ) + +#define T1_FIELD_NUM( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER, _fname, _dict ) + +#define T1_FIELD_FIXED( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED, _fname, _dict ) + +#define T1_FIELD_FIXED_1000( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_1000, _fname, \ + _dict ) + +#define T1_FIELD_STRING( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_STRING, _fname, _dict ) + +#define T1_FIELD_KEY( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_KEY, _fname, _dict ) + +#define T1_FIELD_BBOX( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BBOX, _fname, _dict ) + + +#define T1_FIELD_NUM_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_NUM_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_CALLBACK( _ident, _name, _dict ) \ + T1_NEW_CALLBACK_FIELD( _ident, _name, _dict ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct PS_Parser_FuncsRec_* PS_Parser_Funcs; + + typedef struct PS_Parser_FuncsRec_ + { + void + (*init)( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + + void + (*done)( PS_Parser parser ); + + void + (*skip_spaces)( PS_Parser parser ); + void + (*skip_PS_token)( PS_Parser parser ); + + FT_Long + (*to_int)( PS_Parser parser ); + FT_Fixed + (*to_fixed)( PS_Parser parser, + FT_Int power_ten ); + + FT_Error + (*to_bytes)( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_ULong* pnum_bytes, + FT_Bool delimiters ); + + FT_Int + (*to_coord_array)( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + FT_Int + (*to_fixed_array)( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + void + (*to_token)( PS_Parser parser, + T1_Token token ); + void + (*to_token_array)( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + FT_Error + (*load_field)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_Error + (*load_field_table)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + } PS_Parser_FuncsRec; + + + /************************************************************************** + * + * @struct: + * PS_ParserRec + * + * @description: + * A PS_Parser is an object used to parse a Type 1 font very quickly. + * + * @fields: + * cursor :: + * The current position in the text. + * + * base :: + * Start of the processed text. + * + * limit :: + * End of the processed text. + * + * error :: + * The last error returned. + * + * memory :: + * The object used for memory operations (alloc/realloc). + * + * funcs :: + * A table of functions for the parser. + */ + typedef struct PS_ParserRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + FT_Error error; + FT_Memory memory; + + PS_Parser_FuncsRec funcs; + + } PS_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct PS_Builder_ PS_Builder; + typedef const struct PS_Builder_FuncsRec_* PS_Builder_Funcs; + + typedef struct PS_Builder_FuncsRec_ + { + void + (*init)( PS_Builder* ps_builder, + void* builder, + FT_Bool is_t1 ); + + void + (*done)( PS_Builder* builder ); + + } PS_Builder_FuncsRec; + + + /************************************************************************** + * + * @struct: + * PS_Builder + * + * @description: + * A structure used during glyph loading to store its outline. + * + * @fields: + * memory :: + * The current memory object. + * + * face :: + * The current face object. + * + * glyph :: + * The current glyph slot. + * + * loader :: + * XXX + * + * base :: + * The base glyph outline. + * + * current :: + * The current glyph outline. + * + * pos_x :: + * The horizontal translation (if composite glyph). + * + * pos_y :: + * The vertical translation (if composite glyph). + * + * left_bearing :: + * The left side bearing point. + * + * advance :: + * The horizontal advance vector. + * + * bbox :: + * Unused. + * + * path_begun :: + * A flag which indicates that a new path has begun. + * + * load_points :: + * If this flag is not set, no points are loaded. + * + * no_recurse :: + * Set but not used. + * + * metrics_only :: + * A boolean indicating that we only want to compute the metrics of a + * given glyph, not load all of its points. + * + * is_t1 :: + * Set if current font type is Type 1. + * + * funcs :: + * An array of function pointers for the builder. + */ + struct PS_Builder_ + { + FT_Memory memory; + FT_Face face; + CFF_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Pos* pos_x; + FT_Pos* pos_y; + + FT_Vector* left_bearing; + FT_Vector* advance; + + FT_BBox* bbox; /* bounding box */ + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + FT_Bool is_t1; + + PS_Builder_FuncsRec funcs; + + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define PS_MAX_OPERANDS 48 +#define PS_MAX_SUBRS_CALLS 16 /* maximum subroutine nesting; */ + /* only 10 are allowed but there exist */ + /* fonts like `HiraKakuProN-W3.ttf' */ + /* (Hiragino Kaku Gothic ProN W3; */ + /* 8.2d6e1; 2014-12-19) that exceed */ + /* this limit */ + + /* execution context charstring zone */ + + typedef struct PS_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } PS_Decoder_Zone; + + + typedef FT_Error + (*CFF_Decoder_Get_Glyph_Callback)( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ); + + typedef void + (*CFF_Decoder_Free_Glyph_Callback)( TT_Face face, + FT_Byte** pointer, + FT_ULong length ); + + + typedef struct PS_Decoder_ + { + PS_Builder builder; + + FT_Fixed stack[PS_MAX_OPERANDS + 1]; + FT_Fixed* top; + + PS_Decoder_Zone zones[PS_MAX_SUBRS_CALLS + 1]; + PS_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + CFF_Font cff; + CFF_SubFont current_subfont; /* for current glyph_index */ + FT_Generic* cf2_instance; + + FT_Pos* glyph_width; + FT_Bool width_only; + FT_Int num_hints; + + FT_UInt num_locals; + FT_UInt num_globals; + + FT_Int locals_bias; + FT_Int globals_bias; + + FT_Byte** locals; + FT_Byte** globals; + + FT_Byte** glyph_names; /* for pure CFF fonts only */ + FT_UInt num_glyphs; /* number of glyphs in font */ + + FT_Render_Mode hint_mode; + + FT_Bool seac; + + CFF_Decoder_Get_Glyph_Callback get_glyph_callback; + CFF_Decoder_Free_Glyph_Callback free_glyph_callback; + + /* Type 1 stuff */ + FT_Service_PsCMaps psnames; /* for seac */ + + FT_Int lenIV; /* internal for sub routine calls */ + FT_UInt* locals_len; /* array of subrs length (optional) */ + FT_Hash locals_hash; /* used if `num_subrs' was massaged */ + + FT_Matrix font_matrix; + FT_Vector font_offset; + + PS_Blend blend; /* for multiple master support */ + + FT_Long* buildchar; + FT_UInt len_buildchar; + + } PS_Decoder; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_BuilderRec_* T1_Builder; + + + typedef FT_Error + (*T1_Builder_Check_Points_Func)( T1_Builder builder, + FT_Int count ); + + typedef void + (*T1_Builder_Add_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + typedef FT_Error + (*T1_Builder_Add_Point1_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef FT_Error + (*T1_Builder_Add_Contour_Func)( T1_Builder builder ); + + typedef FT_Error + (*T1_Builder_Start_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef void + (*T1_Builder_Close_Contour_Func)( T1_Builder builder ); + + + typedef const struct T1_Builder_FuncsRec_* T1_Builder_Funcs; + + typedef struct T1_Builder_FuncsRec_ + { + void + (*init)( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Bool hinting ); + + void + (*done)( T1_Builder builder ); + + T1_Builder_Check_Points_Func check_points; + T1_Builder_Add_Point_Func add_point; + T1_Builder_Add_Point1_Func add_point1; + T1_Builder_Add_Contour_Func add_contour; + T1_Builder_Start_Point_Func start_point; + T1_Builder_Close_Contour_Func close_contour; + + } T1_Builder_FuncsRec; + + + /* an enumeration type to handle charstring parsing states */ + typedef enum T1_ParseState_ + { + T1_Parse_Start, + T1_Parse_Have_Width, + T1_Parse_Have_Moveto, + T1_Parse_Have_Path + + } T1_ParseState; + + + /************************************************************************** + * + * @struct: + * T1_BuilderRec + * + * @description: + * A structure used during glyph loading to store its outline. + * + * @fields: + * memory :: + * The current memory object. + * + * face :: + * The current face object. + * + * glyph :: + * The current glyph slot. + * + * loader :: + * XXX + * + * base :: + * The base glyph outline. + * + * current :: + * The current glyph outline. + * + * max_points :: + * maximum points in builder outline + * + * max_contours :: + * Maximum number of contours in builder outline. + * + * pos_x :: + * The horizontal translation (if composite glyph). + * + * pos_y :: + * The vertical translation (if composite glyph). + * + * left_bearing :: + * The left side bearing point. + * + * advance :: + * The horizontal advance vector. + * + * bbox :: + * Unused. + * + * parse_state :: + * An enumeration which controls the charstring parsing state. + * + * load_points :: + * If this flag is not set, no points are loaded. + * + * no_recurse :: + * Set but not used. + * + * metrics_only :: + * A boolean indicating that we only want to compute the metrics of a + * given glyph, not load all of its points. + * + * funcs :: + * An array of function pointers for the builder. + */ + typedef struct T1_BuilderRec_ + { + FT_Memory memory; + FT_Face face; + FT_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + T1_ParseState parse_state; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + + void* hints_funcs; /* hinter-specific */ + void* hints_globals; /* hinter-specific */ + + T1_Builder_FuncsRec funcs; + + } T1_BuilderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 0 + + /************************************************************************** + * + * T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine + * calls during glyph loading. + */ +#define T1_MAX_SUBRS_CALLS 8 + + + /************************************************************************** + * + * T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A + * minimum of 16 is required. + */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 + +#endif /* 0 */ + + + typedef struct T1_Decoder_ZoneRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + } T1_Decoder_ZoneRec, *T1_Decoder_Zone; + + + typedef struct T1_DecoderRec_* T1_Decoder; + typedef const struct T1_Decoder_FuncsRec_* T1_Decoder_Funcs; + + + typedef FT_Error + (*T1_Decoder_Callback)( T1_Decoder decoder, + FT_UInt glyph_index ); + + + typedef struct T1_Decoder_FuncsRec_ + { + FT_Error + (*init)( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback callback ); + + void + (*done)( T1_Decoder decoder ); + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + FT_Error + (*parse_charstrings_old)( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); +#else + FT_Error + (*parse_metrics)( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); +#endif + + FT_Error + (*parse_charstrings)( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + + + } T1_Decoder_FuncsRec; + + + typedef struct T1_DecoderRec_ + { + T1_BuilderRec builder; + + FT_Long stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Long* top; + + T1_Decoder_ZoneRec zones[T1_MAX_SUBRS_CALLS + 1]; + T1_Decoder_Zone zone; + + FT_Service_PsCMaps psnames; /* for seac */ + FT_UInt num_glyphs; + FT_Byte** glyph_names; + + FT_Int lenIV; /* internal for sub routine calls */ + FT_Int num_subrs; + FT_Byte** subrs; + FT_UInt* subrs_len; /* array of subrs length (optional) */ + FT_Hash subrs_hash; /* used if `num_subrs' was massaged */ + + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + PS_Blend blend; /* for multiple master support */ + + FT_Render_Mode hint_mode; + + T1_Decoder_Callback parse_callback; + T1_Decoder_FuncsRec funcs; + + FT_Long* buildchar; + FT_UInt len_buildchar; + + FT_Bool seac; + + FT_Generic cf2_instance; + + } T1_DecoderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct CFF_Builder_ CFF_Builder; + + + typedef FT_Error + (*CFF_Builder_Check_Points_Func)( CFF_Builder* builder, + FT_Int count ); + + typedef void + (*CFF_Builder_Add_Point_Func)( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + typedef FT_Error + (*CFF_Builder_Add_Point1_Func)( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + typedef FT_Error + (*CFF_Builder_Start_Point_Func)( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + typedef void + (*CFF_Builder_Close_Contour_Func)( CFF_Builder* builder ); + + typedef FT_Error + (*CFF_Builder_Add_Contour_Func)( CFF_Builder* builder ); + + typedef const struct CFF_Builder_FuncsRec_* CFF_Builder_Funcs; + + typedef struct CFF_Builder_FuncsRec_ + { + void + (*init)( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ); + + void + (*done)( CFF_Builder* builder ); + + CFF_Builder_Check_Points_Func check_points; + CFF_Builder_Add_Point_Func add_point; + CFF_Builder_Add_Point1_Func add_point1; + CFF_Builder_Add_Contour_Func add_contour; + CFF_Builder_Start_Point_Func start_point; + CFF_Builder_Close_Contour_Func close_contour; + + } CFF_Builder_FuncsRec; + + + /************************************************************************** + * + * @struct: + * CFF_Builder + * + * @description: + * A structure used during glyph loading to store its outline. + * + * @fields: + * memory :: + * The current memory object. + * + * face :: + * The current face object. + * + * glyph :: + * The current glyph slot. + * + * loader :: + * The current glyph loader. + * + * base :: + * The base glyph outline. + * + * current :: + * The current glyph outline. + * + * pos_x :: + * The horizontal translation (if composite glyph). + * + * pos_y :: + * The vertical translation (if composite glyph). + * + * left_bearing :: + * The left side bearing point. + * + * advance :: + * The horizontal advance vector. + * + * bbox :: + * Unused. + * + * path_begun :: + * A flag which indicates that a new path has begun. + * + * load_points :: + * If this flag is not set, no points are loaded. + * + * no_recurse :: + * Set but not used. + * + * metrics_only :: + * A boolean indicating that we only want to compute the metrics of a + * given glyph, not load all of its points. + * + * hints_funcs :: + * Auxiliary pointer for hinting. + * + * hints_globals :: + * Auxiliary pointer for hinting. + * + * funcs :: + * A table of method pointers for this object. + */ + struct CFF_Builder_ + { + FT_Memory memory; + TT_Face face; + CFF_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + + void* hints_funcs; /* hinter-specific */ + void* hints_globals; /* hinter-specific */ + + CFF_Builder_FuncsRec funcs; + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + +#define CFF_MAX_OPERANDS 48 +#define CFF_MAX_SUBRS_CALLS 16 /* maximum subroutine nesting; */ + /* only 10 are allowed but there exist */ + /* fonts like `HiraKakuProN-W3.ttf' */ + /* (Hiragino Kaku Gothic ProN W3; */ + /* 8.2d6e1; 2014-12-19) that exceed */ + /* this limit */ +#define CFF_MAX_TRANS_ELEMENTS 32 + + /* execution context charstring zone */ + + typedef struct CFF_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } CFF_Decoder_Zone; + + + typedef struct CFF_Decoder_ + { + CFF_Builder builder; + CFF_Font cff; + + FT_Fixed stack[CFF_MAX_OPERANDS + 1]; + FT_Fixed* top; + + CFF_Decoder_Zone zones[CFF_MAX_SUBRS_CALLS + 1]; + CFF_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + FT_Pos glyph_width; + FT_Pos nominal_width; + + FT_Bool read_width; + FT_Bool width_only; + FT_Int num_hints; + FT_Fixed buildchar[CFF_MAX_TRANS_ELEMENTS]; + + FT_UInt num_locals; + FT_UInt num_globals; + + FT_Int locals_bias; + FT_Int globals_bias; + + FT_Byte** locals; + FT_Byte** globals; + + FT_Byte** glyph_names; /* for pure CFF fonts only */ + FT_UInt num_glyphs; /* number of glyphs in font */ + + FT_Render_Mode hint_mode; + + FT_Bool seac; + + CFF_SubFont current_subfont; /* for current glyph_index */ + + CFF_Decoder_Get_Glyph_Callback get_glyph_callback; + CFF_Decoder_Free_Glyph_Callback free_glyph_callback; + + } CFF_Decoder; + + + typedef const struct CFF_Decoder_FuncsRec_* CFF_Decoder_Funcs; + + typedef struct CFF_Decoder_FuncsRec_ + { + void + (*init)( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode, + CFF_Decoder_Get_Glyph_Callback get_callback, + CFF_Decoder_Free_Glyph_Callback free_callback ); + + FT_Error + (*prepare)( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ); + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_Error + (*parse_charstrings_old)( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len, + FT_Bool in_dict ); +#endif + + FT_Error + (*parse_charstrings)( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + + } CFF_Decoder_FuncsRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** AFM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_ParserRec_* AFM_Parser; + + typedef struct AFM_Parser_FuncsRec_ + { + FT_Error + (*init)( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + + void + (*done)( AFM_Parser parser ); + + FT_Error + (*parse)( AFM_Parser parser ); + + } AFM_Parser_FuncsRec; + + + typedef struct AFM_StreamRec_* AFM_Stream; + + + /************************************************************************** + * + * @struct: + * AFM_ParserRec + * + * @description: + * An AFM_Parser is a parser for the AFM files. + * + * @fields: + * memory :: + * The object used for memory operations (alloc and realloc). + * + * stream :: + * This is an opaque object. + * + * FontInfo :: + * The result will be stored here. + * + * get_index :: + * A user provided function to get a glyph index by its name. + */ + typedef struct AFM_ParserRec_ + { + FT_Memory memory; + AFM_Stream stream; + + AFM_FontInfo FontInfo; + + FT_Int + (*get_index)( const char* name, + FT_Offset len, + void* user_data ); + + void* user_data; + + } AFM_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CHARMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct T1_CMap_ClassesRec_* T1_CMap_Classes; + + typedef struct T1_CMap_ClassesRec_ + { + FT_CMap_Class standard; + FT_CMap_Class expert; + FT_CMap_Class custom; + FT_CMap_Class unicode; + + } T1_CMap_ClassesRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PSAux Module Interface *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSAux_ServiceRec_ + { + /* don't use `PS_Table_Funcs' and friends to avoid compiler warnings */ + const PS_Table_FuncsRec* ps_table_funcs; + const PS_Parser_FuncsRec* ps_parser_funcs; + const T1_Builder_FuncsRec* t1_builder_funcs; + const T1_Decoder_FuncsRec* t1_decoder_funcs; + + void + (*t1_decrypt)( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + + FT_UInt32 + (*cff_random)( FT_UInt32 r ); + + void + (*ps_decoder_init)( PS_Decoder* ps_decoder, + void* decoder, + FT_Bool is_t1 ); + + void + (*t1_make_subfont)( FT_Face face, + PS_Private priv, + CFF_SubFont subfont ); + + T1_CMap_Classes t1_cmap_classes; + + /* fields after this comment line were added after version 2.1.10 */ + const AFM_Parser_FuncsRec* afm_parser_funcs; + + const CFF_Decoder_FuncsRec* cff_decoder_funcs; + + } PSAux_ServiceRec, *PSAux_Service; + + /* backward compatible type definition */ + typedef PSAux_ServiceRec PSAux_Interface; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Some convenience functions *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define IS_PS_NEWLINE( ch ) \ + ( (ch) == '\r' || \ + (ch) == '\n' ) + +#define IS_PS_SPACE( ch ) \ + ( (ch) == ' ' || \ + IS_PS_NEWLINE( ch ) || \ + (ch) == '\t' || \ + (ch) == '\f' || \ + (ch) == '\0' ) + +#define IS_PS_SPECIAL( ch ) \ + ( (ch) == '/' || \ + (ch) == '(' || (ch) == ')' || \ + (ch) == '<' || (ch) == '>' || \ + (ch) == '[' || (ch) == ']' || \ + (ch) == '{' || (ch) == '}' || \ + (ch) == '%' ) + +#define IS_PS_DELIM( ch ) \ + ( IS_PS_SPACE( ch ) || \ + IS_PS_SPECIAL( ch ) ) + +#define IS_PS_DIGIT( ch ) \ + ( (ch) >= '0' && (ch) <= '9' ) + +#define IS_PS_XDIGIT( ch ) \ + ( IS_PS_DIGIT( ch ) || \ + ( (ch) >= 'A' && (ch) <= 'F' ) || \ + ( (ch) >= 'a' && (ch) <= 'f' ) ) + +#define IS_PS_BASE85( ch ) \ + ( (ch) >= '!' && (ch) <= 'u' ) + +#define IS_PS_TOKEN( cur, limit, token ) \ + ( (char)(cur)[0] == (token)[0] && \ + ( (cur) + sizeof ( (token) ) == (limit) || \ + ( (cur) + sizeof( (token) ) < (limit) && \ + IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) ) && \ + ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 ) + + +FT_END_HEADER + +#endif /* PSAUX_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/pshints.h b/vendor/freetype/include/freetype/internal/pshints.h new file mode 100644 index 0000000..ededc4c --- /dev/null +++ b/vendor/freetype/include/freetype/internal/pshints.h @@ -0,0 +1,699 @@ +/**************************************************************************** + * + * pshints.h + * + * Interface to Postscript-specific (Type 1 and Type 2) hints + * recorders (specification only). These are used to support native + * T1/T2 hints in the 'type1', 'cid', and 'cff' font drivers. + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHINTS_H_ +#define PSHINTS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INTERNAL REPRESENTATION OF GLOBALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSH_GlobalsRec_* PSH_Globals; + + typedef FT_Error + (*PSH_Globals_NewFunc)( FT_Memory memory, + T1_Private* private_dict, + PSH_Globals* aglobals ); + + typedef void + (*PSH_Globals_SetScaleFunc)( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + + typedef void + (*PSH_Globals_DestroyFunc)( PSH_Globals globals ); + + + typedef struct PSH_Globals_FuncsRec_ + { + PSH_Globals_NewFunc create; + PSH_Globals_SetScaleFunc set_scale; + PSH_Globals_DestroyFunc destroy; + + } PSH_Globals_FuncsRec, *PSH_Globals_Funcs; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 1 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @type: + * T1_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 1 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T1_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the 'open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method ('stem', 'stem3', or 'reset'). Note that these functions do + * not return an error code. + * + * - Close the recording session by calling the 'close' method. It + * returns an error code if the hints were invalid or something strange + * happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * PostScript hinter. + * + */ + typedef struct T1_HintsRec_* T1_Hints; + + + /************************************************************************** + * + * @type: + * T1_Hints_Funcs + * + * @description: + * A pointer to the @T1_Hints_FuncsRec structure that defines the API of + * a given @T1_Hints object. + * + */ + typedef const struct T1_Hints_FuncsRec_* T1_Hints_Funcs; + + + /************************************************************************** + * + * @functype: + * T1_Hints_OpenFunc + * + * @description: + * A method of the @T1_Hints class used to prepare it for a new Type 1 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * @note: + * You should always call the @T1_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T1_Hints_OpenFunc)( T1_Hints hints ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_SetStemFunc + * + * @description: + * A method of the @T1_Hints class used to record a new horizontal or + * vertical stem. This corresponds to the Type 1 'hstem' and 'vstem' + * operators. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * coords :: + * Array of 2 coordinates in 16.16 format, used as (position,length) + * stem descriptor. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * 'coords[0]' is the absolute stem position (lowest coordinate); + * 'coords[1]' is the length. + * + * The length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a 'ghost' stem, according to the Type 1 + * specification. + * + * If the length is -21 (corresponding to a bottom ghost stem), then the + * real stem position is 'coords[0]+coords[1]'. + * + */ + typedef void + (*T1_Hints_SetStemFunc)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_SetStem3Func + * + * @description: + * A method of the @T1_Hints class used to record three + * counter-controlled horizontal or vertical stems at once. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems, 1 for vertical ones. + * + * coords :: + * An array of 6 values in 16.16 format, holding 3 (position,length) + * pairs for the counter-controlled stems. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * The lengths cannot be negative (ghost stems are never + * counter-controlled). + * + */ + typedef void + (*T1_Hints_SetStem3Func)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_ResetFunc + * + * @description: + * A method of the @T1_Hints class used to reset the stems hints in a + * recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph in which the + * previously defined hints apply. + * + */ + typedef void + (*T1_Hints_ResetFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_CloseFunc + * + * @description: + * A method of the @T1_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T1_Hints_CloseFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_ApplyFunc + * + * @description: + * A method of the @T1_Hints class used to apply hints to the + * corresponding glyph outline. Must be called once all hints have been + * recorded. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64 of pixels. + * + * The scaling transformation is taken from the 'globals' object which + * must correspond to the same font as the glyph. + * + */ + typedef FT_Error + (*T1_Hints_ApplyFunc)( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************** + * + * @struct: + * T1_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T1_Hints objects. + * + * @fields: + * hints :: + * A handle to the T1 Hints recorder. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stem :: + * The function to set a simple stem. + * + * stem3 :: + * The function to set counter-controlled stems. + * + * reset :: + * The function to reset stem hints. + * + * apply :: + * The function to apply the hints to the corresponding glyph outline. + * + */ + typedef struct T1_Hints_FuncsRec_ + { + T1_Hints hints; + T1_Hints_OpenFunc open; + T1_Hints_CloseFunc close; + T1_Hints_SetStemFunc stem; + T1_Hints_SetStem3Func stem3; + T1_Hints_ResetFunc reset; + T1_Hints_ApplyFunc apply; + + } T1_Hints_FuncsRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 2 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @type: + * T2_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 2 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T2_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the 'open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method ('stems', 'hintmask', 'counters'). Note that these functions + * do not return an error code. + * + * - Close the recording session by calling the 'close' method. It + * returns an error code if the hints were invalid or something strange + * happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * Postscript hinter. + * + */ + typedef struct T2_HintsRec_* T2_Hints; + + + /************************************************************************** + * + * @type: + * T2_Hints_Funcs + * + * @description: + * A pointer to the @T2_Hints_FuncsRec structure that defines the API of + * a given @T2_Hints object. + * + */ + typedef const struct T2_Hints_FuncsRec_* T2_Hints_Funcs; + + + /************************************************************************** + * + * @functype: + * T2_Hints_OpenFunc + * + * @description: + * A method of the @T2_Hints class used to prepare it for a new Type 2 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * @note: + * You should always call the @T2_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T2_Hints_OpenFunc)( T2_Hints hints ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_StemsFunc + * + * @description: + * A method of the @T2_Hints class used to set the table of stems in + * either the vertical or horizontal dimension. Equivalent to the + * 'hstem', 'vstem', 'hstemhm', and 'vstemhm' Type 2 operators. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * count :: + * The number of stems. + * + * coords :: + * An array of 'count' (position,length) pairs in 16.16 format. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * There are '2*count' elements in the 'coords' array. Each even element + * is an absolute position in font units, each odd element is a length in + * font units. + * + * A length can be negative, in which case it must be either -20 or -21. + * It is interpreted as a 'ghost' stem, according to the Type 1 + * specification. + * + */ + typedef void + (*T2_Hints_StemsFunc)( T2_Hints hints, + FT_UInt dimension, + FT_Int count, + FT_Fixed* coordinates ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_MaskFunc + * + * @description: + * A method of the @T2_Hints class used to set a given hintmask (this + * corresponds to the 'hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The glyph index of the last point to which the previously defined or + * activated hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point` should be 0. + * + * `bit_count` is the number of meaningful bits in the 'bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The 'bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_MaskFunc)( T2_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_CounterFunc + * + * @description: + * A method of the @T2_Hints class used to set a given counter mask (this + * corresponds to the 'hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * A glyph index of the last point to which the previously defined or + * active hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point` should be 0. + * + * `bit_count` is the number of meaningful bits in the 'bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The 'bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_CounterFunc)( T2_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_CloseFunc + * + * @description: + * A method of the @T2_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T2_Hints_CloseFunc)( T2_Hints hints, + FT_UInt end_point ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_ApplyFunc + * + * @description: + * A method of the @T2_Hints class used to apply hints to the + * corresponding glyph outline. Must be called after the 'close' method. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64 of pixels. + * + * The scaling transformation is taken from the 'globals' object which + * must correspond to the same font than the glyph. + * + */ + typedef FT_Error + (*T2_Hints_ApplyFunc)( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************** + * + * @struct: + * T2_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T2_Hints objects. + * + * @fields: + * hints :: + * A handle to the T2 hints recorder object. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stems :: + * The function to set the dimension's stems table. + * + * hintmask :: + * The function to set hint masks. + * + * counter :: + * The function to set counter masks. + * + * apply :: + * The function to apply the hints on the corresponding glyph outline. + * + */ + typedef struct T2_Hints_FuncsRec_ + { + T2_Hints hints; + T2_Hints_OpenFunc open; + T2_Hints_CloseFunc close; + T2_Hints_StemsFunc stems; + T2_Hints_MaskFunc hintmask; + T2_Hints_CounterFunc counter; + T2_Hints_ApplyFunc apply; + + } T2_Hints_FuncsRec; + + + /* */ + + + typedef struct PSHinter_Interface_ + { + PSH_Globals_Funcs (*get_globals_funcs)( FT_Module module ); + T1_Hints_Funcs (*get_t1_funcs) ( FT_Module module ); + T2_Hints_Funcs (*get_t2_funcs) ( FT_Module module ); + + } PSHinter_Interface; + + typedef PSHinter_Interface* PSHinter_Service; + + +#define FT_DEFINE_PSHINTER_INTERFACE( \ + class_, \ + get_globals_funcs_, \ + get_t1_funcs_, \ + get_t2_funcs_ ) \ + static const PSHinter_Interface class_ = \ + { \ + get_globals_funcs_, \ + get_t1_funcs_, \ + get_t2_funcs_ \ + }; + + +FT_END_HEADER + +#endif /* PSHINTS_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svbdf.h b/vendor/freetype/include/freetype/internal/services/svbdf.h new file mode 100644 index 0000000..bf0c1dc --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svbdf.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * + * svbdf.h + * + * The FreeType BDF services (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVBDF_H_ +#define SVBDF_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_BDF "bdf" + + typedef FT_Error + (*FT_BDF_GetCharsetIdFunc)( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + typedef FT_Error + (*FT_BDF_GetPropertyFunc)( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + + FT_DEFINE_SERVICE( BDF ) + { + FT_BDF_GetCharsetIdFunc get_charset_id; + FT_BDF_GetPropertyFunc get_property; + }; + + +#define FT_DEFINE_SERVICE_BDFRec( class_, \ + get_charset_id_, \ + get_property_ ) \ + static const FT_Service_BDFRec class_ = \ + { \ + get_charset_id_, get_property_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVBDF_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svcfftl.h b/vendor/freetype/include/freetype/internal/services/svcfftl.h new file mode 100644 index 0000000..4a20498 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svcfftl.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * svcfftl.h + * + * The FreeType CFF tables loader service (specification). + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVCFFTL_H_ +#define SVCFFTL_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_CFF_LOAD "cff-load" + + + typedef FT_UShort + (*FT_Get_Standard_Encoding_Func)( FT_UInt charcode ); + + typedef FT_Error + (*FT_Load_Private_Dict_Func)( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + typedef FT_Byte + (*FT_FD_Select_Get_Func)( CFF_FDSelect fdselect, + FT_UInt glyph_index ); + + typedef FT_Bool + (*FT_Blend_Check_Vector_Func)( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + typedef FT_Error + (*FT_Blend_Build_Vector_Func)( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + + FT_DEFINE_SERVICE( CFFLoad ) + { + FT_Get_Standard_Encoding_Func get_standard_encoding; + FT_Load_Private_Dict_Func load_private_dict; + FT_FD_Select_Get_Func fd_select_get; + FT_Blend_Check_Vector_Func blend_check_vector; + FT_Blend_Build_Vector_Func blend_build_vector; + }; + + +#define FT_DEFINE_SERVICE_CFFLOADREC( class_, \ + get_standard_encoding_, \ + load_private_dict_, \ + fd_select_get_, \ + blend_check_vector_, \ + blend_build_vector_ ) \ + static const FT_Service_CFFLoadRec class_ = \ + { \ + get_standard_encoding_, \ + load_private_dict_, \ + fd_select_get_, \ + blend_check_vector_, \ + blend_build_vector_ \ + }; + + +FT_END_HEADER + + +#endif + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svcid.h b/vendor/freetype/include/freetype/internal/services/svcid.h new file mode 100644 index 0000000..06d0cb8 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svcid.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * + * svcid.h + * + * The FreeType CID font services (specification). + * + * Copyright (C) 2007-2023 by + * Derek Clegg and Michael Toftdal. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVCID_H_ +#define SVCID_H_ + +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_CID "CID" + + typedef FT_Error + (*FT_CID_GetRegistryOrderingSupplementFunc)( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ); + typedef FT_Error + (*FT_CID_GetIsInternallyCIDKeyedFunc)( FT_Face face, + FT_Bool *is_cid ); + typedef FT_Error + (*FT_CID_GetCIDFromGlyphIndexFunc)( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); + + FT_DEFINE_SERVICE( CID ) + { + FT_CID_GetRegistryOrderingSupplementFunc get_ros; + FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid; + FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index; + }; + + +#define FT_DEFINE_SERVICE_CIDREC( class_, \ + get_ros_, \ + get_is_cid_, \ + get_cid_from_glyph_index_ ) \ + static const FT_Service_CIDRec class_ = \ + { \ + get_ros_, get_is_cid_, get_cid_from_glyph_index_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVCID_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svfntfmt.h b/vendor/freetype/include/freetype/internal/services/svfntfmt.h new file mode 100644 index 0000000..bc45e80 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svfntfmt.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * svfntfmt.h + * + * The FreeType font format service (specification only). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVFNTFMT_H_ +#define SVFNTFMT_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * A trivial service used to return the name of a face's font driver, + * according to the XFree86 nomenclature. Note that the service data is a + * simple constant string pointer. + */ + +#define FT_SERVICE_ID_FONT_FORMAT "font-format" + +#define FT_FONT_FORMAT_TRUETYPE "TrueType" +#define FT_FONT_FORMAT_TYPE_1 "Type 1" +#define FT_FONT_FORMAT_BDF "BDF" +#define FT_FONT_FORMAT_PCF "PCF" +#define FT_FONT_FORMAT_TYPE_42 "Type 42" +#define FT_FONT_FORMAT_CID "CID Type 1" +#define FT_FONT_FORMAT_CFF "CFF" +#define FT_FONT_FORMAT_PFR "PFR" +#define FT_FONT_FORMAT_WINFNT "Windows FNT" + + /* */ + + +FT_END_HEADER + + +#endif /* SVFNTFMT_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svgldict.h b/vendor/freetype/include/freetype/internal/services/svgldict.h new file mode 100644 index 0000000..6437abf --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svgldict.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * + * svgldict.h + * + * The FreeType glyph dictionary services (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVGLDICT_H_ +#define SVGLDICT_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * A service used to retrieve glyph names, as well as to find the index of + * a given glyph name in a font. + * + */ + +#define FT_SERVICE_ID_GLYPH_DICT "glyph-dict" + + + typedef FT_Error + (*FT_GlyphDict_GetNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_GlyphDict_NameIndexFunc)( FT_Face face, + const FT_String* glyph_name ); + + + FT_DEFINE_SERVICE( GlyphDict ) + { + FT_GlyphDict_GetNameFunc get_name; + FT_GlyphDict_NameIndexFunc name_index; /* optional */ + }; + + +#define FT_DEFINE_SERVICE_GLYPHDICTREC( class_, \ + get_name_, \ + name_index_ ) \ + static const FT_Service_GlyphDictRec class_ = \ + { \ + get_name_, name_index_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVGLDICT_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svgxval.h b/vendor/freetype/include/freetype/internal/services/svgxval.h new file mode 100644 index 0000000..31016af --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svgxval.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * + * svgxval.h + * + * FreeType API for validating TrueTypeGX/AAT tables (specification). + * + * Copyright (C) 2004-2023 by + * Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef SVGXVAL_H_ +#define SVGXVAL_H_ + +#include +#include + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_GX_VALIDATE "truetypegx-validate" +#define FT_SERVICE_ID_CLASSICKERN_VALIDATE "classickern-validate" + + typedef FT_Error + (*gxv_validate_func)( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + typedef FT_Error + (*ckern_validate_func)( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes *ckern_table ); + + + FT_DEFINE_SERVICE( GXvalidate ) + { + gxv_validate_func validate; + }; + + FT_DEFINE_SERVICE( CKERNvalidate ) + { + ckern_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVGXVAL_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svkern.h b/vendor/freetype/include/freetype/internal/services/svkern.h new file mode 100644 index 0000000..bcabbc3 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svkern.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * svkern.h + * + * The FreeType Kerning service (specification). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVKERN_H_ +#define SVKERN_H_ + +#include +#include + + +FT_BEGIN_HEADER + +#define FT_SERVICE_ID_KERNING "kerning" + + + typedef FT_Error + (*FT_Kerning_TrackGetFunc)( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + FT_DEFINE_SERVICE( Kerning ) + { + FT_Kerning_TrackGetFunc get_track; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVKERN_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svmetric.h b/vendor/freetype/include/freetype/internal/services/svmetric.h new file mode 100644 index 0000000..167617e --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svmetric.h @@ -0,0 +1,131 @@ +/**************************************************************************** + * + * svmetric.h + * + * The FreeType services for metrics variations (specification). + * + * Copyright (C) 2016-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVMETRIC_H_ +#define SVMETRIC_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * A service to manage the `HVAR, `MVAR', and `VVAR' OpenType tables. + * + */ + +#define FT_SERVICE_ID_METRICS_VARIATIONS "metrics-variations" + + + /* HVAR */ + + typedef FT_Error + (*FT_HAdvance_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_LSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_RSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + /* VVAR */ + + typedef FT_Error + (*FT_VAdvance_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_TSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_BSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_VOrg_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + /* MVAR */ + + typedef void + (*FT_Metrics_Adjust_Func)( FT_Face face ); + + typedef FT_Error + (*FT_Size_Reset_Func)( FT_Size size ); + + + FT_DEFINE_SERVICE( MetricsVariations ) + { + FT_HAdvance_Adjust_Func hadvance_adjust; + FT_LSB_Adjust_Func lsb_adjust; + FT_RSB_Adjust_Func rsb_adjust; + + FT_VAdvance_Adjust_Func vadvance_adjust; + FT_TSB_Adjust_Func tsb_adjust; + FT_BSB_Adjust_Func bsb_adjust; + FT_VOrg_Adjust_Func vorg_adjust; + + FT_Metrics_Adjust_Func metrics_adjust; + FT_Size_Reset_Func size_reset; + }; + + +#define FT_DEFINE_SERVICE_METRICSVARIATIONSREC( class_, \ + hadvance_adjust_, \ + lsb_adjust_, \ + rsb_adjust_, \ + vadvance_adjust_, \ + tsb_adjust_, \ + bsb_adjust_, \ + vorg_adjust_, \ + metrics_adjust_, \ + size_reset_ ) \ + static const FT_Service_MetricsVariationsRec class_ = \ + { \ + hadvance_adjust_, \ + lsb_adjust_, \ + rsb_adjust_, \ + vadvance_adjust_, \ + tsb_adjust_, \ + bsb_adjust_, \ + vorg_adjust_, \ + metrics_adjust_, \ + size_reset_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVMETRIC_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svmm.h b/vendor/freetype/include/freetype/internal/services/svmm.h new file mode 100644 index 0000000..7e76ab8 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svmm.h @@ -0,0 +1,214 @@ +/**************************************************************************** + * + * svmm.h + * + * The FreeType Multiple Masters and GX var services (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVMM_H_ +#define SVMM_H_ + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /* + * A service used to manage multiple-masters data in a given face. + * + * See the related APIs in `ftmm.h' (FT_MULTIPLE_MASTERS_H). + * + */ + +#define FT_SERVICE_ID_MULTI_MASTERS "multi-masters" + + + typedef FT_Error + (*FT_Get_MM_Func)( FT_Face face, + FT_Multi_Master* master ); + + typedef FT_Error + (*FT_Get_MM_Var_Func)( FT_Face face, + FT_MM_Var* *master ); + + typedef FT_Error + (*FT_Set_MM_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + /* use return value -1 to indicate that the new coordinates */ + /* are equal to the current ones; no changes are thus needed */ + typedef FT_Error + (*FT_Set_Var_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + /* use return value -1 to indicate that the new coordinates */ + /* are equal to the current ones; no changes are thus needed */ + typedef FT_Error + (*FT_Set_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Get_Var_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Set_Named_Instance_Func)( FT_Face face, + FT_UInt instance_index ); + + typedef FT_Error + (*FT_Get_Default_Named_Instance_Func)( FT_Face face, + FT_UInt *instance_index ); + + typedef FT_Error + (*FT_Get_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Get_Var_Blend_Func)( FT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ); + + typedef void + (*FT_Done_Blend_Func)( FT_Face face ); + + typedef FT_Error + (*FT_Set_MM_WeightVector_Func)( FT_Face face, + FT_UInt len, + FT_Fixed* weight_vector ); + + typedef FT_Error + (*FT_Get_MM_WeightVector_Func)( FT_Face face, + FT_UInt* len, + FT_Fixed* weight_vector ); + + typedef void + (*FT_Construct_PS_Name_Func)( FT_Face face ); + + typedef FT_Error + (*FT_Var_Load_Delta_Set_Idx_Map_Func)( FT_Face face, + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ); + + typedef FT_Error + (*FT_Var_Load_Item_Var_Store_Func)( FT_Face face, + FT_ULong offset, + GX_ItemVarStore itemStore ); + + typedef FT_ItemVarDelta + (*FT_Var_Get_Item_Delta_Func)( FT_Face face, + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ); + + typedef void + (*FT_Var_Done_Item_Var_Store_Func)( FT_Face face, + GX_ItemVarStore itemStore ); + + typedef void + (*FT_Var_Done_Delta_Set_Idx_Map_Func)( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ); + + + FT_DEFINE_SERVICE( MultiMasters ) + { + FT_Get_MM_Func get_mm; + FT_Set_MM_Design_Func set_mm_design; + FT_Set_MM_Blend_Func set_mm_blend; + FT_Get_MM_Blend_Func get_mm_blend; + FT_Get_MM_Var_Func get_mm_var; + FT_Set_Var_Design_Func set_var_design; + FT_Get_Var_Design_Func get_var_design; + FT_Set_Named_Instance_Func set_named_instance; + FT_Get_Default_Named_Instance_Func get_default_named_instance; + FT_Set_MM_WeightVector_Func set_mm_weightvector; + FT_Get_MM_WeightVector_Func get_mm_weightvector; + + /* for internal use; only needed for code sharing between modules */ + FT_Construct_PS_Name_Func construct_ps_name; + FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map; + FT_Var_Load_Item_Var_Store_Func load_item_var_store; + FT_Var_Get_Item_Delta_Func get_item_delta; + FT_Var_Done_Item_Var_Store_Func done_item_var_store; + FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_idx_map; + FT_Get_Var_Blend_Func get_var_blend; + FT_Done_Blend_Func done_blend; + }; + + +#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_named_instance_, \ + get_default_named_instance_, \ + set_mm_weightvector_, \ + get_mm_weightvector_, \ + \ + construct_ps_name_, \ + load_delta_set_idx_map_, \ + load_item_var_store_, \ + get_item_delta_, \ + done_item_var_store_, \ + done_delta_set_idx_map_, \ + get_var_blend_, \ + done_blend_ ) \ + static const FT_Service_MultiMastersRec class_ = \ + { \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_named_instance_, \ + get_default_named_instance_, \ + set_mm_weightvector_, \ + get_mm_weightvector_, \ + \ + construct_ps_name_, \ + load_delta_set_idx_map_, \ + load_item_var_store_, \ + get_item_delta_, \ + done_item_var_store_, \ + done_delta_set_idx_map_, \ + get_var_blend_, \ + done_blend_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVMM_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svotval.h b/vendor/freetype/include/freetype/internal/services/svotval.h new file mode 100644 index 0000000..a4683cd --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svotval.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * svotval.h + * + * The FreeType OpenType validation service (specification). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVOTVAL_H_ +#define SVOTVAL_H_ + +#include +#include + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_OPENTYPE_VALIDATE "opentype-validate" + + + typedef FT_Error + (*otv_validate_func)( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *base, + FT_Bytes *gdef, + FT_Bytes *gpos, + FT_Bytes *gsub, + FT_Bytes *jstf ); + + + FT_DEFINE_SERVICE( OTvalidate ) + { + otv_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVOTVAL_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svpfr.h b/vendor/freetype/include/freetype/internal/services/svpfr.h new file mode 100644 index 0000000..fd189c7 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svpfr.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * + * svpfr.h + * + * Internal PFR service functions (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPFR_H_ +#define SVPFR_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_PFR_METRICS "pfr-metrics" + + + typedef FT_Error + (*FT_PFR_GetMetricsFunc)( FT_Face face, + FT_UInt *aoutline, + FT_UInt *ametrics, + FT_Fixed *ax_scale, + FT_Fixed *ay_scale ); + + typedef FT_Error + (*FT_PFR_GetKerningFunc)( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + typedef FT_Error + (*FT_PFR_GetAdvanceFunc)( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + + FT_DEFINE_SERVICE( PfrMetrics ) + { + FT_PFR_GetMetricsFunc get_metrics; + FT_PFR_GetKerningFunc get_kerning; + FT_PFR_GetAdvanceFunc get_advance; + + }; + + +FT_END_HEADER + +#endif /* SVPFR_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svpostnm.h b/vendor/freetype/include/freetype/internal/services/svpostnm.h new file mode 100644 index 0000000..2b8f6df --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svpostnm.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * + * svpostnm.h + * + * The FreeType PostScript name services (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPOSTNM_H_ +#define SVPOSTNM_H_ + +#include + + +FT_BEGIN_HEADER + + /* + * A trivial service used to retrieve the PostScript name of a given font + * when available. The `get_name' field should never be `NULL`. + * + * The corresponding function can return `NULL` to indicate that the + * PostScript name is not available. + * + * The name is owned by the face and will be destroyed with it. + */ + +#define FT_SERVICE_ID_POSTSCRIPT_FONT_NAME "postscript-font-name" + + + typedef const char* + (*FT_PsName_GetFunc)( FT_Face face ); + + + FT_DEFINE_SERVICE( PsFontName ) + { + FT_PsName_GetFunc get_ps_font_name; + }; + + +#define FT_DEFINE_SERVICE_PSFONTNAMEREC( class_, get_ps_font_name_ ) \ + static const FT_Service_PsFontNameRec class_ = \ + { \ + get_ps_font_name_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPOSTNM_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svprop.h b/vendor/freetype/include/freetype/internal/services/svprop.h new file mode 100644 index 0000000..932ce32 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svprop.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * + * svprop.h + * + * The FreeType property service (specification). + * + * Copyright (C) 2012-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPROP_H_ +#define SVPROP_H_ + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_PROPERTIES "properties" + + + typedef FT_Error + (*FT_Properties_SetFunc)( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ); + + typedef FT_Error + (*FT_Properties_GetFunc)( FT_Module module, + const char* property_name, + void* value ); + + + FT_DEFINE_SERVICE( Properties ) + { + FT_Properties_SetFunc set_property; + FT_Properties_GetFunc get_property; + }; + + +#define FT_DEFINE_SERVICE_PROPERTIESREC( class_, \ + set_property_, \ + get_property_ ) \ + static const FT_Service_PropertiesRec class_ = \ + { \ + set_property_, \ + get_property_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPROP_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svpscmap.h b/vendor/freetype/include/freetype/internal/services/svpscmap.h new file mode 100644 index 0000000..6e599f3 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svpscmap.h @@ -0,0 +1,145 @@ +/**************************************************************************** + * + * svpscmap.h + * + * The FreeType PostScript charmap service (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPSCMAP_H_ +#define SVPSCMAP_H_ + +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_CMAPS "postscript-cmaps" + + + /* + * Adobe glyph name to unicode value. + */ + typedef FT_UInt32 + (*PS_Unicode_ValueFunc)( const char* glyph_name ); + + /* + * Macintosh name id to glyph name. `NULL` if invalid index. + */ + typedef const char* + (*PS_Macintosh_NameFunc)( FT_UInt name_index ); + + /* + * Adobe standard string ID to glyph name. `NULL` if invalid index. + */ + typedef const char* + (*PS_Adobe_Std_StringsFunc)( FT_UInt string_index ); + + + /* + * Simple unicode -> glyph index charmap built from font glyph names table. + */ + typedef struct PS_UniMap_ + { + FT_UInt32 unicode; /* bit 31 set: is glyph variant */ + FT_UInt glyph_index; + + } PS_UniMap; + + + typedef struct PS_UnicodesRec_* PS_Unicodes; + + typedef struct PS_UnicodesRec_ + { + FT_CMapRec cmap; + FT_UInt num_maps; + PS_UniMap* maps; + + } PS_UnicodesRec; + + + /* + * A function which returns a glyph name for a given index. Returns + * `NULL` if invalid index. + */ + typedef const char* + (*PS_GetGlyphNameFunc)( FT_Pointer data, + FT_UInt string_index ); + + /* + * A function used to release the glyph name returned by + * PS_GetGlyphNameFunc, when needed + */ + typedef void + (*PS_FreeGlyphNameFunc)( FT_Pointer data, + const char* name ); + + typedef FT_Error + (*PS_Unicodes_InitFunc)( FT_Memory memory, + PS_Unicodes unicodes, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ); + + typedef FT_UInt + (*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes, + FT_UInt32 unicode ); + + typedef FT_UInt + (*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes, + FT_UInt32 *unicode ); + + + FT_DEFINE_SERVICE( PsCMaps ) + { + PS_Unicode_ValueFunc unicode_value; + + PS_Unicodes_InitFunc unicodes_init; + PS_Unicodes_CharIndexFunc unicodes_char_index; + PS_Unicodes_CharNextFunc unicodes_char_next; + + PS_Macintosh_NameFunc macintosh_name; + PS_Adobe_Std_StringsFunc adobe_std_strings; + const unsigned short* adobe_std_encoding; + const unsigned short* adobe_expert_encoding; + }; + + +#define FT_DEFINE_SERVICE_PSCMAPSREC( class_, \ + unicode_value_, \ + unicodes_init_, \ + unicodes_char_index_, \ + unicodes_char_next_, \ + macintosh_name_, \ + adobe_std_strings_, \ + adobe_std_encoding_, \ + adobe_expert_encoding_ ) \ + static const FT_Service_PsCMapsRec class_ = \ + { \ + unicode_value_, unicodes_init_, \ + unicodes_char_index_, unicodes_char_next_, macintosh_name_, \ + adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPSCMAP_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svpsinfo.h b/vendor/freetype/include/freetype/internal/services/svpsinfo.h new file mode 100644 index 0000000..09c4cdc --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svpsinfo.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * + * svpsinfo.h + * + * The FreeType PostScript info service (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPSINFO_H_ +#define SVPSINFO_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_INFO "postscript-info" + + + typedef FT_Error + (*PS_GetFontInfoFunc)( FT_Face face, + PS_FontInfoRec* afont_info ); + + typedef FT_Error + (*PS_GetFontExtraFunc)( FT_Face face, + PS_FontExtraRec* afont_extra ); + + typedef FT_Int + (*PS_HasGlyphNamesFunc)( FT_Face face ); + + typedef FT_Error + (*PS_GetFontPrivateFunc)( FT_Face face, + PS_PrivateRec* afont_private ); + + typedef FT_Long + (*PS_GetFontValueFunc)( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ); + + + FT_DEFINE_SERVICE( PsInfo ) + { + PS_GetFontInfoFunc ps_get_font_info; + PS_GetFontExtraFunc ps_get_font_extra; + PS_HasGlyphNamesFunc ps_has_glyph_names; + PS_GetFontPrivateFunc ps_get_font_private; + PS_GetFontValueFunc ps_get_font_value; + }; + + +#define FT_DEFINE_SERVICE_PSINFOREC( class_, \ + get_font_info_, \ + ps_get_font_extra_, \ + has_glyph_names_, \ + get_font_private_, \ + get_font_value_ ) \ + static const FT_Service_PsInfoRec class_ = \ + { \ + get_font_info_, ps_get_font_extra_, has_glyph_names_, \ + get_font_private_, get_font_value_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPSINFO_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svsfnt.h b/vendor/freetype/include/freetype/internal/services/svsfnt.h new file mode 100644 index 0000000..f98df2e --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svsfnt.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * + * svsfnt.h + * + * The FreeType SFNT table loading service (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVSFNT_H_ +#define SVSFNT_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_SFNT_TABLE "sfnt-table" + + + /* + * Used to implement FT_Load_Sfnt_Table(). + */ + typedef FT_Error + (*FT_SFNT_TableLoadFunc)( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + /* + * Used to implement FT_Get_Sfnt_Table(). + */ + typedef void* + (*FT_SFNT_TableGetFunc)( FT_Face face, + FT_Sfnt_Tag tag ); + + + /* + * Used to implement FT_Sfnt_Table_Info(). + */ + typedef FT_Error + (*FT_SFNT_TableInfoFunc)( FT_Face face, + FT_UInt idx, + FT_ULong *tag, + FT_ULong *offset, + FT_ULong *length ); + + + FT_DEFINE_SERVICE( SFNT_Table ) + { + FT_SFNT_TableLoadFunc load_table; + FT_SFNT_TableGetFunc get_table; + FT_SFNT_TableInfoFunc table_info; + }; + + +#define FT_DEFINE_SERVICE_SFNT_TABLEREC( class_, load_, get_, info_ ) \ + static const FT_Service_SFNT_TableRec class_ = \ + { \ + load_, get_, info_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVSFNT_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svttcmap.h b/vendor/freetype/include/freetype/internal/services/svttcmap.h new file mode 100644 index 0000000..5f9eb02 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svttcmap.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * svttcmap.h + * + * The FreeType TrueType/sfnt cmap extra information service. + * + * Copyright (C) 2003-2023 by + * Masatake YAMATO, Redhat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/* Development of this service is support of + Information-technology Promotion Agency, Japan. */ + +#ifndef SVTTCMAP_H_ +#define SVTTCMAP_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_CMAP "tt-cmaps" + + + /************************************************************************** + * + * @struct: + * TT_CMapInfo + * + * @description: + * A structure used to store TrueType/sfnt specific cmap information + * which is not covered by the generic @FT_CharMap structure. This + * structure can be accessed with the @FT_Get_TT_CMap_Info function. + * + * @fields: + * language :: + * The language ID used in Mac fonts. Definitions of values are in + * `ttnameid.h`. + * + * format :: + * The cmap format. OpenType 1.6 defines the formats 0 (byte encoding + * table), 2~(high-byte mapping through table), 4~(segment mapping to + * delta values), 6~(trimmed table mapping), 8~(mixed 16-bit and 32-bit + * coverage), 10~(trimmed array), 12~(segmented coverage), 13~(last + * resort font), and 14 (Unicode Variation Sequences). + */ + typedef struct TT_CMapInfo_ + { + FT_ULong language; + FT_Long format; + + } TT_CMapInfo; + + + typedef FT_Error + (*TT_CMap_Info_GetFunc)( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + + FT_DEFINE_SERVICE( TTCMaps ) + { + TT_CMap_Info_GetFunc get_cmap_info; + }; + + +#define FT_DEFINE_SERVICE_TTCMAPSREC( class_, get_cmap_info_ ) \ + static const FT_Service_TTCMapsRec class_ = \ + { \ + get_cmap_info_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVTTCMAP_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svtteng.h b/vendor/freetype/include/freetype/internal/services/svtteng.h new file mode 100644 index 0000000..ad577cb --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svtteng.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * + * svtteng.h + * + * The FreeType TrueType engine query service (specification). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVTTENG_H_ +#define SVTTENG_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_TRUETYPE_ENGINE "truetype-engine" + + /* + * Used to implement FT_Get_TrueType_Engine_Type + */ + + FT_DEFINE_SERVICE( TrueTypeEngine ) + { + FT_TrueTypeEngineType engine_type; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVTTENG_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svttglyf.h b/vendor/freetype/include/freetype/internal/services/svttglyf.h new file mode 100644 index 0000000..ca6fff7 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svttglyf.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * svttglyf.h + * + * The FreeType TrueType glyph service. + * + * Copyright (C) 2007-2023 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef SVTTGLYF_H_ +#define SVTTGLYF_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_GLYF "tt-glyf" + + + typedef FT_ULong + (*TT_Glyf_GetLocationFunc)( FT_Face face, + FT_UInt gindex, + FT_ULong *psize ); + + FT_DEFINE_SERVICE( TTGlyf ) + { + TT_Glyf_GetLocationFunc get_location; + }; + + +#define FT_DEFINE_SERVICE_TTGLYFREC( class_, get_location_ ) \ + static const FT_Service_TTGlyfRec class_ = \ + { \ + get_location_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVTTGLYF_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/services/svwinfnt.h b/vendor/freetype/include/freetype/internal/services/svwinfnt.h new file mode 100644 index 0000000..002923f --- /dev/null +++ b/vendor/freetype/include/freetype/internal/services/svwinfnt.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * svwinfnt.h + * + * The FreeType Windows FNT/FONT service (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVWINFNT_H_ +#define SVWINFNT_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_WINFNT "winfonts" + + typedef FT_Error + (*FT_WinFnt_GetHeaderFunc)( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + + FT_DEFINE_SERVICE( WinFnt ) + { + FT_WinFnt_GetHeaderFunc get_header; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVWINFNT_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/sfnt.h b/vendor/freetype/include/freetype/internal/sfnt.h new file mode 100644 index 0000000..a2d4e15 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/sfnt.h @@ -0,0 +1,1092 @@ +/**************************************************************************** + * + * sfnt.h + * + * High-level 'sfnt' driver interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFNT_H_ +#define SFNT_H_ + + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @functype: + * TT_Init_Face_Func + * + * @description: + * First part of the SFNT face object initialization. This finds the + * face in a SFNT file or collection, and load its format tag in + * face->format_tag. + * + * @input: + * stream :: + * The input stream. + * + * face :: + * A handle to the target face object. + * + * face_index :: + * The index of the TrueType font, if we are opening a collection, in + * bits 0-15. The numbered instance index~+~1 of a GX (sub)font, if + * applicable, in bits 16-30. + * + * num_params :: + * The number of additional parameters. + * + * params :: + * Optional additional parameters. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The stream cursor must be at the font file's origin. + * + * This function recognizes fonts embedded in a 'TrueType collection'. + * + * Once the format tag has been validated by the font driver, it should + * then call the TT_Load_Face_Func() callback to read the rest of the + * SFNT tables in the object. + */ + typedef FT_Error + (*TT_Init_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Face_Func + * + * @description: + * Second part of the SFNT face object initialization. This loads the + * common SFNT tables (head, OS/2, maxp, metrics, etc.) in the face + * object. + * + * @input: + * stream :: + * The input stream. + * + * face :: + * A handle to the target face object. + * + * face_index :: + * The index of the TrueType font, if we are opening a collection, in + * bits 0-15. The numbered instance index~+~1 of a GX (sub)font, if + * applicable, in bits 16-30. + * + * num_params :: + * The number of additional parameters. + * + * params :: + * Optional additional parameters. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function must be called after TT_Init_Face_Func(). + */ + typedef FT_Error + (*TT_Load_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /************************************************************************** + * + * @functype: + * TT_Done_Face_Func + * + * @description: + * A callback used to delete the common SFNT data from a face. + * + * @input: + * face :: + * A handle to the target face object. + * + * @note: + * This function does NOT destroy the face object. + */ + typedef void + (*TT_Done_Face_Func)( TT_Face face ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Any_Func + * + * @description: + * Load any font table into client memory. + * + * @input: + * face :: + * The face object to look for. + * + * tag :: + * The tag of table to load. Use the value 0 if you want to access the + * whole font file, else set this parameter to a valid TrueType table + * tag that you can forge with the MAKE_TT_TAG macro. + * + * offset :: + * The starting offset in the table (or the file if tag == 0). + * + * length :: + * The address of the decision variable: + * + * If `length == NULL`: Loads the whole table. Returns an error if + * 'offset' == 0! + * + * If `*length == 0`: Exits immediately; returning the length of the + * given table or of the font file, depending on the value of 'tag'. + * + * If `*length != 0`: Loads the next 'length' bytes of table or font, + * starting at offset 'offset' (in table or font too). + * + * @output: + * buffer :: + * The address of target buffer. + * + * @return: + * TrueType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Any_Func)( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte *buffer, + FT_ULong* length ); + + + /************************************************************************** + * + * @functype: + * TT_Find_SBit_Image_Func + * + * @description: + * Check whether an embedded bitmap (an 'sbit') exists for a given glyph, + * at a given strike. + * + * @input: + * face :: + * The target face object. + * + * glyph_index :: + * The glyph index. + * + * strike_index :: + * The current strike index. + * + * @output: + * arange :: + * The SBit range containing the glyph index. + * + * astrike :: + * The SBit strike containing the glyph index. + * + * aglyph_offset :: + * The offset of the glyph data in 'EBDT' table. + * + * @return: + * FreeType error code. 0 means success. Returns + * SFNT_Err_Invalid_Argument if no sbit exists for the requested glyph. + */ + typedef FT_Error + (*TT_Find_SBit_Image_Func)( TT_Face face, + FT_UInt glyph_index, + FT_ULong strike_index, + TT_SBit_Range *arange, + TT_SBit_Strike *astrike, + FT_ULong *aglyph_offset ); + + + /************************************************************************** + * + * @functype: + * TT_Load_SBit_Metrics_Func + * + * @description: + * Get the big metrics for a given embedded bitmap. + * + * @input: + * stream :: + * The input stream. + * + * range :: + * The SBit range containing the glyph. + * + * @output: + * big_metrics :: + * A big SBit metrics structure for the glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The stream cursor must be positioned at the glyph's offset within the + * 'EBDT' table before the call. + * + * If the image format uses variable metrics, the stream cursor is + * positioned just after the metrics header in the 'EBDT' table on + * function exit. + */ + typedef FT_Error + (*TT_Load_SBit_Metrics_Func)( FT_Stream stream, + TT_SBit_Range range, + TT_SBit_Metrics metrics ); + + + /************************************************************************** + * + * @functype: + * TT_Load_SBit_Image_Func + * + * @description: + * Load a given glyph sbit image from the font resource. This also + * returns its metrics. + * + * @input: + * face :: + * The target face object. + * + * strike_index :: + * The strike index. + * + * glyph_index :: + * The current glyph index. + * + * load_flags :: + * The current load flags. + * + * stream :: + * The input stream. + * + * @output: + * amap :: + * The target pixmap. + * + * ametrics :: + * A big sbit metrics structure for the glyph image. + * + * @return: + * FreeType error code. 0 means success. Returns an error if no glyph + * sbit exists for the index. + * + * @note: + * The `map.buffer` field is always freed before the glyph is loaded. + */ + typedef FT_Error + (*TT_Load_SBit_Image_Func)( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *amap, + TT_SBit_MetricsRec *ametrics ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Svg_Doc_Func + * + * @description: + * Scan the SVG document list to find the document containing the glyph + * that has the ID 'glyph*XXX*', where *XXX* is the value of + * `glyph_index` as a decimal integer. + * + * @inout: + * glyph :: + * The glyph slot from which pointers to the SVG document list is to be + * grabbed. The results are stored back in the slot. + * + * @input: + * glyph_index :: + * The index of the glyph that is to be looked up. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Svg_Doc_Func)( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + + + /************************************************************************** + * + * @functype: + * TT_Set_SBit_Strike_Func + * + * @description: + * Select an sbit strike for a given size request. + * + * @input: + * face :: + * The target face object. + * + * req :: + * The size request. + * + * @output: + * astrike_index :: + * The index of the sbit strike. + * + * @return: + * FreeType error code. 0 means success. Returns an error if no sbit + * strike exists for the selected ppem values. + */ + typedef FT_Error + (*TT_Set_SBit_Strike_Func)( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Strike_Metrics_Func + * + * @description: + * Load the metrics of a given strike. + * + * @input: + * face :: + * The target face object. + * + * strike_index :: + * The strike index. + * + * @output: + * metrics :: + * the metrics of the strike. + * + * @return: + * FreeType error code. 0 means success. Returns an error if no such + * sbit strike exists. + */ + typedef FT_Error + (*TT_Load_Strike_Metrics_Func)( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + + + /************************************************************************** + * + * @functype: + * TT_Get_PS_Name_Func + * + * @description: + * Get the PostScript glyph name of a glyph. + * + * @input: + * idx :: + * The glyph index. + * + * PSname :: + * The address of a string pointer. Will be `NULL` in case of error, + * otherwise it is a pointer to the glyph name. + * + * You must not modify the returned string! + * + * @output: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Get_PS_Name_Func)( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Metrics_Func + * + * @description: + * Load a metrics table, which is a table with a horizontal and a + * vertical version. + * + * @input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * vertical :: + * A boolean flag. If set, load the vertical one. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Metrics_Func)( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Metrics_Func + * + * @description: + * Load the horizontal or vertical header in a face object. + * + * @input: + * face :: + * A handle to the target face object. + * + * vertical :: + * A boolean flag. If set, load vertical metrics. + * + * gindex :: + * The glyph index. + * + * @output: + * abearing :: + * The horizontal (or vertical) bearing. Set to zero in case of error. + * + * aadvance :: + * The horizontal (or vertical) advance. Set to zero in case of error. + */ + typedef void + (*TT_Get_Metrics_Func)( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); + + + /************************************************************************** + * + * @functype: + * TT_Set_Palette_Func + * + * @description: + * Load the colors into `face->palette` for a given palette index. + * + * @input: + * face :: + * The target face object. + * + * idx :: + * The palette index. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Set_Palette_Func)( TT_Face face, + FT_UInt idx ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Colr_Layer_Func + * + * @description: + * Iteratively get the color layer data of a given glyph index. + * + * @input: + * face :: + * The target face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @inout: + * iterator :: + * An @FT_LayerIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * aglyph_index :: + * The glyph index of the current layer. + * + * acolor_index :: + * The color index into the font face's color palette of the current + * layer. The value 0xFFFF is special; it doesn't reference a palette + * entry but indicates that the text foreground color should be used + * instead (to be set up by the application outside of FreeType). + * + * @return: + * Value~1 if everything is OK. If there are no more layers (or if there + * are no layers at all), value~0 gets returned. In case of an error, + * value~0 is returned also. + */ + typedef FT_Bool + (*TT_Get_Colr_Layer_Func)( TT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Color_Glyph_Paint_Func + * + * @description: + * Find the root @FT_OpaquePaint object for a given glyph ID. + * + * @input: + * face :: + * The target face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_Paint_Func )( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Color_Glyph_ClipBox_Func + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @return: + * Value~1 if a ClipBox is found. If no clip box is found or an + * error occured, value~0 is returned. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_ClipBox_Func )( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Layers_Func + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object referencing the actual paint table. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + */ + typedef FT_Bool + ( *TT_Get_Paint_Layers_Func )( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Colorline_Stops_Func + * + * @description: + * Get the gradient and solid fill information for a given glyph. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * An @FT_ColorStopIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + */ + typedef FT_Bool + ( *TT_Get_Colorline_Stops_Func )( TT_Face face, + FT_ColorStop *color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Func + * + * @description: + * Get the paint details for a given @FT_OpaquePaint object. + * + * @input: + * face :: + * The target face object. + * + * opaque_paint :: + * The @FT_OpaquePaint object. + * + * @output: + * paint :: + * An @FT_COLR_Paint object holding the details on `opaque_paint`. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occured. + */ + typedef FT_Bool + ( *TT_Get_Paint_Func )( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Blend_Colr_Func + * + * @description: + * Blend the bitmap in `new_glyph` into `base_glyph` using the color + * specified by `color_index`. If `color_index` is 0xFFFF, use + * `face->foreground_color` if `face->have_foreground_color` is set. + * Otherwise check `face->palette_data.palette_flags`: If present and + * @FT_PALETTE_FOR_DARK_BACKGROUND is set, use BGRA value 0xFFFFFFFF + * (white opaque). Otherwise use BGRA value 0x000000FF (black opaque). + * + * @input: + * face :: + * The target face object. + * + * color_index :: + * Color index from the COLR table. + * + * base_glyph :: + * Slot for bitmap to be merged into. The underlying bitmap may get + * reallocated. + * + * new_glyph :: + * Slot to be incooperated into `base_glyph`. + * + * @return: + * FreeType error code. 0 means success. Returns an error if + * color_index is invalid or reallocation fails. + */ + typedef FT_Error + (*TT_Blend_Colr_Func)( TT_Face face, + FT_UInt color_index, + FT_GlyphSlot base_glyph, + FT_GlyphSlot new_glyph ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Name_Func + * + * @description: + * From the 'name' table, return a given ENGLISH name record in ASCII. + * + * @input: + * face :: + * A handle to the source face object. + * + * nameid :: + * The name id of the name record to return. + * + * @inout: + * name :: + * The address of an allocated string pointer. `NULL` if no name is + * present. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Get_Name_Func)( TT_Face face, + FT_UShort nameid, + FT_String** name ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Name_ID_Func + * + * @description: + * Search whether an ENGLISH version for a given name ID is in the 'name' + * table. + * + * @input: + * face :: + * A handle to the source face object. + * + * nameid :: + * The name id of the name record to return. + * + * @output: + * win :: + * If non-negative, an index into the 'name' table with the + * corresponding (3,1) or (3,0) Windows entry. + * + * apple :: + * If non-negative, an index into the 'name' table with the + * corresponding (1,0) Apple entry. + * + * @return: + * 1 if there is either a win or apple entry (or both), 0 otheriwse. + */ + typedef FT_Bool + (*TT_Get_Name_ID_Func)( TT_Face face, + FT_UShort nameid, + FT_Int *win, + FT_Int *apple ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Table_Func + * + * @description: + * Load a given TrueType table. + * + * @input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The function uses `face->goto_table` to seek the stream to the start + * of the table, except while loading the font directory. + */ + typedef FT_Error + (*TT_Load_Table_Func)( TT_Face face, + FT_Stream stream ); + + + /************************************************************************** + * + * @functype: + * TT_Free_Table_Func + * + * @description: + * Free a given TrueType table. + * + * @input: + * face :: + * A handle to the target face object. + */ + typedef void + (*TT_Free_Table_Func)( TT_Face face ); + + + /* + * @functype: + * TT_Face_GetKerningFunc + * + * @description: + * Return the horizontal kerning value between two glyphs. + * + * @input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The left glyph index. + * + * right_glyph :: + * The right glyph index. + * + * @return: + * The kerning value in font units. + */ + typedef FT_Int + (*TT_Face_GetKerningFunc)( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + + + /************************************************************************** + * + * @struct: + * SFNT_Interface + * + * @description: + * This structure holds pointers to the functions used to load and free + * the basic tables that are required in a 'sfnt' font file. + * + * @fields: + * Check the various xxx_Func() descriptions for details. + */ + typedef struct SFNT_Interface_ + { + TT_Loader_GotoTableFunc goto_table; + + TT_Init_Face_Func init_face; + TT_Load_Face_Func load_face; + TT_Done_Face_Func done_face; + FT_Module_Requester get_interface; + + TT_Load_Any_Func load_any; + + /* these functions are called by `load_face' but they can also */ + /* be called from external modules, if there is a need to do so */ + TT_Load_Table_Func load_head; + TT_Load_Metrics_Func load_hhea; + TT_Load_Table_Func load_cmap; + TT_Load_Table_Func load_maxp; + TT_Load_Table_Func load_os2; + TT_Load_Table_Func load_post; + + TT_Load_Table_Func load_name; + TT_Free_Table_Func free_name; + + /* this field was called `load_kerning' up to version 2.1.10 */ + TT_Load_Table_Func load_kern; + + TT_Load_Table_Func load_gasp; + TT_Load_Table_Func load_pclt; + + /* see `ttload.h'; this field was called `load_bitmap_header' up to */ + /* version 2.1.10 */ + TT_Load_Table_Func load_bhed; + + TT_Load_SBit_Image_Func load_sbit_image; + + /* see `ttpost.h' */ + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; + + /* starting here, the structure differs from version 2.1.7 */ + + /* this field was introduced in version 2.1.8, named `get_psname' */ + TT_Face_GetKerningFunc get_kerning; + + /* new elements introduced after version 2.1.10 */ + + /* load the font directory, i.e., the offset table and */ + /* the table directory */ + TT_Load_Table_Func load_font_dir; + TT_Load_Metrics_Func load_hmtx; + + TT_Load_Table_Func load_eblc; + TT_Free_Table_Func free_eblc; + + TT_Set_SBit_Strike_Func set_sbit_strike; + TT_Load_Strike_Metrics_Func load_strike_metrics; + + TT_Load_Table_Func load_cpal; + TT_Load_Table_Func load_colr; + TT_Free_Table_Func free_cpal; + TT_Free_Table_Func free_colr; + TT_Set_Palette_Func set_palette; + TT_Get_Colr_Layer_Func get_colr_layer; + TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint; + TT_Get_Color_Glyph_ClipBox_Func get_color_glyph_clipbox; + TT_Get_Paint_Layers_Func get_paint_layers; + TT_Get_Colorline_Stops_Func get_colorline_stops; + TT_Get_Paint_Func get_paint; + TT_Blend_Colr_Func colr_blend; + + TT_Get_Metrics_Func get_metrics; + + TT_Get_Name_Func get_name; + TT_Get_Name_ID_Func get_name_id; + + /* OpenType SVG Support */ + TT_Load_Table_Func load_svg; + TT_Free_Table_Func free_svg; + TT_Load_Svg_Doc_Func load_svg_doc; + + } SFNT_Interface; + + + /* transitional */ + typedef SFNT_Interface* SFNT_Service; + + +#define FT_DEFINE_SFNT_INTERFACE( \ + class_, \ + goto_table_, \ + init_face_, \ + load_face_, \ + done_face_, \ + get_interface_, \ + load_any_, \ + load_head_, \ + load_hhea_, \ + load_cmap_, \ + load_maxp_, \ + load_os2_, \ + load_post_, \ + load_name_, \ + free_name_, \ + load_kern_, \ + load_gasp_, \ + load_pclt_, \ + load_bhed_, \ + load_sbit_image_, \ + get_psname_, \ + free_psnames_, \ + get_kerning_, \ + load_font_dir_, \ + load_hmtx_, \ + load_eblc_, \ + free_eblc_, \ + set_sbit_strike_, \ + load_strike_metrics_, \ + load_cpal_, \ + load_colr_, \ + free_cpal_, \ + free_colr_, \ + set_palette_, \ + get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ + colr_blend_, \ + get_metrics_, \ + get_name_, \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ ) \ + static const SFNT_Interface class_ = \ + { \ + goto_table_, \ + init_face_, \ + load_face_, \ + done_face_, \ + get_interface_, \ + load_any_, \ + load_head_, \ + load_hhea_, \ + load_cmap_, \ + load_maxp_, \ + load_os2_, \ + load_post_, \ + load_name_, \ + free_name_, \ + load_kern_, \ + load_gasp_, \ + load_pclt_, \ + load_bhed_, \ + load_sbit_image_, \ + get_psname_, \ + free_psnames_, \ + get_kerning_, \ + load_font_dir_, \ + load_hmtx_, \ + load_eblc_, \ + free_eblc_, \ + set_sbit_strike_, \ + load_strike_metrics_, \ + load_cpal_, \ + load_colr_, \ + free_cpal_, \ + free_colr_, \ + set_palette_, \ + get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ + colr_blend_, \ + get_metrics_, \ + get_name_, \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ \ + }; + + +FT_END_HEADER + +#endif /* SFNT_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/svginterface.h b/vendor/freetype/include/freetype/internal/svginterface.h new file mode 100644 index 0000000..f464b2c --- /dev/null +++ b/vendor/freetype/include/freetype/internal/svginterface.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * svginterface.h + * + * Interface of ot-svg module (specification only). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVGINTERFACE_H_ +#define SVGINTERFACE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + typedef FT_Error + (*Preset_Bitmap_Func)( FT_Module module, + FT_GlyphSlot slot, + FT_Bool cache ); + + typedef struct SVG_Interface_ + { + Preset_Bitmap_Func preset_slot; + + } SVG_Interface; + + typedef SVG_Interface* SVG_Service; + +FT_END_HEADER + +#endif /* SVGINTERFACE_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/t1types.h b/vendor/freetype/include/freetype/internal/t1types.h new file mode 100644 index 0000000..b9c9439 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/t1types.h @@ -0,0 +1,259 @@ +/**************************************************************************** + * + * t1types.h + * + * Basic Type1/Type2 type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1TYPES_H_ +#define T1TYPES_H_ + + +#include +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TYPE1/TYPE2 TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * T1_EncodingRec + * + * @description: + * A structure modeling a custom encoding. + * + * @fields: + * num_chars :: + * The number of character codes in the encoding. Usually 256. + * + * code_first :: + * The lowest valid character code in the encoding. + * + * code_last :: + * The highest valid character code in the encoding + 1. When equal to + * code_first there are no valid character codes. + * + * char_index :: + * An array of corresponding glyph indices. + * + * char_name :: + * An array of corresponding glyph names. + */ + typedef struct T1_EncodingRecRec_ + { + FT_Int num_chars; + FT_Int code_first; + FT_Int code_last; + + FT_UShort* char_index; + const FT_String** char_name; + + } T1_EncodingRec, *T1_Encoding; + + + /* used to hold extra data of PS_FontInfoRec that + * cannot be stored in the publicly defined structure. + * + * Note these can't be blended with multiple-masters. + */ + typedef struct PS_FontExtraRec_ + { + FT_UShort fs_type; + + } PS_FontExtraRec; + + + typedef struct T1_FontRec_ + { + PS_FontInfoRec font_info; /* font info dictionary */ + PS_FontExtraRec font_extra; /* font info extra fields */ + PS_PrivateRec private_dict; /* private dictionary */ + FT_String* font_name; /* top-level dictionary */ + + T1_EncodingType encoding_type; + T1_EncodingRec encoding; + + FT_Byte* subrs_block; + FT_Byte* charstrings_block; + FT_Byte* glyph_names_block; + + FT_Int num_subrs; + FT_Byte** subrs; + FT_UInt* subrs_len; + FT_Hash subrs_hash; + + FT_Int num_glyphs; + FT_String** glyph_names; /* array of glyph names */ + FT_Byte** charstrings; /* array of glyph charstrings */ + FT_UInt* charstrings_len; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_BBox font_bbox; + FT_Long font_id; + + FT_Fixed stroke_width; + + } T1_FontRec, *T1_Font; + + + typedef struct CID_SubrsRec_ + { + FT_Int num_subrs; + FT_Byte** code; + + } CID_SubrsRec, *CID_Subrs; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** AFM FONT INFORMATION STRUCTURES ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_TrackKernRec_ + { + FT_Int degree; + FT_Fixed min_ptsize; + FT_Fixed min_kern; + FT_Fixed max_ptsize; + FT_Fixed max_kern; + + } AFM_TrackKernRec, *AFM_TrackKern; + + typedef struct AFM_KernPairRec_ + { + FT_UInt index1; + FT_UInt index2; + FT_Int x; + FT_Int y; + + } AFM_KernPairRec, *AFM_KernPair; + + typedef struct AFM_FontInfoRec_ + { + FT_Bool IsCIDFont; + FT_BBox FontBBox; + FT_Fixed Ascender; /* optional, mind the zero */ + FT_Fixed Descender; /* optional, mind the zero */ + AFM_TrackKern TrackKerns; /* free if non-NULL */ + FT_UInt NumTrackKern; + AFM_KernPair KernPairs; /* free if non-NULL */ + FT_UInt NumKernPair; + + } AFM_FontInfoRec, *AFM_FontInfo; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL T1_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_FaceRec_* T1_Face; + typedef struct CID_FaceRec_* CID_Face; + + + typedef struct T1_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + + /* support for Multiple Masters fonts */ + PS_Blend blend; + + /* undocumented, optional: indices of subroutines that express */ + /* the NormalizeDesignVector and the ConvertDesignVector procedure, */ + /* respectively, as Type 2 charstrings; -1 if keywords not present */ + FT_Int ndv_idx; + FT_Int cdv_idx; + + /* undocumented, optional: has the same meaning as len_buildchar */ + /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */ + FT_UInt len_buildchar; + FT_Long* buildchar; + + /* since version 2.1 - interface to PostScript hinter */ + const void* pshinter; + + } T1_FaceRec; + + + typedef struct CID_FaceRec_ + { + FT_FaceRec root; + void* psnames; + void* psaux; + CID_FaceInfoRec cid; + PS_FontExtraRec font_extra; +#if 0 + void* afm_data; +#endif + CID_Subrs subrs; + + /* since version 2.1 - interface to PostScript hinter */ + void* pshinter; + + /* since version 2.1.8, but was originally positioned after `afm_data' */ + FT_Byte* binary_data; /* used if hex data has been converted */ + FT_Stream cid_stream; + + } CID_FaceRec; + + +FT_END_HEADER + +#endif /* T1TYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/tttypes.h b/vendor/freetype/include/freetype/internal/tttypes.h new file mode 100644 index 0000000..b9788c7 --- /dev/null +++ b/vendor/freetype/include/freetype/internal/tttypes.h @@ -0,0 +1,1741 @@ +/**************************************************************************** + * + * tttypes.h + * + * Basic SFNT/TrueType type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTTYPES_H_ +#define TTTYPES_H_ + + +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TTC_HeaderRec + * + * @description: + * TrueType collection header. This table contains the offsets of the + * font headers of each distinct TrueType face in the file. + * + * @fields: + * tag :: + * Must be 'ttc~' to indicate a TrueType collection. + * + * version :: + * The version number. + * + * count :: + * The number of faces in the collection. The specification says this + * should be an unsigned long, but we use a signed long since we need + * the value -1 for specific purposes. + * + * offsets :: + * The offsets of the font headers, one per face. + */ + typedef struct TTC_HeaderRec_ + { + FT_ULong tag; + FT_Fixed version; + FT_Long count; + FT_ULong* offsets; + + } TTC_HeaderRec; + + + /************************************************************************** + * + * @struct: + * SFNT_HeaderRec + * + * @description: + * SFNT file format header. + * + * @fields: + * format_tag :: + * The font format tag. + * + * num_tables :: + * The number of tables in file. + * + * search_range :: + * Must be '16 * (max power of 2 <= num_tables)'. + * + * entry_selector :: + * Must be log2 of 'search_range / 16'. + * + * range_shift :: + * Must be 'num_tables * 16 - search_range'. + */ + typedef struct SFNT_HeaderRec_ + { + FT_ULong format_tag; + FT_UShort num_tables; + FT_UShort search_range; + FT_UShort entry_selector; + FT_UShort range_shift; + + FT_ULong offset; /* not in file */ + + } SFNT_HeaderRec, *SFNT_Header; + + + /************************************************************************** + * + * @struct: + * TT_TableRec + * + * @description: + * This structure describes a given table of a TrueType font. + * + * @fields: + * Tag :: + * A four-bytes tag describing the table. + * + * CheckSum :: + * The table checksum. This value can be ignored. + * + * Offset :: + * The offset of the table from the start of the TrueType font in its + * resource. + * + * Length :: + * The table length (in bytes). + */ + typedef struct TT_TableRec_ + { + FT_ULong Tag; /* table type */ + FT_ULong CheckSum; /* table checksum */ + FT_ULong Offset; /* table file offset */ + FT_ULong Length; /* table length */ + + } TT_TableRec, *TT_Table; + + + /************************************************************************** + * + * @struct: + * TT_LongMetricsRec + * + * @description: + * A structure modeling the long metrics of the 'hmtx' and 'vmtx' + * TrueType tables. The values are expressed in font units. + * + * @fields: + * advance :: + * The advance width or height for the glyph. + * + * bearing :: + * The left-side or top-side bearing for the glyph. + */ + typedef struct TT_LongMetricsRec_ + { + FT_UShort advance; + FT_Short bearing; + + } TT_LongMetricsRec, *TT_LongMetrics; + + + /************************************************************************** + * + * @type: + * TT_ShortMetrics + * + * @description: + * A simple type to model the short metrics of the 'hmtx' and 'vmtx' + * tables. + */ + typedef FT_Short TT_ShortMetrics; + + + /************************************************************************** + * + * @struct: + * TT_NameRec + * + * @description: + * A structure modeling TrueType name records. Name records are used to + * store important strings like family name, style name, copyright, + * etc. in _localized_ versions (i.e., language, encoding, etc). + * + * @fields: + * platformID :: + * The ID of the name's encoding platform. + * + * encodingID :: + * The platform-specific ID for the name's encoding. + * + * languageID :: + * The platform-specific ID for the name's language. + * + * nameID :: + * The ID specifying what kind of name this is. + * + * stringLength :: + * The length of the string in bytes. + * + * stringOffset :: + * The offset to the string in the 'name' table. + * + * string :: + * A pointer to the string's bytes. Note that these are usually UTF-16 + * encoded characters. + */ + typedef struct TT_NameRec_ + { + FT_UShort platformID; + FT_UShort encodingID; + FT_UShort languageID; + FT_UShort nameID; + FT_UShort stringLength; + FT_ULong stringOffset; + + /* this last field is not defined in the spec */ + /* but used by the FreeType engine */ + + FT_Byte* string; + + } TT_NameRec, *TT_Name; + + + /************************************************************************** + * + * @struct: + * TT_LangTagRec + * + * @description: + * A structure modeling language tag records in SFNT 'name' tables, + * introduced in OpenType version 1.6. + * + * @fields: + * stringLength :: + * The length of the string in bytes. + * + * stringOffset :: + * The offset to the string in the 'name' table. + * + * string :: + * A pointer to the string's bytes. Note that these are UTF-16BE + * encoded characters. + */ + typedef struct TT_LangTagRec_ + { + FT_UShort stringLength; + FT_ULong stringOffset; + + /* this last field is not defined in the spec */ + /* but used by the FreeType engine */ + + FT_Byte* string; + + } TT_LangTagRec, *TT_LangTag; + + + /************************************************************************** + * + * @struct: + * TT_NameTableRec + * + * @description: + * A structure modeling the TrueType name table. + * + * @fields: + * format :: + * The format of the name table. + * + * numNameRecords :: + * The number of names in table. + * + * storageOffset :: + * The offset of the name table in the 'name' TrueType table. + * + * names :: + * An array of name records. + * + * numLangTagRecords :: + * The number of language tags in table. + * + * langTags :: + * An array of language tag records. + * + * stream :: + * The file's input stream. + */ + typedef struct TT_NameTableRec_ + { + FT_UShort format; + FT_UInt numNameRecords; + FT_UInt storageOffset; + TT_NameRec* names; + FT_UInt numLangTagRecords; + TT_LangTagRec* langTags; + FT_Stream stream; + + } TT_NameTableRec, *TT_NameTable; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** OPTIONAL TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TT_GaspRangeRec + * + * @description: + * A tiny structure used to model a gasp range according to the TrueType + * specification. + * + * @fields: + * maxPPEM :: + * The maximum ppem value to which `gaspFlag` applies. + * + * gaspFlag :: + * A flag describing the grid-fitting and anti-aliasing modes to be + * used. + */ + typedef struct TT_GaspRangeRec_ + { + FT_UShort maxPPEM; + FT_UShort gaspFlag; + + } TT_GaspRangeRec, *TT_GaspRange; + + +#define TT_GASP_GRIDFIT 0x01 +#define TT_GASP_DOGRAY 0x02 + + + /************************************************************************** + * + * @struct: + * TT_GaspRec + * + * @description: + * A structure modeling the TrueType 'gasp' table used to specify + * grid-fitting and anti-aliasing behaviour. + * + * @fields: + * version :: + * The version number. + * + * numRanges :: + * The number of gasp ranges in table. + * + * gaspRanges :: + * An array of gasp ranges. + */ + typedef struct TT_Gasp_ + { + FT_UShort version; + FT_UShort numRanges; + TT_GaspRange gaspRanges; + + } TT_GaspRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BITMAPS SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TT_SBit_MetricsRec + * + * @description: + * A structure used to hold the big metrics of a given glyph bitmap in a + * TrueType or OpenType font. These are usually found in the 'EBDT' + * (Microsoft) or 'bloc' (Apple) table. + * + * @fields: + * height :: + * The glyph height in pixels. + * + * width :: + * The glyph width in pixels. + * + * horiBearingX :: + * The horizontal left bearing. + * + * horiBearingY :: + * The horizontal top bearing. + * + * horiAdvance :: + * The horizontal advance. + * + * vertBearingX :: + * The vertical left bearing. + * + * vertBearingY :: + * The vertical top bearing. + * + * vertAdvance :: + * The vertical advance. + */ + typedef struct TT_SBit_MetricsRec_ + { + FT_UShort height; + FT_UShort width; + + FT_Short horiBearingX; + FT_Short horiBearingY; + FT_UShort horiAdvance; + + FT_Short vertBearingX; + FT_Short vertBearingY; + FT_UShort vertAdvance; + + } TT_SBit_MetricsRec, *TT_SBit_Metrics; + + + /************************************************************************** + * + * @struct: + * TT_SBit_SmallMetricsRec + * + * @description: + * A structure used to hold the small metrics of a given glyph bitmap in + * a TrueType or OpenType font. These are usually found in the 'EBDT' + * (Microsoft) or the 'bdat' (Apple) table. + * + * @fields: + * height :: + * The glyph height in pixels. + * + * width :: + * The glyph width in pixels. + * + * bearingX :: + * The left-side bearing. + * + * bearingY :: + * The top-side bearing. + * + * advance :: + * The advance width or height. + */ + typedef struct TT_SBit_Small_Metrics_ + { + FT_Byte height; + FT_Byte width; + + FT_Char bearingX; + FT_Char bearingY; + FT_Byte advance; + + } TT_SBit_SmallMetricsRec, *TT_SBit_SmallMetrics; + + + /************************************************************************** + * + * @struct: + * TT_SBit_LineMetricsRec + * + * @description: + * A structure used to describe the text line metrics of a given bitmap + * strike, for either a horizontal or vertical layout. + * + * @fields: + * ascender :: + * The ascender in pixels. + * + * descender :: + * The descender in pixels. + * + * max_width :: + * The maximum glyph width in pixels. + * + * caret_slope_enumerator :: + * Rise of the caret slope, typically set to 1 for non-italic fonts. + * + * caret_slope_denominator :: + * Rise of the caret slope, typically set to 0 for non-italic fonts. + * + * caret_offset :: + * Offset in pixels to move the caret for proper positioning. + * + * min_origin_SB :: + * Minimum of horiBearingX (resp. vertBearingY). + * min_advance_SB :: + * Minimum of + * + * horizontal advance - ( horiBearingX + width ) + * + * resp. + * + * vertical advance - ( vertBearingY + height ) + * + * max_before_BL :: + * Maximum of horiBearingY (resp. vertBearingY). + * + * min_after_BL :: + * Minimum of + * + * horiBearingY - height + * + * resp. + * + * vertBearingX - width + * + * pads :: + * Unused (to make the size of the record a multiple of 32 bits. + */ + typedef struct TT_SBit_LineMetricsRec_ + { + FT_Char ascender; + FT_Char descender; + FT_Byte max_width; + FT_Char caret_slope_numerator; + FT_Char caret_slope_denominator; + FT_Char caret_offset; + FT_Char min_origin_SB; + FT_Char min_advance_SB; + FT_Char max_before_BL; + FT_Char min_after_BL; + FT_Char pads[2]; + + } TT_SBit_LineMetricsRec, *TT_SBit_LineMetrics; + + + /************************************************************************** + * + * @struct: + * TT_SBit_RangeRec + * + * @description: + * A TrueType/OpenType subIndexTable as defined in the 'EBLC' (Microsoft) + * or 'bloc' (Apple) tables. + * + * @fields: + * first_glyph :: + * The first glyph index in the range. + * + * last_glyph :: + * The last glyph index in the range. + * + * index_format :: + * The format of index table. Valid values are 1 to 5. + * + * image_format :: + * The format of 'EBDT' image data. + * + * image_offset :: + * The offset to image data in 'EBDT'. + * + * image_size :: + * For index formats 2 and 5. This is the size in bytes of each glyph + * bitmap. + * + * big_metrics :: + * For index formats 2 and 5. This is the big metrics for each glyph + * bitmap. + * + * num_glyphs :: + * For index formats 4 and 5. This is the number of glyphs in the code + * array. + * + * glyph_offsets :: + * For index formats 1 and 3. + * + * glyph_codes :: + * For index formats 4 and 5. + * + * table_offset :: + * The offset of the index table in the 'EBLC' table. Only used during + * strike loading. + */ + typedef struct TT_SBit_RangeRec_ + { + FT_UShort first_glyph; + FT_UShort last_glyph; + + FT_UShort index_format; + FT_UShort image_format; + FT_ULong image_offset; + + FT_ULong image_size; + TT_SBit_MetricsRec metrics; + FT_ULong num_glyphs; + + FT_ULong* glyph_offsets; + FT_UShort* glyph_codes; + + FT_ULong table_offset; + + } TT_SBit_RangeRec, *TT_SBit_Range; + + + /************************************************************************** + * + * @struct: + * TT_SBit_StrikeRec + * + * @description: + * A structure used describe a given bitmap strike in the 'EBLC' + * (Microsoft) or 'bloc' (Apple) tables. + * + * @fields: + * num_index_ranges :: + * The number of index ranges. + * + * index_ranges :: + * An array of glyph index ranges. + * + * color_ref :: + * Unused. `color_ref` is put in for future enhancements, but these + * fields are already in use by other platforms (e.g. Newton). For + * details, please see + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bloc.html + * + * hori :: + * The line metrics for horizontal layouts. + * + * vert :: + * The line metrics for vertical layouts. + * + * start_glyph :: + * The lowest glyph index for this strike. + * + * end_glyph :: + * The highest glyph index for this strike. + * + * x_ppem :: + * The number of horizontal pixels per EM. + * + * y_ppem :: + * The number of vertical pixels per EM. + * + * bit_depth :: + * The bit depth. Valid values are 1, 2, 4, and 8. + * + * flags :: + * Is this a vertical or horizontal strike? For details, please see + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bloc.html + */ + typedef struct TT_SBit_StrikeRec_ + { + FT_Int num_ranges; + TT_SBit_Range sbit_ranges; + FT_ULong ranges_offset; + + FT_ULong color_ref; + + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_UShort start_glyph; + FT_UShort end_glyph; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte bit_depth; + FT_Char flags; + + } TT_SBit_StrikeRec, *TT_SBit_Strike; + + + /************************************************************************** + * + * @struct: + * TT_SBit_ComponentRec + * + * @description: + * A simple structure to describe a compound sbit element. + * + * @fields: + * glyph_code :: + * The element's glyph index. + * + * x_offset :: + * The element's left bearing. + * + * y_offset :: + * The element's top bearing. + */ + typedef struct TT_SBit_ComponentRec_ + { + FT_UShort glyph_code; + FT_Char x_offset; + FT_Char y_offset; + + } TT_SBit_ComponentRec, *TT_SBit_Component; + + + /************************************************************************** + * + * @struct: + * TT_SBit_ScaleRec + * + * @description: + * A structure used describe a given bitmap scaling table, as defined in + * the 'EBSC' table. + * + * @fields: + * hori :: + * The horizontal line metrics. + * + * vert :: + * The vertical line metrics. + * + * x_ppem :: + * The number of horizontal pixels per EM. + * + * y_ppem :: + * The number of vertical pixels per EM. + * + * x_ppem_substitute :: + * Substitution x_ppem value. + * + * y_ppem_substitute :: + * Substitution y_ppem value. + */ + typedef struct TT_SBit_ScaleRec_ + { + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte x_ppem_substitute; + FT_Byte y_ppem_substitute; + + } TT_SBit_ScaleRec, *TT_SBit_Scale; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** POSTSCRIPT GLYPH NAMES SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TT_Post_NamesRec + * + * @description: + * Postscript names table, either format 2.0 or 2.5. + * + * @fields: + * loaded :: + * A flag to indicate whether the PS names are loaded. + * + * num_glyphs :: + * The number of named glyphs in the table. + * + * num_names :: + * The number of PS names stored in the table. + * + * glyph_indices :: + * The indices of the glyphs in the names arrays. + * + * glyph_names :: + * The PS names not in Mac Encoding. + */ + typedef struct TT_Post_NamesRec_ + { + FT_Bool loaded; + FT_UShort num_glyphs; + FT_UShort num_names; + FT_UShort* glyph_indices; + FT_Byte** glyph_names; + + } TT_Post_NamesRec, *TT_Post_Names; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** GX VARIATION TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + typedef struct GX_BlendRec_ *GX_Blend; +#endif + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BDF PROPERTIES TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * These types are used to support a `BDF ' table that isn't part of the + * official TrueType specification. It is mainly used in SFNT-based bitmap + * fonts that were generated from a set of BDF fonts. + * + * The format of the table is as follows. + * + * USHORT version `BDF ' table version number, should be 0x0001. USHORT + * strikeCount Number of strikes (bitmap sizes) in this table. ULONG + * stringTable Offset (from start of BDF table) to string + * table. + * + * This is followed by an array of `strikeCount' descriptors, having the + * following format. + * + * USHORT ppem Vertical pixels per EM for this strike. USHORT numItems + * Number of items for this strike (properties and + * atoms). Maximum is 255. + * + * This array in turn is followed by `strikeCount' value sets. Each `value + * set' is an array of `numItems' items with the following format. + * + * ULONG item_name Offset in string table to item name. + * USHORT item_type The item type. Possible values are + * 0 => string (e.g., COMMENT) + * 1 => atom (e.g., FONT or even SIZE) + * 2 => int32 + * 3 => uint32 + * 0x10 => A flag to indicate a properties. This + * is ORed with the above values. + * ULONG item_value For strings => Offset into string table without + * the corresponding double quotes. + * For atoms => Offset into string table. + * For integers => Direct value. + * + * All strings in the string table consist of bytes and are + * zero-terminated. + * + */ + +#ifdef TT_CONFIG_OPTION_BDF + + typedef struct TT_BDFRec_ + { + FT_Byte* table; + FT_Byte* table_end; + FT_Byte* strings; + FT_ULong strings_size; + FT_UInt num_strikes; + FT_Bool loaded; + + } TT_BDFRec, *TT_BDF; + +#endif /* TT_CONFIG_OPTION_BDF */ + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL TT_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * This structure/class is defined here because it is common to the + * following formats: TTF, OpenType-TT, and OpenType-CFF. + * + * Note, however, that the classes TT_Size and TT_GlyphSlot are not shared + * between font drivers, and are thus defined in `ttobjs.h`. + * + */ + + + /************************************************************************** + * + * @type: + * TT_Face + * + * @description: + * A handle to a TrueType face/font object. A TT_Face encapsulates the + * resolution and scaling independent parts of a TrueType font resource. + * + * @note: + * The TT_Face structure is also used as a 'parent class' for the + * OpenType-CFF class (T2_Face). + */ + typedef struct TT_FaceRec_* TT_Face; + + + /* a function type used for the truetype bytecode interpreter hooks */ + typedef FT_Error + (*TT_Interpreter)( void* exec_context ); + + /* forward declaration */ + typedef struct TT_LoaderRec_* TT_Loader; + + + /************************************************************************** + * + * @functype: + * TT_Loader_GotoTableFunc + * + * @description: + * Seeks a stream to the start of a given TrueType table. + * + * @input: + * face :: + * A handle to the target face object. + * + * tag :: + * A 4-byte tag used to name the table. + * + * stream :: + * The input stream. + * + * @output: + * length :: + * The length of the table in bytes. Set to 0 if not needed. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The stream cursor must be at the font file's origin. + */ + typedef FT_Error + (*TT_Loader_GotoTableFunc)( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + /************************************************************************** + * + * @functype: + * TT_Loader_StartGlyphFunc + * + * @description: + * Seeks a stream to the start of a given glyph element, and opens a + * frame for it. + * + * @input: + * loader :: + * The current TrueType glyph loader object. + * + * glyph index :: The index of the glyph to access. + * + * offset :: + * The offset of the glyph according to the 'locations' table. + * + * byte_count :: + * The size of the frame in bytes. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function is normally equivalent to FT_STREAM_SEEK(offset) + * followed by FT_FRAME_ENTER(byte_count) with the loader's stream, but + * alternative formats (e.g. compressed ones) might use something + * different. + */ + typedef FT_Error + (*TT_Loader_StartGlyphFunc)( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ); + + + /************************************************************************** + * + * @functype: + * TT_Loader_ReadGlyphFunc + * + * @description: + * Reads one glyph element (its header, a simple glyph, or a composite) + * from the loader's current stream frame. + * + * @input: + * loader :: + * The current TrueType glyph loader object. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Loader_ReadGlyphFunc)( TT_Loader loader ); + + + /************************************************************************** + * + * @functype: + * TT_Loader_EndGlyphFunc + * + * @description: + * Closes the current loader stream frame for the glyph. + * + * @input: + * loader :: + * The current TrueType glyph loader object. + */ + typedef void + (*TT_Loader_EndGlyphFunc)( TT_Loader loader ); + + + typedef enum TT_SbitTableType_ + { + TT_SBIT_TABLE_TYPE_NONE = 0, + TT_SBIT_TABLE_TYPE_EBLC, /* `EBLC' (Microsoft), */ + /* `bloc' (Apple) */ + TT_SBIT_TABLE_TYPE_CBLC, /* `CBLC' (Google) */ + TT_SBIT_TABLE_TYPE_SBIX, /* `sbix' (Apple) */ + + /* do not remove */ + TT_SBIT_TABLE_TYPE_MAX + + } TT_SbitTableType; + + + /* OpenType 1.8 brings new tables for variation font support; */ + /* to make the old MM and GX fonts still work we need to check */ + /* the presence (and validity) of the functionality provided */ + /* by those tables. The following flag macros are for the */ + /* field `variation_support'. */ + /* */ + /* Note that `fvar' gets checked immediately at font loading, */ + /* while the other features are only loaded if MM support is */ + /* actually requested. */ + + /* FVAR */ +#define TT_FACE_FLAG_VAR_FVAR ( 1 << 0 ) + + /* HVAR */ +#define TT_FACE_FLAG_VAR_HADVANCE ( 1 << 1 ) +#define TT_FACE_FLAG_VAR_LSB ( 1 << 2 ) +#define TT_FACE_FLAG_VAR_RSB ( 1 << 3 ) + + /* VVAR */ +#define TT_FACE_FLAG_VAR_VADVANCE ( 1 << 4 ) +#define TT_FACE_FLAG_VAR_TSB ( 1 << 5 ) +#define TT_FACE_FLAG_VAR_BSB ( 1 << 6 ) +#define TT_FACE_FLAG_VAR_VORG ( 1 << 7 ) + + /* MVAR */ +#define TT_FACE_FLAG_VAR_MVAR ( 1 << 8 ) + + + /************************************************************************** + * + * TrueType Face Type + * + * @struct: + * TT_Face + * + * @description: + * The TrueType face class. These objects model the resolution and + * point-size independent data found in a TrueType font file. + * + * @fields: + * root :: + * The base FT_Face structure, managed by the base layer. + * + * ttc_header :: + * The TrueType collection header, used when the file is a 'ttc' rather + * than a 'ttf'. For ordinary font files, the field `ttc_header.count` + * is set to 0. + * + * format_tag :: + * The font format tag. + * + * num_tables :: + * The number of TrueType tables in this font file. + * + * dir_tables :: + * The directory of TrueType tables for this font file. + * + * header :: + * The font's font header ('head' table). Read on font opening. + * + * horizontal :: + * The font's horizontal header ('hhea' table). This field also + * contains the associated horizontal metrics table ('hmtx'). + * + * max_profile :: + * The font's maximum profile table. Read on font opening. Note that + * some maximum values cannot be taken directly from this table. We + * thus define additional fields below to hold the computed maxima. + * + * vertical_info :: + * A boolean which is set when the font file contains vertical metrics. + * If not, the value of the 'vertical' field is undefined. + * + * vertical :: + * The font's vertical header ('vhea' table). This field also contains + * the associated vertical metrics table ('vmtx'), if found. + * IMPORTANT: The contents of this field is undefined if the + * `vertical_info` field is unset. + * + * num_names :: + * The number of name records within this TrueType font. + * + * name_table :: + * The table of name records ('name'). + * + * os2 :: + * The font's OS/2 table ('OS/2'). + * + * postscript :: + * The font's PostScript table ('post' table). The PostScript glyph + * names are not loaded by the driver on face opening. See the + * 'ttpost' module for more details. + * + * cmap_table :: + * Address of the face's 'cmap' SFNT table in memory (it's an extracted + * frame). + * + * cmap_size :: + * The size in bytes of the `cmap_table` described above. + * + * goto_table :: + * A function called by each TrueType table loader to position a + * stream's cursor to the start of a given table according to its tag. + * It defaults to TT_Goto_Face but can be different for strange formats + * (e.g. Type 42). + * + * access_glyph_frame :: + * A function used to access the frame of a given glyph within the + * face's font file. + * + * forget_glyph_frame :: + * A function used to forget the frame of a given glyph when all data + * has been loaded. + * + * read_glyph_header :: + * A function used to read a glyph header. It must be called between + * an 'access' and 'forget'. + * + * read_simple_glyph :: + * A function used to read a simple glyph. It must be called after the + * header was read, and before the 'forget'. + * + * read_composite_glyph :: + * A function used to read a composite glyph. It must be called after + * the header was read, and before the 'forget'. + * + * sfnt :: + * A pointer to the SFNT service. + * + * psnames :: + * A pointer to the PostScript names service. + * + * mm :: + * A pointer to the Multiple Masters service. + * + * tt_var :: + * A pointer to the Metrics Variations service for the "truetype" + * driver. + * + * face_var :: + * A pointer to the Metrics Variations service for this `TT_Face`'s + * driver. + * + * psaux :: + * A pointer to the PostScript Auxiliary service. + * + * gasp :: + * The grid-fitting and scaling properties table ('gasp'). This table + * is optional in TrueType/OpenType fonts. + * + * pclt :: + * The 'pclt' SFNT table. + * + * num_sbit_scales :: + * The number of sbit scales for this font. + * + * sbit_scales :: + * Array of sbit scales embedded in this font. This table is optional + * in a TrueType/OpenType font. + * + * postscript_names :: + * A table used to store the Postscript names of the glyphs for this + * font. See the file `ttconfig.h` for comments on the + * TT_CONFIG_OPTION_POSTSCRIPT_NAMES option. + * + * palette_data :: + * Some fields from the 'CPAL' table that are directly indexed. + * + * palette_index :: + * The current palette index, as set by @FT_Palette_Select. + * + * palette :: + * An array containing the current palette's colors. + * + * have_foreground_color :: + * There was a call to @FT_Palette_Set_Foreground_Color. + * + * foreground_color :: + * The current foreground color corresponding to 'CPAL' color index + * 0xFFFF. Only valid if `have_foreground_color` is set. + * + * font_program_size :: + * Size in bytecodes of the face's font program. 0 if none defined. + * Ignored for Type 2 fonts. + * + * font_program :: + * The face's font program (bytecode stream) executed at load time, + * also used during glyph rendering. Comes from the 'fpgm' table. + * Ignored for Type 2 font fonts. + * + * cvt_program_size :: + * The size in bytecodes of the face's cvt program. Ignored for Type 2 + * fonts. + * + * cvt_program :: + * The face's cvt program (bytecode stream) executed each time an + * instance/size is changed/reset. Comes from the 'prep' table. + * Ignored for Type 2 fonts. + * + * cvt_size :: + * Size of the control value table (in entries). Ignored for Type 2 + * fonts. + * + * cvt :: + * The face's original control value table. Coordinates are expressed + * in unscaled font units (in 26.6 format). Comes from the 'cvt~' + * table. Ignored for Type 2 fonts. + * + * If varied by the `CVAR' table, non-integer values are possible. + * + * interpreter :: + * A pointer to the TrueType bytecode interpreters field is also used + * to hook the debugger in 'ttdebug'. + * + * extra :: + * Reserved for third-party font drivers. + * + * postscript_name :: + * The PS name of the font. Used by the postscript name service. + * + * glyf_len :: + * The length of the 'glyf' table. Needed for malformed 'loca' tables. + * + * glyf_offset :: + * The file offset of the 'glyf' table. + * + * is_cff2 :: + * Set if the font format is CFF2. + * + * doblend :: + * A boolean which is set if the font should be blended (this is for GX + * var). + * + * blend :: + * Contains the data needed to control GX variation tables (rather like + * Multiple Master data). + * + * variation_support :: + * Flags that indicate which OpenType functionality related to font + * variation support is present, valid, and usable. For example, + * TT_FACE_FLAG_VAR_FVAR is only set if we have at least one design + * axis. + * + * var_postscript_prefix :: + * The PostScript name prefix needed for constructing a variation font + * instance's PS name . + * + * var_postscript_prefix_len :: + * The length of the `var_postscript_prefix` string. + * + * var_default_named_instance :: + * The index of the default named instance. + * + * non_var_style_name :: + * The non-variation style name, used as a backup. + * + * horz_metrics_size :: + * The size of the 'hmtx' table. + * + * vert_metrics_size :: + * The size of the 'vmtx' table. + * + * num_locations :: + * The number of glyph locations in this TrueType file. This should be + * one more than the number of glyphs. Ignored for Type 2 fonts. + * + * glyph_locations :: + * An array of longs. These are offsets to glyph data within the + * 'glyf' table. Ignored for Type 2 font faces. + * + * hdmx_table :: + * A pointer to the 'hdmx' table. + * + * hdmx_table_size :: + * The size of the 'hdmx' table. + * + * hdmx_record_count :: + * The number of hdmx records. + * + * hdmx_record_size :: + * The size of a single hdmx record. + * + * hdmx_records :: + * A array of pointers to the 'hdmx' table records sorted by ppem. + * + * sbit_table :: + * A pointer to the font's embedded bitmap location table. + * + * sbit_table_size :: + * The size of `sbit_table`. + * + * sbit_table_type :: + * The sbit table type (CBLC, sbix, etc.). + * + * sbit_num_strikes :: + * The number of sbit strikes exposed by FreeType's API, omitting + * invalid strikes. + * + * sbit_strike_map :: + * A mapping between the strike indices exposed by the API and the + * indices used in the font's sbit table. + * + * kern_table :: + * A pointer to the 'kern' table. + * + * kern_table_size :: + * The size of the 'kern' table. + * + * num_kern_tables :: + * The number of supported kern subtables (up to 32; FreeType + * recognizes only horizontal ones with format 0). + * + * kern_avail_bits :: + * The availability status of kern subtables; if bit n is set, table n + * is available. + * + * kern_order_bits :: + * The sortedness status of kern subtables; if bit n is set, table n is + * sorted. + * + * bdf :: + * Data related to an SFNT font's 'bdf' table; see `tttypes.h`. + * + * horz_metrics_offset :: + * The file offset of the 'hmtx' table. + * + * vert_metrics_offset :: + * The file offset of the 'vmtx' table. + * + * ebdt_start :: + * The file offset of the sbit data table (CBDT, bdat, etc.). + * + * ebdt_size :: + * The size of the sbit data table. + * + * cpal :: + * A pointer to data related to the 'CPAL' table. `NULL` if the table + * is not available. + * + * colr :: + * A pointer to data related to the 'COLR' table. `NULL` if the table + * is not available. + * + * svg :: + * A pointer to data related to the 'SVG' table. `NULL` if the table + * is not available. + */ + typedef struct TT_FaceRec_ + { + FT_FaceRec root; + + TTC_HeaderRec ttc_header; + + FT_ULong format_tag; + FT_UShort num_tables; + TT_Table dir_tables; + + TT_Header header; /* TrueType header table */ + TT_HoriHeader horizontal; /* TrueType horizontal header */ + + TT_MaxProfile max_profile; + + FT_Bool vertical_info; + TT_VertHeader vertical; /* TT Vertical header, if present */ + + FT_UShort num_names; /* number of name records */ + TT_NameTableRec name_table; /* name table */ + + TT_OS2 os2; /* TrueType OS/2 table */ + TT_Postscript postscript; /* TrueType Postscript table */ + + FT_Byte* cmap_table; /* extracted `cmap' table */ + FT_ULong cmap_size; + + TT_Loader_GotoTableFunc goto_table; + + TT_Loader_StartGlyphFunc access_glyph_frame; + TT_Loader_EndGlyphFunc forget_glyph_frame; + TT_Loader_ReadGlyphFunc read_glyph_header; + TT_Loader_ReadGlyphFunc read_simple_glyph; + TT_Loader_ReadGlyphFunc read_composite_glyph; + + /* a typeless pointer to the SFNT_Interface table used to load */ + /* the basic TrueType tables in the face object */ + void* sfnt; + + /* a typeless pointer to the FT_Service_PsCMapsRec table used to */ + /* handle glyph names <-> unicode & Mac values */ + void* psnames; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* a typeless pointer to the FT_Service_MultiMasters table used to */ + /* handle variation fonts */ + void* mm; + + /* a typeless pointer to the FT_Service_MetricsVariationsRec table */ + /* used to handle the HVAR, VVAR, and MVAR OpenType tables by the */ + /* "truetype" driver */ + void* tt_var; + + /* a typeless pointer to the FT_Service_MetricsVariationsRec table */ + /* used to handle the HVAR, VVAR, and MVAR OpenType tables by this */ + /* TT_Face's driver */ + void* face_var; /* since 2.13.1 */ +#endif + + /* a typeless pointer to the PostScript Aux service */ + void* psaux; + + + /************************************************************************ + * + * Optional TrueType/OpenType tables + * + */ + + /* grid-fitting and scaling table */ + TT_GaspRec gasp; /* the `gasp' table */ + + /* PCL 5 table */ + TT_PCLT pclt; + + /* embedded bitmaps support */ + FT_ULong num_sbit_scales; + TT_SBit_Scale sbit_scales; + + /* postscript names table */ + TT_Post_NamesRec postscript_names; + + /* glyph colors */ + FT_Palette_Data palette_data; /* since 2.10 */ + FT_UShort palette_index; + FT_Color* palette; + FT_Bool have_foreground_color; + FT_Color foreground_color; + + + /************************************************************************ + * + * TrueType-specific fields (ignored by the CFF driver) + * + */ + + /* the font program, if any */ + FT_ULong font_program_size; + FT_Byte* font_program; + + /* the cvt program, if any */ + FT_ULong cvt_program_size; + FT_Byte* cvt_program; + + /* the original, unscaled, control value table */ + FT_ULong cvt_size; + FT_Int32* cvt; + + /* A pointer to the bytecode interpreter to use. This is also */ + /* used to hook the debugger for the `ttdebug' utility. */ + TT_Interpreter interpreter; + + + /************************************************************************ + * + * Other tables or fields. This is used by derivative formats like + * OpenType. + * + */ + + FT_Generic extra; + + const char* postscript_name; + + FT_ULong glyf_len; + FT_ULong glyf_offset; /* since 2.7.1 */ + + FT_Bool is_cff2; /* since 2.7.1 */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Bool doblend; + GX_Blend blend; + + FT_UInt32 variation_support; /* since 2.7.1 */ + + const char* var_postscript_prefix; /* since 2.7.2 */ + FT_UInt var_postscript_prefix_len; /* since 2.7.2 */ + + FT_UInt var_default_named_instance; /* since 2.13.1 */ + + const char* non_var_style_name; /* since 2.13.1 */ +#endif + + /* since version 2.2 */ + + FT_ULong horz_metrics_size; + FT_ULong vert_metrics_size; + + FT_ULong num_locations; /* up to 0xFFFF + 1 */ + FT_Byte* glyph_locations; + + FT_Byte* hdmx_table; + FT_ULong hdmx_table_size; + FT_UInt hdmx_record_count; + FT_ULong hdmx_record_size; + FT_Byte** hdmx_records; + + FT_Byte* sbit_table; + FT_ULong sbit_table_size; + TT_SbitTableType sbit_table_type; + FT_UInt sbit_num_strikes; + FT_UInt* sbit_strike_map; + + FT_Byte* kern_table; + FT_ULong kern_table_size; + FT_UInt num_kern_tables; + FT_UInt32 kern_avail_bits; + FT_UInt32 kern_order_bits; + +#ifdef TT_CONFIG_OPTION_BDF + TT_BDFRec bdf; +#endif /* TT_CONFIG_OPTION_BDF */ + + /* since 2.3.0 */ + FT_ULong horz_metrics_offset; + FT_ULong vert_metrics_offset; + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + /* since 2.7 */ + FT_ULong ebdt_start; /* either `CBDT', `EBDT', or `bdat' */ + FT_ULong ebdt_size; +#endif + + /* since 2.10 */ + void* cpal; + void* colr; + + /* since 2.12 */ + void* svg; + + } TT_FaceRec; + + + /************************************************************************** + * + * @struct: + * TT_GlyphZoneRec + * + * @description: + * A glyph zone is used to load, scale and hint glyph outline + * coordinates. + * + * @fields: + * memory :: + * A handle to the memory manager. + * + * max_points :: + * The maximum size in points of the zone. + * + * max_contours :: + * Max size in links contours of the zone. + * + * n_points :: + * The current number of points in the zone. + * + * n_contours :: + * The current number of contours in the zone. + * + * org :: + * The original glyph coordinates (font units/scaled). + * + * cur :: + * The current glyph coordinates (scaled/hinted). + * + * tags :: + * The point control tags. + * + * contours :: + * The contours end points. + * + * first_point :: + * Offset of the current subglyph's first point. + */ + typedef struct TT_GlyphZoneRec_ + { + FT_Memory memory; + FT_UShort max_points; + FT_Short max_contours; + FT_UShort n_points; /* number of points in zone */ + FT_Short n_contours; /* number of contours */ + + FT_Vector* org; /* original point coordinates */ + FT_Vector* cur; /* current point coordinates */ + FT_Vector* orus; /* original (unscaled) point coordinates */ + + FT_Byte* tags; /* current touch flags */ + FT_UShort* contours; /* contour end points */ + + FT_UShort first_point; /* offset of first (#0) point */ + + } TT_GlyphZoneRec, *TT_GlyphZone; + + + /* handle to execution context */ + typedef struct TT_ExecContextRec_* TT_ExecContext; + + + /************************************************************************** + * + * @type: + * TT_Size + * + * @description: + * A handle to a TrueType size object. + */ + typedef struct TT_SizeRec_* TT_Size; + + + /* glyph loader structure */ + typedef struct TT_LoaderRec_ + { + TT_Face face; + TT_Size size; + FT_GlyphSlot glyph; + FT_GlyphLoader gloader; + + FT_ULong load_flags; + FT_UInt glyph_index; + + FT_Stream stream; + FT_UInt byte_len; + + FT_Short n_contours; + FT_BBox bbox; + FT_Int left_bearing; + FT_Int advance; + FT_Int linear; + FT_Bool linear_def; + FT_Vector pp1; + FT_Vector pp2; + + /* the zone where we load our glyphs */ + TT_GlyphZoneRec base; + TT_GlyphZoneRec zone; + + TT_ExecContext exec; + FT_Byte* instructions; + FT_ULong ins_pos; + + /* for possible extensibility in other formats */ + void* other; + + /* since version 2.1.8 */ + FT_Int top_bearing; + FT_Int vadvance; + FT_Vector pp3; + FT_Vector pp4; + + /* since version 2.2.1 */ + FT_Byte* cursor; + FT_Byte* limit; + + /* since version 2.6.2 */ + FT_ListRec composites; + + /* since version 2.11.2 */ + FT_Byte* widthp; + + } TT_LoaderRec; + + +FT_END_HEADER + +#endif /* TTTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/internal/wofftypes.h b/vendor/freetype/include/freetype/internal/wofftypes.h new file mode 100644 index 0000000..0c1d8ee --- /dev/null +++ b/vendor/freetype/include/freetype/internal/wofftypes.h @@ -0,0 +1,312 @@ +/**************************************************************************** + * + * wofftypes.h + * + * Basic WOFF/WOFF2 type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef WOFFTYPES_H_ +#define WOFFTYPES_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * WOFF_HeaderRec + * + * @description: + * WOFF file format header. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF/#WOFFHeader + */ + typedef struct WOFF_HeaderRec_ + { + FT_ULong signature; + FT_ULong flavor; + FT_ULong length; + FT_UShort num_tables; + FT_UShort reserved; + FT_ULong totalSfntSize; + FT_UShort majorVersion; + FT_UShort minorVersion; + FT_ULong metaOffset; + FT_ULong metaLength; + FT_ULong metaOrigLength; + FT_ULong privOffset; + FT_ULong privLength; + + } WOFF_HeaderRec, *WOFF_Header; + + + /************************************************************************** + * + * @struct: + * WOFF_TableRec + * + * @description: + * This structure describes a given table of a WOFF font. + * + * @fields: + * Tag :: + * A four-bytes tag describing the table. + * + * Offset :: + * The offset of the table from the start of the WOFF font in its + * resource. + * + * CompLength :: + * Compressed table length (in bytes). + * + * OrigLength :: + * Uncompressed table length (in bytes). + * + * CheckSum :: + * The table checksum. This value can be ignored. + * + * OrigOffset :: + * The uncompressed table file offset. This value gets computed while + * constructing the (uncompressed) SFNT header. It is not contained in + * the WOFF file. + */ + typedef struct WOFF_TableRec_ + { + FT_Tag Tag; /* table ID */ + FT_ULong Offset; /* table file offset */ + FT_ULong CompLength; /* compressed table length */ + FT_ULong OrigLength; /* uncompressed table length */ + FT_ULong CheckSum; /* uncompressed checksum */ + + FT_ULong OrigOffset; /* uncompressed table file offset */ + /* (not in the WOFF file) */ + } WOFF_TableRec, *WOFF_Table; + + + /************************************************************************** + * + * @struct: + * WOFF2_TtcFontRec + * + * @description: + * Metadata for a TTC font entry in WOFF2. + * + * @fields: + * flavor :: + * TTC font flavor. + * + * num_tables :: + * Number of tables in TTC, indicating number of elements in + * `table_indices`. + * + * table_indices :: + * Array of table indices for each TTC font. + */ + typedef struct WOFF2_TtcFontRec_ + { + FT_ULong flavor; + FT_UShort num_tables; + FT_UShort* table_indices; + + } WOFF2_TtcFontRec, *WOFF2_TtcFont; + + + /************************************************************************** + * + * @struct: + * WOFF2_HeaderRec + * + * @description: + * WOFF2 file format header. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF2/#woff20Header + * + * @note: + * We don't care about the fields `reserved`, `majorVersion` and + * `minorVersion`, so they are not included. The `totalSfntSize` field + * does not necessarily represent the actual size of the uncompressed + * SFNT font stream, so that is used as a reference value instead. + */ + typedef struct WOFF2_HeaderRec_ + { + FT_ULong signature; + FT_ULong flavor; + FT_ULong length; + FT_UShort num_tables; + FT_ULong totalSfntSize; + FT_ULong totalCompressedSize; + FT_ULong metaOffset; + FT_ULong metaLength; + FT_ULong metaOrigLength; + FT_ULong privOffset; + FT_ULong privLength; + + FT_ULong uncompressed_size; /* uncompressed brotli stream size */ + FT_ULong compressed_offset; /* compressed stream offset */ + FT_ULong header_version; /* version of original TTC Header */ + FT_UShort num_fonts; /* number of fonts in TTC */ + FT_ULong actual_sfnt_size; /* actual size of sfnt stream */ + + WOFF2_TtcFont ttc_fonts; /* metadata for fonts in a TTC */ + + } WOFF2_HeaderRec, *WOFF2_Header; + + + /************************************************************************** + * + * @struct: + * WOFF2_TableRec + * + * @description: + * This structure describes a given table of a WOFF2 font. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF2/#table_dir_format + */ + typedef struct WOFF2_TableRec_ + { + FT_Byte FlagByte; /* table type and flags */ + FT_Tag Tag; /* table file offset */ + FT_ULong dst_length; /* uncompressed table length */ + FT_ULong TransformLength; /* transformed length */ + + FT_ULong flags; /* calculated flags */ + FT_ULong src_offset; /* compressed table offset */ + FT_ULong src_length; /* compressed table length */ + FT_ULong dst_offset; /* uncompressed table offset */ + + } WOFF2_TableRec, *WOFF2_Table; + + + /************************************************************************** + * + * @struct: + * WOFF2_InfoRec + * + * @description: + * Metadata for WOFF2 font that may be required for reconstruction of + * sfnt tables. + * + * @fields: + * header_checksum :: + * Checksum of SFNT offset table. + * + * num_glyphs :: + * Number of glyphs in the font. + * + * num_hmetrics :: + * `numberOfHMetrics` field in the 'hhea' table. + * + * x_mins :: + * `xMin` values of glyph bounding box. + * + * glyf_table :: + * A pointer to the `glyf' table record. + * + * loca_table :: + * A pointer to the `loca' table record. + * + * head_table :: + * A pointer to the `head' table record. + */ + typedef struct WOFF2_InfoRec_ + { + FT_ULong header_checksum; + FT_UShort num_glyphs; + FT_UShort num_hmetrics; + FT_Short* x_mins; + + WOFF2_Table glyf_table; + WOFF2_Table loca_table; + WOFF2_Table head_table; + + } WOFF2_InfoRec, *WOFF2_Info; + + + /************************************************************************** + * + * @struct: + * WOFF2_SubstreamRec + * + * @description: + * This structure stores information about a substream in the transformed + * 'glyf' table in a WOFF2 stream. + * + * @fields: + * start :: + * Beginning of the substream relative to uncompressed table stream. + * + * offset :: + * Offset of the substream relative to uncompressed table stream. + * + * size :: + * Size of the substream. + */ + typedef struct WOFF2_SubstreamRec_ + { + FT_ULong start; + FT_ULong offset; + FT_ULong size; + + } WOFF2_SubstreamRec, *WOFF2_Substream; + + + /************************************************************************** + * + * @struct: + * WOFF2_PointRec + * + * @description: + * This structure stores information about a point in the transformed + * 'glyf' table in a WOFF2 stream. + * + * @fields: + * x :: + * x-coordinate of point. + * + * y :: + * y-coordinate of point. + * + * on_curve :: + * Set if point is on-curve. + */ + typedef struct WOFF2_PointRec_ + { + FT_Int x; + FT_Int y; + FT_Bool on_curve; + + } WOFF2_PointRec, *WOFF2_Point; + + +FT_END_HEADER + +#endif /* WOFFTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/otsvg.h b/vendor/freetype/include/freetype/otsvg.h new file mode 100644 index 0000000..bfe9a6a --- /dev/null +++ b/vendor/freetype/include/freetype/otsvg.h @@ -0,0 +1,336 @@ +/**************************************************************************** + * + * otsvg.h + * + * Interface for OT-SVG support related things (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTSVG_H_ +#define OTSVG_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * svg_fonts + * + * @title: + * OpenType SVG Fonts + * + * @abstract: + * OT-SVG API between FreeType and an external SVG rendering library. + * + * @description: + * This section describes the four hooks necessary to render SVG + * 'documents' that are contained in an OpenType font's 'SVG~' table. + * + * For more information on the implementation, see our standard hooks + * based on 'librsvg' in the [FreeType Demo + * Programs](https://gitlab.freedesktop.org/freetype/freetype-demos) + * repository. + * + */ + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Init_Func + * + * @description: + * A callback that is called when the first OT-SVG glyph is rendered in + * the lifetime of an @FT_Library object. In a typical implementation, + * one would want to allocate a structure and point the `data_pointer` + * to it and perform any library initializations that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Init_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Free_Func + * + * @description: + * A callback that is called when the `ot-svg` module is being freed. + * It is only called if the init hook was called earlier. This means + * that neither the init nor the free hook is called if no OT-SVG glyph + * is rendered. + * + * In a typical implementation, one would want to free any state + * structure that was allocated in the init hook and perform any + * library-related closure that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @since: + * 2.12 + */ + typedef void + (*SVG_Lib_Free_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Render_Func + * + * @description: + * A callback that is called to render an OT-SVG glyph. This callback + * hook is called right after the preset hook @SVG_Lib_Preset_Slot_Func + * has been called with `cache` set to `TRUE`. The data necessary to + * render is available through the handle @FT_SVG_Document, which is set + * in the `other` field of @FT_GlyphSlotRec. + * + * The render hook is expected to render the SVG glyph to the bitmap + * buffer that is allocated already at `slot->bitmap.buffer`. It also + * sets the `num_grays` value as well as `slot->format`. + * + * @input: + * slot :: + * The slot to render. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Render_Func)( FT_GlyphSlot slot, + FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Preset_Slot_Func + * + * @description: + * A callback that is called to preset the glyph slot. It is called from + * two places. + * + * 1. When `FT_Load_Glyph` needs to preset the glyph slot. + * + * 2. Right before the `svg` module calls the render callback hook. + * + * When it is the former, the argument `cache` is set to `FALSE`. When + * it is the latter, the argument `cache` is set to `TRUE`. This + * distinction has been made because many calculations that are necessary + * for presetting a glyph slot are the same needed later for the render + * callback hook. Thus, if `cache` is `TRUE`, the hook can _cache_ those + * calculations in a memory block referenced by the state pointer. + * + * This hook is expected to preset the slot by setting parameters such as + * `bitmap_left`, `bitmap_top`, `width`, `rows`, `pitch`, and + * `pixel_mode`. It is also expected to set all the metrics for the slot + * including the vertical advance if it is not already set. Typically, + * fonts have horizontal advances but not vertical ones. If those are + * available, they had already been set, otherwise they have to be + * estimated and set manually. The hook must take into account the + * transformations that have been set, and translate the transformation + * matrices into the SVG coordinate system, as the original matrix is + * intended for the TTF/CFF coordinate system. + * + * @input: + * slot :: + * The glyph slot that has the SVG document loaded. + * + * cache :: + * See description. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Preset_Slot_Func)( FT_GlyphSlot slot, + FT_Bool cache, + FT_Pointer *state ); + + + /************************************************************************** + * + * @struct: + * SVG_RendererHooks + * + * @description: + * A structure that stores the four hooks needed to render OT-SVG glyphs + * properly. The structure is publicly used to set the hooks via the + * @svg-hooks driver property. + * + * The behavior of each hook is described in its documentation. One + * thing to note is that the preset hook and the render hook often need + * to do the same operations; therefore, it's better to cache the + * intermediate data in a state structure to avoid calculating it twice. + * For example, in the preset hook one can draw the glyph on a recorder + * surface and later create a bitmap surface from it in the render hook. + * + * All four hooks must be non-NULL. + * + * @fields: + * init_svg :: + * The initialization hook. + * + * free_svg :: + * The cleanup hook. + * + * render_hook :: + * The render hook. + * + * preset_slot :: + * The preset hook. + * + * @since: + * 2.12 + */ + typedef struct SVG_RendererHooks_ + { + SVG_Lib_Init_Func init_svg; + SVG_Lib_Free_Func free_svg; + SVG_Lib_Render_Func render_svg; + + SVG_Lib_Preset_Slot_Func preset_slot; + + } SVG_RendererHooks; + + + /************************************************************************** + * + * @struct: + * FT_SVG_DocumentRec + * + * @description: + * A structure that models one SVG document. + * + * @fields: + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * The translation to apply to the glyph while rendering. + * + * @note: + * When an @FT_GlyphSlot object `slot` is passed down to a renderer, the + * renderer can only access the `metrics` and `units_per_EM` fields via + * `slot->face`. However, when @FT_Glyph_To_Bitmap sets up a dummy + * object, it has no way to set a `face` object. Thus, metrics + * information and `units_per_EM` (which is necessary for OT-SVG) has to + * be stored separately. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_ + { + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SVG_DocumentRec; + + + /************************************************************************** + * + * @type: + * FT_SVG_Document + * + * @description: + * A handle to an @FT_SVG_DocumentRec object. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_* FT_SVG_Document; + + +FT_END_HEADER + +#endif /* OTSVG_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/t1tables.h b/vendor/freetype/include/freetype/t1tables.h new file mode 100644 index 0000000..1aecfbb --- /dev/null +++ b/vendor/freetype/include/freetype/t1tables.h @@ -0,0 +1,793 @@ +/**************************************************************************** + * + * t1tables.h + * + * Basic Type 1/Type 2 tables definitions and interface (specification + * only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1TABLES_H_ +#define T1TABLES_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * type1_tables + * + * @title: + * Type 1 Tables + * + * @abstract: + * Type~1-specific font tables. + * + * @description: + * This section contains the definition of Type~1-specific tables, + * including structures related to other PostScript font formats. + * + * @order: + * PS_FontInfoRec + * PS_FontInfo + * PS_PrivateRec + * PS_Private + * + * CID_FaceDictRec + * CID_FaceDict + * CID_FaceInfoRec + * CID_FaceInfo + * + * FT_Has_PS_Glyph_Names + * FT_Get_PS_Font_Info + * FT_Get_PS_Font_Private + * FT_Get_PS_Font_Value + * + * T1_Blend_Flags + * T1_EncodingType + * PS_Dict_Keys + * + */ + + + /* Note that we separate font data in PS_FontInfoRec and PS_PrivateRec */ + /* structures in order to support Multiple Master fonts. */ + + + /************************************************************************** + * + * @struct: + * PS_FontInfoRec + * + * @description: + * A structure used to model a Type~1 or Type~2 FontInfo dictionary. + * Note that for Multiple Master fonts, each instance has its own + * FontInfo dictionary. + */ + typedef struct PS_FontInfoRec_ + { + FT_String* version; + FT_String* notice; + FT_String* full_name; + FT_String* family_name; + FT_String* weight; + FT_Long italic_angle; + FT_Bool is_fixed_pitch; + FT_Short underline_position; + FT_UShort underline_thickness; + + } PS_FontInfoRec; + + + /************************************************************************** + * + * @struct: + * PS_FontInfo + * + * @description: + * A handle to a @PS_FontInfoRec structure. + */ + typedef struct PS_FontInfoRec_* PS_FontInfo; + + + /************************************************************************** + * + * @struct: + * T1_FontInfo + * + * @description: + * This type is equivalent to @PS_FontInfoRec. It is deprecated but kept + * to maintain source compatibility between various versions of FreeType. + */ + typedef PS_FontInfoRec T1_FontInfo; + + + /************************************************************************** + * + * @struct: + * PS_PrivateRec + * + * @description: + * A structure used to model a Type~1 or Type~2 private dictionary. Note + * that for Multiple Master fonts, each instance has its own Private + * dictionary. + */ + typedef struct PS_PrivateRec_ + { + FT_Int unique_id; + FT_Int lenIV; + + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Short blue_values[14]; + FT_Short other_blues[10]; + + FT_Short family_blues [14]; + FT_Short family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_fuzz; + + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Bool force_bold; + FT_Bool round_stem_up; + + FT_Short snap_widths [13]; /* including std width */ + FT_Short snap_heights[13]; /* including std height */ + + FT_Fixed expansion_factor; + + FT_Long language_group; + FT_Long password; + + FT_Short min_feature[2]; + + } PS_PrivateRec; + + + /************************************************************************** + * + * @struct: + * PS_Private + * + * @description: + * A handle to a @PS_PrivateRec structure. + */ + typedef struct PS_PrivateRec_* PS_Private; + + + /************************************************************************** + * + * @struct: + * T1_Private + * + * @description: + * This type is equivalent to @PS_PrivateRec. It is deprecated but kept + * to maintain source compatibility between various versions of FreeType. + */ + typedef PS_PrivateRec T1_Private; + + + /************************************************************************** + * + * @enum: + * T1_Blend_Flags + * + * @description: + * A set of flags used to indicate which fields are present in a given + * blend dictionary (font info or private). Used to support Multiple + * Masters fonts. + * + * @values: + * T1_BLEND_UNDERLINE_POSITION :: + * T1_BLEND_UNDERLINE_THICKNESS :: + * T1_BLEND_ITALIC_ANGLE :: + * T1_BLEND_BLUE_VALUES :: + * T1_BLEND_OTHER_BLUES :: + * T1_BLEND_STANDARD_WIDTH :: + * T1_BLEND_STANDARD_HEIGHT :: + * T1_BLEND_STEM_SNAP_WIDTHS :: + * T1_BLEND_STEM_SNAP_HEIGHTS :: + * T1_BLEND_BLUE_SCALE :: + * T1_BLEND_BLUE_SHIFT :: + * T1_BLEND_FAMILY_BLUES :: + * T1_BLEND_FAMILY_OTHER_BLUES :: + * T1_BLEND_FORCE_BOLD :: + */ + typedef enum T1_Blend_Flags_ + { + /* required fields in a FontInfo blend dictionary */ + T1_BLEND_UNDERLINE_POSITION = 0, + T1_BLEND_UNDERLINE_THICKNESS, + T1_BLEND_ITALIC_ANGLE, + + /* required fields in a Private blend dictionary */ + T1_BLEND_BLUE_VALUES, + T1_BLEND_OTHER_BLUES, + T1_BLEND_STANDARD_WIDTH, + T1_BLEND_STANDARD_HEIGHT, + T1_BLEND_STEM_SNAP_WIDTHS, + T1_BLEND_STEM_SNAP_HEIGHTS, + T1_BLEND_BLUE_SCALE, + T1_BLEND_BLUE_SHIFT, + T1_BLEND_FAMILY_BLUES, + T1_BLEND_FAMILY_OTHER_BLUES, + T1_BLEND_FORCE_BOLD, + + T1_BLEND_MAX /* do not remove */ + + } T1_Blend_Flags; + + + /* these constants are deprecated; use the corresponding */ + /* `T1_Blend_Flags` values instead */ +#define t1_blend_underline_position T1_BLEND_UNDERLINE_POSITION +#define t1_blend_underline_thickness T1_BLEND_UNDERLINE_THICKNESS +#define t1_blend_italic_angle T1_BLEND_ITALIC_ANGLE +#define t1_blend_blue_values T1_BLEND_BLUE_VALUES +#define t1_blend_other_blues T1_BLEND_OTHER_BLUES +#define t1_blend_standard_widths T1_BLEND_STANDARD_WIDTH +#define t1_blend_standard_height T1_BLEND_STANDARD_HEIGHT +#define t1_blend_stem_snap_widths T1_BLEND_STEM_SNAP_WIDTHS +#define t1_blend_stem_snap_heights T1_BLEND_STEM_SNAP_HEIGHTS +#define t1_blend_blue_scale T1_BLEND_BLUE_SCALE +#define t1_blend_blue_shift T1_BLEND_BLUE_SHIFT +#define t1_blend_family_blues T1_BLEND_FAMILY_BLUES +#define t1_blend_family_other_blues T1_BLEND_FAMILY_OTHER_BLUES +#define t1_blend_force_bold T1_BLEND_FORCE_BOLD +#define t1_blend_max T1_BLEND_MAX + + /* */ + + + /* maximum number of Multiple Masters designs, as defined in the spec */ +#define T1_MAX_MM_DESIGNS 16 + + /* maximum number of Multiple Masters axes, as defined in the spec */ +#define T1_MAX_MM_AXIS 4 + + /* maximum number of elements in a design map */ +#define T1_MAX_MM_MAP_POINTS 20 + + + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct PS_DesignMap_ + { + FT_Byte num_points; + FT_Long* design_points; + FT_Fixed* blend_points; + + } PS_DesignMapRec, *PS_DesignMap; + + /* backward compatible definition */ + typedef PS_DesignMapRec T1_DesignMap; + + + typedef struct PS_BlendRec_ + { + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; + + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + + PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; + PS_Private privates [T1_MAX_MM_DESIGNS + 1]; + + FT_ULong blend_bitflags; + + FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; + + /* since 2.3.0 */ + + /* undocumented, optional: the default design instance; */ + /* corresponds to default_weight_vector -- */ + /* num_default_design_vector == 0 means it is not present */ + /* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + + } PS_BlendRec, *PS_Blend; + + + /* backward compatible definition */ + typedef PS_BlendRec T1_Blend; + + + /************************************************************************** + * + * @struct: + * CID_FaceDictRec + * + * @description: + * A structure used to represent data in a CID top-level dictionary. In + * most cases, they are part of the font's '/FDArray' array. Within a + * CID font file, such (internal) subfont dictionaries are enclosed by + * '%ADOBeginFontDict' and '%ADOEndFontDict' comments. + * + * Note that `CID_FaceDictRec` misses a field for the '/FontName' + * keyword, specifying the subfont's name (the top-level font name is + * given by the '/CIDFontName' keyword). This is an oversight, but it + * doesn't limit the 'cid' font module's functionality because FreeType + * neither needs this entry nor gives access to CID subfonts. + */ + typedef struct CID_FaceDictRec_ + { + PS_PrivateRec private_dict; + + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; /* this is a duplicate of */ + /* `private_dict->expansion_factor' */ + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_UInt num_subrs; + FT_ULong subrmap_offset; + FT_UInt sd_bytes; + + } CID_FaceDictRec; + + + /************************************************************************** + * + * @struct: + * CID_FaceDict + * + * @description: + * A handle to a @CID_FaceDictRec structure. + */ + typedef struct CID_FaceDictRec_* CID_FaceDict; + + + /************************************************************************** + * + * @struct: + * CID_FontDict + * + * @description: + * This type is equivalent to @CID_FaceDictRec. It is deprecated but + * kept to maintain source compatibility between various versions of + * FreeType. + */ + typedef CID_FaceDictRec CID_FontDict; + + + /************************************************************************** + * + * @struct: + * CID_FaceInfoRec + * + * @description: + * A structure used to represent CID Face information. + */ + typedef struct CID_FaceInfoRec_ + { + FT_String* cid_font_name; + FT_Fixed cid_version; + FT_Int cid_font_type; + + FT_String* registry; + FT_String* ordering; + FT_Int supplement; + + PS_FontInfoRec font_info; + FT_BBox font_bbox; + FT_ULong uid_base; + + FT_Int num_xuid; + FT_ULong xuid[16]; + + FT_ULong cidmap_offset; + FT_UInt fd_bytes; + FT_UInt gd_bytes; + FT_ULong cid_count; + + FT_UInt num_dicts; + CID_FaceDict font_dicts; + + FT_ULong data_offset; + + } CID_FaceInfoRec; + + + /************************************************************************** + * + * @struct: + * CID_FaceInfo + * + * @description: + * A handle to a @CID_FaceInfoRec structure. + */ + typedef struct CID_FaceInfoRec_* CID_FaceInfo; + + + /************************************************************************** + * + * @struct: + * CID_Info + * + * @description: + * This type is equivalent to @CID_FaceInfoRec. It is deprecated but kept + * to maintain source compatibility between various versions of FreeType. + */ + typedef CID_FaceInfoRec CID_Info; + + + /************************************************************************** + * + * @function: + * FT_Has_PS_Glyph_Names + * + * @description: + * Return true if a given face provides reliable PostScript glyph names. + * This is similar to using the @FT_HAS_GLYPH_NAMES macro, except that + * certain fonts (mostly TrueType) contain incorrect glyph name tables. + * + * When this function returns true, the caller is sure that the glyph + * names returned by @FT_Get_Glyph_Name are reliable. + * + * @input: + * face :: + * face handle + * + * @return: + * Boolean. True if glyph names are reliable. + * + */ + FT_EXPORT( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Get_PS_Font_Info + * + * @description: + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_info :: + * A pointer to a @PS_FontInfoRec object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * String pointers within the @PS_FontInfoRec structure are owned by the + * face and don't need to be freed by the caller. Missing entries in the + * font's FontInfo dictionary are represented by `NULL` pointers. + * + * The following font formats support this feature: 'Type~1', 'Type~42', + * 'CFF', 'CID~Type~1'. For other font formats this function returns the + * `FT_Err_Invalid_Argument` error code. + * + * @example: + * ``` + * PS_FontInfoRec font_info; + * + * + * error = FT_Get_PS_Font_Info( face, &font_info ); + * ... + * ``` + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfo afont_info ); + + + /************************************************************************** + * + * @function: + * FT_Get_PS_Font_Private + * + * @description: + * Retrieve the @PS_PrivateRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_private :: + * A pointer to a @PS_PrivateRec object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The string pointers within the @PS_PrivateRec structure are owned by + * the face and don't need to be freed by the caller. + * + * Only the 'Type~1' font format supports this feature. For other font + * formats this function returns the `FT_Err_Invalid_Argument` error + * code. + * + * @example: + * ``` + * PS_PrivateRec font_private; + * + * + * error = FT_Get_PS_Font_Private( face, &font_private ); + * ... + * ``` + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_Private afont_private ); + + + /************************************************************************** + * + * @enum: + * T1_EncodingType + * + * @description: + * An enumeration describing the 'Encoding' entry in a Type 1 dictionary. + * + * @values: + * T1_ENCODING_TYPE_NONE :: + * T1_ENCODING_TYPE_ARRAY :: + * T1_ENCODING_TYPE_STANDARD :: + * T1_ENCODING_TYPE_ISOLATIN1 :: + * T1_ENCODING_TYPE_EXPERT :: + * + * @since: + * 2.4.8 + */ + typedef enum T1_EncodingType_ + { + T1_ENCODING_TYPE_NONE = 0, + T1_ENCODING_TYPE_ARRAY, + T1_ENCODING_TYPE_STANDARD, + T1_ENCODING_TYPE_ISOLATIN1, + T1_ENCODING_TYPE_EXPERT + + } T1_EncodingType; + + + /************************************************************************** + * + * @enum: + * PS_Dict_Keys + * + * @description: + * An enumeration used in calls to @FT_Get_PS_Font_Value to identify the + * Type~1 dictionary entry to retrieve. + * + * @values: + * PS_DICT_FONT_TYPE :: + * PS_DICT_FONT_MATRIX :: + * PS_DICT_FONT_BBOX :: + * PS_DICT_PAINT_TYPE :: + * PS_DICT_FONT_NAME :: + * PS_DICT_UNIQUE_ID :: + * PS_DICT_NUM_CHAR_STRINGS :: + * PS_DICT_CHAR_STRING_KEY :: + * PS_DICT_CHAR_STRING :: + * PS_DICT_ENCODING_TYPE :: + * PS_DICT_ENCODING_ENTRY :: + * PS_DICT_NUM_SUBRS :: + * PS_DICT_SUBR :: + * PS_DICT_STD_HW :: + * PS_DICT_STD_VW :: + * PS_DICT_NUM_BLUE_VALUES :: + * PS_DICT_BLUE_VALUE :: + * PS_DICT_BLUE_FUZZ :: + * PS_DICT_NUM_OTHER_BLUES :: + * PS_DICT_OTHER_BLUE :: + * PS_DICT_NUM_FAMILY_BLUES :: + * PS_DICT_FAMILY_BLUE :: + * PS_DICT_NUM_FAMILY_OTHER_BLUES :: + * PS_DICT_FAMILY_OTHER_BLUE :: + * PS_DICT_BLUE_SCALE :: + * PS_DICT_BLUE_SHIFT :: + * PS_DICT_NUM_STEM_SNAP_H :: + * PS_DICT_STEM_SNAP_H :: + * PS_DICT_NUM_STEM_SNAP_V :: + * PS_DICT_STEM_SNAP_V :: + * PS_DICT_FORCE_BOLD :: + * PS_DICT_RND_STEM_UP :: + * PS_DICT_MIN_FEATURE :: + * PS_DICT_LEN_IV :: + * PS_DICT_PASSWORD :: + * PS_DICT_LANGUAGE_GROUP :: + * PS_DICT_VERSION :: + * PS_DICT_NOTICE :: + * PS_DICT_FULL_NAME :: + * PS_DICT_FAMILY_NAME :: + * PS_DICT_WEIGHT :: + * PS_DICT_IS_FIXED_PITCH :: + * PS_DICT_UNDERLINE_POSITION :: + * PS_DICT_UNDERLINE_THICKNESS :: + * PS_DICT_FS_TYPE :: + * PS_DICT_ITALIC_ANGLE :: + * + * @since: + * 2.4.8 + */ + typedef enum PS_Dict_Keys_ + { + /* conventionally in the font dictionary */ + PS_DICT_FONT_TYPE, /* FT_Byte */ + PS_DICT_FONT_MATRIX, /* FT_Fixed */ + PS_DICT_FONT_BBOX, /* FT_Fixed */ + PS_DICT_PAINT_TYPE, /* FT_Byte */ + PS_DICT_FONT_NAME, /* FT_String* */ + PS_DICT_UNIQUE_ID, /* FT_Int */ + PS_DICT_NUM_CHAR_STRINGS, /* FT_Int */ + PS_DICT_CHAR_STRING_KEY, /* FT_String* */ + PS_DICT_CHAR_STRING, /* FT_String* */ + PS_DICT_ENCODING_TYPE, /* T1_EncodingType */ + PS_DICT_ENCODING_ENTRY, /* FT_String* */ + + /* conventionally in the font Private dictionary */ + PS_DICT_NUM_SUBRS, /* FT_Int */ + PS_DICT_SUBR, /* FT_String* */ + PS_DICT_STD_HW, /* FT_UShort */ + PS_DICT_STD_VW, /* FT_UShort */ + PS_DICT_NUM_BLUE_VALUES, /* FT_Byte */ + PS_DICT_BLUE_VALUE, /* FT_Short */ + PS_DICT_BLUE_FUZZ, /* FT_Int */ + PS_DICT_NUM_OTHER_BLUES, /* FT_Byte */ + PS_DICT_OTHER_BLUE, /* FT_Short */ + PS_DICT_NUM_FAMILY_BLUES, /* FT_Byte */ + PS_DICT_FAMILY_BLUE, /* FT_Short */ + PS_DICT_NUM_FAMILY_OTHER_BLUES, /* FT_Byte */ + PS_DICT_FAMILY_OTHER_BLUE, /* FT_Short */ + PS_DICT_BLUE_SCALE, /* FT_Fixed */ + PS_DICT_BLUE_SHIFT, /* FT_Int */ + PS_DICT_NUM_STEM_SNAP_H, /* FT_Byte */ + PS_DICT_STEM_SNAP_H, /* FT_Short */ + PS_DICT_NUM_STEM_SNAP_V, /* FT_Byte */ + PS_DICT_STEM_SNAP_V, /* FT_Short */ + PS_DICT_FORCE_BOLD, /* FT_Bool */ + PS_DICT_RND_STEM_UP, /* FT_Bool */ + PS_DICT_MIN_FEATURE, /* FT_Short */ + PS_DICT_LEN_IV, /* FT_Int */ + PS_DICT_PASSWORD, /* FT_Long */ + PS_DICT_LANGUAGE_GROUP, /* FT_Long */ + + /* conventionally in the font FontInfo dictionary */ + PS_DICT_VERSION, /* FT_String* */ + PS_DICT_NOTICE, /* FT_String* */ + PS_DICT_FULL_NAME, /* FT_String* */ + PS_DICT_FAMILY_NAME, /* FT_String* */ + PS_DICT_WEIGHT, /* FT_String* */ + PS_DICT_IS_FIXED_PITCH, /* FT_Bool */ + PS_DICT_UNDERLINE_POSITION, /* FT_Short */ + PS_DICT_UNDERLINE_THICKNESS, /* FT_UShort */ + PS_DICT_FS_TYPE, /* FT_UShort */ + PS_DICT_ITALIC_ANGLE, /* FT_Long */ + + PS_DICT_MAX = PS_DICT_ITALIC_ANGLE + + } PS_Dict_Keys; + + + /************************************************************************** + * + * @function: + * FT_Get_PS_Font_Value + * + * @description: + * Retrieve the value for the supplied key from a PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * key :: + * An enumeration value representing the dictionary key to retrieve. + * + * idx :: + * For array values, this specifies the index to be returned. + * + * value :: + * A pointer to memory into which to write the value. + * + * valen_len :: + * The size, in bytes, of the memory supplied for the value. + * + * @output: + * value :: + * The value matching the above key, if it exists. + * + * @return: + * The amount of memory (in bytes) required to hold the requested value + * (if it exists, -1 otherwise). + * + * @note: + * The values returned are not pointers into the internal structures of + * the face, but are 'fresh' copies, so that the memory containing them + * belongs to the calling application. This also enforces the + * 'read-only' nature of these values, i.e., this function cannot be + * used to manipulate the face. + * + * `value` is a void pointer because the values returned can be of + * various types. + * + * If either `value` is `NULL` or `value_len` is too small, just the + * required memory size for the requested entry is returned. + * + * The `idx` parameter is used, not only to retrieve elements of, for + * example, the FontMatrix or FontBBox, but also to retrieve name keys + * from the CharStrings dictionary, and the charstrings themselves. It + * is ignored for atomic values. + * + * `PS_DICT_BLUE_SCALE` returns a value that is scaled up by 1000. To + * get the value as in the font stream, you need to divide by 65536000.0 + * (to remove the FT_Fixed scale, and the x1000 scale). + * + * IMPORTANT: Only key/value pairs read by the FreeType interpreter can + * be retrieved. So, for example, PostScript procedures such as NP, ND, + * and RD are not available. Arbitrary keys are, obviously, not be + * available either. + * + * If the font's format is not PostScript-based, this function returns + * the `FT_Err_Invalid_Argument` error code. + * + * @since: + * 2.4.8 + * + */ + FT_EXPORT( FT_Long ) + FT_Get_PS_Font_Value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ); + + /* */ + +FT_END_HEADER + +#endif /* T1TABLES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/ttnameid.h b/vendor/freetype/include/freetype/ttnameid.h new file mode 100644 index 0000000..e31c68b --- /dev/null +++ b/vendor/freetype/include/freetype/ttnameid.h @@ -0,0 +1,1235 @@ +/**************************************************************************** + * + * ttnameid.h + * + * TrueType name ID definitions (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTNAMEID_H_ +#define TTNAMEID_H_ + + + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * truetype_tables + */ + + + /************************************************************************** + * + * Possible values for the 'platform' identifier code in the name records + * of an SFNT 'name' table. + * + */ + + + /************************************************************************** + * + * @enum: + * TT_PLATFORM_XXX + * + * @description: + * A list of valid values for the `platform_id` identifier code in + * @FT_CharMapRec and @FT_SfntName structures. + * + * @values: + * TT_PLATFORM_APPLE_UNICODE :: + * Used by Apple to indicate a Unicode character map and/or name entry. + * See @TT_APPLE_ID_XXX for corresponding `encoding_id` values. Note + * that name entries in this format are coded as big-endian UCS-2 + * character codes _only_. + * + * TT_PLATFORM_MACINTOSH :: + * Used by Apple to indicate a MacOS-specific charmap and/or name + * entry. See @TT_MAC_ID_XXX for corresponding `encoding_id` values. + * Note that most TrueType fonts contain an Apple roman charmap to be + * usable on MacOS systems (even if they contain a Microsoft charmap as + * well). + * + * TT_PLATFORM_ISO :: + * This value was used to specify ISO/IEC 10646 charmaps. It is + * however now deprecated. See @TT_ISO_ID_XXX for a list of + * corresponding `encoding_id` values. + * + * TT_PLATFORM_MICROSOFT :: + * Used by Microsoft to indicate Windows-specific charmaps. See + * @TT_MS_ID_XXX for a list of corresponding `encoding_id` values. + * Note that most fonts contain a Unicode charmap using + * (`TT_PLATFORM_MICROSOFT`, @TT_MS_ID_UNICODE_CS). + * + * TT_PLATFORM_CUSTOM :: + * Used to indicate application-specific charmaps. + * + * TT_PLATFORM_ADOBE :: + * This value isn't part of any font format specification, but is used + * by FreeType to report Adobe-specific charmaps in an @FT_CharMapRec + * structure. See @TT_ADOBE_ID_XXX. + */ + +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 +#define TT_PLATFORM_ISO 2 /* deprecated */ +#define TT_PLATFORM_MICROSOFT 3 +#define TT_PLATFORM_CUSTOM 4 +#define TT_PLATFORM_ADOBE 7 /* artificial */ + + + /************************************************************************** + * + * @enum: + * TT_APPLE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for + * @TT_PLATFORM_APPLE_UNICODE charmaps and name entries. + * + * @values: + * TT_APPLE_ID_DEFAULT :: + * Unicode version 1.0. + * + * TT_APPLE_ID_UNICODE_1_1 :: + * Unicode 1.1; specifies Hangul characters starting at U+34xx. + * + * TT_APPLE_ID_ISO_10646 :: + * Deprecated (identical to preceding). + * + * TT_APPLE_ID_UNICODE_2_0 :: + * Unicode 2.0 and beyond (UTF-16 BMP only). + * + * TT_APPLE_ID_UNICODE_32 :: + * Unicode 3.1 and beyond, using UTF-32. + * + * TT_APPLE_ID_VARIANT_SELECTOR :: + * From Adobe, not Apple. Not a normal cmap. Specifies variations on + * a real cmap. + * + * TT_APPLE_ID_FULL_UNICODE :: + * Used for fallback fonts that provide complete Unicode coverage with + * a type~13 cmap. + */ + +#define TT_APPLE_ID_DEFAULT 0 /* Unicode 1.0 */ +#define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */ +#define TT_APPLE_ID_ISO_10646 2 /* deprecated */ +#define TT_APPLE_ID_UNICODE_2_0 3 /* or later */ +#define TT_APPLE_ID_UNICODE_32 4 /* 2.0 or later, full repertoire */ +#define TT_APPLE_ID_VARIANT_SELECTOR 5 /* variation selector data */ +#define TT_APPLE_ID_FULL_UNICODE 6 /* used with type 13 cmaps */ + + + /************************************************************************** + * + * @enum: + * TT_MAC_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for + * @TT_PLATFORM_MACINTOSH charmaps and name entries. + */ + +#define TT_MAC_ID_ROMAN 0 +#define TT_MAC_ID_JAPANESE 1 +#define TT_MAC_ID_TRADITIONAL_CHINESE 2 +#define TT_MAC_ID_KOREAN 3 +#define TT_MAC_ID_ARABIC 4 +#define TT_MAC_ID_HEBREW 5 +#define TT_MAC_ID_GREEK 6 +#define TT_MAC_ID_RUSSIAN 7 +#define TT_MAC_ID_RSYMBOL 8 +#define TT_MAC_ID_DEVANAGARI 9 +#define TT_MAC_ID_GURMUKHI 10 +#define TT_MAC_ID_GUJARATI 11 +#define TT_MAC_ID_ORIYA 12 +#define TT_MAC_ID_BENGALI 13 +#define TT_MAC_ID_TAMIL 14 +#define TT_MAC_ID_TELUGU 15 +#define TT_MAC_ID_KANNADA 16 +#define TT_MAC_ID_MALAYALAM 17 +#define TT_MAC_ID_SINHALESE 18 +#define TT_MAC_ID_BURMESE 19 +#define TT_MAC_ID_KHMER 20 +#define TT_MAC_ID_THAI 21 +#define TT_MAC_ID_LAOTIAN 22 +#define TT_MAC_ID_GEORGIAN 23 +#define TT_MAC_ID_ARMENIAN 24 +#define TT_MAC_ID_MALDIVIAN 25 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 +#define TT_MAC_ID_TIBETAN 26 +#define TT_MAC_ID_MONGOLIAN 27 +#define TT_MAC_ID_GEEZ 28 +#define TT_MAC_ID_SLAVIC 29 +#define TT_MAC_ID_VIETNAMESE 30 +#define TT_MAC_ID_SINDHI 31 +#define TT_MAC_ID_UNINTERP 32 + + + /************************************************************************** + * + * @enum: + * TT_ISO_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for @TT_PLATFORM_ISO + * charmaps and name entries. + * + * Their use is now deprecated. + * + * @values: + * TT_ISO_ID_7BIT_ASCII :: + * ASCII. + * TT_ISO_ID_10646 :: + * ISO/10646. + * TT_ISO_ID_8859_1 :: + * Also known as Latin-1. + */ + +#define TT_ISO_ID_7BIT_ASCII 0 +#define TT_ISO_ID_10646 1 +#define TT_ISO_ID_8859_1 2 + + + /************************************************************************** + * + * @enum: + * TT_MS_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for + * @TT_PLATFORM_MICROSOFT charmaps and name entries. + * + * @values: + * TT_MS_ID_SYMBOL_CS :: + * Microsoft symbol encoding. See @FT_ENCODING_MS_SYMBOL. + * + * TT_MS_ID_UNICODE_CS :: + * Microsoft WGL4 charmap, matching Unicode. See @FT_ENCODING_UNICODE. + * + * TT_MS_ID_SJIS :: + * Shift JIS Japanese encoding. See @FT_ENCODING_SJIS. + * + * TT_MS_ID_PRC :: + * Chinese encodings as used in the People's Republic of China (PRC). + * This means the encodings GB~2312 and its supersets GBK and GB~18030. + * See @FT_ENCODING_PRC. + * + * TT_MS_ID_BIG_5 :: + * Traditional Chinese as used in Taiwan and Hong Kong. See + * @FT_ENCODING_BIG5. + * + * TT_MS_ID_WANSUNG :: + * Korean Extended Wansung encoding. See @FT_ENCODING_WANSUNG. + * + * TT_MS_ID_JOHAB :: + * Korean Johab encoding. See @FT_ENCODING_JOHAB. + * + * TT_MS_ID_UCS_4 :: + * UCS-4 or UTF-32 charmaps. This has been added to the OpenType + * specification version 1.4 (mid-2001). + */ + +#define TT_MS_ID_SYMBOL_CS 0 +#define TT_MS_ID_UNICODE_CS 1 +#define TT_MS_ID_SJIS 2 +#define TT_MS_ID_PRC 3 +#define TT_MS_ID_BIG_5 4 +#define TT_MS_ID_WANSUNG 5 +#define TT_MS_ID_JOHAB 6 +#define TT_MS_ID_UCS_4 10 + + /* this value is deprecated */ +#define TT_MS_ID_GB2312 TT_MS_ID_PRC + + + /************************************************************************** + * + * @enum: + * TT_ADOBE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for @TT_PLATFORM_ADOBE + * charmaps. This is a FreeType-specific extension! + * + * @values: + * TT_ADOBE_ID_STANDARD :: + * Adobe standard encoding. + * TT_ADOBE_ID_EXPERT :: + * Adobe expert encoding. + * TT_ADOBE_ID_CUSTOM :: + * Adobe custom encoding. + * TT_ADOBE_ID_LATIN_1 :: + * Adobe Latin~1 encoding. + */ + +#define TT_ADOBE_ID_STANDARD 0 +#define TT_ADOBE_ID_EXPERT 1 +#define TT_ADOBE_ID_CUSTOM 2 +#define TT_ADOBE_ID_LATIN_1 3 + + + /************************************************************************** + * + * @enum: + * TT_MAC_LANGID_XXX + * + * @description: + * Possible values of the language identifier field in the name records + * of the SFNT 'name' table if the 'platform' identifier code is + * @TT_PLATFORM_MACINTOSH. These values are also used as return values + * for function @FT_Get_CMap_Language_ID. + * + * The canonical source for Apple's IDs is + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html + */ + +#define TT_MAC_LANGID_ENGLISH 0 +#define TT_MAC_LANGID_FRENCH 1 +#define TT_MAC_LANGID_GERMAN 2 +#define TT_MAC_LANGID_ITALIAN 3 +#define TT_MAC_LANGID_DUTCH 4 +#define TT_MAC_LANGID_SWEDISH 5 +#define TT_MAC_LANGID_SPANISH 6 +#define TT_MAC_LANGID_DANISH 7 +#define TT_MAC_LANGID_PORTUGUESE 8 +#define TT_MAC_LANGID_NORWEGIAN 9 +#define TT_MAC_LANGID_HEBREW 10 +#define TT_MAC_LANGID_JAPANESE 11 +#define TT_MAC_LANGID_ARABIC 12 +#define TT_MAC_LANGID_FINNISH 13 +#define TT_MAC_LANGID_GREEK 14 +#define TT_MAC_LANGID_ICELANDIC 15 +#define TT_MAC_LANGID_MALTESE 16 +#define TT_MAC_LANGID_TURKISH 17 +#define TT_MAC_LANGID_CROATIAN 18 +#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 +#define TT_MAC_LANGID_URDU 20 +#define TT_MAC_LANGID_HINDI 21 +#define TT_MAC_LANGID_THAI 22 +#define TT_MAC_LANGID_KOREAN 23 +#define TT_MAC_LANGID_LITHUANIAN 24 +#define TT_MAC_LANGID_POLISH 25 +#define TT_MAC_LANGID_HUNGARIAN 26 +#define TT_MAC_LANGID_ESTONIAN 27 +#define TT_MAC_LANGID_LETTISH 28 +#define TT_MAC_LANGID_SAAMISK 29 +#define TT_MAC_LANGID_FAEROESE 30 +#define TT_MAC_LANGID_FARSI 31 +#define TT_MAC_LANGID_RUSSIAN 32 +#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 +#define TT_MAC_LANGID_FLEMISH 34 +#define TT_MAC_LANGID_IRISH 35 +#define TT_MAC_LANGID_ALBANIAN 36 +#define TT_MAC_LANGID_ROMANIAN 37 +#define TT_MAC_LANGID_CZECH 38 +#define TT_MAC_LANGID_SLOVAK 39 +#define TT_MAC_LANGID_SLOVENIAN 40 +#define TT_MAC_LANGID_YIDDISH 41 +#define TT_MAC_LANGID_SERBIAN 42 +#define TT_MAC_LANGID_MACEDONIAN 43 +#define TT_MAC_LANGID_BULGARIAN 44 +#define TT_MAC_LANGID_UKRAINIAN 45 +#define TT_MAC_LANGID_BYELORUSSIAN 46 +#define TT_MAC_LANGID_UZBEK 47 +#define TT_MAC_LANGID_KAZAKH 48 +#define TT_MAC_LANGID_AZERBAIJANI 49 +#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 +#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 +#define TT_MAC_LANGID_ARMENIAN 51 +#define TT_MAC_LANGID_GEORGIAN 52 +#define TT_MAC_LANGID_MOLDAVIAN 53 +#define TT_MAC_LANGID_KIRGHIZ 54 +#define TT_MAC_LANGID_TAJIKI 55 +#define TT_MAC_LANGID_TURKMEN 56 +#define TT_MAC_LANGID_MONGOLIAN 57 +#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 +#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 +#define TT_MAC_LANGID_PASHTO 59 +#define TT_MAC_LANGID_KURDISH 60 +#define TT_MAC_LANGID_KASHMIRI 61 +#define TT_MAC_LANGID_SINDHI 62 +#define TT_MAC_LANGID_TIBETAN 63 +#define TT_MAC_LANGID_NEPALI 64 +#define TT_MAC_LANGID_SANSKRIT 65 +#define TT_MAC_LANGID_MARATHI 66 +#define TT_MAC_LANGID_BENGALI 67 +#define TT_MAC_LANGID_ASSAMESE 68 +#define TT_MAC_LANGID_GUJARATI 69 +#define TT_MAC_LANGID_PUNJABI 70 +#define TT_MAC_LANGID_ORIYA 71 +#define TT_MAC_LANGID_MALAYALAM 72 +#define TT_MAC_LANGID_KANNADA 73 +#define TT_MAC_LANGID_TAMIL 74 +#define TT_MAC_LANGID_TELUGU 75 +#define TT_MAC_LANGID_SINHALESE 76 +#define TT_MAC_LANGID_BURMESE 77 +#define TT_MAC_LANGID_KHMER 78 +#define TT_MAC_LANGID_LAO 79 +#define TT_MAC_LANGID_VIETNAMESE 80 +#define TT_MAC_LANGID_INDONESIAN 81 +#define TT_MAC_LANGID_TAGALOG 82 +#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 +#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 +#define TT_MAC_LANGID_AMHARIC 85 +#define TT_MAC_LANGID_TIGRINYA 86 +#define TT_MAC_LANGID_GALLA 87 +#define TT_MAC_LANGID_SOMALI 88 +#define TT_MAC_LANGID_SWAHILI 89 +#define TT_MAC_LANGID_RUANDA 90 +#define TT_MAC_LANGID_RUNDI 91 +#define TT_MAC_LANGID_CHEWA 92 +#define TT_MAC_LANGID_MALAGASY 93 +#define TT_MAC_LANGID_ESPERANTO 94 +#define TT_MAC_LANGID_WELSH 128 +#define TT_MAC_LANGID_BASQUE 129 +#define TT_MAC_LANGID_CATALAN 130 +#define TT_MAC_LANGID_LATIN 131 +#define TT_MAC_LANGID_QUECHUA 132 +#define TT_MAC_LANGID_GUARANI 133 +#define TT_MAC_LANGID_AYMARA 134 +#define TT_MAC_LANGID_TATAR 135 +#define TT_MAC_LANGID_UIGHUR 136 +#define TT_MAC_LANGID_DZONGKHA 137 +#define TT_MAC_LANGID_JAVANESE 138 +#define TT_MAC_LANGID_SUNDANESE 139 + + /* The following codes are new as of 2000-03-10 */ +#define TT_MAC_LANGID_GALICIAN 140 +#define TT_MAC_LANGID_AFRIKAANS 141 +#define TT_MAC_LANGID_BRETON 142 +#define TT_MAC_LANGID_INUKTITUT 143 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 144 +#define TT_MAC_LANGID_MANX_GAELIC 145 +#define TT_MAC_LANGID_IRISH_GAELIC 146 +#define TT_MAC_LANGID_TONGAN 147 +#define TT_MAC_LANGID_GREEK_POLYTONIC 148 +#define TT_MAC_LANGID_GREELANDIC 149 +#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 + + + /************************************************************************** + * + * @enum: + * TT_MS_LANGID_XXX + * + * @description: + * Possible values of the language identifier field in the name records + * of the SFNT 'name' table if the 'platform' identifier code is + * @TT_PLATFORM_MICROSOFT. These values are also used as return values + * for function @FT_Get_CMap_Language_ID. + * + * The canonical source for Microsoft's IDs is + * + * https://docs.microsoft.com/en-us/windows/desktop/Intl/language-identifier-constants-and-strings , + * + * however, we only provide macros for language identifiers present in + * the OpenType specification: Microsoft has abandoned the concept of + * LCIDs (language code identifiers), and format~1 of the 'name' table + * provides a better mechanism for languages not covered here. + * + * More legacy values not listed in the reference can be found in the + * @FT_TRUETYPE_IDS_H header file. + */ + +#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 +#define TT_MS_LANGID_ARABIC_IRAQ 0x0801 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0C01 +#define TT_MS_LANGID_ARABIC_LIBYA 0x1001 +#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 +#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1C01 +#define TT_MS_LANGID_ARABIC_OMAN 0x2001 +#define TT_MS_LANGID_ARABIC_YEMEN 0x2401 +#define TT_MS_LANGID_ARABIC_SYRIA 0x2801 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2C01 +#define TT_MS_LANGID_ARABIC_LEBANON 0x3001 +#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 +#define TT_MS_LANGID_ARABIC_UAE 0x3801 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3C01 +#define TT_MS_LANGID_ARABIC_QATAR 0x4001 +#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 +#define TT_MS_LANGID_CATALAN_CATALAN 0x0403 +#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 +#define TT_MS_LANGID_CHINESE_PRC 0x0804 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0C04 +#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 +#define TT_MS_LANGID_CHINESE_MACAO 0x1404 +#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405 +#define TT_MS_LANGID_DANISH_DENMARK 0x0406 +#define TT_MS_LANGID_GERMAN_GERMANY 0x0407 +#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0C07 +#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 +#define TT_MS_LANGID_GERMAN_LIECHTENSTEIN 0x1407 +#define TT_MS_LANGID_GREEK_GREECE 0x0408 +#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 +#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0C09 +#define TT_MS_LANGID_ENGLISH_CANADA 0x1009 +#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 +#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1C09 +#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 +#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 +#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2C09 +#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 +#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 +#define TT_MS_LANGID_ENGLISH_INDIA 0x4009 +#define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409 +#define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809 +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040A +#define TT_MS_LANGID_SPANISH_MEXICO 0x080A +#define TT_MS_LANGID_SPANISH_SPAIN_MODERN_SORT 0x0C0A +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100A +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140A +#define TT_MS_LANGID_SPANISH_PANAMA 0x180A +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1C0A +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200A +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240A +#define TT_MS_LANGID_SPANISH_PERU 0x280A +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2C0A +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300A +#define TT_MS_LANGID_SPANISH_CHILE 0x340A +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380A +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3C0A +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400A +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440A +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480A +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4C0A +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500A +#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540A +#define TT_MS_LANGID_FINNISH_FINLAND 0x040B +#define TT_MS_LANGID_FRENCH_FRANCE 0x040C +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080C +#define TT_MS_LANGID_FRENCH_CANADA 0x0C0C +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100C +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140C +#define TT_MS_LANGID_FRENCH_MONACO 0x180C +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040D +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040E +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040F +#define TT_MS_LANGID_ITALIAN_ITALY 0x0410 +#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 +#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 +#define TT_MS_LANGID_KOREAN_KOREA 0x0412 +#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413 +#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814 +#define TT_MS_LANGID_POLISH_POLAND 0x0415 +#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416 +#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816 +#define TT_MS_LANGID_ROMANSH_SWITZERLAND 0x0417 +#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418 +#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041A +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081A +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0C1A +#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101A +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141A +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181A +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x1C1A +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZ_CYRILLIC 0x201A +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041B +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041C +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041D +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081D +#define TT_MS_LANGID_THAI_THAILAND 0x041E +#define TT_MS_LANGID_TURKISH_TURKEY 0x041F +#define TT_MS_LANGID_URDU_PAKISTAN 0x0420 +#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 +#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422 +#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423 +#define TT_MS_LANGID_SLOVENIAN_SLOVENIA 0x0424 +#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425 +#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426 +#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427 +#define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428 +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042A +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042B +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042C +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082C +#define TT_MS_LANGID_BASQUE_BASQUE 0x042D +#define TT_MS_LANGID_UPPER_SORBIAN_GERMANY 0x042E +#define TT_MS_LANGID_LOWER_SORBIAN_GERMANY 0x082E +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042F +#define TT_MS_LANGID_SETSWANA_SOUTH_AFRICA 0x0432 +#define TT_MS_LANGID_ISIXHOSA_SOUTH_AFRICA 0x0434 +#define TT_MS_LANGID_ISIZULU_SOUTH_AFRICA 0x0435 +#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436 +#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 +#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 +#define TT_MS_LANGID_HINDI_INDIA 0x0439 +#define TT_MS_LANGID_MALTESE_MALTA 0x043A +#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043B +#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083B +#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3B +#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103B +#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143B +#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183B +#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3B +#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203B +#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243B +#define TT_MS_LANGID_IRISH_IRELAND 0x083C +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043E +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083E +#define TT_MS_LANGID_KAZAKH_KAZAKHSTAN 0x043F +#define TT_MS_LANGID_KYRGYZ_KYRGYZSTAN /* Cyrillic */ 0x0440 +#define TT_MS_LANGID_KISWAHILI_KENYA 0x0441 +#define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843 +#define TT_MS_LANGID_TATAR_RUSSIA 0x0444 +#define TT_MS_LANGID_BENGALI_INDIA 0x0445 +#define TT_MS_LANGID_BENGALI_BANGLADESH 0x0845 +#define TT_MS_LANGID_PUNJABI_INDIA 0x0446 +#define TT_MS_LANGID_GUJARATI_INDIA 0x0447 +#define TT_MS_LANGID_ODIA_INDIA 0x0448 +#define TT_MS_LANGID_TAMIL_INDIA 0x0449 +#define TT_MS_LANGID_TELUGU_INDIA 0x044A +#define TT_MS_LANGID_KANNADA_INDIA 0x044B +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044C +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044D +#define TT_MS_LANGID_MARATHI_INDIA 0x044E +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044F +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA /* Cyrillic */ 0x0450 +#define TT_MS_LANGID_MONGOLIAN_PRC 0x0850 +#define TT_MS_LANGID_TIBETAN_PRC 0x0451 +#define TT_MS_LANGID_WELSH_UNITED_KINGDOM 0x0452 +#define TT_MS_LANGID_KHMER_CAMBODIA 0x0453 +#define TT_MS_LANGID_LAO_LAOS 0x0454 +#define TT_MS_LANGID_GALICIAN_GALICIAN 0x0456 +#define TT_MS_LANGID_KONKANI_INDIA 0x0457 +#define TT_MS_LANGID_SYRIAC_SYRIA 0x045A +#define TT_MS_LANGID_SINHALA_SRI_LANKA 0x045B +#define TT_MS_LANGID_INUKTITUT_CANADA 0x045D +#define TT_MS_LANGID_INUKTITUT_CANADA_LATIN 0x085D +#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045E +#define TT_MS_LANGID_TAMAZIGHT_ALGERIA 0x085F +#define TT_MS_LANGID_NEPALI_NEPAL 0x0461 +#define TT_MS_LANGID_FRISIAN_NETHERLANDS 0x0462 +#define TT_MS_LANGID_PASHTO_AFGHANISTAN 0x0463 +#define TT_MS_LANGID_FILIPINO_PHILIPPINES 0x0464 +#define TT_MS_LANGID_DHIVEHI_MALDIVES 0x0465 +#define TT_MS_LANGID_HAUSA_NIGERIA 0x0468 +#define TT_MS_LANGID_YORUBA_NIGERIA 0x046A +#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046B +#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086B +#define TT_MS_LANGID_QUECHUA_PERU 0x0C6B +#define TT_MS_LANGID_SESOTHO_SA_LEBOA_SOUTH_AFRICA 0x046C +#define TT_MS_LANGID_BASHKIR_RUSSIA 0x046D +#define TT_MS_LANGID_LUXEMBOURGISH_LUXEMBOURG 0x046E +#define TT_MS_LANGID_GREENLANDIC_GREENLAND 0x046F +#define TT_MS_LANGID_IGBO_NIGERIA 0x0470 +#define TT_MS_LANGID_YI_PRC 0x0478 +#define TT_MS_LANGID_MAPUDUNGUN_CHILE 0x047A +#define TT_MS_LANGID_MOHAWK_MOHAWK 0x047C +#define TT_MS_LANGID_BRETON_FRANCE 0x047E +#define TT_MS_LANGID_UIGHUR_PRC 0x0480 +#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0481 +#define TT_MS_LANGID_OCCITAN_FRANCE 0x0482 +#define TT_MS_LANGID_CORSICAN_FRANCE 0x0483 +#define TT_MS_LANGID_ALSATIAN_FRANCE 0x0484 +#define TT_MS_LANGID_YAKUT_RUSSIA 0x0485 +#define TT_MS_LANGID_KICHE_GUATEMALA 0x0486 +#define TT_MS_LANGID_KINYARWANDA_RWANDA 0x0487 +#define TT_MS_LANGID_WOLOF_SENEGAL 0x0488 +#define TT_MS_LANGID_DARI_AFGHANISTAN 0x048C + + /* */ + + + /* legacy macro definitions not present in OpenType 1.8.1 */ +#define TT_MS_LANGID_ARABIC_GENERAL 0x0001 +#define TT_MS_LANGID_CATALAN_SPAIN \ + TT_MS_LANGID_CATALAN_CATALAN +#define TT_MS_LANGID_CHINESE_GENERAL 0x0004 +#define TT_MS_LANGID_CHINESE_MACAU \ + TT_MS_LANGID_CHINESE_MACAO +#define TT_MS_LANGID_GERMAN_LIECHTENSTEI \ + TT_MS_LANGID_GERMAN_LIECHTENSTEIN +#define TT_MS_LANGID_ENGLISH_GENERAL 0x0009 +#define TT_MS_LANGID_ENGLISH_INDONESIA 0x3809 +#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3C09 +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT \ + TT_MS_LANGID_SPANISH_SPAIN_MODERN_SORT +#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40AU +#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1C0C +#define TT_MS_LANGID_FRENCH_REUNION 0x200C +#define TT_MS_LANGID_FRENCH_CONGO 0x240C + /* which was formerly: */ +#define TT_MS_LANGID_FRENCH_ZAIRE \ + TT_MS_LANGID_FRENCH_CONGO +#define TT_MS_LANGID_FRENCH_SENEGAL 0x280C +#define TT_MS_LANGID_FRENCH_CAMEROON 0x2C0C +#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300C +#define TT_MS_LANGID_FRENCH_MALI 0x340C +#define TT_MS_LANGID_FRENCH_MOROCCO 0x380C +#define TT_MS_LANGID_FRENCH_HAITI 0x3C0C +#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40CU +#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA \ + TT_MS_LANGID_KOREAN_KOREA +#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812 +#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND \ + TT_MS_LANGID_ROMANSH_SWITZERLAND +#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 +#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 +#define TT_MS_LANGID_URDU_INDIA 0x0820 +#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 +#define TT_MS_LANGID_SLOVENE_SLOVENIA \ + TT_MS_LANGID_SLOVENIAN_SLOVENIA +#define TT_MS_LANGID_FARSI_IRAN 0x0429 +#define TT_MS_LANGID_BASQUE_SPAIN \ + TT_MS_LANGID_BASQUE_BASQUE +#define TT_MS_LANGID_SORBIAN_GERMANY \ + TT_MS_LANGID_UPPER_SORBIAN_GERMANY +#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 +#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 +#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA \ + TT_MS_LANGID_SETSWANA_SOUTH_AFRICA +#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433 +#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA \ + TT_MS_LANGID_ISIXHOSA_SOUTH_AFRICA +#define TT_MS_LANGID_ZULU_SOUTH_AFRICA \ + TT_MS_LANGID_ISIZULU_SOUTH_AFRICA +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043B + /* the next two values are incorrectly inverted */ +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043C +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083C +#define TT_MS_LANGID_YIDDISH_GERMANY 0x043D +#define TT_MS_LANGID_KAZAK_KAZAKSTAN \ + TT_MS_LANGID_KAZAKH_KAZAKHSTAN +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \ + TT_MS_LANGID_KYRGYZ_KYRGYZSTAN +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN \ + TT_MS_LANGID_KYRGYZ_KYRGYZSTAN +#define TT_MS_LANGID_SWAHILI_KENYA \ + TT_MS_LANGID_KISWAHILI_KENYA +#define TT_MS_LANGID_TATAR_TATARSTAN \ + TT_MS_LANGID_TATAR_RUSSIA +#define TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN 0x0846 +#define TT_MS_LANGID_ORIYA_INDIA \ + TT_MS_LANGID_ODIA_INDIA +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN \ + TT_MS_LANGID_MONGOLIAN_PRC +#define TT_MS_LANGID_TIBETAN_CHINA \ + TT_MS_LANGID_TIBETAN_PRC +#define TT_MS_LANGID_DZONGHKA_BHUTAN 0x0851 +#define TT_MS_LANGID_TIBETAN_BHUTAN \ + TT_MS_LANGID_DZONGHKA_BHUTAN +#define TT_MS_LANGID_WELSH_WALES \ + TT_MS_LANGID_WELSH_UNITED_KINGDOM +#define TT_MS_LANGID_BURMESE_MYANMAR 0x0455 +#define TT_MS_LANGID_GALICIAN_SPAIN \ + TT_MS_LANGID_GALICIAN_GALICIAN +#define TT_MS_LANGID_MANIPURI_INDIA /* Bengali */ 0x0458 +#define TT_MS_LANGID_SINDHI_INDIA /* Arabic */ 0x0459 +#define TT_MS_LANGID_SINDHI_PAKISTAN 0x0859 +#define TT_MS_LANGID_SINHALESE_SRI_LANKA \ + TT_MS_LANGID_SINHALA_SRI_LANKA +#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045C +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO /* Arabic */ 0x045F +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN \ + TT_MS_LANGID_TAMAZIGHT_ALGERIA +#define TT_MS_LANGID_KASHMIRI_PAKISTAN /* Arabic */ 0x0460 +#define TT_MS_LANGID_KASHMIRI_SASIA 0x0860 +#define TT_MS_LANGID_KASHMIRI_INDIA \ + TT_MS_LANGID_KASHMIRI_SASIA +#define TT_MS_LANGID_NEPALI_INDIA 0x0861 +#define TT_MS_LANGID_DIVEHI_MALDIVES \ + TT_MS_LANGID_DHIVEHI_MALDIVES +#define TT_MS_LANGID_EDO_NIGERIA 0x0466 +#define TT_MS_LANGID_FULFULDE_NIGERIA 0x0467 +#define TT_MS_LANGID_IBIBIO_NIGERIA 0x0469 +#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA \ + TT_MS_LANGID_SESOTHO_SA_LEBOA_SOUTH_AFRICA +#define TT_MS_LANGID_SOTHO_SOUTHERN_SOUTH_AFRICA \ + TT_MS_LANGID_SESOTHO_SA_LEBOA_SOUTH_AFRICA +#define TT_MS_LANGID_KANURI_NIGERIA 0x0471 +#define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472 +#define TT_MS_LANGID_TIGRIGNA_ETHIOPIA 0x0473 +#define TT_MS_LANGID_TIGRIGNA_ERYTHREA 0x0873 +#define TT_MS_LANGID_TIGRIGNA_ERYTREA \ + TT_MS_LANGID_TIGRIGNA_ERYTHREA +#define TT_MS_LANGID_GUARANI_PARAGUAY 0x0474 +#define TT_MS_LANGID_HAWAIIAN_UNITED_STATES 0x0475 +#define TT_MS_LANGID_LATIN 0x0476 +#define TT_MS_LANGID_SOMALI_SOMALIA 0x0477 +#define TT_MS_LANGID_YI_CHINA \ + TT_MS_LANGID_YI_PRC +#define TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES 0x0479 +#define TT_MS_LANGID_UIGHUR_CHINA \ + TT_MS_LANGID_UIGHUR_PRC + + + /************************************************************************** + * + * @enum: + * TT_NAME_ID_XXX + * + * @description: + * Possible values of the 'name' identifier field in the name records of + * an SFNT 'name' table. These values are platform independent. + */ + +#define TT_NAME_ID_COPYRIGHT 0 +#define TT_NAME_ID_FONT_FAMILY 1 +#define TT_NAME_ID_FONT_SUBFAMILY 2 +#define TT_NAME_ID_UNIQUE_ID 3 +#define TT_NAME_ID_FULL_NAME 4 +#define TT_NAME_ID_VERSION_STRING 5 +#define TT_NAME_ID_PS_NAME 6 +#define TT_NAME_ID_TRADEMARK 7 + + /* the following values are from the OpenType spec */ +#define TT_NAME_ID_MANUFACTURER 8 +#define TT_NAME_ID_DESIGNER 9 +#define TT_NAME_ID_DESCRIPTION 10 +#define TT_NAME_ID_VENDOR_URL 11 +#define TT_NAME_ID_DESIGNER_URL 12 +#define TT_NAME_ID_LICENSE 13 +#define TT_NAME_ID_LICENSE_URL 14 + /* number 15 is reserved */ +#define TT_NAME_ID_TYPOGRAPHIC_FAMILY 16 +#define TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY 17 +#define TT_NAME_ID_MAC_FULL_NAME 18 + + /* The following code is new as of 2000-01-21 */ +#define TT_NAME_ID_SAMPLE_TEXT 19 + + /* This is new in OpenType 1.3 */ +#define TT_NAME_ID_CID_FINDFONT_NAME 20 + + /* This is new in OpenType 1.5 */ +#define TT_NAME_ID_WWS_FAMILY 21 +#define TT_NAME_ID_WWS_SUBFAMILY 22 + + /* This is new in OpenType 1.7 */ +#define TT_NAME_ID_LIGHT_BACKGROUND 23 +#define TT_NAME_ID_DARK_BACKGROUND 24 + + /* This is new in OpenType 1.8 */ +#define TT_NAME_ID_VARIATIONS_PREFIX 25 + + /* these two values are deprecated */ +#define TT_NAME_ID_PREFERRED_FAMILY TT_NAME_ID_TYPOGRAPHIC_FAMILY +#define TT_NAME_ID_PREFERRED_SUBFAMILY TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY + + + /************************************************************************** + * + * @enum: + * TT_UCR_XXX + * + * @description: + * Possible bit mask values for the `ulUnicodeRangeX` fields in an SFNT + * 'OS/2' table. + */ + + /* ulUnicodeRange1 */ + /* --------------- */ + + /* Bit 0 Basic Latin */ +#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ + /* Bit 1 C1 Controls and Latin-1 Supplement */ +#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */ + /* Bit 2 Latin Extended-A */ +#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ + /* Bit 3 Latin Extended-B */ +#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ + /* Bit 4 IPA Extensions */ + /* Phonetic Extensions */ + /* Phonetic Extensions Supplement */ +#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ + /* U+1D00-U+1D7F */ + /* U+1D80-U+1DBF */ + /* Bit 5 Spacing Modifier Letters */ + /* Modifier Tone Letters */ +#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ + /* U+A700-U+A71F */ + /* Bit 6 Combining Diacritical Marks */ + /* Combining Diacritical Marks Supplement */ +#define TT_UCR_COMBINING_DIACRITICAL_MARKS (1L << 6) /* U+0300-U+036F */ + /* U+1DC0-U+1DFF */ + /* Bit 7 Greek and Coptic */ +#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ + /* Bit 8 Coptic */ +#define TT_UCR_COPTIC (1L << 8) /* U+2C80-U+2CFF */ + /* Bit 9 Cyrillic */ + /* Cyrillic Supplement */ + /* Cyrillic Extended-A */ + /* Cyrillic Extended-B */ +#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ + /* U+0500-U+052F */ + /* U+2DE0-U+2DFF */ + /* U+A640-U+A69F */ + /* Bit 10 Armenian */ +#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ + /* Bit 11 Hebrew */ +#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ + /* Bit 12 Vai */ +#define TT_UCR_VAI (1L << 12) /* U+A500-U+A63F */ + /* Bit 13 Arabic */ + /* Arabic Supplement */ +#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ + /* U+0750-U+077F */ + /* Bit 14 NKo */ +#define TT_UCR_NKO (1L << 14) /* U+07C0-U+07FF */ + /* Bit 15 Devanagari */ +#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */ + /* Bit 16 Bengali */ +#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */ + /* Bit 17 Gurmukhi */ +#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ + /* Bit 18 Gujarati */ +#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya */ +#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */ + /* Bit 20 Tamil */ +#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ + /* Bit 21 Telugu */ +#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ + /* Bit 22 Kannada */ +#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ + /* Bit 23 Malayalam */ +#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ + /* Bit 24 Thai */ +#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ + /* Bit 25 Lao */ +#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ + /* Bit 26 Georgian */ + /* Georgian Supplement */ +#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ + /* U+2D00-U+2D2F */ + /* Bit 27 Balinese */ +#define TT_UCR_BALINESE (1L << 27) /* U+1B00-U+1B7F */ + /* Bit 28 Hangul Jamo */ +#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ + /* Bit 29 Latin Extended Additional */ + /* Latin Extended-C */ + /* Latin Extended-D */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ + /* U+2C60-U+2C7F */ + /* U+A720-U+A7FF */ + /* Bit 30 Greek Extended */ +#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ + /* Bit 31 General Punctuation */ + /* Supplemental Punctuation */ +#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ + /* U+2E00-U+2E7F */ + + /* ulUnicodeRange2 */ + /* --------------- */ + + /* Bit 32 Superscripts And Subscripts */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ + /* Bit 33 Currency Symbols */ +#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ + /* Bit 34 Combining Diacritical Marks For Symbols */ +#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ + (1L << 2) /* U+20D0-U+20FF */ + /* Bit 35 Letterlike Symbols */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ + /* Bit 36 Number Forms */ +#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ + /* Bit 37 Arrows */ + /* Supplemental Arrows-A */ + /* Supplemental Arrows-B */ + /* Miscellaneous Symbols and Arrows */ +#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ + /* U+27F0-U+27FF */ + /* U+2900-U+297F */ + /* U+2B00-U+2BFF */ + /* Bit 38 Mathematical Operators */ + /* Supplemental Mathematical Operators */ + /* Miscellaneous Mathematical Symbols-A */ + /* Miscellaneous Mathematical Symbols-B */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ + /* U+2A00-U+2AFF */ + /* U+27C0-U+27EF */ + /* U+2980-U+29FF */ + /* Bit 39 Miscellaneous Technical */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */ + /* Bit 40 Control Pictures */ +#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ + /* Bit 41 Optical Character Recognition */ +#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ + /* Bit 42 Enclosed Alphanumerics */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ + /* Bit 43 Box Drawing */ +#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ + /* Bit 44 Block Elements */ +#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ + /* Bit 45 Geometric Shapes */ +#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ + /* Bit 46 Miscellaneous Symbols */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ + /* Bit 47 Dingbats */ +#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ + /* Bit 48 CJK Symbols and Punctuation */ +#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ + /* Bit 49 Hiragana */ +#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ + /* Bit 50 Katakana */ + /* Katakana Phonetic Extensions */ +#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ + /* U+31F0-U+31FF */ + /* Bit 51 Bopomofo */ + /* Bopomofo Extended */ +#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ + /* U+31A0-U+31BF */ + /* Bit 52 Hangul Compatibility Jamo */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */ + /* Bit 53 Phags-Pa */ +#define TT_UCR_CJK_MISC (1L << 21) /* U+A840-U+A87F */ +#define TT_UCR_KANBUN TT_UCR_CJK_MISC /* deprecated */ +#define TT_UCR_PHAGSPA + /* Bit 54 Enclosed CJK Letters and Months */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ + /* Bit 55 CJK Compatibility */ +#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ + /* Bit 56 Hangul Syllables */ +#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ + /* Bit 57 High Surrogates */ + /* High Private Use Surrogates */ + /* Low Surrogates */ + + /* According to OpenType specs v.1.3+, */ + /* setting bit 57 implies that there is */ + /* at least one codepoint beyond the */ + /* Basic Multilingual Plane that is */ + /* supported by this font. So it really */ + /* means >= U+10000. */ +#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */ + /* U+DB80-U+DBFF */ + /* U+DC00-U+DFFF */ +#define TT_UCR_NON_PLANE_0 TT_UCR_SURROGATES + /* Bit 58 Phoenician */ +#define TT_UCR_PHOENICIAN (1L << 26) /*U+10900-U+1091F*/ + /* Bit 59 CJK Unified Ideographs */ + /* CJK Radicals Supplement */ + /* Kangxi Radicals */ + /* Ideographic Description Characters */ + /* CJK Unified Ideographs Extension A */ + /* CJK Unified Ideographs Extension B */ + /* Kanbun */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ + /* U+2E80-U+2EFF */ + /* U+2F00-U+2FDF */ + /* U+2FF0-U+2FFF */ + /* U+3400-U+4DB5 */ + /*U+20000-U+2A6DF*/ + /* U+3190-U+319F */ + /* Bit 60 Private Use */ +#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ + /* Bit 61 CJK Strokes */ + /* CJK Compatibility Ideographs */ + /* CJK Compatibility Ideographs Supplement */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+31C0-U+31EF */ + /* U+F900-U+FAFF */ + /*U+2F800-U+2FA1F*/ + /* Bit 62 Alphabetic Presentation Forms */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */ + /* Bit 63 Arabic Presentation Forms-A */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A (1L << 31) /* U+FB50-U+FDFF */ + + /* ulUnicodeRange3 */ + /* --------------- */ + + /* Bit 64 Combining Half Marks */ +#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ + /* Bit 65 Vertical forms */ + /* CJK Compatibility Forms */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE10-U+FE1F */ + /* U+FE30-U+FE4F */ + /* Bit 66 Small Form Variants */ +#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ + /* Bit 67 Arabic Presentation Forms-B */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B (1L << 3) /* U+FE70-U+FEFE */ + /* Bit 68 Halfwidth and Fullwidth Forms */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ + /* Bit 69 Specials */ +#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ + /* Bit 70 Tibetan */ +#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */ + /* Bit 71 Syriac */ +#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ + /* Bit 72 Thaana */ +#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ + /* Bit 73 Sinhala */ +#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ + /* Bit 74 Myanmar */ +#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ + /* Bit 75 Ethiopic */ + /* Ethiopic Supplement */ + /* Ethiopic Extended */ +#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */ + /* U+1380-U+139F */ + /* U+2D80-U+2DDF */ + /* Bit 76 Cherokee */ +#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ + /* Bit 77 Unified Canadian Aboriginal Syllabics */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */ + /* Bit 78 Ogham */ +#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ + /* Bit 79 Runic */ +#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ + /* Bit 80 Khmer */ + /* Khmer Symbols */ +#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ + /* U+19E0-U+19FF */ + /* Bit 81 Mongolian */ +#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ + /* Bit 82 Braille Patterns */ +#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ + /* Bit 83 Yi Syllables */ + /* Yi Radicals */ +#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */ + /* U+A490-U+A4CF */ + /* Bit 84 Tagalog */ + /* Hanunoo */ + /* Buhid */ + /* Tagbanwa */ +#define TT_UCR_PHILIPPINE (1L << 20) /* U+1700-U+171F */ + /* U+1720-U+173F */ + /* U+1740-U+175F */ + /* U+1760-U+177F */ + /* Bit 85 Old Italic */ +#define TT_UCR_OLD_ITALIC (1L << 21) /*U+10300-U+1032F*/ + /* Bit 86 Gothic */ +#define TT_UCR_GOTHIC (1L << 22) /*U+10330-U+1034F*/ + /* Bit 87 Deseret */ +#define TT_UCR_DESERET (1L << 23) /*U+10400-U+1044F*/ + /* Bit 88 Byzantine Musical Symbols */ + /* Musical Symbols */ + /* Ancient Greek Musical Notation */ +#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) /*U+1D000-U+1D0FF*/ + /*U+1D100-U+1D1FF*/ + /*U+1D200-U+1D24F*/ + /* Bit 89 Mathematical Alphanumeric Symbols */ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) /*U+1D400-U+1D7FF*/ + /* Bit 90 Private Use (plane 15) */ + /* Private Use (plane 16) */ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1L << 26) /*U+F0000-U+FFFFD*/ + /*U+100000-U+10FFFD*/ + /* Bit 91 Variation Selectors */ + /* Variation Selectors Supplement */ +#define TT_UCR_VARIATION_SELECTORS (1L << 27) /* U+FE00-U+FE0F */ + /*U+E0100-U+E01EF*/ + /* Bit 92 Tags */ +#define TT_UCR_TAGS (1L << 28) /*U+E0000-U+E007F*/ + /* Bit 93 Limbu */ +#define TT_UCR_LIMBU (1L << 29) /* U+1900-U+194F */ + /* Bit 94 Tai Le */ +#define TT_UCR_TAI_LE (1L << 30) /* U+1950-U+197F */ + /* Bit 95 New Tai Lue */ +#define TT_UCR_NEW_TAI_LUE (1L << 31) /* U+1980-U+19DF */ + + /* ulUnicodeRange4 */ + /* --------------- */ + + /* Bit 96 Buginese */ +#define TT_UCR_BUGINESE (1L << 0) /* U+1A00-U+1A1F */ + /* Bit 97 Glagolitic */ +#define TT_UCR_GLAGOLITIC (1L << 1) /* U+2C00-U+2C5F */ + /* Bit 98 Tifinagh */ +#define TT_UCR_TIFINAGH (1L << 2) /* U+2D30-U+2D7F */ + /* Bit 99 Yijing Hexagram Symbols */ +#define TT_UCR_YIJING (1L << 3) /* U+4DC0-U+4DFF */ + /* Bit 100 Syloti Nagri */ +#define TT_UCR_SYLOTI_NAGRI (1L << 4) /* U+A800-U+A82F */ + /* Bit 101 Linear B Syllabary */ + /* Linear B Ideograms */ + /* Aegean Numbers */ +#define TT_UCR_LINEAR_B (1L << 5) /*U+10000-U+1007F*/ + /*U+10080-U+100FF*/ + /*U+10100-U+1013F*/ + /* Bit 102 Ancient Greek Numbers */ +#define TT_UCR_ANCIENT_GREEK_NUMBERS (1L << 6) /*U+10140-U+1018F*/ + /* Bit 103 Ugaritic */ +#define TT_UCR_UGARITIC (1L << 7) /*U+10380-U+1039F*/ + /* Bit 104 Old Persian */ +#define TT_UCR_OLD_PERSIAN (1L << 8) /*U+103A0-U+103DF*/ + /* Bit 105 Shavian */ +#define TT_UCR_SHAVIAN (1L << 9) /*U+10450-U+1047F*/ + /* Bit 106 Osmanya */ +#define TT_UCR_OSMANYA (1L << 10) /*U+10480-U+104AF*/ + /* Bit 107 Cypriot Syllabary */ +#define TT_UCR_CYPRIOT_SYLLABARY (1L << 11) /*U+10800-U+1083F*/ + /* Bit 108 Kharoshthi */ +#define TT_UCR_KHAROSHTHI (1L << 12) /*U+10A00-U+10A5F*/ + /* Bit 109 Tai Xuan Jing Symbols */ +#define TT_UCR_TAI_XUAN_JING (1L << 13) /*U+1D300-U+1D35F*/ + /* Bit 110 Cuneiform */ + /* Cuneiform Numbers and Punctuation */ +#define TT_UCR_CUNEIFORM (1L << 14) /*U+12000-U+123FF*/ + /*U+12400-U+1247F*/ + /* Bit 111 Counting Rod Numerals */ +#define TT_UCR_COUNTING_ROD_NUMERALS (1L << 15) /*U+1D360-U+1D37F*/ + /* Bit 112 Sundanese */ +#define TT_UCR_SUNDANESE (1L << 16) /* U+1B80-U+1BBF */ + /* Bit 113 Lepcha */ +#define TT_UCR_LEPCHA (1L << 17) /* U+1C00-U+1C4F */ + /* Bit 114 Ol Chiki */ +#define TT_UCR_OL_CHIKI (1L << 18) /* U+1C50-U+1C7F */ + /* Bit 115 Saurashtra */ +#define TT_UCR_SAURASHTRA (1L << 19) /* U+A880-U+A8DF */ + /* Bit 116 Kayah Li */ +#define TT_UCR_KAYAH_LI (1L << 20) /* U+A900-U+A92F */ + /* Bit 117 Rejang */ +#define TT_UCR_REJANG (1L << 21) /* U+A930-U+A95F */ + /* Bit 118 Cham */ +#define TT_UCR_CHAM (1L << 22) /* U+AA00-U+AA5F */ + /* Bit 119 Ancient Symbols */ +#define TT_UCR_ANCIENT_SYMBOLS (1L << 23) /*U+10190-U+101CF*/ + /* Bit 120 Phaistos Disc */ +#define TT_UCR_PHAISTOS_DISC (1L << 24) /*U+101D0-U+101FF*/ + /* Bit 121 Carian */ + /* Lycian */ + /* Lydian */ +#define TT_UCR_OLD_ANATOLIAN (1L << 25) /*U+102A0-U+102DF*/ + /*U+10280-U+1029F*/ + /*U+10920-U+1093F*/ + /* Bit 122 Domino Tiles */ + /* Mahjong Tiles */ +#define TT_UCR_GAME_TILES (1L << 26) /*U+1F030-U+1F09F*/ + /*U+1F000-U+1F02F*/ + /* Bit 123-127 Reserved for process-internal usage */ + + /* */ + + /* for backward compatibility with older FreeType versions */ +#define TT_UCR_ARABIC_PRESENTATION_A \ + TT_UCR_ARABIC_PRESENTATION_FORMS_A +#define TT_UCR_ARABIC_PRESENTATION_B \ + TT_UCR_ARABIC_PRESENTATION_FORMS_B + +#define TT_UCR_COMBINING_DIACRITICS \ + TT_UCR_COMBINING_DIACRITICAL_MARKS +#define TT_UCR_COMBINING_DIACRITICS_SYMB \ + TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB + + +FT_END_HEADER + +#endif /* TTNAMEID_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/tttables.h b/vendor/freetype/include/freetype/tttables.h new file mode 100644 index 0000000..a9f60e7 --- /dev/null +++ b/vendor/freetype/include/freetype/tttables.h @@ -0,0 +1,855 @@ +/**************************************************************************** + * + * tttables.h + * + * Basic SFNT/TrueType tables definitions and interface + * (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTTABLES_H_ +#define TTTABLES_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * truetype_tables + * + * @title: + * TrueType Tables + * + * @abstract: + * TrueType-specific table types and functions. + * + * @description: + * This section contains definitions of some basic tables specific to + * TrueType and OpenType as well as some routines used to access and + * process them. + * + * @order: + * TT_Header + * TT_HoriHeader + * TT_VertHeader + * TT_OS2 + * TT_Postscript + * TT_PCLT + * TT_MaxProfile + * + * FT_Sfnt_Tag + * FT_Get_Sfnt_Table + * FT_Load_Sfnt_Table + * FT_Sfnt_Table_Info + * + * FT_Get_CMap_Language_ID + * FT_Get_CMap_Format + * + * FT_PARAM_TAG_UNPATENTED_HINTING + * + */ + + + /************************************************************************** + * + * @struct: + * TT_Header + * + * @description: + * A structure to model a TrueType font header table. All fields follow + * the OpenType specification. The 64-bit timestamps are stored in + * two-element arrays `Created` and `Modified`, first the upper then + * the lower 32~bits. + */ + typedef struct TT_Header_ + { + FT_Fixed Table_Version; + FT_Fixed Font_Revision; + + FT_Long CheckSum_Adjust; + FT_Long Magic_Number; + + FT_UShort Flags; + FT_UShort Units_Per_EM; + + FT_ULong Created [2]; + FT_ULong Modified[2]; + + FT_Short xMin; + FT_Short yMin; + FT_Short xMax; + FT_Short yMax; + + FT_UShort Mac_Style; + FT_UShort Lowest_Rec_PPEM; + + FT_Short Font_Direction; + FT_Short Index_To_Loc_Format; + FT_Short Glyph_Data_Format; + + } TT_Header; + + + /************************************************************************** + * + * @struct: + * TT_HoriHeader + * + * @description: + * A structure to model a TrueType horizontal header, the 'hhea' table, + * as well as the corresponding horizontal metrics table, 'hmtx'. + * + * @fields: + * Version :: + * The table version. + * + * Ascender :: + * The font's ascender, i.e., the distance from the baseline to the + * top-most of all glyph points found in the font. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoAscender` field of the 'OS/2' table instead + * if you want the correct one. + * + * Descender :: + * The font's descender, i.e., the distance from the baseline to the + * bottom-most of all glyph points found in the font. It is negative. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoDescender` field of the 'OS/2' table + * instead if you want the correct one. + * + * Line_Gap :: + * The font's line gap, i.e., the distance to add to the ascender and + * descender to get the BTB, i.e., the baseline-to-baseline distance + * for the font. + * + * advance_Width_Max :: + * This field is the maximum of all advance widths found in the font. + * It can be used to compute the maximum width of an arbitrary string + * of text. + * + * min_Left_Side_Bearing :: + * The minimum left side bearing of all glyphs within the font. + * + * min_Right_Side_Bearing :: + * The minimum right side bearing of all glyphs within the font. + * + * xMax_Extent :: + * The maximum horizontal extent (i.e., the 'width' of a glyph's + * bounding box) for all glyphs in the font. + * + * caret_Slope_Rise :: + * The rise coefficient of the cursor's slope of the cursor + * (slope=rise/run). + * + * caret_Slope_Run :: + * The run coefficient of the cursor's slope. + * + * caret_Offset :: + * The cursor's offset for slanted fonts. + * + * Reserved :: + * 8~reserved bytes. + * + * metric_Data_Format :: + * Always~0. + * + * number_Of_HMetrics :: + * Number of HMetrics entries in the 'hmtx' table -- this value can be + * smaller than the total number of glyphs in the font. + * + * long_metrics :: + * A pointer into the 'hmtx' table. + * + * short_metrics :: + * A pointer into the 'hmtx' table. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `caret_Slope_Rise`, + * `caret_Slope_Run`, and `caret_Offset`. + */ + typedef struct TT_HoriHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Width_Max; /* advance width maximum */ + + FT_Short min_Left_Side_Bearing; /* minimum left-sb */ + FT_Short min_Right_Side_Bearing; /* minimum right-sb */ + FT_Short xMax_Extent; /* xmax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_HMetrics; + + /* The following fields are not defined by the OpenType specification */ + /* but they are used to connect the metrics header to the relevant */ + /* 'hmtx' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_HoriHeader; + + + /************************************************************************** + * + * @struct: + * TT_VertHeader + * + * @description: + * A structure used to model a TrueType vertical header, the 'vhea' + * table, as well as the corresponding vertical metrics table, 'vmtx'. + * + * @fields: + * Version :: + * The table version. + * + * Ascender :: + * The font's ascender, i.e., the distance from the baseline to the + * top-most of all glyph points found in the font. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoAscender` field of the 'OS/2' table instead + * if you want the correct one. + * + * Descender :: + * The font's descender, i.e., the distance from the baseline to the + * bottom-most of all glyph points found in the font. It is negative. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoDescender` field of the 'OS/2' table + * instead if you want the correct one. + * + * Line_Gap :: + * The font's line gap, i.e., the distance to add to the ascender and + * descender to get the BTB, i.e., the baseline-to-baseline distance + * for the font. + * + * advance_Height_Max :: + * This field is the maximum of all advance heights found in the font. + * It can be used to compute the maximum height of an arbitrary string + * of text. + * + * min_Top_Side_Bearing :: + * The minimum top side bearing of all glyphs within the font. + * + * min_Bottom_Side_Bearing :: + * The minimum bottom side bearing of all glyphs within the font. + * + * yMax_Extent :: + * The maximum vertical extent (i.e., the 'height' of a glyph's + * bounding box) for all glyphs in the font. + * + * caret_Slope_Rise :: + * The rise coefficient of the cursor's slope of the cursor + * (slope=rise/run). + * + * caret_Slope_Run :: + * The run coefficient of the cursor's slope. + * + * caret_Offset :: + * The cursor's offset for slanted fonts. + * + * Reserved :: + * 8~reserved bytes. + * + * metric_Data_Format :: + * Always~0. + * + * number_Of_VMetrics :: + * Number of VMetrics entries in the 'vmtx' table -- this value can be + * smaller than the total number of glyphs in the font. + * + * long_metrics :: + * A pointer into the 'vmtx' table. + * + * short_metrics :: + * A pointer into the 'vmtx' table. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `Ascender`, `Descender`, + * `Line_Gap`, `caret_Slope_Rise`, `caret_Slope_Run`, and `caret_Offset`. + */ + typedef struct TT_VertHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Height_Max; /* advance height maximum */ + + FT_Short min_Top_Side_Bearing; /* minimum top-sb */ + FT_Short min_Bottom_Side_Bearing; /* minimum bottom-sb */ + FT_Short yMax_Extent; /* ymax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_VMetrics; + + /* The following fields are not defined by the OpenType specification */ + /* but they are used to connect the metrics header to the relevant */ + /* 'vmtx' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_VertHeader; + + + /************************************************************************** + * + * @struct: + * TT_OS2 + * + * @description: + * A structure to model a TrueType 'OS/2' table. All fields comply to + * the OpenType specification. + * + * Note that we now support old Mac fonts that do not include an 'OS/2' + * table. In this case, the `version` field is always set to 0xFFFF. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `sCapHeight`, `sTypoAscender`, + * `sTypoDescender`, `sTypoLineGap`, `sxHeight`, `usWinAscent`, + * `usWinDescent`, `yStrikeoutPosition`, `yStrikeoutSize`, + * `ySubscriptXOffset`, `ySubScriptXSize`, `ySubscriptYOffset`, + * `ySubscriptYSize`, `ySuperscriptXOffset`, `ySuperscriptXSize`, + * `ySuperscriptYOffset`, and `ySuperscriptYSize`. + * + * Possible values for bits in the `ulUnicodeRangeX` fields are given by + * the @TT_UCR_XXX macros. + */ + + typedef struct TT_OS2_ + { + FT_UShort version; /* 0x0001 - more or 0xFFFF */ + FT_Short xAvgCharWidth; + FT_UShort usWeightClass; + FT_UShort usWidthClass; + FT_UShort fsType; + FT_Short ySubscriptXSize; + FT_Short ySubscriptYSize; + FT_Short ySubscriptXOffset; + FT_Short ySubscriptYOffset; + FT_Short ySuperscriptXSize; + FT_Short ySuperscriptYSize; + FT_Short ySuperscriptXOffset; + FT_Short ySuperscriptYOffset; + FT_Short yStrikeoutSize; + FT_Short yStrikeoutPosition; + FT_Short sFamilyClass; + + FT_Byte panose[10]; + + FT_ULong ulUnicodeRange1; /* Bits 0-31 */ + FT_ULong ulUnicodeRange2; /* Bits 32-63 */ + FT_ULong ulUnicodeRange3; /* Bits 64-95 */ + FT_ULong ulUnicodeRange4; /* Bits 96-127 */ + + FT_Char achVendID[4]; + + FT_UShort fsSelection; + FT_UShort usFirstCharIndex; + FT_UShort usLastCharIndex; + FT_Short sTypoAscender; + FT_Short sTypoDescender; + FT_Short sTypoLineGap; + FT_UShort usWinAscent; + FT_UShort usWinDescent; + + /* only version 1 and higher: */ + + FT_ULong ulCodePageRange1; /* Bits 0-31 */ + FT_ULong ulCodePageRange2; /* Bits 32-63 */ + + /* only version 2 and higher: */ + + FT_Short sxHeight; + FT_Short sCapHeight; + FT_UShort usDefaultChar; + FT_UShort usBreakChar; + FT_UShort usMaxContext; + + /* only version 5 and higher: */ + + FT_UShort usLowerOpticalPointSize; /* in twips (1/20 points) */ + FT_UShort usUpperOpticalPointSize; /* in twips (1/20 points) */ + + } TT_OS2; + + + /************************************************************************** + * + * @struct: + * TT_Postscript + * + * @description: + * A structure to model a TrueType 'post' table. All fields comply to + * the OpenType specification. This structure does not reference a + * font's PostScript glyph names; use @FT_Get_Glyph_Name to retrieve + * them. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `underlinePosition` and + * `underlineThickness`. + */ + typedef struct TT_Postscript_ + { + FT_Fixed FormatType; + FT_Fixed italicAngle; + FT_Short underlinePosition; + FT_Short underlineThickness; + FT_ULong isFixedPitch; + FT_ULong minMemType42; + FT_ULong maxMemType42; + FT_ULong minMemType1; + FT_ULong maxMemType1; + + /* Glyph names follow in the 'post' table, but we don't */ + /* load them by default. */ + + } TT_Postscript; + + + /************************************************************************** + * + * @struct: + * TT_PCLT + * + * @description: + * A structure to model a TrueType 'PCLT' table. All fields comply to + * the OpenType specification. + */ + typedef struct TT_PCLT_ + { + FT_Fixed Version; + FT_ULong FontNumber; + FT_UShort Pitch; + FT_UShort xHeight; + FT_UShort Style; + FT_UShort TypeFamily; + FT_UShort CapHeight; + FT_UShort SymbolSet; + FT_Char TypeFace[16]; + FT_Char CharacterComplement[8]; + FT_Char FileName[6]; + FT_Char StrokeWeight; + FT_Char WidthType; + FT_Byte SerifStyle; + FT_Byte Reserved; + + } TT_PCLT; + + + /************************************************************************** + * + * @struct: + * TT_MaxProfile + * + * @description: + * The maximum profile ('maxp') table contains many max values, which can + * be used to pre-allocate arrays for speeding up glyph loading and + * hinting. + * + * @fields: + * version :: + * The version number. + * + * numGlyphs :: + * The number of glyphs in this TrueType font. + * + * maxPoints :: + * The maximum number of points in a non-composite TrueType glyph. See + * also `maxCompositePoints`. + * + * maxContours :: + * The maximum number of contours in a non-composite TrueType glyph. + * See also `maxCompositeContours`. + * + * maxCompositePoints :: + * The maximum number of points in a composite TrueType glyph. See + * also `maxPoints`. + * + * maxCompositeContours :: + * The maximum number of contours in a composite TrueType glyph. See + * also `maxContours`. + * + * maxZones :: + * The maximum number of zones used for glyph hinting. + * + * maxTwilightPoints :: + * The maximum number of points in the twilight zone used for glyph + * hinting. + * + * maxStorage :: + * The maximum number of elements in the storage area used for glyph + * hinting. + * + * maxFunctionDefs :: + * The maximum number of function definitions in the TrueType bytecode + * for this font. + * + * maxInstructionDefs :: + * The maximum number of instruction definitions in the TrueType + * bytecode for this font. + * + * maxStackElements :: + * The maximum number of stack elements used during bytecode + * interpretation. + * + * maxSizeOfInstructions :: + * The maximum number of TrueType opcodes used for glyph hinting. + * + * maxComponentElements :: + * The maximum number of simple (i.e., non-composite) glyphs in a + * composite glyph. + * + * maxComponentDepth :: + * The maximum nesting depth of composite glyphs. + * + * @note: + * This structure is only used during font loading. + */ + typedef struct TT_MaxProfile_ + { + FT_Fixed version; + FT_UShort numGlyphs; + FT_UShort maxPoints; + FT_UShort maxContours; + FT_UShort maxCompositePoints; + FT_UShort maxCompositeContours; + FT_UShort maxZones; + FT_UShort maxTwilightPoints; + FT_UShort maxStorage; + FT_UShort maxFunctionDefs; + FT_UShort maxInstructionDefs; + FT_UShort maxStackElements; + FT_UShort maxSizeOfInstructions; + FT_UShort maxComponentElements; + FT_UShort maxComponentDepth; + + } TT_MaxProfile; + + + /************************************************************************** + * + * @enum: + * FT_Sfnt_Tag + * + * @description: + * An enumeration to specify indices of SFNT tables loaded and parsed by + * FreeType during initialization of an SFNT font. Used in the + * @FT_Get_Sfnt_Table API function. + * + * @values: + * FT_SFNT_HEAD :: + * To access the font's @TT_Header structure. + * + * FT_SFNT_MAXP :: + * To access the font's @TT_MaxProfile structure. + * + * FT_SFNT_OS2 :: + * To access the font's @TT_OS2 structure. + * + * FT_SFNT_HHEA :: + * To access the font's @TT_HoriHeader structure. + * + * FT_SFNT_VHEA :: + * To access the font's @TT_VertHeader structure. + * + * FT_SFNT_POST :: + * To access the font's @TT_Postscript structure. + * + * FT_SFNT_PCLT :: + * To access the font's @TT_PCLT structure. + */ + typedef enum FT_Sfnt_Tag_ + { + FT_SFNT_HEAD, + FT_SFNT_MAXP, + FT_SFNT_OS2, + FT_SFNT_HHEA, + FT_SFNT_VHEA, + FT_SFNT_POST, + FT_SFNT_PCLT, + + FT_SFNT_MAX + + } FT_Sfnt_Tag; + + /* these constants are deprecated; use the corresponding `FT_Sfnt_Tag` */ + /* values instead */ +#define ft_sfnt_head FT_SFNT_HEAD +#define ft_sfnt_maxp FT_SFNT_MAXP +#define ft_sfnt_os2 FT_SFNT_OS2 +#define ft_sfnt_hhea FT_SFNT_HHEA +#define ft_sfnt_vhea FT_SFNT_VHEA +#define ft_sfnt_post FT_SFNT_POST +#define ft_sfnt_pclt FT_SFNT_PCLT + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_Table + * + * @description: + * Return a pointer to a given SFNT table stored within a face. + * + * @input: + * face :: + * A handle to the source. + * + * tag :: + * The index of the SFNT table. + * + * @return: + * A type-less pointer to the table. This will be `NULL` in case of + * error, or if the corresponding table was not found **OR** loaded from + * the file. + * + * Use a typecast according to `tag` to access the structure elements. + * + * @note: + * The table is owned by the face object and disappears with it. + * + * This function is only useful to access SFNT tables that are loaded by + * the sfnt, truetype, and opentype drivers. See @FT_Sfnt_Tag for a + * list. + * + * @example: + * Here is an example demonstrating access to the 'vhea' table. + * + * ``` + * TT_VertHeader* vert_header; + * + * + * vert_header = + * (TT_VertHeader*)FT_Get_Sfnt_Table( face, FT_SFNT_VHEA ); + * ``` + */ + FT_EXPORT( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ); + + + /************************************************************************** + * + * @function: + * FT_Load_Sfnt_Table + * + * @description: + * Load any SFNT font table into client memory. + * + * @input: + * face :: + * A handle to the source face. + * + * tag :: + * The four-byte tag of the table to load. Use value~0 if you want to + * access the whole font file. Otherwise, you can use one of the + * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new + * one with @FT_MAKE_TAG. + * + * offset :: + * The starting offset in the table (or file if tag~==~0). + * + * @output: + * buffer :: + * The target buffer address. The client must ensure that the memory + * array is big enough to hold the data. + * + * @inout: + * length :: + * If the `length` parameter is `NULL`, try to load the whole table. + * Return an error code if it fails. + * + * Else, if `*length` is~0, exit immediately while returning the + * table's (or file) full size in it. + * + * Else the number of bytes to read from the table or file, from the + * starting offset. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If you need to determine the table's length you should first call this + * function with `*length` set to~0, as in the following example: + * + * ``` + * FT_ULong length = 0; + * + * + * error = FT_Load_Sfnt_Table( face, tag, 0, NULL, &length ); + * if ( error ) { ... table does not exist ... } + * + * buffer = malloc( length ); + * if ( buffer == NULL ) { ... not enough memory ... } + * + * error = FT_Load_Sfnt_Table( face, tag, 0, buffer, &length ); + * if ( error ) { ... could not load table ... } + * ``` + * + * Note that structures like @TT_Header or @TT_OS2 can't be used with + * this function; they are limited to @FT_Get_Sfnt_Table. Reason is that + * those structures depend on the processor architecture, with varying + * size (e.g. 32bit vs. 64bit) or order (big endian vs. little endian). + * + */ + FT_EXPORT( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + /************************************************************************** + * + * @function: + * FT_Sfnt_Table_Info + * + * @description: + * Return information on an SFNT table. + * + * @input: + * face :: + * A handle to the source face. + * + * table_index :: + * The index of an SFNT table. The function returns + * FT_Err_Table_Missing for an invalid value. + * + * @inout: + * tag :: + * The name tag of the SFNT table. If the value is `NULL`, + * `table_index` is ignored, and `length` returns the number of SFNT + * tables in the font. + * + * @output: + * length :: + * The length of the SFNT table (or the number of SFNT tables, + * depending on `tag`). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * While parsing fonts, FreeType handles SFNT tables with length zero as + * missing. + * + */ + FT_EXPORT( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ); + + + /************************************************************************** + * + * @function: + * FT_Get_CMap_Language_ID + * + * @description: + * Return cmap language ID as specified in the OpenType standard. + * Definitions of language ID values are in file @FT_TRUETYPE_IDS_H. + * + * @input: + * charmap :: + * The target charmap. + * + * @return: + * The language ID of `charmap`. If `charmap` doesn't belong to an SFNT + * face, just return~0 as the default value. + * + * For a format~14 cmap (to access Unicode IVS), the return value is + * 0xFFFFFFFF. + */ + FT_EXPORT( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ); + + + /************************************************************************** + * + * @function: + * FT_Get_CMap_Format + * + * @description: + * Return the format of an SFNT 'cmap' table. + * + * @input: + * charmap :: + * The target charmap. + * + * @return: + * The format of `charmap`. If `charmap` doesn't belong to an SFNT face, + * return -1. + */ + FT_EXPORT( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ); + + /* */ + + +FT_END_HEADER + +#endif /* TTTABLES_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/freetype/tttags.h b/vendor/freetype/include/freetype/tttags.h new file mode 100644 index 0000000..9bf4fca --- /dev/null +++ b/vendor/freetype/include/freetype/tttags.h @@ -0,0 +1,124 @@ +/**************************************************************************** + * + * tttags.h + * + * Tags for TrueType and OpenType tables (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTAGS_H_ +#define TTAGS_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + +#define TTAG_avar FT_MAKE_TAG( 'a', 'v', 'a', 'r' ) +#define TTAG_BASE FT_MAKE_TAG( 'B', 'A', 'S', 'E' ) +#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) +#define TTAG_BDF FT_MAKE_TAG( 'B', 'D', 'F', ' ' ) +#define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' ) +#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) +#define TTAG_bsln FT_MAKE_TAG( 'b', 's', 'l', 'n' ) +#define TTAG_CBDT FT_MAKE_TAG( 'C', 'B', 'D', 'T' ) +#define TTAG_CBLC FT_MAKE_TAG( 'C', 'B', 'L', 'C' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) +#define TTAG_CFF2 FT_MAKE_TAG( 'C', 'F', 'F', '2' ) +#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' ) +#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) +#define TTAG_COLR FT_MAKE_TAG( 'C', 'O', 'L', 'R' ) +#define TTAG_CPAL FT_MAKE_TAG( 'C', 'P', 'A', 'L' ) +#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) +#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) +#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) +#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) +#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) +#define TTAG_feat FT_MAKE_TAG( 'f', 'e', 'a', 't' ) +#define TTAG_FOND FT_MAKE_TAG( 'F', 'O', 'N', 'D' ) +#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) +#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) +#define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) +#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) +#define TTAG_HVAR FT_MAKE_TAG( 'H', 'V', 'A', 'R' ) +#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) +#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) +#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) +#define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) +#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) +#define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) +#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) +#define TTAG_LWFN FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) +#define TTAG_MATH FT_MAKE_TAG( 'M', 'A', 'T', 'H' ) +#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_mort FT_MAKE_TAG( 'm', 'o', 'r', 't' ) +#define TTAG_morx FT_MAKE_TAG( 'm', 'o', 'r', 'x' ) +#define TTAG_MVAR FT_MAKE_TAG( 'M', 'V', 'A', 'R' ) +#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) +#define TTAG_opbd FT_MAKE_TAG( 'o', 'p', 'b', 'd' ) +#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) +#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) +#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) +#define TTAG_POST FT_MAKE_TAG( 'P', 'O', 'S', 'T' ) +#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) +#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) +#define TTAG_prop FT_MAKE_TAG( 'p', 'r', 'o', 'p' ) +#define TTAG_sbix FT_MAKE_TAG( 's', 'b', 'i', 'x' ) +#define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' ) +#define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_SVG FT_MAKE_TAG( 'S', 'V', 'G', ' ' ) +#define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) +#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) +#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) +#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) +#define TTAG_TYP1 FT_MAKE_TAG( 'T', 'Y', 'P', '1' ) +#define TTAG_typ1 FT_MAKE_TAG( 't', 'y', 'p', '1' ) +#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) +#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) +#define TTAG_VVAR FT_MAKE_TAG( 'V', 'V', 'A', 'R' ) +#define TTAG_wOFF FT_MAKE_TAG( 'w', 'O', 'F', 'F' ) +#define TTAG_wOF2 FT_MAKE_TAG( 'w', 'O', 'F', '2' ) + +/* used by "Keyboard.dfont" on legacy Mac OS X */ +#define TTAG_0xA5kbd FT_MAKE_TAG( 0xA5, 'k', 'b', 'd' ) + +/* used by "LastResort.dfont" on legacy Mac OS X */ +#define TTAG_0xA5lst FT_MAKE_TAG( 0xA5, 'l', 's', 't' ) + + +FT_END_HEADER + +#endif /* TTAGS_H_ */ + + +/* END */ diff --git a/vendor/freetype/include/ft2build.h b/vendor/freetype/include/ft2build.h new file mode 100644 index 0000000..58491ce --- /dev/null +++ b/vendor/freetype/include/ft2build.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * ft2build.h + * + * FreeType 2 build and setup macros. + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This is the 'entry point' for FreeType header file inclusions, to be + * loaded before all other header files. + * + * A typical example is + * + * ``` + * #include + * #include + * ``` + * + */ + + +#ifndef FT2BUILD_H_ +#define FT2BUILD_H_ + +#include + +#endif /* FT2BUILD_H_ */ + + +/* END */ diff --git a/vendor/freetype/lib/freetype.idb b/vendor/freetype/lib/freetype.idb new file mode 100644 index 0000000000000000000000000000000000000000..a5c8f83219fb6106c3a7480487092ee7b45f6f1c GIT binary patch literal 855040 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

    |hKGWEj8f$|(CS|$uCH*^1 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 z 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

  1. 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≶{ z^2h1MoxuEI9>ff%&j&TWg>GZ%V$oN}iia(}&7g1k61TBxso=ut`xm&Az?`^Ca2%I9 zm>lrATsAfAWDpB5bZe@-~Y zcNsA2R|_s&e6Ij5;u*J*_^b_Qi^tW#O*Ap^QW>ZB@+8#!_c^z5*NdVrTz>F<`~4-i zF_qW;!nDB8DIQGcR%_kHjr;@yjE;vbe3-H@o&x5|^@78rV>&;NbZ!pJt_^}KFP$&h zh&%Y+6I^-eyaJfF-?xR&_I@y(tA5}%8kg8`ws`!Da8EHYj4zE-I;TR-q*AxBc9ZDS z?SjqUfk@|V=;YVmD!69Q=akNg2;VE)+{TVi$`9Y8kgva8Fbo@wQ~3Bbi?@M0_?ci? zuPc9T@#Q?tyqy*6i-*3tyWB?eJ%SAv50;m=_rl*V1*gl4EnQelT7Km=4(}J7?oZlq zqv2frfZLdIP;lYuzkdsLeH;&F*6|n*)f0WXpJNLj$F;TVdyKOU1*gYH zHXPfT+IZQoX)HLM&Nf^LoRBo%CK9BKAhTu}e;27VQNW?*X1Q#y8ECRVi?@ba8AZm2@ALY4O3qDE>80pP5DVBm~i3y z1LbrYFk|NkE?j@38sf30&|_?zSH8YP;9}={jN}D^3)e0Xw;Y%?3(LoyMc8XC@))s; z%lCI7^xX!`w@U=4^Ve4XzCk*V#RXiw{enaBaV&oekuD2>sdA6t!u7M`@&0ZEX8Xf} z&B#$zluuc!z&KFS1c@bezy=@&$wZdYyZM>WK^ z-is&)FAGk$mo{8F^m$(K7}vilxN!Mq0JjF1HERSHu3S;yMPPcbEkAr4kO3b6Gi`(5 zGQ*@xJe>13BK_VM+*M(4iAd+&AE4gYB)D+x?>)f%v>E<>A~;=-+tOtg>fO1h-2T}m zxYRKI9)-S{dpt(g{__3xLEm6p3G&Dx!G$XaC*XYgJCx@i1=k{sza_}u2akG;!N&y` zE?usG^Gi^=<+t*2K9-kL9%I;P!G$Y-)8X9o50CN08Num#$o9UyjB-%#9Q^%TaQyF7 z-(Q3D`vI7S7X=rtJ>Lg?-EbQD5)TAm!o8QvfZGPlAbzN=9NcQWzg43mj920WHyK!` z_xA+)ISp&$dmmQ_Zb%p$Zx4CqO8A>3xNzlzEm`AWF{8sppc>IkDMCtP8| z#rGlTdk>gFtp%3|tW!K#AFM2 zgbAnbB+C6`-6D+Qp5^Pi2l~#XMHu)dz0#M6|4#8JVg6x_1guf)5TWqV-SxS!y}9ZBLx?3zVkKctD6;JY#S}O z&SBzv0?y~|h%kQ06I{6ZU>shb$0nh?Oc7jC7=2fuJWra6{Fp7c^f0(Oh{w>v2xH28 z!G$Y-{gKYi7ep8{*l@yxYd<(1JP1s}VjIquehr~x3NR0tIEXpc8}xS-FejIkukS_3 z4_q2yT)>YeoW600Z*)a_Zg)oqzbm+K`N54@R|0coso;EJ!dDx(Et?{Y z16u{hddMlh0}B zfXTPxY~f=%uP`z6mnK|(JOQ0A-=4trt3V&aH@=ekW&>ALfj*Y!=YZL0$2sKheqesE<81lM^6bIjwjKw#wBr{p zzFmMxv*T>~7~d>l^6fZ>@T~ymF+0vd-$r1z+i?#1jsf$h9cRSb;v~?;DlWw*$ES73gFBo~fk1Dt|>7weX_} zmwqhIZGlO%;~erg3z$4R&Xyn4R}9RPcASI04}jTj$2sUb2F!Uo&Ou+jGZ98p{Aj|( zm+6-V%pg0?L0>*FbL}`=_^9tOU|zA~9Q17m<|{kSLEoRiM4q+9!$DsoU|QR8Hhp~G z`j{A4l?nI0-2z-r1^Sr33o5DaLExUQguYT>_S$g{@jVU9MLW(GUxu @{zel)rq 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 EZ{K298Al2f!nAks$7BkF^|w=X!M%aY%96Q3#&V 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,xZa{H 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 $J}Qrcz?`w- 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%0A8=) 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%0AQ_yzM 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

    mFkpg)U`Tjd~!AWmTveSol)GAeOd1+$8L-C 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 z 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

  2. $AABX@?|# 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 za4]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�U| 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

    T~Avj3pI}sT6~+XRNRh%;y;^Y!CA- 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�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%0DKsDCeY*q_!#b^ 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 literal 0 HcmV?d00001 diff --git a/vendor/freetype/objs/.gitignore b/vendor/freetype/objs/.gitignore new file mode 100644 index 0000000..f847620 --- /dev/null +++ b/vendor/freetype/objs/.gitignore @@ -0,0 +1,3 @@ +* +!README +!.gitignore diff --git a/vendor/freetype/objs/README b/vendor/freetype/objs/README new file mode 100644 index 0000000..befb63e --- /dev/null +++ b/vendor/freetype/objs/README @@ -0,0 +1,2 @@ +This directory contains all the object files created when building the +library. diff --git a/vendor/freetype/src/autofit/afblue.c b/vendor/freetype/src/autofit/afblue.c new file mode 100644 index 0000000..d7655b9 --- /dev/null +++ b/vendor/freetype/src/autofit/afblue.c @@ -0,0 +1,779 @@ +/* This file has been generated by the Perl script `afblue.pl', */ +/* using data from file `afblue.dat'. */ + +/**************************************************************************** + * + * afblue.c + * + * Auto-fitter data for blue strings (body). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "aftypes.h" + + + FT_LOCAL_ARRAY_DEF( char ) + af_blue_strings[] = + { + /* */ + '\xF0', '\x9E', '\xA4', '\x8C', ' ', '\xF0', '\x9E', '\xA4', '\x85', ' ', '\xF0', '\x9E', '\xA4', '\x88', ' ', '\xF0', '\x9E', '\xA4', '\x8F', ' ', '\xF0', '\x9E', '\xA4', '\x94', ' ', '\xF0', '\x9E', '\xA4', '\x9A', /* 𞤌 𞤅 𞤈 𞤠𞤔 𞤚 */ + '\0', + '\xF0', '\x9E', '\xA4', '\x82', ' ', '\xF0', '\x9E', '\xA4', '\x96', /* 𞤂 𞤖 */ + '\0', + '\xF0', '\x9E', '\xA4', '\xAC', ' ', '\xF0', '\x9E', '\xA4', '\xAE', ' ', '\xF0', '\x9E', '\xA4', '\xBB', ' ', '\xF0', '\x9E', '\xA4', '\xBC', ' ', '\xF0', '\x9E', '\xA4', '\xBE', /* 𞤬 𞤮 𞤻 𞤼 𞤾 */ + '\0', + '\xF0', '\x9E', '\xA4', '\xA4', ' ', '\xF0', '\x9E', '\xA4', '\xA8', ' ', '\xF0', '\x9E', '\xA4', '\xA9', ' ', '\xF0', '\x9E', '\xA4', '\xAD', ' ', '\xF0', '\x9E', '\xA4', '\xB4', ' ', '\xF0', '\x9E', '\xA4', '\xB8', ' ', '\xF0', '\x9E', '\xA4', '\xBA', ' ', '\xF0', '\x9E', '\xA5', '\x80', /* 𞤤 𞤨 𞤩 𞤭 𞤴 𞤸 𞤺 𞥀 */ + '\0', + '\xD8', '\xA7', ' ', '\xD8', '\xA5', ' ', '\xD9', '\x84', ' ', '\xD9', '\x83', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8', /* ا Ø¥ Ù„ Ùƒ Ø· ظ */ + '\0', + '\xD8', '\xAA', ' ', '\xD8', '\xAB', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8', ' ', '\xD9', '\x83', /* ت Ø« Ø· ظ Ùƒ */ + '\0', + '\xD9', '\x80', /* Ù€ */ + '\0', + '\xD4', '\xB1', ' ', '\xD5', '\x84', ' ', '\xD5', '\x92', ' ', '\xD5', '\x8D', ' ', '\xD4', '\xB2', ' ', '\xD4', '\xB3', ' ', '\xD4', '\xB4', ' ', '\xD5', '\x95', /* Ô± Õ„ Õ’ Õ Ô² Ô³ Ô´ Õ• */ + '\0', + '\xD5', '\x92', ' ', '\xD5', '\x88', ' ', '\xD4', '\xB4', ' ', '\xD5', '\x83', ' ', '\xD5', '\x87', ' ', '\xD5', '\x8D', ' ', '\xD5', '\x8F', ' ', '\xD5', '\x95', /* Õ’ Õˆ Ô´ Õƒ Õ‡ Õ Õ Õ• */ + '\0', + '\xD5', '\xA5', ' ', '\xD5', '\xA7', ' ', '\xD5', '\xAB', ' ', '\xD5', '\xB4', ' ', '\xD5', '\xBE', ' ', '\xD6', '\x86', ' ', '\xD5', '\xB3', /* Õ¥ Õ§ Õ« Õ´ Õ¾ Ö† Õ³ */ + '\0', + '\xD5', '\xA1', ' ', '\xD5', '\xB5', ' ', '\xD6', '\x82', ' ', '\xD5', '\xBD', ' ', '\xD5', '\xA3', ' ', '\xD5', '\xB7', ' ', '\xD6', '\x80', ' ', '\xD6', '\x85', /* Õ¡ Õµ Ö‚ Õ½ Õ£ Õ· Ö€ Ö… */ + '\0', + '\xD5', '\xB0', ' ', '\xD5', '\xB8', ' ', '\xD5', '\xB3', ' ', '\xD5', '\xA1', ' ', '\xD5', '\xA5', ' ', '\xD5', '\xAE', ' ', '\xD5', '\xBD', ' ', '\xD6', '\x85', /* Õ° Õ¸ Õ³ Õ¡ Õ¥ Õ® Õ½ Ö… */ + '\0', + '\xD5', '\xA2', ' ', '\xD5', '\xA8', ' ', '\xD5', '\xAB', ' ', '\xD5', '\xAC', ' ', '\xD5', '\xB2', ' ', '\xD5', '\xBA', ' ', '\xD6', '\x83', ' ', '\xD6', '\x81', /* Õ¢ Õ¨ Õ« Õ¬ Õ² Õº Öƒ Ö */ + '\0', + '\xF0', '\x90', '\xAC', '\x80', ' ', '\xF0', '\x90', '\xAC', '\x81', ' ', '\xF0', '\x90', '\xAC', '\x90', ' ', '\xF0', '\x90', '\xAC', '\x9B', /* 𬀠ð¬ ð¬ 𬛠*/ + '\0', + '\xF0', '\x90', '\xAC', '\x80', ' ', '\xF0', '\x90', '\xAC', '\x81', /* 𬀠ð¬ */ + '\0', + '\xEA', '\x9A', '\xA7', ' ', '\xEA', '\x9A', '\xA8', ' ', '\xEA', '\x9B', '\x9B', ' ', '\xEA', '\x9B', '\x89', ' ', '\xEA', '\x9B', '\x81', ' ', '\xEA', '\x9B', '\x88', ' ', '\xEA', '\x9B', '\xAB', ' ', '\xEA', '\x9B', '\xAF', /* êš§ ꚨ ê›› ꛉ ê› ê›ˆ ꛫ ꛯ */ + '\0', + '\xEA', '\x9A', '\xAD', ' ', '\xEA', '\x9A', '\xB3', ' ', '\xEA', '\x9A', '\xB6', ' ', '\xEA', '\x9B', '\xAC', ' ', '\xEA', '\x9A', '\xA2', ' ', '\xEA', '\x9A', '\xBD', ' ', '\xEA', '\x9B', '\xAF', ' ', '\xEA', '\x9B', '\xB2', /* êš­ êš³ êš¶ ꛬ ꚢ êš½ ꛯ ꛲ */ + '\0', + '\xE0', '\xA6', '\x85', ' ', '\xE0', '\xA6', '\xA1', ' ', '\xE0', '\xA6', '\xA4', ' ', '\xE0', '\xA6', '\xA8', ' ', '\xE0', '\xA6', '\xAC', ' ', '\xE0', '\xA6', '\xAD', ' ', '\xE0', '\xA6', '\xB2', ' ', '\xE0', '\xA6', '\x95', /* অ ড ত ন ব ভ ল ক */ + '\0', + '\xE0', '\xA6', '\x87', ' ', '\xE0', '\xA6', '\x9F', ' ', '\xE0', '\xA6', '\xA0', ' ', '\xE0', '\xA6', '\xBF', ' ', '\xE0', '\xA7', '\x80', ' ', '\xE0', '\xA7', '\x88', ' ', '\xE0', '\xA7', '\x97', /* ই ট ঠ ি à§€ ৈ à§— */ + '\0', + '\xE0', '\xA6', '\x93', ' ', '\xE0', '\xA6', '\x8F', ' ', '\xE0', '\xA6', '\xA1', ' ', '\xE0', '\xA6', '\xA4', ' ', '\xE0', '\xA6', '\xA8', ' ', '\xE0', '\xA6', '\xAC', ' ', '\xE0', '\xA6', '\xB2', ' ', '\xE0', '\xA6', '\x95', /* ও ঠড ত ন ব ল ক */ + '\0', + '\xE1', '\x9D', '\x90', ' ', '\xE1', '\x9D', '\x88', /* á ሠ*/ + '\0', + '\xE1', '\x9D', '\x85', ' ', '\xE1', '\x9D', '\x8A', ' ', '\xE1', '\x9D', '\x8E', /* á… áŠ áŽ */ + '\0', + '\xE1', '\x9D', '\x82', ' ', '\xE1', '\x9D', '\x83', ' ', '\xE1', '\x9D', '\x89', ' ', '\xE1', '\x9D', '\x8C', /* Ⴀრበጠ*/ + '\0', + '\xE1', '\x9D', '\x80', ' ', '\xE1', '\x9D', '\x83', ' ', '\xE1', '\x9D', '\x86', ' ', '\xE1', '\x9D', '\x89', ' ', '\xE1', '\x9D', '\x8B', ' ', '\xE1', '\x9D', '\x8F', ' ', '\xE1', '\x9D', '\x91', /* ဠრᆠበዠá á‘ */ + '\0', + '\xE1', '\x97', '\x9C', ' ', '\xE1', '\x96', '\xB4', ' ', '\xE1', '\x90', '\x81', ' ', '\xE1', '\x92', '\xA3', ' ', '\xE1', '\x91', '\xAB', ' ', '\xE1', '\x91', '\x8E', ' ', '\xE1', '\x94', '\x91', ' ', '\xE1', '\x97', '\xB0', /* á—œ á–´ á á’£ á‘« ᑎ ᔑ á—° */ + '\0', + '\xE1', '\x97', '\xB6', ' ', '\xE1', '\x96', '\xB5', ' ', '\xE1', '\x92', '\xA7', ' ', '\xE1', '\x90', '\x83', ' ', '\xE1', '\x91', '\x8C', ' ', '\xE1', '\x92', '\x8D', ' ', '\xE1', '\x94', '\x91', ' ', '\xE1', '\x97', '\xA2', /* á—¶ á–µ á’§ რᑌ ᒠᔑ á—¢ */ + '\0', + '\xE1', '\x93', '\x93', ' ', '\xE1', '\x93', '\x95', ' ', '\xE1', '\x93', '\x80', ' ', '\xE1', '\x93', '\x82', ' ', '\xE1', '\x93', '\x84', ' ', '\xE1', '\x95', '\x84', ' ', '\xE1', '\x95', '\x86', ' ', '\xE1', '\x98', '\xA3', /* á““ á“• á“€ á“‚ á“„ á•„ ᕆ ᘣ */ + '\0', + '\xE1', '\x95', '\x83', ' ', '\xE1', '\x93', '\x82', ' ', '\xE1', '\x93', '\x80', ' ', '\xE1', '\x95', '\x82', ' ', '\xE1', '\x93', '\x97', ' ', '\xE1', '\x93', '\x9A', ' ', '\xE1', '\x95', '\x86', ' ', '\xE1', '\x98', '\xA3', /* ᕃ á“‚ á“€ á•‚ á“— ᓚ ᕆ ᘣ */ + '\0', + '\xE1', '\x90', '\xAA', ' ', '\xE1', '\x99', '\x86', ' ', '\xE1', '\xA3', '\x98', ' ', '\xE1', '\x90', '\xA2', ' ', '\xE1', '\x92', '\xBE', ' ', '\xE1', '\xA3', '\x97', ' ', '\xE1', '\x94', '\x86', /* ᪠ᙆ ᣘ ᢠᒾ ᣗ ᔆ */ + '\0', + '\xE1', '\x99', '\x86', ' ', '\xE1', '\x97', '\xAE', ' ', '\xE1', '\x92', '\xBB', ' ', '\xE1', '\x90', '\x9E', ' ', '\xE1', '\x94', '\x86', ' ', '\xE1', '\x92', '\xA1', ' ', '\xE1', '\x92', '\xA2', ' ', '\xE1', '\x93', '\x91', /* ᙆ á—® á’» ហᔆ á’¡ á’¢ á“‘ */ + '\0', + '\xF0', '\x90', '\x8A', '\xA7', ' ', '\xF0', '\x90', '\x8A', '\xAB', ' ', '\xF0', '\x90', '\x8A', '\xAC', ' ', '\xF0', '\x90', '\x8A', '\xAD', ' ', '\xF0', '\x90', '\x8A', '\xB1', ' ', '\xF0', '\x90', '\x8A', '\xBA', ' ', '\xF0', '\x90', '\x8A', '\xBC', ' ', '\xF0', '\x90', '\x8A', '\xBF', /* ðŠ§ ðŠ« ðŠ¬ ðŠ­ ðŠ± ðŠº ðŠ¼ ðŠ¿ */ + '\0', + '\xF0', '\x90', '\x8A', '\xA3', ' ', '\xF0', '\x90', '\x8A', '\xA7', ' ', '\xF0', '\x90', '\x8A', '\xB7', ' ', '\xF0', '\x90', '\x8B', '\x80', ' ', '\xF0', '\x90', '\x8A', '\xAB', ' ', '\xF0', '\x90', '\x8A', '\xB8', ' ', '\xF0', '\x90', '\x8B', '\x89', /* ðŠ£ ðŠ§ ðŠ· ð‹€ ðŠ« ðŠ¸ ð‹‰ */ + '\0', + '\xF0', '\x91', '\x84', '\x83', ' ', '\xF0', '\x91', '\x84', '\x85', ' ', '\xF0', '\x91', '\x84', '\x89', ' ', '\xF0', '\x91', '\x84', '\x99', ' ', '\xF0', '\x91', '\x84', '\x97', /* 𑄃 ð‘„… 𑄉 ð‘„™ ð‘„— */ + '\0', + '\xF0', '\x91', '\x84', '\x85', ' ', '\xF0', '\x91', '\x84', '\x9B', ' ', '\xF0', '\x91', '\x84', '\x9D', ' ', '\xF0', '\x91', '\x84', '\x97', ' ', '\xF0', '\x91', '\x84', '\x93', /* ð‘„… ð‘„› ð‘„ ð‘„— ð‘„“ */ + '\0', + '\xF0', '\x91', '\x84', '\x96', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\x98', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\x99', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\xA4', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\xA5', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', /* 𑄖𑄳𑄢 𑄘𑄳𑄢 𑄙𑄳𑄢 𑄤𑄳𑄢 𑄥𑄳𑄢 */ + '\0', + '\xE1', '\x8F', '\x86', ' ', '\xE1', '\x8E', '\xBB', ' ', '\xE1', '\x8E', '\xAC', ' ', '\xE1', '\x8F', '\x83', ' ', '\xE1', '\x8E', '\xA4', ' ', '\xE1', '\x8F', '\xA3', ' ', '\xE1', '\x8E', '\xA6', ' ', '\xE1', '\x8F', '\x95', /* ᆠᎻ Ꭼ რᎤ ᣠᎦ á• */ + '\0', + '\xEA', '\xAE', '\x92', ' ', '\xEA', '\xAE', '\xA4', ' ', '\xEA', '\xAE', '\xB6', ' ', '\xEA', '\xAD', '\xB4', ' ', '\xEA', '\xAD', '\xBE', ' ', '\xEA', '\xAE', '\x97', ' ', '\xEA', '\xAE', '\x9D', ' ', '\xEA', '\xAE', '\xBF', /* ê®’ ꮤ ê®¶ ê­´ ê­¾ ê®— ê® ê®¿ */ + '\0', + '\xEA', '\xAE', '\x96', ' ', '\xEA', '\xAD', '\xBC', ' ', '\xEA', '\xAE', '\x93', ' ', '\xEA', '\xAE', '\xA0', ' ', '\xEA', '\xAE', '\xB3', ' ', '\xEA', '\xAD', '\xB6', ' ', '\xEA', '\xAE', '\xA5', ' ', '\xEA', '\xAE', '\xBB', /* ê®– ê­¼ ꮓ ê®  ꮳ ê­¶ ꮥ ê®» */ + '\0', + '\xE1', '\x8F', '\xB8', ' ', '\xEA', '\xAE', '\x90', ' ', '\xEA', '\xAD', '\xB9', ' ', '\xEA', '\xAD', '\xBB', /* á¸ ê® ê­¹ ê­» */ + '\0', + '\xE2', '\xB2', '\x8C', ' ', '\xE2', '\xB2', '\x8E', ' ', '\xE2', '\xB2', '\xA0', ' ', '\xE2', '\xB3', '\x9E', ' ', '\xE2', '\xB2', '\x9E', ' ', '\xE2', '\xB2', '\x90', ' ', '\xE2', '\xB2', '\xA4', ' ', '\xE2', '\xB3', '\x8A', /* Ⲍ Ⲏ â²  Ⳟ Ⲟ ⲠⲤ Ⳋ */ + '\0', + '\xE2', '\xB3', '\x90', ' ', '\xE2', '\xB3', '\x98', ' ', '\xE2', '\xB3', '\x9E', ' ', '\xE2', '\xB2', '\x8E', ' ', '\xE2', '\xB2', '\x9E', ' ', '\xE2', '\xB2', '\x90', ' ', '\xE2', '\xB3', '\x9C', ' ', '\xE2', '\xB2', '\xB0', /* ⳠⳘ Ⳟ Ⲏ Ⲟ ⲠⳜ â²° */ + '\0', + '\xE2', '\xB2', '\x8D', ' ', '\xE2', '\xB2', '\x8F', ' ', '\xE2', '\xB2', '\xA1', ' ', '\xE2', '\xB3', '\x9F', ' ', '\xE2', '\xB2', '\x9F', ' ', '\xE2', '\xB2', '\x91', ' ', '\xE2', '\xB2', '\xA5', ' ', '\xE2', '\xB3', '\x8B', /* ⲠⲠⲡ ⳟ ⲟ ⲑ â²¥ ⳋ */ + '\0', + '\xE2', '\xB3', '\x91', ' ', '\xE2', '\xB3', '\x99', ' ', '\xE2', '\xB3', '\x9F', ' ', '\xE2', '\xB2', '\x8F', ' ', '\xE2', '\xB2', '\x9F', ' ', '\xE2', '\xB2', '\x91', ' ', '\xE2', '\xB3', '\x9D', ' ', '\xE2', '\xB3', '\x92', /* ⳑ â³™ ⳟ Ⲡⲟ ⲑ â³ â³’ */ + '\0', + '\xF0', '\x90', '\xA0', '\x8D', ' ', '\xF0', '\x90', '\xA0', '\x99', ' ', '\xF0', '\x90', '\xA0', '\xB3', ' ', '\xF0', '\x90', '\xA0', '\xB1', ' ', '\xF0', '\x90', '\xA0', '\x85', ' ', '\xF0', '\x90', '\xA0', '\x93', ' ', '\xF0', '\x90', '\xA0', '\xA3', ' ', '\xF0', '\x90', '\xA0', '\xA6', /* ð  ð ™ ð ³ ð ± ð … ð “ ð £ ð ¦ */ + '\0', + '\xF0', '\x90', '\xA0', '\x83', ' ', '\xF0', '\x90', '\xA0', '\x8A', ' ', '\xF0', '\x90', '\xA0', '\x9B', ' ', '\xF0', '\x90', '\xA0', '\xA3', ' ', '\xF0', '\x90', '\xA0', '\xB3', ' ', '\xF0', '\x90', '\xA0', '\xB5', ' ', '\xF0', '\x90', '\xA0', '\x90', /* ð ƒ ð Š ð › ð £ ð ³ ð µ ð  */ + '\0', + '\xF0', '\x90', '\xA0', '\x88', ' ', '\xF0', '\x90', '\xA0', '\x8F', ' ', '\xF0', '\x90', '\xA0', '\x96', /* ð ˆ ð  ð – */ + '\0', + '\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\x9F', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD', /* Б Ð’ Е П З О С Э */ + '\0', + '\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\xA8', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD', /* Б Ð’ Е Ш З О С Э */ + '\0', + '\xD1', '\x85', ' ', '\xD0', '\xBF', ' ', '\xD0', '\xBD', ' ', '\xD1', '\x88', ' ', '\xD0', '\xB5', ' ', '\xD0', '\xB7', ' ', '\xD0', '\xBE', ' ', '\xD1', '\x81', /* Ñ… п н ш е з о Ñ */ + '\0', + '\xD1', '\x80', ' ', '\xD1', '\x83', ' ', '\xD1', '\x84', /* Ñ€ у Ñ„ */ + '\0', + '\xF0', '\x90', '\x90', '\x82', ' ', '\xF0', '\x90', '\x90', '\x84', ' ', '\xF0', '\x90', '\x90', '\x8B', ' ', '\xF0', '\x90', '\x90', '\x97', ' ', '\xF0', '\x90', '\x90', '\x91', /* ð‚ ð„ ð‹ ð— ð‘ */ + '\0', + '\xF0', '\x90', '\x90', '\x80', ' ', '\xF0', '\x90', '\x90', '\x82', ' ', '\xF0', '\x90', '\x90', '\x84', ' ', '\xF0', '\x90', '\x90', '\x97', ' ', '\xF0', '\x90', '\x90', '\x9B', /* ð€ ð‚ ð„ ð— ð› */ + '\0', + '\xF0', '\x90', '\x90', '\xAA', ' ', '\xF0', '\x90', '\x90', '\xAC', ' ', '\xF0', '\x90', '\x90', '\xB3', ' ', '\xF0', '\x90', '\x90', '\xBF', ' ', '\xF0', '\x90', '\x90', '\xB9', /* ðª ð¬ ð³ ð¿ ð¹ */ + '\0', + '\xF0', '\x90', '\x90', '\xA8', ' ', '\xF0', '\x90', '\x90', '\xAA', ' ', '\xF0', '\x90', '\x90', '\xAC', ' ', '\xF0', '\x90', '\x90', '\xBF', ' ', '\xF0', '\x90', '\x91', '\x83', /* ð¨ ðª ð¬ ð¿ 𑃠*/ + '\0', + '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xA8', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x89', ' ', '\xE0', '\xA4', '\x9B', ' ', '\xE0', '\xA4', '\x9F', ' ', '\xE0', '\xA4', '\xA0', ' ', '\xE0', '\xA4', '\xA1', /* क न म उ छ ट ठ ड */ + '\0', + '\xE0', '\xA4', '\x88', ' ', '\xE0', '\xA4', '\x90', ' ', '\xE0', '\xA4', '\x93', ' ', '\xE0', '\xA4', '\x94', ' ', '\xE0', '\xA4', '\xBF', ' ', '\xE0', '\xA5', '\x80', ' ', '\xE0', '\xA5', '\x8B', ' ', '\xE0', '\xA5', '\x8C', /* ई ठओ औ ि ी ो ौ */ + '\0', + '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x85', ' ', '\xE0', '\xA4', '\x86', ' ', '\xE0', '\xA4', '\xA5', ' ', '\xE0', '\xA4', '\xA7', ' ', '\xE0', '\xA4', '\xAD', ' ', '\xE0', '\xA4', '\xB6', /* क म अ आ थ ध भ श */ + '\0', + '\xE0', '\xA5', '\x81', ' ', '\xE0', '\xA5', '\x83', /* ॠृ */ + '\0', + '\xE1', '\x88', '\x80', ' ', '\xE1', '\x88', '\x83', ' ', '\xE1', '\x8B', '\x98', ' ', '\xE1', '\x8D', '\x90', ' ', '\xE1', '\x88', '\x9B', ' ', '\xE1', '\x89', '\xA0', ' ', '\xE1', '\x8B', '\x8B', ' ', '\xE1', '\x8B', '\x90', /* ሀ ሃ ዘ á ማ በ á‹‹ á‹ */ + '\0', + '\xE1', '\x88', '\x88', ' ', '\xE1', '\x88', '\x90', ' ', '\xE1', '\x89', '\xA0', ' ', '\xE1', '\x8B', '\x98', ' ', '\xE1', '\x88', '\x80', ' ', '\xE1', '\x88', '\xAA', ' ', '\xE1', '\x8B', '\x90', ' ', '\xE1', '\x8C', '\xA8', /* ለ ሠበ ዘ ሀ ሪ ዠጨ */ + '\0', + '\xE1', '\x83', '\x92', ' ', '\xE1', '\x83', '\x93', ' ', '\xE1', '\x83', '\x94', ' ', '\xE1', '\x83', '\x95', ' ', '\xE1', '\x83', '\x97', ' ', '\xE1', '\x83', '\x98', ' ', '\xE1', '\x83', '\x9D', ' ', '\xE1', '\x83', '\xA6', /* გ დ ე ვ თ ი რღ */ + '\0', + '\xE1', '\x83', '\x90', ' ', '\xE1', '\x83', '\x96', ' ', '\xE1', '\x83', '\x9B', ' ', '\xE1', '\x83', '\xA1', ' ', '\xE1', '\x83', '\xA8', ' ', '\xE1', '\x83', '\xAB', ' ', '\xE1', '\x83', '\xAE', ' ', '\xE1', '\x83', '\x9E', /* რზ მ ს შ ძ ხ პ */ + '\0', + '\xE1', '\x83', '\xA1', ' ', '\xE1', '\x83', '\xAE', ' ', '\xE1', '\x83', '\xA5', ' ', '\xE1', '\x83', '\x96', ' ', '\xE1', '\x83', '\x9B', ' ', '\xE1', '\x83', '\xA8', ' ', '\xE1', '\x83', '\xA9', ' ', '\xE1', '\x83', '\xAC', /* ს ხ ქ ზ მ შ ჩ წ */ + '\0', + '\xE1', '\x83', '\x94', ' ', '\xE1', '\x83', '\x95', ' ', '\xE1', '\x83', '\x9F', ' ', '\xE1', '\x83', '\xA2', ' ', '\xE1', '\x83', '\xA3', ' ', '\xE1', '\x83', '\xA4', ' ', '\xE1', '\x83', '\xA5', ' ', '\xE1', '\x83', '\xA7', /* ე ვ ჟ ტ უ ფ ქ ყ */ + '\0', + '\xE1', '\x82', '\xB1', ' ', '\xE1', '\x82', '\xA7', ' ', '\xE1', '\x82', '\xB9', ' ', '\xE1', '\x82', '\xBC', ' ', '\xE1', '\x82', '\xA4', ' ', '\xE1', '\x82', '\xA5', ' ', '\xE1', '\x82', '\xB3', ' ', '\xE1', '\x82', '\xBA', /* Ⴑ á‚§ Ⴙ Ⴜ Ⴄ á‚¥ Ⴓ Ⴚ */ + '\0', + '\xE1', '\x82', '\xA4', ' ', '\xE1', '\x82', '\xA5', ' ', '\xE1', '\x82', '\xA7', ' ', '\xE1', '\x82', '\xA8', ' ', '\xE1', '\x82', '\xA6', ' ', '\xE1', '\x82', '\xB1', ' ', '\xE1', '\x82', '\xAA', ' ', '\xE1', '\x82', '\xAB', /* Ⴄ á‚¥ á‚§ Ⴈ Ⴆ Ⴑ Ⴊ á‚« */ + '\0', + '\xE2', '\xB4', '\x81', ' ', '\xE2', '\xB4', '\x97', ' ', '\xE2', '\xB4', '\x82', ' ', '\xE2', '\xB4', '\x84', ' ', '\xE2', '\xB4', '\x85', ' ', '\xE2', '\xB4', '\x87', ' ', '\xE2', '\xB4', '\x94', ' ', '\xE2', '\xB4', '\x96', /* â´ â´— â´‚ â´„ â´… â´‡ â´” â´– */ + '\0', + '\xE2', '\xB4', '\x88', ' ', '\xE2', '\xB4', '\x8C', ' ', '\xE2', '\xB4', '\x96', ' ', '\xE2', '\xB4', '\x8E', ' ', '\xE2', '\xB4', '\x83', ' ', '\xE2', '\xB4', '\x86', ' ', '\xE2', '\xB4', '\x8B', ' ', '\xE2', '\xB4', '\xA2', /* â´ˆ â´Œ â´– â´Ž â´ƒ â´† â´‹ â´¢ */ + '\0', + '\xE2', '\xB4', '\x90', ' ', '\xE2', '\xB4', '\x91', ' ', '\xE2', '\xB4', '\x93', ' ', '\xE2', '\xB4', '\x95', ' ', '\xE2', '\xB4', '\x99', ' ', '\xE2', '\xB4', '\x9B', ' ', '\xE2', '\xB4', '\xA1', ' ', '\xE2', '\xB4', '\xA3', /* â´ â´‘ â´“ â´• â´™ â´› â´¡ â´£ */ + '\0', + '\xE2', '\xB4', '\x84', ' ', '\xE2', '\xB4', '\x85', ' ', '\xE2', '\xB4', '\x94', ' ', '\xE2', '\xB4', '\x95', ' ', '\xE2', '\xB4', '\x81', ' ', '\xE2', '\xB4', '\x82', ' ', '\xE2', '\xB4', '\x98', ' ', '\xE2', '\xB4', '\x9D', /* â´„ â´… â´” â´• â´ â´‚ â´˜ â´ */ + '\0', + '\xE1', '\xB2', '\x9C', ' ', '\xE1', '\xB2', '\x9F', ' ', '\xE1', '\xB2', '\xB3', ' ', '\xE1', '\xB2', '\xB8', ' ', '\xE1', '\xB2', '\x92', ' ', '\xE1', '\xB2', '\x94', ' ', '\xE1', '\xB2', '\x9D', ' ', '\xE1', '\xB2', '\xB4', /* Ნ Ჟ á²³ Ჸ á²’ á²” á² á²´ */ + '\0', + '\xE1', '\xB2', '\x98', ' ', '\xE1', '\xB2', '\xB2', ' ', '\xE1', '\xB2', '\x9D', ' ', '\xE1', '\xB2', '\xA9', ' ', '\xE1', '\xB2', '\x9B', ' ', '\xE1', '\xB2', '\xA8', ' ', '\xE1', '\xB2', '\xAF', ' ', '\xE1', '\xB2', '\xBD', /* Ი á²² ᲠᲩ á²› Შ Ჯ á²½ */ + '\0', + '\xE2', '\xB0', '\x85', ' ', '\xE2', '\xB0', '\x94', ' ', '\xE2', '\xB0', '\xAA', ' ', '\xE2', '\xB0', '\x84', ' ', '\xE2', '\xB0', '\x82', ' ', '\xE2', '\xB0', '\x8A', ' ', '\xE2', '\xB0', '\xAB', ' ', '\xE2', '\xB0', '\x8B', /* â°… â°” â°ª â°„ â°‚ â°Š â°« â°‹ */ + '\0', + '\xE2', '\xB0', '\x85', ' ', '\xE2', '\xB0', '\x84', ' ', '\xE2', '\xB0', '\x82', ' ', '\xE2', '\xB0', '\xAA', ' ', '\xE2', '\xB0', '\x9E', ' ', '\xE2', '\xB0', '\xA1', ' ', '\xE2', '\xB0', '\x8A', ' ', '\xE2', '\xB0', '\x94', /* â°… â°„ â°‚ â°ª â°ž â°¡ â°Š â°” */ + '\0', + '\xE2', '\xB0', '\xB5', ' ', '\xE2', '\xB1', '\x84', ' ', '\xE2', '\xB1', '\x9A', ' ', '\xE2', '\xB0', '\xB4', ' ', '\xE2', '\xB0', '\xB2', ' ', '\xE2', '\xB0', '\xBA', ' ', '\xE2', '\xB1', '\x9B', ' ', '\xE2', '\xB0', '\xBB', /* â°µ ⱄ ⱚ â°´ â°² â°º â±› â°» */ + '\0', + '\xE2', '\xB0', '\xB5', ' ', '\xE2', '\xB0', '\xB4', ' ', '\xE2', '\xB0', '\xB2', ' ', '\xE2', '\xB1', '\x9A', ' ', '\xE2', '\xB1', '\x8E', ' ', '\xE2', '\xB1', '\x91', ' ', '\xE2', '\xB0', '\xBA', ' ', '\xE2', '\xB1', '\x84', /* â°µ â°´ â°² ⱚ ⱎ ⱑ â°º ⱄ */ + '\0', + '\xF0', '\x90', '\x8C', '\xB2', ' ', '\xF0', '\x90', '\x8C', '\xB6', ' ', '\xF0', '\x90', '\x8D', '\x80', ' ', '\xF0', '\x90', '\x8D', '\x84', ' ', '\xF0', '\x90', '\x8C', '\xB4', ' ', '\xF0', '\x90', '\x8D', '\x83', ' ', '\xF0', '\x90', '\x8D', '\x88', ' ', '\xF0', '\x90', '\x8C', '\xBE', /* ðŒ² ðŒ¶ ð€ ð„ ðŒ´ ðƒ ðˆ ðŒ¾ */ + '\0', + '\xF0', '\x90', '\x8C', '\xB6', ' ', '\xF0', '\x90', '\x8C', '\xB4', ' ', '\xF0', '\x90', '\x8D', '\x83', ' ', '\xF0', '\x90', '\x8D', '\x88', /* ðŒ¶ ðŒ´ ðƒ ðˆ */ + '\0', + '\xCE', '\x93', ' ', '\xCE', '\x92', ' ', '\xCE', '\x95', ' ', '\xCE', '\x96', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F', ' ', '\xCE', '\xA9', /* Γ Î’ Ε Ζ Θ Ο Ω */ + '\0', + '\xCE', '\x92', ' ', '\xCE', '\x94', ' ', '\xCE', '\x96', ' ', '\xCE', '\x9E', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F', /* Î’ Δ Ζ Ξ Θ Ο */ + '\0', + '\xCE', '\xB2', ' ', '\xCE', '\xB8', ' ', '\xCE', '\xB4', ' ', '\xCE', '\xB6', ' ', '\xCE', '\xBB', ' ', '\xCE', '\xBE', /* β θ δ ζ λ ξ */ + '\0', + '\xCE', '\xB1', ' ', '\xCE', '\xB5', ' ', '\xCE', '\xB9', ' ', '\xCE', '\xBF', ' ', '\xCF', '\x80', ' ', '\xCF', '\x83', ' ', '\xCF', '\x84', ' ', '\xCF', '\x89', /* α ε ι ο Ï€ σ Ï„ ω */ + '\0', + '\xCE', '\xB2', ' ', '\xCE', '\xB3', ' ', '\xCE', '\xB7', ' ', '\xCE', '\xBC', ' ', '\xCF', '\x81', ' ', '\xCF', '\x86', ' ', '\xCF', '\x87', ' ', '\xCF', '\x88', /* β γ η μ Ï Ï† χ ψ */ + '\0', + '\xE0', '\xAA', '\xA4', ' ', '\xE0', '\xAA', '\xA8', ' ', '\xE0', '\xAA', '\x8B', ' ', '\xE0', '\xAA', '\x8C', ' ', '\xE0', '\xAA', '\x9B', ' ', '\xE0', '\xAA', '\x9F', ' ', '\xE0', '\xAA', '\xB0', ' ', '\xE0', '\xAB', '\xA6', /* ત ન ઋ ઌ છ ટ ર ૦ */ + '\0', + '\xE0', '\xAA', '\x96', ' ', '\xE0', '\xAA', '\x97', ' ', '\xE0', '\xAA', '\x98', ' ', '\xE0', '\xAA', '\x9E', ' ', '\xE0', '\xAA', '\x87', ' ', '\xE0', '\xAA', '\x88', ' ', '\xE0', '\xAA', '\xA0', ' ', '\xE0', '\xAA', '\x9C', /* ખ ગ ઘ ઞ ઇ ઈ ઠ જ */ + '\0', + '\xE0', '\xAA', '\x88', ' ', '\xE0', '\xAA', '\x8A', ' ', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAB', '\x80', ' ', '\xE0', '\xAA', '\xB2', '\xE0', '\xAB', '\x80', ' ', '\xE0', '\xAA', '\xB6', '\xE0', '\xAB', '\x8D', '\xE0', '\xAA', '\x9A', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAA', '\x9C', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAA', '\xB8', '\xE0', '\xAB', '\x80', /* ઈ ઊ િ à«€ લી શà«àªšàª¿ જિ સી */ + '\0', + '\xE0', '\xAB', '\x81', ' ', '\xE0', '\xAB', '\x83', ' ', '\xE0', '\xAB', '\x84', ' ', '\xE0', '\xAA', '\x96', '\xE0', '\xAB', '\x81', ' ', '\xE0', '\xAA', '\x9B', '\xE0', '\xAB', '\x83', ' ', '\xE0', '\xAA', '\x9B', '\xE0', '\xAB', '\x84', /* ૠૃ à«„ ખૠછૃ છૄ */ + '\0', + '\xE0', '\xAB', '\xA6', ' ', '\xE0', '\xAB', '\xA7', ' ', '\xE0', '\xAB', '\xA8', ' ', '\xE0', '\xAB', '\xA9', ' ', '\xE0', '\xAB', '\xAD', /* ૦ à«§ ૨ à«© à«­ */ + '\0', + '\xE0', '\xA8', '\x95', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x99', ' ', '\xE0', '\xA8', '\x9A', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA4', ' ', '\xE0', '\xA8', '\xA7', ' ', '\xE0', '\xA8', '\xB8', /* ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ */ + '\0', + '\xE0', '\xA8', '\x95', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x99', ' ', '\xE0', '\xA8', '\x9A', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA4', ' ', '\xE0', '\xA8', '\xA7', ' ', '\xE0', '\xA8', '\xB8', /* ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ */ + '\0', + '\xE0', '\xA8', '\x87', ' ', '\xE0', '\xA8', '\x88', ' ', '\xE0', '\xA8', '\x89', ' ', '\xE0', '\xA8', '\x8F', ' ', '\xE0', '\xA8', '\x93', ' ', '\xE0', '\xA9', '\xB3', ' ', '\xE0', '\xA8', '\xBF', ' ', '\xE0', '\xA9', '\x80', /* ਇ ਈ ਉ ਠਓ ੳ ਿ à©€ */ + '\0', + '\xE0', '\xA8', '\x85', ' ', '\xE0', '\xA8', '\x8F', ' ', '\xE0', '\xA8', '\x93', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA0', ' ', '\xE0', '\xA8', '\xB0', ' ', '\xE0', '\xA8', '\xB8', /* ਅ ਠਓ ਗ ਜ ਠ ਰ ਸ */ + '\0', + '\xE0', '\xA9', '\xA6', ' ', '\xE0', '\xA9', '\xA7', ' ', '\xE0', '\xA9', '\xA8', ' ', '\xE0', '\xA9', '\xA9', ' ', '\xE0', '\xA9', '\xAD', /* ੦ à©§ ੨ à©© à©­ */ + '\0', + '\xD7', '\x91', ' ', '\xD7', '\x93', ' ', '\xD7', '\x94', ' ', '\xD7', '\x97', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1', /* ב ד ×” ×— ך ×› × ×¡ */ + '\0', + '\xD7', '\x91', ' ', '\xD7', '\x98', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1', ' ', '\xD7', '\xA6', /* ב ט ×› × ×¡ צ */ + '\0', + '\xD7', '\xA7', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9F', ' ', '\xD7', '\xA3', ' ', '\xD7', '\xA5', /* ×§ ך ן ×£ ×¥ */ + '\0', + '\xE0', '\xB2', '\x87', ' ', '\xE0', '\xB2', '\x8A', ' ', '\xE0', '\xB2', '\x90', ' ', '\xE0', '\xB2', '\xA3', ' ', '\xE0', '\xB2', '\xB8', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xA8', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xA6', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xB0', '\xE0', '\xB2', '\xBE', /* ಇ ಊ ಠಣ ಸಾ ನಾ ದಾ ರಾ */ + '\0', + '\xE0', '\xB2', '\x85', ' ', '\xE0', '\xB2', '\x89', ' ', '\xE0', '\xB2', '\x8E', ' ', '\xE0', '\xB2', '\xB2', ' ', '\xE0', '\xB3', '\xA6', ' ', '\xE0', '\xB3', '\xA8', ' ', '\xE0', '\xB3', '\xAC', ' ', '\xE0', '\xB3', '\xAD', /* ಅ ಉ ಎ ಲ ೦ ೨ ೬ à³­ */ + '\0', + '\xEA', '\xA4', '\x85', ' ', '\xEA', '\xA4', '\x8F', ' ', '\xEA', '\xA4', '\x81', ' ', '\xEA', '\xA4', '\x8B', ' ', '\xEA', '\xA4', '\x80', ' ', '\xEA', '\xA4', '\x8D', /* ꤅ ê¤ ê¤ ê¤‹ ꤀ ê¤ */ + '\0', + '\xEA', '\xA4', '\x88', ' ', '\xEA', '\xA4', '\x98', ' ', '\xEA', '\xA4', '\x80', ' ', '\xEA', '\xA4', '\x8D', ' ', '\xEA', '\xA4', '\xA2', /* ꤈ ꤘ ꤀ ê¤ ê¤¢ */ + '\0', + '\xEA', '\xA4', '\x96', ' ', '\xEA', '\xA4', '\xA1', /* ꤖ ꤡ */ + '\0', + '\xEA', '\xA4', '\x91', ' ', '\xEA', '\xA4', '\x9C', ' ', '\xEA', '\xA4', '\x9E', /* ꤑ ꤜ ꤞ */ + '\0', + '\xEA', '\xA4', '\x91', '\xEA', '\xA4', '\xAC', ' ', '\xEA', '\xA4', '\x9C', '\xEA', '\xA4', '\xAD', ' ', '\xEA', '\xA4', '\x94', '\xEA', '\xA4', '\xAC', /* ꤑ꤬ ꤜ꤭ ꤔ꤬ */ + '\0', + '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x91', ' ', '\xE1', '\x9E', '\x93', ' ', '\xE1', '\x9E', '\xA7', ' ', '\xE1', '\x9E', '\xA9', ' ', '\xE1', '\x9E', '\xB6', /* áž áž‘ áž“ áž§ áž© áž¶ */ + '\0', + '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x80', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x82', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x90', /* ក្ក ក្ហក្គ ក្ហ*/ + '\0', + '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x83', ' ', '\xE1', '\x9E', '\x85', ' ', '\xE1', '\x9E', '\x8B', ' ', '\xE1', '\x9E', '\x94', ' ', '\xE1', '\x9E', '\x98', ' ', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xB2', /* ហឃ áž… áž‹ áž” ម áž™ áž² */ + '\0', + '\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', ' ', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\xB2', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xA2', '\xE1', '\x9E', '\xBF', /* ážáŸ’ážš រៀ ឲ្យ អឿ */ + '\0', + '\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x83', ' ', '\xE1', '\x9E', '\x84', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x85', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9E', '\xBF', ' ', '\xE1', '\x9E', '\x9B', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9E', '\xBF', /* ន្ážáŸ’រៃ ង្ážáŸ’áž™ ក្បៀ ច្រៀ ន្ážáž¿ ល្បឿ */ + '\0', + '\xE1', '\xA7', '\xA0', ' ', '\xE1', '\xA7', '\xA1', /* á§  á§¡ */ + '\0', + '\xE1', '\xA7', '\xB6', ' ', '\xE1', '\xA7', '\xB9', /* á§¶ á§¹ */ + '\0', + '\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\x94', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\xA1', ' ', '\xE0', '\xBA', '\xA5', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\x87', /* າ ດ ອ ມ ລ ວ ຣ ງ */ + '\0', + '\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\x9A', ' ', '\xE0', '\xBA', '\x8D', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\xAE', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA2', /* າ ອ ບ ຠຣ ຮ ວ ຢ */ + '\0', + '\xE0', '\xBA', '\x9B', ' ', '\xE0', '\xBA', '\xA2', ' ', '\xE0', '\xBA', '\x9F', ' ', '\xE0', '\xBA', '\x9D', /* ປ ຢ ຟ ຠ*/ + '\0', + '\xE0', '\xBB', '\x82', ' ', '\xE0', '\xBB', '\x84', ' ', '\xE0', '\xBB', '\x83', /* ໂ ໄ ໃ */ + '\0', + '\xE0', '\xBA', '\x87', ' ', '\xE0', '\xBA', '\x8A', ' ', '\xE0', '\xBA', '\x96', ' ', '\xE0', '\xBA', '\xBD', ' ', '\xE0', '\xBB', '\x86', ' ', '\xE0', '\xBA', '\xAF', /* ງ ຊ ຖ ຽ ໆ ຯ */ + '\0', + 'T', ' ', 'H', ' ', 'E', ' ', 'Z', ' ', 'O', ' ', 'C', ' ', 'Q', ' ', 'S', /* T H E Z O C Q S */ + '\0', + 'H', ' ', 'E', ' ', 'Z', ' ', 'L', ' ', 'O', ' ', 'C', ' ', 'U', ' ', 'S', /* H E Z L O C U S */ + '\0', + 'f', ' ', 'i', ' ', 'j', ' ', 'k', ' ', 'd', ' ', 'b', ' ', 'h', /* f i j k d b h */ + '\0', + 'u', ' ', 'v', ' ', 'x', ' ', 'z', ' ', 'o', ' ', 'e', ' ', 's', ' ', 'c', /* u v x z o e s c */ + '\0', + 'n', ' ', 'r', ' ', 'x', ' ', 'z', ' ', 'o', ' ', 'e', ' ', 's', ' ', 'c', /* n r x z o e s c */ + '\0', + 'p', ' ', 'q', ' ', 'g', ' ', 'j', ' ', 'y', /* p q g j y */ + '\0', + '\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x85', ' ', '\xE2', '\x82', '\x87', ' ', '\xE2', '\x82', '\x88', /* â‚€ ₃ â‚… ₇ ₈ */ + '\0', + '\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x81', ' ', '\xE2', '\x82', '\x82', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x88', /* â‚€ â‚ â‚‚ ₃ ₈ */ + '\0', + '\xE1', '\xB5', '\xA2', ' ', '\xE2', '\xB1', '\xBC', ' ', '\xE2', '\x82', '\x95', ' ', '\xE2', '\x82', '\x96', ' ', '\xE2', '\x82', '\x97', /* áµ¢ â±¼ â‚• â‚– â‚— */ + '\0', + '\xE2', '\x82', '\x90', ' ', '\xE2', '\x82', '\x91', ' ', '\xE2', '\x82', '\x92', ' ', '\xE2', '\x82', '\x93', ' ', '\xE2', '\x82', '\x99', ' ', '\xE2', '\x82', '\x9B', ' ', '\xE1', '\xB5', '\xA5', ' ', '\xE1', '\xB5', '\xA4', ' ', '\xE1', '\xB5', '\xA3', /* â‚ â‚‘ â‚’ â‚“ â‚™ â‚› áµ¥ ᵤ áµ£ */ + '\0', + '\xE1', '\xB5', '\xA6', ' ', '\xE1', '\xB5', '\xA7', ' ', '\xE1', '\xB5', '\xA8', ' ', '\xE1', '\xB5', '\xA9', ' ', '\xE2', '\x82', '\x9A', /* ᵦ áµ§ ᵨ ᵩ ₚ */ + '\0', + '\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB3', ' ', '\xE2', '\x81', '\xB5', ' ', '\xE2', '\x81', '\xB7', ' ', '\xE1', '\xB5', '\x80', ' ', '\xE1', '\xB4', '\xB4', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xBC', /* Ⱐ³ âµ â· áµ€ á´´ á´± á´¼ */ + '\0', + '\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB9', ' ', '\xC2', '\xB2', ' ', '\xC2', '\xB3', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xB8', ' ', '\xE1', '\xB4', '\xBC', ' ', '\xE1', '\xB5', '\x81', /* Ⱐ¹ ² ³ á´± á´¸ á´¼ áµ */ + '\0', + '\xE1', '\xB5', '\x87', ' ', '\xE1', '\xB5', '\x88', ' ', '\xE1', '\xB5', '\x8F', ' ', '\xCA', '\xB0', ' ', '\xCA', '\xB2', ' ', '\xE1', '\xB6', '\xA0', ' ', '\xE2', '\x81', '\xB1', /* ᵇ ᵈ ᵠʰ ʲ á¶  â± */ + '\0', + '\xE1', '\xB5', '\x89', ' ', '\xE1', '\xB5', '\x92', ' ', '\xCA', '\xB3', ' ', '\xCB', '\xA2', ' ', '\xCB', '\xA3', ' ', '\xE1', '\xB6', '\x9C', ' ', '\xE1', '\xB6', '\xBB', /* ᵉ áµ’ ʳ Ë¢ Ë£ á¶œ á¶» */ + '\0', + '\xE1', '\xB5', '\x96', ' ', '\xCA', '\xB8', ' ', '\xE1', '\xB5', '\x8D', /* áµ– ʸ áµ */ + '\0', + '\xEA', '\x93', '\xA1', ' ', '\xEA', '\x93', '\xA7', ' ', '\xEA', '\x93', '\xB1', ' ', '\xEA', '\x93', '\xB6', ' ', '\xEA', '\x93', '\xA9', ' ', '\xEA', '\x93', '\x9A', ' ', '\xEA', '\x93', '\xB5', ' ', '\xEA', '\x93', '\xB3', /* ê“¡ ê“§ ꓱ ê“¶ ê“© ꓚ ꓵ ꓳ */ + '\0', + '\xEA', '\x93', '\x95', ' ', '\xEA', '\x93', '\x9C', ' ', '\xEA', '\x93', '\x9E', ' ', '\xEA', '\x93', '\xA1', ' ', '\xEA', '\x93', '\x9B', ' ', '\xEA', '\x93', '\xA2', ' ', '\xEA', '\x93', '\xB3', ' ', '\xEA', '\x93', '\xB4', /* ê“• ꓜ ꓞ ê“¡ ê“› ê“¢ ꓳ ê“´ */ + '\0', + '\xE0', '\xB4', '\x92', ' ', '\xE0', '\xB4', '\x9F', ' ', '\xE0', '\xB4', '\xA0', ' ', '\xE0', '\xB4', '\xB1', ' ', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xAA', ' ', '\xE0', '\xB4', '\x9A', '\xE0', '\xB5', '\x8D', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xAA', '\xE0', '\xB5', '\x8D', '\xE0', '\xB4', '\xAA', /* à´’ à´Ÿ à´  à´± à´š à´ª à´šàµà´š à´ªàµà´ª */ + '\0', + '\xE0', '\xB4', '\x9F', ' ', '\xE0', '\xB4', '\xA0', ' ', '\xE0', '\xB4', '\xA7', ' ', '\xE0', '\xB4', '\xB6', ' ', '\xE0', '\xB4', '\x98', ' ', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xA5', ' ', '\xE0', '\xB4', '\xB2', /* à´Ÿ à´  à´§ à´¶ à´˜ à´š à´¥ à´² */ + '\0', + '\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x9F', /* ð–¹€ 𖹠𖹂 𖹃 𖹠𖹚 𖹟 */ + '\0', + '\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x92', ' ', '\xF0', '\x96', '\xB9', '\x93', /* ð–¹€ 𖹠𖹂 𖹃 𖹠𖹚 ð–¹’ 𖹓 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA4', ' ', '\xF0', '\x96', '\xB9', '\xAC', ' ', '\xF0', '\x96', '\xB9', '\xA7', ' ', '\xF0', '\x96', '\xB9', '\xB4', ' ', '\xF0', '\x96', '\xB9', '\xB6', ' ', '\xF0', '\x96', '\xB9', '\xBE', /* 𖹤 𖹬 ð–¹§ ð–¹´ ð–¹¶ ð–¹¾ */ + '\0', + '\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB9', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAE', /* ð–¹  𖹡 ð–¹¢ ð–¹¹ ð–¹³ ð–¹® */ + '\0', + '\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAD', ' ', '\xF0', '\x96', '\xB9', '\xBD', /* ð–¹  𖹡 ð–¹¢ ð–¹³ ð–¹­ ð–¹½ */ + '\0', + '\xF0', '\x96', '\xB9', '\xA5', ' ', '\xF0', '\x96', '\xB9', '\xA8', ' ', '\xF0', '\x96', '\xB9', '\xA9', /* ð–¹¥ 𖹨 𖹩 */ + '\0', + '\xF0', '\x96', '\xBA', '\x80', ' ', '\xF0', '\x96', '\xBA', '\x85', ' ', '\xF0', '\x96', '\xBA', '\x88', ' ', '\xF0', '\x96', '\xBA', '\x84', ' ', '\xF0', '\x96', '\xBA', '\x8D', /* 𖺀 ð–º… 𖺈 𖺄 ð–º */ + '\0', + '\xE1', '\xA0', '\xB3', ' ', '\xE1', '\xA0', '\xB4', ' ', '\xE1', '\xA0', '\xB6', ' ', '\xE1', '\xA0', '\xBD', ' ', '\xE1', '\xA1', '\x82', ' ', '\xE1', '\xA1', '\x8A', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xA1', '\xE2', '\x80', '\x8D', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xB3', '\xE2', '\x80', '\x8D', /* á ³ á ´ á ¶ á ½ á¡‚ ᡊ â€á¡¡â€ â€á¡³â€ */ + '\0', + '\xE1', '\xA1', '\x83', /* ᡃ */ + '\0', + '\xE1', '\x80', '\x81', ' ', '\xE1', '\x80', '\x82', ' ', '\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\xA5', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B', /* ဠဂ င ဒ ဠᥠአዠ*/ + '\0', + '\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x8E', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x95', ' ', '\xE1', '\x80', '\x97', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B', /* င ဎ ဒ ပ ဗ ဠአዠ*/ + '\0', + '\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xBC', ' ', '\xE1', '\x81', '\x8D', ' ', '\xE1', '\x81', '\x8F', ' ', '\xE1', '\x81', '\x86', ' ', '\xE1', '\x80', '\xAB', ' ', '\xE1', '\x80', '\xAD', /* ဩ ြ á á ᆠါ ိ */ + '\0', + '\xE1', '\x80', '\x89', ' ', '\xE1', '\x80', '\x8A', ' ', '\xE1', '\x80', '\xA5', ' ', '\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xA8', ' ', '\xE1', '\x81', '\x82', ' ', '\xE1', '\x81', '\x85', ' ', '\xE1', '\x81', '\x89', /* ဉ ည ဥ ဩ ဨ á‚ á… á‰ */ + '\0', + '\xDF', '\x90', ' ', '\xDF', '\x89', ' ', '\xDF', '\x92', ' ', '\xDF', '\x9F', ' ', '\xDF', '\x96', ' ', '\xDF', '\x9C', ' ', '\xDF', '\xA0', ' ', '\xDF', '\xA5', /* ß ß‰ ß’ ߟ ß– ßœ ß  ߥ */ + '\0', + '\xDF', '\x80', ' ', '\xDF', '\x98', ' ', '\xDF', '\xA1', ' ', '\xDF', '\xA0', ' ', '\xDF', '\xA5', /* ߀ ߘ ß¡ ß  ߥ */ + '\0', + '\xDF', '\x8F', ' ', '\xDF', '\x9B', ' ', '\xDF', '\x8B', /* ß ß› ß‹ */ + '\0', + '\xDF', '\x8E', ' ', '\xDF', '\x8F', ' ', '\xDF', '\x9B', ' ', '\xDF', '\x8B', /* ߎ ß ß› ß‹ */ + '\0', + '\xE1', '\xB1', '\x9B', ' ', '\xE1', '\xB1', '\x9C', ' ', '\xE1', '\xB1', '\x9D', ' ', '\xE1', '\xB1', '\xA1', ' ', '\xE1', '\xB1', '\xA2', ' ', '\xE1', '\xB1', '\xA5', /* á±› ᱜ ᱠᱡ á±¢ á±¥ */ + '\0', + '\xF0', '\x90', '\xB0', '\x97', ' ', '\xF0', '\x90', '\xB0', '\x98', ' ', '\xF0', '\x90', '\xB0', '\xA7', /* ð°— ð°˜ ð°§ */ + '\0', + '\xF0', '\x90', '\xB0', '\x89', ' ', '\xF0', '\x90', '\xB0', '\x97', ' ', '\xF0', '\x90', '\xB0', '\xA6', ' ', '\xF0', '\x90', '\xB0', '\xA7', /* ð°‰ ð°— ð°¦ ð°§ */ + '\0', + '\xF0', '\x90', '\x92', '\xBE', ' ', '\xF0', '\x90', '\x93', '\x8D', ' ', '\xF0', '\x90', '\x93', '\x92', ' ', '\xF0', '\x90', '\x93', '\x93', ' ', '\xF0', '\x90', '\x92', '\xBB', ' ', '\xF0', '\x90', '\x93', '\x82', ' ', '\xF0', '\x90', '\x92', '\xB5', ' ', '\xF0', '\x90', '\x93', '\x86', /* ð’¾ ð“ 𓒠𓓠𒻠𓂠𒵠𓆠*/ + '\0', + '\xF0', '\x90', '\x92', '\xB0', ' ', '\xF0', '\x90', '\x93', '\x8D', ' ', '\xF0', '\x90', '\x93', '\x82', ' ', '\xF0', '\x90', '\x92', '\xBF', ' ', '\xF0', '\x90', '\x93', '\x8E', ' ', '\xF0', '\x90', '\x92', '\xB9', /* ð’° ð“ 𓂠𒿠𓎠𒹠*/ + '\0', + '\xF0', '\x90', '\x92', '\xBC', ' ', '\xF0', '\x90', '\x92', '\xBD', ' ', '\xF0', '\x90', '\x92', '\xBE', /* ð’¼ ð’½ ð’¾ */ + '\0', + '\xF0', '\x90', '\x93', '\xB5', ' ', '\xF0', '\x90', '\x93', '\xB6', ' ', '\xF0', '\x90', '\x93', '\xBA', ' ', '\xF0', '\x90', '\x93', '\xBB', ' ', '\xF0', '\x90', '\x93', '\x9D', ' ', '\xF0', '\x90', '\x93', '\xA3', ' ', '\xF0', '\x90', '\x93', '\xAA', ' ', '\xF0', '\x90', '\x93', '\xAE', /* 𓵠𓶠𓺠𓻠ð“ 𓣠𓪠𓮠*/ + '\0', + '\xF0', '\x90', '\x93', '\x98', ' ', '\xF0', '\x90', '\x93', '\x9A', ' ', '\xF0', '\x90', '\x93', '\xA3', ' ', '\xF0', '\x90', '\x93', '\xB5', ' ', '\xF0', '\x90', '\x93', '\xA1', ' ', '\xF0', '\x90', '\x93', '\xA7', ' ', '\xF0', '\x90', '\x93', '\xAA', ' ', '\xF0', '\x90', '\x93', '\xB6', /* 𓘠𓚠𓣠𓵠𓡠𓧠𓪠𓶠*/ + '\0', + '\xF0', '\x90', '\x93', '\xA4', ' ', '\xF0', '\x90', '\x93', '\xA6', ' ', '\xF0', '\x90', '\x93', '\xB8', ' ', '\xF0', '\x90', '\x93', '\xB9', ' ', '\xF0', '\x90', '\x93', '\x9B', /* 𓤠𓦠𓸠𓹠𓛠*/ + '\0', + '\xF0', '\x90', '\x93', '\xA4', ' ', '\xF0', '\x90', '\x93', '\xA5', ' ', '\xF0', '\x90', '\x93', '\xA6', /* 𓤠𓥠𓦠*/ + '\0', + '\xF0', '\x90', '\x92', '\x86', ' ', '\xF0', '\x90', '\x92', '\x89', ' ', '\xF0', '\x90', '\x92', '\x90', ' ', '\xF0', '\x90', '\x92', '\x92', ' ', '\xF0', '\x90', '\x92', '\x98', ' ', '\xF0', '\x90', '\x92', '\x9B', ' ', '\xF0', '\x90', '\x92', '\xA0', ' ', '\xF0', '\x90', '\x92', '\xA3', /* ð’† ð’‰ ð’ ð’’ ð’˜ ð’› ð’  ð’£ */ + '\0', + '\xF0', '\x90', '\x92', '\x80', ' ', '\xF0', '\x90', '\x92', '\x82', ' ', '\xF0', '\x90', '\x92', '\x86', ' ', '\xF0', '\x90', '\x92', '\x88', ' ', '\xF0', '\x90', '\x92', '\x8A', ' ', '\xF0', '\x90', '\x92', '\x92', ' ', '\xF0', '\x90', '\x92', '\xA0', ' ', '\xF0', '\x90', '\x92', '\xA9', /* ð’€ ð’‚ ð’† ð’ˆ ð’Š ð’’ ð’  ð’© */ + '\0', + '\xF0', '\x90', '\xB4', '\x83', ' ', '\xF0', '\x90', '\xB4', '\x80', ' ', '\xF0', '\x90', '\xB4', '\x86', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', /* ð´ƒ ð´€ ð´† ð´– ð´• */ + '\0', + '\xF0', '\x90', '\xB4', '\x94', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', ' ', '\xF0', '\x90', '\xB4', '\x91', ' ', '\xF0', '\x90', '\xB4', '\x90', /* ð´” ð´– ð´• ð´‘ ð´ */ + '\0', + '\xD9', '\x80', /* Ù€ */ + '\0', + '\xEA', '\xA2', '\x9C', ' ', '\xEA', '\xA2', '\x9E', ' ', '\xEA', '\xA2', '\xB3', ' ', '\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\x96', ' ', '\xEA', '\xA2', '\x92', ' ', '\xEA', '\xA2', '\x9D', ' ', '\xEA', '\xA2', '\x9B', /* ꢜ ꢞ ꢳ ꢂ ꢖ ꢒ ê¢ ê¢› */ + '\0', + '\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\xA8', ' ', '\xEA', '\xA2', '\xBA', ' ', '\xEA', '\xA2', '\xA4', ' ', '\xEA', '\xA2', '\x8E', /* ꢂ ꢨ ꢺ ꢤ ꢎ */ + '\0', + '\xF0', '\x90', '\x91', '\x95', ' ', '\xF0', '\x90', '\x91', '\x99', /* ð‘• ð‘™ */ + '\0', + '\xF0', '\x90', '\x91', '\x94', ' ', '\xF0', '\x90', '\x91', '\x96', ' ', '\xF0', '\x90', '\x91', '\x97', ' ', '\xF0', '\x90', '\x91', '\xB9', ' ', '\xF0', '\x90', '\x91', '\xBB', /* 𑔠𑖠𑗠𑹠𑻠*/ + '\0', + '\xF0', '\x90', '\x91', '\x9F', ' ', '\xF0', '\x90', '\x91', '\xA3', /* 𑟠𑣠*/ + '\0', + '\xF0', '\x90', '\x91', '\xB1', ' ', '\xF0', '\x90', '\x91', '\xB2', ' ', '\xF0', '\x90', '\x91', '\xB3', ' ', '\xF0', '\x90', '\x91', '\xB4', ' ', '\xF0', '\x90', '\x91', '\xB8', ' ', '\xF0', '\x90', '\x91', '\xBA', ' ', '\xF0', '\x90', '\x91', '\xBC', /* 𑱠𑲠𑳠𑴠𑸠𑺠𑼠*/ + '\0', + '\xF0', '\x90', '\x91', '\xB4', ' ', '\xF0', '\x90', '\x91', '\xBB', ' ', '\xF0', '\x90', '\x91', '\xB9', /* 𑴠𑻠𑹠*/ + '\0', + '\xE0', '\xB6', '\x89', ' ', '\xE0', '\xB6', '\x9A', ' ', '\xE0', '\xB6', '\x9D', ' ', '\xE0', '\xB6', '\xB3', ' ', '\xE0', '\xB6', '\xB4', ' ', '\xE0', '\xB6', '\xBA', ' ', '\xE0', '\xB6', '\xBD', ' ', '\xE0', '\xB7', '\x86', /* ඉ à¶š à¶ à¶³ à¶´ ය à¶½ à·† */ + '\0', + '\xE0', '\xB6', '\x91', ' ', '\xE0', '\xB6', '\x94', ' ', '\xE0', '\xB6', '\x9D', ' ', '\xE0', '\xB6', '\xA2', ' ', '\xE0', '\xB6', '\xA7', ' ', '\xE0', '\xB6', '\xAE', ' ', '\xE0', '\xB6', '\xB0', ' ', '\xE0', '\xB6', '\xBB', /* à¶‘ à¶” à¶ à¶¢ à¶§ à¶® à¶° à¶» */ + '\0', + '\xE0', '\xB6', '\xAF', ' ', '\xE0', '\xB6', '\xB3', ' ', '\xE0', '\xB6', '\x8B', ' ', '\xE0', '\xB6', '\xBD', ' ', '\xE0', '\xB6', '\xAD', '\xE0', '\xB7', '\x96', ' ', '\xE0', '\xB6', '\xAD', '\xE0', '\xB7', '\x94', ' ', '\xE0', '\xB6', '\xB6', '\xE0', '\xB7', '\x94', ' ', '\xE0', '\xB6', '\xAF', '\xE0', '\xB7', '\x94', /* ද à¶³ à¶‹ à¶½ à¶­à·– à¶­à·” à¶¶à·” දු */ + '\0', + '\xE1', '\xAE', '\x8B', ' ', '\xE1', '\xAE', '\x9E', ' ', '\xE1', '\xAE', '\xAE', ' ', '\xE1', '\xAE', '\xBD', ' ', '\xE1', '\xAE', '\xB0', ' ', '\xE1', '\xAE', '\x88', /* ᮋ ᮞ á®® ᮽ á®° ᮈ */ + '\0', + '\xE1', '\xAE', '\x84', ' ', '\xE1', '\xAE', '\x94', ' ', '\xE1', '\xAE', '\x95', ' ', '\xE1', '\xAE', '\x97', ' ', '\xE1', '\xAE', '\xB0', ' ', '\xE1', '\xAE', '\x86', ' ', '\xE1', '\xAE', '\x88', ' ', '\xE1', '\xAE', '\x89', /* ᮄ á®” ᮕ á®— á®° ᮆ ᮈ ᮉ */ + '\0', + '\xE1', '\xAE', '\xBC', ' ', '\xE1', '\xB3', '\x84', /* ᮼ ᳄ */ + '\0', + '\xEA', '\xAA', '\x86', ' ', '\xEA', '\xAA', '\x94', ' ', '\xEA', '\xAA', '\x92', ' ', '\xEA', '\xAA', '\x96', ' ', '\xEA', '\xAA', '\xAB', /* ꪆ ꪔ ꪒ ꪖ ꪫ */ + '\0', + '\xEA', '\xAA', '\x89', ' ', '\xEA', '\xAA', '\xAB', ' ', '\xEA', '\xAA', '\xAE', /* ꪉ ꪫ ꪮ */ + '\0', + '\xE0', '\xAE', '\x89', ' ', '\xE0', '\xAE', '\x92', ' ', '\xE0', '\xAE', '\x93', ' ', '\xE0', '\xAE', '\xB1', ' ', '\xE0', '\xAE', '\x88', ' ', '\xE0', '\xAE', '\x95', ' ', '\xE0', '\xAE', '\x99', ' ', '\xE0', '\xAE', '\x9A', /* உ à®’ ஓ à®± ஈ க à®™ ச */ + '\0', + '\xE0', '\xAE', '\x95', ' ', '\xE0', '\xAE', '\x9A', ' ', '\xE0', '\xAE', '\xB2', ' ', '\xE0', '\xAE', '\xB6', ' ', '\xE0', '\xAE', '\x89', ' ', '\xE0', '\xAE', '\x99', ' ', '\xE0', '\xAE', '\x9F', ' ', '\xE0', '\xAE', '\xAA', /* க ச ல à®¶ உ à®™ ட ப */ + '\0', + '\xE0', '\xB0', '\x87', ' ', '\xE0', '\xB0', '\x8C', ' ', '\xE0', '\xB0', '\x99', ' ', '\xE0', '\xB0', '\x9E', ' ', '\xE0', '\xB0', '\xA3', ' ', '\xE0', '\xB0', '\xB1', ' ', '\xE0', '\xB1', '\xAF', /* à°‡ à°Œ à°™ à°ž à°£ à°± ౯ */ + '\0', + '\xE0', '\xB0', '\x85', ' ', '\xE0', '\xB0', '\x95', ' ', '\xE0', '\xB0', '\x9A', ' ', '\xE0', '\xB0', '\xB0', ' ', '\xE0', '\xB0', '\xBD', ' ', '\xE0', '\xB1', '\xA8', ' ', '\xE0', '\xB1', '\xAC', /* à°… à°• à°š à°° à°½ ౨ ౬ */ + '\0', + '\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB9', '\x80', ' ', '\xE0', '\xB9', '\x81', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\x81', ' ', '\xE0', '\xB8', '\xB2', /* บ เ ๠อ ภา */ + '\0', + '\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\xA9', ' ', '\xE0', '\xB8', '\xAF', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\xA2', ' ', '\xE0', '\xB8', '\xAE', /* บ ป ษ ฯ อ ย ฮ */ + '\0', + '\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\x9D', ' ', '\xE0', '\xB8', '\x9F', /* ป ภฟ */ + '\0', + '\xE0', '\xB9', '\x82', ' ', '\xE0', '\xB9', '\x83', ' ', '\xE0', '\xB9', '\x84', /* โ ใ ไ */ + '\0', + '\xE0', '\xB8', '\x8E', ' ', '\xE0', '\xB8', '\x8F', ' ', '\xE0', '\xB8', '\xA4', ' ', '\xE0', '\xB8', '\xA6', /* ฎ ภฤ ฦ */ + '\0', + '\xE0', '\xB8', '\x8D', ' ', '\xE0', '\xB8', '\x90', /* ภภ*/ + '\0', + '\xE0', '\xB9', '\x90', ' ', '\xE0', '\xB9', '\x91', ' ', '\xE0', '\xB9', '\x93', /* ๠๑ ๓ */ + '\0', + '\xE2', '\xB5', '\x94', ' ', '\xE2', '\xB5', '\x99', ' ', '\xE2', '\xB5', '\x9B', ' ', '\xE2', '\xB5', '\x9E', ' ', '\xE2', '\xB4', '\xB5', ' ', '\xE2', '\xB4', '\xBC', ' ', '\xE2', '\xB4', '\xB9', ' ', '\xE2', '\xB5', '\x8E', /* âµ” âµ™ âµ› ⵞ â´µ â´¼ â´¹ ⵎ */ + '\0', + '\xEA', '\x97', '\x8D', ' ', '\xEA', '\x98', '\x96', ' ', '\xEA', '\x98', '\x99', ' ', '\xEA', '\x98', '\x9C', ' ', '\xEA', '\x96', '\x9C', ' ', '\xEA', '\x96', '\x9D', ' ', '\xEA', '\x94', '\x85', ' ', '\xEA', '\x95', '\xA2', /* ê— ê˜– ꘙ ꘜ ê–œ ê– ê”… ê•¢ */ + '\0', + '\xEA', '\x97', '\x8D', ' ', '\xEA', '\x98', '\x96', ' ', '\xEA', '\x98', '\x99', ' ', '\xEA', '\x97', '\x9E', ' ', '\xEA', '\x94', '\x85', ' ', '\xEA', '\x95', '\xA2', ' ', '\xEA', '\x96', '\x9C', ' ', '\xEA', '\x94', '\x86', /* ê— ê˜– ꘙ ê—ž ê”… ê•¢ ê–œ ꔆ */ +#ifdef AF_CONFIG_OPTION_CJK + '\0', + '\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0', /* ä»– 们 ä½  來 們 到 å’Œ 地 */ + ' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB8', '\xAD', ' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x83', /* 对 å° å°± 席 我 æ—¶ 時 會 */ + ' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\x88', '\xB0', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99', /* æ¥ ç‚º 能 舰 說 说 è¿™ 這 */ + ' ', '\xE9', '\xBD', '\x8A', ' ', '|', /* 齊 | */ + ' ', '\xE5', '\x86', '\x9B', ' ', '\xE5', '\x90', '\x8C', ' ', '\xE5', '\xB7', '\xB2', ' ', '\xE6', '\x84', '\xBF', ' ', '\xE6', '\x97', '\xA2', ' ', '\xE6', '\x98', '\x9F', ' ', '\xE6', '\x98', '\xAF', ' ', '\xE6', '\x99', '\xAF', /* 军 åŒ å·² æ„¿ æ—¢ 星 是 景 */ + ' ', '\xE6', '\xB0', '\x91', ' ', '\xE7', '\x85', '\xA7', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\xA8', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\xA6', '\x81', /* æ°‘ ç…§ 现 ç¾ ç† ç”¨ ç½® è¦ */ + ' ', '\xE8', '\xBB', '\x8D', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x85', '\x8D', ' ', '\xE9', '\x87', '\x8C', ' ', '\xE9', '\x96', '\x8B', ' ', '\xE9', '\x9B', '\xB7', ' ', '\xE9', '\x9C', '\xB2', ' ', '\xE9', '\x9D', '\xA2', /* è» é‚£ é… é‡Œ é–‹ é›· 露 é¢ */ + ' ', '\xE9', '\xA1', '\xBE', /* 顾 */ + '\0', + '\xE4', '\xB8', '\xAA', ' ', '\xE4', '\xB8', '\xBA', ' ', '\xE4', '\xBA', '\xBA', ' ', '\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xA5', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', /* 个 为 人 ä»– 以 们 ä½  來 */ + ' ', '\xE5', '\x80', '\x8B', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\xA4', '\xA7', ' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1', /* 個 們 到 å’Œ 大 对 å° å°± */ + ' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x89', ' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\xA6', '\x81', ' ', '\xE8', '\xAA', '\xAA', /* 我 æ—¶ 時 有 æ¥ ç‚º è¦ èªª */ + ' ', '\xE8', '\xAF', '\xB4', ' ', '|', /* 说 | */ + ' ', '\xE4', '\xB8', '\xBB', ' ', '\xE4', '\xBA', '\x9B', ' ', '\xE5', '\x9B', '\xA0', ' ', '\xE5', '\xAE', '\x83', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x84', '\x8F', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\x9F', /* 主 些 å›  它 想 æ„ ç† ç”Ÿ */ + ' ', '\xE7', '\x95', '\xB6', ' ', '\xE7', '\x9C', '\x8B', ' ', '\xE7', '\x9D', '\x80', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\x80', '\x85', ' ', '\xE8', '\x87', '\xAA', ' ', '\xE8', '\x91', '\x97', ' ', '\xE8', '\xA3', '\xA1', /* ç•¶ 看 ç€ ç½® 者 自 è‘— 裡 */ + ' ', '\xE8', '\xBF', '\x87', ' ', '\xE8', '\xBF', '\x98', ' ', '\xE8', '\xBF', '\x9B', ' ', '\xE9', '\x80', '\xB2', ' ', '\xE9', '\x81', '\x8E', ' ', '\xE9', '\x81', '\x93', ' ', '\xE9', '\x82', '\x84', ' ', '\xE9', '\x87', '\x8C', /* 过 还 è¿› 進 éŽ é“ é‚„ 里 */ + ' ', '\xE9', '\x9D', '\xA2', /* é¢ */ +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + '\0', + ' ', '\xE4', '\xBA', '\x9B', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0', /* 些 们 ä½  來 們 到 å’Œ 地 */ + ' ', '\xE5', '\xA5', '\xB9', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB9', '\xB4', ' ', '\xE5', '\xBE', '\x97', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x9C', '\x80', /* 她 å°† å°‡ å°± å¹´ å¾— 情 最 */ + ' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE7', '\x90', '\x86', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99', /* æ · 樣 ç† èƒ½ 說 说 è¿™ 這 */ + ' ', '\xE9', '\x80', '\x9A', ' ', '|', /* 通 | */ + ' ', '\xE5', '\x8D', '\xB3', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x90', '\xA7', ' ', '\xE5', '\x90', '\xAC', ' ', '\xE5', '\x91', '\xA2', ' ', '\xE5', '\x93', '\x81', ' ', '\xE5', '\x93', '\x8D', ' ', '\xE5', '\x97', '\x8E', /* å³ å— å§ å¬ å‘¢ å“ å“ å—Ž */ + ' ', '\xE5', '\xB8', '\x88', ' ', '\xE5', '\xB8', '\xAB', ' ', '\xE6', '\x94', '\xB6', ' ', '\xE6', '\x96', '\xAD', ' ', '\xE6', '\x96', '\xB7', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE7', '\x9C', '\xBC', ' ', '\xE9', '\x96', '\x93', /* 师 師 æ”¶ æ–­ æ–· 明 眼 é–“ */ + ' ', '\xE9', '\x97', '\xB4', ' ', '\xE9', '\x99', '\x85', ' ', '\xE9', '\x99', '\x88', ' ', '\xE9', '\x99', '\x90', ' ', '\xE9', '\x99', '\xA4', ' ', '\xE9', '\x99', '\xB3', ' ', '\xE9', '\x9A', '\x8F', ' ', '\xE9', '\x9A', '\x9B', /* é—´ é™… 陈 é™ é™¤ 陳 éš éš› */ + ' ', '\xE9', '\x9A', '\xA8', /* 隨 */ + '\0', + '\xE4', '\xBA', '\x8B', ' ', '\xE5', '\x89', '\x8D', ' ', '\xE5', '\xAD', '\xB8', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x88', '\x96', /* 事 å‰ å­¸ å°† å°‡ 情 想 或 */ + ' ', '\xE6', '\x94', '\xBF', ' ', '\xE6', '\x96', '\xAF', ' ', '\xE6', '\x96', '\xB0', ' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE6', '\xB0', '\x91', ' ', '\xE6', '\xB2', '\x92', ' ', '\xE6', '\xB2', '\xA1', /* 政 æ–¯ æ–° æ · 樣 æ°‘ æ²’ 没 */ + ' ', '\xE7', '\x84', '\xB6', ' ', '\xE7', '\x89', '\xB9', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x83', ' ', '\xE7', '\xAC', '\xAC', ' ', '\xE7', '\xB6', '\x93', ' ', '\xE8', '\xB0', '\x81', /* ç„¶ 特 现 ç¾ çƒ ç¬¬ ç¶“ è° */ + ' ', '\xE8', '\xB5', '\xB7', ' ', '|', /* èµ· | */ + ' ', '\xE4', '\xBE', '\x8B', ' ', '\xE5', '\x88', '\xA5', ' ', '\xE5', '\x88', '\xAB', ' ', '\xE5', '\x88', '\xB6', ' ', '\xE5', '\x8A', '\xA8', ' ', '\xE5', '\x8B', '\x95', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x97', '\x8E', /* 例 別 别 制 动 å‹• å— å—Ž */ + ' ', '\xE5', '\xA2', '\x9E', ' ', '\xE6', '\x8C', '\x87', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE6', '\x9C', '\x9D', ' ', '\xE6', '\x9C', '\x9F', ' ', '\xE6', '\x9E', '\x84', ' ', '\xE7', '\x89', '\xA9', ' ', '\xE7', '\xA1', '\xAE', /* 增 指 明 æœ æœŸ æž„ 物 ç¡® */ + ' ', '\xE7', '\xA7', '\x8D', ' ', '\xE8', '\xAA', '\xBF', ' ', '\xE8', '\xB0', '\x83', ' ', '\xE8', '\xB2', '\xBB', ' ', '\xE8', '\xB4', '\xB9', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x83', '\xBD', ' ', '\xE9', '\x96', '\x93', /* ç§ èª¿ è°ƒ è²» è´¹ é‚£ 都 é–“ */ + ' ', '\xE9', '\x97', '\xB4', /* é—´ */ +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ +#endif /* AF_CONFIG_OPTION_CJK */ + '\0', + + }; + + + /* stringsets are specific to styles */ + FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec ) + af_blue_stringsets[] = + { + /* */ + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARABIC_BOTTOM, 0 }, + { AF_BLUE_STRING_ARABIC_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_AVESTAN_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_BAMUM_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BAMUM_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_BENGALI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BENGALI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BENGALI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_BENGALI_BASE, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_BUHID_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BUHID_LARGE, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BUHID_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_BUHID_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CHAKMA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CHAKMA_BOTTOM, 0 }, + { AF_BLUE_STRING_CHAKMA_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CARIAN_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CHEROKEE_CAPITAL, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CHEROKEE_CAPITAL, 0 }, + { AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CHEROKEE_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CHEROKEE_SMALL, 0 }, + { AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYPRIOT_BOTTOM, 0 }, + { AF_BLUE_STRING_CYPRIOT_SMALL, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYPRIOT_SMALL, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DEVANAGARI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DEVANAGARI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_DEVANAGARI_BASE, 0 }, + { AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM, 0 }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER, 0 }, + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM, 0 }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM, 0 }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GOTHIC_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GREEK_SMALL, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GUJARATI_BOTTOM, 0 }, + { AF_BLUE_STRING_GUJARATI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GUJARATI_DESCENDER, 0 }, + { AF_BLUE_STRING_GUJARATI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GURMUKHI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GURMUKHI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GURMUKHI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GURMUKHI_BOTTOM, 0 }, + { AF_BLUE_STRING_GURMUKHI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_LONG }, + { AF_BLUE_STRING_HEBREW_BOTTOM, 0 }, + { AF_BLUE_STRING_HEBREW_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_KANNADA_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KAYAH_LI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_KAYAH_LI_BOTTOM, 0 }, + { AF_BLUE_STRING_KAYAH_LI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_KAYAH_LI_DESCENDER, 0 }, + { AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KHMER_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP, AF_BLUE_PROPERTY_LATIN_SUB_TOP }, + { AF_BLUE_STRING_KHMER_BOTTOM, 0 }, + { AF_BLUE_STRING_KHMER_DESCENDER, 0 }, + { AF_BLUE_STRING_KHMER_LARGE_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LAO_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LAO_BOTTOM, 0 }, + { AF_BLUE_STRING_LAO_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LAO_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LISU_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MALAYALAM_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MYANMAR_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_MYANMAR_BOTTOM, 0 }, + { AF_BLUE_STRING_MYANMAR_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MYANMAR_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_NKO_BOTTOM, 0 }, + { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OL_CHIKI, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OLD_TURKIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 }, + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSMANYA_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ROHINGYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ROHINGYA_BOTTOM, 0 }, + { AF_BLUE_STRING_ROHINGYA_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 }, + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 }, + { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SINHALA_BOTTOM, 0 }, + { AF_BLUE_STRING_SINHALA_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SUNDANESE_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SUNDANESE_BOTTOM, 0 }, + { AF_BLUE_STRING_SUNDANESE_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TAMIL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TAMIL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TAI_VIET_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TAI_VIET_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TELUGU_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TELUGU_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_THAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_THAI_BOTTOM, 0 }, + { AF_BLUE_STRING_THAI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_THAI_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_THAI_DESCENDER, 0 }, + { AF_BLUE_STRING_THAI_LARGE_DESCENDER, 0 }, + { AF_BLUE_STRING_THAI_DIGIT_TOP, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TIFINAGH, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_VAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_VAI_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, +#ifdef AF_CONFIG_OPTION_CJK + { AF_BLUE_STRING_CJK_TOP, AF_BLUE_PROPERTY_CJK_TOP }, + { AF_BLUE_STRING_CJK_BOTTOM, 0 }, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + { AF_BLUE_STRING_CJK_LEFT, AF_BLUE_PROPERTY_CJK_HORIZ }, + { AF_BLUE_STRING_CJK_RIGHT, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT }, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + { AF_BLUE_STRING_MAX, 0 }, +#endif /* AF_CONFIG_OPTION_CJK */ + + }; + + +/* END */ diff --git a/vendor/freetype/src/autofit/afblue.cin b/vendor/freetype/src/autofit/afblue.cin new file mode 100644 index 0000000..d561c50 --- /dev/null +++ b/vendor/freetype/src/autofit/afblue.cin @@ -0,0 +1,39 @@ +/**************************************************************************** + * + * afblue.c + * + * Auto-fitter data for blue strings (body). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "aftypes.h" + + + FT_LOCAL_ARRAY_DEF( char ) + af_blue_strings[] = + { + /* */ +@AF_BLUE_STRINGS_ARRAY@ + }; + + + /* stringsets are specific to styles */ + FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec ) + af_blue_stringsets[] = + { + /* */ +@AF_BLUE_STRINGSETS_ARRAY@ + }; + + +/* END */ diff --git a/vendor/freetype/src/autofit/afblue.dat b/vendor/freetype/src/autofit/afblue.dat new file mode 100644 index 0000000..8299baa --- /dev/null +++ b/vendor/freetype/src/autofit/afblue.dat @@ -0,0 +1,1121 @@ +// afblue.dat +// +// Auto-fitter data for blue strings. +// +// Copyright (C) 2013-2023 by +// David Turner, Robert Wilhelm, and Werner Lemberg. +// +// This file is part of the FreeType project, and may only be used, +// modified, and distributed under the terms of the FreeType project +// license, LICENSE.TXT. By continuing to use, modify, or distribute +// this file you indicate that you have read the license and +// understand and accept it fully. + + +// This file contains data specific to blue zones. It gets processed by +// a script to simulate `jagged arrays', with enumeration values holding +// offsets into the arrays. +// +// The format of the file is rather simple: A section starts with three +// labels separated by whitespace and followed by a colon (everything in a +// single line); the first label gives the name of the enumeration template, +// the second the name of the array template, and the third the name of the +// `maximum' template. The script then fills the corresponding templates +// (indicated by `@' characters around the name). +// +// A section contains one or more data records. Each data record consists +// of two or more lines. The first line holds the enumeration name, and the +// remaining lines the corresponding array data. +// +// There are two possible representations for array data. +// +// - A string of characters or character clusters (for example, representing +// Aksharas, Devanagari syllables) in UTF-8 encoding enclosed in double +// quotes, using C syntax, where the elements are separated by spaces. +// There can be only one string per line, thus the starting and ending +// double quote must be the first and last character in the line, +// respectively, ignoring whitespace before and after the string. If +// there are multiple strings (in multiple lines), they are concatenated +// to a single string. In the output, a string gets represented as a +// series of singles bytes, followed by a zero byte. The enumeration +// values simply hold byte offsets to the start of the corresponding +// strings. +// +// For strings, the `maximum' template holds the maximum number of +// non-space characters in all strings. +// +// - Data blocks enclosed in balanced braces, which get copied verbatim and +// which can span multiple lines. The opening brace of a block must be +// the first character of a line (ignoring whitespace), and the closing +// brace the last (ignoring whitespace also). The script appends a comma +// character after each block and counts the number of blocks to set the +// enumeration values. +// +// For data blocks, the `maximum' template holds the maximum number of +// array elements. +// +// A section can contain either strings only or data blocks only. +// +// A comment line starts with `//'; it gets removed. A preprocessor +// directive line (using the standard syntax of `cpp') starts with `#' and +// gets copied verbatim to both the enumeration and the array. Whitespace +// outside of a string is insignificant. +// +// Preprocessor directives are ignored while the script computes maximum +// values; this essentially means that the maximum values can easily be too +// large. Given that the purpose of those values is to create local +// fixed-size arrays at compile time for further processing of the blue zone +// data, this isn't a problem. Note the final zero byte of a string is not +// counted. Note also that the count holds the number of UTF-8 encoded +// characters, not bytes. + + +// The blue zone string data, to be used in the blue stringsets below. + +AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: + + AF_BLUE_STRING_ADLAM_CAPITAL_TOP + "𞤌 𞤅 𞤈 𞤠𞤔 𞤚" + AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM + "𞤂 𞤖" + AF_BLUE_STRING_ADLAM_SMALL_TOP + "𞤬 𞤮 𞤻 𞤼 𞤾" + AF_BLUE_STRING_ADLAM_SMALL_BOTTOM + "𞤤 𞤨 𞤩 𞤭 𞤴 𞤸 𞤺 𞥀" + + AF_BLUE_STRING_ARABIC_TOP + "ا Ø¥ Ù„ Ùƒ Ø· ظ" + AF_BLUE_STRING_ARABIC_BOTTOM + "ت Ø« Ø· ظ Ùƒ" + // We don't necessarily have access to medial forms via Unicode in case + // Arabic presentational forms are missing. The only character that is + // guaranteed to have the same vertical position with joining (that is, + // non-isolated) forms is U+0640, ARABIC TATWEEL, which must join both + // round and flat curves. + AF_BLUE_STRING_ARABIC_JOIN + "Ù€" + + AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP + "Ô± Õ„ Õ’ Õ Ô² Ô³ Ô´ Õ•" + AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM + "Õ’ Õˆ Ô´ Õƒ Õ‡ Õ Õ Õ•" + AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER + "Õ¥ Õ§ Õ« Õ´ Õ¾ Ö† Õ³" + AF_BLUE_STRING_ARMENIAN_SMALL_TOP + "Õ¡ Õµ Ö‚ Õ½ Õ£ Õ· Ö€ Ö…" + AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM + "Õ° Õ¸ Õ³ Õ¡ Õ¥ Õ® Õ½ Ö…" + AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER + "Õ¢ Õ¨ Õ« Õ¬ Õ² Õº Öƒ Ö" + + AF_BLUE_STRING_AVESTAN_TOP + "𬀠ð¬ ð¬ ð¬›" + AF_BLUE_STRING_AVESTAN_BOTTOM + "𬀠ð¬" + + AF_BLUE_STRING_BAMUM_TOP + "êš§ ꚨ ê›› ꛉ ê› ê›ˆ ꛫ ꛯ" + AF_BLUE_STRING_BAMUM_BOTTOM + "êš­ êš³ êš¶ ꛬ ꚢ êš½ ꛯ ꛲" + + AF_BLUE_STRING_BENGALI_BASE + "অ ড ত ন ব ভ ল ক" + AF_BLUE_STRING_BENGALI_TOP + "ই ট ঠ ি à§€ ৈ à§—" + AF_BLUE_STRING_BENGALI_HEAD + "ও ঠড ত ন ব ল ক" + + AF_BLUE_STRING_BUHID_TOP + "á áˆ" + AF_BLUE_STRING_BUHID_LARGE + "á… áŠ áŽ" + AF_BLUE_STRING_BUHID_SMALL + "ႠრበáŒ" + AF_BLUE_STRING_BUHID_BOTTOM + "ဠრᆠበዠá á‘" + + AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP + "á—œ á–´ á á’£ á‘« ᑎ ᔑ á—°" + AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM + "á—¶ á–µ á’§ რᑌ ᒠᔑ á—¢" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP + "á““ á“• á“€ á“‚ á“„ á•„ ᕆ ᘣ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM + "ᕃ á“‚ á“€ á•‚ á“— ᓚ ᕆ ᘣ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP + "᪠ᙆ ᣘ ᢠᒾ ᣗ ᔆ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM + "ᙆ á—® á’» ហᔆ á’¡ á’¢ á“‘" + + AF_BLUE_STRING_CARIAN_TOP + "ðŠ§ ðŠ« ðŠ¬ ðŠ­ ðŠ± ðŠº ðŠ¼ ðŠ¿" + AF_BLUE_STRING_CARIAN_BOTTOM + "ðŠ£ ðŠ§ ðŠ· ð‹€ ðŠ« ðŠ¸ ð‹‰" + + AF_BLUE_STRING_CHAKMA_TOP + "𑄃 ð‘„… 𑄉 ð‘„™ ð‘„—" + AF_BLUE_STRING_CHAKMA_BOTTOM + "ð‘„… ð‘„› ð‘„ ð‘„— ð‘„“" + AF_BLUE_STRING_CHAKMA_DESCENDER + "𑄖𑄳𑄢 𑄘𑄳𑄢 𑄙𑄳𑄢 𑄤𑄳𑄢 𑄥𑄳𑄢" + + AF_BLUE_STRING_CHEROKEE_CAPITAL + "ᆠᎻ Ꭼ რᎤ ᣠᎦ á•" + AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER + "ê®’ ꮤ ê®¶ ê­´ ê­¾ ê®— ê® ê®¿" + AF_BLUE_STRING_CHEROKEE_SMALL + "ê®– ê­¼ ꮓ ê®  ꮳ ê­¶ ꮥ ê®»" + AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER + "á¸ ê® ê­¹ ê­»" + + AF_BLUE_STRING_COPTIC_CAPITAL_TOP + "Ⲍ Ⲏ â²  Ⳟ Ⲟ ⲠⲤ Ⳋ" + AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM + "ⳠⳘ Ⳟ Ⲏ Ⲟ ⲠⳜ â²°" + AF_BLUE_STRING_COPTIC_SMALL_TOP + "ⲠⲠⲡ ⳟ ⲟ ⲑ â²¥ ⳋ" + AF_BLUE_STRING_COPTIC_SMALL_BOTTOM + "ⳑ â³™ ⳟ Ⲡⲟ ⲑ â³ â³’" + + AF_BLUE_STRING_CYPRIOT_TOP + "ð  ð ™ ð ³ ð ± ð … ð “ ð £ ð ¦" + AF_BLUE_STRING_CYPRIOT_BOTTOM + "ð ƒ ð Š ð › ð £ ð ³ ð µ ð " + AF_BLUE_STRING_CYPRIOT_SMALL + "ð ˆ ð  ð –" + + AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP + "Б Ð’ Е П З О С Э" + AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM + "Б Ð’ Е Ш З О С Э" + AF_BLUE_STRING_CYRILLIC_SMALL + "Ñ… п н ш е з о Ñ" + AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER + "Ñ€ у Ñ„" + + AF_BLUE_STRING_DESERET_CAPITAL_TOP + "ð‚ ð„ ð‹ ð— ð‘" + AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM + "ð€ ð‚ ð„ ð— ð›" + AF_BLUE_STRING_DESERET_SMALL_TOP + "ðª ð¬ ð³ ð¿ ð¹" + AF_BLUE_STRING_DESERET_SMALL_BOTTOM + "ð¨ ðª ð¬ ð¿ ð‘ƒ" + + AF_BLUE_STRING_DEVANAGARI_BASE + "क न म उ छ ट ठ ड" + AF_BLUE_STRING_DEVANAGARI_TOP + "ई ठओ औ ि ी ो ौ" + // note that some fonts have extreme variation in the height of the + // round head elements; for this reason we also define the `base' + // blue zone, which must be always present + AF_BLUE_STRING_DEVANAGARI_HEAD + "क म अ आ थ ध भ श" + AF_BLUE_STRING_DEVANAGARI_BOTTOM + "ॠृ" + + AF_BLUE_STRING_ETHIOPIC_TOP + "ሀ ሃ ዘ á ማ በ á‹‹ á‹" + AF_BLUE_STRING_ETHIOPIC_BOTTOM + "ለ ሠበ ዘ ሀ ሪ ዠጨ" + + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP + "გ დ ე ვ თ ი რღ" + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM + "რზ მ ს შ ძ ხ პ" + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER + "ს ხ ქ ზ მ შ ჩ წ" + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER + "ე ვ ჟ ტ უ ფ ქ ყ" + + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP + "Ⴑ á‚§ Ⴙ Ⴜ Ⴄ á‚¥ Ⴓ Ⴚ" + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM + "Ⴄ á‚¥ á‚§ Ⴈ Ⴆ Ⴑ Ⴊ á‚«" + + AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP + "â´ â´— â´‚ â´„ â´… â´‡ â´” â´–" + AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM + "â´ˆ â´Œ â´– â´Ž â´ƒ â´† â´‹ â´¢" + AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER + "â´ â´‘ â´“ â´• â´™ â´› â´¡ â´£" + AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER + "â´„ â´… â´” â´• â´ â´‚ â´˜ â´" + + AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP + "Ნ Ჟ á²³ Ჸ á²’ á²” á² á²´" + AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM + "Ი á²² ᲠᲩ á²› Შ Ჯ á²½" + + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP + "â°… â°” â°ª â°„ â°‚ â°Š â°« â°‹" + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM + "â°… â°„ â°‚ â°ª â°ž â°¡ â°Š â°”" + AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP + "â°µ ⱄ ⱚ â°´ â°² â°º â±› â°»" + AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM + "â°µ â°´ â°² ⱚ ⱎ ⱑ â°º ⱄ" + + AF_BLUE_STRING_GOTHIC_TOP + "ðŒ² ðŒ¶ ð€ ð„ ðŒ´ ðƒ ðˆ ðŒ¾" + AF_BLUE_STRING_GOTHIC_BOTTOM + "ðŒ¶ ðŒ´ ðƒ ðˆ" + + AF_BLUE_STRING_GREEK_CAPITAL_TOP + "Γ Î’ Ε Ζ Θ Ο Ω" + AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM + "Î’ Δ Ζ Ξ Θ Ο" + AF_BLUE_STRING_GREEK_SMALL_BETA_TOP + "β θ δ ζ λ ξ" + AF_BLUE_STRING_GREEK_SMALL + "α ε ι ο Ï€ σ Ï„ ω" + AF_BLUE_STRING_GREEK_SMALL_DESCENDER + "β γ η μ Ï Ï† χ ψ" + + AF_BLUE_STRING_GUJARATI_TOP + "ત ન ઋ ઌ છ ટ ર ૦" + AF_BLUE_STRING_GUJARATI_BOTTOM + "ખ ગ ઘ ઞ ઇ ઈ ઠ જ" + AF_BLUE_STRING_GUJARATI_ASCENDER + "ઈ ઊ િ à«€ લી શà«àªšàª¿ જિ સી" + AF_BLUE_STRING_GUJARATI_DESCENDER + "ૠૃ à«„ ખૠછૃ છૄ" + AF_BLUE_STRING_GUJARATI_DIGIT_TOP + "૦ à«§ ૨ à«© à«­" + + AF_BLUE_STRING_GURMUKHI_BASE + "ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ" + AF_BLUE_STRING_GURMUKHI_HEAD + "ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ" + AF_BLUE_STRING_GURMUKHI_TOP + "ਇ ਈ ਉ ਠਓ ੳ ਿ à©€" + AF_BLUE_STRING_GURMUKHI_BOTTOM + "ਅ ਠਓ ਗ ਜ ਠ ਰ ਸ" + AF_BLUE_STRING_GURMUKHI_DIGIT_TOP + "੦ à©§ ੨ à©© à©­" + + AF_BLUE_STRING_HEBREW_TOP + "ב ד ×” ×— ך ×› × ×¡" + AF_BLUE_STRING_HEBREW_BOTTOM + "ב ט ×› × ×¡ צ" + AF_BLUE_STRING_HEBREW_DESCENDER + "×§ ך ן ×£ ×¥" + + AF_BLUE_STRING_KANNADA_TOP + "ಇ ಊ ಠಣ ಸಾ ನಾ ದಾ ರಾ" + AF_BLUE_STRING_KANNADA_BOTTOM + "ಅ ಉ ಎ ಲ ೦ ೨ ೬ à³­" + + AF_BLUE_STRING_KAYAH_LI_TOP + "꤅ ê¤ ê¤ ê¤‹ ꤀ ê¤" + AF_BLUE_STRING_KAYAH_LI_BOTTOM + "꤈ ꤘ ꤀ ê¤ ê¤¢" + AF_BLUE_STRING_KAYAH_LI_ASCENDER + "ꤖ ꤡ" + AF_BLUE_STRING_KAYAH_LI_DESCENDER + "ꤑ ꤜ ꤞ" + AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER + "ꤑ꤬ ꤜ꤭ ꤔ꤬" + + AF_BLUE_STRING_KHMER_TOP + "áž áž‘ áž“ áž§ áž© áž¶" + AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP + "ក្ក ក្ហក្គ ក្áž" + AF_BLUE_STRING_KHMER_BOTTOM + "ហឃ áž… áž‹ áž” ម áž™ áž²" + AF_BLUE_STRING_KHMER_DESCENDER + "ážáŸ’ážš រៀ ឲ្យ អឿ" + AF_BLUE_STRING_KHMER_LARGE_DESCENDER + "ន្ážáŸ’រៃ ង្ážáŸ’áž™ ក្បៀ ច្រៀ ន្ážáž¿ ល្បឿ" + + AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP + "á§  á§¡" + AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM + "á§¶ á§¹" + + AF_BLUE_STRING_LAO_TOP + "າ ດ ອ ມ ລ ວ ຣ ງ" + AF_BLUE_STRING_LAO_BOTTOM + "າ ອ ບ ຠຣ ຮ ວ ຢ" + AF_BLUE_STRING_LAO_ASCENDER + "ປ ຢ ຟ àº" + AF_BLUE_STRING_LAO_LARGE_ASCENDER + "ໂ ໄ ໃ" + AF_BLUE_STRING_LAO_DESCENDER + "ງ ຊ ຖ ຽ ໆ ຯ" + + AF_BLUE_STRING_LATIN_CAPITAL_TOP + "T H E Z O C Q S" + AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM + "H E Z L O C U S" + AF_BLUE_STRING_LATIN_SMALL_F_TOP + "f i j k d b h" + AF_BLUE_STRING_LATIN_SMALL_TOP + "u v x z o e s c" + AF_BLUE_STRING_LATIN_SMALL_BOTTOM + "n r x z o e s c" + AF_BLUE_STRING_LATIN_SMALL_DESCENDER + "p q g j y" + + // we assume that both the subscript and superscript ranges + // don't contain oldstyle digits (actually, most fonts probably + // have digits only in those ranges) + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP + "â‚€ ₃ â‚… ₇ ₈" + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM + "â‚€ â‚ â‚‚ ₃ ₈" + AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP + "áµ¢ â±¼ â‚• â‚– â‚—" + AF_BLUE_STRING_LATIN_SUBS_SMALL + "â‚ â‚‘ â‚’ â‚“ â‚™ â‚› áµ¥ ᵤ áµ£" + AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER + "ᵦ áµ§ ᵨ ᵩ ₚ" + + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP + "Ⱐ³ âµ â· áµ€ á´´ á´± á´¼" + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM + "Ⱐ¹ ² ³ á´± á´¸ á´¼ áµ" + AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP + "ᵇ ᵈ ᵠʰ ʲ á¶  â±" + AF_BLUE_STRING_LATIN_SUPS_SMALL + "ᵉ áµ’ ʳ Ë¢ Ë£ á¶œ á¶»" + AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER + "áµ– ʸ áµ" + + AF_BLUE_STRING_LISU_TOP + "ê“¡ ê“§ ꓱ ê“¶ ê“© ꓚ ꓵ ꓳ" + AF_BLUE_STRING_LISU_BOTTOM + "ê“• ꓜ ꓞ ê“¡ ê“› ê“¢ ꓳ ê“´" + + AF_BLUE_STRING_MALAYALAM_TOP + "à´’ à´Ÿ à´  à´± à´š à´ª à´šàµà´š à´ªàµà´ª" + AF_BLUE_STRING_MALAYALAM_BOTTOM + "à´Ÿ à´  à´§ à´¶ à´˜ à´š à´¥ à´²" + + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP + "ð–¹€ 𖹠𖹂 𖹃 𖹠𖹚 𖹟" + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM + "ð–¹€ 𖹠𖹂 𖹃 𖹠𖹚 ð–¹’ 𖹓" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP + "𖹤 𖹬 ð–¹§ ð–¹´ ð–¹¶ ð–¹¾" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP + "ð–¹  𖹡 ð–¹¢ ð–¹¹ ð–¹³ ð–¹®" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM + "ð–¹  𖹡 ð–¹¢ ð–¹³ ð–¹­ ð–¹½" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER + "ð–¹¥ 𖹨 𖹩" + AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP + "𖺀 ð–º… 𖺈 𖺄 ð–º" + + AF_BLUE_STRING_MONGOLIAN_TOP_BASE + "á ³ á ´ á ¶ á ½ á¡‚ ᡊ â€á¡¡â€ â€á¡³â€" + AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE + "ᡃ" + + AF_BLUE_STRING_MYANMAR_TOP + "ဠဂ င ဒ ဠᥠአá‹" + AF_BLUE_STRING_MYANMAR_BOTTOM + "င ဎ ဒ ပ ဗ ဠአá‹" + AF_BLUE_STRING_MYANMAR_ASCENDER + "ဩ ြ á á ᆠါ ိ" + AF_BLUE_STRING_MYANMAR_DESCENDER + "ဉ ည ဥ ဩ ဨ á‚ á… á‰" + + AF_BLUE_STRING_NKO_TOP + "ß ß‰ ß’ ߟ ß– ßœ ß  ߥ" + AF_BLUE_STRING_NKO_BOTTOM + "߀ ߘ ß¡ ß  ߥ" + AF_BLUE_STRING_NKO_SMALL_TOP + "ß ß› ß‹" + AF_BLUE_STRING_NKO_SMALL_BOTTOM + "ߎ ß ß› ß‹" + + AF_BLUE_STRING_OL_CHIKI + "á±› ᱜ ᱠᱡ á±¢ á±¥" + + AF_BLUE_STRING_OLD_TURKIC_TOP + "ð°— ð°˜ ð°§" + AF_BLUE_STRING_OLD_TURKIC_BOTTOM + "ð°‰ ð°— ð°¦ ð°§" + + AF_BLUE_STRING_OSAGE_CAPITAL_TOP + "ð’¾ ð“ ð“’ ð““ ð’» ð“‚ ð’µ ð“†" + AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM + "ð’° ð“ 𓂠𒿠𓎠ð’¹" + AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER + "ð’¼ ð’½ ð’¾" + AF_BLUE_STRING_OSAGE_SMALL_TOP + "𓵠𓶠𓺠𓻠ð“ 𓣠𓪠ð“®" + AF_BLUE_STRING_OSAGE_SMALL_BOTTOM + "𓘠𓚠𓣠𓵠𓡠𓧠𓪠ð“¶" + AF_BLUE_STRING_OSAGE_SMALL_ASCENDER + "𓤠𓦠𓸠𓹠ð“›" + AF_BLUE_STRING_OSAGE_SMALL_DESCENDER + "𓤠𓥠ð“¦" + + AF_BLUE_STRING_OSMANYA_TOP + "ð’† ð’‰ ð’ ð’’ ð’˜ ð’› ð’  ð’£" + AF_BLUE_STRING_OSMANYA_BOTTOM + "ð’€ ð’‚ ð’† ð’ˆ ð’Š ð’’ ð’  ð’©" + + AF_BLUE_STRING_ROHINGYA_TOP + "ð´ƒ ð´€ ð´† ð´– ð´•" + AF_BLUE_STRING_ROHINGYA_BOTTOM + "ð´” ð´– ð´• ð´‘ ð´" + AF_BLUE_STRING_ROHINGYA_JOIN + "Ù€" + + AF_BLUE_STRING_SAURASHTRA_TOP + "ꢜ ꢞ ꢳ ꢂ ꢖ ꢒ ê¢ ê¢›" + AF_BLUE_STRING_SAURASHTRA_BOTTOM + "ꢂ ꢨ ꢺ ꢤ ꢎ" + + AF_BLUE_STRING_SHAVIAN_TOP + "ð‘• ð‘™" + AF_BLUE_STRING_SHAVIAN_BOTTOM + "𑔠𑖠𑗠𑹠ð‘»" + AF_BLUE_STRING_SHAVIAN_DESCENDER + "𑟠ð‘£" + AF_BLUE_STRING_SHAVIAN_SMALL_TOP + "𑱠𑲠𑳠𑴠𑸠𑺠ð‘¼" + AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM + "ð‘´ ð‘» ð‘¹" + + AF_BLUE_STRING_SINHALA_TOP + "ඉ à¶š à¶ à¶³ à¶´ ය à¶½ à·†" + AF_BLUE_STRING_SINHALA_BOTTOM + "à¶‘ à¶” à¶ à¶¢ à¶§ à¶® à¶° à¶»" + AF_BLUE_STRING_SINHALA_DESCENDER + "ද à¶³ à¶‹ à¶½ à¶­à·– à¶­à·” à¶¶à·” දු" + + AF_BLUE_STRING_SUNDANESE_TOP + "ᮋ ᮞ á®® ᮽ á®° ᮈ" + AF_BLUE_STRING_SUNDANESE_BOTTOM + "ᮄ á®” ᮕ á®— á®° ᮆ ᮈ ᮉ" + AF_BLUE_STRING_SUNDANESE_DESCENDER + "ᮼ ᳄" + + AF_BLUE_STRING_TAI_VIET_TOP + "ꪆ ꪔ ꪒ ꪖ ꪫ" + AF_BLUE_STRING_TAI_VIET_BOTTOM + "ꪉ ꪫ ꪮ" + + AF_BLUE_STRING_TAMIL_TOP + "உ à®’ ஓ à®± ஈ க à®™ ச" + AF_BLUE_STRING_TAMIL_BOTTOM + "க ச ல à®¶ உ à®™ ட ப" + + AF_BLUE_STRING_TELUGU_TOP + "à°‡ à°Œ à°™ à°ž à°£ à°± ౯" + AF_BLUE_STRING_TELUGU_BOTTOM + "à°… à°• à°š à°° à°½ ౨ ౬" + + AF_BLUE_STRING_THAI_TOP + "บ เ ๠อ ภา" + AF_BLUE_STRING_THAI_BOTTOM + "บ ป ษ ฯ อ ย ฮ" + AF_BLUE_STRING_THAI_ASCENDER + "ป ภฟ" + AF_BLUE_STRING_THAI_LARGE_ASCENDER + "โ ใ ไ" + AF_BLUE_STRING_THAI_DESCENDER + "ฎ ภฤ ฦ" + AF_BLUE_STRING_THAI_LARGE_DESCENDER + "ภà¸" + AF_BLUE_STRING_THAI_DIGIT_TOP + "๠๑ ๓" + + AF_BLUE_STRING_TIFINAGH + "âµ” âµ™ âµ› ⵞ â´µ â´¼ â´¹ ⵎ" + + AF_BLUE_STRING_VAI_TOP + "ê— ê˜– ꘙ ꘜ ê–œ ê– ê”… ê•¢" + AF_BLUE_STRING_VAI_BOTTOM + "ê— ê˜– ꘙ ê—ž ê”… ê•¢ ê–œ ꔆ" + + +#ifdef AF_CONFIG_OPTION_CJK + + AF_BLUE_STRING_CJK_TOP + "ä»– 们 ä½  來 們 到 å’Œ 地" + " 对 å° å°± 席 我 æ—¶ 時 會" + " æ¥ ç‚º 能 舰 說 说 è¿™ 這" + " 齊 |" + " 军 åŒ å·² æ„¿ æ—¢ 星 是 景" + " æ°‘ ç…§ 现 ç¾ ç† ç”¨ ç½® è¦" + " è» é‚£ é… é‡Œ é–‹ é›· 露 é¢" + " 顾" + AF_BLUE_STRING_CJK_BOTTOM + "个 为 人 ä»– 以 们 ä½  來" + " 個 們 到 å’Œ 大 对 å° å°±" + " 我 æ—¶ 時 有 æ¥ ç‚º è¦ èªª" + " 说 |" + " 主 些 å›  它 想 æ„ ç† ç”Ÿ" + " ç•¶ 看 ç€ ç½® 者 自 è‘— 裡" + " 过 还 è¿› 進 éŽ é“ é‚„ 里" + " é¢" + +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + + AF_BLUE_STRING_CJK_LEFT + " 些 们 ä½  來 們 到 å’Œ 地" + " 她 å°† å°‡ å°± å¹´ å¾— 情 最" + " æ · 樣 ç† èƒ½ 說 说 è¿™ 這" + " 通 |" + " å³ å— å§ å¬ å‘¢ å“ å“ å—Ž" + " 师 師 æ”¶ æ–­ æ–· 明 眼 é–“" + " é—´ é™… 陈 é™ é™¤ 陳 éš éš›" + " 隨" + AF_BLUE_STRING_CJK_RIGHT + "事 å‰ å­¸ å°† å°‡ 情 想 或" + " 政 æ–¯ æ–° æ · 樣 æ°‘ æ²’ 没" + " ç„¶ 特 现 ç¾ çƒ ç¬¬ ç¶“ è°" + " èµ· |" + " 例 別 别 制 动 å‹• å— å—Ž" + " 增 指 明 æœ æœŸ æž„ 物 ç¡®" + " ç§ èª¿ è°ƒ è²» è´¹ é‚£ 都 é–“" + " é—´" + +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + +#endif /* AF_CONFIG_OPTION_CJK */ + + +// The blue zone stringsets, as used in the script styles, cf. `afstyles.h'. +// +// The AF_BLUE_PROPERTY_XXX flags are defined in `afblue.h'; here some +// explanations. +// +// A blue zone in general is defined by a reference and an overshoot line. +// During the hinting process, all coordinate values between those two lines +// are set equal to the reference value, provided that the blue zone is not +// wider than 0.75 pixels (otherwise the blue zone gets ignored). All +// entries must have `AF_BLUE_STRING_MAX' as the final line. +// +// During the glyph analysis, edges are sorted from bottom to top, and then +// sequentially checked, edge by edge, against the blue zones in the order +// given below. +// +// +// latin auto-hinter +// ----------------- +// +// Characters in a blue string are automatically classified as having a flat +// (reference) or a round (overshoot) extremum. The blue zone is then set +// up by the mean values of all flat extrema and all round extrema, +// respectively. Only horizontal blue zones (i.e., adjusting vertical +// coordinate values) are supported. +// +// Some scripts like Khmer need character composition to get all necessary +// blue zones, since Unicode only provides an abstract data model that +// doesn't represent all possible glyph shapes. For such character +// clusters, the HarfBuzz library is used to convert them into the +// corresponding glyphs. The largest glyph element (where `largest' can be +// either `largest ascender' or `largest descender') then defines the +// corresponding flat or round extremum. +// +// For the latin auto-hinter, the overshoot should be larger than the +// reference for top zones, and vice versa for bottom zones. +// +// LATIN_TOP +// Take the maximum flat and round coordinate values of the blue string +// characters for computing the blue zone's reference and overshoot +// values. +// +// If not set, take the minimum values. +// +// Mutually exclusive with `LATIN_SUB_TOP'. +// +// LATIN_SUB_TOP +// For all glyphs of a character cluster, compute the maximum flat +// and round coordinate values of each component, then take the +// smallest of the maximum values. The idea is to get the top of +// subscript glyphs, as used in Khmer, for example. Note that +// this mechanism doesn't work for ordinary ligatures. +// +// This flags indicates a secondary blue zone: It gets removed if +// there is a non-LATIN_SUB_TOP blue zone at the same coordinate +// value (after scaling). +// +// Mutually exclusive with `LATIN_TOP'. +// +// LATIN_NEUTRAL +// Ignore round extrema and define the blue zone with flat values only. +// Both top and bottom of contours can match. This is useful for +// scripts like Devanagari where vowel signs attach to the base +// character and are implemented as components of composite glyphs. +// +// If not set, both round and flat extrema are taken into account. +// Additionally, only the top or the bottom of a contour can match, +// depending on the LATIN_TOP flag. +// +// Neutral blue zones should always follow non-neutral blue zones. +// +// LATIN_X_HEIGHT +// Scale all glyphs vertically from the corresponding script to make the +// reference line of this blue zone align on the grid. The scaling +// takes place before all other blue zones get aligned to the grid. +// Only one blue character string of a script style can have this flag. +// +// LATIN_LONG +// Apply an additional constraint for blue zone values: Don't +// necessarily use the extremum as-is but a segment of the topmost (or +// bottommost) contour that is longer than a heuristic threshold, and +// which is not too far away vertically from the real extremum. This +// ensures that small bumps in the outline are ignored (for example, the +// `vertical serifs' found in many Hebrew glyph designs). +// +// The segment must be at least EM/25 font units long, and the distance +// to the extremum must be smaller than EM/4. +// +// +// cjk auto-hinter +// --------------- +// +// Characters in a blue string are *not* automatically classified. Instead, +// first come the characters used for the overshoot value, then the +// character `|', then the characters used for the reference value +// (everything separated by space characters). The blue zone is then set up +// by the mean values of all reference values and all overshoot values, +// respectively. Both horizontal and vertical blue zones (i.e., adjusting +// vertical and horizontal coordinate values, respectively) are supported. +// +// For the cjk auto-hinter, the overshoot should be smaller than the +// reference for top zones, and vice versa for bottom zones. +// +// CJK_TOP +// Take the maximum flat and round coordinate values of the blue string +// characters. If not set, take the minimum values. +// +// CJK_RIGHT +// A synonym for CJK_TOP. If CJK_HORIZ is set, this flag indicates the +// right blue zone, taking horizontal maximum values. +// +// CJK_HORIZ +// Define a blue zone for horizontal hinting (i.e., vertical blue +// zones). If not set, this is a blue zone for vertical hinting. + + +AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: + + AF_BLUE_STRINGSET_ADLM + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ARAB + { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARABIC_BOTTOM, 0 } + { AF_BLUE_STRING_ARABIC_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ARMN + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_AVST + { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_AVESTAN_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_BAMU + { AF_BLUE_STRING_BAMUM_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BAMUM_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_BENG + { AF_BLUE_STRING_BENGALI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BENGALI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BENGALI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_BENGALI_BASE, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_BUHD + { AF_BLUE_STRING_BUHID_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BUHID_LARGE, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BUHID_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_BUHID_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CAKM + { AF_BLUE_STRING_CHAKMA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CHAKMA_BOTTOM, 0 } + { AF_BLUE_STRING_CHAKMA_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CANS + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CARI + { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CARIAN_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CHER + { AF_BLUE_STRING_CHEROKEE_CAPITAL, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CHEROKEE_CAPITAL, 0 } + { AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CHEROKEE_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CHEROKEE_SMALL, 0 } + { AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_COPT + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CPRT + { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYPRIOT_BOTTOM, 0 } + { AF_BLUE_STRING_CYPRIOT_SMALL, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYPRIOT_SMALL, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CYRL + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_DEVA + { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DEVANAGARI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DEVANAGARI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_DEVANAGARI_BASE, 0 } + { AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_DSRT + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ETHI + { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GEOR + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM, 0 } + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER, 0 } + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GEOK + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM, 0 } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM, 0 } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GLAG + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GOTH + { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GOTHIC_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GREK + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GREEK_SMALL, 0 } + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GUJR + { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GUJARATI_BOTTOM, 0 } + { AF_BLUE_STRING_GUJARATI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GUJARATI_DESCENDER, 0 } + { AF_BLUE_STRING_GUJARATI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GURU + { AF_BLUE_STRING_GURMUKHI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GURMUKHI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GURMUKHI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GURMUKHI_BOTTOM, 0 } + { AF_BLUE_STRING_GURMUKHI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_HEBR + { AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_LONG } + { AF_BLUE_STRING_HEBREW_BOTTOM, 0 } + { AF_BLUE_STRING_HEBREW_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KNDA + { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_KANNADA_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KALI + { AF_BLUE_STRING_KAYAH_LI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_KAYAH_LI_BOTTOM, 0 } + { AF_BLUE_STRING_KAYAH_LI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_KAYAH_LI_DESCENDER, 0 } + { AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KHMR + { AF_BLUE_STRING_KHMER_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP, AF_BLUE_PROPERTY_LATIN_SUB_TOP } + { AF_BLUE_STRING_KHMER_BOTTOM, 0 } + { AF_BLUE_STRING_KHMER_DESCENDER, 0 } + { AF_BLUE_STRING_KHMER_LARGE_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KHMS + { AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LAO + { AF_BLUE_STRING_LAO_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LAO_BOTTOM, 0 } + { AF_BLUE_STRING_LAO_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LAO_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LATN + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LATB + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LATP + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LISU + { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LISU_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MLYM + { AF_BLUE_STRING_MALAYALAM_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MEDF + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MONG + { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MYMR + { AF_BLUE_STRING_MYANMAR_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_MYANMAR_BOTTOM, 0 } + { AF_BLUE_STRING_MYANMAR_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MYANMAR_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_NKOO + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_NKO_BOTTOM, 0 } + { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_NONE + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_OLCK + { AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OL_CHIKI, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ORKH + { AF_BLUE_STRING_OLD_TURKIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_OSGE + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 } + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_OSMA + { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSMANYA_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ROHG + { AF_BLUE_STRING_ROHINGYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ROHINGYA_BOTTOM, 0 } + { AF_BLUE_STRING_ROHINGYA_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SAUR + { AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SHAW + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 } + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 } + { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SINH + { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SINHALA_BOTTOM, 0 } + { AF_BLUE_STRING_SINHALA_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SUND + { AF_BLUE_STRING_SUNDANESE_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SUNDANESE_BOTTOM, 0 } + { AF_BLUE_STRING_SUNDANESE_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TAML + { AF_BLUE_STRING_TAMIL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TAMIL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TAVT + { AF_BLUE_STRING_TAI_VIET_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TAI_VIET_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TELU + { AF_BLUE_STRING_TELUGU_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TELUGU_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_THAI + { AF_BLUE_STRING_THAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_THAI_BOTTOM, 0 } + { AF_BLUE_STRING_THAI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_THAI_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_THAI_DESCENDER, 0 } + { AF_BLUE_STRING_THAI_LARGE_DESCENDER, 0 } + { AF_BLUE_STRING_THAI_DIGIT_TOP, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TFNG + { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TIFINAGH, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_VAII + { AF_BLUE_STRING_VAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_VAI_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + +#ifdef AF_CONFIG_OPTION_CJK + + AF_BLUE_STRINGSET_HANI + { AF_BLUE_STRING_CJK_TOP, AF_BLUE_PROPERTY_CJK_TOP } + { AF_BLUE_STRING_CJK_BOTTOM, 0 } +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + { AF_BLUE_STRING_CJK_LEFT, AF_BLUE_PROPERTY_CJK_HORIZ } + { AF_BLUE_STRING_CJK_RIGHT, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT } +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + { AF_BLUE_STRING_MAX, 0 } + +#endif /* AF_CONFIG_OPTION_CJK */ + + +// END diff --git a/vendor/freetype/src/autofit/afblue.h b/vendor/freetype/src/autofit/afblue.h new file mode 100644 index 0000000..76f2f47 --- /dev/null +++ b/vendor/freetype/src/autofit/afblue.h @@ -0,0 +1,429 @@ +/* This file has been generated by the Perl script `afblue.pl', */ +/* using data from file `afblue.dat'. */ + +/**************************************************************************** + * + * afblue.h + * + * Auto-fitter data for blue strings (specification). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFBLUE_H_ +#define AFBLUE_H_ + + +FT_BEGIN_HEADER + + + /* an auxiliary macro to decode a UTF-8 character -- since we only use */ + /* hard-coded, self-converted data, no error checking is performed */ +#define GET_UTF8_CHAR( ch, p ) \ + do \ + { \ + ch = (unsigned char)*p++; \ + if ( ch >= 0x80 ) \ + { \ + FT_UInt len_; \ + \ + \ + if ( ch < 0xE0 ) \ + { \ + len_ = 1; \ + ch &= 0x1F; \ + } \ + else if ( ch < 0xF0 ) \ + { \ + len_ = 2; \ + ch &= 0x0F; \ + } \ + else \ + { \ + len_ = 3; \ + ch &= 0x07; \ + } \ + \ + for ( ; len_ > 0; len_-- ) \ + ch = ( ch << 6 ) | ( *p++ & 0x3F ); \ + } \ + } while ( 0 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* At the bottommost level, we define strings for finding blue zones. */ + + +#define AF_BLUE_STRING_MAX_LEN 51 + + /* The AF_Blue_String enumeration values are offsets into the */ + /* `af_blue_strings' array. */ + + typedef enum AF_Blue_String_ + { + AF_BLUE_STRING_ADLAM_CAPITAL_TOP = 0, + AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM = 30, + AF_BLUE_STRING_ADLAM_SMALL_TOP = 40, + AF_BLUE_STRING_ADLAM_SMALL_BOTTOM = 65, + AF_BLUE_STRING_ARABIC_TOP = 105, + AF_BLUE_STRING_ARABIC_BOTTOM = 123, + AF_BLUE_STRING_ARABIC_JOIN = 138, + AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP = 141, + AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM = 165, + AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER = 189, + AF_BLUE_STRING_ARMENIAN_SMALL_TOP = 210, + AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM = 234, + AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER = 258, + AF_BLUE_STRING_AVESTAN_TOP = 282, + AF_BLUE_STRING_AVESTAN_BOTTOM = 302, + AF_BLUE_STRING_BAMUM_TOP = 312, + AF_BLUE_STRING_BAMUM_BOTTOM = 344, + AF_BLUE_STRING_BENGALI_BASE = 376, + AF_BLUE_STRING_BENGALI_TOP = 408, + AF_BLUE_STRING_BENGALI_HEAD = 436, + AF_BLUE_STRING_BUHID_TOP = 468, + AF_BLUE_STRING_BUHID_LARGE = 476, + AF_BLUE_STRING_BUHID_SMALL = 488, + AF_BLUE_STRING_BUHID_BOTTOM = 504, + AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP = 532, + AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM = 564, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP = 596, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM = 628, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP = 660, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM = 688, + AF_BLUE_STRING_CARIAN_TOP = 720, + AF_BLUE_STRING_CARIAN_BOTTOM = 760, + AF_BLUE_STRING_CHAKMA_TOP = 795, + AF_BLUE_STRING_CHAKMA_BOTTOM = 820, + AF_BLUE_STRING_CHAKMA_DESCENDER = 845, + AF_BLUE_STRING_CHEROKEE_CAPITAL = 910, + AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER = 942, + AF_BLUE_STRING_CHEROKEE_SMALL = 974, + AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER = 1006, + AF_BLUE_STRING_COPTIC_CAPITAL_TOP = 1022, + AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM = 1054, + AF_BLUE_STRING_COPTIC_SMALL_TOP = 1086, + AF_BLUE_STRING_COPTIC_SMALL_BOTTOM = 1118, + AF_BLUE_STRING_CYPRIOT_TOP = 1150, + AF_BLUE_STRING_CYPRIOT_BOTTOM = 1190, + AF_BLUE_STRING_CYPRIOT_SMALL = 1225, + AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP = 1240, + AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM = 1264, + AF_BLUE_STRING_CYRILLIC_SMALL = 1288, + AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER = 1312, + AF_BLUE_STRING_DESERET_CAPITAL_TOP = 1321, + AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM = 1346, + AF_BLUE_STRING_DESERET_SMALL_TOP = 1371, + AF_BLUE_STRING_DESERET_SMALL_BOTTOM = 1396, + AF_BLUE_STRING_DEVANAGARI_BASE = 1421, + AF_BLUE_STRING_DEVANAGARI_TOP = 1453, + AF_BLUE_STRING_DEVANAGARI_HEAD = 1485, + AF_BLUE_STRING_DEVANAGARI_BOTTOM = 1517, + AF_BLUE_STRING_ETHIOPIC_TOP = 1525, + AF_BLUE_STRING_ETHIOPIC_BOTTOM = 1557, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP = 1589, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM = 1621, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER = 1653, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER = 1685, + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP = 1717, + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM = 1749, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP = 1781, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM = 1813, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER = 1845, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER = 1877, + AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP = 1909, + AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM = 1941, + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP = 1973, + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM = 2005, + AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP = 2037, + AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM = 2069, + AF_BLUE_STRING_GOTHIC_TOP = 2101, + AF_BLUE_STRING_GOTHIC_BOTTOM = 2141, + AF_BLUE_STRING_GREEK_CAPITAL_TOP = 2161, + AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM = 2182, + AF_BLUE_STRING_GREEK_SMALL_BETA_TOP = 2200, + AF_BLUE_STRING_GREEK_SMALL = 2218, + AF_BLUE_STRING_GREEK_SMALL_DESCENDER = 2242, + AF_BLUE_STRING_GUJARATI_TOP = 2266, + AF_BLUE_STRING_GUJARATI_BOTTOM = 2298, + AF_BLUE_STRING_GUJARATI_ASCENDER = 2330, + AF_BLUE_STRING_GUJARATI_DESCENDER = 2380, + AF_BLUE_STRING_GUJARATI_DIGIT_TOP = 2413, + AF_BLUE_STRING_GURMUKHI_BASE = 2433, + AF_BLUE_STRING_GURMUKHI_HEAD = 2465, + AF_BLUE_STRING_GURMUKHI_TOP = 2497, + AF_BLUE_STRING_GURMUKHI_BOTTOM = 2529, + AF_BLUE_STRING_GURMUKHI_DIGIT_TOP = 2561, + AF_BLUE_STRING_HEBREW_TOP = 2581, + AF_BLUE_STRING_HEBREW_BOTTOM = 2605, + AF_BLUE_STRING_HEBREW_DESCENDER = 2623, + AF_BLUE_STRING_KANNADA_TOP = 2638, + AF_BLUE_STRING_KANNADA_BOTTOM = 2682, + AF_BLUE_STRING_KAYAH_LI_TOP = 2714, + AF_BLUE_STRING_KAYAH_LI_BOTTOM = 2738, + AF_BLUE_STRING_KAYAH_LI_ASCENDER = 2758, + AF_BLUE_STRING_KAYAH_LI_DESCENDER = 2766, + AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER = 2778, + AF_BLUE_STRING_KHMER_TOP = 2799, + AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP = 2823, + AF_BLUE_STRING_KHMER_BOTTOM = 2863, + AF_BLUE_STRING_KHMER_DESCENDER = 2895, + AF_BLUE_STRING_KHMER_LARGE_DESCENDER = 2929, + AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP = 3016, + AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM = 3024, + AF_BLUE_STRING_LAO_TOP = 3032, + AF_BLUE_STRING_LAO_BOTTOM = 3064, + AF_BLUE_STRING_LAO_ASCENDER = 3096, + AF_BLUE_STRING_LAO_LARGE_ASCENDER = 3112, + AF_BLUE_STRING_LAO_DESCENDER = 3124, + AF_BLUE_STRING_LATIN_CAPITAL_TOP = 3148, + AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM = 3164, + AF_BLUE_STRING_LATIN_SMALL_F_TOP = 3180, + AF_BLUE_STRING_LATIN_SMALL_TOP = 3194, + AF_BLUE_STRING_LATIN_SMALL_BOTTOM = 3210, + AF_BLUE_STRING_LATIN_SMALL_DESCENDER = 3226, + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP = 3236, + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM = 3256, + AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP = 3276, + AF_BLUE_STRING_LATIN_SUBS_SMALL = 3296, + AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER = 3332, + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP = 3352, + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM = 3383, + AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP = 3412, + AF_BLUE_STRING_LATIN_SUPS_SMALL = 3438, + AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER = 3463, + AF_BLUE_STRING_LISU_TOP = 3474, + AF_BLUE_STRING_LISU_BOTTOM = 3506, + AF_BLUE_STRING_MALAYALAM_TOP = 3538, + AF_BLUE_STRING_MALAYALAM_BOTTOM = 3582, + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP = 3614, + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM = 3649, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP = 3689, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP = 3719, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM = 3749, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER = 3779, + AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP = 3794, + AF_BLUE_STRING_MONGOLIAN_TOP_BASE = 3819, + AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE = 3863, + AF_BLUE_STRING_MYANMAR_TOP = 3867, + AF_BLUE_STRING_MYANMAR_BOTTOM = 3899, + AF_BLUE_STRING_MYANMAR_ASCENDER = 3931, + AF_BLUE_STRING_MYANMAR_DESCENDER = 3959, + AF_BLUE_STRING_NKO_TOP = 3991, + AF_BLUE_STRING_NKO_BOTTOM = 4015, + AF_BLUE_STRING_NKO_SMALL_TOP = 4030, + AF_BLUE_STRING_NKO_SMALL_BOTTOM = 4039, + AF_BLUE_STRING_OL_CHIKI = 4051, + AF_BLUE_STRING_OLD_TURKIC_TOP = 4075, + AF_BLUE_STRING_OLD_TURKIC_BOTTOM = 4090, + AF_BLUE_STRING_OSAGE_CAPITAL_TOP = 4110, + AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM = 4150, + AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER = 4180, + AF_BLUE_STRING_OSAGE_SMALL_TOP = 4195, + AF_BLUE_STRING_OSAGE_SMALL_BOTTOM = 4235, + AF_BLUE_STRING_OSAGE_SMALL_ASCENDER = 4275, + AF_BLUE_STRING_OSAGE_SMALL_DESCENDER = 4300, + AF_BLUE_STRING_OSMANYA_TOP = 4315, + AF_BLUE_STRING_OSMANYA_BOTTOM = 4355, + AF_BLUE_STRING_ROHINGYA_TOP = 4395, + AF_BLUE_STRING_ROHINGYA_BOTTOM = 4420, + AF_BLUE_STRING_ROHINGYA_JOIN = 4445, + AF_BLUE_STRING_SAURASHTRA_TOP = 4448, + AF_BLUE_STRING_SAURASHTRA_BOTTOM = 4480, + AF_BLUE_STRING_SHAVIAN_TOP = 4500, + AF_BLUE_STRING_SHAVIAN_BOTTOM = 4510, + AF_BLUE_STRING_SHAVIAN_DESCENDER = 4535, + AF_BLUE_STRING_SHAVIAN_SMALL_TOP = 4545, + AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM = 4580, + AF_BLUE_STRING_SINHALA_TOP = 4595, + AF_BLUE_STRING_SINHALA_BOTTOM = 4627, + AF_BLUE_STRING_SINHALA_DESCENDER = 4659, + AF_BLUE_STRING_SUNDANESE_TOP = 4703, + AF_BLUE_STRING_SUNDANESE_BOTTOM = 4727, + AF_BLUE_STRING_SUNDANESE_DESCENDER = 4759, + AF_BLUE_STRING_TAI_VIET_TOP = 4767, + AF_BLUE_STRING_TAI_VIET_BOTTOM = 4787, + AF_BLUE_STRING_TAMIL_TOP = 4799, + AF_BLUE_STRING_TAMIL_BOTTOM = 4831, + AF_BLUE_STRING_TELUGU_TOP = 4863, + AF_BLUE_STRING_TELUGU_BOTTOM = 4891, + AF_BLUE_STRING_THAI_TOP = 4919, + AF_BLUE_STRING_THAI_BOTTOM = 4943, + AF_BLUE_STRING_THAI_ASCENDER = 4971, + AF_BLUE_STRING_THAI_LARGE_ASCENDER = 4983, + AF_BLUE_STRING_THAI_DESCENDER = 4995, + AF_BLUE_STRING_THAI_LARGE_DESCENDER = 5011, + AF_BLUE_STRING_THAI_DIGIT_TOP = 5019, + AF_BLUE_STRING_TIFINAGH = 5031, + AF_BLUE_STRING_VAI_TOP = 5063, + AF_BLUE_STRING_VAI_BOTTOM = 5095, + af_blue_1_1 = 5126, +#ifdef AF_CONFIG_OPTION_CJK + AF_BLUE_STRING_CJK_TOP = af_blue_1_1 + 1, + AF_BLUE_STRING_CJK_BOTTOM = af_blue_1_1 + 203, + af_blue_1_1_1 = af_blue_1_1 + 404, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + AF_BLUE_STRING_CJK_LEFT = af_blue_1_1_1 + 1, + AF_BLUE_STRING_CJK_RIGHT = af_blue_1_1_1 + 204, + af_blue_1_1_2 = af_blue_1_1_1 + 405, +#else + af_blue_1_1_2 = af_blue_1_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + af_blue_1_2 = af_blue_1_1_2 + 0, +#else + af_blue_1_2 = af_blue_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK */ + + + AF_BLUE_STRING_MAX /* do not remove */ + + } AF_Blue_String; + + + FT_LOCAL_ARRAY( char ) + af_blue_strings[]; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S E T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* The next level is to group blue strings into style-specific sets. */ + + + /* Properties are specific to a writing system. We assume that a given */ + /* blue string can't be used in more than a single writing system, which */ + /* is a safe bet. */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) +#define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) +#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) +#define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP + + +#define AF_BLUE_STRINGSET_MAX_LEN 8 + + /* The AF_Blue_Stringset enumeration values are offsets into the */ + /* `af_blue_stringsets' array. */ + + typedef enum AF_Blue_Stringset_ + { + AF_BLUE_STRINGSET_ADLM = 0, + AF_BLUE_STRINGSET_ARAB = 5, + AF_BLUE_STRINGSET_ARMN = 9, + AF_BLUE_STRINGSET_AVST = 16, + AF_BLUE_STRINGSET_BAMU = 19, + AF_BLUE_STRINGSET_BENG = 22, + AF_BLUE_STRINGSET_BUHD = 27, + AF_BLUE_STRINGSET_CAKM = 32, + AF_BLUE_STRINGSET_CANS = 36, + AF_BLUE_STRINGSET_CARI = 43, + AF_BLUE_STRINGSET_CHER = 46, + AF_BLUE_STRINGSET_COPT = 53, + AF_BLUE_STRINGSET_CPRT = 58, + AF_BLUE_STRINGSET_CYRL = 63, + AF_BLUE_STRINGSET_DEVA = 69, + AF_BLUE_STRINGSET_DSRT = 75, + AF_BLUE_STRINGSET_ETHI = 80, + AF_BLUE_STRINGSET_GEOR = 83, + AF_BLUE_STRINGSET_GEOK = 90, + AF_BLUE_STRINGSET_GLAG = 97, + AF_BLUE_STRINGSET_GOTH = 102, + AF_BLUE_STRINGSET_GREK = 105, + AF_BLUE_STRINGSET_GUJR = 112, + AF_BLUE_STRINGSET_GURU = 118, + AF_BLUE_STRINGSET_HEBR = 124, + AF_BLUE_STRINGSET_KNDA = 128, + AF_BLUE_STRINGSET_KALI = 131, + AF_BLUE_STRINGSET_KHMR = 137, + AF_BLUE_STRINGSET_KHMS = 143, + AF_BLUE_STRINGSET_LAO = 146, + AF_BLUE_STRINGSET_LATN = 152, + AF_BLUE_STRINGSET_LATB = 159, + AF_BLUE_STRINGSET_LATP = 166, + AF_BLUE_STRINGSET_LISU = 173, + AF_BLUE_STRINGSET_MLYM = 176, + AF_BLUE_STRINGSET_MEDF = 179, + AF_BLUE_STRINGSET_MONG = 187, + AF_BLUE_STRINGSET_MYMR = 190, + AF_BLUE_STRINGSET_NKOO = 195, + AF_BLUE_STRINGSET_NONE = 200, + AF_BLUE_STRINGSET_OLCK = 201, + AF_BLUE_STRINGSET_ORKH = 204, + AF_BLUE_STRINGSET_OSGE = 207, + AF_BLUE_STRINGSET_OSMA = 215, + AF_BLUE_STRINGSET_ROHG = 218, + AF_BLUE_STRINGSET_SAUR = 222, + AF_BLUE_STRINGSET_SHAW = 225, + AF_BLUE_STRINGSET_SINH = 231, + AF_BLUE_STRINGSET_SUND = 235, + AF_BLUE_STRINGSET_TAML = 239, + AF_BLUE_STRINGSET_TAVT = 242, + AF_BLUE_STRINGSET_TELU = 245, + AF_BLUE_STRINGSET_THAI = 248, + AF_BLUE_STRINGSET_TFNG = 256, + AF_BLUE_STRINGSET_VAII = 259, + af_blue_2_1 = 262, +#ifdef AF_CONFIG_OPTION_CJK + AF_BLUE_STRINGSET_HANI = af_blue_2_1 + 0, + af_blue_2_1_1 = af_blue_2_1 + 2, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + af_blue_2_1_2 = af_blue_2_1_1 + 2, +#else + af_blue_2_1_2 = af_blue_2_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + af_blue_2_2 = af_blue_2_1_2 + 1, +#else + af_blue_2_2 = af_blue_2_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK */ + + + AF_BLUE_STRINGSET_MAX /* do not remove */ + + } AF_Blue_Stringset; + + + typedef struct AF_Blue_StringRec_ + { + AF_Blue_String string; + FT_UShort properties; + + } AF_Blue_StringRec; + + + FT_LOCAL_ARRAY( AF_Blue_StringRec ) + af_blue_stringsets[]; + +/* */ + +FT_END_HEADER + + +#endif /* AFBLUE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afblue.hin b/vendor/freetype/src/autofit/afblue.hin new file mode 100644 index 0000000..6a31298 --- /dev/null +++ b/vendor/freetype/src/autofit/afblue.hin @@ -0,0 +1,146 @@ +/**************************************************************************** + * + * afblue.h + * + * Auto-fitter data for blue strings (specification). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFBLUE_H_ +#define AFBLUE_H_ + + +FT_BEGIN_HEADER + + + /* an auxiliary macro to decode a UTF-8 character -- since we only use */ + /* hard-coded, self-converted data, no error checking is performed */ +#define GET_UTF8_CHAR( ch, p ) \ + do \ + { \ + ch = (unsigned char)*p++; \ + if ( ch >= 0x80 ) \ + { \ + FT_UInt len_; \ + \ + \ + if ( ch < 0xE0 ) \ + { \ + len_ = 1; \ + ch &= 0x1F; \ + } \ + else if ( ch < 0xF0 ) \ + { \ + len_ = 2; \ + ch &= 0x0F; \ + } \ + else \ + { \ + len_ = 3; \ + ch &= 0x07; \ + } \ + \ + for ( ; len_ > 0; len_-- ) \ + ch = ( ch << 6 ) | ( *p++ & 0x3F ); \ + } \ + } while ( 0 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* At the bottommost level, we define strings for finding blue zones. */ + + +#define AF_BLUE_STRING_MAX_LEN @AF_BLUE_STRING_MAX_LEN@ + + /* The AF_Blue_String enumeration values are offsets into the */ + /* `af_blue_strings' array. */ + + typedef enum AF_Blue_String_ + { +@AF_BLUE_STRING_ENUM@ + + AF_BLUE_STRING_MAX /* do not remove */ + + } AF_Blue_String; + + + FT_LOCAL_ARRAY( char ) + af_blue_strings[]; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S E T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* The next level is to group blue strings into style-specific sets. */ + + + /* Properties are specific to a writing system. We assume that a given */ + /* blue string can't be used in more than a single writing system, which */ + /* is a safe bet. */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) +#define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) +#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) +#define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP + + +#define AF_BLUE_STRINGSET_MAX_LEN @AF_BLUE_STRINGSET_MAX_LEN@ + + /* The AF_Blue_Stringset enumeration values are offsets into the */ + /* `af_blue_stringsets' array. */ + + typedef enum AF_Blue_Stringset_ + { +@AF_BLUE_STRINGSET_ENUM@ + + AF_BLUE_STRINGSET_MAX /* do not remove */ + + } AF_Blue_Stringset; + + + typedef struct AF_Blue_StringRec_ + { + AF_Blue_String string; + FT_UShort properties; + + } AF_Blue_StringRec; + + + FT_LOCAL_ARRAY( AF_Blue_StringRec ) + af_blue_stringsets[]; + +/* */ + +FT_END_HEADER + + +#endif /* AFBLUE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afcjk.c b/vendor/freetype/src/autofit/afcjk.c new file mode 100644 index 0000000..f414289 --- /dev/null +++ b/vendor/freetype/src/autofit/afcjk.c @@ -0,0 +1,2383 @@ +/**************************************************************************** + * + * afcjk.c + * + * Auto-fitter hinting routines for CJK writing system (body). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /* + * The algorithm is based on akito's autohint patch, archived at + * + * https://web.archive.org/web/20051219160454/http://www.kde.gr.jp:80/~akito/patch/freetype2/2.1.7/ + * + */ + +#include +#include + +#include "afglobal.h" +#include "aflatin.h" +#include "afcjk.h" + + +#ifdef AF_CONFIG_OPTION_CJK + +#undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + +#include "aferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afcjk + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Basically the Latin version with AF_CJKMetrics */ + /* to replace AF_LatinMetrics. */ + + FT_LOCAL_DEF( void ) + af_cjk_metrics_init_widths( AF_CJKMetrics metrics, + FT_Face face ) + { + /* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + + + FT_TRACE5(( "\n" )); + FT_TRACE5(( "cjk standard widths computation (style `%s')\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "===================================================\n" )); + FT_TRACE5(( "\n" )); + + af_glyph_hints_init( hints, face->memory ); + + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + + { + FT_Error error; + FT_ULong glyph_index; + int dim; + AF_CJKMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + + AF_StyleClass style_class = metrics->root.style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + const char* p; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_ULong ch = 0; +#endif + + p = script_class->standard_charstring; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + /* We check a list of standard characters. The first match wins. */ + + glyph_index = 0; + while ( *p ) + { + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* otherwise exit loop if we have a result */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); + if ( glyph_index ) + break; + } + + af_shaper_buf_destroy( face, shaper_buf ); + + if ( !glyph_index ) + goto Exit; + + if ( !glyph_index ) + goto Exit; + + FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n", + ch, glyph_index )); + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + + FT_ZERO( dummy ); + + dummy->units_per_em = metrics->units_per_em; + + scaler->x_scale = 0x10000L; + scaler->y_scale = 0x10000L; + scaler->x_delta = 0; + scaler->y_delta = 0; + + scaler->face = face; + scaler->render_mode = FT_RENDER_MODE_NORMAL; + scaler->flags = 0; + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy ); + + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + + + error = af_latin_hints_compute_segments( hints, + (AF_Dimension)dim ); + if ( error ) + goto Exit; + + /* + * We assume that the glyphs selected for the stem width + * computation are `featureless' enough so that the linking + * algorithm works fine without adjustments of its scoring + * function. + */ + af_latin_hints_link_segments( hints, + 0, + NULL, + (AF_Dimension)dim ); + + seg = axhints->segments; + limit = seg + axhints->num_segments; + + for ( ; seg < limit; seg++ ) + { + link = seg->link; + + /* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + + + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + + if ( num_widths < AF_CJK_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } + + /* this also replaces multiple almost identical stem widths */ + /* with a single one (the value 100 is heuristic) */ + af_sort_and_quantize_widths( &num_widths, axis->widths, + dummy->units_per_em / 100 ); + axis->width_count = num_widths; + } + + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + + + stdw = ( axis->width_count > 0 ) ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); + + /* let's try 20% of the smallest width */ + axis->edge_distance_threshold = stdw / 5; + axis->standard_width = stdw; + axis->extra_light = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + FT_TRACE5(( "%s widths:\n", + dim == AF_DIMENSION_VERT ? "horizontal" + : "vertical" )); + + FT_TRACE5(( " %ld (standard)", axis->standard_width )); + for ( i = 1; i < axis->width_count; i++ ) + FT_TRACE5(( " %ld", axis->widths[i].org )); + + FT_TRACE5(( "\n" )); + } +#endif + } + } + + FT_TRACE5(( "\n" )); + + af_glyph_hints_done( hints ); + } + + + /* Find all blue zones. */ + + static void + af_cjk_metrics_init_blues( AF_CJKMetrics metrics, + FT_Face face ) + { + FT_Pos fills[AF_BLUE_STRING_MAX_LEN]; + FT_Pos flats[AF_BLUE_STRING_MAX_LEN]; + + FT_UInt num_fills; + FT_UInt num_flats; + + FT_Bool fill; + + AF_CJKBlue blue; + FT_Error error; + AF_CJKAxis axis; + FT_Outline outline; + + AF_StyleClass sc = metrics->root.style_class; + + AF_Blue_Stringset bss = sc->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + + /* we walk over the blue character strings as specified in the */ + /* style's entry in the `af_blue_stringset' array, computing its */ + /* extremum points (depending on the string properties) */ + + FT_TRACE5(( "cjk blue zones computation\n" )); + FT_TRACE5(( "==========================\n" )); + FT_TRACE5(( "\n" )); + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) + { + const char* p = &af_blue_strings[bs->string]; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + + + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) + axis = &metrics->axis[AF_DIMENSION_HORZ]; + else + axis = &metrics->axis[AF_DIMENSION_VERT]; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_String* cjk_blue_name[4] = + { + (FT_String*)"bottom", /* -- , -- */ + (FT_String*)"top", /* -- , TOP */ + (FT_String*)"left", /* HORIZ, -- */ + (FT_String*)"right" /* HORIZ, TOP */ + }; + + + FT_TRACE5(( "blue zone %d (%s):\n", + axis->blue_count, + cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) | + AF_CJK_IS_TOP_BLUE( bs ) ] )); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + num_fills = 0; + num_flats = 0; + + fill = 1; /* start with characters that define fill values */ + FT_TRACE5(( " [overshoot values]\n" )); + + while ( *p ) + { + FT_ULong glyph_index; + FT_Pos best_pos; /* same as points.y or points.x, resp. */ + FT_Int best_point; + FT_Vector* points; + + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; + FT_ULong ch; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + /* switch to characters that define flat values */ + if ( *p == '|' ) + { + fill = 0; + FT_TRACE5(( " [reference values]\n" )); + p++; + continue; + } + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* load the character in the face -- skip unknown or empty ones */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); + if ( glyph_index == 0 ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + outline = face->glyph->outline; + if ( error || outline.n_points <= 2 ) + { + FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); + continue; + } + + /* now compute min or max point indices and coordinates */ + points = outline.points; + best_point = -1; + best_pos = 0; /* make compiler happy */ + + { + FT_Int nn; + FT_Int pp, first, last; + + + last = -1; + for ( nn = 0; nn < outline.n_contours; nn++ ) + { + first = last + 1; + last = outline.contours[nn]; + + /* Avoid single-point contours since they are never rasterized. */ + /* In some fonts, they correspond to mark attachment points */ + /* which are way outside of the glyph's real outline. */ + if ( last <= first ) + continue; + + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) + { + if ( AF_CJK_IS_RIGHT_BLUE( bs ) ) + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x > best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x < best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + } + } + else + { + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y > best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y < best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + } + } + } + + FT_TRACE5(( " U+%04lX: best_pos = %5ld\n", ch, best_pos )); + } + + if ( fill ) + fills[num_fills++] = best_pos; + else + flats[num_flats++] = best_pos; + + } /* end while loop */ + + if ( num_flats == 0 && num_fills == 0 ) + { + /* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( " empty\n" )); + continue; + } + + /* we have computed the contents of the `fill' and `flats' tables, */ + /* now determine the reference and overshoot position of the blue -- */ + /* we simply take the median value after a simple sort */ + af_sort_pos( num_fills, fills ); + af_sort_pos( num_flats, flats ); + + blue = &axis->blues[axis->blue_count]; + blue_ref = &blue->ref.org; + blue_shoot = &blue->shoot.org; + + axis->blue_count++; + + if ( num_flats == 0 ) + { + *blue_ref = + *blue_shoot = fills[num_fills / 2]; + } + else if ( num_fills == 0 ) + { + *blue_ref = + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = fills[num_fills / 2]; + *blue_shoot = flats[num_flats / 2]; + } + + /* make sure blue_ref >= blue_shoot for top/right or */ + /* vice versa for bottom/left */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool under_ref = FT_BOOL( shoot < ref ); + + + /* AF_CJK_IS_TOP_BLUE covers `right' and `top' */ + if ( AF_CJK_IS_TOP_BLUE( bs ) ^ under_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + + FT_TRACE5(( " [reference smaller than overshoot," + " taking mean value]\n" )); + } + } + + blue->flags = 0; + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + blue->flags |= AF_CJK_BLUE_TOP; + + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); + + } /* end for loop */ + + af_shaper_buf_destroy( face, shaper_buf ); + + FT_TRACE5(( "\n" )); + + return; + } + + + /* Basically the Latin version with type AF_CJKMetrics for metrics. */ + + FT_LOCAL_DEF( void ) + af_cjk_metrics_check_digits( AF_CJKMetrics metrics, + FT_Face face ) + { + FT_Bool started = 0, same_width = 1; + FT_Long advance = 0, old_advance = 0; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + /* in all supported charmaps, digits have character codes 0x30-0x39 */ + const char digits[] = "0 1 2 3 4 5 6 7 8 9"; + const char* p; + + + p = digits; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + while ( *p ) + { + FT_ULong glyph_index; + unsigned int num_idx; + + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + &advance, + NULL ); + if ( !glyph_index ) + continue; + + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + + af_shaper_buf_destroy( face, shaper_buf ); + + metrics->root.digits_have_same_width = same_width; + } + + + /* Initialize global metrics. */ + + FT_LOCAL_DEF( FT_Error ) + af_cjk_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Face face ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + FT_CharMap oldmap = face->charmap; + + + metrics->units_per_em = face->units_per_EM; + + if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + { + af_cjk_metrics_init_widths( metrics, face ); + af_cjk_metrics_init_blues( metrics, face ); + af_cjk_metrics_check_digits( metrics, face ); + } + + face->charmap = oldmap; + return FT_Err_Ok; + } + + + /* Adjust scaling value, then scale and shift widths */ + /* and blue zones (if applicable) for given dimension. */ + + static void + af_cjk_metrics_scale_dim( AF_CJKMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) + { + FT_Fixed scale; + FT_Pos delta; + AF_CJKAxis axis; + FT_UInt nn; + + + if ( dim == AF_DIMENSION_HORZ ) + { + scale = scaler->x_scale; + delta = scaler->x_delta; + } + else + { + scale = scaler->y_scale; + delta = scaler->y_delta; + } + + axis = &metrics->axis[dim]; + + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + + axis->org_scale = scale; + axis->org_delta = delta; + + axis->scale = scale; + axis->delta = delta; + + /* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_CJKBlue blue = &axis->blues[nn]; + FT_Pos dist; + + + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_CJK_BLUE_ACTIVE; + + /* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { + FT_Pos delta1, delta2; + + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + + /* shoot is under shoot for cjk */ + delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + + delta2 = FT_MulFix( delta2, scale ); + + FT_TRACE5(( "delta: %ld", delta1 )); + if ( delta2 < 32 ) + delta2 = 0; +#if 0 + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); +#endif + else + delta2 = FT_PIX_ROUND( delta2 ); + FT_TRACE5(( "/%ld\n", delta2 )); + + if ( delta1 < 0 ) + delta2 = -delta2; + + blue->shoot.fit = blue->ref.fit - delta2; + + FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n", + ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', + nn, blue->ref.org, blue->shoot.org )); + FT_TRACE5(( " ref: cur=%.2f fit=%.2f\n", + (double)blue->ref.cur / 64, + (double)blue->ref.fit / 64 )); + FT_TRACE5(( " shoot: cur=%.2f fit=%.2f\n", + (double)blue->shoot.cur / 64, + (double)blue->shoot.fit / 64 )); + + blue->flags |= AF_CJK_BLUE_ACTIVE; + } + } + } + + + /* Scale global values in both directions. */ + + FT_LOCAL_DEF( void ) + af_cjk_metrics_scale( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + AF_Scaler scaler ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + /* we copy the whole structure since the x and y scaling values */ + /* are not modified, contrary to e.g. the `latin' auto-hinter */ + metrics->root.scaler = *scaler; + + af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); + af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); + } + + + /* Extract standard_width from writing system/script specific */ + /* metrics class. */ + + FT_CALLBACK_DEF( void ) + af_cjk_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + if ( stdHW ) + *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; + + if ( stdVW ) + *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L Y P H A N A L Y S I S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Walk over all contours and compute its segments. */ + + static FT_Error + af_cjk_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + FT_Error error; + AF_Segment seg; + + + error = af_latin_hints_compute_segments( hints, dim ); + if ( error ) + return error; + + /* a segment is round if it doesn't have successive */ + /* on-curve points. */ + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Point pt = seg->first; + AF_Point last = seg->last; + FT_UInt f0 = pt->flags & AF_FLAG_CONTROL; + FT_UInt f1; + + + seg->flags &= ~AF_EDGE_ROUND; + + for ( ; pt != last; f0 = f1 ) + { + pt = pt->next; + f1 = pt->flags & AF_FLAG_CONTROL; + + if ( !f0 && !f1 ) + break; + + if ( pt == last ) + seg->flags |= AF_EDGE_ROUND; + } + } + + return FT_Err_Ok; + } + + + static void + af_cjk_hints_link_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Direction major_dir = axis->major_dir; + AF_Segment seg1, seg2; + FT_Pos len_threshold; + FT_Pos dist_threshold; + + + len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); + + dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + dist_threshold = FT_DivFix( 64 * 3, dist_threshold ); + + /* now compare each segment to the others */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + if ( seg1->dir != major_dir ) + continue; + + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 ) + { + FT_Pos dist = seg2->pos - seg1->pos; + + + if ( dist < 0 ) + continue; + + { + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len; + + + if ( min < seg2->min_coord ) + min = seg2->min_coord; + + if ( max > seg2->max_coord ) + max = seg2->max_coord; + + len = max - min; + if ( len >= len_threshold ) + { + if ( dist * 8 < seg1->score * 9 && + ( dist * 8 < seg1->score * 7 || seg1->len < len ) ) + { + seg1->score = dist; + seg1->len = len; + seg1->link = seg2; + } + + if ( dist * 8 < seg2->score * 9 && + ( dist * 8 < seg2->score * 7 || seg2->len < len ) ) + { + seg2->score = dist; + seg2->len = len; + seg2->link = seg1; + } + } + } + } + } + + /* + * now compute the `serif' segments + * + * In Hanzi, some strokes are wider on one or both of the ends. + * We either identify the stems on the ends as serifs or remove + * the linkage, depending on the length of the stems. + * + */ + + { + AF_Segment link1, link2; + + + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + link1 = seg1->link; + if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos ) + continue; + + if ( seg1->score >= dist_threshold ) + continue; + + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + if ( seg2->pos > seg1->pos || seg1 == seg2 ) + continue; + + link2 = seg2->link; + if ( !link2 || link2->link != seg2 || link2->pos < link1->pos ) + continue; + + if ( seg1->pos == seg2->pos && link1->pos == link2->pos ) + continue; + + if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score ) + continue; + + /* seg2 < seg1 < link1 < link2 */ + + if ( seg1->len >= seg2->len * 3 ) + { + AF_Segment seg; + + + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Segment link = seg->link; + + + if ( link == seg2 ) + { + seg->link = NULL; + seg->serif = link1; + } + else if ( link == link2 ) + { + seg->link = NULL; + seg->serif = seg1; + } + } + } + else + { + seg1->link = link1->link = NULL; + + break; + } + } + } + } + + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg2 = seg1->link; + + if ( seg2 ) + { + if ( seg2->link != seg1 ) + { + seg1->link = NULL; + + if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 ) + seg1->serif = seg2->link; + } + } + } + } + + + static FT_Error + af_cjk_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = FT_Err_Ok; + FT_Memory memory = hints->memory; + AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim]; + + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Segment seg; + + FT_Fixed scale; + FT_Pos edge_distance_threshold; + + + axis->num_edges = 0; + + scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + + /********************************************************************** + * + * We begin by generating a sorted table of edges for the current + * direction. To do so, we simply scan each segment and try to find + * an edge in our table that corresponds to its position. + * + * If no edge is found, we create and insert a new edge in the + * sorted table. Otherwise, we simply add the segment to the edge's + * list which is then processed in the second step to compute the + * edge's properties. + * + * Note that the edges table is sorted along the segment/edge + * position. + * + */ + + edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = FT_DivFix( 64 / 4, scale ); + else + edge_distance_threshold = laxis->edge_distance_threshold; + + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = NULL; + FT_Pos best = 0xFFFFU; + FT_UInt ee; + + + /* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + + + if ( edge->dir != seg->dir ) + continue; + + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + + if ( dist < edge_distance_threshold && dist < best ) + { + AF_Segment link = seg->link; + + + /* check whether all linked segments of the candidate edge */ + /* can make a single edge. */ + if ( link ) + { + AF_Segment seg1 = edge->first; + FT_Pos dist2 = 0; + + + do + { + AF_Segment link1 = seg1->link; + + + if ( link1 ) + { + dist2 = AF_SEGMENT_DIST( link, link1 ); + if ( dist2 >= edge_distance_threshold ) + break; + } + + } while ( ( seg1 = seg1->edge_next ) != edge->first ); + + if ( dist2 >= edge_distance_threshold ) + continue; + } + + best = dist; + found = edge; + } + } + + if ( !found ) + { + AF_Edge edge; + + + /* insert a new edge in the list and */ + /* sort according to the position */ + error = af_axis_hints_new_edge( axis, seg->pos, + (AF_Direction)seg->dir, 0, + memory, &edge ); + if ( error ) + goto Exit; + + /* add the segment to the new edge's list */ + FT_ZERO( edge ); + + edge->first = seg; + edge->last = seg; + edge->dir = seg->dir; + edge->fpos = seg->pos; + edge->opos = FT_MulFix( seg->pos, scale ); + edge->pos = edge->opos; + seg->edge_next = seg; + } + else + { + /* if an edge was found, simply add the segment to the edge's */ + /* list */ + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } + + /******************************************************************* + * + * Good, we now compute each edge's properties according to the + * segments found on its position. Basically, these are + * + * - the edge's main direction + * - stem edge, serif edge or both (which defaults to stem then) + * - rounded edge, straight or both (which defaults to straight) + * - link for edge + * + */ + + /* first of all, set the `edge' field in each segment -- this is */ + /* required in order to compute edge links */ + + /* + * Note that removing this loop and setting the `edge' field of each + * segment directly in the code above slows down execution speed for + * some reasons on platforms like the Sun. + */ + { + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + + /* now compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Int is_round = 0; /* does it contain round segments? */ + FT_Int is_straight = 0; /* does it contain straight segments? */ + + + seg = edge->first; + if ( !seg ) + goto Skip_Loop; + + do + { + FT_Bool is_serif; + + + /* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; + + /* check for links -- if seg->serif is set, then seg->link must */ + /* be ignored */ + is_serif = FT_BOOL( seg->serif && seg->serif->edge != edge ); + + if ( seg->link || is_serif ) + { + AF_Edge edge2; + AF_Segment seg2; + + + edge2 = edge->link; + seg2 = seg->link; + + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + + + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + + seg_delta = AF_SEGMENT_DIST( seg, seg2 ); + + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + + Skip_Loop: + /* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; + + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; + + /* get rid of serifs if link is set */ + /* XXX: This gets rid of many unpleasant artefacts! */ + /* Example: the `c' in cour.pfa at size 13 */ + + if ( edge->serif && edge->link ) + edge->serif = NULL; + } + } + + Exit: + return error; + } + + + /* Detect segments and edges for given dimension. */ + + static FT_Error + af_cjk_hints_detect_features( AF_GlyphHints hints, + AF_Dimension dim ) + { + FT_Error error; + + + error = af_cjk_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_cjk_hints_link_segments( hints, dim ); + + error = af_cjk_hints_compute_edges( hints, dim ); + } + return error; + } + + + /* Compute all edges which lie within blue zones. */ + + static void + af_cjk_hints_compute_blue_edges( AF_GlyphHints hints, + AF_CJKMetrics metrics, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); + AF_CJKAxis cjk = &metrics->axis[dim]; + FT_Fixed scale = cjk->scale; + FT_Pos best_dist0; /* initial threshold */ + + + /* compute the initial threshold as a fraction of the EM size */ + best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale ); + + if ( best_dist0 > 64 / 2 ) /* maximum 1/2 pixel */ + best_dist0 = 64 / 2; + + /* compute which blue zones are active, i.e. have their scaled */ + /* size < 3/4 pixels */ + + /* If the distant between an edge and a blue zone is shorter than */ + /* best_dist0, set the blue zone for the edge. Then search for */ + /* the blue zone with the smallest best_dist to the edge. */ + + for ( ; edge < edge_limit; edge++ ) + { + FT_UInt bb; + AF_Width best_blue = NULL; + FT_Pos best_dist = best_dist0; + + + for ( bb = 0; bb < cjk->blue_count; bb++ ) + { + AF_CJKBlue blue = cjk->blues + bb; + FT_Bool is_top_right_blue, is_major_dir; + + + /* skip inactive blue zones (i.e., those that are too small) */ + if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) ) + continue; + + /* if it is a top zone, check for right edges -- if it is a bottom */ + /* zone, check for left edges */ + /* */ + /* of course, that's for TrueType */ + is_top_right_blue = + (FT_Byte)( ( blue->flags & AF_CJK_BLUE_TOP ) != 0 ); + is_major_dir = + FT_BOOL( edge->dir == axis->major_dir ); + + /* if it is a top zone, the edge must be against the major */ + /* direction; if it is a bottom zone, it must be in the major */ + /* direction */ + if ( is_top_right_blue ^ is_major_dir ) + { + FT_Pos dist; + AF_Width compare; + + + /* Compare the edge to the closest blue zone type */ + if ( FT_ABS( edge->fpos - blue->ref.org ) > + FT_ABS( edge->fpos - blue->shoot.org ) ) + compare = &blue->shoot; + else + compare = &blue->ref; + + dist = edge->fpos - compare->org; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = compare; + } + } + } + + if ( best_blue ) + edge->blue_edge = best_blue; + } + } + + + /* Initalize hinting engine. */ + + FT_LOCAL_DEF( FT_Error ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */ + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + FT_Render_Mode mode; + FT_UInt32 scaler_flags, other_flags; + + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); + + /* + * correct x_scale and y_scale when needed, since they may have + * been modified af_cjk_scale_dim above + */ + hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; + hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; + hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; + hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; + + /* compute flags depending on render mode, etc. */ + mode = metrics->root.scaler.render_mode; + + scaler_flags = hints->scaler_flags; + other_flags = 0; + + /* + * We snap the width of vertical stems for the monochrome and + * horizontal LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_HORZ_SNAP; + + /* + * We snap the width of horizontal stems for the monochrome and + * vertical LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) + other_flags |= AF_LATIN_HINTS_VERT_SNAP; + + /* + * We adjust stems to full pixels unless in `light' or `lcd' mode. + */ + if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_STEM_ADJUST; + + if ( mode == FT_RENDER_MODE_MONO ) + other_flags |= AF_LATIN_HINTS_MONO; + + scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE; + + hints->scaler_flags = scaler_flags; + hints->other_flags = other_flags; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L Y P H G R I D - F I T T I N G *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* Snap a given width in scaled coordinates to one of the */ + /* current standard widths. */ + + static FT_Pos + af_cjk_snap_width( AF_Width widths, + FT_UInt count, + FT_Pos width ) + { + FT_UInt n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + FT_Pos scaled; + + + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + scaled = FT_PIX_ROUND( reference ); + + if ( width >= reference ) + { + if ( width < scaled + 48 ) + width = reference; + } + else + { + if ( width > scaled - 48 ) + width = reference; + } + + return width; + } + + + /* Compute the snapped width of a given stem. */ + /* There is a lot of voodoo in this function; changing the hard-coded */ + /* parameters influence the whole hinting process. */ + + static FT_Pos + af_cjk_compute_stem_width( AF_GlyphHints hints, + AF_Dimension dim, + FT_Pos width, + FT_UInt base_flags, + FT_UInt stem_flags ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)hints->metrics; + AF_CJKAxis axis = &metrics->axis[dim]; + FT_Pos dist = width; + FT_Int sign = 0; + FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT ); + + FT_UNUSED( base_flags ); + FT_UNUSED( stem_flags ); + + + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + return width; + + if ( dist < 0 ) + { + dist = -width; + sign = 1; + } + + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + { + /* smooth hinting process: very lightly quantize the stem width */ + + if ( axis->width_count > 0 ) + { + if ( FT_ABS( dist - axis->widths[0].cur ) < 40 ) + { + dist = axis->widths[0].cur; + if ( dist < 48 ) + dist = 48; + + goto Done_Width; + } + } + + if ( dist < 54 ) + dist += ( 54 - dist ) / 2; + else if ( dist < 3 * 64 ) + { + FT_Pos delta; + + + delta = dist & 63; + dist &= -64; + + if ( delta < 10 ) + dist += delta; + else if ( delta < 22 ) + dist += 10; + else if ( delta < 42 ) + dist += delta; + else if ( delta < 54 ) + dist += 54; + else + dist += delta; + } + } + else + { + /* strong hinting process: snap the stem width to integer pixels */ + + dist = af_cjk_snap_width( axis->widths, axis->width_count, dist ); + + if ( vertical ) + { + /* in the case of vertical hinting, always round */ + /* the stem heights to integer pixels */ + + if ( dist >= 64 ) + dist = ( dist + 16 ) & ~63; + else + dist = 64; + } + else + { + if ( AF_LATIN_HINTS_DO_MONO( hints ) ) + { + /* monochrome horizontal hinting: snap widths to integer pixels */ + /* with a different threshold */ + + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & ~63; + } + else + { + /* for horizontal anti-aliased hinting, we adopt a more subtle */ + /* approach: we strengthen small stems, round stems whose size */ + /* is between 1 and 2 pixels to an integer, otherwise nothing */ + + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + + else if ( dist < 128 ) + dist = ( dist + 22 ) & ~63; + else + /* round otherwise to prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & ~63; + } + } + } + + Done_Width: + if ( sign ) + dist = -dist; + + return dist; + } + + + /* Align one stem edge relative to the previous stem edge. */ + + static void + af_cjk_align_linked_edge( AF_GlyphHints hints, + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) + { + FT_Pos dist = stem_edge->opos - base_edge->opos; + + FT_Pos fitted_width = af_cjk_compute_stem_width( hints, dim, dist, + base_edge->flags, + stem_edge->flags ); + + + stem_edge->pos = base_edge->pos + fitted_width; + + FT_TRACE5(( " CJKLINK: edge %td @%d (opos=%.2f) linked to %.2f," + " dist was %.2f, now %.2f\n", + stem_edge - hints->axis[dim].edges, stem_edge->fpos, + (double)stem_edge->opos / 64, + (double)stem_edge->pos / 64, + (double)dist / 64, + (double)fitted_width / 64 )); + } + + + /* Shift the coordinates of the `serif' edge by the same amount */ + /* as the corresponding `base' edge has been moved already. */ + + static void + af_cjk_align_serif_edge( AF_GlyphHints hints, + AF_Edge base, + AF_Edge serif ) + { + FT_UNUSED( hints ); + + serif->pos = base->pos + ( serif->opos - base->opos ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** E D G E H I N T I N G ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define AF_LIGHT_MODE_MAX_HORZ_GAP 9 +#define AF_LIGHT_MODE_MAX_VERT_GAP 15 +#define AF_LIGHT_MODE_MAX_DELTA_ABS 14 + + + static FT_Pos + af_hint_normal_stem( AF_GlyphHints hints, + AF_Edge edge, + AF_Edge edge2, + FT_Pos anchor, + AF_Dimension dim ) + { + FT_Pos org_len, cur_len, org_center; + FT_Pos cur_pos1, cur_pos2; + FT_Pos d_off1, u_off1, d_off2, u_off2, delta; + FT_Pos offset; + FT_Pos threshold = 64; + + + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + { + if ( ( edge->flags & AF_EDGE_ROUND ) && + ( edge2->flags & AF_EDGE_ROUND ) ) + { + if ( dim == AF_DIMENSION_VERT ) + threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP; + else + threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP; + } + else + { + if ( dim == AF_DIMENSION_VERT ) + threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3; + else + threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3; + } + } + + org_len = edge2->opos - edge->opos; + cur_len = af_cjk_compute_stem_width( hints, dim, org_len, + edge->flags, + edge2->flags ); + + org_center = ( edge->opos + edge2->opos ) / 2 + anchor; + cur_pos1 = org_center - cur_len / 2; + cur_pos2 = cur_pos1 + cur_len; + d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 ); + d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 ); + u_off1 = 64 - d_off1; + u_off2 = 64 - d_off2; + delta = 0; + + + if ( d_off1 == 0 || d_off2 == 0 ) + goto Exit; + + if ( cur_len <= threshold ) + { + if ( d_off2 < cur_len ) + { + if ( u_off1 <= d_off2 ) + delta = u_off1; + else + delta = -d_off2; + } + + goto Exit; + } + + if ( threshold < 64 ) + { + if ( d_off1 >= threshold || u_off1 >= threshold || + d_off2 >= threshold || u_off2 >= threshold ) + goto Exit; + } + + offset = cur_len & 63; + + if ( offset < 32 ) + { + if ( u_off1 <= offset || d_off2 <= offset ) + goto Exit; + } + else + offset = 64 - threshold; + + d_off1 = threshold - u_off1; + u_off1 = u_off1 - offset; + u_off2 = threshold - d_off2; + d_off2 = d_off2 - offset; + + if ( d_off1 <= u_off1 ) + u_off1 = -d_off1; + + if ( d_off2 <= u_off2 ) + u_off2 = -d_off2; + + if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) ) + delta = u_off1; + else + delta = u_off2; + + Exit: + +#if 1 + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + { + if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS ) + delta = AF_LIGHT_MODE_MAX_DELTA_ABS; + else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS ) + delta = -AF_LIGHT_MODE_MAX_DELTA_ABS; + } +#endif + + cur_pos1 += delta; + + if ( edge->opos < edge2->opos ) + { + edge->pos = cur_pos1; + edge2->pos = cur_pos1 + cur_len; + } + else + { + edge->pos = cur_pos1 + cur_len; + edge2->pos = cur_pos1; + } + + return delta; + } + + + /* The main grid-fitting routine. */ + + static void + af_cjk_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + FT_PtrDist n_edges; + AF_Edge edge; + AF_Edge anchor = NULL; + FT_Pos delta = 0; + FT_Int skipped = 0; + FT_Bool has_last_stem = FALSE; + FT_Pos last_stem_pos = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt num_actions = 0; +#endif + + + FT_TRACE5(( "cjk %s edge hinting (style `%s')\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", + af_style_names[hints->metrics->style_class->style] )); + + /* we begin by aligning all stems relative to the blue zone */ + + if ( AF_HINTS_DO_BLUES( hints ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; + AF_Edge edge1, edge2; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + blue = edge->blue_edge; + edge1 = NULL; + edge2 = edge->link; + + if ( blue ) + { + edge1 = edge; + } + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + + if ( !edge1 ) + continue; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " CJKBLUE: edge %td @%d (opos=%.2f) snapped to %.2f," + " was %.2f\n", + edge1 - edges, edge1->fpos, (double)edge1->opos / 64, + (double)blue->fit / 64, (double)edge1->pos / 64 )); + + num_actions++; +#endif + + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + + if ( edge2 && !edge2->blue_edge ) + { + af_cjk_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + } + + if ( !anchor ) + anchor = edge; + } + } + + /* now we align all stem edges. */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge edge2; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + /* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + skipped++; + continue; + } + + /* Some CJK characters have so many stems that + * the hinter is likely to merge two adjacent ones. + * To solve this problem, if either edge of a stem + * is too close to the previous one, we avoid + * aligning the two edges, but rather interpolate + * their locations at the end of this function in + * order to preserve the space between the stems. + */ + if ( has_last_stem && + ( edge->pos < last_stem_pos + 64 || + edge2->pos < last_stem_pos + 64 ) ) + { + skipped++; + continue; + } + + /* now align the stem */ + + /* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( "ASSERTION FAILED for edge %td\n", edge2 - edges )); + + af_cjk_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + + continue; + } + + if ( edge2 < edge ) + { + af_cjk_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + + /* We rarely reaches here it seems; + * usually the two edges belonging + * to one stem are marked as DONE together + */ + has_last_stem = TRUE; + last_stem_pos = edge->pos; + continue; + } + + if ( dim != AF_DIMENSION_VERT && !anchor ) + { + +#if 0 + if ( fixedpitch ) + { + AF_Edge left = edge; + AF_Edge right = edge_limit - 1; + AF_EdgeRec left1, left2, right1, right2; + FT_Pos target, center1, center2; + FT_Pos delta1, delta2, d1, d2; + + + while ( right > left && !right->link ) + right--; + + left1 = *left; + left2 = *left->link; + right1 = *right->link; + right2 = *right; + + delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2; + target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16; + + delta1 = delta; + delta1 += af_hint_normal_stem( hints, left, left->link, + delta1, 0 ); + + if ( left->link != right ) + af_hint_normal_stem( hints, right->link, right, delta1, 0 ); + + center1 = left->pos + ( right->pos - left->pos ) / 2; + + if ( center1 >= target ) + delta2 = delta - 32; + else + delta2 = delta + 32; + + delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 ); + + if ( delta1 != delta2 ) + { + if ( left->link != right ) + af_hint_normal_stem( hints, &right1, &right2, delta2, 0 ); + + center2 = left1.pos + ( right2.pos - left1.pos ) / 2; + + d1 = center1 - target; + d2 = center2 - target; + + if ( FT_ABS( d2 ) < FT_ABS( d1 ) ) + { + left->pos = left1.pos; + left->link->pos = left2.pos; + + if ( left->link != right ) + { + right->link->pos = right1.pos; + right->pos = right2.pos; + } + + delta1 = delta2; + } + } + + delta = delta1; + right->link->flags |= AF_EDGE_DONE; + right->flags |= AF_EDGE_DONE; + } + else + +#endif /* 0 */ + + delta = af_hint_normal_stem( hints, edge, edge2, 0, + AF_DIMENSION_HORZ ); + } + else + af_hint_normal_stem( hints, edge, edge2, delta, dim ); + +#if 0 + printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n", + edge - edges, edge2 - edges, + (double)( edge->pos - edge->opos ) / 64, + (double)( edge2->pos - edge2->opos ) / 64 ); +#endif + + anchor = edge; + edge->flags |= AF_EDGE_DONE; + edge2->flags |= AF_EDGE_DONE; + has_last_stem = TRUE; + last_stem_pos = edge2->pos; + } + + /* make sure that lowercase m's maintain their symmetry */ + + /* In general, lowercase m's have six vertical edges if they are sans */ + /* serif, or twelve if they are with serifs. This implementation is */ + /* based on that assumption, and seems to work very well with most */ + /* faces. However, if for a certain face this assumption is not */ + /* true, the m is just rendered like before. In addition, any stem */ + /* correction will only be applied to symmetrical glyphs (even if the */ + /* glyph is not an m), so the potential for unwanted distortion is */ + /* relatively low. */ + + /* We don't handle horizontal edges since we can't easily assure that */ + /* the third (lowest) stem aligns with the base line; it might end up */ + /* one pixel higher or lower. */ + + n_edges = edge_limit - edges; + if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) + { + AF_Edge edge1, edge2, edge3; + FT_Pos dist1, dist2, span; + + + if ( n_edges == 6 ) + { + edge1 = edges; + edge2 = edges + 2; + edge3 = edges + 4; + } + else + { + edge1 = edges + 1; + edge2 = edges + 5; + edge3 = edges + 9; + } + + dist1 = edge2->opos - edge1->opos; + dist2 = edge3->opos - edge2->opos; + + span = dist1 - dist2; + if ( span < 0 ) + span = -span; + + if ( edge1->link == edge1 + 1 && + edge2->link == edge2 + 1 && + edge3->link == edge3 + 1 && span < 8 ) + { + delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); + edge3->pos -= delta; + if ( edge3->link ) + edge3->link->pos -= delta; + + /* move the serifs along with the stem */ + if ( n_edges == 12 ) + { + ( edges + 8 )->pos -= delta; + ( edges + 11 )->pos -= delta; + } + + edge3->flags |= AF_EDGE_DONE; + if ( edge3->link ) + edge3->link->flags |= AF_EDGE_DONE; + } + } + + if ( !skipped ) + goto Exit; + + /* + * now hint the remaining edges (serifs and single) in order + * to complete our processing + */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + if ( edge->flags & AF_EDGE_DONE ) + continue; + + if ( edge->serif ) + { + af_cjk_align_serif_edge( hints, edge->serif, edge ); + edge->flags |= AF_EDGE_DONE; + skipped--; + } + } + + if ( !skipped ) + goto Exit; + + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge before, after; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + before = after = edge; + + while ( --before >= edges ) + if ( before->flags & AF_EDGE_DONE ) + break; + + while ( ++after < edge_limit ) + if ( after->flags & AF_EDGE_DONE ) + break; + + if ( before >= edges || after < edge_limit ) + { + if ( before < edges ) + af_cjk_align_serif_edge( hints, after, edge ); + else if ( after >= edge_limit ) + af_cjk_align_serif_edge( hints, before, edge ); + else + { + if ( after->fpos == before->fpos ) + edge->pos = before->pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->fpos - before->fpos, + after->pos - before->pos, + after->fpos - before->fpos ); + } + } + } + + Exit: + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !num_actions ) + FT_TRACE5(( " (none)\n" )); + FT_TRACE5(( "\n" )); +#endif + + return; + } + + + static void + af_cjk_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + FT_Bool snapping; + + + snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ && + AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) || + ( dim == AF_DIMENSION_VERT && + AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ); + + for ( edge = edges; edge < edge_limit; edge++ ) + { + /* move the points of each segment */ + /* in each edge to the edge's position */ + AF_Segment seg = edge->first; + + + if ( snapping ) + { + do + { + AF_Point point = seg->first; + + + for (;;) + { + if ( dim == AF_DIMENSION_HORZ ) + { + point->x = edge->pos; + point->flags |= AF_FLAG_TOUCH_X; + } + else + { + point->y = edge->pos; + point->flags |= AF_FLAG_TOUCH_Y; + } + + if ( point == seg->last ) + break; + + point = point->next; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + else + { + FT_Pos delta = edge->pos - edge->opos; + + + do + { + AF_Point point = seg->first; + + + for (;;) + { + if ( dim == AF_DIMENSION_HORZ ) + { + point->x += delta; + point->flags |= AF_FLAG_TOUCH_X; + } + else + { + point->y += delta; + point->flags |= AF_FLAG_TOUCH_Y; + } + + if ( point == seg->last ) + break; + + point = point->next; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + } + } + + + /* Apply the complete hinting algorithm to a CJK glyph. */ + + FT_LOCAL_DEF( FT_Error ) + af_cjk_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */ + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + FT_Error error; + int dim; + + FT_UNUSED( metrics ); + FT_UNUSED( glyph_index ); + + + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; + + /* analyze glyph outline */ + if ( AF_HINTS_DO_HORIZONTAL( hints ) ) + { + error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ ); + } + + if ( AF_HINTS_DO_VERTICAL( hints ) ) + { + error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT ); + } + + /* grid-fit the outline */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || + ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + { + af_cjk_hint_edges( hints, (AF_Dimension)dim ); + af_cjk_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + } + + af_glyph_hints_save( hints, outline ); + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K S C R I P T C L A S S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, + + AF_WRITING_SYSTEM_CJK, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) af_cjk_metrics_init, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)af_cjk_metrics_scale, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)af_cjk_get_standard_widths, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_cjk_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_cjk_hints_apply /* style_hints_apply */ + ) + + +#else /* !AF_CONFIG_OPTION_CJK */ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, + + AF_WRITING_SYSTEM_CJK, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) NULL, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) NULL /* style_hints_apply */ + ) + + +#endif /* !AF_CONFIG_OPTION_CJK */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afcjk.h b/vendor/freetype/src/autofit/afcjk.h new file mode 100644 index 0000000..f380ef6 --- /dev/null +++ b/vendor/freetype/src/autofit/afcjk.h @@ -0,0 +1,141 @@ +/**************************************************************************** + * + * afcjk.h + * + * Auto-fitter hinting routines for CJK writing system (specification). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFCJK_H_ +#define AFCJK_H_ + +#include "afhints.h" +#include "aflatin.h" + + +FT_BEGIN_HEADER + + + /* the CJK-specific writing system */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_cjk_writing_system_class ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* + * CJK glyphs tend to fill the square. So we have both vertical and + * horizontal blue zones. But some glyphs have flat bounding strokes that + * leave some space between neighbour glyphs. + */ + +#define AF_CJK_IS_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_CJK_TOP ) +#define AF_CJK_IS_HORIZ_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_CJK_HORIZ ) +#define AF_CJK_IS_RIGHT_BLUE AF_CJK_IS_TOP_BLUE + +#define AF_CJK_MAX_WIDTHS 16 + + +#define AF_CJK_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ +#define AF_CJK_BLUE_TOP ( 1U << 1 ) /* result of AF_CJK_IS_TOP_BLUE */ +#define AF_CJK_BLUE_ADJUSTMENT ( 1U << 2 ) /* used for scale adjustment */ + /* optimization */ + + + typedef struct AF_CJKBlueRec_ + { + AF_WidthRec ref; + AF_WidthRec shoot; /* undershoot */ + FT_UInt flags; + + } AF_CJKBlueRec, *AF_CJKBlue; + + + typedef struct AF_CJKAxisRec_ + { + FT_Fixed scale; + FT_Pos delta; + + FT_UInt width_count; /* number of used widths */ + AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; /* widths array */ + FT_Pos edge_distance_threshold; /* used for creating edges */ + FT_Pos standard_width; /* the default stem thickness */ + FT_Bool extra_light; /* is standard width very light? */ + + /* used for horizontal metrics too for CJK */ + FT_Bool control_overshoot; + FT_UInt blue_count; + AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX]; + + FT_Fixed org_scale; + FT_Pos org_delta; + + } AF_CJKAxisRec, *AF_CJKAxis; + + + typedef struct AF_CJKMetricsRec_ + { + AF_StyleMetricsRec root; + FT_UInt units_per_em; + AF_CJKAxisRec axis[AF_DIMENSION_MAX]; + + } AF_CJKMetricsRec, *AF_CJKMetrics; + + +#ifdef AF_CONFIG_OPTION_CJK + FT_LOCAL( FT_Error ) + af_cjk_metrics_init( AF_StyleMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_cjk_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ); + + FT_LOCAL( FT_Error ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ); + + FT_LOCAL( FT_Error ) + af_cjk_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ); + + /* shared; called from afindic.c */ + FT_LOCAL( void ) + af_cjk_metrics_check_digits( AF_CJKMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_cjk_metrics_init_widths( AF_CJKMetrics metrics, + FT_Face face ); +#endif /* AF_CONFIG_OPTION_CJK */ + + +/* */ + +FT_END_HEADER + +#endif /* AFCJK_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afcover.h b/vendor/freetype/src/autofit/afcover.h new file mode 100644 index 0000000..102ed42 --- /dev/null +++ b/vendor/freetype/src/autofit/afcover.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * + * afcover.h + * + * Auto-fitter coverages (specification only). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* This header file can be included multiple times. */ + /* Define `COVERAGE' as needed. */ + + + /* Add new coverages here. The first and second arguments are the */ + /* coverage name in lowercase and uppercase, respectively, followed */ + /* by a description string. The last four arguments are the four */ + /* characters defining the corresponding OpenType feature. */ + +#if 0 + /* XXX: It's not possible to define blue zone characters in advance. */ + COVERAGE( alternative_fractions, ALTERNATIVE_FRACTIONS, + "alternative fractions", + 'a', 'f', 'r', 'c' ) +#endif + + COVERAGE( petite_capitals_from_capitals, PETITE_CAPITALS_FROM_CAPITALS, + "petite capitals from capitals", + 'c', '2', 'c', 'p' ) + + COVERAGE( small_capitals_from_capitals, SMALL_CAPITALS_FROM_CAPITALS, + "small capitals from capitals", + 'c', '2', 's', 'c' ) + +#if 0 + /* XXX: Only digits are in this coverage, however, both normal style */ + /* and oldstyle representation forms are possible. */ + COVERAGE( denominators, DENOMINATORS, + "denominators", + 'd', 'n', 'o', 'm' ) +#endif + +#if 0 + /* XXX: It's not possible to define blue zone characters in advance. */ + COVERAGE( fractions, FRACTIONS, + "fractions", + 'f', 'r', 'a', 'c' ) +#endif + +#if 0 + /* XXX: Only digits are in this coverage, however, both normal style */ + /* and oldstyle representation forms are possible. */ + COVERAGE( numerators, NUMERATORS, + "numerators", + 'n', 'u', 'm', 'r' ) +#endif + + COVERAGE( ordinals, ORDINALS, + "ordinals", + 'o', 'r', 'd', 'n' ) + + COVERAGE( petite_capitals, PETITE_CAPITALS, + "petite capitals", + 'p', 'c', 'a', 'p' ) + + COVERAGE( ruby, RUBY, + "ruby", + 'r', 'u', 'b', 'y' ) + + COVERAGE( scientific_inferiors, SCIENTIFIC_INFERIORS, + "scientific inferiors", + 's', 'i', 'n', 'f' ) + + COVERAGE( small_capitals, SMALL_CAPITALS, + "small capitals", + 's', 'm', 'c', 'p' ) + + COVERAGE( subscript, SUBSCRIPT, + "subscript", + 's', 'u', 'b', 's' ) + + COVERAGE( superscript, SUPERSCRIPT, + "superscript", + 's', 'u', 'p', 's' ) + + COVERAGE( titling, TITLING, + "titling", + 't', 'i', 't', 'l' ) + +#if 0 + /* to be always excluded */ + COVERAGE(nalt, 'n', 'a', 'l', 't'); /* Alternate Annotation Forms (?) */ + COVERAGE(ornm, 'o', 'r', 'n', 'm'); /* Ornaments (?) */ +#endif + + +/* END */ diff --git a/vendor/freetype/src/autofit/afdummy.c b/vendor/freetype/src/autofit/afdummy.c new file mode 100644 index 0000000..a4629b5 --- /dev/null +++ b/vendor/freetype/src/autofit/afdummy.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * afdummy.c + * + * Auto-fitter dummy routines to be used if no hinting should be + * performed (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afdummy.h" +#include "afhints.h" +#include "aferrors.h" + + + static FT_Error + af_dummy_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ) + { + af_glyph_hints_rescale( hints, metrics ); + + hints->x_scale = metrics->scaler.x_scale; + hints->y_scale = metrics->scaler.y_scale; + hints->x_delta = metrics->scaler.x_delta; + hints->y_delta = metrics->scaler.y_delta; + + return FT_Err_Ok; + } + + + static FT_Error + af_dummy_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ) + { + FT_Error error; + + FT_UNUSED( glyph_index ); + FT_UNUSED( metrics ); + + + error = af_glyph_hints_reload( hints, outline ); + if ( !error ) + af_glyph_hints_save( hints, outline ); + + return error; + } + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_dummy_writing_system_class, + + AF_WRITING_SYSTEM_DUMMY, + + sizeof ( AF_StyleMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_dummy_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_dummy_hints_apply /* style_hints_apply */ + ) + + +/* END */ diff --git a/vendor/freetype/src/autofit/afdummy.h b/vendor/freetype/src/autofit/afdummy.h new file mode 100644 index 0000000..a7af3f6 --- /dev/null +++ b/vendor/freetype/src/autofit/afdummy.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * + * afdummy.h + * + * Auto-fitter dummy routines to be used if no hinting should be + * performed (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFDUMMY_H_ +#define AFDUMMY_H_ + +#include "aftypes.h" + + +FT_BEGIN_HEADER + + /* A dummy writing system used when no hinting should be performed. */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_dummy_writing_system_class ) + +/* */ + +FT_END_HEADER + + +#endif /* AFDUMMY_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/aferrors.h b/vendor/freetype/src/autofit/aferrors.h new file mode 100644 index 0000000..88faf05 --- /dev/null +++ b/vendor/freetype/src/autofit/aferrors.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * aferrors.h + * + * Autofitter error codes (specification only). + * + * Copyright (C) 2005-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Autofitter error enumeration + * constants. + * + */ + +#ifndef AFERRORS_H_ +#define AFERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX AF_Err_ +#define FT_ERR_BASE FT_Mod_Err_Autofit + +#include + +#endif /* AFERRORS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afglobal.c b/vendor/freetype/src/autofit/afglobal.c new file mode 100644 index 0000000..b195757 --- /dev/null +++ b/vendor/freetype/src/autofit/afglobal.c @@ -0,0 +1,513 @@ +/**************************************************************************** + * + * afglobal.c + * + * Auto-fitter routines to compute global hinting values (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afglobal.h" +#include "afranges.h" +#include "afshaper.h" +#include "afws-decl.h" +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afglobal + + +#include "aferrors.h" + + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + AF_DEFINE_SCRIPT_CLASS( \ + af_ ## s ## _script_class, \ + AF_SCRIPT_ ## S, \ + af_ ## s ## _uniranges, \ + af_ ## s ## _nonbase_uniranges, \ + AF_ ## H, \ + ss ) + +#include "afscript.h" + + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + AF_DEFINE_STYLE_CLASS( \ + af_ ## s ## _style_class, \ + AF_STYLE_ ## S, \ + ws, \ + sc, \ + ss, \ + c ) + +#include "afstyles.h" + + +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) \ + &af_ ## ws ## _writing_system_class, + + FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass ) + af_writing_system_classes[] = + { + +#include "afws-iter.h" + + NULL /* do not remove */ + }; + + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + &af_ ## s ## _script_class, + + FT_LOCAL_ARRAY_DEF( AF_ScriptClass ) + af_script_classes[] = + { + +#include "afscript.h" + + NULL /* do not remove */ + }; + + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + &af_ ## s ## _style_class, + + FT_LOCAL_ARRAY_DEF( AF_StyleClass ) + af_style_classes[] = + { + +#include "afstyles.h" + + NULL /* do not remove */ + }; + + +#ifdef FT_DEBUG_LEVEL_TRACE + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) #s, + + FT_LOCAL_ARRAY_DEF( char* ) + af_style_names[] = + { + +#include "afstyles.h" + + }; + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /* Compute the style index of each glyph within a given face. */ + + static FT_Error + af_face_globals_compute_style_coverage( AF_FaceGlobals globals ) + { + FT_Error error; + FT_Face face = globals->face; + FT_CharMap old_charmap = face->charmap; + FT_UShort* gstyles = globals->glyph_styles; + FT_UShort ss; + FT_UShort dflt = 0xFFFFU; /* a non-valid value */ + FT_UInt i; + + + /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */ + for ( i = 0; i < globals->glyph_count; i++ ) + gstyles[i] = AF_STYLE_UNASSIGNED; + + error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); + if ( error ) + { + /* + * Ignore this error; we simply use the fallback style. + * XXX: Shouldn't we rather disable hinting? + */ + error = FT_Err_Ok; + goto Exit; + } + + /* scan each style in a Unicode charmap */ + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = + af_style_classes[ss]; + AF_ScriptClass script_class = + af_script_classes[style_class->script]; + AF_Script_UniRange range; + + + if ( !script_class->script_uni_ranges ) + continue; + + /* + * Scan all Unicode points in the range and set the corresponding + * glyph style index. + */ + if ( style_class->coverage == AF_COVERAGE_DEFAULT ) + { + if ( style_class->script == globals->module->default_script ) + dflt = ss; + + for ( range = script_class->script_uni_ranges; + range->first != 0; + range++ ) + { + FT_ULong charcode = range->first; + FT_UInt gindex; + + + gindex = FT_Get_Char_Index( face, charcode ); + + if ( gindex != 0 && + gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) + gstyles[gindex] = ss; + + for (;;) + { + charcode = FT_Get_Next_Char( face, charcode, &gindex ); + + if ( gindex == 0 || charcode > range->last ) + break; + + if ( gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) + gstyles[gindex] = ss; + } + } + + /* do the same for the script's non-base characters */ + for ( range = script_class->script_uni_nonbase_ranges; + range->first != 0; + range++ ) + { + FT_ULong charcode = range->first; + FT_UInt gindex; + + + gindex = FT_Get_Char_Index( face, charcode ); + + if ( gindex != 0 && + gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == ss ) + gstyles[gindex] |= AF_NONBASE; + + for (;;) + { + charcode = FT_Get_Next_Char( face, charcode, &gindex ); + + if ( gindex == 0 || charcode > range->last ) + break; + + if ( gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == ss ) + gstyles[gindex] |= AF_NONBASE; + } + } + } + else + { + /* get glyphs not directly addressable by cmap */ + af_shaper_get_coverage( globals, style_class, gstyles, 0 ); + } + } + + /* handle the remaining default OpenType features ... */ + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = af_style_classes[ss]; + + + if ( style_class->coverage == AF_COVERAGE_DEFAULT ) + af_shaper_get_coverage( globals, style_class, gstyles, 0 ); + } + + /* ... and finally the default OpenType features of the default script */ + af_shaper_get_coverage( globals, af_style_classes[dflt], gstyles, 1 ); + + /* mark ASCII digits */ + for ( i = 0x30; i <= 0x39; i++ ) + { + FT_UInt gindex = FT_Get_Char_Index( face, i ); + + + if ( gindex != 0 && gindex < globals->glyph_count ) + gstyles[gindex] |= AF_DIGIT; + } + + Exit: + /* + * By default, all uncovered glyphs are set to the fallback style. + * XXX: Shouldn't we disable hinting or do something similar? + */ + if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) + { + FT_UInt nn; + + + for ( nn = 0; nn < globals->glyph_count; nn++ ) + { + if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) + { + gstyles[nn] &= ~AF_STYLE_MASK; + gstyles[nn] |= globals->module->fallback_style; + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + + FT_TRACE4(( "\n" )); + FT_TRACE4(( "style coverage\n" )); + FT_TRACE4(( "==============\n" )); + FT_TRACE4(( "\n" )); + + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = af_style_classes[ss]; + FT_UInt count = 0; + FT_UInt idx; + + + FT_TRACE4(( "%s:\n", af_style_names[style_class->style] )); + + for ( idx = 0; idx < globals->glyph_count; idx++ ) + { + if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style ) + { + if ( !( count % 10 ) ) + FT_TRACE4(( " " )); + + FT_TRACE4(( " %d", idx )); + count++; + + if ( !( count % 10 ) ) + FT_TRACE4(( "\n" )); + } + } + + if ( !count ) + FT_TRACE4(( " (none)\n" )); + if ( count % 10 ) + FT_TRACE4(( "\n" )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + face->charmap = old_charmap; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + af_face_globals_new( FT_Face face, + AF_FaceGlobals *aglobals, + AF_Module module ) + { + FT_Error error; + FT_Memory memory; + AF_FaceGlobals globals = NULL; + + + memory = face->memory; + + /* we allocate an AF_FaceGlobals structure together */ + /* with the glyph_styles array */ + if ( FT_QALLOC( globals, + sizeof ( *globals ) + + (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) ) + goto Exit; + + FT_ZERO( &globals->metrics ); + + globals->face = face; + globals->glyph_count = (FT_UInt)face->num_glyphs; + /* right after the globals structure come the glyph styles */ + globals->glyph_styles = (FT_UShort*)( globals + 1 ); + globals->module = module; + globals->stem_darkening_for_ppem = 0; + globals->darken_x = 0; + globals->darken_y = 0; + globals->standard_vertical_width = 0; + globals->standard_horizontal_width = 0; + globals->scale_down_factor = 0; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + globals->hb_font = hb_ft_font_create_( face, NULL ); + globals->hb_buf = hb_buffer_create(); +#endif + + error = af_face_globals_compute_style_coverage( globals ); + if ( error ) + { + af_face_globals_free( globals ); + globals = NULL; + } + else + globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; + + Exit: + *aglobals = globals; + return error; + } + + + FT_LOCAL_DEF( void ) + af_face_globals_free( void* globals_ ) + { + AF_FaceGlobals globals = (AF_FaceGlobals)globals_; + + + if ( globals ) + { + FT_Memory memory = globals->face->memory; + FT_UInt nn; + + + for ( nn = 0; nn < AF_STYLE_MAX; nn++ ) + { + if ( globals->metrics[nn] ) + { + AF_StyleClass style_class = + af_style_classes[nn]; + AF_WritingSystemClass writing_system_class = + af_writing_system_classes[style_class->writing_system]; + + + if ( writing_system_class->style_metrics_done ) + writing_system_class->style_metrics_done( globals->metrics[nn] ); + + FT_FREE( globals->metrics[nn] ); + } + } + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + hb_font_destroy( globals->hb_font ); + hb_buffer_destroy( globals->hb_buf ); +#endif + + /* no need to free `globals->glyph_styles'; */ + /* it is part of the `globals' array */ + FT_FREE( globals ); + } + } + + + FT_LOCAL_DEF( FT_Error ) + af_face_globals_get_metrics( AF_FaceGlobals globals, + FT_UInt gindex, + FT_UInt options, + AF_StyleMetrics *ametrics ) + { + AF_StyleMetrics metrics = NULL; + + AF_Style style = (AF_Style)options; + AF_WritingSystemClass writing_system_class; + AF_StyleClass style_class; + + FT_Error error = FT_Err_Ok; + + + if ( gindex >= globals->glyph_count ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* if we have a forced style (via `options'), use it, */ + /* otherwise look into `glyph_styles' array */ + if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX ) + style = (AF_Style)( globals->glyph_styles[gindex] & + AF_STYLE_UNASSIGNED ); + + Again: + style_class = af_style_classes[style]; + writing_system_class = af_writing_system_classes + [style_class->writing_system]; + + metrics = globals->metrics[style]; + if ( !metrics ) + { + /* create the global metrics object if necessary */ + FT_Memory memory = globals->face->memory; + + + if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) ) + goto Exit; + + metrics->style_class = style_class; + metrics->globals = globals; + + if ( writing_system_class->style_metrics_init ) + { + error = writing_system_class->style_metrics_init( metrics, + globals->face ); + if ( error ) + { + if ( writing_system_class->style_metrics_done ) + writing_system_class->style_metrics_done( metrics ); + + FT_FREE( metrics ); + + /* internal error code -1 indicates */ + /* that no blue zones have been found */ + if ( error == -1 ) + { + style = (AF_Style)( globals->glyph_styles[gindex] & + AF_STYLE_UNASSIGNED ); + /* IMPORTANT: Clear the error code, see + * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1063 + */ + error = FT_Err_Ok; + goto Again; + } + + goto Exit; + } + } + + globals->metrics[style] = metrics; + } + + Exit: + *ametrics = metrics; + + return error; + } + + + FT_LOCAL_DEF( FT_Bool ) + af_face_globals_is_digit( AF_FaceGlobals globals, + FT_UInt gindex ) + { + if ( gindex < globals->glyph_count ) + return FT_BOOL( globals->glyph_styles[gindex] & AF_DIGIT ); + + return FT_BOOL( 0 ); + } + + +/* END */ diff --git a/vendor/freetype/src/autofit/afglobal.h b/vendor/freetype/src/autofit/afglobal.h new file mode 100644 index 0000000..66170e4 --- /dev/null +++ b/vendor/freetype/src/autofit/afglobal.h @@ -0,0 +1,173 @@ +/**************************************************************************** + * + * afglobal.h + * + * Auto-fitter routines to compute global hinting values + * (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFGLOBAL_H_ +#define AFGLOBAL_H_ + + +#include "aftypes.h" +#include "afmodule.h" +#include "afshaper.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL_ARRAY( AF_WritingSystemClass ) + af_writing_system_classes[]; + + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + AF_DECLARE_SCRIPT_CLASS( af_ ## s ## _script_class ) + +#include "afscript.h" + + FT_LOCAL_ARRAY( AF_ScriptClass ) + af_script_classes[]; + + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + AF_DECLARE_STYLE_CLASS( af_ ## s ## _style_class ) + +#include "afstyles.h" + + FT_LOCAL_ARRAY( AF_StyleClass ) + af_style_classes[]; + + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_LOCAL_ARRAY( char* ) + af_style_names[]; +#endif + + + /* + * Default values and flags for both autofitter globals (found in + * AF_ModuleRec) and face globals (in AF_FaceGlobalsRec). + */ + + /* index of fallback style in `af_style_classes' */ +#ifdef AF_CONFIG_OPTION_CJK +#define AF_STYLE_FALLBACK AF_STYLE_HANI_DFLT +#else +#define AF_STYLE_FALLBACK AF_STYLE_NONE_DFLT +#endif + /* default script for OpenType; ignored if HarfBuzz isn't used */ +#define AF_SCRIPT_DEFAULT AF_SCRIPT_LATN + + /* a bit mask for AF_DIGIT and AF_NONBASE */ +#define AF_STYLE_MASK 0x3FFF + /* an uncovered glyph */ +#define AF_STYLE_UNASSIGNED AF_STYLE_MASK + + /* if this flag is set, we have an ASCII digit */ +#define AF_DIGIT 0x8000U + /* if this flag is set, we have a non-base character */ +#define AF_NONBASE 0x4000U + + /* `increase-x-height' property */ +#define AF_PROP_INCREASE_X_HEIGHT_MIN 6 +#define AF_PROP_INCREASE_X_HEIGHT_MAX 0 + + + /************************************************************************/ + /************************************************************************/ + /***** *****/ + /***** F A C E G L O B A L S *****/ + /***** *****/ + /************************************************************************/ + /************************************************************************/ + + + /* + * Note that glyph_styles[] maps each glyph to an index into the + * `af_style_classes' array. + * + */ + typedef struct AF_FaceGlobalsRec_ + { + FT_Face face; + FT_UInt glyph_count; /* unsigned face->num_glyphs */ + FT_UShort* glyph_styles; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + hb_font_t* hb_font; + hb_buffer_t* hb_buf; /* for feature comparison */ +#endif + + /* per-face auto-hinter properties */ + FT_UInt increase_x_height; + + AF_StyleMetrics metrics[AF_STYLE_MAX]; + + /* Compute darkening amount once per size. Use this to check whether */ + /* darken_{x,y} needs to be recomputed. */ + FT_UShort stem_darkening_for_ppem; + /* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_HORZ] */ + /* to compute the darkening amount. */ + FT_Pos standard_vertical_width; + /* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_VERT] */ + /* to compute the darkening amount. */ + FT_Pos standard_horizontal_width; + /* The actual amount to darken a glyph along the X axis. */ + FT_Pos darken_x; + /* The actual amount to darken a glyph along the Y axis. */ + FT_Pos darken_y; + /* Amount to scale down by to keep emboldened points */ + /* on the Y-axis in pre-computed blue zones. */ + FT_Fixed scale_down_factor; + AF_Module module; /* to access global properties */ + + } AF_FaceGlobalsRec; + + + /* + * model the global hints data for a given face, decomposed into + * style-specific items + */ + + FT_LOCAL( FT_Error ) + af_face_globals_new( FT_Face face, + AF_FaceGlobals *aglobals, + AF_Module module ); + + FT_LOCAL( FT_Error ) + af_face_globals_get_metrics( AF_FaceGlobals globals, + FT_UInt gindex, + FT_UInt options, + AF_StyleMetrics *ametrics ); + + FT_LOCAL( void ) + af_face_globals_free( void* globals ); + + FT_LOCAL( FT_Bool ) + af_face_globals_is_digit( AF_FaceGlobals globals, + FT_UInt gindex ); + + /* */ + + +FT_END_HEADER + +#endif /* AFGLOBAL_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afhints.c b/vendor/freetype/src/autofit/afhints.c new file mode 100644 index 0000000..e4a378f --- /dev/null +++ b/vendor/freetype/src/autofit/afhints.c @@ -0,0 +1,1796 @@ +/**************************************************************************** + * + * afhints.c + * + * Auto-fitter hinting routines (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afhints.h" +#include "aferrors.h" +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afhints + + + FT_LOCAL_DEF( void ) + af_sort_pos( FT_UInt count, + FT_Pos* table ) + { + FT_UInt i, j; + FT_Pos swap; + + + for ( i = 1; i < count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j] >= table[j - 1] ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + } + + + FT_LOCAL_DEF( void ) + af_sort_and_quantize_widths( FT_UInt* count, + AF_Width table, + FT_Pos threshold ) + { + FT_UInt i, j; + FT_UInt cur_idx; + FT_Pos cur_val; + FT_Pos sum; + AF_WidthRec swap; + + + if ( *count == 1 ) + return; + + /* sort */ + for ( i = 1; i < *count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j].org >= table[j - 1].org ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + + cur_idx = 0; + cur_val = table[cur_idx].org; + + /* compute and use mean values for clusters not larger than */ + /* `threshold'; this is very primitive and might not yield */ + /* the best result, but normally, using reference character */ + /* `o', `*count' is 2, so the code below is fully sufficient */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org - cur_val > threshold || + i == *count - 1 ) + { + sum = 0; + + /* fix loop for end of array */ + if ( table[i].org - cur_val <= threshold && + i == *count - 1 ) + i++; + + for ( j = cur_idx; j < i; j++ ) + { + sum += table[j].org; + table[j].org = 0; + } + table[cur_idx].org = sum / (FT_Pos)j; + + if ( i < *count - 1 ) + { + cur_idx = i + 1; + cur_val = table[cur_idx].org; + } + } + } + + cur_idx = 1; + + /* compress array to remove zero values */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org ) + table[cur_idx++] = table[i]; + } + + *count = cur_idx; + } + + /* Get new segment for given axis. */ + + FT_LOCAL_DEF( FT_Error ) + af_axis_hints_new_segment( AF_AxisHints axis, + FT_Memory memory, + AF_Segment *asegment ) + { + FT_Error error = FT_Err_Ok; + AF_Segment segment = NULL; + + + if ( axis->num_segments < AF_SEGMENTS_EMBEDDED ) + { + if ( !axis->segments ) + { + axis->segments = axis->embedded.segments; + axis->max_segments = AF_SEGMENTS_EMBEDDED; + } + } + else if ( axis->num_segments >= axis->max_segments ) + { + FT_UInt old_max = axis->max_segments; + FT_UInt new_max = old_max; + FT_UInt big_max = FT_INT_MAX / sizeof ( *segment ); + + + if ( old_max >= big_max ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + + new_max += ( new_max >> 2 ) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + + if ( axis->segments == axis->embedded.segments ) + { + if ( FT_NEW_ARRAY( axis->segments, new_max ) ) + goto Exit; + ft_memcpy( axis->segments, axis->embedded.segments, + sizeof ( axis->embedded.segments ) ); + } + else + { + if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) ) + goto Exit; + } + + axis->max_segments = new_max; + } + + segment = axis->segments + axis->num_segments++; + + Exit: + *asegment = segment; + return error; + } + + + /* Get new edge for given axis, direction, and position, */ + /* without initializing the edge itself. */ + + FT_LOCAL_DEF( FT_Error ) + af_axis_hints_new_edge( AF_AxisHints axis, + FT_Int fpos, + AF_Direction dir, + FT_Bool top_to_bottom_hinting, + FT_Memory memory, + AF_Edge *anedge ) + { + FT_Error error = FT_Err_Ok; + AF_Edge edge = NULL; + AF_Edge edges; + + + if ( axis->num_edges < AF_EDGES_EMBEDDED ) + { + if ( !axis->edges ) + { + axis->edges = axis->embedded.edges; + axis->max_edges = AF_EDGES_EMBEDDED; + } + } + else if ( axis->num_edges >= axis->max_edges ) + { + FT_UInt old_max = axis->max_edges; + FT_UInt new_max = old_max; + FT_UInt big_max = FT_INT_MAX / sizeof ( *edge ); + + + if ( old_max >= big_max ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + + new_max += ( new_max >> 2 ) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + + if ( axis->edges == axis->embedded.edges ) + { + if ( FT_NEW_ARRAY( axis->edges, new_max ) ) + goto Exit; + ft_memcpy( axis->edges, axis->embedded.edges, + sizeof ( axis->embedded.edges ) ); + } + else + { + if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) ) + goto Exit; + } + + axis->max_edges = new_max; + } + + edges = axis->edges; + edge = edges + axis->num_edges; + + while ( edge > edges ) + { + if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos ) + : ( edge[-1].fpos < fpos ) ) + break; + + /* we want the edge with same position and minor direction */ + /* to appear before those in the major one in the list */ + if ( edge[-1].fpos == fpos && dir == axis->major_dir ) + break; + + edge[0] = edge[-1]; + edge--; + } + + axis->num_edges++; + + Exit: + *anedge = edge; + return error; + } + + +#ifdef FT_DEBUG_AUTOFIT + +#include FT_CONFIG_STANDARD_LIBRARY_H + + /* The dump functions are used in the `ftgrid' demo program, too. */ +#define AF_DUMP( varformat ) \ + do \ + { \ + if ( to_stdout ) \ + printf varformat; \ + else \ + FT_TRACE7( varformat ); \ + } while ( 0 ) + + + static const char* + af_dir_str( AF_Direction dir ) + { + const char* result; + + + switch ( dir ) + { + case AF_DIR_UP: + result = "up"; + break; + case AF_DIR_DOWN: + result = "down"; + break; + case AF_DIR_LEFT: + result = "left"; + break; + case AF_DIR_RIGHT: + result = "right"; + break; + default: + result = "none"; + } + + return result; + } + + +#define AF_INDEX_NUM( ptr, base ) (int)( (ptr) ? ( (ptr) - (base) ) : -1 ) + + + static char* + af_print_idx( char* p, + size_t n, + int idx ) + { + if ( idx == -1 ) + { + p[0] = '-'; + p[1] = '-'; + p[2] = '\0'; + } + else + ft_snprintf( p, n, "%d", idx ); + + return p; + } + + + static int + af_get_segment_index( AF_GlyphHints hints, + int point_idx, + int dimension ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Point point = hints->points + point_idx; + AF_Segment segments = axis->segments; + AF_Segment limit = segments + axis->num_segments; + AF_Segment segment; + + + for ( segment = segments; segment < limit; segment++ ) + { + if ( segment->first <= segment->last ) + { + if ( point >= segment->first && point <= segment->last ) + break; + } + else + { + AF_Point p = segment->first; + + + for (;;) + { + if ( point == p ) + goto Exit; + + if ( p == segment->last ) + break; + + p = p->next; + } + } + } + + Exit: + if ( segment == limit ) + return -1; + + return (int)( segment - segments ); + } + + + static int + af_get_edge_index( AF_GlyphHints hints, + int segment_idx, + int dimension ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Edge edges = axis->edges; + AF_Segment segment = axis->segments + segment_idx; + + + return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges ); + } + + + static int + af_get_strong_edge_index( AF_GlyphHints hints, + AF_Edge* strong_edges, + int dimension ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Edge edges = axis->edges; + + + return AF_INDEX_NUM( strong_edges[dimension], edges ); + } + + +#ifdef __cplusplus + extern "C" { +#endif + void + af_glyph_hints_dump_points( AF_GlyphHints hints, + FT_Bool to_stdout ) + { + AF_Point points = hints->points; + AF_Point limit = points + hints->num_points; + AF_Point* contour = hints->contours; + AF_Point* climit = contour + hints->num_contours; + AF_Point point; + + + AF_DUMP(( "Table of points:\n" )); + + if ( hints->num_points ) + { + AF_DUMP(( " index hedge hseg vedge vseg flags " + /* " XXXXX XXXXX XXXXX XXXXX XXXXX XXXXXX" */ + " xorg yorg xscale yscale xfit yfit " + /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */ + " hbef haft vbef vaft" )); + /* " XXXXX XXXXX XXXXX XXXXX" */ + } + else + AF_DUMP(( " (none)\n" )); + + for ( point = points; point < limit; point++ ) + { + int point_idx = AF_INDEX_NUM( point, points ); + int segment_idx_0 = af_get_segment_index( hints, point_idx, 0 ); + int segment_idx_1 = af_get_segment_index( hints, point_idx, 1 ); + + char buf1[16], buf2[16], buf3[16], buf4[16]; + char buf5[16], buf6[16], buf7[16], buf8[16]; + + + /* insert extra newline at the beginning of a contour */ + if ( contour < climit && *contour == point ) + { + AF_DUMP(( "\n" )); + contour++; + } + + AF_DUMP(( " %5d %5s %5s %5s %5s %s" + " %5d %5d %7.2f %7.2f %7.2f %7.2f" + " %5s %5s %5s %5s\n", + point_idx, + af_print_idx( buf1, 16, + af_get_edge_index( hints, segment_idx_1, 1 ) ), + af_print_idx( buf2, 16, segment_idx_1 ), + af_print_idx( buf3, 16, + af_get_edge_index( hints, segment_idx_0, 0 ) ), + af_print_idx( buf4, 16, segment_idx_0 ), + ( point->flags & AF_FLAG_NEAR ) + ? " near " + : ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) + ? " weak " + : "strong", + + point->fx, + point->fy, + (double)point->ox / 64, + (double)point->oy / 64, + (double)point->x / 64, + (double)point->y / 64, + + af_print_idx( buf5, 16, + af_get_strong_edge_index( hints, + point->before, + 1 ) ), + af_print_idx( buf6, 16, + af_get_strong_edge_index( hints, + point->after, + 1 ) ), + af_print_idx( buf7, 16, + af_get_strong_edge_index( hints, + point->before, + 0 ) ), + af_print_idx( buf8, 16, + af_get_strong_edge_index( hints, + point->after, + 0 ) ) )); + } + AF_DUMP(( "\n" )); + } +#ifdef __cplusplus + } +#endif + + + static const char* + af_edge_flags_to_string( FT_UInt flags ) + { + static char temp[32]; + int pos = 0; + + + if ( flags & AF_EDGE_ROUND ) + { + ft_memcpy( temp + pos, "round", 5 ); + pos += 5; + } + if ( flags & AF_EDGE_SERIF ) + { + if ( pos > 0 ) + temp[pos++] = ' '; + ft_memcpy( temp + pos, "serif", 5 ); + pos += 5; + } + if ( pos == 0 ) + return "normal"; + + temp[pos] = '\0'; + + return temp; + } + + + /* Dump the array of linked segments. */ + +#ifdef __cplusplus + extern "C" { +#endif + void + af_glyph_hints_dump_segments( AF_GlyphHints hints, + FT_Bool to_stdout ) + { + FT_Int dimension; + + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Point points = hints->points; + AF_Edge edges = axis->edges; + AF_Segment segments = axis->segments; + AF_Segment limit = segments + axis->num_segments; + AF_Segment seg; + + char buf1[16], buf2[16], buf3[16]; + + + AF_DUMP(( "Table of %s segments:\n", + dimension == AF_DIMENSION_HORZ ? "vertical" + : "horizontal" )); + if ( axis->num_segments ) + { + AF_DUMP(( " index pos delta dir from to " + /* " XXXXX XXXXX XXXXX XXXXX XXXX XXXX" */ + " link serif edge" + /* " XXXX XXXXX XXXX" */ + " height extra flags\n" )); + /* " XXXXXX XXXXX XXXXXXXXXXX" */ + } + else + AF_DUMP(( " (none)\n" )); + + for ( seg = segments; seg < limit; seg++ ) + AF_DUMP(( " %5d %5d %5d %5s %4d %4d" + " %4s %5s %4s" + " %6d %5d %11s\n", + AF_INDEX_NUM( seg, segments ), + seg->pos, + seg->delta, + af_dir_str( (AF_Direction)seg->dir ), + AF_INDEX_NUM( seg->first, points ), + AF_INDEX_NUM( seg->last, points ), + + af_print_idx( buf1, 16, + AF_INDEX_NUM( seg->link, segments ) ), + af_print_idx( buf2, 16, + AF_INDEX_NUM( seg->serif, segments ) ), + af_print_idx( buf3, 16, + AF_INDEX_NUM( seg->edge, edges ) ), + + seg->height, + seg->height - ( seg->max_coord - seg->min_coord ), + af_edge_flags_to_string( seg->flags ) )); + AF_DUMP(( "\n" )); + } + } +#ifdef __cplusplus + } +#endif + + + /* Fetch number of segments. */ + +#ifdef __cplusplus + extern "C" { +#endif + FT_Error + af_glyph_hints_get_num_segments( AF_GlyphHints hints, + FT_Int dimension, + FT_UInt* num_segments ) + { + AF_Dimension dim; + AF_AxisHints axis; + + + dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; + + axis = &hints->axis[dim]; + *num_segments = axis->num_segments; + + return FT_Err_Ok; + } +#ifdef __cplusplus + } +#endif + + + /* Fetch offset of segments into user supplied offset array. */ + +#ifdef __cplusplus + extern "C" { +#endif + FT_Error + af_glyph_hints_get_segment_offset( AF_GlyphHints hints, + FT_Int dimension, + FT_UInt idx, + FT_Pos *offset, + FT_Bool *is_blue, + FT_Pos *blue_offset ) + { + AF_Dimension dim; + AF_AxisHints axis; + AF_Segment seg; + + + if ( !offset ) + return FT_THROW( Invalid_Argument ); + + dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; + + axis = &hints->axis[dim]; + + if ( idx >= axis->num_segments ) + return FT_THROW( Invalid_Argument ); + + seg = &axis->segments[idx]; + *offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx + : seg->first->fy; + if ( seg->edge ) + *is_blue = FT_BOOL( seg->edge->blue_edge ); + else + *is_blue = FALSE; + + if ( *is_blue ) + *blue_offset = seg->edge->blue_edge->org; + else + *blue_offset = 0; + + return FT_Err_Ok; + } +#ifdef __cplusplus + } +#endif + + + /* Dump the array of linked edges. */ + +#ifdef __cplusplus + extern "C" { +#endif + void + af_glyph_hints_dump_edges( AF_GlyphHints hints, + FT_Bool to_stdout ) + { + FT_Int dimension; + + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Edge edges = axis->edges; + AF_Edge limit = edges + axis->num_edges; + AF_Edge edge; + + char buf1[16], buf2[16]; + + + /* + * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges + * since they have a constant X coordinate. + */ + if ( dimension == AF_DIMENSION_HORZ ) + AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", + "vertical", + 65536 * 64 / (double)hints->x_scale, + 10 * (double)hints->x_scale / 65536 / 64 )); + else + AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", + "horizontal", + 65536 * 64 / (double)hints->y_scale, + 10 * (double)hints->y_scale / 65536 / 64 )); + + if ( axis->num_edges ) + { + AF_DUMP(( " index pos dir link serif" + /* " XXXXX XXXX.XX XXXXX XXXX XXXXX" */ + " blue opos pos flags\n" )); + /* " X XXXX.XX XXXX.XX XXXXXXXXXXX" */ + } + else + AF_DUMP(( " (none)\n" )); + + for ( edge = edges; edge < limit; edge++ ) + AF_DUMP(( " %5d %7.2f %5s %4s %5s" + " %c %7.2f %7.2f %11s\n", + AF_INDEX_NUM( edge, edges ), + (double)(int)edge->opos / 64, + af_dir_str( (AF_Direction)edge->dir ), + af_print_idx( buf1, 16, + AF_INDEX_NUM( edge->link, edges ) ), + af_print_idx( buf2, 16, + AF_INDEX_NUM( edge->serif, edges ) ), + + edge->blue_edge ? 'y' : 'n', + (double)edge->opos / 64, + (double)edge->pos / 64, + af_edge_flags_to_string( edge->flags ) )); + AF_DUMP(( "\n" )); + } + } +#ifdef __cplusplus + } +#endif + +#undef AF_DUMP + +#endif /* !FT_DEBUG_AUTOFIT */ + + + /* Compute the direction value of a given vector. */ + + FT_LOCAL_DEF( AF_Direction ) + af_direction_compute( FT_Pos dx, + FT_Pos dy ) + { + FT_Pos ll, ss; /* long and short arm lengths */ + AF_Direction dir; /* candidate direction */ + + + if ( dy >= dx ) + { + if ( dy >= -dx ) + { + dir = AF_DIR_UP; + ll = dy; + ss = dx; + } + else + { + dir = AF_DIR_LEFT; + ll = -dx; + ss = dy; + } + } + else /* dy < dx */ + { + if ( dy >= -dx ) + { + dir = AF_DIR_RIGHT; + ll = dx; + ss = dy; + } + else + { + dir = AF_DIR_DOWN; + ll = -dy; + ss = dx; + } + } + + /* return no direction if arm lengths do not differ enough */ + /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */ + /* the long arm is never negative */ + if ( ll <= 14 * FT_ABS( ss ) ) + dir = AF_DIR_NONE; + + return dir; + } + + + FT_LOCAL_DEF( void ) + af_glyph_hints_init( AF_GlyphHints hints, + FT_Memory memory ) + { + /* no need to initialize the embedded items */ + FT_MEM_ZERO( hints, sizeof ( *hints ) - sizeof ( hints->embedded ) ); + hints->memory = memory; + } + + + FT_LOCAL_DEF( void ) + af_glyph_hints_done( AF_GlyphHints hints ) + { + FT_Memory memory; + int dim; + + + if ( !( hints && hints->memory ) ) + return; + + memory = hints->memory; + + /* + * note that we don't need to free the segment and edge + * buffers since they are really within the hints->points array + */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_AxisHints axis = &hints->axis[dim]; + + + axis->num_segments = 0; + axis->max_segments = 0; + if ( axis->segments != axis->embedded.segments ) + FT_FREE( axis->segments ); + + axis->num_edges = 0; + axis->max_edges = 0; + if ( axis->edges != axis->embedded.edges ) + FT_FREE( axis->edges ); + } + + if ( hints->contours != hints->embedded.contours ) + FT_FREE( hints->contours ); + hints->max_contours = 0; + hints->num_contours = 0; + + if ( hints->points != hints->embedded.points ) + FT_FREE( hints->points ); + hints->max_points = 0; + hints->num_points = 0; + + hints->memory = NULL; + } + + + /* Reset metrics. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_rescale( AF_GlyphHints hints, + AF_StyleMetrics metrics ) + { + hints->metrics = metrics; + hints->scaler_flags = metrics->scaler.flags; + } + + + /* Recompute all AF_Point in AF_GlyphHints from the definitions */ + /* in a source outline. */ + + FT_LOCAL_DEF( FT_Error ) + af_glyph_hints_reload( AF_GlyphHints hints, + FT_Outline* outline ) + { + FT_Error error = FT_Err_Ok; + AF_Point points; + FT_Int old_max, new_max; + FT_Fixed x_scale = hints->x_scale; + FT_Fixed y_scale = hints->y_scale; + FT_Pos x_delta = hints->x_delta; + FT_Pos y_delta = hints->y_delta; + FT_Memory memory = hints->memory; + + + hints->num_points = 0; + hints->num_contours = 0; + + hints->axis[0].num_segments = 0; + hints->axis[0].num_edges = 0; + hints->axis[1].num_segments = 0; + hints->axis[1].num_edges = 0; + + /* first of all, reallocate the contours array if necessary */ + new_max = outline->n_contours; + old_max = hints->max_contours; + + if ( new_max <= AF_CONTOURS_EMBEDDED ) + { + if ( !hints->contours ) + { + hints->contours = hints->embedded.contours; + hints->max_contours = AF_CONTOURS_EMBEDDED; + } + } + else if ( new_max > old_max ) + { + if ( hints->contours == hints->embedded.contours ) + hints->contours = NULL; + + new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */ + + if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) + goto Exit; + + hints->max_contours = new_max; + } + + /* + * then reallocate the points arrays if necessary -- + * note that we reserve two additional point positions, used to + * hint metrics appropriately + */ + new_max = outline->n_points + 2; + old_max = hints->max_points; + + if ( new_max <= AF_POINTS_EMBEDDED ) + { + if ( !hints->points ) + { + hints->points = hints->embedded.points; + hints->max_points = AF_POINTS_EMBEDDED; + } + } + else if ( new_max > old_max ) + { + if ( hints->points == hints->embedded.points ) + hints->points = NULL; + + new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */ + + if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) + goto Exit; + + hints->max_points = new_max; + } + + hints->num_points = outline->n_points; + hints->num_contours = outline->n_contours; + + /* We can't rely on the value of `FT_Outline.flags' to know the fill */ + /* direction used for a glyph, given that some fonts are broken (e.g., */ + /* the Arphic ones). We thus recompute it each time we need to. */ + /* */ + hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP; + hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT; + + if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) + { + hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN; + hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT; + } + + hints->x_scale = x_scale; + hints->y_scale = y_scale; + hints->x_delta = x_delta; + hints->y_delta = y_delta; + + points = hints->points; + if ( hints->num_points == 0 ) + goto Exit; + + { + AF_Point point; + AF_Point point_limit = points + hints->num_points; + + /* value 20 in `near_limit' is heuristic */ + FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM; + FT_Int near_limit = 20 * units_per_em / 2048; + + + /* compute coordinates & Bezier flags, next and prev */ + { + FT_Vector* vec = outline->points; + char* tag = outline->tags; + FT_Short endpoint = outline->contours[0]; + AF_Point end = points + endpoint; + AF_Point prev = end; + FT_Int contour_index = 0; + + + for ( point = points; point < point_limit; point++, vec++, tag++ ) + { + FT_Pos out_x, out_y; + + + point->in_dir = (FT_Char)AF_DIR_NONE; + point->out_dir = (FT_Char)AF_DIR_NONE; + + point->fx = (FT_Short)vec->x; + point->fy = (FT_Short)vec->y; + point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; + point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; + + end->fx = (FT_Short)outline->points[endpoint].x; + end->fy = (FT_Short)outline->points[endpoint].y; + + switch ( FT_CURVE_TAG( *tag ) ) + { + case FT_CURVE_TAG_CONIC: + point->flags = AF_FLAG_CONIC; + break; + case FT_CURVE_TAG_CUBIC: + point->flags = AF_FLAG_CUBIC; + break; + default: + point->flags = AF_FLAG_NONE; + } + + out_x = point->fx - prev->fx; + out_y = point->fy - prev->fy; + + if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit ) + prev->flags |= AF_FLAG_NEAR; + + point->prev = prev; + prev->next = point; + prev = point; + + if ( point == end ) + { + if ( ++contour_index < outline->n_contours ) + { + endpoint = outline->contours[contour_index]; + end = points + endpoint; + prev = end; + } + } + +#ifdef FT_DEBUG_AUTOFIT + point->before[0] = NULL; + point->before[1] = NULL; + point->after[0] = NULL; + point->after[1] = NULL; +#endif + + } + } + + /* set up the contours array */ + { + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + short* end = outline->contours; + short idx = 0; + + + for ( ; contour < contour_limit; contour++, end++ ) + { + contour[0] = points + idx; + idx = (short)( end[0] + 1 ); + } + } + + { + /* + * Compute directions of `in' and `out' vectors. + * + * Note that distances between points that are very near to each + * other are accumulated. In other words, the auto-hinter either + * prepends the small vectors between near points to the first + * non-near vector, or the sum of small vector lengths exceeds a + * threshold, thus `grouping' the small vectors. All intermediate + * points are tagged as weak; the directions are adjusted also to + * be equal to the accumulated one. + */ + + FT_Int near_limit2 = 2 * near_limit - 1; + + AF_Point* contour; + AF_Point* contour_limit = hints->contours + hints->num_contours; + + + for ( contour = hints->contours; contour < contour_limit; contour++ ) + { + AF_Point first = *contour; + AF_Point next, prev, curr; + + FT_Pos out_x, out_y; + + + /* since the first point of a contour could be part of a */ + /* series of near points, go backwards to find the first */ + /* non-near point and adjust `first' */ + + point = first; + prev = first->prev; + + while ( prev != first ) + { + out_x = point->fx - prev->fx; + out_y = point->fy - prev->fy; + + /* + * We use Taxicab metrics to measure the vector length. + * + * Note that the accumulated distances so far could have the + * opposite direction of the distance measured here. For this + * reason we use `near_limit2' for the comparison to get a + * non-near point even in the worst case. + */ + if ( FT_ABS( out_x ) + FT_ABS( out_y ) >= near_limit2 ) + break; + + point = prev; + prev = prev->prev; + } + + /* adjust first point */ + first = point; + + /* now loop over all points of the contour to get */ + /* `in' and `out' vector directions */ + + curr = first; + + /* + * We abuse the `u' and `v' fields to store index deltas to the + * next and previous non-near point, respectively. + * + * To avoid problems with not having non-near points, we point to + * `first' by default as the next non-near point. + * + */ + curr->u = (FT_Pos)( first - curr ); + first->v = -curr->u; + + out_x = 0; + out_y = 0; + + next = first; + do + { + AF_Direction out_dir; + + + point = next; + next = point->next; + + out_x += next->fx - point->fx; + out_y += next->fy - point->fy; + + if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit ) + { + next->flags |= AF_FLAG_WEAK_INTERPOLATION; + continue; + } + + curr->u = (FT_Pos)( next - curr ); + next->v = -curr->u; + + out_dir = af_direction_compute( out_x, out_y ); + + /* adjust directions for all points inbetween; */ + /* the loop also updates position of `curr' */ + curr->out_dir = (FT_Char)out_dir; + for ( curr = curr->next; curr != next; curr = curr->next ) + { + curr->in_dir = (FT_Char)out_dir; + curr->out_dir = (FT_Char)out_dir; + } + next->in_dir = (FT_Char)out_dir; + + curr->u = (FT_Pos)( first - curr ); + first->v = -curr->u; + + out_x = 0; + out_y = 0; + + } while ( next != first ); + } + + /* + * The next step is to `simplify' an outline's topology so that we + * can identify local extrema more reliably: A series of + * non-horizontal or non-vertical vectors pointing into the same + * quadrant are handled as a single, long vector. From a + * topological point of the view, the intermediate points are of no + * interest and thus tagged as weak. + */ + + for ( point = points; point < point_limit; point++ ) + { + if ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) + continue; + + if ( point->in_dir == AF_DIR_NONE && + point->out_dir == AF_DIR_NONE ) + { + /* check whether both vectors point into the same quadrant */ + + FT_Pos in_x, in_y; + FT_Pos out_x, out_y; + + AF_Point next_u = point + point->u; + AF_Point prev_v = point + point->v; + + + in_x = point->fx - prev_v->fx; + in_y = point->fy - prev_v->fy; + + out_x = next_u->fx - point->fx; + out_y = next_u->fy - point->fy; + + if ( ( in_x ^ out_x ) >= 0 && ( in_y ^ out_y ) >= 0 ) + { + /* yes, so tag current point as weak */ + /* and update index deltas */ + + point->flags |= AF_FLAG_WEAK_INTERPOLATION; + + prev_v->u = (FT_Pos)( next_u - prev_v ); + next_u->v = -prev_v->u; + } + } + } + + /* + * Finally, check for remaining weak points. Everything else not + * collected in edges so far is then implicitly classified as strong + * points. + */ + + for ( point = points; point < point_limit; point++ ) + { + if ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) + continue; + + if ( point->flags & AF_FLAG_CONTROL ) + { + /* control points are always weak */ + Is_Weak_Point: + point->flags |= AF_FLAG_WEAK_INTERPOLATION; + } + else if ( point->out_dir == point->in_dir ) + { + if ( point->out_dir != AF_DIR_NONE ) + { + /* current point lies on a horizontal or */ + /* vertical segment (but doesn't start or end it) */ + goto Is_Weak_Point; + } + + { + AF_Point next_u = point + point->u; + AF_Point prev_v = point + point->v; + + + if ( ft_corner_is_flat( point->fx - prev_v->fx, + point->fy - prev_v->fy, + next_u->fx - point->fx, + next_u->fy - point->fy ) ) + { + /* either the `in' or the `out' vector is much more */ + /* dominant than the other one, so tag current point */ + /* as weak and update index deltas */ + + prev_v->u = (FT_Pos)( next_u - prev_v ); + next_u->v = -prev_v->u; + + goto Is_Weak_Point; + } + } + } + else if ( point->in_dir == -point->out_dir ) + { + /* current point forms a spike */ + goto Is_Weak_Point; + } + } + } + } + + Exit: + return error; + } + + + /* Store the hinted outline in an FT_Outline structure. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_save( AF_GlyphHints hints, + FT_Outline* outline ) + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + FT_Vector* vec = outline->points; + char* tag = outline->tags; + + + for ( ; point < limit; point++, vec++, tag++ ) + { + vec->x = point->x; + vec->y = point->y; + + if ( point->flags & AF_FLAG_CONIC ) + tag[0] = FT_CURVE_TAG_CONIC; + else if ( point->flags & AF_FLAG_CUBIC ) + tag[0] = FT_CURVE_TAG_CUBIC; + else + tag[0] = FT_CURVE_TAG_ON; + } + } + + + /**************************************************************** + * + * EDGE POINT GRID-FITTING + * + ****************************************************************/ + + + /* Align all points of an edge to the same coordinate value, */ + /* either horizontally or vertically. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Segment seg; + + + if ( dim == AF_DIMENSION_HORZ ) + { + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge edge = seg->edge; + AF_Point point, first, last; + + + if ( !edge ) + continue; + + first = seg->first; + last = seg->last; + point = first; + for (;;) + { + point->x = edge->pos; + point->flags |= AF_FLAG_TOUCH_X; + + if ( point == last ) + break; + + point = point->next; + } + } + } + else + { + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge edge = seg->edge; + AF_Point point, first, last; + + + if ( !edge ) + continue; + + first = seg->first; + last = seg->last; + point = first; + for (;;) + { + point->y = edge->pos; + point->flags |= AF_FLAG_TOUCH_Y; + + if ( point == last ) + break; + + point = point->next; + } + } + } + } + + + /**************************************************************** + * + * STRONG POINT INTERPOLATION + * + ****************************************************************/ + + + /* Hint the strong points -- this is equivalent to the TrueType `IP' */ + /* hinting instruction. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_strong_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + FT_UInt touch_flag; + + + if ( dim == AF_DIMENSION_HORZ ) + touch_flag = AF_FLAG_TOUCH_X; + else + touch_flag = AF_FLAG_TOUCH_Y; + + if ( edges < edge_limit ) + { + AF_Point point; + AF_Edge edge; + + + for ( point = points; point < point_limit; point++ ) + { + FT_Pos u, ou, fu; /* point position */ + FT_Pos delta; + + + if ( point->flags & touch_flag ) + continue; + + /* if this point is candidate to weak interpolation, we */ + /* interpolate it after all strong points have been processed */ + + if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ) + continue; + + if ( dim == AF_DIMENSION_VERT ) + { + u = point->fy; + ou = point->oy; + } + else + { + u = point->fx; + ou = point->ox; + } + + fu = u; + + /* is the point before the first edge? */ + edge = edges; + delta = edge->fpos - u; + if ( delta >= 0 ) + { + u = edge->pos - ( edge->opos - ou ); + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = edge; + point->after[dim] = NULL; +#endif + + goto Store_Point; + } + + /* is the point after the last edge? */ + edge = edge_limit - 1; + delta = u - edge->fpos; + if ( delta >= 0 ) + { + u = edge->pos + ( ou - edge->opos ); + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = NULL; + point->after[dim] = edge; +#endif + + goto Store_Point; + } + + { + FT_PtrDist min, max, mid; + FT_Pos fpos; + + + /* find enclosing edges */ + min = 0; + max = edge_limit - edges; + +#if 1 + /* for a small number of edges, a linear search is better */ + if ( max <= 8 ) + { + FT_PtrDist nn; + + + for ( nn = 0; nn < max; nn++ ) + if ( edges[nn].fpos >= u ) + break; + + if ( edges[nn].fpos == u ) + { + u = edges[nn].pos; + goto Store_Point; + } + min = nn; + } + else +#endif + while ( min < max ) + { + mid = ( max + min ) >> 1; + edge = edges + mid; + fpos = edge->fpos; + + if ( u < fpos ) + max = mid; + else if ( u > fpos ) + min = mid + 1; + else + { + /* we are on the edge */ + u = edge->pos; + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = NULL; + point->after[dim] = NULL; +#endif + + goto Store_Point; + } + } + + /* point is not on an edge */ + { + AF_Edge before = edges + min - 1; + AF_Edge after = edges + min + 0; + + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = before; + point->after[dim] = after; +#endif + + /* assert( before && after && before != after ) */ + if ( before->scale == 0 ) + before->scale = FT_DivFix( after->pos - before->pos, + after->fpos - before->fpos ); + + u = before->pos + FT_MulFix( fu - before->fpos, + before->scale ); + } + } + + Store_Point: + /* save the point position */ + if ( dim == AF_DIMENSION_HORZ ) + point->x = u; + else + point->y = u; + + point->flags |= touch_flag; + } + } + } + + + /**************************************************************** + * + * WEAK POINT INTERPOLATION + * + ****************************************************************/ + + + /* Shift the original coordinates of all points between `p1' and */ + /* `p2' to get hinted coordinates, using the same difference as */ + /* given by `ref'. */ + + static void + af_iup_shift( AF_Point p1, + AF_Point p2, + AF_Point ref ) + { + AF_Point p; + FT_Pos delta = ref->u - ref->v; + + + if ( delta == 0 ) + return; + + for ( p = p1; p < ref; p++ ) + p->u = p->v + delta; + + for ( p = ref + 1; p <= p2; p++ ) + p->u = p->v + delta; + } + + + /* Interpolate the original coordinates of all points between `p1' and */ + /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */ + /* reference points. The `u' and `v' members are the current and */ + /* original coordinate values, respectively. */ + /* */ + /* Details can be found in the TrueType bytecode specification. */ + + static void + af_iup_interp( AF_Point p1, + AF_Point p2, + AF_Point ref1, + AF_Point ref2 ) + { + AF_Point p; + FT_Pos u, v1, v2, u1, u2, d1, d2; + + + if ( p1 > p2 ) + return; + + if ( ref1->v > ref2->v ) + { + p = ref1; + ref1 = ref2; + ref2 = p; + } + + v1 = ref1->v; + v2 = ref2->v; + u1 = ref1->u; + u2 = ref2->u; + d1 = u1 - v1; + d2 = u2 - v2; + + if ( u1 == u2 || v1 == v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = u1; + + p->u = u; + } + } + else + { + FT_Fixed scale = FT_DivFix( u2 - u1, v2 - v1 ); + + + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = u1 + FT_MulFix( u - v1, scale ); + + p->u = u; + } + } + } + + + /* Hint the weak points -- this is equivalent to the TrueType `IUP' */ + /* hinting instruction. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_weak_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + FT_UInt touch_flag; + AF_Point point; + AF_Point end_point; + AF_Point first_point; + + + /* PASS 1: Move segment points to edge positions */ + + if ( dim == AF_DIMENSION_HORZ ) + { + touch_flag = AF_FLAG_TOUCH_X; + + for ( point = points; point < point_limit; point++ ) + { + point->u = point->x; + point->v = point->ox; + } + } + else + { + touch_flag = AF_FLAG_TOUCH_Y; + + for ( point = points; point < point_limit; point++ ) + { + point->u = point->y; + point->v = point->oy; + } + } + + for ( ; contour < contour_limit; contour++ ) + { + AF_Point first_touched, last_touched; + + + point = *contour; + end_point = point->prev; + first_point = point; + + /* find first touched point */ + for (;;) + { + if ( point > end_point ) /* no touched point in contour */ + goto NextContour; + + if ( point->flags & touch_flag ) + break; + + point++; + } + + first_touched = point; + + for (;;) + { + FT_ASSERT( point <= end_point && + ( point->flags & touch_flag ) != 0 ); + + /* skip any touched neighbours */ + while ( point < end_point && + ( point[1].flags & touch_flag ) != 0 ) + point++; + + last_touched = point; + + /* find the next touched point, if any */ + point++; + for (;;) + { + if ( point > end_point ) + goto EndContour; + + if ( ( point->flags & touch_flag ) != 0 ) + break; + + point++; + } + + /* interpolate between last_touched and point */ + af_iup_interp( last_touched + 1, point - 1, + last_touched, point ); + } + + EndContour: + /* special case: only one point was touched */ + if ( last_touched == first_touched ) + af_iup_shift( first_point, end_point, first_touched ); + + else /* interpolate the last part */ + { + if ( last_touched < end_point ) + af_iup_interp( last_touched + 1, end_point, + last_touched, first_touched ); + + if ( first_touched > points ) + af_iup_interp( first_point, first_touched - 1, + last_touched, first_touched ); + } + + NextContour: + ; + } + + /* now save the interpolated values back to x/y */ + if ( dim == AF_DIMENSION_HORZ ) + { + for ( point = points; point < point_limit; point++ ) + point->x = point->u; + } + else + { + for ( point = points; point < point_limit; point++ ) + point->y = point->u; + } + } + + +/* END */ diff --git a/vendor/freetype/src/autofit/afhints.h b/vendor/freetype/src/autofit/afhints.h new file mode 100644 index 0000000..d1cf952 --- /dev/null +++ b/vendor/freetype/src/autofit/afhints.h @@ -0,0 +1,467 @@ +/**************************************************************************** + * + * afhints.h + * + * Auto-fitter hinting routines (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFHINTS_H_ +#define AFHINTS_H_ + +#include "aftypes.h" + +FT_BEGIN_HEADER + + /* + * The definition of outline glyph hints. These are shared by all + * writing system analysis routines (until now). + */ + + typedef enum AF_Dimension_ + { + AF_DIMENSION_HORZ = 0, /* x coordinates, */ + /* i.e., vertical segments & edges */ + AF_DIMENSION_VERT = 1, /* y coordinates, */ + /* i.e., horizontal segments & edges */ + + AF_DIMENSION_MAX /* do not remove */ + + } AF_Dimension; + + + /* hint directions -- the values are computed so that two vectors are */ + /* in opposite directions iff `dir1 + dir2 == 0' */ + typedef enum AF_Direction_ + { + AF_DIR_NONE = 4, + AF_DIR_RIGHT = 1, + AF_DIR_LEFT = -1, + AF_DIR_UP = 2, + AF_DIR_DOWN = -2 + + } AF_Direction; + + + /* + * The following explanations are mostly taken from the article + * + * Real-Time Grid Fitting of Typographic Outlines + * + * by David Turner and Werner Lemberg + * + * https://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf + * + * with appropriate updates. + * + * + * Segments + * + * `af_{cjk,latin,...}_hints_compute_segments' are the functions to + * find segments in an outline. + * + * A segment is a series of at least two consecutive points that are + * approximately aligned along a coordinate axis. The analysis to do + * so is specific to a writing system. + * + * + * Edges + * + * `af_{cjk,latin,...}_hints_compute_edges' are the functions to find + * edges. + * + * As soon as segments are defined, the auto-hinter groups them into + * edges. An edge corresponds to a single position on the main + * dimension that collects one or more segments (allowing for a small + * threshold). + * + * As an example, the `latin' writing system first tries to grid-fit + * edges, then to align segments on the edges unless it detects that + * they form a serif. + * + * + * A H + * | | + * | | + * | | + * | | + * C | | F + * +------<-----+ +-----<------+ + * | B G | + * | | + * | | + * +--------------->------------------+ + * D E + * + * + * Stems + * + * Stems are detected by `af_{cjk,latin,...}_hint_edges'. + * + * Segments need to be `linked' to other ones in order to detect stems. + * A stem is made of two segments that face each other in opposite + * directions and that are sufficiently close to each other. Using + * vocabulary from the TrueType specification, stem segments form a + * `black distance'. + * + * In the above ASCII drawing, the horizontal segments are BC, DE, and + * FG; the vertical segments are AB, CD, EF, and GH. + * + * Each segment has at most one `best' candidate to form a black + * distance, or no candidate at all. Notice that two distinct segments + * can have the same candidate, which frequently means a serif. + * + * A stem is recognized by the following condition: + * + * best segment_1 = segment_2 && best segment_2 = segment_1 + * + * The best candidate is stored in field `link' in structure + * `AF_Segment'. + * + * In the above ASCII drawing, the best candidate for both AB and CD is + * GH, while the best candidate for GH is AB. Similarly, the best + * candidate for EF and GH is AB, while the best candidate for AB is + * GH. + * + * The detection and handling of stems is dependent on the writing + * system. + * + * + * Serifs + * + * Serifs are detected by `af_{cjk,latin,...}_hint_edges'. + * + * In comparison to a stem, a serif (as handled by the auto-hinter + * module that takes care of the `latin' writing system) has + * + * best segment_1 = segment_2 && best segment_2 != segment_1 + * + * where segment_1 corresponds to the serif segment (CD and EF in the + * above ASCII drawing). + * + * The best candidate is stored in field `serif' in structure + * `AF_Segment' (and `link' is set to NULL). + * + * + * Touched points + * + * A point is called `touched' if it has been processed somehow by the + * auto-hinter. It basically means that it shouldn't be moved again + * (or moved only under certain constraints to preserve the already + * applied processing). + * + * + * Flat and round segments + * + * Segments are `round' or `flat', depending on the series of points + * that define them. A segment is round if the next and previous point + * of an extremum (which can be either a single point or sequence of + * points) are both conic or cubic control points. Otherwise, a + * segment with an extremum is flat. + * + * + * Strong Points + * + * Experience has shown that points not part of an edge need to be + * interpolated linearly between their two closest edges, even if these + * are not part of the contour of those particular points. Typical + * candidates for this are + * + * - angle points (i.e., points where the `in' and `out' direction + * differ greatly) + * + * - inflection points (i.e., where the `in' and `out' angles are the + * same, but the curvature changes sign) [currently, such points + * aren't handled specially in the auto-hinter] + * + * `af_glyph_hints_align_strong_points' is the function that takes + * care of such situations; it is equivalent to the TrueType `IP' + * hinting instruction. + * + * + * Weak Points + * + * Other points in the outline must be interpolated using the + * coordinates of their previous and next unfitted contour neighbours. + * These are called `weak points' and are touched by the function + * `af_glyph_hints_align_weak_points', equivalent to the TrueType `IUP' + * hinting instruction. Typical candidates are control points and + * points on the contour without a major direction. + * + * The major effect is to reduce possible distortion caused by + * alignment of edges and strong points, thus weak points are processed + * after strong points. + */ + + + /* point hint flags */ +#define AF_FLAG_NONE 0 + + /* point type flags */ +#define AF_FLAG_CONIC ( 1U << 0 ) +#define AF_FLAG_CUBIC ( 1U << 1 ) +#define AF_FLAG_CONTROL ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) + + /* point touch flags */ +#define AF_FLAG_TOUCH_X ( 1U << 2 ) +#define AF_FLAG_TOUCH_Y ( 1U << 3 ) + + /* candidates for weak interpolation have this flag set */ +#define AF_FLAG_WEAK_INTERPOLATION ( 1U << 4 ) + + /* the distance to the next point is very small */ +#define AF_FLAG_NEAR ( 1U << 5 ) + + + /* edge hint flags */ +#define AF_EDGE_NORMAL 0 +#define AF_EDGE_ROUND ( 1U << 0 ) +#define AF_EDGE_SERIF ( 1U << 1 ) +#define AF_EDGE_DONE ( 1U << 2 ) +#define AF_EDGE_NEUTRAL ( 1U << 3 ) /* edge aligns to a neutral blue zone */ + + + typedef struct AF_PointRec_* AF_Point; + typedef struct AF_SegmentRec_* AF_Segment; + typedef struct AF_EdgeRec_* AF_Edge; + + + typedef struct AF_PointRec_ + { + FT_UShort flags; /* point flags used by hinter */ + FT_Char in_dir; /* direction of inwards vector */ + FT_Char out_dir; /* direction of outwards vector */ + + FT_Pos ox, oy; /* original, scaled position */ + FT_Short fx, fy; /* original, unscaled position (in font units) */ + FT_Pos x, y; /* current position */ + FT_Pos u, v; /* current (x,y) or (y,x) depending on context */ + + AF_Point next; /* next point in contour */ + AF_Point prev; /* previous point in contour */ + +#ifdef FT_DEBUG_AUTOFIT + /* track `before' and `after' edges for strong points */ + AF_Edge before[2]; + AF_Edge after[2]; +#endif + + } AF_PointRec; + + + typedef struct AF_SegmentRec_ + { + FT_Byte flags; /* edge/segment flags for this segment */ + FT_Char dir; /* segment direction */ + FT_Short pos; /* position of segment */ + FT_Short delta; /* deviation from segment position */ + FT_Short min_coord; /* minimum coordinate of segment */ + FT_Short max_coord; /* maximum coordinate of segment */ + FT_Short height; /* the hinted segment height */ + + AF_Edge edge; /* the segment's parent edge */ + AF_Segment edge_next; /* link to next segment in parent edge */ + + AF_Segment link; /* (stem) link segment */ + AF_Segment serif; /* primary segment for serifs */ + FT_Pos score; /* used during stem matching */ + FT_Pos len; /* used during stem matching */ + + AF_Point first; /* first point in edge segment */ + AF_Point last; /* last point in edge segment */ + + } AF_SegmentRec; + + + typedef struct AF_EdgeRec_ + { + FT_Short fpos; /* original, unscaled position (in font units) */ + FT_Pos opos; /* original, scaled position */ + FT_Pos pos; /* current position */ + + FT_Byte flags; /* edge flags */ + FT_Char dir; /* edge direction */ + FT_Fixed scale; /* used to speed up interpolation between edges */ + + AF_Width blue_edge; /* non-NULL if this is a blue edge */ + AF_Edge link; /* link edge */ + AF_Edge serif; /* primary edge for serifs */ + FT_Int score; /* used during stem matching */ + + AF_Segment first; /* first segment in edge */ + AF_Segment last; /* last segment in edge */ + + } AF_EdgeRec; + +#define AF_SEGMENTS_EMBEDDED 18 /* number of embedded segments */ +#define AF_EDGES_EMBEDDED 12 /* number of embedded edges */ + + typedef struct AF_AxisHintsRec_ + { + FT_UInt num_segments; /* number of used segments */ + FT_UInt max_segments; /* number of allocated segments */ + AF_Segment segments; /* segments array */ + + FT_UInt num_edges; /* number of used edges */ + FT_UInt max_edges; /* number of allocated edges */ + AF_Edge edges; /* edges array */ + + AF_Direction major_dir; /* either vertical or horizontal */ + + /* two arrays to avoid allocation penalty */ + struct + { + AF_SegmentRec segments[AF_SEGMENTS_EMBEDDED]; + AF_EdgeRec edges[AF_EDGES_EMBEDDED]; + } embedded; + + + } AF_AxisHintsRec, *AF_AxisHints; + + +#define AF_POINTS_EMBEDDED 96 /* number of embedded points */ +#define AF_CONTOURS_EMBEDDED 8 /* number of embedded contours */ + + typedef struct AF_GlyphHintsRec_ + { + FT_Memory memory; + + FT_Fixed x_scale; + FT_Pos x_delta; + + FT_Fixed y_scale; + FT_Pos y_delta; + + FT_Int max_points; /* number of allocated points */ + FT_Int num_points; /* number of used points */ + AF_Point points; /* points array */ + + FT_Int max_contours; /* number of allocated contours */ + FT_Int num_contours; /* number of used contours */ + AF_Point* contours; /* contours array */ + + AF_AxisHintsRec axis[AF_DIMENSION_MAX]; + + FT_UInt32 scaler_flags; /* copy of scaler flags */ + FT_UInt32 other_flags; /* free for style-specific */ + /* implementations */ + AF_StyleMetrics metrics; + + /* Two arrays to avoid allocation penalty. */ + /* The `embedded' structure must be the last element! */ + struct + { + AF_Point contours[AF_CONTOURS_EMBEDDED]; + AF_PointRec points[AF_POINTS_EMBEDDED]; + } embedded; + + } AF_GlyphHintsRec; + + +#define AF_HINTS_TEST_SCALER( h, f ) ( (h)->scaler_flags & (f) ) +#define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) ) + + +#ifdef FT_DEBUG_AUTOFIT + +#define AF_HINTS_DO_HORIZONTAL( h ) \ + ( !af_debug_disable_horz_hints_ && \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) ) + +#define AF_HINTS_DO_VERTICAL( h ) \ + ( !af_debug_disable_vert_hints_ && \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) ) + +#define AF_HINTS_DO_BLUES( h ) ( !af_debug_disable_blue_hints_ ) + +#else /* !FT_DEBUG_AUTOFIT */ + +#define AF_HINTS_DO_HORIZONTAL( h ) \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) + +#define AF_HINTS_DO_VERTICAL( h ) \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) + +#define AF_HINTS_DO_BLUES( h ) 1 + +#endif /* !FT_DEBUG_AUTOFIT */ + + +#define AF_HINTS_DO_ADVANCE( h ) \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE ) + + + FT_LOCAL( AF_Direction ) + af_direction_compute( FT_Pos dx, + FT_Pos dy ); + + + FT_LOCAL( FT_Error ) + af_axis_hints_new_segment( AF_AxisHints axis, + FT_Memory memory, + AF_Segment *asegment ); + + FT_LOCAL( FT_Error) + af_axis_hints_new_edge( AF_AxisHints axis, + FT_Int fpos, + AF_Direction dir, + FT_Bool top_to_bottom_hinting, + FT_Memory memory, + AF_Edge *edge ); + + FT_LOCAL( void ) + af_glyph_hints_init( AF_GlyphHints hints, + FT_Memory memory ); + + FT_LOCAL( void ) + af_glyph_hints_rescale( AF_GlyphHints hints, + AF_StyleMetrics metrics ); + + FT_LOCAL( FT_Error ) + af_glyph_hints_reload( AF_GlyphHints hints, + FT_Outline* outline ); + + FT_LOCAL( void ) + af_glyph_hints_save( AF_GlyphHints hints, + FT_Outline* outline ); + + FT_LOCAL( void ) + af_glyph_hints_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_glyph_hints_align_strong_points( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_glyph_hints_align_weak_points( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_glyph_hints_done( AF_GlyphHints hints ); + +/* */ + +#define AF_SEGMENT_LEN( seg ) ( (seg)->max_coord - (seg)->min_coord ) + +#define AF_SEGMENT_DIST( seg1, seg2 ) ( ( (seg1)->pos > (seg2)->pos ) \ + ? (seg1)->pos - (seg2)->pos \ + : (seg2)->pos - (seg1)->pos ) + + +FT_END_HEADER + +#endif /* AFHINTS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afindic.c b/vendor/freetype/src/autofit/afindic.c new file mode 100644 index 0000000..7fb12c6 --- /dev/null +++ b/vendor/freetype/src/autofit/afindic.c @@ -0,0 +1,157 @@ +/**************************************************************************** + * + * afindic.c + * + * Auto-fitter hinting routines for Indic writing system (body). + * + * Copyright (C) 2007-2023 by + * Rahul Bhalerao , . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "aftypes.h" +#include "aflatin.h" +#include "afcjk.h" + + +#ifdef AF_CONFIG_OPTION_INDIC + +#include "afindic.h" +#include "aferrors.h" + + + static FT_Error + af_indic_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Face face ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + /* skip blue zone init in CJK routines */ + FT_CharMap oldmap = face->charmap; + + + metrics->units_per_em = face->units_per_EM; + + if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + face->charmap = NULL; + else + { + af_cjk_metrics_init_widths( metrics, face ); +#if 0 + /* either need indic specific blue_chars[] or just skip blue zones */ + af_cjk_metrics_init_blues( metrics, face, af_cjk_blue_chars ); +#endif + af_cjk_metrics_check_digits( metrics, face ); + } + + face->charmap = oldmap; + return FT_Err_Ok; + } + + + static void + af_indic_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ) + { + /* use CJK routines */ + af_cjk_metrics_scale( metrics, scaler ); + } + + + static FT_Error + af_indic_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ) + { + /* use CJK routines */ + return af_cjk_hints_init( hints, metrics ); + } + + + static FT_Error + af_indic_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ) + { + /* use CJK routines */ + return af_cjk_hints_apply( glyph_index, hints, outline, metrics ); + } + + + /* Extract standard_width from writing system/script specific */ + /* metrics class. */ + + static void + af_indic_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + if ( stdHW ) + *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; + + if ( stdVW ) + *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** I N D I C S C R I P T C L A S S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_indic_writing_system_class, + + AF_WRITING_SYSTEM_INDIC, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) af_indic_metrics_init, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)af_indic_metrics_scale, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)af_indic_get_standard_widths, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_indic_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_indic_hints_apply /* style_hints_apply */ + ) + + +#else /* !AF_CONFIG_OPTION_INDIC */ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_indic_writing_system_class, + + AF_WRITING_SYSTEM_INDIC, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) NULL, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) NULL /* style_hints_apply */ + ) + + +#endif /* !AF_CONFIG_OPTION_INDIC */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afindic.h b/vendor/freetype/src/autofit/afindic.h new file mode 100644 index 0000000..3eb67f6 --- /dev/null +++ b/vendor/freetype/src/autofit/afindic.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * afindic.h + * + * Auto-fitter hinting routines for Indic writing system + * (specification). + * + * Copyright (C) 2007-2023 by + * Rahul Bhalerao , . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFINDIC_H_ +#define AFINDIC_H_ + +#include "afhints.h" + + +FT_BEGIN_HEADER + + + /* the `indic' writing system */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_indic_writing_system_class ) + + +/* */ + +FT_END_HEADER + +#endif /* AFINDIC_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/aflatin.c b/vendor/freetype/src/autofit/aflatin.c new file mode 100644 index 0000000..b86367a --- /dev/null +++ b/vendor/freetype/src/autofit/aflatin.c @@ -0,0 +1,3644 @@ +/**************************************************************************** + * + * aflatin.c + * + * Auto-fitter hinting routines for latin writing system (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + +#include "afglobal.h" +#include "aflatin.h" +#include "aferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT aflatin + + + /* needed for computation of round vs. flat segments */ +#define FLAT_THRESHOLD( x ) ( x / 14 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Find segments and links, compute all stem widths, and initialize */ + /* standard width and height for the glyph with given charcode. */ + + FT_LOCAL_DEF( void ) + af_latin_metrics_init_widths( AF_LatinMetrics metrics, + FT_Face face ) + { + /* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + + + FT_TRACE5(( "\n" )); + FT_TRACE5(( "latin standard widths computation (style `%s')\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "=====================================================\n" )); + FT_TRACE5(( "\n" )); + + af_glyph_hints_init( hints, face->memory ); + + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + + { + FT_Error error; + FT_ULong glyph_index; + int dim; + AF_LatinMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + + AF_StyleClass style_class = metrics->root.style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + const char* p; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_ULong ch = 0; +#endif + + + p = script_class->standard_charstring; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + /* + * We check a list of standard characters to catch features like + * `c2sc' (small caps from caps) that don't contain lowercase letters + * by definition, or other features that mainly operate on numerals. + * The first match wins. + */ + + glyph_index = 0; + while ( *p ) + { + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* otherwise exit loop if we have a result */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); + if ( glyph_index ) + break; + } + + af_shaper_buf_destroy( face, shaper_buf ); + + if ( !glyph_index ) + { + FT_TRACE5(( "standard character missing;" + " using fallback stem widths\n" )); + goto Exit; + } + + FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n", + ch, glyph_index )); + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + + FT_ZERO( dummy ); + + dummy->units_per_em = metrics->units_per_em; + + scaler->x_scale = 0x10000L; + scaler->y_scale = 0x10000L; + scaler->x_delta = 0; + scaler->y_delta = 0; + + scaler->face = face; + scaler->render_mode = FT_RENDER_MODE_NORMAL; + scaler->flags = 0; + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy ); + + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + + + error = af_latin_hints_compute_segments( hints, + (AF_Dimension)dim ); + if ( error ) + goto Exit; + + /* + * We assume that the glyphs selected for the stem width + * computation are `featureless' enough so that the linking + * algorithm works fine without adjustments of its scoring + * function. + */ + af_latin_hints_link_segments( hints, + 0, + NULL, + (AF_Dimension)dim ); + + seg = axhints->segments; + limit = FT_OFFSET( seg, axhints->num_segments ); + + for ( ; seg < limit; seg++ ) + { + link = seg->link; + + /* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + + + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + + if ( num_widths < AF_LATIN_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } + + /* this also replaces multiple almost identical stem widths */ + /* with a single one (the value 100 is heuristic) */ + af_sort_and_quantize_widths( &num_widths, axis->widths, + dummy->units_per_em / 100 ); + axis->width_count = num_widths; + } + + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + + + stdw = ( axis->width_count > 0 ) ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); + + /* let's try 20% of the smallest width */ + axis->edge_distance_threshold = stdw / 5; + axis->standard_width = stdw; + axis->extra_light = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + FT_TRACE5(( "%s widths:\n", + dim == AF_DIMENSION_VERT ? "horizontal" + : "vertical" )); + + FT_TRACE5(( " %ld (standard)", axis->standard_width )); + for ( i = 1; i < axis->width_count; i++ ) + FT_TRACE5(( " %ld", axis->widths[i].org )); + + FT_TRACE5(( "\n" )); + } +#endif + } + } + + FT_TRACE5(( "\n" )); + + af_glyph_hints_done( hints ); + } + + + static void + af_latin_sort_blue( FT_UInt count, + AF_LatinBlue* table ) + { + FT_UInt i, j; + AF_LatinBlue swap; + + + /* we sort from bottom to top */ + for ( i = 1; i < count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + FT_Pos a, b; + + + if ( table[j - 1]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + a = table[j - 1]->ref.org; + else + a = table[j - 1]->shoot.org; + + if ( table[j]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + b = table[j]->ref.org; + else + b = table[j]->shoot.org; + + if ( b >= a ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + } + + + /* Find all blue zones. Flat segments give the reference points, */ + /* round segments the overshoot positions. */ + + static int + af_latin_metrics_init_blues( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_Pos flats [AF_BLUE_STRING_MAX_LEN]; + FT_Pos rounds[AF_BLUE_STRING_MAX_LEN]; + + FT_UInt num_flats; + FT_UInt num_rounds; + + AF_LatinBlue blue; + FT_Error error; + AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; + FT_Outline outline; + + AF_StyleClass sc = metrics->root.style_class; + + AF_Blue_Stringset bss = sc->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + + FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em ); + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + + /* we walk over the blue character strings as specified in the */ + /* style's entry in the `af_blue_stringset' array */ + + FT_TRACE5(( "latin blue zones computation\n" )); + FT_TRACE5(( "============================\n" )); + FT_TRACE5(( "\n" )); + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) + { + const char* p = &af_blue_strings[bs->string]; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + FT_Pos ascender; + FT_Pos descender; + + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Bool have_flag = 0; + + + FT_TRACE5(( "blue zone %d", axis->blue_count )); + + if ( bs->properties ) + { + FT_TRACE5(( " (" )); + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + { + FT_TRACE5(( "top" )); + have_flag = 1; + } + else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) ) + { + FT_TRACE5(( "sub top" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "neutral" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "small top" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_LONG_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "long" )); + } + + FT_TRACE5(( ")" )); + } + + FT_TRACE5(( ":\n" )); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + num_flats = 0; + num_rounds = 0; + ascender = 0; + descender = 0; + + while ( *p ) + { + FT_ULong glyph_index; + FT_Long y_offset; + FT_Int best_point, best_contour_first, best_contour_last; + FT_Vector* points; + + FT_Pos best_y_extremum; /* same as points.y */ + FT_Bool best_round = 0; + + unsigned int i, num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; + FT_ULong ch; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + + if ( !num_idx ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + best_y_extremum = FT_INT_MIN; + else + best_y_extremum = FT_INT_MAX; + + /* iterate over all glyph elements of the character cluster */ + /* and get the data of the `biggest' one */ + for ( i = 0; i < num_idx; i++ ) + { + FT_Pos best_y; + FT_Bool round = 0; + + + /* load the character in the face -- skip unknown or empty ones */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + i, + NULL, + &y_offset ); + if ( glyph_index == 0 ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + outline = face->glyph->outline; + /* reject glyphs that don't produce any rendering */ + if ( error || outline.n_points <= 2 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( num_idx == 1 ) + FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); + else + FT_TRACE5(( " component %d of cluster starting with U+%04lX" + " contains no (usable) outlines\n", i, ch )); +#endif + continue; + } + + /* now compute min or max point indices and coordinates */ + points = outline.points; + best_point = -1; + best_contour_first = -1; + best_contour_last = -1; + best_y = 0; /* make compiler happy */ + + { + FT_Int nn; + FT_Int pp, first, last; + + + last = -1; + for ( nn = 0; nn < outline.n_contours; nn++ ) + { + first = last + 1; + last = outline.contours[nn]; + + /* Avoid single-point contours since they are never */ + /* rasterized. In some fonts, they correspond to mark */ + /* attachment points that are way outside of the glyph's */ + /* real outline. */ + if ( last <= first ) + continue; + + if ( AF_LATIN_IS_TOP_BLUE( bs ) || + AF_LATIN_IS_SUB_TOP_BLUE( bs ) ) + { + for ( pp = first; pp <= last; pp++ ) + { + if ( best_point < 0 || points[pp].y > best_y ) + { + best_point = pp; + best_y = points[pp].y; + ascender = FT_MAX( ascender, best_y + y_offset ); + } + else + descender = FT_MIN( descender, points[pp].y + y_offset ); + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + { + if ( best_point < 0 || points[pp].y < best_y ) + { + best_point = pp; + best_y = points[pp].y; + descender = FT_MIN( descender, best_y + y_offset ); + } + else + ascender = FT_MAX( ascender, points[pp].y + y_offset ); + } + } + + if ( best_point > best_contour_last ) + { + best_contour_first = first; + best_contour_last = last; + } + } + } + + /* now check whether the point belongs to a straight or round */ + /* segment; we first need to find in which contour the extremum */ + /* lies, then inspect its previous and next points */ + if ( best_point >= 0 ) + { + FT_Pos best_x = points[best_point].x; + FT_Int prev, next; + FT_Int best_segment_first, best_segment_last; + FT_Int best_on_point_first, best_on_point_last; + FT_Pos dist; + + + best_segment_first = best_point; + best_segment_last = best_point; + + if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON ) + { + best_on_point_first = best_point; + best_on_point_last = best_point; + } + else + { + best_on_point_first = -1; + best_on_point_last = -1; + } + + /* look for the previous and next points on the contour */ + /* that are not on the same Y coordinate, then threshold */ + /* the `closeness'... */ + prev = best_point; + next = prev; + + do + { + if ( prev > best_contour_first ) + prev--; + else + prev = best_contour_last; + + dist = FT_ABS( points[prev].y - best_y ); + /* accept a small distance or a small angle (both values are */ + /* heuristic; value 20 corresponds to approx. 2.9 degrees) */ + if ( dist > 5 ) + if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist ) + break; + + best_segment_first = prev; + + if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON ) + { + best_on_point_first = prev; + if ( best_on_point_last < 0 ) + best_on_point_last = prev; + } + + } while ( prev != best_point ); + + do + { + if ( next < best_contour_last ) + next++; + else + next = best_contour_first; + + dist = FT_ABS( points[next].y - best_y ); + if ( dist > 5 ) + if ( FT_ABS( points[next].x - best_x ) <= 20 * dist ) + break; + + best_segment_last = next; + + if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON ) + { + best_on_point_last = next; + if ( best_on_point_first < 0 ) + best_on_point_first = next; + } + + } while ( next != best_point ); + + if ( AF_LATIN_IS_LONG_BLUE( bs ) ) + { + /* If this flag is set, we have an additional constraint to */ + /* get the blue zone distance: Find a segment of the topmost */ + /* (or bottommost) contour that is longer than a heuristic */ + /* threshold. This ensures that small bumps in the outline */ + /* are ignored (for example, the `vertical serifs' found in */ + /* many Hebrew glyph designs). */ + + /* If this segment is long enough, we are done. Otherwise, */ + /* search the segment next to the extremum that is long */ + /* enough, has the same direction, and a not too large */ + /* vertical distance from the extremum. Note that the */ + /* algorithm doesn't check whether the found segment is */ + /* actually the one (vertically) nearest to the extremum. */ + + /* heuristic threshold value */ + FT_Pos length_threshold = metrics->units_per_em / 25; + + + dist = FT_ABS( points[best_segment_last].x - + points[best_segment_first].x ); + + if ( dist < length_threshold && + best_segment_last - best_segment_first + 2 <= + best_contour_last - best_contour_first ) + { + /* heuristic threshold value */ + FT_Pos height_threshold = metrics->units_per_em / 4; + + FT_Int first; + FT_Int last; + FT_Bool hit; + + /* we intentionally declare these two variables */ + /* outside of the loop since various compilers emit */ + /* incorrect warning messages otherwise, talking about */ + /* `possibly uninitialized variables' */ + FT_Int p_first = 0; /* make compiler happy */ + FT_Int p_last = 0; + + FT_Bool left2right; + + + /* compute direction */ + prev = best_point; + + do + { + if ( prev > best_contour_first ) + prev--; + else + prev = best_contour_last; + + if ( points[prev].x != best_x ) + break; + + } while ( prev != best_point ); + + /* skip glyph for the degenerate case */ + if ( prev == best_point ) + continue; + + left2right = FT_BOOL( points[prev].x < points[best_point].x ); + + first = best_segment_last; + last = first; + hit = 0; + + do + { + FT_Bool l2r; + FT_Pos d; + + + if ( !hit ) + { + /* no hit; adjust first point */ + first = last; + + /* also adjust first and last on point */ + if ( FT_CURVE_TAG( outline.tags[first] ) == + FT_CURVE_TAG_ON ) + { + p_first = first; + p_last = first; + } + else + { + p_first = -1; + p_last = -1; + } + + hit = 1; + } + + if ( last < best_contour_last ) + last++; + else + last = best_contour_first; + + if ( FT_ABS( best_y - points[first].y ) > height_threshold ) + { + /* vertical distance too large */ + hit = 0; + continue; + } + + /* same test as above */ + dist = FT_ABS( points[last].y - points[first].y ); + if ( dist > 5 ) + if ( FT_ABS( points[last].x - points[first].x ) <= + 20 * dist ) + { + hit = 0; + continue; + } + + if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON ) + { + p_last = last; + if ( p_first < 0 ) + p_first = last; + } + + l2r = FT_BOOL( points[first].x < points[last].x ); + d = FT_ABS( points[last].x - points[first].x ); + + if ( l2r == left2right && + d >= length_threshold ) + { + /* all constraints are met; update segment after */ + /* finding its end */ + do + { + if ( last < best_contour_last ) + last++; + else + last = best_contour_first; + + d = FT_ABS( points[last].y - points[first].y ); + if ( d > 5 ) + if ( FT_ABS( points[next].x - points[first].x ) <= + 20 * dist ) + { + if ( last > best_contour_first ) + last--; + else + last = best_contour_last; + break; + } + + p_last = last; + + if ( FT_CURVE_TAG( outline.tags[last] ) == + FT_CURVE_TAG_ON ) + { + p_last = last; + if ( p_first < 0 ) + p_first = last; + } + + } while ( last != best_segment_first ); + + best_y = points[first].y; + + best_segment_first = first; + best_segment_last = last; + + best_on_point_first = p_first; + best_on_point_last = p_last; + + break; + } + + } while ( last != best_segment_first ); + } + } + + /* for computing blue zones, we add the y offset as returned */ + /* by the currently used OpenType feature -- for example, */ + /* superscript glyphs might be identical to subscript glyphs */ + /* with a vertical shift */ + best_y += y_offset; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( num_idx == 1 ) + FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y )); + else + FT_TRACE5(( " component %d of cluster starting with U+%04lX:" + " best_y = %5ld", i, ch, best_y )); +#endif + + /* now set the `round' flag depending on the segment's kind: */ + /* */ + /* - if the horizontal distance between the first and last */ + /* `on' point is larger than a heuristic threshold */ + /* we have a flat segment */ + /* - if either the first or the last point of the segment is */ + /* an `off' point, the segment is round, otherwise it is */ + /* flat */ + if ( best_on_point_first >= 0 && + best_on_point_last >= 0 && + ( FT_ABS( points[best_on_point_last].x - + points[best_on_point_first].x ) ) > + flat_threshold ) + round = 0; + else + round = FT_BOOL( + FT_CURVE_TAG( outline.tags[best_segment_first] ) != + FT_CURVE_TAG_ON || + FT_CURVE_TAG( outline.tags[best_segment_last] ) != + FT_CURVE_TAG_ON ); + + if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) + { + /* only use flat segments for a neutral blue zone */ + FT_TRACE5(( " (round, skipped)\n" )); + continue; + } + + FT_TRACE5(( " (%s)\n", round ? "round" : "flat" )); + } + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + { + if ( best_y > best_y_extremum ) + { + best_y_extremum = best_y; + best_round = round; + } + } + else + { + if ( best_y < best_y_extremum ) + { + best_y_extremum = best_y; + best_round = round; + } + } + + } /* end for loop */ + + if ( !( best_y_extremum == FT_INT_MIN || + best_y_extremum == FT_INT_MAX ) ) + { + if ( best_round ) + rounds[num_rounds++] = best_y_extremum; + else + flats[num_flats++] = best_y_extremum; + } + + } /* end while loop */ + + if ( num_flats == 0 && num_rounds == 0 ) + { + /* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( " empty\n" )); + continue; + } + + /* we have computed the contents of the `rounds' and `flats' tables, */ + /* now determine the reference and overshoot position of the blue -- */ + /* we simply take the median value after a simple sort */ + af_sort_pos( num_rounds, rounds ); + af_sort_pos( num_flats, flats ); + + blue = &axis->blues[axis->blue_count]; + blue_ref = &blue->ref.org; + blue_shoot = &blue->shoot.org; + + axis->blue_count++; + + if ( num_flats == 0 ) + { + *blue_ref = + *blue_shoot = rounds[num_rounds / 2]; + } + else if ( num_rounds == 0 ) + { + *blue_ref = + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = flats [num_flats / 2]; + *blue_shoot = rounds[num_rounds / 2]; + } + + /* there are sometimes problems: if the overshoot position of top */ + /* zones is under its reference position, or the opposite for bottom */ + /* zones. We must thus check everything there and correct the errors */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool over_ref = FT_BOOL( shoot > ref ); + + + if ( ( AF_LATIN_IS_TOP_BLUE( bs ) || + AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + + FT_TRACE5(( " [overshoot smaller than reference," + " taking mean value]\n" )); + } + } + + blue->ascender = ascender; + blue->descender = descender; + + blue->flags = 0; + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_TOP; + if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_SUB_TOP; + if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_NEUTRAL; + + /* + * The following flag is used later to adjust the y and x scales + * in order to optimize the pixel grid alignment of the top of small + * letters. + */ + if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; + + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); + + } /* end for loop */ + + af_shaper_buf_destroy( face, shaper_buf ); + + if ( axis->blue_count ) + { + /* we finally check whether blue zones are ordered; */ + /* `ref' and `shoot' values of two blue zones must not overlap */ + + FT_UInt i; + AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN + 2]; + + + for ( i = 0; i < axis->blue_count; i++ ) + blue_sorted[i] = &axis->blues[i]; + + /* sort bottoms of blue zones... */ + af_latin_sort_blue( axis->blue_count, blue_sorted ); + + /* ...and adjust top values if necessary */ + for ( i = 0; i < axis->blue_count - 1; i++ ) + { + FT_Pos* a; + FT_Pos* b; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool a_is_top = 0; +#endif + + + if ( blue_sorted[i]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + { + a = &blue_sorted[i]->shoot.org; +#ifdef FT_DEBUG_LEVEL_TRACE + a_is_top = 1; +#endif + } + else + a = &blue_sorted[i]->ref.org; + + if ( blue_sorted[i + 1]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + b = &blue_sorted[i + 1]->shoot.org; + else + b = &blue_sorted[i + 1]->ref.org; + + if ( *a > *b ) + { + *a = *b; + FT_TRACE5(( "blue zone overlap:" + " adjusting %s %td to %ld\n", + a_is_top ? "overshoot" : "reference", + blue_sorted[i] - axis->blues, + *a )); + } + } + + FT_TRACE5(( "\n" )); + + return 0; + } + else + { + /* disable hinting for the current style if there are no blue zones */ + + AF_FaceGlobals globals = metrics->root.globals; + FT_UShort* gstyles = globals->glyph_styles; + + FT_UInt i; + + + FT_TRACE5(( "no blue zones found:" + " hinting disabled for this style\n" )); + + for ( i = 0; i < globals->glyph_count; i++ ) + { + if ( ( gstyles[i] & AF_STYLE_MASK ) == sc->style ) + gstyles[i] = AF_STYLE_NONE_DFLT; + } + + FT_TRACE5(( "\n" )); + + return 1; + } + } + + + /* Check whether all ASCII digits have the same advance width. */ + + FT_LOCAL_DEF( void ) + af_latin_metrics_check_digits( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_Bool started = 0, same_width = 1; + FT_Long advance = 0, old_advance = 0; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + /* in all supported charmaps, digits have character codes 0x30-0x39 */ + const char digits[] = "0 1 2 3 4 5 6 7 8 9"; + const char* p; + + + p = digits; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + while ( *p ) + { + FT_ULong glyph_index; + unsigned int num_idx; + + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + &advance, + NULL ); + if ( !glyph_index ) + continue; + + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + + af_shaper_buf_destroy( face, shaper_buf ); + + metrics->root.digits_have_same_width = same_width; + } + + + /* Initialize global metrics. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_metrics_init( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ + FT_Face face ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + FT_Error error = FT_Err_Ok; + + FT_CharMap oldmap = face->charmap; + + + metrics->units_per_em = face->units_per_EM; + + if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + { + af_latin_metrics_init_widths( metrics, face ); + if ( af_latin_metrics_init_blues( metrics, face ) ) + { + /* use internal error code to indicate missing blue zones */ + error = -1; + goto Exit; + } + af_latin_metrics_check_digits( metrics, face ); + } + + Exit: + face->charmap = oldmap; + return error; + } + + + /* Adjust scaling value, then scale and shift widths */ + /* and blue zones (if applicable) for given dimension. */ + + static void + af_latin_metrics_scale_dim( AF_LatinMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) + { + FT_Fixed scale; + FT_Pos delta; + AF_LatinAxis axis; + FT_UInt nn; + + + if ( dim == AF_DIMENSION_HORZ ) + { + scale = scaler->x_scale; + delta = scaler->x_delta; + } + else + { + scale = scaler->y_scale; + delta = scaler->y_delta; + } + + axis = &metrics->axis[dim]; + + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + + axis->org_scale = scale; + axis->org_delta = delta; + + /* + * correct X and Y scale to optimize the alignment of the top of small + * letters to the pixel grid + */ + { + AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; + AF_LatinBlue blue = NULL; + + + for ( nn = 0; nn < Axis->blue_count; nn++ ) + { + if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) + { + blue = &Axis->blues[nn]; + break; + } + } + + if ( blue ) + { + FT_Pos scaled; + FT_Pos threshold; + FT_Pos fitted; + FT_UInt limit; + FT_UInt ppem; + + + scaled = FT_MulFix( blue->shoot.org, scale ); + ppem = metrics->root.scaler.face->size->metrics.x_ppem; + limit = metrics->root.globals->increase_x_height; + threshold = 40; + + /* if the `increase-x-height' property is active, */ + /* we round up much more often */ + if ( limit && + ppem <= limit && + ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN ) + threshold = 52; + + fitted = ( scaled + threshold ) & ~63; + + if ( scaled != fitted ) + { +#if 0 + if ( dim == AF_DIMENSION_HORZ ) + { + if ( fitted < scaled ) + scale -= scale / 50; /* scale *= 0.98 */ + } + else +#endif + if ( dim == AF_DIMENSION_VERT ) + { + FT_Pos max_height; + FT_Pos dist; + FT_Fixed new_scale; + + + new_scale = FT_MulDiv( scale, fitted, scaled ); + + /* the scaling should not change the result by more than two pixels */ + max_height = metrics->units_per_em; + + for ( nn = 0; nn < Axis->blue_count; nn++ ) + { + max_height = FT_MAX( max_height, Axis->blues[nn].ascender ); + max_height = FT_MAX( max_height, -Axis->blues[nn].descender ); + } + + dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) ); + dist &= ~127; + + if ( dist == 0 ) + { + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " vertical scaling changed" + " from %.5f to %.5f (by %ld%%)\n", + (double)scale / 65536, + (double)new_scale / 65536, + ( fitted - scaled ) * 100 / scaled )); + FT_TRACE5(( "\n" )); + + scale = new_scale; + } +#ifdef FT_DEBUG_LEVEL_TRACE + else + { + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " excessive vertical scaling abandoned\n" )); + FT_TRACE5(( "\n" )); + } +#endif + } + } + } + } + + axis->scale = scale; + axis->delta = delta; + + if ( dim == AF_DIMENSION_HORZ ) + { + metrics->root.scaler.x_scale = scale; + metrics->root.scaler.x_delta = delta; + } + else + { + metrics->root.scaler.y_scale = scale; + metrics->root.scaler.y_delta = delta; + } + + FT_TRACE5(( "%s widths (style `%s')\n", + dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical", + af_style_names[metrics->root.style_class->style] )); + + /* scale the widths */ + for ( nn = 0; nn < axis->width_count; nn++ ) + { + AF_Width width = axis->widths + nn; + + + width->cur = FT_MulFix( width->org, scale ); + width->fit = width->cur; + + FT_TRACE5(( " %ld scaled to %.2f\n", + width->org, + (double)width->cur / 64 )); + } + + FT_TRACE5(( "\n" )); + + /* an extra-light axis corresponds to a standard width that is */ + /* smaller than 5/8 pixels */ + axis->extra_light = + FT_BOOL( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( axis->extra_light ) + { + FT_TRACE5(( "`%s' style is extra light (at current resolution)\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "\n" )); + } +#endif + + if ( dim == AF_DIMENSION_VERT ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( axis->blue_count ) + FT_TRACE5(( "blue zones (style `%s')\n", + af_style_names[metrics->root.style_class->style] )); +#endif + + /* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + FT_Pos dist; + + + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_LATIN_BLUE_ACTIVE; + + /* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { +#if 0 + FT_Pos delta1; +#endif + FT_Pos delta2; + + + /* use discrete values for blue zone widths */ + +#if 0 + + /* generic, original code */ + delta1 = blue->shoot.org - blue->ref.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + + delta2 = FT_MulFix( delta2, scale ); + + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); + else + delta2 = FT_PIX_ROUND( delta2 ); + + if ( delta1 < 0 ) + delta2 = -delta2; + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->shoot.fit = blue->ref.fit + delta2; + +#else + + /* simplified version due to abs(dist) <= 48 */ + delta2 = dist; + if ( dist < 0 ) + delta2 = -delta2; + + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta2 < 48 ) + delta2 = 32; + else + delta2 = 64; + + if ( dist < 0 ) + delta2 = -delta2; + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->shoot.fit = blue->ref.fit - delta2; + +#endif + + blue->flags |= AF_LATIN_BLUE_ACTIVE; + } + } + + /* use sub-top blue zone only if it doesn't overlap with */ + /* another (non-sup-top) blue zone; otherwise, the */ + /* effect would be similar to a neutral blue zone, which */ + /* is not desired here */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + FT_UInt i; + + + if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) ) + continue; + if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; + + for ( i = 0; i < axis->blue_count; i++ ) + { + AF_LatinBlue b = &axis->blues[i]; + + + if ( b->flags & AF_LATIN_BLUE_SUB_TOP ) + continue; + if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; + + if ( b->ref.fit <= blue->shoot.fit && + b->shoot.fit >= blue->ref.fit ) + { + blue->flags &= ~AF_LATIN_BLUE_ACTIVE; + break; + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + + + FT_TRACE5(( " reference %d: %ld scaled to %.2f%s\n", + nn, + blue->ref.org, + (double)blue->ref.fit / 64, + ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" + : " (inactive)" )); + FT_TRACE5(( " overshoot %d: %ld scaled to %.2f%s\n", + nn, + blue->shoot.org, + (double)blue->shoot.fit / 64, + ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" + : " (inactive)" )); + } +#endif + } + } + + + /* Scale global values in both directions. */ + + FT_LOCAL_DEF( void ) + af_latin_metrics_scale( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ + AF_Scaler scaler ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + + metrics->root.scaler.render_mode = scaler->render_mode; + metrics->root.scaler.face = scaler->face; + metrics->root.scaler.flags = scaler->flags; + + af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); + af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); + } + + + /* Extract standard_width from writing system/script specific */ + /* metrics class. */ + + FT_CALLBACK_DEF( void ) + af_latin_get_standard_widths( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + + if ( stdHW ) + *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; + + if ( stdVW ) + *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L Y P H A N A L Y S I S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Walk over all contours and compute its segments. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; + AF_AxisHints axis = &hints->axis[dim]; + FT_Memory memory = hints->memory; + FT_Error error = FT_Err_Ok; + AF_Segment segment = NULL; + AF_SegmentRec seg0; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + AF_Direction major_dir, segment_dir; + + FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em ); + + + FT_ZERO( &seg0 ); + seg0.score = 32000; + seg0.flags = AF_EDGE_NORMAL; + + major_dir = (AF_Direction)FT_ABS( axis->major_dir ); + segment_dir = major_dir; + + axis->num_segments = 0; + + /* set up (u,v) in each point */ + if ( dim == AF_DIMENSION_HORZ ) + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + + + for ( ; point < limit; point++ ) + { + point->u = point->fx; + point->v = point->fy; + } + } + else + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + + + for ( ; point < limit; point++ ) + { + point->u = point->fy; + point->v = point->fx; + } + } + + /* do each contour separately */ + for ( ; contour < contour_limit; contour++ ) + { + AF_Point point = contour[0]; + AF_Point last = point->prev; + int on_edge = 0; + + /* we call values measured along a segment (point->v) */ + /* `coordinates', and values orthogonal to it (point->u) */ + /* `positions' */ + FT_Pos min_pos = 32000; + FT_Pos max_pos = -32000; + FT_Pos min_coord = 32000; + FT_Pos max_coord = -32000; + FT_UShort min_flags = AF_FLAG_NONE; + FT_UShort max_flags = AF_FLAG_NONE; + FT_Pos min_on_coord = 32000; + FT_Pos max_on_coord = -32000; + + FT_Bool passed; + + AF_Segment prev_segment = NULL; + + FT_Pos prev_min_pos = min_pos; + FT_Pos prev_max_pos = max_pos; + FT_Pos prev_min_coord = min_coord; + FT_Pos prev_max_coord = max_coord; + FT_UShort prev_min_flags = min_flags; + FT_UShort prev_max_flags = max_flags; + FT_Pos prev_min_on_coord = min_on_coord; + FT_Pos prev_max_on_coord = max_on_coord; + + + if ( FT_ABS( last->out_dir ) == major_dir && + FT_ABS( point->out_dir ) == major_dir ) + { + /* we are already on an edge, try to locate its start */ + last = point; + + for (;;) + { + point = point->prev; + if ( FT_ABS( point->out_dir ) != major_dir ) + { + point = point->next; + break; + } + if ( point == last ) + break; + } + } + + last = point; + passed = 0; + + for (;;) + { + FT_Pos u, v; + + + if ( on_edge ) + { + /* get minimum and maximum position */ + u = point->u; + if ( u < min_pos ) + min_pos = u; + if ( u > max_pos ) + max_pos = u; + + /* get minimum and maximum coordinate together with flags */ + v = point->v; + if ( v < min_coord ) + { + min_coord = v; + min_flags = point->flags; + } + if ( v > max_coord ) + { + max_coord = v; + max_flags = point->flags; + } + + /* get minimum and maximum coordinate of `on' points */ + if ( !( point->flags & AF_FLAG_CONTROL ) ) + { + v = point->v; + if ( v < min_on_coord ) + min_on_coord = v; + if ( v > max_on_coord ) + max_on_coord = v; + } + + if ( point->out_dir != segment_dir || point == last ) + { + /* check whether the new segment's start point is identical to */ + /* the previous segment's end point; for example, this might */ + /* happen for spikes */ + + if ( !prev_segment || segment->first != prev_segment->last ) + { + /* points are different: we are just leaving an edge, thus */ + /* record a new segment */ + + segment->last = point; + segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 ); + segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 ); + + /* a segment is round if either its first or last point */ + /* is a control point, and the length of the on points */ + /* inbetween doesn't exceed a heuristic limit */ + if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL && + ( max_on_coord - min_on_coord ) < flat_threshold ) + segment->flags |= AF_EDGE_ROUND; + + segment->min_coord = (FT_Short)min_coord; + segment->max_coord = (FT_Short)max_coord; + segment->height = segment->max_coord - segment->min_coord; + + prev_segment = segment; + prev_min_pos = min_pos; + prev_max_pos = max_pos; + prev_min_coord = min_coord; + prev_max_coord = max_coord; + prev_min_flags = min_flags; + prev_max_flags = max_flags; + prev_min_on_coord = min_on_coord; + prev_max_on_coord = max_on_coord; + } + else + { + /* points are the same: we don't create a new segment but */ + /* merge the current segment with the previous one */ + + if ( prev_segment->last->in_dir == point->in_dir ) + { + /* we have identical directions (this can happen for */ + /* degenerate outlines that move zig-zag along the main */ + /* axis without changing the coordinate value of the other */ + /* axis, and where the segments have just been merged): */ + /* unify segments */ + + /* update constraints */ + + if ( prev_min_pos < min_pos ) + min_pos = prev_min_pos; + if ( prev_max_pos > max_pos ) + max_pos = prev_max_pos; + + if ( prev_min_coord < min_coord ) + { + min_coord = prev_min_coord; + min_flags = prev_min_flags; + } + if ( prev_max_coord > max_coord ) + { + max_coord = prev_max_coord; + max_flags = prev_max_flags; + } + + if ( prev_min_on_coord < min_on_coord ) + min_on_coord = prev_min_on_coord; + if ( prev_max_on_coord > max_on_coord ) + max_on_coord = prev_max_on_coord; + + prev_segment->last = point; + prev_segment->pos = (FT_Short)( ( min_pos + + max_pos ) >> 1 ); + prev_segment->delta = (FT_Short)( ( max_pos - + min_pos ) >> 1 ); + + if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL && + ( max_on_coord - min_on_coord ) < flat_threshold ) + prev_segment->flags |= AF_EDGE_ROUND; + else + prev_segment->flags &= ~AF_EDGE_ROUND; + + prev_segment->min_coord = (FT_Short)min_coord; + prev_segment->max_coord = (FT_Short)max_coord; + prev_segment->height = prev_segment->max_coord - + prev_segment->min_coord; + } + else + { + /* we have different directions; use the properties of the */ + /* longer segment and discard the other one */ + + if ( FT_ABS( prev_max_coord - prev_min_coord ) > + FT_ABS( max_coord - min_coord ) ) + { + /* discard current segment */ + + if ( min_pos < prev_min_pos ) + prev_min_pos = min_pos; + if ( max_pos > prev_max_pos ) + prev_max_pos = max_pos; + + prev_segment->last = point; + prev_segment->pos = (FT_Short)( ( prev_min_pos + + prev_max_pos ) >> 1 ); + prev_segment->delta = (FT_Short)( ( prev_max_pos - + prev_min_pos ) >> 1 ); + } + else + { + /* discard previous segment */ + + if ( prev_min_pos < min_pos ) + min_pos = prev_min_pos; + if ( prev_max_pos > max_pos ) + max_pos = prev_max_pos; + + segment->last = point; + segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 ); + segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 ); + + if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL && + ( max_on_coord - min_on_coord ) < flat_threshold ) + segment->flags |= AF_EDGE_ROUND; + + segment->min_coord = (FT_Short)min_coord; + segment->max_coord = (FT_Short)max_coord; + segment->height = segment->max_coord - + segment->min_coord; + + *prev_segment = *segment; + + prev_min_pos = min_pos; + prev_max_pos = max_pos; + prev_min_coord = min_coord; + prev_max_coord = max_coord; + prev_min_flags = min_flags; + prev_max_flags = max_flags; + prev_min_on_coord = min_on_coord; + prev_max_on_coord = max_on_coord; + } + } + + axis->num_segments--; + } + + on_edge = 0; + segment = NULL; + + /* fall through */ + } + } + + /* now exit if we are at the start/end point */ + if ( point == last ) + { + if ( passed ) + break; + passed = 1; + } + + /* if we are not on an edge, check whether the major direction */ + /* coincides with the current point's `out' direction, or */ + /* whether we have a single-point contour */ + if ( !on_edge && + ( FT_ABS( point->out_dir ) == major_dir || + point == point->prev ) ) + { + /* + * For efficiency, we restrict the number of segments to 1000, + * which is a heuristic value: it is very unlikely that a glyph + * with so many segments can be hinted in a sensible way. + * Reasons: + * + * - The glyph has really 1000 segments; this implies that it has + * at least 2000 outline points. Assuming 'normal' fonts that + * have superfluous points optimized away, viewing such a glyph + * only makes sense at large magnifications where hinting + * isn't applied anyway. + * + * - We have a broken glyph. Hinting doesn't make sense in this + * case either. + */ + if ( axis->num_segments > 1000 ) + { + FT_TRACE0(( "af_latin_hints_compute_segments:" + " more than 1000 segments in this glyph;\n" )); + FT_TRACE0(( " " + " hinting is suppressed\n" )); + axis->num_segments = 0; + return FT_Err_Ok; + } + + /* this is the start of a new segment! */ + segment_dir = (AF_Direction)point->out_dir; + + error = af_axis_hints_new_segment( axis, memory, &segment ); + if ( error ) + goto Exit; + + /* clear all segment fields */ + segment[0] = seg0; + + segment->dir = (FT_Char)segment_dir; + segment->first = point; + segment->last = point; + + /* `af_axis_hints_new_segment' reallocates memory, */ + /* thus we have to refresh the `prev_segment' pointer */ + if ( prev_segment ) + prev_segment = segment - 1; + + min_pos = max_pos = point->u; + min_coord = max_coord = point->v; + min_flags = max_flags = point->flags; + + if ( point->flags & AF_FLAG_CONTROL ) + { + min_on_coord = 32000; + max_on_coord = -32000; + } + else + min_on_coord = max_on_coord = point->v; + + on_edge = 1; + + if ( point == point->prev ) + { + /* we have a one-point segment: this is a one-point */ + /* contour with `in' and `out' direction set to */ + /* AF_DIR_NONE */ + segment->pos = (FT_Short)min_pos; + + if (point->flags & AF_FLAG_CONTROL) + segment->flags |= AF_EDGE_ROUND; + + segment->min_coord = (FT_Short)point->v; + segment->max_coord = (FT_Short)point->v; + segment->height = 0; + + on_edge = 0; + segment = NULL; + } + } + + point = point->next; + } + + } /* contours */ + + + /* now slightly increase the height of segments if this makes */ + /* sense -- this is used to better detect and ignore serifs */ + { + AF_Segment segments = axis->segments; + AF_Segment segments_end = FT_OFFSET( segments, axis->num_segments ); + + + for ( segment = segments; segment < segments_end; segment++ ) + { + AF_Point first = segment->first; + AF_Point last = segment->last; + FT_Pos first_v = first->v; + FT_Pos last_v = last->v; + + + if ( first_v < last_v ) + { + AF_Point p; + + + p = first->prev; + if ( p->v < first_v ) + segment->height = (FT_Short)( segment->height + + ( ( first_v - p->v ) >> 1 ) ); + + p = last->next; + if ( p->v > last_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - last_v ) >> 1 ) ); + } + else + { + AF_Point p; + + + p = first->prev; + if ( p->v > first_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - first_v ) >> 1 ) ); + + p = last->next; + if ( p->v < last_v ) + segment->height = (FT_Short)( segment->height + + ( ( last_v - p->v ) >> 1 ) ); + } + } + } + + Exit: + return error; + } + + + /* Link segments to form stems and serifs. If `width_count' and */ + /* `widths' are non-zero, use them to fine-tune the scoring function. */ + + FT_LOCAL_DEF( void ) + af_latin_hints_link_segments( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + FT_Pos len_threshold, len_score, dist_score, max_width; + AF_Segment seg1, seg2; + + + if ( width_count ) + max_width = widths[width_count - 1].org; + else + max_width = 0; + + /* a heuristic value to set up a minimum value for overlapping */ + len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); + if ( len_threshold == 0 ) + len_threshold = 1; + + /* a heuristic value to weight lengths */ + len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 ); + + /* a heuristic value to weight distances (no call to */ + /* AF_LATIN_CONSTANT needed, since we work on multiples */ + /* of the stem width) */ + dist_score = 3000; + + /* now compare each segment to the others */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + if ( seg1->dir != axis->major_dir ) + continue; + + /* search for stems having opposite directions, */ + /* with seg1 to the `left' of seg2 */ + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + FT_Pos pos1 = seg1->pos; + FT_Pos pos2 = seg2->pos; + + + if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 ) + { + /* compute distance between the two segments */ + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len; + + + if ( min < seg2->min_coord ) + min = seg2->min_coord; + + if ( max > seg2->max_coord ) + max = seg2->max_coord; + + /* compute maximum coordinate difference of the two segments */ + /* (that is, how much they overlap) */ + len = max - min; + if ( len >= len_threshold ) + { + /* + * The score is the sum of two demerits indicating the + * `badness' of a fit, measured along the segments' main axis + * and orthogonal to it, respectively. + * + * - The less overlapping along the main axis, the worse it + * is, causing a larger demerit. + * + * - The nearer the orthogonal distance to a stem width, the + * better it is, causing a smaller demerit. For simplicity, + * however, we only increase the demerit for values that + * exceed the largest stem width. + */ + + FT_Pos dist = pos2 - pos1; + + FT_Pos dist_demerit, score; + + + if ( max_width ) + { + /* distance demerits are based on multiples of `max_width'; */ + /* we scale by 1024 for getting more precision */ + FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 ); + + + if ( delta > 10000 ) + dist_demerit = 32000; + else if ( delta > 0 ) + dist_demerit = delta * delta / dist_score; + else + dist_demerit = 0; + } + else + dist_demerit = dist; /* default if no widths available */ + + score = dist_demerit + len_score / len; + + /* and we search for the smallest score */ + if ( score < seg1->score ) + { + seg1->score = score; + seg1->link = seg2; + } + + if ( score < seg2->score ) + { + seg2->score = score; + seg2->link = seg1; + } + } + } + } + } + + /* now compute the `serif' segments, cf. explanations in `afhints.h' */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg2 = seg1->link; + + if ( seg2 ) + { + if ( seg2->link != seg1 ) + { + seg1->link = NULL; + seg1->serif = seg2->link; + } + } + } + } + + + /* Link segments to edges, using feature analysis for selection. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = FT_Err_Ok; + FT_Memory memory = hints->memory; + AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; + + AF_StyleClass style_class = hints->metrics->style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + FT_Bool top_to_bottom_hinting = 0; + + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Segment seg; + +#if 0 + AF_Direction up_dir; +#endif + FT_Fixed scale; + FT_Pos edge_distance_threshold; + FT_Pos segment_length_threshold; + FT_Pos segment_width_threshold; + + + axis->num_edges = 0; + + scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + +#if 0 + up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP + : AF_DIR_RIGHT; +#endif + + if ( dim == AF_DIMENSION_VERT ) + top_to_bottom_hinting = script_class->top_to_bottom_hinting; + + /* + * We ignore all segments that are less than 1 pixel in length + * to avoid many problems with serif fonts. We compute the + * corresponding threshold in font units. + */ + if ( dim == AF_DIMENSION_HORZ ) + segment_length_threshold = FT_DivFix( 64, hints->y_scale ); + else + segment_length_threshold = 0; + + /* + * Similarly, we ignore segments that have a width delta + * larger than 0.5px (i.e., a width larger than 1px). + */ + segment_width_threshold = FT_DivFix( 32, scale ); + + /********************************************************************** + * + * We begin by generating a sorted table of edges for the current + * direction. To do so, we simply scan each segment and try to find + * an edge in our table that corresponds to its position. + * + * If no edge is found, we create and insert a new edge in the + * sorted table. Otherwise, we simply add the segment to the edge's + * list which gets processed in the second step to compute the + * edge's properties. + * + * Note that the table of edges is sorted along the segment/edge + * position. + * + */ + + /* assure that edge distance threshold is at most 0.25px */ + edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = 64 / 4; + + edge_distance_threshold = FT_DivFix( edge_distance_threshold, + scale ); + + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = NULL; + FT_UInt ee; + + + /* ignore too short segments, too wide ones, and, in this loop, */ + /* one-point segments without a direction */ + if ( seg->height < segment_length_threshold || + seg->delta > segment_width_threshold || + seg->dir == AF_DIR_NONE ) + continue; + + /* A special case for serif edges: If they are smaller than */ + /* 1.5 pixels we ignore them. */ + if ( seg->serif && + 2 * seg->height < 3 * segment_length_threshold ) + continue; + + /* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + + + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + + if ( dist < edge_distance_threshold && edge->dir == seg->dir ) + { + found = edge; + break; + } + } + + if ( !found ) + { + AF_Edge edge; + + + /* insert a new edge in the list and */ + /* sort according to the position */ + error = af_axis_hints_new_edge( axis, seg->pos, + (AF_Direction)seg->dir, + top_to_bottom_hinting, + memory, &edge ); + if ( error ) + goto Exit; + + /* add the segment to the new edge's list */ + FT_ZERO( edge ); + + edge->first = seg; + edge->last = seg; + edge->dir = seg->dir; + edge->fpos = seg->pos; + edge->opos = FT_MulFix( seg->pos, scale ); + edge->pos = edge->opos; + seg->edge_next = seg; + } + else + { + /* if an edge was found, simply add the segment to the edge's */ + /* list */ + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } + + /* we loop again over all segments to catch one-point segments */ + /* without a direction: if possible, link them to existing edges */ + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = NULL; + FT_UInt ee; + + + if ( seg->dir != AF_DIR_NONE ) + continue; + + /* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + + + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + + if ( dist < edge_distance_threshold ) + { + found = edge; + break; + } + } + + /* one-point segments without a match are ignored */ + if ( found ) + { + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } + + + /******************************************************************* + * + * Good, we now compute each edge's properties according to the + * segments found on its position. Basically, these are + * + * - the edge's main direction + * - stem edge, serif edge or both (which defaults to stem then) + * - rounded edge, straight or both (which defaults to straight) + * - link for edge + * + */ + + /* first of all, set the `edge' field in each segment -- this is */ + /* required in order to compute edge links */ + + /* + * Note that removing this loop and setting the `edge' field of each + * segment directly in the code above slows down execution speed for + * some reasons on platforms like the Sun. + */ + { + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + + /* now compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Int is_round = 0; /* does it contain round segments? */ + FT_Int is_straight = 0; /* does it contain straight segments? */ +#if 0 + FT_Pos ups = 0; /* number of upwards segments */ + FT_Pos downs = 0; /* number of downwards segments */ +#endif + + + seg = edge->first; + + do + { + FT_Bool is_serif; + + + /* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; + +#if 0 + /* check for segment direction */ + if ( seg->dir == up_dir ) + ups += seg->max_coord - seg->min_coord; + else + downs += seg->max_coord - seg->min_coord; +#endif + + /* check for links -- if seg->serif is set, then seg->link must */ + /* be ignored */ + is_serif = FT_BOOL( seg->serif && + seg->serif->edge && + seg->serif->edge != edge ); + + if ( ( seg->link && seg->link->edge ) || is_serif ) + { + AF_Edge edge2; + AF_Segment seg2; + + + edge2 = edge->link; + seg2 = seg->link; + + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + + + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + + seg_delta = seg->pos - seg2->pos; + if ( seg_delta < 0 ) + seg_delta = -seg_delta; + + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + + /* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; + + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; + +#if 0 + /* set the edge's main direction */ + edge->dir = AF_DIR_NONE; + + if ( ups > downs ) + edge->dir = (FT_Char)up_dir; + + else if ( ups < downs ) + edge->dir = (FT_Char)-up_dir; + + else if ( ups == downs ) + edge->dir = 0; /* both up and down! */ +#endif + + /* get rid of serifs if link is set */ + /* XXX: This gets rid of many unpleasant artefacts! */ + /* Example: the `c' in cour.pfa at size 13 */ + + if ( edge->serif && edge->link ) + edge->serif = NULL; + } + } + + Exit: + return error; + } + + + /* Detect segments and edges for given dimension. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_detect_features( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ) + { + FT_Error error; + + + error = af_latin_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_latin_hints_link_segments( hints, width_count, widths, dim ); + + error = af_latin_hints_compute_edges( hints, dim ); + } + + return error; + } + + + /* Compute all edges which lie within blue zones. */ + + static void + af_latin_hints_compute_blue_edges( AF_GlyphHints hints, + AF_LatinMetrics metrics ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); + AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT]; + FT_Fixed scale = latin->scale; + + + /* compute which blue zones are active, i.e. have their scaled */ + /* size < 3/4 pixels */ + + /* for each horizontal edge search the blue zone which is closest */ + for ( ; edge < edge_limit; edge++ ) + { + FT_UInt bb; + AF_Width best_blue = NULL; + FT_Bool best_blue_is_neutral = 0; + FT_Pos best_dist; /* initial threshold */ + + + /* compute the initial threshold as a fraction of the EM size */ + /* (the value 40 is heuristic) */ + best_dist = FT_MulFix( metrics->units_per_em / 40, scale ); + + /* assure a minimum distance of 0.5px */ + if ( best_dist > 64 / 2 ) + best_dist = 64 / 2; + + for ( bb = 0; bb < latin->blue_count; bb++ ) + { + AF_LatinBlue blue = latin->blues + bb; + FT_Bool is_top_blue, is_neutral_blue, is_major_dir; + + + /* skip inactive blue zones (i.e., those that are too large) */ + if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; + + /* if it is a top zone, check for right edges (against the major */ + /* direction); if it is a bottom zone, check for left edges (in */ + /* the major direction) -- this assumes the TrueType convention */ + /* for the orientation of contours */ + is_top_blue = + (FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) != 0 ); + is_neutral_blue = + (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0); + is_major_dir = + FT_BOOL( edge->dir == axis->major_dir ); + + /* neutral blue zones are handled for both directions */ + if ( is_top_blue ^ is_major_dir || is_neutral_blue ) + { + FT_Pos dist; + + + /* first of all, compare it to the reference position */ + dist = edge->fpos - blue->ref.org; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = &blue->ref; + best_blue_is_neutral = is_neutral_blue; + } + + /* now compare it to the overshoot position and check whether */ + /* the edge is rounded, and whether the edge is over the */ + /* reference position of a top zone, or under the reference */ + /* position of a bottom zone (provided we don't have a */ + /* neutral blue zone) */ + if ( edge->flags & AF_EDGE_ROUND && + dist != 0 && + !is_neutral_blue ) + { + FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); + + + if ( is_top_blue ^ is_under_ref ) + { + dist = edge->fpos - blue->shoot.org; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = &blue->shoot; + best_blue_is_neutral = is_neutral_blue; + } + } + } + } + } + + if ( best_blue ) + { + edge->blue_edge = best_blue; + if ( best_blue_is_neutral ) + edge->flags |= AF_EDGE_NEUTRAL; + } + } + } + + + /* Initalize hinting engine. */ + + static FT_Error + af_latin_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */ + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + FT_Render_Mode mode; + FT_UInt32 scaler_flags, other_flags; + FT_Face face = metrics->root.scaler.face; + + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); + + /* + * correct x_scale and y_scale if needed, since they may have + * been modified by `af_latin_metrics_scale_dim' above + */ + hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; + hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; + hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; + hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; + + /* compute flags depending on render mode, etc. */ + mode = metrics->root.scaler.render_mode; + + scaler_flags = hints->scaler_flags; + other_flags = 0; + + /* + * We snap the width of vertical stems for the monochrome and + * horizontal LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_HORZ_SNAP; + + /* + * We snap the width of horizontal stems for the monochrome and + * vertical LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) + other_flags |= AF_LATIN_HINTS_VERT_SNAP; + + /* + * We adjust stems to full pixels unless in `light' or `lcd' mode. + */ + if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_STEM_ADJUST; + + if ( mode == FT_RENDER_MODE_MONO ) + other_flags |= AF_LATIN_HINTS_MONO; + + /* + * In `light' or `lcd' mode we disable horizontal hinting completely. + * We also do it if the face is italic. + * + * However, if warping is enabled (which only works in `light' hinting + * mode), advance widths get adjusted, too. + */ + if ( mode == FT_RENDER_MODE_LIGHT || mode == FT_RENDER_MODE_LCD || + ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) + scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; + + hints->scaler_flags = scaler_flags; + hints->other_flags = other_flags; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L Y P H G R I D - F I T T I N G *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* Snap a given width in scaled coordinates to one of the */ + /* current standard widths. */ + + static FT_Pos + af_latin_snap_width( AF_Width widths, + FT_UInt count, + FT_Pos width ) + { + FT_UInt n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + FT_Pos scaled; + + + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + scaled = FT_PIX_ROUND( reference ); + + if ( width >= reference ) + { + if ( width < scaled + 48 ) + width = reference; + } + else + { + if ( width > scaled - 48 ) + width = reference; + } + + return width; + } + + + /* Compute the snapped width of a given stem, ignoring very thin ones. */ + /* There is a lot of voodoo in this function; changing the hard-coded */ + /* parameters influence the whole hinting process. */ + + static FT_Pos + af_latin_compute_stem_width( AF_GlyphHints hints, + AF_Dimension dim, + FT_Pos width, + FT_Pos base_delta, + FT_UInt base_flags, + FT_UInt stem_flags ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; + AF_LatinAxis axis = &metrics->axis[dim]; + FT_Pos dist = width; + FT_Int sign = 0; + FT_Int vertical = ( dim == AF_DIMENSION_VERT ); + + + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || + axis->extra_light ) + return width; + + if ( dist < 0 ) + { + dist = -width; + sign = 1; + } + + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + { + /* smooth hinting process: very lightly quantize the stem width */ + + /* leave the widths of serifs alone */ + if ( ( stem_flags & AF_EDGE_SERIF ) && + vertical && + ( dist < 3 * 64 ) ) + goto Done_Width; + + else if ( base_flags & AF_EDGE_ROUND ) + { + if ( dist < 80 ) + dist = 64; + } + else if ( dist < 56 ) + dist = 56; + + if ( axis->width_count > 0 ) + { + FT_Pos delta; + + + /* compare to standard width */ + delta = dist - axis->widths[0].cur; + + if ( delta < 0 ) + delta = -delta; + + if ( delta < 40 ) + { + dist = axis->widths[0].cur; + if ( dist < 48 ) + dist = 48; + + goto Done_Width; + } + + if ( dist < 3 * 64 ) + { + delta = dist & 63; + dist &= -64; + + if ( delta < 10 ) + dist += delta; + + else if ( delta < 32 ) + dist += 10; + + else if ( delta < 54 ) + dist += 54; + + else + dist += delta; + } + else + { + /* A stem's end position depends on two values: the start */ + /* position and the stem length. The former gets usually */ + /* rounded to the grid, while the latter gets rounded also if it */ + /* exceeds a certain length (see below in this function). This */ + /* `double rounding' can lead to a great difference to the */ + /* original, unhinted position; this normally doesn't matter for */ + /* large PPEM values, but for small sizes it can easily make */ + /* outlines collide. For this reason, we adjust the stem length */ + /* by a small amount depending on the PPEM value in case the */ + /* former and latter rounding both point into the same */ + /* direction. */ + + FT_Pos bdelta = 0; + + + if ( ( ( width > 0 ) && ( base_delta > 0 ) ) || + ( ( width < 0 ) && ( base_delta < 0 ) ) ) + { + FT_UInt ppem = metrics->root.scaler.face->size->metrics.x_ppem; + + + if ( ppem < 10 ) + bdelta = base_delta; + else if ( ppem < 30 ) + bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20; + + if ( bdelta < 0 ) + bdelta = -bdelta; + } + + dist = ( dist - bdelta + 32 ) & ~63; + } + } + } + else + { + /* strong hinting process: snap the stem width to integer pixels */ + + FT_Pos org_dist = dist; + + + dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); + + if ( vertical ) + { + /* in the case of vertical hinting, always round */ + /* the stem heights to integer pixels */ + + if ( dist >= 64 ) + dist = ( dist + 16 ) & ~63; + else + dist = 64; + } + else + { + if ( AF_LATIN_HINTS_DO_MONO( hints ) ) + { + /* monochrome horizontal hinting: snap widths to integer pixels */ + /* with a different threshold */ + + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & ~63; + } + else + { + /* for horizontal anti-aliased hinting, we adopt a more subtle */ + /* approach: we strengthen small stems, round stems whose size */ + /* is between 1 and 2 pixels to an integer, otherwise nothing */ + + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + + else if ( dist < 128 ) + { + /* We only round to an integer width if the corresponding */ + /* distortion is less than 1/4 pixel. Otherwise this */ + /* makes everything worse since the diagonals, which are */ + /* not hinted, appear a lot bolder or thinner than the */ + /* vertical stems. */ + + FT_Pos delta; + + + dist = ( dist + 22 ) & ~63; + delta = dist - org_dist; + if ( delta < 0 ) + delta = -delta; + + if ( delta >= 16 ) + { + dist = org_dist; + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + } + } + else + /* round otherwise to prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & ~63; + } + } + } + + Done_Width: + if ( sign ) + dist = -dist; + + return dist; + } + + + /* Align one stem edge relative to the previous stem edge. */ + + static void + af_latin_align_linked_edge( AF_GlyphHints hints, + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) + { + FT_Pos dist, base_delta; + FT_Pos fitted_width; + + + dist = stem_edge->opos - base_edge->opos; + base_delta = base_edge->pos - base_edge->opos; + + fitted_width = af_latin_compute_stem_width( hints, dim, + dist, base_delta, + base_edge->flags, + stem_edge->flags ); + + + stem_edge->pos = base_edge->pos + fitted_width; + + FT_TRACE5(( " LINK: edge %td (opos=%.2f) linked to %.2f," + " dist was %.2f, now %.2f\n", + stem_edge - hints->axis[dim].edges, + (double)stem_edge->opos / 64, (double)stem_edge->pos / 64, + (double)dist / 64, (double)fitted_width / 64 )); + } + + + /* Shift the coordinates of the `serif' edge by the same amount */ + /* as the corresponding `base' edge has been moved already. */ + + static void + af_latin_align_serif_edge( AF_GlyphHints hints, + AF_Edge base, + AF_Edge serif ) + { + FT_UNUSED( hints ); + + serif->pos = base->pos + ( serif->opos - base->opos ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** E D G E H I N T I N G ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* The main grid-fitting routine. */ + + static void + af_latin_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + FT_PtrDist n_edges; + AF_Edge edge; + AF_Edge anchor = NULL; + FT_Int has_serifs = 0; + + AF_StyleClass style_class = hints->metrics->style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + FT_Bool top_to_bottom_hinting = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt num_actions = 0; +#endif + + + FT_TRACE5(( "latin %s edge hinting (style `%s')\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", + af_style_names[hints->metrics->style_class->style] )); + + if ( dim == AF_DIMENSION_VERT ) + top_to_bottom_hinting = script_class->top_to_bottom_hinting; + + /* we begin by aligning all stems relative to the blue zone */ + /* if needed -- that's only for horizontal edges */ + + if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; + AF_Edge edge1, edge2; /* these edges form the stem to check */ + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + edge1 = NULL; + edge2 = edge->link; + + /* + * If a stem contains both a neutral and a non-neutral blue zone, + * skip the neutral one. Otherwise, outlines with different + * directions might be incorrectly aligned at the same vertical + * position. + * + * If we have two neutral blue zones, skip one of them. + * + */ + if ( edge->blue_edge && edge2 && edge2->blue_edge ) + { + FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL; + FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL; + + + if ( neutral2 ) + { + edge2->blue_edge = NULL; + edge2->flags &= ~AF_EDGE_NEUTRAL; + } + else if ( neutral ) + { + edge->blue_edge = NULL; + edge->flags &= ~AF_EDGE_NEUTRAL; + } + } + + blue = edge->blue_edge; + if ( blue ) + edge1 = edge; + + /* flip edges if the other edge is aligned to a blue zone */ + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + + if ( !edge1 ) + continue; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !anchor ) + FT_TRACE5(( " BLUE_ANCHOR: edge %td (opos=%.2f) snapped to %.2f," + " was %.2f (anchor=edge %td)\n", + edge1 - edges, + (double)edge1->opos / 64, (double)blue->fit / 64, + (double)edge1->pos / 64, edge - edges )); + else + FT_TRACE5(( " BLUE: edge %td (opos=%.2f) snapped to %.2f," + " was %.2f\n", + edge1 - edges, + (double)edge1->opos / 64, (double)blue->fit / 64, + (double)edge1->pos / 64 )); + + num_actions++; +#endif + + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + + if ( edge2 && !edge2->blue_edge ) + { + af_latin_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + } + + if ( !anchor ) + anchor = edge; + } + } + + /* now we align all other stem edges, trying to maintain the */ + /* relative order of stems in the glyph */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge edge2; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + /* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + has_serifs++; + continue; + } + + /* now align the stem */ + + /* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( " ASSERTION FAILED for edge %td\n", edge2 - edges )); + + af_latin_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + continue; + } + + if ( !anchor ) + { + /* if we reach this if clause, no stem has been aligned yet */ + + FT_Pos org_len, org_center, cur_len; + FT_Pos cur_pos1, error1, error2, u_off, d_off; + + + org_len = edge2->opos - edge->opos; + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, + edge->flags, + edge2->flags ); + + /* some voodoo to specially round edges for small stem widths; */ + /* the idea is to align the center of a stem, then shifting */ + /* the stem edges to suitable positions */ + if ( cur_len <= 64 ) + { + /* width <= 1px */ + u_off = 32; + d_off = 32; + } + else + { + /* 1px < width < 1.5px */ + u_off = 38; + d_off = 26; + } + + if ( cur_len < 96 ) + { + org_center = edge->opos + ( org_len >> 1 ); + cur_pos1 = FT_PIX_ROUND( org_center ); + + error1 = org_center - ( cur_pos1 - u_off ); + if ( error1 < 0 ) + error1 = -error1; + + error2 = org_center - ( cur_pos1 + d_off ); + if ( error2 < 0 ) + error2 = -error2; + + if ( error1 < error2 ) + cur_pos1 -= u_off; + else + cur_pos1 += d_off; + + edge->pos = cur_pos1 - cur_len / 2; + edge2->pos = edge->pos + cur_len; + } + else + edge->pos = FT_PIX_ROUND( edge->opos ); + + anchor = edge; + edge->flags |= AF_EDGE_DONE; + + FT_TRACE5(( " ANCHOR: edge %td (opos=%.2f) and %td (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); + + af_latin_align_linked_edge( hints, dim, edge, edge2 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions += 2; +#endif + } + else + { + FT_Pos org_pos, org_len, org_center, cur_len; + FT_Pos cur_pos1, cur_pos2, delta1, delta2; + + + org_pos = anchor->pos + ( edge->opos - anchor->opos ); + org_len = edge2->opos - edge->opos; + org_center = org_pos + ( org_len >> 1 ); + + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, + edge->flags, + edge2->flags ); + + if ( edge2->flags & AF_EDGE_DONE ) + { + FT_TRACE5(( " ADJUST: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, (double)edge->pos / 64, + (double)( edge2->pos - cur_len ) / 64 )); + + edge->pos = edge2->pos - cur_len; + } + + else if ( cur_len < 96 ) + { + FT_Pos u_off, d_off; + + + cur_pos1 = FT_PIX_ROUND( org_center ); + + if ( cur_len <= 64 ) + { + u_off = 32; + d_off = 32; + } + else + { + u_off = 38; + d_off = 26; + } + + delta1 = org_center - ( cur_pos1 - u_off ); + if ( delta1 < 0 ) + delta1 = -delta1; + + delta2 = org_center - ( cur_pos1 + d_off ); + if ( delta2 < 0 ) + delta2 = -delta2; + + if ( delta1 < delta2 ) + cur_pos1 -= u_off; + else + cur_pos1 += d_off; + + edge->pos = cur_pos1 - cur_len / 2; + edge2->pos = cur_pos1 + cur_len / 2; + + FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); + } + + else + { + org_pos = anchor->pos + ( edge->opos - anchor->opos ); + org_len = edge2->opos - edge->opos; + org_center = org_pos + ( org_len >> 1 ); + + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, + edge->flags, + edge2->flags ); + + cur_pos1 = FT_PIX_ROUND( org_pos ); + delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center; + if ( delta1 < 0 ) + delta1 = -delta1; + + cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len; + delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center; + if ( delta2 < 0 ) + delta2 = -delta2; + + edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2; + edge2->pos = edge->pos + cur_len; + + FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + + edge->flags |= AF_EDGE_DONE; + edge2->flags |= AF_EDGE_DONE; + + if ( edge > edges && + ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos ) + : ( edge->pos < edge[-1].pos ) ) ) + { + /* don't move if stem would (almost) disappear otherwise; */ + /* the ad-hoc value 16 corresponds to 1/4px */ + if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, + (double)edge->pos / 64, + (double)edge[-1].pos / 64 )); + + num_actions++; +#endif + + edge->pos = edge[-1].pos; + } + } + } + } + + /* make sure that lowercase m's maintain their symmetry */ + + /* In general, lowercase m's have six vertical edges if they are sans */ + /* serif, or twelve if they are with serifs. This implementation is */ + /* based on that assumption, and seems to work very well with most */ + /* faces. However, if for a certain face this assumption is not */ + /* true, the m is just rendered like before. In addition, any stem */ + /* correction will only be applied to symmetrical glyphs (even if the */ + /* glyph is not an m), so the potential for unwanted distortion is */ + /* relatively low. */ + + /* We don't handle horizontal edges since we can't easily assure that */ + /* the third (lowest) stem aligns with the base line; it might end up */ + /* one pixel higher or lower. */ + + n_edges = edge_limit - edges; + if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) + { + AF_Edge edge1, edge2, edge3; + FT_Pos dist1, dist2, span, delta; + + + if ( n_edges == 6 ) + { + edge1 = edges; + edge2 = edges + 2; + edge3 = edges + 4; + } + else + { + edge1 = edges + 1; + edge2 = edges + 5; + edge3 = edges + 9; + } + + dist1 = edge2->opos - edge1->opos; + dist2 = edge3->opos - edge2->opos; + + span = dist1 - dist2; + if ( span < 0 ) + span = -span; + + if ( span < 8 ) + { + delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); + edge3->pos -= delta; + if ( edge3->link ) + edge3->link->pos -= delta; + + /* move the serifs along with the stem */ + if ( n_edges == 12 ) + { + ( edges + 8 )->pos -= delta; + ( edges + 11 )->pos -= delta; + } + + edge3->flags |= AF_EDGE_DONE; + if ( edge3->link ) + edge3->link->flags |= AF_EDGE_DONE; + } + } + + if ( has_serifs || !anchor ) + { + /* + * now hint the remaining edges (serifs and single) in order + * to complete our processing + */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Pos delta; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + delta = 1000; + + if ( edge->serif ) + { + delta = edge->serif->opos - edge->opos; + if ( delta < 0 ) + delta = -delta; + } + + if ( delta < 64 + 16 ) + { + af_latin_align_serif_edge( hints, edge->serif, edge ); + FT_TRACE5(( " SERIF: edge %td (opos=%.2f) serif to %td (opos=%.2f)" + " aligned to %.2f\n", + edge - edges, (double)edge->opos / 64, + edge->serif - edges, (double)edge->serif->opos / 64, + (double)edge->pos / 64 )); + } + else if ( !anchor ) + { + edge->pos = FT_PIX_ROUND( edge->opos ); + anchor = edge; + FT_TRACE5(( " SERIF_ANCHOR: edge %td (opos=%.2f)" + " snapped to %.2f\n", + edge - edges, + (double)edge->opos / 64, (double)edge->pos / 64 )); + } + else + { + AF_Edge before, after; + + + for ( before = edge - 1; before >= edges; before-- ) + if ( before->flags & AF_EDGE_DONE ) + break; + + for ( after = edge + 1; after < edge_limit; after++ ) + if ( after->flags & AF_EDGE_DONE ) + break; + + if ( before >= edges && before < edge && + after < edge_limit && after > edge ) + { + if ( after->opos == before->opos ) + edge->pos = before->pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->opos - before->opos, + after->pos - before->pos, + after->opos - before->opos ); + + FT_TRACE5(( " SERIF_LINK1: edge %td (opos=%.2f) snapped to %.2f" + " from %td (opos=%.2f)\n", + edge - edges, (double)edge->opos / 64, + (double)edge->pos / 64, + before - edges, (double)before->opos / 64 )); + } + else + { + edge->pos = anchor->pos + + ( ( edge->opos - anchor->opos + 16 ) & ~31 ); + FT_TRACE5(( " SERIF_LINK2: edge %td (opos=%.2f)" + " snapped to %.2f\n", + edge - edges, + (double)edge->opos / 64, (double)edge->pos / 64 )); + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + edge->flags |= AF_EDGE_DONE; + + if ( edge > edges && + ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos ) + : ( edge->pos < edge[-1].pos ) ) ) + { + /* don't move if stem would (almost) disappear otherwise; */ + /* the ad-hoc value 16 corresponds to 1/4px */ + if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, + (double)edge->pos / 64, + (double)edge[-1].pos / 64 )); + + num_actions++; +#endif + edge->pos = edge[-1].pos; + } + } + + if ( edge + 1 < edge_limit && + edge[1].flags & AF_EDGE_DONE && + ( top_to_bottom_hinting ? ( edge->pos < edge[1].pos ) + : ( edge->pos > edge[1].pos ) ) ) + { + /* don't move if stem would (almost) disappear otherwise; */ + /* the ad-hoc value 16 corresponds to 1/4px */ + if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, + (double)edge->pos / 64, + (double)edge[1].pos / 64 )); + + num_actions++; +#endif + + edge->pos = edge[1].pos; + } + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !num_actions ) + FT_TRACE5(( " (none)\n" )); + FT_TRACE5(( "\n" )); +#endif + } + + + /* Apply the complete hinting algorithm to a latin glyph. */ + + static FT_Error + af_latin_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */ + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + FT_Error error; + int dim; + + AF_LatinAxis axis; + + + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; + + /* analyze glyph outline */ + if ( AF_HINTS_DO_HORIZONTAL( hints ) ) + { + axis = &metrics->axis[AF_DIMENSION_HORZ]; + error = af_latin_hints_detect_features( hints, + axis->width_count, + axis->widths, + AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + } + + if ( AF_HINTS_DO_VERTICAL( hints ) ) + { + axis = &metrics->axis[AF_DIMENSION_VERT]; + error = af_latin_hints_detect_features( hints, + axis->width_count, + axis->widths, + AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + + /* apply blue zones to base characters only */ + if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) ) + af_latin_hints_compute_blue_edges( hints, metrics ); + } + + /* grid-fit the outline */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || + ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + { + af_latin_hint_edges( hints, (AF_Dimension)dim ); + af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + } + + af_glyph_hints_save( hints, outline ); + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N S C R I P T C L A S S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_latin_writing_system_class, + + AF_WRITING_SYSTEM_LATIN, + + sizeof ( AF_LatinMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_latin_hints_apply /* style_hints_apply */ + ) + + +/* END */ diff --git a/vendor/freetype/src/autofit/aflatin.h b/vendor/freetype/src/autofit/aflatin.h new file mode 100644 index 0000000..31aa91d --- /dev/null +++ b/vendor/freetype/src/autofit/aflatin.h @@ -0,0 +1,194 @@ +/**************************************************************************** + * + * aflatin.h + * + * Auto-fitter hinting routines for latin writing system + * (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFLATIN_H_ +#define AFLATIN_H_ + +#include "afhints.h" + + +FT_BEGIN_HEADER + + /* the `latin' writing system */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_latin_writing_system_class ) + + + /* constants are given with units_per_em == 2048 in mind */ +#define AF_LATIN_CONSTANT( metrics, c ) \ + ( ( (c) * (FT_Long)( (AF_LatinMetrics)(metrics) )->units_per_em ) / 2048 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* + * The following declarations could be embedded in the file `aflatin.c'; + * they have been made semi-public to allow alternate writing system + * hinters to re-use some of them. + */ + + +#define AF_LATIN_IS_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_TOP ) +#define AF_LATIN_IS_SUB_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_SUB_TOP ) +#define AF_LATIN_IS_NEUTRAL_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_NEUTRAL ) +#define AF_LATIN_IS_X_HEIGHT_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT ) +#define AF_LATIN_IS_LONG_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG ) + +#define AF_LATIN_MAX_WIDTHS 16 + + +#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ +#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ +#define AF_LATIN_BLUE_SUB_TOP ( 1U << 2 ) /* we have a subscript top */ + /* blue zone */ +#define AF_LATIN_BLUE_NEUTRAL ( 1U << 3 ) /* we have neutral blue zone */ +#define AF_LATIN_BLUE_ADJUSTMENT ( 1U << 4 ) /* used for scale adjustment */ + /* optimization */ + + + typedef struct AF_LatinBlueRec_ + { + AF_WidthRec ref; + AF_WidthRec shoot; + FT_Pos ascender; + FT_Pos descender; + FT_UInt flags; + + } AF_LatinBlueRec, *AF_LatinBlue; + + + typedef struct AF_LatinAxisRec_ + { + FT_Fixed scale; + FT_Pos delta; + + FT_UInt width_count; /* number of used widths */ + AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]; /* widths array */ + FT_Pos edge_distance_threshold; /* used for creating edges */ + FT_Pos standard_width; /* the default stem thickness */ + FT_Bool extra_light; /* is standard width very light? */ + + /* ignored for horizontal metrics */ + FT_UInt blue_count; + AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]; + + FT_Fixed org_scale; + FT_Pos org_delta; + + } AF_LatinAxisRec, *AF_LatinAxis; + + + typedef struct AF_LatinMetricsRec_ + { + AF_StyleMetricsRec root; + FT_UInt units_per_em; + AF_LatinAxisRec axis[AF_DIMENSION_MAX]; + + } AF_LatinMetricsRec, *AF_LatinMetrics; + + + FT_LOCAL( FT_Error ) + af_latin_metrics_init( AF_StyleMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_latin_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ); + + FT_LOCAL( void ) + af_latin_metrics_init_widths( AF_LatinMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_latin_metrics_check_digits( AF_LatinMetrics metrics, + FT_Face face ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L Y P H A N A L Y S I S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define AF_LATIN_HINTS_HORZ_SNAP ( 1U << 0 ) /* stem width snapping */ +#define AF_LATIN_HINTS_VERT_SNAP ( 1U << 1 ) /* stem height snapping */ +#define AF_LATIN_HINTS_STEM_ADJUST ( 1U << 2 ) /* stem width/height */ + /* adjustment */ +#define AF_LATIN_HINTS_MONO ( 1U << 3 ) /* monochrome rendering */ + + +#define AF_LATIN_HINTS_DO_HORZ_SNAP( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_HORZ_SNAP ) + +#define AF_LATIN_HINTS_DO_VERT_SNAP( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_VERT_SNAP ) + +#define AF_LATIN_HINTS_DO_STEM_ADJUST( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_STEM_ADJUST ) + +#define AF_LATIN_HINTS_DO_MONO( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_MONO ) + + + /* + * The next functions shouldn't normally be exported. However, other + * writing systems might like to use these functions as-is. + */ + FT_LOCAL( FT_Error ) + af_latin_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_latin_hints_link_segments( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ); + + FT_LOCAL( FT_Error ) + af_latin_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( FT_Error ) + af_latin_hints_detect_features( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ); + +/* */ + +FT_END_HEADER + +#endif /* AFLATIN_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afloader.c b/vendor/freetype/src/autofit/afloader.c new file mode 100644 index 0000000..7c47d56 --- /dev/null +++ b/vendor/freetype/src/autofit/afloader.c @@ -0,0 +1,706 @@ +/**************************************************************************** + * + * afloader.c + * + * Auto-fitter glyph loading routines (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afglobal.h" +#include "afloader.h" +#include "afhints.h" +#include "aferrors.h" +#include "afmodule.h" + +#include + + + /* Initialize glyph loader. */ + + FT_LOCAL_DEF( void ) + af_loader_init( AF_Loader loader, + AF_GlyphHints hints ) + { + FT_ZERO( loader ); + + loader->hints = hints; + } + + + /* Reset glyph loader and compute globals if necessary. */ + + FT_LOCAL_DEF( FT_Error ) + af_loader_reset( AF_Loader loader, + AF_Module module, + FT_Face face ) + { + FT_Error error = FT_Err_Ok; + + + loader->face = face; + loader->globals = (AF_FaceGlobals)face->autohint.data; + + if ( !loader->globals ) + { + error = af_face_globals_new( face, &loader->globals, module ); + if ( !error ) + { + face->autohint.data = (FT_Pointer)loader->globals; + face->autohint.finalizer = af_face_globals_free; + } + } + + return error; + } + + + /* Finalize glyph loader. */ + + FT_LOCAL_DEF( void ) + af_loader_done( AF_Loader loader ) + { + loader->face = NULL; + loader->globals = NULL; + loader->hints = NULL; + } + + +#define af_intToFixed( i ) \ + ( (FT_Fixed)( (FT_UInt32)(i) << 16 ) ) +#define af_fixedToInt( x ) \ + ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) ) +#define af_floatToFixed( f ) \ + ( (FT_Fixed)( (f) * 65536.0 + 0.5 ) ) + + + static FT_Error + af_loader_embolden_glyph_in_slot( AF_Loader loader, + FT_Face face, + AF_StyleMetrics style_metrics ) + { + FT_Error error = FT_Err_Ok; + + FT_GlyphSlot slot = face->glyph; + AF_FaceGlobals globals = loader->globals; + AF_WritingSystemClass writing_system_class; + + FT_Size_Metrics* size_metrics = &face->size->internal->autohint_metrics; + + FT_Pos stdVW = 0; + FT_Pos stdHW = 0; + + FT_Bool size_changed = size_metrics->x_ppem != + globals->stem_darkening_for_ppem; + + FT_Fixed em_size = af_intToFixed( face->units_per_EM ); + + FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; + + + /* Skip stem darkening for broken fonts. */ + if ( !face->units_per_EM ) + { + error = FT_ERR( Corrupted_Font_Header ); + goto Exit; + } + + /* + * We depend on the writing system (script analyzers) to supply + * standard widths for the script of the glyph we are looking at. If + * it can't deliver, stem darkening is disabled. + */ + writing_system_class = + af_writing_system_classes[style_metrics->style_class->writing_system]; + + if ( writing_system_class->style_metrics_getstdw ) + writing_system_class->style_metrics_getstdw( style_metrics, + &stdHW, + &stdVW ); + else + { + error = FT_ERR( Unimplemented_Feature ); + goto Exit; + } + + if ( size_changed || + ( stdVW > 0 && stdVW != globals->standard_vertical_width ) ) + { + FT_Fixed darken_by_font_units_x, darken_x; + + + darken_by_font_units_x = + af_loader_compute_darkening( loader, + face, + stdVW ) ; + darken_x = FT_MulFix( darken_by_font_units_x, + size_metrics->x_scale ); + + globals->standard_vertical_width = stdVW; + globals->stem_darkening_for_ppem = size_metrics->x_ppem; + globals->darken_x = af_fixedToInt( darken_x ); + } + + if ( size_changed || + ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) ) + { + FT_Fixed darken_by_font_units_y, darken_y; + + + darken_by_font_units_y = + af_loader_compute_darkening( loader, + face, + stdHW ) ; + darken_y = FT_MulFix( darken_by_font_units_y, + size_metrics->y_scale ); + + globals->standard_horizontal_width = stdHW; + globals->stem_darkening_for_ppem = size_metrics->x_ppem; + globals->darken_y = af_fixedToInt( darken_y ); + + /* + * Scale outlines down on the Y-axis to keep them inside their blue + * zones. The stronger the emboldening, the stronger the downscaling + * (plus heuristical padding to prevent outlines still falling out + * their zones due to rounding). + * + * Reason: `FT_Outline_Embolden' works by shifting the rightmost + * points of stems farther to the right, and topmost points farther + * up. This positions points on the Y-axis outside their + * pre-computed blue zones and leads to distortion when applying the + * hints in the code further below. Code outside this emboldening + * block doesn't know we are presenting it with modified outlines the + * analyzer didn't see! + * + * An unfortunate side effect of downscaling is that the emboldening + * effect is slightly decreased. The loss becomes more pronounced + * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. + */ + globals->scale_down_factor = + FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), + em_size ); + } + + FT_Outline_EmboldenXY( &slot->outline, + globals->darken_x, + globals->darken_y ); + + scale_down_matrix.yy = globals->scale_down_factor; + FT_Outline_Transform( &slot->outline, &scale_down_matrix ); + + Exit: + return error; + } + + + /* Load the glyph at index into the current slot of a face and hint it. */ + + FT_LOCAL_DEF( FT_Error ) + af_loader_load_glyph( AF_Loader loader, + AF_Module module, + FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + + FT_Size size = face->size; + FT_Size_Internal size_internal = size->internal; + FT_GlyphSlot slot = face->glyph; + FT_Slot_Internal slot_internal = slot->internal; + FT_GlyphLoader gloader = slot_internal->loader; + + AF_GlyphHints hints = loader->hints; + AF_ScalerRec scaler; + AF_StyleMetrics style_metrics; + FT_UInt style_options = AF_STYLE_NONE_DFLT; + AF_StyleClass style_class; + AF_WritingSystemClass writing_system_class; + + + FT_ZERO( &scaler ); + + if ( !size_internal->autohint_metrics.x_scale || + size_internal->autohint_mode != FT_LOAD_TARGET_MODE( load_flags ) ) + { + /* switching between hinting modes usually means different scaling */ + /* values; this later on enforces recomputation of everything */ + /* related to the current size */ + + size_internal->autohint_mode = FT_LOAD_TARGET_MODE( load_flags ); + size_internal->autohint_metrics = size->metrics; + +#ifdef AF_CONFIG_OPTION_TT_SIZE_METRICS + { + FT_Size_Metrics* size_metrics = &size_internal->autohint_metrics; + + + /* set metrics to integer values and adjust scaling accordingly; */ + /* this is the same setup as with TrueType fonts, cf. function */ + /* `tt_size_reset' in file `ttobjs.c' */ + size_metrics->ascender = FT_PIX_ROUND( + FT_MulFix( face->ascender, + size_metrics->y_scale ) ); + size_metrics->descender = FT_PIX_ROUND( + FT_MulFix( face->descender, + size_metrics->y_scale ) ); + size_metrics->height = FT_PIX_ROUND( + FT_MulFix( face->height, + size_metrics->y_scale ) ); + + size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6, + face->units_per_EM ); + size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6, + face->units_per_EM ); + size_metrics->max_advance = FT_PIX_ROUND( + FT_MulFix( face->max_advance_width, + size_metrics->x_scale ) ); + } +#endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */ + } + + /* + * TODO: This code currently doesn't support fractional advance widths, + * i.e., placing hinted glyphs at anything other than integer + * x-positions. This is only relevant for the warper code, which + * scales and shifts glyphs to optimize blackness of stems (hinting on + * the x-axis by nature places things on pixel integers, hinting on the + * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta + * values of the scaler would need to be adjusted. + */ + scaler.face = face; + scaler.x_scale = size_internal->autohint_metrics.x_scale; + scaler.x_delta = 0; + scaler.y_scale = size_internal->autohint_metrics.y_scale; + scaler.y_delta = 0; + + scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); + scaler.flags = 0; + + /* note that the fallback style can't be changed anymore */ + /* after the first call of `af_loader_load_glyph' */ + error = af_loader_reset( loader, module, face ); + if ( error ) + goto Exit; + + /* + * Glyphs (really code points) are assigned to scripts. Script + * analysis is done lazily: For each glyph that passes through here, + * the corresponding script analyzer is called, but returns immediately + * if it has been run already. + */ + error = af_face_globals_get_metrics( loader->globals, glyph_index, + style_options, &style_metrics ); + if ( error ) + goto Exit; + + style_class = style_metrics->style_class; + writing_system_class = + af_writing_system_classes[style_class->writing_system]; + + loader->metrics = style_metrics; + + if ( writing_system_class->style_metrics_scale ) + writing_system_class->style_metrics_scale( style_metrics, &scaler ); + else + style_metrics->scaler = scaler; + + if ( writing_system_class->style_hints_init ) + { + error = writing_system_class->style_hints_init( hints, + style_metrics ); + if ( error ) + goto Exit; + } + + /* + * Do the main work of `af_loader_load_glyph'. Note that we never have + * to deal with composite glyphs as those get loaded into + * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. + * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies + * FT_LOAD_NO_SCALE and as such the auto-hinter is never called. + */ + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM | + FT_LOAD_LINEAR_DESIGN; + load_flags &= ~FT_LOAD_RENDER; + + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + goto Exit; + + /* + * Apply stem darkening (emboldening) here before hints are applied to + * the outline. Glyphs are scaled down proportionally to the + * emboldening so that curve points don't fall outside their + * precomputed blue zones. + * + * Any emboldening done by the font driver (e.g., the CFF driver) + * doesn't reach here because the autohinter loads the unprocessed + * glyphs in font units for analysis (functions `af_*_metrics_init_*') + * and then above to prepare it for the rasterizers by itself, + * independently of the font driver. So emboldening must be done here, + * within the autohinter. + * + * All glyphs to be autohinted pass through here one by one. The + * standard widths can therefore change from one glyph to the next, + * depending on what script a glyph is assigned to (each script has its + * own set of standard widths and other metrics). The darkening amount + * must therefore be recomputed for each size and + * `standard_{vertical,horizontal}_width' change. + * + * Ignore errors and carry on without emboldening. + * + */ + + /* stem darkening only works well in `light' mode */ + if ( scaler.render_mode == FT_RENDER_MODE_LIGHT && + ( !face->internal->no_stem_darkening || + ( face->internal->no_stem_darkening < 0 && + !module->no_stem_darkening ) ) ) + af_loader_embolden_glyph_in_slot( loader, face, style_metrics ); + + loader->transformed = slot_internal->glyph_transformed; + if ( loader->transformed ) + { + FT_Matrix inverse; + + + loader->trans_matrix = slot_internal->glyph_matrix; + loader->trans_delta = slot_internal->glyph_delta; + + inverse = loader->trans_matrix; + if ( !FT_Matrix_Invert( &inverse ) ) + FT_Vector_Transform( &loader->trans_delta, &inverse ); + } + + switch ( slot->format ) + { + case FT_GLYPH_FORMAT_OUTLINE: + /* translate the loaded glyph when an internal transform is needed */ + if ( loader->transformed ) + FT_Outline_Translate( &slot->outline, + loader->trans_delta.x, + loader->trans_delta.y ); + + /* compute original horizontal phantom points */ + /* (and ignore vertical ones) */ + loader->pp1.x = hints->x_delta; + loader->pp1.y = hints->y_delta; + loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, + hints->x_scale ) + hints->x_delta; + loader->pp2.y = hints->y_delta; + + /* be sure to check for spacing glyphs */ + if ( slot->outline.n_points == 0 ) + goto Hint_Metrics; + + /* now load the slot image into the auto-outline */ + /* and run the automatic hinting process */ + if ( writing_system_class->style_hints_apply ) + { + error = writing_system_class->style_hints_apply( + glyph_index, + hints, + &gloader->base.outline, + style_metrics ); + if ( error ) + goto Exit; + } + + /* we now need to adjust the metrics according to the change in */ + /* width/positioning that occurred during the hinting process */ + if ( scaler.render_mode != FT_RENDER_MODE_LIGHT ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; + + + if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) + { + AF_Edge edge1 = axis->edges; /* leftmost edge */ + AF_Edge edge2 = edge1 + + axis->num_edges - 1; /* rightmost edge */ + + FT_Pos old_rsb = loader->pp2.x - edge2->opos; + /* loader->pp1.x is always zero at this point of time */ + FT_Pos old_lsb = edge1->opos; /* - loader->pp1.x */ + FT_Pos new_lsb = edge1->pos; + + /* remember unhinted values to later account */ + /* for rounding errors */ + FT_Pos pp1x_uh = new_lsb - old_lsb; + FT_Pos pp2x_uh = edge2->pos + old_rsb; + + + /* prefer too much space over too little space */ + /* for very small sizes */ + + if ( old_lsb < 24 ) + pp1x_uh -= 8; + + if ( old_rsb < 24 ) + pp2x_uh += 8; + + loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); + loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); + + if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) + loader->pp1.x -= 64; + + if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) + loader->pp2.x += 64; + + slot->lsb_delta = loader->pp1.x - pp1x_uh; + slot->rsb_delta = loader->pp2.x - pp2x_uh; + } + else + { + FT_Pos pp1x = loader->pp1.x; + FT_Pos pp2x = loader->pp2.x; + + + loader->pp1.x = FT_PIX_ROUND( pp1x ); + loader->pp2.x = FT_PIX_ROUND( pp2x ); + + slot->lsb_delta = loader->pp1.x - pp1x; + slot->rsb_delta = loader->pp2.x - pp2x; + } + } + /* `light' mode uses integer advance widths */ + /* but sets `lsb_delta' and `rsb_delta' */ + else + { + FT_Pos pp1x = loader->pp1.x; + FT_Pos pp2x = loader->pp2.x; + + + loader->pp1.x = FT_PIX_ROUND( pp1x ); + loader->pp2.x = FT_PIX_ROUND( pp2x ); + + slot->lsb_delta = loader->pp1.x - pp1x; + slot->rsb_delta = loader->pp2.x - pp2x; + } + + break; + + default: + /* we don't support other formats (yet?) */ + error = FT_THROW( Unimplemented_Feature ); + } + + Hint_Metrics: + { + FT_BBox bbox; + FT_Vector vvector; + + + vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; + vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; + vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale ); + vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale ); + + /* transform the hinted outline if needed */ + if ( loader->transformed ) + { + FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); + FT_Vector_Transform( &vvector, &loader->trans_matrix ); + } + + /* we must translate our final outline by -pp1.x and compute */ + /* the new metrics */ + if ( loader->pp1.x ) + FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); + + FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); + + bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); + bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); + bbox.xMax = FT_PIX_CEIL( bbox.xMax ); + bbox.yMax = FT_PIX_CEIL( bbox.yMax ); + + slot->metrics.width = bbox.xMax - bbox.xMin; + slot->metrics.height = bbox.yMax - bbox.yMin; + slot->metrics.horiBearingX = bbox.xMin; + slot->metrics.horiBearingY = bbox.yMax; + + slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); + slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); + + /* for mono-width fonts (like Andale, Courier, etc.) we need */ + /* to keep the original rounded advance width; ditto for */ + /* digits if all have the same advance width */ + if ( scaler.render_mode != FT_RENDER_MODE_LIGHT && + ( FT_IS_FIXED_WIDTH( slot->face ) || + ( af_face_globals_is_digit( loader->globals, glyph_index ) && + style_metrics->digits_have_same_width ) ) ) + { + slot->metrics.horiAdvance = + FT_MulFix( slot->metrics.horiAdvance, + style_metrics->scaler.x_scale ); + + /* Set delta values to 0. Otherwise code that uses them is */ + /* going to ruin the fixed advance width. */ + slot->lsb_delta = 0; + slot->rsb_delta = 0; + } + else + { + /* non-spacing glyphs must stay as-is */ + if ( slot->metrics.horiAdvance ) + slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; + } + + slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, + style_metrics->scaler.y_scale ); + + slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); + slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); + + slot->format = FT_GLYPH_FORMAT_OUTLINE; + } + + Exit: + return error; + } + + + /* + * Compute amount of font units the face should be emboldened by, in + * analogy to the CFF driver's `cf2_computeDarkening' function. See there + * for details of the algorithm. + * + * XXX: Currently a crude adaption of the original algorithm. Do better? + */ + FT_LOCAL_DEF( FT_Fixed ) + af_loader_compute_darkening( AF_Loader loader, + FT_Face face, + FT_Pos standard_width ) + { + AF_Module module = loader->globals->module; + + FT_UShort units_per_EM; + FT_Fixed ppem, em_ratio; + FT_Fixed stem_width, stem_width_per_1000, scaled_stem, darken_amount; + FT_Int log_base_2; + FT_Int x1, y1, x2, y2, x3, y3, x4, y4; + + + ppem = FT_MAX( af_intToFixed( 4 ), + af_intToFixed( face->size->metrics.x_ppem ) ); + units_per_EM = face->units_per_EM; + + em_ratio = FT_DivFix( af_intToFixed( 1000 ), + af_intToFixed ( units_per_EM ) ); + if ( em_ratio < af_floatToFixed( .01 ) ) + { + /* If something goes wrong, don't embolden. */ + return 0; + } + + x1 = module->darken_params[0]; + y1 = module->darken_params[1]; + x2 = module->darken_params[2]; + y2 = module->darken_params[3]; + x3 = module->darken_params[4]; + y3 = module->darken_params[5]; + x4 = module->darken_params[6]; + y4 = module->darken_params[7]; + + if ( standard_width <= 0 ) + { + stem_width = af_intToFixed( 75 ); /* taken from cf2font.c */ + stem_width_per_1000 = stem_width; + } + else + { + stem_width = af_intToFixed( standard_width ); + stem_width_per_1000 = FT_MulFix( stem_width, em_ratio ); + } + + log_base_2 = FT_MSB( (FT_UInt32)stem_width_per_1000 ) + + FT_MSB( (FT_UInt32)ppem ); + + if ( log_base_2 >= 46 ) + { + /* possible overflow */ + scaled_stem = af_intToFixed( x4 ); + } + else + scaled_stem = FT_MulFix( stem_width_per_1000, ppem ); + + /* now apply the darkening parameters */ + if ( scaled_stem < af_intToFixed( x1 ) ) + darken_amount = FT_DivFix( af_intToFixed( y1 ), ppem ); + + else if ( scaled_stem < af_intToFixed( x2 ) ) + { + FT_Int xdelta = x2 - x1; + FT_Int ydelta = y2 - y1; + FT_Int x = stem_width_per_1000 - + FT_DivFix( af_intToFixed( x1 ), ppem ); + + + if ( !xdelta ) + goto Try_x3; + + darken_amount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( af_intToFixed( y1 ), ppem ); + } + + else if ( scaled_stem < af_intToFixed( x3 ) ) + { + Try_x3: + { + FT_Int xdelta = x3 - x2; + FT_Int ydelta = y3 - y2; + FT_Int x = stem_width_per_1000 - + FT_DivFix( af_intToFixed( x2 ), ppem ); + + + if ( !xdelta ) + goto Try_x4; + + darken_amount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( af_intToFixed( y2 ), ppem ); + } + } + + else if ( scaled_stem < af_intToFixed( x4 ) ) + { + Try_x4: + { + FT_Int xdelta = x4 - x3; + FT_Int ydelta = y4 - y3; + FT_Int x = stem_width_per_1000 - + FT_DivFix( af_intToFixed( x3 ), ppem ); + + + if ( !xdelta ) + goto Use_y4; + + darken_amount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( af_intToFixed( y3 ), ppem ); + } + } + + else + { + Use_y4: + darken_amount = FT_DivFix( af_intToFixed( y4 ), ppem ); + } + + /* Convert darken_amount from per 1000 em to true character space. */ + return FT_DivFix( darken_amount, em_ratio ); + } + + +/* END */ diff --git a/vendor/freetype/src/autofit/afloader.h b/vendor/freetype/src/autofit/afloader.h new file mode 100644 index 0000000..e4e197e --- /dev/null +++ b/vendor/freetype/src/autofit/afloader.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * afloader.h + * + * Auto-fitter glyph loading routines (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFLOADER_H_ +#define AFLOADER_H_ + +#include "afhints.h" +#include "afmodule.h" +#include "afglobal.h" + + +FT_BEGIN_HEADER + + /* + * The autofitter module's (global) data structure to communicate with + * actual fonts. If necessary, `local' data like the current face, the + * current face's auto-hint data, or the current glyph's parameters + * relevant to auto-hinting are `swapped in'. Cf. functions like + * `af_loader_reset' and `af_loader_load_g'. + */ + + typedef struct AF_LoaderRec_ + { + /* current face data */ + FT_Face face; + AF_FaceGlobals globals; + + /* current glyph data */ + AF_GlyphHints hints; + AF_StyleMetrics metrics; + FT_Bool transformed; + FT_Matrix trans_matrix; + FT_Vector trans_delta; + FT_Vector pp1; + FT_Vector pp2; + /* we don't handle vertical phantom points */ + + } AF_LoaderRec, *AF_Loader; + + + FT_LOCAL( void ) + af_loader_init( AF_Loader loader, + AF_GlyphHints hints ); + + + FT_LOCAL( FT_Error ) + af_loader_reset( AF_Loader loader, + AF_Module module, + FT_Face face ); + + + FT_LOCAL( void ) + af_loader_done( AF_Loader loader ); + + + FT_LOCAL( FT_Error ) + af_loader_load_glyph( AF_Loader loader, + AF_Module module, + FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags ); + + FT_LOCAL( FT_Fixed ) + af_loader_compute_darkening( AF_Loader loader, + FT_Face face, + FT_Pos standard_width ); + +/* */ + + +FT_END_HEADER + +#endif /* AFLOADER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afmodule.c b/vendor/freetype/src/autofit/afmodule.c new file mode 100644 index 0000000..20a6b96 --- /dev/null +++ b/vendor/freetype/src/autofit/afmodule.c @@ -0,0 +1,527 @@ +/**************************************************************************** + * + * afmodule.c + * + * Auto-fitter module implementation (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afglobal.h" +#include "afmodule.h" +#include "afloader.h" +#include "aferrors.h" + +#ifdef FT_DEBUG_AUTOFIT + +#ifndef FT_MAKE_OPTION_SINGLE_OBJECT + +#ifdef __cplusplus + extern "C" { +#endif + extern void + af_glyph_hints_dump_segments( AF_GlyphHints hints, + FT_Bool to_stdout ); + extern void + af_glyph_hints_dump_points( AF_GlyphHints hints, + FT_Bool to_stdout ); + extern void + af_glyph_hints_dump_edges( AF_GlyphHints hints, + FT_Bool to_stdout ); +#ifdef __cplusplus + } +#endif + +#endif + + int af_debug_disable_horz_hints_; + int af_debug_disable_vert_hints_; + int af_debug_disable_blue_hints_; + + /* we use a global object instead of a local one for debugging */ + static AF_GlyphHintsRec af_debug_hints_rec_[1]; + + void* af_debug_hints_ = af_debug_hints_rec_; +#endif + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afmodule + + + static FT_Error + af_property_get_face_globals( FT_Face face, + AF_FaceGlobals* aglobals, + AF_Module module ) + { + FT_Error error = FT_Err_Ok; + AF_FaceGlobals globals; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + globals = (AF_FaceGlobals)face->autohint.data; + if ( !globals ) + { + /* trigger computation of the global style data */ + /* in case it hasn't been done yet */ + error = af_face_globals_new( face, &globals, module ); + if ( !error ) + { + face->autohint.data = (FT_Pointer)globals; + face->autohint.finalizer = af_face_globals_free; + } + } + + if ( !error ) + *aglobals = globals; + + return error; + } + + + static FT_Error + af_property_set( FT_Module ft_module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + AF_Module module = (AF_Module)ft_module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "fallback-script" ) ) + { + AF_Script* fallback_script; + FT_UInt ss; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + return FT_THROW( Invalid_Argument ); +#endif + + fallback_script = (AF_Script*)value; + + /* We translate the fallback script to a fallback style that uses */ + /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its */ + /* coverage value. */ + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = af_style_classes[ss]; + + + if ( style_class->script == *fallback_script && + style_class->coverage == AF_COVERAGE_DEFAULT ) + { + module->fallback_style = ss; + break; + } + } + + if ( !af_style_classes[ss] ) + { + FT_TRACE2(( "af_property_set: Invalid value %d for property `%s'\n", + *fallback_script, property_name )); + return FT_THROW( Invalid_Argument ); + } + + return error; + } + else if ( !ft_strcmp( property_name, "default-script" ) ) + { + AF_Script* default_script; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + return FT_THROW( Invalid_Argument ); +#endif + + default_script = (AF_Script*)value; + + module->default_script = *default_script; + + return error; + } + else if ( !ft_strcmp( property_name, "increase-x-height" ) ) + { + FT_Prop_IncreaseXHeight* prop; + AF_FaceGlobals globals; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + return FT_THROW( Invalid_Argument ); +#endif + + prop = (FT_Prop_IncreaseXHeight*)value; + + error = af_property_get_face_globals( prop->face, &globals, module ); + if ( !error ) + globals->increase_x_height = prop->limit; + + return error; + } + else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params; + FT_Int x1, y1, x2, y2, x3, y3, x4, y4; + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_Int dp[8]; + + + if ( value_is_string ) + { + const char* s = (const char*)value; + char* ep; + int i; + + + /* eight comma-separated numbers */ + for ( i = 0; i < 7; i++ ) + { + dp[i] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( *ep != ',' || s == ep ) + return FT_THROW( Invalid_Argument ); + + s = ep + 1; + } + + dp[7] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( !( *ep == '\0' || *ep == ' ' ) || s == ep ) + return FT_THROW( Invalid_Argument ); + + darken_params = dp; + } + else +#endif + darken_params = (FT_Int*)value; + + x1 = darken_params[0]; + y1 = darken_params[1]; + x2 = darken_params[2]; + y2 = darken_params[3]; + x3 = darken_params[4]; + y3 = darken_params[5]; + x4 = darken_params[6]; + y4 = darken_params[7]; + + if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || + y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 || + x1 > x2 || x2 > x3 || x3 > x4 || + y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 ) + return FT_THROW( Invalid_Argument ); + + module->darken_params[0] = x1; + module->darken_params[1] = y1; + module->darken_params[2] = x2; + module->darken_params[3] = y2; + module->darken_params[4] = x3; + module->darken_params[5] = y3; + module->darken_params[6] = x4; + module->darken_params[7] = y4; + + return error; + } + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + long nsd = ft_strtol( s, NULL, 10 ); + + + if ( !nsd ) + module->no_stem_darkening = FALSE; + else + module->no_stem_darkening = TRUE; + } + else +#endif + { + FT_Bool* no_stem_darkening = (FT_Bool*)value; + + + module->no_stem_darkening = *no_stem_darkening; + } + + return error; + } + + FT_TRACE2(( "af_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + static FT_Error + af_property_get( FT_Module ft_module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + AF_Module module = (AF_Module)ft_module; + + + if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) + { + FT_Prop_GlyphToScriptMap* prop = (FT_Prop_GlyphToScriptMap*)value; + AF_FaceGlobals globals; + + + error = af_property_get_face_globals( prop->face, &globals, module ); + if ( !error ) + prop->map = globals->glyph_styles; + + return error; + } + else if ( !ft_strcmp( property_name, "fallback-script" ) ) + { + AF_Script* val = (AF_Script*)value; + + AF_StyleClass style_class = af_style_classes[module->fallback_style]; + + + *val = style_class->script; + + return error; + } + else if ( !ft_strcmp( property_name, "default-script" ) ) + { + AF_Script* val = (AF_Script*)value; + + + *val = module->default_script; + + return error; + } + else if ( !ft_strcmp( property_name, "increase-x-height" ) ) + { + FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value; + AF_FaceGlobals globals; + + + error = af_property_get_face_globals( prop->face, &globals, module ); + if ( !error ) + prop->limit = globals->increase_x_height; + + return error; + } + else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params = module->darken_params; + FT_Int* val = (FT_Int*)value; + + + val[0] = darken_params[0]; + val[1] = darken_params[1]; + val[2] = darken_params[2]; + val[3] = darken_params[3]; + val[4] = darken_params[4]; + val[5] = darken_params[5]; + val[6] = darken_params[6]; + val[7] = darken_params[7]; + + return error; + } + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { + FT_Bool no_stem_darkening = module->no_stem_darkening; + FT_Bool* val = (FT_Bool*)value; + + + *val = no_stem_darkening; + + return error; + } + + FT_TRACE2(( "af_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + af_service_properties, + + af_property_set, /* FT_Properties_SetFunc set_property */ + af_property_get /* FT_Properties_GetFunc get_property */ + ) + + + FT_DEFINE_SERVICEDESCREC1( + af_services, + + FT_SERVICE_ID_PROPERTIES, &af_service_properties ) + + + FT_CALLBACK_DEF( FT_Module_Interface ) + af_get_interface( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( af_services, module_interface ); + } + + + FT_CALLBACK_DEF( FT_Error ) + af_autofitter_init( FT_Module ft_module ) /* AF_Module */ + { + AF_Module module = (AF_Module)ft_module; + + + module->fallback_style = AF_STYLE_FALLBACK; + module->default_script = AF_SCRIPT_DEFAULT; + module->no_stem_darkening = TRUE; + + module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + module->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + module->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + module->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + module->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + af_autofitter_done( FT_Module ft_module ) /* AF_Module */ + { + FT_UNUSED( ft_module ); + +#ifdef FT_DEBUG_AUTOFIT + if ( af_debug_hints_rec_->memory ) + af_glyph_hints_done( af_debug_hints_rec_ ); +#endif + } + + + FT_CALLBACK_DEF( FT_Error ) + af_autofitter_load_glyph( FT_AutoHinter module_, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + AF_Module module = (AF_Module)module_; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = module->root.library->memory; + +#ifdef FT_DEBUG_AUTOFIT + + /* in debug mode, we use a global object that survives this routine */ + + AF_GlyphHints hints = af_debug_hints_rec_; + AF_LoaderRec loader[1]; + + FT_UNUSED( size ); + + + if ( hints->memory ) + af_glyph_hints_done( hints ); + + af_glyph_hints_init( hints, memory ); + af_loader_init( loader, hints ); + + error = af_loader_load_glyph( loader, module, slot->face, + glyph_index, load_flags ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] ) + { +#endif + af_glyph_hints_dump_points( hints, 0 ); + af_glyph_hints_dump_segments( hints, 0 ); + af_glyph_hints_dump_edges( hints, 0 ); +#ifdef FT_DEBUG_LEVEL_TRACE + } +#endif + + af_loader_done( loader ); + + return error; + +#else /* !FT_DEBUG_AUTOFIT */ + + AF_GlyphHintsRec hints[1]; + AF_LoaderRec loader[1]; + + FT_UNUSED( size ); + + + af_glyph_hints_init( hints, memory ); + af_loader_init( loader, hints ); + + error = af_loader_load_glyph( loader, module, slot->face, + glyph_index, load_flags ); + + af_loader_done( loader ); + af_glyph_hints_done( hints ); + + return error; + +#endif /* !FT_DEBUG_AUTOFIT */ + } + + + FT_DEFINE_AUTOHINTER_INTERFACE( + af_autofitter_interface, + + NULL, /* FT_AutoHinter_GlobalResetFunc reset_face */ + NULL, /* FT_AutoHinter_GlobalGetFunc get_global_hints */ + NULL, /* FT_AutoHinter_GlobalDoneFunc done_global_hints */ + af_autofitter_load_glyph /* FT_AutoHinter_GlyphLoadFunc load_glyph */ + ) + + FT_DEFINE_MODULE( + autofit_module_class, + + FT_MODULE_HINTER, + sizeof ( AF_ModuleRec ), + + "autofitter", + 0x10000L, /* version 1.0 of the autofitter */ + 0x20000L, /* requires FreeType 2.0 or above */ + + (const void*)&af_autofitter_interface, + + af_autofitter_init, /* FT_Module_Constructor module_init */ + af_autofitter_done, /* FT_Module_Destructor module_done */ + af_get_interface /* FT_Module_Requester get_interface */ + ) + + +/* END */ diff --git a/vendor/freetype/src/autofit/afmodule.h b/vendor/freetype/src/autofit/afmodule.h new file mode 100644 index 0000000..4b8b456 --- /dev/null +++ b/vendor/freetype/src/autofit/afmodule.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * afmodule.h + * + * Auto-fitter module implementation (specification). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFMODULE_H_ +#define AFMODULE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /* + * This is the `extended' FT_Module structure that holds the + * autofitter's global data. + */ + + typedef struct AF_ModuleRec_ + { + FT_ModuleRec root; + + FT_UInt fallback_style; + AF_Script default_script; + FT_Bool no_stem_darkening; + FT_Int darken_params[8]; + + } AF_ModuleRec, *AF_Module; + + +FT_DECLARE_AUTOHINTER_INTERFACE( af_autofitter_interface ) +FT_DECLARE_MODULE( autofit_module_class ) + + +FT_END_HEADER + +#endif /* AFMODULE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afranges.c b/vendor/freetype/src/autofit/afranges.c new file mode 100644 index 0000000..cfcaf34 --- /dev/null +++ b/vendor/freetype/src/autofit/afranges.c @@ -0,0 +1,1072 @@ +/**************************************************************************** + * + * afranges.c + * + * Auto-fitter Unicode script ranges (body). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afranges.h" + + /* + * The algorithm for assigning properties and styles to the `glyph_styles' + * array is as follows (cf. the implementation in + * `af_face_globals_compute_style_coverage'). + * + * Walk over all scripts (as listed in `afscript.h'). + * + * For a given script, walk over all styles (as listed in `afstyles.h'). + * The order of styles is important and should be as follows. + * + * - First come styles based on OpenType features (small caps, for + * example). Since features rely on glyph indices, thus completely + * bypassing character codes, no properties are assigned. + * + * - Next comes the default style, using the character ranges as defined + * below. This also assigns properties. + * + * Note that there also exist fallback scripts, mainly covering + * superscript and subscript glyphs of a script that are not present as + * OpenType features. Fallback scripts are defined below, also + * assigning properties; they are applied after the corresponding + * script. + * + */ + + + /* XXX Check base character ranges again: */ + /* Right now, they are quickly derived by visual inspection. */ + /* I can imagine that fine-tuning is necessary. */ + + /* for the auto-hinter, a `non-base character' is something that should */ + /* not be affected by blue zones, regardless of whether this is a */ + /* spacing or no-spacing glyph */ + + /* the `af_xxxx_nonbase_uniranges' ranges must be strict subsets */ + /* of the corresponding `af_xxxx_uniranges' ranges */ + + + const AF_Script_UniRangeRec af_adlm_uniranges[] = + { + AF_UNIRANGE_REC( 0x1E900, 0x1E95F ), /* Adlam */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_adlm_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1D944, 0x1E94A ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_arab_uniranges[] = + { + AF_UNIRANGE_REC( 0x0600, 0x06FF ), /* Arabic */ + AF_UNIRANGE_REC( 0x0750, 0x07FF ), /* Arabic Supplement */ + AF_UNIRANGE_REC( 0x08A0, 0x08FF ), /* Arabic Extended-A */ + AF_UNIRANGE_REC( 0xFB50, 0xFDFF ), /* Arabic Presentation Forms-A */ + AF_UNIRANGE_REC( 0xFE70, 0xFEFF ), /* Arabic Presentation Forms-B */ + AF_UNIRANGE_REC( 0x1EE00, 0x1EEFF ), /* Arabic Mathematical Alphabetic Symbols */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_arab_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0600, 0x0605 ), + AF_UNIRANGE_REC( 0x0610, 0x061A ), + AF_UNIRANGE_REC( 0x064B, 0x065F ), + AF_UNIRANGE_REC( 0x0670, 0x0670 ), + AF_UNIRANGE_REC( 0x06D6, 0x06DC ), + AF_UNIRANGE_REC( 0x06DF, 0x06E4 ), + AF_UNIRANGE_REC( 0x06E7, 0x06E8 ), + AF_UNIRANGE_REC( 0x06EA, 0x06ED ), + AF_UNIRANGE_REC( 0x08D4, 0x08E1 ), + AF_UNIRANGE_REC( 0x08D3, 0x08FF ), + AF_UNIRANGE_REC( 0xFBB2, 0xFBC1 ), + AF_UNIRANGE_REC( 0xFE70, 0xFE70 ), + AF_UNIRANGE_REC( 0xFE72, 0xFE72 ), + AF_UNIRANGE_REC( 0xFE74, 0xFE74 ), + AF_UNIRANGE_REC( 0xFE76, 0xFE76 ), + AF_UNIRANGE_REC( 0xFE78, 0xFE78 ), + AF_UNIRANGE_REC( 0xFE7A, 0xFE7A ), + AF_UNIRANGE_REC( 0xFE7C, 0xFE7C ), + AF_UNIRANGE_REC( 0xFE7E, 0xFE7E ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_armn_uniranges[] = + { + AF_UNIRANGE_REC( 0x0530, 0x058F ), /* Armenian */ + AF_UNIRANGE_REC( 0xFB13, 0xFB17 ), /* Alphab. Present. Forms (Armenian) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_armn_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0559, 0x055F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_avst_uniranges[] = + { + AF_UNIRANGE_REC( 0x10B00, 0x10B3F ), /* Avestan */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_avst_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x10B39, 0x10B3F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_bamu_uniranges[] = + { + AF_UNIRANGE_REC( 0xA6A0, 0xA6FF ), /* Bamum */ +#if 0 + /* The characters in the Bamum supplement are pictograms, */ + /* not (directly) related to the syllabic Bamum script */ + AF_UNIRANGE_REC( 0x16800, 0x16A3F ), /* Bamum Supplement */ +#endif + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_bamu_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA6F0, 0xA6F1 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_beng_uniranges[] = + { + AF_UNIRANGE_REC( 0x0980, 0x09FF ), /* Bengali */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_beng_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0981, 0x0981 ), + AF_UNIRANGE_REC( 0x09BC, 0x09BC ), + AF_UNIRANGE_REC( 0x09C1, 0x09C4 ), + AF_UNIRANGE_REC( 0x09CD, 0x09CD ), + AF_UNIRANGE_REC( 0x09E2, 0x09E3 ), + AF_UNIRANGE_REC( 0x09FE, 0x09FE ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_buhd_uniranges[] = + { + AF_UNIRANGE_REC( 0x1740, 0x175F ), /* Buhid */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_buhd_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1752, 0x1753 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cakm_uniranges[] = + { + AF_UNIRANGE_REC( 0x11100, 0x1114F ), /* Chakma */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cakm_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x11100, 0x11102 ), + AF_UNIRANGE_REC( 0x11127, 0x11134 ), + AF_UNIRANGE_REC( 0x11146, 0x11146 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cans_uniranges[] = + { + AF_UNIRANGE_REC( 0x1400, 0x167F ), /* Unified Canadian Aboriginal Syllabics */ + AF_UNIRANGE_REC( 0x18B0, 0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cans_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cari_uniranges[] = + { + AF_UNIRANGE_REC( 0x102A0, 0x102DF ), /* Carian */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cari_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cher_uniranges[] = + { + AF_UNIRANGE_REC( 0x13A0, 0x13FF ), /* Cherokee */ + AF_UNIRANGE_REC( 0xAB70, 0xABBF ), /* Cherokee Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cher_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_copt_uniranges[] = + { + AF_UNIRANGE_REC( 0x2C80, 0x2CFF ), /* Coptic */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_copt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x2CEF, 0x2CF1 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cprt_uniranges[] = + { + AF_UNIRANGE_REC( 0x10800, 0x1083F ), /* Cypriot */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cprt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cyrl_uniranges[] = + { + AF_UNIRANGE_REC( 0x0400, 0x04FF ), /* Cyrillic */ + AF_UNIRANGE_REC( 0x0500, 0x052F ), /* Cyrillic Supplement */ + AF_UNIRANGE_REC( 0x2DE0, 0x2DFF ), /* Cyrillic Extended-A */ + AF_UNIRANGE_REC( 0xA640, 0xA69F ), /* Cyrillic Extended-B */ + AF_UNIRANGE_REC( 0x1C80, 0x1C8F ), /* Cyrillic Extended-C */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cyrl_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0483, 0x0489 ), + AF_UNIRANGE_REC( 0x2DE0, 0x2DFF ), + AF_UNIRANGE_REC( 0xA66F, 0xA67F ), + AF_UNIRANGE_REC( 0xA69E, 0xA69F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + /* There are some characters in the Devanagari Unicode block that are */ + /* generic to Indic scripts; we omit them so that their presence doesn't */ + /* trigger Devanagari. */ + + const AF_Script_UniRangeRec af_deva_uniranges[] = + { + AF_UNIRANGE_REC( 0x0900, 0x093B ), /* Devanagari */ + /* omitting U+093C nukta */ + AF_UNIRANGE_REC( 0x093D, 0x0950 ), /* ... continued */ + /* omitting U+0951 udatta, U+0952 anudatta */ + AF_UNIRANGE_REC( 0x0953, 0x0963 ), /* ... continued */ + /* omitting U+0964 danda, U+0965 double danda */ + AF_UNIRANGE_REC( 0x0966, 0x097F ), /* ... continued */ + AF_UNIRANGE_REC( 0x20B9, 0x20B9 ), /* (new) Rupee sign */ + AF_UNIRANGE_REC( 0xA8E0, 0xA8FF ), /* Devanagari Extended */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_deva_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0900, 0x0902 ), + AF_UNIRANGE_REC( 0x093A, 0x093A ), + AF_UNIRANGE_REC( 0x0941, 0x0948 ), + AF_UNIRANGE_REC( 0x094D, 0x094D ), + AF_UNIRANGE_REC( 0x0953, 0x0957 ), + AF_UNIRANGE_REC( 0x0962, 0x0963 ), + AF_UNIRANGE_REC( 0xA8E0, 0xA8F1 ), + AF_UNIRANGE_REC( 0xA8FF, 0xA8FF ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_dsrt_uniranges[] = + { + AF_UNIRANGE_REC( 0x10400, 0x1044F ), /* Deseret */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_dsrt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_ethi_uniranges[] = + { + AF_UNIRANGE_REC( 0x1200, 0x137F ), /* Ethiopic */ + AF_UNIRANGE_REC( 0x1380, 0x139F ), /* Ethiopic Supplement */ + AF_UNIRANGE_REC( 0x2D80, 0x2DDF ), /* Ethiopic Extended */ + AF_UNIRANGE_REC( 0xAB00, 0xAB2F ), /* Ethiopic Extended-A */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_ethi_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x135D, 0x135F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_geor_uniranges[] = + { + AF_UNIRANGE_REC( 0x10D0, 0x10FF ), /* Georgian (Mkhedruli) */ + AF_UNIRANGE_REC( 0x1C90, 0x1CBF ), /* Georgian Extended (Mtavruli) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_geor_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_geok_uniranges[] = + { + /* Khutsuri */ + AF_UNIRANGE_REC( 0x10A0, 0x10CD ), /* Georgian (Asomtavruli) */ + AF_UNIRANGE_REC( 0x2D00, 0x2D2D ), /* Georgian Supplement (Nuskhuri) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_geok_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_glag_uniranges[] = + { + AF_UNIRANGE_REC( 0x2C00, 0x2C5F ), /* Glagolitic */ + AF_UNIRANGE_REC( 0x1E000, 0x1E02F ), /* Glagolitic Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_glag_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1E000, 0x1E02F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_goth_uniranges[] = + { + AF_UNIRANGE_REC( 0x10330, 0x1034F ), /* Gothic */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_goth_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_grek_uniranges[] = + { + AF_UNIRANGE_REC( 0x0370, 0x03FF ), /* Greek and Coptic */ + AF_UNIRANGE_REC( 0x1F00, 0x1FFF ), /* Greek Extended */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_grek_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x037A, 0x037A ), + AF_UNIRANGE_REC( 0x0384, 0x0385 ), + AF_UNIRANGE_REC( 0x1FBD, 0x1FC1 ), + AF_UNIRANGE_REC( 0x1FCD, 0x1FCF ), + AF_UNIRANGE_REC( 0x1FDD, 0x1FDF ), + AF_UNIRANGE_REC( 0x1FED, 0x1FEF ), + AF_UNIRANGE_REC( 0x1FFD, 0x1FFE ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_gujr_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A80, 0x0AFF ), /* Gujarati */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_gujr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A81, 0x0A82 ), + AF_UNIRANGE_REC( 0x0ABC, 0x0ABC ), + AF_UNIRANGE_REC( 0x0AC1, 0x0AC8 ), + AF_UNIRANGE_REC( 0x0ACD, 0x0ACD ), + AF_UNIRANGE_REC( 0x0AE2, 0x0AE3 ), + AF_UNIRANGE_REC( 0x0AFA, 0x0AFF ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_guru_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A00, 0x0A7F ), /* Gurmukhi */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_guru_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A01, 0x0A02 ), + AF_UNIRANGE_REC( 0x0A3C, 0x0A3C ), + AF_UNIRANGE_REC( 0x0A41, 0x0A51 ), + AF_UNIRANGE_REC( 0x0A70, 0x0A71 ), + AF_UNIRANGE_REC( 0x0A75, 0x0A75 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_hebr_uniranges[] = + { + AF_UNIRANGE_REC( 0x0590, 0x05FF ), /* Hebrew */ + AF_UNIRANGE_REC( 0xFB1D, 0xFB4F ), /* Alphab. Present. Forms (Hebrew) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_hebr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0591, 0x05BF ), + AF_UNIRANGE_REC( 0x05C1, 0x05C2 ), + AF_UNIRANGE_REC( 0x05C4, 0x05C5 ), + AF_UNIRANGE_REC( 0x05C7, 0x05C7 ), + AF_UNIRANGE_REC( 0xFB1E, 0xFB1E ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_kali_uniranges[] = + { + AF_UNIRANGE_REC( 0xA900, 0xA92F ), /* Kayah Li */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_kali_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA926, 0xA92D ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_knda_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C80, 0x0CFF ), /* Kannada */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_knda_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C81, 0x0C81 ), + AF_UNIRANGE_REC( 0x0CBC, 0x0CBC ), + AF_UNIRANGE_REC( 0x0CBF, 0x0CBF ), + AF_UNIRANGE_REC( 0x0CC6, 0x0CC6 ), + AF_UNIRANGE_REC( 0x0CCC, 0x0CCD ), + AF_UNIRANGE_REC( 0x0CE2, 0x0CE3 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_khmr_uniranges[] = + { + AF_UNIRANGE_REC( 0x1780, 0x17FF ), /* Khmer */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_khmr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x17B7, 0x17BD ), + AF_UNIRANGE_REC( 0x17C6, 0x17C6 ), + AF_UNIRANGE_REC( 0x17C9, 0x17D3 ), + AF_UNIRANGE_REC( 0x17DD, 0x17DD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_khms_uniranges[] = + { + AF_UNIRANGE_REC( 0x19E0, 0x19FF ), /* Khmer Symbols */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_khms_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_lao_uniranges[] = + { + AF_UNIRANGE_REC( 0x0E80, 0x0EFF ), /* Lao */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_lao_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0EB1, 0x0EB1 ), + AF_UNIRANGE_REC( 0x0EB4, 0x0EBC ), + AF_UNIRANGE_REC( 0x0EC8, 0x0ECD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_latn_uniranges[] = + { + AF_UNIRANGE_REC( 0x0020, 0x007F ), /* Basic Latin (no control chars) */ + AF_UNIRANGE_REC( 0x00A0, 0x00A9 ), /* Latin-1 Supplement (no control chars) */ + AF_UNIRANGE_REC( 0x00AB, 0x00B1 ), /* ... continued */ + AF_UNIRANGE_REC( 0x00B4, 0x00B8 ), /* ... continued */ + AF_UNIRANGE_REC( 0x00BB, 0x00FF ), /* ... continued */ + AF_UNIRANGE_REC( 0x0100, 0x017F ), /* Latin Extended-A */ + AF_UNIRANGE_REC( 0x0180, 0x024F ), /* Latin Extended-B */ + AF_UNIRANGE_REC( 0x0250, 0x02AF ), /* IPA Extensions */ + AF_UNIRANGE_REC( 0x02B9, 0x02DF ), /* Spacing Modifier Letters */ + AF_UNIRANGE_REC( 0x02E5, 0x02FF ), /* ... continued */ + AF_UNIRANGE_REC( 0x0300, 0x036F ), /* Combining Diacritical Marks */ + AF_UNIRANGE_REC( 0x1AB0, 0x1ABE ), /* Combining Diacritical Marks Extended */ + AF_UNIRANGE_REC( 0x1D00, 0x1D2B ), /* Phonetic Extensions */ + AF_UNIRANGE_REC( 0x1D6B, 0x1D77 ), /* ... continued */ + AF_UNIRANGE_REC( 0x1D79, 0x1D7F ), /* ... continued */ + AF_UNIRANGE_REC( 0x1D80, 0x1D9A ), /* Phonetic Extensions Supplement */ + AF_UNIRANGE_REC( 0x1DC0, 0x1DFF ), /* Combining Diacritical Marks Supplement */ + AF_UNIRANGE_REC( 0x1E00, 0x1EFF ), /* Latin Extended Additional */ + AF_UNIRANGE_REC( 0x2000, 0x206F ), /* General Punctuation */ + AF_UNIRANGE_REC( 0x20A0, 0x20B8 ), /* Currency Symbols ... */ + AF_UNIRANGE_REC( 0x20BA, 0x20CF ), /* ... except new Rupee sign */ + AF_UNIRANGE_REC( 0x2150, 0x218F ), /* Number Forms */ + AF_UNIRANGE_REC( 0x2C60, 0x2C7B ), /* Latin Extended-C */ + AF_UNIRANGE_REC( 0x2C7E, 0x2C7F ), /* ... continued */ + AF_UNIRANGE_REC( 0x2E00, 0x2E7F ), /* Supplemental Punctuation */ + AF_UNIRANGE_REC( 0xA720, 0xA76F ), /* Latin Extended-D */ + AF_UNIRANGE_REC( 0xA771, 0xA7F7 ), /* ... continued */ + AF_UNIRANGE_REC( 0xA7FA, 0xA7FF ), /* ... continued */ + AF_UNIRANGE_REC( 0xAB30, 0xAB5B ), /* Latin Extended-E */ + AF_UNIRANGE_REC( 0xAB60, 0xAB6F ), /* ... continued */ + AF_UNIRANGE_REC( 0xFB00, 0xFB06 ), /* Alphab. Present. Forms (Latin Ligs) */ + AF_UNIRANGE_REC( 0x1D400, 0x1D7FF ), /* Mathematical Alphanumeric Symbols */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_latn_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x005E, 0x0060 ), + AF_UNIRANGE_REC( 0x007E, 0x007E ), + AF_UNIRANGE_REC( 0x00A8, 0x00A9 ), + AF_UNIRANGE_REC( 0x00AE, 0x00B0 ), + AF_UNIRANGE_REC( 0x00B4, 0x00B4 ), + AF_UNIRANGE_REC( 0x00B8, 0x00B8 ), + AF_UNIRANGE_REC( 0x00BC, 0x00BE ), + AF_UNIRANGE_REC( 0x02B9, 0x02DF ), + AF_UNIRANGE_REC( 0x02E5, 0x02FF ), + AF_UNIRANGE_REC( 0x0300, 0x036F ), + AF_UNIRANGE_REC( 0x1AB0, 0x1ABE ), + AF_UNIRANGE_REC( 0x1DC0, 0x1DFF ), + AF_UNIRANGE_REC( 0x2017, 0x2017 ), + AF_UNIRANGE_REC( 0x203E, 0x203E ), + AF_UNIRANGE_REC( 0xA788, 0xA788 ), + AF_UNIRANGE_REC( 0xA7F8, 0xA7FA ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_latb_uniranges[] = + { + AF_UNIRANGE_REC( 0x1D62, 0x1D6A ), /* some small subscript letters */ + AF_UNIRANGE_REC( 0x2080, 0x209C ), /* subscript digits and letters */ + AF_UNIRANGE_REC( 0x2C7C, 0x2C7C ), /* latin subscript small letter j */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_latb_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_latp_uniranges[] = + { + AF_UNIRANGE_REC( 0x00AA, 0x00AA ), /* feminine ordinal indicator */ + AF_UNIRANGE_REC( 0x00B2, 0x00B3 ), /* superscript two and three */ + AF_UNIRANGE_REC( 0x00B9, 0x00BA ), /* superscript one, masc. ord. indic. */ + AF_UNIRANGE_REC( 0x02B0, 0x02B8 ), /* some latin superscript mod. letters */ + AF_UNIRANGE_REC( 0x02E0, 0x02E4 ), /* some IPA modifier letters */ + AF_UNIRANGE_REC( 0x1D2C, 0x1D61 ), /* latin superscript modifier letters */ + AF_UNIRANGE_REC( 0x1D78, 0x1D78 ), /* modifier letter cyrillic en */ + AF_UNIRANGE_REC( 0x1D9B, 0x1DBF ), /* more modifier letters */ + AF_UNIRANGE_REC( 0x2070, 0x207F ), /* superscript digits and letters */ + AF_UNIRANGE_REC( 0x2C7D, 0x2C7D ), /* modifier letter capital v */ + AF_UNIRANGE_REC( 0xA770, 0xA770 ), /* modifier letter us */ + AF_UNIRANGE_REC( 0xA7F8, 0xA7F9 ), /* more modifier letters */ + AF_UNIRANGE_REC( 0xAB5C, 0xAB5F ), /* more modifier letters */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_latp_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_lisu_uniranges[] = + { + AF_UNIRANGE_REC( 0xA4D0, 0xA4FF ), /* Lisu */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_lisu_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_mlym_uniranges[] = + { + AF_UNIRANGE_REC( 0x0D00, 0x0D7F ), /* Malayalam */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_mlym_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0D00, 0x0D01 ), + AF_UNIRANGE_REC( 0x0D3B, 0x0D3C ), + AF_UNIRANGE_REC( 0x0D4D, 0x0D4E ), + AF_UNIRANGE_REC( 0x0D62, 0x0D63 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_medf_uniranges[] = + { + AF_UNIRANGE_REC( 0x16E40, 0x16E9F ), /* Medefaidrin */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_medf_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_mong_uniranges[] = + { + AF_UNIRANGE_REC( 0x1800, 0x18AF ), /* Mongolian */ + AF_UNIRANGE_REC( 0x11660, 0x1167F ), /* Mongolian Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_mong_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1885, 0x1886 ), + AF_UNIRANGE_REC( 0x18A9, 0x18A9 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_mymr_uniranges[] = + { + AF_UNIRANGE_REC( 0x1000, 0x109F ), /* Myanmar */ + AF_UNIRANGE_REC( 0xA9E0, 0xA9FF ), /* Myanmar Extended-B */ + AF_UNIRANGE_REC( 0xAA60, 0xAA7F ), /* Myanmar Extended-A */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_mymr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x102D, 0x1030 ), + AF_UNIRANGE_REC( 0x1032, 0x1037 ), + AF_UNIRANGE_REC( 0x103A, 0x103A ), + AF_UNIRANGE_REC( 0x103D, 0x103E ), + AF_UNIRANGE_REC( 0x1058, 0x1059 ), + AF_UNIRANGE_REC( 0x105E, 0x1060 ), + AF_UNIRANGE_REC( 0x1071, 0x1074 ), + AF_UNIRANGE_REC( 0x1082, 0x1082 ), + AF_UNIRANGE_REC( 0x1085, 0x1086 ), + AF_UNIRANGE_REC( 0x108D, 0x108D ), + AF_UNIRANGE_REC( 0xA9E5, 0xA9E5 ), + AF_UNIRANGE_REC( 0xAA7C, 0xAA7C ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_nkoo_uniranges[] = + { + AF_UNIRANGE_REC( 0x07C0, 0x07FF ), /* N'Ko */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_nkoo_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x07EB, 0x07F5 ), + AF_UNIRANGE_REC( 0x07FD, 0x07FD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_none_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_none_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_olck_uniranges[] = + { + AF_UNIRANGE_REC( 0x1C50, 0x1C7F ), /* Ol Chiki */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_olck_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_orkh_uniranges[] = + { + AF_UNIRANGE_REC( 0x10C00, 0x10C4F ), /* Old Turkic */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_orkh_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_osge_uniranges[] = + { + AF_UNIRANGE_REC( 0x104B0, 0x104FF ), /* Osage */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_osge_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_osma_uniranges[] = + { + AF_UNIRANGE_REC( 0x10480, 0x104AF ), /* Osmanya */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_osma_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_rohg_uniranges[] = + { + AF_UNIRANGE_REC( 0x10D00, 0x10D3F ), /* Hanifi Rohingya */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_rohg_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_saur_uniranges[] = + { + AF_UNIRANGE_REC( 0xA880, 0xA8DF ), /* Saurashtra */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_saur_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA880, 0xA881 ), + AF_UNIRANGE_REC( 0xA8B4, 0xA8C5 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_shaw_uniranges[] = + { + AF_UNIRANGE_REC( 0x10450, 0x1047F ), /* Shavian */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_shaw_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_sinh_uniranges[] = + { + AF_UNIRANGE_REC( 0x0D80, 0x0DFF ), /* Sinhala */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_sinh_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0DCA, 0x0DCA ), + AF_UNIRANGE_REC( 0x0DD2, 0x0DD6 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_sund_uniranges[] = + { + AF_UNIRANGE_REC( 0x1B80, 0x1BBF ), /* Sundanese */ + AF_UNIRANGE_REC( 0x1CC0, 0x1CCF ), /* Sundanese Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_sund_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1B80, 0x1B82 ), + AF_UNIRANGE_REC( 0x1BA1, 0x1BAD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_taml_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B80, 0x0BFF ), /* Tamil */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_taml_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B82, 0x0B82 ), + AF_UNIRANGE_REC( 0x0BC0, 0x0BC2 ), + AF_UNIRANGE_REC( 0x0BCD, 0x0BCD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_tavt_uniranges[] = + { + AF_UNIRANGE_REC( 0xAA80, 0xAADF ), /* Tai Viet */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_tavt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xAAB0, 0xAAB0 ), + AF_UNIRANGE_REC( 0xAAB2, 0xAAB4 ), + AF_UNIRANGE_REC( 0xAAB7, 0xAAB8 ), + AF_UNIRANGE_REC( 0xAABE, 0xAABF ), + AF_UNIRANGE_REC( 0xAAC1, 0xAAC1 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_telu_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C00, 0x0C7F ), /* Telugu */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_telu_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C00, 0x0C00 ), + AF_UNIRANGE_REC( 0x0C04, 0x0C04 ), + AF_UNIRANGE_REC( 0x0C3E, 0x0C40 ), + AF_UNIRANGE_REC( 0x0C46, 0x0C56 ), + AF_UNIRANGE_REC( 0x0C62, 0x0C63 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_thai_uniranges[] = + { + AF_UNIRANGE_REC( 0x0E00, 0x0E7F ), /* Thai */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_thai_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0E31, 0x0E31 ), + AF_UNIRANGE_REC( 0x0E34, 0x0E3A ), + AF_UNIRANGE_REC( 0x0E47, 0x0E4E ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_tfng_uniranges[] = + { + AF_UNIRANGE_REC( 0x2D30, 0x2D7F ), /* Tifinagh */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_tfng_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_vaii_uniranges[] = + { + AF_UNIRANGE_REC( 0xA500, 0xA63F ), /* Vai */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_vaii_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + +#ifdef AF_CONFIG_OPTION_INDIC + + const AF_Script_UniRangeRec af_limb_uniranges[] = + { + AF_UNIRANGE_REC( 0x1900, 0x194F ), /* Limbu */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_limb_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1920, 0x1922 ), + AF_UNIRANGE_REC( 0x1927, 0x1934 ), + AF_UNIRANGE_REC( 0x1937, 0x193B ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_orya_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B00, 0x0B7F ), /* Oriya */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_orya_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B01, 0x0B02 ), + AF_UNIRANGE_REC( 0x0B3C, 0x0B3C ), + AF_UNIRANGE_REC( 0x0B3F, 0x0B3F ), + AF_UNIRANGE_REC( 0x0B41, 0x0B44 ), + AF_UNIRANGE_REC( 0x0B4D, 0x0B56 ), + AF_UNIRANGE_REC( 0x0B62, 0x0B63 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_sylo_uniranges[] = + { + AF_UNIRANGE_REC( 0xA800, 0xA82F ), /* Syloti Nagri */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_sylo_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA802, 0xA802 ), + AF_UNIRANGE_REC( 0xA806, 0xA806 ), + AF_UNIRANGE_REC( 0xA80B, 0xA80B ), + AF_UNIRANGE_REC( 0xA825, 0xA826 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_tibt_uniranges[] = + { + AF_UNIRANGE_REC( 0x0F00, 0x0FFF ), /* Tibetan */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_tibt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0F18, 0x0F19 ), + AF_UNIRANGE_REC( 0x0F35, 0x0F35 ), + AF_UNIRANGE_REC( 0x0F37, 0x0F37 ), + AF_UNIRANGE_REC( 0x0F39, 0x0F39 ), + AF_UNIRANGE_REC( 0x0F3E, 0x0F3F ), + AF_UNIRANGE_REC( 0x0F71, 0x0F7E ), + AF_UNIRANGE_REC( 0x0F80, 0x0F84 ), + AF_UNIRANGE_REC( 0x0F86, 0x0F87 ), + AF_UNIRANGE_REC( 0x0F8D, 0x0FBC ), + AF_UNIRANGE_REC( 0, 0 ) + }; + +#endif /* !AF_CONFIG_OPTION_INDIC */ + +#ifdef AF_CONFIG_OPTION_CJK + + /* this corresponds to Unicode 6.0 */ + + const AF_Script_UniRangeRec af_hani_uniranges[] = + { + AF_UNIRANGE_REC( 0x1100, 0x11FF ), /* Hangul Jamo */ + AF_UNIRANGE_REC( 0x2E80, 0x2EFF ), /* CJK Radicals Supplement */ + AF_UNIRANGE_REC( 0x2F00, 0x2FDF ), /* Kangxi Radicals */ + AF_UNIRANGE_REC( 0x2FF0, 0x2FFF ), /* Ideographic Description Characters */ + AF_UNIRANGE_REC( 0x3000, 0x303F ), /* CJK Symbols and Punctuation */ + AF_UNIRANGE_REC( 0x3040, 0x309F ), /* Hiragana */ + AF_UNIRANGE_REC( 0x30A0, 0x30FF ), /* Katakana */ + AF_UNIRANGE_REC( 0x3100, 0x312F ), /* Bopomofo */ + AF_UNIRANGE_REC( 0x3130, 0x318F ), /* Hangul Compatibility Jamo */ + AF_UNIRANGE_REC( 0x3190, 0x319F ), /* Kanbun */ + AF_UNIRANGE_REC( 0x31A0, 0x31BF ), /* Bopomofo Extended */ + AF_UNIRANGE_REC( 0x31C0, 0x31EF ), /* CJK Strokes */ + AF_UNIRANGE_REC( 0x31F0, 0x31FF ), /* Katakana Phonetic Extensions */ + AF_UNIRANGE_REC( 0x3300, 0x33FF ), /* CJK Compatibility */ + AF_UNIRANGE_REC( 0x3400, 0x4DBF ), /* CJK Unified Ideographs Extension A */ + AF_UNIRANGE_REC( 0x4DC0, 0x4DFF ), /* Yijing Hexagram Symbols */ + AF_UNIRANGE_REC( 0x4E00, 0x9FFF ), /* CJK Unified Ideographs */ + AF_UNIRANGE_REC( 0xA960, 0xA97F ), /* Hangul Jamo Extended-A */ + AF_UNIRANGE_REC( 0xAC00, 0xD7AF ), /* Hangul Syllables */ + AF_UNIRANGE_REC( 0xD7B0, 0xD7FF ), /* Hangul Jamo Extended-B */ + AF_UNIRANGE_REC( 0xF900, 0xFAFF ), /* CJK Compatibility Ideographs */ + AF_UNIRANGE_REC( 0xFE10, 0xFE1F ), /* Vertical forms */ + AF_UNIRANGE_REC( 0xFE30, 0xFE4F ), /* CJK Compatibility Forms */ + AF_UNIRANGE_REC( 0xFF00, 0xFFEF ), /* Halfwidth and Fullwidth Forms */ + AF_UNIRANGE_REC( 0x1B000, 0x1B0FF ), /* Kana Supplement */ + AF_UNIRANGE_REC( 0x1B100, 0x1B12F ), /* Kana Extended-A */ + AF_UNIRANGE_REC( 0x1D300, 0x1D35F ), /* Tai Xuan Hing Symbols */ + AF_UNIRANGE_REC( 0x20000, 0x2A6DF ), /* CJK Unified Ideographs Extension B */ + AF_UNIRANGE_REC( 0x2A700, 0x2B73F ), /* CJK Unified Ideographs Extension C */ + AF_UNIRANGE_REC( 0x2B740, 0x2B81F ), /* CJK Unified Ideographs Extension D */ + AF_UNIRANGE_REC( 0x2B820, 0x2CEAF ), /* CJK Unified Ideographs Extension E */ + AF_UNIRANGE_REC( 0x2CEB0, 0x2EBEF ), /* CJK Unified Ideographs Extension F */ + AF_UNIRANGE_REC( 0x2F800, 0x2FA1F ), /* CJK Compatibility Ideographs Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_hani_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x302A, 0x302F ), + AF_UNIRANGE_REC( 0x3190, 0x319F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + +#endif /* !AF_CONFIG_OPTION_CJK */ + +/* END */ diff --git a/vendor/freetype/src/autofit/afranges.h b/vendor/freetype/src/autofit/afranges.h new file mode 100644 index 0000000..5775738 --- /dev/null +++ b/vendor/freetype/src/autofit/afranges.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * afranges.h + * + * Auto-fitter Unicode script ranges (specification). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFRANGES_H_ +#define AFRANGES_H_ + + +#include "aftypes.h" + + +FT_BEGIN_HEADER + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + extern const AF_Script_UniRangeRec af_ ## s ## _uniranges[]; + +#include "afscript.h" + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + extern const AF_Script_UniRangeRec af_ ## s ## _nonbase_uniranges[]; + +#include "afscript.h" + + /* */ + +FT_END_HEADER + +#endif /* AFRANGES_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afscript.h b/vendor/freetype/src/autofit/afscript.h new file mode 100644 index 0000000..3a10193 --- /dev/null +++ b/vendor/freetype/src/autofit/afscript.h @@ -0,0 +1,408 @@ +/**************************************************************************** + * + * afscript.h + * + * Auto-fitter scripts (specification only). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* The following part can be included multiple times. */ + /* Define `SCRIPT' as needed. */ + + + /* Add new scripts here. The first and second arguments are the */ + /* script name in lowercase and uppercase, respectively, followed */ + /* by a description string. Then comes the corresponding HarfBuzz */ + /* script name tag, followed by a string of standard characters (to */ + /* derive the standard width and height of stems). */ + /* */ + /* Note that fallback scripts only have a default style, thus we */ + /* use `HB_SCRIPT_INVALID' as the HarfBuzz script name tag for */ + /* them. */ + + SCRIPT( adlm, ADLM, + "Adlam", + HB_SCRIPT_ADLAM, + HINTING_BOTTOM_TO_TOP, + "\xF0\x9E\xA4\x8C \xF0\x9E\xA4\xAE" ) /* 𞤌 𞤮 */ + + SCRIPT( arab, ARAB, + "Arabic", + HB_SCRIPT_ARABIC, + HINTING_BOTTOM_TO_TOP, + "\xD9\x84 \xD8\xAD \xD9\x80" ) /* Ù„ Ø­ Ù€ */ + + SCRIPT( armn, ARMN, + "Armenian", + HB_SCRIPT_ARMENIAN, + HINTING_BOTTOM_TO_TOP, + "\xD5\xBD \xD5\x8D" ) /* Õ½ Õ */ + + SCRIPT( avst, AVST, + "Avestan", + HB_SCRIPT_AVESTAN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xAC\x9A" ) /* 𬚠*/ + + SCRIPT( bamu, BAMU, + "Bamum", + HB_SCRIPT_BAMUM, + HINTING_BOTTOM_TO_TOP, + "\xEA\x9B\x81 \xEA\x9B\xAF" ) /* ê› ê›¯ */ + + /* there are no simple forms for letters; we thus use two digit shapes */ + SCRIPT( beng, BENG, + "Bengali", + HB_SCRIPT_BENGALI, + HINTING_TOP_TO_BOTTOM, + "\xE0\xA7\xA6 \xE0\xA7\xAA" ) /* ০ ৪ */ + + SCRIPT( buhd, BUHD, + "Buhid", + HB_SCRIPT_BUHID, + HINTING_BOTTOM_TO_TOP, + "\xE1\x9D\x8B \xE1\x9D\x8F" ) /* á‹ á */ + + SCRIPT( cakm, CAKM, + "Chakma", + HB_SCRIPT_CHAKMA, + HINTING_BOTTOM_TO_TOP, + "\xF0\x91\x84\xA4 \xF0\x91\x84\x89 \xF0\x91\x84\x9B" ) /* 𑄤 𑄉 ð‘„› */ + + SCRIPT( cans, CANS, + "Canadian Syllabics", + HB_SCRIPT_CANADIAN_SYLLABICS, + HINTING_BOTTOM_TO_TOP, + "\xE1\x91\x8C \xE1\x93\x9A" ) /* ᑌ ᓚ */ + + SCRIPT( cari, CARI, + "Carian", + HB_SCRIPT_CARIAN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x8A\xAB \xF0\x90\x8B\x89" ) /* ðŠ« ð‹‰ */ + + SCRIPT( cher, CHER, + "Cherokee", + HB_SCRIPT_CHEROKEE, + HINTING_BOTTOM_TO_TOP, + "\xE1\x8E\xA4 \xE1\x8F\x85 \xEA\xAE\x95" ) /* Ꭴ á… ê®• */ + + SCRIPT( copt, COPT, + "Coptic", + HB_SCRIPT_COPTIC, + HINTING_BOTTOM_TO_TOP, + "\xE2\xB2\x9E \xE2\xB2\x9F" ) /* Ⲟ ⲟ */ + + SCRIPT( cprt, CPRT, + "Cypriot", + HB_SCRIPT_CYPRIOT, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xA0\x85 \xF0\x90\xA0\xA3" ) /* ð … ð £ */ + + SCRIPT( cyrl, CYRL, + "Cyrillic", + HB_SCRIPT_CYRILLIC, + HINTING_BOTTOM_TO_TOP, + "\xD0\xBE \xD0\x9E" ) /* о О */ + + SCRIPT( deva, DEVA, + "Devanagari", + HB_SCRIPT_DEVANAGARI, + HINTING_TOP_TO_BOTTOM, + "\xE0\xA4\xA0 \xE0\xA4\xB5 \xE0\xA4\x9F" ) /* ठ व ट */ + + SCRIPT( dsrt, DSRT, + "Deseret", + HB_SCRIPT_DESERET, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x90\x84 \xF0\x90\x90\xAC" ) /* ð„ ð¬ */ + + SCRIPT( ethi, ETHI, + "Ethiopic", + HB_SCRIPT_ETHIOPIC, + HINTING_BOTTOM_TO_TOP, + "\xE1\x8B\x90" ) /* á‹ */ + + SCRIPT( geor, GEOR, + "Georgian (Mkhedruli)", + HB_SCRIPT_GEORGIAN, + HINTING_BOTTOM_TO_TOP, + "\xE1\x83\x98 \xE1\x83\x94 \xE1\x83\x90 \xE1\xB2\xBF" ) /* ი ე რᲘ */ + + SCRIPT( geok, GEOK, + "Georgian (Khutsuri)", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE1\x82\xB6 \xE1\x82\xB1 \xE2\xB4\x99" ) /* á‚¶ Ⴑ â´™ */ + + SCRIPT( glag, GLAG, + "Glagolitic", + HB_SCRIPT_GLAGOLITIC, + HINTING_BOTTOM_TO_TOP, + "\xE2\xB0\x95 \xE2\xB1\x85" ) /* â°• â±… */ + + SCRIPT( goth, GOTH, + "Gothic", + HB_SCRIPT_GOTHIC, + HINTING_TOP_TO_BOTTOM, + "\xF0\x90\x8C\xB4 \xF0\x90\x8C\xBE \xF0\x90\x8D\x83" ) /* ðŒ´ ðŒ¾ ðƒ */ + + SCRIPT( grek, GREK, + "Greek", + HB_SCRIPT_GREEK, + HINTING_BOTTOM_TO_TOP, + "\xCE\xBF \xCE\x9F" ) /* ο Ο */ + + SCRIPT( gujr, GUJR, + "Gujarati", + HB_SCRIPT_GUJARATI, + HINTING_BOTTOM_TO_TOP, + "\xE0\xAA\x9F \xE0\xAB\xA6" ) /* ટ ૦ */ + + SCRIPT( guru, GURU, + "Gurmukhi", + HB_SCRIPT_GURMUKHI, + HINTING_TOP_TO_BOTTOM, + "\xE0\xA8\xA0 \xE0\xA8\xB0 \xE0\xA9\xA6" ) /* ਠ ਰ ੦ */ + + SCRIPT( hebr, HEBR, + "Hebrew", + HB_SCRIPT_HEBREW, + HINTING_BOTTOM_TO_TOP, + "\xD7\x9D" ) /* × */ + + SCRIPT( kali, KALI, + "Kayah Li", + HB_SCRIPT_KAYAH_LI, + HINTING_BOTTOM_TO_TOP, + "\xEA\xA4\x8D \xEA\xA4\x80" ) /* ê¤ ê¤€ */ + + /* only digit zero has a simple shape in the Khmer script */ + SCRIPT( khmr, KHMR, + "Khmer", + HB_SCRIPT_KHMER, + HINTING_BOTTOM_TO_TOP, + "\xE1\x9F\xA0" ) /* ០ */ + + SCRIPT( khms, KHMS, + "Khmer Symbols", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE1\xA7\xA1 \xE1\xA7\xAA" ) /* á§¡ ᧪ */ + + SCRIPT( knda, KNDA, + "Kannada", + HB_SCRIPT_KANNADA, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB3\xA6 \xE0\xB2\xAC" ) /* ೦ ಬ */ + + /* only digit zero has a simple shape in the Lao script */ + SCRIPT( lao, LAO, + "Lao", + HB_SCRIPT_LAO, + HINTING_BOTTOM_TO_TOP, + "\xE0\xBB\x90" ) /* à» */ + + SCRIPT( latn, LATN, + "Latin", + HB_SCRIPT_LATIN, + HINTING_BOTTOM_TO_TOP, + "o O 0" ) + + SCRIPT( latb, LATB, + "Latin Subscript Fallback", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE2\x82\x92 \xE2\x82\x80" ) /* â‚’ â‚€ */ + + SCRIPT( latp, LATP, + "Latin Superscript Fallback", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE1\xB5\x92 \xE1\xB4\xBC \xE2\x81\xB0" ) /* áµ’ á´¼ â° */ + + SCRIPT( lisu, LISU, + "Lisu", + HB_SCRIPT_LISU, + HINTING_BOTTOM_TO_TOP, + "\xEA\x93\xB3" ) /* ꓳ */ + + SCRIPT( mlym, MLYM, + "Malayalam", + HB_SCRIPT_MALAYALAM, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB4\xA0 \xE0\xB4\xB1" ) /* à´  à´± */ + + SCRIPT( medf, MEDF, + "Medefaidrin", + HB_SCRIPT_MEDEFAIDRIN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x96\xB9\xA1 \xF0\x96\xB9\x9B \xF0\x96\xB9\xAF" ) /* 𖹡 ð–¹› 𖹯 */ + + SCRIPT( mong, MONG, + "Mongolian", + HB_SCRIPT_MONGOLIAN, + HINTING_TOP_TO_BOTTOM, + "\xE1\xA1\x82 \xE1\xA0\xAA" ) /* á¡‚ á ª */ + + SCRIPT( mymr, MYMR, + "Myanmar", + HB_SCRIPT_MYANMAR, + HINTING_BOTTOM_TO_TOP, + "\xE1\x80\x9D \xE1\x80\x84 \xE1\x80\x82" ) /* ဠင ဂ */ + + SCRIPT( nkoo, NKOO, + "N'Ko", + HB_SCRIPT_NKO, + HINTING_BOTTOM_TO_TOP, + "\xDF\x8B \xDF\x80" ) /* ß‹ ߀ */ + + SCRIPT( none, NONE, + "no script", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "" ) + + SCRIPT( olck, OLCK, + "Ol Chiki", + HB_SCRIPT_OL_CHIKI, + HINTING_BOTTOM_TO_TOP, + "\xE1\xB1\x9B" ) /* á±› */ + + SCRIPT( orkh, ORKH, + "Old Turkic", + HB_SCRIPT_OLD_TURKIC, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xB0\x97" ) /* ð°— */ + + SCRIPT( osge, OSGE, + "Osage", + HB_SCRIPT_OSAGE, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x93\x82 \xF0\x90\x93\xAA" ) /* 𓂠𓪠*/ + + SCRIPT( osma, OSMA, + "Osmanya", + HB_SCRIPT_OSMANYA, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x92\x86 \xF0\x90\x92\xA0" ) /* ð’† ð’  */ + + SCRIPT( rohg, ROHG, + "Hanifi Rohingya", + HB_SCRIPT_HANIFI_ROHINGYA, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xB4\xB0" ) /* ð´° */ + + SCRIPT( saur, SAUR, + "Saurashtra", + HB_SCRIPT_SAURASHTRA, + HINTING_BOTTOM_TO_TOP, + "\xEA\xA2\x9D \xEA\xA3\x90" ) /* ê¢ ê£ */ + + SCRIPT( shaw, SHAW, + "Shavian", + HB_SCRIPT_SHAVIAN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x91\xB4" ) /* ð‘´ */ + + SCRIPT( sinh, SINH, + "Sinhala", + HB_SCRIPT_SINHALA, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB6\xA7" ) /* à¶§ */ + + /* only digit zero has a simple (round) shape in the Sundanese script */ + SCRIPT( sund, SUND, + "Sundanese", + HB_SCRIPT_SUNDANESE, + HINTING_BOTTOM_TO_TOP, + "\xE1\xAE\xB0" ) /* á®° */ + + /* only digit zero has a simple (round) shape in the Tamil script */ + SCRIPT( taml, TAML, + "Tamil", + HB_SCRIPT_TAMIL, + HINTING_BOTTOM_TO_TOP, + "\xE0\xAF\xA6" ) /* ௦ */ + + SCRIPT( tavt, TAVT, + "Tai Viet", + HB_SCRIPT_TAI_VIET, + HINTING_BOTTOM_TO_TOP, + "\xEA\xAA\x92 \xEA\xAA\xAB" ) /* ꪒ ꪫ */ + + /* there are no simple forms for letters; we thus use two digit shapes */ + SCRIPT( telu, TELU, + "Telugu", + HB_SCRIPT_TELUGU, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB1\xA6 \xE0\xB1\xA7" ) /* ౦ à±§ */ + + SCRIPT( tfng, TFNG, + "Tifinagh", + HB_SCRIPT_TIFINAGH, + HINTING_BOTTOM_TO_TOP, + "\xE2\xB5\x94" ) /* âµ” */ + + SCRIPT( thai, THAI, + "Thai", + HB_SCRIPT_THAI, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB8\xB2 \xE0\xB9\x85 \xE0\xB9\x90" ) /* า ๅ ๠*/ + + SCRIPT( vaii, VAII, + "Vai", + HB_SCRIPT_VAI, + HINTING_BOTTOM_TO_TOP, + "\xEA\x98\x93 \xEA\x96\x9C \xEA\x96\xB4" ) /* ꘓ ê–œ ê–´ */ + +#ifdef AF_CONFIG_OPTION_INDIC + + SCRIPT( limb, LIMB, + "Limbu", + HB_SCRIPT_LIMBU, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + + SCRIPT( orya, ORYA, + "Oriya", + HB_SCRIPT_ORIYA, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + + SCRIPT( sylo, SYLO, + "Syloti Nagri", + HB_SCRIPT_SYLOTI_NAGRI, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + + SCRIPT( tibt, TIBT, + "Tibetan", + HB_SCRIPT_TIBETAN, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + +#endif /* AF_CONFIG_OPTION_INDIC */ + +#ifdef AF_CONFIG_OPTION_CJK + + SCRIPT( hani, HANI, + "CJKV ideographs", + HB_SCRIPT_HAN, + HINTING_BOTTOM_TO_TOP, + "\xE7\x94\xB0 \xE5\x9B\x97" ) /* ç”° å›— */ + +#endif /* AF_CONFIG_OPTION_CJK */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afshaper.c b/vendor/freetype/src/autofit/afshaper.c new file mode 100644 index 0000000..abc6f1d --- /dev/null +++ b/vendor/freetype/src/autofit/afshaper.c @@ -0,0 +1,690 @@ +/**************************************************************************** + * + * afshaper.c + * + * HarfBuzz interface for accessing OpenType features (body). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include "afglobal.h" +#include "aftypes.h" +#include "afshaper.h" + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afshaper + + + /* + * We use `sets' (in the HarfBuzz sense, which comes quite near to the + * usual mathematical meaning) to manage both lookups and glyph indices. + * + * 1. For each coverage, collect lookup IDs in a set. Note that an + * auto-hinter `coverage' is represented by one `feature', and a + * feature consists of an arbitrary number of (font specific) `lookup's + * that actually do the mapping job. Please check the OpenType + * specification for more details on features and lookups. + * + * 2. Create glyph ID sets from the corresponding lookup sets. + * + * 3. The glyph set corresponding to AF_COVERAGE_DEFAULT is computed + * with all lookups specific to the OpenType script activated. It + * relies on the order of AF_DEFINE_STYLE_CLASS entries so that + * special coverages (like `oldstyle figures') don't get overwritten. + * + */ + + + /* load coverage tags */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + static const hb_tag_t name ## _coverage[] = \ + { \ + HB_TAG( tag1, tag2, tag3, tag4 ), \ + HB_TAG_NONE \ + }; + + +#include "afcover.h" + + + /* define mapping between coverage tags and AF_Coverage */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + name ## _coverage, + + + static const hb_tag_t* coverages[] = + { +#include "afcover.h" + + NULL /* AF_COVERAGE_DEFAULT */ + }; + + + /* load HarfBuzz script tags */ +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) h, + + + static const hb_script_t scripts[] = + { +#include "afscript.h" + }; + + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) + { + hb_face_t* face; + + hb_set_t* gsub_lookups = NULL; /* GSUB lookups for a given script */ + hb_set_t* gsub_glyphs = NULL; /* glyphs covered by GSUB lookups */ + hb_set_t* gpos_lookups = NULL; /* GPOS lookups for a given script */ + hb_set_t* gpos_glyphs = NULL; /* glyphs covered by GPOS lookups */ + + hb_script_t script; + const hb_tag_t* coverage_tags; + hb_tag_t script_tags[] = { HB_TAG_NONE, + HB_TAG_NONE, + HB_TAG_NONE, + HB_TAG_NONE }; + + hb_codepoint_t idx; +#ifdef FT_DEBUG_LEVEL_TRACE + int count; +#endif + + + if ( !globals || !style_class || !gstyles ) + return FT_THROW( Invalid_Argument ); + + face = hb_font_get_face( globals->hb_font ); + + coverage_tags = coverages[style_class->coverage]; + script = scripts[style_class->script]; + + /* Convert a HarfBuzz script tag into the corresponding OpenType */ + /* tag or tags -- some Indic scripts like Devanagari have an old */ + /* and a new set of features. */ + { + unsigned int tags_count = 3; + hb_tag_t tags[3]; + + + hb_ot_tags_from_script_and_language( script, + HB_LANGUAGE_INVALID, + &tags_count, + tags, + NULL, + NULL ); + script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE; + script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE; + script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE; + } + + /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */ + /* HB_TAG_NONE except for the default script. */ + if ( default_script ) + { + if ( script_tags[0] == HB_TAG_NONE ) + script_tags[0] = HB_OT_TAG_DEFAULT_SCRIPT; + else + { + if ( script_tags[1] == HB_TAG_NONE ) + script_tags[1] = HB_OT_TAG_DEFAULT_SCRIPT; + else if ( script_tags[1] != HB_OT_TAG_DEFAULT_SCRIPT ) + script_tags[2] = HB_OT_TAG_DEFAULT_SCRIPT; + } + } + else + { + /* we use non-standard tags like `khms' for special purposes; */ + /* HarfBuzz maps them to `DFLT', which we don't want to handle here */ + if ( script_tags[0] == HB_OT_TAG_DEFAULT_SCRIPT ) + goto Exit; + } + + gsub_lookups = hb_set_create(); + hb_ot_layout_collect_lookups( face, + HB_OT_TAG_GSUB, + script_tags, + NULL, + coverage_tags, + gsub_lookups ); + + if ( hb_set_is_empty( gsub_lookups ) ) + goto Exit; /* nothing to do */ + + FT_TRACE4(( "GSUB lookups (style `%s'):\n", + af_style_names[style_class->style] )); + FT_TRACE4(( " " )); + +#ifdef FT_DEBUG_LEVEL_TRACE + count = 0; +#endif + + gsub_glyphs = hb_set_create(); + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " %d", idx )); + count++; +#endif + + /* get output coverage of GSUB feature */ + hb_ot_layout_lookup_collect_glyphs( face, + HB_OT_TAG_GSUB, + idx, + NULL, + NULL, + NULL, + gsub_glyphs ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE4(( " (none)" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); +#endif + + FT_TRACE4(( "GPOS lookups (style `%s'):\n", + af_style_names[style_class->style] )); + FT_TRACE4(( " " )); + + gpos_lookups = hb_set_create(); + hb_ot_layout_collect_lookups( face, + HB_OT_TAG_GPOS, + script_tags, + NULL, + coverage_tags, + gpos_lookups ); + +#ifdef FT_DEBUG_LEVEL_TRACE + count = 0; +#endif + + gpos_glyphs = hb_set_create(); + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " %d", idx )); + count++; +#endif + + /* get input coverage of GPOS feature */ + hb_ot_layout_lookup_collect_glyphs( face, + HB_OT_TAG_GPOS, + idx, + NULL, + gpos_glyphs, + NULL, + NULL ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE4(( " (none)" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); +#endif + + /* + * We now check whether we can construct blue zones, using glyphs + * covered by the feature only. In case there is not a single zone + * (that is, not a single character is covered), we skip this coverage. + * + */ + if ( style_class->coverage != AF_COVERAGE_DEFAULT ) + { + AF_Blue_Stringset bss = style_class->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + + FT_Bool found = 0; + + + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) + { + const char* p = &af_blue_strings[bs->string]; + + + while ( *p ) + { + hb_codepoint_t ch; + + + GET_UTF8_CHAR( ch, p ); + + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, + &idx ); ) + { + hb_codepoint_t gidx = FT_Get_Char_Index( globals->face, ch ); + + + if ( hb_ot_layout_lookup_would_substitute( face, idx, + &gidx, 1, 1 ) ) + { + found = 1; + break; + } + } + } + } + + if ( !found ) + { + FT_TRACE4(( " no blue characters found; style skipped\n" )); + goto Exit; + } + } + + /* + * Various OpenType features might use the same glyphs at different + * vertical positions; for example, superscript and subscript glyphs + * could be the same. However, the auto-hinter is completely + * agnostic of OpenType features after the feature analysis has been + * completed: The engine then simply receives a glyph index and returns a + * hinted and usually rendered glyph. + * + * Consider the superscript feature of font `pala.ttf': Some of the + * glyphs are `real', that is, they have a zero vertical offset, but + * most of them are small caps glyphs shifted up to the superscript + * position (that is, the `sups' feature is present in both the GSUB and + * GPOS tables). The code for blue zones computation actually uses a + * feature's y offset so that the `real' glyphs get correct hints. But + * later on it is impossible to decide whether a glyph index belongs to, + * say, the small caps or superscript feature. + * + * For this reason, we don't assign a style to a glyph if the current + * feature covers the glyph in both the GSUB and the GPOS tables. This + * is quite a broad condition, assuming that + * + * (a) glyphs that get used in multiple features are present in a + * feature without vertical shift, + * + * and + * + * (b) a feature's GPOS data really moves the glyph vertically. + * + * Not fulfilling condition (a) makes a font larger; it would also + * reduce the number of glyphs that could be addressed directly without + * using OpenType features, so this assumption is rather strong. + * + * Condition (b) is much weaker, and there might be glyphs which get + * missed. However, the OpenType features we are going to handle are + * primarily located in GSUB, and HarfBuzz doesn't provide an API to + * directly get the necessary information from the GPOS table. A + * possible solution might be to directly parse the GPOS table to find + * out whether a glyph gets shifted vertically, but this is something I + * would like to avoid if not really necessary. + * + * Note that we don't follow this logic for the default coverage. + * Complex scripts like Devanagari have mandatory GPOS features to + * position many glyph elements, using mark-to-base or mark-to-ligature + * tables; the number of glyphs missed due to condition (b) would be far + * too large. + * + */ + if ( style_class->coverage != AF_COVERAGE_DEFAULT ) + hb_set_subtract( gsub_glyphs, gpos_glyphs ); + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " glyphs without GPOS data (`*' means already assigned)" )); + count = 0; +#endif + + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( count % 10 ) ) + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " " )); + } + + FT_TRACE4(( " %d", idx )); + count++; +#endif + + /* glyph indices returned by `hb_ot_layout_lookup_collect_glyphs' */ + /* can be arbitrary: some fonts use fake indices for processing */ + /* internal to GSUB or GPOS, which is fully valid */ + if ( idx >= (hb_codepoint_t)globals->glyph_count ) + continue; + + if ( gstyles[idx] == AF_STYLE_UNASSIGNED ) + gstyles[idx] = (FT_UShort)style_class->style; +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE4(( "*" )); +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " (none)" )); + } + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); +#endif + + Exit: + hb_set_destroy( gsub_lookups ); + hb_set_destroy( gsub_glyphs ); + hb_set_destroy( gpos_lookups ); + hb_set_destroy( gpos_glyphs ); + + return FT_Err_Ok; + } + + + /* construct HarfBuzz features */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + static const hb_feature_t name ## _feature[] = \ + { \ + { \ + HB_TAG( tag1, tag2, tag3, tag4 ), \ + 1, 0, (unsigned int)-1 \ + } \ + }; + + +#include "afcover.h" + + + /* define mapping between HarfBuzz features and AF_Coverage */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + name ## _feature, + + + static const hb_feature_t* features[] = + { +#include "afcover.h" + + NULL /* AF_COVERAGE_DEFAULT */ + }; + + + void* + af_shaper_buf_create( FT_Face face ) + { + FT_UNUSED( face ); + + return (void*)hb_buffer_create(); + } + + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ) + { + FT_UNUSED( face ); + + hb_buffer_destroy( (hb_buffer_t*)buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { + AF_StyleClass style_class; + const hb_feature_t* feature; + FT_Int upem; + const char* q; + int len; + + hb_buffer_t* buf = (hb_buffer_t*)buf_; + hb_font_t* font; + hb_codepoint_t dummy; + + + upem = (FT_Int)metrics->globals->face->units_per_EM; + style_class = metrics->style_class; + feature = features[style_class->coverage]; + + font = metrics->globals->hb_font; + + /* we shape at a size of units per EM; this means font units */ + hb_font_set_scale( font, upem, upem ); + + while ( *p == ' ' ) + p++; + + /* count bytes up to next space (or end of buffer) */ + q = p; + while ( !( *q == ' ' || *q == '\0' ) ) + GET_UTF8_CHAR( dummy, q ); + len = (int)( q - p ); + + /* feed character(s) to the HarfBuzz buffer */ + hb_buffer_clear_contents( buf ); + hb_buffer_add_utf8( buf, p, len, 0, len ); + + /* we let HarfBuzz guess the script and writing direction */ + hb_buffer_guess_segment_properties( buf ); + + /* shape buffer, which means conversion from character codes to */ + /* glyph indices, possibly applying a feature */ + hb_shape( font, buf, feature, feature ? 1 : 0 ); + + if ( feature ) + { + hb_buffer_t* hb_buf = metrics->globals->hb_buf; + + unsigned int gcount; + hb_glyph_info_t* ginfo; + + unsigned int hb_gcount; + hb_glyph_info_t* hb_ginfo; + + + /* we have to check whether applying a feature does actually change */ + /* glyph indices; otherwise the affected glyph or glyphs aren't */ + /* available at all in the feature */ + + hb_buffer_clear_contents( hb_buf ); + hb_buffer_add_utf8( hb_buf, p, len, 0, len ); + hb_buffer_guess_segment_properties( hb_buf ); + hb_shape( font, hb_buf, NULL, 0 ); + + ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); + hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount ); + + if ( gcount == hb_gcount ) + { + unsigned int i; + + + for (i = 0; i < gcount; i++ ) + if ( ginfo[i].codepoint != hb_ginfo[i].codepoint ) + break; + + if ( i == gcount ) + { + /* both buffers have identical glyph indices */ + hb_buffer_clear_contents( buf ); + } + } + } + + *count = hb_buffer_get_length( buf ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( feature && *count > 1 ) + FT_TRACE1(( "af_shaper_get_cluster:" + " input character mapped to multiple glyphs\n" )); +#endif + + return q; + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { + hb_buffer_t* buf = (hb_buffer_t*)buf_; + hb_glyph_info_t* ginfo; + hb_glyph_position_t* gpos; + unsigned int gcount; + + FT_UNUSED( metrics ); + + + ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); + gpos = hb_buffer_get_glyph_positions( buf, &gcount ); + + if ( idx >= gcount ) + return 0; + + if ( advance ) + *advance = gpos[idx].x_advance; + if ( y_offset ) + *y_offset = gpos[idx].y_offset; + + return ginfo[idx].codepoint; + } + + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) + { + FT_UNUSED( globals ); + FT_UNUSED( style_class ); + FT_UNUSED( gstyles ); + FT_UNUSED( default_script ); + + return FT_Err_Ok; + } + + + void* + af_shaper_buf_create( FT_Face face ) + { + FT_UNUSED( face ); + + return NULL; + } + + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ) + { + FT_UNUSED( face ); + FT_UNUSED( buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { + FT_Face face = metrics->globals->face; + FT_ULong ch, dummy = 0; + FT_ULong* buf = (FT_ULong*)buf_; + + + while ( *p == ' ' ) + p++; + + GET_UTF8_CHAR( ch, p ); + + /* since we don't have an engine to handle clusters, */ + /* we scan the characters but return zero */ + while ( !( *p == ' ' || *p == '\0' ) ) + GET_UTF8_CHAR( dummy, p ); + + if ( dummy ) + { + *buf = 0; + *count = 0; + } + else + { + *buf = FT_Get_Char_Index( face, ch ); + *count = 1; + } + + return p; + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { + FT_Face face = metrics->globals->face; + FT_ULong glyph_index = *(FT_ULong*)buf_; + + FT_UNUSED( idx ); + + + if ( advance ) + FT_Get_Advance( face, + glyph_index, + FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_TRANSFORM, + advance ); + + if ( y_offset ) + *y_offset = 0; + + return glyph_index; + } + + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afshaper.h b/vendor/freetype/src/autofit/afshaper.h new file mode 100644 index 0000000..054a18f --- /dev/null +++ b/vendor/freetype/src/autofit/afshaper.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * + * afshaper.h + * + * HarfBuzz interface for accessing OpenType features (specification). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFSHAPER_H_ +#define AFSHAPER_H_ + + +#include + + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +#include +#include +#include "ft-hb.h" + +#endif + + +FT_BEGIN_HEADER + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ); + + + void* + af_shaper_buf_create( FT_Face face ); + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ); + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ); + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* x_advance, + FT_Long* y_offset ); + + /* */ + +FT_END_HEADER + +#endif /* AFSHAPER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afstyles.h b/vendor/freetype/src/autofit/afstyles.h new file mode 100644 index 0000000..73ebef0 --- /dev/null +++ b/vendor/freetype/src/autofit/afstyles.h @@ -0,0 +1,487 @@ +/**************************************************************************** + * + * afstyles.h + * + * Auto-fitter styles (specification only). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* The following part can be included multiple times. */ + /* Define `STYLE' as needed. */ + + + /* Add new styles here. The first and second arguments are the */ + /* style name in lowercase and uppercase, respectively, followed */ + /* by a description string. The next arguments are the */ + /* corresponding writing system, script, blue stringset, and */ + /* coverage. */ + /* */ + /* Note that styles using `AF_COVERAGE_DEFAULT' should always */ + /* come after styles with other coverages. Also note that */ + /* fallback scripts only use `AF_COVERAGE_DEFAULT' for its */ + /* style. */ + /* */ + /* Example: */ + /* */ + /* STYLE( cyrl_dflt, CYRL_DFLT, */ + /* "Cyrillic default style", */ + /* AF_WRITING_SYSTEM_LATIN, */ + /* AF_SCRIPT_CYRL, */ + /* AF_BLUE_STRINGSET_CYRL, */ + /* AF_COVERAGE_DEFAULT ) */ + +#undef STYLE_LATIN +#define STYLE_LATIN( s, S, f, F, ds, df, C ) \ + STYLE( s ## _ ## f, S ## _ ## F, \ + ds " " df " style", \ + AF_WRITING_SYSTEM_LATIN, \ + AF_SCRIPT_ ## S, \ + AF_BLUE_STRINGSET_ ## S, \ + AF_COVERAGE_ ## C ) + +#undef META_STYLE_LATIN +#define META_STYLE_LATIN( s, S, ds ) \ + STYLE_LATIN( s, S, c2cp, C2CP, ds, \ + "petite capitals from capitals", \ + PETITE_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, c2sc, C2SC, ds, \ + "small capitals from capitals", \ + SMALL_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, ordn, ORDN, ds, \ + "ordinals", \ + ORDINALS ) \ + STYLE_LATIN( s, S, pcap, PCAP, ds, \ + "petite capitals", \ + PETITE_CAPITALS ) \ + STYLE_LATIN( s, S, sinf, SINF, ds, \ + "scientific inferiors", \ + SCIENTIFIC_INFERIORS ) \ + STYLE_LATIN( s, S, smcp, SMCP, ds, \ + "small capitals", \ + SMALL_CAPITALS ) \ + STYLE_LATIN( s, S, subs, SUBS, ds, \ + "subscript", \ + SUBSCRIPT ) \ + STYLE_LATIN( s, S, sups, SUPS, ds, \ + "superscript", \ + SUPERSCRIPT ) \ + STYLE_LATIN( s, S, titl, TITL, ds, \ + "titling", \ + TITLING ) \ + STYLE_LATIN( s, S, dflt, DFLT, ds, \ + "default", \ + DEFAULT ) + + + STYLE( adlm_dflt, ADLM_DFLT, + "Adlam default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ADLM, + AF_BLUE_STRINGSET_ADLM, + AF_COVERAGE_DEFAULT ) + + STYLE( arab_dflt, ARAB_DFLT, + "Arabic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ARAB, + AF_BLUE_STRINGSET_ARAB, + AF_COVERAGE_DEFAULT ) + + STYLE( armn_dflt, ARMN_DFLT, + "Armenian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ARMN, + AF_BLUE_STRINGSET_ARMN, + AF_COVERAGE_DEFAULT ) + + STYLE( avst_dflt, AVST_DFLT, + "Avestan default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_AVST, + AF_BLUE_STRINGSET_AVST, + AF_COVERAGE_DEFAULT ) + + STYLE( bamu_dflt, BAMU_DFLT, + "Bamum default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_BAMU, + AF_BLUE_STRINGSET_BAMU, + AF_COVERAGE_DEFAULT ) + + STYLE( beng_dflt, BENG_DFLT, + "Bengali default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_BENG, + AF_BLUE_STRINGSET_BENG, + AF_COVERAGE_DEFAULT ) + + STYLE( buhd_dflt, BUHD_DFLT, + "Buhid default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_BUHD, + AF_BLUE_STRINGSET_BUHD, + AF_COVERAGE_DEFAULT ) + + STYLE( cakm_dflt, CAKM_DFLT, + "Chakma default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CAKM, + AF_BLUE_STRINGSET_CAKM, + AF_COVERAGE_DEFAULT ) + + STYLE( cans_dflt, CANS_DFLT, + "Canadian Syllabics default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CANS, + AF_BLUE_STRINGSET_CANS, + AF_COVERAGE_DEFAULT ) + + STYLE( cari_dflt, CARI_DFLT, + "Carian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CARI, + AF_BLUE_STRINGSET_CARI, + AF_COVERAGE_DEFAULT ) + + STYLE( cher_dflt, CHER_DFLT, + "Cherokee default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CHER, + AF_BLUE_STRINGSET_CHER, + AF_COVERAGE_DEFAULT ) + + STYLE( copt_dflt, COPT_DFLT, + "Coptic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_COPT, + AF_BLUE_STRINGSET_COPT, + AF_COVERAGE_DEFAULT ) + + STYLE( cprt_dflt, CPRT_DFLT, + "Cypriot default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CPRT, + AF_BLUE_STRINGSET_CPRT, + AF_COVERAGE_DEFAULT ) + + META_STYLE_LATIN( cyrl, CYRL, "Cyrillic" ) + + STYLE( deva_dflt, DEVA_DFLT, + "Devanagari default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_DEVA, + AF_BLUE_STRINGSET_DEVA, + AF_COVERAGE_DEFAULT ) + + STYLE( dsrt_dflt, DSRT_DFLT, + "Deseret default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_DSRT, + AF_BLUE_STRINGSET_DSRT, + AF_COVERAGE_DEFAULT ) + + STYLE( ethi_dflt, ETHI_DFLT, + "Ethiopic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ETHI, + AF_BLUE_STRINGSET_ETHI, + AF_COVERAGE_DEFAULT ) + + STYLE( geor_dflt, GEOR_DFLT, + "Georgian (Mkhedruli) default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GEOR, + AF_BLUE_STRINGSET_GEOR, + AF_COVERAGE_DEFAULT ) + + STYLE( geok_dflt, GEOK_DFLT, + "Georgian (Khutsuri) default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GEOK, + AF_BLUE_STRINGSET_GEOK, + AF_COVERAGE_DEFAULT ) + + STYLE( glag_dflt, GLAG_DFLT, + "Glagolitic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GLAG, + AF_BLUE_STRINGSET_GLAG, + AF_COVERAGE_DEFAULT ) + + STYLE( goth_dflt, GOTH_DFLT, + "Gothic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GOTH, + AF_BLUE_STRINGSET_GOTH, + AF_COVERAGE_DEFAULT ) + + META_STYLE_LATIN( grek, GREK, "Greek" ) + + STYLE( gujr_dflt, GUJR_DFLT, + "Gujarati default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GUJR, + AF_BLUE_STRINGSET_GUJR, + AF_COVERAGE_DEFAULT ) + + STYLE( guru_dflt, GURU_DFLT, + "Gurmukhi default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GURU, + AF_BLUE_STRINGSET_GURU, + AF_COVERAGE_DEFAULT ) + + STYLE( hebr_dflt, HEBR_DFLT, + "Hebrew default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_HEBR, + AF_BLUE_STRINGSET_HEBR, + AF_COVERAGE_DEFAULT ) + + STYLE( kali_dflt, KALI_DFLT, + "Kayah Li default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KALI, + AF_BLUE_STRINGSET_KALI, + AF_COVERAGE_DEFAULT ) + + STYLE( khmr_dflt, KHMR_DFLT, + "Khmer default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KHMR, + AF_BLUE_STRINGSET_KHMR, + AF_COVERAGE_DEFAULT ) + + STYLE( khms_dflt, KHMS_DFLT, + "Khmer Symbols default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KHMS, + AF_BLUE_STRINGSET_KHMS, + AF_COVERAGE_DEFAULT ) + + STYLE( knda_dflt, KNDA_DFLT, + "Kannada default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KNDA, + AF_BLUE_STRINGSET_KNDA, + AF_COVERAGE_DEFAULT ) + + STYLE( lao_dflt, LAO_DFLT, + "Lao default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LAO, + AF_BLUE_STRINGSET_LAO, + AF_COVERAGE_DEFAULT ) + + META_STYLE_LATIN( latn, LATN, "Latin" ) + + STYLE( latb_dflt, LATB_DFLT, + "Latin subscript fallback default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LATB, + AF_BLUE_STRINGSET_LATB, + AF_COVERAGE_DEFAULT ) + + STYLE( latp_dflt, LATP_DFLT, + "Latin superscript fallback default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LATP, + AF_BLUE_STRINGSET_LATP, + AF_COVERAGE_DEFAULT ) + + STYLE( lisu_dflt, LISU_DFLT, + "Lisu default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LISU, + AF_BLUE_STRINGSET_LISU, + AF_COVERAGE_DEFAULT ) + + STYLE( mlym_dflt, MLYM_DFLT, + "Malayalam default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MLYM, + AF_BLUE_STRINGSET_MLYM, + AF_COVERAGE_DEFAULT ) + + STYLE( medf_dflt, MEDF_DFLT, + "Medefaidrin default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MEDF, + AF_BLUE_STRINGSET_MEDF, + AF_COVERAGE_DEFAULT ) + + STYLE( mong_dflt, MONG_DFLT, + "Mongolian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MONG, + AF_BLUE_STRINGSET_MONG, + AF_COVERAGE_DEFAULT ) + + STYLE( mymr_dflt, MYMR_DFLT, + "Myanmar default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MYMR, + AF_BLUE_STRINGSET_MYMR, + AF_COVERAGE_DEFAULT ) + + STYLE( nkoo_dflt, NKOO_DFLT, + "N'Ko default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_NKOO, + AF_BLUE_STRINGSET_NKOO, + AF_COVERAGE_DEFAULT ) + + STYLE( none_dflt, NONE_DFLT, + "no style", + AF_WRITING_SYSTEM_DUMMY, + AF_SCRIPT_NONE, + AF_BLUE_STRINGSET_NONE, + AF_COVERAGE_DEFAULT ) + + STYLE( olck_dflt, OLCK_DFLT, + "Ol Chiki default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_OLCK, + AF_BLUE_STRINGSET_OLCK, + AF_COVERAGE_DEFAULT ) + + STYLE( orkh_dflt, ORKH_DFLT, + "Old Turkic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ORKH, + AF_BLUE_STRINGSET_ORKH, + AF_COVERAGE_DEFAULT ) + + STYLE( osge_dflt, OSGE_DFLT, + "Osage default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_OSGE, + AF_BLUE_STRINGSET_OSGE, + AF_COVERAGE_DEFAULT ) + + STYLE( osma_dflt, OSMA_DFLT, + "Osmanya default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_OSMA, + AF_BLUE_STRINGSET_OSMA, + AF_COVERAGE_DEFAULT ) + + STYLE( rohg_dflt, ROHG_DFLT, + "Hanifi Rohingya default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ROHG, + AF_BLUE_STRINGSET_ROHG, + AF_COVERAGE_DEFAULT ) + + STYLE( saur_dflt, SAUR_DFLT, + "Saurashtra default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SAUR, + AF_BLUE_STRINGSET_SAUR, + AF_COVERAGE_DEFAULT ) + + STYLE( shaw_dflt, SHAW_DFLT, + "Shavian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SHAW, + AF_BLUE_STRINGSET_SHAW, + AF_COVERAGE_DEFAULT ) + + STYLE( sinh_dflt, SINH_DFLT, + "Sinhala default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SINH, + AF_BLUE_STRINGSET_SINH, + AF_COVERAGE_DEFAULT ) + + STYLE( sund_dflt, SUND_DFLT, + "Sundanese default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SUND, + AF_BLUE_STRINGSET_SUND, + AF_COVERAGE_DEFAULT ) + + STYLE( taml_dflt, TAML_DFLT, + "Tamil default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TAML, + AF_BLUE_STRINGSET_TAML, + AF_COVERAGE_DEFAULT ) + + STYLE( tavt_dflt, TAVT_DFLT, + "Tai Viet default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TAVT, + AF_BLUE_STRINGSET_TAVT, + AF_COVERAGE_DEFAULT ) + + STYLE( telu_dflt, TELU_DFLT, + "Telugu default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TELU, + AF_BLUE_STRINGSET_TELU, + AF_COVERAGE_DEFAULT ) + + STYLE( tfng_dflt, TFNG_DFLT, + "Tifinagh default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TFNG, + AF_BLUE_STRINGSET_TFNG, + AF_COVERAGE_DEFAULT ) + + STYLE( thai_dflt, THAI_DFLT, + "Thai default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_THAI, + AF_BLUE_STRINGSET_THAI, + AF_COVERAGE_DEFAULT ) + + STYLE( vaii_dflt, VAII_DFLT, + "Vai default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_VAII, + AF_BLUE_STRINGSET_VAII, + AF_COVERAGE_DEFAULT ) + +#ifdef AF_CONFIG_OPTION_INDIC + + /* no blue stringset support for the Indic writing system yet */ +#undef STYLE_DEFAULT_INDIC +#define STYLE_DEFAULT_INDIC( s, S, d ) \ + STYLE( s ## _dflt, S ## _DFLT, \ + d " default style", \ + AF_WRITING_SYSTEM_INDIC, \ + AF_SCRIPT_ ## S, \ + (AF_Blue_Stringset)0, \ + AF_COVERAGE_DEFAULT ) + + STYLE_DEFAULT_INDIC( limb, LIMB, "Limbu" ) + STYLE_DEFAULT_INDIC( orya, ORYA, "Oriya" ) + STYLE_DEFAULT_INDIC( sylo, SYLO, "Syloti Nagri" ) + STYLE_DEFAULT_INDIC( tibt, TIBT, "Tibetan" ) + +#endif /* AF_CONFIG_OPTION_INDIC */ + +#ifdef AF_CONFIG_OPTION_CJK + + STYLE( hani_dflt, HANI_DFLT, + "CJKV ideographs default style", + AF_WRITING_SYSTEM_CJK, + AF_SCRIPT_HANI, + AF_BLUE_STRINGSET_HANI, + AF_COVERAGE_DEFAULT ) + +#endif /* AF_CONFIG_OPTION_CJK */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/aftypes.h b/vendor/freetype/src/autofit/aftypes.h new file mode 100644 index 0000000..6615194 --- /dev/null +++ b/vendor/freetype/src/autofit/aftypes.h @@ -0,0 +1,511 @@ +/**************************************************************************** + * + * aftypes.h + * + * Auto-fitter types (specification only). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************* + * + * The auto-fitter is a complete rewrite of the old auto-hinter. + * Its main feature is the ability to differentiate between different + * writing systems and scripts in order to apply specific rules. + * + * The code has also been compartmentalized into several entities that + * should make algorithmic experimentation easier than with the old + * code. + * + *************************************************************************/ + + +#ifndef AFTYPES_H_ +#define AFTYPES_H_ + + +#include +#include +#include +#include + +#include "afblue.h" + +#ifdef FT_DEBUG_AUTOFIT +#include FT_CONFIG_STANDARD_LIBRARY_H +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** D E B U G G I N G *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#ifdef FT_DEBUG_AUTOFIT + +extern int af_debug_disable_horz_hints_; +extern int af_debug_disable_vert_hints_; +extern int af_debug_disable_blue_hints_; +extern void* af_debug_hints_; + +#endif /* FT_DEBUG_AUTOFIT */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** U T I L I T Y S T U F F *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AF_WidthRec_ + { + FT_Pos org; /* original position/width in font units */ + FT_Pos cur; /* current/scaled position/width in device subpixels */ + FT_Pos fit; /* current/fitted position/width in device subpixels */ + + } AF_WidthRec, *AF_Width; + + + FT_LOCAL( void ) + af_sort_pos( FT_UInt count, + FT_Pos* table ); + + FT_LOCAL( void ) + af_sort_and_quantize_widths( FT_UInt* count, + AF_Width widths, + FT_Pos threshold ); + + + /* + * opaque handle to glyph-specific hints -- see `afhints.h' for more + * details + */ + typedef struct AF_GlyphHintsRec_* AF_GlyphHints; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S C A L E R S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * A scaler models the target pixel device that will receive the + * auto-hinted glyph image. + */ + +#define AF_SCALER_FLAG_NO_HORIZONTAL 1U /* disable horizontal hinting */ +#define AF_SCALER_FLAG_NO_VERTICAL 2U /* disable vertical hinting */ +#define AF_SCALER_FLAG_NO_ADVANCE 4U /* disable advance hinting */ + + + typedef struct AF_ScalerRec_ + { + FT_Face face; /* source font face */ + FT_Fixed x_scale; /* from font units to 1/64 device pixels */ + FT_Fixed y_scale; /* from font units to 1/64 device pixels */ + FT_Pos x_delta; /* in 1/64 device pixels */ + FT_Pos y_delta; /* in 1/64 device pixels */ + FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc. */ + FT_UInt32 flags; /* additional control flags, see above */ + + } AF_ScalerRec, *AF_Scaler; + + +#define AF_SCALER_EQUAL_SCALES( a, b ) \ + ( (a)->x_scale == (b)->x_scale && \ + (a)->y_scale == (b)->y_scale && \ + (a)->x_delta == (b)->x_delta && \ + (a)->y_delta == (b)->y_delta ) + + + typedef struct AF_StyleMetricsRec_* AF_StyleMetrics; + + /* + * This function parses an FT_Face to compute global metrics for + * a specific style. + */ + typedef FT_Error + (*AF_WritingSystem_InitMetricsFunc)( AF_StyleMetrics metrics, + FT_Face face ); + + typedef void + (*AF_WritingSystem_ScaleMetricsFunc)( AF_StyleMetrics metrics, + AF_Scaler scaler ); + + typedef void + (*AF_WritingSystem_DoneMetricsFunc)( AF_StyleMetrics metrics ); + + typedef void + (*AF_WritingSystem_GetStdWidthsFunc)( AF_StyleMetrics metrics, + FT_Pos* stdHW, + FT_Pos* stdVW ); + + + typedef FT_Error + (*AF_WritingSystem_InitHintsFunc)( AF_GlyphHints hints, + AF_StyleMetrics metrics ); + + typedef FT_Error + (*AF_WritingSystem_ApplyHintsFunc)( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** W R I T I N G S Y S T E M S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * For the auto-hinter, a writing system consists of multiple scripts that + * can be handled similarly *in a typographical way*; the relationship is + * not based on history. For example, both the Greek and the unrelated + * Armenian scripts share the same features like ascender, descender, + * x-height, etc. Essentially, a writing system is covered by a + * submodule of the auto-fitter; it contains + * + * - a specific global analyzer that computes global metrics specific to + * the script (based on script-specific characters to identify ascender + * height, x-height, etc.), + * + * - a specific glyph analyzer that computes segments and edges for each + * glyph covered by the script, + * + * - a specific grid-fitting algorithm that distorts the scaled glyph + * outline according to the results of the glyph analyzer. + */ + +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) \ + AF_WRITING_SYSTEM_ ## WS, + + /* The list of known writing systems. */ + typedef enum AF_WritingSystem_ + { + +#include "afws-iter.h" + + AF_WRITING_SYSTEM_MAX /* do not remove */ + + } AF_WritingSystem; + + + typedef struct AF_WritingSystemClassRec_ + { + AF_WritingSystem writing_system; + + FT_Offset style_metrics_size; + AF_WritingSystem_InitMetricsFunc style_metrics_init; + AF_WritingSystem_ScaleMetricsFunc style_metrics_scale; + AF_WritingSystem_DoneMetricsFunc style_metrics_done; + AF_WritingSystem_GetStdWidthsFunc style_metrics_getstdw; + + AF_WritingSystem_InitHintsFunc style_hints_init; + AF_WritingSystem_ApplyHintsFunc style_hints_apply; + + } AF_WritingSystemClassRec; + + typedef const AF_WritingSystemClassRec* AF_WritingSystemClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S C R I P T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * Each script is associated with two sets of Unicode ranges to test + * whether the font face supports the script, and which non-base + * characters the script contains. + * + * We use four-letter script tags from the OpenType specification, + * extended by `NONE', which indicates `no script'. + */ + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + AF_SCRIPT_ ## S, + + /* The list of known scripts. */ + typedef enum AF_Script_ + { + +#include "afscript.h" + + AF_SCRIPT_MAX /* do not remove */ + + } AF_Script; + + + typedef struct AF_Script_UniRangeRec_ + { + FT_UInt32 first; + FT_UInt32 last; + + } AF_Script_UniRangeRec; + +#define AF_UNIRANGE_REC( a, b ) { (FT_UInt32)(a), (FT_UInt32)(b) } + + typedef const AF_Script_UniRangeRec* AF_Script_UniRange; + + + typedef struct AF_ScriptClassRec_ + { + AF_Script script; + + /* last element in the ranges must be { 0, 0 } */ + AF_Script_UniRange script_uni_ranges; + AF_Script_UniRange script_uni_nonbase_ranges; + + FT_Bool top_to_bottom_hinting; + + const char* standard_charstring; /* for default width and height */ + + } AF_ScriptClassRec; + + typedef const AF_ScriptClassRec* AF_ScriptClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C O V E R A G E S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * Usually, a font contains more glyphs than can be addressed by its + * character map. + * + * In the PostScript font world, encoding vectors specific to a given + * task are used to select such glyphs, and these glyphs can be often + * recognized by having a suffix in its glyph names. For example, a + * superscript glyph `A' might be called `A.sup'. Unfortunately, this + * naming scheme is not standardized and thus unusable for us. + * + * In the OpenType world, a better solution was invented, namely + * `features', which cleanly separate a character's input encoding from + * the corresponding glyph's appearance, and which don't use glyph names + * at all. For our purposes, and slightly generalized, an OpenType + * feature is a name of a mapping that maps character codes to + * non-standard glyph indices (features get used for other things also). + * For example, the `sups' feature provides superscript glyphs, thus + * mapping character codes like `A' or `B' to superscript glyph + * representation forms. How this mapping happens is completely + * uninteresting to us. + * + * For the auto-hinter, a `coverage' represents all glyphs of an OpenType + * feature collected in a set (as listed below) that can be hinted + * together. To continue the above example, superscript glyphs must not + * be hinted together with normal glyphs because the blue zones + * completely differ. + * + * Note that FreeType itself doesn't compute coverages; it only provides + * the glyphs addressable by the default Unicode character map. Instead, + * we use the HarfBuzz library (if available), which has many functions + * exactly for this purpose. + * + * AF_COVERAGE_DEFAULT is special: It should cover everything that isn't + * listed separately (including the glyphs addressable by the character + * map). In case HarfBuzz isn't available, it exactly covers the glyphs + * addressable by the character map. + * + */ + +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + AF_COVERAGE_ ## NAME, + + + typedef enum AF_Coverage_ + { +#include "afcover.h" + + AF_COVERAGE_DEFAULT + + } AF_Coverage; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S T Y L E S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * The topmost structure for modelling the auto-hinter glyph input data + * is a `style class', grouping everything together. + */ + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + AF_STYLE_ ## S, + + /* The list of known styles. */ + typedef enum AF_Style_ + { + +#include "afstyles.h" + + AF_STYLE_MAX /* do not remove */ + + } AF_Style; + + + typedef struct AF_StyleClassRec_ + { + AF_Style style; + + AF_WritingSystem writing_system; + AF_Script script; + AF_Blue_Stringset blue_stringset; + AF_Coverage coverage; + + } AF_StyleClassRec; + + typedef const AF_StyleClassRec* AF_StyleClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S T Y L E M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; + + /* This is the main structure that combines everything. Autofit modules */ + /* specific to writing systems derive their structures from it, for */ + /* example `AF_LatinMetrics'. */ + + typedef struct AF_StyleMetricsRec_ + { + AF_StyleClass style_class; + AF_ScalerRec scaler; + FT_Bool digits_have_same_width; + + AF_FaceGlobals globals; /* to access properties */ + + } AF_StyleMetricsRec; + + +#define AF_HINTING_BOTTOM_TO_TOP 0 +#define AF_HINTING_TOP_TO_BOTTOM 1 + + + /* Declare and define vtables for classes */ +#define AF_DECLARE_WRITING_SYSTEM_CLASS( writing_system_class ) \ + FT_CALLBACK_TABLE const AF_WritingSystemClassRec \ + writing_system_class; + +#define AF_DEFINE_WRITING_SYSTEM_CLASS( \ + writing_system_class, \ + system, \ + m_size, \ + m_init, \ + m_scale, \ + m_done, \ + m_stdw, \ + h_init, \ + h_apply ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_WritingSystemClassRec writing_system_class = \ + { \ + system, \ + \ + m_size, \ + \ + m_init, \ + m_scale, \ + m_done, \ + m_stdw, \ + \ + h_init, \ + h_apply \ + }; + + +#define AF_DECLARE_SCRIPT_CLASS( script_class ) \ + FT_CALLBACK_TABLE const AF_ScriptClassRec \ + script_class; + +#define AF_DEFINE_SCRIPT_CLASS( \ + script_class, \ + script, \ + ranges, \ + nonbase_ranges, \ + top_to_bottom, \ + std_charstring ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_ScriptClassRec script_class = \ + { \ + script, \ + ranges, \ + nonbase_ranges, \ + top_to_bottom, \ + std_charstring, \ + }; + + +#define AF_DECLARE_STYLE_CLASS( style_class ) \ + FT_CALLBACK_TABLE const AF_StyleClassRec \ + style_class; + +#define AF_DEFINE_STYLE_CLASS( \ + style_class, \ + style, \ + writing_system, \ + script, \ + blue_stringset, \ + coverage ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_StyleClassRec style_class = \ + { \ + style, \ + writing_system, \ + script, \ + blue_stringset, \ + coverage \ + }; + +/* */ + + +FT_END_HEADER + +#endif /* AFTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afws-decl.h b/vendor/freetype/src/autofit/afws-decl.h new file mode 100644 index 0000000..48c888a --- /dev/null +++ b/vendor/freetype/src/autofit/afws-decl.h @@ -0,0 +1,33 @@ +/**************************************************************************** + * + * afws-decl.h + * + * Auto-fitter writing system declarations (specification only). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFWS_DECL_H_ +#define AFWS_DECL_H_ + + /* Since preprocessor directives can't create other preprocessor */ + /* directives, we have to include the header files manually. */ + +#include "afdummy.h" +#include "aflatin.h" +#include "afcjk.h" +#include "afindic.h" + +#endif /* AFWS_DECL_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/afws-iter.h b/vendor/freetype/src/autofit/afws-iter.h new file mode 100644 index 0000000..a0a686f --- /dev/null +++ b/vendor/freetype/src/autofit/afws-iter.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * afws-iter.h + * + * Auto-fitter writing systems iterator (specification only). + * + * Copyright (C) 2013-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /* This header may be included multiple times. */ + /* Define `WRITING_SYSTEM' as needed. */ + + + /* Add new writing systems here. The arguments are the writing system */ + /* name in lowercase and uppercase, respectively. */ + + WRITING_SYSTEM( dummy, DUMMY ) + WRITING_SYSTEM( latin, LATIN ) + WRITING_SYSTEM( cjk, CJK ) + WRITING_SYSTEM( indic, INDIC ) + + +/* END */ diff --git a/vendor/freetype/src/autofit/autofit.c b/vendor/freetype/src/autofit/autofit.c new file mode 100644 index 0000000..8bd609b --- /dev/null +++ b/vendor/freetype/src/autofit/autofit.c @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * autofit.c + * + * Auto-fitter module (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ft-hb.c" +#include "afblue.c" +#include "afcjk.c" +#include "afdummy.c" +#include "afglobal.c" +#include "afhints.c" +#include "afindic.c" +#include "aflatin.c" +#include "afloader.c" +#include "afmodule.c" +#include "afranges.c" +#include "afshaper.c" + + +/* END */ diff --git a/vendor/freetype/src/autofit/ft-hb.c b/vendor/freetype/src/autofit/ft-hb.c new file mode 100644 index 0000000..71aee04 --- /dev/null +++ b/vendor/freetype/src/autofit/ft-hb.c @@ -0,0 +1,115 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + +#include +#include + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +#include "ft-hb.h" + +/* The following three functions are a more or less verbatim + * copy of corresponding HarfBuzz code from hb-ft.cc + */ + +static hb_blob_t * +hb_ft_reference_table_ (hb_face_t *face, hb_tag_t tag, void *user_data) +{ + FT_Face ft_face = (FT_Face) user_data; + FT_Byte *buffer; + FT_ULong length = 0; + FT_Error error; + + FT_UNUSED (face); + + /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); + if (error) + return NULL; + + buffer = (FT_Byte *) ft_smalloc (length); + if (!buffer) + return NULL; + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); + if (error) + { + free (buffer); + return NULL; + } + + return hb_blob_create ((const char *) buffer, length, + HB_MEMORY_MODE_WRITABLE, + buffer, ft_sfree); +} + +static hb_face_t * +hb_ft_face_create_ (FT_Face ft_face, + hb_destroy_func_t destroy) +{ + hb_face_t *face; + + if (!ft_face->stream->read) { + hb_blob_t *blob; + + blob = hb_blob_create ((const char *) ft_face->stream->base, + (unsigned int) ft_face->stream->size, + HB_MEMORY_MODE_READONLY, + ft_face, destroy); + face = hb_face_create (blob, ft_face->face_index); + hb_blob_destroy (blob); + } else { + face = hb_face_create_for_tables (hb_ft_reference_table_, ft_face, destroy); + } + + hb_face_set_index (face, ft_face->face_index); + hb_face_set_upem (face, ft_face->units_per_EM); + + return face; +} + +FT_LOCAL_DEF(hb_font_t *) +hb_ft_font_create_ (FT_Face ft_face, + hb_destroy_func_t destroy) +{ + hb_font_t *font; + hb_face_t *face; + + face = hb_ft_face_create_ (ft_face, destroy); + font = hb_font_create (face); + hb_face_destroy (face); + return font; +} + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* ANSI C doesn't like empty source files */ +typedef int ft_hb_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* END */ diff --git a/vendor/freetype/src/autofit/ft-hb.h b/vendor/freetype/src/autofit/ft-hb.h new file mode 100644 index 0000000..92a5774 --- /dev/null +++ b/vendor/freetype/src/autofit/ft-hb.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + +#ifndef FT_HB_H +#define FT_HB_H + +#include + +#include +#include + + +FT_BEGIN_HEADER + +FT_LOCAL(hb_font_t *) +hb_ft_font_create_ (FT_Face ft_face, + hb_destroy_func_t destroy); + + +FT_END_HEADER + +#endif /* FT_HB_H */ + + +/* END */ diff --git a/vendor/freetype/src/autofit/module.mk b/vendor/freetype/src/autofit/module.mk new file mode 100644 index 0000000..95cb20a --- /dev/null +++ b/vendor/freetype/src/autofit/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 auto-fitter module definition +# + + +# Copyright (C) 2003-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += AUTOFIT_MODULE + +define AUTOFIT_MODULE +$(OPEN_DRIVER) FT_Module_Class, autofit_module_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)autofit $(ECHO_DRIVER_DESC)automatic hinting module$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/autofit/rules.mk b/vendor/freetype/src/autofit/rules.mk new file mode 100644 index 0000000..a46ba3f --- /dev/null +++ b/vendor/freetype/src/autofit/rules.mk @@ -0,0 +1,88 @@ +# +# FreeType 2 auto-fitter module configuration rules +# + + +# Copyright (C) 2003-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# AUTOF driver directory +# +AUTOF_DIR := $(SRC_DIR)/autofit + + +# compilation flags for the driver +# +AUTOF_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(AUTOF_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# AUTOF driver sources (i.e., C files) +# +AUTOF_DRV_SRC := $(AUTOF_DIR)/afblue.c \ + $(AUTOF_DIR)/afcjk.c \ + $(AUTOF_DIR)/afdummy.c \ + $(AUTOF_DIR)/afglobal.c \ + $(AUTOF_DIR)/afhints.c \ + $(AUTOF_DIR)/afindic.c \ + $(AUTOF_DIR)/aflatin.c \ + $(AUTOF_DIR)/afloader.c \ + $(AUTOF_DIR)/afmodule.c \ + $(AUTOF_DIR)/afranges.c \ + $(AUTOF_DIR)/afshaper.c \ + $(AUTOF_DIR)/ft-hb.c + +# AUTOF driver headers +# +AUTOF_DRV_H := $(AUTOF_DRV_SRC:%c=%h) \ + $(AUTOF_DIR)/afcover.h \ + $(AUTOF_DIR)/aferrors.h \ + $(AUTOF_DIR)/afscript.h \ + $(AUTOF_DIR)/afstyles.h \ + $(AUTOF_DIR)/aftypes.h \ + $(AUTOF_DIR)/afws-decl.h \ + $(AUTOF_DIR)/afws-iter.h + + +# AUTOF driver object(s) +# +# AUTOF_DRV_OBJ_M is used during `multi' builds. +# AUTOF_DRV_OBJ_S is used during `single' builds. +# +AUTOF_DRV_OBJ_M := $(AUTOF_DRV_SRC:$(AUTOF_DIR)/%.c=$(OBJ_DIR)/%.$O) +AUTOF_DRV_OBJ_S := $(OBJ_DIR)/autofit.$O + +# AUTOF driver source file for single build +# +AUTOF_DRV_SRC_S := $(AUTOF_DIR)/autofit.c + + +# AUTOF driver - single object +# +$(AUTOF_DRV_OBJ_S): $(AUTOF_DRV_SRC_S) $(AUTOF_DRV_SRC) \ + $(FREETYPE_H) $(AUTOF_DRV_H) + $(AUTOF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(AUTOF_DRV_SRC_S)) + + +# AUTOF driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(AUTOF_DIR)/%.c $(FREETYPE_H) $(AUTOF_DRV_H) + $(AUTOF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(AUTOF_DRV_OBJ_S) +DRV_OBJS_M += $(AUTOF_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/base/ftadvanc.c b/vendor/freetype/src/base/ftadvanc.c new file mode 100644 index 0000000..de25476 --- /dev/null +++ b/vendor/freetype/src/base/ftadvanc.c @@ -0,0 +1,174 @@ +/**************************************************************************** + * + * ftadvanc.c + * + * Quick computation of advance widths (body). + * + * Copyright (C) 2008-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include + + + static FT_Error + ft_face_scale_advances_( FT_Face face, + FT_Fixed* advances, + FT_UInt count, + FT_Int32 flags ) + { + FT_Fixed scale; + FT_UInt nn; + + + if ( flags & FT_LOAD_NO_SCALE ) + return FT_Err_Ok; + + if ( !face->size ) + return FT_THROW( Invalid_Size_Handle ); + + if ( flags & FT_LOAD_VERTICAL_LAYOUT ) + scale = face->size->metrics.y_scale; + else + scale = face->size->metrics.x_scale; + + /* this must be the same scaling as to get linear{Hori,Vert}Advance */ + /* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c) */ + + for ( nn = 0; nn < count; nn++ ) + advances[nn] = FT_MulDiv( advances[nn], scale, 64 ); + + return FT_Err_Ok; + } + + + /* at the moment, we can perform fast advance retrieval only in */ + /* the following cases: */ + /* */ + /* - unscaled load */ + /* - unhinted load */ + /* - light-hinted load */ + /* - if a variations font, it must have an `HVAR' or `VVAR' */ + /* table (thus the old MM or GX fonts don't qualify; this */ + /* gets checked by the driver-specific functions) */ + +#define LOAD_ADVANCE_FAST_CHECK( face, flags ) \ + ( flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) || \ + FT_LOAD_TARGET_MODE( flags ) == FT_RENDER_MODE_LIGHT ) + + + /* documentation is in ftadvanc.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Advance( FT_Face face, + FT_UInt gindex, + FT_Int32 flags, + FT_Fixed *padvance ) + { + FT_Face_GetAdvancesFunc func; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !padvance ) + return FT_THROW( Invalid_Argument ); + + if ( gindex >= (FT_UInt)face->num_glyphs ) + return FT_THROW( Invalid_Glyph_Index ); + + func = face->driver->clazz->get_advances; + if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) ) + { + FT_Error error; + + + error = func( face, gindex, 1, flags, padvance ); + if ( !error ) + return ft_face_scale_advances_( face, padvance, 1, flags ); + + if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) + return error; + } + + return FT_Get_Advances( face, gindex, 1, flags, padvance ); + } + + + /* documentation is in ftadvanc.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed *padvances ) + { + FT_Error error = FT_Err_Ok; + + FT_Face_GetAdvancesFunc func; + + FT_UInt num, end, nn; + FT_Int factor; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !padvances ) + return FT_THROW( Invalid_Argument ); + + num = (FT_UInt)face->num_glyphs; + end = start + count; + if ( start >= num || end < start || end > num ) + return FT_THROW( Invalid_Glyph_Index ); + + if ( count == 0 ) + return FT_Err_Ok; + + func = face->driver->clazz->get_advances; + if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) ) + { + error = func( face, start, count, flags, padvances ); + if ( !error ) + return ft_face_scale_advances_( face, padvances, count, flags ); + + if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) + return error; + } + + error = FT_Err_Ok; + + if ( flags & FT_ADVANCE_FLAG_FAST_ONLY ) + return FT_THROW( Unimplemented_Feature ); + + flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; + factor = ( flags & FT_LOAD_NO_SCALE ) ? 1 : 1024; + for ( nn = 0; nn < count; nn++ ) + { + error = FT_Load_Glyph( face, start + nn, flags ); + if ( error ) + break; + + /* scale from 26.6 to 16.16, unless NO_SCALE was requested */ + padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) + ? face->glyph->advance.y * factor + : face->glyph->advance.x * factor; + } + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftbase.c b/vendor/freetype/src/base/ftbase.c new file mode 100644 index 0000000..156510f --- /dev/null +++ b/vendor/freetype/src/base/ftbase.c @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * ftbase.c + * + * Single object library component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftadvanc.c" +#include "ftcalc.c" +#include "ftcolor.c" +#include "ftdbgmem.c" +#include "fterrors.c" +#include "ftfntfmt.c" +#include "ftgloadr.c" +#include "fthash.c" +#include "ftlcdfil.c" +#include "ftmac.c" +#include "ftobjs.c" +#include "ftoutln.c" +#include "ftpsprop.c" +#include "ftrfork.c" +#include "ftsnames.c" +#include "ftstream.c" +#include "fttrigon.c" +#include "ftutil.c" + + +/* END */ diff --git a/vendor/freetype/src/base/ftbase.h b/vendor/freetype/src/base/ftbase.h new file mode 100644 index 0000000..00790d3 --- /dev/null +++ b/vendor/freetype/src/base/ftbase.h @@ -0,0 +1,82 @@ +/**************************************************************************** + * + * ftbase.h + * + * Private functions used in the `base' module (specification). + * + * Copyright (C) 2008-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBASE_H_ +#define FTBASE_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_GLYPH( ft_bitmap_glyph_class ) + FT_DECLARE_GLYPH( ft_outline_glyph_class ) + FT_DECLARE_GLYPH( ft_svg_glyph_class ) + + +#ifdef FT_CONFIG_OPTION_MAC_FONTS + + /* MacOS resource fork cannot exceed 16MB at least for Carbon code; */ + /* see https://support.microsoft.com/en-us/kb/130437 */ +#define FT_MAC_RFORK_MAX_LEN 0x00FFFFFFUL + + + /* Assume the stream is sfnt-wrapped PS Type1 or sfnt-wrapped CID-keyed */ + /* font, and try to load a face specified by the face_index. */ + FT_LOCAL( FT_Error ) + open_face_PS_from_sfnt_stream( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter *params, + FT_Face *aface ); + + + /* Create a new FT_Face given a buffer and a driver name. */ + /* From ftmac.c. */ + FT_LOCAL( FT_Error ) + open_face_from_buffer( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Long face_index, + const char* driver_name, + FT_Face *aface ); + + +#if defined( FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK ) && \ + !defined( FT_MACINTOSH ) + /* Mac OS X/Darwin kernel often changes recommended method to access */ + /* the resource fork and older methods makes the kernel issue the */ + /* warning of deprecated method. To calm it down, the methods based */ + /* on Darwin VFS should be grouped and skip the rest methods after */ + /* the case the resource is opened but found to lack a font in it. */ + FT_LOCAL( FT_Bool ) + ft_raccess_rule_by_darwin_vfs( FT_Library library, FT_UInt rule_index ); +#endif + +#endif /* FT_CONFIG_OPTION_MAC_FONTS */ + + +FT_END_HEADER + +#endif /* FTBASE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/base/ftbbox.c b/vendor/freetype/src/base/ftbbox.c new file mode 100644 index 0000000..385fea4 --- /dev/null +++ b/vendor/freetype/src/base/ftbbox.c @@ -0,0 +1,542 @@ +/**************************************************************************** + * + * ftbbox.c + * + * FreeType bbox computation (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component has a _single_ role: to compute exact outline bounding + * boxes. + * + */ + + +#include + +#include +#include +#include +#include +#include + + + typedef struct TBBox_Rec_ + { + FT_Vector last; + FT_BBox bbox; + + } TBBox_Rec; + + +#define FT_UPDATE_BBOX( p, bbox ) \ + FT_BEGIN_STMNT \ + if ( p->x < bbox.xMin ) \ + bbox.xMin = p->x; \ + if ( p->x > bbox.xMax ) \ + bbox.xMax = p->x; \ + if ( p->y < bbox.yMin ) \ + bbox.yMin = p->y; \ + if ( p->y > bbox.yMax ) \ + bbox.yMax = p->y; \ + FT_END_STMNT + +#define CHECK_X( p, bbox ) \ + ( p->x < bbox.xMin || p->x > bbox.xMax ) + +#define CHECK_Y( p, bbox ) \ + ( p->y < bbox.yMin || p->y > bbox.yMax ) + + + /************************************************************************** + * + * @Function: + * BBox_Move_To + * + * @Description: + * This function is used as a `move_to' emitter during + * FT_Outline_Decompose(). It simply records the destination point + * in `user->last'. We also update bbox in case contour starts with + * an implicit `on' point. + * + * @Input: + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * A pointer to the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + */ + FT_CALLBACK_DEF( int ) + BBox_Move_To( const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + FT_UPDATE_BBOX( to, user->bbox ); + + user->last = *to; + + return 0; + } + + + /************************************************************************** + * + * @Function: + * BBox_Line_To + * + * @Description: + * This function is used as a `line_to' emitter during + * FT_Outline_Decompose(). It simply records the destination point + * in `user->last'; no further computations are necessary because + * bbox already contains both explicit ends of the line segment. + * + * @Input: + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * A pointer to the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + */ + FT_CALLBACK_DEF( int ) + BBox_Line_To( const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + user->last = *to; + + return 0; + } + + + /************************************************************************** + * + * @Function: + * BBox_Conic_Check + * + * @Description: + * Find the extrema of a 1-dimensional conic Bezier curve and update + * a bounding range. This version uses direct computation, as it + * doesn't need square roots. + * + * @Input: + * y1 :: + * The start coordinate. + * + * y2 :: + * The coordinate of the control point. + * + * y3 :: + * The end coordinate. + * + * @InOut: + * min :: + * The address of the current minimum. + * + * max :: + * The address of the current maximum. + */ + static void + BBox_Conic_Check( FT_Pos y1, + FT_Pos y2, + FT_Pos y3, + FT_Pos* min, + FT_Pos* max ) + { + /* This function is only called when a control off-point is outside */ + /* the bbox that contains all on-points. It finds a local extremum */ + /* within the segment, equal to (y1*y3 - y2*y2)/(y1 - 2*y2 + y3). */ + /* Or, offsetting from y2, we get */ + + y1 -= y2; + y3 -= y2; + y2 += FT_MulDiv( y1, y3, y1 + y3 ); + + if ( y2 < *min ) + *min = y2; + if ( y2 > *max ) + *max = y2; + } + + + /************************************************************************** + * + * @Function: + * BBox_Conic_To + * + * @Description: + * This function is used as a `conic_to' emitter during + * FT_Outline_Decompose(). It checks a conic Bezier curve with the + * current bounding box, and computes its extrema if necessary to + * update it. + * + * @Input: + * control :: + * A pointer to a control point. + * + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * The address of the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + * + * @Note: + * In the case of a non-monotonous arc, we compute directly the + * extremum coordinates, as it is sufficiently fast. + */ + FT_CALLBACK_DEF( int ) + BBox_Conic_To( const FT_Vector* control, + const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + /* in case `to' is implicit and not included in bbox yet */ + FT_UPDATE_BBOX( to, user->bbox ); + + if ( CHECK_X( control, user->bbox ) ) + BBox_Conic_Check( user->last.x, + control->x, + to->x, + &user->bbox.xMin, + &user->bbox.xMax ); + + if ( CHECK_Y( control, user->bbox ) ) + BBox_Conic_Check( user->last.y, + control->y, + to->y, + &user->bbox.yMin, + &user->bbox.yMax ); + + user->last = *to; + + return 0; + } + + + /************************************************************************** + * + * @Function: + * BBox_Cubic_Check + * + * @Description: + * Find the extrema of a 1-dimensional cubic Bezier curve and + * update a bounding range. This version uses iterative splitting + * because it is faster than the exact solution with square roots. + * + * @Input: + * p1 :: + * The start coordinate. + * + * p2 :: + * The coordinate of the first control point. + * + * p3 :: + * The coordinate of the second control point. + * + * p4 :: + * The end coordinate. + * + * @InOut: + * min :: + * The address of the current minimum. + * + * max :: + * The address of the current maximum. + */ + static FT_Pos + cubic_peak( FT_Pos q1, + FT_Pos q2, + FT_Pos q3, + FT_Pos q4 ) + { + FT_Pos peak = 0; + FT_Int shift; + + + /* This function finds a peak of a cubic segment if it is above 0 */ + /* using iterative bisection of the segment, or returns 0. */ + /* The fixed-point arithmetic of bisection is inherently stable */ + /* but may loose accuracy in the two lowest bits. To compensate, */ + /* we upscale the segment if there is room. Large values may need */ + /* to be downscaled to avoid overflows during bisection. */ + /* It is called with either q2 or q3 positive, which is necessary */ + /* for the peak to exist and avoids undefined FT_MSB. */ + + shift = 27 - FT_MSB( (FT_UInt32)( FT_ABS( q1 ) | + FT_ABS( q2 ) | + FT_ABS( q3 ) | + FT_ABS( q4 ) ) ); + + if ( shift > 0 ) + { + /* upscaling too much just wastes time */ + if ( shift > 2 ) + shift = 2; + + q1 *= 1 << shift; + q2 *= 1 << shift; + q3 *= 1 << shift; + q4 *= 1 << shift; + } + else + { + q1 >>= -shift; + q2 >>= -shift; + q3 >>= -shift; + q4 >>= -shift; + } + + /* for a peak to exist above 0, the cubic segment must have */ + /* at least one of its control off-points above 0. */ + while ( q2 > 0 || q3 > 0 ) + { + /* determine which half contains the maximum and split */ + if ( q1 + q2 > q3 + q4 ) /* first half */ + { + q4 = q4 + q3; + q3 = q3 + q2; + q2 = q2 + q1; + q4 = q4 + q3; + q3 = q3 + q2; + q4 = ( q4 + q3 ) >> 3; + q3 = q3 >> 2; + q2 = q2 >> 1; + } + else /* second half */ + { + q1 = q1 + q2; + q2 = q2 + q3; + q3 = q3 + q4; + q1 = q1 + q2; + q2 = q2 + q3; + q1 = ( q1 + q2 ) >> 3; + q2 = q2 >> 2; + q3 = q3 >> 1; + } + + /* check whether either end reached the maximum */ + if ( q1 == q2 && q1 >= q3 ) + { + peak = q1; + break; + } + if ( q3 == q4 && q2 <= q4 ) + { + peak = q4; + break; + } + } + + if ( shift > 0 ) + peak >>= shift; + else + peak <<= -shift; + + return peak; + } + + + static void + BBox_Cubic_Check( FT_Pos p1, + FT_Pos p2, + FT_Pos p3, + FT_Pos p4, + FT_Pos* min, + FT_Pos* max ) + { + /* This function is only called when a control off-point is outside */ + /* the bbox that contains all on-points. So at least one of the */ + /* conditions below holds and cubic_peak is called with at least one */ + /* non-zero argument. */ + + if ( p2 > *max || p3 > *max ) + *max += cubic_peak( p1 - *max, p2 - *max, p3 - *max, p4 - *max ); + + /* now flip the signs to update the minimum */ + if ( p2 < *min || p3 < *min ) + *min -= cubic_peak( *min - p1, *min - p2, *min - p3, *min - p4 ); + } + + + /************************************************************************** + * + * @Function: + * BBox_Cubic_To + * + * @Description: + * This function is used as a `cubic_to' emitter during + * FT_Outline_Decompose(). It checks a cubic Bezier curve with the + * current bounding box, and computes its extrema if necessary to + * update it. + * + * @Input: + * control1 :: + * A pointer to the first control point. + * + * control2 :: + * A pointer to the second control point. + * + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * The address of the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + * + * @Note: + * In the case of a non-monotonous arc, we don't compute directly + * extremum coordinates, we subdivide instead. + */ + FT_CALLBACK_DEF( int ) + BBox_Cubic_To( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + /* We don't need to check `to' since it is always an on-point, */ + /* thus within the bbox. Only segments with an off-point outside */ + /* the bbox can possibly reach new extreme values. */ + + if ( CHECK_X( control1, user->bbox ) || + CHECK_X( control2, user->bbox ) ) + BBox_Cubic_Check( user->last.x, + control1->x, + control2->x, + to->x, + &user->bbox.xMin, + &user->bbox.xMax ); + + if ( CHECK_Y( control1, user->bbox ) || + CHECK_Y( control2, user->bbox ) ) + BBox_Cubic_Check( user->last.y, + control1->y, + control2->y, + to->y, + &user->bbox.yMin, + &user->bbox.yMax ); + + user->last = *to; + + return 0; + } + + + FT_DEFINE_OUTLINE_FUNCS( + bbox_interface, + + (FT_Outline_MoveTo_Func) BBox_Move_To, /* move_to */ + (FT_Outline_LineTo_Func) BBox_Line_To, /* line_to */ + (FT_Outline_ConicTo_Func)BBox_Conic_To, /* conic_to */ + (FT_Outline_CubicTo_Func)BBox_Cubic_To, /* cubic_to */ + 0, /* shift */ + 0 /* delta */ + ) + + + /* documentation is in ftbbox.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ) + { + FT_BBox cbox = { 0x7FFFFFFFL, 0x7FFFFFFFL, + -0x7FFFFFFFL, -0x7FFFFFFFL }; + FT_BBox bbox = { 0x7FFFFFFFL, 0x7FFFFFFFL, + -0x7FFFFFFFL, -0x7FFFFFFFL }; + FT_Vector* vec; + FT_UShort n; + + + if ( !abbox ) + return FT_THROW( Invalid_Argument ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + /* if outline is empty, return (0,0,0,0) */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + { + abbox->xMin = abbox->xMax = 0; + abbox->yMin = abbox->yMax = 0; + + return 0; + } + + /* We compute the control box as well as the bounding box of */ + /* all `on' points in the outline. Then, if the two boxes */ + /* coincide, we exit immediately. */ + + vec = outline->points; + + for ( n = 0; n < outline->n_points; n++ ) + { + FT_UPDATE_BBOX( vec, cbox ); + + if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON ) + FT_UPDATE_BBOX( vec, bbox ); + + vec++; + } + + /* test two boxes for equality */ + if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax || + cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax ) + { + /* the two boxes are different, now walk over the outline to */ + /* get the Bezier arc extrema. */ + + FT_Error error; + TBBox_Rec user; + + + user.bbox = bbox; + + error = FT_Outline_Decompose( outline, &bbox_interface, &user ); + if ( error ) + return error; + + *abbox = user.bbox; + } + else + *abbox = bbox; + + return FT_Err_Ok; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftbdf.c b/vendor/freetype/src/base/ftbdf.c new file mode 100644 index 0000000..f697c00 --- /dev/null +++ b/vendor/freetype/src/base/ftbdf.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * ftbdf.c + * + * FreeType API for accessing BDF-specific strings (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include + + + /* documentation is in ftbdf.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + FT_Error error; + const char* encoding = NULL; + const char* registry = NULL; + + FT_Service_BDF service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + FT_FACE_FIND_SERVICE( face, service, BDF ); + + if ( service && service->get_charset_id ) + error = service->get_charset_id( face, &encoding, ®istry ); + else + error = FT_THROW( Invalid_Argument ); + + if ( acharset_encoding ) + *acharset_encoding = encoding; + + if ( acharset_registry ) + *acharset_registry = registry; + + return error; + } + + + /* documentation is in ftbdf.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + FT_Error error; + + FT_Service_BDF service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !aproperty ) + return FT_THROW( Invalid_Argument ); + + aproperty->type = BDF_PROPERTY_TYPE_NONE; + + FT_FACE_FIND_SERVICE( face, service, BDF ); + + if ( service && service->get_property ) + error = service->get_property( face, prop_name, aproperty ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftbitmap.c b/vendor/freetype/src/base/ftbitmap.c new file mode 100644 index 0000000..1c93648 --- /dev/null +++ b/vendor/freetype/src/base/ftbitmap.c @@ -0,0 +1,1144 @@ +/**************************************************************************** + * + * ftbitmap.c + * + * FreeType utility functions for bitmaps (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bitmap + + + static + const FT_Bitmap null_bitmap = { 0, 0, 0, NULL, 0, 0, 0, NULL }; + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( void ) + FT_Bitmap_Init( FT_Bitmap *abitmap ) + { + if ( abitmap ) + *abitmap = null_bitmap; + } + + + /* deprecated function name; retained for ABI compatibility */ + + FT_EXPORT_DEF( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ) + { + if ( abitmap ) + *abitmap = null_bitmap; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target) + { + FT_Memory memory; + FT_Error error = FT_Err_Ok; + FT_Int pitch; + FT_Int flip; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !source || !target ) + return FT_THROW( Invalid_Argument ); + + if ( source == target ) + return FT_Err_Ok; + + flip = ( source->pitch < 0 && target->pitch > 0 ) || + ( source->pitch > 0 && target->pitch < 0 ); + + memory = library->memory; + FT_FREE( target->buffer ); + + *target = *source; + + if ( flip ) + target->pitch = -target->pitch; + + if ( !source->buffer ) + return FT_Err_Ok; + + pitch = source->pitch; + if ( pitch < 0 ) + pitch = -pitch; + + FT_MEM_QALLOC_MULT( target->buffer, target->rows, pitch ); + + if ( !error ) + { + if ( flip ) + { + /* take care of bitmap flow */ + FT_UInt i; + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + + + t += (FT_ULong)pitch * ( target->rows - 1 ); + + for ( i = target->rows; i > 0; i-- ) + { + FT_ARRAY_COPY( t, s, pitch ); + + s += pitch; + t -= pitch; + } + } + else + FT_MEM_COPY( target->buffer, source->buffer, + (FT_Long)source->rows * pitch ); + } + + return error; + } + + + /* Enlarge `bitmap' horizontally and vertically by `xpixels' */ + /* and `ypixels', respectively. */ + + static FT_Error + ft_bitmap_assure_buffer( FT_Memory memory, + FT_Bitmap* bitmap, + FT_UInt xpixels, + FT_UInt ypixels ) + { + FT_Error error; + unsigned int pitch; + unsigned int new_pitch; + FT_UInt bpp; + FT_UInt width, height; + unsigned char* buffer = NULL; + + + width = bitmap->width; + height = bitmap->rows; + pitch = (unsigned int)FT_ABS( bitmap->pitch ); + + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + bpp = 1; + new_pitch = ( width + xpixels + 7 ) >> 3; + break; + case FT_PIXEL_MODE_GRAY2: + bpp = 2; + new_pitch = ( width + xpixels + 3 ) >> 2; + break; + case FT_PIXEL_MODE_GRAY4: + bpp = 4; + new_pitch = ( width + xpixels + 1 ) >> 1; + break; + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + bpp = 8; + new_pitch = width + xpixels; + break; + default: + return FT_THROW( Invalid_Glyph_Format ); + } + + /* if no need to allocate memory */ + if ( ypixels == 0 && new_pitch <= pitch ) + { + /* zero the padding */ + FT_UInt bit_width = pitch * 8; + FT_UInt bit_last = ( width + xpixels ) * bpp; + + + if ( bit_last < bit_width ) + { + FT_Byte* line = bitmap->buffer + ( bit_last >> 3 ); + FT_Byte* end = bitmap->buffer + pitch; + FT_UInt shift = bit_last & 7; + FT_UInt mask = 0xFF00U >> shift; + FT_UInt count = height; + + + for ( ; count > 0; count--, line += pitch, end += pitch ) + { + FT_Byte* write = line; + + + if ( shift > 0 ) + { + write[0] = (FT_Byte)( write[0] & mask ); + write++; + } + if ( write < end ) + FT_MEM_ZERO( write, end - write ); + } + } + + return FT_Err_Ok; + } + + /* otherwise allocate new buffer */ + if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) ) + return error; + + /* new rows get added at the top of the bitmap, */ + /* thus take care of the flow direction */ + if ( bitmap->pitch > 0 ) + { + FT_UInt len = ( width * bpp + 7 ) >> 3; + + unsigned char* in = bitmap->buffer; + unsigned char* out = buffer; + + unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; + unsigned int delta = new_pitch - len; + + + FT_MEM_ZERO( out, new_pitch * ypixels ); + out += new_pitch * ypixels; + + while ( in < limit ) + { + FT_MEM_COPY( out, in, len ); + in += pitch; + out += len; + + /* we use FT_QALLOC_MULT, which doesn't zero out the buffer; */ + /* consequently, we have to manually zero out the remaining bytes */ + FT_MEM_ZERO( out, delta ); + out += delta; + } + } + else + { + FT_UInt len = ( width * bpp + 7 ) >> 3; + + unsigned char* in = bitmap->buffer; + unsigned char* out = buffer; + + unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; + unsigned int delta = new_pitch - len; + + + while ( in < limit ) + { + FT_MEM_COPY( out, in, len ); + in += pitch; + out += len; + + FT_MEM_ZERO( out, delta ); + out += delta; + } + + FT_MEM_ZERO( out, new_pitch * ypixels ); + } + + FT_FREE( bitmap->buffer ); + bitmap->buffer = buffer; + + /* set pitch only, width and height are left untouched */ + if ( bitmap->pitch < 0 ) + bitmap->pitch = -(int)new_pitch; + else + bitmap->pitch = (int)new_pitch; + + return FT_Err_Ok; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ) + { + FT_Error error; + unsigned char* p; + FT_Int i, x, pitch; + FT_UInt y; + FT_Int xstr, ystr; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !bitmap || !bitmap->buffer ) + return FT_THROW( Invalid_Argument ); + + if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) || + ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) ) + return FT_THROW( Invalid_Argument ); + + xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6; + ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6; + + if ( xstr == 0 && ystr == 0 ) + return FT_Err_Ok; + else if ( xstr < 0 || ystr < 0 ) + return FT_THROW( Invalid_Argument ); + + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + { + FT_Bitmap tmp; + + + /* convert to 8bpp */ + FT_Bitmap_Init( &tmp ); + error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 ); + if ( error ) + return error; + + FT_Bitmap_Done( library, bitmap ); + *bitmap = tmp; + } + break; + + case FT_PIXEL_MODE_MONO: + if ( xstr > 8 ) + xstr = 8; + break; + + case FT_PIXEL_MODE_LCD: + xstr *= 3; + break; + + case FT_PIXEL_MODE_LCD_V: + ystr *= 3; + break; + + case FT_PIXEL_MODE_BGRA: + /* We don't embolden color glyphs. */ + return FT_Err_Ok; + } + + error = ft_bitmap_assure_buffer( library->memory, bitmap, + (FT_UInt)xstr, (FT_UInt)ystr ); + if ( error ) + return error; + + /* take care of bitmap flow */ + pitch = bitmap->pitch; + if ( pitch > 0 ) + p = bitmap->buffer + pitch * ystr; + else + { + pitch = -pitch; + p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 ); + } + + /* for each row */ + for ( y = 0; y < bitmap->rows; y++ ) + { + /* + * Horizontally: + * + * From the last pixel on, make each pixel or'ed with the + * `xstr' pixels before it. + */ + for ( x = pitch - 1; x >= 0; x-- ) + { + unsigned char tmp; + + + tmp = p[x]; + for ( i = 1; i <= xstr; i++ ) + { + if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) + { + p[x] |= tmp >> i; + + /* the maximum value of 8 for `xstr' comes from here */ + if ( x > 0 ) + p[x] |= p[x - 1] << ( 8 - i ); + +#if 0 + if ( p[x] == 0xFF ) + break; +#endif + } + else + { + if ( x - i >= 0 ) + { + if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) + { + p[x] = (unsigned char)( bitmap->num_grays - 1 ); + break; + } + else + { + p[x] = (unsigned char)( p[x] + p[x - i] ); + if ( p[x] == bitmap->num_grays - 1 ) + break; + } + } + else + break; + } + } + } + + /* + * Vertically: + * + * Make the above `ystr' rows or'ed with it. + */ + for ( x = 1; x <= ystr; x++ ) + { + unsigned char* q; + + + q = p - bitmap->pitch * x; + for ( i = 0; i < pitch; i++ ) + q[i] |= p[i]; + } + + p += bitmap->pitch; + } + + bitmap->width += (FT_UInt)xstr; + bitmap->rows += (FT_UInt)ystr; + + return FT_Err_Ok; + } + + + static FT_Byte + ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra ) + { + FT_UInt a = bgra[3]; + FT_UInt l; + + + /* Short-circuit transparent color to avoid division by zero. */ + if ( !a ) + return 0; + + /* + * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722 + * coefficients for RGB channels *on the linear colors*. + * A gamma of 2.2 is fair to assume. And then, we need to + * undo the premultiplication too. + * + * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#SideNotes + * + * We do the computation with integers only, applying a gamma of 2.0. + * We guarantee 32-bit arithmetic to avoid overflow but the resulting + * luminosity fits into 16 bits. + * + */ + + l = ( 4731UL /* 0.072186 * 65536 */ * bgra[0] * bgra[0] + + 46868UL /* 0.715158 * 65536 */ * bgra[1] * bgra[1] + + 13937UL /* 0.212656 * 65536 */ * bgra[2] * bgra[2] ) >> 16; + + /* + * Final transparency can be determined as follows. + * + * - If alpha is zero, we want 0. + * - If alpha is zero and luminosity is zero, we want 255. + * - If alpha is zero and luminosity is one, we want 0. + * + * So the formula is a * (1 - l) = a - l * a. + * + * We still need to undo premultiplication by dividing l by a*a. + * + */ + + return (FT_Byte)( a - l / a ); + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + FT_Byte* s; + FT_Byte* t; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !source || !target ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + case FT_PIXEL_MODE_BGRA: + { + FT_Int width = (FT_Int)source->width; + FT_Int neg = ( target->pitch == 0 && source->pitch < 0 ) || + target->pitch < 0; + + + FT_Bitmap_Done( library, target ); + + target->pixel_mode = FT_PIXEL_MODE_GRAY; + target->rows = source->rows; + target->width = source->width; + + if ( alignment ) + { + FT_Int rem = width % alignment; + + + if ( rem ) + width = alignment > 0 ? width - rem + alignment + : width - rem - alignment; + } + + if ( FT_QALLOC_MULT( target->buffer, target->rows, width ) ) + return error; + + target->pitch = neg ? -width : width; + } + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + s = source->buffer; + t = target->buffer; + + /* take care of bitmap flow */ + if ( source->pitch < 0 ) + s -= source->pitch * (FT_Int)( source->rows - 1 ); + if ( target->pitch < 0 ) + t -= target->pitch * (FT_Int)( target->rows - 1 ); + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + FT_UInt i; + + + target->num_grays = 2; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + /* get the full bytes */ + for ( j = source->width >> 3; j > 0; j-- ) + { + FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ + + + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); + tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); + tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); + tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); + tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); + tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); + tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); + tt[7] = (FT_Byte)( val & 0x01 ); + + tt += 8; + ss += 1; + } + + /* get remaining pixels (if any) */ + j = source->width & 7; + if ( j > 0 ) + { + FT_Int val = *ss; + + + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); + val <<= 1; + tt += 1; + } + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + { + FT_UInt width = source->width; + FT_UInt i; + + + target->num_grays = 256; + + for ( i = source->rows; i > 0; i-- ) + { + FT_ARRAY_COPY( t, s, width ); + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY2: + { + FT_UInt i; + + + target->num_grays = 4; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + /* get the full bytes */ + for ( j = source->width >> 2; j > 0; j-- ) + { + FT_Int val = ss[0]; + + + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); + tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); + tt[3] = (FT_Byte)( ( val & 0x03 ) ); + + ss += 1; + tt += 4; + } + + j = source->width & 3; + if ( j > 0 ) + { + FT_Int val = ss[0]; + + + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + val <<= 2; + tt += 1; + } + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY4: + { + FT_UInt i; + + + target->num_grays = 16; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + /* get the full bytes */ + for ( j = source->width >> 1; j > 0; j-- ) + { + FT_Int val = ss[0]; + + + tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); + tt[1] = (FT_Byte)( ( val & 0x0F ) ); + + ss += 1; + tt += 2; + } + + if ( source->width & 1 ) + tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_BGRA: + { + FT_UInt i; + + + target->num_grays = 256; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + for ( j = source->width; j > 0; j-- ) + { + tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss ); + + ss += 4; + tt += 1; + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + default: + ; + } + + return error; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Blend( FT_Library library, + const FT_Bitmap* source_, + const FT_Vector source_offset_, + FT_Bitmap* target, + FT_Vector *atarget_offset, + FT_Color color ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + FT_Bitmap source_bitmap; + const FT_Bitmap* source; + + FT_Vector source_offset; + FT_Vector target_offset; + + FT_Bool free_source_bitmap = 0; + FT_Bool free_target_bitmap_on_error = 0; + + FT_Pos source_llx, source_lly, source_urx, source_ury; + FT_Pos target_llx, target_lly, target_urx, target_ury; + FT_Pos final_llx, final_lly, final_urx, final_ury; + + unsigned int final_rows, final_width; + long x, y; + + + if ( !library || !target || !source_ || !atarget_offset ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + if ( !( target->pixel_mode == FT_PIXEL_MODE_NONE || + ( target->pixel_mode == FT_PIXEL_MODE_BGRA && + target->buffer ) ) ) + return FT_THROW( Invalid_Argument ); + + if ( source_->pixel_mode == FT_PIXEL_MODE_NONE ) + return FT_Err_Ok; /* nothing to do */ + + /* pitches must have the same sign */ + if ( target->pixel_mode == FT_PIXEL_MODE_BGRA && + ( source_->pitch ^ target->pitch ) < 0 ) + return FT_THROW( Invalid_Argument ); + + if ( !( source_->width && source_->rows ) ) + return FT_Err_Ok; /* nothing to do */ + + /* assure integer pixel offsets */ + source_offset.x = FT_PIX_FLOOR( source_offset_.x ); + source_offset.y = FT_PIX_FLOOR( source_offset_.y ); + target_offset.x = FT_PIX_FLOOR( atarget_offset->x ); + target_offset.y = FT_PIX_FLOOR( atarget_offset->y ); + + /* get source bitmap dimensions */ + source_llx = source_offset.x; + if ( FT_LONG_MIN + (FT_Pos)( source_->rows << 6 ) + 64 > source_offset.y ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: y coordinate overflow in source bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + source_lly = source_offset.y - ( source_->rows << 6 ); + + if ( FT_LONG_MAX - (FT_Pos)( source_->width << 6 ) - 64 < source_llx ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: x coordinate overflow in source bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + source_urx = source_llx + ( source_->width << 6 ); + source_ury = source_offset.y; + + /* get target bitmap dimensions */ + if ( target->width && target->rows ) + { + target_llx = target_offset.x; + if ( FT_LONG_MIN + (FT_Pos)( target->rows << 6 ) > target_offset.y ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: y coordinate overflow in target bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + target_lly = target_offset.y - ( target->rows << 6 ); + + if ( FT_LONG_MAX - (FT_Pos)( target->width << 6 ) < target_llx ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: x coordinate overflow in target bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + target_urx = target_llx + ( target->width << 6 ); + target_ury = target_offset.y; + } + else + { + target_llx = FT_LONG_MAX; + target_lly = FT_LONG_MAX; + target_urx = FT_LONG_MIN; + target_ury = FT_LONG_MIN; + } + + /* compute final bitmap dimensions */ + final_llx = FT_MIN( source_llx, target_llx ); + final_lly = FT_MIN( source_lly, target_lly ); + final_urx = FT_MAX( source_urx, target_urx ); + final_ury = FT_MAX( source_ury, target_ury ); + + final_width = ( final_urx - final_llx ) >> 6; + final_rows = ( final_ury - final_lly ) >> 6; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( "FT_Bitmap_Blend:\n" )); + FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + source_llx / 64, source_lly / 64, + source_urx / 64, source_ury / 64, + source_->width, source_->rows )); + + if ( target->width && target->rows ) + FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + target_llx / 64, target_lly / 64, + target_urx / 64, target_ury / 64, + target->width, target->rows )); + else + FT_TRACE5(( " target bitmap: empty\n" )); + + if ( final_width && final_rows ) + FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + final_llx / 64, final_lly / 64, + final_urx / 64, final_ury / 64, + final_width, final_rows )); + else + FT_TRACE5(( " final bitmap: empty\n" )); +#endif /* FT_DEBUG_LEVEL_TRACE */ + + if ( !( final_width && final_rows ) ) + return FT_Err_Ok; /* nothing to do */ + + /* for blending, set offset vector of final bitmap */ + /* temporarily to (0,0) */ + source_llx -= final_llx; + source_lly -= final_lly; + + if ( target->width && target->rows ) + { + target_llx -= final_llx; + target_lly -= final_lly; + } + + /* set up target bitmap */ + if ( target->pixel_mode == FT_PIXEL_MODE_NONE ) + { + /* create new empty bitmap */ + target->width = final_width; + target->rows = final_rows; + target->pixel_mode = FT_PIXEL_MODE_BGRA; + target->pitch = (int)final_width * 4; + target->num_grays = 256; + + if ( FT_LONG_MAX / target->pitch < (int)target->rows ) + { + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + final_width, final_rows )); + return FT_THROW( Invalid_Argument ); + } + + if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) ) + return error; + + free_target_bitmap_on_error = 1; + } + else if ( target->width != final_width || + target->rows != final_rows ) + { + /* adjust old bitmap to enlarged size */ + int pitch, new_pitch; + + unsigned char* buffer = NULL; + + + pitch = target->pitch; + + if ( pitch < 0 ) + pitch = -pitch; + + new_pitch = (int)final_width * 4; + + if ( FT_LONG_MAX / new_pitch < (int)final_rows ) + { + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + final_width, final_rows )); + return FT_THROW( Invalid_Argument ); + } + + /* TODO: provide an in-buffer solution for large bitmaps */ + /* to avoid allocation of a new buffer */ + if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) ) + goto Error; + + /* copy data to new buffer */ + x = target_llx >> 6; + y = target_lly >> 6; + + /* the bitmap flow is from top to bottom, */ + /* but y is measured from bottom to top */ + if ( target->pitch < 0 ) + { + /* XXX */ + } + else + { + unsigned char* p = + target->buffer; + unsigned char* q = + buffer + + ( final_rows - y - target->rows ) * new_pitch + + x * 4; + unsigned char* limit_p = + p + pitch * (int)target->rows; + + + while ( p < limit_p ) + { + FT_MEM_COPY( q, p, pitch ); + + p += pitch; + q += new_pitch; + } + } + + FT_FREE( target->buffer ); + + target->width = final_width; + target->rows = final_rows; + + if ( target->pitch < 0 ) + target->pitch = -new_pitch; + else + target->pitch = new_pitch; + + target->buffer = buffer; + } + + /* adjust source bitmap if necessary */ + if ( source_->pixel_mode != FT_PIXEL_MODE_GRAY ) + { + FT_Bitmap_Init( &source_bitmap ); + error = FT_Bitmap_Convert( library, source_, &source_bitmap, 1 ); + if ( error ) + goto Error; + + source = &source_bitmap; + free_source_bitmap = 1; + } + else + source = source_; + + /* do blending; the code below returns pre-multiplied channels, */ + /* similar to what FreeType gets from `CBDT' tables */ + x = source_llx >> 6; + y = source_lly >> 6; + + /* the bitmap flow is from top to bottom, */ + /* but y is measured from bottom to top */ + if ( target->pitch < 0 ) + { + /* XXX */ + } + else + { + unsigned char* p = + source->buffer; + unsigned char* q = + target->buffer + + ( target->rows - y - source->rows ) * target->pitch + + x * 4; + unsigned char* limit_p = + p + source->pitch * (int)source->rows; + + + while ( p < limit_p ) + { + unsigned char* r = p; + unsigned char* s = q; + unsigned char* limit_r = r + source->width; + + + while ( r < limit_r ) + { + int aa = *r++; + int fa = color.alpha * aa / 255; + + int fb = color.blue * fa / 255; + int fg = color.green * fa / 255; + int fr = color.red * fa / 255; + + int ba2 = 255 - fa; + + int bb = s[0]; + int bg = s[1]; + int br = s[2]; + int ba = s[3]; + + + *s++ = (unsigned char)( bb * ba2 / 255 + fb ); + *s++ = (unsigned char)( bg * ba2 / 255 + fg ); + *s++ = (unsigned char)( br * ba2 / 255 + fr ); + *s++ = (unsigned char)( ba * ba2 / 255 + fa ); + } + + p += source->pitch; + q += target->pitch; + } + } + + atarget_offset->x = final_llx; + atarget_offset->y = final_lly + ( final_rows << 6 ); + + Error: + if ( error && free_target_bitmap_on_error ) + FT_Bitmap_Done( library, target ); + + if ( free_source_bitmap ) + FT_Bitmap_Done( library, &source_bitmap ); + + return error; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ) + { + if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP && + !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_Bitmap bitmap; + FT_Error error; + + + FT_Bitmap_Init( &bitmap ); + error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap ); + if ( error ) + return error; + + slot->bitmap = bitmap; + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + + return FT_Err_Ok; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !bitmap ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + FT_FREE( bitmap->buffer ); + *bitmap = null_bitmap; + + return FT_Err_Ok; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftcalc.c b/vendor/freetype/src/base/ftcalc.c new file mode 100644 index 0000000..c5bc7e3 --- /dev/null +++ b/vendor/freetype/src/base/ftcalc.c @@ -0,0 +1,1127 @@ +/**************************************************************************** + * + * ftcalc.c + * + * Arithmetic computations (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * Support for 1-complement arithmetic has been totally dropped in this + * release. You can still write your own code if you need it. + * + */ + + /************************************************************************** + * + * Implementing basic computation routines. + * + * FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(), + * and FT_FloorFix() are declared in freetype.h. + * + */ + + +#include +#include +#include +#include +#include + + +#ifdef FT_MULFIX_ASSEMBLER +#undef FT_MulFix +#endif + +/* we need to emulate a 64-bit data type if a real one isn't available */ + +#ifndef FT_INT64 + + typedef struct FT_Int64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + + } FT_Int64; + +#endif /* !FT_INT64 */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT calc + + + /* transfer sign, leaving a positive number; */ + /* we need an unsigned value to safely negate INT_MIN (or LONG_MIN) */ +#define FT_MOVE_SIGN( x, x_unsigned, s ) \ + FT_BEGIN_STMNT \ + if ( x < 0 ) \ + { \ + x_unsigned = 0U - (x_unsigned); \ + s = -s; \ + } \ + FT_END_STMNT + + /* The following three functions are available regardless of whether */ + /* FT_INT64 is defined. */ + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_RoundFix( FT_Fixed a ) + { + return ( ADD_LONG( a, 0x8000L - ( a < 0 ) ) ) & ~0xFFFFL; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_CeilFix( FT_Fixed a ) + { + return ( ADD_LONG( a, 0xFFFFL ) ) & ~0xFFFFL; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_FloorFix( FT_Fixed a ) + { + return a & ~0xFFFFL; + } + +#ifndef FT_MSB + + FT_BASE_DEF( FT_Int ) + FT_MSB( FT_UInt32 z ) + { + FT_Int shift = 0; + + + /* determine msb bit index in `shift' */ + if ( z & 0xFFFF0000UL ) + { + z >>= 16; + shift += 16; + } + if ( z & 0x0000FF00UL ) + { + z >>= 8; + shift += 8; + } + if ( z & 0x000000F0UL ) + { + z >>= 4; + shift += 4; + } + if ( z & 0x0000000CUL ) + { + z >>= 2; + shift += 2; + } + if ( z & 0x00000002UL ) + { + /* z >>= 1; */ + shift += 1; + } + + return shift; + } + +#endif /* !FT_MSB */ + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Fixed ) + FT_Hypot( FT_Fixed x, + FT_Fixed y ) + { + FT_Vector v; + + + v.x = x; + v.y = y; + + return FT_Vector_Length( &v ); + } + + +#ifdef FT_INT64 + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulDiv( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt64 a, b, c, d; + FT_Long d_; + + + a = (FT_UInt64)a_; + b = (FT_UInt64)b_; + c = (FT_UInt64)c_; + + FT_MOVE_SIGN( a_, a, s ); + FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( c_, c, s ); + + d = c > 0 ? ( a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFUL; + + d_ = (FT_Long)d; + + return s < 0 ? NEG_LONG( d_ ) : d_; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Long ) + FT_MulDiv_No_Round( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt64 a, b, c, d; + FT_Long d_; + + + a = (FT_UInt64)a_; + b = (FT_UInt64)b_; + c = (FT_UInt64)c_; + + FT_MOVE_SIGN( a_, a, s ); + FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( c_, c, s ); + + d = c > 0 ? a * b / c + : 0x7FFFFFFFUL; + + d_ = (FT_Long)d; + + return s < 0 ? NEG_LONG( d_ ) : d_; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulFix( FT_Long a_, + FT_Long b_ ) + { +#ifdef FT_MULFIX_ASSEMBLER + + return FT_MULFIX_ASSEMBLER( (FT_Int32)a_, (FT_Int32)b_ ); + +#else + + FT_Int64 ab = (FT_Int64)a_ * (FT_Int64)b_; + + /* this requires arithmetic right shift of signed numbers */ + return (FT_Long)( ( ab + 0x8000L - ( ab < 0 ) ) >> 16 ); + +#endif /* FT_MULFIX_ASSEMBLER */ + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_DivFix( FT_Long a_, + FT_Long b_ ) + { + FT_Int s = 1; + FT_UInt64 a, b, q; + FT_Long q_; + + + a = (FT_UInt64)a_; + b = (FT_UInt64)b_; + + FT_MOVE_SIGN( a_, a, s ); + FT_MOVE_SIGN( b_, b, s ); + + q = b > 0 ? ( ( a << 16 ) + ( b >> 1 ) ) / b + : 0x7FFFFFFFUL; + + q_ = (FT_Long)q; + + return s < 0 ? NEG_LONG( q_ ) : q_; + } + + +#else /* !FT_INT64 */ + + + static void + ft_multo64( FT_UInt32 x, + FT_UInt32 y, + FT_Int64 *z ) + { + FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; + + + lo1 = x & 0x0000FFFFU; hi1 = x >> 16; + lo2 = y & 0x0000FFFFU; hi2 = y >> 16; + + lo = lo1 * lo2; + i1 = lo1 * hi2; + i2 = lo2 * hi1; + hi = hi1 * hi2; + + /* Check carry overflow of i1 + i2 */ + i1 += i2; + hi += (FT_UInt32)( i1 < i2 ) << 16; + + hi += i1 >> 16; + i1 = i1 << 16; + + /* Check carry overflow of i1 + lo */ + lo += i1; + hi += ( lo < i1 ); + + z->lo = lo; + z->hi = hi; + } + + + static FT_UInt32 + ft_div64by32( FT_UInt32 hi, + FT_UInt32 lo, + FT_UInt32 y ) + { + FT_UInt32 r, q; + FT_Int i; + + + if ( hi >= y ) + return (FT_UInt32)0x7FFFFFFFL; + + /* We shift as many bits as we can into the high register, perform */ + /* 32-bit division with modulo there, then work through the remaining */ + /* bits with long division. This optimization is especially noticeable */ + /* for smaller dividends that barely use the high register. */ + + i = 31 - FT_MSB( hi ); + r = ( hi << i ) | ( lo >> ( 32 - i ) ); lo <<= i; /* left 64-bit shift */ + q = r / y; + r -= q * y; /* remainder */ + + i = 32 - i; /* bits remaining in low register */ + do + { + q <<= 1; + r = ( r << 1 ) | ( lo >> 31 ); lo <<= 1; + + if ( r >= y ) + { + r -= y; + q |= 1; + } + } while ( --i ); + + return q; + } + + + static void + FT_Add64( FT_Int64* x, + FT_Int64* y, + FT_Int64 *z ) + { + FT_UInt32 lo, hi; + + + lo = x->lo + y->lo; + hi = x->hi + y->hi + ( lo < x->lo ); + + z->lo = lo; + z->hi = hi; + } + + + /* The FT_MulDiv function has been optimized thanks to ideas from */ + /* Graham Asher and Alexei Podtelezhnikov. The trick is to optimize */ + /* a rather common case when everything fits within 32-bits. */ + /* */ + /* We compute 'a*b+c/2', then divide it by 'c' (all positive values). */ + /* */ + /* The product of two positive numbers never exceeds the square of */ + /* its mean values. Therefore, we always avoid the overflow by */ + /* imposing */ + /* */ + /* (a + b) / 2 <= sqrt(X - c/2) , */ + /* */ + /* where X = 2^32 - 1, the maximum unsigned 32-bit value, and using */ + /* unsigned arithmetic. Now we replace `sqrt' with a linear function */ + /* that is smaller or equal for all values of c in the interval */ + /* [0;X/2]; it should be equal to sqrt(X) and sqrt(3X/4) at the */ + /* endpoints. Substituting the linear solution and explicit numbers */ + /* we get */ + /* */ + /* a + b <= 131071.99 - c / 122291.84 . */ + /* */ + /* In practice, we should use a faster and even stronger inequality */ + /* */ + /* a + b <= 131071 - (c >> 16) */ + /* */ + /* or, alternatively, */ + /* */ + /* a + b <= 129894 - (c >> 17) . */ + /* */ + /* FT_MulFix, on the other hand, is optimized for a small value of */ + /* the first argument, when the second argument can be much larger. */ + /* This can be achieved by scaling the second argument and the limit */ + /* in the above inequalities. For example, */ + /* */ + /* a + (b >> 8) <= (131071 >> 4) */ + /* */ + /* covers the practical range of use. The actual test below is a bit */ + /* tighter to avoid the border case overflows. */ + /* */ + /* In the case of FT_DivFix, the exact overflow check */ + /* */ + /* a << 16 <= X - c/2 */ + /* */ + /* is scaled down by 2^16 and we use */ + /* */ + /* a <= 65535 - (c >> 17) . */ + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulDiv( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt32 a, b, c; + + + /* XXX: this function does not allow 64-bit arguments */ + + a = (FT_UInt32)a_; + b = (FT_UInt32)b_; + c = (FT_UInt32)c_; + + FT_MOVE_SIGN( a_, a, s ); + FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( c_, c, s ); + + if ( c == 0 ) + a = 0x7FFFFFFFUL; + + else if ( a + b <= 129894UL - ( c >> 17 ) ) + a = ( a * b + ( c >> 1 ) ) / c; + + else + { + FT_Int64 temp, temp2; + + + ft_multo64( a, b, &temp ); + + temp2.hi = 0; + temp2.lo = c >> 1; + + FT_Add64( &temp, &temp2, &temp ); + + /* last attempt to ditch long division */ + a = ( temp.hi == 0 ) ? temp.lo / c + : ft_div64by32( temp.hi, temp.lo, c ); + } + + a_ = (FT_Long)a; + + return s < 0 ? NEG_LONG( a_ ) : a_; + } + + + FT_BASE_DEF( FT_Long ) + FT_MulDiv_No_Round( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt32 a, b, c; + + + /* XXX: this function does not allow 64-bit arguments */ + + a = (FT_UInt32)a_; + b = (FT_UInt32)b_; + c = (FT_UInt32)c_; + + FT_MOVE_SIGN( a_, a, s ); + FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( c_, c, s ); + + if ( c == 0 ) + a = 0x7FFFFFFFUL; + + else if ( a + b <= 131071UL ) + a = a * b / c; + + else + { + FT_Int64 temp; + + + ft_multo64( a, b, &temp ); + + /* last attempt to ditch long division */ + a = ( temp.hi == 0 ) ? temp.lo / c + : ft_div64by32( temp.hi, temp.lo, c ); + } + + a_ = (FT_Long)a; + + return s < 0 ? NEG_LONG( a_ ) : a_; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulFix( FT_Long a_, + FT_Long b_ ) + { +#ifdef FT_MULFIX_ASSEMBLER + + return FT_MULFIX_ASSEMBLER( a_, b_ ); + +#elif 0 + + /* + * This code is nonportable. See comment below. + * + * However, on a platform where right-shift of a signed quantity fills + * the leftmost bits by copying the sign bit, it might be faster. + */ + + FT_Long sa, sb; + FT_UInt32 a, b; + + + /* + * This is a clever way of converting a signed number `a' into its + * absolute value (stored back into `a') and its sign. The sign is + * stored in `sa'; 0 means `a' was positive or zero, and -1 means `a' + * was negative. (Similarly for `b' and `sb'). + * + * Unfortunately, it doesn't work (at least not portably). + * + * It makes the assumption that right-shift on a negative signed value + * fills the leftmost bits by copying the sign bit. This is wrong. + * According to K&R 2nd ed, section `A7.8 Shift Operators' on page 206, + * the result of right-shift of a negative signed value is + * implementation-defined. At least one implementation fills the + * leftmost bits with 0s (i.e., it is exactly the same as an unsigned + * right shift). This means that when `a' is negative, `sa' ends up + * with the value 1 rather than -1. After that, everything else goes + * wrong. + */ + sa = ( a_ >> ( sizeof ( a_ ) * 8 - 1 ) ); + a = ( a_ ^ sa ) - sa; + sb = ( b_ >> ( sizeof ( b_ ) * 8 - 1 ) ); + b = ( b_ ^ sb ) - sb; + + a = (FT_UInt32)a_; + b = (FT_UInt32)b_; + + if ( a + ( b >> 8 ) <= 8190UL ) + a = ( a * b + 0x8000U ) >> 16; + else + { + FT_UInt32 al = a & 0xFFFFUL; + + + a = ( a >> 16 ) * b + al * ( b >> 16 ) + + ( ( al * ( b & 0xFFFFUL ) + 0x8000UL ) >> 16 ); + } + + sa ^= sb; + a = ( a ^ sa ) - sa; + + return (FT_Long)a; + +#else /* 0 */ + + FT_Int s = 1; + FT_UInt32 a, b; + + + /* XXX: this function does not allow 64-bit arguments */ + + a = (FT_UInt32)a_; + b = (FT_UInt32)b_; + + FT_MOVE_SIGN( a_, a, s ); + FT_MOVE_SIGN( b_, b, s ); + + if ( a + ( b >> 8 ) <= 8190UL ) + a = ( a * b + 0x8000UL ) >> 16; + else + { + FT_UInt32 al = a & 0xFFFFUL; + + + a = ( a >> 16 ) * b + al * ( b >> 16 ) + + ( ( al * ( b & 0xFFFFUL ) + 0x8000UL ) >> 16 ); + } + + a_ = (FT_Long)a; + + return s < 0 ? NEG_LONG( a_ ) : a_; + +#endif /* 0 */ + + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_DivFix( FT_Long a_, + FT_Long b_ ) + { + FT_Int s = 1; + FT_UInt32 a, b, q; + FT_Long q_; + + + /* XXX: this function does not allow 64-bit arguments */ + + a = (FT_UInt32)a_; + b = (FT_UInt32)b_; + + FT_MOVE_SIGN( a_, a, s ); + FT_MOVE_SIGN( b_, b, s ); + + if ( b == 0 ) + { + /* check for division by 0 */ + q = 0x7FFFFFFFUL; + } + else if ( a <= 65535UL - ( b >> 17 ) ) + { + /* compute result directly */ + q = ( ( a << 16 ) + ( b >> 1 ) ) / b; + } + else + { + /* we need more bits; we have to do it by hand */ + FT_Int64 temp, temp2; + + + temp.hi = a >> 16; + temp.lo = a << 16; + temp2.hi = 0; + temp2.lo = b >> 1; + + FT_Add64( &temp, &temp2, &temp ); + q = ft_div64by32( temp.hi, temp.lo, b ); + } + + q_ = (FT_Long)q; + + return s < 0 ? NEG_LONG( q_ ) : q_; + } + + +#endif /* !FT_INT64 */ + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix *b ) + { + FT_Fixed xx, xy, yx, yy; + + + if ( !a || !b ) + return; + + xx = ADD_LONG( FT_MulFix( a->xx, b->xx ), + FT_MulFix( a->xy, b->yx ) ); + xy = ADD_LONG( FT_MulFix( a->xx, b->xy ), + FT_MulFix( a->xy, b->yy ) ); + yx = ADD_LONG( FT_MulFix( a->yx, b->xx ), + FT_MulFix( a->yy, b->yx ) ); + yy = ADD_LONG( FT_MulFix( a->yx, b->xy ), + FT_MulFix( a->yy, b->yy ) ); + + b->xx = xx; + b->xy = xy; + b->yx = yx; + b->yy = yy; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ) + { + FT_Pos delta, xx, yy; + + + if ( !matrix ) + return FT_THROW( Invalid_Argument ); + + /* compute discriminant */ + delta = FT_MulFix( matrix->xx, matrix->yy ) - + FT_MulFix( matrix->xy, matrix->yx ); + + if ( !delta ) + return FT_THROW( Invalid_Argument ); /* matrix can't be inverted */ + + matrix->xy = -FT_DivFix( matrix->xy, delta ); + matrix->yx = -FT_DivFix( matrix->yx, delta ); + + xx = matrix->xx; + yy = matrix->yy; + + matrix->xx = FT_DivFix( yy, delta ); + matrix->yy = FT_DivFix( xx, delta ); + + return FT_Err_Ok; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( void ) + FT_Matrix_Multiply_Scaled( const FT_Matrix* a, + FT_Matrix *b, + FT_Long scaling ) + { + FT_Fixed xx, xy, yx, yy; + + FT_Long val = 0x10000L * scaling; + + + if ( !a || !b ) + return; + + xx = ADD_LONG( FT_MulDiv( a->xx, b->xx, val ), + FT_MulDiv( a->xy, b->yx, val ) ); + xy = ADD_LONG( FT_MulDiv( a->xx, b->xy, val ), + FT_MulDiv( a->xy, b->yy, val ) ); + yx = ADD_LONG( FT_MulDiv( a->yx, b->xx, val ), + FT_MulDiv( a->yy, b->yx, val ) ); + yy = ADD_LONG( FT_MulDiv( a->yx, b->xy, val ), + FT_MulDiv( a->yy, b->yy, val ) ); + + b->xx = xx; + b->xy = xy; + b->yx = yx; + b->yy = yy; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Bool ) + FT_Matrix_Check( const FT_Matrix* matrix ) + { + FT_Fixed xx, xy, yx, yy; + FT_Fixed val; + FT_Int shift; + FT_ULong temp1, temp2; + + + if ( !matrix ) + return 0; + + xx = matrix->xx; + xy = matrix->xy; + yx = matrix->yx; + yy = matrix->yy; + val = FT_ABS( xx ) | FT_ABS( xy ) | FT_ABS( yx ) | FT_ABS( yy ); + + /* we only handle non-zero 32-bit values */ + if ( !val || val > 0x7FFFFFFFL ) + return 0; + + /* Scale matrix to avoid the temp1 overflow, which is */ + /* more stringent than avoiding the temp2 overflow. */ + + shift = FT_MSB( val ) - 12; + + if ( shift > 0 ) + { + xx >>= shift; + xy >>= shift; + yx >>= shift; + yy >>= shift; + } + + temp1 = 32U * (FT_ULong)FT_ABS( xx * yy - xy * yx ); + temp2 = (FT_ULong)( xx * xx ) + (FT_ULong)( xy * xy ) + + (FT_ULong)( yx * yx ) + (FT_ULong)( yy * yy ); + + if ( temp1 <= temp2 ) + return 0; + + return 1; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( void ) + FT_Vector_Transform_Scaled( FT_Vector* vector, + const FT_Matrix* matrix, + FT_Long scaling ) + { + FT_Pos xz, yz; + + FT_Long val = 0x10000L * scaling; + + + if ( !vector || !matrix ) + return; + + xz = ADD_LONG( FT_MulDiv( vector->x, matrix->xx, val ), + FT_MulDiv( vector->y, matrix->xy, val ) ); + yz = ADD_LONG( FT_MulDiv( vector->x, matrix->yx, val ), + FT_MulDiv( vector->y, matrix->yy, val ) ); + + vector->x = xz; + vector->y = yz; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_UInt32 ) + FT_Vector_NormLen( FT_Vector* vector ) + { + FT_Int32 x_ = vector->x; + FT_Int32 y_ = vector->y; + FT_Int32 b, z; + FT_UInt32 x, y, u, v, l; + FT_Int sx = 1, sy = 1, shift; + + + x = (FT_UInt32)x_; + y = (FT_UInt32)y_; + + FT_MOVE_SIGN( x_, x, sx ); + FT_MOVE_SIGN( y_, y, sy ); + + /* trivial cases */ + if ( x == 0 ) + { + if ( y > 0 ) + vector->y = sy * 0x10000; + return y; + } + else if ( y == 0 ) + { + if ( x > 0 ) + vector->x = sx * 0x10000; + return x; + } + + /* Estimate length and prenormalize by shifting so that */ + /* the new approximate length is between 2/3 and 4/3. */ + /* The magic constant 0xAAAAAAAAUL (2/3 of 2^32) helps */ + /* achieve this in 16.16 fixed-point representation. */ + l = x > y ? x + ( y >> 1 ) + : y + ( x >> 1 ); + + shift = 31 - FT_MSB( l ); + shift -= 15 + ( l >= ( 0xAAAAAAAAUL >> shift ) ); + + if ( shift > 0 ) + { + x <<= shift; + y <<= shift; + + /* re-estimate length for tiny vectors */ + l = x > y ? x + ( y >> 1 ) + : y + ( x >> 1 ); + } + else + { + x >>= -shift; + y >>= -shift; + l >>= -shift; + } + + /* lower linear approximation for reciprocal length minus one */ + b = 0x10000 - (FT_Int32)l; + + x_ = (FT_Int32)x; + y_ = (FT_Int32)y; + + /* Newton's iterations */ + do + { + u = (FT_UInt32)( x_ + ( x_ * b >> 16 ) ); + v = (FT_UInt32)( y_ + ( y_ * b >> 16 ) ); + + /* Normalized squared length in the parentheses approaches 2^32. */ + /* On two's complement systems, converting to signed gives the */ + /* difference with 2^32 even if the expression wraps around. */ + z = -(FT_Int32)( u * u + v * v ) / 0x200; + z = z * ( ( 0x10000 + b ) >> 8 ) / 0x10000; + + b += z; + + } while ( z > 0 ); + + vector->x = sx < 0 ? -(FT_Pos)u : (FT_Pos)u; + vector->y = sy < 0 ? -(FT_Pos)v : (FT_Pos)v; + + /* Conversion to signed helps to recover from likely wrap around */ + /* in calculating the prenormalized length, because it gives the */ + /* correct difference with 2^32 on two's complement systems. */ + l = (FT_UInt32)( 0x10000 + (FT_Int32)( u * x + v * y ) / 0x10000 ); + if ( shift > 0 ) + l = ( l + ( 1 << ( shift - 1 ) ) ) >> shift; + else + l <<= -shift; + + return l; + } + + +#if 0 + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Int32 ) + FT_SqrtFixed( FT_Int32 x ) + { + FT_UInt32 root, rem_hi, rem_lo, test_div; + FT_Int count; + + + root = 0; + + if ( x > 0 ) + { + rem_hi = 0; + rem_lo = (FT_UInt32)x; + count = 24; + do + { + rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 ); + rem_lo <<= 2; + root <<= 1; + test_div = ( root << 1 ) + 1; + + if ( rem_hi >= test_div ) + { + rem_hi -= test_div; + root += 1; + } + } while ( --count ); + } + + return (FT_Int32)root; + } + +#endif /* 0 */ + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ) + { + /* we silently ignore overflow errors since such large values */ + /* lead to even more (harmless) rendering errors later on */ + +#ifdef FT_INT64 + + FT_Int64 delta = SUB_INT64( MUL_INT64( in_x, out_y ), + MUL_INT64( in_y, out_x ) ); + + + return ( delta > 0 ) - ( delta < 0 ); + +#else + + FT_Int result; + + + if ( ADD_LONG( FT_ABS( in_x ), FT_ABS( out_y ) ) <= 131071L && + ADD_LONG( FT_ABS( in_y ), FT_ABS( out_x ) ) <= 131071L ) + { + FT_Long z1 = MUL_LONG( in_x, out_y ); + FT_Long z2 = MUL_LONG( in_y, out_x ); + + + if ( z1 > z2 ) + result = +1; + else if ( z1 < z2 ) + result = -1; + else + result = 0; + } + else /* products might overflow 32 bits */ + { + FT_Int64 z1, z2; + + + /* XXX: this function does not allow 64-bit arguments */ + ft_multo64( (FT_UInt32)in_x, (FT_UInt32)out_y, &z1 ); + ft_multo64( (FT_UInt32)in_y, (FT_UInt32)out_x, &z2 ); + + if ( z1.hi > z2.hi ) + result = +1; + else if ( z1.hi < z2.hi ) + result = -1; + else if ( z1.lo > z2.lo ) + result = +1; + else if ( z1.lo < z2.lo ) + result = -1; + else + result = 0; + } + + /* XXX: only the sign of return value, +1/0/-1 must be used */ + return result; + +#endif + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ) + { + FT_Pos ax = in_x + out_x; + FT_Pos ay = in_y + out_y; + + FT_Pos d_in, d_out, d_hypot; + + + /* The idea of this function is to compare the length of the */ + /* hypotenuse with the `in' and `out' length. The `corner' */ + /* represented by `in' and `out' is flat if the hypotenuse's */ + /* length isn't too large. */ + /* */ + /* This approach has the advantage that the angle between */ + /* `in' and `out' is not checked. In case one of the two */ + /* vectors is `dominant', that is, much larger than the */ + /* other vector, we thus always have a flat corner. */ + /* */ + /* hypotenuse */ + /* x---------------------------x */ + /* \ / */ + /* \ / */ + /* in \ / out */ + /* \ / */ + /* o */ + /* Point */ + + d_in = FT_HYPOT( in_x, in_y ); + d_out = FT_HYPOT( out_x, out_y ); + d_hypot = FT_HYPOT( ax, ay ); + + /* now do a simple length comparison: */ + /* */ + /* d_in + d_out < 17/16 d_hypot */ + + return ( d_in + d_out - d_hypot ) < ( d_hypot >> 4 ); + } + + + FT_BASE_DEF( FT_Int32 ) + FT_MulAddFix( FT_Fixed* s, + FT_Int32* f, + FT_UInt count ) + { + FT_UInt i; + FT_Int64 temp; + + +#ifdef FT_INT64 + temp = 0; + + for ( i = 0; i < count; ++i ) + temp += (FT_Int64)s[i] * f[i]; + + return (FT_Int32)( ( temp + 0x8000 ) >> 16 ); +#else + temp.hi = 0; + temp.lo = 0; + + for ( i = 0; i < count; ++i ) + { + FT_Int64 multResult; + + FT_Int sign = 1; + FT_UInt32 carry = 0; + + FT_UInt32 scalar; + FT_UInt32 factor; + + + scalar = (FT_UInt32)s[i]; + factor = (FT_UInt32)f[i]; + + FT_MOVE_SIGN( s[i], scalar, sign ); + FT_MOVE_SIGN( f[i], factor, sign ); + + ft_multo64( scalar, factor, &multResult ); + + if ( sign < 0 ) + { + /* Emulated `FT_Int64` negation. */ + carry = ( multResult.lo == 0 ); + + multResult.lo = ~multResult.lo + 1; + multResult.hi = ~multResult.hi + carry; + } + + FT_Add64( &temp, &multResult, &temp ); + } + + /* Shift and round value. */ + return (FT_Int32)( ( ( temp.hi << 16 ) | ( temp.lo >> 16 ) ) + + ( 1 & ( temp.lo >> 15 ) ) ); + + +#endif /* !FT_INT64 */ + + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftcid.c b/vendor/freetype/src/base/ftcid.c new file mode 100644 index 0000000..866cd23 --- /dev/null +++ b/vendor/freetype/src/base/ftcid.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * + * ftcid.c + * + * FreeType API for accessing CID font information. + * + * Copyright (C) 2007-2023 by + * Derek Clegg and Michael Toftdal. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + + + /* documentation is in ftcid.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_CID_Registry_Ordering_Supplement( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement) + { + FT_Error error; + const char* r = NULL; + const char* o = NULL; + FT_Int s = 0; + + + error = FT_ERR( Invalid_Argument ); + + if ( face ) + { + FT_Service_CID service; + + + FT_FACE_FIND_SERVICE( face, service, CID ); + + if ( service && service->get_ros ) + error = service->get_ros( face, &r, &o, &s ); + } + + if ( registry ) + *registry = r; + + if ( ordering ) + *ordering = o; + + if ( supplement ) + *supplement = s; + + return error; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face, + FT_Bool *is_cid ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_Bool ic = 0; + + + if ( face ) + { + FT_Service_CID service; + + + FT_FACE_FIND_SERVICE( face, service, CID ); + + if ( service && service->get_is_cid ) + error = service->get_is_cid( face, &ic); + } + + if ( is_cid ) + *is_cid = ic; + + return error; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_CID_From_Glyph_Index( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_UInt c = 0; + + + if ( face ) + { + FT_Service_CID service; + + + FT_FACE_FIND_SERVICE( face, service, CID ); + + if ( service && service->get_cid_from_glyph_index ) + error = service->get_cid_from_glyph_index( face, glyph_index, &c); + } + + if ( cid ) + *cid = c; + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftcolor.c b/vendor/freetype/src/base/ftcolor.c new file mode 100644 index 0000000..bcd6e89 --- /dev/null +++ b/vendor/freetype/src/base/ftcolor.c @@ -0,0 +1,156 @@ +/**************************************************************************** + * + * ftcolor.c + * + * FreeType's glyph color management (body). + * + * Copyright (C) 2018-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS + + static + const FT_Palette_Data null_palette_data = { 0, NULL, NULL, 0, NULL }; + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Data_Get( FT_Face face, + FT_Palette_Data *apalette_data ) + { + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + if ( !apalette_data) + return FT_THROW( Invalid_Argument ); + + if ( FT_IS_SFNT( face ) ) + *apalette_data = ( (TT_Face)face )->palette_data; + else + *apalette_data = null_palette_data; + + return FT_Err_Ok; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Select( FT_Face face, + FT_UShort palette_index, + FT_Color* *apalette ) + { + FT_Error error; + + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !FT_IS_SFNT( face ) ) + { + if ( apalette ) + *apalette = NULL; + + return FT_Err_Ok; + } + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + error = sfnt->set_palette( ttface, palette_index ); + if ( error ) + return error; + + ttface->palette_index = palette_index; + + if ( apalette ) + *apalette = ttface->palette; + + return FT_Err_Ok; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Set_Foreground_Color( FT_Face face, + FT_Color foreground_color ) + { + TT_Face ttface; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !FT_IS_SFNT( face ) ) + return FT_Err_Ok; + + ttface = (TT_Face)face; + + ttface->foreground_color = foreground_color; + ttface->have_foreground_color = 1; + + return FT_Err_Ok; + } + +#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Data_Get( FT_Face face, + FT_Palette_Data *apalette_data ) + { + FT_UNUSED( face ); + FT_UNUSED( apalette_data ); + + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Select( FT_Face face, + FT_UShort palette_index, + FT_Color* *apalette ) + { + FT_UNUSED( face ); + FT_UNUSED( palette_index ); + FT_UNUSED( apalette ); + + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Set_Foreground_Color( FT_Face face, + FT_Color foreground_color ) + { + FT_UNUSED( face ); + FT_UNUSED( foreground_color ); + + + return FT_THROW( Unimplemented_Feature ); + } + +#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + +/* END */ diff --git a/vendor/freetype/src/base/ftdbgmem.c b/vendor/freetype/src/base/ftdbgmem.c new file mode 100644 index 0000000..8fab50d --- /dev/null +++ b/vendor/freetype/src/base/ftdbgmem.c @@ -0,0 +1,971 @@ +/**************************************************************************** + * + * ftdbgmem.c + * + * Memory debugger (body). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include + + +#ifdef FT_DEBUG_MEMORY + +#define KEEPALIVE /* `Keep alive' means that freed blocks aren't released + * to the heap. This is useful to detect double-frees + * or weird heap corruption, but it uses large amounts of + * memory, however. + */ + +#include FT_CONFIG_STANDARD_LIBRARY_H + + FT_BASE_DEF( const char* ) ft_debug_file_ = NULL; + FT_BASE_DEF( long ) ft_debug_lineno_ = 0; + + extern void + FT_DumpMemory( FT_Memory memory ); + + + typedef struct FT_MemSourceRec_* FT_MemSource; + typedef struct FT_MemNodeRec_* FT_MemNode; + typedef struct FT_MemTableRec_* FT_MemTable; + + +#define FT_MEM_VAL( addr ) ( (FT_PtrDist)(FT_Pointer)( addr ) ) + + /* + * This structure holds statistics for a single allocation/release + * site. This is useful to know where memory operations happen the + * most. + */ + typedef struct FT_MemSourceRec_ + { + const char* file_name; + long line_no; + + FT_Long cur_blocks; /* current number of allocated blocks */ + FT_Long max_blocks; /* max. number of allocated blocks */ + FT_Long all_blocks; /* total number of blocks allocated */ + + FT_Long cur_size; /* current cumulative allocated size */ + FT_Long max_size; /* maximum cumulative allocated size */ + FT_Long all_size; /* total cumulative allocated size */ + + FT_Long cur_max; /* current maximum allocated size */ + + FT_UInt32 hash; + FT_MemSource link; + + } FT_MemSourceRec; + + + /* + * We don't need a resizable array for the memory sources because + * their number is pretty limited within FreeType. + */ +#define FT_MEM_SOURCE_BUCKETS 128 + + /* + * This structure holds information related to a single allocated + * memory block. If KEEPALIVE is defined, blocks that are freed by + * FreeType are never released to the system. Instead, their `size' + * field is set to `-size'. This is mainly useful to detect double + * frees, at the price of a large memory footprint during execution. + */ + typedef struct FT_MemNodeRec_ + { + FT_Byte* address; + FT_Long size; /* < 0 if the block was freed */ + + FT_MemSource source; + +#ifdef KEEPALIVE + const char* free_file_name; + FT_Long free_line_no; +#endif + + FT_MemNode link; + + } FT_MemNodeRec; + + + /* + * The global structure, containing compound statistics and all hash + * tables. + */ + typedef struct FT_MemTableRec_ + { + FT_Long size; + FT_Long nodes; + FT_MemNode* buckets; + + FT_Long alloc_total; + FT_Long alloc_current; + FT_Long alloc_max; + FT_Long alloc_count; + + FT_Bool bound_total; + FT_Long alloc_total_max; + + FT_Bool bound_count; + FT_Long alloc_count_max; + + FT_MemSource sources[FT_MEM_SOURCE_BUCKETS]; + + FT_Bool keep_alive; + + FT_Memory memory; + FT_Pointer memory_user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + + } FT_MemTableRec; + + +#define FT_MEM_SIZE_MIN 7 +#define FT_MEM_SIZE_MAX 13845163 + +#define FT_FILENAME( x ) ( (x) ? (x) : "unknown file" ) + + + /* + * Prime numbers are ugly to handle. It would be better to implement + * L-Hashing, which is 10% faster and doesn't require divisions. + */ + static const FT_Int ft_mem_primes[] = + { + 7, + 11, + 19, + 37, + 73, + 109, + 163, + 251, + 367, + 557, + 823, + 1237, + 1861, + 2777, + 4177, + 6247, + 9371, + 14057, + 21089, + 31627, + 47431, + 71143, + 106721, + 160073, + 240101, + 360163, + 540217, + 810343, + 1215497, + 1823231, + 2734867, + 4102283, + 6153409, + 9230113, + 13845163, + }; + + + static FT_Long + ft_mem_closest_prime( FT_Long num ) + { + size_t i; + + + for ( i = 0; + i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ ) + if ( ft_mem_primes[i] > num ) + return ft_mem_primes[i]; + + return FT_MEM_SIZE_MAX; + } + + + static void + ft_mem_debug_panic( const char* fmt, + ... ) + { + va_list ap; + + + printf( "FreeType.Debug: " ); + + va_start( ap, fmt ); + vprintf( fmt, ap ); + va_end( ap ); + + printf( "\n" ); + exit( EXIT_FAILURE ); + } + + + static FT_Pointer + ft_mem_table_alloc( FT_MemTable table, + FT_Long size ) + { + FT_Memory memory = table->memory; + FT_Pointer block; + + + memory->user = table->memory_user; + block = table->alloc( memory, size ); + memory->user = table; + + return block; + } + + + static void + ft_mem_table_free( FT_MemTable table, + FT_Pointer block ) + { + FT_Memory memory = table->memory; + + + memory->user = table->memory_user; + table->free( memory, block ); + memory->user = table; + } + + + static void + ft_mem_table_resize( FT_MemTable table ) + { + FT_Long new_size; + + + new_size = ft_mem_closest_prime( table->nodes ); + if ( new_size != table->size ) + { + FT_MemNode* new_buckets; + FT_Long i; + + + new_buckets = (FT_MemNode *) + ft_mem_table_alloc( + table, + new_size * (FT_Long)sizeof ( FT_MemNode ) ); + if ( !new_buckets ) + return; + + FT_ARRAY_ZERO( new_buckets, new_size ); + + for ( i = 0; i < table->size; i++ ) + { + FT_MemNode node, next, *pnode; + FT_PtrDist hash; + + + node = table->buckets[i]; + while ( node ) + { + next = node->link; + hash = FT_MEM_VAL( node->address ) % (FT_PtrDist)new_size; + pnode = new_buckets + hash; + + node->link = pnode[0]; + pnode[0] = node; + + node = next; + } + } + + if ( table->buckets ) + ft_mem_table_free( table, table->buckets ); + + table->buckets = new_buckets; + table->size = new_size; + } + } + + + static void + ft_mem_table_destroy( FT_MemTable table ) + { + FT_Long i; + FT_Long leak_count = 0; + FT_Long leaks = 0; + + + /* remove all blocks from the table, revealing leaked ones */ + for ( i = 0; i < table->size; i++ ) + { + FT_MemNode *pnode = table->buckets + i, next, node = *pnode; + + + while ( node ) + { + next = node->link; + node->link = NULL; + + if ( node->size > 0 ) + { + printf( + "leaked memory block at address %p, size %8ld in (%s:%ld)\n", + (void*)node->address, + node->size, + FT_FILENAME( node->source->file_name ), + node->source->line_no ); + + leak_count++; + leaks += node->size; + + ft_mem_table_free( table, node->address ); + } + + node->address = NULL; + node->size = 0; + + ft_mem_table_free( table, node ); + node = next; + } + table->buckets[i] = NULL; + } + + ft_mem_table_free( table, table->buckets ); + table->buckets = NULL; + + table->size = 0; + table->nodes = 0; + + /* remove all sources */ + for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ ) + { + FT_MemSource source, next; + + + for ( source = table->sources[i]; source != NULL; source = next ) + { + next = source->link; + ft_mem_table_free( table, source ); + } + + table->sources[i] = NULL; + } + + printf( "FreeType: total memory allocations = %ld\n", + table->alloc_total ); + printf( "FreeType: maximum memory footprint = %ld\n", + table->alloc_max ); + + if ( leak_count > 0 ) + ft_mem_debug_panic( + "FreeType: %ld bytes of memory leaked in %ld blocks\n", + leaks, leak_count ); + + printf( "FreeType: no memory leaks detected\n" ); + } + + + static FT_MemNode* + ft_mem_table_get_nodep( FT_MemTable table, + FT_Byte* address ) + { + FT_PtrDist hash; + FT_MemNode *pnode, node; + + + hash = FT_MEM_VAL( address ); + pnode = table->buckets + ( hash % (FT_PtrDist)table->size ); + + for (;;) + { + node = pnode[0]; + if ( !node ) + break; + + if ( node->address == address ) + break; + + pnode = &node->link; + } + return pnode; + } + + + static FT_MemSource + ft_mem_table_get_source( FT_MemTable table ) + { + FT_UInt32 hash; + FT_MemSource node, *pnode; + + + /* cast to FT_PtrDist first since void* can be larger */ + /* than FT_UInt32 and GCC 4.1.1 emits a warning */ + hash = (FT_UInt32)(FT_PtrDist)(void*)ft_debug_file_ + + (FT_UInt32)( 5 * ft_debug_lineno_ ); + pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS]; + + for (;;) + { + node = *pnode; + if ( !node ) + break; + + if ( node->file_name == ft_debug_file_ && + node->line_no == ft_debug_lineno_ ) + goto Exit; + + pnode = &node->link; + } + + node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) ); + if ( !node ) + ft_mem_debug_panic( + "not enough memory to perform memory debugging\n" ); + + node->file_name = ft_debug_file_; + node->line_no = ft_debug_lineno_; + + node->cur_blocks = 0; + node->max_blocks = 0; + node->all_blocks = 0; + + node->cur_size = 0; + node->max_size = 0; + node->all_size = 0; + + node->cur_max = 0; + + node->link = NULL; + node->hash = hash; + *pnode = node; + + Exit: + return node; + } + + + static void + ft_mem_table_set( FT_MemTable table, + FT_Byte* address, + FT_Long size, + FT_Long delta ) + { + FT_MemNode *pnode, node; + + + if ( table ) + { + FT_MemSource source; + + + pnode = ft_mem_table_get_nodep( table, address ); + node = *pnode; + if ( node ) + { + if ( node->size < 0 ) + { + /* This block was already freed. Our memory is now completely */ + /* corrupted! */ + /* This can only happen in keep-alive mode. */ + ft_mem_debug_panic( + "memory heap corrupted (allocating freed block)" ); + } + else + { + /* This block was already allocated. This means that our memory */ + /* is also corrupted! */ + ft_mem_debug_panic( + "memory heap corrupted (re-allocating allocated block at" + " %p, of size %ld)\n" + "org=%s:%d new=%s:%d\n", + node->address, node->size, + FT_FILENAME( node->source->file_name ), node->source->line_no, + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ ); + } + } + + /* we need to create a new node in this table */ + node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) ); + if ( !node ) + ft_mem_debug_panic( "not enough memory to run memory tests" ); + + node->address = address; + node->size = size; + node->source = source = ft_mem_table_get_source( table ); + + if ( delta == 0 ) + { + /* this is an allocation */ + source->all_blocks++; + source->cur_blocks++; + if ( source->cur_blocks > source->max_blocks ) + source->max_blocks = source->cur_blocks; + } + + if ( size > source->cur_max ) + source->cur_max = size; + + if ( delta != 0 ) + { + /* we are growing or shrinking a reallocated block */ + source->cur_size += delta; + table->alloc_current += delta; + } + else + { + /* we are allocating a new block */ + source->cur_size += size; + table->alloc_current += size; + } + + source->all_size += size; + + if ( source->cur_size > source->max_size ) + source->max_size = source->cur_size; + + node->free_file_name = NULL; + node->free_line_no = 0; + + node->link = pnode[0]; + + pnode[0] = node; + table->nodes++; + + table->alloc_total += size; + + if ( table->alloc_current > table->alloc_max ) + table->alloc_max = table->alloc_current; + + if ( table->nodes * 3 < table->size || + table->size * 3 < table->nodes ) + ft_mem_table_resize( table ); + } + } + + + static void + ft_mem_table_remove( FT_MemTable table, + FT_Byte* address, + FT_Long delta ) + { + if ( table ) + { + FT_MemNode *pnode, node; + + + pnode = ft_mem_table_get_nodep( table, address ); + node = *pnode; + if ( node ) + { + FT_MemSource source; + + + if ( node->size < 0 ) + ft_mem_debug_panic( + "freeing memory block at %p more than once\n" + " at (%s:%ld)!\n" + " Block was allocated at (%s:%ld)\n" + " and released at (%s:%ld).", + address, + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_, + FT_FILENAME( node->source->file_name ), node->source->line_no, + FT_FILENAME( node->free_file_name ), node->free_line_no ); + + /* scramble the node's content for additional safety */ + FT_MEM_SET( address, 0xF3, node->size ); + + if ( delta == 0 ) + { + source = node->source; + + source->cur_blocks--; + source->cur_size -= node->size; + + table->alloc_current -= node->size; + } + + if ( table->keep_alive ) + { + /* we simply invert the node's size to indicate that the node */ + /* was freed. */ + node->size = -node->size; + node->free_file_name = ft_debug_file_; + node->free_line_no = ft_debug_lineno_; + } + else + { + table->nodes--; + + *pnode = node->link; + + node->size = 0; + node->source = NULL; + + ft_mem_table_free( table, node ); + + if ( table->nodes * 3 < table->size || + table->size * 3 < table->nodes ) + ft_mem_table_resize( table ); + } + } + else + ft_mem_debug_panic( + "trying to free unknown block at %p in (%s:%ld)\n", + address, + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ ); + } + } + + + static FT_Pointer + ft_mem_debug_alloc( FT_Memory memory, + FT_Long size ) + { + FT_MemTable table = (FT_MemTable)memory->user; + FT_Byte* block; + + + if ( size <= 0 ) + ft_mem_debug_panic( "negative block size allocation (%ld)", size ); + + /* return NULL if the maximum number of allocations was reached */ + if ( table->bound_count && + table->alloc_count >= table->alloc_count_max ) + return NULL; + + /* return NULL if this allocation would overflow the maximum heap size */ + if ( table->bound_total && + table->alloc_total_max - table->alloc_current > size ) + return NULL; + + block = (FT_Byte *)ft_mem_table_alloc( table, size ); + if ( block ) + { + ft_mem_table_set( table, block, size, 0 ); + + table->alloc_count++; + } + + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; + + return (FT_Pointer)block; + } + + + static void + ft_mem_debug_free( FT_Memory memory, + FT_Pointer block ) + { + FT_MemTable table = (FT_MemTable)memory->user; + + + if ( !block ) + ft_mem_debug_panic( "trying to free NULL in (%s:%ld)", + FT_FILENAME( ft_debug_file_ ), + ft_debug_lineno_ ); + + ft_mem_table_remove( table, (FT_Byte*)block, 0 ); + + if ( !table->keep_alive ) + ft_mem_table_free( table, block ); + + table->alloc_count--; + + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; + } + + + static FT_Pointer + ft_mem_debug_realloc( FT_Memory memory, + FT_Long cur_size, + FT_Long new_size, + FT_Pointer block ) + { + FT_MemTable table = (FT_MemTable)memory->user; + FT_MemNode node, *pnode; + FT_Pointer new_block; + FT_Long delta; + + const char* file_name = FT_FILENAME( ft_debug_file_ ); + FT_Long line_no = ft_debug_lineno_; + + + /* unlikely, but possible */ + if ( new_size == cur_size ) + return block; + + /* the following is valid according to ANSI C */ +#if 0 + if ( !block || !cur_size ) + ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)", + file_name, line_no ); +#endif + + /* while the following is allowed in ANSI C also, we abort since */ + /* such case should be handled by FreeType. */ + if ( new_size <= 0 ) + ft_mem_debug_panic( + "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)", + block, cur_size, file_name, line_no ); + + /* check `cur_size' value */ + pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block ); + node = *pnode; + if ( !node ) + ft_mem_debug_panic( + "trying to reallocate unknown block at %p in (%s:%ld)", + block, file_name, line_no ); + + if ( node->size <= 0 ) + ft_mem_debug_panic( + "trying to reallocate freed block at %p in (%s:%ld)", + block, file_name, line_no ); + + if ( node->size != cur_size ) + ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is " + "%ld instead of %ld in (%s:%ld)", + block, cur_size, node->size, file_name, line_no ); + + /* return NULL if the maximum number of allocations was reached */ + if ( table->bound_count && + table->alloc_count >= table->alloc_count_max ) + return NULL; + + delta = new_size - cur_size; + + /* return NULL if this allocation would overflow the maximum heap size */ + if ( delta > 0 && + table->bound_total && + table->alloc_current + delta > table->alloc_total_max ) + return NULL; + + new_block = (FT_Pointer)ft_mem_table_alloc( table, new_size ); + if ( !new_block ) + return NULL; + + ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta ); + + ft_memcpy( new_block, block, cur_size < new_size ? (size_t)cur_size + : (size_t)new_size ); + + ft_mem_table_remove( table, (FT_Byte*)block, delta ); + + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; + + if ( !table->keep_alive ) + ft_mem_table_free( table, block ); + + return new_block; + } + + + extern void + ft_mem_debug_init( FT_Memory memory ) + { + FT_MemTable table; + + + if ( !ft_getenv( "FT2_DEBUG_MEMORY" ) ) + return; + + table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); + + if ( table ) + { + FT_ZERO( table ); + + table->memory = memory; + table->memory_user = memory->user; + table->alloc = memory->alloc; + table->realloc = memory->realloc; + table->free = memory->free; + + ft_mem_table_resize( table ); + + if ( table->size ) + { + const char* p; + + + memory->user = table; + memory->alloc = ft_mem_debug_alloc; + memory->realloc = ft_mem_debug_realloc; + memory->free = ft_mem_debug_free; + + p = ft_getenv( "FT2_ALLOC_TOTAL_MAX" ); + if ( p ) + { + FT_Long total_max = ft_strtol( p, NULL, 10 ); + + + if ( total_max > 0 ) + { + table->bound_total = 1; + table->alloc_total_max = total_max; + } + } + + p = ft_getenv( "FT2_ALLOC_COUNT_MAX" ); + if ( p ) + { + FT_Long total_count = ft_strtol( p, NULL, 10 ); + + + if ( total_count > 0 ) + { + table->bound_count = 1; + table->alloc_count_max = total_count; + } + } + + p = ft_getenv( "FT2_KEEP_ALIVE" ); + if ( p ) + { + FT_Long keep_alive = ft_strtol( p, NULL, 10 ); + + + if ( keep_alive > 0 ) + table->keep_alive = 1; + } + } + else + memory->free( memory, table ); + } + } + + + extern void + ft_mem_debug_done( FT_Memory memory ) + { + if ( memory->free == ft_mem_debug_free ) + { + FT_MemTable table = (FT_MemTable)memory->user; + + + FT_DumpMemory( memory ); + + ft_mem_table_destroy( table ); + + memory->free = table->free; + memory->realloc = table->realloc; + memory->alloc = table->alloc; + memory->user = table->memory_user; + + memory->free( memory, table ); + } + } + + + FT_COMPARE_DEF( int ) + ft_mem_source_compare( const void* p1, + const void* p2 ) + { + FT_MemSource s1 = *(FT_MemSource*)p1; + FT_MemSource s2 = *(FT_MemSource*)p2; + + + if ( s2->max_size > s1->max_size ) + return 1; + else if ( s2->max_size < s1->max_size ) + return -1; + else + return 0; + } + + + extern void + FT_DumpMemory( FT_Memory memory ) + { + if ( memory->free == ft_mem_debug_free ) + { + FT_MemTable table = (FT_MemTable)memory->user; + FT_MemSource* bucket = table->sources; + FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS; + FT_MemSource* sources; + FT_Int nn, count; + const char* fmt; + + + count = 0; + for ( ; bucket < limit; bucket++ ) + { + FT_MemSource source = *bucket; + + + for ( ; source; source = source->link ) + count++; + } + + sources = (FT_MemSource*) + ft_mem_table_alloc( + table, count * (FT_Long)sizeof ( *sources ) ); + + count = 0; + for ( bucket = table->sources; bucket < limit; bucket++ ) + { + FT_MemSource source = *bucket; + + + for ( ; source; source = source->link ) + sources[count++] = source; + } + + ft_qsort( sources, + (size_t)count, + sizeof ( *sources ), + ft_mem_source_compare ); + + printf( "FreeType Memory Dump: " + "current=%ld max=%ld total=%ld count=%ld\n", + table->alloc_current, table->alloc_max, + table->alloc_total, table->alloc_count ); + printf( " block block sizes sizes sizes source\n" ); + printf( " count high sum highsum max location\n" ); + printf( "-------------------------------------------------\n" ); + + fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n"; + + for ( nn = 0; nn < count; nn++ ) + { + FT_MemSource source = sources[nn]; + + + printf( fmt, + source->cur_blocks, source->max_blocks, + source->cur_size, source->max_size, source->cur_max, + FT_FILENAME( source->file_name ), + source->line_no ); + } + printf( "------------------------------------------------\n" ); + + ft_mem_table_free( table, sources ); + } + } + +#else /* !FT_DEBUG_MEMORY */ + + /* ANSI C doesn't like empty source files */ + typedef int debug_mem_dummy_; + +#endif /* !FT_DEBUG_MEMORY */ + + +/* END */ diff --git a/vendor/freetype/src/base/ftdebug.c b/vendor/freetype/src/base/ftdebug.c new file mode 100644 index 0000000..61c4563 --- /dev/null +++ b/vendor/freetype/src/base/ftdebug.c @@ -0,0 +1,644 @@ +/**************************************************************************** + * + * ftdebug.c + * + * Debugging and logging component (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component contains various macros and functions used to ease the + * debugging of the FreeType engine. Its main purpose is in assertion + * checking, tracing, and error detection. + * + * There are now three debugging modes: + * + * - trace mode + * + * Error and trace messages are sent to the log file (which can be the + * standard error output). + * + * - error mode + * + * Only error messages are generated. + * + * - release mode: + * + * No error message is sent or generated. The code is free from any + * debugging parts. + * + */ + + +#include +#include +#include +#include + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Variables used to control logging. + * + * 1. `ft_default_trace_level` stores the value of trace levels, which are + * provided to FreeType using the `FT2_DEBUG` environment variable. + * + * 2. `ft_fileptr` stores the `FILE*` handle. + * + * 3. `ft_component` is a string that holds the name of `FT_COMPONENT`. + * + * 4. The flag `ft_component_flag` prints the name of `FT_COMPONENT` along + * with the actual log message if set to true. + * + * 5. The flag `ft_timestamp_flag` prints time along with the actual log + * message if set to ture. + * + * 6. `ft_have_newline_char` is used to differentiate between a log + * message with and without a trailing newline character. + * + * 7. `ft_custom_trace_level` stores the custom trace level value, which + * is provided by the user at run-time. + * + * We use `static` to avoid 'unused variable' warnings. + * + */ + static const char* ft_default_trace_level = NULL; + static FILE* ft_fileptr = NULL; + static const char* ft_component = NULL; + static FT_Bool ft_component_flag = FALSE; + static FT_Bool ft_timestamp_flag = FALSE; + static FT_Bool ft_have_newline_char = TRUE; + static const char* ft_custom_trace_level = NULL; + + /* declared in ftdebug.h */ + + dlg_handler ft_default_log_handler = NULL; + FT_Custom_Log_Handler custom_output_handler = NULL; + +#endif /* FT_DEBUG_LOGGING */ + + +#ifdef FT_DEBUG_LEVEL_ERROR + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Message( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Panic( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + + exit( EXIT_FAILURE ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( int ) + FT_Throw( FT_Error error, + int line, + const char* file ) + { +#if 0 + /* activating the code in this block makes FreeType very chatty */ + fprintf( stderr, + "%s:%d: error 0x%02x: %s\n", + file, + line, + error, + FT_Error_String( error ) ); +#else + FT_UNUSED( error ); + FT_UNUSED( line ); + FT_UNUSED( file ); +#endif + + return 0; + } + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* array of trace levels, initialized to 0; */ + /* this gets adjusted at run-time */ + static int ft_trace_levels_enabled[trace_count]; + + /* array of trace levels, always initialized to 0 */ + static int ft_trace_levels_disabled[trace_count]; + + /* a pointer to either `ft_trace_levels_enabled' */ + /* or `ft_trace_levels_disabled' */ + int* ft_trace_levels; + + /* define array of trace toggle names */ +#define FT_TRACE_DEF( x ) #x , + + static const char* ft_trace_toggles[trace_count + 1] = + { +#include + NULL + }; + +#undef FT_TRACE_DEF + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return trace_count; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + int max = FT_Trace_Get_Count(); + + + if ( idx < max ) + return ft_trace_toggles[idx]; + else + return NULL; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + ft_trace_levels = ft_trace_levels_disabled; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + ft_trace_levels = ft_trace_levels_enabled; + } + + + /************************************************************************** + * + * Initialize the tracing sub-system. This is done by retrieving the + * value of the `FT2_DEBUG' environment variable. It must be a list of + * toggles, separated by spaces, `;', or `,'. Example: + * + * export FT2_DEBUG="any:3 memory:7 stream:5" + * + * This requests that all levels be set to 3, except the trace level for + * the memory and stream components which are set to 7 and 5, + * respectively. + * + * See the file `include/freetype/internal/fttrace.h' for details of + * the available toggle names. + * + * The level must be between 0 and 7; 0 means quiet (except for serious + * runtime errors), and 7 means _very_ verbose. + */ + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + const char* ft2_debug = NULL; + + +#ifdef FT_DEBUG_LOGGING + if ( ft_custom_trace_level != NULL ) + ft2_debug = ft_custom_trace_level; + else + ft2_debug = ft_default_trace_level; +#else + ft2_debug = ft_getenv( "FT2_DEBUG" ); +#endif + + if ( ft2_debug ) + { + const char* p = ft2_debug; + const char* q; + + + for ( ; *p; p++ ) + { + /* skip leading whitespace and separators */ + if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' ) + continue; + +#ifdef FT_DEBUG_LOGGING + + /* check extra arguments for logging */ + if ( *p == '-' ) + { + const char* r = ++p; + + + if ( *r == 'v' ) + { + const char* s = ++r; + + + ft_component_flag = TRUE; + + if ( *s == 't' ) + { + ft_timestamp_flag = TRUE; + p++; + } + + p++; + } + + else if ( *r == 't' ) + { + const char* s = ++r; + + + ft_timestamp_flag = TRUE; + + if ( *s == 'v' ) + { + ft_component_flag = TRUE; + p++; + } + + p++; + } + } + +#endif /* FT_DEBUG_LOGGING */ + + /* read toggle name, followed by ':' */ + q = p; + while ( *p && *p != ':' ) + p++; + + if ( !*p ) + break; + + if ( *p == ':' && p > q ) + { + FT_Int n, i, len = (FT_Int)( p - q ); + FT_Int level = -1, found = -1; + + + for ( n = 0; n < trace_count; n++ ) + { + const char* toggle = ft_trace_toggles[n]; + + + for ( i = 0; i < len; i++ ) + { + if ( toggle[i] != q[i] ) + break; + } + + if ( i == len && toggle[i] == 0 ) + { + found = n; + break; + } + } + + /* read level */ + p++; + if ( *p ) + { + level = *p - '0'; + if ( level < 0 || level > 7 ) + level = -1; + } + + if ( found >= 0 && level >= 0 ) + { + if ( found == trace_any ) + { + /* special case for `any' */ + for ( n = 0; n < trace_count; n++ ) + ft_trace_levels_enabled[n] = level; + } + else + ft_trace_levels_enabled[found] = level; + } + } + } + } + + ft_trace_levels = ft_trace_levels_enabled; + } + + +#else /* !FT_DEBUG_LEVEL_TRACE */ + + + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + /* nothing */ + } + + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return 0; + } + + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + FT_UNUSED( idx ); + + return NULL; + } + + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + /* nothing */ + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Initialize and de-initialize 'dlg' library. + * + */ + + FT_BASE_DEF( void ) + ft_logging_init( void ) + { + ft_default_log_handler = ft_log_handler; + ft_default_trace_level = ft_getenv( "FT2_DEBUG" ); + + if ( ft_getenv( "FT_LOGGING_FILE" ) ) + ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" ); + else + ft_fileptr = stderr; + + ft_debug_init(); + + /* Set the default output handler for 'dlg'. */ + dlg_set_handler( ft_default_log_handler, NULL ); + } + + + FT_BASE_DEF( void ) + ft_logging_deinit( void ) + { + if ( ft_fileptr != stderr ) + ft_fclose( ft_fileptr ); + } + + + /************************************************************************** + * + * An output log handler for FreeType. + * + */ + FT_BASE_DEF( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ) + { + char features_buf[128]; + char* bufp = features_buf; + + FT_UNUSED( data ); + + + if ( ft_have_newline_char ) + { + const char* features = NULL; + size_t features_length = 0; + + +#define FEATURES_TIMESTAMP "[%h:%m] " +#define FEATURES_COMPONENT "[%t] " +#define FEATURES_TIMESTAMP_COMPONENT "[%h:%m %t] " + + if ( ft_timestamp_flag && ft_component_flag ) + { + features = FEATURES_TIMESTAMP_COMPONENT; + features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT ); + } + else if ( ft_timestamp_flag ) + { + features = FEATURES_TIMESTAMP; + features_length = sizeof ( FEATURES_TIMESTAMP ); + } + else if ( ft_component_flag ) + { + features = FEATURES_COMPONENT; + features_length = sizeof ( FEATURES_COMPONENT ); + } + + if ( ft_component_flag || ft_timestamp_flag ) + { + ft_strncpy( features_buf, features, features_length ); + bufp += features_length - 1; + } + + if ( ft_component_flag ) + { + size_t tag_length = ft_strlen( *origin->tags ); + size_t i; + + + /* To vertically align tracing messages we compensate the */ + /* different FT_COMPONENT string lengths by inserting an */ + /* appropriate amount of space characters. */ + for ( i = 0; + i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length; + i++ ) + *bufp++ = ' '; + } + } + + /* Finally add the format string for the tracing message. */ + *bufp++ = '%'; + *bufp++ = 'c'; + *bufp = '\0'; + + dlg_generic_outputf_stream( ft_fileptr, + (const char*)features_buf, + origin, + string, + dlg_default_output_styles, + true ); + + if ( ft_strrchr( string, '\n' ) ) + ft_have_newline_char = TRUE; + else + ft_have_newline_char = FALSE; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_add_tag( const char* tag ) + { + ft_component = tag; + + dlg_add_tag( tag, NULL ); + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_remove_tag( const char* tag ) + { + dlg_remove_tag( tag, NULL ); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = level; + + ft_debug_init(); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = NULL; + + ft_debug_init(); + } + + + /************************************************************************** + * + * Functions to handle a custom log handler. + * + */ + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + custom_output_handler = handler; + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + custom_output_handler = NULL; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + FT_Logging_Callback( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + custom_output_handler( ft_component, fmt, ap ); + va_end( ap ); + } + +#else /* !FT_DEBUG_LOGGING */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + FT_UNUSED( level ); + } + + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + /* nothing */ + } + + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + FT_UNUSED( handler ); + } + + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LOGGING */ + + +/* END */ diff --git a/vendor/freetype/src/base/fterrors.c b/vendor/freetype/src/base/fterrors.c new file mode 100644 index 0000000..5ad9709 --- /dev/null +++ b/vendor/freetype/src/base/fterrors.c @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * fterrors.c + * + * FreeType API for error code handling. + * + * Copyright (C) 2018-2023 by + * Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + + + /* documentation is in fterrors.h */ + + FT_EXPORT_DEF( const char* ) + FT_Error_String( FT_Error error_code ) + { + if ( error_code < 0 || + error_code >= FT_ERR_CAT( FT_ERR_PREFIX, Max ) ) + return NULL; + +#if defined( FT_CONFIG_OPTION_ERROR_STRINGS ) || \ + defined( FT_DEBUG_LEVEL_ERROR ) + +#undef FTERRORS_H_ +#define FT_ERROR_START_LIST switch ( FT_ERROR_BASE( error_code ) ) { +#define FT_ERRORDEF( e, v, s ) case v: return s; +#define FT_ERROR_END_LIST } + +#include + +#endif /* defined( FT_CONFIG_OPTION_ERROR_STRINGS ) || ... */ + + return NULL; + } diff --git a/vendor/freetype/src/base/ftfntfmt.c b/vendor/freetype/src/base/ftfntfmt.c new file mode 100644 index 0000000..0b41f7c --- /dev/null +++ b/vendor/freetype/src/base/ftfntfmt.c @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * ftfntfmt.c + * + * FreeType utility file for font formats (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + + + /* documentation is in ftfntfmt.h */ + + FT_EXPORT_DEF( const char* ) + FT_Get_Font_Format( FT_Face face ) + { + const char* result = NULL; + + + if ( face ) + FT_FACE_FIND_SERVICE( face, result, FONT_FORMAT ); + + return result; + } + + + /* deprecated function name; retained for ABI compatibility */ + + FT_EXPORT_DEF( const char* ) + FT_Get_X11_Font_Format( FT_Face face ) + { + const char* result = NULL; + + + if ( face ) + FT_FACE_FIND_SERVICE( face, result, FONT_FORMAT ); + + return result; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftfstype.c b/vendor/freetype/src/base/ftfstype.c new file mode 100644 index 0000000..ea24e64 --- /dev/null +++ b/vendor/freetype/src/base/ftfstype.c @@ -0,0 +1,61 @@ +/**************************************************************************** + * + * ftfstype.c + * + * FreeType utility file to access FSType data (body). + * + * Copyright (C) 2008-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UShort ) + FT_Get_FSType_Flags( FT_Face face ) + { + TT_OS2* os2; + + + /* first, try to get the fs_type directly from the font */ + if ( face ) + { + FT_Service_PsInfo service = NULL; + + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_extra ) + { + PS_FontExtraRec extra; + + + if ( !service->ps_get_font_extra( face, &extra ) && + extra.fs_type != 0 ) + return extra.fs_type; + } + } + + /* look at FSType before fsType for Type42 */ + + if ( ( os2 = (TT_OS2*)FT_Get_Sfnt_Table( face, FT_SFNT_OS2 ) ) != NULL && + os2->version != 0xFFFFU ) + return os2->fsType; + + return 0; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftgasp.c b/vendor/freetype/src/base/ftgasp.c new file mode 100644 index 0000000..29b7b08 --- /dev/null +++ b/vendor/freetype/src/base/ftgasp.c @@ -0,0 +1,60 @@ +/**************************************************************************** + * + * ftgasp.c + * + * Access of TrueType's `gasp' table (body). + * + * Copyright (C) 2007-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + + + FT_EXPORT_DEF( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ) + { + FT_Int result = FT_GASP_NO_TABLE; + + + if ( face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( ttface->gasp.numRanges > 0 ) + { + TT_GaspRange range = ttface->gasp.gaspRanges; + TT_GaspRange range_end = range + ttface->gasp.numRanges; + + + while ( ppem > range->maxPPEM ) + { + range++; + if ( range >= range_end ) + goto Exit; + } + + result = range->gaspFlag; + + /* ensure that we don't have spurious bits */ + if ( ttface->gasp.version == 0 ) + result &= 3; + } + } + Exit: + return result; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftgloadr.c b/vendor/freetype/src/base/ftgloadr.c new file mode 100644 index 0000000..9823d09 --- /dev/null +++ b/vendor/freetype/src/base/ftgloadr.c @@ -0,0 +1,392 @@ +/**************************************************************************** + * + * ftgloadr.c + * + * The FreeType glyph loader (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT gloader + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** G L Y P H L O A D E R *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * The glyph loader is a simple object which is used to load a set of + * glyphs easily. It is critical for the correct loading of composites. + * + * Ideally, one can see it as a stack of abstract `glyph' objects. + * + * loader.base Is really the bottom of the stack. It describes a + * single glyph image made of the juxtaposition of + * several glyphs (those `in the stack'). + * + * loader.current Describes the top of the stack, on which a new + * glyph can be loaded. + * + * Rewind Clears the stack. + * Prepare Set up `loader.current' for addition of a new glyph + * image. + * Add Add the `current' glyph image to the `base' one, + * and prepare for another one. + * + * The glyph loader is now a base object. Each driver used to + * re-implement it in one way or the other, which wasted code and + * energy. + * + */ + + + /* create a new glyph loader */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ) + { + FT_GlyphLoader loader = NULL; + FT_Error error; + + + if ( !FT_NEW( loader ) ) + { + loader->memory = memory; + *aloader = loader; + } + return error; + } + + + /* rewind the glyph loader - reset counters to 0 */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) + { + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + + + base->outline.n_points = 0; + base->outline.n_contours = 0; + base->outline.flags = 0; + base->num_subglyphs = 0; + + *current = *base; + } + + + /* reset glyph loader, free all allocated tables, */ + /* and start from zero */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ) + { + FT_Memory memory = loader->memory; + + + FT_FREE( loader->base.outline.points ); + FT_FREE( loader->base.outline.tags ); + FT_FREE( loader->base.outline.contours ); + FT_FREE( loader->base.extra_points ); + FT_FREE( loader->base.subglyphs ); + + loader->base.extra_points2 = NULL; + + loader->max_points = 0; + loader->max_contours = 0; + loader->max_subglyphs = 0; + + FT_GlyphLoader_Rewind( loader ); + } + + + /* delete a glyph loader */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ) + { + if ( loader ) + { + FT_Memory memory = loader->memory; + + + FT_GlyphLoader_Reset( loader ); + FT_FREE( loader ); + } + } + + + /* re-adjust the `current' outline fields */ + static void + FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader ) + { + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + + + current->points = FT_OFFSET( base->points, base->n_points ); + current->tags = FT_OFFSET( base->tags, base->n_points ); + current->contours = FT_OFFSET( base->contours, base->n_contours ); + + /* handle extra points table - if any */ + if ( loader->use_extra ) + { + loader->current.extra_points = loader->base.extra_points + + base->n_points; + + loader->current.extra_points2 = loader->base.extra_points2 + + base->n_points; + } + } + + + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ) + { + FT_Error error; + FT_Memory memory = loader->memory; + + + if ( loader->max_points == 0 || + loader->base.extra_points != NULL ) + return FT_Err_Ok; + + if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) + { + loader->use_extra = 1; + loader->base.extra_points2 = loader->base.extra_points + + loader->max_points; + + FT_GlyphLoader_Adjust_Points( loader ); + } + return error; + } + + + /* re-adjust the `current' subglyphs field */ + static void + FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) + { + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + + + current->subglyphs = FT_OFFSET( base->subglyphs, base->num_subglyphs ); + } + + + /* Ensure that we can add `n_points' and `n_contours' to our glyph. */ + /* This function reallocates its outline tables if necessary. Note that */ + /* it DOESN'T change the number of points within the loader! */ + /* */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + FT_Bool adjust = 0; + + FT_UInt new_max, old_max, min_new_max; + + + error = FT_GlyphLoader_CreateExtra( loader ); + if ( error ) + goto Exit; + + /* check points & tags */ + new_max = (FT_UInt)base->n_points + (FT_UInt)current->n_points + + n_points; + old_max = loader->max_points; + + if ( new_max > old_max ) + { + if ( new_max > FT_OUTLINE_POINTS_MAX ) + { + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + min_new_max = old_max + ( old_max >> 1 ); + if ( new_max < min_new_max ) + new_max = min_new_max; + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( new_max > FT_OUTLINE_POINTS_MAX ) + new_max = FT_OUTLINE_POINTS_MAX; + + if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || + FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) + goto Exit; + + if ( loader->use_extra ) + { + if ( FT_RENEW_ARRAY( loader->base.extra_points, + old_max * 2, new_max * 2 ) ) + goto Exit; + + FT_ARRAY_MOVE( loader->base.extra_points + new_max, + loader->base.extra_points + old_max, + old_max ); + + loader->base.extra_points2 = loader->base.extra_points + new_max; + } + + adjust = 1; + loader->max_points = new_max; + } + + error = FT_GlyphLoader_CreateExtra( loader ); + if ( error ) + goto Exit; + + /* check contours */ + old_max = loader->max_contours; + new_max = (FT_UInt)base->n_contours + (FT_UInt)current->n_contours + + n_contours; + if ( new_max > old_max ) + { + if ( new_max > FT_OUTLINE_CONTOURS_MAX ) + { + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + min_new_max = old_max + ( old_max >> 1 ); + if ( new_max < min_new_max ) + new_max = min_new_max; + new_max = FT_PAD_CEIL( new_max, 4 ); + if ( new_max > FT_OUTLINE_CONTOURS_MAX ) + new_max = FT_OUTLINE_CONTOURS_MAX; + + if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) + goto Exit; + + adjust = 1; + loader->max_contours = new_max; + } + + if ( adjust ) + FT_GlyphLoader_Adjust_Points( loader ); + + Exit: + if ( error ) + FT_GlyphLoader_Reset( loader ); + + return error; + } + + + /* Ensure that we can add `n_subglyphs' to our glyph. this function */ + /* reallocates its subglyphs table if necessary. Note that it DOES */ + /* NOT change the number of subglyphs within the loader! */ + /* */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_UInt new_max, old_max; + + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + + + new_max = base->num_subglyphs + current->num_subglyphs + n_subs; + old_max = loader->max_subglyphs; + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 2 ); + if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) + goto Exit; + + loader->max_subglyphs = new_max; + + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } + + Exit: + return error; + } + + + /* prepare loader for the addition of a new glyph on top of the base one */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) + { + FT_GlyphLoad current = &loader->current; + + + current->outline.n_points = 0; + current->outline.n_contours = 0; + current->num_subglyphs = 0; + + FT_GlyphLoader_Adjust_Points ( loader ); + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } + + + /* add current glyph to the base image -- and prepare for another */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ) + { + FT_GlyphLoad base; + FT_GlyphLoad current; + + FT_Int n_curr_contours; + FT_Int n_base_points; + FT_Int n; + + + if ( !loader ) + return; + + base = &loader->base; + current = &loader->current; + + n_curr_contours = current->outline.n_contours; + n_base_points = base->outline.n_points; + + base->outline.n_points = + (short)( base->outline.n_points + current->outline.n_points ); + base->outline.n_contours = + (short)( base->outline.n_contours + current->outline.n_contours ); + + base->num_subglyphs += current->num_subglyphs; + + /* adjust contours count in newest outline */ + for ( n = 0; n < n_curr_contours; n++ ) + current->outline.contours[n] = + (short)( current->outline.contours[n] + n_base_points ); + + /* prepare for another new glyph image */ + FT_GlyphLoader_Prepare( loader ); + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftglyph.c b/vendor/freetype/src/base/ftglyph.c new file mode 100644 index 0000000..393d494 --- /dev/null +++ b/vendor/freetype/src/base/ftglyph.c @@ -0,0 +1,911 @@ +/**************************************************************************** + * + * ftglyph.c + * + * FreeType convenience functions to handle glyphs (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file contains the definition of several convenience functions + * that can be used by client applications to easily retrieve glyph + * bitmaps and outlines from a given face. + * + * These functions should be optional if you are writing a font server + * or text layout engine on top of FreeType. However, they are pretty + * handy for many other simple uses of the library. + * + */ + + +#include + +#include +#include +#include +#include +#include + +#include "ftbase.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT glyph + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_BitmapGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( FT_Error ) + ft_bitmap_glyph_init( FT_Glyph bitmap_glyph, + FT_GlyphSlot slot ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH( glyph )->library; + + + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + glyph->left = slot->bitmap_left; + glyph->top = slot->bitmap_top; + + /* do lazy copying whenever possible */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + glyph->bitmap = slot->bitmap; + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + FT_Bitmap_Init( &glyph->bitmap ); + error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap ); + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_bitmap_glyph_copy( FT_Glyph bitmap_source, + FT_Glyph bitmap_target ) + { + FT_Library library = bitmap_source->library; + FT_BitmapGlyph source = (FT_BitmapGlyph)bitmap_source; + FT_BitmapGlyph target = (FT_BitmapGlyph)bitmap_target; + + + target->left = source->left; + target->top = source->top; + + return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap ); + } + + + FT_CALLBACK_DEF( void ) + ft_bitmap_glyph_done( FT_Glyph bitmap_glyph ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + FT_Library library = FT_GLYPH( glyph )->library; + + + FT_Bitmap_Done( library, &glyph->bitmap ); + } + + + FT_CALLBACK_DEF( void ) + ft_bitmap_glyph_bbox( FT_Glyph bitmap_glyph, + FT_BBox* cbox ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + + + cbox->xMin = glyph->left * 64; + cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 ); + cbox->yMax = glyph->top * 64; + cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 ); + } + + + FT_DEFINE_GLYPH( + ft_bitmap_glyph_class, + + sizeof ( FT_BitmapGlyphRec ), + FT_GLYPH_FORMAT_BITMAP, + + ft_bitmap_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_bitmap_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_bitmap_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + NULL, /* FT_Glyph_TransformFunc glyph_transform */ + ft_bitmap_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + NULL /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_OutlineGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_init( FT_Glyph outline_glyph, + FT_GlyphSlot slot ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH( glyph )->library; + FT_Outline* source = &slot->outline; + FT_Outline* target = &glyph->outline; + + + /* check format in glyph slot */ + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* allocate new outline */ + error = FT_Outline_New( library, + (FT_UInt)source->n_points, + source->n_contours, + &glyph->outline ); + if ( error ) + goto Exit; + + FT_Outline_Copy( source, target ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_outline_glyph_done( FT_Glyph outline_glyph ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_copy( FT_Glyph outline_source, + FT_Glyph outline_target ) + { + FT_OutlineGlyph source = (FT_OutlineGlyph)outline_source; + FT_OutlineGlyph target = (FT_OutlineGlyph)outline_target; + FT_Error error; + FT_Library library = FT_GLYPH( source )->library; + + + error = FT_Outline_New( library, + (FT_UInt)source->outline.n_points, + source->outline.n_contours, + &target->outline ); + if ( !error ) + FT_Outline_Copy( &source->outline, &target->outline ); + + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_outline_glyph_transform( FT_Glyph outline_glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + if ( matrix ) + FT_Outline_Transform( &glyph->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); + } + + + FT_CALLBACK_DEF( void ) + ft_outline_glyph_bbox( FT_Glyph outline_glyph, + FT_BBox* bbox ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + FT_Outline_Get_CBox( &glyph->outline, bbox ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_prepare( FT_Glyph outline_glyph, + FT_GlyphSlot slot ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + slot->format = FT_GLYPH_FORMAT_OUTLINE; + slot->outline = glyph->outline; + slot->outline.flags &= ~FT_OUTLINE_OWNER; + + return FT_Err_Ok; + } + + + FT_DEFINE_GLYPH( + ft_outline_glyph_class, + + sizeof ( FT_OutlineGlyphRec ), + FT_GLYPH_FORMAT_OUTLINE, + + ft_outline_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_outline_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_outline_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + ft_outline_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ + ft_outline_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + ft_outline_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + + +#ifdef FT_CONFIG_OPTION_SVG + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_SvgGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_init( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_ULong doc_length; + FT_SVG_Document document; + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( glyph )->library->memory; + + + if ( slot->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( slot->other == NULL ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + document = (FT_SVG_Document)slot->other; + + if ( document->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + /* allocate a new document */ + doc_length = document->svg_document_length; + if ( FT_QALLOC( glyph->svg_document, doc_length ) ) + goto Exit; + glyph->svg_document_length = doc_length; + + glyph->glyph_index = slot->glyph_index; + + glyph->metrics = document->metrics; + glyph->units_per_EM = document->units_per_EM; + + glyph->start_glyph_id = document->start_glyph_id; + glyph->end_glyph_id = document->end_glyph_id; + + glyph->transform = document->transform; + glyph->delta = document->delta; + + /* copy the document into glyph */ + FT_MEM_COPY( glyph->svg_document, document->svg_document, doc_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_done( FT_Glyph svg_glyph ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Memory memory = svg_glyph->library->memory; + + + /* just free the memory */ + FT_FREE( glyph->svg_document ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_copy( FT_Glyph svg_source, + FT_Glyph svg_target ) + { + FT_SvgGlyph source = (FT_SvgGlyph)svg_source; + FT_SvgGlyph target = (FT_SvgGlyph)svg_target; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( source )->library->memory; + + + if ( svg_source->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( source->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + target->glyph_index = source->glyph_index; + + target->svg_document_length = source->svg_document_length; + + target->metrics = source->metrics; + target->units_per_EM = source->units_per_EM; + + target->start_glyph_id = source->start_glyph_id; + target->end_glyph_id = source->end_glyph_id; + + target->transform = source->transform; + target->delta = source->delta; + + /* allocate space for the SVG document */ + if ( FT_QALLOC( target->svg_document, target->svg_document_length ) ) + goto Exit; + + /* copy the document */ + FT_MEM_COPY( target->svg_document, + source->svg_document, + target->svg_document_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_transform( FT_Glyph svg_glyph, + const FT_Matrix* _matrix, + const FT_Vector* _delta ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Matrix* matrix = (FT_Matrix*)_matrix; + FT_Vector* delta = (FT_Vector*)_delta; + + FT_Matrix tmp_matrix; + FT_Vector tmp_delta; + + FT_Matrix a, b; + FT_Pos x, y; + + + if ( !matrix ) + { + tmp_matrix.xx = 0x10000; + tmp_matrix.xy = 0; + tmp_matrix.yx = 0; + tmp_matrix.yy = 0x10000; + + matrix = &tmp_matrix; + } + + if ( !delta ) + { + tmp_delta.x = 0; + tmp_delta.y = 0; + + delta = &tmp_delta; + } + + a = glyph->transform; + b = *matrix; + FT_Matrix_Multiply( &b, &a ); + + x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, glyph->delta.x ), + FT_MulFix( matrix->xy, glyph->delta.y ) ), + delta->x ); + y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, glyph->delta.x ), + FT_MulFix( matrix->yy, glyph->delta.y ) ), + delta->y ); + + glyph->delta.x = x; + glyph->delta.y = y; + + glyph->transform = a; + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_prepare( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = svg_glyph->library->memory; + + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + return error; + + document->svg_document = glyph->svg_document; + document->svg_document_length = glyph->svg_document_length; + + document->metrics = glyph->metrics; + document->units_per_EM = glyph->units_per_EM; + + document->start_glyph_id = glyph->start_glyph_id; + document->end_glyph_id = glyph->end_glyph_id; + + document->transform = glyph->transform; + document->delta = glyph->delta; + + slot->format = FT_GLYPH_FORMAT_SVG; + slot->glyph_index = glyph->glyph_index; + slot->other = document; + + return error; + } + + + FT_DEFINE_GLYPH( + ft_svg_glyph_class, + + sizeof ( FT_SvgGlyphRec ), + FT_GLYPH_FORMAT_SVG, + + ft_svg_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_svg_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_svg_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + ft_svg_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ + NULL, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + ft_svg_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + +#endif /* FT_CONFIG_OPTION_SVG */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_Glyph class and API ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + ft_new_glyph( FT_Library library, + const FT_Glyph_Class* clazz, + FT_Glyph* aglyph ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Glyph glyph = NULL; + + + *aglyph = NULL; + + if ( !FT_ALLOC( glyph, clazz->glyph_size ) ) + { + glyph->library = library; + glyph->clazz = clazz; + glyph->format = clazz->glyph_format; + + *aglyph = glyph; + } + + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ) + { + FT_Glyph copy; + FT_Error error; + const FT_Glyph_Class* clazz; + + + /* check arguments */ + if ( !target || !source || !source->clazz ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + *target = NULL; + + if ( !source || !source->clazz ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + clazz = source->clazz; + error = ft_new_glyph( source->library, clazz, © ); + if ( error ) + goto Exit; + + copy->advance = source->advance; + copy->format = source->format; + + if ( clazz->glyph_copy ) + error = clazz->glyph_copy( source, copy ); + + if ( error ) + FT_Done_Glyph( copy ); + else + *target = copy; + + Exit: + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT( FT_Error ) + FT_New_Glyph( FT_Library library, + FT_Glyph_Format format, + FT_Glyph *aglyph ) + { + const FT_Glyph_Class* clazz = NULL; + + if ( !library || !aglyph ) + return FT_THROW( Invalid_Argument ); + + /* if it is a bitmap, that's easy :-) */ + if ( format == FT_GLYPH_FORMAT_BITMAP ) + clazz = &ft_bitmap_glyph_class; + + /* if it is an outline */ + else if ( format == FT_GLYPH_FORMAT_OUTLINE ) + clazz = &ft_outline_glyph_class; + +#ifdef FT_CONFIG_OPTION_SVG + /* if it is an SVG glyph */ + else if ( format == FT_GLYPH_FORMAT_SVG ) + clazz = &ft_svg_glyph_class; +#endif + + else + { + /* try to find a renderer that supports the glyph image format */ + FT_Renderer render = FT_Lookup_Renderer( library, format, 0 ); + + + if ( render ) + clazz = &render->glyph_class; + } + + if ( !clazz ) + return FT_THROW( Invalid_Glyph_Format ); + + /* create FT_Glyph object */ + return ft_new_glyph( library, clazz, aglyph ); + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ) + { + FT_Error error; + FT_Glyph glyph; + + + if ( !slot ) + return FT_THROW( Invalid_Slot_Handle ); + + if ( !aglyph ) + return FT_THROW( Invalid_Argument ); + + /* create FT_Glyph object */ + error = FT_New_Glyph( slot->library, slot->format, &glyph ); + if ( error ) + goto Exit; + + /* copy advance while converting 26.6 to 16.16 format */ + if ( slot->advance.x >= 0x8000L * 64 || + slot->advance.x <= -0x8000L * 64 ) + { + FT_ERROR(( "FT_Get_Glyph: advance width too large\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit2; + } + if ( slot->advance.y >= 0x8000L * 64 || + slot->advance.y <= -0x8000L * 64 ) + { + FT_ERROR(( "FT_Get_Glyph: advance height too large\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit2; + } + + glyph->advance.x = slot->advance.x * 1024; + glyph->advance.y = slot->advance.y * 1024; + + /* now import the image from the glyph slot */ + error = glyph->clazz->glyph_init( glyph, slot ); + + Exit2: + /* if an error occurred, destroy the glyph */ + if ( error ) + { + FT_Done_Glyph( glyph ); + *aglyph = NULL; + } + else + *aglyph = glyph; + + Exit: + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( !glyph || !glyph->clazz ) + error = FT_THROW( Invalid_Argument ); + else + { + const FT_Glyph_Class* clazz = glyph->clazz; + + + if ( clazz->glyph_transform ) + { + /* transform glyph image */ + clazz->glyph_transform( glyph, matrix, delta ); + + /* transform advance vector */ + if ( matrix ) + FT_Vector_Transform( &glyph->advance, matrix ); + } + else + error = FT_THROW( Invalid_Glyph_Format ); + } + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ) + { + const FT_Glyph_Class* clazz; + + + if ( !acbox ) + return; + + acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0; + + if ( !glyph || !glyph->clazz ) + return; + + clazz = glyph->clazz; + if ( !clazz->glyph_bbox ) + return; + + /* retrieve bbox in 26.6 coordinates */ + clazz->glyph_bbox( glyph, acbox ); + + /* perform grid fitting if needed */ + if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT || + bbox_mode == FT_GLYPH_BBOX_PIXELS ) + { + acbox->xMin = FT_PIX_FLOOR( acbox->xMin ); + acbox->yMin = FT_PIX_FLOOR( acbox->yMin ); + acbox->xMax = FT_PIX_CEIL_LONG( acbox->xMax ); + acbox->yMax = FT_PIX_CEIL_LONG( acbox->yMax ); + } + + /* convert to integer pixels if needed */ + if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE || + bbox_mode == FT_GLYPH_BBOX_PIXELS ) + { + acbox->xMin >>= 6; + acbox->yMin >>= 6; + acbox->xMax >>= 6; + acbox->yMax >>= 6; + } + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ) + { + FT_GlyphSlotRec dummy; + FT_GlyphSlot_InternalRec dummy_internal; + FT_Error error = FT_Err_Ok; + FT_Glyph b, glyph; + FT_BitmapGlyph bitmap = NULL; + const FT_Glyph_Class* clazz; + + FT_Library library; + + + /* check argument */ + if ( !the_glyph ) + goto Bad; + glyph = *the_glyph; + if ( !glyph ) + goto Bad; + + clazz = glyph->clazz; + library = glyph->library; + if ( !library || !clazz ) + goto Bad; + + /* when called with a bitmap glyph, do nothing and return successfully */ + if ( clazz == &ft_bitmap_glyph_class ) + goto Exit; + + if ( !clazz->glyph_prepare ) + goto Bad; + + /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ + /* then calling FT_Render_Glyph_Internal() */ + + FT_ZERO( &dummy ); + FT_ZERO( &dummy_internal ); + dummy.internal = &dummy_internal; + dummy.library = library; + dummy.format = clazz->glyph_format; + + /* create result bitmap glyph */ + error = ft_new_glyph( library, &ft_bitmap_glyph_class, &b ); + if ( error ) + goto Exit; + bitmap = (FT_BitmapGlyph)b; + +#if 1 + /* if `origin' is set, translate the glyph image */ + if ( origin ) + FT_Glyph_Transform( glyph, NULL, origin ); +#else + FT_UNUSED( origin ); +#endif + + /* prepare dummy slot for rendering */ + error = clazz->glyph_prepare( glyph, &dummy ); + if ( !error ) + error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); + +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz == &ft_svg_glyph_class ) + { + FT_Memory memory = library->memory; + + + FT_FREE( dummy.other ); + } +#endif + +#if 1 + if ( !destroy && origin ) + { + FT_Vector v; + + + v.x = -origin->x; + v.y = -origin->y; + FT_Glyph_Transform( glyph, NULL, &v ); + } +#endif + + if ( error ) + goto Exit; + + /* in case of success, copy the bitmap to the glyph bitmap */ + error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy ); + if ( error ) + goto Exit; + + /* copy advance */ + bitmap->root.advance = glyph->advance; + + if ( destroy ) + FT_Done_Glyph( glyph ); + + *the_glyph = FT_GLYPH( bitmap ); + + Exit: + if ( error && bitmap ) + FT_Done_Glyph( FT_GLYPH( bitmap ) ); + + return error; + + Bad: + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( void ) + FT_Done_Glyph( FT_Glyph glyph ) + { + if ( glyph ) + { + FT_Memory memory = glyph->library->memory; + const FT_Glyph_Class* clazz = glyph->clazz; + + + if ( clazz->glyph_done ) + clazz->glyph_done( glyph ); + + FT_FREE( glyph ); + } + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftgxval.c b/vendor/freetype/src/base/ftgxval.c new file mode 100644 index 0000000..6b3c5d2 --- /dev/null +++ b/vendor/freetype/src/base/ftgxval.c @@ -0,0 +1,141 @@ +/**************************************************************************** + * + * ftgxval.c + * + * FreeType API for validating TrueTypeGX/AAT tables (body). + * + * Copyright (C) 2004-2023 by + * Masatake YAMATO, Redhat K.K, + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include + +#include +#include + + + /* documentation is in ftgxval.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ) + { + FT_Service_GXvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( !tables ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, GX_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + tables, + table_length ); + else + error = FT_THROW( Unimplemented_Feature ); + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + FT_FREE( table ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ) + { + FT_Service_CKERNvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( !ckern_table ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, CLASSICKERN_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + ckern_table ); + else + error = FT_THROW( Unimplemented_Feature ); + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + + FT_FREE( table ); + } + + +/* END */ diff --git a/vendor/freetype/src/base/fthash.c b/vendor/freetype/src/base/fthash.c new file mode 100644 index 0000000..313bbbb --- /dev/null +++ b/vendor/freetype/src/base/fthash.c @@ -0,0 +1,338 @@ +/**************************************************************************** + * + * fthash.c + * + * Hashing functions (body). + * + */ + +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2015 + * Francesco Zappa Nardelli + * + * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is based on code from bdf.c,v 1.22 2000/03/16 20:08:50 + * + * taken from Mark Leisher's xmbdfed package + * + */ + + +#include +#include + + +#define INITIAL_HT_SIZE 241 + + + static FT_ULong + hash_str_lookup( FT_Hashkey* key ) + { + const char* kp = key->str; + FT_ULong res = 0; + + + /* Mocklisp hash function. */ + while ( *kp ) + res = ( res << 5 ) - res + (FT_ULong)*kp++; + + return res; + } + + + static FT_ULong + hash_num_lookup( FT_Hashkey* key ) + { + FT_ULong num = (FT_ULong)key->num; + FT_ULong res; + + + /* Mocklisp hash function. */ + res = num & 0xFF; + res = ( res << 5 ) - res + ( ( num >> 8 ) & 0xFF ); + res = ( res << 5 ) - res + ( ( num >> 16 ) & 0xFF ); + res = ( res << 5 ) - res + ( ( num >> 24 ) & 0xFF ); + + return res; + } + + + static FT_Bool + hash_str_compare( FT_Hashkey* a, + FT_Hashkey* b ) + { + if ( a->str[0] == b->str[0] && + ft_strcmp( a->str, b->str ) == 0 ) + return 1; + + return 0; + } + + + static FT_Bool + hash_num_compare( FT_Hashkey* a, + FT_Hashkey* b ) + { + if ( a->num == b->num ) + return 1; + + return 0; + } + + + static FT_Hashnode* + hash_bucket( FT_Hashkey key, + FT_Hash hash ) + { + FT_ULong res = 0; + FT_Hashnode* bp = hash->table; + FT_Hashnode* ndp; + + + res = (hash->lookup)( &key ); + + ndp = bp + ( res % hash->size ); + while ( *ndp ) + { + if ( (hash->compare)( &(*ndp)->key, &key ) ) + break; + + ndp--; + if ( ndp < bp ) + ndp = bp + ( hash->size - 1 ); + } + + return ndp; + } + + + static FT_Error + hash_rehash( FT_Hash hash, + FT_Memory memory ) + { + FT_Hashnode* obp = hash->table; + FT_Hashnode* bp; + FT_Hashnode* nbp; + + FT_UInt i, sz = hash->size; + FT_Error error = FT_Err_Ok; + + + hash->size <<= 1; + hash->limit = hash->size / 3; + + if ( FT_NEW_ARRAY( hash->table, hash->size ) ) + goto Exit; + + for ( i = 0, bp = obp; i < sz; i++, bp++ ) + { + if ( *bp ) + { + nbp = hash_bucket( (*bp)->key, hash ); + *nbp = *bp; + } + } + + FT_FREE( obp ); + + Exit: + return error; + } + + + static FT_Error + hash_init( FT_Hash hash, + FT_Bool is_num, + FT_Memory memory ) + { + FT_UInt sz = INITIAL_HT_SIZE; + FT_Error error; + + + hash->size = sz; + hash->limit = sz / 3; + hash->used = 0; + + if ( is_num ) + { + hash->lookup = hash_num_lookup; + hash->compare = hash_num_compare; + } + else + { + hash->lookup = hash_str_lookup; + hash->compare = hash_str_compare; + } + + FT_MEM_NEW_ARRAY( hash->table, sz ); + + return error; + } + + + FT_Error + ft_hash_str_init( FT_Hash hash, + FT_Memory memory ) + { + return hash_init( hash, 0, memory ); + } + + + FT_Error + ft_hash_num_init( FT_Hash hash, + FT_Memory memory ) + { + return hash_init( hash, 1, memory ); + } + + + void + ft_hash_str_free( FT_Hash hash, + FT_Memory memory ) + { + if ( hash ) + { + FT_UInt sz = hash->size; + FT_Hashnode* bp = hash->table; + FT_UInt i; + + + for ( i = 0; i < sz; i++, bp++ ) + FT_FREE( *bp ); + + FT_FREE( hash->table ); + } + } + + + /* `ft_hash_num_free' is the same as `ft_hash_str_free' */ + + + static FT_Error + hash_insert( FT_Hashkey key, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashnode nn; + FT_Hashnode* bp = hash_bucket( key, hash ); + FT_Error error = FT_Err_Ok; + + + nn = *bp; + if ( !nn ) + { + if ( FT_QNEW( nn ) ) + goto Exit; + *bp = nn; + + nn->key = key; + nn->data = data; + + if ( hash->used >= hash->limit ) + { + error = hash_rehash( hash, memory ); + if ( error ) + goto Exit; + } + + hash->used++; + } + else + nn->data = data; + + Exit: + return error; + } + + + FT_Error + ft_hash_str_insert( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.str = key; + + return hash_insert( hk, data, hash, memory ); + } + + + FT_Error + ft_hash_num_insert( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.num = num; + + return hash_insert( hk, data, hash, memory ); + } + + + static size_t* + hash_lookup( FT_Hashkey key, + FT_Hash hash ) + { + FT_Hashnode* np = hash_bucket( key, hash ); + + + return (*np) ? &(*np)->data + : NULL; + } + + + size_t* + ft_hash_str_lookup( const char* key, + FT_Hash hash ) + { + FT_Hashkey hk; + + + hk.str = key; + + return hash_lookup( hk, hash ); + } + + + size_t* + ft_hash_num_lookup( FT_Int num, + FT_Hash hash ) + { + FT_Hashkey hk; + + + hk.num = num; + + return hash_lookup( hk, hash ); + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftinit.c b/vendor/freetype/src/base/ftinit.c new file mode 100644 index 0000000..c9c71d2 --- /dev/null +++ b/vendor/freetype/src/base/ftinit.c @@ -0,0 +1,263 @@ +/**************************************************************************** + * + * ftinit.c + * + * FreeType initialization layer (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * The purpose of this file is to implement the following two + * functions: + * + * FT_Add_Default_Modules(): + * This function is used to add the set of default modules to a + * fresh new library object. The set is taken from the header file + * `freetype/config/ftmodule.h'. See the document `FreeType 2.0 + * Build System' for more information. + * + * FT_Init_FreeType(): + * This function creates a system object for the current platform, + * builds a library out of it, then calls FT_Default_Drivers(). + * + * Note that even if FT_Init_FreeType() uses the implementation of the + * system object defined at build time, client applications are still + * able to provide their own `ftsystem.c'. + * + */ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT init + + +#undef FT_USE_MODULE +#ifdef __cplusplus +#define FT_USE_MODULE( type, x ) extern "C" const type x; +#else +#define FT_USE_MODULE( type, x ) extern const type x; +#endif + +#include FT_CONFIG_MODULES_H + +#undef FT_USE_MODULE +#define FT_USE_MODULE( type, x ) (const FT_Module_Class*)&(x), + + static + const FT_Module_Class* const ft_default_modules[] = + { +#include FT_CONFIG_MODULES_H + 0 + }; + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Add_Default_Modules( FT_Library library ) + { + FT_Error error; + const FT_Module_Class* const* cur; + + + /* GCC 4.6 warns the type difference: + * FT_Module_Class** != const FT_Module_Class* const* + */ + cur = (const FT_Module_Class* const*)ft_default_modules; + + /* test for valid `library' delayed to FT_Add_Module() */ + while ( *cur ) + { + error = FT_Add_Module( library, *cur ); + /* notify errors, but don't stop */ + if ( error ) + FT_TRACE0(( "FT_Add_Default_Module:" + " Cannot install `%s', error = 0x%x\n", + (*cur)->module_name, error )); + cur++; + } + } + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + +#define MAX_LENGTH 128 + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Default_Properties( FT_Library library ) + { + const char* env; + const char* p; + const char* q; + + char module_name[MAX_LENGTH + 1]; + char property_name[MAX_LENGTH + 1]; + char property_value[MAX_LENGTH + 1]; + + int i; + + + env = ft_getenv( "FREETYPE_PROPERTIES" ); + if ( !env ) + return; + + for ( p = env; *p; p++ ) + { + /* skip leading whitespace and separators */ + if ( *p == ' ' || *p == '\t' ) + continue; + + /* read module name, followed by `:' */ + q = p; + for ( i = 0; i < MAX_LENGTH; i++ ) + { + if ( !*p || *p == ':' ) + break; + module_name[i] = *p++; + } + module_name[i] = '\0'; + + if ( !*p || *p != ':' || p == q ) + break; + + /* read property name, followed by `=' */ + q = ++p; + for ( i = 0; i < MAX_LENGTH; i++ ) + { + if ( !*p || *p == '=' ) + break; + property_name[i] = *p++; + } + property_name[i] = '\0'; + + if ( !*p || *p != '=' || p == q ) + break; + + /* read property value, followed by whitespace (if any) */ + q = ++p; + for ( i = 0; i < MAX_LENGTH; i++ ) + { + if ( !*p || *p == ' ' || *p == '\t' ) + break; + property_value[i] = *p++; + } + property_value[i] = '\0'; + + if ( !( *p == '\0' || *p == ' ' || *p == '\t' ) || p == q ) + break; + + /* we completely ignore errors */ + ft_property_string_set( library, + module_name, + property_name, + property_value ); + + if ( !*p ) + break; + } + } + +#else + + FT_EXPORT_DEF( void ) + FT_Set_Default_Properties( FT_Library library ) + { + FT_UNUSED( library ); + } + +#endif + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ) + { + FT_Error error; + FT_Memory memory; + + +#ifdef FT_DEBUG_LOGGING + ft_logging_init(); +#endif + + /* check of `alibrary' delayed to `FT_New_Library' */ + + /* First of all, allocate a new system object -- this function is part */ + /* of the system-specific component, i.e. `ftsystem.c'. */ + + memory = FT_New_Memory(); + if ( !memory ) + { + FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" )); + return FT_THROW( Unimplemented_Feature ); + } + + /* build a library out of it, then fill it with the set of */ + /* default drivers. */ + + error = FT_New_Library( memory, alibrary ); + if ( error ) + FT_Done_Memory( memory ); + else + FT_Add_Default_Modules( *alibrary ); + + FT_Set_Default_Properties( *alibrary ); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_FreeType( FT_Library library ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + memory = library->memory; + + /* Discard the library object */ + FT_Done_Library( library ); + + /* discard memory manager */ + FT_Done_Memory( memory ); + +#ifdef FT_DEBUG_LOGGING + ft_logging_deinit(); +#endif + + return FT_Err_Ok; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftlcdfil.c b/vendor/freetype/src/base/ftlcdfil.c new file mode 100644 index 0000000..6c3fd66 --- /dev/null +++ b/vendor/freetype/src/base/ftlcdfil.c @@ -0,0 +1,437 @@ +/**************************************************************************** + * + * ftlcdfil.c + * + * FreeType API for color filtering of subpixel bitmap glyphs (body). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + +/* define USE_LEGACY to implement the legacy filter */ +#define USE_LEGACY + +#define FT_SHIFTCLAMP( x ) ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) ) + + + /* add padding according to filter weights */ + FT_BASE_DEF( void ) + ft_lcd_padding( FT_BBox* cbox, + FT_GlyphSlot slot, + FT_Render_Mode mode ) + { + FT_Byte* lcd_weights; + FT_Bitmap_LcdFilterFunc lcd_filter_func; + + + /* Per-face LCD filtering takes priority if set up. */ + if ( slot->face && slot->face->internal->lcd_filter_func ) + { + lcd_weights = slot->face->internal->lcd_weights; + lcd_filter_func = slot->face->internal->lcd_filter_func; + } + else + { + lcd_weights = slot->library->lcd_weights; + lcd_filter_func = slot->library->lcd_filter_func; + } + + if ( lcd_filter_func == ft_lcd_filter_fir ) + { + if ( mode == FT_RENDER_MODE_LCD ) + { + cbox->xMin -= lcd_weights[0] ? 43 : + lcd_weights[1] ? 22 : 0; + cbox->xMax += lcd_weights[4] ? 43 : + lcd_weights[3] ? 22 : 0; + } + else if ( mode == FT_RENDER_MODE_LCD_V ) + { + cbox->yMin -= lcd_weights[0] ? 43 : + lcd_weights[1] ? 22 : 0; + cbox->yMax += lcd_weights[4] ? 43 : + lcd_weights[3] ? 22 : 0; + } + } + } + + + /* FIR filter used by the default and light filters */ + FT_BASE_DEF( void ) + ft_lcd_filter_fir( FT_Bitmap* bitmap, + FT_LcdFiveTapFilter weights ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + FT_Byte* origin = bitmap->buffer; + FT_Byte mode = bitmap->pixel_mode; + + + /* take care of bitmap flow */ + if ( pitch > 0 && height > 0 ) + origin += pitch * (FT_Int)( height - 1 ); + + /* horizontal in-place FIR filter */ + if ( mode == FT_PIXEL_MODE_LCD && width >= 2 ) + { + FT_Byte* line = origin; + + + /* `fir' must be at least 32 bit wide, since the sum of */ + /* the values in `weights' can exceed 0xFF */ + + for ( ; height > 0; height--, line -= pitch ) + { + FT_UInt fir[5]; + FT_UInt val, xx; + + + val = line[0]; + fir[2] = weights[2] * val; + fir[3] = weights[3] * val; + fir[4] = weights[4] * val; + + val = line[1]; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + + for ( xx = 2; xx < width; xx++ ) + { + val = line[xx]; + fir[0] = fir[1] + weights[0] * val; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + + line[xx - 2] = FT_SHIFTCLAMP( fir[0] ); + } + + line[xx - 2] = FT_SHIFTCLAMP( fir[1] ); + line[xx - 1] = FT_SHIFTCLAMP( fir[2] ); + } + } + + /* vertical in-place FIR filter */ + else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 ) + { + FT_Byte* column = origin; + + + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column; + FT_UInt fir[5]; + FT_UInt val, yy; + + + val = col[0]; + fir[2] = weights[2] * val; + fir[3] = weights[3] * val; + fir[4] = weights[4] * val; + col -= pitch; + + val = col[0]; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + col -= pitch; + + for ( yy = 2; yy < height; yy++, col -= pitch ) + { + val = col[0]; + fir[0] = fir[1] + weights[0] * val; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + + col[pitch * 2] = FT_SHIFTCLAMP( fir[0] ); + } + + col[pitch * 2] = FT_SHIFTCLAMP( fir[1] ); + col[pitch] = FT_SHIFTCLAMP( fir[2] ); + } + } + } + + +#ifdef USE_LEGACY + + /* intra-pixel filter used by the legacy filter */ + static void + _ft_lcd_filter_legacy( FT_Bitmap* bitmap, + FT_Byte* weights ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + FT_Byte* origin = bitmap->buffer; + FT_Byte mode = bitmap->pixel_mode; + + static const unsigned int filters[3][3] = + { + { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 }, + { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 }, + { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 } + }; + + FT_UNUSED( weights ); + + + /* take care of bitmap flow */ + if ( pitch > 0 && height > 0 ) + origin += pitch * (FT_Int)( height - 1 ); + + /* horizontal in-place intra-pixel filter */ + if ( mode == FT_PIXEL_MODE_LCD && width >= 3 ) + { + FT_Byte* line = origin; + + + for ( ; height > 0; height--, line -= pitch ) + { + FT_UInt xx; + + + for ( xx = 0; xx < width; xx += 3 ) + { + FT_UInt r, g, b; + FT_UInt p; + + + p = line[xx]; + r = filters[0][0] * p; + g = filters[0][1] * p; + b = filters[0][2] * p; + + p = line[xx + 1]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + + p = line[xx + 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + + line[xx] = (FT_Byte)( r / 65536 ); + line[xx + 1] = (FT_Byte)( g / 65536 ); + line[xx + 2] = (FT_Byte)( b / 65536 ); + } + } + } + else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 ) + { + FT_Byte* column = origin; + + + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column - 2 * pitch; + + + for ( ; height > 0; height -= 3, col -= 3 * pitch ) + { + FT_UInt r, g, b; + FT_UInt p; + + + p = col[0]; + r = filters[0][0] * p; + g = filters[0][1] * p; + b = filters[0][2] * p; + + p = col[pitch]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + + p = col[pitch * 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + + col[0] = (FT_Byte)( r / 65536 ); + col[pitch] = (FT_Byte)( g / 65536 ); + col[pitch * 2] = (FT_Byte)( b / 65536 ); + } + } + } + } + +#endif /* USE_LEGACY */ + + + /* documentation in ftlcdfil.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ) + { + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !weights ) + return FT_THROW( Invalid_Argument ); + + ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; + + return FT_Err_Ok; + } + + + /* documentation in ftlcdfil.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { + static const FT_LcdFiveTapFilter default_weights = + { 0x08, 0x4d, 0x56, 0x4d, 0x08 }; + static const FT_LcdFiveTapFilter light_weights = + { 0x00, 0x55, 0x56, 0x55, 0x00 }; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + switch ( filter ) + { + case FT_LCD_FILTER_NONE: + library->lcd_filter_func = NULL; + break; + + case FT_LCD_FILTER_DEFAULT: + ft_memcpy( library->lcd_weights, + default_weights, + FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; + break; + + case FT_LCD_FILTER_LIGHT: + ft_memcpy( library->lcd_weights, + light_weights, + FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; + break; + +#ifdef USE_LEGACY + + case FT_LCD_FILTER_LEGACY: + case FT_LCD_FILTER_LEGACY1: + library->lcd_filter_func = _ft_lcd_filter_legacy; + break; + +#endif + + default: + return FT_THROW( Invalid_Argument ); + } + + return FT_Err_Ok; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdGeometry( FT_Library library, + FT_Vector sub[3] ) + { + FT_UNUSED( library ); + FT_UNUSED( sub ); + + return FT_THROW( Unimplemented_Feature ); + } + +#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /* add padding to accommodate outline shifts */ + FT_BASE_DEF( void ) + ft_lcd_padding( FT_BBox* cbox, + FT_GlyphSlot slot, + FT_Render_Mode mode ) + { + FT_Vector* sub = slot->library->lcd_geometry; + + if ( mode == FT_RENDER_MODE_LCD ) + { + cbox->xMin -= FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x ); + cbox->xMax -= FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x ); + cbox->yMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y ); + cbox->yMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y ); + } + else if ( mode == FT_RENDER_MODE_LCD_V ) + { + cbox->xMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y ); + cbox->xMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y ); + cbox->yMin += FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x ); + cbox->yMax += FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x ); + } + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ) + { + FT_UNUSED( library ); + FT_UNUSED( weights ); + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { + FT_UNUSED( library ); + FT_UNUSED( filter ); + + return FT_THROW( Unimplemented_Feature ); + } + + + /* documentation in ftlcdfil.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdGeometry( FT_Library library, + FT_Vector sub[3] ) + { + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !sub ) + return FT_THROW( Invalid_Argument ); + + ft_memcpy( library->lcd_geometry, sub, 3 * sizeof( FT_Vector ) ); + + return FT_Err_Ok; + } + +#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + +/* END */ diff --git a/vendor/freetype/src/base/ftmac.c b/vendor/freetype/src/base/ftmac.c new file mode 100644 index 0000000..492d055 --- /dev/null +++ b/vendor/freetype/src/base/ftmac.c @@ -0,0 +1,1090 @@ +/**************************************************************************** + * + * ftmac.c + * + * Mac FOND support. Written by just@letterror.com. + * Heavily modified by mpsuzuki, George Williams, and Sean McBride. + * + * This file is for Mac OS X only; see builds/mac/ftoldmac.c for + * classic platforms built by MPW. + * + * Copyright (C) 1996-2023 by + * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + Notes + + Mac suitcase files can (and often do!) contain multiple fonts. To + support this I use the face_index argument of FT_(Open|New)_Face() + functions, and pretend the suitcase file is a collection. + + Warning: fbit and NFNT bitmap resources are not supported yet. In old + sfnt fonts, bitmap glyph data for each size is stored in each `NFNT' + resources instead of the `bdat' table in the sfnt resource. Therefore, + face->num_fixed_sizes is set to 0, because bitmap data in `NFNT' + resource is unavailable at present. + + The Mac FOND support works roughly like this: + + - Check whether the offered stream points to a Mac suitcase file. This + is done by checking the file type: it has to be 'FFIL' or 'tfil'. The + stream that gets passed to our init_face() routine is a stdio stream, + which isn't usable for us, since the FOND resources live in the + resource fork. So we just grab the stream->pathname field. + + - Read the FOND resource into memory, then check whether there is a + TrueType font and/or(!) a Type 1 font available. + + - If there is a Type 1 font available (as a separate `LWFN' file), read + its data into memory, massage it slightly so it becomes PFB data, wrap + it into a memory stream, load the Type 1 driver and delegate the rest + of the work to it by calling FT_Open_Face(). (XXX TODO: after this + has been done, the kerning data from the FOND resource should be + appended to the face: On the Mac there are usually no AFM files + available. However, this is tricky since we need to map Mac char + codes to ps glyph names to glyph ID's...) + + - If there is a TrueType font (an `sfnt' resource), read it into memory, + wrap it into a memory stream, load the TrueType driver and delegate + the rest of the work to it, by calling FT_Open_Face(). + + - Some suitcase fonts (notably Onyx) might point the `LWFN' file to + itself, even though it doesn't contains `POST' resources. To handle + this special case without opening the file an extra time, we just + ignore errors from the `LWFN' and fallback to the `sfnt' if both are + available. + */ + + +#include +#include +#include +#include +#include "ftbase.h" + + +#ifdef FT_MACINTOSH + + /* This is for Mac OS X. Without redefinition, OS_INLINE */ + /* expands to `static inline' which doesn't survive the */ + /* -ansi compilation flag of GCC. */ +#if !HAVE_ANSI_OS_INLINE +#undef OS_INLINE +#define OS_INLINE static __inline__ +#endif + + /* `configure' checks the availability of `ResourceIndex' strictly */ + /* and sets HAVE_TYPE_RESOURCE_INDEX 1 or 0 always. If it is */ + /* not set (e.g., a build without `configure'), the availability */ + /* is guessed from the SDK version. */ +#ifndef HAVE_TYPE_RESOURCE_INDEX +#if !defined( MAC_OS_X_VERSION_10_5 ) || \ + ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 ) +#define HAVE_TYPE_RESOURCE_INDEX 0 +#else +#define HAVE_TYPE_RESOURCE_INDEX 1 +#endif +#endif /* !HAVE_TYPE_RESOURCE_INDEX */ + +#if ( HAVE_TYPE_RESOURCE_INDEX == 0 ) + typedef short ResourceIndex; +#endif + +#include +#include +#include /* PATH_MAX */ + + /* Don't want warnings about our own use of deprecated functions. */ +#define FT_DEPRECATED_ATTRIBUTE + +#include + +#ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */ +#define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault +#endif + + + /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over + TrueType in case *both* are available (this is not common, + but it *is* possible). */ +#ifndef PREFER_LWFN +#define PREFER_LWFN 1 +#endif + + + /* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_THROW( Unimplemented_Feature ); + } + + + /* Private function. */ + /* The FSSpec type has been discouraged for a long time, */ + /* unfortunately an FSRef replacement API for */ + /* ATSFontGetFileSpecification() is only available in */ + /* Mac OS X 10.5 and later. */ + static OSStatus + FT_ATSFontGetFileReference( ATSFontRef ats_font_id, + FSRef* ats_font_ref ) + { +#if defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) + + OSStatus err; + + err = ATSFontGetFileReference( ats_font_id, ats_font_ref ); + + return err; +#elif __LP64__ /* No 64bit Carbon API on legacy platforms */ + FT_UNUSED( ats_font_id ); + FT_UNUSED( ats_font_ref ); + + + return fnfErr; +#else /* 32bit Carbon API on legacy platforms */ + OSStatus err; + FSSpec spec; + + + err = ATSFontGetFileSpecification( ats_font_id, &spec ); + if ( noErr == err ) + err = FSpMakeFSRef( &spec, ats_font_ref ); + + return err; +#endif + } + + + static FT_Error + FT_GetFileRef_From_Mac_ATS_Name( const char* fontName, + FSRef* ats_font_ref, + FT_Long* face_index ) + { + CFStringRef cf_fontName; + ATSFontRef ats_font_id; + + + *face_index = 0; + + cf_fontName = CFStringCreateWithCString( NULL, fontName, + kCFStringEncodingMacRoman ); + ats_font_id = ATSFontFindFromName( cf_fontName, + kATSOptionFlagsUnRestrictedScope ); + CFRelease( cf_fontName ); + + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + return FT_THROW( Unknown_File_Format ); + + if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) ) + return FT_THROW( Unknown_File_Format ); + + /* face_index calculation by searching preceding fontIDs */ + /* with same FSRef */ + { + ATSFontRef id2 = ats_font_id - 1; + FSRef ref2; + + + while ( id2 > 0 ) + { + if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) ) + break; + if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) ) + break; + + id2 --; + } + *face_index = ats_font_id - ( id2 + 1 ); + } + + return FT_Err_Ok; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + { + FSRef ref; + FT_Error err; + + + if ( !fontName || !face_index ) + return FT_THROW( Invalid_Argument); + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( err ) + return err; + + if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) ) + return FT_THROW( Unknown_File_Format ); + + return FT_Err_Ok; + } + + + /* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { +#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_THROW( Unimplemented_Feature ); +#else + FSRef ref; + FT_Error err; + + + if ( !fontName || !face_index ) + return FT_THROW( Invalid_Argument ); + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( err ) + return err; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, + pathSpec, NULL ) ) + return FT_THROW( Unknown_File_Format ); + + return FT_Err_Ok; +#endif + } + + + static OSErr + FT_FSPathMakeRes( const UInt8* pathname, + ResFileRefNum* res ) + { + OSErr err; + FSRef ref; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + /* at present, no support for dfont format */ + err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res ); + if ( noErr == err ) + return err; + + /* fallback to original resource-fork font */ + *res = FSOpenResFile( &ref, fsRdPerm ); + err = ResError(); + + return err; + } + + + /* Return the file type for given pathname */ + static OSType + get_file_type_from_path( const UInt8* pathname ) + { + FSRef ref; + FSCatalogInfo info; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return ( OSType ) 0; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info, + NULL, NULL, NULL ) ) + return ( OSType ) 0; + + return ( (FInfo *)( info.finderInfo ) )->fdType; + } + + + /* Given a PostScript font name, create the Macintosh LWFN file name. */ + static void + create_lwfn_name( char* ps_name, + Str255 lwfn_file_name ) + { + int max = 5, count = 0; + FT_Byte* p = lwfn_file_name; + FT_Byte* q = (FT_Byte*)ps_name; + + + lwfn_file_name[0] = 0; + + while ( *q ) + { + if ( ft_isupper( *q ) ) + { + if ( count ) + max = 3; + count = 0; + } + if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) + { + *++p = *q; + lwfn_file_name[0]++; + count++; + } + q++; + } + } + + + static short + count_faces_sfnt( char* fond_data ) + { + /* The count is 1 greater than the value in the FOND. */ + /* Isn't that cute? :-) */ + + return EndianS16_BtoN( *( (short*)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + } + + + static short + count_faces_scalable( char* fond_data ) + { + AsscEntry* assoc; + short i, face, face_all; + + + face_all = EndianS16_BtoN( *( (short *)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + face = 0; + + for ( i = 0; i < face_all; i++ ) + { + if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) ) + face++; + } + return face; + } + + + /* Look inside the FOND data, answer whether there should be an SFNT + resource, and answer the name of a possible LWFN Type 1 file. + + Thanks to Paul Miller (paulm@profoundeffects.com) for the fix + to load a face OTHER than the first one in the FOND! + */ + + + static void + parse_fond( char* fond_data, + short* have_sfnt, + ResID* sfnt_id, + Str255 lwfn_file_name, + short face_index ) + { + AsscEntry* assoc; + AsscEntry* base_assoc; + FamRec* fond; + + + *sfnt_id = 0; + *have_sfnt = 0; + lwfn_file_name[0] = 0; + + fond = (FamRec*)fond_data; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + base_assoc = assoc; + + /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */ + if ( 47 < face_index ) + return; + + /* Let's do a little range checking before we get too excited here */ + if ( face_index < count_faces_sfnt( fond_data ) ) + { + assoc += face_index; /* add on the face_index! */ + + /* if the face at this index is not scalable, + fall back to the first one (old behavior) */ + if ( EndianS16_BtoN( assoc->fontSize ) == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( assoc->fontID ); + } + else if ( base_assoc->fontSize == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( base_assoc->fontID ); + } + } + + if ( EndianS32_BtoN( fond->ffStylOff ) ) + { + unsigned char* p = (unsigned char*)fond_data; + StyleTable* style; + unsigned short string_count; + char ps_name[256]; + unsigned char* names[64]; + int i; + + + p += EndianS32_BtoN( fond->ffStylOff ); + style = (StyleTable*)p; + p += sizeof ( StyleTable ); + string_count = EndianS16_BtoN( *(short*)(p) ); + string_count = FT_MIN( 64, string_count ); + p += sizeof ( short ); + + for ( i = 0; i < string_count; i++ ) + { + names[i] = p; + p += names[i][0]; + p++; + } + + { + size_t ps_name_len = (size_t)names[0][0]; + + + if ( ps_name_len != 0 ) + { + ft_memcpy( ps_name, names[0] + 1, ps_name_len ); + ps_name[ps_name_len] = 0; + } + if ( style->indexes[face_index] > 1 && + style->indexes[face_index] <= string_count ) + { + unsigned char* suffixes = names[style->indexes[face_index] - 1]; + + + for ( i = 1; i <= suffixes[0]; i++ ) + { + unsigned char* s; + size_t j = suffixes[i] - 1; + + + if ( j < string_count && ( s = names[j] ) != NULL ) + { + size_t s_len = (size_t)s[0]; + + + if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) + { + ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); + ps_name_len += s_len; + ps_name[ps_name_len] = 0; + } + } + } + } + } + + create_lwfn_name( ps_name, lwfn_file_name ); + } + } + + + static FT_Error + lookup_lwfn_by_fond( const UInt8* path_fond, + ConstStr255Param base_lwfn, + UInt8* path_lwfn, + size_t path_size ) + { + FSRef ref, par_ref; + size_t dirname_len; + + + /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ + /* We should not extract parent directory by string manipulation. */ + + if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) + return FT_THROW( Invalid_Argument ); + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, &par_ref ) ) + return FT_THROW( Invalid_Argument ); + + if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) + return FT_THROW( Invalid_Argument ); + + if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) + return FT_THROW( Invalid_Argument ); + + /* now we have absolute dirname in path_lwfn */ + ft_strcat( (char *)path_lwfn, "/" ); + dirname_len = ft_strlen( (char *)path_lwfn ); + ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); + path_lwfn[dirname_len + base_lwfn[0]] = '\0'; + + if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, NULL ) ) + return FT_THROW( Cannot_Open_Resource ); + + return FT_Err_Ok; + } + + + static short + count_faces( Handle fond, + const UInt8* pathname ) + { + ResID sfnt_id; + short have_sfnt, have_lwfn; + Str255 lwfn_file_name; + UInt8 buff[PATH_MAX]; + FT_Error err; + short num_faces; + + + have_sfnt = have_lwfn = 0; + + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); + + if ( lwfn_file_name[0] ) + { + err = lookup_lwfn_by_fond( pathname, lwfn_file_name, + buff, sizeof ( buff ) ); + if ( !err ) + have_lwfn = 1; + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + num_faces = 1; + else + num_faces = count_faces_scalable( *fond ); + + return num_faces; + } + + + /* Read Type 1 data from the POST resources inside the LWFN file, + return a PFB buffer. This is somewhat convoluted because the FT2 + PFB parser wants the ASCII header as one chunk, and the LWFN + chunks are often not organized that way, so we glue chunks + of the same type together. */ + static FT_Error + read_lwfn( FT_Memory memory, + ResFileRefNum res, + FT_Byte** pfb_data, + FT_ULong* size ) + { + FT_Error error = FT_Err_Ok; + ResID res_id; + unsigned char *buffer, *p, *size_p = NULL; + FT_ULong total_size = 0; + FT_ULong old_total_size = 0; + FT_ULong post_size, pfb_chunk_size; + Handle post_data; + char code, last_code; + + + UseResFile( res ); + + /* First pass: load all POST resources, and determine the size of */ + /* the output buffer. */ + res_id = 501; + last_code = -1; + + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( !post_data ) + break; /* we are done */ + + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( code == 5 ) + total_size += 2; /* just the end code */ + else + total_size += 6; /* code + 4 bytes chunk length */ + } + + total_size += (FT_ULong)GetHandleSize( post_data ) - 2; + last_code = code; + + /* detect resource fork overflow */ + if ( FT_MAC_RFORK_MAX_LEN < total_size ) + { + error = FT_THROW( Array_Too_Large ); + goto Error; + } + + old_total_size = total_size; + } + + if ( FT_QALLOC( buffer, (FT_Long)total_size ) ) + goto Error; + + /* Second pass: append all POST data to the buffer, add PFB fields. */ + /* Glue all consecutive chunks of the same type together. */ + p = buffer; + res_id = 501; + last_code = -1; + pfb_chunk_size = 0; + + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( !post_data ) + break; /* we are done */ + + post_size = (FT_ULong)GetHandleSize( post_data ) - 2; + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( last_code != -1 ) + { + /* we are done adding a chunk, fill in the size field */ + if ( size_p ) + { + *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); + } + pfb_chunk_size = 0; + } + + *p++ = 0x80; + if ( code == 5 ) + *p++ = 0x03; /* the end */ + else if ( code == 2 ) + *p++ = 0x02; /* binary segment */ + else + *p++ = 0x01; /* ASCII segment */ + + if ( code != 5 ) + { + size_p = p; /* save for later */ + p += 4; /* make space for size field */ + } + } + + ft_memcpy( p, *post_data + 2, post_size ); + pfb_chunk_size += post_size; + p += post_size; + last_code = code; + } + + *pfb_data = buffer; + *size = total_size; + + Error: + CloseResFile( res ); + return error; + } + + + /* Create a new FT_Face from a file path to an LWFN file. */ + static FT_Error + FT_New_Face_From_LWFN( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Byte* pfb_data; + FT_ULong pfb_size; + FT_Error error; + ResFileRefNum res; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res ) ) + return FT_THROW( Cannot_Open_Resource ); + + pfb_data = NULL; + pfb_size = 0; + error = read_lwfn( library->memory, res, &pfb_data, &pfb_size ); + CloseResFile( res ); /* PFB is already loaded, useless anymore */ + if ( error ) + return error; + + return open_face_from_buffer( library, + pfb_data, + pfb_size, + face_index, + "type1", + aface ); + } + + + /* Create a new FT_Face from an SFNT resource, specified by res ID. */ + static FT_Error + FT_New_Face_From_SFNT( FT_Library library, + ResID sfnt_id, + FT_Long face_index, + FT_Face* aface ) + { + Handle sfnt = NULL; + FT_Byte* sfnt_data; + size_t sfnt_size; + FT_Error error = FT_Err_Ok; + FT_Memory memory = library->memory; + int is_cff, is_sfnt_ps; + + + sfnt = GetResource( TTAG_sfnt, sfnt_id ); + if ( !sfnt ) + return FT_THROW( Invalid_Handle ); + + sfnt_size = (FT_ULong)GetHandleSize( sfnt ); + + /* detect resource fork overflow */ + if ( FT_MAC_RFORK_MAX_LEN < sfnt_size ) + return FT_THROW( Array_Too_Large ); + + if ( FT_QALLOC( sfnt_data, (FT_Long)sfnt_size ) ) + { + ReleaseResource( sfnt ); + return error; + } + + ft_memcpy( sfnt_data, *sfnt, sfnt_size ); + ReleaseResource( sfnt ); + + is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); + is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 ); + + if ( is_sfnt_ps ) + { + FT_Stream stream; + + + if ( FT_NEW( stream ) ) + goto Try_OpenType; + + FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size ); + if ( !open_face_PS_from_sfnt_stream( library, + stream, + face_index, + 0, NULL, + aface ) ) + { + FT_Stream_Close( stream ); + FT_FREE( stream ); + FT_FREE( sfnt_data ); + goto Exit; + } + + FT_FREE( stream ); + } + Try_OpenType: + error = open_face_from_buffer( library, + sfnt_data, + sfnt_size, + face_index, + is_cff ? "cff" : "truetype", + aface ); + Exit: + return error; + } + + + /* Create a new FT_Face from a file path to a suitcase file. */ + static FT_Error + FT_New_Face_From_Suitcase( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error = FT_ERR( Cannot_Open_Resource ); + ResFileRefNum res_ref; + ResourceIndex res_index; + Handle fond; + short num_faces_in_res; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) + return FT_THROW( Cannot_Open_Resource ); + + UseResFile( res_ref ); + if ( ResError() ) + return FT_THROW( Cannot_Open_Resource ); + + num_faces_in_res = 0; + for ( res_index = 1; ; res_index++ ) + { + short num_faces_in_fond; + + + fond = Get1IndResource( TTAG_FOND, res_index ); + if ( ResError() ) + break; + + num_faces_in_fond = count_faces( fond, pathname ); + num_faces_in_res += num_faces_in_fond; + + if ( 0 <= face_index && face_index < num_faces_in_fond && error ) + error = FT_New_Face_From_FOND( library, fond, face_index, aface ); + + face_index -= num_faces_in_fond; + } + + CloseResFile( res_ref ); + if ( !error && aface && *aface ) + (*aface)->num_faces = num_faces_in_res; + return error; + } + + + /* documentation is in ftmac.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face* aface ) + { + short have_sfnt, have_lwfn = 0; + ResID sfnt_id, fond_id; + OSType fond_type; + Str255 fond_name; + Str255 lwfn_file_name; + UInt8 path_lwfn[PATH_MAX]; + OSErr err; + FT_Error error = FT_Err_Ok; + + + /* check of `library' and `aface' delayed to `FT_New_Face_From_XXX' */ + + GetResInfo( fond, &fond_id, &fond_type, fond_name ); + if ( ResError() != noErr || fond_type != TTAG_FOND ) + return FT_THROW( Invalid_File_Format ); + + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index ); + + if ( lwfn_file_name[0] ) + { + ResFileRefNum res; + + + res = HomeResFile( fond ); + if ( noErr != ResError() ) + goto found_no_lwfn_file; + + { + UInt8 path_fond[PATH_MAX]; + FSRef ref; + + + err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum, + NULL, NULL, NULL, &ref, NULL ); + if ( noErr != err ) + goto found_no_lwfn_file; + + err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) ); + if ( noErr != err ) + goto found_no_lwfn_file; + + error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, + path_lwfn, sizeof ( path_lwfn ) ); + if ( !error ) + have_lwfn = 1; + } + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + error = FT_New_Face_From_LWFN( library, + path_lwfn, + face_index, + aface ); + else + error = FT_THROW( Unknown_File_Format ); + + found_no_lwfn_file: + if ( have_sfnt && error ) + error = FT_New_Face_From_SFNT( library, + sfnt_id, + face_index, + aface ); + + return error; + } + + + /* Common function to load a new FT_Face from a resource file. */ + static FT_Error + FT_New_Face_From_Resource( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + OSType file_type; + FT_Error error; + + + /* LWFN is a (very) specific file format, check for it explicitly */ + file_type = get_file_type_from_path( pathname ); + if ( file_type == TTAG_LWFN ) + return FT_New_Face_From_LWFN( library, pathname, face_index, aface ); + + /* Otherwise the file type doesn't matter (there are more than */ + /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */ + /* if it works, fine. */ + + error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface ); + if ( error ) + { + /* let it fall through to normal loader (.ttf, .otf, etc.); */ + /* we signal this by returning no error and no FT_Face */ + *aface = NULL; + } + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * FT_New_Face + * + * @Description: + * This is the Mac-specific implementation of FT_New_Face. In + * addition to the standard FT_New_Face() functionality, it also + * accepts pathnames to Mac suitcase files. For further + * documentation see the original FT_New_Face() in freetype.h. + */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Open_Args args; + FT_Error error; + + + /* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_THROW( Invalid_Argument ); + + *aface = NULL; + + /* try resourcefork based font: LWFN, FFIL */ + error = FT_New_Face_From_Resource( library, (UInt8 *)pathname, + face_index, aface ); + if ( error || *aface ) + return error; + + /* let it fall through to normal loader (.ttf, .otf, etc.) */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /************************************************************************** + * + * @Function: + * FT_New_Face_From_FSRef + * + * @Description: + * FT_New_Face_From_FSRef is identical to FT_New_Face except it + * accepts an FSRef instead of a path. + * + * This function is deprecated because Carbon data types (FSRef) + * are not cross-platform, and thus not suitable for the FreeType API. + */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef* ref, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error; + FT_Open_Args args; + + OSErr err; + UInt8 pathname[PATH_MAX]; + + + /* check of `library' and `aface' delayed to */ + /* `FT_New_Face_From_Resource' */ + + if ( !ref ) + return FT_THROW( Invalid_Argument ); + + err = FSRefMakePath( ref, pathname, sizeof ( pathname ) ); + if ( err ) + error = FT_THROW( Cannot_Open_Resource ); + + error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); + if ( error || *aface ) + return error; + + /* fallback to datafork font */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /************************************************************************** + * + * @Function: + * FT_New_Face_From_FSSpec + * + * @Description: + * FT_New_Face_From_FSSpec is identical to FT_New_Face except it + * accepts an FSSpec instead of a path. + * + * This function is deprecated because FSSpec is deprecated in Mac OS X + */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec* spec, + FT_Long face_index, + FT_Face* aface ) + { +#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) + FT_UNUSED( library ); + FT_UNUSED( spec ); + FT_UNUSED( face_index ); + FT_UNUSED( aface ); + + return FT_THROW( Unimplemented_Feature ); +#else + FSRef ref; + + + /* check of `library' and `aface' delayed to `FT_New_Face_From_FSRef' */ + + if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr ) + return FT_THROW( Invalid_Argument ); + else + return FT_New_Face_From_FSRef( library, &ref, face_index, aface ); +#endif + } + +#else /* !FT_MACINTOSH */ + + /* ANSI C doesn't like empty source files */ + typedef int ft_mac_dummy_; + +#endif /* !FT_MACINTOSH */ + + +/* END */ diff --git a/vendor/freetype/src/base/ftmm.c b/vendor/freetype/src/base/ftmm.c new file mode 100644 index 0000000..9e2dd7e --- /dev/null +++ b/vendor/freetype/src/base/ftmm.c @@ -0,0 +1,704 @@ +/**************************************************************************** + * + * ftmm.c + * + * Multiple Master font support (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT mm + + + static FT_Error + ft_face_get_mm_service( FT_Face face, + FT_Service_MultiMasters *aservice ) + { + FT_Error error; + + + *aservice = NULL; + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + error = FT_ERR( Invalid_Argument ); + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_FACE_LOOKUP_SERVICE( face, + *aservice, + MULTI_MASTERS ); + + if ( *aservice ) + error = FT_Err_Ok; + } + + return error; + } + + + static FT_Error + ft_face_get_mvar_service( FT_Face face, + FT_Service_MetricsVariations *aservice ) + { + FT_Error error; + + + *aservice = NULL; + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + error = FT_ERR( Invalid_Argument ); + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_FACE_LOOKUP_SERVICE( face, + *aservice, + METRICS_VARIATIONS ); + + if ( *aservice ) + error = FT_Err_Ok; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !amaster ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm ) + error = service->get_mm( face, amaster ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !amaster ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_var ) + error = service->get_mm_var( face, amaster ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_MM_Var( FT_Library library, + FT_MM_Var* amaster ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + memory = library->memory; + FT_FREE( amaster ); + + return FT_Err_Ok; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->set_mm_design ) + error = service->set_mm_design( face, num_coords, coords ); + + if ( !error ) + { + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( len && !weightvector ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->set_mm_weightvector ) + error = service->set_mm_weightvector( face, len, weightvector ); + + if ( !error ) + { + if ( len ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( len && !weightvector ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_weightvector ) + error = service->get_mm_weightvector( face, len, weightvector ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_var_design ) + error = service_mm->set_var_design( face, num_coords, coords ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_var_design ) + error = service->get_var_design( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_mm_blend ) + error = service_mm->set_mm_blend( face, num_coords, coords ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + /* This is exactly the same as the previous function. It exists for */ + /* orthogonality. */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_mm_blend ) + error = service_mm->set_mm_blend( face, num_coords, coords ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_blend ) + error = service->get_mm_blend( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + /* This is exactly the same as the previous function. It exists for */ + /* orthogonality. */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_blend ) + error = service->get_mm_blend( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Var_Axis_Flags( FT_MM_Var* master, + FT_UInt axis_index, + FT_UInt* flags ) + { + FT_UShort* axis_flags; + + + if ( !master || !flags ) + return FT_THROW( Invalid_Argument ); + + if ( axis_index >= master->num_axis ) + return FT_THROW( Invalid_Argument ); + + /* the axis flags array immediately follows the data of `master' */ + axis_flags = (FT_UShort*)&( master[1] ); + *flags = axis_flags[axis_index]; + + return FT_Err_Ok; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Named_Instance( FT_Face face, + FT_UInt instance_index ) + { + FT_Error error; + + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_named_instance ) + error = service_mm->set_named_instance( face, instance_index ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + face->face_index = ( instance_index << 16 ) | + ( face->face_index & 0xFFFFL ); + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ) + { + FT_Error error; + + FT_Service_MultiMasters service_mm = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + /* no error if `get_default_named_instance` is not available */ + if ( service_mm->get_default_named_instance ) + error = service_mm->get_default_named_instance( face, + instance_index ); + else + error = FT_Err_Ok; + } + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftobjs.c b/vendor/freetype/src/base/ftobjs.c new file mode 100644 index 0000000..89a25bc --- /dev/null +++ b/vendor/freetype/src/base/ftobjs.c @@ -0,0 +1,5914 @@ +/**************************************************************************** + * + * ftobjs.c + * + * The FreeType private base classes (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* for SFNT_Load_Table_Func */ +#include /* for PS_Driver */ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#include "ftbase.h" +#endif + + +#ifdef FT_DEBUG_LEVEL_TRACE + +#include + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `conversion from XXX to YYY, */ + /* possible loss of data' in order to compile cleanly with */ + /* the maximum level of warnings: `md5.c' is non-FreeType */ + /* code, and it gets used during development builds only. */ +#pragma warning( push ) +#pragma warning( disable : 4244 ) +#endif /* _MSC_VER */ + + /* It's easiest to include `md5.c' directly. However, since OpenSSL */ + /* also provides the same functions, there might be conflicts if */ + /* both FreeType and OpenSSL are built as static libraries. For */ + /* this reason, we put the MD5 stuff into the `FT_' namespace. */ +#define MD5_u32plus FT_MD5_u32plus +#define MD5_CTX FT_MD5_CTX +#define MD5_Init FT_MD5_Init +#define MD5_Update FT_MD5_Update +#define MD5_Final FT_MD5_Final + +#undef HAVE_OPENSSL + +#include "md5.c" + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + + /* This array must stay in sync with the @FT_Pixel_Mode enumeration */ + /* (in file `ftimage.h`). */ + + static const char* const pixel_modes[] = + { + "none", + "monochrome bitmap", + "gray 8-bit bitmap", + "gray 2-bit bitmap", + "gray 4-bit bitmap", + "LCD 8-bit bitmap", + "vertical LCD 8-bit bitmap", + "BGRA 32-bit color image bitmap", + "SDF 8-bit bitmap" + }; + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + +#define GRID_FIT_METRICS + + + /* forward declaration */ + static FT_Error + ft_open_face_internal( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface, + FT_Bool test_mac_fonts ); + + + FT_BASE_DEF( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ) + { + FT_Pointer result = NULL; + FT_ServiceDesc desc = service_descriptors; + + + if ( desc && service_id ) + { + for ( ; desc->serv_id != NULL; desc++ ) + { + if ( ft_strcmp( desc->serv_id, service_id ) == 0 ) + { + result = (FT_Pointer)desc->serv_data; + break; + } + } + } + + return result; + } + + + FT_BASE_DEF( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ) + { + valid->base = base; + valid->limit = limit; + valid->level = level; + valid->error = FT_Err_Ok; + } + + + FT_BASE_DEF( FT_Int ) + ft_validator_run( FT_Validator valid ) + { + /* This function doesn't work! None should call it. */ + FT_UNUSED( valid ); + + return -1; + } + + + FT_BASE_DEF( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ) + { + /* since the cast below also disables the compiler's */ + /* type check, we introduce a dummy variable, which */ + /* will be optimized away */ + volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer; + + + valid->error = error; + + /* throw away volatileness; use `jump_buffer' or the */ + /* compiler may warn about an unused local variable */ + ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S T R E A M ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* create a new input stream from an FT_Open_Args structure */ + /* */ + FT_BASE_DEF( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream = NULL; + FT_UInt mode; + + + *astream = NULL; + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !args ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + mode = args->flags & + ( FT_OPEN_MEMORY | FT_OPEN_STREAM | FT_OPEN_PATHNAME ); + + if ( mode == FT_OPEN_MEMORY ) + { + /* create a memory-based stream */ + if ( FT_NEW( stream ) ) + goto Exit; + + FT_Stream_OpenMemory( stream, + (const FT_Byte*)args->memory_base, + (FT_ULong)args->memory_size ); + stream->memory = memory; + } + +#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT + + else if ( mode == FT_OPEN_PATHNAME ) + { + /* create a normal system stream */ + if ( FT_NEW( stream ) ) + goto Exit; + + stream->memory = memory; + error = FT_Stream_Open( stream, args->pathname ); + if ( error ) + FT_FREE( stream ); + } + else if ( ( mode == FT_OPEN_STREAM ) && args->stream ) + { + /* use an existing, user-provided stream */ + + /* in this case, we do not need to allocate a new stream object */ + /* since the caller is responsible for closing it himself */ + stream = args->stream; + stream->memory = memory; + error = FT_Err_Ok; + } + +#endif + + else + { + error = FT_THROW( Invalid_Argument ); + if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + FT_Stream_Close( args->stream ); + } + + if ( !error ) + *astream = stream; + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ) + { + if ( stream ) + { + FT_Memory memory = stream->memory; + + + FT_Stream_Close( stream ); + + if ( !external ) + FT_FREE( stream ); + } + } + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT objs + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + ft_glyphslot_init( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + FT_Error error = FT_Err_Ok; + FT_Slot_Internal internal = NULL; + + + slot->library = driver->root.library; + + if ( FT_NEW( internal ) ) + goto Exit; + + slot->internal = internal; + + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + error = FT_GlyphLoader_New( memory, &internal->loader ); + + if ( !error && clazz->init_slot ) + error = clazz->init_slot( slot ); + +#ifdef FT_CONFIG_OPTION_SVG + /* if SVG table exists, allocate the space in `slot->other` */ + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + goto Exit; + slot->other = document; + } +#endif + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ) + { + if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + + + FT_FREE( slot->bitmap.buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + /* assume that the bitmap buffer was stolen or not */ + /* allocated from the heap */ + slot->bitmap.buffer = NULL; + } + } + + + /* overflow-resistant presetting of bitmap position and dimensions; */ + /* also check whether the size is too large for rendering */ + FT_BASE_DEF( FT_Bool ) + ft_glyphslot_preset_bitmap( FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + + FT_Pixel_Mode pixel_mode; + + FT_BBox cbox, pbox; + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + FT_Pos x_left, y_top; + FT_Pos width, height, pitch; + + + if ( slot->format == FT_GLYPH_FORMAT_SVG ) + { + FT_Module module; + SVG_Service svg_service; + + + module = FT_Get_Module( slot->library, "ot-svg" ); + svg_service = (SVG_Service)module->clazz->module_interface; + + return (FT_Bool)svg_service->preset_slot( module, slot, FALSE ); + } + else if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + return 1; + + if ( origin ) + { + x_shift = origin->x; + y_shift = origin->y; + } + + /* compute the control box, and grid-fit it, */ + /* taking into account the origin shift */ + FT_Outline_Get_CBox( outline, &cbox ); + + /* rough estimate of pixel box */ + pbox.xMin = ( cbox.xMin >> 6 ) + ( x_shift >> 6 ); + pbox.yMin = ( cbox.yMin >> 6 ) + ( y_shift >> 6 ); + pbox.xMax = ( cbox.xMax >> 6 ) + ( x_shift >> 6 ); + pbox.yMax = ( cbox.yMax >> 6 ) + ( y_shift >> 6 ); + + /* tiny remainder box */ + cbox.xMin = ( cbox.xMin & 63 ) + ( x_shift & 63 ); + cbox.yMin = ( cbox.yMin & 63 ) + ( y_shift & 63 ); + cbox.xMax = ( cbox.xMax & 63 ) + ( x_shift & 63 ); + cbox.yMax = ( cbox.yMax & 63 ) + ( y_shift & 63 ); + + switch ( mode ) + { + case FT_RENDER_MODE_MONO: + pixel_mode = FT_PIXEL_MODE_MONO; +#if 1 + /* x */ + + /* undocumented but confirmed: bbox values get rounded; */ + /* we do asymmetric rounding so that the center of a pixel */ + /* gets always included */ + + pbox.xMin += ( cbox.xMin + 31 ) >> 6; + pbox.xMax += ( cbox.xMax + 32 ) >> 6; + + /* if the bbox collapsed, we add a pixel based on the total */ + /* rounding remainder to cover most of the original cbox */ + + if ( pbox.xMin == pbox.xMax ) + { + if ( ( ( cbox.xMin + 31 ) & 63 ) - 31 + + ( ( cbox.xMax + 32 ) & 63 ) - 32 < 0 ) + pbox.xMin -= 1; + else + pbox.xMax += 1; + } + + /* y */ + + pbox.yMin += ( cbox.yMin + 31 ) >> 6; + pbox.yMax += ( cbox.yMax + 32 ) >> 6; + + if ( pbox.yMin == pbox.yMax ) + { + if ( ( ( cbox.yMin + 31 ) & 63 ) - 31 + + ( ( cbox.yMax + 32 ) & 63 ) - 32 < 0 ) + pbox.yMin -= 1; + else + pbox.yMax += 1; + } + + break; +#else + goto Adjust; +#endif + + case FT_RENDER_MODE_LCD: + pixel_mode = FT_PIXEL_MODE_LCD; + ft_lcd_padding( &cbox, slot, mode ); + goto Adjust; + + case FT_RENDER_MODE_LCD_V: + pixel_mode = FT_PIXEL_MODE_LCD_V; + ft_lcd_padding( &cbox, slot, mode ); + goto Adjust; + + case FT_RENDER_MODE_NORMAL: + case FT_RENDER_MODE_LIGHT: + default: + pixel_mode = FT_PIXEL_MODE_GRAY; + Adjust: + pbox.xMin += cbox.xMin >> 6; + pbox.yMin += cbox.yMin >> 6; + pbox.xMax += ( cbox.xMax + 63 ) >> 6; + pbox.yMax += ( cbox.yMax + 63 ) >> 6; + } + + x_left = pbox.xMin; + y_top = pbox.yMax; + + width = pbox.xMax - pbox.xMin; + height = pbox.yMax - pbox.yMin; + + switch ( pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + pitch = ( ( width + 15 ) >> 4 ) << 1; + break; + + case FT_PIXEL_MODE_LCD: + width *= 3; + pitch = FT_PAD_CEIL( width, 4 ); + break; + + case FT_PIXEL_MODE_LCD_V: + height *= 3; + FALL_THROUGH; + + case FT_PIXEL_MODE_GRAY: + default: + pitch = width; + } + + slot->bitmap_left = (FT_Int)x_left; + slot->bitmap_top = (FT_Int)y_top; + + bitmap->pixel_mode = (unsigned char)pixel_mode; + bitmap->num_grays = 256; + bitmap->width = (unsigned int)width; + bitmap->rows = (unsigned int)height; + bitmap->pitch = pitch; + + if ( pbox.xMin < -0x8000 || pbox.xMax > 0x7FFF || + pbox.yMin < -0x8000 || pbox.yMax > 0x7FFF ) + { + FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n", + pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax )); + return 1; + } + + return 0; + } + + + FT_BASE_DEF( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ) + { + ft_glyphslot_free_bitmap( slot ); + + slot->bitmap.buffer = buffer; + + FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 ); + } + + + FT_BASE_DEF( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_Error error; + + + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + FT_FREE( slot->bitmap.buffer ); + else + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + FT_MEM_ALLOC( slot->bitmap.buffer, size ); + return error; + } + + + static void + ft_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* clear all public fields in the glyph slot */ + slot->glyph_index = 0; + + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + + slot->bitmap.width = 0; + slot->bitmap.rows = 0; + slot->bitmap.pitch = 0; + slot->bitmap.pixel_mode = 0; + /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */ + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = NULL; + slot->control_data = NULL; + slot->control_len = 0; + +#ifndef FT_CONFIG_OPTION_SVG + slot->other = NULL; +#else + if ( !( slot->face->face_flags & FT_FACE_FLAG_SVG ) ) + slot->other = NULL; + else + { + if ( slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_Memory memory = slot->face->memory; + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + } +#endif + + slot->format = FT_GLYPH_FORMAT_NONE; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + slot->advance.x = 0; + slot->advance.y = 0; + slot->lsb_delta = 0; + slot->rsb_delta = 0; + } + + + static void + ft_glyphslot_done( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + +#ifdef FT_CONFIG_OPTION_SVG + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + /* Free memory in case SVG was there. */ + /* `slot->internal` might be NULL in out-of-memory situations. */ + if ( slot->internal && slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + + slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + + FT_FREE( slot->other ); + } +#endif + + if ( clazz->done_slot ) + clazz->done_slot( slot ); + + /* free bitmap buffer if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* slot->internal might be NULL in out-of-memory situations */ + if ( slot->internal ) + { + /* free glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + FT_GlyphLoader_Done( slot->internal->loader ); + slot->internal->loader = NULL; + } + + FT_FREE( slot->internal ); + } + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ) + { + FT_Error error; + FT_Driver driver; + FT_Driver_Class clazz; + FT_Memory memory; + FT_GlyphSlot slot = NULL; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !face->driver ) + return FT_THROW( Invalid_Argument ); + + driver = face->driver; + clazz = driver->clazz; + memory = driver->root.memory; + + FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); + if ( !FT_ALLOC( slot, clazz->slot_object_size ) ) + { + slot->face = face; + + error = ft_glyphslot_init( slot ); + if ( error ) + { + ft_glyphslot_done( slot ); + FT_FREE( slot ); + goto Exit; + } + + slot->next = face->glyph; + face->glyph = slot; + + if ( aslot ) + *aslot = slot; + } + else if ( aslot ) + *aslot = NULL; + + + Exit: + FT_TRACE4(( "FT_New_GlyphSlot: Return 0x%x\n", error )); + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ) + { + if ( slot ) + { + FT_Driver driver = slot->face->driver; + FT_Memory memory = driver->root.memory; + FT_GlyphSlot prev; + FT_GlyphSlot cur; + + + /* Remove slot from its parent face's list */ + prev = NULL; + cur = slot->face->glyph; + + while ( cur ) + { + if ( cur == slot ) + { + if ( !prev ) + slot->face->glyph = cur->next; + else + prev->next = cur->next; + + /* finalize client-specific data */ + if ( slot->generic.finalizer ) + slot->generic.finalizer( slot ); + + ft_glyphslot_done( slot ); + FT_FREE( slot ); + break; + } + prev = cur; + cur = cur->next; + } + } + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + + + if ( !face ) + return; + + internal = face->internal; + + internal->transform_flags = 0; + + if ( !matrix ) + { + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + + matrix = &internal->transform_matrix; + } + else + internal->transform_matrix = *matrix; + + /* set transform_flags bit flag 0 if `matrix' isn't the identity */ + if ( ( matrix->xy | matrix->yx ) || + matrix->xx != 0x10000L || + matrix->yy != 0x10000L ) + internal->transform_flags |= 1; + + if ( !delta ) + { + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + + delta = &internal->transform_delta; + } + else + internal->transform_delta = *delta; + + /* set transform_flags bit flag 1 if `delta' isn't the null vector */ + if ( delta->x | delta->y ) + internal->transform_flags |= 2; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + + + if ( !face ) + return; + + internal = face->internal; + + if ( matrix ) + *matrix = internal->transform_matrix; + + if ( delta ) + *delta = internal->transform_delta; + } + + + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ); + + +#ifdef GRID_FIT_METRICS + static void + ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, + FT_Bool vertical ) + { + FT_Glyph_Metrics* metrics = &slot->metrics; + FT_Pos right, bottom; + + + if ( vertical ) + { + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY ); + + right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingX, + metrics->width ) ); + bottom = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingY, + metrics->height ) ); + + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + + metrics->width = SUB_LONG( right, + metrics->vertBearingX ); + metrics->height = SUB_LONG( bottom, + metrics->vertBearingY ); + } + else + { + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + + right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->horiBearingX, + metrics->width ) ); + bottom = FT_PIX_FLOOR( SUB_LONG( metrics->horiBearingY, + metrics->height ) ); + + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY ); + + metrics->width = SUB_LONG( right, + metrics->horiBearingX ); + metrics->height = SUB_LONG( metrics->horiBearingY, + bottom ); + } + + metrics->horiAdvance = FT_PIX_ROUND_LONG( metrics->horiAdvance ); + metrics->vertAdvance = FT_PIX_ROUND_LONG( metrics->vertAdvance ); + } +#endif /* GRID_FIT_METRICS */ + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + FT_Driver driver; + FT_GlyphSlot slot; + FT_Library library; + FT_Bool autohint = FALSE; + FT_Module hinter; + TT_Face ttface = (TT_Face)face; + + + if ( !face || !face->size || !face->glyph ) + return FT_THROW( Invalid_Face_Handle ); + + /* The validity test for `glyph_index' is performed by the */ + /* font drivers. */ + + slot = face->glyph; + ft_glyphslot_clear( slot ); + + driver = face->driver; + library = driver->root.library; + hinter = library->auto_hinter; + + /* undefined scale means no scale */ + if ( face->size->metrics.x_ppem == 0 || + face->size->metrics.y_ppem == 0 ) + load_flags |= FT_LOAD_NO_SCALE; + + /* resolve load flags dependencies */ + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM; + + if ( load_flags & FT_LOAD_NO_SCALE ) + { + load_flags |= FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP; + + load_flags &= ~FT_LOAD_RENDER; + } + + if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) + load_flags &= ~FT_LOAD_RENDER; + + /* + * Determine whether we need to auto-hint or not. + * The general rules are: + * + * - Do only auto-hinting if we have + * + * - a hinter module, + * - a scalable font, + * - not a tricky font, and + * - no transforms except simple slants and/or rotations by + * integer multiples of 90 degrees. + * + * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't + * have a native font hinter. + * + * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't + * any hinting bytecode in the TrueType/OpenType font. + * + * - Exception: The font is `tricky' and requires the native hinter to + * load properly. + */ + + if ( hinter && + !( load_flags & FT_LOAD_NO_HINTING ) && + !( load_flags & FT_LOAD_NO_AUTOHINT ) && + FT_IS_SCALABLE( face ) && + !FT_IS_TRICKY( face ) && + ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) || + ( face->internal->transform_matrix.yx == 0 && + face->internal->transform_matrix.xx != 0 ) || + ( face->internal->transform_matrix.xx == 0 && + face->internal->transform_matrix.yx != 0 ) ) ) + { + if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) || + !FT_DRIVER_HAS_HINTER( driver ) ) + autohint = TRUE; + else + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + FT_Bool is_light_type1; + + + /* only the new Adobe engine (for both CFF and Type 1) is `light'; */ + /* we use `strstr' to catch both `Type 1' and `CID Type 1' */ + is_light_type1 = + ft_strstr( FT_Get_Font_Format( face ), "Type 1" ) != NULL && + ((PS_Driver)driver)->hinting_engine == FT_HINTING_ADOBE; + + /* the check for `num_locations' assures that we actually */ + /* test for instructions in a TTF and not in a CFF-based OTF */ + /* */ + /* since `maxSizeOfInstructions' might be unreliable, we */ + /* check the size of the `fpgm' and `prep' tables, too -- */ + /* the assumption is that there don't exist real TTFs where */ + /* both `fpgm' and `prep' tables are missing */ + if ( ( mode == FT_RENDER_MODE_LIGHT && + ( !FT_DRIVER_HINTS_LIGHTLY( driver ) && + !is_light_type1 ) ) || + ( FT_IS_SFNT( face ) && + ttface->num_locations && + ttface->max_profile.maxSizeOfInstructions == 0 && + ttface->font_program_size == 0 && + ttface->cvt_program_size == 0 ) ) + autohint = TRUE; + } + } + + if ( autohint ) + { + FT_AutoHinter_Interface hinting; + + + /* XXX: The use of the `FT_LOAD_XXX_ONLY` flags is not very */ + /* elegant. */ + + /* try to load SVG documents if available */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + FT_HAS_SVG( face ) ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SVG_ONLY ); + + if ( !error && slot->format == FT_GLYPH_FORMAT_SVG ) + goto Load_Ok; + } + + /* try to load embedded bitmaps if available */ + if ( FT_HAS_FIXED_SIZES( face ) && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SBITS_ONLY ); + + if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP ) + goto Load_Ok; + } + + { + FT_Face_Internal internal = face->internal; + FT_Int transform_flags = internal->transform_flags; + + + /* since the auto-hinter calls FT_Load_Glyph by itself, */ + /* make sure that glyphs aren't transformed */ + internal->transform_flags = 0; + + /* load auto-hinted outline */ + hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface; + + error = hinting->load_glyph( (FT_AutoHinter)hinter, + slot, face->size, + glyph_index, load_flags ); + + internal->transform_flags = transform_flags; + } + } + else + { + error = driver->clazz->load_glyph( slot, + face->size, + glyph_index, + load_flags ); + if ( error ) + goto Exit; + + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + /* check that the loaded outline is correct */ + error = FT_Outline_Check( &slot->outline ); + if ( error ) + goto Exit; + +#ifdef GRID_FIT_METRICS + if ( !( load_flags & FT_LOAD_NO_HINTING ) ) + ft_glyphslot_grid_fit_metrics( + slot, + FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ); +#endif + } + } + + Load_Ok: + /* compute the advance */ + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + slot->advance.x = 0; + slot->advance.y = slot->metrics.vertAdvance; + } + else + { + slot->advance.x = slot->metrics.horiAdvance; + slot->advance.y = 0; + } + + /* compute the linear advance in 16.16 pixels */ + if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 && + FT_IS_SCALABLE( face ) ) + { + FT_Size_Metrics* metrics = &face->size->metrics; + + + /* it's tricky! */ + slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance, + metrics->x_scale, 64 ); + + slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance, + metrics->y_scale, 64 ); + } + + if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 ) + { + FT_Face_Internal internal = face->internal; + + + /* now, transform the glyph image if needed */ + if ( internal->transform_flags ) + { + /* get renderer */ + FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); + + + if ( renderer ) + error = renderer->clazz->transform_glyph( + renderer, slot, + &internal->transform_matrix, + &internal->transform_delta ); + else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + /* apply `standard' transformation if no renderer is available */ + if ( internal->transform_flags & 1 ) + FT_Outline_Transform( &slot->outline, + &internal->transform_matrix ); + + if ( internal->transform_flags & 2 ) + FT_Outline_Translate( &slot->outline, + internal->transform_delta.x, + internal->transform_delta.y ); + } + + /* transform advance */ + FT_Vector_Transform( &slot->advance, &internal->transform_matrix ); + } + } + + slot->glyph_index = glyph_index; + slot->internal->load_flags = load_flags; + + /* do we need to render the image or preset the bitmap now? */ + if ( !error && + ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + slot->format != FT_GLYPH_FORMAT_BITMAP && + slot->format != FT_GLYPH_FORMAT_COMPOSITE ) + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + + + if ( mode == FT_RENDER_MODE_NORMAL && + load_flags & FT_LOAD_MONOCHROME ) + mode = FT_RENDER_MODE_MONO; + + if ( load_flags & FT_LOAD_RENDER ) + error = FT_Render_Glyph( slot, mode ); + else + ft_glyphslot_preset_bitmap( slot, mode, NULL ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n", + glyph_index, load_flags )); + FT_TRACE5(( " bitmap %dx%d %s, %s (mode %d)\n", + slot->bitmap.width, + slot->bitmap.rows, + slot->outline.points ? + slot->bitmap.buffer ? "rendered" + : "preset" + : + slot->internal->flags & FT_GLYPH_OWN_BITMAP ? "owned" + : "unowned", + pixel_modes[slot->bitmap.pixel_mode], + slot->bitmap.pixel_mode )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " x advance: %f\n", (double)slot->advance.x / 64 )); + FT_TRACE5(( " y advance: %f\n", (double)slot->advance.y / 64 )); + FT_TRACE5(( " linear x advance: %f\n", + (double)slot->linearHoriAdvance / 65536 )); + FT_TRACE5(( " linear y advance: %f\n", + (double)slot->linearVertAdvance / 65536 )); + + { + FT_Glyph_Metrics* metrics = &slot->metrics; + + + FT_TRACE5(( " metrics:\n" )); + FT_TRACE5(( " width: %f\n", (double)metrics->width / 64 )); + FT_TRACE5(( " height: %f\n", (double)metrics->height / 64 )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " horiBearingX: %f\n", + (double)metrics->horiBearingX / 64 )); + FT_TRACE5(( " horiBearingY: %f\n", + (double)metrics->horiBearingY / 64 )); + FT_TRACE5(( " horiAdvance: %f\n", + (double)metrics->horiAdvance / 64 )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " vertBearingX: %f\n", + (double)metrics->vertBearingX / 64 )); + FT_TRACE5(( " vertBearingY: %f\n", + (double)metrics->vertBearingY / 64 )); + FT_TRACE5(( " vertAdvance: %f\n", + (double)metrics->vertAdvance / 64 )); + } +#endif + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ) + { + FT_UInt glyph_index; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + glyph_index = (FT_UInt)char_code; + if ( face->charmap ) + glyph_index = FT_Get_Char_Index( face, char_code ); + + return FT_Load_Glyph( face, glyph_index, load_flags ); + } + + + /* destructor for sizes list */ + static void + destroy_size( FT_Memory memory, + void* size_, + void* driver_ ) + { + FT_Size size = (FT_Size)size_; + FT_Driver driver = (FT_Driver)driver_; + + + /* finalize client-specific data */ + if ( size->generic.finalizer ) + size->generic.finalizer( size ); + + /* finalize format-specific stuff */ + if ( driver->clazz->done_size ) + driver->clazz->done_size( size ); + + FT_FREE( size->internal ); + FT_FREE( size ); + } + + + static void + ft_cmap_done_internal( FT_CMap cmap ); + + + static void + destroy_charmaps( FT_Face face, + FT_Memory memory ) + { + FT_Int n; + + + if ( !face ) + return; + + for ( n = 0; n < face->num_charmaps; n++ ) + { + FT_CMap cmap = FT_CMAP( face->charmaps[n] ); + + + ft_cmap_done_internal( cmap ); + + face->charmaps[n] = NULL; + } + + FT_FREE( face->charmaps ); + face->num_charmaps = 0; + } + + + /* destructor for faces list */ + static void + destroy_face( FT_Memory memory, + void* face_, + void* driver_ ) + { + FT_Face face = (FT_Face)face_; + FT_Driver driver = (FT_Driver)driver_; + FT_Driver_Class clazz = driver->clazz; + + + /* discard auto-hinting data */ + if ( face->autohint.finalizer ) + face->autohint.finalizer( face->autohint.data ); + + /* Discard glyph slots for this face. */ + /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */ + while ( face->glyph ) + FT_Done_GlyphSlot( face->glyph ); + + /* discard all sizes for this face */ + FT_List_Finalize( &face->sizes_list, + destroy_size, + memory, + driver ); + face->size = NULL; + + /* now discard client data */ + if ( face->generic.finalizer ) + face->generic.finalizer( face ); + + /* discard charmaps */ + destroy_charmaps( face, memory ); + + /* finalize format-specific stuff */ + if ( clazz->done_face ) + clazz->done_face( face ); + + /* close the stream for this face if needed */ + FT_Stream_Free( + face->stream, + ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->stream = NULL; + + /* get rid of it */ + if ( face->internal ) + { + FT_FREE( face->internal ); + } + FT_FREE( face ); + } + + + static void + Destroy_Driver( FT_Driver driver ) + { + FT_List_Finalize( &driver->faces_list, + destroy_face, + driver->root.memory, + driver ); + } + + + /************************************************************************** + * + * @Function: + * find_unicode_charmap + * + * @Description: + * This function finds a Unicode charmap, if there is one. + * And if there is more than one, it tries to favour the more + * extensive one, i.e., one that supports UCS-4 against those which + * are limited to the BMP (said UCS-2 encoding.) + * + * This function is called from open_face() (just below), and also + * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). + */ + static FT_Error + find_unicode_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* cur; + + + /* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + + first = face->charmaps; + + if ( !first ) + return FT_THROW( Invalid_CharMap_Handle ); + + /* + * The original TrueType specification(s) only specified charmap + * formats that are capable of mapping 8 or 16 bit character codes to + * glyph indices. + * + * However, recent updates to the Apple and OpenType specifications + * introduced new formats that are capable of mapping 32-bit character + * codes as well. And these are already used on some fonts, mainly to + * map non-BMP Asian ideographs as defined in Unicode. + * + * For compatibility purposes, these fonts generally come with + * *several* Unicode charmaps: + * + * - One of them in the "old" 16-bit format, that cannot access + * all glyphs in the font. + * + * - Another one in the "new" 32-bit format, that can access all + * the glyphs. + * + * This function has been written to always favor a 32-bit charmap + * when found. Otherwise, a 16-bit one is returned when found. + */ + + /* Since the `interesting' table, with IDs (3,10), is normally the */ + /* last one, we loop backwards. This loses with type1 fonts with */ + /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */ + /* chars (.01% ?), and this is the same about 99.99% of the time! */ + + cur = first + face->num_charmaps; /* points after the last one */ + + for ( ; --cur >= first; ) + { + if ( cur[0]->encoding == FT_ENCODING_UNICODE ) + { + /* XXX If some new encodings to represent UCS-4 are added, */ + /* they should be added here. */ + if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT && + cur[0]->encoding_id == TT_MS_ID_UCS_4 ) || + ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + } + + /* We do not have any UCS-4 charmap. */ + /* Do the loop again and search for UCS-2 charmaps. */ + cur = first + face->num_charmaps; + + for ( ; --cur >= first; ) + { + if ( cur[0]->encoding == FT_ENCODING_UNICODE ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + + return FT_THROW( Invalid_CharMap_Handle ); + } + + + /************************************************************************** + * + * @Function: + * find_variant_selector_charmap + * + * @Description: + * This function finds the variant selector charmap, if there is one. + * There can only be one (platform=0, specific=5, format=14). + */ + static FT_CharMap + find_variant_selector_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* end; + FT_CharMap* cur; + + + /* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + + first = face->charmaps; + + if ( !first ) + return NULL; + + end = first + face->num_charmaps; /* points after the last one */ + + for ( cur = first; cur < end; cur++ ) + { + if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR && + FT_Get_CMap_Format( cur[0] ) == 14 ) + return cur[0]; + } + + return NULL; + } + + + /************************************************************************** + * + * @Function: + * open_face + * + * @Description: + * This function does some work for FT_Open_Face(). + */ + static FT_Error + open_face( FT_Driver driver, + FT_Stream *astream, + FT_Bool *anexternal_stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter* params, + FT_Face *aface ) + { + FT_Memory memory; + FT_Driver_Class clazz; + FT_Face face = NULL; + FT_Face_Internal internal = NULL; + + FT_Error error, error2; + + + clazz = driver->clazz; + memory = driver->root.memory; + + /* allocate the face object and perform basic initialization */ + if ( FT_ALLOC( face, clazz->face_object_size ) ) + goto Fail; + + face->driver = driver; + face->memory = memory; + face->stream = *astream; + + /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ + if ( *anexternal_stream ) + face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; + + if ( FT_NEW( internal ) ) + goto Fail; + + face->internal = internal; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + { + int i; + + + face->internal->incremental_interface = NULL; + for ( i = 0; i < num_params && !face->internal->incremental_interface; + i++ ) + if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL ) + face->internal->incremental_interface = + (FT_Incremental_Interface)params[i].data; + } +#endif + + face->internal->random_seed = -1; + + if ( clazz->init_face ) + error = clazz->init_face( *astream, + face, + (FT_Int)face_index, + num_params, + params ); + /* Stream may have been changed. */ + *astream = face->stream; + *anexternal_stream = + ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0; + if ( error ) + goto Fail; + + /* select Unicode charmap by default */ + error2 = find_unicode_charmap( face ); + + /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */ + /* is returned. */ + + /* no error should happen, but we want to play safe */ + if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) ) + { + error = error2; + goto Fail; + } + + *aface = face; + + Fail: + if ( error ) + { + destroy_charmaps( face, memory ); + if ( clazz->done_face ) + clazz->done_face( face ); + FT_FREE( internal ); + FT_FREE( face ); + *aface = NULL; + } + + return error; + } + + + /* there's a Mac-specific extended implementation of FT_New_Face() */ + /* in src/base/ftmac.c */ + +#ifndef FT_MACINTOSH + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; + + + /* test for valid `library' and `aface' delayed to `FT_Open_Face' */ + if ( !pathname ) + return FT_THROW( Invalid_Argument ); + + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + args.stream = NULL; + + return ft_open_face_internal( library, &args, face_index, aface, 1 ); + } + +#endif + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; + + + /* test for valid `library' and `face' delayed to `FT_Open_Face' */ + if ( !file_base ) + return FT_THROW( Invalid_Argument ); + + args.flags = FT_OPEN_MEMORY; + args.memory_base = file_base; + args.memory_size = file_size; + args.stream = NULL; + + return ft_open_face_internal( library, &args, face_index, aface, 1 ); + } + + +#ifdef FT_CONFIG_OPTION_MAC_FONTS + + /* The behavior here is very similar to that in base/ftmac.c, but it */ + /* is designed to work on non-mac systems, so no mac specific calls. */ + /* */ + /* We look at the file and determine if it is a mac dfont file or a mac */ + /* resource file, or a macbinary file containing a mac resource file. */ + /* */ + /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */ + /* the point, especially since there may be multiple `FOND' resources. */ + /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */ + /* they occur in the file. */ + /* */ + /* Note that multiple `POST' resources do not mean multiple postscript */ + /* fonts; they all get jammed together to make what is essentially a */ + /* pfb file. */ + /* */ + /* We aren't interested in `NFNT' or `FONT' bitmap resources. */ + /* */ + /* As soon as we get an `sfnt' load it into memory and pass it off to */ + /* FT_Open_Face. */ + /* */ + /* If we have a (set of) `POST' resources, massage them into a (memory) */ + /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */ + /* going to try to save the kerning info. After all that lives in the */ + /* `FOND' which isn't in the file containing the `POST' resources so */ + /* we don't really have access to it. */ + + + /* Finalizer for a memory stream; gets called by FT_Done_Face(). */ + /* It frees the memory it uses. */ + /* From `ftmac.c'. */ + static void + memory_stream_close( FT_Stream stream ) + { + FT_Memory memory = (FT_Memory)stream->descriptor.pointer; + + + FT_FREE( stream->base ); + stream->size = 0; + stream->close = NULL; + FT_FREE( stream ); + } + + + /* Create a new memory stream from a buffer and a size. */ + /* From `ftmac.c'. */ + static FT_Error + new_memory_stream( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Stream_CloseFunc close, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream = NULL; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !base ) + return FT_THROW( Invalid_Argument ); + + *astream = NULL; + memory = library->memory; + if ( FT_NEW( stream ) ) + goto Exit; + + FT_Stream_OpenMemory( stream, base, size ); + + stream->descriptor.pointer = memory; + stream->close = close; + + *astream = stream; + + Exit: + return error; + } + + + /* Create a new FT_Face given a buffer and a driver name. */ + /* From `ftmac.c'. */ + FT_LOCAL_DEF( FT_Error ) + open_face_from_buffer( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Long face_index, + const char* driver_name, + FT_Face *aface ) + { + FT_Open_Args args; + FT_Error error; + FT_Memory memory = library->memory; + + + args.driver = NULL; + args.flags = 0; + + if ( driver_name ) + { + args.driver = FT_Get_Module( library, driver_name ); + if ( !args.driver ) + { + FT_FREE( base ); + return FT_THROW( Missing_Module ); + } + + args.flags = args.flags | FT_OPEN_DRIVER; + } + + /* `memory_stream_close` also frees the stream object. */ + error = new_memory_stream( library, + base, + size, + memory_stream_close, + &args.stream ); + if ( error ) + { + FT_FREE( base ); + return error; + } + + args.flags |= FT_OPEN_STREAM; + +#ifdef FT_MACINTOSH + /* At this point, the face index has served its purpose; */ + /* whoever calls this function has already used it to */ + /* locate the correct font data. We should not propagate */ + /* this index to FT_Open_Face() (unless it is negative). */ + + if ( face_index > 0 ) + face_index &= 0x7FFF0000L; /* retain GX data */ +#endif + + return ft_open_face_internal( library, &args, face_index, aface, 0 ); + } + + + /* Look up `TYP1' or `CID ' table from sfnt table directory. */ + /* `offset' and `length' must exclude the binary header in tables. */ + + /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */ + /* format too. Here, since we can't expect that the TrueType font */ + /* driver is loaded unconditionally, we must parse the font by */ + /* ourselves. We are only interested in the name of the table and */ + /* the offset. */ + + static FT_Error + ft_lookup_PS_in_sfnt_stream( FT_Stream stream, + FT_Long face_index, + FT_ULong* offset, + FT_ULong* length, + FT_Bool* is_sfnt_cid ) + { + FT_Error error; + FT_UShort numTables; + FT_Long pstable_index; + FT_ULong tag; + int i; + + + *offset = 0; + *length = 0; + *is_sfnt_cid = FALSE; + + /* TODO: support for sfnt-wrapped PS/CID in TTC format */ + + /* version check for 'typ1' (should be ignored?) */ + if ( FT_READ_ULONG( tag ) ) + return error; + if ( tag != TTAG_typ1 ) + return FT_THROW( Unknown_File_Format ); + + if ( FT_READ_USHORT( numTables ) ) + return error; + if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */ + return error; + + pstable_index = -1; + *is_sfnt_cid = FALSE; + + for ( i = 0; i < numTables; i++ ) + { + if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) || + FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) ) + return error; + + if ( tag == TTAG_CID ) + { + pstable_index++; + *offset += 22; + *length -= 22; + *is_sfnt_cid = TRUE; + if ( face_index < 0 ) + return FT_Err_Ok; + } + else if ( tag == TTAG_TYP1 ) + { + pstable_index++; + *offset += 24; + *length -= 24; + *is_sfnt_cid = FALSE; + if ( face_index < 0 ) + return FT_Err_Ok; + } + if ( face_index >= 0 && pstable_index == face_index ) + return FT_Err_Ok; + } + + return FT_THROW( Table_Missing ); + } + + + FT_LOCAL_DEF( FT_Error ) + open_face_PS_from_sfnt_stream( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter *params, + FT_Face *aface ) + { + FT_Error error; + FT_Memory memory = library->memory; + FT_ULong offset, length; + FT_ULong pos; + FT_Bool is_sfnt_cid; + FT_Byte* sfnt_ps = NULL; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + /* ignore GX stuff */ + if ( face_index > 0 ) + face_index &= 0xFFFFL; + + pos = FT_STREAM_POS(); + + error = ft_lookup_PS_in_sfnt_stream( stream, + face_index, + &offset, + &length, + &is_sfnt_cid ); + if ( error ) + goto Exit; + + if ( offset > stream->size ) + { + FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table offset\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + else if ( length > stream->size - offset ) + { + FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table length\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + error = FT_Stream_Seek( stream, pos + offset ); + if ( error ) + goto Exit; + + if ( FT_QALLOC( sfnt_ps, (FT_Long)length ) ) + goto Exit; + + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length ); + if ( error ) + { + FT_FREE( sfnt_ps ); + goto Exit; + } + + error = open_face_from_buffer( library, + sfnt_ps, + length, + FT_MIN( face_index, 0 ), + is_sfnt_cid ? "t1cid" : "type1", + aface ); + Exit: + { + FT_Error error1; + + + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + error1 = FT_Stream_Seek( stream, pos ); + if ( error1 ) + return error1; + } + + return error; + } + } + + +#ifndef FT_MACINTOSH + + /* The resource header says we've got resource_cnt `POST' (type1) */ + /* resources in this file. They all need to be coalesced into */ + /* one lump which gets passed on to the type1 driver. */ + /* Here can be only one PostScript font in a file so face_index */ + /* must be 0 (or -1). */ + /* */ + static FT_Error + Mac_Read_POST_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Error error = FT_ERR( Cannot_Open_Resource ); + FT_Memory memory = library->memory; + + FT_Byte* pfb_data = NULL; + int i, type, flags; + FT_ULong len; + FT_ULong pfb_len, pfb_pos, pfb_lenpos; + FT_ULong rlen, temp; + + + if ( face_index == -1 ) + face_index = 0; + if ( face_index != 0 ) + return error; + + /* Find the length of all the POST resources, concatenated. Assume */ + /* worst case (each resource in its own section). */ + pfb_len = 0; + for ( i = 0; i < resource_cnt; i++ ) + { + error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] ); + if ( error ) + goto Exit; + if ( FT_READ_ULONG( temp ) ) /* actually LONG */ + goto Exit; + + /* FT2 allocator takes signed long buffer length, + * too large value causing overflow should be checked + */ + FT_TRACE4(( " POST fragment #%d: length=0x%08lx" + " total pfb_len=0x%08lx\n", + i, temp, pfb_len + temp + 6 )); + + if ( FT_MAC_RFORK_MAX_LEN < temp || + FT_MAC_RFORK_MAX_LEN - temp < pfb_len + 6 ) + { + FT_TRACE2(( " MacOS resource length cannot exceed" + " 0x%08lx\n", + FT_MAC_RFORK_MAX_LEN )); + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + + pfb_len += temp + 6; + } + + FT_TRACE2(( " total buffer size to concatenate" + " %ld POST fragments: 0x%08lx\n", + resource_cnt, pfb_len + 2 )); + + if ( pfb_len + 2 < 6 ) + { + FT_TRACE2(( " too long fragment length makes" + " pfb_len confused: pfb_len=0x%08lx\n", + pfb_len )); + + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + if ( FT_QALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) + goto Exit; + + pfb_data[0] = 0x80; + pfb_data[1] = 1; /* Ascii section */ + pfb_data[2] = 0; /* 4-byte length, fill in later */ + pfb_data[3] = 0; + pfb_data[4] = 0; + pfb_data[5] = 0; + pfb_pos = 6; + pfb_lenpos = 2; + + len = 0; + type = 1; + + for ( i = 0; i < resource_cnt; i++ ) + { + error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] ); + if ( error ) + goto Exit2; + if ( FT_READ_ULONG( rlen ) ) + goto Exit2; + + /* FT2 allocator takes signed long buffer length, + * too large fragment length causing overflow should be checked + */ + if ( 0x7FFFFFFFUL < rlen ) + { + error = FT_THROW( Invalid_Offset ); + goto Exit2; + } + + if ( FT_READ_USHORT( flags ) ) + goto Exit2; + + FT_TRACE3(( "POST fragment[%d]:" + " offsets=0x%08lx, rlen=0x%08lx, flags=0x%04x\n", + i, offsets[i], rlen, flags )); + + error = FT_ERR( Array_Too_Large ); + + /* postpone the check of `rlen longer than buffer' */ + /* until `FT_Stream_Read' */ + + if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */ + { + FT_TRACE3(( " Skip POST fragment #%d because it is a comment\n", + i )); + continue; + } + + /* the flags are part of the resource, so rlen >= 2, */ + /* but some fonts declare rlen = 0 for empty fragment */ + if ( rlen > 2 ) + rlen -= 2; + else + rlen = 0; + + if ( ( flags >> 8 ) == type ) + len += rlen; + else + { + FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer" + " %p + 0x%08lx\n", + i, (void*)pfb_data, pfb_lenpos )); + + if ( pfb_lenpos + 3 > pfb_len + 2 ) + goto Exit2; + + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); + + if ( ( flags >> 8 ) == 5 ) /* End of font mark */ + break; + + FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer" + " %p + 0x%08lx\n", + i, (void*)pfb_data, pfb_pos )); + + if ( pfb_pos + 6 > pfb_len + 2 ) + goto Exit2; + + pfb_data[pfb_pos++] = 0x80; + + type = flags >> 8; + len = rlen; + + pfb_data[pfb_pos++] = (FT_Byte)type; + pfb_lenpos = pfb_pos; + pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */ + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + } + + if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len ) + goto Exit2; + + FT_TRACE3(( " Load POST fragment #%d (%ld byte) to buffer" + " %p + 0x%08lx\n", + i, rlen, (void*)pfb_data, pfb_pos )); + + error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); + if ( error ) + goto Exit2; + + pfb_pos += rlen; + } + + error = FT_ERR( Array_Too_Large ); + + if ( pfb_pos + 2 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_pos++] = 0x80; + pfb_data[pfb_pos++] = 3; + + if ( pfb_lenpos + 3 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); + + return open_face_from_buffer( library, + pfb_data, + pfb_pos, + face_index, + "type1", + aface ); + + Exit2: + if ( FT_ERR_EQ( error, Array_Too_Large ) ) + FT_TRACE2(( " Abort due to too-short buffer to store" + " all POST fragments\n" )); + else if ( FT_ERR_EQ( error, Invalid_Offset ) ) + FT_TRACE2(( " Abort due to invalid offset in a POST fragment\n" )); + + if ( error ) + error = FT_ERR( Cannot_Open_Resource ); + FT_FREE( pfb_data ); + + Exit: + return error; + } + + + /* The resource header says we've got resource_cnt `sfnt' */ + /* (TrueType/OpenType) resources in this file. Look through */ + /* them for the one indicated by face_index, load it into mem, */ + /* pass it on to the truetype driver, and return it. */ + /* */ + static FT_Error + Mac_Read_sfnt_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Byte* sfnt_data = NULL; + FT_Error error; + FT_ULong flag_offset; + FT_ULong rlen; + int is_cff; + FT_Long face_index_in_resource = 0; + + + if ( face_index < 0 ) + face_index = -face_index - 1; + if ( face_index >= resource_cnt ) + return FT_THROW( Cannot_Open_Resource ); + + flag_offset = (FT_ULong)offsets[face_index]; + error = FT_Stream_Seek( stream, flag_offset ); + if ( error ) + goto Exit; + + if ( FT_READ_ULONG( rlen ) ) + goto Exit; + if ( !rlen ) + return FT_THROW( Cannot_Open_Resource ); + if ( rlen > FT_MAC_RFORK_MAX_LEN ) + return FT_THROW( Invalid_Offset ); + + error = open_face_PS_from_sfnt_stream( library, + stream, + face_index, + 0, NULL, + aface ); + if ( !error ) + goto Exit; + + /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */ + error = FT_Stream_Seek( stream, flag_offset + 4 ); + if ( error ) + goto Exit; + + if ( FT_QALLOC( sfnt_data, rlen ) ) + return error; + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen ); + if ( error ) + { + FT_FREE( sfnt_data ); + goto Exit; + } + + is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); + error = open_face_from_buffer( library, + sfnt_data, + rlen, + face_index_in_resource, + is_cff ? "cff" : "truetype", + aface ); + + Exit: + return error; + } + + + /* Check for a valid resource fork header, or a valid dfont */ + /* header. In a resource fork the first 16 bytes are repeated */ + /* at the location specified by bytes 4-7. In a dfont bytes */ + /* 4-7 point to 16 bytes of zeroes instead. */ + /* */ + static FT_Error + IsMacResource( FT_Library library, + FT_Stream stream, + FT_Long resource_offset, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Long map_offset, rdata_pos; + FT_Long *data_offsets; + FT_Long count; + + + error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset, + &map_offset, &rdata_pos ); + if ( error ) + return error; + + /* POST resources must be sorted to concatenate properly */ + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdata_pos, + TTAG_POST, TRUE, + &data_offsets, &count ); + if ( !error ) + { + error = Mac_Read_POST_Resource( library, stream, data_offsets, count, + face_index, aface ); + FT_FREE( data_offsets ); + /* POST exists in an LWFN providing a single face */ + if ( !error ) + (*aface)->num_faces = 1; + return error; + } + + /* sfnt resources should not be sorted to preserve the face order by + QuickDraw API */ + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdata_pos, + TTAG_sfnt, FALSE, + &data_offsets, &count ); + if ( !error ) + { + FT_Long face_index_internal = face_index % count; + + + error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count, + face_index_internal, aface ); + FT_FREE( data_offsets ); + if ( !error ) + (*aface)->num_faces = count; + } + + return error; + } + + + /* Check for a valid macbinary header, and if we find one */ + /* check that the (flattened) resource fork in it is valid. */ + /* */ + static FT_Error + IsMacBinary( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface ) + { + unsigned char header[128]; + FT_Error error; + FT_Long dlen, offset; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Operation ); + + error = FT_Stream_Seek( stream, 0 ); + if ( error ) + goto Exit; + + error = FT_Stream_Read( stream, (FT_Byte*)header, 128 ); + if ( error ) + goto Exit; + + if ( header[ 0] != 0 || + header[74] != 0 || + header[82] != 0 || + header[ 1] == 0 || + header[ 1] > 33 || + header[63] != 0 || + header[2 + header[1]] != 0 || + header[0x53] > 0x7F ) + return FT_THROW( Unknown_File_Format ); + + dlen = ( header[0x53] << 24 ) | + ( header[0x54] << 16 ) | + ( header[0x55] << 8 ) | + header[0x56]; +#if 0 + rlen = ( header[0x57] << 24 ) | + ( header[0x58] << 16 ) | + ( header[0x59] << 8 ) | + header[0x5A]; +#endif /* 0 */ + offset = 128 + ( ( dlen + 127 ) & ~127 ); + + return IsMacResource( library, stream, offset, face_index, aface ); + + Exit: + return error; + } + + + static FT_Error + load_face_in_embedded_rfork( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { + +#undef FT_COMPONENT +#define FT_COMPONENT raccess + + FT_Memory memory = library->memory; + FT_Error error = FT_ERR( Unknown_File_Format ); + FT_UInt i; + + char* file_names[FT_RACCESS_N_RULES]; + FT_Long offsets[FT_RACCESS_N_RULES]; + FT_Error errors[FT_RACCESS_N_RULES]; + FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */ + + FT_Open_Args args2; + FT_Stream stream2 = NULL; + + + FT_Raccess_Guess( library, stream, + args->pathname, file_names, offsets, errors ); + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i ); + if ( is_darwin_vfs && vfs_rfork_has_no_font ) + { + FT_TRACE3(( "Skip rule %d: darwin vfs resource fork" + " is already checked and" + " no font is found\n", + i )); + continue; + } + + if ( errors[i] ) + { + FT_TRACE3(( "Error 0x%x has occurred in rule %d\n", + errors[i], i )); + continue; + } + + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_names[i] ? file_names[i] : args->pathname; + + FT_TRACE3(( "Try rule %d: %s (offset=%ld) ...", + i, args2.pathname, offsets[i] )); + + error = FT_Stream_New( library, &args2, &stream2 ); + if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) ) + vfs_rfork_has_no_font = TRUE; + + if ( error ) + { + FT_TRACE3(( "failed\n" )); + continue; + } + + error = IsMacResource( library, stream2, offsets[i], + face_index, aface ); + FT_Stream_Free( stream2, 0 ); + + FT_TRACE3(( "%s\n", error ? "failed": "successful" )); + + if ( !error ) + break; + else if ( is_darwin_vfs ) + vfs_rfork_has_no_font = TRUE; + } + + for (i = 0; i < FT_RACCESS_N_RULES; i++) + { + if ( file_names[i] ) + FT_FREE( file_names[i] ); + } + + /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */ + if ( error ) + error = FT_ERR( Unknown_File_Format ); + + return error; + +#undef FT_COMPONENT +#define FT_COMPONENT objs + + } + + + /* Check for some macintosh formats without Carbon framework. */ + /* Is this a macbinary file? If so look at the resource fork. */ + /* Is this a mac dfont file? */ + /* Is this an old style resource fork? (in data) */ + /* Else call load_face_in_embedded_rfork to try extra rules */ + /* (defined in `ftrfork.c'). */ + /* */ + static FT_Error + load_mac_face( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { + FT_Error error; + FT_UNUSED( args ); + + + error = IsMacBinary( library, stream, face_index, aface ); + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + +#undef FT_COMPONENT +#define FT_COMPONENT raccess + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE3(( "Try as dfont: " )); + if ( !( args->flags & FT_OPEN_MEMORY ) ) + FT_TRACE3(( "%s ...", args->pathname )); +#endif + + error = IsMacResource( library, stream, 0, face_index, aface ); + + FT_TRACE3(( "%s\n", error ? "failed" : "successful" )); + +#undef FT_COMPONENT +#define FT_COMPONENT objs + + } + + if ( ( FT_ERR_EQ( error, Unknown_File_Format ) || + FT_ERR_EQ( error, Invalid_Stream_Operation ) ) && + ( args->flags & FT_OPEN_PATHNAME ) ) + error = load_face_in_embedded_rfork( library, stream, + face_index, aface, args ); + return error; + } +#endif + +#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ) + { + return ft_open_face_internal( library, args, face_index, aface, 1 ); + } + + + static FT_Error + ft_open_face_internal( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface, + FT_Bool test_mac_fonts ) + { + FT_Error error; + FT_Driver driver = NULL; + FT_Memory memory = NULL; + FT_Stream stream = NULL; + FT_Face face = NULL; + FT_ListNode node = NULL; + FT_Bool external_stream; + FT_Module* cur; + FT_Module* limit; + +#ifndef FT_CONFIG_OPTION_MAC_FONTS + FT_UNUSED( test_mac_fonts ); +#endif + + + /* only use lower 31 bits together with sign bit */ + if ( face_index > 0 ) + face_index &= 0x7FFFFFFFL; + else + { + face_index = -face_index; + face_index &= 0x7FFFFFFFL; + face_index = -face_index; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE3(( "FT_Open_Face: " )); + if ( face_index < 0 ) + FT_TRACE3(( "Requesting number of faces and named instances\n")); + else + { + FT_TRACE3(( "Requesting face %ld", face_index & 0xFFFFL )); + if ( face_index & 0x7FFF0000L ) + FT_TRACE3(( ", named instance %ld", face_index >> 16 )); + FT_TRACE3(( "\n" )); + } +#endif + + /* test for valid `library' delayed to `FT_Stream_New' */ + + if ( !args ) + return FT_THROW( Invalid_Argument ); + + external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && + args->stream ); + + /* create input stream */ + error = FT_Stream_New( library, args, &stream ); + if ( error ) + goto Fail3; + + /* Do this error check after `FT_Stream_New` to ensure that the */ + /* 'close' callback is called. */ + if ( !aface && face_index >= 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail3; + } + + memory = library->memory; + + /* If the font driver is specified in the `args' structure, use */ + /* it. Otherwise, we scan the list of registered drivers. */ + if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver ) + { + driver = FT_DRIVER( args->driver ); + + /* not all modules are drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( driver ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = NULL; + + + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, &stream, &external_stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + } + else + error = FT_THROW( Invalid_Handle ); + + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + else + { + error = FT_ERR( Missing_Module ); + + /* check each font driver for an appropriate format */ + cur = library->modules; + limit = cur + library->num_modules; + + for ( ; cur < limit; cur++ ) + { + /* not all modules are font drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( cur[0] ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = NULL; + + + driver = FT_DRIVER( cur[0] ); + + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, &stream, &external_stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + +#ifdef FT_CONFIG_OPTION_MAC_FONTS + if ( test_mac_fonts && + ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 && + FT_ERR_EQ( error, Table_Missing ) ) + { + /* TrueType but essential tables are missing */ + error = FT_Stream_Seek( stream, 0 ); + if ( error ) + break; + + error = open_face_PS_from_sfnt_stream( library, + stream, + face_index, + num_params, + params, + aface ); + if ( !error ) + { + FT_Stream_Free( stream, external_stream ); + return error; + } + } +#endif + + if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) + goto Fail3; + } + } + + Fail3: + /* If we are on the mac, and we get an */ + /* FT_Err_Invalid_Stream_Operation it may be because we have an */ + /* empty data fork, so we need to check the resource fork. */ + if ( FT_ERR_NEQ( error, Cannot_Open_Stream ) && + FT_ERR_NEQ( error, Unknown_File_Format ) && + FT_ERR_NEQ( error, Invalid_Stream_Operation ) ) + goto Fail2; + +#if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) + if ( test_mac_fonts ) + { + error = load_mac_face( library, stream, face_index, aface, args ); + if ( !error ) + { + /* We don't want to go to Success here. We've already done */ + /* that. On the other hand, if we succeeded we still need to */ + /* close this stream (we opened a different stream which */ + /* extracted the interesting information out of this stream */ + /* here. That stream will still be open and the face will */ + /* point to it). */ + FT_Stream_Free( stream, external_stream ); + return error; + } + } + + if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) + goto Fail2; +#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ + + /* no driver is able to handle this format */ + error = FT_THROW( Unknown_File_Format ); + + Fail2: + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + + Success: + FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); + + /* add the face object to its driver's list */ + if ( FT_QNEW( node ) ) + goto Fail; + + node->data = face; + /* don't assume driver is the same as face->driver, so use */ + /* face->driver instead. */ + FT_List_Add( &face->driver->faces_list, node ); + + /* now allocate a glyph slot object for the face */ + FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); + + if ( face_index >= 0 ) + { + error = FT_New_GlyphSlot( face, NULL ); + if ( error ) + goto Fail; + + /* finally, allocate a size object for the face */ + { + FT_Size size; + + + FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); + + error = FT_New_Size( face, &size ); + if ( error ) + goto Fail; + + face->size = size; + } + } + + /* some checks */ + + if ( FT_IS_SCALABLE( face ) ) + { + if ( face->height < 0 ) + face->height = (FT_Short)-face->height; + + if ( !FT_HAS_VERTICAL( face ) ) + face->max_advance_height = (FT_Short)face->height; + } + + if ( FT_HAS_FIXED_SIZES( face ) ) + { + FT_Int i; + + + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + + + if ( bsize->height < 0 ) + bsize->height = -bsize->height; + if ( bsize->x_ppem < 0 ) + bsize->x_ppem = -bsize->x_ppem; + if ( bsize->y_ppem < 0 ) + bsize->y_ppem = -bsize->y_ppem; + + /* check whether negation actually has worked */ + if ( bsize->height < 0 || bsize->x_ppem < 0 || bsize->y_ppem < 0 ) + { + FT_TRACE0(( "FT_Open_Face:" + " Invalid bitmap dimensions for strike %d," + " now disabled\n", i )); + bsize->width = 0; + bsize->height = 0; + bsize->size = 0; + bsize->x_ppem = 0; + bsize->y_ppem = 0; + } + } + } + + /* initialize internal face data */ + { + FT_Face_Internal internal = face->internal; + + + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + + internal->refcount = 1; + + internal->no_stem_darkening = -1; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + /* Per-face filtering can only be set up by FT_Face_Properties */ + internal->lcd_filter_func = NULL; +#endif + } + + if ( aface ) + *aface = face; + else + FT_Done_Face( face ); + + goto Exit; + + Fail: + if ( node ) + FT_Done_Face( face ); /* face must be in the driver's list */ + else if ( face ) + destroy_face( memory, face, driver ); + + Exit: +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !error && face_index < 0 ) + { + FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n", + face->num_faces, + face->num_faces == 1 ? "" : "s" )); + FT_TRACE3(( " and %ld named instance%s for face %ld\n", + face->style_flags >> 16, + ( face->style_flags >> 16 ) == 1 ? "" : "s", + -face_index - 1 )); + } +#endif + + FT_TRACE4(( "FT_Open_Face: Return 0x%x\n", error )); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ) + { + FT_Open_Args open; + + + /* test for valid `face' delayed to `FT_Attach_Stream' */ + + if ( !filepathname ) + return FT_THROW( Invalid_Argument ); + + open.stream = NULL; + open.flags = FT_OPEN_PATHNAME; + open.pathname = (char*)filepathname; + + return FT_Attach_Stream( face, &open ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Attach_Stream( FT_Face face, + const FT_Open_Args* parameters ) + { + FT_Stream stream; + FT_Error error; + FT_Driver driver; + + FT_Driver_Class clazz; + + + /* test for valid `parameters' delayed to `FT_Stream_New' */ + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + driver = face->driver; + if ( !driver ) + return FT_THROW( Invalid_Driver_Handle ); + + error = FT_Stream_New( driver->root.library, parameters, &stream ); + if ( error ) + goto Exit; + + /* we implement FT_Attach_Stream in each driver through the */ + /* `attach_file' interface */ + + error = FT_ERR( Unimplemented_Feature ); + clazz = driver->clazz; + if ( clazz->attach_file ) + error = clazz->attach_file( face, stream ); + + /* close the attached stream */ + FT_Stream_Free( stream, + FT_BOOL( parameters->stream && + ( parameters->flags & FT_OPEN_STREAM ) ) ); + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Reference_Face( FT_Face face ) + { + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + face->internal->refcount++; + + return FT_Err_Ok; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Face( FT_Face face ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_ListNode node; + + + error = FT_ERR( Invalid_Face_Handle ); + if ( face && face->driver ) + { + face->internal->refcount--; + if ( face->internal->refcount > 0 ) + error = FT_Err_Ok; + else + { + driver = face->driver; + memory = driver->root.memory; + + /* find face in driver's list */ + node = FT_List_Find( &driver->faces_list, face ); + if ( node ) + { + /* remove face object from the driver's list */ + FT_List_Remove( &driver->faces_list, node ); + FT_FREE( node ); + + /* now destroy the object proper */ + destroy_face( memory, face, driver ); + error = FT_Err_Ok; + } + } + } + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size *asize ) + { + FT_Error error; + FT_Memory memory; + FT_Driver driver; + FT_Driver_Class clazz; + + FT_Size size = NULL; + FT_ListNode node = NULL; + + FT_Size_Internal internal = NULL; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !asize ) + return FT_THROW( Invalid_Argument ); + + if ( !face->driver ) + return FT_THROW( Invalid_Driver_Handle ); + + *asize = NULL; + + driver = face->driver; + clazz = driver->clazz; + memory = face->memory; + + /* Allocate new size object and perform basic initialisation */ + if ( FT_ALLOC( size, clazz->size_object_size ) || FT_QNEW( node ) ) + goto Exit; + + size->face = face; + + if ( FT_NEW( internal ) ) + goto Exit; + + size->internal = internal; + + if ( clazz->init_size ) + error = clazz->init_size( size ); + + /* in case of success, add to the face's list */ + if ( !error ) + { + *asize = size; + node->data = size; + FT_List_Add( &face->sizes_list, node ); + } + + Exit: + if ( error ) + { + FT_FREE( node ); + if ( size ) + FT_FREE( size->internal ); + FT_FREE( size ); + } + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Size( FT_Size size ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Face face; + FT_ListNode node; + + + if ( !size ) + return FT_THROW( Invalid_Size_Handle ); + + face = size->face; + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + driver = face->driver; + if ( !driver ) + return FT_THROW( Invalid_Driver_Handle ); + + memory = driver->root.memory; + + error = FT_Err_Ok; + node = FT_List_Find( &face->sizes_list, size ); + if ( node ) + { + FT_List_Remove( &face->sizes_list, node ); + FT_FREE( node ); + + if ( face->size == size ) + { + face->size = NULL; + if ( face->sizes_list.head ) + face->size = (FT_Size)(face->sizes_list.head->data); + } + + destroy_size( memory, size, driver ); + } + else + error = FT_THROW( Invalid_Size_Handle ); + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ) + { + FT_Int i; + FT_Long w, h; + + + if ( !FT_HAS_FIXED_SIZES( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + /* FT_Bitmap_Size doesn't provide enough info... */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + return FT_THROW( Unimplemented_Feature ); + + w = FT_REQUEST_WIDTH ( req ); + h = FT_REQUEST_HEIGHT( req ); + + if ( req->width && !req->height ) + h = w; + else if ( !req->width && req->height ) + w = h; + + w = FT_PIX_ROUND( w ); + h = FT_PIX_ROUND( h ); + + if ( !w || !h ) + return FT_THROW( Invalid_Pixel_Size ); + + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + + + if ( h != FT_PIX_ROUND( bsize->y_ppem ) ) + continue; + + if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width ) + { + FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i )); + + if ( size_index ) + *size_index = (FT_ULong)i; + + return FT_Err_Ok; + } + } + + FT_TRACE3(( "FT_Match_Size: no matching bitmap strike\n" )); + + return FT_THROW( Invalid_Pixel_Size ); + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ) + { + FT_Pos height = metrics->height; + + + /* compensate for glyph with bbox above/below the baseline */ + if ( metrics->horiBearingY < 0 ) + { + if ( height < metrics->horiBearingY ) + height = metrics->horiBearingY; + } + else if ( metrics->horiBearingY > 0 ) + height -= metrics->horiBearingY; + + /* the factor 1.2 is a heuristical value */ + if ( !advance ) + advance = height * 12 / 10; + + metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2; + metrics->vertBearingY = ( advance - height ) / 2; + metrics->vertAdvance = advance; + } + + + static void + ft_recompute_scaled_metrics( FT_Face face, + FT_Size_Metrics* metrics ) + { + /* Compute root ascender, descender, test height, and max_advance */ + +#ifdef GRID_FIT_METRICS + metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender, + metrics->y_scale ) ); + + metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender, + metrics->y_scale ) ); + + metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, + metrics->y_scale ) ); + + metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, + metrics->x_scale ) ); +#else /* !GRID_FIT_METRICS */ + metrics->ascender = FT_MulFix( face->ascender, + metrics->y_scale ); + + metrics->descender = FT_MulFix( face->descender, + metrics->y_scale ); + + metrics->height = FT_MulFix( face->height, + metrics->y_scale ); + + metrics->max_advance = FT_MulFix( face->max_advance_width, + metrics->x_scale ); +#endif /* !GRID_FIT_METRICS */ + } + + + FT_BASE_DEF( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ) + { + FT_Size_Metrics* metrics; + FT_Bitmap_Size* bsize; + + + metrics = &face->size->metrics; + bsize = face->available_sizes + strike_index; + + metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 ); + metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 ); + + if ( FT_IS_SCALABLE( face ) ) + { + metrics->x_scale = FT_DivFix( bsize->x_ppem, + face->units_per_EM ); + metrics->y_scale = FT_DivFix( bsize->y_ppem, + face->units_per_EM ); + + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + metrics->x_scale = 1L << 16; + metrics->y_scale = 1L << 16; + metrics->ascender = bsize->y_ppem; + metrics->descender = 0; + metrics->height = bsize->height << 6; + metrics->max_advance = bsize->x_ppem; + } + } + + + FT_BASE_DEF( FT_Error ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ) + { + FT_Error error = FT_Err_Ok; + + FT_Size_Metrics* metrics; + + + metrics = &face->size->metrics; + + if ( FT_IS_SCALABLE( face ) ) + { + FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0; + + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + w = h = face->units_per_EM; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + w = h = face->ascender - face->descender; + break; + + case FT_SIZE_REQUEST_TYPE_BBOX: + w = face->bbox.xMax - face->bbox.xMin; + h = face->bbox.yMax - face->bbox.yMin; + break; + + case FT_SIZE_REQUEST_TYPE_CELL: + w = face->max_advance_width; + h = face->ascender - face->descender; + break; + + case FT_SIZE_REQUEST_TYPE_SCALES: + metrics->x_scale = (FT_Fixed)req->width; + metrics->y_scale = (FT_Fixed)req->height; + if ( !metrics->x_scale ) + metrics->x_scale = metrics->y_scale; + else if ( !metrics->y_scale ) + metrics->y_scale = metrics->x_scale; + goto Calculate_Ppem; + + case FT_SIZE_REQUEST_TYPE_MAX: + break; + } + + /* to be on the safe side */ + if ( w < 0 ) + w = -w; + + if ( h < 0 ) + h = -h; + + scaled_w = FT_REQUEST_WIDTH ( req ); + scaled_h = FT_REQUEST_HEIGHT( req ); + + /* determine scales */ + if ( req->height || !req->width ) + { + if ( h == 0 ) + { + FT_ERROR(( "FT_Request_Metrics: Divide by zero\n" )); + error = FT_ERR( Divide_By_Zero ); + goto Exit; + } + + metrics->y_scale = FT_DivFix( scaled_h, h ); + } + + if ( req->width ) + { + if ( w == 0 ) + { + FT_ERROR(( "FT_Request_Metrics: Divide by zero\n" )); + error = FT_ERR( Divide_By_Zero ); + goto Exit; + } + + metrics->x_scale = FT_DivFix( scaled_w, w ); + } + else + { + metrics->x_scale = metrics->y_scale; + scaled_w = FT_MulDiv( scaled_h, w, h ); + } + + if ( !req->height ) + { + metrics->y_scale = metrics->x_scale; + scaled_h = FT_MulDiv( scaled_w, h, w ); + } + + if ( req->type == FT_SIZE_REQUEST_TYPE_CELL ) + { + if ( metrics->y_scale > metrics->x_scale ) + metrics->y_scale = metrics->x_scale; + else + metrics->x_scale = metrics->y_scale; + } + + Calculate_Ppem: + /* calculate the ppems */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + { + scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale ); + scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); + } + + scaled_w = ( scaled_w + 32 ) >> 6; + scaled_h = ( scaled_h + 32 ) >> 6; + if ( scaled_w > (FT_Long)FT_USHORT_MAX || + scaled_h > (FT_Long)FT_USHORT_MAX ) + { + FT_ERROR(( "FT_Request_Metrics: Resulting ppem size too large\n" )); + error = FT_ERR( Invalid_Pixel_Size ); + goto Exit; + } + + metrics->x_ppem = (FT_UShort)scaled_w; + metrics->y_ppem = (FT_UShort)scaled_h; + + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + FT_ZERO( metrics ); + metrics->x_scale = 1L << 16; + metrics->y_scale = 1L << 16; + } + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ) + { + FT_Error error = FT_Err_Ok; + FT_Driver_Class clazz; + + + if ( !face || !FT_HAS_FIXED_SIZES( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + if ( strike_index < 0 || strike_index >= face->num_fixed_sizes ) + return FT_THROW( Invalid_Argument ); + + clazz = face->driver->clazz; + + if ( clazz->select_size ) + { + error = clazz->select_size( face->size, (FT_ULong)strike_index ); + + FT_TRACE5(( "FT_Select_Size (%s driver):\n", + face->driver->root.clazz->module_name )); + } + else + { + FT_Select_Metrics( face, (FT_ULong)strike_index ); + + FT_TRACE5(( "FT_Select_Size:\n" )); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Size_Metrics* metrics = &face->size->metrics; + + + FT_TRACE5(( " x scale: %ld (%f)\n", + metrics->x_scale, (double)metrics->x_scale / 65536 )); + FT_TRACE5(( " y scale: %ld (%f)\n", + metrics->y_scale, (double)metrics->y_scale / 65536 )); + FT_TRACE5(( " ascender: %f\n", + (double)metrics->ascender / 64 )); + FT_TRACE5(( " descender: %f\n", + (double)metrics->descender / 64 )); + FT_TRACE5(( " height: %f\n", + (double)metrics->height / 64 )); + FT_TRACE5(( " max advance: %f\n", + (double)metrics->max_advance / 64 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + } +#endif + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ) + { + FT_Error error; + FT_Driver_Class clazz; + FT_ULong strike_index; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !face->size ) + return FT_THROW( Invalid_Size_Handle ); + + if ( !req || req->width < 0 || req->height < 0 || + req->type >= FT_SIZE_REQUEST_TYPE_MAX ) + return FT_THROW( Invalid_Argument ); + + /* signal the auto-hinter to recompute its size metrics */ + /* (if requested) */ + face->size->internal->autohint_metrics.x_scale = 0; + + clazz = face->driver->clazz; + + if ( clazz->request_size ) + { + error = clazz->request_size( face->size, req ); + + FT_TRACE5(( "FT_Request_Size (%s driver):\n", + face->driver->root.clazz->module_name )); + } + else if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) ) + { + /* + * The reason that a driver doesn't have `request_size' defined is + * either that the scaling here suffices or that the supported formats + * are bitmap-only and size matching is not implemented. + * + * In the latter case, a simple size matching is done. + */ + error = FT_Match_Size( face, req, 0, &strike_index ); + if ( error ) + goto Exit; + + return FT_Select_Size( face, (FT_Int)strike_index ); + } + else + { + error = FT_Request_Metrics( face, req ); + if ( error ) + goto Exit; + + FT_TRACE5(( "FT_Request_Size:\n" )); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Size_Metrics* metrics = &face->size->metrics; + + + FT_TRACE5(( " x scale: %ld (%f)\n", + metrics->x_scale, (double)metrics->x_scale / 65536 )); + FT_TRACE5(( " y scale: %ld (%f)\n", + metrics->y_scale, (double)metrics->y_scale / 65536 )); + FT_TRACE5(( " ascender: %f\n", + (double)metrics->ascender / 64 )); + FT_TRACE5(( " descender: %f\n", + (double)metrics->descender / 64 )); + FT_TRACE5(( " height: %f\n", + (double)metrics->height / 64 )); + FT_TRACE5(( " max advance: %f\n", + (double)metrics->max_advance / 64 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + } +#endif + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Size_RequestRec req; + + + /* check of `face' delayed to `FT_Request_Size' */ + + if ( !char_width ) + char_width = char_height; + else if ( !char_height ) + char_height = char_width; + + if ( !horz_resolution ) + horz_resolution = vert_resolution; + else if ( !vert_resolution ) + vert_resolution = horz_resolution; + + if ( char_width < 1 * 64 ) + char_width = 1 * 64; + if ( char_height < 1 * 64 ) + char_height = 1 * 64; + + if ( !horz_resolution ) + horz_resolution = vert_resolution = 72; + + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = char_width; + req.height = char_height; + req.horiResolution = horz_resolution; + req.vertResolution = vert_resolution; + + return FT_Request_Size( face, &req ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + FT_Size_RequestRec req; + + + /* check of `face' delayed to `FT_Request_Size' */ + + if ( pixel_width == 0 ) + pixel_width = pixel_height; + else if ( pixel_height == 0 ) + pixel_height = pixel_width; + + if ( pixel_width < 1 ) + pixel_width = 1; + if ( pixel_height < 1 ) + pixel_height = 1; + + /* use `>=' to avoid potential compiler warning on 16bit platforms */ + if ( pixel_width >= 0xFFFFU ) + pixel_width = 0xFFFFU; + if ( pixel_height >= 0xFFFFU ) + pixel_height = 0xFFFFU; + + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = (FT_Long)( pixel_width << 6 ); + req.height = (FT_Long)( pixel_height << 6 ); + req.horiResolution = 0; + req.vertResolution = 0; + + return FT_Request_Size( face, &req ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ) + { + FT_Error error = FT_Err_Ok; + FT_Driver driver; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !akerning ) + return FT_THROW( Invalid_Argument ); + + driver = face->driver; + + akerning->x = 0; + akerning->y = 0; + + if ( driver->clazz->get_kerning ) + { + error = driver->clazz->get_kerning( face, + left_glyph, + right_glyph, + akerning ); + if ( !error ) + { + if ( kern_mode != FT_KERNING_UNSCALED ) + { + akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale ); + akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale ); + + if ( kern_mode != FT_KERNING_UNFITTED ) + { + FT_Pos orig_x = akerning->x; + FT_Pos orig_y = akerning->y; + + + /* we scale down kerning values for small ppem values */ + /* to avoid that rounding makes them too big. */ + /* `25' has been determined heuristically. */ + if ( face->size->metrics.x_ppem < 25 ) + akerning->x = FT_MulDiv( orig_x, + face->size->metrics.x_ppem, 25 ); + if ( face->size->metrics.y_ppem < 25 ) + akerning->y = FT_MulDiv( orig_y, + face->size->metrics.y_ppem, 25 ); + + akerning->x = FT_PIX_ROUND( akerning->x ); + akerning->y = FT_PIX_ROUND( akerning->y ); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Pos orig_x_rounded = FT_PIX_ROUND( orig_x ); + FT_Pos orig_y_rounded = FT_PIX_ROUND( orig_y ); + + + if ( akerning->x != orig_x_rounded || + akerning->y != orig_y_rounded ) + FT_TRACE5(( "FT_Get_Kerning: horizontal kerning" + " (%ld, %ld) scaled down to (%ld, %ld) pixels\n", + orig_x_rounded / 64, orig_y_rounded / 64, + akerning->x / 64, akerning->y / 64 )); + } +#endif + } + } + } + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ) + { + FT_Service_Kerning service; + FT_Error error = FT_Err_Ok; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !akerning ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_FIND_SERVICE( face, service, KERNING ); + if ( !service ) + return FT_THROW( Unimplemented_Feature ); + + error = service->get_track( face, + point_size, + degree, + akerning ); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + /* FT_ENCODING_NONE is a valid encoding for BDF, PCF, and Windows FNT */ + if ( encoding == FT_ENCODING_NONE && !face->num_charmaps ) + return FT_THROW( Invalid_Argument ); + + /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */ + /* charmap available, i.e., one with UCS-4 characters, if possible. */ + /* */ + /* This is done by find_unicode_charmap() above, to share code. */ + if ( encoding == FT_ENCODING_UNICODE ) + return find_unicode_charmap( face ); + + cur = face->charmaps; + if ( !cur ) + return FT_THROW( Invalid_CharMap_Handle ); + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0]->encoding == encoding ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + + return FT_THROW( Invalid_Argument ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + cur = face->charmaps; + if ( !cur || !charmap ) + return FT_THROW( Invalid_CharMap_Handle ); + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == charmap && + FT_Get_CMap_Format ( charmap ) != 14 ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + + return FT_THROW( Invalid_Argument ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ) + { + FT_Int i; + + + if ( !charmap || !charmap->face ) + return -1; + + for ( i = 0; i < charmap->face->num_charmaps; i++ ) + if ( charmap->face->charmaps[i] == charmap ) + break; + + FT_ASSERT( i < charmap->face->num_charmaps ); + + return i; + } + + + static void + ft_cmap_done_internal( FT_CMap cmap ) + { + FT_CMap_Class clazz = cmap->clazz; + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + if ( clazz->done ) + clazz->done( cmap ); + + FT_FREE( cmap ); + } + + + FT_BASE_DEF( void ) + FT_CMap_Done( FT_CMap cmap ) + { + if ( cmap ) + { + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error; + FT_Int i, j; + + + for ( i = 0; i < face->num_charmaps; i++ ) + { + if ( (FT_CMap)face->charmaps[i] == cmap ) + { + FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; + + + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps - 1 ) ) + return; + + /* remove it from our list of charmaps */ + for ( j = i + 1; j < face->num_charmaps; j++ ) + { + if ( j == face->num_charmaps - 1 ) + face->charmaps[j - 1] = last_charmap; + else + face->charmaps[j - 1] = face->charmaps[j]; + } + + face->num_charmaps--; + + if ( (FT_CMap)face->charmap == cmap ) + face->charmap = NULL; + + ft_cmap_done_internal( cmap ); + + break; + } + } + } + } + + + FT_BASE_DEF( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ) + { + FT_Error error; + FT_Face face; + FT_Memory memory; + FT_CMap cmap = NULL; + + + if ( !clazz || !charmap || !charmap->face ) + return FT_THROW( Invalid_Argument ); + + face = charmap->face; + memory = FT_FACE_MEMORY( face ); + + if ( !FT_ALLOC( cmap, clazz->size ) ) + { + cmap->charmap = *charmap; + cmap->clazz = clazz; + + if ( clazz->init ) + { + error = clazz->init( cmap, init_data ); + if ( error ) + goto Fail; + } + + /* add it to our list of charmaps */ + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps + 1 ) ) + goto Fail; + + face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; + } + + Exit: + if ( acmap ) + *acmap = cmap; + + return error; + + Fail: + ft_cmap_done_internal( cmap ); + cmap = NULL; + goto Exit; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ) + { + FT_UInt result = 0; + + + if ( face && face->charmap ) + { + FT_CMap cmap = FT_CMAP( face->charmap ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + + result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode ); + if ( result >= (FT_UInt)face->num_glyphs ) + result = 0; + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + + + /* only do something if we have a charmap, and we have glyphs at all */ + if ( face && face->charmap && face->num_glyphs ) + { + gindex = FT_Get_Char_Index( face, 0 ); + if ( gindex == 0 ) + result = FT_Get_Next_Char( face, 0, &gindex ); + } + + if ( agindex ) + *agindex = gindex; + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong charcode, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + + + if ( face && face->charmap && face->num_glyphs ) + { + FT_UInt32 code = (FT_UInt32)charcode; + FT_CMap cmap = FT_CMAP( face->charmap ); + + + do + { + gindex = cmap->clazz->char_next( cmap, &code ); + + } while ( gindex >= (FT_UInt)face->num_glyphs ); + + result = ( gindex == 0 ) ? 0 : code; + } + + if ( agindex ) + *agindex = gindex; + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Face_Properties( FT_Face face, + FT_UInt num_properties, + FT_Parameter* properties ) + { + FT_Error error = FT_Err_Ok; + + + if ( num_properties > 0 && !properties ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + for ( ; num_properties > 0; num_properties-- ) + { + if ( properties->tag == FT_PARAM_TAG_STEM_DARKENING ) + { + if ( properties->data ) + { + if ( *( (FT_Bool*)properties->data ) == TRUE ) + face->internal->no_stem_darkening = FALSE; + else + face->internal->no_stem_darkening = TRUE; + } + else + { + /* use module default */ + face->internal->no_stem_darkening = -1; + } + } + else if ( properties->tag == FT_PARAM_TAG_LCD_FILTER_WEIGHTS ) + { +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + if ( properties->data ) + { + ft_memcpy( face->internal->lcd_weights, + properties->data, + FT_LCD_FILTER_FIVE_TAPS ); + face->internal->lcd_filter_func = ft_lcd_filter_fir; + } +#else + error = FT_THROW( Unimplemented_Feature ); + goto Exit; +#endif + } + else if ( properties->tag == FT_PARAM_TAG_RANDOM_SEED ) + { + if ( properties->data ) + { + face->internal->random_seed = *( (FT_Int32*)properties->data ); + if ( face->internal->random_seed < 0 ) + face->internal->random_seed = 0; + } + else + { + /* use module default */ + face->internal->random_seed = -1; + } + } + else + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( error ) + break; + + properties++; + } + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Face_GetCharVariantIndex( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ) + { + FT_UInt result = 0; + + + if ( face && + face->charmap && + face->charmap->encoding == FT_ENCODING_UNICODE ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + FT_CMap ucmap = FT_CMAP( face->charmap ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIndex:" + " too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIndex:" + " too large variantSelector" )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); + } + + result = vcmap->clazz->char_var_index( vcmap, ucmap, + (FT_UInt32)charcode, + (FT_UInt32)variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Face_GetCharVariantIsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ) + { + FT_Int result = -1; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:" + " too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:" + " too large variantSelector" )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); + } + + result = vcmap->clazz->char_var_default( vcmap, + (FT_UInt32)charcode, + (FT_UInt32)variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetVariantSelectors( FT_Face face ) + { + FT_UInt32 *result = NULL; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + result = vcmap->clazz->variant_list( vcmap, memory ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetVariantsOfChar( FT_Face face, + FT_ULong charcode ) + { + FT_UInt32 *result = NULL; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetVariantsOfChar: too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + + result = vcmap->clazz->charvariant_list( vcmap, memory, + (FT_UInt32)charcode ); + } + } + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetCharsOfVariant( FT_Face face, + FT_ULong variantSelector ) + { + FT_UInt32 *result = NULL; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); + } + + result = vcmap->clazz->variantchar_list( vcmap, memory, + (FT_UInt32)variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + const FT_String* glyph_name ) + { + FT_UInt result = 0; + + + if ( face && + FT_HAS_GLYPH_NAMES( face ) && + glyph_name ) + { + FT_Service_GlyphDict service; + + + FT_FACE_LOOKUP_SERVICE( face, + service, + GLYPH_DICT ); + + if ( service && service->name_index ) + result = service->name_index( face, glyph_name ); + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_Error error; + FT_Service_GlyphDict service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !buffer || buffer_max == 0 ) + return FT_THROW( Invalid_Argument ); + + /* clean up buffer */ + ((FT_Byte*)buffer)[0] = '\0'; + + if ( (FT_Long)glyph_index >= face->num_glyphs ) + return FT_THROW( Invalid_Glyph_Index ); + + if ( !FT_HAS_GLYPH_NAMES( face ) ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_LOOKUP_SERVICE( face, service, GLYPH_DICT ); + if ( service && service->get_name ) + error = service->get_name( face, glyph_index, buffer, buffer_max ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( const char* ) + FT_Get_Postscript_Name( FT_Face face ) + { + const char* result = NULL; + + + if ( !face ) + goto Exit; + + if ( !result ) + { + FT_Service_PsFontName service; + + + FT_FACE_LOOKUP_SERVICE( face, + service, + POSTSCRIPT_FONT_NAME ); + + if ( service && service->get_ps_font_name ) + result = service->get_ps_font_name( face ); + } + + Exit: + return result; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ) + { + void* table = NULL; + FT_Service_SFNT_Table service; + + + if ( face && FT_IS_SFNT( face ) ) + { + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service ) + table = service->get_table( face, tag ); + } + + return table; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Service_SFNT_Table service; + + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( !service ) + return FT_THROW( Unimplemented_Feature ); + + return service->load_table( face, tag, offset, buffer, length ); + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ) + { + FT_Service_SFNT_Table service; + FT_ULong offset; + + + /* test for valid `length' delayed to `service->table_info' */ + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( !service ) + return FT_THROW( Unimplemented_Feature ); + + return service->table_info( face, table_index, tag, &offset, length ); + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + + + if ( !charmap || !charmap->face ) + return 0; + + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( !service ) + return 0; + if ( service->get_cmap_info( charmap, &cmap_info )) + return 0; + + return cmap_info.language; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + + + if ( !charmap || !charmap->face ) + return -1; + + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( !service ) + return -1; + if ( service->get_cmap_info( charmap, &cmap_info )) + return -1; + + return cmap_info.format; + } + + + /* documentation is in ftsizes.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Activate_Size( FT_Size size ) + { + FT_Face face; + + + if ( !size ) + return FT_THROW( Invalid_Size_Handle ); + + face = size->face; + if ( !face || !face->driver ) + return FT_THROW( Invalid_Face_Handle ); + + /* we don't need anything more complex than that; all size objects */ + /* are already listed by the face */ + face->size = size; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* lookup a renderer by glyph format in the library's list */ + FT_BASE_DEF( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ) + { + FT_ListNode cur; + FT_Renderer result = NULL; + + + if ( !library ) + goto Exit; + + cur = library->renderers.head; + + if ( node ) + { + if ( *node ) + cur = (*node)->next; + *node = NULL; + } + + while ( cur ) + { + FT_Renderer renderer = FT_RENDERER( cur->data ); + + + if ( renderer->glyph_format == format ) + { + if ( node ) + *node = cur; + + result = renderer; + break; + } + cur = cur->next; + } + + Exit: + return result; + } + + + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ) + { + FT_Face face = slot->face; + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Renderer result = library->cur_renderer; + + + if ( !result || result->glyph_format != slot->format ) + result = FT_Lookup_Renderer( library, slot->format, 0 ); + + return result; + } + + + static void + ft_set_current_renderer( FT_Library library ) + { + FT_Renderer renderer; + + + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 ); + library->cur_renderer = renderer; + } + + + static FT_Error + ft_add_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_Error error; + FT_ListNode node = NULL; + + + if ( FT_QNEW( node ) ) + goto Exit; + + { + FT_Renderer render = FT_RENDERER( module ); + FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; + + + render->clazz = clazz; + render->glyph_format = clazz->glyph_format; + + /* allocate raster object if needed */ + if ( clazz->raster_class && clazz->raster_class->raster_new ) + { + error = clazz->raster_class->raster_new( memory, &render->raster ); + if ( error ) + goto Fail; + + render->raster_render = clazz->raster_class->raster_render; + render->render = clazz->render_glyph; + } + +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz->glyph_format == FT_GLYPH_FORMAT_SVG ) + render->render = clazz->render_glyph; +#endif + + /* add to list */ + node->data = module; + FT_List_Add( &library->renderers, node ); + + ft_set_current_renderer( library ); + } + + Fail: + if ( error ) + FT_FREE( node ); + + Exit: + return error; + } + + + static void + ft_remove_renderer( FT_Module module ) + { + FT_Library library; + FT_Memory memory; + FT_ListNode node; + + + library = module->library; + if ( !library ) + return; + + memory = library->memory; + + node = FT_List_Find( &library->renderers, module ); + if ( node ) + { + FT_Renderer render = FT_RENDERER( module ); + + + /* release raster object, if any */ + if ( render->raster ) + render->clazz->raster_class->raster_done( render->raster ); + + /* remove from list */ + FT_List_Remove( &library->renderers, node ); + FT_FREE( node ); + + ft_set_current_renderer( library ); + } + } + + + /* documentation is in ftrender.h */ + + FT_EXPORT_DEF( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ) + { + /* test for valid `library' delayed to `FT_Lookup_Renderer' */ + + return FT_Lookup_Renderer( library, format, 0 ); + } + + + /* documentation is in ftrender.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ) + { + FT_ListNode node; + FT_Error error = FT_Err_Ok; + + FT_Renderer_SetModeFunc set_mode; + + + if ( !library ) + { + error = FT_THROW( Invalid_Library_Handle ); + goto Exit; + } + + if ( !renderer ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( num_params > 0 && !parameters ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + node = FT_List_Find( &library->renderers, renderer ); + if ( !node ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_List_Up( &library->renderers, node ); + + if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE ) + library->cur_renderer = renderer; + + set_mode = renderer->clazz->set_mode; + + for ( ; num_params > 0; num_params-- ) + { + error = set_mode( renderer, parameters->tag, parameters->data ); + if ( error ) + break; + parameters++; + } + + Exit: + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Error error = FT_Err_Ok; + FT_Face face = slot->face; + FT_Renderer renderer; + + + switch ( slot->format ) + { + default: + if ( slot->internal->load_flags & FT_LOAD_COLOR ) + { + FT_LayerIterator iterator; + + FT_UInt base_glyph = slot->glyph_index; + + FT_Bool have_layers; + FT_UInt glyph_index; + FT_UInt color_index; + + + /* check whether we have colored glyph layers */ + iterator.p = NULL; + have_layers = FT_Get_Color_Glyph_Layer( face, + base_glyph, + &glyph_index, + &color_index, + &iterator ); + if ( have_layers ) + { + error = FT_New_GlyphSlot( face, NULL ); + if ( !error ) + { + TT_Face ttface = (TT_Face)face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + + do + { + FT_Int32 load_flags = slot->internal->load_flags; + + + /* disable the `FT_LOAD_COLOR' flag to avoid recursion */ + /* right here in this function */ + load_flags &= ~FT_LOAD_COLOR; + + /* render into the new `face->glyph' glyph slot */ + load_flags |= FT_LOAD_RENDER; + + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + break; + + /* blend new `face->glyph' into old `slot'; */ + /* at the first call, `slot' is still empty */ + error = sfnt->colr_blend( ttface, + color_index, + slot, + face->glyph ); + if ( error ) + break; + + } while ( FT_Get_Color_Glyph_Layer( face, + base_glyph, + &glyph_index, + &color_index, + &iterator ) ); + + if ( !error ) + slot->format = FT_GLYPH_FORMAT_BITMAP; + + /* this call also restores `slot' as the glyph slot */ + FT_Done_GlyphSlot( face->glyph ); + } + + if ( !error ) + return error; + + /* Failed to do the colored layer. Draw outline instead. */ + slot->format = FT_GLYPH_FORMAT_OUTLINE; + } + } + + { + FT_ListNode node = NULL; + + + /* small shortcut for the very common case */ + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + renderer = library->cur_renderer; + node = library->renderers.head; + } + else + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + + error = FT_ERR( Cannot_Render_Glyph ); + while ( renderer ) + { + error = renderer->render( renderer, slot, render_mode, NULL ); + if ( !error || + FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format. */ + + /* now, look for another renderer that supports the same */ + /* format. */ + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + } + + /* it is not an error if we cannot render a bitmap glyph */ + if ( FT_ERR_EQ( error, Cannot_Render_Glyph ) && + slot->format == FT_GLYPH_FORMAT_BITMAP ) + error = FT_Err_Ok; + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + +#undef FT_COMPONENT +#define FT_COMPONENT checksum + + /* + * Computing the MD5 checksum is expensive, unnecessarily distorting a + * possible profiling of FreeType if compiled with tracing support. For + * this reason, we execute the following code only if explicitly + * requested. + */ + + /* we use FT_TRACE3 in this block */ + if ( !error && + ft_trace_levels[trace_checksum] >= 3 && + slot->bitmap.buffer ) + { + FT_Bitmap bitmap; + FT_Error err; + + + FT_Bitmap_Init( &bitmap ); + + /* we convert to a single bitmap format for computing the checksum */ + /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */ + err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 ); + if ( !err ) + { + MD5_CTX ctx; + unsigned char md5[16]; + unsigned long coverage = 0; + int i, j; + int rows = (int)bitmap.rows; + int pitch = bitmap.pitch; + + + FT_TRACE3(( "FT_Render_Glyph: bitmap %dx%d, %s (mode %d)\n", + pitch, + rows, + pixel_modes[slot->bitmap.pixel_mode], + slot->bitmap.pixel_mode )); + + for ( i = 0; i < rows; i++ ) + for ( j = 0; j < pitch; j++ ) + coverage += bitmap.buffer[i * pitch + j]; + + FT_TRACE3(( " Total coverage: %lu\n", coverage )); + + MD5_Init( &ctx ); + if ( bitmap.buffer ) + MD5_Update( &ctx, bitmap.buffer, + (unsigned long)rows * (unsigned long)pitch ); + MD5_Final( md5, &ctx ); + + FT_TRACE3(( " MD5 checksum: " )); + for ( i = 0; i < 16; i++ ) + FT_TRACE3(( "%02X", md5[i] )); + FT_TRACE3(( "\n" )); + } + + FT_Bitmap_Done( library, &bitmap ); + } + + /* + * Dump bitmap in Netpbm format (PBM or PGM). + */ + + /* we use FT_TRACE7 in this block */ + if ( !error && + ft_trace_levels[trace_checksum] >= 7 && + slot->bitmap.buffer ) + { + if ( slot->bitmap.rows < 128U && + slot->bitmap.width < 128U ) + { + int rows = (int)slot->bitmap.rows; + int width = (int)slot->bitmap.width; + int pitch = slot->bitmap.pitch; + int i, j, m; + + unsigned char* topleft = slot->bitmap.buffer; + + + if ( pitch < 0 ) + topleft -= pitch * ( rows - 1 ); + + FT_TRACE7(( "Netpbm image: start\n" )); + switch ( slot->bitmap.pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + FT_TRACE7(( "P1 %d %d\n", width, rows )); + for ( i = 0; i < rows; i++ ) + { + for ( j = 0; j < width; ) + for ( m = 128; m > 0 && j < width; m >>= 1, j++ ) + FT_TRACE7(( " %d", + ( topleft[i * pitch + j / 8] & m ) != 0 )); + FT_TRACE7(( "\n" )); + } + break; + + default: + FT_TRACE7(( "P2 %d %d 255\n", width, rows )); + for ( i = 0; i < rows; i++ ) + { + for ( j = 0; j < width; j += 1 ) + FT_TRACE7(( " %3u", topleft[i * pitch + j] )); + FT_TRACE7(( "\n" )); + } + } + FT_TRACE7(( "Netpbm image: end\n" )); + } + else + FT_TRACE7(( "Netpbm image: too large, omitted\n" )); + } + +#undef FT_COMPONENT +#define FT_COMPONENT objs + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Library library; + + + if ( !slot || !slot->face ) + return FT_THROW( Invalid_Argument ); + + library = FT_FACE_LIBRARY( slot->face ); + + return FT_Render_Glyph_Internal( library, slot, render_mode ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * Destroy_Module + * + * @Description: + * Destroys a given module object. For drivers, this also destroys + * all child faces. + * + * @InOut: + * module :: + * A handle to the target driver object. + * + * @Note: + * The driver _must_ be LOCKED! + */ + static void + Destroy_Module( FT_Module module ) + { + FT_Memory memory = module->memory; + FT_Module_Class* clazz = module->clazz; + FT_Library library = module->library; + + + if ( library && library->auto_hinter == module ) + library->auto_hinter = NULL; + + /* if the module is a renderer */ + if ( FT_MODULE_IS_RENDERER( module ) ) + ft_remove_renderer( module ); + + /* if the module is a font driver, add some steps */ + if ( FT_MODULE_IS_DRIVER( module ) ) + Destroy_Driver( FT_DRIVER( module ) ); + + /* finalize the module object */ + if ( clazz->module_done ) + clazz->module_done( module ); + + /* discard it */ + FT_FREE( module ); + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ) + { + FT_Error error; + FT_Memory memory; + FT_Module module = NULL; + FT_UInt nn; + + +#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ + FREETYPE_MINOR ) + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !clazz ) + return FT_THROW( Invalid_Argument ); + + /* check FreeType version */ + if ( clazz->module_requires > FREETYPE_VER_FIXED ) + return FT_THROW( Invalid_Version ); + + /* look for a module with the same name in the library's table */ + for ( nn = 0; nn < library->num_modules; nn++ ) + { + module = library->modules[nn]; + if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) + { + /* this installed module has the same name, compare their versions */ + if ( clazz->module_version <= module->clazz->module_version ) + return FT_THROW( Lower_Module_Version ); + + /* remove the module from our list, then exit the loop to replace */ + /* it by our new version.. */ + FT_Remove_Module( library, module ); + break; + } + } + + memory = library->memory; + error = FT_Err_Ok; + + if ( library->num_modules >= FT_MAX_MODULES ) + { + error = FT_THROW( Too_Many_Drivers ); + goto Exit; + } + + /* allocate module object */ + if ( FT_ALLOC( module, clazz->module_size ) ) + goto Exit; + + /* base initialization */ + module->library = library; + module->memory = memory; + module->clazz = (FT_Module_Class*)clazz; + + /* check whether the module is a renderer - this must be performed */ + /* before the normal module initialization */ + if ( FT_MODULE_IS_RENDERER( module ) ) + { + /* add to the renderers list */ + error = ft_add_renderer( module ); + if ( error ) + goto Fail; + } + + /* is the module a auto-hinter? */ + if ( FT_MODULE_IS_HINTER( module ) ) + library->auto_hinter = module; + + /* if the module is a font driver */ + if ( FT_MODULE_IS_DRIVER( module ) ) + { + FT_Driver driver = FT_DRIVER( module ); + + + driver->clazz = (FT_Driver_Class)module->clazz; + } + + if ( clazz->module_init ) + { + error = clazz->module_init( module ); + if ( error ) + goto Fail; + } + + /* add module to the library's table */ + library->modules[library->num_modules++] = module; + + Exit: + return error; + + Fail: + if ( FT_MODULE_IS_RENDERER( module ) ) + { + FT_Renderer renderer = FT_RENDERER( module ); + + + if ( renderer->clazz && + renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && + renderer->raster ) + renderer->clazz->raster_class->raster_done( renderer->raster ); + } + + FT_FREE( module ); + goto Exit; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ) + { + FT_Module result = NULL; + FT_Module* cur; + FT_Module* limit; + + + if ( !library || !module_name ) + return result; + + cur = library->modules; + limit = cur + library->num_modules; + + for ( ; cur < limit; cur++ ) + if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) + { + result = cur[0]; + break; + } + + return result; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ) + { + FT_Module module; + + + /* test for valid `library' delayed to FT_Get_Module() */ + + module = FT_Get_Module( library, mod_name ); + + return module ? module->clazz->module_interface : 0; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id, + FT_Bool global ) + { + FT_Pointer result = NULL; + + + if ( module ) + { + FT_ASSERT( module->clazz && module->clazz->get_interface ); + + /* first, look for the service in the module */ + if ( module->clazz->get_interface ) + result = module->clazz->get_interface( module, service_id ); + + if ( global && !result ) + { + /* we didn't find it, look in all other modules then */ + FT_Library library = module->library; + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] != module ) + { + FT_ASSERT( cur[0]->clazz ); + + if ( cur[0]->clazz->get_interface ) + { + result = cur[0]->clazz->get_interface( cur[0], service_id ); + if ( result ) + break; + } + } + } + } + } + + return result; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ) + { + /* try to find the module from the table, then remove it from there */ + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( module ) + { + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == module ) + { + /* remove it from the table */ + library->num_modules--; + limit--; + while ( cur < limit ) + { + cur[0] = cur[1]; + cur++; + } + limit[0] = NULL; + + /* destroy the module */ + Destroy_Module( module ); + + return FT_Err_Ok; + } + } + } + return FT_THROW( Invalid_Driver_Handle ); + } + + + static FT_Error + ft_property_do( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value, + FT_Bool set, + FT_Bool value_is_string ) + { + FT_Module* cur; + FT_Module* limit; + FT_Module_Interface interface; + + FT_Service_Properties service; + +#ifdef FT_DEBUG_LEVEL_ERROR + const FT_String* set_name = "FT_Property_Set"; + const FT_String* get_name = "FT_Property_Get"; + const FT_String* func_name = set ? set_name : get_name; +#endif + + FT_Bool missing_func; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !module_name || !property_name || !value ) + return FT_THROW( Invalid_Argument ); + + cur = library->modules; + limit = cur + library->num_modules; + + /* search module */ + for ( ; cur < limit; cur++ ) + if ( !ft_strcmp( cur[0]->clazz->module_name, module_name ) ) + break; + + if ( cur == limit ) + { + FT_TRACE2(( "%s: can't find module `%s'\n", + func_name, module_name )); + return FT_THROW( Missing_Module ); + } + + /* check whether we have a service interface */ + if ( !cur[0]->clazz->get_interface ) + { + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); + return FT_THROW( Unimplemented_Feature ); + } + + /* search property service */ + interface = cur[0]->clazz->get_interface( cur[0], + FT_SERVICE_ID_PROPERTIES ); + if ( !interface ) + { + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); + return FT_THROW( Unimplemented_Feature ); + } + + service = (FT_Service_Properties)interface; + + if ( set ) + missing_func = FT_BOOL( !service->set_property ); + else + missing_func = FT_BOOL( !service->get_property ); + + if ( missing_func ) + { + FT_TRACE2(( "%s: property service of module `%s' is broken\n", + func_name, module_name )); + return FT_THROW( Unimplemented_Feature ); + } + + return set ? service->set_property( cur[0], + property_name, + value, + value_is_string ) + : service->get_property( cur[0], + property_name, + value ); + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Property_Set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + const void* value ) + { + return ft_property_do( library, + module_name, + property_name, + (void*)value, + TRUE, + FALSE ); + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Property_Get( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value ) + { + return ft_property_do( library, + module_name, + property_name, + value, + FALSE, + FALSE ); + } + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + /* this variant is used for handling the FREETYPE_PROPERTIES */ + /* environment variable */ + + FT_BASE_DEF( FT_Error ) + ft_property_string_set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + FT_String* value ) + { + return ft_property_do( library, + module_name, + property_name, + (void*)value, + TRUE, + TRUE ); + } + +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Reference_Library( FT_Library library ) + { + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + library->refcount++; + + return FT_Err_Ok; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ) + { + FT_Library library = NULL; + FT_Error error; + + + if ( !memory || !alibrary ) + return FT_THROW( Invalid_Argument ); + +#ifndef FT_DEBUG_LOGGING +#ifdef FT_DEBUG_LEVEL_ERROR + /* init debugging support */ + ft_debug_init(); +#endif /* FT_DEBUG_LEVEL_ERROR */ +#endif /* !FT_DEBUG_LOGGING */ + + /* first of all, allocate the library object */ + if ( FT_NEW( library ) ) + return error; + + library->memory = memory; + + library->version_major = FREETYPE_MAJOR; + library->version_minor = FREETYPE_MINOR; + library->version_patch = FREETYPE_PATCH; + + library->refcount = 1; + + /* That's ok now */ + *alibrary = library; + + return FT_Err_Ok; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ) + { + FT_Int major = 0; + FT_Int minor = 0; + FT_Int patch = 0; + + + if ( library ) + { + major = library->version_major; + minor = library->version_minor; + patch = library->version_patch; + } + + if ( amajor ) + *amajor = major; + + if ( aminor ) + *aminor = minor; + + if ( apatch ) + *apatch = patch; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Library( FT_Library library ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + library->refcount--; + if ( library->refcount > 0 ) + goto Exit; + + memory = library->memory; + + /* + * Close all faces in the library. If we don't do this, we can have + * some subtle memory leaks. + * + * Example: + * + * - the cff font driver uses the pshinter module in cff_size_done + * - if the pshinter module is destroyed before the cff font driver, + * opened FT_Face objects managed by the driver are not properly + * destroyed, resulting in a memory leak + * + * Some faces are dependent on other faces, like Type42 faces that + * depend on TrueType faces synthesized internally. + * + * The order of drivers should be specified in driver_name[]. + */ + { + FT_UInt m, n; + const char* driver_name[] = { "type42", NULL }; + + + for ( m = 0; + m < sizeof ( driver_name ) / sizeof ( driver_name[0] ); + m++ ) + { + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + const char* module_name = module->clazz->module_name; + FT_List faces; + + + if ( driver_name[m] && + ft_strcmp( module_name, driver_name[m] ) != 0 ) + continue; + + if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 ) + continue; + + FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name )); + + faces = &FT_DRIVER( module )->faces_list; + while ( faces->head ) + { + FT_Done_Face( FT_FACE( faces->head->data ) ); + if ( faces->head ) + FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" )); + } + } + } + } + + /* Close all other modules in the library */ +#if 1 + /* XXX Modules are removed in the reversed order so that */ + /* type42 module is removed before truetype module. This */ + /* avoids double free in some occasions. It is a hack. */ + while ( library->num_modules > 0 ) + FT_Remove_Module( library, + library->modules[library->num_modules - 1] ); +#else + { + FT_UInt n; + + + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + + + if ( module ) + { + Destroy_Module( module ); + library->modules[n] = NULL; + } + } + } +#endif + + FT_FREE( library ); + + Exit: + return FT_Err_Ok; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ) + { + if ( library && debug_hook && + hook_index < + ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) ) + library->debug_hooks[hook_index] = debug_hook; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ) + { + FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE; + + + if ( library ) + { + FT_Module module = FT_Get_Module( library, "truetype" ); + + + if ( module ) + { + FT_Service_TrueTypeEngine service; + + + service = (FT_Service_TrueTypeEngine) + ft_module_get_service( module, + FT_SERVICE_ID_TRUETYPE_ENGINE, + 0 ); + if ( service ) + result = service->engine_type; + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + + + if ( glyph && + glyph->subglyphs && + glyph->format == FT_GLYPH_FORMAT_COMPOSITE && + sub_index < glyph->num_subglyphs ) + { + FT_SubGlyph subg = glyph->subglyphs + sub_index; + + + *p_index = subg->index; + *p_flags = subg->flags; + *p_arg1 = subg->arg1; + *p_arg2 = subg->arg2; + *p_transform = subg->transform; + + error = FT_Err_Ok; + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_Layer( FT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || + !aglyph_index || + !acolor_index || + !iterator || + base_glyph >= (FT_UInt)face->num_glyphs ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colr_layer ) + return sfnt->get_colr_layer( ttface, + base_glyph, + aglyph_index, + acolor_index, + iterator ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colr_layer ) + return sfnt->get_colr_glyph_paint( ttface, + base_glyph, + root_transform, + paint ); + else + return 0; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !clip_box ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_color_glyph_clipbox ) + return sfnt->get_color_glyph_clipbox( ttface, + base_glyph, + clip_box ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* layer_iterator, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint || !layer_iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint_layers ) + return sfnt->get_paint_layers( ttface, layer_iterator, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint ) + return sfnt->get_paint( ttface, opaque_paint, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Colorline_Stops ( FT_Face face, + FT_ColorStop * color_stop, + FT_ColorStopIterator *iterator ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !color_stop || !iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colorline_stops ) + return sfnt->get_colorline_stops ( ttface, color_stop, iterator ); + else + return 0; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftotval.c b/vendor/freetype/src/base/ftotval.c new file mode 100644 index 0000000..192e12a --- /dev/null +++ b/vendor/freetype/src/base/ftotval.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * ftotval.c + * + * FreeType API for validating OpenType tables (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include + +#include +#include +#include + + + /* documentation is in ftotval.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ) + { + FT_Service_OTvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( !( BASE_table && + GDEF_table && + GPOS_table && + GSUB_table && + JSTF_table ) ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + BASE_table, + GDEF_table, + GPOS_table, + GSUB_table, + JSTF_table ); + else + error = FT_THROW( Unimplemented_Feature ); + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + FT_FREE( table ); + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftoutln.c b/vendor/freetype/src/base/ftoutln.c new file mode 100644 index 0000000..134f39d --- /dev/null +++ b/vendor/freetype/src/base/ftoutln.c @@ -0,0 +1,1118 @@ +/**************************************************************************** + * + * ftoutln.c + * + * FreeType outline management (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT outline + + + static + const FT_Outline null_outline = { 0, 0, NULL, NULL, NULL, 0 }; + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( (x) * ( 1L << shift ) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + FT_Error error; + + FT_Int n; /* index of contour in outline */ + FT_Int first; /* index of first point in contour */ + FT_Int last; /* index of last point in contour */ + + FT_Int tag; /* current point's state */ + + FT_Int shift; + FT_Pos delta; + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !func_interface ) + return FT_THROW( Invalid_Argument ); + + shift = func_interface->shift; + delta = func_interface->delta; + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n )); + + first = last + 1; + last = outline->contours[n]; + if ( last < first ) + goto Invalid_Outline; + + limit = outline->points + last; + + v_start = outline->points[first]; + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + + v_last = outline->points[last]; + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + /* v_last = v_start; */ + } + point--; + tags--; + } + + FT_TRACE5(( " move to (%.2f, %.2f)\n", + (double)v_start.x / 64, (double)v_start.y / 64 )); + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " line to (%.2f, %.2f)\n", + (double)vec.x / 64, (double)vec.y / 64 )); + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + (double)vec.x / 64, + (double)vec.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + (double)v_middle.x / 64, + (double)v_middle.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + (double)v_start.x / 64, + (double)v_start.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + (double)vec.x / 64, + (double)vec.y / 64, + (double)vec1.x / 64, + (double)vec1.y / 64, + (double)vec2.x / 64, + (double)vec2.y / 64 )); + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + (double)v_start.x / 64, + (double)v_start.y / 64, + (double)vec1.x / 64, + (double)vec1.y / 64, + (double)vec2.x / 64, + (double)vec2.y / 64 )); + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + FT_TRACE5(( " line to (%.2f, %.2f)\n", + (double)v_start.x / 64, (double)v_start.y / 64 )); + error = func_interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + } + + FT_TRACE5(( "FT_Outline_Decompose: Done\n" )); + return FT_Err_Ok; + + Invalid_Outline: + error = FT_THROW( Invalid_Outline ); + /* fall through */ + + Exit: + FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ) + { + FT_Error error; + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + memory = library->memory; + + if ( !anoutline || !memory ) + return FT_THROW( Invalid_Argument ); + + *anoutline = null_outline; + + if ( numContours < 0 || + (FT_UInt)numContours > numPoints ) + return FT_THROW( Invalid_Argument ); + + if ( numPoints > FT_OUTLINE_POINTS_MAX ) + return FT_THROW( Array_Too_Large ); + + if ( FT_NEW_ARRAY( anoutline->points, numPoints ) || + FT_NEW_ARRAY( anoutline->tags, numPoints ) || + FT_NEW_ARRAY( anoutline->contours, numContours ) ) + goto Fail; + + anoutline->n_points = (FT_Short)numPoints; + anoutline->n_contours = (FT_Short)numContours; + anoutline->flags |= FT_OUTLINE_OWNER; + + return FT_Err_Ok; + + Fail: + anoutline->flags |= FT_OUTLINE_OWNER; + FT_Outline_Done( library, anoutline ); + + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Check( FT_Outline* outline ) + { + if ( outline ) + { + FT_Int n_points = outline->n_points; + FT_Int n_contours = outline->n_contours; + FT_Int end0, end; + FT_Int n; + + + /* empty glyph? */ + if ( n_points == 0 && n_contours == 0 ) + return FT_Err_Ok; + + /* check point and contour counts */ + if ( n_points <= 0 || n_contours <= 0 ) + goto Bad; + + end0 = -1; + for ( n = 0; n < n_contours; n++ ) + { + end = outline->contours[n]; + + /* note that we don't accept empty contours */ + if ( end <= end0 || end >= n_points ) + goto Bad; + + end0 = end; + } + + if ( end0 != n_points - 1 ) + goto Bad; + + /* XXX: check the tags array */ + return FT_Err_Ok; + } + + Bad: + return FT_THROW( Invalid_Outline ); + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ) + { + FT_Int is_owner; + + + if ( !source || !target ) + return FT_THROW( Invalid_Outline ); + + if ( source->n_points != target->n_points || + source->n_contours != target->n_contours ) + return FT_THROW( Invalid_Argument ); + + if ( source == target ) + return FT_Err_Ok; + + if ( source->n_points ) + { + FT_ARRAY_COPY( target->points, source->points, source->n_points ); + FT_ARRAY_COPY( target->tags, source->tags, source->n_points ); + } + + if ( source->n_contours ) + FT_ARRAY_COPY( target->contours, source->contours, source->n_contours ); + + /* copy all flags, except the `FT_OUTLINE_OWNER' one */ + is_owner = target->flags & FT_OUTLINE_OWNER; + target->flags = source->flags; + + target->flags &= ~FT_OUTLINE_OWNER; + target->flags |= is_owner; + + return FT_Err_Ok; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + memory = library->memory; + + if ( !memory ) + return FT_THROW( Invalid_Argument ); + + if ( outline->flags & FT_OUTLINE_OWNER ) + { + FT_FREE( outline->points ); + FT_FREE( outline->tags ); + FT_FREE( outline->contours ); + } + *outline = null_outline; + + return FT_Err_Ok; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ) + { + FT_Pos xMin, yMin, xMax, yMax; + + + if ( outline && acbox ) + { + if ( outline->n_points == 0 ) + { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } + else + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + + for ( ; vec < limit; vec++ ) + { + FT_Pos x, y; + + + x = vec->x; + if ( x < xMin ) xMin = x; + if ( x > xMax ) xMax = x; + + y = vec->y; + if ( y < yMin ) yMin = y; + if ( y > yMax ) yMax = y; + } + } + acbox->xMin = xMin; + acbox->xMax = xMax; + acbox->yMin = yMin; + acbox->yMax = yMax; + } + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ) + { + FT_UShort n; + FT_Vector* vec; + + + if ( !outline ) + return; + + vec = outline->points; + + for ( n = 0; n < outline->n_points; n++ ) + { + vec->x = ADD_LONG( vec->x, xOffset ); + vec->y = ADD_LONG( vec->y, yOffset ); + vec++; + } + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Reverse( FT_Outline* outline ) + { + FT_UShort n; + FT_Int first, last; + + + if ( !outline ) + return; + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + /* keep the first contour point as is and swap points around it */ + /* to guarantee that the cubic arches stay valid after reverse */ + first = last + 2; + last = outline->contours[n]; + + /* reverse point table */ + { + FT_Vector* p = outline->points + first; + FT_Vector* q = outline->points + last; + FT_Vector swap; + + + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + + /* reverse tags table */ + { + char* p = outline->tags + first; + char* q = outline->tags + last; + + + while ( p < q ) + { + char swap; + + + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + } + + outline->flags ^= FT_OUTLINE_REVERSE_FILL; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ) + { + FT_Error error; + FT_Renderer renderer; + FT_ListNode node; + FT_BBox cbox; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !params ) + return FT_THROW( Invalid_Argument ); + + FT_Outline_Get_CBox( outline, &cbox ); + if ( cbox.xMin < -0x1000000L || cbox.yMin < -0x1000000L || + cbox.xMax > 0x1000000L || cbox.yMax > 0x1000000L ) + return FT_THROW( Invalid_Outline ); + + renderer = library->cur_renderer; + node = library->renderers.head; + + params->source = (void*)outline; + + /* preset clip_box for direct mode */ + if ( params->flags & FT_RASTER_FLAG_DIRECT && + !( params->flags & FT_RASTER_FLAG_CLIP ) ) + { + params->clip_box.xMin = cbox.xMin >> 6; + params->clip_box.yMin = cbox.yMin >> 6; + params->clip_box.xMax = ( cbox.xMax + 63 ) >> 6; + params->clip_box.yMax = ( cbox.yMax + 63 ) >> 6; + } + + error = FT_ERR( Cannot_Render_Glyph ); + while ( renderer ) + { + error = renderer->raster_render( renderer->raster, params ); + if ( !error || FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format */ + + /* now, look for another renderer that supports the same */ + /* format */ + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, + &node ); + } + + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ) + { + FT_Raster_Params params; + + + if ( !abitmap ) + return FT_THROW( Invalid_Argument ); + + /* other checks are delayed to `FT_Outline_Render' */ + + params.target = abitmap; + params.flags = 0; + + if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) + params.flags |= FT_RASTER_FLAG_AA; + + return FT_Outline_Render( library, outline, ¶ms ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Transform( FT_Vector* vector, + const FT_Matrix* matrix ) + { + FT_Pos xz, yz; + + + if ( !vector || !matrix ) + return; + + xz = FT_MulFix( vector->x, matrix->xx ) + + FT_MulFix( vector->y, matrix->xy ); + + yz = FT_MulFix( vector->x, matrix->yx ) + + FT_MulFix( vector->y, matrix->yy ); + + vector->x = xz; + vector->y = yz; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ) + { + FT_Vector* vec; + FT_Vector* limit; + + + if ( !outline || !matrix || !outline->points ) + return; + + vec = outline->points; + limit = vec + outline->n_points; + + for ( ; vec < limit; vec++ ) + FT_Vector_Transform( vec, matrix ); + } + + +#if 0 + +#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \ + do \ + { \ + (first) = ( c > 0 ) ? (outline)->points + \ + (outline)->contours[c - 1] + 1 \ + : (outline)->points; \ + (last) = (outline)->points + (outline)->contours[c]; \ + } while ( 0 ) + + + /* Is a point in some contour? */ + /* */ + /* We treat every point of the contour as if it */ + /* it were ON. That is, we allow false positives, */ + /* but disallow false negatives. (XXX really?) */ + static FT_Bool + ft_contour_has( FT_Outline* outline, + FT_Short c, + FT_Vector* point ) + { + FT_Vector* first; + FT_Vector* last; + FT_Vector* a; + FT_Vector* b; + FT_UInt n = 0; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( a = first; a <= last; a++ ) + { + FT_Pos x; + FT_Int intersect; + + + b = ( a == last ) ? first : a + 1; + + intersect = ( a->y - point->y ) ^ ( b->y - point->y ); + + /* a and b are on the same side */ + if ( intersect >= 0 ) + { + if ( intersect == 0 && a->y == point->y ) + { + if ( ( a->x <= point->x && b->x >= point->x ) || + ( a->x >= point->x && b->x <= point->x ) ) + return 1; + } + + continue; + } + + x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y ); + + if ( x < point->x ) + n++; + else if ( x == point->x ) + return 1; + } + + return n & 1; + } + + + static FT_Bool + ft_contour_enclosed( FT_Outline* outline, + FT_UShort c ) + { + FT_Vector* first; + FT_Vector* last; + FT_Short i; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( i = 0; i < outline->n_contours; i++ ) + { + if ( i != c && ft_contour_has( outline, i, first ) ) + { + FT_Vector* pt; + + + for ( pt = first + 1; pt <= last; pt++ ) + if ( !ft_contour_has( outline, i, pt ) ) + return 0; + + return 1; + } + } + + return 0; + } + + + /* This version differs from the public one in that each */ + /* part (contour not enclosed in another contour) of the */ + /* outline is checked for orientation. This is */ + /* necessary for some buggy CJK fonts. */ + static FT_Orientation + ft_outline_get_orientation( FT_Outline* outline ) + { + FT_Short i; + FT_Vector* first; + FT_Vector* last; + FT_Orientation orient = FT_ORIENTATION_NONE; + + + first = outline->points; + for ( i = 0; i < outline->n_contours; i++, first = last + 1 ) + { + FT_Vector* point; + FT_Vector* xmin_point; + FT_Pos xmin; + + + last = outline->points + outline->contours[i]; + + /* skip degenerate contours */ + if ( last < first + 2 ) + continue; + + if ( ft_contour_enclosed( outline, i ) ) + continue; + + xmin = first->x; + xmin_point = first; + + for ( point = first + 1; point <= last; point++ ) + { + if ( point->x < xmin ) + { + xmin = point->x; + xmin_point = point; + } + } + + /* check the orientation of the contour */ + { + FT_Vector* prev; + FT_Vector* next; + FT_Orientation o; + + + prev = ( xmin_point == first ) ? last : xmin_point - 1; + next = ( xmin_point == last ) ? first : xmin_point + 1; + + if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) > + FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) ) + o = FT_ORIENTATION_POSTSCRIPT; + else + o = FT_ORIENTATION_TRUETYPE; + + if ( orient == FT_ORIENTATION_NONE ) + orient = o; + else if ( orient != o ) + return FT_ORIENTATION_NONE; + } + } + + return orient; + } + +#endif /* 0 */ + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ) + { + return FT_Outline_EmboldenXY( outline, strength, strength ); + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_EmboldenXY( FT_Outline* outline, + FT_Pos xstrength, + FT_Pos ystrength ) + { + FT_Vector* points; + FT_Int c, first, last; + FT_Orientation orientation; + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + xstrength /= 2; + ystrength /= 2; + if ( xstrength == 0 && ystrength == 0 ) + return FT_Err_Ok; + + orientation = FT_Outline_Get_Orientation( outline ); + if ( orientation == FT_ORIENTATION_NONE ) + { + if ( outline->n_contours ) + return FT_THROW( Invalid_Argument ); + else + return FT_Err_Ok; + } + + points = outline->points; + + last = -1; + for ( c = 0; c < outline->n_contours; c++ ) + { + FT_Vector in, out, anchor, shift; + FT_Fixed l_in, l_out, l_anchor = 0, l, q, d; + FT_Int i, j, k; + + + first = last + 1; + last = outline->contours[c]; + l_in = 0; + + /* pacify compiler */ + in.x = in.y = anchor.x = anchor.y = 0; + + /* Counter j cycles though the points; counter i advances only */ + /* when points are moved; anchor k marks the first moved point. */ + for ( i = last, j = first, k = -1; + j != i && i != k; + j = j < last ? j + 1 : first ) + { + if ( j != k ) + { + out.x = points[j].x - points[i].x; + out.y = points[j].y - points[i].y; + l_out = (FT_Fixed)FT_Vector_NormLen( &out ); + + if ( l_out == 0 ) + continue; + } + else + { + out = anchor; + l_out = l_anchor; + } + + if ( l_in != 0 ) + { + if ( k < 0 ) + { + k = i; + anchor = in; + l_anchor = l_in; + } + + d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y ); + + /* shift only if turn is less than ~160 degrees */ + if ( d > -0xF000L ) + { + d = d + 0x10000L; + + /* shift components along lateral bisector in proper orientation */ + shift.x = in.y + out.y; + shift.y = in.x + out.x; + + if ( orientation == FT_ORIENTATION_TRUETYPE ) + shift.x = -shift.x; + else + shift.y = -shift.y; + + /* restrict shift magnitude to better handle collapsing segments */ + q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x ); + if ( orientation == FT_ORIENTATION_TRUETYPE ) + q = -q; + + l = FT_MIN( l_in, l_out ); + + /* non-strict inequalities avoid divide-by-zero when q == l == 0 */ + if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) ) + shift.x = FT_MulDiv( shift.x, xstrength, d ); + else + shift.x = FT_MulDiv( shift.x, l, q ); + + + if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) ) + shift.y = FT_MulDiv( shift.y, ystrength, d ); + else + shift.y = FT_MulDiv( shift.y, l, q ); + } + else + shift.x = shift.y = 0; + + for ( ; + i != j; + i = i < last ? i + 1 : first ) + { + points[i].x += xstrength + shift.x; + points[i].y += ystrength + shift.y; + } + } + else + i = j; + + in = out; + l_in = l_out; + } + } + + return FT_Err_Ok; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ) + { + FT_BBox cbox = { 0, 0, 0, 0 }; + FT_Int xshift, yshift; + FT_Vector* points; + FT_Vector v_prev, v_cur; + FT_Int c, n, first, last; + FT_Pos area = 0; + + + if ( !outline || outline->n_points <= 0 ) + return FT_ORIENTATION_TRUETYPE; + + /* We use the nonzero winding rule to find the orientation. */ + /* Since glyph outlines behave much more `regular' than arbitrary */ + /* cubic or quadratic curves, this test deals with the polygon */ + /* only that is spanned up by the control points. */ + + FT_Outline_Get_CBox( outline, &cbox ); + + /* Handle collapsed outlines to avoid undefined FT_MSB. */ + if ( cbox.xMin == cbox.xMax || cbox.yMin == cbox.yMax ) + return FT_ORIENTATION_NONE; + + /* Reject values large outlines. */ + if ( cbox.xMin < -0x1000000L || cbox.yMin < -0x1000000L || + cbox.xMax > 0x1000000L || cbox.yMax > 0x1000000L ) + return FT_ORIENTATION_NONE; + + xshift = FT_MSB( (FT_UInt32)( FT_ABS( cbox.xMax ) | + FT_ABS( cbox.xMin ) ) ) - 14; + xshift = FT_MAX( xshift, 0 ); + + yshift = FT_MSB( (FT_UInt32)( cbox.yMax - cbox.yMin ) ) - 14; + yshift = FT_MAX( yshift, 0 ); + + points = outline->points; + + last = -1; + for ( c = 0; c < outline->n_contours; c++ ) + { + first = last + 1; + last = outline->contours[c]; + + v_prev.x = points[last].x >> xshift; + v_prev.y = points[last].y >> yshift; + + for ( n = first; n <= last; n++ ) + { + v_cur.x = points[n].x >> xshift; + v_cur.y = points[n].y >> yshift; + + area = ADD_LONG( area, + MUL_LONG( v_cur.y - v_prev.y, + v_cur.x + v_prev.x ) ); + + v_prev = v_cur; + } + } + + if ( area > 0 ) + return FT_ORIENTATION_POSTSCRIPT; + else if ( area < 0 ) + return FT_ORIENTATION_TRUETYPE; + else + return FT_ORIENTATION_NONE; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftpatent.c b/vendor/freetype/src/base/ftpatent.c new file mode 100644 index 0000000..cb5efad --- /dev/null +++ b/vendor/freetype/src/base/ftpatent.c @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * ftpatent.c + * + * FreeType API for checking patented TrueType bytecode instructions + * (body). Obsolete, retained for backward compatibility. + * + * Copyright (C) 2007-2023 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include +#include +#include + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ) + { + FT_UNUSED( face ); + + return FALSE; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ) + { + FT_UNUSED( face ); + FT_UNUSED( value ); + + return FALSE; + } + +/* END */ diff --git a/vendor/freetype/src/base/ftpfr.c b/vendor/freetype/src/base/ftpfr.c new file mode 100644 index 0000000..378385a --- /dev/null +++ b/vendor/freetype/src/base/ftpfr.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * + * ftpfr.c + * + * FreeType API for accessing PFR-specific data (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include + +#include +#include + + + /* check the format */ + static FT_Service_PfrMetrics + ft_pfr_check( FT_Face face ) + { + FT_Service_PfrMetrics service = NULL; + + + if ( face ) + FT_FACE_LOOKUP_SERVICE( face, service, PFR_METRICS ); + + return service; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + FT_Error error = FT_Err_Ok; + FT_Service_PfrMetrics service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + service = ft_pfr_check( face ); + if ( service ) + { + error = service->get_metrics( face, + aoutline_resolution, + ametrics_resolution, + ametrics_x_scale, + ametrics_y_scale ); + } + else + { + FT_Fixed x_scale, y_scale; + + + /* this is not a PFR font */ + if ( aoutline_resolution ) + *aoutline_resolution = face->units_per_EM; + + if ( ametrics_resolution ) + *ametrics_resolution = face->units_per_EM; + + x_scale = y_scale = 0x10000L; + if ( face->size ) + { + x_scale = face->size->metrics.x_scale; + y_scale = face->size->metrics.y_scale; + } + + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + + error = FT_THROW( Unknown_File_Format ); + } + + return error; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + FT_Error error; + FT_Service_PfrMetrics service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !avector ) + return FT_THROW( Invalid_Argument ); + + service = ft_pfr_check( face ); + if ( service ) + error = service->get_kerning( face, left, right, avector ); + else + error = FT_Get_Kerning( face, left, right, + FT_KERNING_UNSCALED, avector ); + + return error; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ) + { + FT_Error error; + FT_Service_PfrMetrics service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !aadvance ) + return FT_THROW( Invalid_Argument ); + + service = ft_pfr_check( face ); + if ( service ) + error = service->get_advance( face, gindex, aadvance ); + else + /* XXX: TODO: PROVIDE ADVANCE-LOADING METHOD TO ALL FONT DRIVERS */ + error = FT_THROW( Invalid_Argument ); + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftpsprop.c b/vendor/freetype/src/base/ftpsprop.c new file mode 100644 index 0000000..cefdf48 --- /dev/null +++ b/vendor/freetype/src/base/ftpsprop.c @@ -0,0 +1,284 @@ +/**************************************************************************** + * + * ftpsprop.c + * + * Get and set properties of PostScript drivers (body). + * See `ftdriver.h' for available properties. + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT psprops + + + FT_BASE_CALLBACK_DEF( FT_Error ) + ps_property_set( FT_Module module, /* PS_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + PS_Driver driver = (PS_Driver)module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params; + FT_Int x1, y1, x2, y2, x3, y3, x4, y4; + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_Int dp[8]; + + + if ( value_is_string ) + { + const char* s = (const char*)value; + char* ep; + int i; + + + /* eight comma-separated numbers */ + for ( i = 0; i < 7; i++ ) + { + dp[i] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( *ep != ',' || s == ep ) + return FT_THROW( Invalid_Argument ); + + s = ep + 1; + } + + dp[7] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( !( *ep == '\0' || *ep == ' ' ) || s == ep ) + return FT_THROW( Invalid_Argument ); + + darken_params = dp; + } + else +#endif + darken_params = (FT_Int*)value; + + x1 = darken_params[0]; + y1 = darken_params[1]; + x2 = darken_params[2]; + y2 = darken_params[3]; + x3 = darken_params[4]; + y3 = darken_params[5]; + x4 = darken_params[6]; + y4 = darken_params[7]; + + if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || + y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 || + x1 > x2 || x2 > x3 || x3 > x4 || + y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 ) + return FT_THROW( Invalid_Argument ); + + driver->darken_params[0] = x1; + driver->darken_params[1] = y1; + driver->darken_params[2] = x2; + driver->darken_params[3] = y2; + driver->darken_params[4] = x3; + driver->darken_params[5] = y3; + driver->darken_params[6] = x4; + driver->darken_params[7] = y4; + + return error; + } + + else if ( !ft_strcmp( property_name, "hinting-engine" ) ) + { +#if defined( CFF_CONFIG_OPTION_OLD_ENGINE ) || \ + defined( T1_CONFIG_OPTION_OLD_ENGINE ) + const char* module_name = module->clazz->module_name; +#endif + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + + + if ( !ft_strcmp( s, "adobe" ) ) + driver->hinting_engine = FT_HINTING_ADOBE; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + else if ( !ft_strcmp( module_name, "cff" ) && + !ft_strcmp( s, "freetype" ) ) + driver->hinting_engine = FT_HINTING_FREETYPE; +#endif + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + else if ( ( !ft_strcmp( module_name, "type1" ) || + !ft_strcmp( module_name, "t1cid" ) ) && + !ft_strcmp( s, "freetype" ) ) + driver->hinting_engine = FT_HINTING_FREETYPE; +#endif + + else + return FT_THROW( Invalid_Argument ); + } + else +#endif /* FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES */ + { + FT_UInt* hinting_engine = (FT_UInt*)value; + + + if ( *hinting_engine == FT_HINTING_ADOBE +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + || ( *hinting_engine == FT_HINTING_FREETYPE && + !ft_strcmp( module_name, "cff" ) ) +#endif +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + || ( *hinting_engine == FT_HINTING_FREETYPE && + ( !ft_strcmp( module_name, "type1" ) || + !ft_strcmp( module_name, "t1cid" ) ) ) +#endif + ) + driver->hinting_engine = *hinting_engine; + else + error = FT_ERR( Unimplemented_Feature ); + } + + return error; + } + + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + long nsd = ft_strtol( s, NULL, 10 ); + + + if ( !nsd ) + driver->no_stem_darkening = FALSE; + else + driver->no_stem_darkening = TRUE; + } + else +#endif + { + FT_Bool* no_stem_darkening = (FT_Bool*)value; + + + driver->no_stem_darkening = *no_stem_darkening; + } + + return error; + } + + else if ( !ft_strcmp( property_name, "random-seed" ) ) + { + FT_Int32 random_seed; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + + + random_seed = (FT_Int32)ft_strtol( s, NULL, 10 ); + } + else +#endif + random_seed = *(FT_Int32*)value; + + if ( random_seed < 0 ) + random_seed = 0; + + driver->random_seed = random_seed; + + return error; + } + + FT_TRACE2(( "ps_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_BASE_CALLBACK_DEF( FT_Error ) + ps_property_get( FT_Module module, /* PS_Driver */ + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + PS_Driver driver = (PS_Driver)module; + + + if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params = driver->darken_params; + FT_Int* val = (FT_Int*)value; + + + val[0] = darken_params[0]; + val[1] = darken_params[1]; + val[2] = darken_params[2]; + val[3] = darken_params[3]; + val[4] = darken_params[4]; + val[5] = darken_params[5]; + val[6] = darken_params[6]; + val[7] = darken_params[7]; + + return error; + } + + else if ( !ft_strcmp( property_name, "hinting-engine" ) ) + { + FT_UInt hinting_engine = driver->hinting_engine; + FT_UInt* val = (FT_UInt*)value; + + + *val = hinting_engine; + + return error; + } + + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { + FT_Bool no_stem_darkening = driver->no_stem_darkening; + FT_Bool* val = (FT_Bool*)value; + + + *val = no_stem_darkening; + + return error; + } + + FT_TRACE2(( "ps_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftrfork.c b/vendor/freetype/src/base/ftrfork.c new file mode 100644 index 0000000..2ab4301 --- /dev/null +++ b/vendor/freetype/src/base/ftrfork.c @@ -0,0 +1,934 @@ +/**************************************************************************** + * + * ftrfork.c + * + * Embedded resource forks accessor (body). + * + * Copyright (C) 2004-2023 by + * Masatake YAMATO and Redhat K.K. + * + * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are + * derived from ftobjs.c. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * Development of the code in this file is support of + * Information-technology Promotion Agency, Japan. + */ + + +#include +#include +#include + +#include "ftbase.h" + +#undef FT_COMPONENT +#define FT_COMPONENT raccess + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** Resource fork directory access ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ) + { + FT_Error error; + unsigned char head[16], head2[16]; + FT_Long map_pos, map_len, rdata_len; + int allzeros, allmatch, i; + FT_Long type_list; + + FT_UNUSED( library ); + + + error = FT_Stream_Seek( stream, (FT_ULong)rfork_offset ); + if ( error ) + return error; + + error = FT_Stream_Read( stream, (FT_Byte*)head, 16 ); + if ( error ) + return error; + + /* ensure positive values */ + if ( head[0] >= 0x80 || + head[4] >= 0x80 || + head[8] >= 0x80 || + head[12] >= 0x80 ) + return FT_THROW( Unknown_File_Format ); + + *rdata_pos = ( head[ 0] << 24 ) | + ( head[ 1] << 16 ) | + ( head[ 2] << 8 ) | + head[ 3]; + map_pos = ( head[ 4] << 24 ) | + ( head[ 5] << 16 ) | + ( head[ 6] << 8 ) | + head[ 7]; + rdata_len = ( head[ 8] << 24 ) | + ( head[ 9] << 16 ) | + ( head[10] << 8 ) | + head[11]; + map_len = ( head[12] << 24 ) | + ( head[13] << 16 ) | + ( head[14] << 8 ) | + head[15]; + + /* the map must not be empty */ + if ( !map_pos ) + return FT_THROW( Unknown_File_Format ); + + /* check whether rdata and map overlap */ + if ( *rdata_pos < map_pos ) + { + if ( *rdata_pos > map_pos - rdata_len ) + return FT_THROW( Unknown_File_Format ); + } + else + { + if ( map_pos > *rdata_pos - map_len ) + return FT_THROW( Unknown_File_Format ); + } + + /* check whether end of rdata or map exceeds stream size */ + if ( FT_LONG_MAX - rdata_len < *rdata_pos || + FT_LONG_MAX - map_len < map_pos || + + FT_LONG_MAX - ( *rdata_pos + rdata_len ) < rfork_offset || + FT_LONG_MAX - ( map_pos + map_len ) < rfork_offset || + + (FT_ULong)( rfork_offset + *rdata_pos + rdata_len ) > stream->size || + (FT_ULong)( rfork_offset + map_pos + map_len ) > stream->size ) + return FT_THROW( Unknown_File_Format ); + + *rdata_pos += rfork_offset; + map_pos += rfork_offset; + + error = FT_Stream_Seek( stream, (FT_ULong)map_pos ); + if ( error ) + return error; + + head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */ + + error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 ); + if ( error ) + return error; + + allzeros = 1; + allmatch = 1; + for ( i = 0; i < 16; i++ ) + { + if ( head2[i] != 0 ) + allzeros = 0; + if ( head2[i] != head[i] ) + allmatch = 0; + } + if ( !allzeros && !allmatch ) + return FT_THROW( Unknown_File_Format ); + + /* If we have reached this point then it is probably a mac resource */ + /* file. Now, does it contain any interesting resources? */ + + (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */ + + 2 /* skip file resource number */ + + 2 ); /* skip attributes */ + + if ( FT_READ_SHORT( type_list ) ) + return error; + if ( type_list < 0 ) + return FT_THROW( Unknown_File_Format ); + + error = FT_Stream_Seek( stream, (FT_ULong)( map_pos + type_list ) ); + if ( error ) + return error; + + *map_offset = map_pos + type_list; + return FT_Err_Ok; + } + + + FT_COMPARE_DEF( int ) + ft_raccess_sort_ref_by_id( const void* a, + const void* b ) + { + return ( (FT_RFork_Ref*)a )->res_id - ( (FT_RFork_Ref*)b )->res_id; + } + + + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Bool sort_by_res_id, + FT_Long **offsets, + FT_Long *count ) + { + FT_Error error; + int i, j, cnt, subcnt; + FT_Long tag_internal, rpos; + FT_Memory memory = library->memory; + FT_Long temp; + FT_Long *offsets_internal = NULL; + FT_RFork_Ref *ref = NULL; + + + FT_TRACE3(( "\n" )); + error = FT_Stream_Seek( stream, (FT_ULong)map_offset ); + if ( error ) + return error; + + if ( FT_READ_SHORT( cnt ) ) + return error; + cnt++; + + /* `rpos' is a signed 16bit integer offset to resource records; the */ + /* size of a resource record is 12 bytes. The map header is 28 bytes, */ + /* and a type list needs 10 bytes or more. If we assume that the name */ + /* list is empty and we have only a single entry in the type list, */ + /* there can be at most */ + /* */ + /* (32768 - 28 - 10) / 12 = 2727 */ + /* */ + /* resources. */ + /* */ + /* A type list starts with a two-byte counter, followed by 10-byte */ + /* type records. Assuming that there are no resources, the number of */ + /* type records can be at most */ + /* */ + /* (32768 - 28 - 2) / 8 = 4079 */ + /* */ + if ( cnt > 4079 ) + return FT_THROW( Invalid_Table ); + + for ( i = 0; i < cnt; i++ ) + { + if ( FT_READ_LONG( tag_internal ) || + FT_READ_SHORT( subcnt ) || + FT_READ_SHORT( rpos ) ) + return error; + + FT_TRACE2(( "Resource tags: %c%c%c%c\n", + (char)( 0xFF & ( tag_internal >> 24 ) ), + (char)( 0xFF & ( tag_internal >> 16 ) ), + (char)( 0xFF & ( tag_internal >> 8 ) ), + (char)( 0xFF & ( tag_internal >> 0 ) ) )); + FT_TRACE3(( " : subcount=%d, suboffset=0x%04lx\n", + subcnt, rpos )); + + if ( tag_internal == tag ) + { + *count = subcnt + 1; + rpos += map_offset; + + /* a zero count might be valid in the resource specification, */ + /* however, it is completely useless to us */ + if ( *count < 1 || *count > 2727 ) + return FT_THROW( Invalid_Table ); + + error = FT_Stream_Seek( stream, (FT_ULong)rpos ); + if ( error ) + return error; + + if ( FT_QNEW_ARRAY( ref, *count ) ) + return error; + + for ( j = 0; j < *count; j++ ) + { + if ( FT_READ_SHORT( ref[j].res_id ) ) + goto Exit; + if ( FT_STREAM_SKIP( 2 ) ) /* resource name offset */ + goto Exit; + if ( FT_READ_LONG( temp ) ) /* attributes (8bit), offset (24bit) */ + goto Exit; + if ( FT_STREAM_SKIP( 4 ) ) /* mbz */ + goto Exit; + + /* + * According to Inside Macintosh: More Macintosh Toolbox, + * "Resource IDs" (1-46), there are some reserved IDs. + * However, FreeType2 is not a font synthesizer, no need + * to check the acceptable resource ID. + */ + if ( temp < 0 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + ref[j].offset = temp & 0xFFFFFFL; + + FT_TRACE3(( " [%d]:" + " resource_id=0x%04x, offset=0x%08lx\n", + j, (FT_UShort)ref[j].res_id, ref[j].offset )); + } + + if ( sort_by_res_id ) + { + ft_qsort( ref, + (size_t)*count, + sizeof ( FT_RFork_Ref ), + ft_raccess_sort_ref_by_id ); + + FT_TRACE3(( " -- sort resources by their ids --\n" )); + + for ( j = 0; j < *count; j++ ) + FT_TRACE3(( " [%d]:" + " resource_id=0x%04x, offset=0x%08lx\n", + j, ref[j].res_id, ref[j].offset )); + } + + if ( FT_QNEW_ARRAY( offsets_internal, *count ) ) + goto Exit; + + /* XXX: duplicated reference ID, + * gap between reference IDs are acceptable? + * further investigation on Apple implementation is needed. + */ + for ( j = 0; j < *count; j++ ) + offsets_internal[j] = rdata_pos + ref[j].offset; + + *offsets = offsets_internal; + error = FT_Err_Ok; + + Exit: + FT_FREE( ref ); + return error; + } + } + + return FT_THROW( Cannot_Open_Resource ); + } + + +#ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** Guessing functions ****/ + /**** ****/ + /**** When you add a new guessing function, ****/ + /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_newvfs( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + + CONST_FT_RFORK_RULE_ARRAY_BEGIN( ft_raccess_guess_table, + ft_raccess_guess_rec ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( apple_double, apple_double ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( apple_single, apple_single ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_ufs_export, darwin_ufs_export ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_newvfs, darwin_newvfs ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_hfsplus, darwin_hfsplus ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( vfat, vfat ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_cap, linux_cap ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_double, linux_double ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_netatalk, linux_netatalk ) + CONST_FT_RFORK_RULE_ARRAY_END + + + /*************************************************************************/ + /**** ****/ + /**** Helper functions ****/ + /**** ****/ + /*************************************************************************/ + + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char *base_file_name, + FT_Int32 magic, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char* file_name, + FT_Long *result_offset ); + + static char * + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ); + + FT_BASE_DEF( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char **new_names, + FT_Long *offsets, + FT_Error *errors ) + { + FT_Int i; + + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + new_names[i] = NULL; + if ( NULL != stream ) + errors[i] = FT_Stream_Seek( stream, 0 ); + else + errors[i] = FT_Err_Ok; + + if ( errors[i] ) + continue; + + errors[i] = ft_raccess_guess_table[i].func( library, + stream, base_name, + &(new_names[i]), + &(offsets[i]) ); + } + + return; + } + + +#if defined( FT_CONFIG_OPTION_MAC_FONTS ) && !defined( FT_MACINTOSH ) + static FT_RFork_Rule + raccess_get_rule_type_from_rule_index( FT_Library library, + FT_UInt rule_index ) + { + FT_UNUSED( library ); + + if ( rule_index >= FT_RACCESS_N_RULES ) + return FT_RFork_Rule_invalid; + + return ft_raccess_guess_table[rule_index].type; + } + + + /* + * For this function, refer ftbase.h. + */ + FT_LOCAL_DEF( FT_Bool ) + ft_raccess_rule_by_darwin_vfs( FT_Library library, + FT_UInt rule_index ) + { + switch( raccess_get_rule_type_from_rule_index( library, rule_index ) ) + { + case FT_RFork_Rule_darwin_newvfs: + case FT_RFork_Rule_darwin_hfsplus: + return TRUE; + + default: + return FALSE; + } + } +#endif + + + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = ( 0x00 << 24 ) | + ( 0x05 << 16 ) | + ( 0x16 << 8 ) | + 0x07; + + + *result_file_name = NULL; + if ( NULL == stream ) + return FT_THROW( Cannot_Open_Stream ); + + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + + + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = ( 0x00 << 24 ) | + ( 0x05 << 16 ) | + ( 0x16 << 8 ) | + 0x00; + + + *result_file_name = NULL; + if ( NULL == stream ) + return FT_THROW( Cannot_Open_Stream ); + + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + + + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, "._" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + /* + Only meaningful on systems with hfs+ drivers (or Macs). + */ + FT_Error error; + char* newpath = NULL; + FT_Memory memory; + FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); + + FT_UNUSED( stream ); + + + memory = library->memory; + + if ( base_file_len + 6 > FT_INT_MAX ) + return FT_THROW( Array_Too_Large ); + + if ( FT_QALLOC( newpath, base_file_len + 6 ) ) + return error; + + FT_MEM_COPY( newpath, base_file_name, base_file_len ); + FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_darwin_newvfs( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + /* + Only meaningful on systems with Mac OS X (> 10.1). + */ + FT_Error error; + char* newpath = NULL; + FT_Memory memory; + FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); + + FT_UNUSED( stream ); + + + memory = library->memory; + + if ( base_file_len + 18 > FT_INT_MAX ) + return FT_THROW( Array_Too_Large ); + + if ( FT_QALLOC( newpath, base_file_len + 18 ) ) + return error; + + FT_MEM_COPY( newpath, base_file_name, base_file_len ); + FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, + "resource.frk/" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, ".resource/" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, "%" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, + ".AppleDouble/" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char *base_file_name, + FT_Int32 magic, + FT_Long *result_offset ) + { + FT_Int32 magic_from_stream; + FT_Error error; + FT_Int32 version_number = 0; + FT_UShort n_of_entries; + + int i; + FT_Int32 entry_id, entry_offset, entry_length = 0; + + const FT_Int32 resource_fork_entry_id = 0x2; + + FT_UNUSED( library ); + FT_UNUSED( base_file_name ); + FT_UNUSED( version_number ); + FT_UNUSED( entry_length ); + + + if ( FT_READ_LONG( magic_from_stream ) ) + return error; + if ( magic_from_stream != magic ) + return FT_THROW( Unknown_File_Format ); + + if ( FT_READ_LONG( version_number ) ) + return error; + + /* filler */ + error = FT_Stream_Skip( stream, 16 ); + if ( error ) + return error; + + if ( FT_READ_USHORT( n_of_entries ) ) + return error; + if ( n_of_entries == 0 ) + return FT_THROW( Unknown_File_Format ); + + for ( i = 0; i < n_of_entries; i++ ) + { + if ( FT_READ_LONG( entry_id ) ) + return error; + if ( entry_id == resource_fork_entry_id ) + { + if ( FT_READ_LONG( entry_offset ) || + FT_READ_LONG( entry_length ) ) + continue; + *result_offset = entry_offset; + + return FT_Err_Ok; + } + else + { + error = FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */ + if ( error ) + return error; + } + } + + return FT_THROW( Unknown_File_Format ); + } + + + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char *file_name, + FT_Long *result_offset ) + { + FT_Open_Args args2; + FT_Stream stream2; + char* nouse = NULL; + FT_Error error; + + + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_name; + error = FT_Stream_New( library, &args2, &stream2 ); + if ( error ) + return error; + + error = raccess_guess_apple_double( library, stream2, file_name, + &nouse, result_offset ); + + FT_Stream_Free( stream2, 0 ); + + return error; + } + + + static char* + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ) + { + char* new_name = NULL; + const char* tmp; + const char* slash; + size_t new_length; + FT_Error error; + + + new_length = ft_strlen( original_name ) + ft_strlen( insertion ); + if ( FT_QALLOC( new_name, new_length + 1 ) ) + return NULL; + + tmp = ft_strrchr( original_name, '/' ); + if ( tmp ) + { + ft_strncpy( new_name, + original_name, + (size_t)( tmp - original_name + 1 ) ); + new_name[tmp - original_name + 1] = '\0'; + slash = tmp + 1; + } + else + { + slash = original_name; + new_name[0] = '\0'; + } + + ft_strcat( new_name, insertion ); + ft_strcat( new_name, slash ); + + return new_name; + } + + +#else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + + /************************************************************************** + * Dummy function; just sets errors + */ + + FT_BASE_DEF( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char *base_name, + char **new_names, + FT_Long *offsets, + FT_Error *errors ) + { + FT_Int i; + + FT_UNUSED( library ); + FT_UNUSED( stream ); + FT_UNUSED( base_name ); + + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + new_names[i] = NULL; + offsets[i] = 0; + errors[i] = FT_ERR( Unimplemented_Feature ); + } + } + + +#endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + +/* END */ diff --git a/vendor/freetype/src/base/ftsnames.c b/vendor/freetype/src/base/ftsnames.c new file mode 100644 index 0000000..1917a3f --- /dev/null +++ b/vendor/freetype/src/base/ftsnames.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * + * ftsnames.c + * + * Simple interface to access SFNT name tables (which are used + * to hold font names, copyright info, notices, etc.) (body). + * + * This is _not_ used to retrieve glyph names! + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_SFNT_NAMES + + + /* documentation is in ftsnames.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ) + { + return ( face && FT_IS_SFNT( face ) ) ? ((TT_Face)face)->num_names : 0; + } + + + /* documentation is in ftsnames.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + + + if ( aname && face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( idx < (FT_UInt)ttface->num_names ) + { + TT_Name entry = ttface->name_table.names + idx; + + + /* load name on demand */ + if ( entry->stringLength > 0 && !entry->string ) + { + FT_Memory memory = face->memory; + FT_Stream stream = face->stream; + + + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || + FT_STREAM_SEEK( entry->stringOffset ) || + FT_STREAM_READ( entry->string, entry->stringLength ) ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } + } + + aname->platform_id = entry->platformID; + aname->encoding_id = entry->encodingID; + aname->language_id = entry->languageID; + aname->name_id = entry->nameID; + aname->string = (FT_Byte*)entry->string; + aname->string_len = entry->stringLength; + + error = FT_Err_Ok; + } + } + + return error; + } + + + /* documentation is in ftsnames.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_LangTag( FT_Face face, + FT_UInt langID, + FT_SfntLangTag *alangTag ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + + + if ( alangTag && face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( ttface->name_table.format != 1 ) + return FT_THROW( Invalid_Table ); + + if ( langID > 0x8000U && + langID - 0x8000U < ttface->name_table.numLangTagRecords ) + { + TT_LangTag entry = ttface->name_table.langTags + + ( langID - 0x8000U ); + + + /* load name on demand */ + if ( entry->stringLength > 0 && !entry->string ) + { + FT_Memory memory = face->memory; + FT_Stream stream = face->stream; + + + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || + FT_STREAM_SEEK( entry->stringOffset ) || + FT_STREAM_READ( entry->string, entry->stringLength ) ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } + } + + alangTag->string = (FT_Byte*)entry->string; + alangTag->string_len = entry->stringLength; + + error = FT_Err_Ok; + } + } + + return error; + } + + +#else /* !TT_CONFIG_OPTION_SFNT_NAMES */ + + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ) + { + FT_UNUSED( face ); + + return 0; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ) + { + FT_UNUSED( face ); + FT_UNUSED( idx ); + FT_UNUSED( aname ); + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_LangTag( FT_Face face, + FT_UInt langID, + FT_SfntLangTag *alangTag ) + { + FT_UNUSED( face ); + FT_UNUSED( langID ); + FT_UNUSED( alangTag ); + + return FT_THROW( Unimplemented_Feature ); + } + + +#endif /* !TT_CONFIG_OPTION_SFNT_NAMES */ + + +/* END */ diff --git a/vendor/freetype/src/base/ftstream.c b/vendor/freetype/src/base/ftstream.c new file mode 100644 index 0000000..64826ac --- /dev/null +++ b/vendor/freetype/src/base/ftstream.c @@ -0,0 +1,872 @@ +/**************************************************************************** + * + * ftstream.c + * + * I/O stream support (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT stream + + + FT_BASE_DEF( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ) + { + stream->base = (FT_Byte*) base; + stream->size = size; + stream->pos = 0; + stream->cursor = NULL; + stream->read = NULL; + stream->close = NULL; + } + + + FT_BASE_DEF( void ) + FT_Stream_Close( FT_Stream stream ) + { + if ( stream && stream->close ) + stream->close( stream ); + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ) + { + FT_Error error = FT_Err_Ok; + + + if ( stream->read ) + { + if ( stream->read( stream, pos, NULL, 0 ) ) + { + FT_ERROR(( "FT_Stream_Seek:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + } + } + /* note that seeking to the first position after the file is valid */ + else if ( pos > stream->size ) + { + FT_ERROR(( "FT_Stream_Seek:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + } + + if ( !error ) + stream->pos = pos; + + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ) + { + if ( distance < 0 ) + return FT_THROW( Invalid_Stream_Operation ); + + return FT_Stream_Seek( stream, stream->pos + (FT_ULong)distance ); + } + + + FT_BASE_DEF( FT_ULong ) + FT_Stream_Pos( FT_Stream stream ) + { + return stream->pos; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + return FT_Stream_ReadAt( stream, stream->pos, buffer, count ); + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + if ( pos >= stream->size ) + { + FT_ERROR(( "FT_Stream_ReadAt:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + return FT_THROW( Invalid_Stream_Operation ); + } + + if ( stream->read ) + read_bytes = stream->read( stream, pos, buffer, count ); + else + { + read_bytes = stream->size - pos; + if ( read_bytes > count ) + read_bytes = count; + + /* Allow "reading" zero bytes without UB even if buffer is NULL */ + if ( count ) + FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); + } + + stream->pos = pos + read_bytes; + + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_ReadAt:" + " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + error = FT_THROW( Invalid_Stream_Operation ); + } + + return error; + } + + + FT_BASE_DEF( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong read_bytes = 0; + + + if ( stream->pos >= stream->size ) + goto Exit; + + if ( stream->read ) + read_bytes = stream->read( stream, stream->pos, buffer, count ); + else + { + read_bytes = stream->size - stream->pos; + if ( read_bytes > count ) + read_bytes = count; + + /* Allow "reading" zero bytes without UB even if buffer is NULL */ + if ( count ) + FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); + } + + stream->pos += read_bytes; + + Exit: + return read_bytes; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ) + { + FT_Error error; + + + error = FT_Stream_EnterFrame( stream, count ); + if ( !error ) + { + *pbytes = (FT_Byte*)stream->cursor; + + /* equivalent to FT_Stream_ExitFrame(), with no memory block release */ + stream->cursor = NULL; + stream->limit = NULL; + } + + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ) + { + if ( stream && stream->read ) + { + FT_Memory memory = stream->memory; + + +#ifdef FT_DEBUG_MEMORY + ft_mem_free( memory, *pbytes ); +#else + FT_FREE( *pbytes ); +#endif + } + + *pbytes = NULL; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count )); + + /* check for nested frame access */ + FT_ASSERT( stream && stream->cursor == 0 ); + + if ( stream->read ) + { + /* allocate the frame in memory */ + FT_Memory memory = stream->memory; + + + /* simple sanity check */ + if ( count > stream->size ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " frame size (%lu) larger than stream size (%lu)\n", + count, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + goto Exit; + } + +#ifdef FT_DEBUG_MEMORY + /* assume `ft_debug_file_` and `ft_debug_lineno_` are already set */ + stream->base = (unsigned char*)ft_mem_qalloc( memory, + (FT_Long)count, + &error ); + if ( error ) + goto Exit; +#else + if ( FT_QALLOC( stream->base, count ) ) + goto Exit; +#endif + /* read it */ + read_bytes = stream->read( stream, stream->pos, + stream->base, count ); + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + FT_FREE( stream->base ); + error = FT_THROW( Invalid_Stream_Operation ); + } + + stream->cursor = stream->base; + stream->limit = FT_OFFSET( stream->cursor, count ); + stream->pos += read_bytes; + } + else + { + /* check current and new position */ + if ( stream->pos >= stream->size || + stream->size - stream->pos < count ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", + stream->pos, count, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + goto Exit; + } + + /* set cursor */ + stream->cursor = stream->base + stream->pos; + stream->limit = stream->cursor + count; + stream->pos += count; + } + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_ExitFrame( FT_Stream stream ) + { + /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ + /* that it is possible to access a frame of length 0 in */ + /* some weird fonts (usually, when accessing an array of */ + /* 0 records, like in some strange kern tables). */ + /* */ + /* In this case, the loader code handles the 0-length table */ + /* gracefully; however, stream.cursor is really set to 0 by the */ + /* FT_Stream_EnterFrame() call, and this is not an error. */ + + FT_TRACE7(( "FT_Stream_ExitFrame\n" )); + + FT_ASSERT( stream ); + + if ( stream->read ) + { + FT_Memory memory = stream->memory; + + +#ifdef FT_DEBUG_MEMORY + ft_mem_free( memory, stream->base ); + stream->base = NULL; +#else + FT_FREE( stream->base ); +#endif + } + + stream->cursor = NULL; + stream->limit = NULL; + } + + + FT_BASE_DEF( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ) + { + FT_Byte result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + if ( stream->cursor < stream->limit ) + result = *stream->cursor++; + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_GetUShort( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt16 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_USHORT( p ); + stream->cursor = p; + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_GetUShortLE( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt16 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_USHORT_LE( p ); + stream->cursor = p; + + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_GetUOffset( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt32 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 2 < stream->limit ) + result = FT_NEXT_UOFF3( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_GetULong( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt32 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_ULONG( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_GetULongLE( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt32 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_ULONG_LE( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, + FT_Error* error ) + { + FT_Byte result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) + goto Fail; + } + else + result = stream->base[stream->pos]; + } + else + goto Fail; + + stream->pos++; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadByte:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_ReadUShort( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p; + FT_UInt16 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_USHORT( p ); + } + else + goto Fail; + + stream->pos += 2; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadUShort:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_ReadUShortLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p; + FT_UInt16 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_USHORT_LE( p ); + } + else + goto Fail; + + stream->pos += 2; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadUShortLE:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_ULong ) + FT_Stream_ReadUOffset( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[3]; + FT_Byte* p; + FT_ULong result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 2 < stream->size ) + { + if ( stream->read ) + { + if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_UOFF3( p ); + } + else + goto Fail; + + stream->pos += 3; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadUOffset:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_ReadULong( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p; + FT_UInt32 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_ULONG( p ); + } + else + goto Fail; + + stream->pos += 4; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadULong:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_ReadULongLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p; + FT_UInt32 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_ULONG_LE( p ); + } + else + goto Fail; + + stream->pos += 4; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadULongLE:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ) + { + FT_Error error; + FT_Bool frame_accessed = 0; + FT_Byte* cursor; + + + if ( !fields ) + return FT_THROW( Invalid_Argument ); + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + + cursor = stream->cursor; + + error = FT_Err_Ok; + do + { + FT_ULong value; + FT_Int sign_shift; + FT_Byte* p; + + + switch ( fields->value ) + { + case ft_frame_start: /* access a new frame */ + error = FT_Stream_EnterFrame( stream, fields->offset ); + if ( error ) + goto Exit; + + frame_accessed = 1; + cursor = stream->cursor; + fields++; + continue; /* loop! */ + + case ft_frame_bytes: /* read a byte sequence */ + case ft_frame_skip: /* skip some bytes */ + { + FT_UInt len = fields->size; + + + if ( cursor + len > stream->limit ) + { + error = FT_THROW( Invalid_Stream_Operation ); + goto Exit; + } + + if ( fields->value == ft_frame_bytes ) + { + p = (FT_Byte*)structure + fields->offset; + FT_MEM_COPY( p, cursor, len ); + } + cursor += len; + fields++; + continue; + } + + case ft_frame_byte: + case ft_frame_schar: /* read a single byte */ + value = FT_NEXT_BYTE( cursor ); + sign_shift = 24; + break; + + case ft_frame_short_be: + case ft_frame_ushort_be: /* read a 2-byte big-endian short */ + value = FT_NEXT_USHORT( cursor ); + sign_shift = 16; + break; + + case ft_frame_short_le: + case ft_frame_ushort_le: /* read a 2-byte little-endian short */ + value = FT_NEXT_USHORT_LE( cursor ); + sign_shift = 16; + break; + + case ft_frame_long_be: + case ft_frame_ulong_be: /* read a 4-byte big-endian long */ + value = FT_NEXT_ULONG( cursor ); + sign_shift = 0; + break; + + case ft_frame_long_le: + case ft_frame_ulong_le: /* read a 4-byte little-endian long */ + value = FT_NEXT_ULONG_LE( cursor ); + sign_shift = 0; + break; + + case ft_frame_off3_be: + case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ + value = FT_NEXT_UOFF3( cursor ); + sign_shift = 8; + break; + + case ft_frame_off3_le: + case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ + value = FT_NEXT_UOFF3_LE( cursor ); + sign_shift = 8; + break; + + default: + /* otherwise, exit the loop */ + stream->cursor = cursor; + goto Exit; + } + + /* now, compute the signed value is necessary */ + if ( fields->value & FT_FRAME_OP_SIGNED ) + value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); + + /* finally, store the value in the object */ + + p = (FT_Byte*)structure + fields->offset; + switch ( fields->size ) + { + case ( 8 / FT_CHAR_BIT ): + *(FT_Byte*)p = (FT_Byte)value; + break; + + case ( 16 / FT_CHAR_BIT ): + *(FT_UShort*)p = (FT_UShort)value; + break; + + case ( 32 / FT_CHAR_BIT ): + *(FT_UInt32*)p = (FT_UInt32)value; + break; + + default: /* for 64-bit systems */ + *(FT_ULong*)p = (FT_ULong)value; + } + + /* go to next field */ + fields++; + } + while ( 1 ); + + Exit: + /* close the frame if it was opened by this read */ + if ( frame_accessed ) + FT_Stream_ExitFrame( stream ); + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftstroke.c b/vendor/freetype/src/base/ftstroke.c new file mode 100644 index 0000000..92f1e43 --- /dev/null +++ b/vendor/freetype/src/base/ftstroke.c @@ -0,0 +1,2403 @@ +/**************************************************************************** + * + * ftstroke.c + * + * FreeType path stroker (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include + + + /* declare an extern to access `ft_outline_glyph_class' globally */ + /* allocated in `ftglyph.c' */ + FT_CALLBACK_TABLE const FT_Glyph_Class ft_outline_glyph_class; + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + + + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_RIGHT + : FT_STROKER_BORDER_LEFT; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + + + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT + : FT_STROKER_BORDER_RIGHT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BEZIER COMPUTATIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 ) +#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 8 ) + +#define FT_EPSILON 2 + +#define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON ) + + + static FT_Pos + ft_pos_abs( FT_Pos x ) + { + return x >= 0 ? x : -x; + } + + + static void + ft_conic_split( FT_Vector* base ) + { + FT_Pos a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; + } + + + static FT_Bool + ft_conic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_out ) + { + FT_Vector d1, d2; + FT_Angle theta; + FT_Int close1, close2; + + + d1.x = base[1].x - base[2].x; + d1.y = base[1].y - base[2].y; + d2.x = base[0].x - base[1].x; + d2.y = base[0].y - base[1].y; + + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + + if ( close1 ) + { + if ( close2 ) + { + /* basically a point; */ + /* do nothing to retain original direction */ + } + else + { + *angle_in = + *angle_out = FT_Atan2( d2.x, d2.y ); + } + } + else /* !close1 */ + { + if ( close2 ) + { + *angle_in = + *angle_out = FT_Atan2( d1.x, d1.y ); + } + else + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d2.x, d2.y ); + } + } + + theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) ); + + return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD ); + } + + + static void + ft_cubic_split( FT_Vector* base ) + { + FT_Pos a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; + } + + + /* Return the average of `angle1' and `angle2'. */ + /* This gives correct result even if `angle1' and `angle2' */ + /* have opposite signs. */ + static FT_Angle + ft_angle_mean( FT_Angle angle1, + FT_Angle angle2 ) + { + return angle1 + FT_Angle_Diff( angle1, angle2 ) / 2; + } + + + static FT_Bool + ft_cubic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_mid, + FT_Angle *angle_out ) + { + FT_Vector d1, d2, d3; + FT_Angle theta1, theta2; + FT_Int close1, close2, close3; + + + d1.x = base[2].x - base[3].x; + d1.y = base[2].y - base[3].y; + d2.x = base[1].x - base[2].x; + d2.y = base[1].y - base[2].y; + d3.x = base[0].x - base[1].x; + d3.y = base[0].y - base[1].y; + + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y ); + + if ( close1 ) + { + if ( close2 ) + { + if ( close3 ) + { + /* basically a point; */ + /* do nothing to retain original direction */ + } + else /* !close3 */ + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + else /* !close2 */ + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d2.x, d2.y ); + } + else /* !close3 */ + { + *angle_in = + *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + } + else /* !close1 */ + { + if ( close2 ) + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d1.x, d1.y ); + } + else /* !close3 */ + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + *angle_mid = ft_angle_mean( *angle_in, *angle_out ); + } + } + else /* !close2 */ + { + if ( close3 ) + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = + *angle_out = FT_Atan2( d2.x, d2.y ); + } + else /* !close3 */ + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + } + + theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) ); + theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) ); + + return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD && + theta2 < FT_SMALL_CUBIC_THRESHOLD ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STROKE BORDERS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef enum FT_StrokeTags_ + { + FT_STROKE_TAG_ON = 1, /* on-curve point */ + FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ + FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ + FT_STROKE_TAG_END = 8 /* sub-path end */ + + } FT_StrokeTags; + +#define FT_STROKE_TAG_BEGIN_END ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END ) + + typedef struct FT_StrokeBorderRec_ + { + FT_UInt num_points; + FT_UInt max_points; + FT_Vector* points; + FT_Byte* tags; + FT_Bool movable; /* TRUE for ends of lineto borders */ + FT_Int start; /* index of current sub-path start point */ + FT_Memory memory; + FT_Bool valid; + + } FT_StrokeBorderRec, *FT_StrokeBorder; + + + static FT_Error + ft_stroke_border_grow( FT_StrokeBorder border, + FT_UInt new_points ) + { + FT_UInt old_max = border->max_points; + FT_UInt new_max = border->num_points + new_points; + FT_Error error = FT_Err_Ok; + + + if ( new_max > old_max ) + { + FT_UInt cur_max = old_max; + FT_Memory memory = border->memory; + + + while ( cur_max < new_max ) + cur_max += ( cur_max >> 1 ) + 16; + + if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) || + FT_RENEW_ARRAY( border->tags, old_max, cur_max ) ) + goto Exit; + + border->max_points = cur_max; + } + + Exit: + return error; + } + + + static void + ft_stroke_border_close( FT_StrokeBorder border, + FT_Bool reverse ) + { + FT_UInt start = (FT_UInt)border->start; + FT_UInt count = border->num_points; + + + FT_ASSERT( border->start >= 0 ); + + /* don't record empty paths! */ + if ( count <= start + 1U ) + border->num_points = start; + else + { + /* copy the last point to the start of this sub-path, since */ + /* it contains the `adjusted' starting coordinates */ + border->num_points = --count; + border->points[start] = border->points[count]; + border->tags[start] = border->tags[count]; + + if ( reverse ) + { + /* reverse the points */ + { + FT_Vector* vec1 = border->points + start + 1; + FT_Vector* vec2 = border->points + count - 1; + + + for ( ; vec1 < vec2; vec1++, vec2-- ) + { + FT_Vector tmp; + + + tmp = *vec1; + *vec1 = *vec2; + *vec2 = tmp; + } + } + + /* then the tags */ + { + FT_Byte* tag1 = border->tags + start + 1; + FT_Byte* tag2 = border->tags + count - 1; + + + for ( ; tag1 < tag2; tag1++, tag2-- ) + { + FT_Byte tmp; + + + tmp = *tag1; + *tag1 = *tag2; + *tag2 = tmp; + } + } + } + + border->tags[start ] |= FT_STROKE_TAG_BEGIN; + border->tags[count - 1] |= FT_STROKE_TAG_END; + } + + border->start = -1; + border->movable = FALSE; + } + + + static FT_Error + ft_stroke_border_lineto( FT_StrokeBorder border, + FT_Vector* to, + FT_Bool movable ) + { + FT_Error error = FT_Err_Ok; + + + FT_ASSERT( border->start >= 0 ); + + if ( border->movable ) + { + /* move last point */ + border->points[border->num_points - 1] = *to; + } + else + { + /* don't add zero-length lineto, but always add moveto */ + if ( border->num_points > (FT_UInt)border->start && + FT_IS_SMALL( border->points[border->num_points - 1].x - to->x ) && + FT_IS_SMALL( border->points[border->num_points - 1].y - to->y ) ) + return error; + + /* add one point */ + error = ft_stroke_border_grow( border, 1 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *to; + tag[0] = FT_STROKE_TAG_ON; + + border->num_points += 1; + } + } + border->movable = movable; + return error; + } + + + static FT_Error + ft_stroke_border_conicto( FT_StrokeBorder border, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error; + + + FT_ASSERT( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 2 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *control; + vec[1] = *to; + + tag[0] = 0; + tag[1] = FT_STROKE_TAG_ON; + + border->num_points += 2; + } + + border->movable = FALSE; + + return error; + } + + + static FT_Error + ft_stroke_border_cubicto( FT_StrokeBorder border, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error; + + + FT_ASSERT( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 3 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + + tag[0] = FT_STROKE_TAG_CUBIC; + tag[1] = FT_STROKE_TAG_CUBIC; + tag[2] = FT_STROKE_TAG_ON; + + border->num_points += 3; + } + + border->movable = FALSE; + + return error; + } + + +#define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 ) + + + static FT_Error + ft_stroke_border_arcto( FT_StrokeBorder border, + FT_Vector* center, + FT_Fixed radius, + FT_Angle angle_start, + FT_Angle angle_diff ) + { + FT_Fixed coef; + FT_Vector a0, a1, a2, a3; + FT_Int i, arcs = 1; + FT_Error error = FT_Err_Ok; + + + /* number of cubic arcs to draw */ + while ( angle_diff > FT_ARC_CUBIC_ANGLE * arcs || + -angle_diff > FT_ARC_CUBIC_ANGLE * arcs ) + arcs++; + + /* control tangents */ + coef = FT_Tan( angle_diff / ( 4 * arcs ) ); + coef += coef / 3; + + /* compute start and first control point */ + FT_Vector_From_Polar( &a0, radius, angle_start ); + a1.x = FT_MulFix( -a0.y, coef ); + a1.y = FT_MulFix( a0.x, coef ); + + a0.x += center->x; + a0.y += center->y; + a1.x += a0.x; + a1.y += a0.y; + + for ( i = 1; i <= arcs; i++ ) + { + /* compute end and second control point */ + FT_Vector_From_Polar( &a3, radius, + angle_start + i * angle_diff / arcs ); + a2.x = FT_MulFix( a3.y, coef ); + a2.y = FT_MulFix( -a3.x, coef ); + + a3.x += center->x; + a3.y += center->y; + a2.x += a3.x; + a2.y += a3.y; + + /* add cubic arc */ + error = ft_stroke_border_cubicto( border, &a1, &a2, &a3 ); + if ( error ) + break; + + /* a0 = a3; */ + a1.x = a3.x - a2.x + a3.x; + a1.y = a3.y - a2.y + a3.y; + } + + return error; + } + + + static FT_Error + ft_stroke_border_moveto( FT_StrokeBorder border, + FT_Vector* to ) + { + /* close current open path if any ? */ + if ( border->start >= 0 ) + ft_stroke_border_close( border, FALSE ); + + border->start = (FT_Int)border->num_points; + border->movable = FALSE; + + return ft_stroke_border_lineto( border, to, FALSE ); + } + + + static void + ft_stroke_border_init( FT_StrokeBorder border, + FT_Memory memory ) + { + border->memory = memory; + border->points = NULL; + border->tags = NULL; + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static void + ft_stroke_border_reset( FT_StrokeBorder border ) + { + border->num_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static void + ft_stroke_border_done( FT_StrokeBorder border ) + { + FT_Memory memory = border->memory; + + + FT_FREE( border->points ); + FT_FREE( border->tags ); + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static FT_Error + ft_stroke_border_get_counts( FT_StrokeBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_Error error = FT_Err_Ok; + FT_UInt num_points = 0; + FT_UInt num_contours = 0; + + FT_UInt count = border->num_points; + FT_Vector* point = border->points; + FT_Byte* tags = border->tags; + FT_Int in_contour = 0; + + + for ( ; count > 0; count--, num_points++, point++, tags++ ) + { + if ( tags[0] & FT_STROKE_TAG_BEGIN ) + { + if ( in_contour != 0 ) + goto Fail; + + in_contour = 1; + } + else if ( in_contour == 0 ) + goto Fail; + + if ( tags[0] & FT_STROKE_TAG_END ) + { + in_contour = 0; + num_contours++; + } + } + + if ( in_contour != 0 ) + goto Fail; + + border->valid = TRUE; + + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + + Fail: + num_points = 0; + num_contours = 0; + goto Exit; + } + + + static void + ft_stroke_border_export( FT_StrokeBorder border, + FT_Outline* outline ) + { + /* copy point locations */ + if ( border->num_points ) + FT_ARRAY_COPY( outline->points + outline->n_points, + border->points, + border->num_points ); + + /* copy tags */ + { + FT_UInt count = border->num_points; + FT_Byte* read = border->tags; + FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points; + + + for ( ; count > 0; count--, read++, write++ ) + { + if ( *read & FT_STROKE_TAG_ON ) + *write = FT_CURVE_TAG_ON; + else if ( *read & FT_STROKE_TAG_CUBIC ) + *write = FT_CURVE_TAG_CUBIC; + else + *write = FT_CURVE_TAG_CONIC; + } + } + + /* copy contours */ + { + FT_UInt count = border->num_points; + FT_Byte* tags = border->tags; + FT_Short* write = outline->contours + outline->n_contours; + FT_Short idx = (FT_Short)outline->n_points; + + + for ( ; count > 0; count--, tags++, idx++ ) + { + if ( *tags & FT_STROKE_TAG_END ) + { + *write++ = idx; + outline->n_contours++; + } + } + } + + outline->n_points += (short)border->num_points; + + FT_ASSERT( FT_Outline_Check( outline ) == 0 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STROKER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI ) + + typedef struct FT_StrokerRec_ + { + FT_Angle angle_in; /* direction into curr join */ + FT_Angle angle_out; /* direction out of join */ + FT_Vector center; /* current position */ + FT_Fixed line_length; /* length of last lineto */ + FT_Bool first_point; /* is this the start? */ + FT_Bool subpath_open; /* is the subpath open? */ + FT_Angle subpath_angle; /* subpath start direction */ + FT_Vector subpath_start; /* subpath start position */ + FT_Fixed subpath_line_length; /* subpath start lineto len */ + FT_Bool handle_wide_strokes; /* use wide strokes logic? */ + + FT_Stroker_LineCap line_cap; + FT_Stroker_LineJoin line_join; + FT_Stroker_LineJoin line_join_saved; + FT_Fixed miter_limit; + FT_Fixed radius; + + FT_StrokeBorderRec borders[2]; + FT_Library library; + + } FT_StrokerRec; + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ) + { + FT_Error error; /* assigned in FT_NEW */ + FT_Memory memory; + FT_Stroker stroker = NULL; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !astroker ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + if ( !FT_NEW( stroker ) ) + { + stroker->library = library; + + ft_stroke_border_init( &stroker->borders[0], memory ); + ft_stroke_border_init( &stroker->borders[1], memory ); + } + + *astroker = stroker; + + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ) + { + if ( !stroker ) + return; + + stroker->radius = radius; + stroker->line_cap = line_cap; + stroker->line_join = line_join; + stroker->miter_limit = miter_limit; + + /* ensure miter limit has sensible value */ + if ( stroker->miter_limit < 0x10000L ) + stroker->miter_limit = 0x10000L; + + /* save line join style: */ + /* line join style can be temporarily changed when stroking curves */ + stroker->line_join_saved = line_join; + + FT_Stroker_Rewind( stroker ); + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Rewind( FT_Stroker stroker ) + { + if ( stroker ) + { + ft_stroke_border_reset( &stroker->borders[0] ); + ft_stroke_border_reset( &stroker->borders[1] ); + } + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Done( FT_Stroker stroker ) + { + if ( stroker ) + { + FT_Memory memory = stroker->library->memory; + + + ft_stroke_border_done( &stroker->borders[0] ); + ft_stroke_border_done( &stroker->borders[1] ); + + stroker->library = NULL; + FT_FREE( stroker ); + } + } + + + /* create a circular arc at a corner or cap */ + static FT_Error + ft_stroker_arcto( FT_Stroker stroker, + FT_Int side ) + { + FT_Angle total, rotate; + FT_Fixed radius = stroker->radius; + FT_Error error = FT_Err_Ok; + FT_StrokeBorder border = stroker->borders + side; + + + rotate = FT_SIDE_TO_ROTATE( side ); + + total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( total == FT_ANGLE_PI ) + total = -rotate * 2; + + error = ft_stroke_border_arcto( border, + &stroker->center, + radius, + stroker->angle_in + rotate, + total ); + border->movable = FALSE; + return error; + } + + + /* add a cap at the end of an opened path */ + static FT_Error + ft_stroker_cap( FT_Stroker stroker, + FT_Angle angle, + FT_Int side ) + { + FT_Error error = FT_Err_Ok; + + + if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND ) + { + /* add a round cap */ + stroker->angle_in = angle; + stroker->angle_out = angle + FT_ANGLE_PI; + + error = ft_stroker_arcto( stroker, side ); + } + else + { + /* add a square or butt cap */ + FT_Vector middle, delta; + FT_Fixed radius = stroker->radius; + FT_StrokeBorder border = stroker->borders + side; + + + /* compute middle point and first angle point */ + FT_Vector_From_Polar( &middle, radius, angle ); + delta.x = side ? middle.y : -middle.y; + delta.y = side ? -middle.x : middle.x; + + if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) + { + middle.x += stroker->center.x; + middle.y += stroker->center.y; + } + else /* FT_STROKER_LINECAP_BUTT */ + { + middle.x = stroker->center.x; + middle.y = stroker->center.y; + } + + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* compute second angle point */ + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + + Exit: + return error; + } + + + /* process an inside corner, i.e. compute intersection */ + static FT_Error + ft_stroker_inside( FT_Stroker stroker, + FT_Int side, + FT_Fixed line_length ) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Angle phi, theta, rotate; + FT_Fixed length; + FT_Vector sigma = { 0, 0 }; + FT_Vector delta; + FT_Error error = FT_Err_Ok; + FT_Bool intersect; /* use intersection of lines? */ + + + rotate = FT_SIDE_TO_ROTATE( side ); + + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; + + /* Only intersect borders if between two lineto's and both */ + /* lines are long enough (line_length is zero for curves). */ + /* Also avoid U-turns of nearly 180 degree. */ + if ( !border->movable || line_length == 0 || + theta > 0x59C000 || theta < -0x59C000 ) + intersect = FALSE; + else + { + /* compute minimum required length of lines */ + FT_Fixed min_length; + + + FT_Vector_Unit( &sigma, theta ); + min_length = + ft_pos_abs( FT_MulDiv( stroker->radius, sigma.y, sigma.x ) ); + + intersect = FT_BOOL( min_length && + stroker->line_length >= min_length && + line_length >= min_length ); + } + + if ( !intersect ) + { + FT_Vector_From_Polar( &delta, stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + border->movable = FALSE; + } + else + { + /* compute median angle */ + phi = stroker->angle_in + theta + rotate; + + length = FT_DivFix( stroker->radius, sigma.x ); + + FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + } + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + + return error; + } + + + /* process an outside corner, i.e. compute bevel/miter/round */ + static FT_Error + ft_stroker_outside( FT_Stroker stroker, + FT_Int side, + FT_Fixed line_length ) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Error error; + FT_Angle rotate; + + + if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND ) + error = ft_stroker_arcto( stroker, side ); + else + { + /* this is a mitered (pointed) or beveled (truncated) corner */ + FT_Fixed radius = stroker->radius; + FT_Vector sigma = { 0, 0 }; + FT_Angle theta = 0, phi = 0; + FT_Bool bevel, fixed_bevel; + + + rotate = FT_SIDE_TO_ROTATE( side ); + + bevel = + FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_BEVEL ); + + fixed_bevel = + FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE ); + + /* check miter limit first */ + if ( !bevel ) + { + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; + + if ( theta == FT_ANGLE_PI2 ) + theta = -rotate; + + phi = stroker->angle_in + theta + rotate; + + FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta ); + + /* is miter limit exceeded? */ + if ( sigma.x < 0x10000L ) + { + /* don't create variable bevels for very small deviations; */ + /* FT_Sin(x) = 0 for x <= 57 */ + if ( fixed_bevel || ft_pos_abs( theta ) > 57 ) + bevel = TRUE; + } + } + + if ( bevel ) /* this is a bevel (broken angle) */ + { + if ( fixed_bevel ) + { + /* the outer corners are simply joined together */ + FT_Vector delta; + + + /* add bevel */ + FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + else /* variable bevel or clipped miter */ + { + /* the miter is truncated */ + FT_Vector middle, delta; + FT_Fixed coef; + + + /* compute middle point and first angle point */ + FT_Vector_From_Polar( &middle, + FT_MulFix( radius, stroker->miter_limit ), + phi ); + + coef = FT_DivFix( 0x10000L - sigma.x, sigma.y ); + delta.x = FT_MulFix( middle.y, coef ); + delta.y = FT_MulFix( -middle.x, coef ); + + middle.x += stroker->center.x; + middle.y += stroker->center.y; + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* compute second angle point */ + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* finally, add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + else /* this is a miter (intersection) */ + { + FT_Fixed length; + FT_Vector delta; + + + length = FT_MulDiv( stroker->radius, stroker->miter_limit, sigma.x ); + + FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* now add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + FT_Vector_From_Polar( &delta, + stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + + Exit: + return error; + } + + + static FT_Error + ft_stroker_process_corner( FT_Stroker stroker, + FT_Fixed line_length ) + { + FT_Error error = FT_Err_Ok; + FT_Angle turn; + FT_Int inside_side; + + + turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + + /* no specific corner processing is required if the turn is 0 */ + if ( turn == 0 ) + goto Exit; + + /* when we turn to the right, the inside side is 0 */ + /* otherwise, the inside side is 1 */ + inside_side = ( turn < 0 ); + + /* process the inside side */ + error = ft_stroker_inside( stroker, inside_side, line_length ); + if ( error ) + goto Exit; + + /* process the outside side */ + error = ft_stroker_outside( stroker, !inside_side, line_length ); + + Exit: + return error; + } + + + /* add two points to the left and right borders corresponding to the */ + /* start of the subpath */ + static FT_Error + ft_stroker_subpath_start( FT_Stroker stroker, + FT_Angle start_angle, + FT_Fixed line_length ) + { + FT_Vector delta; + FT_Vector point; + FT_Error error; + FT_StrokeBorder border; + + + FT_Vector_From_Polar( &delta, stroker->radius, + start_angle + FT_ANGLE_PI2 ); + + point.x = stroker->center.x + delta.x; + point.y = stroker->center.y + delta.y; + + border = stroker->borders; + error = ft_stroke_border_moveto( border, &point ); + if ( error ) + goto Exit; + + point.x = stroker->center.x - delta.x; + point.y = stroker->center.y - delta.y; + + border++; + error = ft_stroke_border_moveto( border, &point ); + + /* save angle, position, and line length for last join */ + /* (line_length is zero for curves) */ + stroker->subpath_angle = start_angle; + stroker->first_point = FALSE; + stroker->subpath_line_length = line_length; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_StrokeBorder border; + FT_Vector delta; + FT_Angle angle; + FT_Int side; + FT_Fixed line_length; + + + if ( !stroker || !to ) + return FT_THROW( Invalid_Argument ); + + delta.x = to->x - stroker->center.x; + delta.y = to->y - stroker->center.y; + + /* a zero-length lineto is a no-op; avoid creating a spurious corner */ + if ( delta.x == 0 && delta.y == 0 ) + goto Exit; + + /* compute length of line */ + line_length = FT_Vector_Length( &delta ); + + angle = FT_Atan2( delta.x, delta.y ); + FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 ); + + /* process corner if necessary */ + if ( stroker->first_point ) + { + /* This is the first segment of a subpath. We need to */ + /* add a point to each border at their respective starting */ + /* point locations. */ + error = ft_stroker_subpath_start( stroker, angle, line_length ); + if ( error ) + goto Exit; + } + else + { + /* process the current corner */ + stroker->angle_out = angle; + error = ft_stroker_process_corner( stroker, line_length ); + if ( error ) + goto Exit; + } + + /* now add a line segment to both the `inside' and `outside' paths */ + for ( border = stroker->borders, side = 1; side >= 0; side--, border++ ) + { + FT_Vector point; + + + point.x = to->x + delta.x; + point.y = to->y + delta.y; + + /* the ends of lineto borders are movable */ + error = ft_stroke_border_lineto( border, &point, TRUE ); + if ( error ) + goto Exit; + + delta.x = -delta.x; + delta.y = -delta.y; + } + + stroker->angle_in = angle; + stroker->center = *to; + stroker->line_length = line_length; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_Vector bez_stack[34]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 30; + FT_Bool first_arc = TRUE; + + + if ( !stroker || !control || !to ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* if all control points are coincident, this is a no-op; */ + /* avoid creating a spurious corner */ + if ( FT_IS_SMALL( stroker->center.x - control->x ) && + FT_IS_SMALL( stroker->center.y - control->y ) && + FT_IS_SMALL( control->x - to->x ) && + FT_IS_SMALL( control->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control; + arc[2] = stroker->center; + + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_out; + + + /* initialize with current direction */ + angle_in = angle_out = stroker->angle_in; + + if ( arc < limit && + !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + + ft_conic_split( arc ); + arc += 2; + continue; + } + + if ( first_arc ) + { + first_arc = FALSE; + + /* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + FT_SMALL_CONIC_THRESHOLD / 4 ) + { + /* if the deviation from one arc to the next is too great, */ + /* add a round corner */ + stroker->center = arc[2]; + stroker->angle_out = angle_in; + stroker->line_join = FT_STROKER_LINEJOIN_ROUND; + + error = ft_stroker_process_corner( stroker, 0 ); + + /* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + + if ( error ) + goto Exit; + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + FT_Vector ctrl, end; + FT_Angle theta, phi, rotate, alpha0 = 0; + FT_Fixed length; + FT_StrokeBorder border; + FT_Int side; + + + theta = FT_Angle_Diff( angle_in, angle_out ) / 2; + phi = angle_in + theta; + length = FT_DivFix( stroker->radius, FT_Cos( theta ) ); + + /* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = FT_Atan2( arc[0].x - arc[2].x, arc[0].y - arc[2].y ); + + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); + + /* compute control point */ + FT_Vector_From_Polar( &ctrl, length, phi + rotate ); + ctrl.x += arc[1].x; + ctrl.y += arc[1].y; + + /* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + if ( stroker->handle_wide_strokes ) + { + FT_Vector start; + FT_Angle alpha1; + + + /* determine whether the border radius is greater than the */ + /* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + + alpha1 = FT_Atan2( end.x - start.x, end.y - start.y ); + + /* is the direction of the border arc opposite to */ + /* that of the original arc? */ + if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) > + FT_ANGLE_PI / 2 ) + { + FT_Angle beta, gamma; + FT_Vector bvec, delta; + FT_Fixed blen, sinA, sinB, alen; + + + /* use the sine rule to find the intersection point */ + beta = FT_Atan2( arc[2].x - start.x, arc[2].y - start.y ); + gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + + blen = FT_Vector_Length( &bvec ); + + sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( FT_Sin( beta - gamma ) ); + + alen = FT_MulDiv( blen, sinA, sinB ); + + FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; + + /* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_conicto( border, &ctrl, &start ); + if ( error ) + goto Exit; + /* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + + continue; + } + + /* else fall through */ + } + + /* simply add an arc */ + error = ft_stroke_border_conicto( border, &ctrl, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 2; + + stroker->angle_in = angle_out; + } + + stroker->center = *to; + stroker->line_length = 0; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_Vector bez_stack[37]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 32; + FT_Bool first_arc = TRUE; + + + if ( !stroker || !control1 || !control2 || !to ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* if all control points are coincident, this is a no-op; */ + /* avoid creating a spurious corner */ + if ( FT_IS_SMALL( stroker->center.x - control1->x ) && + FT_IS_SMALL( stroker->center.y - control1->y ) && + FT_IS_SMALL( control1->x - control2->x ) && + FT_IS_SMALL( control1->y - control2->y ) && + FT_IS_SMALL( control2->x - to->x ) && + FT_IS_SMALL( control2->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control2; + arc[2] = *control1; + arc[3] = stroker->center; + + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_mid, angle_out; + + + /* initialize with current direction */ + angle_in = angle_out = angle_mid = stroker->angle_in; + + if ( arc < limit && + !ft_cubic_is_small_enough( arc, &angle_in, + &angle_mid, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + + ft_cubic_split( arc ); + arc += 3; + continue; + } + + if ( first_arc ) + { + first_arc = FALSE; + + /* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + FT_SMALL_CUBIC_THRESHOLD / 4 ) + { + /* if the deviation from one arc to the next is too great, */ + /* add a round corner */ + stroker->center = arc[3]; + stroker->angle_out = angle_in; + stroker->line_join = FT_STROKER_LINEJOIN_ROUND; + + error = ft_stroker_process_corner( stroker, 0 ); + + /* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + + if ( error ) + goto Exit; + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + FT_Vector ctrl1, ctrl2, end; + FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0; + FT_Fixed length1, length2; + FT_StrokeBorder border; + FT_Int side; + + + theta1 = FT_Angle_Diff( angle_in, angle_mid ) / 2; + theta2 = FT_Angle_Diff( angle_mid, angle_out ) / 2; + phi1 = ft_angle_mean( angle_in, angle_mid ); + phi2 = ft_angle_mean( angle_mid, angle_out ); + length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) ); + length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) ); + + /* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = FT_Atan2( arc[0].x - arc[3].x, arc[0].y - arc[3].y ); + + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); + + /* compute control points */ + FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate ); + ctrl1.x += arc[2].x; + ctrl1.y += arc[2].y; + + FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate ); + ctrl2.x += arc[1].x; + ctrl2.y += arc[1].y; + + /* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + if ( stroker->handle_wide_strokes ) + { + FT_Vector start; + FT_Angle alpha1; + + + /* determine whether the border radius is greater than the */ + /* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + + alpha1 = FT_Atan2( end.x - start.x, end.y - start.y ); + + /* is the direction of the border arc opposite to */ + /* that of the original arc? */ + if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) > + FT_ANGLE_PI / 2 ) + { + FT_Angle beta, gamma; + FT_Vector bvec, delta; + FT_Fixed blen, sinA, sinB, alen; + + + /* use the sine rule to find the intersection point */ + beta = FT_Atan2( arc[3].x - start.x, arc[3].y - start.y ); + gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + + blen = FT_Vector_Length( &bvec ); + + sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( FT_Sin( beta - gamma ) ); + + alen = FT_MulDiv( blen, sinA, sinB ); + + FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; + + /* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_cubicto( border, + &ctrl2, + &ctrl1, + &start ); + if ( error ) + goto Exit; + /* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + + continue; + } + + /* else fall through */ + } + + /* simply add an arc */ + error = ft_stroke_border_cubicto( border, &ctrl1, &ctrl2, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 3; + + stroker->angle_in = angle_out; + } + + stroker->center = *to; + stroker->line_length = 0; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ) + { + if ( !stroker || !to ) + return FT_THROW( Invalid_Argument ); + + /* We cannot process the first point, because there is not enough */ + /* information regarding its corner/cap. The latter will be processed */ + /* in the `FT_Stroker_EndSubPath' routine. */ + /* */ + stroker->first_point = TRUE; + stroker->center = *to; + stroker->subpath_open = open; + + /* Determine if we need to check whether the border radius is greater */ + /* than the radius of curvature of a curve, to handle this case */ + /* specially. This is only required if bevel joins or butt caps may */ + /* be created, because round & miter joins and round & square caps */ + /* cover the negative sector created with wide strokes. */ + stroker->handle_wide_strokes = + FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_ROUND || + ( stroker->subpath_open && + stroker->line_cap == FT_STROKER_LINECAP_BUTT ) ); + + /* record the subpath start point for each border */ + stroker->subpath_start = *to; + + stroker->angle_in = 0; + + return FT_Err_Ok; + } + + + static FT_Error + ft_stroker_add_reverse_left( FT_Stroker stroker, + FT_Bool open ) + { + FT_StrokeBorder right = stroker->borders + 0; + FT_StrokeBorder left = stroker->borders + 1; + FT_Int new_points; + FT_Error error = FT_Err_Ok; + + + FT_ASSERT( left->start >= 0 ); + + new_points = (FT_Int)left->num_points - left->start; + if ( new_points > 0 ) + { + error = ft_stroke_border_grow( right, (FT_UInt)new_points ); + if ( error ) + goto Exit; + + { + FT_Vector* dst_point = right->points + right->num_points; + FT_Byte* dst_tag = right->tags + right->num_points; + FT_Vector* src_point = left->points + left->num_points - 1; + FT_Byte* src_tag = left->tags + left->num_points - 1; + + + while ( src_point >= left->points + left->start ) + { + *dst_point = *src_point; + *dst_tag = *src_tag; + + if ( open ) + dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END; + else + { + FT_Byte ttag = + (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END ); + + + /* switch begin/end tags if necessary */ + if ( ttag == FT_STROKE_TAG_BEGIN || + ttag == FT_STROKE_TAG_END ) + dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END; + } + + src_point--; + src_tag--; + dst_point++; + dst_tag++; + } + } + + left->num_points = (FT_UInt)left->start; + right->num_points += (FT_UInt)new_points; + + right->movable = FALSE; + left->movable = FALSE; + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + /* there's a lot of magic in this function! */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ) + { + FT_Error error = FT_Err_Ok; + + + if ( !stroker ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( stroker->subpath_open ) + { + FT_StrokeBorder right = stroker->borders; + + + /* All right, this is an opened path, we need to add a cap between */ + /* right & left, add the reverse of left, then add a final cap */ + /* between left & right. */ + error = ft_stroker_cap( stroker, stroker->angle_in, 0 ); + if ( error ) + goto Exit; + + /* add reversed points from `left' to `right' */ + error = ft_stroker_add_reverse_left( stroker, TRUE ); + if ( error ) + goto Exit; + + /* now add the final cap */ + stroker->center = stroker->subpath_start; + error = ft_stroker_cap( stroker, + stroker->subpath_angle + FT_ANGLE_PI, 0 ); + if ( error ) + goto Exit; + + /* Now end the right subpath accordingly. The left one is */ + /* rewind and doesn't need further processing. */ + ft_stroke_border_close( right, FALSE ); + } + else + { + /* close the path if needed */ + if ( !FT_IS_SMALL( stroker->center.x - stroker->subpath_start.x ) || + !FT_IS_SMALL( stroker->center.y - stroker->subpath_start.y ) ) + { + error = FT_Stroker_LineTo( stroker, &stroker->subpath_start ); + if ( error ) + goto Exit; + } + + /* process the corner */ + stroker->angle_out = stroker->subpath_angle; + + error = ft_stroker_process_corner( stroker, + stroker->subpath_line_length ); + if ( error ) + goto Exit; + + /* then end our two subpaths */ + ft_stroke_border_close( stroker->borders + 0, FALSE ); + ft_stroke_border_close( stroker->borders + 1, TRUE ); + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt num_points = 0, num_contours = 0; + FT_Error error; + + + if ( !stroker || border > 1 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = ft_stroke_border_get_counts( stroker->borders + border, + &num_points, &num_contours ); + Exit: + if ( anum_points ) + *anum_points = num_points; + + if ( anum_contours ) + *anum_contours = num_contours; + + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt count1, count2, num_points = 0; + FT_UInt count3, count4, num_contours = 0; + FT_Error error; + + + if ( !stroker ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = ft_stroke_border_get_counts( stroker->borders + 0, + &count1, &count2 ); + if ( error ) + goto Exit; + + error = ft_stroke_border_get_counts( stroker->borders + 1, + &count3, &count4 ); + if ( error ) + goto Exit; + + num_points = count1 + count3; + num_contours = count2 + count4; + + Exit: + if ( anum_points ) + *anum_points = num_points; + + if ( anum_contours ) + *anum_contours = num_contours; + + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ) + { + if ( !stroker || !outline ) + return; + + if ( border == FT_STROKER_BORDER_LEFT || + border == FT_STROKER_BORDER_RIGHT ) + { + FT_StrokeBorder sborder = & stroker->borders[border]; + + + if ( sborder->valid ) + ft_stroke_border_export( sborder, outline ); + } + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ) + { + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline ); + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline ); + } + + + /* documentation is in ftstroke.h */ + + /* + * The following is very similar to FT_Outline_Decompose, except + * that we do support opened paths, and do not scale the outline. + */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + FT_Error error; + + FT_Int n; /* index of contour in outline */ + FT_Int first; /* index of first point in contour */ + FT_Int last; /* index of last point in contour */ + + FT_Int tag; /* current point's state */ + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !stroker ) + return FT_THROW( Invalid_Argument ); + + FT_Stroker_Rewind( stroker ); + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + first = last + 1; + last = outline->contours[n]; + + /* skip empty points; we don't stroke these */ + if ( last <= first ) + continue; + + limit = outline->points + last; + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* First point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + } + point--; + tags--; + } + + error = FT_Stroker_BeginSubPath( stroker, &v_start, opened ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = point->x; + vec.y = point->y; + + error = FT_Stroker_LineTo( stroker, &vec ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = point->x; + v_control.y = point->y; + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec = point[0]; + + if ( tag == FT_CURVE_TAG_ON ) + { + error = FT_Stroker_ConicTo( stroker, &v_control, &vec ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = FT_Stroker_ConicTo( stroker, &v_control, &v_start ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1 = point[-2]; + vec2 = point[-1]; + + if ( point <= limit ) + { + FT_Vector vec; + + + vec = point[0]; + + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec ); + if ( error ) + goto Exit; + continue; + } + + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start ); + goto Close; + } + } + } + + Close: + if ( error ) + goto Exit; + + /* don't try to end the path if no segments have been generated */ + if ( !stroker->first_point ) + { + error = FT_Stroker_EndSubPath( stroker ); + if ( error ) + goto Exit; + } + } + + return FT_Err_Ok; + + Exit: + return error; + + Invalid_Outline: + return FT_THROW( Invalid_Outline ); + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_Glyph glyph = NULL; + + + if ( !pglyph ) + goto Exit; + + glyph = *pglyph; + if ( !glyph || glyph->clazz != &ft_outline_glyph_class ) + goto Exit; + + { + FT_Glyph copy; + + + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + + glyph = copy; + } + + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + + + error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); + if ( error ) + goto Fail; + + FT_Stroker_GetCounts( stroker, &num_points, &num_contours ); + + FT_Outline_Done( glyph->library, outline ); + + error = FT_Outline_New( glyph->library, + num_points, + (FT_Int)num_contours, + outline ); + if ( error ) + goto Fail; + + outline->n_points = 0; + outline->n_contours = 0; + + FT_Stroker_Export( stroker, outline ); + } + + if ( destroy ) + FT_Done_Glyph( *pglyph ); + + *pglyph = glyph; + goto Exit; + + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + + if ( !destroy ) + *pglyph = NULL; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_Glyph glyph = NULL; + + + if ( !pglyph ) + goto Exit; + + glyph = *pglyph; + if ( !glyph || glyph->clazz != &ft_outline_glyph_class ) + goto Exit; + + { + FT_Glyph copy; + + + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + + glyph = copy; + } + + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph; + FT_StrokerBorder border; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + + + border = FT_Outline_GetOutsideBorder( outline ); + if ( inside ) + { + if ( border == FT_STROKER_BORDER_LEFT ) + border = FT_STROKER_BORDER_RIGHT; + else + border = FT_STROKER_BORDER_LEFT; + } + + error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); + if ( error ) + goto Fail; + + FT_Stroker_GetBorderCounts( stroker, border, + &num_points, &num_contours ); + + FT_Outline_Done( glyph->library, outline ); + + error = FT_Outline_New( glyph->library, + num_points, + (FT_Int)num_contours, + outline ); + if ( error ) + goto Fail; + + outline->n_points = 0; + outline->n_contours = 0; + + FT_Stroker_ExportBorder( stroker, border, outline ); + } + + if ( destroy ) + FT_Done_Glyph( *pglyph ); + + *pglyph = glyph; + goto Exit; + + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + + if ( !destroy ) + *pglyph = NULL; + + Exit: + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftsynth.c b/vendor/freetype/src/base/ftsynth.c new file mode 100644 index 0000000..f32edd3 --- /dev/null +++ b/vendor/freetype/src/base/ftsynth.c @@ -0,0 +1,180 @@ +/**************************************************************************** + * + * ftsynth.c + * + * FreeType synthesizing code for emboldening and slanting (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT synth + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL OBLIQUING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ) + { + /* Value '0x0366A' corresponds to a shear angle of about 12 degrees. */ + FT_GlyphSlot_Slant( slot, 0x0366A, 0 ); + } + + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Slant( FT_GlyphSlot slot, + FT_Fixed xslant, + FT_Fixed yslant ) + { + FT_Matrix transform; + FT_Outline* outline; + + + if ( !slot ) + return; + + outline = &slot->outline; + + /* only oblique outline glyphs */ + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + return; + + /* we don't touch the advance width */ + + /* For italic, simply apply a shear transform */ + transform.xx = 0x10000L; + transform.yx = -yslant; + + transform.xy = xslant; + transform.yy = 0x10000L; + + FT_Outline_Transform( outline, &transform ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL EMBOLDENING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ) + { + FT_GlyphSlot_AdjustWeight( slot, 0x0AAA, 0x0AAA ); + } + + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot, + FT_Fixed xdelta, + FT_Fixed ydelta ) + { + FT_Library library; + FT_Size size; + FT_Error error; + FT_Pos xstr, ystr; + + + if ( !slot ) + return; + + library = slot->library; + size = slot->face->size; + + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE && + slot->format != FT_GLYPH_FORMAT_BITMAP ) + return; + + /* express deltas in pixels in 26.6 format */ + xstr = (FT_Pos)size->metrics.x_ppem * xdelta / 1024; + ystr = (FT_Pos)size->metrics.y_ppem * ydelta / 1024; + + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + FT_Outline_EmboldenXY( &slot->outline, xstr, ystr ); + + else /* slot->format == FT_GLYPH_FORMAT_BITMAP */ + { + /* round to full pixels */ + xstr &= ~63; + if ( xstr == 0 ) + xstr = 1 << 6; + ystr &= ~63; + + /* + * XXX: overflow check for 16-bit system, for compatibility + * with FT_GlyphSlot_Embolden() since FreeType 2.1.10. + * unfortunately, this function return no informations + * about the cause of error. + */ + if ( ( ystr >> 6 ) > FT_INT_MAX || ( ystr >> 6 ) < FT_INT_MIN ) + { + FT_TRACE1(( "FT_GlyphSlot_Embolden:" )); + FT_TRACE1(( "too strong emboldening parameter ystr=%ld\n", ystr )); + return; + } + error = FT_GlyphSlot_Own_Bitmap( slot ); + if ( error ) + return; + + error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr ); + if ( error ) + return; + } + + if ( slot->advance.x ) + slot->advance.x += xstr; + + if ( slot->advance.y ) + slot->advance.y += ystr; + + slot->metrics.width += xstr; + slot->metrics.height += ystr; + slot->metrics.horiAdvance += xstr; + slot->metrics.vertAdvance += ystr; + slot->metrics.horiBearingY += ystr; + + /* XXX: 16-bit overflow case must be excluded before here */ + if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + slot->bitmap_top += (FT_Int)( ystr >> 6 ); + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftsystem.c b/vendor/freetype/src/base/ftsystem.c new file mode 100644 index 0000000..61c99e3 --- /dev/null +++ b/vendor/freetype/src/base/ftsystem.c @@ -0,0 +1,338 @@ +/**************************************************************************** + * + * ftsystem.c + * + * ANSI-specific FreeType low-level system interface (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file contains the default interface used by FreeType to access + * low-level, i.e. memory management, i/o access as well as thread + * synchronisation. It can be replaced by user-specific routines if + * necessary. + * + */ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * MEMORY MANAGEMENT INTERFACE + * + */ + + /************************************************************************** + * + * It is not necessary to do any error checking for the + * allocation-related functions. This will be done by the higher level + * routines like ft_mem_alloc() or ft_mem_realloc(). + * + */ + + + /************************************************************************** + * + * @Function: + * ft_alloc + * + * @Description: + * The memory allocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * size :: + * The requested size in bytes. + * + * @Return: + * The address of newly allocated block. + */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return ft_smalloc( (size_t)size ); + } + + + /************************************************************************** + * + * @Function: + * ft_realloc + * + * @Description: + * The memory reallocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * cur_size :: + * The current size of the allocated memory block. + * + * new_size :: + * The newly requested size in bytes. + * + * block :: + * The current address of the block in memory. + * + * @Return: + * The address of the reallocated memory block. + */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return ft_srealloc( block, (size_t)new_size ); + } + + + /************************************************************************** + * + * @Function: + * ft_free + * + * @Description: + * The memory release function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * block :: + * The address of block in memory to be freed. + */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + ft_sfree( block ); + } + + + /************************************************************************** + * + * RESOURCE MANAGEMENT INTERFACE + * + */ + +#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer ) + + + /************************************************************************** + * + * @Function: + * ft_ansi_stream_close + * + * @Description: + * The function to close a stream. + * + * @Input: + * stream :: + * A pointer to the stream object. + */ + FT_CALLBACK_DEF( void ) + ft_ansi_stream_close( FT_Stream stream ) + { + ft_fclose( STREAM_FILE( stream ) ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /************************************************************************** + * + * @Function: + * ft_ansi_stream_io + * + * @Description: + * The function to open a stream. + * + * @Input: + * stream :: + * A pointer to the stream object. + * + * offset :: + * The position in the data stream to start reading. + * + * buffer :: + * The address of buffer to store the read data. + * + * count :: + * The number of bytes to read from the stream. + * + * @Return: + * The number of bytes actually read. If `count' is zero (that is, + * the function is used for seeking), a non-zero return value + * indicates an error. + */ + FT_CALLBACK_DEF( unsigned long ) + ft_ansi_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_FILE* file; + + + if ( offset > stream->size && !count ) + return 1; + + file = STREAM_FILE( stream ); + + if ( stream->pos != offset ) + ft_fseek( file, (long)offset, SEEK_SET ); + + /* Avoid calling `fread` with `buffer=NULL` and `count=0`, */ + /* which is undefined behaviour. */ + if ( !count ) + return 0; + + return (unsigned long)ft_fread( buffer, 1, count, file ); + } + + + /* documentation is in ftstream.h */ + + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + FT_FILE* file; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + + stream->descriptor.pointer = NULL; + stream->pathname.pointer = (char*)filepathname; + stream->base = NULL; + stream->pos = 0; + stream->read = NULL; + stream->close = NULL; + + file = ft_fopen( filepathname, "rb" ); + if ( !file ) + { + FT_ERROR(( "FT_Stream_Open:" + " could not open `%s'\n", filepathname )); + + return FT_THROW( Cannot_Open_Resource ); + } + + ft_fseek( file, 0, SEEK_END ); + stream->size = (unsigned long)ft_ftell( file ); + if ( !stream->size ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " opened `%s' but zero-sized\n", filepathname )); + ft_fclose( file ); + return FT_THROW( Cannot_Open_Stream ); + } + ft_fseek( file, 0, SEEK_SET ); + + stream->descriptor.pointer = file; + stream->read = ft_ansi_stream_io; + stream->close = ft_ansi_stream_close; + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + } + +#endif /* !FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)ft_smalloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = NULL; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif + ft_sfree( memory ); + } + + +/* END */ diff --git a/vendor/freetype/src/base/fttrigon.c b/vendor/freetype/src/base/fttrigon.c new file mode 100644 index 0000000..2dd2c34 --- /dev/null +++ b/vendor/freetype/src/base/fttrigon.c @@ -0,0 +1,517 @@ +/**************************************************************************** + * + * fttrigon.c + * + * FreeType trigonometric functions (body). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This is a fixed-point CORDIC implementation of trigonometric + * functions as well as transformations between Cartesian and polar + * coordinates. The angles are represented as 16.16 fixed-point values + * in degrees, i.e., the angular resolution is 2^-16 degrees. Note that + * only vectors longer than 2^16*180/pi (or at least 22 bits) on a + * discrete Cartesian grid can have the same or better angular + * resolution. Therefore, to maintain this precision, some functions + * require an interim upscaling of the vectors, whereas others operate + * with 24-bit long vectors directly. + * + */ + +#include +#include +#include + + + /* the Cordic shrink factor 0.858785336480436 * 2^32 */ +#define FT_TRIG_SCALE 0xDBD95B16UL + + /* the highest bit in overflow-safe vector components, */ + /* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ +#define FT_TRIG_SAFE_MSB 29 + + /* this table was generated for FT_PI = 180L << 16, i.e. degrees */ +#define FT_TRIG_MAX_ITERS 23 + + static const FT_Angle + ft_trig_arctan_table[] = + { + 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, + 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, + 57L, 29L, 14L, 7L, 4L, 2L, 1L + }; + + +#ifdef FT_INT64 + + /* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Int s = 1; + + + if ( val < 0 ) + { + val = -val; + s = -1; + } + + /* 0x40000000 comes from regression analysis between true */ + /* and CORDIC hypotenuse, so it minimizes the error */ + val = (FT_Fixed)( + ( (FT_UInt64)val * FT_TRIG_SCALE + 0x40000000UL ) >> 32 ); + + return s < 0 ? -val : val; + } + +#else /* !FT_INT64 */ + + /* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Int s = 1; + FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; + + + if ( val < 0 ) + { + val = -val; + s = -1; + } + + lo1 = (FT_UInt32)val & 0x0000FFFFU; + hi1 = (FT_UInt32)val >> 16; + lo2 = FT_TRIG_SCALE & 0x0000FFFFU; + hi2 = FT_TRIG_SCALE >> 16; + + lo = lo1 * lo2; + i1 = lo1 * hi2; + i2 = lo2 * hi1; + hi = hi1 * hi2; + + /* Check carry overflow of i1 + i2 */ + i1 += i2; + hi += (FT_UInt32)( i1 < i2 ) << 16; + + hi += i1 >> 16; + i1 = i1 << 16; + + /* Check carry overflow of i1 + lo */ + lo += i1; + hi += ( lo < i1 ); + + /* 0x40000000 comes from regression analysis between true */ + /* and CORDIC hypotenuse, so it minimizes the error */ + + /* Check carry overflow of lo + 0x40000000 */ + lo += 0x40000000UL; + hi += ( lo < 0x40000000UL ); + + val = (FT_Fixed)hi; + + return s < 0 ? -val : val; + } + +#endif /* !FT_INT64 */ + + + /* undefined and never called for zero vector */ + static FT_Int + ft_trig_prenorm( FT_Vector* vec ) + { + FT_Pos x, y; + FT_Int shift; + + + x = vec->x; + y = vec->y; + + shift = FT_MSB( (FT_UInt32)( FT_ABS( x ) | FT_ABS( y ) ) ); + + if ( shift <= FT_TRIG_SAFE_MSB ) + { + shift = FT_TRIG_SAFE_MSB - shift; + vec->x = (FT_Pos)( (FT_ULong)x << shift ); + vec->y = (FT_Pos)( (FT_ULong)y << shift ); + } + else + { + shift -= FT_TRIG_SAFE_MSB; + vec->x = x >> shift; + vec->y = y >> shift; + shift = -shift; + } + + return shift; + } + + + static void + ft_trig_pseudo_rotate( FT_Vector* vec, + FT_Angle theta ) + { + FT_Int i; + FT_Fixed x, y, xtemp, b; + const FT_Angle *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Rotate inside [-PI/4,PI/4] sector */ + while ( theta < -FT_ANGLE_PI4 ) + { + xtemp = y; + y = -x; + x = xtemp; + theta += FT_ANGLE_PI2; + } + + while ( theta > FT_ANGLE_PI4 ) + { + xtemp = -y; + y = x; + x = xtemp; + theta -= FT_ANGLE_PI2; + } + + arctanptr = ft_trig_arctan_table; + + /* Pseudorotations, with right shifts */ + for ( i = 1, b = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++ ) + { + if ( theta < 0 ) + { + xtemp = x + ( ( y + b ) >> i ); + y = y - ( ( x + b ) >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( ( y + b ) >> i ); + y = y + ( ( x + b ) >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } + + vec->x = x; + vec->y = y; + } + + + static void + ft_trig_pseudo_polarize( FT_Vector* vec ) + { + FT_Angle theta; + FT_Int i; + FT_Fixed x, y, xtemp, b; + const FT_Angle *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Get the vector into [-PI/4,PI/4] sector */ + if ( y > x ) + { + if ( y > -x ) + { + theta = FT_ANGLE_PI2; + xtemp = y; + y = -x; + x = xtemp; + } + else + { + theta = y > 0 ? FT_ANGLE_PI : -FT_ANGLE_PI; + x = -x; + y = -y; + } + } + else + { + if ( y < -x ) + { + theta = -FT_ANGLE_PI2; + xtemp = -y; + y = x; + x = xtemp; + } + else + { + theta = 0; + } + } + + arctanptr = ft_trig_arctan_table; + + /* Pseudorotations, with right shifts */ + for ( i = 1, b = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++ ) + { + if ( y > 0 ) + { + xtemp = x + ( ( y + b ) >> i ); + y = y - ( ( x + b ) >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( ( y + b ) >> i ); + y = y + ( ( x + b ) >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } + + /* round theta to acknowledge its error that mostly comes */ + /* from accumulated rounding errors in the arctan table */ + if ( theta >= 0 ) + theta = FT_PAD_ROUND( theta, 16 ); + else + theta = -FT_PAD_ROUND( -theta, 16 ); + + vec->x = x; + vec->y = theta; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Cos( FT_Angle angle ) + { + FT_Vector v; + + + FT_Vector_Unit( &v, angle ); + + return v.x; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Sin( FT_Angle angle ) + { + FT_Vector v; + + + FT_Vector_Unit( &v, angle ); + + return v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Tan( FT_Angle angle ) + { + FT_Vector v = { 1 << 24, 0 }; + + + ft_trig_pseudo_rotate( &v, angle ); + + return FT_DivFix( v.y, v.x ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Angle ) + FT_Atan2( FT_Fixed dx, + FT_Fixed dy ) + { + FT_Vector v; + + + if ( dx == 0 && dy == 0 ) + return 0; + + v.x = dx; + v.y = dy; + ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + return v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ) + { + if ( !vec ) + return; + + vec->x = FT_TRIG_SCALE >> 8; + vec->y = 0; + ft_trig_pseudo_rotate( vec, angle ); + vec->x = ( vec->x + 0x80L ) >> 8; + vec->y = ( vec->y + 0x80L ) >> 8; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ) + { + FT_Int shift; + FT_Vector v; + + + if ( !vec || !angle ) + return; + + v = *vec; + + if ( v.x == 0 && v.y == 0 ) + return; + + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_rotate( &v, angle ); + v.x = ft_trig_downscale( v.x ); + v.y = ft_trig_downscale( v.y ); + + if ( shift > 0 ) + { + FT_Int32 half = (FT_Int32)1L << ( shift - 1 ); + + + vec->x = ( v.x + half - ( v.x < 0 ) ) >> shift; + vec->y = ( v.y + half - ( v.y < 0 ) ) >> shift; + } + else + { + shift = -shift; + vec->x = (FT_Pos)( (FT_ULong)v.x << shift ); + vec->y = (FT_Pos)( (FT_ULong)v.y << shift ); + } + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ) + { + FT_Int shift; + FT_Vector v; + + + if ( !vec ) + return 0; + + v = *vec; + + /* handle trivial cases */ + if ( v.x == 0 ) + { + return FT_ABS( v.y ); + } + else if ( v.y == 0 ) + { + return FT_ABS( v.x ); + } + + /* general case */ + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + if ( shift > 0 ) + return ( v.x + ( 1L << ( shift - 1 ) ) ) >> shift; + + return (FT_Fixed)( (FT_UInt32)v.x << -shift ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ) + { + FT_Int shift; + FT_Vector v; + + + if ( !vec || !length || !angle ) + return; + + v = *vec; + + if ( v.x == 0 && v.y == 0 ) + return; + + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + *length = shift >= 0 ? ( v.x >> shift ) + : (FT_Fixed)( (FT_UInt32)v.x << -shift ); + *angle = v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ) + { + if ( !vec ) + return; + + vec->x = length; + vec->y = 0; + + FT_Vector_Rotate( vec, angle ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ) + { + FT_Angle delta = angle2 - angle1; + + + while ( delta <= -FT_ANGLE_PI ) + delta += FT_ANGLE_2PI; + + while ( delta > FT_ANGLE_PI ) + delta -= FT_ANGLE_2PI; + + return delta; + } + + +/* END */ diff --git a/vendor/freetype/src/base/fttype1.c b/vendor/freetype/src/base/fttype1.c new file mode 100644 index 0000000..637c5cf --- /dev/null +++ b/vendor/freetype/src/base/fttype1.c @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * fttype1.c + * + * FreeType utility file for PS names support (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + FT_Error error; + FT_Service_PsInfo service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !afont_info ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_info ) + error = service->ps_get_font_info( face, afont_info ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ) + { + FT_Int result = 0; + FT_Service_PsInfo service; + + + if ( face ) + { + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_has_glyph_names ) + result = service->ps_has_glyph_names( face ); + } + + return result; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_PrivateRec* afont_private ) + { + FT_Error error; + FT_Service_PsInfo service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !afont_private ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_private ) + error = service->ps_get_font_private( face, afont_private ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_Get_PS_Font_Value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ) + { + FT_Int result = 0; + FT_Service_PsInfo service = NULL; + + + if ( face ) + { + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_value ) + result = service->ps_get_font_value( face, key, idx, + value, value_len ); + } + + return result; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftutil.c b/vendor/freetype/src/base/ftutil.c new file mode 100644 index 0000000..6120846 --- /dev/null +++ b/vendor/freetype/src/base/ftutil.c @@ -0,0 +1,442 @@ +/**************************************************************************** + * + * ftutil.c + * + * FreeType utility file for memory and list management (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT memory + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** M E M O R Y M A N A G E M E N T *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer block = ft_mem_qalloc( memory, size, &error ); + + if ( !error && block && size > 0 ) + FT_MEM_ZERO( block, size ); + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + FT_Pointer block = NULL; + + + if ( size > 0 ) + { + block = memory->alloc( memory, size ); + if ( !block ) + error = FT_THROW( Out_Of_Memory ); + } + else if ( size < 0 ) + { + /* may help catch/prevent security issues */ + error = FT_THROW( Invalid_Argument ); + } + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + + + block = ft_mem_qrealloc( memory, item_size, + cur_count, new_count, block, &error ); + if ( !error && block && new_count > cur_count ) + FT_MEM_ZERO( (char*)block + cur_count * item_size, + ( new_count - cur_count ) * item_size ); + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + + + /* Note that we now accept `item_size == 0' as a valid parameter, in + * order to cover very weird cases where an ALLOC_MULT macro would be + * called. + */ + if ( cur_count < 0 || new_count < 0 || item_size < 0 ) + { + /* may help catch/prevent nasty security issues */ + error = FT_THROW( Invalid_Argument ); + } + else if ( new_count == 0 || item_size == 0 ) + { + ft_mem_free( memory, block ); + block = NULL; + } + else if ( new_count > FT_INT_MAX / item_size ) + { + error = FT_THROW( Array_Too_Large ); + } + else if ( cur_count == 0 ) + { + FT_ASSERT( !block ); + + block = memory->alloc( memory, new_count * item_size ); + if ( block == NULL ) + error = FT_THROW( Out_Of_Memory ); + } + else + { + FT_Pointer block2; + FT_Long cur_size = cur_count * item_size; + FT_Long new_size = new_count * item_size; + + + block2 = memory->realloc( memory, cur_size, new_size, block ); + if ( !block2 ) + error = FT_THROW( Out_Of_Memory ); + else + block = block2; + } + + *p_error = error; + return block; + } + + + FT_BASE_DEF( void ) + ft_mem_free( FT_Memory memory, + const void *P ) + { + if ( P ) + memory->free( memory, (void*)P ); + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer p = ft_mem_qalloc( memory, (FT_Long)size, &error ); + + + if ( !error && address && size > 0 ) + ft_memcpy( p, address, size ); + + *p_error = error; + return p; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ) + { + FT_ULong len = str ? (FT_ULong)ft_strlen( str ) + 1 + : 0; + + + return ft_mem_dup( memory, str, len, p_error ); + } + + + FT_BASE_DEF( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ) + { + while ( size > 1 && *src != 0 ) + { + *dst++ = *src++; + size--; + } + + *dst = 0; /* always zero-terminate */ + + return *src != 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** D O U B L Y L I N K E D L I S T S *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#undef FT_COMPONENT +#define FT_COMPONENT list + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ) + { + FT_ListNode cur; + + + if ( !list ) + return NULL; + + cur = list->head; + while ( cur ) + { + if ( cur->data == data ) + return cur; + + cur = cur->next; + } + + return NULL; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Add( FT_List list, + FT_ListNode node ) + { + FT_ListNode before; + + + if ( !list || !node ) + return; + + before = list->tail; + + node->next = NULL; + node->prev = before; + + if ( before ) + before->next = node; + else + list->head = node; + + list->tail = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ) + { + FT_ListNode after; + + + if ( !list || !node ) + return; + + after = list->head; + + node->next = after; + node->prev = NULL; + + if ( !after ) + list->tail = node; + else + after->prev = node; + + list->head = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + if ( !list || !node ) + return; + + before = node->prev; + after = node->next; + + if ( before ) + before->next = after; + else + list->head = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Up( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + if ( !list || !node ) + return; + + before = node->prev; + after = node->next; + + /* check whether we are already on top of the list */ + if ( !before ) + return; + + before->next = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + + node->prev = NULL; + node->next = list->head; + list->head->prev = node; + list->head = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ) + { + FT_ListNode cur; + FT_Error error = FT_Err_Ok; + + + if ( !list || !iterator ) + return FT_THROW( Invalid_Argument ); + + cur = list->head; + + while ( cur ) + { + FT_ListNode next = cur->next; + + + error = iterator( cur, user ); + if ( error ) + break; + + cur = next; + } + + return error; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ) + { + FT_ListNode cur; + + + if ( !list || !memory ) + return; + + cur = list->head; + while ( cur ) + { + FT_ListNode next = cur->next; + void* data = cur->data; + + + if ( destroy ) + destroy( memory, data, user ); + + FT_FREE( cur ); + cur = next; + } + + list->head = NULL; + list->tail = NULL; + } + + +/* END */ diff --git a/vendor/freetype/src/base/ftver.rc b/vendor/freetype/src/base/ftver.rc new file mode 100644 index 0000000..137a633 --- /dev/null +++ b/vendor/freetype/src/base/ftver.rc @@ -0,0 +1,61 @@ +/***************************************************************************/ +/* */ +/* ftver.rc */ +/* */ +/* FreeType VERSIONINFO resource for Windows DLLs. */ +/* */ +/* Copyright (C) 2018-2023 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include + +#define FT_VERSION 2,13,2,0 +#define FT_VERSION_STR "2.13.2" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION FT_VERSION +PRODUCTVERSION FT_VERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG +FILEFLAGS VS_FF_DEBUG +#endif +#ifdef DLL_EXPORT +FILETYPE VFT_DLL +#define FT_FILENAME "freetype.dll" +#else +FILETYPE VFT_STATIC_LIB +#define FT_FILENAME "freetype.lib" +#endif +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "The FreeType Project" + VALUE "FileDescription", "Font Rendering Library" + VALUE "FileVersion", FT_VERSION_STR + VALUE "ProductName", "FreeType" + VALUE "ProductVersion", FT_VERSION_STR + VALUE "LegalCopyright", L"\x00A9 2000-2023 The FreeType Project www.freetype.org. All rights reserved." + VALUE "InternalName", "freetype" + VALUE "OriginalFilename", FT_FILENAME + END + END + + BLOCK "VarFileInfo" + BEGIN + /* The following line should only be modified for localized versions. */ + /* It consists of any number of WORD,WORD pairs, with each pair */ + /* describing a "language,codepage" combination supported by the file. */ + VALUE "Translation", 0x409, 1200 + END +END diff --git a/vendor/freetype/src/base/ftwinfnt.c b/vendor/freetype/src/base/ftwinfnt.c new file mode 100644 index 0000000..03b023e --- /dev/null +++ b/vendor/freetype/src/base/ftwinfnt.c @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * ftwinfnt.c + * + * FreeType API for accessing Windows FNT specific info (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + + /* documentation is in ftwinfnt.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *header ) + { + FT_Service_WinFnt service; + FT_Error error; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !header ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_LOOKUP_SERVICE( face, service, WINFNT ); + + if ( service ) + error = service->get_header( face, header ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/base/md5.c b/vendor/freetype/src/base/md5.c new file mode 100644 index 0000000..b235e17 --- /dev/null +++ b/vendor/freetype/src/base/md5.c @@ -0,0 +1,291 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#ifndef HAVE_OPENSSL + +#include + +#include "md5.h" + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * MD5_u32plus. In practice, this problem may occur if these MD5 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD5 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD5_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +void MD5_Init(MD5_CTX *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) +{ + MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + available = 64 - used; + + if (size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +#define OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); + +void MD5_Final(unsigned char *result, MD5_CTX *ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if (available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + OUT(&ctx->buffer[56], ctx->lo) + OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + OUT(&result[0], ctx->a) + OUT(&result[4], ctx->b) + OUT(&result[8], ctx->c) + OUT(&result[12], ctx->d) + + memset(ctx, 0, sizeof(*ctx)); +} + +#endif diff --git a/vendor/freetype/src/base/md5.h b/vendor/freetype/src/base/md5.h new file mode 100644 index 0000000..2da44bf --- /dev/null +++ b/vendor/freetype/src/base/md5.h @@ -0,0 +1,45 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. + */ + +#ifdef HAVE_OPENSSL +#include +#elif !defined(_MD5_H) +#define _MD5_H + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD5_u32plus; + +typedef struct { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + MD5_u32plus block[16]; +} MD5_CTX; + +extern void MD5_Init(MD5_CTX *ctx); +extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); +extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); + +#endif diff --git a/vendor/freetype/src/base/rules.mk b/vendor/freetype/src/base/rules.mk new file mode 100644 index 0000000..b7de9b5 --- /dev/null +++ b/vendor/freetype/src/base/rules.mk @@ -0,0 +1,108 @@ +# +# FreeType 2 base layer configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# It sets the following variables which are used by the master Makefile +# after the call: +# +# BASE_OBJ_S: The single-object base layer. +# BASE_OBJ_M: A list of all objects for a multiple-objects build. +# BASE_EXT_OBJ: A list of base layer extensions, i.e., components found +# in `src/base' which are not compiled within the base +# layer proper. + + +BASE_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(BASE_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# Base layer sources +# +# ftsystem, ftinit, and ftdebug are handled by freetype.mk +# +# All files listed here should be included in `ftbase.c' (for a `single' +# build). +# +BASE_SRC := $(BASE_DIR)/ftadvanc.c \ + $(BASE_DIR)/ftcalc.c \ + $(BASE_DIR)/ftcolor.c \ + $(BASE_DIR)/ftdbgmem.c \ + $(BASE_DIR)/fterrors.c \ + $(BASE_DIR)/ftfntfmt.c \ + $(BASE_DIR)/ftgloadr.c \ + $(BASE_DIR)/fthash.c \ + $(BASE_DIR)/ftlcdfil.c \ + $(BASE_DIR)/ftobjs.c \ + $(BASE_DIR)/ftoutln.c \ + $(BASE_DIR)/ftpsprop.c \ + $(BASE_DIR)/ftrfork.c \ + $(BASE_DIR)/ftsnames.c \ + $(BASE_DIR)/ftstream.c \ + $(BASE_DIR)/fttrigon.c \ + $(BASE_DIR)/ftutil.c + + +ifneq ($(ftmac_c),) + BASE_SRC += $(BASE_DIR)/$(ftmac_c) +endif + +# for simplicity, we also handle `md5.c' (which gets included by `ftobjs.h') +BASE_H := $(BASE_DIR)/ftbase.h \ + $(BASE_DIR)/md5.c \ + $(BASE_DIR)/md5.h + +# Base layer `extensions' sources +# +# An extension is added to the library file as a separate object. It is +# then linked to the final executable only if one of its symbols is used by +# the application. +# +BASE_EXT_SRC := $(patsubst %,$(BASE_DIR)/%,$(BASE_EXTENSIONS)) + +# Default extensions objects +# +BASE_EXT_OBJ := $(BASE_EXT_SRC:$(BASE_DIR)/%.c=$(OBJ_DIR)/%.$O) + + +# Base layer object(s) +# +# BASE_OBJ_M is used during `multi' builds (each base source file compiles +# to a single object file). +# +# BASE_OBJ_S is used during `single' builds (the whole base layer is +# compiled as a single object file using ftbase.c). +# +BASE_OBJ_M := $(BASE_SRC:$(BASE_DIR)/%.c=$(OBJ_DIR)/%.$O) +BASE_OBJ_S := $(OBJ_DIR)/ftbase.$O + +# Base layer root source file for single build +# +BASE_SRC_S := $(BASE_DIR)/ftbase.c + + +# Base layer - single object build +# +$(BASE_OBJ_S): $(BASE_SRC_S) $(BASE_SRC) $(FREETYPE_H) $(BASE_H) + $(BASE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(BASE_SRC_S)) + + +# Multiple objects build + extensions +# +$(OBJ_DIR)/%.$O: $(BASE_DIR)/%.c $(FREETYPE_H) $(BASE_H) + $(BASE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# EOF diff --git a/vendor/freetype/src/bdf/README b/vendor/freetype/src/bdf/README new file mode 100644 index 0000000..d7cb8c1 --- /dev/null +++ b/vendor/freetype/src/bdf/README @@ -0,0 +1,152 @@ + FreeType font driver for BDF fonts + + Francesco Zappa Nardelli + + + +Introduction +************ + +BDF (Bitmap Distribution Format) is a bitmap font format defined by Adobe, +which is intended to be easily understood by both humans and computers. +This code implements a BDF driver for the FreeType library, following the +Adobe Specification V 2.2. The specification of the BDF font format is +available from Adobe's web site: + + https://adobe-type-tools.github.io/font-tech-notes/pdfs/5005.BDF_Spec.pdf + +Many good bitmap fonts in bdf format come with XFree86 (www.XFree86.org). +They do not define vertical metrics, because the X Consortium BDF +specification has removed them. + + +Encodings +********* + +[This section is out of date, retained for historical reasons. BDF + properties can be retrieved with `FT_Get_BDF_Property`, character set ID + values with `FT_Get_BDF_Charset_ID`.] + +The variety of encodings that accompanies bdf fonts appears to encompass the +small set defined in freetype.h. On the other hand, two properties that +specify encoding and registry are usually defined in bdf fonts. + +I decided to make these two properties directly accessible, leaving to the +client application the work of interpreting them. For instance: + + + #include FT_INTERNAL_BDF_TYPES_H + + FT_Face face; + BDF_Public_Face bdfface; + + + FT_New_Face( library, ..., &face ); + + bdfface = (BDF_Public_Face)face; + + if ( ( bdfface->charset_registry == "ISO10646" ) && + ( bdfface->charset_encoding == "1" ) ) + [..] + + +Thus the driver always exports `ft_encoding_none' as face->charmap.encoding. +FT_Get_Char_Index's behavior is unmodified, that is, it converts the ULong +value given as argument into the corresponding glyph number. + +If the two properties are not available, Adobe Standard Encoding should be +assumed. + + +Anti-Aliased Bitmaps +******************** + +The driver supports an extension to the BDF format as used in Mark Leisher's +xmbdfed bitmap font editor. Microsoft's SBIT tool expects bitmap fonts in +that format for adding anti-aliased them to TrueType fonts. It introduces a +fourth field to the `SIZE' keyword which gives the bpp value (bits per +pixel) of the glyph data in the font. Possible values are 1 (the default), +2 (four gray levels), 4 (16 gray levels), and 8 (256 gray levels). The +driver returns either a bitmap with 1 bit per pixel or a pixmap with 8bits +per pixel (using 4, 16, and 256 gray levels, respectively). + + +Known problems +************** + +- A font is entirely loaded into memory. Obviously, this is not the Right + Thing(TM). If you have big fonts I suggest you convert them into PCF + format (using the bdftopcf utility): the PCF font drive of FreeType can + perform incremental glyph loading. + +When I have some time, I will implement on-demand glyph parsing. + +- Except for encodings properties, client applications have no visibility of + the PCF_Face object. This means that applications cannot directly access + font tables and must trust FreeType. + +- Currently, glyph names are ignored. + + I plan to give full visibility of the BDF_Face object in an upcoming + revision of the driver, thus implementing also glyph names. + +- As I have never seen a BDF font that defines vertical metrics, vertical + metrics are (parsed and) discarded. If you own a BDF font that defines + vertical metrics, please let me know (I will implement them in 5-10 + minutes). + + +License +******* + +Copyright (C) 2001-2002 by Francesco Zappa Nardelli + +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. + +*** Portions of the driver (that is, bdflib.c and bdf.h): + +Copyright 2000 Computing Research Labs, New Mexico State University +Copyright 2001-2002, 2011 Francesco Zappa Nardelli + +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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY 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. + + +Credits +******* + +This driver is based on excellent Mark Leisher's bdf library. If you +find something good in this driver you should probably thank him, not +me. diff --git a/vendor/freetype/src/bdf/bdf.c b/vendor/freetype/src/bdf/bdf.c new file mode 100644 index 0000000..249012e --- /dev/null +++ b/vendor/freetype/src/bdf/bdf.c @@ -0,0 +1,34 @@ +/* bdf.c + + FreeType font driver for bdf files + + Copyright (C) 2001, 2002 by + Francesco Zappa Nardelli + +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. +*/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "bdflib.c" +#include "bdfdrivr.c" + + +/* END */ diff --git a/vendor/freetype/src/bdf/bdf.h b/vendor/freetype/src/bdf/bdf.h new file mode 100644 index 0000000..e2cb52c --- /dev/null +++ b/vendor/freetype/src/bdf/bdf.h @@ -0,0 +1,253 @@ +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2004, 2011 Francesco Zappa Nardelli + * + * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY 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. + */ + + +#ifndef BDF_H_ +#define BDF_H_ + + +/* + * Based on bdf.h,v 1.16 2000/03/16 20:08:51 mleisher + */ + +#include +#include +#include + + +FT_BEGIN_HEADER + + +/* Imported from bdfP.h */ + +#define _bdf_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] & ( 1UL << ( (e) & 31 ) ) ) +#define _bdf_set_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] |= ( 1UL << ( (e) & 31 ) ) ) +#define _bdf_clear_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] &= ~( 1UL << ( (e) & 31 ) ) ) + +/* end of bdfP.h */ + + + /************************************************************************** + * + * BDF font options macros and types. + * + */ + + +#define BDF_CORRECT_METRICS 0x01 /* Correct invalid metrics when loading. */ +#define BDF_KEEP_COMMENTS 0x02 /* Preserve the font comments. */ +#define BDF_KEEP_UNENCODED 0x04 /* Keep the unencoded glyphs. */ +#define BDF_PROPORTIONAL 0x08 /* Font has proportional spacing. */ +#define BDF_MONOWIDTH 0x10 /* Font has mono width. */ +#define BDF_CHARCELL 0x20 /* Font has charcell spacing. */ + +#define BDF_ALL_SPACING ( BDF_PROPORTIONAL | \ + BDF_MONOWIDTH | \ + BDF_CHARCELL ) + +#define BDF_DEFAULT_LOAD_OPTIONS ( BDF_CORRECT_METRICS | \ + BDF_KEEP_COMMENTS | \ + BDF_KEEP_UNENCODED | \ + BDF_PROPORTIONAL ) + + + typedef struct bdf_options_t_ + { + int correct_metrics; + int keep_unencoded; + int keep_comments; + int font_spacing; + + } bdf_options_t; + + + /* Callback function type for unknown configuration options. */ + typedef int + (*bdf_options_callback_t)( bdf_options_t* opts, + char** params, + unsigned long nparams, + void* client_data ); + + + /************************************************************************** + * + * BDF font property macros and types. + * + */ + + +#define BDF_ATOM 1 +#define BDF_INTEGER 2 +#define BDF_CARDINAL 3 + + + /* This structure represents a particular property of a font. */ + /* There are a set of defaults and each font has their own. */ + typedef struct bdf_property_t_ + { + const char* name; /* Name of the property. */ + int format; /* Format of the property. */ + int builtin; /* A builtin property. */ + union + { + char* atom; + long l; + unsigned long ul; + + } value; /* Value of the property. */ + + } bdf_property_t; + + + /************************************************************************** + * + * BDF font metric and glyph types. + * + */ + + + typedef struct bdf_bbx_t_ + { + unsigned short width; + unsigned short height; + + short x_offset; + short y_offset; + + short ascent; + short descent; + + } bdf_bbx_t; + + + typedef struct bdf_glyph_t_ + { + char* name; /* Glyph name. */ + unsigned long encoding; /* Glyph encoding. */ + unsigned short swidth; /* Scalable width. */ + unsigned short dwidth; /* Device width. */ + bdf_bbx_t bbx; /* Glyph bounding box. */ + unsigned char* bitmap; /* Glyph bitmap. */ + unsigned long bpr; /* Number of bytes used per row. */ + unsigned short bytes; /* Number of bytes used for the bitmap. */ + + } bdf_glyph_t; + + + typedef struct bdf_font_t_ + { + char* name; /* Name of the font. */ + bdf_bbx_t bbx; /* Font bounding box. */ + + unsigned long point_size; /* Point size of the font. */ + unsigned long resolution_x; /* Font horizontal resolution. */ + unsigned long resolution_y; /* Font vertical resolution. */ + + int spacing; /* Font spacing value. */ + + unsigned short monowidth; /* Logical width for monowidth font. */ + + unsigned long default_char; /* Encoding of the default glyph. */ + + long font_ascent; /* Font ascent. */ + long font_descent; /* Font descent. */ + + unsigned long glyphs_size; /* Glyph structures allocated. */ + unsigned long glyphs_used; /* Glyph structures used. */ + bdf_glyph_t* glyphs; /* Glyphs themselves. */ + + unsigned long unencoded_size; /* Unencoded glyph struct. allocated. */ + unsigned long unencoded_used; /* Unencoded glyph struct. used. */ + bdf_glyph_t* unencoded; /* Unencoded glyphs themselves. */ + + unsigned long props_size; /* Font properties allocated. */ + unsigned long props_used; /* Font properties used. */ + bdf_property_t* props; /* Font properties themselves. */ + + char* comments; /* Font comments. */ + unsigned long comments_len; /* Length of comment string. */ + + void* internal; /* Internal data for the font. */ + + unsigned short bpp; /* Bits per pixel. */ + + FT_Memory memory; + + bdf_property_t* user_props; + unsigned long nuser_props; + FT_HashRec proptbl; + + } bdf_font_t; + + + /************************************************************************** + * + * Types for load/save callbacks. + * + */ + + + /* Error codes. */ +#define BDF_MISSING_START -1 +#define BDF_MISSING_FONTNAME -2 +#define BDF_MISSING_SIZE -3 +#define BDF_MISSING_CHARS -4 +#define BDF_MISSING_STARTCHAR -5 +#define BDF_MISSING_ENCODING -6 +#define BDF_MISSING_BBX -7 + +#define BDF_OUT_OF_MEMORY -20 + +#define BDF_INVALID_LINE -100 + + + /************************************************************************** + * + * BDF font API. + * + */ + + FT_LOCAL( FT_Error ) + bdf_load_font( FT_Stream stream, + FT_Memory memory, + bdf_options_t* opts, + bdf_font_t* *font ); + + FT_LOCAL( void ) + bdf_free_font( bdf_font_t* font ); + + FT_LOCAL( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ); + + +FT_END_HEADER + + +#endif /* BDF_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/bdf/bdfdrivr.c b/vendor/freetype/src/bdf/bdfdrivr.c new file mode 100644 index 0000000..e02a160 --- /dev/null +++ b/vendor/freetype/src/bdf/bdfdrivr.c @@ -0,0 +1,1013 @@ +/* bdfdrivr.c + + FreeType font driver for bdf files + + Copyright (C) 2001-2008, 2011, 2013, 2014 by + Francesco Zappa Nardelli + +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 +#include +#include +#include +#include + +#include +#include + +#include "bdf.h" +#include "bdfdrivr.h" + +#include "bdferror.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bdfdriver + + + typedef struct BDF_CMapRec_ + { + FT_CMapRec cmap; + FT_ULong num_encodings; /* ftobjs.h: FT_CMap->clazz->size */ + BDF_encoding_el* encodings; + + } BDF_CMapRec, *BDF_CMap; + + + FT_CALLBACK_DEF( FT_Error ) + bdf_cmap_init( FT_CMap bdfcmap, + FT_Pointer init_data ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_Face face = (BDF_Face)FT_CMAP_FACE( cmap ); + FT_UNUSED( init_data ); + + + cmap->num_encodings = face->bdffont->glyphs_used; + cmap->encodings = face->en_table; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + bdf_cmap_done( FT_CMap bdfcmap ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + + + cmap->encodings = NULL; + cmap->num_encodings = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_index( FT_CMap bdfcmap, + FT_UInt32 charcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; + FT_UShort result = 0; /* encodings->glyph */ + + FT_ULong min = 0; + FT_ULong max = cmap->num_encodings; + FT_ULong mid = ( min + max ) >> 1; + + + while ( min < max ) + { + FT_ULong code = encodings[mid].enc; + + + if ( charcode == code ) + { + /* increase glyph index by 1 -- */ + /* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + break; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + + /* reasonable prediction in a continuous block */ + mid += charcode - code; + if ( mid >= max || mid < min ) + mid = ( min + max ) >> 1; + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_next( FT_CMap bdfcmap, + FT_UInt32 *acharcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; + FT_UShort result = 0; /* encodings->glyph */ + FT_ULong charcode = *acharcode + 1; + + FT_ULong min = 0; + FT_ULong max = cmap->num_encodings; + FT_ULong mid = ( min + max ) >> 1; + + + while ( min < max ) + { + FT_ULong code = encodings[mid].enc; + + + if ( charcode == code ) + { + /* increase glyph index by 1 -- */ + /* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + goto Exit; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + + /* prediction in a continuous block */ + mid += charcode - code; + if ( mid >= max || mid < min ) + mid = ( min + max ) >> 1; + } + + charcode = 0; + if ( min < cmap->num_encodings ) + { + charcode = encodings[min].enc; + result = encodings[min].glyph + 1; + } + + Exit: + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%lx > 32bit API", + charcode )); + *acharcode = 0; + /* XXX: result should be changed to indicate an overflow error */ + } + else + *acharcode = (FT_UInt32)charcode; + return result; + } + + + static + const FT_CMap_ClassRec bdf_cmap_class = + { + sizeof ( BDF_CMapRec ), + bdf_cmap_init, + bdf_cmap_done, + bdf_cmap_char_index, + bdf_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL + }; + + + static FT_Error + bdf_interpret_style( BDF_Face bdf ) + { + FT_Error error = FT_Err_Ok; + FT_Face face = FT_FACE( bdf ); + FT_Memory memory = face->memory; + bdf_font_t* font = bdf->bdffont; + bdf_property_t* prop; + + const char* strings[4] = { NULL, NULL, NULL, NULL }; + size_t lengths[4], nn, len; + + + face->style_flags = 0; + + prop = bdf_get_font_property( font, "SLANT" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ) + ? "Oblique" + : "Italic"; + } + + prop = bdf_get_font_property( font, "WEIGHT_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = "Bold"; + } + + prop = bdf_get_font_property( font, "SETWIDTH_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (const char *)(prop->value.atom); + + prop = bdf_get_font_property( font, "ADD_STYLE_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (const char *)(prop->value.atom); + + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + + if ( len == 0 ) + { + strings[0] = "Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + + { + char* s; + + + if ( FT_QALLOC( face->style_name, len ) ) + return error; + + s = face->style_name; + + for ( nn = 0; nn < 4; nn++ ) + { + const char* src = strings[nn]; + + + len = lengths[nn]; + + if ( !src ) + continue; + + /* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + + ft_memcpy( s, src, len ); + + /* need to convert spaces to dashes for */ + /* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + size_t mm; + + + for ( mm = 0; mm < len; mm++ ) + if ( s[mm] == ' ' ) + s[mm] = '-'; + } + + s += len; + } + *s = 0; + } + + return error; + } + + + FT_CALLBACK_DEF( void ) + BDF_Face_Done( FT_Face face ) /* BDF_Face */ + { + BDF_Face bdfface = (BDF_Face)face; + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + bdf_free_font( bdfface->bdffont ); + + FT_FREE( bdfface->en_table ); + + FT_FREE( bdfface->charset_encoding ); + FT_FREE( bdfface->charset_registry ); + FT_FREE( face->family_name ); + FT_FREE( face->style_name ); + + FT_FREE( face->available_sizes ); + + FT_FREE( bdfface->bdffont ); + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Face_Init( FT_Stream stream, + FT_Face face, /* BDF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error = FT_Err_Ok; + BDF_Face bdfface = (BDF_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + + bdf_font_t* font = NULL; + bdf_options_t options; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "BDF driver\n" )); + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + options.correct_metrics = 1; /* FZ XXX: options semantics */ + options.keep_unencoded = 1; + options.keep_comments = 0; + options.font_spacing = BDF_PROPORTIONAL; + + error = bdf_load_font( stream, memory, &options, &font ); + if ( FT_ERR_EQ( error, Missing_Startfont_Field ) ) + { + FT_TRACE2(( " not a BDF file\n" )); + goto Fail; + } + else if ( error ) + goto Exit; + + /* we have a bdf font: let's construct the face object */ + bdfface->bdffont = font; + + /* BDF cannot have multiple faces in a single font file. + * XXX: non-zero face_index is already invalid argument, but + * Type1, Type42 driver has a convention to return + * an invalid argument error when the font could be + * opened by the specified driver. + */ + if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "BDF_Face_Init: invalid face index\n" )); + BDF_Face_Done( face ); + return FT_THROW( Invalid_Argument ); + } + + { + bdf_property_t* prop = NULL; + + + FT_TRACE4(( " number of glyphs: allocated %ld (used %ld)\n", + font->glyphs_size, + font->glyphs_used )); + FT_TRACE4(( " number of unencoded glyphs: allocated %ld (used %ld)\n", + font->unencoded_size, + font->unencoded_used )); + + face->num_faces = 1; + face->face_index = 0; + + face->face_flags |= FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + prop = bdf_get_font_property( font, "SPACING" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' || + *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) ) + face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */ + /* FZ XXX: I need a font to implement this */ + + prop = bdf_get_font_property( font, "FAMILY_NAME" ); + if ( prop && prop->value.atom ) + { + if ( FT_STRDUP( face->family_name, prop->value.atom ) ) + goto Exit; + } + else + face->family_name = NULL; + + if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) ) + goto Exit; + + /* the number of glyphs (with one slot for the undefined glyph */ + /* at position 0 and all unencoded glyphs) */ + face->num_glyphs = (FT_Long)( font->glyphs_size + 1 ); + + face->num_fixed_sizes = 1; + if ( FT_NEW( face->available_sizes ) ) + goto Exit; + + { + FT_Bitmap_Size* bsize = face->available_sizes; + FT_Short resolution_x = 0; + FT_Short resolution_y = 0; + long value; + + + /* sanity checks */ + if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF ) + { + font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %ld\n", + font->font_ascent )); + } + if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF ) + { + font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %ld\n", + font->font_descent )); + } + + bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); + + prop = bdf_get_font_property( font, "AVERAGE_WIDTH" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative average width\n" )); +#endif + if ( prop->value.l > 0x7FFFL * 10 - 5 || + prop->value.l < -( 0x7FFFL * 10 - 5 ) ) + { + bsize->width = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n", + bsize->width )); + } + else + bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); + } + else + { + /* this is a heuristical value */ + bsize->width = ( bsize->height * 2 + 1 ) / 3; + } + + prop = bdf_get_font_property( font, "POINT_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative point size\n" )); +#endif + /* convert from 722.7 decipoints to 72 points per inch */ + if ( prop->value.l > 0x504C2L || /* 0x7FFF * 72270/7200 */ + prop->value.l < -0x504C2L ) + { + bsize->size = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", + bsize->size )); + } + else + bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), + 64 * 7200, + 72270L ); + } + else if ( font->point_size ) + { + if ( font->point_size > 0x7FFF ) + { + bsize->size = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", + bsize->size )); + } + else + bsize->size = (FT_Pos)font->point_size << 6; + } + else + { + /* this is a heuristical value */ + bsize->size = bsize->width * 64; + } + + prop = bdf_get_font_property( font, "PIXEL_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" )); +#endif + if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF ) + { + bsize->y_ppem = 0x7FFF << 6; + FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n", + bsize->y_ppem )); + } + else + bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; + } + + prop = bdf_get_font_property( font, "RESOLUTION_X" ); + if ( prop ) + value = prop->value.l; + else + value = (long)font->resolution_x; + if ( value ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( value < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" )); +#endif + if ( value > 0x7FFF || value < -0x7FFF ) + { + resolution_x = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n", + resolution_x )); + } + else + resolution_x = FT_ABS( (FT_Short)value ); + } + + prop = bdf_get_font_property( font, "RESOLUTION_Y" ); + if ( prop ) + value = prop->value.l; + else + value = (long)font->resolution_y; + if ( value ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( value < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" )); +#endif + if ( value > 0x7FFF || value < -0x7FFF ) + { + resolution_y = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n", + resolution_y )); + } + else + resolution_y = FT_ABS( (FT_Short)value ); + } + + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = FT_MulDiv( bsize->y_ppem, + resolution_x, + resolution_y ); + else + bsize->x_ppem = bsize->y_ppem; + } + + /* encoding table */ + { + bdf_glyph_t* cur = font->glyphs; + unsigned long n; + + + if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) ) + goto Exit; + + bdfface->default_glyph = 0; + for ( n = 0; n < font->glyphs_size; n++ ) + { + (bdfface->en_table[n]).enc = cur[n].encoding; + FT_TRACE4(( " idx %ld, val 0x%lX\n", n, cur[n].encoding )); + (bdfface->en_table[n]).glyph = (FT_UShort)n; + + if ( cur[n].encoding == font->default_char ) + { + if ( n < FT_UINT_MAX ) + bdfface->default_glyph = (FT_UInt)n; + else + FT_TRACE1(( "BDF_Face_Init:" + " idx %ld is too large for this system\n", n )); + } + } + } + + /* charmaps */ + { + bdf_property_t *charset_registry, *charset_encoding; + FT_Bool unicode_charmap = 0; + + + charset_registry = + bdf_get_font_property( font, "CHARSET_REGISTRY" ); + charset_encoding = + bdf_get_font_property( font, "CHARSET_ENCODING" ); + if ( charset_registry && charset_encoding ) + { + if ( charset_registry->format == BDF_ATOM && + charset_encoding->format == BDF_ATOM && + charset_registry->value.atom && + charset_encoding->value.atom ) + { + const char* s; + + + if ( FT_STRDUP( bdfface->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( bdfface->charset_registry, + charset_registry->value.atom ) ) + goto Exit; + + /* Uh, oh, compare first letters manually to avoid dependency */ + /* on locales. */ + s = bdfface->charset_registry; + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( bdfface->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + /* another name for ASCII */ + else if ( !ft_strcmp( s, "646.1991" ) && + !ft_strcmp( bdfface->charset_encoding, "IRV" ) ) + unicode_charmap = 1; + } + + { + FT_CharMapRec charmap; + + + charmap.face = face; + charmap.encoding = FT_ENCODING_NONE; + /* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + } + + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); + } + + goto Exit; + } + } + + /* otherwise assume Adobe standard encoding */ + + { + FT_CharMapRec charmap; + + + charmap.face = face; + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.platform_id = TT_PLATFORM_ADOBE; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); + + /* Select default charmap */ + if ( face->num_charmaps ) + face->charmap = face->charmaps[0]; + } + } + } + + Exit: + return error; + + Fail: + BDF_Face_Done( face ); + return FT_THROW( Unknown_File_Format ); + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont; + + + FT_Select_Metrics( size->face, strike_index ); + + size->metrics.ascender = bdffont->font_ascent * 64; + size->metrics.descender = -bdffont->font_descent * 64; + size->metrics.max_advance = bdffont->bbx.width * 64; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FT_Face face = size->face; + FT_Bitmap_Size* bsize = face->available_sizes; + bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont; + FT_Error error = FT_ERR( Invalid_Pixel_Size ); + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = FT_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( bdffont->font_ascent + + bdffont->font_descent ) ) + error = FT_Err_Ok; + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + if ( error ) + return error; + else + return BDF_Size_Select( size, 0 ); + } + + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size ); + FT_Face face = FT_FACE( bdf ); + FT_Error error = FT_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + bdf_glyph_t glyph; + int bpp = bdf->bdffont->bpp; + + FT_UNUSED( load_flags ); + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( glyph_index >= (FT_UInt)face->num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index )); + + /* index 0 is the undefined glyph */ + if ( glyph_index == 0 ) + glyph_index = bdf->default_glyph; + else + glyph_index--; + + /* slot, bitmap => freetype, glyph => bdflib */ + glyph = bdf->bdffont->glyphs[glyph_index]; + + bitmap->rows = glyph.bbx.height; + bitmap->width = glyph.bbx.width; + if ( glyph.bpr > FT_INT_MAX ) + FT_TRACE1(( "BDF_Glyph_Load: too large pitch %ld is truncated\n", + glyph.bpr )); + bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */ + + /* note: we don't allocate a new array to hold the bitmap; */ + /* we can simply point to it */ + ft_glyphslot_set_bitmap( slot, glyph.bitmap ); + + switch ( bpp ) + { + case 1: + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + break; + case 2: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; + break; + case 4: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; + break; + case 8: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + break; + } + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = glyph.bbx.x_offset; + slot->bitmap_top = glyph.bbx.ascent; + + slot->metrics.horiAdvance = (FT_Pos)( glyph.dwidth * 64 ); + slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 ); + slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 ); + slot->metrics.width = (FT_Pos)( bitmap->width * 64 ); + slot->metrics.height = (FT_Pos)( bitmap->rows * 64 ); + + /* + * XXX DWIDTH1 and VVECTOR should be parsed and + * used here, provided such fonts do exist. + */ + ft_synthesize_vertical_metrics( &slot->metrics, + bdf->bdffont->bbx.height * 64 ); + + Exit: + return error; + } + + + /* + * + * BDF SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + bdf_get_bdf_property( FT_Face face, /* BDF_Face */ + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + BDF_Face bdfface = (BDF_Face)face; + bdf_property_t* prop; + + + FT_ASSERT( bdfface && bdfface->bdffont ); + + prop = bdf_get_font_property( bdfface->bdffont, prop_name ); + if ( prop ) + { + switch ( prop->format ) + { + case BDF_ATOM: + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + break; + + case BDF_INTEGER: + if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) + { + FT_TRACE1(( "bdf_get_bdf_property:" + " too large integer 0x%lx is truncated\n", + prop->value.l )); + } + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = (FT_Int32)prop->value.l; + break; + + case BDF_CARDINAL: + if ( prop->value.ul > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "bdf_get_bdf_property:" + " too large cardinal 0x%lx is truncated\n", + prop->value.ul )); + } + aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; + aproperty->u.cardinal = (FT_UInt32)prop->value.ul; + break; + + default: + goto Fail; + } + return 0; + } + + Fail: + return FT_THROW( Invalid_Argument ); + } + + + FT_CALLBACK_DEF( FT_Error ) + bdf_get_charset_id( FT_Face face, /* BDF_Face */ + const char* *acharset_encoding, + const char* *acharset_registry ) + { + BDF_Face bdfface = (BDF_Face)face; + + + *acharset_encoding = bdfface->charset_encoding; + *acharset_registry = bdfface->charset_registry; + + return 0; + } + + + static const FT_Service_BDFRec bdf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, /* get_charset_id */ + (FT_BDF_GetPropertyFunc) bdf_get_bdf_property /* get_property */ + }; + + + /* + * + * SERVICES LIST + * + */ + + static const FT_ServiceDescRec bdf_services[] = + { + { FT_SERVICE_ID_BDF, &bdf_service_bdf }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + bdf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( bdf_services, name ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec bdf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + + "bdf", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + bdf_driver_requester /* FT_Module_Requester get_interface */ + }, + + sizeof ( BDF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + BDF_Face_Init, /* FT_Face_InitFunc init_face */ + BDF_Face_Done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + NULL, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + BDF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + BDF_Size_Request, /* FT_Size_RequestFunc request_size */ + BDF_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/vendor/freetype/src/bdf/bdfdrivr.h b/vendor/freetype/src/bdf/bdfdrivr.h new file mode 100644 index 0000000..54aaa33 --- /dev/null +++ b/vendor/freetype/src/bdf/bdfdrivr.h @@ -0,0 +1,72 @@ +/* bdfdrivr.h + + FreeType font driver for bdf fonts + + Copyright (C) 2001, 2002, 2003, 2004 by + Francesco Zappa Nardelli + +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. +*/ + + +#ifndef BDFDRIVR_H_ +#define BDFDRIVR_H_ + +#include + +#include "bdf.h" + + +FT_BEGIN_HEADER + + + typedef struct BDF_encoding_el_ + { + FT_ULong enc; + FT_UShort glyph; + + } BDF_encoding_el; + + + typedef struct BDF_FaceRec_ + { + FT_FaceRec root; + + char* charset_encoding; + char* charset_registry; + + bdf_font_t* bdffont; + + BDF_encoding_el* en_table; + + FT_UInt default_glyph; + + } BDF_FaceRec, *BDF_Face; + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) bdf_driver_class; + + +FT_END_HEADER + + +#endif /* BDFDRIVR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/bdf/bdferror.h b/vendor/freetype/src/bdf/bdferror.h new file mode 100644 index 0000000..c1b5444 --- /dev/null +++ b/vendor/freetype/src/bdf/bdferror.h @@ -0,0 +1,45 @@ +/* + * Copyright 2001, 2002, 2012 Francesco Zappa Nardelli + * + * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is used to define the BDF error enumeration constants. + * + */ + +#ifndef BDFERROR_H_ +#define BDFERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX BDF_Err_ +#define FT_ERR_BASE FT_Mod_Err_BDF + +#include + +#endif /* BDFERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/bdf/bdflib.c b/vendor/freetype/src/bdf/bdflib.c new file mode 100644 index 0000000..0fa7e0a --- /dev/null +++ b/vendor/freetype/src/bdf/bdflib.c @@ -0,0 +1,2387 @@ +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2014 + * Francesco Zappa Nardelli + * + * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 + * + * taken from Mark Leisher's xmbdfed package + * + */ + + + +#include +#include +#include +#include + +#include "bdf.h" +#include "bdferror.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bdflib + + +#define BUFSIZE 128 + + + /************************************************************************** + * + * Default BDF font options. + * + */ + + + static const bdf_options_t bdf_opts_ = + { + 1, /* Correct metrics. */ + 1, /* Preserve unencoded glyphs. */ + 0, /* Preserve comments. */ + BDF_PROPORTIONAL /* Default spacing. */ + }; + + + /************************************************************************** + * + * Builtin BDF font properties. + * + */ + + /* List of most properties that might appear in a font. Doesn't include */ + /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ + + static const bdf_property_t bdf_properties_[] = + { + { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, + { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, + { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, + { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, + { "COMMENT", BDF_ATOM, 1, { 0 } }, + { "COPYRIGHT", BDF_ATOM, 1, { 0 } }, + { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, + { "DESTINATION", BDF_CARDINAL, 1, { 0 } }, + { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, + { "END_SPACE", BDF_INTEGER, 1, { 0 } }, + { "FACE_NAME", BDF_ATOM, 1, { 0 } }, + { "FAMILY_NAME", BDF_ATOM, 1, { 0 } }, + { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "FONT", BDF_ATOM, 1, { 0 } }, + { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, + { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "FOUNDRY", BDF_ATOM, 1, { 0 } }, + { "FULL_NAME", BDF_ATOM, 1, { 0 } }, + { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, + { "MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { "MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { "NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { "NOTICE", BDF_ATOM, 1, { 0 } }, + { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { "POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, + { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { "RESOLUTION", BDF_INTEGER, 1, { 0 } }, + { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, + { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, + { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, + { "SLANT", BDF_ATOM, 1, { 0 } }, + { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { "SPACING", BDF_ATOM, 1, { 0 } }, + { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { "WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, + { "X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, + { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, + }; + + static const unsigned long + num_bdf_properties_ = sizeof ( bdf_properties_ ) / + sizeof ( bdf_properties_[0] ); + + + /* An auxiliary macro to parse properties, to be used in conditionals. */ + /* It behaves like `strncmp' but also tests the following character */ + /* whether it is a whitespace or null. */ + /* `property' is a constant string of length `n' to compare with. */ +#define _bdf_strncmp( name, property, n ) \ + ( ft_strncmp( name, property, n ) || \ + !( name[n] == ' ' || \ + name[n] == '\0' || \ + name[n] == '\n' || \ + name[n] == '\r' || \ + name[n] == '\t' ) ) + + /* Auto correction messages. */ +#define ACMSG1 "FONT_ASCENT property missing. " \ + "Added `FONT_ASCENT %hd'.\n" +#define ACMSG2 "FONT_DESCENT property missing. " \ + "Added `FONT_DESCENT %hd'.\n" +#define ACMSG3 "Font width != actual width. Old: %d New: %d.\n" +#define ACMSG4 "Font left bearing != actual left bearing. " \ + "Old: %hd New: %hd.\n" +#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" +#define ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n" +#define ACMSG7 "Font height != actual height. Old: %d New: %d.\n" +#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" +#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n" +#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n" +#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" +#define ACMSG13 "Glyph %lu extra rows removed.\n" +#define ACMSG14 "Glyph %lu extra columns removed.\n" +#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" +#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n" +#define ACMSG17 "Adjusting number of glyphs to %ld.\n" + + /* Error messages. */ +#define ERRMSG1 "[line %ld] Missing `%s' line.\n" +#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n" +#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n" +#define ERRMSG4 "[line %ld] BBX too big.\n" +#define ERRMSG5 "[line %ld] `%s' value too big.\n" +#define ERRMSG6 "[line %ld] Input line too long.\n" +#define ERRMSG7 "[line %ld] Font name too long.\n" +#define ERRMSG8 "[line %ld] Invalid `%s' value.\n" +#define ERRMSG9 "[line %ld] Invalid keyword.\n" + + /* Debug messages. */ +#define DBGMSG1 " [%6ld] %s" /* no \n */ +#define DBGMSG2 " (0x%lX)\n" + + + /************************************************************************** + * + * Utility types and functions. + * + */ + + + /* Function type for parsing lines of a BDF font. */ + + typedef FT_Error + (*bdf_line_func_t_)( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ); + + + /* List structure for splitting lines into fields. */ + + typedef struct bdf_list_t__ + { + char** field; + unsigned long size; + unsigned long used; + FT_Memory memory; + + } bdf_list_t_; + + + /* Structure used while loading BDF fonts. */ + + typedef struct bdf_parse_t__ + { + unsigned long flags; + unsigned long cnt; + unsigned long row; + + short minlb; + short maxlb; + short maxrb; + short maxas; + short maxds; + + short rbearing; + + char* glyph_name; + long glyph_enc; + + bdf_font_t* font; + bdf_options_t* opts; + + bdf_list_t_ list; + + FT_Memory memory; + unsigned long size; /* the stream size */ + + } bdf_parse_t_; + + +#define setsbit( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) +#define sbitset( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) + + + static void + bdf_list_init_( bdf_list_t_* list, + FT_Memory memory ) + { + FT_ZERO( list ); + list->memory = memory; + } + + + static void + bdf_list_done_( bdf_list_t_* list ) + { + FT_Memory memory = list->memory; + + + if ( memory ) + { + FT_FREE( list->field ); + FT_ZERO( list ); + } + } + + + static FT_Error + bdf_list_ensure_( bdf_list_t_* list, + unsigned long num_items ) /* same as bdf_list_t_.used */ + { + FT_Error error = FT_Err_Ok; + + + if ( num_items > list->size ) + { + unsigned long oldsize = list->size; /* same as bdf_list_t_.size */ + unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5; + unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) ); + FT_Memory memory = list->memory; + + + if ( oldsize == bigsize ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + else if ( newsize < oldsize || newsize > bigsize ) + newsize = bigsize; + + if ( FT_QRENEW_ARRAY( list->field, oldsize, newsize ) ) + goto Exit; + + list->size = newsize; + } + + Exit: + return error; + } + + + static void + bdf_list_shift_( bdf_list_t_* list, + unsigned long n ) + { + unsigned long i, u; + + + if ( list == NULL || list->used == 0 || n == 0 ) + return; + + if ( n >= list->used ) + { + list->used = 0; + return; + } + + for ( u = n, i = 0; u < list->used; i++, u++ ) + list->field[i] = list->field[u]; + list->used -= n; + } + + + /* An empty string for empty fields. */ + + static const char empty[] = ""; /* XXX eliminate this */ + + + static char * + bdf_list_join_( bdf_list_t_* list, + int c, + unsigned long *alen ) + { + unsigned long i, j; + char* dp; + + + *alen = 0; + + if ( list == NULL || list->used == 0 ) + return NULL; + + dp = list->field[0]; + for ( i = j = 0; i < list->used; i++ ) + { + char* fp = list->field[i]; + + + while ( *fp ) + dp[j++] = *fp++; + + if ( i + 1 < list->used ) + dp[j++] = (char)c; + } + if ( dp != empty ) + dp[j] = 0; + + *alen = j; + return dp; + } + + + /* The code below ensures that we have at least 4 + 1 `field' */ + /* elements in `list' (which are possibly NULL) so that we */ + /* don't have to check the number of fields in most cases. */ + + static FT_Error + bdf_list_split_( bdf_list_t_* list, + const char* separators, + char* line, + unsigned long linelen ) + { + unsigned long final_empty; + int mult; + const char *sp, *end; + char *ep; + char seps[32]; + FT_Error error = FT_Err_Ok; + + + /* Initialize the list. */ + list->used = 0; + if ( list->size ) + { + list->field[0] = (char*)empty; + list->field[1] = (char*)empty; + list->field[2] = (char*)empty; + list->field[3] = (char*)empty; + list->field[4] = (char*)empty; + } + + /* If the line is empty, then simply return. */ + if ( linelen == 0 || line[0] == 0 ) + goto Exit; + + /* In the original code, if the `separators' parameter is NULL or */ + /* empty, the list is split into individual bytes. We don't need */ + /* this, so an error is signaled. */ + if ( separators == NULL || *separators == 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* Prepare the separator bitmap. */ + FT_MEM_ZERO( seps, 32 ); + + /* If the very last character of the separator string is a plus, then */ + /* set the `mult' flag to indicate that multiple separators should be */ + /* collapsed into one. */ + for ( mult = 0, sp = separators; sp && *sp; sp++ ) + { + if ( *sp == '+' && *( sp + 1 ) == 0 ) + mult = 1; + else + setsbit( seps, *sp ); + } + + /* Break the line up into fields. */ + for ( final_empty = 0, sp = ep = line, end = sp + linelen; + sp < end && *sp; ) + { + /* Collect everything that is not a separator. */ + for ( ; *ep && !sbitset( seps, *ep ); ep++ ) + ; + + /* Resize the list if necessary. */ + if ( list->used == list->size ) + { + error = bdf_list_ensure_( list, list->used + 1 ); + if ( error ) + goto Exit; + } + + /* Assign the field appropriately. */ + list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty; + + sp = ep; + + if ( mult ) + { + /* If multiple separators should be collapsed, do it now by */ + /* setting all the separator characters to 0. */ + for ( ; *ep && sbitset( seps, *ep ); ep++ ) + *ep = 0; + } + else if ( *ep != 0 ) + /* Don't collapse multiple separators by making them 0, so just */ + /* make the one encountered 0. */ + *ep++ = 0; + + final_empty = ( ep > sp && *ep == 0 ); + sp = ep; + } + + /* Finally, NULL-terminate the list. */ + if ( list->used + final_empty >= list->size ) + { + error = bdf_list_ensure_( list, list->used + final_empty + 1 ); + if ( error ) + goto Exit; + } + + if ( final_empty ) + list->field[list->used++] = (char*)empty; + + list->field[list->used] = NULL; + + Exit: + return error; + } + + +#define NO_SKIP 256 /* this value cannot be stored in a 'char' */ + + + static FT_Error + bdf_readstream_( FT_Stream stream, + bdf_line_func_t_ callback, + void* client_data, + unsigned long *lno ) + { + bdf_line_func_t_ cb; + unsigned long lineno, buf_size; + int refill, hold, to_skip; + ptrdiff_t bytes, start, end, cursor, avail; + char* buf = NULL; + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + + + if ( callback == NULL ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* initial size and allocation of the input buffer */ + buf_size = 1024; + + if ( FT_QALLOC( buf, buf_size ) ) + goto Exit; + + cb = callback; + lineno = 1; + buf[0] = 0; + start = 0; + avail = 0; + cursor = 0; + refill = 1; + to_skip = NO_SKIP; + bytes = 0; /* make compiler happy */ + + for (;;) + { + if ( refill ) + { + bytes = (ptrdiff_t)FT_Stream_TryRead( + stream, (FT_Byte*)buf + cursor, + buf_size - (unsigned long)cursor ); + avail = cursor + bytes; + cursor = 0; + refill = 0; + } + + end = start; + + /* should we skip an optional character like \n or \r? */ + if ( start < avail && buf[start] == to_skip ) + { + start += 1; + to_skip = NO_SKIP; + continue; + } + + /* try to find the end of the line */ + while ( end < avail && buf[end] != '\n' && buf[end] != '\r' ) + end++; + + /* if we hit the end of the buffer, try shifting its content */ + /* or even resizing it */ + if ( end >= avail ) + { + if ( bytes == 0 ) + { + /* last line in file doesn't end in \r or \n; */ + /* ignore it then exit */ + if ( lineno == 1 ) + error = FT_THROW( Missing_Startfont_Field ); + break; + } + + if ( start == 0 ) + { + /* this line is definitely too long; try resizing the input */ + /* buffer a bit to handle it. */ + FT_ULong new_size; + + + if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */ + { + if ( lineno == 1 ) + error = FT_THROW( Missing_Startfont_Field ); + else + { + FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno )); + error = FT_THROW( Invalid_Argument ); + } + goto Exit; + } + + new_size = buf_size * 2; + if ( FT_QREALLOC( buf, buf_size, new_size ) ) + goto Exit; + + cursor = avail; + buf_size = new_size; + } + else + { + bytes = avail - start; + + FT_MEM_MOVE( buf, buf + start, bytes ); + + cursor = bytes; + start = 0; + } + refill = 1; + continue; + } + + /* Temporarily NUL-terminate the line. */ + hold = buf[end]; + buf[end] = 0; + + /* XXX: Use encoding independent value for 0x1A */ + if ( buf[start] != '#' && buf[start] != 0x1A && end > start ) + { + error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, + (void*)&cb, client_data ); + /* Redo if we have encountered CHARS without properties. */ + if ( error == -1 ) + error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, + (void*)&cb, client_data ); + if ( error ) + break; + } + + lineno += 1; + buf[end] = (char)hold; + start = end + 1; + + if ( hold == '\n' ) + to_skip = '\r'; + else if ( hold == '\r' ) + to_skip = '\n'; + else + to_skip = NO_SKIP; + } + + *lno = lineno; + + Exit: + FT_FREE( buf ); + return error; + } + + + /* XXX: make this work with EBCDIC also */ + + static const unsigned char a2i[128] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + static const unsigned char ddigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static const unsigned char hdigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, + 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + + /* Routine to convert a decimal ASCII string to an unsigned long integer. */ + static unsigned long + bdf_atoul_( const char* s ) + { + unsigned long v; + + + if ( s == NULL || *s == 0 ) + return 0; + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( FT_ULONG_MAX - 9 ) / 10 ) + v = v * 10 + a2i[(int)*s]; + else + { + v = FT_ULONG_MAX; + break; + } + } + + return v; + } + + + /* Routine to convert a decimal ASCII string to a signed long integer. */ + static long + bdf_atol_( const char* s ) + { + long v, neg; + + + if ( s == NULL || *s == 0 ) + return 0; + + /* Check for a minus sign. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( FT_LONG_MAX - 9 ) / 10 ) + v = v * 10 + a2i[(int)*s]; + else + { + v = FT_LONG_MAX; + break; + } + } + + return ( !neg ) ? v : -v; + } + + + /* Routine to convert a decimal ASCII string to an unsigned short integer. */ + static unsigned short + bdf_atous_( const char* s ) + { + unsigned short v; + + + if ( s == NULL || *s == 0 ) + return 0; + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( FT_USHORT_MAX - 9 ) / 10 ) + v = (unsigned short)( v * 10 + a2i[(int)*s] ); + else + { + v = FT_USHORT_MAX; + break; + } + } + + return v; + } + + + /* Routine to convert a decimal ASCII string to a signed short integer. */ + static short + bdf_atos_( const char* s ) + { + short v, neg; + + + if ( s == NULL || *s == 0 ) + return 0; + + /* Check for a minus. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( SHRT_MAX - 9 ) / 10 ) + v = (short)( v * 10 + a2i[(int)*s] ); + else + { + v = SHRT_MAX; + break; + } + } + + return (short)( ( !neg ) ? v : -v ); + } + + + /* Routine to compare two glyphs by encoding so they can be sorted. */ + FT_COMPARE_DEF( int ) + by_encoding( const void* a, + const void* b ) + { + bdf_glyph_t *c1, *c2; + + + c1 = (bdf_glyph_t *)a; + c2 = (bdf_glyph_t *)b; + + if ( c1->encoding < c2->encoding ) + return -1; + + if ( c1->encoding > c2->encoding ) + return 1; + + return 0; + } + + + static FT_Error + bdf_create_property( const char* name, + int format, + bdf_font_t* font ) + { + size_t n; + bdf_property_t* p; + FT_Memory memory = font->memory; + FT_Error error = FT_Err_Ok; + + + /* First check whether the property has */ + /* already been added or not. If it has, then */ + /* simply ignore it. */ + if ( ft_hash_str_lookup( name, &(font->proptbl) ) ) + goto Exit; + + if ( FT_QRENEW_ARRAY( font->user_props, + font->nuser_props, + font->nuser_props + 1 ) ) + goto Exit; + + p = font->user_props + font->nuser_props; + + n = ft_strlen( name ) + 1; + if ( n > FT_LONG_MAX ) + return FT_THROW( Invalid_Argument ); + + if ( FT_QALLOC( p->name, n ) ) + goto Exit; + + FT_MEM_COPY( (char *)p->name, name, n ); + + p->format = format; + p->builtin = 0; + p->value.atom = NULL; /* nothing is ever stored here */ + + n = num_bdf_properties_ + font->nuser_props; + + error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory ); + if ( error ) + goto Exit; + + font->nuser_props++; + + Exit: + return error; + } + + + static bdf_property_t* + bdf_get_property( const char* name, + bdf_font_t* font ) + { + size_t* propid; + + + if ( name == NULL || *name == 0 ) + return NULL; + + if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL ) + return NULL; + + if ( *propid >= num_bdf_properties_ ) + return font->user_props + ( *propid - num_bdf_properties_ ); + + return (bdf_property_t*)bdf_properties_ + *propid; + } + + + /************************************************************************** + * + * BDF font file parsing flags and functions. + * + */ + + + /* Parse flags. */ + +#define BDF_START_ 0x0001U +#define BDF_FONT_NAME_ 0x0002U +#define BDF_SIZE_ 0x0004U +#define BDF_FONT_BBX_ 0x0008U +#define BDF_PROPS_ 0x0010U +#define BDF_GLYPHS_ 0x0020U +#define BDF_GLYPH_ 0x0040U +#define BDF_ENCODING_ 0x0080U +#define BDF_SWIDTH_ 0x0100U +#define BDF_DWIDTH_ 0x0200U +#define BDF_BBX_ 0x0400U +#define BDF_BITMAP_ 0x0800U + +#define BDF_SWIDTH_ADJ_ 0x1000U + +#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \ + BDF_ENCODING_ | \ + BDF_SWIDTH_ | \ + BDF_DWIDTH_ | \ + BDF_BBX_ | \ + BDF_BITMAP_ ) + +#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL +#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL + + + static FT_Error + bdf_add_comment_( bdf_font_t* font, + const char* comment, + unsigned long len ) + { + char* cp; + FT_Memory memory = font->memory; + FT_Error error = FT_Err_Ok; + + + if ( FT_QRENEW_ARRAY( font->comments, + font->comments_len, + font->comments_len + len + 1 ) ) + goto Exit; + + cp = font->comments + font->comments_len; + + FT_MEM_COPY( cp, comment, len ); + cp[len] = '\0'; + + font->comments_len += len + 1; + + Exit: + return error; + } + + + /* Set the spacing from the font name if it exists, or set it to the */ + /* default specified in the options. */ + static FT_Error + bdf_set_default_spacing_( bdf_font_t* font, + bdf_options_t* opts, + unsigned long lineno ) + { + size_t len; + char name[256]; + bdf_list_t_ list; + FT_Memory memory; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + if ( font == NULL || font->name == NULL || font->name[0] == 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = font->memory; + + bdf_list_init_( &list, memory ); + + font->spacing = opts->font_spacing; + + len = ft_strlen( font->name ) + 1; + /* Limit ourselves to 256 characters in the font name. */ + if ( len >= 256 ) + { + FT_ERROR(( "bdf_set_default_spacing_: " ERRMSG7, lineno )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_MEM_COPY( name, font->name, len ); + + error = bdf_list_split_( &list, "-", name, (unsigned long)len ); + if ( error ) + goto Fail; + + if ( list.used == 15 ) + { + switch ( list.field[11][0] ) + { + case 'C': + case 'c': + font->spacing = BDF_CHARCELL; + break; + case 'M': + case 'm': + font->spacing = BDF_MONOWIDTH; + break; + case 'P': + case 'p': + font->spacing = BDF_PROPORTIONAL; + break; + } + } + + Fail: + bdf_list_done_( &list ); + + Exit: + return error; + } + + + /* Determine whether the property is an atom or not. If it is, then */ + /* clean it up so the double quotes are removed if they exist. */ + static int + bdf_is_atom_( char* line, + unsigned long linelen, + char** name, + char** value, + bdf_font_t* font ) + { + int hold; + char *sp, *ep; + bdf_property_t* p; + + + sp = ep = line; + + while ( *ep && *ep != ' ' && *ep != '\t' ) + ep++; + + hold = *ep; + *ep = '\0'; + + p = bdf_get_property( sp, font ); + + /* If the property exists and is not an atom, just return here. */ + if ( p && p->format != BDF_ATOM ) + { + *ep = (char)hold; /* Undo NUL-termination. */ + return 0; + } + + *name = sp; + + /* The property is an atom. Trim all leading and trailing whitespace */ + /* and double quotes for the atom value. */ + sp = ep; + ep = line + linelen; + + /* Trim the leading whitespace if it exists. */ + if ( sp < ep ) + do + sp++; + while ( *sp == ' ' || *sp == '\t' ); + + /* Trim the leading double quote if it exists. */ + if ( *sp == '"' ) + sp++; + + *value = sp; + + /* Trim the trailing whitespace if it exists. */ + if ( sp < ep ) + do + *ep-- = '\0'; + while ( *ep == ' ' || *ep == '\t' ); + + /* Trim the trailing double quote if it exists. */ + if ( *ep == '"' ) + *ep = '\0'; + + return 1; + } + + + static FT_Error + bdf_add_property_( bdf_font_t* font, + const char* name, + char* value, + unsigned long lineno ) + { + size_t* propid; + bdf_property_t *prop, *fp; + FT_Memory memory = font->memory; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + /* First, check whether the property already exists in the font. */ + if ( ( propid = ft_hash_str_lookup( name, + (FT_Hash)font->internal ) ) != NULL ) + { + /* The property already exists in the font, so simply replace */ + /* the value of the property with the current value. */ + fp = font->props + *propid; + + switch ( fp->format ) + { + case BDF_ATOM: + /* Delete the current atom if it exists. */ + FT_FREE( fp->value.atom ); + + if ( value && value[0] != 0 ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + + case BDF_INTEGER: + fp->value.l = bdf_atol_( value ); + break; + + case BDF_CARDINAL: + fp->value.ul = bdf_atoul_( value ); + break; + + default: + ; + } + + goto Exit; + } + + /* See whether this property type exists yet or not. */ + /* If not, create it. */ + propid = ft_hash_str_lookup( name, &(font->proptbl) ); + if ( !propid ) + { + error = bdf_create_property( name, BDF_ATOM, font ); + if ( error ) + goto Exit; + propid = ft_hash_str_lookup( name, &(font->proptbl) ); + } + + /* Allocate another property if this is overflowing. */ + if ( font->props_used == font->props_size ) + { + if ( FT_QRENEW_ARRAY( font->props, + font->props_size, + font->props_size + 1 ) ) + goto Exit; + + font->props_size++; + } + + if ( *propid >= num_bdf_properties_ ) + prop = font->user_props + ( *propid - num_bdf_properties_ ); + else + prop = (bdf_property_t*)bdf_properties_ + *propid; + + fp = font->props + font->props_used; + + fp->name = prop->name; + fp->format = prop->format; + fp->builtin = prop->builtin; + + switch ( prop->format ) + { + case BDF_ATOM: + fp->value.atom = NULL; + if ( value && value[0] ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + + case BDF_INTEGER: + fp->value.l = bdf_atol_( value ); + break; + + case BDF_CARDINAL: + fp->value.ul = bdf_atoul_( value ); + break; + } + + /* If the property happens to be a comment, then it doesn't need */ + /* to be added to the internal hash table. */ + if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 ) + { + /* Add the property to the font property table. */ + error = ft_hash_str_insert( fp->name, + font->props_used, + (FT_Hash)font->internal, + memory ); + if ( error ) + goto Exit; + } + + font->props_used++; + + /* Some special cases need to be handled here. The DEFAULT_CHAR */ + /* property needs to be located if it exists in the property list, the */ + /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ + /* present, and the SPACING property should override the default */ + /* spacing. */ + if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 ) + font->default_char = fp->value.ul; + else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 ) + font->font_ascent = fp->value.l; + else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 ) + font->font_descent = fp->value.l; + else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 ) + { + if ( !fp->value.atom ) + { + FT_ERROR(( "bdf_add_property_: " ERRMSG8, lineno, "SPACING" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) + font->spacing = BDF_PROPORTIONAL; + else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) + font->spacing = BDF_MONOWIDTH; + else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) + font->spacing = BDF_CHARCELL; + } + + Exit: + return error; + } + + + static const unsigned char nibble_mask[8] = + { + 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE + }; + + + static FT_Error + bdf_parse_end_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + /* a no-op; we ignore everything after `ENDFONT' */ + + FT_UNUSED( line ); + FT_UNUSED( linelen ); + FT_UNUSED( lineno ); + FT_UNUSED( call_data ); + FT_UNUSED( client_data ); + + return FT_Err_Ok; + } + + + /* Actually parse the glyph info and bitmaps. */ + static FT_Error + bdf_parse_glyphs_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + int c, mask_index; + char* s; + unsigned char* bp; + unsigned long i, slen, nibbles; + + bdf_line_func_t_* next; + bdf_parse_t_* p; + bdf_glyph_t* glyph; + bdf_font_t* font; + + FT_Memory memory; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + next = (bdf_line_func_t_ *)call_data; + p = (bdf_parse_t_ *) client_data; + + font = p->font; + memory = font->memory; + + /* Check for a comment. */ + if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->opts->keep_comments ) + { + linelen -= 7; + + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + error = bdf_add_comment_( p->font, s, linelen ); + } + goto Exit; + } + + /* The very first thing expected is the number of glyphs. */ + if ( !( p->flags & BDF_GLYPHS_ ) ) + { + if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "CHARS" )); + error = FT_THROW( Missing_Chars_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + p->cnt = font->glyphs_size = bdf_atoul_( p->list.field[1] ); + + /* We need at least 20 bytes per glyph. */ + if ( p->cnt > p->size / 20 ) + { + p->cnt = font->glyphs_size = p->size / 20; + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG17, p->cnt )); + } + + /* Make sure the number of glyphs is non-zero. */ + if ( p->cnt == 0 ) + font->glyphs_size = 64; + + /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ + /* number of code points available in Unicode). */ + if ( p->cnt >= 0x110000UL ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "CHARS" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) + goto Exit; + + p->flags |= BDF_GLYPHS_; + + goto Exit; + } + + /* Check for the ENDFONT field. */ + if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 ) + { + if ( p->flags & BDF_GLYPH_BITS_ ) + { + /* Missing ENDCHAR field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); + error = FT_THROW( Corrupted_Font_Glyphs ); + goto Exit; + } + + /* Sort the glyphs by encoding. */ + ft_qsort( (char *)font->glyphs, + font->glyphs_used, + sizeof ( bdf_glyph_t ), + by_encoding ); + + p->flags &= ~BDF_START_; + *next = bdf_parse_end_; + + goto Exit; + } + + /* Check for the ENDCHAR field. */ + if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 ) + { + p->glyph_enc = 0; + p->flags &= ~BDF_GLYPH_BITS_; + + goto Exit; + } + + /* Check whether a glyph is being scanned but should be */ + /* ignored because it is an unencoded glyph. */ + if ( ( p->flags & BDF_GLYPH_ ) && + p->glyph_enc == -1 && + p->opts->keep_unencoded == 0 ) + goto Exit; + + /* Check for the STARTCHAR field. */ + if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 ) + { + if ( p->flags & BDF_GLYPH_BITS_ ) + { + /* Missing ENDCHAR field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); + error = FT_THROW( Missing_Startchar_Field ); + goto Exit; + } + + /* Set the character name in the parse info first until the */ + /* encoding can be checked for an unencoded character. */ + FT_FREE( p->glyph_name ); + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + bdf_list_shift_( &p->list, 1 ); + + s = bdf_list_join_( &p->list, ' ', &slen ); + + if ( !s ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG8, lineno, "STARTCHAR" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( FT_QALLOC( p->glyph_name, slen + 1 ) ) + goto Exit; + + FT_MEM_COPY( p->glyph_name, s, slen + 1 ); + + p->flags |= BDF_GLYPH_; + + FT_TRACE4(( DBGMSG1, lineno, s )); + + goto Exit; + } + + /* Check for the ENCODING field. */ + if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 ) + { + if ( !( p->flags & BDF_GLYPH_ ) ) + { + /* Missing STARTCHAR field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" )); + error = FT_THROW( Missing_Startchar_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + p->glyph_enc = bdf_atol_( p->list.field[1] ); + + /* Normalize negative encoding values. The specification only */ + /* allows -1, but we can be more generous here. */ + if ( p->glyph_enc < -1 ) + p->glyph_enc = -1; + + /* Check for alternative encoding format. */ + if ( p->glyph_enc == -1 && p->list.used > 2 ) + p->glyph_enc = bdf_atol_( p->list.field[2] ); + + if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L ) + p->glyph_enc = -1; + + FT_TRACE4(( DBGMSG2, p->glyph_enc )); + + if ( p->glyph_enc >= 0 ) + { + /* Make sure there are enough glyphs allocated in case the */ + /* number of characters happen to be wrong. */ + if ( font->glyphs_used == font->glyphs_size ) + { + if ( FT_RENEW_ARRAY( font->glyphs, + font->glyphs_size, + font->glyphs_size + 64 ) ) + goto Exit; + + font->glyphs_size += 64; + } + + glyph = font->glyphs + font->glyphs_used++; + glyph->name = p->glyph_name; + glyph->encoding = (unsigned long)p->glyph_enc; + + /* Reset the initial glyph info. */ + p->glyph_name = NULL; + } + else + { + /* Unencoded glyph. Check whether it should */ + /* be added or not. */ + if ( p->opts->keep_unencoded ) + { + /* Allocate the next unencoded glyph. */ + if ( font->unencoded_used == font->unencoded_size ) + { + if ( FT_RENEW_ARRAY( font->unencoded , + font->unencoded_size, + font->unencoded_size + 4 ) ) + goto Exit; + + font->unencoded_size += 4; + } + + glyph = font->unencoded + font->unencoded_used; + glyph->name = p->glyph_name; + glyph->encoding = font->unencoded_used++; + + /* Reset the initial glyph info. */ + p->glyph_name = NULL; + } + else + { + /* Free up the glyph name if the unencoded shouldn't be */ + /* kept. */ + FT_FREE( p->glyph_name ); + } + } + + /* Clear the flags that might be added when width and height are */ + /* checked for consistency. */ + p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ ); + + p->flags |= BDF_ENCODING_; + + goto Exit; + } + + if ( !( p->flags & BDF_ENCODING_ ) ) + goto Missing_Encoding; + + /* Point at the glyph being constructed. */ + if ( p->glyph_enc == -1 ) + glyph = font->unencoded + ( font->unencoded_used - 1 ); + else + glyph = font->glyphs + ( font->glyphs_used - 1 ); + + /* Check whether a bitmap is being constructed. */ + if ( p->flags & BDF_BITMAP_ ) + { + /* If there are more rows than are specified in the glyph metrics, */ + /* ignore the remaining lines. */ + if ( p->row >= (unsigned long)glyph->bbx.height ) + { + if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) ) + { + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG13, glyph->encoding )); + p->flags |= BDF_GLYPH_HEIGHT_CHECK_; + } + + goto Exit; + } + + /* Only collect the number of nibbles indicated by the glyph */ + /* metrics. If there are more columns, they are simply ignored. */ + nibbles = glyph->bpr << 1; + bp = glyph->bitmap + p->row * glyph->bpr; + + for ( i = 0; i < nibbles; i++ ) + { + c = line[i]; + if ( !sbitset( hdigits, c ) ) + break; + *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); + if ( i + 1 < nibbles && ( i & 1 ) ) + *++bp = 0; + } + + /* If any line has not enough columns, */ + /* indicate they have been padded with zero bits. */ + if ( i < nibbles && + !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) + { + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG16, glyph->encoding )); + p->flags |= BDF_GLYPH_WIDTH_CHECK_; + } + + /* Remove possible garbage at the right. */ + mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; + if ( glyph->bbx.width ) + *bp &= nibble_mask[mask_index]; + + /* If any line has extra columns, indicate they have been removed. */ + if ( i == nibbles && + sbitset( hdigits, line[nibbles] ) && + !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) + { + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG14, glyph->encoding )); + p->flags |= BDF_GLYPH_WIDTH_CHECK_; + } + + p->row++; + goto Exit; + } + + /* Expect the SWIDTH (scalable width) field next. */ + if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + glyph->swidth = bdf_atous_( p->list.field[1] ); + p->flags |= BDF_SWIDTH_; + + goto Exit; + } + + /* Expect the DWIDTH (device width) field next. */ + if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + glyph->dwidth = bdf_atous_( p->list.field[1] ); + + if ( !( p->flags & BDF_SWIDTH_ ) ) + { + /* Missing SWIDTH field. Emit an auto correction message and set */ + /* the scalable width from the device width. */ + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno )); + + glyph->swidth = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + } + + p->flags |= BDF_DWIDTH_; + goto Exit; + } + + /* Expect the BBX field next. */ + if ( _bdf_strncmp( line, "BBX", 3 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + glyph->bbx.width = bdf_atous_( p->list.field[1] ); + glyph->bbx.height = bdf_atous_( p->list.field[2] ); + glyph->bbx.x_offset = bdf_atos_( p->list.field[3] ); + glyph->bbx.y_offset = bdf_atos_( p->list.field[4] ); + + /* Generate the ascent and descent of the character. */ + glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); + glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); + + /* Determine the overall font bounding box as the characters are */ + /* loaded so corrections can be done later if indicated. */ + p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); + p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); + + p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); + + p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); + p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); + p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); + + if ( !( p->flags & BDF_DWIDTH_ ) ) + { + /* Missing DWIDTH field. Emit an auto correction message and set */ + /* the device width to the glyph width. */ + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno )); + glyph->dwidth = glyph->bbx.width; + } + + /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ + /* value if necessary. */ + if ( p->opts->correct_metrics ) + { + /* Determine the point size of the glyph. */ + unsigned short sw = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + + + if ( sw != glyph->swidth ) + { + glyph->swidth = sw; + + p->flags |= BDF_SWIDTH_ADJ_; + } + } + + p->flags |= BDF_BBX_; + goto Exit; + } + + /* And finally, gather up the bitmap. */ + if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 ) + { + unsigned long bitmap_size; + + + if ( !( p->flags & BDF_BBX_ ) ) + { + /* Missing BBX field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" )); + error = FT_THROW( Missing_Bbx_Field ); + goto Exit; + } + + /* Allocate enough space for the bitmap. */ + glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; + + bitmap_size = glyph->bpr * glyph->bbx.height; + if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno )); + error = FT_THROW( Bbx_Too_Big ); + goto Exit; + } + else + glyph->bytes = (unsigned short)bitmap_size; + + if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) ) + goto Exit; + + p->row = 0; + p->flags |= BDF_BITMAP_; + + goto Exit; + } + + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + + Missing_Encoding: + /* Missing ENCODING field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" )); + error = FT_THROW( Missing_Encoding_Field ); + + Exit: + if ( error && ( p->flags & BDF_GLYPH_ ) ) + FT_FREE( p->glyph_name ); + + return error; + } + + + /* Load the font properties. */ + static FT_Error + bdf_parse_properties_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long vlen; + bdf_line_func_t_* next; + bdf_parse_t_* p; + char* name; + char* value; + char nbuf[BUFSIZE]; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); + + + next = (bdf_line_func_t_ *)call_data; + p = (bdf_parse_t_ *) client_data; + + /* Check for the end of the properties. */ + if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 ) + { + /* If the FONT_ASCENT or FONT_DESCENT properties have not been */ + /* encountered yet, then make sure they are added as properties and */ + /* make sure they are set from the font bounding box info. */ + /* */ + /* This is *always* done regardless of the options, because X11 */ + /* requires these two fields to compile fonts. */ + if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) + { + p->font->font_ascent = p->font->bbx.ascent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent ); + error = bdf_add_property_( p->font, "FONT_ASCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + + FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent )); + } + + if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) + { + p->font->font_descent = p->font->bbx.descent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent ); + error = bdf_add_property_( p->font, "FONT_DESCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + + FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent )); + } + + p->flags &= ~BDF_PROPS_; + *next = bdf_parse_glyphs_; + + goto Exit; + } + + /* Ignore the _XFREE86_GLYPH_RANGES properties. */ + if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) + goto Exit; + + /* Handle COMMENT fields and properties in a special way to preserve */ + /* the spacing. */ + if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + { + name = value = line; + value += 7; + if ( *value ) + *value++ = 0; + error = bdf_add_property_( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + else if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) ) + { + error = bdf_add_property_( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + else + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + name = p->list.field[0]; + + bdf_list_shift_( &p->list, 1 ); + value = bdf_list_join_( &p->list, ' ', &vlen ); + + error = bdf_add_property_( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + + Exit: + return error; + } + + + /* Load the font header. */ + static FT_Error + bdf_parse_start_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long slen; + bdf_line_func_t_* next; + bdf_parse_t_* p; + bdf_font_t* font; + char *s; + + FT_Memory memory = NULL; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + next = (bdf_line_func_t_ *)call_data; + p = (bdf_parse_t_ *) client_data; + + if ( p->font ) + memory = p->font->memory; + + /* Check for a comment. This is done to handle those fonts that have */ + /* comments before the STARTFONT line for some reason. */ + if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->opts->keep_comments && p->font ) + { + linelen -= 7; + + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + error = bdf_add_comment_( p->font, s, linelen ); + } + goto Exit; + } + + if ( !( p->flags & BDF_START_ ) ) + { + memory = p->memory; + + if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 ) + { + /* we don't emit an error message since this code gets */ + /* explicitly caught one level higher */ + error = FT_THROW( Missing_Startfont_Field ); + goto Exit; + } + + p->flags = BDF_START_; + font = p->font = NULL; + + if ( FT_NEW( font ) ) + goto Exit; + p->font = font; + + font->memory = p->memory; + + { /* setup */ + size_t i; + bdf_property_t* prop; + + + error = ft_hash_str_init( &(font->proptbl), memory ); + if ( error ) + goto Exit; + for ( i = 0, prop = (bdf_property_t*)bdf_properties_; + i < num_bdf_properties_; i++, prop++ ) + { + error = ft_hash_str_insert( prop->name, i, + &(font->proptbl), memory ); + if ( error ) + goto Exit; + } + } + + if ( FT_QALLOC( p->font->internal, sizeof ( FT_HashRec ) ) ) + goto Exit; + error = ft_hash_str_init( (FT_Hash)p->font->internal, memory ); + if ( error ) + goto Exit; + p->font->spacing = p->opts->font_spacing; + p->font->default_char = ~0UL; + + goto Exit; + } + + /* Check for the start of the properties. */ + if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 ) + { + if ( !( p->flags & BDF_FONT_BBX_ ) ) + { + /* Missing the FONTBOUNDINGBOX field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); + error = FT_THROW( Missing_Fontboundingbox_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + /* at this point, `p->font' can't be NULL */ + p->cnt = p->font->props_size = bdf_atoul_( p->list.field[1] ); + /* We need at least 4 bytes per property. */ + if ( p->cnt > p->size / 4 ) + { + p->font->props_size = 0; + + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "STARTPROPERTIES" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) + { + p->font->props_size = 0; + goto Exit; + } + + p->flags |= BDF_PROPS_; + *next = bdf_parse_properties_; + + goto Exit; + } + + /* Check for the FONTBOUNDINGBOX field. */ + if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) + { + if ( !( p->flags & BDF_SIZE_ ) ) + { + /* Missing the SIZE field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" )); + error = FT_THROW( Missing_Size_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + p->font->bbx.width = bdf_atous_( p->list.field[1] ); + p->font->bbx.height = bdf_atous_( p->list.field[2] ); + + p->font->bbx.x_offset = bdf_atos_( p->list.field[3] ); + p->font->bbx.y_offset = bdf_atos_( p->list.field[4] ); + + p->font->bbx.ascent = (short)( p->font->bbx.height + + p->font->bbx.y_offset ); + + p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); + + p->flags |= BDF_FONT_BBX_; + + goto Exit; + } + + /* The next thing to check for is the FONT field. */ + if ( _bdf_strncmp( line, "FONT", 4 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + bdf_list_shift_( &p->list, 1 ); + + s = bdf_list_join_( &p->list, ' ', &slen ); + + if ( !s ) + { + FT_ERROR(( "bdf_parse_start_: " ERRMSG8, lineno, "FONT" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ + FT_FREE( p->font->name ); + + if ( FT_QALLOC( p->font->name, slen + 1 ) ) + goto Exit; + FT_MEM_COPY( p->font->name, s, slen + 1 ); + + /* If the font name is an XLFD name, set the spacing to the one in */ + /* the font name. If there is no spacing fall back on the default. */ + error = bdf_set_default_spacing_( p->font, p->opts, lineno ); + if ( error ) + goto Exit; + + p->flags |= BDF_FONT_NAME_; + + goto Exit; + } + + /* Check for the SIZE field. */ + if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 ) + { + if ( !( p->flags & BDF_FONT_NAME_ ) ) + { + /* Missing the FONT field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" )); + error = FT_THROW( Missing_Font_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + p->font->point_size = bdf_atoul_( p->list.field[1] ); + p->font->resolution_x = bdf_atoul_( p->list.field[2] ); + p->font->resolution_y = bdf_atoul_( p->list.field[3] ); + + /* Check for the bits per pixel field. */ + if ( p->list.used == 5 ) + { + unsigned short bpp; + + + bpp = bdf_atous_( p->list.field[4] ); + + /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */ + if ( bpp > 4 ) + p->font->bpp = 8; + else if ( bpp > 2 ) + p->font->bpp = 4; + else if ( bpp > 1 ) + p->font->bpp = 2; + else + p->font->bpp = 1; + + if ( p->font->bpp != bpp ) + FT_TRACE2(( "bdf_parse_start_: " ACMSG11, p->font->bpp )); + } + else + p->font->bpp = 1; + + p->flags |= BDF_SIZE_; + + goto Exit; + } + + /* Check for the CHARS field -- font properties are optional */ + if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 ) + { + char nbuf[BUFSIZE]; + + + if ( !( p->flags & BDF_FONT_BBX_ ) ) + { + /* Missing the FONTBOUNDINGBOX field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); + error = FT_THROW( Missing_Fontboundingbox_Field ); + goto Exit; + } + + /* Add the two standard X11 properties which are required */ + /* for compiling fonts. */ + p->font->font_ascent = p->font->bbx.ascent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent ); + error = bdf_add_property_( p->font, "FONT_ASCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent )); + + p->font->font_descent = p->font->bbx.descent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent ); + error = bdf_add_property_( p->font, "FONT_DESCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent )); + + *next = bdf_parse_glyphs_; + + /* A special return value. */ + error = -1; + goto Exit; + } + + FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno )); + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + /************************************************************************** + * + * API. + * + */ + + + FT_LOCAL_DEF( FT_Error ) + bdf_load_font( FT_Stream stream, + FT_Memory memory, + bdf_options_t* opts, + bdf_font_t* *font ) + { + unsigned long lineno = 0; /* make compiler happy */ + bdf_parse_t_ *p = NULL; + + FT_Error error = FT_Err_Ok; + + + if ( FT_NEW( p ) ) + goto Exit; + + p->opts = (bdf_options_t*)( opts ? opts : &bdf_opts_ ); + p->minlb = 32767; + p->size = stream->size; + p->memory = memory; /* only during font creation */ + + bdf_list_init_( &p->list, memory ); + + error = bdf_readstream_( stream, bdf_parse_start_, + (void *)p, &lineno ); + if ( error ) + goto Fail; + + if ( p->font ) + { + /* If the font is not proportional, set the font's monowidth */ + /* field to the width of the font bounding box. */ + + if ( p->font->spacing != BDF_PROPORTIONAL ) + p->font->monowidth = p->font->bbx.width; + + /* If the number of glyphs loaded is not that of the original count, */ + /* indicate the difference. */ + if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, + p->font->glyphs_used + p->font->unencoded_used )); + } + + /* Once the font has been loaded, adjust the overall font metrics if */ + /* necessary. */ + if ( p->opts->correct_metrics != 0 && + ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) + { + if ( p->maxrb - p->minlb != p->font->bbx.width ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG3, + p->font->bbx.width, p->maxrb - p->minlb )); + p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); + } + + if ( p->font->bbx.x_offset != p->minlb ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG4, + p->font->bbx.x_offset, p->minlb )); + p->font->bbx.x_offset = p->minlb; + } + + if ( p->font->bbx.ascent != p->maxas ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG5, + p->font->bbx.ascent, p->maxas )); + p->font->bbx.ascent = p->maxas; + } + + if ( p->font->bbx.descent != p->maxds ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG6, + p->font->bbx.descent, p->maxds )); + p->font->bbx.descent = p->maxds; + p->font->bbx.y_offset = (short)( -p->maxds ); + } + + if ( p->maxas + p->maxds != p->font->bbx.height ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG7, + p->font->bbx.height, p->maxas + p->maxds )); + p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); + } + + if ( p->flags & BDF_SWIDTH_ADJ_ ) + FT_TRACE2(( "bdf_load_font: " ACMSG8 )); + } + } + + if ( p->flags & BDF_START_ ) + { + /* The ENDFONT field was never reached or did not exist. */ + if ( !( p->flags & BDF_GLYPHS_ ) ) + { + /* Error happened while parsing header. */ + FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); + error = FT_THROW( Corrupted_Font_Header ); + goto Fail; + } + else + { + /* Error happened when parsing glyphs. */ + FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); + error = FT_THROW( Corrupted_Font_Glyphs ); + goto Fail; + } + } + + if ( !p->font && !error ) + error = FT_THROW( Invalid_File_Format ); + + *font = p->font; + + Exit: + if ( p ) + { + bdf_list_done_( &p->list ); + + FT_FREE( p->glyph_name ); + FT_FREE( p ); + } + + return error; + + Fail: + bdf_free_font( p->font ); + + FT_FREE( p->font ); + + goto Exit; + } + + + FT_LOCAL_DEF( void ) + bdf_free_font( bdf_font_t* font ) + { + bdf_property_t* prop; + unsigned long i; + bdf_glyph_t* glyphs; + FT_Memory memory; + + + if ( font == NULL ) + return; + + memory = font->memory; + + FT_FREE( font->name ); + + /* Free up the internal hash table of property names. */ + if ( font->internal ) + { + ft_hash_str_free( (FT_Hash)font->internal, memory ); + FT_FREE( font->internal ); + } + + /* Free up the comment info. */ + FT_FREE( font->comments ); + + /* Free up the properties. */ + for ( i = 0; i < font->props_size; i++ ) + { + if ( font->props[i].format == BDF_ATOM ) + FT_FREE( font->props[i].value.atom ); + } + + FT_FREE( font->props ); + + /* Free up the character info. */ + for ( i = 0, glyphs = font->glyphs; + i < font->glyphs_used; i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + + for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; + i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + + FT_FREE( font->glyphs ); + FT_FREE( font->unencoded ); + + /* bdf_cleanup */ + ft_hash_str_free( &(font->proptbl), memory ); + + /* Free up the user defined properties. */ + for ( prop = font->user_props, i = 0; + i < font->nuser_props; i++, prop++ ) + FT_FREE( prop->name ); + + FT_FREE( font->user_props ); + + /* FREE( font ); */ /* XXX Fixme */ + } + + + FT_LOCAL_DEF( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ) + { + size_t* propid; + + + if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 ) + return 0; + + propid = ft_hash_str_lookup( name, (FT_Hash)font->internal ); + + return propid ? ( font->props + *propid ) : 0; + } + + +/* END */ diff --git a/vendor/freetype/src/bdf/module.mk b/vendor/freetype/src/bdf/module.mk new file mode 100644 index 0000000..fe06ae8 --- /dev/null +++ b/vendor/freetype/src/bdf/module.mk @@ -0,0 +1,34 @@ +# +# FreeType 2 BDF module definition +# + +# Copyright 2001, 2002, 2006 by +# Francesco Zappa Nardelli +# +# 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. + + +FTMODULE_H_COMMANDS += BDF_DRIVER + +define BDF_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, bdf_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)bdf $(ECHO_DRIVER_DESC)bdf bitmap fonts$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/bdf/rules.mk b/vendor/freetype/src/bdf/rules.mk new file mode 100644 index 0000000..d1dd76b --- /dev/null +++ b/vendor/freetype/src/bdf/rules.mk @@ -0,0 +1,84 @@ +# +# FreeType 2 bdf driver configuration rules +# + + +# Copyright (C) 2001, 2002, 2003, 2008 by +# Francesco Zappa Nardelli +# +# 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. + + + + +# bdf driver directory +# +BDF_DIR := $(SRC_DIR)/bdf + + +BDF_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(BDF_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# bdf driver sources (i.e., C files) +# +BDF_DRV_SRC := $(BDF_DIR)/bdflib.c \ + $(BDF_DIR)/bdfdrivr.c + + +# bdf driver headers +# +BDF_DRV_H := $(BDF_DIR)/bdf.h \ + $(BDF_DIR)/bdfdrivr.h \ + $(BDF_DIR)/bdferror.h + +# bdf driver object(s) +# +# BDF_DRV_OBJ_M is used during `multi' builds +# BDF_DRV_OBJ_S is used during `single' builds +# +BDF_DRV_OBJ_M := $(BDF_DRV_SRC:$(BDF_DIR)/%.c=$(OBJ_DIR)/%.$O) +BDF_DRV_OBJ_S := $(OBJ_DIR)/bdf.$O + +# bdf driver source file for single build +# +BDF_DRV_SRC_S := $(BDF_DIR)/bdf.c + + +# bdf driver - single object +# +$(BDF_DRV_OBJ_S): $(BDF_DRV_SRC_S) $(BDF_DRV_SRC) $(FREETYPE_H) $(BDF_DRV_H) + $(BDF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(BDF_DRV_SRC_S)) + + +# bdf driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(BDF_DIR)/%.c $(FREETYPE_H) $(BDF_DRV_H) + $(BDF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(BDF_DRV_OBJ_S) +DRV_OBJS_M += $(BDF_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/bzip2/ftbzip2.c b/vendor/freetype/src/bzip2/ftbzip2.c new file mode 100644 index 0000000..ad342bd --- /dev/null +++ b/vendor/freetype/src/bzip2/ftbzip2.c @@ -0,0 +1,535 @@ +/**************************************************************************** + * + * ftbzip2.c + * + * FreeType support for .bz2 compressed files. + * + * This optional component relies on libbz2. It should mainly be used to + * parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2010-2023 by + * Joel Klinghed. + * + * based on `src/gzip/ftgzip.c' + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Bzip2_Err_ +#define FT_ERR_BASE FT_Mod_Err_Bzip2 + +#include + + +#ifdef FT_CONFIG_OPTION_USE_BZIP2 + +#define BZ_NO_STDIO /* Do not need FILE */ +#include + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z I P 2 M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + /* it is better to use FreeType memory routines instead of raw + 'malloc/free' */ + + typedef void* (*alloc_func)( void*, int, int ); + typedef void (*free_func) ( void*, void* ); + + + static void* + ft_bzip2_alloc( void* memory_, /* FT_Memory */ + int items, + int size ) + { + FT_Memory memory = (FT_Memory)memory_; + + FT_ULong sz = (FT_ULong)size * (FT_ULong)items; + FT_Error error; + FT_Pointer p = NULL; + + + FT_MEM_QALLOC( p, sz ); + return p; + } + + + static void + ft_bzip2_free( void* memory_, /* FT_Memory */ + void* address ) + { + FT_Memory memory = (FT_Memory)memory_; + + + FT_MEM_FREE( address ); + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z I P 2 F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_BZIP2_BUFFER_SIZE 4096 + + typedef struct FT_BZip2FileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + bz_stream bzstream; /* bzlib input stream */ + + FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */ + + FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + FT_Bool reset; /* reset before next read */ + + } FT_BZip2FileRec, *FT_BZip2File; + + + /* check and skip .bz2 header - we don't support `transparent' compression */ + static FT_Error + ft_bzip2_check_header( FT_Stream stream ) + { + FT_Error error = FT_Err_Ok; + FT_Byte head[4]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 4 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers; */ + /* head[2] is the version, and head[3] the blocksize */ + if ( head[0] != 0x42 || + head[1] != 0x5A || + head[2] != 0x68 ) /* only support bzip2 (huffman) */ + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + Exit: + return error; + } + + + static FT_Error + ft_bzip2_file_init( FT_BZip2File zip, + FT_Stream stream, + FT_Stream source ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Error error = FT_Err_Ok; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + zip->reset = 0; + + /* check .bz2 header */ + { + stream = source; + + error = ft_bzip2_check_header( stream ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + } + + /* initialize bzlib */ + bzstream->bzalloc = ft_bzip2_alloc; + bzstream->bzfree = ft_bzip2_free; + bzstream->opaque = zip->memory; + + bzstream->avail_in = 0; + bzstream->next_in = (char*)zip->buffer; + + if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK || + !bzstream->next_in ) + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + static void + ft_bzip2_file_done( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + + + BZ2_bzDecompressEnd( bzstream ); + + /* clear the rest */ + bzstream->bzalloc = NULL; + bzstream->bzfree = NULL; + bzstream->opaque = NULL; + bzstream->next_in = NULL; + bzstream->next_out = NULL; + bzstream->avail_in = 0; + bzstream->avail_out = 0; + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_bzip2_file_reset( FT_BZip2File zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( 0 ) ) + { + bz_stream* bzstream = &zip->bzstream; + + + BZ2_bzDecompressEnd( bzstream ); + + bzstream->avail_in = 0; + bzstream->next_in = (char*)zip->input; + bzstream->avail_out = 0; + bzstream->next_out = (char*)zip->buffer; + + zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + zip->reset = 0; + + BZ2_bzDecompressInit( bzstream, 0, 0 ); + } + + return error; + } + + + static FT_Error + ft_bzip2_file_fill_input( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Stream stream = zip->source; + FT_ULong size; + + + if ( stream->read ) + { + size = stream->read( stream, stream->pos, zip->input, + FT_BZIP2_BUFFER_SIZE ); + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + } + else + { + size = stream->size - stream->pos; + if ( size > FT_BZIP2_BUFFER_SIZE ) + size = FT_BZIP2_BUFFER_SIZE; + + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + + FT_MEM_COPY( zip->input, stream->base + stream->pos, size ); + } + stream->pos += size; + + bzstream->next_in = (char*)zip->input; + bzstream->avail_in = size; + + return FT_Err_Ok; + } + + + static FT_Error + ft_bzip2_file_fill_output( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Error error = FT_Err_Ok; + + + zip->cursor = zip->buffer; + bzstream->next_out = (char*)zip->cursor; + bzstream->avail_out = FT_BZIP2_BUFFER_SIZE; + + while ( bzstream->avail_out > 0 ) + { + int err; + + + if ( bzstream->avail_in == 0 ) + { + error = ft_bzip2_file_fill_input( zip ); + if ( error ) + break; + } + + err = BZ2_bzDecompress( bzstream ); + + if ( err != BZ_OK ) + { + zip->reset = 1; + + if ( err == BZ_STREAM_END ) + { + zip->limit = (FT_Byte*)bzstream->next_out; + if ( zip->limit == zip->cursor ) + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + else + { + zip->limit = zip->cursor; + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + } + } + + return error; + } + + + /* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */ + static FT_Error + ft_bzip2_file_skip_output( FT_BZip2File zip, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + + + for (;;) + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_bzip2_file_fill_output( zip ); + if ( error ) + break; + } + + return error; + } + + + static FT_ULong + ft_bzip2_file_io( FT_BZip2File zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* Reset inflate stream if seeking backwards or bzip reported an error. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos || zip->reset ) + { + error = ft_bzip2_file_reset( zip ); + if ( error ) + goto Exit; + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer, zip->cursor, delta ); + buffer += delta; + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_bzip2_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_bzip2_stream_close( FT_Stream stream ) + { + FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize bzip file descriptor */ + ft_bzip2_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + } + + + static unsigned long + ft_bzip2_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer; + + + return ft_bzip2_file_io( zip, offset, buffer, count ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory; + FT_BZip2File zip = NULL; + + + if ( !stream || !source ) + { + error = FT_THROW( Invalid_Stream_Handle ); + goto Exit; + } + + memory = source->memory; + + /* + * check the header right now; this prevents allocating unnecessary + * objects when we don't need them + */ + error = ft_bzip2_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_bzip2_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + stream->pos = 0; + stream->base = NULL; + stream->read = ft_bzip2_stream_io; + stream->close = ft_bzip2_stream_close; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_USE_BZIP2 */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return FT_THROW( Unimplemented_Feature ); + } + +#endif /* !FT_CONFIG_OPTION_USE_BZIP2 */ + + +/* END */ diff --git a/vendor/freetype/src/bzip2/rules.mk b/vendor/freetype/src/bzip2/rules.mk new file mode 100644 index 0000000..f4d3733 --- /dev/null +++ b/vendor/freetype/src/bzip2/rules.mk @@ -0,0 +1,64 @@ +# +# FreeType 2 BZIP2 support configuration rules +# + +# Copyright (C) 2010-2023 by +# Joel Klinghed. +# +# based on `src/lzw/rules.mk' +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# BZIP2 driver directory +# +BZIP2_DIR := $(SRC_DIR)/bzip2 + + +# compilation flags for the driver +# +BZIP2_COMPILE := $(CC) $(ANSIFLAGS) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# BZIP2 support sources (i.e., C files) +# +BZIP2_DRV_SRC := $(BZIP2_DIR)/ftbzip2.c + +# BZIP2 driver object(s) +# +# BZIP2_DRV_OBJ_M is used during `multi' builds +# BZIP2_DRV_OBJ_S is used during `single' builds +# +BZIP2_DRV_OBJ_M := $(OBJ_DIR)/ftbzip2.$O +BZIP2_DRV_OBJ_S := $(OBJ_DIR)/ftbzip2.$O + +# BZIP2 support source file for single build +# +BZIP2_DRV_SRC_S := $(BZIP2_DIR)/ftbzip2.c + + +# BZIP2 support - single object +# +$(BZIP2_DRV_OBJ_S): $(BZIP2_DRV_SRC_S) $(BZIP2_DRV_SRC) $(FREETYPE_H) $(BZIP2_DRV_H) + $(BZIP2_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(BZIP2_DRV_SRC_S)) + + +# BZIP2 support - multiple objects +# +$(OBJ_DIR)/%.$O: $(BZIP2_DIR)/%.c $(FREETYPE_H) $(BZIP2_DRV_H) + $(BZIP2_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(BZIP2_DRV_OBJ_S) +DRV_OBJS_M += $(BZIP2_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/cache/ftcache.c b/vendor/freetype/src/cache/ftcache.c new file mode 100644 index 0000000..1af2e67 --- /dev/null +++ b/vendor/freetype/src/cache/ftcache.c @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * ftcache.c + * + * The FreeType Caching sub-system (body only). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftcbasic.c" +#include "ftccache.c" +#include "ftccmap.c" +#include "ftcglyph.c" +#include "ftcimage.c" +#include "ftcmanag.c" +#include "ftcmru.c" +#include "ftcsbits.c" + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcbasic.c b/vendor/freetype/src/cache/ftcbasic.c new file mode 100644 index 0000000..24a56c8 --- /dev/null +++ b/vendor/freetype/src/cache/ftcbasic.c @@ -0,0 +1,638 @@ +/**************************************************************************** + * + * ftcbasic.c + * + * The FreeType basic cache interface (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ftcglyph.h" +#include "ftcimage.h" +#include "ftcsbits.h" + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + /* + * Basic Families + * + */ + typedef struct FTC_BasicAttrRec_ + { + FTC_ScalerRec scaler; + FT_UInt load_flags; + + } FTC_BasicAttrRec, *FTC_BasicAttrs; + +#define FTC_BASIC_ATTR_COMPARE( a, b ) \ + FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \ + (a)->load_flags == (b)->load_flags ) + +#define FTC_BASIC_ATTR_HASH( a ) \ + ( FTC_SCALER_HASH( &(a)->scaler ) + 31 * (a)->load_flags ) + + + typedef struct FTC_BasicQueryRec_ + { + FTC_GQueryRec gquery; + FTC_BasicAttrRec attrs; + + } FTC_BasicQueryRec, *FTC_BasicQuery; + + + typedef struct FTC_BasicFamilyRec_ + { + FTC_FamilyRec family; + FTC_BasicAttrRec attrs; + + } FTC_BasicFamilyRec, *FTC_BasicFamily; + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_basic_family_compare( FTC_MruNode ftcfamily, + FT_Pointer ftcquery ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; + + + return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_init( FTC_MruNode ftcfamily, + FT_Pointer ftcquery, + FT_Pointer ftccache ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; + FTC_Cache cache = (FTC_Cache)ftccache; + + + FTC_Family_Init( FTC_FAMILY( family ), cache ); + family->attrs = query->attrs; + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + ftc_basic_family_get_count( FTC_Family ftcfamily, + FTC_Manager manager ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FT_Face face; + FT_UInt result = 0; + + + error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id, + &face ); + + if ( error || !face ) + return result; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs ) + { + FT_TRACE1(( "ftc_basic_family_get_count:" + " the number of glyphs in this face is %ld,\n", + face->num_glyphs )); + FT_TRACE1(( " " + " which is too much and thus truncated\n" )); + } +#endif + + result = (FT_UInt)face->num_glyphs; + + return result; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_load_bitmap( FTC_Family ftcfamily, + FT_UInt gindex, + FTC_Manager manager, + FT_Face *aface ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FT_Size size; + + + error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size ); + if ( !error ) + { + FT_Face face = size->face; + + + error = FT_Load_Glyph( + face, + gindex, + (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER ); + if ( !error ) + *aface = face; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_load_glyph( FTC_Family ftcfamily, + FT_UInt gindex, + FTC_Cache cache, + FT_Glyph *aglyph ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FTC_Scaler scaler = &family->attrs.scaler; + FT_Face face; + FT_Size size; + + + /* we will now load the glyph image */ + error = FTC_Manager_LookupSize( cache->manager, + scaler, + &size ); + if ( !error ) + { + face = size->face; + + error = FT_Load_Glyph( face, + gindex, + (FT_Int)family->attrs.load_flags ); + if ( !error ) + { + if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || + face->glyph->format == FT_GLYPH_FORMAT_OUTLINE || + face->glyph->format == FT_GLYPH_FORMAT_SVG ) + { + /* ok, copy it */ + FT_Glyph glyph; + + + error = FT_Get_Glyph( face->glyph, &glyph ); + if ( !error ) + { + *aglyph = glyph; + goto Exit; + } + } + else + error = FT_THROW( Invalid_Argument ); + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode, + FT_Pointer ftcface_id, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_GNode gnode = (FTC_GNode)ftcgnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FTC_BasicFamily family = (FTC_BasicFamily)gnode->family; + FT_Bool result; + + + if ( list_changed ) + *list_changed = FALSE; + result = FT_BOOL( family->attrs.scaler.face_id == face_id ); + if ( result ) + { + /* we must call this function to avoid this node from appearing + * in later lookups with the same face_id! + */ + FTC_GNode_UnselectFamily( gnode, cache ); + } + return result; + } + + + /* + * + * basic image cache + * + */ + + static + const FTC_IFamilyClassRec ftc_basic_image_family_class = + { + { + sizeof ( FTC_BasicFamilyRec ), + + ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ + NULL, /* FTC_MruNode_ResetFunc node_reset */ + NULL /* FTC_MruNode_DoneFunc node_done */ + }, + + ftc_basic_family_load_glyph /* FTC_IFamily_LoadGlyphFunc family_load_glyph */ + }; + + + static + const FTC_GCacheClassRec ftc_basic_image_cache_class = + { + { + ftc_inode_new, /* FTC_Node_NewFunc node_new */ + ftc_inode_weight, /* FTC_Node_WeightFunc node_weight */ + ftc_gnode_compare, /* FTC_Node_CompareFunc node_compare */ + ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ + ftc_inode_free, /* FTC_Node_FreeFunc node_free */ + + sizeof ( FTC_GCacheRec ), + ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */ + ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */ + }, + + (FTC_MruListClass)&ftc_basic_image_family_class + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ) + { + return FTC_GCache_New( manager, &ftc_basic_image_cache_class, + (FTC_GCache*)acache ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ) + { + FTC_BasicQueryRec query; + FTC_Node node = 0; /* make compiler happy */ + FT_Error error; + FT_Offset hash; + + + /* some argument checks are delayed to `FTC_Cache_Lookup' */ + if ( !aglyph ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + *aglyph = NULL; + if ( anode ) + *anode = NULL; + + /* + * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', + * but public `FT_ImageType->flags' is of type `FT_Int32'. + * + * On 16bit systems, higher bits of type->flags cannot be handled. + */ +#if 0xFFFFFFFFUL > FT_UINT_MAX + if ( (type->flags & (FT_ULong)FT_UINT_MAX) ) + FT_TRACE1(( "FTC_ImageCache_Lookup:" + " higher bits in load_flags 0x%lx are dropped\n", + (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) )); +#endif + + query.attrs.scaler.face_id = type->face_id; + query.attrs.scaler.width = type->width; + query.attrs.scaler.height = type->height; + query.attrs.load_flags = (FT_UInt)type->flags; + + query.attrs.scaler.pixel = 1; + query.attrs.scaler.x_res = 0; /* make compilers happy */ + query.attrs.scaler.y_res = 0; + + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; + +#if 1 /* inlining is about 50% faster! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_gnode_compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, gindex, + FTC_GQUERY( &query ), + &node ); +#endif + if ( !error ) + { + *aglyph = FTC_INODE( node )->glyph; + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + } + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ) + { + FTC_BasicQueryRec query; + FTC_Node node = 0; /* make compiler happy */ + FT_Error error; + FT_Offset hash; + + + /* some argument checks are delayed to `FTC_Cache_Lookup' */ + if ( !aglyph || !scaler ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + *aglyph = NULL; + if ( anode ) + *anode = NULL; + + /* + * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', + * but public `FT_Face->face_flags' is of type `FT_Long'. + * + * On long > int systems, higher bits of load_flags cannot be handled. + */ +#if FT_ULONG_MAX > FT_UINT_MAX + if ( load_flags > FT_UINT_MAX ) + FT_TRACE1(( "FTC_ImageCache_LookupScaler:" + " higher bits in load_flags 0x%lx are dropped\n", + load_flags & ~((FT_ULong)FT_UINT_MAX) )); +#endif + + query.attrs.scaler = scaler[0]; + query.attrs.load_flags = (FT_UInt)load_flags; + + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; + + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_gnode_compare, + hash, gindex, + &query, + node, + error ); + if ( !error ) + { + *aglyph = FTC_INODE( node )->glyph; + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + } + + Exit: + return error; + } + + + /* + * + * basic small bitmap cache + * + */ + + static + const FTC_SFamilyClassRec ftc_basic_sbit_family_class = + { + { + sizeof ( FTC_BasicFamilyRec ), + ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ + NULL, /* FTC_MruNode_ResetFunc node_reset */ + NULL /* FTC_MruNode_DoneFunc node_done */ + }, + + ftc_basic_family_get_count, + ftc_basic_family_load_bitmap + }; + + + static + const FTC_GCacheClassRec ftc_basic_sbit_cache_class = + { + { + ftc_snode_new, /* FTC_Node_NewFunc node_new */ + ftc_snode_weight, /* FTC_Node_WeightFunc node_weight */ + ftc_snode_compare, /* FTC_Node_CompareFunc node_compare */ + ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ + ftc_snode_free, /* FTC_Node_FreeFunc node_free */ + + sizeof ( FTC_GCacheRec ), + ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */ + ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */ + }, + + (FTC_MruListClass)&ftc_basic_sbit_family_class + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ) + { + return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class, + (FTC_GCache*)acache ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *ansbit, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = 0; /* make compiler happy */ + FT_Offset hash; + + + if ( anode ) + *anode = NULL; + + /* other argument checks delayed to `FTC_Cache_Lookup' */ + if ( !ansbit ) + return FT_THROW( Invalid_Argument ); + + *ansbit = NULL; + + /* + * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', + * but public `FT_ImageType->flags' is of type `FT_Int32'. + * + * On 16bit systems, higher bits of type->flags cannot be handled. + */ +#if 0xFFFFFFFFUL > FT_UINT_MAX + if ( (type->flags & (FT_ULong)FT_UINT_MAX) ) + FT_TRACE1(( "FTC_ImageCache_Lookup:" + " higher bits in load_flags 0x%lx are dropped\n", + (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) )); +#endif + + query.attrs.scaler.face_id = type->face_id; + query.attrs.scaler.width = type->width; + query.attrs.scaler.height = type->height; + query.attrs.load_flags = (FT_UInt)type->flags; + + query.attrs.scaler.pixel = 1; + query.attrs.scaler.x_res = 0; /* make compilers happy */ + query.attrs.scaler.y_res = 0; + + /* beware, the hash must be the same for all glyph ranges! */ + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + + gindex / FTC_SBIT_ITEMS_PER_NODE; + +#if 1 /* inlining is about 50% faster! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_snode_compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, + gindex, + FTC_GQUERY( &query ), + &node ); +#endif + if ( error ) + goto Exit; + + *ansbit = FTC_SNODE( node )->sbits + + ( gindex - FTC_GNODE( node )->gindex ); + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *ansbit, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = 0; /* make compiler happy */ + FT_Offset hash; + + + if ( anode ) + *anode = NULL; + + /* other argument checks delayed to `FTC_Cache_Lookup' */ + if ( !ansbit || !scaler ) + return FT_THROW( Invalid_Argument ); + + *ansbit = NULL; + + /* + * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', + * but public `FT_Face->face_flags' is of type `FT_Long'. + * + * On long > int systems, higher bits of load_flags cannot be handled. + */ +#if FT_ULONG_MAX > FT_UINT_MAX + if ( load_flags > FT_UINT_MAX ) + FT_TRACE1(( "FTC_ImageCache_LookupScaler:" + " higher bits in load_flags 0x%lx are dropped\n", + load_flags & ~((FT_ULong)FT_UINT_MAX) )); +#endif + + query.attrs.scaler = scaler[0]; + query.attrs.load_flags = (FT_UInt)load_flags; + + /* beware, the hash must be the same for all glyph ranges! */ + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + + gindex / FTC_SBIT_ITEMS_PER_NODE; + + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_snode_compare, + hash, gindex, + &query, + node, + error ); + if ( error ) + goto Exit; + + *ansbit = FTC_SNODE( node )->sbits + + ( gindex - FTC_GNODE( node )->gindex ); + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + + Exit: + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/cache/ftccache.c b/vendor/freetype/src/cache/ftccache.c new file mode 100644 index 0000000..e069855 --- /dev/null +++ b/vendor/freetype/src/cache/ftccache.c @@ -0,0 +1,599 @@ +/**************************************************************************** + * + * ftccache.c + * + * The FreeType internal cache interface (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "ftcmanag.h" +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + +#define FTC_HASH_MAX_LOAD 2 +#define FTC_HASH_MIN_LOAD 1 +#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD ) + + /* this one _must_ be a power of 2! */ +#define FTC_HASH_INITIAL_SIZE 8 + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* add a new node to the head of the manager's circular MRU list */ + static void + ftc_node_mru_link( FTC_Node node, + FTC_Manager manager ) + { + void *nl = &manager->nodes_list; + + + FTC_MruNode_Prepend( (FTC_MruNode*)nl, + (FTC_MruNode)node ); + manager->num_nodes++; + } + + + /* remove a node from the manager's MRU list */ + static void + ftc_node_mru_unlink( FTC_Node node, + FTC_Manager manager ) + { + void *nl = &manager->nodes_list; + + + FTC_MruNode_Remove( (FTC_MruNode*)nl, + (FTC_MruNode)node ); + manager->num_nodes--; + } + + +#ifndef FTC_INLINE + + /* move a node to the head of the manager's MRU list */ + static void + ftc_node_mru_up( FTC_Node node, + FTC_Manager manager ) + { + FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list, + (FTC_MruNode)node ); + } + + + /* get a top bucket for specified hash from cache, + * body for FTC_NODE_TOP_FOR_HASH( cache, hash ) + */ + FT_LOCAL_DEF( FTC_Node* ) + ftc_get_top_node_for_hash( FTC_Cache cache, + FT_Offset hash ) + { + FT_Offset idx; + + + idx = hash & cache->mask; + if ( idx >= cache->p ) + idx = hash & ( cache->mask >> 1 ); + + return cache->buckets + idx; + } + +#endif /* !FTC_INLINE */ + + + /* Note that this function cannot fail. If we cannot re-size the + * buckets array appropriately, we simply degrade the hash table's + * performance! + */ + static void + ftc_cache_resize( FTC_Cache cache ) + { + for (;;) + { + FTC_Node node, *pnode; + FT_UFast p = cache->p; + FT_UFast size = cache->mask + 1; /* available size */ + FT_UFast half = size >> 1; + + + /* do we need to expand the buckets array? */ + if ( cache->slack < 0 ) + { + FTC_Node new_list = NULL; + + + /* try to expand the buckets array _before_ splitting + * the bucket lists + */ + if ( p == size ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + /* if we can't expand the array, leave immediately */ + if ( FT_QRENEW_ARRAY( cache->buckets, size, size * 2 ) ) + break; + + cache->mask = 2 * size - 1; + half = size; + } + + /* the bucket to split */ + pnode = cache->buckets + p - half; + + for (;;) + { + node = *pnode; + if ( !node ) + break; + + if ( node->hash & half ) + { + *pnode = node->link; + node->link = new_list; + new_list = node; + } + else + pnode = &node->link; + } + + cache->buckets[p] = new_list; + + cache->slack += FTC_HASH_MAX_LOAD; + cache->p = p + 1; + + FT_TRACE2(( "ftc_cache_resize: cache %u increased to %u hashes\n", + cache->index, cache->p )); + } + + /* do we need to shrink the buckets array? */ + else if ( cache->slack > (FT_Long)p * FTC_HASH_SUB_LOAD ) + { + FTC_Node old_list = cache->buckets[--p]; + + + if ( p < FTC_HASH_INITIAL_SIZE ) + break; + + if ( p == half ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + /* if we can't shrink the array, leave immediately */ + if ( FT_QRENEW_ARRAY( cache->buckets, size, half ) ) + break; + + cache->mask = half - 1; + } + + /* the bucket to merge */ + pnode = cache->buckets + p - half; + + while ( *pnode ) + pnode = &(*pnode)->link; + + *pnode = old_list; + + cache->slack -= FTC_HASH_MAX_LOAD; + cache->p = p; + + FT_TRACE2(( "ftc_cache_resize: cache %u decreased to %u hashes\n", + cache->index, cache->p )); + } + + /* otherwise, the hash table is balanced */ + else + break; + } + } + + + /* remove a node from its cache's hash table */ + static void + ftc_node_hash_unlink( FTC_Node node0, + FTC_Cache cache ) + { + FTC_Node *pnode = FTC_NODE_TOP_FOR_HASH( cache, node0->hash ); + + + for (;;) + { + FTC_Node node = *pnode; + + + if ( !node ) + { + FT_TRACE0(( "ftc_node_hash_unlink: unknown node\n" )); + return; + } + + if ( node == node0 ) + break; + + pnode = &node->link; + } + + *pnode = node0->link; + node0->link = NULL; + + cache->slack++; + ftc_cache_resize( cache ); + } + + + /* add a node to the `top' of its cache's hash table */ + static void + ftc_node_hash_link( FTC_Node node, + FTC_Cache cache ) + { + FTC_Node *pnode = FTC_NODE_TOP_FOR_HASH( cache, node->hash ); + + + node->link = *pnode; + *pnode = node; + + cache->slack--; + ftc_cache_resize( cache ); + } + + + /* remove a node from the cache manager */ + FT_LOCAL_DEF( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ) + { + FTC_Cache cache; + + +#ifdef FT_DEBUG_ERROR + /* find node's cache */ + if ( node->cache_index >= manager->num_caches ) + { + FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + cache = manager->caches[node->cache_index]; + +#ifdef FT_DEBUG_ERROR + if ( !cache ) + { + FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* remove node from cache's hash table */ + ftc_node_hash_unlink( node, cache ); + + /* now finalize it */ + cache->clazz.node_free( node, cache ); + +#if 0 + /* check, just in case of general corruption :-) */ + if ( manager->num_nodes == 0 ) + FT_TRACE0(( "ftc_node_destroy: invalid cache node count (%u)\n", + manager->num_nodes )); +#endif + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ABSTRACT CACHE CLASS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + ftc_cache_init( FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + cache->p = FTC_HASH_INITIAL_SIZE; + cache->mask = FTC_HASH_INITIAL_SIZE - 1; + cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD; + + FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE ); + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ) + { + return ftc_cache_init( cache ); + } + + + FT_LOCAL_DEF( void ) + ftc_cache_done( FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + + + if ( cache->buckets ) + { + FTC_Manager manager = cache->manager; + FT_UFast count = cache->p; + FT_UFast i; + + + for ( i = 0; i < count; i++ ) + { + FTC_Node node = cache->buckets[i], next; + + + while ( node ) + { + next = node->link; + node->link = NULL; + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* now finalize it */ + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + cache->clazz.node_free( node, cache ); + node = next; + } + } + } + + FT_FREE( cache->buckets ); + + cache->p = 0; + cache->mask = 0; + cache->slack = 0; + } + + + FT_LOCAL_DEF( void ) + FTC_Cache_Done( FTC_Cache cache ) + { + ftc_cache_done( cache ); + } + + + static void + ftc_cache_add( FTC_Cache cache, + FT_Offset hash, + FTC_Node node ) + { + node->hash = hash; + node->cache_index = (FT_UShort)cache->index; + node->ref_count = 0; + + ftc_node_hash_link( node, cache ); + ftc_node_mru_link( node, cache->manager ); + + { + FTC_Manager manager = cache->manager; + + + manager->cur_weight += cache->clazz.node_weight( node, cache ); + + if ( manager->cur_weight >= manager->max_weight ) + { + node->ref_count++; + FTC_Manager_Compress( manager ); + node->ref_count--; + } + } + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ) + { + FT_Error error; + FTC_Node node; + + + /* + * We use the FTC_CACHE_TRYLOOP macros to support out-of-memory + * errors (OOM) correctly, i.e., by flushing the cache progressively + * in order to make more room. + */ + + FTC_CACHE_TRYLOOP( cache ) + { + error = cache->clazz.node_new( &node, query, cache ); + } + FTC_CACHE_TRYLOOP_END( NULL ) + + if ( error ) + node = NULL; + else + { + /* don't assume that the cache has the same number of buckets, since + * our allocation request might have triggered global cache flushing + */ + ftc_cache_add( cache, hash, node ); + } + + *anode = node; + return error; + } + + +#ifndef FTC_INLINE + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ) + { + FTC_Node* bucket; + FTC_Node* pnode; + FTC_Node node; + FT_Error error = FT_Err_Ok; + FT_Bool list_changed = FALSE; + + FTC_Node_CompareFunc compare = cache->clazz.node_compare; + + + if ( !cache || !anode ) + return FT_THROW( Invalid_Argument ); + + /* Go to the `top' node of the list sharing same masked hash */ + bucket = pnode = FTC_NODE_TOP_FOR_HASH( cache, hash ); + + /* Lookup a node with exactly same hash and queried properties. */ + /* NOTE: _nodcomp() may change the linked list to reduce memory. */ + for (;;) + { + node = *pnode; + if ( !node ) + goto NewNode; + + if ( node->hash == hash && + compare( node, query, cache, &list_changed ) ) + break; + + pnode = &node->link; + } + + if ( list_changed ) + { + /* Update bucket by modified linked list */ + bucket = pnode = FTC_NODE_TOP_FOR_HASH( cache, hash ); + + /* Update pnode by modified linked list */ + while ( *pnode != node ) + { + if ( !*pnode ) + { + FT_ERROR(( "FTC_Cache_Lookup: oops!!! node missing\n" )); + goto NewNode; + } + else + pnode = &(*pnode)->link; + } + } + + /* Reorder the list to move the found node to the `top' */ + if ( node != *bucket ) + { + *pnode = node->link; + node->link = *bucket; + *bucket = node; + } + + /* move to head of MRU list */ + { + FTC_Manager manager = cache->manager; + + + if ( node != manager->nodes_list ) + ftc_node_mru_up( node, manager ); + } + *anode = node; + + return error; + + NewNode: + return FTC_Cache_NewNode( cache, hash, query, anode ); + } + +#endif /* !FTC_INLINE */ + + + FT_LOCAL_DEF( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ) + { + FTC_Manager manager = cache->manager; + FTC_Node frees = NULL; + FT_UFast count = cache->p; + FT_UFast i; + + + for ( i = 0; i < count; i++ ) + { + FTC_Node* pnode = cache->buckets + i; + + + for (;;) + { + FTC_Node node = *pnode; + FT_Bool list_changed = FALSE; + + + if ( !node ) + break; + + if ( cache->clazz.node_remove_faceid( node, face_id, + cache, &list_changed ) ) + { + *pnode = node->link; + node->link = frees; + frees = node; + } + else + pnode = &node->link; + } + } + + /* remove all nodes in the free list */ + while ( frees ) + { + FTC_Node node; + + + node = frees; + frees = node->link; + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + ftc_node_mru_unlink( node, manager ); + + cache->clazz.node_free( node, cache ); + + cache->slack++; + } + + ftc_cache_resize( cache ); + } + + +/* END */ diff --git a/vendor/freetype/src/cache/ftccache.h b/vendor/freetype/src/cache/ftccache.h new file mode 100644 index 0000000..850d255 --- /dev/null +++ b/vendor/freetype/src/cache/ftccache.h @@ -0,0 +1,355 @@ +/**************************************************************************** + * + * ftccache.h + * + * FreeType internal cache interface (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCCACHE_H_ +#define FTCCACHE_H_ + +#include +#include "ftcmru.h" + +FT_BEGIN_HEADER + +#define FTC_FACE_ID_HASH( i ) \ + ( ( (FT_Offset)(i) >> 3 ) ^ ( (FT_Offset)(i) << 7 ) ) + + /* handle to cache object */ + typedef struct FTC_CacheRec_* FTC_Cache; + + /* handle to cache class */ + typedef const struct FTC_CacheClassRec_* FTC_CacheClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * Each cache controls one or more cache nodes. Each node is part of + * the global_lru list of the manager. Its `data' field however is used + * as a reference count for now. + * + * A node can be anything, depending on the type of information held by + * the cache. It can be an individual glyph image, a set of bitmaps + * glyphs for a given size, some metrics, etc. + * + */ + + /* structure size should be 20 bytes on 32-bits machines */ + typedef struct FTC_NodeRec_ + { + FTC_MruNodeRec mru; /* circular mru list pointer */ + FTC_Node link; /* used for hashing */ + FT_Offset hash; /* used for hashing too */ + FT_UShort cache_index; /* index of cache the node belongs to */ + FT_Short ref_count; /* reference count for this node */ + + } FTC_NodeRec; + + +#define FTC_NODE( x ) ( (FTC_Node)(x) ) +#define FTC_NODE_P( x ) ( (FTC_Node*)(x) ) + +#define FTC_NODE_NEXT( x ) FTC_NODE( (x)->mru.next ) +#define FTC_NODE_PREV( x ) FTC_NODE( (x)->mru.prev ) + + /* address the hash table entries */ +#ifdef FTC_INLINE +#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \ + ( ( cache )->buckets + \ + ( ( ( ( hash ) & ( cache )->mask ) >= ( cache )->p ) \ + ? ( ( hash ) & ( ( cache )->mask >> 1 ) ) \ + : ( ( hash ) & ( cache )->mask ) ) ) +#else + FT_LOCAL( FTC_Node* ) + ftc_get_top_node_for_hash( FTC_Cache cache, + FT_Offset hash ); +#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \ + ftc_get_top_node_for_hash( ( cache ), ( hash ) ) +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* initialize a new cache node */ + typedef FT_Error + (*FTC_Node_NewFunc)( FTC_Node *pnode, + FT_Pointer query, + FTC_Cache cache ); + + typedef FT_Offset + (*FTC_Node_WeightFunc)( FTC_Node node, + FTC_Cache cache ); + + /* compare a node to a given key pair */ + typedef FT_Bool + (*FTC_Node_CompareFunc)( FTC_Node node, + FT_Pointer key, + FTC_Cache cache, + FT_Bool* list_changed ); + + + typedef void + (*FTC_Node_FreeFunc)( FTC_Node node, + FTC_Cache cache ); + + typedef FT_Error + (*FTC_Cache_InitFunc)( FTC_Cache cache ); + + typedef void + (*FTC_Cache_DoneFunc)( FTC_Cache cache ); + + + typedef struct FTC_CacheClassRec_ + { + FTC_Node_NewFunc node_new; + FTC_Node_WeightFunc node_weight; + FTC_Node_CompareFunc node_compare; + FTC_Node_CompareFunc node_remove_faceid; + FTC_Node_FreeFunc node_free; + + FT_Offset cache_size; + FTC_Cache_InitFunc cache_init; + FTC_Cache_DoneFunc cache_done; + + } FTC_CacheClassRec; + + + /* each cache really implements a hash table to manage its nodes */ + /* the number of the table entries (buckets) can change dynamically */ + /* each bucket contains a linked lists of nodes for a given hash */ + typedef struct FTC_CacheRec_ + { + FT_UFast p; /* hash table counter */ + FT_UFast mask; /* hash table index range */ + FT_Long slack; + FTC_Node* buckets; + + FTC_CacheClassRec clazz; /* local copy, for speed */ + + FTC_Manager manager; + FT_Memory memory; + FT_UInt index; /* in manager's table */ + + FTC_CacheClass org_class; /* original class pointer */ + + } FTC_CacheRec; + + +#define FTC_CACHE( x ) ( (FTC_Cache)(x) ) +#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) + + + /* default cache initialize */ + FT_LOCAL( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ); + + /* default cache finalizer */ + FT_LOCAL( void ) + FTC_Cache_Done( FTC_Cache cache ); + + /* Call this function to look up the cache. If no corresponding + * node is found, a new one is automatically created. This function + * is capable of flushing the cache adequately to make room for the + * new cache object. + */ + +#ifndef FTC_INLINE + FT_LOCAL( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ); +#endif + + FT_LOCAL( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ); + + /* Remove all nodes that relate to a given face_id. This is useful + * when un-installing fonts. Note that if a cache node relates to + * the face_id but is locked (i.e., has `ref_count > 0'), the node + * will _not_ be destroyed, but its internal face_id reference will + * be modified. + * + * The final result will be that the node will never come back + * in further lookup requests, and will be flushed on demand from + * the cache normally when its reference count reaches 0. + */ + FT_LOCAL( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ); + + +#ifdef FTC_INLINE + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_Node *_bucket, *_pnode, _node; \ + FTC_Cache _cache = FTC_CACHE( cache ); \ + FT_Offset _hash = (FT_Offset)(hash); \ + FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \ + FT_Bool _list_changed = FALSE; \ + \ + \ + error = FT_Err_Ok; \ + node = NULL; \ + \ + /* Go to the `top' node of the list sharing same masked hash */ \ + _bucket = _pnode = FTC_NODE_TOP_FOR_HASH( _cache, _hash ); \ + \ + /* Look up a node with identical hash and queried properties. */ \ + /* NOTE: _nodcomp() may change the linked list to reduce memory. */ \ + for (;;) \ + { \ + _node = *_pnode; \ + if ( !_node ) \ + goto NewNode_; \ + \ + if ( _node->hash == _hash && \ + _nodcomp( _node, query, _cache, &_list_changed ) ) \ + break; \ + \ + _pnode = &_node->link; \ + } \ + \ + if ( _list_changed ) \ + { \ + /* Update _bucket by possibly modified linked list */ \ + _bucket = _pnode = FTC_NODE_TOP_FOR_HASH( _cache, _hash ); \ + \ + /* Update _pnode by possibly modified linked list */ \ + while ( *_pnode != _node ) \ + { \ + if ( !*_pnode ) \ + { \ + FT_ERROR(( "FTC_CACHE_LOOKUP_CMP: oops!!! node missing\n" )); \ + goto NewNode_; \ + } \ + else \ + _pnode = &(*_pnode)->link; \ + } \ + } \ + \ + /* Reorder the list to move the found node to the `top' */ \ + if ( _node != *_bucket ) \ + { \ + *_pnode = _node->link; \ + _node->link = *_bucket; \ + *_bucket = _node; \ + } \ + \ + /* Update MRU list */ \ + { \ + FTC_Manager _manager = _cache->manager; \ + void* _nl = &_manager->nodes_list; \ + \ + \ + if ( _node != _manager->nodes_list ) \ + FTC_MruNode_Up( (FTC_MruNode*)_nl, \ + (FTC_MruNode)_node ); \ + } \ + goto Ok_; \ + \ + NewNode_: \ + error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \ + \ + Ok_: \ + node = _node; \ + FT_END_STMNT + +#else /* !FTC_INLINE */ + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, \ + (FTC_Node*)&(node) ); \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + + /* + * This macro, together with FTC_CACHE_TRYLOOP_END, defines a retry + * loop to flush the cache repeatedly in case of memory overflows. + * + * It is used when creating a new cache node, or within a lookup + * that needs to allocate data (e.g. the sbit cache lookup). + * + * Example: + * + * { + * FTC_CACHE_TRYLOOP( cache ) + * error = load_data( ... ); + * FTC_CACHE_TRYLOOP_END() + * } + * + */ +#define FTC_CACHE_TRYLOOP( cache ) \ + { \ + FTC_Manager _try_manager = FTC_CACHE( cache )->manager; \ + FT_UInt _try_count = 4; \ + \ + \ + for (;;) \ + { \ + FT_UInt _try_done; + + +#define FTC_CACHE_TRYLOOP_END( list_changed ) \ + if ( !error || FT_ERR_NEQ( error, Out_Of_Memory ) ) \ + break; \ + \ + _try_done = FTC_Manager_FlushN( _try_manager, _try_count ); \ + if ( _try_done > 0 && list_changed != NULL ) \ + *(FT_Bool*)( list_changed ) = TRUE; \ + \ + if ( _try_done == 0 ) \ + break; \ + \ + if ( _try_done == _try_count ) \ + { \ + _try_count *= 2; \ + if ( _try_count < _try_done || \ + _try_count > _try_manager->num_nodes ) \ + _try_count = _try_manager->num_nodes; \ + } \ + } \ + } + + /* */ + +FT_END_HEADER + + +#endif /* FTCCACHE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftccback.h b/vendor/freetype/src/cache/ftccback.h new file mode 100644 index 0000000..5f9db21 --- /dev/null +++ b/vendor/freetype/src/cache/ftccback.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * + * ftccback.h + * + * Callback functions of the caching sub-system (specification only). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTCCBACK_H_ +#define FTCCBACK_H_ + +#include +#include "ftcmru.h" +#include "ftcimage.h" +#include "ftcmanag.h" +#include "ftcglyph.h" +#include "ftcsbits.h" + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + ftc_inode_free( FTC_Node inode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + ftc_inode_new( FTC_Node *pinode, + FT_Pointer gquery, + FTC_Cache cache ); + + FT_LOCAL( FT_Offset ) + ftc_inode_weight( FTC_Node inode, + FTC_Cache cache ); + + + FT_LOCAL( void ) + ftc_snode_free( FTC_Node snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + ftc_snode_new( FTC_Node *psnode, + FT_Pointer gquery, + FTC_Cache cache ); + + FT_LOCAL( FT_Offset ) + ftc_snode_weight( FTC_Node snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Bool ) + ftc_snode_compare( FTC_Node snode, + FT_Pointer gquery, + FTC_Cache cache, + FT_Bool* list_changed ); + + + FT_LOCAL( FT_Bool ) + ftc_gnode_compare( FTC_Node gnode, + FT_Pointer gquery, + FTC_Cache cache, + FT_Bool* list_changed ); + + + FT_LOCAL( FT_Error ) + ftc_gcache_init( FTC_Cache cache ); + + FT_LOCAL( void ) + ftc_gcache_done( FTC_Cache cache ); + + + FT_LOCAL( FT_Error ) + ftc_cache_init( FTC_Cache cache ); + + FT_LOCAL( void ) + ftc_cache_done( FTC_Cache cache ); + + FT_LOCAL( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ); + +FT_END_HEADER + +#endif /* FTCCBACK_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftccmap.c b/vendor/freetype/src/cache/ftccmap.c new file mode 100644 index 0000000..84f22a6 --- /dev/null +++ b/vendor/freetype/src/cache/ftccmap.c @@ -0,0 +1,323 @@ +/**************************************************************************** + * + * ftccmap.c + * + * FreeType CharMap cache (body) + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include "ftcmanag.h" +#include +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + /************************************************************************** + * + * Each FTC_CMapNode contains a simple array to map a range of character + * codes to equivalent glyph indices. + * + * For now, the implementation is very basic: Each node maps a range of + * 128 consecutive character codes to their corresponding glyph indices. + * + * We could do more complex things, but I don't think it is really very + * useful. + * + */ + + + /* number of glyph indices / character code per node */ +#define FTC_CMAP_INDICES_MAX 128 + + /* compute a query/node hash */ +#define FTC_CMAP_HASH( faceid, index, charcode ) \ + ( FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \ + ( (charcode) / FTC_CMAP_INDICES_MAX ) ) + + /* the charmap query */ + typedef struct FTC_CMapQueryRec_ + { + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 char_code; + + } FTC_CMapQueryRec, *FTC_CMapQuery; + +#define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x)) + + /* the cmap cache node */ + typedef struct FTC_CMapNodeRec_ + { + FTC_NodeRec node; + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 first; /* first character in node */ + FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */ + + } FTC_CMapNodeRec, *FTC_CMapNode; + +#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) ) + + /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */ + /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */ +#define FTC_CMAP_UNKNOWN (FT_UInt16)~0 + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHARMAP NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( void ) + ftc_cmap_node_free( FTC_Node ftcnode, + FTC_Cache cache ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FT_Memory memory = cache->memory; + + + FT_FREE( node ); + } + + + /* initialize a new cmap node */ + FT_CALLBACK_DEF( FT_Error ) + ftc_cmap_node_new( FTC_Node *ftcanode, + FT_Pointer ftcquery, + FTC_Cache cache ) + { + FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode; + FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; + FT_Error error; + FT_Memory memory = cache->memory; + FTC_CMapNode node = NULL; + FT_UInt nn; + + + if ( !FT_QNEW( node ) ) + { + node->face_id = query->face_id; + node->cmap_index = query->cmap_index; + node->first = (query->char_code / FTC_CMAP_INDICES_MAX) * + FTC_CMAP_INDICES_MAX; + + for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ ) + node->indices[nn] = FTC_CMAP_UNKNOWN; + } + + *anode = node; + return error; + } + + + /* compute the weight of a given cmap node */ + FT_CALLBACK_DEF( FT_Offset ) + ftc_cmap_node_weight( FTC_Node cnode, + FTC_Cache cache ) + { + FT_UNUSED( cnode ); + FT_UNUSED( cache ); + + return sizeof ( *cnode ); + } + + + /* compare a cmap node to a given query */ + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_compare( FTC_Node ftcnode, + FT_Pointer ftcquery, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; + FT_UNUSED( cache ); + + + if ( list_changed ) + *list_changed = FALSE; + if ( node->face_id == query->face_id && + node->cmap_index == query->cmap_index ) + { + FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); + + + return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); + } + + return 0; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_remove_faceid( FTC_Node ftcnode, + FT_Pointer ftcface_id, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FT_UNUSED( cache ); + + + if ( list_changed ) + *list_changed = FALSE; + return FT_BOOL( node->face_id == face_id ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE CACHE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static + const FTC_CacheClassRec ftc_cmap_cache_class = + { + ftc_cmap_node_new, /* FTC_Node_NewFunc node_new */ + ftc_cmap_node_weight, /* FTC_Node_WeightFunc node_weight */ + ftc_cmap_node_compare, /* FTC_Node_CompareFunc node_compare */ + ftc_cmap_node_remove_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ + ftc_cmap_node_free, /* FTC_Node_FreeFunc node_free */ + + sizeof ( FTC_CacheRec ), + ftc_cache_init, /* FTC_Cache_InitFunc cache_init */ + ftc_cache_done, /* FTC_Cache_DoneFunc cache_done */ + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ) + { + return FTC_Manager_RegisterCache( manager, + &ftc_cmap_cache_class, + FTC_CACHE_P( acache ) ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ) + { + FTC_Cache cache = FTC_CACHE( cmap_cache ); + FTC_CMapQueryRec query; + FTC_Node node; + FT_Error error; + FT_UInt gindex = 0; + FT_Offset hash; + FT_Int no_cmap_change = 0; + + + if ( cmap_index < 0 ) + { + /* Treat a negative cmap index as a special value, meaning that you */ + /* don't want to change the FT_Face's character map through this */ + /* call. This can be useful if the face requester callback already */ + /* sets the face's charmap to the appropriate value. */ + + no_cmap_change = 1; + cmap_index = 0; + } + + if ( !cache ) + { + FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" )); + return 0; + } + + query.face_id = face_id; + query.cmap_index = (FT_UInt)cmap_index; + query.char_code = char_code; + + hash = FTC_CMAP_HASH( face_id, (FT_UInt)cmap_index, char_code ); + +#if 1 + FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query, + node, error ); +#else + error = FTC_Cache_Lookup( cache, hash, &query, &node ); +#endif + if ( error ) + goto Exit; + + FT_ASSERT( char_code - FTC_CMAP_NODE( node )->first < + FTC_CMAP_INDICES_MAX ); + + /* something rotten can happen with rogue clients */ + if ( char_code - FTC_CMAP_NODE( node )->first >= FTC_CMAP_INDICES_MAX ) + return 0; /* XXX: should return appropriate error */ + + gindex = FTC_CMAP_NODE( node )->indices[char_code - + FTC_CMAP_NODE( node )->first]; + if ( gindex == FTC_CMAP_UNKNOWN ) + { + FT_Face face; + + + gindex = 0; + + error = FTC_Manager_LookupFace( cache->manager, + FTC_CMAP_NODE( node )->face_id, + &face ); + if ( error ) + goto Exit; + + if ( cmap_index < face->num_charmaps ) + { + FT_CharMap old = face->charmap; + FT_CharMap cmap = face->charmaps[cmap_index]; + + + if ( !no_cmap_change ) + face->charmap = cmap; + + gindex = FT_Get_Char_Index( face, char_code ); + + if ( !no_cmap_change ) + face->charmap = old; + } + + FTC_CMAP_NODE( node )->indices[char_code - + FTC_CMAP_NODE( node )->first] + = (FT_UShort)gindex; + } + + Exit: + return gindex; + } + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcerror.h b/vendor/freetype/src/cache/ftcerror.h new file mode 100644 index 0000000..dc1a620 --- /dev/null +++ b/vendor/freetype/src/cache/ftcerror.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * ftcerror.h + * + * Caching sub-system error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the caching sub-system error enumeration + * constants. + * + */ + +#ifndef FTCERROR_H_ +#define FTCERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX FTC_Err_ +#define FT_ERR_BASE FT_Mod_Err_Cache + +#include + +#endif /* FTCERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcglyph.c b/vendor/freetype/src/cache/ftcglyph.c new file mode 100644 index 0000000..d344733 --- /dev/null +++ b/vendor/freetype/src/cache/ftcglyph.c @@ -0,0 +1,204 @@ +/**************************************************************************** + * + * ftcglyph.c + * + * FreeType Glyph Image (FT_Glyph) cache (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include "ftcglyph.h" +#include + +#include "ftccback.h" +#include "ftcerror.h" + + + /* create a new chunk node, setting its cache index and ref count */ + FT_LOCAL_DEF( void ) + FTC_GNode_Init( FTC_GNode gnode, + FT_UInt gindex, + FTC_Family family ) + { + gnode->family = family; + gnode->gindex = gindex; + family->num_nodes++; + } + + + FT_LOCAL_DEF( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ) + { + FTC_Family family = gnode->family; + + + gnode->family = NULL; + if ( family && --family->num_nodes == 0 ) + FTC_FAMILY_FREE( family, cache ); + } + + + FT_LOCAL_DEF( void ) + FTC_GNode_Done( FTC_GNode gnode, + FTC_Cache cache ) + { + /* finalize the node */ + gnode->gindex = 0; + + FTC_GNode_UnselectFamily( gnode, cache ); + } + + + FT_LOCAL_DEF( FT_Bool ) + ftc_gnode_compare( FTC_Node ftcgnode, + FT_Pointer ftcgquery, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_GNode gnode = (FTC_GNode)ftcgnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + FT_UNUSED( cache ); + + + if ( list_changed ) + *list_changed = FALSE; + return FT_BOOL( gnode->family == gquery->family && + gnode->gindex == gquery->gindex ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHUNK SETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ) + { + FTC_GCacheClass clazz = FTC_CACHE_GCACHE_CLASS( cache ); + + + family->clazz = clazz->family_class; + family->num_nodes = 0; + family->cache = cache; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_gcache_init( FTC_Cache cache ) + { + FTC_GCache gcache = (FTC_GCache)cache; + FT_Error error; + + + error = FTC_Cache_Init( cache ); + if ( !error ) + { + FTC_GCacheClass clazz = (FTC_GCacheClass)cache->org_class; + + FTC_MruList_Init( &gcache->families, + clazz->family_class, + 0, /* no maximum here! */ + cache, + cache->memory ); + } + + return error; + } + + +#if 0 + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_Init( FTC_GCache gcache ) + { + return ftc_gcache_init( FTC_CACHE( gcache ) ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( void ) + ftc_gcache_done( FTC_Cache cache ) + { + FTC_GCache gcache = (FTC_GCache)cache; + + + FTC_Cache_Done( cache ); + FTC_MruList_Done( &gcache->families ); + } + + +#if 0 + + FT_LOCAL_DEF( void ) + FTC_GCache_Done( FTC_GCache gcache ) + { + ftc_gcache_done( FTC_CACHE( gcache ) ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ) + { + return FTC_Manager_RegisterCache( manager, (FTC_CacheClass)clazz, + (FTC_Cache*)acache ); + } + + +#ifndef FTC_INLINE + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_Lookup( FTC_GCache gcache, + FT_Offset hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ) + { + FT_Error error; + + + query->gindex = gindex; + + FTC_MRULIST_LOOKUP( &cache->families, query, query->family, error ); + if ( !error ) + { + FTC_Family family = query->family; + + + /* prevent the family from being destroyed too early when an */ + /* out-of-memory condition occurs during glyph node initialization. */ + family->num_nodes++; + + error = FTC_Cache_Lookup( FTC_CACHE( gcache ), hash, query, anode ); + + if ( --family->num_nodes == 0 ) + FTC_FAMILY_FREE( family, cache ); + } + return error; + } + +#endif /* !FTC_INLINE */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcglyph.h b/vendor/freetype/src/cache/ftcglyph.h new file mode 100644 index 0000000..0181e98 --- /dev/null +++ b/vendor/freetype/src/cache/ftcglyph.h @@ -0,0 +1,315 @@ +/**************************************************************************** + * + * ftcglyph.h + * + * FreeType abstract glyph cache (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + * + * FTC_GCache is an _abstract_ cache object optimized to store glyph + * data. It works as follows: + * + * - It manages FTC_GNode objects. Each one of them can hold one or more + * glyph `items'. Item types are not specified in the FTC_GCache but + * in classes that extend it. + * + * - Glyph attributes, like face ID, character size, render mode, etc., + * can be grouped into abstract `glyph families'. This avoids storing + * the attributes within the FTC_GCache, since it is likely that many + * FTC_GNodes will belong to the same family in typical uses. + * + * - Each FTC_GNode is thus an FTC_Node with two additional fields: + * + * * gindex: A glyph index, or the first index in a glyph range. + * * family: A pointer to a glyph `family'. + * + * - Family types are not fully specific in the FTC_Family type, but + * by classes that extend it. + * + * Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. + * They share an FTC_Family sub-class called FTC_BasicFamily which is + * used to store the following data: face ID, pixel/point sizes, load + * flags. For more details see the file `src/cache/ftcbasic.c'. + * + * Client applications can extend FTC_GNode with their own FTC_GNode + * and FTC_Family sub-classes to implement more complex caches (e.g., + * handling automatic synthesis, like obliquing & emboldening, colored + * glyphs, etc.). + * + * See also the FTC_ICache & FTC_SCache classes in `ftcimage.h' and + * `ftcsbits.h', which both extend FTC_GCache with additional + * optimizations. + * + * A typical FTC_GCache implementation must provide at least the + * following: + * + * - FTC_GNode sub-class, e.g. MyNode, with relevant methods: + * my_node_new (must call FTC_GNode_Init) + * my_node_free (must call FTC_GNode_Done) + * my_node_compare (must call ftc_gnode_compare) + * my_node_remove_faceid (must call ftc_gnode_unselect in case + * of match) + * + * - FTC_Family sub-class, e.g. MyFamily, with relevant methods: + * my_family_compare + * my_family_init + * my_family_reset (optional) + * my_family_done + * + * - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query + * data. + * + * - Constant structures for a FTC_GNodeClass. + * + * - MyCacheNew() can be implemented easily as a call to the convenience + * function FTC_GCache_New. + * + * - MyCacheLookup with a call to FTC_GCache_Lookup. This function will + * automatically: + * + * - Search for the corresponding family in the cache, or create + * a new one if necessary. Put it in FTC_GQUERY(myquery).family + * + * - Call FTC_Cache_Lookup. + * + * If it returns NULL, you should create a new node, then call + * ftc_cache_add as usual. + */ + + + /************************************************************************** + * + * Important: The functions defined in this file are only used to + * implement an abstract glyph cache class. You need to + * provide additional logic to implement a complete cache. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef FTCGLYPH_H_ +#define FTCGLYPH_H_ + + +#include "ftcmanag.h" + + +FT_BEGIN_HEADER + + + /* + * We can group glyphs into `families'. Each family correspond to a + * given face ID, character size, transform, etc. + * + * Families are implemented as MRU list nodes. They are + * reference-counted. + */ + + typedef struct FTC_FamilyRec_ + { + FTC_MruNodeRec mrunode; + FT_UInt num_nodes; /* current number of nodes in this family */ + FTC_Cache cache; + FTC_MruListClass clazz; + + } FTC_FamilyRec, *FTC_Family; + +#define FTC_FAMILY( x ) ( (FTC_Family)(x) ) +#define FTC_FAMILY_P( x ) ( (FTC_Family*)(x) ) + + + typedef struct FTC_GNodeRec_ + { + FTC_NodeRec node; + FTC_Family family; + FT_UInt gindex; + + } FTC_GNodeRec, *FTC_GNode; + +#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) +#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) + + + typedef struct FTC_GQueryRec_ + { + FT_UInt gindex; + FTC_Family family; + + } FTC_GQueryRec, *FTC_GQuery; + +#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) ) + + + /************************************************************************** + * + * These functions are exported so that they can be called from + * user-provided cache classes; otherwise, they are really part of the + * cache sub-system internals. + */ + + /* must be called by derived FTC_Node_InitFunc routines */ + FT_LOCAL( void ) + FTC_GNode_Init( FTC_GNode node, + FT_UInt gindex, /* glyph index for node */ + FTC_Family family ); + + /* call this function to clear a node's family -- this is necessary */ + /* to implement the `node_remove_faceid' cache method correctly */ + FT_LOCAL( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ); + + /* must be called by derived FTC_Node_DoneFunc routines */ + FT_LOCAL( void ) + FTC_GNode_Done( FTC_GNode node, + FTC_Cache cache ); + + + FT_LOCAL( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ); + + typedef struct FTC_GCacheRec_ + { + FTC_CacheRec cache; + FTC_MruListRec families; + + } FTC_GCacheRec, *FTC_GCache; + +#define FTC_GCACHE( x ) ((FTC_GCache)(x)) + + +#if 0 + /* can be used as @FTC_Cache_InitFunc */ + FT_LOCAL( FT_Error ) + FTC_GCache_Init( FTC_GCache cache ); +#endif + + +#if 0 + /* can be used as @FTC_Cache_DoneFunc */ + FT_LOCAL( void ) + FTC_GCache_Done( FTC_GCache cache ); +#endif + + + /* the glyph cache class adds fields for the family implementation */ + typedef struct FTC_GCacheClassRec_ + { + FTC_CacheClassRec clazz; + FTC_MruListClass family_class; + + } FTC_GCacheClassRec; + + typedef const FTC_GCacheClassRec* FTC_GCacheClass; + +#define FTC_GCACHE_CLASS( x ) ((FTC_GCacheClass)(x)) + +#define FTC_CACHE_GCACHE_CLASS( x ) \ + FTC_GCACHE_CLASS( FTC_CACHE( x )->org_class ) +#define FTC_CACHE_FAMILY_CLASS( x ) \ + ( (FTC_MruListClass)FTC_CACHE_GCACHE_CLASS( x )->family_class ) + + + /* convenience function; use it instead of FTC_Manager_Register_Cache */ + FT_LOCAL( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ); + +#ifndef FTC_INLINE + FT_LOCAL( FT_Error ) + FTC_GCache_Lookup( FTC_GCache cache, + FT_Offset hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ); +#endif + + + /* */ + + +#define FTC_FAMILY_FREE( family, cache ) \ + FTC_MruList_Remove( &FTC_GCACHE((cache))->families, \ + (FTC_MruNode)(family) ) + + +#ifdef FTC_INLINE + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_GCache _gcache = FTC_GCACHE( cache ); \ + FTC_GQuery _gquery = (FTC_GQuery)( query ); \ + FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \ + FTC_MruNode _mrunode; \ + \ + \ + _gquery->gindex = (gindex); \ + \ + FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare, \ + _mrunode, error ); \ + _gquery->family = FTC_FAMILY( _mrunode ); \ + if ( !error ) \ + { \ + FTC_Family _gqfamily = _gquery->family; \ + \ + \ + _gqfamily->num_nodes++; \ + \ + FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \ + \ + if ( --_gqfamily->num_nodes == 0 ) \ + FTC_FAMILY_FREE( _gqfamily, _gcache ); \ + } \ + FT_END_STMNT + /* */ + +#else /* !FTC_INLINE */ + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + \ + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, \ + FTC_GQUERY( query ), &node ); \ + \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + +FT_END_HEADER + + +#endif /* FTCGLYPH_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcimage.c b/vendor/freetype/src/cache/ftcimage.c new file mode 100644 index 0000000..428e5e1 --- /dev/null +++ b/vendor/freetype/src/cache/ftcimage.c @@ -0,0 +1,164 @@ +/**************************************************************************** + * + * ftcimage.c + * + * FreeType Image cache (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcimage.h" +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + + + /* finalize a given glyph image node */ + FT_LOCAL_DEF( void ) + ftc_inode_free( FTC_Node ftcinode, + FTC_Cache cache ) + { + FTC_INode inode = (FTC_INode)ftcinode; + FT_Memory memory = cache->memory; + + + if ( inode->glyph ) + { + FT_Done_Glyph( inode->glyph ); + inode->glyph = NULL; + } + + FTC_GNode_Done( FTC_GNODE( inode ), cache ); + FT_FREE( inode ); + } + + + FT_LOCAL_DEF( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ) + { + ftc_inode_free( FTC_NODE( inode ), cache ); + } + + + /* initialize a new glyph image node */ + FT_LOCAL_DEF( FT_Error ) + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + FTC_INode inode = NULL; + + + if ( !FT_QNEW( inode ) ) + { + FTC_GNode gnode = FTC_GNODE( inode ); + FTC_Family family = gquery->family; + FT_UInt gindex = gquery->gindex; + FTC_IFamilyClass clazz = FTC_CACHE_IFAMILY_CLASS( cache ); + + + /* initialize its inner fields */ + FTC_GNode_Init( gnode, gindex, family ); + inode->glyph = NULL; + + /* we will now load the glyph image */ + error = clazz->family_load_glyph( family, gindex, cache, + &inode->glyph ); + if ( error ) + { + FTC_INode_Free( inode, cache ); + inode = NULL; + } + } + + *pinode = inode; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_inode_new( FTC_Node *ftcpinode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_INode *pinode = (FTC_INode*)ftcpinode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + + + return FTC_INode_New( pinode, gquery, cache ); + } + + + FT_LOCAL_DEF( FT_Offset ) + ftc_inode_weight( FTC_Node ftcinode, + FTC_Cache ftccache ) + { + FTC_INode inode = (FTC_INode)ftcinode; + FT_Offset size = 0; + FT_Glyph glyph = inode->glyph; + + FT_UNUSED( ftccache ); + + + switch ( glyph->format ) + { + case FT_GLYPH_FORMAT_BITMAP: + { + FT_BitmapGlyph bitg; + + + bitg = (FT_BitmapGlyph)glyph; + size = bitg->bitmap.rows * (FT_Offset)FT_ABS( bitg->bitmap.pitch ) + + sizeof ( *bitg ); + } + break; + + case FT_GLYPH_FORMAT_OUTLINE: + { + FT_OutlineGlyph outg; + + + outg = (FT_OutlineGlyph)glyph; + size = (FT_Offset)outg->outline.n_points * + ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) + + (FT_Offset)outg->outline.n_contours * sizeof ( FT_Short ) + + sizeof ( *outg ); + } + break; + + default: + ; + } + + size += sizeof ( *inode ); + return size; + } + + +#if 0 + + FT_LOCAL_DEF( FT_Offset ) + FTC_INode_Weight( FTC_INode inode ) + { + return ftc_inode_weight( FTC_NODE( inode ), NULL ); + } + +#endif /* 0 */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcimage.h b/vendor/freetype/src/cache/ftcimage.h new file mode 100644 index 0000000..d2a807f --- /dev/null +++ b/vendor/freetype/src/cache/ftcimage.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * + * ftcimage.h + * + * FreeType Generic Image cache (specification) + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + * FTC_ICache is an _abstract_ cache used to store a single FT_Glyph + * image per cache node. + * + * FTC_ICache extends FTC_GCache. For an implementation example, + * see FTC_ImageCache in `src/cache/ftbasic.c'. + */ + + + /************************************************************************** + * + * Each image cache really manages FT_Glyph objects. + * + */ + + +#ifndef FTCIMAGE_H_ +#define FTCIMAGE_H_ + + +#include +#include "ftcglyph.h" + +FT_BEGIN_HEADER + + + /* the FT_Glyph image node type - we store only 1 glyph per node */ + typedef struct FTC_INodeRec_ + { + FTC_GNodeRec gnode; + FT_Glyph glyph; + + } FTC_INodeRec, *FTC_INode; + +#define FTC_INODE( x ) ( (FTC_INode)( x ) ) +#define FTC_INODE_GINDEX( x ) FTC_GNODE( x )->gindex +#define FTC_INODE_FAMILY( x ) FTC_GNODE( x )->family + + typedef FT_Error + (*FTC_IFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Cache cache, + FT_Glyph *aglyph ); + + typedef struct FTC_IFamilyClassRec_ + { + FTC_MruListClassRec clazz; + FTC_IFamily_LoadGlyphFunc family_load_glyph; + + } FTC_IFamilyClassRec; + + typedef const FTC_IFamilyClassRec* FTC_IFamilyClass; + +#define FTC_IFAMILY_CLASS( x ) ((FTC_IFamilyClass)(x)) + +#define FTC_CACHE_IFAMILY_CLASS( x ) \ + FTC_IFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS( x )->family_class ) + + + /* can be used as a @FTC_Node_FreeFunc */ + FT_LOCAL( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ); + + /* Can be used as @FTC_Node_NewFunc. `gquery.index' and `gquery.family' + * must be set correctly. This function will call the `family_load_glyph' + * method to load the FT_Glyph into the cache node. + */ + FT_LOCAL( FT_Error ) + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ); + +#if 0 + /* can be used as @FTC_Node_WeightFunc */ + FT_LOCAL( FT_ULong ) + FTC_INode_Weight( FTC_INode inode ); +#endif + + + /* */ + +FT_END_HEADER + +#endif /* FTCIMAGE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcmanag.c b/vendor/freetype/src/cache/ftcmanag.c new file mode 100644 index 0000000..94f8469 --- /dev/null +++ b/vendor/freetype/src/cache/ftcmanag.c @@ -0,0 +1,696 @@ +/**************************************************************************** + * + * ftcmanag.c + * + * FreeType Cache Manager (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcmanag.h" +#include +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + static FT_Error + ftc_scaler_lookup_size( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Face face; + FT_Size size = NULL; + FT_Error error; + + + error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); + if ( error ) + goto Exit; + + error = FT_New_Size( face, &size ); + if ( error ) + goto Exit; + + FT_Activate_Size( size ); + + if ( scaler->pixel ) + error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); + else + error = FT_Set_Char_Size( face, + (FT_F26Dot6)scaler->width, + (FT_F26Dot6)scaler->height, + scaler->x_res, + scaler->y_res ); + if ( error ) + { + FT_Done_Size( size ); + size = NULL; + } + + Exit: + *asize = size; + return error; + } + + + typedef struct FTC_SizeNodeRec_ + { + FTC_MruNodeRec node; + FT_Size size; + FTC_ScalerRec scaler; + + } FTC_SizeNodeRec, *FTC_SizeNode; + +#define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) ) + + + FT_CALLBACK_DEF( void ) + ftc_size_node_done( FTC_MruNode ftcnode, + FT_Pointer data ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FT_Size size = node->size; + FT_UNUSED( data ); + + + if ( size ) + FT_Done_Size( size ); + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_size_node_compare( FTC_MruNode ftcnode, + FT_Pointer ftcscaler ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Scaler scaler0 = &node->scaler; + + + if ( FTC_SCALER_COMPARE( scaler0, scaler ) ) + { + FT_Activate_Size( node->size ); + return 1; + } + return 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_init( FTC_MruNode ftcnode, + FT_Pointer ftcscaler, + FT_Pointer ftcmanager ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_reset( FTC_MruNode ftcnode, + FT_Pointer ftcscaler, + FT_Pointer ftcmanager ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + FT_Done_Size( node->size ); + + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); + } + + + static + const FTC_MruListClassRec ftc_size_list_class = + { + sizeof ( FTC_SizeNodeRec ), + + ftc_size_node_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_size_node_init, /* FTC_MruNode_InitFunc node_init */ + ftc_size_node_reset, /* FTC_MruNode_ResetFunc node_reset */ + ftc_size_node_done /* FTC_MruNode_DoneFunc node_done */ + }; + + + /* helper function used by ftc_face_node_done */ + static FT_Bool + ftc_size_node_compare_faceid( FTC_MruNode ftcnode, + FT_Pointer ftcface_id ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + + + return FT_BOOL( node->scaler.face_id == face_id ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Error error; + FTC_MruNode mrunode; + + + if ( !asize || !scaler ) + return FT_THROW( Invalid_Argument ); + + *asize = NULL; + + if ( !manager ) + return FT_THROW( Invalid_Cache_Handle ); + +#ifdef FTC_INLINE + + FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare, + mrunode, error ); + +#else + error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode ); +#endif + + if ( !error ) + *asize = FTC_SIZE_NODE( mrunode )->size; + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE MRU IMPLEMENTATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct FTC_FaceNodeRec_ + { + FTC_MruNodeRec node; + FTC_FaceID face_id; + FT_Face face; + + } FTC_FaceNodeRec, *FTC_FaceNode; + +#define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) ) + + + FT_CALLBACK_DEF( FT_Error ) + ftc_face_node_init( FTC_MruNode ftcnode, + FT_Pointer ftcface_id, + FT_Pointer ftcmanager ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FTC_Manager manager = (FTC_Manager)ftcmanager; + FT_Error error; + + + node->face_id = face_id; + + error = manager->request_face( face_id, + manager->library, + manager->request_data, + &node->face ); + if ( !error ) + { + /* destroy initial size object; it will be re-created later */ + if ( node->face->size ) + FT_Done_Size( node->face->size ); + } + + return error; + } + + + FT_CALLBACK_DEF( void ) + ftc_face_node_done( FTC_MruNode ftcnode, + FT_Pointer ftcmanager ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + /* we must begin by removing all scalers for the target face */ + /* from the manager's list */ + FTC_MruList_RemoveSelection( &manager->sizes, + ftc_size_node_compare_faceid, + node->face_id ); + + /* all right, we can discard the face now */ + FT_Done_Face( node->face ); + node->face = NULL; + node->face_id = NULL; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_face_node_compare( FTC_MruNode ftcnode, + FT_Pointer ftcface_id ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + + + return FT_BOOL( node->face_id == face_id ); + } + + + static + const FTC_MruListClassRec ftc_face_list_class = + { + sizeof ( FTC_FaceNodeRec), + + ftc_face_node_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_face_node_init, /* FTC_MruNode_InitFunc node_init */ + NULL, /* FTC_MruNode_ResetFunc node_reset */ + ftc_face_node_done /* FTC_MruNode_DoneFunc node_done */ + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ) + { + FT_Error error; + FTC_MruNode mrunode; + + + if ( !aface ) + return FT_THROW( Invalid_Argument ); + + *aface = NULL; + + if ( !manager ) + return FT_THROW( Invalid_Cache_Handle ); + + /* we break encapsulation for the sake of speed */ +#ifdef FTC_INLINE + + FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare, + mrunode, error ); + +#else + error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode ); +#endif + + if ( !error ) + *aface = FTC_FACE_NODE( mrunode )->face; + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ) + { + FT_Error error; + FT_Memory memory; + FTC_Manager manager = NULL; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !amanager || !requester ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + if ( FT_QNEW( manager ) ) + goto Exit; + + if ( max_faces == 0 ) + max_faces = FTC_MAX_FACES_DEFAULT; + + if ( max_sizes == 0 ) + max_sizes = FTC_MAX_SIZES_DEFAULT; + + if ( max_bytes == 0 ) + max_bytes = FTC_MAX_BYTES_DEFAULT; + + manager->library = library; + manager->memory = memory; + manager->max_weight = max_bytes; + manager->cur_weight = 0; + + manager->request_face = requester; + manager->request_data = req_data; + + FTC_MruList_Init( &manager->faces, + &ftc_face_list_class, + max_faces, + manager, + memory ); + + FTC_MruList_Init( &manager->sizes, + &ftc_size_list_class, + max_sizes, + manager, + memory ); + + manager->nodes_list = NULL; + manager->num_nodes = 0; + manager->num_caches = 0; + + *amanager = manager; + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Done( FTC_Manager manager ) + { + FT_Memory memory; + FT_UInt idx; + + + if ( !manager || !manager->library ) + return; + + memory = manager->memory; + + /* now discard all caches */ + for ( idx = manager->num_caches; idx-- > 0; ) + { + FTC_Cache cache = manager->caches[idx]; + + + if ( cache ) + { + cache->clazz.cache_done( cache ); + FT_FREE( cache ); + manager->caches[idx] = NULL; + } + } + manager->num_caches = 0; + + /* discard faces and sizes */ + FTC_MruList_Done( &manager->sizes ); + FTC_MruList_Done( &manager->faces ); + + manager->library = NULL; + manager->memory = NULL; + + FT_FREE( manager ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Reset( FTC_Manager manager ) + { + if ( !manager ) + return; + + FTC_MruList_Reset( &manager->sizes ); + FTC_MruList_Reset( &manager->faces ); + + FTC_Manager_FlushN( manager, manager->num_nodes ); + } + + +#ifdef FT_DEBUG_ERROR + + static void + FTC_Manager_Check( FTC_Manager manager ) + { + FTC_Node node, first; + + + first = manager->nodes_list; + + /* check node weights */ + if ( first ) + { + FT_Offset weight = 0; + + + node = first; + + do + { + FTC_Cache cache = manager->caches[node->cache_index]; + + + if ( node->cache_index >= manager->num_caches ) + FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %hu\n", + node->cache_index )); + else + weight += cache->clazz.node_weight( node, cache ); + + node = FTC_NODE_NEXT( node ); + + } while ( node != first ); + + if ( weight != manager->cur_weight ) + FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n", + manager->cur_weight, weight )); + } + + /* check circular list */ + if ( first ) + { + FT_UFast count = 0; + + + node = first; + do + { + count++; + node = FTC_NODE_NEXT( node ); + + } while ( node != first ); + + if ( count != manager->num_nodes ) + FT_TRACE0(( "FTC_Manager_Check:" + " invalid cache node count %u instead of %u\n", + manager->num_nodes, count )); + } + } + +#endif /* FT_DEBUG_ERROR */ + + + /* `Compress' the manager's data, i.e., get rid of old cache nodes */ + /* that are not referenced anymore in order to limit the total */ + /* memory used by the cache. */ + + /* documentation is in ftcmanag.h */ + + FT_LOCAL_DEF( void ) + FTC_Manager_Compress( FTC_Manager manager ) + { + FTC_Node node, prev, first; + + + if ( !manager ) + return; + + first = manager->nodes_list; + +#ifdef FT_DEBUG_ERROR + FTC_Manager_Check( manager ); + + FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %u\n", + manager->cur_weight, manager->max_weight, + manager->num_nodes )); +#endif + + if ( manager->cur_weight < manager->max_weight || !first ) + return; + + /* go to last node -- it's a circular list */ + prev = FTC_NODE_PREV( first ); + do + { + node = prev; + prev = FTC_NODE_PREV( node ); + + if ( node->ref_count <= 0 ) + ftc_node_destroy( node, manager ); + + } while ( node != first && manager->cur_weight > manager->max_weight ); + } + + + /* documentation is in ftcmanag.h */ + + FT_LOCAL_DEF( FT_Error ) + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FTC_Cache cache = NULL; + + + if ( manager && clazz && acache ) + { + FT_Memory memory = manager->memory; + + + if ( manager->num_caches >= FTC_MAX_CACHES ) + { + error = FT_THROW( Too_Many_Caches ); + FT_ERROR(( "FTC_Manager_RegisterCache:" + " too many registered caches\n" )); + goto Exit; + } + + if ( !FT_QALLOC( cache, clazz->cache_size ) ) + { + cache->manager = manager; + cache->memory = memory; + cache->clazz = clazz[0]; + cache->org_class = clazz; + + /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */ + /* IF IT IS NOT SET CORRECTLY */ + cache->index = manager->num_caches; + + error = clazz->cache_init( cache ); + if ( error ) + { + clazz->cache_done( cache ); + FT_FREE( cache ); + goto Exit; + } + + manager->caches[manager->num_caches++] = cache; + } + } + + Exit: + if ( acache ) + *acache = cache; + return error; + } + + + FT_LOCAL_DEF( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ) + { + FTC_Node first = manager->nodes_list; + FTC_Node prev, node; + FT_UInt result = 0; + + + /* try to remove `count' nodes from the list */ + if ( !first || !count ) + return result; + + /* go to last node -- it's a circular list */ + prev = FTC_NODE_PREV( first ); + do + { + node = prev; + prev = FTC_NODE_PREV( node ); + + /* don't touch locked nodes */ + if ( node->ref_count <= 0 ) + { + ftc_node_destroy( node, manager ); + result++; + } + } while ( node != first && result < count ); + + return result; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ) + { + FT_UInt nn; + + + if ( !manager ) + return; + + /* this will remove all FTC_SizeNode that correspond to + * the face_id as well + */ + FTC_MruList_RemoveSelection( &manager->faces, + ftc_face_node_compare, + face_id ); + + for ( nn = 0; nn < manager->num_caches; nn++ ) + FTC_Cache_RemoveFaceID( manager->caches[nn], face_id ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ) + { + if ( node && + manager && + node->cache_index < manager->num_caches ) + node->ref_count--; + } + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcmanag.h b/vendor/freetype/src/cache/ftcmanag.h new file mode 100644 index 0000000..5b30929 --- /dev/null +++ b/vendor/freetype/src/cache/ftcmanag.h @@ -0,0 +1,175 @@ +/**************************************************************************** + * + * ftcmanag.h + * + * FreeType Cache Manager (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * A cache manager is in charge of the following: + * + * - Maintain a mapping between generic FTC_FaceIDs and live FT_Face + * objects. The mapping itself is performed through a user-provided + * callback. However, the manager maintains a small cache of FT_Face + * and FT_Size objects in order to speed up things considerably. + * + * - Manage one or more cache objects. Each cache is in charge of + * holding a varying number of `cache nodes'. Each cache node + * represents a minimal amount of individually accessible cached + * data. For example, a cache node can be an FT_Glyph image + * containing a vector outline, or some glyph metrics, or anything + * else. + * + * Each cache node has a certain size in bytes that is added to the + * total amount of `cache memory' within the manager. + * + * All cache nodes are located in a global LRU list, where the oldest + * node is at the tail of the list. + * + * Each node belongs to a single cache, and includes a reference + * count to avoid destroying it (due to caching). + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef FTCMANAG_H_ +#define FTCMANAG_H_ + + +#include +#include "ftcmru.h" +#include "ftccache.h" + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Section: + * cache_subsystem + * + */ + + +#define FTC_MAX_FACES_DEFAULT 2 +#define FTC_MAX_SIZES_DEFAULT 4 +#define FTC_MAX_BYTES_DEFAULT 200000L /* ~200kByte by default */ + + /* maximum number of caches registered in a single manager */ +#define FTC_MAX_CACHES 16 + + + typedef struct FTC_ManagerRec_ + { + FT_Library library; + FT_Memory memory; + + FTC_Node nodes_list; + FT_Offset max_weight; + FT_Offset cur_weight; + FT_UInt num_nodes; + + FTC_Cache caches[FTC_MAX_CACHES]; + FT_UInt num_caches; + + FTC_MruListRec faces; + FTC_MruListRec sizes; + + FT_Pointer request_data; + FTC_Face_Requester request_face; + + } FTC_ManagerRec; + + + /************************************************************************** + * + * @Function: + * FTC_Manager_Compress + * + * @Description: + * This function is used to check the state of the cache manager if + * its `num_bytes' field is greater than its `max_bytes' field. It + * will flush as many old cache nodes as possible (ignoring cache + * nodes with a non-zero reference count). + * + * @InOut: + * manager :: + * A handle to the cache manager. + * + * @Note: + * Client applications should not call this function directly. It is + * normally invoked by specific cache implementations. + * + * The reason this function is exported is to allow client-specific + * cache classes. + */ + FT_LOCAL( void ) + FTC_Manager_Compress( FTC_Manager manager ); + + + /* try to flush `count' old nodes from the cache; return the number + * of really flushed nodes + */ + FT_LOCAL( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ); + + + /* this must be used internally for the moment */ + FT_LOCAL( FT_Error ) + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ); + + /* */ + +#define FTC_SCALER_COMPARE( a, b ) \ + ( (a)->face_id == (b)->face_id && \ + (a)->width == (b)->width && \ + (a)->height == (b)->height && \ + ((a)->pixel != 0) == ((b)->pixel != 0) && \ + ( (a)->pixel || \ + ( (a)->x_res == (b)->x_res && \ + (a)->y_res == (b)->y_res ) ) ) + +#define FTC_SCALER_HASH( q ) \ + ( FTC_FACE_ID_HASH( (q)->face_id ) + \ + (q)->width + (q)->height*7 + \ + ( (q)->pixel ? 0 : ( (q)->x_res*33 ^ (q)->y_res*61 ) ) ) + + /* */ + +FT_END_HEADER + +#endif /* FTCMANAG_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcmru.c b/vendor/freetype/src/cache/ftcmru.c new file mode 100644 index 0000000..ad10a06 --- /dev/null +++ b/vendor/freetype/src/cache/ftcmru.c @@ -0,0 +1,352 @@ +/**************************************************************************** + * + * ftcmru.c + * + * FreeType MRU support (body). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcmru.h" +#include +#include + +#include "ftcerror.h" + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + + + if ( first ) + { + FTC_MruNode last = first->prev; + + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + + + do + { + if ( cnode == node ) + { + fprintf( stderr, "FTC_MruNode_Prepend: invalid action\n" ); + exit( 2 ); + } + cnode = cnode->next; + + } while ( cnode != first ); + } +#endif + + first->prev = node; + last->next = node; + node->next = first; + node->prev = last; + } + else + { + node->next = node; + node->prev = node; + } + *plist = node; + } + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + + + FT_ASSERT( first ); + + if ( first != node ) + { + FTC_MruNode prev, next, last; + + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + do + { + if ( cnode == node ) + goto Ok; + cnode = cnode->next; + + } while ( cnode != first ); + + fprintf( stderr, "FTC_MruNode_Up: invalid action\n" ); + exit( 2 ); + Ok: + } +#endif + prev = node->prev; + next = node->next; + + prev->next = next; + next->prev = prev; + + last = first->prev; + + last->next = node; + first->prev = node; + + node->next = first; + node->prev = last; + + *plist = node; + } + } + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + FTC_MruNode prev, next; + + + FT_ASSERT( first ); + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + + + do + { + if ( cnode == node ) + goto Ok; + cnode = cnode->next; + + } while ( cnode != first ); + + fprintf( stderr, "FTC_MruNode_Remove: invalid action\n" ); + exit( 2 ); + Ok: + } +#endif + + prev = node->prev; + next = node->next; + + prev->next = next; + next->prev = prev; + + if ( node == next ) + { + FT_ASSERT( first == node ); + FT_ASSERT( prev == node ); + + *plist = NULL; + } + else if ( node == first ) + *plist = next; + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ) + { + list->num_nodes = 0; + list->max_nodes = max_nodes; + list->nodes = NULL; + list->clazz = *clazz; + list->data = data; + list->memory = memory; + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Reset( FTC_MruList list ) + { + while ( list->nodes ) + FTC_MruList_Remove( list, list->nodes ); + + FT_ASSERT( list->num_nodes == 0 ); + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Done( FTC_MruList list ) + { + FTC_MruList_Reset( list ); + } + + +#ifndef FTC_INLINE + FT_LOCAL_DEF( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ) + { + FTC_MruNode_CompareFunc compare = list->clazz.node_compare; + FTC_MruNode first, node; + + + first = list->nodes; + node = NULL; + + if ( first ) + { + node = first; + do + { + if ( compare( node, key ) ) + { + if ( node != first ) + FTC_MruNode_Up( &list->nodes, node ); + + return node; + } + + node = node->next; + + } while ( node != first); + } + + return NULL; + } +#endif + + FT_LOCAL_DEF( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ) + { + FT_Error error; + FTC_MruNode node = NULL; + FT_Memory memory = list->memory; + + + if ( list->num_nodes >= list->max_nodes && list->max_nodes > 0 ) + { + node = list->nodes->prev; + + FT_ASSERT( node ); + + if ( list->clazz.node_reset ) + { + FTC_MruNode_Up( &list->nodes, node ); + + error = list->clazz.node_reset( node, key, list->data ); + if ( !error ) + goto Exit; + } + + FTC_MruNode_Remove( &list->nodes, node ); + list->num_nodes--; + + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + } + + /* zero new node in case of node_init failure */ + else if ( FT_ALLOC( node, list->clazz.node_size ) ) + goto Exit; + + error = list->clazz.node_init( node, key, list->data ); + if ( error ) + goto Fail; + + FTC_MruNode_Prepend( &list->nodes, node ); + list->num_nodes++; + + Exit: + *anode = node; + return error; + + Fail: + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + goto Exit; + } + + +#ifndef FTC_INLINE + FT_LOCAL_DEF( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ) + { + FTC_MruNode node; + + + node = FTC_MruList_Find( list, key ); + if ( !node ) + return FTC_MruList_New( list, key, anode ); + + *anode = node; + return 0; + } +#endif /* FTC_INLINE */ + + FT_LOCAL_DEF( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ) + { + FTC_MruNode_Remove( &list->nodes, node ); + list->num_nodes--; + + { + FT_Memory memory = list->memory; + + + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + } + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc selection, + FT_Pointer key ) + { + FTC_MruNode first = list->nodes; + FTC_MruNode prev, node; + + + if ( !first || !selection ) + return; + + prev = first->prev; + do + { + node = prev; + prev = node->prev; + + if ( selection( node, key ) ) + FTC_MruList_Remove( list, node ); + + } while ( node != first ); + } + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcmru.h b/vendor/freetype/src/cache/ftcmru.h new file mode 100644 index 0000000..45e5249 --- /dev/null +++ b/vendor/freetype/src/cache/ftcmru.h @@ -0,0 +1,248 @@ +/**************************************************************************** + * + * ftcmru.h + * + * Simple MRU list-cache (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * An MRU is a list that cannot hold more than a certain number of + * elements (`max_elements'). All elements in the list are sorted in + * least-recently-used order, i.e., the `oldest' element is at the tail + * of the list. + * + * When doing a lookup (either through `Lookup()' or `Lookup_Node()'), + * the list is searched for an element with the corresponding key. If + * it is found, the element is moved to the head of the list and is + * returned. + * + * If no corresponding element is found, the lookup routine will try to + * obtain a new element with the relevant key. If the list is already + * full, the oldest element from the list is discarded and replaced by a + * new one; a new element is added to the list otherwise. + * + * Note that it is possible to pre-allocate the element list nodes. + * This is handy if `max_elements' is sufficiently small, as it saves + * allocations/releases during the lookup process. + * + */ + + +#ifndef FTCMRU_H_ +#define FTCMRU_H_ + + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + +#define xxFT_DEBUG_ERROR +#define FTC_INLINE + +FT_BEGIN_HEADER + + typedef struct FTC_MruNodeRec_* FTC_MruNode; + + typedef struct FTC_MruNodeRec_ + { + FTC_MruNode next; + FTC_MruNode prev; + + } FTC_MruNodeRec; + + + FT_LOCAL( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ); + + + typedef struct FTC_MruListRec_* FTC_MruList; + + typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; + + + typedef FT_Bool + (*FTC_MruNode_CompareFunc)( FTC_MruNode node, + FT_Pointer key ); + + typedef FT_Error + (*FTC_MruNode_InitFunc)( FTC_MruNode node, + FT_Pointer key, + FT_Pointer data ); + + typedef FT_Error + (*FTC_MruNode_ResetFunc)( FTC_MruNode node, + FT_Pointer key, + FT_Pointer data ); + + typedef void + (*FTC_MruNode_DoneFunc)( FTC_MruNode node, + FT_Pointer data ); + + + typedef struct FTC_MruListClassRec_ + { + FT_Offset node_size; + + FTC_MruNode_CompareFunc node_compare; + FTC_MruNode_InitFunc node_init; + FTC_MruNode_ResetFunc node_reset; + FTC_MruNode_DoneFunc node_done; + + } FTC_MruListClassRec; + + + typedef struct FTC_MruListRec_ + { + FT_UInt num_nodes; + FT_UInt max_nodes; + FTC_MruNode nodes; + FT_Pointer data; + FTC_MruListClassRec clazz; + FT_Memory memory; + + } FTC_MruListRec; + + + FT_LOCAL( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ); + + FT_LOCAL( void ) + FTC_MruList_Reset( FTC_MruList list ); + + + FT_LOCAL( void ) + FTC_MruList_Done( FTC_MruList list ); + + + FT_LOCAL( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ); + + FT_LOCAL( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc selection, + FT_Pointer key ); + + +#ifdef FTC_INLINE + +#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error ) \ + FT_BEGIN_STMNT \ + FTC_MruNode* _pfirst = &(list)->nodes; \ + FTC_MruNode_CompareFunc _compare = (FTC_MruNode_CompareFunc)(compare); \ + FTC_MruNode _first, _node; \ + \ + \ + error = FT_Err_Ok; \ + _first = *(_pfirst); \ + _node = NULL; \ + \ + if ( _first ) \ + { \ + _node = _first; \ + do \ + { \ + if ( _compare( _node, (key) ) ) \ + { \ + if ( _node != _first ) \ + FTC_MruNode_Up( _pfirst, _node ); \ + \ + node = _node; \ + goto MruOk_; \ + } \ + _node = _node->next; \ + \ + } while ( _node != _first); \ + } \ + \ + error = FTC_MruList_New( (list), (key), (FTC_MruNode*)(void*)&(node) ); \ + MruOk_: \ + ; \ + FT_END_STMNT + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error ) + +#else /* !FTC_INLINE */ + + FT_LOCAL( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ); + + FT_LOCAL( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *pnode ); + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) ) + +#endif /* !FTC_INLINE */ + + +#define FTC_MRULIST_LOOP( list, node ) \ + FT_BEGIN_STMNT \ + FTC_MruNode _first = (list)->nodes; \ + \ + \ + if ( _first ) \ + { \ + FTC_MruNode _node = _first; \ + \ + \ + do \ + { \ + *(FTC_MruNode*)&(node) = _node; + + +#define FTC_MRULIST_LOOP_END() \ + _node = _node->next; \ + \ + } while ( _node != _first ); \ + } \ + FT_END_STMNT + + /* */ + +FT_END_HEADER + + +#endif /* FTCMRU_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/ftcsbits.c b/vendor/freetype/src/cache/ftcsbits.c new file mode 100644 index 0000000..9929a0b --- /dev/null +++ b/vendor/freetype/src/cache/ftcsbits.c @@ -0,0 +1,414 @@ +/**************************************************************************** + * + * ftcsbits.c + * + * FreeType sbits manager (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcsbits.h" +#include +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SBIT CACHE NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + ftc_sbit_copy_bitmap( FTC_SBit sbit, + FT_Bitmap* bitmap, + FT_Memory memory ) + { + FT_Error error; + FT_Int pitch = bitmap->pitch; + FT_ULong size; + + + if ( pitch < 0 ) + pitch = -pitch; + + size = (FT_ULong)pitch * bitmap->rows; + + if ( !FT_QALLOC( sbit->buffer, size ) ) + FT_MEM_COPY( sbit->buffer, bitmap->buffer, size ); + + return error; + } + + + FT_LOCAL_DEF( void ) + ftc_snode_free( FTC_Node ftcsnode, + FTC_Cache cache ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FTC_SBit sbit = snode->sbits; + FT_UInt count = snode->count; + FT_Memory memory = cache->memory; + + + for ( ; count > 0; sbit++, count-- ) + FT_FREE( sbit->buffer ); + + FTC_GNode_Done( FTC_GNODE( snode ), cache ); + + FT_FREE( snode ); + } + + + FT_LOCAL_DEF( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ) + { + ftc_snode_free( FTC_NODE( snode ), cache ); + } + + + /* + * This function tries to load a small bitmap within a given FTC_SNode. + * Note that it returns a non-zero error code _only_ in the case of + * out-of-memory condition. For all other errors (e.g., corresponding + * to a bad font file), this function will mark the sbit as `unavailable' + * and return a value of 0. + * + * You should also read the comment within the @ftc_snode_compare + * function below to see how out-of-memory is handled during a lookup. + */ + static FT_Error + ftc_snode_load( FTC_SNode snode, + FTC_Manager manager, + FT_UInt gindex, + FT_ULong *asize ) + { + FT_Error error; + FTC_GNode gnode = FTC_GNODE( snode ); + FTC_Family family = gnode->family; + FT_Face face; + FTC_SBit sbit; + FTC_SFamilyClass clazz; + + + if ( gindex - gnode->gindex >= snode->count ) + { + FT_ERROR(( "ftc_snode_load: invalid glyph index" )); + return FT_THROW( Invalid_Argument ); + } + + sbit = snode->sbits + ( gindex - gnode->gindex ); + clazz = (FTC_SFamilyClass)family->clazz; + + error = clazz->family_load_glyph( family, gindex, manager, &face ); + if ( error ) + goto BadGlyph; + + { + FT_Int temp; + FT_GlyphSlot slot = face->glyph; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Pos xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */ + + + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) + { + FT_TRACE0(( "ftc_snode_load:" + " glyph loaded didn't return a bitmap\n" )); + goto BadGlyph; + } + + /* Check whether our values fit into 8/16-bit containers! */ + /* If this is not the case, our bitmap is too large */ + /* and we will leave it as `missing' with sbit.buffer = 0 */ + +#define CHECK_CHAR( d ) ( temp = (FT_Char)d, (FT_Int) temp == (FT_Int) d ) +#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, (FT_UInt)temp == (FT_UInt)d ) +#define CHECK_SHRT( d ) ( temp = (FT_Short)d, (FT_Int)temp == (FT_Int) d ) + + /* horizontal advance in pixels */ + xadvance = ( slot->advance.x + 32 ) >> 6; + yadvance = ( slot->advance.y + 32 ) >> 6; + + if ( !CHECK_BYTE( bitmap->rows ) || + !CHECK_BYTE( bitmap->width ) || + !CHECK_SHRT( bitmap->pitch ) || + !CHECK_CHAR( slot->bitmap_left ) || + !CHECK_CHAR( slot->bitmap_top ) || + !CHECK_CHAR( xadvance ) || + !CHECK_CHAR( yadvance ) ) + { + FT_TRACE2(( "ftc_snode_load:" + " glyph too large for small bitmap cache\n")); + goto BadGlyph; + } + + sbit->width = (FT_Byte)bitmap->width; + sbit->height = (FT_Byte)bitmap->rows; + sbit->pitch = (FT_Short)bitmap->pitch; + sbit->left = (FT_Char)slot->bitmap_left; + sbit->top = (FT_Char)slot->bitmap_top; + sbit->xadvance = (FT_Char)xadvance; + sbit->yadvance = (FT_Char)yadvance; + sbit->format = (FT_Byte)bitmap->pixel_mode; + sbit->max_grays = (FT_Byte)( bitmap->num_grays - 1 ); + + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + /* take the bitmap ownership */ + sbit->buffer = bitmap->buffer; + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + /* copy the bitmap into a new buffer -- ignore error */ + error = ftc_sbit_copy_bitmap( sbit, bitmap, manager->memory ); + } + + /* now, compute size */ + if ( asize ) + *asize = (FT_ULong)FT_ABS( sbit->pitch ) * sbit->height; + + } /* glyph loading successful */ + + /* ignore the errors that might have occurred -- */ + /* we mark unloaded glyphs with `sbit.buffer == 0' */ + /* and `width == 255', `height == 0' */ + /* */ + if ( error && FT_ERR_NEQ( error, Out_Of_Memory ) ) + { + BadGlyph: + sbit->width = 255; + sbit->height = 0; + sbit->buffer = NULL; + error = FT_Err_Ok; + if ( asize ) + *asize = 0; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + FTC_SNode snode = NULL; + FT_UInt gindex = gquery->gindex; + FTC_Family family = gquery->family; + + FTC_SFamilyClass clazz = FTC_CACHE_SFAMILY_CLASS( cache ); + FT_UInt total; + FT_UInt node_count; + + + total = clazz->family_get_count( family, cache->manager ); + if ( total == 0 || gindex >= total ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( snode ) ) + { + FT_UInt count, start; + + + start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE ); + count = total - start; + if ( count > FTC_SBIT_ITEMS_PER_NODE ) + count = FTC_SBIT_ITEMS_PER_NODE; + + FTC_GNode_Init( FTC_GNODE( snode ), start, family ); + + snode->count = count; + for ( node_count = 0; node_count < count; node_count++ ) + { + snode->sbits[node_count].width = 255; + snode->sbits[node_count].height = 0; + snode->sbits[node_count].buffer = NULL; + } + + error = ftc_snode_load( snode, + cache->manager, + gindex, + NULL ); + if ( error ) + { + FTC_SNode_Free( snode, cache ); + snode = NULL; + } + } + + Exit: + *psnode = snode; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_snode_new( FTC_Node *ftcpsnode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_SNode *psnode = (FTC_SNode*)ftcpsnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + + + return FTC_SNode_New( psnode, gquery, cache ); + } + + + FT_LOCAL_DEF( FT_Offset ) + ftc_snode_weight( FTC_Node ftcsnode, + FTC_Cache cache ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FT_UInt count = snode->count; + FTC_SBit sbit = snode->sbits; + FT_Int pitch; + FT_Offset size; + + FT_UNUSED( cache ); + + + FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE ); + + /* the node itself */ + size = sizeof ( *snode ); + + for ( ; count > 0; count--, sbit++ ) + { + if ( sbit->buffer ) + { + pitch = sbit->pitch; + if ( pitch < 0 ) + pitch = -pitch; + + /* add the size of a given glyph image */ + size += (FT_Offset)pitch * sbit->height; + } + } + + return size; + } + + +#if 0 + + FT_LOCAL_DEF( FT_Offset ) + FTC_SNode_Weight( FTC_SNode snode ) + { + return ftc_snode_weight( FTC_NODE( snode ), NULL ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Bool ) + ftc_snode_compare( FTC_Node ftcsnode, + FT_Pointer ftcgquery, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + FTC_GNode gnode = FTC_GNODE( snode ); + FT_UInt gindex = gquery->gindex; + FT_Bool result; + + + if ( list_changed ) + *list_changed = FALSE; + result = FT_BOOL( gnode->family == gquery->family && + gindex - gnode->gindex < snode->count ); + if ( result ) + { + /* check if we need to load the glyph bitmap now */ + FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex ); + + + /* + * The following code illustrates what to do when you want to + * perform operations that may fail within a lookup function. + * + * Here, we want to load a small bitmap on-demand; we thus + * need to call the `ftc_snode_load' function which may return + * a non-zero error code only when we are out of memory (OOM). + * + * The correct thing to do is to use @FTC_CACHE_TRYLOOP and + * @FTC_CACHE_TRYLOOP_END in order to implement a retry loop + * that is capable of flushing the cache incrementally when + * an OOM errors occur. + * + * However, we need to `lock' the node before this operation to + * prevent it from being flushed within the loop. + * + * When we exit the loop, we unlock the node, then check the `error' + * variable. If it is non-zero, this means that the cache was + * completely flushed and that no usable memory was found to load + * the bitmap. + * + * We then prefer to return a value of 0 (i.e., NO MATCH). This + * ensures that the caller will try to allocate a new node. + * This operation consequently _fail_ and the lookup function + * returns the appropriate OOM error code. + * + * Note that `buffer == NULL && width == 255' is a hack used to + * tag `unavailable' bitmaps in the array. We should never try + * to load these. + * + */ + + if ( !sbit->buffer && sbit->width == 255 ) + { + FT_ULong size; + FT_Error error; + + + ftcsnode->ref_count++; /* lock node to prevent flushing */ + /* in retry loop */ + + FTC_CACHE_TRYLOOP( cache ) + { + error = ftc_snode_load( snode, cache->manager, gindex, &size ); + } + FTC_CACHE_TRYLOOP_END( list_changed ) + + ftcsnode->ref_count--; /* unlock the node */ + + if ( error ) + result = 0; + else + cache->manager->cur_weight += size; + } + } + + return result; + } + +/* END */ diff --git a/vendor/freetype/src/cache/ftcsbits.h b/vendor/freetype/src/cache/ftcsbits.h new file mode 100644 index 0000000..e833cb5 --- /dev/null +++ b/vendor/freetype/src/cache/ftcsbits.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * ftcsbits.h + * + * A small-bitmap cache (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCSBITS_H_ +#define FTCSBITS_H_ + + +#include +#include "ftcglyph.h" + + +FT_BEGIN_HEADER + +#define FTC_SBIT_ITEMS_PER_NODE 16 + + typedef struct FTC_SNodeRec_ + { + FTC_GNodeRec gnode; + FT_UInt count; + FTC_SBitRec sbits[FTC_SBIT_ITEMS_PER_NODE]; + + } FTC_SNodeRec, *FTC_SNode; + + +#define FTC_SNODE( x ) ( (FTC_SNode)( x ) ) +#define FTC_SNODE_GINDEX( x ) FTC_GNODE( x )->gindex +#define FTC_SNODE_FAMILY( x ) FTC_GNODE( x )->family + + typedef FT_UInt + (*FTC_SFamily_GetCountFunc)( FTC_Family family, + FTC_Manager manager ); + + typedef FT_Error + (*FTC_SFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Manager manager, + FT_Face *aface ); + + typedef struct FTC_SFamilyClassRec_ + { + FTC_MruListClassRec clazz; + FTC_SFamily_GetCountFunc family_get_count; + FTC_SFamily_LoadGlyphFunc family_load_glyph; + + } FTC_SFamilyClassRec; + + typedef const FTC_SFamilyClassRec* FTC_SFamilyClass; + +#define FTC_SFAMILY_CLASS( x ) ( (FTC_SFamilyClass)(x) ) + +#define FTC_CACHE_SFAMILY_CLASS( x ) \ + FTC_SFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS( x )->family_class ) + + + FT_LOCAL( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ); + +#if 0 + FT_LOCAL( FT_ULong ) + FTC_SNode_Weight( FTC_SNode inode ); +#endif + + /* */ + +FT_END_HEADER + +#endif /* FTCSBITS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cache/rules.mk b/vendor/freetype/src/cache/rules.mk new file mode 100644 index 0000000..82b39aa --- /dev/null +++ b/vendor/freetype/src/cache/rules.mk @@ -0,0 +1,85 @@ +# +# FreeType 2 Cache configuration rules +# + + +# Copyright (C) 2000-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Cache driver directory +# +CACHE_DIR := $(SRC_DIR)/cache + + +# compilation flags for the driver +# +CACHE_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(CACHE_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# Cache driver sources (i.e., C files) +# +CACHE_DRV_SRC := $(CACHE_DIR)/ftcbasic.c \ + $(CACHE_DIR)/ftccache.c \ + $(CACHE_DIR)/ftccmap.c \ + $(CACHE_DIR)/ftcglyph.c \ + $(CACHE_DIR)/ftcimage.c \ + $(CACHE_DIR)/ftcmanag.c \ + $(CACHE_DIR)/ftcmru.c \ + $(CACHE_DIR)/ftcsbits.c + + +# Cache driver headers +# +CACHE_DRV_H := $(CACHE_DIR)/ftccache.h \ + $(CACHE_DIR)/ftccback.h \ + $(CACHE_DIR)/ftcerror.h \ + $(CACHE_DIR)/ftcglyph.h \ + $(CACHE_DIR)/ftcimage.h \ + $(CACHE_DIR)/ftcmanag.h \ + $(CACHE_DIR)/ftcmru.h \ + $(CACHE_DIR)/ftcsbits.h + + +# Cache driver object(s) +# +# CACHE_DRV_OBJ_M is used during `multi' builds. +# CACHE_DRV_OBJ_S is used during `single' builds. +# +CACHE_DRV_OBJ_M := $(CACHE_DRV_SRC:$(CACHE_DIR)/%.c=$(OBJ_DIR)/%.$O) +CACHE_DRV_OBJ_S := $(OBJ_DIR)/ftcache.$O + +# Cache driver source file for single build +# +CACHE_DRV_SRC_S := $(CACHE_DIR)/ftcache.c + + +# Cache driver - single object +# +$(CACHE_DRV_OBJ_S): $(CACHE_DRV_SRC_S) $(CACHE_DRV_SRC) \ + $(FREETYPE_H) $(CACHE_DRV_H) + $(CACHE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(CACHE_DRV_SRC_S)) + + +# Cache driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(CACHE_DIR)/%.c $(FREETYPE_H) $(CACHE_DRV_H) + $(CACHE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(CACHE_DRV_OBJ_S) +DRV_OBJS_M += $(CACHE_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/cff/cff.c b/vendor/freetype/src/cff/cff.c new file mode 100644 index 0000000..b486c38 --- /dev/null +++ b/vendor/freetype/src/cff/cff.c @@ -0,0 +1,28 @@ +/**************************************************************************** + * + * cff.c + * + * FreeType OpenType driver component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "cffcmap.c" +#include "cffdrivr.c" +#include "cffgload.c" +#include "cffparse.c" +#include "cffload.c" +#include "cffobjs.c" + +/* END */ diff --git a/vendor/freetype/src/cff/cffcmap.c b/vendor/freetype/src/cff/cffcmap.c new file mode 100644 index 0000000..10d287b --- /dev/null +++ b/vendor/freetype/src/cff/cffcmap.c @@ -0,0 +1,230 @@ +/**************************************************************************** + * + * cffcmap.c + * + * CFF character mapping table (cmap) support (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "cffcmap.h" +#include "cffload.h" + +#include "cfferrs.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( FT_Error ) + cff_cmap_encoding_init( FT_CMap cmap, + FT_Pointer pointer ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Encoding encoding = &cff->encoding; + + FT_UNUSED( pointer ); + + + cffcmap->gids = encoding->codes; + + return 0; + } + + + FT_CALLBACK_DEF( void ) + cff_cmap_encoding_done( FT_CMap cmap ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + + + cffcmap->gids = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_index( FT_CMap cmap, + FT_UInt32 char_code ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + FT_UInt result = 0; + + + if ( char_code < 256 ) + result = cffcmap->gids[char_code]; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + + + while ( char_code < 255 ) + { + result = cffcmap->gids[++char_code]; + if ( result ) + { + *pchar_code = char_code; + break; + } + } + + return result; + } + + + FT_DEFINE_CMAP_CLASS( + cff_cmap_encoding_class_rec, + + sizeof ( CFF_CMapStdRec ), + + (FT_CMap_InitFunc) cff_cmap_encoding_init, /* init */ + (FT_CMap_DoneFunc) cff_cmap_encoding_done, /* done */ + (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, /* char_index */ + (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( const char* ) + cff_sid_to_glyph_name( void* face_, /* TT_Face */ + FT_UInt idx ) + { + TT_Face face = (TT_Face)face_; + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Charset charset = &cff->charset; + FT_UInt sid = charset->sids[idx]; + + + return cff_index_get_sid_string( cff, sid ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Charset charset = &cff->charset; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + FT_UNUSED( pointer ); + + + /* can't build Unicode map for CID-keyed font */ + /* because we don't know glyph names. */ + if ( !charset->sids ) + return FT_THROW( No_Unicode_Glyph_Name ); + + if ( !psnames->unicodes_init ) + return FT_THROW( Unimplemented_Feature ); + + return psnames->unicodes_init( memory, + unicodes, + cff->num_glyphs, + &cff_sid_to_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + cff_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_DEFINE_CMAP_CLASS( + cff_cmap_unicode_class_rec, + + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) cff_cmap_unicode_init, /* init */ + (FT_CMap_DoneFunc) cff_cmap_unicode_done, /* done */ + (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, /* char_index */ + (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + ) + + +/* END */ diff --git a/vendor/freetype/src/cff/cffcmap.h b/vendor/freetype/src/cff/cffcmap.h new file mode 100644 index 0000000..b2afc2f --- /dev/null +++ b/vendor/freetype/src/cff/cffcmap.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * + * cffcmap.h + * + * CFF character mapping table (cmap) support (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFCMAP_H_ +#define CFFCMAP_H_ + +#include + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* standard (and expert) encoding cmaps */ + typedef struct CFF_CMapStdRec_* CFF_CMapStd; + + typedef struct CFF_CMapStdRec_ + { + FT_CMapRec cmap; + FT_UShort* gids; /* up to 256 elements */ + + } CFF_CMapStdRec; + + + FT_DECLARE_CMAP_CLASS( cff_cmap_encoding_class_rec ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* unicode (synthetic) cmaps */ + + FT_DECLARE_CMAP_CLASS( cff_cmap_unicode_class_rec ) + + +FT_END_HEADER + +#endif /* CFFCMAP_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cff/cffdrivr.c b/vendor/freetype/src/cff/cffdrivr.c new file mode 100644 index 0000000..9898d62 --- /dev/null +++ b/vendor/freetype/src/cff/cffdrivr.c @@ -0,0 +1,1263 @@ +/**************************************************************************** + * + * cffdrivr.c + * + * OpenType font driver implementation (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cffdrivr.h" +#include "cffgload.h" +#include "cffload.h" +#include "cffcmap.h" +#include "cffparse.h" +#include "cffobjs.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include "cfferrs.h" + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffdriver + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * cff_get_kerning + * + * @Description: + * A driver method used to return the kerning vector between two + * glyphs of the same face. + * + * @Input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * @Output: + * kerning :: + * The kerning vector. This is in font units for + * scalable formats, and in pixels for fixed-sizes + * formats. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only horizontal layouts (left-to-right & right-to-left) are + * supported by this function. Other layouts, or more sophisticated + * kernings, are out of scope of this method (the basic driver + * interface is meant to be simple). + * + * They can be implemented by format-specific interfaces. + */ + FT_CALLBACK_DEF( FT_Error ) + cff_get_kerning( FT_Face face, /* CFF_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + CFF_Face cffface = (CFF_Face)face; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + + + kerning->x = 0; + kerning->y = 0; + + if ( sfnt ) + kerning->x = sfnt->get_kerning( cffface, left_glyph, right_glyph ); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * cff_glyph_load + * + * @Description: + * A driver method used to load a glyph within a given glyph slot. + * + * @Input: + * slot :: + * A handle to the target slot object where the glyph + * will be loaded. + * + * size :: + * A handle to the source face size at which the glyph + * must be scaled, loaded, etc. + * + * glyph_index :: + * The index of the glyph in the font file. + * + * load_flags :: + * A flag indicating what to load for this glyph. The + * FT_LOAD_??? constants can be used to control the + * glyph loading process (e.g., whether the outline + * should be scaled, whether to load bitmaps or not, + * whether to hint the outline, etc). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_CALLBACK_DEF( FT_Error ) + cff_glyph_load( FT_GlyphSlot slot, /* CFF_GlyphSlot */ + FT_Size size, /* CFF_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + CFF_GlyphSlot cffslot = (CFF_GlyphSlot)slot; + CFF_Size cffsize = (CFF_Size)size; + + + if ( !cffslot ) + return FT_THROW( Invalid_Slot_Handle ); + + FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index )); + + /* check whether we want a scaled outline or bitmap */ + if ( !cffsize ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + /* reset the size object if necessary */ + if ( load_flags & FT_LOAD_NO_SCALE ) + size = NULL; + + if ( size ) + { + /* these two objects must have the same parent */ + if ( size->face != slot->face ) + return FT_THROW( Invalid_Face_Handle ); + } + + /* now load the glyph outline if necessary */ + error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed* advances ) + { + FT_UInt nn; + FT_Error error = FT_Err_Ok; + FT_GlyphSlot slot = face->glyph; + + + if ( FT_IS_SFNT( face ) ) + { + /* OpenType 1.7 mandates that the data from `hmtx' table be used; */ + /* it is no longer necessary that those values are identical to */ + /* the values in the `CFF' table */ + + CFF_Face cffface = (CFF_Face)face; + FT_Short dummy; + + + if ( flags & FT_LOAD_VERTICAL_LAYOUT ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + /* check whether we have data from the `vmtx' table at all; */ + /* otherwise we extract the info from the CFF glyphstrings */ + /* (instead of synthesizing a global value using the `OS/2' */ + /* table) */ + if ( !cffface->vertical_info ) + goto Missing_Table; + + for ( nn = 0; nn < count; nn++ ) + { + FT_UShort ah; + + + ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, + 1, + start + nn, + &dummy, + &ah ); + + FT_TRACE5(( " idx %d: advance height %d font unit%s\n", + start + nn, + ah, + ah == 1 ? "" : "s" )); + advances[nn] = ah; + } + } + else + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + /* check whether we have data from the `hmtx' table at all */ + if ( !cffface->horizontal.number_Of_HMetrics ) + goto Missing_Table; + + for ( nn = 0; nn < count; nn++ ) + { + FT_UShort aw; + + + ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, + 0, + start + nn, + &dummy, + &aw ); + + FT_TRACE5(( " idx %d: advance width %d font unit%s\n", + start + nn, + aw, + aw == 1 ? "" : "s" )); + advances[nn] = aw; + } + } + + return error; + } + + Missing_Table: + flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; + + for ( nn = 0; nn < count; nn++ ) + { + error = cff_glyph_load( slot, face->size, start + nn, flags ); + if ( error ) + break; + + advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) + ? slot->linearVertAdvance + : slot->linearHoriAdvance; + } + + return error; + } + + + /* + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cff_get_glyph_name( FT_Face face, /* CFF_Face */ + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font font = (CFF_Font)cffface->extra.data; + FT_String* gname; + FT_UShort sid; + FT_Error error; + + + /* CFF2 table does not have glyph names; */ + /* we need to use `post' table method */ + if ( font->version_major == 2 ) + { + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); + FT_Service_GlyphDict service = + (FT_Service_GlyphDict)ft_module_get_service( + sfnt_module, + FT_SERVICE_ID_GLYPH_DICT, + 0 ); + + + if ( service && service->get_name ) + return service->get_name( face, glyph_index, buffer, buffer_max ); + else + { + FT_ERROR(( "cff_get_glyph_name:" + " cannot get glyph name from a CFF2 font\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + } + + if ( !font->psnames ) + { + FT_ERROR(( "cff_get_glyph_name:" + " cannot get glyph name from CFF & CEF fonts\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + /* first, locate the sid in the charset table */ + sid = font->charset.sids[glyph_index]; + + /* now, look up the name itself */ + gname = cff_index_get_sid_string( font, sid ); + + if ( gname ) + FT_STRCPYN( buffer, gname, buffer_max ); + + error = FT_Err_Ok; + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_get_name_index( FT_Face face, /* CFF_Face */ + const FT_String* glyph_name ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + CFF_Charset charset = &cff->charset; + FT_Service_PsCMaps psnames; + FT_String* name; + FT_UShort sid; + FT_UInt i; + + + /* CFF2 table does not have glyph names; */ + /* we need to use `post' table method */ + if ( cff->version_major == 2 ) + { + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); + FT_Service_GlyphDict service = + (FT_Service_GlyphDict)ft_module_get_service( + sfnt_module, + FT_SERVICE_ID_GLYPH_DICT, + 0 ); + + + if ( service && service->name_index ) + return service->name_index( face, glyph_name ); + else + { + FT_ERROR(( "cff_get_name_index:" + " cannot get glyph index from a CFF2 font\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + return 0; + } + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + return 0; + + for ( i = 0; i < cff->num_glyphs; i++ ) + { + sid = charset->sids[i]; + + if ( sid > 390 ) + name = cff_index_get_string( cff, sid - 391 ); + else + name = (FT_String *)psnames->adobe_std_strings( sid ); + + if ( !name ) + continue; + + if ( !ft_strcmp( glyph_name, name ) ) + return i; + } + + return 0; + } + + + FT_DEFINE_SERVICE_GLYPHDICTREC( + cff_service_glyph_dict, + + cff_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + cff_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ + ) + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Int ) + cff_ps_has_glyph_names( FT_Face face ) + { + return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_ps_get_font_info( FT_Face face, /* CFF_Face */ + PS_FontInfoRec* afont_info ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + FT_Error error = FT_Err_Ok; + + + if ( cffface->is_cff2 ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + if ( cff && !cff->font_info ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_FontInfoRec* font_info = NULL; + + + if ( FT_QNEW( font_info ) ) + goto Fail; + + font_info->version = cff_index_get_sid_string( cff, + dict->version ); + font_info->notice = cff_index_get_sid_string( cff, + dict->notice ); + font_info->full_name = cff_index_get_sid_string( cff, + dict->full_name ); + font_info->family_name = cff_index_get_sid_string( cff, + dict->family_name ); + font_info->weight = cff_index_get_sid_string( cff, + dict->weight ); + font_info->italic_angle = dict->italic_angle; + font_info->is_fixed_pitch = dict->is_fixed_pitch; + font_info->underline_position = (FT_Short)dict->underline_position; + font_info->underline_thickness = (FT_UShort)dict->underline_thickness; + + cff->font_info = font_info; + } + + if ( cff ) + *afont_info = *cff->font_info; + + Fail: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_ps_get_font_extra( FT_Face face, /* CFF_Face */ + PS_FontExtraRec* afont_extra ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + FT_Error error = FT_Err_Ok; + + + if ( cff && !cff->font_extra ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_FontExtraRec* font_extra = NULL; + FT_String* embedded_postscript; + + + if ( FT_QNEW( font_extra ) ) + goto Fail; + + font_extra->fs_type = 0U; + + embedded_postscript = cff_index_get_sid_string( + cff, + dict->embedded_postscript ); + if ( embedded_postscript ) + { + FT_String* start_fstype; + FT_String* start_def; + + + /* Identify the XYZ integer in `/FSType XYZ def' substring. */ + if ( ( start_fstype = ft_strstr( embedded_postscript, + "/FSType" ) ) != NULL && + ( start_def = ft_strstr( start_fstype + + sizeof ( "/FSType" ) - 1, + "def" ) ) != NULL ) + { + FT_String* s; + + + for ( s = start_fstype + sizeof ( "/FSType" ) - 1; + s != start_def; + s++ ) + { + if ( *s >= '0' && *s <= '9' ) + { + if ( font_extra->fs_type >= ( FT_USHORT_MAX - 9 ) / 10 ) + { + /* Overflow - ignore the FSType value. */ + font_extra->fs_type = 0U; + break; + } + + font_extra->fs_type *= 10; + font_extra->fs_type += (FT_UShort)( *s - '0' ); + } + else if ( *s != ' ' && *s != '\n' && *s != '\r' ) + { + /* Non-whitespace character between `/FSType' and next `def' */ + /* - ignore the FSType value. */ + font_extra->fs_type = 0U; + break; + } + } + } + } + + cff->font_extra = font_extra; + } + + if ( cff ) + *afont_extra = *cff->font_extra; + + Fail: + return error; + } + + + FT_DEFINE_SERVICE_PSINFOREC( + cff_service_ps_info, + + cff_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + cff_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + cff_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ + /* unsupported with CFF fonts */ + NULL, /* PS_GetFontPrivateFunc ps_get_font_private */ + /* not implemented */ + NULL /* PS_GetFontValueFunc ps_get_font_value */ + ) + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + FT_CALLBACK_DEF( const char* ) + cff_get_ps_name( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + + + /* following the OpenType specification 1.7, we return the name stored */ + /* in the `name' table for a CFF wrapped into an SFNT container */ + + if ( FT_IS_SFNT( face ) && sfnt ) + { + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); + FT_Service_PsFontName service = + (FT_Service_PsFontName)ft_module_get_service( + sfnt_module, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, + 0 ); + + + if ( service && service->get_ps_font_name ) + return service->get_ps_font_name( face ); + } + + return cff ? (const char*)cff->font_name : NULL; + } + + + FT_DEFINE_SERVICE_PSFONTNAMEREC( + cff_service_ps_name, + + cff_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */ + ) + + + /* + * TT CMAP INFO + * + * If the charmap is a synthetic Unicode encoding cmap or + * a Type 1 standard (or expert) encoding cmap, hide TT CMAP INFO + * service defined in SFNT module. + * + * Otherwise call the service function in the sfnt module. + * + */ + FT_CALLBACK_DEF( FT_Error ) + cff_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = FT_CMAP( charmap ); + FT_Error error = FT_Err_Ok; + + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Library library = FT_FACE_LIBRARY( face ); + + + if ( cmap->clazz != &cff_cmap_encoding_class_rec && + cmap->clazz != &cff_cmap_unicode_class_rec ) + { + FT_Module sfnt = FT_Get_Module( library, "sfnt" ); + FT_Service_TTCMaps service = + (FT_Service_TTCMaps)ft_module_get_service( sfnt, + FT_SERVICE_ID_TT_CMAP, + 0 ); + + + if ( service && service->get_cmap_info ) + error = service->get_cmap_info( charmap, cmap_info ); + } + else + error = FT_THROW( Invalid_CharMap_Format ); + + return error; + } + + + FT_DEFINE_SERVICE_TTCMAPSREC( + cff_service_get_cmap_info, + + cff_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */ + ) + + + /* + * CID INFO SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + cff_get_ros( FT_Face face, /* FT_Face */ + const char* *registry, + const char* *ordering, + FT_Int *supplement ) + { + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + + + if ( cff ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + + + if ( dict->cid_registry == 0xFFFFU ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + if ( registry ) + { + if ( !cff->registry ) + cff->registry = cff_index_get_sid_string( cff, + dict->cid_registry ); + *registry = cff->registry; + } + + if ( ordering ) + { + if ( !cff->ordering ) + cff->ordering = cff_index_get_sid_string( cff, + dict->cid_ordering ); + *ordering = cff->ordering; + } + + /* + * XXX: According to Adobe TechNote #5176, the supplement in CFF + * can be a real number. We truncate it to fit public API + * since freetype-2.3.6. + */ + if ( supplement ) + { + if ( dict->cid_supplement < FT_INT_MIN || + dict->cid_supplement > FT_INT_MAX ) + FT_TRACE1(( "cff_get_ros: too large supplement %ld is truncated\n", + dict->cid_supplement )); + *supplement = (FT_Int)dict->cid_supplement; + } + } + + Fail: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_is_cid( FT_Face face, /* CFF_Face */ + FT_Bool *is_cid ) + { + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + + + *is_cid = 0; + + if ( cff ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + + + if ( dict->cid_registry != 0xFFFFU ) + *is_cid = 1; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_cid_from_glyph_index( FT_Face face, /* CFF_Face */ + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + + + if ( cff ) + { + FT_UInt c; + CFF_FontRecDict dict = &cff->top_font.font_dict; + + + if ( dict->cid_registry == 0xFFFFU ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + if ( glyph_index >= cff->num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + c = cff->charset.sids[glyph_index]; + + if ( cid ) + *cid = c; + } + + Fail: + return error; + } + + + FT_DEFINE_SERVICE_CIDREC( + cff_service_cid_info, + + cff_get_ros, + /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */ + cff_get_is_cid, + /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */ + cff_get_cid_from_glyph_index + /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */ + ) + + + /* + * PROPERTY SERVICE + * + */ + + FT_DEFINE_SERVICE_PROPERTIESREC( + cff_service_properties, + + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /* + * MULTIPLE MASTER SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cff_set_mm_blend( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_mm_blend( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_blend( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_mm_blend( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_set_mm_weightvector( FT_Face face, /* CFF_Face */ + FT_UInt len, + FT_Fixed* weightvector ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_mm_weightvector( face, len, weightvector ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_weightvector( FT_Face face, /* CFF_Face */ + FT_UInt* len, + FT_Fixed* weightvector ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_mm_weightvector( face, len, weightvector ); + } + + + FT_CALLBACK_DEF( void ) + cff_construct_ps_name( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->construct_ps_name( face ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_var( FT_Face face, /* CFF_Face */ + FT_MM_Var* *master ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_mm_var( face, master ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_set_var_design( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_var_design( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_var_design( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_var_design( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_set_named_instance( FT_Face face, /* CFF_Face */ + FT_UInt instance_index ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_named_instance( face, instance_index ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_default_named_instance( FT_Face face, /* CFF_Face */ + FT_UInt *instance_index ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_default_named_instance( face, instance_index ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_load_item_variation_store( FT_Face face, /* CFF_Face */ + FT_ULong offset, + GX_ItemVarStore itemStore ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->load_item_var_store( face, offset, itemStore ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_load_delta_set_index_mapping( FT_Face face, /* CFF_Face */ + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->load_delta_set_idx_map( face, offset, map, + itemStore, table_len ); + } + + + FT_CALLBACK_DEF( FT_Int ) + cff_get_item_delta( FT_Face face, /* CFF_Face */ + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_item_delta( face, itemStore, outerIndex, innerIndex ); + } + + + FT_CALLBACK_DEF( void ) + cff_done_item_variation_store( FT_Face face, /* CFF_Face */ + GX_ItemVarStore itemStore ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->done_item_var_store( face, itemStore ); + } + + + FT_CALLBACK_DEF( void ) + cff_done_delta_set_index_map( FT_Face face, /* CFF_Face */ + GX_DeltaSetIdxMap deltaSetIdxMap ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->done_delta_set_idx_map( face, deltaSetIdxMap ); + } + + + + FT_DEFINE_SERVICE_MULTIMASTERSREC( + cff_service_multi_masters, + + NULL, /* FT_Get_MM_Func get_mm */ + NULL, /* FT_Set_MM_Design_Func set_mm_design */ + cff_set_mm_blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + cff_get_mm_blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + cff_get_mm_var, /* FT_Get_MM_Var_Func get_mm_var */ + cff_set_var_design, /* FT_Set_Var_Design_Func set_var_design */ + cff_get_var_design, /* FT_Get_Var_Design_Func get_var_design */ + cff_set_named_instance, + /* FT_Set_Named_Instance_Func set_named_instance */ + cff_get_default_named_instance, + /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + cff_set_mm_weightvector, + /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + cff_get_mm_weightvector, + /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ + cff_construct_ps_name, + /* FT_Construct_PS_Name_Func construct_ps_name */ + cff_load_delta_set_index_mapping, + /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + cff_load_item_variation_store, + /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + cff_get_item_delta, + /* FT_Var_Get_Item_Delta_Func get_item_delta */ + cff_done_item_variation_store, + /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + cff_done_delta_set_index_map, + /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + cff_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */ + cff_done_blend /* FT_Done_Blend_Func done_blend */ + ) + + + /* + * METRICS VARIATIONS SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cff_hadvance_adjust( FT_Face face, /* CFF_Face */ + FT_UInt gindex, + FT_Int *avalue ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MetricsVariations + var = (FT_Service_MetricsVariations)cffface->tt_var; + + + return var->hadvance_adjust( face, gindex, avalue ); + } + + + FT_CALLBACK_DEF( void ) + cff_metrics_adjust( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MetricsVariations + var = (FT_Service_MetricsVariations)cffface->tt_var; + + + var->metrics_adjust( face ); + } + + + FT_DEFINE_SERVICE_METRICSVARIATIONSREC( + cff_service_metrics_variations, + + cff_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */ + NULL, /* FT_LSB_Adjust_Func lsb_adjust */ + NULL, /* FT_RSB_Adjust_Func rsb_adjust */ + + NULL, /* FT_VAdvance_Adjust_Func vadvance_adjust */ + NULL, /* FT_TSB_Adjust_Func tsb_adjust */ + NULL, /* FT_BSB_Adjust_Func bsb_adjust */ + NULL, /* FT_VOrg_Adjust_Func vorg_adjust */ + + cff_metrics_adjust, /* FT_Metrics_Adjust_Func metrics_adjust */ + NULL /* FT_Size_Reset_Func size_reset */ + ) +#endif + + + /* + * CFFLOAD SERVICE + * + */ + + FT_DEFINE_SERVICE_CFFLOADREC( + cff_service_cff_load, + + cff_get_standard_encoding, /* FT_Get_Standard_Encoding_Func get_standard_encoding */ + cff_load_private_dict, /* FT_Load_Private_Dict_Func load_private_dict */ + cff_fd_select_get, /* FT_FD_Select_Get_Func fd_select_get */ + cff_blend_check_vector, /* FT_Blend_Check_Vector_Func blend_check_vector */ + cff_blend_build_vector /* FT_Blend_Build_Vector_Func blend_build_vector */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#if defined TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_DEFINE_SERVICEDESCREC10( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_MULTI_MASTERS, &cff_service_multi_masters, + FT_SERVICE_ID_METRICS_VARIATIONS, &cff_service_metrics_variations, + FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, + FT_SERVICE_ID_CID, &cff_service_cid_info, + FT_SERVICE_ID_PROPERTIES, &cff_service_properties, + FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load + ) +#else + FT_DEFINE_SERVICEDESCREC8( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, + FT_SERVICE_ID_CID, &cff_service_cid_info, + FT_SERVICE_ID_PROPERTIES, &cff_service_properties, + FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load + ) +#endif + + + FT_CALLBACK_DEF( FT_Module_Interface ) + cff_get_interface( FT_Module driver, /* CFF_Driver */ + const char* module_interface ) + { + FT_Library library; + FT_Module sfnt; + FT_Module_Interface result; + + + result = ft_service_list_lookup( cff_services, module_interface ); + if ( result ) + return result; + + /* `driver' is not yet evaluated */ + if ( !driver ) + return NULL; + library = driver->library; + if ( !library ) + return NULL; + + /* we pass our request to the `sfnt' module */ + sfnt = FT_Get_Module( library, "sfnt" ); + + return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#define CFF_SIZE_SELECT cff_size_select +#else +#define CFF_SIZE_SELECT 0 +#endif + + FT_DEFINE_DRIVER( + cff_driver_class, + + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER | + FT_MODULE_DRIVER_HINTS_LIGHTLY, + + sizeof ( PS_DriverRec ), + "cff", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + cff_driver_init, /* FT_Module_Constructor module_init */ + cff_driver_done, /* FT_Module_Destructor module_done */ + cff_get_interface, /* FT_Module_Requester get_interface */ + + sizeof ( TT_FaceRec ), + sizeof ( CFF_SizeRec ), + sizeof ( CFF_GlyphSlotRec ), + + cff_face_init, /* FT_Face_InitFunc init_face */ + cff_face_done, /* FT_Face_DoneFunc done_face */ + cff_size_init, /* FT_Size_InitFunc init_size */ + cff_size_done, /* FT_Size_DoneFunc done_size */ + cff_slot_init, /* FT_Slot_InitFunc init_slot */ + cff_slot_done, /* FT_Slot_DoneFunc done_slot */ + + cff_glyph_load, /* FT_Slot_LoadFunc load_glyph */ + + cff_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + cff_get_advances, /* FT_Face_GetAdvancesFunc get_advances */ + + cff_size_request, /* FT_Size_RequestFunc request_size */ + CFF_SIZE_SELECT /* FT_Size_SelectFunc select_size */ + ) + + +/* END */ diff --git a/vendor/freetype/src/cff/cffdrivr.h b/vendor/freetype/src/cff/cffdrivr.h new file mode 100644 index 0000000..ab1f147 --- /dev/null +++ b/vendor/freetype/src/cff/cffdrivr.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * cffdrivr.h + * + * High-level OpenType driver interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFDRIVER_H_ +#define CFFDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_DRIVER( cff_driver_class ) + +FT_END_HEADER + +#endif /* CFFDRIVER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cff/cfferrs.h b/vendor/freetype/src/cff/cfferrs.h new file mode 100644 index 0000000..bc9a304 --- /dev/null +++ b/vendor/freetype/src/cff/cfferrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * cfferrs.h + * + * CFF error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the CFF error enumeration constants. + * + */ + +#ifndef CFFERRS_H_ +#define CFFERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CFF_Err_ +#define FT_ERR_BASE FT_Mod_Err_CFF + + +#include + +#endif /* CFFERRS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cff/cffgload.c b/vendor/freetype/src/cff/cffgload.c new file mode 100644 index 0000000..c483d1d --- /dev/null +++ b/vendor/freetype/src/cff/cffgload.c @@ -0,0 +1,762 @@ +/**************************************************************************** + * + * cffgload.c + * + * OpenType Glyph Loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "cffload.h" +#include "cffgload.h" + +#include "cfferrs.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#define IS_DEFAULT_INSTANCE( _face ) \ + ( !( FT_IS_NAMED_INSTANCE( _face ) || \ + FT_IS_VARIATION( _face ) ) ) +#else +#define IS_DEFAULT_INSTANCE( _face ) 1 +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffgload + + + FT_LOCAL_DEF( FT_Error ) + cff_get_glyph_data( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( face->root.internal->incremental_interface ) + { + FT_Data data; + FT_Error error = + face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, &data ); + + + *pointer = (FT_Byte*)data.pointer; + *length = data.length; + + return error; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + { + CFF_Font cff = (CFF_Font)( face->extra.data ); + + + return cff_index_access_element( &cff->charstrings_index, glyph_index, + pointer, length ); + } + } + + + FT_LOCAL_DEF( void ) + cff_free_glyph_data( TT_Face face, + FT_Byte** pointer, + FT_ULong length ) + { +#ifndef FT_CONFIG_OPTION_INCREMENTAL + FT_UNUSED( length ); +#endif + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( face->root.internal->incremental_interface ) + { + FT_Data data; + + + data.pointer = *pointer; + data.length = (FT_UInt)length; + + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, &data ); + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + { + CFF_Font cff = (CFF_Font)( face->extra.data ); + + + cff_index_forget_element( &cff->charstrings_index, pointer ); + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#if 0 /* unused until we support pure CFF fonts */ + + + FT_LOCAL_DEF( FT_Error ) + cff_compute_max_advance( TT_Face face, + FT_Int* max_advance ) + { + FT_Error error = FT_Err_Ok; + CFF_Decoder decoder; + FT_Int glyph_index; + CFF_Font cff = (CFF_Font)face->other; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; + + + *max_advance = 0; + + /* Initialize load decoder */ + decoder_funcs->init( &decoder, face, 0, 0, 0, 0, 0, 0 ); + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* For each glyph, parse the glyph charstring and extract */ + /* the advance width. */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + FT_Byte* charstring; + FT_ULong charstring_len; + + + /* now get load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); + if ( !error ) + { + error = decoder_funcs->prepare( &decoder, size, glyph_index ); + if ( !error ) + error = decoder_funcs->parse_charstrings_old( &decoder, + charstring, + charstring_len, + 0 ); + + cff_free_glyph_data( face, &charstring, &charstring_len ); + } + + /* ignore the error if one has occurred -- skip to next glyph */ + error = FT_Err_Ok; + } + + *max_advance = decoder.builder.advance.x; + + return FT_Err_Ok; + } + + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + cff_slot_load( CFF_GlyphSlot glyph, + CFF_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + CFF_Decoder decoder; + PS_Decoder psdecoder; + TT_Face face = (TT_Face)glyph->root.face; + FT_Bool hinting, scaled, force_scaling; + CFF_Font cff = (CFF_Font)face->extra.data; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; + + FT_Matrix font_matrix; + FT_Vector font_offset; + + + force_scaling = FALSE; + + /* in a CID-keyed font, consider `glyph_index' as a CID and map */ + /* it immediately to the real glyph_index -- if it isn't a */ + /* subsetted font, glyph_indices and CIDs are identical, though */ + if ( cff->top_font.font_dict.cid_registry != 0xFFFFU && + cff->charset.cids ) + { + /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */ + if ( glyph_index != 0 ) + { + glyph_index = cff_charset_cid_to_gindex( &cff->charset, + glyph_index ); + if ( glyph_index == 0 ) + return FT_THROW( Invalid_Argument ); + } + } + else if ( glyph_index >= cff->num_glyphs ) + return FT_THROW( Invalid_Argument ); + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + if ( size ) + { + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* try to load embedded bitmap if any */ + /* */ + /* XXX: The convention should be emphasized in */ + /* the documents because it can be confusing. */ + if ( size ) + { + CFF_Face cff_face = (CFF_Face)size->root.face; + SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt; + FT_Stream stream = cff_face->root.stream; + + + if ( size->strike_index != 0xFFFFFFFFUL && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + IS_DEFAULT_INSTANCE( size->root.face ) ) + { + TT_SBit_MetricsRec metrics; + + + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_UInt)load_flags, + stream, + &glyph->root.bitmap, + &metrics ); + + if ( !error ) + { + FT_Bool has_vertical_info; + FT_UShort advance; + FT_Short dummy; + + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + glyph->root.metrics.width = (FT_Pos)metrics.width * 64; + glyph->root.metrics.height = (FT_Pos)metrics.height * 64; + + glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX * 64; + glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY * 64; + glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance * 64; + + glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX * 64; + glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY * 64; + glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance * 64; + + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->root.bitmap_left = metrics.vertBearingX; + glyph->root.bitmap_top = metrics.vertBearingY; + } + else + { + glyph->root.bitmap_left = metrics.horiBearingX; + glyph->root.bitmap_top = metrics.horiBearingY; + } + + /* compute linear advance widths */ + + (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0, + glyph_index, + &dummy, + &advance ); + glyph->root.linearHoriAdvance = advance; + + has_vertical_info = FT_BOOL( + face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ); + + /* get the vertical metrics from the vmtx table if we have one */ + if ( has_vertical_info ) + { + (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1, + glyph_index, + &dummy, + &advance ); + glyph->root.linearVertAdvance = advance; + } + else + { + /* make up vertical ones */ + if ( face->os2.version != 0xFFFFU ) + glyph->root.linearVertAdvance = (FT_Pos) + ( face->os2.sTypoAscender - face->os2.sTypoDescender ); + else + glyph->root.linearVertAdvance = (FT_Pos) + ( face->horizontal.Ascender - face->horizontal.Descender ); + } + + return error; + } + } + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* return immediately if we only want the embedded bitmaps */ + if ( load_flags & FT_LOAD_SBITS_ONLY ) + return FT_THROW( Invalid_Argument ); + +#ifdef FT_CONFIG_OPTION_SVG + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + ( load_flags & FT_LOAD_COLOR ) && + face->svg ) + { + /* + * We load the SVG document and try to grab the advances from the + * table. For the bearings we rely on the presetting hook to do that. + */ + + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + if ( size && (size->root.metrics.x_ppem < 1 || + size->root.metrics.y_ppem < 1 ) ) + { + error = FT_THROW( Invalid_Size_Handle ); + return error; + } + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + + error = sfnt->load_svg_doc( (FT_GlyphSlot)glyph, glyph_index ); + if ( !error ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short dummy; + FT_UShort advanceX; + FT_UShort advanceY; + + + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->root.format = FT_GLYPH_FORMAT_SVG; + + /* + * If horizontal or vertical advances are not present in the table, + * this is a problem with the font since the standard requires them. + * However, we are graceful and calculate the values by ourselves + * for the vertical case. + */ + sfnt->get_metrics( face, + FALSE, + glyph_index, + &dummy, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &dummy, + &advanceY ); + + glyph->root.linearHoriAdvance = advanceX; + glyph->root.linearVertAdvance = advanceY; + + glyph->root.metrics.horiAdvance = FT_MulFix( advanceX, x_scale ); + glyph->root.metrics.vertAdvance = FT_MulFix( advanceY, y_scale ); + + return error; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + /* if we have a CID subfont, use its matrix (which has already */ + /* been multiplied with the root matrix) */ + + /* this scaling is only relevant if the PS hinter isn't active */ + if ( cff->num_subfonts ) + { + FT_Long top_upm, sub_upm; + FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, + glyph_index ); + + + if ( fd_index >= cff->num_subfonts ) + fd_index = (FT_Byte)( cff->num_subfonts - 1 ); + + top_upm = (FT_Long)cff->top_font.font_dict.units_per_em; + sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em; + + font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; + font_offset = cff->subfonts[fd_index]->font_dict.font_offset; + + if ( top_upm != sub_upm ) + { + glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm ); + glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm ); + + force_scaling = TRUE; + } + } + else + { + font_matrix = cff->top_font.font_dict.font_matrix; + font_offset = cff->top_font.font_dict.font_offset; + } + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + /* top-level code ensures that FT_LOAD_NO_HINTING is set */ + /* if FT_LOAD_NO_SCALE is active */ + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); + + glyph->hint = hinting; + glyph->scaled = scaled; + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */ + + { +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); +#endif + + FT_Byte* charstring; + FT_ULong charstring_len; + + + decoder_funcs->init( &decoder, face, size, glyph, hinting, + FT_LOAD_TARGET_MODE( load_flags ), + cff_get_glyph_data, + cff_free_glyph_data ); + + /* this is for pure CFFs */ + if ( load_flags & FT_LOAD_ADVANCE_ONLY ) + decoder.width_only = TRUE; + + decoder.builder.no_recurse = + FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); + + /* this function also checks for a valid subfont index */ + error = decoder_funcs->prepare( &decoder, size, glyph_index ); + if ( error ) + goto Glyph_Build_Finished; + + /* now load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); + if ( error ) + goto Glyph_Build_Finished; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + /* choose which CFF renderer to use */ + if ( driver->hinting_engine == FT_HINTING_FREETYPE ) + error = decoder_funcs->parse_charstrings_old( &decoder, + charstring, + charstring_len, + 0 ); + else +#endif + { + psaux->ps_decoder_init( &psdecoder, &decoder, FALSE ); + + error = decoder_funcs->parse_charstrings( &psdecoder, + charstring, + charstring_len ); + + /* Adobe's engine uses 16.16 numbers everywhere; */ + /* as a consequence, glyphs larger than 2000ppem get rejected */ + if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) + { + /* this time, we retry unhinted and scale up the glyph later on */ + /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ + /* 0x400 for both `x_scale' and `y_scale' in this case) */ + hinting = FALSE; + force_scaling = TRUE; + glyph->hint = hinting; + + error = decoder_funcs->parse_charstrings( &psdecoder, + charstring, + charstring_len ); + } + } + + cff_free_glyph_data( face, &charstring, charstring_len ); + + if ( error ) + goto Glyph_Build_Finished; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Control data and length may not be available for incremental */ + /* fonts. */ + if ( face->root.internal->incremental_interface ) + { + glyph->root.control_data = NULL; + glyph->root.control_len = 0; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + /* We set control_data and control_len if charstrings is loaded. */ + /* See how charstring loads at cff_index_access_element() in */ + /* cffload.c. */ + { + CFF_Index csindex = &cff->charstrings_index; + + + if ( csindex->offsets ) + { + glyph->root.control_data = csindex->bytes + + csindex->offsets[glyph_index] - 1; + glyph->root.control_len = (FT_Long)charstring_len; + } + } + + Glyph_Build_Finished: + /* save new glyph tables, if no error */ + if ( !error ) + decoder.builder.funcs.done( &decoder.builder ); + /* XXX: anything to do for broken glyph entry? */ + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && + face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = decoder.builder.left_bearing.x; + metrics.bearing_y = 0; + metrics.advance = decoder.builder.advance.x; + metrics.advance_v = decoder.builder.advance.y; + + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &metrics ); + + decoder.builder.left_bearing.x = metrics.bearing_x; + decoder.builder.advance.x = metrics.advance; + decoder.builder.advance.y = metrics.advance_v; + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + if ( !error ) + { + /* Now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax. */ + + /* For composite glyphs, return only left side bearing and */ + /* advance width. */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = glyph->root.internal; + + + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.glyph_width; + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + FT_Bool has_vertical_info; + + + if ( face->horizontal.number_Of_HMetrics ) + { + FT_Short horiBearingX = 0; + FT_UShort horiAdvance = 0; + + + ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, + glyph_index, + &horiBearingX, + &horiAdvance ); + metrics->horiAdvance = horiAdvance; + metrics->horiBearingX = horiBearingX; + glyph->root.linearHoriAdvance = horiAdvance; + } + else + { + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.glyph_width; + glyph->root.linearHoriAdvance = decoder.glyph_width; + } + + glyph->root.internal->glyph_transformed = 0; + + has_vertical_info = FT_BOOL( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ); + + /* get the vertical metrics from the vmtx table if we have one */ + if ( has_vertical_info ) + { + FT_Short vertBearingY = 0; + FT_UShort vertAdvance = 0; + + + ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, + glyph_index, + &vertBearingY, + &vertAdvance ); + metrics->vertBearingY = vertBearingY; + metrics->vertAdvance = vertAdvance; + } + else + { + /* make up vertical ones */ + if ( face->os2.version != 0xFFFFU ) + metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender - + face->horizontal.Descender ); + } + + glyph->root.linearVertAdvance = metrics->vertAdvance; + + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + + glyph->root.outline.flags = 0; + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + { + FT_Outline_Transform( &glyph->root.outline, &font_matrix ); + + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + font_matrix.xx ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, + font_matrix.yy ); + } + + if ( font_offset.x || font_offset.y ) + { + FT_Outline_Translate( &glyph->root.outline, + font_offset.x, + font_offset.y ); + + metrics->horiAdvance += font_offset.x; + metrics->vertAdvance += font_offset.y; + } + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = &glyph->root.outline; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + if ( has_vertical_info ) + { + metrics->vertBearingX = metrics->horiBearingX - + metrics->horiAdvance / 2; + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, + glyph->y_scale ); + } + else + { + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + } + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/cff/cffgload.h b/vendor/freetype/src/cff/cffgload.h new file mode 100644 index 0000000..3b8cf23 --- /dev/null +++ b/vendor/freetype/src/cff/cffgload.h @@ -0,0 +1,62 @@ +/**************************************************************************** + * + * cffgload.h + * + * OpenType Glyph Loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFGLOAD_H_ +#define CFFGLOAD_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + cff_get_glyph_data( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ); + FT_LOCAL( void ) + cff_free_glyph_data( TT_Face face, + FT_Byte** pointer, + FT_ULong length ); + + +#if 0 /* unused until we support pure CFF fonts */ + + /* Compute the maximum advance width of a font through quick parsing */ + FT_LOCAL( FT_Error ) + cff_compute_max_advance( TT_Face face, + FT_Int* max_advance ); + +#endif /* 0 */ + + + FT_LOCAL( FT_Error ) + cff_slot_load( CFF_GlyphSlot glyph, + CFF_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* CFFGLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cff/cffload.c b/vendor/freetype/src/cff/cffload.c new file mode 100644 index 0000000..af79082 --- /dev/null +++ b/vendor/freetype/src/cff/cffload.c @@ -0,0 +1,2579 @@ +/**************************************************************************** + * + * cffload.c + * + * OpenType and CFF data/program tables loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include "cffload.h" +#include "cffparse.h" + +#include "cfferrs.h" + + +#define FT_FIXED_ONE ( (FT_Fixed)0x10000 ) + + +#if 1 + + static const FT_UShort cff_isoadobe_charset[229] = + { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228 + }; + + static const FT_UShort cff_expert_charset[166] = + { + 0, 1, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, + 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 326, 150, + 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 + }; + + static const FT_UShort cff_expertsubset_charset[87] = + { + 0, 1, 231, 232, 235, 236, 237, 238, + 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, + 300, 301, 302, 305, 314, 315, 158, 155, + 163, 320, 321, 322, 323, 324, 325, 326, + 150, 164, 169, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 + }; + + static const FT_UShort cff_standard_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, + 0, 111, 112, 113, 114, 0, 115, 116, + 117, 118, 119, 120, 121, 122, 0, 123, + 0, 124, 125, 126, 127, 128, 129, 130, + 131, 0, 132, 133, 0, 134, 135, 136, + 137, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 139, 0, 0, 0, 0, + 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, + 146, 147, 148, 149, 0, 0, 0, 0 + }; + + static const FT_UShort cff_expert_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 229, 230, 0, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 0, 253, 254, 255, 256, 257, 0, 0, + 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, + 110, 267, 268, 269, 0, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 306, 0, 0, 307, 308, + 309, 310, 311, 0, 312, 0, 0, 312, + 0, 0, 314, 315, 0, 0, 316, 317, + 318, 0, 0, 0, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 0, 0, + 326, 150, 164, 169, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378 + }; + +#endif /* 1 */ + + + FT_LOCAL_DEF( FT_UShort ) + cff_get_standard_encoding( FT_UInt charcode ) + { + return (FT_UShort)( charcode < 256 ? cff_standard_encoding[charcode] + : 0 ); + } + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffload + + + /* read an offset from the index's stream current position */ + static FT_ULong + cff_index_read_offset( CFF_Index idx, + FT_Error *errorp ) + { + FT_Error error; + FT_Stream stream = idx->stream; + FT_Byte tmp[4]; + FT_ULong result = 0; + + + if ( !FT_STREAM_READ( tmp, idx->off_size ) ) + { + FT_Int nn; + + + for ( nn = 0; nn < idx->off_size; nn++ ) + result = ( result << 8 ) | tmp[nn]; + } + + *errorp = error; + return result; + } + + + static FT_Error + cff_index_init( CFF_Index idx, + FT_Stream stream, + FT_Bool load, + FT_Bool cff2 ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt count; + + + FT_ZERO( idx ); + + idx->stream = stream; + idx->start = FT_STREAM_POS(); + + if ( cff2 ) + { + if ( FT_READ_ULONG( count ) ) + goto Exit; + idx->hdr_size = 5; + } + else + { + if ( FT_READ_USHORT( count ) ) + goto Exit; + idx->hdr_size = 3; + } + + if ( count > 0 ) + { + FT_Byte offsize; + FT_ULong size; + + + /* there is at least one element; read the offset size, */ + /* then access the offset table to compute the index's total size */ + if ( FT_READ_BYTE( offsize ) ) + goto Exit; + + if ( offsize < 1 || offsize > 4 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + idx->count = count; + idx->off_size = offsize; + size = (FT_ULong)( count + 1 ) * offsize; + + idx->data_offset = idx->start + idx->hdr_size + size; + + if ( FT_STREAM_SKIP( size - offsize ) ) + goto Exit; + + size = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + + if ( size == 0 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + idx->data_size = --size; + + if ( load ) + { + /* load the data */ + if ( FT_FRAME_EXTRACT( size, idx->bytes ) ) + goto Exit; + } + else + { + /* skip the data */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + } + + Exit: + if ( error ) + FT_FREE( idx->offsets ); + + return error; + } + + + static void + cff_index_done( CFF_Index idx ) + { + if ( idx->stream ) + { + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + + + if ( idx->bytes ) + FT_FRAME_RELEASE( idx->bytes ); + + FT_FREE( idx->offsets ); + FT_ZERO( idx ); + } + } + + + static FT_Error + cff_index_load_offsets( CFF_Index idx ) + { + FT_Error error = FT_Err_Ok; + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + + + if ( idx->count > 0 && !idx->offsets ) + { + FT_Byte offsize = idx->off_size; + FT_ULong data_size; + FT_Byte* p; + FT_Byte* p_end; + FT_ULong* poff; + + + data_size = (FT_ULong)( idx->count + 1 ) * offsize; + + if ( FT_QNEW_ARRAY( idx->offsets, idx->count + 1 ) || + FT_STREAM_SEEK( idx->start + idx->hdr_size ) || + FT_FRAME_ENTER( data_size ) ) + goto Exit; + + poff = idx->offsets; + p = (FT_Byte*)stream->cursor; + p_end = p + data_size; + + switch ( offsize ) + { + case 1: + for ( ; p < p_end; p++, poff++ ) + poff[0] = p[0]; + break; + + case 2: + for ( ; p < p_end; p += 2, poff++ ) + poff[0] = FT_PEEK_USHORT( p ); + break; + + case 3: + for ( ; p < p_end; p += 3, poff++ ) + poff[0] = FT_PEEK_UOFF3( p ); + break; + + default: + for ( ; p < p_end; p += 4, poff++ ) + poff[0] = FT_PEEK_ULONG( p ); + } + + FT_FRAME_EXIT(); + } + + Exit: + if ( error ) + FT_FREE( idx->offsets ); + + return error; + } + + + /* Allocate a table containing pointers to an index's elements. */ + /* The `pool' argument makes this function convert the index */ + /* entries to C-style strings (that is, null-terminated). */ + static FT_Error + cff_index_get_pointers( CFF_Index idx, + FT_Byte*** table, + FT_Byte** pool, + FT_ULong* pool_size ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = idx->stream->memory; + + FT_Byte** tbl = NULL; + FT_Byte* new_bytes = NULL; + FT_ULong new_size; + + + *table = NULL; + + if ( !idx->offsets ) + { + error = cff_index_load_offsets( idx ); + if ( error ) + goto Exit; + } + + new_size = idx->data_size + idx->count; + + if ( idx->count > 0 && + !FT_QNEW_ARRAY( tbl, idx->count + 1 ) && + ( !pool || !FT_ALLOC( new_bytes, new_size ) ) ) + { + FT_ULong n, cur_offset; + FT_ULong extra = 0; + FT_Byte* org_bytes = idx->bytes; + + + /* at this point, `idx->offsets' can't be NULL */ + cur_offset = idx->offsets[0] - 1; + + /* sanity check */ + if ( cur_offset != 0 ) + { + FT_TRACE0(( "cff_index_get_pointers:" + " invalid first offset value %ld set to zero\n", + cur_offset )); + cur_offset = 0; + } + + if ( !pool ) + tbl[0] = org_bytes + cur_offset; + else + tbl[0] = new_bytes + cur_offset; + + for ( n = 1; n <= idx->count; n++ ) + { + FT_ULong next_offset = idx->offsets[n] - 1; + + + /* two sanity checks for invalid offset tables */ + if ( next_offset < cur_offset ) + next_offset = cur_offset; + else if ( next_offset > idx->data_size ) + next_offset = idx->data_size; + + if ( !pool ) + tbl[n] = org_bytes + next_offset; + else + { + tbl[n] = new_bytes + next_offset + extra; + + if ( next_offset != cur_offset ) + { + FT_MEM_COPY( tbl[n - 1], + org_bytes + cur_offset, + tbl[n] - tbl[n - 1] ); + tbl[n][0] = '\0'; + tbl[n] += 1; + extra++; + } + } + + cur_offset = next_offset; + } + *table = tbl; + + if ( pool ) + *pool = new_bytes; + if ( pool_size ) + *pool_size = new_size; + } + + Exit: + if ( error && new_bytes ) + FT_FREE( new_bytes ); + if ( error && tbl ) + FT_FREE( tbl ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_index_access_element( CFF_Index idx, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ) + { + FT_Error error = FT_Err_Ok; + + + if ( idx && idx->count > element ) + { + /* compute start and end offsets */ + FT_Stream stream = idx->stream; + FT_ULong off1, off2 = 0; + + + /* load offsets from file or the offset table */ + if ( !idx->offsets ) + { + FT_ULong pos = element * idx->off_size; + + + if ( FT_STREAM_SEEK( idx->start + idx->hdr_size + pos ) ) + goto Exit; + + off1 = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + + if ( off1 != 0 ) + { + do + { + element++; + off2 = cff_index_read_offset( idx, &error ); + + } while ( off2 == 0 && element < idx->count ); + } + } + else /* use offsets table */ + { + off1 = idx->offsets[element]; + if ( off1 ) + { + do + { + element++; + off2 = idx->offsets[element]; + + } while ( off2 == 0 && element < idx->count ); + } + } + + /* XXX: should check off2 does not exceed the end of this entry; */ + /* at present, only truncate off2 at the end of this stream */ + if ( off2 > stream->size + 1 || + idx->data_offset > stream->size - off2 + 1 ) + { + FT_ERROR(( "cff_index_access_element:" + " offset to next entry (%ld)" + " exceeds the end of stream (%ld)\n", + off2, stream->size - idx->data_offset + 1 )); + off2 = stream->size - idx->data_offset + 1; + } + + /* access element */ + if ( off1 && off2 > off1 ) + { + *pbyte_len = off2 - off1; + + if ( idx->bytes ) + { + /* this index was completely loaded in memory, that's easy */ + *pbytes = idx->bytes + off1 - 1; + } + else + { + /* this index is still on disk/file, access it through a frame */ + if ( FT_STREAM_SEEK( idx->data_offset + off1 - 1 ) || + FT_FRAME_EXTRACT( off2 - off1, *pbytes ) ) + goto Exit; + } + } + else + { + /* empty index element */ + *pbytes = 0; + *pbyte_len = 0; + } + } + else + error = FT_THROW( Invalid_Argument ); + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_index_forget_element( CFF_Index idx, + FT_Byte** pbytes ) + { + if ( idx->bytes == 0 ) + { + FT_Stream stream = idx->stream; + + + FT_FRAME_RELEASE( *pbytes ); + } + } + + + /* get an entry from Name INDEX */ + FT_LOCAL_DEF( FT_String* ) + cff_index_get_name( CFF_Font font, + FT_UInt element ) + { + CFF_Index idx = &font->name_index; + FT_Memory memory; + FT_Byte* bytes; + FT_ULong byte_len; + FT_Error error; + FT_String* name = NULL; + + + if ( !idx->stream ) /* CFF2 does not include a name index */ + goto Exit; + + memory = idx->stream->memory; + + error = cff_index_access_element( idx, element, &bytes, &byte_len ); + if ( error ) + goto Exit; + + if ( !FT_QALLOC( name, byte_len + 1 ) ) + { + FT_MEM_COPY( name, bytes, byte_len ); + name[byte_len] = 0; + } + cff_index_forget_element( idx, &bytes ); + + Exit: + return name; + } + + + /* get an entry from String INDEX */ + FT_LOCAL_DEF( FT_String* ) + cff_index_get_string( CFF_Font font, + FT_UInt element ) + { + return ( element < font->num_strings ) + ? (FT_String*)font->strings[element] + : NULL; + } + + + FT_LOCAL_DEF( FT_String* ) + cff_index_get_sid_string( CFF_Font font, + FT_UInt sid ) + { + /* value 0xFFFFU indicates a missing dictionary entry */ + if ( sid == 0xFFFFU ) + return NULL; + + /* if it is not a standard string, return it */ + if ( sid > 390 ) + return cff_index_get_string( font, sid - 391 ); + + /* CID-keyed CFF fonts don't have glyph names */ + if ( !font->psnames ) + return NULL; + + /* this is a standard string */ + return (FT_String *)font->psnames->adobe_std_strings( sid ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** FD Select table support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + + static void + CFF_Done_FD_Select( CFF_FDSelect fdselect, + FT_Stream stream ) + { + if ( fdselect->data ) + FT_FRAME_RELEASE( fdselect->data ); + + fdselect->data_size = 0; + fdselect->format = 0; + fdselect->range_count = 0; + } + + + static FT_Error + CFF_Load_FD_Select( CFF_FDSelect fdselect, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong offset ) + { + FT_Error error; + FT_Byte format; + FT_UInt num_ranges; + + + /* read format */ + if ( FT_STREAM_SEEK( offset ) || FT_READ_BYTE( format ) ) + goto Exit; + + fdselect->format = format; + fdselect->cache_count = 0; /* clear cache */ + + switch ( format ) + { + case 0: /* format 0, that's simple */ + fdselect->data_size = num_glyphs; + goto Load_Data; + + case 3: /* format 3, a tad more complex */ + if ( FT_READ_USHORT( num_ranges ) ) + goto Exit; + + if ( !num_ranges ) + { + FT_TRACE0(( "CFF_Load_FD_Select: empty FDSelect array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + fdselect->data_size = num_ranges * 3 + 2; + + Load_Data: + if ( FT_FRAME_EXTRACT( fdselect->data_size, fdselect->data ) ) + goto Exit; + break; + + default: /* hmm... that's wrong */ + error = FT_THROW( Invalid_File_Format ); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ) + { + FT_Byte fd = 0; + + + /* if there is no FDSelect, return zero */ + /* Note: CFF2 with just one Font Dict has no FDSelect */ + if ( !fdselect->data ) + goto Exit; + + switch ( fdselect->format ) + { + case 0: + fd = fdselect->data[glyph_index]; + break; + + case 3: + /* first, compare to the cache */ + if ( glyph_index - fdselect->cache_first < fdselect->cache_count ) + { + fd = fdselect->cache_fd; + break; + } + + /* then, look up the ranges array */ + { + FT_Byte* p = fdselect->data; + FT_Byte* p_limit = p + fdselect->data_size; + FT_Byte fd2; + FT_UInt first, limit; + + + first = FT_NEXT_USHORT( p ); + do + { + if ( glyph_index < first ) + break; + + fd2 = *p++; + limit = FT_NEXT_USHORT( p ); + + if ( glyph_index < limit ) + { + fd = fd2; + + /* update cache */ + fdselect->cache_first = first; + fdselect->cache_count = limit - first; + fdselect->cache_fd = fd2; + break; + } + first = limit; + + } while ( p < p_limit ); + } + break; + + default: + ; + } + + Exit: + return fd; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** CFF font support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + cff_charset_compute_cids( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_UInt i; + FT_UShort max_cid = 0; + + + if ( charset->max_cid > 0 ) + goto Exit; + + for ( i = 0; i < num_glyphs; i++ ) + { + if ( charset->sids[i] > max_cid ) + max_cid = charset->sids[i]; + } + + if ( FT_NEW_ARRAY( charset->cids, (FT_ULong)max_cid + 1 ) ) + goto Exit; + + /* When multiple GIDs map to the same CID, we choose the lowest */ + /* GID. This is not described in any spec, but it matches the */ + /* behaviour of recent Acroread versions. The loop stops when */ + /* the unsigned index wraps around after reaching zero. */ + for ( i = num_glyphs - 1; i < num_glyphs; i-- ) + charset->cids[charset->sids[i]] = (FT_UShort)i; + + charset->max_cid = max_cid; + charset->num_glyphs = num_glyphs; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_UInt ) + cff_charset_cid_to_gindex( CFF_Charset charset, + FT_UInt cid ) + { + FT_UInt result = 0; + + + if ( cid <= charset->max_cid ) + result = charset->cids[cid]; + + return result; + } + + + static void + cff_charset_free_cids( CFF_Charset charset, + FT_Memory memory ) + { + FT_FREE( charset->cids ); + charset->max_cid = 0; + } + + + static void + cff_charset_done( CFF_Charset charset, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + cff_charset_free_cids( charset, memory ); + + FT_FREE( charset->sids ); + charset->format = 0; + charset->offset = 0; + } + + + static FT_Error + cff_charset_load( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset, + FT_Bool invert ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + FT_UShort glyph_sid; + + + /* If the offset is greater than 2, we have to parse the charset */ + /* table. */ + if ( offset > 2 ) + { + FT_UInt j; + + + charset->offset = base_offset + offset; + + /* Get the format of the table. */ + if ( FT_STREAM_SEEK( charset->offset ) || + FT_READ_BYTE( charset->format ) ) + goto Exit; + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* assign the .notdef glyph */ + charset->sids[0] = 0; + + switch ( charset->format ) + { + case 0: + if ( num_glyphs > 0 ) + { + if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) ) + goto Exit; + + for ( j = 1; j < num_glyphs; j++ ) + charset->sids[j] = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + } + break; + + case 1: + case 2: + { + FT_UInt nleft; + FT_UInt i; + + + j = 1; + + while ( j < num_glyphs ) + { + /* Read the first glyph sid of the range. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; + + /* Read the number of glyphs in the range. */ + if ( charset->format == 2 ) + { + if ( FT_READ_USHORT( nleft ) ) + goto Exit; + } + else + { + if ( FT_READ_BYTE( nleft ) ) + goto Exit; + } + + /* try to rescue some of the SIDs if `nleft' is too large */ + if ( glyph_sid > 0xFFFFL - nleft ) + { + FT_ERROR(( "cff_charset_load: invalid SID range trimmed" + " nleft=%d -> %ld\n", nleft, 0xFFFFL - glyph_sid )); + nleft = ( FT_UInt )( 0xFFFFL - glyph_sid ); + } + + /* Fill in the range of sids -- `nleft + 1' glyphs. */ + for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ ) + charset->sids[j] = glyph_sid; + } + } + break; + + default: + FT_ERROR(( "cff_charset_load: invalid table format\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + else + { + /* Parse default tables corresponding to offset == 0, 1, or 2. */ + /* CFF specification intimates the following: */ + /* */ + /* In order to use a predefined charset, the following must be */ + /* true: The charset constructed for the glyphs in the font's */ + /* charstrings dictionary must match the predefined charset in */ + /* the first num_glyphs. */ + + charset->offset = offset; /* record charset type */ + + switch ( (FT_UInt)offset ) + { + case 0: + if ( num_glyphs > 229 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe ISO-Latin)\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs ); + + break; + + case 1: + if ( num_glyphs > 166 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert)\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs ); + + break; + + case 2: + if ( num_glyphs > 87 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert Subset)\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs ); + + break; + + default: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + /* we have to invert the `sids' array for subsetted CID-keyed fonts */ + if ( invert ) + error = cff_charset_compute_cids( charset, num_glyphs, memory ); + + Exit: + /* Clean up if there was an error. */ + if ( error ) + { + FT_FREE( charset->sids ); + FT_FREE( charset->cids ); + charset->format = 0; + charset->offset = 0; + } + + return error; + } + + + static void + cff_vstore_done( CFF_VStoreRec* vstore, + FT_Memory memory ) + { + FT_UInt i; + + + /* free regionList and axisLists */ + if ( vstore->varRegionList ) + { + for ( i = 0; i < vstore->regionCount; i++ ) + FT_FREE( vstore->varRegionList[i].axisList ); + } + FT_FREE( vstore->varRegionList ); + + /* free varData and indices */ + if ( vstore->varData ) + { + for ( i = 0; i < vstore->dataCount; i++ ) + FT_FREE( vstore->varData[i].regionIndices ); + } + FT_FREE( vstore->varData ); + } + + + /* convert 2.14 to Fixed */ + #define FT_fdot14ToFixed( x ) ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) + + + static FT_Error + cff_vstore_load( CFF_VStoreRec* vstore, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_ERR( Invalid_File_Format ); + + FT_ULong* dataOffsetArray = NULL; + FT_UInt i, j; + + + /* no offset means no vstore to parse */ + if ( offset ) + { + FT_UInt vsOffset; + FT_UInt format; + FT_UInt dataCount; + FT_UInt regionCount; + FT_ULong regionListOffset; + + + /* we need to parse the table to determine its size; */ + /* skip table length */ + if ( FT_STREAM_SEEK( base_offset + offset ) || + FT_STREAM_SKIP( 2 ) ) + goto Exit; + + /* actual variation store begins after the length */ + vsOffset = FT_STREAM_POS(); + + /* check the header */ + if ( FT_READ_USHORT( format ) ) + goto Exit; + if ( format != 1 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* read top level fields */ + if ( FT_READ_ULONG( regionListOffset ) || + FT_READ_USHORT( dataCount ) ) + goto Exit; + + /* make temporary copy of item variation data offsets; */ + /* we'll parse region list first, then come back */ + if ( FT_QNEW_ARRAY( dataOffsetArray, dataCount ) ) + goto Exit; + + for ( i = 0; i < dataCount; i++ ) + { + if ( FT_READ_ULONG( dataOffsetArray[i] ) ) + goto Exit; + } + + /* parse regionList and axisLists */ + if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) || + FT_READ_USHORT( vstore->axisCount ) || + FT_READ_USHORT( regionCount ) ) + goto Exit; + + vstore->regionCount = 0; + if ( FT_QNEW_ARRAY( vstore->varRegionList, regionCount ) ) + goto Exit; + + for ( i = 0; i < regionCount; i++ ) + { + CFF_VarRegion* region = &vstore->varRegionList[i]; + + + if ( FT_QNEW_ARRAY( region->axisList, vstore->axisCount ) ) + goto Exit; + + /* keep track of how many axisList to deallocate on error */ + vstore->regionCount++; + + for ( j = 0; j < vstore->axisCount; j++ ) + { + CFF_AxisCoords* axis = ®ion->axisList[j]; + + FT_Int16 start14, peak14, end14; + + + if ( FT_READ_SHORT( start14 ) || + FT_READ_SHORT( peak14 ) || + FT_READ_SHORT( end14 ) ) + goto Exit; + + axis->startCoord = FT_fdot14ToFixed( start14 ); + axis->peakCoord = FT_fdot14ToFixed( peak14 ); + axis->endCoord = FT_fdot14ToFixed( end14 ); + } + } + + /* use dataOffsetArray now to parse varData items */ + vstore->dataCount = 0; + if ( FT_QNEW_ARRAY( vstore->varData, dataCount ) ) + goto Exit; + + for ( i = 0; i < dataCount; i++ ) + { + CFF_VarData* data = &vstore->varData[i]; + + + if ( FT_STREAM_SEEK( vsOffset + dataOffsetArray[i] ) ) + goto Exit; + + /* ignore `itemCount' and `shortDeltaCount' */ + /* because CFF2 has no delta sets */ + if ( FT_STREAM_SKIP( 4 ) ) + goto Exit; + + /* Note: just record values; consistency is checked later */ + /* by cff_blend_build_vector when it consumes `vstore' */ + + if ( FT_READ_USHORT( data->regionIdxCount ) ) + goto Exit; + + if ( FT_QNEW_ARRAY( data->regionIndices, data->regionIdxCount ) ) + goto Exit; + + /* keep track of how many regionIndices to deallocate on error */ + vstore->dataCount++; + + for ( j = 0; j < data->regionIdxCount; j++ ) + { + if ( FT_READ_USHORT( data->regionIndices[j] ) ) + goto Exit; + } + } + } + + error = FT_Err_Ok; + + Exit: + FT_FREE( dataOffsetArray ); + if ( error ) + cff_vstore_done( vstore, memory ); + + return error; + } + + + /* Clear blend stack (after blend values are consumed). */ + /* */ + /* TODO: Should do this in cff_run_parse, but subFont */ + /* ref is not available there. */ + /* */ + /* Allocation is not changed when stack is cleared. */ + FT_LOCAL_DEF( void ) + cff_blend_clear( CFF_SubFont subFont ) + { + subFont->blend_top = subFont->blend_stack; + subFont->blend_used = 0; + } + + + /* Blend numOperands on the stack, */ + /* store results into the first numBlends values, */ + /* then pop remaining arguments. */ + /* */ + /* This is comparable to `cf2_doBlend' but */ + /* the cffparse stack is different and can't be written. */ + /* Blended values are written to a different buffer, */ + /* using reserved operator 255. */ + /* */ + /* Blend calculation is done in 16.16 fixed-point. */ + FT_LOCAL_DEF( FT_Error ) + cff_blend_doBlend( CFF_SubFont subFont, + CFF_Parser parser, + FT_UInt numBlends ) + { + FT_UInt delta; + FT_UInt base; + FT_UInt i, j; + FT_UInt size; + + CFF_Blend blend = &subFont->blend; + + FT_Memory memory = subFont->blend.font->memory; /* for FT_REALLOC */ + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + + /* compute expected number of operands for this blend */ + FT_UInt numOperands = (FT_UInt)( numBlends * blend->lenBV ); + FT_UInt count = (FT_UInt)( parser->top - 1 - parser->stack ); + + + if ( numOperands > count ) + { + FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d argument%s\n", + count, + count == 1 ? "" : "s" )); + + error = FT_THROW( Stack_Underflow ); + goto Exit; + } + + /* check whether we have room for `numBlends' values at `blend_top' */ + size = 5 * numBlends; /* add 5 bytes per entry */ + if ( subFont->blend_used + size > subFont->blend_alloc ) + { + FT_Byte* blend_stack_old = subFont->blend_stack; + FT_Byte* blend_top_old = subFont->blend_top; + + + /* increase or allocate `blend_stack' and reset `blend_top'; */ + /* prepare to append `numBlends' values to the buffer */ + if ( FT_QREALLOC( subFont->blend_stack, + subFont->blend_alloc, + subFont->blend_alloc + size ) ) + goto Exit; + + subFont->blend_top = subFont->blend_stack + subFont->blend_used; + subFont->blend_alloc += size; + + /* iterate over the parser stack and adjust pointers */ + /* if the reallocated buffer has a different address */ + if ( blend_stack_old && + subFont->blend_stack != blend_stack_old ) + { + FT_PtrDist offset = subFont->blend_stack - blend_stack_old; + FT_Byte** p; + + + for ( p = parser->stack; p < parser->top; p++ ) + { + if ( *p >= blend_stack_old && *p < blend_top_old ) + *p += offset; + } + } + } + subFont->blend_used += size; + + base = count - numOperands; /* index of first blend arg */ + delta = base + numBlends; /* index of first delta arg */ + + for ( i = 0; i < numBlends; i++ ) + { + const FT_Int32* weight = &blend->BV[1]; + FT_Fixed sum; + + + /* convert inputs to 16.16 fixed point */ + sum = cff_parse_fixed( parser, &parser->stack[i + base] ); + + for ( j = 1; j < blend->lenBV; j++ ) + sum += FT_MulFix( cff_parse_fixed( parser, &parser->stack[delta++] ), + *weight++ ); + + /* point parser stack to new value on blend_stack */ + parser->stack[i + base] = subFont->blend_top; + + /* Push blended result as Type 2 5-byte fixed-point number. This */ + /* will not conflict with actual DICTs because 255 is a reserved */ + /* opcode in both CFF and CFF2 DICTs. See `cff_parse_num' for */ + /* decode of this, which rounds to an integer. */ + *subFont->blend_top++ = 255; + *subFont->blend_top++ = (FT_Byte)( sum >> 24 ); + *subFont->blend_top++ = (FT_Byte)( sum >> 16 ); + *subFont->blend_top++ = (FT_Byte)( sum >> 8 ); + *subFont->blend_top++ = (FT_Byte)sum; + } + + /* leave only numBlends results on parser stack */ + parser->top = &parser->stack[base + numBlends]; + + Exit: + return error; + } + + + /* Compute a blend vector from variation store index and normalized */ + /* vector based on pseudo-code in OpenType Font Variations Overview. */ + /* */ + /* Note: lenNDV == 0 produces a default blend vector, (1,0,0,...). */ + FT_LOCAL_DEF( FT_Error ) + cff_blend_build_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + FT_Memory memory = blend->font->memory; /* for FT_REALLOC */ + + FT_UInt len; + CFF_VStore vs; + CFF_VarData* varData; + FT_UInt master; + + + /* protect against malformed fonts */ + if ( !( lenNDV == 0 || NDV ) ) + { + FT_TRACE4(( " cff_blend_build_vector:" + " Malformed Normalize Design Vector data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + blend->builtBV = FALSE; + + vs = &blend->font->vstore; + + /* VStore and fvar must be consistent */ + if ( lenNDV != 0 && lenNDV != vs->axisCount ) + { + FT_TRACE4(( " cff_blend_build_vector: Axis count mismatch\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( vsindex >= vs->dataCount ) + { + FT_TRACE4(( " cff_blend_build_vector: vsindex out of range\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* select the item variation data structure */ + varData = &vs->varData[vsindex]; + + /* prepare buffer for the blend vector */ + len = varData->regionIdxCount + 1; /* add 1 for default component */ + if ( FT_QRENEW_ARRAY( blend->BV, blend->lenBV, len ) ) + goto Exit; + + blend->lenBV = len; + + /* outer loop steps through master designs to be blended */ + for ( master = 0; master < len; master++ ) + { + FT_UInt j; + FT_UInt idx; + CFF_VarRegion* varRegion; + + + /* default factor is always one */ + if ( master == 0 ) + { + blend->BV[master] = FT_FIXED_ONE; + FT_TRACE4(( " build blend vector len %d\n", len )); + FT_TRACE4(( " [ %f ", blend->BV[master] / 65536.0 )); + continue; + } + + /* VStore array does not include default master, so subtract one */ + idx = varData->regionIndices[master - 1]; + varRegion = &vs->varRegionList[idx]; + + if ( idx >= vs->regionCount ) + { + FT_TRACE4(( " cff_blend_build_vector:" + " region index out of range\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Note: `lenNDV' could be zero. */ + /* In that case, build default blend vector (1,0,0...). */ + if ( !lenNDV ) + { + blend->BV[master] = 0; + continue; + } + + /* In the normal case, initialize each component to 1 */ + /* before inner loop. */ + blend->BV[master] = FT_FIXED_ONE; /* default */ + + /* inner loop steps through axes in this region */ + for ( j = 0; j < lenNDV; j++ ) + { + CFF_AxisCoords* axis = &varRegion->axisList[j]; + FT_Fixed axisScalar; + + + /* compute the scalar contribution of this axis; */ + /* ignore invalid ranges */ + if ( axis->startCoord > axis->peakCoord || + axis->peakCoord > axis->endCoord ) + axisScalar = FT_FIXED_ONE; + + else if ( axis->startCoord < 0 && + axis->endCoord > 0 && + axis->peakCoord != 0 ) + axisScalar = FT_FIXED_ONE; + + /* peak of 0 means ignore this axis */ + else if ( axis->peakCoord == 0 ) + axisScalar = FT_FIXED_ONE; + + /* ignore this region if coords are out of range */ + else if ( NDV[j] < axis->startCoord || + NDV[j] > axis->endCoord ) + axisScalar = 0; + + /* calculate a proportional factor */ + else + { + if ( NDV[j] == axis->peakCoord ) + axisScalar = FT_FIXED_ONE; + else if ( NDV[j] < axis->peakCoord ) + axisScalar = FT_DivFix( NDV[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else + axisScalar = FT_DivFix( axis->endCoord - NDV[j], + axis->endCoord - axis->peakCoord ); + } + + /* take product of all the axis scalars */ + blend->BV[master] = FT_MulFix( blend->BV[master], axisScalar ); + } + + FT_TRACE4(( ", %f ", + blend->BV[master] / 65536.0 )); + } + + FT_TRACE4(( "]\n" )); + + /* record the parameters used to build the blend vector */ + blend->lastVsindex = vsindex; + + if ( lenNDV != 0 ) + { + /* user has set a normalized vector */ + if ( FT_QRENEW_ARRAY( blend->lastNDV, blend->lenNDV, lenNDV ) ) + goto Exit; + + FT_MEM_COPY( blend->lastNDV, + NDV, + lenNDV * sizeof ( *NDV ) ); + } + + blend->lenNDV = lenNDV; + blend->builtBV = TRUE; + + Exit: + return error; + } + + + /* `lenNDV' is zero for default vector; */ + /* return TRUE if blend vector needs to be built. */ + FT_LOCAL_DEF( FT_Bool ) + cff_blend_check_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + if ( !blend->builtBV || + blend->lastVsindex != vsindex || + blend->lenNDV != lenNDV || + ( lenNDV && + ft_memcmp( NDV, + blend->lastNDV, + lenNDV * sizeof ( *NDV ) ) != 0 ) ) + { + /* need to build blend vector */ + return TRUE; + } + + return FALSE; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + FT_LOCAL_DEF( FT_Error ) + cff_get_var_blend( FT_Face face, /* CFF_Face */ + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_var_blend( face, + num_coords, + coords, + normalizedcoords, + mm_var ); + } + + + FT_LOCAL_DEF( void ) + cff_done_blend( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + if ( mm ) + mm->done_blend( face ); + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static void + cff_encoding_done( CFF_Encoding encoding ) + { + encoding->format = 0; + encoding->offset = 0; + encoding->count = 0; + } + + + static FT_Error + cff_encoding_load( CFF_Encoding encoding, + CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count; + FT_UInt j; + FT_UShort glyph_sid; + FT_UInt glyph_code; + + + /* Check for charset->sids. If we do not have this, we fail. */ + if ( !charset->sids ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Note: The encoding table in a CFF font is indexed by glyph index; */ + /* the first encoded glyph index is 1. Hence, we read the character */ + /* code (`glyph_code') at index j and make the assignment: */ + /* */ + /* encoding->codes[glyph_code] = j + 1 */ + /* */ + /* We also make the assignment: */ + /* */ + /* encoding->sids[glyph_code] = charset->sids[j + 1] */ + /* */ + /* This gives us both a code to GID and a code to SID mapping. */ + + if ( offset > 1 ) + { + /* Zero out the code to gid/sid mappings. */ + FT_ARRAY_ZERO( encoding->sids, 256 ); + FT_ARRAY_ZERO( encoding->codes, 256 ); + + encoding->offset = base_offset + offset; + + /* we need to parse the table to determine its size */ + if ( FT_STREAM_SEEK( encoding->offset ) || + FT_READ_BYTE( encoding->format ) || + FT_READ_BYTE( count ) ) + goto Exit; + + switch ( encoding->format & 0x7F ) + { + case 0: + { + FT_Byte* p; + + + /* By convention, GID 0 is always ".notdef" and is never */ + /* coded in the font. Hence, the number of codes found */ + /* in the table is `count+1'. */ + /* */ + encoding->count = count + 1; + + if ( FT_FRAME_ENTER( count ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + + for ( j = 1; j <= count; j++ ) + { + glyph_code = *p++; + + /* Make sure j is not too big. */ + if ( j < num_glyphs ) + { + /* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)j; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[j]; + } + } + + FT_FRAME_EXIT(); + } + break; + + case 1: + { + FT_UInt nleft; + FT_UInt i = 1; + FT_UInt k; + + + encoding->count = 0; + + /* Parse the Format1 ranges. */ + for ( j = 0; j < count; j++, i += nleft ) + { + /* Read the first glyph code of the range. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; + + /* Read the number of codes in the range. */ + if ( FT_READ_BYTE( nleft ) ) + goto Exit; + + /* Increment nleft, so we read `nleft + 1' codes/sids. */ + nleft++; + + /* compute max number of character codes */ + if ( (FT_UInt)nleft > encoding->count ) + encoding->count = nleft; + + /* Fill in the range of codes/sids. */ + for ( k = i; k < nleft + i; k++, glyph_code++ ) + { + /* Make sure k is not too big. */ + if ( k < num_glyphs && glyph_code < 256 ) + { + /* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)k; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[k]; + } + } + } + + /* simple check; one never knows what can be found in a font */ + if ( encoding->count > 256 ) + encoding->count = 256; + } + break; + + default: + FT_ERROR(( "cff_encoding_load: invalid table format\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Parse supplemental encodings, if any. */ + if ( encoding->format & 0x80 ) + { + FT_UInt gindex; + + + /* count supplements */ + if ( FT_READ_BYTE( count ) ) + goto Exit; + + for ( j = 0; j < count; j++ ) + { + /* Read supplemental glyph code. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; + + /* Read the SID associated with this glyph code. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = glyph_sid; + + /* First, look up GID which has been assigned to */ + /* SID glyph_sid. */ + for ( gindex = 0; gindex < num_glyphs; gindex++ ) + { + if ( charset->sids[gindex] == glyph_sid ) + { + encoding->codes[glyph_code] = (FT_UShort)gindex; + break; + } + } + } + } + } + else + { + /* We take into account the fact a CFF font can use a predefined */ + /* encoding without containing all of the glyphs encoded by this */ + /* encoding (see the note at the end of section 12 in the CFF */ + /* specification). */ + + switch ( (FT_UInt)offset ) + { + case 0: + /* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_standard_encoding, 256 ); + goto Populate; + + case 1: + /* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_expert_encoding, 256 ); + + Populate: + /* Construct code to GID mapping from code to SID mapping */ + /* and charset. */ + + encoding->offset = offset; /* used in cff_face_init */ + encoding->count = 0; + + error = cff_charset_compute_cids( charset, num_glyphs, + stream->memory ); + if ( error ) + goto Exit; + + for ( j = 0; j < 256; j++ ) + { + FT_UInt sid = encoding->sids[j]; + FT_UInt gid = 0; + + + if ( sid ) + gid = cff_charset_cid_to_gindex( charset, sid ); + + if ( gid != 0 ) + { + encoding->codes[j] = (FT_UShort)gid; + encoding->count = j + 1; + } + else + { + encoding->codes[j] = 0; + encoding->sids [j] = 0; + } + } + break; + + default: + FT_ERROR(( "cff_encoding_load: invalid table format\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + Exit: + + /* Clean up if there was an error. */ + return error; + } + + + /* Parse private dictionary; first call is always from `cff_face_init', */ + /* so NDV has not been set for CFF2 variation. */ + /* */ + /* `cff_slot_load' must call this function each time NDV changes. */ + FT_LOCAL_DEF( FT_Error ) + cff_load_private_dict( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + FT_Error error = FT_Err_Ok; + CFF_ParserRec parser; + CFF_FontRecDict top = &subfont->font_dict; + CFF_Private priv = &subfont->private_dict; + FT_Stream stream = font->stream; + FT_UInt stackSize; + + + /* store handle needed to access memory, vstore for blend; */ + /* we need this for clean-up even if there is no private DICT */ + subfont->blend.font = font; + subfont->blend.usedBV = FALSE; /* clear state */ + + if ( !top->private_offset || !top->private_size ) + goto Exit2; /* no private DICT, do nothing */ + + /* set defaults */ + FT_ZERO( priv ); + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = -1; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + + /* provide inputs for blend calculations */ + priv->subfont = subfont; + subfont->lenNDV = lenNDV; + subfont->NDV = NDV; + + /* add 1 for the operator */ + stackSize = font->cff2 ? font->top_font.font_dict.maxstack + 1 + : CFF_MAX_STACK_DEPTH + 1; + + if ( cff_parser_init( &parser, + font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE, + priv, + font->library, + stackSize, + top->num_designs, + top->num_axes ) ) + goto Exit; + + if ( FT_STREAM_SEEK( font->base_offset + top->private_offset ) || + FT_FRAME_ENTER( top->private_size ) ) + goto Exit; + + FT_TRACE4(( " private dictionary:\n" )); + error = cff_parser_run( &parser, + (FT_Byte*)stream->cursor, + (FT_Byte*)stream->limit ); + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + /* ensure that `num_blue_values' is even */ + priv->num_blue_values &= ~1; + + /* sanitize `initialRandomSeed' to be a positive value, if necessary; */ + /* this is not mandated by the specification but by our implementation */ + if ( priv->initial_random_seed < 0 ) + priv->initial_random_seed = -priv->initial_random_seed; + else if ( priv->initial_random_seed == 0 ) + priv->initial_random_seed = 987654321; + + /* some sanitizing to avoid overflows later on; */ + /* the upper limits are ad-hoc values */ + if ( priv->blue_shift > 1000 || priv->blue_shift < 0 ) + { + FT_TRACE2(( "cff_load_private_dict:" + " setting unlikely BlueShift value %ld to default (7)\n", + priv->blue_shift )); + priv->blue_shift = 7; + } + + if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 ) + { + FT_TRACE2(( "cff_load_private_dict:" + " setting unlikely BlueFuzz value %ld to default (1)\n", + priv->blue_fuzz )); + priv->blue_fuzz = 1; + } + + Exit: + /* clean up */ + cff_blend_clear( subfont ); /* clear blend stack */ + cff_parser_done( &parser ); /* free parser stack */ + + Exit2: + /* no clean up (parser not initialized) */ + return error; + } + + + /* There are 3 ways to call this function, distinguished by code. */ + /* */ + /* . CFF_CODE_TOPDICT for either a CFF Top DICT or a CFF Font DICT */ + /* . CFF2_CODE_TOPDICT for CFF2 Top DICT */ + /* . CFF2_CODE_FONTDICT for CFF2 Font DICT */ + + static FT_Error + cff_subfont_load( CFF_SubFont subfont, + CFF_Index idx, + FT_UInt font_index, + FT_Stream stream, + FT_ULong base_offset, + FT_UInt code, + CFF_Font font, + CFF_Face face ) + { + FT_Error error; + CFF_ParserRec parser; + FT_Byte* dict = NULL; + FT_ULong dict_len; + CFF_FontRecDict top = &subfont->font_dict; + CFF_Private priv = &subfont->private_dict; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + FT_Bool cff2 = FT_BOOL( code == CFF2_CODE_TOPDICT || + code == CFF2_CODE_FONTDICT ); + FT_UInt stackSize = cff2 ? CFF2_DEFAULT_STACK + : CFF_MAX_STACK_DEPTH; + + + /* Note: We use default stack size for CFF2 Font DICT because */ + /* Top and Font DICTs are not allowed to have blend operators. */ + error = cff_parser_init( &parser, + code, + top, + font->library, + stackSize, + 0, + 0 ); + if ( error ) + goto Exit; + + /* set defaults */ + FT_ZERO( top ); + + top->underline_position = -( 100L << 16 ); + top->underline_thickness = 50L << 16; + top->charstring_type = 2; + top->font_matrix.xx = 0x10000L; + top->font_matrix.yy = 0x10000L; + top->cid_count = 8720; + + /* we use the implementation specific SID value 0xFFFF to indicate */ + /* missing entries */ + top->version = 0xFFFFU; + top->notice = 0xFFFFU; + top->copyright = 0xFFFFU; + top->full_name = 0xFFFFU; + top->family_name = 0xFFFFU; + top->weight = 0xFFFFU; + top->embedded_postscript = 0xFFFFU; + + top->cid_registry = 0xFFFFU; + top->cid_ordering = 0xFFFFU; + top->cid_font_name = 0xFFFFU; + + /* set default stack size */ + top->maxstack = cff2 ? CFF2_DEFAULT_STACK : 48; + + if ( idx->count ) /* count is nonzero for a real index */ + error = cff_index_access_element( idx, font_index, &dict, &dict_len ); + else + { + /* CFF2 has a fake top dict index; */ + /* simulate `cff_index_access_element' */ + + /* Note: macros implicitly use `stream' and set `error' */ + if ( FT_STREAM_SEEK( idx->data_offset ) || + FT_FRAME_EXTRACT( idx->data_size, dict ) ) + goto Exit; + + dict_len = idx->data_size; + } + + if ( !error ) + { + FT_TRACE4(( " top dictionary:\n" )); + error = cff_parser_run( &parser, dict, FT_OFFSET( dict, dict_len ) ); + } + + /* clean up regardless of error */ + if ( idx->count ) + cff_index_forget_element( idx, &dict ); + else + FT_FRAME_RELEASE( dict ); + + if ( error ) + goto Exit; + + /* if it is a CID font, we stop there */ + if ( top->cid_registry != 0xFFFFU ) + goto Exit; + + /* Parse the private dictionary, if any. */ + /* */ + /* CFF2 does not have a private dictionary in the Top DICT */ + /* but may have one in a Font DICT. We need to parse */ + /* the latter here in order to load any local subrs. */ + error = cff_load_private_dict( font, subfont, 0, 0 ); + if ( error ) + goto Exit; + + if ( !cff2 ) + { + /* + * Initialize the random number generator. + * + * - If we have a face-specific seed, use it. + * If non-zero, update it to a positive value. + * + * - Otherwise, use the seed from the CFF driver. + * If non-zero, update it to a positive value. + * + * - If the random value is zero, use the seed given by the subfont's + * `initialRandomSeed' value. + * + */ + if ( face->root.internal->random_seed == -1 ) + { + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); + + + subfont->random = (FT_UInt32)driver->random_seed; + if ( driver->random_seed ) + { + do + { + driver->random_seed = + (FT_Int32)psaux->cff_random( (FT_UInt32)driver->random_seed ); + + } while ( driver->random_seed < 0 ); + } + } + else + { + subfont->random = (FT_UInt32)face->root.internal->random_seed; + if ( face->root.internal->random_seed ) + { + do + { + face->root.internal->random_seed = + (FT_Int32)psaux->cff_random( + (FT_UInt32)face->root.internal->random_seed ); + + } while ( face->root.internal->random_seed < 0 ); + } + } + + if ( !subfont->random ) + subfont->random = (FT_UInt32)priv->initial_random_seed; + } + + /* read the local subrs, if any */ + if ( priv->local_subrs_offset ) + { + if ( FT_STREAM_SEEK( base_offset + top->private_offset + + priv->local_subrs_offset ) ) + goto Exit; + + error = cff_index_init( &subfont->local_subrs_index, stream, 1, cff2 ); + if ( error ) + goto Exit; + + error = cff_index_get_pointers( &subfont->local_subrs_index, + &subfont->local_subrs, NULL, NULL ); + if ( error ) + goto Exit; + } + + Exit: + cff_parser_done( &parser ); /* free parser stack */ + + return error; + } + + + static void + cff_subfont_done( FT_Memory memory, + CFF_SubFont subfont ) + { + if ( subfont ) + { + cff_index_done( &subfont->local_subrs_index ); + FT_FREE( subfont->local_subrs ); + + FT_FREE( subfont->blend.lastNDV ); + FT_FREE( subfont->blend.BV ); + FT_FREE( subfont->blend_stack ); + } + } + + + FT_LOCAL_DEF( FT_Error ) + cff_font_load( FT_Library library, + FT_Stream stream, + FT_Int face_index, + CFF_Font font, + CFF_Face face, + FT_Bool pure_cff, + FT_Bool cff2 ) + { + static const FT_Frame_Field cff_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRec + + FT_FRAME_START( 3 ), + FT_FRAME_BYTE( version_major ), + FT_FRAME_BYTE( version_minor ), + FT_FRAME_BYTE( header_size ), + FT_FRAME_END + }; + + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong base_offset; + CFF_FontRecDict dict; + CFF_IndexRec string_index; + FT_UInt subfont_index; + + + FT_ZERO( font ); + FT_ZERO( &string_index ); + + dict = &font->top_font.font_dict; + base_offset = FT_STREAM_POS(); + + font->library = library; + font->stream = stream; + font->memory = memory; + font->cff2 = cff2; + font->base_offset = base_offset; + + /* read CFF font header */ + if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) ) + goto Exit; + + if ( cff2 ) + { + if ( font->version_major != 2 || + font->header_size < 5 ) + { + FT_TRACE2(( " not a CFF2 font header\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( FT_READ_USHORT( font->top_dict_length ) ) + goto Exit; + } + else + { + FT_Byte absolute_offset; + + + if ( FT_READ_BYTE( absolute_offset ) ) + goto Exit; + + if ( font->version_major != 1 || + font->header_size < 4 || + absolute_offset > 4 ) + { + FT_TRACE2(( " not a CFF font header\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + } + + /* skip the rest of the header */ + if ( FT_STREAM_SEEK( base_offset + font->header_size ) ) + { + /* For pure CFFs we have read only four bytes so far. Contrary to */ + /* other formats like SFNT those bytes doesn't define a signature; */ + /* it is thus possible that the font isn't a CFF at all. */ + if ( pure_cff ) + { + FT_TRACE2(( " not a CFF file\n" )); + error = FT_THROW( Unknown_File_Format ); + } + goto Exit; + } + + if ( cff2 ) + { + /* For CFF2, the top dict data immediately follow the header */ + /* and the length is stored in the header `offSize' field; */ + /* there is no index for it. */ + /* */ + /* Use the `font_dict_index' to save the current position */ + /* and length of data, but leave count at zero as an indicator. */ + FT_ZERO( &font->font_dict_index ); + + font->font_dict_index.data_offset = FT_STREAM_POS(); + font->font_dict_index.data_size = font->top_dict_length; + + /* skip the top dict data for now, we will parse it later */ + if ( FT_STREAM_SKIP( font->top_dict_length ) ) + goto Exit; + + /* next, read the global subrs index */ + if ( FT_SET_ERROR( cff_index_init( &font->global_subrs_index, + stream, 1, cff2 ) ) ) + goto Exit; + } + else + { + /* for CFF, read the name, top dict, string and global subrs index */ + if ( FT_SET_ERROR( cff_index_init( &font->name_index, + stream, 0, cff2 ) ) ) + { + if ( pure_cff ) + { + FT_TRACE2(( " not a CFF file\n" )); + error = FT_THROW( Unknown_File_Format ); + } + goto Exit; + } + + /* if we have an empty font name, */ + /* it must be the only font in the CFF */ + if ( font->name_index.count > 1 && + font->name_index.data_size < font->name_index.count ) + { + /* for pure CFFs, we still haven't checked enough bytes */ + /* to be sure that it is a CFF at all */ + error = pure_cff ? FT_THROW( Unknown_File_Format ) + : FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( FT_SET_ERROR( cff_index_init( &font->font_dict_index, + stream, 0, cff2 ) ) || + FT_SET_ERROR( cff_index_init( &string_index, + stream, 1, cff2 ) ) || + FT_SET_ERROR( cff_index_init( &font->global_subrs_index, + stream, 1, cff2 ) ) || + FT_SET_ERROR( cff_index_get_pointers( &string_index, + &font->strings, + &font->string_pool, + &font->string_pool_size ) ) ) + goto Exit; + + /* there must be a Top DICT index entry for each name index entry */ + if ( font->name_index.count > font->font_dict_index.count ) + { + FT_ERROR(( "cff_font_load:" + " not enough entries in Top DICT index\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + font->num_strings = string_index.count; + + if ( pure_cff ) + { + /* well, we don't really forget the `disabled' fonts... */ + subfont_index = (FT_UInt)( face_index & 0xFFFF ); + + if ( face_index > 0 && subfont_index >= font->name_index.count ) + { + FT_ERROR(( "cff_font_load:" + " invalid subfont index for pure CFF font (%d)\n", + subfont_index )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + font->num_faces = font->name_index.count; + } + else + { + subfont_index = 0; + + if ( font->name_index.count > 1 ) + { + FT_ERROR(( "cff_font_load:" + " invalid CFF font with multiple subfonts\n" )); + FT_ERROR(( " " + " in SFNT wrapper\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + /* in case of a font format check, simply exit now */ + if ( face_index < 0 ) + goto Exit; + + /* now, parse the top-level font dictionary */ + FT_TRACE4(( "parsing top-level\n" )); + error = cff_subfont_load( &font->top_font, + &font->font_dict_index, + subfont_index, + stream, + base_offset, + cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT, + font, + face ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) ) + goto Exit; + + error = cff_index_init( &font->charstrings_index, stream, 0, cff2 ); + if ( error ) + goto Exit; + + /* now, check for a CID or CFF2 font */ + if ( dict->cid_registry != 0xFFFFU || + cff2 ) + { + CFF_IndexRec fd_index; + CFF_SubFont sub = NULL; + FT_UInt idx; + + + /* for CFF2, read the Variation Store if available; */ + /* this must follow the Top DICT parse and precede any Private DICT */ + error = cff_vstore_load( &font->vstore, + stream, + base_offset, + dict->vstore_offset ); + if ( error ) + goto Exit; + + /* this is a CID-keyed font, we must now allocate a table of */ + /* sub-fonts, then load each of them separately */ + if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) ) + goto Exit; + + error = cff_index_init( &fd_index, stream, 0, cff2 ); + if ( error ) + goto Exit; + + /* Font Dicts are not limited to 256 for CFF2. */ + /* TODO: support this for CFF2 */ + if ( fd_index.count > CFF_MAX_CID_FONTS ) + { + FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" )); + goto Fail_CID; + } + + /* allocate & read each font dict independently */ + font->num_subfonts = fd_index.count; + if ( FT_NEW_ARRAY( sub, fd_index.count ) ) + goto Fail_CID; + + /* set up pointer table */ + for ( idx = 0; idx < fd_index.count; idx++ ) + font->subfonts[idx] = sub + idx; + + /* now load each subfont independently */ + for ( idx = 0; idx < fd_index.count; idx++ ) + { + sub = font->subfonts[idx]; + FT_TRACE4(( "parsing subfont %u\n", idx )); + error = cff_subfont_load( sub, + &fd_index, + idx, + stream, + base_offset, + cff2 ? CFF2_CODE_FONTDICT + : CFF_CODE_TOPDICT, + font, + face ); + if ( error ) + goto Fail_CID; + } + + /* now load the FD Select array; */ + /* CFF2 omits FDSelect if there is only one FD */ + if ( !cff2 || fd_index.count > 1 ) + error = CFF_Load_FD_Select( &font->fd_select, + font->charstrings_index.count, + stream, + base_offset + dict->cid_fd_select_offset ); + + Fail_CID: + cff_index_done( &fd_index ); + + if ( error ) + goto Exit; + } + else + font->num_subfonts = 0; + + /* read the charstrings index now */ + if ( dict->charstrings_offset == 0 ) + { + FT_ERROR(( "cff_font_load: no charstrings offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + font->num_glyphs = font->charstrings_index.count; + + error = cff_index_get_pointers( &font->global_subrs_index, + &font->global_subrs, NULL, NULL ); + + if ( error ) + goto Exit; + + /* read the Charset and Encoding tables if available */ + if ( !cff2 && font->num_glyphs > 0 ) + { + FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff ); + + + error = cff_charset_load( &font->charset, font->num_glyphs, stream, + base_offset, dict->charset_offset, invert ); + if ( error ) + goto Exit; + + /* CID-keyed CFFs don't have an encoding */ + if ( dict->cid_registry == 0xFFFFU ) + { + error = cff_encoding_load( &font->encoding, + &font->charset, + font->num_glyphs, + stream, + base_offset, + dict->encoding_offset ); + if ( error ) + goto Exit; + } + } + + /* get the font name (/CIDFontName for CID-keyed fonts, */ + /* /FontName otherwise) */ + font->font_name = cff_index_get_name( font, subfont_index ); + + Exit: + cff_index_done( &string_index ); + + return error; + } + + + FT_LOCAL_DEF( void ) + cff_font_done( CFF_Font font ) + { + FT_Memory memory = font->memory; + FT_UInt idx; + + + cff_index_done( &font->global_subrs_index ); + cff_index_done( &font->font_dict_index ); + cff_index_done( &font->name_index ); + cff_index_done( &font->charstrings_index ); + + /* release font dictionaries, but only if working with */ + /* a CID keyed CFF font or a CFF2 font */ + if ( font->num_subfonts > 0 ) + { + for ( idx = 0; idx < font->num_subfonts; idx++ ) + cff_subfont_done( memory, font->subfonts[idx] ); + + /* the subfonts array has been allocated as a single block */ + FT_FREE( font->subfonts[0] ); + } + + cff_encoding_done( &font->encoding ); + cff_charset_done( &font->charset, font->stream ); + cff_vstore_done( &font->vstore, memory ); + + cff_subfont_done( memory, &font->top_font ); + + CFF_Done_FD_Select( &font->fd_select, font->stream ); + + FT_FREE( font->font_info ); + + FT_FREE( font->font_name ); + FT_FREE( font->global_subrs ); + FT_FREE( font->strings ); + FT_FREE( font->string_pool ); + + if ( font->cf2_instance.finalizer ) + { + font->cf2_instance.finalizer( font->cf2_instance.data ); + FT_FREE( font->cf2_instance.data ); + } + + FT_FREE( font->font_extra ); + } + + +/* END */ diff --git a/vendor/freetype/src/cff/cffload.h b/vendor/freetype/src/cff/cffload.h new file mode 100644 index 0000000..b5286b0 --- /dev/null +++ b/vendor/freetype/src/cff/cffload.h @@ -0,0 +1,124 @@ +/**************************************************************************** + * + * cffload.h + * + * OpenType & CFF data/program tables loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFLOAD_H_ +#define CFFLOAD_H_ + + +#include +#include "cffparse.h" +#include /* for CFF_Face */ + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_UShort ) + cff_get_standard_encoding( FT_UInt charcode ); + + + FT_LOCAL( FT_String* ) + cff_index_get_string( CFF_Font font, + FT_UInt element ); + + FT_LOCAL( FT_String* ) + cff_index_get_sid_string( CFF_Font font, + FT_UInt sid ); + + + FT_LOCAL( FT_Error ) + cff_index_access_element( CFF_Index idx, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ); + + FT_LOCAL( void ) + cff_index_forget_element( CFF_Index idx, + FT_Byte** pbytes ); + + FT_LOCAL( FT_String* ) + cff_index_get_name( CFF_Font font, + FT_UInt element ); + + + FT_LOCAL( FT_UInt ) + cff_charset_cid_to_gindex( CFF_Charset charset, + FT_UInt cid ); + + + FT_LOCAL( FT_Error ) + cff_font_load( FT_Library library, + FT_Stream stream, + FT_Int face_index, + CFF_Font font, + CFF_Face face, + FT_Bool pure_cff, + FT_Bool cff2 ); + + FT_LOCAL( void ) + cff_font_done( CFF_Font font ); + + + FT_LOCAL( FT_Error ) + cff_load_private_dict( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ); + + FT_LOCAL( FT_Bool ) + cff_blend_check_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( FT_Error ) + cff_blend_build_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( void ) + cff_blend_clear( CFF_SubFont subFont ); + + FT_LOCAL( FT_Error ) + cff_blend_doBlend( CFF_SubFont subfont, + CFF_Parser parser, + FT_UInt numBlends ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_LOCAL( FT_Error ) + cff_get_var_blend( FT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ); + + FT_LOCAL( void ) + cff_done_blend( FT_Face face ); +#endif + + +FT_END_HEADER + +#endif /* CFFLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cff/cffobjs.c b/vendor/freetype/src/cff/cffobjs.c new file mode 100644 index 0000000..6d08620 --- /dev/null +++ b/vendor/freetype/src/cff/cffobjs.c @@ -0,0 +1,1204 @@ +/**************************************************************************** + * + * cffobjs.c + * + * OpenType objects manager (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#include +#endif + +#include +#include "cffobjs.h" +#include "cffload.h" +#include "cffcmap.h" + +#include "cfferrs.h" + +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffobjs + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + + + static PSH_Globals_Funcs + cff_size_get_globals_funcs( CFF_Size size ) + { + CFF_Face face = (CFF_Face)size->root.face; + CFF_Font font = (CFF_Font)face->extra.data; + PSHinter_Service pshinter = font->pshinter; + FT_Module module; + + + module = FT_Get_Module( font->library, "pshinter" ); + + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + cff_size_done( FT_Size cffsize ) /* CFF_Size */ + { + FT_Memory memory = cffsize->face->memory; + CFF_Size size = (CFF_Size)cffsize; + CFF_Face face = (CFF_Face)size->root.face; + CFF_Font font = (CFF_Font)face->extra.data; + CFF_Internal internal = (CFF_Internal)cffsize->internal->module_data; + + + if ( internal ) + { + PSH_Globals_Funcs funcs; + + + funcs = cff_size_get_globals_funcs( size ); + if ( funcs ) + { + FT_UInt i; + + + funcs->destroy( internal->topfont ); + + for ( i = font->num_subfonts; i > 0; i-- ) + funcs->destroy( internal->subfonts[i - 1] ); + } + + FT_FREE( internal ); + } + } + + + /* CFF and Type 1 private dictionaries have slightly different */ + /* structures; we need to synthesize a Type 1 dictionary on the fly */ + + static void + cff_make_private_dict( CFF_SubFont subfont, + PS_Private priv ) + { + CFF_Private cpriv = &subfont->private_dict; + FT_UInt n, count; + + + FT_ZERO( priv ); + + count = priv->num_blue_values = cpriv->num_blue_values; + for ( n = 0; n < count; n++ ) + priv->blue_values[n] = (FT_Short)cpriv->blue_values[n]; + + count = priv->num_other_blues = cpriv->num_other_blues; + for ( n = 0; n < count; n++ ) + priv->other_blues[n] = (FT_Short)cpriv->other_blues[n]; + + count = priv->num_family_blues = cpriv->num_family_blues; + for ( n = 0; n < count; n++ ) + priv->family_blues[n] = (FT_Short)cpriv->family_blues[n]; + + count = priv->num_family_other_blues = cpriv->num_family_other_blues; + for ( n = 0; n < count; n++ ) + priv->family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n]; + + priv->blue_scale = cpriv->blue_scale; + priv->blue_shift = (FT_Int)cpriv->blue_shift; + priv->blue_fuzz = (FT_Int)cpriv->blue_fuzz; + + priv->standard_width[0] = (FT_UShort)cpriv->standard_width; + priv->standard_height[0] = (FT_UShort)cpriv->standard_height; + + count = priv->num_snap_widths = cpriv->num_snap_widths; + for ( n = 0; n < count; n++ ) + priv->snap_widths[n] = (FT_Short)cpriv->snap_widths[n]; + + count = priv->num_snap_heights = cpriv->num_snap_heights; + for ( n = 0; n < count; n++ ) + priv->snap_heights[n] = (FT_Short)cpriv->snap_heights[n]; + + priv->force_bold = cpriv->force_bold; + priv->language_group = cpriv->language_group; + priv->lenIV = cpriv->lenIV; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_size_init( FT_Size cffsize ) /* CFF_Size */ + { + CFF_Size size = (CFF_Size)cffsize; + FT_Error error = FT_Err_Ok; + PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size ); + + FT_Memory memory = cffsize->face->memory; + CFF_Internal internal = NULL; + CFF_Face face = (CFF_Face)cffsize->face; + CFF_Font font = (CFF_Font)face->extra.data; + + PS_PrivateRec priv; + + FT_UInt i; + + if ( !funcs ) + goto Exit; + + if ( FT_NEW( internal ) ) + goto Exit; + + cff_make_private_dict( &font->top_font, &priv ); + error = funcs->create( memory, &priv, &internal->topfont ); + if ( error ) + goto Exit; + + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + + + cff_make_private_dict( sub, &priv ); + error = funcs->create( memory, &priv, &internal->subfonts[i - 1] ); + if ( error ) + goto Exit; + } + + cffsize->internal->module_data = internal; + + size->strike_index = 0xFFFFFFFFUL; + + Exit: + if ( error ) + { + if ( internal ) + { + for ( i = font->num_subfonts; i > 0; i-- ) + FT_FREE( internal->subfonts[i - 1] ); + FT_FREE( internal->topfont ); + } + + FT_FREE( internal ); + } + + return error; + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL_DEF( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ) + { + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + + + cffsize->strike_index = strike_index; + + FT_Select_Metrics( size->face, strike_index ); + + funcs = cff_size_get_globals_funcs( cffsize ); + + if ( funcs ) + { + CFF_Face face = (CFF_Face)size->face; + CFF_Font font = (CFF_Font)face->extra.data; + CFF_Internal internal = (CFF_Internal)size->internal->module_data; + + FT_Long top_upm = (FT_Long)font->top_font.font_dict.units_per_em; + FT_UInt i; + + + funcs->set_scale( internal->topfont, + size->metrics.x_scale, size->metrics.y_scale, + 0, 0 ); + + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + FT_Long sub_upm = (FT_Long)sub->font_dict.units_per_em; + FT_Pos x_scale, y_scale; + + + if ( top_upm != sub_upm ) + { + x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm ); + y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm ); + } + else + { + x_scale = size->metrics.x_scale; + y_scale = size->metrics.y_scale; + } + + funcs->set_scale( internal->subfonts[i - 1], + x_scale, y_scale, 0, 0 ); + } + } + + return FT_Err_Ok; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + FT_LOCAL_DEF( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ) + { + FT_Error error; + + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + CFF_Face cffface = (CFF_Face)size->face; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + FT_ULong strike_index; + + + if ( sfnt->set_sbit_strike( cffface, req, &strike_index ) ) + cffsize->strike_index = 0xFFFFFFFFUL; + else + return cff_size_select( size, strike_index ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; + + funcs = cff_size_get_globals_funcs( cffsize ); + + if ( funcs ) + { + CFF_Face cffface = (CFF_Face)size->face; + CFF_Font font = (CFF_Font)cffface->extra.data; + CFF_Internal internal = (CFF_Internal)size->internal->module_data; + + FT_Long top_upm = (FT_Long)font->top_font.font_dict.units_per_em; + FT_UInt i; + + + funcs->set_scale( internal->topfont, + size->metrics.x_scale, size->metrics.y_scale, + 0, 0 ); + + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + FT_Long sub_upm = (FT_Long)sub->font_dict.units_per_em; + FT_Pos x_scale, y_scale; + + + if ( top_upm != sub_upm ) + { + x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm ); + y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm ); + } + else + { + x_scale = size->metrics.x_scale; + y_scale = size->metrics.y_scale; + } + + funcs->set_scale( internal->subfonts[i - 1], + x_scale, y_scale, 0, 0 ); + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * SLOT FUNCTIONS + * + */ + + FT_LOCAL_DEF( void ) + cff_slot_done( FT_GlyphSlot slot ) + { + if ( slot->internal ) + slot->internal->glyph_hints = NULL; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_slot_init( FT_GlyphSlot slot ) + { + CFF_Face face = (CFF_Face)slot->face; + CFF_Font font = (CFF_Font)face->extra.data; + PSHinter_Service pshinter = font->pshinter; + + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->library, "pshinter" ); + if ( module ) + { + T2_Hints_Funcs funcs; + + + funcs = pshinter->get_t2_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * FACE FUNCTIONS + * + */ + + static FT_String* + cff_strcpy( FT_Memory memory, + const FT_String* source ) + { + FT_Error error; + FT_String* result; + + + FT_MEM_STRDUP( result, source ); + + return result; + } + + + /* Strip all subset prefixes of the form `ABCDEF+'. Usually, there */ + /* is only one, but font names like `APCOOG+JFABTD+FuturaBQ-Bold' */ + /* have been seen in the wild. */ + + static void + remove_subset_prefix( FT_String* name ) + { + FT_Int32 idx = 0; + FT_Int32 length = (FT_Int32)ft_strlen( name ) + 1; + FT_Bool continue_search = 1; + + + while ( continue_search ) + { + if ( length >= 7 && name[6] == '+' ) + { + for ( idx = 0; idx < 6; idx++ ) + { + /* ASCII uppercase letters */ + if ( !( 'A' <= name[idx] && name[idx] <= 'Z' ) ) + continue_search = 0; + } + + if ( continue_search ) + { + for ( idx = 7; idx < length; idx++ ) + name[idx - 7] = name[idx]; + length -= 7; + } + } + else + continue_search = 0; + } + } + + + /* Remove the style part from the family name (if present). */ + + static void + remove_style( FT_String* family_name, + const FT_String* style_name ) + { + FT_Int32 family_name_length, style_name_length; + + + family_name_length = (FT_Int32)ft_strlen( family_name ); + style_name_length = (FT_Int32)ft_strlen( style_name ); + + if ( family_name_length > style_name_length ) + { + FT_Int idx; + + + for ( idx = 1; idx <= style_name_length; idx++ ) + { + if ( family_name[family_name_length - idx] != + style_name[style_name_length - idx] ) + break; + } + + if ( idx > style_name_length ) + { + /* family_name ends with style_name; remove it */ + idx = family_name_length - style_name_length - 1; + + /* also remove special characters */ + /* between real family name and style */ + while ( idx > 0 && + ( family_name[idx] == '-' || + family_name[idx] == ' ' || + family_name[idx] == '_' || + family_name[idx] == '+' ) ) + idx--; + + if ( idx > 0 ) + family_name[idx + 1] = '\0'; + } + } + } + + + FT_LOCAL_DEF( FT_Error ) + cff_face_init( FT_Stream stream, + FT_Face cffface, /* CFF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + CFF_Face face = (CFF_Face)cffface; + FT_Error error; + SFNT_Service sfnt; + FT_Service_PsCMaps psnames; + PSHinter_Service pshinter; + PSAux_Service psaux; + FT_Service_CFFLoad cffload; + FT_Bool pure_cff = 1; + FT_Bool cff2 = 0; + FT_Bool sfnt_format = 0; + FT_Library library = cffface->driver->root.library; + + + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, + "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "cff_face_init: cannot access `sfnt' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + + pshinter = (PSHinter_Service)FT_Get_Module_Interface( library, + "pshinter" ); + + psaux = (PSAux_Service)FT_Get_Module_Interface( library, + "psaux" ); + if ( !psaux ) + { + FT_ERROR(( "cff_face_init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + face->psaux = psaux; + + FT_FACE_FIND_GLOBAL_SERVICE( face, cffload, CFF_LOAD ); + + FT_TRACE2(( "CFF driver\n" )); + + /* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + /* check whether we have a valid OpenType file */ + FT_TRACE2(( " " )); + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( !error ) + { + if ( face->format_tag != TTAG_OTTO ) /* `OTTO'; OpenType/CFF font */ + { + FT_TRACE2(( " not an OpenType/CFF font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* if we are performing a simple font format check, exit immediately */ + if ( face_index < 0 ) + return FT_Err_Ok; + + sfnt_format = 1; + + /* now, the font can be either an OpenType/CFF font, or an SVG CEF */ + /* font; in the latter case it doesn't have a `head' table */ + error = face->goto_table( face, TTAG_head, stream, 0 ); + if ( !error ) + { + pure_cff = 0; + + /* load font directory */ + error = sfnt->load_face( stream, face, face_index, + num_params, params ); + if ( error ) + goto Exit; + } + else + { + /* load the `cmap' table explicitly */ + error = sfnt->load_cmap( face, stream ); + if ( error ) + goto Exit; + } + + /* now load the CFF part of the file; */ + /* give priority to CFF2 */ + error = face->goto_table( face, TTAG_CFF2, stream, 0 ); + if ( !error ) + { + cff2 = 1; + face->is_cff2 = cff2; + } + + if ( FT_ERR_EQ( error, Table_Missing ) ) + error = face->goto_table( face, TTAG_CFF, stream, 0 ); + + if ( error ) + goto Exit; + } + else + { + /* rewind to start of file; we are going to load a pure-CFF font */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + error = FT_Err_Ok; + } + + /* now load and parse the CFF table in the file */ + { + CFF_Font cff = NULL; + CFF_FontRecDict dict; + FT_Memory memory = cffface->memory; + FT_Int32 flags; + FT_UInt i; + + + if ( FT_NEW( cff ) ) + goto Exit; + + face->extra.data = cff; + error = cff_font_load( library, + stream, + face_index, + cff, + face, + pure_cff, + cff2 ); + if ( error ) + goto Exit; + + /* if we are performing a simple font format check, exit immediately */ + /* (this is here for pure CFF) */ + if ( face_index < 0 ) + { + cffface->num_faces = (FT_Long)cff->num_faces; + return FT_Err_Ok; + } + + cff->pshinter = pshinter; + cff->psnames = psnames; + cff->cffload = cffload; + + cffface->face_index = face_index & 0xFFFF; + + /* Complement the root flags with some interesting information. */ + /* Note that this is only necessary for pure CFF and CEF fonts; */ + /* SFNT based fonts use the `name' table instead. */ + + cffface->num_glyphs = (FT_Long)cff->num_glyphs; + + dict = &cff->top_font.font_dict; + + /* we need the `psnames' module for CFF and CEF formats */ + /* which aren't CID-keyed */ + if ( dict->cid_registry == 0xFFFFU && !psnames ) + { + FT_ERROR(( "cff_face_init:" + " cannot open CFF & CEF fonts\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt idx; + FT_String* s; + + + FT_TRACE4(( "SIDs\n" )); + + /* dump string index, including default strings for convenience */ + for ( idx = 0; idx <= 390; idx++ ) + { + s = cff_index_get_sid_string( cff, idx ); + if ( s ) + FT_TRACE4(( " %5d %s\n", idx, s )); + } + + /* In Multiple Master CFFs, two SIDs hold the Normalize Design */ + /* Vector (NDV) and Convert Design Vector (CDV) charstrings, */ + /* which may contain null bytes in the middle of the data, too. */ + /* We thus access `cff->strings' directly. */ + for ( idx = 1; idx < cff->num_strings; idx++ ) + { + FT_Byte* s1 = cff->strings[idx - 1]; + FT_Byte* s2 = cff->strings[idx]; + FT_PtrDist s1len = s2 - s1 - 1; /* without the final null byte */ + FT_PtrDist l; + + + FT_TRACE4(( " %5d ", idx + 390 )); + for ( l = 0; l < s1len; l++ ) + FT_TRACE4(( "%c", s1[l] )); + FT_TRACE4(( "\n" )); + } + + /* print last element */ + if ( cff->num_strings ) + { + FT_Byte* s1 = cff->strings[cff->num_strings - 1]; + FT_Byte* s2 = cff->string_pool + cff->string_pool_size; + FT_PtrDist s1len = s2 - s1 - 1; + FT_PtrDist l; + + + FT_TRACE4(( " %5d ", cff->num_strings + 390 )); + for ( l = 0; l < s1len; l++ ) + FT_TRACE4(( "%c", s1[l] )); + FT_TRACE4(( "\n" )); + } + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_UInt instance_index = (FT_UInt)face_index >> 16; + + + if ( FT_HAS_MULTIPLE_MASTERS( cffface ) && + instance_index > 0 ) + { + error = FT_Set_Named_Instance( cffface, instance_index ); + if ( error ) + goto Exit; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + if ( !dict->has_font_matrix ) + dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM; + + /* Normalize the font matrix so that `matrix->yy' is 1; if */ + /* it is zero, we use `matrix->yx' instead. The scaling is */ + /* done with `units_per_em' then (at this point, it already */ + /* contains the scaling factor, but without normalization */ + /* of the matrix). */ + /* */ + /* Note that the offsets must be expressed in integer font */ + /* units. */ + + { + FT_Matrix* matrix = &dict->font_matrix; + FT_Vector* offset = &dict->font_offset; + FT_ULong* upm = &dict->units_per_em; + FT_Fixed temp; + + + temp = matrix->yy ? FT_ABS( matrix->yy ) + : FT_ABS( matrix->yx ); + + if ( temp != 0x10000L ) + { + *upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp ); + + matrix->xx = FT_DivFix( matrix->xx, temp ); + matrix->yx = FT_DivFix( matrix->yx, temp ); + matrix->xy = FT_DivFix( matrix->xy, temp ); + matrix->yy = FT_DivFix( matrix->yy, temp ); + offset->x = FT_DivFix( offset->x, temp ); + offset->y = FT_DivFix( offset->y, temp ); + } + + offset->x >>= 16; + offset->y >>= 16; + } + + for ( i = cff->num_subfonts; i > 0; i-- ) + { + CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict; + CFF_FontRecDict top = &cff->top_font.font_dict; + + FT_Matrix* matrix; + FT_Vector* offset; + FT_ULong* upm; + FT_Fixed temp; + + + if ( sub->has_font_matrix ) + { + FT_Long scaling; + + + /* if we have a top-level matrix, */ + /* concatenate the subfont matrix */ + + if ( top->has_font_matrix ) + { + if ( top->units_per_em > 1 && sub->units_per_em > 1 ) + scaling = (FT_Long)FT_MIN( top->units_per_em, + sub->units_per_em ); + else + scaling = 1; + + FT_Matrix_Multiply_Scaled( &top->font_matrix, + &sub->font_matrix, + scaling ); + FT_Vector_Transform_Scaled( &sub->font_offset, + &top->font_matrix, + scaling ); + + sub->units_per_em = (FT_ULong) + FT_MulDiv( (FT_Long)sub->units_per_em, + (FT_Long)top->units_per_em, + scaling ); + } + } + else + { + sub->font_matrix = top->font_matrix; + sub->font_offset = top->font_offset; + + sub->units_per_em = top->units_per_em; + } + + matrix = &sub->font_matrix; + offset = &sub->font_offset; + upm = &sub->units_per_em; + + temp = matrix->yy ? FT_ABS( matrix->yy ) + : FT_ABS( matrix->yx ); + + + if ( temp != 0x10000L ) + { + *upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp ); + + matrix->xx = FT_DivFix( matrix->xx, temp ); + matrix->yx = FT_DivFix( matrix->yx, temp ); + matrix->xy = FT_DivFix( matrix->xy, temp ); + matrix->yy = FT_DivFix( matrix->yy, temp ); + offset->x = FT_DivFix( offset->x, temp ); + offset->y = FT_DivFix( offset->y, temp ); + } + + offset->x >>= 16; + offset->y >>= 16; + } + + if ( pure_cff ) + { + char* style_name = NULL; + + + /* set up num_faces */ + cffface->num_faces = (FT_Long)cff->num_faces; + + /* compute number of glyphs */ + if ( dict->cid_registry != 0xFFFFU ) + cffface->num_glyphs = (FT_Long)( cff->charset.max_cid + 1 ); + else + cffface->num_glyphs = (FT_Long)cff->charstrings_index.count; + + /* set global bbox, as well as EM size */ + cffface->bbox.xMin = dict->font_bbox.xMin >> 16; + cffface->bbox.yMin = dict->font_bbox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFF ) >> 16; + cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFF ) >> 16; + + cffface->units_per_EM = (FT_UShort)( dict->units_per_em ); + + cffface->ascender = (FT_Short)( cffface->bbox.yMax ); + cffface->descender = (FT_Short)( cffface->bbox.yMin ); + + cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 ); + if ( cffface->height < cffface->ascender - cffface->descender ) + cffface->height = (FT_Short)( cffface->ascender - + cffface->descender ); + + cffface->underline_position = + (FT_Short)( dict->underline_position >> 16 ); + cffface->underline_thickness = + (FT_Short)( dict->underline_thickness >> 16 ); + + /* retrieve font family & style name */ + if ( dict->family_name ) + { + char* family_name; + + + family_name = cff_index_get_sid_string( cff, dict->family_name ); + if ( family_name ) + cffface->family_name = cff_strcpy( memory, family_name ); + } + + if ( !cffface->family_name ) + { + cffface->family_name = cff_index_get_name( + cff, + (FT_UInt)( face_index & 0xFFFF ) ); + if ( cffface->family_name ) + remove_subset_prefix( cffface->family_name ); + } + + if ( cffface->family_name ) + { + char* full = cff_index_get_sid_string( cff, + dict->full_name ); + char* fullp = full; + char* family = cffface->family_name; + + + /* We try to extract the style name from the full name. */ + /* We need to ignore spaces and dashes during the search. */ + if ( full && family ) + { + while ( *fullp ) + { + /* skip common characters at the start of both strings */ + if ( *fullp == *family ) + { + family++; + fullp++; + continue; + } + + /* ignore spaces and dashes in full name during comparison */ + if ( *fullp == ' ' || *fullp == '-' ) + { + fullp++; + continue; + } + + /* ignore spaces and dashes in family name during comparison */ + if ( *family == ' ' || *family == '-' ) + { + family++; + continue; + } + + if ( !*family && *fullp ) + { + /* The full name begins with the same characters as the */ + /* family name, with spaces and dashes removed. In this */ + /* case, the remaining string in `fullp' will be used as */ + /* the style name. */ + style_name = cff_strcpy( memory, fullp ); + + /* remove the style part from the family name (if present) */ + if ( style_name ) + remove_style( cffface->family_name, style_name ); + } + break; + } + } + } + else + { + char *cid_font_name = + cff_index_get_sid_string( cff, + dict->cid_font_name ); + + + /* do we have a `/FontName' for a CID-keyed font? */ + if ( cid_font_name ) + cffface->family_name = cff_strcpy( memory, cid_font_name ); + } + + if ( style_name ) + cffface->style_name = style_name; + else + /* assume "Regular" style if we don't know better */ + cffface->style_name = cff_strcpy( memory, "Regular" ); + + /******************************************************************** + * + * Compute face flags. + */ + flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ + FT_FACE_FLAG_HINTER; /* has native hinter */ + + if ( sfnt_format ) + flags |= FT_FACE_FLAG_SFNT; + + /* fixed width font? */ + if ( dict->is_fixed_pitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */ +#if 0 + /* kerning available? */ + if ( face->kern_pairs ) + flags |= FT_FACE_FLAG_KERNING; +#endif + + cffface->face_flags |= flags; + + /******************************************************************** + * + * Compute style flags. + */ + flags = 0; + + if ( dict->italic_angle ) + flags |= FT_STYLE_FLAG_ITALIC; + + { + char *weight = cff_index_get_sid_string( cff, + dict->weight ); + + + if ( weight ) + if ( !ft_strcmp( weight, "Bold" ) || + !ft_strcmp( weight, "Black" ) ) + flags |= FT_STYLE_FLAG_BOLD; + } + + /* double check */ + if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name ) + if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) || + !ft_strncmp( cffface->style_name, "Black", 5 ) ) + flags |= FT_STYLE_FLAG_BOLD; + + cffface->style_flags = flags; + } + + /* CID-keyed CFF or CFF2 fonts don't have glyph names -- the SFNT */ + /* loader has unset this flag because of the 3.0 `post' table. */ + if ( dict->cid_registry == 0xFFFFU && !cff2 ) + cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; + + if ( dict->cid_registry != 0xFFFFU && pure_cff ) + cffface->face_flags |= FT_FACE_FLAG_CID_KEYED; + + /******************************************************************** + * + * Compute char maps. + */ + + /* Try to synthesize a Unicode charmap if there is none available */ + /* already. If an OpenType font contains a Unicode "cmap", we */ + /* will use it, whatever be in the CFF part of the file. */ + { + FT_CharMapRec cmaprec; + FT_CharMap cmap; + FT_Int nn; + CFF_Encoding encoding = &cff->encoding; + + + for ( nn = 0; nn < cffface->num_charmaps; nn++ ) + { + cmap = cffface->charmaps[nn]; + + /* Windows Unicode? */ + if ( cmap->platform_id == TT_PLATFORM_MICROSOFT && + cmap->encoding_id == TT_MS_ID_UNICODE_CS ) + goto Skip_Unicode; + + /* Apple Unicode platform id? */ + if ( cmap->platform_id == TT_PLATFORM_APPLE_UNICODE ) + goto Skip_Unicode; /* Apple Unicode */ + } + + /* since CID-keyed fonts don't contain glyph names, we can't */ + /* construct a cmap */ + if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU ) + goto Exit; + + /* we didn't find a Unicode charmap -- synthesize one */ + cmaprec.face = cffface; + cmaprec.platform_id = TT_PLATFORM_MICROSOFT; + cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; + cmaprec.encoding = FT_ENCODING_UNICODE; + + nn = cffface->num_charmaps; + + error = FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, + &cmaprec, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + + /* if no Unicode charmap was previously selected, select this one */ + if ( !cffface->charmap && nn != cffface->num_charmaps ) + cffface->charmap = cffface->charmaps[nn]; + + Skip_Unicode: + if ( encoding->count > 0 ) + { + FT_CMap_Class clazz; + + + cmaprec.face = cffface; + cmaprec.platform_id = TT_PLATFORM_ADOBE; /* Adobe platform id */ + + if ( encoding->offset == 0 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_STANDARD; + cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD; + clazz = &cff_cmap_encoding_class_rec; + } + else if ( encoding->offset == 1 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_EXPERT; + cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT; + clazz = &cff_cmap_encoding_class_rec; + } + else + { + cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM; + cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM; + clazz = &cff_cmap_encoding_class_rec; + } + + error = FT_CMap_New( clazz, NULL, &cmaprec, NULL ); + } + } + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_face_done( FT_Face cffface ) /* CFF_Face */ + { + CFF_Face face = (CFF_Face)cffface; + FT_Memory memory; + SFNT_Service sfnt; + + + if ( !face ) + return; + + memory = cffface->memory; + sfnt = (SFNT_Service)face->sfnt; + + if ( sfnt ) + sfnt->done_face( face ); + + { + CFF_Font cff = (CFF_Font)face->extra.data; + + + if ( cff ) + { + cff_font_done( cff ); + FT_FREE( face->extra.data ); + } + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + cff_done_blend( cffface ); + face->blend = NULL; +#endif + } + + + FT_LOCAL_DEF( FT_Error ) + cff_driver_init( FT_Module module ) /* CFF_Driver */ + { + PS_Driver driver = (PS_Driver)module; + + FT_UInt32 seed; + + + /* set default property values, cf. `ftcffdrv.h' */ + driver->hinting_engine = FT_HINTING_ADOBE; + + driver->no_stem_darkening = TRUE; + + driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&module ^ + (FT_Offset)(char*)module->memory ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + + driver->random_seed = (FT_Int32)seed; + if ( driver->random_seed < 0 ) + driver->random_seed = -driver->random_seed; + else if ( driver->random_seed == 0 ) + driver->random_seed = 123456789; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + cff_driver_done( FT_Module module ) /* CFF_Driver */ + { + FT_UNUSED( module ); + } + + +/* END */ diff --git a/vendor/freetype/src/cff/cffobjs.h b/vendor/freetype/src/cff/cffobjs.h new file mode 100644 index 0000000..8f05f61 --- /dev/null +++ b/vendor/freetype/src/cff/cffobjs.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * + * cffobjs.h + * + * OpenType objects manager (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFOBJS_H_ +#define CFFOBJS_H_ + + + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + cff_size_init( FT_Size size ); /* CFF_Size */ + + FT_LOCAL( void ) + cff_size_done( FT_Size size ); /* CFF_Size */ + + FT_LOCAL( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ); + +#endif + + FT_LOCAL( void ) + cff_slot_done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + cff_slot_init( FT_GlyphSlot slot ); + + + /************************************************************************** + * + * Face functions + */ + FT_LOCAL( FT_Error ) + cff_face_init( FT_Stream stream, + FT_Face face, /* CFF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + cff_face_done( FT_Face face ); /* CFF_Face */ + + + /************************************************************************** + * + * Driver functions + */ + FT_LOCAL( FT_Error ) + cff_driver_init( FT_Module module ); /* PS_Driver */ + + FT_LOCAL( void ) + cff_driver_done( FT_Module module ); /* PS_Driver */ + + +FT_END_HEADER + +#endif /* CFFOBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cff/cffparse.c b/vendor/freetype/src/cff/cffparse.c new file mode 100644 index 0000000..3b07670 --- /dev/null +++ b/vendor/freetype/src/cff/cffparse.c @@ -0,0 +1,1513 @@ +/**************************************************************************** + * + * cffparse.c + * + * CFF token stream parser (body) + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "cffparse.h" +#include +#include +#include +#include +#include + +#include "cfferrs.h" +#include "cffload.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffparse + + + FT_LOCAL_DEF( FT_Error ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object, + FT_Library library, + FT_UInt stackSize, + FT_UShort num_designs, + FT_UShort num_axes ) + { + FT_Memory memory = library->memory; /* for FT_NEW_ARRAY */ + FT_Error error; /* for FT_NEW_ARRAY */ + + + FT_ZERO( parser ); + +#if 0 + parser->top = parser->stack; +#endif + parser->object_code = code; + parser->object = object; + parser->library = library; + parser->num_designs = num_designs; + parser->num_axes = num_axes; + + /* allocate the stack buffer */ + if ( FT_QNEW_ARRAY( parser->stack, stackSize ) ) + goto Exit; + + parser->stackSize = stackSize; + parser->top = parser->stack; /* empty stack */ + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_parser_done( CFF_Parser parser ) + { + FT_Memory memory = parser->library->memory; /* for FT_FREE */ + + + FT_FREE( parser->stack ); + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_List_Finalize( &parser->t2_strings, NULL, memory, NULL ); +#endif + } + + + /* The parser limit checks in the next two functions are supposed */ + /* to detect the immediate crossing of the stream boundary. They */ + /* shall not be triggered from the distant t2_strings buffers. */ + + /* read an integer */ + static FT_Long + cff_parse_integer( FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Int v = *p++; + FT_Long val = 0; + + + if ( v == 28 ) + { + if ( p + 2 > limit && limit >= p ) + goto Bad; + + val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] ); + } + else if ( v == 29 ) + { + if ( p + 4 > limit && limit >= p ) + goto Bad; + + val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) | + ( (FT_ULong)p[1] << 16 ) | + ( (FT_ULong)p[2] << 8 ) | + (FT_ULong)p[3] ); + } + else if ( v < 247 ) + { + val = v - 139; + } + else if ( v < 251 ) + { + if ( p + 1 > limit && limit >= p ) + goto Bad; + + val = ( v - 247 ) * 256 + p[0] + 108; + } + else + { + if ( p + 1 > limit && limit >= p ) + goto Bad; + + val = -( v - 251 ) * 256 - p[0] - 108; + } + + Exit: + return val; + + Bad: + val = 0; + FT_TRACE4(( "!!!END OF DATA:!!!" )); + goto Exit; + } + + + static const FT_Long power_tens[] = + { + 1L, + 10L, + 100L, + 1000L, + 10000L, + 100000L, + 1000000L, + 10000000L, + 100000000L, + 1000000000L + }; + + /* maximum values allowed for multiplying */ + /* with the corresponding `power_tens' element */ + static const FT_Long power_ten_limits[] = + { + FT_LONG_MAX / 1L, + FT_LONG_MAX / 10L, + FT_LONG_MAX / 100L, + FT_LONG_MAX / 1000L, + FT_LONG_MAX / 10000L, + FT_LONG_MAX / 100000L, + FT_LONG_MAX / 1000000L, + FT_LONG_MAX / 10000000L, + FT_LONG_MAX / 100000000L, + FT_LONG_MAX / 1000000000L, + }; + + + /* read a real */ + static FT_Fixed + cff_parse_real( FT_Byte* start, + FT_Byte* limit, + FT_Long power_ten, + FT_Long* scaling ) + { + FT_Byte* p = start; + FT_Int nib; + FT_UInt phase; + + FT_Long result, number, exponent; + FT_Int sign = 0, exponent_sign = 0, have_overflow = 0; + FT_Long exponent_add, integer_length, fraction_length; + + + if ( scaling ) + *scaling = 0; + + result = 0; + + number = 0; + exponent = 0; + + exponent_add = 0; + integer_length = 0; + fraction_length = 0; + + /* First of all, read the integer part. */ + phase = 4; + + for (;;) + { + /* If we entered this iteration with phase == 4, we need to */ + /* read a new byte. This also skips past the initial 0x1E. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p + 1 > limit && limit >= p ) + goto Bad; + } + + /* Get the nibble. */ + nib = (FT_Int)( p[0] >> phase ) & 0xF; + phase = 4 - phase; + + if ( nib == 0xE ) + sign = 1; + else if ( nib > 9 ) + break; + else + { + /* Increase exponent if we can't add the digit. */ + if ( number >= 0xCCCCCCCL ) + exponent_add++; + /* Skip leading zeros. */ + else if ( nib || number ) + { + integer_length++; + number = number * 10 + nib; + } + } + } + + /* Read fraction part, if any. */ + if ( nib == 0xA ) + for (;;) + { + /* If we entered this iteration with phase == 4, we need */ + /* to read a new byte. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p + 1 > limit && limit >= p ) + goto Bad; + } + + /* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; + + /* Skip leading zeros if possible. */ + if ( !nib && !number ) + exponent_add--; + /* Only add digit if we don't overflow. */ + else if ( number < 0xCCCCCCCL && fraction_length < 9 ) + { + fraction_length++; + number = number * 10 + nib; + } + } + + /* Read exponent, if any. */ + if ( nib == 12 ) + { + exponent_sign = 1; + nib = 11; + } + + if ( nib == 11 ) + { + for (;;) + { + /* If we entered this iteration with phase == 4, */ + /* we need to read a new byte. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p + 1 > limit && limit >= p ) + goto Bad; + } + + /* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; + + /* Arbitrarily limit exponent. */ + if ( exponent > 1000 ) + have_overflow = 1; + else + exponent = exponent * 10 + nib; + } + + if ( exponent_sign ) + exponent = -exponent; + } + + if ( !number ) + goto Exit; + + if ( have_overflow ) + { + if ( exponent_sign ) + goto Underflow; + else + goto Overflow; + } + + /* We don't check `power_ten' and `exponent_add'. */ + exponent += power_ten + exponent_add; + + if ( scaling ) + { + /* Only use `fraction_length'. */ + fraction_length += integer_length; + exponent += integer_length; + + if ( fraction_length <= 5 ) + { + if ( number > 0x7FFFL ) + { + result = FT_DivFix( number, 10 ); + *scaling = exponent - fraction_length + 1; + } + else + { + if ( exponent > 0 ) + { + FT_Long new_fraction_length, shift; + + + /* Make `scaling' as small as possible. */ + new_fraction_length = FT_MIN( exponent, 5 ); + shift = new_fraction_length - fraction_length; + + if ( shift > 0 ) + { + exponent -= new_fraction_length; + number *= power_tens[shift]; + if ( number > 0x7FFFL ) + { + number /= 10; + exponent += 1; + } + } + else + exponent -= fraction_length; + } + else + exponent -= fraction_length; + + result = (FT_Long)( (FT_ULong)number << 16 ); + *scaling = exponent; + } + } + else + { + if ( ( number / power_tens[fraction_length - 5] ) > 0x7FFFL ) + { + result = FT_DivFix( number, power_tens[fraction_length - 4] ); + *scaling = exponent - 4; + } + else + { + result = FT_DivFix( number, power_tens[fraction_length - 5] ); + *scaling = exponent - 5; + } + } + } + else + { + integer_length += exponent; + fraction_length -= exponent; + + if ( integer_length > 5 ) + goto Overflow; + if ( integer_length < -5 ) + goto Underflow; + + /* Remove non-significant digits. */ + if ( integer_length < 0 ) + { + number /= power_tens[-integer_length]; + fraction_length += integer_length; + } + + /* this can only happen if exponent was non-zero */ + if ( fraction_length == 10 ) + { + number /= 10; + fraction_length -= 1; + } + + /* Convert into 16.16 format. */ + if ( fraction_length > 0 ) + { + if ( ( number / power_tens[fraction_length] ) > 0x7FFFL ) + goto Exit; + + result = FT_DivFix( number, power_tens[fraction_length] ); + } + else + { + number *= power_tens[-fraction_length]; + + if ( number > 0x7FFFL ) + goto Overflow; + + result = (FT_Long)( (FT_ULong)number << 16 ); + } + } + + Exit: + if ( sign ) + result = -result; + + return result; + + Overflow: + result = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + goto Exit; + + Underflow: + result = 0; + FT_TRACE4(( "!!!UNDERFLOW:!!!" )); + goto Exit; + + Bad: + result = 0; + FT_TRACE4(( "!!!END OF DATA:!!!" )); + goto Exit; + } + + + /* read a number, either integer or real */ + FT_LOCAL_DEF( FT_Long ) + cff_parse_num( CFF_Parser parser, + FT_Byte** d ) + { + if ( **d == 30 ) + { + /* binary-coded decimal is truncated to integer */ + return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16; + } + + else if ( **d == 255 ) + { + /* 16.16 fixed-point is used internally for CFF2 blend results. */ + /* Since these are trusted values, a limit check is not needed. */ + + /* After the 255, 4 bytes give the number. */ + /* The blend value is converted to integer, with rounding; */ + /* due to the right-shift we don't need the lowest byte. */ +#if 0 + return (FT_Short)( + ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | + (FT_UInt32)*( d[0] + 4 ) ) + 0x8000U ) >> 16 ); +#else + return (FT_Short)( + ( ( ( (FT_UInt32)*( d[0] + 1 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 8 ) | + (FT_UInt32)*( d[0] + 3 ) ) + 0x80U ) >> 8 ); +#endif + } + + else + return cff_parse_integer( *d, parser->limit ); + } + + + /* read a floating point number, either integer or real */ + static FT_Fixed + do_fixed( CFF_Parser parser, + FT_Byte** d, + FT_Long scaling ) + { + if ( **d == 30 ) + return cff_parse_real( *d, parser->limit, scaling, NULL ); + else if ( **d == 255 ) + { + FT_Fixed val = ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | + (FT_UInt32)*( d[0] + 4 ) ) ); + + if ( scaling ) + { + if ( FT_ABS( val ) > power_ten_limits[scaling] ) + { + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + return val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL; + } + val *= power_tens[scaling]; + } + return val; + } + else + { + FT_Long val = cff_parse_integer( *d, parser->limit ); + + + if ( scaling ) + { + if ( ( FT_ABS( val ) << 16 ) > power_ten_limits[scaling] ) + { + val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL; + goto Overflow; + } + + val *= power_tens[scaling]; + } + + if ( val > 0x7FFF ) + { + val = 0x7FFFFFFFL; + goto Overflow; + } + else if ( val < -0x7FFF ) + { + val = -0x7FFFFFFFL; + goto Overflow; + } + + return (FT_Long)( (FT_ULong)val << 16 ); + + Overflow: + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + return val; + } + } + + + /* read a floating point number, either integer or real */ + FT_LOCAL_DEF( FT_Fixed ) + cff_parse_fixed( CFF_Parser parser, + FT_Byte** d ) + { + return do_fixed( parser, d, 0 ); + } + + + /* read a floating point number, either integer or real, */ + /* but return `10^scaling' times the number read in */ + static FT_Fixed + cff_parse_fixed_scaled( CFF_Parser parser, + FT_Byte** d, + FT_Long scaling ) + { + return do_fixed( parser, d, scaling ); + } + + + /* read a floating point number, either integer or real, */ + /* and return it as precise as possible -- `scaling' returns */ + /* the scaling factor (as a power of 10) */ + static FT_Fixed + cff_parse_fixed_dynamic( CFF_Parser parser, + FT_Byte** d, + FT_Long* scaling ) + { + FT_ASSERT( scaling ); + + if ( **d == 30 ) + return cff_parse_real( *d, parser->limit, 0, scaling ); + else + { + FT_Long number; + FT_Int integer_length; + + + number = cff_parse_integer( *d, parser->limit ); + + if ( number > 0x7FFFL ) + { + for ( integer_length = 5; integer_length < 10; integer_length++ ) + if ( number < power_tens[integer_length] ) + break; + + if ( ( number / power_tens[integer_length - 5] ) > 0x7FFFL ) + { + *scaling = integer_length - 4; + return FT_DivFix( number, power_tens[integer_length - 4] ); + } + else + { + *scaling = integer_length - 5; + return FT_DivFix( number, power_tens[integer_length - 5] ); + } + } + else + { + *scaling = 0; + return (FT_Long)( (FT_ULong)number << 16 ); + } + } + } + + + static FT_Error + cff_parse_font_matrix( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Matrix* matrix = &dict->font_matrix; + FT_Vector* offset = &dict->font_offset; + FT_ULong* upm = &dict->units_per_em; + FT_Byte** data = parser->stack; + + + if ( parser->top >= parser->stack + 6 ) + { + FT_Fixed values[6]; + FT_Long scalings[6]; + + FT_Long min_scaling, max_scaling; + int i; + + + dict->has_font_matrix = TRUE; + + /* We expect a well-formed font matrix, that is, the matrix elements */ + /* `xx' and `yy' are of approximately the same magnitude. To avoid */ + /* loss of precision, we use the magnitude of the largest matrix */ + /* element to scale all other elements. The scaling factor is then */ + /* contained in the `units_per_em' value. */ + + max_scaling = FT_LONG_MIN; + min_scaling = FT_LONG_MAX; + + for ( i = 0; i < 6; i++ ) + { + values[i] = cff_parse_fixed_dynamic( parser, data++, &scalings[i] ); + if ( values[i] ) + { + if ( scalings[i] > max_scaling ) + max_scaling = scalings[i]; + if ( scalings[i] < min_scaling ) + min_scaling = scalings[i]; + } + } + + if ( max_scaling < -9 || + max_scaling > 0 || + ( max_scaling - min_scaling ) < 0 || + ( max_scaling - min_scaling ) > 9 ) + { + FT_TRACE1(( "cff_parse_font_matrix:" + " strange scaling values (minimum %ld, maximum %ld),\n", + min_scaling, max_scaling )); + FT_TRACE1(( " " + " using default matrix\n" )); + goto Unlikely; + } + + for ( i = 0; i < 6; i++ ) + { + FT_Fixed value = values[i]; + FT_Long divisor, half_divisor; + + + if ( !value ) + continue; + + divisor = power_tens[max_scaling - scalings[i]]; + half_divisor = divisor >> 1; + + if ( value < 0 ) + { + if ( FT_LONG_MIN + half_divisor < value ) + values[i] = ( value - half_divisor ) / divisor; + else + values[i] = FT_LONG_MIN / divisor; + } + else + { + if ( FT_LONG_MAX - half_divisor > value ) + values[i] = ( value + half_divisor ) / divisor; + else + values[i] = FT_LONG_MAX / divisor; + } + } + + matrix->xx = values[0]; + matrix->yx = values[1]; + matrix->xy = values[2]; + matrix->yy = values[3]; + offset->x = values[4]; + offset->y = values[5]; + + *upm = (FT_ULong)power_tens[-max_scaling]; + + FT_TRACE4(( " [%f %f %f %f %f %f]\n", + (double)matrix->xx / (double)*upm / 65536, + (double)matrix->xy / (double)*upm / 65536, + (double)matrix->yx / (double)*upm / 65536, + (double)matrix->yy / (double)*upm / 65536, + (double)offset->x / (double)*upm / 65536, + (double)offset->y / (double)*upm / 65536 )); + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_TRACE1(( "cff_parse_font_matrix:" + " degenerate values, using default matrix\n" )); + goto Unlikely; + } + + return FT_Err_Ok; + } + else + return FT_THROW( Stack_Underflow ); + + Unlikely: + /* Return default matrix in case of unlikely values. */ + + matrix->xx = 0x10000L; + matrix->yx = 0; + matrix->xy = 0; + matrix->yy = 0x10000L; + offset->x = 0; + offset->y = 0; + *upm = 1; + + return FT_Err_Ok; + } + + + static FT_Error + cff_parse_font_bbox( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_BBox* bbox = &dict->font_bbox; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = FT_ERR( Stack_Underflow ); + + if ( parser->top >= parser->stack + 4 ) + { + bbox->xMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->yMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->xMax = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->yMax = FT_RoundFix( cff_parse_fixed( parser, data ) ); + error = FT_Err_Ok; + + FT_TRACE4(( " [%ld %ld %ld %ld]\n", + bbox->xMin / 65536, + bbox->yMin / 65536, + bbox->xMax / 65536, + bbox->yMax / 65536 )); + } + + return error; + } + + + static FT_Error + cff_parse_private_dict( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = FT_ERR( Stack_Underflow ); + + if ( parser->top >= parser->stack + 2 ) + { + FT_Long tmp; + + + tmp = cff_parse_num( parser, data++ ); + if ( tmp < 0 ) + { + FT_ERROR(( "cff_parse_private_dict: Invalid dictionary size\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + dict->private_size = (FT_ULong)tmp; + + tmp = cff_parse_num( parser, data ); + if ( tmp < 0 ) + { + FT_ERROR(( "cff_parse_private_dict: Invalid dictionary offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + dict->private_offset = (FT_ULong)tmp; + + FT_TRACE4(( " %lu %lu\n", + dict->private_size, dict->private_offset )); + + error = FT_Err_Ok; + } + + Fail: + return error; + } + + + /* The `MultipleMaster' operator comes before any */ + /* top DICT operators that contain T2 charstrings. */ + + static FT_Error + cff_parse_multiple_master( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Error error; + + +#ifdef FT_DEBUG_LEVEL_TRACE + /* beautify tracing message */ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] < 4 ) + FT_TRACE1(( "Multiple Master CFFs not supported yet," + " handling first master design only\n" )); + else + FT_TRACE1(( " (not supported yet," + " handling first master design only)\n" )); +#endif + + error = FT_ERR( Stack_Underflow ); + + /* currently, we handle only the first argument */ + if ( parser->top >= parser->stack + 5 ) + { + FT_Long num_designs = cff_parse_num( parser, parser->stack ); + + + if ( num_designs > 16 || num_designs < 2 ) + { + FT_ERROR(( "cff_parse_multiple_master:" + " Invalid number of designs\n" )); + error = FT_THROW( Invalid_File_Format ); + } + else + { + dict->num_designs = (FT_UShort)num_designs; + dict->num_axes = (FT_UShort)( parser->top - parser->stack - 4 ); + + parser->num_designs = dict->num_designs; + parser->num_axes = dict->num_axes; + + error = FT_Err_Ok; + } + } + + return error; + } + + + static FT_Error + cff_parse_cid_ros( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = FT_ERR( Stack_Underflow ); + + if ( parser->top >= parser->stack + 3 ) + { + dict->cid_registry = (FT_UInt)cff_parse_num( parser, data++ ); + dict->cid_ordering = (FT_UInt)cff_parse_num( parser, data++ ); + if ( **data == 30 ) + FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" )); + dict->cid_supplement = cff_parse_num( parser, data ); + if ( dict->cid_supplement < 0 ) + FT_TRACE1(( "cff_parse_cid_ros: negative supplement %ld is found\n", + dict->cid_supplement )); + error = FT_Err_Ok; + + FT_TRACE4(( " %d %d %ld\n", + dict->cid_registry, + dict->cid_ordering, + dict->cid_supplement )); + } + + return error; + } + + + static FT_Error + cff_parse_vsindex( CFF_Parser parser ) + { + /* vsindex operator can only be used in a Private DICT */ + CFF_Private priv = (CFF_Private)parser->object; + FT_Byte** data = parser->stack; + CFF_Blend blend; + FT_Error error; + + + if ( !priv || !priv->subfont ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + blend = &priv->subfont->blend; + + if ( blend->usedBV ) + { + FT_ERROR(( " cff_parse_vsindex: vsindex not allowed after blend\n" )); + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ ); + + FT_TRACE4(( " %d\n", priv->vsindex )); + + error = FT_Err_Ok; + + Exit: + return error; + } + + + static FT_Error + cff_parse_blend( CFF_Parser parser ) + { + /* blend operator can only be used in a Private DICT */ + CFF_Private priv = (CFF_Private)parser->object; + CFF_SubFont subFont; + CFF_Blend blend; + FT_UInt numBlends; + FT_Error error; + + + if ( !priv || !priv->subfont ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + subFont = priv->subfont; + blend = &subFont->blend; + + if ( cff_blend_check_vector( blend, + priv->vsindex, + subFont->lenNDV, + subFont->NDV ) ) + { + error = cff_blend_build_vector( blend, + priv->vsindex, + subFont->lenNDV, + subFont->NDV ); + if ( error ) + goto Exit; + } + + numBlends = (FT_UInt)cff_parse_num( parser, parser->top - 1 ); + if ( numBlends > parser->stackSize ) + { + FT_ERROR(( "cff_parse_blend: Invalid number of blends\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_TRACE4(( " %d value%s blended\n", + numBlends, + numBlends == 1 ? "" : "s" )); + + error = cff_blend_doBlend( subFont, parser, numBlends ); + + blend->usedBV = TRUE; + + Exit: + return error; + } + + + /* maxstack operator increases parser and operand stacks for CFF2 */ + static FT_Error + cff_parse_maxstack( CFF_Parser parser ) + { + /* maxstack operator can only be used in a Top DICT */ + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error = FT_Err_Ok; + + + if ( !dict ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + dict->maxstack = (FT_UInt)cff_parse_num( parser, data++ ); + if ( dict->maxstack > CFF2_MAX_STACK ) + dict->maxstack = CFF2_MAX_STACK; + if ( dict->maxstack < CFF2_DEFAULT_STACK ) + dict->maxstack = CFF2_DEFAULT_STACK; + + FT_TRACE4(( " %d\n", dict->maxstack )); + + Exit: + return error; + } + + +#define CFF_FIELD_NUM( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_num ) +#define CFF_FIELD_FIXED( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_fixed ) +#define CFF_FIELD_FIXED_1000( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_fixed_thousand ) +#define CFF_FIELD_STRING( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_string ) +#define CFF_FIELD_BOOL( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_bool ) + + +#undef CFF_FIELD +#undef CFF_FIELD_DELTA + + +#ifndef FT_DEBUG_LEVEL_TRACE + + +#define CFF_FIELD_CALLBACK( code, name, id ) \ + { \ + cff_kind_callback, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_ ## name, \ + 0, 0 \ + }, + +#define CFF_FIELD_BLEND( code, id ) \ + { \ + cff_kind_blend, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_blend, \ + 0, 0 \ + }, + +#define CFF_FIELD( code, name, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE( name ), \ + 0, 0, 0 \ + }, + +#define CFF_FIELD_DELTA( code, name, max, id ) \ + { \ + cff_kind_delta, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + 0, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ) \ + }, + + static const CFF_Field_Handler cff_field_handlers[] = + { + +#include "cfftoken.h" + + { 0, 0, 0, 0, 0, 0, 0 } + }; + + +#else /* FT_DEBUG_LEVEL_TRACE */ + + + +#define CFF_FIELD_CALLBACK( code, name, id ) \ + { \ + cff_kind_callback, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_ ## name, \ + 0, 0, \ + id \ + }, + +#define CFF_FIELD_BLEND( code, id ) \ + { \ + cff_kind_blend, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_blend, \ + 0, 0, \ + id \ + }, + +#define CFF_FIELD( code, name, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE( name ), \ + 0, 0, 0, \ + id \ + }, + +#define CFF_FIELD_DELTA( code, name, max, id ) \ + { \ + cff_kind_delta, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + 0, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ), \ + id \ + }, + + static const CFF_Field_Handler cff_field_handlers[] = + { + +#include "cfftoken.h" + + { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + FT_LOCAL_DEF( FT_Error ) + cff_parser_run( CFF_Parser parser, + FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Error error = FT_Err_Ok; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PSAux_Service psaux; + + FT_Library library = parser->library; + FT_Memory memory = library->memory; +#endif + + parser->top = parser->stack; + parser->start = start; + parser->limit = limit; + parser->cursor = start; + + while ( p < limit ) + { + FT_UInt v = *p; + + + /* Opcode 31 is legacy MM T2 operator, not a number. */ + /* Opcode 255 is reserved and should not appear in fonts; */ + /* it is used internally for CFF2 blends. */ + if ( v >= 27 && v != 31 && v != 255 ) + { + /* it's a number; we will push its position on the stack */ + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + *parser->top++ = p; + + /* now, skip it */ + if ( v == 30 ) + { + /* skip real number */ + p++; + for (;;) + { + /* An unterminated floating point number at the */ + /* end of a dictionary is invalid but harmless. */ + if ( p >= limit ) + goto Exit; + v = p[0] >> 4; + if ( v == 15 ) + break; + v = p[0] & 0xF; + if ( v == 15 ) + break; + p++; + } + } + else if ( v == 28 ) + p += 2; + else if ( v == 29 ) + p += 4; + else if ( v > 246 ) + p += 1; + } +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + else if ( v == 31 ) + { + /* a Type 2 charstring */ + + CFF_Decoder decoder; + CFF_FontRec cff_rec; + FT_Byte* charstring_base; + FT_ULong charstring_len; + + FT_Fixed* stack; + FT_Byte* q = NULL; + + + charstring_base = ++p; + + /* search `endchar' operator */ + for (;;) + { + if ( p >= limit ) + goto Exit; + if ( *p == 14 ) + break; + p++; + } + + charstring_len = (FT_ULong)( p - charstring_base ) + 1; + + /* construct CFF_Decoder object */ + FT_ZERO( &decoder ); + FT_ZERO( &cff_rec ); + + cff_rec.top_font.font_dict.num_designs = parser->num_designs; + cff_rec.top_font.font_dict.num_axes = parser->num_axes; + decoder.cff = &cff_rec; + + psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" ); + if ( !psaux ) + { + FT_ERROR(( "cff_parser_run: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + error = psaux->cff_decoder_funcs->parse_charstrings_old( + &decoder, charstring_base, charstring_len, 1 ); + if ( error ) + goto Exit; + + /* Now copy the stack data in the temporary decoder object, */ + /* converting it back to charstring number representations */ + /* (this is ugly, I know). */ + /* The maximum required size is 5 bytes per stack element. */ + if ( FT_QALLOC( q, (FT_Long)( 2 * sizeof ( FT_ListNode ) ) + + 5 * ( decoder.top - decoder.stack ) ) ) + goto Exit; + + FT_List_Add( &parser->t2_strings, (FT_ListNode)q ); + + q += 2 * sizeof ( FT_ListNode ); + + for ( stack = decoder.stack; stack < decoder.top; stack++ ) + { + FT_Long num = *stack; + + + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + *parser->top++ = q; + + if ( num & 0xFFFFU ) + { + *q++ = 255; + *q++ = (FT_Byte)( ( num >> 24 ) & 0xFF ); + *q++ = (FT_Byte)( ( num >> 16 ) & 0xFF ); + *q++ = (FT_Byte)( ( num >> 8 ) & 0xFF ); + *q++ = (FT_Byte)( ( num ) & 0xFF ); + } + else + { + num >>= 16; + + if ( -107 <= num && num <= 107 ) + *q++ = (FT_Byte)( num + 139 ); + else if ( 108 <= num && num <= 1131 ) + { + *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 ); + *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); + } + else if ( -1131 <= num && num <= -108 ) + { + *q++ = (FT_Byte)( ( ( -num - 108 ) >> 8 ) + 251 ); + *q++ = (FT_Byte)( ( -num - 108) & 0xFF ); + } + else + { + *q++ = 28; + *q++ = (FT_Byte)( num >> 8 ); + *q++ = (FT_Byte)( num & 0xFF ); + } + } + } + } +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + else + { + /* This is not a number, hence it's an operator. Compute its code */ + /* and look for it in our current list. */ + + FT_UInt code; + FT_UInt num_args; + const CFF_Field_Handler* field; + + + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + num_args = (FT_UInt)( parser->top - parser->stack ); + *parser->top = p; + code = v; + + if ( v == 12 ) + { + /* two byte operator */ + p++; + if ( p >= limit ) + goto Syntax_Error; + + code = 0x100 | p[0]; + } + code = code | parser->object_code; + + for ( field = cff_field_handlers; field->kind; field++ ) + { + if ( field->code == (FT_Int)code ) + { + /* we found our field's handler; read it */ + FT_Long val; + FT_Byte* q = (FT_Byte*)parser->object + field->offset; + + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " %s", field->id )); +#endif + + /* check that we have enough arguments -- except for */ + /* delta encoded arrays, which can be empty */ + if ( field->kind != cff_kind_delta && num_args < 1 ) + goto Stack_Underflow; + + switch ( field->kind ) + { + case cff_kind_bool: + case cff_kind_string: + case cff_kind_num: + val = cff_parse_num( parser, parser->stack ); + goto Store_Number; + + case cff_kind_fixed: + val = cff_parse_fixed( parser, parser->stack ); + goto Store_Number; + + case cff_kind_fixed_thousand: + val = cff_parse_fixed_scaled( parser, parser->stack, 3 ); + + Store_Number: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + switch ( field->kind ) + { + case cff_kind_bool: + FT_TRACE4(( " %s\n", val ? "true" : "false" )); + break; + + case cff_kind_string: + FT_TRACE4(( " %ld (SID)\n", val )); + break; + + case cff_kind_num: + FT_TRACE4(( " %ld\n", val )); + break; + + case cff_kind_fixed: + FT_TRACE4(( " %f\n", (double)val / 65536 )); + break; + + case cff_kind_fixed_thousand: + FT_TRACE4(( " %f\n", (double)val / 65536 / 1000 )); + break; + + default: + ; /* never reached */ + } +#endif + + break; + + case cff_kind_delta: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + + FT_Byte** data = parser->stack; + + + if ( num_args > field->array_max ) + num_args = field->array_max; + + FT_TRACE4(( " [" )); + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while ( num_args > 0 ) + { + val = ADD_LONG( val, cff_parse_num( parser, data++ ) ); + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + + FT_TRACE4(( " %ld", val )); + + q += field->size; + num_args--; + } + + FT_TRACE4(( "]\n" )); + } + break; + + default: /* callback or blend */ + error = field->reader( parser ); + if ( error ) + goto Exit; + } + goto Found; + } + } + + /* this is an unknown operator, or it is unsupported; */ + /* we will ignore it for now. */ + + Found: + /* clear stack */ + /* TODO: could clear blend stack here, */ + /* but we don't have access to subFont */ + if ( field->kind != cff_kind_blend ) + parser->top = parser->stack; + } + p++; + } /* while ( p < limit ) */ + + Exit: + return error; + + Stack_Overflow: + error = FT_THROW( Invalid_Argument ); + goto Exit; + + Stack_Underflow: + error = FT_THROW( Invalid_Argument ); + goto Exit; + + Syntax_Error: + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + +/* END */ diff --git a/vendor/freetype/src/cff/cffparse.h b/vendor/freetype/src/cff/cffparse.h new file mode 100644 index 0000000..418caac --- /dev/null +++ b/vendor/freetype/src/cff/cffparse.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * + * cffparse.h + * + * CFF token stream parser (specification) + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFPARSE_H_ +#define CFFPARSE_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /* CFF uses constant parser stack size; */ + /* CFF2 can increase from default 193 */ +#define CFF_MAX_STACK_DEPTH 96 + + /* + * There are plans to remove the `maxstack' operator in a forthcoming + * revision of the CFF2 specification, increasing the (then static) stack + * size to 513. By making the default stack size equal to the maximum + * stack size, the operator is essentially disabled, which has the + * desired effect in FreeType. + */ +#define CFF2_MAX_STACK 513 +#define CFF2_DEFAULT_STACK 513 + +#define CFF_CODE_TOPDICT 0x1000 +#define CFF_CODE_PRIVATE 0x2000 +#define CFF2_CODE_TOPDICT 0x3000 +#define CFF2_CODE_FONTDICT 0x4000 +#define CFF2_CODE_PRIVATE 0x5000 + + + typedef struct CFF_ParserRec_ + { + FT_Library library; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* cursor; + + FT_Byte** stack; + FT_Byte** top; + FT_UInt stackSize; /* allocated size */ + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_ListRec t2_strings; +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + + FT_UInt object_code; + void* object; + + FT_UShort num_designs; /* a copy of `CFF_FontRecDict->num_designs' */ + FT_UShort num_axes; /* a copy of `CFF_FontRecDict->num_axes' */ + + } CFF_ParserRec, *CFF_Parser; + + + FT_LOCAL( FT_Long ) + cff_parse_num( CFF_Parser parser, + FT_Byte** d ); + + FT_LOCAL( FT_Fixed ) + cff_parse_fixed( CFF_Parser parser, + FT_Byte** d ); + + FT_LOCAL( FT_Error ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object, + FT_Library library, + FT_UInt stackSize, + FT_UShort num_designs, + FT_UShort num_axes ); + + FT_LOCAL( void ) + cff_parser_done( CFF_Parser parser ); + + FT_LOCAL( FT_Error ) + cff_parser_run( CFF_Parser parser, + FT_Byte* start, + FT_Byte* limit ); + + + enum + { + cff_kind_none = 0, + cff_kind_num, + cff_kind_fixed, + cff_kind_fixed_thousand, + cff_kind_string, + cff_kind_bool, + cff_kind_delta, + cff_kind_callback, + cff_kind_blend, + + cff_kind_max /* do not remove */ + }; + + + /* now generate handlers for the most simple fields */ + typedef FT_Error (*CFF_Field_Reader)( CFF_Parser parser ); + + typedef struct CFF_Field_Handler_ + { + int kind; + int code; + FT_UInt offset; + FT_Byte size; + CFF_Field_Reader reader; + FT_UInt array_max; + FT_UInt count_offset; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* id; +#endif + + } CFF_Field_Handler; + + +FT_END_HEADER + + +#endif /* CFFPARSE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cff/cfftoken.h b/vendor/freetype/src/cff/cfftoken.h new file mode 100644 index 0000000..b61cb0e --- /dev/null +++ b/vendor/freetype/src/cff/cfftoken.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * + * cfftoken.h + * + * CFF token definitions (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRecDictRec + +#undef CFFCODE +#define CFFCODE CFF_CODE_TOPDICT + + CFF_FIELD_STRING ( 0, version, "Version" ) + CFF_FIELD_STRING ( 1, notice, "Notice" ) + CFF_FIELD_STRING ( 0x100, copyright, "Copyright" ) + CFF_FIELD_STRING ( 2, full_name, "FullName" ) + CFF_FIELD_STRING ( 3, family_name, "FamilyName" ) + CFF_FIELD_STRING ( 4, weight, "Weight" ) + CFF_FIELD_BOOL ( 0x101, is_fixed_pitch, "isFixedPitch" ) + CFF_FIELD_FIXED ( 0x102, italic_angle, "ItalicAngle" ) + CFF_FIELD_FIXED ( 0x103, underline_position, "UnderlinePosition" ) + CFF_FIELD_FIXED ( 0x104, underline_thickness, "UnderlineThickness" ) + CFF_FIELD_NUM ( 0x105, paint_type, "PaintType" ) + CFF_FIELD_NUM ( 0x106, charstring_type, "CharstringType" ) + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) + CFF_FIELD_NUM ( 13, unique_id, "UniqueID" ) + CFF_FIELD_CALLBACK( 5, font_bbox, "FontBBox" ) + CFF_FIELD_NUM ( 0x108, stroke_width, "StrokeWidth" ) +#if 0 + CFF_FIELD_DELTA ( 14, xuid, 16, "XUID" ) +#endif + CFF_FIELD_NUM ( 15, charset_offset, "charset" ) + CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" ) + CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" ) + CFF_FIELD_CALLBACK( 18, private_dict, "Private" ) + CFF_FIELD_NUM ( 0x114, synthetic_base, "SyntheticBase" ) + CFF_FIELD_STRING ( 0x115, embedded_postscript, "PostScript" ) + +#if 0 + CFF_FIELD_STRING ( 0x116, base_font_name, "BaseFontName" ) + CFF_FIELD_DELTA ( 0x117, base_font_blend, 16, "BaseFontBlend" ) +#endif + + /* the next two operators were removed from the Type2 specification */ + /* in version 16-March-2000 */ + CFF_FIELD_CALLBACK( 0x118, multiple_master, "MultipleMaster" ) +#if 0 + CFF_FIELD_CALLBACK( 0x11A, blend_axis_types, "BlendAxisTypes" ) +#endif + + CFF_FIELD_CALLBACK( 0x11E, cid_ros, "ROS" ) + CFF_FIELD_NUM ( 0x11F, cid_font_version, "CIDFontVersion" ) + CFF_FIELD_NUM ( 0x120, cid_font_revision, "CIDFontRevision" ) + CFF_FIELD_NUM ( 0x121, cid_font_type, "CIDFontType" ) + CFF_FIELD_NUM ( 0x122, cid_count, "CIDCount" ) + CFF_FIELD_NUM ( 0x123, cid_uid_base, "UIDBase" ) + CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" ) + CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" ) + CFF_FIELD_STRING ( 0x126, cid_font_name, "FontName" ) + +#if 0 + CFF_FIELD_NUM ( 0x127, chameleon, "Chameleon" ) +#endif + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_PrivateRec +#undef CFFCODE +#define CFFCODE CFF_CODE_PRIVATE + + CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" ) + CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" ) + CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" ) + CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRecDictRec +#undef CFFCODE +#define CFFCODE CFF2_CODE_TOPDICT + + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) + CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" ) + CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" ) + CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" ) + CFF_FIELD_NUM ( 24, vstore_offset, "vstore" ) + CFF_FIELD_CALLBACK( 25, maxstack, "maxstack" ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRecDictRec +#undef CFFCODE +#define CFFCODE CFF2_CODE_FONTDICT + + CFF_FIELD_CALLBACK( 18, private_dict, "Private" ) + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_PrivateRec +#undef CFFCODE +#define CFFCODE CFF2_CODE_PRIVATE + + CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" ) + CFF_FIELD_BLEND ( 23, "blend" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + + +/* END */ diff --git a/vendor/freetype/src/cff/module.mk b/vendor/freetype/src/cff/module.mk new file mode 100644 index 0000000..b881d04 --- /dev/null +++ b/vendor/freetype/src/cff/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 CFF module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += CFF_DRIVER + +define CFF_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, cff_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)cff $(ECHO_DRIVER_DESC)OpenType fonts with extension *.otf$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/cff/rules.mk b/vendor/freetype/src/cff/rules.mk new file mode 100644 index 0000000..629424a --- /dev/null +++ b/vendor/freetype/src/cff/rules.mk @@ -0,0 +1,75 @@ +# +# FreeType 2 OpenType/CFF driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# OpenType driver directory +# +CFF_DIR := $(SRC_DIR)/cff + + +CFF_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(CFF_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# CFF driver sources (i.e., C files) +# +CFF_DRV_SRC := $(CFF_DIR)/cffcmap.c \ + $(CFF_DIR)/cffdrivr.c \ + $(CFF_DIR)/cffgload.c \ + $(CFF_DIR)/cffload.c \ + $(CFF_DIR)/cffobjs.c \ + $(CFF_DIR)/cffparse.c + + +# CFF driver headers +# +CFF_DRV_H := $(CFF_DRV_SRC:%.c=%.h) \ + $(CFF_DIR)/cfferrs.h \ + $(CFF_DIR)/cfftoken.h + + +# CFF driver object(s) +# +# CFF_DRV_OBJ_M is used during `multi' builds +# CFF_DRV_OBJ_S is used during `single' builds +# +CFF_DRV_OBJ_M := $(CFF_DRV_SRC:$(CFF_DIR)/%.c=$(OBJ_DIR)/%.$O) +CFF_DRV_OBJ_S := $(OBJ_DIR)/cff.$O + +# CFF driver source file for single build +# +CFF_DRV_SRC_S := $(CFF_DIR)/cff.c + + +# CFF driver - single object +# +$(CFF_DRV_OBJ_S): $(CFF_DRV_SRC_S) $(CFF_DRV_SRC) $(FREETYPE_H) $(CFF_DRV_H) + $(CFF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(CFF_DRV_SRC_S)) + + +# CFF driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(CFF_DIR)/%.c $(FREETYPE_H) $(CFF_DRV_H) + $(CFF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(CFF_DRV_OBJ_S) +DRV_OBJS_M += $(CFF_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/cid/ciderrs.h b/vendor/freetype/src/cid/ciderrs.h new file mode 100644 index 0000000..40a1097 --- /dev/null +++ b/vendor/freetype/src/cid/ciderrs.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * ciderrs.h + * + * CID error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the CID error enumeration constants. + * + */ + +#ifndef CIDERRS_H_ +#define CIDERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CID_Err_ +#define FT_ERR_BASE FT_Mod_Err_CID + +#include + +#endif /* CIDERRS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cid/cidgload.c b/vendor/freetype/src/cid/cidgload.c new file mode 100644 index 0000000..eaca765 --- /dev/null +++ b/vendor/freetype/src/cid/cidgload.c @@ -0,0 +1,618 @@ +/**************************************************************************** + * + * cidgload.c + * + * CID-keyed Type1 Glyph Loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "cidload.h" +#include "cidgload.h" +#include +#include +#include +#include + +#include +#include +#include + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidgload + + + /* + * A helper function to compute FD number (`fd_select`), the offset to the + * head of the glyph data (`off1`), and the offset to the and of the glyph + * data (`off2`). + * + * The number how many times `cid_get_offset` is invoked can be controlled + * by the number of non-NULL arguments. If `fd_select` is non-NULL but + * `off1` and `off2` are NULL, `cid_get_offset` is invoked only for + * `fd_select`; `off1` and `off2` are not validated. + * + */ + FT_LOCAL_DEF( FT_Error ) + cid_compute_fd_and_offsets( CID_Face face, + FT_UInt glyph_index, + FT_ULong* fd_select_p, + FT_ULong* off1_p, + FT_ULong* off2_p ) + { + FT_Error error = FT_Err_Ok; + + CID_FaceInfo cid = &face->cid; + FT_Stream stream = face->cid_stream; + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; + + FT_Byte* p; + FT_Bool need_frame_exit = 0; + FT_ULong fd_select, off1, off2; + + + /* For ordinary fonts, read the CID font dictionary index */ + /* and charstring offset from the CIDMap. */ + + if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset + + glyph_index * entry_len ) || + FT_FRAME_ENTER( 2 * entry_len ) ) + goto Exit; + + need_frame_exit = 1; + + p = (FT_Byte*)stream->cursor; + fd_select = cid_get_offset( &p, cid->fd_bytes ); + off1 = cid_get_offset( &p, cid->gd_bytes ); + + p += cid->fd_bytes; + off2 = cid_get_offset( &p, cid->gd_bytes ); + + if ( fd_select_p ) + *fd_select_p = fd_select; + if ( off1_p ) + *off1_p = off1; + if ( off2_p ) + *off2_p = off2; + + if ( fd_select >= cid->num_dicts ) + { + /* + * fd_select == 0xFF is often used to indicate that the CID + * has no charstring to be rendered, similar to GID = 0xFFFF + * in TrueType fonts. + */ + if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) || + ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) ) + { + FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE1(( " FD number %ld is the maximum\n", + fd_select )); + FT_TRACE1(( " integer fitting into %d byte%s\n", + cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" )); + } + else + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE0(( " FD number %ld is larger\n", + fd_select )); + FT_TRACE0(( " than number of dictionaries (%d)\n", + cid->num_dicts )); + } + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off2 > stream->size ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE0(( " end of the glyph data\n" )); + FT_TRACE0(( " is beyond the data stream\n" )); + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off1 > off2 ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE0(( " the end position of glyph data\n" )); + FT_TRACE0(( " is set before the start position\n" )); + + error = FT_THROW( Invalid_Offset ); + } + + Exit: + if ( need_frame_exit ) + FT_FRAME_EXIT(); + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_load_glyph( T1_Decoder decoder, + FT_UInt glyph_index ) + { + CID_Face face = (CID_Face)decoder->builder.face; + CID_FaceInfo cid = &face->cid; + FT_Byte* p; + FT_ULong fd_select; + FT_Stream stream = face->cid_stream; + FT_Error error = FT_Err_Ok; + FT_Byte* charstring = NULL; + FT_Memory memory = face->root.memory; + FT_ULong glyph_length = 0; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + FT_Bool force_scaling = FALSE; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; +#endif + + + FT_TRACE1(( "cid_load_glyph: glyph index %u\n", glyph_index )); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* For incremental fonts get the character data using */ + /* the callback function. */ + if ( inc ) + { + FT_Data glyph_data; + + + error = inc->funcs->get_glyph_data( inc->object, + glyph_index, &glyph_data ); + if ( error || glyph_data.length < cid->fd_bytes ) + goto Exit; + + p = (FT_Byte*)glyph_data.pointer; + fd_select = cid_get_offset( &p, cid->fd_bytes ); + + glyph_length = glyph_data.length - cid->fd_bytes; + + if ( !FT_QALLOC( charstring, glyph_length ) ) + FT_MEM_COPY( charstring, glyph_data.pointer + cid->fd_bytes, + glyph_length ); + + inc->funcs->free_glyph_data( inc->object, &glyph_data ); + + if ( error ) + goto Exit; + } + + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ULong off1, off2; + + + error = cid_compute_fd_and_offsets( face, glyph_index, + &fd_select, &off1, &off2 ); + if ( error ) + goto Exit; + + glyph_length = off2 - off1; + + if ( glyph_length == 0 || + FT_QALLOC( charstring, glyph_length ) || + FT_STREAM_READ_AT( cid->data_offset + off1, + charstring, glyph_length ) ) + goto Exit; + } + + /* Now set up the subrs array and parse the charstrings. */ + { + CID_FaceDict dict; + CID_Subrs cid_subrs = face->subrs + fd_select; + FT_UInt cs_offset; + + + /* Set up subrs */ + decoder->num_subrs = cid_subrs->num_subrs; + decoder->subrs = cid_subrs->code; + decoder->subrs_len = 0; + decoder->subrs_hash = NULL; + + /* Set up font matrix */ + dict = cid->font_dicts + fd_select; + + decoder->font_matrix = dict->font_matrix; + decoder->font_offset = dict->font_offset; + decoder->lenIV = dict->private_dict.lenIV; + + /* Decode the charstring. */ + + /* Adjustment for seed bytes. */ + cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0; + if ( cs_offset > glyph_length ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, " + "offset to the charstring is beyond glyph length\n", + glyph_index )); + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + + /* Decrypt only if lenIV >= 0. */ + if ( decoder->lenIV >= 0 ) + psaux->t1_decrypt( charstring, glyph_length, 4330 ); + + /* choose which renderer to use */ +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + if ( ( (PS_Driver)FT_FACE_DRIVER( face ) )->hinting_engine == + FT_HINTING_FREETYPE || + decoder->builder.metrics_only ) + error = psaux->t1_decoder_funcs->parse_charstrings_old( + decoder, + charstring + cs_offset, + glyph_length - cs_offset ); +#else + if ( decoder->builder.metrics_only ) + error = psaux->t1_decoder_funcs->parse_metrics( + decoder, + charstring + cs_offset, + glyph_length - cs_offset ); +#endif + else + { + PS_Decoder psdecoder; + CFF_SubFontRec subfont; + + + psaux->ps_decoder_init( &psdecoder, decoder, TRUE ); + + psaux->t1_make_subfont( FT_FACE( face ), + &dict->private_dict, + &subfont ); + psdecoder.current_subfont = &subfont; + + error = psaux->t1_decoder_funcs->parse_charstrings( + &psdecoder, + charstring + cs_offset, + glyph_length - cs_offset ); + + /* Adobe's engine uses 16.16 numbers everywhere; */ + /* as a consequence, glyphs larger than 2000ppem get rejected */ + if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) + { + /* this time, we retry unhinted and scale up the glyph later on */ + /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ + /* 0x400 for both `x_scale' and `y_scale' in this case) */ + ((CID_GlyphSlot)decoder->builder.glyph)->hint = FALSE; + + force_scaling = TRUE; + + error = psaux->t1_decoder_funcs->parse_charstrings( + &psdecoder, + charstring + cs_offset, + glyph_length - cs_offset ); + } + } + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && inc && inc->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = FIXED_TO_INT( decoder->builder.left_bearing.x ); + metrics.bearing_y = 0; + metrics.advance = FIXED_TO_INT( decoder->builder.advance.x ); + metrics.advance_v = FIXED_TO_INT( decoder->builder.advance.y ); + + error = inc->funcs->get_glyph_metrics( inc->object, + glyph_index, FALSE, &metrics ); + + decoder->builder.left_bearing.x = INT_TO_FIXED( metrics.bearing_x ); + decoder->builder.advance.x = INT_TO_FIXED( metrics.advance ); + decoder->builder.advance.y = INT_TO_FIXED( metrics.advance_v ); + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + Exit: + FT_FREE( charstring ); + + ((CID_GlyphSlot)decoder->builder.glyph)->scaled = force_scaling; + + return error; + } + + +#if 0 + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + cid_face_compute_max_advance( CID_Face face, + FT_Int* max_advance ) + { + FT_Error error; + T1_DecoderRec decoder; + FT_Int glyph_index; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + *max_advance = 0; + + /* Initialize load decoder */ + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + 0, /* glyph names! XXX */ + 0, /* blend == 0 */ + 0, /* hinting == 0 */ + cid_load_glyph ); + if ( error ) + return error; + + /* TODO: initialize decoder.len_buildchar and decoder.buildchar */ + /* if we ever support CID-keyed multiple master fonts */ + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + /* now get load the unscaled outline */ + error = cid_load_glyph( &decoder, glyph_index ); + /* ignore the error if one occurred - skip to next glyph */ + } + + *max_advance = FIXED_TO_INT( decoder.builder.advance.x ); + + psaux->t1_decoder_funcs->done( &decoder ); + + return FT_Err_Ok; + } + + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + cid_slot_load_glyph( FT_GlyphSlot cidglyph, /* CID_GlyphSlot */ + FT_Size cidsize, /* CID_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + CID_GlyphSlot glyph = (CID_GlyphSlot)cidglyph; + FT_Error error; + T1_DecoderRec decoder; + CID_Face face = (CID_Face)cidglyph->face; + FT_Bool hinting; + FT_Bool scaled; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_Bool must_finish_decoder = FALSE; + + + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = cidsize->metrics.x_scale; + glyph->y_scale = cidsize->metrics.y_scale; + + cidglyph->outline.n_points = 0; + cidglyph->outline.n_contours = 0; + + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); + + glyph->hint = hinting; + glyph->scaled = scaled; + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + error = psaux->t1_decoder_funcs->init( &decoder, + cidglyph->face, + cidsize, + cidglyph, + 0, /* glyph names -- XXX */ + 0, /* blend == 0 */ + hinting, + FT_LOAD_TARGET_MODE( load_flags ), + cid_load_glyph ); + if ( error ) + goto Exit; + + /* TODO: initialize decoder.len_buildchar and decoder.buildchar */ + /* if we ever support CID-keyed multiple master fonts */ + + must_finish_decoder = TRUE; + + /* set up the decoder */ + decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); + + error = cid_load_glyph( &decoder, glyph_index ); + if ( error ) + goto Exit; + + /* copy flags back for forced scaling */ + hinting = glyph->hint; + scaled = glyph->scaled; + + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; + + /* save new glyph tables */ + psaux->t1_decoder_funcs->done( &decoder ); + + must_finish_decoder = FALSE; + + /* now set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + cidglyph->outline.flags &= FT_OUTLINE_OWNER; + cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = cidglyph->internal; + + + cidglyph->metrics.horiBearingX = + FIXED_TO_INT( decoder.builder.left_bearing.x ); + cidglyph->metrics.horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &cidglyph->metrics; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + cidglyph->linearHoriAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + cidglyph->internal->glyph_transformed = 0; + + /* make up vertical ones */ + metrics->vertAdvance = ( face->cid.font_bbox.yMax - + face->cid.font_bbox.yMin ) >> 16; + cidglyph->linearVertAdvance = metrics->vertAdvance; + + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + if ( cidsize->metrics.y_ppem < 24 ) + cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + /* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + { + FT_Outline_Transform( &cidglyph->outline, &font_matrix ); + + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + font_matrix.xx ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, + font_matrix.yy ); + } + + if ( font_offset.x || font_offset.y ) + { + FT_Outline_Translate( &cidglyph->outline, + font_offset.x, + font_offset.y ); + + metrics->horiAdvance += font_offset.x; + metrics->vertAdvance += font_offset.y; + } + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || scaled ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &cidglyph->outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* make up vertical ones */ + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + + Exit: + + if ( must_finish_decoder ) + psaux->t1_decoder_funcs->done( &decoder ); + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/cid/cidgload.h b/vendor/freetype/src/cid/cidgload.h new file mode 100644 index 0000000..edd6229 --- /dev/null +++ b/vendor/freetype/src/cid/cidgload.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * + * cidgload.h + * + * OpenType Glyph Loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDGLOAD_H_ +#define CIDGLOAD_H_ + + +#include "cidobjs.h" + + +FT_BEGIN_HEADER + + +#if 0 + + /* Compute the maximum advance width of a font through quick parsing */ + FT_LOCAL( FT_Error ) + cid_face_compute_max_advance( CID_Face face, + FT_Int* max_advance ); + +#endif /* 0 */ + + FT_LOCAL( FT_Error ) + cid_slot_load_glyph( FT_GlyphSlot glyph, /* CID_Glyph_Slot */ + FT_Size size, /* CID_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + FT_LOCAL( FT_Error ) + cid_compute_fd_and_offsets( CID_Face face, + FT_UInt glyph_index, + FT_ULong* fd_select_p, + FT_ULong* off1_p, + FT_ULong* off2_p ); + + +FT_END_HEADER + +#endif /* CIDGLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cid/cidload.c b/vendor/freetype/src/cid/cidload.c new file mode 100644 index 0000000..a7da8ea --- /dev/null +++ b/vendor/freetype/src/cid/cidload.c @@ -0,0 +1,950 @@ +/**************************************************************************** + * + * cidload.c + * + * CID-keyed Type1 font loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include + +#include "cidload.h" + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidload + + + /* read a single offset */ + FT_LOCAL_DEF( FT_ULong ) + cid_get_offset( FT_Byte* *start, + FT_UInt offsize ) + { + FT_ULong result; + FT_Byte* p = *start; + + + for ( result = 0; offsize > 0; offsize-- ) + { + result <<= 8; + result |= *p++; + } + + *start = p; + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + cid_load_keyword( CID_Face face, + CID_Loader* loader, + const T1_Field keyword ) + { + FT_Error error; + CID_Parser* parser = &loader->parser; + FT_Byte* object; + void* dummy_object; + CID_FaceInfo cid = &face->cid; + + + /* if the keyword has a dedicated callback, call it */ + if ( keyword->type == T1_FIELD_TYPE_CALLBACK ) + { + FT_TRACE4(( " %s", keyword->ident )); + + keyword->reader( (FT_Face)face, parser ); + error = parser->root.error; + goto Exit; + } + + /* we must now compute the address of our target object */ + switch ( keyword->location ) + { + case T1_FIELD_LOCATION_CID_INFO: + object = (FT_Byte*)cid; + break; + + case T1_FIELD_LOCATION_FONT_INFO: + object = (FT_Byte*)&cid->font_info; + break; + + case T1_FIELD_LOCATION_FONT_EXTRA: + object = (FT_Byte*)&face->font_extra; + break; + + case T1_FIELD_LOCATION_BBOX: + object = (FT_Byte*)&cid->font_bbox; + break; + + default: + { + CID_FaceDict dict; + + + if ( parser->num_dict >= cid->num_dicts ) + { + FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n", + keyword->ident )); + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + dict = cid->font_dicts + parser->num_dict; + switch ( keyword->location ) + { + case T1_FIELD_LOCATION_PRIVATE: + object = (FT_Byte*)&dict->private_dict; + break; + + default: + object = (FT_Byte*)dict; + } + } + } + + FT_TRACE4(( " %s", keyword->ident )); + + dummy_object = object; + + /* now, load the keyword data in the object's field(s) */ + if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY || + keyword->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = cid_parser_load_field_table( &loader->parser, keyword, + &dummy_object ); + else + error = cid_parser_load_field( &loader->parser, + keyword, &dummy_object ); + + FT_TRACE4(( "\n" )); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + cid_parse_font_matrix( FT_Face face, /* CID_Face */ + void* parser_ ) + { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + CID_FaceDict dict; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + + + if ( parser->num_dict < cidface->cid.num_dicts ) + { + FT_Matrix* matrix; + FT_Vector* offset; + FT_Int result; + + + dict = cidface->cid.font_dicts + parser->num_dict; + matrix = &dict->font_matrix; + offset = &dict->font_offset; + + /* input is scaled by 1000 to accommodate default FontMatrix */ + result = cid_parser_to_fixed_array( parser, 6, temp, 3 ); + + if ( result < 6 ) + { + FT_ERROR(( "cid_parse_font_matrix: not enough matrix elements\n" )); + goto Exit; + } + + FT_TRACE4(( " [%f %f %f %f %f %f]\n", + (double)temp[0] / 65536 / 1000, + (double)temp[1] / 65536 / 1000, + (double)temp[2] / 65536 / 1000, + (double)temp[3] / 65536 / 1000, + (double)temp[4] / 65536 / 1000, + (double)temp[5] / 65536 / 1000 )); + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" )); + goto Exit; + } + + /* atypical case */ + if ( temp_scale != 0x10000L ) + { + /* set units per EM based on FontMatrix values */ + face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); + + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; + } + + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* note that the font offsets are expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + Exit: + return; + } + + + FT_CALLBACK_DEF( void ) + parse_fd_array( FT_Face face, /* CID_Face */ + void* parser_ ) + { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + CID_FaceInfo cid = &cidface->cid; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Stream stream = parser->stream; + FT_Error error = FT_Err_Ok; + FT_Long num_dicts, max_dicts; + + + num_dicts = cid_parser_to_int( parser ); + if ( num_dicts < 0 || num_dicts > FT_INT_MAX ) + { + FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" )); + goto Exit; + } + + FT_TRACE4(( " %ld\n", num_dicts )); + + /* + * A single entry in the FDArray must (at least) contain the following + * structure elements. + * + * %ADOBeginFontDict 18 + * X dict begin 13 + * /FontMatrix [X X X X] 22 + * /Private X dict begin 22 + * end 4 + * end 4 + * %ADOEndFontDict 16 + * + * This needs 18+13+22+22+4+4+16=99 bytes or more. Normally, you also + * need a `dup X' at the very beginning and a `put' at the end, so a + * rough guess using 100 bytes as the minimum is justified. + */ + max_dicts = (FT_Long)( stream->size / 100 ); + if ( num_dicts > max_dicts ) + { + FT_TRACE0(( "parse_fd_array: adjusting FDArray size" + " (from %ld to %ld)\n", + num_dicts, max_dicts )); + num_dicts = max_dicts; + } + + if ( !cid->font_dicts ) + { + FT_UInt n; + + + if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) + goto Exit; + + cid->num_dicts = num_dicts; + + /* set some default values (the same as for Type 1 fonts) */ + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + + + dict->private_dict.blue_shift = 7; + dict->private_dict.blue_fuzz = 1; + dict->private_dict.lenIV = 4; + dict->private_dict.expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + dict->private_dict.blue_scale = (FT_Fixed)( + 0.039625 * 0x10000L * 1000 ); + } + } + + Exit: + return; + } + + + /* By mistake, `expansion_factor' appears both in PS_PrivateRec */ + /* and CID_FaceDictRec (both are public header files and can't */ + /* be thus changed). We simply copy the value. */ + + FT_CALLBACK_DEF( void ) + parse_expansion_factor( FT_Face face, /* CID_Face */ + void* parser_ ) + { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + CID_FaceDict dict; + + + if ( parser->num_dict < cidface->cid.num_dicts ) + { + dict = cidface->cid.font_dicts + parser->num_dict; + + dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); + dict->private_dict.expansion_factor = dict->expansion_factor; + + FT_TRACE4(( "%ld\n", dict->expansion_factor )); + } + + return; + } + + + /* By mistake, `CID_FaceDictRec' doesn't contain a field for the */ + /* `FontName' keyword. FreeType doesn't need it, but it is nice */ + /* to catch it for producing better trace output. */ + + FT_CALLBACK_DEF( void ) + parse_font_name( FT_Face face, /* CID_Face */ + void* parser_ ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + + + if ( parser->num_dict < cidface->cid.num_dicts ) + { + T1_TokenRec token; + FT_UInt len; + + + cid_parser_to_token( parser, &token ); + + len = (FT_UInt)( token.limit - token.start ); + if ( len ) + FT_TRACE4(( " %.*s\n", len, token.start )); + else + FT_TRACE4(( " \n" )); + } +#else + FT_UNUSED( face ); + FT_UNUSED( parser_ ); +#endif + + return; + } + + + static + const T1_FieldRec cid_field_records[] = + { + +#include "cidtoken.h" + + T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 ) + T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix, 0 ) + T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 ) + T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 ) + + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; + + + static FT_Error + cid_parse_dict( CID_Face face, + CID_Loader* loader, + FT_Byte* base, + FT_ULong size ) + { + CID_Parser* parser = &loader->parser; + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = FT_Err_Ok; + + { + FT_Byte* cur = base; + FT_Byte* limit = cur + size; + + + for (;;) + { + FT_Byte* newlimit; + + + parser->root.cursor = cur; + cid_parser_skip_spaces( parser ); + + if ( parser->root.cursor >= limit ) + newlimit = limit - 1 - 17; + else + newlimit = parser->root.cursor - 17; + + /* look for `%ADOBeginFontDict' */ + for ( ; cur < newlimit; cur++ ) + { + if ( *cur == '%' && + ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) + { + /* if /FDArray was found, then cid->num_dicts is > 0, and */ + /* we can start increasing parser->num_dict */ + if ( face->cid.num_dicts > 0 ) + { + parser->num_dict++; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " FontDict %u", parser->num_dict )); + if ( parser->num_dict > face->cid.num_dicts ) + FT_TRACE4(( " (ignored)" )); + FT_TRACE4(( "\n" )); +#endif + } + } + } + + cur = parser->root.cursor; + /* no error can occur in cid_parser_skip_spaces */ + if ( cur >= limit ) + break; + + cid_parser_skip_PS_token( parser ); + if ( parser->root.cursor >= limit || parser->root.error ) + break; + + /* look for immediates */ + if ( *cur == '/' && cur + 2 < limit ) + { + FT_UInt len; + + + cur++; + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( len > 0 && len < 22 ) + { + /* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)cid_field_records; + + + for (;;) + { + FT_Byte* name; + + + name = (FT_Byte*)keyword->ident; + if ( !name ) + break; + + if ( cur[0] == name[0] && + len == ft_strlen( (const char*)name ) ) + { + FT_UInt n; + + + for ( n = 1; n < len; n++ ) + if ( cur[n] != name[n] ) + break; + + if ( n >= len ) + { + /* we found it - run the parsing callback */ + parser->root.error = cid_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; + } + } + keyword++; + } + } + } + + cur = parser->root.cursor; + } + + if ( !face->cid.num_dicts ) + { + FT_ERROR(( "cid_parse_dict: No font dictionary found\n" )); + return FT_THROW( Invalid_File_Format ); + } + } + + return parser->root.error; + } + + + /* read the subrmap and the subrs of each font dict */ + static FT_Error + cid_read_subrs( CID_Face face ) + { + CID_FaceInfo cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Stream stream = face->cid_stream; + FT_Error error; + FT_UInt n; + CID_Subrs subr; + FT_UInt max_offsets = 0; + FT_ULong* offsets = NULL; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) + goto Exit; + + subr = face->subrs; + for ( n = 0; n < cid->num_dicts; n++, subr++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + FT_Int lenIV = dict->private_dict.lenIV; + FT_UInt count, num_subrs = dict->num_subrs; + FT_ULong data_len; + FT_Byte* p; + + + if ( !num_subrs ) + continue; + + /* reallocate offsets array if needed */ + if ( num_subrs + 1 > max_offsets ) + { + FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 ); + + + if ( new_max <= max_offsets ) + { + error = FT_THROW( Syntax_Error ); + goto Fail; + } + + if ( FT_QRENEW_ARRAY( offsets, max_offsets, new_max ) ) + goto Fail; + + max_offsets = new_max; + } + + /* read the subrmap's offsets */ + if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || + FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) ) + goto Fail; + + p = (FT_Byte*)stream->cursor; + for ( count = 0; count <= num_subrs; count++ ) + offsets[count] = cid_get_offset( &p, dict->sd_bytes ); + + FT_FRAME_EXIT(); + + /* offsets must be ordered */ + for ( count = 1; count <= num_subrs; count++ ) + if ( offsets[count - 1] > offsets[count] ) + { + FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( offsets[num_subrs] > stream->size - cid->data_offset ) + { + FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* now, compute the size of subrs charstrings, */ + /* allocate, and read them */ + data_len = offsets[num_subrs] - offsets[0]; + + if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) || + FT_QALLOC( subr->code[0], data_len ) ) + goto Fail; + + if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || + FT_STREAM_READ( subr->code[0], data_len ) ) + goto Fail; + + /* set up pointers */ + for ( count = 1; count <= num_subrs; count++ ) + { + FT_ULong len; + + + len = offsets[count] - offsets[count - 1]; + subr->code[count] = subr->code[count - 1] + len; + } + + /* decrypt subroutines, but only if lenIV >= 0 */ + if ( lenIV >= 0 ) + { + for ( count = 0; count < num_subrs; count++ ) + { + FT_ULong len; + + + len = offsets[count + 1] - offsets[count]; + psaux->t1_decrypt( subr->code[count], len, 4330 ); + } + } + + subr->num_subrs = (FT_Int)num_subrs; + } + + Exit: + FT_FREE( offsets ); + return error; + + Fail: + if ( face->subrs ) + { + for ( n = 0; n < cid->num_dicts; n++ ) + { + if ( face->subrs[n].code ) + FT_FREE( face->subrs[n].code[0] ); + + FT_FREE( face->subrs[n].code ); + } + FT_FREE( face->subrs ); + } + goto Exit; + } + + + static void + cid_init_loader( CID_Loader* loader, + CID_Face face ) + { + FT_UNUSED( face ); + + FT_ZERO( loader ); + } + + + static void + cid_done_loader( CID_Loader* loader ) + { + CID_Parser* parser = &loader->parser; + + + /* finalize parser */ + cid_parser_done( parser ); + } + + + static FT_Error + cid_hex_to_binary( FT_Byte* data, + FT_ULong data_len, + FT_ULong offset, + CID_Face face, + FT_ULong* data_written ) + { + FT_Stream stream = face->root.stream; + FT_Error error; + + FT_Byte buffer[256]; + FT_Byte *p, *plimit; + FT_Byte *d = data, *dlimit; + FT_Byte val; + + FT_Bool upper_nibble, done; + + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + + dlimit = d + data_len; + p = buffer; + plimit = p; + + upper_nibble = 1; + done = 0; + + while ( d < dlimit ) + { + if ( p >= plimit ) + { + FT_ULong oldpos = FT_STREAM_POS(); + FT_ULong size = stream->size - oldpos; + + + if ( size == 0 ) + { + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) ) + goto Exit; + p = buffer; + plimit = p + FT_STREAM_POS() - oldpos; + } + + if ( ft_isdigit( *p ) ) + val = (FT_Byte)( *p - '0' ); + else if ( *p >= 'a' && *p <= 'f' ) + val = (FT_Byte)( *p - 'a' + 10 ); + else if ( *p >= 'A' && *p <= 'F' ) + val = (FT_Byte)( *p - 'A' + 10 ); + else if ( *p == ' ' || + *p == '\t' || + *p == '\r' || + *p == '\n' || + *p == '\f' || + *p == '\0' ) + { + p++; + continue; + } + else if ( *p == '>' ) + { + val = 0; + done = 1; + } + else + { + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + if ( upper_nibble ) + *d = (FT_Byte)( val << 4 ); + else + { + *d = (FT_Byte)( *d + val ); + d++; + } + + upper_nibble = (FT_Byte)( 1 - upper_nibble ); + + if ( done ) + break; + + p++; + } + + error = FT_Err_Ok; + + Exit: + *data_written = (FT_ULong)( d - data ); + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_face_open( CID_Face face, + FT_Int face_index ) + { + CID_Loader loader; + CID_Parser* parser; + FT_Memory memory = face->root.memory; + FT_Error error; + FT_UInt n; + + CID_FaceInfo cid = &face->cid; + + FT_ULong binary_length; + + + cid_init_loader( &loader, face ); + + parser = &loader.parser; + error = cid_parser_new( parser, face->root.stream, face->root.memory, + (PSAux_Service)face->psaux ); + if ( error ) + goto Exit; + + error = cid_parse_dict( face, &loader, + parser->postscript, + parser->postscript_len ); + if ( error ) + goto Exit; + + if ( face_index < 0 ) + goto Exit; + + if ( FT_NEW( face->cid_stream ) ) + goto Exit; + + if ( parser->binary_length ) + { + if ( parser->binary_length > + face->root.stream->size - parser->data_offset ) + { + FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" )); + FT_TRACE0(( " (from %lu to %lu bytes)\n", + parser->binary_length, + face->root.stream->size - parser->data_offset )); + parser->binary_length = face->root.stream->size - + parser->data_offset; + } + + /* we must convert the data section from hexadecimal to binary */ + if ( FT_QALLOC( face->binary_data, parser->binary_length ) || + FT_SET_ERROR( cid_hex_to_binary( face->binary_data, + parser->binary_length, + parser->data_offset, + face, + &binary_length ) ) ) + goto Exit; + + FT_Stream_OpenMemory( face->cid_stream, + face->binary_data, binary_length ); + cid->data_offset = 0; + } + else + { + *face->cid_stream = *face->root.stream; + cid->data_offset = loader.parser.data_offset; + } + + /* sanity tests */ + + if ( cid->gd_bytes == 0 ) + { + FT_ERROR(( "cid_face_open:" + " Invalid `GDBytes' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* allow at most 32bit offsets */ + if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 ) + { + FT_ERROR(( "cid_face_open:" + " Values of `FDBytes' or `GDBytes' larger than 4\n" )); + FT_ERROR(( " " + " are not supported\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + binary_length = face->cid_stream->size - cid->data_offset; + + if ( cid->cidmap_offset > binary_length ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* the initial pre-check prevents the multiplication overflow */ + if ( cid->cid_count > FT_ULONG_MAX / 8 || + cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) > + binary_length - cid->cidmap_offset ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + + + /* the upper limits are ad-hoc values */ + if ( dict->private_dict.blue_shift > 1000 || + dict->private_dict.blue_shift < 0 ) + { + FT_TRACE2(( "cid_face_open:" + " setting unlikely BlueShift value %d to default (7)\n", + dict->private_dict.blue_shift )); + dict->private_dict.blue_shift = 7; + } + + if ( dict->private_dict.blue_fuzz > 1000 || + dict->private_dict.blue_fuzz < 0 ) + { + FT_TRACE2(( "cid_face_open:" + " setting unlikely BlueFuzz value %d to default (1)\n", + dict->private_dict.blue_fuzz )); + dict->private_dict.blue_fuzz = 1; + } + + if ( dict->num_subrs && dict->sd_bytes == 0 ) + { + FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( dict->sd_bytes > 4 ) + { + FT_ERROR(( "cid_face_open:" + " Values of `SDBytes' larger than 4" + " are not supported\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( dict->subrmap_offset > binary_length ) + { + FT_ERROR(( "cid_face_open: Invalid `SubrMapOffset' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* the initial pre-check prevents the multiplication overflow */ + if ( dict->num_subrs > FT_UINT_MAX / 4 || + dict->num_subrs * dict->sd_bytes > + binary_length - dict->subrmap_offset ) + { + FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + /* we can now safely proceed */ + error = cid_read_subrs( face ); + + Exit: + cid_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/cid/cidload.h b/vendor/freetype/src/cid/cidload.h new file mode 100644 index 0000000..d12d296 --- /dev/null +++ b/vendor/freetype/src/cid/cidload.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * cidload.h + * + * CID-keyed Type1 font loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDLOAD_H_ +#define CIDLOAD_H_ + + +#include +#include "cidparse.h" + + +FT_BEGIN_HEADER + + + typedef struct CID_Loader_ + { + CID_Parser parser; /* parser used to read the stream */ + FT_Int num_chars; /* number of characters in encoding */ + + } CID_Loader; + + + FT_LOCAL( FT_ULong ) + cid_get_offset( FT_Byte** start, + FT_UInt offsize ); + + FT_LOCAL( FT_Error ) + cid_face_open( CID_Face face, + FT_Int face_index ); + + +FT_END_HEADER + +#endif /* CIDLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cid/cidobjs.c b/vendor/freetype/src/cid/cidobjs.c new file mode 100644 index 0000000..f698a41 --- /dev/null +++ b/vendor/freetype/src/cid/cidobjs.c @@ -0,0 +1,543 @@ +/**************************************************************************** + * + * cidobjs.c + * + * CID objects manager (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + +#include "cidgload.h" +#include "cidload.h" + +#include +#include +#include +#include + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidobjs + + + /************************************************************************** + * + * SLOT FUNCTIONS + * + */ + + FT_LOCAL_DEF( void ) + cid_slot_done( FT_GlyphSlot slot ) + { + if ( slot->internal ) + slot->internal->glyph_hints = NULL; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_slot_init( FT_GlyphSlot slot ) + { + CID_Face face; + PSHinter_Service pshinter; + + + face = (CID_Face)slot->face; + pshinter = (PSHinter_Service)face->pshinter; + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->library, "pshinter" ); + if ( module ) + { + T1_Hints_Funcs funcs; + + + funcs = pshinter->get_t1_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return 0; + } + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + + + static PSH_Globals_Funcs + cid_size_get_globals_funcs( CID_Size size ) + { + CID_Face face = (CID_Face)size->root.face; + PSHinter_Service pshinter = (PSHinter_Service)face->pshinter; + FT_Module module; + + + module = FT_Get_Module( size->root.face->driver->root.library, + "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + cid_size_done( FT_Size cidsize ) /* CID_Size */ + { + CID_Size size = (CID_Size)cidsize; + + + if ( cidsize->internal->module_data ) + { + PSH_Globals_Funcs funcs; + + + funcs = cid_size_get_globals_funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)cidsize->internal->module_data ); + + cidsize->internal->module_data = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + cid_size_init( FT_Size cidsize ) /* CID_Size */ + { + CID_Size size = (CID_Size)cidsize; + FT_Error error = FT_Err_Ok; + PSH_Globals_Funcs funcs = cid_size_get_globals_funcs( size ); + + + if ( funcs ) + { + PSH_Globals globals; + CID_Face face = (CID_Face)cidsize->face; + CID_FaceDict dict = face->cid.font_dicts + face->root.face_index; + PS_Private priv = &dict->private_dict; + + + error = funcs->create( cidsize->face->memory, priv, &globals ); + if ( !error ) + cidsize->internal->module_data = globals; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_size_request( FT_Size size, + FT_Size_Request req ) + { + FT_Error error; + + PSH_Globals_Funcs funcs; + + + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; + + funcs = cid_size_get_globals_funcs( (CID_Size)size ); + + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->internal->module_data, + size->metrics.x_scale, + size->metrics.y_scale, + 0, 0 ); + + Exit: + return error; + } + + + /************************************************************************** + * + * FACE FUNCTIONS + * + */ + + /************************************************************************** + * + * @Function: + * cid_face_done + * + * @Description: + * Finalizes a given face object. + * + * @Input: + * face :: + * A pointer to the face object to destroy. + */ + FT_LOCAL_DEF( void ) + cid_face_done( FT_Face cidface ) /* CID_Face */ + { + CID_Face face = (CID_Face)cidface; + FT_Memory memory; + CID_FaceInfo cid; + PS_FontInfo info; + + + if ( !face ) + return; + + cid = &face->cid; + info = &cid->font_info; + memory = cidface->memory; + + /* release subrs */ + if ( face->subrs ) + { + FT_UInt n; + + + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_Subrs subr = face->subrs + n; + + + if ( subr->code ) + { + FT_FREE( subr->code[0] ); + FT_FREE( subr->code ); + } + } + + FT_FREE( face->subrs ); + } + + /* release FontInfo strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + + /* release font dictionaries */ + FT_FREE( cid->font_dicts ); + cid->num_dicts = 0; + + /* release other strings */ + FT_FREE( cid->cid_font_name ); + FT_FREE( cid->registry ); + FT_FREE( cid->ordering ); + + cidface->family_name = NULL; + cidface->style_name = NULL; + + FT_FREE( face->binary_data ); + FT_FREE( face->cid_stream ); + } + + + /************************************************************************** + * + * @Function: + * cid_face_init + * + * @Description: + * Initializes a given CID face object. + * + * @Input: + * stream :: + * Dummy argument for compatibility with the `FT_Face_InitFunc` API. + * Ignored. The stream should be passed through `face->root.stream`. + * + * face_index :: + * The index of the font face in the resource. + * + * num_params :: + * Number of additional generic parameters. Ignored. + * + * params :: + * Additional generic parameters. Ignored. + * + * @InOut: + * face :: + * The newly built face object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + cid_face_init( FT_Stream stream, + FT_Face cidface, /* CID_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + CID_Face face = (CID_Face)cidface; + FT_Error error; + PSAux_Service psaux; + PSHinter_Service pshinter; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + + + cidface->num_faces = 1; + + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + psaux = (PSAux_Service)FT_Get_Module_Interface( + FT_FACE_LIBRARY( face ), "psaux" ); + + if ( !psaux ) + { + FT_ERROR(( "cid_face_init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + face->psaux = psaux; + } + + pshinter = (PSHinter_Service)face->pshinter; + if ( !pshinter ) + { + pshinter = (PSHinter_Service)FT_Get_Module_Interface( + FT_FACE_LIBRARY( face ), "pshinter" ); + + face->pshinter = pshinter; + } + + FT_TRACE2(( "CID driver\n" )); + + /* open the tokenizer; this will also check the font format */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + error = cid_face_open( face, face_index ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + /* XXX: handle CID fonts with more than a single face */ + if ( ( face_index & 0xFFFF ) != 0 ) + { + FT_ERROR(( "cid_face_init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* now load the font program into the face object */ + + /* initialize the face object fields */ + + /* set up root face fields */ + { + CID_FaceInfo cid = &face->cid; + PS_FontInfo info = &cid->font_info; + + + cidface->num_glyphs = (FT_Long)cid->cid_count; + cidface->num_charmaps = 0; + + cidface->face_index = face_index & 0xFFFF; + + cidface->face_flags |= FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ + FT_FACE_FLAG_HINTER; /* has native hinter */ + + if ( info->is_fixed_pitch ) + cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* + * For the sfnt-wrapped CID fonts for MacOS, currently, + * its `cmap' tables are ignored, and the content in + * its `CID ' table is treated the same as naked CID-keyed + * font. See ft_lookup_PS_in_sfnt_stream(). + */ + cidface->face_flags |= FT_FACE_FLAG_CID_KEYED; + + /* XXX: TODO: add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a /FontName dictionary entry! */ + cidface->family_name = info->family_name; + /* assume "Regular" style if we don't know better */ + cidface->style_name = (char *)"Regular"; + if ( cidface->family_name ) + { + char* full = info->full_name; + char* family = cidface->family_name; + + + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + cidface->style_name = full; + break; + } + } + } + } + } + else + { + /* do we have a `/FontName'? */ + if ( cid->cid_font_name ) + cidface->family_name = cid->cid_font_name; + } + + /* compute style flags */ + cidface->style_flags = 0; + if ( info->italic_angle ) + cidface->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( info->weight ) + { + if ( !ft_strcmp( info->weight, "Bold" ) || + !ft_strcmp( info->weight, "Black" ) ) + cidface->style_flags |= FT_STYLE_FLAG_BOLD; + } + + /* no embedded bitmap support */ + cidface->num_fixed_sizes = 0; + cidface->available_sizes = NULL; + + cidface->bbox.xMin = cid->font_bbox.xMin >> 16; + cidface->bbox.yMin = cid->font_bbox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + cidface->bbox.xMax = ( cid->font_bbox.xMax + 0xFFFF ) >> 16; + cidface->bbox.yMax = ( cid->font_bbox.yMax + 0xFFFF ) >> 16; + + if ( !cidface->units_per_EM ) + cidface->units_per_EM = 1000; + + cidface->ascender = (FT_Short)( cidface->bbox.yMax ); + cidface->descender = (FT_Short)( cidface->bbox.yMin ); + + cidface->height = (FT_Short)( ( cidface->units_per_EM * 12 ) / 10 ); + if ( cidface->height < cidface->ascender - cidface->descender ) + cidface->height = (FT_Short)( cidface->ascender - cidface->descender ); + + cidface->underline_position = (FT_Short)info->underline_position; + cidface->underline_thickness = (FT_Short)info->underline_thickness; + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * cid_driver_init + * + * @Description: + * Initializes a given CID driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + cid_driver_init( FT_Module module ) + { + PS_Driver driver = (PS_Driver)module; + + FT_UInt32 seed; + + + /* set default property values, cf. `ftt1drv.h' */ + driver->hinting_engine = FT_HINTING_ADOBE; + + driver->no_stem_darkening = TRUE; + + driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&module ^ + (FT_Offset)(char*)module->memory ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + + driver->random_seed = (FT_Int32)seed; + if ( driver->random_seed < 0 ) + driver->random_seed = -driver->random_seed; + else if ( driver->random_seed == 0 ) + driver->random_seed = 123456789; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * cid_driver_done + * + * @Description: + * Finalizes a given CID driver. + * + * @Input: + * driver :: + * A handle to the target CID driver. + */ + FT_LOCAL_DEF( void ) + cid_driver_done( FT_Module driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/vendor/freetype/src/cid/cidobjs.h b/vendor/freetype/src/cid/cidobjs.h new file mode 100644 index 0000000..83c0c61 --- /dev/null +++ b/vendor/freetype/src/cid/cidobjs.h @@ -0,0 +1,154 @@ +/**************************************************************************** + * + * cidobjs.h + * + * CID objects manager (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDOBJS_H_ +#define CIDOBJS_H_ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + /* The following structures must be defined by the hinter */ + typedef struct CID_Size_Hints_ CID_Size_Hints; + typedef struct CID_Glyph_Hints_ CID_Glyph_Hints; + + + /************************************************************************** + * + * @Type: + * CID_Driver + * + * @Description: + * A handle to a Type 1 driver object. + */ + typedef struct CID_DriverRec_* CID_Driver; + + + /************************************************************************** + * + * @Type: + * CID_Size + * + * @Description: + * A handle to a Type 1 size object. + */ + typedef struct CID_SizeRec_* CID_Size; + + + /************************************************************************** + * + * @Type: + * CID_GlyphSlot + * + * @Description: + * A handle to a Type 1 glyph slot object. + */ + typedef struct CID_GlyphSlotRec_* CID_GlyphSlot; + + + /************************************************************************** + * + * @Type: + * CID_CharMap + * + * @Description: + * A handle to a Type 1 character mapping object. + * + * @Note: + * The Type 1 format doesn't use a charmap but an encoding table. + * The driver is responsible for making up charmap objects + * corresponding to these tables. + */ + typedef struct CID_CharMapRec_* CID_CharMap; + + + /************************************************************************** + * + * HERE BEGINS THE TYPE 1 SPECIFIC STUFF + * + */ + + + typedef struct CID_SizeRec_ + { + FT_SizeRec root; + FT_Bool valid; + + } CID_SizeRec; + + + typedef struct CID_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } CID_GlyphSlotRec; + + + FT_LOCAL( void ) + cid_slot_done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + cid_slot_init( FT_GlyphSlot slot ); + + + FT_LOCAL( void ) + cid_size_done( FT_Size size ); /* CID_Size */ + + FT_LOCAL( FT_Error ) + cid_size_init( FT_Size size ); /* CID_Size */ + + FT_LOCAL( FT_Error ) + cid_size_request( FT_Size size, /* CID_Size */ + FT_Size_Request req ); + + FT_LOCAL( FT_Error ) + cid_face_init( FT_Stream stream, + FT_Face face, /* CID_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + cid_face_done( FT_Face face ); /* CID_Face */ + + + FT_LOCAL( FT_Error ) + cid_driver_init( FT_Module driver ); + + FT_LOCAL( void ) + cid_driver_done( FT_Module driver ); + + +FT_END_HEADER + +#endif /* CIDOBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cid/cidparse.c b/vendor/freetype/src/cid/cidparse.c new file mode 100644 index 0000000..171a886 --- /dev/null +++ b/vendor/freetype/src/cid/cidparse.c @@ -0,0 +1,286 @@ +/**************************************************************************** + * + * cidparse.c + * + * CID-keyed Type1 parser (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + +#include "cidparse.h" + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidparse + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define STARTDATA "StartData" +#define STARTDATA_LEN ( sizeof ( STARTDATA ) - 1 ) +#define SFNTS "/sfnts" +#define SFNTS_LEN ( sizeof ( SFNTS ) - 1 ) + + + FT_LOCAL_DEF( FT_Error ) + cid_parser_new( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error; + FT_ULong base_offset, offset, ps_len; + FT_Byte *cur, *limit; + FT_Byte *arg1, *arg2; + + + FT_ZERO( parser ); + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); + + parser->stream = stream; + + base_offset = FT_STREAM_POS(); + + /* first of all, check the font format in the header */ + if ( FT_FRAME_ENTER( 31 ) ) + { + FT_TRACE2(( " not a CID-keyed font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( ft_strncmp( (char *)stream->cursor, + "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) + { + FT_TRACE2(( " not a CID-keyed font\n" )); + error = FT_THROW( Unknown_File_Format ); + } + + FT_FRAME_EXIT(); + if ( error ) + goto Exit; + + Again: + /* now, read the rest of the file until we find */ + /* `StartData' or `/sfnts' */ + { + /* + * The algorithm is as follows (omitting the case with less than 256 + * bytes to fill for simplicity). + * + * 1. Fill the buffer with 256 + STARTDATA_LEN bytes. + * + * 2. Search for the STARTDATA and SFNTS strings at positions + * buffer[0], buffer[1], ..., + * buffer[255 + STARTDATA_LEN - SFNTS_LEN]. + * + * 3. Move the last STARTDATA_LEN bytes to buffer[0]. + * + * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN. + * + * 5. Repeat with step 2. + * + */ + FT_Byte buffer[256 + STARTDATA_LEN + 1]; + + /* values for the first loop */ + FT_ULong read_len = 256 + STARTDATA_LEN; + FT_ULong read_offset = 0; + FT_Byte* p = buffer; + + + for ( offset = FT_STREAM_POS(); ; offset += 256 ) + { + FT_ULong stream_len; + + + stream_len = stream->size - FT_STREAM_POS(); + + read_len = FT_MIN( read_len, stream_len ); + if ( FT_STREAM_READ( p, read_len ) ) + goto Exit; + + /* ensure that we do not compare with data beyond the buffer */ + p[read_len] = '\0'; + + limit = p + read_len - SFNTS_LEN; + + for ( p = buffer; p < limit; p++ ) + { + if ( p[0] == 'S' && + ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 ) + { + /* save offset of binary data after `StartData' */ + offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; + goto Found; + } + else if ( p[1] == 's' && + ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 ) + { + offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; + goto Found; + } + } + + if ( read_offset + read_len < STARTDATA_LEN ) + { + FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_MEM_MOVE( buffer, + buffer + read_offset + read_len - STARTDATA_LEN, + STARTDATA_LEN ); + + /* values for the next loop */ + read_len = 256; + read_offset = STARTDATA_LEN; + p = buffer + read_offset; + } + } + + Found: + /* We have found the start of the binary data or the `/sfnts' token. */ + /* Now rewind and extract the frame corresponding to this PostScript */ + /* section. */ + + ps_len = offset - base_offset; + if ( FT_STREAM_SEEK( base_offset ) || + FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = offset; + parser->postscript_len = ps_len; + parser->root.base = parser->postscript; + parser->root.cursor = parser->postscript; + parser->root.limit = parser->root.cursor + ps_len; + parser->num_dict = FT_UINT_MAX; + + /* Finally, we check whether `StartData' or `/sfnts' was real -- */ + /* it could be in a comment or string. We also get the arguments */ + /* of `StartData' to find out whether the data is represented in */ + /* binary or hex format. */ + + arg1 = parser->root.cursor; + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + arg2 = parser->root.cursor; + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + + limit = parser->root.limit; + cur = parser->root.cursor; + + while ( cur <= limit - SFNTS_LEN ) + { + if ( parser->root.error ) + { + error = parser->root.error; + goto Exit; + } + + if ( cur[0] == 'S' && + cur <= limit - STARTDATA_LEN && + ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 ) + { + T1_TokenRec type_token; + FT_Long binary_length; + + + parser->root.cursor = arg1; + cid_parser_to_token( parser, &type_token ); + if ( type_token.limit - type_token.start == 5 && + ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 ) + { + parser->root.cursor = arg2; + binary_length = cid_parser_to_int( parser ); + if ( binary_length < 0 ) + { + FT_ERROR(( "cid_parser_new: invalid length of hex data\n" )); + error = FT_THROW( Invalid_File_Format ); + } + else + parser->binary_length = (FT_ULong)binary_length; + } + + goto Exit; + } + else if ( cur[1] == 's' && + ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 ) + { + FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + arg1 = arg2; + arg2 = cur; + cur = parser->root.cursor; + } + + /* we haven't found the correct `StartData'; go back and continue */ + /* searching */ + FT_FRAME_RELEASE( parser->postscript ); + if ( !FT_STREAM_SEEK( offset ) ) + goto Again; + + Exit: + return error; + } + + +#undef STARTDATA +#undef STARTDATA_LEN +#undef SFNTS +#undef SFNTS_LEN + + + FT_LOCAL_DEF( void ) + cid_parser_done( CID_Parser* parser ) + { + /* always free the private dictionary */ + if ( parser->postscript ) + { + FT_Stream stream = parser->stream; + + + FT_FRAME_RELEASE( parser->postscript ); + } + parser->root.funcs.done( &parser->root ); + } + + +/* END */ diff --git a/vendor/freetype/src/cid/cidparse.h b/vendor/freetype/src/cid/cidparse.h new file mode 100644 index 0000000..2fd4e7a --- /dev/null +++ b/vendor/freetype/src/cid/cidparse.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * cidparse.h + * + * CID-keyed Type1 parser (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDPARSE_H_ +#define CIDPARSE_H_ + + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Struct: + * CID_Parser + * + * @Description: + * A CID_Parser is an object used to parse a Type 1 fonts very + * quickly. + * + * @Fields: + * root :: + * The root PS_ParserRec fields. + * + * stream :: + * The current input stream. + * + * postscript :: + * A pointer to the data to be parsed. + * + * postscript_len :: + * The length of the data to be parsed. + * + * data_offset :: + * The start position of the binary data (i.e., the + * end of the data to be parsed. + * + * binary_length :: + * The length of the data after the `StartData' + * command if the data format is hexadecimal. + * + * cid :: + * A structure which holds the information about + * the current font. + * + * num_dict :: + * The number of font dictionaries. + */ + typedef struct CID_Parser_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* postscript; + FT_ULong postscript_len; + + FT_ULong data_offset; + + FT_ULong binary_length; + + CID_FaceInfo cid; + FT_UInt num_dict; + + } CID_Parser; + + + FT_LOCAL( FT_Error ) + cid_parser_new( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( void ) + cid_parser_done( CID_Parser* parser ); + + + /************************************************************************** + * + * PARSING ROUTINES + * + */ + +#define cid_parser_skip_spaces( p ) \ + (p)->root.funcs.skip_spaces( &(p)->root ) +#define cid_parser_skip_PS_token( p ) \ + (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define cid_parser_to_int( p ) (p)->root.funcs.to_int( &(p)->root ) +#define cid_parser_to_fixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) + +#define cid_parser_to_coord_array( p, m, c ) \ + (p)->root.funcs.to_coord_array( &(p)->root, m, c ) +#define cid_parser_to_fixed_array( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define cid_parser_to_token( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define cid_parser_to_token_array( p, t, m, c ) \ + (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) + +#define cid_parser_load_field( p, f, o ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, 0, 0 ) +#define cid_parser_load_field_table( p, f, o ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, 0, 0 ) + + +FT_END_HEADER + +#endif /* CIDPARSE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cid/cidriver.c b/vendor/freetype/src/cid/cidriver.c new file mode 100644 index 0000000..99e7b11 --- /dev/null +++ b/vendor/freetype/src/cid/cidriver.c @@ -0,0 +1,274 @@ +/**************************************************************************** + * + * cidriver.c + * + * CID driver interface (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "cidriver.h" +#include "cidgload.h" +#include +#include + +#include "ciderrs.h" + +#include +#include +#include +#include +#include +#include + +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ciddriver + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + FT_CALLBACK_DEF( const char* ) + cid_get_postscript_name( FT_Face face ) /* CID_Face */ + { + CID_Face cidface = (CID_Face)face; + const char* result = cidface->cid.cid_font_name; + + + if ( result && result[0] == '/' ) + result++; + + return result; + } + + + static const FT_Service_PsFontNameRec cid_service_ps_name = + { + (FT_PsName_GetFunc)cid_get_postscript_name /* get_ps_font_name */ + }; + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cid_ps_get_font_info( FT_Face face, /* CID_Face */ + PS_FontInfoRec* afont_info ) + { + *afont_info = ( (CID_Face)face )->cid.font_info; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_ps_get_font_extra( FT_Face face, /* CID_Face */ + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ( (CID_Face)face )->font_extra; + + return FT_Err_Ok; + } + + + static const FT_Service_PsInfoRec cid_service_ps_info = + { + cid_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + cid_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + /* unsupported with CID fonts */ + NULL, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ + /* unsupported */ + NULL, /* PS_GetFontPrivateFunc ps_get_font_private */ + /* not implemented */ + NULL /* PS_GetFontValueFunc ps_get_font_value */ + }; + + + /* + * CID INFO SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + cid_get_ros( FT_Face face, /* CID_Face */ + const char* *registry, + const char* *ordering, + FT_Int *supplement ) + { + CID_Face cidface = (CID_Face)face; + CID_FaceInfo cid = &cidface->cid; + + + if ( registry ) + *registry = cid->registry; + + if ( ordering ) + *ordering = cid->ordering; + + if ( supplement ) + *supplement = cid->supplement; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_get_is_cid( FT_Face face, /* CID_Face */ + FT_Bool *is_cid ) + { + FT_Error error = FT_Err_Ok; + FT_UNUSED( face ); + + + /* + * XXX: If the ROS is Adobe-Identity-H or -V, + * the font has no reliable information about + * its glyph collection. Should we not set + * *is_cid in such cases? + */ + if ( is_cid ) + *is_cid = 1; + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_get_cid_from_glyph_index( FT_Face face, /* CID_Face */ + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = FT_Err_Ok; + CID_Face cidface = (CID_Face)face; + + + /* + * Currently, FreeType does not support incrementally-defined, CID-keyed + * fonts that store the glyph description data in a `/GlyphDirectory` + * array or dictionary. Fonts loaded by the incremental loading feature + * are thus not handled here. + */ + error = cid_compute_fd_and_offsets( cidface, glyph_index, + NULL, NULL, NULL ); + if ( error ) + *cid = 0; + else + *cid = glyph_index; + + return error; + } + + + static const FT_Service_CIDRec cid_service_cid_info = + { + cid_get_ros, + /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */ + cid_get_is_cid, + /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */ + cid_get_cid_from_glyph_index + /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */ + }; + + + /* + * PROPERTY SERVICE + * + */ + + FT_DEFINE_SERVICE_PROPERTIESREC( + cid_service_properties, + + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec cid_services[] = + { + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CID }, + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cid_service_ps_name }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &cid_service_ps_info }, + { FT_SERVICE_ID_CID, &cid_service_cid_info }, + { FT_SERVICE_ID_PROPERTIES, &cid_service_properties }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + cid_get_interface( FT_Module module, + const char* cid_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( cid_services, cid_interface ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec t1cid_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + sizeof ( PS_DriverRec ), + + "t1cid", /* module name */ + 0x10000L, /* version 1.0 of driver */ + 0x20000L, /* requires FreeType 2.0 */ + + NULL, /* module-specific interface */ + + cid_driver_init, /* FT_Module_Constructor module_init */ + cid_driver_done, /* FT_Module_Destructor module_done */ + cid_get_interface /* FT_Module_Requester get_interface */ + }, + + sizeof ( CID_FaceRec ), + sizeof ( CID_SizeRec ), + sizeof ( CID_GlyphSlotRec ), + + cid_face_init, /* FT_Face_InitFunc init_face */ + cid_face_done, /* FT_Face_DoneFunc done_face */ + cid_size_init, /* FT_Size_InitFunc init_size */ + cid_size_done, /* FT_Size_DoneFunc done_size */ + cid_slot_init, /* FT_Slot_InitFunc init_slot */ + cid_slot_done, /* FT_Slot_DoneFunc done_slot */ + + cid_slot_load_glyph, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + cid_size_request, /* FT_Size_RequestFunc request_size */ + NULL /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/vendor/freetype/src/cid/cidriver.h b/vendor/freetype/src/cid/cidriver.h new file mode 100644 index 0000000..a624938 --- /dev/null +++ b/vendor/freetype/src/cid/cidriver.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * cidriver.h + * + * High-level CID driver interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDRIVER_H_ +#define CIDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_CALLBACK_TABLE + const FT_Driver_ClassRec t1cid_driver_class; + +FT_END_HEADER + +#endif /* CIDRIVER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/cid/cidtoken.h b/vendor/freetype/src/cid/cidtoken.h new file mode 100644 index 0000000..925951a --- /dev/null +++ b/vendor/freetype/src/cid/cidtoken.h @@ -0,0 +1,115 @@ +/**************************************************************************** + * + * cidtoken.h + * + * CID token definitions (specification only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CID_FaceInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_CID_INFO + + T1_FIELD_KEY ( "CIDFontName", cid_font_name, 0 ) + T1_FIELD_FIXED ( "CIDFontVersion", cid_version, 0 ) + T1_FIELD_NUM ( "CIDFontType", cid_font_type, 0 ) + T1_FIELD_STRING ( "Registry", registry, 0 ) + T1_FIELD_STRING ( "Ordering", ordering, 0 ) + T1_FIELD_NUM ( "Supplement", supplement, 0 ) + T1_FIELD_NUM ( "UIDBase", uid_base, 0 ) + + T1_FIELD_NUM_TABLE( "XUID", xuid, 16, 0 ) + + T1_FIELD_NUM ( "CIDMapOffset", cidmap_offset, 0 ) + T1_FIELD_NUM ( "FDBytes", fd_bytes, 0 ) + T1_FIELD_NUM ( "GDBytes", gd_bytes, 0 ) + T1_FIELD_NUM ( "CIDCount", cid_count, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, 0 ) + T1_FIELD_STRING( "Notice", notice, 0 ) + T1_FIELD_STRING( "FullName", full_name, 0 ) + T1_FIELD_STRING( "FamilyName", family_name, 0 ) + T1_FIELD_STRING( "Weight", weight, 0 ) + T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontExtraRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA + + T1_FIELD_NUM ( "FSType", fs_type, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CID_FaceDictRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_NUM ( "PaintType", paint_type, 0 ) + T1_FIELD_NUM ( "FontType", font_type, 0 ) + T1_FIELD_NUM ( "SubrMapOffset", subrmap_offset, 0 ) + T1_FIELD_NUM ( "SDBytes", sd_bytes, 0 ) + T1_FIELD_NUM ( "SubrCount", num_subrs, 0 ) + T1_FIELD_NUM ( "lenBuildCharArray", len_buildchar, 0 ) + T1_FIELD_FIXED( "ForceBoldThreshold", forcebold_threshold, 0 ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_PrivateRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_PRIVATE + + T1_FIELD_NUM ( "UniqueID", unique_id, 0 ) + T1_FIELD_NUM ( "lenIV", lenIV, 0 ) + T1_FIELD_NUM ( "LanguageGroup", language_group, 0 ) + T1_FIELD_NUM ( "password", password, 0 ) + + T1_FIELD_FIXED_1000( "BlueScale", blue_scale, 0 ) + T1_FIELD_NUM ( "BlueShift", blue_shift, 0 ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, 0 ) + + T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, 0 ) + T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, 0 ) + T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, 0 ) + T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, 0 ) + + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, 0 ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, 0 ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, 0 ) + + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, 0 ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, 0 ) + + T1_FIELD_BOOL ( "ForceBold", force_bold, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, 0 ) + + +/* END */ diff --git a/vendor/freetype/src/cid/module.mk b/vendor/freetype/src/cid/module.mk new file mode 100644 index 0000000..563cb34 --- /dev/null +++ b/vendor/freetype/src/cid/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 CID module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += TYPE1CID_DRIVER + +define TYPE1CID_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, t1cid_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)cid $(ECHO_DRIVER_DESC)Postscript CID-keyed fonts, no known extension$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/cid/rules.mk b/vendor/freetype/src/cid/rules.mk new file mode 100644 index 0000000..c526ad3 --- /dev/null +++ b/vendor/freetype/src/cid/rules.mk @@ -0,0 +1,73 @@ +# +# FreeType 2 CID driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# CID driver directory +# +CID_DIR := $(SRC_DIR)/cid + + +CID_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(CID_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# CID driver sources (i.e., C files) +# +CID_DRV_SRC := $(CID_DIR)/cidparse.c \ + $(CID_DIR)/cidload.c \ + $(CID_DIR)/cidriver.c \ + $(CID_DIR)/cidgload.c \ + $(CID_DIR)/cidobjs.c + +# CID driver headers +# +CID_DRV_H := $(CID_DRV_SRC:%.c=%.h) \ + $(CID_DIR)/cidtoken.h \ + $(CID_DIR)/ciderrs.h + + +# CID driver object(s) +# +# CID_DRV_OBJ_M is used during `multi' builds +# CID_DRV_OBJ_S is used during `single' builds +# +CID_DRV_OBJ_M := $(CID_DRV_SRC:$(CID_DIR)/%.c=$(OBJ_DIR)/%.$O) +CID_DRV_OBJ_S := $(OBJ_DIR)/type1cid.$O + +# CID driver source file for single build +# +CID_DRV_SRC_S := $(CID_DIR)/type1cid.c + + +# CID driver - single object +# +$(CID_DRV_OBJ_S): $(CID_DRV_SRC_S) $(CID_DRV_SRC) $(FREETYPE_H) $(CID_DRV_H) + $(CID_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(CID_DRV_SRC_S)) + + +# CID driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(CID_DIR)/%.c $(FREETYPE_H) $(CID_DRV_H) + $(CID_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(CID_DRV_OBJ_S) +DRV_OBJS_M += $(CID_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/cid/type1cid.c b/vendor/freetype/src/cid/type1cid.c new file mode 100644 index 0000000..905c896 --- /dev/null +++ b/vendor/freetype/src/cid/type1cid.c @@ -0,0 +1,28 @@ +/**************************************************************************** + * + * type1cid.c + * + * FreeType OpenType driver component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "cidgload.c" +#include "cidload.c" +#include "cidobjs.c" +#include "cidparse.c" +#include "cidriver.c" + + +/* END */ diff --git a/vendor/freetype/src/dlg/dlgwrap.c b/vendor/freetype/src/dlg/dlgwrap.c new file mode 100644 index 0000000..e9dc341 --- /dev/null +++ b/vendor/freetype/src/dlg/dlgwrap.c @@ -0,0 +1,32 @@ +/**************************************************************************** + * + * dlgwrap.c + * + * Wrapper file for the 'dlg' library (body only) + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include FT_CONFIG_OPTIONS_H + + +#ifdef FT_DEBUG_LOGGING +#define DLG_STATIC +#include "dlg.c" +#else + /* ANSI C doesn't like empty source files */ + typedef int dlg_dummy_; +#endif + + +/* END */ diff --git a/vendor/freetype/src/dlg/rules.mk b/vendor/freetype/src/dlg/rules.mk new file mode 100644 index 0000000..7f506fd --- /dev/null +++ b/vendor/freetype/src/dlg/rules.mk @@ -0,0 +1,70 @@ +# +# FreeType 2 dlg logging library configuration rules +# + + +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# dlg logging library directory +# +DLG_DIR := $(SRC_DIR)/dlg + + +# compilation flags for the library +# +DLG_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(DLG_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# dlg logging library sources (i.e., C files) +# +DLG_SRC := $(DLG_DIR)/dlgwrap.c + +# dlg logging library headers +# +DLG_H := $(TOP_DIR)/include/dlg/dlg.h \ + $(TOP_DIR)/include/dlg/output.h + + +# dlg logging library object(s) +# +# DLG_OBJ_M is used during `multi' builds +# DLG_OBJ_S is used during `single' builds +# +DLG_OBJ_M := $(DLG_SRC:$(DLG_DIR)/%.c=$(OBJ_DIR)/%.$O) +DLG_OBJ_S := $(OBJ_DIR)/dlg.$O + +# dlg logging library source file for single build +# +DLG_SRC_S := $(DLG_DIR)/dlgwrap.c + + +# dlg logging library - single object +# +$(DLG_OBJ_S): $(DLG_SRC_S) $(DLG_SRC) $(FREETYPE_H) $(DLG_H) + $(DLG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(DLG_SRC_S)) + + +# dlg logging library - multiple objects +# +$(OBJ_DIR)/%.$O: $(DLG_DIR)/%.c $(FREETYPE_H) $(DLG_H) + $(DLG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main object lists +# +DLG_OBJS_S += $(DLG_OBJ_S) +DLG_OBJS_M += $(DLG_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/gxvalid/README b/vendor/freetype/src/gxvalid/README new file mode 100644 index 0000000..0e3db32 --- /dev/null +++ b/vendor/freetype/src/gxvalid/README @@ -0,0 +1,532 @@ +gxvalid: TrueType GX validator +============================== + + +1. What is this +--------------- + + `gxvalid' is a module to validate TrueType GX tables: a collection of + additional tables in TrueType font which are used by `QuickDraw GX + Text', Apple Advanced Typography (AAT). In addition, gxvalid can + validates `kern' tables which have been extended for AAT. Like the + otvalid module, gxvalid uses FreeType 2's validator framework + (ftvalid). + + You can link gxvalid with your program; before running your own layout + engine, gxvalid validates a font file. As the result, you can remove + error-checking code from the layout engine. It is also possible to + use gxvalid as a stand-alone font validator; the `ftvalid' test + program included in the ft2demo bundle calls gxvalid internally. + A stand-alone font validator may be useful for font developers. + + This documents documents the following issues. + + - supported TrueType GX tables + - fundamental validation limitations + - permissive error handling of broken GX tables + - `kern' table issue. + + +2. Supported tables +------------------- + + The following GX tables are currently supported. + + bsln + feat + just + kern(*) + lcar + mort + morx + opbd + prop + trak + + The following GX tables are currently unsupported. + + cvar + fdsc + fmtx + fvar + gvar + Zapf + + The following GX tables won't be supported. + + acnt(**) + hsty(***) + + The following undocumented tables in TrueType fonts designed for Apple + platform aren't handled either. + + addg + CVTM + TPNM + umif + + + *) The `kern' validator handles both the classic and the new kern + formats; the former is supported on both Microsoft and Apple + platforms, while the latter is supported on Apple platforms. + + **) `acnt' tables are not supported by currently available Apple font + tools. + + ***) There is one more Apple extension, `hsty', but it is for + Newton-OS, not GX (Newton-OS is a platform by Apple, but it can + use sfnt- housed bitmap fonts only). Therefore, it should be + excluded from `Apple platform' in the context of TrueType. + gxvalid ignores it as Apple font tools do so. + + + We have checked 183 fonts bundled with MacOS 9.1, MacOS 9.2, MacOS + 10.0, MacOS X 10.1, MSIE for MacOS, and AppleWorks 6.0. In addition, + we have checked 67 Dynalab fonts (designed for MacOS) and 189 Ricoh + fonts (designed for Windows and MacOS dual platforms). The number of + fonts including TrueType GX tables are as follows. + + bsln: 76 + feat: 191 + just: 84 + kern: 59 + lcar: 4 + mort: 326 + morx: 19 + opbd: 4 + prop: 114 + trak: 16 + + Dynalab and Ricoh fonts don't have GX tables except of `feat' and + `mort'. + + +3. Fundamental validation limitations +------------------------------------- + + TrueType GX provides layout information to libraries for font + rasterizers and text layout. gxvalid can check whether the layout + data in a font is conformant to the TrueType GX format specified by + Apple. But gxvalid cannot check a how QuickDraw GX/AAT renderer uses + the stored information. + + 3-1. Validation of State Machine activity + ----------------------------------------- + + QuickDraw GX/AAT uses a `State Machine' to provide `stateful' layout + features, and TrueType GX stores the state transition diagram of + this `State Machine' in a `StateTable' data structure. While the + State Machine receives a series of glyph IDs, the State Machine + starts with `start of text' state, walks around various states and + generates various layout information to the renderer, and finally + reaches the `end of text' state. + + gxvalid can check essential errors like: + + - possibility of state transitions to undefined states + - existence of glyph IDs that the State Machine doesn't know how + to handle + - the State Machine cannot compute the layout information from + given diagram + + These errors can be checked within finite steps, and without the + State Machine itself, because these are `expression' errors of state + transition diagram. + + There is no limitation about how long the State Machine walks + around, so validation of the algorithm in the state transition + diagram requires infinite steps, even if we had a State Machine in + gxvalid. Therefore, the following errors and problems cannot be + checked. + + - existence of states which the State Machine never transits to + - the possibility that the State Machine never reaches `end of + text' + - the possibility of stack underflow/overflow in the State Machine + (in ligature and contextual glyph substitutions, the State + Machine can store 16 glyphs onto its stack) + + In addition, gxvalid doesn't check `temporary glyph IDs' used in the + chained State Machines (in `mort' and `morx' tables). If a layout + feature is implemented by a single State Machine, a glyph ID + converted by the State Machine is passed to the glyph renderer, thus + it should not point to an undefined glyph ID. But if a layout + feature is implemented by chained State Machines, a component State + Machine (if it is not the final one) is permitted to generate + undefined glyph IDs for temporary use, because it is handled by next + component State Machine and not by the glyph renderer. To validate + such temporary glyph IDs, gxvalid must stack all undefined glyph IDs + which can occur in the output of the previous State Machine and + search them in the `ClassTable' structure of the current State + Machine. It is too complex to list all possible glyph IDs from the + StateTable, especially from a ligature substitution table. + + 3-2. Validation of relationship between multiple layout features + ---------------------------------------------------------------- + + gxvalid does not validate the relationship between multiple layout + features at all. + + If multiple layout features are defined in TrueType GX tables, + possible interactions, overrides, and conflicts between layout + features are implicitly given in the font too. For example, there + are several predefined spacing control features: + + - Text Spacing (Proportional/Monospace/Half-width/Normal) + - Number Spacing (Monospaced-numbers/Proportional-numbers) + - Kana Spacing (Full-width/Proportional) + - Ideographic Spacing (Full-width/Proportional) + - CJK Roman Spacing (Half-width/Proportional/Default-roman + /Full-width-roman/Proportional) + + If all layout features are independently managed, we can activate + inconsistent typographic rules like `Text Spacing=Monospace' and + `Ideographic Spacing=Proportional' at the same time. + + The combinations of layout features is managed by a 32bit integer + (one bit each for selector setting), so we can define relationships + between up to 32 features, theoretically. But if one feature + setting affects another feature setting, we need typographic + priority rules to validate the relationship. Unfortunately, the + TrueType GX format specification does not give such information even + for predefined features. + + +4. Permissive error handling of broken GX tables +------------------------------------------------ + + When Apple's font rendering system finds an inconsistency, like a + specification violation or an unspecified value in a TrueType GX + table, it does not always return error. In most cases, the rendering + engine silently ignores such wrong values or even whole tables. In + fact, MacOS is shipped with fonts including broken GX/AAT tables, but + no harmful effects due to `officially broken' fonts are observed by + end-users. + + gxvalid is designed to continue the validation process as long as + possible. When gxvalid find wrong values, gxvalid warns it at least, + and takes a fallback procedure if possible. The fallback procedure + depends on the debug level. + + We used the following three tools to investigate Apple's error handling. + + - FontValidator (for MacOS 8.5 - 9.2) resource fork font + - ftxvalidator (for MacOS X 10.1 -) dfont or naked-sfnt + - ftxdumperfuser (for MacOS X 10.1 -) dfont or naked-sfnt + + However, all tests were done on a PowerPC based Macintosh; at present, + we have not checked those tools on a m68k-based Macintosh. + + In total, we checked 183 fonts bundled to MacOS 9.1, MacOS 9.2, MacOS + 10.0, MacOS X 10.1, MSIE for MacOS, and AppleWorks 6.0. These fonts + are distributed officially, but many broken GX/AAT tables were found + by Apple's font tools. In the following, we list typical violation of + the GX specification, in fonts officially distributed with those Apple + systems. + + 4-1. broken BinSrchHeader (19/183) + ---------------------------------- + + `BinSrchHeader' is a header of a data array for m68k platforms to + access memory efficiently. Although there are only two independent + parameters for real (`unitSize' and `nUnits'), BinSrchHeader has + three additional parameters which can be calculated from `unitSize' + and `nUnits', for fast setup. Apple font tools ignore them + silently, so gxvalid warns if it finds and inconsistency, and always + continues validation. The additional parameters are ignored + regardless of the consistency. + + 19 fonts include such inconsistencies; all breaks are in the + BinSrchHeader structure of the `kern' table. + + 4-2. too-short LookupTable (5/183) + ---------------------------------- + + LookupTable format 0 is a simple array to get a value from a given + GID (glyph ID); the index of this array is a GID too. Therefore, + the length of the array is expected to be same as the maximum GID + value defined in the `maxp' table, but there are some fonts whose + LookupTable format 0 is too short to cover all GIDs. FontValidator + ignores this error silently, ftxvalidator and ftxdumperfuser both + warn and continue. Similar problems are found in format 3 subtables + of `kern'. gxvalid warns always and abort if the validation level + is set to FT_VALIDATE_PARANOID. + + 5 fonts include too-short kern format 0 subtables. + 1 font includes too-short kern format 3 subtable. + + 4-3. broken LookupTable format 2 (1/183) + ---------------------------------------- + + LookupTable format 2, subformat 4 covers the GID space by a + collection of segments which are specified by `firstGlyph' and + `lastGlyph'. Some fonts store `firstGlyph' and `lastGlyph' in + reverse order, so the segment specification is broken. Apple font + tools ignore this error silently; a broken segment is ignored as if + it did not exist. gxvalid warns and normalize the segment at + FT_VALIDATE_DEFAULT, or ignore the segment at FT_VALIDATE_TIGHT, or + abort at FT_VALIDATE_PARANOID. + + 1 font includes broken LookupTable format 2, in the `just' table. + + *) It seems that all fonts manufactured by ITC for AppleWorks have + this error. + + 4-4. bad bracketing in glyph property (14/183) + ---------------------------------------------- + + GX/AAT defines a `bracketing' property of the glyphs in the `prop' + table, to control layout features of strings enclosed inside and + outside of brackets. Some fonts give inappropriate bracket + properties to glyphs. Apple font tools warn about this error; + gxvalid warns too and aborts at FT_VALIDATE_PARANOID. + + 14 fonts include wrong bracket properties. + + + 4-5. invalid feature number (117/183) + ------------------------------------- + + The GX/AAT extension can include 255 different layout features, + but popular layout features are predefined (see + https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html). + Some fonts include feature numbers which are incompatible with the + predefined feature registry. + + In our survey, there are 140 fonts including `feat' table. + + a) 67 fonts use a feature number which should not be used. + b) 117 fonts set the wrong feature range (nSetting). This is mostly + found in the `mort' and `morx' tables. + + Apple font tools give no warning, although they cannot recognize + what the feature is. At FT_VALIDATE_DEFAULT, gxvalid warns but + continues in both cases (a, b). At FT_VALIDATE_TIGHT, gxvalid warns + and aborts for (a), but continues for (b). At FT_VALIDATE_PARANOID, + gxvalid warns and aborts in both cases (a, b). + + 4-6. invalid prop version (10/183) + ---------------------------------- + + As most TrueType GX tables, the `prop' table must start with a 32bit + version identifier: 0x00010000, 0x00020000 or 0x00030000. But some + fonts store nonsense binary data instead. When Apple font tools + find them, they abort the processing immediately, and the data which + follows is unhandled. gxvalid does the same. + + 10 fonts include broken `prop' version. + + All of these fonts are classic TrueType fonts for the Japanese + script, manufactured by Apple. + + 4-7. unknown resource name (2/183) + ------------------------------------ + + NOTE: THIS IS NOT A TRUETYPE GX ERROR. + + If a TrueType font is stored in the resource fork or in dfont + format, the data must be tagged as `sfnt' in the resource fork index + to invoke TrueType font handler for the data. But the TrueType font + data in `Keyboard.dfont' is tagged as `kbd', and that in + `LastResort.dfont' is tagged as `lst'. Apple font tools can detect + that the data is in TrueType format and successfully validate them. + Maybe this is possible because they are known to be dfont. The + current implementation of the resource fork driver of FreeType + cannot do that, thus gxvalid cannot validate them. + + 2 fonts use an unknown tag for the TrueType font resource. + +5. `kern' table issues +---------------------- + + In common terminology of TrueType, `kern' is classified as a basic and + platform-independent table. But there are Apple extensions of `kern', + and there is an extension which requires a GX state machine for + contextual kerning. Therefore, gxvalid includes a special validator + for `kern' tables. Unfortunately, there is no exact algorithm to + check Apple's extension, so gxvalid includes a heuristic algorithm to + find the proper validation routines for all possible data formats, + including the data format for Microsoft. By calling + classic_kern_validate() instead of gxv_validate(), you can specify the + `kern' format explicitly. However, current FreeType2 uses Microsoft + `kern' format only, others are ignored (and should be handled in a + library one level higher than FreeType). + + 5-1. History + ------------ + + The original 16bit version of `kern' was designed by Apple in the + pre-GX era, and it was also approved by Microsoft. Afterwards, + Apple designed a new 32bit version of the `kern' table. According + to the documentation, the difference between the 16bit and 32bit + version is only the size of variables in the `kern' header. In the + following, we call the original 16bit version as `classic', and + 32bit version as `new'. + + 5-2. Versions and dialects which should be differentiated + --------------------------------------------------------- + + The `kern' table consists of a table header and several subtables. + The version number which identifies a `classic' or a `new' version + is explicitly written in the table header, but there are + undocumented differences between Microsoft's and Apple's formats. + It is called a `dialect' in the following. There are three cases + which should be handled: the new Apple-dialect, the classic + Apple-dialect, and the classic Microsoft-dialect. An analysis of + the formats and the auto detection algorithm of gxvalid is described + in the following. + + 5-2-1. Version detection: classic and new kern + ---------------------------------------------- + + According to Apple TrueType specification, there are only two + differences between the classic and the new: + + - The `kern' table header starts with the version number. + The classic version starts with 0x0000 (16bit), + the new version starts with 0x00010000 (32bit). + + - In the `kern' table header, the number of subtables follows + the version number. + In the classic version, it is stored as a 16bit value. + In the new version, it is stored as a 32bit value. + + From Apple font tool's output (DumpKERN is also tested in addition + to the three Apple font tools in above), there is another + undocumented difference. In the new version, the subtable header + includes a 16bit variable named `tupleIndex' which does not exist + in the classic version. + + The new version can store all subtable formats (0, 1, 2, and 3), + but the Apple TrueType specification does not mention the subtable + formats available in the classic version. + + 5-2-2. Available subtable formats in classic version + ---------------------------------------------------- + + Although the Apple TrueType specification recommends to use the + classic version in the case if the font is designed for both the + Apple and Microsoft platforms, it does not document the available + subtable formats in the classic version. + + According to the Microsoft TrueType specification, the subtable + format assured for Windows and OS/2 support is only subtable + format 0. The Microsoft TrueType specification also describes + subtable format 2, but does not mention which platforms support + it. Subtable formats 1, 3, and higher are documented as reserved + for future use. Therefore, the classic version can store subtable + formats 0 and 2, at least. `ttfdump.exe', a font tool provided by + Microsoft, ignores the subtable format written in the subtable + header, and parses the table as if all subtables are in format 0. + + `kern' subtable format 1 uses a StateTable, so it cannot be + utilized without a GX State Machine. Therefore, it is reasonable + to assume that format 1 (and 3) were introduced after Apple had + introduced GX and moved to the new 32bit version. + + 5-2-3. Apple and Microsoft dialects + ----------------------------------- + + The `kern' subtable has a 16bit `coverage' field to describe + kerning attributes, but bit interpretations by Apple and Microsoft + are different: For example, Apple uses bits 0-7 to identify the + subtable, while Microsoft uses bits 8-15. + + In addition, due to the output of DumpKERN and FontValidator, + Apple's bit interpretations of coverage in classic and new version + are incompatible also. In summary, there are three dialects: + classic Apple dialect, classic Microsoft dialect, and new Apple + dialect. The classic Microsoft dialect and the new Apple dialect + are documented by each vendors' TrueType font specification, but + the documentation for classic Apple dialect is not available. + + For example, in the new Apple dialect, bit 15 is documented as + `set to 1 if the kerning is vertical'. On the other hand, in + classic Microsoft dialect, bit 1 is documented as `set to 1 if the + kerning is horizontal'. From the outputs of DumpKERN and + FontValidator, classic Apple dialect recognizes 15 as `set to 1 + when the kerning is horizontal'. From the results of similar + experiments, classic Apple dialect seems to be the Endian reverse + of the classic Microsoft dialect. + + As a conclusion it must be noted that no font tool can identify + classic Apple dialect or classic Microsoft dialect automatically. + + 5-2-4. gxvalid auto dialect detection algorithm + ----------------------------------------------- + + The first 16 bits of the `kern' table are enough to identify the + version: + + - if the first 16 bits are 0x0000, the `kern' table is in + classic Apple dialect or classic Microsoft dialect + - if the first 16 bits are 0x0001, and next 16 bits are 0x0000, + the kern table is in new Apple dialect. + + If the `kern' table is a classic one, the 16bit `coverage' field + is checked next. Firstly, the coverage bits are decoded for the + classic Apple dialect using the following bit masks (this is based + on DumpKERN output): + + 0x8000: 1=horizontal, 0=vertical + 0x4000: not used + 0x2000: 1=cross-stream, 0=normal + 0x1FF0: reserved + 0x000F: subtable format + + If any of reserved bits are set or the subtable bits is + interpreted as format 1 or 3, we take it as `impossible in classic + Apple dialect' and retry, using the classic Microsoft dialect. + + The most popular coverage in new Apple-dialect: 0x8000, + The most popular coverage in classic Apple-dialect: 0x0000, + The most popular coverage in classic Microsoft dialect: 0x0001. + + 5-3. Tested fonts + ----------------- + + We checked 59 fonts bundled with MacOS and 38 fonts bundled with + Windows, where all font include a `kern' table. + + - fonts bundled with MacOS + * new Apple dialect + format 0: 18 + format 2: 1 + format 3: 1 + * classic Apple dialect + format 0: 14 + * classic Microsoft dialect + format 0: 15 + + - fonts bundled with Windows + * classic Microsoft dialect + format 0: 38 + + It looks strange that classic Microsoft-dialect fonts are bundled to + MacOS: they come from MSIE for MacOS, except of MarkerFelt.dfont. + + + ACKNOWLEDGEMENT + --------------- + + Some parts of gxvalid are derived from both the `gxlayout' module and + the `otvalid' module. Development of gxlayout was supported by the + Information-technology Promotion Agency(IPA), Japan. + + The detailed analysis of undefined glyph ID utilization in `mort' and + `morx' tables is provided by George Williams. + +------------------------------------------------------------------------ + +Copyright (C) 2004-2023 by +suzuki toshiya, Masatake YAMATO, Red hat K.K., +David Turner, Robert Wilhelm, and Werner Lemberg. + +This file is part of the FreeType project, and may only be used, +modified, and distributed under the terms of the FreeType project +license, LICENSE.TXT. By continuing to use, modify, or distribute this +file you indicate that you have read the license and understand and +accept it fully. + + +--- end of README --- diff --git a/vendor/freetype/src/gxvalid/gxvalid.c b/vendor/freetype/src/gxvalid/gxvalid.c new file mode 100644 index 0000000..e0359f4 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvalid.c @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * gxvalid.c + * + * FreeType validator for TrueTypeGX/AAT tables (body only). + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "gxvbsln.c" +#include "gxvcommn.c" +#include "gxvfeat.c" +#include "gxvjust.c" +#include "gxvkern.c" +#include "gxvlcar.c" +#include "gxvmod.c" +#include "gxvmort.c" +#include "gxvmort0.c" +#include "gxvmort1.c" +#include "gxvmort2.c" +#include "gxvmort4.c" +#include "gxvmort5.c" +#include "gxvmorx.c" +#include "gxvmorx0.c" +#include "gxvmorx1.c" +#include "gxvmorx2.c" +#include "gxvmorx4.c" +#include "gxvmorx5.c" +#include "gxvopbd.c" +#include "gxvprop.c" +#include "gxvtrak.c" + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvalid.h b/vendor/freetype/src/gxvalid/gxvalid.h new file mode 100644 index 0000000..a83408b --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvalid.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * + * gxvalid.h + * + * TrueTypeGX/AAT table validation (specification only). + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVALID_H_ +#define GXVALID_H_ + +#include + +#include "gxverror.h" /* must come before `ftvalid.h' */ + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + gxv_feat_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + + FT_LOCAL( void ) + gxv_bsln_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + + FT_LOCAL( void ) + gxv_trak_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_just_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_morx_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_kern_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_kern_validate_classic( FT_Bytes table, + FT_Face face, + FT_Int dialect_flags, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_opbd_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_prop_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_lcar_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + +FT_END_HEADER + + +#endif /* GXVALID_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvbsln.c b/vendor/freetype/src/gxvalid/gxvbsln.c new file mode 100644 index 0000000..030a64e --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvbsln.c @@ -0,0 +1,334 @@ +/**************************************************************************** + * + * gxvbsln.c + * + * TrueTypeGX/AAT bsln table validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvbsln + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_BSLN_VALUE_COUNT 32 +#define GXV_BSLN_VALUE_EMPTY 0xFFFFU + + + typedef struct GXV_bsln_DataRec_ + { + FT_Bytes ctlPoints_p; + FT_UShort defaultBaseline; + + } GXV_bsln_DataRec, *GXV_bsln_Data; + + +#define GXV_BSLN_DATA( field ) GXV_TABLE_DATA( bsln, field ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_bsln_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UShort v = value_p->u; + FT_UShort* ctlPoints; + + FT_UNUSED( glyph ); + + + GXV_NAME_ENTER( "lookup value" ); + + if ( v >= GXV_BSLN_VALUE_COUNT ) + FT_INVALID_DATA; + + ctlPoints = (FT_UShort*)GXV_BSLN_DATA( ctlPoints_p ); + if ( ctlPoints && ctlPoints[v] == GXV_BSLN_VALUE_EMPTY ) + FT_INVALID_DATA; + + GXV_EXIT; + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + ... | + | + 16bit value array | + +===============+ | + | value | <-------+ + ... + */ + + static GXV_LookupValueDesc + gxv_bsln_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range ? */ + offset = (FT_UShort)( base_value_p->u + + ( relative_gindex * sizeof ( FT_UShort ) ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + GXV_LIMIT_CHECK( 2 ); + + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + static void + gxv_bsln_parts_fmt0_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 0" ); + + /* deltas */ + GXV_LIMIT_CHECK( 2 * GXV_BSLN_VALUE_COUNT ); + + gxvalid->table_data = NULL; /* No ctlPoints here. */ + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt1_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 1" ); + + /* deltas */ + gxv_bsln_parts_fmt0_validate( p, limit, gxvalid ); + + /* mappingData */ + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_bsln_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit; + gxv_LookupTable_validate( p + 2 * GXV_BSLN_VALUE_COUNT, + limit, + gxvalid ); + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt2_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = tables; + + FT_UShort stdGlyph; + FT_UShort ctlPoint; + FT_Int i; + + FT_UShort defaultBaseline = GXV_BSLN_DATA( defaultBaseline ); + + + GXV_NAME_ENTER( "parts format 2" ); + + GXV_LIMIT_CHECK( 2 + ( 2 * GXV_BSLN_VALUE_COUNT ) ); + + /* stdGlyph */ + stdGlyph = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (stdGlyph = %u)\n", stdGlyph )); + + gxv_glyphid_validate( stdGlyph, gxvalid ); + + /* Record the position of ctlPoints */ + GXV_BSLN_DATA( ctlPoints_p ) = p; + + /* ctlPoints */ + for ( i = 0; i < GXV_BSLN_VALUE_COUNT; i++ ) + { + ctlPoint = FT_NEXT_USHORT( p ); + if ( ctlPoint == GXV_BSLN_VALUE_EMPTY ) + { + if ( i == defaultBaseline ) + FT_INVALID_DATA; + } + else + gxv_ctlPoint_validate( stdGlyph, ctlPoint, gxvalid ); + } + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt3_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 3" ); + + /* stdGlyph + ctlPoints */ + gxv_bsln_parts_fmt2_validate( p, limit, gxvalid ); + + /* mappingData */ + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_bsln_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit; + gxv_LookupTable_validate( p + ( 2 + 2 * GXV_BSLN_VALUE_COUNT ), + limit, + gxvalid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** bsln TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_bsln_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_bsln_DataRec bslnrec; + GXV_bsln_Data bsln = &bslnrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong version; + FT_UShort format; + FT_UShort defaultBaseline; + + GXV_Validate_Func fmt_funcs_table [] = + { + gxv_bsln_parts_fmt0_validate, + gxv_bsln_parts_fmt1_validate, + gxv_bsln_parts_fmt2_validate, + gxv_bsln_parts_fmt3_validate, + }; + + + gxvalid->root = ftvalid; + gxvalid->table_data = bsln; + gxvalid->face = face; + + FT_TRACE3(( "validating `bsln' table\n" )); + GXV_INIT; + + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + defaultBaseline = FT_NEXT_USHORT( p ); + + /* only version 1.0 is defined (1996) */ + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* only format 1, 2, 3 are defined (1996) */ + GXV_TRACE(( " (format = %d)\n", format )); + if ( format > 3 ) + FT_INVALID_FORMAT; + + if ( defaultBaseline > 31 ) + FT_INVALID_FORMAT; + + bsln->defaultBaseline = defaultBaseline; + + fmt_funcs_table[format]( p, limit, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* arch-tag: ebe81143-fdaa-4c68-a4d1-b57227daa3bc + (do not change this comment) */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvcommn.c b/vendor/freetype/src/gxvalid/gxvcommn.c new file mode 100644 index 0000000..7f90874 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvcommn.c @@ -0,0 +1,1747 @@ +/**************************************************************************** + * + * gxvcommn.c + * + * TrueTypeGX/AAT common tables validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvcommon + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 16bit offset sorter *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_COMPARE_DEF( int ) + gxv_compare_ushort_offset( const void* a, + const void* b ) + { + return *(FT_UShort*)a - *(FT_UShort*)b; + } + + + FT_LOCAL_DEF( void ) + gxv_set_length_by_ushort_offset( FT_UShort* offset, + FT_UShort** length, + FT_UShort* buff, + FT_UInt nmemb, + FT_UShort limit, + GXV_Validator gxvalid ) + { + FT_UInt i; + + + for ( i = 0; i < nmemb; i++ ) + *(length[i]) = 0; + + for ( i = 0; i < nmemb; i++ ) + buff[i] = offset[i]; + buff[nmemb] = limit; + + ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ), + gxv_compare_ushort_offset ); + + if ( buff[nmemb] > limit ) + FT_INVALID_OFFSET; + + for ( i = 0; i < nmemb; i++ ) + { + FT_UInt j; + + + for ( j = 0; j < nmemb; j++ ) + if ( buff[j] == offset[i] ) + break; + + if ( j == nmemb ) + FT_INVALID_OFFSET; + + *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] ); + + if ( 0 != offset[i] && 0 == *(length[i]) ) + FT_INVALID_OFFSET; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 32bit offset sorter *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_COMPARE_DEF( int ) + gxv_compare_ulong_offset( const void* a, + const void* b ) + { + FT_ULong a_ = *(FT_ULong*)a; + FT_ULong b_ = *(FT_ULong*)b; + + + if ( a_ < b_ ) + return -1; + else if ( a_ > b_ ) + return 1; + else + return 0; + } + + + FT_LOCAL_DEF( void ) + gxv_set_length_by_ulong_offset( FT_ULong* offset, + FT_ULong** length, + FT_ULong* buff, + FT_UInt nmemb, + FT_ULong limit, + GXV_Validator gxvalid) + { + FT_UInt i; + + + for ( i = 0; i < nmemb; i++ ) + *(length[i]) = 0; + + for ( i = 0; i < nmemb; i++ ) + buff[i] = offset[i]; + buff[nmemb] = limit; + + ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ), + gxv_compare_ulong_offset ); + + if ( buff[nmemb] > limit ) + FT_INVALID_OFFSET; + + for ( i = 0; i < nmemb; i++ ) + { + FT_UInt j; + + + for ( j = 0; j < nmemb; j++ ) + if ( buff[j] == offset[i] ) + break; + + if ( j == nmemb ) + FT_INVALID_OFFSET; + + *(length[i]) = buff[j + 1] - buff[j]; + + if ( 0 != offset[i] && 0 == *(length[i]) ) + FT_INVALID_OFFSET; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** scan value array and get min & max *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + gxv_array_getlimits_byte( FT_Bytes table, + FT_Bytes limit, + FT_Byte* min, + FT_Byte* max, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + *min = 0xFF; + *max = 0x00; + + while ( p < limit ) + { + FT_Byte val; + + + GXV_LIMIT_CHECK( 1 ); + val = FT_NEXT_BYTE( p ); + + *min = (FT_Byte)FT_MIN( *min, val ); + *max = (FT_Byte)FT_MAX( *max, val ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + FT_LOCAL_DEF( void ) + gxv_array_getlimits_ushort( FT_Bytes table, + FT_Bytes limit, + FT_UShort* min, + FT_UShort* max, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + *min = 0xFFFFU; + *max = 0x0000; + + while ( p < limit ) + { + FT_UShort val; + + + GXV_LIMIT_CHECK( 2 ); + val = FT_NEXT_USHORT( p ); + + *min = (FT_Byte)FT_MIN( *min, val ); + *max = (FT_Byte)FT_MAX( *max, val ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BINSEARCHHEADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_BinSrchHeader_ + { + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort searchRange; + FT_UShort entrySelector; + FT_UShort rangeShift; + + } GXV_BinSrchHeader; + + + static void + gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader, + GXV_Validator gxvalid ) + { + FT_UShort searchRange; + FT_UShort entrySelector; + FT_UShort rangeShift; + + + if ( binSrchHeader->unitSize == 0 ) + FT_INVALID_DATA; + + if ( binSrchHeader->nUnits == 0 ) + { + if ( binSrchHeader->searchRange == 0 && + binSrchHeader->entrySelector == 0 && + binSrchHeader->rangeShift == 0 ) + return; + else + FT_INVALID_DATA; + } + + for ( searchRange = 1, entrySelector = 1; + ( searchRange * 2 ) <= binSrchHeader->nUnits && + searchRange < 0x8000U; + searchRange *= 2, entrySelector++ ) + ; + + entrySelector--; + searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize ); + rangeShift = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize + - searchRange ); + + if ( searchRange != binSrchHeader->searchRange || + entrySelector != binSrchHeader->entrySelector || + rangeShift != binSrchHeader->rangeShift ) + { + GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" )); + GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, " + "searchRange=%d, entrySelector=%d, " + "rangeShift=%d\n", + binSrchHeader->unitSize, binSrchHeader->nUnits, + binSrchHeader->searchRange, binSrchHeader->entrySelector, + binSrchHeader->rangeShift )); + GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, " + "searchRange=%d, entrySelector=%d, " + "rangeShift=%d\n", + binSrchHeader->unitSize, binSrchHeader->nUnits, + searchRange, entrySelector, rangeShift )); + + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + } + + + /* + * parser & validator of BinSrchHeader + * which is used in LookupTable format 2, 4, 6. + * + * Essential parameters (unitSize, nUnits) are returned by + * given pointer, others (searchRange, entrySelector, rangeShift) + * can be calculated by essential parameters, so they are just + * validated and discarded. + * + * However, wrong values in searchRange, entrySelector, rangeShift + * won't cause fatal errors, because these parameters might be + * only used in old m68k font driver in MacOS. + * -- suzuki toshiya + */ + + FT_LOCAL_DEF( void ) + gxv_BinSrchHeader_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort* unitSize_p, + FT_UShort* nUnits_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_BinSrchHeader binSrchHeader; + + + GXV_NAME_ENTER( "BinSrchHeader validate" ); + + if ( *unitSize_p == 0 ) + { + GXV_LIMIT_CHECK( 2 ); + binSrchHeader.unitSize = FT_NEXT_USHORT( p ); + } + else + binSrchHeader.unitSize = *unitSize_p; + + if ( *nUnits_p == 0 ) + { + GXV_LIMIT_CHECK( 2 ); + binSrchHeader.nUnits = FT_NEXT_USHORT( p ); + } + else + binSrchHeader.nUnits = *nUnits_p; + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + binSrchHeader.searchRange = FT_NEXT_USHORT( p ); + binSrchHeader.entrySelector = FT_NEXT_USHORT( p ); + binSrchHeader.rangeShift = FT_NEXT_USHORT( p ); + GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits )); + + gxv_BinSrchHeader_check_consistency( &binSrchHeader, gxvalid ); + + if ( *unitSize_p == 0 ) + *unitSize_p = binSrchHeader.unitSize; + + if ( *nUnits_p == 0 ) + *nUnits_p = binSrchHeader.nUnits; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC ) \ + ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) ) + + static GXV_LookupValueDesc + gxv_lookup_value_load( FT_Bytes p, + GXV_LookupValue_SignSpec signspec ) + { + GXV_LookupValueDesc v; + + + if ( signspec == GXV_LOOKUPVALUE_UNSIGNED ) + v.u = FT_NEXT_USHORT( p ); + else + v.s = FT_NEXT_SHORT( p ); + + return v; + } + + +#define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \ + FT_BEGIN_STMNT \ + if ( UNITSIZE != CORRECTSIZE ) \ + { \ + FT_ERROR(( "unitSize=%d differs from" \ + " expected unitSize=%d" \ + " in LookupTable %s\n", \ + UNITSIZE, CORRECTSIZE, FORMAT )); \ + if ( UNITSIZE != 0 && NUNITS != 0 ) \ + { \ + FT_ERROR(( " cannot validate anymore\n" )); \ + FT_INVALID_FORMAT; \ + } \ + else \ + FT_ERROR(( " forcibly continues\n" )); \ + } \ + FT_END_STMNT + + + /* ================= Simple Array Format 0 Lookup Table ================ */ + static void + gxv_LookupTable_fmt0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 0" ); + + GXV_LIMIT_CHECK( 2 * gxvalid->face->num_glyphs ); + + for ( i = 0; i < gxvalid->face->num_glyphs; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + if ( p + 2 >= limit ) /* some fonts have too-short fmt0 array */ + { + GXV_TRACE(( "too short, glyphs %d - %ld are missing\n", + i, gxvalid->face->num_glyphs )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + break; + } + + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + gxvalid->lookupval_func( i, &value, gxvalid ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Segment Single Format 2 Lookup Table ============== */ + /* + * Apple spec says: + * + * To guarantee that a binary search terminates, you must include one or + * more special `end of search table' values at the end of the data to + * be searched. The number of termination values that need to be + * included is table-specific. The value that indicates binary search + * termination is 0xFFFF. + * + * The problem is that nUnits does not include this end-marker. It's + * quite difficult to discriminate whether the following 0xFFFF comes from + * the end-marker or some next data. + * + * -- suzuki toshiya + */ + static void + gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table, + FT_UShort unitSize, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + while ( ( p + 4 ) < gxvalid->root->limit ) + { + if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */ + p[2] != 0xFF || p[3] != 0xFF ) /* firstGlyph */ + break; + p += unitSize; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_LookupTable_fmt2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort gid; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort unit; + FT_UShort lastGlyph; + FT_UShort firstGlyph; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 2" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid ); + p += gxvalid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 ); + + for ( unit = 0, gid = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + lastGlyph = FT_NEXT_USHORT( p ); + firstGlyph = FT_NEXT_USHORT( p ); + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( lastGlyph, gxvalid ); + + if ( lastGlyph < gid ) + { + GXV_TRACE(( "reverse ordered segment specification:" + " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", + unit, lastGlyph, unit - 1 , gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + if ( lastGlyph < firstGlyph ) + { + GXV_TRACE(( "reverse ordered range specification at unit %d:" + " lastGlyph %d < firstGlyph %d ", + unit, lastGlyph, firstGlyph )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + + if ( gxvalid->root->level == FT_VALIDATE_TIGHT ) + continue; /* ftxvalidator silently skips such an entry */ + + FT_TRACE4(( "continuing with exchanged values\n" )); + gid = firstGlyph; + firstGlyph = lastGlyph; + lastGlyph = gid; + } + + for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) + gxvalid->lookupval_func( gid, &value, gxvalid ); + } + + gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Segment Array Format 4 Lookup Table =============== */ + static void + gxv_LookupTable_fmt4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort unit; + FT_UShort gid; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort lastGlyph; + FT_UShort firstGlyph; + GXV_LookupValueDesc base_value; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 4" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid ); + p += gxvalid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 ); + + for ( unit = 0, gid = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 ); + lastGlyph = FT_NEXT_USHORT( p ); + firstGlyph = FT_NEXT_USHORT( p ); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( lastGlyph, gxvalid ); + + if ( lastGlyph < gid ) + { + GXV_TRACE(( "reverse ordered segment specification:" + " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", + unit, lastGlyph, unit - 1 , gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + if ( lastGlyph < firstGlyph ) + { + GXV_TRACE(( "reverse ordered range specification at unit %d:" + " lastGlyph %d < firstGlyph %d ", + unit, lastGlyph, firstGlyph )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + + if ( gxvalid->root->level == FT_VALIDATE_TIGHT ) + continue; /* ftxvalidator silently skips such an entry */ + + FT_TRACE4(( "continuing with exchanged values\n" )); + gid = firstGlyph; + firstGlyph = lastGlyph; + lastGlyph = gid; + } + + GXV_LIMIT_CHECK( 2 ); + base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED ); + + for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) + { + value = gxvalid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ), + &base_value, + limit, + gxvalid ); + + gxvalid->lookupval_func( gid, &value, gxvalid ); + } + } + + gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Segment Table Format 6 Lookup Table =============== */ + static void + gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table, + FT_UShort unitSize, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + while ( p < gxvalid->root->limit ) + { + if ( p[0] != 0xFF || p[1] != 0xFF ) + break; + p += unitSize; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_LookupTable_fmt6_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort unit; + FT_UShort prev_glyph; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort glyph; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 6" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid ); + p += gxvalid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 ); + + for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 ); + glyph = FT_NEXT_USHORT( p ); + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + + if ( gxv_glyphid_validate( glyph, gxvalid ) ) + GXV_TRACE(( " endmarker found within defined range" + " (entry %d < nUnits=%d)\n", + unit, nUnits )); + + if ( prev_glyph > glyph ) + { + GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n", + glyph, prev_glyph )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + prev_glyph = glyph; + + gxvalid->lookupval_func( glyph, &value, gxvalid ); + } + + gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Trimmed Array Format 8 Lookup Table =============== */ + static void + gxv_LookupTable_fmt8_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_LookupValueDesc value; + FT_UShort firstGlyph; + FT_UShort glyphCount; + + + GXV_NAME_ENTER( "LookupTable format 8" ); + + /* firstGlyph + glyphCount */ + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + glyphCount = FT_NEXT_USHORT( p ); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), gxvalid ); + + /* valueArray */ + for ( i = 0; i < glyphCount; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + gxvalid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, gxvalid ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_LookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort format; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_LookupTable_fmt0_validate, /* 0 */ + NULL, /* 1 */ + gxv_LookupTable_fmt2_validate, /* 2 */ + NULL, /* 3 */ + gxv_LookupTable_fmt4_validate, /* 4 */ + NULL, /* 5 */ + gxv_LookupTable_fmt6_validate, /* 6 */ + NULL, /* 7 */ + gxv_LookupTable_fmt8_validate, /* 8 */ + }; + + GXV_Validate_Func func; + + + GXV_NAME_ENTER( "LookupTable" ); + + /* lookuptbl_head may be used in fmt4 transit function. */ + gxvalid->lookuptbl_head = table; + + /* format */ + GXV_LIMIT_CHECK( 2 ); + format = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (format %d)\n", format )); + + if ( format > 8 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[format]; + if ( !func ) + FT_INVALID_FORMAT; + + func( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Glyph ID *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Int ) + gxv_glyphid_validate( FT_UShort gid, + GXV_Validator gxvalid ) + { + FT_Face face; + + + if ( gid == 0xFFFFU ) + { + GXV_EXIT; + return 1; + } + + face = gxvalid->face; + if ( face->num_glyphs < gid ) + { + GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %ld < %d\n", + face->num_glyphs, gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + return 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CONTROL POINT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_ctlPoint_validate( FT_UShort gid, + FT_UShort ctl_point, + GXV_Validator gxvalid ) + { + FT_Face face; + FT_Error error; + + FT_GlyphSlot glyph; + FT_Outline outline; + FT_UShort n_points; + + + face = gxvalid->face; + + error = FT_Load_Glyph( face, + gid, + FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM ); + if ( error ) + FT_INVALID_GLYPH_ID; + + glyph = face->glyph; + outline = glyph->outline; + n_points = (FT_UShort)outline.n_points; + + if ( !( ctl_point < n_points ) ) + FT_INVALID_DATA; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SFNT NAME *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_sfntName_validate( FT_UShort name_index, + FT_UShort min_index, + FT_UShort max_index, + GXV_Validator gxvalid ) + { + FT_SfntName name; + FT_UInt i; + FT_UInt nnames; + + + GXV_NAME_ENTER( "sfntName" ); + + if ( name_index < min_index || max_index < name_index ) + FT_INVALID_FORMAT; + + nnames = FT_Get_Sfnt_Name_Count( gxvalid->face ); + for ( i = 0; i < nnames; i++ ) + { + if ( FT_Get_Sfnt_Name( gxvalid->face, i, &name ) != FT_Err_Ok ) + continue; + + if ( name.name_id == name_index ) + goto Out; + } + + GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index )); + FT_INVALID_DATA; + goto Exit; /* make compiler happy */ + + Out: + FT_TRACE1(( " nameIndex = %d (", name_index )); + GXV_TRACE_HEXDUMP_SFNTNAME( name ); + FT_TRACE1(( ")\n" )); + + Exit: + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STATE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* -------------------------- Class Table --------------------------- */ + + /* + * highestClass specifies how many classes are defined in this + * Class Subtable. Apple spec does not mention whether undefined + * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used) + * are permitted. At present, holes in a defined class are not checked. + * -- suzuki toshiya + */ + + static void + gxv_ClassTable_validate( FT_Bytes table, + FT_UShort* length_p, + FT_UShort stateSize, + FT_Byte* maxClassID_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort firstGlyph; + FT_UShort nGlyphs; + + + GXV_NAME_ENTER( "ClassTable" ); + + *maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */ + + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + nGlyphs = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs )); + + if ( !nGlyphs ) + goto Out; + + gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), gxvalid ); + + { + FT_Byte nGlyphInClass[256]; + FT_Byte classID; + FT_UShort i; + + + FT_MEM_ZERO( nGlyphInClass, 256 ); + + + for ( i = 0; i < nGlyphs; i++ ) + { + GXV_LIMIT_CHECK( 1 ); + classID = FT_NEXT_BYTE( p ); + switch ( classID ) + { + /* following classes should not appear in class array */ + case 0: /* end of text */ + case 2: /* out of bounds */ + case 3: /* end of line */ + FT_INVALID_DATA; + break; + + case 1: /* out of bounds */ + default: /* user-defined: 4 - ( stateSize - 1 ) */ + if ( classID >= stateSize ) + FT_INVALID_DATA; /* assign glyph to undefined state */ + + nGlyphInClass[classID]++; + break; + } + } + *length_p = (FT_UShort)( p - table ); + + /* scan max ClassID in use */ + for ( i = 0; i < stateSize; i++ ) + if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) ) + *maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */ + } + + Out: + GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n", + stateSize, *maxClassID_p )); + GXV_EXIT; + } + + + /* --------------------------- State Array ----------------------------- */ + + static void + gxv_StateArray_validate( FT_Bytes table, + FT_UShort* length_p, + FT_Byte maxClassID, + FT_UShort stateSize, + FT_Byte* maxState_p, + FT_Byte* maxEntry_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_Byte clazz; + FT_Byte entry; + + FT_UNUSED( stateSize ); /* for the non-debugging case */ + + + GXV_NAME_ENTER( "StateArray" ); + + GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n", + (int)( *length_p ), stateSize, (int)maxClassID )); + + /* + * 2 states are predefined and must be described in StateArray: + * state 0 (start of text), 1 (start of line) + */ + GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 ); + + *maxState_p = 0; + *maxEntry_p = 0; + + /* read if enough to read another state */ + while ( p + ( 1 + maxClassID ) <= limit ) + { + (*maxState_p)++; + for ( clazz = 0; clazz <= maxClassID; clazz++ ) + { + entry = FT_NEXT_BYTE( p ); + *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry ); + } + } + GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", + *maxState_p, *maxEntry_p )); + + *length_p = (FT_UShort)( p - table ); + + GXV_EXIT; + } + + + /* --------------------------- Entry Table ----------------------------- */ + + static void + gxv_EntryTable_validate( FT_Bytes table, + FT_UShort* length_p, + FT_Byte maxEntry, + FT_UShort stateArray, + FT_UShort stateArray_length, + FT_Byte maxClassID, + FT_Bytes statetable_table, + FT_Bytes statetable_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_Byte entry; + FT_Byte state; + FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable ); + + GXV_XStateTable_GlyphOffsetDesc glyphOffset; + + + GXV_NAME_ENTER( "EntryTable" ); + + GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); + + if ( ( maxEntry + 1 ) * entrySize > *length_p ) + { + GXV_SET_ERR_IF_PARANOID( FT_INVALID_TOO_SHORT ); + + /* ftxvalidator and FontValidator both warn and continue */ + maxEntry = (FT_Byte)( *length_p / entrySize - 1 ); + GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n", + maxEntry )); + } + + for ( entry = 0; entry <= maxEntry; entry++ ) + { + FT_UShort newState; + FT_UShort flags; + + + GXV_LIMIT_CHECK( 2 + 2 ); + newState = FT_NEXT_USHORT( p ); + flags = FT_NEXT_USHORT( p ); + + + if ( newState < stateArray || + stateArray + stateArray_length < newState ) + { + GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n", + newState )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + continue; + } + + if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) ) + { + GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n", + newState, 1 + maxClassID )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + continue; + } + + state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) ); + + switch ( GXV_GLYPHOFFSET_FMT( statetable ) ) + { + case GXV_GLYPHOFFSET_NONE: + glyphOffset.uc = 0; /* make compiler happy */ + break; + + case GXV_GLYPHOFFSET_UCHAR: + glyphOffset.uc = FT_NEXT_BYTE( p ); + break; + + case GXV_GLYPHOFFSET_CHAR: + glyphOffset.c = FT_NEXT_CHAR( p ); + break; + + case GXV_GLYPHOFFSET_USHORT: + glyphOffset.u = FT_NEXT_USHORT( p ); + break; + + case GXV_GLYPHOFFSET_SHORT: + glyphOffset.s = FT_NEXT_SHORT( p ); + break; + + case GXV_GLYPHOFFSET_ULONG: + glyphOffset.ul = FT_NEXT_ULONG( p ); + break; + + case GXV_GLYPHOFFSET_LONG: + glyphOffset.l = FT_NEXT_LONG( p ); + break; + } + + if ( gxvalid->statetable.entry_validate_func ) + gxvalid->statetable.entry_validate_func( state, + flags, + &glyphOffset, + statetable_table, + statetable_limit, + gxvalid ); + } + + *length_p = (FT_UShort)( p - table ); + + GXV_EXIT; + } + + + /* =========================== State Table ============================= */ + + FT_LOCAL_DEF( void ) + gxv_StateTable_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[3]; + FT_UShort* l[3]; + FT_UShort buff[4]; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + + gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, gxvalid ); + } + + + FT_LOCAL_DEF( void ) + gxv_StateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_UShort stateSize; + FT_UShort classTable; /* offset to Class(Sub)Table */ + FT_UShort stateArray; /* offset to StateArray */ + FT_UShort entryTable; /* offset to EntryTable */ + + FT_UShort classTable_length; + FT_UShort stateArray_length; + FT_UShort entryTable_length; + FT_Byte maxClassID; + FT_Byte maxState; + FT_Byte maxEntry; + + GXV_StateTable_Subtable_Setup_Func setup_func; + + FT_Bytes p = table; + + + GXV_NAME_ENTER( "StateTable" ); + + GXV_TRACE(( "StateTable header\n" )); + + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + stateSize = FT_NEXT_USHORT( p ); + classTable = FT_NEXT_USHORT( p ); + stateArray = FT_NEXT_USHORT( p ); + entryTable = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "stateSize=0x%04x\n", stateSize )); + GXV_TRACE(( "offset to classTable=0x%04x\n", classTable )); + GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray )); + GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable )); + + if ( stateSize > 0xFF ) + FT_INVALID_DATA; + + if ( gxvalid->statetable.optdata_load_func ) + gxvalid->statetable.optdata_load_func( p, limit, gxvalid ); + + if ( gxvalid->statetable.subtable_setup_func ) + setup_func = gxvalid->statetable.subtable_setup_func; + else + setup_func = gxv_StateTable_subtable_setup; + + setup_func( (FT_UShort)( limit - table ), + classTable, + stateArray, + entryTable, + &classTable_length, + &stateArray_length, + &entryTable_length, + gxvalid ); + + GXV_TRACE(( "StateTable Subtables\n" )); + + if ( classTable != 0 ) + gxv_ClassTable_validate( table + classTable, + &classTable_length, + stateSize, + &maxClassID, + gxvalid ); + else + maxClassID = (FT_Byte)( stateSize - 1 ); + + if ( stateArray != 0 ) + gxv_StateArray_validate( table + stateArray, + &stateArray_length, + maxClassID, + stateSize, + &maxState, + &maxEntry, + gxvalid ); + else + { +#if 0 + maxState = 1; /* 0:start of text, 1:start of line are predefined */ +#endif + maxEntry = 0; + } + + if ( maxEntry > 0 && entryTable == 0 ) + FT_INVALID_OFFSET; + + if ( entryTable != 0 ) + gxv_EntryTable_validate( table + entryTable, + &entryTable_length, + maxEntry, + stateArray, + stateArray_length, + maxClassID, + table, + limit, + gxvalid ); + + GXV_EXIT; + } + + + /* ================= eXtended State Table (for morx) =================== */ + + FT_LOCAL_DEF( void ) + gxv_XStateTable_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[3]; + FT_ULong* l[3]; + FT_ULong buff[4]; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + + gxv_set_length_by_ulong_offset( o, l, buff, 3, table_size, gxvalid ); + } + + + static void + gxv_XClassTable_lookupval_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + if ( value_p->u >= gxvalid->xstatetable.nClasses ) + FT_INVALID_DATA; + if ( value_p->u > gxvalid->xstatetable.maxClassID ) + gxvalid->xstatetable.maxClassID = value_p->u; + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 16bit value array | + +===============+ | + | value | <-------+ + .... + */ + static GXV_LookupValueDesc + gxv_XClassTable_lookupfmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + static void + gxv_XStateArray_validate( FT_Bytes table, + FT_ULong* length_p, + FT_UShort maxClassID, + FT_ULong stateSize, + FT_UShort* maxState_p, + FT_UShort* maxEntry_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort clazz; + FT_UShort entry; + + FT_UNUSED( stateSize ); /* for the non-debugging case */ + + + GXV_NAME_ENTER( "XStateArray" ); + + GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n", + (int)( *length_p ), (int)stateSize, (int)maxClassID )); + + /* + * 2 states are predefined and must be described: + * state 0 (start of text), 1 (start of line) + */ + GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 ); + + *maxState_p = 0; + *maxEntry_p = 0; + + /* read if enough to read another state */ + while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit ) + { + (*maxState_p)++; + for ( clazz = 0; clazz <= maxClassID; clazz++ ) + { + entry = FT_NEXT_USHORT( p ); + *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry ); + } + } + GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", + *maxState_p, *maxEntry_p )); + + *length_p = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_XEntryTable_validate( FT_Bytes table, + FT_ULong* length_p, + FT_UShort maxEntry, + FT_ULong stateArray_length, + FT_UShort maxClassID, + FT_Bytes xstatetable_table, + FT_Bytes xstatetable_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort entry; + FT_UShort state; + FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable ); + + + GXV_NAME_ENTER( "XEntryTable" ); + GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); + + if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit ) + FT_INVALID_TOO_SHORT; + + for (entry = 0; entry <= maxEntry; entry++ ) + { + FT_UShort newState_idx; + FT_UShort flags; + GXV_XStateTable_GlyphOffsetDesc glyphOffset; + + + GXV_LIMIT_CHECK( 2 + 2 ); + newState_idx = FT_NEXT_USHORT( p ); + flags = FT_NEXT_USHORT( p ); + + if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) ) + { + GXV_TRACE(( " newState index 0x%04x points out of stateArray\n", + newState_idx )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + + state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) ); + if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) ) + { + FT_TRACE4(( "-> new state = %d (supposed)\n", + state )); + FT_TRACE4(( "but newState index 0x%04x" + " is not aligned to %d-classes\n", + newState_idx, 1 + maxClassID )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + + switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) ) + { + case GXV_GLYPHOFFSET_NONE: + glyphOffset.uc = 0; /* make compiler happy */ + break; + + case GXV_GLYPHOFFSET_UCHAR: + glyphOffset.uc = FT_NEXT_BYTE( p ); + break; + + case GXV_GLYPHOFFSET_CHAR: + glyphOffset.c = FT_NEXT_CHAR( p ); + break; + + case GXV_GLYPHOFFSET_USHORT: + glyphOffset.u = FT_NEXT_USHORT( p ); + break; + + case GXV_GLYPHOFFSET_SHORT: + glyphOffset.s = FT_NEXT_SHORT( p ); + break; + + case GXV_GLYPHOFFSET_ULONG: + glyphOffset.ul = FT_NEXT_ULONG( p ); + break; + + case GXV_GLYPHOFFSET_LONG: + glyphOffset.l = FT_NEXT_LONG( p ); + break; + + default: + GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); + goto Exit; + } + + if ( gxvalid->xstatetable.entry_validate_func ) + gxvalid->xstatetable.entry_validate_func( state, + flags, + &glyphOffset, + xstatetable_table, + xstatetable_limit, + gxvalid ); + } + + Exit: + *length_p = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_XStateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + /* StateHeader members */ + FT_ULong classTable; /* offset to Class(Sub)Table */ + FT_ULong stateArray; /* offset to StateArray */ + FT_ULong entryTable; /* offset to EntryTable */ + + FT_ULong classTable_length; + FT_ULong stateArray_length; + FT_ULong entryTable_length; + FT_UShort maxState; + FT_UShort maxEntry; + + GXV_XStateTable_Subtable_Setup_Func setup_func; + + FT_Bytes p = table; + + + GXV_NAME_ENTER( "XStateTable" ); + + GXV_TRACE(( "XStateTable header\n" )); + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); + gxvalid->xstatetable.nClasses = FT_NEXT_ULONG( p ); + classTable = FT_NEXT_ULONG( p ); + stateArray = FT_NEXT_ULONG( p ); + entryTable = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "nClasses =0x%08lx\n", gxvalid->xstatetable.nClasses )); + GXV_TRACE(( "offset to classTable=0x%08lx\n", classTable )); + GXV_TRACE(( "offset to stateArray=0x%08lx\n", stateArray )); + GXV_TRACE(( "offset to entryTable=0x%08lx\n", entryTable )); + + if ( gxvalid->xstatetable.nClasses > 0xFFFFU ) + FT_INVALID_DATA; + + GXV_TRACE(( "StateTable Subtables\n" )); + + if ( gxvalid->xstatetable.optdata_load_func ) + gxvalid->xstatetable.optdata_load_func( p, limit, gxvalid ); + + if ( gxvalid->xstatetable.subtable_setup_func ) + setup_func = gxvalid->xstatetable.subtable_setup_func; + else + setup_func = gxv_XStateTable_subtable_setup; + + setup_func( (FT_ULong)( limit - table ), + classTable, + stateArray, + entryTable, + &classTable_length, + &stateArray_length, + &entryTable_length, + gxvalid ); + + if ( classTable != 0 ) + { + gxvalid->xstatetable.maxClassID = 0; + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_XClassTable_lookupval_validate; + gxvalid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit; + gxv_LookupTable_validate( table + classTable, + table + classTable + classTable_length, + gxvalid ); +#if 0 + if ( gxvalid->subtable_length < classTable_length ) + classTable_length = gxvalid->subtable_length; +#endif + } + else + { + /* XXX: check range? */ + gxvalid->xstatetable.maxClassID = + (FT_UShort)( gxvalid->xstatetable.nClasses - 1 ); + } + + if ( stateArray != 0 ) + gxv_XStateArray_validate( table + stateArray, + &stateArray_length, + gxvalid->xstatetable.maxClassID, + gxvalid->xstatetable.nClasses, + &maxState, + &maxEntry, + gxvalid ); + else + { +#if 0 + maxState = 1; /* 0:start of text, 1:start of line are predefined */ +#endif + maxEntry = 0; + } + + if ( maxEntry > 0 && entryTable == 0 ) + FT_INVALID_OFFSET; + + if ( entryTable != 0 ) + gxv_XEntryTable_validate( table + entryTable, + &entryTable_length, + maxEntry, + stateArray_length, + gxvalid->xstatetable.maxClassID, + table, + limit, + gxvalid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Table overlapping *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static int + gxv_compare_ranges( FT_Bytes table1_start, + FT_ULong table1_length, + FT_Bytes table2_start, + FT_ULong table2_length ) + { + if ( table1_start == table2_start ) + { + if ( ( table1_length == 0 || table2_length == 0 ) ) + goto Out; + } + else if ( table1_start < table2_start ) + { + if ( ( table1_start + table1_length ) <= table2_start ) + goto Out; + } + else if ( table1_start > table2_start ) + { + if ( ( table1_start >= table2_start + table2_length ) ) + goto Out; + } + return 1; + + Out: + return 0; + } + + + FT_LOCAL_DEF( void ) + gxv_odtect_add_range( FT_Bytes start, + FT_ULong length, + const FT_String* name, + GXV_odtect_Range odtect ) + { + odtect->range[odtect->nRanges].start = start; + odtect->range[odtect->nRanges].length = length; + odtect->range[odtect->nRanges].name = (FT_String*)name; + odtect->nRanges++; + } + + + FT_LOCAL_DEF( void ) + gxv_odtect_validate( GXV_odtect_Range odtect, + GXV_Validator gxvalid ) + { + FT_UInt i, j; + + + GXV_NAME_ENTER( "check overlap among multi ranges" ); + + for ( i = 0; i < odtect->nRanges; i++ ) + for ( j = 0; j < i; j++ ) + if ( 0 != gxv_compare_ranges( odtect->range[i].start, + odtect->range[i].length, + odtect->range[j].start, + odtect->range[j].length ) ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( odtect->range[i].name || odtect->range[j].name ) + GXV_TRACE(( "found overlap between range %d and range %d\n", + i, j )); + else + GXV_TRACE(( "found overlap between `%s' and `%s\'\n", + odtect->range[i].name, + odtect->range[j].name )); +#endif + FT_INVALID_OFFSET; + } + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvcommn.h b/vendor/freetype/src/gxvalid/gxvcommn.h new file mode 100644 index 0000000..f88d23a --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvcommn.h @@ -0,0 +1,584 @@ +/**************************************************************************** + * + * gxvcommn.h + * + * TrueTypeGX/AAT common tables validation (specification). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + + /* + * keywords in variable naming + * --------------------------- + * table: Of type FT_Bytes, pointing to the start of this table/subtable. + * limit: Of type FT_Bytes, pointing to the end of this table/subtable, + * including padding for alignment. + * offset: Of type FT_UInt, the number of octets from the start to target. + * length: Of type FT_UInt, the number of octets from the start to the + * end in this table/subtable, including padding for alignment. + * + * _MIN, _MAX: Should be added to the tail of macros, as INT_MIN, etc. + */ + + +#ifndef GXVCOMMN_H_ +#define GXVCOMMN_H_ + + +#include "gxvalid.h" +#include +#include + + +FT_BEGIN_HEADER + + + /* some variables are not evaluated or only used in trace */ + +#ifdef FT_DEBUG_LEVEL_TRACE +#define GXV_LOAD_TRACE_VARS +#else +#undef GXV_LOAD_TRACE_VARS +#endif + +#undef GXV_LOAD_UNUSED_VARS /* debug purpose */ + +#define IS_PARANOID_VALIDATION \ + ( gxvalid->root->level >= FT_VALIDATE_PARANOID ) +#define GXV_SET_ERR_IF_PARANOID( err ) \ + do { if ( IS_PARANOID_VALIDATION ) ( err ); } while ( 0 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALIDATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_ValidatorRec_* GXV_Validator; + + +#define DUMMY_LIMIT 0 + + typedef void + (*GXV_Validate_Func)( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + + /* ====================== LookupTable Validator ======================== */ + + typedef union GXV_LookupValueDesc_ + { + FT_UShort u; + FT_Short s; + + } GXV_LookupValueDesc; + + typedef const GXV_LookupValueDesc* GXV_LookupValueCPtr; + + typedef enum GXV_LookupValue_SignSpec_ + { + GXV_LOOKUPVALUE_UNSIGNED = 0, + GXV_LOOKUPVALUE_SIGNED + + } GXV_LookupValue_SignSpec; + + + typedef void + (*GXV_Lookup_Value_Validate_Func)( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ); + + typedef GXV_LookupValueDesc + (*GXV_Lookup_Fmt4_Transit_Func)( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ); + + + /* ====================== StateTable Validator ========================= */ + + typedef enum GXV_GlyphOffset_Format_ + { + GXV_GLYPHOFFSET_NONE = -1, + GXV_GLYPHOFFSET_UCHAR = 2, + GXV_GLYPHOFFSET_CHAR, + GXV_GLYPHOFFSET_USHORT = 4, + GXV_GLYPHOFFSET_SHORT, + GXV_GLYPHOFFSET_ULONG = 8, + GXV_GLYPHOFFSET_LONG + + } GXV_GlyphOffset_Format; + + +#define GXV_GLYPHOFFSET_FMT( table ) \ + ( gxvalid->table.entry_glyphoffset_fmt ) + +#define GXV_GLYPHOFFSET_SIZE( table ) \ + ( gxvalid->table.entry_glyphoffset_fmt / 2 ) + + + /* ----------------------- 16bit StateTable ---------------------------- */ + + typedef union GXV_StateTable_GlyphOffsetDesc_ + { + FT_Byte uc; + FT_UShort u; /* same as GXV_LookupValueDesc */ + FT_ULong ul; + FT_Char c; + FT_Short s; /* same as GXV_LookupValueDesc */ + FT_Long l; + + } GXV_StateTable_GlyphOffsetDesc; + + typedef const GXV_StateTable_GlyphOffsetDesc* GXV_StateTable_GlyphOffsetCPtr; + + typedef void + (*GXV_StateTable_Subtable_Setup_Func)( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ); + + typedef void + (*GXV_StateTable_Entry_Validate_Func)( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes statetable_table, + FT_Bytes statetable_limit, + GXV_Validator gxvalid ); + + typedef void + (*GXV_StateTable_OptData_Load_Func)( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + typedef struct GXV_StateTable_ValidatorRec_ + { + GXV_GlyphOffset_Format entry_glyphoffset_fmt; + void* optdata; + + GXV_StateTable_Subtable_Setup_Func subtable_setup_func; + GXV_StateTable_Entry_Validate_Func entry_validate_func; + GXV_StateTable_OptData_Load_Func optdata_load_func; + + } GXV_StateTable_ValidatorRec, *GXV_StateTable_ValidatorRecData; + + + /* ---------------------- 32bit XStateTable ---------------------------- */ + + typedef GXV_StateTable_GlyphOffsetDesc GXV_XStateTable_GlyphOffsetDesc; + + typedef const GXV_XStateTable_GlyphOffsetDesc* GXV_XStateTable_GlyphOffsetCPtr; + + typedef void + (*GXV_XStateTable_Subtable_Setup_Func)( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ); + + typedef void + (*GXV_XStateTable_Entry_Validate_Func)( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes xstatetable_table, + FT_Bytes xstatetable_limit, + GXV_Validator gxvalid ); + + + typedef GXV_StateTable_OptData_Load_Func GXV_XStateTable_OptData_Load_Func; + + + typedef struct GXV_XStateTable_ValidatorRec_ + { + int entry_glyphoffset_fmt; + void* optdata; + + GXV_XStateTable_Subtable_Setup_Func subtable_setup_func; + GXV_XStateTable_Entry_Validate_Func entry_validate_func; + GXV_XStateTable_OptData_Load_Func optdata_load_func; + + FT_ULong nClasses; + FT_UShort maxClassID; + + } GXV_XStateTable_ValidatorRec, *GXV_XStateTable_ValidatorRecData; + + + /* ===================================================================== */ + + typedef struct GXV_ValidatorRec_ + { + FT_Validator root; + + FT_Face face; + void* table_data; + + FT_ULong subtable_length; + + GXV_LookupValue_SignSpec lookupval_sign; + GXV_Lookup_Value_Validate_Func lookupval_func; + GXV_Lookup_Fmt4_Transit_Func lookupfmt4_trans; + FT_Bytes lookuptbl_head; + + FT_UShort min_gid; + FT_UShort max_gid; + + GXV_StateTable_ValidatorRec statetable; + GXV_XStateTable_ValidatorRec xstatetable; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt debug_indent; + const FT_String* debug_function_name[3]; +#endif + + } GXV_ValidatorRec; + + +#define GXV_TABLE_DATA( tag, field ) \ + ( ( (GXV_ ## tag ## _Data)gxvalid->table_data )->field ) + +#undef FT_INVALID_ +#define FT_INVALID_( _error ) \ + ft_validator_error( gxvalid->root, FT_THROW( _error ) ) + +#define GXV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( p + _count > ( limit? limit : gxvalid->root->limit ) ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define GXV_INIT gxvalid->debug_indent = 0 + +#define GXV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + gxvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", gxvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", name )); \ + FT_END_STMNT + +#define GXV_EXIT gxvalid->debug_indent -= 2 + +#define GXV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", gxvalid->debug_indent, "" )); \ + FT_TRACE4( s ); \ + FT_END_STMNT + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define GXV_INIT do { } while ( 0 ) +#define GXV_NAME_ENTER( name ) do { } while ( 0 ) +#define GXV_EXIT do { } while ( 0 ) + +#define GXV_TRACE( s ) do { } while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 32bit alignment checking *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_32BIT_ALIGNMENT_VALIDATE( a ) \ + FT_BEGIN_STMNT \ + { \ + if ( (a) & 3 ) \ + FT_INVALID_OFFSET; \ + } \ + FT_END_STMNT + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Dumping Binary Data *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_TRACE_HEXDUMP( p, len ) \ + FT_BEGIN_STMNT \ + { \ + FT_Bytes b; \ + \ + \ + for ( b = p; b < (FT_Bytes)p + len; b++ ) \ + FT_TRACE1(("\\x%02x", *b)); \ + } \ + FT_END_STMNT + +#define GXV_TRACE_HEXDUMP_C( p, len ) \ + FT_BEGIN_STMNT \ + { \ + FT_Bytes b; \ + \ + \ + for ( b = p; b < (FT_Bytes)p + len; b++ ) \ + if ( 0x40 < *b && *b < 0x7E ) \ + FT_TRACE1(("%c", *b)); \ + else \ + FT_TRACE1(("\\x%02x", *b)); \ + } \ + FT_END_STMNT + +#define GXV_TRACE_HEXDUMP_SFNTNAME( n ) \ + GXV_TRACE_HEXDUMP( n.string, n.string_len ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_BinSrchHeader_validate( FT_Bytes p, + FT_Bytes limit, + FT_UShort* unitSize_p, + FT_UShort* nUnits_p, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_LookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Glyph ID *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( FT_Int ) + gxv_glyphid_validate( FT_UShort gid, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CONTROL POINT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_ctlPoint_validate( FT_UShort gid, + FT_UShort ctl_point, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SFNT NAME *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_sfntName_validate( FT_UShort name_index, + FT_UShort min_index, + FT_UShort max_index, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STATE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_StateTable_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_XStateTable_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_StateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_XStateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY MACROS AND FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_array_getlimits_byte( FT_Bytes table, + FT_Bytes limit, + FT_Byte* min, + FT_Byte* max, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_array_getlimits_ushort( FT_Bytes table, + FT_Bytes limit, + FT_UShort* min, + FT_UShort* max, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_set_length_by_ushort_offset( FT_UShort* offset, + FT_UShort** length, + FT_UShort* buff, + FT_UInt nmemb, + FT_UShort limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_set_length_by_ulong_offset( FT_ULong* offset, + FT_ULong** length, + FT_ULong* buff, + FT_UInt nmemb, + FT_ULong limit, + GXV_Validator gxvalid); + + +#define GXV_SUBTABLE_OFFSET_CHECK( _offset ) \ + FT_BEGIN_STMNT \ + if ( (_offset) > gxvalid->subtable_length ) \ + FT_INVALID_OFFSET; \ + FT_END_STMNT + +#define GXV_SUBTABLE_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( ( p + (_count) - gxvalid->subtable_start ) > \ + gxvalid->subtable_length ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + +#define GXV_USHORT_TO_SHORT( _us ) \ + ( ( 0x8000U < ( _us ) ) ? ( ( _us ) - 0x8000U ) : ( _us ) ) + +#define GXV_STATETABLE_HEADER_SIZE ( 2 + 2 + 2 + 2 ) +#define GXV_STATEHEADER_SIZE GXV_STATETABLE_HEADER_SIZE + +#define GXV_XSTATETABLE_HEADER_SIZE ( 4 + 4 + 4 + 4 ) +#define GXV_XSTATEHEADER_SIZE GXV_XSTATETABLE_HEADER_SIZE + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Table overlapping *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_odtect_DataRec_ + { + FT_Bytes start; + FT_ULong length; + FT_String* name; + + } GXV_odtect_DataRec, *GXV_odtect_Data; + + typedef struct GXV_odtect_RangeRec_ + { + FT_UInt nRanges; + GXV_odtect_Data range; + + } GXV_odtect_RangeRec, *GXV_odtect_Range; + + + FT_LOCAL( void ) + gxv_odtect_add_range( FT_Bytes start, + FT_ULong length, + const FT_String* name, + GXV_odtect_Range odtect ); + + FT_LOCAL( void ) + gxv_odtect_validate( GXV_odtect_Range odtect, + GXV_Validator gxvalid ); + + +#define GXV_ODTECT( n, odtect ) \ + GXV_odtect_DataRec odtect ## _range[n]; \ + GXV_odtect_RangeRec odtect ## _rec = { 0, NULL }; \ + GXV_odtect_Range odtect = NULL + +#define GXV_ODTECT_INIT( odtect ) \ + FT_BEGIN_STMNT \ + odtect ## _rec.nRanges = 0; \ + odtect ## _rec.range = odtect ## _range; \ + odtect = & odtect ## _rec; \ + FT_END_STMNT + + + /* */ + +FT_END_HEADER + +#endif /* GXVCOMMN_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxverror.h b/vendor/freetype/src/gxvalid/gxverror.h new file mode 100644 index 0000000..09311ed --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxverror.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * gxverror.h + * + * TrueTypeGX/AAT validation module error codes (specification only). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + + /************************************************************************** + * + * This file is used to define the OpenType validation module error + * enumeration constants. + * + */ + +#ifndef GXVERROR_H_ +#define GXVERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX GXV_Err_ +#define FT_ERR_BASE FT_Mod_Err_GXvalid + +#include + +#endif /* GXVERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvfeat.c b/vendor/freetype/src/gxvalid/gxvfeat.c new file mode 100644 index 0000000..6cf1821 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvfeat.c @@ -0,0 +1,339 @@ +/**************************************************************************** + * + * gxvfeat.c + * + * TrueTypeGX/AAT feat table validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" +#include "gxvfeat.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvfeat + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_feat_DataRec_ + { + FT_UInt reserved_size; + FT_UShort feature; + FT_UShort setting; + + } GXV_feat_DataRec, *GXV_feat_Data; + + +#define GXV_FEAT_DATA( field ) GXV_TABLE_DATA( feat, field ) + + + typedef enum GXV_FeatureFlagsMask_ + { + GXV_FEAT_MASK_EXCLUSIVE_SETTINGS = 0x8000U, + GXV_FEAT_MASK_DYNAMIC_DEFAULT = 0x4000, + GXV_FEAT_MASK_UNUSED = 0x3F00, + GXV_FEAT_MASK_DEFAULT_SETTING = 0x00FF + + } GXV_FeatureFlagsMask; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_feat_registry_validate( FT_UShort feature, + FT_UShort nSettings, + FT_Bool exclusive, + GXV_Validator gxvalid ) + { + GXV_NAME_ENTER( "feature in registry" ); + + GXV_TRACE(( " (feature = %u)\n", feature )); + + if ( feature >= gxv_feat_registry_length ) + { + GXV_TRACE(( "feature number %d is out of range %lu\n", + feature, gxv_feat_registry_length )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + goto Exit; + } + + if ( gxv_feat_registry[feature].existence == 0 ) + { + GXV_TRACE(( "feature number %d is in defined range but doesn't exist\n", + feature )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + goto Exit; + } + + if ( gxv_feat_registry[feature].apple_reserved ) + { + /* Don't use here. Apple is reserved. */ + GXV_TRACE(( "feature number %d is reserved by Apple\n", feature )); + if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + if ( nSettings != gxv_feat_registry[feature].nSettings ) + { + GXV_TRACE(( "feature %d: nSettings %d != defined nSettings %d\n", + feature, nSettings, + gxv_feat_registry[feature].nSettings )); + if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + if ( exclusive != gxv_feat_registry[feature].exclusive ) + { + GXV_TRACE(( "exclusive flag %d differs from predefined value\n", + exclusive )); + if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + Exit: + GXV_EXIT; + } + + + static void + gxv_feat_name_index_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + FT_Short nameIndex; + + + GXV_NAME_ENTER( "nameIndex" ); + + GXV_LIMIT_CHECK( 2 ); + nameIndex = FT_NEXT_SHORT ( p ); + GXV_TRACE(( " (nameIndex = %d)\n", nameIndex )); + + gxv_sfntName_validate( (FT_UShort)nameIndex, + 255, + 32768U, + gxvalid ); + + GXV_EXIT; + } + + + static void + gxv_feat_setting_validate( FT_Bytes table, + FT_Bytes limit, + FT_Bool exclusive, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort setting; + + + GXV_NAME_ENTER( "setting" ); + + GXV_LIMIT_CHECK( 2 ); + + setting = FT_NEXT_USHORT( p ); + + /* If we have exclusive setting, the setting should be odd. */ + if ( exclusive && ( setting & 1 ) == 0 ) + FT_INVALID_DATA; + + gxv_feat_name_index_validate( p, limit, gxvalid ); + + GXV_FEAT_DATA( setting ) = setting; + + GXV_EXIT; + } + + + static void + gxv_feat_name_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UInt reserved_size = GXV_FEAT_DATA( reserved_size ); + + FT_UShort feature; + FT_UShort nSettings; + FT_ULong settingTable; + FT_UShort featureFlags; + + FT_Bool exclusive; + FT_Int last_setting; + FT_UInt i; + + + GXV_NAME_ENTER( "name" ); + + /* feature + nSettings + settingTable + featureFlags */ + GXV_LIMIT_CHECK( 2 + 2 + 4 + 2 ); + + feature = FT_NEXT_USHORT( p ); + GXV_FEAT_DATA( feature ) = feature; + + nSettings = FT_NEXT_USHORT( p ); + settingTable = FT_NEXT_ULONG ( p ); + featureFlags = FT_NEXT_USHORT( p ); + + if ( settingTable < reserved_size ) + FT_INVALID_OFFSET; + + if ( ( featureFlags & GXV_FEAT_MASK_UNUSED ) == 0 ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + + exclusive = FT_BOOL( featureFlags & GXV_FEAT_MASK_EXCLUSIVE_SETTINGS ); + if ( exclusive ) + { + FT_Byte dynamic_default; + + + if ( featureFlags & GXV_FEAT_MASK_DYNAMIC_DEFAULT ) + dynamic_default = (FT_Byte)( featureFlags & + GXV_FEAT_MASK_DEFAULT_SETTING ); + else + dynamic_default = 0; + + /* If exclusive, check whether default setting is in the range. */ + if ( !( dynamic_default < nSettings ) ) + FT_INVALID_FORMAT; + } + + gxv_feat_registry_validate( feature, nSettings, exclusive, gxvalid ); + + gxv_feat_name_index_validate( p, limit, gxvalid ); + + p = gxvalid->root->base + settingTable; + for ( last_setting = -1, i = 0; i < nSettings; i++ ) + { + gxv_feat_setting_validate( p, limit, exclusive, gxvalid ); + + if ( (FT_Int)GXV_FEAT_DATA( setting ) <= last_setting ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); + + last_setting = (FT_Int)GXV_FEAT_DATA( setting ); + /* setting + nameIndex */ + p += ( 2 + 2 ); + } + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** feat TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_feat_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_feat_DataRec featrec; + GXV_feat_Data feat = &featrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_UInt featureNameCount; + + FT_UInt i; + FT_Int last_feature; + + + gxvalid->root = ftvalid; + gxvalid->table_data = feat; + gxvalid->face = face; + + FT_TRACE3(( "validating `feat' table\n" )); + GXV_INIT; + + feat->reserved_size = 0; + + /* version + featureNameCount + none_0 + none_1 */ + GXV_LIMIT_CHECK( 4 + 2 + 2 + 4 ); + feat->reserved_size += 4 + 2 + 2 + 4; + + if ( FT_NEXT_ULONG( p ) != 0x00010000UL ) /* Version */ + FT_INVALID_FORMAT; + + featureNameCount = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (featureNameCount = %d)\n", featureNameCount )); + + if ( !( IS_PARANOID_VALIDATION ) ) + p += 6; /* skip (none) and (none) */ + else + { + if ( FT_NEXT_USHORT( p ) != 0 ) + FT_INVALID_DATA; + + if ( FT_NEXT_ULONG( p ) != 0 ) + FT_INVALID_DATA; + } + + feat->reserved_size += featureNameCount * ( 2 + 2 + 4 + 2 + 2 ); + + for ( last_feature = -1, i = 0; i < featureNameCount; i++ ) + { + gxv_feat_name_validate( p, limit, gxvalid ); + + if ( (FT_Int)GXV_FEAT_DATA( feature ) <= last_feature ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); + + last_feature = GXV_FEAT_DATA( feature ); + p += 2 + 2 + 4 + 2 + 2; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvfeat.h b/vendor/freetype/src/gxvalid/gxvfeat.h new file mode 100644 index 0000000..b33c1bc --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvfeat.h @@ -0,0 +1,173 @@ +/**************************************************************************** + * + * gxvfeat.h + * + * TrueTypeGX/AAT feat table validation (specification). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVFEAT_H_ +#define GXVFEAT_H_ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Registry predefined by Apple *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* TODO: More compact format */ + typedef struct GXV_Feature_RegistryRec_ + { + FT_Bool existence; + FT_Bool apple_reserved; + FT_Bool exclusive; + FT_Byte nSettings; + + } GX_Feature_RegistryRec; + + +#define gxv_feat_registry_length \ + ( sizeof ( gxv_feat_registry ) / \ + sizeof ( GX_Feature_RegistryRec ) ) + + + static GX_Feature_RegistryRec gxv_feat_registry[] = + { + /* Generated from gxvfgen.c */ + {1, 0, 0, 1}, /* All Typographic Features */ + {1, 0, 0, 8}, /* Ligatures */ + {1, 0, 1, 3}, /* Cursive Connection */ + {1, 0, 1, 6}, /* Letter Case */ + {1, 0, 0, 1}, /* Vertical Substitution */ + {1, 0, 0, 1}, /* Linguistic Rearrangement */ + {1, 0, 1, 2}, /* Number Spacing */ + {1, 1, 0, 0}, /* Apple Reserved 1 */ + {1, 0, 0, 5}, /* Smart Swashes */ + {1, 0, 1, 3}, /* Diacritics */ + {1, 0, 1, 4}, /* Vertical Position */ + {1, 0, 1, 3}, /* Fractions */ + {1, 1, 0, 0}, /* Apple Reserved 2 */ + {1, 0, 0, 1}, /* Overlapping Characters */ + {1, 0, 0, 6}, /* Typographic Extras */ + {1, 0, 0, 5}, /* Mathematical Extras */ + {1, 0, 1, 7}, /* Ornament Sets */ + {1, 0, 1, 1}, /* Character Alternatives */ + {1, 0, 1, 5}, /* Design Complexity */ + {1, 0, 1, 6}, /* Style Options */ + {1, 0, 1, 11}, /* Character Shape */ + {1, 0, 1, 2}, /* Number Case */ + {1, 0, 1, 4}, /* Text Spacing */ + {1, 0, 1, 10}, /* Transliteration */ + {1, 0, 1, 9}, /* Annotation */ + {1, 0, 1, 2}, /* Kana Spacing */ + {1, 0, 1, 2}, /* Ideographic Spacing */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {1, 0, 1, 4}, /* Text Spacing */ + {1, 0, 1, 2}, /* Kana Spacing */ + {1, 0, 1, 2}, /* Ideographic Spacing */ + {1, 0, 1, 4}, /* CJK Roman Spacing */ + }; + + +#endif /* GXVFEAT_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvfgen.c b/vendor/freetype/src/gxvalid/gxvfgen.c new file mode 100644 index 0000000..cf98bb3 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvfgen.c @@ -0,0 +1,484 @@ +/**************************************************************************** + * + * gxfgen.c + * + * Generate feature registry data for gxv `feat' validator. + * This program is derived from gxfeatreg.c in gxlayout. + * + * Copyright (C) 2004-2023 by + * Masatake YAMATO and Redhat K.K. + * + * This file may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxfeatreg.c + * + * Database of font features pre-defined by Apple Computer, Inc. + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html + * (body). + * + * Copyright 2003 by + * Masatake YAMATO and Redhat K.K. + * + * This file may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * Development of gxfeatreg.c is supported by + * Information-technology Promotion Agency, Japan. + * + */ + + +/**************************************************************************** + * + * This file is compiled as a stand-alone executable. + * This file is never compiled into `libfreetype2'. + * The output of this file is used in `gxvfeat.c'. + * ----------------------------------------------------------------------- + * Compile: gcc `pkg-config --cflags freetype2` gxvfgen.c -o gxvfgen + * Run: ./gxvfgen > tmp.c + * + */ + + /******************************************************************** + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + + /* + * If you add a new setting to a feature, check the number of settings + * in the feature. If the number is greater than the value defined as + * FEATREG_MAX_SETTING, update the value. + */ +#define FEATREG_MAX_SETTING 12 + + /******************************************************************** + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + + +#include +#include + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define APPLE_RESERVED "Apple Reserved" +#define APPLE_RESERVED_LENGTH 14 + + typedef struct GX_Feature_RegistryRec_ + { + const char* feat_name; + char exclusive; + char* setting_name[FEATREG_MAX_SETTING]; + + } GX_Feature_RegistryRec; + + +#define EMPTYFEAT {0, 0, {NULL}} + + + static GX_Feature_RegistryRec featreg_table[] = + { + { /* 0 */ + "All Typographic Features", + 0, + { + "All Type Features", + NULL + } + }, { /* 1 */ + "Ligatures", + 0, + { + "Required Ligatures", + "Common Ligatures", + "Rare Ligatures", + "Logos", + "Rebus Pictures", + "Diphthong Ligatures", + "Squared Ligatures", + "Squared Ligatures, Abbreviated", + NULL + } + }, { /* 2 */ + "Cursive Connection", + 1, + { + "Unconnected", + "Partially Connected", + "Cursive", + NULL + } + }, { /* 3 */ + "Letter Case", + 1, + { + "Upper & Lower Case", + "All Caps", + "All Lower Case", + "Small Caps", + "Initial Caps", + "Initial Caps & Small Caps", + NULL + } + }, { /* 4 */ + "Vertical Substitution", + 0, + { + /* "Substitute Vertical Forms", */ + "Turns on the feature", + NULL + } + }, { /* 5 */ + "Linguistic Rearrangement", + 0, + { + /* "Linguistic Rearrangement", */ + "Turns on the feature", + NULL + } + }, { /* 6 */ + "Number Spacing", + 1, + { + "Monospaced Numbers", + "Proportional Numbers", + NULL + } + }, { /* 7 */ + APPLE_RESERVED " 1", + 0, + {NULL} + }, { /* 8 */ + "Smart Swashes", + 0, + { + "Word Initial Swashes", + "Word Final Swashes", + "Line Initial Swashes", + "Line Final Swashes", + "Non-Final Swashes", + NULL + } + }, { /* 9 */ + "Diacritics", + 1, + { + "Show Diacritics", + "Hide Diacritics", + "Decompose Diacritics", + NULL + } + }, { /* 10 */ + "Vertical Position", + 1, + { + /* "Normal Position", */ + "No Vertical Position", + "Superiors", + "Inferiors", + "Ordinals", + NULL + } + }, { /* 11 */ + "Fractions", + 1, + { + "No Fractions", + "Vertical Fractions", + "Diagonal Fractions", + NULL + } + }, { /* 12 */ + APPLE_RESERVED " 2", + 0, + {NULL} + }, { /* 13 */ + "Overlapping Characters", + 0, + { + /* "Prevent Overlap", */ + "Turns on the feature", + NULL + } + }, { /* 14 */ + "Typographic Extras", + 0, + { + "Hyphens to Em Dash", + "Hyphens to En Dash", + "Unslashed Zero", + "Form Interrobang", + "Smart Quotes", + "Periods to Ellipsis", + NULL + } + }, { /* 15 */ + "Mathematical Extras", + 0, + { + "Hyphens to Minus", + "Asterisk to Multiply", + "Slash to Divide", + "Inequality Ligatures", + "Exponents", + NULL + } + }, { /* 16 */ + "Ornament Sets", + 1, + { + "No Ornaments", + "Dingbats", + "Pi Characters", + "Fleurons", + "Decorative Borders", + "International Symbols", + "Math Symbols", + NULL + } + }, { /* 17 */ + "Character Alternatives", + 1, + { + "No Alternates", + /* TODO */ + NULL + } + }, { /* 18 */ + "Design Complexity", + 1, + { + "Design Level 1", + "Design Level 2", + "Design Level 3", + "Design Level 4", + "Design Level 5", + /* TODO */ + NULL + } + }, { /* 19 */ + "Style Options", + 1, + { + "No Style Options", + "Display Text", + "Engraved Text", + "Illuminated Caps", + "Tilling Caps", + "Tall Caps", + NULL + } + }, { /* 20 */ + "Character Shape", + 1, + { + "Traditional Characters", + "Simplified Characters", + "JIS 1978 Characters", + "JIS 1983 Characters", + "JIS 1990 Characters", + "Traditional Characters, Alternative Set 1", + "Traditional Characters, Alternative Set 2", + "Traditional Characters, Alternative Set 3", + "Traditional Characters, Alternative Set 4", + "Traditional Characters, Alternative Set 5", + "Expert Characters", + NULL /* count => 12 */ + } + }, { /* 21 */ + "Number Case", + 1, + { + "Lower Case Numbers", + "Upper Case Numbers", + NULL + } + }, { /* 22 */ + "Text Spacing", + 1, + { + "Proportional", + "Monospaced", + "Half-width", + "Normal", + NULL + } + }, /* Here after Newer */ { /* 23 */ + "Transliteration", + 1, + { + "No Transliteration", + "Hanja To Hangul", + "Hiragana to Katakana", + "Katakana to Hiragana", + "Kana to Romanization", + "Romanization to Hiragana", + "Romanization to Katakana", + "Hanja to Hangul, Alternative Set 1", + "Hanja to Hangul, Alternative Set 2", + "Hanja to Hangul, Alternative Set 3", + NULL + } + }, { /* 24 */ + "Annotation", + 1, + { + "No Annotation", + "Box Annotation", + "Rounded Box Annotation", + "Circle Annotation", + "Inverted Circle Annotation", + "Parenthesis Annotation", + "Period Annotation", + "Roman Numeral Annotation", + "Diamond Annotation", + NULL + } + }, { /* 25 */ + "Kana Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 26 */ + "Ideographic Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 27-30 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 31-35 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 36-40 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 40-45 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 46-50 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 51-55 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 56-60 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 61-65 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 66-70 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 71-75 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 76-80 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 81-85 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 86-90 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 91-95 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 96-98 */ + EMPTYFEAT, /* 99 */ { /* 100 => 22 */ + "Text Spacing", + 1, + { + "Proportional", + "Monospaced", + "Half-width", + "Normal", + NULL + } + }, { /* 101 => 25 */ + "Kana Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 102 => 26 */ + "Ideographic Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 103 */ + "CJK Roman Spacing", + 1, + { + "Half-width", + "Proportional", + "Default Roman", + "Full-width Roman", + NULL + } + }, { /* 104 => 1 */ + "All Typographic Features", + 0, + { + "All Type Features", + NULL + } + } + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Generator *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + int + main( void ) + { + int i; + + + printf( " {\n" ); + printf( " /* Generated from %s */\n", __FILE__ ); + + for ( i = 0; + i < sizeof ( featreg_table ) / sizeof ( GX_Feature_RegistryRec ); + i++ ) + { + const char* feat_name; + int nSettings; + + + feat_name = featreg_table[i].feat_name; + for ( nSettings = 0; + featreg_table[i].setting_name[nSettings]; + nSettings++) + ; /* Do nothing */ + + printf( " {%1d, %1d, %1d, %2d}, /* %s */\n", + feat_name ? 1 : 0, + ( feat_name && + ( ft_strncmp( feat_name, + APPLE_RESERVED, APPLE_RESERVED_LENGTH ) == 0 ) + ) ? 1 : 0, + featreg_table[i].exclusive ? 1 : 0, + nSettings, + feat_name ? feat_name : "__EMPTY__" ); + } + + printf( " };\n" ); + + return 0; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvjust.c b/vendor/freetype/src/gxvalid/gxvjust.c new file mode 100644 index 0000000..5cca94d --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvjust.c @@ -0,0 +1,721 @@ +/**************************************************************************** + * + * gxvjust.c + * + * TrueTypeGX/AAT just table validation (body). + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvjust + + /* + * referred `just' table format specification: + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html + * last updated 2000. + * ---------------------------------------------- + * [JUST HEADER]: GXV_JUST_HEADER_SIZE + * version (fixed: 32bit) = 0x00010000 + * format (uint16: 16bit) = 0 is only defined (2000) + * horizOffset (uint16: 16bit) + * vertOffset (uint16: 16bit) + * ---------------------------------------------- + */ + + typedef struct GXV_just_DataRec_ + { + FT_UShort wdc_offset_max; + FT_UShort wdc_offset_min; + FT_UShort pc_offset_max; + FT_UShort pc_offset_min; + + } GXV_just_DataRec, *GXV_just_Data; + + +#define GXV_JUST_DATA( a ) GXV_TABLE_DATA( just, a ) + + + /* GX just table does not define their subset of GID */ + static void + gxv_just_check_max_gid( FT_UShort gid, + const FT_String* msg_tag, + GXV_Validator gxvalid ) + { + FT_UNUSED( msg_tag ); + + if ( gid < gxvalid->face->num_glyphs ) + return; + + GXV_TRACE(( "just table includes too large %s" + " GID=%d > %ld (in maxp)\n", + msg_tag, gid, gxvalid->face->num_glyphs )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + + static void + gxv_just_wdp_entry_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong justClass; +#ifdef GXV_LOAD_UNUSED_VARS + FT_Fixed beforeGrowLimit; + FT_Fixed beforeShrinkGrowLimit; + FT_Fixed afterGrowLimit; + FT_Fixed afterShrinkGrowLimit; + FT_UShort growFlags; + FT_UShort shrinkFlags; +#endif + + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 ); + justClass = FT_NEXT_ULONG( p ); +#ifndef GXV_LOAD_UNUSED_VARS + p += 4 + 4 + 4 + 4 + 2 + 2; +#else + beforeGrowLimit = FT_NEXT_ULONG( p ); + beforeShrinkGrowLimit = FT_NEXT_ULONG( p ); + afterGrowLimit = FT_NEXT_ULONG( p ); + afterShrinkGrowLimit = FT_NEXT_ULONG( p ); + growFlags = FT_NEXT_USHORT( p ); + shrinkFlags = FT_NEXT_USHORT( p ); +#endif + + /* According to Apple spec, only 7bits in justClass is used */ + if ( ( justClass & 0xFFFFFF80UL ) != 0 ) + { + GXV_TRACE(( "just table includes non-zero value" + " in unused justClass higher bits" + " of WidthDeltaPair" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_wdc_entry_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong count, i; + + + GXV_LIMIT_CHECK( 4 ); + count = FT_NEXT_ULONG( p ); + for ( i = 0; i < count; i++ ) + { + GXV_TRACE(( "validating wdc pair %lu/%lu\n", i + 1, count )); + gxv_just_wdp_entry_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_widthDeltaClusters_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes wdc_end = table + GXV_JUST_DATA( wdc_offset_max ); + + + GXV_NAME_ENTER( "just justDeltaClusters" ); + + if ( limit <= wdc_end ) + FT_INVALID_OFFSET; + + while ( p <= wdc_end ) + { + gxv_just_wdc_entry_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_just_actSubrecord_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + FT_Fixed lowerLimit; + FT_Fixed upperLimit; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort order; +#endif + FT_UShort decomposedCount; + + FT_UInt i; + + + GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); + lowerLimit = FT_NEXT_LONG( p ); + upperLimit = FT_NEXT_LONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + order = FT_NEXT_USHORT( p ); +#else + p += 2; +#endif + decomposedCount = FT_NEXT_USHORT( p ); + + if ( lowerLimit >= upperLimit ) + { + GXV_TRACE(( "just table includes invalid range spec:" + " lowerLimit(%ld) > upperLimit(%ld)\n", + lowerLimit, upperLimit )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + for ( i = 0; i < decomposedCount; i++ ) + { + FT_UShort glyphs; + + + GXV_LIMIT_CHECK( 2 ); + glyphs = FT_NEXT_USHORT( p ); + gxv_just_check_max_gid( glyphs, "type0:glyphs", gxvalid ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_actSubrecord_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort addGlyph; + + + GXV_LIMIT_CHECK( 2 ); + addGlyph = FT_NEXT_USHORT( p ); + + gxv_just_check_max_gid( addGlyph, "type1:addGlyph", gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_actSubrecord_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_UNUSED_VARS + FT_Fixed substThreshhold; /* Apple misspelled "Threshhold" */ +#endif + FT_UShort addGlyph; + FT_UShort substGlyph; + + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); +#ifdef GXV_LOAD_UNUSED_VARS + substThreshhold = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + addGlyph = FT_NEXT_USHORT( p ); + substGlyph = FT_NEXT_USHORT( p ); + + if ( addGlyph != 0xFFFF ) + gxv_just_check_max_gid( addGlyph, "type2:addGlyph", gxvalid ); + + gxv_just_check_max_gid( substGlyph, "type2:substGlyph", gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_actSubrecord_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong variantsAxis; + FT_Fixed minimumLimit; + FT_Fixed noStretchValue; + FT_Fixed maximumLimit; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); + variantsAxis = FT_NEXT_ULONG( p ); + minimumLimit = FT_NEXT_LONG( p ); + noStretchValue = FT_NEXT_LONG( p ); + maximumLimit = FT_NEXT_LONG( p ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + if ( variantsAxis != 0x64756374L ) /* 'duct' */ + GXV_TRACE(( "variantsAxis 0x%08lx is non default value", + variantsAxis )); + + if ( minimumLimit > noStretchValue ) + GXV_TRACE(( "type4:minimumLimit 0x%08lx > noStretchValue 0x%08lx\n", + minimumLimit, noStretchValue )); + else if ( noStretchValue > maximumLimit ) + GXV_TRACE(( "type4:noStretchValue 0x%08lx > maximumLimit 0x%08lx\n", + noStretchValue, maximumLimit )); + else if ( !IS_PARANOID_VALIDATION ) + return; + + FT_INVALID_DATA; + } + + + static void + gxv_just_actSubrecord_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort flags; + FT_UShort glyph; + + + GXV_LIMIT_CHECK( 2 + 2 ); + flags = FT_NEXT_USHORT( p ); + glyph = FT_NEXT_USHORT( p ); + + if ( flags ) + GXV_TRACE(( "type5: nonzero value 0x%04x in unused flags\n", + flags )); + gxv_just_check_max_gid( glyph, "type5:glyph", gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + /* parse single actSubrecord */ + static void + gxv_just_actSubrecord_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort actionClass; + FT_UShort actionType; + FT_ULong actionLength; + + + GXV_NAME_ENTER( "just actSubrecord" ); + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + actionClass = FT_NEXT_USHORT( p ); + actionType = FT_NEXT_USHORT( p ); + actionLength = FT_NEXT_ULONG( p ); + + /* actionClass is related with justClass using 7bit only */ + if ( ( actionClass & 0xFF80 ) != 0 ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + + if ( actionType == 0 ) + gxv_just_actSubrecord_type0_validate( p, limit, gxvalid ); + else if ( actionType == 1 ) + gxv_just_actSubrecord_type1_validate( p, limit, gxvalid ); + else if ( actionType == 2 ) + gxv_just_actSubrecord_type2_validate( p, limit, gxvalid ); + else if ( actionType == 3 ) + ; /* Stretch glyph action: no actionData */ + else if ( actionType == 4 ) + gxv_just_actSubrecord_type4_validate( p, limit, gxvalid ); + else if ( actionType == 5 ) + gxv_just_actSubrecord_type5_validate( p, limit, gxvalid ); + else + FT_INVALID_DATA; + + gxvalid->subtable_length = actionLength; + + GXV_EXIT; + } + + + static void + gxv_just_pcActionRecord_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong actionCount; + FT_ULong i; + + + GXV_LIMIT_CHECK( 4 ); + actionCount = FT_NEXT_ULONG( p ); + GXV_TRACE(( "actionCount = %lu\n", actionCount )); + + for ( i = 0; i < actionCount; i++ ) + { + gxv_just_actSubrecord_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_just_pcTable_LookupValue_entry_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) ) + GXV_JUST_DATA( pc_offset_max ) = value_p->u; + if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) ) + GXV_JUST_DATA( pc_offset_min ) = value_p->u; + } + + + static void + gxv_just_pcLookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "just pcLookupTable" ); + GXV_JUST_DATA( pc_offset_max ) = 0x0000; + GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + static void + gxv_just_postcompTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "just postcompTable" ); + + gxv_just_pcLookupTable_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + gxv_just_pcActionRecord_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_just_classTable_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + /* TODO: validate markClass & currentClass */ + FT_UShort setMark; + FT_UShort dontAdvance; + FT_UShort markClass; + FT_UShort currentClass; +#endif + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + FT_UNUSED( gxvalid ); + +#ifndef GXV_LOAD_UNUSED_VARS + FT_UNUSED( flags ); +#else + setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markClass = (FT_UShort)( ( flags >> 7 ) & 0x7F ); + currentClass = (FT_UShort)( flags & 0x7F ); +#endif + } + + + static void + gxv_just_justClassTable_validate ( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort length; + FT_UShort coverage; + FT_ULong subFeatureFlags; + + + GXV_NAME_ENTER( "just justClassTable" ); + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + subFeatureFlags = FT_NEXT_ULONG( p ); + + GXV_TRACE(( " justClassTable: coverage = 0x%04x ", coverage )); + if ( ( coverage & 0x4000 ) == 0 ) + GXV_TRACE(( "ascending\n" )); + else + GXV_TRACE(( "descending\n" )); + + if ( subFeatureFlags ) + GXV_TRACE(( " justClassTable: nonzero value (0x%08lx)" + " in unused subFeatureFlags\n", subFeatureFlags )); + + gxvalid->statetable.optdata = NULL; + gxvalid->statetable.optdata_load_func = NULL; + gxvalid->statetable.subtable_setup_func = NULL; + gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_just_classTable_entry_validate; + + gxv_StateTable_validate( p, table + length, gxvalid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + static void + gxv_just_wdcTable_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) ) + GXV_JUST_DATA( wdc_offset_max ) = value_p->u; + if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) ) + GXV_JUST_DATA( wdc_offset_min ) = value_p->u; + } + + + static void + gxv_just_justData_lookuptable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_JUST_DATA( wdc_offset_max ) = 0x0000; + GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_just_wdcTable_LookupValue_validate; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + /* + * gxv_just_justData_validate() parses and validates horizData, vertData. + */ + static void + gxv_just_justData_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + /* + * following 3 offsets are measured from the start of `just' + * (which table points to), not justData + */ + FT_UShort justClassTableOffset; + FT_UShort wdcTableOffset; + FT_UShort pcTableOffset; + FT_Bytes p = table; + + GXV_ODTECT( 4, odtect ); + + + GXV_NAME_ENTER( "just justData" ); + + GXV_ODTECT_INIT( odtect ); + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + justClassTableOffset = FT_NEXT_USHORT( p ); + wdcTableOffset = FT_NEXT_USHORT( p ); + pcTableOffset = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset )); + GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset )); + GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset )); + + gxv_just_justData_lookuptable_validate( p, limit, gxvalid ); + gxv_odtect_add_range( p, gxvalid->subtable_length, + "just_LookupTable", odtect ); + + if ( wdcTableOffset ) + { + gxv_just_widthDeltaClusters_validate( + gxvalid->root->base + wdcTableOffset, limit, gxvalid ); + gxv_odtect_add_range( gxvalid->root->base + wdcTableOffset, + gxvalid->subtable_length, "just_wdcTable", odtect ); + } + + if ( pcTableOffset ) + { + gxv_just_postcompTable_validate( gxvalid->root->base + pcTableOffset, + limit, gxvalid ); + gxv_odtect_add_range( gxvalid->root->base + pcTableOffset, + gxvalid->subtable_length, "just_pcTable", odtect ); + } + + if ( justClassTableOffset ) + { + gxv_just_justClassTable_validate( + gxvalid->root->base + justClassTableOffset, limit, gxvalid ); + gxv_odtect_add_range( gxvalid->root->base + justClassTableOffset, + gxvalid->subtable_length, "just_justClassTable", + odtect ); + } + + gxv_odtect_validate( odtect, gxvalid ); + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_just_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + GXV_just_DataRec justrec; + GXV_just_Data just = &justrec; + + FT_ULong version; + FT_UShort format; + FT_UShort horizOffset; + FT_UShort vertOffset; + + GXV_ODTECT( 3, odtect ); + + + GXV_ODTECT_INIT( odtect ); + + gxvalid->root = ftvalid; + gxvalid->table_data = just; + gxvalid->face = face; + + FT_TRACE3(( "validating `just' table\n" )); + GXV_INIT; + + limit = gxvalid->root->limit; + + GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + horizOffset = FT_NEXT_USHORT( p ); + vertOffset = FT_NEXT_USHORT( p ); + gxv_odtect_add_range( table, (FT_ULong)( p - table ), + "just header", odtect ); + + + /* Version 1.0 (always:2000) */ + GXV_TRACE(( " (version = 0x%08lx)\n", version )); + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* format 0 (always:2000) */ + GXV_TRACE(( " (format = 0x%04x)\n", format )); + if ( format != 0x0000 ) + FT_INVALID_FORMAT; + + GXV_TRACE(( " (horizOffset = %d)\n", horizOffset )); + GXV_TRACE(( " (vertOffset = %d)\n", vertOffset )); + + + /* validate justData */ + if ( 0 < horizOffset ) + { + gxv_just_justData_validate( table + horizOffset, limit, gxvalid ); + gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length, + "horizJustData", odtect ); + } + + if ( 0 < vertOffset ) + { + gxv_just_justData_validate( table + vertOffset, limit, gxvalid ); + gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length, + "vertJustData", odtect ); + } + + gxv_odtect_validate( odtect, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvkern.c b/vendor/freetype/src/gxvalid/gxvkern.c new file mode 100644 index 0000000..21fc245 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvkern.c @@ -0,0 +1,920 @@ +/**************************************************************************** + * + * gxvkern.c + * + * TrueTypeGX/AAT kern table validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvkern + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef enum GXV_kern_Version_ + { + KERN_VERSION_CLASSIC = 0x0000, + KERN_VERSION_NEW = 0x0001 + + } GXV_kern_Version; + + + typedef enum GXV_kern_Dialect_ + { + KERN_DIALECT_UNKNOWN = 0, + KERN_DIALECT_MS = FT_VALIDATE_MS, + KERN_DIALECT_APPLE = FT_VALIDATE_APPLE, + KERN_DIALECT_ANY = FT_VALIDATE_CKERN + + } GXV_kern_Dialect; + + + typedef struct GXV_kern_DataRec_ + { + GXV_kern_Version version; + void *subtable_data; + GXV_kern_Dialect dialect_request; + + } GXV_kern_DataRec, *GXV_kern_Data; + + +#define GXV_KERN_DATA( field ) GXV_TABLE_DATA( kern, field ) + +#define KERN_IS_CLASSIC( gxvalid ) \ + ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) ) +#define KERN_IS_NEW( gxvalid ) \ + ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) ) + +#define KERN_DIALECT( gxvalid ) \ + GXV_KERN_DATA( dialect_request ) +#define KERN_ALLOWS_MS( gxvalid ) \ + ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_MS ) +#define KERN_ALLOWS_APPLE( gxvalid ) \ + ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_APPLE ) + +#define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( gxvalid ) ? 8 : 4 ) +#define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( gxvalid ) ? 8 : 6 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SUBTABLE VALIDATORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* ============================= format 0 ============================== */ + + static void + gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nPairs, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + FT_UShort last_gid_left = 0; + FT_UShort last_gid_right = 0; + + FT_UNUSED( limit ); + + + GXV_NAME_ENTER( "kern format 0 pairs" ); + + for ( i = 0; i < nPairs; i++ ) + { + FT_UShort gid_left; + FT_UShort gid_right; +#ifdef GXV_LOAD_UNUSED_VARS + FT_Short kernValue; +#endif + + + /* left */ + gid_left = FT_NEXT_USHORT( p ); + gxv_glyphid_validate( gid_left, gxvalid ); + + /* right */ + gid_right = FT_NEXT_USHORT( p ); + gxv_glyphid_validate( gid_right, gxvalid ); + + /* Pairs of left and right GIDs must be unique and sorted. */ + GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right )); + if ( gid_left == last_gid_left ) + { + if ( last_gid_right < gid_right ) + last_gid_right = gid_right; + else + FT_INVALID_DATA; + } + else if ( last_gid_left < gid_left ) + { + last_gid_left = gid_left; + last_gid_right = gid_right; + } + else + FT_INVALID_DATA; + + /* skip the kern value */ +#ifdef GXV_LOAD_UNUSED_VARS + kernValue = FT_NEXT_SHORT( p ); +#else + p += 2; +#endif + } + + GXV_EXIT; + } + + static void + gxv_kern_subtable_fmt0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + + FT_UShort nPairs; + FT_UShort unitSize; + + + GXV_NAME_ENTER( "kern subtable format 0" ); + + unitSize = 2 + 2 + 2; + nPairs = 0; + + /* nPairs, searchRange, entrySelector, rangeShift */ + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, gxvalid ); + p += 2 + 2 + 2 + 2; + + gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, gxvalid ); + + GXV_EXIT; + } + + + /* ============================= format 1 ============================== */ + + + typedef struct GXV_kern_fmt1_StateOptRec_ + { + FT_UShort valueTable; + FT_UShort valueTable_length; + + } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData; + + + static void + gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_kern_fmt1_StateOptRecData optdata = + (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->valueTable = FT_NEXT_USHORT( p ); + } + + + /* + * passed tables_size covers whole StateTable, including kern fmt1 header + */ + static void + gxv_kern_subtable_fmt1_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[4]; + FT_UShort *l[4]; + FT_UShort buff[5]; + + GXV_kern_fmt1_StateOptRecData optdata = + (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->valueTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->valueTable_length); + + gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + /* + * passed table & limit are of whole StateTable, not including subtables + */ + static void + gxv_kern_subtable_fmt1_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort push; + FT_UShort dontAdvance; +#endif + FT_UShort valueOffset; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort kernAction; + FT_UShort kernValue; +#endif + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + + +#ifdef GXV_LOAD_UNUSED_VARS + push = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + valueOffset = (FT_UShort)( flags & 0x3FFF ); + + { + GXV_kern_fmt1_StateOptRecData vt_rec = + (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; + FT_Bytes p; + + + if ( valueOffset < vt_rec->valueTable ) + FT_INVALID_OFFSET; + + p = table + valueOffset; + limit = table + vt_rec->valueTable + vt_rec->valueTable_length; + + GXV_LIMIT_CHECK( 2 + 2 ); +#ifdef GXV_LOAD_UNUSED_VARS + kernAction = FT_NEXT_USHORT( p ); + kernValue = FT_NEXT_USHORT( p ); +#endif + } + } + + + static void + gxv_kern_subtable_fmt1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_kern_fmt1_StateOptRec vt_rec; + + + GXV_NAME_ENTER( "kern subtable format 1" ); + + gxvalid->statetable.optdata = + &vt_rec; + gxvalid->statetable.optdata_load_func = + gxv_kern_subtable_fmt1_valueTable_load; + gxvalid->statetable.subtable_setup_func = + gxv_kern_subtable_fmt1_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_kern_subtable_fmt1_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + + /* ================ Data for Class-Based Subtables 2, 3 ================ */ + + typedef enum GXV_kern_ClassSpec_ + { + GXV_KERN_CLS_L = 0, + GXV_KERN_CLS_R + + } GXV_kern_ClassSpec; + + + /* ============================= format 2 ============================== */ + + /* ---------------------- format 2 specific data ----------------------- */ + + typedef struct GXV_kern_subtable_fmt2_DataRec_ + { + FT_UShort rowWidth; + FT_UShort array; + FT_UShort offset_min[2]; + FT_UShort offset_max[2]; + const FT_String* class_tag[2]; + GXV_odtect_Range odtect; + + } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data; + + +#define GXV_KERN_FMT2_DATA( field ) \ + ( ( (GXV_kern_subtable_fmt2_DataRec *) \ + ( GXV_KERN_DATA( subtable_data ) ) )->field ) + + + /* -------------------------- utility functions ----------------------- */ + + static void + gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table, + FT_Bytes limit, + GXV_kern_ClassSpec spec, + GXV_Validator gxvalid ) + { + const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] ); + GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect ); + + FT_Bytes p = table; + FT_UShort firstGlyph; + FT_UShort nGlyphs; + + + GXV_NAME_ENTER( "kern format 2 classTable" ); + + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + nGlyphs = FT_NEXT_USHORT( p ); + GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n", + tag, firstGlyph, nGlyphs )); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), gxvalid ); + + gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ), + &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ), + &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ), + gxvalid ); + + gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect ); + + GXV_EXIT; + } + + + static void + gxv_kern_subtable_fmt2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + GXV_ODTECT( 3, odtect ); + GXV_kern_subtable_fmt2_DataRec fmt2_rec = + { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL }; + + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + FT_UShort leftOffsetTable; + FT_UShort rightOffsetTable; + + + GXV_NAME_ENTER( "kern subtable format 2" ); + + GXV_ODTECT_INIT( odtect ); + fmt2_rec.odtect = odtect; + GXV_KERN_DATA( subtable_data ) = &fmt2_rec; + + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p ); + leftOffsetTable = FT_NEXT_USHORT( p ); + rightOffsetTable = FT_NEXT_USHORT( p ); + GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) )); + + + GXV_LIMIT_CHECK( leftOffsetTable ); + GXV_LIMIT_CHECK( rightOffsetTable ); + GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) ); + + gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit, + GXV_KERN_CLS_L, gxvalid ); + + gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit, + GXV_KERN_CLS_R, gxvalid ); + + if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) + + GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] ) + < GXV_KERN_FMT2_DATA( array ) ) + FT_INVALID_OFFSET; + + gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ), + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] ) + + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] ) + - GXV_KERN_FMT2_DATA( array ), + "array", odtect ); + + gxv_odtect_validate( odtect, gxvalid ); + + GXV_EXIT; + } + + + /* ============================= format 3 ============================== */ + + static void + gxv_kern_subtable_fmt3_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + FT_UShort glyphCount; + FT_Byte kernValueCount; + FT_Byte leftClassCount; + FT_Byte rightClassCount; + FT_Byte flags; + + + GXV_NAME_ENTER( "kern subtable format 3" ); + + GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 ); + glyphCount = FT_NEXT_USHORT( p ); + kernValueCount = FT_NEXT_BYTE( p ); + leftClassCount = FT_NEXT_BYTE( p ); + rightClassCount = FT_NEXT_BYTE( p ); + flags = FT_NEXT_BYTE( p ); + + if ( gxvalid->face->num_glyphs != glyphCount ) + { + GXV_TRACE(( "maxGID=%ld, but glyphCount=%d\n", + gxvalid->face->num_glyphs, glyphCount )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + if ( flags != 0 ) + GXV_TRACE(( "kern subtable fmt3 has nonzero value" + " (%d) in unused flag\n", flags )); + /* + * just skip kernValue[kernValueCount] + */ + GXV_LIMIT_CHECK( 2 * kernValueCount ); + p += 2 * kernValueCount; + + /* + * check leftClass[gid] < leftClassCount + */ + { + FT_Byte min, max; + + + GXV_LIMIT_CHECK( glyphCount ); + gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, gxvalid ); + p += gxvalid->subtable_length; + + if ( leftClassCount < max ) + FT_INVALID_DATA; + } + + /* + * check rightClass[gid] < rightClassCount + */ + { + FT_Byte min, max; + + + GXV_LIMIT_CHECK( glyphCount ); + gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, gxvalid ); + p += gxvalid->subtable_length; + + if ( rightClassCount < max ) + FT_INVALID_DATA; + } + + /* + * check kernIndex[i, j] < kernValueCount + */ + { + FT_UShort i, j; + + + for ( i = 0; i < leftClassCount; i++ ) + { + for ( j = 0; j < rightClassCount; j++ ) + { + GXV_LIMIT_CHECK( 1 ); + if ( kernValueCount < FT_NEXT_BYTE( p ) ) + FT_INVALID_OFFSET; + } + } + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static FT_Bool + gxv_kern_coverage_new_apple_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + /* new Apple-dialect */ +#ifdef GXV_LOAD_TRACE_VARS + FT_Bool kernVertical; + FT_Bool kernCrossStream; + FT_Bool kernVariation; +#endif + + FT_UNUSED( gxvalid ); + + + /* reserved bits = 0 */ + if ( coverage & 0x1FFC ) + return FALSE; + +#ifdef GXV_LOAD_TRACE_VARS + kernVertical = FT_BOOL( ( coverage >> 15 ) & 1 ); + kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 ); + kernVariation = FT_BOOL( ( coverage >> 13 ) & 1 ); +#endif + + *format = (FT_UShort)( coverage & 0x0003 ); + + GXV_TRACE(( "new Apple-dialect: " + "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n", + !kernVertical, kernCrossStream, kernVariation, *format )); + + GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); + + return TRUE; + } + + + static FT_Bool + gxv_kern_coverage_classic_apple_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + /* classic Apple-dialect */ +#ifdef GXV_LOAD_TRACE_VARS + FT_Bool horizontal; + FT_Bool cross_stream; +#endif + + + /* check expected flags, but don't check if MS-dialect is impossible */ + if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( gxvalid ) ) + return FALSE; + + /* reserved bits = 0 */ + if ( coverage & 0x02FC ) + return FALSE; + +#ifdef GXV_LOAD_TRACE_VARS + horizontal = FT_BOOL( ( coverage >> 15 ) & 1 ); + cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 ); +#endif + + *format = (FT_UShort)( coverage & 0x0003 ); + + GXV_TRACE(( "classic Apple-dialect: " + "horizontal=%d, cross-stream=%d, format=%d\n", + horizontal, cross_stream, *format )); + + /* format 1 requires GX State Machine, too new for classic */ + if ( *format == 1 ) + return FALSE; + + GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); + + return TRUE; + } + + + static FT_Bool + gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + /* classic Microsoft-dialect */ +#ifdef GXV_LOAD_TRACE_VARS + FT_Bool horizontal; + FT_Bool minimum; + FT_Bool cross_stream; + FT_Bool override; +#endif + + FT_UNUSED( gxvalid ); + + + /* reserved bits = 0 */ + if ( coverage & 0xFDF0 ) + return FALSE; + +#ifdef GXV_LOAD_TRACE_VARS + horizontal = FT_BOOL( coverage & 1 ); + minimum = FT_BOOL( ( coverage >> 1 ) & 1 ); + cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 ); + override = FT_BOOL( ( coverage >> 3 ) & 1 ); +#endif + + *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 ); + + GXV_TRACE(( "classic Microsoft-dialect: " + "horizontal=%d, minimum=%d, cross-stream=%d, " + "override=%d, format=%d\n", + horizontal, minimum, cross_stream, override, *format )); + + if ( *format == 2 ) + GXV_TRACE(( + "kerning values in Microsoft format 2 subtable are ignored\n" )); + + return TRUE; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MAIN *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static GXV_kern_Dialect + gxv_kern_coverage_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + GXV_kern_Dialect result = KERN_DIALECT_UNKNOWN; + + + GXV_NAME_ENTER( "validating coverage" ); + + GXV_TRACE(( "interpret coverage 0x%04x by Apple style\n", coverage )); + + if ( KERN_IS_NEW( gxvalid ) ) + { + if ( gxv_kern_coverage_new_apple_validate( coverage, + format, + gxvalid ) ) + { + result = KERN_DIALECT_APPLE; + goto Exit; + } + } + + if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_APPLE( gxvalid ) ) + { + if ( gxv_kern_coverage_classic_apple_validate( coverage, + format, + gxvalid ) ) + { + result = KERN_DIALECT_APPLE; + goto Exit; + } + } + + if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_MS( gxvalid ) ) + { + if ( gxv_kern_coverage_classic_microsoft_validate( coverage, + format, + gxvalid ) ) + { + result = KERN_DIALECT_MS; + goto Exit; + } + } + + GXV_TRACE(( "cannot interpret coverage, broken kern subtable\n" )); + + Exit: + GXV_EXIT; + return result; + } + + + static void + gxv_kern_subtable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_TRACE_VARS + FT_UShort version = 0; /* MS only: subtable version, unused */ +#endif + FT_ULong length; /* MS: 16bit, Apple: 32bit */ + FT_UShort coverage; +#ifdef GXV_LOAD_TRACE_VARS + FT_UShort tupleIndex = 0; /* Apple only */ +#endif + FT_UShort u16[2]; + FT_UShort format = 255; /* subtable format */ + + + GXV_NAME_ENTER( "kern subtable" ); + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + u16[0] = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */ + u16[1] = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */ + coverage = FT_NEXT_USHORT( p ); + + switch ( gxv_kern_coverage_validate( coverage, &format, gxvalid ) ) + { + case KERN_DIALECT_MS: +#ifdef GXV_LOAD_TRACE_VARS + version = u16[0]; +#endif + length = u16[1]; +#ifdef GXV_LOAD_TRACE_VARS + tupleIndex = 0; +#endif + GXV_TRACE(( "Subtable version = %d\n", version )); + GXV_TRACE(( "Subtable length = %lu\n", length )); + break; + + case KERN_DIALECT_APPLE: +#ifdef GXV_LOAD_TRACE_VARS + version = 0; +#endif + length = ( (FT_ULong)u16[0] << 16 ) + u16[1]; +#ifdef GXV_LOAD_TRACE_VARS + tupleIndex = 0; +#endif + GXV_TRACE(( "Subtable length = %lu\n", length )); + + if ( KERN_IS_NEW( gxvalid ) ) + { + GXV_LIMIT_CHECK( 2 ); +#ifdef GXV_LOAD_TRACE_VARS + tupleIndex = FT_NEXT_USHORT( p ); +#else + p += 2; +#endif + GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex )); + } + break; + + default: + length = u16[1]; + GXV_TRACE(( "cannot detect subtable dialect, " + "just skip %lu byte\n", length )); + goto Exit; + } + + /* formats 1, 2, 3 require the position of the start of this subtable */ + if ( format == 0 ) + gxv_kern_subtable_fmt0_validate( table, table + length, gxvalid ); + else if ( format == 1 ) + gxv_kern_subtable_fmt1_validate( table, table + length, gxvalid ); + else if ( format == 2 ) + gxv_kern_subtable_fmt2_validate( table, table + length, gxvalid ); + else if ( format == 3 ) + gxv_kern_subtable_fmt3_validate( table, table + length, gxvalid ); + else + FT_INVALID_DATA; + + Exit: + gxvalid->subtable_length = length; + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** kern TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_kern_validate_generic( FT_Bytes table, + FT_Face face, + FT_Bool classic_only, + GXV_kern_Dialect dialect_request, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_kern_DataRec kernrec; + GXV_kern_Data kern = &kernrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong nTables = 0; + FT_UInt i; + + + gxvalid->root = ftvalid; + gxvalid->table_data = kern; + gxvalid->face = face; + + FT_TRACE3(( "validating `kern' table\n" )); + GXV_INIT; + KERN_DIALECT( gxvalid ) = dialect_request; + + GXV_LIMIT_CHECK( 2 ); + GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p ); + GXV_TRACE(( "version 0x%04x (higher 16bit)\n", + GXV_KERN_DATA( version ) )); + + if ( 0x0001 < GXV_KERN_DATA( version ) ) + FT_INVALID_FORMAT; + else if ( KERN_IS_CLASSIC( gxvalid ) ) + { + GXV_LIMIT_CHECK( 2 ); + nTables = FT_NEXT_USHORT( p ); + } + else if ( KERN_IS_NEW( gxvalid ) ) + { + if ( classic_only ) + FT_INVALID_FORMAT; + + if ( 0x0000 != FT_NEXT_USHORT( p ) ) + FT_INVALID_FORMAT; + + GXV_LIMIT_CHECK( 4 ); + nTables = FT_NEXT_ULONG( p ); + } + + for ( i = 0; i < nTables; i++ ) + { + GXV_TRACE(( "validating subtable %d/%lu\n", i, nTables )); + /* p should be 32bit-aligned? */ + gxv_kern_subtable_validate( p, 0, gxvalid ); + p += gxvalid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + + FT_LOCAL_DEF( void ) + gxv_kern_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid ); + } + + + FT_LOCAL_DEF( void ) + gxv_kern_validate_classic( FT_Bytes table, + FT_Face face, + FT_Int dialect_flags, + FT_Validator ftvalid ) + { + GXV_kern_Dialect dialect_request; + + + dialect_request = (GXV_kern_Dialect)dialect_flags; + gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid ); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvlcar.c b/vendor/freetype/src/gxvalid/gxvlcar.c new file mode 100644 index 0000000..5f3bf89 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvlcar.c @@ -0,0 +1,224 @@ +/**************************************************************************** + * + * gxvlcar.c + * + * TrueTypeGX/AAT lcar table validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvlcar + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_lcar_DataRec_ + { + FT_UShort format; + + } GXV_lcar_DataRec, *GXV_lcar_Data; + + +#define GXV_LCAR_DATA( FIELD ) GXV_TABLE_DATA( lcar, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_lcar_partial_validate( FT_Short partial, + FT_UShort glyph, + GXV_Validator gxvalid ) + { + GXV_NAME_ENTER( "partial" ); + + if ( GXV_LCAR_DATA( format ) != 1 ) + goto Exit; + + gxv_ctlPoint_validate( glyph, (FT_UShort)partial, gxvalid ); + + Exit: + GXV_EXIT; + } + + + static void + gxv_lcar_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = gxvalid->root->base + value_p->u; + FT_Bytes limit = gxvalid->root->limit; + FT_UShort count; + FT_Short partial; + FT_UShort i; + + + GXV_NAME_ENTER( "element in lookupTable" ); + + GXV_LIMIT_CHECK( 2 ); + count = FT_NEXT_USHORT( p ); + + GXV_LIMIT_CHECK( 2 * count ); + for ( i = 0; i < count; i++ ) + { + partial = FT_NEXT_SHORT( p ); + gxv_lcar_partial_validate( partial, glyph, gxvalid ); + } + + GXV_EXIT; + } + + + /* + +------ lcar --------------------+ + | | + | +===============+ | + | | lookup header | | + | +===============+ | + | | BinSrchHeader | | + | +===============+ | + | | lastGlyph[0] | | + | +---------------+ | + | | firstGlyph[0] | | head of lcar sfnt table + | +---------------+ | + + | | offset[0] | -> | offset [byte] + | +===============+ | + + | | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + | +---------------+ | + | | firstGlyph[1] | | + | +---------------+ | + | | offset[1] | | + | +===============+ | + | | + | .... | + | | + | 16bit value array | + | +===============+ | + +------| value | <-------+ + | .... + | + | + | + | + | + +----> lcar values...handled by lcar callback function + */ + + static GXV_LookupValueDesc + gxv_lcar_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + FT_UNUSED( lookuptbl_limit ); + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + p = gxvalid->root->base + offset; + limit = gxvalid->root->limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** lcar TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_lcar_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_lcar_DataRec lcarrec; + GXV_lcar_Data lcar = &lcarrec; + + FT_Fixed version; + + + gxvalid->root = ftvalid; + gxvalid->table_data = lcar; + gxvalid->face = face; + + FT_TRACE3(( "validating `lcar' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 ); + version = FT_NEXT_LONG( p ); + GXV_LCAR_DATA( format ) = FT_NEXT_USHORT( p ); + + if ( version != 0x00010000UL) + FT_INVALID_FORMAT; + + if ( GXV_LCAR_DATA( format ) > 1 ) + FT_INVALID_FORMAT; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_lcar_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_lcar_LookupFmt4_transit; + gxv_LookupTable_validate( p, limit, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmod.c b/vendor/freetype/src/gxvalid/gxvmod.c new file mode 100644 index 0000000..0b4115b --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmod.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * + * gxvmod.c + * + * FreeType's TrueTypeGX/AAT validation module implementation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include +#include +#include +#include +#include + +#include "gxvmod.h" +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmodule + + + static FT_Error + gxv_load_table( FT_Face face, + FT_Tag tag, + FT_Byte* volatile* table, + FT_ULong* table_len ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); + if ( FT_ERR_EQ( error, Table_Missing ) ) + return FT_Err_Ok; + if ( error ) + goto Exit; + + if ( FT_QALLOC( *table, *table_len ) ) + goto Exit; + + error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); + + Exit: + return error; + } + + +#define GXV_TABLE_DECL( _sfnt ) \ + FT_Byte* volatile _sfnt = NULL; \ + FT_ULong len_ ## _sfnt = 0 + +#define GXV_TABLE_LOAD( _sfnt ) \ + FT_BEGIN_STMNT \ + if ( ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) && \ + ( gx_flags & FT_VALIDATE_ ## _sfnt ) ) \ + { \ + error = gxv_load_table( face, TTAG_ ## _sfnt, \ + &_sfnt, &len_ ## _sfnt ); \ + if ( error ) \ + goto Exit; \ + } \ + FT_END_STMNT + +#define GXV_TABLE_VALIDATE( _sfnt ) \ + FT_BEGIN_STMNT \ + if ( _sfnt ) \ + { \ + ft_validator_init( &valid, _sfnt, _sfnt + len_ ## _sfnt, \ + FT_VALIDATE_DEFAULT ); \ + if ( ft_setjmp( valid.jump_buffer ) == 0 ) \ + gxv_ ## _sfnt ## _validate( _sfnt, face, &valid ); \ + error = valid.error; \ + if ( error ) \ + goto Exit; \ + } \ + FT_END_STMNT + +#define GXV_TABLE_SET( _sfnt ) \ + if ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) \ + tables[FT_VALIDATE_ ## _sfnt ## _INDEX] = (FT_Bytes)_sfnt + + + static FT_Error + gxv_validate( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_count ) + { + FT_Memory volatile memory = FT_FACE_MEMORY( face ); + + FT_Error error = FT_Err_Ok; + FT_ValidatorRec volatile valid; + + FT_UInt i; + + + GXV_TABLE_DECL( feat ); + GXV_TABLE_DECL( bsln ); + GXV_TABLE_DECL( trak ); + GXV_TABLE_DECL( just ); + GXV_TABLE_DECL( mort ); + GXV_TABLE_DECL( morx ); + GXV_TABLE_DECL( kern ); + GXV_TABLE_DECL( opbd ); + GXV_TABLE_DECL( prop ); + GXV_TABLE_DECL( lcar ); + + for ( i = 0; i < table_count; i++ ) + tables[i] = 0; + + /* load tables */ + GXV_TABLE_LOAD( feat ); + GXV_TABLE_LOAD( bsln ); + GXV_TABLE_LOAD( trak ); + GXV_TABLE_LOAD( just ); + GXV_TABLE_LOAD( mort ); + GXV_TABLE_LOAD( morx ); + GXV_TABLE_LOAD( kern ); + GXV_TABLE_LOAD( opbd ); + GXV_TABLE_LOAD( prop ); + GXV_TABLE_LOAD( lcar ); + + /* validate tables */ + GXV_TABLE_VALIDATE( feat ); + GXV_TABLE_VALIDATE( bsln ); + GXV_TABLE_VALIDATE( trak ); + GXV_TABLE_VALIDATE( just ); + GXV_TABLE_VALIDATE( mort ); + GXV_TABLE_VALIDATE( morx ); + GXV_TABLE_VALIDATE( kern ); + GXV_TABLE_VALIDATE( opbd ); + GXV_TABLE_VALIDATE( prop ); + GXV_TABLE_VALIDATE( lcar ); + + /* Set results */ + GXV_TABLE_SET( feat ); + GXV_TABLE_SET( mort ); + GXV_TABLE_SET( morx ); + GXV_TABLE_SET( bsln ); + GXV_TABLE_SET( just ); + GXV_TABLE_SET( kern ); + GXV_TABLE_SET( opbd ); + GXV_TABLE_SET( trak ); + GXV_TABLE_SET( prop ); + GXV_TABLE_SET( lcar ); + + Exit: + if ( error ) + { + FT_FREE( feat ); + FT_FREE( bsln ); + FT_FREE( trak ); + FT_FREE( just ); + FT_FREE( mort ); + FT_FREE( morx ); + FT_FREE( kern ); + FT_FREE( opbd ); + FT_FREE( prop ); + FT_FREE( lcar ); + } + + return error; + } + + + static FT_Error + classic_kern_validate( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes* ckern_table ) + { + FT_Memory volatile memory = FT_FACE_MEMORY( face ); + + FT_Byte* volatile ckern = NULL; + FT_ULong len_ckern = 0; + + /* without volatile on `error' GCC 4.1.1. emits: */ + /* warning: variable 'error' might be clobbered by 'longjmp' or 'vfork' */ + /* this warning seems spurious but --- */ + FT_Error volatile error; + FT_ValidatorRec volatile valid; + + + *ckern_table = NULL; + + error = gxv_load_table( face, TTAG_kern, &ckern, &len_ckern ); + if ( error ) + goto Exit; + + if ( ckern ) + { + ft_validator_init( &valid, ckern, ckern + len_ckern, + FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + gxv_kern_validate_classic( ckern, face, + ckern_flags & FT_VALIDATE_CKERN, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + *ckern_table = ckern; + + Exit: + if ( error ) + FT_FREE( ckern ); + + return error; + } + + + static + const FT_Service_GXvalidateRec gxvalid_interface = + { + gxv_validate /* validate */ + }; + + + static + const FT_Service_CKERNvalidateRec ckernvalid_interface = + { + classic_kern_validate /* validate */ + }; + + + static + const FT_ServiceDescRec gxvalid_services[] = + { + { FT_SERVICE_ID_GX_VALIDATE, &gxvalid_interface }, + { FT_SERVICE_ID_CLASSICKERN_VALIDATE, &ckernvalid_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + gxvalid_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( gxvalid_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class gxv_module_class = + { + 0, + sizeof ( FT_ModuleRec ), + "gxvalid", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + (FT_Module_Constructor)NULL, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) gxvalid_get_service /* get_interface */ + }; + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmod.h b/vendor/freetype/src/gxvalid/gxvmod.h new file mode 100644 index 0000000..db3d1d9 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmod.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * gxvmod.h + * + * FreeType's TrueTypeGX/AAT validation module implementation + * (specification). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVMOD_H_ +#define GXVMOD_H_ + +#include + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) gxv_module_class; + + +FT_END_HEADER + +#endif /* GXVMOD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmort.c b/vendor/freetype/src/gxvalid/gxvmort.c new file mode 100644 index 0000000..7032d63 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmort.c @@ -0,0 +1,301 @@ +/**************************************************************************** + * + * gxvmort.c + * + * TrueTypeGX/AAT mort table validation (body). + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" +#include "gxvfeat.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + static void + gxv_mort_feature_validate( GXV_mort_feature f, + GXV_Validator gxvalid ) + { + if ( f->featureType >= gxv_feat_registry_length ) + { + GXV_TRACE(( "featureType %d is out of registered range, " + "setting %d is unchecked\n", + f->featureType, f->featureSetting )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + else if ( !gxv_feat_registry[f->featureType].existence ) + { + GXV_TRACE(( "featureType %d is within registered area " + "but undefined, setting %d is unchecked\n", + f->featureType, f->featureSetting )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + else + { + FT_Byte nSettings_max; + + + /* nSettings in gxvfeat.c is halved for exclusive on/off settings */ + nSettings_max = gxv_feat_registry[f->featureType].nSettings; + if ( gxv_feat_registry[f->featureType].exclusive ) + nSettings_max = (FT_Byte)( 2 * nSettings_max ); + + GXV_TRACE(( "featureType %d is registered", f->featureType )); + GXV_TRACE(( "setting %d", f->featureSetting )); + + if ( f->featureSetting > nSettings_max ) + { + GXV_TRACE(( "out of defined range %d", nSettings_max )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + GXV_TRACE(( "\n" )); + } + + /* TODO: enableFlags must be unique value in specified chain? */ + } + + + /* + * nFeatureFlags is typed to FT_ULong to accept that in + * mort (typed FT_UShort) and morx (typed FT_ULong). + */ + FT_LOCAL_DEF( void ) + gxv_mort_featurearray_validate( FT_Bytes table, + FT_Bytes limit, + FT_ULong nFeatureFlags, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong i; + + GXV_mort_featureRec f = GXV_MORT_FEATURE_OFF; + + + GXV_NAME_ENTER( "mort feature list" ); + for ( i = 0; i < nFeatureFlags; i++ ) + { + GXV_LIMIT_CHECK( 2 + 2 + 4 + 4 ); + f.featureType = FT_NEXT_USHORT( p ); + f.featureSetting = FT_NEXT_USHORT( p ); + f.enableFlags = FT_NEXT_ULONG( p ); + f.disableFlags = FT_NEXT_ULONG( p ); + + gxv_mort_feature_validate( &f, gxvalid ); + } + + if ( !IS_GXV_MORT_FEATURE_OFF( f ) ) + FT_INVALID_DATA; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_coverage_validate( FT_UShort coverage, + GXV_Validator gxvalid ) + { + FT_UNUSED( gxvalid ); + FT_UNUSED( coverage ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( coverage & 0x8000U ) + GXV_TRACE(( " this subtable is for vertical text only\n" )); + else + GXV_TRACE(( " this subtable is for horizontal text only\n" )); + + if ( coverage & 0x4000 ) + GXV_TRACE(( " this subtable is applied to glyph array " + "in descending order\n" )); + else + GXV_TRACE(( " this subtable is applied to glyph array " + "in ascending order\n" )); + + if ( coverage & 0x2000 ) + GXV_TRACE(( " this subtable is forcibly applied to " + "vertical/horizontal text\n" )); + + if ( coverage & 0x1FF8 ) + GXV_TRACE(( " coverage has non-zero bits in reserved area\n" )); +#endif + } + + + static void + gxv_mort_subtables_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nSubtables, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_mort_subtable_type0_validate, /* 0 */ + gxv_mort_subtable_type1_validate, /* 1 */ + gxv_mort_subtable_type2_validate, /* 2 */ + NULL, /* 3 */ + gxv_mort_subtable_type4_validate, /* 4 */ + gxv_mort_subtable_type5_validate, /* 5 */ + + }; + + FT_UShort i; + + + GXV_NAME_ENTER( "subtables in a chain" ); + + for ( i = 0; i < nSubtables; i++ ) + { + GXV_Validate_Func func; + + FT_UShort length; + FT_UShort coverage; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong subFeatureFlags; +#endif + FT_UInt type; + FT_UInt rest; + + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); +#ifdef GXV_LOAD_UNUSED_VARS + subFeatureFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + + GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n", + i + 1, nSubtables, length )); + type = coverage & 0x0007; + rest = length - ( 2 + 2 + 4 ); + + GXV_LIMIT_CHECK( rest ); + gxv_mort_coverage_validate( coverage, gxvalid ); + + if ( type > 5 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[type]; + if ( !func ) + GXV_TRACE(( "morx type %d is reserved\n", type )); + + func( p, p + rest, gxvalid ); + + p += rest; + /* TODO: validate subFeatureFlags */ + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_mort_chain_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong defaultFlags; +#endif + FT_ULong chainLength; + FT_UShort nFeatureFlags; + FT_UShort nSubtables; + + + GXV_NAME_ENTER( "mort chain header" ); + + GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); +#ifdef GXV_LOAD_UNUSED_VARS + defaultFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + chainLength = FT_NEXT_ULONG( p ); + nFeatureFlags = FT_NEXT_USHORT( p ); + nSubtables = FT_NEXT_USHORT( p ); + + gxv_mort_featurearray_validate( p, table + chainLength, + nFeatureFlags, gxvalid ); + p += gxvalid->subtable_length; + gxv_mort_subtables_validate( p, table + chainLength, nSubtables, gxvalid ); + gxvalid->subtable_length = chainLength; + + /* TODO: validate defaultFlags */ + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_ULong version; + FT_ULong nChains; + FT_ULong i; + + + gxvalid->root = ftvalid; + gxvalid->face = face; + limit = gxvalid->root->limit; + + FT_TRACE3(( "validating `mort' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 4 ); + version = FT_NEXT_ULONG( p ); + nChains = FT_NEXT_ULONG( p ); + + if (version != 0x00010000UL) + FT_INVALID_FORMAT; + + for ( i = 0; i < nChains; i++ ) + { + GXV_TRACE(( "validating chain %lu/%lu\n", i + 1, nChains )); + GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); + gxv_mort_chain_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmort.h b/vendor/freetype/src/gxvalid/gxvmort.h new file mode 100644 index 0000000..5c819bd --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmort.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * + * gxvmort.h + * + * TrueTypeGX/AAT common definition for mort table (specification). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVMORT_H_ +#define GXVMORT_H_ + +#include "gxvalid.h" +#include "gxvcommn.h" + +#include + + +FT_BEGIN_HEADER + + + typedef struct GXV_mort_featureRec_ + { + FT_UShort featureType; + FT_UShort featureSetting; + FT_ULong enableFlags; + FT_ULong disableFlags; + + } GXV_mort_featureRec, *GXV_mort_feature; + +#define GXV_MORT_FEATURE_OFF {0, 1, 0x00000000UL, 0x00000000UL} + +#define IS_GXV_MORT_FEATURE_OFF( f ) \ + ( (f).featureType == 0 || \ + (f).featureSetting == 1 || \ + (f).enableFlags == 0x00000000UL || \ + (f).disableFlags == 0x00000000UL ) + + + FT_LOCAL( void ) + gxv_mort_featurearray_validate( FT_Bytes table, + FT_Bytes limit, + FT_ULong nFeatureFlags, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_coverage_validate( FT_UShort coverage, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + +FT_END_HEADER + +#endif /* GXVMORT_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmort0.c b/vendor/freetype/src/gxvalid/gxvmort0.c new file mode 100644 index 0000000..24e70a0 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmort0.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * + * gxvmort0.c + * + * TrueTypeGX/AAT mort table validation + * body for type0 (Indic Script Rearrangement) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + static const char* GXV_Mort_IndicScript_Msg[] = + { + "no change", + "Ax => xA", + "xD => Dx", + "AxD => DxA", + "ABx => xAB", + "ABx => xBA", + "xCD => CDx", + "xCD => DCx", + "AxCD => CDxA", + "AxCD => DCxA", + "ABxD => DxAB", + "ABxD => DxBA", + "ABxCD => CDxAB", + "ABxCD => CDxBA", + "ABxCD => DCxAB", + "ABxCD => DCxBA", + + }; + + + static void + gxv_mort_subtable_type0_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_UShort markFirst; + FT_UShort dontAdvance; + FT_UShort markLast; + FT_UShort reserved; + FT_UShort verb = 0; + + FT_UNUSED( state ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + FT_UNUSED( GXV_Mort_IndicScript_Msg[verb] ); /* for the non-debugging */ + FT_UNUSED( glyphOffset_p ); /* case */ + + + markFirst = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markLast = (FT_UShort)( ( flags >> 13 ) & 1 ); + + reserved = (FT_UShort)( flags & 0x1FF0 ); + verb = (FT_UShort)( flags & 0x000F ); + + GXV_TRACE(( " IndicScript MorphRule for glyphOffset 0x%04x", + glyphOffset_p->u )); + GXV_TRACE(( " markFirst=%01d", markFirst )); + GXV_TRACE(( " dontAdvance=%01d", dontAdvance )); + GXV_TRACE(( " markLast=%01d", markLast )); + GXV_TRACE(( " %02d", verb )); + GXV_TRACE(( " %s\n", GXV_Mort_IndicScript_Msg[verb] )); + + if ( markFirst > 0 && markLast > 0 ) + { + GXV_TRACE(( " [odd] a glyph is marked as the first and last" + " in Indic rearrangement\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + if ( markFirst > 0 && dontAdvance > 0 ) + { + GXV_TRACE(( " [odd] the first glyph is marked as dontAdvance" + " in Indic rearrangement\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + else + GXV_TRACE(( "\n" )); + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( + "mort chain subtable type0 (Indic-Script Rearrangement)" ); + + GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE ); + + gxvalid->statetable.optdata = NULL; + gxvalid->statetable.optdata_load_func = NULL; + gxvalid->statetable.subtable_setup_func = NULL; + gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_mort_subtable_type0_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmort1.c b/vendor/freetype/src/gxvalid/gxvmort1.c new file mode 100644 index 0000000..ea5591f --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmort1.c @@ -0,0 +1,260 @@ +/**************************************************************************** + * + * gxvmort1.c + * + * TrueTypeGX/AAT mort table validation + * body for type1 (Contextual Substitution) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + typedef struct GXV_mort_subtable_type1_StateOptRec_ + { + FT_UShort substitutionTable; + FT_UShort substitutionTable_length; + + } GXV_mort_subtable_type1_StateOptRec, + *GXV_mort_subtable_type1_StateOptRecData; + +#define GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 ) + + + static void + gxv_mort_subtable_type1_substitutionTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type1_StateOptRecData optdata = + (GXV_mort_subtable_type1_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->substitutionTable = FT_NEXT_USHORT( p ); + } + + + static void + gxv_mort_subtable_type1_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[4]; + FT_UShort *l[4]; + FT_UShort buff[5]; + + GXV_mort_subtable_type1_StateOptRecData optdata = + (GXV_mort_subtable_type1_StateOptRecData)gxvalid->statetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->substitutionTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &( optdata->substitutionTable_length ); + + gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + static void + gxv_mort_subtable_type1_offset_to_subst_validate( + FT_Short wordOffset, + const FT_String* tag, + FT_Byte state, + GXV_Validator gxvalid ) + { + FT_UShort substTable; + FT_UShort substTable_limit; + + FT_UNUSED( tag ); + FT_UNUSED( state ); + + + substTable = + ((GXV_mort_subtable_type1_StateOptRec *) + (gxvalid->statetable.optdata))->substitutionTable; + substTable_limit = + (FT_UShort)( substTable + + ((GXV_mort_subtable_type1_StateOptRec *) + (gxvalid->statetable.optdata))->substitutionTable_length ); + + gxvalid->min_gid = (FT_UShort)( ( substTable - wordOffset * 2 ) / 2 ); + gxvalid->max_gid = (FT_UShort)( ( substTable_limit - wordOffset * 2 ) / 2 ); + gxvalid->max_gid = (FT_UShort)( FT_MAX( gxvalid->max_gid, + gxvalid->face->num_glyphs ) ); + + /* XXX: check range? */ + + /* TODO: min_gid & max_gid comparison with ClassTable contents */ + } + + + static void + gxv_mort_subtable_type1_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort setMark; + FT_UShort dontAdvance; +#endif + FT_UShort reserved; + FT_Short markOffset; + FT_Short currentOffset; + + FT_UNUSED( table ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setMark = (FT_UShort)( flags >> 15 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + reserved = (FT_UShort)( flags & 0x3FFF ); + + markOffset = (FT_Short)( glyphOffset_p->ul >> 16 ); + currentOffset = (FT_Short)( glyphOffset_p->ul ); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + gxv_mort_subtable_type1_offset_to_subst_validate( markOffset, + "markOffset", + state, + gxvalid ); + + gxv_mort_subtable_type1_offset_to_subst_validate( currentOffset, + "currentOffset", + state, + gxvalid ); + } + + + static void + gxv_mort_subtable_type1_substTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort num_gids = (FT_UShort)( + ((GXV_mort_subtable_type1_StateOptRec *) + (gxvalid->statetable.optdata))->substitutionTable_length / 2 ); + FT_UShort i; + + + GXV_NAME_ENTER( "validating contents of substitutionTable" ); + for ( i = 0; i < num_gids; i++ ) + { + FT_UShort dst_gid; + + + GXV_LIMIT_CHECK( 2 ); + dst_gid = FT_NEXT_USHORT( p ); + + if ( dst_gid >= 0xFFFFU ) + continue; + + if ( dst_gid < gxvalid->min_gid || gxvalid->max_gid < dst_gid ) + { + GXV_TRACE(( "substTable include a strange gid[%d]=%d >" + " out of define range (%d..%d)\n", + i, dst_gid, gxvalid->min_gid, gxvalid->max_gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + } + + GXV_EXIT; + } + + + /* + * subtable for Contextual glyph substitution is a modified StateTable. + * In addition to classTable, stateArray, and entryTable, the field + * `substitutionTable' is added. + */ + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type1_StateOptRec st_rec; + + + GXV_NAME_ENTER( "mort chain subtable type1 (Contextual Glyph Subst)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE ); + + gxvalid->statetable.optdata = + &st_rec; + gxvalid->statetable.optdata_load_func = + gxv_mort_subtable_type1_substitutionTable_load; + gxvalid->statetable.subtable_setup_func = + gxv_mort_subtable_type1_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->statetable.entry_validate_func = + + gxv_mort_subtable_type1_entry_validate; + gxv_StateTable_validate( p, limit, gxvalid ); + + gxv_mort_subtable_type1_substTable_validate( + table + st_rec.substitutionTable, + table + st_rec.substitutionTable + st_rec.substitutionTable_length, + gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmort2.c b/vendor/freetype/src/gxvalid/gxvmort2.c new file mode 100644 index 0000000..50644f0 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmort2.c @@ -0,0 +1,312 @@ +/**************************************************************************** + * + * gxvmort2.c + * + * TrueTypeGX/AAT mort table validation + * body for type2 (Ligature Substitution) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + typedef struct GXV_mort_subtable_type2_StateOptRec_ + { + FT_UShort ligActionTable; + FT_UShort componentTable; + FT_UShort ligatureTable; + FT_UShort ligActionTable_length; + FT_UShort componentTable_length; + FT_UShort ligatureTable_length; + + } GXV_mort_subtable_type2_StateOptRec, + *GXV_mort_subtable_type2_StateOptRecData; + +#define GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 + 2 + 2 ) + + + static void + gxv_mort_subtable_type2_opttable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + optdata->ligActionTable = FT_NEXT_USHORT( p ); + optdata->componentTable = FT_NEXT_USHORT( p ); + optdata->ligatureTable = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "offset to ligActionTable=0x%04x\n", + optdata->ligActionTable )); + GXV_TRACE(( "offset to componentTable=0x%04x\n", + optdata->componentTable )); + GXV_TRACE(( "offset to ligatureTable=0x%04x\n", + optdata->ligatureTable )); + } + + + static void + gxv_mort_subtable_type2_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort *classTable_length_p, + FT_UShort *stateArray_length_p, + FT_UShort *entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[6]; + FT_UShort *l[6]; + FT_UShort buff[7]; + + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_NAME_ENTER( "subtable boundaries setup" ); + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->ligActionTable; + o[4] = optdata->componentTable; + o[5] = optdata->ligatureTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->ligActionTable_length); + l[4] = &(optdata->componentTable_length); + l[5] = &(optdata->ligatureTable_length); + + gxv_set_length_by_ushort_offset( o, l, buff, 6, table_size, gxvalid ); + + GXV_TRACE(( "classTable: offset=0x%04x length=0x%04x\n", + classTable, *classTable_length_p )); + GXV_TRACE(( "stateArray: offset=0x%04x length=0x%04x\n", + stateArray, *stateArray_length_p )); + GXV_TRACE(( "entryTable: offset=0x%04x length=0x%04x\n", + entryTable, *entryTable_length_p )); + GXV_TRACE(( "ligActionTable: offset=0x%04x length=0x%04x\n", + optdata->ligActionTable, + optdata->ligActionTable_length )); + GXV_TRACE(( "componentTable: offset=0x%04x length=0x%04x\n", + optdata->componentTable, + optdata->componentTable_length )); + GXV_TRACE(( "ligatureTable: offset=0x%04x length=0x%04x\n", + optdata->ligatureTable, + optdata->ligatureTable_length )); + + GXV_EXIT; + } + + + static void + gxv_mort_subtable_type2_ligActionOffset_validate( + FT_Bytes table, + FT_UShort ligActionOffset, + GXV_Validator gxvalid ) + { + /* access ligActionTable */ + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + FT_Bytes lat_base = table + optdata->ligActionTable; + FT_Bytes p = table + ligActionOffset; + FT_Bytes lat_limit = lat_base + optdata->ligActionTable; + + + GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset ); + if ( p < lat_base ) + { + GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%ld byte rewind)\n", + ligActionOffset, lat_base - p )); + + /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + else if ( lat_limit < p ) + { + GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%ld byte overrun)\n", + ligActionOffset, p - lat_limit )); + + /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + else + { + /* validate entry in ligActionTable */ + FT_ULong lig_action; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort last; + FT_UShort store; +#endif + FT_ULong offset; + + + lig_action = FT_NEXT_ULONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + last = (FT_UShort)( ( lig_action >> 31 ) & 1 ); + store = (FT_UShort)( ( lig_action >> 30 ) & 1 ); +#endif + + /* Apple spec defines this offset as a word offset */ + offset = lig_action & 0x3FFFFFFFUL; + if ( offset * 2 < optdata->ligatureTable ) + { + GXV_TRACE(( "too short offset 0x%08lx:" + " 2 x offset < ligatureTable (%lu byte rewind)\n", + offset, optdata->ligatureTable - offset * 2 )); + + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } else if ( offset * 2 > + optdata->ligatureTable + optdata->ligatureTable_length ) + { + GXV_TRACE(( "too long offset 0x%08lx:" + " 2 x offset > ligatureTable + ligatureTable_length" + " (%lu byte overrun)\n", + offset, + optdata->ligatureTable + optdata->ligatureTable_length + - offset * 2 )); + + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + } + } + + + static void + gxv_mort_subtable_type2_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort setComponent; + FT_UShort dontAdvance; +#endif + FT_UShort offset; + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setComponent = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + + offset = (FT_UShort)( flags & 0x3FFFU ); + + if ( 0 < offset ) + gxv_mort_subtable_type2_ligActionOffset_validate( table, offset, + gxvalid ); + } + + + static void + gxv_mort_subtable_type2_ligatureTable_validate( FT_Bytes table, + GXV_Validator gxvalid ) + { + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + FT_Bytes p = table + optdata->ligatureTable; + FT_Bytes limit = table + optdata->ligatureTable + + optdata->ligatureTable_length; + + + GXV_NAME_ENTER( "mort chain subtable type2 - substitutionTable" ); + if ( 0 != optdata->ligatureTable ) + { + /* Apple does not give specification of ligatureTable format */ + while ( p < limit ) + { + FT_UShort lig_gid; + + + GXV_LIMIT_CHECK( 2 ); + lig_gid = FT_NEXT_USHORT( p ); + + if ( gxvalid->face->num_glyphs < lig_gid ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + } + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type2_StateOptRec lig_rec; + + + GXV_NAME_ENTER( "mort chain subtable type2 (Ligature Substitution)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE ); + + gxvalid->statetable.optdata = + &lig_rec; + gxvalid->statetable.optdata_load_func = + gxv_mort_subtable_type2_opttable_load; + gxvalid->statetable.subtable_setup_func = + gxv_mort_subtable_type2_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_mort_subtable_type2_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + p += gxvalid->subtable_length; + gxv_mort_subtable_type2_ligatureTable_validate( table, gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmort4.c b/vendor/freetype/src/gxvalid/gxvmort4.c new file mode 100644 index 0000000..0641b11 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmort4.c @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * gxvmort4.c + * + * TrueTypeGX/AAT mort table validation + * body for type4 (Non-Contextual Glyph Substitution) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + static void + gxv_mort_subtable_type4_lookupval_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + gxv_glyphid_validate( value_p->u, gxvalid ); + } + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 16bit value array | + +===============+ | + | value | <-------+ + .... + */ + + static GXV_LookupValueDesc + gxv_mort_subtable_type4_lookupfmt4_transit( + FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "mort chain subtable type4 " + "(Non-Contextual Glyph Substitution)" ); + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_mort_subtable_type4_lookupval_validate; + gxvalid->lookupfmt4_trans = gxv_mort_subtable_type4_lookupfmt4_transit; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmort5.c b/vendor/freetype/src/gxvalid/gxvmort5.c new file mode 100644 index 0000000..9225bb0 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmort5.c @@ -0,0 +1,234 @@ +/**************************************************************************** + * + * gxvmort5.c + * + * TrueTypeGX/AAT mort table validation + * body for type5 (Contextual Glyph Insertion) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + /* + * mort subtable type5 (Contextual Glyph Insertion) + * has the format of StateTable with insertion-glyph-list, + * but without name. The offset is given by glyphOffset in + * entryTable. There is no table location declaration + * like xxxTable. + */ + + typedef struct GXV_mort_subtable_type5_StateOptRec_ + { + FT_UShort classTable; + FT_UShort stateArray; + FT_UShort entryTable; + +#define GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE GXV_STATETABLE_HEADER_SIZE + + FT_UShort* classTable_length_p; + FT_UShort* stateArray_length_p; + FT_UShort* entryTable_length_p; + + } GXV_mort_subtable_type5_StateOptRec, + *GXV_mort_subtable_type5_StateOptRecData; + + + static void + gxv_mort_subtable_type5_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + GXV_mort_subtable_type5_StateOptRecData optdata = + (GXV_mort_subtable_type5_StateOptRecData)gxvalid->statetable.optdata; + + + gxv_StateTable_subtable_setup( table_size, + classTable, + stateArray, + entryTable, + classTable_length_p, + stateArray_length_p, + entryTable_length_p, + gxvalid ); + + optdata->classTable = classTable; + optdata->stateArray = stateArray; + optdata->entryTable = entryTable; + + optdata->classTable_length_p = classTable_length_p; + optdata->stateArray_length_p = stateArray_length_p; + optdata->entryTable_length_p = entryTable_length_p; + } + + + static void + gxv_mort_subtable_type5_InsertList_validate( FT_UShort offset, + FT_UShort count, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + /* + * We don't know the range of insertion-glyph-list. + * Set range by whole of state table. + */ + FT_Bytes p = table + offset; + + GXV_mort_subtable_type5_StateOptRecData optdata = + (GXV_mort_subtable_type5_StateOptRecData)gxvalid->statetable.optdata; + + if ( optdata->classTable < offset && + offset < optdata->classTable + *(optdata->classTable_length_p) ) + GXV_TRACE(( " offset runs into ClassTable" )); + if ( optdata->stateArray < offset && + offset < optdata->stateArray + *(optdata->stateArray_length_p) ) + GXV_TRACE(( " offset runs into StateArray" )); + if ( optdata->entryTable < offset && + offset < optdata->entryTable + *(optdata->entryTable_length_p) ) + GXV_TRACE(( " offset runs into EntryTable" )); + +#ifndef GXV_LOAD_TRACE_VARS + GXV_LIMIT_CHECK( count * 2 ); +#else + while ( p < table + offset + ( count * 2 ) ) + { + FT_UShort insert_glyphID; + + + GXV_LIMIT_CHECK( 2 ); + insert_glyphID = FT_NEXT_USHORT( p ); + GXV_TRACE(( " 0x%04x", insert_glyphID )); + } + GXV_TRACE(( "\n" )); +#endif + } + + + static void + gxv_mort_subtable_type5_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_Bool setMark; + FT_Bool dontAdvance; + FT_Bool currentIsKashidaLike; + FT_Bool markedIsKashidaLike; + FT_Bool currentInsertBefore; + FT_Bool markedInsertBefore; +#endif + FT_Byte currentInsertCount; + FT_Byte markedInsertCount; + FT_UShort currentInsertList; + FT_UShort markedInsertList; + + FT_UNUSED( state ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setMark = FT_BOOL( ( flags >> 15 ) & 1 ); + dontAdvance = FT_BOOL( ( flags >> 14 ) & 1 ); + currentIsKashidaLike = FT_BOOL( ( flags >> 13 ) & 1 ); + markedIsKashidaLike = FT_BOOL( ( flags >> 12 ) & 1 ); + currentInsertBefore = FT_BOOL( ( flags >> 11 ) & 1 ); + markedInsertBefore = FT_BOOL( ( flags >> 10 ) & 1 ); +#endif + + currentInsertCount = (FT_Byte)( ( flags >> 5 ) & 0x1F ); + markedInsertCount = (FT_Byte)( flags & 0x001F ); + + currentInsertList = (FT_UShort)( glyphOffset->ul >> 16 ); + markedInsertList = (FT_UShort)( glyphOffset->ul ); + + if ( 0 != currentInsertList && 0 != currentInsertCount ) + { + gxv_mort_subtable_type5_InsertList_validate( currentInsertList, + currentInsertCount, + table, + limit, + gxvalid ); + } + + if ( 0 != markedInsertList && 0 != markedInsertCount ) + { + gxv_mort_subtable_type5_InsertList_validate( markedInsertList, + markedInsertCount, + table, + limit, + gxvalid ); + } + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type5_StateOptRec et_rec; + GXV_mort_subtable_type5_StateOptRecData et = &et_rec; + + + GXV_NAME_ENTER( "mort chain subtable type5 (Glyph Insertion)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE ); + + gxvalid->statetable.optdata = + et; + gxvalid->statetable.optdata_load_func = + NULL; + gxvalid->statetable.subtable_setup_func = + gxv_mort_subtable_type5_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->statetable.entry_validate_func = + gxv_mort_subtable_type5_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmorx.c b/vendor/freetype/src/gxvalid/gxvmorx.c new file mode 100644 index 0000000..931bf00 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmorx.c @@ -0,0 +1,199 @@ +/**************************************************************************** + * + * gxvmorx.c + * + * TrueTypeGX/AAT morx table validation (body). + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + static void + gxv_morx_subtables_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nSubtables, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_morx_subtable_type0_validate, /* 0 */ + gxv_morx_subtable_type1_validate, /* 1 */ + gxv_morx_subtable_type2_validate, /* 2 */ + NULL, /* 3 */ + gxv_morx_subtable_type4_validate, /* 4 */ + gxv_morx_subtable_type5_validate, /* 5 */ + + }; + + FT_UShort i; + + + GXV_NAME_ENTER( "subtables in a chain" ); + + for ( i = 0; i < nSubtables; i++ ) + { + GXV_Validate_Func func; + + FT_ULong length; + FT_ULong coverage; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong subFeatureFlags; +#endif + FT_ULong type; + FT_ULong rest; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 ); + length = FT_NEXT_ULONG( p ); + coverage = FT_NEXT_ULONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + subFeatureFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + + GXV_TRACE(( "validating chain subtable %d/%d (%lu bytes)\n", + i + 1, nSubtables, length )); + + type = coverage & 0x0007; + rest = length - ( 4 + 4 + 4 ); + GXV_LIMIT_CHECK( rest ); + + /* morx coverage consists of mort_coverage & 16bit padding */ + gxv_mort_coverage_validate( (FT_UShort)( ( coverage >> 16 ) | coverage ), + gxvalid ); + if ( type > 5 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[type]; + if ( !func ) + GXV_TRACE(( "morx type %lu is reserved\n", type )); + + func( p, p + rest, gxvalid ); + + /* TODO: subFeatureFlags should be unique in a table? */ + p += rest; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_morx_chain_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong defaultFlags; +#endif + FT_ULong chainLength; + FT_ULong nFeatureFlags; + FT_ULong nSubtables; + + + GXV_NAME_ENTER( "morx chain header" ); + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); +#ifdef GXV_LOAD_UNUSED_VARS + defaultFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + chainLength = FT_NEXT_ULONG( p ); + nFeatureFlags = FT_NEXT_ULONG( p ); + nSubtables = FT_NEXT_ULONG( p ); + + /* feature-array of morx is same with that of mort */ + gxv_mort_featurearray_validate( p, limit, nFeatureFlags, gxvalid ); + p += gxvalid->subtable_length; + + if ( nSubtables >= 0x10000L ) + FT_INVALID_DATA; + + gxv_morx_subtables_validate( p, table + chainLength, + (FT_UShort)nSubtables, gxvalid ); + + gxvalid->subtable_length = chainLength; + + /* TODO: defaultFlags should be compared with the flags in tables */ + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_morx_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_ULong version; + FT_ULong nChains; + FT_ULong i; + + + gxvalid->root = ftvalid; + gxvalid->face = face; + + FT_TRACE3(( "validating `morx' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 4 ); + version = FT_NEXT_ULONG( p ); + nChains = FT_NEXT_ULONG( p ); + + if ( version != 0x00020000UL ) + FT_INVALID_FORMAT; + + for ( i = 0; i < nChains; i++ ) + { + GXV_TRACE(( "validating chain %lu/%lu\n", i + 1, nChains )); + GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); + gxv_morx_chain_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmorx.h b/vendor/freetype/src/gxvalid/gxvmorx.h new file mode 100644 index 0000000..2757255 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmorx.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * + * gxvmorx.h + * + * TrueTypeGX/AAT common definition for morx table (specification). + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVMORX_H_ +#define GXVMORX_H_ + + +#include "gxvalid.h" +#include "gxvcommn.h" +#include "gxvmort.h" + +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + gxv_morx_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + +FT_END_HEADER + +#endif /* GXVMORX_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmorx0.c b/vendor/freetype/src/gxvalid/gxvmorx0.c new file mode 100644 index 0000000..73523f3 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmorx0.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * + * gxvmorx0.c + * + * TrueTypeGX/AAT morx table validation + * body for type0 (Indic Script Rearrangement) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + static void + gxv_morx_subtable_type0_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_XStateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort markFirst; + FT_UShort dontAdvance; + FT_UShort markLast; +#endif + FT_UShort reserved; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort verb; +#endif + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + markFirst = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markLast = (FT_UShort)( ( flags >> 13 ) & 1 ); +#endif + + reserved = (FT_UShort)( flags & 0x1FF0 ); +#ifdef GXV_LOAD_UNUSED_VARS + verb = (FT_UShort)( flags & 0x000F ); +#endif + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + FT_INVALID_DATA; + } + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( + "morx chain subtable type0 (Indic-Script Rearrangement)" ); + + GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE ); + + gxvalid->xstatetable.optdata = NULL; + gxvalid->xstatetable.optdata_load_func = NULL; + gxvalid->xstatetable.subtable_setup_func = NULL; + gxvalid->xstatetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type0_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmorx1.c b/vendor/freetype/src/gxvalid/gxvmorx1.c new file mode 100644 index 0000000..71a2018 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmorx1.c @@ -0,0 +1,278 @@ +/**************************************************************************** + * + * gxvmorx1.c + * + * TrueTypeGX/AAT morx table validation + * body for type1 (Contextual Substitution) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + typedef struct GXV_morx_subtable_type1_StateOptRec_ + { + FT_ULong substitutionTable; + FT_ULong substitutionTable_length; + FT_UShort substitutionTable_num_lookupTables; + + } GXV_morx_subtable_type1_StateOptRec, + *GXV_morx_subtable_type1_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 ) + + + static void + gxv_morx_subtable_type1_substitutionTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->substitutionTable = FT_NEXT_USHORT( p ); + } + + + static void + gxv_morx_subtable_type1_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[4]; + FT_ULong *l[4]; + FT_ULong buff[5]; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->substitutionTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->substitutionTable_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + static void + gxv_morx_subtable_type1_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_TRACE_VARS + FT_UShort setMark; + FT_UShort dontAdvance; +#endif + FT_UShort reserved; + FT_Short markIndex; + FT_Short currentIndex; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + FT_UNUSED( state ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_TRACE_VARS + setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + + reserved = (FT_UShort)( flags & 0x3FFF ); + + markIndex = (FT_Short)( glyphOffset_p->ul >> 16 ); + currentIndex = (FT_Short)( glyphOffset_p->ul ); + + GXV_TRACE(( " setMark=%01d dontAdvance=%01d\n", + setMark, dontAdvance )); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + GXV_TRACE(( "markIndex = %d, currentIndex = %d\n", + markIndex, currentIndex )); + + if ( optdata->substitutionTable_num_lookupTables < markIndex + 1 ) + optdata->substitutionTable_num_lookupTables = + (FT_UShort)( markIndex + 1 ); + + if ( optdata->substitutionTable_num_lookupTables < currentIndex + 1 ) + optdata->substitutionTable_num_lookupTables = + (FT_UShort)( currentIndex + 1 ); + } + + + static void + gxv_morx_subtable_type1_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); /* for the non-debugging case */ + + GXV_TRACE(( "morx subtable type1 subst.: %d -> %d\n", glyph, value_p->u )); + + if ( value_p->u > gxvalid->face->num_glyphs ) + FT_INVALID_GLYPH_ID; + } + + + static GXV_LookupValueDesc + gxv_morx_subtable_type1_LookupFmt4_transit( + FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /* + * TODO: length should be limit? + **/ + static void + gxv_morx_subtable_type1_substitutionTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + + /* TODO: calculate offset/length for each lookupTables */ + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_morx_subtable_type1_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_morx_subtable_type1_LookupFmt4_transit; + + for ( i = 0; i < optdata->substitutionTable_num_lookupTables; i++ ) + { + FT_ULong offset; + + + GXV_LIMIT_CHECK( 4 ); + offset = FT_NEXT_ULONG( p ); + + gxv_LookupTable_validate( table + offset, limit, gxvalid ); + } + + /* TODO: overlapping of lookupTables in substitutionTable */ + } + + + /* + * subtable for Contextual glyph substitution is a modified StateTable. + * In addition to classTable, stateArray, entryTable, the field + * `substitutionTable' is added. + */ + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type1_StateOptRec st_rec; + + + GXV_NAME_ENTER( "morx chain subtable type1 (Contextual Glyph Subst)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE ); + + st_rec.substitutionTable_num_lookupTables = 0; + + gxvalid->xstatetable.optdata = + &st_rec; + gxvalid->xstatetable.optdata_load_func = + gxv_morx_subtable_type1_substitutionTable_load; + gxvalid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type1_subtable_setup; + gxvalid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type1_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + + gxv_morx_subtable_type1_substitutionTable_validate( + table + st_rec.substitutionTable, + table + st_rec.substitutionTable + st_rec.substitutionTable_length, + gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmorx2.c b/vendor/freetype/src/gxvalid/gxvmorx2.c new file mode 100644 index 0000000..858c811 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmorx2.c @@ -0,0 +1,331 @@ +/**************************************************************************** + * + * gxvmorx2.c + * + * TrueTypeGX/AAT morx table validation + * body for type2 (Ligature Substitution) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + typedef struct GXV_morx_subtable_type2_StateOptRec_ + { + FT_ULong ligActionTable; + FT_ULong componentTable; + FT_ULong ligatureTable; + FT_ULong ligActionTable_length; + FT_ULong componentTable_length; + FT_ULong ligatureTable_length; + + } GXV_morx_subtable_type2_StateOptRec, + *GXV_morx_subtable_type2_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE \ + ( GXV_XSTATETABLE_HEADER_SIZE + 4 + 4 + 4 ) + + + static void + gxv_morx_subtable_type2_opttable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 ); + optdata->ligActionTable = FT_NEXT_ULONG( p ); + optdata->componentTable = FT_NEXT_ULONG( p ); + optdata->ligatureTable = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "offset to ligActionTable=0x%08lx\n", + optdata->ligActionTable )); + GXV_TRACE(( "offset to componentTable=0x%08lx\n", + optdata->componentTable )); + GXV_TRACE(( "offset to ligatureTable=0x%08lx\n", + optdata->ligatureTable )); + } + + + static void + gxv_morx_subtable_type2_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[6]; + FT_ULong* l[6]; + FT_ULong buff[7]; + + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_NAME_ENTER( "subtable boundaries setup" ); + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->ligActionTable; + o[4] = optdata->componentTable; + o[5] = optdata->ligatureTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->ligActionTable_length); + l[4] = &(optdata->componentTable_length); + l[5] = &(optdata->ligatureTable_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 6, table_size, gxvalid ); + + GXV_TRACE(( "classTable: offset=0x%08lx length=0x%08lx\n", + classTable, *classTable_length_p )); + GXV_TRACE(( "stateArray: offset=0x%08lx length=0x%08lx\n", + stateArray, *stateArray_length_p )); + GXV_TRACE(( "entryTable: offset=0x%08lx length=0x%08lx\n", + entryTable, *entryTable_length_p )); + GXV_TRACE(( "ligActionTable: offset=0x%08lx length=0x%08lx\n", + optdata->ligActionTable, + optdata->ligActionTable_length )); + GXV_TRACE(( "componentTable: offset=0x%08lx length=0x%08lx\n", + optdata->componentTable, + optdata->componentTable_length )); + GXV_TRACE(( "ligatureTable: offset=0x%08lx length=0x%08lx\n", + optdata->ligatureTable, + optdata->ligatureTable_length )); + + GXV_EXIT; + } + + +#define GXV_MORX_LIGACTION_ENTRY_SIZE 4 + + + static void + gxv_morx_subtable_type2_ligActionIndex_validate( + FT_Bytes table, + FT_UShort ligActionIndex, + GXV_Validator gxvalid ) + { + /* access ligActionTable */ + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + FT_Bytes lat_base = table + optdata->ligActionTable; + FT_Bytes p = lat_base + + ligActionIndex * GXV_MORX_LIGACTION_ENTRY_SIZE; + FT_Bytes lat_limit = lat_base + optdata->ligActionTable; + + + if ( p < lat_base ) + { + GXV_TRACE(( "p < lat_base (%ld byte rewind)\n", lat_base - p )); + FT_INVALID_OFFSET; + } + else if ( lat_limit < p ) + { + GXV_TRACE(( "lat_limit < p (%ld byte overrun)\n", p - lat_limit )); + FT_INVALID_OFFSET; + } + + { + /* validate entry in ligActionTable */ + FT_ULong lig_action; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort last; + FT_UShort store; +#endif + FT_ULong offset; + FT_Long gid_limit; + + + lig_action = FT_NEXT_ULONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + last = (FT_UShort)( ( lig_action >> 31 ) & 1 ); + store = (FT_UShort)( ( lig_action >> 30 ) & 1 ); +#endif + + offset = lig_action & 0x3FFFFFFFUL; + + /* this offset is 30-bit signed value to add to GID */ + /* it is different from the location offset in mort */ + if ( ( offset & 0x3FFF0000UL ) == 0x3FFF0000UL ) + { /* negative offset */ + gid_limit = gxvalid->face->num_glyphs - + (FT_Long)( offset & 0x0000FFFFUL ); + if ( gid_limit > 0 ) + return; + + GXV_TRACE(( "ligature action table includes" + " too negative offset moving all GID" + " below defined range: 0x%04lx\n", + offset & 0xFFFFU )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + else if ( ( offset & 0x3FFF0000UL ) == 0x00000000UL ) + { /* positive offset */ + if ( (FT_Long)offset < gxvalid->face->num_glyphs ) + return; + + GXV_TRACE(( "ligature action table includes" + " too large offset moving all GID" + " over defined range: 0x%04lx\n", + offset & 0xFFFFU )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + + GXV_TRACE(( "ligature action table includes" + " invalid offset to add to 16-bit GID:" + " 0x%08lx\n", offset )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + } + + + static void + gxv_morx_subtable_type2_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort setComponent; + FT_UShort dontAdvance; + FT_UShort performAction; +#endif + FT_UShort reserved; + FT_UShort ligActionIndex; + + FT_UNUSED( state ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setComponent = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + performAction = (FT_UShort)( ( flags >> 13 ) & 1 ); +#endif + + reserved = (FT_UShort)( flags & 0x1FFF ); + ligActionIndex = glyphOffset_p->u; + + if ( reserved > 0 ) + GXV_TRACE(( " reserved 14bit is non-zero\n" )); + + if ( 0 < ligActionIndex ) + gxv_morx_subtable_type2_ligActionIndex_validate( + table, ligActionIndex, gxvalid ); + } + + + static void + gxv_morx_subtable_type2_ligatureTable_validate( FT_Bytes table, + GXV_Validator gxvalid ) + { + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + FT_Bytes p = table + optdata->ligatureTable; + FT_Bytes limit = table + optdata->ligatureTable + + optdata->ligatureTable_length; + + + GXV_NAME_ENTER( "morx chain subtable type2 - substitutionTable" ); + + if ( 0 != optdata->ligatureTable ) + { + /* Apple does not give specification of ligatureTable format */ + while ( p < limit ) + { + FT_UShort lig_gid; + + + GXV_LIMIT_CHECK( 2 ); + lig_gid = FT_NEXT_USHORT( p ); + if ( lig_gid < gxvalid->face->num_glyphs ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + } + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type2_StateOptRec lig_rec; + + + GXV_NAME_ENTER( "morx chain subtable type2 (Ligature Substitution)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE ); + + gxvalid->xstatetable.optdata = + &lig_rec; + gxvalid->xstatetable.optdata_load_func = + gxv_morx_subtable_type2_opttable_load; + gxvalid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type2_subtable_setup; + gxvalid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_USHORT; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type2_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + +#if 0 + p += gxvalid->subtable_length; +#endif + gxv_morx_subtable_type2_ligatureTable_validate( table, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmorx4.c b/vendor/freetype/src/gxvalid/gxvmorx4.c new file mode 100644 index 0000000..c9ad199 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmorx4.c @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * gxvmorx4.c + * + * TrueTypeGX/AAT morx table validation + * body for "morx" type4 (Non-Contextual Glyph Substitution) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + GXV_NAME_ENTER( "morx chain subtable type4 " + "(Non-Contextual Glyph Substitution)" ); + + gxv_mort_subtable_type4_validate( table, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvmorx5.c b/vendor/freetype/src/gxvalid/gxvmorx5.c new file mode 100644 index 0000000..95fa4e2 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvmorx5.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * + * gxvmorx5.c + * + * TrueTypeGX/AAT morx table validation + * body for type5 (Contextual Glyph Insertion) subtable. + * + * Copyright (C) 2005-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + /* + * `morx' subtable type5 (Contextual Glyph Insertion) + * has format of a StateTable with insertion-glyph-list + * without name. However, the 32bit offset from the head + * of subtable to the i-g-l is given after `entryTable', + * without variable name specification (the existence of + * this offset to the table is different from mort type5). + */ + + + typedef struct GXV_morx_subtable_type5_StateOptRec_ + { + FT_ULong insertionGlyphList; + FT_ULong insertionGlyphList_length; + + } GXV_morx_subtable_type5_StateOptRec, + *GXV_morx_subtable_type5_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 4 ) + + + static void + gxv_morx_subtable_type5_insertionGlyphList_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type5_StateOptRecData optdata = + (GXV_morx_subtable_type5_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 4 ); + optdata->insertionGlyphList = FT_NEXT_ULONG( p ); + } + + + static void + gxv_morx_subtable_type5_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[4]; + FT_ULong* l[4]; + FT_ULong buff[5]; + + GXV_morx_subtable_type5_StateOptRecData optdata = + (GXV_morx_subtable_type5_StateOptRecData)gxvalid->xstatetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->insertionGlyphList; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->insertionGlyphList_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + static void + gxv_morx_subtable_type5_InsertList_validate( FT_UShort table_index, + FT_UShort count, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table + table_index * 2; + + +#ifndef GXV_LOAD_TRACE_VARS + GXV_LIMIT_CHECK( count * 2 ); +#else + while ( p < table + count * 2 + table_index * 2 ) + { + FT_UShort insert_glyphID; + + + GXV_LIMIT_CHECK( 2 ); + insert_glyphID = FT_NEXT_USHORT( p ); + GXV_TRACE(( " 0x%04x", insert_glyphID )); + } + + GXV_TRACE(( "\n" )); +#endif + } + + + static void + gxv_morx_subtable_type5_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_Bool setMark; + FT_Bool dontAdvance; + FT_Bool currentIsKashidaLike; + FT_Bool markedIsKashidaLike; + FT_Bool currentInsertBefore; + FT_Bool markedInsertBefore; +#endif + FT_Byte currentInsertCount; + FT_Byte markedInsertCount; + FT_Byte currentInsertList; + FT_UShort markedInsertList; + + FT_UNUSED( state ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setMark = FT_BOOL( ( flags >> 15 ) & 1 ); + dontAdvance = FT_BOOL( ( flags >> 14 ) & 1 ); + currentIsKashidaLike = FT_BOOL( ( flags >> 13 ) & 1 ); + markedIsKashidaLike = FT_BOOL( ( flags >> 12 ) & 1 ); + currentInsertBefore = FT_BOOL( ( flags >> 11 ) & 1 ); + markedInsertBefore = FT_BOOL( ( flags >> 10 ) & 1 ); +#endif + + currentInsertCount = (FT_Byte)( ( flags >> 5 ) & 0x1F ); + markedInsertCount = (FT_Byte)( flags & 0x001F ); + + currentInsertList = (FT_Byte) ( glyphOffset_p->ul >> 16 ); + markedInsertList = (FT_UShort)( glyphOffset_p->ul ); + + if ( currentInsertList && 0 != currentInsertCount ) + gxv_morx_subtable_type5_InsertList_validate( currentInsertList, + currentInsertCount, + table, limit, + gxvalid ); + + if ( markedInsertList && 0 != markedInsertCount ) + gxv_morx_subtable_type5_InsertList_validate( markedInsertList, + markedInsertCount, + table, limit, + gxvalid ); + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type5_StateOptRec et_rec; + GXV_morx_subtable_type5_StateOptRecData et = &et_rec; + + + GXV_NAME_ENTER( "morx chain subtable type5 (Glyph Insertion)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE ); + + gxvalid->xstatetable.optdata = + et; + gxvalid->xstatetable.optdata_load_func = + gxv_morx_subtable_type5_insertionGlyphList_load; + gxvalid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type5_subtable_setup; + gxvalid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type5_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvopbd.c b/vendor/freetype/src/gxvalid/gxvopbd.c new file mode 100644 index 0000000..5e9a966 --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvopbd.c @@ -0,0 +1,218 @@ +/**************************************************************************** + * + * gxvopbd.c + * + * TrueTypeGX/AAT opbd table validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvopbd + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_opbd_DataRec_ + { + FT_UShort format; + FT_UShort valueOffset_min; + + } GXV_opbd_DataRec, *GXV_opbd_Data; + + +#define GXV_OPBD_DATA( FIELD ) GXV_TABLE_DATA( opbd, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_opbd_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + /* offset in LookupTable is measured from the head of opbd table */ + FT_Bytes p = gxvalid->root->base + value_p->u; + FT_Bytes limit = gxvalid->root->limit; + FT_Short delta_value; + int i; + + + if ( value_p->u < GXV_OPBD_DATA( valueOffset_min ) ) + GXV_OPBD_DATA( valueOffset_min ) = value_p->u; + + for ( i = 0; i < 4; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + delta_value = FT_NEXT_SHORT( p ); + + if ( GXV_OPBD_DATA( format ) ) /* format 1, value is ctrl pt. */ + { + if ( delta_value == -1 ) + continue; + + gxv_ctlPoint_validate( glyph, (FT_UShort)delta_value, gxvalid ); + } + else /* format 0, value is distance */ + continue; + } + } + + + /* + opbd ---------------------+ + | + +===============+ | + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of opbd sfnt table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 4 * sizeof(FT_Short) [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 48bit value array | + +===============+ | + | value | <-------+ + | | + | | + | | + +---------------+ + .... */ + + static GXV_LookupValueDesc + gxv_opbd_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + GXV_LookupValueDesc value; + + FT_UNUSED( lookuptbl_limit ); + FT_UNUSED( gxvalid ); + + /* XXX: check range? */ + value.u = (FT_UShort)( base_value_p->u + + relative_gindex * 4 * sizeof ( FT_Short ) ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** opbd TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_opbd_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + GXV_opbd_DataRec opbdrec; + GXV_opbd_Data opbd = &opbdrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong version; + + + gxvalid->root = ftvalid; + gxvalid->table_data = opbd; + gxvalid->face = face; + + FT_TRACE3(( "validating `opbd' table\n" )); + GXV_INIT; + GXV_OPBD_DATA( valueOffset_min ) = 0xFFFFU; + + + GXV_LIMIT_CHECK( 4 + 2 ); + version = FT_NEXT_ULONG( p ); + GXV_OPBD_DATA( format ) = FT_NEXT_USHORT( p ); + + + /* only 0x00010000 is defined (1996) */ + GXV_TRACE(( "(version=0x%08lx)\n", version )); + if ( 0x00010000UL != version ) + FT_INVALID_FORMAT; + + /* only values 0 and 1 are defined (1996) */ + GXV_TRACE(( "(format=0x%04x)\n", GXV_OPBD_DATA( format ) )); + if ( 0x0001 < GXV_OPBD_DATA( format ) ) + FT_INVALID_FORMAT; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_opbd_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_opbd_LookupFmt4_transit; + + gxv_LookupTable_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + if ( p > table + GXV_OPBD_DATA( valueOffset_min ) ) + { + GXV_TRACE(( + "found overlap between LookupTable and opbd_value array\n" )); + FT_INVALID_OFFSET; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvprop.c b/vendor/freetype/src/gxvalid/gxvprop.c new file mode 100644 index 0000000..63a052a --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvprop.c @@ -0,0 +1,330 @@ +/**************************************************************************** + * + * gxvprop.c + * + * TrueTypeGX/AAT prop table validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvprop + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_PROP_HEADER_SIZE ( 4 + 2 + 2 ) +#define GXV_PROP_SIZE_MIN GXV_PROP_HEADER_SIZE + + typedef struct GXV_prop_DataRec_ + { + FT_Fixed version; + + } GXV_prop_DataRec, *GXV_prop_Data; + +#define GXV_PROP_DATA( field ) GXV_TABLE_DATA( prop, field ) + +#define GXV_PROP_FLOATER 0x8000U +#define GXV_PROP_USE_COMPLEMENTARY_BRACKET 0x1000U +#define GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET 0x0F00U +#define GXV_PROP_ATTACHING_TO_RIGHT 0x0080U +#define GXV_PROP_RESERVED 0x0060U +#define GXV_PROP_DIRECTIONALITY_CLASS 0x001FU + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_prop_zero_advance_validate( FT_UShort gid, + GXV_Validator gxvalid ) + { + FT_Face face; + FT_Error error; + FT_GlyphSlot glyph; + + + GXV_NAME_ENTER( "zero advance" ); + + face = gxvalid->face; + + error = FT_Load_Glyph( face, + gid, + FT_LOAD_IGNORE_TRANSFORM ); + if ( error ) + FT_INVALID_GLYPH_ID; + + glyph = face->glyph; + + if ( glyph->advance.x != (FT_Pos)0 || + glyph->advance.y != (FT_Pos)0 ) + { + GXV_TRACE(( " found non-zero advance in zero-advance glyph\n" )); + FT_INVALID_DATA; + } + + GXV_EXIT; + } + + + /* Pass 0 as GLYPH to check the default property */ + static void + gxv_prop_property_validate( FT_UShort property, + FT_UShort glyph, + GXV_Validator gxvalid ) + { + if ( glyph != 0 && ( property & GXV_PROP_FLOATER ) ) + gxv_prop_zero_advance_validate( glyph, gxvalid ); + + if ( property & GXV_PROP_USE_COMPLEMENTARY_BRACKET ) + { + FT_UShort offset; + char complement; + + + offset = (FT_UShort)( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ); + if ( offset == 0 ) + { + GXV_TRACE(( " found zero offset to property\n" )); + FT_INVALID_OFFSET; + } + + complement = (char)( offset >> 8 ); + if ( complement & 0x08 ) + { + /* Top bit is set: negative */ + + /* Calculate the absolute offset */ + complement = (char)( ( complement & 0x07 ) + 1 ); + + /* The gid for complement must be greater than 0 */ + if ( glyph <= complement ) + { + GXV_TRACE(( " found non-positive glyph complement\n" )); + FT_INVALID_DATA; + } + } + else + { + /* The gid for complement must be the face. */ + gxv_glyphid_validate( (FT_UShort)( glyph + complement ), gxvalid ); + } + } + else + { + if ( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ) + GXV_TRACE(( "glyph %d cannot have complementary bracketing\n", + glyph )); + } + + /* this is introduced in version 2.0 */ + if ( property & GXV_PROP_ATTACHING_TO_RIGHT ) + { + if ( GXV_PROP_DATA( version ) == 0x00010000UL ) + { + GXV_TRACE(( " found older version (1.0) in new version table\n" )); + FT_INVALID_DATA; + } + } + + if ( property & GXV_PROP_RESERVED ) + { + GXV_TRACE(( " found non-zero bits in reserved bits\n" )); + FT_INVALID_DATA; + } + + if ( ( property & GXV_PROP_DIRECTIONALITY_CLASS ) > 11 ) + { + /* TODO: Too restricted. Use the validation level. */ + if ( GXV_PROP_DATA( version ) == 0x00010000UL || + GXV_PROP_DATA( version ) == 0x00020000UL ) + { + GXV_TRACE(( " found too old version in directionality class\n" )); + FT_INVALID_DATA; + } + } + } + + + static void + gxv_prop_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + gxv_prop_property_validate( value_p->u, glyph, gxvalid ); + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + ... | + | + 16bit value array | + +===============+ | + | value | <-------+ + ... + */ + + static GXV_LookupValueDesc + gxv_prop_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** prop TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_prop_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_prop_DataRec proprec; + GXV_prop_Data prop = &proprec; + + FT_Fixed version; + FT_UShort format; + FT_UShort defaultProp; + + + gxvalid->root = ftvalid; + gxvalid->table_data = prop; + gxvalid->face = face; + + FT_TRACE3(( "validating `prop' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + version = FT_NEXT_LONG( p ); + format = FT_NEXT_USHORT( p ); + defaultProp = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " version 0x%08lx\n", version )); + GXV_TRACE(( " format 0x%04x\n", format )); + GXV_TRACE(( " defaultProp 0x%04x\n", defaultProp )); + + /* only versions 1.0, 2.0, 3.0 are defined (1996) */ + if ( version != 0x00010000UL && + version != 0x00020000UL && + version != 0x00030000UL ) + { + GXV_TRACE(( " found unknown version\n" )); + FT_INVALID_FORMAT; + } + + + /* only formats 0x0000, 0x0001 are defined (1996) */ + if ( format > 1 ) + { + GXV_TRACE(( " found unknown format\n" )); + FT_INVALID_FORMAT; + } + + gxv_prop_property_validate( defaultProp, 0, gxvalid ); + + if ( format == 0 ) + { + FT_TRACE3(( "(format 0, no per-glyph properties, " + "remaining %ld bytes are skipped)", limit - p )); + goto Exit; + } + + /* format == 1 */ + GXV_PROP_DATA( version ) = version; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_prop_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_prop_LookupFmt4_transit; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + Exit: + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/gxvtrak.c b/vendor/freetype/src/gxvalid/gxvtrak.c new file mode 100644 index 0000000..f3fb51c --- /dev/null +++ b/vendor/freetype/src/gxvalid/gxvtrak.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * + * gxvtrak.c + * + * TrueTypeGX/AAT trak table validation (body). + * + * Copyright (C) 2004-2023 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvtrak + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * referred track table format specification: + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html + * last update was 1996. + * ---------------------------------------------- + * [MINIMUM HEADER]: GXV_TRAK_SIZE_MIN + * version (fixed: 32bit) = 0x00010000 + * format (uint16: 16bit) = 0 is only defined (1996) + * horizOffset (uint16: 16bit) + * vertOffset (uint16: 16bit) + * reserved (uint16: 16bit) = 0 + * ---------------------------------------------- + * [VARIABLE BODY]: + * horizData + * header ( 2 + 2 + 4 + * trackTable + nTracks * ( 4 + 2 + 2 ) + * sizeTable + nSizes * 4 ) + * ---------------------------------------------- + * vertData + * header ( 2 + 2 + 4 + * trackTable + nTracks * ( 4 + 2 + 2 ) + * sizeTable + nSizes * 4 ) + * ---------------------------------------------- + */ + typedef struct GXV_trak_DataRec_ + { + FT_UShort trackValueOffset_min; + FT_UShort trackValueOffset_max; + + } GXV_trak_DataRec, *GXV_trak_Data; + + +#define GXV_TRAK_DATA( FIELD ) GXV_TABLE_DATA( trak, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_trak_trackTable_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nTracks, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + FT_Fixed track, t; + FT_UShort nameIndex; + FT_UShort offset; + FT_UShort i, j; + + + GXV_NAME_ENTER( "trackTable" ); + + GXV_TRAK_DATA( trackValueOffset_min ) = 0xFFFFU; + GXV_TRAK_DATA( trackValueOffset_max ) = 0x0000; + + GXV_LIMIT_CHECK( nTracks * ( 4 + 2 + 2 ) ); + + for ( i = 0; i < nTracks; i++ ) + { + p = table + i * ( 4 + 2 + 2 ); + track = FT_NEXT_LONG( p ); + nameIndex = FT_NEXT_USHORT( p ); + offset = FT_NEXT_USHORT( p ); + + if ( offset < GXV_TRAK_DATA( trackValueOffset_min ) ) + GXV_TRAK_DATA( trackValueOffset_min ) = offset; + if ( offset > GXV_TRAK_DATA( trackValueOffset_max ) ) + GXV_TRAK_DATA( trackValueOffset_max ) = offset; + + gxv_sfntName_validate( nameIndex, 256, 32767, gxvalid ); + + for ( j = i; j < nTracks; j++ ) + { + p = table + j * ( 4 + 2 + 2 ); + t = FT_NEXT_LONG( p ); + if ( t == track ) + GXV_TRACE(( "duplicated entries found for track value 0x%lx\n", + track )); + } + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + static void + gxv_trak_trackData_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort nTracks; + FT_UShort nSizes; + FT_ULong sizeTableOffset; + + GXV_ODTECT( 4, odtect ); + + + GXV_ODTECT_INIT( odtect ); + GXV_NAME_ENTER( "trackData" ); + + /* read the header of trackData */ + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + nTracks = FT_NEXT_USHORT( p ); + nSizes = FT_NEXT_USHORT( p ); + sizeTableOffset = FT_NEXT_ULONG( p ); + + gxv_odtect_add_range( table, (FT_ULong)( p - table ), + "trackData header", odtect ); + + /* validate trackTable */ + gxv_trak_trackTable_validate( p, limit, nTracks, gxvalid ); + gxv_odtect_add_range( p, gxvalid->subtable_length, + "trackTable", odtect ); + + /* sizeTable is array of FT_Fixed, don't check contents */ + p = gxvalid->root->base + sizeTableOffset; + GXV_LIMIT_CHECK( nSizes * 4 ); + gxv_odtect_add_range( p, nSizes * 4, "sizeTable", odtect ); + + /* validate trackValueOffet */ + p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_min ); + if ( limit - p < nTracks * nSizes * 2 ) + GXV_TRACE(( "too short trackValue array\n" )); + + p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_max ); + GXV_LIMIT_CHECK( nSizes * 2 ); + + gxv_odtect_add_range( gxvalid->root->base + + GXV_TRAK_DATA( trackValueOffset_min ), + GXV_TRAK_DATA( trackValueOffset_max ) + - GXV_TRAK_DATA( trackValueOffset_min ) + + nSizes * 2, + "trackValue array", odtect ); + + gxv_odtect_validate( odtect, gxvalid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** trak TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_trak_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + GXV_trak_DataRec trakrec; + GXV_trak_Data trak = &trakrec; + + FT_ULong version; + FT_UShort format; + FT_UShort horizOffset; + FT_UShort vertOffset; + FT_UShort reserved; + + + GXV_ODTECT( 3, odtect ); + + GXV_ODTECT_INIT( odtect ); + gxvalid->root = ftvalid; + gxvalid->table_data = trak; + gxvalid->face = face; + + limit = gxvalid->root->limit; + + FT_TRACE3(( "validating `trak' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + horizOffset = FT_NEXT_USHORT( p ); + vertOffset = FT_NEXT_USHORT( p ); + reserved = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (version = 0x%08lx)\n", version )); + GXV_TRACE(( " (format = 0x%04x)\n", format )); + GXV_TRACE(( " (horizOffset = 0x%04x)\n", horizOffset )); + GXV_TRACE(( " (vertOffset = 0x%04x)\n", vertOffset )); + GXV_TRACE(( " (reserved = 0x%04x)\n", reserved )); + + /* Version 1.0 (always:1996) */ + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* format 0 (always:1996) */ + if ( format != 0x0000 ) + FT_INVALID_FORMAT; + + GXV_32BIT_ALIGNMENT_VALIDATE( horizOffset ); + GXV_32BIT_ALIGNMENT_VALIDATE( vertOffset ); + + /* Reserved Fixed Value (always) */ + if ( reserved != 0x0000 ) + FT_INVALID_DATA; + + /* validate trackData */ + if ( 0 < horizOffset ) + { + gxv_trak_trackData_validate( table + horizOffset, limit, gxvalid ); + gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length, + "horizJustData", odtect ); + } + + if ( 0 < vertOffset ) + { + gxv_trak_trackData_validate( table + vertOffset, limit, gxvalid ); + gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length, + "vertJustData", odtect ); + } + + gxv_odtect_validate( odtect, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/gxvalid/module.mk b/vendor/freetype/src/gxvalid/module.mk new file mode 100644 index 0000000..4949134 --- /dev/null +++ b/vendor/freetype/src/gxvalid/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 gxvalid module definition +# + +# Copyright (C) 2004-2023 by +# suzuki toshiya, Masatake YAMATO, Red Hat K.K., +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += GXVALID_MODULE + +define GXVALID_MODULE +$(OPEN_DRIVER) FT_Module_Class, gxv_module_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)gxvalid $(ECHO_DRIVER_DESC)TrueTypeGX/AAT validation module$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/gxvalid/rules.mk b/vendor/freetype/src/gxvalid/rules.mk new file mode 100644 index 0000000..95ae633 --- /dev/null +++ b/vendor/freetype/src/gxvalid/rules.mk @@ -0,0 +1,98 @@ +# +# FreeType 2 TrueTypeGX/AAT validation driver configuration rules +# + + +# Copyright (C) 2004-2023 by +# suzuki toshiya, Masatake YAMATO, Red Hat K.K., +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# GXV driver directory +# +GXV_DIR := $(SRC_DIR)/gxvalid + + +# compilation flags for the driver +# +GXV_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(GXV_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# GXV driver sources (i.e., C files) +# +GXV_DRV_SRC := $(GXV_DIR)/gxvcommn.c \ + $(GXV_DIR)/gxvfeat.c \ + $(GXV_DIR)/gxvbsln.c \ + $(GXV_DIR)/gxvtrak.c \ + $(GXV_DIR)/gxvopbd.c \ + $(GXV_DIR)/gxvprop.c \ + $(GXV_DIR)/gxvjust.c \ + $(GXV_DIR)/gxvmort.c \ + $(GXV_DIR)/gxvmort0.c \ + $(GXV_DIR)/gxvmort1.c \ + $(GXV_DIR)/gxvmort2.c \ + $(GXV_DIR)/gxvmort4.c \ + $(GXV_DIR)/gxvmort5.c \ + $(GXV_DIR)/gxvmorx.c \ + $(GXV_DIR)/gxvmorx0.c \ + $(GXV_DIR)/gxvmorx1.c \ + $(GXV_DIR)/gxvmorx2.c \ + $(GXV_DIR)/gxvmorx4.c \ + $(GXV_DIR)/gxvmorx5.c \ + $(GXV_DIR)/gxvlcar.c \ + $(GXV_DIR)/gxvkern.c \ + $(GXV_DIR)/gxvmod.c + +# GXV driver headers +# +GXV_DRV_H := $(GXV_DIR)/gxvalid.h \ + $(GXV_DIR)/gxverror.h \ + $(GXV_DIR)/gxvcommn.h \ + $(GXV_DIR)/gxvfeat.h \ + $(GXV_DIR)/gxvmod.h \ + $(GXV_DIR)/gxvmort.h \ + $(GXV_DIR)/gxvmorx.h + + +# GXV driver object(s) +# +# GXV_DRV_OBJ_M is used during `multi' builds. +# GXV_DRV_OBJ_S is used during `single' builds. +# +GXV_DRV_OBJ_M := $(GXV_DRV_SRC:$(GXV_DIR)/%.c=$(OBJ_DIR)/%.$O) +GXV_DRV_OBJ_S := $(OBJ_DIR)/gxvalid.$O + +# GXV driver source file for single build +# +GXV_DRV_SRC_S := $(GXV_DIR)/gxvalid.c + + +# GXV driver - single object +# +$(GXV_DRV_OBJ_S): $(GXV_DRV_SRC_S) $(GXV_DRV_SRC) \ + $(FREETYPE_H) $(GXV_DRV_H) + $(GXV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(GXV_DRV_SRC_S)) + + +# GXV driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(GXV_DIR)/%.c $(FREETYPE_H) $(GXV_DRV_H) + $(GXV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(GXV_DRV_OBJ_S) +DRV_OBJS_M += $(GXV_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/gzip/README.freetype b/vendor/freetype/src/gzip/README.freetype new file mode 100644 index 0000000..76298b0 --- /dev/null +++ b/vendor/freetype/src/gzip/README.freetype @@ -0,0 +1,23 @@ +Name: zlib +Short Name: zlib +URL: http://zlib.net/ +Version: 1.2.13 +License: see `zlib.h` + +Description: +"A massively spiffy yet delicately unobtrusive compression library." + +'zlib' is a free, general-purpose, legally unencumbered lossless +data-compression library. 'zlib' implements the "deflate" compression +algorithm described by RFC 1951, which combines the LZ77 (Lempel-Ziv) +algorithm with Huffman coding. zlib also implements the zlib (RFC 1950) and +gzip (RFC 1952) wrapper formats. + +Local Modifications: +The files in this directory have been prepared as follows. + + - Take the unmodified source code files from the zlib distribution that are + included by `ftgzip.c`. + - Copy `zconf.h` to `ftzconf.h` (which stays unmodified otherwise). + - Run zlib's `zlib2ansi` script on all `.c` files. + - Apply the diff file(s) in the `patches` folder. diff --git a/vendor/freetype/src/gzip/adler32.c b/vendor/freetype/src/gzip/adler32.c new file mode 100644 index 0000000..aa032e1 --- /dev/null +++ b/vendor/freetype/src/gzip/adler32.c @@ -0,0 +1,192 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef Z_FREETYPE +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); +#endif + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32_z( + uLong adler, + const Bytef *buf, + z_size_t len) +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32( + uLong adler, + const Bytef *buf, + uInt len) +{ + return adler32_z(adler, buf, len); +} + +#ifndef Z_FREETYPE + +/* ========================================================================= */ +local uLong adler32_combine_( + uLong adler1, + uLong adler2, + z_off64_t len2) +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine( + uLong adler1, + uLong adler2, + z_off_t len2) +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64( + uLong adler1, + uLong adler2, + z_off64_t len2) +{ + return adler32_combine_(adler1, adler2, len2); +} + +#endif /* !Z_FREETYPE */ diff --git a/vendor/freetype/src/gzip/crc32.c b/vendor/freetype/src/gzip/crc32.c new file mode 100644 index 0000000..6cd1b09 --- /dev/null +++ b/vendor/freetype/src/gzip/crc32.c @@ -0,0 +1,1135 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + MAKECRCH can be #defined to write out crc32.h. A main() routine is also + produced, so that this one source file can be compiled to an executable. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ + + /* + A CRC of a message is computed on N braids of words in the message, where + each word consists of W bytes (4 or 8). If N is 3, for example, then three + running sparse CRCs are calculated respectively on each braid, at these + indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... + This is done starting at a word boundary, and continues until as many blocks + of N * W bytes as are available have been processed. The results are combined + into a single CRC at the end. For this code, N must be in the range 1..6 and + W must be 4 or 8. The upper limit on N can be increased if desired by adding + more #if blocks, extending the patterns apparent in the code. In addition, + crc32.h would need to be regenerated, if the maximum N value is increased. + + N and W are chosen empirically by benchmarking the execution time on a given + processor. The choices for N and W below were based on testing on Intel Kaby + Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 + Octeon II processors. The Intel, AMD, and ARM processors were all fastest + with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. + They were all tested with either gcc or clang, all using the -O3 optimization + level. Your mileage may vary. + */ + +/* Define N */ +#ifdef Z_TESTN +# define N Z_TESTN +#else +# define N 5 +#endif +#if N < 1 || N > 6 +# error N must be in 1..6 +#endif + +/* + z_crc_t must be at least 32 bits. z_word_t must be at least as long as + z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and + that bytes are eight bits. + */ + +/* + Define W and the associated z_word_t type. If W is not defined, then a + braided calculation is not used, and the associated tables and code are not + compiled. + */ +#ifdef Z_TESTW +# if Z_TESTW-1 != -1 +# define W Z_TESTW +# endif +#else +# ifdef MAKECRCH +# define W 8 /* required for MAKECRCH */ +# else +# if defined(__x86_64__) || defined(__aarch64__) +# define W 8 +# else +# define W 4 +# endif +# endif +#endif +#ifdef W +# if W == 8 && defined(Z_U8) + typedef Z_U8 z_word_t; +# elif defined(Z_U4) +# undef W +# define W 4 + typedef Z_U4 z_word_t; +# else +# undef W +# endif +#endif + +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + +#ifndef Z_FREETYPE +/* Local functions. */ +local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); +local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); +#endif /* Z_FREETYPE */ + +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) + local z_word_t byte_swap OF((z_word_t word)); +#endif + +#if defined(W) && !defined(ARMCRC32) + local z_crc_t crc_word OF((z_word_t data)); + local z_word_t crc_word_big OF((z_word_t data)); +#endif + +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) +/* + Swap the bytes in a z_word_t to convert between little and big endian. Any + self-respecting compiler will optimize this to a single machine byte-swap + instruction, if one is available. This assumes that word_t is either 32 bits + or 64 bits. + */ +local z_word_t byte_swap( + z_word_t word) +{ +# if W == 8 + return + (word & 0xff00000000000000) >> 56 | + (word & 0xff000000000000) >> 40 | + (word & 0xff0000000000) >> 24 | + (word & 0xff00000000) >> 8 | + (word & 0xff000000) << 8 | + (word & 0xff0000) << 24 | + (word & 0xff00) << 40 | + (word & 0xff) << 56; +# else /* W == 4 */ + return + (word & 0xff000000) >> 24 | + (word & 0xff0000) >> 8 | + (word & 0xff00) << 8 | + (word & 0xff) << 24; +# endif +} +#endif + +/* CRC polynomial. */ +#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ + +#ifdef DYNAMIC_CRC_TABLE + +local z_crc_t FAR crc_table[256]; +local z_crc_t FAR x2n_table[32]; +local void make_crc_table OF((void)); +#ifdef W + local z_word_t FAR crc_big_table[256]; + local z_crc_t FAR crc_braid_table[W][256]; + local z_word_t FAR crc_braid_big_table[W][256]; + local void braid OF((z_crc_t [][256], z_word_t [][256], int, int)); +#endif +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *, int)); + local void write_table32hi OF((FILE *, const z_word_t FAR *, int)); + local void write_table64 OF((FILE *, const z_word_t FAR *, int)); +#endif /* MAKECRCH */ + +/* + Define a once() function depending on the availability of atomics. If this is + compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in + multiple threads, and if atomics are not available, then get_crc_table() must + be called to initialize the tables and must return before any threads are + allowed to compute or combine CRCs. + */ + +/* Definition of once functionality. */ +typedef struct once_s once_t; +local void once OF((once_t *, void (*)(void))); + +/* Check for the availability of atomics. */ +#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_ATOMICS__) + +#include + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + atomic_flag begun; + atomic_int done; +}; +#define ONCE_INIT {ATOMIC_FLAG_INIT, 0} + +/* + Run the provided init() function exactly once, even if multiple threads + invoke once() at the same time. The state must be a once_t initialized with + ONCE_INIT. + */ +local void once(state, init) + once_t *state; + void (*init)(void); +{ + if (!atomic_load(&state->done)) { + if (atomic_flag_test_and_set(&state->begun)) + while (!atomic_load(&state->done)) + ; + else { + init(); + atomic_store(&state->done, 1); + } + } +} + +#else /* no atomics */ + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + volatile int begun; + volatile int done; +}; +#define ONCE_INIT {0, 0} + +/* Test and set. Alas, not atomic, but tries to minimize the period of + vulnerability. */ +local int test_and_set OF((int volatile *)); +local int test_and_set( + int volatile *flag) +{ + int was; + + was = *flag; + *flag = 1; + return was; +} + +/* Run the provided init() function once. This is not thread-safe. */ +local void once(state, init) + once_t *state; + void (*init)(void); +{ + if (!state->done) { + if (test_and_set(&state->begun)) + while (!state->done) + ; + else { + init(); + state->done = 1; + } + } +} + +#endif + +/* State for once(). */ +local once_t made = ONCE_INIT; + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x + (which is shifting right by one and adding x^32 mod p if the bit shifted out + is a one). We start with the highest power (least significant bit) of q and + repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all the + information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. + */ + +local void make_crc_table() +{ + unsigned i, j, n; + z_crc_t p; + + /* initialize the CRC of bytes tables */ + for (i = 0; i < 256; i++) { + p = i; + for (j = 0; j < 8; j++) + p = p & 1 ? (p >> 1) ^ POLY : p >> 1; + crc_table[i] = p; +#ifdef W + crc_big_table[i] = byte_swap(p); +#endif + } + + /* initialize the x^2^n mod p(x) table */ + p = (z_crc_t)1 << 30; /* x^1 */ + x2n_table[0] = p; + for (n = 1; n < 32; n++) + x2n_table[n] = p = multmodp(p, p); + +#ifdef W + /* initialize the braiding tables -- needs x2n_table[] */ + braid(crc_braid_table, crc_braid_big_table, N, W); +#endif + +#ifdef MAKECRCH + { + /* + The crc32.h header file contains tables for both 32-bit and 64-bit + z_word_t's, and so requires a 64-bit type be available. In that case, + z_word_t must be defined to be 64-bits. This code then also generates + and writes out the tables for the case that z_word_t is 32 bits. + */ +#if !defined(W) || W != 8 +# error Need a 64-bit integer type in order to generate crc32.h. +#endif + FILE *out; + int k, n; + z_crc_t ltl[8][256]; + z_word_t big[8][256]; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + + /* write out little-endian CRC table to crc32.h */ + fprintf(out, + "/* crc32.h -- tables for rapid CRC calculation\n" + " * Generated automatically by crc32.c\n */\n" + "\n" + "local const z_crc_t FAR crc_table[] = {\n" + " "); + write_table(out, crc_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#ifdef W\n" + "\n" + "#if W == 8\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table64(out, crc_big_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table32hi(out, crc_big_table, 256); + fprintf(out, + "};\n" + "\n" + "#endif\n"); + + /* write out braid tables for each value of N */ + for (n = 1; n <= 6; n++) { + fprintf(out, + "\n" + "#if N == %d\n", n); + + /* compute braid tables for this N and 64-bit word_t */ + braid(ltl, big, n, 8); + + /* write out braid tables for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#if W == 8\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table64(out, big[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n"); + + /* compute braid tables for this N and 32-bit word_t */ + braid(ltl, big, n, 4); + + /* write out braid tables for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table32hi(out, big[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "#endif\n" + "\n" + "#endif\n"); + } + fprintf(out, + "\n" + "#endif\n"); + + /* write out zeros operator table to crc32.h */ + fprintf(out, + "\n" + "local const z_crc_t FAR x2n_table[] = {\n" + " "); + write_table(out, x2n_table, 32); + fprintf(out, + "};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH + +/* + Write the 32-bit values in table[0..k-1] to out, five per line in + hexadecimal separated by commas. + */ +local void write_table( + FILE *out, + const z_crc_t FAR *table, + int k) +{ + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the high 32-bits of each value in table[0..k-1] to out, five per line + in hexadecimal separated by commas. + */ +local void write_table32hi( + FILE *out, + const z_word_t FAR *table, + int k) +{ + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n] >> 32), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the 64-bit values in table[0..k-1] to out, three per line in + hexadecimal separated by commas. This assumes that if there is a 64-bit + type, then there is also a long long integer type, and it is at least 64 + bits. If not, then the type cast and format string can be adjusted + accordingly. + */ +local void write_table64( + FILE *out, + const z_word_t FAR *table, + int k) +{ + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", + (unsigned long long)(table[n]), + n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); +} + +/* Actually do the deed. */ +int main() +{ + make_crc_table(); + return 0; +} + +#endif /* MAKECRCH */ + +#ifdef W +/* + Generate the little and big-endian braid tables for the given n and z_word_t + size w. Each array must have room for w blocks of 256 elements. + */ +local void braid(ltl, big, n, w) + z_crc_t ltl[][256]; + z_word_t big[][256]; + int n; + int w; +{ + int k; + z_crc_t i, p, q; + for (k = 0; k < w; k++) { + p = x2nmodp((n * w + 3 - k) << 3, 0); + ltl[k][0] = 0; + big[w - 1 - k][0] = 0; + for (i = 1; i < 256; i++) { + ltl[k][i] = q = multmodp(i << 24, p); + big[w - 1 - k][i] = byte_swap(q); + } + } +} +#endif + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ======================================================================== + * Routines used for CRC calculation. Some are also required for the table + * generation above. + */ + +#ifndef Z_FREETYPE + +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp( + z_crc_t a, + z_crc_t b) +{ + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp( + z_off64_t n, + unsigned k) +{ + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +/* ========================================================================= + * This function can be used by asm versions of crc32(), and to force the + * generation of the CRC tables in a threaded application. + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +#endif /* Z_FREETYPE */ + +/* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for + * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will + * only be defined if the compilation specifies an ARM processor architecture + * that has the instructions. For example, compiling with -march=armv8.1-a or + * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 + * instructions. + */ +#ifdef ARMCRC32 + +/* + Constants empirically determined to maximize speed. These values are from + measurements on a Cortex-A57. Your mileage may vary. + */ +#define Z_BATCH 3990 /* number of words in a batch */ +#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ +#define Z_BATCH_MIN 800 /* fewest words in a final batch */ + +unsigned long ZEXPORT crc32_z( + unsigned long crc, + const unsigned char FAR *buf, + z_size_t len) +{ + z_crc_t val; + z_word_t crc1, crc2; + const z_word_t *word; + z_word_t val0, val1, val2; + z_size_t last, last2, i; + z_size_t num; + + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + + /* Compute the CRC up to a word boundary. */ + while (len && ((z_size_t)buf & 7) != 0) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ + word = (z_word_t const *)buf; + num = len >> 3; + len &= 7; + + /* Do three interleaved CRCs to realize the throughput of one crc32x + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ + while (num >= 3 * Z_BATCH) { + crc1 = 0; + crc2 = 0; + for (i = 0; i < Z_BATCH; i++) { + val0 = word[i]; + val1 = word[i + Z_BATCH]; + val2 = word[i + 2 * Z_BATCH]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * Z_BATCH; + num -= 3 * Z_BATCH; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; + } + + /* Do one last smaller batch with the remaining words, if there are enough + to pay for the combination of CRCs. */ + last = num / 3; + if (last >= Z_BATCH_MIN) { + last2 = last << 1; + crc1 = 0; + crc2 = 0; + for (i = 0; i < last; i++) { + val0 = word[i]; + val1 = word[i + last]; + val2 = word[i + last2]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * last; + num -= 3 * last; + val = x2nmodp(last, 6); + crc = multmodp(val, crc) ^ crc1; + crc = multmodp(val, crc) ^ crc2; + } + + /* Compute the CRC on any remaining words. */ + for (i = 0; i < num; i++) { + val0 = word[i]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + } + word += num; + + /* Complete the CRC on any remaining bytes. */ + buf = (const unsigned char FAR *)word; + while (len) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#else + +#ifdef W + +/* + Return the CRC of the W bytes in the word_t data, taking the + least-significant byte of the word as the first byte of data, without any pre + or post conditioning. This is used to combine the CRCs of each braid. + */ +local z_crc_t crc_word( + z_word_t data) +{ + int k; + for (k = 0; k < W; k++) + data = (data >> 8) ^ crc_table[data & 0xff]; + return (z_crc_t)data; +} + +local z_word_t crc_word_big( + z_word_t data) +{ + int k; + for (k = 0; k < W; k++) + data = (data << 8) ^ + crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; + return data; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32_z( + unsigned long crc, + const unsigned char FAR *buf, + z_size_t len) +{ + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + +#ifdef W + + /* If provided enough bytes, do a braided CRC calculation. */ + if (len >= N * W + W - 1) { + z_size_t blks; + z_word_t const *words; + unsigned endian; + int k; + + /* Compute the CRC up to a z_word_t boundary. */ + while (len && ((z_size_t)buf & (W - 1)) != 0) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Compute the CRC on as many N z_word_t blocks as are available. */ + blks = len / (N * W); + len -= blks * N * W; + words = (z_word_t const *)buf; + + /* Do endian check at execution time instead of compile time, since ARM + processors can change the endianess at execution time. If the + compiler knows what the endianess will be, it can optimize out the + check and the unused branch. */ + endian = 1; + if (*(unsigned char *)&endian) { + /* Little endian. */ + + z_crc_t crc0; + z_word_t word0; +#if N > 1 + z_crc_t crc1; + z_word_t word1; +#if N > 2 + z_crc_t crc2; + z_word_t word2; +#if N > 3 + z_crc_t crc3; + z_word_t word3; +#if N > 4 + z_crc_t crc4; + z_word_t word4; +#if N > 5 + z_crc_t crc5; + z_word_t word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = crc; +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + crc = crc_word(crc0 ^ words[0]); +#if N > 1 + crc = crc_word(crc1 ^ words[1] ^ crc); +#if N > 2 + crc = crc_word(crc2 ^ words[2] ^ crc); +#if N > 3 + crc = crc_word(crc3 ^ words[3] ^ crc); +#if N > 4 + crc = crc_word(crc4 ^ words[4] ^ crc); +#if N > 5 + crc = crc_word(crc5 ^ words[5] ^ crc); +#endif +#endif +#endif +#endif +#endif + words += N; + } + else { + /* Big endian. */ + + z_word_t crc0, word0, comb; +#if N > 1 + z_word_t crc1, word1; +#if N > 2 + z_word_t crc2, word2; +#if N > 3 + z_word_t crc3, word3; +#if N > 4 + z_word_t crc4, word4; +#if N > 5 + z_word_t crc5, word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = byte_swap(crc); +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_big_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_big_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_big_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_big_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_big_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_big_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + comb = crc_word_big(crc0 ^ words[0]); +#if N > 1 + comb = crc_word_big(crc1 ^ words[1] ^ comb); +#if N > 2 + comb = crc_word_big(crc2 ^ words[2] ^ comb); +#if N > 3 + comb = crc_word_big(crc3 ^ words[3] ^ comb); +#if N > 4 + comb = crc_word_big(crc4 ^ words[4] ^ comb); +#if N > 5 + comb = crc_word_big(crc5 ^ words[5] ^ comb); +#endif +#endif +#endif +#endif +#endif + words += N; + crc = byte_swap(comb); + } + + /* + Update the pointer to the remaining bytes to process. + */ + buf = (unsigned char const *)words; + } + +#endif /* W */ + + /* Complete the computation of the CRC on any remaining bytes. */ + while (len >= 8) { + len -= 8; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + while (len) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32( + unsigned long crc, + const unsigned char FAR *buf, + uInt len) +{ + return crc32_z(crc, buf, len); +} + +#ifndef Z_FREETYPE + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine64( + uLong crc1, + uLong crc2, + z_off64_t len2) +{ +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine( + uLong crc1, + uLong crc2, + z_off_t len2) +{ + return crc32_combine64(crc1, crc2, (z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen64( + z_off64_t len2) +{ +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return x2nmodp(len2, 3); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen( + z_off_t len2) +{ + return crc32_combine_gen64((z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_op( + uLong crc1, + uLong crc2, + uLong op) +{ + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); +} + +#endif /* Z_FREETYPE */ diff --git a/vendor/freetype/src/gzip/crc32.h b/vendor/freetype/src/gzip/crc32.h new file mode 100644 index 0000000..137df68 --- /dev/null +++ b/vendor/freetype/src/gzip/crc32.h @@ -0,0 +1,9446 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}; + +#ifdef W + +#if W == 8 + +local const z_word_t FAR crc_big_table[] = { + 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}; + +#else /* W == 4 */ + +local const z_word_t FAR crc_big_table[] = { + 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}; + +#endif + +#if N == 1 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}, + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}, + {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, + 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, + 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, + 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, + 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, + 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, + 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, + 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, + 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, + 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, + 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, + 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, + 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, + 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, + 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, + 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, + 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, + 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, + 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, + 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, + 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, + 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, + 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, + 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, + 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, + 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, + 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, + 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, + 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, + 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, + 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, + 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, + 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, + 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, + 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, + 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, + 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, + 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, + 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, + 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, + 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, + 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, + 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, + 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, + 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, + 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, + 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, + 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, + 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, + 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, + 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, + 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, + 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, + 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, + 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, + 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, + 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, + 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, + 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, + 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, + 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, + 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, + 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, + 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, + 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, + 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, + 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, + 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, + 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, + 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, + 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, + 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, + 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, + 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, + 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, + 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, + 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, + 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, + 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, + 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, + 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, + 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, + 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, + 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, + 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, + 0x72fd249300000000}, + {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, + 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, + 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, + 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, + 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, + 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, + 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, + 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, + 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, + 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, + 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, + 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, + 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, + 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, + 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, + 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, + 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, + 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, + 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, + 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, + 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, + 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, + 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, + 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, + 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, + 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, + 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, + 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, + 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, + 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, + 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, + 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, + 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, + 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, + 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, + 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, + 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, + 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, + 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, + 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, + 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, + 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, + 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, + 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, + 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, + 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, + 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, + 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, + 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, + 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, + 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, + 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, + 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, + 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, + 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, + 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, + 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, + 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, + 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, + 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, + 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, + 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, + 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, + 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, + 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, + 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, + 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, + 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, + 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, + 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, + 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, + 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, + 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, + 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, + 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, + 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, + 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, + 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, + 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, + 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, + 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, + 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, + 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, + 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, + 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, + 0xed3498be00000000}, + {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, + 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, + 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, + 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, + 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, + 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, + 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, + 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, + 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, + 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, + 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, + 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, + 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, + 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, + 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, + 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, + 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, + 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, + 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, + 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, + 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, + 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, + 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, + 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, + 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, + 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, + 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, + 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, + 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, + 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, + 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, + 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, + 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, + 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, + 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, + 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, + 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, + 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, + 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, + 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, + 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, + 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, + 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, + 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, + 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, + 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, + 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, + 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, + 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, + 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, + 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, + 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, + 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, + 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, + 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, + 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, + 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, + 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, + 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, + 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, + 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, + 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, + 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, + 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, + 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, + 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, + 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, + 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, + 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, + 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, + 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, + 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, + 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, + 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, + 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, + 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, + 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, + 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, + 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, + 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, + 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, + 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, + 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, + 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, + 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, + 0xf10605de00000000}, + {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, + 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, + 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, + 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, + 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, + 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, + 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, + 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, + 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, + 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, + 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, + 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, + 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, + 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, + 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, + 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, + 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, + 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, + 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, + 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, + 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, + 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, + 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, + 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, + 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, + 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, + 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, + 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, + 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, + 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, + 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, + 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, + 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, + 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, + 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, + 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, + 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, + 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, + 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, + 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, + 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, + 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, + 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, + 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, + 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, + 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, + 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, + 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, + 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, + 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, + 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, + 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, + 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, + 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, + 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, + 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, + 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, + 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, + 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, + 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, + 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, + 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, + 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, + 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, + 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, + 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, + 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, + 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, + 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, + 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, + 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, + 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, + 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, + 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, + 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, + 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, + 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, + 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, + 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, + 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, + 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, + 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, + 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, + 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, + 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, + 0x8cc764ca00000000}, + {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, + 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, + 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, + 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, + 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, + 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, + 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, + 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, + 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, + 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, + 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, + 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, + 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, + 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, + 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, + 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, + 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, + 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, + 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, + 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, + 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, + 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, + 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, + 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, + 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, + 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, + 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, + 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, + 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, + 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, + 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, + 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, + 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, + 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, + 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, + 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, + 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, + 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, + 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, + 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, + 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, + 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, + 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, + 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, + 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, + 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, + 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, + 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, + 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, + 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, + 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, + 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, + 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, + 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, + 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, + 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, + 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, + 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, + 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, + 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, + 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, + 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, + 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, + 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, + 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, + 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, + 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, + 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, + 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, + 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, + 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, + 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, + 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, + 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, + 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, + 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, + 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, + 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, + 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, + 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, + 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, + 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, + 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, + 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, + 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, + 0xccabc4e400000000}, + {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, + 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, + 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, + 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, + 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, + 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, + 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, + 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, + 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, + 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, + 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, + 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, + 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, + 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, + 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, + 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, + 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, + 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, + 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, + 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, + 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, + 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, + 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, + 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, + 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, + 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, + 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, + 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, + 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, + 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, + 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, + 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, + 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, + 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, + 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, + 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, + 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, + 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, + 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, + 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, + 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, + 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, + 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, + 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, + 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, + 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, + 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, + 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, + 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, + 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, + 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, + 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, + 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, + 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, + 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, + 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, + 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, + 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, + 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, + 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, + 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, + 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, + 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, + 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, + 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, + 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, + 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, + 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, + 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, + 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, + 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, + 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, + 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, + 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, + 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, + 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, + 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, + 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, + 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, + 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, + 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, + 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, + 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, + 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, + 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, + 0x304a369200000000}, + {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, + 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, + 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, + 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, + 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, + 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, + 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, + 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, + 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, + 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, + 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, + 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, + 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, + 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, + 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, + 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, + 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, + 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, + 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, + 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, + 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, + 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, + 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, + 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, + 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, + 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, + 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, + 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, + 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, + 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, + 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, + 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, + 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, + 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, + 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, + 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, + 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, + 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, + 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, + 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, + 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, + 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, + 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, + 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, + 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, + 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, + 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, + 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, + 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, + 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, + 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, + 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, + 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, + 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, + 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, + 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, + 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, + 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, + 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, + 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, + 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, + 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, + 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, + 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, + 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, + 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, + 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, + 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, + 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, + 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, + 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, + 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, + 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, + 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, + 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, + 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, + 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, + 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, + 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, + 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, + 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, + 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, + 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, + 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, + 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, + 0xe6064b2600000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}, + {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, + 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, + 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, + 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, + 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, + 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, + 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, + 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, + 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, + 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, + 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, + 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, + 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, + 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, + 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, + 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, + 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, + 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, + 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, + 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, + 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, + 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, + 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, + 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, + 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, + 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, + 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, + 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, + 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, + 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, + 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, + 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, + 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, + 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, + 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, + 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, + 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, + 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, + 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, + 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, + 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, + 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, + 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, + 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, + 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, + 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, + 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, + 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, + 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, + 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, + 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, + 0x72fd2493}, + {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, + 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, + 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, + 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, + 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, + 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, + 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, + 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, + 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, + 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, + 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, + 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, + 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, + 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, + 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, + 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, + 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, + 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, + 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, + 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, + 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, + 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, + 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, + 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, + 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, + 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, + 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, + 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, + 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, + 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, + 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, + 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, + 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, + 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, + 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, + 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, + 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, + 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, + 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, + 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, + 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, + 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, + 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, + 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, + 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, + 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, + 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, + 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, + 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, + 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, + 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, + 0xed3498be}, + {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, + 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, + 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, + 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, + 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, + 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, + 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, + 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, + 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, + 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, + 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, + 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, + 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, + 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, + 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, + 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, + 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, + 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, + 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, + 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, + 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, + 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, + 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, + 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, + 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, + 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, + 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, + 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, + 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, + 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, + 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, + 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, + 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, + 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, + 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, + 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, + 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, + 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, + 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, + 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, + 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, + 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, + 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, + 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, + 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, + 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, + 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, + 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, + 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, + 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, + 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, + 0xf10605de}}; + +#endif + +#endif + +#if N == 2 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}, + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, + 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, + 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, + 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, + 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, + 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, + 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, + 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, + 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, + 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, + 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, + 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, + 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, + 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, + 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, + 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, + 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, + 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, + 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, + 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, + 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, + 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, + 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, + 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, + 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, + 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, + 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, + 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, + 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, + 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, + 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, + 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, + 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, + 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, + 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, + 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, + 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, + 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, + 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, + 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, + 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, + 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, + 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, + 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, + 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, + 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, + 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, + 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, + 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, + 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, + 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, + 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, + 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, + 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, + 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, + 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, + 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, + 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, + 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, + 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, + 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, + 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, + 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, + 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, + 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, + 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, + 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, + 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, + 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, + 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, + 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, + 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, + 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, + 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, + 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, + 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, + 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, + 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, + 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, + 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, + 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, + 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, + 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, + 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, + 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, + 0x4b0c4f4900000000}, + {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, + 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, + 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, + 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, + 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, + 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, + 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, + 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, + 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, + 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, + 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, + 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, + 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, + 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, + 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, + 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, + 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, + 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, + 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, + 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, + 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, + 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, + 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, + 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, + 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, + 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, + 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, + 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, + 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, + 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, + 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, + 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, + 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, + 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, + 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, + 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, + 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, + 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, + 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, + 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, + 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, + 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, + 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, + 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, + 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, + 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, + 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, + 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, + 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, + 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, + 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, + 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, + 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, + 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, + 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, + 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, + 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, + 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, + 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, + 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, + 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, + 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, + 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, + 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, + 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, + 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, + 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, + 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, + 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, + 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, + 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, + 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, + 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, + 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, + 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, + 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, + 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, + 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, + 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, + 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, + 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, + 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, + 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, + 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, + 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, + 0x14d747e100000000}, + {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, + 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, + 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, + 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, + 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, + 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, + 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, + 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, + 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, + 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, + 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, + 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, + 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, + 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, + 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, + 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, + 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, + 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, + 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, + 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, + 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, + 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, + 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, + 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, + 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, + 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, + 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, + 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, + 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, + 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, + 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, + 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, + 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, + 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, + 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, + 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, + 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, + 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, + 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, + 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, + 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, + 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, + 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, + 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, + 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, + 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, + 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, + 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, + 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, + 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, + 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, + 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, + 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, + 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, + 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, + 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, + 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, + 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, + 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, + 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, + 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, + 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, + 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, + 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, + 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, + 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, + 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, + 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, + 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, + 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, + 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, + 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, + 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, + 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, + 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, + 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, + 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, + 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, + 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, + 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, + 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, + 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, + 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, + 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, + 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, + 0xaa933b1a00000000}, + {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, + 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, + 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, + 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, + 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, + 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, + 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, + 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, + 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, + 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, + 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, + 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, + 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, + 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, + 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, + 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, + 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, + 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, + 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, + 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, + 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, + 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, + 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, + 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, + 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, + 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, + 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, + 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, + 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, + 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, + 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, + 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, + 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, + 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, + 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, + 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, + 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, + 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, + 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, + 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, + 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, + 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, + 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, + 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, + 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, + 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, + 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, + 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, + 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, + 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, + 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, + 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, + 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, + 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, + 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, + 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, + 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, + 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, + 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, + 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, + 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, + 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, + 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, + 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, + 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, + 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, + 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, + 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, + 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, + 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, + 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, + 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, + 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, + 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, + 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, + 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, + 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, + 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, + 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, + 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, + 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, + 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, + 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, + 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, + 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, + 0x6571193600000000}, + {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, + 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, + 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, + 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, + 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, + 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, + 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, + 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, + 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, + 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, + 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, + 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, + 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, + 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, + 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, + 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, + 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, + 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, + 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, + 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, + 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, + 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, + 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, + 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, + 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, + 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, + 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, + 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, + 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, + 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, + 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, + 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, + 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, + 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, + 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, + 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, + 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, + 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, + 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, + 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, + 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, + 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, + 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, + 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, + 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, + 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, + 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, + 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, + 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, + 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, + 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, + 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, + 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, + 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, + 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, + 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, + 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, + 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, + 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, + 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, + 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, + 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, + 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, + 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, + 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, + 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, + 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, + 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, + 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, + 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, + 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, + 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, + 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, + 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, + 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, + 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, + 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, + 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, + 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, + 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, + 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, + 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, + 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, + 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, + 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, + 0xa68cee3d00000000}, + {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, + 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, + 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, + 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, + 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, + 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, + 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, + 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, + 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, + 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, + 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, + 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, + 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, + 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, + 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, + 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, + 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, + 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, + 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, + 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, + 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, + 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, + 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, + 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, + 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, + 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, + 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, + 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, + 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, + 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, + 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, + 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, + 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, + 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, + 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, + 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, + 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, + 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, + 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, + 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, + 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, + 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, + 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, + 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, + 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, + 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, + 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, + 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, + 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, + 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, + 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, + 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, + 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, + 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, + 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, + 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, + 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, + 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, + 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, + 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, + 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, + 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, + 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, + 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, + 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, + 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, + 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, + 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, + 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, + 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, + 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, + 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, + 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, + 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, + 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, + 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, + 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, + 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, + 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, + 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, + 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, + 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, + 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, + 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, + 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, + 0x51e8883f00000000}, + {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, + 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, + 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, + 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, + 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, + 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, + 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, + 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, + 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, + 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, + 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, + 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, + 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, + 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, + 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, + 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, + 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, + 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, + 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, + 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, + 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, + 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, + 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, + 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, + 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, + 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, + 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, + 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, + 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, + 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, + 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, + 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, + 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, + 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, + 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, + 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, + 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, + 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, + 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, + 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, + 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, + 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, + 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, + 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, + 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, + 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, + 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, + 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, + 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, + 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, + 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, + 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, + 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, + 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, + 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, + 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, + 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, + 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, + 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, + 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, + 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, + 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, + 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, + 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, + 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, + 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, + 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, + 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, + 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, + 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, + 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, + 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, + 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, + 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, + 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, + 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, + 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, + 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, + 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, + 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, + 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, + 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, + 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, + 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, + 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, + 0x8ae9531c00000000}, + {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, + 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, + 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, + 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, + 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, + 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, + 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, + 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, + 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, + 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, + 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, + 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, + 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, + 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, + 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, + 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, + 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, + 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, + 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, + 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, + 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, + 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, + 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, + 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, + 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, + 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, + 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, + 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, + 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, + 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, + 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, + 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, + 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, + 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, + 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, + 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, + 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, + 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, + 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, + 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, + 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, + 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, + 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, + 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, + 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, + 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, + 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, + 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, + 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, + 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, + 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, + 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, + 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, + 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, + 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, + 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, + 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, + 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, + 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, + 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, + 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, + 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, + 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, + 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, + 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, + 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, + 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, + 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, + 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, + 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, + 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, + 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, + 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, + 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, + 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, + 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, + 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, + 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, + 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, + 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, + 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, + 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, + 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, + 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, + 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, + 0xd739710d00000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, + 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, + 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, + 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, + 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, + 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, + 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, + 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, + 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, + 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, + 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, + 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, + 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, + 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, + 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, + 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, + 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, + 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, + 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, + 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, + 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, + 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, + 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, + 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, + 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, + 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, + 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, + 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, + 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, + 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, + 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, + 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, + 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, + 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, + 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, + 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, + 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, + 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, + 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, + 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, + 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, + 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, + 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, + 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, + 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, + 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, + 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, + 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, + 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, + 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, + 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, + 0x8cc764ca}, + {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, + 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, + 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, + 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, + 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, + 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, + 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, + 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, + 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, + 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, + 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, + 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, + 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, + 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, + 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, + 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, + 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, + 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, + 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, + 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, + 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, + 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, + 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, + 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, + 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, + 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, + 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, + 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, + 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, + 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, + 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, + 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, + 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, + 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, + 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, + 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, + 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, + 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, + 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, + 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, + 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, + 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, + 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, + 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, + 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, + 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, + 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, + 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, + 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, + 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, + 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, + 0xccabc4e4}, + {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, + 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, + 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, + 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, + 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, + 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, + 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, + 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, + 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, + 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, + 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, + 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, + 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, + 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, + 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, + 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, + 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, + 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, + 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, + 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, + 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, + 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, + 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, + 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, + 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, + 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, + 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, + 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, + 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, + 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, + 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, + 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, + 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, + 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, + 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, + 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, + 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, + 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, + 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, + 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, + 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, + 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, + 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, + 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, + 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, + 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, + 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, + 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, + 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, + 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, + 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, + 0x304a3692}, + {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, + 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, + 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, + 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, + 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, + 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, + 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, + 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, + 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, + 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, + 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, + 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, + 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, + 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, + 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, + 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, + 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, + 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, + 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, + 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, + 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, + 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, + 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, + 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, + 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, + 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, + 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, + 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, + 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, + 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, + 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, + 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, + 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, + 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, + 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, + 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, + 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, + 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, + 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, + 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, + 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, + 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, + 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, + 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, + 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, + 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, + 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, + 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, + 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, + 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, + 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, + 0xe6064b26}}; + +#endif + +#endif + +#if N == 3 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}, + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, + 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, + 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, + 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, + 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, + 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, + 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, + 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, + 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, + 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, + 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, + 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, + 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, + 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, + 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, + 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, + 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, + 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, + 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, + 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, + 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, + 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, + 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, + 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, + 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, + 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, + 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, + 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, + 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, + 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, + 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, + 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, + 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, + 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, + 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, + 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, + 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, + 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, + 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, + 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, + 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, + 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, + 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, + 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, + 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, + 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, + 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, + 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, + 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, + 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, + 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, + 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, + 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, + 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, + 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, + 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, + 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, + 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, + 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, + 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, + 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, + 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, + 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, + 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, + 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, + 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, + 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, + 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, + 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, + 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, + 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, + 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, + 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, + 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, + 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, + 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, + 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, + 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, + 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, + 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, + 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, + 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, + 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, + 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, + 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, + 0x4e36ba1800000000}, + {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, + 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, + 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, + 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, + 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, + 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, + 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, + 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, + 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, + 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, + 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, + 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, + 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, + 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, + 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, + 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, + 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, + 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, + 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, + 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, + 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, + 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, + 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, + 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, + 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, + 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, + 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, + 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, + 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, + 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, + 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, + 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, + 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, + 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, + 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, + 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, + 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, + 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, + 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, + 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, + 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, + 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, + 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, + 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, + 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, + 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, + 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, + 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, + 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, + 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, + 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, + 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, + 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, + 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, + 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, + 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, + 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, + 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, + 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, + 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, + 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, + 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, + 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, + 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, + 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, + 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, + 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, + 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, + 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, + 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, + 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, + 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, + 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, + 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, + 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, + 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, + 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, + 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, + 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, + 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, + 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, + 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, + 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, + 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, + 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, + 0xa1d67c9100000000}, + {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, + 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, + 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, + 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, + 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, + 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, + 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, + 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, + 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, + 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, + 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, + 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, + 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, + 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, + 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, + 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, + 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, + 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, + 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, + 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, + 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, + 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, + 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, + 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, + 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, + 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, + 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, + 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, + 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, + 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, + 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, + 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, + 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, + 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, + 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, + 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, + 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, + 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, + 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, + 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, + 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, + 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, + 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, + 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, + 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, + 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, + 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, + 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, + 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, + 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, + 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, + 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, + 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, + 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, + 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, + 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, + 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, + 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, + 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, + 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, + 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, + 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, + 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, + 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, + 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, + 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, + 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, + 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, + 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, + 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, + 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, + 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, + 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, + 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, + 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, + 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, + 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, + 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, + 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, + 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, + 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, + 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, + 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, + 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, + 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, + 0xa8ef40a100000000}, + {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, + 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, + 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, + 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, + 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, + 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, + 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, + 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, + 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, + 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, + 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, + 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, + 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, + 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, + 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, + 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, + 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, + 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, + 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, + 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, + 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, + 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, + 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, + 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, + 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, + 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, + 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, + 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, + 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, + 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, + 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, + 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, + 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, + 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, + 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, + 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, + 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, + 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, + 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, + 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, + 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, + 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, + 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, + 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, + 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, + 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, + 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, + 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, + 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, + 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, + 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, + 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, + 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, + 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, + 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, + 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, + 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, + 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, + 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, + 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, + 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, + 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, + 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, + 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, + 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, + 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, + 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, + 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, + 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, + 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, + 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, + 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, + 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, + 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, + 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, + 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, + 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, + 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, + 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, + 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, + 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, + 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, + 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, + 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, + 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, + 0x356bacd800000000}, + {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, + 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, + 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, + 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, + 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, + 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, + 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, + 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, + 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, + 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, + 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, + 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, + 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, + 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, + 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, + 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, + 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, + 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, + 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, + 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, + 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, + 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, + 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, + 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, + 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, + 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, + 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, + 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, + 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, + 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, + 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, + 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, + 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, + 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, + 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, + 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, + 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, + 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, + 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, + 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, + 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, + 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, + 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, + 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, + 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, + 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, + 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, + 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, + 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, + 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, + 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, + 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, + 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, + 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, + 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, + 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, + 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, + 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, + 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, + 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, + 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, + 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, + 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, + 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, + 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, + 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, + 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, + 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, + 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, + 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, + 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, + 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, + 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, + 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, + 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, + 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, + 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, + 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, + 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, + 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, + 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, + 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, + 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, + 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, + 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, + 0x48686b5600000000}, + {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, + 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, + 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, + 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, + 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, + 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, + 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, + 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, + 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, + 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, + 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, + 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, + 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, + 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, + 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, + 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, + 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, + 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, + 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, + 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, + 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, + 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, + 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, + 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, + 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, + 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, + 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, + 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, + 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, + 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, + 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, + 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, + 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, + 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, + 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, + 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, + 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, + 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, + 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, + 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, + 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, + 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, + 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, + 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, + 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, + 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, + 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, + 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, + 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, + 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, + 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, + 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, + 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, + 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, + 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, + 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, + 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, + 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, + 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, + 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, + 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, + 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, + 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, + 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, + 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, + 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, + 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, + 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, + 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, + 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, + 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, + 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, + 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, + 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, + 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, + 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, + 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, + 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, + 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, + 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, + 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, + 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, + 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, + 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, + 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, + 0xcaa2517800000000}, + {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, + 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, + 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, + 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, + 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, + 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, + 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, + 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, + 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, + 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, + 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, + 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, + 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, + 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, + 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, + 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, + 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, + 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, + 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, + 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, + 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, + 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, + 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, + 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, + 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, + 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, + 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, + 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, + 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, + 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, + 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, + 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, + 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, + 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, + 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, + 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, + 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, + 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, + 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, + 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, + 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, + 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, + 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, + 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, + 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, + 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, + 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, + 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, + 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, + 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, + 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, + 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, + 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, + 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, + 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, + 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, + 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, + 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, + 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, + 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, + 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, + 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, + 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, + 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, + 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, + 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, + 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, + 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, + 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, + 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, + 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, + 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, + 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, + 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, + 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, + 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, + 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, + 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, + 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, + 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, + 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, + 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, + 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, + 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, + 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, + 0x0c7ac97b00000000}, + {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, + 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, + 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, + 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, + 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, + 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, + 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, + 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, + 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, + 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, + 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, + 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, + 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, + 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, + 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, + 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, + 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, + 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, + 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, + 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, + 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, + 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, + 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, + 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, + 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, + 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, + 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, + 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, + 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, + 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, + 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, + 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, + 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, + 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, + 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, + 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, + 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, + 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, + 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, + 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, + 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, + 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, + 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, + 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, + 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, + 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, + 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, + 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, + 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, + 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, + 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, + 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, + 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, + 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, + 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, + 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, + 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, + 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, + 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, + 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, + 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, + 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, + 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, + 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, + 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, + 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, + 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, + 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, + 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, + 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, + 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, + 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, + 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, + 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, + 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, + 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, + 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, + 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, + 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, + 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, + 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, + 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, + 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, + 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, + 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, + 0x5185cd0900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, + 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, + 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, + 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, + 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, + 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, + 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, + 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, + 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, + 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, + 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, + 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, + 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, + 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, + 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, + 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, + 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, + 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, + 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, + 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, + 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, + 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, + 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, + 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, + 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, + 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, + 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, + 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, + 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, + 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, + 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, + 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, + 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, + 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, + 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, + 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, + 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, + 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, + 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, + 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, + 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, + 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, + 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, + 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, + 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, + 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, + 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, + 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, + 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, + 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, + 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, + 0x4b0c4f49}, + {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, + 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, + 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, + 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, + 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, + 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, + 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, + 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, + 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, + 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, + 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, + 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, + 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, + 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, + 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, + 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, + 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, + 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, + 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, + 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, + 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, + 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, + 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, + 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, + 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, + 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, + 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, + 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, + 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, + 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, + 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, + 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, + 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, + 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, + 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, + 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, + 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, + 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, + 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, + 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, + 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, + 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, + 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, + 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, + 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, + 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, + 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, + 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, + 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, + 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, + 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, + 0x14d747e1}, + {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, + 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, + 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, + 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, + 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, + 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, + 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, + 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, + 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, + 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, + 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, + 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, + 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, + 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, + 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, + 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, + 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, + 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, + 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, + 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, + 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, + 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, + 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, + 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, + 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, + 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, + 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, + 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, + 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, + 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, + 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, + 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, + 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, + 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, + 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, + 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, + 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, + 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, + 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, + 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, + 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, + 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, + 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, + 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, + 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, + 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, + 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, + 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, + 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, + 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, + 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, + 0xaa933b1a}, + {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, + 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, + 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, + 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, + 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, + 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, + 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, + 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, + 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, + 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, + 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, + 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, + 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, + 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, + 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, + 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, + 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, + 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, + 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, + 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, + 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, + 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, + 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, + 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, + 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, + 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, + 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, + 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, + 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, + 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, + 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, + 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, + 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, + 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, + 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, + 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, + 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, + 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, + 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, + 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, + 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, + 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, + 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, + 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, + 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, + 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, + 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, + 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, + 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, + 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, + 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, + 0x65711936}}; + +#endif + +#endif + +#if N == 4 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, + 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, + 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, + 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, + 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, + 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, + 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, + 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, + 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, + 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, + 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, + 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, + 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, + 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, + 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, + 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, + 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, + 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, + 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, + 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, + 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, + 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, + 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, + 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, + 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, + 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, + 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, + 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, + 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, + 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, + 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, + 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, + 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, + 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, + 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, + 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, + 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, + 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, + 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, + 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, + 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, + 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, + 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, + 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, + 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, + 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, + 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, + 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, + 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, + 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, + 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, + 0xe3c45916}, + {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, + 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, + 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, + 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, + 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, + 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, + 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, + 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, + 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, + 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, + 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, + 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, + 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, + 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, + 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, + 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, + 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, + 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, + 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, + 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, + 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, + 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, + 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, + 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, + 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, + 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, + 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, + 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, + 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, + 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, + 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, + 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, + 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, + 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, + 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, + 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, + 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, + 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, + 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, + 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, + 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, + 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, + 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, + 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, + 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, + 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, + 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, + 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, + 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, + 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, + 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, + 0xa7520488}, + {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, + 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, + 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, + 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, + 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, + 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, + 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, + 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, + 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, + 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, + 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, + 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, + 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, + 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, + 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, + 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, + 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, + 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, + 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, + 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, + 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, + 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, + 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, + 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, + 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, + 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, + 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, + 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, + 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, + 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, + 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, + 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, + 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, + 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, + 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, + 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, + 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, + 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, + 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, + 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, + 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, + 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, + 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, + 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, + 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, + 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, + 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, + 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, + 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, + 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, + 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, + 0x3522e9e4}, + {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, + 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, + 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, + 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, + 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, + 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, + 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, + 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, + 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, + 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, + 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, + 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, + 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, + 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, + 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, + 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, + 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, + 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, + 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, + 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, + 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, + 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, + 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, + 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, + 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, + 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, + 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, + 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, + 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, + 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, + 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, + 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, + 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, + 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, + 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, + 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, + 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, + 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, + 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, + 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, + 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, + 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, + 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, + 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, + 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, + 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, + 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, + 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, + 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, + 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, + 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, + 0x97411e28}, + {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, + 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, + 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, + 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, + 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, + 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, + 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, + 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, + 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, + 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, + 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, + 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, + 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, + 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, + 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, + 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, + 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, + 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, + 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, + 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, + 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, + 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, + 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, + 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, + 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, + 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, + 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, + 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, + 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, + 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, + 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, + 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, + 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, + 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, + 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, + 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, + 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, + 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, + 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, + 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, + 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, + 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, + 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, + 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, + 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, + 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, + 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, + 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, + 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, + 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, + 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, + 0x93c7a00b}, + {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, + 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, + 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, + 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, + 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, + 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, + 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, + 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, + 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, + 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, + 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, + 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, + 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, + 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, + 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, + 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, + 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, + 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, + 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, + 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, + 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, + 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, + 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, + 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, + 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, + 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, + 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, + 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, + 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, + 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, + 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, + 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, + 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, + 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, + 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, + 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, + 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, + 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, + 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, + 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, + 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, + 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, + 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, + 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, + 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, + 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, + 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, + 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, + 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, + 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, + 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, + 0xce5f968d}, + {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, + 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, + 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, + 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, + 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, + 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, + 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, + 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, + 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, + 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, + 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, + 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, + 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, + 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, + 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, + 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, + 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, + 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, + 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, + 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, + 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, + 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, + 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, + 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, + 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, + 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, + 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, + 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, + 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, + 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, + 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, + 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, + 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, + 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, + 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, + 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, + 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, + 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, + 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, + 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, + 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, + 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, + 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, + 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, + 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, + 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, + 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, + 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, + 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, + 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, + 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, + 0x3e721277}, + {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, + 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, + 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, + 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, + 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, + 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, + 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, + 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, + 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, + 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, + 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, + 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, + 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, + 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, + 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, + 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, + 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, + 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, + 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, + 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, + 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, + 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, + 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, + 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, + 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, + 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, + 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, + 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, + 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, + 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, + 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, + 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, + 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, + 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, + 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, + 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, + 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, + 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, + 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, + 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, + 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, + 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, + 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, + 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, + 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, + 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, + 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, + 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, + 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, + 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, + 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, + 0x1c65ace7}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, + 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, + 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, + 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, + 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, + 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, + 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, + 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, + 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, + 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, + 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, + 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, + 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, + 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, + 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, + 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, + 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, + 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, + 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, + 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, + 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, + 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, + 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, + 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, + 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, + 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, + 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, + 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, + 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, + 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, + 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, + 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, + 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, + 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, + 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, + 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, + 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, + 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, + 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, + 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, + 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, + 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, + 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, + 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, + 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, + 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, + 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, + 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, + 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, + 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, + 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, + 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, + 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, + 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, + 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, + 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, + 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, + 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, + 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, + 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, + 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, + 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, + 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, + 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, + 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, + 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, + 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, + 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, + 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, + 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, + 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, + 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, + 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, + 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, + 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, + 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, + 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, + 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, + 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, + 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, + 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, + 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, + 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, + 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, + 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, + 0xe7ac651c00000000}, + {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, + 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, + 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, + 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, + 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, + 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, + 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, + 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, + 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, + 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, + 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, + 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, + 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, + 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, + 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, + 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, + 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, + 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, + 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, + 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, + 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, + 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, + 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, + 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, + 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, + 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, + 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, + 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, + 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, + 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, + 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, + 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, + 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, + 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, + 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, + 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, + 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, + 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, + 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, + 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, + 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, + 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, + 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, + 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, + 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, + 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, + 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, + 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, + 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, + 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, + 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, + 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, + 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, + 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, + 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, + 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, + 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, + 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, + 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, + 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, + 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, + 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, + 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, + 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, + 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, + 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, + 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, + 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, + 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, + 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, + 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, + 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, + 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, + 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, + 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, + 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, + 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, + 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, + 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, + 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, + 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, + 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, + 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, + 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, + 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, + 0x7712723e00000000}, + {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, + 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, + 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, + 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, + 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, + 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, + 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, + 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, + 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, + 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, + 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, + 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, + 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, + 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, + 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, + 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, + 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, + 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, + 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, + 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, + 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, + 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, + 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, + 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, + 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, + 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, + 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, + 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, + 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, + 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, + 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, + 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, + 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, + 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, + 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, + 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, + 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, + 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, + 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, + 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, + 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, + 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, + 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, + 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, + 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, + 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, + 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, + 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, + 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, + 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, + 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, + 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, + 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, + 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, + 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, + 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, + 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, + 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, + 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, + 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, + 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, + 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, + 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, + 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, + 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, + 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, + 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, + 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, + 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, + 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, + 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, + 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, + 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, + 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, + 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, + 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, + 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, + 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, + 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, + 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, + 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, + 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, + 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, + 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, + 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, + 0x8d965fce00000000}, + {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, + 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, + 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, + 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, + 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, + 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, + 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, + 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, + 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, + 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, + 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, + 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, + 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, + 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, + 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, + 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, + 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, + 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, + 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, + 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, + 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, + 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, + 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, + 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, + 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, + 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, + 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, + 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, + 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, + 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, + 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, + 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, + 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, + 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, + 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, + 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, + 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, + 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, + 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, + 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, + 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, + 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, + 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, + 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, + 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, + 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, + 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, + 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, + 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, + 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, + 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, + 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, + 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, + 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, + 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, + 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, + 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, + 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, + 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, + 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, + 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, + 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, + 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, + 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, + 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, + 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, + 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, + 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, + 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, + 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, + 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, + 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, + 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, + 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, + 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, + 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, + 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, + 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, + 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, + 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, + 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, + 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, + 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, + 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, + 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, + 0x0ba0c79300000000}, + {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, + 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, + 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, + 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, + 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, + 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, + 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, + 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, + 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, + 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, + 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, + 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, + 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, + 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, + 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, + 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, + 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, + 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, + 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, + 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, + 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, + 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, + 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, + 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, + 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, + 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, + 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, + 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, + 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, + 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, + 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, + 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, + 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, + 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, + 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, + 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, + 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, + 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, + 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, + 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, + 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, + 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, + 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, + 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, + 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, + 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, + 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, + 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, + 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, + 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, + 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, + 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, + 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, + 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, + 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, + 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, + 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, + 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, + 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, + 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, + 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, + 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, + 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, + 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, + 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, + 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, + 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, + 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, + 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, + 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, + 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, + 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, + 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, + 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, + 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, + 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, + 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, + 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, + 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, + 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, + 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, + 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, + 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, + 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, + 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, + 0x281e419700000000}, + {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, + 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, + 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, + 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, + 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, + 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, + 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, + 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, + 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, + 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, + 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, + 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, + 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, + 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, + 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, + 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, + 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, + 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, + 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, + 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, + 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, + 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, + 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, + 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, + 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, + 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, + 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, + 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, + 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, + 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, + 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, + 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, + 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, + 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, + 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, + 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, + 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, + 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, + 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, + 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, + 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, + 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, + 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, + 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, + 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, + 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, + 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, + 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, + 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, + 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, + 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, + 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, + 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, + 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, + 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, + 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, + 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, + 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, + 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, + 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, + 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, + 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, + 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, + 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, + 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, + 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, + 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, + 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, + 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, + 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, + 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, + 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, + 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, + 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, + 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, + 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, + 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, + 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, + 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, + 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, + 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, + 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, + 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, + 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, + 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, + 0xe4e9223500000000}, + {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, + 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, + 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, + 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, + 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, + 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, + 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, + 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, + 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, + 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, + 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, + 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, + 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, + 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, + 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, + 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, + 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, + 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, + 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, + 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, + 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, + 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, + 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, + 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, + 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, + 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, + 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, + 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, + 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, + 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, + 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, + 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, + 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, + 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, + 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, + 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, + 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, + 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, + 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, + 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, + 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, + 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, + 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, + 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, + 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, + 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, + 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, + 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, + 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, + 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, + 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, + 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, + 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, + 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, + 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, + 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, + 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, + 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, + 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, + 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, + 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, + 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, + 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, + 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, + 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, + 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, + 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, + 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, + 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, + 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, + 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, + 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, + 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, + 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, + 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, + 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, + 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, + 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, + 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, + 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, + 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, + 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, + 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, + 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, + 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, + 0x880452a700000000}, + {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, + 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, + 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, + 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, + 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, + 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, + 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, + 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, + 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, + 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, + 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, + 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, + 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, + 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, + 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, + 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, + 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, + 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, + 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, + 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, + 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, + 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, + 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, + 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, + 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, + 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, + 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, + 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, + 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, + 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, + 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, + 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, + 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, + 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, + 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, + 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, + 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, + 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, + 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, + 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, + 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, + 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, + 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, + 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, + 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, + 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, + 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, + 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, + 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, + 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, + 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, + 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, + 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, + 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, + 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, + 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, + 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, + 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, + 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, + 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, + 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, + 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, + 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, + 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, + 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, + 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, + 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, + 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, + 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, + 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, + 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, + 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, + 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, + 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, + 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, + 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, + 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, + 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, + 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, + 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, + 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, + 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, + 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, + 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, + 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, + 0x1659c4e300000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, + 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, + 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, + 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, + 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, + 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, + 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, + 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, + 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, + 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, + 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, + 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, + 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, + 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, + 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, + 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, + 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, + 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, + 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, + 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, + 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, + 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, + 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, + 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, + 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, + 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, + 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, + 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, + 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, + 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, + 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, + 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, + 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, + 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, + 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, + 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, + 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, + 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, + 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, + 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, + 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, + 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, + 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, + 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, + 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, + 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, + 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, + 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, + 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, + 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, + 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, + 0xa68cee3d}, + {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, + 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, + 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, + 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, + 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, + 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, + 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, + 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, + 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, + 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, + 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, + 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, + 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, + 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, + 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, + 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, + 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, + 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, + 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, + 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, + 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, + 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, + 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, + 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, + 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, + 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, + 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, + 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, + 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, + 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, + 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, + 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, + 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, + 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, + 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, + 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, + 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, + 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, + 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, + 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, + 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, + 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, + 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, + 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, + 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, + 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, + 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, + 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, + 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, + 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, + 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, + 0x51e8883f}, + {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, + 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, + 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, + 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, + 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, + 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, + 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, + 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, + 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, + 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, + 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, + 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, + 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, + 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, + 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, + 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, + 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, + 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, + 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, + 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, + 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, + 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, + 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, + 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, + 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, + 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, + 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, + 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, + 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, + 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, + 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, + 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, + 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, + 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, + 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, + 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, + 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, + 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, + 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, + 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, + 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, + 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, + 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, + 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, + 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, + 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, + 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, + 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, + 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, + 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, + 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, + 0x8ae9531c}, + {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, + 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, + 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, + 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, + 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, + 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, + 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, + 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, + 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, + 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, + 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, + 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, + 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, + 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, + 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, + 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, + 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, + 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, + 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, + 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, + 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, + 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, + 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, + 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, + 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, + 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, + 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, + 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, + 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, + 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, + 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, + 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, + 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, + 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, + 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, + 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, + 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, + 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, + 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, + 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, + 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, + 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, + 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, + 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, + 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, + 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, + 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, + 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, + 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, + 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, + 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, + 0xd739710d}}; + +#endif + +#endif + +#if N == 5 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, + 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, + 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, + 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, + 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, + 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, + 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, + 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, + 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, + 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, + 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, + 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, + 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, + 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, + 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, + 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, + 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, + 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, + 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, + 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, + 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, + 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, + 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, + 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, + 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, + 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, + 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, + 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, + 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, + 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, + 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, + 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, + 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, + 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, + 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, + 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, + 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, + 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, + 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, + 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, + 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, + 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, + 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, + 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, + 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, + 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, + 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, + 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, + 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, + 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, + 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, + 0xe9947565}, + {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, + 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, + 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, + 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, + 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, + 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, + 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, + 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, + 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, + 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, + 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, + 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, + 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, + 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, + 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, + 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, + 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, + 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, + 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, + 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, + 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, + 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, + 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, + 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, + 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, + 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, + 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, + 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, + 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, + 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, + 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, + 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, + 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, + 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, + 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, + 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, + 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, + 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, + 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, + 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, + 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, + 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, + 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, + 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, + 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, + 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, + 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, + 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, + 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, + 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, + 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, + 0xf7d05006}, + {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, + 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, + 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, + 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, + 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, + 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, + 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, + 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, + 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, + 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, + 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, + 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, + 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, + 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, + 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, + 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, + 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, + 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, + 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, + 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, + 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, + 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, + 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, + 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, + 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, + 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, + 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, + 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, + 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, + 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, + 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, + 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, + 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, + 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, + 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, + 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, + 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, + 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, + 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, + 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, + 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, + 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, + 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, + 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, + 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, + 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, + 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, + 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, + 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, + 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, + 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, + 0xb2075b94}, + {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, + 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, + 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, + 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, + 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, + 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, + 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, + 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, + 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, + 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, + 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, + 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, + 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, + 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, + 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, + 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, + 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, + 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, + 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, + 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, + 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, + 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, + 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, + 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, + 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, + 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, + 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, + 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, + 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, + 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, + 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, + 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, + 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, + 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, + 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, + 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, + 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, + 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, + 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, + 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, + 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, + 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, + 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, + 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, + 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, + 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, + 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, + 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, + 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, + 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, + 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, + 0xba50bcb9}, + {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, + 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, + 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, + 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, + 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, + 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, + 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, + 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, + 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, + 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, + 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, + 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, + 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, + 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, + 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, + 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, + 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, + 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, + 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, + 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, + 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, + 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, + 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, + 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, + 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, + 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, + 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, + 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, + 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, + 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, + 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, + 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, + 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, + 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, + 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, + 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, + 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, + 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, + 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, + 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, + 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, + 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, + 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, + 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, + 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, + 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, + 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, + 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, + 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, + 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, + 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, + 0x808abcf4}, + {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, + 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, + 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, + 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, + 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, + 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, + 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, + 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, + 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, + 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, + 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, + 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, + 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, + 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, + 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, + 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, + 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, + 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, + 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, + 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, + 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, + 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, + 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, + 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, + 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, + 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, + 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, + 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, + 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, + 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, + 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, + 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, + 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, + 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, + 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, + 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, + 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, + 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, + 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, + 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, + 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, + 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, + 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, + 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, + 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, + 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, + 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, + 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, + 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, + 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, + 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, + 0xefdb3f95}, + {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, + 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, + 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, + 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, + 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, + 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, + 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, + 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, + 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, + 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, + 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, + 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, + 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, + 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, + 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, + 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, + 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, + 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, + 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, + 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, + 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, + 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, + 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, + 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, + 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, + 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, + 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, + 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, + 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, + 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, + 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, + 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, + 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, + 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, + 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, + 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, + 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, + 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, + 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, + 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, + 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, + 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, + 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, + 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, + 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, + 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, + 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, + 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, + 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, + 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, + 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, + 0x0e2fbf43}, + {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, + 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, + 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, + 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, + 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, + 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, + 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, + 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, + 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, + 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, + 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, + 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, + 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, + 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, + 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, + 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, + 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, + 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, + 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, + 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, + 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, + 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, + 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, + 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, + 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, + 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, + 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, + 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, + 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, + 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, + 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, + 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, + 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, + 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, + 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, + 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, + 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, + 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, + 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, + 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, + 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, + 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, + 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, + 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, + 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, + 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, + 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, + 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, + 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, + 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, + 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, + 0xf4377108}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, + 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, + 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, + 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, + 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, + 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, + 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, + 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, + 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, + 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, + 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, + 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, + 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, + 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, + 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, + 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, + 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, + 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, + 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, + 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, + 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, + 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, + 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, + 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, + 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, + 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, + 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, + 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, + 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, + 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, + 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, + 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, + 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, + 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, + 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, + 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, + 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, + 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, + 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, + 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, + 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, + 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, + 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, + 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, + 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, + 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, + 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, + 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, + 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, + 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, + 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, + 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, + 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, + 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, + 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, + 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, + 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, + 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, + 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, + 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, + 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, + 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, + 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, + 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, + 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, + 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, + 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, + 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, + 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, + 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, + 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, + 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, + 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, + 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, + 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, + 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, + 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, + 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, + 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, + 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, + 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, + 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, + 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, + 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, + 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, + 0x087137f400000000}, + {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, + 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, + 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, + 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, + 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, + 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, + 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, + 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, + 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, + 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, + 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, + 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, + 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, + 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, + 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, + 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, + 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, + 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, + 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, + 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, + 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, + 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, + 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, + 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, + 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, + 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, + 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, + 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, + 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, + 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, + 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, + 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, + 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, + 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, + 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, + 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, + 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, + 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, + 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, + 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, + 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, + 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, + 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, + 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, + 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, + 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, + 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, + 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, + 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, + 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, + 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, + 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, + 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, + 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, + 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, + 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, + 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, + 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, + 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, + 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, + 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, + 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, + 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, + 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, + 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, + 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, + 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, + 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, + 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, + 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, + 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, + 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, + 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, + 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, + 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, + 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, + 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, + 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, + 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, + 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, + 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, + 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, + 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, + 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, + 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, + 0x43bf2f0e00000000}, + {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, + 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, + 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, + 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, + 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, + 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, + 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, + 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, + 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, + 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, + 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, + 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, + 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, + 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, + 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, + 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, + 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, + 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, + 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, + 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, + 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, + 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, + 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, + 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, + 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, + 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, + 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, + 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, + 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, + 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, + 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, + 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, + 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, + 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, + 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, + 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, + 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, + 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, + 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, + 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, + 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, + 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, + 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, + 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, + 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, + 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, + 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, + 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, + 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, + 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, + 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, + 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, + 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, + 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, + 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, + 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, + 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, + 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, + 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, + 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, + 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, + 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, + 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, + 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, + 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, + 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, + 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, + 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, + 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, + 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, + 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, + 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, + 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, + 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, + 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, + 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, + 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, + 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, + 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, + 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, + 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, + 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, + 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, + 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, + 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, + 0x953fdbef00000000}, + {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, + 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, + 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, + 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, + 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, + 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, + 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, + 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, + 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, + 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, + 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, + 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, + 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, + 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, + 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, + 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, + 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, + 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, + 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, + 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, + 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, + 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, + 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, + 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, + 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, + 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, + 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, + 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, + 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, + 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, + 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, + 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, + 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, + 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, + 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, + 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, + 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, + 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, + 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, + 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, + 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, + 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, + 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, + 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, + 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, + 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, + 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, + 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, + 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, + 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, + 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, + 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, + 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, + 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, + 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, + 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, + 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, + 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, + 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, + 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, + 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, + 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, + 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, + 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, + 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, + 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, + 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, + 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, + 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, + 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, + 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, + 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, + 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, + 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, + 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, + 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, + 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, + 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, + 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, + 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, + 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, + 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, + 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, + 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, + 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, + 0xf4bc8a8000000000}, + {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, + 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, + 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, + 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, + 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, + 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, + 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, + 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, + 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, + 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, + 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, + 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, + 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, + 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, + 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, + 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, + 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, + 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, + 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, + 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, + 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, + 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, + 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, + 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, + 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, + 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, + 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, + 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, + 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, + 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, + 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, + 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, + 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, + 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, + 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, + 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, + 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, + 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, + 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, + 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, + 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, + 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, + 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, + 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, + 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, + 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, + 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, + 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, + 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, + 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, + 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, + 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, + 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, + 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, + 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, + 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, + 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, + 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, + 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, + 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, + 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, + 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, + 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, + 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, + 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, + 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, + 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, + 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, + 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, + 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, + 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, + 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, + 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, + 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, + 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, + 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, + 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, + 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, + 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, + 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, + 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, + 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, + 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, + 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, + 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, + 0xb9bc50ba00000000}, + {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, + 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, + 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, + 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, + 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, + 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, + 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, + 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, + 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, + 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, + 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, + 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, + 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, + 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, + 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, + 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, + 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, + 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, + 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, + 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, + 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, + 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, + 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, + 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, + 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, + 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, + 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, + 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, + 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, + 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, + 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, + 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, + 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, + 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, + 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, + 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, + 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, + 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, + 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, + 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, + 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, + 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, + 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, + 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, + 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, + 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, + 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, + 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, + 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, + 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, + 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, + 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, + 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, + 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, + 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, + 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, + 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, + 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, + 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, + 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, + 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, + 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, + 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, + 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, + 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, + 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, + 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, + 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, + 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, + 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, + 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, + 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, + 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, + 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, + 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, + 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, + 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, + 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, + 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, + 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, + 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, + 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, + 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, + 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, + 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, + 0x945b07b200000000}, + {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, + 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, + 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, + 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, + 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, + 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, + 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, + 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, + 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, + 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, + 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, + 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, + 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, + 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, + 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, + 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, + 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, + 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, + 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, + 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, + 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, + 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, + 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, + 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, + 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, + 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, + 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, + 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, + 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, + 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, + 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, + 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, + 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, + 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, + 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, + 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, + 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, + 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, + 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, + 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, + 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, + 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, + 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, + 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, + 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, + 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, + 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, + 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, + 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, + 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, + 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, + 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, + 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, + 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, + 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, + 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, + 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, + 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, + 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, + 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, + 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, + 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, + 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, + 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, + 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, + 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, + 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, + 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, + 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, + 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, + 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, + 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, + 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, + 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, + 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, + 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, + 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, + 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, + 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, + 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, + 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, + 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, + 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, + 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, + 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, + 0x0650d0f700000000}, + {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, + 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, + 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, + 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, + 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, + 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, + 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, + 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, + 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, + 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, + 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, + 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, + 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, + 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, + 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, + 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, + 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, + 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, + 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, + 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, + 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, + 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, + 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, + 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, + 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, + 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, + 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, + 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, + 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, + 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, + 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, + 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, + 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, + 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, + 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, + 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, + 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, + 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, + 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, + 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, + 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, + 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, + 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, + 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, + 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, + 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, + 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, + 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, + 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, + 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, + 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, + 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, + 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, + 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, + 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, + 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, + 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, + 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, + 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, + 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, + 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, + 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, + 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, + 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, + 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, + 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, + 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, + 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, + 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, + 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, + 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, + 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, + 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, + 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, + 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, + 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, + 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, + 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, + 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, + 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, + 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, + 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, + 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, + 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, + 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, + 0x657594e900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, + 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, + 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, + 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, + 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, + 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, + 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, + 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, + 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, + 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, + 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, + 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, + 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, + 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, + 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, + 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, + 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, + 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, + 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, + 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, + 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, + 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, + 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, + 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, + 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, + 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, + 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, + 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, + 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, + 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, + 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, + 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, + 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, + 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, + 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, + 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, + 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, + 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, + 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, + 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, + 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, + 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, + 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, + 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, + 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, + 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, + 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, + 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, + 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, + 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, + 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, + 0x4e36ba18}, + {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, + 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, + 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, + 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, + 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, + 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, + 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, + 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, + 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, + 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, + 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, + 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, + 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, + 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, + 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, + 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, + 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, + 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, + 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, + 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, + 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, + 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, + 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, + 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, + 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, + 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, + 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, + 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, + 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, + 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, + 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, + 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, + 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, + 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, + 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, + 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, + 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, + 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, + 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, + 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, + 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, + 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, + 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, + 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, + 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, + 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, + 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, + 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, + 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, + 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, + 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, + 0xa1d67c91}, + {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, + 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, + 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, + 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, + 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, + 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, + 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, + 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, + 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, + 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, + 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, + 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, + 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, + 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, + 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, + 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, + 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, + 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, + 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, + 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, + 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, + 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, + 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, + 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, + 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, + 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, + 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, + 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, + 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, + 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, + 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, + 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, + 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, + 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, + 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, + 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, + 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, + 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, + 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, + 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, + 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, + 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, + 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, + 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, + 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, + 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, + 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, + 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, + 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, + 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, + 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, + 0xa8ef40a1}, + {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, + 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, + 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, + 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, + 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, + 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, + 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, + 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, + 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, + 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, + 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, + 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, + 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, + 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, + 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, + 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, + 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, + 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, + 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, + 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, + 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, + 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, + 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, + 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, + 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, + 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, + 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, + 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, + 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, + 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, + 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, + 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, + 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, + 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, + 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, + 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, + 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, + 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, + 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, + 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, + 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, + 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, + 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, + 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, + 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, + 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, + 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, + 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, + 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, + 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, + 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, + 0x356bacd8}}; + +#endif + +#endif + +#if N == 6 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, + 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, + 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, + 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, + 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, + 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, + 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, + 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, + 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, + 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, + 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, + 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, + 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, + 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, + 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, + 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, + 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, + 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, + 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, + 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, + 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, + 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, + 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, + 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, + 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, + 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, + 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, + 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, + 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, + 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, + 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, + 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, + 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, + 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, + 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, + 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, + 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, + 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, + 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, + 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, + 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, + 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, + 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, + 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, + 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, + 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, + 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, + 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, + 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, + 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, + 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, + 0x8568a0a8}, + {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, + 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, + 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, + 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, + 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, + 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, + 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, + 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, + 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, + 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, + 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, + 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, + 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, + 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, + 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, + 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, + 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, + 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, + 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, + 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, + 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, + 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, + 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, + 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, + 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, + 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, + 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, + 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, + 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, + 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, + 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, + 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, + 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, + 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, + 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, + 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, + 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, + 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, + 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, + 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, + 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, + 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, + 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, + 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, + 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, + 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, + 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, + 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, + 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, + 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, + 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, + 0x0d907052}, + {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, + 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, + 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, + 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, + 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, + 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, + 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, + 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, + 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, + 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, + 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, + 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, + 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, + 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, + 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, + 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, + 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, + 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, + 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, + 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, + 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, + 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, + 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, + 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, + 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, + 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, + 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, + 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, + 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, + 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, + 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, + 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, + 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, + 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, + 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, + 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, + 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, + 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, + 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, + 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, + 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, + 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, + 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, + 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, + 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, + 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, + 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, + 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, + 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, + 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, + 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, + 0xfd1a6c8a}, + {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, + 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, + 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, + 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, + 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, + 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, + 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, + 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, + 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, + 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, + 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, + 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, + 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, + 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, + 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, + 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, + 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, + 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, + 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, + 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, + 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, + 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, + 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, + 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, + 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, + 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, + 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, + 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, + 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, + 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, + 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, + 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, + 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, + 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, + 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, + 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, + 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, + 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, + 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, + 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, + 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, + 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, + 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, + 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, + 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, + 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, + 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, + 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, + 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, + 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, + 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, + 0x7895f01a}, + {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, + 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, + 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, + 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, + 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, + 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, + 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, + 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, + 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, + 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, + 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, + 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, + 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, + 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, + 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, + 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, + 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, + 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, + 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, + 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, + 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, + 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, + 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, + 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, + 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, + 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, + 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, + 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, + 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, + 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, + 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, + 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, + 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, + 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, + 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, + 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, + 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, + 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, + 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, + 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, + 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, + 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, + 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, + 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, + 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, + 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, + 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, + 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, + 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, + 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, + 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, + 0x9239b848}, + {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, + 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, + 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, + 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, + 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, + 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, + 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, + 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, + 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, + 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, + 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, + 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, + 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, + 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, + 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, + 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, + 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, + 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, + 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, + 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, + 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, + 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, + 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, + 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, + 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, + 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, + 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, + 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, + 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, + 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, + 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, + 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, + 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, + 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, + 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, + 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, + 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, + 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, + 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, + 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, + 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, + 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, + 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, + 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, + 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, + 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, + 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, + 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, + 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, + 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, + 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, + 0xeb36d3cc}, + {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, + 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, + 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, + 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, + 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, + 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, + 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, + 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, + 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, + 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, + 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, + 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, + 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, + 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, + 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, + 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, + 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, + 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, + 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, + 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, + 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, + 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, + 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, + 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, + 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, + 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, + 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, + 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, + 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, + 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, + 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, + 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, + 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, + 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, + 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, + 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, + 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, + 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, + 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, + 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, + 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, + 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, + 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, + 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, + 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, + 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, + 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, + 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, + 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, + 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, + 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, + 0x38e5f3c5}, + {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, + 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, + 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, + 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, + 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, + 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, + 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, + 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, + 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, + 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, + 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, + 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, + 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, + 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, + 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, + 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, + 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, + 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, + 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, + 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, + 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, + 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, + 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, + 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, + 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, + 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, + 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, + 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, + 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, + 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, + 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, + 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, + 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, + 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, + 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, + 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, + 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, + 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, + 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, + 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, + 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, + 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, + 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, + 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, + 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, + 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, + 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, + 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, + 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, + 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, + 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, + 0x3d3101a2}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, + 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, + 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, + 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, + 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, + 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, + 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, + 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, + 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, + 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, + 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, + 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, + 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, + 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, + 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, + 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, + 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, + 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, + 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, + 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, + 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, + 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, + 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, + 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, + 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, + 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, + 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, + 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, + 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, + 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, + 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, + 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, + 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, + 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, + 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, + 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, + 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, + 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, + 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, + 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, + 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, + 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, + 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, + 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, + 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, + 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, + 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, + 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, + 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, + 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, + 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, + 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, + 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, + 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, + 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, + 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, + 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, + 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, + 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, + 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, + 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, + 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, + 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, + 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, + 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, + 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, + 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, + 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, + 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, + 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, + 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, + 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, + 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, + 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, + 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, + 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, + 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, + 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, + 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, + 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, + 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, + 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, + 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, + 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, + 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, + 0xa201313d00000000}, + {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, + 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, + 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, + 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, + 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, + 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, + 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, + 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, + 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, + 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, + 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, + 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, + 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, + 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, + 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, + 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, + 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, + 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, + 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, + 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, + 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, + 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, + 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, + 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, + 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, + 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, + 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, + 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, + 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, + 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, + 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, + 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, + 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, + 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, + 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, + 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, + 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, + 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, + 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, + 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, + 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, + 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, + 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, + 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, + 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, + 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, + 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, + 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, + 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, + 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, + 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, + 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, + 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, + 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, + 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, + 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, + 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, + 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, + 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, + 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, + 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, + 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, + 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, + 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, + 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, + 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, + 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, + 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, + 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, + 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, + 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, + 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, + 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, + 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, + 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, + 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, + 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, + 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, + 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, + 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, + 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, + 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, + 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, + 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, + 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, + 0xc5f3e53800000000}, + {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, + 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, + 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, + 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, + 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, + 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, + 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, + 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, + 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, + 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, + 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, + 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, + 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, + 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, + 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, + 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, + 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, + 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, + 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, + 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, + 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, + 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, + 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, + 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, + 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, + 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, + 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, + 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, + 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, + 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, + 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, + 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, + 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, + 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, + 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, + 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, + 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, + 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, + 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, + 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, + 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, + 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, + 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, + 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, + 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, + 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, + 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, + 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, + 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, + 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, + 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, + 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, + 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, + 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, + 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, + 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, + 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, + 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, + 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, + 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, + 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, + 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, + 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, + 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, + 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, + 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, + 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, + 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, + 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, + 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, + 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, + 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, + 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, + 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, + 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, + 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, + 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, + 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, + 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, + 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, + 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, + 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, + 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, + 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, + 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, + 0xccd336eb00000000}, + {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, + 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, + 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, + 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, + 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, + 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, + 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, + 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, + 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, + 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, + 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, + 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, + 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, + 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, + 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, + 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, + 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, + 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, + 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, + 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, + 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, + 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, + 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, + 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, + 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, + 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, + 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, + 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, + 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, + 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, + 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, + 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, + 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, + 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, + 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, + 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, + 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, + 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, + 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, + 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, + 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, + 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, + 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, + 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, + 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, + 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, + 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, + 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, + 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, + 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, + 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, + 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, + 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, + 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, + 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, + 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, + 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, + 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, + 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, + 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, + 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, + 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, + 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, + 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, + 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, + 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, + 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, + 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, + 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, + 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, + 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, + 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, + 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, + 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, + 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, + 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, + 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, + 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, + 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, + 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, + 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, + 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, + 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, + 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, + 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, + 0x48b8399200000000}, + {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, + 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, + 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, + 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, + 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, + 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, + 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, + 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, + 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, + 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, + 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, + 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, + 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, + 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, + 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, + 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, + 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, + 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, + 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, + 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, + 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, + 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, + 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, + 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, + 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, + 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, + 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, + 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, + 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, + 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, + 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, + 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, + 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, + 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, + 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, + 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, + 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, + 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, + 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, + 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, + 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, + 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, + 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, + 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, + 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, + 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, + 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, + 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, + 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, + 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, + 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, + 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, + 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, + 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, + 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, + 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, + 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, + 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, + 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, + 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, + 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, + 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, + 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, + 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, + 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, + 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, + 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, + 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, + 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, + 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, + 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, + 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, + 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, + 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, + 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, + 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, + 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, + 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, + 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, + 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, + 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, + 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, + 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, + 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, + 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, + 0x1af0957800000000}, + {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, + 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, + 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, + 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, + 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, + 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, + 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, + 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, + 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, + 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, + 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, + 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, + 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, + 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, + 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, + 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, + 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, + 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, + 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, + 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, + 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, + 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, + 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, + 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, + 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, + 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, + 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, + 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, + 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, + 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, + 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, + 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, + 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, + 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, + 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, + 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, + 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, + 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, + 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, + 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, + 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, + 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, + 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, + 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, + 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, + 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, + 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, + 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, + 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, + 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, + 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, + 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, + 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, + 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, + 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, + 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, + 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, + 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, + 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, + 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, + 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, + 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, + 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, + 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, + 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, + 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, + 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, + 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, + 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, + 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, + 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, + 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, + 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, + 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, + 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, + 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, + 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, + 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, + 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, + 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, + 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, + 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, + 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, + 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, + 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, + 0x8a6c1afd00000000}, + {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, + 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, + 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, + 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, + 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, + 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, + 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, + 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, + 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, + 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, + 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, + 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, + 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, + 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, + 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, + 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, + 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, + 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, + 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, + 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, + 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, + 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, + 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, + 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, + 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, + 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, + 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, + 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, + 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, + 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, + 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, + 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, + 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, + 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, + 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, + 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, + 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, + 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, + 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, + 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, + 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, + 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, + 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, + 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, + 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, + 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, + 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, + 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, + 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, + 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, + 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, + 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, + 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, + 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, + 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, + 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, + 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, + 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, + 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, + 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, + 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, + 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, + 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, + 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, + 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, + 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, + 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, + 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, + 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, + 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, + 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, + 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, + 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, + 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, + 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, + 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, + 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, + 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, + 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, + 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, + 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, + 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, + 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, + 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, + 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, + 0x5270900d00000000}, + {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, + 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, + 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, + 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, + 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, + 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, + 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, + 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, + 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, + 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, + 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, + 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, + 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, + 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, + 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, + 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, + 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, + 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, + 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, + 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, + 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, + 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, + 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, + 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, + 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, + 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, + 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, + 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, + 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, + 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, + 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, + 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, + 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, + 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, + 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, + 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, + 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, + 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, + 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, + 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, + 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, + 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, + 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, + 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, + 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, + 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, + 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, + 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, + 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, + 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, + 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, + 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, + 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, + 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, + 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, + 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, + 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, + 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, + 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, + 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, + 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, + 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, + 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, + 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, + 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, + 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, + 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, + 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, + 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, + 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, + 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, + 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, + 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, + 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, + 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, + 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, + 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, + 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, + 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, + 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, + 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, + 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, + 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, + 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, + 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, + 0xa8a0688500000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, + 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, + 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, + 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, + 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, + 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, + 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, + 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, + 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, + 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, + 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, + 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, + 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, + 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, + 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, + 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, + 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, + 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, + 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, + 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, + 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, + 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, + 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, + 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, + 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, + 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, + 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, + 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, + 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, + 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, + 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, + 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, + 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, + 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, + 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, + 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, + 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, + 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, + 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, + 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, + 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, + 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, + 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, + 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, + 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, + 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, + 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, + 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, + 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, + 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, + 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, + 0x48686b56}, + {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, + 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, + 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, + 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, + 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, + 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, + 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, + 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, + 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, + 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, + 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, + 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, + 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, + 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, + 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, + 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, + 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, + 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, + 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, + 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, + 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, + 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, + 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, + 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, + 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, + 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, + 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, + 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, + 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, + 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, + 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, + 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, + 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, + 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, + 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, + 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, + 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, + 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, + 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, + 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, + 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, + 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, + 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, + 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, + 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, + 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, + 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, + 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, + 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, + 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, + 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, + 0xcaa25178}, + {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, + 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, + 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, + 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, + 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, + 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, + 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, + 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, + 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, + 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, + 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, + 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, + 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, + 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, + 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, + 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, + 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, + 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, + 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, + 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, + 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, + 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, + 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, + 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, + 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, + 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, + 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, + 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, + 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, + 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, + 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, + 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, + 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, + 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, + 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, + 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, + 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, + 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, + 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, + 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, + 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, + 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, + 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, + 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, + 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, + 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, + 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, + 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, + 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, + 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, + 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, + 0x0c7ac97b}, + {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, + 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, + 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, + 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, + 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, + 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, + 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, + 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, + 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, + 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, + 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, + 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, + 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, + 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, + 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, + 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, + 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, + 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, + 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, + 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, + 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, + 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, + 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, + 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, + 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, + 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, + 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, + 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, + 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, + 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, + 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, + 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, + 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, + 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, + 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, + 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, + 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, + 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, + 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, + 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, + 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, + 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, + 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, + 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, + 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, + 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, + 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, + 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, + 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, + 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, + 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, + 0x5185cd09}}; + +#endif + +#endif + +#endif + +local const z_crc_t FAR x2n_table[] = { + 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, + 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, + 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, + 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, + 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, + 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, + 0xc40ba6d0, 0xc4e22c3c}; diff --git a/vendor/freetype/src/gzip/ftgzip.c b/vendor/freetype/src/gzip/ftgzip.c new file mode 100644 index 0000000..ca6a2aa --- /dev/null +++ b/vendor/freetype/src/gzip/ftgzip.c @@ -0,0 +1,805 @@ +/**************************************************************************** + * + * ftgzip.c + * + * FreeType support for .gz compressed files. + * + * This optional component relies on zlib. It should mainly be used to + * parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Gzip_Err_ +#define FT_ERR_BASE FT_Mod_Err_Gzip + +#include + + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + +#ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB + +#include + +#else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + /* In this case, we include our own modified sources of the ZLib */ + /* within the `gzip' component. The modifications were necessary */ + /* to #include all files without conflicts, as well as preventing */ + /* the definition of `extern' functions that may cause linking */ + /* conflicts when a program is linked with both FreeType and the */ + /* original ZLib. */ + +#ifndef USE_ZLIB_ZCALLOC +#define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutil.c */ +#endif + + /* Note that our `zlib.h' includes `ftzconf.h' instead of `zconf.h'; */ + /* the main reason is that even a global `zlib.h' includes `zconf.h' */ + /* with */ + /* */ + /* #include "zconf.h" */ + /* */ + /* instead of the expected */ + /* */ + /* #include */ + /* */ + /* so that configuration with `FT_CONFIG_OPTION_SYSTEM_ZLIB' might */ + /* include the wrong `zconf.h' file, leading to errors. */ + +#define ZEXPORT + /* prevent zlib functions from being visible outside their object files */ +#define ZEXTERN static + +#define HAVE_MEMCPY 1 +#define Z_SOLO 1 +#define Z_FREETYPE 1 + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `conversion from XXX to YYY, */ + /* possible loss of data' in order to compile cleanly with */ + /* the maximum level of warnings: zlib is non-FreeType */ + /* code. */ +#pragma warning( push ) +#pragma warning( disable : 4244 ) +#endif /* _MSC_VER */ + +#if defined( __GNUC__ ) +#pragma GCC diagnostic push +#ifndef __cplusplus +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +#include "zutil.c" +#include "inffast.c" +#include "inflate.c" +#include "inftrees.c" +#include "adler32.c" +#include "crc32.c" + +#if defined( __GNUC__ ) +#pragma GCC diagnostic pop +#endif + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + +#endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** Z L I B M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + /* it is better to use FreeType memory routines instead of raw + 'malloc/free' */ + + static voidpf + ft_gzip_alloc( voidpf opaque, + uInt items, + uInt size ) + { + FT_Memory memory = (FT_Memory)opaque; + FT_ULong sz = (FT_ULong)size * items; + FT_Error error; + FT_Pointer p = NULL; + + + /* allocate and zero out */ + FT_MEM_ALLOC( p, sz ); + return p; + } + + + static void + ft_gzip_free( voidpf opaque, + voidpf address ) + { + FT_Memory memory = (FT_Memory)opaque; + + + FT_MEM_FREE( address ); + } + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** Z L I B F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_GZIP_BUFFER_SIZE 4096 + + typedef struct FT_GZipFileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + z_stream zstream; /* zlib input stream */ + + FT_ULong start; /* starting position, after .gz header */ + FT_Byte input[FT_GZIP_BUFFER_SIZE]; /* input read buffer */ + + FT_Byte buffer[FT_GZIP_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + + } FT_GZipFileRec, *FT_GZipFile; + + + /* gzip flag byte */ +#define FT_GZIP_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define FT_GZIP_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define FT_GZIP_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define FT_GZIP_ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define FT_GZIP_COMMENT 0x10 /* bit 4 set: file comment present */ +#define FT_GZIP_RESERVED 0xE0 /* bits 5..7: reserved */ + + + /* check and skip .gz header - we don't support `transparent' compression */ + static FT_Error + ft_gzip_check_header( FT_Stream stream ) + { + FT_Error error; + FT_Byte head[4]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 4 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers; */ + /* head[2] is the method, and head[3] the flags */ + if ( head[0] != 0x1F || + head[1] != 0x8B || + head[2] != Z_DEFLATED || + (head[3] & FT_GZIP_RESERVED) ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* skip time, xflags and os code */ + (void)FT_STREAM_SKIP( 6 ); + + /* skip the extra field */ + if ( head[3] & FT_GZIP_EXTRA_FIELD ) + { + FT_UInt len; + + + if ( FT_READ_USHORT_LE( len ) || + FT_STREAM_SKIP( len ) ) + goto Exit; + } + + /* skip original file name */ + if ( head[3] & FT_GZIP_ORIG_NAME ) + for (;;) + { + FT_UInt c; + + + if ( FT_READ_BYTE( c ) ) + goto Exit; + + if ( c == 0 ) + break; + } + + /* skip .gz comment */ + if ( head[3] & FT_GZIP_COMMENT ) + for (;;) + { + FT_UInt c; + + + if ( FT_READ_BYTE( c ) ) + goto Exit; + + if ( c == 0 ) + break; + } + + /* skip CRC */ + if ( head[3] & FT_GZIP_HEAD_CRC ) + if ( FT_STREAM_SKIP( 2 ) ) + goto Exit; + + Exit: + return error; + } + + + static FT_Error + ft_gzip_file_init( FT_GZipFile zip, + FT_Stream stream, + FT_Stream source ) + { + z_stream* zstream = &zip->zstream; + FT_Error error = FT_Err_Ok; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + + /* check and skip .gz header */ + { + stream = source; + + error = ft_gzip_check_header( stream ); + if ( error ) + goto Exit; + + zip->start = FT_STREAM_POS(); + } + + /* initialize zlib -- there is no zlib header in the compressed stream */ + zstream->zalloc = ft_gzip_alloc; + zstream->zfree = ft_gzip_free; + zstream->opaque = stream->memory; + + zstream->avail_in = 0; + zstream->next_in = zip->buffer; + + if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK || + !zstream->next_in ) + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + static void + ft_gzip_file_done( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + + + inflateEnd( zstream ); + + /* clear the rest */ + zstream->zalloc = NULL; + zstream->zfree = NULL; + zstream->opaque = NULL; + zstream->next_in = NULL; + zstream->next_out = NULL; + zstream->avail_in = 0; + zstream->avail_out = 0; + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_gzip_file_reset( FT_GZipFile zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( zip->start ) ) + { + z_stream* zstream = &zip->zstream; + + + inflateReset( zstream ); + + zstream->avail_in = 0; + zstream->next_in = zip->input; + zstream->avail_out = 0; + zstream->next_out = zip->buffer; + + zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + } + + return error; + } + + + static FT_Error + ft_gzip_file_fill_input( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + FT_Stream stream = zip->source; + FT_ULong size; + + + if ( stream->read ) + { + size = stream->read( stream, stream->pos, zip->input, + FT_GZIP_BUFFER_SIZE ); + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + } + else + { + size = stream->size - stream->pos; + if ( size > FT_GZIP_BUFFER_SIZE ) + size = FT_GZIP_BUFFER_SIZE; + + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + + FT_MEM_COPY( zip->input, stream->base + stream->pos, size ); + } + stream->pos += size; + + zstream->next_in = zip->input; + zstream->avail_in = size; + + return FT_Err_Ok; + } + + + static FT_Error + ft_gzip_file_fill_output( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + FT_Error error = FT_Err_Ok; + + + zip->cursor = zip->buffer; + zstream->next_out = zip->cursor; + zstream->avail_out = FT_GZIP_BUFFER_SIZE; + + while ( zstream->avail_out > 0 ) + { + int err; + + + if ( zstream->avail_in == 0 ) + { + error = ft_gzip_file_fill_input( zip ); + if ( error ) + break; + } + + err = inflate( zstream, Z_NO_FLUSH ); + + if ( err == Z_STREAM_END ) + { + zip->limit = zstream->next_out; + if ( zip->limit == zip->cursor ) + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + else if ( err != Z_OK ) + { + zip->limit = zip->cursor; + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + } + + return error; + } + + + /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */ + static FT_Error + ft_gzip_file_skip_output( FT_GZipFile zip, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + + + for (;;) + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_gzip_file_fill_output( zip ); + if ( error ) + break; + } + + return error; + } + + + static FT_ULong + ft_gzip_file_io( FT_GZipFile zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* Reset inflate stream if we're seeking backwards. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos ) + { + error = ft_gzip_file_reset( zip ); + if ( error ) + goto Exit; + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer, zip->cursor, delta ); + buffer += delta; + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_gzip_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** G Z E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_gzip_stream_close( FT_Stream stream ) + { + FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize gzip file descriptor */ + ft_gzip_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + + if ( !stream->read ) + FT_FREE( stream->base ); + } + + + static unsigned long + ft_gzip_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; + + + return ft_gzip_file_io( zip, offset, buffer, count ); + } + + + static FT_ULong + ft_gzip_get_uncompressed_size( FT_Stream stream ) + { + FT_Error error; + FT_ULong old_pos; + FT_ULong result = 0; + + + old_pos = stream->pos; + if ( !FT_Stream_Seek( stream, stream->size - 4 ) ) + { + result = FT_Stream_ReadULongLE( stream, &error ); + if ( error ) + result = 0; + + (void)FT_Stream_Seek( stream, old_pos ); + } + + return result; + } + + + /* documentation is in ftgzip.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory; + FT_GZipFile zip = NULL; + + + if ( !stream || !source ) + { + error = FT_THROW( Invalid_Stream_Handle ); + goto Exit; + } + + memory = source->memory; + + /* + * check the header right now; this prevents allocating un-necessary + * objects when we don't need them + */ + error = ft_gzip_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_gzip_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + /* + * We use the following trick to try to dramatically improve the + * performance while dealing with small files. If the original stream + * size is less than a certain threshold, we try to load the whole font + * file into memory. This saves us from using the 32KB buffer needed + * to inflate the file, plus the two 4KB intermediate input/output + * buffers used in the `FT_GZipFile' structure. + */ + { + FT_ULong zip_size = ft_gzip_get_uncompressed_size( source ); + + + if ( zip_size != 0 && zip_size < 40 * 1024 ) + { + FT_Byte* zip_buff = NULL; + + + if ( !FT_QALLOC( zip_buff, zip_size ) ) + { + FT_ULong count; + + + count = ft_gzip_file_io( zip, 0, zip_buff, zip_size ); + if ( count == zip_size ) + { + ft_gzip_file_done( zip ); + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + + stream->size = zip_size; + stream->pos = 0; + stream->base = zip_buff; + stream->read = NULL; + stream->close = ft_gzip_stream_close; + + goto Exit; + } + + ft_gzip_file_io( zip, 0, NULL, 0 ); + FT_FREE( zip_buff ); + } + error = FT_Err_Ok; + } + + if ( zip_size ) + stream->size = zip_size; + else + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + } + + stream->pos = 0; + stream->base = NULL; + stream->read = ft_gzip_stream_io; + stream->close = ft_gzip_stream_close; + + Exit: + return error; + } + + + /* documentation is in ftgzip.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Gzip_Uncompress( FT_Memory memory, + FT_Byte* output, + FT_ULong* output_len, + const FT_Byte* input, + FT_ULong input_len ) + { + z_stream stream; + int err; + + + /* check for `input' delayed to `inflate' */ + + if ( !memory || !output_len || !output ) + return FT_THROW( Invalid_Argument ); + + /* this function is modeled after zlib's `uncompress' function */ + + stream.next_in = (Bytef*)input; + stream.avail_in = (uInt)input_len; + + stream.next_out = output; + stream.avail_out = (uInt)*output_len; + + stream.zalloc = ft_gzip_alloc; + stream.zfree = ft_gzip_free; + stream.opaque = memory; + + err = inflateInit2( &stream, MAX_WBITS|32 ); + + if ( err != Z_OK ) + return FT_THROW( Invalid_Argument ); + + err = inflate( &stream, Z_FINISH ); + if ( err != Z_STREAM_END ) + { + inflateEnd( &stream ); + if ( err == Z_OK ) + err = Z_BUF_ERROR; + } + else + { + *output_len = stream.total_out; + + err = inflateEnd( &stream ); + } + + if ( err == Z_MEM_ERROR ) + return FT_THROW( Out_Of_Memory ); + + if ( err == Z_BUF_ERROR ) + return FT_THROW( Array_Too_Large ); + + if ( err == Z_DATA_ERROR ) + return FT_THROW( Invalid_Table ); + + if ( err == Z_NEED_DICT ) + return FT_THROW( Invalid_Table ); + + return FT_Err_Ok; + } + + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Gzip_Uncompress( FT_Memory memory, + FT_Byte* output, + FT_ULong* output_len, + const FT_Byte* input, + FT_ULong input_len ) + { + FT_UNUSED( memory ); + FT_UNUSED( output ); + FT_UNUSED( output_len ); + FT_UNUSED( input ); + FT_UNUSED( input_len ); + + return FT_THROW( Unimplemented_Feature ); + } + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + + +/* END */ diff --git a/vendor/freetype/src/gzip/ftzconf.h b/vendor/freetype/src/gzip/ftzconf.h new file mode 100644 index 0000000..bf977d3 --- /dev/null +++ b/vendor/freetype/src/gzip/ftzconf.h @@ -0,0 +1,547 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/vendor/freetype/src/gzip/gzguts.h b/vendor/freetype/src/gzip/gzguts.h new file mode 100644 index 0000000..4f09a52 --- /dev/null +++ b/vendor/freetype/src/gzip/gzguts.h @@ -0,0 +1,219 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY__ 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/vendor/freetype/src/gzip/inffast.c b/vendor/freetype/src/gzip/inffast.c new file mode 100644 index 0000000..809737b --- /dev/null +++ b/vendor/freetype/src/gzip/inffast.c @@ -0,0 +1,323 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast( + z_streamp strm, + unsigned start) +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code const *here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode + (hold & lmask); + dolen: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op == 0) { /* literal */ + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode + (hold & dmask); + dodist: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode + here->val + (hold & ((1U << op) - 1)); + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode + here->val + (hold & ((1U << op) - 1)); + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/vendor/freetype/src/gzip/inffast.h b/vendor/freetype/src/gzip/inffast.h new file mode 100644 index 0000000..684ae87 --- /dev/null +++ b/vendor/freetype/src/gzip/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/vendor/freetype/src/gzip/inffixed.h b/vendor/freetype/src/gzip/inffixed.h new file mode 100644 index 0000000..d628327 --- /dev/null +++ b/vendor/freetype/src/gzip/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/vendor/freetype/src/gzip/inflate.c b/vendor/freetype/src/gzip/inflate.c new file mode 100644 index 0000000..5117e2e --- /dev/null +++ b/vendor/freetype/src/gzip/inflate.c @@ -0,0 +1,1605 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local int inflateStateCheck OF((z_streamp strm)); +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +#ifndef Z_FREETYPE +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); +#endif + +local int inflateStateCheck( + z_streamp strm) +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep( + z_streamp strm) +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->flags = -1; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset( + z_streamp strm) +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2( + z_streamp strm, + int windowBits) +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_( + z_streamp strm, + int windowBits, + const char *version, + int stream_size) +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +#ifndef Z_FREETYPE + +int ZEXPORT inflateInit_( + z_streamp strm, + const char *version, + int stream_size) +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime( + z_streamp strm, + int bits, + int value) +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +#endif /* !Z_FREETYPE */ + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables( + struct inflate_state FAR *state) +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow( + z_streamp strm, + const Bytef *end, + unsigned copy) +{ + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE_CHECK(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate( + z_streamp strm, + int flush) +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + /* fallthrough */ + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + /* fallthrough */ + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + /* fallthrough */ + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + /* fallthrough */ + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + /* fallthrough */ + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + /* fallthrough */ + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + /* fallthrough */ + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + /* fallthrough */ + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + /* fallthrough */ + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case COPY_: + state->mode = COPY; + /* fallthrough */ + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + /* fallthrough */ + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + /* fallthrough */ + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case LEN_: + state->mode = LEN; + /* fallthrough */ + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + /* fallthrough */ + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + /* fallthrough */ + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + /* fallthrough */ + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + /* fallthrough */ + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + /* fallthrough */ + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + /* fallthrough */ + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* fallthrough */ + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd( + z_streamp strm) +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +#ifndef Z_FREETYPE + +int ZEXPORT inflateGetDictionary( + z_streamp strm, + Bytef *dictionary, + uInt *dictLength) +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary( + z_streamp strm, + const Bytef *dictionary, + uInt dictLength) +{ + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader( + z_streamp strm, + gz_headerp head) +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch( + unsigned FAR *have, + const unsigned char FAR *buf, + unsigned len) +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync( + z_streamp strm) +{ + unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->flags = flags; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint( + z_streamp strm) +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy( + z_streamp dest, + z_streamp source) +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine( + z_streamp strm, + int subvert) +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate( + z_streamp strm, + int check) +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark( + z_streamp strm) +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed( + z_streamp strm) +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} + +#endif /* !Z_FREETYPE */ diff --git a/vendor/freetype/src/gzip/inflate.h b/vendor/freetype/src/gzip/inflate.h new file mode 100644 index 0000000..c6f5a52 --- /dev/null +++ b/vendor/freetype/src/gzip/inflate.h @@ -0,0 +1,131 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef INFLATE_H +#define INFLATE_H + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; + +#endif /* INFLATE_H */ diff --git a/vendor/freetype/src/gzip/inftrees.c b/vendor/freetype/src/gzip/inftrees.c new file mode 100644 index 0000000..dd4965e --- /dev/null +++ b/vendor/freetype/src/gzip/inftrees.c @@ -0,0 +1,304 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +static const char inflate_copyright[] = + " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table( + codetype type, + unsigned short FAR *lens, + unsigned codes, + code FAR * FAR *table, + unsigned FAR *bits, + unsigned short FAR *work) +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/vendor/freetype/src/gzip/inftrees.h b/vendor/freetype/src/gzip/inftrees.h new file mode 100644 index 0000000..a2207ef --- /dev/null +++ b/vendor/freetype/src/gzip/inftrees.h @@ -0,0 +1,67 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef INFTREES_H +#define INFTREES_H + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +static int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); + +#endif /* INFTREES_H_ */ diff --git a/vendor/freetype/src/gzip/patches/freetype-zlib.diff b/vendor/freetype/src/gzip/patches/freetype-zlib.diff new file mode 100644 index 0000000..6ac76df --- /dev/null +++ b/vendor/freetype/src/gzip/patches/freetype-zlib.diff @@ -0,0 +1,469 @@ +[zlib] Fix zlib sources for compilation with FreeType + +We must ensure that they do not issue compiler errors or warnings when they +are compiled as part of `src/gzip/ftgzip.c`. + +* src/gzip/gzguts.h (COPY): Rename to... +(COPY__): ... this since `COPY` and `COPY_` conflict with enum values, +which have the same name in `zlib.h`. + +* src/gzip/inflate.c, src/gzip/adler32.c, src/gzip/crc32.c, +src/gzip/zutil.c: Omit unused function declarations and definitions when +`Z_FREETYPE` is defined. + +* src/gzip/inffast.h (inflate_fast): Declare as static. + +* src/gzip/inftrees.c (inflate_copyright): Declare as static. + +* src/gzip/zlib.h: Include `ftzconf.h` instead of `zconf.h` to avoid +conflicts with system-installed headers. +Omit unused function declarations when `Z_FREETYPE` is defined. +(inflateInit2)[Z_FREETYPE]: Provide proper declaration. + +* src/gzip/zutil.h: Use `ft_memxxx` functions instead of `memxxx`. +Omit unused function declarations when `Z_FREETYPE` is defined. + +* src/gzip/inflate.h, src/gzip/inftrees.h: Add header guard macros to +prevent compiler errors. + +* src/gzip/inftrees.h: Add header guard macros to prevent compiler errors. +(inflate_table): Declare as static. + +diff --git b/src/gzip/adler32.c a/src/gzip/adler32.c +index be5e8a247..aa032e1dd 100644 +--- b/src/gzip/adler32.c ++++ a/src/gzip/adler32.c +@@ -7,7 +7,9 @@ + + #include "zutil.h" + ++#ifndef Z_FREETYPE + local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); ++#endif + + #define BASE 65521U /* largest prime smaller than 65536 */ + #define NMAX 5552 +@@ -139,6 +141,8 @@ uLong ZEXPORT adler32( + return adler32_z(adler, buf, len); + } + ++#ifndef Z_FREETYPE ++ + /* ========================================================================= */ + local uLong adler32_combine_( + uLong adler1, +@@ -184,3 +188,5 @@ uLong ZEXPORT adler32_combine64( + { + return adler32_combine_(adler1, adler2, len2); + } ++ ++#endif /* !Z_FREETYPE */ +diff --git b/src/gzip/crc32.c a/src/gzip/crc32.c +index 3a52aa89d..6cd1b09d5 100644 +--- b/src/gzip/crc32.c ++++ a/src/gzip/crc32.c +@@ -103,9 +103,11 @@ + # define ARMCRC32 + #endif + ++#ifndef Z_FREETYPE + /* Local functions. */ + local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); + local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); ++#endif /* Z_FREETYPE */ + + #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) + local z_word_t byte_swap OF((z_word_t word)); +@@ -544,6 +546,8 @@ local void braid(ltl, big, n, w) + * generation above. + */ + ++#ifndef Z_FREETYPE ++ + /* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. +@@ -600,6 +604,8 @@ const z_crc_t FAR * ZEXPORT get_crc_table() + return (const z_crc_t FAR *)crc_table; + } + ++#endif /* Z_FREETYPE */ ++ + /* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for +@@ -1077,6 +1083,8 @@ unsigned long ZEXPORT crc32( + return crc32_z(crc, buf, len); + } + ++#ifndef Z_FREETYPE ++ + /* ========================================================================= */ + uLong ZEXPORT crc32_combine64( + uLong crc1, +@@ -1123,3 +1131,5 @@ uLong ZEXPORT crc32_combine_op( + { + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); + } ++ ++#endif /* Z_FREETYPE */ +diff --git b/src/gzip/gzguts.h a/src/gzip/gzguts.h +index 57faf3716..4f09a52a7 100644 +--- b/src/gzip/gzguts.h ++++ a/src/gzip/gzguts.h +@@ -163,7 +163,7 @@ + + /* values for gz_state how */ + #define LOOK 0 /* look for a gzip header */ +-#define COPY 1 /* copy input directly */ ++#define COPY__ 1 /* copy input directly */ + #define GZIP 2 /* decompress a gzip stream */ + + /* internal gzip file state data structure */ +diff --git b/src/gzip/inffast.h a/src/gzip/inffast.h +index e5c1aa4ca..684ae878c 100644 +--- b/src/gzip/inffast.h ++++ a/src/gzip/inffast.h +@@ -8,4 +8,4 @@ + subject to change. Applications should only use zlib.h. + */ + +-void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); ++static void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); +diff --git b/src/gzip/inflate.c a/src/gzip/inflate.c +index c9e566b03..5117e2e26 100644 +--- b/src/gzip/inflate.c ++++ a/src/gzip/inflate.c +@@ -99,8 +99,10 @@ local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + #ifdef BUILDFIXED + void makefixed OF((void)); + #endif ++#ifndef Z_FREETYPE + local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); ++#endif + + local int inflateStateCheck( + z_streamp strm) +@@ -239,6 +241,8 @@ int ZEXPORT inflateInit2_( + return ret; + } + ++#ifndef Z_FREETYPE ++ + int ZEXPORT inflateInit_( + z_streamp strm, + const char *version, +@@ -268,6 +272,8 @@ int ZEXPORT inflatePrime( + return Z_OK; + } + ++#endif /* !Z_FREETYPE */ ++ + /* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. +@@ -1315,6 +1321,8 @@ int ZEXPORT inflateEnd( + return Z_OK; + } + ++#ifndef Z_FREETYPE ++ + int ZEXPORT inflateGetDictionary( + z_streamp strm, + Bytef *dictionary, +@@ -1593,3 +1601,5 @@ unsigned long ZEXPORT inflateCodesUsed( + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); + } ++ ++#endif /* !Z_FREETYPE */ +diff --git b/src/gzip/inflate.h a/src/gzip/inflate.h +index f127b6b1f..c6f5a52e1 100644 +--- b/src/gzip/inflate.h ++++ a/src/gzip/inflate.h +@@ -3,6 +3,9 @@ + * For conditions of distribution and use, see copyright notice in zlib.h + */ + ++#ifndef INFLATE_H ++#define INFLATE_H ++ + /* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. +@@ -124,3 +127,5 @@ struct inflate_state { + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ + }; ++ ++#endif /* INFLATE_H */ +diff --git b/src/gzip/inftrees.c a/src/gzip/inftrees.c +index d8405a24c..dd4965e9a 100644 +--- b/src/gzip/inftrees.c ++++ a/src/gzip/inftrees.c +@@ -8,7 +8,7 @@ + + #define MAXBITS 15 + +-const char inflate_copyright[] = ++static const char inflate_copyright[] = + " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; + /* + If you use the zlib library in a product, an acknowledgment is welcome +diff --git b/src/gzip/inftrees.h a/src/gzip/inftrees.h +index f53665311..a2207efb1 100644 +--- b/src/gzip/inftrees.h ++++ a/src/gzip/inftrees.h +@@ -3,6 +3,9 @@ + * For conditions of distribution and use, see copyright notice in zlib.h + */ + ++#ifndef INFTREES_H ++#define INFTREES_H ++ + /* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. +@@ -57,6 +60,8 @@ typedef enum { + DISTS + } codetype; + +-int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, ++static int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); ++ ++#endif /* INFTREES_H_ */ +diff --git b/src/gzip/zlib.h a/src/gzip/zlib.h +index 953cb5012..3f2f76e3c 100644 +--- b/src/gzip/zlib.h ++++ a/src/gzip/zlib.h +@@ -31,7 +31,7 @@ + #ifndef ZLIB_H + #define ZLIB_H + +-#include "zconf.h" ++#include "ftzconf.h" + + #ifdef __cplusplus + extern "C" { +@@ -211,6 +211,8 @@ typedef gz_header FAR *gz_headerp; + + #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + ++#ifndef Z_FREETYPE ++ + #define zlib_version zlibVersion() + /* for compatibility with versions < 1.0.2 */ + +@@ -373,6 +375,7 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); + deallocated). + */ + ++#endif /* !Z_FREETYPE */ + + /* + ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); +@@ -534,6 +537,8 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); + The following functions are needed only in some special applications. + */ + ++#ifndef Z_FREETYPE ++ + /* + ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, +@@ -956,6 +961,8 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + destination. + */ + ++#endif /* !Z_FREETYPE */ ++ + ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); + /* + This function is equivalent to inflateEnd followed by inflateInit, +@@ -980,6 +987,8 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + the windowBits parameter is invalid. + */ + ++#ifndef Z_FREETYPE ++ + ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +@@ -1069,6 +1078,8 @@ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + stream state was inconsistent. + */ + ++#endif /* !Z_FREETYPE */ ++ + /* + ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); +@@ -1095,6 +1106,8 @@ typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); + typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + ++#ifndef Z_FREETYPE ++ + ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +@@ -1214,6 +1227,8 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); + 27-31: 0 (reserved) + */ + ++#endif /* !Z_FREETYPE */ ++ + #ifndef Z_SOLO + + /* utility functions */ +@@ -1765,6 +1780,8 @@ ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2)); + crc32_combine_op(). + */ + ++#ifndef Z_FREETYPE ++ + ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); + /* + Give the same result as crc32_combine(), using op in place of len2. op is +@@ -1822,6 +1839,19 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + ZLIB_VERSION, (int)sizeof(z_stream)) + #endif + ++#else /* Z_FREETYPE */ ++ ++ ++ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, ++ const char *version, int stream_size)); ++ ++# define inflateInit2(strm, windowBits) \ ++ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ ++ (int)sizeof(z_stream)) ++ ++#endif /* Z_FREETYPE */ ++ ++ + #ifndef Z_SOLO + + /* gzgetc() macro and its supporting function and exposed data structure. Note +@@ -1901,20 +1931,25 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ + + #else /* Z_SOLO */ + ++#ifndef Z_FREETYPE + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); ++#endif + + #endif /* !Z_SOLO */ + + /* undocumented functions */ ++#ifndef Z_FREETYPE + ZEXTERN const char * ZEXPORT zError OF((int)); + ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); + ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); + ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); + ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); + ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); ++#endif /* !Z_FREETYPE */ + ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ++#ifndef Z_FREETYPE + ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); + #if defined(_WIN32) && !defined(Z_SOLO) + ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, +@@ -1927,6 +1962,7 @@ ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + va_list va)); + # endif + #endif ++#endif /* !Z_FREETYPE */ + + #ifdef __cplusplus + } +diff --git b/src/gzip/zutil.c a/src/gzip/zutil.c +index ef174ca64..542706ca0 100644 +--- b/src/gzip/zutil.c ++++ a/src/gzip/zutil.c +@@ -10,6 +10,8 @@ + # include "gzguts.h" + #endif + ++#ifndef Z_FREETYPE ++ + z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ +@@ -138,6 +140,8 @@ const char * ZEXPORT zError( + return ERR_MSG(err); + } + ++#endif /* !Z_FREETYPE */ ++ + #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. +@@ -159,6 +163,8 @@ void ZLIB_INTERNAL zmemcpy( + } while (--len != 0); + } + ++#ifndef Z_FREETYPE ++ + int ZLIB_INTERNAL zmemcmp( + const Bytef* s1, + const Bytef* s2, +@@ -181,6 +187,7 @@ void ZLIB_INTERNAL zmemzero( + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); + } ++#endif /* !Z_FREETYPE */ + #endif + + #ifndef Z_SOLO +diff --git b/src/gzip/zutil.h a/src/gzip/zutil.h +index 0bc7f4ecd..055ba8b62 100644 +--- b/src/gzip/zutil.h ++++ a/src/gzip/zutil.h +@@ -53,8 +53,10 @@ typedef unsigned long ulg; + # endif + #endif + ++#ifndef Z_FREETYPE + extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + /* (size given to avoid silly warnings with Visual C++) */ ++#endif /* !Z_FREETYPE */ + + #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +@@ -188,6 +190,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + #pragma warn -8066 + #endif + ++#ifndef Z_FREETYPE ++ + /* provide prototypes for these when building zlib without LFS */ + #if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) +@@ -196,6 +200,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); + #endif + ++#endif /* !Z_FREETYPE */ ++ + /* common defaults */ + + #ifndef OS_CODE +@@ -227,9 +233,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + # define zmemcmp _fmemcmp + # define zmemzero(dest, len) _fmemset(dest, 0, len) + # else +-# define zmemcpy memcpy +-# define zmemcmp memcmp +-# define zmemzero(dest, len) memset(dest, 0, len) ++# define zmemcpy ft_memcpy ++# define zmemcmp ft_memcmp ++# define zmemzero(dest, len) ft_memset(dest, 0, len) + # endif + #else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); diff --git a/vendor/freetype/src/gzip/rules.mk b/vendor/freetype/src/gzip/rules.mk new file mode 100644 index 0000000..c76eacb --- /dev/null +++ b/vendor/freetype/src/gzip/rules.mk @@ -0,0 +1,81 @@ +# +# FreeType 2 GZip support configuration rules +# + + +# Copyright (C) 2002-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# gzip driver directory +# +GZIP_DIR := $(SRC_DIR)/gzip + + +# compilation flags for the driver +# +ifeq ($(SYSTEM_ZLIB),) + GZIP_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(GZIP_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) +else + GZIP_COMPILE := $(CC) $(ANSIFLAGS) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) +endif + + +# gzip support sources +# +# All source and header files get loaded by `ftgzip.c' only if SYSTEM_ZLIB +# is not defined (regardless whether we have a `single' or a `multi' build). +# +ifeq ($(SYSTEM_ZLIB),) + GZIP_DRV_SRCS := $(GZIP_DIR)/adler32.c \ + $(GZIP_DIR)/crc32.c \ + $(GZIP_DIR)/crc32.h \ + $(GZIP_DIR)/ftzconf.h \ + $(GZIP_DIR)/inffast.c \ + $(GZIP_DIR)/inffast.h \ + $(GZIP_DIR)/inffixed.h \ + $(GZIP_DIR)/inflate.c \ + $(GZIP_DIR)/inflate.h \ + $(GZIP_DIR)/inftrees.c \ + $(GZIP_DIR)/inftrees.h \ + $(GZIP_DIR)/zlib.h \ + $(GZIP_DIR)/zutil.c \ + $(GZIP_DIR)/zutil.h +endif + +# gzip driver object(s) +# +# GZIP_DRV_OBJ is used during both `single' and `multi' builds +# +GZIP_DRV_OBJ := $(OBJ_DIR)/ftgzip.$O + + +# gzip main source file +# +GZIP_DRV_SRC := $(GZIP_DIR)/ftgzip.c + + +# gzip support - object +# +$(GZIP_DRV_OBJ): $(GZIP_DRV_SRC) $(GZIP_DRV_SRCS) $(FREETYPE_H) + $(GZIP_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(GZIP_DRV_SRC)) + + +# update main driver object lists +# +DRV_OBJS_S += $(GZIP_DRV_OBJ) +DRV_OBJS_M += $(GZIP_DRV_OBJ) + + +# EOF diff --git a/vendor/freetype/src/gzip/zlib.h b/vendor/freetype/src/gzip/zlib.h new file mode 100644 index 0000000..3f2f76e --- /dev/null +++ b/vendor/freetype/src/gzip/zlib.h @@ -0,0 +1,1971 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.13, October 13th, 2022 + + Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "ftzconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.13" +#define ZLIB_VERNUM 0x12d0 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 13 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#ifndef Z_FREETYPE + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + +#endif /* !Z_FREETYPE */ + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +#ifndef Z_FREETYPE + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +#endif /* !Z_FREETYPE */ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +#ifndef Z_FREETYPE + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +#endif /* !Z_FREETYPE */ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +#ifndef Z_FREETYPE + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#endif /* !Z_FREETYPE */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); +/* + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Compress and write the given null-terminated string s to file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewind file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z OF((uLong crc, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2)); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). +*/ + +#ifndef Z_FREETYPE + +ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#else /* Z_FREETYPE */ + + +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); + +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) + +#endif /* Z_FREETYPE */ + + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# define z_crc32_combine_gen z_crc32_combine_gen64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# define crc32_combine_gen crc32_combine_gen64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); +#endif + +#else /* Z_SOLO */ + +#ifndef Z_FREETYPE + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); +#endif + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +#ifndef Z_FREETYPE +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); +#endif /* !Z_FREETYPE */ +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +#ifndef Z_FREETYPE +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif +#endif /* !Z_FREETYPE */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/vendor/freetype/src/gzip/zutil.c b/vendor/freetype/src/gzip/zutil.c new file mode 100644 index 0000000..542706c --- /dev/null +++ b/vendor/freetype/src/gzip/zutil.c @@ -0,0 +1,334 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +#ifndef Z_FREETYPE + +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif + /* +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif + */ +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error( + char *m) +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError( + int err) +{ + return ERR_MSG(err); +} + +#endif /* !Z_FREETYPE */ + +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy( + Bytef* dest, + const Bytef* source, + uInt len) +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +#ifndef Z_FREETYPE + +int ZLIB_INTERNAL zmemcmp( + const Bytef* s1, + const Bytef* s2, + uInt len) +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero( + Bytef* dest, + uInt len) +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif /* !Z_FREETYPE */ +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) +{ + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) +{ + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) +{ + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc( + voidpf opaque, + unsigned items, + unsigned size) +{ + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree( + voidpf opaque, + voidpf ptr) +{ + (void)opaque; + free(ptr); +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/vendor/freetype/src/gzip/zutil.h b/vendor/freetype/src/gzip/zutil.h new file mode 100644 index 0000000..055ba8b --- /dev/null +++ b/vendor/freetype/src/gzip/zutil.h @@ -0,0 +1,281 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) +# include +# if (ULONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long +# elif (ULLONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long long +# elif (UINT_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned +# endif +#endif + +#ifndef Z_FREETYPE +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ +#endif /* !Z_FREETYPE */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 7 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +#ifndef Z_FREETYPE + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); +#endif + +#endif /* !Z_FREETYPE */ + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy ft_memcpy +# define zmemcmp ft_memcmp +# define zmemzero(dest, len) ft_memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/vendor/freetype/src/lzw/ftlzw.c b/vendor/freetype/src/lzw/ftlzw.c new file mode 100644 index 0000000..8838379 --- /dev/null +++ b/vendor/freetype/src/lzw/ftlzw.c @@ -0,0 +1,415 @@ +/**************************************************************************** + * + * ftlzw.c + * + * FreeType support for .Z compressed files. + * + * This optional component relies on NetBSD's zopen(). It should mainly + * be used to parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2004-2023 by + * Albert Chin-A-Young. + * + * based on code in `src/gzip/ftgzip.c' + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX LZW_Err_ +#define FT_ERR_BASE FT_Mod_Err_LZW + +#include + + +#ifdef FT_CONFIG_OPTION_USE_LZW + +#include "ftzopen.h" + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_LZW_BUFFER_SIZE 4096 + + typedef struct FT_LZWFileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + FT_LzwStateRec lzw; /* lzw decompressor state */ + + FT_Byte buffer[FT_LZW_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + + } FT_LZWFileRec, *FT_LZWFile; + + + /* check and skip .Z header */ + static FT_Error + ft_lzw_check_header( FT_Stream stream ) + { + FT_Error error; + FT_Byte head[2]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 2 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers */ + if ( head[0] != 0x1F || + head[1] != 0x9D ) + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + static FT_Error + ft_lzw_file_init( FT_LZWFile zip, + FT_Stream stream, + FT_Stream source ) + { + FT_LzwState lzw = &zip->lzw; + FT_Error error; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + + /* check and skip .Z header */ + error = ft_lzw_check_header( source ); + if ( error ) + goto Exit; + + /* initialize internal lzw variable */ + ft_lzwstate_init( lzw, source ); + + Exit: + return error; + } + + + static void + ft_lzw_file_done( FT_LZWFile zip ) + { + /* clear the rest */ + ft_lzwstate_done( &zip->lzw ); + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_lzw_file_reset( FT_LZWFile zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( 0 ) ) + { + ft_lzwstate_reset( &zip->lzw ); + + zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + } + + return error; + } + + + static FT_Error + ft_lzw_file_fill_output( FT_LZWFile zip ) + { + FT_LzwState lzw = &zip->lzw; + FT_ULong count; + FT_Error error = FT_Err_Ok; + + + zip->cursor = zip->buffer; + + count = ft_lzwstate_io( lzw, zip->buffer, FT_LZW_BUFFER_SIZE ); + + zip->limit = zip->cursor + count; + + if ( count == 0 ) + error = FT_THROW( Invalid_Stream_Operation ); + + return error; + } + + + /* fill output buffer; `count' must be <= FT_LZW_BUFFER_SIZE */ + static FT_Error + ft_lzw_file_skip_output( FT_LZWFile zip, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + + + /* first, we skip what we can from the output buffer */ + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + } + + /* next, we skip as many bytes remaining as possible */ + while ( count > 0 ) + { + FT_ULong delta = FT_LZW_BUFFER_SIZE; + FT_ULong numread; + + + if ( delta > count ) + delta = count; + + numread = ft_lzwstate_io( &zip->lzw, NULL, delta ); + if ( numread < delta ) + { + /* not enough bytes */ + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + + zip->pos += delta; + count -= delta; + } + + return error; + } + + + static FT_ULong + ft_lzw_file_io( FT_LZWFile zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* seeking backwards. */ + if ( pos < zip->pos ) + { + /* If the new position is within the output buffer, simply */ + /* decrement pointers, otherwise we reset the stream completely! */ + if ( ( zip->pos - pos ) <= (FT_ULong)( zip->cursor - zip->buffer ) ) + { + zip->cursor -= zip->pos - pos; + zip->pos = pos; + } + else + { + error = ft_lzw_file_reset( zip ); + if ( error ) + goto Exit; + } + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_lzw_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer + result, zip->cursor, delta ); + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_lzw_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** L Z W E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_lzw_stream_close( FT_Stream stream ) + { + FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize lzw file descriptor */ + ft_lzw_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + } + + + static unsigned long + ft_lzw_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer; + + + return ft_lzw_file_io( zip, offset, buffer, count ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory; + FT_LZWFile zip = NULL; + + + if ( !stream || !source ) + { + error = FT_THROW( Invalid_Stream_Handle ); + goto Exit; + } + + memory = source->memory; + + /* + * Check the header right now; this prevents allocation of a huge + * LZWFile object (400 KByte of heap memory) if not necessary. + * + * Did I mention that you should never use .Z compressed font + * files? + */ + error = ft_lzw_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_lzw_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + stream->pos = 0; + stream->base = NULL; + stream->read = ft_lzw_stream_io; + stream->close = ft_lzw_stream_close; + + Exit: + return error; + } + + +#include "ftzopen.c" + + +#else /* !FT_CONFIG_OPTION_USE_LZW */ + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return FT_THROW( Unimplemented_Feature ); + } + + +#endif /* !FT_CONFIG_OPTION_USE_LZW */ + + +/* END */ diff --git a/vendor/freetype/src/lzw/ftzopen.c b/vendor/freetype/src/lzw/ftzopen.c new file mode 100644 index 0000000..e680c4d --- /dev/null +++ b/vendor/freetype/src/lzw/ftzopen.c @@ -0,0 +1,429 @@ +/**************************************************************************** + * + * ftzopen.c + * + * FreeType support for .Z compressed files. + * + * This optional component relies on NetBSD's zopen(). It should mainly + * be used to parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2005-2023 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include "ftzopen.h" +#include +#include +#include + + + static int + ft_lzwstate_refill( FT_LzwState state ) + { + FT_ULong count; + + + if ( state->in_eof ) + return -1; + + count = FT_Stream_TryRead( state->source, + state->buf_tab, + state->num_bits ); /* WHY? */ + + state->buf_size = (FT_UInt)count; + state->buf_total += count; + state->in_eof = FT_BOOL( count < state->num_bits ); + state->buf_offset = 0; + + state->buf_size <<= 3; + if ( state->buf_size > state->num_bits ) + state->buf_size -= state->num_bits - 1; + else + return -1; /* not enough data */ + + if ( count == 0 ) /* end of file */ + return -1; + + return 0; + } + + + static FT_Int32 + ft_lzwstate_get_code( FT_LzwState state ) + { + FT_UInt num_bits = state->num_bits; + FT_UInt offset = state->buf_offset; + FT_Byte* p; + FT_Int result; + + + if ( state->buf_clear || + offset >= state->buf_size || + state->free_ent >= state->free_bits ) + { + if ( state->free_ent >= state->free_bits ) + { + state->num_bits = ++num_bits; + if ( num_bits > LZW_MAX_BITS ) + return -1; + + state->free_bits = state->num_bits < state->max_bits + ? (FT_UInt)( ( 1UL << num_bits ) - 256 ) + : state->max_free + 1; + } + + if ( state->buf_clear ) + { + state->num_bits = num_bits = LZW_INIT_BITS; + state->free_bits = (FT_UInt)( ( 1UL << num_bits ) - 256 ); + state->buf_clear = 0; + } + + if ( ft_lzwstate_refill( state ) < 0 ) + return -1; + + offset = 0; + } + + state->buf_offset = offset + num_bits; + + p = &state->buf_tab[offset >> 3]; + offset &= 7; + result = *p++ >> offset; + offset = 8 - offset; + num_bits -= offset; + + if ( num_bits >= 8 ) + { + result |= *p++ << offset; + offset += 8; + num_bits -= 8; + } + if ( num_bits > 0 ) + result |= ( *p & LZW_MASK( num_bits ) ) << offset; + + return result; + } + + + /* grow the character stack */ + static int + ft_lzwstate_stack_grow( FT_LzwState state ) + { + if ( state->stack_top >= state->stack_size ) + { + FT_Memory memory = state->memory; + FT_Error error; + FT_Offset old_size = state->stack_size; + FT_Offset new_size = old_size; + + new_size = new_size + ( new_size >> 1 ) + 4; + + /* if relocating to heap */ + if ( state->stack == state->stack_0 ) + { + state->stack = NULL; + old_size = 0; + } + + /* requirement of the character stack larger than 1< ( 1 << LZW_MAX_BITS ) ) + { + new_size = 1 << LZW_MAX_BITS; + if ( new_size == old_size ) + return -1; + } + + if ( FT_QREALLOC( state->stack, old_size, new_size ) ) + return -1; + + /* if relocating to heap */ + if ( old_size == 0 ) + FT_MEM_COPY( state->stack, state->stack_0, FT_LZW_DEFAULT_STACK_SIZE ); + + state->stack_size = new_size; + } + return 0; + } + + + /* grow the prefix/suffix arrays */ + static int + ft_lzwstate_prefix_grow( FT_LzwState state ) + { + FT_UInt old_size = state->prefix_size; + FT_UInt new_size = old_size; + FT_Memory memory = state->memory; + FT_Error error; + + + if ( new_size == 0 ) /* first allocation -> 9 bits */ + new_size = 512; + else + new_size += new_size >> 2; /* don't grow too fast */ + + /* + * Note that the `suffix' array is located in the same memory block + * pointed to by `prefix'. + * + * I know that sizeof(FT_Byte) == 1 by definition, but it is clearer + * to write it literally. + * + */ + if ( FT_REALLOC_MULT( state->prefix, old_size, new_size, + sizeof ( FT_UShort ) + sizeof ( FT_Byte ) ) ) + return -1; + + /* now adjust `suffix' and move the data accordingly */ + state->suffix = (FT_Byte*)( state->prefix + new_size ); + + FT_MEM_MOVE( state->suffix, + state->prefix + old_size, + old_size * sizeof ( FT_Byte ) ); + + state->prefix_size = new_size; + return 0; + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_reset( FT_LzwState state ) + { + state->in_eof = 0; + state->buf_offset = 0; + state->buf_size = 0; + state->buf_clear = 0; + state->buf_total = 0; + state->stack_top = 0; + state->num_bits = LZW_INIT_BITS; + state->phase = FT_LZW_PHASE_START; + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_init( FT_LzwState state, + FT_Stream source ) + { + FT_ZERO( state ); + + state->source = source; + state->memory = source->memory; + + state->prefix = NULL; + state->suffix = NULL; + state->prefix_size = 0; + + state->stack = state->stack_0; + state->stack_size = sizeof ( state->stack_0 ); + + ft_lzwstate_reset( state ); + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_done( FT_LzwState state ) + { + FT_Memory memory = state->memory; + + + ft_lzwstate_reset( state ); + + if ( state->stack != state->stack_0 ) + FT_FREE( state->stack ); + + FT_FREE( state->prefix ); + state->suffix = NULL; + + FT_ZERO( state ); + } + + +#define FTLZW_STACK_PUSH( c ) \ + FT_BEGIN_STMNT \ + if ( state->stack_top >= state->stack_size && \ + ft_lzwstate_stack_grow( state ) < 0 ) \ + goto Eof; \ + \ + state->stack[state->stack_top++] = (FT_Byte)(c); \ + FT_END_STMNT + + + FT_LOCAL_DEF( FT_ULong ) + ft_lzwstate_io( FT_LzwState state, + FT_Byte* buffer, + FT_ULong out_size ) + { + FT_ULong result = 0; + + FT_UInt old_char = state->old_char; + FT_UInt old_code = state->old_code; + FT_UInt in_code = state->in_code; + + + if ( out_size == 0 ) + goto Exit; + + switch ( state->phase ) + { + case FT_LZW_PHASE_START: + { + FT_Byte max_bits; + FT_Int32 c; + + + /* skip magic bytes, and read max_bits + block_flag */ + if ( FT_Stream_Seek( state->source, 2 ) != 0 || + FT_Stream_TryRead( state->source, &max_bits, 1 ) != 1 ) + goto Eof; + + state->max_bits = max_bits & LZW_BIT_MASK; + state->block_mode = max_bits & LZW_BLOCK_MASK; + state->max_free = (FT_UInt)( ( 1UL << state->max_bits ) - 256 ); + + if ( state->max_bits > LZW_MAX_BITS ) + goto Eof; + + state->num_bits = LZW_INIT_BITS; + state->free_ent = ( state->block_mode ? LZW_FIRST + : LZW_CLEAR ) - 256; + in_code = 0; + + state->free_bits = state->num_bits < state->max_bits + ? (FT_UInt)( ( 1UL << state->num_bits ) - 256 ) + : state->max_free + 1; + + c = ft_lzwstate_get_code( state ); + if ( c < 0 || c > 255 ) + goto Eof; + + old_code = old_char = (FT_UInt)c; + + if ( buffer ) + buffer[result] = (FT_Byte)old_char; + + if ( ++result >= out_size ) + goto Exit; + + state->phase = FT_LZW_PHASE_CODE; + } + FALL_THROUGH; + + case FT_LZW_PHASE_CODE: + { + FT_Int32 c; + FT_UInt code; + + + NextCode: + c = ft_lzwstate_get_code( state ); + if ( c < 0 ) + goto Eof; + + code = (FT_UInt)c; + + if ( code == LZW_CLEAR && state->block_mode ) + { + /* why not LZW_FIRST-256 ? */ + state->free_ent = ( LZW_FIRST - 1 ) - 256; + state->buf_clear = 1; + + /* not quite right, but at least more predictable */ + old_code = 0; + old_char = 0; + + goto NextCode; + } + + in_code = code; /* save code for later */ + + if ( code >= 256U ) + { + /* special case for KwKwKwK */ + if ( code - 256U >= state->free_ent ) + { + /* corrupted LZW stream */ + if ( code - 256U > state->free_ent ) + goto Eof; + + FTLZW_STACK_PUSH( old_char ); + code = old_code; + } + + while ( code >= 256U ) + { + if ( !state->prefix ) + goto Eof; + + FTLZW_STACK_PUSH( state->suffix[code - 256] ); + code = state->prefix[code - 256]; + } + } + + old_char = code; + FTLZW_STACK_PUSH( old_char ); + + state->phase = FT_LZW_PHASE_STACK; + } + FALL_THROUGH; + + case FT_LZW_PHASE_STACK: + { + while ( state->stack_top > 0 ) + { + state->stack_top--; + + if ( buffer ) + buffer[result] = state->stack[state->stack_top]; + + if ( ++result == out_size ) + goto Exit; + } + + /* now create new entry */ + if ( state->free_ent < state->max_free ) + { + if ( state->free_ent >= state->prefix_size && + ft_lzwstate_prefix_grow( state ) < 0 ) + goto Eof; + + FT_ASSERT( state->free_ent < state->prefix_size ); + + state->prefix[state->free_ent] = (FT_UShort)old_code; + state->suffix[state->free_ent] = (FT_Byte) old_char; + + state->free_ent += 1; + } + + old_code = in_code; + + state->phase = FT_LZW_PHASE_CODE; + goto NextCode; + } + + default: /* state == EOF */ + ; + } + + Exit: + state->old_code = old_code; + state->old_char = old_char; + state->in_code = in_code; + + return result; + + Eof: + state->phase = FT_LZW_PHASE_EOF; + goto Exit; + } + + +/* END */ diff --git a/vendor/freetype/src/lzw/ftzopen.h b/vendor/freetype/src/lzw/ftzopen.h new file mode 100644 index 0000000..6c75636 --- /dev/null +++ b/vendor/freetype/src/lzw/ftzopen.h @@ -0,0 +1,174 @@ +/**************************************************************************** + * + * ftzopen.h + * + * FreeType support for .Z compressed files. + * + * This optional component relies on NetBSD's zopen(). It should mainly + * be used to parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2005-2023 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTZOPEN_H_ +#define FTZOPEN_H_ + +#include + +FT_BEGIN_HEADER + + /* + * This is a complete re-implementation of the LZW file reader, + * since the old one was incredibly badly written, using + * 400 KByte of heap memory before decompressing anything. + * + */ + +#define FT_LZW_IN_BUFF_SIZE 64 +#define FT_LZW_DEFAULT_STACK_SIZE 64 + +#define LZW_INIT_BITS 9 +#define LZW_MAX_BITS 16 + +#define LZW_CLEAR 256 +#define LZW_FIRST 257 + +#define LZW_BIT_MASK 0x1F +#define LZW_BLOCK_MASK 0x80 +#define LZW_MASK( n ) ( ( 1U << (n) ) - 1U ) + + + typedef enum FT_LzwPhase_ + { + FT_LZW_PHASE_START = 0, + FT_LZW_PHASE_CODE, + FT_LZW_PHASE_STACK, + FT_LZW_PHASE_EOF + + } FT_LzwPhase; + + + /* + * state of LZW decompressor + * + * small technical note + * -------------------- + * + * We use a few tricks in this implementation that are explained here to + * ease debugging and maintenance. + * + * - First of all, the `prefix' and `suffix' arrays contain the suffix + * and prefix for codes over 256; this means that + * + * prefix_of(code) == state->prefix[code-256] + * suffix_of(code) == state->suffix[code-256] + * + * Each prefix is a 16-bit code, and each suffix an 8-bit byte. + * + * Both arrays are stored in a single memory block, pointed to by + * `state->prefix'. This means that the following equality is always + * true: + * + * state->suffix == (FT_Byte*)(state->prefix + state->prefix_size) + * + * Of course, state->prefix_size is the number of prefix/suffix slots + * in the arrays, corresponding to codes 256..255+prefix_size. + * + * - `free_ent' is the index of the next free entry in the `prefix' + * and `suffix' arrays. This means that the corresponding `next free + * code' is really `256+free_ent'. + * + * Moreover, `max_free' is the maximum value that `free_ent' can reach. + * + * `max_free' corresponds to `(1 << max_bits) - 256'. Note that this + * value is always <= 0xFF00, which means that both `free_ent' and + * `max_free' can be stored in an FT_UInt variable, even on 16-bit + * machines. + * + * If `free_ent == max_free', you cannot add new codes to the + * prefix/suffix table. + * + * - `num_bits' is the current number of code bits, starting at 9 and + * growing each time `free_ent' reaches the value of `free_bits'. The + * latter is computed as follows + * + * if num_bits < max_bits: + * free_bits = (1 << num_bits)-256 + * else: + * free_bits = max_free + 1 + * + * Since the value of `max_free + 1' can never be reached by + * `free_ent', `num_bits' cannot grow larger than `max_bits'. + */ + + typedef struct FT_LzwStateRec_ + { + FT_LzwPhase phase; + FT_Int in_eof; + + FT_Byte buf_tab[16]; + FT_UInt buf_offset; + FT_UInt buf_size; + FT_Bool buf_clear; + FT_Offset buf_total; + + FT_UInt max_bits; /* max code bits, from file header */ + FT_Int block_mode; /* block mode flag, from file header */ + FT_UInt max_free; /* (1 << max_bits) - 256 */ + + FT_UInt num_bits; /* current code bit number */ + FT_UInt free_ent; /* index of next free entry */ + FT_UInt free_bits; /* if reached by free_ent, increment num_bits */ + FT_UInt old_code; + FT_UInt old_char; + FT_UInt in_code; + + FT_UShort* prefix; /* always dynamically allocated / reallocated */ + FT_Byte* suffix; /* suffix = (FT_Byte*)(prefix + prefix_size) */ + FT_UInt prefix_size; /* number of slots in `prefix' or `suffix' */ + + FT_Byte* stack; /* character stack */ + FT_UInt stack_top; + FT_Offset stack_size; + FT_Byte stack_0[FT_LZW_DEFAULT_STACK_SIZE]; /* minimize heap alloc */ + + FT_Stream source; /* source stream */ + FT_Memory memory; + + } FT_LzwStateRec, *FT_LzwState; + + + FT_LOCAL( void ) + ft_lzwstate_init( FT_LzwState state, + FT_Stream source ); + + FT_LOCAL( void ) + ft_lzwstate_done( FT_LzwState state ); + + + FT_LOCAL( void ) + ft_lzwstate_reset( FT_LzwState state ); + + + FT_LOCAL( FT_ULong ) + ft_lzwstate_io( FT_LzwState state, + FT_Byte* buffer, + FT_ULong out_size ); + +/* */ + +FT_END_HEADER + +#endif /* FTZOPEN_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/lzw/rules.mk b/vendor/freetype/src/lzw/rules.mk new file mode 100644 index 0000000..b750216 --- /dev/null +++ b/vendor/freetype/src/lzw/rules.mk @@ -0,0 +1,72 @@ +# +# FreeType 2 LZW support configuration rules +# + + +# Copyright (C) 2004-2023 by +# Albert Chin-A-Young. +# +# based on `src/lzw/rules.mk' +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# LZW driver directory +# +LZW_DIR := $(SRC_DIR)/lzw + + +# compilation flags for the driver +# +LZW_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(LZW_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# LZW support sources (i.e., C files) +# +LZW_DRV_SRC := $(LZW_DIR)/ftlzw.c + +# LZW support headers +# +LZW_DRV_H := $(LZW_DIR)/ftzopen.h \ + $(LZW_DIR)/ftzopen.c + + +# LZW driver object(s) +# +# LZW_DRV_OBJ_M is used during `multi' builds +# LZW_DRV_OBJ_S is used during `single' builds +# +LZW_DRV_OBJ_M := $(OBJ_DIR)/ftlzw.$O +LZW_DRV_OBJ_S := $(OBJ_DIR)/ftlzw.$O + +# LZW support source file for single build +# +LZW_DRV_SRC_S := $(LZW_DIR)/ftlzw.c + + +# LZW support - single object +# +$(LZW_DRV_OBJ_S): $(LZW_DRV_SRC_S) $(LZW_DRV_SRC) $(FREETYPE_H) $(LZW_DRV_H) + $(LZW_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(LZW_DRV_SRC_S)) + + +# LZW support - multiple objects +# +$(OBJ_DIR)/%.$O: $(LZW_DIR)/%.c $(FREETYPE_H) $(LZW_DRV_H) + $(LZW_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(LZW_DRV_OBJ_S) +DRV_OBJS_M += $(LZW_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/otvalid/module.mk b/vendor/freetype/src/otvalid/module.mk new file mode 100644 index 0000000..9013842 --- /dev/null +++ b/vendor/freetype/src/otvalid/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 otvalid module definition +# + + +# Copyright (C) 2004-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += OTVALID_MODULE + +define OTVALID_MODULE +$(OPEN_DRIVER) FT_Module_Class, otv_module_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)otvalid $(ECHO_DRIVER_DESC)OpenType validation module$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/otvalid/otvalid.c b/vendor/freetype/src/otvalid/otvalid.c new file mode 100644 index 0000000..3b1e23a --- /dev/null +++ b/vendor/freetype/src/otvalid/otvalid.c @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * otvalid.c + * + * FreeType validator for OpenType tables (body only). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "otvbase.c" +#include "otvcommn.c" +#include "otvgdef.c" +#include "otvgpos.c" +#include "otvgsub.c" +#include "otvjstf.c" +#include "otvmath.c" +#include "otvmod.c" + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvalid.h b/vendor/freetype/src/otvalid/otvalid.h new file mode 100644 index 0000000..7edadb7 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvalid.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * otvalid.h + * + * OpenType table validation (specification only). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVALID_H_ +#define OTVALID_H_ + + +#include + +#include "otverror.h" /* must come before `ftvalid.h' */ + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_MATH_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ); + + +FT_END_HEADER + +#endif /* OTVALID_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvbase.c b/vendor/freetype/src/otvalid/otvbase.c new file mode 100644 index 0000000..f449795 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvbase.c @@ -0,0 +1,345 @@ +/**************************************************************************** + * + * otvbase.c + * + * OpenType BASE table validation (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvbase + + + static void + otv_BaseCoord_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordFormat; + + + OTV_NAME_ENTER( "BaseCoord" ); + + OTV_LIMIT_CHECK( 4 ); + BaseCoordFormat = FT_NEXT_USHORT( p ); + p += 2; /* skip Coordinate */ + + OTV_TRACE(( " (format %d)\n", BaseCoordFormat )); + + switch ( BaseCoordFormat ) + { + case 1: /* BaseCoordFormat1 */ + break; + + case 2: /* BaseCoordFormat2 */ + OTV_LIMIT_CHECK( 4 ); /* ReferenceGlyph, BaseCoordPoint */ + break; + + case 3: /* BaseCoordFormat3 */ + OTV_LIMIT_CHECK( 2 ); + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + static void + otv_BaseTagList_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseTagCount; + + + OTV_NAME_ENTER( "BaseTagList" ); + + OTV_LIMIT_CHECK( 2 ); + + BaseTagCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseTagCount = %d)\n", BaseTagCount )); + + OTV_LIMIT_CHECK( BaseTagCount * 4 ); /* BaselineTag */ + + OTV_EXIT; + } + + + static void + otv_BaseValues_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordCount; + + + OTV_NAME_ENTER( "BaseValues" ); + + OTV_LIMIT_CHECK( 4 ); + + p += 2; /* skip DefaultIndex */ + BaseCoordCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseCoordCount = %d)\n", BaseCoordCount )); + + OTV_LIMIT_CHECK( BaseCoordCount * 2 ); + + /* BaseCoord */ + for ( ; BaseCoordCount > 0; BaseCoordCount-- ) + otv_BaseCoord_validate( table + FT_NEXT_USHORT( p ), otvalid ); + + OTV_EXIT; + } + + + static void + otv_MinMax_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt FeatMinMaxCount; + + OTV_OPTIONAL_TABLE( MinCoord ); + OTV_OPTIONAL_TABLE( MaxCoord ); + + + OTV_NAME_ENTER( "MinMax" ); + + OTV_LIMIT_CHECK( 6 ); + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + FeatMinMaxCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatMinMaxCount = %d)\n", FeatMinMaxCount )); + + table_size = FeatMinMaxCount * 8 + 6; + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, otvalid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, otvalid ); + + OTV_LIMIT_CHECK( FeatMinMaxCount * 8 ); + + /* FeatMinMaxRecord */ + for ( ; FeatMinMaxCount > 0; FeatMinMaxCount-- ) + { + p += 4; /* skip FeatureTableTag */ + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, otvalid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScript_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt BaseLangSysCount; + + OTV_OPTIONAL_TABLE( BaseValues ); + OTV_OPTIONAL_TABLE( DefaultMinMax ); + + + OTV_NAME_ENTER( "BaseScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( BaseValues ); + OTV_OPTIONAL_OFFSET( DefaultMinMax ); + BaseLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseLangSysCount = %d)\n", BaseLangSysCount )); + + table_size = BaseLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( BaseValues ); + if ( BaseValues ) + otv_BaseValues_validate( table + BaseValues, otvalid ); + + OTV_SIZE_CHECK( DefaultMinMax ); + if ( DefaultMinMax ) + otv_MinMax_validate( table + DefaultMinMax, otvalid ); + + OTV_LIMIT_CHECK( BaseLangSysCount * 6 ); + + /* BaseLangSysRecord */ + for ( ; BaseLangSysCount > 0; BaseLangSysCount-- ) + { + p += 4; /* skip BaseLangSysTag */ + + otv_MinMax_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScriptList_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseScriptCount; + + + OTV_NAME_ENTER( "BaseScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + BaseScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseScriptCount = %d)\n", BaseScriptCount )); + + OTV_LIMIT_CHECK( BaseScriptCount * 6 ); + + /* BaseScriptRecord */ + for ( ; BaseScriptCount > 0; BaseScriptCount-- ) + { + p += 4; /* skip BaseScriptTag */ + + /* BaseScript */ + otv_BaseScript_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_Axis_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( BaseTagList ); + + + OTV_NAME_ENTER( "Axis" ); + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( BaseTagList ); + + table_size = 4; + + OTV_SIZE_CHECK( BaseTagList ); + if ( BaseTagList ) + otv_BaseTagList_validate( table + BaseTagList, otvalid ); + + /* BaseScriptList */ + otv_BaseScriptList_validate( table + FT_NEXT_USHORT( p ), otvalid ); + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + + OTV_OPTIONAL_TABLE( HorizAxis ); + OTV_OPTIONAL_TABLE( VertAxis ); + + OTV_OPTIONAL_TABLE32( itemVarStore ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating BASE table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 8; + switch ( version ) + { + case 0: + OTV_LIMIT_CHECK( 4 ); + break; + + case 1: + OTV_LIMIT_CHECK( 8 ); + table_size += 4; + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_OPTIONAL_OFFSET( HorizAxis ); + OTV_SIZE_CHECK( HorizAxis ); + if ( HorizAxis ) + otv_Axis_validate( table + HorizAxis, otvalid ); + + OTV_OPTIONAL_OFFSET( VertAxis ); + OTV_SIZE_CHECK( VertAxis ); + if ( VertAxis ) + otv_Axis_validate( table + VertAxis, otvalid ); + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET32( itemVarStore ); + OTV_SIZE_CHECK32( itemVarStore ); + if ( itemVarStore ) + OTV_TRACE(( " [omitting itemVarStore validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvcommn.c b/vendor/freetype/src/otvalid/otvcommn.c new file mode 100644 index 0000000..b94d8a0 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvcommn.c @@ -0,0 +1,1099 @@ +/**************************************************************************** + * + * otvcommn.c + * + * OpenType common tables validation (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvcommon + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator otvalid, + FT_Int expected_count ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat; + FT_UInt total = 0; + + + OTV_NAME_ENTER( "Coverage" ); + + OTV_LIMIT_CHECK( 4 ); + CoverageFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", CoverageFormat )); + + switch ( CoverageFormat ) + { + case 1: /* CoverageFormat1 */ + { + FT_UInt GlyphCount; + FT_UInt i; + + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* GlyphArray */ + + for ( i = 0; i < GlyphCount; i++ ) + { + FT_UInt gid; + + + gid = FT_NEXT_USHORT( p ); + if ( gid >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + } + + total = GlyphCount; + } + break; + + case 2: /* CoverageFormat2 */ + { + FT_UInt n, RangeCount; + FT_UInt Start, End, StartCoverageIndex, last = 0; + + + RangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (RangeCount = %d)\n", RangeCount )); + + OTV_LIMIT_CHECK( RangeCount * 6 ); + + /* RangeRecord */ + for ( n = 0; n < RangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + StartCoverageIndex = FT_NEXT_USHORT( p ); + + if ( Start > End || StartCoverageIndex != total ) + FT_INVALID_DATA; + + if ( End >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + + if ( n > 0 && Start <= last ) + FT_INVALID_DATA; + + total += End - Start + 1; + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* Generally, a coverage table offset has an associated count field. */ + /* The number of glyphs in the table should match this field. If */ + /* there is no associated count, a value of -1 tells us not to check. */ + if ( expected_count != -1 && (FT_UInt)expected_count != total ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ) + { + FT_Bytes p = table; + + + p += 4; /* skip CoverageFormat and Glyph/RangeCount */ + + return FT_NEXT_USHORT( p ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + if ( !count ) + return result; + + switch ( CoverageFormat ) + { + case 1: + p += ( count - 1 ) * 2; + result = FT_NEXT_USHORT( p ); + break; + + case 2: + p += ( count - 1 ) * 6 + 2; + result = FT_NEXT_USHORT( p ); + break; + + default: + ; + } + + return result; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + switch ( CoverageFormat ) + { + case 1: + return count; + + case 2: + { + FT_UInt Start, End; + + + for ( ; count > 0; count-- ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip StartCoverageIndex */ + + result += End - Start + 1; + } + } + break; + + default: + ; + } + + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt ClassFormat; + + + OTV_NAME_ENTER( "ClassDef" ); + + OTV_LIMIT_CHECK( 4 ); + ClassFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", ClassFormat )); + + switch ( ClassFormat ) + { + case 1: /* ClassDefFormat1 */ + { + FT_UInt StartGlyph; + FT_UInt GlyphCount; + + + OTV_LIMIT_CHECK( 4 ); + + StartGlyph = FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* ClassValueArray */ + + if ( StartGlyph + GlyphCount - 1 >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + } + break; + + case 2: /* ClassDefFormat2 */ + { + FT_UInt n, ClassRangeCount; + FT_UInt Start, End, last = 0; + + + ClassRangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount )); + + OTV_LIMIT_CHECK( ClassRangeCount * 6 ); + + /* ClassRangeRecord */ + for ( n = 0; n < ClassRangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip Class */ + + if ( Start > End || ( n > 0 && Start <= last ) ) + FT_INVALID_DATA; + + if ( End >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* no need to check glyph indices used as input to class definition */ + /* tables since even invalid glyph indices return a meaningful result */ + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt StartSize, EndSize, DeltaFormat, count; + + + OTV_NAME_ENTER( "Device" ); + + OTV_LIMIT_CHECK( 6 ); + StartSize = FT_NEXT_USHORT( p ); + EndSize = FT_NEXT_USHORT( p ); + DeltaFormat = FT_NEXT_USHORT( p ); + + if ( DeltaFormat == 0x8000U ) + { + /* VariationIndex, nothing to do */ + } + else + { + if ( DeltaFormat < 1 || DeltaFormat > 3 ) + FT_INVALID_FORMAT; + + if ( EndSize < StartSize ) + FT_INVALID_DATA; + + count = EndSize - StartSize + 1; + OTV_LIMIT_CHECK( ( 1 << DeltaFormat ) * count / 8 ); /* DeltaValue */ + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->type_count */ + /* uses otvalid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LookupType, LookupFlag, SubTableCount; + OTV_Validate_Func validate; + + + OTV_NAME_ENTER( "Lookup" ); + + OTV_LIMIT_CHECK( 6 ); + LookupType = FT_NEXT_USHORT( p ); + LookupFlag = FT_NEXT_USHORT( p ); + SubTableCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (type %d)\n", LookupType )); + + if ( LookupType == 0 || LookupType > otvalid->type_count ) + FT_INVALID_DATA; + + validate = otvalid->type_funcs[LookupType - 1]; + + OTV_TRACE(( " (SubTableCount = %d)\n", SubTableCount )); + + OTV_LIMIT_CHECK( SubTableCount * 2 ); + + /* SubTable */ + for ( ; SubTableCount > 0; SubTableCount-- ) + validate( table + FT_NEXT_USHORT( p ), otvalid ); + + if ( LookupFlag & 0x10 ) + OTV_LIMIT_CHECK( 2 ); /* MarkFilteringSet */ + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "LookupList" ); + + OTV_LIMIT_CHECK( 2 ); + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + otvalid->lookup_count = LookupCount; + + /* Lookup */ + for ( ; LookupCount > 0; LookupCount-- ) + otv_Lookup_validate( table + FT_NEXT_USHORT( p ), otvalid ); + + OTV_EXIT; + } + + + static FT_UInt + otv_LookupList_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "Feature" ); + + OTV_LIMIT_CHECK( 4 ); + p += 2; /* skip FeatureParams (unused) */ + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + /* LookupListIndex */ + for ( ; LookupCount > 0; LookupCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->lookup_count ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + static FT_UInt + otv_Feature_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /* sets otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "FeatureList" ); + + OTV_LIMIT_CHECK( 2 ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + otvalid->lookup_count = otv_LookupList_get_count( lookups ); + + /* FeatureRecord */ + for ( ; FeatureCount > 0; FeatureCount-- ) + { + p += 4; /* skip FeatureTag */ + + /* Feature */ + otv_Feature_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* uses otvalid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt ReqFeatureIndex; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "LangSys" ); + + OTV_LIMIT_CHECK( 6 ); + p += 2; /* skip LookupOrder (unused) */ + ReqFeatureIndex = FT_NEXT_USHORT( p ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ReqFeatureIndex = %d)\n", ReqFeatureIndex )); + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + if ( ReqFeatureIndex != 0xFFFFU && ReqFeatureIndex >= otvalid->extra1 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + /* FeatureIndex */ + for ( ; FeatureCount > 0; FeatureCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_UInt DefaultLangSys, LangSysCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "Script" ); + + OTV_LIMIT_CHECK( 4 ); + DefaultLangSys = FT_NEXT_USHORT( p ); + LangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LangSysCount = %d)\n", LangSysCount )); + + if ( DefaultLangSys != 0 ) + otv_LangSys_validate( table + DefaultLangSys, otvalid ); + + OTV_LIMIT_CHECK( LangSysCount * 6 ); + + /* LangSysRecord */ + for ( ; LangSysCount > 0; LangSysCount-- ) + { + p += 4; /* skip LangSysTag */ + + /* LangSys */ + otv_LangSys_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator otvalid ) + { + FT_UInt ScriptCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "ScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + ScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ScriptCount = %d)\n", ScriptCount )); + + OTV_LIMIT_CHECK( ScriptCount * 6 ); + + otvalid->extra1 = otv_Feature_get_count( features ); + + /* ScriptRecord */ + for ( ; ScriptCount > 0; ScriptCount-- ) + { + p += 4; /* skip ScriptTag */ + + otv_Script_validate( table + FT_NEXT_USHORT( p ), otvalid ); /* Script */ + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + u: uint16 + ux: unit16 [x] + + s: struct + sx: struct [x] + sxy: struct [x], using external y count + + x: uint16 x + + C: Coverage + + O: Offset + On: Offset (NULL) + Ox: Offset [x] + Onx: Offset (NULL) [x] + */ + + FT_LOCAL_DEF( void ) + otv_x_Ox( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count, Coverage; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)Count ); + + OTV_LIMIT_CHECK( Count * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /* uses otvalid->extra1 (if > 0: array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + if ( otvalid->extra1 ) + { + for ( ; Count > 0; Count-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `ux' in the function's name is not really correct since only x-1 */ + /* elements are tested */ + + /* uses otvalid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count1, Count2; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Count1 = FT_NEXT_USHORT( p ); + Count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count1 = %d)\n", Count1 )); + OTV_TRACE(( " (Count2 = %d)\n", Count2 )); + + if ( Count1 == 0 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( ( Count1 - 1 ) * 2 + Count2 * 4 ); + p += ( Count1 - 1 ) * 2; + + for ( ; Count2 > 0; Count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= Count1 ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `uy' in the function's name is not really correct since only y-1 */ + /* elements are tested */ + + /* uses otvalid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BacktrackCount, InputCount, LookaheadCount; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + BacktrackCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackCount = %d)\n", BacktrackCount )); + + OTV_LIMIT_CHECK( BacktrackCount * 2 + 2 ); + p += BacktrackCount * 2; + + InputCount = FT_NEXT_USHORT( p ); + if ( InputCount == 0 ) + FT_INVALID_DATA; + + OTV_TRACE(( " (InputCount = %d)\n", InputCount )); + + OTV_LIMIT_CHECK( InputCount * 2 ); + p += ( InputCount - 1 ) * 2; + + LookaheadCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadCount = %d)\n", LookaheadCount )); + + OTV_LIMIT_CHECK( LookaheadCount * 2 + 2 ); + p += LookaheadCount * 2; + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 4 ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Coverage, ClassDef, ClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ClassDef = FT_NEXT_USHORT( p ); + ClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassSetCount = %d)\n", ClassSetCount )); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + otv_ClassDef_validate( table + ClassDef, otvalid ); + + OTV_LIMIT_CHECK( ClassSetCount * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = otvalid->lookup_count; + + for ( ; ClassSetCount > 0; ClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, otvalid ); + } + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /* uses otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt GlyphCount, Count, count1; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + GlyphCount = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( GlyphCount * 2 + Count * 4 ); + + for ( count1 = GlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= GlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Coverage; + FT_UInt BacktrackClassDef, InputClassDef, LookaheadClassDef; + FT_UInt ChainClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 10 ); + Coverage = FT_NEXT_USHORT( p ); + BacktrackClassDef = FT_NEXT_USHORT( p ); + InputClassDef = FT_NEXT_USHORT( p ); + LookaheadClassDef = FT_NEXT_USHORT( p ); + ChainClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ChainClassSetCount = %d)\n", ChainClassSetCount )); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + + otv_ClassDef_validate( table + BacktrackClassDef, otvalid ); + otv_ClassDef_validate( table + InputClassDef, otvalid ); + otv_ClassDef_validate( table + LookaheadClassDef, otvalid ); + + OTV_LIMIT_CHECK( ChainClassSetCount * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = otvalid->lookup_count; + + for ( ; ChainClassSetCount > 0; ChainClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, otvalid ); + } + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /* uses otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BacktrackGlyphCount, InputGlyphCount, LookaheadGlyphCount; + FT_UInt count1, count2; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 2 ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + InputGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (InputGlyphCount = %d)\n", InputGlyphCount )); + + OTV_LIMIT_CHECK( InputGlyphCount * 2 + 2 ); + + for ( count1 = InputGlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", count2 )); + + OTV_LIMIT_CHECK( count2 * 4 ); + + for ( ; count2 > 0; count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputGlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ) + { + FT_Bytes p = table + 8; + + + return otv_LookupList_get_count( table + FT_NEXT_USHORT( p ) ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ) + { + FT_Bytes p, lookup; + FT_UInt count; + + + if ( !table ) + return 0; + + /* LookupList */ + p = table + 8; + table += FT_NEXT_USHORT( p ); + + /* LookupCount */ + p = table; + count = FT_NEXT_USHORT( p ); + + for ( ; count > 0; count-- ) + { + FT_Bytes oldp; + + + /* Lookup */ + lookup = table + FT_NEXT_USHORT( p ); + + oldp = p; + + /* LookupFlag */ + p = lookup + 2; + if ( FT_NEXT_USHORT( p ) & 0xFF00U ) + return 1; + + p = oldp; + } + + return 0; + } + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvcommn.h b/vendor/freetype/src/otvalid/otvcommn.h new file mode 100644 index 0000000..6702c00 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvcommn.h @@ -0,0 +1,468 @@ +/**************************************************************************** + * + * otvcommn.h + * + * OpenType common tables validation (specification). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVCOMMN_H_ +#define OTVCOMMN_H_ + + +#include "otvalid.h" +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALIDATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct OTV_ValidatorRec_* OTV_Validator; + + typedef void (*OTV_Validate_Func)( FT_Bytes table, + OTV_Validator otvalid ); + + typedef struct OTV_ValidatorRec_ + { + FT_Validator root; + FT_UInt type_count; + OTV_Validate_Func* type_funcs; + + FT_UInt lookup_count; + FT_UInt glyph_count; + + FT_UInt nesting_level; + + OTV_Validate_Func func[3]; + + FT_UInt extra1; /* for passing parameters */ + FT_UInt extra2; + FT_Bytes extra3; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt debug_indent; + const FT_String* debug_function_name[3]; +#endif + + } OTV_ValidatorRec; + + +#undef FT_INVALID_ +#define FT_INVALID_( _error ) \ + ft_validator_error( otvalid->root, FT_THROW( _error ) ) + +#define OTV_OPTIONAL_TABLE( _table ) FT_UShort _table; \ + FT_Bytes _table ## _p + +#define OTV_OPTIONAL_TABLE32( _table ) FT_ULong _table; \ + FT_Bytes _table ## _p + +#define OTV_OPTIONAL_OFFSET( _offset ) \ + FT_BEGIN_STMNT \ + _offset ## _p = p; \ + _offset = FT_NEXT_USHORT( p ); \ + FT_END_STMNT + +#define OTV_OPTIONAL_OFFSET32( _offset ) \ + FT_BEGIN_STMNT \ + _offset ## _p = p; \ + _offset = FT_NEXT_ULONG( p ); \ + FT_END_STMNT + +#define OTV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( p + (_count) > otvalid->root->limit ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + +#define OTV_SIZE_CHECK( _size ) \ + FT_BEGIN_STMNT \ + if ( _size > 0 && _size < table_size ) \ + { \ + if ( otvalid->root->level == FT_VALIDATE_PARANOID ) \ + FT_INVALID_OFFSET; \ + else \ + { \ + /* strip off `const' */ \ + FT_Byte* pp = (FT_Byte*)_size ## _p; \ + \ + \ + FT_TRACE3(( "\n" )); \ + FT_TRACE3(( "Invalid offset to optional table `%s'" \ + " set to zero.\n", \ + #_size )); \ + FT_TRACE3(( "\n" )); \ + \ + _size = pp[0] = pp[1] = 0; \ + } \ + } \ + FT_END_STMNT + +#define OTV_SIZE_CHECK32( _size ) \ + FT_BEGIN_STMNT \ + if ( _size > 0 && _size < table_size ) \ + { \ + if ( otvalid->root->level == FT_VALIDATE_PARANOID ) \ + FT_INVALID_OFFSET; \ + else \ + { \ + /* strip off `const' */ \ + FT_Byte* pp = (FT_Byte*)_size ## _p; \ + \ + \ + FT_TRACE3(( "\n" )); \ + FT_TRACE3(( "Invalid offset to optional table `%s'" \ + " set to zero.\n", \ + #_size )); \ + FT_TRACE3(( "\n" )); \ + \ + _size = pp[0] = pp[1] = pp[2] = pp[3] = 0; \ + } \ + } \ + FT_END_STMNT + + +#define OTV_NAME_(x) #x +#define OTV_NAME(x) OTV_NAME_(x) + +#define OTV_FUNC_(x) x##Func +#define OTV_FUNC(x) OTV_FUNC_(x) + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define OTV_NEST1( x ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->debug_function_name[0] = OTV_NAME( x ); \ + FT_END_STMNT + +#define OTV_NEST2( x, y ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + otvalid->debug_function_name[0] = OTV_NAME( x ); \ + otvalid->debug_function_name[1] = OTV_NAME( y ); \ + FT_END_STMNT + +#define OTV_NEST3( x, y, z ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + otvalid->func[2] = OTV_FUNC( z ); \ + otvalid->debug_function_name[0] = OTV_NAME( x ); \ + otvalid->debug_function_name[1] = OTV_NAME( y ); \ + otvalid->debug_function_name[2] = OTV_NAME( z ); \ + FT_END_STMNT + +#define OTV_INIT otvalid->debug_indent = 0 + +#define OTV_ENTER \ + FT_BEGIN_STMNT \ + otvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", \ + otvalid->debug_function_name[otvalid->nesting_level] )); \ + FT_END_STMNT + +#define OTV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + otvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", name )); \ + FT_END_STMNT + +#define OTV_EXIT otvalid->debug_indent -= 2 + +#define OTV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4( s ); \ + FT_END_STMNT + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define OTV_NEST1( x ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + FT_END_STMNT + +#define OTV_NEST2( x, y ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + FT_END_STMNT + +#define OTV_NEST3( x, y, z ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + otvalid->func[2] = OTV_FUNC( z ); \ + FT_END_STMNT + +#define OTV_INIT do { } while ( 0 ) +#define OTV_ENTER do { } while ( 0 ) +#define OTV_NAME_ENTER( name ) do { } while ( 0 ) +#define OTV_EXIT do { } while ( 0 ) + +#define OTV_TRACE( s ) do { } while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#define OTV_RUN otvalid->func[0] + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator otvalid, + FT_Int expected_count ); + + /* return first covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ); + + /* return last covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ); + + /* return number of covered glyphs */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator otvalid ); + + FT_LOCAL( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator otvalid ); + + /* lookups must already be validated */ + FT_LOCAL( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator otvalid ); + + /* features must already be validated */ + FT_LOCAL( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define ChainPosClassSetFunc otv_x_Ox +#define ChainPosRuleSetFunc otv_x_Ox +#define ChainSubClassSetFunc otv_x_Ox +#define ChainSubRuleSetFunc otv_x_Ox +#define JstfLangSysFunc otv_x_Ox +#define JstfMaxFunc otv_x_Ox +#define LigGlyphFunc otv_x_Ox +#define LigatureArrayFunc otv_x_Ox +#define LigatureSetFunc otv_x_Ox +#define PosClassSetFunc otv_x_Ox +#define PosRuleSetFunc otv_x_Ox +#define SubClassSetFunc otv_x_Ox +#define SubRuleSetFunc otv_x_Ox + + FT_LOCAL( void ) + otv_x_Ox ( FT_Bytes table, + OTV_Validator otvalid ); + +#define AlternateSubstFormat1Func otv_u_C_x_Ox +#define ChainContextPosFormat1Func otv_u_C_x_Ox +#define ChainContextSubstFormat1Func otv_u_C_x_Ox +#define ContextPosFormat1Func otv_u_C_x_Ox +#define ContextSubstFormat1Func otv_u_C_x_Ox +#define LigatureSubstFormat1Func otv_u_C_x_Ox +#define MultipleSubstFormat1Func otv_u_C_x_Ox + + FT_LOCAL( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator otvalid ); + +#define AlternateSetFunc otv_x_ux +#define AttachPointFunc otv_x_ux +#define ExtenderGlyphFunc otv_x_ux +#define JstfGPOSModListFunc otv_x_ux +#define JstfGSUBModListFunc otv_x_ux +#define SequenceFunc otv_x_ux + + FT_LOCAL( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator otvalid ); + +#define PosClassRuleFunc otv_x_y_ux_sy +#define PosRuleFunc otv_x_y_ux_sy +#define SubClassRuleFunc otv_x_y_ux_sy +#define SubRuleFunc otv_x_y_ux_sy + + FT_LOCAL( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator otvalid ); + +#define ChainPosClassRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainPosRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainSubClassRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainSubRuleFunc otv_x_ux_y_uy_z_uz_p_sp + + FT_LOCAL( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator otvalid ); + +#define ContextPosFormat2Func otv_u_O_O_x_Onx +#define ContextSubstFormat2Func otv_u_O_O_x_Onx + + FT_LOCAL( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ); + +#define ContextPosFormat3Func otv_u_x_y_Ox_sy +#define ContextSubstFormat3Func otv_u_x_y_Ox_sy + + FT_LOCAL( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator otvalid ); + +#define ChainContextPosFormat2Func otv_u_O_O_O_O_x_Onx +#define ChainContextSubstFormat2Func otv_u_O_O_O_O_x_Onx + + FT_LOCAL( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ); + +#define ChainContextPosFormat3Func otv_u_x_Ox_y_Oy_z_Oz_p_sp +#define ChainContextSubstFormat3Func otv_u_x_Ox_y_Oy_z_Oz_p_sp + + FT_LOCAL( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator otvalid ); + + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ); + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ); + + /* */ + +FT_END_HEADER + +#endif /* OTVCOMMN_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otverror.h b/vendor/freetype/src/otvalid/otverror.h new file mode 100644 index 0000000..4c4049c --- /dev/null +++ b/vendor/freetype/src/otvalid/otverror.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * otverror.h + * + * OpenType validation module error codes (specification only). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the OpenType validation module error + * enumeration constants. + * + */ + +#ifndef OTVERROR_H_ +#define OTVERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX OTV_Err_ +#define FT_ERR_BASE FT_Mod_Err_OTvalid + +#include + +#endif /* OTVERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvgdef.c b/vendor/freetype/src/otvalid/otvgdef.c new file mode 100644 index 0000000..d62e818 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvgdef.c @@ -0,0 +1,303 @@ +/**************************************************************************** + * + * otvgdef.c + * + * OpenType GDEF table validation (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvgdef + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define AttachListFunc otv_O_x_Ox +#define LigCaretListFunc otv_O_x_Ox + + /* sets valid->extra1 (0) */ + + static void + otv_O_x_Ox( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_Bytes Coverage; + FT_UInt GlyphCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( Coverage, otvalid, (FT_Int)GlyphCount ); + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = 0; + + for ( ; GlyphCount > 0; GlyphCount-- ) + func( table + FT_NEXT_USHORT( p ), otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LIGATURE CARETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define CaretValueFunc otv_CaretValue_validate + + static void + otv_CaretValue_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt CaretValueFormat; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + + CaretValueFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format = %d)\n", CaretValueFormat )); + + switch ( CaretValueFormat ) + { + case 1: /* CaretValueFormat1 */ + /* skip Coordinate, no test */ + break; + + case 2: /* CaretValueFormat2 */ + /* skip CaretValuePoint, no test */ + break; + + case 3: /* CaretValueFormat3 */ + p += 2; /* skip Coordinate */ + + OTV_LIMIT_CHECK( 2 ); + + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MARK GLYPH SETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MarkGlyphSets_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt MarkGlyphSetCount; + + + OTV_NAME_ENTER( "MarkGlyphSets" ); + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 2 ); + MarkGlyphSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (MarkGlyphSetCount = %d)\n", MarkGlyphSetCount )); + + OTV_LIMIT_CHECK( MarkGlyphSetCount * 4 ); /* CoverageOffsets */ + + for ( ; MarkGlyphSetCount > 0; MarkGlyphSetCount-- ) + otv_Coverage_validate( table + FT_NEXT_ULONG( p ), otvalid, -1 ); + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GDEF TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + FT_Bool need_MarkAttachClassDef = 1; + + OTV_OPTIONAL_TABLE( GlyphClassDef ); + OTV_OPTIONAL_TABLE( AttachListOffset ); + OTV_OPTIONAL_TABLE( LigCaretListOffset ); + OTV_OPTIONAL_TABLE( MarkAttachClassDef ); + OTV_OPTIONAL_TABLE( MarkGlyphSetsDef ); + + OTV_OPTIONAL_TABLE32( itemVarStore ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating GDEF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 10; + switch ( version ) + { + case 0: + /* MarkAttachClassDef has been added to the OpenType */ + /* specification without increasing GDEF's version, */ + /* so we use this ugly hack to find out whether the */ + /* table is needed actually. */ + + need_MarkAttachClassDef = FT_BOOL( + otv_GSUBGPOS_have_MarkAttachmentType_flag( gsub ) || + otv_GSUBGPOS_have_MarkAttachmentType_flag( gpos ) ); + + if ( need_MarkAttachClassDef ) + { + OTV_LIMIT_CHECK( 8 ); + table_size += 2; + } + else + OTV_LIMIT_CHECK( 6 ); /* OpenType < 1.2 */ + + break; + + case 2: + OTV_LIMIT_CHECK( 10 ); + table_size += 4; + break; + + case 3: + OTV_LIMIT_CHECK( 14 ); + table_size += 8; + break; + + default: + FT_INVALID_FORMAT; + } + + otvalid->glyph_count = glyph_count; + + OTV_OPTIONAL_OFFSET( GlyphClassDef ); + OTV_SIZE_CHECK( GlyphClassDef ); + if ( GlyphClassDef ) + otv_ClassDef_validate( table + GlyphClassDef, otvalid ); + + OTV_OPTIONAL_OFFSET( AttachListOffset ); + OTV_SIZE_CHECK( AttachListOffset ); + if ( AttachListOffset ) + { + OTV_NEST2( AttachList, AttachPoint ); + OTV_RUN( table + AttachListOffset, otvalid ); + } + + OTV_OPTIONAL_OFFSET( LigCaretListOffset ); + OTV_SIZE_CHECK( LigCaretListOffset ); + if ( LigCaretListOffset ) + { + OTV_NEST3( LigCaretList, LigGlyph, CaretValue ); + OTV_RUN( table + LigCaretListOffset, otvalid ); + } + + if ( need_MarkAttachClassDef ) + { + OTV_OPTIONAL_OFFSET( MarkAttachClassDef ); + OTV_SIZE_CHECK( MarkAttachClassDef ); + if ( MarkAttachClassDef ) + otv_ClassDef_validate( table + MarkAttachClassDef, otvalid ); + } + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET( MarkGlyphSetsDef ); + OTV_SIZE_CHECK( MarkGlyphSetsDef ); + if ( MarkGlyphSetsDef ) + otv_MarkGlyphSets_validate( table + MarkGlyphSetsDef, otvalid ); + } + + if ( version > 2 ) + { + OTV_OPTIONAL_OFFSET32( itemVarStore ); + OTV_SIZE_CHECK32( itemVarStore ); + if ( itemVarStore ) + OTV_TRACE(( " [omitting itemVarStore validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvgpos.c b/vendor/freetype/src/otvalid/otvgpos.c new file mode 100644 index 0000000..f6102af --- /dev/null +++ b/vendor/freetype/src/otvalid/otvgpos.c @@ -0,0 +1,1051 @@ +/**************************************************************************** + * + * otvgpos.c + * + * OpenType GPOS table validation (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvgpos + + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ); + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define BaseArrayFunc otv_x_sxy +#define LigatureAttachFunc otv_x_sxy +#define Mark2ArrayFunc otv_x_sxy + + /* uses valid->extra1 (counter) */ + /* uses valid->extra2 (boolean to handle NULL anchor field) */ + + static void + otv_x_sxy( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count, count1, table_size; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * otvalid->extra1 * 2 ); + + table_size = Count * otvalid->extra1 * 2 + 2; + + for ( ; Count > 0; Count-- ) + for ( count1 = otvalid->extra1; count1 > 0; count1-- ) + { + OTV_OPTIONAL_TABLE( anchor_offset ); + + + OTV_OPTIONAL_OFFSET( anchor_offset ); + + if ( otvalid->extra2 ) + { + OTV_SIZE_CHECK( anchor_offset ); + if ( anchor_offset ) + otv_Anchor_validate( table + anchor_offset, otvalid ); + } + else + otv_Anchor_validate( table + anchor_offset, otvalid ); + } + + OTV_EXIT; + } + + +#define MarkBasePosFormat1Func otv_u_O_O_u_O_O +#define MarkLigPosFormat1Func otv_u_O_O_u_O_O +#define MarkMarkPosFormat1Func otv_u_O_O_u_O_O + + /* sets otvalid->extra1 (class count) */ + + static void + otv_u_O_O_u_O_O( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Coverage1, Coverage2, ClassCount; + FT_UInt Array1, Array2; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip PosFormat */ + + OTV_LIMIT_CHECK( 10 ); + Coverage1 = FT_NEXT_USHORT( p ); + Coverage2 = FT_NEXT_USHORT( p ); + ClassCount = FT_NEXT_USHORT( p ); + Array1 = FT_NEXT_USHORT( p ); + Array2 = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage1, otvalid, -1 ); + otv_Coverage_validate( table + Coverage2, otvalid, -1 ); + + otv_MarkArray_validate( table + Array1, otvalid ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = ClassCount; + + func( table + Array2, otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALUE RECORDS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_UInt + otv_value_length( FT_UInt format ) + { + FT_UInt count; + + + count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); + count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); + count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); + + return count * 2; + } + + + /* uses otvalid->extra3 (pointer to base table) */ + + static void + otv_ValueRecord_validate( FT_Bytes table, + FT_UInt format, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt count; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Int loop; + FT_ULong res = 0; + + + OTV_NAME_ENTER( "ValueRecord" ); + + /* display `format' in dual representation */ + for ( loop = 7; loop >= 0; loop-- ) + { + res <<= 4; + res += ( format >> loop ) & 1; + } + + OTV_TRACE(( " (format 0b%08lx)\n", res )); +#endif + + if ( format >= 0x100 ) + FT_INVALID_FORMAT; + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + /* XPlacement, YPlacement, XAdvance, YAdvance */ + OTV_LIMIT_CHECK( 2 ); + p += 2; + } + + format >>= 1; + } + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + FT_PtrDist table_size; + + OTV_OPTIONAL_TABLE( device ); + + + /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ + OTV_LIMIT_CHECK( 2 ); + OTV_OPTIONAL_OFFSET( device ); + + table_size = p - otvalid->extra3; + + OTV_SIZE_CHECK( device ); + if ( device ) + otv_Device_validate( otvalid->extra3 + device, otvalid ); + } + format >>= 1; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ANCHORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt AnchorFormat; + + + OTV_NAME_ENTER( "Anchor"); + + OTV_LIMIT_CHECK( 6 ); + AnchorFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", AnchorFormat )); + + p += 4; /* skip XCoordinate and YCoordinate */ + + switch ( AnchorFormat ) + { + case 1: + break; + + case 2: + OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ + break; + + case 3: + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( XDeviceTable ); + OTV_OPTIONAL_TABLE( YDeviceTable ); + + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( XDeviceTable ); + OTV_OPTIONAL_OFFSET( YDeviceTable ); + + table_size = 6 + 4; + + OTV_SIZE_CHECK( XDeviceTable ); + if ( XDeviceTable ) + otv_Device_validate( table + XDeviceTable, otvalid ); + + OTV_SIZE_CHECK( YDeviceTable ); + if ( YDeviceTable ) + otv_Device_validate( table + YDeviceTable, otvalid ); + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MARK ARRAYS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt MarkCount; + + + OTV_NAME_ENTER( "MarkArray" ); + + OTV_LIMIT_CHECK( 2 ); + MarkCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); + + OTV_LIMIT_CHECK( MarkCount * 4 ); + + /* MarkRecord */ + for ( ; MarkCount > 0; MarkCount-- ) + { + p += 2; /* skip Class */ + /* MarkAnchor */ + otv_Anchor_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra3 (pointer to base table) */ + + static void + otv_SinglePos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "SinglePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + otvalid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* SinglePosFormat1 */ + { + FT_UInt Coverage, ValueFormat; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + otv_ValueRecord_validate( p, ValueFormat, otvalid ); /* Value */ + } + break; + + case 2: /* SinglePosFormat2 */ + { + FT_UInt Coverage, ValueFormat, ValueCount, len_value; + + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + ValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); + + len_value = otv_value_length( ValueFormat ); + + otv_Coverage_validate( table + Coverage, + otvalid, + (FT_Int)ValueCount ); + + OTV_LIMIT_CHECK( ValueCount * len_value ); + + /* Value */ + for ( ; ValueCount > 0; ValueCount-- ) + { + otv_ValueRecord_validate( p, ValueFormat, otvalid ); + p += len_value; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra3 (pointer to base table) */ + + static void + otv_PairSet_validate( FT_Bytes table, + FT_UInt format1, + FT_UInt format2, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt value_len1, value_len2, PairValueCount; + + + OTV_NAME_ENTER( "PairSet" ); + + otvalid->extra3 = table; + + OTV_LIMIT_CHECK( 2 ); + PairValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); + + value_len1 = otv_value_length( format1 ); + value_len2 = otv_value_length( format2 ); + + OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); + + /* PairValueRecord */ + for ( ; PairValueCount > 0; PairValueCount-- ) + { + p += 2; /* skip SecondGlyph */ + + if ( format1 ) + otv_ValueRecord_validate( p, format1, otvalid ); /* Value1 */ + p += value_len1; + + if ( format2 ) + otv_ValueRecord_validate( p, format2, otvalid ); /* Value2 */ + p += value_len2; + } + + OTV_EXIT; + } + + + /* sets otvalid->extra3 (pointer to base table) */ + + static void + otv_PairPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "PairPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* PairPosFormat1 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; + + + OTV_LIMIT_CHECK( 8 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + PairSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + + OTV_LIMIT_CHECK( PairSetCount * 2 ); + + /* PairSetOffset */ + for ( ; PairSetCount > 0; PairSetCount-- ) + otv_PairSet_validate( table + FT_NEXT_USHORT( p ), + ValueFormat1, ValueFormat2, otvalid ); + } + break; + + case 2: /* PairPosFormat2 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; + FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; + + + OTV_LIMIT_CHECK( 14 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + ClassDef1 = FT_NEXT_USHORT( p ); + ClassDef2 = FT_NEXT_USHORT( p ); + ClassCount1 = FT_NEXT_USHORT( p ); + ClassCount2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); + OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); + + len_value1 = otv_value_length( ValueFormat1 ); + len_value2 = otv_value_length( ValueFormat2 ); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + otv_ClassDef_validate( table + ClassDef1, otvalid ); + otv_ClassDef_validate( table + ClassDef2, otvalid ); + + OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * + ( len_value1 + len_value2 ) ); + + otvalid->extra3 = table; + + /* Class1Record */ + for ( ; ClassCount1 > 0; ClassCount1-- ) + { + /* Class2Record */ + for ( count = ClassCount2; count > 0; count-- ) + { + if ( ValueFormat1 ) + /* Value1 */ + otv_ValueRecord_validate( p, ValueFormat1, otvalid ); + p += len_value1; + + if ( ValueFormat2 ) + /* Value2 */ + otv_ValueRecord_validate( p, ValueFormat2, otvalid ); + p += len_value2; + } + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_CursivePos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "CursivePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* CursivePosFormat1 */ + { + FT_UInt table_size; + FT_UInt Coverage, EntryExitCount; + + OTV_OPTIONAL_TABLE( EntryAnchor ); + OTV_OPTIONAL_TABLE( ExitAnchor ); + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + EntryExitCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); + + otv_Coverage_validate( table + Coverage, + otvalid, + (FT_Int)EntryExitCount ); + + OTV_LIMIT_CHECK( EntryExitCount * 4 ); + + table_size = EntryExitCount * 4 + 4; + + /* EntryExitRecord */ + for ( ; EntryExitCount > 0; EntryExitCount-- ) + { + OTV_OPTIONAL_OFFSET( EntryAnchor ); + OTV_OPTIONAL_OFFSET( ExitAnchor ); + + OTV_SIZE_CHECK( EntryAnchor ); + if ( EntryAnchor ) + otv_Anchor_validate( table + EntryAnchor, otvalid ); + + OTV_SIZE_CHECK( ExitAnchor ); + if ( ExitAnchor ) + otv_Anchor_validate( table + ExitAnchor, otvalid ); + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* UNDOCUMENTED (in OpenType 1.5): */ + /* BaseRecord tables can contain NULL pointers. */ + + /* sets otvalid->extra2 (1) */ + + static void + otv_MarkBasePos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkBasePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + otvalid->extra2 = 1; + OTV_NEST2( MarkBasePosFormat1, BaseArray ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra2 (1) */ + + static void + otv_MarkLigPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkLigPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + otvalid->extra2 = 1; + OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra2 (0) */ + + static void + otv_MarkMarkPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkMarkPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + otvalid->extra2 = 0; + OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ContextPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ContextPosFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ChainContextPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ChainContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ChainContextPosFormat1, + ChainPosRuleSet, ChainPosRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextPosFormat2, + ChainPosClassSet, ChainPosClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ChainContextPosFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 9 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->type_funcs */ + + static void + otv_ExtensionPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ExtensionPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* ExtensionPosFormat1 */ + { + FT_UInt ExtensionLookupType; + FT_ULong ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 ) + FT_INVALID_DATA; + + validate = otvalid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, otvalid ); + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gpos_validate_funcs[9] = + { + otv_SinglePos_validate, + otv_PairPos_validate, + otv_CursivePos_validate, + otv_MarkBasePos_validate, + otv_MarkLigPos_validate, + otv_MarkMarkPos_validate, + otv_ContextPos_validate, + otv_ChainContextPos_validate, + otv_ExtensionPos_validate + }; + + + /* sets otvalid->type_count */ + /* sets otvalid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + otvalid->type_count = 9; + otvalid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + + otv_Lookup_validate( table, otvalid ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator otvalid = &validrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + FT_UInt ScriptList, FeatureList, LookupList; + + OTV_OPTIONAL_TABLE32( featureVariations ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating GPOS table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 10; + switch ( version ) + { + case 0: + OTV_LIMIT_CHECK( 6 ); + break; + + case 1: + OTV_LIMIT_CHECK( 10 ); + table_size += 4; + break; + + default: + FT_INVALID_FORMAT; + } + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + otvalid->type_count = 9; + otvalid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + otvalid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + otvalid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + otvalid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + otvalid ); + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET32( featureVariations ); + OTV_SIZE_CHECK32( featureVariations ); + if ( featureVariations ) + OTV_TRACE(( " [omitting featureVariations validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvgpos.h b/vendor/freetype/src/otvalid/otvgpos.h new file mode 100644 index 0000000..b5d0f54 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvgpos.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * otvgpos.h + * + * OpenType GPOS table validator (specification). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVGPOS_H_ +#define OTVGPOS_H_ + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator valid ); + + +FT_END_HEADER + +#endif /* OTVGPOS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvgsub.c b/vendor/freetype/src/otvalid/otvgsub.c new file mode 100644 index 0000000..5d40d92 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvgsub.c @@ -0,0 +1,627 @@ +/**************************************************************************** + * + * otvgsub.c + * + * OpenType GSUB table validation (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvgsub + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->glyph_count */ + + static void + otv_SingleSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "SingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* SingleSubstFormat1 */ + { + FT_Bytes Coverage; + FT_Int DeltaGlyphID; + FT_UInt first_cov, last_cov; + FT_UInt first_idx, last_idx; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + DeltaGlyphID = FT_NEXT_SHORT( p ); + + otv_Coverage_validate( Coverage, otvalid, -1 ); + + first_cov = otv_Coverage_get_first( Coverage ); + last_cov = otv_Coverage_get_last( Coverage ); + + /* These additions are modulo 65536. */ + first_idx = (FT_UInt)( (FT_Int)first_cov + DeltaGlyphID ) & 0xFFFFU; + last_idx = (FT_UInt)( (FT_Int)last_cov + DeltaGlyphID ) & 0xFFFFU; + + /* Since the maximum number of glyphs is 2^16 - 1 = 65535, */ + /* the largest possible glyph index is 65534. For this */ + /* reason there can't be a wrap-around region, which would */ + /* imply the use of the invalid glyph index 65535. */ + if ( first_idx > last_idx ) + FT_INVALID_DATA; + + if ( last_idx >= otvalid->glyph_count ) + FT_INVALID_DATA; + } + break; + + case 2: /* SingleSubstFormat2 */ + { + FT_UInt Coverage, GlyphCount; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( table + Coverage, + otvalid, + (FT_Int)GlyphCount ); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (glyph count) */ + + static void + otv_MultipleSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "MultipleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + otvalid->extra1 = otvalid->glyph_count; + OTV_NEST2( MultipleSubstFormat1, Sequence ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (glyph count) */ + + static void + otv_AlternateSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "AlternateSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + otvalid->extra1 = otvalid->glyph_count; + OTV_NEST2( AlternateSubstFormat1, AlternateSet ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define LigatureFunc otv_Ligature_validate + + /* uses otvalid->glyph_count */ + + static void + otv_Ligature_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LigatureGlyph, CompCount; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + LigatureGlyph = FT_NEXT_USHORT( p ); + if ( LigatureGlyph >= otvalid->glyph_count ) + FT_INVALID_DATA; + + CompCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (CompCount = %d)\n", CompCount )); + + if ( CompCount == 0 ) + FT_INVALID_DATA; + + CompCount--; + + OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */ + + /* no need to check the Component glyph indices */ + + OTV_EXIT; + } + + + static void + otv_LigatureSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "LigatureSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ContextSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ContextSubstFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ChainContextSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ChainContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ChainContextSubstFormat1, + ChainSubRuleSet, ChainSubRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextSubstFormat2, + ChainSubClassSet, ChainSubClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ChainContextSubstFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->type_funcs */ + + static void + otv_ExtensionSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ExtensionSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ExtensionSubstFormat1 */ + { + FT_UInt ExtensionLookupType; + FT_ULong ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || + ExtensionLookupType == 7 || + ExtensionLookupType > 8 ) + FT_INVALID_DATA; + + validate = otvalid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, otvalid ); + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->glyph_count */ + + static void + otv_ReverseChainSingleSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table, Coverage; + FT_UInt SubstFormat; + FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount; + + + OTV_NAME_ENTER( "ReverseChainSingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ReverseChainSingleSubstFormat1 */ + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + otv_Coverage_validate( Coverage, otvalid, -1 ); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) + FT_INVALID_DATA; + + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gsub_validate_funcs[8] = + { + otv_SingleSubst_validate, + otv_MultipleSubst_validate, + otv_AlternateSubst_validate, + otv_LigatureSubst_validate, + otv_ContextSubst_validate, + otv_ChainContextSubst_validate, + otv_ExtensionSubst_validate, + otv_ReverseChainSingleSubst_validate + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->type_count */ + /* sets otvalid->type_funcs */ + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + FT_UInt ScriptList, FeatureList, LookupList; + + OTV_OPTIONAL_TABLE32( featureVariations ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating GSUB table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 10; + switch ( version ) + { + case 0: + OTV_LIMIT_CHECK( 6 ); + break; + + case 1: + OTV_LIMIT_CHECK( 10 ); + table_size += 4; + break; + + default: + FT_INVALID_FORMAT; + } + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + otvalid->type_count = 8; + otvalid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs; + otvalid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + otvalid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + otvalid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + otvalid ); + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET32( featureVariations ); + OTV_SIZE_CHECK32( featureVariations ); + if ( featureVariations ) + OTV_TRACE(( " [omitting featureVariations validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvjstf.c b/vendor/freetype/src/otvalid/otvjstf.c new file mode 100644 index 0000000..712039c --- /dev/null +++ b/vendor/freetype/src/otvalid/otvjstf.c @@ -0,0 +1,259 @@ +/**************************************************************************** + * + * otvjstf.c + * + * OpenType JSTF table validation (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvjstf + + +#define JstfPriorityFunc otv_JstfPriority_validate +#define JstfLookupFunc otv_GPOS_subtable_validate + + /* uses otvalid->extra1 (GSUB lookup count) */ + /* uses otvalid->extra2 (GPOS lookup count) */ + /* sets otvalid->extra1 (counter) */ + + static void + otv_JstfPriority_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt gsub_lookup_count, gpos_lookup_count; + + OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionEnableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionDisableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionEnableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionDisableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageJstfMax ); + OTV_OPTIONAL_TABLE( ExtensionJstfMax ); + + + OTV_ENTER; + OTV_TRACE(( "JstfPriority table\n" )); + + OTV_LIMIT_CHECK( 20 ); + + gsub_lookup_count = otvalid->extra1; + gpos_lookup_count = otvalid->extra2; + + table_size = 20; + + otvalid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB ); + OTV_SIZE_CHECK( ShrinkageEnableGSUB ); + if ( ShrinkageEnableGSUB ) + otv_x_ux( table + ShrinkageEnableGSUB, otvalid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB ); + OTV_SIZE_CHECK( ShrinkageDisableGSUB ); + if ( ShrinkageDisableGSUB ) + otv_x_ux( table + ShrinkageDisableGSUB, otvalid ); + + otvalid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS ); + OTV_SIZE_CHECK( ShrinkageEnableGPOS ); + if ( ShrinkageEnableGPOS ) + otv_x_ux( table + ShrinkageEnableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS ); + OTV_SIZE_CHECK( ShrinkageDisableGPOS ); + if ( ShrinkageDisableGPOS ) + otv_x_ux( table + ShrinkageDisableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ShrinkageJstfMax ); + OTV_SIZE_CHECK( ShrinkageJstfMax ); + if ( ShrinkageJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ShrinkageJstfMax, otvalid ); + } + + otvalid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB ); + OTV_SIZE_CHECK( ExtensionEnableGSUB ); + if ( ExtensionEnableGSUB ) + otv_x_ux( table + ExtensionEnableGSUB, otvalid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB ); + OTV_SIZE_CHECK( ExtensionDisableGSUB ); + if ( ExtensionDisableGSUB ) + otv_x_ux( table + ExtensionDisableGSUB, otvalid ); + + otvalid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS ); + OTV_SIZE_CHECK( ExtensionEnableGPOS ); + if ( ExtensionEnableGPOS ) + otv_x_ux( table + ExtensionEnableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS ); + OTV_SIZE_CHECK( ExtensionDisableGPOS ); + if ( ExtensionDisableGPOS ) + otv_x_ux( table + ExtensionDisableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ExtensionJstfMax ); + OTV_SIZE_CHECK( ExtensionJstfMax ); + if ( ExtensionJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ExtensionJstfMax, otvalid ); + } + + otvalid->extra1 = gsub_lookup_count; + otvalid->extra2 = gpos_lookup_count; + + OTV_EXIT; + } + + + /* sets otvalid->extra (glyph count) */ + /* sets otvalid->func1 (otv_JstfPriority_validate) */ + + static void + otv_JstfScript_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt JstfLangSysCount; + + OTV_OPTIONAL_TABLE( ExtGlyph ); + OTV_OPTIONAL_TABLE( DefJstfLangSys ); + + + OTV_NAME_ENTER( "JstfScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( ExtGlyph ); + OTV_OPTIONAL_OFFSET( DefJstfLangSys ); + JstfLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount )); + + table_size = JstfLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( ExtGlyph ); + if ( ExtGlyph ) + { + otvalid->extra1 = otvalid->glyph_count; + OTV_NEST1( ExtenderGlyph ); + OTV_RUN( table + ExtGlyph, otvalid ); + } + + OTV_SIZE_CHECK( DefJstfLangSys ); + if ( DefJstfLangSys ) + { + OTV_NEST2( JstfLangSys, JstfPriority ); + OTV_RUN( table + DefJstfLangSys, otvalid ); + } + + OTV_LIMIT_CHECK( 6 * JstfLangSysCount ); + + /* JstfLangSysRecord */ + OTV_NEST2( JstfLangSys, JstfPriority ); + for ( ; JstfLangSysCount > 0; JstfLangSysCount-- ) + { + p += 4; /* skip JstfLangSysTag */ + + OTV_RUN( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (GSUB lookup count) */ + /* sets otvalid->extra2 (GPOS lookup count) */ + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt JstfScriptCount; + + + otvalid->root = ftvalid; + + + FT_TRACE3(( "validating JSTF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 6 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_FORMAT; + + JstfScriptCount = FT_NEXT_USHORT( p ); + + FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount )); + + OTV_LIMIT_CHECK( JstfScriptCount * 6 ); + + if ( gsub ) + otvalid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub ); + else + otvalid->extra1 = 0; + + if ( gpos ) + otvalid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos ); + else + otvalid->extra2 = 0; + + otvalid->glyph_count = glyph_count; + + /* JstfScriptRecord */ + for ( ; JstfScriptCount > 0; JstfScriptCount-- ) + { + p += 4; /* skip JstfScriptTag */ + + /* JstfScript */ + otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvmath.c b/vendor/freetype/src/otvalid/otvmath.c new file mode 100644 index 0000000..01fd863 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvmath.c @@ -0,0 +1,453 @@ +/**************************************************************************** + * + * otvmath.c + * + * OpenType MATH table validation (body). + * + * Copyright (C) 2007-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by George Williams. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvmath + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH TYPOGRAPHIC CONSTANTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathConstants_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt i; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + + OTV_NAME_ENTER( "MathConstants" ); + + /* 56 constants, 51 have device tables */ + OTV_LIMIT_CHECK( 2 * ( 56 + 51 ) ); + table_size = 2 * ( 56 + 51 ); + + p += 4 * 2; /* First 4 constants have no device tables */ + for ( i = 0; i < 51; i++ ) + { + p += 2; /* skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH ITALICS CORRECTION *****/ + /***** MATH TOP ACCENT ATTACHMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathItalicsCorrectionInfo_validate( FT_Bytes table, + OTV_Validator otvalid, + FT_Int isItalic ) + { + FT_Bytes p = table; + FT_UInt i, cnt, table_size; + + OTV_OPTIONAL_TABLE( Coverage ); + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + FT_UNUSED( isItalic ); /* only used if tracing is active */ + + + OTV_NAME_ENTER( isItalic ? "MathItalicsCorrectionInfo" + : "MathTopAccentAttachment" ); + + OTV_LIMIT_CHECK( 4 ); + + OTV_OPTIONAL_OFFSET( Coverage ); + cnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 4 * cnt ); + table_size = 4 + 4 * cnt; + + OTV_SIZE_CHECK( Coverage ); + otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)cnt ); + + for ( i = 0; i < cnt; i++ ) + { + p += 2; /* Skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH KERNING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathKern_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt i, cnt, table_size; + + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + + /* OTV_NAME_ENTER( "MathKern" ); */ + + OTV_LIMIT_CHECK( 2 ); + + cnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 4 * cnt + 2 ); + table_size = 4 + 4 * cnt; + + /* Heights */ + for ( i = 0; i < cnt; i++ ) + { + p += 2; /* Skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + /* One more Kerning value */ + for ( i = 0; i < cnt + 1; i++ ) + { + p += 2; /* Skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_MathKernInfo_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt i, j, cnt, table_size; + + OTV_OPTIONAL_TABLE( Coverage ); + OTV_OPTIONAL_TABLE( MKRecordOffset ); + + + OTV_NAME_ENTER( "MathKernInfo" ); + + OTV_LIMIT_CHECK( 4 ); + + OTV_OPTIONAL_OFFSET( Coverage ); + cnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 8 * cnt ); + table_size = 4 + 8 * cnt; + + OTV_SIZE_CHECK( Coverage ); + otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)cnt ); + + for ( i = 0; i < cnt; i++ ) + { + for ( j = 0; j < 4; j++ ) + { + OTV_OPTIONAL_OFFSET( MKRecordOffset ); + OTV_SIZE_CHECK( MKRecordOffset ); + if ( MKRecordOffset ) + otv_MathKern_validate( table + MKRecordOffset, otvalid ); + } + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH GLYPH INFO *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathGlyphInfo_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt MathItalicsCorrectionInfo, MathTopAccentAttachment; + FT_UInt ExtendedShapeCoverage, MathKernInfo; + + + OTV_NAME_ENTER( "MathGlyphInfo" ); + + OTV_LIMIT_CHECK( 8 ); + + MathItalicsCorrectionInfo = FT_NEXT_USHORT( p ); + MathTopAccentAttachment = FT_NEXT_USHORT( p ); + ExtendedShapeCoverage = FT_NEXT_USHORT( p ); + MathKernInfo = FT_NEXT_USHORT( p ); + + if ( MathItalicsCorrectionInfo ) + otv_MathItalicsCorrectionInfo_validate( + table + MathItalicsCorrectionInfo, otvalid, TRUE ); + + /* Italic correction and Top Accent Attachment have the same format */ + if ( MathTopAccentAttachment ) + otv_MathItalicsCorrectionInfo_validate( + table + MathTopAccentAttachment, otvalid, FALSE ); + + if ( ExtendedShapeCoverage ) + { + OTV_NAME_ENTER( "ExtendedShapeCoverage" ); + otv_Coverage_validate( table + ExtendedShapeCoverage, otvalid, -1 ); + OTV_EXIT; + } + + if ( MathKernInfo ) + otv_MathKernInfo_validate( table + MathKernInfo, otvalid ); + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH GLYPH CONSTRUCTION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_GlyphAssembly_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt pcnt, table_size; + FT_UInt i; + + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + + /* OTV_NAME_ENTER( "GlyphAssembly" ); */ + + OTV_LIMIT_CHECK( 6 ); + + p += 2; /* Skip the Italics Correction value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + pcnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 8 * pcnt ); + table_size = 6 + 8 * pcnt; + + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + + for ( i = 0; i < pcnt; i++ ) + { + FT_UInt gid; + + + gid = FT_NEXT_USHORT( p ); + if ( gid >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + p += 2*4; /* skip the Start, End, Full, and Flags fields */ + } + + /* OTV_EXIT; */ + } + + + static void + otv_MathGlyphConstruction_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt vcnt, table_size; + FT_UInt i; + + OTV_OPTIONAL_TABLE( GlyphAssembly ); + + + /* OTV_NAME_ENTER( "MathGlyphConstruction" ); */ + + OTV_LIMIT_CHECK( 4 ); + + OTV_OPTIONAL_OFFSET( GlyphAssembly ); + vcnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 4 * vcnt ); + table_size = 4 + 4 * vcnt; + + for ( i = 0; i < vcnt; i++ ) + { + FT_UInt gid; + + + gid = FT_NEXT_USHORT( p ); + if ( gid >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + p += 2; /* skip the size */ + } + + OTV_SIZE_CHECK( GlyphAssembly ); + if ( GlyphAssembly ) + otv_GlyphAssembly_validate( table+GlyphAssembly, otvalid ); + + /* OTV_EXIT; */ + } + + + static void + otv_MathVariants_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt vcnt, hcnt, i, table_size; + + OTV_OPTIONAL_TABLE( VCoverage ); + OTV_OPTIONAL_TABLE( HCoverage ); + OTV_OPTIONAL_TABLE( Offset ); + + + OTV_NAME_ENTER( "MathVariants" ); + + OTV_LIMIT_CHECK( 10 ); + + p += 2; /* Skip the MinConnectorOverlap constant */ + OTV_OPTIONAL_OFFSET( VCoverage ); + OTV_OPTIONAL_OFFSET( HCoverage ); + vcnt = FT_NEXT_USHORT( p ); + hcnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 2 * vcnt + 2 * hcnt ); + table_size = 10 + 2 * vcnt + 2 * hcnt; + + OTV_SIZE_CHECK( VCoverage ); + if ( VCoverage ) + otv_Coverage_validate( table + VCoverage, otvalid, (FT_Int)vcnt ); + + OTV_SIZE_CHECK( HCoverage ); + if ( HCoverage ) + otv_Coverage_validate( table + HCoverage, otvalid, (FT_Int)hcnt ); + + for ( i = 0; i < vcnt; i++ ) + { + OTV_OPTIONAL_OFFSET( Offset ); + OTV_SIZE_CHECK( Offset ); + otv_MathGlyphConstruction_validate( table + Offset, otvalid ); + } + + for ( i = 0; i < hcnt; i++ ) + { + OTV_OPTIONAL_OFFSET( Offset ); + OTV_SIZE_CHECK( Offset ); + otv_MathGlyphConstruction_validate( table + Offset, otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_MATH_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt MathConstants, MathGlyphInfo, MathVariants; + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating MATH table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 10 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_FORMAT; + + MathConstants = FT_NEXT_USHORT( p ); + MathGlyphInfo = FT_NEXT_USHORT( p ); + MathVariants = FT_NEXT_USHORT( p ); + + otvalid->glyph_count = glyph_count; + + otv_MathConstants_validate( table + MathConstants, + otvalid ); + otv_MathGlyphInfo_validate( table + MathGlyphInfo, + otvalid ); + otv_MathVariants_validate ( table + MathVariants, + otvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvmod.c b/vendor/freetype/src/otvalid/otvmod.c new file mode 100644 index 0000000..d6057c5 --- /dev/null +++ b/vendor/freetype/src/otvalid/otvmod.c @@ -0,0 +1,281 @@ +/**************************************************************************** + * + * otvmod.c + * + * FreeType's OpenType validation module implementation (body). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "otvmod.h" +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvmodule + + + static FT_Error + otv_load_table( FT_Face face, + FT_Tag tag, + FT_Byte* volatile* table, + FT_ULong* table_len ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); + if ( FT_ERR_EQ( error, Table_Missing ) ) + return FT_Err_Ok; + if ( error ) + goto Exit; + + if ( FT_QALLOC( *table, *table_len ) ) + goto Exit; + + error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); + + Exit: + return error; + } + + + static FT_Error + otv_validate( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *ot_base, + FT_Bytes *ot_gdef, + FT_Bytes *ot_gpos, + FT_Bytes *ot_gsub, + FT_Bytes *ot_jstf ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* volatile base; + FT_Byte* volatile gdef; + FT_Byte* volatile gpos; + FT_Byte* volatile gsub; + FT_Byte* volatile jstf; + FT_Byte* volatile math; + FT_ULong len_base, len_gdef, len_gpos, len_gsub, len_jstf; + FT_ULong len_math; + FT_UInt num_glyphs = (FT_UInt)face->num_glyphs; + FT_ValidatorRec volatile valid; + + + base = gdef = gpos = gsub = jstf = math = NULL; + len_base = len_gdef = len_gpos = len_gsub = len_jstf = len_math = 0; + + /* + * XXX: OpenType tables cannot handle 32-bit glyph index, + * although broken TrueType can have 32-bit glyph index. + */ + if ( face->num_glyphs > 0xFFFFL ) + { + FT_TRACE1(( "otv_validate: Invalid glyphs index (0x0000FFFF - 0x%08lx) ", + face->num_glyphs )); + FT_TRACE1(( "are not handled by OpenType tables\n" )); + num_glyphs = 0xFFFF; + } + + /* load tables */ + + if ( ot_flags & FT_VALIDATE_BASE ) + { + error = otv_load_table( face, TTAG_BASE, &base, &len_base ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GDEF ) + { + error = otv_load_table( face, TTAG_GDEF, &gdef, &len_gdef ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GPOS ) + { + error = otv_load_table( face, TTAG_GPOS, &gpos, &len_gpos ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GSUB ) + { + error = otv_load_table( face, TTAG_GSUB, &gsub, &len_gsub ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_JSTF ) + { + error = otv_load_table( face, TTAG_JSTF, &jstf, &len_jstf ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_MATH ) + { + error = otv_load_table( face, TTAG_MATH, &math, &len_math ); + if ( error ) + goto Exit; + } + + /* validate tables */ + + if ( base ) + { + ft_validator_init( &valid, base, base + len_base, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_BASE_validate( base, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gpos ) + { + ft_validator_init( &valid, gpos, gpos + len_gpos, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GPOS_validate( gpos, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gsub ) + { + ft_validator_init( &valid, gsub, gsub + len_gsub, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GSUB_validate( gsub, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gdef ) + { + ft_validator_init( &valid, gdef, gdef + len_gdef, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GDEF_validate( gdef, gsub, gpos, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( jstf ) + { + ft_validator_init( &valid, jstf, jstf + len_jstf, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_JSTF_validate( jstf, gsub, gpos, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( math ) + { + ft_validator_init( &valid, math, math + len_math, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_MATH_validate( math, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + *ot_base = (FT_Bytes)base; + *ot_gdef = (FT_Bytes)gdef; + *ot_gpos = (FT_Bytes)gpos; + *ot_gsub = (FT_Bytes)gsub; + *ot_jstf = (FT_Bytes)jstf; + + Exit: + if ( error ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( base ); + FT_FREE( gdef ); + FT_FREE( gpos ); + FT_FREE( gsub ); + FT_FREE( jstf ); + } + + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( math ); /* Can't return this as API is frozen */ + } + + return error; + } + + + static + const FT_Service_OTvalidateRec otvalid_interface = + { + otv_validate /* validate */ + }; + + + static + const FT_ServiceDescRec otvalid_services[] = + { + { FT_SERVICE_ID_OPENTYPE_VALIDATE, &otvalid_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + otvalid_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( otvalid_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class otv_module_class = + { + 0, + sizeof ( FT_ModuleRec ), + "otvalid", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + (FT_Module_Constructor)NULL, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) otvalid_get_service /* get_interface */ + }; + + +/* END */ diff --git a/vendor/freetype/src/otvalid/otvmod.h b/vendor/freetype/src/otvalid/otvmod.h new file mode 100644 index 0000000..f0e68db --- /dev/null +++ b/vendor/freetype/src/otvalid/otvmod.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * otvmod.h + * + * FreeType's OpenType validation module implementation + * (specification). + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVMOD_H_ +#define OTVMOD_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) otv_module_class; + + +FT_END_HEADER + +#endif /* OTVMOD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/otvalid/rules.mk b/vendor/freetype/src/otvalid/rules.mk new file mode 100644 index 0000000..800cb87 --- /dev/null +++ b/vendor/freetype/src/otvalid/rules.mk @@ -0,0 +1,81 @@ +# +# FreeType 2 OpenType validation driver configuration rules +# + + +# Copyright (C) 2004-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# OTV driver directory +# +OTV_DIR := $(SRC_DIR)/otvalid + + +# compilation flags for the driver +# +OTV_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(OTV_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# OTV driver sources (i.e., C files) +# +OTV_DRV_SRC := $(OTV_DIR)/otvbase.c \ + $(OTV_DIR)/otvcommn.c \ + $(OTV_DIR)/otvgdef.c \ + $(OTV_DIR)/otvgpos.c \ + $(OTV_DIR)/otvgsub.c \ + $(OTV_DIR)/otvjstf.c \ + $(OTV_DIR)/otvmath.c \ + $(OTV_DIR)/otvmod.c + +# OTV driver headers +# +OTV_DRV_H := $(OTV_DIR)/otvalid.h \ + $(OTV_DIR)/otvcommn.h \ + $(OTV_DIR)/otverror.h \ + $(OTV_DIR)/otvgpos.h \ + $(OTV_DIR)/otvmod.h + + +# OTV driver object(s) +# +# OTV_DRV_OBJ_M is used during `multi' builds. +# OTV_DRV_OBJ_S is used during `single' builds. +# +OTV_DRV_OBJ_M := $(OTV_DRV_SRC:$(OTV_DIR)/%.c=$(OBJ_DIR)/%.$O) +OTV_DRV_OBJ_S := $(OBJ_DIR)/otvalid.$O + +# OTV driver source file for single build +# +OTV_DRV_SRC_S := $(OTV_DIR)/otvalid.c + + +# OTV driver - single object +# +$(OTV_DRV_OBJ_S): $(OTV_DRV_SRC_S) $(OTV_DRV_SRC) \ + $(FREETYPE_H) $(OTV_DRV_H) + $(OTV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(OTV_DRV_SRC_S)) + + +# OTV driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(OTV_DIR)/%.c $(FREETYPE_H) $(OTV_DRV_H) + $(OTV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(OTV_DRV_OBJ_S) +DRV_OBJS_M += $(OTV_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/pcf/README b/vendor/freetype/src/pcf/README new file mode 100644 index 0000000..09ea970 --- /dev/null +++ b/vendor/freetype/src/pcf/README @@ -0,0 +1,96 @@ + FreeType font driver for PCF fonts + + Francesco Zappa Nardelli + + + +Introduction +************ + +PCF (Portable Compiled Format) is a binary bitmap font format, largely used +in X world. This code implements a PCF driver for the FreeType library. +Glyph images are loaded into memory only on demand, thus leading to a small +memory footprint. + +Information on the PCF font format can only be worked out from +`pcfread.c', and `pcfwrite.c', to be found, for instance, in the XFree86 +(www.xfree86.org) source tree (xc/lib/font/bitmap/). + +Many good bitmap fonts in bdf format come with XFree86: they can be +compiled into the pcf format using the `bdftopcf' utility. + + +Supported hardware +****************** + +The driver has been tested on linux/x86 and sunos5.5/sparc. In both +cases the compiler was gcc. When back in Paris, I will test it also +on linux/alpha. + + +Encodings +********* + +Use `FT_Get_BDF_Charset_ID' to access the encoding and registry. + +The driver always exports `ft_encoding_none' as face->charmap.encoding. +FT_Get_Char_Index() behavior is unmodified, that is, it converts the ULong +value given as argument into the corresponding glyph number. + + +Known problems +************** + +- dealing explicitly with encodings breaks the uniformity of FreeType 2 + API. + +- except for encodings properties, client applications have no + visibility of the PCF_Face object. This means that applications + cannot directly access font tables and are obliged to trust + FreeType. + +- currently, glyph names and ink_metrics are ignored. + +I plan to give full visibility of the PCF_Face object in the next +release of the driver, thus implementing also glyph names and +ink_metrics. + +- height is defined as (ascent - descent). Is this correct? + +- if unable to read size information from the font, PCF_Init_Face + sets available_size->width and available_size->height to 12. + +- too many english grammar errors in the readme file :-( + + +License +******* + +Copyright (C) 2000 by Francesco Zappa Nardelli + +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. + + +Credits +******* + +Keith Packard wrote the pcf driver found in XFree86. His work is at +the same time the specification and the sample implementation of the +PCF format. Undoubtedly, this driver is inspired from his work. diff --git a/vendor/freetype/src/pcf/module.mk b/vendor/freetype/src/pcf/module.mk new file mode 100644 index 0000000..df383ff --- /dev/null +++ b/vendor/freetype/src/pcf/module.mk @@ -0,0 +1,34 @@ +# +# FreeType 2 PCF module definition +# + +# Copyright 2000, 2006 by +# Francesco Zappa Nardelli +# +# 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. + + +FTMODULE_H_COMMANDS += PCF_DRIVER + +define PCF_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, pcf_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)pcf $(ECHO_DRIVER_DESC)pcf bitmap fonts$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/pcf/pcf.c b/vendor/freetype/src/pcf/pcf.c new file mode 100644 index 0000000..6b30fb2 --- /dev/null +++ b/vendor/freetype/src/pcf/pcf.c @@ -0,0 +1,35 @@ +/* pcf.c + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2003 by + Francesco Zappa Nardelli + +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. +*/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pcfdrivr.c" +#include "pcfread.c" +#include "pcfutil.c" + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcf.h b/vendor/freetype/src/pcf/pcf.h new file mode 100644 index 0000000..3134cc3 --- /dev/null +++ b/vendor/freetype/src/pcf/pcf.h @@ -0,0 +1,251 @@ +/* pcf.h + + FreeType font driver for pcf fonts + + Copyright (C) 2000, 2001, 2002, 2003, 2006, 2010 by + Francesco Zappa Nardelli + +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. +*/ + + +#ifndef PCF_H_ +#define PCF_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + typedef struct PCF_TableRec_ + { + FT_ULong type; + FT_ULong format; + FT_ULong size; + FT_ULong offset; + + } PCF_TableRec, *PCF_Table; + + + typedef struct PCF_TocRec_ + { + FT_ULong version; + FT_ULong count; + PCF_Table tables; + + } PCF_TocRec, *PCF_Toc; + + + typedef struct PCF_ParsePropertyRec_ + { + FT_Long name; + FT_Byte isString; + FT_Long value; + + } PCF_ParsePropertyRec, *PCF_ParseProperty; + + + typedef struct PCF_PropertyRec_ + { + FT_String* name; + FT_Byte isString; + + union + { + FT_String* atom; + FT_Long l; + FT_ULong ul; + + } value; + + } PCF_PropertyRec, *PCF_Property; + + + typedef struct PCF_Compressed_MetricRec_ + { + FT_Byte leftSideBearing; + FT_Byte rightSideBearing; + FT_Byte characterWidth; + FT_Byte ascent; + FT_Byte descent; + + } PCF_Compressed_MetricRec, *PCF_Compressed_Metric; + + + typedef struct PCF_MetricRec_ + { + FT_Short leftSideBearing; + FT_Short rightSideBearing; + FT_Short characterWidth; + FT_Short ascent; + FT_Short descent; + FT_Short attributes; + + FT_ULong bits; /* offset into the PCF_BITMAPS table */ + + } PCF_MetricRec, *PCF_Metric; + + + typedef struct PCF_EncRec_ + { + FT_UShort firstCol; + FT_UShort lastCol; + FT_UShort firstRow; + FT_UShort lastRow; + FT_UShort defaultChar; + + FT_UShort* offset; + + } PCF_EncRec, *PCF_Enc; + + + typedef struct PCF_AccelRec_ + { + FT_Byte noOverlap; + FT_Byte constantMetrics; + FT_Byte terminalFont; + FT_Byte constantWidth; + FT_Byte inkInside; + FT_Byte inkMetrics; + FT_Byte drawDirection; + FT_Long fontAscent; + FT_Long fontDescent; + FT_Long maxOverlap; + PCF_MetricRec minbounds; + PCF_MetricRec maxbounds; + PCF_MetricRec ink_minbounds; + PCF_MetricRec ink_maxbounds; + + } PCF_AccelRec, *PCF_Accel; + + + /* + * This file uses X11 terminology for PCF data; an `encoding' in X11 speak + * is the same as a `character code' in FreeType speak. + */ + typedef struct PCF_FaceRec_ + { + FT_FaceRec root; + + FT_StreamRec comp_stream; + FT_Stream comp_source; + + char* charset_encoding; + char* charset_registry; + + PCF_TocRec toc; + PCF_AccelRec accel; + + int nprops; + PCF_Property properties; + + FT_ULong nmetrics; + PCF_Metric metrics; + + PCF_EncRec enc; + + FT_ULong bitmapsFormat; + + } PCF_FaceRec, *PCF_Face; + + + typedef struct PCF_DriverRec_ + { + FT_DriverRec root; + + FT_Bool no_long_family_names; + + } PCF_DriverRec, *PCF_Driver; + + + /* macros for pcf font format */ + +#define LSBFirst 0 +#define MSBFirst 1 + +#define PCF_FILE_VERSION ( ( 'p' << 24 ) | \ + ( 'c' << 16 ) | \ + ( 'f' << 8 ) | 1 ) +#define PCF_FORMAT_MASK 0xFFFFFF00UL + +#define PCF_DEFAULT_FORMAT 0x00000000UL +#define PCF_INKBOUNDS 0x00000200UL +#define PCF_ACCEL_W_INKBOUNDS 0x00000100UL +#define PCF_COMPRESSED_METRICS 0x00000100UL + +#define PCF_FORMAT_MATCH( a, b ) \ + ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) ) + +#define PCF_GLYPH_PAD_MASK ( 3 << 0 ) +#define PCF_BYTE_MASK ( 1 << 2 ) +#define PCF_BIT_MASK ( 1 << 3 ) +#define PCF_SCAN_UNIT_MASK ( 3 << 4 ) + +#define PCF_BYTE_ORDER( f ) \ + ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_BIT_ORDER( f ) \ + ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_GLYPH_PAD_INDEX( f ) \ + ( (f) & PCF_GLYPH_PAD_MASK ) +#define PCF_GLYPH_PAD( f ) \ + ( 1 << PCF_GLYPH_PAD_INDEX( f ) ) +#define PCF_SCAN_UNIT_INDEX( f ) \ + ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 ) +#define PCF_SCAN_UNIT( f ) \ + ( 1 << PCF_SCAN_UNIT_INDEX( f ) ) +#define PCF_FORMAT_BITS( f ) \ + ( (f) & ( PCF_GLYPH_PAD_MASK | \ + PCF_BYTE_MASK | \ + PCF_BIT_MASK | \ + PCF_SCAN_UNIT_MASK ) ) + +#define PCF_SIZE_TO_INDEX( s ) ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 ) +#define PCF_INDEX_TO_SIZE( b ) ( 1 << b ) + +#define PCF_FORMAT( bit, byte, glyph, scan ) \ + ( ( PCF_SIZE_TO_INDEX( scan ) << 4 ) | \ + ( ( (bit) == MSBFirst ? 1 : 0 ) << 3 ) | \ + ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \ + ( PCF_SIZE_TO_INDEX( glyph ) << 0 ) ) + +#define PCF_PROPERTIES ( 1 << 0 ) +#define PCF_ACCELERATORS ( 1 << 1 ) +#define PCF_METRICS ( 1 << 2 ) +#define PCF_BITMAPS ( 1 << 3 ) +#define PCF_INK_METRICS ( 1 << 4 ) +#define PCF_BDF_ENCODINGS ( 1 << 5 ) +#define PCF_SWIDTHS ( 1 << 6 ) +#define PCF_GLYPH_NAMES ( 1 << 7 ) +#define PCF_BDF_ACCELERATORS ( 1 << 8 ) + +#define GLYPHPADOPTIONS 4 /* I'm not sure about this */ + + FT_LOCAL( FT_Error ) + pcf_load_font( FT_Stream stream, + PCF_Face face, + FT_Long face_index ); + +FT_END_HEADER + +#endif /* PCF_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcfdrivr.c b/vendor/freetype/src/pcf/pcfdrivr.c new file mode 100644 index 0000000..f1dba02 --- /dev/null +++ b/vendor/freetype/src/pcf/pcfdrivr.c @@ -0,0 +1,836 @@ +/* pcfdrivr.c + + FreeType font driver for pcf files + + Copyright (C) 2000-2004, 2006-2011, 2013, 2014 by + Francesco Zappa Nardelli + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcf.h" +#include "pcfdrivr.h" +#include "pcfread.h" + +#include "pcferror.h" +#include "pcfutil.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pcfread + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT pcfdriver + + + /* + * This file uses X11 terminology for PCF data; an `encoding' in X11 speak + * is the same as a `character code' in FreeType speak. + */ + typedef struct PCF_CMapRec_ + { + FT_CMapRec root; + PCF_Enc enc; + + } PCF_CMapRec, *PCF_CMap; + + + FT_CALLBACK_DEF( FT_Error ) + pcf_cmap_init( FT_CMap cmap, /* PCF_CMap */ + FT_Pointer init_data ) + { + PCF_CMap pcfcmap = (PCF_CMap)cmap; + PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap ); + + FT_UNUSED( init_data ); + + + pcfcmap->enc = &face->enc; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + pcf_cmap_done( FT_CMap cmap ) /* PCF_CMap */ + { + PCF_CMap pcfcmap = (PCF_CMap)cmap; + + + pcfcmap->enc = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pcf_cmap_char_index( FT_CMap cmap, /* PCF_CMap */ + FT_UInt32 charcode ) + { + PCF_Enc enc = ( (PCF_CMap)cmap )->enc; + + FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow; + FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol; + FT_UInt32 h = enc->lastRow - enc->firstRow + 1; + FT_UInt32 w = enc->lastCol - enc->firstCol + 1; + + + /* wrapped around "negative" values are also rejected */ + if ( i >= h || j >= w ) + return 0; + + return (FT_UInt)enc->offset[i * w + j]; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pcf_cmap_char_next( FT_CMap cmap, /* PCF_CMap */ + FT_UInt32 *acharcode ) + { + PCF_Enc enc = ( (PCF_CMap)cmap )->enc; + FT_UInt32 charcode = *acharcode + 1; + + FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow; + FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol; + FT_UInt32 h = enc->lastRow - enc->firstRow + 1; + FT_UInt32 w = enc->lastCol - enc->firstCol + 1; + + FT_UInt result = 0; + + + /* adjust wrapped around "negative" values */ + if ( (FT_Int32)i < 0 ) + i = 0; + if ( (FT_Int32)j < 0 ) + j = 0; + + for ( ; i < h; i++, j = 0 ) + for ( ; j < w; j++ ) + { + result = (FT_UInt)enc->offset[i * w + j]; + if ( result != 0xFFFFU ) + goto Exit; + } + + Exit: + *acharcode = ( ( i + enc->firstRow ) << 8 ) | ( j + enc->firstCol ); + + return result; + } + + + static + const FT_CMap_ClassRec pcf_cmap_class = + { + sizeof ( PCF_CMapRec ), + pcf_cmap_init, + pcf_cmap_done, + pcf_cmap_char_index, + pcf_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL + }; + + + FT_CALLBACK_DEF( void ) + PCF_Face_Done( FT_Face face ) /* PCF_Face */ + { + PCF_Face pcfface = (PCF_Face)face; + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + FT_FREE( pcfface->metrics ); + FT_FREE( pcfface->enc.offset ); + + /* free properties */ + if ( pcfface->properties ) + { + FT_Int i; + + + for ( i = 0; i < pcfface->nprops; i++ ) + { + PCF_Property prop = &pcfface->properties[i]; + + + if ( prop ) + { + FT_FREE( prop->name ); + if ( prop->isString ) + FT_FREE( prop->value.atom ); + } + } + + FT_FREE( pcfface->properties ); + } + + FT_FREE( pcfface->toc.tables ); + FT_FREE( face->family_name ); + FT_FREE( face->style_name ); + FT_FREE( face->available_sizes ); + FT_FREE( pcfface->charset_encoding ); + FT_FREE( pcfface->charset_registry ); + + /* close compressed stream if any */ + if ( face->stream == &pcfface->comp_stream ) + { + FT_Stream_Close( &pcfface->comp_stream ); + face->stream = pcfface->comp_source; + } + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Face_Init( FT_Stream stream, + FT_Face face, /* PCF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PCF_Face pcfface = (PCF_Face)face; + FT_Error error; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "PCF driver\n" )); + + error = pcf_load_font( stream, pcfface, face_index ); + if ( error ) + { + PCF_Face_Done( face ); + +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_LZW ) || \ + defined( FT_CONFIG_OPTION_USE_BZIP2 ) + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + { + FT_Error error2; + + + /* this didn't work, try gzip support! */ + FT_TRACE2(( " ... try gzip stream\n" )); + error2 = FT_Stream_OpenGzip( &pcfface->comp_stream, stream ); + if ( FT_ERR_EQ( error2, Unimplemented_Feature ) ) + goto Fail; + + error = error2; + } +#endif /* FT_CONFIG_OPTION_USE_ZLIB */ + +#ifdef FT_CONFIG_OPTION_USE_LZW + if ( error ) + { + FT_Error error3; + + + /* this didn't work, try LZW support! */ + FT_TRACE2(( " ... try LZW stream\n" )); + error3 = FT_Stream_OpenLZW( &pcfface->comp_stream, stream ); + if ( FT_ERR_EQ( error3, Unimplemented_Feature ) ) + goto Fail; + + error = error3; + } +#endif /* FT_CONFIG_OPTION_USE_LZW */ + +#ifdef FT_CONFIG_OPTION_USE_BZIP2 + if ( error ) + { + FT_Error error4; + + + /* this didn't work, try Bzip2 support! */ + FT_TRACE2(( " ... try Bzip2 stream\n" )); + error4 = FT_Stream_OpenBzip2( &pcfface->comp_stream, stream ); + if ( FT_ERR_EQ( error4, Unimplemented_Feature ) ) + goto Fail; + + error = error4; + } +#endif /* FT_CONFIG_OPTION_USE_BZIP2 */ + + if ( error ) + goto Fail; + + pcfface->comp_source = stream; + face->stream = &pcfface->comp_stream; + + stream = face->stream; + + error = pcf_load_font( stream, pcfface, face_index ); + if ( error ) + goto Fail; + +#else /* !(FT_CONFIG_OPTION_USE_ZLIB || + FT_CONFIG_OPTION_USE_LZW || + FT_CONFIG_OPTION_USE_BZIP2) */ + + goto Fail; + +#endif + } + + /* PCF cannot have multiple faces in a single font file. + * XXX: A non-zero face_index is already an invalid argument, but + * Type1, Type42 drivers have a convention to return + * an invalid argument error when the font could be + * opened by the specified driver. + */ + if ( face_index < 0 ) + goto Exit; + else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "PCF_Face_Init: invalid face index\n" )); + PCF_Face_Done( face ); + return FT_THROW( Invalid_Argument ); + } + + /* set up charmap */ + { + FT_String *charset_registry = pcfface->charset_registry; + FT_String *charset_encoding = pcfface->charset_encoding; + FT_Bool unicode_charmap = 0; + + + if ( charset_registry && charset_encoding ) + { + char* s = charset_registry; + + + /* Uh, oh, compare first letters manually to avoid dependency + on locales. */ + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( pcfface->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + /* another name for ASCII */ + else if ( !ft_strcmp( s, "646.1991" ) && + !ft_strcmp( pcfface->charset_encoding, "IRV" ) ) + unicode_charmap = 1; + } + } + + { + FT_CharMapRec charmap; + + + charmap.face = face; + charmap.encoding = FT_ENCODING_NONE; + /* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + } + + error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL ); + } + } + + Exit: + return error; + + Fail: + FT_TRACE2(( " not a PCF file\n" )); + PCF_Face_Done( face ); + error = FT_THROW( Unknown_File_Format ); /* error */ + goto Exit; + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + PCF_Accel accel = &( (PCF_Face)size->face )->accel; + + + FT_Select_Metrics( size->face, strike_index ); + + size->metrics.ascender = accel->fontAscent * 64; + size->metrics.descender = -accel->fontDescent * 64; + size->metrics.max_advance = accel->maxbounds.characterWidth * 64; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + PCF_Face face = (PCF_Face)size->face; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = FT_ERR( Invalid_Pixel_Size ); + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = FT_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( face->accel.fontAscent + + face->accel.fontDescent ) ) + error = FT_Err_Ok; + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + if ( error ) + return error; + else + return PCF_Size_Select( size, 0 ); + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + PCF_Face face = (PCF_Face)FT_SIZE_FACE( size ); + FT_Stream stream; + FT_Error error = FT_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + PCF_Metric metric; + FT_ULong bytes; + + + FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index )); + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + stream = face->root.stream; + + metric = face->metrics + glyph_index; + + bitmap->rows = (unsigned int)( metric->ascent + + metric->descent ); + bitmap->width = (unsigned int)( metric->rightSideBearing - + metric->leftSideBearing ); + bitmap->num_grays = 1; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + + switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) ) + { + case 1: + bitmap->pitch = (int)( ( bitmap->width + 7 ) >> 3 ); + break; + + case 2: + bitmap->pitch = (int)( ( ( bitmap->width + 15 ) >> 4 ) << 1 ); + break; + + case 4: + bitmap->pitch = (int)( ( ( bitmap->width + 31 ) >> 5 ) << 2 ); + break; + + case 8: + bitmap->pitch = (int)( ( ( bitmap->width + 63 ) >> 6 ) << 3 ); + break; + + default: + return FT_THROW( Invalid_File_Format ); + } + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = metric->leftSideBearing; + slot->bitmap_top = metric->ascent; + + slot->metrics.horiAdvance = (FT_Pos)( metric->characterWidth * 64 ); + slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 ); + slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 ); + slot->metrics.width = (FT_Pos)( ( metric->rightSideBearing - + metric->leftSideBearing ) * 64 ); + slot->metrics.height = (FT_Pos)( bitmap->rows * 64 ); + + ft_synthesize_vertical_metrics( &slot->metrics, + ( face->accel.fontAscent + + face->accel.fontDescent ) * 64 ); + + if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) + goto Exit; + + /* XXX: to do: are there cases that need repadding the bitmap? */ + bytes = (FT_ULong)bitmap->pitch * bitmap->rows; + + error = ft_glyphslot_alloc_bitmap( slot, (FT_ULong)bytes ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( metric->bits ) || + FT_STREAM_READ( bitmap->buffer, bytes ) ) + goto Exit; + + if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst ) + BitOrderInvert( bitmap->buffer, bytes ); + + if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) != + PCF_BIT_ORDER( face->bitmapsFormat ) ) ) + { + switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) ) + { + case 1: + break; + + case 2: + TwoByteSwap( bitmap->buffer, bytes ); + break; + + case 4: + FourByteSwap( bitmap->buffer, bytes ); + break; + } + } + + Exit: + return error; + } + + + /* + * + * BDF SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + pcf_get_bdf_property( FT_Face face, /* PCF_Face */ + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + PCF_Face pcfface = (PCF_Face)face; + PCF_Property prop; + + + prop = pcf_find_property( pcfface, prop_name ); + if ( prop ) + { + if ( prop->isString ) + { + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + } + else + { + if ( prop->value.l > 0x7FFFFFFFL || + prop->value.l < ( -1 - 0x7FFFFFFFL ) ) + { + FT_TRACE2(( "pcf_get_bdf_property:" + " too large integer 0x%lx is truncated\n", + prop->value.l )); + } + + /* + * The PCF driver loads all properties as signed integers. + * This really doesn't seem to be a problem, because this is + * sufficient for any meaningful values. + */ + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = (FT_Int32)prop->value.l; + } + + return FT_Err_Ok; + } + + return FT_THROW( Invalid_Argument ); + } + + + FT_CALLBACK_DEF( FT_Error ) + pcf_get_charset_id( FT_Face face, /* PCF_Face */ + const char* *acharset_encoding, + const char* *acharset_registry ) + { + PCF_Face pcfface = (PCF_Face)face; + + + *acharset_encoding = pcfface->charset_encoding; + *acharset_registry = pcfface->charset_registry; + + return FT_Err_Ok; + } + + + static const FT_Service_BDFRec pcf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id, /* get_charset_id */ + (FT_BDF_GetPropertyFunc) pcf_get_bdf_property /* get_property */ + }; + + + /* + * PROPERTY SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + pcf_property_set( FT_Module module, /* PCF_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + FT_Error error = FT_Err_Ok; + PCF_Driver driver = (PCF_Driver)module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "no-long-family-names" ) ) + { +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + long lfn = ft_strtol( s, NULL, 10 ); + + + if ( lfn == 0 ) + driver->no_long_family_names = 0; + else if ( lfn == 1 ) + driver->no_long_family_names = 1; + else + return FT_THROW( Invalid_Argument ); + } + else +#endif + { + FT_Bool* no_long_family_names = (FT_Bool*)value; + + + driver->no_long_family_names = *no_long_family_names; + } + + return error; + } + +#else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_UNUSED( module ); + FT_UNUSED( value ); + FT_UNUSED( value_is_string ); +#ifndef FT_DEBUG_LEVEL_TRACE + FT_UNUSED( property_name ); +#endif + +#endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_TRACE2(( "pcf_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_CALLBACK_DEF( FT_Error ) + pcf_property_get( FT_Module module, /* PCF_Driver */ + const char* property_name, + void* value ) + { +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + FT_Error error = FT_Err_Ok; + PCF_Driver driver = (PCF_Driver)module; + + + if ( !ft_strcmp( property_name, "no-long-family-names" ) ) + { + FT_Bool no_long_family_names = driver->no_long_family_names; + FT_Bool* val = (FT_Bool*)value; + + + *val = no_long_family_names; + + return error; + } + +#else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_UNUSED( module ); + FT_UNUSED( value ); +#ifndef FT_DEBUG_LEVEL_TRACE + FT_UNUSED( property_name ); +#endif + +#endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_TRACE2(( "pcf_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + pcf_service_properties, + + (FT_Properties_SetFunc)pcf_property_set, /* set_property */ + (FT_Properties_GetFunc)pcf_property_get ) /* get_property */ + + + /* + * + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec pcf_services[] = + { + { FT_SERVICE_ID_BDF, &pcf_service_bdf }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PCF }, + { FT_SERVICE_ID_PROPERTIES, &pcf_service_properties }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + pcf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pcf_services, name ); + } + + + FT_CALLBACK_DEF( FT_Error ) + pcf_driver_init( FT_Module module ) /* PCF_Driver */ + { +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + PCF_Driver driver = (PCF_Driver)module; + + + driver->no_long_family_names = 0; +#else + FT_UNUSED( module ); +#endif + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + pcf_driver_done( FT_Module module ) /* PCF_Driver */ + { + FT_UNUSED( module ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pcf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + + sizeof ( PCF_DriverRec ), + "pcf", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + pcf_driver_init, /* FT_Module_Constructor module_init */ + pcf_driver_done, /* FT_Module_Destructor module_done */ + pcf_driver_requester /* FT_Module_Requester get_interface */ + }, + + sizeof ( PCF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + PCF_Face_Init, /* FT_Face_InitFunc init_face */ + PCF_Face_Done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + NULL, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + PCF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + PCF_Size_Request, /* FT_Size_RequestFunc request_size */ + PCF_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcfdrivr.h b/vendor/freetype/src/pcf/pcfdrivr.h new file mode 100644 index 0000000..d465393 --- /dev/null +++ b/vendor/freetype/src/pcf/pcfdrivr.h @@ -0,0 +1,44 @@ +/* pcfdrivr.h + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2002 by + Francesco Zappa Nardelli + +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. +*/ + + +#ifndef PCFDRIVR_H_ +#define PCFDRIVR_H_ + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class; + +FT_END_HEADER + + +#endif /* PCFDRIVR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcferror.h b/vendor/freetype/src/pcf/pcferror.h new file mode 100644 index 0000000..8b9e990 --- /dev/null +++ b/vendor/freetype/src/pcf/pcferror.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * pcferror.h + * + * PCF error codes (specification only). + * + * Copyright 2001, 2012 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PCF error enumeration constants. + * + */ + +#ifndef PCFERROR_H_ +#define PCFERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PCF_Err_ +#define FT_ERR_BASE FT_Mod_Err_PCF + +#include + +#endif /* PCFERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcfread.c b/vendor/freetype/src/pcf/pcfread.c new file mode 100644 index 0000000..f167bcb --- /dev/null +++ b/vendor/freetype/src/pcf/pcfread.c @@ -0,0 +1,1731 @@ +/* pcfread.c + + FreeType font driver for pcf fonts + + Copyright 2000-2010, 2012-2014 by + Francesco Zappa Nardelli + +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 +#include +#include + +#include "pcf.h" +#include "pcfread.h" + +#include "pcferror.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT pcfread + + +#ifdef FT_DEBUG_LEVEL_TRACE + static const char* const tableNames[] = + { + "properties", + "accelerators", + "metrics", + "bitmaps", + "ink metrics", + "encodings", + "swidths", + "glyph names", + "BDF accelerators" + }; +#endif + + + static + const FT_Frame_Field pcf_toc_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TocRec + + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( version ), + FT_FRAME_ULONG_LE( count ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_table_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TableRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( type ), + FT_FRAME_ULONG_LE( format ), + FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */ + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + + + static FT_Error + pcf_read_TOC( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + PCF_Toc toc = &face->toc; + PCF_Table tables; + + FT_Memory memory = FT_FACE( face )->memory; + FT_UInt n; + + FT_ULong size; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) ) + return FT_THROW( Cannot_Open_Resource ); + + if ( toc->version != PCF_FILE_VERSION || + toc->count == 0 ) + return FT_THROW( Invalid_File_Format ); + + if ( stream->size < 16 ) + return FT_THROW( Invalid_File_Format ); + + /* we need 16 bytes per TOC entry, */ + /* and there can be most 9 tables */ + if ( toc->count > ( stream->size >> 4 ) || + toc->count > 9 ) + { + FT_TRACE0(( "pcf_read_TOC: adjusting number of tables" + " (from %ld to %ld)\n", + toc->count, + FT_MIN( stream->size >> 4, 9 ) )); + toc->count = FT_MIN( stream->size >> 4, 9 ); + } + + if ( FT_QNEW_ARRAY( face->toc.tables, toc->count ) ) + return error; + + tables = face->toc.tables; + for ( n = 0; n < toc->count; n++ ) + { + if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) + goto Exit; + tables++; + } + + /* Sort tables and check for overlaps. Because they are almost */ + /* always ordered already, an in-place bubble sort with simultaneous */ + /* boundary checking seems appropriate. */ + tables = face->toc.tables; + + for ( n = 0; n < toc->count - 1; n++ ) + { + FT_UInt i, have_change; + + + have_change = 0; + + for ( i = 0; i < toc->count - 1 - n; i++ ) + { + PCF_TableRec tmp; + + + if ( tables[i].offset > tables[i + 1].offset ) + { + tmp = tables[i]; + tables[i] = tables[i + 1]; + tables[i + 1] = tmp; + + have_change = 1; + } + + if ( ( tables[i].size > tables[i + 1].offset ) || + ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) + { + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + } + + if ( !have_change ) + break; + } + + /* + * We now check whether the `size' and `offset' values are reasonable: + * `offset' + `size' must not exceed the stream size. + * + * Note, however, that X11's `pcfWriteFont' routine (used by the + * `bdftopcf' program to create PCF font files) has two special + * features. + * + * - It always assigns the accelerator table a size of 100 bytes in the + * TOC, regardless of its real size, which can vary between 34 and 72 + * bytes. + * + * - Due to the way the routine is designed, it ships out the last font + * table with its real size, ignoring the TOC's size value. Since + * the TOC size values are always rounded up to a multiple of 4, the + * difference can be up to three bytes for all tables except the + * accelerator table, for which the difference can be as large as 66 + * bytes. + * + */ + + tables = face->toc.tables; + size = stream->size; + + for ( n = 0; n < toc->count - 1; n++ ) + { + /* we need two checks to avoid overflow */ + if ( ( tables->size > size ) || + ( tables->offset > size - tables->size ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + tables++; + } + + /* only check `tables->offset' for last table element ... */ + if ( ( tables->offset > size ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + /* ... and adjust `tables->size' to the real value if necessary */ + if ( tables->size > size - tables->offset ) + tables->size = size - tables->offset; + +#ifdef FT_DEBUG_LEVEL_TRACE + + { + FT_UInt i, j; + const char* name = "?"; + + + FT_TRACE4(( "pcf_read_TOC:\n" )); + + FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); + + tables = face->toc.tables; + for ( i = 0; i < toc->count; i++ ) + { + for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); + j++ ) + if ( tables[i].type == 1UL << j ) + name = tableNames[j]; + + FT_TRACE4(( " %d: type=%s, format=0x%lX," + " size=%ld (0x%lX), offset=%ld (0x%lX)\n", + i, name, + tables[i].format, + tables[i].size, tables[i].size, + tables[i].offset, tables[i].offset )); + } + } + +#endif + + return FT_Err_Ok; + + Exit: + FT_FREE( face->toc.tables ); + return error; + } + + +#define PCF_METRIC_SIZE 12 + + static + const FT_Frame_Field pcf_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT_LE( leftSideBearing ), + FT_FRAME_SHORT_LE( rightSideBearing ), + FT_FRAME_SHORT_LE( characterWidth ), + FT_FRAME_SHORT_LE( ascent ), + FT_FRAME_SHORT_LE( descent ), + FT_FRAME_SHORT_LE( attributes ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_metric_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT( leftSideBearing ), + FT_FRAME_SHORT( rightSideBearing ), + FT_FRAME_SHORT( characterWidth ), + FT_FRAME_SHORT( ascent ), + FT_FRAME_SHORT( descent ), + FT_FRAME_SHORT( attributes ), + FT_FRAME_END + }; + + +#define PCF_COMPRESSED_METRIC_SIZE 5 + + static + const FT_Frame_Field pcf_compressed_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_Compressed_MetricRec + + FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), + FT_FRAME_BYTE( leftSideBearing ), + FT_FRAME_BYTE( rightSideBearing ), + FT_FRAME_BYTE( characterWidth ), + FT_FRAME_BYTE( ascent ), + FT_FRAME_BYTE( descent ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_metric( FT_Stream stream, + FT_ULong format, + PCF_Metric metric ) + { + FT_Error error = FT_Err_Ok; + + + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + const FT_Frame_Field* fields; + + + /* parsing normal metrics */ + fields = ( PCF_BYTE_ORDER( format ) == MSBFirst ) + ? pcf_metric_msb_header + : pcf_metric_header; + + /* the following sets `error' but doesn't return in case of failure */ + (void)FT_STREAM_READ_FIELDS( fields, metric ); + } + else + { + PCF_Compressed_MetricRec compr; + + + /* parsing compressed metrics */ + if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) + goto Exit; + + metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); + metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); + metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); + metric->ascent = (FT_Short)( compr.ascent - 0x80 ); + metric->descent = (FT_Short)( compr.descent - 0x80 ); + metric->attributes = 0; + } + + FT_TRACE5(( " width=%d," + " lsb=%d, rsb=%d," + " ascent=%d, descent=%d," + " attributes=%d\n", + metric->characterWidth, + metric->leftSideBearing, + metric->rightSideBearing, + metric->ascent, + metric->descent, + metric->attributes )); + + Exit: + return error; + } + + + static FT_Error + pcf_seek_to_table_type( FT_Stream stream, + PCF_Table tables, + FT_ULong ntables, /* same as PCF_Toc->count */ + FT_ULong type, + FT_ULong *aformat, + FT_ULong *asize ) + { + FT_Error error = FT_ERR( Invalid_File_Format ); + FT_ULong i; + + + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + { + if ( stream->pos > tables[i].offset ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Fail; + } + + if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Fail; + } + + *asize = tables[i].size; + *aformat = tables[i].format; + + return FT_Err_Ok; + } + + Fail: + *asize = 0; + return error; + } + + + static FT_Bool + pcf_has_table_type( PCF_Table tables, + FT_ULong ntables, /* same as PCF_Toc->count */ + FT_ULong type ) + { + FT_ULong i; + + + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + return TRUE; + + return FALSE; + } + + +#define PCF_PROPERTY_SIZE 9 + + static + const FT_Frame_Field pcf_property_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG_LE( name ), + FT_FRAME_BYTE ( isString ), + FT_FRAME_LONG_LE( value ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_property_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG( name ), + FT_FRAME_BYTE( isString ), + FT_FRAME_LONG( value ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ) + { + PCF_Property properties = face->properties; + FT_Bool found = 0; + int i; + + + for ( i = 0; i < face->nprops && !found; i++ ) + { + if ( !ft_strcmp( properties[i].name, prop ) ) + found = 1; + } + + if ( found ) + return properties + i - 1; + else + return NULL; + } + + + static FT_Error + pcf_get_properties( FT_Stream stream, + PCF_Face face ) + { + PCF_ParseProperty props = NULL; + PCF_Property properties = NULL; + FT_ULong nprops, orig_nprops, i; + FT_ULong format, size; + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_ULong string_size; + FT_String* strings = NULL; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_PROPERTIES, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_properties:\n" )); + FT_TRACE4(( " format: 0x%lX (%s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + goto Bail; + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( orig_nprops ); + else + (void)FT_READ_ULONG_LE( orig_nprops ); + if ( error ) + goto Bail; + + FT_TRACE4(( " number of properties: %ld\n", orig_nprops )); + + /* rough estimate */ + if ( orig_nprops > size / PCF_PROPERTY_SIZE ) + { + error = FT_THROW( Invalid_Table ); + goto Bail; + } + + /* as a heuristic limit to avoid excessive allocation in */ + /* gzip bombs (i.e., very small, invalid input data that */ + /* pretends to expand to an insanely large file) we only */ + /* load the first 256 properties */ + if ( orig_nprops > 256 ) + { + FT_TRACE0(( "pcf_get_properties:" + " only loading first 256 properties\n" )); + nprops = 256; + } + else + nprops = orig_nprops; + + face->nprops = (int)nprops; + + if ( FT_QNEW_ARRAY( props, nprops ) ) + goto Bail; + + for ( i = 0; i < nprops; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) + goto Bail; + } + } + + /* this skip will only work if we really have an extremely large */ + /* number of properties; it will fail for fake data, avoiding an */ + /* unnecessarily large allocation later on */ + if ( FT_STREAM_SKIP( ( orig_nprops - nprops ) * PCF_PROPERTY_SIZE ) ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Bail; + } + + /* pad the property array */ + /* */ + /* clever here - nprops is the same as the number of odd-units read, */ + /* as only isStringProp are odd length (Keith Packard) */ + /* */ + if ( orig_nprops & 3 ) + { + i = 4 - ( orig_nprops & 3 ); + if ( FT_STREAM_SKIP( i ) ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Bail; + } + } + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( string_size ); + else + (void)FT_READ_ULONG_LE( string_size ); + if ( error ) + goto Bail; + + FT_TRACE4(( " string size: %ld\n", string_size )); + + /* rough estimate */ + if ( string_size > size - orig_nprops * PCF_PROPERTY_SIZE ) + { + error = FT_THROW( Invalid_Table ); + goto Bail; + } + + /* the strings in the `strings' array are PostScript strings, */ + /* which can have a maximum length of 65536 characters each */ + if ( string_size > 16777472 ) /* 256 * (65536 + 1) */ + { + FT_TRACE0(( "pcf_get_properties:" + " loading only 16777472 bytes of strings array\n" )); + string_size = 16777472; + } + + /* allocate one more byte so that we have a final null byte */ + if ( FT_QALLOC( strings, string_size + 1 ) || + FT_STREAM_READ( strings, string_size ) ) + goto Bail; + + strings[string_size] = '\0'; + + /* zero out in case of failure */ + if ( FT_NEW_ARRAY( properties, nprops ) ) + goto Bail; + + face->properties = properties; + + FT_TRACE4(( "\n" )); + for ( i = 0; i < nprops; i++ ) + { + FT_Long name_offset = props[i].name; + + + if ( ( name_offset < 0 ) || + ( (FT_ULong)name_offset > string_size ) ) + { + error = FT_THROW( Invalid_Offset ); + goto Bail; + } + + if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) + goto Bail; + + FT_TRACE4(( " %s:", properties[i].name )); + + properties[i].isString = props[i].isString; + + if ( props[i].isString ) + { + FT_Long value_offset = props[i].value; + + + if ( ( value_offset < 0 ) || + ( (FT_ULong)value_offset > string_size ) ) + { + error = FT_THROW( Invalid_Offset ); + goto Bail; + } + + if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) + goto Bail; + + FT_TRACE4(( " `%s'\n", properties[i].value.atom )); + } + else + { + properties[i].value.l = props[i].value; + + FT_TRACE4(( " %ld\n", properties[i].value.l )); + } + } + + error = FT_Err_Ok; + + Bail: + FT_FREE( props ); + FT_FREE( strings ); + + return error; + } + + + static FT_Error + pcf_get_metrics( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_ULong format, size; + PCF_Metric metrics = NULL; + FT_ULong nmetrics, orig_nmetrics, i; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_METRICS, + &format, + &size ); + if ( error ) + return error; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_metrics:\n" )); + FT_TRACE4(( " format: 0x%lX (%s, %s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", + PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ? + "compressed" : "uncompressed" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) + return FT_THROW( Invalid_File_Format ); + + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( orig_nmetrics ); + else + (void)FT_READ_ULONG_LE( orig_nmetrics ); + } + else + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_USHORT( orig_nmetrics ); + else + (void)FT_READ_USHORT_LE( orig_nmetrics ); + } + if ( error ) + return FT_THROW( Invalid_File_Format ); + + FT_TRACE4(( " number of metrics: %ld\n", orig_nmetrics )); + + /* rough estimate */ + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( orig_nmetrics > size / PCF_METRIC_SIZE ) + return FT_THROW( Invalid_Table ); + } + else + { + if ( orig_nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) + return FT_THROW( Invalid_Table ); + } + + if ( !orig_nmetrics ) + return FT_THROW( Invalid_Table ); + + /* + * PCF is a format from ancient times; Unicode was in its infancy, and + * widely used two-byte character sets for CJK scripts (Big 5, GB 2312, + * JIS X 0208, etc.) did have at most 15000 characters. Even the more + * exotic CNS 11643 and CCCII standards, which were essentially + * three-byte character sets, provided less then 65536 assigned + * characters. + * + * While technically possible to have a larger number of glyphs in PCF + * files, we thus limit the number to 65535, taking into account that we + * synthesize the metrics of glyph 0 to be a copy of the `default + * character', and that 0xFFFF in the encodings array indicates a + * missing glyph. + */ + if ( orig_nmetrics > 65534 ) + { + FT_TRACE0(( "pcf_get_metrics:" + " only loading first 65534 metrics\n" )); + nmetrics = 65534; + } + else + nmetrics = orig_nmetrics; + + face->nmetrics = nmetrics + 1; + + if ( FT_QNEW_ARRAY( face->metrics, face->nmetrics ) ) + return error; + + /* we handle glyph index 0 later on */ + metrics = face->metrics + 1; + + FT_TRACE4(( "\n" )); + for ( i = 1; i < face->nmetrics; i++, metrics++ ) + { + FT_TRACE5(( " idx %ld:", i )); + error = pcf_get_metric( stream, format, metrics ); + + metrics->bits = 0; + + if ( error ) + break; + + /* sanity checks -- those values are used in `PCF_Glyph_Load' to */ + /* compute a glyph's bitmap dimensions, thus setting them to zero in */ + /* case of an error disables this particular glyph only */ + if ( metrics->rightSideBearing < metrics->leftSideBearing || + metrics->ascent < -metrics->descent ) + { + metrics->characterWidth = 0; + metrics->leftSideBearing = 0; + metrics->rightSideBearing = 0; + metrics->ascent = 0; + metrics->descent = 0; + + FT_TRACE0(( "pcf_get_metrics:" + " invalid metrics for glyph %ld\n", i )); + } + } + + if ( error ) + FT_FREE( face->metrics ); + + Bail: + return error; + } + + + static FT_Error + pcf_get_bitmaps( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + FT_ULong bitmapSizes[GLYPHPADOPTIONS]; + FT_ULong format, size, pos; + FT_ULong nbitmaps, orig_nbitmaps, i, sizebitmaps = 0; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BITMAPS, + &format, + &size ); + if ( error ) + return error; + + error = FT_Stream_EnterFrame( stream, 8 ); + if ( error ) + return error; + + format = FT_GET_ULONG_LE(); + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + orig_nbitmaps = FT_GET_ULONG(); + else + orig_nbitmaps = FT_GET_ULONG_LE(); + + FT_Stream_ExitFrame( stream ); + + FT_TRACE4(( "pcf_get_bitmaps:\n" )); + FT_TRACE4(( " format: 0x%lX\n", format )); + FT_TRACE4(( " (%s, %s,\n", + PCF_BYTE_ORDER( format ) == MSBFirst + ? "most significant byte first" + : "least significant byte first", + PCF_BIT_ORDER( format ) == MSBFirst + ? "most significant bit first" + : "least significant bit first" )); + FT_TRACE4(( " padding=%d bit%s, scanning=%d bit%s)\n", + 8 << PCF_GLYPH_PAD_INDEX( format ), + ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s", + 8 << PCF_SCAN_UNIT_INDEX( format ), + ( 8 << PCF_SCAN_UNIT_INDEX( format ) ) == 1 ? "" : "s" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + return FT_THROW( Invalid_File_Format ); + + FT_TRACE4(( " number of bitmaps: %ld\n", orig_nbitmaps )); + + /* see comment in `pcf_get_metrics' */ + if ( orig_nbitmaps > 65534 ) + { + FT_TRACE0(( "pcf_get_bitmaps:" + " only loading first 65534 bitmaps\n" )); + nbitmaps = 65534; + } + else + nbitmaps = orig_nbitmaps; + + /* no extra bitmap for glyph 0 */ + if ( nbitmaps != face->nmetrics - 1 ) + return FT_THROW( Invalid_File_Format ); + + /* start position of bitmap data */ + pos = stream->pos + nbitmaps * 4 + 4 * 4; + + FT_TRACE5(( "\n" )); + for ( i = 1; i <= nbitmaps; i++ ) + { + FT_ULong offset; + + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( offset ); + else + (void)FT_READ_ULONG_LE( offset ); + + FT_TRACE5(( " bitmap %lu: offset %lu (0x%lX)\n", + i, offset, offset )); + + /* right now, we only check the offset with a rough estimate; */ + /* actual bitmaps are only loaded on demand */ + if ( offset > size ) + { + FT_TRACE0(( "pcf_get_bitmaps:" + " invalid offset to bitmap data of glyph %lu\n", i )); + face->metrics[i].bits = pos; + } + else + face->metrics[i].bits = pos + offset; + } + if ( error ) + goto Bail; + + for ( i = 0; i < GLYPHPADOPTIONS; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( bitmapSizes[i] ); + else + (void)FT_READ_ULONG_LE( bitmapSizes[i] ); + if ( error ) + goto Bail; + + sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; + + FT_TRACE4(( " %d-bit padding implies a size of %lu\n", + 8 << i, bitmapSizes[i] )); + } + + FT_TRACE4(( " %lu bitmaps, using %d-bit padding\n", + nbitmaps, + 8 << PCF_GLYPH_PAD_INDEX( format ) )); + FT_TRACE4(( " bitmap size: %lu\n", sizebitmaps )); + + FT_UNUSED( sizebitmaps ); /* only used for debugging */ + + face->bitmapsFormat = format; + + Bail: + return error; + } + + + /* + * This file uses X11 terminology for PCF data; an `encoding' in X11 speak + * is the same as a character code in FreeType speak. + */ +#define PCF_ENC_SIZE 10 + + static + const FT_Frame_Field pcf_enc_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_EncRec + + FT_FRAME_START( PCF_ENC_SIZE ), + FT_FRAME_USHORT_LE( firstCol ), + FT_FRAME_USHORT_LE( lastCol ), + FT_FRAME_USHORT_LE( firstRow ), + FT_FRAME_USHORT_LE( lastRow ), + FT_FRAME_USHORT_LE( defaultChar ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_enc_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_EncRec + + FT_FRAME_START( PCF_ENC_SIZE ), + FT_FRAME_USHORT( firstCol ), + FT_FRAME_USHORT( lastCol ), + FT_FRAME_USHORT( firstRow ), + FT_FRAME_USHORT( lastRow ), + FT_FRAME_USHORT( defaultChar ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_encodings( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_ULong format, size; + PCF_Enc enc = &face->enc; + FT_ULong nencoding; + FT_UShort* offset; + FT_UShort defaultCharRow, defaultCharCol; + FT_UShort encodingOffset, defaultCharEncodingOffset; + FT_UShort i, j; + FT_Byte* pos; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BDF_ENCODINGS, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_encodings:\n" )); + FT_TRACE4(( " format: 0x%lX (%s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_BDF_ENCODINGS ) ) + return FT_THROW( Invalid_File_Format ); + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_enc_msb_header, enc ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_enc_header, enc ) ) + goto Bail; + } + + FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n", + enc->firstCol, enc->lastCol )); + FT_TRACE4(( " firstRow 0x%X, lastRow 0x%X\n", + enc->firstRow, enc->lastRow )); + FT_TRACE4(( " defaultChar 0x%X\n", + enc->defaultChar )); + + /* sanity checks; we limit numbers of rows and columns to 256 */ + if ( enc->firstCol > enc->lastCol || + enc->lastCol > 0xFF || + enc->firstRow > enc->lastRow || + enc->lastRow > 0xFF ) + return FT_THROW( Invalid_Table ); + + FT_TRACE5(( "\n" )); + + defaultCharRow = enc->defaultChar >> 8; + defaultCharCol = enc->defaultChar & 0xFF; + + /* validate default character */ + if ( defaultCharRow < enc->firstRow || + defaultCharRow > enc->lastRow || + defaultCharCol < enc->firstCol || + defaultCharCol > enc->lastCol ) + { + enc->defaultChar = enc->firstRow * 256U + enc->firstCol; + FT_TRACE0(( "pcf_get_encodings:" + " Invalid default character set to %u\n", + enc->defaultChar )); + + defaultCharRow = enc->firstRow; + defaultCharCol = enc->firstCol; + } + + nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) * + (FT_ULong)( enc->lastRow - enc->firstRow + 1 ); + + error = FT_Stream_EnterFrame( stream, 2 * nencoding ); + if ( error ) + goto Bail; + + /* + * FreeType mandates that glyph index 0 is the `undefined glyph', which + * PCF calls the `default character'. However, FreeType needs glyph + * index 0 to be used for the undefined glyph only, which is is not the + * case for PCF. For this reason, we add one slot for glyph index 0 and + * simply copy the default character to it. + * + * `stream->cursor' still points to the beginning of the frame; we can + * thus easily get the offset to the default character. + */ + pos = stream->cursor + + 2 * ( ( defaultCharRow - enc->firstRow ) * + ( enc->lastCol - enc->firstCol + 1 ) + + defaultCharCol - enc->firstCol ); + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + defaultCharEncodingOffset = FT_PEEK_USHORT( pos ); + else + defaultCharEncodingOffset = FT_PEEK_USHORT_LE( pos ); + + if ( defaultCharEncodingOffset == 0xFFFF ) + { + FT_TRACE0(( "pcf_get_encodings:" + " No glyph for default character,\n" )); + FT_TRACE0(( " " + " setting it to the first glyph of the font\n" )); + defaultCharEncodingOffset = 1; + } + else + { + defaultCharEncodingOffset++; + + if ( defaultCharEncodingOffset >= face->nmetrics ) + { + FT_TRACE0(( "pcf_get_encodings:" + " Invalid glyph index for default character,\n" )); + FT_TRACE0(( " " + " setting it to the first glyph of the font\n" )); + defaultCharEncodingOffset = 1; + } + } + + /* copy metrics of default character to index 0 */ + face->metrics[0] = face->metrics[defaultCharEncodingOffset]; + + if ( FT_QNEW_ARRAY( enc->offset, nencoding ) ) + goto Bail; + + /* now loop over all values */ + offset = enc->offset; + for ( i = enc->firstRow; i <= enc->lastRow; i++ ) + { + for ( j = enc->firstCol; j <= enc->lastCol; j++ ) + { + /* X11's reference implementation uses the equivalent to */ + /* `FT_GET_SHORT', however PCF fonts with more than 32768 */ + /* characters (e.g., `unifont.pcf') clearly show that an */ + /* unsigned value is needed. */ + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + encodingOffset = FT_GET_USHORT(); + else + encodingOffset = FT_GET_USHORT_LE(); + + /* everything is off by 1 due to the artificial glyph 0 */ + *offset++ = encodingOffset == 0xFFFF ? 0xFFFF + : encodingOffset + 1; + } + } + FT_Stream_ExitFrame( stream ); + + Bail: + return error; + } + + + static + const FT_Frame_Field pcf_accel_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG_LE ( fontAscent ), + FT_FRAME_LONG_LE ( fontDescent ), + FT_FRAME_LONG_LE ( maxOverlap ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_accel_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG ( fontAscent ), + FT_FRAME_LONG ( fontDescent ), + FT_FRAME_LONG ( maxOverlap ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_accel( FT_Stream stream, + PCF_Face face, + FT_ULong type ) + { + FT_ULong format, size; + FT_Error error; + PCF_Accel accel = &face->accel; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + type, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_accel%s:\n", + type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)" + : "" )); + FT_TRACE4(( " format: 0x%lX (%s, %s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", + PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ? + "accelerated" : "not accelerated" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + goto Bail; + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) + goto Bail; + } + + FT_TRACE5(( " noOverlap=%s, constantMetrics=%s," + " terminalFont=%s, constantWidth=%s\n", + accel->noOverlap ? "yes" : "no", + accel->constantMetrics ? "yes" : "no", + accel->terminalFont ? "yes" : "no", + accel->constantWidth ? "yes" : "no" )); + FT_TRACE5(( " inkInside=%s, inkMetrics=%s, drawDirection=%s\n", + accel->inkInside ? "yes" : "no", + accel->inkMetrics ? "yes" : "no", + accel->drawDirection ? "RTL" : "LTR" )); + FT_TRACE5(( " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n", + accel->fontAscent, + accel->fontDescent, + accel->maxOverlap )); + + /* sanity checks */ + if ( FT_ABS( accel->fontAscent ) > 0x7FFF ) + { + accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %ld\n", + accel->fontAscent )); + } + if ( FT_ABS( accel->fontDescent ) > 0x7FFF ) + { + accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "pfc_get_accel: clamping font descent to value %ld\n", + accel->fontDescent )); + } + + FT_TRACE5(( " minbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->minbounds) ); + if ( error ) + goto Bail; + + FT_TRACE5(( " maxbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->maxbounds) ); + if ( error ) + goto Bail; + + if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + { + FT_TRACE5(( " ink minbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_minbounds) ); + if ( error ) + goto Bail; + + FT_TRACE5(( " ink maxbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_maxbounds) ); + if ( error ) + goto Bail; + } + else + { + accel->ink_minbounds = accel->minbounds; + accel->ink_maxbounds = accel->maxbounds; + } + + Bail: + return error; + } + + + static FT_Error + pcf_interpret_style( PCF_Face pcf ) + { + FT_Error error = FT_Err_Ok; + FT_Face face = FT_FACE( pcf ); + FT_Memory memory = face->memory; + + PCF_Property prop; + + const char* strings[4] = { NULL, NULL, NULL, NULL }; + size_t lengths[4], nn, len; + + + face->style_flags = 0; + + prop = pcf_find_property( pcf, "SLANT" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || + *(prop->value.atom) == 'o' ) ? "Oblique" + : "Italic"; + } + + prop = pcf_find_property( pcf, "WEIGHT_NAME" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = "Bold"; + } + + prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (const char*)( prop->value.atom ); + + prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (const char*)( prop->value.atom ); + + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + + if ( len == 0 ) + { + strings[0] = "Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + + { + char* s; + + + if ( FT_QALLOC( face->style_name, len ) ) + return error; + + s = face->style_name; + + for ( nn = 0; nn < 4; nn++ ) + { + const char* src = strings[nn]; + + + len = lengths[nn]; + + if ( !src ) + continue; + + /* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + + ft_memcpy( s, src, len ); + + /* need to convert spaces to dashes for */ + /* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + size_t mm; + + + for ( mm = 0; mm < len; mm++ ) + if ( s[mm] == ' ' ) + s[mm] = '-'; + } + + s += len; + } + *s = 0; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pcf_load_font( FT_Stream stream, + PCF_Face face, + FT_Long face_index ) + { + FT_Face root = FT_FACE( face ); + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_Bool hasBDFAccelerators; + + + error = pcf_read_TOC( stream, face ); + if ( error ) + goto Exit; + + root->num_faces = 1; + root->face_index = 0; + + /* If we are performing a simple font format check, exit immediately. */ + if ( face_index < 0 ) + return FT_Err_Ok; + + error = pcf_get_properties( stream, face ); + if ( error ) + goto Exit; + + /* Use the old accelerators if no BDF accelerators are in the file. */ + hasBDFAccelerators = pcf_has_table_type( face->toc.tables, + face->toc.count, + PCF_BDF_ACCELERATORS ); + if ( !hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); + if ( error ) + goto Exit; + } + + /* metrics */ + error = pcf_get_metrics( stream, face ); + if ( error ) + goto Exit; + + /* bitmaps */ + error = pcf_get_bitmaps( stream, face ); + if ( error ) + goto Exit; + + /* encodings */ + error = pcf_get_encodings( stream, face ); + if ( error ) + goto Exit; + + /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ + if ( hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); + if ( error ) + goto Exit; + } + + /* XXX: TO DO: inkmetrics and glyph_names are missing */ + + /* now construct the face object */ + { + PCF_Property prop; + + + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + if ( face->accel.constantWidth ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( FT_SET_ERROR( pcf_interpret_style( face ) ) ) + goto Exit; + + prop = pcf_find_property( face, "FAMILY_NAME" ); + if ( prop && prop->isString ) + { + +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + PCF_Driver driver = (PCF_Driver)FT_FACE_DRIVER( face ); + + + if ( !driver->no_long_family_names ) + { + /* Prepend the foundry name plus a space to the family name. */ + /* There are many fonts just called `Fixed' which look */ + /* completely different, and which have nothing to do with each */ + /* other. When selecting `Fixed' in KDE or Gnome one gets */ + /* results that appear rather random, the style changes often if */ + /* one changes the size and one cannot select some fonts at all. */ + /* */ + /* We also check whether we have `wide' characters; all put */ + /* together, we get family names like `Sony Fixed' or `Misc */ + /* Fixed Wide'. */ + + PCF_Property foundry_prop, point_size_prop, average_width_prop; + + int l = ft_strlen( prop->value.atom ) + 1; + int wide = 0; + + + foundry_prop = pcf_find_property( face, "FOUNDRY" ); + point_size_prop = pcf_find_property( face, "POINT_SIZE" ); + average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" ); + + if ( point_size_prop && average_width_prop ) + { + if ( average_width_prop->value.l >= point_size_prop->value.l ) + { + /* This font is at least square shaped or even wider */ + wide = 1; + l += ft_strlen( " Wide" ); + } + } + + if ( foundry_prop && foundry_prop->isString ) + { + l += ft_strlen( foundry_prop->value.atom ) + 1; + + if ( FT_QALLOC( root->family_name, l ) ) + goto Exit; + + ft_strcpy( root->family_name, foundry_prop->value.atom ); + ft_strcat( root->family_name, " " ); + ft_strcat( root->family_name, prop->value.atom ); + } + else + { + if ( FT_QALLOC( root->family_name, l ) ) + goto Exit; + + ft_strcpy( root->family_name, prop->value.atom ); + } + + if ( wide ) + ft_strcat( root->family_name, " Wide" ); + } + else + +#endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + { + if ( FT_STRDUP( root->family_name, prop->value.atom ) ) + goto Exit; + } + } + else + root->family_name = NULL; + + root->num_glyphs = (FT_Long)face->nmetrics; + + root->num_fixed_sizes = 1; + if ( FT_NEW( root->available_sizes ) ) + goto Exit; + + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_Short resolution_x = 0, resolution_y = 0; + + + /* for simplicity, we take absolute values of integer properties */ + +#if 0 + bsize->height = face->accel.maxbounds.ascent << 6; +#endif + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( face->accel.fontAscent + face->accel.fontDescent < 0 ) + FT_TRACE0(( "pcf_load_font: negative height\n" )); +#endif + if ( FT_ABS( face->accel.fontAscent + + face->accel.fontDescent ) > 0x7FFF ) + { + bsize->height = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping height to value %d\n", + bsize->height )); + } + else + bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent + + face->accel.fontDescent ) ); + + prop = pcf_find_property( face, "AVERAGE_WIDTH" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative average width\n" )); +#endif + if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) ) + { + bsize->width = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n", + bsize->width )); + } + else + bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); + } + else + { + /* this is a heuristical value */ + bsize->width = ( bsize->height * 2 + 1 ) / 3; + } + + prop = pcf_find_property( face, "POINT_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative point size\n" )); +#endif + /* convert from 722.7 decipoints to 72 points per inch */ + if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */ + { + bsize->size = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping point size to value %ld\n", + bsize->size )); + } + else + bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), + 64 * 7200, + 72270L ); + } + + prop = pcf_find_property( face, "PIXEL_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative pixel size\n" )); +#endif + if ( FT_ABS( prop->value.l ) > 0x7FFF ) + { + bsize->y_ppem = 0x7FFF << 6; + FT_TRACE0(( "pcf_load_font: clamping pixel size to value %ld\n", + bsize->y_ppem )); + } + else + bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; + } + + prop = pcf_find_property( face, "RESOLUTION_X" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative X resolution\n" )); +#endif + if ( FT_ABS( prop->value.l ) > 0x7FFF ) + { + resolution_x = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n", + resolution_x )); + } + else + resolution_x = FT_ABS( (FT_Short)prop->value.l ); + } + + prop = pcf_find_property( face, "RESOLUTION_Y" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative Y resolution\n" )); +#endif + if ( FT_ABS( prop->value.l ) > 0x7FFF ) + { + resolution_y = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n", + resolution_y )); + } + else + resolution_y = FT_ABS( (FT_Short)prop->value.l ); + } + + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = FT_MulDiv( bsize->y_ppem, + resolution_x, + resolution_y ); + else + bsize->x_ppem = bsize->y_ppem; + } + + /* set up charset */ + { + PCF_Property charset_registry, charset_encoding; + + + charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); + charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); + + if ( charset_registry && charset_registry->isString && + charset_encoding && charset_encoding->isString ) + { + if ( FT_STRDUP( face->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( face->charset_registry, + charset_registry->value.atom ) ) + goto Exit; + } + } + } + + Exit: + if ( error ) + { + /* This is done to respect the behaviour of the original */ + /* PCF font driver. */ + error = FT_THROW( Invalid_File_Format ); + } + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcfread.h b/vendor/freetype/src/pcf/pcfread.h new file mode 100644 index 0000000..a54648f --- /dev/null +++ b/vendor/freetype/src/pcf/pcfread.h @@ -0,0 +1,44 @@ +/* pcfread.h + + FreeType font driver for pcf fonts + + Copyright 2003 by + Francesco Zappa Nardelli + +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. +*/ + + +#ifndef PCFREAD_H_ +#define PCFREAD_H_ + + + +FT_BEGIN_HEADER + + FT_LOCAL( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ); + +FT_END_HEADER + +#endif /* PCFREAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcfutil.c b/vendor/freetype/src/pcf/pcfutil.c new file mode 100644 index 0000000..9575726 --- /dev/null +++ b/vendor/freetype/src/pcf/pcfutil.c @@ -0,0 +1,119 @@ +/* + +Copyright 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */ + +/* + * Author: Keith Packard, MIT X Consortium + */ + +/* Modified for use with FreeType */ + + +#include "pcfutil.h" + + + /* + * Invert bit order within each BYTE of an array. + */ + + FT_LOCAL_DEF( void ) + BitOrderInvert( unsigned char* buf, + size_t nbytes ) + { + for ( ; nbytes > 0; nbytes--, buf++ ) + { + unsigned int val = *buf; + + + val = ( ( val >> 1 ) & 0x55 ) | ( ( val << 1 ) & 0xAA ); + val = ( ( val >> 2 ) & 0x33 ) | ( ( val << 2 ) & 0xCC ); + val = ( ( val >> 4 ) & 0x0F ) | ( ( val << 4 ) & 0xF0 ); + + *buf = (unsigned char)val; + } + } + + +#if defined( __clang__ ) || \ + ( defined( __GNUC__ ) && \ + ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 8 ) ) ) + +#define BSWAP16( x ) __builtin_bswap16( x ) +#define BSWAP32( x ) __builtin_bswap32( x ) + +#elif defined( _MSC_VER ) && _MSC_VER >= 1300 + +#pragma intrinsic( _byteswap_ushort ) +#pragma intrinsic( _byteswap_ulong ) + +#define BSWAP16( x ) _byteswap_ushort( x ) +#define BSWAP32( x ) _byteswap_ulong( x ) + +#else + +#define BSWAP16( x ) \ + (FT_UInt16)( ( ( ( x ) >> 8 ) & 0xff ) | \ + ( ( ( x ) & 0xff ) << 8 ) ) +#define BSWAP32( x ) \ + (FT_UInt32)( ( ( ( x ) & 0xff000000u ) >> 24 ) | \ + ( ( ( x ) & 0x00ff0000u ) >> 8 ) | \ + ( ( ( x ) & 0x0000ff00u ) << 8 ) | \ + ( ( ( x ) & 0x000000ffu ) << 24 ) ) + +#endif + + /* + * Invert byte order within each 16-bits of an array. + */ + + FT_LOCAL_DEF( void ) + TwoByteSwap( unsigned char* buf, + size_t nbytes ) + { + FT_UInt16* b = (FT_UInt16*)buf; + + + for ( ; nbytes >= 2; nbytes -= 2, b++ ) + *b = BSWAP16( *b ); + } + + /* + * Invert byte order within each 32-bits of an array. + */ + + FT_LOCAL_DEF( void ) + FourByteSwap( unsigned char* buf, + size_t nbytes ) + { + FT_UInt32* b = (FT_UInt32*)buf; + + + for ( ; nbytes >= 4; nbytes -= 4, b++ ) + *b = BSWAP32( *b ); + } + + +/* END */ diff --git a/vendor/freetype/src/pcf/pcfutil.h b/vendor/freetype/src/pcf/pcfutil.h new file mode 100644 index 0000000..a197c15 --- /dev/null +++ b/vendor/freetype/src/pcf/pcfutil.h @@ -0,0 +1,55 @@ +/* pcfutil.h + + FreeType font driver for pcf fonts + + Copyright 2000, 2001, 2004 by + Francesco Zappa Nardelli + +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. +*/ + + +#ifndef PCFUTIL_H_ +#define PCFUTIL_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + BitOrderInvert( unsigned char* buf, + size_t nbytes ); + + FT_LOCAL( void ) + TwoByteSwap( unsigned char* buf, + size_t nbytes ); + + FT_LOCAL( void ) + FourByteSwap( unsigned char* buf, + size_t nbytes ); + +FT_END_HEADER + +#endif /* PCFUTIL_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pcf/rules.mk b/vendor/freetype/src/pcf/rules.mk new file mode 100644 index 0000000..1b55daf --- /dev/null +++ b/vendor/freetype/src/pcf/rules.mk @@ -0,0 +1,82 @@ +# +# FreeType 2 pcf driver configuration rules +# + + +# Copyright (C) 2000, 2001, 2003, 2008 by +# Francesco Zappa Nardelli +# +# 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. + + +# pcf driver directory +# +PCF_DIR := $(SRC_DIR)/pcf + + +PCF_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(PCF_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# pcf driver sources (i.e., C files) +# +PCF_DRV_SRC := $(PCF_DIR)/pcfdrivr.c \ + $(PCF_DIR)/pcfread.c \ + $(PCF_DIR)/pcfutil.c + +# pcf driver headers +# +PCF_DRV_H := $(PCF_DRV_SRC:%.c=%.h) \ + $(PCF_DIR)/pcf.h \ + $(PCF_DIR)/pcferror.h + +# pcf driver object(s) +# +# PCF_DRV_OBJ_M is used during `multi' builds +# PCF_DRV_OBJ_S is used during `single' builds +# +PCF_DRV_OBJ_M := $(PCF_DRV_SRC:$(PCF_DIR)/%.c=$(OBJ_DIR)/%.$O) +PCF_DRV_OBJ_S := $(OBJ_DIR)/pcf.$O + +# pcf driver source file for single build +# +PCF_DRV_SRC_S := $(PCF_DIR)/pcf.c + + +# pcf driver - single object +# +$(PCF_DRV_OBJ_S): $(PCF_DRV_SRC_S) $(PCF_DRV_SRC) $(FREETYPE_H) $(PCF_DRV_H) + $(PCF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(PCF_DRV_SRC_S)) + + +# pcf driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(PCF_DIR)/%.c $(FREETYPE_H) $(PCF_DRV_H) + $(PCF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(PCF_DRV_OBJ_S) +DRV_OBJS_M += $(PCF_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/pfr/module.mk b/vendor/freetype/src/pfr/module.mk new file mode 100644 index 0000000..388a38e --- /dev/null +++ b/vendor/freetype/src/pfr/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 PFR module definition +# + + +# Copyright (C) 2002-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += PFR_DRIVER + +define PFR_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, pfr_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)pfr $(ECHO_DRIVER_DESC)PFR/TrueDoc font files with extension *.pfr$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/pfr/pfr.c b/vendor/freetype/src/pfr/pfr.c new file mode 100644 index 0000000..d373815 --- /dev/null +++ b/vendor/freetype/src/pfr/pfr.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * pfr.c + * + * FreeType PFR driver component. + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pfrcmap.c" +#include "pfrdrivr.c" +#include "pfrgload.c" +#include "pfrload.c" +#include "pfrobjs.c" +#include "pfrsbit.c" + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrcmap.c b/vendor/freetype/src/pfr/pfrcmap.c new file mode 100644 index 0000000..08fe41d --- /dev/null +++ b/vendor/freetype/src/pfr/pfrcmap.c @@ -0,0 +1,188 @@ +/**************************************************************************** + * + * pfrcmap.c + * + * FreeType PFR cmap handling (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "pfrcmap.h" +#include "pfrobjs.h" + +#include "pfrerror.h" + + + FT_CALLBACK_DEF( FT_Error ) + pfr_cmap_init( FT_CMap cmap, /* PFR_CMap */ + FT_Pointer pointer ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_Error error = FT_Err_Ok; + PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap ); + + FT_UNUSED( pointer ); + + + pfrcmap->num_chars = face->phy_font.num_chars; + pfrcmap->chars = face->phy_font.chars; + + /* just for safety, check that the character entries are correctly */ + /* sorted in increasing character code order */ + { + FT_UInt n; + + + for ( n = 1; n < pfrcmap->num_chars; n++ ) + { + if ( pfrcmap->chars[n - 1].char_code >= pfrcmap->chars[n].char_code ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + pfr_cmap_done( FT_CMap cmap ) /* PFR_CMap */ + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + + + pfrcmap->chars = NULL; + pfrcmap->num_chars = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_index( FT_CMap cmap, /* PFR_CMap */ + FT_UInt32 char_code ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_UInt min = 0; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; + PFR_Char gchar; + + + while ( min < max ) + { + gchar = pfrcmap->chars + mid; + + if ( gchar->char_code == char_code ) + return mid + 1; + + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_next( FT_CMap cmap, /* PFR_CMap */ + FT_UInt32 *pchar_code ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + Restart: + { + FT_UInt min = 0; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; + PFR_Char gchar; + + + while ( min < max ) + { + gchar = pfrcmap->chars + mid; + + if ( gchar->char_code == char_code ) + { + result = mid; + if ( result != 0 ) + { + result++; + goto Exit; + } + + char_code++; + goto Restart; + } + + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + /* we didn't find it, but we have a pair just above it */ + char_code = 0; + + if ( min < pfrcmap->num_chars ) + { + gchar = pfrcmap->chars + min; + result = min; + if ( result != 0 ) + { + result++; + char_code = gchar->char_code; + } + } + } + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + pfr_cmap_class_rec = + { + sizeof ( PFR_CMapRec ), + + (FT_CMap_InitFunc) pfr_cmap_init, /* init */ + (FT_CMap_DoneFunc) pfr_cmap_done, /* done */ + (FT_CMap_CharIndexFunc)pfr_cmap_char_index, /* char_index */ + (FT_CMap_CharNextFunc) pfr_cmap_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrcmap.h b/vendor/freetype/src/pfr/pfrcmap.h new file mode 100644 index 0000000..8110f17 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrcmap.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * pfrcmap.h + * + * FreeType PFR cmap handling (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRCMAP_H_ +#define PFRCMAP_H_ + +#include +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt num_chars; + PFR_Char chars; + + } PFR_CMapRec, *PFR_CMap; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec pfr_cmap_class_rec; + +FT_END_HEADER + + +#endif /* PFRCMAP_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrdrivr.c b/vendor/freetype/src/pfr/pfrdrivr.c new file mode 100644 index 0000000..0048f52 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrdrivr.c @@ -0,0 +1,212 @@ +/**************************************************************************** + * + * pfrdrivr.c + * + * FreeType PFR driver interface (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include "pfrdrivr.h" +#include "pfrobjs.h" + +#include "pfrerror.h" + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_kerning( FT_Face face, /* PFR_Face */ + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + PFR_Face pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; + + + (void)pfr_face_get_kerning( face, left, right, avector ); + + /* convert from metrics to outline units when necessary */ + if ( phys->outline_resolution != phys->metrics_resolution ) + { + if ( avector->x != 0 ) + avector->x = FT_MulDiv( avector->x, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + + if ( avector->y != 0 ) + avector->y = FT_MulDiv( avector->y, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + } + + return FT_Err_Ok; + } + + + /* + * PFR METRICS SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_advance( FT_Face face, /* PFR_Face */ + FT_UInt gindex, + FT_Pos *anadvance ) + { + PFR_Face pfrface = (PFR_Face)face; + FT_Error error = FT_ERR( Invalid_Argument ); + + + *anadvance = 0; + + if ( !gindex ) + goto Exit; + + gindex--; + + if ( pfrface ) + { + PFR_PhyFont phys = &pfrface->phy_font; + + + if ( gindex < phys->num_chars ) + { + *anadvance = phys->chars[gindex].advance; + error = FT_Err_Ok; + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_metrics( FT_Face face, /* PFR_Face */ + FT_UInt *anoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + PFR_Face pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; + FT_Fixed x_scale, y_scale; + FT_Size size = pfrface->root.size; + + + if ( anoutline_resolution ) + *anoutline_resolution = phys->outline_resolution; + + if ( ametrics_resolution ) + *ametrics_resolution = phys->metrics_resolution; + + x_scale = 0x10000L; + y_scale = 0x10000L; + + if ( size ) + { + x_scale = FT_DivFix( size->metrics.x_ppem << 6, + (FT_Long)phys->metrics_resolution ); + + y_scale = FT_DivFix( size->metrics.y_ppem << 6, + (FT_Long)phys->metrics_resolution ); + } + + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + + return FT_Err_Ok; + } + + + static + const FT_Service_PfrMetricsRec pfr_metrics_service_rec = + { + pfr_get_metrics, /* get_metrics */ + pfr_face_get_kerning, /* get_kerning */ + pfr_get_advance /* get_advance */ + }; + + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec pfr_services[] = + { + { FT_SERVICE_ID_PFR_METRICS, &pfr_metrics_service_rec }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PFR }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + pfr_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pfr_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pfr_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE, + + sizeof ( FT_DriverRec ), + + "pfr", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + pfr_get_service /* FT_Module_Requester get_interface */ + }, + + sizeof ( PFR_FaceRec ), + sizeof ( PFR_SizeRec ), + sizeof ( PFR_SlotRec ), + + pfr_face_init, /* FT_Face_InitFunc init_face */ + pfr_face_done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + pfr_slot_init, /* FT_Slot_InitFunc init_slot */ + pfr_slot_done, /* FT_Slot_DoneFunc done_slot */ + + pfr_slot_load, /* FT_Slot_LoadFunc load_glyph */ + + pfr_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + NULL, /* FT_Size_RequestFunc request_size */ + NULL, /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrdrivr.h b/vendor/freetype/src/pfr/pfrdrivr.h new file mode 100644 index 0000000..da14468 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrdrivr.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * pfrdrivr.h + * + * High-level Type PFR driver interface (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRDRIVR_H_ +#define PFRDRIVR_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pfr_driver_class; + +FT_END_HEADER + + +#endif /* PFRDRIVR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrerror.h b/vendor/freetype/src/pfr/pfrerror.h new file mode 100644 index 0000000..5dfb254 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrerror.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * pfrerror.h + * + * PFR error codes (specification only). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PFR error enumeration constants. + * + */ + +#ifndef PFRERROR_H_ +#define PFRERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PFR_Err_ +#define FT_ERR_BASE FT_Mod_Err_PFR + +#include + +#endif /* PFRERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrgload.c b/vendor/freetype/src/pfr/pfrgload.c new file mode 100644 index 0000000..48cf27e --- /dev/null +++ b/vendor/freetype/src/pfr/pfrgload.c @@ -0,0 +1,849 @@ +/**************************************************************************** + * + * pfrgload.c + * + * FreeType PFR glyph loader (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrgload.h" +#include "pfrsbit.h" +#include "pfrload.h" /* for macro definitions */ +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ) + { + FT_ZERO( glyph ); + + glyph->loader = loader; + + FT_GlyphLoader_Rewind( loader ); + } + + + FT_LOCAL_DEF( void ) + pfr_glyph_done( PFR_Glyph glyph ) + { + FT_Memory memory = glyph->loader->memory; + + + FT_FREE( glyph->x_control ); + glyph->y_control = NULL; + + glyph->max_xy_control = 0; +#if 0 + glyph->num_x_control = 0; + glyph->num_y_control = 0; +#endif + + FT_FREE( glyph->subs ); + + glyph->max_subs = 0; + glyph->num_subs = 0; + + glyph->loader = NULL; + glyph->path_begun = 0; + } + + + /* close current contour, if any */ + static void + pfr_glyph_close_contour( PFR_Glyph glyph ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Int last, first; + + + if ( !glyph->path_begun ) + return; + + /* compute first and last point indices in current glyph outline */ + last = outline->n_points - 1; + first = 0; + if ( outline->n_contours > 0 ) + first = outline->contours[outline->n_contours - 1]; + + /* if the last point falls on the same location as the first one */ + /* we need to delete it */ + if ( last > first ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + last; + + + if ( p1->x == p2->x && p1->y == p2->y ) + { + outline->n_points--; + last--; + } + } + + /* don't add empty contours */ + if ( last >= first ) + outline->contours[outline->n_contours++] = (short)last; + + glyph->path_begun = 0; + } + + + /* reset glyph to start the loading of a new glyph */ + static void + pfr_glyph_start( PFR_Glyph glyph ) + { + glyph->path_begun = 0; + } + + + static FT_Error + pfr_glyph_line_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 ); + if ( !error ) + { + FT_Int n = outline->n_points; + + + outline->points[n] = *to; + outline->tags [n] = FT_CURVE_TAG_ON; + + outline->n_points++; + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_curve_to( PFR_Glyph glyph, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 ); + if ( !error ) + { + FT_Vector* vec = outline->points + outline->n_points; + FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + tag[0] = FT_CURVE_TAG_CUBIC; + tag[1] = FT_CURVE_TAG_CUBIC; + tag[2] = FT_CURVE_TAG_ON; + + outline->n_points = (FT_Short)( outline->n_points + 3 ); + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_move_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Error error; + + + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* indicate that a new contour has started */ + glyph->path_begun = 1; + + /* check that there is space for a new contour and a new point */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 ); + if ( !error ) + { + /* add new start point */ + error = pfr_glyph_line_to( glyph, to ); + } + + return error; + } + + + static void + pfr_glyph_end( PFR_Glyph glyph ) + { + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* merge the current glyph into the stack */ + FT_GlyphLoader_Add( glyph->loader ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH LOADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* load a simple glyph */ + static FT_Error + pfr_glyph_load_simple( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = glyph->loader->memory; + FT_UInt flags, x_count, y_count, i, count, mask; + FT_Int x; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( flags & PFR_GLYPH_IS_COMPOUND ) + goto Failure; + + x_count = 0; + y_count = 0; + + if ( flags & PFR_GLYPH_1BYTE_XYCOUNT ) + { + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + x_count = count & 15; + y_count = count >> 4; + } + else + { + if ( flags & PFR_GLYPH_XCOUNT ) + { + PFR_CHECK( 1 ); + x_count = PFR_NEXT_BYTE( p ); + } + + if ( flags & PFR_GLYPH_YCOUNT ) + { + PFR_CHECK( 1 ); + y_count = PFR_NEXT_BYTE( p ); + } + } + + count = x_count + y_count; + + /* re-allocate array when necessary */ + if ( count > glyph->max_xy_control ) + { + FT_UInt new_max = FT_PAD_CEIL( count, 8 ); + + + if ( FT_RENEW_ARRAY( glyph->x_control, + glyph->max_xy_control, + new_max ) ) + goto Exit; + + glyph->max_xy_control = new_max; + } + + glyph->y_control = glyph->x_control + x_count; + + mask = 0; + x = 0; + + for ( i = 0; i < count; i++ ) + { + if ( ( i & 7 ) == 0 ) + { + PFR_CHECK( 1 ); + mask = PFR_NEXT_BYTE( p ); + } + + if ( mask & 1 ) + { + PFR_CHECK( 2 ); + x = PFR_NEXT_SHORT( p ); + } + else + { + PFR_CHECK( 1 ); + x += PFR_NEXT_BYTE( p ); + } + + glyph->x_control[i] = x; + + mask >>= 1; + } + + /* XXX: we ignore the secondary stroke and edge definitions */ + /* since we don't support native PFR hinting */ + /* */ + if ( flags & PFR_GLYPH_SINGLE_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + + pfr_glyph_start( glyph ); + + /* now load a simple glyph */ + { + FT_Vector pos[4]; + FT_Vector* cur; + + + pos[0].x = pos[0].y = 0; + pos[3] = pos[0]; + + for (;;) + { + FT_UInt format, format_low, args_format = 0, args_count, n; + + + /**************************************************************** + * read instruction + */ + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + format_low = format & 15; + + switch ( format >> 4 ) + { + case 0: /* end glyph */ + FT_TRACE6(( "- end glyph" )); + args_count = 0; + break; + + case 1: /* general line operation */ + FT_TRACE6(( "- general line" )); + goto Line1; + + case 4: /* move to inside contour */ + FT_TRACE6(( "- move to inside" )); + goto Line1; + + case 5: /* move to outside contour */ + FT_TRACE6(( "- move to outside" )); + Line1: + args_format = format_low; + args_count = 1; + break; + + case 2: /* horizontal line to */ + FT_TRACE6(( "- horizontal line to cx.%d", format_low )); + if ( format_low >= x_count ) + goto Failure; + pos[0].x = glyph->x_control[format_low]; + pos[0].y = pos[3].y; + pos[3] = pos[0]; + args_count = 0; + break; + + case 3: /* vertical line to */ + FT_TRACE6(( "- vertical line to cy.%d", format_low )); + if ( format_low >= y_count ) + goto Failure; + pos[0].x = pos[3].x; + pos[0].y = glyph->y_control[format_low]; + pos[3] = pos[0]; + args_count = 0; + break; + + case 6: /* horizontal to vertical curve */ + FT_TRACE6(( "- hv curve" )); + args_format = 0xB8E; + args_count = 3; + break; + + case 7: /* vertical to horizontal curve */ + FT_TRACE6(( "- vh curve" )); + args_format = 0xE2B; + args_count = 3; + break; + + default: /* general curve to */ + FT_TRACE6(( "- general curve" )); + args_count = 4; + args_format = format_low; + } + + /************************************************************ + * now read arguments + */ + cur = pos; + for ( n = 0; n < args_count; n++ ) + { + FT_UInt idx; + FT_Int delta; + + + /* read the X argument */ + switch ( args_format & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= x_count ) + goto Failure; + cur->x = glyph->x_control[idx]; + FT_TRACE7(( " cx#%d", idx )); + break; + + case 1: /* 16-bit absolute value */ + PFR_CHECK( 2 ); + cur->x = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " x.%ld", cur->x )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->x = pos[3].x + delta; + FT_TRACE7(( " dx.%d", delta )); + break; + + default: + FT_TRACE7(( " |" )); + cur->x = pos[3].x; + } + + /* read the Y argument */ + switch ( ( args_format >> 2 ) & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= y_count ) + goto Failure; + cur->y = glyph->y_control[idx]; + FT_TRACE7(( " cy#%d", idx )); + break; + + case 1: /* 16-bit absolute value */ + PFR_CHECK( 2 ); + cur->y = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " y.%ld", cur->y )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->y = pos[3].y + delta; + FT_TRACE7(( " dy.%d", delta )); + break; + + default: + FT_TRACE7(( " -" )); + cur->y = pos[3].y; + } + + /* read the additional format flag for the general curve */ + if ( n == 0 && args_count == 4 ) + { + PFR_CHECK( 1 ); + args_format = PFR_NEXT_BYTE( p ); + args_count--; + } + else + args_format >>= 4; + + /* save the previous point */ + pos[3] = cur[0]; + cur++; + } + + FT_TRACE7(( "\n" )); + + /************************************************************ + * finally, execute instruction + */ + switch ( format >> 4 ) + { + case 0: /* end glyph => EXIT */ + pfr_glyph_end( glyph ); + goto Exit; + + case 1: /* line operations */ + case 2: + case 3: + error = pfr_glyph_line_to( glyph, pos ); + goto Test_Error; + + case 4: /* move to inside contour */ + case 5: /* move to outside contour */ + error = pfr_glyph_move_to( glyph, pos ); + goto Test_Error; + + default: /* curve operations */ + error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 ); + + Test_Error: /* test error condition */ + if ( error ) + goto Exit; + } + } /* for (;;) */ + } + + Exit: + return error; + + Failure: + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" )); + goto Exit; + } + + + /* load a composite/compound glyph */ + static FT_Error + pfr_glyph_load_compound( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = glyph->loader->memory; + PFR_SubGlyph subglyph; + FT_UInt flags, i, count, org_count; + FT_Int x_pos, y_pos; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( !( flags & PFR_GLYPH_IS_COMPOUND ) ) + goto Failure; + + count = flags & 0x3F; + + /* ignore extra items when present */ + /* */ + if ( flags & PFR_GLYPH_COMPOUND_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + + /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */ + /* the PFR format is dumb, using direct file offsets to point to the */ + /* sub-glyphs (instead of glyph indices). Sigh. */ + /* */ + /* For now, we load the list of sub-glyphs into a different array */ + /* but this will prevent us from using the auto-hinter at its best */ + /* quality. */ + /* */ + org_count = glyph->num_subs; + + if ( org_count + count > glyph->max_subs ) + { + FT_UInt new_max = ( org_count + count + 3 ) & (FT_UInt)-4; + + + /* we arbitrarily limit the number of subglyphs */ + /* to avoid endless recursion */ + if ( new_max > 64 ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_compound:" + " too many compound glyphs components\n" )); + goto Exit; + } + + if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) ) + goto Exit; + + glyph->max_subs = new_max; + } + + subglyph = glyph->subs + org_count; + + for ( i = 0; i < count; i++, subglyph++ ) + { + FT_UInt format; + + + x_pos = 0; + y_pos = 0; + + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + + /* read scale when available */ + subglyph->x_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_XSCALE ) + { + PFR_CHECK( 2 ); + subglyph->x_scale = PFR_NEXT_SHORT( p ) * 16; + } + + subglyph->y_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_YSCALE ) + { + PFR_CHECK( 2 ); + subglyph->y_scale = PFR_NEXT_SHORT( p ) * 16; + } + + /* read offset */ + switch ( format & 3 ) + { + case 1: + PFR_CHECK( 2 ); + x_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + x_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + switch ( ( format >> 2 ) & 3 ) + { + case 1: + PFR_CHECK( 2 ); + y_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + y_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + subglyph->x_delta = x_pos; + subglyph->y_delta = y_pos; + + /* read glyph position and size now */ + if ( format & PFR_SUBGLYPH_2BYTE_SIZE ) + { + PFR_CHECK( 2 ); + subglyph->gps_size = PFR_NEXT_USHORT( p ); + } + else + { + PFR_CHECK( 1 ); + subglyph->gps_size = PFR_NEXT_BYTE( p ); + } + + if ( format & PFR_SUBGLYPH_3BYTE_OFFSET ) + { + PFR_CHECK( 3 ); + subglyph->gps_offset = PFR_NEXT_ULONG( p ); + } + else + { + PFR_CHECK( 2 ); + subglyph->gps_offset = PFR_NEXT_USHORT( p ); + } + + glyph->num_subs++; + } + + Exit: + return error; + + Failure: + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_glyph_load_rec( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + FT_Error error; + FT_Byte* p; + FT_Byte* limit; + + + if ( FT_STREAM_SEEK( gps_offset + offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + limit = p + size; + + if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND ) + { + FT_UInt n, old_count, count; + FT_GlyphLoader loader = glyph->loader; + FT_Outline* base = &loader->base.outline; + + + old_count = glyph->num_subs; + + /* this is a compound glyph - load it */ + error = pfr_glyph_load_compound( glyph, p, limit ); + + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + count = glyph->num_subs - old_count; + + FT_TRACE4(( "compound glyph with %d element%s (offset %lu):\n", + count, + count == 1 ? "" : "s", + offset )); + + /* now, load each individual glyph */ + for ( n = 0; n < count; n++ ) + { + FT_Int i, old_points, num_points; + PFR_SubGlyph subglyph; + + + FT_TRACE4(( " subglyph %d:\n", n )); + + subglyph = glyph->subs + old_count + n; + old_points = base->n_points; + + error = pfr_glyph_load_rec( glyph, stream, gps_offset, + subglyph->gps_offset, + subglyph->gps_size ); + if ( error ) + break; + + /* note that `glyph->subs' might have been re-allocated */ + subglyph = glyph->subs + old_count + n; + num_points = base->n_points - old_points; + + /* translate and eventually scale the new glyph points */ + if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L ) + { + FT_Vector* vec = base->points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x = FT_MulFix( vec->x, subglyph->x_scale ) + + subglyph->x_delta; + vec->y = FT_MulFix( vec->y, subglyph->y_scale ) + + subglyph->y_delta; + } + } + else + { + FT_Vector* vec = loader->base.outline.points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x += subglyph->x_delta; + vec->y += subglyph->y_delta; + } + } + + /* proceed to next sub-glyph */ + } + + FT_TRACE4(( "end compound glyph with %d element%s\n", + count, + count == 1 ? "" : "s" )); + } + else + { + FT_TRACE4(( "simple glyph (offset %lu)\n", offset )); + + /* load a simple glyph */ + error = pfr_glyph_load_simple( glyph, p, limit ); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + /* initialize glyph loader */ + FT_GlyphLoader_Rewind( glyph->loader ); + + glyph->num_subs = 0; + + /* load the glyph, recursively when needed */ + return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size ); + } + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrgload.h b/vendor/freetype/src/pfr/pfrgload.h new file mode 100644 index 0000000..92a59bc --- /dev/null +++ b/vendor/freetype/src/pfr/pfrgload.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * pfrgload.h + * + * FreeType PFR glyph loader (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRGLOAD_H_ +#define PFRGLOAD_H_ + +#include "pfrtypes.h" + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ); + + FT_LOCAL( void ) + pfr_glyph_done( PFR_Glyph glyph ); + + + FT_LOCAL( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ); + + +FT_END_HEADER + + +#endif /* PFRGLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrload.c b/vendor/freetype/src/pfr/pfrload.c new file mode 100644 index 0000000..856a594 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrload.c @@ -0,0 +1,1062 @@ +/**************************************************************************** + * + * pfrload.c + * + * FreeType PFR loader (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrload.h" +#include +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /* + * The overall structure of a PFR file is as follows. + * + * PFR header + * 58 bytes (contains nPhysFonts) + * + * Logical font directory (size at most 2^16 bytes) + * 2 bytes (nLogFonts) + * + nLogFonts * 5 bytes + * + * ==> nLogFonts <= 13106 + * + * Logical font section (size at most 2^24 bytes) + * nLogFonts * logFontRecord + * + * logFontRecord (size at most 2^16 bytes) + * 12 bytes (fontMatrix) + * + 1 byte (flags) + * + 0-5 bytes (depending on `flags') + * + 0-(1+255*(2+255)) = 0-65536 (depending on `flags') + * + 5 bytes (physical font info) + * + 0-1 bytes (depending on PFR header) + * + * ==> minimum size 18 bytes + * + * Physical font section (size at most 2^24 bytes) + * nPhysFonts * (physFontRecord + * + nBitmapSizes * nBmapChars * bmapCharRecord) + * + * physFontRecord (size at most 2^24 bytes) + * 14 bytes (font info) + * + 1 byte (flags) + * + 0-2 (depending on `flags') + * + 0-? (structure too complicated to be shown here; depending on + * `flags'; contains `nBitmapSizes' and `nBmapChars') + * + 3 bytes (nAuxBytes) + * + nAuxBytes + * + 1 byte (nBlueValues) + * + 2 * nBlueValues + * + 6 bytes (hinting data) + * + 2 bytes (nCharacters) + * + nCharacters * (4-10 bytes) (depending on `flags') + * + * ==> minimum size 27 bytes + * + * bmapCharRecord + * 4-7 bytes + * + * Glyph program strings (three possible types: simpleGps, compoundGps, + * and bitmapGps; size at most 2^24 bytes) + * simpleGps (size at most 2^16 bytes) + * 1 byte (flags) + * 1-2 bytes (n[XY]orus, depending on `flags') + * 0-(64+512*2) = 0-1088 bytes (depending on `n[XY]orus') + * 0-? (structure too complicated to be shown here; depending on + * `flags') + * 1-? glyph data (faintly resembling PS Type 1 charstrings) + * + * ==> minimum size 3 bytes + * + * compoundGps (size at most 2^16 bytes) + * 1 byte (nElements <= 63, flags) + * + 0-(1+255*(2+255)) = 0-65536 (depending on `flags') + * + nElements * (6-14 bytes) + * + * bitmapGps (size at most 2^16 bytes) + * 1 byte (flags) + * 3-13 bytes (position info, depending on `flags') + * 0-? bitmap data + * + * ==> minimum size 4 bytes + * + * PFR trailer + * 8 bytes + * + * + * ==> minimum size of a valid PFR: + * 58 (header) + * + 2 (nLogFonts) + * + 27 (1 physFontRecord) + * + 8 (trailer) + * ----- + * 95 bytes + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** EXTRA ITEMS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ) + { + return pfr_extra_items_parse( pp, limit, NULL, NULL ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* p = *pp; + FT_UInt num_items, item_type, item_size; + + + PFR_CHECK( 1 ); + num_items = PFR_NEXT_BYTE( p ); + + for ( ; num_items > 0; num_items-- ) + { + PFR_CHECK( 2 ); + item_size = PFR_NEXT_BYTE( p ); + item_type = PFR_NEXT_BYTE( p ); + + PFR_CHECK( item_size ); + + if ( item_list ) + { + PFR_ExtraItem extra = item_list; + + + for ( extra = item_list; extra->parser != NULL; extra++ ) + { + if ( extra->type == item_type ) + { + error = extra->parser( p, p + item_size, item_data ); + if ( error ) + goto Exit; + + break; + } + } + } + + p += item_size; + } + + Exit: + *pp = p; + return error; + + Too_Short: + FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR HEADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static const FT_Frame_Field pfr_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PFR_HeaderRec + + FT_FRAME_START( 58 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_USHORT( version ), + FT_FRAME_USHORT( signature2 ), + FT_FRAME_USHORT( header_size ), + + FT_FRAME_USHORT( log_dir_size ), + FT_FRAME_USHORT( log_dir_offset ), + + FT_FRAME_USHORT( log_font_max_size ), + FT_FRAME_UOFF3 ( log_font_section_size ), + FT_FRAME_UOFF3 ( log_font_section_offset ), + + FT_FRAME_USHORT( phy_font_max_size ), + FT_FRAME_UOFF3 ( phy_font_section_size ), + FT_FRAME_UOFF3 ( phy_font_section_offset ), + + FT_FRAME_USHORT( gps_max_size ), + FT_FRAME_UOFF3 ( gps_section_size ), + FT_FRAME_UOFF3 ( gps_section_offset ), + + FT_FRAME_BYTE ( max_blue_values ), + FT_FRAME_BYTE ( max_x_orus ), + FT_FRAME_BYTE ( max_y_orus ), + + FT_FRAME_BYTE ( phy_font_max_size_high ), + FT_FRAME_BYTE ( color_flags ), + + FT_FRAME_UOFF3 ( bct_max_size ), + FT_FRAME_UOFF3 ( bct_set_max_size ), + FT_FRAME_UOFF3 ( phy_bct_set_max_size ), + + FT_FRAME_USHORT( num_phy_fonts ), + FT_FRAME_BYTE ( max_vert_stem_snap ), + FT_FRAME_BYTE ( max_horz_stem_snap ), + FT_FRAME_USHORT( max_chars ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ) + { + FT_Error error; + + + /* read header directly */ + if ( !FT_STREAM_SEEK( 0 ) && + !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) ) + { + /* make a few adjustments to the header */ + header->phy_font_max_size += + (FT_UInt32)header->phy_font_max_size_high << 16; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Bool ) + pfr_header_check( PFR_Header header ) + { + FT_Bool result = 1; + + + /* check signature and header size */ + if ( header->signature != 0x50465230L || /* "PFR0" */ + header->version > 4 || + header->header_size < 58 || + header->signature2 != 0x0D0A ) /* CR/LF */ + result = 0; + + return result; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR LOGICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 section_offset, + FT_Long *acount ) + { + FT_Error error; + FT_UInt count; + FT_UInt result = 0; + + + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( count ) ) + goto Exit; + + /* check maximum value and a rough minimum size: */ + /* - no more than 13106 log fonts */ + /* - we need 5 bytes for a log header record */ + /* - we need at least 18 bytes for a log font record */ + /* - the overall size is at least 95 bytes plus the */ + /* log header and log font records */ + if ( count > ( ( 1 << 16 ) - 2 ) / 5 || + 2 + count * 5 >= stream->size - section_offset || + 95 + count * ( 5 + 18 ) >= stream->size ) + { + FT_ERROR(( "pfr_log_font_count:" + " invalid number of logical fonts\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + result = count; + + Exit: + *acount = (FT_Long)result; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt idx, + FT_UInt32 section_offset, + FT_Bool size_increment ) + { + FT_UInt num_log_fonts; + FT_UInt flags; + FT_UInt32 offset; + FT_UInt32 size; + FT_Error error; + + + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( num_log_fonts ) ) + goto Exit; + + if ( idx >= num_log_fonts ) + return FT_THROW( Invalid_Argument ); + + if ( FT_STREAM_SKIP( idx * 5 ) || + FT_READ_USHORT( size ) || + FT_READ_UOFF3 ( offset ) ) + goto Exit; + + /* save logical font size and offset */ + log_font->size = size; + log_font->offset = offset; + + /* now, check the rest of the table before loading it */ + { + FT_Byte* p; + FT_Byte* limit; + FT_UInt local; + + + if ( FT_STREAM_SEEK( offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK( 13 ); + + log_font->matrix[0] = PFR_NEXT_LONG( p ); + log_font->matrix[1] = PFR_NEXT_LONG( p ); + log_font->matrix[2] = PFR_NEXT_LONG( p ); + log_font->matrix[3] = PFR_NEXT_LONG( p ); + + flags = PFR_NEXT_BYTE( p ); + + local = 0; + if ( flags & PFR_LOG_STROKE ) + { + local++; + if ( flags & PFR_LOG_2BYTE_STROKE ) + local++; + + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + local += 3; + } + if ( flags & PFR_LOG_BOLD ) + { + local++; + if ( flags & PFR_LOG_2BYTE_BOLD ) + local++; + } + + PFR_CHECK( local ); + + if ( flags & PFR_LOG_STROKE ) + { + log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + log_font->miter_limit = PFR_NEXT_LONG( p ); + } + + if ( flags & PFR_LOG_BOLD ) + log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + + if ( flags & PFR_LOG_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Fail; + } + + PFR_CHECK( 5 ); + log_font->phys_size = PFR_NEXT_USHORT( p ); + log_font->phys_offset = PFR_NEXT_ULONG( p ); + if ( size_increment ) + { + PFR_CHECK( 1 ); + log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16; + } + } + + Fail: + FT_FRAME_EXIT(); + + Exit: + return error; + + Too_Short: + FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" )); + error = FT_THROW( Invalid_Table ); + goto Fail; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR PHYSICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + /* load bitmap strikes lists */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_bitmap_info( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Memory memory = phy_font->memory; + PFR_Strike strike; + FT_UInt flags0; + FT_UInt n, count, size1; + FT_Error error = FT_Err_Ok; + + + PFR_CHECK( 5 ); + + p += 3; /* skip bctSize */ + flags0 = PFR_NEXT_BYTE( p ); + count = PFR_NEXT_BYTE( p ); + + /* re-allocate when needed */ + if ( phy_font->num_strikes + count > phy_font->max_strikes ) + { + FT_UInt new_max = FT_PAD_CEIL( phy_font->num_strikes + count, 4 ); + + + if ( FT_RENEW_ARRAY( phy_font->strikes, + phy_font->num_strikes, + new_max ) ) + goto Exit; + + phy_font->max_strikes = new_max; + } + + size1 = 1 + 1 + 1 + 2 + 2 + 1; + if ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + size1++; + + strike = phy_font->strikes + phy_font->num_strikes; + + PFR_CHECK( count * size1 ); + + for ( n = 0; n < count; n++, strike++ ) + { + strike->x_ppm = ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->y_ppm = ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->flags = PFR_NEXT_BYTE( p ); + + strike->bct_size = ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->bct_offset = ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + } + + phy_font->num_strikes += count; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_bitmap_info:" + " invalid bitmap info table\n" )); + goto Exit; + } + + + /* Load font ID. This is a so-called `unique' name that is rather + * long and descriptive (like `Tiresias ScreenFont v7.51'). + * + * Note that a PFR font's family name is contained in an *undocumented* + * string of the `auxiliary data' portion of a physical font record. This + * may also contain the `real' style name! + * + * If no family name is present, the font ID is used instead for the + * family. + */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_font_id( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + FT_UInt len = (FT_UInt)( limit - p ); + + + if ( phy_font->font_id ) + goto Exit; + + if ( FT_QALLOC( phy_font->font_id, len + 1 ) ) + goto Exit; + + /* copy font ID name, and terminate it for safety */ + FT_MEM_COPY( phy_font->font_id, p, len ); + phy_font->font_id[len] = 0; + + Exit: + return error; + } + + + /* load stem snap tables */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_stem_snaps( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_UInt count, num_vert, num_horz; + FT_Int* snaps = NULL; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + + + if ( phy_font->vertical.stem_snaps ) + goto Exit; + + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + + num_vert = count & 15; + num_horz = count >> 4; + count = num_vert + num_horz; + + PFR_CHECK( count * 2 ); + + if ( FT_QNEW_ARRAY( snaps, count ) ) + goto Exit; + + phy_font->vertical.stem_snaps = snaps; + phy_font->horizontal.stem_snaps = snaps + num_vert; + + for ( ; count > 0; count--, snaps++ ) + *snaps = FT_NEXT_SHORT( p ); + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_stem_snaps:" + " invalid stem snaps table\n" )); + goto Exit; + } + + + /* load kerning pair data */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_kerning_pairs( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + PFR_KernItem item = NULL; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + + + if ( FT_NEW( item ) ) + goto Exit; + + PFR_CHECK( 4 ); + + item->pair_count = PFR_NEXT_BYTE( p ); + item->base_adj = PFR_NEXT_SHORT( p ); + item->flags = PFR_NEXT_BYTE( p ); + item->offset = phy_font->offset + + (FT_Offset)( p - phy_font->cursor ); + +#ifndef PFR_CONFIG_NO_CHECKS + item->pair_size = 3; + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + item->pair_size += 2; + + if ( item->flags & PFR_KERN_2BYTE_ADJ ) + item->pair_size += 1; + + PFR_CHECK( item->pair_count * item->pair_size ); +#endif + + /* load first and last pairs into the item to speed up */ + /* lookup later... */ + if ( item->pair_count > 0 ) + { + FT_UInt char1, char2; + FT_Byte* q; + + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + { + q = p; + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + else + { + q = p; + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + + /* add new item to the current list */ + item->next = NULL; + *phy_font->kern_items_tail = item; + phy_font->kern_items_tail = &item->next; + phy_font->num_kern_pairs += item->pair_count; + } + else + { + /* empty item! */ + FT_FREE( item ); + } + + Exit: + return error; + + Too_Short: + FT_FREE( item ); + + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_kerning_pairs:" + " invalid kerning pairs table\n" )); + goto Exit; + } + + + static const PFR_ExtraItemRec pfr_phy_font_extra_items[] = + { + { 1, pfr_extra_item_load_bitmap_info }, + { 2, pfr_extra_item_load_font_id }, + { 3, pfr_extra_item_load_stem_snaps }, + { 4, pfr_extra_item_load_kerning_pairs }, + { 0, NULL } + }; + + + /* + * Load a name from the auxiliary data. Since this extracts undocumented + * strings from the font file, we need to be careful here. + */ + static FT_Error + pfr_aux_name_load( FT_Byte* p, + FT_UInt len, + FT_Memory memory, + FT_String* *astring ) + { + FT_Error error = FT_Err_Ok; + FT_String* result = NULL; + FT_UInt n, ok; + + + if ( *astring ) + FT_FREE( *astring ); + + if ( len > 0 && p[len - 1] == 0 ) + len--; + + /* check that each character is ASCII */ + /* for making sure not to load garbage */ + ok = ( len > 0 ); + for ( n = 0; n < len; n++ ) + if ( p[n] < 32 || p[n] > 127 ) + { + ok = 0; + break; + } + + if ( ok ) + { + if ( FT_QALLOC( result, len + 1 ) ) + goto Exit; + + FT_MEM_COPY( result, p, len ); + result[len] = 0; + } + + Exit: + *astring = result; + return error; + } + + + FT_LOCAL_DEF( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ) + { + FT_FREE( phy_font->font_id ); + FT_FREE( phy_font->family_name ); + FT_FREE( phy_font->style_name ); + + FT_FREE( phy_font->vertical.stem_snaps ); + phy_font->vertical.num_stem_snaps = 0; + + phy_font->horizontal.stem_snaps = NULL; + phy_font->horizontal.num_stem_snaps = 0; + + FT_FREE( phy_font->strikes ); + phy_font->num_strikes = 0; + phy_font->max_strikes = 0; + + FT_FREE( phy_font->chars ); + phy_font->num_chars = 0; + phy_font->chars_offset = 0; + + FT_FREE( phy_font->blue_values ); + phy_font->num_blue_values = 0; + + { + PFR_KernItem item, next; + + + item = phy_font->kern_items; + while ( item ) + { + next = item->next; + FT_FREE( item ); + item = next; + } + phy_font->kern_items = NULL; + phy_font->kern_items_tail = NULL; + } + + phy_font->num_kern_pairs = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt flags; + FT_ULong num_aux; + FT_Byte* p; + FT_Byte* limit; + + + phy_font->memory = memory; + phy_font->offset = offset; + + phy_font->kern_items = NULL; + phy_font->kern_items_tail = &phy_font->kern_items; + + if ( FT_STREAM_SEEK( offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + phy_font->cursor = stream->cursor; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK( 15 ); + phy_font->font_ref_number = PFR_NEXT_USHORT( p ); + phy_font->outline_resolution = PFR_NEXT_USHORT( p ); + phy_font->metrics_resolution = PFR_NEXT_USHORT( p ); + phy_font->bbox.xMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.xMax = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); + phy_font->flags = flags = PFR_NEXT_BYTE( p ); + + if ( !phy_font->outline_resolution || + !phy_font->metrics_resolution ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: invalid resolution\n" )); + goto Fail; + } + + /* get the standard advance for non-proportional fonts */ + if ( !( flags & PFR_PHY_PROPORTIONAL ) ) + { + PFR_CHECK( 2 ); + phy_font->standard_advance = PFR_NEXT_SHORT( p ); + } + + /* load the extra items when present */ + if ( flags & PFR_PHY_EXTRA_ITEMS ) + { + error = pfr_extra_items_parse( &p, limit, + pfr_phy_font_extra_items, phy_font ); + if ( error ) + goto Fail; + } + + /* In certain fonts, the auxiliary bytes contain interesting */ + /* information. These are not in the specification but can be */ + /* guessed by looking at the content of a few 'PFR0' fonts. */ + PFR_CHECK( 3 ); + num_aux = PFR_NEXT_ULONG( p ); + + if ( num_aux > 0 ) + { + FT_Byte* q = p; + FT_Byte* q2; + + + PFR_CHECK_SIZE( num_aux ); + p += num_aux; + + while ( num_aux > 0 ) + { + FT_UInt length, type; + + + if ( q + 4 > p ) + break; + + length = PFR_NEXT_USHORT( q ); + if ( length < 4 || length > num_aux ) + break; + + q2 = q + length - 2; + type = PFR_NEXT_USHORT( q ); + + switch ( type ) + { + case 1: + /* this seems to correspond to the font's family name, padded to */ + /* an even number of bytes with a zero byte appended if needed */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->family_name ); + if ( error ) + goto Exit; + break; + + case 2: + if ( q + 32 > q2 ) + break; + + q += 10; + phy_font->ascent = PFR_NEXT_SHORT( q ); + phy_font->descent = PFR_NEXT_SHORT( q ); + phy_font->leading = PFR_NEXT_SHORT( q ); + break; + + case 3: + /* this seems to correspond to the font's style name, padded to */ + /* an even number of bytes with a zero byte appended if needed */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->style_name ); + if ( error ) + goto Exit; + break; + + default: + ; + } + + q = q2; + num_aux -= length; + } + } + + /* read the blue values */ + { + FT_UInt n, count; + + + PFR_CHECK( 1 ); + phy_font->num_blue_values = count = PFR_NEXT_BYTE( p ); + + PFR_CHECK( count * 2 ); + + if ( FT_QNEW_ARRAY( phy_font->blue_values, count ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + phy_font->blue_values[n] = PFR_NEXT_SHORT( p ); + } + + PFR_CHECK( 8 ); + phy_font->blue_fuzz = PFR_NEXT_BYTE( p ); + phy_font->blue_scale = PFR_NEXT_BYTE( p ); + + phy_font->vertical.standard = PFR_NEXT_USHORT( p ); + phy_font->horizontal.standard = PFR_NEXT_USHORT( p ); + + /* read the character descriptors */ + { + FT_UInt n, count, Size; + + + phy_font->num_chars = count = PFR_NEXT_USHORT( p ); + phy_font->chars_offset = offset + (FT_Offset)( p - stream->cursor ); + + if ( !phy_font->num_chars ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: no glyphs\n" )); + goto Fail; + } + + Size = 1 + 1 + 2; + if ( flags & PFR_PHY_2BYTE_CHARCODE ) + Size += 1; + + if ( flags & PFR_PHY_PROPORTIONAL ) + Size += 2; + + if ( flags & PFR_PHY_ASCII_CODE ) + Size += 1; + + if ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + Size += 1; + + if ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + Size += 1; + + PFR_CHECK_SIZE( count * Size ); + + if ( FT_QNEW_ARRAY( phy_font->chars, count ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + PFR_Char cur = &phy_font->chars[n]; + + + cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->advance = ( flags & PFR_PHY_PROPORTIONAL ) + ? PFR_NEXT_SHORT( p ) + : phy_font->standard_advance; + +#if 0 + cur->ascii = ( flags & PFR_PHY_ASCII_CODE ) + ? PFR_NEXT_BYTE( p ) + : 0; +#else + if ( flags & PFR_PHY_ASCII_CODE ) + p += 1; +#endif + cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + } + } + + /* that's it! */ + + Fail: + FT_FRAME_EXIT(); + + /* save position of bitmap info */ + phy_font->bct_offset = FT_STREAM_POS(); + phy_font->cursor = NULL; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" )); + goto Fail; + } + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrload.h b/vendor/freetype/src/pfr/pfrload.h new file mode 100644 index 0000000..d7b20a4 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrload.h @@ -0,0 +1,123 @@ +/**************************************************************************** + * + * pfrload.h + * + * FreeType PFR loader (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRLOAD_H_ +#define PFRLOAD_H_ + +#include "pfrobjs.h" +#include + + +FT_BEGIN_HEADER + + /* some size checks should be always done (mainly to prevent */ + /* excessive allocation for malformed data), ... */ +#define PFR_CHECK_SIZE( x ) do \ + { \ + if ( p + (x) > limit ) \ + goto Too_Short; \ + } while ( 0 ) + + /* ... and some only if intensive checking is explicitly requested */ +#ifdef PFR_CONFIG_NO_CHECKS +#define PFR_CHECK( x ) do { } while ( 0 ) +#else +#define PFR_CHECK PFR_CHECK_SIZE +#endif + +#define PFR_NEXT_BYTE( p ) FT_NEXT_BYTE( p ) +#define PFR_NEXT_INT8( p ) FT_NEXT_CHAR( p ) +#define PFR_NEXT_SHORT( p ) FT_NEXT_SHORT( p ) +#define PFR_NEXT_USHORT( p ) FT_NEXT_USHORT( p ) +#define PFR_NEXT_LONG( p ) FT_NEXT_OFF3( p ) +#define PFR_NEXT_ULONG( p ) FT_NEXT_UOFF3( p ) + + + /* handling extra items */ + + typedef FT_Error + (*PFR_ExtraItem_ParseFunc)( FT_Byte* p, + FT_Byte* limit, + FT_Pointer data ); + + typedef struct PFR_ExtraItemRec_ + { + FT_UInt type; + PFR_ExtraItem_ParseFunc parser; + + } PFR_ExtraItemRec; + + typedef const struct PFR_ExtraItemRec_* PFR_ExtraItem; + + + FT_LOCAL( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ); + + FT_LOCAL( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ); + + + /* load a PFR header */ + FT_LOCAL( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ); + + /* check a PFR header */ + FT_LOCAL( FT_Bool ) + pfr_header_check( PFR_Header header ); + + + /* return number of logical fonts in this file */ + FT_LOCAL( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 log_section_offset, + FT_Long *acount ); + + /* load a pfr logical font entry */ + FT_LOCAL( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt face_index, + FT_UInt32 section_offset, + FT_Bool size_increment ); + + + /* load a physical font entry */ + FT_LOCAL( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ); + + /* finalize a physical font */ + FT_LOCAL( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ); + + /* */ + +FT_END_HEADER + +#endif /* PFRLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrobjs.c b/vendor/freetype/src/pfr/pfrobjs.c new file mode 100644 index 0000000..8ef17c6 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrobjs.c @@ -0,0 +1,603 @@ +/**************************************************************************** + * + * pfrobjs.c + * + * FreeType PFR object methods (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrobjs.h" +#include "pfrload.h" +#include "pfrgload.h" +#include "pfrcmap.h" +#include "pfrsbit.h" +#include +#include +#include +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE OBJECT METHODS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + pfr_face_done( FT_Face pfrface ) /* PFR_Face */ + { + PFR_Face face = (PFR_Face)pfrface; + FT_Memory memory; + + + if ( !face ) + return; + + memory = pfrface->memory; + + /* we don't want dangling pointers */ + pfrface->family_name = NULL; + pfrface->style_name = NULL; + + /* finalize the physical font record */ + pfr_phy_font_done( &face->phy_font, memory ); + + /* no need to finalize the logical font or the header */ + FT_FREE( pfrface->available_sizes ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face pfrface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "PFR driver\n" )); + + /* load the header and check it */ + error = pfr_header_load( &face->header, stream ); + if ( error ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( !pfr_header_check( &face->header ) ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* check face index */ + { + FT_Long num_faces; + + + error = pfr_log_font_count( stream, + face->header.log_dir_offset, + &num_faces ); + if ( error ) + goto Exit; + + pfrface->num_faces = num_faces; + } + + if ( face_index < 0 ) + goto Exit; + + if ( ( face_index & 0xFFFF ) >= pfrface->num_faces ) + { + FT_ERROR(( "pfr_face_init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* load the face */ + error = pfr_log_font_load( + &face->log_font, + stream, + (FT_UInt)( face_index & 0xFFFF ), + face->header.log_dir_offset, + FT_BOOL( face->header.phy_font_max_size_high ) ); + if ( error ) + goto Exit; + + /* load the physical font descriptor */ + error = pfr_phy_font_load( &face->phy_font, stream, + face->log_font.phys_offset, + face->log_font.phys_size ); + if ( error ) + goto Exit; + + /* set up all root face fields */ + { + PFR_PhyFont phy_font = &face->phy_font; + + + pfrface->face_index = face_index & 0xFFFF; + pfrface->num_glyphs = (FT_Long)phy_font->num_chars + 1; + + pfrface->face_flags |= FT_FACE_FLAG_SCALABLE; + + /* if gps_offset == 0 for all characters, we */ + /* assume that the font only contains bitmaps */ + { + FT_UInt nn; + + + for ( nn = 0; nn < phy_font->num_chars; nn++ ) + if ( phy_font->chars[nn].gps_offset != 0 ) + break; + + if ( nn == phy_font->num_chars ) + { + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + else + { + FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + } + + if ( !( phy_font->flags & PFR_PHY_PROPORTIONAL ) ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( phy_font->flags & PFR_PHY_VERTICAL ) + pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; + else + pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + + if ( phy_font->num_kern_pairs > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + + /* If no family name was found in the `undocumented' auxiliary + * data, use the font ID instead. This sucks but is better than + * nothing. + */ + pfrface->family_name = phy_font->family_name; + if ( !pfrface->family_name ) + pfrface->family_name = phy_font->font_id; + + /* note that the style name can be NULL in certain PFR fonts, + * probably meaning `Regular' + */ + pfrface->style_name = phy_font->style_name; + + pfrface->num_fixed_sizes = 0; + pfrface->available_sizes = NULL; + + pfrface->bbox = phy_font->bbox; + pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; + pfrface->ascender = (FT_Short) phy_font->bbox.yMax; + pfrface->descender = (FT_Short) phy_font->bbox.yMin; + + pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); + if ( pfrface->height < pfrface->ascender - pfrface->descender ) + pfrface->height = (FT_Short)( pfrface->ascender - pfrface->descender ); + + if ( phy_font->num_strikes > 0 ) + { + FT_UInt n, count = phy_font->num_strikes; + FT_Bitmap_Size* size; + PFR_Strike strike; + FT_Memory memory = pfrface->memory; + + + if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) ) + goto Exit; + + size = pfrface->available_sizes; + strike = phy_font->strikes; + for ( n = 0; n < count; n++, size++, strike++ ) + { + size->height = (FT_Short)strike->y_ppm; + size->width = (FT_Short)strike->x_ppm; + size->size = (FT_Pos)( strike->y_ppm << 6 ); + size->x_ppem = (FT_Pos)( strike->x_ppm << 6 ); + size->y_ppem = (FT_Pos)( strike->y_ppm << 6 ); + } + pfrface->num_fixed_sizes = (FT_Int)count; + } + + /* now compute maximum advance width */ + if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) + pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; + else + { + FT_Int max = 0; + FT_UInt count = phy_font->num_chars; + PFR_Char gchar = phy_font->chars; + + + for ( ; count > 0; count--, gchar++ ) + { + if ( max < gchar->advance ) + max = gchar->advance; + } + + pfrface->max_advance_width = (FT_Short)max; + } + + pfrface->max_advance_height = pfrface->height; + + pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); + pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); + + /* create charmap */ + { + FT_CharMapRec charmap; + + + charmap.face = pfrface; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + + error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); + } + + /* check whether we have loaded any kerning pairs */ + if ( phy_font->num_kern_pairs ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SLOT OBJECT METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + FT_GlyphLoader loader = pfrslot->internal->loader; + + + pfr_glyph_init( &slot->glyph, loader ); + + return 0; + } + + + FT_LOCAL_DEF( void ) + pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + + + pfr_glyph_done( &slot->glyph ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ + FT_Size pfrsize, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ) + { + PFR_Slot slot = (PFR_Slot)pfrslot; + PFR_Size size = (PFR_Size)pfrsize; + FT_Error error; + PFR_Face face = (PFR_Face)pfrslot->face; + PFR_Char gchar; + FT_Outline* outline = &pfrslot->outline; + FT_ULong gps_offset; + + + FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex )); + + if ( gindex > 0 ) + gindex--; + + if ( !face || gindex >= face->phy_font.num_chars ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* try to load an embedded bitmap */ + if ( !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) ) + { + error = pfr_slot_load_bitmap( + slot, + size, + gindex, + ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); + if ( !error ) + goto Exit; + } + + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + gchar = face->phy_font.chars + gindex; + pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; + outline->n_points = 0; + outline->n_contours = 0; + gps_offset = face->header.gps_section_offset; + + /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ + error = pfr_glyph_load( &slot->glyph, face->root.stream, + gps_offset, gchar->gps_offset, gchar->gps_size ); + + if ( !error ) + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &pfrslot->metrics; + FT_Pos advance; + FT_UInt em_metrics, em_outline; + FT_Bool scaling; + + + scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); + + /* copy outline data */ + *outline = slot->glyph.loader->base.outline; + + outline->flags &= ~FT_OUTLINE_OWNER; + outline->flags |= FT_OUTLINE_REVERSE_FILL; + + if ( pfrsize->metrics.y_ppem < 24 ) + outline->flags |= FT_OUTLINE_HIGH_PRECISION; + + /* compute the advance vector */ + metrics->horiAdvance = 0; + metrics->vertAdvance = 0; + + advance = gchar->advance; + em_metrics = face->phy_font.metrics_resolution; + em_outline = face->phy_font.outline_resolution; + + if ( em_metrics != em_outline ) + advance = FT_MulDiv( advance, + (FT_Long)em_outline, + (FT_Long)em_metrics ); + + if ( face->phy_font.flags & PFR_PHY_VERTICAL ) + metrics->vertAdvance = advance; + else + metrics->horiAdvance = advance; + + pfrslot->linearHoriAdvance = metrics->horiAdvance; + pfrslot->linearVertAdvance = metrics->vertAdvance; + + /* make up vertical metrics(?) */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + +#if 0 /* some fonts seem to be broken here! */ + + /* Apply the font matrix, if any. */ + /* TODO: Test existing fonts with unusual matrix */ + /* whether we have to adjust Units per EM. */ + { + FT_Matrix font_matrix; + + + font_matrix.xx = face->log_font.matrix[0] << 8; + font_matrix.yx = face->log_font.matrix[1] << 8; + font_matrix.xy = face->log_font.matrix[2] << 8; + font_matrix.yy = face->log_font.matrix[3] << 8; + + FT_Outline_Transform( outline, &font_matrix ); + } +#endif + + /* scale when needed */ + if ( scaling ) + { + FT_Int n; + FT_Fixed x_scale = pfrsize->metrics.x_scale; + FT_Fixed y_scale = pfrsize->metrics.y_scale; + FT_Vector* vec = outline->points; + + + /* scale outline points */ + for ( n = 0; n < outline->n_points; n++, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* scale the advance */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the rest of the metrics */ + FT_Outline_Get_CBox( outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax - metrics->height; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** KERNING METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error = FT_Err_Ok; + PFR_PhyFont phy_font = &face->phy_font; + FT_UInt32 code1, code2, pair; + + + kerning->x = 0; + kerning->y = 0; + + /* PFR indexing skips .notdef, which becomes UINT_MAX */ + glyph1--; + glyph2--; + + /* check the array bounds, .notdef is automatically out */ + if ( glyph1 >= phy_font->num_chars || + glyph2 >= phy_font->num_chars ) + goto Exit; + + /* convert glyph indices to character codes */ + code1 = phy_font->chars[glyph1].char_code; + code2 = phy_font->chars[glyph2].char_code; + pair = PFR_KERN_INDEX( code1, code2 ); + + /* now search the list of kerning items */ + { + PFR_KernItem item = phy_font->kern_items; + FT_Stream stream = pfrface->stream; + + + for ( ; item; item = item->next ) + { + if ( pair >= item->pair1 && pair <= item->pair2 ) + goto FoundPair; + } + goto Exit; + + FoundPair: /* we found an item, now parse it and find the value if any */ + if ( FT_STREAM_SEEK( item->offset ) || + FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) + goto Exit; + + { + FT_UInt count = item->pair_count; + FT_UInt size = item->pair_size; + FT_UInt power = 1 << FT_MSB( count ); + FT_UInt probe = power * size; + FT_UInt extra = count - power; + FT_Byte* base = stream->cursor; + FT_Bool twobytes = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR ); + FT_Bool twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ ); + FT_Byte* p; + FT_UInt32 cpair; + + + if ( extra > 0 ) + { + p = base + extra * size; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + { + if ( twobyte_adj ) + p += 2; + else + p++; + base = p; + } + } + + while ( probe > size ) + { + probe >>= 1; + p = base + probe; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + base += probe; + } + + p = base; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + { + FT_Int value; + + + Found: + if ( twobyte_adj ) + value = FT_PEEK_SHORT( p ); + else + value = p[0]; + + kerning->x = item->base_adj + value; + } + } + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrobjs.h b/vendor/freetype/src/pfr/pfrobjs.h new file mode 100644 index 0000000..fcf8c38 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrobjs.h @@ -0,0 +1,96 @@ +/**************************************************************************** + * + * pfrobjs.h + * + * FreeType PFR object methods (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFROBJS_H_ +#define PFROBJS_H_ + +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_FaceRec_* PFR_Face; + + typedef struct PFR_SizeRec_* PFR_Size; + + typedef struct PFR_SlotRec_* PFR_Slot; + + + typedef struct PFR_FaceRec_ + { + FT_FaceRec root; + PFR_HeaderRec header; + PFR_LogFontRec log_font; + PFR_PhyFontRec phy_font; + + } PFR_FaceRec; + + + typedef struct PFR_SizeRec_ + { + FT_SizeRec root; + + } PFR_SizeRec; + + + typedef struct PFR_SlotRec_ + { + FT_GlyphSlotRec root; + PFR_GlyphRec glyph; + + } PFR_SlotRec; + + + FT_LOCAL( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face face, /* PFR_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + pfr_face_done( FT_Face face ); /* PFR_Face */ + + + FT_LOCAL( FT_Error ) + pfr_face_get_kerning( FT_Face face, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + + FT_LOCAL( FT_Error ) + pfr_slot_init( FT_GlyphSlot slot ); /* PFR_Slot */ + + FT_LOCAL( void ) + pfr_slot_done( FT_GlyphSlot slot ); /* PFR_Slot */ + + + FT_LOCAL( FT_Error ) + pfr_slot_load( FT_GlyphSlot slot, /* PFR_Slot */ + FT_Size size, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* PFROBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrsbit.c b/vendor/freetype/src/pfr/pfrsbit.c new file mode 100644 index 0000000..46a988e --- /dev/null +++ b/vendor/freetype/src/pfr/pfrsbit.c @@ -0,0 +1,813 @@ +/**************************************************************************** + * + * pfrsbit.c + * + * FreeType PFR bitmap loader (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrsbit.h" +#include "pfrload.h" +#include +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR BIT WRITER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PFR_BitWriter_ + { + FT_Byte* line; /* current line start */ + FT_Int pitch; /* line size in bytes */ + FT_UInt width; /* width in pixels/bits */ + FT_UInt rows; /* number of remaining rows to scan */ + FT_UInt total; /* total number of bits to draw */ + + } PFR_BitWriterRec, *PFR_BitWriter; + + + static void + pfr_bitwriter_init( PFR_BitWriter writer, + FT_Bitmap* target, + FT_Bool decreasing ) + { + writer->line = target->buffer; + writer->pitch = target->pitch; + writer->width = target->width; + writer->rows = target->rows; + writer->total = writer->width * writer->rows; + + if ( !decreasing ) + { + writer->line += writer->pitch * (FT_Int)( target->rows - 1 ); + writer->pitch = -writer->pitch; + } + } + + + static void + pfr_bitwriter_decode_bytes( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt val = 0; + FT_UInt c = 0; + + + n = (FT_UInt)( limit - p ) * 8; + if ( n > writer->total ) + n = writer->total; + + reload = n & 7; + + for ( ; n > 0; n-- ) + { + if ( ( n & 7 ) == reload ) + val = *p++; + + if ( val & 0x80 ) + c |= mask; + + val <<= 1; + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur++; + } + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte)c; + } + + + static void + pfr_bitwriter_decode_rle1( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int phase, count, counts[2]; + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + counts[0] = 0; + counts[1] = 0; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( phase ) + { + FT_Int v; + + + if ( p >= limit ) + break; + + v = *p++; + counts[0] = v >> 4; + counts[1] = v & 15; + phase = 0; + count = counts[0]; + } + else + { + phase = 1; + count = counts[1]; + } + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + static void + pfr_bitwriter_decode_rle2( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int phase, count; + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( p >= limit ) + break; + + count = *p++; + phase = phase ^ 1; + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + left = writer->width; + + writer->line += writer->pitch; + cur = writer->line; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + cur++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP DATA DECODING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + pfr_lookup_bitmap_data( FT_Byte* base, + FT_Byte* limit, + FT_UInt count, + FT_UInt* flags, + FT_UInt char_code, + FT_ULong* found_offset, + FT_ULong* found_size ) + { + FT_UInt min, max, mid, char_len; + FT_Bool two = FT_BOOL( *flags & PFR_BITMAP_2BYTE_CHARCODE ); + FT_Byte* buff; + + + char_len = 4; + if ( two ) + char_len += 1; + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) + char_len += 1; + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) + char_len += 1; + + if ( !( *flags & PFR_BITMAP_CHARCODES_VALIDATED ) ) + { + FT_Byte* p; + FT_Byte* lim; + FT_UInt code; + FT_Long prev_code; + + + *flags |= PFR_BITMAP_VALID_CHARCODES; + prev_code = -1; + lim = base + count * char_len; + + if ( lim > limit ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " number of bitmap records too large,\n" )); + FT_TRACE0(( " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + } + else + { + /* check whether records are sorted by code */ + for ( p = base; p < lim; p += char_len ) + { + if ( two ) + code = FT_PEEK_USHORT( p ); + else + code = *p; + + if ( (FT_Long)code <= prev_code ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " bitmap records are not sorted,\n" )); + FT_TRACE0(( " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + break; + } + + prev_code = code; + } + } + + *flags |= PFR_BITMAP_CHARCODES_VALIDATED; + } + + /* ignore bitmaps in case table is not valid */ + /* (this might be sanitized, but PFR is dead...) */ + if ( !( *flags & PFR_BITMAP_VALID_CHARCODES ) ) + goto Fail; + + min = 0; + max = count; + mid = min + ( max - min ) / 2; + + /* binary search */ + while ( min < max ) + { + FT_UInt code; + + + buff = base + mid * char_len; + + if ( two ) + code = PFR_NEXT_USHORT( buff ); + else + code = PFR_NEXT_BYTE( buff ); + + if ( char_code < code ) + max = mid; + else if ( char_code > code ) + min = mid + 1; + else + goto Found_It; + + /* reasonable prediction in a continuous block */ + mid += char_code - code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + Fail: + /* Not found */ + *found_size = 0; + *found_offset = 0; + return; + + Found_It: + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) + *found_size = PFR_NEXT_USHORT( buff ); + else + *found_size = PFR_NEXT_BYTE( buff ); + + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) + *found_offset = PFR_NEXT_ULONG( buff ); + else + *found_offset = PFR_NEXT_USHORT( buff ); + } + + + /* load bitmap metrics. `*aadvance' must be set to the default value */ + /* before calling this function */ + /* */ + static FT_Error + pfr_load_bitmap_metrics( FT_Byte** pdata, + FT_Byte* limit, + FT_Long scaled_advance, + FT_Long *axpos, + FT_Long *aypos, + FT_UInt *axsize, + FT_UInt *aysize, + FT_Long *aadvance, + FT_UInt *aformat ) + { + FT_Error error = FT_Err_Ok; + FT_Byte flags; + FT_Byte b; + FT_Byte* p = *pdata; + FT_Long xpos, ypos, advance; + FT_UInt xsize, ysize; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + xpos = 0; + ypos = 0; + xsize = 0; + ysize = 0; + advance = 0; + + switch ( flags & 3 ) + { + case 0: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xpos = (FT_Char)b >> 4; + ypos = ( (FT_Char)( b << 4 ) ) >> 4; + break; + + case 1: + PFR_CHECK( 2 ); + xpos = PFR_NEXT_INT8( p ); + ypos = PFR_NEXT_INT8( p ); + break; + + case 2: + PFR_CHECK( 4 ); + xpos = PFR_NEXT_SHORT( p ); + ypos = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 6 ); + xpos = PFR_NEXT_LONG( p ); + ypos = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + /* blank image */ + xsize = 0; + ysize = 0; + break; + + case 1: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xsize = ( b >> 4 ) & 0xF; + ysize = b & 0xF; + break; + + case 2: + PFR_CHECK( 2 ); + xsize = PFR_NEXT_BYTE( p ); + ysize = PFR_NEXT_BYTE( p ); + break; + + case 3: + PFR_CHECK( 4 ); + xsize = PFR_NEXT_USHORT( p ); + ysize = PFR_NEXT_USHORT( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + advance = scaled_advance; + break; + + case 1: + PFR_CHECK( 1 ); + advance = PFR_NEXT_INT8( p ) * 256; + break; + + case 2: + PFR_CHECK( 2 ); + advance = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 3 ); + advance = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + *axpos = xpos; + *aypos = ypos; + *axsize = xsize; + *aysize = ysize; + *aadvance = advance; + *aformat = flags >> 2; + *pdata = p; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_load_bitmap_bits( FT_Byte* p, + FT_Byte* limit, + FT_UInt format, + FT_Bool decreasing, + FT_Bitmap* target ) + { + FT_Error error = FT_Err_Ok; + PFR_BitWriterRec writer; + + + if ( target->rows > 0 && target->width > 0 ) + { + pfr_bitwriter_init( &writer, target, decreasing ); + + switch ( format ) + { + case 0: /* packed bits */ + pfr_bitwriter_decode_bytes( &writer, p, limit ); + break; + + case 1: /* RLE1 */ + pfr_bitwriter_decode_rle1( &writer, p, limit ); + break; + + case 2: /* RLE2 */ + pfr_bitwriter_decode_rle2( &writer, p, limit ); + break; + + default: + ; + } + } + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP LOADING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index, + FT_Bool metrics_only ) + { + FT_Error error; + PFR_Face face = (PFR_Face) glyph->root.face; + FT_Stream stream = face->root.stream; + PFR_PhyFont phys = &face->phy_font; + FT_ULong gps_offset; + FT_ULong gps_size; + PFR_Char character; + PFR_Strike strike; + + + character = &phys->chars[glyph_index]; + + /* look up a bitmap strike corresponding to the current */ + /* character dimensions */ + { + FT_UInt n; + + + strike = phys->strikes; + for ( n = 0; n < phys->num_strikes; n++ ) + { + if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem && + strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem ) + goto Found_Strike; + + strike++; + } + + /* couldn't find it */ + return FT_THROW( Invalid_Argument ); + } + + Found_Strike: + + /* now look up the glyph's position within the file */ + { + FT_UInt char_len; + + + char_len = 4; + if ( strike->flags & PFR_BITMAP_2BYTE_CHARCODE ) + char_len += 1; + if ( strike->flags & PFR_BITMAP_2BYTE_SIZE ) + char_len += 1; + if ( strike->flags & PFR_BITMAP_3BYTE_OFFSET ) + char_len += 1; + + /* access data directly in the frame to speed up lookups */ + if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) || + FT_FRAME_ENTER( char_len * strike->num_bitmaps ) ) + goto Exit; + + pfr_lookup_bitmap_data( stream->cursor, + stream->limit, + strike->num_bitmaps, + &strike->flags, + character->char_code, + &gps_offset, + &gps_size ); + + FT_FRAME_EXIT(); + + if ( gps_size == 0 ) + { + /* could not find a bitmap program string for this glyph */ + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + /* get the bitmap metrics */ + { + FT_Long xpos = 0, ypos = 0, advance = 0; + FT_UInt xsize = 0, ysize = 0, format = 0; + FT_Byte* p; + + + /* compute linear advance */ + advance = character->advance; + if ( phys->metrics_resolution != phys->outline_resolution ) + advance = FT_MulDiv( advance, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + + glyph->root.linearHoriAdvance = advance; + + /* compute default advance, i.e., scaled advance; this can be */ + /* overridden in the bitmap header of certain glyphs */ + advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8, + character->advance, + (FT_Long)phys->metrics_resolution ); + + if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) || + FT_FRAME_ENTER( gps_size ) ) + goto Exit; + + p = stream->cursor; + error = pfr_load_bitmap_metrics( &p, stream->limit, + advance, + &xpos, &ypos, + &xsize, &ysize, + &advance, &format ); + if ( error ) + goto Exit1; + + /* + * Before allocating the target bitmap, we check whether the given + * bitmap dimensions are valid, depending on the image format. + * + * Format 0: We have a stream of pixels (with 8 pixels per byte). + * + * (xsize * ysize + 7) / 8 <= gps_size + * + * Format 1: Run-length encoding; the high nibble holds the number of + * white bits, the low nibble the number of black bits. In + * other words, a single byte can represent at most 15 + * pixels. + * + * xsize * ysize <= 15 * gps_size + * + * Format 2: Run-length encoding; the high byte holds the number of + * white bits, the low byte the number of black bits. In + * other words, two bytes can represent at most 255 pixels. + * + * xsize * ysize <= 255 * (gps_size + 1) / 2 + */ + switch ( format ) + { + case 0: + if ( ( (FT_ULong)xsize * ysize + 7 ) / 8 > gps_size ) + error = FT_THROW( Invalid_Table ); + break; + case 1: + if ( (FT_ULong)xsize * ysize > 15 * gps_size ) + error = FT_THROW( Invalid_Table ); + break; + case 2: + if ( (FT_ULong)xsize * ysize > 255 * ( ( gps_size + 1 ) / 2 ) ) + error = FT_THROW( Invalid_Table ); + break; + default: + FT_ERROR(( "pfr_slot_load_bitmap: invalid image type\n" )); + error = FT_THROW( Invalid_Table ); + } + + if ( error ) + { + if ( FT_ERR_EQ( error, Invalid_Table ) ) + FT_ERROR(( "pfr_slot_load_bitmap: invalid bitmap dimensions\n" )); + goto Exit1; + } + + /* + * XXX: on 16bit systems we return an error for huge bitmaps + * that cause size truncation, because truncated + * size properties make bitmap glyphs broken. + */ + if ( xpos > FT_INT_MAX || + xpos < FT_INT_MIN || + ysize > FT_INT_MAX || + ypos > FT_INT_MAX - (FT_Long)ysize || + ypos + (FT_Long)ysize < FT_INT_MIN ) + { + FT_TRACE1(( "pfr_slot_load_bitmap:" + " huge bitmap glyph %ldx%ld over FT_GlyphSlot\n", + xpos, ypos )); + error = FT_THROW( Invalid_Pixel_Size ); + } + + if ( !error ) + { + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; + + /* Set up glyph bitmap and metrics */ + + /* XXX: needs casts to fit FT_Bitmap.{width|rows|pitch} */ + glyph->root.bitmap.width = xsize; + glyph->root.bitmap.rows = ysize; + glyph->root.bitmap.pitch = (FT_Int)( xsize + 7 ) >> 3; + glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + /* XXX: needs casts to fit FT_Glyph_Metrics.{width|height} */ + glyph->root.metrics.width = (FT_Pos)xsize << 6; + glyph->root.metrics.height = (FT_Pos)ysize << 6; + glyph->root.metrics.horiBearingX = xpos * 64; + glyph->root.metrics.horiBearingY = ypos * 64; + glyph->root.metrics.horiAdvance = FT_PIX_ROUND( ( advance >> 2 ) ); + glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1; + glyph->root.metrics.vertBearingY = 0; + glyph->root.metrics.vertAdvance = size->root.metrics.height; + + /* XXX: needs casts fit FT_GlyphSlotRec.bitmap_{left|top} */ + glyph->root.bitmap_left = (FT_Int)xpos; + glyph->root.bitmap_top = (FT_Int)( ypos + (FT_Long)ysize ); + + if ( metrics_only ) + goto Exit1; + + /* Allocate and read bitmap data */ + { + FT_ULong len = (FT_ULong)glyph->root.bitmap.pitch * ysize; + + + error = ft_glyphslot_alloc_bitmap( &glyph->root, len ); + if ( !error ) + error = pfr_load_bitmap_bits( + p, + stream->limit, + format, + FT_BOOL( face->header.color_flags & + PFR_FLAG_INVERT_BITMAP ), + &glyph->root.bitmap ); + } + } + + Exit1: + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrsbit.h b/vendor/freetype/src/pfr/pfrsbit.h new file mode 100644 index 0000000..3e1dba9 --- /dev/null +++ b/vendor/freetype/src/pfr/pfrsbit.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * pfrsbit.h + * + * FreeType PFR bitmap loader (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRSBIT_H_ +#define PFRSBIT_H_ + +#include "pfrobjs.h" + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index, + FT_Bool metrics_only ); + +FT_END_HEADER + +#endif /* PFRSBIT_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/pfrtypes.h b/vendor/freetype/src/pfr/pfrtypes.h new file mode 100644 index 0000000..2f8909f --- /dev/null +++ b/vendor/freetype/src/pfr/pfrtypes.h @@ -0,0 +1,331 @@ +/**************************************************************************** + * + * pfrtypes.h + * + * FreeType PFR data structures (specification only). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRTYPES_H_ +#define PFRTYPES_H_ + +#include + +FT_BEGIN_HEADER + + /************************************************************************/ + + /* the PFR Header structure */ + typedef struct PFR_HeaderRec_ + { + FT_UInt32 signature; + FT_UInt version; + FT_UInt signature2; + FT_UInt header_size; + + FT_UInt log_dir_size; + FT_UInt log_dir_offset; + + FT_UInt log_font_max_size; + FT_UInt32 log_font_section_size; + FT_UInt32 log_font_section_offset; + + FT_UInt32 phy_font_max_size; + FT_UInt32 phy_font_section_size; + FT_UInt32 phy_font_section_offset; + + FT_UInt gps_max_size; + FT_UInt32 gps_section_size; + FT_UInt32 gps_section_offset; + + FT_UInt max_blue_values; + FT_UInt max_x_orus; + FT_UInt max_y_orus; + + FT_UInt phy_font_max_size_high; + FT_UInt color_flags; + + FT_UInt32 bct_max_size; + FT_UInt32 bct_set_max_size; + FT_UInt32 phy_bct_set_max_size; + + FT_UInt num_phy_fonts; + FT_UInt max_vert_stem_snap; + FT_UInt max_horz_stem_snap; + FT_UInt max_chars; + + } PFR_HeaderRec, *PFR_Header; + + + /* used in `color_flags' field of the PFR_Header */ +#define PFR_FLAG_BLACK_PIXEL 0x01U +#define PFR_FLAG_INVERT_BITMAP 0x02U + + + /************************************************************************/ + + typedef struct PFR_LogFontRec_ + { + FT_UInt32 size; + FT_UInt32 offset; + + FT_Int32 matrix[4]; + FT_UInt stroke_flags; + FT_Int stroke_thickness; + FT_Int bold_thickness; + FT_Int32 miter_limit; + + FT_UInt32 phys_size; + FT_UInt32 phys_offset; + + } PFR_LogFontRec, *PFR_LogFont; + + +#define PFR_LINE_JOIN_MITER 0x00U +#define PFR_LINE_JOIN_ROUND 0x01U +#define PFR_LINE_JOIN_BEVEL 0x02U +#define PFR_LINE_JOIN_MASK ( PFR_LINE_JOIN_ROUND | PFR_LINE_JOIN_BEVEL ) + +#define PFR_LOG_STROKE 0x04U +#define PFR_LOG_2BYTE_STROKE 0x08U +#define PFR_LOG_BOLD 0x10U +#define PFR_LOG_2BYTE_BOLD 0x20U +#define PFR_LOG_EXTRA_ITEMS 0x40U + + + /************************************************************************/ + +#define PFR_BITMAP_2BYTE_CHARCODE 0x01U +#define PFR_BITMAP_2BYTE_SIZE 0x02U +#define PFR_BITMAP_3BYTE_OFFSET 0x04U + + /* not part of the specification but used for implementation */ +#define PFR_BITMAP_CHARCODES_VALIDATED 0x40U +#define PFR_BITMAP_VALID_CHARCODES 0x80U + + + typedef struct PFR_BitmapCharRec_ + { + FT_UInt char_code; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_BitmapCharRec, *PFR_BitmapChar; + + +#define PFR_STRIKE_2BYTE_XPPM 0x01U +#define PFR_STRIKE_2BYTE_YPPM 0x02U +#define PFR_STRIKE_3BYTE_SIZE 0x04U +#define PFR_STRIKE_3BYTE_OFFSET 0x08U +#define PFR_STRIKE_2BYTE_COUNT 0x10U + + + typedef struct PFR_StrikeRec_ + { + FT_UInt x_ppm; + FT_UInt y_ppm; + FT_UInt flags; + + FT_UInt32 gps_size; + FT_UInt32 gps_offset; + + FT_UInt32 bct_size; + FT_UInt32 bct_offset; + + /* optional */ + FT_UInt num_bitmaps; + PFR_BitmapChar bitmaps; + + } PFR_StrikeRec, *PFR_Strike; + + + /************************************************************************/ + + typedef struct PFR_CharRec_ + { + FT_UInt char_code; + FT_Int advance; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_CharRec, *PFR_Char; + + + /************************************************************************/ + + typedef struct PFR_DimensionRec_ + { + FT_UInt standard; + FT_UInt num_stem_snaps; + FT_Int* stem_snaps; + + } PFR_DimensionRec, *PFR_Dimension; + + /************************************************************************/ + + typedef struct PFR_KernItemRec_* PFR_KernItem; + + typedef struct PFR_KernItemRec_ + { + PFR_KernItem next; + FT_Byte pair_count; + FT_Byte flags; + FT_Short base_adj; + FT_UInt pair_size; + FT_Offset offset; + FT_UInt32 pair1; + FT_UInt32 pair2; + + } PFR_KernItemRec; + + +#define PFR_KERN_INDEX( g1, g2 ) \ + ( ( (FT_UInt32)(g1) << 16 ) | (FT_UInt16)(g2) ) + +#define PFR_KERN_PAIR_INDEX( pair ) \ + PFR_KERN_INDEX( (pair)->glyph1, (pair)->glyph2 ) + +#define PFR_NEXT_KPAIR( p ) ( p += 2, \ + ( (FT_UInt32)p[-2] << 16 ) | p[-1] ) + + + /************************************************************************/ + + typedef struct PFR_PhyFontRec_ + { + FT_Memory memory; + FT_UInt32 offset; + + FT_UInt font_ref_number; + FT_UInt outline_resolution; + FT_UInt metrics_resolution; + FT_BBox bbox; + FT_UInt flags; + FT_Int standard_advance; + + FT_Int ascent; /* optional, bbox.yMax if not present */ + FT_Int descent; /* optional, bbox.yMin if not present */ + FT_Int leading; /* optional, 0 if not present */ + + PFR_DimensionRec horizontal; + PFR_DimensionRec vertical; + + FT_String* font_id; + FT_String* family_name; + FT_String* style_name; + + FT_UInt num_strikes; + FT_UInt max_strikes; + PFR_StrikeRec* strikes; + + FT_UInt num_blue_values; + FT_Int *blue_values; + FT_UInt blue_fuzz; + FT_UInt blue_scale; + + FT_UInt num_chars; + FT_Offset chars_offset; + PFR_Char chars; + + FT_UInt num_kern_pairs; + PFR_KernItem kern_items; + PFR_KernItem* kern_items_tail; + + /* not part of the spec, but used during load */ + FT_ULong bct_offset; + FT_Byte* cursor; + + } PFR_PhyFontRec, *PFR_PhyFont; + + +#define PFR_PHY_VERTICAL 0x01U +#define PFR_PHY_2BYTE_CHARCODE 0x02U +#define PFR_PHY_PROPORTIONAL 0x04U +#define PFR_PHY_ASCII_CODE 0x08U +#define PFR_PHY_2BYTE_GPS_SIZE 0x10U +#define PFR_PHY_3BYTE_GPS_OFFSET 0x20U +#define PFR_PHY_EXTRA_ITEMS 0x80U + + +#define PFR_KERN_2BYTE_CHAR 0x01U +#define PFR_KERN_2BYTE_ADJ 0x02U + + + /************************************************************************/ + +#define PFR_GLYPH_YCOUNT 0x01U +#define PFR_GLYPH_XCOUNT 0x02U +#define PFR_GLYPH_1BYTE_XYCOUNT 0x04U + +#define PFR_GLYPH_SINGLE_EXTRA_ITEMS 0x08U +#define PFR_GLYPH_COMPOUND_EXTRA_ITEMS 0x40U + +#define PFR_GLYPH_IS_COMPOUND 0x80U + + + /* controlled coordinate */ + typedef struct PFR_CoordRec_ + { + FT_UInt org; + FT_UInt cur; + + } PFR_CoordRec, *PFR_Coord; + + + typedef struct PFR_SubGlyphRec_ + { + FT_Fixed x_scale; + FT_Fixed y_scale; + FT_Int x_delta; + FT_Int y_delta; + FT_UInt32 gps_offset; + FT_UInt gps_size; + + } PFR_SubGlyphRec, *PFR_SubGlyph; + + +#define PFR_SUBGLYPH_XSCALE 0x10U +#define PFR_SUBGLYPH_YSCALE 0x20U +#define PFR_SUBGLYPH_2BYTE_SIZE 0x40U +#define PFR_SUBGLYPH_3BYTE_OFFSET 0x80U + + + typedef struct PFR_GlyphRec_ + { + FT_Byte format; + +#if 0 + FT_UInt num_x_control; + FT_UInt num_y_control; +#endif + FT_UInt max_xy_control; + FT_Pos* x_control; + FT_Pos* y_control; + + + FT_UInt num_subs; + FT_UInt max_subs; + PFR_SubGlyphRec* subs; + + FT_GlyphLoader loader; + FT_Bool path_begun; + + } PFR_GlyphRec, *PFR_Glyph; + + +FT_END_HEADER + +#endif /* PFRTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pfr/rules.mk b/vendor/freetype/src/pfr/rules.mk new file mode 100644 index 0000000..50695fd --- /dev/null +++ b/vendor/freetype/src/pfr/rules.mk @@ -0,0 +1,76 @@ +# +# FreeType 2 PFR driver configuration rules +# + + +# Copyright (C) 2002-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# pfr driver directory +# +PFR_DIR := $(SRC_DIR)/pfr + + +# compilation flags for the driver +# +PFR_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(PFR_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# pfr driver sources (i.e., C files) +# +PFR_DRV_SRC := $(PFR_DIR)/pfrload.c \ + $(PFR_DIR)/pfrgload.c \ + $(PFR_DIR)/pfrcmap.c \ + $(PFR_DIR)/pfrdrivr.c \ + $(PFR_DIR)/pfrsbit.c \ + $(PFR_DIR)/pfrobjs.c + +# pfr driver headers +# +PFR_DRV_H := $(PFR_DRV_SRC:%.c=%.h) \ + $(PFR_DIR)/pfrerror.h \ + $(PFR_DIR)/pfrtypes.h + + +# Pfr driver object(s) +# +# PFR_DRV_OBJ_M is used during `multi' builds +# PFR_DRV_OBJ_S is used during `single' builds +# +PFR_DRV_OBJ_M := $(PFR_DRV_SRC:$(PFR_DIR)/%.c=$(OBJ_DIR)/%.$O) +PFR_DRV_OBJ_S := $(OBJ_DIR)/pfr.$O + +# pfr driver source file for single build +# +PFR_DRV_SRC_S := $(PFR_DIR)/pfr.c + + +# pfr driver - single object +# +$(PFR_DRV_OBJ_S): $(PFR_DRV_SRC_S) $(PFR_DRV_SRC) $(FREETYPE_H) $(PFR_DRV_H) + $(PFR_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(PFR_DRV_SRC_S)) + + +# pfr driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(PFR_DIR)/%.c $(FREETYPE_H) $(PFR_DRV_H) + $(PFR_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(PFR_DRV_OBJ_S) +DRV_OBJS_M += $(PFR_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/psaux/afmparse.c b/vendor/freetype/src/psaux/afmparse.c new file mode 100644 index 0000000..db08941 --- /dev/null +++ b/vendor/freetype/src/psaux/afmparse.c @@ -0,0 +1,1094 @@ +/**************************************************************************** + * + * afmparse.c + * + * AFM parser (body). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include + +#ifndef T1_CONFIG_OPTION_NO_AFM + +#include "afmparse.h" +#include "psconv.h" + +#include "psauxerr.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afmparse + + + /************************************************************************** + * + * AFM_Stream + * + * The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. + * + */ + + enum + { + AFM_STREAM_STATUS_NORMAL, + AFM_STREAM_STATUS_EOC, + AFM_STREAM_STATUS_EOL, + AFM_STREAM_STATUS_EOF + }; + + + typedef struct AFM_StreamRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + FT_Int status; + + } AFM_StreamRec; + + +#ifndef EOF +#define EOF -1 +#endif + + + /* this works because empty lines are ignored */ +#define AFM_IS_NEWLINE( ch ) ( (ch) == '\r' || (ch) == '\n' ) + +#define AFM_IS_EOF( ch ) ( (ch) == EOF || (ch) == '\x1a' ) +#define AFM_IS_SPACE( ch ) ( (ch) == ' ' || (ch) == '\t' ) + + /* column separator; there is no `column' in the spec actually */ +#define AFM_IS_SEP( ch ) ( (ch) == ';' ) + +#define AFM_GETC() \ + ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \ + : EOF ) + +#define AFM_STREAM_KEY_BEGIN( stream ) \ + (char*)( (stream)->cursor - 1 ) + +#define AFM_STREAM_KEY_LEN( stream, key ) \ + (FT_Offset)( (char*)(stream)->cursor - key - 1 ) + +#define AFM_STATUS_EOC( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOC ) + +#define AFM_STATUS_EOL( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOL ) + +#define AFM_STATUS_EOF( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOF ) + + + static int + afm_stream_skip_spaces( AFM_Stream stream ) + { + int ch = 0; /* make stupid compiler happy */ + + + if ( AFM_STATUS_EOC( stream ) ) + return ';'; + + while ( 1 ) + { + ch = AFM_GETC(); + if ( !AFM_IS_SPACE( ch ) ) + break; + } + + if ( AFM_IS_NEWLINE( ch ) ) + stream->status = AFM_STREAM_STATUS_EOL; + else if ( AFM_IS_SEP( ch ) ) + stream->status = AFM_STREAM_STATUS_EOC; + else if ( AFM_IS_EOF( ch ) ) + stream->status = AFM_STREAM_STATUS_EOF; + + return ch; + } + + + /* read a key or value in current column */ + static char* + afm_stream_read_one( AFM_Stream stream ) + { + char* str; + + + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOC( stream ) ) + return NULL; + + str = AFM_STREAM_KEY_BEGIN( stream ); + + while ( 1 ) + { + int ch = AFM_GETC(); + + + if ( AFM_IS_SPACE( ch ) ) + break; + else if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_SEP( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOC; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + + return str; + } + + + /* read a string (i.e., read to EOL) */ + static char* + afm_stream_read_string( AFM_Stream stream ) + { + char* str; + + + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOL( stream ) ) + return NULL; + + str = AFM_STREAM_KEY_BEGIN( stream ); + + /* scan to eol */ + while ( 1 ) + { + int ch = AFM_GETC(); + + + if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + + return str; + } + + + /************************************************************************** + * + * AFM_Parser + * + */ + + /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */ + typedef enum AFM_Token_ + { + AFM_TOKEN_ASCENDER, + AFM_TOKEN_AXISLABEL, + AFM_TOKEN_AXISTYPE, + AFM_TOKEN_B, + AFM_TOKEN_BLENDAXISTYPES, + AFM_TOKEN_BLENDDESIGNMAP, + AFM_TOKEN_BLENDDESIGNPOSITIONS, + AFM_TOKEN_C, + AFM_TOKEN_CC, + AFM_TOKEN_CH, + AFM_TOKEN_CAPHEIGHT, + AFM_TOKEN_CHARWIDTH, + AFM_TOKEN_CHARACTERSET, + AFM_TOKEN_CHARACTERS, + AFM_TOKEN_DESCENDER, + AFM_TOKEN_ENCODINGSCHEME, + AFM_TOKEN_ENDAXIS, + AFM_TOKEN_ENDCHARMETRICS, + AFM_TOKEN_ENDCOMPOSITES, + AFM_TOKEN_ENDDIRECTION, + AFM_TOKEN_ENDFONTMETRICS, + AFM_TOKEN_ENDKERNDATA, + AFM_TOKEN_ENDKERNPAIRS, + AFM_TOKEN_ENDTRACKKERN, + AFM_TOKEN_ESCCHAR, + AFM_TOKEN_FAMILYNAME, + AFM_TOKEN_FONTBBOX, + AFM_TOKEN_FONTNAME, + AFM_TOKEN_FULLNAME, + AFM_TOKEN_ISBASEFONT, + AFM_TOKEN_ISCIDFONT, + AFM_TOKEN_ISFIXEDPITCH, + AFM_TOKEN_ISFIXEDV, + AFM_TOKEN_ITALICANGLE, + AFM_TOKEN_KP, + AFM_TOKEN_KPH, + AFM_TOKEN_KPX, + AFM_TOKEN_KPY, + AFM_TOKEN_L, + AFM_TOKEN_MAPPINGSCHEME, + AFM_TOKEN_METRICSSETS, + AFM_TOKEN_N, + AFM_TOKEN_NOTICE, + AFM_TOKEN_PCC, + AFM_TOKEN_STARTAXIS, + AFM_TOKEN_STARTCHARMETRICS, + AFM_TOKEN_STARTCOMPOSITES, + AFM_TOKEN_STARTDIRECTION, + AFM_TOKEN_STARTFONTMETRICS, + AFM_TOKEN_STARTKERNDATA, + AFM_TOKEN_STARTKERNPAIRS, + AFM_TOKEN_STARTKERNPAIRS0, + AFM_TOKEN_STARTKERNPAIRS1, + AFM_TOKEN_STARTTRACKKERN, + AFM_TOKEN_STDHW, + AFM_TOKEN_STDVW, + AFM_TOKEN_TRACKKERN, + AFM_TOKEN_UNDERLINEPOSITION, + AFM_TOKEN_UNDERLINETHICKNESS, + AFM_TOKEN_VV, + AFM_TOKEN_VVECTOR, + AFM_TOKEN_VERSION, + AFM_TOKEN_W, + AFM_TOKEN_W0, + AFM_TOKEN_W0X, + AFM_TOKEN_W0Y, + AFM_TOKEN_W1, + AFM_TOKEN_W1X, + AFM_TOKEN_W1Y, + AFM_TOKEN_WX, + AFM_TOKEN_WY, + AFM_TOKEN_WEIGHT, + AFM_TOKEN_WEIGHTVECTOR, + AFM_TOKEN_XHEIGHT, + N_AFM_TOKENS, + AFM_TOKEN_UNKNOWN + + } AFM_Token; + + + static const char* const afm_key_table[N_AFM_TOKENS] = + { + "Ascender", + "AxisLabel", + "AxisType", + "B", + "BlendAxisTypes", + "BlendDesignMap", + "BlendDesignPositions", + "C", + "CC", + "CH", + "CapHeight", + "CharWidth", + "CharacterSet", + "Characters", + "Descender", + "EncodingScheme", + "EndAxis", + "EndCharMetrics", + "EndComposites", + "EndDirection", + "EndFontMetrics", + "EndKernData", + "EndKernPairs", + "EndTrackKern", + "EscChar", + "FamilyName", + "FontBBox", + "FontName", + "FullName", + "IsBaseFont", + "IsCIDFont", + "IsFixedPitch", + "IsFixedV", + "ItalicAngle", + "KP", + "KPH", + "KPX", + "KPY", + "L", + "MappingScheme", + "MetricsSets", + "N", + "Notice", + "PCC", + "StartAxis", + "StartCharMetrics", + "StartComposites", + "StartDirection", + "StartFontMetrics", + "StartKernData", + "StartKernPairs", + "StartKernPairs0", + "StartKernPairs1", + "StartTrackKern", + "StdHW", + "StdVW", + "TrackKern", + "UnderlinePosition", + "UnderlineThickness", + "VV", + "VVector", + "Version", + "W", + "W0", + "W0X", + "W0Y", + "W1", + "W1X", + "W1Y", + "WX", + "WY", + "Weight", + "WeightVector", + "XHeight" + }; + + + /* + * `afm_parser_read_vals' and `afm_parser_next_key' provide + * high-level operations to an AFM_Stream. The rest of the + * parser functions should use them without accessing the + * AFM_Stream directly. + */ + + FT_LOCAL_DEF( FT_Int ) + afm_parser_read_vals( AFM_Parser parser, + AFM_Value vals, + FT_Int n ) + { + AFM_Stream stream = parser->stream; + char* str; + FT_Int i; + + + if ( n > AFM_MAX_ARGUMENTS ) + return 0; + + for ( i = 0; i < n; i++ ) + { + FT_Offset len; + AFM_Value val = vals + i; + + + if ( val->type == AFM_VALUE_TYPE_STRING ) + str = afm_stream_read_string( stream ); + else + str = afm_stream_read_one( stream ); + + if ( !str ) + break; + + len = AFM_STREAM_KEY_LEN( stream, str ); + + switch ( val->type ) + { + case AFM_VALUE_TYPE_STRING: + case AFM_VALUE_TYPE_NAME: + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( !FT_QALLOC( val->u.s, len + 1 ) ) + { + ft_memcpy( val->u.s, str, len ); + val->u.s[len] = '\0'; + } + } + break; + + case AFM_VALUE_TYPE_FIXED: + val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len, 0 ); + break; + + case AFM_VALUE_TYPE_INTEGER: + val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len ); + break; + + case AFM_VALUE_TYPE_BOOL: + val->u.b = FT_BOOL( len == 4 && + !ft_strncmp( str, "true", 4 ) ); + break; + + case AFM_VALUE_TYPE_INDEX: + if ( parser->get_index ) + val->u.i = parser->get_index( str, len, parser->user_data ); + else + val->u.i = 0; + break; + } + } + + return i; + } + + + FT_LOCAL_DEF( char* ) + afm_parser_next_key( AFM_Parser parser, + FT_Bool line, + FT_Offset* len ) + { + AFM_Stream stream = parser->stream; + char* key = NULL; /* make stupid compiler happy */ + + + if ( line ) + { + while ( 1 ) + { + /* skip current line */ + if ( !AFM_STATUS_EOL( stream ) ) + afm_stream_read_string( stream ); + + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); + + /* skip empty line */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOL( stream ) ) + continue; + + break; + } + } + else + { + while ( 1 ) + { + /* skip current column */ + while ( !AFM_STATUS_EOC( stream ) ) + afm_stream_read_one( stream ); + + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); + + /* skip empty column */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOC( stream ) ) + continue; + + break; + } + } + + if ( len ) + *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key ) + : 0; + + return key; + } + + + static AFM_Token + afm_tokenize( const char* key, + FT_Offset len ) + { + int n; + + + for ( n = 0; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) == *key ) + { + for ( ; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) != *key ) + return AFM_TOKEN_UNKNOWN; + + if ( ft_strncmp( afm_key_table[n], key, len ) == 0 ) + return (AFM_Token) n; + } + } + } + + return AFM_TOKEN_UNKNOWN; + } + + + FT_LOCAL_DEF( FT_Error ) + afm_parser_init( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ) + { + AFM_Stream stream = NULL; + FT_Error error; + + + if ( FT_NEW( stream ) ) + return error; + + stream->cursor = stream->base = base; + stream->limit = limit; + + /* don't skip the first line during the first call */ + stream->status = AFM_STREAM_STATUS_EOL; + + parser->memory = memory; + parser->stream = stream; + parser->FontInfo = NULL; + parser->get_index = NULL; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + afm_parser_done( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + + + FT_FREE( parser->stream ); + } + + + static FT_Error + afm_parser_read_int( AFM_Parser parser, + FT_Int* aint ) + { + AFM_ValueRec val; + + + val.type = AFM_VALUE_TYPE_INTEGER; + + if ( afm_parser_read_vals( parser, &val, 1 ) == 1 ) + { + *aint = val.u.i; + + return FT_Err_Ok; + } + else + return FT_THROW( Syntax_Error ); + } + + + static FT_Error + afm_parse_track_kern( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; + AFM_TrackKern tk; + + char* key; + FT_Offset len; + int n = -1; + FT_Int tmp; + + + if ( afm_parser_read_int( parser, &tmp ) ) + goto Fail; + + if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_track_kern: invalid number of track kerns\n" )); + goto Fail; + } + + fi->NumTrackKern = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_track_kern: %u track kern%s expected\n", + fi->NumTrackKern, + fi->NumTrackKern == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `TrackKern` */ + /* command is 20 characters (including the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 20 < + fi->NumTrackKern ) + { + FT_ERROR(( "afm_parse_track_kern:" + " number of track kern entries exceeds stream size\n" )); + goto Fail; + } + + if ( fi->NumTrackKern ) + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) ) + return error; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[5]; + + + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_TRACKKERN: + n++; + + if ( n >= (int)fi->NumTrackKern ) + { + FT_ERROR(( "afm_parse_track_kern: too many track kern data\n" )); + goto Fail; + } + + tk = fi->TrackKerns + n; + + shared_vals[0].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + shared_vals[4].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 ) + { + FT_ERROR(( "afm_parse_track_kern:" + " insufficient number of parameters for entry %d\n", + n )); + goto Fail; + } + + tk->degree = shared_vals[0].u.i; + tk->min_ptsize = shared_vals[1].u.f; + tk->min_kern = shared_vals[2].u.f; + tk->max_ptsize = shared_vals[3].u.f; + tk->max_kern = shared_vals[4].u.f; + + break; + + case AFM_TOKEN_ENDTRACKKERN: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumTrackKern ) + { + FT_TRACE1(( "afm_parse_track_kern: %s%d track kern entr%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "y" : "ies" )); + fi->NumTrackKern = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_track_kern: %d track kern entr%s seen\n", + tmp, + tmp == 1 ? "y" : "ies" )); + return FT_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) + + + /* compare two kerning pairs */ + FT_COMPARE_DEF( int ) + afm_compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair kp1 = (AFM_KernPair)a; + AFM_KernPair kp2 = (AFM_KernPair)b; + + FT_ULong index1 = KERN_INDEX( kp1->index1, kp1->index2 ); + FT_ULong index2 = KERN_INDEX( kp2->index1, kp2->index2 ); + + + if ( index1 > index2 ) + return 1; + else if ( index1 < index2 ) + return -1; + else + return 0; + } + + + static FT_Error + afm_parse_kern_pairs( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; + AFM_KernPair kp; + char* key; + FT_Offset len; + int n = -1; + FT_Int tmp; + + + if ( afm_parser_read_int( parser, &tmp ) ) + goto Fail; + + if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_kern_pairs: invalid number of kern pairs\n" )); + goto Fail; + } + + fi->NumKernPair = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_kern_pairs: %u kern pair%s expected\n", + fi->NumKernPair, + fi->NumKernPair == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `KP`, */ + /* `KPH`,`KPX`, and `KPY` commands is 10 characters (including */ + /* the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 10 < + fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " number of kern pairs exceeds stream size\n" )); + goto Fail; + } + + if ( fi->NumKernPair ) + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + return error; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + + + switch ( token ) + { + case AFM_TOKEN_KP: + case AFM_TOKEN_KPX: + case AFM_TOKEN_KPY: + { + FT_Int r; + AFM_ValueRec shared_vals[4]; + + + n++; + + if ( n >= (int)fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs: too many kern pairs\n" )); + goto Fail; + } + + kp = fi->KernPairs + n; + + shared_vals[0].type = AFM_VALUE_TYPE_INDEX; + shared_vals[1].type = AFM_VALUE_TYPE_INDEX; + shared_vals[2].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[3].type = AFM_VALUE_TYPE_INTEGER; + r = afm_parser_read_vals( parser, shared_vals, 4 ); + if ( r < 3 ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " insufficient number of parameters for entry %d\n", + n )); + goto Fail; + } + + /* index values can't be negative */ + kp->index1 = shared_vals[0].u.u; + kp->index2 = shared_vals[1].u.u; + if ( token == AFM_TOKEN_KPY ) + { + kp->x = 0; + kp->y = shared_vals[2].u.i; + } + else + { + kp->x = shared_vals[2].u.i; + kp->y = ( token == AFM_TOKEN_KP && r == 4 ) + ? shared_vals[3].u.i : 0; + } + } + break; + + case AFM_TOKEN_ENDKERNPAIRS: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumKernPair ) + { + FT_TRACE1(( "afm_parse_kern_pairs: %s%d kern pair%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "" : "s" )); + fi->NumKernPair = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_kern_pairs: %d kern pair%s seen\n", + tmp, + tmp == 1 ? "" : "s" )); + + ft_qsort( fi->KernPairs, fi->NumKernPair, + sizeof ( AFM_KernPairRec ), + afm_compare_kern_pairs ); + return FT_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + + static FT_Error + afm_parse_kern_data( AFM_Parser parser ) + { + FT_Error error; + char* key; + FT_Offset len; + + int have_trackkern = 0; + int have_kernpairs = 0; + + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_STARTTRACKKERN: + if ( have_trackkern ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal track kern section\n" )); + goto Fail; + } + + error = afm_parse_track_kern( parser ); + if ( error ) + return error; + + have_trackkern = 1; + break; + + case AFM_TOKEN_STARTKERNPAIRS: + case AFM_TOKEN_STARTKERNPAIRS0: + if ( have_kernpairs ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal kern pair section\n" )); + goto Fail; + } + + error = afm_parse_kern_pairs( parser ); + if ( error ) + return error; + + have_kernpairs = 1; + break; + + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + return FT_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + + static FT_Error + afm_parser_skip_section( AFM_Parser parser, + FT_Int n, + AFM_Token end_section ) + { + char* key; + FT_Offset len; + + + while ( n-- > 0 ) + { + key = afm_parser_next_key( parser, 1, NULL ); + if ( !key ) + goto Fail; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + + + if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS ) + return FT_Err_Ok; + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + + FT_LOCAL_DEF( FT_Error ) + afm_parser_parse( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + AFM_FontInfo fi = parser->FontInfo; + FT_Error error = FT_ERR( Syntax_Error ); + char* key; + FT_Offset len; + FT_Int metrics_sets = 0; + + + if ( !fi ) + return FT_THROW( Invalid_Argument ); + + key = afm_parser_next_key( parser, 1, &len ); + if ( !key || len != 16 || + ft_strncmp( key, "StartFontMetrics", 16 ) != 0 ) + return FT_THROW( Unknown_File_Format ); + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[4]; + + + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_METRICSSETS: + if ( afm_parser_read_int( parser, &metrics_sets ) ) + goto Fail; + + if ( metrics_sets != 0 && metrics_sets != 2 ) + { + error = FT_THROW( Unimplemented_Feature ); + + goto Fail; + } + break; + + case AFM_TOKEN_ISCIDFONT: + shared_vals[0].type = AFM_VALUE_TYPE_BOOL; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->IsCIDFont = shared_vals[0].u.b; + break; + + case AFM_TOKEN_FONTBBOX: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 ) + goto Fail; + + fi->FontBBox.xMin = shared_vals[0].u.f; + fi->FontBBox.yMin = shared_vals[1].u.f; + fi->FontBBox.xMax = shared_vals[2].u.f; + fi->FontBBox.yMax = shared_vals[3].u.f; + break; + + case AFM_TOKEN_ASCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->Ascender = shared_vals[0].u.f; + break; + + case AFM_TOKEN_DESCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->Descender = shared_vals[0].u.f; + break; + + case AFM_TOKEN_STARTCHARMETRICS: + { + FT_Int n = 0; + + + if ( afm_parser_read_int( parser, &n ) ) + goto Fail; + + error = afm_parser_skip_section( parser, n, + AFM_TOKEN_ENDCHARMETRICS ); + if ( error ) + return error; + } + break; + + case AFM_TOKEN_STARTKERNDATA: + error = afm_parse_kern_data( parser ); + if ( error ) + goto Fail; + /* we only support kern data, so ... */ + FALL_THROUGH; + + case AFM_TOKEN_ENDFONTMETRICS: + return FT_Err_Ok; + + default: + break; + } + } + + Fail: + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + + fi->IsCIDFont = 0; + + return error; + } + +#else /* T1_CONFIG_OPTION_NO_AFM */ + + /* ANSI C doesn't like empty source files */ + typedef int afm_parse_dummy_; + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/afmparse.h b/vendor/freetype/src/psaux/afmparse.h new file mode 100644 index 0000000..2d3b6e6 --- /dev/null +++ b/vendor/freetype/src/psaux/afmparse.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * + * afmparse.h + * + * AFM parser (specification). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFMPARSE_H_ +#define AFMPARSE_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + afm_parser_init( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + + + FT_LOCAL( void ) + afm_parser_done( AFM_Parser parser ); + + + FT_LOCAL( FT_Error ) + afm_parser_parse( AFM_Parser parser ); + + + enum AFM_ValueType_ + { + AFM_VALUE_TYPE_STRING, + AFM_VALUE_TYPE_NAME, + AFM_VALUE_TYPE_FIXED, /* real number */ + AFM_VALUE_TYPE_INTEGER, + AFM_VALUE_TYPE_BOOL, + AFM_VALUE_TYPE_INDEX /* glyph index */ + }; + + + typedef struct AFM_ValueRec_ + { + enum AFM_ValueType_ type; + union + { + char* s; + FT_Fixed f; + FT_Int i; + FT_UInt u; + FT_Bool b; + + } u; + + } AFM_ValueRec, *AFM_Value; + +#define AFM_MAX_ARGUMENTS 5 + + FT_LOCAL( FT_Int ) + afm_parser_read_vals( AFM_Parser parser, + AFM_Value vals, + FT_Int n ); + + /* read the next key from the next line or column */ + FT_LOCAL( char* ) + afm_parser_next_key( AFM_Parser parser, + FT_Bool line, + FT_Offset* len ); + +FT_END_HEADER + +#endif /* AFMPARSE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/cffdecode.c b/vendor/freetype/src/psaux/cffdecode.c new file mode 100644 index 0000000..562d17d --- /dev/null +++ b/vendor/freetype/src/psaux/cffdecode.c @@ -0,0 +1,2423 @@ +/**************************************************************************** + * + * cffdecode.c + * + * PostScript CFF (Type 2) decoding routines (body). + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "cffdecode.h" +#include "psobjs.h" + +#include "psauxerr.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffdecode + + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + + typedef enum CFF_Operator_ + { + cff_op_unknown = 0, + + cff_op_rmoveto, + cff_op_hmoveto, + cff_op_vmoveto, + + cff_op_rlineto, + cff_op_hlineto, + cff_op_vlineto, + + cff_op_rrcurveto, + cff_op_hhcurveto, + cff_op_hvcurveto, + cff_op_rcurveline, + cff_op_rlinecurve, + cff_op_vhcurveto, + cff_op_vvcurveto, + + cff_op_flex, + cff_op_hflex, + cff_op_hflex1, + cff_op_flex1, + + cff_op_endchar, + + cff_op_hstem, + cff_op_vstem, + cff_op_hstemhm, + cff_op_vstemhm, + + cff_op_hintmask, + cff_op_cntrmask, + cff_op_dotsection, /* deprecated, acts as no-op */ + + cff_op_abs, + cff_op_add, + cff_op_sub, + cff_op_div, + cff_op_neg, + cff_op_random, + cff_op_mul, + cff_op_sqrt, + + cff_op_blend, + + cff_op_drop, + cff_op_exch, + cff_op_index, + cff_op_roll, + cff_op_dup, + + cff_op_put, + cff_op_get, + cff_op_store, + cff_op_load, + + cff_op_and, + cff_op_or, + cff_op_not, + cff_op_eq, + cff_op_ifelse, + + cff_op_callsubr, + cff_op_callgsubr, + cff_op_return, + + /* Type 1 opcodes: invalid but seen in real life */ + cff_op_hsbw, + cff_op_closepath, + cff_op_callothersubr, + cff_op_pop, + cff_op_seac, + cff_op_sbw, + cff_op_setcurrentpoint, + + /* do not remove */ + cff_op_max + + } CFF_Operator; + + +#define CFF_COUNT_CHECK_WIDTH 0x80 +#define CFF_COUNT_EXACT 0x40 +#define CFF_COUNT_CLEAR_STACK 0x20 + + /* count values which have the `CFF_COUNT_CHECK_WIDTH' flag set are */ + /* used for checking the width and requested numbers of arguments */ + /* only; they are set to zero afterwards */ + + /* the other two flags are informative only and unused currently */ + + static const FT_Byte cff_argument_counts[] = + { + 0, /* unknown */ + + 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */ + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + + 0 | CFF_COUNT_CLEAR_STACK, /* rlineto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + + 0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + + 13, /* flex */ + 7, + 9, + 11, + + 0 | CFF_COUNT_CHECK_WIDTH, /* endchar */ + + 2 | CFF_COUNT_CHECK_WIDTH, /* hstem */ + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + + 0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */ + 0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */ + 0, /* dotsection */ + + 1, /* abs */ + 2, + 2, + 2, + 1, + 0, + 2, + 1, + + 1, /* blend */ + + 1, /* drop */ + 2, + 1, + 2, + 1, + + 2, /* put */ + 1, + 4, + 3, + + 2, /* and */ + 2, + 1, + 2, + 4, + + 1, /* callsubr */ + 1, + 0, + + 2, /* hsbw */ + 0, + 0, + 0, + 5, /* seac */ + 4, /* sbw */ + 2 /* setcurrentpoint */ + }; + + + static FT_Error + cff_operator_seac( CFF_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + CFF_Builder* builder = &decoder->builder; + FT_Int bchar_index, achar_index; + TT_Face face = decoder->builder.face; + FT_Vector left_bearing, advance; + FT_Byte* charstring; + FT_ULong charstring_len; + FT_Pos glyph_width; + + + if ( decoder->seac ) + { + FT_ERROR(( "cff_operator_seac: invalid nested seac\n" )); + return FT_THROW( Syntax_Error ); + } + + adx = ADD_LONG( adx, decoder->builder.left_bearing.x ); + ady = ADD_LONG( ady, decoder->builder.left_bearing.y ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Incremental fonts don't necessarily have valid charsets. */ + /* They use the character code, not the glyph index, in this case. */ + if ( face->root.internal->incremental_interface ) + { + bchar_index = bchar; + achar_index = achar; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + CFF_Font cff = (CFF_Font)( face->extra.data ); + + + bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar ); + achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar ); + } + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "cff_operator_seac:" + " invalid seac character code arguments\n" )); + return FT_THROW( Syntax_Error ); + } + + /* If we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( builder->no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)builder->glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)( adx >> 16 ); + subg->arg2 = (FT_Int)( ady >> 16 ); + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + } + + FT_GlyphLoader_Prepare( builder->loader ); + + /* First load `bchar' in builder */ + error = decoder->get_glyph_callback( face, (FT_UInt)bchar_index, + &charstring, &charstring_len ); + if ( !error ) + { + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len, 0 ); + decoder->seac = FALSE; + + decoder->free_glyph_callback( face, &charstring, charstring_len ); + + if ( error ) + goto Exit; + } + + /* Save the left bearing, advance and glyph width of the base */ + /* character as they will be erased by the next load. */ + + left_bearing = builder->left_bearing; + advance = builder->advance; + glyph_width = decoder->glyph_width; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + + builder->pos_x = SUB_LONG( adx, asb ); + builder->pos_y = ady; + + /* Now load `achar' on top of the base outline. */ + error = decoder->get_glyph_callback( face, (FT_UInt)achar_index, + &charstring, &charstring_len ); + if ( !error ) + { + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len, 0 ); + decoder->seac = FALSE; + + decoder->free_glyph_callback( face, &charstring, charstring_len ); + + if ( error ) + goto Exit; + } + + /* Restore the left side bearing, advance and glyph width */ + /* of the base character. */ + builder->left_bearing = left_bearing; + builder->advance = advance; + decoder->glyph_width = glyph_width; + + builder->pos_x = 0; + builder->pos_y = 0; + + Exit: + return error; + } + +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRING PARSING *********/ + /********** *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * cff_compute_bias + * + * @Description: + * Computes the bias value in dependence of the number of glyph + * subroutines. + * + * @Input: + * in_charstring_type :: + * The `CharstringType' value of the top DICT + * dictionary. + * + * num_subrs :: + * The number of glyph subroutines. + * + * @Return: + * The bias value. + */ + static FT_Int + cff_compute_bias( FT_Int in_charstring_type, + FT_UInt num_subrs ) + { + FT_Int result; + + + if ( in_charstring_type == 1 ) + result = 0; + else if ( num_subrs < 1240 ) + result = 107; + else if ( num_subrs < 33900U ) + result = 1131; + else + result = 32768U; + + return result; + } + + + FT_LOCAL_DEF( FT_Int ) + cff_lookup_glyph_by_stdcharcode( CFF_Font cff, + FT_Int charcode ) + { + FT_UInt n; + FT_UShort glyph_sid; + + FT_Service_CFFLoad cffload; + + + /* CID-keyed fonts don't have glyph names */ + if ( !cff->charset.sids ) + return -1; + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + +#if 0 + /* retrieve cffload from list of current modules */ + FT_Service_CFFLoad cffload; + + + FT_FACE_FIND_GLOBAL_SERVICE( face, cffload, CFF_LOAD ); + if ( !cffload ) + { + FT_ERROR(( "cff_lookup_glyph_by_stdcharcode:" + " the `cffload' module is not available\n" )); + return FT_THROW( Unimplemented_Feature ); + } +#endif + + cffload = (FT_Service_CFFLoad)cff->cffload; + + /* Get code to SID mapping from `cff_standard_encoding'. */ + glyph_sid = cffload->get_standard_encoding( (FT_UInt)charcode ); + + for ( n = 0; n < cff->num_glyphs; n++ ) + { + if ( cff->charset.sids[n] == glyph_sid ) + return (FT_Int)n; + } + + return -1; + } + + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + + /************************************************************************** + * + * @Function: + * cff_decoder_parse_charstrings + * + * @Description: + * Parses a given Type 2 charstrings program. + * + * @InOut: + * decoder :: + * The current Type 1 decoder. + * + * @Input: + * charstring_base :: + * The base of the charstring stream. + * + * charstring_len :: + * The length in bytes of the charstring stream. + * + * in_dict :: + * Set to 1 if function is called from top or + * private DICT (needed for Multiple Master CFFs). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len, + FT_Bool in_dict ) + { + FT_Error error; + CFF_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + CFF_Builder* builder = &decoder->builder; + FT_Pos x, y; + FT_Fixed* stack; + FT_Int charstring_type = + decoder->cff->top_font.font_dict.charstring_type; + FT_UShort num_designs = + decoder->cff->top_font.font_dict.num_designs; + FT_UShort num_axes = + decoder->cff->top_font.font_dict.num_axes; + + T2_Hints_Funcs hinter; + + + /* set default width */ + decoder->num_hints = 0; + decoder->read_width = 1; + + /* initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + stack = decoder->top; + + hinter = (T2_Hints_Funcs)builder->hints_funcs; + + builder->path_begun = 0; + + if ( !charstring_base ) + return FT_Err_Ok; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = FT_Err_Ok; + + x = builder->pos_x; + y = builder->pos_y; + + /* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); + + /* now execute loop */ + while ( ip < limit ) + { + CFF_Operator op; + FT_Byte v; + + + /********************************************************************* + * + * Decode operator or operand + */ + v = *ip++; + if ( v >= 32 || v == 28 ) + { + FT_Int shift = 16; + FT_Int32 val; + + + /* this is an operand, push it on the stack */ + + /* if we use shifts, all computations are done with unsigned */ + /* values; the conversion to a signed value is the last step */ + if ( v == 28 ) + { + if ( ip + 1 >= limit ) + goto Syntax_Error; + val = (FT_Short)( ( (FT_UShort)ip[0] << 8 ) | ip[1] ); + ip += 2; + } + else if ( v < 247 ) + val = (FT_Int32)v - 139; + else if ( v < 251 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = ( (FT_Int32)v - 247 ) * 256 + *ip++ + 108; + } + else if ( v < 255 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = -( (FT_Int32)v - 251 ) * 256 - *ip++ - 108; + } + else + { + if ( ip + 3 >= limit ) + goto Syntax_Error; + val = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) | + ( (FT_UInt32)ip[1] << 16 ) | + ( (FT_UInt32)ip[2] << 8 ) | + (FT_UInt32)ip[3] ); + ip += 4; + if ( charstring_type == 2 ) + shift = 0; + } + if ( decoder->top - stack >= CFF_MAX_OPERANDS ) + goto Stack_Overflow; + + val = (FT_Int32)( (FT_UInt32)val << shift ); + *decoder->top++ = val; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( val & 0xFFFFL ) ) + FT_TRACE4(( " %hd", (FT_Short)( (FT_UInt32)val >> 16 ) )); + else + FT_TRACE4(( " %.5f", val / 65536.0 )); +#endif + + } + else + { + /* The specification says that normally arguments are to be taken */ + /* from the bottom of the stack. However, this seems not to be */ + /* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */ + /* arguments similar to a PS interpreter. */ + + FT_Fixed* args = decoder->top; + FT_Int num_args = (FT_Int)( args - decoder->stack ); + FT_Int req_args; + + + /* find operator */ + op = cff_op_unknown; + + switch ( v ) + { + case 1: + op = cff_op_hstem; + break; + case 3: + op = cff_op_vstem; + break; + case 4: + op = cff_op_vmoveto; + break; + case 5: + op = cff_op_rlineto; + break; + case 6: + op = cff_op_hlineto; + break; + case 7: + op = cff_op_vlineto; + break; + case 8: + op = cff_op_rrcurveto; + break; + case 9: + op = cff_op_closepath; + break; + case 10: + op = cff_op_callsubr; + break; + case 11: + op = cff_op_return; + break; + case 12: + if ( ip >= limit ) + goto Syntax_Error; + v = *ip++; + + switch ( v ) + { + case 0: + op = cff_op_dotsection; + break; + case 1: /* this is actually the Type1 vstem3 operator */ + op = cff_op_vstem; + break; + case 2: /* this is actually the Type1 hstem3 operator */ + op = cff_op_hstem; + break; + case 3: + op = cff_op_and; + break; + case 4: + op = cff_op_or; + break; + case 5: + op = cff_op_not; + break; + case 6: + op = cff_op_seac; + break; + case 7: + op = cff_op_sbw; + break; + case 8: + op = cff_op_store; + break; + case 9: + op = cff_op_abs; + break; + case 10: + op = cff_op_add; + break; + case 11: + op = cff_op_sub; + break; + case 12: + op = cff_op_div; + break; + case 13: + op = cff_op_load; + break; + case 14: + op = cff_op_neg; + break; + case 15: + op = cff_op_eq; + break; + case 16: + op = cff_op_callothersubr; + break; + case 17: + op = cff_op_pop; + break; + case 18: + op = cff_op_drop; + break; + case 20: + op = cff_op_put; + break; + case 21: + op = cff_op_get; + break; + case 22: + op = cff_op_ifelse; + break; + case 23: + op = cff_op_random; + break; + case 24: + op = cff_op_mul; + break; + case 26: + op = cff_op_sqrt; + break; + case 27: + op = cff_op_dup; + break; + case 28: + op = cff_op_exch; + break; + case 29: + op = cff_op_index; + break; + case 30: + op = cff_op_roll; + break; + case 33: + op = cff_op_setcurrentpoint; + break; + case 34: + op = cff_op_hflex; + break; + case 35: + op = cff_op_flex; + break; + case 36: + op = cff_op_hflex1; + break; + case 37: + op = cff_op_flex1; + break; + default: + FT_TRACE4(( " unknown op (12, %d)\n", v )); + break; + } + break; + case 13: + op = cff_op_hsbw; + break; + case 14: + op = cff_op_endchar; + break; + case 16: + op = cff_op_blend; + break; + case 18: + op = cff_op_hstemhm; + break; + case 19: + op = cff_op_hintmask; + break; + case 20: + op = cff_op_cntrmask; + break; + case 21: + op = cff_op_rmoveto; + break; + case 22: + op = cff_op_hmoveto; + break; + case 23: + op = cff_op_vstemhm; + break; + case 24: + op = cff_op_rcurveline; + break; + case 25: + op = cff_op_rlinecurve; + break; + case 26: + op = cff_op_vvcurveto; + break; + case 27: + op = cff_op_hhcurveto; + break; + case 29: + op = cff_op_callgsubr; + break; + case 30: + op = cff_op_vhcurveto; + break; + case 31: + op = cff_op_hvcurveto; + break; + default: + FT_TRACE4(( " unknown op (%d)\n", v )); + break; + } + + if ( op == cff_op_unknown ) + continue; + + /* in Multiple Master CFFs, T2 charstrings can appear in */ + /* dictionaries, but some operators are prohibited */ + if ( in_dict ) + { + switch ( op ) + { + case cff_op_hstem: + case cff_op_vstem: + case cff_op_vmoveto: + case cff_op_rlineto: + case cff_op_hlineto: + case cff_op_vlineto: + case cff_op_rrcurveto: + case cff_op_hstemhm: + case cff_op_hintmask: + case cff_op_cntrmask: + case cff_op_rmoveto: + case cff_op_hmoveto: + case cff_op_vstemhm: + case cff_op_rcurveline: + case cff_op_rlinecurve: + case cff_op_vvcurveto: + case cff_op_hhcurveto: + case cff_op_vhcurveto: + case cff_op_hvcurveto: + case cff_op_hflex: + case cff_op_flex: + case cff_op_hflex1: + case cff_op_flex1: + case cff_op_callsubr: + case cff_op_callgsubr: + /* deprecated opcodes */ + case cff_op_dotsection: + /* invalid Type 1 opcodes */ + case cff_op_hsbw: + case cff_op_closepath: + case cff_op_callothersubr: + case cff_op_seac: + case cff_op_sbw: + case cff_op_setcurrentpoint: + goto MM_Error; + + default: + break; + } + } + + /* check arguments */ + req_args = cff_argument_counts[op]; + if ( req_args & CFF_COUNT_CHECK_WIDTH ) + { + if ( num_args > 0 && decoder->read_width ) + { + /* If `nominal_width' is non-zero, the number is really a */ + /* difference against `nominal_width'. Else, the number here */ + /* is truly a width, not a difference against `nominal_width'. */ + /* If the font does not set `nominal_width', then */ + /* `nominal_width' defaults to zero, and so we can set */ + /* `glyph_width' to `nominal_width' plus number on the stack */ + /* -- for either case. */ + + FT_Int set_width_ok; + + + switch ( op ) + { + case cff_op_hmoveto: + case cff_op_vmoveto: + set_width_ok = num_args & 2; + break; + + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: + case cff_op_rmoveto: + case cff_op_hintmask: + case cff_op_cntrmask: + set_width_ok = num_args & 1; + break; + + case cff_op_endchar: + /* If there is a width specified for endchar, we either have */ + /* 1 argument or 5 arguments. We like to argue. */ + set_width_ok = in_dict + ? 0 + : ( ( num_args == 5 ) || ( num_args == 1 ) ); + break; + + default: + set_width_ok = 0; + break; + } + + if ( set_width_ok ) + { + decoder->glyph_width = decoder->nominal_width + + ( stack[0] >> 16 ); + + if ( decoder->width_only ) + { + /* we only want the advance width; stop here */ + break; + } + + /* Consumed an argument. */ + num_args--; + } + } + + decoder->read_width = 0; + req_args = 0; + } + + req_args &= 0x000F; + if ( num_args < req_args ) + goto Stack_Underflow; + args -= req_args; + num_args -= req_args; + + /* At this point, `args' points to the first argument of the */ + /* operand in case `req_args' isn't zero. Otherwise, we have */ + /* to adjust `args' manually. */ + + /* Note that we only pop arguments from the stack which we */ + /* really need and can digest so that we can continue in case */ + /* of superfluous stack elements. */ + + switch ( op ) + { + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: + /* the number of arguments is always even here */ + FT_TRACE4(( "%s\n", + op == cff_op_hstem ? " hstem" : + ( op == cff_op_vstem ? " vstem" : + ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) )); + + if ( hinter ) + hinter->stems( hinter->hints, + ( op == cff_op_hstem || op == cff_op_hstemhm ), + num_args / 2, + args - ( num_args & ~1 ) ); + + decoder->num_hints += num_args / 2; + args = stack; + break; + + case cff_op_hintmask: + case cff_op_cntrmask: + FT_TRACE4(( "%s", op == cff_op_hintmask ? " hintmask" + : " cntrmask" )); + + /* implement vstem when needed -- */ + /* the specification doesn't say it, but this also works */ + /* with the 'cntrmask' operator */ + /* */ + if ( num_args > 0 ) + { + if ( hinter ) + hinter->stems( hinter->hints, + 0, + num_args / 2, + args - ( num_args & ~1 ) ); + + decoder->num_hints += num_args / 2; + } + + /* In a valid charstring there must be at least one byte */ + /* after `hintmask' or `cntrmask' (e.g., for a `return' */ + /* instruction). Additionally, there must be space for */ + /* `num_hints' bits. */ + + if ( ( ip + ( ( decoder->num_hints + 7 ) >> 3 ) ) >= limit ) + goto Syntax_Error; + + if ( hinter ) + { + if ( op == cff_op_hintmask ) + hinter->hintmask( hinter->hints, + (FT_UInt)builder->current->n_points, + (FT_UInt)decoder->num_hints, + ip ); + else + hinter->counter( hinter->hints, + (FT_UInt)decoder->num_hints, + ip ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt maskbyte; + + + FT_TRACE4(( " (maskbytes:" )); + + for ( maskbyte = 0; + maskbyte < (FT_UInt)( ( decoder->num_hints + 7 ) >> 3 ); + maskbyte++, ip++ ) + FT_TRACE4(( " 0x%02X", *ip )); + + FT_TRACE4(( ")\n" )); + } +#else + ip += ( decoder->num_hints + 7 ) >> 3; +#endif + args = stack; + break; + + case cff_op_rmoveto: + FT_TRACE4(( " rmoveto\n" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x = ADD_LONG( x, args[-2] ); + y = ADD_LONG( y, args[-1] ); + args = stack; + break; + + case cff_op_vmoveto: + FT_TRACE4(( " vmoveto\n" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + y = ADD_LONG( y, args[-1] ); + args = stack; + break; + + case cff_op_hmoveto: + FT_TRACE4(( " hmoveto\n" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x = ADD_LONG( x, args[-1] ); + args = stack; + break; + + case cff_op_rlineto: + FT_TRACE4(( " rlineto\n" )); + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_args / 2 ) ) + goto Fail; + + if ( num_args < 2 ) + goto Stack_Underflow; + + args -= num_args & ~1; + while ( args < decoder->top ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 1 ); + args += 2; + } + args = stack; + break; + + case cff_op_hlineto: + case cff_op_vlineto: + { + FT_Int phase = ( op == cff_op_hlineto ); + + + FT_TRACE4(( "%s\n", op == cff_op_hlineto ? " hlineto" + : " vlineto" )); + + if ( num_args < 0 ) + goto Stack_Underflow; + + /* there exist subsetted fonts (found in PDFs) */ + /* which call `hlineto' without arguments */ + if ( num_args == 0 ) + break; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_args ) ) + goto Fail; + + args = stack; + while ( args < decoder->top ) + { + if ( phase ) + x = ADD_LONG( x, args[0] ); + else + y = ADD_LONG( y, args[0] ); + + if ( cff_builder_add_point1( builder, x, y ) ) + goto Fail; + + args++; + phase ^= 1; + } + args = stack; + } + break; + + case cff_op_rrcurveto: + { + FT_Int nargs; + + + FT_TRACE4(( " rrcurveto\n" )); + + if ( num_args < 6 ) + goto Stack_Underflow; + + nargs = num_args - num_args % 6; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, nargs / 2 ) ) + goto Fail; + + args -= nargs; + while ( args < decoder->top ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[4] ); + y = ADD_LONG( y, args[5] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 6; + } + args = stack; + } + break; + + case cff_op_vvcurveto: + { + FT_Int nargs; + + + FT_TRACE4(( " vvcurveto\n" )); + + if ( num_args < 4 ) + goto Stack_Underflow; + + /* if num_args isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + + nargs = num_args & ~2; + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args -= nargs; + + if ( nargs & 1 ) + { + x = ADD_LONG( x, args[0] ); + args++; + nargs--; + } + + if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + y = ADD_LONG( y, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 4; + } + args = stack; + } + break; + + case cff_op_hhcurveto: + { + FT_Int nargs; + + + FT_TRACE4(( " hhcurveto\n" )); + + if ( num_args < 4 ) + goto Stack_Underflow; + + /* if num_args isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + + nargs = num_args & ~2; + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args -= nargs; + if ( nargs & 1 ) + { + y = ADD_LONG( y, args[0] ); + args++; + nargs--; + } + + if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + x = ADD_LONG( x, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[3] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 4; + } + args = stack; + } + break; + + case cff_op_vhcurveto: + case cff_op_hvcurveto: + { + FT_Int phase; + FT_Int nargs; + + + FT_TRACE4(( "%s\n", op == cff_op_vhcurveto ? " vhcurveto" + : " hvcurveto" )); + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + if ( num_args < 4 ) + goto Stack_Underflow; + + /* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */ + /* we enforce it by clearing the second bit */ + + nargs = num_args & ~2; + + args -= nargs; + if ( cff_check_points( builder, ( nargs / 4 ) * 3 ) ) + goto Stack_Underflow; + + phase = ( op == cff_op_hvcurveto ); + + while ( nargs >= 4 ) + { + nargs -= 4; + if ( phase ) + { + x = ADD_LONG( x, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + y = ADD_LONG( y, args[3] ); + if ( nargs == 1 ) + x = ADD_LONG( x, args[4] ); + cff_builder_add_point( builder, x, y, 1 ); + } + else + { + y = ADD_LONG( y, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[3] ); + if ( nargs == 1 ) + y = ADD_LONG( y, args[4] ); + cff_builder_add_point( builder, x, y, 1 ); + } + args += 4; + phase ^= 1; + } + args = stack; + } + break; + + case cff_op_rlinecurve: + { + FT_Int num_lines; + FT_Int nargs; + + + FT_TRACE4(( " rlinecurve\n" )); + + if ( num_args < 8 ) + goto Stack_Underflow; + + nargs = num_args & ~1; + num_lines = ( nargs - 6 ) / 2; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_lines + 3 ) ) + goto Fail; + + args -= nargs; + + /* first, add the line segments */ + while ( num_lines > 0 ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 2; + num_lines--; + } + + /* then the curve */ + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[4] ); + y = ADD_LONG( y, args[5] ); + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + } + break; + + case cff_op_rcurveline: + { + FT_Int num_curves; + FT_Int nargs; + + + FT_TRACE4(( " rcurveline\n" )); + + if ( num_args < 8 ) + goto Stack_Underflow; + + nargs = num_args - 2; + nargs = nargs - nargs % 6 + 2; + num_curves = ( nargs - 2 ) / 6; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_curves * 3 + 2 ) ) + goto Fail; + + args -= nargs; + + /* first, add the curves */ + while ( num_curves > 0 ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[4] ); + y = ADD_LONG( y, args[5] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 6; + num_curves--; + } + + /* then the final line */ + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + } + break; + + case cff_op_hflex1: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex1\n" )); + + /* adding five more points: 4 control points, 1 on-curve point */ + /* -- make sure we have enough space for the start point if it */ + /* needs to be added */ + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's y position for later use */ + start_y = y; + + /* first control point */ + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* second control point */ + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x = ADD_LONG( x, args[4] ); + cff_builder_add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x = ADD_LONG( x, args[5] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* fourth control point */ + x = ADD_LONG( x, args[6] ); + y = ADD_LONG( y, args[7] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start */ + x = ADD_LONG( x, args[8] ); + y = start_y; + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_hflex: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex\n" )); + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's y-position for later use */ + start_y = y; + + /* first control point */ + x = ADD_LONG( x, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* second control point */ + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x = ADD_LONG( x, args[3] ); + cff_builder_add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x = ADD_LONG( x, args[4] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* fourth control point */ + x = ADD_LONG( x, args[5] ); + y = start_y; + cff_builder_add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start point's */ + /* y-value -- we don't add this point, though */ + x = ADD_LONG( x, args[6] ); + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_flex1: + { + FT_Pos start_x, start_y; /* record start x, y values for */ + /* alter use */ + FT_Fixed dx = 0, dy = 0; /* used in horizontal/vertical */ + /* algorithm below */ + FT_Int horizontal, count; + FT_Fixed* temp; + + + FT_TRACE4(( " flex1\n" )); + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's x, y position for later use */ + start_x = x; + start_y = y; + + /* XXX: figure out whether this is supposed to be a horizontal */ + /* or vertical flex; the Type 2 specification is vague... */ + + temp = args; + + /* grab up to the last argument */ + for ( count = 5; count > 0; count-- ) + { + dx = ADD_LONG( dx, temp[0] ); + dy = ADD_LONG( dy, temp[1] ); + temp += 2; + } + + if ( dx < 0 ) + dx = NEG_LONG( dx ); + if ( dy < 0 ) + dy = NEG_LONG( dy ); + + /* strange test, but here it is... */ + horizontal = ( dx > dy ); + + for ( count = 5; count > 0; count-- ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, + FT_BOOL( count == 3 ) ); + args += 2; + } + + /* is last operand an x- or y-delta? */ + if ( horizontal ) + { + x = ADD_LONG( x, args[0] ); + y = start_y; + } + else + { + x = start_x; + y = ADD_LONG( y, args[0] ); + } + + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_flex: + { + FT_UInt count; + + + FT_TRACE4(( " flex\n" )); + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + for ( count = 6; count > 0; count-- ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, + FT_BOOL( count == 4 || count == 1 ) ); + args += 2; + } + + args = stack; + } + break; + + case cff_op_seac: + FT_TRACE4(( " seac\n" )); + + error = cff_operator_seac( decoder, + args[0], args[1], args[2], + (FT_Int)( args[3] >> 16 ), + (FT_Int)( args[4] >> 16 ) ); + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* return now! */ + FT_TRACE4(( "\n" )); + return error; + + case cff_op_endchar: + /* in dictionaries, `endchar' simply indicates end of data */ + if ( in_dict ) + return error; + + FT_TRACE4(( " endchar\n" )); + + /* We are going to emulate the seac operator. */ + if ( num_args >= 4 ) + { + /* Save glyph width so that the subglyphs don't overwrite it. */ + FT_Pos glyph_width = decoder->glyph_width; + + + error = cff_operator_seac( decoder, + 0L, args[-4], args[-3], + (FT_Int)( args[-2] >> 16 ), + (FT_Int)( args[-1] >> 16 ) ); + + decoder->glyph_width = glyph_width; + } + else + { + cff_builder_close_contour( builder ); + + /* close hints recording session */ + if ( hinter ) + { + if ( hinter->close( hinter->hints, + (FT_UInt)builder->current->n_points ) ) + goto Syntax_Error; + + /* apply hints to the loaded glyph outline now */ + error = hinter->apply( hinter->hints, + builder->current, + (PSH_Globals)builder->hints_globals, + decoder->hint_mode ); + if ( error ) + goto Fail; + } + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + } + + /* return now! */ + FT_TRACE4(( "\n" )); + return error; + + case cff_op_abs: + FT_TRACE4(( " abs\n" )); + + if ( args[0] < 0 ) + { + if ( args[0] == FT_LONG_MIN ) + args[0] = FT_LONG_MAX; + else + args[0] = -args[0]; + } + args++; + break; + + case cff_op_add: + FT_TRACE4(( " add\n" )); + + args[0] = ADD_LONG( args[0], args[1] ); + args++; + break; + + case cff_op_sub: + FT_TRACE4(( " sub\n" )); + + args[0] = SUB_LONG( args[0], args[1] ); + args++; + break; + + case cff_op_div: + FT_TRACE4(( " div\n" )); + + args[0] = FT_DivFix( args[0], args[1] ); + args++; + break; + + case cff_op_neg: + FT_TRACE4(( " neg\n" )); + + if ( args[0] == FT_LONG_MIN ) + args[0] = FT_LONG_MAX; + args[0] = -args[0]; + args++; + break; + + case cff_op_random: + { + FT_UInt32* randval = in_dict ? &decoder->cff->top_font.random + : &decoder->current_subfont->random; + + + FT_TRACE4(( " random\n" )); + + /* only use the lower 16 bits of `random' */ + /* to generate a number in the range (0;1] */ + args[0] = (FT_Fixed)( ( *randval & 0xFFFF ) + 1 ); + args++; + + *randval = cff_random( *randval ); + } + break; + + case cff_op_mul: + FT_TRACE4(( " mul\n" )); + + args[0] = FT_MulFix( args[0], args[1] ); + args++; + break; + + case cff_op_sqrt: + FT_TRACE4(( " sqrt\n" )); + + /* without upper limit the loop below might not finish */ + if ( args[0] > 0x7FFFFFFFL ) + args[0] = 46341; + else if ( args[0] > 0 ) + { + FT_Fixed root = args[0]; + FT_Fixed new_root; + + + for (;;) + { + new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1; + if ( new_root == root ) + break; + root = new_root; + } + args[0] = new_root; + } + else + args[0] = 0; + args++; + break; + + case cff_op_drop: + /* nothing */ + FT_TRACE4(( " drop\n" )); + + break; + + case cff_op_exch: + { + FT_Fixed tmp; + + + FT_TRACE4(( " exch\n" )); + + tmp = args[0]; + args[0] = args[1]; + args[1] = tmp; + args += 2; + } + break; + + case cff_op_index: + { + FT_Int idx = (FT_Int)( args[0] >> 16 ); + + + FT_TRACE4(( " index\n" )); + + if ( idx < 0 ) + idx = 0; + else if ( idx > num_args - 2 ) + idx = num_args - 2; + args[0] = args[-( idx + 1 )]; + args++; + } + break; + + case cff_op_roll: + { + FT_Int count = (FT_Int)( args[0] >> 16 ); + FT_Int idx = (FT_Int)( args[1] >> 16 ); + + + FT_TRACE4(( " roll\n" )); + + if ( count <= 0 ) + count = 1; + + args -= count; + if ( args < stack ) + goto Stack_Underflow; + + if ( idx >= 0 ) + { + idx = idx % count; + while ( idx > 0 ) + { + FT_Fixed tmp = args[count - 1]; + FT_Int i; + + + for ( i = count - 2; i >= 0; i-- ) + args[i + 1] = args[i]; + args[0] = tmp; + idx--; + } + } + else + { + /* before C99 it is implementation-defined whether */ + /* the result of `%' is negative if the first operand */ + /* is negative */ + idx = -( NEG_INT( idx ) % count ); + while ( idx < 0 ) + { + FT_Fixed tmp = args[0]; + FT_Int i; + + + for ( i = 0; i < count - 1; i++ ) + args[i] = args[i + 1]; + args[count - 1] = tmp; + idx++; + } + } + args += count; + } + break; + + case cff_op_dup: + FT_TRACE4(( " dup\n" )); + + args[1] = args[0]; + args += 2; + break; + + case cff_op_put: + { + FT_Fixed val = args[0]; + FT_UInt idx = (FT_UInt)( args[1] >> 16 ); + + + FT_TRACE4(( " put\n" )); + + /* the Type2 specification before version 16-March-2000 */ + /* didn't give a hard-coded size limit of the temporary */ + /* storage array; instead, an argument of the */ + /* `MultipleMaster' operator set the size */ + if ( idx < CFF_MAX_TRANS_ELEMENTS ) + decoder->buildchar[idx] = val; + } + break; + + case cff_op_get: + { + FT_UInt idx = (FT_UInt)( args[0] >> 16 ); + FT_Fixed val = 0; + + + FT_TRACE4(( " get\n" )); + + if ( idx < CFF_MAX_TRANS_ELEMENTS ) + val = decoder->buildchar[idx]; + + args[0] = val; + args++; + } + break; + + case cff_op_store: + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, this is a no-op */ + FT_TRACE4(( " store\n" )); + break; + + case cff_op_load: + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + { + FT_UInt reg_idx = (FT_UInt)args[0]; + FT_UInt idx = (FT_UInt)args[1]; + FT_UInt count = (FT_UInt)args[2]; + + + FT_TRACE4(( " load\n" )); + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, we store a vector [1 0 0 ...] in the */ + /* temporary storage array regardless of the Registry index */ + if ( reg_idx <= 2 && + idx < CFF_MAX_TRANS_ELEMENTS && + count <= num_axes ) + { + FT_UInt end, i; + + + end = FT_MIN( idx + count, CFF_MAX_TRANS_ELEMENTS ); + + if ( idx < end ) + decoder->buildchar[idx] = 1 << 16; + + for ( i = idx + 1; i < end; i++ ) + decoder->buildchar[i] = 0; + } + } + break; + + case cff_op_blend: + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + if ( num_designs ) + { + FT_Int num_results = (FT_Int)( args[0] >> 16 ); + + + FT_TRACE4(( " blend\n" )); + + if ( num_results < 0 ) + goto Syntax_Error; + + if ( num_results > num_args || + num_results * (FT_Int)num_designs > num_args ) + goto Stack_Underflow; + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, return the `num_results' values of the */ + /* first master */ + args -= num_results * ( num_designs - 1 ); + num_args -= num_results * ( num_designs - 1 ); + } + else + goto Syntax_Error; + break; + + case cff_op_dotsection: + /* this operator is deprecated and ignored by the parser */ + FT_TRACE4(( " dotsection\n" )); + break; + + case cff_op_closepath: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " closepath (invalid op)\n" )); + + args = stack; + break; + + case cff_op_hsbw: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " hsbw (invalid op)\n" )); + + decoder->glyph_width = + ADD_LONG( decoder->nominal_width, ( args[1] >> 16 ) ); + + decoder->builder.left_bearing.x = args[0]; + decoder->builder.left_bearing.y = 0; + + x = ADD_LONG( decoder->builder.pos_x, args[0] ); + y = decoder->builder.pos_y; + args = stack; + break; + + case cff_op_sbw: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " sbw (invalid op)\n" )); + + decoder->glyph_width = + ADD_LONG( decoder->nominal_width, ( args[2] >> 16 ) ); + + decoder->builder.left_bearing.x = args[0]; + decoder->builder.left_bearing.y = args[1]; + + x = ADD_LONG( decoder->builder.pos_x, args[0] ); + y = ADD_LONG( decoder->builder.pos_y, args[1] ); + args = stack; + break; + + case cff_op_setcurrentpoint: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " setcurrentpoint (invalid op)\n" )); + + x = ADD_LONG( decoder->builder.pos_x, args[0] ); + y = ADD_LONG( decoder->builder.pos_y, args[1] ); + args = stack; + break; + + case cff_op_callothersubr: + { + FT_Fixed arg; + + + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from */ + /* probably Type 1 to CFF, and some parsers seem to accept */ + /* it */ + + FT_TRACE4(( " callothersubr (invalid op)\n" )); + + /* subsequent `pop' operands should add the arguments, */ + /* this is the implementation described for `unknown' */ + /* other subroutines in the Type1 spec. */ + /* */ + /* XXX Fix return arguments (see discussion below). */ + + arg = 2 + ( args[-2] >> 16 ); + if ( arg >= CFF_MAX_OPERANDS ) + goto Stack_Underflow; + + args -= arg; + if ( args < stack ) + goto Stack_Underflow; + } + break; + + case cff_op_pop: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " pop (invalid op)\n" )); + + /* XXX Increasing `args' is wrong: After a certain number of */ + /* `pop's we get a stack overflow. Reason for doing it is */ + /* code like this (actually found in a CFF font): */ + /* */ + /* 17 1 3 callothersubr */ + /* pop */ + /* callsubr */ + /* */ + /* Since we handle `callothersubr' as a no-op, and */ + /* `callsubr' needs at least one argument, `pop' can't be a */ + /* no-op too as it basically should be. */ + /* */ + /* The right solution would be to provide real support for */ + /* `callothersubr' as done in `t1decode.c', however, given */ + /* the fact that CFF fonts with `pop' are invalid, it is */ + /* questionable whether it is worth the time. */ + args++; + break; + + case cff_op_and: + { + FT_Fixed cond = ( args[0] && args[1] ); + + + FT_TRACE4(( " and\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_or: + { + FT_Fixed cond = ( args[0] || args[1] ); + + + FT_TRACE4(( " or\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_not: + { + FT_Fixed cond = !args[0]; + + + FT_TRACE4(( " not\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_eq: + { + FT_Fixed cond = ( args[0] == args[1] ); + + + FT_TRACE4(( " eq\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_ifelse: + { + FT_Fixed cond = ( args[2] <= args[3] ); + + + FT_TRACE4(( " ifelse\n" )); + + if ( !cond ) + args[0] = args[1]; + args++; + } + break; + + case cff_op_callsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->locals_bias ); + + + FT_TRACE4(( " callsubr (idx %d, entering level %td)\n", + idx, + zone - decoder->zones + 1 )); + + if ( idx >= decoder->num_locals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid local subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->locals[idx]; + zone->limit = decoder->locals[idx + 1]; + zone->cursor = zone->base; + + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case cff_op_callgsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->globals_bias ); + + + FT_TRACE4(( " callgsubr (idx %d, entering level %td)\n", + idx, + zone - decoder->zones + 1 )); + + if ( idx >= decoder->num_globals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid global subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->globals[idx]; + zone->limit = decoder->globals[idx + 1]; + zone->cursor = zone->base; + + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case cff_op_return: + FT_TRACE4(( " return (leaving level %td)\n", + decoder->zone - decoder->zones )); + + if ( decoder->zone <= decoder->zones ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " unexpected return\n" )); + goto Syntax_Error; + } + + decoder->zone--; + zone = decoder->zone; + ip = zone->cursor; + limit = zone->limit; + break; + + default: + FT_ERROR(( "Unimplemented opcode: %d", ip[-1] )); + + if ( ip[-1] == 12 ) + FT_ERROR(( " %d", ip[0] )); + FT_ERROR(( "\n" )); + + return FT_THROW( Unimplemented_Feature ); + } + + decoder->top = args; + + if ( decoder->top - stack >= CFF_MAX_OPERANDS ) + goto Stack_Overflow; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); + + Fail: + return error; + + MM_Error: + FT_TRACE4(( "cff_decoder_parse_charstrings:" + " invalid opcode found in top DICT charstring\n")); + return FT_THROW( Invalid_File_Format ); + + Syntax_Error: + FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" )); + return FT_THROW( Invalid_File_Format ); + + Stack_Underflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow\n" )); + return FT_THROW( Too_Few_Arguments ); + + Stack_Overflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow\n" )); + return FT_THROW( Stack_Overflow ); + } + +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + + + /************************************************************************** + * + * @Function: + * cff_decoder_init + * + * @Description: + * Initializes a given glyph decoder. + * + * @InOut: + * decoder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * slot :: + * The current glyph object. + * + * hinting :: + * Whether hinting is active. + * + * hint_mode :: + * The hinting mode. + */ + FT_LOCAL_DEF( void ) + cff_decoder_init( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode, + CFF_Decoder_Get_Glyph_Callback get_callback, + CFF_Decoder_Free_Glyph_Callback free_callback ) + { + CFF_Font cff = (CFF_Font)face->extra.data; + + + /* clear everything */ + FT_ZERO( decoder ); + + /* initialize builder */ + cff_builder_init( &decoder->builder, face, size, slot, hinting ); + + /* initialize Type2 decoder */ + decoder->cff = cff; + decoder->num_globals = cff->global_subrs_index.count; + decoder->globals = cff->global_subrs; + decoder->globals_bias = cff_compute_bias( + cff->top_font.font_dict.charstring_type, + decoder->num_globals ); + + decoder->hint_mode = hint_mode; + + decoder->get_glyph_callback = get_callback; + decoder->free_glyph_callback = free_callback; + } + + + /* this function is used to select the subfont */ + /* and the locals subrs array */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ) + { + CFF_Builder *builder = &decoder->builder; + CFF_Font cff = (CFF_Font)builder->face->extra.data; + CFF_SubFont sub = &cff->top_font; + FT_Error error = FT_Err_Ok; + + FT_Service_CFFLoad cffload = (FT_Service_CFFLoad)cff->cffload; + + + /* manage CID fonts */ + if ( cff->num_subfonts ) + { + FT_Byte fd_index = cffload->fd_select_get( &cff->fd_select, + glyph_index ); + + + if ( fd_index >= cff->num_subfonts ) + { + FT_TRACE4(( "cff_decoder_prepare: invalid CID subfont index\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_TRACE3(( " in subfont %d:\n", fd_index )); + + sub = cff->subfonts[fd_index]; + + if ( builder->hints_funcs && size ) + { + FT_Size ftsize = FT_SIZE( size ); + CFF_Internal internal = (CFF_Internal)ftsize->internal->module_data; + + + /* for CFFs without subfonts, this value has already been set */ + builder->hints_globals = (void *)internal->subfonts[fd_index]; + } + } + + decoder->num_locals = sub->local_subrs_index.count; + decoder->locals = sub->local_subrs; + decoder->locals_bias = cff_compute_bias( + decoder->cff->top_font.font_dict.charstring_type, + decoder->num_locals ); + + decoder->glyph_width = sub->private_dict.default_width; + decoder->nominal_width = sub->private_dict.nominal_width; + + decoder->current_subfont = sub; + + Exit: + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/cffdecode.h b/vendor/freetype/src/psaux/cffdecode.h new file mode 100644 index 0000000..e8bb400 --- /dev/null +++ b/vendor/freetype/src/psaux/cffdecode.h @@ -0,0 +1,63 @@ +/**************************************************************************** + * + * cffdecode.h + * + * PostScript CFF (Type 2) decoding routines (specification). + * + * Copyright (C) 2017-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFDECODE_H_ +#define CFFDECODE_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + cff_decoder_init( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode, + CFF_Decoder_Get_Glyph_Callback get_callback, + CFF_Decoder_Free_Glyph_Callback free_callback ); + + FT_LOCAL( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ); + + + FT_LOCAL( FT_Int ) + cff_lookup_glyph_by_stdcharcode( CFF_Font cff, + FT_Int charcode ); + + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_LOCAL( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len, + FT_Bool in_dict ); +#endif + + +FT_END_HEADER + +#endif + + +/* END */ diff --git a/vendor/freetype/src/psaux/module.mk b/vendor/freetype/src/psaux/module.mk new file mode 100644 index 0000000..c6fb4eb --- /dev/null +++ b/vendor/freetype/src/psaux/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 PSaux module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += PSAUX_MODULE + +define PSAUX_MODULE +$(OPEN_DRIVER) FT_Module_Class, psaux_module_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)psaux $(ECHO_DRIVER_DESC)Postscript Type 1 & Type 2 helper module$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/psaux/psarrst.c b/vendor/freetype/src/psaux/psarrst.c new file mode 100644 index 0000000..70313d2 --- /dev/null +++ b/vendor/freetype/src/psaux/psarrst.c @@ -0,0 +1,240 @@ +/**************************************************************************** + * + * psarrst.c + * + * Adobe's code for Array Stacks (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" +#include "psarrst.h" + +#include "pserror.h" + + + /* + * CF2_ArrStack uses an error pointer, to enable shared errors. + * Shared errors are necessary when multiple objects allow the program + * to continue after detecting errors. Only the first error should be + * recorded. + */ + + FT_LOCAL_DEF( void ) + cf2_arrstack_init( CF2_ArrStack arrstack, + FT_Memory memory, + FT_Error* error, + size_t sizeItem ) + { + FT_ASSERT( arrstack ); + + /* initialize the structure */ + arrstack->memory = memory; + arrstack->error = error; + arrstack->sizeItem = sizeItem; + arrstack->allocated = 0; + arrstack->count = 0; + arrstack->totalSize = 0; + arrstack->ptr = NULL; + } + + + FT_LOCAL_DEF( void ) + cf2_arrstack_finalize( CF2_ArrStack arrstack ) + { + FT_Memory memory = arrstack->memory; /* for FT_FREE */ + + + FT_ASSERT( arrstack ); + + arrstack->allocated = 0; + arrstack->count = 0; + arrstack->totalSize = 0; + + /* free the data buffer */ + FT_FREE( arrstack->ptr ); + } + + + /* allocate or reallocate the buffer size; */ + /* return false on memory error */ + static FT_Bool + cf2_arrstack_setNumElements( CF2_ArrStack arrstack, + size_t numElements ) + { + FT_ASSERT( arrstack ); + + { + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + FT_Memory memory = arrstack->memory; /* for FT_REALLOC */ + + size_t newSize = numElements * arrstack->sizeItem; + + + if ( numElements > FT_LONG_MAX / arrstack->sizeItem ) + goto exit; + + + FT_ASSERT( newSize > 0 ); /* avoid realloc with zero size */ + + if ( !FT_QREALLOC( arrstack->ptr, arrstack->totalSize, newSize ) ) + { + arrstack->allocated = numElements; + arrstack->totalSize = newSize; + + if ( arrstack->count > numElements ) + { + /* we truncated the list! */ + CF2_SET_ERROR( arrstack->error, Stack_Overflow ); + arrstack->count = numElements; + return FALSE; + } + + return TRUE; /* success */ + } + } + + exit: + /* if there's not already an error, store this one */ + CF2_SET_ERROR( arrstack->error, Out_Of_Memory ); + + return FALSE; + } + + + /* set the count, ensuring allocation is sufficient */ + FT_LOCAL_DEF( void ) + cf2_arrstack_setCount( CF2_ArrStack arrstack, + size_t numElements ) + { + FT_ASSERT( arrstack ); + + if ( numElements > arrstack->allocated ) + { + /* expand the allocation first */ + if ( !cf2_arrstack_setNumElements( arrstack, numElements ) ) + return; + } + + arrstack->count = numElements; + } + + + /* clear the count */ + FT_LOCAL_DEF( void ) + cf2_arrstack_clear( CF2_ArrStack arrstack ) + { + FT_ASSERT( arrstack ); + + arrstack->count = 0; + } + + + /* current number of items */ + FT_LOCAL_DEF( size_t ) + cf2_arrstack_size( const CF2_ArrStack arrstack ) + { + FT_ASSERT( arrstack ); + + return arrstack->count; + } + + + FT_LOCAL_DEF( void* ) + cf2_arrstack_getBuffer( const CF2_ArrStack arrstack ) + { + FT_ASSERT( arrstack ); + + return arrstack->ptr; + } + + + /* return pointer to the given element */ + FT_LOCAL_DEF( void* ) + cf2_arrstack_getPointer( const CF2_ArrStack arrstack, + size_t idx ) + { + void* newPtr; + + + FT_ASSERT( arrstack ); + + if ( idx >= arrstack->count ) + { + /* overflow */ + CF2_SET_ERROR( arrstack->error, Stack_Overflow ); + idx = 0; /* choose safe default */ + } + + newPtr = (FT_Byte*)arrstack->ptr + idx * arrstack->sizeItem; + + return newPtr; + } + + + /* push (append) an element at the end of the list; */ + /* return false on memory error */ + /* TODO: should there be a length param for extra checking? */ + FT_LOCAL_DEF( void ) + cf2_arrstack_push( CF2_ArrStack arrstack, + const void* ptr ) + { + FT_ASSERT( arrstack ); + + if ( arrstack->count == arrstack->allocated ) + { + /* increase the buffer size */ + if ( !cf2_arrstack_setNumElements( + arrstack, arrstack->allocated * 2 + 16 ) ) + { + /* on error, ignore the push */ + return; + } + } + + FT_ASSERT( ptr ); + + { + size_t offset = arrstack->count * arrstack->sizeItem; + void* newPtr = (FT_Byte*)arrstack->ptr + offset; + + + FT_MEM_COPY( newPtr, ptr, arrstack->sizeItem ); + arrstack->count += 1; + } + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psarrst.h b/vendor/freetype/src/psaux/psarrst.h new file mode 100644 index 0000000..31e5330 --- /dev/null +++ b/vendor/freetype/src/psaux/psarrst.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * + * psarrst.h + * + * Adobe's code for Array Stacks (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSARRST_H_ +#define PSARRST_H_ + + +#include "pserror.h" + + +FT_BEGIN_HEADER + + + /* need to define the struct here (not opaque) so it can be allocated by */ + /* clients */ + typedef struct CF2_ArrStackRec_ + { + FT_Memory memory; + FT_Error* error; + + size_t sizeItem; /* bytes per element */ + size_t allocated; /* items allocated */ + size_t count; /* number of elements allocated */ + size_t totalSize; /* total bytes allocated */ + + void* ptr; /* ptr to data */ + + } CF2_ArrStackRec, *CF2_ArrStack; + + + FT_LOCAL( void ) + cf2_arrstack_init( CF2_ArrStack arrstack, + FT_Memory memory, + FT_Error* error, + size_t sizeItem ); + FT_LOCAL( void ) + cf2_arrstack_finalize( CF2_ArrStack arrstack ); + + FT_LOCAL( void ) + cf2_arrstack_setCount( CF2_ArrStack arrstack, + size_t numElements ); + FT_LOCAL( void ) + cf2_arrstack_clear( CF2_ArrStack arrstack ); + FT_LOCAL( size_t ) + cf2_arrstack_size( const CF2_ArrStack arrstack ); + + FT_LOCAL( void* ) + cf2_arrstack_getBuffer( const CF2_ArrStack arrstack ); + FT_LOCAL( void* ) + cf2_arrstack_getPointer( const CF2_ArrStack arrstack, + size_t idx ); + + FT_LOCAL( void ) + cf2_arrstack_push( CF2_ArrStack arrstack, + const void* ptr ); + + +FT_END_HEADER + + +#endif /* PSARRST_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psaux.c b/vendor/freetype/src/psaux/psaux.c new file mode 100644 index 0000000..5879ed1 --- /dev/null +++ b/vendor/freetype/src/psaux/psaux.c @@ -0,0 +1,40 @@ +/**************************************************************************** + * + * psaux.c + * + * FreeType auxiliary PostScript driver component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "afmparse.c" +#include "psauxmod.c" +#include "psconv.c" +#include "psobjs.c" +#include "t1cmap.c" +#include "t1decode.c" +#include "cffdecode.c" + +#include "psarrst.c" +#include "psblues.c" +#include "pserror.c" +#include "psfont.c" +#include "psft.c" +#include "pshints.c" +#include "psintrp.c" +#include "psread.c" +#include "psstack.c" + + +/* END */ diff --git a/vendor/freetype/src/psaux/psauxerr.h b/vendor/freetype/src/psaux/psauxerr.h new file mode 100644 index 0000000..895ffa4 --- /dev/null +++ b/vendor/freetype/src/psaux/psauxerr.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * psauxerr.h + * + * PS auxiliary module error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PS auxiliary module error enumeration + * constants. + * + */ + +#ifndef PSAUXERR_H_ +#define PSAUXERR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSaux_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSaux + +#include + +#endif /* PSAUXERR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psauxmod.c b/vendor/freetype/src/psaux/psauxmod.c new file mode 100644 index 0000000..45e35aa --- /dev/null +++ b/vendor/freetype/src/psaux/psauxmod.c @@ -0,0 +1,190 @@ +/**************************************************************************** + * + * psauxmod.c + * + * FreeType auxiliary PostScript module implementation (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "psauxmod.h" +#include "psobjs.h" +#include "t1decode.h" +#include "t1cmap.h" +#include "psft.h" +#include "cffdecode.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "afmparse.h" +#endif + + + FT_CALLBACK_TABLE_DEF + const PS_Table_FuncsRec ps_table_funcs = + { + ps_table_new, /* init */ + ps_table_done, /* done */ + ps_table_add, /* add */ + ps_table_release /* release */ + }; + + + FT_CALLBACK_TABLE_DEF + const PS_Parser_FuncsRec ps_parser_funcs = + { + ps_parser_init, /* init */ + ps_parser_done, /* done */ + + ps_parser_skip_spaces, /* skip_spaces */ + ps_parser_skip_PS_token, /* skip_PS_token */ + + ps_parser_to_int, /* to_int */ + ps_parser_to_fixed, /* to_fixed */ + ps_parser_to_bytes, /* to_bytes */ + ps_parser_to_coord_array, /* to_coord_array */ + ps_parser_to_fixed_array, /* to_fixed_array */ + ps_parser_to_token, /* to_token */ + ps_parser_to_token_array, /* to_token_array */ + + ps_parser_load_field, /* load_field */ + ps_parser_load_field_table /* load_field_table */ + }; + + + FT_CALLBACK_TABLE_DEF + const PS_Builder_FuncsRec ps_builder_funcs = + { + ps_builder_init, /* init */ + ps_builder_done /* done */ + }; + + + FT_CALLBACK_TABLE_DEF + const T1_Builder_FuncsRec t1_builder_funcs = + { + t1_builder_init, /* init */ + t1_builder_done, /* done */ + + t1_builder_check_points, /* check_points */ + t1_builder_add_point, /* add_point */ + t1_builder_add_point1, /* add_point1 */ + t1_builder_add_contour, /* add_contour */ + t1_builder_start_point, /* start_point */ + t1_builder_close_contour /* close_contour */ + }; + + + FT_CALLBACK_TABLE_DEF + const T1_Decoder_FuncsRec t1_decoder_funcs = + { + t1_decoder_init, /* init */ + t1_decoder_done, /* done */ +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + t1_decoder_parse_charstrings, /* parse_charstrings_old */ +#else + t1_decoder_parse_metrics, /* parse_metrics */ +#endif + cf2_decoder_parse_charstrings /* parse_charstrings */ + }; + + +#ifndef T1_CONFIG_OPTION_NO_AFM + FT_CALLBACK_TABLE_DEF + const AFM_Parser_FuncsRec afm_parser_funcs = + { + afm_parser_init, /* init */ + afm_parser_done, /* done */ + afm_parser_parse /* parse */ + }; +#endif + + + FT_CALLBACK_TABLE_DEF + const T1_CMap_ClassesRec t1_cmap_classes = + { + &t1_cmap_standard_class_rec, + &t1_cmap_expert_class_rec, + &t1_cmap_custom_class_rec, + &t1_cmap_unicode_class_rec + }; + + + FT_CALLBACK_TABLE_DEF + const CFF_Builder_FuncsRec cff_builder_funcs = + { + cff_builder_init, /* init */ + cff_builder_done, /* done */ + + cff_check_points, /* check_points */ + cff_builder_add_point, /* add_point */ + cff_builder_add_point1, /* add_point1 */ + cff_builder_add_contour, /* add_contour */ + cff_builder_start_point, /* start_point */ + cff_builder_close_contour /* close_contour */ + }; + + + FT_CALLBACK_TABLE_DEF + const CFF_Decoder_FuncsRec cff_decoder_funcs = + { + cff_decoder_init, /* init */ + cff_decoder_prepare, /* prepare */ + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + cff_decoder_parse_charstrings, /* parse_charstrings_old */ +#endif + cf2_decoder_parse_charstrings /* parse_charstrings */ + }; + + + static + const PSAux_Interface psaux_interface = + { + &ps_table_funcs, + &ps_parser_funcs, + &t1_builder_funcs, + &t1_decoder_funcs, + t1_decrypt, + cff_random, + ps_decoder_init, + t1_make_subfont, + + (const T1_CMap_ClassesRec*) &t1_cmap_classes, + +#ifndef T1_CONFIG_OPTION_NO_AFM + &afm_parser_funcs, +#else + 0, +#endif + + &cff_decoder_funcs, + }; + + + FT_DEFINE_MODULE( + psaux_module_class, + + 0, + sizeof ( FT_ModuleRec ), + "psaux", + 0x20000L, + 0x20000L, + + &psaux_interface, /* module-specific interface */ + + (FT_Module_Constructor)NULL, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) NULL /* get_interface */ + ) + + +/* END */ diff --git a/vendor/freetype/src/psaux/psauxmod.h b/vendor/freetype/src/psaux/psauxmod.h new file mode 100644 index 0000000..94dbf48 --- /dev/null +++ b/vendor/freetype/src/psaux/psauxmod.h @@ -0,0 +1,60 @@ +/**************************************************************************** + * + * psauxmod.h + * + * FreeType auxiliary PostScript module implementation (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSAUXMOD_H_ +#define PSAUXMOD_H_ + + +#include + +#include + + +FT_BEGIN_HEADER + + + FT_CALLBACK_TABLE + const CFF_Builder_FuncsRec cff_builder_funcs; + + FT_CALLBACK_TABLE + const PS_Builder_FuncsRec ps_builder_funcs; + +#ifndef T1_CONFIG_OPTION_NO_AFM + FT_CALLBACK_TABLE + const AFM_Parser_FuncsRec afm_parser_funcs; +#endif + + FT_CALLBACK_TABLE + const T1_CMap_ClassesRec t1_cmap_classes; + + FT_CALLBACK_TABLE + const CFF_Decoder_FuncsRec cff_decoder_funcs; + + + FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class; + + + FT_DECLARE_MODULE( psaux_module_class ) + + +FT_END_HEADER + +#endif /* PSAUXMOD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psblues.c b/vendor/freetype/src/psaux/psblues.c new file mode 100644 index 0000000..f9c864f --- /dev/null +++ b/vendor/freetype/src/psaux/psblues.c @@ -0,0 +1,583 @@ +/**************************************************************************** + * + * psblues.c + * + * Adobe's code for handling Blue Zones (body). + * + * Copyright 2009-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psblues.h" +#include "pshints.h" +#include "psfont.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cf2blues + + + /* + * For blue values, the FreeType parser produces an array of integers, + * while the Adobe CFF engine produces an array of fixed. + * Define a macro to convert FreeType to fixed. + */ +#define cf2_blueToFixed( x ) cf2_intToFixed( x ) + + + FT_LOCAL_DEF( void ) + cf2_blues_init( CF2_Blues blues, + CF2_Font font ) + { + /* pointer to parsed font object */ + PS_Decoder* decoder = font->decoder; + + CF2_Fixed zoneHeight; + CF2_Fixed maxZoneHeight = 0; + CF2_Fixed csUnitsPerPixel; + + size_t numBlueValues; + size_t numOtherBlues; + size_t numFamilyBlues; + size_t numFamilyOtherBlues; + + FT_Pos* blueValues; + FT_Pos* otherBlues; + FT_Pos* familyBlues; + FT_Pos* familyOtherBlues; + + size_t i; + CF2_Fixed emBoxBottom, emBoxTop; + +#if 0 + CF2_Int unitsPerEm = font->unitsPerEm; + + + if ( unitsPerEm == 0 ) + unitsPerEm = 1000; +#endif + + FT_ZERO( blues ); + blues->scale = font->innerTransform.d; + + cf2_getBlueMetrics( decoder, + &blues->blueScale, + &blues->blueShift, + &blues->blueFuzz ); + + cf2_getBlueValues( decoder, &numBlueValues, &blueValues ); + cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues ); + cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues ); + cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues ); + + /* + * synthetic em box hint heuristic + * + * Apply this when ideographic dictionary (LanguageGroup 1) has no + * real alignment zones. Adobe tools generate dummy zones at -250 and + * 1100 for a 1000 unit em. Fonts with ICF-based alignment zones + * should not enable the heuristic. When the heuristic is enabled, + * the font's blue zones are ignored. + * + */ + + /* get em box from OS/2 typoAscender/Descender */ + /* TODO: FreeType does not parse these metrics. Skip them for now. */ +#if 0 + FCM_getHorizontalLineMetrics( &e, + font->font, + &ascender, + &descender, + &linegap ); + if ( ascender - descender == unitsPerEm ) + { + emBoxBottom = cf2_intToFixed( descender ); + emBoxTop = cf2_intToFixed( ascender ); + } + else +#endif + { + emBoxBottom = CF2_ICF_Bottom; + emBoxTop = CF2_ICF_Top; + } + + if ( cf2_getLanguageGroup( decoder ) == 1 && + ( numBlueValues == 0 || + ( numBlueValues == 4 && + cf2_blueToFixed( blueValues[0] ) < emBoxBottom && + cf2_blueToFixed( blueValues[1] ) < emBoxBottom && + cf2_blueToFixed( blueValues[2] ) > emBoxTop && + cf2_blueToFixed( blueValues[3] ) > emBoxTop ) ) ) + { + /* + * Construct hint edges suitable for synthetic ghost hints at top + * and bottom of em box. +-CF2_MIN_COUNTER allows for unhinted + * features above or below the last hinted edge. This also gives a + * net 1 pixel boost to the height of ideographic glyphs. + * + * Note: Adjust synthetic hints outward by epsilon (0x.0001) to + * avoid interference. E.g., some fonts have real hints at + * 880 and -120. + */ + + blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON; + blues->emBoxBottomEdge.dsCoord = cf2_fixedRound( + FT_MulFix( + blues->emBoxBottomEdge.csCoord, + blues->scale ) ) - + CF2_MIN_COUNTER; + blues->emBoxBottomEdge.scale = blues->scale; + blues->emBoxBottomEdge.flags = CF2_GhostBottom | + CF2_Locked | + CF2_Synthetic; + + blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON + + 2 * font->darkenY; + blues->emBoxTopEdge.dsCoord = cf2_fixedRound( + FT_MulFix( + blues->emBoxTopEdge.csCoord, + blues->scale ) ) + + CF2_MIN_COUNTER; + blues->emBoxTopEdge.scale = blues->scale; + blues->emBoxTopEdge.flags = CF2_GhostTop | + CF2_Locked | + CF2_Synthetic; + + blues->doEmBoxHints = TRUE; /* enable the heuristic */ + + return; + } + + /* copy `BlueValues' and `OtherBlues' to a combined array of top and */ + /* bottom zones */ + for ( i = 0; i < numBlueValues; i += 2 ) + { + blues->zone[blues->count].csBottomEdge = + cf2_blueToFixed( blueValues[i] ); + blues->zone[blues->count].csTopEdge = + cf2_blueToFixed( blueValues[i + 1] ); + + zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, + blues->zone[blues->count].csBottomEdge ); + + if ( zoneHeight < 0 ) + { + FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); + continue; /* reject this zone */ + } + + if ( zoneHeight > maxZoneHeight ) + { + /* take maximum before darkening adjustment */ + /* so overshoot suppression point doesn't change */ + maxZoneHeight = zoneHeight; + } + + /* adjust both edges of top zone upward by twice darkening amount */ + if ( i != 0 ) + { + blues->zone[blues->count].csTopEdge += 2 * font->darkenY; + blues->zone[blues->count].csBottomEdge += 2 * font->darkenY; + } + + /* first `BlueValue' is bottom zone; others are top */ + if ( i == 0 ) + { + blues->zone[blues->count].bottomZone = + TRUE; + blues->zone[blues->count].csFlatEdge = + blues->zone[blues->count].csTopEdge; + } + else + { + blues->zone[blues->count].bottomZone = + FALSE; + blues->zone[blues->count].csFlatEdge = + blues->zone[blues->count].csBottomEdge; + } + + blues->count += 1; + } + + for ( i = 0; i < numOtherBlues; i += 2 ) + { + blues->zone[blues->count].csBottomEdge = + cf2_blueToFixed( otherBlues[i] ); + blues->zone[blues->count].csTopEdge = + cf2_blueToFixed( otherBlues[i + 1] ); + + zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, + blues->zone[blues->count].csBottomEdge ); + + if ( zoneHeight < 0 ) + { + FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); + continue; /* reject this zone */ + } + + if ( zoneHeight > maxZoneHeight ) + { + /* take maximum before darkening adjustment */ + /* so overshoot suppression point doesn't change */ + maxZoneHeight = zoneHeight; + } + + /* Note: bottom zones are not adjusted for darkening amount */ + + /* all OtherBlues are bottom zone */ + blues->zone[blues->count].bottomZone = + TRUE; + blues->zone[blues->count].csFlatEdge = + blues->zone[blues->count].csTopEdge; + + blues->count += 1; + } + + /* Adjust for FamilyBlues */ + + /* Search for the nearest flat edge in `FamilyBlues' or */ + /* `FamilyOtherBlues'. According to the Black Book, any matching edge */ + /* must be within one device pixel */ + + csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale ); + + /* loop on all zones in this font */ + for ( i = 0; i < blues->count; i++ ) + { + size_t j; + CF2_Fixed minDiff; + CF2_Fixed flatFamilyEdge, diff; + /* value for this font */ + CF2_Fixed flatEdge = blues->zone[i].csFlatEdge; + + + if ( blues->zone[i].bottomZone ) + { + /* In a bottom zone, the top edge is the flat edge. */ + /* Search `FamilyOtherBlues' for bottom zones; look for closest */ + /* Family edge that is within the one pixel threshold. */ + + minDiff = CF2_FIXED_MAX; + + for ( j = 0; j < numFamilyOtherBlues; j += 2 ) + { + /* top edge */ + flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] ); + + diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); + + if ( diff < minDiff && diff < csUnitsPerPixel ) + { + blues->zone[i].csFlatEdge = flatFamilyEdge; + minDiff = diff; + + if ( diff == 0 ) + break; + } + } + + /* check the first member of FamilyBlues, which is a bottom zone */ + if ( numFamilyBlues >= 2 ) + { + /* top edge */ + flatFamilyEdge = cf2_blueToFixed( familyBlues[1] ); + + diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); + + if ( diff < minDiff && diff < csUnitsPerPixel ) + blues->zone[i].csFlatEdge = flatFamilyEdge; + } + } + else + { + /* In a top zone, the bottom edge is the flat edge. */ + /* Search `FamilyBlues' for top zones; skip first zone, which is a */ + /* bottom zone; look for closest Family edge that is within the */ + /* one pixel threshold */ + + minDiff = CF2_FIXED_MAX; + + for ( j = 2; j < numFamilyBlues; j += 2 ) + { + /* bottom edge */ + flatFamilyEdge = cf2_blueToFixed( familyBlues[j] ); + + /* adjust edges of top zone upward by twice darkening amount */ + flatFamilyEdge += 2 * font->darkenY; /* bottom edge */ + + diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); + + if ( diff < minDiff && diff < csUnitsPerPixel ) + { + blues->zone[i].csFlatEdge = flatFamilyEdge; + minDiff = diff; + + if ( diff == 0 ) + break; + } + } + } + } + + /* TODO: enforce separation of zones, including BlueFuzz */ + + /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */ + /* `bcsetup.c'. */ + + if ( maxZoneHeight > 0 ) + { + if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ), + maxZoneHeight ) ) + { + /* clamp at maximum scale */ + blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ), + maxZoneHeight ); + } + + /* + * TODO: Revisit the bug fix for 613448. The minimum scale + * requirement catches a number of library fonts. For + * example, with default BlueScale (.039625) and 0.4 minimum, + * the test below catches any font with maxZoneHeight < 10.1. + * There are library fonts ranging from 2 to 10 that get + * caught, including e.g., Eurostile LT Std Medium with + * maxZoneHeight of 6. + * + */ +#if 0 + if ( blueScale < .4 / maxZoneHeight ) + { + tetraphilia_assert( 0 ); + /* clamp at minimum scale, per bug 0613448 fix */ + blueScale = .4 / maxZoneHeight; + } +#endif + + } + + /* + * Suppress overshoot and boost blue zones at small sizes. Boost + * amount varies linearly from 0.5 pixel near 0 to 0 pixel at + * blueScale cutoff. + * Note: This boost amount is different from the coretype heuristic. + * + */ + + if ( blues->scale < blues->blueScale ) + { + blues->suppressOvershoot = TRUE; + + /* Change rounding threshold for `dsFlatEdge'. */ + /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */ + /* 10ppem Arial */ + + blues->boost = cf2_doubleToFixed( .6 ) - + FT_MulDiv( cf2_doubleToFixed ( .6 ), + blues->scale, + blues->blueScale ); + if ( blues->boost > 0x7FFF ) + { + /* boost must remain less than 0.5, or baseline could go negative */ + blues->boost = 0x7FFF; + } + } + + /* boost and darkening have similar effects; don't do both */ + if ( font->stemDarkened ) + blues->boost = 0; + + /* set device space alignment for each zone; */ + /* apply boost amount before rounding flat edge */ + + for ( i = 0; i < blues->count; i++ ) + { + if ( blues->zone[i].bottomZone ) + blues->zone[i].dsFlatEdge = cf2_fixedRound( + FT_MulFix( + blues->zone[i].csFlatEdge, + blues->scale ) - + blues->boost ); + else + blues->zone[i].dsFlatEdge = cf2_fixedRound( + FT_MulFix( + blues->zone[i].csFlatEdge, + blues->scale ) + + blues->boost ); + } + } + + + /* + * Check whether `stemHint' is captured by one of the blue zones. + * + * Zero, one or both edges may be valid; only valid edges can be + * captured. For compatibility with CoolType, search top and bottom + * zones in the same pass (see `BlueLock'). If a hint is captured, + * return true and position the edge(s) in one of 3 ways: + * + * 1) If `BlueScale' suppresses overshoot, position the captured edge + * at the flat edge of the zone. + * 2) If overshoot is not suppressed and `BlueShift' requires + * overshoot, position the captured edge a minimum of 1 device pixel + * from the flat edge. + * 3) If overshoot is not suppressed or required, position the captured + * edge at the nearest device pixel. + * + */ + FT_LOCAL_DEF( FT_Bool ) + cf2_blues_capture( const CF2_Blues blues, + CF2_Hint bottomHintEdge, + CF2_Hint topHintEdge ) + { + /* TODO: validate? */ + CF2_Fixed csFuzz = blues->blueFuzz; + + /* new position of captured edge */ + CF2_Fixed dsNew; + + /* amount that hint is moved when positioned */ + CF2_Fixed dsMove = 0; + + FT_Bool captured = FALSE; + CF2_UInt i; + + + /* assert edge flags are consistent */ + FT_ASSERT( !cf2_hint_isTop( bottomHintEdge ) && + !cf2_hint_isBottom( topHintEdge ) ); + + /* TODO: search once without blue fuzz for compatibility with coretype? */ + for ( i = 0; i < blues->count; i++ ) + { + if ( blues->zone[i].bottomZone && + cf2_hint_isBottom( bottomHintEdge ) ) + { + if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <= + bottomHintEdge->csCoord && + bottomHintEdge->csCoord <= + ADD_INT32( blues->zone[i].csTopEdge, csFuzz ) ) + { + /* bottom edge captured by bottom zone */ + + if ( blues->suppressOvershoot ) + dsNew = blues->zone[i].dsFlatEdge; + + else if ( SUB_INT32( blues->zone[i].csTopEdge, + bottomHintEdge->csCoord ) >= + blues->blueShift ) + { + /* guarantee minimum of 1 pixel overshoot */ + dsNew = FT_MIN( + cf2_fixedRound( bottomHintEdge->dsCoord ), + SUB_INT32( blues->zone[i].dsFlatEdge, + cf2_intToFixed( 1 ) ) ); + } + + else + { + /* simply round captured edge */ + dsNew = cf2_fixedRound( bottomHintEdge->dsCoord ); + } + + dsMove = SUB_INT32( dsNew, bottomHintEdge->dsCoord ); + captured = TRUE; + + break; + } + } + + if ( !blues->zone[i].bottomZone && cf2_hint_isTop( topHintEdge ) ) + { + if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <= + topHintEdge->csCoord && + topHintEdge->csCoord <= + ADD_INT32( blues->zone[i].csTopEdge, csFuzz ) ) + { + /* top edge captured by top zone */ + + if ( blues->suppressOvershoot ) + dsNew = blues->zone[i].dsFlatEdge; + + else if ( SUB_INT32( topHintEdge->csCoord, + blues->zone[i].csBottomEdge ) >= + blues->blueShift ) + { + /* guarantee minimum of 1 pixel overshoot */ + dsNew = FT_MAX( + cf2_fixedRound( topHintEdge->dsCoord ), + blues->zone[i].dsFlatEdge + cf2_intToFixed( 1 ) ); + } + + else + { + /* simply round captured edge */ + dsNew = cf2_fixedRound( topHintEdge->dsCoord ); + } + + dsMove = SUB_INT32( dsNew, topHintEdge->dsCoord ); + captured = TRUE; + + break; + } + } + } + + if ( captured ) + { + /* move both edges and flag them `locked' */ + if ( cf2_hint_isValid( bottomHintEdge ) ) + { + bottomHintEdge->dsCoord = ADD_INT32( bottomHintEdge->dsCoord, + dsMove ); + cf2_hint_lock( bottomHintEdge ); + } + + if ( cf2_hint_isValid( topHintEdge ) ) + { + topHintEdge->dsCoord = ADD_INT32( topHintEdge->dsCoord, dsMove ); + cf2_hint_lock( topHintEdge ); + } + } + + return captured; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psblues.h b/vendor/freetype/src/psaux/psblues.h new file mode 100644 index 0000000..55fb88e --- /dev/null +++ b/vendor/freetype/src/psaux/psblues.h @@ -0,0 +1,185 @@ +/**************************************************************************** + * + * psblues.h + * + * Adobe's code for handling Blue Zones (specification). + * + * Copyright 2009-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + + /* + * A `CF2_Blues' object stores the blue zones (horizontal alignment + * zones) of a font. These are specified in the CFF private dictionary + * by `BlueValues', `OtherBlues', `FamilyBlues', and `FamilyOtherBlues'. + * Each zone is defined by a top and bottom edge in character space. + * Further, each zone is either a top zone or a bottom zone, as recorded + * by `bottomZone'. + * + * The maximum number of `BlueValues' and `FamilyBlues' is 7 each. + * However, these are combined to produce a total of 7 zones. + * Similarly, the maximum number of `OtherBlues' and `FamilyOtherBlues' + * is 5 and these are combined to produce an additional 5 zones. + * + * Blue zones are used to `capture' hints and force them to a common + * alignment point. This alignment is recorded in device space in + * `dsFlatEdge'. Except for this value, a `CF2_Blues' object could be + * constructed independently of scaling. Construction may occur once + * the matrix is known. Other features implemented in the Capture + * method are overshoot suppression, overshoot enforcement, and Blue + * Boost. + * + * Capture is determined by `BlueValues' and `OtherBlues', but the + * alignment point may be adjusted to the scaled flat edge of + * `FamilyBlues' or `FamilyOtherBlues'. No alignment is done to the + * curved edge of a zone. + * + */ + + +#ifndef PSBLUES_H_ +#define PSBLUES_H_ + + +#include "psglue.h" + + +FT_BEGIN_HEADER + + + /* + * `CF2_Hint' is shared by `cf2hints.h' and + * `cf2blues.h', but `cf2blues.h' depends on + * `cf2hints.h', so define it here. Note: The typedef is in + * `cf2glue.h'. + * + */ + enum + { + CF2_GhostBottom = 0x1, /* a single bottom edge */ + CF2_GhostTop = 0x2, /* a single top edge */ + CF2_PairBottom = 0x4, /* the bottom edge of a stem hint */ + CF2_PairTop = 0x8, /* the top edge of a stem hint */ + CF2_Locked = 0x10, /* this edge has been aligned */ + /* by a blue zone */ + CF2_Synthetic = 0x20 /* this edge was synthesized */ + }; + + + /* + * Default value for OS/2 typoAscender/Descender when their difference + * is not equal to `unitsPerEm'. The default is based on -250 and 1100 + * in `CF2_Blues', assuming 1000 units per em here. + * + */ + enum + { + CF2_ICF_Top = cf2_intToFixed( 880 ), + CF2_ICF_Bottom = cf2_intToFixed( -120 ) + }; + + + /* + * Constant used for hint adjustment and for synthetic em box hint + * placement. + */ +#define CF2_MIN_COUNTER cf2_doubleToFixed( 0.5 ) + + + /* shared typedef is in cf2glue.h */ + struct CF2_HintRec_ + { + CF2_UInt flags; /* attributes of the edge */ + size_t index; /* index in original stem hint array */ + /* (if not synthetic) */ + CF2_Fixed csCoord; + CF2_Fixed dsCoord; + CF2_Fixed scale; + }; + + + typedef struct CF2_BlueRec_ + { + CF2_Fixed csBottomEdge; + CF2_Fixed csTopEdge; + CF2_Fixed csFlatEdge; /* may be from either local or Family zones */ + CF2_Fixed dsFlatEdge; /* top edge of bottom zone or bottom edge */ + /* of top zone (rounded) */ + FT_Bool bottomZone; + + } CF2_BlueRec; + + + /* max total blue zones is 12 */ + enum + { + CF2_MAX_BLUES = 7, + CF2_MAX_OTHERBLUES = 5 + }; + + + typedef struct CF2_BluesRec_ + { + CF2_Fixed scale; + CF2_UInt count; + FT_Bool suppressOvershoot; + FT_Bool doEmBoxHints; + + CF2_Fixed blueScale; + CF2_Fixed blueShift; + CF2_Fixed blueFuzz; + + CF2_Fixed boost; + + CF2_HintRec emBoxTopEdge; + CF2_HintRec emBoxBottomEdge; + + CF2_BlueRec zone[CF2_MAX_BLUES + CF2_MAX_OTHERBLUES]; + + } CF2_BluesRec, *CF2_Blues; + + + FT_LOCAL( void ) + cf2_blues_init( CF2_Blues blues, + CF2_Font font ); + FT_LOCAL( FT_Bool ) + cf2_blues_capture( const CF2_Blues blues, + CF2_Hint bottomHintEdge, + CF2_Hint topHintEdge ); + + +FT_END_HEADER + + +#endif /* PSBLUES_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psconv.c b/vendor/freetype/src/psaux/psconv.c new file mode 100644 index 0000000..b9c7138 --- /dev/null +++ b/vendor/freetype/src/psaux/psconv.c @@ -0,0 +1,610 @@ +/**************************************************************************** + * + * psconv.c + * + * Some convenience conversions (body). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + +#include "psconv.h" +#include "psauxerr.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT psconv + + + /* The following array is used by various functions to quickly convert */ + /* digits (both decimal and non-decimal) into numbers. */ + +#if 'A' == 65 + /* ASCII */ + + static const FT_Char ft_char_table[128] = + { + /* 0x00 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + }; + + /* no character >= 0x80 can represent a valid number */ +#define OP >= + +#endif /* 'A' == 65 */ + +#if 'A' == 193 + /* EBCDIC */ + + static const FT_Char ft_char_table[128] = + { + /* 0x80 */ + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + }; + + /* no character < 0x80 can represent a valid number */ +#define OP < + +#endif /* 'A' == 193 */ + + + FT_LOCAL_DEF( FT_Long ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Long base ) + { + FT_Byte* p = *cursor; + + FT_Long num = 0; + FT_Bool sign = 0; + FT_Bool have_overflow = 0; + + FT_Long num_limit; + FT_Char c_limit; + + + if ( p >= limit ) + goto Bad; + + if ( base < 2 || base > 36 ) + { + FT_TRACE4(( "!!!INVALID BASE:!!!" )); + return 0; + } + + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + + p++; + if ( p == limit ) + goto Bad; + + /* only a single sign is allowed */ + if ( *p == '-' || *p == '+' ) + return 0; + } + + num_limit = 0x7FFFFFFFL / base; + c_limit = (FT_Char)( 0x7FFFFFFFL % base ); + + for ( ; p < limit; p++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7F]; + + if ( c < 0 || c >= base ) + break; + + if ( num > num_limit || ( num == num_limit && c > c_limit ) ) + have_overflow = 1; + else + num = num * base + c; + } + + *cursor = p; + + if ( have_overflow ) + { + num = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + } + + if ( sign ) + num = -num; + + return num; + + Bad: + FT_TRACE4(( "!!!END OF DATA:!!!" )); + return 0; + } + + + FT_LOCAL_DEF( FT_Long ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ) + + { + FT_Byte* p = *cursor; + FT_Byte* curp; + + FT_Long num; + + + curp = p; + num = PS_Conv_Strtol( &p, limit, 10 ); + + if ( p == curp ) + return 0; + + if ( p < limit && *p == '#' ) + { + p++; + + curp = p; + num = PS_Conv_Strtol( &p, limit, num ); + + if ( p == curp ) + return 0; + } + + *cursor = p; + + return num; + } + + + FT_LOCAL_DEF( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ) + { + FT_Byte* p = *cursor; + FT_Byte* curp; + + FT_Fixed integral = 0; + FT_Long decimal = 0; + FT_Long divider = 1; + + FT_Bool sign = 0; + FT_Bool have_overflow = 0; + FT_Bool have_underflow = 0; + + + if ( p >= limit ) + goto Bad; + + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + + p++; + if ( p == limit ) + goto Bad; + + /* only a single sign is allowed */ + if ( *p == '-' || *p == '+' ) + return 0; + } + + /* read the integer part */ + if ( *p != '.' ) + { + curp = p; + integral = PS_Conv_ToInt( &p, limit ); + + if ( p == curp ) + return 0; + + if ( integral > 0x7FFF ) + have_overflow = 1; + else + integral = (FT_Fixed)( (FT_UInt32)integral << 16 ); + } + + /* read the decimal part */ + if ( p < limit && *p == '.' ) + { + p++; + + for ( ; p < limit; p++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7F]; + + if ( c < 0 || c >= 10 ) + break; + + /* only add digit if we don't overflow */ + if ( divider < 0xCCCCCCCL && decimal < 0xCCCCCCCL ) + { + decimal = decimal * 10 + c; + + if ( !integral && power_ten > 0 ) + power_ten--; + else + divider *= 10; + } + } + } + + /* read exponent, if any */ + if ( p + 1 < limit && ( *p == 'e' || *p == 'E' ) ) + { + FT_Long exponent; + + + p++; + + curp = p; + exponent = PS_Conv_ToInt( &p, limit ); + + if ( curp == p ) + return 0; + + /* arbitrarily limit exponent */ + if ( exponent > 1000 ) + have_overflow = 1; + else if ( exponent < -1000 ) + have_underflow = 1; + else + power_ten += exponent; + } + + *cursor = p; + + if ( !integral && !decimal ) + return 0; + + if ( have_overflow ) + goto Overflow; + if ( have_underflow ) + goto Underflow; + + while ( power_ten > 0 ) + { + if ( integral >= 0xCCCCCCCL ) + goto Overflow; + integral *= 10; + + if ( decimal >= 0xCCCCCCCL ) + { + if ( divider == 1 ) + goto Overflow; + divider /= 10; + } + else + decimal *= 10; + + power_ten--; + } + + while ( power_ten < 0 ) + { + integral /= 10; + if ( divider < 0xCCCCCCCL ) + divider *= 10; + else + decimal /= 10; + + if ( !integral && !decimal ) + goto Underflow; + + power_ten++; + } + + if ( decimal ) + { + decimal = FT_DivFix( decimal, divider ); + /* it's not necessary to check this addition for overflow */ + /* due to the structure of the real number representation */ + integral += decimal; + } + + Exit: + if ( sign ) + integral = -integral; + + return integral; + + Bad: + FT_TRACE4(( "!!!END OF DATA:!!!" )); + return 0; + + Overflow: + integral = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + goto Exit; + + Underflow: + FT_TRACE4(( "!!!UNDERFLOW:!!!" )); + return 0; + } + + +#if 0 + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ) + { + FT_Byte* p; + FT_UInt r = 0; + + + for ( p = *cursor; r < n && p < limit; p++ ) + { + FT_Byte b; + + + if ( *p != '\\' ) + { + buffer[r++] = *p; + + continue; + } + + p++; + + switch ( *p ) + { + case 'n': + b = '\n'; + break; + case 'r': + b = '\r'; + break; + case 't': + b = '\t'; + break; + case 'b': + b = '\b'; + break; + case 'f': + b = '\f'; + break; + case '\r': + p++; + if ( *p != '\n' ) + { + b = *p; + + break; + } + /* no break */ + case '\n': + continue; + break; + default: + if ( IS_PS_DIGIT( *p ) ) + { + b = *p - '0'; + + p++; + + if ( IS_PS_DIGIT( *p ) ) + { + b = b * 8 + *p - '0'; + + p++; + + if ( IS_PS_DIGIT( *p ) ) + b = b * 8 + *p - '0'; + else + { + buffer[r++] = b; + b = *p; + } + } + else + { + buffer[r++] = b; + b = *p; + } + } + else + b = *p; + break; + } + + buffer[r++] = b; + } + + *cursor = p; + + return r; + } +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ) + { + FT_Byte* p; + FT_UInt r = 0; + FT_UInt w = 0; + FT_UInt pad = 0x01; + + + n *= 2; + +#if 1 + + p = *cursor; + + if ( p >= limit ) + return 0; + + if ( n > (FT_UInt)( limit - p ) ) + n = (FT_UInt)( limit - p ); + + /* we try to process two nibbles at a time to be as fast as possible */ + for ( ; r < n; r++ ) + { + FT_UInt c = p[r]; + + + if ( IS_PS_SPACE( c ) ) + continue; + + if ( c OP 0x80 ) + break; + + c = (FT_UInt)ft_char_table[c & 0x7F]; + if ( c >= 16 ) + break; + + pad = ( pad << 4 ) | c; + if ( pad & 0x100 ) + { + buffer[w++] = (FT_Byte)pad; + pad = 0x01; + } + } + + if ( pad != 0x01 ) + buffer[w++] = (FT_Byte)( pad << 4 ); + + *cursor = p + r; + + return w; + +#else /* 0 */ + + for ( r = 0; r < n; r++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) ) + continue; + + if ( *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7F]; + + if ( (unsigned)c >= 16 ) + break; + + if ( r & 1 ) + { + *buffer = (FT_Byte)( *buffer + c ); + buffer++; + } + else + *buffer = (FT_Byte)( c << 4 ); + + r++; + } + + *cursor = p; + + return ( r + 1 ) / 2; + +#endif /* 0 */ + + } + + + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n, + FT_UShort* seed ) + { + FT_Byte* p; + FT_UInt r; + FT_UInt s = *seed; + + +#if 1 + + p = *cursor; + + if ( p >= limit ) + return 0; + + if ( n > (FT_UInt)( limit - p ) ) + n = (FT_UInt)( limit - p ); + + for ( r = 0; r < n; r++ ) + { + FT_UInt val = p[r]; + FT_UInt b = ( val ^ ( s >> 8 ) ); + + + s = ( (val + s)*52845U + 22719 ) & 0xFFFFU; + buffer[r] = (FT_Byte) b; + } + + *cursor = p + n; + *seed = (FT_UShort)s; + +#else /* 0 */ + + for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ ) + { + FT_Byte b = (FT_Byte)( *p ^ ( s >> 8 ) ); + + + s = (FT_UShort)( ( *p + s ) * 52845U + 22719 ); + *buffer++ = b; + } + *cursor = p; + *seed = s; + +#endif /* 0 */ + + return r; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psconv.h b/vendor/freetype/src/psaux/psconv.h new file mode 100644 index 0000000..b7c3ee0 --- /dev/null +++ b/vendor/freetype/src/psaux/psconv.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * + * psconv.h + * + * Some convenience conversions (specification). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSCONV_H_ +#define PSCONV_H_ + + +#include + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Long ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Long base ); + + + FT_LOCAL( FT_Long ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ); + + FT_LOCAL( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ); + +#if 0 + FT_LOCAL( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ); +#endif + + FT_LOCAL( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ); + + FT_LOCAL( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n, + FT_UShort* seed ); + + +FT_END_HEADER + +#endif /* PSCONV_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/pserror.c b/vendor/freetype/src/psaux/pserror.c new file mode 100644 index 0000000..98cebcf --- /dev/null +++ b/vendor/freetype/src/psaux/pserror.c @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * pserror.c + * + * Adobe's code for error handling (body). + * + * Copyright 2006-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include "pserror.h" + + + FT_LOCAL_DEF( void ) + cf2_setError( FT_Error* error, + FT_Error value ) + { + if ( error && !*error ) + *error = value; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/pserror.h b/vendor/freetype/src/psaux/pserror.h new file mode 100644 index 0000000..5738853 --- /dev/null +++ b/vendor/freetype/src/psaux/pserror.h @@ -0,0 +1,120 @@ +/**************************************************************************** + * + * pserror.h + * + * Adobe's code for error handling (specification). + * + * Copyright 2006-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSERROR_H_ +#define PSERROR_H_ + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CF2_Err_ +#define FT_ERR_BASE FT_Mod_Err_CF2 + + +#include +#include +#include "psft.h" + + +FT_BEGIN_HEADER + + + /* + * A poor-man error facility. + * + * This code being written in vanilla C, doesn't have the luxury of a + * language-supported exception mechanism such as the one available in + * Java. Instead, we are stuck with using error codes that must be + * carefully managed and preserved. However, it is convenient for us to + * model our error mechanism on a Java-like exception mechanism. + * When we assign an error code we are thus `throwing' an error. + * + * The preservation of an error code is done by coding convention. + * Upon a function call if the error code is anything other than + * `FT_Err_Ok', which is guaranteed to be zero, we + * will return without altering that error. This will allow the + * error to propagate and be handled at the appropriate location in + * the code. + * + * This allows a style of code where the error code is initialized + * up front and a block of calls are made with the error code only + * being checked after the block. If a new error occurs, the original + * error will be preserved and a functional no-op should result in any + * subsequent function that has an initial error code not equal to + * `FT_Err_Ok'. + * + * Errors are encoded by calling the `FT_THROW' macro. For example, + * + * { + * FT_Error e; + * + * + * ... + * e = FT_THROW( Out_Of_Memory ); + * } + * + */ + + + /* Set error code to a particular value. */ + FT_LOCAL( void ) + cf2_setError( FT_Error* error, + FT_Error value ); + + + /* + * A macro that conditionally sets an error code. + * + * This macro will first check whether `error' is set; + * if not, it will set it to `e'. + * + */ +#define CF2_SET_ERROR( error, e ) \ + cf2_setError( error, FT_THROW( e ) ) + + +FT_END_HEADER + + +#endif /* PSERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psfixed.h b/vendor/freetype/src/psaux/psfixed.h new file mode 100644 index 0000000..299d076 --- /dev/null +++ b/vendor/freetype/src/psaux/psfixed.h @@ -0,0 +1,94 @@ +/**************************************************************************** + * + * psfixed.h + * + * Adobe's code for Fixed-Point Mathematics (specification only). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSFIXED_H_ +#define PSFIXED_H_ + + +FT_BEGIN_HEADER + + + /* rasterizer integer and fixed-point arithmetic must be 32-bit */ + +#define CF2_Fixed CF2_F16Dot16 + typedef FT_Int32 CF2_Frac; /* 2.30 fixed-point */ + + +#define CF2_FIXED_MAX ( (CF2_Fixed)0x7FFFFFFFL ) +#define CF2_FIXED_MIN ( (CF2_Fixed)0x80000000L ) +#define CF2_FIXED_ONE ( (CF2_Fixed)0x10000L ) +#define CF2_FIXED_EPSILON ( (CF2_Fixed)0x0001 ) + + /* in C 89, left and right shift of negative numbers is */ + /* implementation specific behaviour in the general case */ + +#define cf2_intToFixed( i ) \ + ( (CF2_Fixed)( (FT_UInt32)(i) << 16 ) ) +#define cf2_fixedToInt( x ) \ + ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) ) +#define cf2_fixedRound( x ) \ + ( (CF2_Fixed)( ( (FT_UInt32)(x) + 0x8000U ) & 0xFFFF0000UL ) ) +#define cf2_doubleToFixed( f ) \ + ( (CF2_Fixed)( (f) * 65536.0 + 0.5 ) ) +#define cf2_fixedAbs( x ) \ + ( (x) < 0 ? NEG_INT32( x ) : (x) ) +#define cf2_fixedFloor( x ) \ + ( (CF2_Fixed)( (FT_UInt32)(x) & 0xFFFF0000UL ) ) +#define cf2_fixedFraction( x ) \ + ( (x) - cf2_fixedFloor( x ) ) +#define cf2_fracToFixed( x ) \ + ( ( (x) + 0x2000 - ( (x) < 0 ) ) >> 14 ) + + + /* signed numeric types */ + typedef enum CF2_NumberType_ + { + CF2_NumberFixed, /* 16.16 */ + CF2_NumberFrac, /* 2.30 */ + CF2_NumberInt /* 32.0 */ + + } CF2_NumberType; + + +FT_END_HEADER + + +#endif /* PSFIXED_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psfont.c b/vendor/freetype/src/psaux/psfont.c new file mode 100644 index 0000000..0db1f0c --- /dev/null +++ b/vendor/freetype/src/psaux/psfont.c @@ -0,0 +1,566 @@ +/**************************************************************************** + * + * psfont.c + * + * Adobe's code for font instances (body). + * + * Copyright 2007-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include + +#include "psft.h" + +#include "psglue.h" +#include "psfont.h" +#include "pserror.h" +#include "psintrp.h" + + + /* Compute a stem darkening amount in character space. */ + static void + cf2_computeDarkening( CF2_Fixed emRatio, + CF2_Fixed ppem, + CF2_Fixed stemWidth, + CF2_Fixed* darkenAmount, + CF2_Fixed boldenAmount, + FT_Bool stemDarkened, + FT_Int* darkenParams ) + { + /* + * Total darkening amount is computed in 1000 unit character space + * using the modified 5 part curve as Adobe's Avalon rasterizer. + * The darkening amount is smaller for thicker stems. + * It becomes zero when the stem is thicker than 2.333 pixels. + * + * By default, we use + * + * darkenAmount = 0.4 pixels if scaledStem <= 0.5 pixels, + * darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels, + * darkenAmount = 0 pixel if scaledStem >= 2.333 pixels, + * + * and piecewise linear in-between: + * + * + * darkening + * ^ + * | + * | (x1,y1) + * |--------+ + * | \ + * | \ + * | \ (x3,y3) + * | +----------+ + * | (x2,y2) \ + * | \ + * | \ + * | +----------------- + * | (x4,y4) + * +---------------------------------------------> stem + * thickness + * + * + * This corresponds to the following values for the + * `darkening-parameters' property: + * + * (x1, y1) = (500, 400) + * (x2, y2) = (1000, 275) + * (x3, y3) = (1667, 275) + * (x4, y4) = (2333, 0) + * + */ + + /* Internal calculations are done in units per thousand for */ + /* convenience. The x axis is scaled stem width in */ + /* thousandths of a pixel. That is, 1000 is 1 pixel. */ + /* The y axis is darkening amount in thousandths of a pixel.*/ + /* In the code, below, dividing by ppem and */ + /* adjusting for emRatio converts darkenAmount to character */ + /* space (font units). */ + CF2_Fixed stemWidthPer1000, scaledStem; + FT_Int logBase2; + + + *darkenAmount = 0; + + if ( boldenAmount == 0 && !stemDarkened ) + return; + + /* protect against range problems and divide by zero */ + if ( emRatio < cf2_doubleToFixed( .01 ) ) + return; + + if ( stemDarkened ) + { + FT_Int x1 = darkenParams[0]; + FT_Int y1 = darkenParams[1]; + FT_Int x2 = darkenParams[2]; + FT_Int y2 = darkenParams[3]; + FT_Int x3 = darkenParams[4]; + FT_Int y3 = darkenParams[5]; + FT_Int x4 = darkenParams[6]; + FT_Int y4 = darkenParams[7]; + + + /* convert from true character space to 1000 unit character space; */ + /* add synthetic emboldening effect */ + + /* `stemWidthPer1000' will not overflow for a legitimate font */ + + stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio ); + + /* `scaledStem' can easily overflow, so we must clamp its maximum */ + /* value; the test doesn't need to be precise, but must be */ + /* conservative. The clamp value (default 2333) where */ + /* `darkenAmount' is zero is well below the overflow value of */ + /* 32767. */ + /* */ + /* FT_MSB computes the integer part of the base 2 logarithm. The */ + /* number of bits for the product is 1 or 2 more than the sum of */ + /* logarithms; remembering that the 16 lowest bits of the fraction */ + /* are dropped this is correct to within a factor of almost 4. */ + /* For example, 0x80.0000 * 0x80.0000 = 0x4000.0000 is 23+23 and */ + /* is flagged as possible overflow because 0xFF.FFFF * 0xFF.FFFF = */ + /* 0xFFFF.FE00 is also 23+23. */ + + logBase2 = FT_MSB( (FT_UInt32)stemWidthPer1000 ) + + FT_MSB( (FT_UInt32)ppem ); + + if ( logBase2 >= 46 ) + /* possible overflow */ + scaledStem = cf2_intToFixed( x4 ); + else + scaledStem = FT_MulFix( stemWidthPer1000, ppem ); + + /* now apply the darkening parameters */ + + if ( scaledStem < cf2_intToFixed( x1 ) ) + *darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem ); + + else if ( scaledStem < cf2_intToFixed( x2 ) ) + { + FT_Int xdelta = x2 - x1; + FT_Int ydelta = y2 - y1; + FT_Int x = stemWidthPer1000 - + FT_DivFix( cf2_intToFixed( x1 ), ppem ); + + + if ( !xdelta ) + goto Try_x3; + + *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( cf2_intToFixed( y1 ), ppem ); + } + + else if ( scaledStem < cf2_intToFixed( x3 ) ) + { + Try_x3: + { + FT_Int xdelta = x3 - x2; + FT_Int ydelta = y3 - y2; + FT_Int x = stemWidthPer1000 - + FT_DivFix( cf2_intToFixed( x2 ), ppem ); + + + if ( !xdelta ) + goto Try_x4; + + *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( cf2_intToFixed( y2 ), ppem ); + } + } + + else if ( scaledStem < cf2_intToFixed( x4 ) ) + { + Try_x4: + { + FT_Int xdelta = x4 - x3; + FT_Int ydelta = y4 - y3; + FT_Int x = stemWidthPer1000 - + FT_DivFix( cf2_intToFixed( x3 ), ppem ); + + + if ( !xdelta ) + goto Use_y4; + + *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( cf2_intToFixed( y3 ), ppem ); + } + } + + else + { + Use_y4: + *darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem ); + } + + /* use half the amount on each side and convert back to true */ + /* character space */ + *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio ); + } + + /* add synthetic emboldening effect in character space */ + *darkenAmount += boldenAmount / 2; + } + + + /* set up values for the current FontDict and matrix; */ + /* called for each glyph to be rendered */ + + /* caller's transform is adjusted for subpixel positioning */ + static void + cf2_font_setup( CF2_Font font, + const CF2_Matrix* transform ) + { + /* pointer to parsed font object */ + PS_Decoder* decoder = font->decoder; + + FT_Bool needExtraSetup = FALSE; + + CFF_VStoreRec* vstore; + FT_Bool hasVariations = FALSE; + + /* character space units */ + CF2_Fixed boldenX = font->syntheticEmboldeningAmountX; + CF2_Fixed boldenY = font->syntheticEmboldeningAmountY; + + CFF_SubFont subFont; + CF2_Fixed ppem; + + CF2_UInt lenNormalizedV = 0; + FT_Fixed* normalizedV = NULL; + + /* clear previous error */ + font->error = FT_Err_Ok; + + /* if a CID fontDict has changed, we need to recompute some cached */ + /* data */ + subFont = cf2_getSubfont( decoder ); + if ( font->lastSubfont != subFont ) + { + font->lastSubfont = subFont; + needExtraSetup = TRUE; + } + + if ( !font->isT1 ) + { + /* check for variation vectors */ + vstore = cf2_getVStore( decoder ); + hasVariations = ( vstore->dataCount != 0 ); + + if ( hasVariations ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Service_CFFLoad cffload = (FT_Service_CFFLoad)font->cffload; + + + /* check whether Private DICT in this subfont needs to be reparsed */ + font->error = cf2_getNormalizedVector( decoder, + &lenNormalizedV, + &normalizedV ); + if ( font->error ) + return; + + if ( cffload->blend_check_vector( &subFont->blend, + subFont->private_dict.vsindex, + lenNormalizedV, + normalizedV ) ) + { + /* blend has changed, reparse */ + cffload->load_private_dict( decoder->cff, + subFont, + lenNormalizedV, + normalizedV ); + needExtraSetup = TRUE; + } +#endif + + /* copy from subfont */ + font->blend.font = subFont->blend.font; + + /* clear state of charstring blend */ + font->blend.usedBV = FALSE; + + /* initialize value for charstring */ + font->vsindex = subFont->private_dict.vsindex; + + /* store vector inputs for blends in charstring */ + font->lenNDV = lenNormalizedV; + font->NDV = normalizedV; + } + } + + /* if ppem has changed, we need to recompute some cached data */ + /* note: because of CID font matrix concatenation, ppem and transform */ + /* do not necessarily track. */ + ppem = cf2_getPpemY( decoder ); + if ( font->ppem != ppem ) + { + font->ppem = ppem; + needExtraSetup = TRUE; + } + + /* copy hinted flag on each call */ + font->hinted = FT_BOOL( font->renderingFlags & CF2_FlagsHinted ); + + /* determine if transform has changed; */ + /* include Fontmatrix but ignore translation */ + if ( ft_memcmp( transform, + &font->currentTransform, + 4 * sizeof ( CF2_Fixed ) ) != 0 ) + { + /* save `key' information for `cache of one' matrix data; */ + /* save client transform, without the translation */ + font->currentTransform = *transform; + font->currentTransform.tx = + font->currentTransform.ty = cf2_intToFixed( 0 ); + + /* TODO: FreeType transform is simple scalar; for now, use identity */ + /* for outer */ + font->innerTransform = *transform; + font->outerTransform.a = + font->outerTransform.d = cf2_intToFixed( 1 ); + font->outerTransform.b = + font->outerTransform.c = cf2_intToFixed( 0 ); + + needExtraSetup = TRUE; + } + + /* + * font->darkened is set to true if there is a stem darkening request or + * the font is synthetic emboldened. + * font->darkened controls whether to adjust blue zones, winding order, + * and hinting. + * + */ + if ( font->stemDarkened != ( font->renderingFlags & CF2_FlagsDarkened ) ) + { + font->stemDarkened = + FT_BOOL( font->renderingFlags & CF2_FlagsDarkened ); + + /* blue zones depend on darkened flag */ + needExtraSetup = TRUE; + } + + /* recompute variables that are dependent on transform or FontDict or */ + /* darken flag */ + if ( needExtraSetup ) + { + /* StdVW is found in the private dictionary; */ + /* recompute darkening amounts whenever private dictionary or */ + /* transform change */ + /* Note: a rendering flag turns darkening on or off, so we want to */ + /* store the `on' amounts; */ + /* darkening amount is computed in character space */ + /* TODO: testing size-dependent darkening here; */ + /* what to do for rotations? */ + + CF2_Fixed emRatio; + CF2_Fixed stdHW; + CF2_Int unitsPerEm = font->unitsPerEm; + + + if ( unitsPerEm == 0 ) + unitsPerEm = 1000; + + ppem = FT_MAX( cf2_intToFixed( 4 ), + font->ppem ); /* use minimum ppem of 4 */ + +#if 0 + /* since vstem is measured in the x-direction, we use the `a' member */ + /* of the fontMatrix */ + emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->a ); +#endif + + /* Freetype does not preserve the fontMatrix when parsing; use */ + /* unitsPerEm instead. */ + /* TODO: check precision of this */ + emRatio = cf2_intToFixed( 1000 ) / unitsPerEm; + font->stdVW = cf2_getStdVW( decoder ); + + if ( font->stdVW <= 0 ) + font->stdVW = FT_DivFix( cf2_intToFixed( 75 ), emRatio ); + + if ( boldenX > 0 ) + { + /* Ensure that boldenX is at least 1 pixel for synthetic bold font */ + /* (similar to what Avalon does) */ + boldenX = FT_MAX( boldenX, + FT_DivFix( cf2_intToFixed( unitsPerEm ), ppem ) ); + + /* Synthetic emboldening adds at least 1 pixel to darkenX, while */ + /* stem darkening adds at most half pixel. Since the purpose of */ + /* stem darkening (readability at small sizes) is met with */ + /* synthetic emboldening, no need to add stem darkening for a */ + /* synthetic bold font. */ + cf2_computeDarkening( emRatio, + ppem, + font->stdVW, + &font->darkenX, + boldenX, + FALSE, + font->darkenParams ); + } + else + cf2_computeDarkening( emRatio, + ppem, + font->stdVW, + &font->darkenX, + 0, + font->stemDarkened, + font->darkenParams ); + +#if 0 + /* since hstem is measured in the y-direction, we use the `d' member */ + /* of the fontMatrix */ + /* TODO: use the same units per em as above; check this */ + emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->d ); +#endif + + /* set the default stem width, because it must be the same for all */ + /* family members; */ + /* choose a constant for StdHW that depends on font contrast */ + stdHW = cf2_getStdHW( decoder ); + + if ( stdHW > 0 && font->stdVW > MUL_INT32( 2, stdHW ) ) + font->stdHW = FT_DivFix( cf2_intToFixed( 75 ), emRatio ); + else + { + /* low contrast font gets less hstem darkening */ + font->stdHW = FT_DivFix( cf2_intToFixed( 110 ), emRatio ); + } + + cf2_computeDarkening( emRatio, + ppem, + font->stdHW, + &font->darkenY, + boldenY, + font->stemDarkened, + font->darkenParams ); + + if ( font->darkenX != 0 || font->darkenY != 0 ) + font->darkened = TRUE; + else + font->darkened = FALSE; + + font->reverseWinding = FALSE; /* initial expectation is CCW */ + + /* compute blue zones for this instance */ + cf2_blues_init( &font->blues, font ); + + } /* needExtraSetup */ + } + + + /* equivalent to AdobeGetOutline */ + FT_LOCAL_DEF( FT_Error ) + cf2_getGlyphOutline( CF2_Font font, + CF2_Buffer charstring, + const CF2_Matrix* transform, + CF2_F16Dot16* glyphWidth ) + { + FT_Error lastError = FT_Err_Ok; + + FT_Vector translation; + +#if 0 + FT_Vector advancePoint; +#endif + + CF2_Fixed advWidth = 0; + FT_Bool needWinding; + + + /* Note: use both integer and fraction for outlines. This allows bbox */ + /* to come out directly. */ + + translation.x = transform->tx; + translation.y = transform->ty; + + /* set up values based on transform */ + cf2_font_setup( font, transform ); + if ( font->error ) + goto exit; /* setup encountered an error */ + + /* reset darken direction */ + font->reverseWinding = FALSE; + + /* winding order only affects darkening */ + needWinding = font->darkened; + + while ( 1 ) + { + /* reset output buffer */ + cf2_outline_reset( &font->outline ); + + /* build the outline, passing the full translation */ + cf2_interpT2CharString( font, + charstring, + (CF2_OutlineCallbacks)&font->outline, + &translation, + FALSE, + 0, + 0, + &advWidth ); + + if ( font->error ) + goto exit; + + if ( !needWinding ) + break; + + /* check winding order */ + if ( font->outline.root.windingMomentum >= 0 ) /* CFF is CCW */ + break; + + /* invert darkening and render again */ + /* TODO: this should be a parameter to getOutline-computeOffset */ + font->reverseWinding = TRUE; + + needWinding = FALSE; /* exit after next iteration */ + } + + /* finish storing client outline */ + cf2_outline_close( &font->outline ); + + exit: + /* FreeType just wants the advance width; there is no translation */ + *glyphWidth = advWidth; + + /* free resources and collect errors from objects we've used */ + cf2_setError( &font->error, lastError ); + + return font->error; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psfont.h b/vendor/freetype/src/psaux/psfont.h new file mode 100644 index 0000000..836fce4 --- /dev/null +++ b/vendor/freetype/src/psaux/psfont.h @@ -0,0 +1,134 @@ +/**************************************************************************** + * + * psfont.h + * + * Adobe's code for font instances (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSFONT_H_ +#define PSFONT_H_ + + +#include + +#include "psft.h" +#include "psblues.h" + + +FT_BEGIN_HEADER + + +#define CF2_OPERAND_STACK_SIZE 48 +#define CF2_MAX_SUBR 16 /* maximum subroutine nesting; */ + /* only 10 are allowed but there exist */ + /* fonts like `HiraKakuProN-W3.ttf' */ + /* (Hiragino Kaku Gothic ProN W3; */ + /* 8.2d6e1; 2014-12-19) that exceed */ + /* this limit */ +#define CF2_STORAGE_SIZE 32 + + + /* typedef is in `cf2glue.h' */ + struct CF2_FontRec_ + { + FT_Memory memory; + FT_Error error; /* shared error for this instance */ + + FT_Bool isT1; + FT_Bool isCFF2; + CF2_RenderingFlags renderingFlags; + + /* variables that depend on Transform: */ + /* the following have zero translation; */ + /* inner * outer = font * original */ + + CF2_Matrix currentTransform; /* original client matrix */ + CF2_Matrix innerTransform; /* for hinting; erect, scaled */ + CF2_Matrix outerTransform; /* post hinting; includes rotations */ + CF2_Fixed ppem; /* transform-dependent */ + + /* variation data */ + CFF_BlendRec blend; /* cached charstring blend vector */ + CF2_UInt vsindex; /* current vsindex */ + CF2_UInt lenNDV; /* current length NDV or zero */ + FT_Fixed* NDV; /* ptr to current NDV or NULL */ + + CF2_Int unitsPerEm; + + CF2_Fixed syntheticEmboldeningAmountX; /* character space units */ + CF2_Fixed syntheticEmboldeningAmountY; /* character space units */ + + /* FreeType related members */ + CF2_OutlineRec outline; /* freetype glyph outline functions */ + PS_Decoder* decoder; + CFF_SubFont lastSubfont; /* FreeType parsed data; */ + /* top font or subfont */ + + /* these flags can vary from one call to the next */ + FT_Bool hinted; + FT_Bool darkened; /* true if stemDarkened or synthetic bold */ + /* i.e. darkenX != 0 || darkenY != 0 */ + FT_Bool stemDarkened; + + FT_Int darkenParams[8]; /* 1000 unit character space */ + + /* variables that depend on both FontDict and Transform */ + CF2_Fixed stdVW; /* in character space; depends on dict entry */ + CF2_Fixed stdHW; /* in character space; depends on dict entry */ + CF2_Fixed darkenX; /* character space units */ + CF2_Fixed darkenY; /* depends on transform */ + /* and private dict (StdVW) */ + FT_Bool reverseWinding; /* darken assuming */ + /* counterclockwise winding */ + + CF2_BluesRec blues; /* computed zone data */ + + FT_Service_CFFLoad cffload; /* pointer to cff functions */ + }; + + + FT_LOCAL( FT_Error ) + cf2_getGlyphOutline( CF2_Font font, + CF2_Buffer charstring, + const CF2_Matrix* transform, + CF2_F16Dot16* glyphWidth ); + + +FT_END_HEADER + + +#endif /* PSFONT_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psft.c b/vendor/freetype/src/psaux/psft.c new file mode 100644 index 0000000..618864e --- /dev/null +++ b/vendor/freetype/src/psaux/psft.c @@ -0,0 +1,895 @@ +/**************************************************************************** + * + * psft.c + * + * FreeType Glue Component to Adobe's Interpreter (body). + * + * Copyright 2013-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psfont.h" +#include "pserror.h" +#include "psobjs.h" +#include "cffdecode.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include + + +#define CF2_MAX_SIZE cf2_intToFixed( 2000 ) /* max ppem */ + + + /* + * This check should avoid most internal overflow cases. Clients should + * generally respond to `Glyph_Too_Big' by getting a glyph outline + * at EM size, scaling it and filling it as a graphics operation. + * + */ + static FT_Error + cf2_checkTransform( const CF2_Matrix* transform, + CF2_Int unitsPerEm ) + { + CF2_Fixed maxScale; + + + if ( transform->a <= 0 || transform->d <= 0 ) + return FT_THROW( Invalid_Size_Handle ); + + FT_ASSERT( unitsPerEm > 0 ); + FT_ASSERT( transform->b == 0 && transform->c == 0 ); + FT_ASSERT( transform->tx == 0 && transform->ty == 0 ); + + if ( unitsPerEm > 0x7FFF ) + return FT_THROW( Glyph_Too_Big ); + + maxScale = FT_DivFix( CF2_MAX_SIZE, cf2_intToFixed( unitsPerEm ) ); + + if ( transform->a > maxScale || transform->d > maxScale ) + return FT_THROW( Glyph_Too_Big ); + + return FT_Err_Ok; + } + + + static void + cf2_setGlyphWidth( CF2_Outline outline, + CF2_Fixed width ) + { + PS_Decoder* decoder = outline->decoder; + + + FT_ASSERT( decoder ); + + if ( !decoder->builder.is_t1 ) + *decoder->glyph_width = cf2_fixedToInt( width ); + } + + + /* Clean up font instance. */ + static void + cf2_free_instance( void* ptr ) + { + CF2_Font font = (CF2_Font)ptr; + + + if ( font ) + { + FT_Memory memory = font->memory; + + + FT_FREE( font->blend.lastNDV ); + FT_FREE( font->blend.BV ); + } + } + + + /********************************************* + * + * functions for handling client outline; + * FreeType uses coordinates in 26.6 format + * + */ + + static void + cf2_builder_moveTo( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ) + { + /* downcast the object pointer */ + CF2_Outline outline = (CF2_Outline)callbacks; + PS_Builder* builder; + + (void)params; /* only used in debug mode */ + + + FT_ASSERT( outline && outline->decoder ); + FT_ASSERT( params->op == CF2_PathOpMoveTo ); + + builder = &outline->decoder->builder; + + /* note: two successive moves simply close the contour twice */ + ps_builder_close_contour( builder ); + builder->path_begun = 0; + } + + + static void + cf2_builder_lineTo( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ) + { + FT_Error error; + + /* downcast the object pointer */ + CF2_Outline outline = (CF2_Outline)callbacks; + PS_Builder* builder; + + + FT_ASSERT( outline && outline->decoder ); + FT_ASSERT( params->op == CF2_PathOpLineTo ); + + builder = &outline->decoder->builder; + + if ( !builder->path_begun ) + { + /* record the move before the line; also check points and set */ + /* `path_begun' */ + error = ps_builder_start_point( builder, + params->pt0.x, + params->pt0.y ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + } + + /* `ps_builder_add_point1' includes a check_points call for one point */ + error = ps_builder_add_point1( builder, + params->pt1.x, + params->pt1.y ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + } + + + static void + cf2_builder_cubeTo( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ) + { + FT_Error error; + + /* downcast the object pointer */ + CF2_Outline outline = (CF2_Outline)callbacks; + PS_Builder* builder; + + + FT_ASSERT( outline && outline->decoder ); + FT_ASSERT( params->op == CF2_PathOpCubeTo ); + + builder = &outline->decoder->builder; + + if ( !builder->path_begun ) + { + /* record the move before the line; also check points and set */ + /* `path_begun' */ + error = ps_builder_start_point( builder, + params->pt0.x, + params->pt0.y ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + } + + /* prepare room for 3 points: 2 off-curve, 1 on-curve */ + error = ps_builder_check_points( builder, 3 ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + + ps_builder_add_point( builder, + params->pt1.x, + params->pt1.y, 0 ); + ps_builder_add_point( builder, + params->pt2.x, + params->pt2.y, 0 ); + ps_builder_add_point( builder, + params->pt3.x, + params->pt3.y, 1 ); + } + + + static void + cf2_outline_init( CF2_Outline outline, + FT_Memory memory, + FT_Error* error ) + { + FT_ZERO( outline ); + + outline->root.memory = memory; + outline->root.error = error; + + outline->root.moveTo = cf2_builder_moveTo; + outline->root.lineTo = cf2_builder_lineTo; + outline->root.cubeTo = cf2_builder_cubeTo; + } + + + /* get scaling and hint flag from GlyphSlot */ + static void + cf2_getScaleAndHintFlag( PS_Decoder* decoder, + CF2_Fixed* x_scale, + CF2_Fixed* y_scale, + FT_Bool* hinted, + FT_Bool* scaled ) + { + FT_ASSERT( decoder && decoder->builder.glyph ); + + /* note: FreeType scale includes a factor of 64 */ + *hinted = decoder->builder.glyph->hint; + *scaled = decoder->builder.glyph->scaled; + + if ( *hinted ) + { + *x_scale = ADD_INT32( decoder->builder.glyph->x_scale, 32 ) / 64; + *y_scale = ADD_INT32( decoder->builder.glyph->y_scale, 32 ) / 64; + } + else + { + /* for unhinted outlines, `cff_slot_load' does the scaling, */ + /* thus render at `unity' scale */ + + *x_scale = 0x0400; /* 1/64 as 16.16 */ + *y_scale = 0x0400; + } + } + + + /* get units per em from `FT_Face' */ + /* TODO: should handle font matrix concatenation? */ + static FT_UShort + cf2_getUnitsPerEm( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->builder.face ); + + return decoder->builder.face->units_per_EM; + } + + + /* Main entry point: Render one glyph. */ + FT_LOCAL_DEF( FT_Error ) + cf2_decoder_parse_charstrings( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ) + { + FT_Memory memory; + FT_Error error = FT_Err_Ok; + CF2_Font font; + + FT_Bool is_t1 = decoder->builder.is_t1; + + + FT_ASSERT( decoder && + ( is_t1 || decoder->cff ) ); + + if ( is_t1 && !decoder->current_subfont ) + { + FT_ERROR(( "cf2_decoder_parse_charstrings (Type 1): " + "SubFont missing. Use `t1_make_subfont' first\n" )); + return FT_THROW( Invalid_Table ); + } + + memory = decoder->builder.memory; + + /* CF2 data is saved here across glyphs */ + font = (CF2_Font)decoder->cf2_instance->data; + + /* on first glyph, allocate instance structure */ + if ( !decoder->cf2_instance->data ) + { + decoder->cf2_instance->finalizer = + (FT_Generic_Finalizer)cf2_free_instance; + + if ( FT_ALLOC( decoder->cf2_instance->data, + sizeof ( CF2_FontRec ) ) ) + return FT_THROW( Out_Of_Memory ); + + font = (CF2_Font)decoder->cf2_instance->data; + + font->memory = memory; + + if ( !is_t1 ) + font->cffload = (FT_Service_CFFLoad)decoder->cff->cffload; + + /* initialize a client outline, to be shared by each glyph rendered */ + cf2_outline_init( &font->outline, font->memory, &font->error ); + } + + /* save decoder; it is a stack variable and will be different on each */ + /* call */ + font->decoder = decoder; + font->outline.decoder = decoder; + + { + /* build parameters for Adobe engine */ + + PS_Builder* builder = &decoder->builder; + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); + + FT_Bool no_stem_darkening_driver = + driver->no_stem_darkening; + FT_Char no_stem_darkening_font = + builder->face->internal->no_stem_darkening; + + /* local error */ + FT_Error error2 = FT_Err_Ok; + CF2_BufferRec buf; + CF2_Matrix transform; + CF2_F16Dot16 glyphWidth; + + FT_Bool hinted; + FT_Bool scaled; + + + /* FreeType has already looked up the GID; convert to */ + /* `RegionBuffer', assuming that the input has been validated */ + FT_ASSERT( charstring_base + charstring_len >= charstring_base ); + + FT_ZERO( &buf ); + buf.start = + buf.ptr = charstring_base; + buf.end = FT_OFFSET( charstring_base, charstring_len ); + + FT_ZERO( &transform ); + + cf2_getScaleAndHintFlag( decoder, + &transform.a, + &transform.d, + &hinted, + &scaled ); + + if ( is_t1 ) + font->isCFF2 = FALSE; + else + { + /* copy isCFF2 boolean from TT_Face to CF2_Font */ + font->isCFF2 = ((TT_Face)builder->face)->is_cff2; + } + font->isT1 = is_t1; + + font->renderingFlags = 0; + if ( hinted ) + font->renderingFlags |= CF2_FlagsHinted; + if ( scaled && ( !no_stem_darkening_font || + ( no_stem_darkening_font < 0 && + !no_stem_darkening_driver ) ) ) + font->renderingFlags |= CF2_FlagsDarkened; + + font->darkenParams[0] = driver->darken_params[0]; + font->darkenParams[1] = driver->darken_params[1]; + font->darkenParams[2] = driver->darken_params[2]; + font->darkenParams[3] = driver->darken_params[3]; + font->darkenParams[4] = driver->darken_params[4]; + font->darkenParams[5] = driver->darken_params[5]; + font->darkenParams[6] = driver->darken_params[6]; + font->darkenParams[7] = driver->darken_params[7]; + + /* now get an outline for this glyph; */ + /* also get units per em to validate scale */ + font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder ); + + if ( scaled ) + { + error2 = cf2_checkTransform( &transform, font->unitsPerEm ); + if ( error2 ) + return error2; + } + + error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth ); + if ( error2 ) + return FT_ERR( Invalid_File_Format ); + + cf2_setGlyphWidth( &font->outline, glyphWidth ); + + return FT_Err_Ok; + } + } + + + /* get pointer to current FreeType subfont (based on current glyphID) */ + FT_LOCAL_DEF( CFF_SubFont ) + cf2_getSubfont( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return decoder->current_subfont; + } + + + /* get pointer to VStore structure */ + FT_LOCAL_DEF( CFF_VStore ) + cf2_getVStore( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->cff ); + + return &decoder->cff->vstore; + } + + + /* get maxstack value from CFF2 Top DICT */ + FT_LOCAL_DEF( FT_UInt ) + cf2_getMaxstack( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->cff ); + + return decoder->cff->top_font.font_dict.maxstack; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Get normalized design vector for current render request; */ + /* return pointer and length. */ + /* */ + /* Note: Uses FT_Fixed not CF2_Fixed for the vector. */ + FT_LOCAL_DEF( FT_Error ) + cf2_getNormalizedVector( PS_Decoder* decoder, + CF2_UInt *len, + FT_Fixed* *vec ) + { + TT_Face face; + FT_Service_MultiMasters mm; + + + FT_ASSERT( decoder && decoder->builder.face ); + FT_ASSERT( vec && len ); + FT_ASSERT( !decoder->builder.is_t1 ); + + face = (TT_Face)decoder->builder.face; + mm = (FT_Service_MultiMasters)face->mm; + + return mm->get_var_blend( FT_FACE( face ), len, NULL, vec, NULL ); + } +#endif + + + /* get `y_ppem' from `CFF_Size' */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getPpemY( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && + decoder->builder.face && + decoder->builder.face->size ); + + /* + * Note that `y_ppem' can be zero if there wasn't a call to + * `FT_Set_Char_Size' or something similar. However, this isn't a + * problem since we come to this place in the code only if + * FT_LOAD_NO_SCALE is set (the other case gets caught by + * `cf2_checkTransform'). The ppem value is needed to compute the stem + * darkening, which is disabled for getting the unscaled outline. + * + */ + return cf2_intToFixed( + decoder->builder.face->size->metrics.y_ppem ); + } + + + /* get standard stem widths for the current subfont; */ + /* FreeType stores these as integer font units */ + /* (note: variable names seem swapped) */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getStdVW( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.standard_height ); + } + + + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getStdHW( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.standard_width ); + } + + + /* note: FreeType stores 1000 times the actual value for `BlueScale' */ + FT_LOCAL_DEF( void ) + cf2_getBlueMetrics( PS_Decoder* decoder, + CF2_Fixed* blueScale, + CF2_Fixed* blueShift, + CF2_Fixed* blueFuzz ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *blueScale = FT_DivFix( + decoder->current_subfont->private_dict.blue_scale, + cf2_intToFixed( 1000 ) ); + *blueShift = cf2_intToFixed( + decoder->current_subfont->private_dict.blue_shift ); + *blueFuzz = cf2_intToFixed( + decoder->current_subfont->private_dict.blue_fuzz ); + } + + + /* get blue values counts and arrays; the FreeType parser has validated */ + /* the counts and verified that each is an even number */ + FT_LOCAL_DEF( void ) + cf2_getBlueValues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_blue_values; + *data = (FT_Pos*) + &decoder->current_subfont->private_dict.blue_values; + } + + + FT_LOCAL_DEF( void ) + cf2_getOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_other_blues; + *data = (FT_Pos*) + &decoder->current_subfont->private_dict.other_blues; + } + + + FT_LOCAL_DEF( void ) + cf2_getFamilyBlues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_family_blues; + *data = (FT_Pos*) + &decoder->current_subfont->private_dict.family_blues; + } + + + FT_LOCAL_DEF( void ) + cf2_getFamilyOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_family_other_blues; + *data = (FT_Pos*) + &decoder->current_subfont->private_dict.family_other_blues; + } + + + FT_LOCAL_DEF( CF2_Int ) + cf2_getLanguageGroup( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return decoder->current_subfont->private_dict.language_group; + } + + + /* convert unbiased subroutine index to `CF2_Buffer' and */ + /* return 0 on success */ + FT_LOCAL_DEF( CF2_Int ) + cf2_initGlobalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ) + { + CF2_UInt idx; + + + FT_ASSERT( decoder ); + + FT_ZERO( buf ); + + idx = (CF2_UInt)( subrNum + decoder->globals_bias ); + if ( idx >= decoder->num_globals ) + return TRUE; /* error */ + + FT_ASSERT( decoder->globals ); + + buf->start = + buf->ptr = decoder->globals[idx]; + buf->end = decoder->globals[idx + 1]; + + return FALSE; /* success */ + } + + + /* convert AdobeStandardEncoding code to CF2_Buffer; */ + /* used for seac component */ + FT_LOCAL_DEF( FT_Error ) + cf2_getSeacComponent( PS_Decoder* decoder, + CF2_Int code, + CF2_Buffer buf ) + { + CF2_Int gid; + FT_Byte* charstring; + FT_ULong len; + FT_Error error; + + + FT_ASSERT( decoder ); + FT_ASSERT( !decoder->builder.is_t1 ); + + FT_ZERO( buf ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Incremental fonts don't necessarily have valid charsets. */ + /* They use the character code, not the glyph index, in this case. */ + if ( decoder->builder.face->internal->incremental_interface ) + gid = code; + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code ); + if ( gid < 0 ) + return FT_THROW( Invalid_Glyph_Format ); + } + + error = decoder->get_glyph_callback( (TT_Face)decoder->builder.face, + (CF2_UInt)gid, + &charstring, + &len ); + /* TODO: for now, just pass the FreeType error through */ + if ( error ) + return error; + + /* assume input has been validated */ + FT_ASSERT( charstring + len >= charstring ); + + buf->start = charstring; + buf->end = FT_OFFSET( charstring, len ); + buf->ptr = buf->start; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + cf2_freeSeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ) + { + FT_ASSERT( decoder ); + FT_ASSERT( !decoder->builder.is_t1 ); + + decoder->free_glyph_callback( (TT_Face)decoder->builder.face, + (FT_Byte**)&buf->start, + (FT_ULong)( buf->end - buf->start ) ); + } + + + FT_LOCAL_DEF( FT_Error ) + cf2_getT1SeacComponent( PS_Decoder* decoder, + FT_UInt glyph_index, + CF2_Buffer buf ) + { + FT_Data glyph_data; + FT_Error error = FT_Err_Ok; + T1_Face face = (T1_Face)decoder->builder.face; + T1_Font type1 = &face->type1; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; + + + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( inc ) + error = inc->funcs->get_glyph_data( inc->object, + glyph_index, &glyph_data ); + else +#endif + /* For ordinary fonts get the character data stored in the face record. */ + { + glyph_data.pointer = type1->charstrings[glyph_index]; + glyph_data.length = type1->charstrings_len[glyph_index]; + } + + if ( !error ) + { + FT_Byte* charstring_base = (FT_Byte*)glyph_data.pointer; + FT_ULong charstring_len = glyph_data.length; + + + FT_ASSERT( charstring_base + charstring_len >= charstring_base ); + + FT_ZERO( buf ); + buf->start = + buf->ptr = charstring_base; + buf->end = charstring_base + charstring_len; + } + + return error; + } + + + FT_LOCAL_DEF( void ) + cf2_freeT1SeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + T1_Face face; + FT_Data data; + + + FT_ASSERT( decoder ); + + face = (T1_Face)decoder->builder.face; + + data.pointer = buf->start; + data.length = (FT_UInt)( buf->end - buf->start ); + + if ( face->root.internal->incremental_interface ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &data ); + +#else /* !FT_CONFIG_OPTION_INCREMENTAL */ + + FT_UNUSED( decoder ); + FT_UNUSED( buf ); + +#endif /* !FT_CONFIG_OPTION_INCREMENTAL */ + } + + + FT_LOCAL_DEF( CF2_Int ) + cf2_initLocalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ) + { + CF2_UInt idx; + + + FT_ASSERT( decoder ); + + FT_ZERO( buf ); + + idx = (CF2_UInt)( subrNum + decoder->locals_bias ); + if ( idx >= decoder->num_locals ) + return TRUE; /* error */ + + FT_ASSERT( decoder->locals ); + + buf->start = decoder->locals[idx]; + + if ( decoder->builder.is_t1 ) + { + /* The Type 1 driver stores subroutines without the seed bytes. */ + /* The CID driver stores subroutines with seed bytes. This */ + /* case is taken care of when decoder->subrs_len == 0. */ + if ( decoder->locals_len ) + buf->end = FT_OFFSET( buf->start, decoder->locals_len[idx] ); + else + { + /* We are using subroutines from a CID font. We must adjust */ + /* for the seed bytes. */ + buf->start += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + buf->end = decoder->locals[idx + 1]; + } + + if ( !buf->start ) + { + FT_ERROR(( "cf2_initLocalRegionBuffer (Type 1 mode):" + " invoking empty subrs\n" )); + } + } + else + { + buf->end = decoder->locals[idx + 1]; + } + + buf->ptr = buf->start; + + return FALSE; /* success */ + } + + + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getDefaultWidthX( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.default_width ); + } + + + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getNominalWidthX( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.nominal_width ); + } + + + FT_LOCAL_DEF( void ) + cf2_outline_reset( CF2_Outline outline ) + { + PS_Decoder* decoder = outline->decoder; + + + FT_ASSERT( decoder ); + + outline->root.windingMomentum = 0; + + FT_GlyphLoader_Rewind( decoder->builder.loader ); + } + + + FT_LOCAL_DEF( void ) + cf2_outline_close( CF2_Outline outline ) + { + PS_Decoder* decoder = outline->decoder; + + + FT_ASSERT( decoder ); + + ps_builder_close_contour( &decoder->builder ); + + FT_GlyphLoader_Add( decoder->builder.loader ); + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psft.h b/vendor/freetype/src/psaux/psft.h new file mode 100644 index 0000000..3da454e --- /dev/null +++ b/vendor/freetype/src/psaux/psft.h @@ -0,0 +1,167 @@ +/**************************************************************************** + * + * psft.h + * + * FreeType Glue Component to Adobe's Interpreter (specification). + * + * Copyright 2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSFT_H_ +#define PSFT_H_ + + +#include +#include "pstypes.h" + + /* TODO: disable asserts for now */ +#define CF2_NDEBUG + + +#include + +#include "psglue.h" +#include /* for PS_Decoder */ + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + cf2_decoder_parse_charstrings( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + + FT_LOCAL( CFF_SubFont ) + cf2_getSubfont( PS_Decoder* decoder ); + + FT_LOCAL( CFF_VStore ) + cf2_getVStore( PS_Decoder* decoder ); + + FT_LOCAL( FT_UInt ) + cf2_getMaxstack( PS_Decoder* decoder ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_LOCAL( FT_Error ) + cf2_getNormalizedVector( PS_Decoder* decoder, + CF2_UInt *len, + FT_Fixed* *vec ); +#endif + + FT_LOCAL( CF2_Fixed ) + cf2_getPpemY( PS_Decoder* decoder ); + FT_LOCAL( CF2_Fixed ) + cf2_getStdVW( PS_Decoder* decoder ); + FT_LOCAL( CF2_Fixed ) + cf2_getStdHW( PS_Decoder* decoder ); + + FT_LOCAL( void ) + cf2_getBlueMetrics( PS_Decoder* decoder, + CF2_Fixed* blueScale, + CF2_Fixed* blueShift, + CF2_Fixed* blueFuzz ); + FT_LOCAL( void ) + cf2_getBlueValues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ); + FT_LOCAL( void ) + cf2_getOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ); + FT_LOCAL( void ) + cf2_getFamilyBlues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ); + FT_LOCAL( void ) + cf2_getFamilyOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Pos* *data ); + + FT_LOCAL( CF2_Int ) + cf2_getLanguageGroup( PS_Decoder* decoder ); + + FT_LOCAL( CF2_Int ) + cf2_initGlobalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ); + FT_LOCAL( FT_Error ) + cf2_getSeacComponent( PS_Decoder* decoder, + CF2_Int code, + CF2_Buffer buf ); + FT_LOCAL( void ) + cf2_freeSeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ); + FT_LOCAL( CF2_Int ) + cf2_initLocalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ); + + FT_LOCAL( CF2_Fixed ) + cf2_getDefaultWidthX( PS_Decoder* decoder ); + FT_LOCAL( CF2_Fixed ) + cf2_getNominalWidthX( PS_Decoder* decoder ); + + + FT_LOCAL( FT_Error ) + cf2_getT1SeacComponent( PS_Decoder* decoder, + FT_UInt glyph_index, + CF2_Buffer buf ); + FT_LOCAL( void ) + cf2_freeT1SeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ); + + /* + * FreeType client outline + * + * process output from the charstring interpreter + */ + typedef struct CF2_OutlineRec_ + { + CF2_OutlineCallbacksRec root; /* base class must be first */ + PS_Decoder* decoder; + + } CF2_OutlineRec, *CF2_Outline; + + + FT_LOCAL( void ) + cf2_outline_reset( CF2_Outline outline ); + FT_LOCAL( void ) + cf2_outline_close( CF2_Outline outline ); + + +FT_END_HEADER + + +#endif /* PSFT_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psglue.h b/vendor/freetype/src/psaux/psglue.h new file mode 100644 index 0000000..63085d7 --- /dev/null +++ b/vendor/freetype/src/psaux/psglue.h @@ -0,0 +1,144 @@ +/**************************************************************************** + * + * psglue.h + * + * Adobe's code for shared stuff (specification only). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSGLUE_H_ +#define PSGLUE_H_ + + +/* common includes for other modules */ +#include "pserror.h" +#include "psfixed.h" +#include "psarrst.h" +#include "psread.h" + + +FT_BEGIN_HEADER + + + /* rendering parameters */ + + /* apply hints to rendered glyphs */ +#define CF2_FlagsHinted 1 + /* for testing */ +#define CF2_FlagsDarkened 2 + + /* type for holding the flags */ + typedef CF2_Int CF2_RenderingFlags; + + + /* elements of a glyph outline */ + typedef enum CF2_PathOp_ + { + CF2_PathOpMoveTo = 1, /* change the current point */ + CF2_PathOpLineTo = 2, /* line */ + CF2_PathOpQuadTo = 3, /* quadratic curve */ + CF2_PathOpCubeTo = 4 /* cubic curve */ + + } CF2_PathOp; + + + /* a matrix of fixed-point values */ + typedef struct CF2_Matrix_ + { + CF2_F16Dot16 a; + CF2_F16Dot16 b; + CF2_F16Dot16 c; + CF2_F16Dot16 d; + CF2_F16Dot16 tx; + CF2_F16Dot16 ty; + + } CF2_Matrix; + + + /* these typedefs are needed by more than one header file */ + /* and gcc compiler doesn't allow redefinition */ + typedef struct CF2_FontRec_ CF2_FontRec, *CF2_Font; + typedef struct CF2_HintRec_ CF2_HintRec, *CF2_Hint; + + + /* A common structure for all callback parameters. */ + /* */ + /* Some members may be unused. For example, `pt0' is not used for */ + /* `moveTo' and `pt3' is not used for `quadTo'. The initial point `pt0' */ + /* is included for each path element for generality; curve conversions */ + /* need it. The `op' parameter allows one function to handle multiple */ + /* element types. */ + + typedef struct CF2_CallbackParamsRec_ + { + FT_Vector pt0; + FT_Vector pt1; + FT_Vector pt2; + FT_Vector pt3; + + CF2_Int op; + + } CF2_CallbackParamsRec, *CF2_CallbackParams; + + + /* forward reference */ + typedef struct CF2_OutlineCallbacksRec_ CF2_OutlineCallbacksRec, + *CF2_OutlineCallbacks; + + /* callback function pointers */ + typedef void + (*CF2_Callback_Type)( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ); + + + struct CF2_OutlineCallbacksRec_ + { + CF2_Callback_Type moveTo; + CF2_Callback_Type lineTo; + CF2_Callback_Type quadTo; + CF2_Callback_Type cubeTo; + + CF2_Int windingMomentum; /* for winding order detection */ + + FT_Memory memory; + FT_Error* error; + }; + + +FT_END_HEADER + + +#endif /* PSGLUE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/pshints.c b/vendor/freetype/src/psaux/pshints.c new file mode 100644 index 0000000..7bd08a9 --- /dev/null +++ b/vendor/freetype/src/psaux/pshints.c @@ -0,0 +1,1952 @@ +/**************************************************************************** + * + * pshints.c + * + * Adobe's code for handling CFF hints (body). + * + * Copyright 2007-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" +#include "psfont.h" +#include "pshints.h" +#include "psintrp.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cf2hints + + + typedef struct CF2_HintMoveRec_ + { + size_t j; /* index of upper hint map edge */ + CF2_Fixed moveUp; /* adjustment to optimum position */ + + } CF2_HintMoveRec, *CF2_HintMove; + + + /* Compute angular momentum for winding order detection. It is called */ + /* for all lines and curves, but not necessarily in element order. */ + static CF2_Int + cf2_getWindingMomentum( CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2 ) + { + /* cross product of pt1 position from origin with pt2 position from */ + /* pt1; we reduce the precision so that the result fits into 32 bits */ + + return ( x1 >> 16 ) * ( SUB_INT32( y2, y1 ) >> 16 ) - + ( y1 >> 16 ) * ( SUB_INT32( x2, x1 ) >> 16 ); + } + + + /* + * Construct from a StemHint; this is used as a parameter to + * `cf2_blues_capture'. + * `hintOrigin' is the character space displacement of a seac accent. + * Adjust stem hint for darkening here. + * + */ + static void + cf2_hint_init( CF2_Hint hint, + const CF2_ArrStack stemHintArray, + size_t indexStemHint, + const CF2_Font font, + CF2_Fixed hintOrigin, + CF2_Fixed scale, + FT_Bool bottom ) + { + CF2_Fixed width; + const CF2_StemHintRec* stemHint; + + + FT_ZERO( hint ); + + stemHint = (const CF2_StemHintRec*)cf2_arrstack_getPointer( + stemHintArray, + indexStemHint ); + + width = SUB_INT32( stemHint->max, stemHint->min ); + + if ( width == cf2_intToFixed( -21 ) ) + { + /* ghost bottom */ + + if ( bottom ) + { + hint->csCoord = stemHint->max; + hint->flags = CF2_GhostBottom; + } + else + hint->flags = 0; + } + + else if ( width == cf2_intToFixed( -20 ) ) + { + /* ghost top */ + + if ( bottom ) + hint->flags = 0; + else + { + hint->csCoord = stemHint->min; + hint->flags = CF2_GhostTop; + } + } + + else if ( width < 0 ) + { + /* inverted pair */ + + /* + * Hints with negative widths were produced by an early version of a + * non-Adobe font tool. The Type 2 spec allows edge (ghost) hints + * with negative widths, but says + * + * All other negative widths have undefined meaning. + * + * CoolType has a silent workaround that negates the hint width; for + * permissive mode, we do the same here. + * + * Note: Such fonts cannot use ghost hints, but should otherwise work. + * Note: Some poor hints in our faux fonts can produce negative + * widths at some blends. For example, see a light weight of + * `u' in ASerifMM. + * + */ + if ( bottom ) + { + hint->csCoord = stemHint->max; + hint->flags = CF2_PairBottom; + } + else + { + hint->csCoord = stemHint->min; + hint->flags = CF2_PairTop; + } + } + + else + { + /* normal pair */ + + if ( bottom ) + { + hint->csCoord = stemHint->min; + hint->flags = CF2_PairBottom; + } + else + { + hint->csCoord = stemHint->max; + hint->flags = CF2_PairTop; + } + } + + /* Now that ghost hints have been detected, adjust this edge for */ + /* darkening. Bottoms are not changed; tops are incremented by twice */ + /* `darkenY'. */ + if ( cf2_hint_isTop( hint ) ) + hint->csCoord = ADD_INT32( hint->csCoord, 2 * font->darkenY ); + + hint->csCoord = ADD_INT32( hint->csCoord, hintOrigin ); + hint->scale = scale; + hint->index = indexStemHint; /* index in original stem hint array */ + + /* if original stem hint has been used, use the same position */ + if ( hint->flags != 0 && stemHint->used ) + { + if ( cf2_hint_isTop( hint ) ) + hint->dsCoord = stemHint->maxDS; + else + hint->dsCoord = stemHint->minDS; + + cf2_hint_lock( hint ); + } + else + hint->dsCoord = FT_MulFix( hint->csCoord, scale ); + } + + + /* initialize an invalid hint map element */ + static void + cf2_hint_initZero( CF2_Hint hint ) + { + FT_ZERO( hint ); + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hint_isValid( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags ); + } + + + static FT_Bool + cf2_hint_isPair( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & ( CF2_PairBottom | CF2_PairTop ) ); + } + + + static FT_Bool + cf2_hint_isPairTop( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & CF2_PairTop ); + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hint_isTop( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & ( CF2_PairTop | CF2_GhostTop ) ); + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hint_isBottom( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & ( CF2_PairBottom | CF2_GhostBottom ) ); + } + + + static FT_Bool + cf2_hint_isLocked( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & CF2_Locked ); + } + + + static FT_Bool + cf2_hint_isSynthetic( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & CF2_Synthetic ); + } + + + FT_LOCAL_DEF( void ) + cf2_hint_lock( CF2_Hint hint ) + { + hint->flags |= CF2_Locked; + } + + + FT_LOCAL_DEF( void ) + cf2_hintmap_init( CF2_HintMap hintmap, + CF2_Font font, + CF2_HintMap initialMap, + CF2_ArrStack hintMoves, + CF2_Fixed scale ) + { + FT_ZERO( hintmap ); + + /* copy parameters from font instance */ + hintmap->hinted = font->hinted; + hintmap->scale = scale; + hintmap->font = font; + hintmap->initialHintMap = initialMap; + /* will clear in `cf2_hintmap_adjustHints' */ + hintmap->hintMoves = hintMoves; + } + + + static FT_Bool + cf2_hintmap_isValid( const CF2_HintMap hintmap ) + { + return hintmap->isValid; + } + + + static void + cf2_hintmap_dump( CF2_HintMap hintmap ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + CF2_UInt i; + + + FT_TRACE6(( " index csCoord dsCoord scale flags\n" )); + + for ( i = 0; i < hintmap->count; i++ ) + { + CF2_Hint hint = &hintmap->edge[i]; + + + FT_TRACE6(( " %3zu %7.2f %7.2f %5d %s%s%s%s\n", + hint->index, + hint->csCoord / 65536.0, + hint->dsCoord / ( hint->scale * 1.0 ), + hint->scale, + ( cf2_hint_isPair( hint ) ? "p" : "g" ), + ( cf2_hint_isTop( hint ) ? "t" : "b" ), + ( cf2_hint_isLocked( hint ) ? "L" : ""), + ( cf2_hint_isSynthetic( hint ) ? "S" : "" ) )); + } +#else + FT_UNUSED( hintmap ); +#endif + } + + + /* transform character space coordinate to device space using hint map */ + static CF2_Fixed + cf2_hintmap_map( CF2_HintMap hintmap, + CF2_Fixed csCoord ) + { + if ( hintmap->count == 0 || !hintmap->hinted ) + { + /* there are no hints; use uniform scale and zero offset */ + return FT_MulFix( csCoord, hintmap->scale ); + } + else + { + /* start linear search from last hit */ + CF2_UInt i = hintmap->lastIndex; + + + FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES ); + + /* search up */ + while ( i < hintmap->count - 1 && + csCoord >= hintmap->edge[i + 1].csCoord ) + i += 1; + + /* search down */ + while ( i > 0 && csCoord < hintmap->edge[i].csCoord ) + i -= 1; + + hintmap->lastIndex = i; + + if ( i == 0 && csCoord < hintmap->edge[0].csCoord ) + { + /* special case for points below first edge: use uniform scale */ + return ADD_INT32( FT_MulFix( SUB_INT32( csCoord, + hintmap->edge[0].csCoord ), + hintmap->scale ), + hintmap->edge[0].dsCoord ); + } + else + { + /* + * Note: entries with duplicate csCoord are allowed. + * Use edge[i], the highest entry where csCoord >= entry[i].csCoord + */ + return ADD_INT32( FT_MulFix( SUB_INT32( csCoord, + hintmap->edge[i].csCoord ), + hintmap->edge[i].scale ), + hintmap->edge[i].dsCoord ); + } + } + } + + + /* + * This hinting policy moves a hint pair in device space so that one of + * its two edges is on a device pixel boundary (its fractional part is + * zero). `cf2_hintmap_insertHint' guarantees no overlap in CS + * space. Ensure here that there is no overlap in DS. + * + * In the first pass, edges are adjusted relative to adjacent hints. + * Those that are below have already been adjusted. Those that are + * above have not yet been adjusted. If a hint above blocks an + * adjustment to an optimal position, we will try again in a second + * pass. The second pass is top-down. + * + */ + + static void + cf2_hintmap_adjustHints( CF2_HintMap hintmap ) + { + size_t i, j; + + + cf2_arrstack_clear( hintmap->hintMoves ); /* working storage */ + + /* + * First pass is bottom-up (font hint order) without look-ahead. + * Locked edges are already adjusted. + * Unlocked edges begin with dsCoord from `initialHintMap'. + * Save edges that are not optimally adjusted in `hintMoves' array, + * and process them in second pass. + */ + + for ( i = 0; i < hintmap->count; i++ ) + { + FT_Bool isPair = cf2_hint_isPair( &hintmap->edge[i] ); + + /* final amount to move edge or edge pair */ + CF2_Fixed move = 0; + + CF2_Fixed dsCoord_i; + CF2_Fixed dsCoord_j; + + + /* index of upper edge (same value for ghost hint) */ + j = isPair ? i + 1 : i; + + FT_ASSERT( j < hintmap->count ); + FT_ASSERT( cf2_hint_isValid( &hintmap->edge[i] ) ); + FT_ASSERT( cf2_hint_isValid( &hintmap->edge[j] ) ); + FT_ASSERT( cf2_hint_isLocked( &hintmap->edge[i] ) == + cf2_hint_isLocked( &hintmap->edge[j] ) ); + + dsCoord_i = hintmap->edge[i].dsCoord; + dsCoord_j = hintmap->edge[j].dsCoord; + + if ( !cf2_hint_isLocked( &hintmap->edge[i] ) ) + { + /* hint edge is not locked, we can adjust it */ + CF2_Fixed fracDown = cf2_fixedFraction( dsCoord_i ); + CF2_Fixed fracUp = cf2_fixedFraction( dsCoord_j ); + + /* calculate all four possibilities; moves down are negative */ + CF2_Fixed downMoveDown = 0 - fracDown; + CF2_Fixed upMoveDown = 0 - fracUp; + CF2_Fixed downMoveUp = ( fracDown == 0 ) + ? 0 + : cf2_intToFixed( 1 ) - fracDown; + CF2_Fixed upMoveUp = ( fracUp == 0 ) + ? 0 + : cf2_intToFixed( 1 ) - fracUp; + + /* smallest move up */ + CF2_Fixed moveUp = FT_MIN( downMoveUp, upMoveUp ); + /* smallest move down */ + CF2_Fixed moveDown = FT_MAX( downMoveDown, upMoveDown ); + + CF2_Fixed downMinCounter = CF2_MIN_COUNTER; + CF2_Fixed upMinCounter = CF2_MIN_COUNTER; + FT_Bool saveEdge = FALSE; + + + /* minimum counter constraint doesn't apply when adjacent edges */ + /* are synthetic */ + /* TODO: doesn't seem a big effect; for now, reduce the code */ +#if 0 + if ( i == 0 || + cf2_hint_isSynthetic( &hintmap->edge[i - 1] ) ) + downMinCounter = 0; + + if ( j >= hintmap->count - 1 || + cf2_hint_isSynthetic( &hintmap->edge[j + 1] ) ) + upMinCounter = 0; +#endif + + /* is there room to move up? */ + /* there is if we are at top of array or the next edge is at or */ + /* beyond proposed move up? */ + if ( j >= hintmap->count - 1 || + hintmap->edge[j + 1].dsCoord >= + ADD_INT32( dsCoord_j, moveUp + upMinCounter ) ) + { + /* there is room to move up; is there also room to move down? */ + if ( i == 0 || + hintmap->edge[i - 1].dsCoord <= + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) + { + /* move smaller absolute amount */ + move = ( -moveDown < moveUp ) ? moveDown : moveUp; /* optimum */ + } + else + move = moveUp; + } + else + { + /* is there room to move down? */ + if ( i == 0 || + hintmap->edge[i - 1].dsCoord <= + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) + { + move = moveDown; + /* true if non-optimum move */ + saveEdge = FT_BOOL( moveUp < -moveDown ); + } + else + { + /* no room to move either way without overlapping or reducing */ + /* the counter too much */ + move = 0; + saveEdge = TRUE; + } + } + + /* Identify non-moves and moves down that aren't optimal, and save */ + /* them for second pass. */ + /* Do this only if there is an unlocked edge above (which could */ + /* possibly move). */ + if ( saveEdge && + j < hintmap->count - 1 && + !cf2_hint_isLocked( &hintmap->edge[j + 1] ) ) + { + CF2_HintMoveRec savedMove; + + + savedMove.j = j; + /* desired adjustment in second pass */ + savedMove.moveUp = moveUp - move; + + cf2_arrstack_push( hintmap->hintMoves, &savedMove ); + } + + /* move the edge(s) */ + hintmap->edge[i].dsCoord = ADD_INT32( dsCoord_i, move ); + if ( isPair ) + hintmap->edge[j].dsCoord = ADD_INT32( dsCoord_j, move ); + } + + /* assert there are no overlaps in device space; */ + /* ignore tests if there was overflow (that is, if */ + /* operands have the same sign but the sum does not) */ + FT_ASSERT( i == 0 || + ( ( dsCoord_i ^ move ) >= 0 && + ( dsCoord_i ^ hintmap->edge[i].dsCoord ) < 0 ) || + hintmap->edge[i - 1].dsCoord <= hintmap->edge[i].dsCoord ); + FT_ASSERT( i < j || + ( ( dsCoord_j ^ move ) >= 0 && + ( dsCoord_j ^ hintmap->edge[j].dsCoord ) < 0 ) || + hintmap->edge[i].dsCoord <= hintmap->edge[j].dsCoord ); + + /* adjust the scales, avoiding divide by zero */ + if ( i > 0 ) + { + if ( hintmap->edge[i].csCoord != hintmap->edge[i - 1].csCoord ) + hintmap->edge[i - 1].scale = + FT_DivFix( SUB_INT32( hintmap->edge[i].dsCoord, + hintmap->edge[i - 1].dsCoord ), + SUB_INT32( hintmap->edge[i].csCoord, + hintmap->edge[i - 1].csCoord ) ); + } + + if ( isPair ) + { + if ( hintmap->edge[j].csCoord != hintmap->edge[j - 1].csCoord ) + hintmap->edge[j - 1].scale = + FT_DivFix( SUB_INT32( hintmap->edge[j].dsCoord, + hintmap->edge[j - 1].dsCoord ), + SUB_INT32( hintmap->edge[j].csCoord, + hintmap->edge[j - 1].csCoord ) ); + + i += 1; /* skip upper edge on next loop */ + } + } + + /* second pass tries to move non-optimal hints up, in case there is */ + /* room now */ + for ( i = cf2_arrstack_size( hintmap->hintMoves ); i > 0; i-- ) + { + CF2_HintMove hintMove = (CF2_HintMove) + cf2_arrstack_getPointer( hintmap->hintMoves, i - 1 ); + + + j = hintMove->j; + + /* this was tested before the push, above */ + FT_ASSERT( j < hintmap->count - 1 ); + + /* is there room to move up? */ + if ( hintmap->edge[j + 1].dsCoord >= + ADD_INT32( hintmap->edge[j].dsCoord, + hintMove->moveUp + CF2_MIN_COUNTER ) ) + { + /* there is more room now, move edge up */ + hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord, + hintMove->moveUp ); + + if ( cf2_hint_isPair( &hintmap->edge[j] ) ) + { + FT_ASSERT( j > 0 ); + hintmap->edge[j - 1].dsCoord = + ADD_INT32( hintmap->edge[j - 1].dsCoord, hintMove->moveUp ); + } + } + } + } + + + /* insert hint edges into map, sorted by csCoord */ + static void + cf2_hintmap_insertHint( CF2_HintMap hintmap, + CF2_Hint bottomHintEdge, + CF2_Hint topHintEdge ) + { + CF2_UInt indexInsert; + + /* set default values, then check for edge hints */ + FT_Bool isPair = TRUE; + CF2_Hint firstHintEdge = bottomHintEdge; + CF2_Hint secondHintEdge = topHintEdge; + + + /* one or none of the input params may be invalid when dealing with */ + /* edge hints; at least one edge must be valid */ + FT_ASSERT( cf2_hint_isValid( bottomHintEdge ) || + cf2_hint_isValid( topHintEdge ) ); + + /* determine how many and which edges to insert */ + if ( !cf2_hint_isValid( bottomHintEdge ) ) + { + /* insert only the top edge */ + firstHintEdge = topHintEdge; + isPair = FALSE; + } + else if ( !cf2_hint_isValid( topHintEdge ) ) + { + /* insert only the bottom edge */ + isPair = FALSE; + } + + /* paired edges must be in proper order */ + if ( isPair && + topHintEdge->csCoord < bottomHintEdge->csCoord ) + return; + + /* linear search to find index value of insertion point */ + indexInsert = 0; + for ( ; indexInsert < hintmap->count; indexInsert++ ) + { + if ( hintmap->edge[indexInsert].csCoord >= firstHintEdge->csCoord ) + break; + } + + FT_TRACE7(( " Got hint at %.2f (%.2f)\n", + firstHintEdge->csCoord / 65536.0, + firstHintEdge->dsCoord / 65536.0 )); + if ( isPair ) + FT_TRACE7(( " Got hint at %.2f (%.2f)\n", + secondHintEdge->csCoord / 65536.0, + secondHintEdge->dsCoord / 65536.0 )); + + /* + * Discard any hints that overlap in character space. Most often, this + * is while building the initial map, where captured hints from all + * zones are combined. Define overlap to include hints that `touch' + * (overlap zero). Hiragino Sans/Gothic fonts have numerous hints that + * touch. Some fonts have non-ideographic glyphs that overlap our + * synthetic hints. + * + * Overlap also occurs when darkening stem hints that are close. + * + */ + if ( indexInsert < hintmap->count ) + { + /* we are inserting before an existing edge: */ + /* verify that an existing edge is not the same */ + if ( hintmap->edge[indexInsert].csCoord == firstHintEdge->csCoord ) + return; /* ignore overlapping stem hint */ + + /* verify that a new pair does not straddle the next edge */ + if ( isPair && + hintmap->edge[indexInsert].csCoord <= secondHintEdge->csCoord ) + return; /* ignore overlapping stem hint */ + + /* verify that we are not inserting between paired edges */ + if ( cf2_hint_isPairTop( &hintmap->edge[indexInsert] ) ) + return; /* ignore overlapping stem hint */ + } + + /* recompute device space locations using initial hint map */ + if ( cf2_hintmap_isValid( hintmap->initialHintMap ) && + !cf2_hint_isLocked( firstHintEdge ) ) + { + if ( isPair ) + { + /* Use hint map to position the center of stem, and nominal scale */ + /* to position the two edges. This preserves the stem width. */ + CF2_Fixed midpoint = + cf2_hintmap_map( + hintmap->initialHintMap, + ADD_INT32( + firstHintEdge->csCoord, + SUB_INT32 ( secondHintEdge->csCoord, + firstHintEdge->csCoord ) / 2 ) ); + CF2_Fixed halfWidth = + FT_MulFix( SUB_INT32( secondHintEdge->csCoord, + firstHintEdge->csCoord ) / 2, + hintmap->scale ); + + + firstHintEdge->dsCoord = SUB_INT32( midpoint, halfWidth ); + secondHintEdge->dsCoord = ADD_INT32( midpoint, halfWidth ); + } + else + firstHintEdge->dsCoord = cf2_hintmap_map( hintmap->initialHintMap, + firstHintEdge->csCoord ); + } + + /* + * Discard any hints that overlap in device space; this can occur + * because locked hints have been moved to align with blue zones. + * + * TODO: Although we might correct this later during adjustment, we + * don't currently have a way to delete a conflicting hint once it has + * been inserted. See v2.030 MinionPro-Regular, 12 ppem darkened, + * initial hint map for second path, glyph 945 (the perispomeni (tilde) + * in U+1F6E, Greek omega with psili and perispomeni). Darkening is + * 25. Pair 667,747 initially conflicts in design space with top edge + * 660. This is because 667 maps to 7.87, and the top edge was + * captured by a zone at 8.0. The pair is later successfully inserted + * in a zone without the top edge. In this zone it is adjusted to 8.0, + * and no longer conflicts with the top edge in design space. This + * means it can be included in yet a later zone which does have the top + * edge hint. This produces a small mismatch between the first and + * last points of this path, even though the hint masks are the same. + * The density map difference is tiny (1/256). + * + */ + + if ( indexInsert > 0 ) + { + /* we are inserting after an existing edge */ + if ( firstHintEdge->dsCoord < hintmap->edge[indexInsert - 1].dsCoord ) + return; + } + + if ( indexInsert < hintmap->count ) + { + /* we are inserting before an existing edge */ + if ( isPair ) + { + if ( secondHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord ) + return; + } + else + { + if ( firstHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord ) + return; + } + } + + /* make room to insert */ + { + CF2_UInt iSrc = hintmap->count - 1; + CF2_UInt iDst = isPair ? hintmap->count + 1 : hintmap->count; + + CF2_UInt count = hintmap->count - indexInsert; + + + if ( iDst >= CF2_MAX_HINT_EDGES ) + { + FT_TRACE4(( "cf2_hintmap_insertHint: too many hintmaps\n" )); + return; + } + + while ( count-- ) + hintmap->edge[iDst--] = hintmap->edge[iSrc--]; + + /* insert first edge */ + hintmap->edge[indexInsert] = *firstHintEdge; /* copy struct */ + hintmap->count += 1; + + FT_TRACE7(( " Inserting hint %.2f (%.2f)\n", + firstHintEdge->csCoord / 65536.0, + firstHintEdge->dsCoord / 65536.0 )); + + if ( isPair ) + { + /* insert second edge */ + hintmap->edge[indexInsert + 1] = *secondHintEdge; /* copy struct */ + hintmap->count += 1; + + FT_TRACE7(( " Inserting hint %.2f (%.2f)\n", + secondHintEdge->csCoord / 65536.0, + secondHintEdge->dsCoord / 65536.0 )); + + } + } + + return; + } + + + /* + * Build a map from hints and mask. + * + * This function may recur one level if `hintmap->initialHintMap' is not yet + * valid. + * If `initialMap' is true, simply build initial map. + * + * Synthetic hints are used in two ways. A hint at zero is inserted, if + * needed, in the initial hint map, to prevent translations from + * propagating across the origin. If synthetic em box hints are enabled + * for ideographic dictionaries, then they are inserted in all hint + * maps, including the initial one. + * + */ + FT_LOCAL_DEF( void ) + cf2_hintmap_build( CF2_HintMap hintmap, + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOrigin, + FT_Bool initialMap ) + { + FT_Byte* maskPtr; + + CF2_Font font = hintmap->font; + CF2_HintMaskRec tempHintMask; + + size_t bitCount, i; + FT_Byte maskByte; + + + /* check whether initial map is constructed */ + if ( !initialMap && !cf2_hintmap_isValid( hintmap->initialHintMap ) ) + { + /* make recursive call with initialHintMap and temporary mask; */ + /* temporary mask will get all bits set, below */ + cf2_hintmask_init( &tempHintMask, hintMask->error ); + cf2_hintmap_build( hintmap->initialHintMap, + hStemHintArray, + vStemHintArray, + &tempHintMask, + hintOrigin, + TRUE ); + } + + if ( !cf2_hintmask_isValid( hintMask ) ) + { + /* without a hint mask, assume all hints are active */ + cf2_hintmask_setAll( hintMask, + cf2_arrstack_size( hStemHintArray ) + + cf2_arrstack_size( vStemHintArray ) ); + if ( !cf2_hintmask_isValid( hintMask ) ) + { + if ( font->isT1 ) + { + /* no error, just continue unhinted */ + *hintMask->error = FT_Err_Ok; + hintmap->hinted = FALSE; + } + return; /* too many stem hints */ + } + } + + /* begin by clearing the map */ + hintmap->count = 0; + hintmap->lastIndex = 0; + + /* make a copy of the hint mask so we can modify it */ + tempHintMask = *hintMask; + maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); + + /* use the hStem hints only, which are first in the mask */ + bitCount = cf2_arrstack_size( hStemHintArray ); + + /* Defense-in-depth. Should never return here. */ + if ( bitCount > hintMask->bitCount ) + return; + + /* synthetic embox hints get highest priority */ + if ( font->blues.doEmBoxHints ) + { + CF2_HintRec dummy; + + + cf2_hint_initZero( &dummy ); /* invalid hint map element */ + + /* ghost bottom */ + cf2_hintmap_insertHint( hintmap, + &font->blues.emBoxBottomEdge, + &dummy ); + /* ghost top */ + cf2_hintmap_insertHint( hintmap, + &dummy, + &font->blues.emBoxTopEdge ); + } + + /* insert hints captured by a blue zone or already locked (higher */ + /* priority) */ + for ( i = 0, maskByte = 0x80; i < bitCount; i++ ) + { + if ( maskByte & *maskPtr ) + { + /* expand StemHint into two `CF2_Hint' elements */ + CF2_HintRec bottomHintEdge, topHintEdge; + + + cf2_hint_init( &bottomHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + TRUE /* bottom */ ); + cf2_hint_init( &topHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + FALSE /* top */ ); + + if ( cf2_hint_isLocked( &bottomHintEdge ) || + cf2_hint_isLocked( &topHintEdge ) || + cf2_blues_capture( &font->blues, + &bottomHintEdge, + &topHintEdge ) ) + { + /* insert captured hint into map */ + cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); + + *maskPtr &= ~maskByte; /* turn off the bit for this hint */ + } + } + + if ( ( i & 7 ) == 7 ) + { + /* move to next mask byte */ + maskPtr++; + maskByte = 0x80; + } + else + maskByte >>= 1; + } + + /* initial hint map includes only captured hints plus maybe one at 0 */ + + /* + * TODO: There is a problem here because we are trying to build a + * single hint map containing all captured hints. It is + * possible for there to be conflicts between captured hints, + * either because of darkening or because the hints are in + * separate hint zones (we are ignoring hint zones for the + * initial map). An example of the latter is MinionPro-Regular + * v2.030 glyph 883 (Greek Capital Alpha with Psili) at 15ppem. + * A stem hint for the psili conflicts with the top edge hint + * for the base character. The stem hint gets priority because + * of its sort order. In glyph 884 (Greek Capital Alpha with + * Psili and Oxia), the top of the base character gets a stem + * hint, and the psili does not. This creates different initial + * maps for the two glyphs resulting in different renderings of + * the base character. Will probably defer this either as not + * worth the cost or as a font bug. I don't think there is any + * good reason for an accent to be captured by an alignment + * zone. -darnold 2/12/10 + */ + + if ( initialMap ) + { + /* Apply a heuristic that inserts a point for (0,0), unless it's */ + /* already covered by a mapping. This locks the baseline for glyphs */ + /* that have no baseline hints. */ + + if ( hintmap->count == 0 || + hintmap->edge[0].csCoord > 0 || + hintmap->edge[hintmap->count - 1].csCoord < 0 ) + { + /* all edges are above 0 or all edges are below 0; */ + /* construct a locked edge hint at 0 */ + + CF2_HintRec edge, invalid; + + + cf2_hint_initZero( &edge ); + + edge.flags = CF2_GhostBottom | + CF2_Locked | + CF2_Synthetic; + edge.scale = hintmap->scale; + + cf2_hint_initZero( &invalid ); + cf2_hintmap_insertHint( hintmap, &edge, &invalid ); + } + } + else + { + /* insert remaining hints */ + + maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); + + for ( i = 0, maskByte = 0x80; i < bitCount; i++ ) + { + if ( maskByte & *maskPtr ) + { + CF2_HintRec bottomHintEdge, topHintEdge; + + + cf2_hint_init( &bottomHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + TRUE /* bottom */ ); + cf2_hint_init( &topHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + FALSE /* top */ ); + + cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); + } + + if ( ( i & 7 ) == 7 ) + { + /* move to next mask byte */ + maskPtr++; + maskByte = 0x80; + } + else + maskByte >>= 1; + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( initialMap ) + { + FT_TRACE6(( "flags: [p]air [g]host [t]op" + " [b]ottom [L]ocked [S]ynthetic\n" )); + FT_TRACE6(( "Initial hintmap:\n" )); + } + else + FT_TRACE6(( "Hints:\n" )); +#endif + + cf2_hintmap_dump( hintmap ); + + /* + * Note: The following line is a convenient place to break when + * debugging hinting. Examine `hintmap->edge' for the list of + * enabled hints, then step over the call to see the effect of + * adjustment. We stop here first on the recursive call that + * creates the initial map, and then on each counter group and + * hint zone. + */ + + /* adjust positions of hint edges that are not locked to blue zones */ + cf2_hintmap_adjustHints( hintmap ); + + FT_TRACE6(( "Hints adjusted:\n" )); + cf2_hintmap_dump( hintmap ); + + /* save the position of all hints that were used in this hint map; */ + /* if we use them again, we'll locate them in the same position */ + if ( !initialMap ) + { + for ( i = 0; i < hintmap->count; i++ ) + { + if ( !cf2_hint_isSynthetic( &hintmap->edge[i] ) ) + { + /* Note: include both valid and invalid edges */ + /* Note: top and bottom edges are copied back separately */ + CF2_StemHint stemhint = (CF2_StemHint) + cf2_arrstack_getPointer( hStemHintArray, + hintmap->edge[i].index ); + + + if ( cf2_hint_isTop( &hintmap->edge[i] ) ) + stemhint->maxDS = hintmap->edge[i].dsCoord; + else + stemhint->minDS = hintmap->edge[i].dsCoord; + + stemhint->used = TRUE; + } + } + } + + /* hint map is ready to use */ + hintmap->isValid = TRUE; + + /* remember this mask has been used */ + cf2_hintmask_setNew( hintMask, FALSE ); + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_init( CF2_GlyphPath glyphpath, + CF2_Font font, + CF2_OutlineCallbacks callbacks, + CF2_Fixed scaleY, + /* CF2_Fixed hShift, */ + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOriginY, + const CF2_Blues blues, + const FT_Vector* fractionalTranslation ) + { + FT_ZERO( glyphpath ); + + glyphpath->font = font; + glyphpath->callbacks = callbacks; + + cf2_arrstack_init( &glyphpath->hintMoves, + font->memory, + &font->error, + sizeof ( CF2_HintMoveRec ) ); + + cf2_hintmap_init( &glyphpath->initialHintMap, + font, + &glyphpath->initialHintMap, + &glyphpath->hintMoves, + scaleY ); + cf2_hintmap_init( &glyphpath->firstHintMap, + font, + &glyphpath->initialHintMap, + &glyphpath->hintMoves, + scaleY ); + cf2_hintmap_init( &glyphpath->hintMap, + font, + &glyphpath->initialHintMap, + &glyphpath->hintMoves, + scaleY ); + + glyphpath->scaleX = font->innerTransform.a; + glyphpath->scaleC = font->innerTransform.c; + glyphpath->scaleY = font->innerTransform.d; + + glyphpath->fractionalTranslation = *fractionalTranslation; + +#if 0 + glyphpath->hShift = hShift; /* for fauxing */ +#endif + + glyphpath->hStemHintArray = hStemHintArray; + glyphpath->vStemHintArray = vStemHintArray; + glyphpath->hintMask = hintMask; /* ptr to current mask */ + glyphpath->hintOriginY = hintOriginY; + glyphpath->blues = blues; + glyphpath->darken = font->darkened; /* TODO: should we make copies? */ + glyphpath->xOffset = font->darkenX; + glyphpath->yOffset = font->darkenY; + glyphpath->miterLimit = 2 * FT_MAX( + cf2_fixedAbs( glyphpath->xOffset ), + cf2_fixedAbs( glyphpath->yOffset ) ); + + /* .1 character space unit */ + glyphpath->snapThreshold = cf2_doubleToFixed( 0.1 ); + + glyphpath->moveIsPending = TRUE; + glyphpath->pathIsOpen = FALSE; + glyphpath->pathIsClosing = FALSE; + glyphpath->elemIsQueued = FALSE; + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_finalize( CF2_GlyphPath glyphpath ) + { + cf2_arrstack_finalize( &glyphpath->hintMoves ); + } + + + /* + * Hint point in y-direction and apply outerTransform. + * Input `current' hint map (which is actually delayed by one element). + * Input x,y point in Character Space. + * Output x,y point in Device Space, including translation. + */ + static void + cf2_glyphpath_hintPoint( CF2_GlyphPath glyphpath, + CF2_HintMap hintmap, + FT_Vector* ppt, + CF2_Fixed x, + CF2_Fixed y ) + { + FT_Vector pt; /* hinted point in upright DS */ + + + pt.x = ADD_INT32( FT_MulFix( glyphpath->scaleX, x ), + FT_MulFix( glyphpath->scaleC, y ) ); + pt.y = cf2_hintmap_map( hintmap, y ); + + ppt->x = ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.a, pt.x ), + ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.c, pt.y ), + glyphpath->fractionalTranslation.x ) ); + ppt->y = ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.b, pt.x ), + ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.d, pt.y ), + glyphpath->fractionalTranslation.y ) ); + } + + + /* + * From two line segments, (u1,u2) and (v1,v2), compute a point of + * intersection on the corresponding lines. + * Return false if no intersection is found, or if the intersection is + * too far away from the ends of the line segments, u2 and v1. + * + */ + static FT_Bool + cf2_glyphpath_computeIntersection( CF2_GlyphPath glyphpath, + const FT_Vector* u1, + const FT_Vector* u2, + const FT_Vector* v1, + const FT_Vector* v2, + FT_Vector* intersection ) + { + /* + * Let `u' be a zero-based vector from the first segment, `v' from the + * second segment. + * Let `w 'be the zero-based vector from `u1' to `v1'. + * `perp' is the `perpendicular dot product'; see + * https://mathworld.wolfram.com/PerpDotProduct.html. + * `s' is the parameter for the parametric line for the first segment + * (`u'). + * + * See notation in + * http://geomalgorithms.com/a05-_intersect-1.html. + * Calculations are done in 16.16, but must handle the squaring of + * line lengths in character space. We scale all vectors by 1/32 to + * avoid overflow. This allows values up to 4095 to be squared. The + * scale factor cancels in the divide. + * + * TODO: the scale factor could be computed from UnitsPerEm. + * + */ + +#define cf2_perp( a, b ) \ + ( FT_MulFix( a.x, b.y ) - FT_MulFix( a.y, b.x ) ) + + /* round and divide by 32 */ +#define CF2_CS_SCALE( x ) \ + ( ( (x) + 0x10 ) >> 5 ) + + FT_Vector u, v, w; /* scaled vectors */ + CF2_Fixed denominator, s; + + + u.x = CF2_CS_SCALE( SUB_INT32( u2->x, u1->x ) ); + u.y = CF2_CS_SCALE( SUB_INT32( u2->y, u1->y ) ); + v.x = CF2_CS_SCALE( SUB_INT32( v2->x, v1->x ) ); + v.y = CF2_CS_SCALE( SUB_INT32( v2->y, v1->y ) ); + w.x = CF2_CS_SCALE( SUB_INT32( v1->x, u1->x ) ); + w.y = CF2_CS_SCALE( SUB_INT32( v1->y, u1->y ) ); + + denominator = cf2_perp( u, v ); + + if ( denominator == 0 ) + return FALSE; /* parallel or coincident lines */ + + s = FT_DivFix( cf2_perp( w, v ), denominator ); + + intersection->x = ADD_INT32( u1->x, + FT_MulFix( s, SUB_INT32( u2->x, u1->x ) ) ); + intersection->y = ADD_INT32( u1->y, + FT_MulFix( s, SUB_INT32( u2->y, u1->y ) ) ); + + + /* + * Special case snapping for horizontal and vertical lines. + * This cleans up intersections and reduces problems with winding + * order detection. + * Sample case is sbc cd KozGoPr6N-Medium.otf 20 16685. + * Note: these calculations are in character space. + * + */ + + if ( u1->x == u2->x && + cf2_fixedAbs( SUB_INT32( intersection->x, + u1->x ) ) < glyphpath->snapThreshold ) + intersection->x = u1->x; + if ( u1->y == u2->y && + cf2_fixedAbs( SUB_INT32( intersection->y, + u1->y ) ) < glyphpath->snapThreshold ) + intersection->y = u1->y; + + if ( v1->x == v2->x && + cf2_fixedAbs( SUB_INT32( intersection->x, + v1->x ) ) < glyphpath->snapThreshold ) + intersection->x = v1->x; + if ( v1->y == v2->y && + cf2_fixedAbs( SUB_INT32( intersection->y, + v1->y ) ) < glyphpath->snapThreshold ) + intersection->y = v1->y; + + /* limit the intersection distance from midpoint of u2 and v1 */ + if ( cf2_fixedAbs( intersection->x - ADD_INT32( u2->x, v1->x ) / 2 ) > + glyphpath->miterLimit || + cf2_fixedAbs( intersection->y - ADD_INT32( u2->y, v1->y ) / 2 ) > + glyphpath->miterLimit ) + return FALSE; + + return TRUE; + } + + + /* + * Push the cached element (glyphpath->prevElem*) to the outline + * consumer. When a darkening offset is used, the end point of the + * cached element may be adjusted to an intersection point or we may + * synthesize a connecting line to the current element. If we are + * closing a subpath, we may also generate a connecting line to the start + * point. + * + * This is where Character Space (CS) is converted to Device Space (DS) + * using a hint map. This calculation must use a HintMap that was valid + * at the time the element was saved. For the first point in a subpath, + * that is a saved HintMap. For most elements, it just means the caller + * has delayed building a HintMap from the current HintMask. + * + * Transform each point with outerTransform and call the outline + * callbacks. This is a general 3x3 transform: + * + * x' = a*x + c*y + tx, y' = b*x + d*y + ty + * + * but it uses 4 elements from CF2_Font and the translation part + * from CF2_GlyphPath. + * + */ + static void + cf2_glyphpath_pushPrevElem( CF2_GlyphPath glyphpath, + CF2_HintMap hintmap, + FT_Vector* nextP0, + FT_Vector nextP1, + FT_Bool close ) + { + CF2_CallbackParamsRec params; + + FT_Vector* prevP0; + FT_Vector* prevP1; + + FT_Vector intersection = { 0, 0 }; + FT_Bool useIntersection = FALSE; + + + FT_ASSERT( glyphpath->prevElemOp == CF2_PathOpLineTo || + glyphpath->prevElemOp == CF2_PathOpCubeTo ); + + if ( glyphpath->prevElemOp == CF2_PathOpLineTo ) + { + prevP0 = &glyphpath->prevElemP0; + prevP1 = &glyphpath->prevElemP1; + } + else + { + prevP0 = &glyphpath->prevElemP2; + prevP1 = &glyphpath->prevElemP3; + } + + /* optimization: if previous and next elements are offset by the same */ + /* amount, then there will be no gap, and no need to compute an */ + /* intersection. */ + if ( prevP1->x != nextP0->x || prevP1->y != nextP0->y ) + { + /* previous element does not join next element: */ + /* adjust end point of previous element to the intersection */ + useIntersection = cf2_glyphpath_computeIntersection( glyphpath, + prevP0, + prevP1, + nextP0, + &nextP1, + &intersection ); + if ( useIntersection ) + { + /* modify the last point of the cached element (either line or */ + /* curve) */ + *prevP1 = intersection; + } + } + + params.pt0 = glyphpath->currentDS; + + switch( glyphpath->prevElemOp ) + { + case CF2_PathOpLineTo: + params.op = CF2_PathOpLineTo; + + /* note: pt2 and pt3 are unused */ + + if ( close ) + { + /* use first hint map if closing */ + cf2_glyphpath_hintPoint( glyphpath, + &glyphpath->firstHintMap, + ¶ms.pt1, + glyphpath->prevElemP1.x, + glyphpath->prevElemP1.y ); + } + else + { + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt1, + glyphpath->prevElemP1.x, + glyphpath->prevElemP1.y ); + } + + /* output only non-zero length lines */ + if ( params.pt0.x != params.pt1.x || params.pt0.y != params.pt1.y ) + { + glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt1; + } + break; + + case CF2_PathOpCubeTo: + params.op = CF2_PathOpCubeTo; + + /* TODO: should we intersect the interior joins (p1-p2 and p2-p3)? */ + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt1, + glyphpath->prevElemP1.x, + glyphpath->prevElemP1.y ); + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt2, + glyphpath->prevElemP2.x, + glyphpath->prevElemP2.y ); + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt3, + glyphpath->prevElemP3.x, + glyphpath->prevElemP3.y ); + + glyphpath->callbacks->cubeTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt3; + + break; + } + + if ( !useIntersection || close ) + { + /* insert connecting line between end of previous element and start */ + /* of current one */ + /* note: at the end of a subpath, we might do both, so use `nextP0' */ + /* before we change it, below */ + + if ( close ) + { + /* if we are closing the subpath, then nextP0 is in the first */ + /* hint zone */ + cf2_glyphpath_hintPoint( glyphpath, + &glyphpath->firstHintMap, + ¶ms.pt1, + nextP0->x, + nextP0->y ); + } + else + { + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt1, + nextP0->x, + nextP0->y ); + } + + if ( params.pt1.x != glyphpath->currentDS.x || + params.pt1.y != glyphpath->currentDS.y ) + { + /* length is nonzero */ + params.op = CF2_PathOpLineTo; + params.pt0 = glyphpath->currentDS; + + /* note: pt2 and pt3 are unused */ + glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt1; + } + } + + if ( useIntersection ) + { + /* return intersection point to caller */ + *nextP0 = intersection; + } + } + + + /* push a MoveTo element based on current point and offset of current */ + /* element */ + static void + cf2_glyphpath_pushMove( CF2_GlyphPath glyphpath, + FT_Vector start ) + { + CF2_CallbackParamsRec params; + + + params.op = CF2_PathOpMoveTo; + params.pt0 = glyphpath->currentDS; + + /* Test if move has really happened yet; it would have called */ + /* `cf2_hintmap_build' to set `isValid'. */ + if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) ) + { + /* we are here iff first subpath is missing a moveto operator: */ + /* synthesize first moveTo to finish initialization of hintMap */ + cf2_glyphpath_moveTo( glyphpath, + glyphpath->start.x, + glyphpath->start.y ); + } + + cf2_glyphpath_hintPoint( glyphpath, + &glyphpath->hintMap, + ¶ms.pt1, + start.x, + start.y ); + + /* note: pt2 and pt3 are unused */ + glyphpath->callbacks->moveTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt1; + glyphpath->offsetStart0 = start; + } + + + /* + * All coordinates are in character space. + * On input, (x1, y1) and (x2, y2) give line segment. + * On output, (x, y) give offset vector. + * We use a piecewise approximation to trig functions. + * + * TODO: Offset true perpendicular and proper length + * supply the y-translation for hinting here, too, + * that adds yOffset unconditionally to *y. + */ + static void + cf2_glyphpath_computeOffset( CF2_GlyphPath glyphpath, + CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2, + CF2_Fixed* x, + CF2_Fixed* y ) + { + CF2_Fixed dx = SUB_INT32( x2, x1 ); + CF2_Fixed dy = SUB_INT32( y2, y1 ); + + + /* note: negative offsets don't work here; negate deltas to change */ + /* quadrants, below */ + if ( glyphpath->font->reverseWinding ) + { + dx = NEG_INT32( dx ); + dy = NEG_INT32( dy ); + } + + *x = *y = 0; + + if ( !glyphpath->darken ) + return; + + /* add momentum for this path element */ + glyphpath->callbacks->windingMomentum = + ADD_INT32( glyphpath->callbacks->windingMomentum, + cf2_getWindingMomentum( x1, y1, x2, y2 ) ); + + /* note: allow mixed integer and fixed multiplication here */ + if ( dx >= 0 ) + { + if ( dy >= 0 ) + { + /* first quadrant, +x +y */ + + if ( dx > MUL_INT32( 2, dy ) ) + { + /* +x */ + *x = 0; + *y = 0; + } + else if ( dy > MUL_INT32( 2, dx ) ) + { + /* +y */ + *x = glyphpath->xOffset; + *y = glyphpath->yOffset; + } + else + { + /* +x +y */ + *x = FT_MulFix( cf2_doubleToFixed( 0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ), + glyphpath->yOffset ); + } + } + else + { + /* fourth quadrant, +x -y */ + + if ( dx > MUL_INT32( -2, dy ) ) + { + /* +x */ + *x = 0; + *y = 0; + } + else if ( NEG_INT32( dy ) > MUL_INT32( 2, dx ) ) + { + /* -y */ + *x = NEG_INT32( glyphpath->xOffset ); + *y = glyphpath->yOffset; + } + else + { + /* +x -y */ + *x = FT_MulFix( cf2_doubleToFixed( -0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ), + glyphpath->yOffset ); + } + } + } + else + { + if ( dy >= 0 ) + { + /* second quadrant, -x +y */ + + if ( NEG_INT32( dx ) > MUL_INT32( 2, dy ) ) + { + /* -x */ + *x = 0; + *y = MUL_INT32( 2, glyphpath->yOffset ); + } + else if ( dy > MUL_INT32( -2, dx ) ) + { + /* +y */ + *x = glyphpath->xOffset; + *y = glyphpath->yOffset; + } + else + { + /* -x +y */ + *x = FT_MulFix( cf2_doubleToFixed( 0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ), + glyphpath->yOffset ); + } + } + else + { + /* third quadrant, -x -y */ + + if ( NEG_INT32( dx ) > MUL_INT32( -2, dy ) ) + { + /* -x */ + *x = 0; + *y = MUL_INT32( 2, glyphpath->yOffset ); + } + else if ( NEG_INT32( dy ) > MUL_INT32( -2, dx ) ) + { + /* -y */ + *x = NEG_INT32( glyphpath->xOffset ); + *y = glyphpath->yOffset; + } + else + { + /* -x -y */ + *x = FT_MulFix( cf2_doubleToFixed( -0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ), + glyphpath->yOffset ); + } + } + } + } + + + /* + * The functions cf2_glyphpath_{moveTo,lineTo,curveTo,closeOpenPath} are + * called by the interpreter with Character Space (CS) coordinates. Each + * path element is placed into a queue of length one to await the + * calculation of the following element. At that time, the darkening + * offset of the following element is known and joins can be computed, + * including possible modification of this element, before mapping to + * Device Space (DS) and passing it on to the outline consumer. + * + */ + FT_LOCAL_DEF( void ) + cf2_glyphpath_moveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ) + { + cf2_glyphpath_closeOpenPath( glyphpath ); + + /* save the parameters of the move for later, when we'll know how to */ + /* offset it; */ + /* also save last move point */ + glyphpath->currentCS.x = glyphpath->start.x = x; + glyphpath->currentCS.y = glyphpath->start.y = y; + + glyphpath->moveIsPending = TRUE; + + /* ensure we have a valid map with current mask */ + if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) || + cf2_hintmask_isNew( glyphpath->hintMask ) ) + cf2_hintmap_build( &glyphpath->hintMap, + glyphpath->hStemHintArray, + glyphpath->vStemHintArray, + glyphpath->hintMask, + glyphpath->hintOriginY, + FALSE ); + + /* save a copy of current HintMap to use when drawing initial point */ + glyphpath->firstHintMap = glyphpath->hintMap; /* structure copy */ + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_lineTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ) + { + CF2_Fixed xOffset, yOffset; + FT_Vector P0, P1; + FT_Bool newHintMap; + + /* + * New hints will be applied after cf2_glyphpath_pushPrevElem has run. + * In case this is a synthesized closing line, any new hints should be + * delayed until this path is closed (`cf2_hintmask_isNew' will be + * called again before the next line or curve). + */ + + /* true if new hint map not on close */ + newHintMap = cf2_hintmask_isNew( glyphpath->hintMask ) && + !glyphpath->pathIsClosing; + + /* + * Zero-length lines may occur in the charstring. Because we cannot + * compute darkening offsets or intersections from zero-length lines, + * it is best to remove them and avoid artifacts. However, zero-length + * lines in CS at the start of a new hint map can generate non-zero + * lines in DS due to hint substitution. We detect a change in hint + * map here and pass those zero-length lines along. + */ + + /* + * Note: Find explicitly closed paths here with a conditional + * breakpoint using + * + * !gp->pathIsClosing && gp->start.x == x && gp->start.y == y + * + */ + + if ( glyphpath->currentCS.x == x && + glyphpath->currentCS.y == y && + !newHintMap ) + /* + * Ignore zero-length lines in CS where the hint map is the same + * because the line in DS will also be zero length. + * + * Ignore zero-length lines when we synthesize a closing line because + * the close will be handled in cf2_glyphPath_pushPrevElem. + */ + return; + + cf2_glyphpath_computeOffset( glyphpath, + glyphpath->currentCS.x, + glyphpath->currentCS.y, + x, + y, + &xOffset, + &yOffset ); + + /* construct offset points */ + P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset ); + P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset ); + P1.x = ADD_INT32( x, xOffset ); + P1.y = ADD_INT32( y, yOffset ); + + if ( glyphpath->moveIsPending ) + { + /* emit offset 1st point as MoveTo */ + cf2_glyphpath_pushMove( glyphpath, P0 ); + + glyphpath->moveIsPending = FALSE; /* adjust state machine */ + glyphpath->pathIsOpen = TRUE; + + glyphpath->offsetStart1 = P1; /* record second point */ + } + + if ( glyphpath->elemIsQueued ) + { + FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) || + glyphpath->hintMap.count == 0 ); + + cf2_glyphpath_pushPrevElem( glyphpath, + &glyphpath->hintMap, + &P0, + P1, + FALSE ); + } + + /* queue the current element with offset points */ + glyphpath->elemIsQueued = TRUE; + glyphpath->prevElemOp = CF2_PathOpLineTo; + glyphpath->prevElemP0 = P0; + glyphpath->prevElemP1 = P1; + + /* update current map */ + if ( newHintMap ) + cf2_hintmap_build( &glyphpath->hintMap, + glyphpath->hStemHintArray, + glyphpath->vStemHintArray, + glyphpath->hintMask, + glyphpath->hintOriginY, + FALSE ); + + glyphpath->currentCS.x = x; /* pre-offset current point */ + glyphpath->currentCS.y = y; + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_curveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2, + CF2_Fixed x3, + CF2_Fixed y3 ) + { + CF2_Fixed xOffset1, yOffset1, xOffset3, yOffset3; + FT_Vector P0, P1, P2, P3; + + + /* TODO: ignore zero length portions of curve?? */ + cf2_glyphpath_computeOffset( glyphpath, + glyphpath->currentCS.x, + glyphpath->currentCS.y, + x1, + y1, + &xOffset1, + &yOffset1 ); + cf2_glyphpath_computeOffset( glyphpath, + x2, + y2, + x3, + y3, + &xOffset3, + &yOffset3 ); + + /* add momentum from the middle segment */ + glyphpath->callbacks->windingMomentum = + ADD_INT32( glyphpath->callbacks->windingMomentum, + cf2_getWindingMomentum( x1, y1, x2, y2 ) ); + + /* construct offset points */ + P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset1 ); + P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset1 ); + P1.x = ADD_INT32( x1, xOffset1 ); + P1.y = ADD_INT32( y1, yOffset1 ); + /* note: preserve angle of final segment by using offset3 at both ends */ + P2.x = ADD_INT32( x2, xOffset3 ); + P2.y = ADD_INT32( y2, yOffset3 ); + P3.x = ADD_INT32( x3, xOffset3 ); + P3.y = ADD_INT32( y3, yOffset3 ); + + if ( glyphpath->moveIsPending ) + { + /* emit offset 1st point as MoveTo */ + cf2_glyphpath_pushMove( glyphpath, P0 ); + + glyphpath->moveIsPending = FALSE; + glyphpath->pathIsOpen = TRUE; + + glyphpath->offsetStart1 = P1; /* record second point */ + } + + if ( glyphpath->elemIsQueued ) + { + FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) || + glyphpath->hintMap.count == 0 ); + + cf2_glyphpath_pushPrevElem( glyphpath, + &glyphpath->hintMap, + &P0, + P1, + FALSE ); + } + + /* queue the current element with offset points */ + glyphpath->elemIsQueued = TRUE; + glyphpath->prevElemOp = CF2_PathOpCubeTo; + glyphpath->prevElemP0 = P0; + glyphpath->prevElemP1 = P1; + glyphpath->prevElemP2 = P2; + glyphpath->prevElemP3 = P3; + + /* update current map */ + if ( cf2_hintmask_isNew( glyphpath->hintMask ) ) + cf2_hintmap_build( &glyphpath->hintMap, + glyphpath->hStemHintArray, + glyphpath->vStemHintArray, + glyphpath->hintMask, + glyphpath->hintOriginY, + FALSE ); + + glyphpath->currentCS.x = x3; /* pre-offset current point */ + glyphpath->currentCS.y = y3; + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_closeOpenPath( CF2_GlyphPath glyphpath ) + { + if ( glyphpath->pathIsOpen ) + { + /* + * A closing line in Character Space line is always generated below + * with `cf2_glyphPath_lineTo'. It may be ignored later if it turns + * out to be zero length in Device Space. + */ + glyphpath->pathIsClosing = TRUE; + + cf2_glyphpath_lineTo( glyphpath, + glyphpath->start.x, + glyphpath->start.y ); + + /* empty the final element from the queue and close the path */ + if ( glyphpath->elemIsQueued ) + cf2_glyphpath_pushPrevElem( glyphpath, + &glyphpath->hintMap, + &glyphpath->offsetStart0, + glyphpath->offsetStart1, + TRUE ); + + /* reset state machine */ + glyphpath->moveIsPending = TRUE; + glyphpath->pathIsOpen = FALSE; + glyphpath->pathIsClosing = FALSE; + glyphpath->elemIsQueued = FALSE; + } + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/pshints.h b/vendor/freetype/src/psaux/pshints.h new file mode 100644 index 0000000..31a8230 --- /dev/null +++ b/vendor/freetype/src/psaux/pshints.h @@ -0,0 +1,288 @@ +/**************************************************************************** + * + * pshints.h + * + * Adobe's code for handling CFF hints (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSHINT_H_ +#define PSHINT_H_ + +FT_BEGIN_HEADER + + + enum + { + CF2_MAX_HINTS = 96 /* maximum # of hints */ + }; + + + /* + * A HintMask object stores a bit mask that specifies which hints in the + * charstring are active at a given time. Hints in CFF must be declared + * at the start, before any drawing operators, with horizontal hints + * preceding vertical hints. The HintMask is ordered the same way, with + * horizontal hints immediately followed by vertical hints. Clients are + * responsible for knowing how many of each type are present. + * + * The maximum total number of hints is 96, as specified by the CFF + * specification. + * + * A HintMask is built 0 or more times while interpreting a charstring, by + * the HintMask operator. There is only one HintMask, but it is built or + * rebuilt each time there is a hint substitution (HintMask operator) in + * the charstring. A default HintMask with all bits set is built if there + * has been no HintMask operator prior to the first drawing operator. + * + */ + + typedef struct CF2_HintMaskRec_ + { + FT_Error* error; + + FT_Bool isValid; + FT_Bool isNew; + + size_t bitCount; + size_t byteCount; + + FT_Byte mask[( CF2_MAX_HINTS + 7 ) / 8]; + + } CF2_HintMaskRec, *CF2_HintMask; + + + typedef struct CF2_StemHintRec_ + { + FT_Bool used; /* DS positions are valid */ + + CF2_Fixed min; /* original character space value */ + CF2_Fixed max; + + CF2_Fixed minDS; /* DS position after first use */ + CF2_Fixed maxDS; + + } CF2_StemHintRec, *CF2_StemHint; + + + /* + * A HintMap object stores a piecewise linear function for mapping + * y-coordinates from character space to device space, providing + * appropriate pixel alignment to stem edges. + * + * The map is implemented as an array of `CF2_Hint' elements, each + * representing an edge. When edges are paired, as from stem hints, the + * bottom edge must immediately precede the top edge in the array. + * Element character space AND device space positions must both increase + * monotonically in the array. `CF2_Hint' elements are also used as + * parameters to `cf2_blues_capture'. + * + * The `cf2_hintmap_build' method must be called before any drawing + * operation (beginning with a Move operator) and at each hint + * substitution (HintMask operator). + * + * The `cf2_hintmap_map' method is called to transform y-coordinates at + * each drawing operation (move, line, curve). + * + */ + + /* TODO: make this a CF2_ArrStack and add a deep copy method */ + enum + { + CF2_MAX_HINT_EDGES = CF2_MAX_HINTS * 2 + }; + + + typedef struct CF2_HintMapRec_ + { + CF2_Font font; + + /* initial map based on blue zones */ + struct CF2_HintMapRec_* initialHintMap; + + /* working storage for 2nd pass adjustHints */ + CF2_ArrStack hintMoves; + + FT_Bool isValid; + FT_Bool hinted; + + CF2_Fixed scale; + CF2_UInt count; + + /* start search from this index */ + CF2_UInt lastIndex; + + CF2_HintRec edge[CF2_MAX_HINT_EDGES]; /* 192 */ + + } CF2_HintMapRec, *CF2_HintMap; + + + FT_LOCAL( FT_Bool ) + cf2_hint_isValid( const CF2_Hint hint ); + FT_LOCAL( FT_Bool ) + cf2_hint_isTop( const CF2_Hint hint ); + FT_LOCAL( FT_Bool ) + cf2_hint_isBottom( const CF2_Hint hint ); + FT_LOCAL( void ) + cf2_hint_lock( CF2_Hint hint ); + + + FT_LOCAL( void ) + cf2_hintmap_init( CF2_HintMap hintmap, + CF2_Font font, + CF2_HintMap initialMap, + CF2_ArrStack hintMoves, + CF2_Fixed scale ); + FT_LOCAL( void ) + cf2_hintmap_build( CF2_HintMap hintmap, + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOrigin, + FT_Bool initialMap ); + + + /* + * GlyphPath is a wrapper for drawing operations that scales the + * coordinates according to the render matrix and HintMap. It also tracks + * open paths to control ClosePath and to insert MoveTo for broken fonts. + * + */ + typedef struct CF2_GlyphPathRec_ + { + /* TODO: gather some of these into a hinting context */ + + CF2_Font font; /* font instance */ + CF2_OutlineCallbacks callbacks; /* outline consumer */ + + + CF2_HintMapRec hintMap; /* current hint map */ + CF2_HintMapRec firstHintMap; /* saved copy */ + CF2_HintMapRec initialHintMap; /* based on all captured hints */ + + CF2_ArrStackRec hintMoves; /* list of hint moves for 2nd pass */ + + CF2_Fixed scaleX; /* matrix a */ + CF2_Fixed scaleC; /* matrix c */ + CF2_Fixed scaleY; /* matrix d */ + + FT_Vector fractionalTranslation; /* including deviceXScale */ +#if 0 + CF2_Fixed hShift; /* character space horizontal shift */ + /* (for fauxing) */ +#endif + + FT_Bool pathIsOpen; /* true after MoveTo */ + FT_Bool pathIsClosing; /* true when synthesizing closepath line */ + FT_Bool darken; /* true if stem darkening */ + FT_Bool moveIsPending; /* true between MoveTo and offset MoveTo */ + + /* references used to call `cf2_hintmap_build', if necessary */ + CF2_ArrStack hStemHintArray; + CF2_ArrStack vStemHintArray; + CF2_HintMask hintMask; /* ptr to the current mask */ + CF2_Fixed hintOriginY; /* copy of current origin */ + const CF2_BluesRec* blues; + + CF2_Fixed xOffset; /* character space offsets */ + CF2_Fixed yOffset; + + /* character space miter limit threshold */ + CF2_Fixed miterLimit; + /* vertical/horizontal snap distance in character space */ + CF2_Fixed snapThreshold; + + FT_Vector offsetStart0; /* first and second points of first */ + FT_Vector offsetStart1; /* element with offset applied */ + + /* current point, character space, before offset */ + FT_Vector currentCS; + /* current point, device space */ + FT_Vector currentDS; + /* start point of subpath, character space */ + FT_Vector start; + + /* the following members constitute the `queue' of one element */ + FT_Bool elemIsQueued; + CF2_Int prevElemOp; + + FT_Vector prevElemP0; + FT_Vector prevElemP1; + FT_Vector prevElemP2; + FT_Vector prevElemP3; + + } CF2_GlyphPathRec, *CF2_GlyphPath; + + + FT_LOCAL( void ) + cf2_glyphpath_init( CF2_GlyphPath glyphpath, + CF2_Font font, + CF2_OutlineCallbacks callbacks, + CF2_Fixed scaleY, + /* CF2_Fixed hShift, */ + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOrigin, + const CF2_Blues blues, + const FT_Vector* fractionalTranslation ); + FT_LOCAL( void ) + cf2_glyphpath_finalize( CF2_GlyphPath glyphpath ); + + FT_LOCAL( void ) + cf2_glyphpath_moveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ); + FT_LOCAL( void ) + cf2_glyphpath_lineTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ); + FT_LOCAL( void ) + cf2_glyphpath_curveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2, + CF2_Fixed x3, + CF2_Fixed y3 ); + FT_LOCAL( void ) + cf2_glyphpath_closeOpenPath( CF2_GlyphPath glyphpath ); + + +FT_END_HEADER + + +#endif /* PSHINT_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psintrp.c b/vendor/freetype/src/psaux/psintrp.c new file mode 100644 index 0000000..6c640ee --- /dev/null +++ b/vendor/freetype/src/psaux/psintrp.c @@ -0,0 +1,3059 @@ +/**************************************************************************** + * + * psintrp.c + * + * Adobe's CFF Interpreter (body). + * + * Copyright 2007-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include +#include + +#include "psglue.h" +#include "psfont.h" +#include "psstack.h" +#include "pshints.h" +#include "psintrp.h" + +#include "pserror.h" + +#include "psobjs.h" /* for cff_random */ +#include "t1decode.h" /* for t1 seac */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cf2interp + + + FT_LOCAL_DEF( void ) + cf2_hintmask_init( CF2_HintMask hintmask, + FT_Error* error ) + { + FT_ZERO( hintmask ); + + hintmask->error = error; + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hintmask_isValid( const CF2_HintMask hintmask ) + { + return hintmask->isValid; + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hintmask_isNew( const CF2_HintMask hintmask ) + { + return hintmask->isNew; + } + + + FT_LOCAL_DEF( void ) + cf2_hintmask_setNew( CF2_HintMask hintmask, + FT_Bool val ) + { + hintmask->isNew = val; + } + + + /* clients call `getMaskPtr' in order to iterate */ + /* through hint mask */ + + FT_LOCAL_DEF( FT_Byte* ) + cf2_hintmask_getMaskPtr( CF2_HintMask hintmask ) + { + return hintmask->mask; + } + + + static size_t + cf2_hintmask_setCounts( CF2_HintMask hintmask, + size_t bitCount ) + { + if ( bitCount > CF2_MAX_HINTS ) + { + /* total of h and v stems must be <= 96 */ + CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format ); + return 0; + } + + hintmask->bitCount = bitCount; + hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8; + + hintmask->isValid = TRUE; + hintmask->isNew = TRUE; + + return bitCount; + } + + + /* consume the hintmask bytes from the charstring, advancing the src */ + /* pointer */ + static void + cf2_hintmask_read( CF2_HintMask hintmask, + CF2_Buffer charstring, + size_t bitCount ) + { + size_t i; + +#ifndef CF2_NDEBUG + /* these are the bits in the final mask byte that should be zero */ + /* Note: this variable is only used in an assert expression below */ + /* and then only if CF2_NDEBUG is not defined */ + CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1; +#endif + + + /* initialize counts and isValid */ + if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 ) + return; + + FT_ASSERT( hintmask->byteCount > 0 ); + + FT_TRACE4(( " (maskbytes:" )); + + /* set mask and advance interpreter's charstring pointer */ + for ( i = 0; i < hintmask->byteCount; i++ ) + { + hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring ); + FT_TRACE4(( " 0x%02X", hintmask->mask[i] )); + } + + FT_TRACE4(( ")\n" )); + + /* assert any unused bits in last byte are zero unless there's a prior */ + /* error */ + /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */ +#ifndef CF2_NDEBUG + FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 || + *hintmask->error ); +#endif + } + + + FT_LOCAL_DEF( void ) + cf2_hintmask_setAll( CF2_HintMask hintmask, + size_t bitCount ) + { + size_t i; + CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1; + + + /* initialize counts and isValid */ + if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 ) + return; + + FT_ASSERT( hintmask->byteCount > 0 ); + FT_ASSERT( hintmask->byteCount <= + sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) ); + + /* set mask to all ones */ + for ( i = 0; i < hintmask->byteCount; i++ ) + hintmask->mask[i] = 0xFF; + + /* clear unused bits */ + /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */ + hintmask->mask[hintmask->byteCount - 1] &= ~mask; + } + + + /* Type2 charstring opcodes */ + enum + { + cf2_cmdRESERVED_0, /* 0 */ + cf2_cmdHSTEM, /* 1 */ + cf2_cmdRESERVED_2, /* 2 */ + cf2_cmdVSTEM, /* 3 */ + cf2_cmdVMOVETO, /* 4 */ + cf2_cmdRLINETO, /* 5 */ + cf2_cmdHLINETO, /* 6 */ + cf2_cmdVLINETO, /* 7 */ + cf2_cmdRRCURVETO, /* 8 */ + cf2_cmdCLOSEPATH, /* 9 T1 only */ + cf2_cmdCALLSUBR, /* 10 */ + cf2_cmdRETURN, /* 11 */ + cf2_cmdESC, /* 12 */ + cf2_cmdHSBW, /* 13 T1 only */ + cf2_cmdENDCHAR, /* 14 */ + cf2_cmdVSINDEX, /* 15 */ + cf2_cmdBLEND, /* 16 */ + cf2_cmdRESERVED_17, /* 17 */ + cf2_cmdHSTEMHM, /* 18 */ + cf2_cmdHINTMASK, /* 19 */ + cf2_cmdCNTRMASK, /* 20 */ + cf2_cmdRMOVETO, /* 21 */ + cf2_cmdHMOVETO, /* 22 */ + cf2_cmdVSTEMHM, /* 23 */ + cf2_cmdRCURVELINE, /* 24 */ + cf2_cmdRLINECURVE, /* 25 */ + cf2_cmdVVCURVETO, /* 26 */ + cf2_cmdHHCURVETO, /* 27 */ + cf2_cmdEXTENDEDNMBR, /* 28 */ + cf2_cmdCALLGSUBR, /* 29 */ + cf2_cmdVHCURVETO, /* 30 */ + cf2_cmdHVCURVETO /* 31 */ + }; + + enum + { + cf2_escDOTSECTION, /* 0 */ + cf2_escVSTEM3, /* 1 T1 only */ + cf2_escHSTEM3, /* 2 T1 only */ + cf2_escAND, /* 3 */ + cf2_escOR, /* 4 */ + cf2_escNOT, /* 5 */ + cf2_escSEAC, /* 6 T1 only */ + cf2_escSBW, /* 7 T1 only */ + cf2_escRESERVED_8, /* 8 */ + cf2_escABS, /* 9 */ + cf2_escADD, /* 10 like otherADD */ + cf2_escSUB, /* 11 like otherSUB */ + cf2_escDIV, /* 12 */ + cf2_escRESERVED_13, /* 13 */ + cf2_escNEG, /* 14 */ + cf2_escEQ, /* 15 */ + cf2_escCALLOTHERSUBR,/* 16 T1 only */ + cf2_escPOP, /* 17 T1 only */ + cf2_escDROP, /* 18 */ + cf2_escRESERVED_19, /* 19 */ + cf2_escPUT, /* 20 like otherPUT */ + cf2_escGET, /* 21 like otherGET */ + cf2_escIFELSE, /* 22 like otherIFELSE */ + cf2_escRANDOM, /* 23 like otherRANDOM */ + cf2_escMUL, /* 24 like otherMUL */ + cf2_escRESERVED_25, /* 25 */ + cf2_escSQRT, /* 26 */ + cf2_escDUP, /* 27 like otherDUP */ + cf2_escEXCH, /* 28 like otherEXCH */ + cf2_escINDEX, /* 29 */ + cf2_escROLL, /* 30 */ + cf2_escRESERVED_31, /* 31 */ + cf2_escRESERVED_32, /* 32 */ + cf2_escSETCURRENTPT, /* 33 T1 only */ + cf2_escHFLEX, /* 34 */ + cf2_escFLEX, /* 35 */ + cf2_escHFLEX1, /* 36 */ + cf2_escFLEX1, /* 37 */ + cf2_escRESERVED_38 /* 38 & all higher */ + }; + + + /* `stemHintArray' does not change once we start drawing the outline. */ + static void + cf2_doStems( const CF2_Font font, + CF2_Stack opStack, + CF2_ArrStack stemHintArray, + CF2_Fixed* width, + FT_Bool* haveWidth, + CF2_Fixed hintOffset ) + { + CF2_UInt i; + CF2_UInt count = cf2_stack_count( opStack ); + FT_Bool hasWidthArg = FT_BOOL( count & 1 ); + + /* variable accumulates delta values from operand stack */ + CF2_Fixed position = hintOffset; + + if ( font->isT1 && !font->decoder->flex_state && !*haveWidth ) + FT_ERROR(( "cf2_doStems (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( !font->isT1 && hasWidthArg && !*haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + cf2_getNominalWidthX( font->decoder ) ); + + if ( font->decoder->width_only ) + goto exit; + + for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 ) + { + /* construct a CF2_StemHint and push it onto the list */ + CF2_StemHintRec stemhint; + + + stemhint.min = + position = ADD_INT32( position, + cf2_stack_getReal( opStack, i ) ); + stemhint.max = + position = ADD_INT32( position, + cf2_stack_getReal( opStack, i + 1 ) ); + + stemhint.used = FALSE; + stemhint.maxDS = + stemhint.minDS = 0; + + cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */ + } + + cf2_stack_clear( opStack ); + + exit: + /* cf2_doStems must define a width (may be default) */ + *haveWidth = TRUE; + } + + + static void + cf2_doFlex( CF2_Stack opStack, + CF2_Fixed* curX, + CF2_Fixed* curY, + CF2_GlyphPath glyphPath, + const FT_Bool* readFromStack, + FT_Bool doConditionalLastRead ) + { + CF2_Fixed vals[14]; + CF2_UInt idx; + FT_Bool isHFlex; + CF2_Int top, i, j; + + + vals[0] = *curX; + vals[1] = *curY; + idx = 0; + isHFlex = FT_BOOL( readFromStack[9] == FALSE ); + top = isHFlex ? 9 : 10; + + for ( i = 0; i < top; i++ ) + { + vals[i + 2] = vals[i]; + if ( readFromStack[i] ) + vals[i + 2] = ADD_INT32( vals[i + 2], cf2_stack_getReal( opStack, + idx++ ) ); + } + + if ( isHFlex ) + vals[9 + 2] = *curY; + + if ( doConditionalLastRead ) + { + FT_Bool lastIsX = FT_BOOL( + cf2_fixedAbs( SUB_INT32( vals[10], *curX ) ) > + cf2_fixedAbs( SUB_INT32( vals[11], *curY ) ) ); + CF2_Fixed lastVal = cf2_stack_getReal( opStack, idx ); + + + if ( lastIsX ) + { + vals[12] = ADD_INT32( vals[10], lastVal ); + vals[13] = *curY; + } + else + { + vals[12] = *curX; + vals[13] = ADD_INT32( vals[11], lastVal ); + } + } + else + { + if ( readFromStack[10] ) + vals[12] = ADD_INT32( vals[10], + cf2_stack_getReal( opStack, idx++ ) ); + else + vals[12] = *curX; + + if ( readFromStack[11] ) + vals[13] = ADD_INT32( vals[11], + cf2_stack_getReal( opStack, idx ) ); + else + vals[13] = *curY; + } + + for ( j = 0; j < 2; j++ ) + cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2], + vals[j * 6 + 3], + vals[j * 6 + 4], + vals[j * 6 + 5], + vals[j * 6 + 6], + vals[j * 6 + 7] ); + + cf2_stack_clear( opStack ); + + *curX = vals[12]; + *curY = vals[13]; + } + + + /* Blend numOperands on the stack, */ + /* store results into the first numBlends values, */ + /* then pop remaining arguments. */ + static void + cf2_doBlend( const CFF_Blend blend, + CF2_Stack opStack, + CF2_UInt numBlends ) + { + CF2_UInt delta; + CF2_UInt base; + CF2_UInt i, j; + CF2_UInt numOperands = (CF2_UInt)( numBlends * blend->lenBV ); + + + base = cf2_stack_count( opStack ) - numOperands; + delta = base + numBlends; + + for ( i = 0; i < numBlends; i++ ) + { + const CF2_Fixed* weight = &blend->BV[1]; + + /* start with first term */ + CF2_Fixed sum = cf2_stack_getReal( opStack, i + base ); + + + for ( j = 1; j < blend->lenBV; j++ ) + sum = ADD_INT32( sum, + FT_MulFix( *weight++, + cf2_stack_getReal( opStack, + delta++ ) ) ); + + /* store blended result */ + cf2_stack_setReal( opStack, i + base, sum ); + } + + /* leave only `numBlends' results on stack */ + cf2_stack_pop( opStack, numOperands - numBlends ); + } + + + /* + * `error' is a shared error code used by many objects in this + * routine. Before the code continues from an error, it must check and + * record the error in `*error'. The idea is that this shared + * error code will record the first error encountered. If testing + * for an error anyway, the cost of `goto exit' is small, so we do it, + * even if continuing would be safe. In this case, `lastError' is + * set, so the testing and storing can be done in one place, at `exit'. + * + * Continuing after an error is intended for objects which do their own + * testing of `*error', e.g., array stack functions. This allows us to + * avoid an extra test after the call. + * + * Unimplemented opcodes are ignored. + * + */ + FT_LOCAL_DEF( void ) + cf2_interpT2CharString( CF2_Font font, + const CF2_Buffer buf, + CF2_OutlineCallbacks callbacks, + const FT_Vector* translation, + FT_Bool doingSeac, + CF2_Fixed curX, + CF2_Fixed curY, + CF2_Fixed* width ) + { + /* lastError is used for errors that are immediately tested */ + FT_Error lastError = FT_Err_Ok; + + /* pointer to parsed font object */ + PS_Decoder* decoder = font->decoder; + + FT_Error* error = &font->error; + FT_Memory memory = font->memory; + + CF2_Fixed scaleY = font->innerTransform.d; + CF2_Fixed nominalWidthX = cf2_getNominalWidthX( decoder ); + + /* stuff for Type 1 */ + FT_Int known_othersubr_result_cnt = 0; + FT_Bool large_int = FALSE; + FT_Bool initial_map_ready = FALSE; + +#define PS_STORAGE_SIZE 3 + CF2_F16Dot16 results[PS_STORAGE_SIZE]; /* for othersubr results */ + FT_Int result_cnt = 0; + + /* save this for hinting seac accents */ + CF2_Fixed hintOriginY = curY; + + CF2_Stack opStack = NULL; + FT_UInt stackSize; + FT_Byte op1; /* first opcode byte */ + + CF2_F16Dot16 storage[CF2_STORAGE_SIZE]; /* for `put' and `get' */ + CF2_F16Dot16 flexStore[6]; /* for Type 1 flex */ + + /* instruction limit; 20,000,000 matches Avalon */ + FT_UInt32 instructionLimit = 20000000UL; + + CF2_ArrStackRec subrStack; + + FT_Bool haveWidth; + CF2_Buffer charstring = NULL; + + CF2_Int charstringIndex = -1; /* initialize to empty */ + + /* TODO: placeholders for hint structures */ + + /* objects used for hinting */ + CF2_ArrStackRec hStemHintArray; + CF2_ArrStackRec vStemHintArray; + + CF2_HintMaskRec hintMask; + CF2_GlyphPathRec glyphPath; + + + FT_ZERO( &storage ); + FT_ZERO( &results ); + FT_ZERO( &flexStore ); + + /* initialize the remaining objects */ + cf2_arrstack_init( &subrStack, + memory, + error, + sizeof ( CF2_BufferRec ) ); + cf2_arrstack_init( &hStemHintArray, + memory, + error, + sizeof ( CF2_StemHintRec ) ); + cf2_arrstack_init( &vStemHintArray, + memory, + error, + sizeof ( CF2_StemHintRec ) ); + + /* initialize CF2_StemHint arrays */ + cf2_hintmask_init( &hintMask, error ); + + /* initialize path map to manage drawing operations */ + + /* Note: last 4 params are used to handle `MoveToPermissive', which */ + /* may need to call `hintMap.Build' */ + /* TODO: MoveToPermissive is gone; are these still needed? */ + cf2_glyphpath_init( &glyphPath, + font, + callbacks, + scaleY, + /* hShift, */ + &hStemHintArray, + &vStemHintArray, + &hintMask, + hintOriginY, + &font->blues, + translation ); + + /* + * Initialize state for width parsing. From the CFF Spec: + * + * The first stack-clearing operator, which must be one of hstem, + * hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, + * rmoveto, or endchar, takes an additional argument - the width (as + * described earlier), which may be expressed as zero or one numeric + * argument. + * + * What we implement here uses the first validly specified width, but + * does not detect errors for specifying more than one width. + * + * If one of the above operators occurs without explicitly specifying + * a width, we assume the default width. + * + * CFF2 charstrings always return the default width (0). + * + */ + haveWidth = font->isCFF2 ? TRUE : FALSE; + *width = cf2_getDefaultWidthX( decoder ); + + /* + * Note: At this point, all pointers to resources must be NULL + * and all local objects must be initialized. + * There must be no branches to `exit:' above this point. + * + */ + + /* allocate an operand stack */ + stackSize = font->isCFF2 ? cf2_getMaxstack( decoder ) + : CF2_OPERAND_STACK_SIZE; + opStack = cf2_stack_init( memory, error, stackSize ); + + if ( !opStack ) + { + lastError = FT_THROW( Out_Of_Memory ); + goto exit; + } + + /* initialize subroutine stack by placing top level charstring as */ + /* first element (max depth plus one for the charstring) */ + /* Note: Caller owns and must finalize the first charstring. */ + /* Our copy of it does not change that requirement. */ + cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 ); + + charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack ); + + /* catch errors so far */ + if ( *error ) + goto exit; + + *charstring = *buf; /* structure copy */ + charstringIndex = 0; /* entry is valid now */ + + /* main interpreter loop */ + while ( 1 ) + { + if ( font->isT1 ) + FT_ASSERT( known_othersubr_result_cnt == 0 || + result_cnt == 0 ); + + if ( cf2_buf_isEnd( charstring ) ) + { + /* If we've reached the end of the charstring, simulate a */ + /* cf2_cmdRETURN or cf2_cmdENDCHAR. */ + /* We do this for both CFF and CFF2. */ + if ( charstringIndex ) + op1 = cf2_cmdRETURN; /* end of buffer for subroutine */ + else + op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */ + } + else + { + op1 = (FT_Byte)cf2_buf_readByte( charstring ); + + /* Explicit RETURN and ENDCHAR in CFF2 should be ignored. */ + /* Note: Trace message will report 0 instead of 11 or 14. */ + if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) && + font->isCFF2 ) + op1 = cf2_cmdRESERVED_0; + } + + if ( font->isT1 ) + { + if ( !initial_map_ready && + !( op1 == cf2_cmdHSTEM || + op1 == cf2_cmdVSTEM || + op1 == cf2_cmdHSBW || + op1 == cf2_cmdCALLSUBR || + op1 == cf2_cmdRETURN || + op1 == cf2_cmdESC || + op1 == cf2_cmdENDCHAR || + op1 >= 32 /* Numbers */ ) ) + { + /* Skip outline commands first time round. */ + /* `endchar' will trigger initial hintmap build */ + /* and rewind the charstring. */ + FT_TRACE4(( " \n" )); + cf2_stack_clear( opStack ); + continue; + } + + if ( result_cnt > 0 && + !( op1 == cf2_cmdCALLSUBR || + op1 == cf2_cmdRETURN || + op1 == cf2_cmdESC || + op1 >= 32 /* Numbers */ ) ) + { + /* all operands have been transferred by previous pops */ + result_cnt = 0; + } + + if ( large_int && !( op1 >= 32 || op1 == cf2_escDIV ) ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " no `div' after large integer\n" )); + + large_int = FALSE; + } + } + + /* check for errors once per loop */ + if ( *error ) + goto exit; + + instructionLimit--; + if ( instructionLimit == 0 ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + switch( op1 ) + { + case cf2_cmdRESERVED_0: + case cf2_cmdRESERVED_2: + case cf2_cmdRESERVED_17: + /* we may get here if we have a prior error */ + FT_TRACE4(( " unknown op (%d)\n", op1 )); + break; + + case cf2_cmdVSINDEX: + FT_TRACE4(( " vsindex\n" )); + + if ( !font->isCFF2 ) + break; /* clear stack & ignore */ + + if ( font->blend.usedBV ) + { + /* vsindex not allowed after blend */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + { + FT_Int temp = cf2_stack_popInt( opStack ); + + + if ( temp >= 0 ) + font->vsindex = (FT_UInt)temp; + } + break; + + case cf2_cmdBLEND: + { + FT_UInt numBlends; + + + FT_TRACE4(( " blend\n" )); + + if ( !font->isCFF2 ) + break; /* clear stack & ignore */ + + /* do we have a `blend' op in a non-variant font? */ + if ( !font->blend.font ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* check cached blend vector */ + if ( font->cffload->blend_check_vector( &font->blend, + font->vsindex, + font->lenNDV, + font->NDV ) ) + { + lastError = font->cffload->blend_build_vector( &font->blend, + font->vsindex, + font->lenNDV, + font->NDV ); + if ( lastError ) + goto exit; + } + + /* do the blend */ + numBlends = (FT_UInt)cf2_stack_popInt( opStack ); + if ( numBlends > stackSize ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + cf2_doBlend( &font->blend, opStack, numBlends ); + + font->blend.usedBV = TRUE; + } + continue; /* do not clear the stack */ + + case cf2_cmdHSTEMHM: + case cf2_cmdHSTEM: + FT_TRACE4(( "%s\n", op1 == cf2_cmdHSTEMHM ? " hstemhm" + : " hstem" )); + + if ( !font->isT1 ) + { + /* never add hints after the mask is computed */ + /* except if in Type 1 mode (no hintmask op) */ + if ( cf2_hintmask_isValid( &hintMask ) ) + { + FT_TRACE4(( "cf2_interpT2CharString:" + " invalid horizontal hint mask\n" )); + break; + } + } + + /* add left-sidebearing correction in Type 1 mode */ + cf2_doStems( font, + opStack, + &hStemHintArray, + width, + &haveWidth, + font->isT1 ? decoder->builder.left_bearing->y + : 0 ); + + if ( decoder->width_only ) + goto exit; + + break; + + case cf2_cmdVSTEMHM: + case cf2_cmdVSTEM: + FT_TRACE4(( "%s\n", op1 == cf2_cmdVSTEMHM ? " vstemhm" + : " vstem" )); + + if ( !font->isT1 ) + { + /* never add hints after the mask is computed */ + /* except if in Type 1 mode (no hintmask op) */ + if ( cf2_hintmask_isValid( &hintMask ) ) + { + FT_TRACE4(( "cf2_interpT2CharString:" + " invalid vertical hint mask\n" )); + break; + } + } + + /* add left-sidebearing correction in Type 1 mode */ + cf2_doStems( font, + opStack, + &vStemHintArray, + width, + &haveWidth, + font->isT1 ? decoder->builder.left_bearing->x + : 0 ); + + if ( decoder->width_only ) + goto exit; + + break; + + case cf2_cmdVMOVETO: + FT_TRACE4(( " vmoveto\n" )); + + if ( font->isT1 && !decoder->flex_state && !haveWidth ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( cf2_stack_count( opStack ) > 1 && !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) ); + + if ( !decoder->flex_state ) + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + break; + + case cf2_cmdRLINETO: + { + CF2_UInt idx; + CF2_UInt count = cf2_stack_count( opStack ); + + + FT_TRACE4(( " rlineto\n" )); + + for ( idx = 0; idx < count; idx += 2 ) + { + curX = ADD_INT32( curX, cf2_stack_getReal( opStack, + idx + 0 ) ); + curY = ADD_INT32( curY, cf2_stack_getReal( opStack, + idx + 1 ) ); + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdHLINETO: + case cf2_cmdVLINETO: + { + CF2_UInt idx; + CF2_UInt count = cf2_stack_count( opStack ); + + FT_Bool isX = FT_BOOL( op1 == cf2_cmdHLINETO ); + + + FT_TRACE4(( "%s\n", isX ? " hlineto" : " vlineto" )); + + for ( idx = 0; idx < count; idx++ ) + { + CF2_Fixed v = cf2_stack_getReal( opStack, idx ); + + + if ( isX ) + curX = ADD_INT32( curX, v ); + else + curY = ADD_INT32( curY, v ); + + isX = !isX; + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + } + + cf2_stack_clear( opStack ); + } + continue; + + case cf2_cmdRCURVELINE: + case cf2_cmdRRCURVETO: + { + CF2_UInt count = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + FT_TRACE4(( "%s\n", op1 == cf2_cmdRCURVELINE ? " rcurveline" + : " rrcurveto" )); + + while ( idx + 6 <= count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 ); + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 ); + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 6; + } + + if ( op1 == cf2_cmdRCURVELINE ) + { + curX = ADD_INT32( curX, cf2_stack_getReal( opStack, + idx + 0 ) ); + curY = ADD_INT32( curY, cf2_stack_getReal( opStack, + idx + 1 ) ); + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdCLOSEPATH: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (%d)\n", op1 )); + else + { + FT_TRACE4(( " closepath\n" )); + + /* if there is no path, `closepath' is a no-op */ + cf2_glyphpath_closeOpenPath( &glyphPath ); + + haveWidth = TRUE; + } + break; + + case cf2_cmdCALLGSUBR: + case cf2_cmdCALLSUBR: + { + CF2_Int subrNum; + + + FT_TRACE4(( "%s", op1 == cf2_cmdCALLGSUBR ? " callgsubr" + : " callsubr" )); + + if ( ( !font->isT1 && charstringIndex > CF2_MAX_SUBR ) || + ( font->isT1 && charstringIndex > T1_MAX_SUBRS_CALLS ) ) + { + /* max subr plus one for charstring */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* overflow of stack */ + } + + /* push our current CFF charstring region on subrStack */ + charstring = (CF2_Buffer) + cf2_arrstack_getPointer( + &subrStack, + (size_t)charstringIndex + 1 ); + + /* set up the new CFF region and pointer */ + subrNum = cf2_stack_popInt( opStack ); + + if ( font->isT1 && decoder->locals_hash ) + { + size_t* val = ft_hash_num_lookup( subrNum, + decoder->locals_hash ); + + + if ( val ) + subrNum = *val; + else + subrNum = -1; + } + + switch ( op1 ) + { + case cf2_cmdCALLGSUBR: + FT_TRACE4(( " (idx %d, entering level %d)\n", + subrNum + decoder->globals_bias, + charstringIndex + 1 )); + + if ( cf2_initGlobalRegionBuffer( decoder, + subrNum, + charstring ) ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* subroutine lookup or stream error */ + } + break; + + default: + /* cf2_cmdCALLSUBR */ + FT_TRACE4(( " (idx %d, entering level %d)\n", + subrNum + decoder->locals_bias, + charstringIndex + 1 )); + + if ( cf2_initLocalRegionBuffer( decoder, + subrNum, + charstring ) ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* subroutine lookup or stream error */ + } + } + + charstringIndex += 1; /* entry is valid now */ + } + continue; /* do not clear the stack */ + + case cf2_cmdRETURN: + FT_TRACE4(( " return (leaving level %d)\n", charstringIndex )); + + if ( charstringIndex < 1 ) + { + /* Note: cannot return from top charstring */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* underflow of stack */ + } + + /* restore position in previous charstring */ + charstring = (CF2_Buffer) + cf2_arrstack_getPointer( + &subrStack, + (CF2_UInt)--charstringIndex ); + continue; /* do not clear the stack */ + + case cf2_cmdESC: + { + FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring ); + + + /* first switch for 2-byte operators handles CFF2 */ + /* and opcodes that are reserved for both CFF and CFF2 */ + switch ( op2 ) + { + case cf2_escHFLEX: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, FALSE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, FALSE /* dy3 */, + TRUE /* dx4 */, FALSE /* dy4 */, + TRUE /* dx5 */, FALSE /* dy5 */, + TRUE /* dx6 */, FALSE /* dy6 */ + }; + + + FT_TRACE4(( " hflex\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); + } + continue; + + case cf2_escFLEX: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, TRUE /* dy3 */, + TRUE /* dx4 */, TRUE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + TRUE /* dx6 */, TRUE /* dy6 */ + }; + + + FT_TRACE4(( " flex\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); + } + break; /* TODO: why is this not a continue? */ + + case cf2_escHFLEX1: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, FALSE /* dy3 */, + TRUE /* dx4 */, FALSE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + TRUE /* dx6 */, FALSE /* dy6 */ + }; + + + FT_TRACE4(( " hflex1\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); + } + continue; + + case cf2_escFLEX1: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, TRUE /* dy3 */, + TRUE /* dx4 */, TRUE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + FALSE /* dx6 */, FALSE /* dy6 */ + }; + + + FT_TRACE4(( " flex1\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + TRUE /* doConditionalLastRead */ ); + } + continue; + + /* these opcodes are always reserved */ + case cf2_escRESERVED_8: + case cf2_escRESERVED_13: + case cf2_escRESERVED_19: + case cf2_escRESERVED_25: + case cf2_escRESERVED_31: + case cf2_escRESERVED_32: + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + break; + + default: + { + if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else if ( font->isT1 && result_cnt > 0 && op2 != cf2_escPOP ) + { + /* all operands have been transferred by previous pops */ + result_cnt = 0; + } + else + { + /* second switch for 2-byte operators handles */ + /* CFF and Type 1 */ + switch ( op2 ) + { + + case cf2_escDOTSECTION: + /* something about `flip type of locking' -- ignore it */ + FT_TRACE4(( " dotsection\n" )); + + break; + + case cf2_escVSTEM3: + case cf2_escHSTEM3: + /* + * Type 1: Type 2: + * x0 dx0 x1 dx1 x2 dx2 vstem3 x dx {dxa dxb}* vstem + * y0 dy0 y1 dy1 y2 dy2 hstem3 y dy {dya dyb}* hstem + * relative to lsb point relative to zero + * + */ + { + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + CF2_F16Dot16 v0, v1, v2; + + FT_Bool isV = FT_BOOL( op2 == cf2_escVSTEM3 ); + + + FT_TRACE4(( "%s\n", isV ? " vstem3" + : " hstem3" )); + + FT_ASSERT( cf2_stack_count( opStack ) == 6 ); + + v0 = cf2_stack_getReal( opStack, 0 ); + v1 = cf2_stack_getReal( opStack, 2 ); + v2 = cf2_stack_getReal( opStack, 4 ); + + cf2_stack_setReal( + opStack, 2, + SUB_INT32( SUB_INT32( v1, v0 ), + cf2_stack_getReal( opStack, 1 ) ) ); + cf2_stack_setReal( + opStack, 4, + SUB_INT32( SUB_INT32( v2, v1 ), + cf2_stack_getReal( opStack, 3 ) ) ); + + /* add left-sidebearing correction */ + cf2_doStems( font, + opStack, + isV ? &vStemHintArray : &hStemHintArray, + width, + &haveWidth, + isV ? decoder->builder.left_bearing->x + : decoder->builder.left_bearing->y ); + + if ( decoder->width_only ) + goto exit; + } + } + break; + + case cf2_escAND: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " and\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, arg1 && arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escOR: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " or\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, arg1 || arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escNOT: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " not\n" )); + + arg = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, !arg ); + } + continue; /* do not clear the stack */ + + case cf2_escSEAC: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + FT_Error error2; + CF2_Int bchar_index, achar_index; + FT_Vector left_bearing, advance; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + T1_Face face = (T1_Face)decoder->builder.face; +#endif + CF2_BufferRec component; + CF2_Fixed dummyWidth; + + CF2_Int achar = cf2_stack_popInt( opStack ); + CF2_Int bchar = cf2_stack_popInt( opStack ); + + FT_Pos ady = cf2_stack_popFixed ( opStack ); + FT_Pos adx = cf2_stack_popFixed ( opStack ); + FT_Pos asb = cf2_stack_popFixed ( opStack ); + + + FT_TRACE4(( " seac\n" )); + + if ( doingSeac ) + { + FT_ERROR(( " nested seac\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* nested seac */ + } + + if ( decoder->builder.metrics_only ) + { + FT_ERROR(( " unexpected seac\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* unexpected seac */ + } + + /* `glyph_names' is set to 0 for CID fonts which do */ + /* not include an encoding. How can we deal with */ + /* these? */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( decoder->glyph_names == 0 && + !face->root.internal->incremental_interface ) +#else + if ( decoder->glyph_names == 0 ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) glyph names table" + " not available in this font\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* seac weirdness */ + adx += decoder->builder.left_bearing->x; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( face->root.internal->incremental_interface ) + { + /* the caller must handle the font encoding also */ + bchar_index = bchar; + achar_index = achar; + } + else +#endif + { + bchar_index = t1_lookup_glyph_by_stdcharcode_ps( + decoder, bchar ); + achar_index = t1_lookup_glyph_by_stdcharcode_ps( + decoder, achar ); + } + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) invalid" + " seac character code arguments\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* if we are trying to load a composite glyph, */ + /* do not load the accent character and return */ + /* the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error2 = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)FIXED_TO_INT( adx - asb ); + subg->arg2 = (FT_Int)FIXED_TO_INT( ady ); + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + + goto exit; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + /* prepare loader */ + FT_GlyphLoader_Prepare( decoder->builder.loader ); + + error2 = cf2_getT1SeacComponent( decoder, + (FT_UInt)bchar_index, + &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + + /* save the left bearing and width of the SEAC */ + /* glyph as they will be erased by the next load */ + + left_bearing = *decoder->builder.left_bearing; + advance = *decoder->builder.advance; + + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + 0, + 0, + &dummyWidth ); + cf2_freeT1SeacComponent( decoder, &component ); + + /* If the SEAC glyph doesn't have a (H)SBW of its */ + /* own use the values from the base glyph. */ + + if ( !haveWidth ) + { + left_bearing = *decoder->builder.left_bearing; + advance = *decoder->builder.advance; + } + + decoder->builder.left_bearing->x = 0; + decoder->builder.left_bearing->y = 0; + + /* Now load `achar' on top of */ + /* the base outline */ + + error2 = cf2_getT1SeacComponent( decoder, + (FT_UInt)achar_index, + &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + adx - asb, + ady, + &dummyWidth ); + cf2_freeT1SeacComponent( decoder, &component ); + + /* restore the left side bearing and advance width */ + /* of the SEAC glyph or base character (saved above) */ + + *decoder->builder.left_bearing = left_bearing; + *decoder->builder.advance = advance; + + goto exit; + } + break; + + case cf2_escSBW: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + CF2_Fixed lsb_x, lsb_y; + PS_Builder* builder; + + + FT_TRACE4(( " sbw" )); + + builder = &decoder->builder; + + builder->advance->y = cf2_stack_popFixed( opStack ); + builder->advance->x = cf2_stack_popFixed( opStack ); + + lsb_y = cf2_stack_popFixed( opStack ); + lsb_x = cf2_stack_popFixed( opStack ); + + builder->left_bearing->x = + ADD_INT32( builder->left_bearing->x, lsb_x ); + builder->left_bearing->y = + ADD_INT32( builder->left_bearing->y, lsb_y ); + + haveWidth = TRUE; + + /* the `metrics_only' indicates that we only want */ + /* to compute the glyph's metrics (lsb + advance */ + /* width), not load the rest of it; so exit */ + /* immediately */ + if ( builder->metrics_only ) + goto exit; + + if ( initial_map_ready ) + { + curX = ADD_INT32( curX, lsb_x ); + curY = ADD_INT32( curY, lsb_y ); + } + } + break; + + case cf2_escABS: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " abs\n" )); + + arg = cf2_stack_popFixed( opStack ); + + if ( arg < -CF2_FIXED_MAX ) + cf2_stack_pushFixed( opStack, CF2_FIXED_MAX ); + else + cf2_stack_pushFixed( opStack, FT_ABS( arg ) ); + } + continue; /* do not clear the stack */ + + case cf2_escADD: + { + CF2_F16Dot16 summand1; + CF2_F16Dot16 summand2; + + + FT_TRACE4(( " add\n" )); + + summand2 = cf2_stack_popFixed( opStack ); + summand1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + ADD_INT32( summand1, + summand2 ) ); + } + continue; /* do not clear the stack */ + + case cf2_escSUB: + { + CF2_F16Dot16 minuend; + CF2_F16Dot16 subtrahend; + + + FT_TRACE4(( " sub\n" )); + + subtrahend = cf2_stack_popFixed( opStack ); + minuend = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + SUB_INT32( minuend, subtrahend ) ); + } + continue; /* do not clear the stack */ + + case cf2_escDIV: + { + CF2_F16Dot16 dividend; + CF2_F16Dot16 divisor; + + + FT_TRACE4(( " div\n" )); + + if ( font->isT1 && large_int ) + { + divisor = (CF2_F16Dot16)cf2_stack_popInt( opStack ); + dividend = (CF2_F16Dot16)cf2_stack_popInt( opStack ); + + large_int = FALSE; + } + else + { + divisor = cf2_stack_popFixed( opStack ); + dividend = cf2_stack_popFixed( opStack ); + } + + cf2_stack_pushFixed( opStack, + FT_DivFix( dividend, divisor ) ); + + } + continue; /* do not clear the stack */ + + case cf2_escNEG: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " neg\n" )); + + arg = cf2_stack_popFixed( opStack ); + + if ( arg < -CF2_FIXED_MAX ) + cf2_stack_pushFixed( opStack, CF2_FIXED_MAX ); + else + cf2_stack_pushFixed( opStack, -arg ); + } + continue; /* do not clear the stack */ + + case cf2_escEQ: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " eq\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, arg1 == arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escCALLOTHERSUBR: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + CF2_Int subr_no; + CF2_Int arg_cnt; + CF2_UInt count; + CF2_UInt opIdx = 0; + + + FT_TRACE4(( " callothersubr\n" )); + + subr_no = cf2_stack_popInt( opStack ); + arg_cnt = cf2_stack_popInt( opStack ); + + /******************************************************** + * + * remove all operands to callothersubr from the stack + * + * for handled othersubrs, where we know the number of + * arguments, we increase the stack by the value of + * known_othersubr_result_cnt + * + * for unhandled othersubrs the following pops adjust + * the stack pointer as necessary + */ + + count = cf2_stack_count( opStack ); + if ( (CF2_UInt)arg_cnt > count ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " stack underflow\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + opIdx += count - (CF2_UInt)arg_cnt; + + known_othersubr_result_cnt = 0; + result_cnt = 0; + + /* XXX TODO: The checks to `arg_count == ' */ + /* might not be correct; an othersubr expects a */ + /* certain number of operands on the PostScript stack */ + /* (as opposed to the T1 stack) but it doesn't have to */ + /* put them there by itself; previous othersubrs might */ + /* have left the operands there if they were not */ + /* followed by an appropriate number of pops */ + /* */ + /* On the other hand, Adobe Reader 7.0.8 for Linux */ + /* doesn't accept a font that contains charstrings */ + /* like */ + /* */ + /* 100 200 2 20 callothersubr */ + /* 300 1 20 callothersubr pop */ + /* */ + /* Perhaps this is the reason why BuildCharArray */ + /* exists. */ + + switch ( subr_no ) + { + case 0: /* end flex feature */ + if ( arg_cnt != 3 ) + goto Unexpected_OtherSubr; + + if ( initial_map_ready && + ( !decoder->flex_state || + decoder->num_flex_vectors != 7 ) ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " unexpected flex end\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* the two `results' are popped */ + /* by the following setcurrentpoint */ + cf2_stack_pushFixed( opStack, curX ); + cf2_stack_pushFixed( opStack, curY ); + known_othersubr_result_cnt = 2; + break; + + case 1: /* start flex feature */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( !initial_map_ready ) + break; + + if ( ps_builder_check_points( &decoder->builder, 6 ) ) + goto exit; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + break; + + case 2: /* add flex vectors */ + { + FT_Int idx; + FT_Int idx2; + + + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( !initial_map_ready ) + break; + + if ( !decoder->flex_state ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " missing flex start\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* note that we should not add a point for */ + /* index 0; this will move our current position */ + /* to the flex point without adding any point */ + /* to the outline */ + idx = decoder->num_flex_vectors++; + if ( idx > 0 && idx < 7 ) + { + /* in malformed fonts it is possible to have */ + /* other opcodes in the middle of a flex (which */ + /* don't increase `num_flex_vectors'); we thus */ + /* have to check whether we can add a point */ + + if ( ps_builder_check_points( &decoder->builder, + 1 ) ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* map: 1->2 2->4 3->6 4->2 5->4 6->6 */ + idx2 = ( idx > 3 ? idx - 3 : idx ) * 2; + + flexStore[idx2 - 2] = curX; + flexStore[idx2 - 1] = curY; + + if ( idx == 3 || idx == 6 ) + cf2_glyphpath_curveTo( &glyphPath, + flexStore[0], + flexStore[1], + flexStore[2], + flexStore[3], + flexStore[4], + flexStore[5] ); + } + } + break; + + case 3: /* change hints */ + if ( arg_cnt != 1 ) + goto Unexpected_OtherSubr; + + if ( initial_map_ready ) + { + /* do not clear hints if initial hintmap */ + /* is not ready - we need to collate all */ + cf2_arrstack_clear( &vStemHintArray ); + cf2_arrstack_clear( &hStemHintArray ); + + cf2_hintmask_init( &hintMask, error ); + hintMask.isValid = FALSE; + hintMask.isNew = TRUE; + } + + known_othersubr_result_cnt = 1; + break; + + case 12: + case 13: + /* counter control hints, clear stack */ + cf2_stack_clear( opStack ); + break; + + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + PS_Blend blend = decoder->blend; + FT_UInt num_points, nn, mm; + CF2_UInt delta; + CF2_UInt values; + + + if ( !blend ) + { + FT_ERROR(( + "cf2_interpT2CharString:" + " unexpected multiple masters operator\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + num_points = (FT_UInt)subr_no - 13 + + ( subr_no == 18 ); + if ( arg_cnt != (FT_Int)( num_points * + blend->num_designs ) ) + { + FT_ERROR(( + "cf2_interpT2CharString:" + " incorrect number of multiple masters arguments\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* We want to compute */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have a0, a1-a0, a2-a0, ..., ak-a0. */ + /* */ + /* However, given that w0 + w1 + ... + wk == 1, we */ + /* can rewrite it easily as */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1. */ + /* */ + /* I guess that's why it's written in this `compact' */ + /* form. */ + /* */ + delta = opIdx + num_points; + values = opIdx; + for ( nn = 0; nn < num_points; nn++ ) + { + CF2_Fixed tmp = cf2_stack_getReal( opStack, + values ); + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + tmp = ADD_INT32( tmp, + FT_MulFix( + cf2_stack_getReal( opStack, + delta++ ), + blend->weight_vector[mm] ) ); + + cf2_stack_setReal( opStack, values++, tmp ); + } + cf2_stack_pop( opStack, + (CF2_UInt)arg_cnt - num_points ); + + known_othersubr_result_cnt = (FT_Int)num_points; + break; + } + + case 19: + /* 1 19 callothersubr */ + /* ==> replace elements starting from index */ + /* cvi( ) of BuildCharArray with */ + /* WeightVector */ + { + FT_UInt idx; + PS_Blend blend = decoder->blend; + FT_UInt len_buildchar = decoder->len_buildchar; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = (FT_UInt)cf2_stack_popInt( opStack ); + + if ( len_buildchar < blend->num_designs || + len_buildchar - blend->num_designs < idx ) + goto Unexpected_OtherSubr; + + if ( decoder->buildchar && blend->weight_vector ) + ft_memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof ( blend->weight_vector[0] ) ); + } + break; + + case 20: + /* 2 20 callothersubr pop */ + /* ==> push + onto T1 stack */ + { + CF2_F16Dot16 summand1; + CF2_F16Dot16 summand2; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + summand2 = cf2_stack_popFixed( opStack ); + summand1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + ADD_INT32( summand1, + summand2 ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 21: + /* 2 21 callothersubr pop */ + /* ==> push - onto T1 stack */ + { + CF2_F16Dot16 minuend; + CF2_F16Dot16 subtrahend; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + subtrahend = cf2_stack_popFixed( opStack ); + minuend = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + SUB_INT32( minuend, + subtrahend ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 22: + /* 2 22 callothersubr pop */ + /* ==> push * onto T1 stack */ + { + CF2_F16Dot16 factor1; + CF2_F16Dot16 factor2; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + factor2 = cf2_stack_popFixed( opStack ); + factor1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + FT_MulFix( factor1, factor2 ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 23: + /* 2 23 callothersubr pop */ + /* ==> push / onto T1 stack */ + { + CF2_F16Dot16 dividend; + CF2_F16Dot16 divisor; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + divisor = cf2_stack_popFixed( opStack ); + dividend = cf2_stack_popFixed( opStack ); + + if ( divisor == 0 ) + goto Unexpected_OtherSubr; + + cf2_stack_pushFixed( opStack, + FT_DivFix( dividend, + divisor ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 24: + /* 2 24 callothersubr */ + /* ==> set BuildCharArray[cvi( )] = */ + { + CF2_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 2 || !blend ) + goto Unexpected_OtherSubr; + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + decoder->buildchar[idx] = + cf2_stack_popFixed( opStack ); + } + break; + + case 25: + /* 1 25 callothersubr pop */ + /* ==> push BuildCharArray[cvi( idx )] */ + /* onto T1 stack */ + { + CF2_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + cf2_stack_pushFixed( opStack, + decoder->buildchar[idx] ); + known_othersubr_result_cnt = 1; + } + break; + +#if 0 + case 26: + /* mark */ + /* ==> set BuildCharArray[cvi( )] = , */ + /* leave mark on T1 stack */ + /* */ + /* ==> set BuildCharArray[cvi( )] = */ + XXX which routine has left its mark on the + XXX (PostScript) stack?; + break; +#endif + + case 27: + /* 4 27 callothersubr pop */ + /* ==> push onto T1 stack if <= , */ + /* otherwise push */ + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + CF2_F16Dot16 cond1; + CF2_F16Dot16 cond2; + + + if ( arg_cnt != 4 ) + goto Unexpected_OtherSubr; + + cond2 = cf2_stack_popFixed( opStack ); + cond1 = cf2_stack_popFixed( opStack ); + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + cond1 <= cond2 ? arg1 : arg2 ); + known_othersubr_result_cnt = 1; + } + break; + + case 28: + /* 0 28 callothersubr pop */ + /* ==> push random value from interval [0, 1) */ + /* onto stack */ + { + CF2_F16Dot16 r; + + + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + /* only use the lower 16 bits of `random' */ + /* to generate a number in the range (0;1] */ + r = (CF2_F16Dot16) + ( ( decoder->current_subfont->random & 0xFFFF ) + 1 ); + + decoder->current_subfont->random = + cff_random( decoder->current_subfont->random ); + + cf2_stack_pushFixed( opStack, r ); + known_othersubr_result_cnt = 1; + } + break; + + default: + if ( arg_cnt >= 0 && subr_no >= 0 ) + { + FT_Int i; + + + FT_ERROR(( + "cf2_interpT2CharString (Type 1 mode):" + " unknown othersubr [%d %d], wish me luck\n", + arg_cnt, subr_no )); + + /* store the unused args */ + /* for this unhandled OtherSubr */ + + if ( arg_cnt > PS_STORAGE_SIZE ) + arg_cnt = PS_STORAGE_SIZE; + result_cnt = arg_cnt; + + for ( i = 1; i <= arg_cnt; i++ ) + results[result_cnt - i] = + cf2_stack_popFixed( opStack ); + + break; + } + /* fall through */ + + Unexpected_OtherSubr: + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " invalid othersubr [%d %d]\n", + arg_cnt, subr_no )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + } + continue; /* do not clear the stack */ + + case cf2_escPOP: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + FT_TRACE4(( " pop" )); + + if ( known_othersubr_result_cnt > 0 ) + { + known_othersubr_result_cnt--; + /* ignore, we pushed the operands ourselves */ + continue; + } + + if ( result_cnt == 0 ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " no more operands for othersubr\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + result_cnt--; + cf2_stack_pushFixed( opStack, results[result_cnt] ); + } + continue; /* do not clear the stack */ + + case cf2_escDROP: + FT_TRACE4(( " drop\n" )); + + (void)cf2_stack_popFixed( opStack ); + continue; /* do not clear the stack */ + + case cf2_escPUT: + { + CF2_F16Dot16 val; + CF2_UInt idx; + + + FT_TRACE4(( " put\n" )); + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + val = cf2_stack_popFixed( opStack ); + + if ( idx < CF2_STORAGE_SIZE ) + storage[idx] = val; + } + continue; /* do not clear the stack */ + + case cf2_escGET: + { + CF2_UInt idx; + + + FT_TRACE4(( " get\n" )); + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + + if ( idx < CF2_STORAGE_SIZE ) + cf2_stack_pushFixed( opStack, storage[idx] ); + } + continue; /* do not clear the stack */ + + case cf2_escIFELSE: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + CF2_F16Dot16 cond1; + CF2_F16Dot16 cond2; + + + FT_TRACE4(( " ifelse\n" )); + + cond2 = cf2_stack_popFixed( opStack ); + cond1 = cf2_stack_popFixed( opStack ); + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + cond1 <= cond2 ? arg1 : arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escRANDOM: /* in spec */ + { + CF2_F16Dot16 r; + + + FT_TRACE4(( " random\n" )); + + /* only use the lower 16 bits of `random' */ + /* to generate a number in the range (0;1] */ + r = (CF2_F16Dot16) + ( ( decoder->current_subfont->random & 0xFFFF ) + 1 ); + + decoder->current_subfont->random = + cff_random( decoder->current_subfont->random ); + + cf2_stack_pushFixed( opStack, r ); + } + continue; /* do not clear the stack */ + + case cf2_escMUL: + { + CF2_F16Dot16 factor1; + CF2_F16Dot16 factor2; + + + FT_TRACE4(( " mul\n" )); + + factor2 = cf2_stack_popFixed( opStack ); + factor1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + FT_MulFix( factor1, factor2 ) ); + } + continue; /* do not clear the stack */ + + case cf2_escSQRT: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " sqrt\n" )); + + arg = cf2_stack_popFixed( opStack ); + if ( arg > 0 ) + { + /* use a start value that doesn't make */ + /* the algorithm's addition overflow */ + FT_Fixed root = arg < 10 ? arg : arg >> 1; + FT_Fixed new_root; + + + /* Babylonian method */ + for (;;) + { + new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1; + if ( new_root == root ) + break; + root = new_root; + } + arg = new_root; + } + else + arg = 0; + + cf2_stack_pushFixed( opStack, arg ); + } + continue; /* do not clear the stack */ + + case cf2_escDUP: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " dup\n" )); + + arg = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, arg ); + cf2_stack_pushFixed( opStack, arg ); + } + continue; /* do not clear the stack */ + + case cf2_escEXCH: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " exch\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, arg2 ); + cf2_stack_pushFixed( opStack, arg1 ); + } + continue; /* do not clear the stack */ + + case cf2_escINDEX: + { + CF2_Int idx; + CF2_UInt size; + + + FT_TRACE4(( " index\n" )); + + idx = cf2_stack_popInt( opStack ); + size = cf2_stack_count( opStack ); + + if ( size > 0 ) + { + /* for `cf2_stack_getReal', */ + /* index 0 is bottom of stack */ + CF2_UInt gr_idx; + + + if ( idx < 0 ) + gr_idx = size - 1; + else if ( (CF2_UInt)idx >= size ) + gr_idx = 0; + else + gr_idx = size - 1 - (CF2_UInt)idx; + + cf2_stack_pushFixed( opStack, + cf2_stack_getReal( opStack, + gr_idx ) ); + } + } + continue; /* do not clear the stack */ + + case cf2_escROLL: + { + CF2_Int idx; + CF2_Int count; + + + FT_TRACE4(( " roll\n" )); + + idx = cf2_stack_popInt( opStack ); + count = cf2_stack_popInt( opStack ); + + cf2_stack_roll( opStack, count, idx ); + } + continue; /* do not clear the stack */ + + case cf2_escSETCURRENTPT: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + FT_TRACE4(( " setcurrentpoint" )); + + if ( !initial_map_ready ) + break; + + /* From the T1 specification, section 6.4: */ + /* */ + /* The setcurrentpoint command is used only in */ + /* conjunction with results from OtherSubrs */ + /* procedures. */ + + /* known_othersubr_result_cnt != 0 is already handled */ + /* above. */ + + /* Note, however, that both Ghostscript and Adobe */ + /* Distiller handle this situation by silently */ + /* ignoring the inappropriate `setcurrentpoint' */ + /* instruction. So we do the same. */ +#if 0 + + if ( decoder->flex_state != 1 ) + { + FT_ERROR(( "cf2_interpT2CharString:" + " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + } + else + ... +#endif + + curY = cf2_stack_popFixed( opStack ); + curX = cf2_stack_popFixed( opStack ); + + decoder->flex_state = 0; + } + break; + + } /* end of 2nd switch checking op2 */ + } + } + } /* end of 1st switch checking op2 */ + } /* case cf2_cmdESC */ + + break; + + case cf2_cmdHSBW: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (%d)\n", op1 )); + else + { + CF2_Fixed lsb_x; + PS_Builder* builder; + + + FT_TRACE4(( " hsbw\n" )); + + builder = &decoder->builder; + + builder->advance->x = cf2_stack_popFixed( opStack ); + builder->advance->y = 0; + + lsb_x = cf2_stack_popFixed( opStack ); + + builder->left_bearing->x = ADD_INT32( builder->left_bearing->x, + lsb_x ); + + haveWidth = TRUE; + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + goto exit; + + if ( initial_map_ready ) + curX = ADD_INT32( curX, lsb_x ); + } + break; + + case cf2_cmdENDCHAR: + FT_TRACE4(( " endchar\n" )); + + if ( font->isT1 && !initial_map_ready ) + { + FT_TRACE5(( "cf2_interpT2CharString (Type 1 mode): " + "Build initial hintmap, rewinding...\n" )); + + /* trigger initial hintmap build */ + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + initial_map_ready = TRUE; + + /* change hints routine - clear for rewind */ + cf2_arrstack_clear( &vStemHintArray ); + cf2_arrstack_clear( &hStemHintArray ); + + cf2_hintmask_init( &hintMask, error ); + hintMask.isValid = FALSE; + hintMask.isNew = TRUE; + + /* rewind charstring */ + /* some charstrings use endchar from a final subroutine call */ + /* without returning, detect these and exit to the top level */ + /* charstring */ + while ( charstringIndex > 0 ) + { + FT_TRACE4(( " return (leaving level %d)\n", charstringIndex )); + + /* restore position in previous charstring */ + charstring = (CF2_Buffer) + cf2_arrstack_getPointer( + &subrStack, + (CF2_UInt)--charstringIndex ); + } + charstring->ptr = charstring->start; + + break; + } + + if ( cf2_stack_count( opStack ) == 1 || + cf2_stack_count( opStack ) == 5 ) + { + if ( !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + } + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + /* close path if still open */ + cf2_glyphpath_closeOpenPath( &glyphPath ); + + /* disable seac for CFF2 and Type1 */ + /* (charstring ending with args on stack) */ + if ( !font->isCFF2 && !font->isT1 && cf2_stack_count( opStack ) > 1 ) + { + /* must be either 4 or 5 -- */ + /* this is a (deprecated) implied `seac' operator */ + + CF2_Int achar; + CF2_Int bchar; + CF2_BufferRec component; + CF2_Fixed dummyWidth; /* ignore component width */ + FT_Error error2; + + + if ( doingSeac ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* nested seac */ + } + + achar = cf2_stack_popInt( opStack ); + bchar = cf2_stack_popInt( opStack ); + + curY = cf2_stack_popFixed( opStack ); + curX = cf2_stack_popFixed( opStack ); + + error2 = cf2_getSeacComponent( decoder, achar, &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + curX, + curY, + &dummyWidth ); + cf2_freeSeacComponent( decoder, &component ); + + error2 = cf2_getSeacComponent( decoder, bchar, &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + 0, + 0, + &dummyWidth ); + cf2_freeSeacComponent( decoder, &component ); + } + goto exit; + + case cf2_cmdCNTRMASK: + case cf2_cmdHINTMASK: + /* the final \n in the tracing message gets added in */ + /* `cf2_hintmask_read' (which also traces the mask bytes) */ + FT_TRACE4(( "%s", op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" )); + + /* never add hints after the mask is computed */ + if ( cf2_stack_count( opStack ) > 1 && + cf2_hintmask_isValid( &hintMask ) ) + { + FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" )); + break; + } + + /* if there are arguments on the stack, there this is an */ + /* implied cf2_cmdVSTEMHM */ + cf2_doStems( font, + opStack, + &vStemHintArray, + width, + &haveWidth, + 0 ); + + if ( decoder->width_only ) + goto exit; + + if ( op1 == cf2_cmdHINTMASK ) + { + /* consume the hint mask bytes which follow the operator */ + cf2_hintmask_read( &hintMask, + charstring, + cf2_arrstack_size( &hStemHintArray ) + + cf2_arrstack_size( &vStemHintArray ) ); + } + else + { + /* + * Consume the counter mask bytes which follow the operator: + * Build a temporary hint map, just to place and lock those + * stems participating in the counter mask. These are most + * likely the dominant hstems, and are grouped together in a + * few counter groups, not necessarily in correspondence + * with the hint groups. This reduces the chances of + * conflicts between hstems that are initially placed in + * separate hint groups and then brought together. The + * positions are copied back to `hStemHintArray', so we can + * discard `counterMask' and `counterHintMap'. + * + */ + CF2_HintMapRec counterHintMap; + CF2_HintMaskRec counterMask; + + + cf2_hintmap_init( &counterHintMap, + font, + &glyphPath.initialHintMap, + &glyphPath.hintMoves, + scaleY ); + cf2_hintmask_init( &counterMask, error ); + + cf2_hintmask_read( &counterMask, + charstring, + cf2_arrstack_size( &hStemHintArray ) + + cf2_arrstack_size( &vStemHintArray ) ); + cf2_hintmap_build( &counterHintMap, + &hStemHintArray, + &vStemHintArray, + &counterMask, + 0, + FALSE ); + } + break; + + case cf2_cmdRMOVETO: + FT_TRACE4(( " rmoveto\n" )); + + if ( font->isT1 && !decoder->flex_state && !haveWidth ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( cf2_stack_count( opStack ) > 2 && !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) ); + curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) ); + + if ( !decoder->flex_state ) + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + break; + + case cf2_cmdHMOVETO: + FT_TRACE4(( " hmoveto\n" )); + + if ( font->isT1 && !decoder->flex_state && !haveWidth ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( cf2_stack_count( opStack ) > 1 && !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) ); + + if ( !decoder->flex_state ) + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + break; + + case cf2_cmdRLINECURVE: + { + CF2_UInt count = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + FT_TRACE4(( " rlinecurve\n" )); + + while ( idx + 6 < count ) + { + curX = ADD_INT32( curX, cf2_stack_getReal( opStack, + idx + 0 ) ); + curY = ADD_INT32( curY, cf2_stack_getReal( opStack, + idx + 1 ) ); + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + idx += 2; + } + + while ( idx < count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 ); + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 ); + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 6; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdVVCURVETO: + { + CF2_UInt count, count1 = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + /* (and sorting the stack indexing to suit) */ + count = count1 & ~2U; + idx += count1 - count; + + FT_TRACE4(( " vvcurveto\n" )); + + while ( idx < count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + if ( ( count - idx ) & 1 ) + { + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curX ); + + idx++; + } + else + x1 = curX; + + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + x3 = x2; + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 ); + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 4; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdHHCURVETO: + { + CF2_UInt count, count1 = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + /* (and sorting the stack indexing to suit) */ + count = count1 & ~2U; + idx += count1 - count; + + FT_TRACE4(( " hhcurveto\n" )); + + while ( idx < count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + if ( ( count - idx ) & 1 ) + { + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curY ); + + idx++; + } + else + y1 = curY; + + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 ); + y3 = y2; + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 4; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdVHCURVETO: + case cf2_cmdHVCURVETO: + { + CF2_UInt count, count1 = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + FT_Bool alternate = FT_BOOL( op1 == cf2_cmdHVCURVETO ); + + + /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */ + /* 8n+4, or 8n+5, we enforce it by clearing the */ + /* second bit */ + /* (and sorting the stack indexing to suit) */ + count = count1 & ~2U; + idx += count1 - count; + + FT_TRACE4(( "%s\n", alternate ? " hvcurveto" : " vhcurveto" )); + + while ( idx < count ) + { + CF2_Fixed x1, x2, x3, y1, y2, y3; + + + if ( alternate ) + { + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + y1 = curY; + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 ); + + if ( count - idx == 5 ) + { + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 ); + + idx++; + } + else + x3 = x2; + + alternate = FALSE; + } + else + { + x1 = curX; + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 ); + + if ( count - idx == 5 ) + { + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), y2 ); + + idx++; + } + else + y3 = y2; + + alternate = TRUE; + } + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 4; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdEXTENDEDNMBR: + { + CF2_Int v; + + CF2_Int byte1 = cf2_buf_readByte( charstring ); + CF2_Int byte2 = cf2_buf_readByte( charstring ); + + + v = (FT_Short)( ( byte1 << 8 ) | + byte2 ); + + FT_TRACE4(( " %d", v )); + + cf2_stack_pushInt( opStack, v ); + } + continue; + + default: + /* numbers */ + { + if ( /* op1 >= 32 && */ op1 <= 246 ) + { + CF2_Int v; + + + v = op1 - 139; + + FT_TRACE4(( " %d", v )); + + /* -107 .. 107 */ + cf2_stack_pushInt( opStack, v ); + } + + else if ( /* op1 >= 247 && */ op1 <= 250 ) + { + CF2_Int v; + + + v = op1; + v -= 247; + v *= 256; + v += cf2_buf_readByte( charstring ); + v += 108; + + FT_TRACE4(( " %d", v )); + + /* 108 .. 1131 */ + cf2_stack_pushInt( opStack, v ); + } + + else if ( /* op1 >= 251 && */ op1 <= 254 ) + { + CF2_Int v; + + + v = op1; + v -= 251; + v *= 256; + v += cf2_buf_readByte( charstring ); + v = -v - 108; + + FT_TRACE4(( " %d", v )); + + /* -1131 .. -108 */ + cf2_stack_pushInt( opStack, v ); + } + + else /* op1 == 255 */ + { + CF2_Fixed v; + + FT_UInt32 byte1 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte2 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte3 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte4 = (FT_UInt32)cf2_buf_readByte( charstring ); + + + v = (CF2_Fixed)( ( byte1 << 24 ) | + ( byte2 << 16 ) | + ( byte3 << 8 ) | + byte4 ); + + /* + * For Type 1: + * + * According to the specification, values > 32000 or < -32000 + * must be followed by a `div' operator to make the result be + * in the range [-32000;32000]. We expect that the second + * argument of `div' is not a large number. Additionally, we + * don't handle stuff like ` div + * div' or div div'. This is probably + * not allowed anyway. + * + * + div is not checked but should not be + * allowed as the large value remains untouched. + * + */ + if ( font->isT1 ) + { + if ( v > 32000 || v < -32000 ) + { + if ( large_int ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " no `div' after large integer\n" )); + else + large_int = TRUE; + } + + FT_TRACE4(( " %d", v )); + + cf2_stack_pushInt( opStack, (CF2_Int)v ); + } + else + { + FT_TRACE4(( " %.5fF", v / 65536.0 )); + + cf2_stack_pushFixed( opStack, v ); + } + } + } + continue; /* don't clear stack */ + + } /* end of switch statement checking `op1' */ + + cf2_stack_clear( opStack ); + + } /* end of main interpreter loop */ + + /* we get here if the charstring ends without cf2_cmdENDCHAR */ + FT_TRACE4(( "cf2_interpT2CharString:" + " charstring ends without ENDCHAR\n" )); + + exit: + /* check whether last error seen is also the first one */ + cf2_setError( error, lastError ); + + if ( *error ) + FT_TRACE4(( "charstring error %d\n", *error )); + + /* free resources from objects we've used */ + cf2_glyphpath_finalize( &glyphPath ); + cf2_arrstack_finalize( &vStemHintArray ); + cf2_arrstack_finalize( &hStemHintArray ); + cf2_arrstack_finalize( &subrStack ); + cf2_stack_free( opStack ); + + FT_TRACE4(( "\n" )); + + return; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psintrp.h b/vendor/freetype/src/psaux/psintrp.h new file mode 100644 index 0000000..d8b9342 --- /dev/null +++ b/vendor/freetype/src/psaux/psintrp.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * + * psintrp.h + * + * Adobe's CFF Interpreter (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSINTRP_H_ +#define PSINTRP_H_ + + +#include "psft.h" +#include "pshints.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + cf2_hintmask_init( CF2_HintMask hintmask, + FT_Error* error ); + FT_LOCAL( FT_Bool ) + cf2_hintmask_isValid( const CF2_HintMask hintmask ); + FT_LOCAL( FT_Bool ) + cf2_hintmask_isNew( const CF2_HintMask hintmask ); + FT_LOCAL( void ) + cf2_hintmask_setNew( CF2_HintMask hintmask, + FT_Bool val ); + FT_LOCAL( FT_Byte* ) + cf2_hintmask_getMaskPtr( CF2_HintMask hintmask ); + FT_LOCAL( void ) + cf2_hintmask_setAll( CF2_HintMask hintmask, + size_t bitCount ); + + FT_LOCAL( void ) + cf2_interpT2CharString( CF2_Font font, + const CF2_Buffer buf, + CF2_OutlineCallbacks callbacks, + const FT_Vector* translation, + FT_Bool doingSeac, + CF2_Fixed curX, + CF2_Fixed curY, + CF2_Fixed* width ); + + +FT_END_HEADER + + +#endif /* PSINTRP_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psobjs.c b/vendor/freetype/src/psaux/psobjs.c new file mode 100644 index 0000000..8da755d --- /dev/null +++ b/vendor/freetype/src/psaux/psobjs.c @@ -0,0 +1,2562 @@ +/**************************************************************************** + * + * psobjs.c + * + * Auxiliary functions for PostScript fonts (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "psobjs.h" +#include "psconv.h" + +#include "psauxerr.h" +#include "psauxmod.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT psobjs + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * ps_table_new + * + * @Description: + * Initializes a PS_Table. + * + * @InOut: + * table :: + * The address of the target table. + * + * @Input: + * count :: + * The table size = the maximum number of elements. + * + * memory :: + * The memory object to use for all subsequent + * reallocations. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + + + table->memory = memory; + if ( FT_NEW_ARRAY( table->elements, count ) || + FT_NEW_ARRAY( table->lengths, count ) ) + goto Exit; + + table->max_elems = count; + table->init = 0xDEADBEEFUL; + table->block = NULL; + table->capacity = 0; + table->cursor = 0; + + *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; + + Exit: + if ( error ) + FT_FREE( table->elements ); + + return error; + } + + + static FT_Error + ps_table_realloc( PS_Table table, + FT_Offset new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; + + + /* (re)allocate the base block */ + if ( FT_REALLOC( table->block, table->capacity, new_size ) ) + return error; + + /* rebase offsets if necessary */ + if ( old_base && table->block != old_base ) + { + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + for ( ; offset < limit; offset++ ) + { + if ( *offset ) + *offset = table->block + ( *offset - old_base ); + } + } + + table->capacity = new_size; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * ps_table_add + * + * @Description: + * Adds an object to a PS_Table, possibly growing its memory block. + * + * @InOut: + * table :: + * The target table. + * + * @Input: + * idx :: + * The index of the object in the table. + * + * object :: + * The address of the object to copy in memory. + * + * length :: + * The length in bytes of the source object. + * + * @Return: + * FreeType error code. 0 means success. An error is returned if a + * reallocation fails. + */ + FT_LOCAL_DEF( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + const void* object, + FT_UInt length ) + { + if ( idx < 0 || idx >= table->max_elems ) + { + FT_ERROR(( "ps_table_add: invalid index\n" )); + return FT_THROW( Invalid_Argument ); + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Offset new_size = table->capacity; + FT_PtrDist in_offset; + + + in_offset = (FT_Byte*)object - table->block; + if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity ) + in_offset = -1; + + while ( new_size < table->cursor + length ) + { + /* increase size by 25% and round up to the nearest multiple + of 1024 */ + new_size += ( new_size >> 2 ) + 1; + new_size = FT_PAD_CEIL( new_size, 1024 ); + } + + error = ps_table_realloc( table, new_size ); + if ( error ) + return error; + + if ( in_offset >= 0 ) + object = table->block + in_offset; + } + + /* add the object to the base block and adjust offset */ + table->elements[idx] = FT_OFFSET( table->block, table->cursor ); + table->lengths [idx] = length; + FT_MEM_COPY( table->block + table->cursor, object, length ); + + table->cursor += length; + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * ps_table_done + * + * @Description: + * Finalizes a PS_TableRec (i.e., reallocate it to its current + * cursor). + * + * @InOut: + * table :: + * The target table. + */ + FT_LOCAL_DEF( void ) + ps_table_done( PS_Table table ) + { + /* no problem if shrinking fails */ + ps_table_realloc( table, table->cursor ); + } + + + FT_LOCAL_DEF( void ) + ps_table_release( PS_Table table ) + { + FT_Memory memory = table->memory; + + + if ( table->init == 0xDEADBEEFUL ) + { + FT_FREE( table->block ); + FT_FREE( table->elements ); + FT_FREE( table->lengths ); + table->init = 0; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* first character must be already part of the comment */ + + static void + skip_comment( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + + + while ( cur < limit ) + { + if ( IS_PS_NEWLINE( *cur ) ) + break; + cur++; + } + + *acur = cur; + } + + + static void + skip_spaces( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + + + while ( cur < limit ) + { + if ( !IS_PS_SPACE( *cur ) ) + { + if ( *cur == '%' ) + /* According to the PLRM, a comment is equal to a space. */ + skip_comment( &cur, limit ); + else + break; + } + cur++; + } + + *acur = cur; + } + + +#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) + + + /* first character must be `('; */ + /* *acur is positioned at the character after the closing `)' */ + + static FT_Error + skip_literal_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Int embed = 0; + FT_Error error = FT_ERR( Invalid_File_Format ); + unsigned int i; + + + while ( cur < limit ) + { + FT_Byte c = *cur; + + + cur++; + + if ( c == '\\' ) + { + /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ + /* A backslash can introduce three different types */ + /* of escape sequences: */ + /* - a special escaped char like \r, \n, etc. */ + /* - a one-, two-, or three-digit octal number */ + /* - none of the above in which case the backslash is ignored */ + + if ( cur == limit ) + /* error (or to be ignored?) */ + break; + + switch ( *cur ) + { + /* skip `special' escape */ + case 'n': + case 'r': + case 't': + case 'b': + case 'f': + case '\\': + case '(': + case ')': + cur++; + break; + + default: + /* skip octal escape or ignore backslash */ + for ( i = 0; i < 3 && cur < limit; i++ ) + { + if ( !IS_OCTAL_DIGIT( *cur ) ) + break; + + cur++; + } + } + } + else if ( c == '(' ) + embed++; + else if ( c == ')' ) + { + embed--; + if ( embed == 0 ) + { + error = FT_Err_Ok; + break; + } + } + } + + *acur = cur; + + return error; + } + + + /* first character must be `<' */ + + static FT_Error + skip_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Error err = FT_Err_Ok; + + + while ( ++cur < limit ) + { + /* All whitespace characters are ignored. */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + break; + + if ( !IS_PS_XDIGIT( *cur ) ) + break; + } + + if ( cur < limit && *cur != '>' ) + { + FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); + err = FT_THROW( Invalid_File_Format ); + } + else + cur++; + + *acur = cur; + return err; + } + + + /* first character must be the opening brace that */ + /* starts the procedure */ + + /* NB: [ and ] need not match: */ + /* `/foo {[} def' is a valid PostScript fragment, */ + /* even within a Type1 font */ + + static FT_Error + skip_procedure( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur; + FT_Int embed = 0; + FT_Error error = FT_Err_Ok; + + + FT_ASSERT( **acur == '{' ); + + for ( cur = *acur; cur < limit && error == FT_Err_Ok; cur++ ) + { + switch ( *cur ) + { + case '{': + embed++; + break; + + case '}': + embed--; + if ( embed == 0 ) + { + cur++; + goto end; + } + break; + + case '(': + error = skip_literal_string( &cur, limit ); + break; + + case '<': + error = skip_string( &cur, limit ); + break; + + case '%': + skip_comment( &cur, limit ); + break; + } + } + + end: + if ( embed != 0 ) + error = FT_THROW( Invalid_File_Format ); + + *acur = cur; + + return error; + } + + + /************************************************************************ + * + * All exported parsing routines handle leading whitespace and stop at + * the first character which isn't part of the just handled token. + * + */ + + + FT_LOCAL_DEF( void ) + ps_parser_skip_PS_token( PS_Parser parser ) + { + /* Note: PostScript allows any non-delimiting, non-whitespace */ + /* character in a name (PS Ref Manual, 3rd ed, p31). */ + /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ + + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + FT_Error error = FT_Err_Ok; + + + skip_spaces( &cur, limit ); /* this also skips comments */ + if ( cur >= limit ) + goto Exit; + + /* self-delimiting, single-character tokens */ + if ( *cur == '[' || *cur == ']' ) + { + cur++; + goto Exit; + } + + /* skip balanced expressions (procedures and strings) */ + + if ( *cur == '{' ) /* {...} */ + { + error = skip_procedure( &cur, limit ); + goto Exit; + } + + if ( *cur == '(' ) /* (...) */ + { + error = skip_literal_string( &cur, limit ); + goto Exit; + } + + if ( *cur == '<' ) /* <...> */ + { + if ( cur + 1 < limit && *( cur + 1 ) == '<' ) /* << */ + { + cur++; + cur++; + } + else + error = skip_string( &cur, limit ); + + goto Exit; + } + + if ( *cur == '>' ) + { + cur++; + if ( cur >= limit || *cur != '>' ) /* >> */ + { + FT_ERROR(( "ps_parser_skip_PS_token:" + " unexpected closing delimiter `>'\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + cur++; + goto Exit; + } + + if ( *cur == '/' ) + cur++; + + /* anything else */ + while ( cur < limit ) + { + /* *cur might be invalid (e.g., ')' or '}'), but this */ + /* is handled by the test `cur == parser->cursor' below */ + if ( IS_PS_DELIM( *cur ) ) + break; + + cur++; + } + + Exit: + if ( cur < limit && cur == parser->cursor ) + { + FT_ERROR(( "ps_parser_skip_PS_token:" + " current token is `%c' which is self-delimiting\n", + *cur )); + FT_ERROR(( " " + " but invalid at this point\n" )); + + error = FT_THROW( Invalid_File_Format ); + } + + if ( cur > limit ) + cur = limit; + + parser->error = error; + parser->cursor = cur; + } + + + FT_LOCAL_DEF( void ) + ps_parser_skip_spaces( PS_Parser parser ) + { + skip_spaces( &parser->cursor, parser->limit ); + } + + + /* `token' here means either something between balanced delimiters */ + /* or the next token; the delimiters are not removed. */ + + FT_LOCAL_DEF( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ) + { + FT_Byte* cur; + FT_Byte* limit; + FT_Int embed; + + + token->type = T1_TOKEN_TYPE_NONE; + token->start = NULL; + token->limit = NULL; + + /* first of all, skip leading whitespace */ + ps_parser_skip_spaces( parser ); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur >= limit ) + return; + + switch ( *cur ) + { + /************* check for literal string *****************/ + case '(': + token->type = T1_TOKEN_TYPE_STRING; + token->start = cur; + + if ( skip_literal_string( &cur, limit ) == FT_Err_Ok ) + token->limit = cur; + break; + + /************* check for programs/array *****************/ + case '{': + token->type = T1_TOKEN_TYPE_ARRAY; + token->start = cur; + + if ( skip_procedure( &cur, limit ) == FT_Err_Ok ) + token->limit = cur; + break; + + /************* check for table/array ********************/ + /* XXX: in theory we should also look for "<<" */ + /* since this is semantically equivalent to "["; */ + /* in practice it doesn't matter (?) */ + case '[': + token->type = T1_TOKEN_TYPE_ARRAY; + embed = 1; + token->start = cur++; + + /* we need this to catch `[ ]' */ + parser->cursor = cur; + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + + while ( cur < limit && !parser->error ) + { + /* XXX: this is wrong because it does not */ + /* skip comments, procedures, and strings */ + if ( *cur == '[' ) + embed++; + else if ( *cur == ']' ) + { + embed--; + if ( embed <= 0 ) + { + token->limit = ++cur; + break; + } + } + + parser->cursor = cur; + ps_parser_skip_PS_token( parser ); + /* we need this to catch `[XXX ]' */ + ps_parser_skip_spaces ( parser ); + cur = parser->cursor; + } + break; + + /* ************ otherwise, it is any token **************/ + default: + token->start = cur; + token->type = ( *cur == '/' ) ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY; + ps_parser_skip_PS_token( parser ); + cur = parser->cursor; + if ( !parser->error ) + token->limit = cur; + } + + if ( !token->limit ) + { + token->start = NULL; + token->type = T1_TOKEN_TYPE_NONE; + } + + parser->cursor = cur; + } + + + /* NB: `tokens' can be NULL if we only want to count */ + /* the number of array elements */ + + FT_LOCAL_DEF( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ) + { + T1_TokenRec master; + + + *pnum_tokens = -1; + + /* this also handles leading whitespace */ + ps_parser_to_token( parser, &master ); + + if ( master.type == T1_TOKEN_TYPE_ARRAY ) + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + T1_Token cur = tokens; + T1_Token limit = cur + max_tokens; + + + /* don't include outermost delimiters */ + parser->cursor = master.start + 1; + parser->limit = master.limit - 1; + + while ( parser->cursor < parser->limit ) + { + T1_TokenRec token; + + + ps_parser_to_token( parser, &token ); + if ( !token.type ) + break; + + if ( tokens && cur < limit ) + *cur = token; + + cur++; + } + + *pnum_tokens = (FT_Int)( cur - tokens ); + + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } + + + /* first character must be a delimiter or a part of a number */ + /* NB: `coords' can be NULL if we just want to skip the */ + /* array; in this case we ignore `max_coords' */ + + static FT_Int + ps_tocoordarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_coords, + FT_Short* coords ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* check for the beginning of an array; otherwise, only one number */ + /* will be read */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the coordinates */ + while ( cur < limit ) + { + FT_Short dummy; + FT_Byte* old_cur; + + + /* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + + if ( *cur == ender ) + { + cur++; + break; + } + + old_cur = cur; + + if ( coords && count >= max_coords ) + break; + + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( coords ? &coords[count] : &dummy ) = + (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); + + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + + if ( !ender ) + break; + } + + Exit: + *acur = cur; + return count; + } + + + /* first character must be a delimiter or a part of a number */ + /* NB: `values' can be NULL if we just want to skip the */ + /* array; in this case we ignore `max_values' */ + /* */ + /* return number of successfully parsed values */ + + static FT_Int + ps_tofixedarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* Check for the beginning of an array. Otherwise, only one number */ + /* will be read. */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the values */ + while ( cur < limit ) + { + FT_Fixed dummy; + FT_Byte* old_cur; + + + /* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + + if ( *cur == ender ) + { + cur++; + break; + } + + old_cur = cur; + + if ( values && count >= max_values ) + break; + + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( values ? &values[count] : &dummy ) = + PS_Conv_ToFixed( &cur, limit, power_ten ); + + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + + if ( !ender ) + break; + } + + Exit: + *acur = cur; + return count; + } + + +#if 0 + + static FT_String* + ps_tostring( FT_Byte** cursor, + FT_Byte* limit, + FT_Memory memory ) + { + FT_Byte* cur = *cursor; + FT_UInt len = 0; + FT_Int count; + FT_String* result; + FT_Error error; + + + /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ + /* that simply doesn't begin with an opening parenthesis, even */ + /* though they have a closing one! E.g. "amuncial.pfb" */ + /* */ + /* We must deal with these ill-fated cases there. Note that */ + /* these fonts didn't work with the old Type 1 driver as the */ + /* notice/copyright was not recognized as a valid string token */ + /* and made the old token parser commit errors. */ + + while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) + cur++; + if ( cur + 1 >= limit ) + return 0; + + if ( *cur == '(' ) + cur++; /* skip the opening parenthesis, if there is one */ + + *cursor = cur; + count = 0; + + /* then, count its length */ + for ( ; cur < limit; cur++ ) + { + if ( *cur == '(' ) + count++; + + else if ( *cur == ')' ) + { + count--; + if ( count < 0 ) + break; + } + } + + len = (FT_UInt)( cur - *cursor ); + if ( cur >= limit || FT_QALLOC( result, len + 1 ) ) + return 0; + + /* now copy the string */ + FT_MEM_COPY( result, *cursor, len ); + result[len] = '\0'; + *cursor = cur; + return result; + } + +#endif /* 0 */ + + + static int + ps_tobool( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Bool result = 0; + + + /* return 1 if we find `true', 0 otherwise */ + if ( cur + 3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur + 4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + + *acur = cur; + return result; + } + + + /* load a simple field (i.e. non-table) into the current list of objects */ + + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec token; + FT_Byte* cur; + FT_Byte* limit; + FT_UInt count; + FT_UInt idx; + FT_Error error; + T1_FieldType type; + + + /* this also skips leading whitespace */ + ps_parser_to_token( parser, &token ); + if ( !token.type ) + goto Fail; + + count = 1; + idx = 0; + cur = token.start; + limit = token.limit; + + type = field->type; + + /* we must detect arrays in /FontBBox */ + if ( type == T1_FIELD_TYPE_BBOX ) + { + T1_TokenRec token2; + FT_Byte* old_cur = parser->cursor; + FT_Byte* old_limit = parser->limit; + + + /* don't include delimiters */ + parser->cursor = token.start + 1; + parser->limit = token.limit - 1; + + ps_parser_to_token( parser, &token2 ); + parser->cursor = old_cur; + parser->limit = old_limit; + + if ( token2.type == T1_TOKEN_TYPE_ARRAY ) + { + type = T1_FIELD_TYPE_MM_BBOX; + goto FieldArray; + } + } + else if ( token.type == T1_TOKEN_TYPE_ARRAY ) + { + count = max_objects; + + FieldArray: + /* if this is an array and we have no blend, an error occurs */ + if ( max_objects == 0 ) + goto Fail; + + idx = 1; + + /* don't include delimiters */ + cur++; + limit--; + } + + for ( ; count > 0; count--, idx++ ) + { + FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; + FT_Long val; + + + skip_spaces( &cur, limit ); + + switch ( type ) + { + case T1_FIELD_TYPE_BOOL: + val = ps_tobool( &cur, limit ); + FT_TRACE4(( " %s", val ? "true" : "false" )); + goto Store_Integer; + + case T1_FIELD_TYPE_FIXED: + val = PS_Conv_ToFixed( &cur, limit, 0 ); + FT_TRACE4(( " %f", (double)val / 65536 )); + goto Store_Integer; + + case T1_FIELD_TYPE_FIXED_1000: + val = PS_Conv_ToFixed( &cur, limit, 3 ); + FT_TRACE4(( " %f", (double)val / 65536 / 1000 )); + goto Store_Integer; + + case T1_FIELD_TYPE_INTEGER: + val = PS_Conv_ToInt( &cur, limit ); + FT_TRACE4(( " %ld", val )); + /* fall through */ + + Store_Integer: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_UShort*)q = (FT_UShort)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_UInt32*)q = (FT_UInt32)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + break; + + case T1_FIELD_TYPE_STRING: + case T1_FIELD_TYPE_KEY: + { + FT_Memory memory = parser->memory; + FT_UInt len = (FT_UInt)( limit - cur ); + FT_String* string = NULL; + + + if ( cur >= limit ) + break; + + /* we allow both a string or a name */ + /* for cases like /FontName (foo) def */ + if ( token.type == T1_TOKEN_TYPE_KEY ) + { + /* don't include leading `/' */ + len--; + cur++; + } + else if ( token.type == T1_TOKEN_TYPE_STRING ) + { + /* don't include delimiting parentheses */ + /* XXX we don't handle <<...>> here */ + /* XXX should we convert octal escapes? */ + /* if so, what encoding should we use? */ + cur++; + len -= 2; + } + else + { + FT_ERROR(( "ps_parser_load_field:" + " expected a name or string\n" )); + FT_ERROR(( " " + " but found token of type %d instead\n", + token.type )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* for this to work (FT_String**)q must have been */ + /* initialized to NULL */ + if ( *(FT_String**)q ) + { + FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", + field->ident )); + FT_FREE( *(FT_String**)q ); + } + + if ( FT_QALLOC( string, len + 1 ) ) + goto Exit; + + FT_MEM_COPY( string, cur, len ); + string[len] = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( token.type == T1_TOKEN_TYPE_STRING ) + FT_TRACE4(( " (%s)", string )); + else + FT_TRACE4(( " /%s", string )); +#endif + + *(FT_String**)q = string; + } + break; + + case T1_FIELD_TYPE_BBOX: + { + FT_Fixed temp[4]; + FT_BBox* bbox = (FT_BBox*)q; + FT_Int result; + + + result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); + + if ( result < 4 ) + { + FT_ERROR(( "ps_parser_load_field:" + " expected four integers in bounding box\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + bbox->xMin = FT_RoundFix( temp[0] ); + bbox->yMin = FT_RoundFix( temp[1] ); + bbox->xMax = FT_RoundFix( temp[2] ); + bbox->yMax = FT_RoundFix( temp[3] ); + + FT_TRACE4(( " [%ld %ld %ld %ld]", + bbox->xMin / 65536, + bbox->yMin / 65536, + bbox->xMax / 65536, + bbox->yMax / 65536 )); + } + break; + + case T1_FIELD_TYPE_MM_BBOX: + { + FT_Memory memory = parser->memory; + FT_Fixed* temp = NULL; + FT_Int result; + FT_UInt i; + + + if ( FT_QNEW_ARRAY( temp, max_objects * 4 ) ) + goto Exit; + + for ( i = 0; i < 4; i++ ) + { + result = ps_tofixedarray( &cur, limit, (FT_Int)max_objects, + temp + i * max_objects, 0 ); + if ( result < 0 || (FT_UInt)result < max_objects ) + { + FT_ERROR(( "ps_parser_load_field:" + " expected %d integer%s in the %s subarray\n", + max_objects, max_objects > 1 ? "s" : "", + i == 0 ? "first" + : ( i == 1 ? "second" + : ( i == 2 ? "third" + : "fourth" ) ) )); + FT_ERROR(( " " + " of /FontBBox in the /Blend dictionary\n" )); + error = FT_THROW( Invalid_File_Format ); + + FT_FREE( temp ); + goto Exit; + } + + skip_spaces( &cur, limit ); + } + + FT_TRACE4(( " [" )); + for ( i = 0; i < max_objects; i++ ) + { + FT_BBox* bbox = (FT_BBox*)objects[i]; + + + bbox->xMin = FT_RoundFix( temp[i ] ); + bbox->yMin = FT_RoundFix( temp[i + max_objects] ); + bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] ); + bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] ); + + FT_TRACE4(( " [%ld %ld %ld %ld]", + bbox->xMin / 65536, + bbox->yMin / 65536, + bbox->xMax / 65536, + bbox->yMax / 65536 )); + } + FT_TRACE4(( "]" )); + + FT_FREE( temp ); + } + break; + + default: + /* an error occurred */ + goto Fail; + } + } + +#if 0 /* obsolete -- keep for reference */ + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + + error = FT_Err_Ok; + + Exit: + return error; + + Fail: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + +#define T1_MAX_TABLE_ELEMENTS 32 + + + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; + T1_Token token; + FT_Int num_elements; + FT_Error error = FT_Err_Ok; + FT_Byte* old_cursor; + FT_Byte* old_limit; + T1_FieldRec fieldrec = *(T1_Field)field; + + + fieldrec.type = T1_FIELD_TYPE_INTEGER; + if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || + field->type == T1_FIELD_TYPE_BBOX ) + fieldrec.type = T1_FIELD_TYPE_FIXED; + + ps_parser_to_token_array( parser, elements, + T1_MAX_TABLE_ELEMENTS, &num_elements ); + if ( num_elements < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( (FT_UInt)num_elements > field->array_max ) + num_elements = (FT_Int)field->array_max; + + old_cursor = parser->cursor; + old_limit = parser->limit; + + /* we store the elements count if necessary; */ + /* we further assume that `count_offset' can't be zero */ + if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) + *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = + (FT_Byte)num_elements; + + FT_TRACE4(( " [" )); + + /* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + + error = ps_parser_load_field( parser, + &fieldrec, + objects, + max_objects, + 0 ); + if ( error ) + break; + + fieldrec.offset += fieldrec.size; + } + + FT_TRACE4(( "]" )); + +#if 0 /* obsolete -- keep for reference */ + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Long ) + ps_parser_to_int( PS_Parser parser ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToInt( &parser->cursor, parser->limit ); + } + + + /* first character must be `<' if `delimiters' is non-zero */ + + FT_LOCAL_DEF( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_ULong* pnum_bytes, + FT_Bool delimiters ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* cur; + + + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + + if ( cur >= parser->limit ) + goto Exit; + + if ( delimiters ) + { + if ( *cur != '<' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + cur++; + } + + *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, + parser->limit, + bytes, + max_bytes ); + + parser->cursor = cur; + + if ( delimiters ) + { + if ( cur < parser->limit && *cur != '>' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + parser->cursor++; + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); + } + + + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ) + { + ps_parser_skip_spaces( parser ); + return ps_tocoordarray( &parser->cursor, parser->limit, + max_coords, coords ); + } + + + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return ps_tofixedarray( &parser->cursor, parser->limit, + max_values, values, power_ten ); + } + + +#if 0 + + FT_LOCAL_DEF( FT_String* ) + T1_ToString( PS_Parser parser ) + { + return ps_tostring( &parser->cursor, parser->limit, parser->memory ); + } + + + FT_LOCAL_DEF( FT_Bool ) + T1_ToBool( PS_Parser parser ) + { + return ps_tobool( &parser->cursor, parser->limit ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ) + { + parser->error = FT_Err_Ok; + parser->base = base; + parser->limit = limit; + parser->cursor = base; + parser->memory = memory; + parser->funcs = ps_parser_funcs; + } + + + FT_LOCAL_DEF( void ) + ps_parser_done( PS_Parser parser ) + { + FT_UNUSED( parser ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * t1_builder_init + * + * @Description: + * Initializes a given glyph builder. + * + * @InOut: + * builder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * glyph :: + * The current glyph object. + * + * hinting :: + * Whether hinting should be applied. + */ + FT_LOCAL_DEF( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->parse_state = T1_Parse_Start; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->memory; + + if ( glyph ) + { + FT_GlyphLoader loader = glyph->internal->loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + + builder->hints_globals = size->internal->module_data; + builder->hints_funcs = NULL; + + if ( hinting ) + builder->hints_funcs = glyph->internal->glyph_hints; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->funcs = t1_builder_funcs; + } + + + /************************************************************************** + * + * @Function: + * t1_builder_done + * + * @Description: + * Finalizes a given glyph builder. Its contents can still be used + * after the call, but the function saves important information + * within the corresponding glyph slot. + * + * @Input: + * builder :: + * A pointer to the glyph builder to finalize. + */ + FT_LOCAL_DEF( void ) + t1_builder_done( T1_Builder builder ) + { + FT_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->outline = *builder->base; + } + + + /* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + + + point->x = FIXED_TO_INT( x ); + point->y = FIXED_TO_INT( y ); + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = t1_builder_check_points( builder, 1 ); + if ( !error ) + t1_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + /* this might happen in invalid fonts */ + if ( !outline ) + { + FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" )); + return FT_THROW( Invalid_File_Format ); + } + + if ( !builder->load_points ) + { + outline->n_contours++; + return FT_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = FT_ERR( Invalid_File_Format ); + + + /* test whether we are building a new contour */ + + if ( builder->parse_state == T1_Parse_Have_Path ) + error = FT_Err_Ok; + else + { + builder->parse_state = T1_Parse_Have_Path; + error = t1_builder_add_contour( builder ); + if ( !error ) + error = t1_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + FT_LOCAL_DEF( void ) + t1_builder_close_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + + + if ( !outline ) + return; + + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; + + /* in malformed fonts it can happen that a contour was started */ + /* but no points were added */ + if ( outline->n_contours && first == outline->n_points ) + { + outline->n_contours--; + return; + } + + /* We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + + + /* `delete' last point only if it coincides with the first */ + /* point and it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + { + /* Don't add contours only consisting of one point, i.e., */ + /* check whether the first and the last point is the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * cff_builder_init + * + * @Description: + * Initializes a given glyph builder. + * + * @InOut: + * builder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * glyph :: + * The current glyph object. + * + * hinting :: + * Whether hinting is active. + */ + FT_LOCAL_DEF( void ) + cff_builder_init( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if ( glyph ) + { + FT_GlyphLoader loader = glyph->root.internal->loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + + builder->hints_globals = NULL; + builder->hints_funcs = NULL; + + if ( hinting && size ) + { + FT_Size ftsize = FT_SIZE( size ); + CFF_Internal internal = (CFF_Internal)ftsize->internal->module_data; + + if ( internal ) + { + builder->hints_globals = (void *)internal->topfont; + builder->hints_funcs = glyph->root.internal->glyph_hints; + } + } + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->funcs = cff_builder_funcs; + } + + + /************************************************************************** + * + * @Function: + * cff_builder_done + * + * @Description: + * Finalizes a given glyph builder. Its contents can still be used + * after the call, but the function saves important information + * within the corresponding glyph slot. + * + * @Input: + * builder :: + * A pointer to the glyph builder to finalize. + */ + FT_LOCAL_DEF( void ) + cff_builder_done( CFF_Builder* builder ) + { + CFF_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + cff_check_points( CFF_Builder* builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + cff_builder_add_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); + + + if ( driver->hinting_engine == FT_HINTING_FREETYPE ) + { + point->x = x >> 16; + point->y = y >> 16; + } + else +#endif + { + /* cf2_decoder_parse_charstrings uses 16.16 coordinates */ + point->x = x >> 10; + point->y = y >> 10; + } + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + cff_builder_add_point1( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = cff_check_points( builder, 1 ); + if ( !error ) + cff_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + cff_builder_add_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + if ( !builder->load_points ) + { + outline->n_contours++; + return FT_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + cff_builder_start_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = FT_Err_Ok; + + + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + builder->path_begun = 1; + error = cff_builder_add_contour( builder ); + if ( !error ) + error = cff_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + FT_LOCAL_DEF( void ) + cff_builder_close_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + + + if ( !outline ) + return; + + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; + + /* in malformed fonts it can happen that a contour was started */ + /* but no points were added */ + if ( outline->n_contours && first == outline->n_points ) + { + outline->n_contours--; + return; + } + + /* We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + + + /* `delete' last point only if it coincides with the first */ + /* point and if it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + { + /* Don't add contours only consisting of one point, i.e., */ + /* check whether begin point and last point are the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * ps_builder_init + * + * @Description: + * Initializes a given glyph builder. + * + * @InOut: + * builder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * glyph :: + * The current glyph object. + * + * hinting :: + * Whether hinting should be applied. + */ + FT_LOCAL_DEF( void ) + ps_builder_init( PS_Builder* ps_builder, + void* builder, + FT_Bool is_t1 ) + { + FT_ZERO( ps_builder ); + + if ( is_t1 ) + { + T1_Builder t1builder = (T1_Builder)builder; + + + ps_builder->memory = t1builder->memory; + ps_builder->face = (FT_Face)t1builder->face; + ps_builder->glyph = (CFF_GlyphSlot)t1builder->glyph; + ps_builder->loader = t1builder->loader; + ps_builder->base = t1builder->base; + ps_builder->current = t1builder->current; + + ps_builder->pos_x = &t1builder->pos_x; + ps_builder->pos_y = &t1builder->pos_y; + + ps_builder->left_bearing = &t1builder->left_bearing; + ps_builder->advance = &t1builder->advance; + + ps_builder->bbox = &t1builder->bbox; + ps_builder->path_begun = 0; + ps_builder->load_points = t1builder->load_points; + ps_builder->no_recurse = t1builder->no_recurse; + + ps_builder->metrics_only = t1builder->metrics_only; + } + else + { + CFF_Builder* cffbuilder = (CFF_Builder*)builder; + + + ps_builder->memory = cffbuilder->memory; + ps_builder->face = (FT_Face)cffbuilder->face; + ps_builder->glyph = cffbuilder->glyph; + ps_builder->loader = cffbuilder->loader; + ps_builder->base = cffbuilder->base; + ps_builder->current = cffbuilder->current; + + ps_builder->pos_x = &cffbuilder->pos_x; + ps_builder->pos_y = &cffbuilder->pos_y; + + ps_builder->left_bearing = &cffbuilder->left_bearing; + ps_builder->advance = &cffbuilder->advance; + + ps_builder->bbox = &cffbuilder->bbox; + ps_builder->path_begun = cffbuilder->path_begun; + ps_builder->load_points = cffbuilder->load_points; + ps_builder->no_recurse = cffbuilder->no_recurse; + + ps_builder->metrics_only = cffbuilder->metrics_only; + } + + ps_builder->is_t1 = is_t1; + ps_builder->funcs = ps_builder_funcs; + } + + + /************************************************************************** + * + * @Function: + * ps_builder_done + * + * @Description: + * Finalizes a given glyph builder. Its contents can still be used + * after the call, but the function saves important information + * within the corresponding glyph slot. + * + * @Input: + * builder :: + * A pointer to the glyph builder to finalize. + */ + FT_LOCAL_DEF( void ) + ps_builder_done( PS_Builder* builder ) + { + CFF_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_check_points( PS_Builder* builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + ps_builder_add_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); + + + if ( !builder->is_t1 && + driver->hinting_engine == FT_HINTING_FREETYPE ) + { + point->x = x >> 16; + point->y = y >> 16; + } + else +#endif +#ifdef T1_CONFIG_OPTION_OLD_ENGINE +#ifndef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); +#endif + if ( builder->is_t1 && + driver->hinting_engine == FT_HINTING_FREETYPE ) + { + point->x = FIXED_TO_INT( x ); + point->y = FIXED_TO_INT( y ); + } + else +#endif + { + /* cf2_decoder_parse_charstrings uses 16.16 coordinates */ + point->x = x >> 10; + point->y = y >> 10; + } + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_add_point1( PS_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = ps_builder_check_points( builder, 1 ); + if ( !error ) + ps_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_add_contour( PS_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + /* this might happen in invalid fonts */ + if ( !outline ) + { + FT_ERROR(( "ps_builder_add_contour: no outline to add points to\n" )); + return FT_THROW( Invalid_File_Format ); + } + + if ( !builder->load_points ) + { + outline->n_contours++; + return FT_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_start_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = FT_Err_Ok; + + + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + builder->path_begun = 1; + error = ps_builder_add_contour( builder ); + if ( !error ) + error = ps_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + FT_LOCAL_DEF( void ) + ps_builder_close_contour( PS_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + + + if ( !outline ) + return; + + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; + + /* in malformed fonts it can happen that a contour was started */ + /* but no points were added */ + if ( outline->n_contours && first == outline->n_points ) + { + outline->n_contours--; + return; + } + + /* We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + + + /* `delete' last point only if it coincides with the first */ + /* point and it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + { + /* Don't add contours only consisting of one point, i.e., */ + /* check whether the first and the last point is the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** OTHER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * ps_decoder_init + * + * @Description: + * Creates a wrapper decoder for use in the combined + * Type 1 / CFF interpreter. + * + * @InOut: + * ps_decoder :: + * A pointer to the decoder to initialize. + * + * @Input: + * decoder :: + * A pointer to the original decoder. + * + * is_t1 :: + * Flag indicating Type 1 or CFF + */ + FT_LOCAL_DEF( void ) + ps_decoder_init( PS_Decoder* ps_decoder, + void* decoder, + FT_Bool is_t1 ) + { + FT_ZERO( ps_decoder ); + + if ( is_t1 ) + { + T1_Decoder t1_decoder = (T1_Decoder)decoder; + + + ps_builder_init( &ps_decoder->builder, + &t1_decoder->builder, + is_t1 ); + + ps_decoder->cf2_instance = &t1_decoder->cf2_instance; + ps_decoder->psnames = t1_decoder->psnames; + + ps_decoder->num_glyphs = t1_decoder->num_glyphs; + ps_decoder->glyph_names = t1_decoder->glyph_names; + ps_decoder->hint_mode = t1_decoder->hint_mode; + ps_decoder->blend = t1_decoder->blend; + + ps_decoder->num_locals = (FT_UInt)t1_decoder->num_subrs; + ps_decoder->locals = t1_decoder->subrs; + ps_decoder->locals_len = t1_decoder->subrs_len; + ps_decoder->locals_hash = t1_decoder->subrs_hash; + + ps_decoder->buildchar = t1_decoder->buildchar; + ps_decoder->len_buildchar = t1_decoder->len_buildchar; + + ps_decoder->lenIV = t1_decoder->lenIV; + } + else + { + CFF_Decoder* cff_decoder = (CFF_Decoder*)decoder; + + + ps_builder_init( &ps_decoder->builder, + &cff_decoder->builder, + is_t1 ); + + ps_decoder->cff = cff_decoder->cff; + ps_decoder->cf2_instance = &cff_decoder->cff->cf2_instance; + ps_decoder->current_subfont = cff_decoder->current_subfont; + + ps_decoder->num_globals = cff_decoder->num_globals; + ps_decoder->globals = cff_decoder->globals; + ps_decoder->globals_bias = cff_decoder->globals_bias; + ps_decoder->num_locals = cff_decoder->num_locals; + ps_decoder->locals = cff_decoder->locals; + ps_decoder->locals_bias = cff_decoder->locals_bias; + + ps_decoder->glyph_width = &cff_decoder->glyph_width; + ps_decoder->width_only = cff_decoder->width_only; + + ps_decoder->hint_mode = cff_decoder->hint_mode; + + ps_decoder->get_glyph_callback = cff_decoder->get_glyph_callback; + ps_decoder->free_glyph_callback = cff_decoder->free_glyph_callback; + } + } + + + /* Synthesize a SubFont object for Type 1 fonts, for use in the */ + /* new interpreter to access Private dict data. */ + FT_LOCAL_DEF( void ) + t1_make_subfont( FT_Face face, + PS_Private priv, + CFF_SubFont subfont ) + { + CFF_Private cpriv = &subfont->private_dict; + FT_UInt n, count; + + + FT_ZERO( subfont ); + FT_ZERO( cpriv ); + + count = cpriv->num_blue_values = priv->num_blue_values; + for ( n = 0; n < count; n++ ) + cpriv->blue_values[n] = (FT_Pos)priv->blue_values[n]; + + count = cpriv->num_other_blues = priv->num_other_blues; + for ( n = 0; n < count; n++ ) + cpriv->other_blues[n] = (FT_Pos)priv->other_blues[n]; + + count = cpriv->num_family_blues = priv->num_family_blues; + for ( n = 0; n < count; n++ ) + cpriv->family_blues[n] = (FT_Pos)priv->family_blues[n]; + + count = cpriv->num_family_other_blues = priv->num_family_other_blues; + for ( n = 0; n < count; n++ ) + cpriv->family_other_blues[n] = (FT_Pos)priv->family_other_blues[n]; + + cpriv->blue_scale = priv->blue_scale; + cpriv->blue_shift = (FT_Pos)priv->blue_shift; + cpriv->blue_fuzz = (FT_Pos)priv->blue_fuzz; + + cpriv->standard_width = (FT_Pos)priv->standard_width[0]; + cpriv->standard_height = (FT_Pos)priv->standard_height[0]; + + count = cpriv->num_snap_widths = priv->num_snap_widths; + for ( n = 0; n < count; n++ ) + cpriv->snap_widths[n] = (FT_Pos)priv->snap_widths[n]; + + count = cpriv->num_snap_heights = priv->num_snap_heights; + for ( n = 0; n < count; n++ ) + cpriv->snap_heights[n] = (FT_Pos)priv->snap_heights[n]; + + cpriv->force_bold = priv->force_bold; + cpriv->lenIV = priv->lenIV; + cpriv->language_group = priv->language_group; + cpriv->expansion_factor = priv->expansion_factor; + + cpriv->subfont = subfont; + + + /* Initialize the random number generator. */ + if ( face->internal->random_seed != -1 ) + { + /* If we have a face-specific seed, use it. */ + /* If non-zero, update it to a positive value. */ + subfont->random = (FT_UInt32)face->internal->random_seed; + if ( face->internal->random_seed ) + { + do + { + face->internal->random_seed = (FT_Int32)cff_random( + (FT_UInt32)face->internal->random_seed ); + + } while ( face->internal->random_seed < 0 ); + } + } + if ( !subfont->random ) + { + FT_UInt32 seed; + + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&face ^ + (FT_Offset)(char*)&subfont ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + if ( seed == 0 ) + seed = 0x7384; + + subfont->random = seed; + } + } + + + FT_LOCAL_DEF( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ) + { + PS_Conv_EexecDecode( &buffer, + FT_OFFSET( buffer, length ), + buffer, + length, + &seed ); + } + + + FT_LOCAL_DEF( FT_UInt32 ) + cff_random( FT_UInt32 r ) + { + /* a 32bit version of the `xorshift' algorithm */ + r ^= r << 13; + r ^= r >> 17; + r ^= r << 5; + + return r; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psobjs.h b/vendor/freetype/src/psaux/psobjs.h new file mode 100644 index 0000000..d5bce54 --- /dev/null +++ b/vendor/freetype/src/psaux/psobjs.h @@ -0,0 +1,312 @@ +/**************************************************************************** + * + * psobjs.h + * + * Auxiliary functions for PostScript fonts (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSOBJS_H_ +#define PSOBJS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_TABLE + const PS_Table_FuncsRec ps_table_funcs; + + FT_CALLBACK_TABLE + const PS_Parser_FuncsRec ps_parser_funcs; + + FT_CALLBACK_TABLE + const T1_Builder_FuncsRec t1_builder_funcs; + + + FT_LOCAL( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ); + + FT_LOCAL( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + const void* object, + FT_UInt length ); + + FT_LOCAL( void ) + ps_table_done( PS_Table table ); + + + FT_LOCAL( void ) + ps_table_release( PS_Table table ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL( void ) + ps_parser_skip_spaces( PS_Parser parser ); + + FT_LOCAL( void ) + ps_parser_skip_PS_token( PS_Parser parser ); + + FT_LOCAL( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ); + + FT_LOCAL( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + FT_LOCAL( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_LOCAL( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_LOCAL( FT_Long ) + ps_parser_to_int( PS_Parser parser ); + + + FT_LOCAL( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_ULong* pnum_bytes, + FT_Bool delimiters ); + + + FT_LOCAL( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ); + + + FT_LOCAL( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + + FT_LOCAL( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + + FT_LOCAL( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + + FT_LOCAL( void ) + ps_parser_done( PS_Parser parser ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ); + + FT_LOCAL( void ) + t1_builder_done( T1_Builder builder ); + + FT_LOCAL( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ); + + FT_LOCAL( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + FT_LOCAL( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + FT_LOCAL( FT_Error ) + t1_builder_add_contour( T1_Builder builder ); + + + FT_LOCAL( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + + FT_LOCAL( void ) + t1_builder_close_contour( T1_Builder builder ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + cff_builder_init( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ); + + FT_LOCAL( void ) + cff_builder_done( CFF_Builder* builder ); + + FT_LOCAL( FT_Error ) + cff_check_points( CFF_Builder* builder, + FT_Int count ); + + FT_LOCAL( void ) + cff_builder_add_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + FT_LOCAL( FT_Error ) + cff_builder_add_point1( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + FT_LOCAL( FT_Error ) + cff_builder_start_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + FT_LOCAL( void ) + cff_builder_close_contour( CFF_Builder* builder ); + + FT_LOCAL( FT_Error ) + cff_builder_add_contour( CFF_Builder* builder ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + ps_builder_init( PS_Builder* ps_builder, + void* builder, + FT_Bool is_t1 ); + + + FT_LOCAL( void ) + ps_builder_done( PS_Builder* builder ); + + FT_LOCAL( FT_Error ) + ps_builder_check_points( PS_Builder* builder, + FT_Int count ); + + FT_LOCAL( void ) + ps_builder_add_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + FT_LOCAL( FT_Error ) + ps_builder_add_point1( PS_Builder* builder, + FT_Pos x, + FT_Pos y ); + + FT_LOCAL( FT_Error ) + ps_builder_add_contour( PS_Builder* builder ); + + FT_LOCAL( FT_Error ) + ps_builder_start_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y ); + + FT_LOCAL( void ) + ps_builder_close_contour( PS_Builder* builder ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** OTHER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + ps_decoder_init( PS_Decoder* ps_decoder, + void* decoder, + FT_Bool is_t1 ); + + FT_LOCAL( void ) + t1_make_subfont( FT_Face face, + PS_Private priv, + CFF_SubFont subfont ); + + FT_LOCAL( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + + + FT_LOCAL( FT_UInt32 ) + cff_random( FT_UInt32 r ); + + +FT_END_HEADER + +#endif /* PSOBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psread.c b/vendor/freetype/src/psaux/psread.c new file mode 100644 index 0000000..7f657f2 --- /dev/null +++ b/vendor/freetype/src/psaux/psread.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * + * psread.c + * + * Adobe's code for stream handling (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" + +#include "pserror.h" + + + /* Define CF2_IO_FAIL as 1 to enable random errors and random */ + /* value errors in I/O. */ +#define CF2_IO_FAIL 0 + + +#if CF2_IO_FAIL + + /* set the .00 value to a nonzero probability */ + static int + randomError2( void ) + { + /* for region buffer ReadByte (interp) function */ + return (double)rand() / RAND_MAX < .00; + } + + /* set the .00 value to a nonzero probability */ + static CF2_Int + randomValue() + { + return (double)rand() / RAND_MAX < .00 ? rand() : 0; + } + +#endif /* CF2_IO_FAIL */ + + + /* Region Buffer */ + /* */ + /* Can be constructed from a copied buffer managed by */ + /* `FCM_getDatablock'. */ + /* Reads bytes with check for end of buffer. */ + + /* reading past the end of the buffer sets error and returns zero */ + FT_LOCAL_DEF( CF2_Int ) + cf2_buf_readByte( CF2_Buffer buf ) + { + if ( buf->ptr < buf->end ) + { +#if CF2_IO_FAIL + if ( randomError2() ) + { + CF2_SET_ERROR( buf->error, Invalid_Stream_Operation ); + return 0; + } + + return *(buf->ptr)++ + randomValue(); +#else + return *(buf->ptr)++; +#endif + } + else + { + CF2_SET_ERROR( buf->error, Invalid_Stream_Operation ); + return 0; + } + } + + + /* note: end condition can occur without error */ + FT_LOCAL_DEF( FT_Bool ) + cf2_buf_isEnd( CF2_Buffer buf ) + { + return FT_BOOL( buf->ptr >= buf->end ); + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psread.h b/vendor/freetype/src/psaux/psread.h new file mode 100644 index 0000000..9e55fe0 --- /dev/null +++ b/vendor/freetype/src/psaux/psread.h @@ -0,0 +1,68 @@ +/**************************************************************************** + * + * psread.h + * + * Adobe's code for stream handling (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSREAD_H_ +#define PSREAD_H_ + + +FT_BEGIN_HEADER + + + typedef struct CF2_BufferRec_ + { + FT_Error* error; + const FT_Byte* start; + const FT_Byte* end; + const FT_Byte* ptr; + + } CF2_BufferRec, *CF2_Buffer; + + + FT_LOCAL( CF2_Int ) + cf2_buf_readByte( CF2_Buffer buf ); + FT_LOCAL( FT_Bool ) + cf2_buf_isEnd( CF2_Buffer buf ); + + +FT_END_HEADER + + +#endif /* PSREAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/psstack.c b/vendor/freetype/src/psaux/psstack.c new file mode 100644 index 0000000..7974865 --- /dev/null +++ b/vendor/freetype/src/psaux/psstack.c @@ -0,0 +1,329 @@ +/**************************************************************************** + * + * psstack.c + * + * Adobe's code for emulating a CFF stack (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" +#include "psfont.h" +#include "psstack.h" + +#include "pserror.h" + + + /* Allocate and initialize an instance of CF2_Stack. */ + /* Note: This function returns NULL on error (does not set */ + /* `error'). */ + FT_LOCAL_DEF( CF2_Stack ) + cf2_stack_init( FT_Memory memory, + FT_Error* e, + FT_UInt stackSize ) + { + FT_Error error; /* for FT_QNEW */ + CF2_Stack stack = NULL; + + + if ( FT_QNEW( stack ) ) + return NULL; + + stack->memory = memory; + stack->error = e; + + /* allocate the stack buffer */ + if ( FT_QNEW_ARRAY( stack->buffer, stackSize ) ) + { + FT_FREE( stack ); + return NULL; + } + + stack->stackSize = stackSize; + stack->top = stack->buffer; /* empty stack */ + + return stack; + } + + + FT_LOCAL_DEF( void ) + cf2_stack_free( CF2_Stack stack ) + { + if ( stack ) + { + FT_Memory memory = stack->memory; + + /* free the buffer */ + FT_FREE( stack->buffer ); + + /* free the main structure */ + FT_FREE( stack ); + } + } + + + FT_LOCAL_DEF( CF2_UInt ) + cf2_stack_count( CF2_Stack stack ) + { + return (CF2_UInt)( stack->top - stack->buffer ); + } + + + FT_LOCAL_DEF( void ) + cf2_stack_pushInt( CF2_Stack stack, + CF2_Int val ) + { + if ( stack->top == stack->buffer + stack->stackSize ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; /* stack overflow */ + } + + stack->top->u.i = val; + stack->top->type = CF2_NumberInt; + stack->top++; + } + + + FT_LOCAL_DEF( void ) + cf2_stack_pushFixed( CF2_Stack stack, + CF2_Fixed val ) + { + if ( stack->top == stack->buffer + stack->stackSize ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; /* stack overflow */ + } + + stack->top->u.r = val; + stack->top->type = CF2_NumberFixed; + stack->top++; + } + + + /* this function is only allowed to pop an integer type */ + FT_LOCAL_DEF( CF2_Int ) + cf2_stack_popInt( CF2_Stack stack ) + { + if ( stack->top == stack->buffer ) + { + CF2_SET_ERROR( stack->error, Stack_Underflow ); + return 0; /* underflow */ + } + if ( stack->top[-1].type != CF2_NumberInt ) + { + CF2_SET_ERROR( stack->error, Syntax_Error ); + return 0; /* type mismatch */ + } + + stack->top--; + + return stack->top->u.i; + } + + + /* Note: type mismatch is silently cast */ + /* TODO: check this */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_stack_popFixed( CF2_Stack stack ) + { + if ( stack->top == stack->buffer ) + { + CF2_SET_ERROR( stack->error, Stack_Underflow ); + return cf2_intToFixed( 0 ); /* underflow */ + } + + stack->top--; + + switch ( stack->top->type ) + { + case CF2_NumberInt: + return cf2_intToFixed( stack->top->u.i ); + case CF2_NumberFrac: + return cf2_fracToFixed( stack->top->u.f ); + default: + return stack->top->u.r; + } + } + + + /* Note: type mismatch is silently cast */ + /* TODO: check this */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_stack_getReal( CF2_Stack stack, + CF2_UInt idx ) + { + FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize ); + + if ( idx >= cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return cf2_intToFixed( 0 ); /* bounds error */ + } + + switch ( stack->buffer[idx].type ) + { + case CF2_NumberInt: + return cf2_intToFixed( stack->buffer[idx].u.i ); + case CF2_NumberFrac: + return cf2_fracToFixed( stack->buffer[idx].u.f ); + default: + return stack->buffer[idx].u.r; + } + } + + + /* provide random access to stack */ + FT_LOCAL_DEF( void ) + cf2_stack_setReal( CF2_Stack stack, + CF2_UInt idx, + CF2_Fixed val ) + { + if ( idx > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; + } + + stack->buffer[idx].u.r = val; + stack->buffer[idx].type = CF2_NumberFixed; + } + + + /* discard (pop) num values from stack */ + FT_LOCAL_DEF( void ) + cf2_stack_pop( CF2_Stack stack, + CF2_UInt num ) + { + if ( num > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Underflow ); + return; + } + stack->top -= num; + } + + + FT_LOCAL_DEF( void ) + cf2_stack_roll( CF2_Stack stack, + CF2_Int count, + CF2_Int shift ) + { + /* we initialize this variable to avoid compiler warnings */ + CF2_StackNumber last = { { 0 }, CF2_NumberInt }; + + CF2_Int start_idx, idx, i; + + + if ( count < 2 ) + return; /* nothing to do (values 0 and 1), or undefined value */ + + if ( (CF2_UInt)count > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; + } + + /* before C99 it is implementation-defined whether */ + /* the result of `%' is negative if the first operand */ + /* is negative */ + if ( shift < 0 ) + shift = -( ( -shift ) % count ); + else + shift %= count; + + if ( shift == 0 ) + return; /* nothing to do */ + + /* We use the following algorithm to do the rolling, */ + /* which needs two temporary variables only. */ + /* */ + /* Example: */ + /* */ + /* count = 8 */ + /* shift = 2 */ + /* */ + /* stack indices before roll: 7 6 5 4 3 2 1 0 */ + /* stack indices after roll: 1 0 7 6 5 4 3 2 */ + /* */ + /* The value of index 0 gets moved to index 2, while */ + /* the old value of index 2 gets moved to index 4, */ + /* and so on. We thus have the following copying */ + /* chains for shift value 2. */ + /* */ + /* 0 -> 2 -> 4 -> 6 -> 0 */ + /* 1 -> 3 -> 5 -> 7 -> 1 */ + /* */ + /* If `count' and `shift' are incommensurable, we */ + /* have a single chain only. Otherwise, increase */ + /* the start index by 1 after the first chain, then */ + /* do the next chain until all elements in all */ + /* chains are handled. */ + + start_idx = -1; + idx = -1; + for ( i = 0; i < count; i++ ) + { + CF2_StackNumber tmp; + + + if ( start_idx == idx ) + { + start_idx++; + idx = start_idx; + last = stack->buffer[idx]; + } + + idx += shift; + if ( idx >= count ) + idx -= count; + else if ( idx < 0 ) + idx += count; + + tmp = stack->buffer[idx]; + stack->buffer[idx] = last; + last = tmp; + } + } + + + FT_LOCAL_DEF( void ) + cf2_stack_clear( CF2_Stack stack ) + { + stack->top = stack->buffer; + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/psstack.h b/vendor/freetype/src/psaux/psstack.h new file mode 100644 index 0000000..907b424 --- /dev/null +++ b/vendor/freetype/src/psaux/psstack.h @@ -0,0 +1,122 @@ +/**************************************************************************** + * + * psstack.h + * + * Adobe's code for emulating a CFF stack (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSSTACK_H_ +#define PSSTACK_H_ + +#include + +FT_BEGIN_HEADER + + + /* CFF operand stack; specified maximum of 48 or 192 values */ + typedef struct CF2_StackNumber_ + { + union + { + CF2_Fixed r; /* 16.16 fixed-point */ + CF2_Frac f; /* 2.30 fixed-point (for font matrix) */ + CF2_Int i; + } u; + + CF2_NumberType type; + + } CF2_StackNumber; + + + typedef struct CF2_StackRec_ + { + FT_Memory memory; + FT_Error* error; + CF2_StackNumber* buffer; + CF2_StackNumber* top; + FT_UInt stackSize; + + } CF2_StackRec, *CF2_Stack; + + + FT_LOCAL( CF2_Stack ) + cf2_stack_init( FT_Memory memory, + FT_Error* error, + FT_UInt stackSize ); + FT_LOCAL( void ) + cf2_stack_free( CF2_Stack stack ); + + FT_LOCAL( CF2_UInt ) + cf2_stack_count( CF2_Stack stack ); + + FT_LOCAL( void ) + cf2_stack_pushInt( CF2_Stack stack, + CF2_Int val ); + FT_LOCAL( void ) + cf2_stack_pushFixed( CF2_Stack stack, + CF2_Fixed val ); + + FT_LOCAL( CF2_Int ) + cf2_stack_popInt( CF2_Stack stack ); + FT_LOCAL( CF2_Fixed ) + cf2_stack_popFixed( CF2_Stack stack ); + + FT_LOCAL( CF2_Fixed ) + cf2_stack_getReal( CF2_Stack stack, + CF2_UInt idx ); + FT_LOCAL( void ) + cf2_stack_setReal( CF2_Stack stack, + CF2_UInt idx, + CF2_Fixed val ); + + FT_LOCAL( void ) + cf2_stack_pop( CF2_Stack stack, + CF2_UInt num ); + + FT_LOCAL( void ) + cf2_stack_roll( CF2_Stack stack, + CF2_Int count, + CF2_Int idx ); + + FT_LOCAL( void ) + cf2_stack_clear( CF2_Stack stack ); + + +FT_END_HEADER + + +#endif /* PSSTACK_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/pstypes.h b/vendor/freetype/src/psaux/pstypes.h new file mode 100644 index 0000000..435ef7e --- /dev/null +++ b/vendor/freetype/src/psaux/pstypes.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * pstypes.h + * + * Adobe's code for defining data types (specification only). + * + * Copyright 2011-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSTYPES_H_ +#define PSTYPES_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * The data models that we expect to support are as follows: + * + * name char short int long long-long pointer example + * ----------------------------------------------------- + * ILP32 8 16 32 32 64* 32 32-bit MacOS, x86 + * LLP64 8 16 32 32 64 64 x64 + * LP64 8 16 32 64 64 64 64-bit MacOS + * + * *) type may be supported by emulation on a 32-bit architecture + * + */ + + + /* integers at least 32 bits wide */ +#define CF2_UInt FT_UFast +#define CF2_Int FT_Fast + + + /* fixed-float numbers */ + typedef FT_Int32 CF2_F16Dot16; + + +FT_END_HEADER + + +#endif /* PSTYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/rules.mk b/vendor/freetype/src/psaux/rules.mk new file mode 100644 index 0000000..d542ab8 --- /dev/null +++ b/vendor/freetype/src/psaux/rules.mk @@ -0,0 +1,89 @@ +# +# FreeType 2 PSaux driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# PSAUX driver directory +# +PSAUX_DIR := $(SRC_DIR)/psaux + + +# compilation flags for the driver +# +PSAUX_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(PSAUX_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# PSAUX driver sources (i.e., C files) +# +PSAUX_DRV_SRC := $(PSAUX_DIR)/psobjs.c \ + $(PSAUX_DIR)/t1decode.c \ + $(PSAUX_DIR)/t1cmap.c \ + $(PSAUX_DIR)/afmparse.c \ + $(PSAUX_DIR)/psconv.c \ + $(PSAUX_DIR)/psauxmod.c \ + $(PSAUX_DIR)/psarrst.c \ + $(PSAUX_DIR)/psblues.c \ + $(PSAUX_DIR)/pserror.c \ + $(PSAUX_DIR)/psfont.c \ + $(PSAUX_DIR)/psft.c \ + $(PSAUX_DIR)/pshints.c \ + $(PSAUX_DIR)/psintrp.c \ + $(PSAUX_DIR)/psread.c \ + $(PSAUX_DIR)/psstack.c \ + $(PSAUX_DIR)/cffdecode.c + +# PSAUX driver headers +# +PSAUX_DRV_H := $(PSAUX_DRV_SRC:%c=%h) \ + $(PSAUX_DIR)/psauxerr.h \ + $(PSAUX_DIR)/psfixed.h \ + $(PSAUX_DIR)/psglue.h \ + $(PSAUX_DIR)/pstypes.h + + +# PSAUX driver object(s) +# +# PSAUX_DRV_OBJ_M is used during `multi' builds. +# PSAUX_DRV_OBJ_S is used during `single' builds. +# +PSAUX_DRV_OBJ_M := $(PSAUX_DRV_SRC:$(PSAUX_DIR)/%.c=$(OBJ_DIR)/%.$O) +PSAUX_DRV_OBJ_S := $(OBJ_DIR)/psaux.$O + +# PSAUX driver source file for single build +# +PSAUX_DRV_SRC_S := $(PSAUX_DIR)/psaux.c + + +# PSAUX driver - single object +# +$(PSAUX_DRV_OBJ_S): $(PSAUX_DRV_SRC_S) $(PSAUX_DRV_SRC) \ + $(FREETYPE_H) $(PSAUX_DRV_H) + $(PSAUX_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(PSAUX_DRV_SRC_S)) + + +# PSAUX driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(PSAUX_DIR)/%.c $(FREETYPE_H) $(PSAUX_DRV_H) + $(PSAUX_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(PSAUX_DRV_OBJ_S) +DRV_OBJS_M += $(PSAUX_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/psaux/t1cmap.c b/vendor/freetype/src/psaux/t1cmap.c new file mode 100644 index 0000000..c4bcf59 --- /dev/null +++ b/vendor/freetype/src/psaux/t1cmap.c @@ -0,0 +1,393 @@ +/**************************************************************************** + * + * t1cmap.c + * + * Type 1 character map support (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1cmap.h" + +#include + +#include "psauxerr.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t1_cmap_std_init( T1_CMapStd cmap, + FT_Int is_expert ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + cmap->num_glyphs = (FT_UInt)face->type1.num_glyphs; + cmap->glyph_names = (const char* const*)face->type1.glyph_names; + cmap->sid_to_string = psnames->adobe_std_strings; + cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding + : psnames->adobe_std_encoding; + + FT_ASSERT( cmap->code_to_sid ); + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_std_done( FT_CMap cmap_ ) /* T1_CMapStd */ + { + T1_CMapStd cmap = (T1_CMapStd)cmap_; + + + cmap->num_glyphs = 0; + cmap->glyph_names = NULL; + cmap->sid_to_string = NULL; + cmap->code_to_sid = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_index( FT_CMap cmap, /* T1_CMapStd */ + FT_UInt32 char_code ) + { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; + FT_UInt result = 0; + + + if ( char_code < 256 ) + { + FT_UInt code, n; + const char* glyph_name; + + + /* convert character code to Adobe SID string */ + code = t1cmap->code_to_sid[char_code]; + glyph_name = t1cmap->sid_to_string( code ); + + /* look for the corresponding glyph name */ + for ( n = 0; n < t1cmap->num_glyphs; n++ ) + { + const char* gname = t1cmap->glyph_names[n]; + + + if ( gname && gname[0] == glyph_name[0] && + ft_strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + while ( char_code < 256 ) + { + result = t1_cmap_std_char_index( cmap, char_code ); + if ( result != 0 ) + goto Exit; + + char_code++; + } + char_code = 0; + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_standard_init( FT_CMap cmap, /* T1_CMapStd */ + FT_Pointer pointer ) + { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; + FT_UNUSED( pointer ); + + + t1_cmap_std_init( t1cmap, 0 ); + return 0; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_standard_class_rec = + { + sizeof ( T1_CMapStdRec ), + + (FT_CMap_InitFunc) t1_cmap_standard_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_std_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_expert_init( FT_CMap cmap, /* T1_CMapStd */ + FT_Pointer pointer ) + { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; + FT_UNUSED( pointer ); + + + t1_cmap_std_init( t1cmap, 1 ); + return 0; + } + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_expert_class_rec = + { + sizeof ( T1_CMapStdRec ), + + (FT_CMap_InitFunc) t1_cmap_expert_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_std_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CUSTOM ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_custom_init( FT_CMap cmap, /* T1_CMapCustom */ + FT_Pointer pointer ) + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + T1_Encoding encoding = &face->type1.encoding; + + FT_UNUSED( pointer ); + + + t1cmap->first = (FT_UInt)encoding->code_first; + t1cmap->count = (FT_UInt)encoding->code_last - t1cmap->first; + t1cmap->indices = encoding->char_index; + + FT_ASSERT( t1cmap->indices ); + FT_ASSERT( encoding->code_first <= encoding->code_last ); + + return 0; + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_custom_done( FT_CMap cmap ) /* T1_CMapCustom */ + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + + + t1cmap->indices = NULL; + t1cmap->first = 0; + t1cmap->count = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_index( FT_CMap cmap, /* T1_CMapCustom */ + FT_UInt32 char_code ) + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + FT_UInt result = 0; + + + if ( char_code >= t1cmap->first && + char_code < ( t1cmap->first + t1cmap->count ) ) + result = t1cmap->indices[char_code]; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_next( FT_CMap cmap, /* T1_CMapCustom */ + FT_UInt32 *pchar_code ) + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + + + char_code++; + + if ( char_code < t1cmap->first ) + char_code = t1cmap->first; + + for ( ; char_code < ( t1cmap->first + t1cmap->count ); char_code++ ) + { + result = t1cmap->indices[char_code]; + if ( result != 0 ) + goto Exit; + } + + char_code = 0; + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_custom_class_rec = + { + sizeof ( T1_CMapCustomRec ), + + (FT_CMap_InitFunc) t1_cmap_custom_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_custom_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_custom_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( const char * ) + psaux_get_glyph_name( void* face_, + FT_UInt idx ) + { + T1_Face face = (T1_Face)face_; + + + return face->type1.glyph_names[idx]; + } + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + FT_UNUSED( pointer ); + + + if ( !psnames->unicodes_init ) + return FT_THROW( Unimplemented_Feature ); + + return psnames->unicodes_init( memory, + unicodes, + (FT_UInt)face->type1.num_glyphs, + &psaux_get_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_unicode_class_rec = + { + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) t1_cmap_unicode_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_unicode_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + +/* END */ diff --git a/vendor/freetype/src/psaux/t1cmap.h b/vendor/freetype/src/psaux/t1cmap.h new file mode 100644 index 0000000..b370249 --- /dev/null +++ b/vendor/freetype/src/psaux/t1cmap.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * t1cmap.h + * + * Type 1 character map support (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1CMAP_H_ +#define T1CMAP_H_ + +#include +#include + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* standard (and expert) encoding cmaps */ + typedef struct T1_CMapStdRec_* T1_CMapStd; + + typedef struct T1_CMapStdRec_ + { + FT_CMapRec cmap; + + const FT_UShort* code_to_sid; + PS_Adobe_Std_StringsFunc sid_to_string; + + FT_UInt num_glyphs; + const char* const* glyph_names; + + } T1_CMapStdRec; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_standard_class_rec; + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_expert_class_rec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CUSTOM ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct T1_CMapCustomRec_* T1_CMapCustom; + + typedef struct T1_CMapCustomRec_ + { + FT_CMapRec cmap; + FT_UInt first; + FT_UInt count; + FT_UShort* indices; + + } T1_CMapCustomRec; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_custom_class_rec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* unicode (synthetic) cmaps */ + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_unicode_class_rec; + + /* */ + + +FT_END_HEADER + +#endif /* T1CMAP_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psaux/t1decode.c b/vendor/freetype/src/psaux/t1decode.c new file mode 100644 index 0000000..4b6b969 --- /dev/null +++ b/vendor/freetype/src/psaux/t1decode.c @@ -0,0 +1,2159 @@ +/**************************************************************************** + * + * t1decode.c + * + * PostScript Type 1 decoding routines (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "t1decode.h" +#include "psobjs.h" + +#include "psauxerr.h" + + +/* ensure proper sign extension */ +#define Fix2Int( f ) ( (FT_Int) (FT_Short)( (f) >> 16 ) ) +#define Fix2UInt( f ) ( (FT_UInt)(FT_Short)( (f) >> 16 ) ) + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1decode + + + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + op_unknown15, + + op_max /* never remove this one */ + + } T1_Operator; + + + static + const FT_Int t1_args_count[op_max] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2, /* setcurrentpoint */ + 2 /* opcode 15 (undocumented and obsolete) */ + }; + + + /************************************************************************** + * + * @Function: + * t1_lookup_glyph_by_stdcharcode_ps + * + * @Description: + * Looks up a given glyph by its StandardEncoding charcode. Used to + * implement the SEAC Type 1 operator in the Adobe engine + * + * @Input: + * face :: + * The current face object. + * + * charcode :: + * The character code to look for. + * + * @Return: + * A glyph index in the font face. Returns -1 if the corresponding + * glyph wasn't found. + */ + FT_LOCAL_DEF( FT_Int ) + t1_lookup_glyph_by_stdcharcode_ps( PS_Decoder* decoder, + FT_Int charcode ) + { + FT_UInt n; + const FT_String* glyph_name; + FT_Service_PsCMaps psnames = decoder->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < decoder->num_glyphs; n++ ) + { + FT_String* name = (FT_String*)decoder->glyph_names[n]; + + + if ( name && + name[0] == glyph_name[0] && + ft_strcmp( name, glyph_name ) == 0 ) + return (FT_Int)n; + } + + return -1; + } + + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + + /************************************************************************** + * + * @Function: + * t1_lookup_glyph_by_stdcharcode + * + * @Description: + * Looks up a given glyph by its StandardEncoding charcode. Used to + * implement the SEAC Type 1 operator. + * + * @Input: + * face :: + * The current face object. + * + * charcode :: + * The character code to look for. + * + * @Return: + * A glyph index in the font face. Returns -1 if the corresponding + * glyph wasn't found. + */ + static FT_Int + t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder, + FT_Int charcode ) + { + FT_UInt n; + const FT_String* glyph_name; + FT_Service_PsCMaps psnames = decoder->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < decoder->num_glyphs; n++ ) + { + FT_String* name = (FT_String*)decoder->glyph_names[n]; + + + if ( name && + name[0] == glyph_name[0] && + ft_strcmp( name, glyph_name ) == 0 ) + return (FT_Int)n; + } + + return -1; + } + + + /* parse a single Type 1 glyph */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph ) + { + return decoder->parse_callback( decoder, glyph ); + } + + + /************************************************************************** + * + * @Function: + * t1operator_seac + * + * @Description: + * Implements the `seac' Type 1 operator for a Type 1 decoder. + * + * @Input: + * decoder :: + * The current CID decoder. + * + * asb :: + * The accent's side bearing. + * + * adx :: + * The horizontal offset of the accent. + * + * ady :: + * The vertical offset of the accent. + * + * bchar :: + * The base character's StandardEncoding charcode. + * + * achar :: + * The accent character's StandardEncoding charcode. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + t1operator_seac( T1_Decoder decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index; +#if 0 + FT_Int n_base_points; + FT_Outline* base = decoder->builder.base; +#endif + FT_Vector left_bearing, advance; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + T1_Face face = (T1_Face)decoder->builder.face; +#endif + + + if ( decoder->seac ) + { + FT_ERROR(( "t1operator_seac: invalid nested seac\n" )); + return FT_THROW( Syntax_Error ); + } + + if ( decoder->builder.metrics_only ) + { + FT_ERROR(( "t1operator_seac: unexpected seac\n" )); + return FT_THROW( Syntax_Error ); + } + + /* seac weirdness */ + adx += decoder->builder.left_bearing.x; + + /* `glyph_names' is set to 0 for CID fonts which do not */ + /* include an encoding. How can we deal with these? */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( decoder->glyph_names == 0 && + !face->root.internal->incremental_interface ) +#else + if ( decoder->glyph_names == 0 ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ERROR(( "t1operator_seac:" + " glyph names table not available in this font\n" )); + return FT_THROW( Syntax_Error ); + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( face->root.internal->incremental_interface ) + { + /* the caller must handle the font encoding also */ + bchar_index = bchar; + achar_index = achar; + } + else +#endif + { + bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar ); + achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar ); + } + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" + " invalid seac character code arguments\n" )); + return FT_THROW( Syntax_Error ); + } + + /* if we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)FIXED_TO_INT( adx - asb ); + subg->arg2 = (FT_Int)FIXED_TO_INT( ady ); + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + goto Exit; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ + + /* save the left bearing and width of the SEAC */ + /* glyph as they will be erased by the next load */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = t1_decoder_parse_glyph( decoder, (FT_UInt)bchar_index ); + decoder->seac = FALSE; + if ( error ) + goto Exit; + + /* If the SEAC glyph doesn't have a (H)SBW of its */ + /* own use the values from the base glyph. */ + + if ( decoder->builder.parse_state != T1_Parse_Have_Width ) + { + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + } + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + decoder->builder.pos_x = adx - asb; + decoder->builder.pos_y = ady; + + /* Now load `achar' on top of */ + /* the base outline */ + + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = t1_decoder_parse_glyph( decoder, (FT_UInt)achar_index ); + decoder->seac = FALSE; + if ( error ) + goto Exit; + + /* restore the left side bearing and advance width */ + /* of the SEAC glyph or base character (saved above) */ + + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + decoder->builder.pos_x = 0; + decoder->builder.pos_y = 0; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * t1_decoder_parse_charstrings + * + * @Description: + * Parses a given Type 1 charstrings program. + * + * @Input: + * decoder :: + * The current Type 1 decoder. + * + * charstring_base :: + * The base address of the charstring stream. + * + * charstring_len :: + * The length in bytes of the charstring stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ) + { + FT_Error error; + T1_Decoder_Zone zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder builder = &decoder->builder; + FT_Pos x, y, orig_x, orig_y; + FT_Int known_othersubr_result_cnt = 0; + FT_Int unknown_othersubr_result_cnt = 0; + FT_Bool large_int; + FT_Fixed seed; + + T1_Hints_Funcs hinter; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool bol = TRUE; +#endif + + + /* compute random seed from stack address of parameter */ + seed = (FT_Fixed)( ( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&decoder ^ + (FT_Offset)(char*)&charstring_base ) & + FT_ULONG_MAX ); + seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL; + if ( seed == 0 ) + seed = 0x7384; + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->parse_state = T1_Parse_Start; + + hinter = (T1_Hints_Funcs)builder->hints_funcs; + + /* a font that reads BuildCharArray without setting */ + /* its values first is buggy, but ... */ + FT_ASSERT( ( decoder->len_buildchar == 0 ) == + ( decoder->buildchar == NULL ) ); + + if ( decoder->buildchar && decoder->len_buildchar > 0 ) + FT_ARRAY_ZERO( decoder->buildchar, decoder->len_buildchar ); + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = FT_Err_Ok; + + x = orig_x = builder->pos_x; + y = orig_y = builder->pos_y; + + /* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); + + large_int = FALSE; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Long* top = decoder->top; + T1_Operator op = op_none; + FT_Int32 value = 0; + + + FT_ASSERT( known_othersubr_result_cnt == 0 || + unknown_othersubr_result_cnt == 0 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( bol ) + { + FT_TRACE5(( " (%td)", decoder->top - decoder->stack )); + bol = FALSE; + } +#endif + + /********************************************************************** + * + * Decode operator or operand + * + */ + + /* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; + + case 15: /* undocumented, obsolete operator */ + op = op_unknown15; + break; + + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + + case 12: + if ( ip >= limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + + default: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) | + ( (FT_UInt32)ip[1] << 16 ) | + ( (FT_UInt32)ip[2] << 8 ) | + (FT_UInt32)ip[3] ); + ip += 4; + + /* According to the specification, values > 32000 or < -32000 must */ + /* be followed by a `div' operator to make the result be in the */ + /* range [-32000;32000]. We expect that the second argument of */ + /* `div' is not a large number. Additionally, we don't handle */ + /* stuff like ` div div' or */ + /* div div'. This is probably not allowed */ + /* anyway. */ + if ( value > 32000 || value < -32000 ) + { + if ( large_int ) + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no `div' after large integer\n" )); + else + large_int = TRUE; + } + else + { + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Int32)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( ( ip[-2] - 247 ) * 256 ) + ip[-1] + 108; + else + value = -( ( ( ip[-2] - 251 ) * 256 ) + ip[-1] + 108 ); + } + + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + else + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid byte (%d)\n", ip[-1] )); + goto Syntax_Error; + } + } + + if ( unknown_othersubr_result_cnt > 0 ) + { + switch ( op ) + { + case op_callsubr: + case op_return: + case op_none: + case op_pop: + break; + + default: + /* all operands have been transferred by previous pops */ + unknown_othersubr_result_cnt = 0; + break; + } + } + + if ( large_int && !( op == op_none || op == op_div ) ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no `div' after large integer\n" )); + + large_int = FALSE; + } + + /********************************************************************** + * + * Push value on stack, or process operator + * + */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow\n" )); + goto Syntax_Error; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( large_int ) + FT_TRACE4(( " %d", value )); + else + FT_TRACE4(( " %d", value / 65536 )); +#endif + + *top++ = value; + decoder->top = top; + } + else if ( op == op_callothersubr ) /* callothersubr */ + { + FT_Int subr_no; + FT_Int arg_cnt; + + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " callothersubr\n" )); + bol = TRUE; +#endif + + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + + subr_no = Fix2Int( top[1] ); + arg_cnt = Fix2Int( top[0] ); + + /************************************************************ + * + * remove all operands to callothersubr from the stack + * + * for handled othersubrs, where we know the number of + * arguments, we increase the stack by the value of + * known_othersubr_result_cnt + * + * for unhandled othersubrs the following pops adjust the + * stack pointer as necessary + */ + + if ( arg_cnt > top - decoder->stack ) + goto Stack_Underflow; + + top -= arg_cnt; + + known_othersubr_result_cnt = 0; + unknown_othersubr_result_cnt = 0; + + /* XXX TODO: The checks to `arg_count == ' */ + /* might not be correct; an othersubr expects a certain */ + /* number of operands on the PostScript stack (as opposed */ + /* to the T1 stack) but it doesn't have to put them there */ + /* by itself; previous othersubrs might have left the */ + /* operands there if they were not followed by an */ + /* appropriate number of pops */ + /* */ + /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */ + /* accept a font that contains charstrings like */ + /* */ + /* 100 200 2 20 callothersubr */ + /* 300 1 20 callothersubr pop */ + /* */ + /* Perhaps this is the reason why BuildCharArray exists. */ + + switch ( subr_no ) + { + case 0: /* end flex feature */ + if ( arg_cnt != 3 ) + goto Unexpected_OtherSubr; + + if ( !decoder->flex_state || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected flex end\n" )); + goto Syntax_Error; + } + + /* the two `results' are popped by the following setcurrentpoint */ + top[0] = x; + top[1] = y; + known_othersubr_result_cnt = 2; + break; + + case 1: /* start flex feature */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 6 ) ) ) + goto Fail; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + break; + + case 2: /* add flex vectors */ + { + FT_Int idx; + + + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( !decoder->flex_state ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " missing flex start\n" )); + goto Syntax_Error; + } + + /* note that we should not add a point for index 0; */ + /* this will move our current position to the flex */ + /* point without adding any point to the outline */ + idx = decoder->num_flex_vectors++; + if ( idx > 0 && idx < 7 ) + { + /* in malformed fonts it is possible to have other */ + /* opcodes in the middle of a flex (which don't */ + /* increase `num_flex_vectors'); we thus have to */ + /* check whether we can add a point */ + if ( FT_SET_ERROR( t1_builder_check_points( builder, 1 ) ) ) + goto Syntax_Error; + + t1_builder_add_point( builder, + x, + y, + (FT_Byte)( idx == 3 || idx == 6 ) ); + } + } + break; + + case 3: /* change hints */ + if ( arg_cnt != 1 ) + goto Unexpected_OtherSubr; + + known_othersubr_result_cnt = 1; + + if ( hinter ) + hinter->reset( hinter->hints, + (FT_UInt)builder->current->n_points ); + break; + + case 12: + case 13: + /* counter control hints, clear stack */ + top = decoder->stack; + break; + + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + PS_Blend blend = decoder->blend; + FT_UInt num_points, nn, mm; + FT_Long* delta; + FT_Long* values; + + + if ( !blend ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected multiple masters operator\n" )); + goto Syntax_Error; + } + + num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 ); + if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " incorrect number of multiple masters arguments\n" )); + goto Syntax_Error; + } + + /* We want to compute */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have a0, a1-a0, a2-a0, ..., ak-a0. */ + /* */ + /* However, given that w0 + w1 + ... + wk == 1, we can */ + /* rewrite it easily as */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1. */ + /* */ + /* I guess that's why it's written in this `compact' */ + /* form. */ + /* */ + delta = top + num_points; + values = top; + for ( nn = 0; nn < num_points; nn++ ) + { + FT_Long tmp = values[0]; + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + tmp = ADD_LONG( tmp, + FT_MulFix( *delta++, + blend->weight_vector[mm] ) ); + + *values++ = tmp; + } + + known_othersubr_result_cnt = (FT_Int)num_points; + break; + } + + case 19: + /* 1 19 callothersubr */ + /* => replace elements starting from index cvi( ) */ + /* of BuildCharArray with WeightVector */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = Fix2Int( top[0] ); + + if ( idx < 0 || + (FT_UInt)idx + blend->num_designs > decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + ft_memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof ( blend->weight_vector[0] ) ); + } + break; + + case 20: + /* 2 20 callothersubr pop */ + /* ==> push + onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] = ADD_LONG( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 21: + /* 2 21 callothersubr pop */ + /* ==> push - onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] = SUB_LONG( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 22: + /* 2 22 callothersubr pop */ + /* ==> push * onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] = FT_MulFix( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 23: + /* 2 23 callothersubr pop */ + /* ==> push / onto T1 stack */ + if ( arg_cnt != 2 || top[1] == 0 ) + goto Unexpected_OtherSubr; + + top[0] = FT_DivFix( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 24: + /* 2 24 callothersubr */ + /* ==> set BuildCharArray[cvi( )] = */ + { + FT_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 2 || !blend ) + goto Unexpected_OtherSubr; + + idx = Fix2UInt( top[1] ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + decoder->buildchar[idx] = top[0]; + } + break; + + case 25: + /* 1 25 callothersubr pop */ + /* ==> push BuildCharArray[cvi( idx )] */ + /* onto T1 stack */ + { + FT_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = Fix2UInt( top[0] ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + top[0] = decoder->buildchar[idx]; + } + + known_othersubr_result_cnt = 1; + break; + +#if 0 + case 26: + /* mark ==> set BuildCharArray[cvi( )] = , */ + /* leave mark on T1 stack */ + /* ==> set BuildCharArray[cvi( )] = */ + XXX which routine has left its mark on the (PostScript) stack?; + break; +#endif + + case 27: + /* 4 27 callothersubr pop */ + /* ==> push onto T1 stack if <= , */ + /* otherwise push */ + if ( arg_cnt != 4 ) + goto Unexpected_OtherSubr; + + if ( top[2] > top[3] ) + top[0] = top[1]; + + known_othersubr_result_cnt = 1; + break; + + case 28: + /* 0 28 callothersubr pop */ + /* => push random value from interval [0, 1) onto stack */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + { + FT_Fixed Rand; + + + Rand = seed; + if ( Rand >= 0x8000L ) + Rand++; + + top[0] = Rand; + + seed = FT_MulFix( seed, 0x10000L - seed ); + if ( seed == 0 ) + seed += 0x2873; + } + + known_othersubr_result_cnt = 1; + break; + + default: + if ( arg_cnt >= 0 && subr_no >= 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unknown othersubr [%d %d], wish me luck\n", + arg_cnt, subr_no )); + unknown_othersubr_result_cnt = arg_cnt; + break; + } + /* fall through */ + + Unexpected_OtherSubr: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid othersubr [%d %d]\n", arg_cnt, subr_no )); + goto Syntax_Error; + } + + top += known_othersubr_result_cnt; + + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + FT_ASSERT( num_args >= 0 ); + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + /* XXX Operators usually take their operands from the */ + /* bottom of the stack, i.e., the operands are */ + /* decoder->stack[0], ..., decoder->stack[num_args - 1]; */ + /* only div, callsubr, and callothersubr are different. */ + /* In practice it doesn't matter (?). */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + switch ( op ) + { + case op_callsubr: + case op_div: + case op_callothersubr: + case op_pop: + case op_return: + break; + + default: + if ( top - decoder->stack != num_args ) + FT_TRACE0(( "t1_decoder_parse_charstrings:" + " too much operands on the stack" + " (seen %td, expected %d)\n", + top - decoder->stack, num_args )); + break; + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + top -= num_args; + + switch ( op ) + { + case op_endchar: + FT_TRACE4(( " endchar\n" )); + + t1_builder_close_contour( builder ); + + /* close hints recording session */ + if ( hinter ) + { + if ( hinter->close( hinter->hints, + (FT_UInt)builder->current->n_points ) ) + goto Syntax_Error; + + /* apply hints to the loaded glyph outline now */ + error = hinter->apply( hinter->hints, + builder->current, + (PSH_Globals)builder->hints_globals, + decoder->hint_mode ); + if ( error ) + goto Fail; + } + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* the compiler should optimize away this empty loop but ... */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + if ( decoder->len_buildchar > 0 ) + { + FT_UInt i; + + + FT_TRACE4(( "BuildCharArray = [ " )); + + for ( i = 0; i < decoder->len_buildchar; i++ ) + FT_TRACE4(( "%ld ", decoder->buildchar[i] )); + + FT_TRACE4(( "]\n" )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + FT_TRACE4(( "\n" )); + + /* return now! */ + return FT_Err_Ok; + + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + + builder->advance.x = top[1]; + builder->advance.y = 0; + + orig_x = x = ADD_LONG( builder->pos_x, top[0] ); + orig_y = y = builder->pos_y; + + FT_UNUSED( orig_y ); + + /* `metrics_only' indicates that we only want to compute the */ + /* glyph's metrics (lsb + advance width) without loading the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + { + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + } + + break; + + case op_seac: + return t1operator_seac( decoder, + top[0], + top[1], + top[2], + Fix2Int( top[3] ), + Fix2Int( top[4] ) ); + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + builder->left_bearing.y = ADD_LONG( builder->left_bearing.y, + top[1] ); + + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + x = ADD_LONG( builder->pos_x, top[0] ); + y = ADD_LONG( builder->pos_y, top[1] ); + + /* `metrics_only' indicates that we only want to compute the */ + /* glyph's metrics (lsb + advance width) without loading the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + { + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + } + + break; + + case op_closepath: + FT_TRACE4(( " closepath" )); + + /* if there is no path, `closepath' is a no-op */ + if ( builder->parse_state == T1_Parse_Have_Path || + builder->parse_state == T1_Parse_Have_Moveto ) + t1_builder_close_contour( builder ); + + builder->parse_state = T1_Parse_Have_Width; + break; + + case op_hlineto: + FT_TRACE4(( " hlineto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + goto Add_Line; + + case op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + x = ADD_LONG( x, top[0] ); + + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_hvcurveto: + FT_TRACE4(( " hvcurveto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 3 ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[1] ); + y = ADD_LONG( y, top[2] ); + t1_builder_add_point( builder, x, y, 0 ); + + y = ADD_LONG( y, top[3] ); + t1_builder_add_point( builder, x, y, 1 ); + break; + + case op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + y = ADD_LONG( y, top[1] ); + + Add_Line: + if ( FT_SET_ERROR( t1_builder_add_point1( builder, x, y ) ) ) + goto Fail; + break; + + case op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + x = ADD_LONG( x, top[0] ); + y = ADD_LONG( y, top[1] ); + + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_rrcurveto: + FT_TRACE4(( " rrcurveto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 3 ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + y = ADD_LONG( y, top[1] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[2] ); + y = ADD_LONG( y, top[3] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[4] ); + y = ADD_LONG( y, top[5] ); + t1_builder_add_point( builder, x, y, 1 ); + break; + + case op_vhcurveto: + FT_TRACE4(( " vhcurveto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 3 ) ) ) + goto Fail; + + y = ADD_LONG( y, top[0] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[1] ); + y = ADD_LONG( y, top[2] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[3] ); + t1_builder_add_point( builder, x, y, 1 ); + break; + + case op_vlineto: + FT_TRACE4(( " vlineto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) ) + goto Fail; + + y = ADD_LONG( y, top[0] ); + goto Add_Line; + + case op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + y = ADD_LONG( y, top[0] ); + + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_div: + FT_TRACE4(( " div" )); + + /* if `large_int' is set, we divide unscaled numbers; */ + /* otherwise, we divide numbers in 16.16 format -- */ + /* in both cases, it is the same operation */ + *top = FT_DivFix( top[0], top[1] ); + top++; + + large_int = FALSE; + break; + + case op_callsubr: + { + FT_Int idx; + + + FT_TRACE4(( " callsubr" )); + + idx = Fix2Int( top[0] ); + + if ( decoder->subrs_hash ) + { + size_t* val = ft_hash_num_lookup( idx, + decoder->subrs_hash ); + + + if ( val ) + idx = *val; + else + idx = -1; + } + + if ( idx < 0 || idx >= decoder->num_subrs ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + + /* The Type 1 driver stores subroutines without the seed bytes. */ + /* The CID driver stores subroutines with seed bytes. This */ + /* case is taken care of when decoder->subrs_len == 0. */ + zone->base = decoder->subrs[idx]; + + if ( decoder->subrs_len ) + zone->limit = zone->base + decoder->subrs_len[idx]; + else + { + /* We are using subroutines from a CID font. We must adjust */ + /* for the seed bytes. */ + zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + zone->limit = decoder->subrs[idx + 1]; + } + + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_pop: + FT_TRACE4(( " pop" )); + + if ( known_othersubr_result_cnt > 0 ) + { + known_othersubr_result_cnt--; + /* ignore, we pushed the operands ourselves */ + break; + } + + if ( unknown_othersubr_result_cnt == 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no more operands for othersubr\n" )); + goto Syntax_Error; + } + + unknown_othersubr_result_cnt--; + top++; /* `push' the operand to callothersubr onto the stack */ + break; + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + case op_dotsection: + FT_TRACE4(( " dotsection" )); + + break; + + case op_hstem: + FT_TRACE4(( " hstem" )); + + /* record horizontal hint */ + if ( hinter ) + { + /* top[0] += builder->left_bearing.y; */ + hinter->stem( hinter->hints, 1, top ); + } + break; + + case op_hstem3: + FT_TRACE4(( " hstem3" )); + + /* record horizontal counter-controlled hints */ + if ( hinter ) + hinter->stem3( hinter->hints, 1, top ); + break; + + case op_vstem: + FT_TRACE4(( " vstem" )); + + /* record vertical hint */ + if ( hinter ) + { + top[0] = ADD_LONG( top[0], orig_x ); + hinter->stem( hinter->hints, 0, top ); + } + break; + + case op_vstem3: + FT_TRACE4(( " vstem3" )); + + /* record vertical counter-controlled hints */ + if ( hinter ) + { + FT_Pos dx = orig_x; + + + top[0] = ADD_LONG( top[0], dx ); + top[2] = ADD_LONG( top[2], dx ); + top[4] = ADD_LONG( top[4], dx ); + hinter->stem3( hinter->hints, 0, top ); + } + break; + + case op_setcurrentpoint: + FT_TRACE4(( " setcurrentpoint" )); + + /* From the T1 specification, section 6.4: */ + /* */ + /* The setcurrentpoint command is used only in */ + /* conjunction with results from OtherSubrs procedures. */ + + /* known_othersubr_result_cnt != 0 is already handled */ + /* above. */ + + /* Note, however, that both Ghostscript and Adobe */ + /* Distiller handle this situation by silently ignoring */ + /* the inappropriate `setcurrentpoint' instruction. So */ + /* we do the same. */ +#if 0 + + if ( decoder->flex_state != 1 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + } + else + ... +#endif + + x = top[0]; + y = top[1]; + decoder->flex_state = 0; + break; + + case op_unknown15: + FT_TRACE4(( " opcode_15" )); + /* nothing to do except to pop the two arguments */ + break; + + default: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + /* XXX Operators usually clear the operand stack; */ + /* only div, callsubr, callothersubr, pop, and */ + /* return are different. */ + /* In practice it doesn't matter (?). */ + + decoder->top = top; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( "\n" )); + bol = TRUE; +#endif + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); + + Fail: + return error; + + Syntax_Error: + return FT_THROW( Syntax_Error ); + + Stack_Underflow: + return FT_THROW( Stack_Underflow ); + } + + +#else /* !T1_CONFIG_OPTION_OLD_ENGINE */ + + + /************************************************************************** + * + * @Function: + * t1_decoder_parse_metrics + * + * @Description: + * Parses a given Type 1 charstrings program to extract width + * + * @Input: + * decoder :: + * The current Type 1 decoder. + * + * charstring_base :: + * The base address of the charstring stream. + * + * charstring_len :: + * The length in bytes of the charstring stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_metrics( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ) + { + T1_Decoder_Zone zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder builder = &decoder->builder; + FT_Bool large_int; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool bol = TRUE; +#endif + + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->parse_state = T1_Parse_Start; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + large_int = FALSE; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Long* top = decoder->top; + T1_Operator op = op_none; + FT_Int32 value = 0; + + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( bol ) + { + FT_TRACE5(( " (%ld)", decoder->top - decoder->stack )); + bol = FALSE; + } +#endif + + /********************************************************************** + * + * Decode operator or operand + * + */ + + /* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 14: + case 15: + case 21: + case 22: + case 30: + case 31: + goto No_Width; + + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + + case 12: + if ( ip >= limit ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + + default: + goto No_Width; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) | + ( (FT_UInt32)ip[1] << 16 ) | + ( (FT_UInt32)ip[2] << 8 ) | + (FT_UInt32)ip[3] ); + ip += 4; + + /* According to the specification, values > 32000 or < -32000 must */ + /* be followed by a `div' operator to make the result be in the */ + /* range [-32000;32000]. We expect that the second argument of */ + /* `div' is not a large number. Additionally, we don't handle */ + /* stuff like ` div div' or */ + /* div div'. This is probably not allowed */ + /* anyway. */ + if ( value > 32000 || value < -32000 ) + { + if ( large_int ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " no `div' after large integer\n" )); + goto Syntax_Error; + } + else + large_int = TRUE; + } + else + { + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Int32)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( ( ip[-2] - 247 ) * 256 ) + ip[-1] + 108; + else + value = -( ( ( ip[-2] - 251 ) * 256 ) + ip[-1] + 108 ); + } + + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + else + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invalid byte (%d)\n", ip[-1] )); + goto Syntax_Error; + } + } + + if ( large_int && !( op == op_none || op == op_div ) ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " no `div' after large integer\n" )); + goto Syntax_Error; + } + + /********************************************************************** + * + * Push value on stack, or process operator + * + */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "t1_decoder_parse_metrics: stack overflow\n" )); + goto Syntax_Error; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( large_int ) + FT_TRACE4(( " %d", value )); + else + FT_TRACE4(( " %d", value / 65536 )); +#endif + + *top++ = value; + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + FT_ASSERT( num_args >= 0 ); + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + +#ifdef FT_DEBUG_LEVEL_TRACE + + switch ( op ) + { + case op_callsubr: + case op_div: + case op_return: + break; + + default: + if ( top - decoder->stack != num_args ) + FT_TRACE0(( "t1_decoder_parse_metrics:" + " too much operands on the stack" + " (seen %ld, expected %d)\n", + top - decoder->stack, num_args )); + break; + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + top -= num_args; + + switch ( op ) + { + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + + builder->advance.x = top[1]; + builder->advance.y = 0; + + /* we only want to compute the glyph's metrics */ + /* (lsb + advance width) without loading the */ + /* rest of it; so exit immediately */ + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + builder->left_bearing.y = ADD_LONG( builder->left_bearing.y, + top[1] ); + + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + /* we only want to compute the glyph's metrics */ + /* (lsb + advance width), without loading the */ + /* rest of it; so exit immediately */ + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + + case op_div: + FT_TRACE4(( " div" )); + + /* if `large_int' is set, we divide unscaled numbers; */ + /* otherwise, we divide numbers in 16.16 format -- */ + /* in both cases, it is the same operation */ + *top = FT_DivFix( top[0], top[1] ); + top++; + + large_int = FALSE; + break; + + case op_callsubr: + { + FT_Int idx; + + + FT_TRACE4(( " callsubr" )); + + idx = Fix2Int( top[0] ); + + if ( decoder->subrs_hash ) + { + size_t* val = ft_hash_num_lookup( idx, + decoder->subrs_hash ); + + + if ( val ) + idx = *val; + else + idx = -1; + } + + if ( idx < 0 || idx >= decoder->num_subrs ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + + /* The Type 1 driver stores subroutines without the seed bytes. */ + /* The CID driver stores subroutines with seed bytes. This */ + /* case is taken care of when decoder->subrs_len == 0. */ + zone->base = decoder->subrs[idx]; + + if ( decoder->subrs_len ) + zone->limit = zone->base + decoder->subrs_len[idx]; + else + { + /* We are using subroutines from a CID font. We must adjust */ + /* for the seed bytes. */ + zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + zone->limit = decoder->subrs[idx + 1]; + } + + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + default: + FT_ERROR(( "t1_decoder_parse_metrics:" + " unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); + + No_Width: + FT_ERROR(( "t1_decoder_parse_metrics:" + " no width, found op %d instead\n", + ip[-1] )); + Syntax_Error: + return FT_THROW( Syntax_Error ); + + Stack_Underflow: + return FT_THROW( Stack_Underflow ); + } + +#endif /* !T1_CONFIG_OPTION_OLD_ENGINE */ + + + /* initialize T1 decoder */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_callback ) + { + FT_ZERO( decoder ); + + /* retrieve `psnames' interface from list of current modules */ + { + FT_Service_PsCMaps psnames; + + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + { + FT_ERROR(( "t1_decoder_init:" + " the `psnames' module is not available\n" )); + return FT_THROW( Unimplemented_Feature ); + } + + decoder->psnames = psnames; + } + + t1_builder_init( &decoder->builder, face, size, slot, hinting ); + + /* decoder->buildchar and decoder->len_buildchar have to be */ + /* initialized by the caller since we cannot know the length */ + /* of the BuildCharArray */ + + decoder->num_glyphs = (FT_UInt)face->num_glyphs; + decoder->glyph_names = glyph_names; + decoder->hint_mode = hint_mode; + decoder->blend = blend; + decoder->parse_callback = parse_callback; + + decoder->funcs = t1_decoder_funcs; + + return FT_Err_Ok; + } + + + /* finalize T1 decoder */ + FT_LOCAL_DEF( void ) + t1_decoder_done( T1_Decoder decoder ) + { + FT_Memory memory = decoder->builder.memory; + + + t1_builder_done( &decoder->builder ); + + if ( decoder->cf2_instance.finalizer ) + { + decoder->cf2_instance.finalizer( decoder->cf2_instance.data ); + FT_FREE( decoder->cf2_instance.data ); + } + } + + +/* END */ diff --git a/vendor/freetype/src/psaux/t1decode.h b/vendor/freetype/src/psaux/t1decode.h new file mode 100644 index 0000000..0970def --- /dev/null +++ b/vendor/freetype/src/psaux/t1decode.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * + * t1decode.h + * + * PostScript Type 1 decoding routines (specification). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1DECODE_H_ +#define T1DECODE_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_CALLBACK_TABLE + const T1_Decoder_FuncsRec t1_decoder_funcs; + + FT_LOCAL( FT_Int ) + t1_lookup_glyph_by_stdcharcode_ps( PS_Decoder* decoder, + FT_Int charcode ); + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + FT_LOCAL( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph_index ); + + FT_LOCAL( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); +#else + FT_LOCAL( FT_Error ) + t1_decoder_parse_metrics( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ); +#endif + + FT_LOCAL( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_glyph ); + + FT_LOCAL( void ) + t1_decoder_done( T1_Decoder decoder ); + + +FT_END_HEADER + +#endif /* T1DECODE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pshinter/module.mk b/vendor/freetype/src/pshinter/module.mk new file mode 100644 index 0000000..dbc137d --- /dev/null +++ b/vendor/freetype/src/pshinter/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 PSHinter module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += PSHINTER_MODULE + +define PSHINTER_MODULE +$(OPEN_DRIVER) FT_Module_Class, pshinter_module_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)pshinter $(ECHO_DRIVER_DESC)Postscript hinter module$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/pshinter/pshalgo.c b/vendor/freetype/src/pshinter/pshalgo.c new file mode 100644 index 0000000..4f622e1 --- /dev/null +++ b/vendor/freetype/src/pshinter/pshalgo.c @@ -0,0 +1,2191 @@ +/**************************************************************************** + * + * pshalgo.c + * + * PostScript hinting algorithm (body). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "pshalgo.h" + +#include "pshnterr.h" + + +#undef FT_COMPONENT +#define FT_COMPONENT pshalgo + + +#ifdef DEBUG_HINTER + PSH_Hint_Table ps_debug_hint_table = NULL; + PSH_HintFunc ps_debug_hint_func = NULL; + PSH_Glyph ps_debug_glyph = NULL; +#endif + + +#define COMPUTE_INFLEXS /* compute inflection points to optimize `S' */ + /* and similar glyphs */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC HINTS RECORDINGS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* return true if two stem hints overlap */ + static FT_Int + psh_hint_overlap( PSH_Hint hint1, + PSH_Hint hint2 ) + { + return ADD_INT( hint1->org_pos, hint1->org_len ) >= hint2->org_pos && + ADD_INT( hint2->org_pos, hint2->org_len ) >= hint1->org_pos; + } + + + /* destroy hints table */ + static void + psh_hint_table_done( PSH_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->zones ); + table->num_zones = 0; + table->zone = NULL; + + FT_FREE( table->sort ); + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + table->sort_global = NULL; + } + + + /* deactivate all hints in a table */ + static void + psh_hint_table_deactivate( PSH_Hint_Table table ) + { + FT_UInt count = table->max_hints; + PSH_Hint hint = table->hints; + + + for ( ; count > 0; count--, hint++ ) + { + psh_hint_deactivate( hint ); + hint->order = -1; + } + } + + + /* internal function to record a new hint */ + static void + psh_hint_table_record( PSH_Hint_Table table, + FT_UInt idx ) + { + PSH_Hint hint = table->hints + idx; + + + if ( idx >= table->max_hints ) + { + FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx )); + return; + } + + /* ignore active hints */ + if ( psh_hint_is_active( hint ) ) + return; + + psh_hint_activate( hint ); + + /* now scan the current active hint set to check */ + /* whether `hint' overlaps with another hint */ + { + PSH_Hint* sorted = table->sort_global; + FT_UInt count = table->num_hints; + PSH_Hint hint2; + + + hint->parent = NULL; + for ( ; count > 0; count--, sorted++ ) + { + hint2 = sorted[0]; + + if ( psh_hint_overlap( hint, hint2 ) ) + { + hint->parent = hint2; + break; + } + } + } + + if ( table->num_hints < table->max_hints ) + table->sort_global[table->num_hints++] = hint; + else + FT_TRACE0(( "psh_hint_table_record: too many sorted hints! BUG!\n" )); + } + + + static void + psh_hint_table_record_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit; + + + limit = hint_mask->num_bits; + + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + + if ( val & mask ) + psh_hint_table_record( table, idx ); + + mask >>= 1; + } + } + + + /* create hints table */ + static FT_Error + psh_hint_table_init( PSH_Hint_Table table, + PS_Hint_Table hints, + PS_Mask_Table hint_masks, + PS_Mask_Table counter_masks, + FT_Memory memory ) + { + FT_UInt count; + FT_Error error; + + FT_UNUSED( counter_masks ); + + + count = hints->num_hints; + + /* allocate our tables */ + if ( FT_QNEW_ARRAY( table->sort, 2 * count ) || + FT_QNEW_ARRAY( table->hints, count ) || + FT_QNEW_ARRAY( table->zones, 2 * count + 1 ) ) + goto Exit; + + table->max_hints = count; + table->sort_global = FT_OFFSET( table->sort, count ); + table->num_hints = 0; + table->num_zones = 0; + table->zone = NULL; + + /* initialize the `table->hints' array */ + { + PSH_Hint write = table->hints; + PS_Hint read = hints->hints; + + + for ( ; count > 0; count--, write++, read++ ) + { + write->org_pos = read->pos; + write->org_len = read->len; + write->flags = read->flags; + } + } + + /* we now need to determine the initial `parent' stems; first */ + /* activate the hints that are given by the initial hint masks */ + if ( hint_masks ) + { + PS_Mask mask = hint_masks->masks; + + + count = hint_masks->num_masks; + table->hint_masks = hint_masks; + + for ( ; count > 0; count--, mask++ ) + psh_hint_table_record_mask( table, mask ); + } + + /* finally, do a linear parse in case some hints were left alone */ + if ( table->num_hints != table->max_hints ) + { + FT_UInt idx; + + + FT_TRACE0(( "psh_hint_table_init: missing/incorrect hint masks\n" )); + + count = table->max_hints; + for ( idx = 0; idx < count; idx++ ) + psh_hint_table_record( table, idx ); + } + + Exit: + return error; + } + + + static void + psh_hint_table_activate_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit, count; + + + limit = hint_mask->num_bits; + count = 0; + + psh_hint_table_deactivate( table ); + + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + + if ( val & mask ) + { + PSH_Hint hint = &table->hints[idx]; + + + if ( !psh_hint_is_active( hint ) ) + { + FT_UInt count2; + +#if 0 + PSH_Hint* sort = table->sort; + PSH_Hint hint2; + + + for ( count2 = count; count2 > 0; count2--, sort++ ) + { + hint2 = sort[0]; + if ( psh_hint_overlap( hint, hint2 ) ) + FT_TRACE0(( "psh_hint_table_activate_mask:" + " found overlapping hints\n" )) + } +#else + count2 = 0; +#endif + + if ( count2 == 0 ) + { + psh_hint_activate( hint ); + if ( count < table->max_hints ) + table->sort[count++] = hint; + else + FT_TRACE0(( "psh_hint_tableactivate_mask:" + " too many active hints\n" )); + } + } + } + + mask >>= 1; + } + table->num_hints = count; + + /* now, sort the hints; they are guaranteed to not overlap */ + /* so we can compare their "org_pos" field directly */ + { + FT_UInt i1, i2; + PSH_Hint hint1, hint2; + PSH_Hint* sort = table->sort; + + + /* a simple bubble sort will do, since in 99% of cases, the hints */ + /* will be already sorted -- and the sort will be linear */ + for ( i1 = 1; i1 < count; i1++ ) + { + hint1 = sort[i1]; + /* this loop stops when i2 wraps around after reaching 0 */ + for ( i2 = i1 - 1; i2 < i1; i2-- ) + { + hint2 = sort[i2]; + + if ( hint2->org_pos < hint1->org_pos ) + break; + + sort[i2 + 1] = hint2; + sort[i2] = hint1; + } + } + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HINTS GRID-FITTING AND OPTIMIZATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 1 + static FT_Pos + psh_dimension_quantize_len( PSH_Dimension dim, + FT_Pos len, + FT_Bool do_snapping ) + { + if ( len <= 64 ) + len = 64; + else + { + FT_Pos delta = len - dim->stdw.widths[0].cur; + + + if ( delta < 0 ) + delta = -delta; + + if ( delta < 40 ) + { + len = dim->stdw.widths[0].cur; + if ( len < 48 ) + len = 48; + } + + if ( len < 3 * 64 ) + { + delta = ( len & 63 ); + len &= -64; + + if ( delta < 10 ) + len += delta; + + else if ( delta < 32 ) + len += 10; + + else if ( delta < 54 ) + len += 54; + + else + len += delta; + } + else + len = FT_PIX_ROUND( len ); + } + + if ( do_snapping ) + len = FT_PIX_ROUND( len ); + + return len; + } +#endif /* 0 */ + + +#ifdef DEBUG_HINTER + + static void + ps_simple_scale( PSH_Hint_Table table, + FT_Fixed scale, + FT_Fixed delta, + FT_Int dimension ) + { + FT_UInt count; + + + for ( count = 0; count < table->max_hints; count++ ) + { + PSH_Hint hint = table->hints + count; + + + hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta; + hint->cur_len = FT_MulFix( hint->org_len, scale ); + + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); + } + } + +#endif /* DEBUG_HINTER */ + + + static FT_Fixed + psh_hint_snap_stem_side_delta( FT_Fixed pos, + FT_Fixed len ) + { + FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos; + FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len; + + + if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) ) + return delta1; + else + return delta2; + } + + + static void + psh_hint_align( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + + FT_Int do_snapping; + FT_Pos fit_len; + PSH_AlignmentRec align; + + + /* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + + psh_hint_set_fitted( hint ); + return; + } + + /* perform stem snapping when requested - this is necessary + * for monochrome and LCD hinting modes only + */ + do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) || + ( dimension == 1 && glyph->do_vert_snapping ); + + hint->cur_len = fit_len = len; + + /* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + ADD_INT( hint->org_pos, hint->org_len ), + hint->org_pos, + &align ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + /* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + + case PSH_BLUE_ALIGN_BOT: + /* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: + /* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + + default: + { + PSH_Hint parent = hint->parent; + + + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; + + + /* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align( parent, globals, dimension, glyph ); + + /* keep original relation between hints, that is, use the */ + /* scaled distance between the centers of the hints to */ + /* compute the new position */ + par_org_center = parent->org_pos + ( parent->org_len >> 1 ); + par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 ); + cur_org_center = hint->org_pos + ( hint->org_len >> 1 ); + + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + + hint->cur_pos = pos; + hint->cur_len = fit_len; + + /* Stem adjustment tries to snap stem widths to standard + * ones. This is important to prevent unpleasant rounding + * artefacts. + */ + if ( glyph->do_stem_adjust ) + { + if ( len <= 64 ) + { + /* the stem is less than one pixel; we will center it + * around the nearest pixel center + */ + if ( len >= 32 ) + { + /* This is a special case where we also widen the stem + * and align it to the pixel grid. + * + * stem_center = pos + (len/2) + * nearest_pixel_center = FT_ROUND(stem_center-32)+32 + * new_pos = nearest_pixel_center-32 + * = FT_ROUND(stem_center-32) + * = FT_FLOOR(stem_center-32+32) + * = FT_FLOOR(stem_center) + * new_len = 64 + */ + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ); + len = 64; + } + else if ( len > 0 ) + { + /* This is a very small stem; we simply align it to the + * pixel grid, trying to find the minimum displacement. + * + * left = pos + * right = pos + len + * left_nearest_edge = ROUND(pos) + * right_nearest_edge = ROUND(right) + * + * if ( ABS(left_nearest_edge - left) <= + * ABS(right_nearest_edge - right) ) + * new_pos = left + * else + * new_pos = right + */ + FT_Pos left_nearest = FT_PIX_ROUND( pos ); + FT_Pos right_nearest = FT_PIX_ROUND( pos + len ); + FT_Pos left_disp = left_nearest - pos; + FT_Pos right_disp = right_nearest - ( pos + len ); + + + if ( left_disp < 0 ) + left_disp = -left_disp; + if ( right_disp < 0 ) + right_disp = -right_disp; + if ( left_disp <= right_disp ) + pos = left_nearest; + else + pos = right_nearest; + } + else + { + /* this is a ghost stem; we simply round it */ + pos = FT_PIX_ROUND( pos ); + } + } + else + { + len = psh_dimension_quantize_len( dim, len, 0 ); + } + } + + /* now that we have a good hinted stem width, try to position */ + /* the stem along a pixel grid integer coordinate */ + hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len ); + hint->cur_len = len; + } + } + + if ( do_snapping ) + { + pos = hint->cur_pos; + len = hint->cur_len; + + if ( len < 64 ) + len = 64; + else + len = FT_PIX_ROUND( len ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + hint->cur_pos = align.align_top - len; + hint->cur_len = len; + break; + + case PSH_BLUE_ALIGN_BOT: + hint->cur_len = len; + break; + + case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP: + /* don't touch */ + break; + + + default: + hint->cur_len = len; + if ( len & 64 ) + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32; + else + pos = FT_PIX_ROUND( pos + ( len >> 1 ) ); + + hint->cur_pos = pos - ( len >> 1 ); + hint->cur_len = len; + } + } + + psh_hint_set_fitted( hint ); + +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } + + +#if 0 /* not used for now, experimental */ + + /* + * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT) + * of stems + */ + static void + psh_hint_align_light( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + + FT_Pos fit_len; + + PSH_AlignmentRec align; + + + /* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + + psh_hint_set_fitted( hint ); + return; + } + + fit_len = len; + + hint->cur_len = fit_len; + + /* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + ADD_INT( hint->org_pos, hint->org_len ), + hint->org_pos, + &align ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + /* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + + case PSH_BLUE_ALIGN_BOT: + /* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: + /* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + + default: + { + PSH_Hint parent = hint->parent; + + + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; + + + /* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align_light( parent, globals, dimension, glyph ); + + par_org_center = parent->org_pos + ( parent->org_len / 2 ); + par_cur_center = parent->cur_pos + ( parent->cur_len / 2 ); + cur_org_center = hint->org_pos + ( hint->org_len / 2 ); + + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + + /* Stems less than one pixel wide are easy -- we want to + * make them as dark as possible, so they must fall within + * one pixel. If the stem is split between two pixels + * then snap the edge that is nearer to the pixel boundary + * to the pixel boundary. + */ + if ( len <= 64 ) + { + if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 ) + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } + + /* Position stems other to minimize the amount of mid-grays. + * There are, in general, two positions that do this, + * illustrated as A) and B) below. + * + * + + + + + * + * A) |--------------------------------| + * B) |--------------------------------| + * C) |--------------------------------| + * + * Position A) (split the excess stem equally) should be better + * for stems of width N + f where f < 0.5. + * + * Position B) (split the deficiency equally) should be better + * for stems of width N + f where f > 0.5. + * + * It turns out though that minimizing the total number of lit + * pixels is also important, so position C), with one edge + * aligned with a pixel boundary is actually preferable + * to A). There are also more possible positions for C) than + * for A) or B), so it involves less distortion of the overall + * character shape. + */ + else /* len > 64 */ + { + FT_Fixed frac_len = len & 63; + FT_Fixed center = pos + ( len >> 1 ); + FT_Fixed delta_a, delta_b; + + + if ( ( len / 64 ) & 1 ) + { + delta_a = FT_PIX_FLOOR( center ) + 32 - center; + delta_b = FT_PIX_ROUND( center ) - center; + } + else + { + delta_a = FT_PIX_ROUND( center ) - center; + delta_b = FT_PIX_FLOOR( center ) + 32 - center; + } + + /* We choose between B) and C) above based on the amount + * of fractional stem width; for small amounts, choose + * C) always, for large amounts, B) always, and inbetween, + * pick whichever one involves less stem movement. + */ + if ( frac_len < 32 ) + { + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } + else if ( frac_len < 48 ) + { + FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos, + len ); + + if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) ) + pos += side_delta; + else + pos += delta_b; + } + else + { + pos += delta_b; + } + } + + hint->cur_pos = pos; + } + } /* switch */ + + psh_hint_set_fitted( hint ); + +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } + +#endif /* 0 */ + + + static void + psh_hint_table_align_hints( PSH_Hint_Table table, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Hint hint; + FT_UInt count; + +#ifdef DEBUG_HINTER + + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( ps_debug_no_vert_hints && dimension == 0 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } + + if ( ps_debug_no_horz_hints && dimension == 1 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } + +#endif /* DEBUG_HINTER */ + + hint = table->hints; + count = table->max_hints; + + for ( ; count > 0; count--, hint++ ) + psh_hint_align( hint, globals, dimension, glyph ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** POINTS INTERPOLATION ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define xxDEBUG_ZONES + + +#ifdef DEBUG_ZONES + +#include FT_CONFIG_STANDARD_LIBRARY_H + + static void + psh_print_zone( PSH_Zone zone ) + { + printf( "zone [scale,delta,min,max] = [%.5f,%.2f,%d,%d]\n", + zone->scale / 65536.0, + zone->delta / 64.0, + zone->min, + zone->max ); + } + +#endif /* DEBUG_ZONES */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HINTER GLYPH MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define psh_corner_is_flat ft_corner_is_flat +#define psh_corner_orientation ft_corner_orientation + + +#ifdef COMPUTE_INFLEXS + + /* compute all inflex points in a given glyph */ + static void + psh_glyph_compute_inflections( PSH_Glyph glyph ) + { + FT_UInt n; + + + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first, start, end, before, after; + FT_Pos in_x, in_y, out_x, out_y; + FT_Int orient_prev, orient_cur; + FT_Int finished = 0; + + + /* we need at least 4 points to create an inflection point */ + if ( glyph->contours[n].count < 4 ) + continue; + + /* compute first segment in contour */ + first = glyph->contours[n].start; + + start = end = first; + do + { + end = end->next; + if ( end == first ) + goto Skip; + + in_x = end->org_u - start->org_u; + in_y = end->org_v - start->org_v; + + } while ( in_x == 0 && in_y == 0 ); + + /* extend the segment start whenever possible */ + before = start; + do + { + do + { + start = before; + before = before->prev; + if ( before == first ) + goto Skip; + + out_x = start->org_u - before->org_u; + out_y = start->org_v - before->org_v; + + } while ( out_x == 0 && out_y == 0 ); + + orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y ); + + } while ( orient_prev == 0 ); + + first = start; + in_x = out_x; + in_y = out_y; + + /* now, process all segments in the contour */ + do + { + /* first, extend current segment's end whenever possible */ + after = end; + do + { + do + { + end = after; + after = after->next; + if ( after == first ) + finished = 1; + + out_x = after->org_u - end->org_u; + out_y = after->org_v - end->org_v; + + } while ( out_x == 0 && out_y == 0 ); + + orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y ); + + } while ( orient_cur == 0 ); + + if ( ( orient_cur ^ orient_prev ) < 0 ) + { + do + { + psh_point_set_inflex( start ); + start = start->next; + } + while ( start != end ); + + psh_point_set_inflex( start ); + } + + start = end; + end = after; + orient_prev = orient_cur; + in_x = out_x; + in_y = out_y; + + } while ( !finished ); + + Skip: + ; + } + } + +#endif /* COMPUTE_INFLEXS */ + + + static void + psh_glyph_done( PSH_Glyph glyph ) + { + FT_Memory memory = glyph->memory; + + + psh_hint_table_done( &glyph->hint_tables[1], memory ); + psh_hint_table_done( &glyph->hint_tables[0], memory ); + + FT_FREE( glyph->points ); + FT_FREE( glyph->contours ); + + glyph->num_points = 0; + glyph->num_contours = 0; + + glyph->memory = NULL; + } + + + static PSH_Dir + psh_compute_dir( FT_Pos dx, + FT_Pos dy ) + { + FT_Pos ax, ay; + PSH_Dir result = PSH_DIR_NONE; + + + ax = FT_ABS( dx ); + ay = FT_ABS( dy ); + + if ( ay * 12 < ax ) + { + /* |dy| <<< |dx| means a near-horizontal segment */ + result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT; + } + else if ( ax * 12 < ay ) + { + /* |dx| <<< |dy| means a near-vertical segment */ + result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN; + } + + return result; + } + + + /* load outline point coordinates into hinter glyph */ + static void + psh_glyph_load_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_Vector* vec = glyph->outline->points; + PSH_Point point = glyph->points; + FT_UInt count = glyph->num_points; + + + for ( ; count > 0; count--, point++, vec++ ) + { + point->flags2 = 0; + point->hint = NULL; + if ( dimension == 0 ) + { + point->org_u = vec->x; + point->org_v = vec->y; + } + else + { + point->org_u = vec->y; + point->org_v = vec->x; + } + +#ifdef DEBUG_HINTER + point->org_x = vec->x; + point->org_y = vec->y; +#endif + + } + } + + + /* save hinted point coordinates back to outline */ + static void + psh_glyph_save_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_UInt n; + PSH_Point point = glyph->points; + FT_Vector* vec = glyph->outline->points; + char* tags = glyph->outline->tags; + + + for ( n = 0; n < glyph->num_points; n++ ) + { + if ( dimension == 0 ) + vec[n].x = point->cur_u; + else + vec[n].y = point->cur_u; + + if ( psh_point_is_strong( point ) ) + tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 ); + +#ifdef DEBUG_HINTER + + if ( dimension == 0 ) + { + point->cur_x = point->cur_u; + point->flags_x = point->flags2 | point->flags; + } + else + { + point->cur_y = point->cur_u; + point->flags_y = point->flags2 | point->flags; + } + +#endif + + point++; + } + } + + + static FT_Error + psh_glyph_init( PSH_Glyph glyph, + FT_Outline* outline, + PS_Hints ps_hints, + PSH_Globals globals ) + { + FT_Error error; + FT_Memory memory; + + + /* clear all fields */ + FT_ZERO( glyph ); + + memory = glyph->memory = globals->memory; + + /* allocate and setup points + contours arrays */ + if ( FT_QNEW_ARRAY( glyph->points, outline->n_points ) || + FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) ) + goto Exit; + + glyph->num_points = (FT_UInt)outline->n_points; + glyph->num_contours = (FT_UInt)outline->n_contours; + + { + FT_UInt first = 0, next, n; + PSH_Point points = glyph->points; + PSH_Contour contour = glyph->contours; + + + for ( n = 0; n < glyph->num_contours; n++ ) + { + FT_UInt count; + PSH_Point point; + + + next = (FT_UInt)outline->contours[n] + 1; + count = next - first; + + contour->start = points + first; + contour->count = count; + + if ( count > 0 ) + { + point = points + first; + + point->prev = points + next - 1; + point->contour = contour; + + for ( ; count > 1; count-- ) + { + point[0].next = point + 1; + point[1].prev = point; + point++; + point->contour = contour; + } + point->next = points + first; + } + + contour++; + first = next; + } + } + + { + PSH_Point points = glyph->points; + PSH_Point point = points; + FT_Vector* vec = outline->points; + FT_UInt n; + + + for ( n = 0; n < glyph->num_points; n++, point++ ) + { + FT_Int n_prev = (FT_Int)( point->prev - points ); + FT_Int n_next = (FT_Int)( point->next - points ); + FT_Pos dxi, dyi, dxo, dyo; + + + point->flags = 0; + if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) + psh_point_set_off( point ); + + dxi = vec[n].x - vec[n_prev].x; + dyi = vec[n].y - vec[n_prev].y; + + point->dir_in = psh_compute_dir( dxi, dyi ); + + dxo = vec[n_next].x - vec[n].x; + dyo = vec[n_next].y - vec[n].y; + + point->dir_out = psh_compute_dir( dxo, dyo ); + + /* detect smooth points */ + if ( psh_point_is_off( point ) ) + psh_point_set_smooth( point ); + + else if ( point->dir_in == point->dir_out ) + { + if ( point->dir_out != PSH_DIR_NONE || + psh_corner_is_flat( dxi, dyi, dxo, dyo ) ) + psh_point_set_smooth( point ); + } + } + } + + glyph->outline = outline; + glyph->globals = globals; + +#ifdef COMPUTE_INFLEXS + psh_glyph_load_points( glyph, 0 ); + psh_glyph_compute_inflections( glyph ); +#endif /* COMPUTE_INFLEXS */ + + /* now deal with hints tables */ + error = psh_hint_table_init( &glyph->hint_tables [0], + &ps_hints->dimension[0].hints, + &ps_hints->dimension[0].masks, + &ps_hints->dimension[0].counters, + memory ); + if ( error ) + goto Exit; + + error = psh_hint_table_init( &glyph->hint_tables [1], + &ps_hints->dimension[1].hints, + &ps_hints->dimension[1].masks, + &ps_hints->dimension[1].counters, + memory ); + if ( error ) + goto Exit; + + Exit: + return error; + } + + + /* compute all extrema in a glyph for a given dimension */ + static void + psh_glyph_compute_extrema( PSH_Glyph glyph ) + { + FT_UInt n; + + + /* first of all, compute all local extrema */ + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first = glyph->contours[n].start; + PSH_Point point, before, after; + + + if ( glyph->contours[n].count == 0 ) + continue; + + point = first; + before = point; + + do + { + before = before->prev; + if ( before == first ) + goto Skip; + + } while ( before->org_u == point->org_u ); + + first = point = before->next; + + for (;;) + { + after = point; + do + { + after = after->next; + if ( after == first ) + goto Next; + + } while ( after->org_u == point->org_u ); + + if ( before->org_u < point->org_u ) + { + if ( after->org_u < point->org_u ) + { + /* local maximum */ + goto Extremum; + } + } + else /* before->org_u > point->org_u */ + { + if ( after->org_u > point->org_u ) + { + /* local minimum */ + Extremum: + do + { + psh_point_set_extremum( point ); + point = point->next; + + } while ( point != after ); + } + } + + before = after->prev; + point = after; + + } /* for */ + + Next: + ; + } + + /* for each extremum, determine its direction along the */ + /* orthogonal axis */ + for ( n = 0; n < glyph->num_points; n++ ) + { + PSH_Point point, before, after; + + + point = &glyph->points[n]; + before = point; + after = point; + + if ( psh_point_is_extremum( point ) ) + { + do + { + before = before->prev; + if ( before == point ) + goto Skip; + + } while ( before->org_v == point->org_v ); + + do + { + after = after->next; + if ( after == point ) + goto Skip; + + } while ( after->org_v == point->org_v ); + } + + if ( before->org_v < point->org_v && + after->org_v > point->org_v ) + { + psh_point_set_positive( point ); + } + else if ( before->org_v > point->org_v && + after->org_v < point->org_v ) + { + psh_point_set_negative( point ); + } + + Skip: + ; + } + } + + + /* the min and max are based on contour orientation and fill rule */ + static void + psh_hint_table_find_strong_points( PSH_Hint_Table table, + PSH_Point point, + FT_UInt count, + FT_Int threshold, + PSH_Dir major_dir ) + { + PSH_Hint* sort = table->sort; + FT_UInt num_hints = table->num_hints; + + + for ( ; count > 0; count--, point++ ) + { + PSH_Dir point_dir; + FT_Pos org_u = point->org_u; + + + if ( psh_point_is_strong( point ) ) + continue; + + point_dir = + (PSH_Dir)( ( point->dir_in | point->dir_out ) & major_dir ); + + if ( point_dir & ( PSH_DIR_DOWN | PSH_DIR_RIGHT ) ) + { + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + + + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + break; + } + } + } + else if ( point_dir & ( PSH_DIR_UP | PSH_DIR_LEFT ) ) + { + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + + + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + break; + } + } + } + +#if 1 + else if ( psh_point_is_extremum( point ) ) + { + /* treat extrema as special cases for stem edge alignment */ + FT_UInt nn, min_flag, max_flag; + + + if ( major_dir == PSH_DIR_HORIZONTAL ) + { + min_flag = PSH_POINT_POSITIVE; + max_flag = PSH_POINT_NEGATIVE; + } + else + { + min_flag = PSH_POINT_NEGATIVE; + max_flag = PSH_POINT_POSITIVE; + } + + if ( point->flags2 & min_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + + + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + else if ( point->flags2 & max_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + + + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + + if ( !point->hint ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + + + if ( org_u >= hint->org_pos && + org_u <= ADD_INT( hint->org_pos, hint->org_len ) ) + { + point->hint = hint; + break; + } + } + } + } + +#endif /* 1 */ + } + } + + + /* the accepted shift for strong points in fractional pixels */ +#define PSH_STRONG_THRESHOLD 32 + + /* the maximum shift value in font units tuned to distinguish */ + /* between stems and serifs in URW+ font collection */ +#define PSH_STRONG_THRESHOLD_MAXIMUM 12 + + + /* find strong points in a glyph */ + static void + psh_glyph_find_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { + /* a point is `strong' if it is located on a stem edge and */ + /* has an `in' or `out' tangent parallel to the hint's direction */ + + PSH_Hint_Table table = &glyph->hint_tables[dimension]; + PS_Mask mask = table->hint_masks->masks; + FT_UInt num_masks = table->hint_masks->num_masks; + FT_UInt first = 0; + PSH_Dir major_dir = ( dimension == 0 ) ? PSH_DIR_VERTICAL + : PSH_DIR_HORIZONTAL; + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Int threshold; + + + threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale ); + if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM ) + threshold = PSH_STRONG_THRESHOLD_MAXIMUM; + + /* process secondary hints to `selected' points */ + if ( num_masks > 1 && glyph->num_points > 0 ) + { + /* the `endchar' op can reduce the number of points */ + first = mask->end_point > glyph->num_points + ? glyph->num_points + : mask->end_point; + mask++; + for ( ; num_masks > 1; num_masks--, mask++ ) + { + FT_UInt next = FT_MIN( mask->end_point, glyph->num_points ); + + + if ( next > first ) + { + FT_UInt count = next - first; + PSH_Point point = glyph->points + first; + + + psh_hint_table_activate_mask( table, mask ); + + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } + first = next; + } + } + + /* process primary hints for all points */ + if ( num_masks == 1 ) + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + psh_hint_table_activate_mask( table, table->hint_masks->masks ); + + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } + + /* now, certain points may have been attached to a hint and */ + /* not marked as strong; update their flags then */ + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + for ( ; count > 0; count--, point++ ) + if ( point->hint && !psh_point_is_strong( point ) ) + psh_point_set_strong( point ); + } + } + + + /* find points in a glyph which are in a blue zone and have `in' or */ + /* `out' tangents parallel to the horizontal axis */ + static void + psh_glyph_find_blue_points( PSH_Blues blues, + PSH_Glyph glyph ) + { + PSH_Blue_Table table; + PSH_Blue_Zone zone; + FT_UInt glyph_count = glyph->num_points; + FT_UInt blue_count; + PSH_Point point = glyph->points; + + + for ( ; glyph_count > 0; glyph_count--, point++ ) + { + FT_Pos y; + + + /* check tangents */ + if ( !( point->dir_in & PSH_DIR_HORIZONTAL ) && + !( point->dir_out & PSH_DIR_HORIZONTAL ) ) + continue; + + /* skip strong points */ + if ( psh_point_is_strong( point ) ) + continue; + + y = point->org_u; + + /* look up top zones */ + table = &blues->normal_top; + blue_count = table->count; + zone = table->zones; + + for ( ; blue_count > 0; blue_count--, zone++ ) + { + FT_Pos delta = y - zone->org_bottom; + + + if ( delta < -blues->blue_fuzz ) + break; + + if ( y <= zone->org_top + blues->blue_fuzz ) + if ( blues->no_overshoots || delta <= blues->blue_threshold ) + { + point->cur_u = zone->cur_bottom; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } + + /* look up bottom zones */ + table = &blues->normal_bottom; + blue_count = table->count; + zone = table->zones + blue_count - 1; + + for ( ; blue_count > 0; blue_count--, zone-- ) + { + FT_Pos delta = zone->org_top - y; + + + if ( delta < -blues->blue_fuzz ) + break; + + if ( y >= zone->org_bottom - blues->blue_fuzz ) + if ( blues->no_overshoots || delta < blues->blue_threshold ) + { + point->cur_u = zone->cur_top; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } + } + } + + + /* interpolate strong points with the help of hinted coordinates */ + static void + psh_glyph_interpolate_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + for ( ; count > 0; count--, point++ ) + { + PSH_Hint hint = point->hint; + + + if ( hint ) + { + FT_Pos delta; + + + if ( psh_point_is_edge_min( point ) ) + point->cur_u = hint->cur_pos; + + else if ( psh_point_is_edge_max( point ) ) + point->cur_u = hint->cur_pos + hint->cur_len; + + else + { + delta = point->org_u - hint->org_pos; + + if ( delta <= 0 ) + point->cur_u = hint->cur_pos + FT_MulFix( delta, scale ); + + else if ( delta >= hint->org_len ) + point->cur_u = hint->cur_pos + hint->cur_len + + FT_MulFix( delta - hint->org_len, scale ); + + else /* hint->org_len > 0 */ + point->cur_u = hint->cur_pos + + FT_MulDiv( delta, hint->cur_len, + hint->org_len ); + } + psh_point_set_fitted( point ); + } + } + } + + +#define PSH_MAX_STRONG_INTERNAL 16 + + static void + psh_glyph_interpolate_normal_points( PSH_Glyph glyph, + FT_Int dimension ) + { + +#if 1 + /* first technique: a point is strong if it is a local extremum */ + + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Memory memory = glyph->memory; + + PSH_Point* strongs = NULL; + PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL]; + FT_UInt num_strongs = 0; + + PSH_Point points = glyph->points; + PSH_Point points_end = points + glyph->num_points; + PSH_Point point; + + + /* first count the number of strong points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + num_strongs++; + } + + if ( num_strongs == 0 ) /* nothing to do here */ + return; + + /* allocate an array to store a list of points, */ + /* stored in increasing org_u order */ + if ( num_strongs <= PSH_MAX_STRONG_INTERNAL ) + strongs = strongs_0; + else + { + FT_Error error; + + + if ( FT_QNEW_ARRAY( strongs, num_strongs ) ) + return; + } + + num_strongs = 0; + for ( point = points; point < points_end; point++ ) + { + PSH_Point* insert; + + + if ( !psh_point_is_strong( point ) ) + continue; + + for ( insert = strongs + num_strongs; insert > strongs; insert-- ) + { + if ( insert[-1]->org_u <= point->org_u ) + break; + + insert[0] = insert[-1]; + } + insert[0] = point; + num_strongs++; + } + + /* now try to interpolate all normal points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + continue; + + /* sometimes, some local extrema are smooth points */ + if ( psh_point_is_smooth( point ) ) + { + if ( point->dir_in == PSH_DIR_NONE || + point->dir_in != point->dir_out ) + continue; + + if ( !psh_point_is_extremum( point ) && + !psh_point_is_inflex( point ) ) + continue; + + point->flags &= ~PSH_POINT_SMOOTH; + } + + /* find best enclosing point coordinates then interpolate */ + { + PSH_Point before, after; + FT_UInt nn; + + + for ( nn = 0; nn < num_strongs; nn++ ) + if ( strongs[nn]->org_u > point->org_u ) + break; + + if ( nn == 0 ) /* point before the first strong point */ + { + after = strongs[0]; + + point->cur_u = after->cur_u + + FT_MulFix( point->org_u - after->org_u, + scale ); + } + else + { + before = strongs[nn - 1]; + + for ( nn = num_strongs; nn > 0; nn-- ) + if ( strongs[nn - 1]->org_u < point->org_u ) + break; + + if ( nn == num_strongs ) /* point is after last strong point */ + { + before = strongs[nn - 1]; + + point->cur_u = before->cur_u + + FT_MulFix( point->org_u - before->org_u, + scale ); + } + else + { + FT_Pos u; + + + after = strongs[nn]; + + /* now interpolate point between before and after */ + u = point->org_u; + + if ( u == before->org_u ) + point->cur_u = before->cur_u; + + else if ( u == after->org_u ) + point->cur_u = after->cur_u; + + else + point->cur_u = before->cur_u + + FT_MulDiv( u - before->org_u, + after->cur_u - before->cur_u, + after->org_u - before->org_u ); + } + } + psh_point_set_fitted( point ); + } + } + + if ( strongs != strongs_0 ) + FT_FREE( strongs ); + +#endif /* 1 */ + + } + + + /* interpolate other points */ + static void + psh_glyph_interpolate_other_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + PSH_Contour contour = glyph->contours; + FT_UInt num_contours = glyph->num_contours; + + + for ( ; num_contours > 0; num_contours--, contour++ ) + { + PSH_Point start = contour->start; + PSH_Point first, next, point; + FT_UInt fit_count; + + + /* count the number of strong points in this contour */ + next = start + contour->count; + fit_count = 0; + first = NULL; + + for ( point = start; point < next; point++ ) + if ( psh_point_is_fitted( point ) ) + { + if ( !first ) + first = point; + + fit_count++; + } + + /* if there are less than 2 fitted points in the contour, we */ + /* simply scale and eventually translate the contour points */ + if ( fit_count < 2 ) + { + if ( fit_count == 1 ) + delta = first->cur_u - FT_MulFix( first->org_u, scale ); + + for ( point = start; point < next; point++ ) + if ( point != first ) + point->cur_u = FT_MulFix( point->org_u, scale ) + delta; + + goto Next_Contour; + } + + /* there are more than 2 strong points in this contour; we */ + /* need to interpolate weak points between them */ + start = first; + do + { + /* skip consecutive fitted points */ + for (;;) + { + next = first->next; + if ( next == start ) + goto Next_Contour; + + if ( !psh_point_is_fitted( next ) ) + break; + + first = next; + } + + /* find next fitted point after unfitted one */ + for (;;) + { + next = next->next; + if ( psh_point_is_fitted( next ) ) + break; + } + + /* now interpolate between them */ + { + FT_Pos org_a, org_ab, cur_a, cur_ab; + FT_Pos org_c, org_ac, cur_c; + FT_Fixed scale_ab; + + + if ( first->org_u <= next->org_u ) + { + org_a = first->org_u; + cur_a = first->cur_u; + org_ab = next->org_u - org_a; + cur_ab = next->cur_u - cur_a; + } + else + { + org_a = next->org_u; + cur_a = next->cur_u; + org_ab = first->org_u - org_a; + cur_ab = first->cur_u - cur_a; + } + + scale_ab = 0x10000L; + if ( org_ab > 0 ) + scale_ab = FT_DivFix( cur_ab, org_ab ); + + point = first->next; + do + { + org_c = point->org_u; + org_ac = org_c - org_a; + + if ( org_ac <= 0 ) + { + /* on the left of the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale ); + } + else if ( org_ac >= org_ab ) + { + /* on the right on the interpolation zone */ + cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale ); + } + else + { + /* within the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale_ab ); + } + + point->cur_u = cur_c; + + point = point->next; + + } while ( point != next ); + } + + /* keep going until all points in the contours have been processed */ + first = next; + + } while ( first != start ); + + Next_Contour: + ; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HIGH-LEVEL INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + PSH_GlyphRec glyphrec; + PSH_Glyph glyph = &glyphrec; + FT_Error error; +#ifdef DEBUG_HINTER + FT_Memory memory; +#endif + FT_Int dimension; + + + /* something to do? */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return FT_Err_Ok; + +#ifdef DEBUG_HINTER + + memory = globals->memory; + + if ( ps_debug_glyph ) + { + psh_glyph_done( ps_debug_glyph ); + FT_FREE( ps_debug_glyph ); + } + + if ( FT_NEW( glyph ) ) + return error; + + ps_debug_glyph = glyph; + +#endif /* DEBUG_HINTER */ + + error = psh_glyph_init( glyph, outline, ps_hints, globals ); + if ( error ) + goto Exit; + + /* try to optimize the y_scale so that the top of non-capital letters + * is aligned on a pixel boundary whenever possible + */ + { + PSH_Dimension dim_x = &glyph->globals->dimension[0]; + PSH_Dimension dim_y = &glyph->globals->dimension[1]; + + FT_Fixed x_scale = dim_x->scale_mult; + FT_Fixed y_scale = dim_y->scale_mult; + + FT_Fixed old_x_scale = x_scale; + FT_Fixed old_y_scale = y_scale; + + FT_Fixed scaled = 0; + FT_Fixed fitted = 0; + + FT_Bool rescale = FALSE; + + + if ( globals->blues.normal_top.count ) + { + scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); + fitted = FT_PIX_ROUND( scaled ); + } + + if ( fitted != 0 && scaled != fitted ) + { + rescale = TRUE; + + y_scale = FT_MulDiv( y_scale, fitted, scaled ); + + if ( fitted < scaled ) + x_scale -= x_scale / 50; + + psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 ); + } + + glyph->do_horz_hints = 1; + glyph->do_vert_hints = 1; + + glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD ); + + glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD_V ); + + glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); + + for ( dimension = 0; dimension < 2; dimension++ ) + { + /* load outline coordinates into glyph */ + psh_glyph_load_points( glyph, dimension ); + + /* compute local extrema */ + psh_glyph_compute_extrema( glyph ); + + /* compute aligned stem/hints positions */ + psh_hint_table_align_hints( &glyph->hint_tables[dimension], + glyph->globals, + dimension, + glyph ); + + /* find strong points, align them, then interpolate others */ + psh_glyph_find_strong_points( glyph, dimension ); + if ( dimension == 1 ) + psh_glyph_find_blue_points( &globals->blues, glyph ); + psh_glyph_interpolate_strong_points( glyph, dimension ); + psh_glyph_interpolate_normal_points( glyph, dimension ); + psh_glyph_interpolate_other_points( glyph, dimension ); + + /* save hinted coordinates back to outline */ + psh_glyph_save_points( glyph, dimension ); + + if ( rescale ) + psh_globals_set_scale( glyph->globals, + old_x_scale, old_y_scale, 0, 0 ); + } + } + + Exit: + +#ifndef DEBUG_HINTER + psh_glyph_done( glyph ); +#endif + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshalgo.h b/vendor/freetype/src/pshinter/pshalgo.h new file mode 100644 index 0000000..3f0ba28 --- /dev/null +++ b/vendor/freetype/src/pshinter/pshalgo.h @@ -0,0 +1,233 @@ +/**************************************************************************** + * + * pshalgo.h + * + * PostScript hinting algorithm (specification). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHALGO_H_ +#define PSHALGO_H_ + + +#include "pshrec.h" +#include "pshglob.h" + + +FT_BEGIN_HEADER + + + /* handle to Hint structure */ + typedef struct PSH_HintRec_* PSH_Hint; + + + /* hint bit-flags */ +#define PSH_HINT_GHOST PS_HINT_FLAG_GHOST +#define PSH_HINT_BOTTOM PS_HINT_FLAG_BOTTOM +#define PSH_HINT_ACTIVE 4U +#define PSH_HINT_FITTED 8U + + +#define psh_hint_is_active( x ) ( ( (x)->flags & PSH_HINT_ACTIVE ) != 0 ) +#define psh_hint_is_ghost( x ) ( ( (x)->flags & PSH_HINT_GHOST ) != 0 ) +#define psh_hint_is_fitted( x ) ( ( (x)->flags & PSH_HINT_FITTED ) != 0 ) + +#define psh_hint_activate( x ) (x)->flags |= PSH_HINT_ACTIVE +#define psh_hint_deactivate( x ) (x)->flags &= ~PSH_HINT_ACTIVE +#define psh_hint_set_fitted( x ) (x)->flags |= PSH_HINT_FITTED + + + /* hint structure */ + typedef struct PSH_HintRec_ + { + FT_Int org_pos; + FT_Int org_len; + FT_Pos cur_pos; + FT_Pos cur_len; + FT_UInt flags; + PSH_Hint parent; + FT_Int order; + + } PSH_HintRec; + + + /* this is an interpolation zone used for strong points; */ + /* weak points are interpolated according to their strong */ + /* neighbours */ + typedef struct PSH_ZoneRec_ + { + FT_Fixed scale; + FT_Fixed delta; + FT_Pos min; + FT_Pos max; + + } PSH_ZoneRec, *PSH_Zone; + + + typedef struct PSH_Hint_TableRec_ + { + FT_UInt max_hints; + FT_UInt num_hints; + PSH_Hint hints; + PSH_Hint* sort; + PSH_Hint* sort_global; + FT_UInt num_zones; + PSH_ZoneRec* zones; + PSH_Zone zone; + PS_Mask_Table hint_masks; + PS_Mask_Table counter_masks; + + } PSH_Hint_TableRec, *PSH_Hint_Table; + + + typedef struct PSH_PointRec_* PSH_Point; + typedef struct PSH_ContourRec_* PSH_Contour; + + typedef enum PSH_Dir_ + { + PSH_DIR_NONE = 0, + PSH_DIR_UP = 1, + PSH_DIR_DOWN = 2, + PSH_DIR_VERTICAL = 1 | 2, + PSH_DIR_LEFT = 4, + PSH_DIR_RIGHT = 8, + PSH_DIR_HORIZONTAL = 4 | 8 + + } PSH_Dir; + + + /* the following bit-flags are computed once by the glyph */ + /* analyzer, for both dimensions */ +#define PSH_POINT_OFF 1U /* point is off the curve */ +#define PSH_POINT_SMOOTH 2U /* point is smooth */ +#define PSH_POINT_INFLEX 4U /* point is inflection */ + + +#define psh_point_is_smooth( p ) ( (p)->flags & PSH_POINT_SMOOTH ) +#define psh_point_is_off( p ) ( (p)->flags & PSH_POINT_OFF ) +#define psh_point_is_inflex( p ) ( (p)->flags & PSH_POINT_INFLEX ) + +#define psh_point_set_smooth( p ) (p)->flags |= PSH_POINT_SMOOTH +#define psh_point_set_off( p ) (p)->flags |= PSH_POINT_OFF +#define psh_point_set_inflex( p ) (p)->flags |= PSH_POINT_INFLEX + + + /* the following bit-flags are re-computed for each dimension */ +#define PSH_POINT_STRONG 16U /* point is strong */ +#define PSH_POINT_FITTED 32U /* point is already fitted */ +#define PSH_POINT_EXTREMUM 64U /* point is local extremum */ +#define PSH_POINT_POSITIVE 128U /* extremum has positive contour flow */ +#define PSH_POINT_NEGATIVE 256U /* extremum has negative contour flow */ +#define PSH_POINT_EDGE_MIN 512U /* point is aligned to left/bottom stem edge */ +#define PSH_POINT_EDGE_MAX 1024U /* point is aligned to top/right stem edge */ + + +#define psh_point_is_strong( p ) ( (p)->flags2 & PSH_POINT_STRONG ) +#define psh_point_is_fitted( p ) ( (p)->flags2 & PSH_POINT_FITTED ) +#define psh_point_is_extremum( p ) ( (p)->flags2 & PSH_POINT_EXTREMUM ) +#define psh_point_is_positive( p ) ( (p)->flags2 & PSH_POINT_POSITIVE ) +#define psh_point_is_negative( p ) ( (p)->flags2 & PSH_POINT_NEGATIVE ) +#define psh_point_is_edge_min( p ) ( (p)->flags2 & PSH_POINT_EDGE_MIN ) +#define psh_point_is_edge_max( p ) ( (p)->flags2 & PSH_POINT_EDGE_MAX ) + +#define psh_point_set_strong( p ) (p)->flags2 |= PSH_POINT_STRONG +#define psh_point_set_fitted( p ) (p)->flags2 |= PSH_POINT_FITTED +#define psh_point_set_extremum( p ) (p)->flags2 |= PSH_POINT_EXTREMUM +#define psh_point_set_positive( p ) (p)->flags2 |= PSH_POINT_POSITIVE +#define psh_point_set_negative( p ) (p)->flags2 |= PSH_POINT_NEGATIVE +#define psh_point_set_edge_min( p ) (p)->flags2 |= PSH_POINT_EDGE_MIN +#define psh_point_set_edge_max( p ) (p)->flags2 |= PSH_POINT_EDGE_MAX + + + typedef struct PSH_PointRec_ + { + PSH_Point prev; + PSH_Point next; + PSH_Contour contour; + FT_UInt flags; + FT_UInt flags2; + PSH_Dir dir_in; + PSH_Dir dir_out; + PSH_Hint hint; + FT_Pos org_u; + FT_Pos org_v; + FT_Pos cur_u; +#ifdef DEBUG_HINTER + FT_Pos org_x; + FT_Pos cur_x; + FT_Pos org_y; + FT_Pos cur_y; + FT_UInt flags_x; + FT_UInt flags_y; +#endif + + } PSH_PointRec; + + + typedef struct PSH_ContourRec_ + { + PSH_Point start; + FT_UInt count; + + } PSH_ContourRec; + + + typedef struct PSH_GlyphRec_ + { + FT_UInt num_points; + FT_UInt num_contours; + + PSH_Point points; + PSH_Contour contours; + + FT_Memory memory; + FT_Outline* outline; + PSH_Globals globals; + PSH_Hint_TableRec hint_tables[2]; + + FT_Bool do_horz_hints; + FT_Bool do_vert_hints; + FT_Bool do_horz_snapping; + FT_Bool do_vert_snapping; + FT_Bool do_stem_adjust; + + } PSH_GlyphRec, *PSH_Glyph; + + +#ifdef DEBUG_HINTER + extern PSH_Hint_Table ps_debug_hint_table; + + typedef void + (*PSH_HintFunc)( PSH_Hint hint, + FT_Bool vertical ); + + extern PSH_HintFunc ps_debug_hint_func; + + extern PSH_Glyph ps_debug_glyph; +#endif + + + extern FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + +FT_END_HEADER + + +#endif /* PSHALGO_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshglob.c b/vendor/freetype/src/pshinter/pshglob.c new file mode 100644 index 0000000..d4c5eb3 --- /dev/null +++ b/vendor/freetype/src/pshinter/pshglob.c @@ -0,0 +1,795 @@ +/**************************************************************************** + * + * pshglob.c + * + * PostScript hinter global hinting management (body). + * Inspired by the new auto-hinter module. + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "pshglob.h" + +#ifdef DEBUG_HINTER + PSH_Globals ps_debug_globals = NULL; +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STANDARD WIDTHS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* scale the widths/heights table */ + static void + psh_globals_scale_widths( PSH_Globals globals, + FT_UInt direction ) + { + PSH_Dimension dim = &globals->dimension[direction]; + PSH_Widths stdw = &dim->stdw; + FT_UInt count = stdw->count; + PSH_Width width = stdw->widths; + PSH_Width stand = width; /* standard width/height */ + FT_Fixed scale = dim->scale_mult; + + + if ( count > 0 ) + { + width->cur = FT_MulFix( width->org, scale ); + width->fit = FT_PIX_ROUND( width->cur ); + + width++; + count--; + + for ( ; count > 0; count--, width++ ) + { + FT_Pos w, dist; + + + w = FT_MulFix( width->org, scale ); + dist = w - stand->cur; + + if ( dist < 0 ) + dist = -dist; + + if ( dist < 128 ) + w = stand->cur; + + width->cur = w; + width->fit = FT_PIX_ROUND( w ); + } + } + } + + +#if 0 + + /* org_width is in font units, result in device pixels, 26.6 format */ + FT_LOCAL_DEF( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ) + { + FT_UInt n; + FT_Pos width = FT_MulFix( org_width, dimension->scale_mult ); + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + + + for ( n = 0; n < dimension->stdw.count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = dimension->stdw.widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + if ( width >= reference ) + { + width -= 0x21; + if ( width < reference ) + width = reference; + } + else + { + width += 0x21; + if ( width > reference ) + width = reference; + } + + return width; + } + +#endif /* 0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BLUE ZONES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + psh_blues_set_zones_0( PSH_Blues target, + FT_Bool is_others, + FT_UInt read_count, + FT_Short* read, + PSH_Blue_Table top_table, + PSH_Blue_Table bot_table ) + { + FT_UInt count_top = top_table->count; + FT_UInt count_bot = bot_table->count; + FT_Bool first = 1; + + FT_UNUSED( target ); + + + for ( ; read_count > 1; read_count -= 2 ) + { + FT_Int reference, delta; + FT_UInt count; + PSH_Blue_Zone zones, zone; + FT_Bool top; + + + /* read blue zone entry, and select target top/bottom zone */ + top = 0; + if ( first || is_others ) + { + reference = read[1]; + delta = read[0] - reference; + + zones = bot_table->zones; + count = count_bot; + first = 0; + } + else + { + reference = read[0]; + delta = read[1] - reference; + + zones = top_table->zones; + count = count_top; + top = 1; + } + + /* insert into sorted table */ + zone = zones; + for ( ; count > 0; count--, zone++ ) + { + if ( reference < zone->org_ref ) + break; + + if ( reference == zone->org_ref ) + { + FT_Int delta0 = zone->org_delta; + + + /* we have two zones on the same reference position -- */ + /* only keep the largest one */ + if ( delta < 0 ) + { + if ( delta < delta0 ) + zone->org_delta = delta; + } + else + { + if ( delta > delta0 ) + zone->org_delta = delta; + } + goto Skip; + } + } + + for ( ; count > 0; count-- ) + zone[count] = zone[count-1]; + + zone->org_ref = reference; + zone->org_delta = delta; + + if ( top ) + count_top++; + else + count_bot++; + + Skip: + read += 2; + } + + top_table->count = count_top; + bot_table->count = count_bot; + } + + + /* Re-read blue zones from the original fonts and store them into our */ + /* private structure. This function re-orders, sanitizes, and */ + /* fuzz-expands the zones as well. */ + static void + psh_blues_set_zones( PSH_Blues target, + FT_UInt count, + FT_Short* blues, + FT_UInt count_others, + FT_Short* other_blues, + FT_Int fuzz, + FT_Int family ) + { + PSH_Blue_Table top_table, bot_table; + FT_UInt count_top, count_bot; + + + if ( family ) + { + top_table = &target->family_top; + bot_table = &target->family_bottom; + } + else + { + top_table = &target->normal_top; + bot_table = &target->normal_bottom; + } + + /* read the input blue zones, and build two sorted tables */ + /* (one for the top zones, the other for the bottom zones) */ + top_table->count = 0; + bot_table->count = 0; + + /* first, the blues */ + psh_blues_set_zones_0( target, 0, + count, blues, top_table, bot_table ); + psh_blues_set_zones_0( target, 1, + count_others, other_blues, top_table, bot_table ); + + count_top = top_table->count; + count_bot = bot_table->count; + + /* sanitize top table */ + if ( count_top > 0 ) + { + PSH_Blue_Zone zone = top_table->zones; + + + for ( count = count_top; count > 0; count--, zone++ ) + { + FT_Int delta; + + + if ( count > 1 ) + { + delta = zone[1].org_ref - zone[0].org_ref; + if ( zone->org_delta > delta ) + zone->org_delta = delta; + } + + zone->org_bottom = zone->org_ref; + zone->org_top = zone->org_delta + zone->org_ref; + } + } + + /* sanitize bottom table */ + if ( count_bot > 0 ) + { + PSH_Blue_Zone zone = bot_table->zones; + + + for ( count = count_bot; count > 0; count--, zone++ ) + { + FT_Int delta; + + + if ( count > 1 ) + { + delta = zone[0].org_ref - zone[1].org_ref; + if ( zone->org_delta < delta ) + zone->org_delta = delta; + } + + zone->org_top = zone->org_ref; + zone->org_bottom = zone->org_delta + zone->org_ref; + } + } + + /* expand top and bottom tables with blue fuzz */ + { + FT_Int dim, top, bot, delta; + PSH_Blue_Zone zone; + + + zone = top_table->zones; + count = count_top; + + for ( dim = 1; dim >= 0; dim-- ) + { + if ( count > 0 ) + { + /* expand the bottom of the lowest zone normally */ + zone->org_bottom -= fuzz; + + /* expand the top and bottom of intermediate zones; */ + /* checking that the interval is smaller than the fuzz */ + top = zone->org_top; + + for ( count--; count > 0; count-- ) + { + bot = zone[1].org_bottom; + delta = bot - top; + + if ( delta / 2 < fuzz ) + zone[0].org_top = zone[1].org_bottom = top + delta / 2; + else + { + zone[0].org_top = top + fuzz; + zone[1].org_bottom = bot - fuzz; + } + + zone++; + top = zone->org_top; + } + + /* expand the top of the highest zone normally */ + zone->org_top = top + fuzz; + } + zone = bot_table->zones; + count = count_bot; + } + } + } + + + /* reset the blues table when the device transform changes */ + static void + psh_blues_scale_zones( PSH_Blues blues, + FT_Fixed scale, + FT_Pos delta ) + { + FT_UInt count; + FT_UInt num; + PSH_Blue_Table table = NULL; + + /* */ + /* Determine whether we need to suppress overshoots or */ + /* not. We simply need to compare the vertical scale */ + /* parameter to the raw bluescale value. Here is why: */ + /* */ + /* We need to suppress overshoots for all pointsizes. */ + /* At 300dpi that satisfies: */ + /* */ + /* pointsize < 240*bluescale + 0.49 */ + /* */ + /* This corresponds to: */ + /* */ + /* pixelsize < 1000*bluescale + 49/24 */ + /* */ + /* scale*EM_Size < 1000*bluescale + 49/24 */ + /* */ + /* However, for normal Type 1 fonts, EM_Size is 1000! */ + /* We thus only check: */ + /* */ + /* scale < bluescale + 49/24000 */ + /* */ + /* which we shorten to */ + /* */ + /* "scale < bluescale" */ + /* */ + /* Note that `blue_scale' is stored 1000 times its real */ + /* value, and that `scale' converts from font units to */ + /* fractional pixels. */ + /* */ + + /* 1000 / 64 = 125 / 8 */ + if ( scale >= 0x20C49BAL ) + blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 ); + else + blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 ); + + /* */ + /* The blue threshold is the font units distance under */ + /* which overshoots are suppressed due to the BlueShift */ + /* even if the scale is greater than BlueScale. */ + /* */ + /* It is the smallest distance such that */ + /* */ + /* dist <= BlueShift && dist*scale <= 0.5 pixels */ + /* */ + { + FT_Int threshold = blues->blue_shift; + + + while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 ) + threshold--; + + blues->blue_threshold = threshold; + } + + for ( num = 0; num < 4; num++ ) + { + PSH_Blue_Zone zone; + + + switch ( num ) + { + case 0: + table = &blues->normal_top; + break; + case 1: + table = &blues->normal_bottom; + break; + case 2: + table = &blues->family_top; + break; + default: + table = &blues->family_bottom; + break; + } + + zone = table->zones; + count = table->count; + for ( ; count > 0; count--, zone++ ) + { + zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta; + zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta; + zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta; + zone->cur_delta = FT_MulFix( zone->org_delta, scale ); + + /* round scaled reference position */ + zone->cur_ref = FT_PIX_ROUND( zone->cur_ref ); + +#if 0 + if ( zone->cur_ref > zone->cur_top ) + zone->cur_ref -= 64; + else if ( zone->cur_ref < zone->cur_bottom ) + zone->cur_ref += 64; +#endif + } + } + + /* process the families now */ + + for ( num = 0; num < 2; num++ ) + { + PSH_Blue_Zone zone1, zone2; + FT_UInt count1, count2; + PSH_Blue_Table normal, family; + + + switch ( num ) + { + case 0: + normal = &blues->normal_top; + family = &blues->family_top; + break; + + default: + normal = &blues->normal_bottom; + family = &blues->family_bottom; + } + + zone1 = normal->zones; + count1 = normal->count; + + for ( ; count1 > 0; count1--, zone1++ ) + { + /* try to find a family zone whose reference position is less */ + /* than 1 pixel far from the current zone */ + zone2 = family->zones; + count2 = family->count; + + for ( ; count2 > 0; count2--, zone2++ ) + { + FT_Pos Delta; + + + Delta = zone1->org_ref - zone2->org_ref; + if ( Delta < 0 ) + Delta = -Delta; + + if ( FT_MulFix( Delta, scale ) < 64 ) + { + zone1->cur_top = zone2->cur_top; + zone1->cur_bottom = zone2->cur_bottom; + zone1->cur_ref = zone2->cur_ref; + zone1->cur_delta = zone2->cur_delta; + break; + } + } + } + } + } + + + /* calculate the maximum height of given blue zones */ + static FT_Short + psh_calc_max_height( FT_UInt num, + const FT_Short* values, + FT_Short cur_max ) + { + FT_UInt count; + + + for ( count = 0; count < num; count += 2 ) + { + FT_Short cur_height = values[count + 1] - values[count]; + + + if ( cur_height > cur_max ) + cur_max = cur_height; + } + + return cur_max; + } + + + FT_LOCAL_DEF( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ) + { + PSH_Blue_Table table; + FT_UInt count; + FT_Pos delta; + PSH_Blue_Zone zone; + FT_Int no_shoots; + + + alignment->align = PSH_BLUE_ALIGN_NONE; + + no_shoots = blues->no_overshoots; + + /* look up stem top in top zones table */ + table = &blues->normal_top; + count = table->count; + zone = table->zones; + + for ( ; count > 0; count--, zone++ ) + { + delta = SUB_LONG( stem_top, zone->org_bottom ); + if ( delta < -blues->blue_fuzz ) + break; + + if ( stem_top <= zone->org_top + blues->blue_fuzz ) + { + if ( no_shoots || delta <= blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_TOP; + alignment->align_top = zone->cur_ref; + } + break; + } + } + + /* look up stem bottom in bottom zones table */ + table = &blues->normal_bottom; + count = table->count; + zone = table->zones + count-1; + + for ( ; count > 0; count--, zone-- ) + { + delta = SUB_LONG( zone->org_top, stem_bot ); + if ( delta < -blues->blue_fuzz ) + break; + + if ( stem_bot >= zone->org_bottom - blues->blue_fuzz ) + { + if ( no_shoots || delta < blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_BOT; + alignment->align_bot = zone->cur_ref; + } + break; + } + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLOBAL HINTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + psh_globals_destroy( PSH_Globals globals ) + { + if ( globals ) + { + FT_Memory memory; + + + memory = globals->memory; + globals->dimension[0].stdw.count = 0; + globals->dimension[1].stdw.count = 0; + + globals->blues.normal_top.count = 0; + globals->blues.normal_bottom.count = 0; + globals->blues.family_top.count = 0; + globals->blues.family_bottom.count = 0; + + FT_FREE( globals ); + +#ifdef DEBUG_HINTER + ps_debug_globals = NULL; +#endif + } + } + + + static FT_Error + psh_globals_new( FT_Memory memory, + T1_Private* priv, + PSH_Globals *aglobals ) + { + PSH_Globals globals = NULL; + FT_Error error; + + + if ( !FT_QNEW( globals ) ) + { + FT_UInt count; + FT_Short* read; + + + globals->memory = memory; + + /* copy standard widths */ + { + PSH_Dimension dim = &globals->dimension[1]; + PSH_Width write = dim->stdw.widths; + + + write->org = priv->standard_width[0]; + write++; + + read = priv->snap_widths; + for ( count = priv->num_snap_widths; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + + dim->stdw.count = priv->num_snap_widths + 1; + } + + /* copy standard heights */ + { + PSH_Dimension dim = &globals->dimension[0]; + PSH_Width write = dim->stdw.widths; + + + write->org = priv->standard_height[0]; + write++; + read = priv->snap_heights; + for ( count = priv->num_snap_heights; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + + dim->stdw.count = priv->num_snap_heights + 1; + } + + /* copy blue zones */ + psh_blues_set_zones( &globals->blues, priv->num_blue_values, + priv->blue_values, priv->num_other_blues, + priv->other_blues, priv->blue_fuzz, 0 ); + + psh_blues_set_zones( &globals->blues, priv->num_family_blues, + priv->family_blues, priv->num_family_other_blues, + priv->family_other_blues, priv->blue_fuzz, 1 ); + + /* limit the BlueScale value to `1 / max_of_blue_zone_heights' */ + { + FT_Fixed max_scale; + FT_Short max_height = 1; + + + max_height = psh_calc_max_height( priv->num_blue_values, + priv->blue_values, + max_height ); + max_height = psh_calc_max_height( priv->num_other_blues, + priv->other_blues, + max_height ); + max_height = psh_calc_max_height( priv->num_family_blues, + priv->family_blues, + max_height ); + max_height = psh_calc_max_height( priv->num_family_other_blues, + priv->family_other_blues, + max_height ); + + /* BlueScale is scaled 1000 times */ + max_scale = FT_DivFix( 1000, max_height ); + globals->blues.blue_scale = priv->blue_scale < max_scale + ? priv->blue_scale + : max_scale; + } + + globals->blues.blue_shift = priv->blue_shift; + globals->blues.blue_fuzz = priv->blue_fuzz; + + globals->dimension[0].scale_mult = 0; + globals->dimension[0].scale_delta = 0; + globals->dimension[1].scale_mult = 0; + globals->dimension[1].scale_delta = 0; + +#ifdef DEBUG_HINTER + ps_debug_globals = globals; +#endif + } + + *aglobals = globals; + return error; + } + + + FT_LOCAL_DEF( void ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ) + { + PSH_Dimension dim; + + + dim = &globals->dimension[0]; + if ( x_scale != dim->scale_mult || + x_delta != dim->scale_delta ) + { + dim->scale_mult = x_scale; + dim->scale_delta = x_delta; + + psh_globals_scale_widths( globals, 0 ); + } + + dim = &globals->dimension[1]; + if ( y_scale != dim->scale_mult || + y_delta != dim->scale_delta ) + { + dim->scale_mult = y_scale; + dim->scale_delta = y_delta; + + psh_globals_scale_widths( globals, 1 ); + psh_blues_scale_zones( &globals->blues, y_scale, y_delta ); + } + } + + + FT_LOCAL_DEF( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ) + { + funcs->create = psh_globals_new; + funcs->set_scale = psh_globals_set_scale; + funcs->destroy = psh_globals_destroy; + } + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshglob.h b/vendor/freetype/src/pshinter/pshglob.h new file mode 100644 index 0000000..579eb21 --- /dev/null +++ b/vendor/freetype/src/pshinter/pshglob.h @@ -0,0 +1,196 @@ +/**************************************************************************** + * + * pshglob.h + * + * PostScript hinter global hinting management. + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHGLOB_H_ +#define PSHGLOB_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLOBAL HINTS INTERNALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @constant: + * PS_GLOBALS_MAX_BLUE_ZONES + * + * @description: + * The maximum number of blue zones in a font global hints structure. + * See @PS_Globals_BluesRec. + */ +#define PS_GLOBALS_MAX_BLUE_ZONES 16 + + + /************************************************************************** + * + * @constant: + * PS_GLOBALS_MAX_STD_WIDTHS + * + * @description: + * The maximum number of standard and snap widths in either the + * horizontal or vertical direction. See @PS_Globals_WidthsRec. + */ +#define PS_GLOBALS_MAX_STD_WIDTHS 16 + + + /* standard and snap width */ + typedef struct PSH_WidthRec_ + { + FT_Int org; + FT_Pos cur; + FT_Pos fit; + + } PSH_WidthRec, *PSH_Width; + + + /* standard and snap widths table */ + typedef struct PSH_WidthsRec_ + { + FT_UInt count; + PSH_WidthRec widths[PS_GLOBALS_MAX_STD_WIDTHS]; + + } PSH_WidthsRec, *PSH_Widths; + + + typedef struct PSH_DimensionRec_ + { + PSH_WidthsRec stdw; + FT_Fixed scale_mult; + FT_Fixed scale_delta; + + } PSH_DimensionRec, *PSH_Dimension; + + + /* blue zone descriptor */ + typedef struct PSH_Blue_ZoneRec_ + { + FT_Int org_ref; + FT_Int org_delta; + FT_Int org_top; + FT_Int org_bottom; + + FT_Pos cur_ref; + FT_Pos cur_delta; + FT_Pos cur_bottom; + FT_Pos cur_top; + + } PSH_Blue_ZoneRec, *PSH_Blue_Zone; + + + typedef struct PSH_Blue_TableRec_ + { + FT_UInt count; + PSH_Blue_ZoneRec zones[PS_GLOBALS_MAX_BLUE_ZONES]; + + } PSH_Blue_TableRec, *PSH_Blue_Table; + + + /* blue zones table */ + typedef struct PSH_BluesRec_ + { + PSH_Blue_TableRec normal_top; + PSH_Blue_TableRec normal_bottom; + PSH_Blue_TableRec family_top; + PSH_Blue_TableRec family_bottom; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_threshold; + FT_Int blue_fuzz; + FT_Bool no_overshoots; + + } PSH_BluesRec, *PSH_Blues; + + + /* font globals. */ + /* dimension 0 => X coordinates + vertical hints/stems */ + /* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PSH_GlobalsRec_ + { + FT_Memory memory; + PSH_DimensionRec dimension[2]; + PSH_BluesRec blues; + + } PSH_GlobalsRec; + + +#define PSH_BLUE_ALIGN_NONE 0 +#define PSH_BLUE_ALIGN_TOP 1 +#define PSH_BLUE_ALIGN_BOT 2 + + + typedef struct PSH_AlignmentRec_ + { + int align; + FT_Pos align_top; + FT_Pos align_bot; + + } PSH_AlignmentRec, *PSH_Alignment; + + + FT_LOCAL( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ); + + +#if 0 + /* snap a stem width to fitter coordinates. `org_width' is in font */ + /* units. The result is in device pixels (26.6 format). */ + FT_LOCAL( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ); +#endif + + FT_LOCAL( void ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + + /* snap a stem to one or two blue zones */ + FT_LOCAL( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ); + /* */ + +#ifdef DEBUG_HINTER + extern PSH_Globals ps_debug_globals; +#endif + + +FT_END_HEADER + + +#endif /* PSHGLOB_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshinter.c b/vendor/freetype/src/pshinter/pshinter.c new file mode 100644 index 0000000..54ed410 --- /dev/null +++ b/vendor/freetype/src/pshinter/pshinter.c @@ -0,0 +1,27 @@ +/**************************************************************************** + * + * pshinter.c + * + * FreeType PostScript Hinting module + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pshalgo.c" +#include "pshglob.c" +#include "pshmod.c" +#include "pshrec.c" + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshmod.c b/vendor/freetype/src/pshinter/pshmod.c new file mode 100644 index 0000000..974a99e --- /dev/null +++ b/vendor/freetype/src/pshinter/pshmod.c @@ -0,0 +1,125 @@ +/**************************************************************************** + * + * pshmod.c + * + * FreeType PostScript hinter module implementation (body). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "pshrec.h" +#include "pshalgo.h" +#include "pshmod.h" + + + /* the Postscript Hinter module structure */ + typedef struct PS_Hinter_Module_Rec_ + { + FT_ModuleRec root; + PS_HintsRec ps_hints; + + PSH_Globals_FuncsRec globals_funcs; + T1_Hints_FuncsRec t1_funcs; + T2_Hints_FuncsRec t2_funcs; + + } PS_Hinter_ModuleRec, *PS_Hinter_Module; + + + /* finalize module */ + FT_CALLBACK_DEF( void ) + ps_hinter_done( FT_Module module_ ) /* PS_Hinter_Module */ + { + PS_Hinter_Module module = (PS_Hinter_Module)module_; + + + module->t1_funcs.hints = NULL; + module->t2_funcs.hints = NULL; + + ps_hints_done( &module->ps_hints ); + } + + + /* initialize module, create hints recorder and the interface */ + FT_CALLBACK_DEF( FT_Error ) + ps_hinter_init( FT_Module module_ ) /* PS_Hinter_Module */ + { + PS_Hinter_Module module = (PS_Hinter_Module)module_; + + FT_Memory memory = module->root.memory; + void* ph = &module->ps_hints; + + + ps_hints_init( &module->ps_hints, memory ); + + psh_globals_funcs_init( &module->globals_funcs ); + + t1_hints_funcs_init( &module->t1_funcs ); + module->t1_funcs.hints = (T1_Hints)ph; + + t2_hints_funcs_init( &module->t2_funcs ); + module->t2_funcs.hints = (T2_Hints)ph; + + return 0; + } + + + /* returns global hints interface */ + FT_CALLBACK_DEF( PSH_Globals_Funcs ) + pshinter_get_globals_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->globals_funcs; + } + + + /* return Type 1 hints interface */ + FT_CALLBACK_DEF( T1_Hints_Funcs ) + pshinter_get_t1_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t1_funcs; + } + + + /* return Type 2 hints interface */ + FT_CALLBACK_DEF( T2_Hints_Funcs ) + pshinter_get_t2_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t2_funcs; + } + + + FT_DEFINE_PSHINTER_INTERFACE( + pshinter_interface, + + pshinter_get_globals_funcs, + pshinter_get_t1_funcs, + pshinter_get_t2_funcs + ) + + + FT_DEFINE_MODULE( + pshinter_module_class, + + 0, + sizeof ( PS_Hinter_ModuleRec ), + "pshinter", + 0x10000L, + 0x20000L, + + &pshinter_interface, /* module-specific interface */ + + (FT_Module_Constructor)ps_hinter_init, /* module_init */ + (FT_Module_Destructor) ps_hinter_done, /* module_done */ + (FT_Module_Requester) NULL /* get_interface */ + ) + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshmod.h b/vendor/freetype/src/pshinter/pshmod.h new file mode 100644 index 0000000..4bd781a --- /dev/null +++ b/vendor/freetype/src/pshinter/pshmod.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * pshmod.h + * + * PostScript hinter module interface (specification). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHMOD_H_ +#define PSHMOD_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_MODULE( pshinter_module_class ) + + +FT_END_HEADER + + +#endif /* PSHMOD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshnterr.h b/vendor/freetype/src/pshinter/pshnterr.h new file mode 100644 index 0000000..9762495 --- /dev/null +++ b/vendor/freetype/src/pshinter/pshnterr.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * pshnterr.h + * + * PS Hinter error codes (specification only). + * + * Copyright (C) 2003-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PSHinter error enumeration constants. + * + */ + +#ifndef PSHNTERR_H_ +#define PSHNTERR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSH_Err_ +#define FT_ERR_BASE FT_Mod_Err_PShinter + +#include + +#endif /* PSHNTERR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshrec.c b/vendor/freetype/src/pshinter/pshrec.c new file mode 100644 index 0000000..680e6d0 --- /dev/null +++ b/vendor/freetype/src/pshinter/pshrec.c @@ -0,0 +1,1224 @@ +/**************************************************************************** + * + * pshrec.c + * + * FreeType PostScript hints recorder (body). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "pshrec.h" +#include "pshalgo.h" + +#include "pshnterr.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pshrec + +#ifdef DEBUG_HINTER + PS_Hints ps_debug_hints = NULL; + int ps_debug_no_horz_hints = 0; + int ps_debug_no_vert_hints = 0; +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_HINT MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* destroy hints table */ + static void + ps_hint_table_done( PS_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + } + + + /* ensure that a table can contain "count" elements */ + static FT_Error + ps_hint_table_ensure( PS_Hint_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_hints; + FT_UInt new_max = count; + FT_Error error; + + + /* try to grow the table */ + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_QRENEW_ARRAY( table->hints, old_max, new_max ) ) + table->max_hints = new_max; + + return error; + } + + + static FT_Error + ps_hint_table_alloc( PS_Hint_Table table, + FT_Memory memory, + PS_Hint *ahint ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count; + PS_Hint hint = NULL; + + + count = table->num_hints; + count++; + + if ( count > table->max_hints ) + { + error = ps_hint_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + + hint = table->hints + count - 1; /* initialized upstream */ + + table->num_hints = count; + + Exit: + *ahint = hint; + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_MASK MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* destroy mask */ + static void + ps_mask_done( PS_Mask mask, + FT_Memory memory ) + { + FT_FREE( mask->bytes ); + mask->num_bits = 0; + mask->max_bits = 0; + mask->end_point = 0; + } + + + /* ensure that a mask can contain "count" bits */ + static FT_Error + ps_mask_ensure( PS_Mask mask, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = mask->max_bits >> 3; + FT_UInt new_max = ( count + 7 ) >> 3; + FT_Error error = FT_Err_Ok; + + + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + /* added bytes are zeroed here */ + if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) + mask->max_bits = new_max * 8; + } + return error; + } + + + /* test a bit value in a given mask */ + static FT_Int + ps_mask_test_bit( PS_Mask mask, + FT_UInt idx ) + { + if ( idx >= mask->num_bits ) + return 0; + + return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) ); + } + + + /* set a given bit, possibly grow the mask */ + static FT_Error + ps_mask_set_bit( PS_Mask mask, + FT_UInt idx, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* p; + + + if ( idx >= mask->num_bits ) + { + error = ps_mask_ensure( mask, idx + 1, memory ); + if ( error ) + goto Exit; + + mask->num_bits = idx + 1; + } + + p = mask->bytes + ( idx >> 3 ); + p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) ); + + Exit: + return error; + } + + + /* destroy mask table */ + static void + ps_mask_table_done( PS_Mask_Table table, + FT_Memory memory ) + { + FT_UInt count = table->max_masks; + PS_Mask mask = table->masks; + + + for ( ; count > 0; count--, mask++ ) + ps_mask_done( mask, memory ); + + FT_FREE( table->masks ); + table->num_masks = 0; + table->max_masks = 0; + } + + + /* ensure that a mask table can contain "count" masks */ + static FT_Error + ps_mask_table_ensure( PS_Mask_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_masks; + FT_UInt new_max = count; + FT_Error error = FT_Err_Ok; + + + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) ) + table->max_masks = new_max; + } + return error; + } + + + /* allocate a new mask in a table */ + static FT_Error + ps_mask_table_alloc( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_UInt count; + FT_Error error = FT_Err_Ok; + PS_Mask mask = NULL; + + + count = table->num_masks; + count++; + + if ( count > table->max_masks ) + { + error = ps_mask_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + + mask = table->masks + count - 1; + mask->num_bits = 0; + mask->end_point = 0; + /* reused mask must be cleared */ + if ( mask->max_bits ) + FT_MEM_ZERO( mask->bytes, mask->max_bits >> 3 ); + + table->num_masks = count; + + Exit: + *amask = mask; + return error; + } + + + /* return last hint mask in a table, create one if the table is empty */ + static FT_Error + ps_mask_table_last( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count; + PS_Mask mask; + + + count = table->num_masks; + if ( count == 0 ) + { + error = ps_mask_table_alloc( table, memory, &mask ); + if ( error ) + goto Exit; + } + else + mask = table->masks + count - 1; + + Exit: + *amask = mask; + return error; + } + + + /* set a new mask to a given bit range */ + static FT_Error + ps_mask_table_set_bits( PS_Mask_Table table, + const FT_Byte* source, + FT_UInt bit_pos, + FT_UInt bit_count, + FT_Memory memory ) + { + FT_Error error; + PS_Mask mask; + + + error = ps_mask_table_last( table, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_ensure( mask, bit_count, memory ); + if ( error ) + goto Exit; + + mask->num_bits = bit_count; + + /* now, copy bits */ + { + FT_Byte* read = (FT_Byte*)source + ( bit_pos >> 3 ); + FT_Int rmask = 0x80 >> ( bit_pos & 7 ); + FT_Byte* write = mask->bytes; + FT_Int wmask = 0x80; + FT_Int val; + + + for ( ; bit_count > 0; bit_count-- ) + { + val = write[0] & ~wmask; + + if ( read[0] & rmask ) + val |= wmask; + + write[0] = (FT_Byte)val; + + rmask >>= 1; + if ( rmask == 0 ) + { + read++; + rmask = 0x80; + } + + wmask >>= 1; + if ( wmask == 0 ) + { + write++; + wmask = 0x80; + } + } + } + + Exit: + return error; + } + + + /* test whether two masks in a table intersect */ + static FT_Int + ps_mask_table_test_intersect( PS_Mask_Table table, + FT_UInt index1, + FT_UInt index2 ) + { + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_Byte* p1 = mask1->bytes; + FT_Byte* p2 = mask2->bytes; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_UInt count; + + + count = FT_MIN( count1, count2 ); + for ( ; count >= 8; count -= 8 ) + { + if ( p1[0] & p2[0] ) + return 1; + + p1++; + p2++; + } + + if ( count == 0 ) + return 0; + + return ( p1[0] & p2[0] ) & ~( 0xFF >> count ); + } + + + /* merge two masks, used by ps_mask_table_merge_all */ + static FT_Error + ps_mask_table_merge( PS_Mask_Table table, + FT_UInt index1, + FT_UInt index2, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + + + /* swap index1 and index2 so that index1 < index2 */ + if ( index1 > index2 ) + { + FT_UInt temp; + + + temp = index1; + index1 = index2; + index2 = temp; + } + + if ( index1 < index2 && index2 < table->num_masks ) + { + /* we need to merge the bitsets of index1 and index2 with a */ + /* simple union */ + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_UInt delta; + + + if ( count2 > 0 ) + { + FT_UInt pos; + FT_Byte* read; + FT_Byte* write; + + + /* if "count2" is greater than "count1", we need to grow the */ + /* first bitset */ + if ( count2 > count1 ) + { + error = ps_mask_ensure( mask1, count2, memory ); + if ( error ) + goto Exit; + + mask1->num_bits = count2; + } + + /* merge (unite) the bitsets */ + read = mask2->bytes; + write = mask1->bytes; + pos = ( count2 + 7 ) >> 3; + + for ( ; pos > 0; pos-- ) + { + write[0] = (FT_Byte)( write[0] | read[0] ); + write++; + read++; + } + } + + /* Now, remove "mask2" from the list. We need to keep the masks */ + /* sorted in order of importance, so move table elements. */ + mask2->num_bits = 0; + mask2->end_point = 0; + + /* number of masks to move */ + delta = table->num_masks - 1 - index2; + if ( delta > 0 ) + { + /* move to end of table for reuse */ + PS_MaskRec dummy = *mask2; + + + ft_memmove( mask2, + mask2 + 1, + delta * sizeof ( PS_MaskRec ) ); + + mask2[delta] = dummy; + } + + table->num_masks--; + } + else + FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", + index1, index2 )); + + Exit: + return error; + } + + + /* Try to merge all masks in a given table. This is used to merge */ + /* all counter masks into independent counter "paths". */ + /* */ + static FT_Error + ps_mask_table_merge_all( PS_Mask_Table table, + FT_Memory memory ) + { + FT_UInt index1, index2; + FT_Error error = FT_Err_Ok; + + + /* the loops stop when unsigned indices wrap around after 0 */ + for ( index1 = table->num_masks - 1; index1 < table->num_masks; index1-- ) + { + for ( index2 = index1 - 1; index2 < index1; index2-- ) + { + if ( ps_mask_table_test_intersect( table, index1, index2 ) ) + { + error = ps_mask_table_merge( table, index2, index1, memory ); + if ( error ) + goto Exit; + + break; + } + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_DIMENSION MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* finalize a given dimension */ + static void + ps_dimension_done( PS_Dimension dimension, + FT_Memory memory ) + { + ps_mask_table_done( &dimension->counters, memory ); + ps_mask_table_done( &dimension->masks, memory ); + ps_hint_table_done( &dimension->hints, memory ); + } + + + /* initialize a given dimension */ + static void + ps_dimension_init( PS_Dimension dimension ) + { + dimension->hints.num_hints = 0; + dimension->masks.num_masks = 0; + dimension->counters.num_masks = 0; + } + + +#if 0 + + /* set a bit at a given index in the current hint mask */ + static FT_Error + ps_dimension_set_mask_bit( PS_Dimension dim, + FT_UInt idx, + FT_Memory memory ) + { + PS_Mask mask; + FT_Error error = FT_Err_Ok; + + + /* get last hint mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( mask, idx, memory ); + + Exit: + return error; + } + +#endif + + /* set the end point in a mask, called from "End" & "Reset" methods */ + static void + ps_dimension_end_mask( PS_Dimension dim, + FT_UInt end_point ) + { + FT_UInt count = dim->masks.num_masks; + + + if ( count > 0 ) + { + PS_Mask mask = dim->masks.masks + count - 1; + + + mask->end_point = end_point; + } + } + + + /* set the end point in the current mask, then create a new empty one */ + /* (called by "Reset" method) */ + static FT_Error + ps_dimension_reset_mask( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + PS_Mask mask; + + + /* end current mask */ + ps_dimension_end_mask( dim, end_point ); + + /* allocate new one */ + return ps_mask_table_alloc( &dim->masks, memory, &mask ); + } + + + /* set a new mask, called from the "T2Stem" method */ + static FT_Error + ps_dimension_set_mask_bits( PS_Dimension dim, + const FT_Byte* source, + FT_UInt source_pos, + FT_UInt source_bits, + FT_UInt end_point, + FT_Memory memory ) + { + FT_Error error; + + + /* reset current mask, if any */ + error = ps_dimension_reset_mask( dim, end_point, memory ); + if ( error ) + goto Exit; + + /* set bits in new mask */ + error = ps_mask_table_set_bits( &dim->masks, source, + source_pos, source_bits, memory ); + + Exit: + return error; + } + + + /* add a new single stem (called from "T1Stem" method) */ + static FT_Error + ps_dimension_add_t1stem( PS_Dimension dim, + FT_Int pos, + FT_Int len, + FT_Memory memory, + FT_UInt *aindex ) + { + FT_Error error = FT_Err_Ok; + FT_UInt flags = 0; + + + /* detect ghost stem */ + if ( len < 0 ) + { + flags |= PS_HINT_FLAG_GHOST; + if ( len == -21 ) + { + flags |= PS_HINT_FLAG_BOTTOM; + pos = ADD_INT( pos, len ); + } + len = 0; + } + + /* now, lookup stem in the current hints table */ + { + PS_Mask mask; + FT_UInt idx; + FT_UInt max = dim->hints.num_hints; + PS_Hint hint = dim->hints.hints; + + + for ( idx = 0; idx < max; idx++, hint++ ) + { + if ( hint->pos == pos && hint->len == len ) + break; + } + + /* we need to create a new hint in the table */ + if ( idx >= max ) + { + error = ps_hint_table_alloc( &dim->hints, memory, &hint ); + if ( error ) + goto Exit; + + hint->pos = pos; + hint->len = len; + hint->flags = flags; + } + + /* now, store the hint in the current mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( mask, idx, memory ); + if ( error ) + goto Exit; + + if ( aindex ) + *aindex = idx; + } + + Exit: + return error; + } + + + /* add a "hstem3/vstem3" counter to our dimension table */ + static FT_Error + ps_dimension_add_counter( PS_Dimension dim, + FT_UInt hint1, + FT_UInt hint2, + FT_UInt hint3, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count = dim->counters.num_masks; + PS_Mask counter = dim->counters.masks; + + + /* try to find an existing counter mask that already uses */ + /* one of these stems here */ + for ( ; count > 0; count--, counter++ ) + { + if ( ps_mask_test_bit( counter, hint1 ) || + ps_mask_test_bit( counter, hint2 ) || + ps_mask_test_bit( counter, hint3 ) ) + break; + } + + /* create a new counter when needed */ + if ( count == 0 ) + { + error = ps_mask_table_alloc( &dim->counters, memory, &counter ); + if ( error ) + goto Exit; + } + + /* now, set the bits for our hints in the counter mask */ + error = ps_mask_set_bit( counter, hint1, memory ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( counter, hint2, memory ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( counter, hint3, memory ); + if ( error ) + goto Exit; + + Exit: + return error; + } + + + /* end of recording session for a given dimension */ + static FT_Error + ps_dimension_end( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + /* end hint mask table */ + ps_dimension_end_mask( dim, end_point ); + + /* merge all counter masks into independent "paths" */ + return ps_mask_table_merge_all( &dim->counters, memory ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_RECORDER MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* destroy hints */ + FT_LOCAL_DEF( void ) + ps_hints_done( PS_Hints hints ) + { + FT_Memory memory = hints->memory; + + + ps_dimension_done( &hints->dimension[0], memory ); + ps_dimension_done( &hints->dimension[1], memory ); + + hints->error = FT_Err_Ok; + hints->memory = NULL; + } + + + FT_LOCAL_DEF( void ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ) + { + FT_ZERO( hints ); + hints->memory = memory; + } + + + /* initialize a hints for a new session */ + static void + ps_hints_open( PS_Hints hints, + PS_Hint_Type hint_type ) + { + hints->error = FT_Err_Ok; + hints->hint_type = hint_type; + + ps_dimension_init( &hints->dimension[0] ); + ps_dimension_init( &hints->dimension[1] ); + } + + + /* add one or more stems to the current hints table */ + static void + ps_hints_stem( PS_Hints hints, + FT_UInt dimension, + FT_Int count, + FT_Long* stems ) + { + PS_Dimension dim; + + + if ( hints->error ) + return; + + /* limit "dimension" to 0..1 */ + if ( dimension > 1 ) + { + FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } + + /* record the stems in the current hints/masks table */ + /* (Type 1 & 2's `hstem' or `vstem' operators) */ + dim = &hints->dimension[dimension]; + + for ( ; count > 0; count--, stems += 2 ) + { + FT_Error error; + FT_Memory memory = hints->memory; + + + error = ps_dimension_add_t1stem( dim, + (FT_Int)stems[0], + (FT_Int)stems[1], + memory, + NULL ); + if ( error ) + { + FT_ERROR(( "ps_hints_stem: could not add stem" + " (%ld,%ld) to hints table\n", stems[0], stems[1] )); + + hints->error = error; + return; + } + } + } + + + /* add one Type1 counter stem to the current hints table */ + static void + ps_hints_t1stem3( T1_Hints hints_, /* PS_Hints */ + FT_UInt dimension, + FT_Fixed* stems ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error = FT_Err_Ok; + + + if ( !hints->error ) + { + PS_Dimension dim; + FT_Memory memory = hints->memory; + FT_Int count; + FT_UInt idx[3]; + + + /* limit "dimension" to 0..1 */ + if ( dimension > 1 ) + { + FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } + + dim = &hints->dimension[dimension]; + + /* there must be 6 elements in the 'stem' array */ + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { + /* add the three stems to our hints/masks table */ + for ( count = 0; count < 3; count++, stems += 2 ) + { + error = ps_dimension_add_t1stem( dim, + (FT_Int)FIXED_TO_INT( stems[0] ), + (FT_Int)FIXED_TO_INT( stems[1] ), + memory, &idx[count] ); + if ( error ) + goto Fail; + } + + /* now, add the hints to the counters table */ + error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2], + memory ); + if ( error ) + goto Fail; + } + else + { + FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" )); + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + } + + return; + + Fail: + FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" )); + hints->error = error; + } + + + /* reset hints (only with Type 1 hints) */ + static void + ps_hints_t1reset( T1_Hints hints_, /* PS_Hints */ + FT_UInt end_point ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error = FT_Err_Ok; + + + if ( !hints->error ) + { + FT_Memory memory = hints->memory; + + + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { + error = ps_dimension_reset_mask( &hints->dimension[0], + end_point, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_reset_mask( &hints->dimension[1], + end_point, memory ); + if ( error ) + goto Fail; + } + else + { + /* invalid hint type */ + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + } + return; + + Fail: + hints->error = error; + } + + + /* Type2 "hintmask" operator, add a new hintmask to each direction */ + static void + ps_hints_t2mask( T2_Hints hints_, /* PS_Hints */ + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error; + + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + + /* check bit count; must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_TRACE0(( "ps_hints_t2mask:" + " called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); + + /* simply ignore the operator */ + return; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1, + end_point, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2, + end_point, memory ); + if ( error ) + goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + static void + ps_hints_t2counter( T2_Hints hints_, /* PS_Hints */ + FT_UInt bit_count, + const FT_Byte* bytes ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error; + + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + + /* check bit count, must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_TRACE0(( "ps_hints_t2counter:" + " called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); + + /* simply ignore the operator */ + return; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1, + 0, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2, + 0, memory ); + if ( error ) + goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + /* end recording session */ + static FT_Error + ps_hints_close( PS_Hints hints, + FT_UInt end_point ) + { + FT_Error error; + + + error = hints->error; + if ( !error ) + { + FT_Memory memory = hints->memory; + PS_Dimension dim = hints->dimension; + + + error = ps_dimension_end( &dim[0], end_point, memory ); + if ( !error ) + { + error = ps_dimension_end( &dim[1], end_point, memory ); + } + } + +#ifdef DEBUG_HINTER + if ( !error ) + ps_debug_hints = hints; +#endif + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t1_hints_open( T1_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); + } + + static FT_Error + t1_hints_close( T1_Hints hints, + FT_UInt end_point ) + { + return ps_hints_close( (PS_Hints)hints, end_point ); + } + + static void + t1_hints_stem( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ) + { + FT_Pos stems[2]; + + + stems[0] = FIXED_TO_INT( coords[0] ); + stems[1] = FIXED_TO_INT( coords[1] ); + + ps_hints_stem( (PS_Hints)hints, dimension, 1, stems ); + } + + + static FT_Error + t1_hints_apply( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode ); + } + + + FT_LOCAL_DEF( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) + { + FT_ZERO( funcs ); + + funcs->open = (T1_Hints_OpenFunc) t1_hints_open; + funcs->close = (T1_Hints_CloseFunc) t1_hints_close; + funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem; + funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3; + funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset; + funcs->apply = (T1_Hints_ApplyFunc) t1_hints_apply; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 2 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t2_hints_open( T2_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 ); + } + + + static FT_Error + t2_hints_close( T2_Hints hints, + FT_UInt end_point ) + { + return ps_hints_close( (PS_Hints)hints, end_point ); + } + + + static void + t2_hints_stems( T2_Hints hints, + FT_UInt dimension, + FT_Int count, + FT_Fixed* coords ) + { + FT_Pos stems[32], y; + FT_Int total = count, n; + + + y = 0; + while ( total > 0 ) + { + /* determine number of stems to write */ + count = total; + if ( count > 16 ) + count = 16; + + /* compute integer stem positions in font units */ + for ( n = 0; n < count * 2; n++ ) + { + y = ADD_LONG( y, coords[n] ); + stems[n] = FIXED_TO_INT( y ); + } + + /* compute lengths */ + for ( n = 0; n < count * 2; n += 2 ) + stems[n + 1] = stems[n + 1] - stems[n]; + + /* add them to the current dimension */ + ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); + + total -= count; + } + } + + + static FT_Error + t2_hints_apply( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode ); + } + + + FT_LOCAL_DEF( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) + { + FT_ZERO( funcs ); + + funcs->open = (T2_Hints_OpenFunc) t2_hints_open; + funcs->close = (T2_Hints_CloseFunc) t2_hints_close; + funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems; + funcs->hintmask = (T2_Hints_MaskFunc) ps_hints_t2mask; + funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter; + funcs->apply = (T2_Hints_ApplyFunc) t2_hints_apply; + } + + +/* END */ diff --git a/vendor/freetype/src/pshinter/pshrec.h b/vendor/freetype/src/pshinter/pshrec.h new file mode 100644 index 0000000..0b2484a --- /dev/null +++ b/vendor/freetype/src/pshinter/pshrec.h @@ -0,0 +1,171 @@ +/**************************************************************************** + * + * pshrec.h + * + * Postscript (Type1/Type2) hints recorder (specification). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /*************************************************************************** + * + * The functions defined here are called from the Type 1, CID and CFF + * font drivers to record the hints of a given character/glyph. + * + * The hints are recorded in a unified format, and are later processed + * by the `optimizer' and `fitter' to adjust the outlines to the pixel + * grid. + * + */ + + +#ifndef PSHREC_H_ +#define PSHREC_H_ + + +#include +#include "pshglob.h" + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH HINTS RECORDER INTERNALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to hint record */ + typedef struct PS_HintRec_* PS_Hint; + + /* hint types */ + typedef enum PS_Hint_Type_ + { + PS_HINT_TYPE_1 = 1, + PS_HINT_TYPE_2 = 2 + + } PS_Hint_Type; + + + /* hint flags */ +#define PS_HINT_FLAG_GHOST 1U +#define PS_HINT_FLAG_BOTTOM 2U + + + /* hint descriptor */ + typedef struct PS_HintRec_ + { + FT_Int pos; + FT_Int len; + FT_UInt flags; + + } PS_HintRec; + + +#define ps_hint_is_active( x ) ( (x)->flags & PS_HINT_FLAG_ACTIVE ) +#define ps_hint_is_ghost( x ) ( (x)->flags & PS_HINT_FLAG_GHOST ) +#define ps_hint_is_bottom( x ) ( (x)->flags & PS_HINT_FLAG_BOTTOM ) + + + /* hints table descriptor */ + typedef struct PS_Hint_TableRec_ + { + FT_UInt num_hints; + FT_UInt max_hints; + PS_Hint hints; + + } PS_Hint_TableRec, *PS_Hint_Table; + + + /* hint and counter mask descriptor */ + typedef struct PS_MaskRec_ + { + FT_UInt num_bits; + FT_UInt max_bits; + FT_Byte* bytes; + FT_UInt end_point; + + } PS_MaskRec, *PS_Mask; + + + /* masks and counters table descriptor */ + typedef struct PS_Mask_TableRec_ + { + FT_UInt num_masks; + FT_UInt max_masks; + PS_Mask masks; + + } PS_Mask_TableRec, *PS_Mask_Table; + + + /* dimension-specific hints descriptor */ + typedef struct PS_DimensionRec_ + { + PS_Hint_TableRec hints; + PS_Mask_TableRec masks; + PS_Mask_TableRec counters; + + } PS_DimensionRec, *PS_Dimension; + + + /* glyph hints descriptor */ + /* dimension 0 => X coordinates + vertical hints/stems */ + /* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PS_HintsRec_ + { + FT_Memory memory; + FT_Error error; + FT_UInt32 magic; + PS_Hint_Type hint_type; + PS_DimensionRec dimension[2]; + + } PS_HintsRec, *PS_Hints; + + /* */ + + /* initialize hints recorder */ + FT_LOCAL( void ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ); + + /* finalize hints recorder */ + FT_LOCAL( void ) + ps_hints_done( PS_Hints hints ); + + /* initialize Type1 hints recorder interface */ + FT_LOCAL( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ); + + /* initialize Type2 hints recorder interface */ + FT_LOCAL( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ); + + +#ifdef DEBUG_HINTER + extern PS_Hints ps_debug_hints; + extern int ps_debug_no_horz_hints; + extern int ps_debug_no_vert_hints; +#endif + + /* */ + + +FT_END_HEADER + + +#endif /* PSHREC_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/pshinter/rules.mk b/vendor/freetype/src/pshinter/rules.mk new file mode 100644 index 0000000..50058e8 --- /dev/null +++ b/vendor/freetype/src/pshinter/rules.mk @@ -0,0 +1,75 @@ +# +# FreeType 2 PSHinter driver configuration rules +# + + +# Copyright (C) 2001-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# PSHINTER driver directory +# +PSHINTER_DIR := $(SRC_DIR)/pshinter + + +# compilation flags for the driver +# +PSHINTER_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(PSHINTER_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# PSHINTER driver sources (i.e., C files) +# +PSHINTER_DRV_SRC := $(PSHINTER_DIR)/pshalgo.c \ + $(PSHINTER_DIR)/pshglob.c \ + $(PSHINTER_DIR)/pshmod.c \ + $(PSHINTER_DIR)/pshrec.c + + +# PSHINTER driver headers +# +PSHINTER_DRV_H := $(PSHINTER_DRV_SRC:%c=%h) \ + $(PSHINTER_DIR)/pshnterr.h + + +# PSHINTER driver object(s) +# +# PSHINTER_DRV_OBJ_M is used during `multi' builds. +# PSHINTER_DRV_OBJ_S is used during `single' builds. +# +PSHINTER_DRV_OBJ_M := $(PSHINTER_DRV_SRC:$(PSHINTER_DIR)/%.c=$(OBJ_DIR)/%.$O) +PSHINTER_DRV_OBJ_S := $(OBJ_DIR)/pshinter.$O + +# PSHINTER driver source file for single build +# +PSHINTER_DRV_SRC_S := $(PSHINTER_DIR)/pshinter.c + + +# PSHINTER driver - single object +# +$(PSHINTER_DRV_OBJ_S): $(PSHINTER_DRV_SRC_S) $(PSHINTER_DRV_SRC) \ + $(FREETYPE_H) $(PSHINTER_DRV_H) + $(PSHINTER_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(PSHINTER_DRV_SRC_S)) + + +# PSHINTER driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(PSHINTER_DIR)/%.c $(FREETYPE_H) $(PSHINTER_DRV_H) + $(PSHINTER_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(PSHINTER_DRV_OBJ_S) +DRV_OBJS_M += $(PSHINTER_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/psnames/module.mk b/vendor/freetype/src/psnames/module.mk new file mode 100644 index 0000000..1ee0ef8 --- /dev/null +++ b/vendor/freetype/src/psnames/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 PSnames module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += PSNAMES_MODULE + +define PSNAMES_MODULE +$(OPEN_DRIVER) FT_Module_Class, psnames_module_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)psnames $(ECHO_DRIVER_DESC)Postscript & Unicode Glyph name handling$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/psnames/psmodule.c b/vendor/freetype/src/psnames/psmodule.c new file mode 100644 index 0000000..8203a04 --- /dev/null +++ b/vendor/freetype/src/psnames/psmodule.c @@ -0,0 +1,621 @@ +/**************************************************************************** + * + * psmodule.c + * + * psnames module implementation (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + +#include "psmodule.h" + + /* + * The file `pstables.h' with its arrays and its function + * `ft_get_adobe_glyph_index' is useful for other projects also (for + * example, `pdfium' is using it). However, if used as a C++ header, + * including it in two different source files makes it necessary to use + * `extern const' for the declaration of its arrays, otherwise the data + * would be duplicated as mandated by the C++ standard. + * + * For this reason, we use `DEFINE_PS_TABLES' to guard the function + * definitions, and `DEFINE_PS_TABLES_DATA' to provide both proper array + * declarations and definitions. + */ +#include "pstables.h" +#define DEFINE_PS_TABLES +#define DEFINE_PS_TABLES_DATA +#include "pstables.h" + +#include "psnamerr.h" + + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + +#define VARIANT_BIT 0x80000000UL +#define BASE_GLYPH( code ) ( (FT_UInt32)( (code) & ~VARIANT_BIT ) ) + + + /* Return the Unicode value corresponding to a given glyph. Note that */ + /* we do deal with glyph variants by detecting a non-initial dot in */ + /* the name, as in `A.swash' or `e.final'; in this case, the */ + /* VARIANT_BIT is set in the return value. */ + /* */ + FT_CALLBACK_DEF( FT_UInt32 ) + ps_unicode_value( const char* glyph_name ) + { + /* If the name begins with `uni', then the glyph name may be a */ + /* hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' && + glyph_name[1] == 'n' && + glyph_name[2] == 'i' ) + { + /* determine whether the next four characters following are */ + /* hexadecimal. */ + + /* XXX: Add code to deal with ligatures, i.e. glyph names like */ + /* `uniXXXXYYYYZZZZ'... */ + + FT_Int count; + FT_UInt32 value = 0; + const char* p = glyph_name + 3; + + + for ( count = 4; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + + + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + + /* Exit if a non-uppercase hexadecimal character was found */ + /* -- this also catches character codes below `0' since such */ + /* negative numbers cast to `unsigned int' are far too big. */ + if ( d >= 16 ) + break; + + value = ( value << 4 ) + d; + } + + /* there must be exactly four hex digits */ + if ( count == 0 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return (FT_UInt32)( value | VARIANT_BIT ); + } + } + + /* If the name begins with `u', followed by four to six uppercase */ + /* hexadecimal digits, it is a hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' ) + { + FT_Int count; + FT_UInt32 value = 0; + const char* p = glyph_name + 1; + + + for ( count = 6; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + + + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + + if ( d >= 16 ) + break; + + value = ( value << 4 ) + d; + } + + if ( count <= 2 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return (FT_UInt32)( value | VARIANT_BIT ); + } + } + + /* Look for a non-initial dot in the glyph name in order to */ + /* find variants like `A.swash', `e.final', etc. */ + { + FT_UInt32 value = 0; + const char* p = glyph_name; + + + for ( ; *p && *p != '.'; p++ ) + ; + + /* now look up the glyph in the Adobe Glyph List; */ + /* `.notdef', `.null' and the empty name are short cut */ + if ( p > glyph_name ) + { + value = (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); + + if ( *p == '.' ) + value |= (FT_UInt32)VARIANT_BIT; + } + + return value; + } + } + + + /* ft_qsort callback to sort the unicode map */ + FT_COMPARE_DEF( int ) + compare_uni_maps( const void* a, + const void* b ) + { + PS_UniMap* map1 = (PS_UniMap*)a; + PS_UniMap* map2 = (PS_UniMap*)b; + FT_UInt32 unicode1 = BASE_GLYPH( map1->unicode ); + FT_UInt32 unicode2 = BASE_GLYPH( map2->unicode ); + + + /* sort base glyphs before glyph variants */ + if ( unicode1 == unicode2 ) + { + if ( map1->unicode > map2->unicode ) + return 1; + else if ( map1->unicode < map2->unicode ) + return -1; + else + return 0; + } + else + { + if ( unicode1 > unicode2 ) + return 1; + else if ( unicode1 < unicode2 ) + return -1; + else + return 0; + } + } + + + /* support for extra glyphs not handled (well) in AGL; */ + /* we add extra mappings for them if necessary */ + +#define EXTRA_GLYPH_LIST_SIZE 10 + + static const FT_UInt32 ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] = + { + /* WGL 4 */ + 0x0394, + 0x03A9, + 0x2215, + 0x00AD, + 0x02C9, + 0x03BC, + 0x2219, + 0x00A0, + /* Romanian */ + 0x021A, + 0x021B + }; + + static const char ft_extra_glyph_names[] = + { + 'D','e','l','t','a',0, + 'O','m','e','g','a',0, + 'f','r','a','c','t','i','o','n',0, + 'h','y','p','h','e','n',0, + 'm','a','c','r','o','n',0, + 'm','u',0, + 'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0, + 's','p','a','c','e',0, + 'T','c','o','m','m','a','a','c','c','e','n','t',0, + 't','c','o','m','m','a','a','c','c','e','n','t',0 + }; + + static const FT_Int + ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] = + { + 0, + 6, + 12, + 21, + 28, + 35, + 38, + 53, + 59, + 72 + }; + + + static void + ps_check_extra_glyph_name( const char* gname, + FT_UInt glyph, + FT_UInt* extra_glyphs, + FT_UInt *states ) + { + FT_UInt n; + + + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( ft_strcmp( ft_extra_glyph_names + + ft_extra_glyph_name_offsets[n], gname ) == 0 ) + { + if ( states[n] == 0 ) + { + /* mark this extra glyph as a candidate for the cmap */ + states[n] = 1; + extra_glyphs[n] = glyph; + } + + return; + } + } + } + + + static void + ps_check_extra_glyph_unicode( FT_UInt32 uni_char, + FT_UInt *states ) + { + FT_UInt n; + + + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( uni_char == ft_extra_glyph_unicodes[n] ) + { + /* disable this extra glyph from being added to the cmap */ + states[n] = 2; + + return; + } + } + } + + + /* Build a table that maps Unicode values to glyph indices. */ + FT_CALLBACK_DEF( FT_Error ) + ps_unicodes_init( FT_Memory memory, + PS_Unicodes table, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ) + { + FT_Error error; + + FT_UInt extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + FT_UInt extra_glyphs[EXTRA_GLYPH_LIST_SIZE]; + + + /* we first allocate the table */ + table->num_maps = 0; + + if ( !FT_QNEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) + { + FT_UInt n; + FT_UInt count; + PS_UniMap* map; + FT_UInt32 uni_char; + + + map = table->maps; + + for ( n = 0; n < num_glyphs; n++ ) + { + const char* gname = get_glyph_name( glyph_data, n ); + + + if ( gname && *gname ) + { + ps_check_extra_glyph_name( gname, n, + extra_glyphs, extra_glyph_list_states ); + uni_char = ps_unicode_value( gname ); + + if ( BASE_GLYPH( uni_char ) != 0 ) + { + ps_check_extra_glyph_unicode( uni_char, + extra_glyph_list_states ); + map->unicode = uni_char; + map->glyph_index = n; + map++; + } + + if ( free_glyph_name ) + free_glyph_name( glyph_data, gname ); + } + } + + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( extra_glyph_list_states[n] == 1 ) + { + /* This glyph name has an additional representation. */ + /* Add it to the cmap. */ + + map->unicode = ft_extra_glyph_unicodes[n]; + map->glyph_index = extra_glyphs[n]; + map++; + } + } + + /* now compress the table a bit */ + count = (FT_UInt)( map - table->maps ); + + if ( count == 0 ) + { + /* No unicode chars here! */ + FT_FREE( table->maps ); + if ( !error ) + error = FT_THROW( No_Unicode_Glyph_Name ); + } + else + { + /* Reallocate if the number of used entries is much smaller. */ + if ( count < num_glyphs / 2 ) + { + FT_MEM_QRENEW_ARRAY( table->maps, + num_glyphs + EXTRA_GLYPH_LIST_SIZE, + count ); + error = FT_Err_Ok; + } + + /* Sort the table in increasing order of unicode values, */ + /* taking care of glyph variants. */ + ft_qsort( table->maps, count, sizeof ( PS_UniMap ), + compare_uni_maps ); + } + + table->num_maps = count; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_UInt ) + ps_unicodes_char_index( PS_Unicodes table, + FT_UInt32 unicode ) + { + PS_UniMap *result = NULL; + PS_UniMap *min = table->maps; + PS_UniMap *max = min + table->num_maps; + PS_UniMap *mid = min + ( ( max - min ) >> 1 ); + + + /* Perform a binary search on the table. */ + while ( min < max ) + { + FT_UInt32 base_glyph; + + + if ( mid->unicode == unicode ) + { + result = mid; + break; + } + + base_glyph = BASE_GLYPH( mid->unicode ); + + if ( base_glyph == unicode ) + result = mid; /* remember match but continue search for base glyph */ + + if ( base_glyph < unicode ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += unicode - base_glyph; + if ( mid >= max || mid < min ) + mid = min + ( ( max - min ) >> 1 ); + } + + if ( result ) + return result->glyph_index; + else + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + ps_unicodes_char_next( PS_Unicodes table, + FT_UInt32 *unicode ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *unicode + 1; + + + { + FT_UInt min = 0; + FT_UInt max = table->num_maps; + FT_UInt mid = min + ( ( max - min ) >> 1 ); + PS_UniMap* map; + FT_UInt32 base_glyph; + + + while ( min < max ) + { + map = table->maps + mid; + + if ( map->unicode == char_code ) + { + result = map->glyph_index; + goto Exit; + } + + base_glyph = BASE_GLYPH( map->unicode ); + + if ( base_glyph == char_code ) + result = map->glyph_index; + + if ( base_glyph < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - base_glyph; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + if ( result ) + goto Exit; /* we have a variant glyph */ + + /* we didn't find it; check whether we have a map just above it */ + char_code = 0; + + if ( min < table->num_maps ) + { + map = table->maps + min; + result = map->glyph_index; + char_code = BASE_GLYPH( map->unicode ); + } + } + + Exit: + *unicode = char_code; + return result; + } + + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + + FT_CALLBACK_DEF( const char* ) + ps_get_macintosh_name( FT_UInt name_index ) + { + if ( name_index >= FT_NUM_MAC_NAMES ) + name_index = 0; + + return ft_standard_glyph_names + ft_mac_names[name_index]; + } + + + FT_CALLBACK_DEF( const char* ) + ps_get_standard_strings( FT_UInt sid ) + { + if ( sid >= FT_NUM_SID_NAMES ) + return 0; + + return ft_standard_glyph_names + ft_sid_names[sid]; + } + + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + FT_DEFINE_SERVICE_PSCMAPSREC( + pscmaps_interface, + + ps_unicode_value, /* PS_Unicode_ValueFunc unicode_value */ + ps_unicodes_init, /* PS_Unicodes_InitFunc unicodes_init */ + ps_unicodes_char_index, /* PS_Unicodes_CharIndexFunc unicodes_char_index */ + ps_unicodes_char_next, /* PS_Unicodes_CharNextFunc unicodes_char_next */ + + ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */ + ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */ + + t1_standard_encoding, /* adobe_std_encoding */ + t1_expert_encoding /* adobe_expert_encoding */ + ) + +#else + + FT_DEFINE_SERVICE_PSCMAPSREC( + pscmaps_interface, + + NULL, /* PS_Unicode_ValueFunc unicode_value */ + NULL, /* PS_Unicodes_InitFunc unicodes_init */ + NULL, /* PS_Unicodes_CharIndexFunc unicodes_char_index */ + NULL, /* PS_Unicodes_CharNextFunc unicodes_char_next */ + + ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */ + ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */ + + t1_standard_encoding, /* adobe_std_encoding */ + t1_expert_encoding /* adobe_expert_encoding */ + ) + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + + FT_DEFINE_SERVICEDESCREC1( + pscmaps_services, + + FT_SERVICE_ID_POSTSCRIPT_CMAPS, &pscmaps_interface ) + + + static FT_Pointer + psnames_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pscmaps_services, service_id ); + } + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + +#ifndef FT_CONFIG_OPTION_POSTSCRIPT_NAMES +#define PUT_PS_NAMES_SERVICE( a ) NULL +#else +#define PUT_PS_NAMES_SERVICE( a ) a +#endif + + FT_DEFINE_MODULE( + psnames_module_class, + + 0, /* this is not a font driver, nor a renderer */ + sizeof ( FT_ModuleRec ), + + "psnames", /* driver name */ + 0x10000L, /* driver version */ + 0x20000L, /* driver requires FreeType 2 or above */ + + PUT_PS_NAMES_SERVICE( + (void*)&pscmaps_interface ), /* module specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + PUT_PS_NAMES_SERVICE( psnames_get_service ) /* FT_Module_Requester get_interface */ + ) + + +/* END */ diff --git a/vendor/freetype/src/psnames/psmodule.h b/vendor/freetype/src/psnames/psmodule.h new file mode 100644 index 0000000..0904700 --- /dev/null +++ b/vendor/freetype/src/psnames/psmodule.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * psmodule.h + * + * High-level psnames module interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSMODULE_H_ +#define PSMODULE_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_MODULE( psnames_module_class ) + + +FT_END_HEADER + +#endif /* PSMODULE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psnames/psnamerr.h b/vendor/freetype/src/psnames/psnamerr.h new file mode 100644 index 0000000..0073f82 --- /dev/null +++ b/vendor/freetype/src/psnames/psnamerr.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * psnamerr.h + * + * PS names module error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PS names module error enumeration + * constants. + * + */ + +#ifndef PSNAMERR_H_ +#define PSNAMERR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSnames_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSnames + +#include + +#endif /* PSNAMERR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/psnames/psnames.c b/vendor/freetype/src/psnames/psnames.c new file mode 100644 index 0000000..93ed933 --- /dev/null +++ b/vendor/freetype/src/psnames/psnames.c @@ -0,0 +1,24 @@ +/**************************************************************************** + * + * psnames.c + * + * FreeType psnames module component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "psmodule.c" + + +/* END */ diff --git a/vendor/freetype/src/psnames/pstables.h b/vendor/freetype/src/psnames/pstables.h new file mode 100644 index 0000000..7f92cce --- /dev/null +++ b/vendor/freetype/src/psnames/pstables.h @@ -0,0 +1,4238 @@ +/**************************************************************************** + * + * pstables.h + * + * PostScript glyph names. + * + * Copyright (C) 2005-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* This file has been generated automatically -- do not edit! */ + + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const char ft_standard_glyph_names[3696] +#ifdef DEFINE_PS_TABLES_DATA + = + { + '.','n','u','l','l', 0, + 'n','o','n','m','a','r','k','i','n','g','r','e','t','u','r','n', 0, + 'n','o','t','e','q','u','a','l', 0, + 'i','n','f','i','n','i','t','y', 0, + 'l','e','s','s','e','q','u','a','l', 0, + 'g','r','e','a','t','e','r','e','q','u','a','l', 0, + 'p','a','r','t','i','a','l','d','i','f','f', 0, + 's','u','m','m','a','t','i','o','n', 0, + 'p','r','o','d','u','c','t', 0, + 'p','i', 0, + 'i','n','t','e','g','r','a','l', 0, + 'O','m','e','g','a', 0, + 'r','a','d','i','c','a','l', 0, + 'a','p','p','r','o','x','e','q','u','a','l', 0, + 'D','e','l','t','a', 0, + 'n','o','n','b','r','e','a','k','i','n','g','s','p','a','c','e', 0, + 'l','o','z','e','n','g','e', 0, + 'a','p','p','l','e', 0, + 'f','r','a','n','c', 0, + 'G','b','r','e','v','e', 0, + 'g','b','r','e','v','e', 0, + 'I','d','o','t','a','c','c','e','n','t', 0, + 'S','c','e','d','i','l','l','a', 0, + 's','c','e','d','i','l','l','a', 0, + 'C','a','c','u','t','e', 0, + 'c','a','c','u','t','e', 0, + 'C','c','a','r','o','n', 0, + 'c','c','a','r','o','n', 0, + 'd','c','r','o','a','t', 0, + '.','n','o','t','d','e','f', 0, + 's','p','a','c','e', 0, + 'e','x','c','l','a','m', 0, + 'q','u','o','t','e','d','b','l', 0, + 'n','u','m','b','e','r','s','i','g','n', 0, + 'd','o','l','l','a','r', 0, + 'p','e','r','c','e','n','t', 0, + 'a','m','p','e','r','s','a','n','d', 0, + 'q','u','o','t','e','r','i','g','h','t', 0, + 'p','a','r','e','n','l','e','f','t', 0, + 'p','a','r','e','n','r','i','g','h','t', 0, + 'a','s','t','e','r','i','s','k', 0, + 'p','l','u','s', 0, + 'c','o','m','m','a', 0, + 'h','y','p','h','e','n', 0, + 'p','e','r','i','o','d', 0, + 's','l','a','s','h', 0, + 'z','e','r','o', 0, + 'o','n','e', 0, + 't','w','o', 0, + 't','h','r','e','e', 0, + 'f','o','u','r', 0, + 'f','i','v','e', 0, + 's','i','x', 0, + 's','e','v','e','n', 0, + 'e','i','g','h','t', 0, + 'n','i','n','e', 0, + 'c','o','l','o','n', 0, + 's','e','m','i','c','o','l','o','n', 0, + 'l','e','s','s', 0, + 'e','q','u','a','l', 0, + 'g','r','e','a','t','e','r', 0, + 'q','u','e','s','t','i','o','n', 0, + 'a','t', 0, + 'A', 0, + 'B', 0, + 'C', 0, + 'D', 0, + 'E', 0, + 'F', 0, + 'G', 0, + 'H', 0, + 'I', 0, + 'J', 0, + 'K', 0, + 'L', 0, + 'M', 0, + 'N', 0, + 'O', 0, + 'P', 0, + 'Q', 0, + 'R', 0, + 'S', 0, + 'T', 0, + 'U', 0, + 'V', 0, + 'W', 0, + 'X', 0, + 'Y', 0, + 'Z', 0, + 'b','r','a','c','k','e','t','l','e','f','t', 0, + 'b','a','c','k','s','l','a','s','h', 0, + 'b','r','a','c','k','e','t','r','i','g','h','t', 0, + 'a','s','c','i','i','c','i','r','c','u','m', 0, + 'u','n','d','e','r','s','c','o','r','e', 0, + 'q','u','o','t','e','l','e','f','t', 0, + 'a', 0, + 'b', 0, + 'c', 0, + 'd', 0, + 'e', 0, + 'f', 0, + 'g', 0, + 'h', 0, + 'i', 0, + 'j', 0, + 'k', 0, + 'l', 0, + 'm', 0, + 'n', 0, + 'o', 0, + 'p', 0, + 'q', 0, + 'r', 0, + 's', 0, + 't', 0, + 'u', 0, + 'v', 0, + 'w', 0, + 'x', 0, + 'y', 0, + 'z', 0, + 'b','r','a','c','e','l','e','f','t', 0, + 'b','a','r', 0, + 'b','r','a','c','e','r','i','g','h','t', 0, + 'a','s','c','i','i','t','i','l','d','e', 0, + 'e','x','c','l','a','m','d','o','w','n', 0, + 'c','e','n','t', 0, + 's','t','e','r','l','i','n','g', 0, + 'f','r','a','c','t','i','o','n', 0, + 'y','e','n', 0, + 'f','l','o','r','i','n', 0, + 's','e','c','t','i','o','n', 0, + 'c','u','r','r','e','n','c','y', 0, + 'q','u','o','t','e','s','i','n','g','l','e', 0, + 'q','u','o','t','e','d','b','l','l','e','f','t', 0, + 'g','u','i','l','l','e','m','o','t','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','r','i','g','h','t', 0, + 'f','i', 0, + 'f','l', 0, + 'e','n','d','a','s','h', 0, + 'd','a','g','g','e','r', 0, + 'd','a','g','g','e','r','d','b','l', 0, + 'p','e','r','i','o','d','c','e','n','t','e','r','e','d', 0, + 'p','a','r','a','g','r','a','p','h', 0, + 'b','u','l','l','e','t', 0, + 'q','u','o','t','e','s','i','n','g','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','r','i','g','h','t', 0, + 'g','u','i','l','l','e','m','o','t','r','i','g','h','t', 0, + 'e','l','l','i','p','s','i','s', 0, + 'p','e','r','t','h','o','u','s','a','n','d', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n', 0, + 'g','r','a','v','e', 0, + 'a','c','u','t','e', 0, + 'c','i','r','c','u','m','f','l','e','x', 0, + 't','i','l','d','e', 0, + 'm','a','c','r','o','n', 0, + 'b','r','e','v','e', 0, + 'd','o','t','a','c','c','e','n','t', 0, + 'd','i','e','r','e','s','i','s', 0, + 'r','i','n','g', 0, + 'c','e','d','i','l','l','a', 0, + 'h','u','n','g','a','r','u','m','l','a','u','t', 0, + 'o','g','o','n','e','k', 0, + 'c','a','r','o','n', 0, + 'e','m','d','a','s','h', 0, + 'A','E', 0, + 'o','r','d','f','e','m','i','n','i','n','e', 0, + 'L','s','l','a','s','h', 0, + 'O','s','l','a','s','h', 0, + 'O','E', 0, + 'o','r','d','m','a','s','c','u','l','i','n','e', 0, + 'a','e', 0, + 'd','o','t','l','e','s','s','i', 0, + 'l','s','l','a','s','h', 0, + 'o','s','l','a','s','h', 0, + 'o','e', 0, + 'g','e','r','m','a','n','d','b','l','s', 0, + 'o','n','e','s','u','p','e','r','i','o','r', 0, + 'l','o','g','i','c','a','l','n','o','t', 0, + 'm','u', 0, + 't','r','a','d','e','m','a','r','k', 0, + 'E','t','h', 0, + 'o','n','e','h','a','l','f', 0, + 'p','l','u','s','m','i','n','u','s', 0, + 'T','h','o','r','n', 0, + 'o','n','e','q','u','a','r','t','e','r', 0, + 'd','i','v','i','d','e', 0, + 'b','r','o','k','e','n','b','a','r', 0, + 'd','e','g','r','e','e', 0, + 't','h','o','r','n', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s', 0, + 't','w','o','s','u','p','e','r','i','o','r', 0, + 'r','e','g','i','s','t','e','r','e','d', 0, + 'm','i','n','u','s', 0, + 'e','t','h', 0, + 'm','u','l','t','i','p','l','y', 0, + 't','h','r','e','e','s','u','p','e','r','i','o','r', 0, + 'c','o','p','y','r','i','g','h','t', 0, + 'A','a','c','u','t','e', 0, + 'A','c','i','r','c','u','m','f','l','e','x', 0, + 'A','d','i','e','r','e','s','i','s', 0, + 'A','g','r','a','v','e', 0, + 'A','r','i','n','g', 0, + 'A','t','i','l','d','e', 0, + 'C','c','e','d','i','l','l','a', 0, + 'E','a','c','u','t','e', 0, + 'E','c','i','r','c','u','m','f','l','e','x', 0, + 'E','d','i','e','r','e','s','i','s', 0, + 'E','g','r','a','v','e', 0, + 'I','a','c','u','t','e', 0, + 'I','c','i','r','c','u','m','f','l','e','x', 0, + 'I','d','i','e','r','e','s','i','s', 0, + 'I','g','r','a','v','e', 0, + 'N','t','i','l','d','e', 0, + 'O','a','c','u','t','e', 0, + 'O','c','i','r','c','u','m','f','l','e','x', 0, + 'O','d','i','e','r','e','s','i','s', 0, + 'O','g','r','a','v','e', 0, + 'O','t','i','l','d','e', 0, + 'S','c','a','r','o','n', 0, + 'U','a','c','u','t','e', 0, + 'U','c','i','r','c','u','m','f','l','e','x', 0, + 'U','d','i','e','r','e','s','i','s', 0, + 'U','g','r','a','v','e', 0, + 'Y','a','c','u','t','e', 0, + 'Y','d','i','e','r','e','s','i','s', 0, + 'Z','c','a','r','o','n', 0, + 'a','a','c','u','t','e', 0, + 'a','c','i','r','c','u','m','f','l','e','x', 0, + 'a','d','i','e','r','e','s','i','s', 0, + 'a','g','r','a','v','e', 0, + 'a','r','i','n','g', 0, + 'a','t','i','l','d','e', 0, + 'c','c','e','d','i','l','l','a', 0, + 'e','a','c','u','t','e', 0, + 'e','c','i','r','c','u','m','f','l','e','x', 0, + 'e','d','i','e','r','e','s','i','s', 0, + 'e','g','r','a','v','e', 0, + 'i','a','c','u','t','e', 0, + 'i','c','i','r','c','u','m','f','l','e','x', 0, + 'i','d','i','e','r','e','s','i','s', 0, + 'i','g','r','a','v','e', 0, + 'n','t','i','l','d','e', 0, + 'o','a','c','u','t','e', 0, + 'o','c','i','r','c','u','m','f','l','e','x', 0, + 'o','d','i','e','r','e','s','i','s', 0, + 'o','g','r','a','v','e', 0, + 'o','t','i','l','d','e', 0, + 's','c','a','r','o','n', 0, + 'u','a','c','u','t','e', 0, + 'u','c','i','r','c','u','m','f','l','e','x', 0, + 'u','d','i','e','r','e','s','i','s', 0, + 'u','g','r','a','v','e', 0, + 'y','a','c','u','t','e', 0, + 'y','d','i','e','r','e','s','i','s', 0, + 'z','c','a','r','o','n', 0, + 'e','x','c','l','a','m','s','m','a','l','l', 0, + 'H','u','n','g','a','r','u','m','l','a','u','t','s','m','a','l','l', 0, + 'd','o','l','l','a','r','o','l','d','s','t','y','l','e', 0, + 'd','o','l','l','a','r','s','u','p','e','r','i','o','r', 0, + 'a','m','p','e','r','s','a','n','d','s','m','a','l','l', 0, + 'A','c','u','t','e','s','m','a','l','l', 0, + 'p','a','r','e','n','l','e','f','t','s','u','p','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 't','w','o','d','o','t','e','n','l','e','a','d','e','r', 0, + 'o','n','e','d','o','t','e','n','l','e','a','d','e','r', 0, + 'z','e','r','o','o','l','d','s','t','y','l','e', 0, + 'o','n','e','o','l','d','s','t','y','l','e', 0, + 't','w','o','o','l','d','s','t','y','l','e', 0, + 't','h','r','e','e','o','l','d','s','t','y','l','e', 0, + 'f','o','u','r','o','l','d','s','t','y','l','e', 0, + 'f','i','v','e','o','l','d','s','t','y','l','e', 0, + 's','i','x','o','l','d','s','t','y','l','e', 0, + 's','e','v','e','n','o','l','d','s','t','y','l','e', 0, + 'e','i','g','h','t','o','l','d','s','t','y','l','e', 0, + 'n','i','n','e','o','l','d','s','t','y','l','e', 0, + 'c','o','m','m','a','s','u','p','e','r','i','o','r', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s','e','m','d','a','s','h', 0, + 'p','e','r','i','o','d','s','u','p','e','r','i','o','r', 0, + 'q','u','e','s','t','i','o','n','s','m','a','l','l', 0, + 'a','s','u','p','e','r','i','o','r', 0, + 'b','s','u','p','e','r','i','o','r', 0, + 'c','e','n','t','s','u','p','e','r','i','o','r', 0, + 'd','s','u','p','e','r','i','o','r', 0, + 'e','s','u','p','e','r','i','o','r', 0, + 'i','s','u','p','e','r','i','o','r', 0, + 'l','s','u','p','e','r','i','o','r', 0, + 'm','s','u','p','e','r','i','o','r', 0, + 'n','s','u','p','e','r','i','o','r', 0, + 'o','s','u','p','e','r','i','o','r', 0, + 'r','s','u','p','e','r','i','o','r', 0, + 's','s','u','p','e','r','i','o','r', 0, + 't','s','u','p','e','r','i','o','r', 0, + 'f','f', 0, + 'f','f','i', 0, + 'f','f','l', 0, + 'p','a','r','e','n','l','e','f','t','i','n','f','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'C','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'h','y','p','h','e','n','s','u','p','e','r','i','o','r', 0, + 'G','r','a','v','e','s','m','a','l','l', 0, + 'A','s','m','a','l','l', 0, + 'B','s','m','a','l','l', 0, + 'C','s','m','a','l','l', 0, + 'D','s','m','a','l','l', 0, + 'E','s','m','a','l','l', 0, + 'F','s','m','a','l','l', 0, + 'G','s','m','a','l','l', 0, + 'H','s','m','a','l','l', 0, + 'I','s','m','a','l','l', 0, + 'J','s','m','a','l','l', 0, + 'K','s','m','a','l','l', 0, + 'L','s','m','a','l','l', 0, + 'M','s','m','a','l','l', 0, + 'N','s','m','a','l','l', 0, + 'O','s','m','a','l','l', 0, + 'P','s','m','a','l','l', 0, + 'Q','s','m','a','l','l', 0, + 'R','s','m','a','l','l', 0, + 'S','s','m','a','l','l', 0, + 'T','s','m','a','l','l', 0, + 'U','s','m','a','l','l', 0, + 'V','s','m','a','l','l', 0, + 'W','s','m','a','l','l', 0, + 'X','s','m','a','l','l', 0, + 'Y','s','m','a','l','l', 0, + 'Z','s','m','a','l','l', 0, + 'c','o','l','o','n','m','o','n','e','t','a','r','y', 0, + 'o','n','e','f','i','t','t','e','d', 0, + 'r','u','p','i','a','h', 0, + 'T','i','l','d','e','s','m','a','l','l', 0, + 'e','x','c','l','a','m','d','o','w','n','s','m','a','l','l', 0, + 'c','e','n','t','o','l','d','s','t','y','l','e', 0, + 'L','s','l','a','s','h','s','m','a','l','l', 0, + 'S','c','a','r','o','n','s','m','a','l','l', 0, + 'Z','c','a','r','o','n','s','m','a','l','l', 0, + 'D','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'B','r','e','v','e','s','m','a','l','l', 0, + 'C','a','r','o','n','s','m','a','l','l', 0, + 'D','o','t','a','c','c','e','n','t','s','m','a','l','l', 0, + 'M','a','c','r','o','n','s','m','a','l','l', 0, + 'f','i','g','u','r','e','d','a','s','h', 0, + 'h','y','p','h','e','n','i','n','f','e','r','i','o','r', 0, + 'O','g','o','n','e','k','s','m','a','l','l', 0, + 'R','i','n','g','s','m','a','l','l', 0, + 'C','e','d','i','l','l','a','s','m','a','l','l', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n','s','m','a','l','l', 0, + 'o','n','e','e','i','g','h','t','h', 0, + 't','h','r','e','e','e','i','g','h','t','h','s', 0, + 'f','i','v','e','e','i','g','h','t','h','s', 0, + 's','e','v','e','n','e','i','g','h','t','h','s', 0, + 'o','n','e','t','h','i','r','d', 0, + 't','w','o','t','h','i','r','d','s', 0, + 'z','e','r','o','s','u','p','e','r','i','o','r', 0, + 'f','o','u','r','s','u','p','e','r','i','o','r', 0, + 'f','i','v','e','s','u','p','e','r','i','o','r', 0, + 's','i','x','s','u','p','e','r','i','o','r', 0, + 's','e','v','e','n','s','u','p','e','r','i','o','r', 0, + 'e','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 'n','i','n','e','s','u','p','e','r','i','o','r', 0, + 'z','e','r','o','i','n','f','e','r','i','o','r', 0, + 'o','n','e','i','n','f','e','r','i','o','r', 0, + 't','w','o','i','n','f','e','r','i','o','r', 0, + 't','h','r','e','e','i','n','f','e','r','i','o','r', 0, + 'f','o','u','r','i','n','f','e','r','i','o','r', 0, + 'f','i','v','e','i','n','f','e','r','i','o','r', 0, + 's','i','x','i','n','f','e','r','i','o','r', 0, + 's','e','v','e','n','i','n','f','e','r','i','o','r', 0, + 'e','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'n','i','n','e','i','n','f','e','r','i','o','r', 0, + 'c','e','n','t','i','n','f','e','r','i','o','r', 0, + 'd','o','l','l','a','r','i','n','f','e','r','i','o','r', 0, + 'p','e','r','i','o','d','i','n','f','e','r','i','o','r', 0, + 'c','o','m','m','a','i','n','f','e','r','i','o','r', 0, + 'A','g','r','a','v','e','s','m','a','l','l', 0, + 'A','a','c','u','t','e','s','m','a','l','l', 0, + 'A','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'A','t','i','l','d','e','s','m','a','l','l', 0, + 'A','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'A','r','i','n','g','s','m','a','l','l', 0, + 'A','E','s','m','a','l','l', 0, + 'C','c','e','d','i','l','l','a','s','m','a','l','l', 0, + 'E','g','r','a','v','e','s','m','a','l','l', 0, + 'E','a','c','u','t','e','s','m','a','l','l', 0, + 'E','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'E','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'I','g','r','a','v','e','s','m','a','l','l', 0, + 'I','a','c','u','t','e','s','m','a','l','l', 0, + 'I','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'I','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'E','t','h','s','m','a','l','l', 0, + 'N','t','i','l','d','e','s','m','a','l','l', 0, + 'O','g','r','a','v','e','s','m','a','l','l', 0, + 'O','a','c','u','t','e','s','m','a','l','l', 0, + 'O','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'O','t','i','l','d','e','s','m','a','l','l', 0, + 'O','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'O','E','s','m','a','l','l', 0, + 'O','s','l','a','s','h','s','m','a','l','l', 0, + 'U','g','r','a','v','e','s','m','a','l','l', 0, + 'U','a','c','u','t','e','s','m','a','l','l', 0, + 'U','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'U','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'Y','a','c','u','t','e','s','m','a','l','l', 0, + 'T','h','o','r','n','s','m','a','l','l', 0, + 'Y','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + '0','0','1','.','0','0','0', 0, + '0','0','1','.','0','0','1', 0, + '0','0','1','.','0','0','2', 0, + '0','0','1','.','0','0','3', 0, + 'B','l','a','c','k', 0, + 'B','o','l','d', 0, + 'B','o','o','k', 0, + 'L','i','g','h','t', 0, + 'M','e','d','i','u','m', 0, + 'R','e','g','u','l','a','r', 0, + 'R','o','m','a','n', 0, + 'S','e','m','i','b','o','l','d', 0, + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + +#define FT_NUM_MAC_NAMES 258 + + /* Values are offsets into the `ft_standard_glyph_names' table */ + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const short ft_mac_names[FT_NUM_MAC_NAMES] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 253, 0, 6, 261, 267, 274, 283, 294, 301, 309, 758, 330, 340, 351, + 360, 365, 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, + 436, 441, 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, + 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, + 528, 530, 532, 534, 536, 538, 540, 552, 562, 575, 587, 979, 608, 610, + 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, + 640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, + 1375,1392,1405,1414,1486,1512,1562,1603,1632,1610,1622,1645,1639,1652, + 1661,1690,1668,1680,1697,1726,1704,1716,1733,1740,1769,1747,1759,1776, + 1790,1819,1797,1809, 839,1263, 707, 712, 741, 881, 871,1160,1302,1346, + 1197, 985,1031, 23,1086,1108, 32,1219, 41, 51, 730,1194, 64, 76, + 86, 94, 97,1089,1118, 106,1131,1150, 966, 696,1183, 112, 734, 120, + 132, 783, 930, 945, 138,1385,1398,1529,1115,1157, 832,1079, 770, 916, + 598, 319,1246, 155,1833,1586, 721, 749, 797, 811, 826, 829, 846, 856, + 888, 903, 954,1363,1421,1356,1433,1443,1450,1457,1469,1479,1493,1500, + 163,1522,1543,1550,1572,1134, 991,1002,1008,1015,1021,1040,1045,1053, + 1066,1073,1101,1143,1536,1783,1596,1843,1253,1207,1319,1579,1826,1229, + 1270,1313,1323,1171,1290,1332,1211,1235,1276, 169, 175, 182, 189, 200, + 209, 218, 225, 232, 239, 246 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + +#define FT_NUM_SID_NAMES 391 + + /* Values are offsets into the `ft_standard_glyph_names' table */ + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const short ft_sid_names[FT_NUM_SID_NAMES] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 253, 261, 267, 274, 283, 294, 301, 309, 319, 330, 340, 351, 360, 365, + 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, 436, 441, + 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, 500, 502, + 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, + 532, 534, 536, 538, 540, 552, 562, 575, 587, 598, 608, 610, 612, 614, + 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 642, + 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, 696, 707, + 712, 721, 730, 734, 741, 749, 758, 770, 783, 797, 811, 826, 829, 832, + 839, 846, 856, 871, 881, 888, 903, 916, 930, 945, 954, 966, 979, 985, + 991,1002,1008,1015,1021,1031,1040,1045,1053,1066,1073,1079,1086,1089, + 1101,1108,1115,1118,1131,1134,1143,1150,1157,1160,1171,1183,1194,1197, + 1207,1211,1219,1229,1235,1246,1253,1263,1270,1276,1290,1302,1313,1319, + 1323,1332,1346,1356,1363,1375,1385,1392,1398,1405,1414,1421,1433,1443, + 1450,1457,1469,1479,1486,1493,1500,1512,1522,1529,1536,1543,1550,1562, + 1572,1579,1586,1596,1603,1610,1622,1632,1639,1645,1652,1661,1668,1680, + 1690,1697,1704,1716,1726,1733,1740,1747,1759,1769,1776,1783,1790,1797, + 1809,1819,1826,1833,1843,1850,1862,1880,1895,1910,1925,1936,1954,1973, + 1988,2003,2016,2028,2040,2054,2067,2080,2092,2106,2120,2133,2147,2167, + 2182,2196,2206,2216,2229,2239,2249,2259,2269,2279,2289,2299,2309,2319, + 2329,2332,2336,2340,2358,2377,2393,2408,2419,2426,2433,2440,2447,2454, + 2461,2468,2475,2482,2489,2496,2503,2510,2517,2524,2531,2538,2545,2552, + 2559,2566,2573,2580,2587,2594,2601,2615,2625,2632,2643,2659,2672,2684, + 2696,2708,2722,2733,2744,2759,2771,2782,2797,2809,2819,2832,2850,2860, + 2873,2885,2898,2907,2917,2930,2943,2956,2968,2982,2996,3009,3022,3034, + 3046,3060,3073,3086,3098,3112,3126,3139,3152,3167,3182,3196,3208,3220, + 3237,3249,3264,3275,3283,3297,3309,3321,3338,3353,3365,3377,3394,3409, + 3418,3430,3442,3454,3471,3483,3498,3506,3518,3530,3542,3559,3574,3586, + 3597,3612,3620,3628,3636,3644,3650,3655,3660,3666,3673,3681,3687 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + + /* the following are indices into the SID name table */ +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const unsigned short t1_standard_encoding[256] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110, + 0,111,112,113,114, 0,115,116,117,118,119,120,121,122, 0,123, + 0,124,125,126,127,128,129,130,131, 0,132,133, 0,134,135,136, + 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,138, 0,139, 0, 0, 0, 0,140,141,142,143, 0, 0, 0, 0, + 0,144, 0, 0, 0,145, 0, 0,146,147,148,149, 0, 0, 0, 0 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + + /* the following are indices into the SID name table */ +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const unsigned short t1_expert_encoding[256] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1,229,230, 0,231,232,233,234,235,236,237,238, 13, 14, 15, 99, + 239,240,241,242,243,244,245,246,247,248, 27, 28,249,250,251,252, + 0,253,254,255,256,257, 0, 0, 0,258, 0, 0,259,260,261,262, + 0, 0,263,264,265, 0,266,109,110,267,268,269, 0,270,271,272, + 273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288, + 289,290,291,292,293,294,295,296,297,298,299,300,301,302,303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,304,305,306, 0, 0,307,308,309,310,311, 0,312, 0, 0,313, + 0, 0,314,315, 0, 0,316,317,318, 0, 0, 0,158,155,163,319, + 320,321,322,323,324,325, 0, 0,326,150,164,169,327,328,329,330, + 331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346, + 347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362, + 363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + + /* + * This table is a compressed version of the Adobe Glyph List (AGL), + * optimized for efficient searching. It has been generated by the + * `glnames.py' python script located in the `src/tools' directory. + * + * The lookup function to get the Unicode value for a given string + * is defined below the table. + */ + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const unsigned char ft_adobe_glyph_list[55997L] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 0, 52, 0,106, 2,167, 3, 63, 4,220, 6,125, 9,143, 10, 23, + 11,137, 12,199, 14,246, 15, 87, 16,233, 17,219, 18,104, 19, 88, + 22,110, 23, 32, 23, 71, 24, 77, 27,156, 29, 73, 31,247, 32,107, + 32,222, 33, 55, 34,154, 35,218, 58, 10, 64,122, 72,188, 80,109, + 88,104, 93, 61, 98,168,106, 91,114,111,115,237,122,180,127,255, + 135,164,143,132,149,213,158,108,161,115,168,175,183,147,197,199, + 202, 25,204,166,208,209,209, 81,215, 26, 65,143, 0, 65, 0,140, + 0,175, 0,193, 1, 15, 1,147, 1,233, 1,251, 2, 7, 2, 40, + 2, 57, 2, 82, 2, 91, 2,128, 2,136, 2,154, 69,131, 0,198, + 0,150, 0,158, 0,167,225,227,245,244,101,128, 1,252,237,225, + 227,242,239,110,128, 1,226,243,237,225,236,108,128,247,230,225, + 227,245,244,101,129, 0,193, 0,185,243,237,225,236,108,128,247, + 225,226,242,229,246,101,134, 1, 2, 0,213, 0,221, 0,232, 0, + 243, 0,251, 1, 7,225,227,245,244,101,128, 30,174,227,249,242, + 233,236,236,233, 99,128, 4,208,228,239,244,226,229,236,239,119, + 128, 30,182,231,242,225,246,101,128, 30,176,232,239,239,235,225, + 226,239,246,101,128, 30,178,244,233,236,228,101,128, 30,180, 99, + 4, 1, 25, 1, 32, 1,121, 1,137,225,242,239,110,128, 1,205, + 233,242, 99, 2, 1, 40, 1, 45,236,101,128, 36,182,245,237,230, + 236,229,120,134, 0,194, 1, 66, 1, 74, 1, 85, 1, 93, 1,105, + 1,113,225,227,245,244,101,128, 30,164,228,239,244,226,229,236, + 239,119,128, 30,172,231,242,225,246,101,128, 30,166,232,239,239, + 235,225,226,239,246,101,128, 30,168,243,237,225,236,108,128,247, + 226,244,233,236,228,101,128, 30,170,245,244,101,129,246,201, 1, + 129,243,237,225,236,108,128,247,180,249,242,233,236,236,233, 99, + 128, 4, 16,100, 3, 1,155, 1,165, 1,209,226,236,231,242,225, + 246,101,128, 2, 0,233,229,242,229,243,233,115,131, 0,196, 1, + 181, 1,192, 1,201,227,249,242,233,236,236,233, 99,128, 4,210, + 237,225,227,242,239,110,128, 1,222,243,237,225,236,108,128,247, + 228,239,116, 2, 1,216, 1,224,226,229,236,239,119,128, 30,160, + 237,225,227,242,239,110,128, 1,224,231,242,225,246,101,129, 0, + 192, 1,243,243,237,225,236,108,128,247,224,232,239,239,235,225, + 226,239,246,101,128, 30,162,105, 2, 2, 13, 2, 25,229,227,249, + 242,233,236,236,233, 99,128, 4,212,238,246,229,242,244,229,228, + 226,242,229,246,101,128, 2, 2,236,240,232, 97,129, 3,145, 2, + 49,244,239,238,239,115,128, 3,134,109, 2, 2, 63, 2, 71,225, + 227,242,239,110,128, 1, 0,239,238,239,243,240,225,227,101,128, + 255, 33,239,231,239,238,229,107,128, 1, 4,242,233,238,103,131, + 0,197, 2,104, 2,112, 2,120,225,227,245,244,101,128, 1,250, + 226,229,236,239,119,128, 30, 0,243,237,225,236,108,128,247,229, + 243,237,225,236,108,128,247, 97,244,233,236,228,101,129, 0,195, + 2,146,243,237,225,236,108,128,247,227,249,226,225,242,237,229, + 238,233,225,110,128, 5, 49, 66,137, 0, 66, 2,189, 2,198, 2, + 223, 3, 3, 3, 10, 3, 22, 3, 34, 3, 46, 3, 54,227,233,242, + 227,236,101,128, 36,183,228,239,116, 2, 2,206, 2,215,225,227, + 227,229,238,116,128, 30, 2,226,229,236,239,119,128, 30, 4,101, + 3, 2,231, 2,242, 2,254,227,249,242,233,236,236,233, 99,128, + 4, 17,238,225,242,237,229,238,233,225,110,128, 5, 50,244, 97, + 128, 3,146,232,239,239,107,128, 1,129,236,233,238,229,226,229, + 236,239,119,128, 30, 6,237,239,238,239,243,240,225,227,101,128, + 255, 34,242,229,246,229,243,237,225,236,108,128,246,244,243,237, + 225,236,108,128,247, 98,244,239,240,226,225,114,128, 1,130, 67, + 137, 0, 67, 3, 85, 3,127, 3,193, 3,210, 3,224, 4,171, 4, + 188, 4,200, 4,212, 97, 3, 3, 93, 3,104, 3,111,225,242,237, + 229,238,233,225,110,128, 5, 62,227,245,244,101,128, 1, 6,242, + 239,110,129,246,202, 3,119,243,237,225,236,108,128,246,245, 99, + 3, 3,135, 3,142, 3,171,225,242,239,110,128, 1, 12,229,228, + 233,236,236, 97,130, 0,199, 3,155, 3,163,225,227,245,244,101, + 128, 30, 8,243,237,225,236,108,128,247,231,233,242, 99, 2, 3, + 179, 3,184,236,101,128, 36,184,245,237,230,236,229,120,128, 1, + 8,228,239,116,129, 1, 10, 3,201,225,227,227,229,238,116,128, + 1, 10,229,228,233,236,236,225,243,237,225,236,108,128,247,184, + 104, 4, 3,234, 3,246, 4,161, 4,165,225,225,242,237,229,238, + 233,225,110,128, 5, 73,101, 6, 4, 4, 4, 24, 4, 35, 4,103, + 4,115, 4,136,225,226,235,232,225,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,188,227,249,242,233,236,236,233, 99, + 128, 4, 39,100, 2, 4, 41, 4, 85,229,243,227,229,238,228,229, + 114, 2, 4, 54, 4, 74,225,226,235,232,225,243,233,225,238,227, + 249,242,233,236,236,233, 99,128, 4,190,227,249,242,233,236,236, + 233, 99,128, 4,182,233,229,242,229,243,233,243,227,249,242,233, + 236,236,233, 99,128, 4,244,232,225,242,237,229,238,233,225,110, + 128, 5, 67,235,232,225,235,225,243,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,203,246,229,242,244,233,227,225,236, + 243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4, + 184,105,128, 3,167,239,239,107,128, 1,135,233,242,227,245,237, + 230,236,229,248,243,237,225,236,108,128,246,246,237,239,238,239, + 243,240,225,227,101,128,255, 35,239,225,242,237,229,238,233,225, + 110,128, 5, 81,243,237,225,236,108,128,247, 99, 68,142, 0, 68, + 4,252, 5, 10, 5, 36, 5, 96, 5,121, 5,166, 5,173, 5,231, + 5,244, 6, 0, 6, 12, 6, 28, 6, 48, 6, 57, 90,129, 1,241, + 5, 2,227,225,242,239,110,128, 1,196, 97, 2, 5, 16, 5, 27, + 225,242,237,229,238,233,225,110,128, 5, 52,230,242,233,227,225, + 110,128, 1,137, 99, 4, 5, 46, 5, 53, 5, 62, 5, 89,225,242, + 239,110,128, 1, 14,229,228,233,236,236, 97,128, 30, 16,233,242, + 99, 2, 5, 70, 5, 75,236,101,128, 36,185,245,237,230,236,229, + 248,226,229,236,239,119,128, 30, 18,242,239,225,116,128, 1, 16, + 228,239,116, 2, 5,104, 5,113,225,227,227,229,238,116,128, 30, + 10,226,229,236,239,119,128, 30, 12,101, 3, 5,129, 5,140, 5, + 150,227,249,242,233,236,236,233, 99,128, 4, 20,233,227,239,240, + 244,233, 99,128, 3,238,236,244, 97,129, 34, 6, 5,158,231,242, + 229,229,107,128, 3,148,232,239,239,107,128, 1,138,105, 2, 5, + 179, 5,218,229,242,229,243,233,115,131,246,203, 5,194, 5,202, + 5,210,193,227,245,244,101,128,246,204,199,242,225,246,101,128, + 246,205,243,237,225,236,108,128,247,168,231,225,237,237,225,231, + 242,229,229,107,128, 3,220,234,229,227,249,242,233,236,236,233, + 99,128, 4, 2,236,233,238,229,226,229,236,239,119,128, 30, 14, + 237,239,238,239,243,240,225,227,101,128,255, 36,239,244,225,227, + 227,229,238,244,243,237,225,236,108,128,246,247,115, 2, 6, 34, + 6, 41,236,225,243,104,128, 1, 16,237,225,236,108,128,247,100, + 244,239,240,226,225,114,128, 1,139,122,131, 1,242, 6, 67, 6, + 75, 6,112,227,225,242,239,110,128, 1,197,101, 2, 6, 81, 6, + 101,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,224,227,249,242,233,236,236,233, 99,128, 4, 5, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 15, 69,146, 0, + 69, 6,165, 6,183, 6,191, 7, 89, 7,153, 7,165, 7,183, 7, + 211, 8, 7, 8, 36, 8, 94, 8,169, 8,189, 8,208, 8,248, 9, + 44, 9,109, 9,115,225,227,245,244,101,129, 0,201, 6,175,243, + 237,225,236,108,128,247,233,226,242,229,246,101,128, 1, 20, 99, + 5, 6,203, 6,210, 6,224, 6,236, 7, 79,225,242,239,110,128, + 1, 26,229,228,233,236,236,225,226,242,229,246,101,128, 30, 28, + 232,225,242,237,229,238,233,225,110,128, 5, 53,233,242, 99, 2, + 6,244, 6,249,236,101,128, 36,186,245,237,230,236,229,120,135, + 0,202, 7, 16, 7, 24, 7, 32, 7, 43, 7, 51, 7, 63, 7, 71, + 225,227,245,244,101,128, 30,190,226,229,236,239,119,128, 30, 24, + 228,239,244,226,229,236,239,119,128, 30,198,231,242,225,246,101, + 128, 30,192,232,239,239,235,225,226,239,246,101,128, 30,194,243, + 237,225,236,108,128,247,234,244,233,236,228,101,128, 30,196,249, + 242,233,236,236,233, 99,128, 4, 4,100, 3, 7, 97, 7,107, 7, + 127,226,236,231,242,225,246,101,128, 2, 4,233,229,242,229,243, + 233,115,129, 0,203, 7,119,243,237,225,236,108,128,247,235,239, + 116,130, 1, 22, 7,136, 7,145,225,227,227,229,238,116,128, 1, + 22,226,229,236,239,119,128, 30,184,230,227,249,242,233,236,236, + 233, 99,128, 4, 36,231,242,225,246,101,129, 0,200, 7,175,243, + 237,225,236,108,128,247,232,104, 2, 7,189, 7,200,225,242,237, + 229,238,233,225,110,128, 5, 55,239,239,235,225,226,239,246,101, + 128, 30,186,105, 3, 7,219, 7,230, 7,245,231,232,244,242,239, + 237,225,110,128, 33,103,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 6,239,244,233,230,233,229,228,227,249,242,233, + 236,236,233, 99,128, 4,100,108, 2, 8, 13, 8, 24,227,249,242, + 233,236,236,233, 99,128, 4, 27,229,246,229,238,242,239,237,225, + 110,128, 33,106,109, 3, 8, 44, 8, 72, 8, 83,225,227,242,239, + 110,130, 1, 18, 8, 56, 8, 64,225,227,245,244,101,128, 30, 22, + 231,242,225,246,101,128, 30, 20,227,249,242,233,236,236,233, 99, + 128, 4, 28,239,238,239,243,240,225,227,101,128,255, 37,110, 4, + 8,104, 8,115, 8,135, 8,154,227,249,242,233,236,236,233, 99, + 128, 4, 29,228,229,243,227,229,238,228,229,242,227,249,242,233, + 236,236,233, 99,128, 4,162,103,129, 1, 74, 8,141,232,229,227, + 249,242,233,236,236,233, 99,128, 4,164,232,239,239,235,227,249, + 242,233,236,236,233, 99,128, 4,199,111, 2, 8,175, 8,183,231, + 239,238,229,107,128, 1, 24,240,229,110,128, 1,144,240,243,233, + 236,239,110,129, 3,149, 8,200,244,239,238,239,115,128, 3,136, + 114, 2, 8,214, 8,225,227,249,242,233,236,236,233, 99,128, 4, + 32,229,246,229,242,243,229,100,129, 1,142, 8,237,227,249,242, + 233,236,236,233, 99,128, 4, 45,115, 4, 9, 2, 9, 13, 9, 33, + 9, 37,227,249,242,233,236,236,233, 99,128, 4, 33,228,229,243, + 227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4, + 170,104,128, 1,169,237,225,236,108,128,247,101,116, 3, 9, 52, + 9, 78, 9, 92, 97,130, 3,151, 9, 60, 9, 70,242,237,229,238, + 233,225,110,128, 5, 56,244,239,238,239,115,128, 3,137,104,129, + 0,208, 9, 84,243,237,225,236,108,128,247,240,233,236,228,101, + 129, 30,188, 9,101,226,229,236,239,119,128, 30, 26,245,242,111, + 128, 32,172,250,104,130, 1,183, 9,124, 9,132,227,225,242,239, + 110,128, 1,238,242,229,246,229,242,243,229,100,128, 1,184, 70, + 136, 0, 70, 9,163, 9,172, 9,184, 9,212, 9,219, 9,248, 10, + 4, 10, 15,227,233,242,227,236,101,128, 36,187,228,239,244,225, + 227,227,229,238,116,128, 30, 30,101, 2, 9,190, 9,202,232,225, + 242,237,229,238,233,225,110,128, 5, 86,233,227,239,240,244,233, + 99,128, 3,228,232,239,239,107,128, 1,145,105, 2, 9,225, 9, + 238,244,225,227,249,242,233,236,236,233, 99,128, 4,114,246,229, + 242,239,237,225,110,128, 33,100,237,239,238,239,243,240,225,227, + 101,128,255, 38,239,245,242,242,239,237,225,110,128, 33, 99,243, + 237,225,236,108,128,247,102, 71,140, 0, 71, 10, 51, 10, 61, 10, + 107, 10,115, 10,176, 10,193, 10,205, 11, 39, 11, 52, 11, 65, 11, + 90, 11,107,194,243,241,245,225,242,101,128, 51,135, 97, 3, 10, + 69, 10, 76, 10, 94,227,245,244,101,128, 1,244,237,237, 97,129, + 3,147, 10, 84,225,230,242,233,227,225,110,128, 1,148,238,231, + 233,225,227,239,240,244,233, 99,128, 3,234,226,242,229,246,101, + 128, 1, 30, 99, 4, 10,125, 10,132, 10,141, 10,163,225,242,239, + 110,128, 1,230,229,228,233,236,236, 97,128, 1, 34,233,242, 99, + 2, 10,149, 10,154,236,101,128, 36,188,245,237,230,236,229,120, + 128, 1, 28,239,237,237,225,225,227,227,229,238,116,128, 1, 34, + 228,239,116,129, 1, 32, 10,184,225,227,227,229,238,116,128, 1, + 32,229,227,249,242,233,236,236,233, 99,128, 4, 19,104, 3, 10, + 213, 10,226, 11, 33,225,228,225,242,237,229,238,233,225,110,128, + 5, 66,101, 3, 10,234, 10,255, 11, 16,237,233,228,228,236,229, + 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,148,243, + 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,146, + 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, + 144,239,239,107,128, 1,147,233,237,225,242,237,229,238,233,225, + 110,128, 5, 51,234,229,227,249,242,233,236,236,233, 99,128, 4, + 3,109, 2, 11, 71, 11, 79,225,227,242,239,110,128, 30, 32,239, + 238,239,243,240,225,227,101,128,255, 39,242,225,246,101,129,246, + 206, 11, 99,243,237,225,236,108,128,247, 96,115, 2, 11,113, 11, + 129,237,225,236,108,129,247,103, 11,122,232,239,239,107,128, 2, + 155,244,242,239,235,101,128, 1,228, 72,140, 0, 72, 11,165, 11, + 190, 11,198, 11,208, 12, 17, 12, 40, 12, 77, 12,117, 12,129, 12, + 157, 12,165, 12,189,177,184, 53, 3, 11,175, 11,180, 11,185,179, + 51,128, 37,207,180, 51,128, 37,170,181, 49,128, 37,171,178,178, + 176,183, 51,128, 37,161,208,243,241,245,225,242,101,128, 51,203, + 97, 3, 11,216, 11,236, 12, 0,225,226,235,232,225,243,233,225, + 238,227,249,242,233,236,236,233, 99,128, 4,168,228,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,178, + 242,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, 4, + 42, 98, 2, 12, 23, 12, 28,225,114,128, 1, 38,242,229,246,229, + 226,229,236,239,119,128, 30, 42, 99, 2, 12, 46, 12, 55,229,228, + 233,236,236, 97,128, 30, 40,233,242, 99, 2, 12, 63, 12, 68,236, + 101,128, 36,189,245,237,230,236,229,120,128, 1, 36,100, 2, 12, + 83, 12, 93,233,229,242,229,243,233,115,128, 30, 38,239,116, 2, + 12,100, 12,109,225,227,227,229,238,116,128, 30, 34,226,229,236, + 239,119,128, 30, 36,237,239,238,239,243,240,225,227,101,128,255, + 40,111, 2, 12,135, 12,146,225,242,237,229,238,233,225,110,128, + 5, 64,242,233,227,239,240,244,233, 99,128, 3,232,243,237,225, + 236,108,128,247,104,245,238,231,225,242,245,237,236,225,245,116, + 129,246,207, 12,181,243,237,225,236,108,128,246,248,250,243,241, + 245,225,242,101,128, 51,144, 73,146, 0, 73, 12,239, 12,251, 12, + 255, 13, 11, 13, 29, 13, 37, 13, 94, 13,181, 13,214, 13,224, 13, + 242, 13,254, 14, 48, 14, 86, 14, 99, 14,166, 14,187, 14,205,193, + 227,249,242,233,236,236,233, 99,128, 4, 47, 74,128, 1, 50,213, + 227,249,242,233,236,236,233, 99,128, 4, 46,225,227,245,244,101, + 129, 0,205, 13, 21,243,237,225,236,108,128,247,237,226,242,229, + 246,101,128, 1, 44, 99, 3, 13, 45, 13, 52, 13, 84,225,242,239, + 110,128, 1,207,233,242, 99, 2, 13, 60, 13, 65,236,101,128, 36, + 190,245,237,230,236,229,120,129, 0,206, 13, 76,243,237,225,236, + 108,128,247,238,249,242,233,236,236,233, 99,128, 4, 6,100, 3, + 13,102, 13,112, 13,155,226,236,231,242,225,246,101,128, 2, 8, + 233,229,242,229,243,233,115,131, 0,207, 13,128, 13,136, 13,147, + 225,227,245,244,101,128, 30, 46,227,249,242,233,236,236,233, 99, + 128, 4,228,243,237,225,236,108,128,247,239,239,116,130, 1, 48, + 13,164, 13,173,225,227,227,229,238,116,128, 1, 48,226,229,236, + 239,119,128, 30,202,101, 2, 13,187, 13,203,226,242,229,246,229, + 227,249,242,233,236,236,233, 99,128, 4,214,227,249,242,233,236, + 236,233, 99,128, 4, 21,230,242,225,235,244,245,114,128, 33, 17, + 231,242,225,246,101,129, 0,204, 13,234,243,237,225,236,108,128, + 247,236,232,239,239,235,225,226,239,246,101,128, 30,200,105, 3, + 14, 6, 14, 17, 14, 32,227,249,242,233,236,236,233, 99,128, 4, + 24,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 10, + 243,232,239,242,244,227,249,242,233,236,236,233, 99,128, 4, 25, + 109, 2, 14, 54, 14, 75,225,227,242,239,110,129, 1, 42, 14, 64, + 227,249,242,233,236,236,233, 99,128, 4,226,239,238,239,243,240, + 225,227,101,128,255, 41,238,233,225,242,237,229,238,233,225,110, + 128, 5, 59,111, 3, 14,107, 14,118, 14,126,227,249,242,233,236, + 236,233, 99,128, 4, 1,231,239,238,229,107,128, 1, 46,244, 97, + 131, 3,153, 14,137, 14,147, 14,158,225,230,242,233,227,225,110, + 128, 1,150,228,233,229,242,229,243,233,115,128, 3,170,244,239, + 238,239,115,128, 3,138,115, 2, 14,172, 14,179,237,225,236,108, + 128,247,105,244,242,239,235,101,128, 1,151,244,233,236,228,101, + 129, 1, 40, 14,197,226,229,236,239,119,128, 30, 44,250,232,233, + 244,243, 97, 2, 14,216, 14,227,227,249,242,233,236,236,233, 99, + 128, 4,116,228,226,236,231,242,225,246,229,227,249,242,233,236, + 236,233, 99,128, 4,118, 74,134, 0, 74, 15, 6, 15, 18, 15, 41, + 15, 53, 15, 67, 15, 79,225,225,242,237,229,238,233,225,110,128, + 5, 65,227,233,242, 99, 2, 15, 27, 15, 32,236,101,128, 36,191, + 245,237,230,236,229,120,128, 1, 52,229,227,249,242,233,236,236, + 233, 99,128, 4, 8,232,229,232,225,242,237,229,238,233,225,110, + 128, 5, 75,237,239,238,239,243,240,225,227,101,128,255, 42,243, + 237,225,236,108,128,247,106, 75,140, 0, 75, 15,115, 15,125, 15, + 135, 16, 18, 16, 65, 16, 76, 16,106, 16,143, 16,156, 16,168, 16, + 180, 16,208,194,243,241,245,225,242,101,128, 51,133,203,243,241, + 245,225,242,101,128, 51,205, 97, 7, 15,151, 15,169, 15,191, 15, + 211, 15,226, 15,232, 15,249,226,225,243,232,235,233,242,227,249, + 242,233,236,236,233, 99,128, 4,160, 99, 2, 15,175, 15,181,245, + 244,101,128, 30, 48,249,242,233,236,236,233, 99,128, 4, 26,228, + 229,243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99, + 128, 4,154,232,239,239,235,227,249,242,233,236,236,233, 99,128, + 4,195,240,240, 97,128, 3,154,243,244,242,239,235,229,227,249, + 242,233,236,236,233, 99,128, 4,158,246,229,242,244,233,227,225, + 236,243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, + 4,156, 99, 4, 16, 28, 16, 35, 16, 44, 16, 52,225,242,239,110, + 128, 1,232,229,228,233,236,236, 97,128, 1, 54,233,242,227,236, + 101,128, 36,192,239,237,237,225,225,227,227,229,238,116,128, 1, + 54,228,239,244,226,229,236,239,119,128, 30, 50,101, 2, 16, 82, + 16, 94,232,225,242,237,229,238,233,225,110,128, 5, 84,238,225, + 242,237,229,238,233,225,110,128, 5, 63,104, 3, 16,114, 16,126, + 16,137,225,227,249,242,233,236,236,233, 99,128, 4, 37,229,233, + 227,239,240,244,233, 99,128, 3,230,239,239,107,128, 1,152,234, + 229,227,249,242,233,236,236,233, 99,128, 4, 12,236,233,238,229, + 226,229,236,239,119,128, 30, 52,237,239,238,239,243,240,225,227, + 101,128,255, 43,239,240,240, 97, 2, 16,189, 16,200,227,249,242, + 233,236,236,233, 99,128, 4,128,231,242,229,229,107,128, 3,222, + 115, 2, 16,214, 16,226,233,227,249,242,233,236,236,233, 99,128, + 4,110,237,225,236,108,128,247,107, 76,138, 0, 76, 17, 1, 17, + 5, 17, 9, 17, 29, 17, 95, 17,133, 17,147, 17,165, 17,177, 17, + 189, 74,128, 1,199, 76,128,246,191, 97, 2, 17, 15, 17, 22,227, + 245,244,101,128, 1, 57,237,226,228, 97,128, 3,155, 99, 4, 17, + 39, 17, 46, 17, 55, 17, 82,225,242,239,110,128, 1, 61,229,228, + 233,236,236, 97,128, 1, 59,233,242, 99, 2, 17, 63, 17, 68,236, + 101,128, 36,193,245,237,230,236,229,248,226,229,236,239,119,128, + 30, 60,239,237,237,225,225,227,227,229,238,116,128, 1, 59,228, + 239,116,130, 1, 63, 17,105, 17,114,225,227,227,229,238,116,128, + 1, 63,226,229,236,239,119,129, 30, 54, 17,124,237,225,227,242, + 239,110,128, 30, 56,233,247,238,225,242,237,229,238,233,225,110, + 128, 5, 60,106,129, 1,200, 17,153,229,227,249,242,233,236,236, + 233, 99,128, 4, 9,236,233,238,229,226,229,236,239,119,128, 30, + 58,237,239,238,239,243,240,225,227,101,128,255, 44,115, 2, 17, + 195, 17,212,236,225,243,104,129, 1, 65, 17,204,243,237,225,236, + 108,128,246,249,237,225,236,108,128,247,108, 77,137, 0, 77, 17, + 241, 17,251, 18, 24, 18, 33, 18, 58, 18, 71, 18, 83, 18, 91, 18, + 100,194,243,241,245,225,242,101,128, 51,134,225, 99, 2, 18, 2, + 18, 18,242,239,110,129,246,208, 18, 10,243,237,225,236,108,128, + 247,175,245,244,101,128, 30, 62,227,233,242,227,236,101,128, 36, + 194,228,239,116, 2, 18, 41, 18, 50,225,227,227,229,238,116,128, + 30, 64,226,229,236,239,119,128, 30, 66,229,238,225,242,237,229, + 238,233,225,110,128, 5, 68,237,239,238,239,243,240,225,227,101, + 128,255, 45,243,237,225,236,108,128,247,109,244,245,242,238,229, + 100,128, 1,156,117,128, 3,156, 78,141, 0, 78, 18,134, 18,138, + 18,146, 18,212, 18,237, 18,248, 19, 3, 19, 21, 19, 33, 19, 45, + 19, 58, 19, 66, 19, 84, 74,128, 1,202,225,227,245,244,101,128, + 1, 67, 99, 4, 18,156, 18,163, 18,172, 18,199,225,242,239,110, + 128, 1, 71,229,228,233,236,236, 97,128, 1, 69,233,242, 99, 2, + 18,180, 18,185,236,101,128, 36,195,245,237,230,236,229,248,226, + 229,236,239,119,128, 30, 74,239,237,237,225,225,227,227,229,238, + 116,128, 1, 69,228,239,116, 2, 18,220, 18,229,225,227,227,229, + 238,116,128, 30, 68,226,229,236,239,119,128, 30, 70,232,239,239, + 235,236,229,230,116,128, 1,157,233,238,229,242,239,237,225,110, + 128, 33,104,106,129, 1,203, 19, 9,229,227,249,242,233,236,236, + 233, 99,128, 4, 10,236,233,238,229,226,229,236,239,119,128, 30, + 72,237,239,238,239,243,240,225,227,101,128,255, 46,239,247,225, + 242,237,229,238,233,225,110,128, 5, 70,243,237,225,236,108,128, + 247,110,244,233,236,228,101,129, 0,209, 19, 76,243,237,225,236, + 108,128,247,241,117,128, 3,157, 79,141, 0, 79, 19,118, 19,132, + 19,150, 19,203, 20, 78, 20,152, 20,187, 21, 48, 21, 69, 21,213, + 21,223, 21,254, 22, 53, 69,129, 1, 82, 19,124,243,237,225,236, + 108,128,246,250,225,227,245,244,101,129, 0,211, 19,142,243,237, + 225,236,108,128,247,243, 98, 2, 19,156, 19,196,225,242,242,229, + 100, 2, 19,166, 19,177,227,249,242,233,236,236,233, 99,128, 4, + 232,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,234,242,229,246,101,128, 1, 78, 99, 4, 19,213, 19, + 220, 19,235, 20, 68,225,242,239,110,128, 1,209,229,238,244,229, + 242,229,228,244,233,236,228,101,128, 1,159,233,242, 99, 2, 19, + 243, 19,248,236,101,128, 36,196,245,237,230,236,229,120,134, 0, + 212, 20, 13, 20, 21, 20, 32, 20, 40, 20, 52, 20, 60,225,227,245, + 244,101,128, 30,208,228,239,244,226,229,236,239,119,128, 30,216, + 231,242,225,246,101,128, 30,210,232,239,239,235,225,226,239,246, + 101,128, 30,212,243,237,225,236,108,128,247,244,244,233,236,228, + 101,128, 30,214,249,242,233,236,236,233, 99,128, 4, 30,100, 3, + 20, 86, 20,109, 20,142,226,108, 2, 20, 93, 20,101,225,227,245, + 244,101,128, 1, 80,231,242,225,246,101,128, 2, 12,233,229,242, + 229,243,233,115,130, 0,214, 20,123, 20,134,227,249,242,233,236, + 236,233, 99,128, 4,230,243,237,225,236,108,128,247,246,239,244, + 226,229,236,239,119,128, 30,204,103, 2, 20,158, 20,170,239,238, + 229,235,243,237,225,236,108,128,246,251,242,225,246,101,129, 0, + 210, 20,179,243,237,225,236,108,128,247,242,104, 4, 20,197, 20, + 208, 20,212, 21, 34,225,242,237,229,238,233,225,110,128, 5, 85, + 109,128, 33, 38,111, 2, 20,218, 20,228,239,235,225,226,239,246, + 101,128, 30,206,242,110,133, 1,160, 20,243, 20,251, 21, 6, 21, + 14, 21, 26,225,227,245,244,101,128, 30,218,228,239,244,226,229, + 236,239,119,128, 30,226,231,242,225,246,101,128, 30,220,232,239, + 239,235,225,226,239,246,101,128, 30,222,244,233,236,228,101,128, + 30,224,245,238,231,225,242,245,237,236,225,245,116,128, 1, 80, + 105,129, 1,162, 21, 54,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 14,109, 4, 21, 79, 21,107, 21,184, 21,202,225, + 227,242,239,110,130, 1, 76, 21, 91, 21, 99,225,227,245,244,101, + 128, 30, 82,231,242,225,246,101,128, 30, 80,229,231, 97,132, 33, + 38, 21,121, 21,132, 21,140, 21,156,227,249,242,233,236,236,233, + 99,128, 4, 96,231,242,229,229,107,128, 3,169,242,239,245,238, + 228,227,249,242,233,236,236,233, 99,128, 4,122,116, 2, 21,162, + 21,177,233,244,236,239,227,249,242,233,236,236,233, 99,128, 4, + 124,239,238,239,115,128, 3,143,233,227,242,239,110,129, 3,159, + 21,194,244,239,238,239,115,128, 3,140,239,238,239,243,240,225, + 227,101,128,255, 47,238,229,242,239,237,225,110,128, 33, 96,111, + 2, 21,229, 21,248,231,239,238,229,107,129, 1,234, 21,239,237, + 225,227,242,239,110,128, 1,236,240,229,110,128, 1,134,115, 3, + 22, 6, 22, 33, 22, 40,236,225,243,104,130, 0,216, 22, 17, 22, + 25,225,227,245,244,101,128, 1,254,243,237,225,236,108,128,247, + 248,237,225,236,108,128,247,111,244,242,239,235,229,225,227,245, + 244,101,128, 1,254,116, 2, 22, 59, 22, 70,227,249,242,233,236, + 236,233, 99,128, 4,126,233,236,228,101,131, 0,213, 22, 83, 22, + 91, 22,102,225,227,245,244,101,128, 30, 76,228,233,229,242,229, + 243,233,115,128, 30, 78,243,237,225,236,108,128,247,245, 80,136, + 0, 80, 22,130, 22,138, 22,147, 22,159, 22,211, 22,227, 22,246, + 23, 2,225,227,245,244,101,128, 30, 84,227,233,242,227,236,101, + 128, 36,197,228,239,244,225,227,227,229,238,116,128, 30, 86,101, + 3, 22,167, 22,178, 22,190,227,249,242,233,236,236,233, 99,128, + 4, 31,232,225,242,237,229,238,233,225,110,128, 5, 74,237,233, + 228,228,236,229,232,239,239,235,227,249,242,233,236,236,233, 99, + 128, 4,166,104, 2, 22,217, 22,221,105,128, 3,166,239,239,107, + 128, 1,164,105,129, 3,160, 22,233,247,242,225,242,237,229,238, + 233,225,110,128, 5, 83,237,239,238,239,243,240,225,227,101,128, + 255, 48,115, 2, 23, 8, 23, 25,105,129, 3,168, 23, 14,227,249, + 242,233,236,236,233, 99,128, 4,112,237,225,236,108,128,247,112, + 81,131, 0, 81, 23, 42, 23, 51, 23, 63,227,233,242,227,236,101, + 128, 36,198,237,239,238,239,243,240,225,227,101,128,255, 49,243, + 237,225,236,108,128,247,113, 82,138, 0, 82, 23, 95, 23,119, 23, + 166, 23,217, 23,230, 23,240, 23,245, 24, 19, 24, 31, 24, 43, 97, + 2, 23,101, 23,112,225,242,237,229,238,233,225,110,128, 5, 76, + 227,245,244,101,128, 1, 84, 99, 4, 23,129, 23,136, 23,145, 23, + 153,225,242,239,110,128, 1, 88,229,228,233,236,236, 97,128, 1, + 86,233,242,227,236,101,128, 36,199,239,237,237,225,225,227,227, + 229,238,116,128, 1, 86,100, 2, 23,172, 23,182,226,236,231,242, + 225,246,101,128, 2, 16,239,116, 2, 23,189, 23,198,225,227,227, + 229,238,116,128, 30, 88,226,229,236,239,119,129, 30, 90, 23,208, + 237,225,227,242,239,110,128, 30, 92,229,232,225,242,237,229,238, + 233,225,110,128, 5, 80,230,242,225,235,244,245,114,128, 33, 28, + 232,111,128, 3,161,233,110, 2, 23,252, 24, 5,231,243,237,225, + 236,108,128,246,252,246,229,242,244,229,228,226,242,229,246,101, + 128, 2, 18,236,233,238,229,226,229,236,239,119,128, 30, 94,237, + 239,238,239,243,240,225,227,101,128,255, 50,243,237,225,236,108, + 129,247,114, 24, 53,233,238,246,229,242,244,229,100,129, 2,129, + 24, 66,243,245,240,229,242,233,239,114,128, 2,182, 83,139, 0, + 83, 24,103, 26, 17, 26, 55, 26,182, 26,221, 26,250, 27, 84, 27, + 105, 27,117, 27,135, 27,143, 70, 6, 24,117, 24,209, 24,241, 25, + 77, 25,119, 25,221, 48, 9, 24,137, 24,145, 24,153, 24,161, 24, + 169, 24,177, 24,185, 24,193, 24,201,177,176,176,176, 48,128, 37, + 12,178,176,176,176, 48,128, 37, 20,179,176,176,176, 48,128, 37, + 16,180,176,176,176, 48,128, 37, 24,181,176,176,176, 48,128, 37, + 60,182,176,176,176, 48,128, 37, 44,183,176,176,176, 48,128, 37, + 52,184,176,176,176, 48,128, 37, 28,185,176,176,176, 48,128, 37, + 36, 49, 3, 24,217, 24,225, 24,233,176,176,176,176, 48,128, 37, + 0,177,176,176,176, 48,128, 37, 2,185,176,176,176, 48,128, 37, + 97, 50, 9, 25, 5, 25, 13, 25, 21, 25, 29, 25, 37, 25, 45, 25, + 53, 25, 61, 25, 69,176,176,176,176, 48,128, 37, 98,177,176,176, + 176, 48,128, 37, 86,178,176,176,176, 48,128, 37, 85,179,176,176, + 176, 48,128, 37, 99,180,176,176,176, 48,128, 37, 81,181,176,176, + 176, 48,128, 37, 87,182,176,176,176, 48,128, 37, 93,183,176,176, + 176, 48,128, 37, 92,184,176,176,176, 48,128, 37, 91, 51, 4, 25, + 87, 25, 95, 25,103, 25,111,182,176,176,176, 48,128, 37, 94,183, + 176,176,176, 48,128, 37, 95,184,176,176,176, 48,128, 37, 90,185, + 176,176,176, 48,128, 37, 84, 52, 10, 25,141, 25,149, 25,157, 25, + 165, 25,173, 25,181, 25,189, 25,197, 25,205, 25,213,176,176,176, + 176, 48,128, 37,105,177,176,176,176, 48,128, 37,102,178,176,176, + 176, 48,128, 37, 96,179,176,176,176, 48,128, 37, 80,180,176,176, + 176, 48,128, 37,108,181,176,176,176, 48,128, 37,103,182,176,176, + 176, 48,128, 37,104,183,176,176,176, 48,128, 37,100,184,176,176, + 176, 48,128, 37,101,185,176,176,176, 48,128, 37, 89, 53, 5, 25, + 233, 25,241, 25,249, 26, 1, 26, 9,176,176,176,176, 48,128, 37, + 88,177,176,176,176, 48,128, 37, 82,178,176,176,176, 48,128, 37, + 83,179,176,176,176, 48,128, 37,107,180,176,176,176, 48,128, 37, + 106, 97, 2, 26, 23, 26, 44,227,245,244,101,129, 1, 90, 26, 32, + 228,239,244,225,227,227,229,238,116,128, 30,100,237,240,233,231, + 242,229,229,107,128, 3,224, 99, 5, 26, 67, 26, 98, 26,107, 26, + 147, 26,169,225,242,239,110,130, 1, 96, 26, 78, 26, 90,228,239, + 244,225,227,227,229,238,116,128, 30,102,243,237,225,236,108,128, + 246,253,229,228,233,236,236, 97,128, 1, 94,232,247, 97,130, 1, + 143, 26,117, 26,128,227,249,242,233,236,236,233, 99,128, 4,216, + 228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99, + 128, 4,218,233,242, 99, 2, 26,155, 26,160,236,101,128, 36,200, + 245,237,230,236,229,120,128, 1, 92,239,237,237,225,225,227,227, + 229,238,116,128, 2, 24,228,239,116, 2, 26,190, 26,199,225,227, + 227,229,238,116,128, 30, 96,226,229,236,239,119,129, 30, 98, 26, + 209,228,239,244,225,227,227,229,238,116,128, 30,104,101, 2, 26, + 227, 26,239,232,225,242,237,229,238,233,225,110,128, 5, 77,246, + 229,238,242,239,237,225,110,128, 33,102,104, 5, 27, 6, 27, 34, + 27, 48, 27, 59, 27, 72, 97, 2, 27, 12, 27, 23,225,242,237,229, + 238,233,225,110,128, 5, 71,227,249,242,233,236,236,233, 99,128, + 4, 40,227,232,225,227,249,242,233,236,236,233, 99,128, 4, 41, + 229,233,227,239,240,244,233, 99,128, 3,226,232,225,227,249,242, + 233,236,236,233, 99,128, 4,186,233,237,225,227,239,240,244,233, + 99,128, 3,236,105, 2, 27, 90, 27, 96,231,237, 97,128, 3,163, + 248,242,239,237,225,110,128, 33,101,237,239,238,239,243,240,225, + 227,101,128,255, 51,239,230,244,243,233,231,238,227,249,242,233, + 236,236,233, 99,128, 4, 44,243,237,225,236,108,128,247,115,244, + 233,231,237,225,231,242,229,229,107,128, 3,218, 84,141, 0, 84, + 27,186, 27,191, 27,197, 28, 7, 28, 32, 28, 96, 28,147, 28,177, + 28,189, 28,201, 28,246, 29, 6, 29, 46,225,117,128, 3,164,226, + 225,114,128, 1,102, 99, 4, 27,207, 27,214, 27,223, 27,250,225, + 242,239,110,128, 1,100,229,228,233,236,236, 97,128, 1, 98,233, + 242, 99, 2, 27,231, 27,236,236,101,128, 36,201,245,237,230,236, + 229,248,226,229,236,239,119,128, 30,112,239,237,237,225,225,227, + 227,229,238,116,128, 1, 98,228,239,116, 2, 28, 15, 28, 24,225, + 227,227,229,238,116,128, 30,106,226,229,236,239,119,128, 30,108, + 101, 4, 28, 42, 28, 53, 28, 73, 28, 82,227,249,242,233,236,236, + 233, 99,128, 4, 34,228,229,243,227,229,238,228,229,242,227,249, + 242,233,236,236,233, 99,128, 4,172,238,242,239,237,225,110,128, + 33,105,244,243,229,227,249,242,233,236,236,233, 99,128, 4,180, + 104, 3, 28,104, 28,110, 28,136,229,244, 97,128, 3,152,111, 2, + 28,116, 28,121,239,107,128, 1,172,242,110,129, 0,222, 28,128, + 243,237,225,236,108,128,247,254,242,229,229,242,239,237,225,110, + 128, 33, 98,105, 2, 28,153, 28,164,236,228,229,243,237,225,236, + 108,128,246,254,247,238,225,242,237,229,238,233,225,110,128, 5, + 79,236,233,238,229,226,229,236,239,119,128, 30,110,237,239,238, + 239,243,240,225,227,101,128,255, 52,111, 2, 28,207, 28,218,225, + 242,237,229,238,233,225,110,128, 5, 57,238,101, 3, 28,227, 28, + 234, 28,240,230,233,246,101,128, 1,188,243,233,120,128, 1,132, + 244,247,111,128, 1,167,242,229,244,242,239,230,236,229,248,232, + 239,239,107,128, 1,174,115, 3, 29, 14, 29, 26, 29, 39,229,227, + 249,242,233,236,236,233, 99,128, 4, 38,232,229,227,249,242,233, + 236,236,233, 99,128, 4, 11,237,225,236,108,128,247,116,119, 2, + 29, 52, 29, 64,229,236,246,229,242,239,237,225,110,128, 33,107, + 239,242,239,237,225,110,128, 33, 97, 85,142, 0, 85, 29,105, 29, + 123, 29,131, 29,198, 30, 69, 30, 87, 30,198, 30,214, 30,226, 31, + 21, 31, 30, 31,142, 31,149, 31,219,225,227,245,244,101,129, 0, + 218, 29,115,243,237,225,236,108,128,247,250,226,242,229,246,101, + 128, 1,108, 99, 3, 29,139, 29,146, 29,188,225,242,239,110,128, + 1,211,233,242, 99, 2, 29,154, 29,159,236,101,128, 36,202,245, + 237,230,236,229,120,130, 0,219, 29,172, 29,180,226,229,236,239, + 119,128, 30,118,243,237,225,236,108,128,247,251,249,242,233,236, + 236,233, 99,128, 4, 35,100, 3, 29,206, 29,229, 30, 59,226,108, + 2, 29,213, 29,221,225,227,245,244,101,128, 1,112,231,242,225, + 246,101,128, 2, 20,233,229,242,229,243,233,115,134, 0,220, 29, + 251, 30, 3, 30, 11, 30, 34, 30, 42, 30, 51,225,227,245,244,101, + 128, 1,215,226,229,236,239,119,128, 30,114, 99, 2, 30, 17, 30, + 24,225,242,239,110,128, 1,217,249,242,233,236,236,233, 99,128, + 4,240,231,242,225,246,101,128, 1,219,237,225,227,242,239,110, + 128, 1,213,243,237,225,236,108,128,247,252,239,244,226,229,236, + 239,119,128, 30,228,231,242,225,246,101,129, 0,217, 30, 79,243, + 237,225,236,108,128,247,249,104, 2, 30, 93, 30,171,111, 2, 30, + 99, 30,109,239,235,225,226,239,246,101,128, 30,230,242,110,133, + 1,175, 30,124, 30,132, 30,143, 30,151, 30,163,225,227,245,244, + 101,128, 30,232,228,239,244,226,229,236,239,119,128, 30,240,231, + 242,225,246,101,128, 30,234,232,239,239,235,225,226,239,246,101, + 128, 30,236,244,233,236,228,101,128, 30,238,245,238,231,225,242, + 245,237,236,225,245,116,129, 1,112, 30,187,227,249,242,233,236, + 236,233, 99,128, 4,242,233,238,246,229,242,244,229,228,226,242, + 229,246,101,128, 2, 22,235,227,249,242,233,236,236,233, 99,128, + 4,120,109, 2, 30,232, 31, 10,225,227,242,239,110,130, 1,106, + 30,244, 30,255,227,249,242,233,236,236,233, 99,128, 4,238,228, + 233,229,242,229,243,233,115,128, 30,122,239,238,239,243,240,225, + 227,101,128,255, 53,239,231,239,238,229,107,128, 1,114,240,243, + 233,236,239,110,133, 3,165, 31, 49, 31, 53, 31, 90, 31,121, 31, + 134, 49,128, 3,210, 97, 2, 31, 59, 31, 81,227,245,244,229,232, + 239,239,235,243,249,237,226,239,236,231,242,229,229,107,128, 3, + 211,230,242,233,227,225,110,128, 1,177,228,233,229,242,229,243, + 233,115,129, 3,171, 31,103,232,239,239,235,243,249,237,226,239, + 236,231,242,229,229,107,128, 3,212,232,239,239,235,243,249,237, + 226,239,108,128, 3,210,244,239,238,239,115,128, 3,142,242,233, + 238,103,128, 1,110,115, 3, 31,157, 31,172, 31,179,232,239,242, + 244,227,249,242,233,236,236,233, 99,128, 4, 14,237,225,236,108, + 128,247,117,244,242,225,233,231,232,116, 2, 31,191, 31,202,227, + 249,242,233,236,236,233, 99,128, 4,174,243,244,242,239,235,229, + 227,249,242,233,236,236,233, 99,128, 4,176,244,233,236,228,101, + 130, 1,104, 31,231, 31,239,225,227,245,244,101,128, 30,120,226, + 229,236,239,119,128, 30,116, 86,136, 0, 86, 32, 11, 32, 20, 32, + 31, 32, 60, 32, 67, 32, 79, 32, 91, 32, 99,227,233,242,227,236, + 101,128, 36,203,228,239,244,226,229,236,239,119,128, 30,126,101, + 2, 32, 37, 32, 48,227,249,242,233,236,236,233, 99,128, 4, 18, + 247,225,242,237,229,238,233,225,110,128, 5, 78,232,239,239,107, + 128, 1,178,237,239,238,239,243,240,225,227,101,128,255, 54,239, + 225,242,237,229,238,233,225,110,128, 5, 72,243,237,225,236,108, + 128,247,118,244,233,236,228,101,128, 30,124, 87,134, 0, 87, 32, + 123, 32,131, 32,154, 32,194, 32,202, 32,214,225,227,245,244,101, + 128, 30,130,227,233,242, 99, 2, 32,140, 32,145,236,101,128, 36, + 204,245,237,230,236,229,120,128, 1,116,100, 2, 32,160, 32,170, + 233,229,242,229,243,233,115,128, 30,132,239,116, 2, 32,177, 32, + 186,225,227,227,229,238,116,128, 30,134,226,229,236,239,119,128, + 30,136,231,242,225,246,101,128, 30,128,237,239,238,239,243,240, + 225,227,101,128,255, 55,243,237,225,236,108,128,247,119, 88,134, + 0, 88, 32,238, 32,247, 33, 18, 33, 31, 33, 35, 33, 47,227,233, + 242,227,236,101,128, 36,205,100, 2, 32,253, 33, 7,233,229,242, + 229,243,233,115,128, 30,140,239,244,225,227,227,229,238,116,128, + 30,138,229,232,225,242,237,229,238,233,225,110,128, 5, 61,105, + 128, 3,158,237,239,238,239,243,240,225,227,101,128,255, 56,243, + 237,225,236,108,128,247,120, 89,139, 0, 89, 33, 81, 33,116, 33, + 139, 33,189, 33,228, 33,236, 33,253, 34, 40, 34, 52, 34, 60, 34, + 68, 97, 2, 33, 87, 33,104,227,245,244,101,129, 0,221, 33, 96, + 243,237,225,236,108,128,247,253,244,227,249,242,233,236,236,233, + 99,128, 4, 98,227,233,242, 99, 2, 33,125, 33,130,236,101,128, + 36,206,245,237,230,236,229,120,128, 1,118,100, 2, 33,145, 33, + 165,233,229,242,229,243,233,115,129, 1,120, 33,157,243,237,225, + 236,108,128,247,255,239,116, 2, 33,172, 33,181,225,227,227,229, + 238,116,128, 30,142,226,229,236,239,119,128, 30,244,229,114, 2, + 33,196, 33,208,233,227,249,242,233,236,236,233, 99,128, 4, 43, + 245,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,248,231,242,225,246,101,128, 30,242,232,239,239,107, + 129, 1,179, 33,245,225,226,239,246,101,128, 30,246,105, 3, 34, + 5, 34, 16, 34, 27,225,242,237,229,238,233,225,110,128, 5, 69, + 227,249,242,233,236,236,233, 99,128, 4, 7,247,238,225,242,237, + 229,238,233,225,110,128, 5, 82,237,239,238,239,243,240,225,227, + 101,128,255, 57,243,237,225,236,108,128,247,121,244,233,236,228, + 101,128, 30,248,245,115, 2, 34, 75, 34,113,226,233,103, 2, 34, + 83, 34, 94,227,249,242,233,236,236,233, 99,128, 4,106,233,239, + 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, + 108,236,233,244,244,236,101, 2, 34,124, 34,135,227,249,242,233, + 236,236,233, 99,128, 4,102,233,239,244,233,230,233,229,228,227, + 249,242,233,236,236,233, 99,128, 4,104, 90,136, 0, 90, 34,174, + 34,198, 34,243, 35, 14, 35, 81, 35,173, 35,185, 35,197, 97, 2, + 34,180, 34,191,225,242,237,229,238,233,225,110,128, 5, 54,227, + 245,244,101,128, 1,121, 99, 2, 34,204, 34,221,225,242,239,110, + 129, 1,125, 34,213,243,237,225,236,108,128,246,255,233,242, 99, + 2, 34,229, 34,234,236,101,128, 36,207,245,237,230,236,229,120, + 128, 30,144,228,239,116,130, 1,123, 34,253, 35, 6,225,227,227, + 229,238,116,128, 1,123,226,229,236,239,119,128, 30,146,101, 3, + 35, 22, 35, 33, 35, 76,227,249,242,233,236,236,233, 99,128, 4, + 23,100, 2, 35, 39, 35, 58,229,243,227,229,238,228,229,242,227, + 249,242,233,236,236,233, 99,128, 4,152,233,229,242,229,243,233, + 243,227,249,242,233,236,236,233, 99,128, 4,222,244, 97,128, 3, + 150,232,101, 4, 35, 92, 35,103, 35,119, 35,130,225,242,237,229, + 238,233,225,110,128, 5, 58,226,242,229,246,229,227,249,242,233, + 236,236,233, 99,128, 4,193,227,249,242,233,236,236,233, 99,128, + 4, 22,100, 2, 35,136, 35,155,229,243,227,229,238,228,229,242, + 227,249,242,233,236,236,233, 99,128, 4,150,233,229,242,229,243, + 233,243,227,249,242,233,236,236,233, 99,128, 4,220,236,233,238, + 229,226,229,236,239,119,128, 30,148,237,239,238,239,243,240,225, + 227,101,128,255, 58,115, 2, 35,203, 35,210,237,225,236,108,128, + 247,122,244,242,239,235,101,128, 1,181, 97,158, 0, 97, 36, 26, + 38,154, 39, 4, 39, 68, 39,132, 39,196, 40, 4, 40, 68, 40,126, + 40,190, 41, 70, 41,217, 42,137, 42,237, 43, 17, 49,192, 49,229, + 50, 0, 50,225, 51, 7, 52, 96, 52,168, 53,123, 53,132, 54, 5, + 56, 13, 57, 3, 57, 50, 57,201, 57,215, 49,138, 39, 1, 36, 50, + 36,114, 36,154, 36,218, 37, 26, 37, 90, 37,154, 37,218, 38, 26, + 38, 90, 48,138, 39, 33, 36, 74, 36, 78, 36, 82, 36, 86, 36, 90, + 36, 94, 36, 98, 36,102, 36,106, 36,110, 48,128, 39, 94, 49,128, + 39, 97, 50,128, 39, 98, 51,128, 39, 99, 52,128, 39,100, 53,128, + 39, 16, 54,128, 39,101, 55,128, 39,102, 56,128, 39,103, 57,128, + 38, 96, 49,134, 38, 27, 36,130, 36,134, 36,138, 36,142, 36,146, + 36,150, 48,128, 38,101, 49,128, 38,102, 50,128, 38, 99, 55,128, + 39, 9, 56,128, 39, 8, 57,128, 39, 7, 50,138, 38, 30, 36,178, + 36,182, 36,186, 36,190, 36,194, 36,198, 36,202, 36,206, 36,210, + 36,214, 48,128, 36, 96, 49,128, 36, 97, 50,128, 36, 98, 51,128, + 36, 99, 52,128, 36,100, 53,128, 36,101, 54,128, 36,102, 55,128, + 36,103, 56,128, 36,104, 57,128, 36,105, 51,138, 39, 12, 36,242, + 36,246, 36,250, 36,254, 37, 2, 37, 6, 37, 10, 37, 14, 37, 18, + 37, 22, 48,128, 39,118, 49,128, 39,119, 50,128, 39,120, 51,128, + 39,121, 52,128, 39,122, 53,128, 39,123, 54,128, 39,124, 55,128, + 39,125, 56,128, 39,126, 57,128, 39,127, 52,138, 39, 13, 37, 50, + 37, 54, 37, 58, 37, 62, 37, 66, 37, 70, 37, 74, 37, 78, 37, 82, + 37, 86, 48,128, 39,128, 49,128, 39,129, 50,128, 39,130, 51,128, + 39,131, 52,128, 39,132, 53,128, 39,133, 54,128, 39,134, 55,128, + 39,135, 56,128, 39,136, 57,128, 39,137, 53,138, 39, 14, 37,114, + 37,118, 37,122, 37,126, 37,130, 37,134, 37,138, 37,142, 37,146, + 37,150, 48,128, 39,138, 49,128, 39,139, 50,128, 39,140, 51,128, + 39,141, 52,128, 39,142, 53,128, 39,143, 54,128, 39,144, 55,128, + 39,145, 56,128, 39,146, 57,128, 39,147, 54,138, 39, 15, 37,178, + 37,182, 37,186, 37,190, 37,194, 37,198, 37,202, 37,206, 37,210, + 37,214, 48,128, 39,148, 49,128, 33,146, 50,128, 39,163, 51,128, + 33,148, 52,128, 33,149, 53,128, 39,153, 54,128, 39,155, 55,128, + 39,156, 56,128, 39,157, 57,128, 39,158, 55,138, 39, 17, 37,242, + 37,246, 37,250, 37,254, 38, 2, 38, 6, 38, 10, 38, 14, 38, 18, + 38, 22, 48,128, 39,159, 49,128, 39,160, 50,128, 39,161, 51,128, + 39,162, 52,128, 39,164, 53,128, 39,165, 54,128, 39,166, 55,128, + 39,167, 56,128, 39,168, 57,128, 39,169, 56,138, 39, 18, 38, 50, + 38, 54, 38, 58, 38, 62, 38, 66, 38, 70, 38, 74, 38, 78, 38, 82, + 38, 86, 48,128, 39,171, 49,128, 39,173, 50,128, 39,175, 51,128, + 39,178, 52,128, 39,179, 53,128, 39,181, 54,128, 39,184, 55,128, + 39,186, 56,128, 39,187, 57,128, 39,188, 57,138, 39, 19, 38,114, + 38,118, 38,122, 38,126, 38,130, 38,134, 38,138, 38,142, 38,146, + 38,150, 48,128, 39,189, 49,128, 39,190, 50,128, 39,154, 51,128, + 39,170, 52,128, 39,182, 53,128, 39,185, 54,128, 39,152, 55,128, + 39,180, 56,128, 39,183, 57,128, 39,172, 50,138, 39, 2, 38,178, + 38,224, 38,228, 38,232, 38,236, 38,240, 38,244, 38,248, 38,252, + 39, 0, 48,135, 39, 20, 38,196, 38,200, 38,204, 38,208, 38,212, + 38,216, 38,220, 48,128, 39,174, 49,128, 39,177, 50,128, 39, 3, + 51,128, 39, 80, 52,128, 39, 82, 53,128, 39,110, 54,128, 39,112, + 49,128, 39, 21, 50,128, 39, 22, 51,128, 39, 23, 52,128, 39, 24, + 53,128, 39, 25, 54,128, 39, 26, 55,128, 39, 27, 56,128, 39, 28, + 57,128, 39, 34, 51,138, 39, 4, 39, 28, 39, 32, 39, 36, 39, 40, + 39, 44, 39, 48, 39, 52, 39, 56, 39, 60, 39, 64, 48,128, 39, 35, + 49,128, 39, 36, 50,128, 39, 37, 51,128, 39, 38, 52,128, 39, 39, + 53,128, 38, 5, 54,128, 39, 41, 55,128, 39, 42, 56,128, 39, 43, + 57,128, 39, 44, 52,138, 38, 14, 39, 92, 39, 96, 39,100, 39,104, + 39,108, 39,112, 39,116, 39,120, 39,124, 39,128, 48,128, 39, 45, + 49,128, 39, 46, 50,128, 39, 47, 51,128, 39, 48, 52,128, 39, 49, + 53,128, 39, 50, 54,128, 39, 51, 55,128, 39, 52, 56,128, 39, 53, + 57,128, 39, 54, 53,138, 39, 6, 39,156, 39,160, 39,164, 39,168, + 39,172, 39,176, 39,180, 39,184, 39,188, 39,192, 48,128, 39, 55, + 49,128, 39, 56, 50,128, 39, 57, 51,128, 39, 58, 52,128, 39, 59, + 53,128, 39, 60, 54,128, 39, 61, 55,128, 39, 62, 56,128, 39, 63, + 57,128, 39, 64, 54,138, 39, 29, 39,220, 39,224, 39,228, 39,232, + 39,236, 39,240, 39,244, 39,248, 39,252, 40, 0, 48,128, 39, 65, + 49,128, 39, 66, 50,128, 39, 67, 51,128, 39, 68, 52,128, 39, 69, + 53,128, 39, 70, 54,128, 39, 71, 55,128, 39, 72, 56,128, 39, 73, + 57,128, 39, 74, 55,138, 39, 30, 40, 28, 40, 32, 40, 36, 40, 40, + 40, 44, 40, 48, 40, 52, 40, 56, 40, 60, 40, 64, 48,128, 39, 75, + 49,128, 37,207, 50,128, 39, 77, 51,128, 37,160, 52,128, 39, 79, + 53,128, 39, 81, 54,128, 37,178, 55,128, 37,188, 56,128, 37,198, + 57,128, 39, 86, 56,137, 39, 31, 40, 90, 40, 94, 40, 98, 40,102, + 40,106, 40,110, 40,114, 40,118, 40,122, 49,128, 37,215, 50,128, + 39, 88, 51,128, 39, 89, 52,128, 39, 90, 53,128, 39,111, 54,128, + 39,113, 55,128, 39,114, 56,128, 39,115, 57,128, 39,104, 57,138, + 39, 32, 40,150, 40,154, 40,158, 40,162, 40,166, 40,170, 40,174, + 40,178, 40,182, 40,186, 48,128, 39,105, 49,128, 39,108, 50,128, + 39,109, 51,128, 39,106, 52,128, 39,107, 53,128, 39,116, 54,128, + 39,117, 55,128, 39, 91, 56,128, 39, 92, 57,128, 39, 93, 97, 7, + 40,206, 40,216, 40,223, 40,230, 40,255, 41, 15, 41, 26,226,229, + 238,231,225,236,105,128, 9,134,227,245,244,101,128, 0,225,228, + 229,246, 97,128, 9, 6,231,117, 2, 40,237, 40,246,234,225,242, + 225,244,105,128, 10,134,242,237,245,235,232,105,128, 10, 6,237, + 225,244,242,225,231,245,242,237,245,235,232,105,128, 10, 62,242, + 245,243,241,245,225,242,101,128, 51, 3,246,239,247,229,236,243, + 233,231,110, 3, 41, 42, 41, 52, 41, 59,226,229,238,231,225,236, + 105,128, 9,190,228,229,246, 97,128, 9, 62,231,245,234,225,242, + 225,244,105,128, 10,190, 98, 4, 41, 80, 41,121, 41,130, 41,140, + 226,242,229,246,233,225,244,233,239,110, 2, 41, 95, 41,110,237, + 225,242,235,225,242,237,229,238,233,225,110,128, 5, 95,243,233, + 231,238,228,229,246, 97,128, 9,112,229,238,231,225,236,105,128, + 9,133,239,240,239,237,239,230,111,128, 49, 26,242,229,246,101, + 134, 1, 3, 41,159, 41,167, 41,178, 41,189, 41,197, 41,209,225, + 227,245,244,101,128, 30,175,227,249,242,233,236,236,233, 99,128, + 4,209,228,239,244,226,229,236,239,119,128, 30,183,231,242,225, + 246,101,128, 30,177,232,239,239,235,225,226,239,246,101,128, 30, + 179,244,233,236,228,101,128, 30,181, 99, 4, 41,227, 41,234, 42, + 57, 42,127,225,242,239,110,128, 1,206,233,242, 99, 2, 41,242, + 41,247,236,101,128, 36,208,245,237,230,236,229,120,133, 0,226, + 42, 10, 42, 18, 42, 29, 42, 37, 42, 49,225,227,245,244,101,128, + 30,165,228,239,244,226,229,236,239,119,128, 30,173,231,242,225, + 246,101,128, 30,167,232,239,239,235,225,226,239,246,101,128, 30, + 169,244,233,236,228,101,128, 30,171,245,244,101,133, 0,180, 42, + 73, 42, 84, 42,101, 42,108, 42,117,226,229,236,239,247,227,237, + 98,128, 3, 23, 99, 2, 42, 90, 42, 95,237, 98,128, 3, 1,239, + 237, 98,128, 3, 1,228,229,246, 97,128, 9, 84,236,239,247,237, + 239,100,128, 2,207,244,239,238,229,227,237, 98,128, 3, 65,249, + 242,233,236,236,233, 99,128, 4, 48,100, 5, 42,149, 42,159, 42, + 173, 42,179, 42,213,226,236,231,242,225,246,101,128, 2, 1,228, + 225,235,231,245,242,237,245,235,232,105,128, 10,113,229,246, 97, + 128, 9, 5,233,229,242,229,243,233,115,130, 0,228, 42,193, 42, + 204,227,249,242,233,236,236,233, 99,128, 4,211,237,225,227,242, + 239,110,128, 1,223,239,116, 2, 42,220, 42,228,226,229,236,239, + 119,128, 30,161,237,225,227,242,239,110,128, 1,225,101,131, 0, + 230, 42,247, 42,255, 43, 8,225,227,245,244,101,128, 1,253,235, + 239,242,229,225,110,128, 49, 80,237,225,227,242,239,110,128, 1, + 227,230,233,105, 6, 43, 33, 43, 53, 45,246, 45,252, 46, 11, 49, + 111, 48, 2, 43, 39, 43, 46,176,178,176, 56,128, 32, 21,184,185, + 180, 49,128, 32,164,177, 48, 3, 43, 62, 45, 86, 45,221, 48, 9, + 43, 82, 43,102, 43,164, 43,226, 44, 32, 44, 94, 44,156, 44,218, + 45, 24, 49, 3, 43, 90, 43, 94, 43, 98, 55,128, 4, 16, 56,128, + 4, 17, 57,128, 4, 18, 50, 10, 43,124, 43,128, 43,132, 43,136, + 43,140, 43,144, 43,148, 43,152, 43,156, 43,160, 48,128, 4, 19, + 49,128, 4, 20, 50,128, 4, 21, 51,128, 4, 1, 52,128, 4, 22, + 53,128, 4, 23, 54,128, 4, 24, 55,128, 4, 25, 56,128, 4, 26, + 57,128, 4, 27, 51, 10, 43,186, 43,190, 43,194, 43,198, 43,202, + 43,206, 43,210, 43,214, 43,218, 43,222, 48,128, 4, 28, 49,128, + 4, 29, 50,128, 4, 30, 51,128, 4, 31, 52,128, 4, 32, 53,128, + 4, 33, 54,128, 4, 34, 55,128, 4, 35, 56,128, 4, 36, 57,128, + 4, 37, 52, 10, 43,248, 43,252, 44, 0, 44, 4, 44, 8, 44, 12, + 44, 16, 44, 20, 44, 24, 44, 28, 48,128, 4, 38, 49,128, 4, 39, + 50,128, 4, 40, 51,128, 4, 41, 52,128, 4, 42, 53,128, 4, 43, + 54,128, 4, 44, 55,128, 4, 45, 56,128, 4, 46, 57,128, 4, 47, + 53, 10, 44, 54, 44, 58, 44, 62, 44, 66, 44, 70, 44, 74, 44, 78, + 44, 82, 44, 86, 44, 90, 48,128, 4,144, 49,128, 4, 2, 50,128, + 4, 3, 51,128, 4, 4, 52,128, 4, 5, 53,128, 4, 6, 54,128, + 4, 7, 55,128, 4, 8, 56,128, 4, 9, 57,128, 4, 10, 54, 10, + 44,116, 44,120, 44,124, 44,128, 44,132, 44,136, 44,140, 44,144, + 44,148, 44,152, 48,128, 4, 11, 49,128, 4, 12, 50,128, 4, 14, + 51,128,246,196, 52,128,246,197, 53,128, 4, 48, 54,128, 4, 49, + 55,128, 4, 50, 56,128, 4, 51, 57,128, 4, 52, 55, 10, 44,178, + 44,182, 44,186, 44,190, 44,194, 44,198, 44,202, 44,206, 44,210, + 44,214, 48,128, 4, 53, 49,128, 4, 81, 50,128, 4, 54, 51,128, + 4, 55, 52,128, 4, 56, 53,128, 4, 57, 54,128, 4, 58, 55,128, + 4, 59, 56,128, 4, 60, 57,128, 4, 61, 56, 10, 44,240, 44,244, + 44,248, 44,252, 45, 0, 45, 4, 45, 8, 45, 12, 45, 16, 45, 20, + 48,128, 4, 62, 49,128, 4, 63, 50,128, 4, 64, 51,128, 4, 65, + 52,128, 4, 66, 53,128, 4, 67, 54,128, 4, 68, 55,128, 4, 69, + 56,128, 4, 70, 57,128, 4, 71, 57, 10, 45, 46, 45, 50, 45, 54, + 45, 58, 45, 62, 45, 66, 45, 70, 45, 74, 45, 78, 45, 82, 48,128, + 4, 72, 49,128, 4, 73, 50,128, 4, 74, 51,128, 4, 75, 52,128, + 4, 76, 53,128, 4, 77, 54,128, 4, 78, 55,128, 4, 79, 56,128, + 4,145, 57,128, 4, 82, 49, 4, 45, 96, 45,158, 45,163, 45,189, + 48, 10, 45,118, 45,122, 45,126, 45,130, 45,134, 45,138, 45,142, + 45,146, 45,150, 45,154, 48,128, 4, 83, 49,128, 4, 84, 50,128, + 4, 85, 51,128, 4, 86, 52,128, 4, 87, 53,128, 4, 88, 54,128, + 4, 89, 55,128, 4, 90, 56,128, 4, 91, 57,128, 4, 92,177, 48, + 128, 4, 94, 52, 4, 45,173, 45,177, 45,181, 45,185, 53,128, 4, + 15, 54,128, 4, 98, 55,128, 4,114, 56,128, 4,116, 57, 5, 45, + 201, 45,205, 45,209, 45,213, 45,217, 50,128,246,198, 51,128, 4, + 95, 52,128, 4, 99, 53,128, 4,115, 54,128, 4,117, 56, 2, 45, + 227, 45,241, 51, 2, 45,233, 45,237, 49,128,246,199, 50,128,246, + 200,180, 54,128, 4,217,178,185, 57,128, 32, 14,179, 48, 2, 46, + 3, 46, 7, 48,128, 32, 15, 49,128, 32, 13,181, 55, 7, 46, 28, + 46, 98, 47,163, 47,240, 48,197, 49, 34, 49,105, 51, 2, 46, 34, + 46, 48, 56, 2, 46, 40, 46, 44, 49,128, 6,106, 56,128, 6, 12, + 57, 8, 46, 66, 46, 70, 46, 74, 46, 78, 46, 82, 46, 86, 46, 90, + 46, 94, 50,128, 6, 96, 51,128, 6, 97, 52,128, 6, 98, 53,128, + 6, 99, 54,128, 6,100, 55,128, 6,101, 56,128, 6,102, 57,128, + 6,103, 52, 7, 46,114, 46,146, 46,208, 47, 14, 47, 46, 47,102, + 47,158, 48, 5, 46,126, 46,130, 46,134, 46,138, 46,142, 48,128, + 6,104, 49,128, 6,105, 51,128, 6, 27, 55,128, 6, 31, 57,128, + 6, 33, 49, 10, 46,168, 46,172, 46,176, 46,180, 46,184, 46,188, + 46,192, 46,196, 46,200, 46,204, 48,128, 6, 34, 49,128, 6, 35, + 50,128, 6, 36, 51,128, 6, 37, 52,128, 6, 38, 53,128, 6, 39, + 54,128, 6, 40, 55,128, 6, 41, 56,128, 6, 42, 57,128, 6, 43, + 50, 10, 46,230, 46,234, 46,238, 46,242, 46,246, 46,250, 46,254, + 47, 2, 47, 6, 47, 10, 48,128, 6, 44, 49,128, 6, 45, 50,128, + 6, 46, 51,128, 6, 47, 52,128, 6, 48, 53,128, 6, 49, 54,128, + 6, 50, 55,128, 6, 51, 56,128, 6, 52, 57,128, 6, 53, 51, 5, + 47, 26, 47, 30, 47, 34, 47, 38, 47, 42, 48,128, 6, 54, 49,128, + 6, 55, 50,128, 6, 56, 51,128, 6, 57, 52,128, 6, 58, 52, 9, + 47, 66, 47, 70, 47, 74, 47, 78, 47, 82, 47, 86, 47, 90, 47, 94, + 47, 98, 48,128, 6, 64, 49,128, 6, 65, 50,128, 6, 66, 51,128, + 6, 67, 52,128, 6, 68, 53,128, 6, 69, 54,128, 6, 70, 56,128, + 6, 72, 57,128, 6, 73, 53, 9, 47,122, 47,126, 47,130, 47,134, + 47,138, 47,142, 47,146, 47,150, 47,154, 48,128, 6, 74, 49,128, + 6, 75, 50,128, 6, 76, 51,128, 6, 77, 52,128, 6, 78, 53,128, + 6, 79, 54,128, 6, 80, 55,128, 6, 81, 56,128, 6, 82,183, 48, + 128, 6, 71, 53, 3, 47,171, 47,203, 47,235, 48, 5, 47,183, 47, + 187, 47,191, 47,195, 47,199, 53,128, 6,164, 54,128, 6,126, 55, + 128, 6,134, 56,128, 6,152, 57,128, 6,175, 49, 5, 47,215, 47, + 219, 47,223, 47,227, 47,231, 49,128, 6,121, 50,128, 6,136, 51, + 128, 6,145, 52,128, 6,186, 57,128, 6,210,179, 52,128, 6,213, + 54, 7, 48, 0, 48, 5, 48, 10, 48, 15, 48, 53, 48,115, 48,177, + 179, 54,128, 32,170,180, 53,128, 5,190,181, 56,128, 5,195, 54, + 6, 48, 29, 48, 33, 48, 37, 48, 41, 48, 45, 48, 49, 52,128, 5, + 208, 53,128, 5,209, 54,128, 5,210, 55,128, 5,211, 56,128, 5, + 212, 57,128, 5,213, 55, 10, 48, 75, 48, 79, 48, 83, 48, 87, 48, + 91, 48, 95, 48, 99, 48,103, 48,107, 48,111, 48,128, 5,214, 49, + 128, 5,215, 50,128, 5,216, 51,128, 5,217, 52,128, 5,218, 53, + 128, 5,219, 54,128, 5,220, 55,128, 5,221, 56,128, 5,222, 57, + 128, 5,223, 56, 10, 48,137, 48,141, 48,145, 48,149, 48,153, 48, + 157, 48,161, 48,165, 48,169, 48,173, 48,128, 5,224, 49,128, 5, + 225, 50,128, 5,226, 51,128, 5,227, 52,128, 5,228, 53,128, 5, + 229, 54,128, 5,230, 55,128, 5,231, 56,128, 5,232, 57,128, 5, + 233, 57, 3, 48,185, 48,189, 48,193, 48,128, 5,234, 52,128,251, + 42, 53,128,251, 43, 55, 4, 48,207, 48,221, 48,241, 48,246, 48, + 2, 48,213, 48,217, 48,128,251, 75, 53,128,251, 31, 49, 3, 48, + 229, 48,233, 48,237, 54,128, 5,240, 55,128, 5,241, 56,128, 5, + 242,178, 51,128,251, 53, 57, 7, 49, 6, 49, 10, 49, 14, 49, 18, + 49, 22, 49, 26, 49, 30, 51,128, 5,180, 52,128, 5,181, 53,128, + 5,182, 54,128, 5,187, 55,128, 5,184, 56,128, 5,183, 57,128, + 5,176, 56, 3, 49, 42, 49, 86, 49, 91, 48, 7, 49, 58, 49, 62, + 49, 66, 49, 70, 49, 74, 49, 78, 49, 82, 48,128, 5,178, 49,128, + 5,177, 50,128, 5,179, 51,128, 5,194, 52,128, 5,193, 54,128, + 5,185, 55,128, 5,188,179, 57,128, 5,189, 52, 2, 49, 97, 49, + 101, 49,128, 5,191, 50,128, 5,192,185,178, 57,128, 2,188, 54, + 3, 49,119, 49,178, 49,185, 49, 4, 49,129, 49,145, 49,151, 49, + 172, 50, 2, 49,135, 49,140,180, 56,128, 33, 5,184, 57,128, 33, + 19,179,181, 50,128, 33, 22,181, 55, 3, 49,160, 49,164, 49,168, + 51,128, 32, 44, 52,128, 32, 45, 53,128, 32, 46,182,182, 52,128, + 32, 12,179,177,182, 55,128, 6,109,180,185,179, 55,128, 2,189, + 103, 2, 49,198, 49,205,242,225,246,101,128, 0,224,117, 2, 49, + 211, 49,220,234,225,242,225,244,105,128, 10,133,242,237,245,235, + 232,105,128, 10, 5,104, 2, 49,235, 49,245,233,242,225,231,225, + 238, 97,128, 48, 66,239,239,235,225,226,239,246,101,128, 30,163, + 105, 7, 50, 16, 50, 41, 50, 48, 50, 60, 50, 85, 50,101, 50,181, + 98, 2, 50, 22, 50, 31,229,238,231,225,236,105,128, 9,144,239, + 240,239,237,239,230,111,128, 49, 30,228,229,246, 97,128, 9, 16, + 229,227,249,242,233,236,236,233, 99,128, 4,213,231,117, 2, 50, + 67, 50, 76,234,225,242,225,244,105,128, 10,144,242,237,245,235, + 232,105,128, 10, 16,237,225,244,242,225,231,245,242,237,245,235, + 232,105,128, 10, 72,110, 5, 50,113, 50,122, 50,136, 50,152, 50, + 167,225,242,225,226,233, 99,128, 6, 57,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,202,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,203,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,254,204,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 3,246,239,247,229,236,243,233,231,110, 3, 50, + 197, 50,207, 50,214,226,229,238,231,225,236,105,128, 9,200,228, + 229,246, 97,128, 9, 72,231,245,234,225,242,225,244,105,128, 10, + 200,107, 2, 50,231, 50,255,225,244,225,235,225,238, 97,129, 48, + 162, 50,243,232,225,236,230,247,233,228,244,104,128,255,113,239, + 242,229,225,110,128, 49, 79,108, 3, 51, 15, 52, 71, 52, 80,101, + 2, 51, 21, 52, 66,102,136, 5,208, 51, 41, 51, 50, 51, 65, 51, + 79, 51,168, 51,182, 52, 37, 52, 51,225,242,225,226,233, 99,128, + 6, 39,228,225,231,229,243,232,232,229,226,242,229,119,128,251, + 48,230,233,238,225,236,225,242,225,226,233, 99,128,254,142,104, + 2, 51, 85, 51,160,225,237,250, 97, 2, 51, 94, 51,127,225,226, + 239,246,101, 2, 51,104, 51,113,225,242,225,226,233, 99,128, 6, + 35,230,233,238,225,236,225,242,225,226,233, 99,128,254,132,226, + 229,236,239,119, 2, 51,137, 51,146,225,242,225,226,233, 99,128, + 6, 37,230,233,238,225,236,225,242,225,226,233, 99,128,254,136, + 229,226,242,229,119,128, 5,208,236,225,237,229,228,232,229,226, + 242,229,119,128,251, 79,237, 97, 2, 51,189, 51,225,228,228,225, + 225,226,239,246,101, 2, 51,202, 51,211,225,242,225,226,233, 99, + 128, 6, 34,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 130,235,243,245,242, 97, 4, 51,239, 51,248, 52, 6, 52, 22,225, + 242,225,226,233, 99,128, 6, 73,230,233,238,225,236,225,242,225, + 226,233, 99,128,254,240,233,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,254,243,237,229,228,233,225,236,225,242,225,226, + 233, 99,128,254,244,240,225,244,225,232,232,229,226,242,229,119, + 128,251, 46,241,225,237,225,244,243,232,229,226,242,229,119,128, + 251, 47,240,104,128, 33, 53,236,229,241,245,225,108,128, 34, 76, + 240,232, 97,129, 3,177, 52, 88,244,239,238,239,115,128, 3,172, + 109, 4, 52,106, 52,114, 52,125, 52,159,225,227,242,239,110,128, + 1, 1,239,238,239,243,240,225,227,101,128,255, 65,240,229,242, + 243,225,238,100,130, 0, 38, 52,139, 52,151,237,239,238,239,243, + 240,225,227,101,128,255, 6,243,237,225,236,108,128,247, 38,243, + 241,245,225,242,101,128, 51,194,110, 4, 52,178, 52,189, 53, 55, + 53, 65,226,239,240,239,237,239,230,111,128, 49, 34,103, 4, 52, + 199, 52,210, 52,224, 53, 47,226,239,240,239,237,239,230,111,128, + 49, 36,235,232,225,238,235,232,245,244,232,225,105,128, 14, 90, + 236,101,131, 34, 32, 52,235, 53, 32, 53, 39,226,242,225,227,235, + 229,116, 2, 52,247, 53, 11,236,229,230,116,129, 48, 8, 53, 0, + 246,229,242,244,233,227,225,108,128,254, 63,242,233,231,232,116, + 129, 48, 9, 53, 21,246,229,242,244,233,227,225,108,128,254, 64, + 236,229,230,116,128, 35, 41,242,233,231,232,116,128, 35, 42,243, + 244,242,239,109,128, 33, 43,239,244,229,236,229,233, 97,128, 3, + 135,117, 2, 53, 71, 53, 83,228,225,244,244,225,228,229,246, 97, + 128, 9, 82,243,246,225,242, 97, 3, 53, 95, 53,105, 53,112,226, + 229,238,231,225,236,105,128, 9,130,228,229,246, 97,128, 9, 2, + 231,245,234,225,242,225,244,105,128, 10,130,239,231,239,238,229, + 107,128, 1, 5,112, 3, 53,140, 53,164, 53,194, 97, 2, 53,146, + 53,158,225,244,239,243,241,245,225,242,101,128, 51, 0,242,229, + 110,128, 36,156,239,243,244,242,239,240,232,101, 2, 53,177, 53, + 188,225,242,237,229,238,233,225,110,128, 5, 90,237,239,100,128, + 2,188,112, 2, 53,200, 53,205,236,101,128,248,255,242,111, 2, + 53,212, 53,220,225,227,232,229,115,128, 34, 80,120, 2, 53,226, + 53,246,229,241,245,225,108,129, 34, 72, 53,236,239,242,233,237, + 225,231,101,128, 34, 82,233,237,225,244,229,236,249,229,241,245, + 225,108,128, 34, 69,114, 4, 54, 15, 54, 42, 54, 46, 54, 91,225, + 229, 97, 2, 54, 23, 54, 33,229,235,239,242,229,225,110,128, 49, + 142,235,239,242,229,225,110,128, 49,141, 99,128, 35, 18,105, 2, + 54, 52, 54, 66,231,232,244,232,225,236,230,242,233,238,103,128, + 30,154,238,103,130, 0,229, 54, 75, 54, 83,225,227,245,244,101, + 128, 1,251,226,229,236,239,119,128, 30, 1,242,239,119, 8, 54, + 111, 54,118, 54,247, 55, 57, 55,107, 55,162, 55,185, 56, 4,226, + 239,244,104,128, 33,148,100, 3, 54,126, 54,165, 54,212,225,243, + 104, 4, 54,138, 54,145, 54,152, 54,160,228,239,247,110,128, 33, + 227,236,229,230,116,128, 33,224,242,233,231,232,116,128, 33,226, + 245,112,128, 33,225,226,108, 5, 54,178, 54,185, 54,192, 54,199, + 54,207,226,239,244,104,128, 33,212,228,239,247,110,128, 33,211, + 236,229,230,116,128, 33,208,242,233,231,232,116,128, 33,210,245, + 112,128, 33,209,239,247,110,131, 33,147, 54,224, 54,231, 54,239, + 236,229,230,116,128, 33,153,242,233,231,232,116,128, 33,152,247, + 232,233,244,101,128, 33,233,104, 2, 54,253, 55, 48,229,225,100, + 4, 55, 9, 55, 19, 55, 29, 55, 40,228,239,247,238,237,239,100, + 128, 2,197,236,229,230,244,237,239,100,128, 2,194,242,233,231, + 232,244,237,239,100,128, 2,195,245,240,237,239,100,128, 2,196, + 239,242,233,250,229,120,128,248,231,236,229,230,116,131, 33,144, + 55, 70, 55, 87, 55, 99,228,226,108,129, 33,208, 55, 78,243,244, + 242,239,235,101,128, 33,205,239,246,229,242,242,233,231,232,116, + 128, 33,198,247,232,233,244,101,128, 33,230,242,233,231,232,116, + 132, 33,146, 55,123, 55,135, 55,143, 55,154,228,226,236,243,244, + 242,239,235,101,128, 33,207,232,229,225,246,121,128, 39,158,239, + 246,229,242,236,229,230,116,128, 33,196,247,232,233,244,101,128, + 33,232,244,225, 98, 2, 55,170, 55,177,236,229,230,116,128, 33, + 228,242,233,231,232,116,128, 33,229,245,112,132, 33,145, 55,198, + 55,226, 55,244, 55,252,100, 2, 55,204, 55,216,110,129, 33,149, + 55,210,226,243,101,128, 33,168,239,247,238,226,225,243,101,128, + 33,168,236,229,230,116,129, 33,150, 55,235,239,230,228,239,247, + 110,128, 33,197,242,233,231,232,116,128, 33,151,247,232,233,244, + 101,128, 33,231,246,229,242,244,229,120,128,248,230,115, 5, 56, + 25, 56,101, 56,146, 56,229, 56,239, 99, 2, 56, 31, 56, 83,233, + 105, 2, 56, 38, 56, 61,227,233,242,227,245,109,129, 0, 94, 56, + 49,237,239,238,239,243,240,225,227,101,128,255, 62,244,233,236, + 228,101,129, 0,126, 56, 71,237,239,238,239,243,240,225,227,101, + 128,255, 94,242,233,240,116,129, 2, 81, 56, 92,244,245,242,238, + 229,100,128, 2, 82,237,225,236,108, 2, 56,110, 56,121,232,233, + 242,225,231,225,238, 97,128, 48, 65,235,225,244,225,235,225,238, + 97,129, 48,161, 56,134,232,225,236,230,247,233,228,244,104,128, + 255,103,244,229,242,233,115, 2, 56,156, 56,225,107,131, 0, 42, + 56,166, 56,194, 56,217, 97, 2, 56,172, 56,186,236,244,239,238, + 229,225,242,225,226,233, 99,128, 6,109,242,225,226,233, 99,128, + 6,109,109, 2, 56,200, 56,206,225,244,104,128, 34, 23,239,238, + 239,243,240,225,227,101,128,255, 10,243,237,225,236,108,128,254, + 97,109,128, 32, 66,245,240,229,242,233,239,114,128,246,233,249, + 237,240,244,239,244,233,227,225,236,236,249,229,241,245,225,108, + 128, 34, 67,116,132, 0, 64, 57, 15, 57, 22, 57, 34, 57, 42,233, + 236,228,101,128, 0,227,237,239,238,239,243,240,225,227,101,128, + 255, 32,243,237,225,236,108,128,254,107,245,242,238,229,100,128, + 2, 80,117, 6, 57, 64, 57, 89, 57, 96, 57,121, 57,141, 57,157, + 98, 2, 57, 70, 57, 79,229,238,231,225,236,105,128, 9,148,239, + 240,239,237,239,230,111,128, 49, 32,228,229,246, 97,128, 9, 20, + 231,117, 2, 57,103, 57,112,234,225,242,225,244,105,128, 10,148, + 242,237,245,235,232,105,128, 10, 20,236,229,238,231,244,232,237, + 225,242,235,226,229,238,231,225,236,105,128, 9,215,237,225,244, + 242,225,231,245,242,237,245,235,232,105,128, 10, 76,246,239,247, + 229,236,243,233,231,110, 3, 57,173, 57,183, 57,190,226,229,238, + 231,225,236,105,128, 9,204,228,229,246, 97,128, 9, 76,231,245, + 234,225,242,225,244,105,128, 10,204,246,225,231,242,225,232,225, + 228,229,246, 97,128, 9, 61,121, 2, 57,221, 57,233,226,225,242, + 237,229,238,233,225,110,128, 5, 97,233,110,130, 5,226, 57,242, + 58, 1,225,236,244,239,238,229,232,229,226,242,229,119,128,251, + 32,232,229,226,242,229,119,128, 5,226, 98,144, 0, 98, 58, 46, + 58,181, 58,192, 58,201, 58,226, 60, 11, 60, 73, 60,146, 62, 72, + 62, 84, 62,127, 62,135, 62,145, 64, 15, 64, 39, 64, 48, 97, 7, + 58, 62, 58, 72, 58, 96, 58,103, 58,128, 58,152, 58,163,226,229, + 238,231,225,236,105,128, 9,172,227,235,243,236,225,243,104,129, + 0, 92, 58, 84,237,239,238,239,243,240,225,227,101,128,255, 60, + 228,229,246, 97,128, 9, 44,231,117, 2, 58,110, 58,119,234,225, + 242,225,244,105,128, 10,172,242,237,245,235,232,105,128, 10, 44, + 104, 2, 58,134, 58,144,233,242,225,231,225,238, 97,128, 48,112, + 244,244,232,225,105,128, 14, 63,235,225,244,225,235,225,238, 97, + 128, 48,208,114,129, 0,124, 58,169,237,239,238,239,243,240,225, + 227,101,128,255, 92,226,239,240,239,237,239,230,111,128, 49, 5, + 227,233,242,227,236,101,128, 36,209,228,239,116, 2, 58,209, 58, + 218,225,227,227,229,238,116,128, 30, 3,226,229,236,239,119,128, + 30, 5,101, 6, 58,240, 59, 5, 59, 28, 59,170, 59,181, 59,193, + 225,237,229,228,243,233,248,244,229,229,238,244,232,238,239,244, + 229,115,128, 38,108, 99, 2, 59, 11, 59, 18,225,245,243,101,128, + 34, 53,249,242,233,236,236,233, 99,128, 4, 49,104, 5, 59, 40, + 59, 49, 59, 63, 59, 93, 59,152,225,242,225,226,233, 99,128, 6, + 40,230,233,238,225,236,225,242,225,226,233, 99,128,254,144,105, + 2, 59, 69, 59, 84,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,145,242,225,231,225,238, 97,128, 48,121,237,101, 2, + 59,100, 59,113,228,233,225,236,225,242,225,226,233, 99,128,254, + 146,229,237,105, 2, 59,121, 59,136,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,159,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,252, 8,238,239,239,238,230,233,238,225, + 236,225,242,225,226,233, 99,128,252,109,235,225,244,225,235,225, + 238, 97,128, 48,217,238,225,242,237,229,238,233,225,110,128, 5, + 98,116,132, 5,209, 59,205, 59,225, 59,245, 59,254, 97,129, 3, + 178, 59,211,243,249,237,226,239,236,231,242,229,229,107,128, 3, + 208,228,225,231,229,243,104,129,251, 49, 59,236,232,229,226,242, + 229,119,128,251, 49,232,229,226,242,229,119,128, 5,209,242,225, + 230,229,232,229,226,242,229,119,128,251, 76,104, 2, 60, 17, 60, + 67, 97, 3, 60, 25, 60, 35, 60, 42,226,229,238,231,225,236,105, + 128, 9,173,228,229,246, 97,128, 9, 45,231,117, 2, 60, 49, 60, + 58,234,225,242,225,244,105,128, 10,173,242,237,245,235,232,105, + 128, 10, 45,239,239,107,128, 2, 83,105, 5, 60, 85, 60, 96, 60, + 107, 60,121, 60,135,232,233,242,225,231,225,238, 97,128, 48,115, + 235,225,244,225,235,225,238, 97,128, 48,211,236,225,226,233,225, + 236,227,236,233,227,107,128, 2,152,238,228,233,231,245,242,237, + 245,235,232,105,128, 10, 2,242,245,243,241,245,225,242,101,128, + 51, 49,108, 3, 60,154, 62, 55, 62, 66, 97, 2, 60,160, 62, 50, + 227,107, 6, 60,175, 60,184, 60,221, 61,114, 61,169, 61,221,227, + 233,242,227,236,101,128, 37,207,100, 2, 60,190, 60,199,233,225, + 237,239,238,100,128, 37,198,239,247,238,240,239,233,238,244,233, + 238,231,244,242,233,225,238,231,236,101,128, 37,188,108, 2, 60, + 227, 61, 74,101, 2, 60,233, 61, 13,230,244,240,239,233,238,244, + 233,238,103, 2, 60,248, 61, 2,240,239,233,238,244,229,114,128, + 37,196,244,242,233,225,238,231,236,101,128, 37,192,238,244,233, + 227,245,236,225,242,226,242,225,227,235,229,116, 2, 61, 33, 61, + 53,236,229,230,116,129, 48, 16, 61, 42,246,229,242,244,233,227, + 225,108,128,254, 59,242,233,231,232,116,129, 48, 17, 61, 63,246, + 229,242,244,233,227,225,108,128,254, 60,239,247,229,114, 2, 61, + 83, 61, 98,236,229,230,244,244,242,233,225,238,231,236,101,128, + 37,227,242,233,231,232,244,244,242,233,225,238,231,236,101,128, + 37,226,114, 2, 61,120, 61,131,229,227,244,225,238,231,236,101, + 128, 37,172,233,231,232,244,240,239,233,238,244,233,238,103, 2, + 61,148, 61,158,240,239,233,238,244,229,114,128, 37,186,244,242, + 233,225,238,231,236,101,128, 37,182,115, 3, 61,177, 61,207, 61, + 215,109, 2, 61,183, 61,195,225,236,236,243,241,245,225,242,101, + 128, 37,170,233,236,233,238,231,230,225,227,101,128, 38, 59,241, + 245,225,242,101,128, 37,160,244,225,114,128, 38, 5,245,240,112, + 2, 61,229, 62, 11,229,114, 2, 61,236, 61,251,236,229,230,244, + 244,242,233,225,238,231,236,101,128, 37,228,242,233,231,232,244, + 244,242,233,225,238,231,236,101,128, 37,229,239,233,238,244,233, + 238,103, 2, 62, 23, 62, 39,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,180,244,242,233,225,238,231,236,101,128, + 37,178,238,107,128, 36, 35,233,238,229,226,229,236,239,119,128, + 30, 7,239,227,107,128, 37,136,237,239,238,239,243,240,225,227, + 101,128,255, 66,111, 3, 62, 92, 62,105, 62,116,226,225,233,237, + 225,233,244,232,225,105,128, 14, 26,232,233,242,225,231,225,238, + 97,128, 48,124,235,225,244,225,235,225,238, 97,128, 48,220,240, + 225,242,229,110,128, 36,157,241,243,241,245,225,242,101,128, 51, + 195,114, 4, 62,155, 63,149, 63,222, 64, 5,225, 99, 2, 62,162, + 63, 56,101, 3, 62,170, 62,175, 62,243,229,120,128,248,244,236, + 229,230,116,133, 0,123, 62,192, 62,197, 62,219, 62,227, 62,232, + 226,116,128,248,243,109, 2, 62,203, 62,208,233,100,128,248,242, + 239,238,239,243,240,225,227,101,128,255, 91,243,237,225,236,108, + 128,254, 91,244,112,128,248,241,246,229,242,244,233,227,225,108, + 128,254, 55,242,233,231,232,116,133, 0,125, 63, 5, 63, 10, 63, + 32, 63, 40, 63, 45,226,116,128,248,254,109, 2, 63, 16, 63, 21, + 233,100,128,248,253,239,238,239,243,240,225,227,101,128,255, 93, + 243,237,225,236,108,128,254, 92,244,112,128,248,252,246,229,242, + 244,233,227,225,108,128,254, 56,235,229,116, 2, 63, 64, 63,106, + 236,229,230,116,132, 0, 91, 63, 79, 63, 84, 63, 89, 63,101,226, + 116,128,248,240,229,120,128,248,239,237,239,238,239,243,240,225, + 227,101,128,255, 59,244,112,128,248,238,242,233,231,232,116,132, + 0, 93, 63,122, 63,127, 63,132, 63,144,226,116,128,248,251,229, + 120,128,248,250,237,239,238,239,243,240,225,227,101,128,255, 61, + 244,112,128,248,249,229,246,101,131, 2,216, 63,161, 63,172, 63, + 178,226,229,236,239,247,227,237, 98,128, 3, 46,227,237, 98,128, + 3, 6,233,238,246,229,242,244,229,100, 3, 63,193, 63,204, 63, + 210,226,229,236,239,247,227,237, 98,128, 3, 47,227,237, 98,128, + 3, 17,228,239,245,226,236,229,227,237, 98,128, 3, 97,233,228, + 231,101, 2, 63,231, 63,242,226,229,236,239,247,227,237, 98,128, + 3, 42,233,238,246,229,242,244,229,228,226,229,236,239,247,227, + 237, 98,128, 3, 58,239,235,229,238,226,225,114,128, 0,166,115, + 2, 64, 21, 64, 29,244,242,239,235,101,128, 1,128,245,240,229, + 242,233,239,114,128,246,234,244,239,240,226,225,114,128, 1,131, + 117, 3, 64, 56, 64, 67, 64, 78,232,233,242,225,231,225,238, 97, + 128, 48,118,235,225,244,225,235,225,238, 97,128, 48,214,236,108, + 2, 64, 85, 64,115,229,116,130, 32, 34, 64, 94, 64,104,233,238, + 246,229,242,243,101,128, 37,216,239,240,229,242,225,244,239,114, + 128, 34, 25,243,229,249,101,128, 37,206, 99,143, 0, 99, 64,156, + 65,105, 65,116, 65,180, 65,211, 66, 48, 67,215, 68,199, 69, 43, + 69, 92, 72, 84, 72, 92, 72,102, 72,114, 72,147, 97, 9, 64,176, + 64,187, 64,197, 64,204, 64,211, 64,236, 64,246, 65, 42, 65, 51, + 225,242,237,229,238,233,225,110,128, 5,110,226,229,238,231,225, + 236,105,128, 9,154,227,245,244,101,128, 1, 7,228,229,246, 97, + 128, 9, 26,231,117, 2, 64,218, 64,227,234,225,242,225,244,105, + 128, 10,154,242,237,245,235,232,105,128, 10, 26,236,243,241,245, + 225,242,101,128, 51,136,238,228,242,225,226,233,238,228,117, 4, + 65, 8, 65, 18, 65, 24, 65, 31,226,229,238,231,225,236,105,128, + 9,129,227,237, 98,128, 3, 16,228,229,246, 97,128, 9, 1,231, + 245,234,225,242,225,244,105,128, 10,129,240,243,236,239,227,107, + 128, 33,234,114, 3, 65, 59, 65, 65, 65, 91,229,239,102,128, 33, + 5,239,110,130, 2,199, 65, 74, 65, 85,226,229,236,239,247,227, + 237, 98,128, 3, 44,227,237, 98,128, 3, 12,242,233,225,231,229, + 242,229,244,245,242,110,128, 33,181,226,239,240,239,237,239,230, + 111,128, 49, 24, 99, 4, 65,126, 65,133, 65,152, 65,174,225,242, + 239,110,128, 1, 13,229,228,233,236,236, 97,129, 0,231, 65,144, + 225,227,245,244,101,128, 30, 9,233,242, 99, 2, 65,160, 65,165, + 236,101,128, 36,210,245,237,230,236,229,120,128, 1, 9,245,242, + 108,128, 2, 85,100, 2, 65,186, 65,202,239,116,129, 1, 11, 65, + 193,225,227,227,229,238,116,128, 1, 11,243,241,245,225,242,101, + 128, 51,197,101, 2, 65,217, 65,233,228,233,236,236, 97,129, 0, + 184, 65,227,227,237, 98,128, 3, 39,238,116,132, 0,162, 65,246, + 66, 14, 66, 26, 66, 37,105, 2, 65,252, 66, 4,231,242,225,228, + 101,128, 33, 3,238,230,229,242,233,239,114,128,246,223,237,239, + 238,239,243,240,225,227,101,128,255,224,239,236,228,243,244,249, + 236,101,128,247,162,243,245,240,229,242,233,239,114,128,246,224, + 104, 5, 66, 60, 66,123, 66,134, 67, 62, 67,154, 97, 4, 66, 70, + 66, 81, 66, 91, 66, 98,225,242,237,229,238,233,225,110,128, 5, + 121,226,229,238,231,225,236,105,128, 9,155,228,229,246, 97,128, + 9, 27,231,117, 2, 66,105, 66,114,234,225,242,225,244,105,128, + 10,155,242,237,245,235,232,105,128, 10, 27,226,239,240,239,237, + 239,230,111,128, 49, 20,101, 6, 66,148, 66,168, 66,192, 67, 4, + 67, 16, 67, 37,225,226,235,232,225,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,189, 99, 2, 66,174, 66,182,235,237, + 225,242,107,128, 39, 19,249,242,233,236,236,233, 99,128, 4, 71, + 100, 2, 66,198, 66,242,229,243,227,229,238,228,229,114, 2, 66, + 211, 66,231,225,226,235,232,225,243,233,225,238,227,249,242,233, + 236,236,233, 99,128, 4,191,227,249,242,233,236,236,233, 99,128, + 4,183,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,245,232,225,242,237,229,238,233,225,110,128, 5,115, + 235,232,225,235,225,243,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,204,246,229,242,244,233,227,225,236,243,244,242, + 239,235,229,227,249,242,233,236,236,233, 99,128, 4,185,105,129, + 3,199, 67, 68,229,245,227,104, 4, 67, 81, 67,116, 67,131, 67, + 140, 97, 2, 67, 87, 67,102,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50,119,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 23,227,233,242,227,236,229,235,239,242,229,225,110, + 128, 50,105,235,239,242,229,225,110,128, 49, 74,240,225,242,229, + 238,235,239,242,229,225,110,128, 50, 9,111, 2, 67,160, 67,210, + 227,104, 3, 67,169, 67,191, 67,201,225,110, 2, 67,176, 67,184, + 231,244,232,225,105,128, 14, 10,244,232,225,105,128, 14, 8,233, + 238,231,244,232,225,105,128, 14, 9,239,229,244,232,225,105,128, + 14, 12,239,107,128, 1,136,105, 2, 67,221, 68, 67,229,245, 99, + 5, 67,235, 68, 14, 68, 29, 68, 38, 68, 52, 97, 2, 67,241, 68, + 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,118, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 22,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50,104,235,239,242, + 229,225,110,128, 49, 72,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 8,245,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 28,242, 99, 2, 68, 74, 68,169,236,101,132, 37,203, 68, + 87, 68, 98, 68,103, 68,127,237,245,236,244,233,240,236,121,128, + 34,151,239,116,128, 34,153,112, 2, 68,109, 68,115,236,245,115, + 128, 34,149,239,243,244,225,236,237,225,242,107,128, 48, 54,247, + 233,244,104, 2, 68,136, 68,152,236,229,230,244,232,225,236,230, + 226,236,225,227,107,128, 37,208,242,233,231,232,244,232,225,236, + 230,226,236,225,227,107,128, 37,209,245,237,230,236,229,120,130, + 2,198, 68,182, 68,193,226,229,236,239,247,227,237, 98,128, 3, + 45,227,237, 98,128, 3, 2,108, 3, 68,207, 68,213, 69, 11,229, + 225,114,128, 35, 39,233,227,107, 4, 68,225, 68,236, 68,245, 68, + 255,225,236,246,229,239,236,225,114,128, 1,194,228,229,238,244, + 225,108,128, 1,192,236,225,244,229,242,225,108,128, 1,193,242, + 229,244,242,239,230,236,229,120,128, 1,195,245, 98,129, 38, 99, + 69, 18,243,245,233,116, 2, 69, 27, 69, 35,226,236,225,227,107, + 128, 38, 99,247,232,233,244,101,128, 38,103,109, 3, 69, 51, 69, + 65, 69, 76,227,245,226,229,228,243,241,245,225,242,101,128, 51, + 164,239,238,239,243,240,225,227,101,128,255, 67,243,241,245,225, + 242,229,228,243,241,245,225,242,101,128, 51,160,111, 8, 69,110, + 69,121, 69,208, 70,150, 71,179, 71,210, 72, 61, 72, 70,225,242, + 237,229,238,233,225,110,128, 5,129,236,239,110,131, 0, 58, 69, + 133, 69,158, 69,177,237,239,110, 2, 69,141, 69,149,229,244,225, + 242,121,128, 32,161,239,243,240,225,227,101,128,255, 26,115, 2, + 69,164, 69,170,233,231,110,128, 32,161,237,225,236,108,128,254, + 85,244,242,233,225,238,231,245,236,225,114, 2, 69,192, 69,202, + 232,225,236,230,237,239,100,128, 2,209,237,239,100,128, 2,208, + 109, 2, 69,214, 70,143,237, 97,134, 0, 44, 69,231, 70, 39, 70, + 50, 70, 62, 70, 92, 70,115, 97, 3, 69,239, 70, 9, 70, 17,226, + 239,246,101, 2, 69,248, 69,254,227,237, 98,128, 3, 19,242,233, + 231,232,244,227,237, 98,128, 3, 21,227,227,229,238,116,128,246, + 195,114, 2, 70, 23, 70, 30,225,226,233, 99,128, 6, 12,237,229, + 238,233,225,110,128, 5, 93,233,238,230,229,242,233,239,114,128, + 246,225,237,239,238,239,243,240,225,227,101,128,255, 12,242,229, + 246,229,242,243,229,100, 2, 70, 75, 70, 86,225,226,239,246,229, + 227,237, 98,128, 3, 20,237,239,100,128, 2,189,115, 2, 70, 98, + 70,105,237,225,236,108,128,254, 80,245,240,229,242,233,239,114, + 128,246,226,244,245,242,238,229,100, 2, 70,126, 70,137,225,226, + 239,246,229,227,237, 98,128, 3, 18,237,239,100,128, 2,187,240, + 225,243,115,128, 38, 60,110, 2, 70,156, 70,165,231,242,245,229, + 238,116,128, 34, 69,116, 2, 70,171, 70,185,239,245,242,233,238, + 244,229,231,242,225,108,128, 34, 46,242,239,108,142, 35, 3, 70, + 219, 70,225, 70,240, 70,255, 71, 43, 71, 88, 71,102, 71,107, 71, + 112, 71,117, 71,123, 71,128, 71,169, 71,174,193,195, 75,128, 0, + 6, 66, 2, 70,231, 70,236,197, 76,128, 0, 7, 83,128, 0, 8, + 67, 2, 70,246, 70,251,193, 78,128, 0, 24, 82,128, 0, 13, 68, + 3, 71, 7, 71, 33, 71, 38, 67, 4, 71, 17, 71, 21, 71, 25, 71, + 29, 49,128, 0, 17, 50,128, 0, 18, 51,128, 0, 19, 52,128, 0, + 20,197, 76,128, 0,127,204, 69,128, 0, 16, 69, 5, 71, 55, 71, + 59, 71, 64, 71, 69, 71, 74, 77,128, 0, 25,206, 81,128, 0, 5, + 207, 84,128, 0, 4,211, 67,128, 0, 27, 84, 2, 71, 80, 71, 84, + 66,128, 0, 23, 88,128, 0, 3, 70, 2, 71, 94, 71, 98, 70,128, + 0, 12, 83,128, 0, 28,199, 83,128, 0, 29,200, 84,128, 0, 9, + 204, 70,128, 0, 10,206,193, 75,128, 0, 21,210, 83,128, 0, 30, + 83, 5, 71,140, 71,144, 71,154, 71,159, 71,164, 73,128, 0, 15, + 79,129, 0, 14, 71,150, 84,128, 0, 2,212, 88,128, 0, 1,213, + 66,128, 0, 26,217, 78,128, 0, 22,213, 83,128, 0, 31,214, 84, + 128, 0, 11,240,249,242,233,231,232,116,129, 0,169, 71,191,115, + 2, 71,197, 71,203,225,238,115,128,248,233,229,242,233,102,128, + 246,217,114, 2, 71,216, 72, 44,238,229,242,226,242,225,227,235, + 229,116, 2, 71,231, 72, 9,236,229,230,116,130, 48, 12, 71,242, + 71,254,232,225,236,230,247,233,228,244,104,128,255, 98,246,229, + 242,244,233,227,225,108,128,254, 65,242,233,231,232,116,130, 48, + 13, 72, 21, 72, 33,232,225,236,230,247,233,228,244,104,128,255, + 99,246,229,242,244,233,227,225,108,128,254, 66,240,239,242,225, + 244,233,239,238,243,241,245,225,242,101,128, 51,127,243,241,245, + 225,242,101,128, 51,199,246,229,242,235,231,243,241,245,225,242, + 101,128, 51,198,240,225,242,229,110,128, 36,158,242,245,250,229, + 233,242,111,128, 32,162,243,244,242,229,244,227,232,229,100,128, + 2,151,245,114, 2, 72,121, 72,139,236,121, 2, 72,128, 72,134, + 225,238,100,128, 34,207,239,114,128, 34,206,242,229,238,227,121, + 128, 0,164,249,114, 4, 72,158, 72,166, 72,173, 72,181,194,242, + 229,246,101,128,246,209,198,236,229,120,128,246,210,226,242,229, + 246,101,128,246,212,230,236,229,120,128,246,213,100,146, 0,100, + 72,228, 74,110, 75,134, 75,194, 76,114, 77, 68, 77,130, 78, 59, + 78, 72, 78, 81, 78,107, 78,132, 78,141, 79,208, 79,216, 79,227, + 79,247, 80, 19, 97, 11, 72,252, 73, 7, 73, 17, 73, 89, 73,152, + 73,163, 73,174, 73,243, 74, 49, 74, 55, 74, 85,225,242,237,229, + 238,233,225,110,128, 5,100,226,229,238,231,225,236,105,128, 9, + 166,100, 5, 73, 29, 73, 38, 73, 44, 73, 58, 73, 74,225,242,225, + 226,233, 99,128, 6, 54,229,246, 97,128, 9, 38,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,190,233,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,191,237,229,228,233,225,236, + 225,242,225,226,233, 99,128,254,192,103, 3, 73, 97, 73,114, 73, + 128,229,243,104,129, 5,188, 73,105,232,229,226,242,229,119,128, + 5,188,231,229,114,129, 32, 32, 73,122,228,226,108,128, 32, 33, + 117, 2, 73,134, 73,143,234,225,242,225,244,105,128, 10,166,242, + 237,245,235,232,105,128, 10, 38,232,233,242,225,231,225,238, 97, + 128, 48, 96,235,225,244,225,235,225,238, 97,128, 48,192,108, 3, + 73,182, 73,191, 73,229,225,242,225,226,233, 99,128, 6, 47,229, + 116,130, 5,211, 73,200, 73,220,228,225,231,229,243,104,129,251, + 51, 73,211,232,229,226,242,229,119,128,251, 51,232,229,226,242, + 229,119,128, 5,211,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,170,237,237, 97, 3, 73,253, 74, 6, 74, 18,225,242,225, + 226,233, 99,128, 6, 79,236,239,247,225,242,225,226,233, 99,128, + 6, 79,244,225,238, 97, 2, 74, 27, 74, 41,236,244,239,238,229, + 225,242,225,226,233, 99,128, 6, 76,242,225,226,233, 99,128, 6, + 76,238,228, 97,128, 9,100,242,231, 97, 2, 74, 63, 74, 72,232, + 229,226,242,229,119,128, 5,167,236,229,230,244,232,229,226,242, + 229,119,128, 5,167,243,233,225,240,238,229,245,237,225,244,225, + 227,249,242,233,236,236,233,227,227,237, 98,128, 4,133, 98, 3, + 74,118, 75,115, 75,125,108, 9, 74,138, 74,146, 75, 3, 75, 11, + 75, 27, 75, 38, 75, 56, 75, 70, 75, 81,199,242,225,246,101,128, + 246,211, 97, 2, 74,152, 74,209,238,231,236,229,226,242,225,227, + 235,229,116, 2, 74,168, 74,188,236,229,230,116,129, 48, 10, 74, + 177,246,229,242,244,233,227,225,108,128,254, 61,242,233,231,232, + 116,129, 48, 11, 74,198,246,229,242,244,233,227,225,108,128,254, + 62,114, 2, 74,215, 74,236,227,232,233,238,246,229,242,244,229, + 228,226,229,236,239,247,227,237, 98,128, 3, 43,242,239,119, 2, + 74,244, 74,251,236,229,230,116,128, 33,212,242,233,231,232,116, + 128, 33,210,228,225,238,228, 97,128, 9,101,231,242,225,246,101, + 129,246,214, 75, 21,227,237, 98,128, 3, 15,233,238,244,229,231, + 242,225,108,128, 34, 44,236,239,247,236,233,238,101,129, 32, 23, + 75, 50,227,237, 98,128, 3, 51,239,246,229,242,236,233,238,229, + 227,237, 98,128, 3, 63,240,242,233,237,229,237,239,100,128, 2, + 186,246,229,242,244,233,227,225,108, 2, 75, 94, 75,100,226,225, + 114,128, 32, 22,236,233,238,229,225,226,239,246,229,227,237, 98, + 128, 3, 14,239,240,239,237,239,230,111,128, 49, 9,243,241,245, + 225,242,101,128, 51,200, 99, 4, 75,144, 75,151, 75,160, 75,187, + 225,242,239,110,128, 1, 15,229,228,233,236,236, 97,128, 30, 17, + 233,242, 99, 2, 75,168, 75,173,236,101,128, 36,211,245,237,230, + 236,229,248,226,229,236,239,119,128, 30, 19,242,239,225,116,128, + 1, 17,100, 4, 75,204, 76, 29, 76, 39, 76, 90, 97, 4, 75,214, + 75,224, 75,231, 76, 0,226,229,238,231,225,236,105,128, 9,161, + 228,229,246, 97,128, 9, 33,231,117, 2, 75,238, 75,247,234,225, + 242,225,244,105,128, 10,161,242,237,245,235,232,105,128, 10, 33, + 108, 2, 76, 6, 76, 15,225,242,225,226,233, 99,128, 6,136,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,137,228,232,225, + 228,229,246, 97,128, 9, 92,232, 97, 3, 76, 48, 76, 58, 76, 65, + 226,229,238,231,225,236,105,128, 9,162,228,229,246, 97,128, 9, + 34,231,117, 2, 76, 72, 76, 81,234,225,242,225,244,105,128, 10, + 162,242,237,245,235,232,105,128, 10, 34,239,116, 2, 76, 97, 76, + 106,225,227,227,229,238,116,128, 30, 11,226,229,236,239,119,128, + 30, 13,101, 8, 76,132, 76,185, 76,192, 76,217, 76,227, 76,238, + 77, 27, 77, 63, 99, 2, 76,138, 76,175,233,237,225,236,243,229, + 240,225,242,225,244,239,114, 2, 76,156, 76,165,225,242,225,226, + 233, 99,128, 6,107,240,229,242,243,233,225,110,128, 6,107,249, + 242,233,236,236,233, 99,128, 4, 52,231,242,229,101,128, 0,176, + 232,105, 2, 76,199, 76,208,232,229,226,242,229,119,128, 5,173, + 242,225,231,225,238, 97,128, 48,103,233,227,239,240,244,233, 99, + 128, 3,239,235,225,244,225,235,225,238, 97,128, 48,199,108, 2, + 76,244, 77, 11,229,244,101, 2, 76,252, 77, 3,236,229,230,116, + 128, 35, 43,242,233,231,232,116,128, 35, 38,244, 97,129, 3,180, + 77, 18,244,245,242,238,229,100,128, 1,141,238,239,237,233,238, + 225,244,239,242,237,233,238,245,243,239,238,229,238,245,237,229, + 242,225,244,239,242,226,229,238,231,225,236,105,128, 9,248,250, + 104,128, 2,164,104, 2, 77, 74, 77,124, 97, 3, 77, 82, 77, 92, + 77, 99,226,229,238,231,225,236,105,128, 9,167,228,229,246, 97, + 128, 9, 39,231,117, 2, 77,106, 77,115,234,225,242,225,244,105, + 128, 10,167,242,237,245,235,232,105,128, 10, 39,239,239,107,128, + 2, 87,105, 6, 77,144, 77,193, 77,253, 78, 8, 78, 19, 78, 29, + 97, 2, 77,150, 77,172,236,249,244,233,235,225,244,239,238,239, + 115,129, 3,133, 77,166,227,237, 98,128, 3, 68,237,239,238,100, + 129, 38,102, 77,181,243,245,233,244,247,232,233,244,101,128, 38, + 98,229,242,229,243,233,115,133, 0,168, 77,212, 77,220, 77,231, + 77,237, 77,245,225,227,245,244,101,128,246,215,226,229,236,239, + 247,227,237, 98,128, 3, 36,227,237, 98,128, 3, 8,231,242,225, + 246,101,128,246,216,244,239,238,239,115,128, 3,133,232,233,242, + 225,231,225,238, 97,128, 48, 98,235,225,244,225,235,225,238, 97, + 128, 48,194,244,244,239,237,225,242,107,128, 48, 3,246,105, 2, + 78, 36, 78, 47,228,101,129, 0,247, 78, 43,115,128, 34, 35,243, + 233,239,238,243,236,225,243,104,128, 34, 21,234,229,227,249,242, + 233,236,236,233, 99,128, 4, 82,235,243,232,225,228,101,128, 37, + 147,108, 2, 78, 87, 78, 98,233,238,229,226,229,236,239,119,128, + 30, 15,243,241,245,225,242,101,128, 51,151,109, 2, 78,113, 78, + 121,225,227,242,239,110,128, 1, 17,239,238,239,243,240,225,227, + 101,128,255, 68,238,226,236,239,227,107,128, 37,132,111, 10, 78, + 163, 78,175, 78,185, 78,196, 78,207, 79, 23, 79, 28, 79, 39, 79, + 154, 79,180,227,232,225,228,225,244,232,225,105,128, 14, 14,228, + 229,235,244,232,225,105,128, 14, 20,232,233,242,225,231,225,238, + 97,128, 48,105,235,225,244,225,235,225,238, 97,128, 48,201,236, + 236,225,114,132, 0, 36, 78,222, 78,233, 78,245, 79, 0,233,238, + 230,229,242,233,239,114,128,246,227,237,239,238,239,243,240,225, + 227,101,128,255, 4,239,236,228,243,244,249,236,101,128,247, 36, + 115, 2, 79, 6, 79, 13,237,225,236,108,128,254,105,245,240,229, + 242,233,239,114,128,246,228,238,103,128, 32,171,242,245,243,241, + 245,225,242,101,128, 51, 38,116, 6, 79, 53, 79, 70, 79, 92, 79, + 103, 79,135, 79,142,225,227,227,229,238,116,129, 2,217, 79, 64, + 227,237, 98,128, 3, 7,226,229,236,239,247, 99, 2, 79, 81, 79, + 86,237, 98,128, 3, 35,239,237, 98,128, 3, 35,235,225,244,225, + 235,225,238, 97,128, 48,251,236,229,243,115, 2, 79,112, 79,116, + 105,128, 1, 49,106,129,246,190, 79,122,243,244,242,239,235,229, + 232,239,239,107,128, 2,132,237,225,244,104,128, 34,197,244,229, + 228,227,233,242,227,236,101,128, 37,204,245,226,236,229,249,239, + 228,240,225,244,225,104,129,251, 31, 79,171,232,229,226,242,229, + 119,128,251, 31,247,238,244,225,227,107, 2, 79,191, 79,202,226, + 229,236,239,247,227,237, 98,128, 3, 30,237,239,100,128, 2,213, + 240,225,242,229,110,128, 36,159,243,245,240,229,242,233,239,114, + 128,246,235,116, 2, 79,233, 79,239,225,233,108,128, 2, 86,239, + 240,226,225,114,128, 1,140,117, 2, 79,253, 80, 8,232,233,242, + 225,231,225,238, 97,128, 48,101,235,225,244,225,235,225,238, 97, + 128, 48,197,122,132, 1,243, 80, 31, 80, 40, 80, 59, 80, 96,225, + 236,244,239,238,101,128, 2,163, 99, 2, 80, 46, 80, 53,225,242, + 239,110,128, 1,198,245,242,108,128, 2,165,101, 2, 80, 65, 80, + 85,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,225,227,249,242,233,236,236,233, 99,128, 4, 85, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 95,101,151, 0, + 101, 80,159, 80,178, 80,212, 81,186, 81,248, 82, 25, 82, 37, 82, + 60, 82,113, 83,225, 84, 27, 84,129, 84,245, 85,124, 85,199, 85, + 230, 86, 36, 86, 89, 87, 24, 87,157, 87,177, 87,221, 88, 56, 97, + 2, 80,165, 80,172,227,245,244,101,128, 0,233,242,244,104,128, + 38, 65, 98, 3, 80,186, 80,195, 80,205,229,238,231,225,236,105, + 128, 9,143,239,240,239,237,239,230,111,128, 49, 28,242,229,246, + 101,128, 1, 21, 99, 5, 80,224, 81, 41, 81, 55, 81, 87, 81,176, + 97, 2, 80,230, 81, 35,238,228,242, 97, 3, 80,241, 80,248, 81, + 3,228,229,246, 97,128, 9, 13,231,245,234,225,242,225,244,105, + 128, 10,141,246,239,247,229,236,243,233,231,110, 2, 81, 17, 81, + 24,228,229,246, 97,128, 9, 69,231,245,234,225,242,225,244,105, + 128, 10,197,242,239,110,128, 1, 27,229,228,233,236,236,225,226, + 242,229,246,101,128, 30, 29,104, 2, 81, 61, 81, 72,225,242,237, + 229,238,233,225,110,128, 5,101,249,233,247,238,225,242,237,229, + 238,233,225,110,128, 5,135,233,242, 99, 2, 81, 95, 81,100,236, + 101,128, 36,212,245,237,230,236,229,120,134, 0,234, 81,121, 81, + 129, 81,137, 81,148, 81,156, 81,168,225,227,245,244,101,128, 30, + 191,226,229,236,239,119,128, 30, 25,228,239,244,226,229,236,239, + 119,128, 30,199,231,242,225,246,101,128, 30,193,232,239,239,235, + 225,226,239,246,101,128, 30,195,244,233,236,228,101,128, 30,197, + 249,242,233,236,236,233, 99,128, 4, 84,100, 4, 81,196, 81,206, + 81,212, 81,222,226,236,231,242,225,246,101,128, 2, 5,229,246, + 97,128, 9, 15,233,229,242,229,243,233,115,128, 0,235,239,116, + 130, 1, 23, 81,231, 81,240,225,227,227,229,238,116,128, 1, 23, + 226,229,236,239,119,128, 30,185,101, 2, 81,254, 82, 9,231,245, + 242,237,245,235,232,105,128, 10, 15,237,225,244,242,225,231,245, + 242,237,245,235,232,105,128, 10, 71,230,227,249,242,233,236,236, + 233, 99,128, 4, 68,103, 2, 82, 43, 82, 50,242,225,246,101,128, + 0,232,245,234,225,242,225,244,105,128, 10,143,104, 4, 82, 70, + 82, 81, 82, 92, 82,102,225,242,237,229,238,233,225,110,128, 5, + 103,226,239,240,239,237,239,230,111,128, 49, 29,233,242,225,231, + 225,238, 97,128, 48, 72,239,239,235,225,226,239,246,101,128, 30, + 187,105, 4, 82,123, 82,134, 83,192, 83,207,226,239,240,239,237, + 239,230,111,128, 49, 31,231,232,116,142, 0, 56, 82,168, 82,177, + 82,187, 82,217, 82,224, 83, 6, 83, 31, 83, 76, 83,110, 83,122, + 83,133, 83,166, 83,174, 83,185,225,242,225,226,233, 99,128, 6, + 104,226,229,238,231,225,236,105,128, 9,238,227,233,242,227,236, + 101,129, 36,103, 82,198,233,238,246,229,242,243,229,243,225,238, + 243,243,229,242,233,102,128, 39,145,228,229,246, 97,128, 9,110, + 229,229,110, 2, 82,232, 82,241,227,233,242,227,236,101,128, 36, + 113,112, 2, 82,247, 82,254,225,242,229,110,128, 36,133,229,242, + 233,239,100,128, 36,153,231,117, 2, 83, 13, 83, 22,234,225,242, + 225,244,105,128, 10,238,242,237,245,235,232,105,128, 10,110,104, + 2, 83, 37, 83, 63, 97, 2, 83, 43, 83, 54,227,235,225,242,225, + 226,233, 99,128, 6,104,238,231,250,232,239,117,128, 48, 40,238, + 239,244,229,226,229,225,237,229,100,128, 38,107,105, 2, 83, 82, + 83,100,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 39,238,230,229,242,233,239,114,128, 32,136,237,239, + 238,239,243,240,225,227,101,128,255, 24,239,236,228,243,244,249, + 236,101,128,247, 56,112, 2, 83,139, 83,146,225,242,229,110,128, + 36,123,229,114, 2, 83,153, 83,159,233,239,100,128, 36,143,243, + 233,225,110,128, 6,248,242,239,237,225,110,128, 33,119,243,245, + 240,229,242,233,239,114,128, 32,120,244,232,225,105,128, 14, 88, + 238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 7,239, + 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, + 101,107, 2, 83,231, 83,255,225,244,225,235,225,238, 97,129, 48, + 168, 83,243,232,225,236,230,247,233,228,244,104,128,255,116,111, + 2, 84, 5, 84, 20,238,235,225,242,231,245,242,237,245,235,232, + 105,128, 10,116,242,229,225,110,128, 49, 84,108, 3, 84, 35, 84, + 46, 84,107,227,249,242,233,236,236,233, 99,128, 4, 59,101, 2, + 84, 52, 84, 59,237,229,238,116,128, 34, 8,246,229,110, 3, 84, + 69, 84, 78, 84, 99,227,233,242,227,236,101,128, 36,106,112, 2, + 84, 84, 84, 91,225,242,229,110,128, 36,126,229,242,233,239,100, + 128, 36,146,242,239,237,225,110,128, 33,122,236,233,240,243,233, + 115,129, 32, 38, 84,118,246,229,242,244,233,227,225,108,128, 34, + 238,109, 5, 84,141, 84,169, 84,180, 84,200, 84,211,225,227,242, + 239,110,130, 1, 19, 84,153, 84,161,225,227,245,244,101,128, 30, + 23,231,242,225,246,101,128, 30, 21,227,249,242,233,236,236,233, + 99,128, 4, 60,228,225,243,104,129, 32, 20, 84,189,246,229,242, + 244,233,227,225,108,128,254, 49,239,238,239,243,240,225,227,101, + 128,255, 69,112, 2, 84,217, 84,237,232,225,243,233,243,237,225, + 242,235,225,242,237,229,238,233,225,110,128, 5, 91,244,249,243, + 229,116,128, 34, 5,110, 6, 85, 3, 85, 14, 85, 25, 85, 69, 85, + 101, 85,116,226,239,240,239,237,239,230,111,128, 49, 35,227,249, + 242,233,236,236,233, 99,128, 4, 61,100, 2, 85, 31, 85, 50,225, + 243,104,129, 32, 19, 85, 39,246,229,242,244,233,227,225,108,128, + 254, 50,229,243,227,229,238,228,229,242,227,249,242,233,236,236, + 233, 99,128, 4,163,103,130, 1, 75, 85, 77, 85, 88,226,239,240, + 239,237,239,230,111,128, 49, 37,232,229,227,249,242,233,236,236, + 233, 99,128, 4,165,232,239,239,235,227,249,242,233,236,236,233, + 99,128, 4,200,243,240,225,227,101,128, 32, 2,111, 3, 85,132, + 85,140, 85,149,231,239,238,229,107,128, 1, 25,235,239,242,229, + 225,110,128, 49, 83,240,229,110,130, 2, 91, 85,159, 85,168,227, + 236,239,243,229,100,128, 2,154,242,229,246,229,242,243,229,100, + 130, 2, 92, 85,183, 85,192,227,236,239,243,229,100,128, 2, 94, + 232,239,239,107,128, 2, 93,112, 2, 85,205, 85,212,225,242,229, + 110,128, 36,160,243,233,236,239,110,129, 3,181, 85,222,244,239, + 238,239,115,128, 3,173,241,117, 2, 85,237, 86, 25,225,108,130, + 0, 61, 85,246, 86, 2,237,239,238,239,243,240,225,227,101,128, + 255, 29,115, 2, 86, 8, 86, 15,237,225,236,108,128,254,102,245, + 240,229,242,233,239,114,128, 32,124,233,246,225,236,229,238,227, + 101,128, 34, 97,114, 3, 86, 44, 86, 55, 86, 66,226,239,240,239, + 237,239,230,111,128, 49, 38,227,249,242,233,236,236,233, 99,128, + 4, 64,229,246,229,242,243,229,100,129, 2, 88, 86, 78,227,249, + 242,233,236,236,233, 99,128, 4, 77,115, 6, 86,103, 86,114, 86, + 134, 86,215, 87, 4, 87, 14,227,249,242,233,236,236,233, 99,128, + 4, 65,228,229,243,227,229,238,228,229,242,227,249,242,233,236, + 236,233, 99,128, 4,171,104,132, 2,131, 86,146, 86,153, 86,184, + 86,199,227,245,242,108,128, 2,134,239,242,116, 2, 86,161, 86, + 168,228,229,246, 97,128, 9, 14,246,239,247,229,236,243,233,231, + 238,228,229,246, 97,128, 9, 70,242,229,246,229,242,243,229,228, + 236,239,239,112,128, 1,170,243,241,245,225,244,242,229,246,229, + 242,243,229,100,128, 2,133,237,225,236,108, 2, 86,224, 86,235, + 232,233,242,225,231,225,238, 97,128, 48, 71,235,225,244,225,235, + 225,238, 97,129, 48,167, 86,248,232,225,236,230,247,233,228,244, + 104,128,255,106,244,233,237,225,244,229,100,128, 33, 46,245,240, + 229,242,233,239,114,128,246,236,116, 5, 87, 36, 87, 62, 87, 66, + 87, 83, 87,149, 97,130, 3,183, 87, 44, 87, 54,242,237,229,238, + 233,225,110,128, 5,104,244,239,238,239,115,128, 3,174,104,128, + 0,240,233,236,228,101,129, 30,189, 87, 75,226,229,236,239,119, + 128, 30, 27,238,225,232,244, 97, 3, 87, 95, 87,127, 87,136,230, + 239,245,235,104, 2, 87,105, 87,114,232,229,226,242,229,119,128, + 5,145,236,229,230,244,232,229,226,242,229,119,128, 5,145,232, + 229,226,242,229,119,128, 5,145,236,229,230,244,232,229,226,242, + 229,119,128, 5,145,245,242,238,229,100,128, 1,221,117, 2, 87, + 163, 87,172,235,239,242,229,225,110,128, 49, 97,242,111,128, 32, + 172,246,239,247,229,236,243,233,231,110, 3, 87,193, 87,203, 87, + 210,226,229,238,231,225,236,105,128, 9,199,228,229,246, 97,128, + 9, 71,231,245,234,225,242,225,244,105,128, 10,199,120, 2, 87, + 227, 88, 44,227,236,225,109,132, 0, 33, 87,242, 87,253, 88, 24, + 88, 36,225,242,237,229,238,233,225,110,128, 5, 92,100, 2, 88, + 3, 88, 8,226,108,128, 32, 60,239,247,110,129, 0,161, 88, 16, + 243,237,225,236,108,128,247,161,237,239,238,239,243,240,225,227, + 101,128,255, 1,243,237,225,236,108,128,247, 33,233,243,244,229, + 238,244,233,225,108,128, 34, 3,250,104,131, 2,146, 88, 67, 88, + 86, 88, 97, 99, 2, 88, 73, 88, 80,225,242,239,110,128, 1,239, + 245,242,108,128, 2,147,242,229,246,229,242,243,229,100,128, 1, + 185,244,225,233,108,128, 1,186,102,140, 0,102, 88,132, 88,214, + 88,225, 88,234, 88,246, 89, 93, 89,109, 91,117, 91,130, 91,156, + 93, 33, 93, 41, 97, 4, 88,142, 88,149, 88,160, 88,171,228,229, + 246, 97,128, 9, 94,231,245,242,237,245,235,232,105,128, 10, 94, + 232,242,229,238,232,229,233,116,128, 33, 9,244,232, 97, 3, 88, + 181, 88,190, 88,202,225,242,225,226,233, 99,128, 6, 78,236,239, + 247,225,242,225,226,233, 99,128, 6, 78,244,225,238,225,242,225, + 226,233, 99,128, 6, 75,226,239,240,239,237,239,230,111,128, 49, + 8,227,233,242,227,236,101,128, 36,213,228,239,244,225,227,227, + 229,238,116,128, 30, 31,101, 3, 88,254, 89, 76, 89, 86,104, 4, + 89, 8, 89, 31, 89, 45, 89, 61,225,114, 2, 89, 15, 89, 22,225, + 226,233, 99,128, 6, 65,237,229,238,233,225,110,128, 5,134,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,210,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,211,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,254,212,233,227,239,240, + 244,233, 99,128, 3,229,237,225,236,101,128, 38, 64,102,130,251, + 0, 89,101, 89,105,105,128,251, 3,108,128,251, 4,105,136,251, + 1, 89,129, 89,169, 89,180, 89,202, 90, 68, 90, 85, 90, 93, 90, + 106,230,244,229,229,110, 2, 89,139, 89,148,227,233,242,227,236, + 101,128, 36,110,112, 2, 89,154, 89,161,225,242,229,110,128, 36, + 130,229,242,233,239,100,128, 36,150,231,245,242,229,228,225,243, + 104,128, 32, 18,236,236,229,100, 2, 89,189, 89,195,226,239,120, + 128, 37,160,242,229,227,116,128, 37,172,238,225,108, 5, 89,216, + 89,255, 90, 16, 90, 33, 90, 49,235,225,102,130, 5,218, 89,226, + 89,246,228,225,231,229,243,104,129,251, 58, 89,237,232,229,226, + 242,229,119,128,251, 58,232,229,226,242,229,119,128, 5,218,237, + 229,109,129, 5,221, 90, 7,232,229,226,242,229,119,128, 5,221, + 238,245,110,129, 5,223, 90, 24,232,229,226,242,229,119,128, 5, + 223,240,101,129, 5,227, 90, 40,232,229,226,242,229,119,128, 5, + 227,244,243,225,228,105,129, 5,229, 90, 59,232,229,226,242,229, + 119,128, 5,229,242,243,244,244,239,238,229,227,232,233,238,229, + 243,101,128, 2,201,243,232,229,249,101,128, 37,201,244,225,227, + 249,242,233,236,236,233, 99,128, 4,115,246,101,142, 0, 53, 90, + 139, 90,148, 90,158, 90,188, 90,195, 90,205, 90,230, 91, 1, 91, + 35, 91, 47, 91, 58, 91, 91, 91, 99, 91,110,225,242,225,226,233, + 99,128, 6,101,226,229,238,231,225,236,105,128, 9,235,227,233, + 242,227,236,101,129, 36,100, 90,169,233,238,246,229,242,243,229, + 243,225,238,243,243,229,242,233,102,128, 39,142,228,229,246, 97, + 128, 9,107,229,233,231,232,244,232,115,128, 33, 93,231,117, 2, + 90,212, 90,221,234,225,242,225,244,105,128, 10,235,242,237,245, + 235,232,105,128, 10,107,232, 97, 2, 90,237, 90,248,227,235,225, + 242,225,226,233, 99,128, 6,101,238,231,250,232,239,117,128, 48, + 37,105, 2, 91, 7, 91, 25,228,229,239,231,242,225,240,232,233, + 227,240,225,242,229,110,128, 50, 36,238,230,229,242,233,239,114, + 128, 32,133,237,239,238,239,243,240,225,227,101,128,255, 21,239, + 236,228,243,244,249,236,101,128,247, 53,112, 2, 91, 64, 91, 71, + 225,242,229,110,128, 36,120,229,114, 2, 91, 78, 91, 84,233,239, + 100,128, 36,140,243,233,225,110,128, 6,245,242,239,237,225,110, + 128, 33,116,243,245,240,229,242,233,239,114,128, 32,117,244,232, + 225,105,128, 14, 85,108,129,251, 2, 91,123,239,242,233,110,128, + 1,146,109, 2, 91,136, 91,147,239,238,239,243,240,225,227,101, + 128,255, 70,243,241,245,225,242,101,128, 51,153,111, 4, 91,166, + 91,188, 91,200, 91,207,230, 97, 2, 91,173, 91,181,238,244,232, + 225,105,128, 14, 31,244,232,225,105,128, 14, 29,238,231,237,225, + 238,244,232,225,105,128, 14, 79,242,225,236,108,128, 34, 0,245, + 114,142, 0, 52, 91,240, 91,249, 92, 3, 92, 33, 92, 40, 92, 65, + 92, 92, 92,126, 92,138, 92,157, 92,168, 92,201, 92,209, 92,220, + 225,242,225,226,233, 99,128, 6,100,226,229,238,231,225,236,105, + 128, 9,234,227,233,242,227,236,101,129, 36, 99, 92, 14,233,238, + 246,229,242,243,229,243,225,238,243,243,229,242,233,102,128, 39, + 141,228,229,246, 97,128, 9,106,231,117, 2, 92, 47, 92, 56,234, + 225,242,225,244,105,128, 10,234,242,237,245,235,232,105,128, 10, + 106,232, 97, 2, 92, 72, 92, 83,227,235,225,242,225,226,233, 99, + 128, 6,100,238,231,250,232,239,117,128, 48, 36,105, 2, 92, 98, + 92,116,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 35,238,230,229,242,233,239,114,128, 32,132,237,239, + 238,239,243,240,225,227,101,128,255, 20,238,245,237,229,242,225, + 244,239,242,226,229,238,231,225,236,105,128, 9,247,239,236,228, + 243,244,249,236,101,128,247, 52,112, 2, 92,174, 92,181,225,242, + 229,110,128, 36,119,229,114, 2, 92,188, 92,194,233,239,100,128, + 36,139,243,233,225,110,128, 6,244,242,239,237,225,110,128, 33, + 115,243,245,240,229,242,233,239,114,128, 32,116,116, 2, 92,226, + 93, 8,229,229,110, 2, 92,234, 92,243,227,233,242,227,236,101, + 128, 36,109,112, 2, 92,249, 93, 0,225,242,229,110,128, 36,129, + 229,242,233,239,100,128, 36,149,104, 2, 93, 14, 93, 19,225,105, + 128, 14, 84,244,239,238,229,227,232,233,238,229,243,101,128, 2, + 203,240,225,242,229,110,128, 36,161,242, 97, 2, 93, 48, 93, 56, + 227,244,233,239,110,128, 32, 68,238, 99,128, 32,163,103,144, 0, + 103, 93, 97, 94, 43, 94, 66, 94,127, 94,144, 95, 65, 96, 58, 96, + 143, 96,156, 97, 14, 97, 39, 97, 67, 97, 89, 98, 34, 98, 56, 98, + 158, 97, 9, 93,117, 93,127, 93,134, 93,141, 93,205, 93,230, 93, + 241, 93,252, 94, 30,226,229,238,231,225,236,105,128, 9,151,227, + 245,244,101,128, 1,245,228,229,246, 97,128, 9, 23,102, 4, 93, + 151, 93,160, 93,174, 93,190,225,242,225,226,233, 99,128, 6,175, + 230,233,238,225,236,225,242,225,226,233, 99,128,251,147,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,251,148,237,229, + 228,233,225,236,225,242,225,226,233, 99,128,251,149,231,117, 2, + 93,212, 93,221,234,225,242,225,244,105,128, 10,151,242,237,245, + 235,232,105,128, 10, 23,232,233,242,225,231,225,238, 97,128, 48, + 76,235,225,244,225,235,225,238, 97,128, 48,172,237,237, 97,130, + 3,179, 94, 6, 94, 19,236,225,244,233,238,243,237,225,236,108, + 128, 2, 99,243,245,240,229,242,233,239,114,128, 2,224,238,231, + 233,225,227,239,240,244,233, 99,128, 3,235, 98, 2, 94, 49, 94, + 59,239,240,239,237,239,230,111,128, 49, 13,242,229,246,101,128, + 1, 31, 99, 4, 94, 76, 94, 83, 94, 92, 94,114,225,242,239,110, + 128, 1,231,229,228,233,236,236, 97,128, 1, 35,233,242, 99, 2, + 94,100, 94,105,236,101,128, 36,214,245,237,230,236,229,120,128, + 1, 29,239,237,237,225,225,227,227,229,238,116,128, 1, 35,228, + 239,116,129, 1, 33, 94,135,225,227,227,229,238,116,128, 1, 33, + 101, 6, 94,158, 94,169, 94,180, 94,191, 94,210, 95, 56,227,249, + 242,233,236,236,233, 99,128, 4, 51,232,233,242,225,231,225,238, + 97,128, 48, 82,235,225,244,225,235,225,238, 97,128, 48,178,239, + 237,229,244,242,233,227,225,236,236,249,229,241,245,225,108,128, + 34, 81,114, 3, 94,218, 95, 11, 95, 21,229,243,104, 3, 94,228, + 94,243, 94,252,225,227,227,229,238,244,232,229,226,242,229,119, + 128, 5,156,232,229,226,242,229,119,128, 5,243,237,245,241,228, + 225,237,232,229,226,242,229,119,128, 5,157,237,225,238,228,226, + 236,115,128, 0,223,243,232,225,249,233,109, 2, 95, 32, 95, 47, + 225,227,227,229,238,244,232,229,226,242,229,119,128, 5,158,232, + 229,226,242,229,119,128, 5,244,244,225,237,225,242,107,128, 48, + 19,104, 5, 95, 77, 95,210, 96, 17, 96, 42, 96, 48, 97, 4, 95, + 87, 95, 97, 95,120, 95,145,226,229,238,231,225,236,105,128, 9, + 152,100, 2, 95,103, 95,114,225,242,237,229,238,233,225,110,128, + 5,114,229,246, 97,128, 9, 24,231,117, 2, 95,127, 95,136,234, + 225,242,225,244,105,128, 10,152,242,237,245,235,232,105,128, 10, + 24,233,110, 4, 95,156, 95,165, 95,179, 95,195,225,242,225,226, + 233, 99,128, 6, 58,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,206,233,238,233,244,233,225,236,225,242,225,226,233, 99, + 128,254,207,237,229,228,233,225,236,225,242,225,226,233, 99,128, + 254,208,101, 3, 95,218, 95,239, 96, 0,237,233,228,228,236,229, + 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,149,243, + 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,147, + 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, + 145,232, 97, 2, 96, 24, 96, 31,228,229,246, 97,128, 9, 90,231, + 245,242,237,245,235,232,105,128, 10, 90,239,239,107,128, 2, 96, + 250,243,241,245,225,242,101,128, 51,147,105, 3, 96, 66, 96, 77, + 96, 88,232,233,242,225,231,225,238, 97,128, 48, 78,235,225,244, + 225,235,225,238, 97,128, 48,174,109, 2, 96, 94, 96,105,225,242, + 237,229,238,233,225,110,128, 5, 99,229,108,130, 5,210, 96,114, + 96,134,228,225,231,229,243,104,129,251, 50, 96,125,232,229,226, + 242,229,119,128,251, 50,232,229,226,242,229,119,128, 5,210,234, + 229,227,249,242,233,236,236,233, 99,128, 4, 83,236,239,244,244, + 225,108, 2, 96,167, 96,184,233,238,246,229,242,244,229,228,243, + 244,242,239,235,101,128, 1,190,243,244,239,112,132, 2,148, 96, + 199, 96,210, 96,216, 96,248,233,238,246,229,242,244,229,100,128, + 2,150,237,239,100,128, 2,192,242,229,246,229,242,243,229,100, + 130, 2,149, 96,231, 96,237,237,239,100,128, 2,193,243,245,240, + 229,242,233,239,114,128, 2,228,243,244,242,239,235,101,129, 2, + 161, 97, 3,242,229,246,229,242,243,229,100,128, 2,162,109, 2, + 97, 20, 97, 28,225,227,242,239,110,128, 30, 33,239,238,239,243, + 240,225,227,101,128,255, 71,111, 2, 97, 45, 97, 56,232,233,242, + 225,231,225,238, 97,128, 48, 84,235,225,244,225,235,225,238, 97, + 128, 48,180,240, 97, 2, 97, 74, 97, 80,242,229,110,128, 36,162, + 243,241,245,225,242,101,128, 51,172,114, 2, 97, 95, 97,192, 97, + 2, 97,101, 97,109,228,233,229,238,116,128, 34, 7,246,101,134, + 0, 96, 97,126, 97,137, 97,154, 97,161, 97,170, 97,182,226,229, + 236,239,247,227,237, 98,128, 3, 22, 99, 2, 97,143, 97,148,237, + 98,128, 3, 0,239,237, 98,128, 3, 0,228,229,246, 97,128, 9, + 83,236,239,247,237,239,100,128, 2,206,237,239,238,239,243,240, + 225,227,101,128,255, 64,244,239,238,229,227,237, 98,128, 3, 64, + 229,225,244,229,114,132, 0, 62, 97,208, 97,227, 97,239, 98, 26, + 229,241,245,225,108,129, 34,101, 97,218,239,242,236,229,243,115, + 128, 34,219,237,239,238,239,243,240,225,227,101,128,255, 30,111, + 2, 97,245, 98, 15,114, 2, 97,251, 98, 8,229,241,245,233,246, + 225,236,229,238,116,128, 34,115,236,229,243,115,128, 34,119,246, + 229,242,229,241,245,225,108,128, 34,103,243,237,225,236,108,128, + 254,101,115, 2, 98, 40, 98, 48,227,242,233,240,116,128, 2, 97, + 244,242,239,235,101,128, 1,229,117, 4, 98, 66, 98, 77, 98,134, + 98,145,232,233,242,225,231,225,238, 97,128, 48, 80,233,108, 2, + 98, 84, 98,109,236,229,237,239,116, 2, 98, 94, 98,101,236,229, + 230,116,128, 0,171,242,233,231,232,116,128, 0,187,243,233,238, + 231,108, 2, 98,119, 98,126,236,229,230,116,128, 32, 57,242,233, + 231,232,116,128, 32, 58,235,225,244,225,235,225,238, 97,128, 48, + 176,242,225,237,245,243,241,245,225,242,101,128, 51, 24,249,243, + 241,245,225,242,101,128, 51,201,104,144, 0,104, 98,204,101, 90, + 101,125,101,162,101,202,103, 90,103,110,104, 75,104, 87,104, 99, + 105,167,105,175,105,186,105,195,106, 19,106, 23, 97, 13, 98,232, + 99, 15, 99, 25, 99, 55, 99, 80, 99,158, 99,170, 99,195, 99,210, + 99,239, 99,252,100, 54,100, 63, 97, 2, 98,238, 99, 1,226,235, + 232,225,243,233,225,238,227,249,242,233,236,236,233, 99,128, 4, + 169,236,244,239,238,229,225,242,225,226,233, 99,128, 6,193,226, + 229,238,231,225,236,105,128, 9,185,228,101, 2, 99, 32, 99, 50, + 243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, + 4,179,246, 97,128, 9, 57,231,117, 2, 99, 62, 99, 71,234,225, + 242,225,244,105,128, 10,185,242,237,245,235,232,105,128, 10, 57, + 104, 4, 99, 90, 99, 99, 99,113, 99,143,225,242,225,226,233, 99, + 128, 6, 45,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 162,105, 2, 99,119, 99,134,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,254,163,242,225,231,225,238, 97,128, 48,111,237, + 229,228,233,225,236,225,242,225,226,233, 99,128,254,164,233,244, + 245,243,241,245,225,242,101,128, 51, 42,235,225,244,225,235,225, + 238, 97,129, 48,207, 99,183,232,225,236,230,247,233,228,244,104, + 128,255,138,236,225,238,244,231,245,242,237,245,235,232,105,128, + 10, 77,237,250, 97, 2, 99,218, 99,227,225,242,225,226,233, 99, + 128, 6, 33,236,239,247,225,242,225,226,233, 99,128, 6, 33,238, + 231,245,236,230,233,236,236,229,114,128, 49,100,114, 2,100, 2, + 100, 18,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, + 4, 74,240,239,239,110, 2,100, 27,100, 40,236,229,230,244,226, + 225,242,226,245,112,128, 33,188,242,233,231,232,244,226,225,242, + 226,245,112,128, 33,192,243,241,245,225,242,101,128, 51,202,244, + 225,102, 3,100, 73,100,165,101, 0,240,225,244,225,104,134, 5, + 178,100, 93,100, 98,100,112,100,121,100,136,100,152,177, 54,128, + 5,178, 50, 2,100,104,100,108, 51,128, 5,178,102,128, 5,178, + 232,229,226,242,229,119,128, 5,178,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,178,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,178,247,233,228,229,232,229,226,242, + 229,119,128, 5,178,241,225,237,225,244,115,135, 5,179,100,188, + 100,193,100,198,100,203,100,212,100,227,100,243,177, 98,128, 5, + 179,178, 56,128, 5,179,179, 52,128, 5,179,232,229,226,242,229, + 119,128, 5,179,238,225,242,242,239,247,232,229,226,242,229,119, + 128, 5,179,241,245,225,242,244,229,242,232,229,226,242,229,119, + 128, 5,179,247,233,228,229,232,229,226,242,229,119,128, 5,179, + 243,229,231,239,108,135, 5,177,101, 22,101, 27,101, 32,101, 37, + 101, 46,101, 61,101, 77,177, 55,128, 5,177,178, 52,128, 5,177, + 179, 48,128, 5,177,232,229,226,242,229,119,128, 5,177,238,225, + 242,242,239,247,232,229,226,242,229,119,128, 5,177,241,245,225, + 242,244,229,242,232,229,226,242,229,119,128, 5,177,247,233,228, + 229,232,229,226,242,229,119,128, 5,177, 98, 3,101, 98,101,103, + 101,113,225,114,128, 1, 39,239,240,239,237,239,230,111,128, 49, + 15,242,229,246,229,226,229,236,239,119,128, 30, 43, 99, 2,101, + 131,101,140,229,228,233,236,236, 97,128, 30, 41,233,242, 99, 2, + 101,148,101,153,236,101,128, 36,215,245,237,230,236,229,120,128, + 1, 37,100, 2,101,168,101,178,233,229,242,229,243,233,115,128, + 30, 39,239,116, 2,101,185,101,194,225,227,227,229,238,116,128, + 30, 35,226,229,236,239,119,128, 30, 37,101,136, 5,212,101,222, + 101,255,102, 19,102,248,103, 8,103, 53,103, 62,103, 75,225,242, + 116,129, 38,101,101,230,243,245,233,116, 2,101,239,101,247,226, + 236,225,227,107,128, 38,101,247,232,233,244,101,128, 38, 97,228, + 225,231,229,243,104,129,251, 52,102, 10,232,229,226,242,229,119, + 128,251, 52,104, 6,102, 33,102, 61,102, 69,102,119,102,165,102, + 214, 97, 2,102, 39,102, 53,236,244,239,238,229,225,242,225,226, + 233, 99,128, 6,193,242,225,226,233, 99,128, 6, 71,229,226,242, + 229,119,128, 5,212,230,233,238,225,236, 97, 2,102, 80,102,111, + 236,116, 2,102, 87,102, 99,239,238,229,225,242,225,226,233, 99, + 128,251,167,244,247,239,225,242,225,226,233, 99,128,254,234,242, + 225,226,233, 99,128,254,234,232,225,237,250,225,225,226,239,246, + 101, 2,102,134,102,148,230,233,238,225,236,225,242,225,226,233, + 99,128,251,165,233,243,239,236,225,244,229,228,225,242,225,226, + 233, 99,128,251,164,105, 2,102,171,102,205,238,233,244,233,225, + 236, 97, 2,102,183,102,197,236,244,239,238,229,225,242,225,226, + 233, 99,128,251,168,242,225,226,233, 99,128,254,235,242,225,231, + 225,238, 97,128, 48,120,237,229,228,233,225,236, 97, 2,102,226, + 102,240,236,244,239,238,229,225,242,225,226,233, 99,128,251,169, + 242,225,226,233, 99,128,254,236,233,243,229,233,229,242,225,243, + 241,245,225,242,101,128, 51,123,107, 2,103, 14,103, 38,225,244, + 225,235,225,238, 97,129, 48,216,103, 26,232,225,236,230,247,233, + 228,244,104,128,255,141,245,244,225,225,242,245,243,241,245,225, + 242,101,128, 51, 54,238,231,232,239,239,107,128, 2,103,242,245, + 244,245,243,241,245,225,242,101,128, 51, 57,116,129, 5,215,103, + 81,232,229,226,242,229,119,128, 5,215,232,239,239,107,129, 2, + 102,103, 99,243,245,240,229,242,233,239,114,128, 2,177,105, 4, + 103,120,103,205,103,216,103,241,229,245,104, 4,103,132,103,167, + 103,182,103,191, 97, 2,103,138,103,153,227,233,242,227,236,229, + 235,239,242,229,225,110,128, 50,123,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 27,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50,109,235,239,242,229,225,110,128, 49, 78,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 13,232,233,242, + 225,231,225,238, 97,128, 48,114,235,225,244,225,235,225,238, 97, + 129, 48,210,103,229,232,225,236,230,247,233,228,244,104,128,255, + 139,242,233,113,134, 5,180,104, 3,104, 8,104, 22,104, 31,104, + 46,104, 62,177, 52,128, 5,180, 50, 2,104, 14,104, 18, 49,128, + 5,180,100,128, 5,180,232,229,226,242,229,119,128, 5,180,238, + 225,242,242,239,247,232,229,226,242,229,119,128, 5,180,241,245, + 225,242,244,229,242,232,229,226,242,229,119,128, 5,180,247,233, + 228,229,232,229,226,242,229,119,128, 5,180,236,233,238,229,226, + 229,236,239,119,128, 30,150,237,239,238,239,243,240,225,227,101, + 128,255, 72,111, 9,104,119,104,130,104,154,104,179,105, 11,105, + 24,105,110,105,150,105,161,225,242,237,229,238,233,225,110,128, + 5,112,232,105, 2,104,137,104,145,240,244,232,225,105,128, 14, + 43,242,225,231,225,238, 97,128, 48,123,235,225,244,225,235,225, + 238, 97,129, 48,219,104,167,232,225,236,230,247,233,228,244,104, + 128,255,142,236,225,109,135, 5,185,104,199,104,204,104,209,104, + 214,104,223,104,238,104,254,177, 57,128, 5,185,178, 54,128, 5, + 185,179, 50,128, 5,185,232,229,226,242,229,119,128, 5,185,238, + 225,242,242,239,247,232,229,226,242,229,119,128, 5,185,241,245, + 225,242,244,229,242,232,229,226,242,229,119,128, 5,185,247,233, + 228,229,232,229,226,242,229,119,128, 5,185,238,239,235,232,245, + 235,244,232,225,105,128, 14, 46,111, 2,105, 30,105,100,107, 4, + 105, 40,105, 52,105, 58,105, 80,225,226,239,246,229,227,239,237, + 98,128, 3, 9,227,237, 98,128, 3, 9,240,225,236,225,244,225, + 236,233,250,229,228,226,229,236,239,247,227,237, 98,128, 3, 33, + 242,229,244,242,239,230,236,229,248,226,229,236,239,247,227,237, + 98,128, 3, 34,238,243,241,245,225,242,101,128, 51, 66,114, 2, + 105,116,105,143,105, 2,105,122,105,131,227,239,240,244,233, 99, + 128, 3,233,250,239,238,244,225,236,226,225,114,128, 32, 21,238, + 227,237, 98,128, 3, 27,244,243,240,242,233,238,231,115,128, 38, + 104,245,243,101,128, 35, 2,240,225,242,229,110,128, 36,163,243, + 245,240,229,242,233,239,114,128, 2,176,244,245,242,238,229,100, + 128, 2,101,117, 4,105,205,105,216,105,229,105,254,232,233,242, + 225,231,225,238, 97,128, 48,117,233,233,244,239,243,241,245,225, + 242,101,128, 51, 51,235,225,244,225,235,225,238, 97,129, 48,213, + 105,242,232,225,236,230,247,233,228,244,104,128,255,140,238,231, + 225,242,245,237,236,225,245,116,129, 2,221,106, 13,227,237, 98, + 128, 3, 11,118,128, 1,149,249,240,232,229,110,132, 0, 45,106, + 39,106, 50,106, 62,106, 85,233,238,230,229,242,233,239,114,128, + 246,229,237,239,238,239,243,240,225,227,101,128,255, 13,115, 2, + 106, 68,106, 75,237,225,236,108,128,254, 99,245,240,229,242,233, + 239,114,128,246,230,244,247,111,128, 32, 16,105,149, 0,105,106, + 137,106,160,106,194,106,241,110,123,110,243,111, 24,111, 51,111, + 213,111,217,111,255,112, 21,112,105,113, 14,113, 89,113, 97,113, + 110,113,197,113,254,114, 26,114, 70,225, 99, 2,106,144,106,150, + 245,244,101,128, 0,237,249,242,233,236,236,233, 99,128, 4, 79, + 98, 3,106,168,106,177,106,187,229,238,231,225,236,105,128, 9, + 135,239,240,239,237,239,230,111,128, 49, 39,242,229,246,101,128, + 1, 45, 99, 3,106,202,106,209,106,231,225,242,239,110,128, 1, + 208,233,242, 99, 2,106,217,106,222,236,101,128, 36,216,245,237, + 230,236,229,120,128, 0,238,249,242,233,236,236,233, 99,128, 4, + 86,100, 4,106,251,107, 5,110, 80,110,113,226,236,231,242,225, + 246,101,128, 2, 9,101, 2,107, 11,110, 75,239,231,242,225,240, + 104, 7,107, 32,107, 46,107, 59,109,244,110, 19,110, 32,110, 44, + 229,225,242,244,232,227,233,242,227,236,101,128, 50,143,230,233, + 242,229,227,233,242,227,236,101,128, 50,139,233, 99, 14,107, 90, + 107,106,107,205,108, 3,108, 69,108, 98,108,114,108,171,108,220, + 108,232,109, 3,109, 70,109,208,109,237,225,236,236,233,225,238, + 227,229,240,225,242,229,110,128, 50, 63, 99, 4,107,116,107,127, + 107,141,107,148,225,236,236,240,225,242,229,110,128, 50, 58,229, + 238,244,242,229,227,233,242,227,236,101,128, 50,165,236,239,243, + 101,128, 48, 6,111, 3,107,156,107,171,107,191,237,237, 97,129, + 48, 1,107,164,236,229,230,116,128,255,100,238,231,242,225,244, + 245,236,225,244,233,239,238,240,225,242,229,110,128, 50, 55,242, + 242,229,227,244,227,233,242,227,236,101,128, 50,163,101, 3,107, + 213,107,225,107,242,225,242,244,232,240,225,242,229,110,128, 50, + 47,238,244,229,242,240,242,233,243,229,240,225,242,229,110,128, + 50, 61,248,227,229,236,236,229,238,244,227,233,242,227,236,101, + 128, 50,157,102, 2,108, 9,108, 24,229,243,244,233,246,225,236, + 240,225,242,229,110,128, 50, 64,105, 2,108, 30,108, 59,238,225, + 238,227,233,225,108, 2,108, 42,108, 51,227,233,242,227,236,101, + 128, 50,150,240,225,242,229,110,128, 50, 54,242,229,240,225,242, + 229,110,128, 50, 43,104, 2,108, 75,108, 86,225,246,229,240,225, + 242,229,110,128, 50, 50,233,231,232,227,233,242,227,236,101,128, + 50,164,233,244,229,242,225,244,233,239,238,237,225,242,107,128, + 48, 5,108, 3,108,122,108,148,108,160,225,226,239,114, 2,108, + 131,108,140,227,233,242,227,236,101,128, 50,152,240,225,242,229, + 110,128, 50, 56,229,230,244,227,233,242,227,236,101,128, 50,167, + 239,247,227,233,242,227,236,101,128, 50,166,109, 2,108,177,108, + 209,101, 2,108,183,108,198,228,233,227,233,238,229,227,233,242, + 227,236,101,128, 50,169,244,225,236,240,225,242,229,110,128, 50, + 46,239,239,238,240,225,242,229,110,128, 50, 42,238,225,237,229, + 240,225,242,229,110,128, 50, 52,112, 2,108,238,108,246,229,242, + 233,239,100,128, 48, 2,242,233,238,244,227,233,242,227,236,101, + 128, 50,158,114, 2,109, 9,109, 57,101, 3,109, 17,109, 28,109, + 43,225,227,232,240,225,242,229,110,128, 50, 67,240,242,229,243, + 229,238,244,240,225,242,229,110,128, 50, 57,243,239,245,242,227, + 229,240,225,242,229,110,128, 50, 62,233,231,232,244,227,233,242, + 227,236,101,128, 50,168,115, 5,109, 82,109,111,109,125,109,150, + 109,178,101, 2,109, 88,109,101,227,242,229,244,227,233,242,227, + 236,101,128, 50,153,236,230,240,225,242,229,110,128, 50, 66,239, + 227,233,229,244,249,240,225,242,229,110,128, 50, 51,112, 2,109, + 131,109,137,225,227,101,128, 48, 0,229,227,233,225,236,240,225, + 242,229,110,128, 50, 53,116, 2,109,156,109,167,239,227,235,240, + 225,242,229,110,128, 50, 49,245,228,249,240,225,242,229,110,128, + 50, 59,117, 2,109,184,109,193,238,240,225,242,229,110,128, 50, + 48,240,229,242,246,233,243,229,240,225,242,229,110,128, 50, 60, + 119, 2,109,214,109,226,225,244,229,242,240,225,242,229,110,128, + 50, 44,239,239,228,240,225,242,229,110,128, 50, 45,250,229,242, + 111,128, 48, 7,109, 2,109,250,110, 7,229,244,225,236,227,233, + 242,227,236,101,128, 50,142,239,239,238,227,233,242,227,236,101, + 128, 50,138,238,225,237,229,227,233,242,227,236,101,128, 50,148, + 243,245,238,227,233,242,227,236,101,128, 50,144,119, 2,110, 50, + 110, 63,225,244,229,242,227,233,242,227,236,101,128, 50,140,239, + 239,228,227,233,242,227,236,101,128, 50,141,246, 97,128, 9, 7, + 233,229,242,229,243,233,115,130, 0,239,110, 94,110,102,225,227, + 245,244,101,128, 30, 47,227,249,242,233,236,236,233, 99,128, 4, + 229,239,244,226,229,236,239,119,128, 30,203,101, 3,110,131,110, + 147,110,158,226,242,229,246,229,227,249,242,233,236,236,233, 99, + 128, 4,215,227,249,242,233,236,236,233, 99,128, 4, 53,245,238, + 103, 4,110,170,110,205,110,220,110,229, 97, 2,110,176,110,191, + 227,233,242,227,236,229,235,239,242,229,225,110,128, 50,117,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 21,227,233,242, + 227,236,229,235,239,242,229,225,110,128, 50,103,235,239,242,229, + 225,110,128, 49, 71,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 7,103, 2,110,249,111, 0,242,225,246,101,128, 0,236, + 117, 2,111, 6,111, 15,234,225,242,225,244,105,128, 10,135,242, + 237,245,235,232,105,128, 10, 7,104, 2,111, 30,111, 40,233,242, + 225,231,225,238, 97,128, 48, 68,239,239,235,225,226,239,246,101, + 128, 30,201,105, 8,111, 69,111, 79,111, 90,111, 97,111,122,111, + 138,111,153,111,169,226,229,238,231,225,236,105,128, 9,136,227, + 249,242,233,236,236,233, 99,128, 4, 56,228,229,246, 97,128, 9, + 8,231,117, 2,111,104,111,113,234,225,242,225,244,105,128, 10, + 136,242,237,245,235,232,105,128, 10, 8,237,225,244,242,225,231, + 245,242,237,245,235,232,105,128, 10, 64,238,246,229,242,244,229, + 228,226,242,229,246,101,128, 2, 11,243,232,239,242,244,227,249, + 242,233,236,236,233, 99,128, 4, 57,246,239,247,229,236,243,233, + 231,110, 3,111,185,111,195,111,202,226,229,238,231,225,236,105, + 128, 9,192,228,229,246, 97,128, 9, 64,231,245,234,225,242,225, + 244,105,128, 10,192,106,128, 1, 51,107, 2,111,223,111,247,225, + 244,225,235,225,238, 97,129, 48,164,111,235,232,225,236,230,247, + 233,228,244,104,128,255,114,239,242,229,225,110,128, 49, 99,108, + 2,112, 5,112, 10,228,101,128, 2,220,245,249,232,229,226,242, + 229,119,128, 5,172,109, 2,112, 27,112, 94, 97, 3,112, 35,112, + 55,112, 80,227,242,239,110,129, 1, 43,112, 44,227,249,242,233, + 236,236,233, 99,128, 4,227,231,229,239,242,225,240,240,242,239, + 248,233,237,225,244,229,236,249,229,241,245,225,108,128, 34, 83, + 244,242,225,231,245,242,237,245,235,232,105,128, 10, 63,239,238, + 239,243,240,225,227,101,128,255, 73,110, 5,112,117,112,127,112, + 136,112,148,112,232,227,242,229,237,229,238,116,128, 34, 6,230, + 233,238,233,244,121,128, 34, 30,233,225,242,237,229,238,233,225, + 110,128, 5,107,116, 2,112,154,112,222,101, 2,112,160,112,211, + 231,242,225,108,131, 34, 43,112,173,112,191,112,196, 98, 2,112, + 179,112,187,239,244,244,239,109,128, 35, 33,116,128, 35, 33,229, + 120,128,248,245,116, 2,112,202,112,207,239,112,128, 35, 32,112, + 128, 35, 32,242,243,229,227,244,233,239,110,128, 34, 41,233,243, + 241,245,225,242,101,128, 51, 5,118, 3,112,240,112,249,113, 2, + 226,245,236,236,229,116,128, 37,216,227,233,242,227,236,101,128, + 37,217,243,237,233,236,229,230,225,227,101,128, 38, 59,111, 3, + 113, 22,113, 33,113, 41,227,249,242,233,236,236,233, 99,128, 4, + 81,231,239,238,229,107,128, 1, 47,244, 97,131, 3,185,113, 52, + 113, 73,113, 81,228,233,229,242,229,243,233,115,129, 3,202,113, + 65,244,239,238,239,115,128, 3,144,236,225,244,233,110,128, 2, + 105,244,239,238,239,115,128, 3,175,240,225,242,229,110,128, 36, + 164,242,233,231,245,242,237,245,235,232,105,128, 10,114,115, 4, + 113,120,113,165,113,179,113,187,237,225,236,108, 2,113,129,113, + 140,232,233,242,225,231,225,238, 97,128, 48, 67,235,225,244,225, + 235,225,238, 97,129, 48,163,113,153,232,225,236,230,247,233,228, + 244,104,128,255,104,243,232,225,242,226,229,238,231,225,236,105, + 128, 9,250,244,242,239,235,101,128, 2,104,245,240,229,242,233, + 239,114,128,246,237,116, 2,113,203,113,237,229,242,225,244,233, + 239,110, 2,113,215,113,226,232,233,242,225,231,225,238, 97,128, + 48,157,235,225,244,225,235,225,238, 97,128, 48,253,233,236,228, + 101,129, 1, 41,113,246,226,229,236,239,119,128, 30, 45,117, 2, + 114, 4,114, 15,226,239,240,239,237,239,230,111,128, 49, 41,227, + 249,242,233,236,236,233, 99,128, 4, 78,246,239,247,229,236,243, + 233,231,110, 3,114, 42,114, 52,114, 59,226,229,238,231,225,236, + 105,128, 9,191,228,229,246, 97,128, 9, 63,231,245,234,225,242, + 225,244,105,128, 10,191,250,232,233,244,243, 97, 2,114, 81,114, + 92,227,249,242,233,236,236,233, 99,128, 4,117,228,226,236,231, + 242,225,246,229,227,249,242,233,236,236,233, 99,128, 4,119,106, + 138, 0,106,114,135,114,198,114,209,115, 3,115, 19,115,132,115, + 201,115,206,115,218,115,226, 97, 4,114,145,114,156,114,166,114, + 173,225,242,237,229,238,233,225,110,128, 5,113,226,229,238,231, + 225,236,105,128, 9,156,228,229,246, 97,128, 9, 28,231,117, 2, + 114,180,114,189,234,225,242,225,244,105,128, 10,156,242,237,245, + 235,232,105,128, 10, 28,226,239,240,239,237,239,230,111,128, 49, + 16, 99, 3,114,217,114,224,114,246,225,242,239,110,128, 1,240, + 233,242, 99, 2,114,232,114,237,236,101,128, 36,217,245,237,230, + 236,229,120,128, 1, 53,242,239,243,243,229,228,244,225,233,108, + 128, 2,157,228,239,244,236,229,243,243,243,244,242,239,235,101, + 128, 2, 95,101, 3,115, 27,115, 38,115,103,227,249,242,233,236, + 236,233, 99,128, 4, 88,229,109, 4,115, 49,115, 58,115, 72,115, + 88,225,242,225,226,233, 99,128, 6, 44,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,158,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,159,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,254,160,104, 2,115,109,115,118,225,242,225, + 226,233, 99,128, 6,152,230,233,238,225,236,225,242,225,226,233, + 99,128,251,139,104, 2,115,138,115,188, 97, 3,115,146,115,156, + 115,163,226,229,238,231,225,236,105,128, 9,157,228,229,246, 97, + 128, 9, 29,231,117, 2,115,170,115,179,234,225,242,225,244,105, + 128, 10,157,242,237,245,235,232,105,128, 10, 29,229,232,225,242, + 237,229,238,233,225,110,128, 5,123,233,115,128, 48, 4,237,239, + 238,239,243,240,225,227,101,128,255, 74,240,225,242,229,110,128, + 36,165,243,245,240,229,242,233,239,114,128, 2,178,107,146, 0, + 107,116, 21,118,110,118,121,118,183,118,194,119, 28,119, 42,120, + 150,121, 90,121,103,121,129,121,178,122, 60,122, 82,122, 95,122, + 118,122,160,122,170, 97, 12,116, 47,116, 79,116,101,116,131,116, + 245,117, 14,117, 44,117, 69,117,175,117,189,118, 56,118, 85, 98, + 2,116, 53,116, 70,225,243,232,235,233,242,227,249,242,233,236, + 236,233, 99,128, 4,161,229,238,231,225,236,105,128, 9,149, 99, + 2,116, 85,116, 91,245,244,101,128, 30, 49,249,242,233,236,236, + 233, 99,128, 4, 58,228,101, 2,116,108,116,126,243,227,229,238, + 228,229,242,227,249,242,233,236,236,233, 99,128, 4,155,246, 97, + 128, 9, 21,102,135, 5,219,116,149,116,158,116,178,116,192,116, + 201,116,217,116,232,225,242,225,226,233, 99,128, 6, 67,228,225, + 231,229,243,104,129,251, 59,116,169,232,229,226,242,229,119,128, + 251, 59,230,233,238,225,236,225,242,225,226,233, 99,128,254,218, + 232,229,226,242,229,119,128, 5,219,233,238,233,244,233,225,236, + 225,242,225,226,233, 99,128,254,219,237,229,228,233,225,236,225, + 242,225,226,233, 99,128,254,220,242,225,230,229,232,229,226,242, + 229,119,128,251, 77,231,117, 2,116,252,117, 5,234,225,242,225, + 244,105,128, 10,149,242,237,245,235,232,105,128, 10, 21,104, 2, + 117, 20,117, 30,233,242,225,231,225,238, 97,128, 48, 75,239,239, + 235,227,249,242,233,236,236,233, 99,128, 4,196,235,225,244,225, + 235,225,238, 97,129, 48,171,117, 57,232,225,236,230,247,233,228, + 244,104,128,255,118,112, 2,117, 75,117, 96,240, 97,129, 3,186, + 117, 82,243,249,237,226,239,236,231,242,229,229,107,128, 3,240, + 249,229,239,245,110, 3,117,108,117,122,117,156,237,233,229,245, + 237,235,239,242,229,225,110,128, 49,113,112, 2,117,128,117,143, + 232,233,229,245,240,232,235,239,242,229,225,110,128, 49,132,233, + 229,245,240,235,239,242,229,225,110,128, 49,120,243,243,225,238, + 231,240,233,229,245,240,235,239,242,229,225,110,128, 49,121,242, + 239,242,233,233,243,241,245,225,242,101,128, 51, 13,115, 5,117, + 201,117,245,118, 4,118, 12,118, 40,232,233,228,225,225,245,244, + 111, 2,117,214,117,223,225,242,225,226,233, 99,128, 6, 64,238, + 239,243,233,228,229,226,229,225,242,233,238,231,225,242,225,226, + 233, 99,128, 6, 64,237,225,236,236,235,225,244,225,235,225,238, + 97,128, 48,245,241,245,225,242,101,128, 51,132,242, 97, 2,118, + 19,118, 28,225,242,225,226,233, 99,128, 6, 80,244,225,238,225, + 242,225,226,233, 99,128, 6, 77,244,242,239,235,229,227,249,242, + 233,236,236,233, 99,128, 4,159,244,225,232,233,242,225,240,242, + 239,236,239,238,231,237,225,242,235,232,225,236,230,247,233,228, + 244,104,128,255,112,246,229,242,244,233,227,225,236,243,244,242, + 239,235,229,227,249,242,233,236,236,233, 99,128, 4,157,226,239, + 240,239,237,239,230,111,128, 49, 14, 99, 4,118,131,118,153,118, + 162,118,170, 97, 2,118,137,118,147,236,243,241,245,225,242,101, + 128, 51,137,242,239,110,128, 1,233,229,228,233,236,236, 97,128, + 1, 55,233,242,227,236,101,128, 36,218,239,237,237,225,225,227, + 227,229,238,116,128, 1, 55,228,239,244,226,229,236,239,119,128, + 30, 51,101, 4,118,204,118,231,119, 0,119, 12,104, 2,118,210, + 118,221,225,242,237,229,238,233,225,110,128, 5,132,233,242,225, + 231,225,238, 97,128, 48, 81,235,225,244,225,235,225,238, 97,129, + 48,177,118,244,232,225,236,230,247,233,228,244,104,128,255,121, + 238,225,242,237,229,238,233,225,110,128, 5,111,243,237,225,236, + 236,235,225,244,225,235,225,238, 97,128, 48,246,231,242,229,229, + 238,236,225,238,228,233, 99,128, 1, 56,104, 6,119, 56,119,185, + 119,196,119,221,120, 52,120,140, 97, 5,119, 68,119, 78,119, 89, + 119, 96,119,121,226,229,238,231,225,236,105,128, 9,150,227,249, + 242,233,236,236,233, 99,128, 4, 69,228,229,246, 97,128, 9, 22, + 231,117, 2,119,103,119,112,234,225,242,225,244,105,128, 10,150, + 242,237,245,235,232,105,128, 10, 22,104, 4,119,131,119,140,119, + 154,119,170,225,242,225,226,233, 99,128, 6, 46,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,166,233,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,167,237,229,228,233,225,236, + 225,242,225,226,233, 99,128,254,168,229,233,227,239,240,244,233, + 99,128, 3,231,232, 97, 2,119,203,119,210,228,229,246, 97,128, + 9, 89,231,245,242,237,245,235,232,105,128, 10, 89,233,229,245, + 235,104, 4,119,235,120, 14,120, 29,120, 38, 97, 2,119,241,120, + 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,120, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 24,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50,106,235,239,242, + 229,225,110,128, 49, 75,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 10,111, 4,120, 62,120,111,120,121,120,126,235,104, + 4,120, 73,120, 82,120, 91,120,101,225,233,244,232,225,105,128, + 14, 2,239,238,244,232,225,105,128, 14, 5,245,225,244,244,232, + 225,105,128, 14, 3,247,225,233,244,232,225,105,128, 14, 4,237, + 245,244,244,232,225,105,128, 14, 91,239,107,128, 1,153,242,225, + 235,232,225,238,231,244,232,225,105,128, 14, 6,250,243,241,245, + 225,242,101,128, 51,145,105, 4,120,160,120,171,120,196,120,245, + 232,233,242,225,231,225,238, 97,128, 48, 77,235,225,244,225,235, + 225,238, 97,129, 48,173,120,184,232,225,236,230,247,233,228,244, + 104,128,255,119,242,111, 3,120,205,120,220,120,236,231,245,242, + 225,237,245,243,241,245,225,242,101,128, 51, 21,237,229,229,244, + 239,242,245,243,241,245,225,242,101,128, 51, 22,243,241,245,225, + 242,101,128, 51, 20,249,229,239,107, 5,121, 4,121, 39,121, 54, + 121, 63,121, 77, 97, 2,121, 10,121, 25,227,233,242,227,236,229, + 235,239,242,229,225,110,128, 50,110,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 14,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50, 96,235,239,242,229,225,110,128, 49, 49,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 0,243,233,239, + 243,235,239,242,229,225,110,128, 49, 51,234,229,227,249,242,233, + 236,236,233, 99,128, 4, 92,108, 2,121,109,121,120,233,238,229, + 226,229,236,239,119,128, 30, 53,243,241,245,225,242,101,128, 51, + 152,109, 3,121,137,121,151,121,162,227,245,226,229,228,243,241, + 245,225,242,101,128, 51,166,239,238,239,243,240,225,227,101,128, + 255, 75,243,241,245,225,242,229,228,243,241,245,225,242,101,128, + 51,162,111, 5,121,190,121,216,121,254,122, 10,122, 24,104, 2, + 121,196,121,206,233,242,225,231,225,238, 97,128, 48, 83,237,243, + 241,245,225,242,101,128, 51,192,235, 97, 2,121,223,121,231,233, + 244,232,225,105,128, 14, 1,244,225,235,225,238, 97,129, 48,179, + 121,242,232,225,236,230,247,233,228,244,104,128,255,122,239,240, + 239,243,241,245,225,242,101,128, 51, 30,240,240,225,227,249,242, + 233,236,236,233, 99,128, 4,129,114, 2,122, 30,122, 50,229,225, + 238,243,244,225,238,228,225,242,228,243,249,237,226,239,108,128, + 50,127,239,238,233,243,227,237, 98,128, 3, 67,240, 97, 2,122, + 67,122, 73,242,229,110,128, 36,166,243,241,245,225,242,101,128, + 51,170,243,233,227,249,242,233,236,236,233, 99,128, 4,111,116, + 2,122,101,122,110,243,241,245,225,242,101,128, 51,207,245,242, + 238,229,100,128, 2,158,117, 2,122,124,122,135,232,233,242,225, + 231,225,238, 97,128, 48, 79,235,225,244,225,235,225,238, 97,129, + 48,175,122,148,232,225,236,230,247,233,228,244,104,128,255,120, + 246,243,241,245,225,242,101,128, 51,184,247,243,241,245,225,242, + 101,128, 51,190,108,146, 0,108,122,220,124,247,125, 20,125, 86, + 125,124,126, 20,126, 29,126, 45,126, 69,126, 87,126,205,126,246, + 127,125,127,133,127,166,127,175,127,183,127,245, 97, 7,122,236, + 122,246,122,253,123, 4,123, 29,123, 45,124,235,226,229,238,231, + 225,236,105,128, 9,178,227,245,244,101,128, 1, 58,228,229,246, + 97,128, 9, 50,231,117, 2,123, 11,123, 20,234,225,242,225,244, + 105,128, 10,178,242,237,245,235,232,105,128, 10, 50,235,235,232, + 225,238,231,249,225,239,244,232,225,105,128, 14, 69,109, 10,123, + 67,124, 6,124, 23,124, 61,124, 75,124, 94,124,110,124,130,124, + 150,124,173, 97, 2,123, 73,123,254,236,229,102, 4,123, 85,123, + 99,123,191,123,208,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,252,232,225,237,250, 97, 2,123,109,123,150,225,226,239, + 246,101, 2,123,119,123,133,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,248,233,243,239,236,225,244,229,228,225,242,225, + 226,233, 99,128,254,247,226,229,236,239,119, 2,123,160,123,174, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,250,233,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,254,249,233, + 243,239,236,225,244,229,228,225,242,225,226,233, 99,128,254,251, + 237,225,228,228,225,225,226,239,246,101, 2,123,223,123,237,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,246,233,243,239, + 236,225,244,229,228,225,242,225,226,233, 99,128,254,245,242,225, + 226,233, 99,128, 6, 68,226,228, 97,129, 3,187,124, 14,243,244, + 242,239,235,101,128, 1,155,229,100,130, 5,220,124, 32,124, 52, + 228,225,231,229,243,104,129,251, 60,124, 43,232,229,226,242,229, + 119,128,251, 60,232,229,226,242,229,119,128, 5,220,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,222,232,225,232,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,252,202,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,223,234,229, + 229,237,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 252,201,235,232,225,232,233,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,252,203,236,225,237,232,229,232,233,243,239,236, + 225,244,229,228,225,242,225,226,233, 99,128,253,242,237,101, 2, + 124,180,124,193,228,233,225,236,225,242,225,226,233, 99,128,254, + 224,229,109, 2,124,200,124,219,232,225,232,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,253,136,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,252,204,242,231,229,227,233, + 242,227,236,101,128, 37,239, 98, 3,124,255,125, 4,125, 10,225, + 114,128, 1,154,229,236,116,128, 2,108,239,240,239,237,239,230, + 111,128, 49, 12, 99, 4,125, 30,125, 37,125, 46,125, 73,225,242, + 239,110,128, 1, 62,229,228,233,236,236, 97,128, 1, 60,233,242, + 99, 2,125, 54,125, 59,236,101,128, 36,219,245,237,230,236,229, + 248,226,229,236,239,119,128, 30, 61,239,237,237,225,225,227,227, + 229,238,116,128, 1, 60,228,239,116,130, 1, 64,125, 96,125,105, + 225,227,227,229,238,116,128, 1, 64,226,229,236,239,119,129, 30, + 55,125,115,237,225,227,242,239,110,128, 30, 57,101, 3,125,132, + 125,170,126, 15,230,116, 2,125,139,125,155,225,238,231,236,229, + 225,226,239,246,229,227,237, 98,128, 3, 26,244,225,227,235,226, + 229,236,239,247,227,237, 98,128, 3, 24,243,115,132, 0, 60,125, + 183,125,205,125,217,126, 7,229,241,245,225,108,129, 34,100,125, + 193,239,242,231,242,229,225,244,229,114,128, 34,218,237,239,238, + 239,243,240,225,227,101,128,255, 28,111, 2,125,223,125,252,114, + 2,125,229,125,242,229,241,245,233,246,225,236,229,238,116,128, + 34,114,231,242,229,225,244,229,114,128, 34,118,246,229,242,229, + 241,245,225,108,128, 34,102,243,237,225,236,108,128,254,100,250, + 104,128, 2,110,230,226,236,239,227,107,128, 37,140,232,239,239, + 235,242,229,244,242,239,230,236,229,120,128, 2,109,105, 2,126, + 51,126, 56,242, 97,128, 32,164,247,238,225,242,237,229,238,233, + 225,110,128, 5,108,106,129, 1,201,126, 75,229,227,249,242,233, + 236,236,233, 99,128, 4, 89,108,132,246,192,126, 99,126,123,126, + 134,126,143, 97, 2,126,105,126,112,228,229,246, 97,128, 9, 51, + 231,245,234,225,242,225,244,105,128, 10,179,233,238,229,226,229, + 236,239,119,128, 30, 59,236,225,228,229,246, 97,128, 9, 52,246, + 239,227,225,236,233, 99, 3,126,157,126,167,126,174,226,229,238, + 231,225,236,105,128, 9,225,228,229,246, 97,128, 9, 97,246,239, + 247,229,236,243,233,231,110, 2,126,188,126,198,226,229,238,231, + 225,236,105,128, 9,227,228,229,246, 97,128, 9, 99,109, 3,126, + 213,126,226,126,237,233,228,228,236,229,244,233,236,228,101,128, + 2,107,239,238,239,243,240,225,227,101,128,255, 76,243,241,245, + 225,242,101,128, 51,208,111, 6,127, 4,127, 16,127, 58,127, 69, + 127, 75,127,117,227,232,245,236,225,244,232,225,105,128, 14, 44, + 231,233,227,225,108, 3,127, 28,127, 34,127, 53,225,238,100,128, + 34, 39,238,239,116,129, 0,172,127, 42,242,229,246,229,242,243, + 229,100,128, 35, 16,239,114,128, 34, 40,236,233,238,231,244,232, + 225,105,128, 14, 37,238,231,115,128, 1,127,247,236,233,238,101, + 2,127, 85,127,108, 99, 2,127, 91,127,103,229,238,244,229,242, + 236,233,238,101,128,254, 78,237, 98,128, 3, 50,228,225,243,232, + 229,100,128,254, 77,250,229,238,231,101,128, 37,202,240,225,242, + 229,110,128, 36,167,115, 3,127,141,127,148,127,156,236,225,243, + 104,128, 1, 66,241,245,225,242,101,128, 33, 19,245,240,229,242, + 233,239,114,128,246,238,244,243,232,225,228,101,128, 37,145,245, + 244,232,225,105,128, 14, 38,246,239,227,225,236,233, 99, 3,127, + 197,127,207,127,214,226,229,238,231,225,236,105,128, 9,140,228, + 229,246, 97,128, 9, 12,246,239,247,229,236,243,233,231,110, 2, + 127,228,127,238,226,229,238,231,225,236,105,128, 9,226,228,229, + 246, 97,128, 9, 98,248,243,241,245,225,242,101,128, 51,211,109, + 144, 0,109,128, 35,130,144,130,169,130,196,130,221,132, 18,132, + 40,133, 95,133,125,133,174,134, 25,134, 47,134, 72,134, 81,135, + 108,135,136, 97, 12,128, 61,128, 71,128,135,128,142,128,167,128, + 215,130, 51,130, 76,130, 81,130, 95,130,107,130,112,226,229,238, + 231,225,236,105,128, 9,174, 99, 2,128, 77,128,129,242,239,110, + 132, 0,175,128, 91,128,102,128,108,128,117,226,229,236,239,247, + 227,237, 98,128, 3, 49,227,237, 98,128, 3, 4,236,239,247,237, + 239,100,128, 2,205,237,239,238,239,243,240,225,227,101,128,255, + 227,245,244,101,128, 30, 63,228,229,246, 97,128, 9, 46,231,117, + 2,128,149,128,158,234,225,242,225,244,105,128, 10,174,242,237, + 245,235,232,105,128, 10, 46,104, 2,128,173,128,205,225,240,225, + 235,104, 2,128,183,128,192,232,229,226,242,229,119,128, 5,164, + 236,229,230,244,232,229,226,242,229,119,128, 5,164,233,242,225, + 231,225,238, 97,128, 48,126,105, 5,128,227,129, 40,129,103,129, + 133,130, 39,227,232,225,244,244,225,247, 97, 3,128,242,129, 17, + 129, 24,236,239,119, 2,128,250,129, 5,236,229,230,244,244,232, + 225,105,128,248,149,242,233,231,232,244,244,232,225,105,128,248, + 148,244,232,225,105,128, 14, 75,245,240,240,229,242,236,229,230, + 244,244,232,225,105,128,248,147,229,107, 3,129, 49,129, 80,129, + 87,236,239,119, 2,129, 57,129, 68,236,229,230,244,244,232,225, + 105,128,248,140,242,233,231,232,244,244,232,225,105,128,248,139, + 244,232,225,105,128, 14, 72,245,240,240,229,242,236,229,230,244, + 244,232,225,105,128,248,138,232,225,238,225,235,225,116, 2,129, + 115,129,126,236,229,230,244,244,232,225,105,128,248,132,244,232, + 225,105,128, 14, 49,116, 3,129,141,129,169,129,232,225,233,235, + 232,117, 2,129,151,129,162,236,229,230,244,244,232,225,105,128, + 248,137,244,232,225,105,128, 14, 71,232,111, 3,129,178,129,209, + 129,216,236,239,119, 2,129,186,129,197,236,229,230,244,244,232, + 225,105,128,248,143,242,233,231,232,244,244,232,225,105,128,248, + 142,244,232,225,105,128, 14, 73,245,240,240,229,242,236,229,230, + 244,244,232,225,105,128,248,141,242,105, 3,129,241,130, 16,130, + 23,236,239,119, 2,129,249,130, 4,236,229,230,244,244,232,225, + 105,128,248,146,242,233,231,232,244,244,232,225,105,128,248,145, + 244,232,225,105,128, 14, 74,245,240,240,229,242,236,229,230,244, + 244,232,225,105,128,248,144,249,225,237,239,235,244,232,225,105, + 128, 14, 70,235,225,244,225,235,225,238, 97,129, 48,222,130, 64, + 232,225,236,230,247,233,228,244,104,128,255,143,236,101,128, 38, + 66,238,243,249,239,238,243,241,245,225,242,101,128, 51, 71,241, + 225,230,232,229,226,242,229,119,128, 5,190,242,115,128, 38, 66, + 115, 2,130,118,130,136,239,242,225,227,233,242,227,236,229,232, + 229,226,242,229,119,128, 5,175,241,245,225,242,101,128, 51,131, + 98, 2,130,150,130,160,239,240,239,237,239,230,111,128, 49, 7, + 243,241,245,225,242,101,128, 51,212, 99, 2,130,175,130,183,233, + 242,227,236,101,128, 36,220,245,226,229,228,243,241,245,225,242, + 101,128, 51,165,228,239,116, 2,130,204,130,213,225,227,227,229, + 238,116,128, 30, 65,226,229,236,239,119,128, 30, 67,101, 7,130, + 237,131,108,131,119,131,134,131,159,131,196,131,208,101, 2,130, + 243,131, 95,109, 4,130,253,131, 6,131, 20,131, 36,225,242,225, + 226,233, 99,128, 6, 69,230,233,238,225,236,225,242,225,226,233, + 99,128,254,226,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,227,237,101, 2,131, 43,131, 56,228,233,225,236,225, + 242,225,226,233, 99,128,254,228,229,237,105, 2,131, 64,131, 79, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,209,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 72,244, + 239,242,245,243,241,245,225,242,101,128, 51, 77,232,233,242,225, + 231,225,238, 97,128, 48,129,233,250,233,229,242,225,243,241,245, + 225,242,101,128, 51,126,235,225,244,225,235,225,238, 97,129, 48, + 225,131,147,232,225,236,230,247,233,228,244,104,128,255,146,109, + 130, 5,222,131,167,131,187,228,225,231,229,243,104,129,251, 62, + 131,178,232,229,226,242,229,119,128,251, 62,232,229,226,242,229, + 119,128, 5,222,238,225,242,237,229,238,233,225,110,128, 5,116, + 242,235,232, 97, 3,131,219,131,228,132, 5,232,229,226,242,229, + 119,128, 5,165,235,229,230,245,236, 97, 2,131,239,131,248,232, + 229,226,242,229,119,128, 5,166,236,229,230,244,232,229,226,242, + 229,119,128, 5,166,236,229,230,244,232,229,226,242,229,119,128, + 5,165,104, 2,132, 24,132, 30,239,239,107,128, 2,113,250,243, + 241,245,225,242,101,128, 51,146,105, 6,132, 54,132, 91,132,228, + 132,239,133, 8,133, 65,228,100, 2,132, 61,132, 86,236,229,228, + 239,244,235,225,244,225,235,225,238,225,232,225,236,230,247,233, + 228,244,104,128,255,101,239,116,128, 0,183,229,245,109, 5,132, + 105,132,140,132,155,132,164,132,215, 97, 2,132,111,132,126,227, + 233,242,227,236,229,235,239,242,229,225,110,128, 50,114,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 18,227,233,242,227, + 236,229,235,239,242,229,225,110,128, 50,100,235,239,242,229,225, + 110,128, 49, 65,112, 2,132,170,132,202, 97, 2,132,176,132,190, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,112,242,229, + 238,235,239,242,229,225,110,128, 50, 4,233,229,245,240,235,239, + 242,229,225,110,128, 49,110,243,233,239,243,235,239,242,229,225, + 110,128, 49,111,232,233,242,225,231,225,238, 97,128, 48,127,235, + 225,244,225,235,225,238, 97,129, 48,223,132,252,232,225,236,230, + 247,233,228,244,104,128,255,144,238,117, 2,133, 15,133, 60,115, + 132, 34, 18,133, 27,133, 38,133, 47,133, 53,226,229,236,239,247, + 227,237, 98,128, 3, 32,227,233,242,227,236,101,128, 34,150,237, + 239,100,128, 2,215,240,236,245,115,128, 34, 19,244,101,128, 32, + 50,242,105, 2,133, 72,133, 86,226,225,225,242,245,243,241,245, + 225,242,101,128, 51, 74,243,241,245,225,242,101,128, 51, 73,108, + 2,133,101,133,116,239,238,231,236,229,231,244,245,242,238,229, + 100,128, 2,112,243,241,245,225,242,101,128, 51,150,109, 3,133, + 133,133,147,133,158,227,245,226,229,228,243,241,245,225,242,101, + 128, 51,163,239,238,239,243,240,225,227,101,128,255, 77,243,241, + 245,225,242,229,228,243,241,245,225,242,101,128, 51,159,111, 5, + 133,186,133,212,133,237,133,247,134, 0,104, 2,133,192,133,202, + 233,242,225,231,225,238, 97,128, 48,130,237,243,241,245,225,242, + 101,128, 51,193,235,225,244,225,235,225,238, 97,129, 48,226,133, + 225,232,225,236,230,247,233,228,244,104,128,255,147,236,243,241, + 245,225,242,101,128, 51,214,237,225,244,232,225,105,128, 14, 33, + 246,229,242,243,243,241,245,225,242,101,129, 51,167,134, 15,228, + 243,241,245,225,242,101,128, 51,168,240, 97, 2,134, 32,134, 38, + 242,229,110,128, 36,168,243,241,245,225,242,101,128, 51,171,115, + 2,134, 53,134, 62,243,241,245,225,242,101,128, 51,179,245,240, + 229,242,233,239,114,128,246,239,244,245,242,238,229,100,128, 2, + 111,117,141, 0,181,134,111,134,115,134,125,134,149,134,159,134, + 181,134,192,134,217,134,240,134,250,135, 24,135, 88,135, 98, 49, + 128, 0,181,225,243,241,245,225,242,101,128, 51,130,227,104, 2, + 134,132,134,142,231,242,229,225,244,229,114,128, 34,107,236,229, + 243,115,128, 34,106,230,243,241,245,225,242,101,128, 51,140,103, + 2,134,165,134,172,242,229,229,107,128, 3,188,243,241,245,225, + 242,101,128, 51,141,232,233,242,225,231,225,238, 97,128, 48,128, + 235,225,244,225,235,225,238, 97,129, 48,224,134,205,232,225,236, + 230,247,233,228,244,104,128,255,145,108, 2,134,223,134,232,243, + 241,245,225,242,101,128, 51,149,244,233,240,236,121,128, 0,215, + 237,243,241,245,225,242,101,128, 51,155,238,225,104, 2,135, 2, + 135, 11,232,229,226,242,229,119,128, 5,163,236,229,230,244,232, + 229,226,242,229,119,128, 5,163,115, 2,135, 30,135, 79,233, 99, + 3,135, 39,135, 56,135, 67,225,236,238,239,244,101,129, 38,106, + 135, 50,228,226,108,128, 38,107,230,236,225,244,243,233,231,110, + 128, 38,109,243,232,225,242,240,243,233,231,110,128, 38,111,243, + 241,245,225,242,101,128, 51,178,246,243,241,245,225,242,101,128, + 51,182,247,243,241,245,225,242,101,128, 51,188,118, 2,135,114, + 135,127,237,229,231,225,243,241,245,225,242,101,128, 51,185,243, + 241,245,225,242,101,128, 51,183,119, 2,135,142,135,155,237,229, + 231,225,243,241,245,225,242,101,128, 51,191,243,241,245,225,242, + 101,128, 51,189,110,150, 0,110,135,212,136, 90,136,114,136,180, + 136,205,137, 7,137, 17,137, 84,137,127,139,161,139,179,139,204, + 139,235,140, 5,140, 70,142, 52,142, 60,142, 85,142, 93,143, 61, + 143, 71,143, 81, 97, 8,135,230,135,250,136, 1,136, 8,136, 33, + 136, 44,136, 69,136, 81, 98, 2,135,236,135,245,229,238,231,225, + 236,105,128, 9,168,236, 97,128, 34, 7,227,245,244,101,128, 1, + 68,228,229,246, 97,128, 9, 40,231,117, 2,136, 15,136, 24,234, + 225,242,225,244,105,128, 10,168,242,237,245,235,232,105,128, 10, + 40,232,233,242,225,231,225,238, 97,128, 48,106,235,225,244,225, + 235,225,238, 97,129, 48,202,136, 57,232,225,236,230,247,233,228, + 244,104,128,255,133,240,239,243,244,242,239,240,232,101,128, 1, + 73,243,241,245,225,242,101,128, 51,129, 98, 2,136, 96,136,106, + 239,240,239,237,239,230,111,128, 49, 11,243,240,225,227,101,128, + 0,160, 99, 4,136,124,136,131,136,140,136,167,225,242,239,110, + 128, 1, 72,229,228,233,236,236, 97,128, 1, 70,233,242, 99, 2, + 136,148,136,153,236,101,128, 36,221,245,237,230,236,229,248,226, + 229,236,239,119,128, 30, 75,239,237,237,225,225,227,227,229,238, + 116,128, 1, 70,228,239,116, 2,136,188,136,197,225,227,227,229, + 238,116,128, 30, 69,226,229,236,239,119,128, 30, 71,101, 3,136, + 213,136,224,136,249,232,233,242,225,231,225,238, 97,128, 48,109, + 235,225,244,225,235,225,238, 97,129, 48,205,136,237,232,225,236, + 230,247,233,228,244,104,128,255,136,247,243,232,229,241,229,236, + 243,233,231,110,128, 32,170,230,243,241,245,225,242,101,128, 51, + 139,103, 2,137, 23,137, 73, 97, 3,137, 31,137, 41,137, 48,226, + 229,238,231,225,236,105,128, 9,153,228,229,246, 97,128, 9, 25, + 231,117, 2,137, 55,137, 64,234,225,242,225,244,105,128, 10,153, + 242,237,245,235,232,105,128, 10, 25,239,238,231,245,244,232,225, + 105,128, 14, 7,104, 2,137, 90,137,100,233,242,225,231,225,238, + 97,128, 48,147,239,239,107, 2,137,108,137,115,236,229,230,116, + 128, 2,114,242,229,244,242,239,230,236,229,120,128, 2,115,105, + 4,137,137,138, 50,138, 61,138,119,229,245,110, 7,137,155,137, + 190,137,222,137,236,137,245,138, 22,138, 35, 97, 2,137,161,137, + 176,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,111, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 15,227,105, + 2,137,197,137,209,229,245,227,235,239,242,229,225,110,128, 49, + 53,242,227,236,229,235,239,242,229,225,110,128, 50, 97,232,233, + 229,245,232,235,239,242,229,225,110,128, 49, 54,235,239,242,229, + 225,110,128, 49, 52,240, 97, 2,137,252,138, 10,238,243,233,239, + 243,235,239,242,229,225,110,128, 49,104,242,229,238,235,239,242, + 229,225,110,128, 50, 1,243,233,239,243,235,239,242,229,225,110, + 128, 49,103,244,233,235,229,245,244,235,239,242,229,225,110,128, + 49,102,232,233,242,225,231,225,238, 97,128, 48,107,107, 2,138, + 67,138, 91,225,244,225,235,225,238, 97,129, 48,203,138, 79,232, + 225,236,230,247,233,228,244,104,128,255,134,232,225,232,233,116, + 2,138,101,138,112,236,229,230,244,244,232,225,105,128,248,153, + 244,232,225,105,128, 14, 77,238,101,141, 0, 57,138,150,138,159, + 138,169,138,199,138,206,138,231,139, 2,139, 36,139, 48,139, 59, + 139, 92,139,100,139,111,225,242,225,226,233, 99,128, 6,105,226, + 229,238,231,225,236,105,128, 9,239,227,233,242,227,236,101,129, + 36,104,138,180,233,238,246,229,242,243,229,243,225,238,243,243, + 229,242,233,102,128, 39,146,228,229,246, 97,128, 9,111,231,117, + 2,138,213,138,222,234,225,242,225,244,105,128, 10,239,242,237, + 245,235,232,105,128, 10,111,232, 97, 2,138,238,138,249,227,235, + 225,242,225,226,233, 99,128, 6,105,238,231,250,232,239,117,128, + 48, 41,105, 2,139, 8,139, 26,228,229,239,231,242,225,240,232, + 233,227,240,225,242,229,110,128, 50, 40,238,230,229,242,233,239, + 114,128, 32,137,237,239,238,239,243,240,225,227,101,128,255, 25, + 239,236,228,243,244,249,236,101,128,247, 57,112, 2,139, 65,139, + 72,225,242,229,110,128, 36,124,229,114, 2,139, 79,139, 85,233, + 239,100,128, 36,144,243,233,225,110,128, 6,249,242,239,237,225, + 110,128, 33,120,243,245,240,229,242,233,239,114,128, 32,121,116, + 2,139,117,139,155,229,229,110, 2,139,125,139,134,227,233,242, + 227,236,101,128, 36,114,112, 2,139,140,139,147,225,242,229,110, + 128, 36,134,229,242,233,239,100,128, 36,154,232,225,105,128, 14, + 89,106,129, 1,204,139,167,229,227,249,242,233,236,236,233, 99, + 128, 4, 90,235,225,244,225,235,225,238, 97,129, 48,243,139,192, + 232,225,236,230,247,233,228,244,104,128,255,157,108, 2,139,210, + 139,224,229,231,242,233,231,232,244,236,239,238,103,128, 1,158, + 233,238,229,226,229,236,239,119,128, 30, 73,109, 2,139,241,139, + 252,239,238,239,243,240,225,227,101,128,255, 78,243,241,245,225, + 242,101,128, 51,154,110, 2,140, 11,140, 61, 97, 3,140, 19,140, + 29,140, 36,226,229,238,231,225,236,105,128, 9,163,228,229,246, + 97,128, 9, 35,231,117, 2,140, 43,140, 52,234,225,242,225,244, + 105,128, 10,163,242,237,245,235,232,105,128, 10, 35,238,225,228, + 229,246, 97,128, 9, 41,111, 6,140, 84,140, 95,140,120,140,161, + 141,113,142, 40,232,233,242,225,231,225,238, 97,128, 48,110,235, + 225,244,225,235,225,238, 97,129, 48,206,140,108,232,225,236,230, + 247,233,228,244,104,128,255,137,110, 3,140,128,140,144,140,153, + 226,242,229,225,235,233,238,231,243,240,225,227,101,128, 0,160, + 229,238,244,232,225,105,128, 14, 19,245,244,232,225,105,128, 14, + 25,239,110, 7,140,178,140,187,140,201,140,235,140,251,141, 36, + 141, 95,225,242,225,226,233, 99,128, 6, 70,230,233,238,225,236, + 225,242,225,226,233, 99,128,254,230,231,232,245,238,238, 97, 2, + 140,212,140,221,225,242,225,226,233, 99,128, 6,186,230,233,238, + 225,236,225,242,225,226,233, 99,128,251,159,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,254,231,234,229,229,237,105, + 2,141, 5,141, 20,238,233,244,233,225,236,225,242,225,226,233, + 99,128,252,210,243,239,236,225,244,229,228,225,242,225,226,233, + 99,128,252, 75,237,101, 2,141, 43,141, 56,228,233,225,236,225, + 242,225,226,233, 99,128,254,232,229,237,105, 2,141, 64,141, 79, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,213,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 78,238, + 239,239,238,230,233,238,225,236,225,242,225,226,233, 99,128,252, + 141,116, 7,141,129,141,140,141,169,141,204,141,216,141,236,142, + 6,227,239,238,244,225,233,238,115,128, 34, 12,101, 2,141,146, + 141,162,236,229,237,229,238,116,129, 34, 9,141,157,239,102,128, + 34, 9,241,245,225,108,128, 34, 96,231,242,229,225,244,229,114, + 129, 34,111,141,181,238,239,114, 2,141,189,141,197,229,241,245, + 225,108,128, 34,113,236,229,243,115,128, 34,121,233,228,229,238, + 244,233,227,225,108,128, 34, 98,236,229,243,115,129, 34,110,141, + 225,238,239,242,229,241,245,225,108,128, 34,112,112, 2,141,242, + 141,252,225,242,225,236,236,229,108,128, 34, 38,242,229,227,229, + 228,229,115,128, 34,128,243,117, 3,142, 15,142, 22,142, 31,226, + 243,229,116,128, 34,132,227,227,229,229,228,115,128, 34,129,240, + 229,242,243,229,116,128, 34,133,247,225,242,237,229,238,233,225, + 110,128, 5,118,240,225,242,229,110,128, 36,169,115, 2,142, 66, + 142, 75,243,241,245,225,242,101,128, 51,177,245,240,229,242,233, + 239,114,128, 32,127,244,233,236,228,101,128, 0,241,117,132, 3, + 189,142,105,142,116,142,197,143, 24,232,233,242,225,231,225,238, + 97,128, 48,108,107, 2,142,122,142,146,225,244,225,235,225,238, + 97,129, 48,204,142,134,232,225,236,230,247,233,228,244,104,128, + 255,135,244, 97, 3,142,155,142,165,142,172,226,229,238,231,225, + 236,105,128, 9,188,228,229,246, 97,128, 9, 60,231,117, 2,142, + 179,142,188,234,225,242,225,244,105,128, 10,188,242,237,245,235, + 232,105,128, 10, 60,109, 2,142,203,142,237,226,229,242,243,233, + 231,110,130, 0, 35,142,217,142,229,237,239,238,239,243,240,225, + 227,101,128,255, 3,243,237,225,236,108,128,254, 95,229,114, 2, + 142,244,143, 20,225,236,243,233,231,110, 2,142,255,143, 7,231, + 242,229,229,107,128, 3,116,236,239,247,229,242,231,242,229,229, + 107,128, 3,117,111,128, 33, 22,110,130, 5,224,143, 32,143, 52, + 228,225,231,229,243,104,129,251, 64,143, 43,232,229,226,242,229, + 119,128,251, 64,232,229,226,242,229,119,128, 5,224,246,243,241, + 245,225,242,101,128, 51,181,247,243,241,245,225,242,101,128, 51, + 187,249, 97, 3,143, 90,143,100,143,107,226,229,238,231,225,236, + 105,128, 9,158,228,229,246, 97,128, 9, 30,231,117, 2,143,114, + 143,123,234,225,242,225,244,105,128, 10,158,242,237,245,235,232, + 105,128, 10, 30,111,147, 0,111,143,174,143,196,144, 18,144,188, + 145, 4,145, 19,145, 59,145,182,145,203,145,241,145,252,146,174, + 148, 8,148, 72,148,105,148,151,149, 24,149, 71,149, 83, 97, 2, + 143,180,143,187,227,245,244,101,128, 0,243,238,231,244,232,225, + 105,128, 14, 45, 98, 4,143,206,143,248,144, 1,144, 11,225,242, + 242,229,100,130, 2,117,143,218,143,229,227,249,242,233,236,236, + 233, 99,128, 4,233,228,233,229,242,229,243,233,243,227,249,242, + 233,236,236,233, 99,128, 4,235,229,238,231,225,236,105,128, 9, + 147,239,240,239,237,239,230,111,128, 49, 27,242,229,246,101,128, + 1, 79, 99, 3,144, 26,144, 99,144,178, 97, 2,144, 32,144, 93, + 238,228,242, 97, 3,144, 43,144, 50,144, 61,228,229,246, 97,128, + 9, 17,231,245,234,225,242,225,244,105,128, 10,145,246,239,247, + 229,236,243,233,231,110, 2,144, 75,144, 82,228,229,246, 97,128, + 9, 73,231,245,234,225,242,225,244,105,128, 10,201,242,239,110, + 128, 1,210,233,242, 99, 2,144,107,144,112,236,101,128, 36,222, + 245,237,230,236,229,120,133, 0,244,144,131,144,139,144,150,144, + 158,144,170,225,227,245,244,101,128, 30,209,228,239,244,226,229, + 236,239,119,128, 30,217,231,242,225,246,101,128, 30,211,232,239, + 239,235,225,226,239,246,101,128, 30,213,244,233,236,228,101,128, + 30,215,249,242,233,236,236,233, 99,128, 4, 62,100, 4,144,198, + 144,221,144,227,144,250,226,108, 2,144,205,144,213,225,227,245, + 244,101,128, 1, 81,231,242,225,246,101,128, 2, 13,229,246, 97, + 128, 9, 19,233,229,242,229,243,233,115,129, 0,246,144,239,227, + 249,242,233,236,236,233, 99,128, 4,231,239,244,226,229,236,239, + 119,128, 30,205,101,129, 1, 83,145, 10,235,239,242,229,225,110, + 128, 49, 90,103, 3,145, 27,145, 42,145, 49,239,238,229,107,129, + 2,219,145, 36,227,237, 98,128, 3, 40,242,225,246,101,128, 0, + 242,245,234,225,242,225,244,105,128, 10,147,104, 4,145, 69,145, + 80,145, 90,145,168,225,242,237,229,238,233,225,110,128, 5,133, + 233,242,225,231,225,238, 97,128, 48, 74,111, 2,145, 96,145,106, + 239,235,225,226,239,246,101,128, 30,207,242,110,133, 1,161,145, + 121,145,129,145,140,145,148,145,160,225,227,245,244,101,128, 30, + 219,228,239,244,226,229,236,239,119,128, 30,227,231,242,225,246, + 101,128, 30,221,232,239,239,235,225,226,239,246,101,128, 30,223, + 244,233,236,228,101,128, 30,225,245,238,231,225,242,245,237,236, + 225,245,116,128, 1, 81,105,129, 1,163,145,188,238,246,229,242, + 244,229,228,226,242,229,246,101,128, 2, 15,107, 2,145,209,145, + 233,225,244,225,235,225,238, 97,129, 48,170,145,221,232,225,236, + 230,247,233,228,244,104,128,255,117,239,242,229,225,110,128, 49, + 87,236,229,232,229,226,242,229,119,128, 5,171,109, 6,146, 10, + 146, 38,146, 45,146,134,146,145,146,163,225,227,242,239,110,130, + 1, 77,146, 22,146, 30,225,227,245,244,101,128, 30, 83,231,242, + 225,246,101,128, 30, 81,228,229,246, 97,128, 9, 80,229,231, 97, + 133, 3,201,146, 61,146, 65,146, 76,146, 90,146,106, 49,128, 3, + 214,227,249,242,233,236,236,233, 99,128, 4, 97,236,225,244,233, + 238,227,236,239,243,229,100,128, 2,119,242,239,245,238,228,227, + 249,242,233,236,236,233, 99,128, 4,123,116, 2,146,112,146,127, + 233,244,236,239,227,249,242,233,236,236,233, 99,128, 4,125,239, + 238,239,115,128, 3,206,231,245,234,225,242,225,244,105,128, 10, + 208,233,227,242,239,110,129, 3,191,146,155,244,239,238,239,115, + 128, 3,204,239,238,239,243,240,225,227,101,128,255, 79,238,101, + 145, 0, 49,146,213,146,222,146,232,147, 6,147, 31,147, 40,147, + 49,147, 74,147,108,147,142,147,154,147,173,147,184,147,217,147, + 227,147,235,147,246,225,242,225,226,233, 99,128, 6, 97,226,229, + 238,231,225,236,105,128, 9,231,227,233,242,227,236,101,129, 36, + 96,146,243,233,238,246,229,242,243,229,243,225,238,243,243,229, + 242,233,102,128, 39,138,100, 2,147, 12,147, 18,229,246, 97,128, + 9,103,239,244,229,238,236,229,225,228,229,114,128, 32, 36,229, + 233,231,232,244,104,128, 33, 91,230,233,244,244,229,100,128,246, + 220,231,117, 2,147, 56,147, 65,234,225,242,225,244,105,128, 10, + 231,242,237,245,235,232,105,128, 10,103,232, 97, 3,147, 83,147, + 94,147, 99,227,235,225,242,225,226,233, 99,128, 6, 97,236,102, + 128, 0,189,238,231,250,232,239,117,128, 48, 33,105, 2,147,114, + 147,132,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 32,238,230,229,242,233,239,114,128, 32,129,237,239, + 238,239,243,240,225,227,101,128,255, 17,238,245,237,229,242,225, + 244,239,242,226,229,238,231,225,236,105,128, 9,244,239,236,228, + 243,244,249,236,101,128,247, 49,112, 2,147,190,147,197,225,242, + 229,110,128, 36,116,229,114, 2,147,204,147,210,233,239,100,128, + 36,136,243,233,225,110,128, 6,241,241,245,225,242,244,229,114, + 128, 0,188,242,239,237,225,110,128, 33,112,243,245,240,229,242, + 233,239,114,128, 0,185,244,104, 2,147,253,148, 2,225,105,128, + 14, 81,233,242,100,128, 33, 83,111, 3,148, 16,148, 50,148, 66, + 103, 2,148, 22,148, 40,239,238,229,107,129, 1,235,148, 31,237, + 225,227,242,239,110,128, 1,237,245,242,237,245,235,232,105,128, + 10, 19,237,225,244,242,225,231,245,242,237,245,235,232,105,128, + 10, 75,240,229,110,128, 2, 84,112, 3,148, 80,148, 87,148, 98, + 225,242,229,110,128, 36,170,229,238,226,245,236,236,229,116,128, + 37,230,244,233,239,110,128, 35, 37,114, 2,148,111,148,140,100, + 2,148,117,148,128,230,229,237,233,238,233,238,101,128, 0,170, + 237,225,243,227,245,236,233,238,101,128, 0,186,244,232,239,231, + 239,238,225,108,128, 34, 31,115, 5,148,163,148,195,148,212,149, + 1,149, 14,232,239,242,116, 2,148,172,148,179,228,229,246, 97, + 128, 9, 18,246,239,247,229,236,243,233,231,238,228,229,246, 97, + 128, 9, 74,236,225,243,104,129, 0,248,148,204,225,227,245,244, + 101,128, 1,255,237,225,236,108, 2,148,221,148,232,232,233,242, + 225,231,225,238, 97,128, 48, 73,235,225,244,225,235,225,238, 97, + 129, 48,169,148,245,232,225,236,230,247,233,228,244,104,128,255, + 107,244,242,239,235,229,225,227,245,244,101,128, 1,255,245,240, + 229,242,233,239,114,128,246,240,116, 2,149, 30,149, 41,227,249, + 242,233,236,236,233, 99,128, 4,127,233,236,228,101,130, 0,245, + 149, 52,149, 60,225,227,245,244,101,128, 30, 77,228,233,229,242, + 229,243,233,115,128, 30, 79,245,226,239,240,239,237,239,230,111, + 128, 49, 33,118, 2,149, 89,149,170,229,114, 2,149, 96,149,162, + 236,233,238,101,131, 32, 62,149,109,149,132,149,155, 99, 2,149, + 115,149,127,229,238,244,229,242,236,233,238,101,128,254, 74,237, + 98,128, 3, 5,100, 2,149,138,149,146,225,243,232,229,100,128, + 254, 73,226,236,247,225,246,121,128,254, 76,247,225,246,121,128, + 254, 75,243,227,239,242,101,128, 0,175,239,247,229,236,243,233, + 231,110, 3,149,185,149,195,149,202,226,229,238,231,225,236,105, + 128, 9,203,228,229,246, 97,128, 9, 75,231,245,234,225,242,225, + 244,105,128, 10,203,112,145, 0,112,149,251,152,123,152,134,152, + 143,152,155,154, 80,154, 90,155, 82,156,101,156,191,156,217,157, + 92,157,100,158, 2,158, 60,158, 88,158, 98, 97, 14,150, 25,150, + 57,150, 67,150, 74,150, 81,150,129,150,140,150,154,150,165,150, + 212,150,226,151,238,152, 21,152,111, 97, 2,150, 31,150, 43,237, + 240,243,243,241,245,225,242,101,128, 51,128,243,229,238,244,239, + 243,241,245,225,242,101,128, 51, 43,226,229,238,231,225,236,105, + 128, 9,170,227,245,244,101,128, 30, 85,228,229,246, 97,128, 9, + 42,103, 2,150, 87,150,105,101, 2,150, 93,150,100,228,239,247, + 110,128, 33,223,245,112,128, 33,222,117, 2,150,111,150,120,234, + 225,242,225,244,105,128, 10,170,242,237,245,235,232,105,128, 10, + 42,232,233,242,225,231,225,238, 97,128, 48,113,233,249,225,238, + 238,239,233,244,232,225,105,128, 14, 47,235,225,244,225,235,225, + 238, 97,128, 48,209,108, 2,150,171,150,196,225,244,225,236,233, + 250,225,244,233,239,238,227,249,242,233,236,236,233,227,227,237, + 98,128, 4,132,239,227,232,235,225,227,249,242,233,236,236,233, + 99,128, 4,192,238,243,233,239,243,235,239,242,229,225,110,128, + 49,127,114, 3,150,234,150,255,151,227, 97, 2,150,240,150,248, + 231,242,225,240,104,128, 0,182,236,236,229,108,128, 34, 37,229, + 110, 2,151, 6,151,116,236,229,230,116,136, 0, 40,151, 29,151, + 44,151, 49,151, 54,151, 65,151, 77,151,100,151,105,225,236,244, + 239,238,229,225,242,225,226,233, 99,128,253, 62,226,116,128,248, + 237,229,120,128,248,236,233,238,230,229,242,233,239,114,128, 32, + 141,237,239,238,239,243,240,225,227,101,128,255, 8,115, 2,151, + 83,151, 90,237,225,236,108,128,254, 89,245,240,229,242,233,239, + 114,128, 32,125,244,112,128,248,235,246,229,242,244,233,227,225, + 108,128,254, 53,242,233,231,232,116,136, 0, 41,151,140,151,155, + 151,160,151,165,151,176,151,188,151,211,151,216,225,236,244,239, + 238,229,225,242,225,226,233, 99,128,253, 63,226,116,128,248,248, + 229,120,128,248,247,233,238,230,229,242,233,239,114,128, 32,142, + 237,239,238,239,243,240,225,227,101,128,255, 9,115, 2,151,194, + 151,201,237,225,236,108,128,254, 90,245,240,229,242,233,239,114, + 128, 32,126,244,112,128,248,246,246,229,242,244,233,227,225,108, + 128,254, 54,244,233,225,236,228,233,230,102,128, 34, 2,115, 3, + 151,246,152, 1,152, 13,229,241,232,229,226,242,229,119,128, 5, + 192,232,244,225,232,229,226,242,229,119,128, 5,153,241,245,225, + 242,101,128, 51,169,244,225,104,134, 5,183,152, 39,152, 53,152, + 58,152, 67,152, 82,152, 98, 49, 2,152, 45,152, 49, 49,128, 5, + 183,100,128, 5,183,178, 97,128, 5,183,232,229,226,242,229,119, + 128, 5,183,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,183,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,183,247,233,228,229,232,229,226,242,229,119,128, 5,183,250, + 229,242,232,229,226,242,229,119,128, 5,161,226,239,240,239,237, + 239,230,111,128, 49, 6,227,233,242,227,236,101,128, 36,223,228, + 239,244,225,227,227,229,238,116,128, 30, 87,101,137, 5,228,152, + 177,152,188,152,208,152,220,152,240,153, 86,153, 97,153,118,154, + 73,227,249,242,233,236,236,233, 99,128, 4, 63,228,225,231,229, + 243,104,129,251, 68,152,199,232,229,226,242,229,119,128,251, 68, + 229,250,233,243,241,245,225,242,101,128, 51, 59,230,233,238,225, + 236,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 67, + 104, 5,152,252,153, 19,153, 27,153, 41,153, 71,225,114, 2,153, + 3,153, 10,225,226,233, 99,128, 6,126,237,229,238,233,225,110, + 128, 5,122,229,226,242,229,119,128, 5,228,230,233,238,225,236, + 225,242,225,226,233, 99,128,251, 87,105, 2,153, 47,153, 62,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,251, 88,242,225, + 231,225,238, 97,128, 48,122,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,251, 89,235,225,244,225,235,225,238, 97,128, 48, + 218,237,233,228,228,236,229,232,239,239,235,227,249,242,233,236, + 236,233, 99,128, 4,167,114, 5,153,130,153,142,153,184,154, 49, + 154, 62,225,230,229,232,229,226,242,229,119,128,251, 78,227,229, + 238,116,131, 0, 37,153,155,153,164,153,176,225,242,225,226,233, + 99,128, 6,106,237,239,238,239,243,240,225,227,101,128,255, 5, + 243,237,225,236,108,128,254,106,105, 2,153,190,154, 31,239,100, + 134, 0, 46,153,207,153,218,153,229,153,241,153,252,154, 8,225, + 242,237,229,238,233,225,110,128, 5,137,227,229,238,244,229,242, + 229,100,128, 0,183,232,225,236,230,247,233,228,244,104,128,255, + 97,233,238,230,229,242,233,239,114,128,246,231,237,239,238,239, + 243,240,225,227,101,128,255, 14,115, 2,154, 14,154, 21,237,225, + 236,108,128,254, 82,245,240,229,242,233,239,114,128,246,232,243, + 240,239,237,229,238,233,231,242,229,229,235,227,237, 98,128, 3, + 66,240,229,238,228,233,227,245,236,225,114,128, 34,165,244,232, + 239,245,243,225,238,100,128, 32, 48,243,229,244, 97,128, 32,167, + 230,243,241,245,225,242,101,128, 51,138,104, 3,154, 98,154,148, + 155, 29, 97, 3,154,106,154,116,154,123,226,229,238,231,225,236, + 105,128, 9,171,228,229,246, 97,128, 9, 43,231,117, 2,154,130, + 154,139,234,225,242,225,244,105,128, 10,171,242,237,245,235,232, + 105,128, 10, 43,105,133, 3,198,154,162,154,166,154,252,155, 4, + 155, 15, 49,128, 3,213,229,245,240,104, 4,154,179,154,214,154, + 229,154,238, 97, 2,154,185,154,200,227,233,242,227,236,229,235, + 239,242,229,225,110,128, 50,122,240,225,242,229,238,235,239,242, + 229,225,110,128, 50, 26,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,108,235,239,242,229,225,110,128, 49, 77,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 12,236,225,244,233, + 110,128, 2,120,238,244,232,245,244,232,225,105,128, 14, 58,243, + 249,237,226,239,236,231,242,229,229,107,128, 3,213,111, 3,155, + 37,155, 42,155, 68,239,107,128, 1,165,240,104, 2,155, 49,155, + 58,225,238,244,232,225,105,128, 14, 30,245,238,231,244,232,225, + 105,128, 14, 28,243,225,237,240,232,225,239,244,232,225,105,128, + 14, 32,105,133, 3,192,155, 96,156, 52,156, 63,156, 74,156, 88, + 229,245,112, 6,155,112,155,147,155,179,155,207,155,221,156, 17, + 97, 2,155,118,155,133,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,115,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 19,227,105, 2,155,154,155,166,229,245,227,235,239,242, + 229,225,110,128, 49,118,242,227,236,229,235,239,242,229,225,110, + 128, 50,101,107, 2,155,185,155,199,233,249,229,239,235,235,239, + 242,229,225,110,128, 49,114,239,242,229,225,110,128, 49, 66,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 5,243,233,239, + 115, 2,155,230,156, 2,107, 2,155,236,155,250,233,249,229,239, + 235,235,239,242,229,225,110,128, 49,116,239,242,229,225,110,128, + 49, 68,244,233,235,229,245,244,235,239,242,229,225,110,128, 49, + 117,116, 2,156, 23,156, 38,232,233,229,245,244,232,235,239,242, + 229,225,110,128, 49,119,233,235,229,245,244,235,239,242,229,225, + 110,128, 49,115,232,233,242,225,231,225,238, 97,128, 48,116,235, + 225,244,225,235,225,238, 97,128, 48,212,243,249,237,226,239,236, + 231,242,229,229,107,128, 3,214,247,242,225,242,237,229,238,233, + 225,110,128, 5,131,236,245,115,132, 0, 43,156,115,156,126,156, + 135,156,168,226,229,236,239,247,227,237, 98,128, 3, 31,227,233, + 242,227,236,101,128, 34,149,109, 2,156,141,156,148,233,238,245, + 115,128, 0,177,111, 2,156,154,156,158,100,128, 2,214,238,239, + 243,240,225,227,101,128,255, 11,115, 2,156,174,156,181,237,225, + 236,108,128,254, 98,245,240,229,242,233,239,114,128, 32,122,109, + 2,156,197,156,208,239,238,239,243,240,225,227,101,128,255, 80, + 243,241,245,225,242,101,128, 51,216,111, 5,156,229,156,240,157, + 51,157, 62,157, 72,232,233,242,225,231,225,238, 97,128, 48,125, + 233,238,244,233,238,231,233,238,228,229,120, 4,157, 4,157, 16, + 157, 28,157, 41,228,239,247,238,247,232,233,244,101,128, 38, 31, + 236,229,230,244,247,232,233,244,101,128, 38, 28,242,233,231,232, + 244,247,232,233,244,101,128, 38, 30,245,240,247,232,233,244,101, + 128, 38, 29,235,225,244,225,235,225,238, 97,128, 48,221,240,236, + 225,244,232,225,105,128, 14, 27,243,244,225,236,237,225,242,107, + 129, 48, 18,157, 85,230,225,227,101,128, 48, 32,240,225,242,229, + 110,128, 36,171,114, 3,157,108,157,134,157,159,101, 2,157,114, + 157,122,227,229,228,229,115,128, 34,122,243,227,242,233,240,244, + 233,239,110,128, 33, 30,233,237,101, 2,157,142,157,148,237,239, + 100,128, 2,185,242,229,246,229,242,243,229,100,128, 32, 53,111, + 4,157,169,157,176,157,186,157,199,228,245,227,116,128, 34, 15, + 234,229,227,244,233,246,101,128, 35, 5,236,239,238,231,229,228, + 235,225,238, 97,128, 48,252,112, 2,157,205,157,242,101, 2,157, + 211,157,218,236,236,239,114,128, 35, 24,242,243,117, 2,157,226, + 157,233,226,243,229,116,128, 34,130,240,229,242,243,229,116,128, + 34,131,239,242,244,233,239,110,129, 34, 55,157,253,225,108,128, + 34, 29,115, 2,158, 8,158, 51,105,130, 3,200,158, 16,158, 27, + 227,249,242,233,236,236,233, 99,128, 4,113,236,233,240,238,229, + 245,237,225,244,225,227,249,242,233,236,236,233,227,227,237, 98, + 128, 4,134,243,241,245,225,242,101,128, 51,176,117, 2,158, 66, + 158, 77,232,233,242,225,231,225,238, 97,128, 48,119,235,225,244, + 225,235,225,238, 97,128, 48,215,246,243,241,245,225,242,101,128, + 51,180,247,243,241,245,225,242,101,128, 51,186,113,136, 0,113, + 158,128,159,177,159,188,159,197,159,204,159,216,159,254,160, 6, + 97, 4,158,138,158,161,158,225,159,160,100, 2,158,144,158,150, + 229,246, 97,128, 9, 88,237,225,232,229,226,242,229,119,128, 5, + 168,102, 4,158,171,158,180,158,194,158,210,225,242,225,226,233, + 99,128, 6, 66,230,233,238,225,236,225,242,225,226,233, 99,128, + 254,214,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,215,237,229,228,233,225,236,225,242,225,226,233, 99,128,254, + 216,237,225,244,115,136, 5,184,158,248,159, 12,159, 26,159, 31, + 159, 36,159, 45,159, 60,159,147, 49, 3,159, 0,159, 4,159, 8, + 48,128, 5,184, 97,128, 5,184, 99,128, 5,184, 50, 2,159, 18, + 159, 22, 55,128, 5,184, 57,128, 5,184,179, 51,128, 5,184,228, + 101,128, 5,184,232,229,226,242,229,119,128, 5,184,238,225,242, + 242,239,247,232,229,226,242,229,119,128, 5,184,113, 2,159, 66, + 159,132,225,244,225,110, 4,159, 79,159, 88,159,103,159,119,232, + 229,226,242,229,119,128, 5,184,238,225,242,242,239,247,232,229, + 226,242,229,119,128, 5,184,241,245,225,242,244,229,242,232,229, + 226,242,229,119,128, 5,184,247,233,228,229,232,229,226,242,229, + 119,128, 5,184,245,225,242,244,229,242,232,229,226,242,229,119, + 128, 5,184,247,233,228,229,232,229,226,242,229,119,128, 5,184, + 242,238,229,249,240,225,242,225,232,229,226,242,229,119,128, 5, + 159,226,239,240,239,237,239,230,111,128, 49, 17,227,233,242,227, + 236,101,128, 36,224,232,239,239,107,128, 2,160,237,239,238,239, + 243,240,225,227,101,128,255, 81,239,102,130, 5,231,159,225,159, + 245,228,225,231,229,243,104,129,251, 71,159,236,232,229,226,242, + 229,119,128,251, 71,232,229,226,242,229,119,128, 5,231,240,225, + 242,229,110,128, 36,172,117, 4,160, 16,160, 28,160,117,160,204, + 225,242,244,229,242,238,239,244,101,128, 38,105,226,245,244,115, + 135, 5,187,160, 49,160, 54,160, 59,160, 64,160, 73,160, 88,160, + 104,177, 56,128, 5,187,178, 53,128, 5,187,179, 49,128, 5,187, + 232,229,226,242,229,119,128, 5,187,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,187,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,187,247,233,228,229,232,229,226,242, + 229,119,128, 5,187,229,243,244,233,239,110,133, 0, 63,160,136, + 160,159,160,176,160,184,160,196,225,114, 2,160,143,160,150,225, + 226,233, 99,128, 6, 31,237,229,238,233,225,110,128, 5, 94,228, + 239,247,110,129, 0,191,160,168,243,237,225,236,108,128,247,191, + 231,242,229,229,107,128, 3,126,237,239,238,239,243,240,225,227, + 101,128,255, 31,243,237,225,236,108,128,247, 63,239,244,101, 4, + 160,216,161, 31,161, 51,161, 80,228,226,108,133, 0, 34,160,232, + 160,239,160,246,161, 2,161, 23,226,225,243,101,128, 32, 30,236, + 229,230,116,128, 32, 28,237,239,238,239,243,240,225,227,101,128, + 255, 2,240,242,233,237,101,129, 48, 30,161, 12,242,229,246,229, + 242,243,229,100,128, 48, 29,242,233,231,232,116,128, 32, 29,236, + 229,230,116,129, 32, 24,161, 40,242,229,246,229,242,243,229,100, + 128, 32, 27,114, 2,161, 57,161, 67,229,246,229,242,243,229,100, + 128, 32, 27,233,231,232,116,129, 32, 25,161, 76,110,128, 1, 73, + 243,233,238,231,108, 2,161, 90,161, 97,226,225,243,101,128, 32, + 26,101,129, 0, 39,161,103,237,239,238,239,243,240,225,227,101, + 128,255, 7,114,145, 0,114,161,153,162,157,162,168,162,215,163, + 10,164, 27,164, 51,164,146,166,180,166,217,166,229,167, 27,167, + 35,167,197,167,208,167,243,168, 87, 97, 11,161,177,161,188,161, + 198,161,205,162, 14,162, 30,162, 55,162, 66,162, 91,162,114,162, + 151,225,242,237,229,238,233,225,110,128, 5,124,226,229,238,231, + 225,236,105,128, 9,176,227,245,244,101,128, 1, 85,100, 4,161, + 215,161,221,161,235,162, 5,229,246, 97,128, 9, 48,233,227,225, + 108,129, 34, 26,161,230,229,120,128,248,229,239,246,229,242,243, + 243,241,245,225,242,101,129, 51,174,161,251,228,243,241,245,225, + 242,101,128, 51,175,243,241,245,225,242,101,128, 51,173,230,101, + 129, 5,191,162, 21,232,229,226,242,229,119,128, 5,191,231,117, + 2,162, 37,162, 46,234,225,242,225,244,105,128, 10,176,242,237, + 245,235,232,105,128, 10, 48,232,233,242,225,231,225,238, 97,128, + 48,137,235,225,244,225,235,225,238, 97,129, 48,233,162, 79,232, + 225,236,230,247,233,228,244,104,128,255,151,236,239,247,229,242, + 228,233,225,231,239,238,225,236,226,229,238,231,225,236,105,128, + 9,241,109, 2,162,120,162,143,233,228,228,236,229,228,233,225, + 231,239,238,225,236,226,229,238,231,225,236,105,128, 9,240,243, + 232,239,242,110,128, 2,100,244,233,111,128, 34, 54,226,239,240, + 239,237,239,230,111,128, 49, 22, 99, 4,162,178,162,185,162,194, + 162,202,225,242,239,110,128, 1, 89,229,228,233,236,236, 97,128, + 1, 87,233,242,227,236,101,128, 36,225,239,237,237,225,225,227, + 227,229,238,116,128, 1, 87,100, 2,162,221,162,231,226,236,231, + 242,225,246,101,128, 2, 17,239,116, 2,162,238,162,247,225,227, + 227,229,238,116,128, 30, 89,226,229,236,239,119,129, 30, 91,163, + 1,237,225,227,242,239,110,128, 30, 93,101, 6,163, 24,163, 69, + 163,104,163,159,163,184,163,217,102, 2,163, 30,163, 43,229,242, + 229,238,227,229,237,225,242,107,128, 32, 59,236,229,248,243,117, + 2,163, 53,163, 60,226,243,229,116,128, 34,134,240,229,242,243, + 229,116,128, 34,135,231,233,243,244,229,114, 2,163, 80,163, 85, + 229,100,128, 0,174,115, 2,163, 91,163, 97,225,238,115,128,248, + 232,229,242,233,102,128,246,218,104, 3,163,112,163,135,163,149, + 225,114, 2,163,119,163,126,225,226,233, 99,128, 6, 49,237,229, + 238,233,225,110,128, 5,128,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,174,233,242,225,231,225,238, 97,128, 48,140,235, + 225,244,225,235,225,238, 97,129, 48,236,163,172,232,225,236,230, + 247,233,228,244,104,128,255,154,243,104,130, 5,232,163,193,163, + 208,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 72, + 232,229,226,242,229,119,128, 5,232,118, 3,163,225,163,238,164, + 14,229,242,243,229,228,244,233,236,228,101,128, 34, 61,233, 97, + 2,163,245,163,254,232,229,226,242,229,119,128, 5,151,237,245, + 231,242,225,243,232,232,229,226,242,229,119,128, 5,151,236,239, + 231,233,227,225,236,238,239,116,128, 35, 16,230,233,243,232,232, + 239,239,107,129, 2,126,164, 40,242,229,246,229,242,243,229,100, + 128, 2,127,104, 2,164, 57,164, 80, 97, 2,164, 63,164, 73,226, + 229,238,231,225,236,105,128, 9,221,228,229,246, 97,128, 9, 93, + 111,131, 3,193,164, 90,164,119,164,133,239,107,129, 2,125,164, + 97,244,245,242,238,229,100,129, 2,123,164,108,243,245,240,229, + 242,233,239,114,128, 2,181,243,249,237,226,239,236,231,242,229, + 229,107,128, 3,241,244,233,227,232,239,239,235,237,239,100,128, + 2,222,105, 6,164,160,165,204,165,250,166, 5,166, 30,166,166, + 229,245,108, 9,164,182,164,217,164,232,164,246,165, 36,165, 50, + 165,136,165,149,165,184, 97, 2,164,188,164,203,227,233,242,227, + 236,229,235,239,242,229,225,110,128, 50,113,240,225,242,229,238, + 235,239,242,229,225,110,128, 50, 17,227,233,242,227,236,229,235, + 239,242,229,225,110,128, 50, 99,232,233,229,245,232,235,239,242, + 229,225,110,128, 49, 64,107, 2,164,252,165, 28,233,249,229,239, + 107, 2,165, 6,165, 15,235,239,242,229,225,110,128, 49, 58,243, + 233,239,243,235,239,242,229,225,110,128, 49,105,239,242,229,225, + 110,128, 49, 57,237,233,229,245,237,235,239,242,229,225,110,128, + 49, 59,112, 3,165, 58,165, 90,165,105, 97, 2,165, 64,165, 78, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,108,242,229, + 238,235,239,242,229,225,110,128, 50, 3,232,233,229,245,240,232, + 235,239,242,229,225,110,128, 49, 63,233,229,245,112, 2,165,114, + 165,123,235,239,242,229,225,110,128, 49, 60,243,233,239,243,235, + 239,242,229,225,110,128, 49,107,243,233,239,243,235,239,242,229, + 225,110,128, 49, 61,116, 2,165,155,165,170,232,233,229,245,244, + 232,235,239,242,229,225,110,128, 49, 62,233,235,229,245,244,235, + 239,242,229,225,110,128, 49,106,249,229,239,242,233,238,232,233, + 229,245,232,235,239,242,229,225,110,128, 49,109,231,232,116, 2, + 165,212,165,220,225,238,231,236,101,128, 34, 31,116, 2,165,226, + 165,240,225,227,235,226,229,236,239,247,227,237, 98,128, 3, 25, + 242,233,225,238,231,236,101,128, 34,191,232,233,242,225,231,225, + 238, 97,128, 48,138,235,225,244,225,235,225,238, 97,129, 48,234, + 166, 18,232,225,236,230,247,233,228,244,104,128,255,152,110, 2, + 166, 36,166,152,103,131, 2,218,166, 46,166, 57,166, 63,226,229, + 236,239,247,227,237, 98,128, 3, 37,227,237, 98,128, 3, 10,232, + 225,236,102, 2,166, 72,166,118,236,229,230,116,131, 2,191,166, + 85,166, 96,166,107,225,242,237,229,238,233,225,110,128, 5, 89, + 226,229,236,239,247,227,237, 98,128, 3, 28,227,229,238,244,229, + 242,229,100,128, 2,211,242,233,231,232,116,130, 2,190,166,130, + 166,141,226,229,236,239,247,227,237, 98,128, 3, 57,227,229,238, + 244,229,242,229,100,128, 2,210,246,229,242,244,229,228,226,242, + 229,246,101,128, 2, 19,244,244,239,242,245,243,241,245,225,242, + 101,128, 51, 81,108, 2,166,186,166,197,233,238,229,226,229,236, + 239,119,128, 30, 95,239,238,231,236,229,103,129, 2,124,166,208, + 244,245,242,238,229,100,128, 2,122,237,239,238,239,243,240,225, + 227,101,128,255, 82,111, 3,166,237,166,248,167, 17,232,233,242, + 225,231,225,238, 97,128, 48,141,235,225,244,225,235,225,238, 97, + 129, 48,237,167, 5,232,225,236,230,247,233,228,244,104,128,255, + 155,242,245,225,244,232,225,105,128, 14, 35,240,225,242,229,110, + 128, 36,173,114, 3,167, 43,167, 79,167,109, 97, 3,167, 51,167, + 61,167, 68,226,229,238,231,225,236,105,128, 9,220,228,229,246, + 97,128, 9, 49,231,245,242,237,245,235,232,105,128, 10, 92,229, + 104, 2,167, 86,167, 95,225,242,225,226,233, 99,128, 6,145,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,141,246,239,227, + 225,236,233, 99, 4,167,125,167,135,167,142,167,153,226,229,238, + 231,225,236,105,128, 9,224,228,229,246, 97,128, 9, 96,231,245, + 234,225,242,225,244,105,128, 10,224,246,239,247,229,236,243,233, + 231,110, 3,167,169,167,179,167,186,226,229,238,231,225,236,105, + 128, 9,196,228,229,246, 97,128, 9, 68,231,245,234,225,242,225, + 244,105,128, 10,196,243,245,240,229,242,233,239,114,128,246,241, + 116, 2,167,214,167,222,226,236,239,227,107,128, 37,144,245,242, + 238,229,100,129, 2,121,167,232,243,245,240,229,242,233,239,114, + 128, 2,180,117, 4,167,253,168, 8,168, 33,168, 80,232,233,242, + 225,231,225,238, 97,128, 48,139,235,225,244,225,235,225,238, 97, + 129, 48,235,168, 21,232,225,236,230,247,233,228,244,104,128,255, + 153,112, 2,168, 39,168, 74,229,101, 2,168, 46,168, 60,237,225, + 242,235,226,229,238,231,225,236,105,128, 9,242,243,233,231,238, + 226,229,238,231,225,236,105,128, 9,243,233,225,104,128,246,221, + 244,232,225,105,128, 14, 36,246,239,227,225,236,233, 99, 4,168, + 103,168,113,168,120,168,131,226,229,238,231,225,236,105,128, 9, + 139,228,229,246, 97,128, 9, 11,231,245,234,225,242,225,244,105, + 128, 10,139,246,239,247,229,236,243,233,231,110, 3,168,147,168, + 157,168,164,226,229,238,231,225,236,105,128, 9,195,228,229,246, + 97,128, 9, 67,231,245,234,225,242,225,244,105,128, 10,195,115, + 147, 0,115,168,217,170,187,170,198,171, 68,171,107,174, 49,174, + 60,176,203,179, 85,179,131,179,158,180, 93,180,160,181,193,181, + 203,182,133,182,206,183,120,183,130, 97, 9,168,237,168,247,169, + 12,169, 84,169,109,169,120,169,145,169,177,169,217,226,229,238, + 231,225,236,105,128, 9,184,227,245,244,101,129, 1, 91,169, 0, + 228,239,244,225,227,227,229,238,116,128, 30,101,100, 5,169, 24, + 169, 33,169, 39,169, 53,169, 69,225,242,225,226,233, 99,128, 6, + 53,229,246, 97,128, 9, 56,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,186,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,254,187,237,229,228,233,225,236,225,242,225,226,233, + 99,128,254,188,231,117, 2,169, 91,169,100,234,225,242,225,244, + 105,128, 10,184,242,237,245,235,232,105,128, 10, 56,232,233,242, + 225,231,225,238, 97,128, 48, 85,235,225,244,225,235,225,238, 97, + 129, 48,181,169,133,232,225,236,230,247,233,228,244,104,128,255, + 123,236,236,225,236,236,225,232,239,245,225,236,225,249,232,229, + 247,225,243,225,236,236,225,237,225,242,225,226,233, 99,128,253, + 250,237,229,235,104,130, 5,225,169,188,169,208,228,225,231,229, + 243,104,129,251, 65,169,199,232,229,226,242,229,119,128,251, 65, + 232,229,226,242,229,119,128, 5,225,242, 97, 5,169,230,170, 48, + 170, 56,170,106,170,114, 97, 5,169,242,169,250,170, 2,170, 33, + 170, 41,225,244,232,225,105,128, 14, 50,229,244,232,225,105,128, + 14, 65,233,237,225,233,109, 2,170, 12,170, 23,225,236,225,233, + 244,232,225,105,128, 14, 68,245,225,238,244,232,225,105,128, 14, + 67,237,244,232,225,105,128, 14, 51,244,232,225,105,128, 14, 48, + 229,244,232,225,105,128, 14, 64,105, 3,170, 64,170, 88,170, 99, + 105, 2,170, 70,170, 81,236,229,230,244,244,232,225,105,128,248, + 134,244,232,225,105,128, 14, 53,236,229,230,244,244,232,225,105, + 128,248,133,244,232,225,105,128, 14, 52,239,244,232,225,105,128, + 14, 66,117, 3,170,122,170,172,170,179,101, 3,170,130,170,154, + 170,165,101, 2,170,136,170,147,236,229,230,244,244,232,225,105, + 128,248,136,244,232,225,105,128, 14, 55,236,229,230,244,244,232, + 225,105,128,248,135,244,232,225,105,128, 14, 54,244,232,225,105, + 128, 14, 56,245,244,232,225,105,128, 14, 57,226,239,240,239,237, + 239,230,111,128, 49, 25, 99, 5,170,210,170,231,170,240,171, 33, + 171, 55,225,242,239,110,129, 1, 97,170,219,228,239,244,225,227, + 227,229,238,116,128, 30,103,229,228,233,236,236, 97,128, 1, 95, + 232,247, 97,131, 2, 89,170,252,171, 7,171, 26,227,249,242,233, + 236,236,233, 99,128, 4,217,228,233,229,242,229,243,233,243,227, + 249,242,233,236,236,233, 99,128, 4,219,232,239,239,107,128, 2, + 90,233,242, 99, 2,171, 41,171, 46,236,101,128, 36,226,245,237, + 230,236,229,120,128, 1, 93,239,237,237,225,225,227,227,229,238, + 116,128, 2, 25,228,239,116, 2,171, 76,171, 85,225,227,227,229, + 238,116,128, 30, 97,226,229,236,239,119,129, 30, 99,171, 95,228, + 239,244,225,227,227,229,238,116,128, 30,105,101, 9,171,127,171, + 143,171,178,171,243,172, 90,172,117,172,142,172,223,172,250,225, + 231,245,236,236,226,229,236,239,247,227,237, 98,128, 3, 60, 99, + 2,171,149,171,171,239,238,100,129, 32, 51,171,157,244,239,238, + 229,227,232,233,238,229,243,101,128, 2,202,244,233,239,110,128, + 0,167,229,110, 4,171,189,171,198,171,212,171,228,225,242,225, + 226,233, 99,128, 6, 51,230,233,238,225,236,225,242,225,226,233, + 99,128,254,178,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,179,237,229,228,233,225,236,225,242,225,226,233, 99, + 128,254,180,231,239,108,135, 5,182,172, 7,172, 21,172, 26,172, + 35,172, 50,172, 66,172, 77, 49, 2,172, 13,172, 17, 51,128, 5, + 182,102,128, 5,182,178, 99,128, 5,182,232,229,226,242,229,119, + 128, 5,182,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,182,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,182,244,225,232,229,226,242,229,119,128, 5,146,247,233,228, + 229,232,229,226,242,229,119,128, 5,182,104, 2,172, 96,172,107, + 225,242,237,229,238,233,225,110,128, 5,125,233,242,225,231,225, + 238, 97,128, 48, 91,235,225,244,225,235,225,238, 97,129, 48,187, + 172,130,232,225,236,230,247,233,228,244,104,128,255,126,237,105, + 2,172,149,172,192,227,239,236,239,110,131, 0, 59,172,163,172, + 172,172,184,225,242,225,226,233, 99,128, 6, 27,237,239,238,239, + 243,240,225,227,101,128,255, 27,243,237,225,236,108,128,254, 84, + 246,239,233,227,229,228,237,225,242,235,235,225,238, 97,129, 48, + 156,172,211,232,225,236,230,247,233,228,244,104,128,255,159,238, + 116, 2,172,230,172,240,233,243,241,245,225,242,101,128, 51, 34, + 239,243,241,245,225,242,101,128, 51, 35,246,229,110,142, 0, 55, + 173, 28,173, 37,173, 47,173, 77,173, 84,173, 94,173,119,173,146, + 173,180,173,192,173,203,173,236,173,244,173,255,225,242,225,226, + 233, 99,128, 6,103,226,229,238,231,225,236,105,128, 9,237,227, + 233,242,227,236,101,129, 36,102,173, 58,233,238,246,229,242,243, + 229,243,225,238,243,243,229,242,233,102,128, 39,144,228,229,246, + 97,128, 9,109,229,233,231,232,244,232,115,128, 33, 94,231,117, + 2,173,101,173,110,234,225,242,225,244,105,128, 10,237,242,237, + 245,235,232,105,128, 10,109,232, 97, 2,173,126,173,137,227,235, + 225,242,225,226,233, 99,128, 6,103,238,231,250,232,239,117,128, + 48, 39,105, 2,173,152,173,170,228,229,239,231,242,225,240,232, + 233,227,240,225,242,229,110,128, 50, 38,238,230,229,242,233,239, + 114,128, 32,135,237,239,238,239,243,240,225,227,101,128,255, 23, + 239,236,228,243,244,249,236,101,128,247, 55,112, 2,173,209,173, + 216,225,242,229,110,128, 36,122,229,114, 2,173,223,173,229,233, + 239,100,128, 36,142,243,233,225,110,128, 6,247,242,239,237,225, + 110,128, 33,118,243,245,240,229,242,233,239,114,128, 32,119,116, + 2,174, 5,174, 43,229,229,110, 2,174, 13,174, 22,227,233,242, + 227,236,101,128, 36,112,112, 2,174, 28,174, 35,225,242,229,110, + 128, 36,132,229,242,233,239,100,128, 36,152,232,225,105,128, 14, + 87,230,244,232,249,240,232,229,110,128, 0,173,104, 7,174, 76, + 175, 50,175, 61,175, 75,176, 20,176, 33,176,197, 97, 6,174, 90, + 174,101,174,111,174,122,175, 9,175, 34,225,242,237,229,238,233, + 225,110,128, 5,119,226,229,238,231,225,236,105,128, 9,182,227, + 249,242,233,236,236,233, 99,128, 4, 72,100, 2,174,128,174,224, + 228, 97, 4,174,139,174,148,174,179,174,193,225,242,225,226,233, + 99,128, 6, 81,228,225,237,237, 97, 2,174,158,174,167,225,242, + 225,226,233, 99,128,252, 97,244,225,238,225,242,225,226,233, 99, + 128,252, 94,230,225,244,232,225,225,242,225,226,233, 99,128,252, + 96,235,225,243,242, 97, 2,174,203,174,212,225,242,225,226,233, + 99,128,252, 98,244,225,238,225,242,225,226,233, 99,128,252, 95, + 101,132, 37,146,174,236,174,243,174,251,175, 4,228,225,242,107, + 128, 37,147,236,233,231,232,116,128, 37,145,237,229,228,233,245, + 109,128, 37,146,246, 97,128, 9, 54,231,117, 2,175, 16,175, 25, + 234,225,242,225,244,105,128, 10,182,242,237,245,235,232,105,128, + 10, 54,236,243,232,229,236,229,244,232,229,226,242,229,119,128, + 5,147,226,239,240,239,237,239,230,111,128, 49, 21,227,232,225, + 227,249,242,233,236,236,233, 99,128, 4, 73,101, 4,175, 85,175, + 150,175,160,175,177,229,110, 4,175, 96,175,105,175,119,175,135, + 225,242,225,226,233, 99,128, 6, 52,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,182,233,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,254,183,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,254,184,233,227,239,240,244,233, 99,128, 3,227, + 241,229,108,129, 32,170,175,168,232,229,226,242,229,119,128, 32, + 170,246, 97,134, 5,176,175,194,175,209,175,223,175,232,175,247, + 176, 7, 49, 2,175,200,175,205,177, 53,128, 5,176, 53,128, 5, + 176, 50, 2,175,215,175,219, 50,128, 5,176,101,128, 5,176,232, + 229,226,242,229,119,128, 5,176,238,225,242,242,239,247,232,229, + 226,242,229,119,128, 5,176,241,245,225,242,244,229,242,232,229, + 226,242,229,119,128, 5,176,247,233,228,229,232,229,226,242,229, + 119,128, 5,176,232,225,227,249,242,233,236,236,233, 99,128, 4, + 187,105, 2,176, 39,176, 50,237,225,227,239,240,244,233, 99,128, + 3,237,110,131, 5,233,176, 60,176,143,176,152,100, 2,176, 66, + 176,132,225,231,229,243,104,130,251, 73,176, 78,176, 87,232,229, + 226,242,229,119,128,251, 73,115, 2,176, 93,176,113,232,233,238, + 228,239,116,129,251, 44,176,104,232,229,226,242,229,119,128,251, + 44,233,238,228,239,116,129,251, 45,176,123,232,229,226,242,229, + 119,128,251, 45,239,244,232,229,226,242,229,119,128, 5,193,232, + 229,226,242,229,119,128, 5,233,115, 2,176,158,176,178,232,233, + 238,228,239,116,129,251, 42,176,169,232,229,226,242,229,119,128, + 251, 42,233,238,228,239,116,129,251, 43,176,188,232,229,226,242, + 229,119,128,251, 43,239,239,107,128, 2,130,105, 8,176,221,177, + 9,177, 20,177, 45,177, 75,177, 83,177, 96,178, 11,231,237, 97, + 131, 3,195,176,233,176,237,176,245, 49,128, 3,194,230,233,238, + 225,108,128, 3,194,236,245,238,225,244,229,243,249,237,226,239, + 236,231,242,229,229,107,128, 3,242,232,233,242,225,231,225,238, + 97,128, 48, 87,235,225,244,225,235,225,238, 97,129, 48,183,177, + 33,232,225,236,230,247,233,228,244,104,128,255,124,236,245,113, + 2,177, 53,177, 62,232,229,226,242,229,119,128, 5,189,236,229, + 230,244,232,229,226,242,229,119,128, 5,189,237,233,236,225,114, + 128, 34, 60,238,228,239,244,232,229,226,242,229,119,128, 5,194, + 239,115, 6,177,111,177,146,177,178,177,206,177,220,177,252, 97, + 2,177,117,177,132,227,233,242,227,236,229,235,239,242,229,225, + 110,128, 50,116,240,225,242,229,238,235,239,242,229,225,110,128, + 50, 20,227,105, 2,177,153,177,165,229,245,227,235,239,242,229, + 225,110,128, 49,126,242,227,236,229,235,239,242,229,225,110,128, + 50,102,107, 2,177,184,177,198,233,249,229,239,235,235,239,242, + 229,225,110,128, 49,122,239,242,229,225,110,128, 49, 69,238,233, + 229,245,238,235,239,242,229,225,110,128, 49,123,112, 2,177,226, + 177,239,225,242,229,238,235,239,242,229,225,110,128, 50, 6,233, + 229,245,240,235,239,242,229,225,110,128, 49,125,244,233,235,229, + 245,244,235,239,242,229,225,110,128, 49,124,120,141, 0, 54,178, + 41,178, 50,178, 60,178, 90,178, 97,178,122,178,149,178,183,178, + 195,178,206,178,239,178,247,179, 2,225,242,225,226,233, 99,128, + 6,102,226,229,238,231,225,236,105,128, 9,236,227,233,242,227, + 236,101,129, 36,101,178, 71,233,238,246,229,242,243,229,243,225, + 238,243,243,229,242,233,102,128, 39,143,228,229,246, 97,128, 9, + 108,231,117, 2,178,104,178,113,234,225,242,225,244,105,128, 10, + 236,242,237,245,235,232,105,128, 10,108,232, 97, 2,178,129,178, + 140,227,235,225,242,225,226,233, 99,128, 6,102,238,231,250,232, + 239,117,128, 48, 38,105, 2,178,155,178,173,228,229,239,231,242, + 225,240,232,233,227,240,225,242,229,110,128, 50, 37,238,230,229, + 242,233,239,114,128, 32,134,237,239,238,239,243,240,225,227,101, + 128,255, 22,239,236,228,243,244,249,236,101,128,247, 54,112, 2, + 178,212,178,219,225,242,229,110,128, 36,121,229,114, 2,178,226, + 178,232,233,239,100,128, 36,141,243,233,225,110,128, 6,246,242, + 239,237,225,110,128, 33,117,243,245,240,229,242,233,239,114,128, + 32,118,116, 2,179, 8,179, 79,229,229,110, 2,179, 16,179, 58, + 99, 2,179, 22,179, 30,233,242,227,236,101,128, 36,111,245,242, + 242,229,238,227,249,228,229,238,239,237,233,238,225,244,239,242, + 226,229,238,231,225,236,105,128, 9,249,112, 2,179, 64,179, 71, + 225,242,229,110,128, 36,131,229,242,233,239,100,128, 36,151,232, + 225,105,128, 14, 86,108, 2,179, 91,179,111,225,243,104,129, 0, + 47,179, 99,237,239,238,239,243,240,225,227,101,128,255, 15,239, + 238,103,129, 1,127,179,119,228,239,244,225,227,227,229,238,116, + 128, 30,155,109, 2,179,137,179,147,233,236,229,230,225,227,101, + 128, 38, 58,239,238,239,243,240,225,227,101,128,255, 83,111, 6, + 179,172,179,222,179,233,180, 2,180, 47,180, 58,102, 2,179,178, + 179,192,240,225,243,245,241,232,229,226,242,229,119,128, 5,195, + 116, 2,179,198,179,207,232,249,240,232,229,110,128, 0,173,243, + 233,231,238,227,249,242,233,236,236,233, 99,128, 4, 76,232,233, + 242,225,231,225,238, 97,128, 48, 93,235,225,244,225,235,225,238, + 97,129, 48,189,179,246,232,225,236,230,247,233,228,244,104,128, + 255,127,236,233,228,245,115, 2,180, 12,180, 29,236,239,238,231, + 239,246,229,242,236,225,249,227,237, 98,128, 3, 56,243,232,239, + 242,244,239,246,229,242,236,225,249,227,237, 98,128, 3, 55,242, + 245,243,233,244,232,225,105,128, 14, 41,115, 3,180, 66,180, 76, + 180, 84,225,236,225,244,232,225,105,128, 14, 40,239,244,232,225, + 105,128, 14, 11,245,225,244,232,225,105,128, 14, 42,240, 97, 3, + 180,102,180,122,180,154,227,101,129, 0, 32,180,109,232,225,227, + 235,225,242,225,226,233, 99,128, 0, 32,228,101,129, 38, 96,180, + 129,243,245,233,116, 2,180,138,180,146,226,236,225,227,107,128, + 38, 96,247,232,233,244,101,128, 38,100,242,229,110,128, 36,174, + 241,245,225,242,101, 11,180,188,180,199,180,213,180,238,180,255, + 181, 25,181, 40,181, 73,181,100,181,156,181,171,226,229,236,239, + 247,227,237, 98,128, 3, 59, 99, 2,180,205,180,209, 99,128, 51, + 196,109,128, 51,157,228,233,225,231,239,238,225,236,227,242,239, + 243,243,232,225,244,227,232,230,233,236,108,128, 37,169,232,239, + 242,233,250,239,238,244,225,236,230,233,236,108,128, 37,164,107, + 2,181, 5,181, 9,103,128, 51,143,109,129, 51,158,181, 15,227, + 225,240,233,244,225,108,128, 51,206,108, 2,181, 31,181, 35,110, + 128, 51,209,239,103,128, 51,210,109, 4,181, 50,181, 54,181, 59, + 181, 63,103,128, 51,142,233,108,128, 51,213,109,128, 51,156,243, + 241,245,225,242,229,100,128, 51,161,239,242,244,232,239,231,239, + 238,225,236,227,242,239,243,243,232,225,244,227,232,230,233,236, + 108,128, 37,166,245,240,240,229,114, 2,181,110,181,133,236,229, + 230,244,244,239,236,239,247,229,242,242,233,231,232,244,230,233, + 236,108,128, 37,167,242,233,231,232,244,244,239,236,239,247,229, + 242,236,229,230,244,230,233,236,108,128, 37,168,246,229,242,244, + 233,227,225,236,230,233,236,108,128, 37,165,247,232,233,244,229, + 247,233,244,232,243,237,225,236,236,226,236,225,227,107,128, 37, + 163,242,243,241,245,225,242,101,128, 51,219,115, 2,181,209,182, + 123, 97, 4,181,219,181,229,181,236,181,247,226,229,238,231,225, + 236,105,128, 9,183,228,229,246, 97,128, 9, 55,231,245,234,225, + 242,225,244,105,128, 10,183,238,103, 8,182, 10,182, 24,182, 38, + 182, 52,182, 67,182, 81,182, 95,182,108,227,233,229,245,227,235, + 239,242,229,225,110,128, 49, 73,232,233,229,245,232,235,239,242, + 229,225,110,128, 49,133,233,229,245,238,231,235,239,242,229,225, + 110,128, 49,128,235,233,249,229,239,235,235,239,242,229,225,110, + 128, 49, 50,238,233,229,245,238,235,239,242,229,225,110,128, 49, + 101,240,233,229,245,240,235,239,242,229,225,110,128, 49, 67,243, + 233,239,243,235,239,242,229,225,110,128, 49, 70,244,233,235,229, + 245,244,235,239,242,229,225,110,128, 49, 56,245,240,229,242,233, + 239,114,128,246,242,116, 2,182,139,182,162,229,242,236,233,238, + 103,129, 0,163,182,150,237,239,238,239,243,240,225,227,101,128, + 255,225,242,239,235,101, 2,182,171,182,188,236,239,238,231,239, + 246,229,242,236,225,249,227,237, 98,128, 3, 54,243,232,239,242, + 244,239,246,229,242,236,225,249,227,237, 98,128, 3, 53,117, 7, + 182,222,182,254,183, 20,183, 31,183, 72,183, 82,183, 86,226,243, + 229,116,130, 34,130,182,233,182,244,238,239,244,229,241,245,225, + 108,128, 34,138,239,242,229,241,245,225,108,128, 34,134, 99, 2, + 183, 4,183, 12,227,229,229,228,115,128, 34,123,232,244,232,225, + 116,128, 34, 11,232,233,242,225,231,225,238, 97,128, 48, 89,107, + 2,183, 37,183, 61,225,244,225,235,225,238, 97,129, 48,185,183, + 49,232,225,236,230,247,233,228,244,104,128,255,125,245,238,225, + 242,225,226,233, 99,128, 6, 82,237,237,225,244,233,239,110,128, + 34, 17,110,128, 38, 60,240,229,242,243,229,116,130, 34,131,183, + 99,183,110,238,239,244,229,241,245,225,108,128, 34,139,239,242, + 229,241,245,225,108,128, 34,135,246,243,241,245,225,242,101,128, + 51,220,249,239,245,247,225,229,242,225,243,241,245,225,242,101, + 128, 51,124,116,144, 0,116,183,183,184,192,184,213,185,100,185, + 140,187,188,191, 70,192,145,192,157,192,169,193,202,193,227,194, + 57,194,237,195,165,195,255, 97, 10,183,205,183,215,183,236,183, + 243,184, 12,184, 90,184,107,184,132,184,146,184,150,226,229,238, + 231,225,236,105,128, 9,164,227,107, 2,183,222,183,229,228,239, + 247,110,128, 34,164,236,229,230,116,128, 34,163,228,229,246, 97, + 128, 9, 36,231,117, 2,183,250,184, 3,234,225,242,225,244,105, + 128, 10,164,242,237,245,235,232,105,128, 10, 36,104, 4,184, 22, + 184, 31,184, 45,184, 75,225,242,225,226,233, 99,128, 6, 55,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,194,105, 2,184, + 51,184, 66,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,195,242,225,231,225,238, 97,128, 48, 95,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,254,196,233,243,249,239,245,229, + 242,225,243,241,245,225,242,101,128, 51,125,235,225,244,225,235, + 225,238, 97,129, 48,191,184,120,232,225,236,230,247,233,228,244, + 104,128,255,128,244,247,229,229,236,225,242,225,226,233, 99,128, + 6, 64,117,128, 3,196,118,130, 5,234,184,158,184,183,228,225, + 231,229,115,129,251, 74,184,168,104,129,251, 74,184,174,232,229, + 226,242,229,119,128,251, 74,232,229,226,242,229,119,128, 5,234, + 98, 2,184,198,184,203,225,114,128, 1,103,239,240,239,237,239, + 230,111,128, 49, 10, 99, 6,184,227,184,234,184,241,184,250,185, + 60,185, 87,225,242,239,110,128, 1,101,227,245,242,108,128, 2, + 168,229,228,233,236,236, 97,128, 1, 99,232,229,104, 4,185, 6, + 185, 15,185, 29,185, 45,225,242,225,226,233, 99,128, 6,134,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,123,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,251,124,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,251,125,233,242, 99, 2, + 185, 68,185, 73,236,101,128, 36,227,245,237,230,236,229,248,226, + 229,236,239,119,128, 30,113,239,237,237,225,225,227,227,229,238, + 116,128, 1, 99,100, 2,185,106,185,116,233,229,242,229,243,233, + 115,128, 30,151,239,116, 2,185,123,185,132,225,227,227,229,238, + 116,128, 30,107,226,229,236,239,119,128, 30,109,101, 9,185,160, + 185,171,185,191,186,201,186,226,187, 34,187,101,187,106,187,158, + 227,249,242,233,236,236,233, 99,128, 4, 66,228,229,243,227,229, + 238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,173,104, + 7,185,207,185,216,185,230,186, 14,186, 44,186, 85,186,183,225, + 242,225,226,233, 99,128, 6, 42,230,233,238,225,236,225,242,225, + 226,233, 99,128,254,150,232,225,232,105, 2,185,239,185,254,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,252,162,243,239, + 236,225,244,229,228,225,242,225,226,233, 99,128,252, 12,105, 2, + 186, 20,186, 35,238,233,244,233,225,236,225,242,225,226,233, 99, + 128,254,151,242,225,231,225,238, 97,128, 48,102,234,229,229,237, + 105, 2,186, 54,186, 69,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,252,161,243,239,236,225,244,229,228,225,242,225,226, + 233, 99,128,252, 11,109, 2,186, 91,186,125,225,242,226,245,244, + 97, 2,186,102,186,111,225,242,225,226,233, 99,128, 6, 41,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,148,101, 2,186, + 131,186,144,228,233,225,236,225,242,225,226,233, 99,128,254,152, + 229,237,105, 2,186,152,186,167,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,252,164,243,239,236,225,244,229,228,225,242, + 225,226,233, 99,128,252, 14,238,239,239,238,230,233,238,225,236, + 225,242,225,226,233, 99,128,252,115,235,225,244,225,235,225,238, + 97,129, 48,198,186,214,232,225,236,230,247,233,228,244,104,128, + 255,131,108, 2,186,232,186,251,229,240,232,239,238,101,129, 33, + 33,186,243,226,236,225,227,107,128, 38, 14,233,243,232, 97, 2, + 187, 4,187, 19,231,229,228,239,236,225,232,229,226,242,229,119, + 128, 5,160,241,229,244,225,238,225,232,229,226,242,229,119,128, + 5,169,110, 4,187, 44,187, 53,187, 72,187, 93,227,233,242,227, + 236,101,128, 36,105,233,228,229,239,231,242,225,240,232,233,227, + 240,225,242,229,110,128, 50, 41,112, 2,187, 78,187, 85,225,242, + 229,110,128, 36,125,229,242,233,239,100,128, 36,145,242,239,237, + 225,110,128, 33,121,243,104,128, 2,167,116,131, 5,216,187,116, + 187,136,187,145,228,225,231,229,243,104,129,251, 56,187,127,232, + 229,226,242,229,119,128,251, 56,232,229,226,242,229,119,128, 5, + 216,243,229,227,249,242,233,236,236,233, 99,128, 4,181,246,233, + 114, 2,187,166,187,175,232,229,226,242,229,119,128, 5,155,236, + 229,230,244,232,229,226,242,229,119,128, 5,155,104, 6,187,202, + 188, 98,188,220,189, 96,190, 3,191, 60, 97, 5,187,214,187,224, + 187,231,188, 0,188, 29,226,229,238,231,225,236,105,128, 9,165, + 228,229,246, 97,128, 9, 37,231,117, 2,187,238,187,247,234,225, + 242,225,244,105,128, 10,165,242,237,245,235,232,105,128, 10, 37, + 108, 2,188, 6,188, 15,225,242,225,226,233, 99,128, 6, 48,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,172,238,244,232, + 225,235,232,225,116, 3,188, 44,188, 75,188, 82,236,239,119, 2, + 188, 52,188, 63,236,229,230,244,244,232,225,105,128,248,152,242, + 233,231,232,244,244,232,225,105,128,248,151,244,232,225,105,128, + 14, 76,245,240,240,229,242,236,229,230,244,244,232,225,105,128, + 248,150,101, 3,188,106,188,170,188,193,104, 4,188,116,188,125, + 188,139,188,155,225,242,225,226,233, 99,128, 6, 43,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,154,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,254,155,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,254,156,242,101, 2,188,177,188, + 186,229,248,233,243,244,115,128, 34, 3,230,239,242,101,128, 34, + 52,244, 97,130, 3,184,188,202,188,206, 49,128, 3,209,243,249, + 237,226,239,236,231,242,229,229,107,128, 3,209,105, 2,188,226, + 189, 56,229,245,244,104, 4,188,239,189, 18,189, 33,189, 42, 97, + 2,188,245,189, 4,227,233,242,227,236,229,235,239,242,229,225, + 110,128, 50,121,240,225,242,229,238,235,239,242,229,225,110,128, + 50, 25,227,233,242,227,236,229,235,239,242,229,225,110,128, 50, + 107,235,239,242,229,225,110,128, 49, 76,240,225,242,229,238,235, + 239,242,229,225,110,128, 50, 11,242,244,229,229,110, 2,189, 66, + 189, 75,227,233,242,227,236,101,128, 36,108,112, 2,189, 81,189, + 88,225,242,229,110,128, 36,128,229,242,233,239,100,128, 36,148, + 111, 6,189,110,189,127,189,132,189,146,189,151,189,204,238,225, + 238,231,237,239,238,244,232,239,244,232,225,105,128, 14, 17,239, + 107,128, 1,173,240,232,245,244,232,225,239,244,232,225,105,128, + 14, 18,242,110,128, 0,254,244,104, 3,189,160,189,184,189,194, + 97, 2,189,166,189,176,232,225,238,244,232,225,105,128, 14, 23, + 238,244,232,225,105,128, 14, 16,239,238,231,244,232,225,105,128, + 14, 24,245,238,231,244,232,225,105,128, 14, 22,245,243,225,238, + 100, 2,189,214,189,225,227,249,242,233,236,236,233, 99,128, 4, + 130,243,243,229,240,225,242,225,244,239,114, 2,189,240,189,249, + 225,242,225,226,233, 99,128, 6,108,240,229,242,243,233,225,110, + 128, 6,108,242,229,101,144, 0, 51,190, 41,190, 50,190, 60,190, + 90,190, 97,190,107,190,132,190,159,190,193,190,205,190,224,190, + 235,191, 12,191, 34,191, 42,191, 53,225,242,225,226,233, 99,128, + 6, 99,226,229,238,231,225,236,105,128, 9,233,227,233,242,227, + 236,101,129, 36, 98,190, 71,233,238,246,229,242,243,229,243,225, + 238,243,243,229,242,233,102,128, 39,140,228,229,246, 97,128, 9, + 105,229,233,231,232,244,232,115,128, 33, 92,231,117, 2,190,114, + 190,123,234,225,242,225,244,105,128, 10,233,242,237,245,235,232, + 105,128, 10,105,232, 97, 2,190,139,190,150,227,235,225,242,225, + 226,233, 99,128, 6, 99,238,231,250,232,239,117,128, 48, 35,105, + 2,190,165,190,183,228,229,239,231,242,225,240,232,233,227,240, + 225,242,229,110,128, 50, 34,238,230,229,242,233,239,114,128, 32, + 131,237,239,238,239,243,240,225,227,101,128,255, 19,238,245,237, + 229,242,225,244,239,242,226,229,238,231,225,236,105,128, 9,246, + 239,236,228,243,244,249,236,101,128,247, 51,112, 2,190,241,190, + 248,225,242,229,110,128, 36,118,229,114, 2,190,255,191, 5,233, + 239,100,128, 36,138,243,233,225,110,128, 6,243,241,245,225,242, + 244,229,242,115,129, 0,190,191, 25,229,237,228,225,243,104,128, + 246,222,242,239,237,225,110,128, 33,114,243,245,240,229,242,233, + 239,114,128, 0,179,244,232,225,105,128, 14, 83,250,243,241,245, + 225,242,101,128, 51,148,105, 7,191, 86,191, 97,191,212,192, 54, + 192, 66,192,115,192,132,232,233,242,225,231,225,238, 97,128, 48, + 97,107, 2,191,103,191,127,225,244,225,235,225,238, 97,129, 48, + 193,191,115,232,225,236,230,247,233,228,244,104,128,255,129,229, + 245,116, 4,191,139,191,174,191,189,191,198, 97, 2,191,145,191, + 160,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,112, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 16,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50, 98,235,239,242, + 229,225,110,128, 49, 55,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 2,236,228,101,133, 2,220,191,228,191,239,192, 0, + 192, 12,192, 40,226,229,236,239,247,227,237, 98,128, 3, 48, 99, + 2,191,245,191,250,237, 98,128, 3, 3,239,237, 98,128, 3, 3, + 228,239,245,226,236,229,227,237, 98,128, 3, 96,111, 2,192, 18, + 192, 28,240,229,242,225,244,239,114,128, 34, 60,246,229,242,236, + 225,249,227,237, 98,128, 3, 52,246,229,242,244,233,227,225,236, + 227,237, 98,128, 3, 62,237,229,243,227,233,242,227,236,101,128, + 34,151,112, 2,192, 72,192,102,229,232, 97, 2,192, 80,192, 89, + 232,229,226,242,229,119,128, 5,150,236,229,230,244,232,229,226, + 242,229,119,128, 5,150,240,233,231,245,242,237,245,235,232,105, + 128, 10,112,244,236,239,227,249,242,233,236,236,233,227,227,237, + 98,128, 4,131,247,238,225,242,237,229,238,233,225,110,128, 5, + 127,236,233,238,229,226,229,236,239,119,128, 30,111,237,239,238, + 239,243,240,225,227,101,128,255, 84,111, 7,192,185,192,196,192, + 207,192,232,193, 96,193,108,193,192,225,242,237,229,238,233,225, + 110,128, 5,105,232,233,242,225,231,225,238, 97,128, 48,104,235, + 225,244,225,235,225,238, 97,129, 48,200,192,220,232,225,236,230, + 247,233,228,244,104,128,255,132,110, 3,192,240,193, 82,193, 87, + 101, 4,192,250,193, 63,193, 70,193, 76,226,225,114, 4,193, 6, + 193, 35,193, 45,193, 54,229,248,244,242, 97, 2,193, 16,193, 26, + 232,233,231,232,237,239,100,128, 2,229,236,239,247,237,239,100, + 128, 2,233,232,233,231,232,237,239,100,128, 2,230,236,239,247, + 237,239,100,128, 2,232,237,233,228,237,239,100,128, 2,231,230, + 233,246,101,128, 1,189,243,233,120,128, 1,133,244,247,111,128, + 1,168,239,115,128, 3,132,243,241,245,225,242,101,128, 51, 39, + 240,225,244,225,235,244,232,225,105,128, 14, 15,242,244,239,233, + 243,229,243,232,229,236,236,226,242,225,227,235,229,116, 2,193, + 131,193,161,236,229,230,116,130, 48, 20,193,142,193,150,243,237, + 225,236,108,128,254, 93,246,229,242,244,233,227,225,108,128,254, + 57,242,233,231,232,116,130, 48, 21,193,173,193,181,243,237,225, + 236,108,128,254, 94,246,229,242,244,233,227,225,108,128,254, 58, + 244,225,239,244,232,225,105,128, 14, 21,240, 97, 2,193,209,193, + 221,236,225,244,225,236,232,239,239,107,128, 1,171,242,229,110, + 128, 36,175,114, 3,193,235,194, 10,194, 25,225,228,229,237,225, + 242,107,129, 33, 34,193,247,115, 2,193,253,194, 3,225,238,115, + 128,248,234,229,242,233,102,128,246,219,229,244,242,239,230,236, + 229,248,232,239,239,107,128, 2,136,233,225,103, 4,194, 37,194, + 42,194, 47,194, 52,228,110,128, 37,188,236,102,128, 37,196,242, + 116,128, 37,186,245,112,128, 37,178,115,132, 2,166,194, 69,194, + 108,194,214,194,227,225,228,105,130, 5,230,194, 79,194, 99,228, + 225,231,229,243,104,129,251, 70,194, 90,232,229,226,242,229,119, + 128,251, 70,232,229,226,242,229,119,128, 5,230,101, 2,194,114, + 194,125,227,249,242,233,236,236,233, 99,128, 4, 70,242,101,134, + 5,181,194,142,194,156,194,161,194,170,194,185,194,201, 49, 2, + 194,148,194,152, 50,128, 5,181,101,128, 5,181,178, 98,128, 5, + 181,232,229,226,242,229,119,128, 5,181,238,225,242,242,239,247, + 232,229,226,242,229,119,128, 5,181,241,245,225,242,244,229,242, + 232,229,226,242,229,119,128, 5,181,247,233,228,229,232,229,226, + 242,229,119,128, 5,181,232,229,227,249,242,233,236,236,233, 99, + 128, 4, 91,245,240,229,242,233,239,114,128,246,243,116, 4,194, + 247,195, 41,195,106,195,157, 97, 3,194,255,195, 9,195, 16,226, + 229,238,231,225,236,105,128, 9,159,228,229,246, 97,128, 9, 31, + 231,117, 2,195, 23,195, 32,234,225,242,225,244,105,128, 10,159, + 242,237,245,235,232,105,128, 10, 31,229,104, 4,195, 52,195, 61, + 195, 75,195, 91,225,242,225,226,233, 99,128, 6,121,230,233,238, + 225,236,225,242,225,226,233, 99,128,251,103,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,251,104,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,251,105,232, 97, 3,195,115,195, + 125,195,132,226,229,238,231,225,236,105,128, 9,160,228,229,246, + 97,128, 9, 32,231,117, 2,195,139,195,148,234,225,242,225,244, + 105,128, 10,160,242,237,245,235,232,105,128, 10, 32,245,242,238, + 229,100,128, 2,135,117, 3,195,173,195,184,195,209,232,233,242, + 225,231,225,238, 97,128, 48,100,235,225,244,225,235,225,238, 97, + 129, 48,196,195,197,232,225,236,230,247,233,228,244,104,128,255, + 130,243,237,225,236,108, 2,195,219,195,230,232,233,242,225,231, + 225,238, 97,128, 48, 99,235,225,244,225,235,225,238, 97,129, 48, + 195,195,243,232,225,236,230,247,233,228,244,104,128,255,111,119, + 2,196, 5,196,110,101, 2,196, 11,196, 59,236,246,101, 3,196, + 21,196, 30,196, 51,227,233,242,227,236,101,128, 36,107,112, 2, + 196, 36,196, 43,225,242,229,110,128, 36,127,229,242,233,239,100, + 128, 36,147,242,239,237,225,110,128, 33,123,238,244,121, 3,196, + 69,196, 78,196, 89,227,233,242,227,236,101,128, 36,115,232,225, + 238,231,250,232,239,117,128, 83, 68,112, 2,196, 95,196,102,225, + 242,229,110,128, 36,135,229,242,233,239,100,128, 36,155,111,142, + 0, 50,196,142,196,151,196,161,196,191,196,243,197, 12,197, 39, + 197, 73,197, 85,197,104,197,115,197,148,197,156,197,180,225,242, + 225,226,233, 99,128, 6, 98,226,229,238,231,225,236,105,128, 9, + 232,227,233,242,227,236,101,129, 36, 97,196,172,233,238,246,229, + 242,243,229,243,225,238,243,243,229,242,233,102,128, 39,139,100, + 2,196,197,196,203,229,246, 97,128, 9,104,239,116, 2,196,210, + 196,221,229,238,236,229,225,228,229,114,128, 32, 37,236,229,225, + 228,229,114,129, 32, 37,196,232,246,229,242,244,233,227,225,108, + 128,254, 48,231,117, 2,196,250,197, 3,234,225,242,225,244,105, + 128, 10,232,242,237,245,235,232,105,128, 10,104,232, 97, 2,197, + 19,197, 30,227,235,225,242,225,226,233, 99,128, 6, 98,238,231, + 250,232,239,117,128, 48, 34,105, 2,197, 45,197, 63,228,229,239, + 231,242,225,240,232,233,227,240,225,242,229,110,128, 50, 33,238, + 230,229,242,233,239,114,128, 32,130,237,239,238,239,243,240,225, + 227,101,128,255, 18,238,245,237,229,242,225,244,239,242,226,229, + 238,231,225,236,105,128, 9,245,239,236,228,243,244,249,236,101, + 128,247, 50,112, 2,197,121,197,128,225,242,229,110,128, 36,117, + 229,114, 2,197,135,197,141,233,239,100,128, 36,137,243,233,225, + 110,128, 6,242,242,239,237,225,110,128, 33,113,115, 2,197,162, + 197,170,244,242,239,235,101,128, 1,187,245,240,229,242,233,239, + 114,128, 0,178,244,104, 2,197,187,197,192,225,105,128, 14, 82, + 233,242,228,115,128, 33, 84,117,145, 0,117,197,237,197,245,198, + 30,198, 87,198,225,199, 6,199,129,199,145,199,196,200, 10,200, + 91,200,100,200,219,200,243,201, 95,201,123,201,237,225,227,245, + 244,101,128, 0,250, 98, 4,197,255,198, 4,198, 13,198, 23,225, + 114,128, 2,137,229,238,231,225,236,105,128, 9,137,239,240,239, + 237,239,230,111,128, 49, 40,242,229,246,101,128, 1,109, 99, 3, + 198, 38,198, 45,198, 77,225,242,239,110,128, 1,212,233,242, 99, + 2,198, 53,198, 58,236,101,128, 36,228,245,237,230,236,229,120, + 129, 0,251,198, 69,226,229,236,239,119,128, 30,119,249,242,233, + 236,236,233, 99,128, 4, 67,100, 5,198, 99,198,110,198,133,198, + 139,198,215,225,244,244,225,228,229,246, 97,128, 9, 81,226,108, + 2,198,117,198,125,225,227,245,244,101,128, 1,113,231,242,225, + 246,101,128, 2, 21,229,246, 97,128, 9, 9,233,229,242,229,243, + 233,115,133, 0,252,198,159,198,167,198,175,198,198,198,206,225, + 227,245,244,101,128, 1,216,226,229,236,239,119,128, 30,115, 99, + 2,198,181,198,188,225,242,239,110,128, 1,218,249,242,233,236, + 236,233, 99,128, 4,241,231,242,225,246,101,128, 1,220,237,225, + 227,242,239,110,128, 1,214,239,244,226,229,236,239,119,128, 30, + 229,103, 2,198,231,198,238,242,225,246,101,128, 0,249,117, 2, + 198,244,198,253,234,225,242,225,244,105,128, 10,137,242,237,245, + 235,232,105,128, 10, 9,104, 3,199, 14,199, 24,199,102,233,242, + 225,231,225,238, 97,128, 48, 70,111, 2,199, 30,199, 40,239,235, + 225,226,239,246,101,128, 30,231,242,110,133, 1,176,199, 55,199, + 63,199, 74,199, 82,199, 94,225,227,245,244,101,128, 30,233,228, + 239,244,226,229,236,239,119,128, 30,241,231,242,225,246,101,128, + 30,235,232,239,239,235,225,226,239,246,101,128, 30,237,244,233, + 236,228,101,128, 30,239,245,238,231,225,242,245,237,236,225,245, + 116,129, 1,113,199,118,227,249,242,233,236,236,233, 99,128, 4, + 243,233,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, + 23,107, 3,199,153,199,177,199,188,225,244,225,235,225,238, 97, + 129, 48,166,199,165,232,225,236,230,247,233,228,244,104,128,255, + 115,227,249,242,233,236,236,233, 99,128, 4,121,239,242,229,225, + 110,128, 49, 92,109, 2,199,202,199,255, 97, 2,199,208,199,241, + 227,242,239,110,130, 1,107,199,219,199,230,227,249,242,233,236, + 236,233, 99,128, 4,239,228,233,229,242,229,243,233,115,128, 30, + 123,244,242,225,231,245,242,237,245,235,232,105,128, 10, 65,239, + 238,239,243,240,225,227,101,128,255, 85,110, 2,200, 16,200, 71, + 228,229,242,243,227,239,242,101,132, 0, 95,200, 35,200, 41,200, + 53,200, 64,228,226,108,128, 32, 23,237,239,238,239,243,240,225, + 227,101,128,255, 63,246,229,242,244,233,227,225,108,128,254, 51, + 247,225,246,121,128,254, 79,105, 2,200, 77,200, 82,239,110,128, + 34, 42,246,229,242,243,225,108,128, 34, 0,239,231,239,238,229, + 107,128, 1,115,112, 5,200,112,200,119,200,127,200,142,200,193, + 225,242,229,110,128, 36,176,226,236,239,227,107,128, 37,128,240, + 229,242,228,239,244,232,229,226,242,229,119,128, 5,196,243,233, + 236,239,110,131, 3,197,200,156,200,177,200,185,228,233,229,242, + 229,243,233,115,129, 3,203,200,169,244,239,238,239,115,128, 3, + 176,236,225,244,233,110,128, 2,138,244,239,238,239,115,128, 3, + 205,244,225,227,107, 2,200,202,200,213,226,229,236,239,247,227, + 237, 98,128, 3, 29,237,239,100,128, 2,212,114, 2,200,225,200, + 237,225,231,245,242,237,245,235,232,105,128, 10,115,233,238,103, + 128, 1,111,115, 3,200,251,201, 10,201, 55,232,239,242,244,227, + 249,242,233,236,236,233, 99,128, 4, 94,237,225,236,108, 2,201, + 19,201, 30,232,233,242,225,231,225,238, 97,128, 48, 69,235,225, + 244,225,235,225,238, 97,129, 48,165,201, 43,232,225,236,230,247, + 233,228,244,104,128,255,105,244,242,225,233,231,232,116, 2,201, + 67,201, 78,227,249,242,233,236,236,233, 99,128, 4,175,243,244, + 242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,177,244, + 233,236,228,101,130, 1,105,201,107,201,115,225,227,245,244,101, + 128, 30,121,226,229,236,239,119,128, 30,117,117, 5,201,135,201, + 145,201,152,201,177,201,193,226,229,238,231,225,236,105,128, 9, + 138,228,229,246, 97,128, 9, 10,231,117, 2,201,159,201,168,234, + 225,242,225,244,105,128, 10,138,242,237,245,235,232,105,128, 10, + 10,237,225,244,242,225,231,245,242,237,245,235,232,105,128, 10, + 66,246,239,247,229,236,243,233,231,110, 3,201,209,201,219,201, + 226,226,229,238,231,225,236,105,128, 9,194,228,229,246, 97,128, + 9, 66,231,245,234,225,242,225,244,105,128, 10,194,246,239,247, + 229,236,243,233,231,110, 3,201,253,202, 7,202, 14,226,229,238, + 231,225,236,105,128, 9,193,228,229,246, 97,128, 9, 65,231,245, + 234,225,242,225,244,105,128, 10,193,118,139, 0,118,202, 51,202, + 199,202,208,202,219,203,148,203,155,203,253,204, 9,204,109,204, + 117,204,138, 97, 4,202, 61,202, 68,202, 93,202,104,228,229,246, + 97,128, 9, 53,231,117, 2,202, 75,202, 84,234,225,242,225,244, + 105,128, 10,181,242,237,245,235,232,105,128, 10, 53,235,225,244, + 225,235,225,238, 97,128, 48,247,118,132, 5,213,202,116,202,143, + 202,175,202,187,228,225,231,229,243,104,130,251, 53,202,129,202, + 134,182, 53,128,251, 53,232,229,226,242,229,119,128,251, 53,104, + 2,202,149,202,157,229,226,242,229,119,128, 5,213,239,236,225, + 109,129,251, 75,202,166,232,229,226,242,229,119,128,251, 75,246, + 225,246,232,229,226,242,229,119,128, 5,240,249,239,228,232,229, + 226,242,229,119,128, 5,241,227,233,242,227,236,101,128, 36,229, + 228,239,244,226,229,236,239,119,128, 30,127,101, 6,202,233,202, + 244,203, 52,203, 63,203, 69,203,136,227,249,242,233,236,236,233, + 99,128, 4, 50,104, 4,202,254,203, 7,203, 21,203, 37,225,242, + 225,226,233, 99,128, 6,164,230,233,238,225,236,225,242,225,226, + 233, 99,128,251,107,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,251,108,237,229,228,233,225,236,225,242,225,226,233, + 99,128,251,109,235,225,244,225,235,225,238, 97,128, 48,249,238, + 245,115,128, 38, 64,242,244,233,227,225,108, 2,203, 80,203, 86, + 226,225,114,128, 0,124,236,233,238,101, 4,203, 99,203,110,203, + 121,203,130,225,226,239,246,229,227,237, 98,128, 3, 13,226,229, + 236,239,247,227,237, 98,128, 3, 41,236,239,247,237,239,100,128, + 2,204,237,239,100,128, 2,200,247,225,242,237,229,238,233,225, + 110,128, 5,126,232,239,239,107,128, 2,139,105, 3,203,163,203, + 174,203,213,235,225,244,225,235,225,238, 97,128, 48,248,242,225, + 237, 97, 3,203,185,203,195,203,202,226,229,238,231,225,236,105, + 128, 9,205,228,229,246, 97,128, 9, 77,231,245,234,225,242,225, + 244,105,128, 10,205,243,225,242,231, 97, 3,203,225,203,235,203, + 242,226,229,238,231,225,236,105,128, 9,131,228,229,246, 97,128, + 9, 3,231,245,234,225,242,225,244,105,128, 10,131,237,239,238, + 239,243,240,225,227,101,128,255, 86,111, 3,204, 17,204, 28,204, + 98,225,242,237,229,238,233,225,110,128, 5,120,233,227,229,100, + 2,204, 37,204, 73,233,244,229,242,225,244,233,239,110, 2,204, + 51,204, 62,232,233,242,225,231,225,238, 97,128, 48,158,235,225, + 244,225,235,225,238, 97,128, 48,254,237,225,242,235,235,225,238, + 97,129, 48,155,204, 86,232,225,236,230,247,233,228,244,104,128, + 255,158,235,225,244,225,235,225,238, 97,128, 48,250,240,225,242, + 229,110,128, 36,177,116, 2,204,123,204,130,233,236,228,101,128, + 30,125,245,242,238,229,100,128, 2,140,117, 2,204,144,204,155, + 232,233,242,225,231,225,238, 97,128, 48,148,235,225,244,225,235, + 225,238, 97,128, 48,244,119,143, 0,119,204,200,205,177,205,187, + 205,210,205,250,206, 61,206, 69,208, 40,208, 81,208, 93,208,168, + 208,176,208,183,208,194,208,203, 97, 8,204,218,204,225,204,235, + 204,246,205, 28,205, 60,205, 72,205,108,227,245,244,101,128, 30, + 131,229,235,239,242,229,225,110,128, 49, 89,232,233,242,225,231, + 225,238, 97,128, 48,143,107, 2,204,252,205, 20,225,244,225,235, + 225,238, 97,129, 48,239,205, 8,232,225,236,230,247,233,228,244, + 104,128,255,156,239,242,229,225,110,128, 49, 88,243,237,225,236, + 108, 2,205, 38,205, 49,232,233,242,225,231,225,238, 97,128, 48, + 142,235,225,244,225,235,225,238, 97,128, 48,238,244,244,239,243, + 241,245,225,242,101,128, 51, 87,118, 2,205, 78,205, 86,229,228, + 225,243,104,128, 48, 28,249,245,238,228,229,242,243,227,239,242, + 229,246,229,242,244,233,227,225,108,128,254, 52,119, 3,205,116, + 205,125,205,139,225,242,225,226,233, 99,128, 6, 72,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,238,232,225,237,250,225, + 225,226,239,246,101, 2,205,154,205,163,225,242,225,226,233, 99, + 128, 6, 36,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 134,226,243,241,245,225,242,101,128, 51,221,227,233,242, 99, 2, + 205,196,205,201,236,101,128, 36,230,245,237,230,236,229,120,128, + 1,117,100, 2,205,216,205,226,233,229,242,229,243,233,115,128, + 30,133,239,116, 2,205,233,205,242,225,227,227,229,238,116,128, + 30,135,226,229,236,239,119,128, 30,137,101, 4,206, 4,206, 15, + 206, 27,206, 51,232,233,242,225,231,225,238, 97,128, 48,145,233, + 229,242,243,244,242,225,243,115,128, 33, 24,107, 2,206, 33,206, + 43,225,244,225,235,225,238, 97,128, 48,241,239,242,229,225,110, + 128, 49, 94,239,235,239,242,229,225,110,128, 49, 93,231,242,225, + 246,101,128, 30,129,232,233,244,101, 8,206, 90,206, 99,206,183, + 207, 17,207,101,207,146,207,198,207,254,226,245,236,236,229,116, + 128, 37,230, 99, 2,206,105,206,125,233,242,227,236,101,129, 37, + 203,206,115,233,238,246,229,242,243,101,128, 37,217,239,242,238, + 229,242,226,242,225,227,235,229,116, 2,206,142,206,162,236,229, + 230,116,129, 48, 14,206,151,246,229,242,244,233,227,225,108,128, + 254, 67,242,233,231,232,116,129, 48, 15,206,172,246,229,242,244, + 233,227,225,108,128,254, 68,100, 2,206,189,206,230,233,225,237, + 239,238,100,129, 37,199,206,200,227,239,238,244,225,233,238,233, + 238,231,226,236,225,227,235,243,237,225,236,236,228,233,225,237, + 239,238,100,128, 37,200,239,247,238,240,239,233,238,244,233,238, + 103, 2,206,246,207, 6,243,237,225,236,236,244,242,233,225,238, + 231,236,101,128, 37,191,244,242,233,225,238,231,236,101,128, 37, + 189,236,101, 2,207, 24,207, 66,230,244,240,239,233,238,244,233, + 238,103, 2,207, 39,207, 55,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,195,244,242,233,225,238,231,236,101,128, + 37,193,238,244,233,227,245,236,225,242,226,242,225,227,235,229, + 116, 2,207, 86,207, 93,236,229,230,116,128, 48, 22,242,233,231, + 232,116,128, 48, 23,242,233,231,232,244,240,239,233,238,244,233, + 238,103, 2,207,119,207,135,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,185,244,242,233,225,238,231,236,101,128, + 37,183,115, 3,207,154,207,184,207,192,109, 2,207,160,207,172, + 225,236,236,243,241,245,225,242,101,128, 37,171,233,236,233,238, + 231,230,225,227,101,128, 38, 58,241,245,225,242,101,128, 37,161, + 244,225,114,128, 38, 6,116, 2,207,204,207,215,229,236,229,240, + 232,239,238,101,128, 38, 15,239,242,244,239,233,243,229,243,232, + 229,236,236,226,242,225,227,235,229,116, 2,207,239,207,246,236, + 229,230,116,128, 48, 24,242,233,231,232,116,128, 48, 25,245,240, + 240,239,233,238,244,233,238,103, 2,208, 13,208, 29,243,237,225, + 236,236,244,242,233,225,238,231,236,101,128, 37,181,244,242,233, + 225,238,231,236,101,128, 37,179,105, 2,208, 46,208, 57,232,233, + 242,225,231,225,238, 97,128, 48,144,107, 2,208, 63,208, 73,225, + 244,225,235,225,238, 97,128, 48,240,239,242,229,225,110,128, 49, + 95,237,239,238,239,243,240,225,227,101,128,255, 87,111, 4,208, + 103,208,114,208,139,208,157,232,233,242,225,231,225,238, 97,128, + 48,146,235,225,244,225,235,225,238, 97,129, 48,242,208,127,232, + 225,236,230,247,233,228,244,104,128,255,102,110,129, 32,169,208, + 145,237,239,238,239,243,240,225,227,101,128,255,230,247,225,229, + 238,244,232,225,105,128, 14, 39,240,225,242,229,110,128, 36,178, + 242,233,238,103,128, 30,152,243,245,240,229,242,233,239,114,128, + 2,183,244,245,242,238,229,100,128, 2,141,249,238,110,128, 1, + 191,120,137, 0,120,208,231,208,242,208,253,209, 6,209, 33,209, + 46,209, 50,209, 62,209, 70,225,226,239,246,229,227,237, 98,128, + 3, 61,226,239,240,239,237,239,230,111,128, 49, 18,227,233,242, + 227,236,101,128, 36,231,100, 2,209, 12,209, 22,233,229,242,229, + 243,233,115,128, 30,141,239,244,225,227,227,229,238,116,128, 30, + 139,229,232,225,242,237,229,238,233,225,110,128, 5,109,105,128, + 3,190,237,239,238,239,243,240,225,227,101,128,255, 88,240,225, + 242,229,110,128, 36,179,243,245,240,229,242,233,239,114,128, 2, + 227,121,143, 0,121,209,115,210, 74,210, 97,210,137,212,103,212, + 111,212,128,212,192,212,204,213,201,213,241,213,253,214, 8,214, + 29,215, 2, 97, 11,209,139,209,151,209,161,209,168,209,175,209, + 185,209,210,209,221,210, 3,210, 16,210, 62,225,228,239,243,241, + 245,225,242,101,128, 51, 78,226,229,238,231,225,236,105,128, 9, + 175,227,245,244,101,128, 0,253,228,229,246, 97,128, 9, 47,229, + 235,239,242,229,225,110,128, 49, 82,231,117, 2,209,192,209,201, + 234,225,242,225,244,105,128, 10,175,242,237,245,235,232,105,128, + 10, 47,232,233,242,225,231,225,238, 97,128, 48,132,107, 2,209, + 227,209,251,225,244,225,235,225,238, 97,129, 48,228,209,239,232, + 225,236,230,247,233,228,244,104,128,255,148,239,242,229,225,110, + 128, 49, 81,237,225,235,235,225,238,244,232,225,105,128, 14, 78, + 243,237,225,236,108, 2,210, 26,210, 37,232,233,242,225,231,225, + 238, 97,128, 48,131,235,225,244,225,235,225,238, 97,129, 48,227, + 210, 50,232,225,236,230,247,233,228,244,104,128,255,108,244,227, + 249,242,233,236,236,233, 99,128, 4, 99,227,233,242, 99, 2,210, + 83,210, 88,236,101,128, 36,232,245,237,230,236,229,120,128, 1, + 119,100, 2,210,103,210,113,233,229,242,229,243,233,115,128, 0, + 255,239,116, 2,210,120,210,129,225,227,227,229,238,116,128, 30, + 143,226,229,236,239,119,128, 30,245,101, 7,210,153,211,161,211, + 170,211,188,211,220,212, 40,212, 91,104, 8,210,171,210,180,210, + 214,210,228,211, 45,211, 61,211,120,211,138,225,242,225,226,233, + 99,128, 6, 74,226,225,242,242,229,101, 2,210,191,210,200,225, + 242,225,226,233, 99,128, 6,210,230,233,238,225,236,225,242,225, + 226,233, 99,128,251,175,230,233,238,225,236,225,242,225,226,233, + 99,128,254,242,232,225,237,250,225,225,226,239,246,101, 4,210, + 247,211, 0,211, 14,211, 30,225,242,225,226,233, 99,128, 6, 38, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,138,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,139,237,229, + 228,233,225,236,225,242,225,226,233, 99,128,254,140,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,243,237,101, 2, + 211, 68,211, 81,228,233,225,236,225,242,225,226,233, 99,128,254, + 244,229,237,105, 2,211, 89,211,104,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,221,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,252, 88,238,239,239,238,230,233,238,225, + 236,225,242,225,226,233, 99,128,252,148,244,232,242,229,229,228, + 239,244,243,226,229,236,239,247,225,242,225,226,233, 99,128, 6, + 209,235,239,242,229,225,110,128, 49, 86,110,129, 0,165,211,176, + 237,239,238,239,243,240,225,227,101,128,255,229,111, 2,211,194, + 211,203,235,239,242,229,225,110,128, 49, 85,242,233,238,232,233, + 229,245,232,235,239,242,229,225,110,128, 49,134,114, 3,211,228, + 212, 8,212, 20,225,232,226,229,238,249,239,237,111, 2,211,242, + 211,251,232,229,226,242,229,119,128, 5,170,236,229,230,244,232, + 229,226,242,229,119,128, 5,170,233,227,249,242,233,236,236,233, + 99,128, 4, 75,245,228,233,229,242,229,243,233,243,227,249,242, + 233,236,236,233, 99,128, 4,249,243,233,229,245,238,103, 3,212, + 53,212, 62,212, 78,235,239,242,229,225,110,128, 49,129,240,225, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,131,243,233, + 239,243,235,239,242,229,225,110,128, 49,130,244,233,246,232,229, + 226,242,229,119,128, 5,154,231,242,225,246,101,128, 30,243,232, + 239,239,107,129, 1,180,212,120,225,226,239,246,101,128, 30,247, + 105, 5,212,140,212,151,212,162,212,171,212,179,225,242,237,229, + 238,233,225,110,128, 5,117,227,249,242,233,236,236,233, 99,128, + 4, 87,235,239,242,229,225,110,128, 49, 98,238,249,225,238,103, + 128, 38, 47,247,238,225,242,237,229,238,233,225,110,128, 5,130, + 237,239,238,239,243,240,225,227,101,128,255, 89,111, 7,212,220, + 213, 34,213, 45,213, 55,213, 93,213,139,213,148,100,131, 5,217, + 212,230,212,250,213, 3,228,225,231,229,243,104,129,251, 57,212, + 241,232,229,226,242,229,119,128,251, 57,232,229,226,242,229,119, + 128, 5,217,249,239,100, 2,213, 11,213, 20,232,229,226,242,229, + 119,128, 5,242,240,225,244,225,232,232,229,226,242,229,119,128, + 251, 31,232,233,242,225,231,225,238, 97,128, 48,136,233,235,239, + 242,229,225,110,128, 49,137,107, 2,213, 61,213, 85,225,244,225, + 235,225,238, 97,129, 48,232,213, 73,232,225,236,230,247,233,228, + 244,104,128,255,150,239,242,229,225,110,128, 49, 91,243,237,225, + 236,108, 2,213,103,213,114,232,233,242,225,231,225,238, 97,128, + 48,135,235,225,244,225,235,225,238, 97,129, 48,231,213,127,232, + 225,236,230,247,233,228,244,104,128,255,110,244,231,242,229,229, + 107,128, 3,243,121, 2,213,154,213,191, 97, 2,213,160,213,170, + 229,235,239,242,229,225,110,128, 49,136,107, 2,213,176,213,184, + 239,242,229,225,110,128, 49,135,244,232,225,105,128, 14, 34,233, + 238,231,244,232,225,105,128, 14, 13,112, 2,213,207,213,214,225, + 242,229,110,128, 36,180,239,231,229,231,242,225,237,237,229,238, + 105,129, 3,122,213,230,231,242,229,229,235,227,237, 98,128, 3, + 69,114,129, 1,166,213,247,233,238,103,128, 30,153,243,245,240, + 229,242,233,239,114,128, 2,184,116, 2,214, 14,214, 21,233,236, + 228,101,128, 30,249,245,242,238,229,100,128, 2,142,117, 5,214, + 41,214, 52,214, 62,214,100,214,232,232,233,242,225,231,225,238, + 97,128, 48,134,233,235,239,242,229,225,110,128, 49,140,107, 2, + 214, 68,214, 92,225,244,225,235,225,238, 97,129, 48,230,214, 80, + 232,225,236,230,247,233,228,244,104,128,255,149,239,242,229,225, + 110,128, 49, 96,115, 3,214,108,214,146,214,187,226,233,103, 2, + 214,116,214,127,227,249,242,233,236,236,233, 99,128, 4,107,233, + 239,244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, + 4,109,236,233,244,244,236,101, 2,214,157,214,168,227,249,242, + 233,236,236,233, 99,128, 4,103,233,239,244,233,230,233,229,228, + 227,249,242,233,236,236,233, 99,128, 4,105,237,225,236,108, 2, + 214,196,214,207,232,233,242,225,231,225,238, 97,128, 48,133,235, + 225,244,225,235,225,238, 97,129, 48,229,214,220,232,225,236,230, + 247,233,228,244,104,128,255,109,249,101, 2,214,239,214,248,235, + 239,242,229,225,110,128, 49,139,239,235,239,242,229,225,110,128, + 49,138,249, 97, 2,215, 9,215, 19,226,229,238,231,225,236,105, + 128, 9,223,228,229,246, 97,128, 9, 95,122,142, 0,122,215, 58, + 216, 66,216, 77,216,120,216,147,217,182,218, 34,218, 76,218, 88, + 218,100,218,128,218,136,218,152,218,161, 97, 10,215, 80,215, 91, + 215, 98,215,105,215,116,215,194,215,224,215,235,216, 15,216, 27, + 225,242,237,229,238,233,225,110,128, 5,102,227,245,244,101,128, + 1,122,228,229,246, 97,128, 9, 91,231,245,242,237,245,235,232, + 105,128, 10, 91,104, 4,215,126,215,135,215,149,215,179,225,242, + 225,226,233, 99,128, 6, 56,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,198,105, 2,215,155,215,170,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,199,242,225,231,225,238, 97, + 128, 48, 86,237,229,228,233,225,236,225,242,225,226,233, 99,128, + 254,200,233,110, 2,215,201,215,210,225,242,225,226,233, 99,128, + 6, 50,230,233,238,225,236,225,242,225,226,233, 99,128,254,176, + 235,225,244,225,235,225,238, 97,128, 48,182,241,229,102, 2,215, + 243,216, 1,231,225,228,239,236,232,229,226,242,229,119,128, 5, + 149,241,225,244,225,238,232,229,226,242,229,119,128, 5,148,242, + 241,225,232,229,226,242,229,119,128, 5,152,249,233,110,130, 5, + 214,216, 37,216, 57,228,225,231,229,243,104,129,251, 54,216, 48, + 232,229,226,242,229,119,128,251, 54,232,229,226,242,229,119,128, + 5,214,226,239,240,239,237,239,230,111,128, 49, 23, 99, 3,216, + 85,216, 92,216,114,225,242,239,110,128, 1,126,233,242, 99, 2, + 216,100,216,105,236,101,128, 36,233,245,237,230,236,229,120,128, + 30,145,245,242,108,128, 2,145,228,239,116,130, 1,124,216,130, + 216,139,225,227,227,229,238,116,128, 1,124,226,229,236,239,119, + 128, 30,147,101, 6,216,161,216,172,216,215,216,226,216,237,217, + 177,227,249,242,233,236,236,233, 99,128, 4, 55,100, 2,216,178, + 216,197,229,243,227,229,238,228,229,242,227,249,242,233,236,236, + 233, 99,128, 4,153,233,229,242,229,243,233,243,227,249,242,233, + 236,236,233, 99,128, 4,223,232,233,242,225,231,225,238, 97,128, + 48, 92,235,225,244,225,235,225,238, 97,128, 48,188,242,111,140, + 0, 48,217, 10,217, 19,217, 29,217, 36,217, 61,217, 74,217, 85, + 217, 97,217,108,217,118,217,129,217,136,225,242,225,226,233, 99, + 128, 6, 96,226,229,238,231,225,236,105,128, 9,230,228,229,246, + 97,128, 9,102,231,117, 2,217, 43,217, 52,234,225,242,225,244, + 105,128, 10,230,242,237,245,235,232,105,128, 10,102,232,225,227, + 235,225,242,225,226,233, 99,128, 6, 96,233,238,230,229,242,233, + 239,114,128, 32,128,237,239,238,239,243,240,225,227,101,128,255, + 16,239,236,228,243,244,249,236,101,128,247, 48,240,229,242,243, + 233,225,110,128, 6,240,243,245,240,229,242,233,239,114,128, 32, + 112,244,232,225,105,128, 14, 80,247,233,228,244,104, 3,217,148, + 217,157,217,169,234,239,233,238,229,114,128,254,255,238,239,238, + 234,239,233,238,229,114,128, 32, 12,243,240,225,227,101,128, 32, + 11,244, 97,128, 3,182,104, 2,217,188,217,199,226,239,240,239, + 237,239,230,111,128, 49, 19,101, 4,217,209,217,220,217,236,217, + 247,225,242,237,229,238,233,225,110,128, 5,106,226,242,229,246, + 229,227,249,242,233,236,236,233, 99,128, 4,194,227,249,242,233, + 236,236,233, 99,128, 4, 54,100, 2,217,253,218, 16,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,151, + 233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, + 4,221,105, 3,218, 42,218, 53,218, 64,232,233,242,225,231,225, + 238, 97,128, 48, 88,235,225,244,225,235,225,238, 97,128, 48,184, + 238,239,242,232,229,226,242,229,119,128, 5,174,236,233,238,229, + 226,229,236,239,119,128, 30,149,237,239,238,239,243,240,225,227, + 101,128,255, 90,111, 2,218,106,218,117,232,233,242,225,231,225, + 238, 97,128, 48, 94,235,225,244,225,235,225,238, 97,128, 48,190, + 240,225,242,229,110,128, 36,181,242,229,244,242,239,230,236,229, + 248,232,239,239,107,128, 2,144,243,244,242,239,235,101,128, 1, + 182,117, 2,218,167,218,178,232,233,242,225,231,225,238, 97,128, + 48, 90,235,225,244,225,235,225,238, 97,128, 48,186 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + +#ifdef DEFINE_PS_TABLES + /* + * This function searches the compressed table efficiently. + */ + static unsigned long + ft_get_adobe_glyph_index( const char* name, + const char* limit ) + { + int c = 0; + int count, min, max; + const unsigned char* p = ft_adobe_glyph_list; + + + if ( name == 0 || name >= limit ) + goto NotFound; + + c = *name++; + count = p[1]; + p += 2; + + min = 0; + max = count; + + while ( min < max ) + { + int mid = ( min + max ) >> 1; + const unsigned char* q = p + mid * 2; + int c2; + + + q = ft_adobe_glyph_list + ( ( (int)q[0] << 8 ) | q[1] ); + + c2 = q[0] & 127; + if ( c2 == c ) + { + p = q; + goto Found; + } + if ( c2 < c ) + min = mid + 1; + else + max = mid; + } + goto NotFound; + + Found: + for (;;) + { + /* assert (*p & 127) == c */ + + if ( name >= limit ) + { + if ( (p[0] & 128) == 0 && + (p[1] & 128) != 0 ) + return (unsigned long)( ( (int)p[2] << 8 ) | p[3] ); + + goto NotFound; + } + c = *name++; + if ( p[0] & 128 ) + { + p++; + if ( c != (p[0] & 127) ) + goto NotFound; + + continue; + } + + p++; + count = p[0] & 127; + if ( p[0] & 128 ) + p += 2; + + p++; + + for ( ; count > 0; count--, p += 2 ) + { + int offset = ( (int)p[0] << 8 ) | p[1]; + const unsigned char* q = ft_adobe_glyph_list + offset; + + if ( c == ( q[0] & 127 ) ) + { + p = q; + goto NextIter; + } + } + goto NotFound; + + NextIter: + ; + } + + NotFound: + return 0; + } +#endif /* DEFINE_PS_TABLES */ + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + +/* END */ diff --git a/vendor/freetype/src/psnames/rules.mk b/vendor/freetype/src/psnames/rules.mk new file mode 100644 index 0000000..8d7c580 --- /dev/null +++ b/vendor/freetype/src/psnames/rules.mk @@ -0,0 +1,73 @@ +# +# FreeType 2 psnames driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# psnames driver directory +# +PSNAMES_DIR := $(SRC_DIR)/psnames + + +# compilation flags for the driver +# +PSNAMES_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(PSNAMES_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# psnames driver sources (i.e., C files) +# +PSNAMES_DRV_SRC := $(PSNAMES_DIR)/psmodule.c + + +# psnames driver headers +# +PSNAMES_DRV_H := $(PSNAMES_DRV_SRC:%.c=%.h) \ + $(PSNAMES_DIR)/psnamerr.h \ + $(PSNAMES_DIR)/pstables.h + + +# psnames driver object(s) +# +# PSNAMES_DRV_OBJ_M is used during `multi' builds +# PSNAMES_DRV_OBJ_S is used during `single' builds +# +PSNAMES_DRV_OBJ_M := $(PSNAMES_DRV_SRC:$(PSNAMES_DIR)/%.c=$(OBJ_DIR)/%.$O) +PSNAMES_DRV_OBJ_S := $(OBJ_DIR)/psnames.$O + +# psnames driver source file for single build +# +PSNAMES_DRV_SRC_S := $(PSNAMES_DIR)/psnames.c + + +# psnames driver - single object +# +$(PSNAMES_DRV_OBJ_S): $(PSNAMES_DRV_SRC_S) $(PSNAMES_DRV_SRC) \ + $(FREETYPE_H) $(PSNAMES_DRV_H) + $(PSNAMES_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(PSNAMES_DRV_SRC_S)) + + +# psnames driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(PSNAMES_DIR)/%.c $(FREETYPE_H) $(PSNAMES_DRV_H) + $(PSNAMES_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(PSNAMES_DRV_OBJ_S) +DRV_OBJS_M += $(PSNAMES_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/raster/ftmisc.h b/vendor/freetype/src/raster/ftmisc.h new file mode 100644 index 0000000..33dbfd6 --- /dev/null +++ b/vendor/freetype/src/raster/ftmisc.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * + * ftmisc.h + * + * Miscellaneous macros for stand-alone rasterizer (specification + * only). + * + * Copyright (C) 2005-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /**************************************************** + * + * This file is *not* portable! You have to adapt + * its definitions to your platform. + * + */ + +#ifndef FTMISC_H_ +#define FTMISC_H_ + + + /* memset */ +#include FT_CONFIG_STANDARD_LIBRARY_H + +#define FT_BEGIN_HEADER +#define FT_END_HEADER + +#define FT_LOCAL_DEF( x ) static x + + + /* from include/freetype/fttypes.h */ + + typedef unsigned char FT_Byte; + typedef signed int FT_Int; + typedef unsigned int FT_UInt; + typedef signed long FT_Long; + typedef unsigned long FT_ULong; + typedef signed long FT_F26Dot6; + typedef int FT_Error; + + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(FT_Byte)(var) + + + /* from include/freetype/ftsystem.h */ + + typedef struct FT_MemoryRec_* FT_Memory; + + typedef void* (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + typedef void (*FT_Free_Func)( FT_Memory memory, + void* block ); + + typedef void* (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + typedef struct FT_MemoryRec_ + { + void* user; + + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + + } FT_MemoryRec; + + + /* from src/ftcalc.c */ + +#if ( defined _WIN32 || defined _WIN64 ) + + typedef __int64 FT_Int64; + +#else + +#include "inttypes.h" + + typedef int64_t FT_Int64; + +#endif + + + static FT_Long + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + + + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + + d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFL ); + + return ( s > 0 ) ? d : -d; + } + + + static FT_Long + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + + + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + + d = (FT_Long)( c > 0 ? (FT_Int64)a * b / c + : 0x7FFFFFFFL ); + + return ( s > 0 ) ? d : -d; + } + +#endif /* FTMISC_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/raster/ftraster.c b/vendor/freetype/src/raster/ftraster.c new file mode 100644 index 0000000..192ca07 --- /dev/null +++ b/vendor/freetype/src/raster/ftraster.c @@ -0,0 +1,3294 @@ +/**************************************************************************** + * + * ftraster.c + * + * The FreeType glyph rasterizer (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file can be compiled without the rest of the FreeType engine, by + * defining the STANDALONE_ macro when compiling it. You also need to + * put the files `ftimage.h' and `ftmisc.h' into the $(incdir) + * directory. Typically, you should do something like + * + * - copy `src/raster/ftraster.c' (this file) to your current directory + * + * - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' to your + * current directory + * + * - compile `ftraster' with the STANDALONE_ macro defined, as in + * + * cc -c -DSTANDALONE_ ftraster.c + * + * The renderer can be initialized with a call to + * `ft_standard_raster.raster_new'; a bitmap can be generated + * with a call to `ft_standard_raster.raster_render'. + * + * See the comments and documentation in the file `ftimage.h' for more + * details on how the raster works. + * + */ + + + /************************************************************************** + * + * This is a rewrite of the FreeType 1.x scan-line converter + * + */ + +#ifdef STANDALONE_ + + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ +#define FT_RENDER_POOL_SIZE 16384L + +#define FT_CONFIG_STANDARD_LIBRARY_H + +#include /* for memset */ + +#include "ftmisc.h" +#include "ftimage.h" + +#else /* !STANDALONE_ */ + +#include "ftraster.h" +#include /* for FT_MulDiv and FT_MulDiv_No_Round */ +#include /* for FT_Outline_Get_CBox */ + +#endif /* !STANDALONE_ */ + + + /************************************************************************** + * + * A simple technical note on how the raster works + * ----------------------------------------------- + * + * Converting an outline into a bitmap is achieved in several steps: + * + * 1 - Decomposing the outline into successive `profiles'. Each + * profile is simply an array of scanline intersections on a given + * dimension. A profile's main attributes are + * + * o its scanline position boundaries, i.e. `Ymin' and `Ymax' + * + * o an array of intersection coordinates for each scanline + * between `Ymin' and `Ymax' + * + * o a direction, indicating whether it was built going `up' or + * `down', as this is very important for filling rules + * + * o its drop-out mode + * + * 2 - Sweeping the target map's scanlines in order to compute segment + * `spans' which are then filled. Additionally, this pass + * performs drop-out control. + * + * The outline data is parsed during step 1 only. The profiles are + * built from the bottom of the render pool, used as a stack. The + * following graphics shows the profile list under construction: + * + * __________________________________________________________ _ _ + * | | | | | + * | profile | coordinates for | profile | coordinates for |--> + * | 1 | profile 1 | 2 | profile 2 |--> + * |_________|_________________|_________|_________________|__ _ _ + * + * ^ ^ + * | | + * start of render pool top + * + * The top of the profile stack is kept in the `top' variable. + * + * As you can see, a profile record is pushed on top of the render + * pool, which is then followed by its coordinates/intersections. If + * a change of direction is detected in the outline, a new profile is + * generated until the end of the outline. + * + * Note that when all profiles have been generated, the function + * Finalize_Profile_Table() is used to record, for each profile, its + * bottom-most scanline as well as the scanline above its upmost + * boundary. These positions are called `y-turns' because they (sort + * of) correspond to local extrema. They are stored in a sorted list + * built from the top of the render pool as a downwards stack: + * + * _ _ _______________________________________ + * | | + * <--| sorted list of | + * <--| extrema scanlines | + * _ _ __________________|____________________| + * + * ^ ^ + * | | + * maxBuff sizeBuff = end of pool + * + * This list is later used during the sweep phase in order to + * optimize performance (see technical note on the sweep below). + * + * Of course, the raster detects whether the two stacks collide and + * handles the situation properly. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** CONFIGURATION MACROS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** OTHER MACROS (do not change) **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT raster + + +#ifdef STANDALONE_ + + /* Auxiliary macros for token concatenation. */ +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + /* Disable the tracing mechanism for simplicity -- developers can */ + /* activate it easily by redefining these macros. */ +#ifndef FT_ERROR +#define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ +#endif + +#ifndef FT_TRACE +#define FT_TRACE( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE1( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE6( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ +#endif + +#ifndef FT_THROW +#define FT_THROW( e ) FT_ERR_CAT( Raster_Err_, e ) +#endif + +#define Raster_Err_Ok 0 +#define Raster_Err_Invalid_Outline -1 +#define Raster_Err_Cannot_Render_Glyph -2 +#define Raster_Err_Invalid_Argument -3 +#define Raster_Err_Raster_Overflow -4 +#define Raster_Err_Raster_Uninitialized -5 +#define Raster_Err_Raster_Negative_Height -6 + +#define ft_memset memset + +#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \ + raster_reset_, raster_set_mode_, \ + raster_render_, raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; + +#else /* !STANDALONE_ */ + + +#include +#include /* for FT_TRACE, FT_ERROR, and FT_THROW */ + +#include "rasterrs.h" + + +#endif /* !STANDALONE_ */ + + +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif + +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif + +#ifndef FT_ZERO +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) +#endif + + /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ + /* typically a small value and the result of a*b is known to fit into */ + /* 32 bits. */ +#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) + + /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ + /* for clipping computations. It simply uses the FT_MulDiv() function */ + /* defined in `ftcalc.h'. */ +#define SMulDiv FT_MulDiv +#define SMulDiv_No_Round FT_MulDiv_No_Round + + /* The rasterizer is a very general purpose component; please leave */ + /* the following redefinitions there (you never know your target */ + /* environment). */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + +#ifndef SUCCESS +#define SUCCESS 0 +#endif + +#ifndef FAILURE +#define FAILURE 1 +#endif + + +#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ + /* Setting this constant to more than 32 is a */ + /* pure waste of space. */ + +#define Pixel_Bits 6 /* fractional bits of *input* coordinates */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SIMPLE TYPE DECLARATIONS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + typedef int Int; + typedef unsigned int UInt; + typedef short Short; + typedef unsigned short UShort, *PUShort; + typedef long Long, *PLong; + typedef unsigned long ULong; + + typedef unsigned char Byte, *PByte; + typedef char Bool; + + + typedef union Alignment_ + { + Long l; + void* p; + void (*f)(void); + + } Alignment, *PAlignment; + + + typedef struct TPoint_ + { + Long x; + Long y; + + } TPoint; + + + /* values for the `flags' bit field */ +#define Flow_Up 0x08U +#define Overshoot_Top 0x10U +#define Overshoot_Bottom 0x20U + + + /* States of each line, arc, and profile */ + typedef enum TStates_ + { + Unknown_State, + Ascending_State, + Descending_State, + Flat_State + + } TStates; + + + typedef struct TProfile_ TProfile; + typedef TProfile* PProfile; + + struct TProfile_ + { + FT_F26Dot6 X; /* current coordinate during sweep */ + PProfile link; /* link to next profile (various purposes) */ + PLong offset; /* start of profile's data in render pool */ + UShort flags; /* Bit 0-2: drop-out mode */ + /* Bit 3: profile orientation (up/down) */ + /* Bit 4: is top profile? */ + /* Bit 5: is bottom profile? */ + Long height; /* profile's height in scanlines */ + Long start; /* profile's starting scanline */ + + Int countL; /* number of lines to step before this */ + /* profile becomes drawable */ + + PProfile next; /* next profile in same contour, used */ + /* during drop-out control */ + }; + + typedef PProfile TProfileList; + typedef PProfile* PProfileList; + + +#define AlignProfileSize \ + ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( Long ) ) + + +#undef RAS_ARG +#undef RAS_ARGS +#undef RAS_VAR +#undef RAS_VARS + +#ifdef FT_STATIC_RASTER + + +#define RAS_ARGS /* void */ +#define RAS_ARG void + +#define RAS_VARS /* void */ +#define RAS_VAR /* void */ + +#define FT_UNUSED_RASTER do { } while ( 0 ) + + +#else /* !FT_STATIC_RASTER */ + + +#define RAS_ARGS black_PWorker worker, +#define RAS_ARG black_PWorker worker + +#define RAS_VARS worker, +#define RAS_VAR worker + +#define FT_UNUSED_RASTER FT_UNUSED( worker ) + + +#endif /* !FT_STATIC_RASTER */ + + + typedef struct black_TWorker_ black_TWorker, *black_PWorker; + + + /* prototypes used for sweep function dispatch */ + typedef void + Function_Sweep_Init( RAS_ARGS Short min, + Short max ); + + typedef void + Function_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ); + + typedef void + Function_Sweep_Step( RAS_ARG ); + + + /* NOTE: These operations are only valid on 2's complement processors */ +#undef FLOOR +#undef CEILING +#undef TRUNC +#undef SCALED + +#define FLOOR( x ) ( (x) & -ras.precision ) +#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) +#define TRUNC( x ) ( (Long)(x) >> ras.precision_bits ) +#define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) + + /* scale and shift grid to pixel centers */ +#define SCALED( x ) ( (x) * ras.precision_scale - ras.precision_half ) + +#define IS_BOTTOM_OVERSHOOT( x ) \ + (Bool)( CEILING( x ) - x >= ras.precision_half ) +#define IS_TOP_OVERSHOOT( x ) \ + (Bool)( x - FLOOR( x ) >= ras.precision_half ) + + /* Smart dropout rounding to find which pixel is closer to span ends. */ + /* To mimick Windows, symmetric cases break down indepenently of the */ + /* precision. */ +#define SMART( p, q ) FLOOR( ( (p) + (q) + ras.precision * 63 / 64 ) >> 1 ) + +#if FT_RENDER_POOL_SIZE > 2048 +#define FT_MAX_BLACK_POOL ( FT_RENDER_POOL_SIZE / sizeof ( Long ) ) +#else +#define FT_MAX_BLACK_POOL ( 2048 / sizeof ( Long ) ) +#endif + + /* The most used variables are positioned at the top of the structure. */ + /* Thus, their offset can be coded with less opcodes, resulting in a */ + /* smaller executable. */ + + struct black_TWorker_ + { + Int precision_bits; /* precision related variables */ + Int precision; + Int precision_half; + Int precision_scale; + Int precision_step; + Int precision_jitter; + + PLong buff; /* The profiles buffer */ + PLong sizeBuff; /* Render pool size */ + PLong maxBuff; /* Profiles buffer size */ + PLong top; /* Current cursor in buffer */ + + FT_Error error; + + Int numTurns; /* number of Y-turns in outline */ + + Byte dropOutControl; /* current drop_out control method */ + + UShort bWidth; /* target bitmap width */ + PByte bOrigin; /* target bitmap bottom-left origin */ + PByte bLine; /* target bitmap current line */ + + Long lastX, lastY; + Long minY, maxY; + + UShort num_Profs; /* current number of profiles */ + + Bool fresh; /* signals a fresh new profile which */ + /* `start' field must be completed */ + Bool joint; /* signals that the last arc ended */ + /* exactly on a scanline. Allows */ + /* removal of doublets */ + PProfile cProfile; /* current profile */ + PProfile fProfile; /* head of linked list of profiles */ + PProfile gProfile; /* contour's first profile in case */ + /* of impact */ + + TStates state; /* rendering state */ + + FT_Bitmap target; /* description of target bit/pixmap */ + FT_Outline outline; + + /* dispatch variables */ + + Function_Sweep_Init* Proc_Sweep_Init; + Function_Sweep_Span* Proc_Sweep_Span; + Function_Sweep_Span* Proc_Sweep_Drop; + Function_Sweep_Step* Proc_Sweep_Step; + + }; + + + typedef struct black_TRaster_ + { + void* memory; + + } black_TRaster, *black_PRaster; + +#ifdef FT_STATIC_RASTER + + static black_TWorker ras; + +#else /* !FT_STATIC_RASTER */ + +#define ras (*worker) + +#endif /* !FT_STATIC_RASTER */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** PROFILES COMPUTATION **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * Set_High_Precision + * + * @Description: + * Set precision variables according to param flag. + * + * @Input: + * High :: + * Set to True for high precision (typically for ppem < 24), + * false otherwise. + */ + static void + Set_High_Precision( RAS_ARGS Int High ) + { + /* + * `precision_step' is used in `Bezier_Up' to decide when to split a + * given y-monotonous Bezier arc that crosses a scanline before + * approximating it as a straight segment. The default value of 32 (for + * low accuracy) corresponds to + * + * 32 / 64 == 0.5 pixels, + * + * while for the high accuracy case we have + * + * 256 / (1 << 12) = 0.0625 pixels. + * + * `precision_jitter' is an epsilon threshold used in + * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier + * decomposition (after all, we are working with approximations only); + * it avoids switching on additional pixels which would cause artifacts + * otherwise. + * + * The value of `precision_jitter' has been determined heuristically. + * + */ + + if ( High ) + { + ras.precision_bits = 12; + ras.precision_step = 256; + ras.precision_jitter = 30; + } + else + { + ras.precision_bits = 6; + ras.precision_step = 32; + ras.precision_jitter = 2; + } + + FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); + + ras.precision = 1 << ras.precision_bits; + ras.precision_half = ras.precision >> 1; + ras.precision_scale = ras.precision >> Pixel_Bits; + } + + + /************************************************************************** + * + * @Function: + * New_Profile + * + * @Description: + * Create a new profile in the render pool. + * + * @Input: + * aState :: + * The state/orientation of the new profile. + * + * overshoot :: + * Whether the profile's unrounded start position + * differs by at least a half pixel. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow or of incoherent + * profile. + */ + static Bool + New_Profile( RAS_ARGS TStates aState, + Bool overshoot ) + { + if ( !ras.fProfile ) + { + ras.cProfile = (PProfile)ras.top; + ras.fProfile = ras.cProfile; + ras.top += AlignProfileSize; + } + + if ( ras.top >= ras.maxBuff ) + { + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + ras.cProfile->start = 0; + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + ras.cProfile->link = (PProfile)0; + ras.cProfile->next = (PProfile)0; + ras.cProfile->flags = ras.dropOutControl; + + switch ( aState ) + { + case Ascending_State: + ras.cProfile->flags |= Flow_Up; + if ( overshoot ) + ras.cProfile->flags |= Overshoot_Bottom; + + FT_TRACE6(( " new ascending profile = %p\n", (void *)ras.cProfile )); + break; + + case Descending_State: + if ( overshoot ) + ras.cProfile->flags |= Overshoot_Top; + FT_TRACE6(( " new descending profile = %p\n", (void *)ras.cProfile )); + break; + + default: + FT_ERROR(( "New_Profile: invalid profile direction\n" )); + ras.error = FT_THROW( Invalid_Outline ); + return FAILURE; + } + + if ( !ras.gProfile ) + ras.gProfile = ras.cProfile; + + ras.state = aState; + ras.fresh = TRUE; + ras.joint = FALSE; + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * End_Profile + * + * @Description: + * Finalize the current profile. + * + * @Input: + * overshoot :: + * Whether the profile's unrounded end position differs + * by at least a half pixel. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow or incoherency. + */ + static Bool + End_Profile( RAS_ARGS Bool overshoot ) + { + Long h; + + + h = (Long)( ras.top - ras.cProfile->offset ); + + if ( h < 0 ) + { + FT_ERROR(( "End_Profile: negative height encountered\n" )); + ras.error = FT_THROW( Raster_Negative_Height ); + return FAILURE; + } + + if ( h > 0 ) + { + PProfile oldProfile; + + + FT_TRACE6(( " ending profile %p, start = %ld, height = %ld\n", + (void *)ras.cProfile, ras.cProfile->start, h )); + + ras.cProfile->height = h; + if ( overshoot ) + { + if ( ras.cProfile->flags & Flow_Up ) + ras.cProfile->flags |= Overshoot_Top; + else + ras.cProfile->flags |= Overshoot_Bottom; + } + + oldProfile = ras.cProfile; + ras.cProfile = (PProfile)ras.top; + + ras.top += AlignProfileSize; + + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + + oldProfile->next = ras.cProfile; + ras.num_Profs++; + } + + if ( ras.top >= ras.maxBuff ) + { + FT_TRACE1(( "overflow in End_Profile\n" )); + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + ras.joint = FALSE; + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Insert_Y_Turn + * + * @Description: + * Insert a salient into the sorted list placed on top of the render + * pool. + * + * @Input: + * New y scanline position. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow. + */ + static Bool + Insert_Y_Turn( RAS_ARGS Int y ) + { + PLong y_turns; + Int n; + + + n = ras.numTurns - 1; + y_turns = ras.sizeBuff - ras.numTurns; + + /* look for first y value that is <= */ + while ( n >= 0 && y < y_turns[n] ) + n--; + + /* if it is <, simply insert it, ignore if == */ + if ( n >= 0 && y > y_turns[n] ) + do + { + Int y2 = (Int)y_turns[n]; + + + y_turns[n] = y; + y = y2; + } while ( --n >= 0 ); + + if ( n < 0 ) + { + ras.maxBuff--; + if ( ras.maxBuff <= ras.top ) + { + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + ras.numTurns++; + ras.sizeBuff[-ras.numTurns] = y; + } + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Finalize_Profile_Table + * + * @Description: + * Adjust all links in the profiles list. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow. + */ + static Bool + Finalize_Profile_Table( RAS_ARG ) + { + UShort n; + PProfile p; + + + n = ras.num_Profs; + p = ras.fProfile; + + if ( n > 1 && p ) + { + do + { + Int bottom, top; + + + if ( n > 1 ) + p->link = (PProfile)( p->offset + p->height ); + else + p->link = NULL; + + if ( p->flags & Flow_Up ) + { + bottom = (Int)p->start; + top = (Int)( p->start + p->height - 1 ); + } + else + { + bottom = (Int)( p->start - p->height + 1 ); + top = (Int)p->start; + p->start = bottom; + p->offset += p->height - 1; + } + + if ( Insert_Y_Turn( RAS_VARS bottom ) || + Insert_Y_Turn( RAS_VARS top + 1 ) ) + return FAILURE; + + p = p->link; + } while ( --n ); + } + else + ras.fProfile = NULL; + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Split_Conic + * + * @Description: + * Subdivide one conic Bezier into two joint sub-arcs in the Bezier + * stack. + * + * @Input: + * None (subdivided Bezier is taken from the top of the stack). + * + * @Note: + * This routine is the `beef' of this component. It is _the_ inner + * loop that should be optimized to hell to get the best performance. + */ + static void + Split_Conic( TPoint* base ) + { + Long a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; + + /* hand optimized. gcc doesn't seem to be too good at common */ + /* expression substitution and instruction scheduling ;-) */ + } + + + /************************************************************************** + * + * @Function: + * Split_Cubic + * + * @Description: + * Subdivide a third-order Bezier arc into two joint sub-arcs in the + * Bezier stack. + * + * @Note: + * This routine is the `beef' of the component. It is one of _the_ + * inner loops that should be optimized like hell to get the best + * performance. + */ + static void + Split_Cubic( TPoint* base ) + { + Long a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; + } + + + /************************************************************************** + * + * @Function: + * Line_Up + * + * @Description: + * Compute the x-coordinates of an ascending line segment and store + * them in the render pool. + * + * @Input: + * x1 :: + * The x-coordinate of the segment's start point. + * + * y1 :: + * The y-coordinate of the segment's start point. + * + * x2 :: + * The x-coordinate of the segment's end point. + * + * y2 :: + * The y-coordinate of the segment's end point. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Line_Up( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Long Dx, Dy; + Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ + Long Ix, Rx, Ax; + + PLong top; + + + Dx = x2 - x1; + Dy = y2 - y1; + + if ( Dy <= 0 || y2 < miny || y1 > maxy ) + return SUCCESS; + + if ( y1 < miny ) + { + /* Take care: miny-y1 can be a very large value; we use */ + /* a slow MulDiv function to avoid clipping bugs */ + x1 += SMulDiv( Dx, miny - y1, Dy ); + e1 = (Int)TRUNC( miny ); + f1 = 0; + } + else + { + e1 = (Int)TRUNC( y1 ); + f1 = (Int)FRAC( y1 ); + } + + if ( y2 > maxy ) + { + /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ + e2 = (Int)TRUNC( maxy ); + f2 = 0; + } + else + { + e2 = (Int)TRUNC( y2 ); + f2 = (Int)FRAC( y2 ); + } + + if ( f1 > 0 ) + { + if ( e1 == e2 ) + return SUCCESS; + else + { + x1 += SMulDiv( Dx, ras.precision - f1, Dy ); + e1 += 1; + } + } + else + if ( ras.joint ) + { + ras.top--; + ras.joint = FALSE; + } + + ras.joint = (char)( f2 == 0 ); + + if ( ras.fresh ) + { + ras.cProfile->start = e1; + ras.fresh = FALSE; + } + + size = e2 - e1 + 1; + if ( ras.top + size >= ras.maxBuff ) + { + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + if ( Dx > 0 ) + { + Ix = SMulDiv_No_Round( ras.precision, Dx, Dy ); + Rx = ( ras.precision * Dx ) % Dy; + Dx = 1; + } + else + { + Ix = -SMulDiv_No_Round( ras.precision, -Dx, Dy ); + Rx = ( ras.precision * -Dx ) % Dy; + Dx = -1; + } + + Ax = -Dy; + top = ras.top; + + while ( size > 0 ) + { + *top++ = x1; + + x1 += Ix; + Ax += Rx; + if ( Ax >= 0 ) + { + Ax -= Dy; + x1 += Dx; + } + size--; + } + + ras.top = top; + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Line_Down + * + * @Description: + * Compute the x-coordinates of an descending line segment and store + * them in the render pool. + * + * @Input: + * x1 :: + * The x-coordinate of the segment's start point. + * + * y1 :: + * The y-coordinate of the segment's start point. + * + * x2 :: + * The x-coordinate of the segment's end point. + * + * y2 :: + * The y-coordinate of the segment's end point. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Line_Down( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Bool result, fresh; + + + fresh = ras.fresh; + + result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + return result; + } + + + /* A function type describing the functions used to split Bezier arcs */ + typedef void (*TSplitter)( TPoint* base ); + + + /************************************************************************** + * + * @Function: + * Bezier_Up + * + * @Description: + * Compute the x-coordinates of an ascending Bezier arc and store + * them in the render pool. + * + * @Input: + * degree :: + * The degree of the Bezier arc (either 2 or 3). + * + * splitter :: + * The function to split Bezier arcs. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Bezier_Up( RAS_ARGS Int degree, + TPoint* arc, + TSplitter splitter, + Long miny, + Long maxy ) + { + Long y1, y2, e, e2, e0; + Short f1; + + TPoint* start_arc; + + PLong top; + + + y1 = arc[degree].y; + y2 = arc[0].y; + top = ras.top; + + if ( y2 < miny || y1 > maxy ) + goto Fin; + + e2 = FLOOR( y2 ); + + if ( e2 > maxy ) + e2 = maxy; + + e0 = miny; + + if ( y1 < miny ) + e = miny; + else + { + e = CEILING( y1 ); + f1 = (Short)( FRAC( y1 ) ); + e0 = e; + + if ( f1 == 0 ) + { + if ( ras.joint ) + { + top--; + ras.joint = FALSE; + } + + *top++ = arc[degree].x; + + e += ras.precision; + } + } + + if ( ras.fresh ) + { + ras.cProfile->start = TRUNC( e0 ); + ras.fresh = FALSE; + } + + if ( e2 < e ) + goto Fin; + + if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) + { + ras.top = top; + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + start_arc = arc; + + do + { + ras.joint = FALSE; + + y2 = arc[0].y; + + if ( y2 > e ) + { + y1 = arc[degree].y; + if ( y2 - y1 >= ras.precision_step ) + { + splitter( arc ); + arc += degree; + } + else + { + *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x, + e - y1, y2 - y1 ); + arc -= degree; + e += ras.precision; + } + } + else + { + if ( y2 == e ) + { + ras.joint = TRUE; + *top++ = arc[0].x; + + e += ras.precision; + } + arc -= degree; + } + } while ( arc >= start_arc && e <= e2 ); + + Fin: + ras.top = top; + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Bezier_Down + * + * @Description: + * Compute the x-coordinates of an descending Bezier arc and store + * them in the render pool. + * + * @Input: + * degree :: + * The degree of the Bezier arc (either 2 or 3). + * + * splitter :: + * The function to split Bezier arcs. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Bezier_Down( RAS_ARGS Int degree, + TPoint* arc, + TSplitter splitter, + Long miny, + Long maxy ) + { + Bool result, fresh; + + + arc[0].y = -arc[0].y; + arc[1].y = -arc[1].y; + arc[2].y = -arc[2].y; + if ( degree > 2 ) + arc[3].y = -arc[3].y; + + fresh = ras.fresh; + + result = Bezier_Up( RAS_VARS degree, arc, splitter, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + arc[0].y = -arc[0].y; + return result; + } + + + /************************************************************************** + * + * @Function: + * Line_To + * + * @Description: + * Inject a new line segment and adjust the Profiles list. + * + * @Input: + * x :: + * The x-coordinate of the segment's end point (its start point + * is stored in `lastX'). + * + * y :: + * The y-coordinate of the segment's end point (its start point + * is stored in `lastY'). + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow or incorrect + * profile. + */ + static Bool + Line_To( RAS_ARGS Long x, + Long y ) + { + /* First, detect a change of direction */ + + switch ( ras.state ) + { + case Unknown_State: + if ( y > ras.lastY ) + { + if ( New_Profile( RAS_VARS Ascending_State, + IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + else + { + if ( y < ras.lastY ) + if ( New_Profile( RAS_VARS Descending_State, + IS_TOP_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + break; + + case Ascending_State: + if ( y < ras.lastY ) + { + if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) || + New_Profile( RAS_VARS Descending_State, + IS_TOP_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + break; + + case Descending_State: + if ( y > ras.lastY ) + { + if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) || + New_Profile( RAS_VARS Ascending_State, + IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + break; + + default: + ; + } + + /* Then compute the lines */ + + switch ( ras.state ) + { + case Ascending_State: + if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + case Descending_State: + if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + default: + ; + } + + ras.lastX = x; + ras.lastY = y; + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Conic_To + * + * @Description: + * Inject a new conic arc and adjust the profile list. + * + * @Input: + * cx :: + * The x-coordinate of the arc's new control point. + * + * cy :: + * The y-coordinate of the arc's new control point. + * + * x :: + * The x-coordinate of the arc's end point (its start point is + * stored in `lastX'). + * + * y :: + * The y-coordinate of the arc's end point (its start point is + * stored in `lastY'). + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow or incorrect + * profile. + */ + static Bool + Conic_To( RAS_ARGS Long cx, + Long cy, + Long x, + Long y ) + { + Long y1, y2, y3, x3, ymin, ymax; + TStates state_bez; + TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ + + + arc = arcs; + arc[2].x = ras.lastX; + arc[2].y = ras.lastY; + arc[1].x = cx; + arc[1].y = cy; + arc[0].x = x; + arc[0].y = y; + + do + { + y1 = arc[2].y; + y2 = arc[1].y; + y3 = arc[0].y; + x3 = arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y3 ) + { + ymin = y1; + ymax = y3; + } + else + { + ymin = y3; + ymax = y1; + } + + if ( y2 < ymin || y2 > ymax ) + { + /* this arc has no given direction, split it! */ + Split_Conic( arc ); + arc += 2; + } + else if ( y1 == y3 ) + { + /* this arc is flat, ignore it and pop it from the Bezier stack */ + arc -= 2; + } + else + { + /* the arc is y-monotonous, either ascending or descending */ + /* detect a change of direction */ + state_bez = y1 < y3 ? Ascending_State : Descending_State; + if ( ras.state != state_bez ) + { + Bool o = ( state_bez == Ascending_State ) + ? IS_BOTTOM_OVERSHOOT( y1 ) + : IS_TOP_OVERSHOOT( y1 ); + + + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VARS o ) ) + goto Fail; + + /* create a new profile */ + if ( New_Profile( RAS_VARS state_bez, o ) ) + goto Fail; + } + + /* now call the appropriate routine */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) + goto Fail; + arc -= 2; + } + + } while ( arc >= arcs ); + + ras.lastX = x3; + ras.lastY = y3; + + return SUCCESS; + + Fail: + return FAILURE; + } + + + /************************************************************************** + * + * @Function: + * Cubic_To + * + * @Description: + * Inject a new cubic arc and adjust the profile list. + * + * @Input: + * cx1 :: + * The x-coordinate of the arc's first new control point. + * + * cy1 :: + * The y-coordinate of the arc's first new control point. + * + * cx2 :: + * The x-coordinate of the arc's second new control point. + * + * cy2 :: + * The y-coordinate of the arc's second new control point. + * + * x :: + * The x-coordinate of the arc's end point (its start point is + * stored in `lastX'). + * + * y :: + * The y-coordinate of the arc's end point (its start point is + * stored in `lastY'). + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow or incorrect + * profile. + */ + static Bool + Cubic_To( RAS_ARGS Long cx1, + Long cy1, + Long cx2, + Long cy2, + Long x, + Long y ) + { + Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; + TStates state_bez; + TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ + + + arc = arcs; + arc[3].x = ras.lastX; + arc[3].y = ras.lastY; + arc[2].x = cx1; + arc[2].y = cy1; + arc[1].x = cx2; + arc[1].y = cy2; + arc[0].x = x; + arc[0].y = y; + + do + { + y1 = arc[3].y; + y2 = arc[2].y; + y3 = arc[1].y; + y4 = arc[0].y; + x4 = arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y4 ) + { + ymin1 = y1; + ymax1 = y4; + } + else + { + ymin1 = y4; + ymax1 = y1; + } + + if ( y2 <= y3 ) + { + ymin2 = y2; + ymax2 = y3; + } + else + { + ymin2 = y3; + ymax2 = y2; + } + + if ( ymin2 < ymin1 || ymax2 > ymax1 ) + { + /* this arc has no given direction, split it! */ + Split_Cubic( arc ); + arc += 3; + } + else if ( y1 == y4 ) + { + /* this arc is flat, ignore it and pop it from the Bezier stack */ + arc -= 3; + } + else + { + state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; + + /* detect a change of direction */ + if ( ras.state != state_bez ) + { + Bool o = ( state_bez == Ascending_State ) + ? IS_BOTTOM_OVERSHOOT( y1 ) + : IS_TOP_OVERSHOOT( y1 ); + + + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VARS o ) ) + goto Fail; + + if ( New_Profile( RAS_VARS state_bez, o ) ) + goto Fail; + } + + /* compute intersections */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) + goto Fail; + arc -= 3; + } + + } while ( arc >= arcs ); + + ras.lastX = x4; + ras.lastY = y4; + + return SUCCESS; + + Fail: + return FAILURE; + } + + +#undef SWAP_ +#define SWAP_( x, y ) do \ + { \ + Long swap = x; \ + \ + \ + x = y; \ + y = swap; \ + } while ( 0 ) + + + /************************************************************************** + * + * @Function: + * Decompose_Curve + * + * @Description: + * Scan the outline arrays in order to emit individual segments and + * Beziers by calling Line_To() and Bezier_To(). It handles all + * weird cases, like when the first point is off the curve, or when + * there are simply no `on' points in the contour! + * + * @Input: + * first :: + * The index of the first point in the contour. + * + * last :: + * The index of the last point in the contour. + * + * flipped :: + * If set, flip the direction of the curve. + * + * @Return: + * SUCCESS on success, FAILURE on error. + */ + static Bool + Decompose_Curve( RAS_ARGS Int first, + Int last, + Int flipped ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* points; + FT_Vector* point; + FT_Vector* limit; + char* tags; + + UInt tag; /* current point's state */ + + + points = ras.outline.points; + limit = points + last; + + v_start.x = SCALED( points[first].x ); + v_start.y = SCALED( points[first].y ); + v_last.x = SCALED( points[last].x ); + v_last.y = SCALED( points[last].y ); + + if ( flipped ) + { + SWAP_( v_start.x, v_start.y ); + SWAP_( v_last.x, v_last.y ); + } + + v_control = v_start; + + point = points + first; + tags = ras.outline.tags + first; + + /* set scan mode if necessary */ + if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE ) + ras.dropOutControl = (Byte)tags[0] >> 5; + + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + /* v_last = v_start; */ + } + point--; + tags--; + } + + ras.lastX = v_start.x; + ras.lastY = v_start.y; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + Long x, y; + + + x = SCALED( point->x ); + y = SCALED( point->y ); + if ( flipped ) + SWAP_( x, y ); + + if ( Line_To( RAS_VARS x, y ) ) + goto Fail; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point[0].x ); + v_control.y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( v_control.x, v_control.y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector v_middle; + Long x, y; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + x = SCALED( point[0].x ); + y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( x, y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) + goto Fail; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + x ) / 2; + v_middle.y = ( v_control.y + y ) / 2; + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_middle.x, v_middle.y ) ) + goto Fail; + + v_control.x = x; + v_control.y = y; + + goto Do_Conic; + } + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_start.x, v_start.y ) ) + goto Fail; + + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + Long x1, y1, x2, y2, x3, y3; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + x1 = SCALED( point[-2].x ); + y1 = SCALED( point[-2].y ); + x2 = SCALED( point[-1].x ); + y2 = SCALED( point[-1].y ); + + if ( flipped ) + { + SWAP_( x1, y1 ); + SWAP_( x2, y2 ); + } + + if ( point <= limit ) + { + x3 = SCALED( point[0].x ); + y3 = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( x3, y3 ); + + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) + goto Fail; + continue; + } + + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) + goto Fail; + goto Close; + } + } + } + + /* close the contour with a line segment */ + if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) + goto Fail; + + Close: + return SUCCESS; + + Invalid_Outline: + ras.error = FT_THROW( Invalid_Outline ); + + Fail: + return FAILURE; + } + + + /************************************************************************** + * + * @Function: + * Convert_Glyph + * + * @Description: + * Convert a glyph into a series of segments and arcs and make a + * profiles list with them. + * + * @Input: + * flipped :: + * If set, flip the direction of curve. + * + * @Return: + * SUCCESS on success, FAILURE if any error was encountered during + * rendering. + */ + static Bool + Convert_Glyph( RAS_ARGS Int flipped ) + { + Int i; + Int first, last; + + + ras.fProfile = NULL; + ras.joint = FALSE; + ras.fresh = FALSE; + + ras.maxBuff = ras.sizeBuff - AlignProfileSize; + + ras.numTurns = 0; + + ras.cProfile = (PProfile)ras.top; + ras.cProfile->offset = ras.top; + ras.num_Profs = 0; + + last = -1; + for ( i = 0; i < ras.outline.n_contours; i++ ) + { + PProfile lastProfile; + Bool o; + + + ras.state = Unknown_State; + ras.gProfile = NULL; + + first = last + 1; + last = ras.outline.contours[i]; + + if ( Decompose_Curve( RAS_VARS first, last, flipped ) ) + return FAILURE; + + /* we must now check whether the extreme arcs join or not */ + if ( FRAC( ras.lastY ) == 0 && + ras.lastY >= ras.minY && + ras.lastY <= ras.maxY ) + if ( ras.gProfile && + ( ras.gProfile->flags & Flow_Up ) == + ( ras.cProfile->flags & Flow_Up ) ) + ras.top--; + /* Note that ras.gProfile can be nil if the contour was too small */ + /* to be drawn. */ + + lastProfile = ras.cProfile; + if ( ras.top != ras.cProfile->offset && + ( ras.cProfile->flags & Flow_Up ) ) + o = IS_TOP_OVERSHOOT( ras.lastY ); + else + o = IS_BOTTOM_OVERSHOOT( ras.lastY ); + if ( End_Profile( RAS_VARS o ) ) + return FAILURE; + + /* close the `next profile in contour' linked list */ + if ( ras.gProfile ) + lastProfile->next = ras.gProfile; + } + + if ( Finalize_Profile_Table( RAS_VAR ) ) + return FAILURE; + + return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SCAN-LINE SWEEPS AND DRAWING **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Init_Linked + * + * Initializes an empty linked list. + */ + static void + Init_Linked( TProfileList* l ) + { + *l = NULL; + } + + + /************************************************************************** + * + * InsNew + * + * Inserts a new profile in a linked list. + */ + static void + InsNew( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + Long x; + + + old = list; + current = *old; + x = profile->X; + + while ( current ) + { + if ( x < current->X ) + break; + old = ¤t->link; + current = *old; + } + + profile->link = current; + *old = profile; + } + + + /************************************************************************** + * + * DelOld + * + * Removes an old profile from a linked list. + */ + static void + DelOld( PProfileList list, + const PProfile profile ) + { + PProfile *old, current; + + + old = list; + current = *old; + + while ( current ) + { + if ( current == profile ) + { + *old = current->link; + return; + } + + old = ¤t->link; + current = *old; + } + + /* we should never get there, unless the profile was not part of */ + /* the list. */ + } + + + /************************************************************************** + * + * Sort + * + * Sorts a trace list. In 95%, the list is already sorted. We need + * an algorithm which is fast in this case. Bubble sort is enough + * and simple. + */ + static void + Sort( PProfileList list ) + { + PProfile *old, current, next; + + + /* First, set the new X coordinate of each profile */ + current = *list; + while ( current ) + { + current->X = *current->offset; + current->offset += ( current->flags & Flow_Up ) ? 1 : -1; + current->height--; + current = current->link; + } + + /* Then sort them */ + old = list; + current = *old; + + if ( !current ) + return; + + next = current->link; + + while ( next ) + { + if ( current->X <= next->X ) + { + old = ¤t->link; + current = *old; + + if ( !current ) + return; + } + else + { + *old = next; + current->link = next->link; + next->link = current; + + old = list; + current = *old; + } + + next = current->link; + } + } + + + /************************************************************************** + * + * Vertical Sweep Procedure Set + * + * These four routines are used during the vertical black/white sweep + * phase by the generic Draw_Sweep() function. + * + */ + + static void + Vertical_Sweep_Init( RAS_ARGS Short min, + Short max ) + { + FT_UNUSED( max ); + + + ras.bLine = ras.bOrigin - min * ras.target.pitch; + } + + + static void + Vertical_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + + Int dropOutControl = left->flags & 7; + + FT_UNUSED( y ); + FT_UNUSED( left ); + FT_UNUSED( right ); + + + /* in high-precision mode, we need 12 digits after the comma to */ + /* represent multiples of 1/(1<<12) = 1/4096 */ + FT_TRACE7(( " y=%d x=[% .12f;% .12f]", + y, + (double)x1 / (double)ras.precision, + (double)x2 / (double)ras.precision )); + + /* Drop-out control */ + + e1 = CEILING( x1 ); + e2 = FLOOR( x2 ); + + /* take care of the special case where both the left */ + /* and right contour lie exactly on pixel centers */ + if ( dropOutControl != 2 && + x2 - x1 - ras.precision <= ras.precision_jitter && + e1 != x1 && e2 != x2 ) + e2 = e1; + + e1 = TRUNC( e1 ); + e2 = TRUNC( e2 ); + + if ( e2 >= 0 && e1 < ras.bWidth ) + { + Byte* target; + + Int c1, c2; + Byte f1, f2; + + + if ( e1 < 0 ) + e1 = 0; + if ( e2 >= ras.bWidth ) + e2 = ras.bWidth - 1; + + FT_TRACE7(( " -> x=[%ld;%ld]", e1, e2 )); + + c1 = (Short)( e1 >> 3 ); + c2 = (Short)( e2 >> 3 ); + + f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); + f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); + + target = ras.bLine + c1; + c2 -= c1; + + if ( c2 > 0 ) + { + target[0] |= f1; + + /* memset() is slower than the following code on many platforms. */ + /* This is due to the fact that, in the vast majority of cases, */ + /* the span length in bytes is relatively small. */ + while ( --c2 > 0 ) + *( ++target ) = 0xFF; + + target[1] |= f2; + } + else + *target |= ( f1 & f2 ); + } + + FT_TRACE7(( "\n" )); + } + + + static void + Vertical_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2, pxl; + Short c1, f1; + + + FT_TRACE7(( " y=%d x=[% .12f;% .12f]", + y, + (double)x1 / (double)ras.precision, + (double)x2 / (double)ras.precision )); + + /* Drop-out control */ + + /* e2 x2 x1 e1 */ + /* */ + /* ^ | */ + /* | | */ + /* +-------------+---------------------+------------+ */ + /* | | */ + /* | v */ + /* */ + /* pixel contour contour pixel */ + /* center center */ + + /* drop-out mode scan conversion rules (as defined in OpenType) */ + /* --------------------------------------------------------------- */ + /* 0 1, 2, 3 */ + /* 1 1, 2, 4 */ + /* 2 1, 2 */ + /* 3 same as mode 2 */ + /* 4 1, 2, 5 */ + /* 5 1, 2, 6 */ + /* 6, 7 same as mode 2 */ + + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + pxl = e1; + + if ( e1 > e2 ) + { + Int dropOutControl = left->flags & 7; + + + if ( e1 == e2 + ras.precision ) + { + switch ( dropOutControl ) + { + case 0: /* simple drop-outs including stubs */ + pxl = e2; + break; + + case 4: /* smart drop-outs including stubs */ + pxl = SMART( x1, x2 ); + break; + + case 1: /* simple drop-outs excluding stubs */ + case 5: /* smart drop-outs excluding stubs */ + + /* Drop-out Control Rules #4 and #6 */ + + /* The specification neither provides an exact definition */ + /* of a `stub' nor gives exact rules to exclude them. */ + /* */ + /* Here the constraints we use to recognize a stub. */ + /* */ + /* upper stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Right is the successor of P_Left in that contour */ + /* - y is the top of P_Left and P_Right */ + /* */ + /* lower stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Left is the successor of P_Right in that contour */ + /* - y is the bottom of P_Left */ + /* */ + /* We draw a stub if the following constraints are met. */ + /* */ + /* - for an upper or lower stub, there is top or bottom */ + /* overshoot, respectively */ + /* - the covered interval is greater or equal to a half */ + /* pixel */ + + /* upper stub test */ + if ( left->next == right && + left->height <= 0 && + !( left->flags & Overshoot_Top && + x2 - x1 >= ras.precision_half ) ) + goto Exit; + + /* lower stub test */ + if ( right->next == left && + left->start == y && + !( left->flags & Overshoot_Bottom && + x2 - x1 >= ras.precision_half ) ) + goto Exit; + + if ( dropOutControl == 1 ) + pxl = e2; + else + pxl = SMART( x1, x2 ); + break; + + default: /* modes 2, 3, 6, 7 */ + goto Exit; /* no drop-out control */ + } + + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( pxl < 0 ) + pxl = e1; + else if ( TRUNC( pxl ) >= ras.bWidth ) + pxl = e2; + + /* check that the other pixel isn't set */ + e1 = ( pxl == e1 ) ? e2 : e1; + + e1 = TRUNC( e1 ); + + c1 = (Short)( e1 >> 3 ); + f1 = (Short)( e1 & 7 ); + + if ( e1 >= 0 && e1 < ras.bWidth && + ras.bLine[c1] & ( 0x80 >> f1 ) ) + goto Exit; + } + else + goto Exit; + } + + e1 = TRUNC( pxl ); + + if ( e1 >= 0 && e1 < ras.bWidth ) + { + FT_TRACE7(( " -> x=%ld", e1 )); + + c1 = (Short)( e1 >> 3 ); + f1 = (Short)( e1 & 7 ); + + ras.bLine[c1] |= (char)( 0x80 >> f1 ); + } + + Exit: + FT_TRACE7(( " dropout=%d\n", left->flags & 7 )); + } + + + static void + Vertical_Sweep_Step( RAS_ARG ) + { + ras.bLine -= ras.target.pitch; + } + + + /************************************************************************ + * + * Horizontal Sweep Procedure Set + * + * These four routines are used during the horizontal black/white + * sweep phase by the generic Draw_Sweep() function. + * + */ + + static void + Horizontal_Sweep_Init( RAS_ARGS Short min, + Short max ) + { + /* nothing, really */ + FT_UNUSED_RASTER; + FT_UNUSED( min ); + FT_UNUSED( max ); + } + + + static void + Horizontal_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + + FT_UNUSED( left ); + FT_UNUSED( right ); + + + FT_TRACE7(( " x=%d y=[% .12f;% .12f]", + y, + (double)x1 / (double)ras.precision, + (double)x2 / (double)ras.precision )); + + /* We should not need this procedure but the vertical sweep */ + /* mishandles horizontal lines through pixel centers. So we */ + /* have to check perfectly aligned span edges here. */ + /* */ + /* XXX: Can we handle horizontal lines better and drop this? */ + + e1 = CEILING( x1 ); + + if ( x1 == e1 ) + { + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && (ULong)e1 < ras.target.rows ) + { + Byte f1; + PByte bits; + + + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + FT_TRACE7(( bits[0] & f1 ? " redundant" + : " -> y=%ld edge", e1 )); + + bits[0] |= f1; + } + } + + e2 = FLOOR ( x2 ); + + if ( x2 == e2 ) + { + e2 = TRUNC( e2 ); + + if ( e2 >= 0 && (ULong)e2 < ras.target.rows ) + { + Byte f1; + PByte bits; + + + bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.target.pitch; + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + FT_TRACE7(( bits[0] & f1 ? " redundant" + : " -> y=%ld edge", e2 )); + + bits[0] |= f1; + } + } + + FT_TRACE7(( "\n" )); + } + + + static void + Horizontal_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2, pxl; + PByte bits; + Byte f1; + + + FT_TRACE7(( " x=%d y=[% .12f;% .12f]", + y, + (double)x1 / (double)ras.precision, + (double)x2 / (double)ras.precision )); + + /* During the horizontal sweep, we only take care of drop-outs */ + + /* e1 + <-- pixel center */ + /* | */ + /* x1 ---+--> <-- contour */ + /* | */ + /* | */ + /* x2 <--+--- <-- contour */ + /* | */ + /* | */ + /* e2 + <-- pixel center */ + + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + pxl = e1; + + if ( e1 > e2 ) + { + Int dropOutControl = left->flags & 7; + + + if ( e1 == e2 + ras.precision ) + { + switch ( dropOutControl ) + { + case 0: /* simple drop-outs including stubs */ + pxl = e2; + break; + + case 4: /* smart drop-outs including stubs */ + pxl = SMART( x1, x2 ); + break; + + case 1: /* simple drop-outs excluding stubs */ + case 5: /* smart drop-outs excluding stubs */ + /* see Vertical_Sweep_Drop for details */ + + /* rightmost stub test */ + if ( left->next == right && + left->height <= 0 && + !( left->flags & Overshoot_Top && + x2 - x1 >= ras.precision_half ) ) + goto Exit; + + /* leftmost stub test */ + if ( right->next == left && + left->start == y && + !( left->flags & Overshoot_Bottom && + x2 - x1 >= ras.precision_half ) ) + goto Exit; + + if ( dropOutControl == 1 ) + pxl = e2; + else + pxl = SMART( x1, x2 ); + break; + + default: /* modes 2, 3, 6, 7 */ + goto Exit; /* no drop-out control */ + } + + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( pxl < 0 ) + pxl = e1; + else if ( (ULong)( TRUNC( pxl ) ) >= ras.target.rows ) + pxl = e2; + + /* check that the other pixel isn't set */ + e1 = ( pxl == e1 ) ? e2 : e1; + + e1 = TRUNC( e1 ); + + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + if ( e1 >= 0 && + (ULong)e1 < ras.target.rows && + *bits & f1 ) + goto Exit; + } + else + goto Exit; + } + + e1 = TRUNC( pxl ); + + if ( e1 >= 0 && (ULong)e1 < ras.target.rows ) + { + FT_TRACE7(( " -> y=%ld", e1 )); + + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + + bits[0] |= f1; + } + + Exit: + FT_TRACE7(( " dropout=%d\n", left->flags & 7 )); + } + + + static void + Horizontal_Sweep_Step( RAS_ARG ) + { + /* Nothing, really */ + FT_UNUSED_RASTER; + } + + + /************************************************************************** + * + * Generic Sweep Drawing routine + * + */ + + static Bool + Draw_Sweep( RAS_ARG ) + { + Short y, y_change, y_height; + + PProfile P, Q, P_Left, P_Right; + + Short min_Y, max_Y, top, bottom, dropouts; + + Long x1, x2, xs, e1, e2; + + TProfileList waiting; + TProfileList draw_left, draw_right; + + + /* initialize empty linked lists */ + + Init_Linked( &waiting ); + + Init_Linked( &draw_left ); + Init_Linked( &draw_right ); + + /* first, compute min and max Y */ + + P = ras.fProfile; + max_Y = (Short)TRUNC( ras.minY ); + min_Y = (Short)TRUNC( ras.maxY ); + + while ( P ) + { + Q = P->link; + + bottom = (Short)P->start; + top = (Short)( P->start + P->height - 1 ); + + if ( min_Y > bottom ) + min_Y = bottom; + if ( max_Y < top ) + max_Y = top; + + P->X = 0; + InsNew( &waiting, P ); + + P = Q; + } + + /* check the Y-turns */ + if ( ras.numTurns == 0 ) + { + ras.error = FT_THROW( Invalid_Outline ); + return FAILURE; + } + + /* now initialize the sweep */ + + ras.Proc_Sweep_Init( RAS_VARS min_Y, max_Y ); + + /* then compute the distance of each profile from min_Y */ + + P = waiting; + + while ( P ) + { + P->countL = P->start - min_Y; + P = P->link; + } + + /* let's go */ + + y = min_Y; + y_height = 0; + + if ( ras.numTurns > 0 && + ras.sizeBuff[-ras.numTurns] == min_Y ) + ras.numTurns--; + + while ( ras.numTurns > 0 ) + { + /* check waiting list for new activations */ + + P = waiting; + + while ( P ) + { + Q = P->link; + P->countL -= y_height; + if ( P->countL == 0 ) + { + DelOld( &waiting, P ); + + if ( P->flags & Flow_Up ) + InsNew( &draw_left, P ); + else + InsNew( &draw_right, P ); + } + + P = Q; + } + + /* sort the drawing lists */ + + Sort( &draw_left ); + Sort( &draw_right ); + + y_change = (Short)ras.sizeBuff[-ras.numTurns--]; + y_height = (Short)( y_change - y ); + + while ( y < y_change ) + { + /* let's trace */ + + dropouts = 0; + + P_Left = draw_left; + P_Right = draw_right; + + while ( P_Left && P_Right ) + { + x1 = P_Left ->X; + x2 = P_Right->X; + + if ( x1 > x2 ) + { + xs = x1; + x1 = x2; + x2 = xs; + } + + e1 = FLOOR( x1 ); + e2 = CEILING( x2 ); + + if ( x2 - x1 <= ras.precision && + e1 != x1 && e2 != x2 ) + { + if ( e1 > e2 || e2 == e1 + ras.precision ) + { + Int dropOutControl = P_Left->flags & 7; + + + if ( dropOutControl != 2 ) + { + /* a drop-out was detected */ + + P_Left ->X = x1; + P_Right->X = x2; + + /* mark profile for drop-out processing */ + P_Left->countL = 1; + dropouts++; + } + + goto Skip_To_Next; + } + } + + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); + + Skip_To_Next: + + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + /* handle drop-outs _after_ the span drawing -- */ + /* drop-out processing has been moved out of the loop */ + /* for performance tuning */ + if ( dropouts > 0 ) + goto Scan_DropOuts; + + Next_Line: + + ras.Proc_Sweep_Step( RAS_VAR ); + + y++; + + if ( y < y_change ) + { + Sort( &draw_left ); + Sort( &draw_right ); + } + } + + /* now finalize the profiles that need it */ + + P = draw_left; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_left, P ); + P = Q; + } + + P = draw_right; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_right, P ); + P = Q; + } + } + + /* for gray-scaling, flush the bitmap scanline cache */ + while ( y <= max_Y ) + { + ras.Proc_Sweep_Step( RAS_VAR ); + y++; + } + + return SUCCESS; + + Scan_DropOuts: + + P_Left = draw_left; + P_Right = draw_right; + + while ( P_Left && P_Right ) + { + if ( P_Left->countL ) + { + P_Left->countL = 0; +#if 0 + dropouts--; /* -- this is useful when debugging only */ +#endif + ras.Proc_Sweep_Drop( RAS_VARS y, + P_Left->X, + P_Right->X, + P_Left, + P_Right ); + } + + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + goto Next_Line; + } + + +#ifdef STANDALONE_ + + /************************************************************************** + * + * The following functions should only compile in stand-alone mode, + * i.e., when building this component without the rest of FreeType. + * + */ + + /************************************************************************** + * + * @Function: + * FT_Outline_Get_CBox + * + * @Description: + * Return an outline's `control box'. The control box encloses all + * the outline's points, including Bézier control points. Though it + * coincides with the exact bounding box for most glyphs, it can be + * slightly larger in some situations (like when rotating an outline + * that contains Bézier outside arcs). + * + * Computing the control box is very fast, while getting the bounding + * box can take much more time as it needs to walk over all segments + * and arcs in the outline. To get the latter, you can use the + * `ftbbox' component, which is dedicated to this single task. + * + * @Input: + * outline :: + * A pointer to the source outline descriptor. + * + * @Output: + * acbox :: + * The outline's control box. + * + * @Note: + * See @FT_Glyph_Get_CBox for a discussion of tricky fonts. + */ + + static void + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ) + { + if ( outline && acbox ) + { + Long xMin, yMin, xMax, yMax; + + + if ( outline->n_points == 0 ) + { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } + else + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + + for ( ; vec < limit; vec++ ) + { + Long x, y; + + + x = vec->x; + if ( x < xMin ) xMin = x; + if ( x > xMax ) xMax = x; + + y = vec->y; + if ( y < yMin ) yMin = y; + if ( y > yMax ) yMax = y; + } + } + acbox->xMin = xMin; + acbox->xMax = xMax; + acbox->yMin = yMin; + acbox->yMax = yMax; + } + } + +#endif /* STANDALONE_ */ + + + /************************************************************************** + * + * @Function: + * Render_Single_Pass + * + * @Description: + * Perform one sweep with sub-banding. + * + * @Input: + * flipped :: + * If set, flip the direction of the outline. + * + * @Return: + * Renderer error code. + */ + static int + Render_Single_Pass( RAS_ARGS Bool flipped, + Int y_min, + Int y_max ) + { + Int y_mid; + Int band_top = 0; + Int band_stack[32]; /* enough to bisect 32-bit int bands */ + + + while ( 1 ) + { + ras.minY = (Long)y_min * ras.precision; + ras.maxY = (Long)y_max * ras.precision; + + ras.top = ras.buff; + + ras.error = Raster_Err_Ok; + + if ( Convert_Glyph( RAS_VARS flipped ) ) + { + if ( ras.error != Raster_Err_Raster_Overflow ) + return ras.error; + + /* sub-banding */ + + if ( y_min == y_max ) + return ras.error; /* still Raster_Overflow */ + + y_mid = ( y_min + y_max ) >> 1; + + band_stack[band_top++] = y_min; + y_min = y_mid + 1; + } + else + { + if ( ras.fProfile ) + if ( Draw_Sweep( RAS_VAR ) ) + return ras.error; + + if ( --band_top < 0 ) + break; + + y_max = y_min - 1; + y_min = band_stack[band_top]; + } + } + + return Raster_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * Render_Glyph + * + * @Description: + * Render a glyph in a bitmap. Sub-banding if needed. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + Render_Glyph( RAS_ARG ) + { + FT_Error error; + + + Set_High_Precision( RAS_VARS ras.outline.flags & + FT_OUTLINE_HIGH_PRECISION ); + + if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) + ras.dropOutControl = 2; + else + { + if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) + ras.dropOutControl = 4; + else + ras.dropOutControl = 0; + + if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) + ras.dropOutControl += 1; + } + + /* Vertical Sweep */ + FT_TRACE7(( "Vertical pass (ftraster)\n" )); + + ras.Proc_Sweep_Init = Vertical_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Sweep_Step; + + ras.bWidth = (UShort)ras.target.width; + ras.bOrigin = (Byte*)ras.target.buffer; + + if ( ras.target.pitch > 0 ) + ras.bOrigin += (Long)( ras.target.rows - 1 ) * ras.target.pitch; + + error = Render_Single_Pass( RAS_VARS 0, 0, (Int)ras.target.rows - 1 ); + if ( error ) + return error; + + /* Horizontal Sweep */ + if ( !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ) ) + { + FT_TRACE7(( "Horizontal pass (ftraster)\n" )); + + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + + error = Render_Single_Pass( RAS_VARS 1, 0, (Int)ras.target.width - 1 ); + if ( error ) + return error; + } + + return Raster_Err_Ok; + } + + + /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ + /**** a static object. *****/ + + +#ifdef STANDALONE_ + + + static int + ft_black_new( void* memory, + FT_Raster *araster ) + { + static black_TRaster the_raster; + FT_UNUSED( memory ); + + + *araster = (FT_Raster)&the_raster; + FT_ZERO( &the_raster ); + + return 0; + } + + + static void + ft_black_done( FT_Raster raster ) + { + /* nothing */ + FT_UNUSED( raster ); + } + + +#else /* !STANDALONE_ */ + + + static int + ft_black_new( void* memory_, /* FT_Memory */ + FT_Raster *araster_ ) /* black_PRaster */ + { + FT_Memory memory = (FT_Memory)memory_; + black_PRaster *araster = (black_PRaster*)araster_; + + FT_Error error; + black_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + static void + ft_black_done( FT_Raster raster_ ) /* black_PRaster */ + { + black_PRaster raster = (black_PRaster)raster_; + FT_Memory memory = (FT_Memory)raster->memory; + + + FT_FREE( raster ); + } + + +#endif /* !STANDALONE_ */ + + + static void + ft_black_reset( FT_Raster raster, + PByte pool_base, + ULong pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + static int + ft_black_set_mode( FT_Raster raster, + ULong mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return 0; + } + + + static int + ft_black_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + +#ifndef FT_STATIC_RASTER + black_TWorker worker[1]; +#endif + + Long buffer[FT_MAX_BLACK_POOL]; + + + if ( !raster ) + return FT_THROW( Raster_Uninitialized ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return Raster_Err_Ok; + + if ( !outline->contours || !outline->points ) + return FT_THROW( Invalid_Outline ); + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return FT_THROW( Invalid_Outline ); + + /* this version of the raster does not support direct rendering, sorry */ + if ( params->flags & FT_RASTER_FLAG_DIRECT || + params->flags & FT_RASTER_FLAG_AA ) + return FT_THROW( Cannot_Render_Glyph ); + + if ( !target_map ) + return FT_THROW( Invalid_Argument ); + + /* nothing to do */ + if ( !target_map->width || !target_map->rows ) + return Raster_Err_Ok; + + if ( !target_map->buffer ) + return FT_THROW( Invalid_Argument ); + + ras.outline = *outline; + ras.target = *target_map; + + ras.buff = buffer; + ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ + + return Render_Glyph( RAS_VAR ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_standard_raster, + + FT_GLYPH_FORMAT_OUTLINE, + + ft_black_new, /* FT_Raster_New_Func raster_new */ + ft_black_reset, /* FT_Raster_Reset_Func raster_reset */ + ft_black_set_mode, /* FT_Raster_Set_Mode_Func raster_set_mode */ + ft_black_render, /* FT_Raster_Render_Func raster_render */ + ft_black_done /* FT_Raster_Done_Func raster_done */ + ) + + +/* END */ diff --git a/vendor/freetype/src/raster/ftraster.h b/vendor/freetype/src/raster/ftraster.h new file mode 100644 index 0000000..b511b3a --- /dev/null +++ b/vendor/freetype/src/raster/ftraster.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * ftraster.h + * + * The FreeType glyph rasterizer (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTRASTER_H_ +#define FTRASTER_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +#include + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * Uncomment the following line if you are using ftraster.c as a + * standalone module, fully independent of FreeType. + */ +/* #define STANDALONE_ */ + + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_standard_raster; + + +FT_END_HEADER + +#endif /* FTRASTER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/raster/ftrend1.c b/vendor/freetype/src/raster/ftrend1.c new file mode 100644 index 0000000..6d442b1 --- /dev/null +++ b/vendor/freetype/src/raster/ftrend1.c @@ -0,0 +1,209 @@ +/**************************************************************************** + * + * ftrend1.c + * + * The FreeType glyph rasterizer interface (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ftrend1.h" +#include "ftraster.h" + +#include "rasterrs.h" + + + /* initialize renderer -- init its raster */ + static FT_Error + ft_raster1_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return FT_Err_Ok; + } + + + /* set render-specific mode */ + static FT_Error + ft_raster1_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + + /* transform a given glyph image */ + static FT_Error + ft_raster1_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static void + ft_raster1_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_ZERO( cbox ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_raster1_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = render->root.memory; + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + + FT_Raster_Params params; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check rendering mode */ + if ( mode != FT_RENDER_MODE_MONO ) + { + /* raster1 is only capable of producing monochrome bitmaps */ + return FT_THROW( Cannot_Render_Glyph ); + } + + /* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) ) + { + error = FT_THROW( Raster_Overflow ); + goto Exit; + } + + /* allocate new one */ + if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + x_shift = -slot->bitmap_left * 64; + y_shift = ( (FT_Int)bitmap->rows - slot->bitmap_top ) * 64; + + if ( origin ) + { + x_shift += origin->x; + y_shift += origin->y; + } + + /* translate outline to render it into the bitmap */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, x_shift, y_shift ); + + /* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_DEFAULT; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + Exit: + if ( !error ) + /* everything is fine; the glyph is now officially a bitmap */ + slot->format = FT_GLYPH_FORMAT_BITMAP; + else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + return error; + } + + + FT_DEFINE_RENDERER( + ft_raster1_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + + "raster1", + 0x10000L, + 0x20000L, + + NULL, /* module specific interface */ + + ft_raster1_init, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + NULL, /* FT_Module_Requester get_interface */ + + FT_GLYPH_FORMAT_OUTLINE, + + ft_raster1_render, /* FT_Renderer_RenderFunc render_glyph */ + ft_raster1_transform, /* FT_Renderer_TransformFunc transform_glyph */ + ft_raster1_get_cbox, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */ + ft_raster1_set_mode, /* FT_Renderer_SetModeFunc set_mode */ + + &ft_standard_raster /* FT_Raster_Funcs* raster_class */ + ) + + +/* END */ diff --git a/vendor/freetype/src/raster/ftrend1.h b/vendor/freetype/src/raster/ftrend1.h new file mode 100644 index 0000000..cec35c8 --- /dev/null +++ b/vendor/freetype/src/raster/ftrend1.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * ftrend1.h + * + * The FreeType glyph rasterizer interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTREND1_H_ +#define FTREND1_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_RENDERER( ft_raster1_renderer_class ) + + +FT_END_HEADER + +#endif /* FTREND1_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/raster/module.mk b/vendor/freetype/src/raster/module.mk new file mode 100644 index 0000000..6ad1aa7 --- /dev/null +++ b/vendor/freetype/src/raster/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 renderer module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += RASTER_MODULE + +define RASTER_MODULE +$(OPEN_DRIVER) FT_Renderer_Class, ft_raster1_renderer_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)raster $(ECHO_DRIVER_DESC)monochrome bitmap renderer$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/raster/raster.c b/vendor/freetype/src/raster/raster.c new file mode 100644 index 0000000..82f4745 --- /dev/null +++ b/vendor/freetype/src/raster/raster.c @@ -0,0 +1,25 @@ +/**************************************************************************** + * + * raster.c + * + * FreeType monochrome rasterer module component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftraster.c" +#include "ftrend1.c" + + +/* END */ diff --git a/vendor/freetype/src/raster/rasterrs.h b/vendor/freetype/src/raster/rasterrs.h new file mode 100644 index 0000000..989d8b4 --- /dev/null +++ b/vendor/freetype/src/raster/rasterrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * rasterrs.h + * + * monochrome renderer error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the monochrome renderer error enumeration + * constants. + * + */ + +#ifndef RASTERRS_H_ +#define RASTERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Raster_Err_ +#define FT_ERR_BASE FT_Mod_Err_Raster + +#include + +#endif /* RASTERRS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/raster/rules.mk b/vendor/freetype/src/raster/rules.mk new file mode 100644 index 0000000..031b85f --- /dev/null +++ b/vendor/freetype/src/raster/rules.mk @@ -0,0 +1,72 @@ +# +# FreeType 2 renderer module build rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# raster driver directory +# +RASTER_DIR := $(SRC_DIR)/raster + +# compilation flags for the driver +# +RASTER_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(RASTER_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# raster driver sources (i.e., C files) +# +RASTER_DRV_SRC := $(RASTER_DIR)/ftraster.c \ + $(RASTER_DIR)/ftrend1.c + + +# raster driver headers +# +RASTER_DRV_H := $(RASTER_DRV_SRC:%.c=%.h) \ + $(RASTER_DIR)/rasterrs.h + + +# raster driver object(s) +# +# RASTER_DRV_OBJ_M is used during `multi' builds. +# RASTER_DRV_OBJ_S is used during `single' builds. +# +RASTER_DRV_OBJ_M := $(RASTER_DRV_SRC:$(RASTER_DIR)/%.c=$(OBJ_DIR)/%.$O) +RASTER_DRV_OBJ_S := $(OBJ_DIR)/raster.$O + +# raster driver source file for single build +# +RASTER_DRV_SRC_S := $(RASTER_DIR)/raster.c + + +# raster driver - single object +# +$(RASTER_DRV_OBJ_S): $(RASTER_DRV_SRC_S) $(RASTER_DRV_SRC) \ + $(FREETYPE_H) $(RASTER_DRV_H) + $(RASTER_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(RASTER_DRV_SRC_S)) + + +# raster driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(RASTER_DIR)/%.c $(FREETYPE_H) $(RASTER_DRV_H) + $(RASTER_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(RASTER_DRV_OBJ_S) +DRV_OBJS_M += $(RASTER_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/sdf/ftbsdf.c b/vendor/freetype/src/sdf/ftbsdf.c new file mode 100644 index 0000000..e472738 --- /dev/null +++ b/vendor/freetype/src/sdf/ftbsdf.c @@ -0,0 +1,1350 @@ +/**************************************************************************** + * + * ftbsdf.c + * + * Signed Distance Field support for bitmap fonts (body only). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "ftsdf.h" +#include "ftsdferrs.h" +#include "ftsdfcommon.h" + + + /************************************************************************** + * + * A brief technical overview of how the BSDF rasterizer works + * ----------------------------------------------------------- + * + * [Notes]: + * * SDF stands for Signed Distance Field everywhere. + * + * * BSDF stands for Bitmap to Signed Distance Field rasterizer. + * + * * This renderer converts rasterized bitmaps to SDF. There is another + * renderer called 'sdf', which generates SDF directly from outlines; + * see file `ftsdf.c` for more. + * + * * The idea of generating SDF from bitmaps is taken from two research + * papers, where one is dependent on the other: + * + * - Per-Erik Danielsson: Euclidean Distance Mapping + * http://webstaff.itn.liu.se/~stegu/JFA/Danielsson.pdf + * + * From this paper we use the eight-point sequential Euclidean + * distance mapping (8SED). This is the heart of the process used + * in this rasterizer. + * + * - Stefan Gustavson, Robin Strand: Anti-aliased Euclidean distance transform. + * http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf + * + * The original 8SED algorithm discards the pixels' alpha values, + * which can contain information about the actual outline of the + * glyph. This paper takes advantage of those alpha values and + * approximates outline pretty accurately. + * + * * This rasterizer also works for monochrome bitmaps. However, the + * result is not as accurate since we don't have any way to + * approximate outlines from binary bitmaps. + * + * ======================================================================== + * + * Generating SDF from bitmap is done in several steps. + * + * (1) The only information we have is the bitmap itself. It can + * be monochrome or anti-aliased. If it is anti-aliased, pixel values + * are nothing but coverage values. These coverage values can be used + * to extract information about the outline of the image. For + * example, if the pixel's alpha value is 0.5, then we can safely + * assume that the outline passes through the center of the pixel. + * + * (2) Find edge pixels in the bitmap (see `bsdf_is_edge` for more). For + * all edge pixels we use the Anti-aliased Euclidean distance + * transform algorithm and compute approximate edge distances (see + * `compute_edge_distance` and/or the second paper for more). + * + * (3) Now that we have computed approximate distances for edge pixels we + * use the 8SED algorithm to basically sweep the entire bitmap and + * compute distances for the rest of the pixels. (Since the algorithm + * is pretty convoluted it is only explained briefly in a comment to + * function `edt8`. To see the actual algorithm refer to the first + * paper.) + * + * (4) Finally, compute the sign for each pixel. This is done in function + * `finalize_sdf`. The basic idea is that if a pixel's original + * alpha/coverage value is greater than 0.5 then it is 'inside' (and + * 'outside' otherwise). + * + * Pseudo Code: + * + * ``` + * b = source bitmap; + * t = target bitmap; + * dm = list of distances; // dimension equal to b + * + * foreach grid_point (x, y) in b: + * { + * if (is_edge(x, y)): + * dm = approximate_edge_distance(b, x, y); + * + * // do the 8SED on the distances + * edt8(dm); + * + * // determine the signs + * determine_signs(dm): + * + * // copy SDF data to the target bitmap + * copy(dm to t); + * } + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bsdf + + + /************************************************************************** + * + * useful macros + * + */ + +#define ONE 65536 /* 1 in 16.16 */ + + + /************************************************************************** + * + * structs + * + */ + + + /************************************************************************** + * + * @Struct: + * BSDF_TRaster + * + * @Description: + * This struct is used in place of @FT_Raster and is stored within the + * internal FreeType renderer struct. While rasterizing this is passed + * to the @FT_Raster_RenderFunc function, which then can be used however + * we want. + * + * @Fields: + * memory :: + * Used internally to allocate intermediate memory while raterizing. + * + */ + typedef struct BSDF_TRaster_ + { + FT_Memory memory; + + } BSDF_TRaster, *BSDF_PRaster; + + + /************************************************************************** + * + * @Struct: + * ED + * + * @Description: + * Euclidean distance. It gets used for Euclidean distance transforms; + * it can also be interpreted as an edge distance. + * + * @Fields: + * dist :: + * Vector length of the `prox` parameter. Can be squared or absolute + * depending on the `USE_SQUARED_DISTANCES` macro defined in file + * `ftsdfcommon.h`. + * + * prox :: + * Vector to the nearest edge. Can also be interpreted as shortest + * distance of a point. + * + * alpha :: + * Alpha value of the original bitmap from which we generate SDF. + * Needed for computing the gradient and determining the proper sign + * of a pixel. + * + */ + typedef struct ED_ + { + FT_16D16 dist; + FT_16D16_Vec prox; + FT_Byte alpha; + + } ED; + + + /************************************************************************** + * + * @Struct: + * BSDF_Worker + * + * @Description: + * A convenience struct that is passed to functions while generating + * SDF; most of those functions require the same parameters. + * + * @Fields: + * distance_map :: + * A one-dimensional array that gets interpreted as two-dimensional + * one. It contains the Euclidean distances of all points of the + * bitmap. + * + * width :: + * Width of the above `distance_map`. + * + * rows :: + * Number of rows in the above `distance_map`. + * + * params :: + * Internal parameters and properties required by the rasterizer. See + * file `ftsdf.h` for more. + * + */ + typedef struct BSDF_Worker_ + { + ED* distance_map; + + FT_Int width; + FT_Int rows; + + SDF_Raster_Params params; + + } BSDF_Worker; + + + /************************************************************************** + * + * initializer + * + */ + + static const ED zero_ed = { 0, { 0, 0 }, 0 }; + + + /************************************************************************** + * + * rasterizer functions + * + */ + + /************************************************************************** + * + * @Function: + * bsdf_is_edge + * + * @Description: + * Check whether a pixel is an edge pixel, i.e., whether it is + * surrounded by a completely black pixel (zero alpha), and the current + * pixel is not a completely black pixel. + * + * @Input: + * dm :: + * Array of distances. The parameter must point to the current + * pixel, i.e., the pixel that is to be checked for being an edge. + * + * x :: + * The x position of the current pixel. + * + * y :: + * The y position of the current pixel. + * + * w :: + * Width of the bitmap. + * + * r :: + * Number of rows in the bitmap. + * + * @Return: + * 1~if the current pixel is an edge pixel, 0~otherwise. + * + */ + +#ifdef CHECK_NEIGHBOR +#undef CHECK_NEIGHBOR +#endif + +#define CHECK_NEIGHBOR( x_offset, y_offset ) \ + do \ + { \ + if ( x + x_offset >= 0 && x + x_offset < w && \ + y + y_offset >= 0 && y + y_offset < r ) \ + { \ + num_neighbors++; \ + \ + to_check = dm + y_offset * w + x_offset; \ + if ( to_check->alpha == 0 ) \ + { \ + is_edge = 1; \ + goto Done; \ + } \ + } \ + } while ( 0 ) + + static FT_Bool + bsdf_is_edge( ED* dm, /* distance map */ + FT_Int x, /* x index of point to check */ + FT_Int y, /* y index of point to check */ + FT_Int w, /* width */ + FT_Int r ) /* rows */ + { + FT_Bool is_edge = 0; + ED* to_check = NULL; + FT_Int num_neighbors = 0; + + + if ( dm->alpha == 0 ) + goto Done; + + if ( dm->alpha > 0 && dm->alpha < 255 ) + { + is_edge = 1; + goto Done; + } + + /* up */ + CHECK_NEIGHBOR( 0, -1 ); + + /* down */ + CHECK_NEIGHBOR( 0, 1 ); + + /* left */ + CHECK_NEIGHBOR( -1, 0 ); + + /* right */ + CHECK_NEIGHBOR( 1, 0 ); + + /* up left */ + CHECK_NEIGHBOR( -1, -1 ); + + /* up right */ + CHECK_NEIGHBOR( 1, -1 ); + + /* down left */ + CHECK_NEIGHBOR( -1, 1 ); + + /* down right */ + CHECK_NEIGHBOR( 1, 1 ); + + if ( num_neighbors != 8 ) + is_edge = 1; + + Done: + return is_edge; + } + +#undef CHECK_NEIGHBOR + + + /************************************************************************** + * + * @Function: + * compute_edge_distance + * + * @Description: + * Approximate the outline and compute the distance from `current` + * to the approximated outline. + * + * @Input: + * current :: + * Array of Euclidean distances. `current` must point to the position + * for which the distance is to be caculated. We treat this array as + * a two-dimensional array mapped to a one-dimensional array. + * + * x :: + * The x coordinate of the `current` parameter in the array. + * + * y :: + * The y coordinate of the `current` parameter in the array. + * + * w :: + * The width of the distances array. + * + * r :: + * Number of rows in the distances array. + * + * @Return: + * A vector pointing to the approximate edge distance. + * + * @Note: + * This is a computationally expensive function. Try to reduce the + * number of calls to this function. Moreover, this must only be used + * for edge pixel positions. + * + */ + static FT_16D16_Vec + compute_edge_distance( ED* current, + FT_Int x, + FT_Int y, + FT_Int w, + FT_Int r ) + { + /* + * This function, based on the paper presented by Stefan Gustavson and + * Robin Strand, gets used to approximate edge distances from + * anti-aliased bitmaps. + * + * The algorithm is as follows. + * + * (1) In anti-aliased images, the pixel's alpha value is the coverage + * of the pixel by the outline. For example, if the alpha value is + * 0.5f we can assume that the outline passes through the center of + * the pixel. + * + * (2) For this reason we can use that alpha value to approximate the real + * distance of the pixel to edge pretty accurately. A simple + * approximation is `(0.5f - alpha)`, assuming that the outline is + * parallel to the x or y~axis. However, in this algorithm we use a + * different approximation which is quite accurate even for + * non-axis-aligned edges. + * + * (3) The only remaining piece of information that we cannot + * approximate directly from the alpha is the direction of the edge. + * This is where we use Sobel's operator to compute the gradient of + * the pixel. The gradient give us a pretty good approximation of + * the edge direction. We use a 3x3 kernel filter to compute the + * gradient. + * + * (4) After the above two steps we have both the direction and the + * distance to the edge which is used to generate the Signed + * Distance Field. + * + * References: + * + * - Anti-Aliased Euclidean Distance Transform: + * http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf + * - Sobel Operator: + * https://en.wikipedia.org/wiki/Sobel_operator + */ + + FT_16D16_Vec g = { 0, 0 }; + FT_16D16 dist, current_alpha; + FT_16D16 a1, temp; + FT_16D16 gx, gy; + FT_16D16 alphas[9]; + + + /* Since our spread cannot be 0, this condition */ + /* can never be true. */ + if ( x <= 0 || x >= w - 1 || + y <= 0 || y >= r - 1 ) + return g; + + /* initialize the alphas */ + alphas[0] = 256 * (FT_16D16)current[-w - 1].alpha; + alphas[1] = 256 * (FT_16D16)current[-w ].alpha; + alphas[2] = 256 * (FT_16D16)current[-w + 1].alpha; + alphas[3] = 256 * (FT_16D16)current[ -1].alpha; + alphas[4] = 256 * (FT_16D16)current[ 0].alpha; + alphas[5] = 256 * (FT_16D16)current[ 1].alpha; + alphas[6] = 256 * (FT_16D16)current[ w - 1].alpha; + alphas[7] = 256 * (FT_16D16)current[ w ].alpha; + alphas[8] = 256 * (FT_16D16)current[ w + 1].alpha; + + current_alpha = alphas[4]; + + /* Compute the gradient using the Sobel operator. */ + /* In this case we use the following 3x3 filters: */ + /* */ + /* For x: | -1 0 -1 | */ + /* | -root(2) 0 root(2) | */ + /* | -1 0 1 | */ + /* */ + /* For y: | -1 -root(2) -1 | */ + /* | 0 0 0 | */ + /* | 1 root(2) 1 | */ + /* */ + /* [Note]: 92681 is root(2) in 16.16 format. */ + g.x = -alphas[0] - + FT_MulFix( alphas[3], 92681 ) - + alphas[6] + + alphas[2] + + FT_MulFix( alphas[5], 92681 ) + + alphas[8]; + + g.y = -alphas[0] - + FT_MulFix( alphas[1], 92681 ) - + alphas[2] + + alphas[6] + + FT_MulFix( alphas[7], 92681 ) + + alphas[8]; + + FT_Vector_NormLen( &g ); + + /* The gradient gives us the direction of the */ + /* edge for the current pixel. Once we have the */ + /* approximate direction of the edge, we can */ + /* approximate the edge distance much better. */ + + if ( g.x == 0 || g.y == 0 ) + dist = ONE / 2 - alphas[4]; + else + { + gx = g.x; + gy = g.y; + + gx = FT_ABS( gx ); + gy = FT_ABS( gy ); + + if ( gx < gy ) + { + temp = gx; + gx = gy; + gy = temp; + } + + a1 = FT_DivFix( gy, gx ) / 2; + + if ( current_alpha < a1 ) + dist = ( gx + gy ) / 2 - + square_root( 2 * FT_MulFix( gx, + FT_MulFix( gy, + current_alpha ) ) ); + + else if ( current_alpha < ( ONE - a1 ) ) + dist = FT_MulFix( ONE / 2 - current_alpha, gx ); + + else + dist = -( gx + gy ) / 2 + + square_root( 2 * FT_MulFix( gx, + FT_MulFix( gy, + ONE - current_alpha ) ) ); + } + + g.x = FT_MulFix( g.x, dist ); + g.y = FT_MulFix( g.y, dist ); + + return g; + } + + + /************************************************************************** + * + * @Function: + * bsdf_approximate_edge + * + * @Description: + * Loops over all the pixels and call `compute_edge_distance` only for + * edge pixels. This maked the process a lot faster since + * `compute_edge_distance` uses functions such as `FT_Vector_NormLen', + * which are quite slow. + * + * @InOut: + * worker :: + * Contains the distance map as well as all the relevant parameters + * required by the function. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function directly manipulates `worker->distance_map`. + * + */ + static FT_Error + bsdf_approximate_edge( BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + FT_Int i, j; + FT_Int index; + ED* ed; + + + if ( !worker || !worker->distance_map ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + ed = worker->distance_map; + + for ( j = 0; j < worker->rows; j++ ) + { + for ( i = 0; i < worker->width; i++ ) + { + index = j * worker->width + i; + + if ( bsdf_is_edge( worker->distance_map + index, + i, j, + worker->width, + worker->rows ) ) + { + /* approximate the edge distance for edge pixels */ + ed[index].prox = compute_edge_distance( ed + index, + i, j, + worker->width, + worker->rows ); + ed[index].dist = VECTOR_LENGTH_16D16( ed[index].prox ); + } + else + { + /* for non-edge pixels assign far away distances */ + ed[index].dist = 400 * ONE; + ed[index].prox.x = 200 * ONE; + ed[index].prox.y = 200 * ONE; + } + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * bsdf_init_distance_map + * + * @Description: + * Initialize the distance map according to the '8-point sequential + * Euclidean distance mapping' (8SED) algorithm. Basically it copies + * the `source` bitmap alpha values to the `distance_map->alpha` + * parameter of `worker`. + * + * @Input: + * source :: + * Source bitmap to copy the data from. + * + * @Output: + * worker :: + * Target distance map to copy the data to. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + bsdf_init_distance_map( const FT_Bitmap* source, + BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + + FT_Int x_diff, y_diff; + FT_Int t_i, t_j, s_i, s_j; + FT_Byte* s; + ED* t; + + + /* again check the parameters (probably unnecessary) */ + if ( !source || !worker ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* Because of the way we convert a bitmap to SDF, */ + /* i.e., aligning the source to the center of the */ + /* target, the target's width and rows must be */ + /* checked before copying. */ + if ( worker->width < (FT_Int)source->width || + worker->rows < (FT_Int)source->rows ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check pixel mode */ + if ( source->pixel_mode == FT_PIXEL_MODE_NONE ) + { + FT_ERROR(( "bsdf_copy_source_to_target:" + " Invalid pixel mode of source bitmap" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( source->pixel_mode == FT_PIXEL_MODE_MONO ) + { + FT_TRACE0(( "bsdf_copy_source_to_target:" + " The `bsdf' renderer can convert monochrome\n" )); + FT_TRACE0(( " " + " bitmaps to SDF but the results are not perfect\n" )); + FT_TRACE0(( " " + " because there is no way to approximate actual\n" )); + FT_TRACE0(( " " + " outlines from monochrome bitmaps. Consider\n" )); + FT_TRACE0(( " " + " using an anti-aliased bitmap instead.\n" )); + } +#endif + + /* Calculate the width and row differences */ + /* between target and source. */ + x_diff = worker->width - (int)source->width; + y_diff = worker->rows - (int)source->rows; + + x_diff /= 2; + y_diff /= 2; + + t = (ED*)worker->distance_map; + s = source->buffer; + + /* For now we only support pixel mode `FT_PIXEL_MODE_MONO` */ + /* and `FT_PIXEL_MODE_GRAY`. More will be added later. */ + /* */ + /* [NOTE]: We can also use @FT_Bitmap_Convert to convert */ + /* bitmap to 8bpp. To avoid extra allocation and */ + /* since the target bitmap can be 16bpp we manually */ + /* convert the source bitmap to the desired bpp. */ + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + FT_Int t_width = worker->width; + FT_Int t_rows = worker->rows; + FT_Int s_width = (int)source->width; + FT_Int s_rows = (int)source->rows; + + + for ( t_j = 0; t_j < t_rows; t_j++ ) + { + for ( t_i = 0; t_i < t_width; t_i++ ) + { + FT_Int t_index = t_j * t_width + t_i; + FT_Int s_index; + FT_Int div, mod; + FT_Byte pixel, byte; + + + t[t_index] = zero_ed; + + s_i = t_i - x_diff; + s_j = t_j - y_diff; + + /* Assign 0 to padding similar to */ + /* the source bitmap. */ + if ( s_i < 0 || s_i >= s_width || + s_j < 0 || s_j >= s_rows ) + continue; + + if ( worker->params.flip_y ) + s_index = ( s_rows - s_j - 1 ) * source->pitch; + else + s_index = s_j * source->pitch; + + div = s_index + s_i / 8; + mod = 7 - s_i % 8; + + pixel = s[div]; + byte = (FT_Byte)( 1 << mod ); + + t[t_index].alpha = pixel & byte ? 255 : 0; + } + } + } + break; + + case FT_PIXEL_MODE_GRAY: + { + FT_Int t_width = worker->width; + FT_Int t_rows = worker->rows; + FT_Int s_width = (int)source->width; + FT_Int s_rows = (int)source->rows; + + + /* loop over all pixels and assign pixel values from source */ + for ( t_j = 0; t_j < t_rows; t_j++ ) + { + for ( t_i = 0; t_i < t_width; t_i++ ) + { + FT_Int t_index = t_j * t_width + t_i; + FT_Int s_index; + + + t[t_index] = zero_ed; + + s_i = t_i - x_diff; + s_j = t_j - y_diff; + + /* Assign 0 to padding similar to */ + /* the source bitmap. */ + if ( s_i < 0 || s_i >= s_width || + s_j < 0 || s_j >= s_rows ) + continue; + + if ( worker->params.flip_y ) + s_index = ( s_rows - s_j - 1 ) * s_width + s_i; + else + s_index = s_j * s_width + s_i; + + /* simply copy the alpha values */ + t[t_index].alpha = s[s_index]; + } + } + } + break; + + default: + FT_ERROR(( "bsdf_copy_source_to_target:" + " unsopported pixel mode of source bitmap\n" )); + + error = FT_THROW( Unimplemented_Feature ); + break; + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * compare_neighbor + * + * @Description: + * Compare neighbor pixel (which is defined by the offset) and update + * `current` distance if the new distance is shorter than the original. + * + * @Input: + * x_offset :: + * X offset of the neighbor to be checked. The offset is relative to + * the `current`. + * + * y_offset :: + * Y offset of the neighbor to be checked. The offset is relative to + * the `current`. + * + * width :: + * Width of the `current` array. + * + * @InOut: + * current :: + * Pointer into array of distances. This parameter must point to the + * position whose neighbor is to be checked. The array is treated as + * a two-dimensional array. + * + */ + static void + compare_neighbor( ED* current, + FT_Int x_offset, + FT_Int y_offset, + FT_Int width ) + { + ED* to_check; + FT_16D16 dist; + FT_16D16_Vec dist_vec; + + + to_check = current + ( y_offset * width ) + x_offset; + + /* + * While checking for the nearest point we first approximate the + * distance of `current` by adding the deviation (which is sqrt(2) at + * most). Only if the new value is less than the current value we + * calculate the actual distances using `FT_Vector_Length`. This last + * step can be omitted by using squared distances. + */ + + /* + * Approximate the distance. We subtract 1 to avoid precision errors, + * which could happen because the two directions can be opposite. + */ + dist = to_check->dist - ONE; + + if ( dist < current->dist ) + { + dist_vec = to_check->prox; + + dist_vec.x += x_offset * ONE; + dist_vec.y += y_offset * ONE; + dist = VECTOR_LENGTH_16D16( dist_vec ); + + if ( dist < current->dist ) + { + current->dist = dist; + current->prox = dist_vec; + } + } + } + + + /************************************************************************** + * + * @Function: + * first_pass + * + * @Description: + * First pass of the 8SED algorithm. Loop over the bitmap from top to + * bottom and scan each row left to right, updating the distances in + * `worker->distance_map`. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + */ + static void + first_pass( BSDF_Worker* worker ) + { + FT_Int i, j; /* iterators */ + FT_Int w, r; /* width, rows */ + ED* dm; /* distance map */ + + + dm = worker->distance_map; + w = worker->width; + r = worker->rows; + + /* Start scanning from top to bottom and sweep each */ + /* row back and forth comparing the distances of the */ + /* neighborhood. Leave the first row as it has no top */ + /* neighbor; it will be covered in the second scan of */ + /* the image (from bottom to top). */ + for ( j = 1; j < r; j++ ) + { + FT_Int index; + ED* current; + + + /* Forward pass of rows (left -> right). Leave the first */ + /* column, which gets covered in the backward pass. */ + for ( i = 1; i < w - 1; i++ ) + { + index = j * w + i; + current = dm + index; + + /* left-up */ + compare_neighbor( current, -1, -1, w ); + /* up */ + compare_neighbor( current, 0, -1, w ); + /* up-right */ + compare_neighbor( current, 1, -1, w ); + /* left */ + compare_neighbor( current, -1, 0, w ); + } + + /* Backward pass of rows (right -> left). Leave the last */ + /* column, which was already covered in the forward pass. */ + for ( i = w - 2; i >= 0; i-- ) + { + index = j * w + i; + current = dm + index; + + /* right */ + compare_neighbor( current, 1, 0, w ); + } + } + } + + + /************************************************************************** + * + * @Function: + * second_pass + * + * @Description: + * Second pass of the 8SED algorithm. Loop over the bitmap from bottom + * to top and scan each row left to right, updating the distances in + * `worker->distance_map`. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + */ + static void + second_pass( BSDF_Worker* worker ) + { + FT_Int i, j; /* iterators */ + FT_Int w, r; /* width, rows */ + ED* dm; /* distance map */ + + + dm = worker->distance_map; + w = worker->width; + r = worker->rows; + + /* Start scanning from bottom to top and sweep each */ + /* row back and forth comparing the distances of the */ + /* neighborhood. Leave the last row as it has no down */ + /* neighbor; it is already covered in the first scan */ + /* of the image (from top to bottom). */ + for ( j = r - 2; j >= 0; j-- ) + { + FT_Int index; + ED* current; + + + /* Forward pass of rows (left -> right). Leave the first */ + /* column, which gets covered in the backward pass. */ + for ( i = 1; i < w - 1; i++ ) + { + index = j * w + i; + current = dm + index; + + /* left-up */ + compare_neighbor( current, -1, 1, w ); + /* up */ + compare_neighbor( current, 0, 1, w ); + /* up-right */ + compare_neighbor( current, 1, 1, w ); + /* left */ + compare_neighbor( current, -1, 0, w ); + } + + /* Backward pass of rows (right -> left). Leave the last */ + /* column, which was already covered in the forward pass. */ + for ( i = w - 2; i >= 0; i-- ) + { + index = j * w + i; + current = dm + index; + + /* right */ + compare_neighbor( current, 1, 0, w ); + } + } + } + + + /************************************************************************** + * + * @Function: + * edt8 + * + * @Description: + * Compute the distance map of the a bitmap. Execute both first and + * second pass of the 8SED algorithm. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + edt8( BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + + + if ( !worker || !worker->distance_map ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* first scan of the image */ + first_pass( worker ); + + /* second scan of the image */ + second_pass( worker ); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * finalize_sdf + * + * @Description: + * Copy the SDF data from `worker->distance_map` to the `target` bitmap. + * Also transform the data to output format, (which is 6.10 fixed-point + * format at the moment). + * + * @Input: + * worker :: + * Contains source distance map and other SDF data. + * + * @Output: + * target :: + * Target bitmap to which the SDF data is copied to. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + finalize_sdf( BSDF_Worker* worker, + const FT_Bitmap* target ) + { + FT_Error error = FT_Err_Ok; + + FT_Int w, r; + FT_Int i, j; + + FT_SDFFormat* t_buffer; + FT_16D16 sp_sq, spread; + + + if ( !worker || !target ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + w = (int)target->width; + r = (int)target->rows; + t_buffer = (FT_SDFFormat*)target->buffer; + + if ( w != worker->width || + r != worker->rows ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + spread = (FT_16D16)FT_INT_16D16( worker->params.spread ); + +#if USE_SQUARED_DISTANCES + sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread * + worker->params.spread ); +#else + sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread ); +#endif + + for ( j = 0; j < r; j++ ) + { + for ( i = 0; i < w; i++ ) + { + FT_Int index; + FT_16D16 dist; + FT_SDFFormat final_dist; + FT_Char sign; + + + index = j * w + i; + dist = worker->distance_map[index].dist; + + if ( dist < 0 || dist > sp_sq ) + dist = sp_sq; + +#if USE_SQUARED_DISTANCES + dist = square_root( dist ); +#endif + + /* We assume that if the pixel is inside a contour */ + /* its coverage value must be > 127. */ + sign = worker->distance_map[index].alpha < 127 ? -1 : 1; + + /* flip the sign according to the property */ + if ( worker->params.flip_sign ) + sign = -sign; + + /* concatenate from 16.16 to appropriate format */ + final_dist = map_fixed_to_sdf( dist * sign, spread ); + + t_buffer[index] = final_dist; + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * interface functions + * + */ + + /* called when adding a new module through @FT_Add_Module */ + static FT_Error + bsdf_raster_new( void* memory_, /* FT_Memory */ + FT_Raster* araster_ ) /* BSDF_PRaster* */ + { + FT_Memory memory = (FT_Memory)memory_; + BSDF_PRaster* araster = (BSDF_PRaster*)araster_; + + FT_Error error; + BSDF_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + /* unused */ + static void + bsdf_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + /* unused */ + static FT_Error + bsdf_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return FT_Err_Ok; + } + + + /* called while rendering through @FT_Render_Glyph */ + static FT_Error + bsdf_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + const FT_Bitmap* source = NULL; + const FT_Bitmap* target = NULL; + + BSDF_TRaster* bsdf_raster = (BSDF_TRaster*)raster; + BSDF_Worker worker; + + const SDF_Raster_Params* sdf_params = (const SDF_Raster_Params*)params; + + + worker.distance_map = NULL; + + /* check for valid parameters */ + if ( !raster || !params ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check whether the flag is set */ + if ( sdf_params->root.flags != FT_RASTER_FLAG_SDF ) + { + error = FT_THROW( Raster_Corrupted ); + goto Exit; + } + + source = (const FT_Bitmap*)sdf_params->root.source; + target = (const FT_Bitmap*)sdf_params->root.target; + + /* check source and target bitmap */ + if ( !source || !target ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = bsdf_raster->memory; + if ( !memory ) + { + FT_TRACE0(( "bsdf_raster_render: Raster not set up properly,\n" )); + FT_TRACE0(( " unable to find memory handle.\n" )); + + error = FT_THROW( Invalid_Handle ); + goto Exit; + } + + /* check whether spread is set properly */ + if ( sdf_params->spread > MAX_SPREAD || + sdf_params->spread < MIN_SPREAD ) + { + FT_TRACE0(( "bsdf_raster_render:" + " The `spread' field of `SDF_Raster_Params'\n" )); + FT_TRACE0(( " " + " is invalid; the value of this field must be\n" )); + FT_TRACE0(( " " + " within [%d, %d].\n", + MIN_SPREAD, MAX_SPREAD )); + FT_TRACE0(( " " + " Also, you must pass `SDF_Raster_Params'\n" )); + FT_TRACE0(( " " + " instead of the default `FT_Raster_Params'\n" )); + FT_TRACE0(( " " + " while calling this function and set the fields\n" )); + FT_TRACE0(( " " + " accordingly.\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* set up the worker */ + + /* allocate the distance map */ + if ( FT_QALLOC_MULT( worker.distance_map, target->rows, + target->width * sizeof ( *worker.distance_map ) ) ) + goto Exit; + + worker.width = (int)target->width; + worker.rows = (int)target->rows; + worker.params = *sdf_params; + + FT_CALL( bsdf_init_distance_map( source, &worker ) ); + FT_CALL( bsdf_approximate_edge( &worker ) ); + FT_CALL( edt8( &worker ) ); + FT_CALL( finalize_sdf( &worker, target ) ); + + FT_TRACE0(( "bsdf_raster_render: Total memory used = %ld\n", + worker.width * worker.rows * + (long)sizeof ( *worker.distance_map ) )); + + Exit: + if ( worker.distance_map ) + FT_FREE( worker.distance_map ); + + return error; + } + + + /* called while deleting `FT_Library` only if the module is added */ + static void + bsdf_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((BSDF_TRaster*)raster)->memory; + + + FT_FREE( raster ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_bitmap_sdf_raster, + + FT_GLYPH_FORMAT_BITMAP, + + (FT_Raster_New_Func) bsdf_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) bsdf_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)bsdf_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) bsdf_raster_render, /* raster_render */ + (FT_Raster_Done_Func) bsdf_raster_done /* raster_done */ + ) + + +/* END */ diff --git a/vendor/freetype/src/sdf/ftsdf.c b/vendor/freetype/src/sdf/ftsdf.c new file mode 100644 index 0000000..bc4625d --- /dev/null +++ b/vendor/freetype/src/sdf/ftsdf.c @@ -0,0 +1,3932 @@ +/**************************************************************************** + * + * ftsdf.c + * + * Signed Distance Field support for outline fonts (body). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include "ftsdf.h" + +#include "ftsdferrs.h" + + + /************************************************************************** + * + * A brief technical overview of how the SDF rasterizer works + * ---------------------------------------------------------- + * + * [Notes]: + * * SDF stands for Signed Distance Field everywhere. + * + * * This renderer generates SDF directly from outlines. There is + * another renderer called 'bsdf', which converts bitmaps to SDF; see + * file `ftbsdf.c` for more. + * + * * The basic idea of generating the SDF is taken from Viktor Chlumsky's + * research paper. The paper explains both single and multi-channel + * SDF, however, this implementation only generates single-channel SDF. + * + * Chlumsky, Viktor: Shape Decomposition for Multi-channel Distance + * Fields. Master's thesis. Czech Technical University in Prague, + * Faculty of InformationTechnology, 2015. + * + * For more information: https://github.com/Chlumsky/msdfgen + * + * ======================================================================== + * + * Generating SDF from outlines is pretty straightforward. + * + * (1) We have a set of contours that make the outline of a shape/glyph. + * Each contour comprises of several edges, with three types of edges. + * + * * line segments + * * conic Bezier curves + * * cubic Bezier curves + * + * (2) Apart from the outlines we also have a two-dimensional grid, namely + * the bitmap that is used to represent the final SDF data. + * + * (3) In order to generate SDF, our task is to find shortest signed + * distance from each grid point to the outline. The 'signed + * distance' means that if the grid point is filled by any contour + * then its sign is positive, otherwise it is negative. The pseudo + * code is as follows. + * + * ``` + * foreach grid_point (x, y): + * { + * int min_dist = INT_MAX; + * + * foreach contour in outline: + * { + * foreach edge in contour: + * { + * // get shortest distance from point (x, y) to the edge + * d = get_min_dist(x, y, edge); + * + * if (d < min_dist) + * min_dist = d; + * } + * + * bitmap[x, y] = min_dist; + * } + * } + * ``` + * + * (4) After running this algorithm the bitmap contains information about + * the shortest distance from each point to the outline of the shape. + * Of course, while this is the most straightforward way of generating + * SDF, we use various optimizations in our implementation. See the + * `sdf_generate_*' functions in this file for all details. + * + * The optimization currently used by default is subdivision; see + * function `sdf_generate_subdivision` for more. + * + * Also, to see how we compute the shortest distance from a point to + * each type of edge, check out the `get_min_distance_*' functions. + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sdf + + + /************************************************************************** + * + * definitions + * + */ + + /* + * If set to 1, the rasterizer uses Newton-Raphson's method for finding + * the shortest distance from a point to a conic curve. + * + * If set to 0, an analytical method gets used instead, which computes the + * roots of a cubic polynomial to find the shortest distance. However, + * the analytical method can currently underflow; we thus use Newton's + * method by default. + */ +#ifndef USE_NEWTON_FOR_CONIC +#define USE_NEWTON_FOR_CONIC 1 +#endif + + /* + * The number of intervals a Bezier curve gets sampled and checked to find + * the shortest distance. + */ +#define MAX_NEWTON_DIVISIONS 4 + + /* + * The number of steps of Newton's iterations in each interval of the + * Bezier curve. Basically, we run Newton's approximation + * + * x -= Q(t) / Q'(t) + * + * for each division to get the shortest distance. + */ +#define MAX_NEWTON_STEPS 4 + + /* + * The epsilon distance (in 16.16 fractional units) used for corner + * resolving. If the difference of two distances is less than this value + * they will be checked for a corner if they are ambiguous. + */ +#define CORNER_CHECK_EPSILON 32 + +#if 0 + /* + * Coarse grid dimension. Will probably be removed in the future because + * coarse grid optimization is the slowest algorithm. + */ +#define CG_DIMEN 8 +#endif + + + /************************************************************************** + * + * macros + * + */ + +#define MUL_26D6( a, b ) ( ( ( a ) * ( b ) ) / 64 ) +#define VEC_26D6_DOT( p, q ) ( MUL_26D6( p.x, q.x ) + \ + MUL_26D6( p.y, q.y ) ) + + + /************************************************************************** + * + * structures and enums + * + */ + + /************************************************************************** + * + * @Struct: + * SDF_TRaster + * + * @Description: + * This struct is used in place of @FT_Raster and is stored within the + * internal FreeType renderer struct. While rasterizing it is passed to + * the @FT_Raster_RenderFunc function, which then can be used however we + * want. + * + * @Fields: + * memory :: + * Used internally to allocate intermediate memory while raterizing. + * + */ + typedef struct SDF_TRaster_ + { + FT_Memory memory; + + } SDF_TRaster, *SDF_PRaster; + + + /************************************************************************** + * + * @Enum: + * SDF_Edge_Type + * + * @Description: + * Enumeration of all curve types present in fonts. + * + * @Fields: + * SDF_EDGE_UNDEFINED :: + * Undefined edge, simply used to initialize and detect errors. + * + * SDF_EDGE_LINE :: + * Line segment with start and end point. + * + * SDF_EDGE_CONIC :: + * A conic/quadratic Bezier curve with start, end, and one control + * point. + * + * SDF_EDGE_CUBIC :: + * A cubic Bezier curve with start, end, and two control points. + * + */ + typedef enum SDF_Edge_Type_ + { + SDF_EDGE_UNDEFINED = 0, + SDF_EDGE_LINE = 1, + SDF_EDGE_CONIC = 2, + SDF_EDGE_CUBIC = 3 + + } SDF_Edge_Type; + + + /************************************************************************** + * + * @Enum: + * SDF_Contour_Orientation + * + * @Description: + * Enumeration of all orientation values of a contour. We determine the + * orientation by calculating the area covered by a contour. Contrary + * to values returned by @FT_Outline_Get_Orientation, + * `SDF_Contour_Orientation` is independent of the fill rule, which can + * be different for different font formats. + * + * @Fields: + * SDF_ORIENTATION_NONE :: + * Undefined orientation, used for initialization and error detection. + * + * SDF_ORIENTATION_CW :: + * Clockwise orientation (positive area covered). + * + * SDF_ORIENTATION_CCW :: + * Counter-clockwise orientation (negative area covered). + * + * @Note: + * See @FT_Outline_Get_Orientation for more details. + * + */ + typedef enum SDF_Contour_Orientation_ + { + SDF_ORIENTATION_NONE = 0, + SDF_ORIENTATION_CW = 1, + SDF_ORIENTATION_CCW = 2 + + } SDF_Contour_Orientation; + + + /************************************************************************** + * + * @Struct: + * SDF_Edge + * + * @Description: + * Represent an edge of a contour. + * + * @Fields: + * start_pos :: + * Start position of an edge. Valid for all types of edges. + * + * end_pos :: + * Etart position of an edge. Valid for all types of edges. + * + * control_a :: + * A control point of the edge. Valid only for `SDF_EDGE_CONIC` + * and `SDF_EDGE_CUBIC`. + * + * control_b :: + * Another control point of the edge. Valid only for + * `SDF_EDGE_CONIC`. + * + * edge_type :: + * Type of the edge, see @SDF_Edge_Type for all possible edge types. + * + * next :: + * Used to create a singly linked list, which can be interpreted + * as a contour. + * + */ + typedef struct SDF_Edge_ + { + FT_26D6_Vec start_pos; + FT_26D6_Vec end_pos; + FT_26D6_Vec control_a; + FT_26D6_Vec control_b; + + SDF_Edge_Type edge_type; + + struct SDF_Edge_* next; + + } SDF_Edge; + + + /************************************************************************** + * + * @Struct: + * SDF_Contour + * + * @Description: + * Represent a complete contour, which contains a list of edges. + * + * @Fields: + * last_pos :: + * Contains the value of `end_pos' of the last edge in the list of + * edges. Useful while decomposing the outline with + * @FT_Outline_Decompose. + * + * edges :: + * Linked list of all the edges that make the contour. + * + * next :: + * Used to create a singly linked list, which can be interpreted as a + * complete shape or @FT_Outline. + * + */ + typedef struct SDF_Contour_ + { + FT_26D6_Vec last_pos; + SDF_Edge* edges; + + struct SDF_Contour_* next; + + } SDF_Contour; + + + /************************************************************************** + * + * @Struct: + * SDF_Shape + * + * @Description: + * Represent a complete shape, which is the decomposition of + * @FT_Outline. + * + * @Fields: + * memory :: + * Used internally to allocate memory. + * + * contours :: + * Linked list of all the contours that make the shape. + * + */ + typedef struct SDF_Shape_ + { + FT_Memory memory; + SDF_Contour* contours; + + } SDF_Shape; + + + /************************************************************************** + * + * @Struct: + * SDF_Signed_Distance + * + * @Description: + * Represent signed distance of a point, i.e., the distance of the edge + * nearest to the point. + * + * @Fields: + * distance :: + * Distance of the point from the nearest edge. Can be squared or + * absolute depending on the `USE_SQUARED_DISTANCES` macro defined in + * file `ftsdfcommon.h`. + * + * cross :: + * Cross product of the shortest distance vector (i.e., the vector + * from the point to the nearest edge) and the direction of the edge + * at the nearest point. This is used to resolve ambiguities of + * `sign`. + * + * sign :: + * A value used to indicate whether the distance vector is outside or + * inside the contour corresponding to the edge. + * + * @Note: + * `sign` may or may not be correct, therefore it must be checked + * properly in case there is an ambiguity. + * + */ + typedef struct SDF_Signed_Distance_ + { + FT_16D16 distance; + FT_16D16 cross; + FT_Char sign; + + } SDF_Signed_Distance; + + + /************************************************************************** + * + * @Struct: + * SDF_Params + * + * @Description: + * Yet another internal parameters required by the rasterizer. + * + * @Fields: + * orientation :: + * This is not the @SDF_Contour_Orientation value but @FT_Orientation, + * which determines whether clockwise-oriented outlines are to be + * filled or counter-clockwise-oriented ones. + * + * flip_sign :: + * If set to true, flip the sign. By default the points filled by the + * outline are positive. + * + * flip_y :: + * If set to true the output bitmap is upside-down. Can be useful + * because OpenGL and DirectX use different coordinate systems for + * textures. + * + * overload_sign :: + * In the subdivision and bounding box optimization, the default + * outside sign is taken as -1. This parameter can be used to modify + * that behaviour. For example, while generating SDF for a single + * counter-clockwise contour, the outside sign should be 1. + * + */ + typedef struct SDF_Params_ + { + FT_Orientation orientation; + FT_Bool flip_sign; + FT_Bool flip_y; + + FT_Int overload_sign; + + } SDF_Params; + + + /************************************************************************** + * + * constants, initializer, and destructor + * + */ + + static + const FT_Vector zero_vector = { 0, 0 }; + + static + const SDF_Edge null_edge = { { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, + SDF_EDGE_UNDEFINED, NULL }; + + static + const SDF_Contour null_contour = { { 0, 0 }, NULL, NULL }; + + static + const SDF_Shape null_shape = { NULL, NULL }; + + static + const SDF_Signed_Distance max_sdf = { INT_MAX, 0, 0 }; + + + /* Create a new @SDF_Edge on the heap and assigns the `edge` */ + /* pointer to the newly allocated memory. */ + static FT_Error + sdf_edge_new( FT_Memory memory, + SDF_Edge** edge ) + { + FT_Error error = FT_Err_Ok; + SDF_Edge* ptr = NULL; + + + if ( !memory || !edge ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_edge; + *edge = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `edge` variable. */ + static void + sdf_edge_done( FT_Memory memory, + SDF_Edge** edge ) + { + if ( !memory || !edge || !*edge ) + return; + + FT_FREE( *edge ); + } + + + /* Create a new @SDF_Contour on the heap and assign */ + /* the `contour` pointer to the newly allocated memory. */ + static FT_Error + sdf_contour_new( FT_Memory memory, + SDF_Contour** contour ) + { + FT_Error error = FT_Err_Ok; + SDF_Contour* ptr = NULL; + + + if ( !memory || !contour ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_contour; + *contour = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `contour` variable. */ + /* Also free the list of edges. */ + static void + sdf_contour_done( FT_Memory memory, + SDF_Contour** contour ) + { + SDF_Edge* edges; + SDF_Edge* temp; + + + if ( !memory || !contour || !*contour ) + return; + + edges = (*contour)->edges; + + /* release all edges */ + while ( edges ) + { + temp = edges; + edges = edges->next; + + sdf_edge_done( memory, &temp ); + } + + FT_FREE( *contour ); + } + + + /* Create a new @SDF_Shape on the heap and assign */ + /* the `shape` pointer to the newly allocated memory. */ + static FT_Error + sdf_shape_new( FT_Memory memory, + SDF_Shape** shape ) + { + FT_Error error = FT_Err_Ok; + SDF_Shape* ptr = NULL; + + + if ( !memory || !shape ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_shape; + ptr->memory = memory; + *shape = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `shape` variable. */ + /* Also free the list of contours. */ + static void + sdf_shape_done( SDF_Shape** shape ) + { + FT_Memory memory; + SDF_Contour* contours; + SDF_Contour* temp; + + + if ( !shape || !*shape ) + return; + + memory = (*shape)->memory; + contours = (*shape)->contours; + + if ( !memory ) + return; + + /* release all contours */ + while ( contours ) + { + temp = contours; + contours = contours->next; + + sdf_contour_done( memory, &temp ); + } + + /* release the allocated shape struct */ + FT_FREE( *shape ); + } + + + /************************************************************************** + * + * shape decomposition functions + * + */ + + /* This function is called when starting a new contour at `to`, */ + /* which gets added to the shape's list. */ + static FT_Error + sdf_move_to( const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_CALL( sdf_contour_new( memory, &contour ) ); + + contour->last_pos = *to; + contour->next = shape->contours; + shape->contours = contour; + + Exit: + return error; + } + + + /* This function is called when there is a line in the */ + /* contour. The line starts at the previous edge point and */ + /* stops at `to`. */ + static FT_Error + sdf_line_to( const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + if ( contour->last_pos.x == to->x && + contour->last_pos.y == to->y ) + goto Exit; + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_LINE; + edge->start_pos = contour->last_pos; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* This function is called when there is a conic Bezier curve */ + /* in the contour. The curve starts at the previous edge point */ + /* and stops at `to`, with control point `control_1`. */ + static FT_Error + sdf_conic_to( const FT_26D6_Vec* control_1, + const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !control_1 || !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + /* If the control point coincides with any of the end points */ + /* then it is a line and should be treated as one to avoid */ + /* unnecessary complexity later in the algorithm. */ + if ( ( contour->last_pos.x == control_1->x && + contour->last_pos.y == control_1->y ) || + ( control_1->x == to->x && + control_1->y == to->y ) ) + { + sdf_line_to( to, user ); + goto Exit; + } + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_CONIC; + edge->start_pos = contour->last_pos; + edge->control_a = *control_1; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* This function is called when there is a cubic Bezier curve */ + /* in the contour. The curve starts at the previous edge point */ + /* and stops at `to`, with two control points `control_1` and */ + /* `control_2`. */ + static FT_Error + sdf_cubic_to( const FT_26D6_Vec* control_1, + const FT_26D6_Vec* control_2, + const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !control_2 || !control_1 || !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_CUBIC; + edge->start_pos = contour->last_pos; + edge->control_a = *control_1; + edge->control_b = *control_2; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* Construct the structure to hold all four outline */ + /* decomposition functions. */ + FT_DEFINE_OUTLINE_FUNCS( + sdf_decompose_funcs, + + (FT_Outline_MoveTo_Func) sdf_move_to, /* move_to */ + (FT_Outline_LineTo_Func) sdf_line_to, /* line_to */ + (FT_Outline_ConicTo_Func)sdf_conic_to, /* conic_to */ + (FT_Outline_CubicTo_Func)sdf_cubic_to, /* cubic_to */ + + 0, /* shift */ + 0 /* delta */ + ) + + + /* Decompose `outline` and put it into the `shape` structure. */ + static FT_Error + sdf_outline_decompose( FT_Outline* outline, + SDF_Shape* shape ) + { + FT_Error error = FT_Err_Ok; + + + if ( !outline || !shape ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = FT_Outline_Decompose( outline, + &sdf_decompose_funcs, + (void*)shape ); + + Exit: + return error; + } + + + /************************************************************************** + * + * utility functions + * + */ + + /* Return the control box of an edge. The control box is a rectangle */ + /* in which all the control points can fit tightly. */ + static FT_CBox + get_control_box( SDF_Edge edge ) + { + FT_CBox cbox = { 0, 0, 0, 0 }; + FT_Bool is_set = 0; + + + switch ( edge.edge_type ) + { + case SDF_EDGE_CUBIC: + cbox.xMin = edge.control_b.x; + cbox.xMax = edge.control_b.x; + cbox.yMin = edge.control_b.y; + cbox.yMax = edge.control_b.y; + + is_set = 1; + FALL_THROUGH; + + case SDF_EDGE_CONIC: + if ( is_set ) + { + cbox.xMin = edge.control_a.x < cbox.xMin + ? edge.control_a.x + : cbox.xMin; + cbox.xMax = edge.control_a.x > cbox.xMax + ? edge.control_a.x + : cbox.xMax; + + cbox.yMin = edge.control_a.y < cbox.yMin + ? edge.control_a.y + : cbox.yMin; + cbox.yMax = edge.control_a.y > cbox.yMax + ? edge.control_a.y + : cbox.yMax; + } + else + { + cbox.xMin = edge.control_a.x; + cbox.xMax = edge.control_a.x; + cbox.yMin = edge.control_a.y; + cbox.yMax = edge.control_a.y; + + is_set = 1; + } + FALL_THROUGH; + + case SDF_EDGE_LINE: + if ( is_set ) + { + cbox.xMin = edge.start_pos.x < cbox.xMin + ? edge.start_pos.x + : cbox.xMin; + cbox.xMax = edge.start_pos.x > cbox.xMax + ? edge.start_pos.x + : cbox.xMax; + + cbox.yMin = edge.start_pos.y < cbox.yMin + ? edge.start_pos.y + : cbox.yMin; + cbox.yMax = edge.start_pos.y > cbox.yMax + ? edge.start_pos.y + : cbox.yMax; + } + else + { + cbox.xMin = edge.start_pos.x; + cbox.xMax = edge.start_pos.x; + cbox.yMin = edge.start_pos.y; + cbox.yMax = edge.start_pos.y; + } + + cbox.xMin = edge.end_pos.x < cbox.xMin + ? edge.end_pos.x + : cbox.xMin; + cbox.xMax = edge.end_pos.x > cbox.xMax + ? edge.end_pos.x + : cbox.xMax; + + cbox.yMin = edge.end_pos.y < cbox.yMin + ? edge.end_pos.y + : cbox.yMin; + cbox.yMax = edge.end_pos.y > cbox.yMax + ? edge.end_pos.y + : cbox.yMax; + + break; + + default: + break; + } + + return cbox; + } + + + /* Return orientation of a single contour. */ + /* Note that the orientation is independent of the fill rule! */ + /* So, for TTF a clockwise-oriented contour has to be filled */ + /* and the opposite for OTF fonts. */ + static SDF_Contour_Orientation + get_contour_orientation ( SDF_Contour* contour ) + { + SDF_Edge* head = NULL; + FT_26D6 area = 0; + + + /* return none if invalid parameters */ + if ( !contour || !contour->edges ) + return SDF_ORIENTATION_NONE; + + head = contour->edges; + + /* Calculate the area of the control box for all edges. */ + while ( head ) + { + switch ( head->edge_type ) + { + case SDF_EDGE_LINE: + area += MUL_26D6( ( head->end_pos.x - head->start_pos.x ), + ( head->end_pos.y + head->start_pos.y ) ); + break; + + case SDF_EDGE_CONIC: + area += MUL_26D6( head->control_a.x - head->start_pos.x, + head->control_a.y + head->start_pos.y ); + area += MUL_26D6( head->end_pos.x - head->control_a.x, + head->end_pos.y + head->control_a.y ); + break; + + case SDF_EDGE_CUBIC: + area += MUL_26D6( head->control_a.x - head->start_pos.x, + head->control_a.y + head->start_pos.y ); + area += MUL_26D6( head->control_b.x - head->control_a.x, + head->control_b.y + head->control_a.y ); + area += MUL_26D6( head->end_pos.x - head->control_b.x, + head->end_pos.y + head->control_b.y ); + break; + + default: + return SDF_ORIENTATION_NONE; + } + + head = head->next; + } + + /* Clockwise contours cover a positive area, and counter-clockwise */ + /* contours cover a negative area. */ + if ( area > 0 ) + return SDF_ORIENTATION_CW; + else + return SDF_ORIENTATION_CCW; + } + + + /* This function is exactly the same as the one */ + /* in the smooth renderer. It splits a conic */ + /* into two conics exactly half way at t = 0.5. */ + static void + split_conic( FT_26D6_Vec* base ) + { + FT_26D6 a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b / 2; + base[2].x = ( a + b ) / 4; + base[1].x = a / 2; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b / 2; + base[2].y = ( a + b ) / 4; + base[1].y = a / 2; + } + + + /* This function is exactly the same as the one */ + /* in the smooth renderer. It splits a cubic */ + /* into two cubics exactly half way at t = 0.5. */ + static void + split_cubic( FT_26D6_Vec* base ) + { + FT_26D6 a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c / 2; + c += b; + base[4].x = c / 4; + base[1].x = a / 2; + a += b; + base[2].x = a / 4; + base[3].x = ( a + c ) / 8; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c / 2; + c += b; + base[4].y = c / 4; + base[1].y = a / 2; + a += b; + base[2].y = a / 4; + base[3].y = ( a + c ) / 8; + } + + + /* Split a conic Bezier curve into a number of lines */ + /* and add them to `out'. */ + /* */ + /* This function uses recursion; we thus need */ + /* parameter `max_splits' for stopping. */ + static FT_Error + split_sdf_conic( FT_Memory memory, + FT_26D6_Vec* control_points, + FT_UInt max_splits, + SDF_Edge** out ) + { + FT_Error error = FT_Err_Ok; + FT_26D6_Vec cpos[5]; + SDF_Edge* left,* right; + + + if ( !memory || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* split conic outline */ + cpos[0] = control_points[0]; + cpos[1] = control_points[1]; + cpos[2] = control_points[2]; + + split_conic( cpos ); + + /* If max number of splits is done */ + /* then stop and add the lines to */ + /* the list. */ + if ( max_splits <= 2 ) + goto Append; + + /* Otherwise keep splitting. */ + FT_CALL( split_sdf_conic( memory, &cpos[0], max_splits / 2, out ) ); + FT_CALL( split_sdf_conic( memory, &cpos[2], max_splits / 2, out ) ); + + /* [NOTE]: This is not an efficient way of */ + /* splitting the curve. Check the deviation */ + /* instead and stop if the deviation is less */ + /* than a pixel. */ + + goto Exit; + + Append: + /* Do allocation and add the lines to the list. */ + + FT_CALL( sdf_edge_new( memory, &left ) ); + FT_CALL( sdf_edge_new( memory, &right ) ); + + left->start_pos = cpos[0]; + left->end_pos = cpos[2]; + left->edge_type = SDF_EDGE_LINE; + + right->start_pos = cpos[2]; + right->end_pos = cpos[4]; + right->edge_type = SDF_EDGE_LINE; + + left->next = right; + right->next = (*out); + *out = left; + + Exit: + return error; + } + + + /* Split a cubic Bezier curve into a number of lines */ + /* and add them to `out`. */ + /* */ + /* This function uses recursion; we thus need */ + /* parameter `max_splits' for stopping. */ + static FT_Error + split_sdf_cubic( FT_Memory memory, + FT_26D6_Vec* control_points, + FT_UInt max_splits, + SDF_Edge** out ) + { + FT_Error error = FT_Err_Ok; + FT_26D6_Vec cpos[7]; + SDF_Edge* left, *right; + const FT_26D6 threshold = ONE_PIXEL / 4; + + + if ( !memory || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* split the cubic */ + cpos[0] = control_points[0]; + cpos[1] = control_points[1]; + cpos[2] = control_points[2]; + cpos[3] = control_points[3]; + + /* If the segment is flat enough we won't get any benefit by */ + /* splitting it further, so we can just stop splitting. */ + /* */ + /* Check the deviation of the Bezier curve and stop if it is */ + /* smaller than the pre-defined `threshold` value. */ + if ( FT_ABS( 2 * cpos[0].x - 3 * cpos[1].x + cpos[3].x ) < threshold && + FT_ABS( 2 * cpos[0].y - 3 * cpos[1].y + cpos[3].y ) < threshold && + FT_ABS( cpos[0].x - 3 * cpos[2].x + 2 * cpos[3].x ) < threshold && + FT_ABS( cpos[0].y - 3 * cpos[2].y + 2 * cpos[3].y ) < threshold ) + { + split_cubic( cpos ); + goto Append; + } + + split_cubic( cpos ); + + /* If max number of splits is done */ + /* then stop and add the lines to */ + /* the list. */ + if ( max_splits <= 2 ) + goto Append; + + /* Otherwise keep splitting. */ + FT_CALL( split_sdf_cubic( memory, &cpos[0], max_splits / 2, out ) ); + FT_CALL( split_sdf_cubic( memory, &cpos[3], max_splits / 2, out ) ); + + /* [NOTE]: This is not an efficient way of */ + /* splitting the curve. Check the deviation */ + /* instead and stop if the deviation is less */ + /* than a pixel. */ + + goto Exit; + + Append: + /* Do allocation and add the lines to the list. */ + + FT_CALL( sdf_edge_new( memory, &left) ); + FT_CALL( sdf_edge_new( memory, &right) ); + + left->start_pos = cpos[0]; + left->end_pos = cpos[3]; + left->edge_type = SDF_EDGE_LINE; + + right->start_pos = cpos[3]; + right->end_pos = cpos[6]; + right->edge_type = SDF_EDGE_LINE; + + left->next = right; + right->next = (*out); + *out = left; + + Exit: + return error; + } + + + /* Subdivide an entire shape into line segments */ + /* such that it doesn't look visually different */ + /* from the original curve. */ + static FT_Error + split_sdf_shape( SDF_Shape* shape ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + SDF_Contour* contours; + SDF_Contour* new_contours = NULL; + + + if ( !shape || !shape->memory ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contours = shape->contours; + memory = shape->memory; + + /* for each contour */ + while ( contours ) + { + SDF_Edge* edges = contours->edges; + SDF_Edge* new_edges = NULL; + + SDF_Contour* tempc; + + + /* for each edge */ + while ( edges ) + { + SDF_Edge* edge = edges; + SDF_Edge* temp; + + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + /* Just create a duplicate edge in case */ + /* it is a line. We can use the same edge. */ + FT_CALL( sdf_edge_new( memory, &temp ) ); + + ft_memcpy( temp, edge, sizeof ( *edge ) ); + + temp->next = new_edges; + new_edges = temp; + break; + + case SDF_EDGE_CONIC: + /* Subdivide the curve and add it to the list. */ + { + FT_26D6_Vec ctrls[3]; + FT_26D6 dx, dy; + FT_UInt num_splits; + + + ctrls[0] = edge->start_pos; + ctrls[1] = edge->control_a; + ctrls[2] = edge->end_pos; + + dx = FT_ABS( ctrls[2].x + ctrls[0].x - 2 * ctrls[1].x ); + dy = FT_ABS( ctrls[2].y + ctrls[0].y - 2 * ctrls[1].y ); + if ( dx < dy ) + dx = dy; + + /* Calculate the number of necessary bisections. Each */ + /* bisection causes a four-fold reduction of the deviation, */ + /* hence we bisect the Bezier curve until the deviation */ + /* becomes less than 1/8 of a pixel. For more details */ + /* check file `ftgrays.c`. */ + num_splits = 1; + while ( dx > ONE_PIXEL / 8 ) + { + dx >>= 2; + num_splits <<= 1; + } + + error = split_sdf_conic( memory, ctrls, num_splits, &new_edges ); + } + break; + + case SDF_EDGE_CUBIC: + /* Subdivide the curve and add it to the list. */ + { + FT_26D6_Vec ctrls[4]; + + + ctrls[0] = edge->start_pos; + ctrls[1] = edge->control_a; + ctrls[2] = edge->control_b; + ctrls[3] = edge->end_pos; + + error = split_sdf_cubic( memory, ctrls, 32, &new_edges ); + } + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + if ( error != FT_Err_Ok ) + goto Exit; + + edges = edges->next; + } + + /* add to the contours list */ + FT_CALL( sdf_contour_new( memory, &tempc ) ); + + tempc->next = new_contours; + tempc->edges = new_edges; + new_contours = tempc; + new_edges = NULL; + + /* deallocate the contour */ + tempc = contours; + contours = contours->next; + + sdf_contour_done( memory, &tempc ); + } + + shape->contours = new_contours; + + Exit: + return error; + } + + + /************************************************************************** + * + * for debugging + * + */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + static void + sdf_shape_dump( SDF_Shape* shape ) + { + FT_UInt num_contours = 0; + + FT_UInt total_edges = 0; + FT_UInt total_lines = 0; + FT_UInt total_conic = 0; + FT_UInt total_cubic = 0; + + SDF_Contour* contour_list; + + + if ( !shape ) + { + FT_TRACE5(( "sdf_shape_dump: null shape\n" )); + return; + } + + contour_list = shape->contours; + + FT_TRACE5(( "sdf_shape_dump (values are in 26.6 format):\n" )); + + while ( contour_list ) + { + FT_UInt num_edges = 0; + SDF_Edge* edge_list; + SDF_Contour* contour = contour_list; + + + FT_TRACE5(( " Contour %d\n", num_contours )); + + edge_list = contour->edges; + + while ( edge_list ) + { + SDF_Edge* edge = edge_list; + + + FT_TRACE5(( " %3d: ", num_edges )); + + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + FT_TRACE5(( "Line: (%ld, %ld) -- (%ld, %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->end_pos.x, edge->end_pos.y )); + total_lines++; + break; + + case SDF_EDGE_CONIC: + FT_TRACE5(( "Conic: (%ld, %ld) .. (%ld, %ld) .. (%ld, %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->control_a.x, edge->control_a.y, + edge->end_pos.x, edge->end_pos.y )); + total_conic++; + break; + + case SDF_EDGE_CUBIC: + FT_TRACE5(( "Cubic: (%ld, %ld) .. (%ld, %ld)" + " .. (%ld, %ld) .. (%ld %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->control_a.x, edge->control_a.y, + edge->control_b.x, edge->control_b.y, + edge->end_pos.x, edge->end_pos.y )); + total_cubic++; + break; + + default: + break; + } + + num_edges++; + total_edges++; + edge_list = edge_list->next; + } + + num_contours++; + contour_list = contour_list->next; + } + + FT_TRACE5(( "\n" )); + FT_TRACE5(( " total number of contours = %d\n", num_contours )); + FT_TRACE5(( " total number of edges = %d\n", total_edges )); + FT_TRACE5(( " |__lines = %d\n", total_lines )); + FT_TRACE5(( " |__conic = %d\n", total_conic )); + FT_TRACE5(( " |__cubic = %d\n", total_cubic )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * math functions + * + */ + +#if !USE_NEWTON_FOR_CONIC + + /* [NOTE]: All the functions below down until rasterizer */ + /* can be avoided if we decide to subdivide the */ + /* curve into lines. */ + + /* This function uses Newton's iteration to find */ + /* the cube root of a fixed-point integer. */ + static FT_16D16 + cube_root( FT_16D16 val ) + { + /* [IMPORTANT]: This function is not good as it may */ + /* not break, so use a lookup table instead. Or we */ + /* can use an algorithm similar to `square_root`. */ + + FT_Int v, g, c; + + + if ( val == 0 || + val == -FT_INT_16D16( 1 ) || + val == FT_INT_16D16( 1 ) ) + return val; + + v = val < 0 ? -val : val; + g = square_root( v ); + c = 0; + + while ( 1 ) + { + c = FT_MulFix( FT_MulFix( g, g ), g ) - v; + c = FT_DivFix( c, 3 * FT_MulFix( g, g ) ); + + g -= c; + + if ( ( c < 0 ? -c : c ) < 30 ) + break; + } + + return val < 0 ? -g : g; + } + + + /* Calculate the perpendicular by using '1 - base^2'. */ + /* Then use arctan to compute the angle. */ + static FT_16D16 + arc_cos( FT_16D16 val ) + { + FT_16D16 p; + FT_16D16 b = val; + FT_16D16 one = FT_INT_16D16( 1 ); + + + if ( b > one ) + b = one; + if ( b < -one ) + b = -one; + + p = one - FT_MulFix( b, b ); + p = square_root( p ); + + return FT_Atan2( b, p ); + } + + + /* Compute roots of a quadratic polynomial, assign them to `out`, */ + /* and return number of real roots. */ + /* */ + /* The procedure can be found at */ + /* */ + /* https://mathworld.wolfram.com/QuadraticFormula.html */ + static FT_UShort + solve_quadratic_equation( FT_26D6 a, + FT_26D6 b, + FT_26D6 c, + FT_16D16 out[2] ) + { + FT_16D16 discriminant = 0; + + + a = FT_26D6_16D16( a ); + b = FT_26D6_16D16( b ); + c = FT_26D6_16D16( c ); + + if ( a == 0 ) + { + if ( b == 0 ) + return 0; + else + { + out[0] = FT_DivFix( -c, b ); + + return 1; + } + } + + discriminant = FT_MulFix( b, b ) - 4 * FT_MulFix( a, c ); + + if ( discriminant < 0 ) + return 0; + else if ( discriminant == 0 ) + { + out[0] = FT_DivFix( -b, 2 * a ); + + return 1; + } + else + { + discriminant = square_root( discriminant ); + + out[0] = FT_DivFix( -b + discriminant, 2 * a ); + out[1] = FT_DivFix( -b - discriminant, 2 * a ); + + return 2; + } + } + + + /* Compute roots of a cubic polynomial, assign them to `out`, */ + /* and return number of real roots. */ + /* */ + /* The procedure can be found at */ + /* */ + /* https://mathworld.wolfram.com/CubicFormula.html */ + static FT_UShort + solve_cubic_equation( FT_26D6 a, + FT_26D6 b, + FT_26D6 c, + FT_26D6 d, + FT_16D16 out[3] ) + { + FT_16D16 q = 0; /* intermediate */ + FT_16D16 r = 0; /* intermediate */ + + FT_16D16 a2 = b; /* x^2 coefficients */ + FT_16D16 a1 = c; /* x coefficients */ + FT_16D16 a0 = d; /* constant */ + + FT_16D16 q3 = 0; + FT_16D16 r2 = 0; + FT_16D16 a23 = 0; + FT_16D16 a22 = 0; + FT_16D16 a1x2 = 0; + + + /* cutoff value for `a` to be a cubic, otherwise solve quadratic */ + if ( a == 0 || FT_ABS( a ) < 16 ) + return solve_quadratic_equation( b, c, d, out ); + + if ( d == 0 ) + { + out[0] = 0; + + return solve_quadratic_equation( a, b, c, out + 1 ) + 1; + } + + /* normalize the coefficients; this also makes them 16.16 */ + a2 = FT_DivFix( a2, a ); + a1 = FT_DivFix( a1, a ); + a0 = FT_DivFix( a0, a ); + + /* compute intermediates */ + a1x2 = FT_MulFix( a1, a2 ); + a22 = FT_MulFix( a2, a2 ); + a23 = FT_MulFix( a22, a2 ); + + q = ( 3 * a1 - a22 ) / 9; + r = ( 9 * a1x2 - 27 * a0 - 2 * a23 ) / 54; + + /* [BUG]: `q3` and `r2` still cause underflow. */ + + q3 = FT_MulFix( q, q ); + q3 = FT_MulFix( q3, q ); + + r2 = FT_MulFix( r, r ); + + if ( q3 < 0 && r2 < -q3 ) + { + FT_16D16 t = 0; + + + q3 = square_root( -q3 ); + t = FT_DivFix( r, q3 ); + + if ( t > ( 1 << 16 ) ) + t = ( 1 << 16 ); + if ( t < -( 1 << 16 ) ) + t = -( 1 << 16 ); + + t = arc_cos( t ); + a2 /= 3; + q = 2 * square_root( -q ); + + out[0] = FT_MulFix( q, FT_Cos( t / 3 ) ) - a2; + out[1] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 2 ) / 3 ) ) - a2; + out[2] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 4 ) / 3 ) ) - a2; + + return 3; + } + + else if ( r2 == -q3 ) + { + FT_16D16 s = 0; + + + s = cube_root( r ); + a2 /= -3; + + out[0] = a2 + ( 2 * s ); + out[1] = a2 - s; + + return 2; + } + + else + { + FT_16D16 s = 0; + FT_16D16 t = 0; + FT_16D16 dis = 0; + + + if ( q3 == 0 ) + dis = FT_ABS( r ); + else + dis = square_root( q3 + r2 ); + + s = cube_root( r + dis ); + t = cube_root( r - dis ); + a2 /= -3; + out[0] = ( a2 + ( s + t ) ); + + return 1; + } + } + +#endif /* !USE_NEWTON_FOR_CONIC */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** RASTERIZER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * resolve_corner + * + * @Description: + * At some places on the grid two edges can give opposite directions; + * this happens when the closest point is on one of the endpoint. In + * that case we need to check the proper sign. + * + * This can be visualized by an example: + * + * ``` + * x + * + * o + * ^ \ + * / \ + * / \ + * (a) / \ (b) + * / \ + * / \ + * / v + * ``` + * + * Suppose `x` is the point whose shortest distance from an arbitrary + * contour we want to find out. It is clear that `o` is the nearest + * point on the contour. Now to determine the sign we do a cross + * product of the shortest distance vector and the edge direction, i.e., + * + * ``` + * => sign = cross(x - o, direction(a)) + * ``` + * + * Using the right hand thumb rule we can see that the sign will be + * positive. + * + * If we use `b', however, we have + * + * ``` + * => sign = cross(x - o, direction(b)) + * ``` + * + * In this case the sign will be negative. To determine the correct + * sign we thus divide the plane in two halves and check which plane the + * point lies in. + * + * ``` + * | + * x | + * | + * o + * ^|\ + * / | \ + * / | \ + * (a) / | \ (b) + * / | \ + * / \ + * / v + * ``` + * + * We can see that `x` lies in the plane of `a`, so we take the sign + * determined by `a`. This test can be easily done by calculating the + * orthogonality and taking the greater one. + * + * The orthogonality is simply the sinus of the two vectors (i.e., + * x - o) and the corresponding direction. We efficiently pre-compute + * the orthogonality with the corresponding `get_min_distance_*` + * functions. + * + * @Input: + * sdf1 :: + * First signed distance (can be any of `a` or `b`). + * + * sdf1 :: + * Second signed distance (can be any of `a` or `b`). + * + * @Return: + * The correct signed distance, which is computed by using the above + * algorithm. + * + * @Note: + * The function does not care about the actual distance, it simply + * returns the signed distance which has a larger cross product. As a + * consequence, this function should not be used if the two distances + * are fairly apart. In that case simply use the signed distance with + * a shorter absolute distance. + * + */ + static SDF_Signed_Distance + resolve_corner( SDF_Signed_Distance sdf1, + SDF_Signed_Distance sdf2 ) + { + return FT_ABS( sdf1.cross ) > FT_ABS( sdf2.cross ) ? sdf1 : sdf2; + } + + + /************************************************************************** + * + * @Function: + * get_min_distance_line + * + * @Description: + * Find the shortest distance from the `line` segment to a given `point` + * and assign it to `out`. Use it for line segments only. + * + * @Input: + * line :: + * The line segment to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `line`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The `line' parameter must have an edge type of `SDF_EDGE_LINE`. + * + */ + static FT_Error + get_min_distance_line( SDF_Edge* line, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * In order to calculate the shortest distance from a point to + * a line segment, we do the following. Let's assume that + * + * ``` + * a = start point of the line segment + * b = end point of the line segment + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) Write the parametric equation of the line. + * + * ``` + * point_on_line = a + (b - a) * t (t is the factor) + * ``` + * + * (2) Find the projection of point `p` on the line. The projection + * will be perpendicular to the line, which allows us to get the + * solution by making the dot product zero. + * + * ``` + * (point_on_line - a) . (p - point_on_line) = 0 + * + * (point_on_line) + * (a) x-------o----------------x (b) + * |_| + * | + * | + * (p) + * ``` + * + * (3) Simplification of the above equation yields the factor of + * `point_on_line`: + * + * ``` + * t = ((p - a) . (b - a)) / |b - a|^2 + * ``` + * + * (4) We clamp factor `t` between [0.0f, 1.0f] because `point_on_line` + * can be outside of the line segment: + * + * ``` + * (point_on_line) + * (a) x------------------------x (b) -----o--- + * |_| + * | + * | + * (p) + * ``` + * + * (5) Finally, the distance we are interested in is + * + * ``` + * |point_on_line - p| + * ``` + */ + + FT_Error error = FT_Err_Ok; + + FT_Vector a; /* start position */ + FT_Vector b; /* end position */ + FT_Vector p; /* current point */ + + FT_26D6_Vec line_segment; /* `b` - `a` */ + FT_26D6_Vec p_sub_a; /* `p` - `a` */ + + FT_26D6 sq_line_length; /* squared length of `line_segment` */ + FT_16D16 factor; /* factor of the nearest point */ + FT_26D6 cross; /* used to determine sign */ + + FT_16D16_Vec nearest_point; /* `point_on_line` */ + FT_16D16_Vec nearest_vector; /* `p` - `nearest_point` */ + + + if ( !line || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( line->edge_type != SDF_EDGE_LINE ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + a = line->start_pos; + b = line->end_pos; + p = point; + + line_segment.x = b.x - a.x; + line_segment.y = b.y - a.y; + + p_sub_a.x = p.x - a.x; + p_sub_a.y = p.y - a.y; + + sq_line_length = ( line_segment.x * line_segment.x ) / 64 + + ( line_segment.y * line_segment.y ) / 64; + + /* currently factor is 26.6 */ + factor = ( p_sub_a.x * line_segment.x ) / 64 + + ( p_sub_a.y * line_segment.y ) / 64; + + /* now factor is 16.16 */ + factor = FT_DivFix( factor, sq_line_length ); + + /* clamp the factor between 0.0 and 1.0 in fixed-point */ + if ( factor > FT_INT_16D16( 1 ) ) + factor = FT_INT_16D16( 1 ); + if ( factor < 0 ) + factor = 0; + + nearest_point.x = FT_MulFix( FT_26D6_16D16( line_segment.x ), + factor ); + nearest_point.y = FT_MulFix( FT_26D6_16D16( line_segment.y ), + factor ); + + nearest_point.x = FT_26D6_16D16( a.x ) + nearest_point.x; + nearest_point.y = FT_26D6_16D16( a.y ) + nearest_point.y; + + nearest_vector.x = nearest_point.x - FT_26D6_16D16( p.x ); + nearest_vector.y = nearest_point.y - FT_26D6_16D16( p.y ); + + cross = FT_MulFix( nearest_vector.x, line_segment.y ) - + FT_MulFix( nearest_vector.y, line_segment.x ); + + /* assign the output */ + out->sign = cross < 0 ? 1 : -1; + out->distance = VECTOR_LENGTH_16D16( nearest_vector ); + + /* Instead of finding `cross` for checking corner we */ + /* directly set it here. This is more efficient */ + /* because if the distance is perpendicular we can */ + /* directly set it to 1. */ + if ( factor != 0 && factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); + else + { + /* [OPTIMIZATION]: Pre-compute this direction. */ + /* If not perpendicular then compute `cross`. */ + FT_Vector_NormLen( &line_segment ); + FT_Vector_NormLen( &nearest_vector ); + + out->cross = FT_MulFix( line_segment.x, nearest_vector.y ) - + FT_MulFix( line_segment.y, nearest_vector.x ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * get_min_distance_conic + * + * @Description: + * Find the shortest distance from the `conic` Bezier curve to a given + * `point` and assign it to `out`. Use it for conic/quadratic curves + * only. + * + * @Input: + * conic :: + * The conic Bezier curve to which the shortest distance is to be + * computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `conic`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The `conic` parameter must have an edge type of `SDF_EDGE_CONIC`. + * + */ + +#if !USE_NEWTON_FOR_CONIC + + /* + * The function uses an analytical method to find the shortest distance + * which is faster than the Newton-Raphson method, but has underflows at + * the moment. Use Newton's method if you can see artifacts in the SDF. + */ + static FT_Error + get_min_distance_conic( SDF_Edge* conic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * The procedure to find the shortest distance from a point to a + * quadratic Bezier curve is similar to the line segment algorithm. The + * shortest distance is perpendicular to the Bezier curve; the only + * difference from line is that there can be more than one + * perpendicular, and we also have to check the endpoints, because the + * perpendicular may not be the shortest. + * + * Let's assume that + * ``` + * p0 = first endpoint + * p1 = control point + * p2 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a quadratic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 + * ``` + * + * with `t` a factor in the range [0.0f, 1.0f]. This equation can + * be rewritten as + * + * ``` + * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 + * ``` + * + * With + * + * ``` + * A = p0 - 2p1 + p2 + * B = p1 - p0 + * ``` + * + * we have + * + * ``` + * B(t) = t^2 * A + 2t * B + p0 + * ``` + * + * (2) The derivative of the last equation above is + * + * ``` + * B'(t) = 2 *(tA + B) + * ``` + * + * (3) To find the shortest distance from `p` to `B(t)` we find the + * point on the curve at which the shortest distance vector (i.e., + * `B(t) - p`) and the direction (i.e., `B'(t)`) make 90 degrees. + * In other words, we make the dot product zero. + * + * ``` + * (B(t) - p) . (B'(t)) = 0 + * (t^2 * A + 2t * B + p0 - p) . (2 * (tA + B)) = 0 + * ``` + * + * After simplifying we get a cubic equation + * + * ``` + * at^3 + bt^2 + ct + d = 0 + * ``` + * + * with + * + * ``` + * a = A.A + * b = 3A.B + * c = 2B.B + A.p0 - A.p + * d = p0.B - p.B + * ``` + * + * (4) Now the roots of the equation can be computed using 'Cardano's + * Cubic formula'; we clamp the roots in the range [0.0f, 1.0f]. + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB; /* A, B in the above comment */ + FT_26D6_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_26D6 a, b, c, d; /* cubic coefficients */ + + FT_16D16 roots[3] = { 0, 0, 0 }; /* real roots of the cubic eq. */ + FT_16D16 min_factor; /* factor at `nearest_point` */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ + + FT_UShort num_roots; /* number of real roots of cubic */ + FT_UShort i; + + + if ( !conic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( conic->edge_type != SDF_EDGE_CONIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = conic->start_pos; + p1 = conic->control_a; + p2 = conic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = p0.x - 2 * p1.x + p2.x; + aA.y = p0.y - 2 * p1.y + p2.y; + + bB.x = p1.x - p0.x; + bB.y = p1.y - p0.y; + + /* compute cubic coefficients */ + a = VEC_26D6_DOT( aA, aA ); + + b = 3 * VEC_26D6_DOT( aA, bB ); + + c = 2 * VEC_26D6_DOT( bB, bB ) + + VEC_26D6_DOT( aA, p0 ) - + VEC_26D6_DOT( aA, p ); + + d = VEC_26D6_DOT( p0, bB ) - + VEC_26D6_DOT( p, bB ); + + /* find the roots */ + num_roots = solve_cubic_equation( a, b, c, d, roots ); + + if ( num_roots == 0 ) + { + roots[0] = 0; + roots[1] = FT_INT_16D16( 1 ); + num_roots = 2; + } + + /* [OPTIMIZATION]: Check the roots, clamp them and discard */ + /* duplicate roots. */ + + /* convert these values to 16.16 for further computation */ + aA.x = FT_26D6_16D16( aA.x ); + aA.y = FT_26D6_16D16( aA.y ); + + bB.x = FT_26D6_16D16( bB.x ); + bB.y = FT_26D6_16D16( bB.y ); + + p0.x = FT_26D6_16D16( p0.x ); + p0.y = FT_26D6_16D16( p0.y ); + + p.x = FT_26D6_16D16( p.x ); + p.y = FT_26D6_16D16( p.y ); + + for ( i = 0; i < num_roots; i++ ) + { + FT_16D16 t = roots[i]; + FT_16D16 t2 = 0; + FT_16D16 dist = 0; + + FT_16D16_Vec curve_point; + FT_16D16_Vec dist_vector; + + /* + * Ideally we should discard the roots which are outside the range + * [0.0, 1.0] and check the endpoints of the Bezier curve, but Behdad + * Esfahbod proved the following lemma. + * + * Lemma: + * + * (1) If the closest point on the curve [0, 1] is to the endpoint at + * `t` = 1 and the cubic has no real roots at `t` = 1 then the + * cubic must have a real root at some `t` > 1. + * + * (2) Similarly, if the closest point on the curve [0, 1] is to the + * endpoint at `t` = 0 and the cubic has no real roots at `t` = 0 + * then the cubic must have a real root at some `t` < 0. + * + * Now because of this lemma we only need to clamp the roots and that + * will take care of the endpoints. + * + * For more details see + * + * https://lists.nongnu.org/archive/html/freetype-devel/2020-06/msg00147.html + */ + + if ( t < 0 ) + t = 0; + if ( t > FT_INT_16D16( 1 ) ) + t = FT_INT_16D16( 1 ); + + t2 = FT_MulFix( t, t ); + + /* B(t) = t^2 * A + 2t * B + p0 - p */ + curve_point.x = FT_MulFix( aA.x, t2 ) + + 2 * FT_MulFix( bB.x, t ) + p0.x; + curve_point.y = FT_MulFix( aA.y, t2 ) + + 2 * FT_MulFix( bB.y, t ) + p0.y; + + /* `curve_point` - `p` */ + dist_vector.x = curve_point.x - p.x; + dist_vector.y = curve_point.y - p.y; + + dist = VECTOR_LENGTH_16D16( dist_vector ); + + if ( dist < min ) + { + min = dist; + nearest_point = curve_point; + min_factor = t; + } + } + + /* B'(t) = 2 * (tA + B) */ + direction.x = 2 * FT_MulFix( aA.x, min_factor ) + 2 * bB.x; + direction.y = 2 * FT_MulFix( aA.y, min_factor ) + 2 * bB.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - p.x, direction.y ) - + FT_MulFix( nearest_point.y - p.y, direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + +#else /* USE_NEWTON_FOR_CONIC */ + + /* + * The function uses Newton's approximation to find the shortest distance, + * which is a bit slower than the analytical method but doesn't cause + * underflow. + */ + static FT_Error + get_min_distance_conic( SDF_Edge* conic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * This method uses Newton-Raphson's approximation to find the shortest + * distance from a point to a conic curve. It does not involve solving + * any cubic equation, that is why there is no risk of underflow. + * + * Let's assume that + * + * ``` + * p0 = first endpoint + * p1 = control point + * p3 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a quadratic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 + * ``` + * + * with `t` the factor in the range [0.0f, 1.0f]. The above + * equation can be rewritten as + * + * ``` + * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 + * ``` + * + * With + * + * ``` + * A = p0 - 2p1 + p2 + * B = 2 * (p1 - p0) + * ``` + * + * we have + * + * ``` + * B(t) = t^2 * A + t * B + p0 + * ``` + * + * (2) The derivative of the above equation is + * + * ``` + * B'(t) = 2t * A + B + * ``` + * + * (3) The second derivative of the above equation is + * + * ``` + * B''(t) = 2A + * ``` + * + * (4) The equation `P(t)` of the distance from point `p` to the curve + * can be written as + * + * ``` + * P(t) = t^2 * A + t^2 * B + p0 - p + * ``` + * + * With + * + * ``` + * C = p0 - p + * ``` + * + * we have + * + * ``` + * P(t) = t^2 * A + t * B + C + * ``` + * + * (5) Finally, the equation of the angle between `B(t)` and `P(t)` can + * be written as + * + * ``` + * Q(t) = P(t) . B'(t) + * ``` + * + * (6) Our task is to find a value of `t` such that the above equation + * `Q(t)` becomes zero, that is, the point-to-curve vector makes + * 90~degrees with the curve. We solve this with the Newton-Raphson + * method. + * + * (7) We first assume an arbitrary value of factor `t`, which we then + * improve. + * + * ``` + * t := Q(t) / Q'(t) + * ``` + * + * Putting the value of `Q(t)` from the above equation gives + * + * ``` + * t := P(t) . B'(t) / derivative(P(t) . B'(t)) + * t := P(t) . B'(t) / + * (P'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * Note that `P'(t)` is the same as `B'(t)` because the constant is + * gone due to the derivative. + * + * (8) Finally we get the equation to improve the factor as + * + * ``` + * t := P(t) . B'(t) / + * (B'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB, cC; /* A, B, C in the above comment */ + FT_26D6_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_16D16 min_factor = 0; /* factor at `nearest_point' */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ + + FT_UShort iterations; + FT_UShort steps; + + + if ( !conic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( conic->edge_type != SDF_EDGE_CONIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = conic->start_pos; + p1 = conic->control_a; + p2 = conic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = p0.x - 2 * p1.x + p2.x; + aA.y = p0.y - 2 * p1.y + p2.y; + + bB.x = 2 * ( p1.x - p0.x ); + bB.y = 2 * ( p1.y - p0.y ); + + cC.x = p0.x; + cC.y = p0.y; + + /* do Newton's iterations */ + for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) + { + FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; + FT_16D16 factor2; + FT_16D16 length; + + FT_16D16_Vec curve_point; /* point on the curve */ + FT_16D16_Vec dist_vector; /* `curve_point` - `p` */ + + FT_26D6_Vec d1; /* first derivative */ + FT_26D6_Vec d2; /* second derivative */ + + FT_16D16 temp1; + FT_16D16 temp2; + + + for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) + { + factor2 = FT_MulFix( factor, factor ); + + /* B(t) = t^2 * A + t * B + p0 */ + curve_point.x = FT_MulFix( aA.x, factor2 ) + + FT_MulFix( bB.x, factor ) + cC.x; + curve_point.y = FT_MulFix( aA.y, factor2 ) + + FT_MulFix( bB.y, factor ) + cC.y; + + /* convert to 16.16 */ + curve_point.x = FT_26D6_16D16( curve_point.x ); + curve_point.y = FT_26D6_16D16( curve_point.y ); + + /* P(t) in the comment */ + dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); + dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); + + length = VECTOR_LENGTH_16D16( dist_vector ); + + if ( length < min ) + { + min = length; + min_factor = factor; + nearest_point = curve_point; + } + + /* This is Newton's approximation. */ + /* */ + /* t := P(t) . B'(t) / */ + /* (B'(t) . B'(t) + P(t) . B''(t)) */ + + /* B'(t) = 2tA + B */ + d1.x = FT_MulFix( aA.x, 2 * factor ) + bB.x; + d1.y = FT_MulFix( aA.y, 2 * factor ) + bB.y; + + /* B''(t) = 2A */ + d2.x = 2 * aA.x; + d2.y = 2 * aA.y; + + dist_vector.x /= 1024; + dist_vector.y /= 1024; + + /* temp1 = P(t) . B'(t) */ + temp1 = VEC_26D6_DOT( dist_vector, d1 ); + + /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ + temp2 = VEC_26D6_DOT( d1, d1 ) + + VEC_26D6_DOT( dist_vector, d2 ); + + factor -= FT_DivFix( temp1, temp2 ); + + if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) + break; + } + } + + /* B'(t) = 2t * A + B */ + direction.x = 2 * FT_MulFix( aA.x, min_factor ) + bB.x; + direction.y = 2 * FT_MulFix( aA.y, min_factor ) + bB.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), + direction.y ) - + FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), + direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + + +#endif /* USE_NEWTON_FOR_CONIC */ + + + /************************************************************************** + * + * @Function: + * get_min_distance_cubic + * + * @Description: + * Find the shortest distance from the `cubic` Bezier curve to a given + * `point` and assigns it to `out`. Use it for cubic curves only. + * + * @Input: + * cubic :: + * The cubic Bezier curve to which the shortest distance is to be + * computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `cubic`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function uses Newton's approximation to find the shortest + * distance. Another way would be to divide the cubic into conic or + * subdivide the curve into lines, but that is not implemented. + * + * The `cubic` parameter must have an edge type of `SDF_EDGE_CUBIC`. + * + */ + static FT_Error + get_min_distance_cubic( SDF_Edge* cubic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * The procedure to find the shortest distance from a point to a cubic + * Bezier curve is similar to quadratic curve algorithm. The only + * difference is that while calculating factor `t`, instead of a cubic + * polynomial equation we have to find the roots of a 5th degree + * polynomial equation. Solving this would require a significant amount + * of time, and still the results may not be accurate. We are thus + * going to directly approximate the value of `t` using the Newton-Raphson + * method. + * + * Let's assume that + * + * ``` + * p0 = first endpoint + * p1 = first control point + * p2 = second control point + * p3 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a cubic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^3 * p0 + 3(1 - t)^2 t * p1 + + * 3(1 - t)t^2 * p2 + t^3 * p3 + * ``` + * + * The equation can be expanded and written as + * + * ``` + * B(t) = t^3 * (-p0 + 3p1 - 3p2 + p3) + + * 3t^2 * (p0 - 2p1 + p2) + 3t * (-p0 + p1) + p0 + * ``` + * + * With + * + * ``` + * A = -p0 + 3p1 - 3p2 + p3 + * B = 3(p0 - 2p1 + p2) + * C = 3(-p0 + p1) + * ``` + * + * we have + * + * ``` + * B(t) = t^3 * A + t^2 * B + t * C + p0 + * ``` + * + * (2) The derivative of the above equation is + * + * ``` + * B'(t) = 3t^2 * A + 2t * B + C + * ``` + * + * (3) The second derivative of the above equation is + * + * ``` + * B''(t) = 6t * A + 2B + * ``` + * + * (4) The equation `P(t)` of the distance from point `p` to the curve + * can be written as + * + * ``` + * P(t) = t^3 * A + t^2 * B + t * C + p0 - p + * ``` + * + * With + * + * ``` + * D = p0 - p + * ``` + * + * we have + * + * ``` + * P(t) = t^3 * A + t^2 * B + t * C + D + * ``` + * + * (5) Finally the equation of the angle between `B(t)` and `P(t)` can + * be written as + * + * ``` + * Q(t) = P(t) . B'(t) + * ``` + * + * (6) Our task is to find a value of `t` such that the above equation + * `Q(t)` becomes zero, that is, the point-to-curve vector makes + * 90~degree with curve. We solve this with the Newton-Raphson + * method. + * + * (7) We first assume an arbitrary value of factor `t`, which we then + * improve. + * + * ``` + * t := Q(t) / Q'(t) + * ``` + * + * Putting the value of `Q(t)` from the above equation gives + * + * ``` + * t := P(t) . B'(t) / derivative(P(t) . B'(t)) + * t := P(t) . B'(t) / + * (P'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * Note that `P'(t)` is the same as `B'(t)` because the constant is + * gone due to the derivative. + * + * (8) Finally we get the equation to improve the factor as + * + * ``` + * t := P(t) . B'(t) / + * (B'(t) . B'( t ) + P(t) . B''(t)) + * ``` + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB, cC, dD; /* A, B, C, D in the above comment */ + FT_16D16_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_16D16_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2, p3; /* control points of a cubic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_16D16 min_factor = 0; /* factor at shortest distance */ + FT_16D16 min_factor_sq = 0; /* factor at shortest distance */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest distance */ + + FT_UShort iterations; + FT_UShort steps; + + + if ( !cubic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( cubic->edge_type != SDF_EDGE_CUBIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = cubic->start_pos; + p1 = cubic->control_a; + p2 = cubic->control_b; + p3 = cubic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = -p0.x + 3 * ( p1.x - p2.x ) + p3.x; + aA.y = -p0.y + 3 * ( p1.y - p2.y ) + p3.y; + + bB.x = 3 * ( p0.x - 2 * p1.x + p2.x ); + bB.y = 3 * ( p0.y - 2 * p1.y + p2.y ); + + cC.x = 3 * ( p1.x - p0.x ); + cC.y = 3 * ( p1.y - p0.y ); + + dD.x = p0.x; + dD.y = p0.y; + + for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) + { + FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; + + FT_16D16 factor2; /* factor^2 */ + FT_16D16 factor3; /* factor^3 */ + FT_16D16 length; + + FT_16D16_Vec curve_point; /* point on the curve */ + FT_16D16_Vec dist_vector; /* `curve_point' - `p' */ + + FT_26D6_Vec d1; /* first derivative */ + FT_26D6_Vec d2; /* second derivative */ + + FT_16D16 temp1; + FT_16D16 temp2; + + + for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) + { + factor2 = FT_MulFix( factor, factor ); + factor3 = FT_MulFix( factor2, factor ); + + /* B(t) = t^3 * A + t^2 * B + t * C + D */ + curve_point.x = FT_MulFix( aA.x, factor3 ) + + FT_MulFix( bB.x, factor2 ) + + FT_MulFix( cC.x, factor ) + dD.x; + curve_point.y = FT_MulFix( aA.y, factor3 ) + + FT_MulFix( bB.y, factor2 ) + + FT_MulFix( cC.y, factor ) + dD.y; + + /* convert to 16.16 */ + curve_point.x = FT_26D6_16D16( curve_point.x ); + curve_point.y = FT_26D6_16D16( curve_point.y ); + + /* P(t) in the comment */ + dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); + dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); + + length = VECTOR_LENGTH_16D16( dist_vector ); + + if ( length < min ) + { + min = length; + min_factor = factor; + min_factor_sq = factor2; + nearest_point = curve_point; + } + + /* This the Newton's approximation. */ + /* */ + /* t := P(t) . B'(t) / */ + /* (B'(t) . B'(t) + P(t) . B''(t)) */ + + /* B'(t) = 3t^2 * A + 2t * B + C */ + d1.x = FT_MulFix( aA.x, 3 * factor2 ) + + FT_MulFix( bB.x, 2 * factor ) + cC.x; + d1.y = FT_MulFix( aA.y, 3 * factor2 ) + + FT_MulFix( bB.y, 2 * factor ) + cC.y; + + /* B''(t) = 6t * A + 2B */ + d2.x = FT_MulFix( aA.x, 6 * factor ) + 2 * bB.x; + d2.y = FT_MulFix( aA.y, 6 * factor ) + 2 * bB.y; + + dist_vector.x /= 1024; + dist_vector.y /= 1024; + + /* temp1 = P(t) . B'(t) */ + temp1 = VEC_26D6_DOT( dist_vector, d1 ); + + /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ + temp2 = VEC_26D6_DOT( d1, d1 ) + + VEC_26D6_DOT( dist_vector, d2 ); + + factor -= FT_DivFix( temp1, temp2 ); + + if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) + break; + } + } + + /* B'(t) = 3t^2 * A + 2t * B + C */ + direction.x = FT_MulFix( aA.x, 3 * min_factor_sq ) + + FT_MulFix( bB.x, 2 * min_factor ) + cC.x; + direction.y = FT_MulFix( aA.y, 3 * min_factor_sq ) + + FT_MulFix( bB.y, 2 * min_factor ) + cC.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), + direction.y ) - + FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), + direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_edge_get_min_distance + * + * @Description: + * Find shortest distance from `point` to any type of `edge`. It checks + * the edge type and then calls the relevant `get_min_distance_*` + * function. + * + * @Input: + * edge :: + * An edge to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `edge`. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_edge_get_min_distance( SDF_Edge* edge, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + FT_Error error = FT_Err_Ok; + + + if ( !edge || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* edge-specific distance calculation */ + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + get_min_distance_line( edge, point, out ); + break; + + case SDF_EDGE_CONIC: + get_min_distance_conic( edge, point, out ); + break; + + case SDF_EDGE_CUBIC: + get_min_distance_cubic( edge, point, out ); + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + Exit: + return error; + } + + + /* `sdf_generate' is not used at the moment */ +#if 0 + + #error "DO NOT USE THIS!" + #error "The function still outputs 16-bit data, which might cause memory" + #error "corruption. If required I will add this later." + + /************************************************************************** + * + * @Function: + * sdf_contour_get_min_distance + * + * @Description: + * Iterate over all edges that make up the contour, find the shortest + * distance from a point to this contour, and assigns result to `out`. + * + * @Input: + * contour :: + * A contour to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from the `point' to the `contour'. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function does not return a signed distance for each edge which + * makes up the contour, it simply returns the shortest of all the + * edges. + * + */ + static FT_Error + sdf_contour_get_min_distance( SDF_Contour* contour, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + FT_Error error = FT_Err_Ok; + SDF_Signed_Distance min_dist = max_sdf; + SDF_Edge* edge_list; + + + if ( !contour || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + edge_list = contour->edges; + + /* iterate over all the edges manually */ + while ( edge_list ) + { + SDF_Signed_Distance current_dist = max_sdf; + FT_16D16 diff; + + + FT_CALL( sdf_edge_get_min_distance( edge_list, + point, + ¤t_dist ) ); + + if ( current_dist.distance >= 0 ) + { + diff = current_dist.distance - min_dist.distance; + + + if ( FT_ABS( diff ) < CORNER_CHECK_EPSILON ) + min_dist = resolve_corner( min_dist, current_dist ); + else if ( diff < 0 ) + min_dist = current_dist; + } + else + FT_TRACE0(( "sdf_contour_get_min_distance: Overflow.\n" )); + + edge_list = edge_list->next; + } + + *out = min_dist; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate + * + * @Description: + * This is the main function that is responsible for generating signed + * distance fields. The function does not align or compute the size of + * `bitmap`; therefore the calling application must set up `bitmap` + * properly and transform the `shape' appropriately in advance. + * + * Currently we check all pixels against all contours and all edges. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. See + * @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate( const SDF_Params internal_params, + const SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + + FT_UInt width = 0; + FT_UInt rows = 0; + FT_UInt x = 0; /* used to loop in x direction, i.e., width */ + FT_UInt y = 0; /* used to loop in y direction, i.e., rows */ + FT_UInt sp_sq = 0; /* `spread` [* `spread`] as a 16.16 fixed value */ + + FT_Short* buffer; + + + if ( !shape || !bitmap ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + width = bitmap->width; + rows = bitmap->rows; + buffer = (FT_Short*)bitmap->buffer; + + if ( USE_SQUARED_DISTANCES ) + sp_sq = FT_INT_16D16( spread * spread ); + else + sp_sq = FT_INT_16D16( spread ); + + if ( width == 0 || rows == 0 ) + { + FT_TRACE0(( "sdf_generate:" + " Cannot render glyph with width/height == 0\n" )); + FT_TRACE0(( " " + " (width, height provided [%d, %d])\n", + width, rows )); + + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* loop over all rows */ + for ( y = 0; y < rows; y++ ) + { + /* loop over all pixels of a row */ + for ( x = 0; x < width; x++ ) + { + /* `grid_point` is the current pixel position; */ + /* our task is to find the shortest distance */ + /* from this point to the entire shape. */ + FT_26D6_Vec grid_point = zero_vector; + SDF_Signed_Distance min_dist = max_sdf; + SDF_Contour* contour_list; + + FT_UInt index; + FT_Short value; + + + grid_point.x = FT_INT_26D6( x ); + grid_point.y = FT_INT_26D6( y ); + + /* This `grid_point' is at the corner, but we */ + /* use the center of the pixel. */ + grid_point.x += FT_INT_26D6( 1 ) / 2; + grid_point.y += FT_INT_26D6( 1 ) / 2; + + contour_list = shape->contours; + + /* iterate over all contours manually */ + while ( contour_list ) + { + SDF_Signed_Distance current_dist = max_sdf; + + + FT_CALL( sdf_contour_get_min_distance( contour_list, + grid_point, + ¤t_dist ) ); + + if ( current_dist.distance < min_dist.distance ) + min_dist = current_dist; + + contour_list = contour_list->next; + } + + /* [OPTIMIZATION]: if (min_dist > sp_sq) then simply clamp */ + /* the value to spread to avoid square_root */ + + /* clamp the values to spread */ + if ( min_dist.distance > sp_sq ) + min_dist.distance = sp_sq; + + /* square_root the values and fit in a 6.10 fixed-point */ + if ( USE_SQUARED_DISTANCES ) + min_dist.distance = square_root( min_dist.distance ); + + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + min_dist.sign = -min_dist.sign; + if ( internal_params.flip_sign ) + min_dist.sign = -min_dist.sign; + + min_dist.distance /= 64; /* convert from 16.16 to 22.10 */ + + value = min_dist.distance & 0x0000FFFF; /* truncate to 6.10 */ + value *= min_dist.sign; + + if ( internal_params.flip_y ) + index = y * width + x; + else + index = ( rows - y - 1 ) * width + x; + + buffer[index] = value; + } + } + + Exit: + return error; + } + +#endif /* 0 */ + + + /************************************************************************** + * + * @Function: + * sdf_generate_bounding_box + * + * @Description: + * This function does basically the same thing as `sdf_generate` above + * but more efficiently. + * + * Instead of checking all pixels against all edges, we loop over all + * edges and only check pixels around the control box of the edge; the + * control box is increased by the spread in all directions. Anything + * outside of the control box that exceeds `spread` doesn't need to be + * computed. + * + * Lastly, to determine the sign of unchecked pixels, we do a single + * pass of all rows starting with a '+' sign and flipping when we come + * across a '-' sign and continue. This also eliminates the possibility + * of overflow because we only check the proximity of the curve. + * Therefore we can use squared distanced safely. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. + * See @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate_bounding_box( const SDF_Params internal_params, + const SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + FT_Int width, rows, i, j; + FT_Int sp_sq; /* max value to check */ + + SDF_Contour* contours; /* list of all contours */ + FT_SDFFormat* buffer; /* the bitmap buffer */ + + /* This buffer has the same size in indices as the */ + /* bitmap buffer. When we check a pixel position for */ + /* a shortest distance we keep it in this buffer. */ + /* This way we can find out which pixel is set, */ + /* and also determine the signs properly. */ + SDF_Signed_Distance* dists = NULL; + + const FT_16D16 fixed_spread = (FT_16D16)FT_INT_16D16( spread ); + + + if ( !shape || !bitmap ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = shape->memory; + if ( !memory ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_ALLOC( dists, + bitmap->width * bitmap->rows * sizeof ( *dists ) ) ) + goto Exit; + + contours = shape->contours; + width = (FT_Int)bitmap->width; + rows = (FT_Int)bitmap->rows; + buffer = (FT_SDFFormat*)bitmap->buffer; + + if ( USE_SQUARED_DISTANCES ) + sp_sq = FT_INT_16D16( (FT_Int)( spread * spread ) ); + else + sp_sq = fixed_spread; + + if ( width == 0 || rows == 0 ) + { + FT_TRACE0(( "sdf_generate:" + " Cannot render glyph with width/height == 0\n" )); + FT_TRACE0(( " " + " (width, height provided [%d, %d])", width, rows )); + + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* loop over all contours */ + while ( contours ) + { + SDF_Edge* edges = contours->edges; + + + /* loop over all edges */ + while ( edges ) + { + FT_CBox cbox; + FT_Int x, y; + + + /* get the control box and increase it by `spread' */ + cbox = get_control_box( *edges ); + + cbox.xMin = ( cbox.xMin - 63 ) / 64 - ( FT_Pos )spread; + cbox.xMax = ( cbox.xMax + 63 ) / 64 + ( FT_Pos )spread; + cbox.yMin = ( cbox.yMin - 63 ) / 64 - ( FT_Pos )spread; + cbox.yMax = ( cbox.yMax + 63 ) / 64 + ( FT_Pos )spread; + + /* now loop over the pixels in the control box. */ + for ( y = cbox.yMin; y < cbox.yMax; y++ ) + { + for ( x = cbox.xMin; x < cbox.xMax; x++ ) + { + FT_26D6_Vec grid_point = zero_vector; + SDF_Signed_Distance dist = max_sdf; + FT_UInt index = 0; + FT_16D16 diff = 0; + + + if ( x < 0 || x >= width ) + continue; + if ( y < 0 || y >= rows ) + continue; + + grid_point.x = FT_INT_26D6( x ); + grid_point.y = FT_INT_26D6( y ); + + /* This `grid_point` is at the corner, but we */ + /* use the center of the pixel. */ + grid_point.x += FT_INT_26D6( 1 ) / 2; + grid_point.y += FT_INT_26D6( 1 ) / 2; + + FT_CALL( sdf_edge_get_min_distance( edges, + grid_point, + &dist ) ); + + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + dist.sign = -dist.sign; + + /* ignore if the distance is greater than spread; */ + /* otherwise it creates artifacts due to the wrong sign */ + if ( dist.distance > sp_sq ) + continue; + + /* take the square root of the distance if required */ + if ( USE_SQUARED_DISTANCES ) + dist.distance = square_root( dist.distance ); + + if ( internal_params.flip_y ) + index = (FT_UInt)( y * width + x ); + else + index = (FT_UInt)( ( rows - y - 1 ) * width + x ); + + /* check whether the pixel is set or not */ + if ( dists[index].sign == 0 ) + dists[index] = dist; + else + { + diff = FT_ABS( dists[index].distance - dist.distance ); + + if ( diff <= CORNER_CHECK_EPSILON ) + dists[index] = resolve_corner( dists[index], dist ); + else if ( dists[index].distance > dist.distance ) + dists[index] = dist; + } + } + } + + edges = edges->next; + } + + contours = contours->next; + } + + /* final pass */ + for ( j = 0; j < rows; j++ ) + { + /* We assume the starting pixel of each row is outside. */ + FT_Char current_sign = -1; + FT_UInt index; + + + if ( internal_params.overload_sign != 0 ) + current_sign = internal_params.overload_sign < 0 ? -1 : 1; + + for ( i = 0; i < width; i++ ) + { + index = (FT_UInt)( j * width + i ); + + /* if the pixel is not set */ + /* its shortest distance is more than `spread` */ + if ( dists[index].sign == 0 ) + dists[index].distance = fixed_spread; + else + current_sign = dists[index].sign; + + /* clamp the values */ + if ( dists[index].distance > fixed_spread ) + dists[index].distance = fixed_spread; + + /* flip sign if required */ + dists[index].distance *= internal_params.flip_sign ? -current_sign + : current_sign; + + /* concatenate to appropriate format */ + buffer[index] = map_fixed_to_sdf( dists[index].distance, + fixed_spread ); + } + } + + Exit: + FT_FREE( dists ); + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate_subdivision + * + * @Description: + * Subdivide the shape into a number of straight lines, then use the + * above `sdf_generate_bounding_box` function to generate the SDF. + * + * Note: After calling this function `shape` no longer has the original + * edges, it only contains lines. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. + * See @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed inthe output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate_subdivision( const SDF_Params internal_params, + SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + /* + * Thanks to Alexei for providing the idea of this optimization. + * + * We take advantage of two facts. + * + * (1) Computing the shortest distance from a point to a line segment is + * very fast. + * (2) We don't have to compute the shortest distance for the entire + * two-dimensional grid. + * + * Both ideas lead to the following optimization. + * + * (1) Split the outlines into a number of line segments. + * + * (2) For each line segment, only process its neighborhood. + * + * (3) Compute the closest distance to the line only for neighborhood + * grid points. + * + * This greatly reduces the number of grid points to check. + */ + + FT_Error error = FT_Err_Ok; + + + FT_CALL( split_sdf_shape( shape ) ); + FT_CALL( sdf_generate_bounding_box( internal_params, + shape, spread, bitmap ) ); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate_with_overlaps + * + * @Description: + * This function can be used to generate SDF for glyphs with overlapping + * contours. The function generates SDF for contours separately on + * separate bitmaps (to generate SDF it uses + * `sdf_generate_subdivision`). At the end it simply combines all the + * SDF into the output bitmap; this fixes all the signs and removes + * overlaps. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. See + * @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function cannot generate a proper SDF for glyphs with + * self-intersecting contours because we cannot separate them into two + * separate bitmaps. In case of self-intersecting contours it is + * necessary to remove the overlaps before generating the SDF. + * + */ + static FT_Error + sdf_generate_with_overlaps( SDF_Params internal_params, + SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + + FT_Int num_contours; /* total number of contours */ + FT_Int i, j; /* iterators */ + FT_Int width, rows; /* width and rows of the bitmap */ + FT_Bitmap* bitmaps; /* separate bitmaps for contours */ + + SDF_Contour* contour; /* temporary variable to iterate */ + SDF_Contour* temp_contour; /* temporary contour */ + SDF_Contour* head; /* head of the contour list */ + SDF_Shape temp_shape; /* temporary shape */ + + FT_Memory memory; /* to allocate memory */ + FT_SDFFormat* t; /* target bitmap buffer */ + FT_Bool flip_sign; /* flip sign? */ + + /* orientation of all the separate contours */ + SDF_Contour_Orientation* orientations; + + + bitmaps = NULL; + orientations = NULL; + head = NULL; + + if ( !shape || !bitmap || !shape->memory ) + return FT_THROW( Invalid_Argument ); + + /* Disable `flip_sign` to avoid extra complication */ + /* during the combination phase. */ + flip_sign = internal_params.flip_sign; + internal_params.flip_sign = 0; + + contour = shape->contours; + memory = shape->memory; + temp_shape.memory = memory; + width = (FT_Int)bitmap->width; + rows = (FT_Int)bitmap->rows; + num_contours = 0; + + /* find the number of contours in the shape */ + while ( contour ) + { + num_contours++; + contour = contour->next; + } + + /* allocate the bitmaps to generate SDF for separate contours */ + if ( FT_ALLOC( bitmaps, + (FT_UInt)num_contours * sizeof ( *bitmaps ) ) ) + goto Exit; + + /* allocate array to hold orientation for all contours */ + if ( FT_ALLOC( orientations, + (FT_UInt)num_contours * sizeof ( *orientations ) ) ) + goto Exit; + + contour = shape->contours; + + /* Iterate over all contours and generate SDF separately. */ + for ( i = 0; i < num_contours; i++ ) + { + /* initialize the corresponding bitmap */ + FT_Bitmap_Init( &bitmaps[i] ); + + bitmaps[i].width = bitmap->width; + bitmaps[i].rows = bitmap->rows; + bitmaps[i].pitch = bitmap->pitch; + bitmaps[i].num_grays = bitmap->num_grays; + bitmaps[i].pixel_mode = bitmap->pixel_mode; + + /* allocate memory for the buffer */ + if ( FT_ALLOC( bitmaps[i].buffer, + bitmap->rows * (FT_UInt)bitmap->pitch ) ) + goto Exit; + + /* determine the orientation */ + orientations[i] = get_contour_orientation( contour ); + + /* The `overload_sign` property is specific to */ + /* `sdf_generate_bounding_box`. This basically */ + /* overloads the default sign of the outside */ + /* pixels, which is necessary for */ + /* counter-clockwise contours. */ + if ( orientations[i] == SDF_ORIENTATION_CCW && + internal_params.orientation == FT_ORIENTATION_FILL_RIGHT ) + internal_params.overload_sign = 1; + else if ( orientations[i] == SDF_ORIENTATION_CW && + internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + internal_params.overload_sign = 1; + else + internal_params.overload_sign = 0; + + /* Make `contour->next` NULL so that there is */ + /* one contour in the list. Also hold the next */ + /* contour in a temporary variable so as to */ + /* restore the original value. */ + temp_contour = contour->next; + contour->next = NULL; + + /* Use `temp_shape` to hold the new contour. */ + /* Now, `temp_shape` has only one contour. */ + temp_shape.contours = contour; + + /* finally generate the SDF */ + FT_CALL( sdf_generate_subdivision( internal_params, + &temp_shape, + spread, + &bitmaps[i] ) ); + + /* Restore the original `next` variable. */ + contour->next = temp_contour; + + /* Since `split_sdf_shape` deallocated the original */ + /* contours list we need to assign the new value to */ + /* the shape's contour. */ + temp_shape.contours->next = head; + head = temp_shape.contours; + + /* Simply flip the orientation in case of post-script fonts */ + /* so as to avoid modificatons in the combining phase. */ + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + { + if ( orientations[i] == SDF_ORIENTATION_CW ) + orientations[i] = SDF_ORIENTATION_CCW; + else if ( orientations[i] == SDF_ORIENTATION_CCW ) + orientations[i] = SDF_ORIENTATION_CW; + } + + contour = contour->next; + } + + /* assign the new contour list to `shape->contours` */ + shape->contours = head; + + /* cast the output bitmap buffer */ + t = (FT_SDFFormat*)bitmap->buffer; + + /* Iterate over all pixels and combine all separate */ + /* contours. These are the rules for combining: */ + /* */ + /* (1) For all clockwise contours, compute the largest */ + /* value. Name this as `val_c`. */ + /* (2) For all counter-clockwise contours, compute the */ + /* smallest value. Name this as `val_ac`. */ + /* (3) Now, finally use the smaller value of `val_c' */ + /* and `val_ac'. */ + for ( j = 0; j < rows; j++ ) + { + for ( i = 0; i < width; i++ ) + { + FT_Int id = j * width + i; /* index of current pixel */ + FT_Int c; /* contour iterator */ + + FT_SDFFormat val_c = 0; /* max clockwise value */ + FT_SDFFormat val_ac = UCHAR_MAX; /* min counter-clockwise val */ + + + /* iterate through all the contours */ + for ( c = 0; c < num_contours; c++ ) + { + /* current contour value */ + FT_SDFFormat temp = ( (FT_SDFFormat*)bitmaps[c].buffer )[id]; + + + if ( orientations[c] == SDF_ORIENTATION_CW ) + val_c = FT_MAX( val_c, temp ); /* clockwise */ + else + val_ac = FT_MIN( val_ac, temp ); /* counter-clockwise */ + } + + /* Finally find the smaller of the two and assign to output. */ + /* Also apply `flip_sign` if set. */ + t[id] = FT_MIN( val_c, val_ac ); + + if ( flip_sign ) + t[id] = invert_sign( t[id] ); + } + } + + Exit: + /* deallocate orientations array */ + if ( orientations ) + FT_FREE( orientations ); + + /* deallocate temporary bitmaps */ + if ( bitmaps ) + { + if ( num_contours == 0 ) + error = FT_THROW( Raster_Corrupted ); + else + { + for ( i = 0; i < num_contours; i++ ) + FT_FREE( bitmaps[i].buffer ); + + FT_FREE( bitmaps ); + } + } + + /* restore the `flip_sign` property */ + internal_params.flip_sign = flip_sign; + + return error; + } + + + /************************************************************************** + * + * interface functions + * + */ + + static FT_Error + sdf_raster_new( void* memory_, /* FT_Memory */ + FT_Raster* araster_ ) /* SDF_PRaster* */ + { + FT_Memory memory = (FT_Memory)memory_; + SDF_PRaster* araster = (SDF_PRaster*)araster_; + + + FT_Error error; + SDF_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + static void + sdf_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + static FT_Error + sdf_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return FT_Err_Ok; + } + + + static FT_Error + sdf_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + FT_Error error = FT_Err_Ok; + SDF_TRaster* sdf_raster = (SDF_TRaster*)raster; + FT_Outline* outline = NULL; + const SDF_Raster_Params* sdf_params = (const SDF_Raster_Params*)params; + + FT_Memory memory = NULL; + SDF_Shape* shape = NULL; + SDF_Params internal_params; + + + /* check for valid arguments */ + if ( !sdf_raster || !sdf_params ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + outline = (FT_Outline*)sdf_params->root.source; + + /* check whether outline is valid */ + if ( !outline ) + { + error = FT_THROW( Invalid_Outline ); + goto Exit; + } + + /* if the outline is empty, return */ + if ( outline->n_points <= 0 || outline->n_contours <= 0 ) + goto Exit; + + /* check whether the outline has valid fields */ + if ( !outline->contours || !outline->points ) + { + error = FT_THROW( Invalid_Outline ); + goto Exit; + } + + /* check whether spread is set properly */ + if ( sdf_params->spread > MAX_SPREAD || + sdf_params->spread < MIN_SPREAD ) + { + FT_TRACE0(( "sdf_raster_render:" + " The `spread' field of `SDF_Raster_Params' is invalid,\n" )); + FT_TRACE0(( " " + " the value of this field must be within [%d, %d].\n", + MIN_SPREAD, MAX_SPREAD )); + FT_TRACE0(( " " + " Also, you must pass `SDF_Raster_Params' instead of\n" )); + FT_TRACE0(( " " + " the default `FT_Raster_Params' while calling\n" )); + FT_TRACE0(( " " + " this function and set the fields properly.\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = sdf_raster->memory; + if ( !memory ) + { + FT_TRACE0(( "sdf_raster_render:" + " Raster not setup properly,\n" )); + FT_TRACE0(( " " + " unable to find memory handle.\n" )); + + error = FT_THROW( Invalid_Handle ); + goto Exit; + } + + /* set up the parameters */ + internal_params.orientation = FT_Outline_Get_Orientation( outline ); + internal_params.flip_sign = sdf_params->flip_sign; + internal_params.flip_y = sdf_params->flip_y; + internal_params.overload_sign = 0; + + FT_CALL( sdf_shape_new( memory, &shape ) ); + + FT_CALL( sdf_outline_decompose( outline, shape ) ); + + if ( sdf_params->overlaps ) + FT_CALL( sdf_generate_with_overlaps( internal_params, + shape, sdf_params->spread, + sdf_params->root.target ) ); + else + FT_CALL( sdf_generate_subdivision( internal_params, + shape, sdf_params->spread, + sdf_params->root.target ) ); + + if ( shape ) + sdf_shape_done( &shape ); + + Exit: + return error; + } + + + static void + sdf_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((SDF_TRaster*)raster)->memory; + + + FT_FREE( raster ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_sdf_raster, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Raster_New_Func) sdf_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) sdf_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)sdf_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) sdf_raster_render, /* raster_render */ + (FT_Raster_Done_Func) sdf_raster_done /* raster_done */ + ) + + +/* END */ diff --git a/vendor/freetype/src/sdf/ftsdf.h b/vendor/freetype/src/sdf/ftsdf.h new file mode 100644 index 0000000..234c075 --- /dev/null +++ b/vendor/freetype/src/sdf/ftsdf.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * + * ftsdf.h + * + * Signed Distance Field support (specification). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSDF_H_ +#define FTSDF_H_ + +#include +#include FT_CONFIG_CONFIG_H +#include + +/* common properties and function */ +#include "ftsdfcommon.h" + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @struct: + * SDF_Raster_Params + * + * @description: + * This struct must be passed to the raster render function + * @FT_Raster_RenderFunc instead of @FT_Raster_Params because the + * rasterizer requires some additional information to render properly. + * + * @fields: + * root :: + * The native raster parameters structure. + * + * spread :: + * This is an essential parameter/property required by the renderer. + * `spread` defines the maximum unsigned value that is present in the + * final SDF output. For the default value check file + * `ftsdfcommon.h`. + * + * flip_sign :: + * By default positive values indicate positions inside of contours, + * i.e., filled by a contour. If this property is true then that + * output will be the opposite of the default, i.e., negative values + * indicate positions inside of contours. + * + * flip_y :: + * Setting this parameter to true maked the output image flipped + * along the y-axis. + * + * overlaps :: + * Set this to true to generate SDF for glyphs having overlapping + * contours. The overlapping support is limited to glyphs that do not + * have self-intersecting contours. Also, removing overlaps require a + * considerable amount of extra memory; additionally, it will not work + * if generating SDF from bitmap. + * + * @note: + * All properties are valid for both the 'sdf' and 'bsdf' renderers; the + * exception is `overlaps`, which gets ignored by the 'bsdf' renderer. + * + */ + typedef struct SDF_Raster_Params_ + { + FT_Raster_Params root; + FT_UInt spread; + FT_Bool flip_sign; + FT_Bool flip_y; + FT_Bool overlaps; + + } SDF_Raster_Params; + + + /* rasterizer to convert outline to SDF */ + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_sdf_raster; + + /* rasterizer to convert bitmap to SDF */ + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_bitmap_sdf_raster; + +FT_END_HEADER + +#endif /* FTSDF_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sdf/ftsdfcommon.c b/vendor/freetype/src/sdf/ftsdfcommon.c new file mode 100644 index 0000000..5052201 --- /dev/null +++ b/vendor/freetype/src/sdf/ftsdfcommon.c @@ -0,0 +1,147 @@ +/**************************************************************************** + * + * ftsdfcommon.c + * + * Auxiliary data for Signed Distance Field support (body). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "ftsdf.h" +#include "ftsdfcommon.h" + + + /************************************************************************** + * + * common functions + * + */ + + /* + * Original algorithm: + * + * https://github.com/chmike/fpsqrt + * + * Use this to compute the square root of a 16.16 fixed-point number. + */ + FT_LOCAL_DEF( FT_16D16 ) + square_root( FT_16D16 val ) + { + FT_ULong t, q, b, r; + + + r = (FT_ULong)val; + b = 0x40000000L; + q = 0; + + while ( b > 0x40L ) + { + t = q + b; + + if ( r >= t ) + { + r -= t; + q = t + b; + } + + r <<= 1; + b >>= 1; + } + + q >>= 8; + + return (FT_16D16)q; + } + + + /************************************************************************** + * + * format and sign manipulating functions + * + */ + + /* + * Convert 16.16 fixed-point values to the desired output format. + * In this case we reduce 16.16 fixed-point values to normalized + * 8-bit values. + * + * The `max_value` in the parameter is the maximum value in the + * distance field map and is equal to the spread. We normalize + * the distances using this value instead of computing the maximum + * value for the entire bitmap. + * + * You can use this function to map the 16.16 signed values to any + * format required. Do note that the output buffer is 8-bit, so only + * use an 8-bit format for `FT_SDFFormat`, or increase the buffer size in + * `ftsdfrend.c`. + */ + FT_LOCAL_DEF( FT_SDFFormat ) + map_fixed_to_sdf( FT_16D16 dist, + FT_16D16 max_value ) + { + FT_SDFFormat out; + FT_16D16 udist; + + + /* normalize the distance values */ + dist = FT_DivFix( dist, max_value ); + + udist = dist < 0 ? -dist : dist; + + /* Reduce the distance values to 8 bits. */ + /* */ + /* Since +1/-1 in 16.16 takes the 16th bit, we right-shift */ + /* the number by 9 to make it fit into the 7-bit range. */ + /* */ + /* One bit is reserved for the sign. */ + udist >>= 9; + + /* Since `char` can only store a maximum positive value */ + /* of 127 we need to make sure it does not wrap around and */ + /* give a negative value. */ + if ( dist > 0 && udist > 127 ) + udist = 127; + if ( dist < 0 && udist > 128 ) + udist = 128; + + /* Output the data; negative values are from [0, 127] and positive */ + /* from [128, 255]. One important thing is that negative values */ + /* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */ + /* More on that in `freetype.h` near the documentation of */ + /* `FT_RENDER_MODE_SDF`. */ + out = dist < 0 ? 128 - (FT_SDFFormat)udist + : (FT_SDFFormat)udist + 128; + + return out; + } + + + /* + * Invert the signed distance packed into the corresponding format. + * So if the values are negative they will become positive in the + * chosen format. + * + * [Note]: This function should only be used after converting the + * 16.16 signed distance values to `FT_SDFFormat`. If that + * conversion has not been done, then simply invert the sign + * and use the above function to pack the values. + */ + FT_LOCAL_DEF( FT_SDFFormat ) + invert_sign( FT_SDFFormat dist ) + { + return 255 - dist; + } + + +/* END */ diff --git a/vendor/freetype/src/sdf/ftsdfcommon.h b/vendor/freetype/src/sdf/ftsdfcommon.h new file mode 100644 index 0000000..60ca977 --- /dev/null +++ b/vendor/freetype/src/sdf/ftsdfcommon.h @@ -0,0 +1,141 @@ +/**************************************************************************** + * + * ftsdfcommon.h + * + * Auxiliary data for Signed Distance Field support (specification). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /**************************************************** + * + * This file contains common functions and properties + * for both the 'sdf' and 'bsdf' renderers. + * + */ + +#ifndef FTSDFCOMMON_H_ +#define FTSDFCOMMON_H_ + +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * default values (cannot be set individually for each renderer) + * + */ + + /* default spread value */ +#define DEFAULT_SPREAD 8 + /* minimum spread supported by the renderer */ +#define MIN_SPREAD 2 + /* maximum spread supported by the renderer */ +#define MAX_SPREAD 32 + /* pixel size in 26.6 */ +#define ONE_PIXEL ( 1 << 6 ) + + + /************************************************************************** + * + * common definitions (cannot be set individually for each renderer) + * + */ + + /* If this macro is set to 1 the rasterizer uses squared distances for */ + /* computation. It can greatly improve the performance but there is a */ + /* chance of overflow and artifacts. You can safely use it up to a */ + /* pixel size of 128. */ +#ifndef USE_SQUARED_DISTANCES +#define USE_SQUARED_DISTANCES 0 +#endif + + + /************************************************************************** + * + * common macros + * + */ + + /* convert int to 26.6 fixed-point */ +#define FT_INT_26D6( x ) ( x * 64 ) + /* convert int to 16.16 fixed-point */ +#define FT_INT_16D16( x ) ( x * 65536 ) + /* convert 26.6 to 16.16 fixed-point */ +#define FT_26D6_16D16( x ) ( x * 1024 ) + + + /* Convenience macro to call a function; it */ + /* jumps to label `Exit` if an error occurs. */ +#define FT_CALL( x ) do \ + { \ + error = ( x ); \ + if ( error != FT_Err_Ok ) \ + goto Exit; \ + } while ( 0 ) + + + /* + * The macro `VECTOR_LENGTH_16D16` computes either squared distances or + * actual distances, depending on the value of `USE_SQUARED_DISTANCES`. + * + * By using squared distances the performance can be greatly improved but + * there is a risk of overflow. + */ +#if USE_SQUARED_DISTANCES +#define VECTOR_LENGTH_16D16( v ) ( FT_MulFix( v.x, v.x ) + \ + FT_MulFix( v.y, v.y ) ) +#else +#define VECTOR_LENGTH_16D16( v ) FT_Vector_Length( &v ) +#endif + + + /************************************************************************** + * + * common typedefs + * + */ + + typedef FT_Vector FT_26D6_Vec; /* with 26.6 fixed-point components */ + typedef FT_Vector FT_16D16_Vec; /* with 16.16 fixed-point components */ + + typedef FT_Int32 FT_16D16; /* 16.16 fixed-point representation */ + typedef FT_Int32 FT_26D6; /* 26.6 fixed-point representation */ + typedef FT_Byte FT_SDFFormat; /* format to represent SDF data */ + + typedef FT_BBox FT_CBox; /* control box of a curve */ + + + FT_LOCAL( FT_16D16 ) + square_root( FT_16D16 val ); + + FT_LOCAL( FT_SDFFormat ) + map_fixed_to_sdf( FT_16D16 dist, + FT_16D16 max_value ); + + FT_LOCAL( FT_SDFFormat ) + invert_sign( FT_SDFFormat dist ); + + +FT_END_HEADER + +#endif /* FTSDFCOMMON_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sdf/ftsdferrs.h b/vendor/freetype/src/sdf/ftsdferrs.h new file mode 100644 index 0000000..519db0f --- /dev/null +++ b/vendor/freetype/src/sdf/ftsdferrs.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * ftsdferrs.h + * + * Signed Distance Field error codes (specification only). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSDFERRS_H_ +#define FTSDFERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Sdf_Err_ +#define FT_ERR_BASE FT_Mod_Err_Sdf + +#include + +#endif /* FTSDFERRS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sdf/ftsdfrend.c b/vendor/freetype/src/sdf/ftsdfrend.c new file mode 100644 index 0000000..5610c11 --- /dev/null +++ b/vendor/freetype/src/sdf/ftsdfrend.c @@ -0,0 +1,603 @@ +/**************************************************************************** + * + * ftsdfrend.c + * + * Signed Distance Field renderer interface (body). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include "ftsdfrend.h" +#include "ftsdf.h" + +#include "ftsdferrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sdf + + + /************************************************************************** + * + * macros and default property values + * + */ +#define SDF_RENDERER( rend ) ( (SDF_Renderer)rend ) + + + /************************************************************************** + * + * for setting properties + * + */ + + /* property setter function */ + static FT_Error + sdf_property_set( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); + + FT_UNUSED( value_is_string ); + + + if ( ft_strcmp( property_name, "spread" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + if ( val > MAX_SPREAD || val < MIN_SPREAD ) + { + FT_TRACE0(( "[sdf] sdf_property_set:" + " the `spread' property can have a value\n" )); + FT_TRACE0(( " " + " within range [%d, %d] (value provided: %d)\n", + MIN_SPREAD, MAX_SPREAD, val )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + render->spread = (FT_UInt)val; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `spread' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + render->flip_sign = val ? 1 : 0; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `flip_sign' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + render->flip_y = val ? 1 : 0; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `flip_y' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) + { + FT_Bool val = *(const FT_Bool*)value; + + + render->overlaps = val; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `overlaps' to %d\n", val )); + } + + else + { + FT_TRACE0(( "[sdf] sdf_property_set:" + " missing property `%s'\n", property_name )); + error = FT_THROW( Missing_Property ); + } + + Exit: + return error; + } + + + /* property getter function */ + static FT_Error + sdf_property_get( FT_Module module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); + + + if ( ft_strcmp( property_name, "spread" ) == 0 ) + { + FT_UInt* val = (FT_UInt*)value; + + + *val = render->spread; + } + + else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->flip_sign; + } + + else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->flip_y; + } + + else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->overlaps; + } + + else + { + FT_TRACE0(( "[sdf] sdf_property_get:" + " missing property `%s'\n", property_name )); + error = FT_THROW( Missing_Property ); + } + + return error; + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + sdf_service_properties, + + (FT_Properties_SetFunc)sdf_property_set, /* set_property */ + (FT_Properties_GetFunc)sdf_property_get ) /* get_property */ + + + FT_DEFINE_SERVICEDESCREC1( + sdf_services, + + FT_SERVICE_ID_PROPERTIES, &sdf_service_properties ) + + + static FT_Module_Interface + ft_sdf_requester( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( sdf_services, module_interface ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** OUTLINE TO SDF CONVERTER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * interface functions + * + */ + + static FT_Error + ft_sdf_init( FT_Module module ) /* SDF_Renderer */ + { + SDF_Renderer sdf_render = SDF_RENDERER( module ); + + + sdf_render->spread = DEFAULT_SPREAD; + sdf_render->flip_sign = 0; + sdf_render->flip_y = 0; + sdf_render->overlaps = 0; + + return FT_Err_Ok; + } + + + static void + ft_sdf_done( FT_Module module ) + { + FT_UNUSED( module ); + } + + + /* generate signed distance field from a glyph's slot image */ + static FT_Error + ft_sdf_render( FT_Renderer module, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = NULL; + FT_Renderer render = NULL; + + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + + FT_Pos x_pad = 0; + FT_Pos y_pad = 0; + + SDF_Raster_Params params; + SDF_Renderer sdf_module = SDF_RENDERER( module ); + + + render = &sdf_module->root; + memory = render->root.memory; + + /* check whether slot format is correct before rendering */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* check whether render mode is correct */ + if ( mode != FT_RENDER_MODE_SDF ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* deallocate the previously allocated bitmap */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + /* preset the bitmap using the glyph's outline; */ + /* the sdf bitmap is similar to an anti-aliased bitmap */ + /* with a slightly bigger size and different pixel mode */ + if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) ) + { + error = FT_THROW( Raster_Overflow ); + goto Exit; + } + + /* nothing to render */ + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* the padding will simply be equal to the `spread' */ + x_pad = sdf_module->spread; + y_pad = sdf_module->spread; + + /* apply the padding; will be in all the directions */ + bitmap->rows += y_pad * 2; + bitmap->width += x_pad * 2; + + /* ignore the pitch, pixel mode and set custom */ + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->pitch = (int)( bitmap->width ); + bitmap->num_grays = 255; + + /* allocate new buffer */ + if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + slot->bitmap_top += y_pad; + slot->bitmap_left -= x_pad; + + x_shift = 64 * -slot->bitmap_left; + y_shift = 64 * -slot->bitmap_top; + y_shift += 64 * (FT_Int)bitmap->rows; + + if ( origin ) + { + x_shift += origin->x; + y_shift += origin->y; + } + + /* translate outline to render it into the bitmap */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, x_shift, y_shift ); + + /* set up parameters */ + params.root.target = bitmap; + params.root.source = outline; + params.root.flags = FT_RASTER_FLAG_SDF; + params.spread = sdf_module->spread; + params.flip_sign = sdf_module->flip_sign; + params.flip_y = sdf_module->flip_y; + params.overlaps = sdf_module->overlaps; + + /* render the outline */ + error = render->raster_render( render->raster, + (const FT_Raster_Params*)¶ms ); + + /* transform the outline back to the original state */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + Exit: + if ( !error ) + { + /* the glyph is successfully rendered to a bitmap */ + slot->format = FT_GLYPH_FORMAT_BITMAP; + } + else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + return error; + } + + + /* transform the glyph using matrix and/or delta */ + static FT_Error + ft_sdf_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the control box of a glyph's outline */ + static void + ft_sdf_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_ZERO( cbox ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* set render specific modes or attributes */ + static FT_Error + ft_sdf_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* pass it to the rasterizer */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + + FT_DEFINE_RENDERER( + ft_sdf_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SDF_Renderer_Module ), + + "sdf", + 0x10000L, + 0x20000L, + + NULL, + + (FT_Module_Constructor)ft_sdf_init, + (FT_Module_Destructor) ft_sdf_done, + (FT_Module_Requester) ft_sdf_requester, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_sdf_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_sdf_raster /* raster_class */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** BITMAP TO SDF CONVERTER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /* generate signed distance field from glyph's bitmap */ + static FT_Error + ft_bsdf_render( FT_Renderer module, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + FT_Bitmap* bitmap = &slot->bitmap; + FT_Renderer render = NULL; + FT_Bitmap target; + + FT_Pos x_pad = 0; + FT_Pos y_pad = 0; + + SDF_Raster_Params params; + SDF_Renderer sdf_module = SDF_RENDERER( module ); + + + /* initialize the bitmap in case any error occurs */ + FT_Bitmap_Init( &target ); + + render = &sdf_module->root; + memory = render->root.memory; + + /* check whether slot format is correct before rendering */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* check whether render mode is correct */ + if ( mode != FT_RENDER_MODE_SDF ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + if ( origin ) + { + FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" )); + + error = FT_THROW( Unimplemented_Feature ); + goto Exit; + } + + /* nothing to render */ + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* Do not generate SDF if the bitmap is not owned by the */ + /* glyph: it might be that the source buffer is already freed. */ + if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_ERROR(( "ft_bsdf_render: can't generate SDF from" + " unowned source bitmap\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_Bitmap_New( &target ); + + /* padding will simply be equal to `spread` */ + x_pad = sdf_module->spread; + y_pad = sdf_module->spread; + + /* apply padding, which extends to all directions */ + target.rows = bitmap->rows + y_pad * 2; + target.width = bitmap->width + x_pad * 2; + + /* set up the target bitmap */ + target.pixel_mode = FT_PIXEL_MODE_GRAY; + target.pitch = (int)( target.width ); + target.num_grays = 255; + + if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) ) + goto Exit; + + /* set up parameters */ + params.root.target = ⌖ + params.root.source = bitmap; + params.root.flags = FT_RASTER_FLAG_SDF; + params.spread = sdf_module->spread; + params.flip_sign = sdf_module->flip_sign; + params.flip_y = sdf_module->flip_y; + + error = render->raster_render( render->raster, + (const FT_Raster_Params*)¶ms ); + + Exit: + if ( !error ) + { + /* the glyph is successfully converted to a SDF */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + FT_FREE( bitmap->buffer ); + + slot->bitmap = target; + slot->bitmap_top += y_pad; + slot->bitmap_left -= x_pad; + + if ( target.buffer ) + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + else if ( target.buffer ) + FT_FREE( target.buffer ); + + return error; + } + + + FT_DEFINE_RENDERER( + ft_bitmap_sdf_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SDF_Renderer_Module ), + + "bsdf", + 0x10000L, + 0x20000L, + + NULL, + + (FT_Module_Constructor)ft_sdf_init, + (FT_Module_Destructor) ft_sdf_done, + (FT_Module_Requester) ft_sdf_requester, + + FT_GLYPH_FORMAT_BITMAP, + + (FT_Renderer_RenderFunc) ft_bsdf_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_bitmap_sdf_raster /* raster_class */ + ) + + +/* END */ diff --git a/vendor/freetype/src/sdf/ftsdfrend.h b/vendor/freetype/src/sdf/ftsdfrend.h new file mode 100644 index 0000000..571ac83 --- /dev/null +++ b/vendor/freetype/src/sdf/ftsdfrend.h @@ -0,0 +1,118 @@ +/**************************************************************************** + * + * ftsdfrend.h + * + * Signed Distance Field renderer interface (specification). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSDFREND_H_ +#define FTSDFREND_H_ + +#include +#include +#include + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * SDF_Renderer_Module + * + * @description: + * This struct extends the native renderer struct `FT_RendererRec`. It + * is basically used to store various parameters required by the + * renderer and some additional parameters that can be used to tweak the + * output of the renderer. + * + * @fields: + * root :: + * The native rendere struct. + * + * spread :: + * This is an essential parameter/property required by the renderer. + * `spread` defines the maximum unsigned value that is present in the + * final SDF output. For the default value check file + * `ftsdfcommon.h`. + * + * flip_sign :: + * By default positive values indicate positions inside of contours, + * i.e., filled by a contour. If this property is true then that + * output will be the opposite of the default, i.e., negative values + * indicate positions inside of contours. + * + * flip_y :: + * Setting this parameter to true makes the output image flipped + * along the y-axis. + * + * overlaps :: + * Set this to true to generate SDF for glyphs having overlapping + * contours. The overlapping support is limited to glyphs that do not + * have self-intersecting contours. Also, removing overlaps require a + * considerable amount of extra memory; additionally, it will not work + * if generating SDF from bitmap. + * + * @note: + * All properties except `overlaps` are valid for both the 'sdf' and + * 'bsdf' renderers. + * + */ + typedef struct SDF_Renderer_Module_ + { + FT_RendererRec root; + FT_UInt spread; + FT_Bool flip_sign; + FT_Bool flip_y; + FT_Bool overlaps; + + } SDF_Renderer_Module, *SDF_Renderer; + + + /************************************************************************** + * + * @renderer: + * ft_sdf_renderer_class + * + * @description: + * Renderer to convert @FT_Outline to signed distance fields. + * + */ + FT_DECLARE_RENDERER( ft_sdf_renderer_class ) + + + /************************************************************************** + * + * @renderer: + * ft_bitmap_sdf_renderer_class + * + * @description: + * This is not exactly a renderer; it is just a converter that + * transforms bitmaps to signed distance fields. + * + * @note: + * This is not a separate module, it is part of the 'sdf' module. + * + */ + FT_DECLARE_RENDERER( ft_bitmap_sdf_renderer_class ) + + +FT_END_HEADER + +#endif /* FTSDFREND_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sdf/module.mk b/vendor/freetype/src/sdf/module.mk new file mode 100644 index 0000000..e896d20 --- /dev/null +++ b/vendor/freetype/src/sdf/module.mk @@ -0,0 +1,29 @@ +# +# FreeType 2 Signed Distance Field module definition +# + + +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += SDF_RENDERER +FTMODULE_H_COMMANDS += BSDF_RENDERER + +define SDF_RENDERER +$(OPEN_DRIVER) FT_Renderer_Class, ft_sdf_renderer_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)sdf $(ECHO_DRIVER_DESC)signed distance field renderer$(ECHO_DRIVER_DONE) +endef + +define BSDF_RENDERER +$(OPEN_DRIVER) FT_Renderer_Class, ft_bitmap_sdf_renderer_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)bsdf $(ECHO_DRIVER_DESC)bitmap to signed distance field converter$(ECHO_DRIVER_DONE) +endef + +#EOF diff --git a/vendor/freetype/src/sdf/rules.mk b/vendor/freetype/src/sdf/rules.mk new file mode 100644 index 0000000..d774241 --- /dev/null +++ b/vendor/freetype/src/sdf/rules.mk @@ -0,0 +1,78 @@ +# +# FreeType 2 Signed Distance Field driver configuration rules +# + + +# Copyright (C) 2020-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# sdf driver directory +# +SDF_DIR := $(SRC_DIR)/sdf + + +# compilation flags for the driver +# +SDF_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(SDF_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# sdf driver sources (i.e., C files) +# +SDF_DRV_SRC := $(SDF_DIR)/ftsdfrend.c \ + $(SDF_DIR)/ftsdf.c \ + $(SDF_DIR)/ftbsdf.c \ + $(SDF_DIR)/ftsdfcommon.c + + +# sdf driver headers +# +SDF_DRV_H := $(SDF_DIR)/ftsdfrend.h \ + $(SDF_DIR)/ftsdf.h \ + $(SDF_DIR)/ftsdferrs.h \ + $(SDF_DIR)/ftsdfcommon.h + + +# sdf driver object(s) +# +# SDF_DRV_OBJ_M is used during `multi' builds. +# SDF_DRV_OBJ_S is used during `single' builds. +# +SDF_DRV_OBJ_M := $(SDF_DRV_SRC:$(SDF_DIR)/%.c=$(OBJ_DIR)/%.$O) +SDF_DRV_OBJ_S := $(OBJ_DIR)/sdf.$O + + +# sdf driver source file for single build +# +SDF_DRV_SRC_S := $(SDF_DIR)/sdf.c + + +# sdf driver - single object +# +$(SDF_DRV_OBJ_S): $(SDF_DRV_SRC_S) $(SDF_DRV_SRC) \ + $(FREETYPE_H) $(SDF_DRV_H) + $(SDF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(SDF_DRV_SRC_S)) + + +# sdf driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(SDF_DIR)/%.c $(FREETYPE_H) $(SDF_DRV_H) + $(SDF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver list +# +DRV_OBJS_S += $(SDF_DRV_OBJ_S) +DRV_OBJS_M += $(SDF_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/sdf/sdf.c b/vendor/freetype/src/sdf/sdf.c new file mode 100644 index 0000000..c159b08 --- /dev/null +++ b/vendor/freetype/src/sdf/sdf.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * sdf.c + * + * FreeType Signed Distance Field renderer module component (body only). + * + * Copyright (C) 2020-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftsdfrend.c" +#include "ftsdfcommon.c" +#include "ftbsdf.c" +#include "ftsdf.c" + + +/* END */ diff --git a/vendor/freetype/src/sfnt/module.mk b/vendor/freetype/src/sfnt/module.mk new file mode 100644 index 0000000..4491a1b --- /dev/null +++ b/vendor/freetype/src/sfnt/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 SFNT module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += SFNT_MODULE + +define SFNT_MODULE +$(OPEN_DRIVER) FT_Module_Class, sfnt_module_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)sfnt $(ECHO_DRIVER_DESC)helper module for TrueType & OpenType formats$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/sfnt/pngshim.c b/vendor/freetype/src/sfnt/pngshim.c new file mode 100644 index 0000000..3371216 --- /dev/null +++ b/vendor/freetype/src/sfnt/pngshim.c @@ -0,0 +1,462 @@ +/**************************************************************************** + * + * pngshim.c + * + * PNG Bitmap glyph support. + * + * Copyright (C) 2013-2023 by + * Google, Inc. + * Written by Stuart Gill and Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#if defined( TT_CONFIG_OPTION_EMBEDDED_BITMAPS ) && \ + defined( FT_CONFIG_OPTION_USE_PNG ) + + /* We always include , so make libpng shut up! */ +#define PNG_SKIP_SETJMP_CHECK 1 +#include +#include "pngshim.h" + +#include "sferrors.h" + + + /* This code is freely based on cairo-png.c. There's so many ways */ + /* to call libpng, and the way cairo does it is defacto standard. */ + + static unsigned int + multiply_alpha( unsigned int alpha, + unsigned int color ) + { + unsigned int temp = alpha * color + 0x80; + + + return ( temp + ( temp >> 8 ) ) >> 8; + } + + + /* Premultiplies data and converts RGBA bytes => BGRA. */ + static void + premultiply_data( png_structp png, + png_row_infop row_info, + png_bytep data ) + { + unsigned int i = 0, limit; + + /* The `vector_size' attribute was introduced in gcc 3.1, which */ + /* predates clang; the `__BYTE_ORDER__' preprocessor symbol was */ + /* introduced in gcc 4.6 and clang 3.2, respectively. */ + /* `__builtin_shuffle' for gcc was introduced in gcc 4.7.0. */ + /* */ + /* Intel compilers do not currently support __builtin_shuffle; */ + + /* The Intel check must be first. */ +#if !defined( __INTEL_COMPILER ) && \ + ( ( defined( __GNUC__ ) && \ + ( ( __GNUC__ >= 5 ) || \ + ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 7 ) ) ) ) || \ + ( defined( __clang__ ) && \ + ( ( __clang_major__ >= 4 ) || \ + ( ( __clang_major__ == 3 ) && ( __clang_minor__ >= 2 ) ) ) ) ) && \ + defined( __OPTIMIZE__ ) && \ + defined( __SSE__ ) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + +#ifdef __clang__ + /* the clang documentation doesn't cover the two-argument case of */ + /* `__builtin_shufflevector'; however, it is is implemented since */ + /* version 2.8 */ +#define vector_shuffle __builtin_shufflevector +#else +#define vector_shuffle __builtin_shuffle +#endif + + typedef unsigned short v82 __attribute__(( vector_size( 16 ) )); + + + if ( row_info->rowbytes > 15 ) + { + /* process blocks of 16 bytes in one rush, which gives a nice speed-up */ + limit = row_info->rowbytes - 16 + 1; + for ( ; i < limit; i += 16 ) + { + unsigned char* base = &data[i]; + + v82 s, s0, s1, a; + + /* clang <= 3.9 can't apply scalar values to vectors */ + /* (or rather, it needs a different syntax) */ + v82 n0x80 = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + v82 n0xFF = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + v82 n8 = { 8, 8, 8, 8, 8, 8, 8, 8 }; + + v82 ma = { 1, 1, 3, 3, 5, 5, 7, 7 }; + v82 o1 = { 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF }; + v82 m0 = { 1, 0, 3, 2, 5, 4, 7, 6 }; + + + ft_memcpy( &s, base, 16 ); /* RGBA RGBA RGBA RGBA */ + s0 = s & n0xFF; /* R B R B R B R B */ + s1 = s >> n8; /* G A G A G A G A */ + + a = vector_shuffle( s1, ma ); /* A A A A A A A A */ + s1 |= o1; /* G 1 G 1 G 1 G 1 */ + s0 = vector_shuffle( s0, m0 ); /* B R B R B R B R */ + + s0 *= a; + s1 *= a; + s0 += n0x80; + s1 += n0x80; + s0 = ( s0 + ( s0 >> n8 ) ) >> n8; + s1 = ( s1 + ( s1 >> n8 ) ) >> n8; + + s = s0 | ( s1 << n8 ); + ft_memcpy( base, &s, 16 ); + } + } +#endif /* use `vector_size' */ + + FT_UNUSED( png ); + + limit = row_info->rowbytes; + for ( ; i < limit; i += 4 ) + { + unsigned char* base = &data[i]; + unsigned int alpha = base[3]; + + + if ( alpha == 0 ) + base[0] = base[1] = base[2] = base[3] = 0; + + else + { + unsigned int red = base[0]; + unsigned int green = base[1]; + unsigned int blue = base[2]; + + + if ( alpha != 0xFF ) + { + red = multiply_alpha( alpha, red ); + green = multiply_alpha( alpha, green ); + blue = multiply_alpha( alpha, blue ); + } + + base[0] = (unsigned char)blue; + base[1] = (unsigned char)green; + base[2] = (unsigned char)red; + base[3] = (unsigned char)alpha; + } + } + } + + + /* Converts RGBx bytes to BGRA. */ + static void + convert_bytes_to_data( png_structp png, + png_row_infop row_info, + png_bytep data ) + { + unsigned int i; + + FT_UNUSED( png ); + + + for ( i = 0; i < row_info->rowbytes; i += 4 ) + { + unsigned char* base = &data[i]; + unsigned int red = base[0]; + unsigned int green = base[1]; + unsigned int blue = base[2]; + + + base[0] = (unsigned char)blue; + base[1] = (unsigned char)green; + base[2] = (unsigned char)red; + base[3] = 0xFF; + } + } + + + /* Use error callback to avoid png writing to stderr. */ + static void + error_callback( png_structp png, + png_const_charp error_msg ) + { + FT_Error* error = (FT_Error*)png_get_error_ptr( png ); + + FT_UNUSED( error_msg ); + + + *error = FT_THROW( Out_Of_Memory ); +#ifdef PNG_SETJMP_SUPPORTED + ft_longjmp( png_jmpbuf( png ), 1 ); +#endif + /* if we get here, then we have no choice but to abort ... */ + } + + + /* Use warning callback to avoid png writing to stderr. */ + static void + warning_callback( png_structp png, + png_const_charp error_msg ) + { + FT_UNUSED( png ); + FT_UNUSED( error_msg ); + + /* Just ignore warnings. */ + } + + + static void + read_data_from_FT_Stream( png_structp png, + png_bytep data, + png_size_t length ) + { + FT_Error error; + png_voidp p = png_get_io_ptr( png ); + FT_Stream stream = (FT_Stream)p; + + + if ( FT_FRAME_ENTER( length ) ) + { + FT_Error* e = (FT_Error*)png_get_error_ptr( png ); + + + *e = FT_THROW( Invalid_Stream_Read ); + png_error( png, NULL ); + + /* return; (never reached) */ + } + + ft_memcpy( data, stream->cursor, length ); + + FT_FRAME_EXIT(); + } + + + FT_LOCAL_DEF( FT_Error ) + Load_SBit_Png( FT_GlyphSlot slot, + FT_Int x_offset, + FT_Int y_offset, + FT_Int pix_bits, + TT_SBit_Metrics metrics, + FT_Memory memory, + FT_Byte* data, + FT_UInt png_len, + FT_Bool populate_map_and_metrics, + FT_Bool metrics_only ) + { + FT_Bitmap *map = &slot->bitmap; + FT_Error error = FT_Err_Ok; + FT_StreamRec stream; + + png_structp png; + png_infop info; + png_uint_32 imgWidth, imgHeight; + + int bitdepth, color_type, interlace; + FT_Int i; + + /* `rows` gets modified within a 'setjmp' scope; */ + /* we thus need the `volatile` keyword. */ + png_byte* *volatile rows = NULL; + + + if ( x_offset < 0 || + y_offset < 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !populate_map_and_metrics && + ( (FT_UInt)x_offset + metrics->width > map->width || + (FT_UInt)y_offset + metrics->height > map->rows || + pix_bits != 32 || + map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_Stream_OpenMemory( &stream, data, png_len ); + + png = png_create_read_struct( PNG_LIBPNG_VER_STRING, + &error, + error_callback, + warning_callback ); + if ( !png ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + + info = png_create_info_struct( png ); + if ( !info ) + { + error = FT_THROW( Out_Of_Memory ); + png_destroy_read_struct( &png, NULL, NULL ); + goto Exit; + } + + if ( ft_setjmp( png_jmpbuf( png ) ) ) + { + error = FT_THROW( Invalid_File_Format ); + goto DestroyExit; + } + + png_set_read_fn( png, &stream, read_data_from_FT_Stream ); + + png_read_info( png, info ); + png_get_IHDR( png, info, + &imgWidth, &imgHeight, + &bitdepth, &color_type, &interlace, + NULL, NULL ); + + if ( error || + ( !populate_map_and_metrics && + ( (FT_Int)imgWidth != metrics->width || + (FT_Int)imgHeight != metrics->height ) ) ) + goto DestroyExit; + + if ( populate_map_and_metrics ) + { + /* reject too large bitmaps similarly to the rasterizer */ + if ( imgHeight > 0x7FFF || imgWidth > 0x7FFF ) + { + error = FT_THROW( Array_Too_Large ); + goto DestroyExit; + } + + metrics->width = (FT_UShort)imgWidth; + metrics->height = (FT_UShort)imgHeight; + + map->width = metrics->width; + map->rows = metrics->height; + map->pixel_mode = FT_PIXEL_MODE_BGRA; + map->pitch = (int)( map->width * 4 ); + map->num_grays = 256; + } + + /* convert palette/gray image to rgb */ + if ( color_type == PNG_COLOR_TYPE_PALETTE ) + png_set_palette_to_rgb( png ); + + /* expand gray bit depth if needed */ + if ( color_type == PNG_COLOR_TYPE_GRAY ) + { +#if PNG_LIBPNG_VER >= 10209 + png_set_expand_gray_1_2_4_to_8( png ); +#else + png_set_gray_1_2_4_to_8( png ); +#endif + } + + /* transform transparency to alpha */ + if ( png_get_valid( png, info, PNG_INFO_tRNS ) ) + png_set_tRNS_to_alpha( png ); + + if ( bitdepth == 16 ) + png_set_strip_16( png ); + + if ( bitdepth < 8 ) + png_set_packing( png ); + + /* convert grayscale to RGB */ + if ( color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) + png_set_gray_to_rgb( png ); + + if ( interlace != PNG_INTERLACE_NONE ) + png_set_interlace_handling( png ); + + png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); + + /* recheck header after setting EXPAND options */ + png_read_update_info( png, info ); + png_get_IHDR( png, info, + &imgWidth, &imgHeight, + &bitdepth, &color_type, &interlace, + NULL, NULL ); + + if ( bitdepth != 8 || + !( color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) + { + error = FT_THROW( Invalid_File_Format ); + goto DestroyExit; + } + + if ( metrics_only ) + goto DestroyExit; + + switch ( color_type ) + { + default: /* Shouldn't happen, but ... */ + case PNG_COLOR_TYPE_RGB_ALPHA: + png_set_read_user_transform_fn( png, premultiply_data ); + break; + + case PNG_COLOR_TYPE_RGB: + /* Humm, this smells. Carry on though. */ + png_set_read_user_transform_fn( png, convert_bytes_to_data ); + break; + } + + if ( populate_map_and_metrics ) + { + /* this doesn't overflow: 0x7FFF * 0x7FFF * 4 < 2^32 */ + FT_ULong size = map->rows * (FT_ULong)map->pitch; + + + error = ft_glyphslot_alloc_bitmap( slot, size ); + if ( error ) + goto DestroyExit; + } + + if ( FT_QNEW_ARRAY( rows, imgHeight ) ) + { + error = FT_THROW( Out_Of_Memory ); + goto DestroyExit; + } + + for ( i = 0; i < (FT_Int)imgHeight; i++ ) + rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; + + png_read_image( png, rows ); + + png_read_end( png, info ); + + DestroyExit: + /* even if reading fails with longjmp, rows must be freed */ + FT_FREE( rows ); + png_destroy_read_struct( &png, &info, NULL ); + FT_Stream_Close( &stream ); + + Exit: + return error; + } + +#else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ + + /* ANSI C doesn't like empty source files */ + typedef int pngshim_dummy_; + +#endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/pngshim.h b/vendor/freetype/src/sfnt/pngshim.h new file mode 100644 index 0000000..903bd2b --- /dev/null +++ b/vendor/freetype/src/sfnt/pngshim.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * pngshim.h + * + * PNG Bitmap glyph support. + * + * Copyright (C) 2013-2023 by + * Google, Inc. + * Written by Stuart Gill and Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PNGSHIM_H_ +#define PNGSHIM_H_ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_PNG + + FT_LOCAL( FT_Error ) + Load_SBit_Png( FT_GlyphSlot slot, + FT_Int x_offset, + FT_Int y_offset, + FT_Int pix_bits, + TT_SBit_Metrics metrics, + FT_Memory memory, + FT_Byte* data, + FT_UInt png_len, + FT_Bool populate_map_and_metrics, + FT_Bool metrics_only ); + +#endif + +FT_END_HEADER + +#endif /* PNGSHIM_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/rules.mk b/vendor/freetype/src/sfnt/rules.mk new file mode 100644 index 0000000..4d2d7e8 --- /dev/null +++ b/vendor/freetype/src/sfnt/rules.mk @@ -0,0 +1,86 @@ +# +# FreeType 2 SFNT driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# SFNT driver directory +# +SFNT_DIR := $(SRC_DIR)/sfnt + + +# compilation flags for the driver +# +SFNT_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(SFNT_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# SFNT driver sources (i.e., C files) +# +SFNT_DRV_SRC := $(SFNT_DIR)/pngshim.c \ + $(SFNT_DIR)/sfdriver.c \ + $(SFNT_DIR)/sfobjs.c \ + $(SFNT_DIR)/sfwoff.c \ + $(SFNT_DIR)/sfwoff2.c \ + $(SFNT_DIR)/ttbdf.c \ + $(SFNT_DIR)/ttcmap.c \ + $(SFNT_DIR)/ttcolr.c \ + $(SFNT_DIR)/ttsvg.c \ + $(SFNT_DIR)/ttcpal.c \ + $(SFNT_DIR)/ttkern.c \ + $(SFNT_DIR)/ttload.c \ + $(SFNT_DIR)/ttmtx.c \ + $(SFNT_DIR)/ttpost.c \ + $(SFNT_DIR)/ttsbit.c \ + $(SFNT_DIR)/woff2tags.c + +# SFNT driver headers +# +SFNT_DRV_H := $(SFNT_DRV_SRC:%c=%h) \ + $(SFNT_DIR)/sferrors.h + + +# SFNT driver object(s) +# +# SFNT_DRV_OBJ_M is used during `multi' builds. +# SFNT_DRV_OBJ_S is used during `single' builds. +# +SFNT_DRV_OBJ_M := $(SFNT_DRV_SRC:$(SFNT_DIR)/%.c=$(OBJ_DIR)/%.$O) +SFNT_DRV_OBJ_S := $(OBJ_DIR)/sfnt.$O + +# SFNT driver source file for single build +# +SFNT_DRV_SRC_S := $(SFNT_DIR)/sfnt.c + + +# SFNT driver - single object +# +$(SFNT_DRV_OBJ_S): $(SFNT_DRV_SRC_S) $(SFNT_DRV_SRC) \ + $(FREETYPE_H) $(SFNT_DRV_H) + $(SFNT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(SFNT_DRV_SRC_S)) + + +# SFNT driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(SFNT_DIR)/%.c $(FREETYPE_H) $(SFNT_DRV_H) + $(SFNT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(SFNT_DRV_OBJ_S) +DRV_OBJS_M += $(SFNT_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/sfnt/sfdriver.c b/vendor/freetype/src/sfnt/sfdriver.c new file mode 100644 index 0000000..0925940 --- /dev/null +++ b/vendor/freetype/src/sfnt/sfdriver.c @@ -0,0 +1,1369 @@ +/**************************************************************************** + * + * sfdriver.c + * + * High-level SFNT driver interface (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "sfdriver.h" +#include "ttload.h" +#include "sfobjs.h" + +#include "sferrors.h" + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#include "ttsbit.h" +#endif + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#include "ttcolr.h" +#include "ttcpal.h" +#endif + +#ifdef FT_CONFIG_OPTION_SVG +#include "ttsvg.h" +#endif + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#include "ttpost.h" +#endif + +#ifdef TT_CONFIG_OPTION_BDF +#include "ttbdf.h" +#include +#endif + +#include "ttcmap.h" +#include "ttkern.h" +#include "ttmtx.h" + +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfdriver + + + /* + * SFNT TABLE SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + sfnt_load_table( FT_Face face, /* TT_Face */ + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + TT_Face ttface = (TT_Face)face; + + + return tt_face_load_any( ttface, tag, offset, buffer, length ); + } + + + FT_CALLBACK_DEF( void* ) + get_sfnt_table( FT_Face face, /* TT_Face */ + FT_Sfnt_Tag tag ) + { + TT_Face ttface = (TT_Face)face; + + void* table; + + + switch ( tag ) + { + case FT_SFNT_HEAD: + table = &ttface->header; + break; + + case FT_SFNT_HHEA: + table = &ttface->horizontal; + break; + + case FT_SFNT_VHEA: + table = ttface->vertical_info ? &ttface->vertical : NULL; + break; + + case FT_SFNT_OS2: + table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2; + break; + + case FT_SFNT_POST: + table = &ttface->postscript; + break; + + case FT_SFNT_MAXP: + table = &ttface->max_profile; + break; + + case FT_SFNT_PCLT: + table = ttface->pclt.Version ? &ttface->pclt : NULL; + break; + + default: + table = NULL; + } + + return table; + } + + + FT_CALLBACK_DEF( FT_Error ) + sfnt_table_info( FT_Face face, /* TT_Face */ + FT_UInt idx, + FT_ULong *tag, + FT_ULong *offset, + FT_ULong *length ) + { + TT_Face ttface = (TT_Face)face; + + + if ( !offset || !length ) + return FT_THROW( Invalid_Argument ); + + if ( !tag ) + *length = ttface->num_tables; + else + { + if ( idx >= ttface->num_tables ) + return FT_THROW( Table_Missing ); + + *tag = ttface->dir_tables[idx].Tag; + *offset = ttface->dir_tables[idx].Offset; + *length = ttface->dir_tables[idx].Length; + } + + return FT_Err_Ok; + } + + + FT_DEFINE_SERVICE_SFNT_TABLEREC( + sfnt_service_sfnt_table, + + sfnt_load_table, /* FT_SFNT_TableLoadFunc load_table */ + get_sfnt_table, /* FT_SFNT_TableGetFunc get_table */ + sfnt_table_info /* FT_SFNT_TableInfoFunc table_info */ + ) + + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + /* + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + sfnt_get_glyph_name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_String* gname; + FT_Error error; + + + error = tt_face_get_ps_name( (TT_Face)face, glyph_index, &gname ); + if ( !error ) + FT_STRCPYN( buffer, gname, buffer_max ); + + return error; + } + + + FT_CALLBACK_DEF( FT_UInt ) + sfnt_get_name_index( FT_Face face, + const FT_String* glyph_name ) + { + TT_Face ttface = (TT_Face)face; + + FT_UInt i, max_gid = FT_UINT_MAX; + + + if ( face->num_glyphs < 0 ) + return 0; + else if ( (FT_ULong)face->num_glyphs < FT_UINT_MAX ) + max_gid = (FT_UInt)face->num_glyphs; + else + FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08lx\n", + FT_UINT_MAX, face->num_glyphs )); + + for ( i = 0; i < max_gid; i++ ) + { + FT_String* gname; + FT_Error error = tt_face_get_ps_name( ttface, i, &gname ); + + + if ( error ) + continue; + + if ( !ft_strcmp( glyph_name, gname ) ) + return i; + } + + return 0; + } + + + FT_DEFINE_SERVICE_GLYPHDICTREC( + sfnt_service_glyph_dict, + + sfnt_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + sfnt_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ + ) + +#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + /* an array representing allowed ASCII characters in a PS string */ + static const unsigned char sfnt_ps_map[16] = + { + /* 4 0 C 8 */ + 0x00, 0x00, /* 0x00: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 */ + 0x00, 0x00, /* 0x10: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 */ + 0xDE, 0x7C, /* 0x20: 1 1 0 1 1 1 1 0 0 1 1 1 1 1 0 0 */ + 0xFF, 0xAF, /* 0x30: 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 */ + 0xFF, 0xFF, /* 0x40: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 */ + 0xFF, 0xD7, /* 0x50: 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 */ + 0xFF, 0xFF, /* 0x60: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 */ + 0xFF, 0x57 /* 0x70: 1 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 */ + }; + + + static int + sfnt_is_postscript( int c ) + { + unsigned int cc; + + + if ( c < 0 || c >= 0x80 ) + return 0; + + cc = (unsigned int)c; + + return sfnt_ps_map[cc >> 3] & ( 1 << ( cc & 0x07 ) ); + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /* Only ASCII letters and digits are taken for a variation font */ + /* instance's PostScript name. */ + /* */ + /* `ft_isalnum' is a macro, but we need a function here, thus */ + /* this definition. */ + static int + sfnt_is_alphanumeric( int c ) + { + return ft_isalnum( c ); + } + + + /* the implementation of MurmurHash3 is taken and adapted from */ + /* https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp */ + +#define ROTL32( x, r ) ( x << r ) | ( x >> ( 32 - r ) ) + + + static FT_UInt32 + fmix32( FT_UInt32 h ) + { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; + } + + + static void + murmur_hash_3_128( const void* key, + const unsigned int len, + FT_UInt32 seed, + void* out ) + { + const FT_Byte* data = (const FT_Byte*)key; + const int nblocks = (int)len / 16; + + FT_UInt32 h1 = seed; + FT_UInt32 h2 = seed; + FT_UInt32 h3 = seed; + FT_UInt32 h4 = seed; + + const FT_UInt32 c1 = 0x239b961b; + const FT_UInt32 c2 = 0xab0e9789; + const FT_UInt32 c3 = 0x38b34ae5; + const FT_UInt32 c4 = 0xa1e38b93; + + const FT_UInt32* blocks = (const FT_UInt32*)( data + nblocks * 16 ); + + int i; + + + for( i = -nblocks; i; i++ ) + { + FT_UInt32 k1 = blocks[i * 4 + 0]; + FT_UInt32 k2 = blocks[i * 4 + 1]; + FT_UInt32 k3 = blocks[i * 4 + 2]; + FT_UInt32 k4 = blocks[i * 4 + 3]; + + + k1 *= c1; + k1 = ROTL32( k1, 15 ); + k1 *= c2; + h1 ^= k1; + + h1 = ROTL32( h1, 19 ); + h1 += h2; + h1 = h1 * 5 + 0x561ccd1b; + + k2 *= c2; + k2 = ROTL32( k2, 16 ); + k2 *= c3; + h2 ^= k2; + + h2 = ROTL32( h2, 17 ); + h2 += h3; + h2 = h2 * 5 + 0x0bcaa747; + + k3 *= c3; + k3 = ROTL32( k3, 17 ); + k3 *= c4; + h3 ^= k3; + + h3 = ROTL32( h3, 15 ); + h3 += h4; + h3 = h3 * 5 + 0x96cd1c35; + + k4 *= c4; + k4 = ROTL32( k4, 18 ); + k4 *= c1; + h4 ^= k4; + + h4 = ROTL32( h4, 13 ); + h4 += h1; + h4 = h4 * 5 + 0x32ac3b17; + } + + { + const FT_Byte* tail = (const FT_Byte*)( data + nblocks * 16 ); + + FT_UInt32 k1 = 0; + FT_UInt32 k2 = 0; + FT_UInt32 k3 = 0; + FT_UInt32 k4 = 0; + + + switch ( len & 15 ) + { + case 15: + k4 ^= (FT_UInt32)tail[14] << 16; + FALL_THROUGH; + case 14: + k4 ^= (FT_UInt32)tail[13] << 8; + FALL_THROUGH; + case 13: + k4 ^= (FT_UInt32)tail[12]; + k4 *= c4; + k4 = ROTL32( k4, 18 ); + k4 *= c1; + h4 ^= k4; + FALL_THROUGH; + + case 12: + k3 ^= (FT_UInt32)tail[11] << 24; + FALL_THROUGH; + case 11: + k3 ^= (FT_UInt32)tail[10] << 16; + FALL_THROUGH; + case 10: + k3 ^= (FT_UInt32)tail[9] << 8; + FALL_THROUGH; + case 9: + k3 ^= (FT_UInt32)tail[8]; + k3 *= c3; + k3 = ROTL32( k3, 17 ); + k3 *= c4; + h3 ^= k3; + FALL_THROUGH; + + case 8: + k2 ^= (FT_UInt32)tail[7] << 24; + FALL_THROUGH; + case 7: + k2 ^= (FT_UInt32)tail[6] << 16; + FALL_THROUGH; + case 6: + k2 ^= (FT_UInt32)tail[5] << 8; + FALL_THROUGH; + case 5: + k2 ^= (FT_UInt32)tail[4]; + k2 *= c2; + k2 = ROTL32( k2, 16 ); + k2 *= c3; + h2 ^= k2; + FALL_THROUGH; + + case 4: + k1 ^= (FT_UInt32)tail[3] << 24; + FALL_THROUGH; + case 3: + k1 ^= (FT_UInt32)tail[2] << 16; + FALL_THROUGH; + case 2: + k1 ^= (FT_UInt32)tail[1] << 8; + FALL_THROUGH; + case 1: + k1 ^= (FT_UInt32)tail[0]; + k1 *= c1; + k1 = ROTL32( k1, 15 ); + k1 *= c2; + h1 ^= k1; + } + } + + h1 ^= len; + h2 ^= len; + h3 ^= len; + h4 ^= len; + + h1 += h2; + h1 += h3; + h1 += h4; + + h2 += h1; + h3 += h1; + h4 += h1; + + h1 = fmix32( h1 ); + h2 = fmix32( h2 ); + h3 = fmix32( h3 ); + h4 = fmix32( h4 ); + + h1 += h2; + h1 += h3; + h1 += h4; + + h2 += h1; + h3 += h1; + h4 += h1; + + ((FT_UInt32*)out)[0] = h1; + ((FT_UInt32*)out)[1] = h2; + ((FT_UInt32*)out)[2] = h3; + ((FT_UInt32*)out)[3] = h4; + } + + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + typedef int (*char_type_func)( int c ); + + + /* Handling of PID/EID 3/0 and 3/1 is the same. */ +#define IS_WIN( n ) ( (n)->platformID == 3 && \ + ( (n)->encodingID == 1 || (n)->encodingID == 0 ) ) + +#define IS_APPLE( n ) ( (n)->platformID == 1 && \ + (n)->encodingID == 0 ) + + static char* + get_win_string( FT_Memory memory, + FT_Stream stream, + TT_Name entry, + char_type_func char_type, + FT_Bool report_invalid_characters ) + { + FT_Error error; + + char* result = NULL; + FT_String* r; + FT_Char* p; + FT_UInt len; + + + if ( FT_QALLOC( result, entry->stringLength / 2 + 1 ) ) + return NULL; + + if ( FT_STREAM_SEEK( entry->stringOffset ) || + FT_FRAME_ENTER( entry->stringLength ) ) + goto get_win_string_error; + + r = (FT_String*)result; + p = (FT_Char*)stream->cursor; + + for ( len = entry->stringLength / 2; len > 0; len--, p += 2 ) + { + if ( p[0] == 0 && char_type( p[1] ) ) + *r++ = p[1]; + else + { + if ( report_invalid_characters ) + FT_TRACE0(( "get_win_string:" + " Character 0x%X invalid in PS name string\n", + ((unsigned)p[0])*256 + (unsigned)p[1] )); + continue; + } + } + *r = '\0'; + + FT_FRAME_EXIT(); + + if ( r != result ) + return result; + + get_win_string_error: + FT_FREE( result ); + + entry->stringLength = 0; + entry->stringOffset = 0; + FT_FREE( entry->string ); + + return NULL; + } + + + static char* + get_apple_string( FT_Memory memory, + FT_Stream stream, + TT_Name entry, + char_type_func char_type, + FT_Bool report_invalid_characters ) + { + FT_Error error; + + char* result = NULL; + FT_String* r; + FT_Char* p; + FT_UInt len; + + + if ( FT_QALLOC( result, entry->stringLength + 1 ) ) + return NULL; + + if ( FT_STREAM_SEEK( entry->stringOffset ) || + FT_FRAME_ENTER( entry->stringLength ) ) + goto get_apple_string_error; + + r = (FT_String*)result; + p = (FT_Char*)stream->cursor; + + for ( len = entry->stringLength; len > 0; len--, p++ ) + { + if ( char_type( *p ) ) + *r++ = *p; + else + { + if ( report_invalid_characters ) + FT_TRACE0(( "get_apple_string:" + " Character `%c' (0x%X) invalid in PS name string\n", + *p, *p )); + continue; + } + } + *r = '\0'; + + FT_FRAME_EXIT(); + + if ( r != result ) + return result; + + get_apple_string_error: + FT_FREE( result ); + + entry->stringOffset = 0; + entry->stringLength = 0; + FT_FREE( entry->string ); + + return NULL; + } + + + FT_CALLBACK_DEF( FT_Bool ) + sfnt_get_name_id( TT_Face face, + FT_UShort id, + FT_Int *win, + FT_Int *apple ) + { + FT_Int n; + + + *win = -1; + *apple = -1; + + for ( n = 0; n < face->num_names; n++ ) + { + TT_Name name = face->name_table.names + n; + + + if ( name->nameID == id && name->stringLength > 0 ) + { + if ( IS_WIN( name ) && ( name->languageID == 0x409 || *win == -1 ) ) + *win = n; + + if ( IS_APPLE( name ) && ( name->languageID == 0 || *apple == -1 ) ) + *apple = n; + } + } + + return ( *win >= 0 ) || ( *apple >= 0 ); + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /* + The maximum length of an axis value descriptor. + + We need 65536 different values for the decimal fraction; this fits + nicely into five decimal places. Consequently, it consists of + + . the minus sign if the number is negative, + . up to five characters for the digits before the decimal point, + . the decimal point if there is a fractional part, and + . up to five characters for the digits after the decimal point. + + We also need one byte for the leading `_' character and up to four + bytes for the axis tag. + */ +#define MAX_VALUE_DESCRIPTOR_LEN ( 1 + 5 + 1 + 5 + 1 + 4 ) + + + /* the maximum length of PostScript font names */ +#define MAX_PS_NAME_LEN 127 + + + /* + * Find the shortest decimal representation of a 16.16 fixed-point + * number. The function fills `buf' with the result, returning a pointer + * to the position after the representation's last byte. + */ + + static char* + fixed2float( FT_Int fixed, + char* buf ) + { + char* p; + char* q; + char tmp[5]; + + FT_Int int_part; + FT_Int frac_part; + + FT_Int i; + + + p = buf; + + if ( fixed == 0 ) + { + *p++ = '0'; + return p; + } + + if ( fixed < 0 ) + { + *p++ = '-'; + fixed = NEG_INT( fixed ); + } + + int_part = ( fixed >> 16 ) & 0xFFFF; + frac_part = fixed & 0xFFFF; + + /* get digits of integer part (in reverse order) */ + q = tmp; + while ( int_part > 0 ) + { + *q++ = '0' + int_part % 10; + int_part /= 10; + } + + /* copy digits in correct order to buffer */ + while ( q > tmp ) + *p++ = *--q; + + if ( !frac_part ) + return p; + + /* save position of point */ + q = p; + *p++ = '.'; + + /* apply rounding */ + frac_part = frac_part * 10 + 5; + + /* get digits of fractional part */ + for ( i = 0; i < 5; i++ ) + { + *p++ = '0' + (char)( frac_part / 0x10000L ); + + frac_part %= 0x10000L; + if ( !frac_part ) + break; + + frac_part *= 10; + } + + /* + If the remainder stored in `frac_part' (after the last FOR loop) is + smaller than 34480*10, the resulting decimal value minus 0.00001 is + an equivalent representation of `fixed'. + + The above FOR loop always finds the larger of the two values; I + verified this by iterating over all possible fixed-point numbers. + + If the remainder is 17232*10, both values are equally good, and we + take the next even number (following IEEE 754's `round to nearest, + ties to even' rounding rule). + + If the remainder is smaller than 17232*10, the lower of the two + numbers is nearer to the exact result (values 17232 and 34480 were + also found by testing all possible fixed-point values). + + We use this to find a shorter decimal representation. If not ending + with digit zero, we take the representation with less error. + */ + p--; + if ( p - q == 5 ) /* five digits? */ + { + /* take the representation that has zero as the last digit */ + if ( frac_part < 34480 * 10 && + *p == '1' ) + *p = '0'; + + /* otherwise use the one with less error */ + else if ( frac_part == 17232 * 10 && + *p & 1 ) + *p -= 1; + + else if ( frac_part < 17232 * 10 && + *p != '0' ) + *p -= 1; + } + + /* remove trailing zeros */ + while ( *p == '0' ) + *p-- = '\0'; + + return p + 1; + } + + + static const char hexdigits[16] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + + static const char* + sfnt_get_var_ps_name( TT_Face face ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + FT_UInt num_coords; + FT_Fixed* coords; + FT_MM_Var* mm_var; + + FT_Int found, win, apple; + FT_UInt i, j; + + char* result = NULL; + char* p; + + + if ( !face->var_postscript_prefix ) + { + FT_UInt len; + + + /* check whether we have a Variations PostScript Name Prefix */ + found = sfnt_get_name_id( face, + TT_NAME_ID_VARIATIONS_PREFIX, + &win, + &apple ); + if ( !found ) + { + /* otherwise use the typographic family name */ + found = sfnt_get_name_id( face, + TT_NAME_ID_TYPOGRAPHIC_FAMILY, + &win, + &apple ); + } + + if ( !found ) + { + /* according to the 'name' documentation in the OpenType */ + /* specification the font family name is to be used if the */ + /* typographic family name is missing, so let's do that */ + found = sfnt_get_name_id( face, + TT_NAME_ID_FONT_FAMILY, + &win, + &apple ); + } + + if ( !found ) + { + FT_TRACE0(( "sfnt_get_var_ps_name:" + " Can't construct PS name prefix for font instances\n" )); + return NULL; + } + + /* prefer Windows entries over Apple */ + if ( win != -1 ) + result = get_win_string( face->root.memory, + face->name_table.stream, + face->name_table.names + win, + sfnt_is_alphanumeric, + 0 ); + if ( !result && apple != -1 ) + result = get_apple_string( face->root.memory, + face->name_table.stream, + face->name_table.names + apple, + sfnt_is_alphanumeric, + 0 ); + + if ( !result ) + { + FT_TRACE0(( "sfnt_get_var_ps_name:" + " No valid PS name prefix for font instances found\n" )); + /* XXX It probably makes sense to never let this fail */ + /* since an arbitrary prefix should work, too. */ + /* On the other hand, it is very unlikely that */ + /* we ever reach this code at all. */ + return NULL; + } + + len = ft_strlen( result ); + + /* sanitize if necessary; we reserve space for 36 bytes (a 128bit */ + /* checksum as a hex number, preceded by `-' and followed by three */ + /* ASCII dots, to be used if the constructed PS name would be too */ + /* long); this is also sufficient for a single instance */ + if ( len > MAX_PS_NAME_LEN - ( 1 + 32 + 3 ) ) + { + len = MAX_PS_NAME_LEN - ( 1 + 32 + 3 ); + result[len] = '\0'; + + FT_TRACE0(( "sfnt_get_var_ps_name:" + " Shortening variation PS name prefix\n" )); + FT_TRACE0(( " " + " to %d characters\n", len )); + } + + face->var_postscript_prefix = result; + face->var_postscript_prefix_len = len; + } + + mm->get_var_blend( FT_FACE( face ), + &num_coords, + &coords, + NULL, + &mm_var ); + + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) && + !FT_IS_VARIATION( FT_FACE( face ) ) ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_Long instance = ( ( face->root.face_index & 0x7FFF0000L ) >> 16 ) - 1; + FT_UInt psid = mm_var->namedstyle[instance].psid; + + char* ps_name = NULL; + + + /* try first to load the name string with index `postScriptNameID' */ + if ( psid == 6 || + ( psid > 255 && psid < 32768 ) ) + (void)sfnt->get_name( face, (FT_UShort)psid, &ps_name ); + + if ( ps_name ) + { + result = ps_name; + p = result + ft_strlen( result ) + 1; + + goto check_length; + } + else + { + /* otherwise construct a name using `subfamilyNameID' */ + FT_UInt strid = mm_var->namedstyle[instance].strid; + + char* subfamily_name; + char* s; + + + (void)sfnt->get_name( face, (FT_UShort)strid, &subfamily_name ); + + if ( !subfamily_name ) + { + FT_TRACE1(( "sfnt_get_var_ps_name:" + " can't construct named instance PS name;\n" )); + FT_TRACE1(( " " + " trying to construct normal instance PS name\n" )); + goto construct_instance_name; + } + + /* after the prefix we have character `-' followed by the */ + /* subfamily name (using only characters a-z, A-Z, and 0-9) */ + if ( FT_QALLOC( result, face->var_postscript_prefix_len + + 1 + ft_strlen( subfamily_name ) + 1 ) ) + return NULL; + + ft_strcpy( result, face->var_postscript_prefix ); + + p = result + face->var_postscript_prefix_len; + *p++ = '-'; + + s = subfamily_name; + while ( *s ) + { + if ( ft_isalnum( *s ) ) + *p++ = *s; + s++; + } + *p++ = '\0'; + + FT_FREE( subfamily_name ); + } + } + else + { + FT_Var_Axis* axis; + + + construct_instance_name: + axis = mm_var->axis; + + if ( FT_QALLOC( result, + face->var_postscript_prefix_len + + num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) + return NULL; + + p = result; + + ft_strcpy( p, face->var_postscript_prefix ); + p += face->var_postscript_prefix_len; + + for ( i = 0; i < num_coords; i++, coords++, axis++ ) + { + char t; + + + /* omit axis value descriptor if it is identical */ + /* to the default axis value */ + if ( *coords == axis->def ) + continue; + + *p++ = '_'; + p = fixed2float( *coords, p ); + + t = (char)( axis->tag >> 24 ); + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + t = (char)( axis->tag >> 16 ); + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + t = (char)( axis->tag >> 8 ); + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + t = (char)axis->tag; + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + } + *p++ = '\0'; + } + + check_length: + if ( p - result > MAX_PS_NAME_LEN ) + { + /* the PS name is too long; replace the part after the prefix with */ + /* a checksum; we use MurmurHash 3 with a hash length of 128 bit */ + + FT_UInt32 seed = 123456789; + + FT_UInt32 hash[4]; + FT_UInt32* h; + + + murmur_hash_3_128( result, p - result, seed, hash ); + + p = result + face->var_postscript_prefix_len; + *p++ = '-'; + + /* we convert the hash value to hex digits from back to front */ + p += 32 + 3; + h = hash + 3; + + *p-- = '\0'; + *p-- = '.'; + *p-- = '.'; + *p-- = '.'; + + for ( i = 0; i < 4; i++, h-- ) + { + FT_UInt32 v = *h; + + + for ( j = 0; j < 8; j++ ) + { + *p-- = hexdigits[v & 0xF]; + v >>= 4; + } + } + } + + return result; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + FT_CALLBACK_DEF( const char* ) + sfnt_get_ps_name( FT_Face face ) /* TT_Face */ + { + TT_Face ttface = (TT_Face)face; + + FT_Int found, win, apple; + const char* result = NULL; + + + if ( ttface->postscript_name ) + return ttface->postscript_name; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( ttface->blend && + ( FT_IS_NAMED_INSTANCE( face ) || + FT_IS_VARIATION( face ) ) ) + { + ttface->postscript_name = sfnt_get_var_ps_name( ttface ); + return ttface->postscript_name; + } +#endif + + /* scan the name table to see whether we have a Postscript name here, */ + /* either in Macintosh or Windows platform encodings */ + found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple ); + if ( !found ) + return NULL; + + /* prefer Windows entries over Apple */ + if ( win != -1 ) + result = get_win_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + win, + sfnt_is_postscript, + 1 ); + if ( !result && apple != -1 ) + result = get_apple_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + apple, + sfnt_is_postscript, + 1 ); + + ttface->postscript_name = result; + + return result; + } + + + FT_DEFINE_SERVICE_PSFONTNAMEREC( + sfnt_service_ps_name, + + sfnt_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */ + ) + + + /* + * TT CMAP INFO + */ + FT_DEFINE_SERVICE_TTCMAPSREC( + tt_service_get_cmap_info, + + tt_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */ + ) + + +#ifdef TT_CONFIG_OPTION_BDF + + static FT_Error + sfnt_get_charset_id( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + BDF_PropertyRec encoding, registry; + FT_Error error; + + + /* XXX: I don't know whether this is correct, since + * tt_face_find_bdf_prop only returns something correct if we have + * previously selected a size that is listed in the BDF table. + * Should we change the BDF table format to include single offsets + * for `CHARSET_REGISTRY' and `CHARSET_ENCODING'? + */ + error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", ®istry ); + if ( !error ) + { + error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding ); + if ( !error ) + { + if ( registry.type == BDF_PROPERTY_TYPE_ATOM && + encoding.type == BDF_PROPERTY_TYPE_ATOM ) + { + *acharset_encoding = encoding.u.atom; + *acharset_registry = registry.u.atom; + } + else + error = FT_THROW( Invalid_Argument ); + } + } + + return error; + } + + + FT_DEFINE_SERVICE_BDFRec( + sfnt_service_bdf, + + sfnt_get_charset_id, /* FT_BDF_GetCharsetIdFunc get_charset_id */ + tt_face_find_bdf_prop /* FT_BDF_GetPropertyFunc get_property */ + ) + + +#endif /* TT_CONFIG_OPTION_BDF */ + + + /* + * SERVICE LIST + */ + +#if defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES && defined TT_CONFIG_OPTION_BDF + FT_DEFINE_SERVICEDESCREC5( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &sfnt_service_glyph_dict, + FT_SERVICE_ID_BDF, &sfnt_service_bdf, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#elif defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_DEFINE_SERVICEDESCREC4( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &sfnt_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#elif defined TT_CONFIG_OPTION_BDF + FT_DEFINE_SERVICEDESCREC4( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_BDF, &sfnt_service_bdf, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#else + FT_DEFINE_SERVICEDESCREC3( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#endif + + + FT_CALLBACK_DEF( FT_Module_Interface ) + sfnt_get_interface( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( sfnt_services, module_interface ); + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#define PUT_EMBEDDED_BITMAPS( a ) a +#else +#define PUT_EMBEDDED_BITMAPS( a ) NULL +#endif + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define PUT_COLOR_LAYERS( a ) a +#else +#define PUT_COLOR_LAYERS( a ) NULL +#endif + +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_SUPPORT( a ) a +#else +#define PUT_SVG_SUPPORT( a ) NULL +#endif + +#define PUT_COLOR_LAYERS_V1( a ) PUT_COLOR_LAYERS( a ) + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#define PUT_PS_NAMES( a ) a +#else +#define PUT_PS_NAMES( a ) NULL +#endif + + FT_DEFINE_SFNT_INTERFACE( + sfnt_interface, + + tt_face_goto_table, /* TT_Loader_GotoTableFunc goto_table */ + + sfnt_init_face, /* TT_Init_Face_Func init_face */ + sfnt_load_face, /* TT_Load_Face_Func load_face */ + sfnt_done_face, /* TT_Done_Face_Func done_face */ + sfnt_get_interface, /* FT_Module_Requester get_interface */ + + tt_face_load_any, /* TT_Load_Any_Func load_any */ + + tt_face_load_head, /* TT_Load_Table_Func load_head */ + tt_face_load_hhea, /* TT_Load_Metrics_Func load_hhea */ + tt_face_load_cmap, /* TT_Load_Table_Func load_cmap */ + tt_face_load_maxp, /* TT_Load_Table_Func load_maxp */ + tt_face_load_os2, /* TT_Load_Table_Func load_os2 */ + tt_face_load_post, /* TT_Load_Table_Func load_post */ + + tt_face_load_name, /* TT_Load_Table_Func load_name */ + tt_face_free_name, /* TT_Free_Table_Func free_name */ + + tt_face_load_kern, /* TT_Load_Table_Func load_kern */ + tt_face_load_gasp, /* TT_Load_Table_Func load_gasp */ + tt_face_load_pclt, /* TT_Load_Table_Func load_init */ + + /* see `ttload.h' */ + PUT_EMBEDDED_BITMAPS( tt_face_load_bhed ), + /* TT_Load_Table_Func load_bhed */ + PUT_EMBEDDED_BITMAPS( tt_face_load_sbit_image ), + /* TT_Load_SBit_Image_Func load_sbit_image */ + + /* see `ttpost.h' */ + PUT_PS_NAMES( tt_face_get_ps_name ), + /* TT_Get_PS_Name_Func get_psname */ + PUT_PS_NAMES( tt_face_free_ps_names ), + /* TT_Free_Table_Func free_psnames */ + + /* since version 2.1.8 */ + tt_face_get_kerning, /* TT_Face_GetKerningFunc get_kerning */ + + /* since version 2.2 */ + tt_face_load_font_dir, /* TT_Load_Table_Func load_font_dir */ + tt_face_load_hmtx, /* TT_Load_Metrics_Func load_hmtx */ + + /* see `ttsbit.h' and `sfnt.h' */ + PUT_EMBEDDED_BITMAPS( tt_face_load_sbit ), + /* TT_Load_Table_Func load_eblc */ + PUT_EMBEDDED_BITMAPS( tt_face_free_sbit ), + /* TT_Free_Table_Func free_eblc */ + + PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), + /* TT_Set_SBit_Strike_Func set_sbit_strike */ + PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), + /* TT_Load_Strike_Metrics_Func load_strike_metrics */ + + PUT_COLOR_LAYERS( tt_face_load_cpal ), + /* TT_Load_Table_Func load_cpal */ + PUT_COLOR_LAYERS( tt_face_load_colr ), + /* TT_Load_Table_Func load_colr */ + PUT_COLOR_LAYERS( tt_face_free_cpal ), + /* TT_Free_Table_Func free_cpal */ + PUT_COLOR_LAYERS( tt_face_free_colr ), + /* TT_Free_Table_Func free_colr */ + PUT_COLOR_LAYERS( tt_face_palette_set ), + /* TT_Set_Palette_Func set_palette */ + PUT_COLOR_LAYERS( tt_face_get_colr_layer ), + /* TT_Get_Colr_Layer_Func get_colr_layer */ + + PUT_COLOR_LAYERS_V1( tt_face_get_colr_glyph_paint ), + /* TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_color_glyph_clipbox ), + /* TT_Get_Color_Glyph_ClipBox_Func get_clipbox */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint_layers ), + /* TT_Get_Paint_Layers_Func get_paint_layers */ + PUT_COLOR_LAYERS_V1( tt_face_get_colorline_stops ), + /* TT_Get_Paint get_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint ), + /* TT_Get_Colorline_Stops_Func get_colorline_stops */ + + PUT_COLOR_LAYERS( tt_face_colr_blend_layer ), + /* TT_Blend_Colr_Func colr_blend */ + + tt_face_get_metrics, /* TT_Get_Metrics_Func get_metrics */ + + tt_face_get_name, /* TT_Get_Name_Func get_name */ + sfnt_get_name_id, /* TT_Get_Name_ID_Func get_name_id */ + + PUT_SVG_SUPPORT( tt_face_load_svg ), + /* TT_Load_Table_Func load_svg */ + PUT_SVG_SUPPORT( tt_face_free_svg ), + /* TT_Free_Table_Func free_svg */ + PUT_SVG_SUPPORT( tt_face_load_svg_doc ) + /* TT_Load_Svg_Doc_Func load_svg_doc */ + ) + + + FT_DEFINE_MODULE( + sfnt_module_class, + + 0, /* not a font driver or renderer */ + sizeof ( FT_ModuleRec ), + + "sfnt", /* driver name */ + 0x10000L, /* driver version 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or higher */ + + (const void*)&sfnt_interface, /* module specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + sfnt_get_interface /* FT_Module_Requester get_interface */ + ) + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfdriver.h b/vendor/freetype/src/sfnt/sfdriver.h new file mode 100644 index 0000000..2445958 --- /dev/null +++ b/vendor/freetype/src/sfnt/sfdriver.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * sfdriver.h + * + * High-level SFNT driver interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFDRIVER_H_ +#define SFDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_MODULE( sfnt_module_class ) + +FT_END_HEADER + +#endif /* SFDRIVER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sferrors.h b/vendor/freetype/src/sfnt/sferrors.h new file mode 100644 index 0000000..e7a8eb0 --- /dev/null +++ b/vendor/freetype/src/sfnt/sferrors.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * sferrors.h + * + * SFNT error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the SFNT error enumeration constants. + * + */ + +#ifndef SFERRORS_H_ +#define SFERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX SFNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_SFNT + +#include + +#endif /* SFERRORS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfnt.c b/vendor/freetype/src/sfnt/sfnt.c new file mode 100644 index 0000000..8e4f08a --- /dev/null +++ b/vendor/freetype/src/sfnt/sfnt.c @@ -0,0 +1,40 @@ +/**************************************************************************** + * + * sfnt.c + * + * Single object library component. + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pngshim.c" +#include "sfdriver.c" +#include "sfobjs.c" +#include "sfwoff.c" +#include "sfwoff2.c" +#include "ttbdf.c" +#include "ttcmap.c" +#include "ttcolr.c" +#include "ttcpal.c" +#include "ttsvg.c" + +#include "ttkern.c" +#include "ttload.c" +#include "ttmtx.c" +#include "ttpost.c" +#include "ttsbit.c" +#include "woff2tags.c" + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfobjs.c b/vendor/freetype/src/sfnt/sfobjs.c new file mode 100644 index 0000000..f5d66ef --- /dev/null +++ b/vendor/freetype/src/sfnt/sfobjs.c @@ -0,0 +1,1535 @@ +/**************************************************************************** + * + * sfobjs.c + * + * SFNT object management (base). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "sfobjs.h" +#include "ttload.h" +#include "ttcmap.h" +#include "ttkern.h" +#include "sfwoff.h" +#include "sfwoff2.h" +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include "sferrors.h" + +#ifdef TT_CONFIG_OPTION_BDF +#include "ttbdf.h" +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfobjs + + + + /* convert a UTF-16 name entry to ASCII */ + static FT_String* + tt_name_ascii_from_utf16( TT_Name entry, + FT_Memory memory ) + { + FT_String* string = NULL; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + + + len = (FT_UInt)entry->stringLength / 2; + + if ( FT_QNEW_ARRAY( string, len + 1 ) ) + return NULL; + + for ( n = 0; n < len; n++ ) + { + code = FT_NEXT_USHORT( read ); + + if ( code == 0 ) + break; + + if ( code < 32 || code > 127 ) + code = '?'; + + string[n] = (char)code; + } + + string[n] = 0; + + return string; + } + + + /* convert an Apple Roman or symbol name entry to ASCII */ + static FT_String* + tt_name_ascii_from_other( TT_Name entry, + FT_Memory memory ) + { + FT_String* string = NULL; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + + + len = (FT_UInt)entry->stringLength; + + if ( FT_QNEW_ARRAY( string, len + 1 ) ) + return NULL; + + for ( n = 0; n < len; n++ ) + { + code = *read++; + + if ( code == 0 ) + break; + + if ( code < 32 || code > 127 ) + code = '?'; + + string[n] = (char)code; + } + + string[n] = 0; + + return string; + } + + + typedef FT_String* (*TT_Name_ConvertFunc)( TT_Name entry, + FT_Memory memory ); + + + /* documentation is in sfnt.h */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_get_name( TT_Face face, + FT_UShort nameid, + FT_String** name ) + { + FT_Memory memory = face->root.memory; + FT_Error error = FT_Err_Ok; + FT_String* result = NULL; + FT_UShort n; + TT_Name rec; + + FT_Int found_apple = -1; + FT_Int found_apple_roman = -1; + FT_Int found_apple_english = -1; + FT_Int found_win = -1; + FT_Int found_unicode = -1; + + FT_Bool is_english = 0; + + TT_Name_ConvertFunc convert; + + + FT_ASSERT( name ); + + rec = face->name_table.names; + for ( n = 0; n < face->num_names; n++, rec++ ) + { + /* According to the OpenType 1.3 specification, only Microsoft or */ + /* Apple platform IDs might be used in the `name' table. The */ + /* `Unicode' platform is reserved for the `cmap' table, and the */ + /* `ISO' one is deprecated. */ + /* */ + /* However, the Apple TrueType specification doesn't say the same */ + /* thing and goes to suggest that all Unicode `name' table entries */ + /* should be coded in UTF-16 (in big-endian format I suppose). */ + /* */ + if ( rec->nameID == nameid && rec->stringLength > 0 ) + { + switch ( rec->platformID ) + { + case TT_PLATFORM_APPLE_UNICODE: + case TT_PLATFORM_ISO: + /* there is `languageID' to check there. We should use this */ + /* field only as a last solution when nothing else is */ + /* available. */ + /* */ + found_unicode = n; + break; + + case TT_PLATFORM_MACINTOSH: + /* This is a bit special because some fonts will use either */ + /* an English language id, or a Roman encoding id, to indicate */ + /* the English version of its font name. */ + /* */ + if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) + found_apple_english = n; + else if ( rec->encodingID == TT_MAC_ID_ROMAN ) + found_apple_roman = n; + break; + + case TT_PLATFORM_MICROSOFT: + /* we only take a non-English name when there is nothing */ + /* else available in the font */ + /* */ + if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) + { + switch ( rec->encodingID ) + { + case TT_MS_ID_SYMBOL_CS: + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_UCS_4: + is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); + found_win = n; + break; + + default: + ; + } + } + break; + + default: + ; + } + } + } + + found_apple = found_apple_roman; + if ( found_apple_english >= 0 ) + found_apple = found_apple_english; + + /* some fonts contain invalid Unicode or Macintosh formatted entries; */ + /* we will thus favor names encoded in Windows formats if available */ + /* (provided it is an English name) */ + /* */ + convert = NULL; + if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) + { + rec = face->name_table.names + found_win; + switch ( rec->encodingID ) + { + /* all Unicode strings are encoded using UTF-16BE */ + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_SYMBOL_CS: + convert = tt_name_ascii_from_utf16; + break; + + case TT_MS_ID_UCS_4: + /* Apparently, if this value is found in a name table entry, it is */ + /* documented as `full Unicode repertoire'. Experience with the */ + /* MsGothic font shipped with Windows Vista shows that this really */ + /* means UTF-16 encoded names (UCS-4 values are only used within */ + /* charmaps). */ + convert = tt_name_ascii_from_utf16; + break; + + default: + ; + } + } + else if ( found_apple >= 0 ) + { + rec = face->name_table.names + found_apple; + convert = tt_name_ascii_from_other; + } + else if ( found_unicode >= 0 ) + { + rec = face->name_table.names + found_unicode; + convert = tt_name_ascii_from_utf16; + } + + if ( rec && convert ) + { + if ( !rec->string ) + { + FT_Stream stream = face->name_table.stream; + + + if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || + FT_STREAM_SEEK( rec->stringOffset ) || + FT_STREAM_READ( rec->string, rec->stringLength ) ) + { + FT_FREE( rec->string ); + rec->stringLength = 0; + result = NULL; + goto Exit; + } + } + + result = convert( rec, memory ); + } + + Exit: + *name = result; + return error; + } + + + static FT_Encoding + sfnt_find_encoding( int platform_id, + int encoding_id ) + { + typedef struct TEncoding_ + { + int platform_id; + int encoding_id; + FT_Encoding encoding; + + } TEncoding; + + static + const TEncoding tt_encodings[] = + { + { TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE }, + + { TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE }, + + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN }, + + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_SJIS }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_PRC, FT_ENCODING_PRC }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_BIG5 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_WANSUNG }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_JOHAB } + }; + + const TEncoding *cur, *limit; + + + cur = tt_encodings; + limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); + + for ( ; cur < limit; cur++ ) + { + if ( cur->platform_id == platform_id ) + { + if ( cur->encoding_id == encoding_id || + cur->encoding_id == -1 ) + return cur->encoding; + } + } + + return FT_ENCODING_NONE; + } + + + /* Fill in face->ttc_header. If the font is not a TTC, it is */ + /* synthesized into a TTC with one offset table. */ + static FT_Error + sfnt_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_instance_index, + FT_Long* woff2_num_faces ) + { + FT_Memory memory = stream->memory; + FT_Error error; + FT_ULong tag, offset; + + static const FT_Frame_Field ttc_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TTC_HeaderRec + + FT_FRAME_START( 8 ), + FT_FRAME_LONG( version ), + FT_FRAME_LONG( count ), /* this is ULong in the specs */ + FT_FRAME_END + }; + +#ifndef FT_CONFIG_OPTION_USE_BROTLI + FT_UNUSED( face_instance_index ); + FT_UNUSED( woff2_num_faces ); +#endif + + + face->ttc_header.tag = 0; + face->ttc_header.version = 0; + face->ttc_header.count = 0; + +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_BROTLI ) + retry: +#endif + + offset = FT_STREAM_POS(); + + if ( FT_READ_ULONG( tag ) ) + return error; + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + if ( tag == TTAG_wOFF ) + { + FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" )); + + if ( FT_STREAM_SEEK( offset ) ) + return error; + + error = woff_open_font( stream, face ); + if ( error ) + return error; + + /* Swap out stream and retry! */ + stream = face->root.stream; + goto retry; + } +#endif + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + if ( tag == TTAG_wOF2 ) + { + FT_TRACE2(( "sfnt_open_font: file is a WOFF2; synthesizing SFNT\n" )); + + if ( FT_STREAM_SEEK( offset ) ) + return error; + + error = woff2_open_font( stream, + face, + face_instance_index, + woff2_num_faces ); + if ( error ) + return error; + + /* Swap out stream and retry! */ + stream = face->root.stream; + goto retry; + } +#endif + + if ( tag != 0x00010000UL && + tag != TTAG_ttcf && + tag != TTAG_OTTO && + tag != TTAG_true && + tag != TTAG_typ1 && + tag != TTAG_0xA5kbd && + tag != TTAG_0xA5lst && + tag != 0x00020000UL ) + { + FT_TRACE2(( " not a font using the SFNT container format\n" )); + return FT_THROW( Unknown_File_Format ); + } + + face->ttc_header.tag = TTAG_ttcf; + + if ( tag == TTAG_ttcf ) + { + FT_Int n; + + + FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); + + if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) + return error; + + FT_TRACE3(( " with %ld subfonts\n", + face->ttc_header.count )); + + if ( face->ttc_header.count == 0 ) + return FT_THROW( Invalid_Table ); + + /* a rough size estimate: let's conservatively assume that there */ + /* is just a single table info in each subfont header (12 + 16*1 = */ + /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ + /* size of the TTC header plus `28*count' bytes for all subfont */ + /* headers */ + if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) + return FT_THROW( Array_Too_Large ); + + /* now read the offsets of each font in the file */ + if ( FT_QNEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + return error; + + if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) + return error; + + for ( n = 0; n < face->ttc_header.count; n++ ) + face->ttc_header.offsets[n] = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + } + else + { + FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); + + face->ttc_header.version = 1 << 16; + face->ttc_header.count = 1; + + if ( FT_QNEW( face->ttc_header.offsets ) ) + return error; + + face->ttc_header.offsets[0] = offset; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library = face->root.driver->root.library; + SFNT_Service sfnt; + FT_Int face_index; + FT_Long woff2_num_faces = 0; + + + /* for now, parameters are unused */ + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + sfnt = (SFNT_Service)face->sfnt; + if ( !sfnt ) + { + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "sfnt_init_face: cannot access `sfnt' module\n" )); + return FT_THROW( Missing_Module ); + } + + face->sfnt = sfnt; + face->goto_table = sfnt->goto_table; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( !face->mm ) + { + /* we want the MM interface from the `truetype' module only */ + FT_Module tt_module = FT_Get_Module( library, "truetype" ); + + + face->mm = ft_module_get_service( tt_module, + FT_SERVICE_ID_MULTI_MASTERS, + 0 ); + } + + if ( !face->tt_var ) + { + /* we want the metrics variations interface */ + /* from the `truetype' module only */ + FT_Module tt_module = FT_Get_Module( library, "truetype" ); + + + face->tt_var = ft_module_get_service( tt_module, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); + } + + if ( !face->face_var ) + face->face_var = ft_module_get_service( + &face->root.driver->root, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); +#endif + + FT_TRACE2(( "SFNT driver\n" )); + + error = sfnt_open_font( stream, + face, + &face_instance_index, + &woff2_num_faces ); + if ( error ) + return error; + + /* Stream may have changed in sfnt_open_font. */ + stream = face->root.stream; + + FT_TRACE2(( "sfnt_init_face: %p (index %d)\n", + (void *)face, + face_instance_index )); + + face_index = FT_ABS( face_instance_index ) & 0xFFFF; + + /* value -(N+1) requests information on index N */ + if ( face_instance_index < 0 && face_index > 0 ) + face_index--; + + if ( face_index >= face->ttc_header.count ) + { + if ( face_instance_index >= 0 ) + return FT_THROW( Invalid_Argument ); + else + face_index = 0; + } + + if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ) + return error; + + /* check whether we have a valid TrueType file */ + error = sfnt->load_font_dir( face, stream ); + if ( error ) + return error; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Memory memory = face->root.memory; + + FT_ULong fvar_len; + + FT_ULong version; + FT_ULong offset; + + FT_UShort num_axes; + FT_UShort axis_size; + FT_UShort num_instances; + FT_UShort instance_size; + + FT_Int instance_index; + + FT_Byte* default_values = NULL; + FT_Byte* instance_values = NULL; + + + instance_index = FT_ABS( face_instance_index ) >> 16; + + /* test whether current face is a GX font with named instances */ + if ( face->goto_table( face, TTAG_fvar, stream, &fvar_len ) || + fvar_len < 20 || + FT_READ_ULONG( version ) || + FT_READ_USHORT( offset ) || + FT_STREAM_SKIP( 2 ) /* reserved */ || + FT_READ_USHORT( num_axes ) || + FT_READ_USHORT( axis_size ) || + FT_READ_USHORT( num_instances ) || + FT_READ_USHORT( instance_size ) ) + { + version = 0; + offset = 0; + num_axes = 0; + axis_size = 0; + num_instances = 0; + instance_size = 0; + } + + /* check that the data is bound by the table length */ + if ( version != 0x00010000UL || + axis_size != 20 || + num_axes == 0 || + /* `num_axes' limit implied by 16-bit `instance_size' */ + num_axes > 0x3FFE || + !( instance_size == 4 + 4 * num_axes || + instance_size == 6 + 4 * num_axes ) || + /* `num_instances' limit implied by limited range of name IDs */ + num_instances > 0x7EFF || + offset + + axis_size * num_axes + + instance_size * num_instances > fvar_len ) + num_instances = 0; + else + face->variation_support |= TT_FACE_FLAG_VAR_FVAR; + + /* + * As documented in the OpenType specification, an entry for the + * default instance may be omitted in the named instance table. In + * particular this means that even if there is no named instance + * table in the font we actually do have a named instance, namely the + * default instance. + * + * For consistency, we always want the default instance in our list + * of named instances. If it is missing, we try to synthesize it + * later on. Here, we have to adjust `num_instances' accordingly. + */ + + if ( ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) && + !( FT_QALLOC( default_values, num_axes * 4 ) || + FT_QALLOC( instance_values, num_axes * 4 ) ) ) + { + /* the current stream position is 16 bytes after the table start */ + FT_ULong array_start = FT_STREAM_POS() - 16 + offset; + FT_ULong default_value_offset, instance_offset; + + FT_Byte* p; + FT_UInt i; + + + default_value_offset = array_start + 8; + p = default_values; + + for ( i = 0; i < num_axes; i++ ) + { + (void)FT_STREAM_READ_AT( default_value_offset, p, 4 ); + + default_value_offset += axis_size; + p += 4; + } + + instance_offset = array_start + axis_size * num_axes + 4; + + for ( i = 0; i < num_instances; i++ ) + { + (void)FT_STREAM_READ_AT( instance_offset, + instance_values, + num_axes * 4 ); + + if ( !ft_memcmp( default_values, instance_values, num_axes * 4 ) ) + break; + + instance_offset += instance_size; + } + + /* named instance indices start with value 1 */ + face->var_default_named_instance = i + 1; + + if ( i == num_instances ) + { + /* no default instance in named instance table; */ + /* we thus have to synthesize it */ + num_instances++; + } + } + + FT_FREE( default_values ); + FT_FREE( instance_values ); + + /* we don't support Multiple Master CFFs yet; */ + /* note that `glyf' or `CFF2' have precedence */ + if ( face->goto_table( face, TTAG_glyf, stream, 0 ) && + face->goto_table( face, TTAG_CFF2, stream, 0 ) && + !face->goto_table( face, TTAG_CFF, stream, 0 ) ) + num_instances = 0; + + /* instance indices in `face_instance_index' start with index 1, */ + /* thus `>' and not `>=' */ + if ( instance_index > num_instances ) + { + if ( face_instance_index >= 0 ) + return FT_THROW( Invalid_Argument ); + else + num_instances = 0; + } + + face->root.style_flags = (FT_Long)num_instances << 16; + } +#endif + + face->root.num_faces = face->ttc_header.count; + face->root.face_index = face_instance_index; + + /* `num_faces' for a WOFF2 needs to be handled separately. */ + if ( woff2_num_faces ) + face->root.num_faces = woff2_num_faces; + + return error; + } + + +#define LOAD_( x ) \ + do \ + { \ + FT_TRACE2(( "`" #x "' " )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_ ## x( face, stream ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : FT_ERR_EQ( error, Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) + +#define LOADM_( x, vertical ) \ + do \ + { \ + FT_TRACE2(( "`%s" #x "' ", \ + vertical ? "vertical " : "" )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_ ## x( face, stream, vertical ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : FT_ERR_EQ( error, Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) + +#define GET_NAME( id, field ) \ + do \ + { \ + error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \ + if ( error ) \ + goto Exit; \ + } while ( 0 ) + + + FT_LOCAL_DEF( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_Error psnames_error; +#endif + + FT_Bool has_outline; + FT_Bool is_apple_sbit; + + FT_Bool has_CBLC; + FT_Bool has_CBDT; + FT_Bool has_EBLC; + FT_Bool has_bloc; + FT_Bool has_sbix; + + FT_Bool ignore_typographic_family = FALSE; + FT_Bool ignore_typographic_subfamily = FALSE; + FT_Bool ignore_sbix = FALSE; + + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_UNUSED( face_instance_index ); + + + /* Check parameters */ + + { + FT_Int i; + + + for ( i = 0; i < num_params; i++ ) + { + if ( params[i].tag == FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY ) + ignore_typographic_family = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY ) + ignore_typographic_subfamily = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_SBIX ) + ignore_sbix = TRUE; + } + } + + /* Load tables */ + + /* We now support two SFNT-based bitmapped font formats. They */ + /* are recognized easily as they do not include a `glyf' */ + /* table. */ + /* */ + /* The first format comes from Apple, and uses a table named */ + /* `bhed' instead of `head' to store the font header (using */ + /* the same format). It also doesn't include horizontal and */ + /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ + /* missing). */ + /* */ + /* The other format comes from Microsoft, and is used with */ + /* WinCE/PocketPC. It looks like a standard TTF, except that */ + /* it doesn't contain outlines. */ + /* */ + + FT_TRACE2(( "sfnt_load_face: %p\n", (void *)face )); + FT_TRACE2(( "\n" )); + + /* do we have outlines in there? */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + has_outline = FT_BOOL( face->root.internal->incremental_interface || + tt_face_lookup_table( face, TTAG_glyf ) || + tt_face_lookup_table( face, TTAG_CFF ) || + tt_face_lookup_table( face, TTAG_CFF2 ) ); +#else + has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) || + tt_face_lookup_table( face, TTAG_CFF ) || + tt_face_lookup_table( face, TTAG_CFF2 ) ); +#endif + + /* check which sbit formats are present */ + has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); + has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); + has_EBLC = !face->goto_table( face, TTAG_EBLC, stream, 0 ); + has_bloc = !face->goto_table( face, TTAG_bloc, stream, 0 ); + has_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); + + is_apple_sbit = FALSE; + + if ( ignore_sbix ) + has_sbix = FALSE; + + /* if this font doesn't contain outlines, we try to load */ + /* a `bhed' table */ + if ( !has_outline && sfnt->load_bhed ) + { + LOAD_( bhed ); + is_apple_sbit = FT_BOOL( !error ); + } + + /* load the font header (`head' table) if this isn't an Apple */ + /* sbit font file */ + if ( !is_apple_sbit || has_sbix ) + { + LOAD_( head ); + if ( error ) + goto Exit; + } + + /* Ignore outlines for CBLC/CBDT fonts. */ + if ( has_CBLC || has_CBDT ) + has_outline = FALSE; + + /* OpenType 1.8.2 introduced limits to this value; */ + /* however, they make sense for older SFNT fonts also */ + if ( face->header.Units_Per_EM < 16 || + face->header.Units_Per_EM > 16384 ) + { + error = FT_THROW( Invalid_Table ); + + goto Exit; + } + + /* the following tables are often not present in embedded TrueType */ + /* fonts within PDF documents, so don't check for them. */ + LOAD_( maxp ); + LOAD_( cmap ); + + /* the following tables are optional in PCL fonts -- */ + /* don't check for errors */ + LOAD_( name ); + LOAD_( post ); + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + psnames_error = error; +#endif + + /* do not load the metrics headers and tables if this is an Apple */ + /* sbit font file */ + if ( !is_apple_sbit ) + { + /* load the `hhea' and `hmtx' tables */ + LOADM_( hhea, 0 ); + if ( !error ) + { + LOADM_( hmtx, 0 ); + if ( FT_ERR_EQ( error, Table_Missing ) ) + { + error = FT_THROW( Hmtx_Table_Missing ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* If this is an incrementally loaded font and there are */ + /* overriding metrics, tolerate a missing `hmtx' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = FT_Err_Ok; + } +#endif + } + } + else if ( FT_ERR_EQ( error, Table_Missing ) ) + { + /* No `hhea' table necessary for SFNT Mac fonts. */ + if ( face->format_tag == TTAG_true ) + { + FT_TRACE2(( "This is an SFNT Mac font.\n" )); + + has_outline = 0; + error = FT_Err_Ok; + } + else + { + error = FT_THROW( Horiz_Header_Missing ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* If this is an incrementally loaded font and there are */ + /* overriding metrics, tolerate a missing `hhea' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = FT_Err_Ok; + } +#endif + + } + } + + if ( error ) + goto Exit; + + /* try to load the `vhea' and `vmtx' tables */ + LOADM_( hhea, 1 ); + if ( !error ) + { + LOADM_( hmtx, 1 ); + if ( !error ) + face->vertical_info = 1; + } + + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + LOAD_( os2 ); + if ( error ) + { + /* we treat the table as missing if there are any errors */ + face->os2.version = 0xFFFFU; + } + } + + /* the optional tables */ + + /* embedded bitmap support */ + /* TODO: Replace this clumsy check for all possible sbit tables */ + /* with something better (for example, by passing a parameter */ + /* to suppress 'sbix' loading). */ + if ( sfnt->load_eblc && + ( has_CBLC || has_EBLC || has_bloc || has_sbix ) ) + LOAD_( eblc ); + + /* colored glyph support */ + if ( sfnt->load_cpal ) + { + LOAD_( cpal ); + LOAD_( colr ); + } + + /* OpenType-SVG glyph support */ + if ( sfnt->load_svg ) + LOAD_( svg ); + + /* consider the pclt, kerning, and gasp tables as optional */ + LOAD_( pclt ); + LOAD_( gasp ); + LOAD_( kern ); + + face->root.num_glyphs = face->max_profile.numGlyphs; + + /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ + /* a WWS-only font face. `WWS' stands for `weight', width', and */ + /* `slope', a term used by Microsoft's Windows Presentation */ + /* Foundation (WPF). This flag has been introduced in version */ + /* 1.5 of the OpenType specification (May 2008). */ + + face->root.family_name = NULL; + face->root.style_name = NULL; + if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 ) + { + if ( !ignore_typographic_family ) + GET_NAME( TYPOGRAPHIC_FAMILY, &face->root.family_name ); + if ( !face->root.family_name ) + GET_NAME( FONT_FAMILY, &face->root.family_name ); + + if ( !ignore_typographic_subfamily ) + GET_NAME( TYPOGRAPHIC_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name ) + GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); + } + else + { + GET_NAME( WWS_FAMILY, &face->root.family_name ); + if ( !face->root.family_name && !ignore_typographic_family ) + GET_NAME( TYPOGRAPHIC_FAMILY, &face->root.family_name ); + if ( !face->root.family_name ) + GET_NAME( FONT_FAMILY, &face->root.family_name ); + + GET_NAME( WWS_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name && !ignore_typographic_subfamily ) + GET_NAME( TYPOGRAPHIC_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name ) + GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Memory memory = face->root.memory; + + + if ( FT_STRDUP( face->non_var_style_name, face->root.style_name ) ) + goto Exit; + } +#endif + + /* now set up root fields */ + { + FT_Face root = &face->root; + FT_Long flags = root->face_flags; + + + /********************************************************************** + * + * Compute face flags. + */ + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || + face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX || + face->colr || + face->svg ) + flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ + + if ( has_outline == TRUE ) + { + /* by default (and for backward compatibility) we handle */ + /* fonts with an 'sbix' table as bitmap-only */ + if ( has_sbix ) + flags |= FT_FACE_FLAG_SBIX; /* with 'sbix' bitmaps */ + else + flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + } + + /* The sfnt driver only supports bitmap fonts natively, thus we */ + /* don't set FT_FACE_FLAG_HINTER. */ + flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ + FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + if ( !psnames_error && + face->postscript.FormatType != 0x00030000L ) + flags |= FT_FACE_FLAG_GLYPH_NAMES; +#endif + + /* fixed width font? */ + if ( face->postscript.isFixedPitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* vertical information? */ + if ( face->vertical_info ) + flags |= FT_FACE_FLAG_VERTICAL; + + /* kerning available ? */ + if ( TT_FACE_HAS_KERNING( face ) ) + flags |= FT_FACE_FLAG_KERNING; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Don't bother to load the tables unless somebody asks for them. */ + /* No need to do work which will (probably) not be used. */ + if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) + flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; +#endif + + root->face_flags = flags; + + /********************************************************************** + * + * Compute style flags. + */ + + flags = 0; + if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) + { + /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ + /* indicates an oblique font face. This flag has been */ + /* introduced in version 1.5 of the OpenType specification. */ + + if ( face->os2.fsSelection & 512 ) /* bit 9 */ + flags |= FT_STYLE_FLAG_ITALIC; + else if ( face->os2.fsSelection & 1 ) /* bit 0 */ + flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->os2.fsSelection & 32 ) /* bit 5 */ + flags |= FT_STYLE_FLAG_BOLD; + } + else + { + /* this is an old Mac font, use the header field */ + + if ( face->header.Mac_Style & 1 ) + flags |= FT_STYLE_FLAG_BOLD; + + if ( face->header.Mac_Style & 2 ) + flags |= FT_STYLE_FLAG_ITALIC; + } + + root->style_flags |= flags; + + /********************************************************************** + * + * Polish the charmaps. + * + * Try to set the charmap encoding according to the platform & + * encoding ID of each charmap. Emulate Unicode charmap if one + * is missing. + */ + + tt_face_build_cmaps( face ); /* ignore errors */ + + + /* set the encoding fields */ + { + FT_Int m; +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_Bool has_unicode = FALSE; +#endif + + + for ( m = 0; m < root->num_charmaps; m++ ) + { + FT_CharMap charmap = root->charmaps[m]; + + + charmap->encoding = sfnt_find_encoding( charmap->platform_id, + charmap->encoding_id ); + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + if ( charmap->encoding == FT_ENCODING_UNICODE || + charmap->encoding == FT_ENCODING_MS_SYMBOL ) /* PUA */ + has_unicode = TRUE; + } + + /* synthesize Unicode charmap if one is missing */ + if ( !has_unicode && + root->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + { + FT_CharMapRec cmaprec; + + + cmaprec.face = root; + cmaprec.platform_id = TT_PLATFORM_MICROSOFT; + cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; + cmaprec.encoding = FT_ENCODING_UNICODE; + + + error = FT_CMap_New( (FT_CMap_Class)&tt_cmap_unicode_class_rec, + NULL, &cmaprec, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + } + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* + * Now allocate the root array of FT_Bitmap_Size records and + * populate them. Unfortunately, it isn't possible to indicate bit + * depths in the FT_Bitmap_Size record. This is a design error. + */ + { + FT_UInt count; + + + count = face->sbit_num_strikes; + + if ( count > 0 ) + { + FT_Memory memory = face->root.memory; + FT_UShort em_size = face->header.Units_Per_EM; + FT_Short avgwidth = face->os2.xAvgCharWidth; + FT_Size_Metrics metrics; + + FT_UInt* sbit_strike_map = NULL; + FT_UInt strike_idx, bsize_idx; + + + if ( em_size == 0 || face->os2.version == 0xFFFFU ) + { + avgwidth = 1; + em_size = 1; + } + + /* to avoid invalid strike data in the `available_sizes' field */ + /* of `FT_Face', we map `available_sizes' indices to strike */ + /* indices */ + if ( FT_NEW_ARRAY( root->available_sizes, count ) || + FT_QNEW_ARRAY( sbit_strike_map, count ) ) + goto Exit; + + bsize_idx = 0; + for ( strike_idx = 0; strike_idx < count; strike_idx++ ) + { + FT_Bitmap_Size* bsize = root->available_sizes + bsize_idx; + + + error = sfnt->load_strike_metrics( face, strike_idx, &metrics ); + if ( error ) + continue; + + bsize->height = (FT_Short)( metrics.height >> 6 ); + bsize->width = (FT_Short)( + ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); + + bsize->x_ppem = metrics.x_ppem << 6; + bsize->y_ppem = metrics.y_ppem << 6; + + /* assume 72dpi */ + bsize->size = metrics.y_ppem << 6; + + /* only use strikes with valid PPEM values */ + if ( bsize->x_ppem && bsize->y_ppem ) + sbit_strike_map[bsize_idx++] = strike_idx; + } + + /* reduce array size to the actually used elements */ + FT_MEM_QRENEW_ARRAY( sbit_strike_map, count, bsize_idx ); + + /* from now on, all strike indices are mapped */ + /* using `sbit_strike_map' */ + if ( bsize_idx ) + { + face->sbit_strike_map = sbit_strike_map; + + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + root->num_fixed_sizes = (FT_Int)bsize_idx; + } + } + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* a font with no bitmaps and no outlines is scalable; */ + /* it has only empty glyphs then */ + if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) + root->face_flags |= FT_FACE_FLAG_SCALABLE; + + + /********************************************************************** + * + * Set up metrics. + */ + if ( FT_IS_SCALABLE( root ) || + FT_HAS_SBIX( root ) ) + { + /* XXX What about if outline header is missing */ + /* (e.g. sfnt wrapped bitmap)? */ + root->bbox.xMin = face->header.xMin; + root->bbox.yMin = face->header.yMin; + root->bbox.xMax = face->header.xMax; + root->bbox.yMax = face->header.yMax; + root->units_per_EM = face->header.Units_Per_EM; + + + /* + * Computing the ascender/descender/height is tricky. + * + * The OpenType specification v1.8.3 says: + * + * [OS/2's] sTypoAscender, sTypoDescender and sTypoLineGap fields + * are intended to allow applications to lay out documents in a + * typographically-correct and portable fashion. + * + * This is somewhat at odds with the decades of backwards + * compatibility, operating systems and applications doing whatever + * they want, not to mention broken fonts. + * + * Not all fonts have an OS/2 table; in this case, we take the values + * in the horizontal header, although there is nothing stopping the + * values from being unreliable. Even with a OS/2 table, certain fonts + * set the sTypoAscender, sTypoDescender and sTypoLineGap fields to 0 + * and instead correctly set usWinAscent and usWinDescent. + * + * As an example, Arial Narrow is shipped as four files ARIALN.TTF, + * ARIALNI.TTF, ARIALNB.TTF and ARIALNBI.TTF. Strangely, all fonts have + * the same values in their sTypo* fields, except ARIALNB.ttf which + * sets them to 0. All of them have different usWinAscent/Descent + * values. The OS/2 table therefore cannot be trusted for computing the + * text height reliably. + * + * As a compromise, do the following: + * + * 1. If the OS/2 table exists and the fsSelection bit 7 is set + * (USE_TYPO_METRICS), trust the font and use the sTypo* metrics. + * 2. Otherwise, use the `hhea' table's metrics. + * 3. If they are zero and the OS/2 table exists, + * 1. use the OS/2 table's sTypo* metrics if they are non-zero. + * 2. Otherwise, use the OS/2 table's usWin* metrics. + */ + + if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 128 ) + { + root->ascender = face->os2.sTypoAscender; + root->descender = face->os2.sTypoDescender; + root->height = root->ascender - root->descender + + face->os2.sTypoLineGap; + } + else + { + root->ascender = face->horizontal.Ascender; + root->descender = face->horizontal.Descender; + root->height = root->ascender - root->descender + + face->horizontal.Line_Gap; + + if ( !( root->ascender || root->descender ) ) + { + if ( face->os2.version != 0xFFFFU ) + { + if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) + { + root->ascender = face->os2.sTypoAscender; + root->descender = face->os2.sTypoDescender; + root->height = root->ascender - root->descender + + face->os2.sTypoLineGap; + } + else + { + root->ascender = (FT_Short)face->os2.usWinAscent; + root->descender = -(FT_Short)face->os2.usWinDescent; + root->height = root->ascender - root->descender; + } + } + } + } + + root->max_advance_width = + (FT_Short)face->horizontal.advance_Width_Max; + root->max_advance_height = + (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max + : root->height ); + + /* See https://www.microsoft.com/typography/otspec/post.htm -- */ + /* Adjust underline position from top edge to centre of */ + /* stroke to convert TrueType meaning to FreeType meaning. */ + root->underline_position = face->postscript.underlinePosition - + face->postscript.underlineThickness / 2; + root->underline_thickness = face->postscript.underlineThickness; + } + + } + + Exit: + FT_TRACE2(( "sfnt_load_face: done\n" )); + + return error; + } + + +#undef LOAD_ +#undef LOADM_ +#undef GET_NAME + + + FT_LOCAL_DEF( void ) + sfnt_done_face( TT_Face face ) + { + FT_Memory memory; + SFNT_Service sfnt; + + + if ( !face ) + return; + + memory = face->root.memory; + sfnt = (SFNT_Service)face->sfnt; + + if ( sfnt ) + { + /* destroy the postscript names table if it is loaded */ + if ( sfnt->free_psnames ) + sfnt->free_psnames( face ); + + /* destroy the embedded bitmaps table if it is loaded */ + if ( sfnt->free_eblc ) + sfnt->free_eblc( face ); + + /* destroy color table data if it is loaded */ + if ( sfnt->free_cpal ) + { + sfnt->free_cpal( face ); + sfnt->free_colr( face ); + } + +#ifdef FT_CONFIG_OPTION_SVG + /* free SVG data */ + if ( sfnt->free_svg ) + sfnt->free_svg( face ); +#endif + } + +#ifdef TT_CONFIG_OPTION_BDF + /* freeing the embedded BDF properties */ + tt_face_free_bdf_props( face ); +#endif + + /* freeing the kerning table */ + tt_face_done_kern( face ); + + /* freeing the collection table */ + FT_FREE( face->ttc_header.offsets ); + face->ttc_header.count = 0; + + /* freeing table directory */ + FT_FREE( face->dir_tables ); + face->num_tables = 0; + + { + FT_Stream stream = FT_FACE_STREAM( face ); + + + /* simply release the 'cmap' table frame */ + FT_FRAME_RELEASE( face->cmap_table ); + face->cmap_size = 0; + } + + face->horz_metrics_size = 0; + face->vert_metrics_size = 0; + + /* freeing vertical metrics, if any */ + if ( face->vertical_info ) + { + FT_FREE( face->vertical.long_metrics ); + FT_FREE( face->vertical.short_metrics ); + face->vertical_info = 0; + } + + /* freeing the gasp table */ + FT_FREE( face->gasp.gaspRanges ); + face->gasp.numRanges = 0; + + /* freeing the name table */ + if ( sfnt ) + sfnt->free_name( face ); + + /* freeing family and style name */ + FT_FREE( face->root.family_name ); + FT_FREE( face->root.style_name ); + + /* freeing sbit size table */ + FT_FREE( face->root.available_sizes ); + FT_FREE( face->sbit_strike_map ); + face->root.num_fixed_sizes = 0; + + FT_FREE( face->postscript_name ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_FREE( face->var_postscript_prefix ); + FT_FREE( face->non_var_style_name ); +#endif + + /* freeing glyph color palette data */ + FT_FREE( face->palette_data.palette_name_ids ); + FT_FREE( face->palette_data.palette_flags ); + FT_FREE( face->palette_data.palette_entry_name_ids ); + FT_FREE( face->palette ); + + face->sfnt = NULL; + } + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfobjs.h b/vendor/freetype/src/sfnt/sfobjs.h new file mode 100644 index 0000000..906aebb --- /dev/null +++ b/vendor/freetype/src/sfnt/sfobjs.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * + * sfobjs.h + * + * SFNT object management (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFOBJS_H_ +#define SFOBJS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + sfnt_done_face( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_get_name( TT_Face face, + FT_UShort nameid, + FT_String** name ); + + +FT_END_HEADER + +#endif /* SFOBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfwoff.c b/vendor/freetype/src/sfnt/sfwoff.c new file mode 100644 index 0000000..7c0ce22 --- /dev/null +++ b/vendor/freetype/src/sfnt/sfwoff.c @@ -0,0 +1,434 @@ +/**************************************************************************** + * + * sfwoff.c + * + * WOFF format management (base). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "sfwoff.h" +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfwoff + + +#define WRITE_USHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_ULONG( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 24 ); \ + *(p)++ = (FT_Byte)( (v) >> 16 ); \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + + + static void + sfnt_stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->close = NULL; + } + + + FT_COMPARE_DEF( int ) + compare_offsets( const void* a, + const void* b ) + { + WOFF_Table table1 = *(WOFF_Table*)a; + WOFF_Table table2 = *(WOFF_Table*)b; + + FT_ULong offset1 = table1->Offset; + FT_ULong offset2 = table2->Offset; + + + if ( offset1 > offset2 ) + return 1; + else if ( offset1 < offset2 ) + return -1; + else + return 0; + } + + + /* Replace `face->root.stream' with a stream containing the extracted */ + /* SFNT of a WOFF font. */ + + FT_LOCAL_DEF( FT_Error ) + woff_open_font( FT_Stream stream, + TT_Face face ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + + WOFF_HeaderRec woff; + WOFF_Table tables = NULL; + WOFF_Table* indices = NULL; + + FT_ULong woff_offset; + + FT_Byte* sfnt = NULL; + FT_Stream sfnt_stream = NULL; + + FT_Byte* sfnt_header; + FT_ULong sfnt_offset; + + FT_Int nn; + FT_Tag old_tag = 0; + + static const FT_Frame_Field woff_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WOFF_HeaderRec + + FT_FRAME_START( 44 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_ULONG ( flavor ), + FT_FRAME_ULONG ( length ), + FT_FRAME_USHORT( num_tables ), + FT_FRAME_USHORT( reserved ), + FT_FRAME_ULONG ( totalSfntSize ), + FT_FRAME_USHORT( majorVersion ), + FT_FRAME_USHORT( minorVersion ), + FT_FRAME_ULONG ( metaOffset ), + FT_FRAME_ULONG ( metaLength ), + FT_FRAME_ULONG ( metaOrigLength ), + FT_FRAME_ULONG ( privOffset ), + FT_FRAME_ULONG ( privLength ), + FT_FRAME_END + }; + + + FT_ASSERT( stream == face->root.stream ); + FT_ASSERT( FT_STREAM_POS() == 0 ); + + if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) ) + return error; + + /* Make sure we don't recurse back here or hit TTC code. */ + if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf ) + return FT_THROW( Invalid_Table ); + + /* Miscellaneous checks. */ + if ( woff.length != stream->size || + woff.num_tables == 0 || + 44 + woff.num_tables * 20UL >= woff.length || + 12 + woff.num_tables * 16UL >= woff.totalSfntSize || + ( woff.totalSfntSize & 3 ) != 0 || + ( woff.metaOffset == 0 && ( woff.metaLength != 0 || + woff.metaOrigLength != 0 ) ) || + ( woff.metaLength != 0 && woff.metaOrigLength == 0 ) || + ( woff.privOffset == 0 && woff.privLength != 0 ) ) + { + FT_ERROR(( "woff_font_open: invalid WOFF header\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Don't trust `totalSfntSize' before thorough checks. */ + if ( FT_QALLOC( sfnt, 12 ) || FT_NEW( sfnt_stream ) ) + goto Exit; + + sfnt_header = sfnt; + + /* Write sfnt header. */ + { + FT_UInt searchRange, entrySelector, rangeShift, x; + + + x = woff.num_tables; + entrySelector = 0; + while ( x ) + { + x >>= 1; + entrySelector += 1; + } + entrySelector--; + + searchRange = ( 1 << entrySelector ) * 16; + rangeShift = woff.num_tables * 16 - searchRange; + + WRITE_ULONG ( sfnt_header, woff.flavor ); + WRITE_USHORT( sfnt_header, woff.num_tables ); + WRITE_USHORT( sfnt_header, searchRange ); + WRITE_USHORT( sfnt_header, entrySelector ); + WRITE_USHORT( sfnt_header, rangeShift ); + } + + /* While the entries in the sfnt header must be sorted by the */ + /* tag value, the tables themselves are not. We thus have to */ + /* sort them by offset and check that they don't overlap. */ + + if ( FT_QNEW_ARRAY( tables, woff.num_tables ) || + FT_QNEW_ARRAY( indices, woff.num_tables ) ) + goto Exit; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset compLen origLen checksum\n" )); + FT_TRACE2(( " -------------------------------------------\n" )); + + if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) + goto Exit; + + for ( nn = 0; nn < woff.num_tables; nn++ ) + { + WOFF_Table table = tables + nn; + + table->Tag = FT_GET_TAG4(); + table->Offset = FT_GET_ULONG(); + table->CompLength = FT_GET_ULONG(); + table->OrigLength = FT_GET_ULONG(); + table->CheckSum = FT_GET_ULONG(); + + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n", + (FT_Char)( table->Tag >> 24 ), + (FT_Char)( table->Tag >> 16 ), + (FT_Char)( table->Tag >> 8 ), + (FT_Char)( table->Tag ), + table->Offset, + table->CompLength, + table->OrigLength, + table->CheckSum )); + + if ( table->Tag <= old_tag ) + { + FT_FRAME_EXIT(); + + FT_ERROR(( "woff_font_open: table tags are not sorted\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + old_tag = table->Tag; + indices[nn] = table; + } + + FT_FRAME_EXIT(); + + /* Sort by offset. */ + + ft_qsort( indices, + woff.num_tables, + sizeof ( WOFF_Table ), + compare_offsets ); + + /* Check offsets and lengths. */ + + woff_offset = 44 + woff.num_tables * 20L; + sfnt_offset = 12 + woff.num_tables * 16L; + + for ( nn = 0; nn < woff.num_tables; nn++ ) + { + WOFF_Table table = indices[nn]; + + + if ( table->Offset != woff_offset || + table->CompLength > woff.length || + table->Offset > woff.length - table->CompLength || + table->OrigLength > woff.totalSfntSize || + sfnt_offset > woff.totalSfntSize - table->OrigLength || + table->CompLength > table->OrigLength ) + { + FT_ERROR(( "woff_font_open: invalid table offsets\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + table->OrigOffset = sfnt_offset; + + /* The offsets must be multiples of 4. */ + woff_offset += ( table->CompLength + 3 ) & ~3U; + sfnt_offset += ( table->OrigLength + 3 ) & ~3U; + } + + /* + * Final checks! + * + * We don't decode and check the metadata block. + * We don't check table checksums either. + * But other than those, I think we implement all + * `MUST' checks from the spec. + */ + + if ( woff.metaOffset ) + { + if ( woff.metaOffset != woff_offset || + woff.metaOffset + woff.metaLength > woff.length ) + { + FT_ERROR(( "woff_font_open:" + " invalid `metadata' offset or length\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* We have padding only ... */ + woff_offset += woff.metaLength; + } + + if ( woff.privOffset ) + { + /* ... if it isn't the last block. */ + woff_offset = ( woff_offset + 3 ) & ~3U; + + if ( woff.privOffset != woff_offset || + woff.privOffset + woff.privLength > woff.length ) + { + FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* No padding for the last block. */ + woff_offset += woff.privLength; + } + + if ( sfnt_offset != woff.totalSfntSize || + woff_offset != woff.length ) + { + FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* Now use `totalSfntSize'. */ + if ( FT_QREALLOC( sfnt, 12, woff.totalSfntSize ) ) + goto Exit; + + sfnt_header = sfnt + 12; + + /* Write the tables. */ + + for ( nn = 0; nn < woff.num_tables; nn++ ) + { + WOFF_Table table = tables + nn; + + + /* Write SFNT table entry. */ + WRITE_ULONG( sfnt_header, table->Tag ); + WRITE_ULONG( sfnt_header, table->CheckSum ); + WRITE_ULONG( sfnt_header, table->OrigOffset ); + WRITE_ULONG( sfnt_header, table->OrigLength ); + + /* Write table data. */ + if ( FT_STREAM_SEEK( table->Offset ) || + FT_FRAME_ENTER( table->CompLength ) ) + goto Exit; + + if ( table->CompLength == table->OrigLength ) + { + /* Uncompressed data; just copy. */ + ft_memcpy( sfnt + table->OrigOffset, + stream->cursor, + table->OrigLength ); + } + else + { + /* Uncompress with zlib. */ + FT_ULong output_len = table->OrigLength; + + + error = FT_Gzip_Uncompress( memory, + sfnt + table->OrigOffset, &output_len, + stream->cursor, table->CompLength ); + if ( error ) + goto Exit1; + if ( output_len != table->OrigLength ) + { + FT_ERROR(( "woff_font_open: compressed table length mismatch\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit1; + } + } + + FT_FRAME_EXIT(); + + /* We don't check whether the padding bytes in the WOFF file are */ + /* actually '\0'. For the output, however, we do set them properly. */ + sfnt_offset = table->OrigOffset + table->OrigLength; + while ( sfnt_offset & 3 ) + { + sfnt[sfnt_offset] = '\0'; + sfnt_offset++; + } + } + + /* Ok! Finally ready. Swap out stream and return. */ + FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize ); + sfnt_stream->memory = stream->memory; + sfnt_stream->close = sfnt_stream_close; + + FT_Stream_Free( + face->root.stream, + ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->root.stream = sfnt_stream; + + face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + + Exit: + FT_FREE( tables ); + FT_FREE( indices ); + + if ( error ) + { + FT_FREE( sfnt ); + FT_Stream_Close( sfnt_stream ); + FT_FREE( sfnt_stream ); + } + + return error; + + Exit1: + FT_FRAME_EXIT(); + goto Exit; + } + + +#undef WRITE_USHORT +#undef WRITE_ULONG + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfwoff.h b/vendor/freetype/src/sfnt/sfwoff.h new file mode 100644 index 0000000..d438422 --- /dev/null +++ b/vendor/freetype/src/sfnt/sfwoff.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * sfwoff.h + * + * WOFFF format management (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFWOFF_H_ +#define SFWOFF_H_ + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + FT_LOCAL( FT_Error ) + woff_open_font( FT_Stream stream, + TT_Face face ); + + +#endif + +FT_END_HEADER + +#endif /* SFWOFF_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfwoff2.c b/vendor/freetype/src/sfnt/sfwoff2.c new file mode 100644 index 0000000..2be44a3 --- /dev/null +++ b/vendor/freetype/src/sfnt/sfwoff2.c @@ -0,0 +1,2392 @@ +/**************************************************************************** + * + * sfwoff2.c + * + * WOFF2 format management (base). + * + * Copyright (C) 2019-2023 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include "sfwoff2.h" +#include "woff2tags.h" +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfwoff2 + + /* An arbitrary, heuristic size limit (67MByte) for expanded WOFF2 data. */ +#define MAX_SFNT_SIZE ( 1 << 26 ) + +#define READ_255USHORT( var ) FT_SET_ERROR( Read255UShort( stream, &var ) ) + +#define READ_BASE128( var ) FT_SET_ERROR( ReadBase128( stream, &var ) ) + + /* `var' should be FT_ULong */ +#define ROUND4( var ) ( ( var + 3 ) & ~3UL ) + +#define WRITE_USHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_ULONG( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 24 ); \ + *(p)++ = (FT_Byte)( (v) >> 16 ); \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_SHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_SFNT_BUF( buf, s ) \ + write_buf( &sfnt, sfnt_size, &dest_offset, buf, s, memory ) + +#define WRITE_SFNT_BUF_AT( offset, buf, s ) \ + write_buf( &sfnt, sfnt_size, &offset, buf, s, memory ) + +#define N_CONTOUR_STREAM 0 +#define N_POINTS_STREAM 1 +#define FLAG_STREAM 2 +#define GLYPH_STREAM 3 +#define COMPOSITE_STREAM 4 +#define BBOX_STREAM 5 +#define INSTRUCTION_STREAM 6 + +#define HAVE_OVERLAP_SIMPLE_BITMAP 0x1 + + + static void + stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->close = NULL; + } + + + FT_COMPARE_DEF( int ) + compare_tags( const void* a, + const void* b ) + { + WOFF2_Table table1 = *(WOFF2_Table*)a; + WOFF2_Table table2 = *(WOFF2_Table*)b; + + FT_Tag tag1 = table1->Tag; + FT_Tag tag2 = table2->Tag; + + + if ( tag1 > tag2 ) + return 1; + else if ( tag1 < tag2 ) + return -1; + else + return 0; + } + + + static FT_Error + Read255UShort( FT_Stream stream, + FT_UShort* value ) + { + const FT_Byte oneMoreByteCode1 = 255; + const FT_Byte oneMoreByteCode2 = 254; + const FT_Byte wordCode = 253; + const FT_UShort lowestUCode = 253; + + FT_Error error = FT_Err_Ok; + FT_Byte code; + FT_Byte result_byte = 0; + FT_UShort result_short = 0; + + + if ( FT_READ_BYTE( code ) ) + return error; + if ( code == wordCode ) + { + /* Read next two bytes and store `FT_UShort' value. */ + if ( FT_READ_USHORT( result_short ) ) + return error; + *value = result_short; + return FT_Err_Ok; + } + else if ( code == oneMoreByteCode1 ) + { + if ( FT_READ_BYTE( result_byte ) ) + return error; + *value = result_byte + lowestUCode; + return FT_Err_Ok; + } + else if ( code == oneMoreByteCode2 ) + { + if ( FT_READ_BYTE( result_byte ) ) + return error; + *value = result_byte + lowestUCode * 2; + return FT_Err_Ok; + } + else + { + *value = code; + return FT_Err_Ok; + } + } + + + static FT_Error + ReadBase128( FT_Stream stream, + FT_ULong* value ) + { + FT_ULong result = 0; + FT_Int i; + FT_Byte code; + FT_Error error = FT_Err_Ok; + + + for ( i = 0; i < 5; ++i ) + { + code = 0; + if ( FT_READ_BYTE( code ) ) + return error; + + /* Leading zeros are invalid. */ + if ( i == 0 && code == 0x80 ) + return FT_THROW( Invalid_Table ); + + /* If any of top seven bits are set then we're about to overflow. */ + if ( result & 0xfe000000 ) + return FT_THROW( Invalid_Table ); + + result = ( result << 7 ) | ( code & 0x7f ); + + /* Spin until most significant bit of data byte is false. */ + if ( ( code & 0x80 ) == 0 ) + { + *value = result; + return FT_Err_Ok; + } + } + + /* Make sure not to exceed the size bound. */ + return FT_THROW( Invalid_Table ); + } + + + /* Extend memory of `dst_bytes' buffer and copy data from `src'. */ + static FT_Error + write_buf( FT_Byte** dst_bytes, + FT_ULong* dst_size, + FT_ULong* offset, + FT_Byte* src, + FT_ULong size, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + /* We are reallocating memory for `dst', so its pointer may change. */ + FT_Byte* dst = *dst_bytes; + + + /* Check whether we are within limits. */ + if ( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE ) + return FT_THROW( Array_Too_Large ); + + /* Reallocate `dst'. */ + if ( ( *offset + size ) > *dst_size ) + { + FT_TRACE6(( "Reallocating %lu to %lu.\n", + *dst_size, (*offset + size) )); + if ( FT_QREALLOC( dst, + (FT_ULong)( *dst_size ), + (FT_ULong)( *offset + size ) ) ) + goto Exit; + + *dst_size = *offset + size; + } + + /* Copy data. */ + ft_memcpy( dst + *offset, src, size ); + + *offset += size; + /* Set pointer of `dst' to its correct value. */ + *dst_bytes = dst; + + Exit: + return error; + } + + + /* Pad buffer to closest multiple of 4. */ + static FT_Error + pad4( FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte zeroes[] = { 0, 0, 0 }; + FT_ULong pad_bytes; + + + if ( dest_offset + 3 < dest_offset ) + return FT_THROW( Invalid_Table ); + + pad_bytes = ROUND4( dest_offset ) - dest_offset; + if ( pad_bytes > 0 ) + { + if ( WRITE_SFNT_BUF( &zeroes[0], pad_bytes ) ) + return FT_THROW( Invalid_Table ); + } + + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + return FT_Err_Ok; + } + + + /* Calculate table checksum of `buf'. */ + static FT_ULong + compute_ULong_sum( FT_Byte* buf, + FT_ULong size ) + { + FT_ULong checksum = 0; + FT_ULong aligned_size = size & ~3UL; + FT_ULong i; + FT_ULong v; + + + for ( i = 0; i < aligned_size; i += 4 ) + checksum += ( (FT_ULong)buf[i ] << 24 ) | + ( (FT_ULong)buf[i + 1] << 16 ) | + ( (FT_ULong)buf[i + 2] << 8 ) | + ( (FT_ULong)buf[i + 3] << 0 ); + + /* If size is not aligned to 4, treat as if it is padded with 0s. */ + if ( size != aligned_size ) + { + v = 0; + for ( i = aligned_size ; i < size; ++i ) + v |= (FT_ULong)buf[i] << ( 24 - 8 * ( i & 3 ) ); + checksum += v; + } + + return checksum; + } + + + static FT_Error + woff2_decompress( FT_Byte* dst, + FT_ULong dst_size, + const FT_Byte* src, + FT_ULong src_size ) + { + /* this cast is only of importance on 32bit systems; */ + /* we don't validate it */ + FT_Offset uncompressed_size = (FT_Offset)dst_size; + BrotliDecoderResult result; + + + result = BrotliDecoderDecompress( src_size, + src, + &uncompressed_size, + dst ); + + if ( result != BROTLI_DECODER_RESULT_SUCCESS || + uncompressed_size != dst_size ) + { + FT_ERROR(( "woff2_decompress: Stream length mismatch.\n" )); + return FT_THROW( Invalid_Table ); + } + + FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" )); + return FT_Err_Ok; + } + + + static WOFF2_Table + find_table( WOFF2_Table* tables, + FT_UShort num_tables, + FT_Tag tag ) + { + FT_Int i; + + + for ( i = 0; i < num_tables; i++ ) + { + if ( tables[i]->Tag == tag ) + return tables[i]; + } + return NULL; + } + + + /* Read `numberOfHMetrics' field from `hhea' table. */ + static FT_Error + read_num_hmetrics( FT_Stream stream, + FT_UShort* num_hmetrics ) + { + FT_Error error = FT_Err_Ok; + FT_UShort num_metrics; + + + if ( FT_STREAM_SKIP( 34 ) ) + return FT_THROW( Invalid_Table ); + + if ( FT_READ_USHORT( num_metrics ) ) + return FT_THROW( Invalid_Table ); + + *num_hmetrics = num_metrics; + + return error; + } + + + /* An auxiliary function for overflow-safe addition. */ + static FT_Int + with_sign( FT_Byte flag, + FT_Int base_val ) + { + /* Precondition: 0 <= base_val < 65536 (to avoid overflow). */ + return ( flag & 1 ) ? base_val : -base_val; + } + + + /* An auxiliary function for overflow-safe addition. */ + static FT_Int + safe_int_addition( FT_Int a, + FT_Int b, + FT_Int* result ) + { + if ( ( ( a > 0 ) && ( b > FT_INT_MAX - a ) ) || + ( ( a < 0 ) && ( b < FT_INT_MIN - a ) ) ) + return FT_THROW( Invalid_Table ); + + *result = a + b; + return FT_Err_Ok; + } + + + /* + * Decode variable-length (flag, xCoordinate, yCoordinate) triplet for a + * simple glyph. See + * + * https://www.w3.org/TR/WOFF2/#triplet_decoding + */ + static FT_Error + triplet_decode( const FT_Byte* flags_in, + const FT_Byte* in, + FT_ULong in_size, + FT_ULong n_points, + WOFF2_Point result, + FT_ULong* in_bytes_used ) + { + FT_Int x = 0; + FT_Int y = 0; + FT_Int dx; + FT_Int dy; + FT_Int b0, b1, b2; + + FT_ULong triplet_index = 0; + FT_ULong data_bytes; + + FT_UInt i; + + + if ( n_points > in_size ) + return FT_THROW( Invalid_Table ); + + for ( i = 0; i < n_points; ++i ) + { + FT_Byte flag = flags_in[i]; + FT_Bool on_curve = !( flag >> 7 ); + + + flag &= 0x7f; + if ( flag < 84 ) + data_bytes = 1; + else if ( flag < 120 ) + data_bytes = 2; + else if ( flag < 124 ) + data_bytes = 3; + else + data_bytes = 4; + + /* Overflow checks */ + if ( triplet_index + data_bytes > in_size || + triplet_index + data_bytes < triplet_index ) + return FT_THROW( Invalid_Table ); + + if ( flag < 10 ) + { + dx = 0; + dy = with_sign( flag, + ( ( flag & 14 ) << 7 ) + in[triplet_index] ); + } + else if ( flag < 20 ) + { + dx = with_sign( flag, + ( ( ( flag - 10 ) & 14 ) << 7 ) + + in[triplet_index] ); + dy = 0; + } + else if ( flag < 84 ) + { + b0 = flag - 20; + b1 = in[triplet_index]; + dx = with_sign( flag, + 1 + ( b0 & 0x30 ) + ( b1 >> 4 ) ); + dy = with_sign( flag >> 1, + 1 + ( ( b0 & 0x0c ) << 2 ) + ( b1 & 0x0f ) ); + } + else if ( flag < 120 ) + { + b0 = flag - 84; + dx = with_sign( flag, + 1 + ( ( b0 / 12 ) << 8 ) + in[triplet_index] ); + dy = with_sign( flag >> 1, + 1 + ( ( ( b0 % 12 ) >> 2 ) << 8 ) + + in[triplet_index + 1] ); + } + else if ( flag < 124 ) + { + b2 = in[triplet_index + 1]; + dx = with_sign( flag, + ( in[triplet_index] << 4 ) + ( b2 >> 4 ) ); + dy = with_sign( flag >> 1, + ( ( b2 & 0x0f ) << 8 ) + in[triplet_index + 2] ); + } + else + { + dx = with_sign( flag, + ( in[triplet_index] << 8 ) + + in[triplet_index + 1] ); + dy = with_sign( flag >> 1, + ( in[triplet_index + 2] << 8 ) + + in[triplet_index + 3] ); + } + + triplet_index += data_bytes; + + if ( safe_int_addition( x, dx, &x ) ) + return FT_THROW( Invalid_Table ); + + if ( safe_int_addition( y, dy, &y ) ) + return FT_THROW( Invalid_Table ); + + result[i].x = x; + result[i].y = y; + result[i].on_curve = on_curve; + } + + *in_bytes_used = triplet_index; + return FT_Err_Ok; + } + + + /* Store decoded points in glyph buffer. */ + static FT_Error + store_points( FT_ULong n_points, + const WOFF2_Point points, + FT_UShort n_contours, + FT_UShort instruction_len, + FT_Bool have_overlap, + FT_Byte* dst, + FT_ULong dst_size, + FT_ULong* glyph_size ) + { + FT_UInt flag_offset = 10 + ( 2 * n_contours ) + 2 + instruction_len; + FT_Byte last_flag = 0xFFU; + FT_Byte repeat_count = 0; + FT_Int last_x = 0; + FT_Int last_y = 0; + FT_UInt x_bytes = 0; + FT_UInt y_bytes = 0; + FT_UInt xy_bytes; + FT_UInt i; + FT_UInt x_offset; + FT_UInt y_offset; + FT_Byte* pointer; + + + for ( i = 0; i < n_points; ++i ) + { + const WOFF2_PointRec point = points[i]; + + FT_Byte flag = point.on_curve ? GLYF_ON_CURVE : 0; + FT_Int dx = point.x - last_x; + FT_Int dy = point.y - last_y; + + + if ( i == 0 && have_overlap ) + flag |= GLYF_OVERLAP_SIMPLE; + + if ( dx == 0 ) + flag |= GLYF_THIS_X_IS_SAME; + else if ( dx > -256 && dx < 256 ) + { + flag |= GLYF_X_SHORT | ( dx > 0 ? GLYF_THIS_X_IS_SAME : 0 ); + x_bytes += 1; + } + else + x_bytes += 2; + + if ( dy == 0 ) + flag |= GLYF_THIS_Y_IS_SAME; + else if ( dy > -256 && dy < 256 ) + { + flag |= GLYF_Y_SHORT | ( dy > 0 ? GLYF_THIS_Y_IS_SAME : 0 ); + y_bytes += 1; + } + else + y_bytes += 2; + + if ( flag == last_flag && repeat_count != 255 ) + { + dst[flag_offset - 1] |= GLYF_REPEAT; + repeat_count++; + } + else + { + if ( repeat_count != 0 ) + { + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = repeat_count; + } + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = flag; + repeat_count = 0; + } + + last_x = point.x; + last_y = point.y; + last_flag = flag; + } + + if ( repeat_count != 0 ) + { + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = repeat_count; + } + + xy_bytes = x_bytes + y_bytes; + if ( xy_bytes < x_bytes || + flag_offset + xy_bytes < flag_offset || + flag_offset + xy_bytes > dst_size ) + return FT_THROW( Invalid_Table ); + + x_offset = flag_offset; + y_offset = flag_offset + x_bytes; + last_x = 0; + last_y = 0; + + for ( i = 0; i < n_points; ++i ) + { + FT_Int dx = points[i].x - last_x; + FT_Int dy = points[i].y - last_y; + + + if ( dx == 0 ) + ; + else if ( dx > -256 && dx < 256 ) + dst[x_offset++] = (FT_Byte)FT_ABS( dx ); + else + { + pointer = dst + x_offset; + WRITE_SHORT( pointer, dx ); + x_offset += 2; + } + + last_x += dx; + + if ( dy == 0 ) + ; + else if ( dy > -256 && dy < 256 ) + dst[y_offset++] = (FT_Byte)FT_ABS( dy ); + else + { + pointer = dst + y_offset; + WRITE_SHORT( pointer, dy ); + y_offset += 2; + } + + last_y += dy; + } + + *glyph_size = y_offset; + return FT_Err_Ok; + } + + + static void + compute_bbox( FT_ULong n_points, + const WOFF2_Point points, + FT_Byte* dst, + FT_UShort* src_x_min ) + { + FT_Int x_min = 0; + FT_Int y_min = 0; + FT_Int x_max = 0; + FT_Int y_max = 0; + + FT_UInt i; + + FT_ULong offset; + FT_Byte* pointer; + + + if ( n_points > 0 ) + { + x_min = points[0].x; + y_min = points[0].y; + x_max = points[0].x; + y_max = points[0].y; + } + + for ( i = 1; i < n_points; ++i ) + { + FT_Int x = points[i].x; + FT_Int y = points[i].y; + + + x_min = FT_MIN( x, x_min ); + y_min = FT_MIN( y, y_min ); + x_max = FT_MAX( x, x_max ); + y_max = FT_MAX( y, y_max ); + } + + /* Write values to `glyf' record. */ + offset = 2; + pointer = dst + offset; + + WRITE_SHORT( pointer, x_min ); + WRITE_SHORT( pointer, y_min ); + WRITE_SHORT( pointer, x_max ); + WRITE_SHORT( pointer, y_max ); + + *src_x_min = (FT_UShort)x_min; + } + + + static FT_Error + compositeGlyph_size( FT_Stream stream, + FT_ULong offset, + FT_ULong* size, + FT_Bool* have_instructions ) + { + FT_Error error = FT_Err_Ok; + FT_ULong start_offset = offset; + FT_Bool we_have_inst = FALSE; + FT_UShort flags = FLAG_MORE_COMPONENTS; + + + if ( FT_STREAM_SEEK( start_offset ) ) + goto Exit; + while ( flags & FLAG_MORE_COMPONENTS ) + { + FT_ULong arg_size; + + + if ( FT_READ_USHORT( flags ) ) + goto Exit; + we_have_inst |= ( flags & FLAG_WE_HAVE_INSTRUCTIONS ) != 0; + /* glyph index */ + arg_size = 2; + if ( flags & FLAG_ARG_1_AND_2_ARE_WORDS ) + arg_size += 4; + else + arg_size += 2; + + if ( flags & FLAG_WE_HAVE_A_SCALE ) + arg_size += 2; + else if ( flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE ) + arg_size += 4; + else if ( flags & FLAG_WE_HAVE_A_TWO_BY_TWO ) + arg_size += 8; + + if ( FT_STREAM_SKIP( arg_size ) ) + goto Exit; + } + + *size = FT_STREAM_POS() - start_offset; + *have_instructions = we_have_inst; + + Exit: + return error; + } + + + /* Store loca values (provided by `reconstruct_glyf') to output stream. */ + static FT_Error + store_loca( FT_ULong* loca_values, + FT_ULong loca_values_size, + FT_UShort index_format, + FT_ULong* checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte* loca_buf = NULL; + FT_Byte* dst = NULL; + + FT_UInt i = 0; + FT_ULong loca_buf_size; + + const FT_ULong offset_size = index_format ? 4 : 2; + + + if ( ( loca_values_size << 2 ) >> 2 != loca_values_size ) + goto Fail; + + loca_buf_size = loca_values_size * offset_size; + if ( FT_QALLOC( loca_buf, loca_buf_size ) ) + goto Fail; + + dst = loca_buf; + for ( i = 0; i < loca_values_size; i++ ) + { + FT_ULong value = loca_values[i]; + + + if ( index_format ) + WRITE_ULONG( dst, value ); + else + WRITE_USHORT( dst, ( value >> 1 ) ); + } + + *checksum = compute_ULong_sum( loca_buf, loca_buf_size ); + /* Write `loca' table to sfnt buffer. */ + if ( WRITE_SFNT_BUF( loca_buf, loca_buf_size ) ) + goto Fail; + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( loca_buf ); + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + FT_FREE( loca_buf ); + + return error; + } + + + static FT_Error + reconstruct_glyf( FT_Stream stream, + FT_ULong* glyf_checksum, + FT_ULong* loca_checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + WOFF2_Info info, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + + /* current position in stream */ + const FT_ULong pos = FT_STREAM_POS(); + + FT_UInt num_substreams = 7; + + FT_UShort option_flags; + FT_UShort num_glyphs; + FT_UShort index_format; + FT_ULong expected_loca_length; + FT_UInt offset; + FT_UInt i; + FT_ULong points_size; + FT_ULong glyph_buf_size; + FT_ULong bbox_bitmap_offset; + FT_ULong bbox_bitmap_length; + FT_ULong overlap_bitmap_offset = 0; + FT_ULong overlap_bitmap_length = 0; + + const FT_ULong glyf_start = *out_offset; + FT_ULong dest_offset = *out_offset; + + WOFF2_Substream substreams = NULL; + + FT_ULong* loca_values = NULL; + FT_UShort* n_points_arr = NULL; + FT_Byte* glyph_buf = NULL; + WOFF2_Point points = NULL; + + + if ( FT_QNEW_ARRAY( substreams, num_substreams ) ) + goto Fail; + + if ( FT_STREAM_SKIP( 2 ) ) + goto Fail; + if ( FT_READ_USHORT( option_flags ) ) + goto Fail; + if ( FT_READ_USHORT( num_glyphs ) ) + goto Fail; + if ( FT_READ_USHORT( index_format ) ) + goto Fail; + + FT_TRACE4(( "option_flags = %u; num_glyphs = %u; index_format = %u\n", + option_flags, num_glyphs, index_format )); + + info->num_glyphs = num_glyphs; + + /* Calculate expected length of loca and compare. */ + /* See https://www.w3.org/TR/WOFF2/#conform-mustRejectLoca */ + /* index_format = 0 => Short version `loca'. */ + /* index_format = 1 => Long version `loca'. */ + expected_loca_length = ( index_format ? 4 : 2 ) * + ( (FT_ULong)num_glyphs + 1 ); + if ( info->loca_table->dst_length != expected_loca_length ) + goto Fail; + + offset = 2 + 2 + 2 + 2 + ( num_substreams * 4 ); + if ( offset > info->glyf_table->TransformLength ) + goto Fail; + + for ( i = 0; i < num_substreams; ++i ) + { + FT_ULong substream_size; + + + if ( FT_READ_ULONG( substream_size ) ) + goto Fail; + if ( substream_size > info->glyf_table->TransformLength - offset ) + goto Fail; + + substreams[i].start = pos + offset; + substreams[i].offset = pos + offset; + substreams[i].size = substream_size; + + FT_TRACE5(( " Substream %d: offset = %lu; size = %lu;\n", + i, substreams[i].offset, substreams[i].size )); + offset += substream_size; + } + + if ( option_flags & HAVE_OVERLAP_SIMPLE_BITMAP ) + { + /* Size of overlapBitmap = floor((numGlyphs + 7) / 8) */ + overlap_bitmap_length = ( num_glyphs + 7U ) >> 3; + if ( overlap_bitmap_length > info->glyf_table->TransformLength - offset ) + goto Fail; + + overlap_bitmap_offset = pos + offset; + + FT_TRACE5(( " Overlap bitmap: offset = %lu; size = %lu;\n", + overlap_bitmap_offset, overlap_bitmap_length )); + offset += overlap_bitmap_length; + } + + if ( FT_QNEW_ARRAY( loca_values, num_glyphs + 1 ) ) + goto Fail; + + points_size = 0; + bbox_bitmap_offset = substreams[BBOX_STREAM].offset; + + /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */ + bbox_bitmap_length = ( ( num_glyphs + 31U ) >> 5 ) << 2; + /* bboxStreamSize is the combined size of bboxBitmap and bboxStream. */ + substreams[BBOX_STREAM].offset += bbox_bitmap_length; + + glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF; + if ( FT_QALLOC( glyph_buf, glyph_buf_size ) ) + goto Fail; + + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) + goto Fail; + + for ( i = 0; i < num_glyphs; ++i ) + { + FT_ULong glyph_size = 0; + FT_UShort n_contours = 0; + FT_Bool have_bbox = FALSE; + FT_Byte bbox_bitmap; + FT_ULong bbox_offset; + FT_UShort x_min = 0; + + + /* Set `have_bbox'. */ + bbox_offset = bbox_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( bbox_offset ) || + FT_READ_BYTE( bbox_bitmap ) ) + goto Fail; + if ( bbox_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_bbox = TRUE; + + /* Read value from `nContourStream'. */ + if ( FT_STREAM_SEEK( substreams[N_CONTOUR_STREAM].offset ) || + FT_READ_USHORT( n_contours ) ) + goto Fail; + substreams[N_CONTOUR_STREAM].offset += 2; + + if ( n_contours == 0xffff ) + { + /* composite glyph */ + FT_Bool have_instructions = FALSE; + FT_UShort instruction_size = 0; + FT_ULong composite_size = 0; + FT_ULong size_needed; + FT_Byte* pointer = NULL; + + + /* Composite glyphs must have explicit bbox. */ + if ( !have_bbox ) + goto Fail; + + if ( compositeGlyph_size( stream, + substreams[COMPOSITE_STREAM].offset, + &composite_size, + &have_instructions) ) + goto Fail; + + if ( have_instructions ) + { + if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || + READ_255USHORT( instruction_size ) ) + goto Fail; + substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); + } + + size_needed = 12 + composite_size + instruction_size; + if ( glyph_buf_size < size_needed ) + { + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) + goto Fail; + glyph_buf_size = size_needed; + } + + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, n_contours ); + glyph_size += 2; + + /* Read x_min for current glyph. */ + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_READ_USHORT( x_min ) ) + goto Fail; + /* No increment here because we read again. */ + + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) + goto Fail; + + substreams[BBOX_STREAM].offset += 8; + glyph_size += 8; + + if ( FT_STREAM_SEEK( substreams[COMPOSITE_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, composite_size ) ) + goto Fail; + + substreams[COMPOSITE_STREAM].offset += composite_size; + glyph_size += composite_size; + + if ( have_instructions ) + { + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, instruction_size ); + glyph_size += 2; + + if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) + goto Fail; + + substreams[INSTRUCTION_STREAM].offset += instruction_size; + glyph_size += instruction_size; + } + } + else if ( n_contours > 0 ) + { + /* simple glyph */ + FT_ULong total_n_points = 0; + FT_UShort n_points_contour; + FT_UInt j; + FT_ULong flag_size; + FT_ULong triplet_size; + FT_ULong triplet_bytes_used; + FT_Bool have_overlap = FALSE; + FT_Byte overlap_bitmap; + FT_ULong overlap_offset; + FT_Byte* flags_buf = NULL; + FT_Byte* triplet_buf = NULL; + FT_UShort instruction_size; + FT_ULong size_needed; + FT_Int end_point; + FT_UInt contour_ix; + + FT_Byte* pointer = NULL; + + + /* Set `have_overlap`. */ + if ( overlap_bitmap_offset ) + { + overlap_offset = overlap_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( overlap_offset ) || + FT_READ_BYTE( overlap_bitmap ) ) + goto Fail; + if ( overlap_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_overlap = TRUE; + } + + if ( FT_QNEW_ARRAY( n_points_arr, n_contours ) ) + goto Fail; + + if ( FT_STREAM_SEEK( substreams[N_POINTS_STREAM].offset ) ) + goto Fail; + + for ( j = 0; j < n_contours; ++j ) + { + if ( READ_255USHORT( n_points_contour ) ) + goto Fail; + n_points_arr[j] = n_points_contour; + /* Prevent negative/overflow. */ + if ( total_n_points + n_points_contour < total_n_points ) + goto Fail; + total_n_points += n_points_contour; + } + substreams[N_POINTS_STREAM].offset = FT_STREAM_POS(); + + flag_size = total_n_points; + if ( flag_size > substreams[FLAG_STREAM].size ) + goto Fail; + + flags_buf = stream->base + substreams[FLAG_STREAM].offset; + triplet_buf = stream->base + substreams[GLYPH_STREAM].offset; + + if ( substreams[GLYPH_STREAM].size < + ( substreams[GLYPH_STREAM].offset - + substreams[GLYPH_STREAM].start ) ) + goto Fail; + + triplet_size = substreams[GLYPH_STREAM].size - + ( substreams[GLYPH_STREAM].offset - + substreams[GLYPH_STREAM].start ); + triplet_bytes_used = 0; + + /* Create array to store point information. */ + points_size = total_n_points; + if ( FT_QNEW_ARRAY( points, points_size ) ) + goto Fail; + + if ( triplet_decode( flags_buf, + triplet_buf, + triplet_size, + total_n_points, + points, + &triplet_bytes_used ) ) + goto Fail; + + substreams[FLAG_STREAM].offset += flag_size; + substreams[GLYPH_STREAM].offset += triplet_bytes_used; + + if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || + READ_255USHORT( instruction_size ) ) + goto Fail; + + substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); + + if ( total_n_points >= ( 1 << 27 ) ) + goto Fail; + + size_needed = 12 + + ( 2 * n_contours ) + + ( 5 * total_n_points ) + + instruction_size; + if ( glyph_buf_size < size_needed ) + { + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) + goto Fail; + glyph_buf_size = size_needed; + } + + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, n_contours ); + glyph_size += 2; + + if ( have_bbox ) + { + /* Read x_min for current glyph. */ + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_READ_USHORT( x_min ) ) + goto Fail; + /* No increment here because we read again. */ + + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) + goto Fail; + substreams[BBOX_STREAM].offset += 8; + } + else + compute_bbox( total_n_points, points, glyph_buf, &x_min ); + + glyph_size = CONTOUR_OFFSET_END_POINT; + + pointer = glyph_buf + glyph_size; + end_point = -1; + + for ( contour_ix = 0; contour_ix < n_contours; ++contour_ix ) + { + end_point += n_points_arr[contour_ix]; + if ( end_point >= 65536 ) + goto Fail; + + WRITE_SHORT( pointer, end_point ); + glyph_size += 2; + } + + WRITE_USHORT( pointer, instruction_size ); + glyph_size += 2; + + if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) + goto Fail; + + substreams[INSTRUCTION_STREAM].offset += instruction_size; + glyph_size += instruction_size; + + if ( store_points( total_n_points, + points, + n_contours, + instruction_size, + have_overlap, + glyph_buf, + glyph_buf_size, + &glyph_size ) ) + goto Fail; + + FT_FREE( points ); + FT_FREE( n_points_arr ); + } + else + { + /* Empty glyph. */ + /* Must not have a bbox. */ + if ( have_bbox ) + { + FT_ERROR(( "Empty glyph has a bbox.\n" )); + goto Fail; + } + } + + loca_values[i] = dest_offset - glyf_start; + + if ( WRITE_SFNT_BUF( glyph_buf, glyph_size ) ) + goto Fail; + + if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) + goto Fail; + + *glyf_checksum += compute_ULong_sum( glyph_buf, glyph_size ); + + /* Store x_mins, may be required to reconstruct `hmtx'. */ + info->x_mins[i] = (FT_Short)x_min; + } + + info->glyf_table->dst_length = dest_offset - info->glyf_table->dst_offset; + info->loca_table->dst_offset = dest_offset; + + /* `loca[n]' will be equal to the length of the `glyf' table. */ + loca_values[num_glyphs] = info->glyf_table->dst_length; + + if ( store_loca( loca_values, + num_glyphs + 1, + index_format, + loca_checksum, + &sfnt, + sfnt_size, + &dest_offset, + memory ) ) + goto Fail; + + info->loca_table->dst_length = dest_offset - info->loca_table->dst_offset; + + FT_TRACE4(( " loca table info:\n" )); + FT_TRACE4(( " dst_offset = %lu\n", info->loca_table->dst_offset )); + FT_TRACE4(( " dst_length = %lu\n", info->loca_table->dst_length )); + FT_TRACE4(( " checksum = %09lx\n", *loca_checksum )); + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( substreams ); + FT_FREE( loca_values ); + FT_FREE( n_points_arr ); + FT_FREE( glyph_buf ); + FT_FREE( points ); + + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + + FT_FREE( substreams ); + FT_FREE( loca_values ); + FT_FREE( n_points_arr ); + FT_FREE( glyph_buf ); + FT_FREE( points ); + + return error; + } + + + /* Get `x_mins' for untransformed `glyf' table. */ + static FT_Error + get_x_mins( FT_Stream stream, + WOFF2_Table* tables, + FT_UShort num_tables, + WOFF2_Info info, + FT_Memory memory ) + { + FT_UShort num_glyphs; + FT_UShort index_format; + FT_ULong glyf_offset; + FT_UShort glyf_offset_short; + FT_ULong loca_offset; + FT_Int i; + FT_Error error = FT_Err_Ok; + FT_ULong offset_size; + + /* At this point of time those tables might not have been read yet. */ + const WOFF2_Table maxp_table = find_table( tables, num_tables, + TTAG_maxp ); + const WOFF2_Table head_table = find_table( tables, num_tables, + TTAG_head ); + + + if ( !maxp_table ) + { + FT_ERROR(( "`maxp' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + if ( !head_table ) + { + FT_ERROR(( "`head' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + if ( !info->loca_table ) + { + FT_ERROR(( "`loca' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Read `numGlyphs' field from `maxp' table. */ + if ( FT_STREAM_SEEK( maxp_table->src_offset ) || FT_STREAM_SKIP( 8 ) ) + return error; + + if ( FT_READ_USHORT( num_glyphs ) ) + return error; + + info->num_glyphs = num_glyphs; + + /* Read `indexToLocFormat' field from `head' table. */ + if ( FT_STREAM_SEEK( head_table->src_offset ) || + FT_STREAM_SKIP( 50 ) ) + return error; + + if ( FT_READ_USHORT( index_format ) ) + return error; + + offset_size = index_format ? 4 : 2; + + /* Create `x_mins' array. */ + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) + return error; + + loca_offset = info->loca_table->src_offset; + + for ( i = 0; i < num_glyphs; ++i ) + { + if ( FT_STREAM_SEEK( loca_offset ) ) + return error; + + loca_offset += offset_size; + + if ( index_format ) + { + if ( FT_READ_ULONG( glyf_offset ) ) + return error; + } + else + { + if ( FT_READ_USHORT( glyf_offset_short ) ) + return error; + + glyf_offset = (FT_ULong)( glyf_offset_short ); + glyf_offset = glyf_offset << 1; + } + + glyf_offset += info->glyf_table->src_offset; + + if ( FT_STREAM_SEEK( glyf_offset ) || FT_STREAM_SKIP( 2 ) ) + return error; + + if ( FT_READ_SHORT( info->x_mins[i] ) ) + return error; + } + + return error; + } + + + static FT_Error + reconstruct_hmtx( FT_Stream stream, + FT_UShort num_glyphs, + FT_UShort num_hmetrics, + FT_Short* x_mins, + FT_ULong* checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte hmtx_flags; + FT_Bool has_proportional_lsbs, has_monospace_lsbs; + FT_ULong hmtx_table_size; + FT_Int i; + + FT_UShort* advance_widths = NULL; + FT_Short* lsbs = NULL; + FT_Byte* hmtx_table = NULL; + FT_Byte* dst = NULL; + + + if ( FT_READ_BYTE( hmtx_flags ) ) + goto Fail; + + has_proportional_lsbs = ( hmtx_flags & 1 ) == 0; + has_monospace_lsbs = ( hmtx_flags & 2 ) == 0; + + /* Bits 2-7 are reserved and MUST be zero. */ + if ( ( hmtx_flags & 0xFC ) != 0 ) + goto Fail; + + /* Are you REALLY transformed? */ + if ( has_proportional_lsbs && has_monospace_lsbs ) + goto Fail; + + /* Cannot have a transformed `hmtx' without `glyf'. */ + if ( ( num_hmetrics > num_glyphs ) || + ( num_hmetrics < 1 ) ) + goto Fail; + + /* Must have at least one entry. */ + if ( num_hmetrics < 1 ) + goto Fail; + + if ( FT_QNEW_ARRAY( advance_widths, num_hmetrics ) || + FT_QNEW_ARRAY( lsbs, num_glyphs ) ) + goto Fail; + + /* Read `advanceWidth' stream. Always present. */ + for ( i = 0; i < num_hmetrics; i++ ) + { + FT_UShort advance_width; + + + if ( FT_READ_USHORT( advance_width ) ) + goto Fail; + + advance_widths[i] = advance_width; + } + + /* lsb values for proportional glyphs. */ + for ( i = 0; i < num_hmetrics; i++ ) + { + FT_Short lsb; + + + if ( has_proportional_lsbs ) + { + if ( FT_READ_SHORT( lsb ) ) + goto Fail; + } + else + lsb = x_mins[i]; + + lsbs[i] = lsb; + } + + /* lsb values for monospaced glyphs. */ + for ( i = num_hmetrics; i < num_glyphs; i++ ) + { + FT_Short lsb; + + + if ( has_monospace_lsbs ) + { + if ( FT_READ_SHORT( lsb ) ) + goto Fail; + } + else + lsb = x_mins[i]; + + lsbs[i] = lsb; + } + + /* Build the hmtx table. */ + hmtx_table_size = 2 * num_hmetrics + 2 * num_glyphs; + if ( FT_QALLOC( hmtx_table, hmtx_table_size ) ) + goto Fail; + + dst = hmtx_table; + FT_TRACE6(( "hmtx values: \n" )); + for ( i = 0; i < num_glyphs; i++ ) + { + if ( i < num_hmetrics ) + { + WRITE_SHORT( dst, advance_widths[i] ); + FT_TRACE6(( "%d ", advance_widths[i] )); + } + + WRITE_SHORT( dst, lsbs[i] ); + FT_TRACE6(( "%d ", lsbs[i] )); + } + FT_TRACE6(( "\n" )); + + *checksum = compute_ULong_sum( hmtx_table, hmtx_table_size ); + /* Write `hmtx' table to sfnt buffer. */ + if ( WRITE_SFNT_BUF( hmtx_table, hmtx_table_size ) ) + goto Fail; + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( advance_widths ); + FT_FREE( lsbs ); + FT_FREE( hmtx_table ); + + return error; + + Fail: + FT_FREE( advance_widths ); + FT_FREE( lsbs ); + FT_FREE( hmtx_table ); + + if ( !error ) + error = FT_THROW( Invalid_Table ); + + return error; + } + + + static FT_Error + reconstruct_font( FT_Byte* transformed_buf, + FT_ULong transformed_buf_size, + WOFF2_Table* indices, + WOFF2_Header woff2, + WOFF2_Info info, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_Memory memory ) + { + /* Memory management of `transformed_buf' is handled by the caller. */ + + FT_Error error = FT_Err_Ok; + FT_Stream stream = NULL; + FT_Byte* buf_cursor = NULL; + FT_Byte table_entry[16]; + + /* We are reallocating memory for `sfnt', so its pointer may change. */ + FT_Byte* sfnt = *sfnt_bytes; + + FT_UShort num_tables = woff2->num_tables; + FT_ULong dest_offset = 12 + num_tables * 16UL; + + FT_ULong checksum = 0; + FT_ULong loca_checksum = 0; + FT_Int nn = 0; + FT_UShort num_hmetrics = 0; + FT_ULong font_checksum = info->header_checksum; + FT_Bool is_glyf_xform = FALSE; + + FT_ULong table_entry_offset = 12; + + + /* A few table checks before reconstruction. */ + /* `glyf' must be present with `loca'. */ + info->glyf_table = find_table( indices, num_tables, TTAG_glyf ); + info->loca_table = find_table( indices, num_tables, TTAG_loca ); + + if ( ( info->glyf_table == NULL ) ^ ( info->loca_table == NULL ) ) + { + FT_ERROR(( "One of `glyf'/`loca' tables missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Both `glyf' and `loca' must have same transformation. */ + if ( info->glyf_table != NULL ) + { + if ( ( info->glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) != + ( info->loca_table->flags & WOFF2_FLAGS_TRANSFORM ) ) + { + FT_ERROR(( "Transformation mismatch" + " between `glyf' and `loca' table." )); + return FT_THROW( Invalid_Table ); + } + } + + /* Create a stream for the uncompressed buffer. */ + if ( FT_NEW( stream ) ) + goto Fail; + FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size ); + + FT_ASSERT( FT_STREAM_POS() == 0 ); + + /* Reconstruct/copy tables to output stream. */ + for ( nn = 0; nn < num_tables; nn++ ) + { + WOFF2_TableRec table = *( indices[nn] ); + + + FT_TRACE3(( "Seeking to %ld with table size %ld.\n", + table.src_offset, table.src_length )); + FT_TRACE3(( "Table tag: %c%c%c%c.\n", + (FT_Char)( table.Tag >> 24 ), + (FT_Char)( table.Tag >> 16 ), + (FT_Char)( table.Tag >> 8 ), + (FT_Char)( table.Tag ) )); + + if ( FT_STREAM_SEEK( table.src_offset ) ) + goto Fail; + + if ( table.src_offset + table.src_length > transformed_buf_size ) + goto Fail; + + /* Get stream size for fields of `hmtx' table. */ + if ( table.Tag == TTAG_hhea ) + { + if ( read_num_hmetrics( stream, &num_hmetrics ) ) + goto Fail; + } + + info->num_hmetrics = num_hmetrics; + + checksum = 0; + if ( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM ) + { + /* Check whether `head' is at least 12 bytes. */ + if ( table.Tag == TTAG_head ) + { + if ( table.src_length < 12 ) + goto Fail; + + buf_cursor = transformed_buf + table.src_offset + 8; + /* Set checkSumAdjustment = 0 */ + WRITE_ULONG( buf_cursor, 0 ); + } + + table.dst_offset = dest_offset; + + checksum = compute_ULong_sum( transformed_buf + table.src_offset, + table.src_length ); + FT_TRACE4(( "Checksum = %09lx.\n", checksum )); + + if ( WRITE_SFNT_BUF( transformed_buf + table.src_offset, + table.src_length ) ) + goto Fail; + } + else + { + FT_TRACE3(( "This table is transformed.\n" )); + + if ( table.Tag == TTAG_glyf ) + { + is_glyf_xform = TRUE; + table.dst_offset = dest_offset; + + if ( reconstruct_glyf( stream, + &checksum, + &loca_checksum, + &sfnt, + sfnt_size, + &dest_offset, + info, + memory ) ) + goto Fail; + + FT_TRACE4(( "Checksum = %09lx.\n", checksum )); + } + + else if ( table.Tag == TTAG_loca ) + checksum = loca_checksum; + + else if ( table.Tag == TTAG_hmtx ) + { + /* If glyf is not transformed and hmtx is, handle separately. */ + if ( !is_glyf_xform ) + { + if ( get_x_mins( stream, indices, num_tables, info, memory ) ) + goto Fail; + } + + table.dst_offset = dest_offset; + + if ( reconstruct_hmtx( stream, + info->num_glyphs, + info->num_hmetrics, + info->x_mins, + &checksum, + &sfnt, + sfnt_size, + &dest_offset, + memory ) ) + goto Fail; + } + else + { + /* Unknown transform. */ + FT_ERROR(( "Unknown table transform.\n" )); + goto Fail; + } + } + + font_checksum += checksum; + + buf_cursor = &table_entry[0]; + WRITE_ULONG( buf_cursor, table.Tag ); + WRITE_ULONG( buf_cursor, checksum ); + WRITE_ULONG( buf_cursor, table.dst_offset ); + WRITE_ULONG( buf_cursor, table.dst_length ); + + WRITE_SFNT_BUF_AT( table_entry_offset, table_entry, 16 ); + + /* Update checksum. */ + font_checksum += compute_ULong_sum( table_entry, 16 ); + + if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) + goto Fail; + + /* Sanity check. */ + if ( (FT_ULong)( table.dst_offset + table.dst_length ) > dest_offset ) + { + FT_ERROR(( "Table was partially written.\n" )); + goto Fail; + } + } + + /* Update `head' checkSumAdjustment. */ + info->head_table = find_table( indices, num_tables, TTAG_head ); + if ( !info->head_table ) + { + FT_ERROR(( "`head' table is missing.\n" )); + goto Fail; + } + + if ( info->head_table->dst_length < 12 ) + goto Fail; + + buf_cursor = sfnt + info->head_table->dst_offset + 8; + font_checksum = 0xB1B0AFBA - font_checksum; + + WRITE_ULONG( buf_cursor, font_checksum ); + + FT_TRACE2(( "Final checksum = %09lx.\n", font_checksum )); + + woff2->actual_sfnt_size = dest_offset; + + /* Set pointer of sfnt stream to its correct value. */ + *sfnt_bytes = sfnt; + + FT_Stream_Close( stream ); + FT_FREE( stream ); + + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + /* Set pointer of sfnt stream to its correct value. */ + *sfnt_bytes = sfnt; + + FT_Stream_Close( stream ); + FT_FREE( stream ); + + return error; + } + + + /* Replace `face->root.stream' with a stream containing the extracted */ + /* SFNT of a WOFF2 font. */ + + FT_LOCAL_DEF( FT_Error ) + woff2_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_instance_index, + FT_Long* num_faces ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + FT_Int face_index; + + WOFF2_HeaderRec woff2; + WOFF2_InfoRec info = { 0, 0, 0, NULL, NULL, NULL, NULL }; + WOFF2_Table tables = NULL; + WOFF2_Table* indices = NULL; + WOFF2_Table* temp_indices = NULL; + WOFF2_Table last_table; + + FT_Int nn; + FT_ULong j; + FT_ULong flags; + FT_UShort xform_version; + FT_ULong src_offset = 0; + + FT_UInt glyf_index; + FT_UInt loca_index; + FT_UInt32 file_offset; + + FT_Byte* sfnt = NULL; + FT_Stream sfnt_stream = NULL; + FT_Byte* sfnt_header; + FT_ULong sfnt_size; + + FT_Byte* uncompressed_buf = NULL; + + static const FT_Frame_Field woff2_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WOFF2_HeaderRec + + FT_FRAME_START( 48 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_ULONG ( flavor ), + FT_FRAME_ULONG ( length ), + FT_FRAME_USHORT ( num_tables ), + FT_FRAME_SKIP_BYTES( 2 ), + FT_FRAME_ULONG ( totalSfntSize ), + FT_FRAME_ULONG ( totalCompressedSize ), + FT_FRAME_SKIP_BYTES( 2 * 2 ), + FT_FRAME_ULONG ( metaOffset ), + FT_FRAME_ULONG ( metaLength ), + FT_FRAME_ULONG ( metaOrigLength ), + FT_FRAME_ULONG ( privOffset ), + FT_FRAME_ULONG ( privLength ), + FT_FRAME_END + }; + + + FT_ASSERT( stream == face->root.stream ); + FT_ASSERT( FT_STREAM_POS() == 0 ); + + face_index = FT_ABS( *face_instance_index ) & 0xFFFF; + + /* Read WOFF2 Header. */ + if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) ) + return error; + + FT_TRACE4(( "signature -> 0x%lX\n", woff2.signature )); + FT_TRACE2(( "flavor -> 0x%08lx\n", woff2.flavor )); + FT_TRACE4(( "length -> %lu\n", woff2.length )); + FT_TRACE2(( "num_tables -> %hu\n", woff2.num_tables )); + FT_TRACE4(( "totalSfntSize -> %lu\n", woff2.totalSfntSize )); + FT_TRACE4(( "metaOffset -> %lu\n", woff2.metaOffset )); + FT_TRACE4(( "metaLength -> %lu\n", woff2.metaLength )); + FT_TRACE4(( "privOffset -> %lu\n", woff2.privOffset )); + FT_TRACE4(( "privLength -> %lu\n", woff2.privLength )); + + /* Make sure we don't recurse back here. */ + if ( woff2.flavor == TTAG_wOF2 ) + return FT_THROW( Invalid_Table ); + + /* Miscellaneous checks. */ + if ( woff2.length != stream->size || + woff2.num_tables == 0 || + 48 + woff2.num_tables * 20UL >= woff2.length || + ( woff2.metaOffset == 0 && ( woff2.metaLength != 0 || + woff2.metaOrigLength != 0 ) ) || + ( woff2.metaLength != 0 && woff2.metaOrigLength == 0 ) || + ( woff2.metaOffset >= woff2.length ) || + ( woff2.length - woff2.metaOffset < woff2.metaLength ) || + ( woff2.privOffset == 0 && woff2.privLength != 0 ) || + ( woff2.privOffset >= woff2.length ) || + ( woff2.length - woff2.privOffset < woff2.privLength ) ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 header\n" )); + return FT_THROW( Invalid_Table ); + } + + FT_TRACE2(( "woff2_open_font: WOFF2 Header is valid.\n" )); + + woff2.ttc_fonts = NULL; + + /* Read table directory. */ + if ( FT_QNEW_ARRAY( tables, woff2.num_tables ) || + FT_QNEW_ARRAY( indices, woff2.num_tables ) ) + goto Exit; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag flags transform origLen transformLen offset\n" )); + FT_TRACE2(( " -----------------------------------------------------------\n" )); + /* " XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX" */ + + for ( nn = 0; nn < woff2.num_tables; nn++ ) + { + WOFF2_Table table = tables + nn; + + + if ( FT_READ_BYTE( table->FlagByte ) ) + goto Exit; + + if ( ( table->FlagByte & 0x3f ) == 0x3f ) + { + if ( FT_READ_ULONG( table->Tag ) ) + goto Exit; + } + else + { + table->Tag = woff2_known_tags( table->FlagByte & 0x3f ); + if ( !table->Tag ) + { + FT_ERROR(( "woff2_open_font: Unknown table tag." )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + flags = 0; + xform_version = ( table->FlagByte >> 6 ) & 0x03; + + /* 0 means xform for glyph/loca, non-0 for others. */ + if ( table->Tag == TTAG_glyf || table->Tag == TTAG_loca ) + { + if ( xform_version == 0 ) + flags |= WOFF2_FLAGS_TRANSFORM; + } + else if ( xform_version != 0 ) + flags |= WOFF2_FLAGS_TRANSFORM; + + flags |= xform_version; + + if ( READ_BASE128( table->dst_length ) ) + goto Exit; + + table->TransformLength = table->dst_length; + + if ( ( flags & WOFF2_FLAGS_TRANSFORM ) != 0 ) + { + if ( READ_BASE128( table->TransformLength ) ) + goto Exit; + + if ( table->Tag == TTAG_loca && table->TransformLength ) + { + FT_ERROR(( "woff2_open_font: Invalid loca `transformLength'.\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + if ( src_offset + table->TransformLength < src_offset ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 table directory.\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + table->flags = flags; + table->src_offset = src_offset; + table->src_length = table->TransformLength; + src_offset += table->TransformLength; + table->dst_offset = 0; + + FT_TRACE2(( " %c%c%c%c %08d %08d %08ld %08ld %08ld\n", + (FT_Char)( table->Tag >> 24 ), + (FT_Char)( table->Tag >> 16 ), + (FT_Char)( table->Tag >> 8 ), + (FT_Char)( table->Tag ), + table->FlagByte & 0x3f, + ( table->FlagByte >> 6 ) & 0x03, + table->dst_length, + table->TransformLength, + table->src_offset )); + + indices[nn] = table; + } + + /* End of last table is uncompressed size. */ + last_table = indices[woff2.num_tables - 1]; + + woff2.uncompressed_size = last_table->src_offset + + last_table->src_length; + if ( woff2.uncompressed_size < last_table->src_offset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE2(( "Table directory parsed.\n" )); + + /* Check for and read collection directory. */ + woff2.num_fonts = 1; + woff2.header_version = 0; + + if ( woff2.flavor == TTAG_ttcf ) + { + FT_TRACE2(( "Font is a TTC, reading collection directory.\n" )); + + if ( FT_READ_ULONG( woff2.header_version ) ) + goto Exit; + + if ( woff2.header_version != 0x00010000 && + woff2.header_version != 0x00020000 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( READ_255USHORT( woff2.num_fonts ) ) + goto Exit; + + if ( !woff2.num_fonts ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE4(( "Number of fonts in TTC: %d\n", woff2.num_fonts )); + + /* pre-zero pointers within in case of failure */ + if ( FT_NEW_ARRAY( woff2.ttc_fonts, woff2.num_fonts ) ) + goto Exit; + + for ( nn = 0; nn < woff2.num_fonts; nn++ ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts + nn; + + + if ( READ_255USHORT( ttc_font->num_tables ) ) + goto Exit; + if ( FT_READ_ULONG( ttc_font->flavor ) ) + goto Exit; + + if ( FT_QNEW_ARRAY( ttc_font->table_indices, ttc_font->num_tables ) ) + goto Exit; + + FT_TRACE5(( "Number of tables in font %d: %d\n", + nn, ttc_font->num_tables )); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ttc_font->num_tables ) + FT_TRACE6(( " Indices: " )); +#endif + + glyf_index = 0; + loca_index = 0; + + for ( j = 0; j < ttc_font->num_tables; j++ ) + { + FT_UShort table_index; + WOFF2_Table table; + + + if ( READ_255USHORT( table_index ) ) + goto Exit; + + FT_TRACE6(( "%hu ", table_index )); + if ( table_index >= woff2.num_tables ) + { + FT_ERROR(( "woff2_open_font: invalid table index\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + ttc_font->table_indices[j] = table_index; + + table = indices[table_index]; + if ( table->Tag == TTAG_loca ) + loca_index = table_index; + if ( table->Tag == TTAG_glyf ) + glyf_index = table_index; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ttc_font->num_tables ) + FT_TRACE6(( "\n" )); +#endif + + /* glyf and loca must be consecutive */ + if ( glyf_index > 0 || loca_index > 0 ) + { + if ( glyf_index > loca_index || + loca_index - glyf_index != 1 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + } + + /* Collection directory reading complete. */ + FT_TRACE2(( "WOFF2 collection directory is valid.\n" )); + } + else + woff2.ttc_fonts = NULL; + + woff2.compressed_offset = FT_STREAM_POS(); + file_offset = ROUND4( woff2.compressed_offset + + woff2.totalCompressedSize ); + + /* Some more checks before we start reading the tables. */ + if ( file_offset > woff2.length ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( woff2.metaOffset ) + { + if ( file_offset != woff2.metaOffset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + file_offset = ROUND4( woff2.metaOffset + woff2.metaLength ); + } + + if ( woff2.privOffset ) + { + if ( file_offset != woff2.privOffset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + file_offset = ROUND4( woff2.privOffset + woff2.privLength ); + } + + if ( file_offset != ( ROUND4( woff2.length ) ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* Validate requested face index. */ + *num_faces = woff2.num_fonts; + /* value -(N+1) requests information on index N */ + if ( *face_instance_index < 0 && face_index > 0 ) + face_index--; + + if ( face_index >= woff2.num_fonts ) + { + if ( *face_instance_index >= 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + else + face_index = 0; + } + + /* Only retain tables of the requested face in a TTC. */ + if ( woff2.header_version ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts + face_index; + + + /* Create a temporary array. */ + if ( FT_QNEW_ARRAY( temp_indices, + ttc_font->num_tables ) ) + goto Exit; + + FT_TRACE4(( "Storing tables for TTC face index %d.\n", face_index )); + for ( nn = 0; nn < ttc_font->num_tables; nn++ ) + temp_indices[nn] = indices[ttc_font->table_indices[nn]]; + + /* Resize array to required size. */ + if ( FT_QRENEW_ARRAY( indices, + woff2.num_tables, + ttc_font->num_tables ) ) + goto Exit; + + for ( nn = 0; nn < ttc_font->num_tables; nn++ ) + indices[nn] = temp_indices[nn]; + + FT_FREE( temp_indices ); + + /* Change header values. */ + woff2.flavor = ttc_font->flavor; + woff2.num_tables = ttc_font->num_tables; + } + + /* We need to allocate this much at the minimum. */ + sfnt_size = 12 + woff2.num_tables * 16UL; + /* This is what we normally expect. */ + /* Initially trust `totalSfntSize' and change later as required. */ + if ( woff2.totalSfntSize > sfnt_size ) + { + /* However, adjust the value to something reasonable. */ + + /* Factor 64 is heuristic. */ + if ( ( woff2.totalSfntSize >> 6 ) > woff2.length ) + sfnt_size = woff2.length << 6; + else + sfnt_size = woff2.totalSfntSize; + + if ( sfnt_size >= MAX_SFNT_SIZE ) + sfnt_size = MAX_SFNT_SIZE; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( sfnt_size != woff2.totalSfntSize ) + FT_TRACE4(( "adjusting estimate of uncompressed font size" + " to %lu bytes\n", + sfnt_size )); +#endif + } + + /* Write sfnt header. */ + if ( FT_QALLOC( sfnt, sfnt_size ) || + FT_NEW( sfnt_stream ) ) + goto Exit; + + sfnt_header = sfnt; + + WRITE_ULONG( sfnt_header, woff2.flavor ); + + if ( woff2.num_tables ) + { + FT_UInt searchRange, entrySelector, rangeShift, x; + + + x = woff2.num_tables; + entrySelector = 0; + while ( x ) + { + x >>= 1; + entrySelector += 1; + } + entrySelector--; + + searchRange = ( 1 << entrySelector ) * 16; + rangeShift = ( woff2.num_tables * 16 ) - searchRange; + + WRITE_USHORT( sfnt_header, woff2.num_tables ); + WRITE_USHORT( sfnt_header, searchRange ); + WRITE_USHORT( sfnt_header, entrySelector ); + WRITE_USHORT( sfnt_header, rangeShift ); + } + + info.header_checksum = compute_ULong_sum( sfnt, 12 ); + + /* Sort tables by tag. */ + ft_qsort( indices, + woff2.num_tables, + sizeof ( WOFF2_Table ), + compare_tags ); + + /* reject fonts that have multiple tables with the same tag */ + for ( nn = 1; nn < woff2.num_tables; nn++ ) + { + FT_Tag tag = indices[nn]->Tag; + + + if ( tag == indices[nn - 1]->Tag ) + { + FT_ERROR(( "woff2_open_font:" + " multiple tables with tag `%c%c%c%c'.\n", + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + if ( woff2.uncompressed_size < 1 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* We must not blindly trust `uncompressed_size` since its */ + /* value might be corrupted. If it is too large, reject the */ + /* font. In other words, we don't accept a WOFF2 font that */ + /* expands to something larger than MAX_SFNT_SIZE. If ever */ + /* necessary, this limit can be easily adjusted. */ + if ( woff2.uncompressed_size > MAX_SFNT_SIZE ) + { + FT_ERROR(( "Uncompressed font too large.\n" )); + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + /* Allocate memory for uncompressed table data. */ + if ( FT_QALLOC( uncompressed_buf, woff2.uncompressed_size ) || + FT_FRAME_ENTER( woff2.totalCompressedSize ) ) + goto Exit; + + /* Uncompress the stream. */ + error = woff2_decompress( uncompressed_buf, + woff2.uncompressed_size, + stream->cursor, + woff2.totalCompressedSize ); + + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + error = reconstruct_font( uncompressed_buf, + woff2.uncompressed_size, + indices, + &woff2, + &info, + &sfnt, + &sfnt_size, + memory ); + + if ( error ) + goto Exit; + + /* Resize `sfnt' to actual size of sfnt stream. */ + if ( woff2.actual_sfnt_size < sfnt_size ) + { + FT_TRACE5(( "Trimming sfnt stream from %lu to %lu.\n", + sfnt_size, woff2.actual_sfnt_size )); + if ( FT_QREALLOC( sfnt, + (FT_ULong)( sfnt_size ), + (FT_ULong)( woff2.actual_sfnt_size ) ) ) + goto Exit; + } + + /* `reconstruct_font' has done all the work. */ + /* Swap out stream and return. */ + FT_Stream_OpenMemory( sfnt_stream, sfnt, woff2.actual_sfnt_size ); + sfnt_stream->memory = stream->memory; + sfnt_stream->close = stream_close; + + FT_Stream_Free( + face->root.stream, + ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->root.stream = sfnt_stream; + face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + + /* Set face_index to 0 or -1. */ + if ( *face_instance_index >= 0 ) + *face_instance_index = 0; + else + *face_instance_index = -1; + + FT_TRACE2(( "woff2_open_font: SFNT synthesized.\n" )); + + Exit: + FT_FREE( tables ); + FT_FREE( indices ); + FT_FREE( uncompressed_buf ); + FT_FREE( info.x_mins ); + + if ( woff2.ttc_fonts ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts; + + + for ( nn = 0; nn < woff2.num_fonts; nn++ ) + { + FT_FREE( ttc_font->table_indices ); + ttc_font++; + } + + FT_FREE( woff2.ttc_fonts ); + } + + if ( error ) + { + FT_FREE( sfnt ); + if ( sfnt_stream ) + { + FT_Stream_Close( sfnt_stream ); + FT_FREE( sfnt_stream ); + } + } + + return error; + } + + +#undef READ_255USHORT +#undef READ_BASE128 +#undef ROUND4 +#undef WRITE_USHORT +#undef WRITE_ULONG +#undef WRITE_SHORT +#undef WRITE_SFNT_BUF +#undef WRITE_SFNT_BUF_AT + +#undef N_CONTOUR_STREAM +#undef N_POINTS_STREAM +#undef FLAG_STREAM +#undef GLYPH_STREAM +#undef COMPOSITE_STREAM +#undef BBOX_STREAM +#undef INSTRUCTION_STREAM + +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff2_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/sfwoff2.h b/vendor/freetype/src/sfnt/sfwoff2.h new file mode 100644 index 0000000..4901286 --- /dev/null +++ b/vendor/freetype/src/sfnt/sfwoff2.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * + * sfwoff2.h + * + * WOFFF2 format management (specification). + * + * Copyright (C) 2019-2023 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFWOFF2_H_ +#define SFWOFF2_H_ + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + + /* Leave the first byte open to store `flag_byte'. */ +#define WOFF2_FLAGS_TRANSFORM 1 << 8 + +#define WOFF2_SFNT_HEADER_SIZE 12 +#define WOFF2_SFNT_ENTRY_SIZE 16 + + /* Suggested maximum size for output. */ +#define WOFF2_DEFAULT_MAX_SIZE 30 * 1024 * 1024 + + /* 98% of Google Fonts have no glyph above 5k bytes. */ +#define WOFF2_DEFAULT_GLYPH_BUF 5120 + + /* Composite glyph flags. */ + /* See `CompositeGlyph.java' in `sfntly' for full definitions. */ +#define FLAG_ARG_1_AND_2_ARE_WORDS 1 << 0 +#define FLAG_WE_HAVE_A_SCALE 1 << 3 +#define FLAG_MORE_COMPONENTS 1 << 5 +#define FLAG_WE_HAVE_AN_X_AND_Y_SCALE 1 << 6 +#define FLAG_WE_HAVE_A_TWO_BY_TWO 1 << 7 +#define FLAG_WE_HAVE_INSTRUCTIONS 1 << 8 + + /* Simple glyph flags */ +#define GLYF_ON_CURVE 1 << 0 +#define GLYF_X_SHORT 1 << 1 +#define GLYF_Y_SHORT 1 << 2 +#define GLYF_REPEAT 1 << 3 +#define GLYF_THIS_X_IS_SAME 1 << 4 +#define GLYF_THIS_Y_IS_SAME 1 << 5 +#define GLYF_OVERLAP_SIMPLE 1 << 6 + + /* Other constants */ +#define CONTOUR_OFFSET_END_POINT 10 + + + FT_LOCAL( FT_Error ) + woff2_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_index, + FT_Long* num_faces ); + +#endif /* FT_CONFIG_OPTION_USE_BROTLI */ + +FT_END_HEADER + +#endif /* SFWOFF2_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttbdf.c b/vendor/freetype/src/sfnt/ttbdf.c new file mode 100644 index 0000000..536fa74 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttbdf.c @@ -0,0 +1,257 @@ +/**************************************************************************** + * + * ttbdf.c + * + * TrueType and OpenType embedded BDF properties (body). + * + * Copyright (C) 2005-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ttbdf.h" + +#include "sferrors.h" + + +#ifdef TT_CONFIG_OPTION_BDF + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttbdf + + + FT_LOCAL_DEF( void ) + tt_face_free_bdf_props( TT_Face face ) + { + TT_BDF bdf = &face->bdf; + + + if ( bdf->loaded ) + { + FT_Stream stream = FT_FACE( face )->stream; + + + if ( bdf->table ) + FT_FRAME_RELEASE( bdf->table ); + + bdf->table_end = NULL; + bdf->strings = NULL; + bdf->strings_size = 0; + } + } + + + static FT_Error + tt_face_load_bdf_props( TT_Face face, + FT_Stream stream ) + { + TT_BDF bdf = &face->bdf; + FT_ULong length; + FT_Error error; + + + FT_ZERO( bdf ); + + error = tt_face_goto_table( face, TTAG_BDF, stream, &length ); + if ( error || + length < 8 || + FT_FRAME_EXTRACT( length, bdf->table ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bdf->table_end = bdf->table + length; + + { + FT_Byte* p = bdf->table; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt num_strikes = FT_NEXT_USHORT( p ); + FT_ULong strings = FT_NEXT_ULONG ( p ); + FT_UInt count; + FT_Byte* strike; + + + if ( version != 0x0001 || + strings < 8 || + ( strings - 8 ) / 4 < num_strikes || + strings + 1 > length ) + { + goto BadTable; + } + + bdf->num_strikes = num_strikes; + bdf->strings = bdf->table + strings; + bdf->strings_size = length - strings; + + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + count * 4; + + + for ( ; count > 0; count-- ) + { + FT_UInt num_items = FT_PEEK_USHORT( p + 2 ); + + /* + * We don't need to check the value sets themselves, since this + * is done later. + */ + strike += 10 * num_items; + + p += 4; + } + + if ( strike > bdf->strings ) + goto BadTable; + } + + bdf->loaded = 1; + + Exit: + return error; + + BadTable: + FT_FRAME_RELEASE( bdf->table ); + FT_ZERO( bdf ); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_find_bdf_prop( FT_Face face, /* TT_Face */ + const char* property_name, + BDF_PropertyRec *aprop ) + { + TT_Face ttface = (TT_Face)face; + TT_BDF bdf = &ttface->bdf; + FT_Size size = FT_FACE_SIZE( face ); + FT_Error error = FT_Err_Ok; + FT_Byte* p; + FT_UInt count; + FT_Byte* strike; + FT_Offset property_len; + + + aprop->type = BDF_PROPERTY_TYPE_NONE; + + if ( bdf->loaded == 0 ) + { + error = tt_face_load_bdf_props( ttface, FT_FACE_STREAM( face ) ); + if ( error ) + goto Exit; + } + + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + 4 * count; + + error = FT_ERR( Invalid_Argument ); + + if ( !size || !property_name ) + goto Exit; + + property_len = ft_strlen( property_name ); + if ( property_len == 0 ) + goto Exit; + + for ( ; count > 0; count-- ) + { + FT_UInt _ppem = FT_NEXT_USHORT( p ); + FT_UInt _count = FT_NEXT_USHORT( p ); + + + if ( _ppem == size->metrics.y_ppem ) + { + count = _count; + goto FoundStrike; + } + + strike += 10 * _count; + } + goto Exit; + + FoundStrike: + p = strike; + for ( ; count > 0; count-- ) + { + FT_UInt type = FT_PEEK_USHORT( p + 4 ); + + + if ( ( type & 0x10 ) != 0 ) + { + FT_UInt32 name_offset = FT_PEEK_ULONG( p ); + FT_UInt32 value = FT_PEEK_ULONG( p + 6 ); + + /* be a bit paranoid for invalid entries here */ + if ( name_offset < bdf->strings_size && + property_len < bdf->strings_size - name_offset && + ft_strncmp( property_name, + (const char*)bdf->strings + name_offset, + bdf->strings_size - name_offset ) == 0 ) + { + switch ( type & 0x0F ) + { + case 0x00: /* string */ + case 0x01: /* atoms */ + /* check that the content is really 0-terminated */ + if ( value < bdf->strings_size && + ft_memchr( bdf->strings + value, 0, bdf->strings_size ) ) + { + aprop->type = BDF_PROPERTY_TYPE_ATOM; + aprop->u.atom = (const char*)bdf->strings + value; + error = FT_Err_Ok; + goto Exit; + } + break; + + case 0x02: + aprop->type = BDF_PROPERTY_TYPE_INTEGER; + aprop->u.integer = (FT_Int32)value; + error = FT_Err_Ok; + goto Exit; + + case 0x03: + aprop->type = BDF_PROPERTY_TYPE_CARDINAL; + aprop->u.cardinal = value; + error = FT_Err_Ok; + goto Exit; + + default: + ; + } + } + } + p += 10; + } + + Exit: + return error; + } + +#else /* !TT_CONFIG_OPTION_BDF */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_bdf_dummy_; + +#endif /* !TT_CONFIG_OPTION_BDF */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttbdf.h b/vendor/freetype/src/sfnt/ttbdf.h new file mode 100644 index 0000000..0d7a0ac --- /dev/null +++ b/vendor/freetype/src/sfnt/ttbdf.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * ttbdf.h + * + * TrueType and OpenType embedded BDF properties (specification). + * + * Copyright (C) 2005-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTBDF_H_ +#define TTBDF_H_ + + +#include "ttload.h" +#include + + +FT_BEGIN_HEADER + + +#ifdef TT_CONFIG_OPTION_BDF + + FT_LOCAL( void ) + tt_face_free_bdf_props( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_find_bdf_prop( FT_Face face, + const char* property_name, + BDF_PropertyRec *aprop ); + +#endif /* TT_CONFIG_OPTION_BDF */ + + +FT_END_HEADER + +#endif /* TTBDF_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttcmap.c b/vendor/freetype/src/sfnt/ttcmap.c new file mode 100644 index 0000000..9ba25dc --- /dev/null +++ b/vendor/freetype/src/sfnt/ttcmap.c @@ -0,0 +1,3902 @@ +/**************************************************************************** + * + * ttcmap.c + * + * TrueType character mapping table (cmap) support (body). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include "sferrors.h" /* must come before `ftvalid.h' */ + +#include +#include +#include +#include "ttload.h" +#include "ttcmap.h" +#include "ttpost.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttcmap + + +#define TT_PEEK_SHORT FT_PEEK_SHORT +#define TT_PEEK_USHORT FT_PEEK_USHORT +#define TT_PEEK_UINT24 FT_PEEK_UOFF3 +#define TT_PEEK_LONG FT_PEEK_LONG +#define TT_PEEK_ULONG FT_PEEK_ULONG + +#define TT_NEXT_SHORT FT_NEXT_SHORT +#define TT_NEXT_USHORT FT_NEXT_USHORT +#define TT_NEXT_UINT24 FT_NEXT_UOFF3 +#define TT_NEXT_LONG FT_NEXT_LONG +#define TT_NEXT_ULONG FT_NEXT_ULONG + + + /* Too large glyph index return values are caught in `FT_Get_Char_Index' */ + /* and `FT_Get_Next_Char' (the latter calls the internal `next' function */ + /* again in this case). To mark character code return values as invalid */ + /* it is sufficient to set the corresponding glyph index return value to */ + /* zero. */ + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_init( FT_CMap cmap, /* TT_CMap */ + void* table_ ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->data = table; + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 0 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 0 + * length 2 USHORT table length in bytes + * language 4 USHORT Mac language code + * glyph_ids 6 BYTE[256] array of glyph indices + * 262 + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_0 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length; + + + if ( table + 2 + 2 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; /* skip format */ + length = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 262 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices whenever necessary */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt n, idx; + + + p = table + 6; + for ( n = 0; n < 256; n++ ) + { + idx = *p++; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + + + return char_code < 256 ? table[6 + char_code] : 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt32 charcode = *pchar_code; + FT_UInt32 result = 0; + FT_UInt gindex = 0; + + + table += 6; /* go to glyph IDs */ + while ( ++charcode < 256 ) + { + gindex = table[charcode]; + if ( gindex != 0 ) + { + result = charcode; + break; + } + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 0; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap0_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap0_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap0_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 0, + (TT_CMap_ValidateFunc)tt_cmap0_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap0_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 2 *****/ + /***** *****/ + /***** This is used for certain CJK encodings that encode text in a *****/ + /***** mixed 8/16 bits encoding along the following lines. *****/ + /***** *****/ + /***** * Certain byte values correspond to an 8-bit character code *****/ + /***** (typically in the range 0..127 for ASCII compatibility). *****/ + /***** *****/ + /***** * Certain byte values signal the first byte of a 2-byte *****/ + /***** character code (but these values are also valid as the *****/ + /***** second byte of a 2-byte character). *****/ + /***** *****/ + /***** The following charmap lookup and iteration functions all *****/ + /***** assume that the value `charcode' fulfills the following. *****/ + /***** *****/ + /***** - For one-byte characters, `charcode' is simply the *****/ + /***** character code. *****/ + /***** *****/ + /***** - For two-byte characters, `charcode' is the 2-byte *****/ + /***** character code in big endian format. More precisely: *****/ + /***** *****/ + /***** (charcode >> 8) is the first byte value *****/ + /***** (charcode & 0xFF) is the second byte value *****/ + /***** *****/ + /***** Note that not all values of `charcode' are valid according *****/ + /***** to these rules, and the function moderately checks the *****/ + /***** arguments. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 2 + * length 2 USHORT table length in bytes + * language 4 USHORT Mac language code + * keys 6 USHORT[256] sub-header keys + * subs 518 SUBHEAD[NSUBS] sub-headers array + * glyph_ids 518+NSUB*8 USHORT[] glyph ID array + * + * The `keys' table is used to map charcode high bytes to sub-headers. + * The value of `NSUBS' is the number of sub-headers defined in the + * table and is computed by finding the maximum of the `keys' table. + * + * Note that for any `n', `keys[n]' is a byte offset within the `subs' + * table, i.e., it is the corresponding sub-header index multiplied + * by 8. + * + * Each sub-header has the following format. + * + * NAME OFFSET TYPE DESCRIPTION + * + * first 0 USHORT first valid low-byte + * count 2 USHORT number of valid low-bytes + * delta 4 SHORT see below + * offset 6 USHORT see below + * + * A sub-header defines, for each high byte, the range of valid + * low bytes within the charmap. Note that the range defined by `first' + * and `count' must be completely included in the interval [0..255] + * according to the specification. + * + * If a character code is contained within a given sub-header, then + * mapping it to a glyph index is done as follows. + * + * - The value of `offset' is read. This is a _byte_ distance from the + * location of the `offset' field itself into a slice of the + * `glyph_ids' table. Let's call it `slice' (it is a USHORT[], too). + * + * - The value `slice[char.lo - first]' is read. If it is 0, there is + * no glyph for the charcode. Otherwise, the value of `delta' is + * added to it (modulo 65536) to form a new glyph index. + * + * It is up to the validation routine to check that all offsets fall + * within the glyph IDs table (and not within the `subs' table itself or + * outside of the CMap). + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length; + + FT_UInt n, max_subs; + FT_Byte* keys; /* keys table */ + FT_Byte* subs; /* sub-headers */ + FT_Byte* glyph_ids; /* glyph ID array */ + + + if ( table + 2 + 2 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; /* skip format */ + length = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 6 + 512 ) + FT_INVALID_TOO_SHORT; + + keys = table + 6; + + /* parse keys to compute sub-headers count */ + p = keys; + max_subs = 0; + for ( n = 0; n < 256; n++ ) + { + FT_UInt idx = TT_NEXT_USHORT( p ); + + + /* value must be multiple of 8 */ + if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 ) + FT_INVALID_DATA; + + idx >>= 3; + + if ( idx > max_subs ) + max_subs = idx; + } + + FT_ASSERT( p == table + 518 ); + + subs = p; + glyph_ids = subs + ( max_subs + 1 ) * 8; + if ( glyph_ids > valid->limit ) + FT_INVALID_TOO_SHORT; + + /* parse sub-headers */ + for ( n = 0; n <= max_subs; n++ ) + { + FT_UInt first_code, code_count, offset; + FT_Int delta; + + + first_code = TT_NEXT_USHORT( p ); + code_count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT( p ); + offset = TT_NEXT_USHORT( p ); + + /* many Dynalab fonts have empty sub-headers */ + if ( code_count == 0 ) + continue; + + /* check range within 0..255 */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + if ( first_code >= 256 || code_count > 256 - first_code ) + FT_INVALID_DATA; + } + + /* check offset */ + if ( offset != 0 ) + { + FT_Byte* ids; + + + ids = p - 2 + offset; + if ( ids < glyph_ids || ids + code_count * 2 > table + length ) + FT_INVALID_OFFSET; + + /* check glyph IDs */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_Byte* limit = p + code_count * 2; + FT_UInt idx; + + + for ( ; p < limit; ) + { + idx = TT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + } + + return FT_Err_Ok; + } + + + /* return sub header corresponding to a given character code */ + /* NULL on invalid charcode */ + static FT_Byte* + tt_cmap2_get_subheader( FT_Byte* table, + FT_UInt32 char_code ) + { + FT_Byte* result = NULL; + + + if ( char_code < 0x10000UL ) + { + FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); + FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); + FT_Byte* p = table + 6; /* keys table */ + FT_Byte* subs = table + 518; /* subheaders table */ + FT_Byte* sub; + + + if ( char_hi == 0 ) + { + /* an 8-bit character code -- we use subHeader 0 in this case */ + /* to test whether the character code is in the charmap */ + /* */ + sub = subs; /* jump to first sub-header */ + + /* check that the sub-header for this byte is 0, which */ + /* indicates that it is really a valid one-byte value; */ + /* otherwise, return 0 */ + /* */ + p += char_lo * 2; + if ( TT_PEEK_USHORT( p ) != 0 ) + goto Exit; + } + else + { + /* a 16-bit character code */ + + /* jump to key entry */ + p += char_hi * 2; + /* jump to sub-header */ + sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) ); + + /* check that the high byte isn't a valid one-byte value */ + if ( sub == subs ) + goto Exit; + } + + result = sub; + } + + Exit: + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* subheader; + + + subheader = tt_cmap2_get_subheader( table, char_code ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt idx = (FT_UInt)( char_code & 0xFF ); + FT_UInt start, count; + FT_Int delta; + FT_UInt offset; + + + start = TT_NEXT_USHORT( p ); + count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT ( p ); + offset = TT_PEEK_USHORT( p ); + + idx -= start; + if ( idx < count && offset != 0 ) + { + p += offset + 2 * idx; + idx = TT_PEEK_USHORT( p ); + + if ( idx != 0 ) + result = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + } + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pcharcode ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 charcode = *pcharcode + 1; + FT_Byte* subheader; + + + while ( charcode < 0x10000UL ) + { + subheader = tt_cmap2_get_subheader( table, charcode ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_Int delta = TT_NEXT_SHORT ( p ); + FT_UInt offset = TT_PEEK_USHORT( p ); + FT_UInt char_lo = (FT_UInt)( charcode & 0xFF ); + FT_UInt pos, idx; + + + if ( char_lo >= start + count && charcode <= 0xFF ) + { + /* this happens only for a malformed cmap */ + charcode = 0x100; + continue; + } + + if ( offset == 0 ) + { + if ( charcode == 0x100 ) + goto Exit; /* this happens only for a malformed cmap */ + goto Next_SubHeader; + } + + if ( char_lo < start ) + { + char_lo = start; + pos = 0; + } + else + pos = (FT_UInt)( char_lo - start ); + + p += offset + pos * 2; + charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo; + + for ( ; pos < count; pos++, charcode++ ) + { + idx = TT_NEXT_USHORT( p ); + + if ( idx != 0 ) + { + gindex = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + if ( gindex != 0 ) + { + result = charcode; + goto Exit; + } + } + } + + /* if unsuccessful, avoid `charcode' leaving */ + /* the current 256-character block */ + if ( count ) + charcode--; + } + + /* If `charcode' is <= 0xFF, retry with `charcode + 1'. */ + /* Otherwise jump to the next 256-character block and retry. */ + Next_SubHeader: + if ( charcode <= 0xFF ) + charcode++; + else + charcode = FT_PAD_FLOOR( charcode, 0x100 ) + 0x100; + } + + Exit: + *pcharcode = result; + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 2; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap2_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap2_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap2_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 2, + (TT_CMap_ValidateFunc)tt_cmap2_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap2_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_2 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 4 + * length 2 USHORT table length + * in bytes + * language 4 USHORT Mac language code + * + * segCountX2 6 USHORT 2*NUM_SEGS + * searchRange 8 USHORT 2*(1 << LOG_SEGS) + * entrySelector 10 USHORT LOG_SEGS + * rangeShift 12 USHORT segCountX2 - + * searchRange + * + * endCount 14 USHORT[NUM_SEGS] end charcode for + * each segment; last + * is 0xFFFF + * + * pad 14+NUM_SEGS*2 USHORT padding + * + * startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for + * each segment + * + * idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each + * segment + * idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for + * each segment; can be + * zero + * + * glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph ID + * ranges + * + * Character codes are modelled by a series of ordered (increasing) + * intervals called segments. Each segment has start and end codes, + * provided by the `startCount' and `endCount' arrays. Segments must + * not overlap, and the last segment should always contain the value + * 0xFFFF for `endCount'. + * + * The fields `searchRange', `entrySelector' and `rangeShift' are better + * ignored (they are traces of over-engineering in the TrueType + * specification). + * + * Each segment also has a signed `delta', as well as an optional offset + * within the `glyphIds' table. + * + * If a segment's idOffset is 0, the glyph index corresponding to any + * charcode within the segment is obtained by adding the value of + * `idDelta' directly to the charcode, modulo 65536. + * + * Otherwise, a glyph index is taken from the glyph IDs sub-array for + * the segment, and the value of `idDelta' is added to it. + * + * + * Finally, note that a lot of fonts contain an invalid last segment, + * where `start' and `end' are correctly set to 0xFFFF but both `delta' + * and `offset' are incorrect (e.g., `opens___.ttf' which comes with + * OpenOffice.org). We need special code to deal with them correctly. + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + + typedef struct TT_CMap4Rec_ + { + TT_CMapRec cmap; + FT_UInt32 cur_charcode; /* current charcode */ + FT_UInt cur_gindex; /* current glyph index */ + + FT_UInt num_ranges; + FT_UInt cur_range; + FT_UInt cur_start; + FT_UInt cur_end; + FT_Int cur_delta; + FT_Byte* cur_values; + + } TT_CMap4Rec, *TT_CMap4; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_init( FT_CMap cmap, /* TT_CMap4 */ + void* table_ ) + { + TT_CMap4 ttcmap = (TT_CMap4)cmap; + FT_Byte* table = (FT_Byte*)table_; + FT_Byte* p; + + + ttcmap->cmap.data = table; + + p = table + 6; + ttcmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; + ttcmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + ttcmap->cur_gindex = 0; + + return FT_Err_Ok; + } + + + static FT_Int + tt_cmap4_set_range( TT_CMap4 cmap, + FT_UInt range_index ) + { + FT_Byte* table = cmap->cmap.data; + FT_Byte* p; + FT_UInt num_ranges = cmap->num_ranges; + + + while ( range_index < num_ranges ) + { + FT_UInt offset; + + + p = table + 14 + range_index * 2; + cmap->cur_end = FT_PEEK_USHORT( p ); + + p += 2 + num_ranges * 2; + cmap->cur_start = FT_PEEK_USHORT( p ); + + p += num_ranges * 2; + cmap->cur_delta = FT_PEEK_SHORT( p ); + + p += num_ranges * 2; + offset = FT_PEEK_USHORT( p ); + + /* some fonts have an incorrect last segment; */ + /* we have to catch it */ + if ( range_index >= num_ranges - 1 && + cmap->cur_start == 0xFFFFU && + cmap->cur_end == 0xFFFFU ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + + if ( offset && p + offset + 2 > limit ) + { + cmap->cur_delta = 1; + offset = 0; + } + } + + if ( offset != 0xFFFFU ) + { + cmap->cur_values = offset ? p + offset : NULL; + cmap->cur_range = range_index; + return 0; + } + + /* we skip empty segments */ + range_index++; + } + + return -1; + } + + + /* search the index of the charcode next to cmap->cur_charcode; */ + /* caller should call tt_cmap4_set_range with proper range */ + /* before calling this function */ + /* */ + static void + tt_cmap4_next( TT_CMap4 cmap ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + FT_UInt charcode; + + + charcode = (FT_UInt)cmap->cur_charcode + 1; + + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + + for (;;) + { + FT_Byte* values = cmap->cur_values; + FT_UInt end = cmap->cur_end; + FT_Int delta = cmap->cur_delta; + + + if ( charcode <= end ) + { + if ( values ) + { + FT_Byte* p = values + 2 * ( charcode - cmap->cur_start ); + + + /* if p > limit, the whole segment is invalid */ + if ( p > limit ) + goto Next_Segment; + + do + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex ) + { + gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + if ( gindex ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } + } while ( ++charcode <= end ); + } + else + { + do + { + FT_UInt gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; + + + if ( gindex >= (FT_UInt)face->root.num_glyphs ) + { + /* we have an invalid glyph index; if there is an overflow, */ + /* we can adjust `charcode', otherwise the whole segment is */ + /* invalid */ + gindex = 0; + + if ( (FT_Int)charcode + delta < 0 && + (FT_Int)end + delta >= 0 ) + charcode = (FT_UInt)( -delta ); + + else if ( (FT_Int)charcode + delta < 0x10000L && + (FT_Int)end + delta >= 0x10000L ) + charcode = (FT_UInt)( 0x10000L - delta ); + + else + goto Next_Segment; + } + + if ( gindex ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } while ( ++charcode <= end ); + } + } + + Next_Segment: + /* we need to find another range */ + if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 ) + break; + + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + } + + cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + cmap->cur_gindex = 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length; + + FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids; + FT_UInt num_segs; + FT_Error error = FT_Err_Ok; + + + if ( table + 2 + 2 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; /* skip format */ + length = TT_NEXT_USHORT( p ); + + /* in certain fonts, the `length' field is invalid and goes */ + /* out of bound. We try to correct this here... */ + if ( table + length > valid->limit ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_TOO_SHORT; + + length = (FT_UInt)( valid->limit - table ); + } + + /* it also happens that the `length' field is too small; */ + /* this is easy to correct */ + if ( length < (FT_UInt)( valid->limit - table ) ) + { + if ( valid->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + + length = (FT_UInt)( valid->limit - table ); + } + + if ( length < 16 ) + FT_INVALID_TOO_SHORT; + + p = table + 6; + num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */ + + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check that we have an even value here */ + if ( num_segs & 1 ) + FT_INVALID_DATA; + } + + num_segs /= 2; + + if ( length < 16 + num_segs * 2 * 4 ) + FT_INVALID_TOO_SHORT; + + /* check the search parameters - even though we never use them */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check the values of `searchRange', `entrySelector', `rangeShift' */ + FT_UInt search_range = TT_NEXT_USHORT( p ); + FT_UInt entry_selector = TT_NEXT_USHORT( p ); + FT_UInt range_shift = TT_NEXT_USHORT( p ); + + + if ( ( search_range | range_shift ) & 1 ) /* must be even values */ + FT_INVALID_DATA; + + search_range /= 2; + range_shift /= 2; + + /* `search range' is the greatest power of 2 that is <= num_segs */ + + if ( search_range > num_segs || + search_range * 2 < num_segs || + search_range + range_shift != num_segs || + search_range != ( 1U << entry_selector ) ) + FT_INVALID_DATA; + } + + ends = table + 14; + starts = table + 16 + num_segs * 2; + deltas = starts + num_segs * 2; + offsets = deltas + num_segs * 2; + glyph_ids = offsets + num_segs * 2; + + /* check last segment; its end count value must be 0xFFFF */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + p = ends + ( num_segs - 1 ) * 2; + if ( TT_PEEK_USHORT( p ) != 0xFFFFU ) + FT_INVALID_DATA; + } + + { + FT_UInt start, end, offset, n; + FT_UInt last_start = 0, last_end = 0; + FT_Int delta; + FT_Byte* p_start = starts; + FT_Byte* p_end = ends; + FT_Byte* p_delta = deltas; + FT_Byte* p_offset = offsets; + + + for ( n = 0; n < num_segs; n++ ) + { + p = p_offset; + start = TT_NEXT_USHORT( p_start ); + end = TT_NEXT_USHORT( p_end ); + delta = TT_NEXT_SHORT( p_delta ); + offset = TT_NEXT_USHORT( p_offset ); + + if ( start > end ) + FT_INVALID_DATA; + + /* this test should be performed at default validation level; */ + /* unfortunately, some popular Asian fonts have overlapping */ + /* ranges in their charmaps */ + /* */ + if ( start <= last_end && n > 0 ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + else + { + /* allow overlapping segments, provided their start points */ + /* and end points, respectively, are in ascending order */ + /* */ + if ( last_start > start || last_end > end ) + error |= TT_CMAP_FLAG_UNSORTED; + else + error |= TT_CMAP_FLAG_OVERLAPPING; + } + } + + if ( offset && offset != 0xFFFFU ) + { + p += offset; /* start of glyph ID array */ + + /* check that we point within the glyph IDs table only */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > table + length ) + FT_INVALID_DATA; + } + /* Some fonts handle the last segment incorrectly. In */ + /* theory, 0xFFFF might point to an ordinary glyph -- */ + /* a cmap 4 is versatile and could be used for any */ + /* encoding, not only Unicode. However, reality shows */ + /* that far too many fonts are sloppy and incorrectly */ + /* set all fields but `start' and `end' for the last */ + /* segment if it contains only a single character. */ + /* */ + /* We thus omit the test here, delaying it to the */ + /* routines that actually access the cmap. */ + else if ( n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU ) ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > valid->limit ) + FT_INVALID_DATA; + } + + /* check glyph indices within the segment range */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt i, idx; + + + for ( i = start; i < end; i++ ) + { + idx = FT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + else if ( offset == 0xFFFFU ) + { + /* some fonts (erroneously?) use a range offset of 0xFFFF */ + /* to mean missing glyph in cmap table */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID || + n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU ) ) + FT_INVALID_DATA; + } + + last_start = start; + last_end = end; + } + } + + return error; + } + + + static FT_UInt + tt_cmap4_char_map_linear( TT_CMap cmap, + FT_UInt32* pcharcode, + FT_Bool next ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt i, num_segs; + FT_UInt32 charcode = *pcharcode + next; + FT_UInt gindex = 0; + FT_Byte* p; + FT_Byte* q; + + + p = cmap->data + 6; + num_segs = TT_PEEK_USHORT( p ) >> 1; + + if ( !num_segs ) + return 0; + + num_segs2 = num_segs << 1; + + /* linear search */ + p = cmap->data + 14; /* ends table */ + q = cmap->data + 16 + num_segs2; /* starts table */ + + for ( i = 0; i < num_segs; i++ ) + { + end = TT_NEXT_USHORT( p ); + start = TT_NEXT_USHORT( q ); + + if ( charcode < start ) + { + if ( next ) + charcode = start; + else + break; + } + + Again: + if ( charcode <= end ) + { + FT_Byte* r; + + + r = q - 2 + num_segs2; + delta = TT_PEEK_SHORT( r ); + r += num_segs2; + offset = TT_PEEK_USHORT( r ); + + /* some fonts have an incorrect last segment; */ + /* we have to catch it */ + if ( i >= num_segs - 1 && + start == 0xFFFFU && end == 0xFFFFU ) + { + if ( offset && r + offset + 2 > limit ) + { + delta = 1; + offset = 0; + } + } + + if ( offset == 0xFFFFU ) + continue; + + if ( offset ) + { + r += offset + ( charcode - start ) * 2; + + /* if r > limit, the whole segment is invalid */ + if ( next && r > limit ) + continue; + + gindex = TT_PEEK_USHORT( r ); + if ( gindex ) + { + gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + if ( gindex >= (FT_UInt)face->root.num_glyphs ) + gindex = 0; + } + } + else + { + gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; + + if ( next && gindex >= (FT_UInt)face->root.num_glyphs ) + { + /* we have an invalid glyph index; if there is an overflow, */ + /* we can adjust `charcode', otherwise the whole segment is */ + /* invalid */ + gindex = 0; + + if ( (FT_Int)charcode + delta < 0 && + (FT_Int)end + delta >= 0 ) + charcode = (FT_UInt)( -delta ); + + else if ( (FT_Int)charcode + delta < 0x10000L && + (FT_Int)end + delta >= 0x10000L ) + charcode = (FT_UInt)( 0x10000L - delta ); + + else + continue; + } + } + + if ( next && !gindex ) + { + if ( charcode >= 0xFFFFU ) + break; + + charcode++; + goto Again; + } + + break; + } + } + + if ( next ) + *pcharcode = charcode; + + return gindex; + } + + + static FT_UInt + tt_cmap4_char_map_binary( TT_CMap cmap, + FT_UInt32* pcharcode, + FT_Bool next ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt max, min, mid, num_segs; + FT_UInt charcode = (FT_UInt)*pcharcode + next; + FT_UInt gindex = 0; + FT_Byte* p; + + + p = cmap->data + 6; + num_segs = TT_PEEK_USHORT( p ) >> 1; + + if ( !num_segs ) + return 0; + + num_segs2 = num_segs << 1; + + min = 0; + max = num_segs; + + /* binary search */ + do + { + mid = ( min + max ) >> 1; + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + + if ( charcode < start ) + max = mid; + else if ( charcode > end ) + min = mid + 1; + else + { + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + /* some fonts have an incorrect last segment; */ + /* we have to catch it */ + if ( mid >= num_segs - 1 && + start == 0xFFFFU && end == 0xFFFFU ) + { + if ( offset && p + offset + 2 > limit ) + { + delta = 1; + offset = 0; + } + } + + /* search the first segment containing `charcode' */ + if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING ) + { + FT_UInt i; + + + /* call the current segment `max' */ + max = mid; + + if ( offset == 0xFFFFU ) + mid = max + 1; + + /* search in segments before the current segment */ + for ( i = max; i > 0; i-- ) + { + FT_UInt prev_end; + FT_Byte* old_p; + + + old_p = p; + p = cmap->data + 14 + ( i - 1 ) * 2; + prev_end = TT_PEEK_USHORT( p ); + + if ( charcode > prev_end ) + { + p = old_p; + break; + } + + end = prev_end; + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + mid = i - 1; + } + + /* no luck */ + if ( mid == max + 1 ) + { + if ( i != max ) + { + p = cmap->data + 14 + max * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + + mid = max; + + /* search in segments after the current segment */ + for ( i = max + 1; i < num_segs; i++ ) + { + FT_UInt next_end, next_start; + + + p = cmap->data + 14 + i * 2; + next_end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + next_start = TT_PEEK_USHORT( p ); + + if ( charcode < next_start ) + break; + + end = next_end; + start = next_start; + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + mid = i; + } + i--; + + /* still no luck */ + if ( mid == max ) + { + mid = i; + + break; + } + } + + /* end, start, delta, and offset are for the i'th segment */ + if ( mid != i ) + { + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + } + else + { + if ( offset == 0xFFFFU ) + break; + } + + if ( offset ) + { + p += offset + ( charcode - start ) * 2; + + /* if p > limit, the whole segment is invalid */ + if ( next && p > limit ) + break; + + gindex = TT_PEEK_USHORT( p ); + if ( gindex ) + { + gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + if ( gindex >= (FT_UInt)face->root.num_glyphs ) + gindex = 0; + } + } + else + { + gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; + + if ( next && gindex >= (FT_UInt)face->root.num_glyphs ) + { + /* we have an invalid glyph index; if there is an overflow, */ + /* we can adjust `charcode', otherwise the whole segment is */ + /* invalid */ + gindex = 0; + + if ( (FT_Int)charcode + delta < 0 && + (FT_Int)end + delta >= 0 ) + charcode = (FT_UInt)( -delta ); + + else if ( (FT_Int)charcode + delta < 0x10000L && + (FT_Int)end + delta >= 0x10000L ) + charcode = (FT_UInt)( 0x10000L - delta ); + } + } + + break; + } + } + while ( min < max ); + + if ( next ) + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; + + + /* if `charcode' is not in any segment, then `mid' is */ + /* the segment nearest to `charcode' */ + + if ( charcode > end && ++mid == num_segs ) + return 0; + + if ( tt_cmap4_set_range( cmap4, mid ) ) + { + if ( gindex ) + *pcharcode = charcode; + } + else + { + cmap4->cur_charcode = charcode; + + if ( gindex ) + cmap4->cur_gindex = gindex; + else + { + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + } + + if ( gindex ) + *pcharcode = cmap4->cur_charcode; + } + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + + + if ( char_code >= 0x10000UL ) + return 0; + + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + return tt_cmap4_char_map_linear( ttcmap, &char_code, 0 ); + else + return tt_cmap4_char_map_binary( ttcmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_UInt gindex; + + + if ( *pchar_code >= 0xFFFFU ) + return 0; + + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + gindex = tt_cmap4_char_map_linear( ttcmap, pchar_code, 1 ); + else + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; + + + /* no need to search */ + if ( *pchar_code == cmap4->cur_charcode ) + { + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + if ( gindex ) + *pchar_code = cmap4->cur_charcode; + } + else + gindex = tt_cmap4_char_map_binary( ttcmap, pchar_code, 1 ); + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 4; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap4_class_rec, + + sizeof ( TT_CMap4Rec ), + + (FT_CMap_InitFunc) tt_cmap4_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap4_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap4_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 4, + (TT_CMap_ValidateFunc)tt_cmap4_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap4_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_4 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 6 + * length 2 USHORT table length in bytes + * language 4 USHORT Mac language code + * + * first 6 USHORT first segment code + * count 8 USHORT segment size in chars + * glyphIds 10 USHORT[count] glyph IDs + * + * A very simplified segment mapping. + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length, count; + + + if ( table + 10 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; + length = TT_NEXT_USHORT( p ); + + p = table + 8; /* skip language and start index */ + count = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 10 + count * 2 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx = (FT_UInt)( char_code - start ); + + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx; + + + if ( char_code >= 0x10000UL ) + return 0; + + if ( char_code < start ) + char_code = start; + + idx = (FT_UInt)( char_code - start ); + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + result = char_code; + break; + } + + if ( char_code >= 0xFFFFU ) + return 0; + + char_code++; + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 6; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap6_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap6_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap6_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 6, + (TT_CMap_ValidateFunc)tt_cmap6_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap6_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_6 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 8 *****/ + /***** *****/ + /***** It is hard to completely understand what the OpenType spec *****/ + /***** says about this format, but here is my conclusion. *****/ + /***** *****/ + /***** The purpose of this format is to easily map UTF-16 text to *****/ + /***** glyph indices. Basically, the `char_code' must be in one of *****/ + /***** the following formats. *****/ + /***** *****/ + /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ + /***** Area (i.e. U+D800-U+DFFF). *****/ + /***** *****/ + /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/ + /***** `char_code = (char_hi << 16) | char_lo', then both *****/ + /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/ + /***** Area. *****/ + /***** *****/ + /***** The `is32' table embedded in the charmap indicates whether a *****/ + /***** given 16-bit value is in the surrogates area or not. *****/ + /***** *****/ + /***** So, for any given `char_code', we can assert the following. *****/ + /***** *****/ + /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ + /***** *****/ + /***** If `char_hi != 0' then we must have both *****/ + /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 8 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * is32 12 BYTE[8192] 32-bitness bitmap + * count 8204 ULONG number of groups + * + * This header is followed by `count' groups of the following format: + * + * start 0 ULONG first charcode + * end 4 ULONG last charcode + * startId 8 ULONG start glyph ID for the group + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_Byte* is32; + FT_UInt32 length; + FT_UInt32 num_groups; + + + if ( table + 16 + 8192 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + if ( length > (FT_UInt32)( valid->limit - table ) || length < 8192 + 16 ) + FT_INVALID_TOO_SHORT; + + is32 = table + 12; + p = is32 + 8192; /* skip `is32' array */ + num_groups = TT_NEXT_ULONG( p ); + + /* p + num_groups * 12 > valid->limit ? */ + if ( num_groups > (FT_UInt32)( valid->limit - p ) / 12 ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_UInt32 n, start, end, start_id, count, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + FT_UInt hi, lo; + + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt32 d = end - start; + + + /* start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ? */ + if ( d > TT_VALID_GLYPH_COUNT( valid ) || + start_id >= TT_VALID_GLYPH_COUNT( valid ) - d ) + FT_INVALID_GLYPH_ID; + + count = (FT_UInt32)( end - start + 1 ); + + if ( start & ~0xFFFFU ) + { + /* start_hi != 0; check that is32[i] is 1 for each i in */ + /* the `hi' and `lo' of the range [start..end] */ + for ( ; count > 0; count--, start++ ) + { + hi = (FT_UInt)( start >> 16 ); + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + } + } + else + { + /* start_hi == 0; check that is32[i] is 0 for each i in */ + /* the range [start..end] */ + + /* end_hi cannot be != 0! */ + if ( end & ~0xFFFFU ) + FT_INVALID_DATA; + + for ( ; count > 0; count--, start++ ) + { + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 ) + FT_INVALID_DATA; + } + } + } + + last = end; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + break; + + if ( char_code <= end ) + { + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + return 0; + + result = (FT_UInt)( start_id + ( char_code - start ) ); + break; + } + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_UInt32 result = 0; + FT_UInt32 char_code; + FT_UInt gindex = 0; + FT_Byte* table = ttcmap->data; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + char_code = *pchar_code + 1; + + p = table + 8208; + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + Again: + if ( char_code <= end ) + { + /* ignore invalid group */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + continue; + + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + + /* does first element of group point to `.notdef' glyph? */ + if ( gindex == 0 ) + { + if ( char_code >= 0xFFFFFFFFUL ) + break; + + char_code++; + goto Again; + } + + /* if `gindex' is invalid, the remaining values */ + /* in this group are invalid, too */ + if ( gindex >= (FT_UInt)face->num_glyphs ) + { + gindex = 0; + continue; + } + + result = char_code; + break; + } + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 8; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap8_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap8_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap8_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 8, + (TT_CMap_ValidateFunc)tt_cmap8_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap8_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_8 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 10 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 10 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * + * start 12 ULONG first char in range + * count 16 ULONG number of chars in range + * glyphIds 20 USHORT[count] glyph indices covered + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_ULong length, count; + + + if ( table + 20 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + p = table + 16; + count = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 20 + count * 2 ? */ + length < 20 || + ( length - 20 ) / 2 < count ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx; + + + if ( char_code < start ) + return 0; + + idx = char_code - start; + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt32 char_code; + FT_UInt gindex = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + char_code = *pchar_code + 1; + + if ( char_code < start ) + char_code = start; + + idx = char_code - start; + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + break; + + if ( char_code >= 0xFFFFFFFFUL ) + return 0; + + char_code++; + } + + *pchar_code = char_code; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 10; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap10_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap10_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap10_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 10, + (TT_CMap_ValidateFunc)tt_cmap10_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap10_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_10 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 12 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 12 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * count 12 ULONG number of groups + * 16 + * + * This header is followed by `count' groups of the following format: + * + * start 0 ULONG first charcode + * end 4 ULONG last charcode + * startId 8 ULONG start glyph ID for the group + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + + typedef struct TT_CMap12Rec_ + { + TT_CMapRec cmap; + FT_Bool valid; + FT_ULong cur_charcode; + FT_UInt cur_gindex; + FT_ULong cur_group; + FT_ULong num_groups; + + } TT_CMap12Rec, *TT_CMap12; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_init( FT_CMap cmap, /* TT_CMap12 */ + void* table_ ) + { + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; + + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); + + ttcmap->valid = 0; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + + + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 4; + length = TT_NEXT_ULONG( p ); + + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 16 + 12 * num_groups ? */ + length < 16 || + ( length - 16 ) / 12 < num_groups ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, start_id, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt32 d = end - start; + + + /* start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ? */ + if ( d > TT_VALID_GLYPH_COUNT( valid ) || + start_id >= TT_VALID_GLYPH_COUNT( valid ) - d ) + FT_INVALID_GLYPH_ID; + } + + last = end; + } + } + + return FT_Err_Ok; + } + + + /* search the index of the charcode next to cmap->cur_charcode */ + /* cmap->cur_group should be set up properly by caller */ + /* */ + static void + tt_cmap12_next( FT_CMap cmap ) /* TT_CMap12 */ + { + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Byte* p; + FT_ULong start, end, start_id, char_code; + FT_ULong n; + FT_UInt gindex; + + + char_code = ttcmap->cur_charcode + 1; + + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) + { + p = ttcmap->cmap.data + 16 + 12 * n; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_PEEK_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + Again: + if ( char_code <= end ) + { + /* ignore invalid group */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + continue; + + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + + /* does first element of group point to `.notdef' glyph? */ + if ( gindex == 0 ) + { + if ( char_code >= 0xFFFFFFFFUL ) + goto Fail; + + char_code++; + goto Again; + } + + /* if `gindex' is invalid, the remaining values */ + /* in this group are invalid, too */ + if ( gindex >= (FT_UInt)face->num_glyphs ) + continue; + + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; + + return; + } + } + + Fail: + ttcmap->valid = 0; + } + + + static FT_UInt + tt_cmap12_char_map_binary( TT_CMap cmap, + FT_UInt32* pchar_code, + FT_Bool next ) + { + FT_UInt gindex = 0; + FT_Byte* p = cmap->data + 12; + FT_UInt32 num_groups = TT_PEEK_ULONG( p ); + FT_UInt32 char_code = *pchar_code + next; + FT_UInt32 start, end, start_id; + FT_UInt32 max, min, mid; + + + if ( !num_groups ) + return 0; + + min = 0; + max = num_groups; + + /* binary search */ + do + { + mid = ( min + max ) >> 1; + p = cmap->data + 16 + 12 * mid; + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + max = mid; + else if ( char_code > end ) + min = mid + 1; + else + { + start_id = TT_PEEK_ULONG( p ); + + /* reject invalid glyph index */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + gindex = 0; + else + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + break; + } + } + while ( min < max ); + + if ( next ) + { + FT_Face face = FT_CMAP_FACE( cmap ); + TT_CMap12 cmap12 = (TT_CMap12)cmap; + + + /* if `char_code' is not in any group, then `mid' is */ + /* the group nearest to `char_code' */ + + if ( char_code > end && ++mid == num_groups ) + return 0; + + cmap12->valid = 1; + cmap12->cur_charcode = char_code; + cmap12->cur_group = mid; + + if ( gindex >= (FT_UInt)face->num_glyphs ) + gindex = 0; + + if ( !gindex ) + { + tt_cmap12_next( FT_CMAP( cmap12 ) ); + + if ( cmap12->valid ) + gindex = cmap12->cur_gindex; + } + else + cmap12->cur_gindex = gindex; + + *pchar_code = cmap12->cur_charcode; + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + return tt_cmap12_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_next( FT_CMap cmap, /* TT_CMap12 */ + FT_UInt32 *pchar_code ) + { + TT_CMap12 cmap12 = (TT_CMap12)cmap; + FT_UInt gindex; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + /* no need to search */ + if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) + { + tt_cmap12_next( FT_CMAP( cmap12 ) ); + if ( cmap12->valid ) + { + gindex = cmap12->cur_gindex; + *pchar_code = (FT_UInt32)cmap12->cur_charcode; + } + else + gindex = 0; + } + else + gindex = tt_cmap12_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 12; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap12_class_rec, + + sizeof ( TT_CMap12Rec ), + + (FT_CMap_InitFunc) tt_cmap12_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap12_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap12_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 12, + (TT_CMap_ValidateFunc)tt_cmap12_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap12_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_12 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 13 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 13 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * count 12 ULONG number of groups + * 16 + * + * This header is followed by `count' groups of the following format: + * + * start 0 ULONG first charcode + * end 4 ULONG last charcode + * glyphId 8 ULONG glyph ID for the whole group + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_13 + + typedef struct TT_CMap13Rec_ + { + TT_CMapRec cmap; + FT_Bool valid; + FT_ULong cur_charcode; + FT_UInt cur_gindex; + FT_ULong cur_group; + FT_ULong num_groups; + + } TT_CMap13Rec, *TT_CMap13; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_init( FT_CMap cmap, /* TT_CMap13 */ + void* table_ ) + { + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; + + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); + + ttcmap->valid = 0; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + + + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 4; + length = TT_NEXT_ULONG( p ); + + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 16 + 12 * num_groups ? */ + length < 16 || + ( length - 16 ) / 12 < num_groups ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, glyph_id, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + glyph_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( glyph_id >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + + last = end; + } + } + + return FT_Err_Ok; + } + + + /* search the index of the charcode next to cmap->cur_charcode */ + /* cmap->cur_group should be set up properly by caller */ + /* */ + static void + tt_cmap13_next( FT_CMap cmap ) /* TT_CMap13 */ + { + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Byte* p; + FT_ULong start, end, glyph_id, char_code; + FT_ULong n; + FT_UInt gindex; + + + char_code = ttcmap->cur_charcode + 1; + + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) + { + p = ttcmap->cmap.data + 16 + 12 * n; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + glyph_id = TT_PEEK_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + if ( char_code <= end ) + { + gindex = (FT_UInt)glyph_id; + + if ( gindex && gindex < (FT_UInt)face->num_glyphs ) + { + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; + + return; + } + } + } + + ttcmap->valid = 0; + } + + + static FT_UInt + tt_cmap13_char_map_binary( TT_CMap cmap, + FT_UInt32* pchar_code, + FT_Bool next ) + { + FT_UInt gindex = 0; + FT_Byte* p = cmap->data + 12; + FT_UInt32 num_groups = TT_PEEK_ULONG( p ); + FT_UInt32 char_code = *pchar_code + next; + FT_UInt32 start, end; + FT_UInt32 max, min, mid; + + + if ( !num_groups ) + return 0; + + min = 0; + max = num_groups; + + /* binary search */ + do + { + mid = ( min + max ) >> 1; + p = cmap->data + 16 + 12 * mid; + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + max = mid; + else if ( char_code > end ) + min = mid + 1; + else + { + gindex = (FT_UInt)TT_PEEK_ULONG( p ); + + break; + } + } + while ( min < max ); + + if ( next ) + { + FT_Face face = cmap->cmap.charmap.face; + TT_CMap13 cmap13 = (TT_CMap13)cmap; + + + /* if `char_code' is not in any group, then `mid' is */ + /* the group nearest to `char_code' */ + + if ( char_code > end && ++mid == num_groups ) + return 0; + + cmap13->valid = 1; + cmap13->cur_charcode = char_code; + cmap13->cur_group = mid; + + if ( gindex >= (FT_UInt)face->num_glyphs ) + gindex = 0; + + if ( !gindex ) + { + tt_cmap13_next( FT_CMAP( cmap13 ) ); + + if ( cmap13->valid ) + gindex = cmap13->cur_gindex; + } + else + cmap13->cur_gindex = gindex; + + *pchar_code = cmap13->cur_charcode; + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap13_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + return tt_cmap13_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap13_char_next( FT_CMap cmap, /* TT_CMap13 */ + FT_UInt32 *pchar_code ) + { + TT_CMap13 cmap13 = (TT_CMap13)cmap; + FT_UInt gindex; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + /* no need to search */ + if ( cmap13->valid && cmap13->cur_charcode == *pchar_code ) + { + tt_cmap13_next( FT_CMAP( cmap13 ) ); + if ( cmap13->valid ) + { + gindex = cmap13->cur_gindex; + *pchar_code = cmap13->cur_charcode; + } + else + gindex = 0; + } + else + gindex = tt_cmap13_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 13; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap13_class_rec, + + sizeof ( TT_CMap13Rec ), + + (FT_CMap_InitFunc) tt_cmap13_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap13_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap13_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 13, + (TT_CMap_ValidateFunc)tt_cmap13_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap13_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_13 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 14 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 14 + * length 2 ULONG table length in bytes + * numSelector 6 ULONG number of variation sel. records + * + * Followed by numSelector records, each of which looks like + * + * varSelector 0 UINT24 Unicode codepoint of sel. + * defaultOff 3 ULONG offset to a default UVS table + * describing any variants to be found in + * the normal Unicode subtable. + * nonDefOff 7 ULONG offset to a non-default UVS table + * describing any variants not in the + * standard cmap, with GIDs here + * (either offset may be 0 NULL) + * + * Selectors are sorted by code point. + * + * A default Unicode Variation Selector (UVS) subtable is just a list of + * ranges of code points which are to be found in the standard cmap. No + * glyph IDs (GIDs) here. + * + * numRanges 0 ULONG number of ranges following + * + * A range looks like + * + * uniStart 0 UINT24 code point of the first character in + * this range + * additionalCnt 3 UBYTE count of additional characters in this + * range (zero means a range of a single + * character) + * + * Ranges are sorted by `uniStart'. + * + * A non-default Unicode Variation Selector (UVS) subtable is a list of + * mappings from codepoint to GID. + * + * numMappings 0 ULONG number of mappings + * + * A range looks like + * + * uniStart 0 UINT24 code point of the first character in + * this range + * GID 3 USHORT and its GID + * + * Ranges are sorted by `uniStart'. + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_14 + + typedef struct TT_CMap14Rec_ + { + TT_CMapRec cmap; + FT_ULong num_selectors; + + /* This array is used to store the results of various + * cmap 14 query functions. The data is overwritten + * on each call to these functions. + */ + FT_UInt32 max_results; + FT_UInt32* results; + FT_Memory memory; + + } TT_CMap14Rec, *TT_CMap14; + + + FT_CALLBACK_DEF( void ) + tt_cmap14_done( FT_CMap cmap ) /* TT_CMap14 */ + { + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Memory memory = ttcmap->memory; + + + ttcmap->max_results = 0; + if ( memory && ttcmap->results ) + FT_FREE( ttcmap->results ); + } + + + static FT_Error + tt_cmap14_ensure( TT_CMap14 cmap, + FT_UInt32 num_results, + FT_Memory memory ) + { + FT_UInt32 old_max = cmap->max_results; + FT_Error error = FT_Err_Ok; + + + if ( num_results > cmap->max_results ) + { + cmap->memory = memory; + + if ( FT_QRENEW_ARRAY( cmap->results, old_max, num_results ) ) + return error; + + cmap->max_results = num_results; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_init( FT_CMap cmap, /* TT_CMap14 */ + void* table_ ) + { + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; + + table += 6; + ttcmap->num_selectors = FT_PEEK_ULONG( table ); + ttcmap->max_results = 0; + ttcmap->results = NULL; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_selectors; + + + if ( table + 2 + 4 + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; + length = TT_NEXT_ULONG( p ); + num_selectors = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 10 + 11 * num_selectors ? */ + length < 10 || + ( length - 10 ) / 11 < num_selectors ) + FT_INVALID_TOO_SHORT; + + /* check selectors, they must be in increasing order */ + { + /* we start lastVarSel at 1 because a variant selector value of 0 + * isn't valid. + */ + FT_ULong n, lastVarSel = 1; + + + for ( n = 0; n < num_selectors; n++ ) + { + FT_ULong varSel = TT_NEXT_UINT24( p ); + FT_ULong defOff = TT_NEXT_ULONG( p ); + FT_ULong nondefOff = TT_NEXT_ULONG( p ); + + + if ( defOff >= length || nondefOff >= length ) + FT_INVALID_TOO_SHORT; + + if ( varSel < lastVarSel ) + FT_INVALID_DATA; + + lastVarSel = varSel + 1; + + /* check the default table (these glyphs should be reached */ + /* through the normal Unicode cmap, no GIDs, just check order) */ + if ( defOff != 0 ) + { + FT_Byte* defp = table + defOff; + FT_ULong numRanges; + FT_ULong i; + FT_ULong lastBase = 0; + + + if ( defp + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + + numRanges = TT_NEXT_ULONG( defp ); + + /* defp + numRanges * 4 > valid->limit ? */ + if ( numRanges > (FT_ULong)( valid->limit - defp ) / 4 ) + FT_INVALID_TOO_SHORT; + + for ( i = 0; i < numRanges; i++ ) + { + FT_ULong base = TT_NEXT_UINT24( defp ); + FT_ULong cnt = FT_NEXT_BYTE( defp ); + + + if ( base + cnt >= 0x110000UL ) /* end of Unicode */ + FT_INVALID_DATA; + + if ( base < lastBase ) + FT_INVALID_DATA; + + lastBase = base + cnt + 1U; + } + } + + /* and the non-default table (these glyphs are specified here) */ + if ( nondefOff != 0 ) + { + FT_Byte* ndp = table + nondefOff; + FT_ULong numMappings; + FT_ULong i, lastUni = 0; + + + if ( ndp + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + + numMappings = TT_NEXT_ULONG( ndp ); + + /* numMappings * 5 > (FT_ULong)( valid->limit - ndp ) ? */ + if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 5 ) + FT_INVALID_TOO_SHORT; + + for ( i = 0; i < numMappings; i++ ) + { + FT_ULong uni = TT_NEXT_UINT24( ndp ); + FT_ULong gid = TT_NEXT_USHORT( ndp ); + + + if ( uni >= 0x110000UL ) /* end of Unicode */ + FT_INVALID_DATA; + + if ( uni < lastUni ) + FT_INVALID_DATA; + + lastUni = uni + 1U; + + if ( valid->level >= FT_VALIDATE_TIGHT && + gid >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_index( FT_CMap cmap, + FT_UInt32 char_code ) + { + FT_UNUSED( cmap ); + FT_UNUSED( char_code ); + + /* This can't happen */ + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UNUSED( cmap ); + + /* This can't happen */ + *pchar_code = 0; + return 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_get_info( FT_CharMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_UNUSED( cmap ); + + cmap_info->format = 14; + /* subtable 14 does not define a language field */ + cmap_info->language = 0xFFFFFFFFUL; + + return FT_Err_Ok; + } + + + static FT_UInt + tt_cmap14_char_map_def_binary( FT_Byte *base, + FT_UInt32 char_code ) + { + FT_UInt32 numRanges = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + + + min = 0; + max = numRanges; + + base += 4; + + /* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 4 * mid; + FT_ULong start = TT_NEXT_UINT24( p ); + FT_UInt cnt = FT_NEXT_BYTE( p ); + + + if ( char_code < start ) + max = mid; + else if ( char_code > start + cnt ) + min = mid + 1; + else + return TRUE; + } + + return FALSE; + } + + + static FT_UInt + tt_cmap14_char_map_nondef_binary( FT_Byte *base, + FT_UInt32 char_code ) + { + FT_UInt32 numMappings = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + + + min = 0; + max = numMappings; + + base += 4; + + /* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 5 * mid; + FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); + + + if ( char_code < uni ) + max = mid; + else if ( char_code > uni ) + min = mid + 1; + else + return TT_PEEK_USHORT( p ); + } + + return 0; + } + + + static FT_Byte* + tt_cmap14_find_variant( FT_Byte *base, + FT_UInt32 variantCode ) + { + FT_UInt32 numVar = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + + + min = 0; + max = numVar; + + base += 4; + + /* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 11 * mid; + FT_ULong varSel = TT_NEXT_UINT24( p ); + + + if ( variantCode < varSel ) + max = mid; + else if ( variantCode > varSel ) + min = mid + 1; + else + return p; + } + + return NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_var_index( FT_CMap cmap, /* TT_CMap */ + FT_CMap ucmap, /* TT_CMap */ + FT_UInt32 charcode, + FT_UInt32 variantSelector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap ttucmap = (TT_CMap)ucmap; + + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_ULong defOff; + FT_ULong nondefOff; + + + if ( !p ) + return 0; + + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_PEEK_ULONG( p ); + + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) + { + /* This is the default variant of this charcode. GID not stored */ + /* here; stored in the normal Unicode charmap instead. */ + return ttucmap->cmap.clazz->char_index( &ttucmap->cmap, charcode ); + } + + if ( nondefOff != 0 ) + return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charcode ); + + return 0; + } + + + FT_CALLBACK_DEF( FT_Int ) + tt_cmap14_char_var_isdefault( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 charcode, + FT_UInt32 variantSelector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_ULong defOff; + FT_ULong nondefOff; + + + if ( !p ) + return -1; + + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_NEXT_ULONG( p ); + + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) + return 1; + + if ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charcode ) != 0 ) + return 0; + + return -1; + } + + + FT_CALLBACK_DEF( FT_UInt32* ) + tt_cmap14_variants( FT_CMap cmap, /* TT_CMap14 */ + FT_Memory memory ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; + FT_UInt32 count = cmap14->num_selectors; + FT_Byte* p = ttcmap->data + 10; + FT_UInt32* result; + FT_UInt32 i; + + + if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) + return NULL; + + result = cmap14->results; + for ( i = 0; i < count; i++ ) + { + result[i] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 8; + } + result[i] = 0; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt32 * ) + tt_cmap14_char_variants( FT_CMap cmap, /* TT_CMap14 */ + FT_Memory memory, + FT_UInt32 charCode ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; + FT_UInt32 count = cmap14->num_selectors; + FT_Byte* p = ttcmap->data + 10; + FT_UInt32* q; + + + if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) + return NULL; + + for ( q = cmap14->results; count > 0; count-- ) + { + FT_UInt32 varSel = TT_NEXT_UINT24( p ); + FT_ULong defOff = TT_NEXT_ULONG( p ); + FT_ULong nondefOff = TT_NEXT_ULONG( p ); + + + if ( ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, + charCode ) ) || + ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charCode ) != 0 ) ) + { + q[0] = varSel; + q++; + } + } + q[0] = 0; + + return cmap14->results; + } + + + static FT_UInt + tt_cmap14_def_char_count( FT_Byte *p ) + { + FT_UInt32 numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); + FT_UInt tot = 0; + + + p += 3; /* point to the first `cnt' field */ + for ( ; numRanges > 0; numRanges-- ) + { + tot += 1 + p[0]; + p += 4; + } + + return tot; + } + + + static FT_UInt32* + tt_cmap14_get_def_chars( TT_CMap cmap, + FT_Byte* p, + FT_Memory memory ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 numRanges; + FT_UInt cnt; + FT_UInt32* q; + + + cnt = tt_cmap14_def_char_count( p ); + numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); + + if ( tt_cmap14_ensure( cmap14, ( cnt + 1 ), memory ) ) + return NULL; + + for ( q = cmap14->results; numRanges > 0; numRanges-- ) + { + FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); + + + cnt = FT_NEXT_BYTE( p ) + 1; + do + { + q[0] = uni; + uni += 1; + q += 1; + + } while ( --cnt != 0 ); + } + q[0] = 0; + + return cmap14->results; + } + + + static FT_UInt32* + tt_cmap14_get_nondef_chars( TT_CMap cmap, + FT_Byte *p, + FT_Memory memory ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 numMappings; + FT_UInt i; + FT_UInt32 *ret; + + + numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); + + if ( tt_cmap14_ensure( cmap14, ( numMappings + 1 ), memory ) ) + return NULL; + + ret = cmap14->results; + for ( i = 0; i < numMappings; i++ ) + { + ret[i] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + } + ret[i] = 0; + + return ret; + } + + + FT_CALLBACK_DEF( FT_UInt32 * ) + tt_cmap14_variant_chars( FT_CMap cmap, /* TT_CMap */ + FT_Memory memory, + FT_UInt32 variantSelector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte *p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_Int i; + FT_ULong defOff; + FT_ULong nondefOff; + + + if ( !p ) + return NULL; + + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_NEXT_ULONG( p ); + + if ( defOff == 0 && nondefOff == 0 ) + return NULL; + + if ( defOff == 0 ) + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, + memory ); + else if ( nondefOff == 0 ) + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, + memory ); + else + { + /* Both a default and a non-default glyph set? That's probably not */ + /* good font design, but the spec allows for it... */ + TT_CMap14 cmap14 = (TT_CMap14)cmap; + FT_UInt32 numRanges; + FT_UInt32 numMappings; + FT_UInt32 duni; + FT_UInt32 dcnt; + FT_UInt32 nuni; + FT_Byte* dp; + FT_UInt di, ni, k; + + FT_UInt32 *ret; + + + p = ttcmap->data + nondefOff; + dp = ttcmap->data + defOff; + + numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); + dcnt = tt_cmap14_def_char_count( dp ); + numRanges = (FT_UInt32)TT_NEXT_ULONG( dp ); + + if ( numMappings == 0 ) + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, + memory ); + if ( dcnt == 0 ) + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, + memory ); + + if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) ) + return NULL; + + ret = cmap14->results; + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + di = 1; + nuni = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + ni = 1; + i = 0; + + for (;;) + { + if ( nuni > duni + dcnt ) + { + for ( k = 0; k <= dcnt; k++ ) + ret[i++] = duni + k; + + di++; + + if ( di > numRanges ) + break; + + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + } + else + { + if ( nuni < duni ) + ret[i++] = nuni; + /* If it is within the default range then ignore it -- */ + /* that should not have happened */ + ni++; + if ( ni > numMappings ) + break; + + nuni = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + } + } + + if ( ni <= numMappings ) + { + /* If we get here then we have run out of all default ranges. */ + /* We have read one non-default mapping which we haven't stored */ + /* and there may be others that need to be read. */ + ret[i++] = nuni; + while ( ni < numMappings ) + { + ret[i++] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + ni++; + } + } + else if ( di <= numRanges ) + { + /* If we get here then we have run out of all non-default */ + /* mappings. We have read one default range which we haven't */ + /* stored and there may be others that need to be read. */ + for ( k = 0; k <= dcnt; k++ ) + ret[i++] = duni + k; + + while ( di < numRanges ) + { + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + + for ( k = 0; k <= dcnt; k++ ) + ret[i++] = duni + k; + di++; + } + } + + ret[i] = 0; + + return ret; + } + } + + + FT_DEFINE_TT_CMAP( + tt_cmap14_class_rec, + + sizeof ( TT_CMap14Rec ), + + (FT_CMap_InitFunc) tt_cmap14_init, /* init */ + (FT_CMap_DoneFunc) tt_cmap14_done, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap14_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap14_char_next, /* char_next */ + + /* Format 14 extension functions */ + (FT_CMap_CharVarIndexFunc) tt_cmap14_char_var_index, + (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault, + (FT_CMap_VariantListFunc) tt_cmap14_variants, + (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants, + (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars, + + 14, + (TT_CMap_ValidateFunc)tt_cmap14_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap14_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_14 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SYNTHETIC UNICODE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* This charmap is generated using postscript glyph names. */ + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + FT_CALLBACK_DEF( const char * ) + tt_get_glyph_name( void* face_, /* TT_Face */ + FT_UInt idx ) + { + TT_Face face = (TT_Face)face_; + FT_String* PSname = NULL; + + + tt_face_get_ps_name( face, idx, &PSname ); + + return PSname; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + FT_UNUSED( pointer ); + + + if ( !psnames->unicodes_init ) + return FT_THROW( Unimplemented_Feature ); + + return psnames->unicodes_init( memory, + unicodes, + face->root.num_glyphs, + &tt_get_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + tt_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_DEFINE_TT_CMAP( + tt_cmap_unicode_class_rec, + + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) tt_cmap_unicode_init, /* init */ + (FT_CMap_DoneFunc) tt_cmap_unicode_done, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap_unicode_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap_unicode_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + ~0U, + (TT_CMap_ValidateFunc)NULL, /* validate */ + (TT_CMap_Info_GetFunc)NULL /* get_cmap_info */ + ) + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + static const TT_CMap_Class tt_cmap_classes[] = + { +#undef TTCMAPCITEM +#define TTCMAPCITEM( a ) &a, +#include "ttcmapc.h" + NULL, + }; + + + /* parse the `cmap' table and build the corresponding TT_CMap objects */ + /* in the current face */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_build_cmaps( TT_Face face ) + { + FT_Byte* const table = face->cmap_table; + FT_Byte* limit; + FT_UInt volatile num_cmaps; + FT_Byte* volatile p = table; + FT_Library library = FT_FACE_LIBRARY( face ); + + FT_UNUSED( library ); + + + if ( !p || face->cmap_size < 4 ) + return FT_THROW( Invalid_Table ); + + /* Version 1.8.3 of the OpenType specification contains the following */ + /* (https://docs.microsoft.com/en-us/typography/opentype/spec/cmap): */ + /* */ + /* The 'cmap' table version number remains at 0x0000 for fonts that */ + /* make use of the newer subtable formats. */ + /* */ + /* This essentially means that a version format test is useless. */ + + /* ignore format */ + p += 2; + + num_cmaps = TT_NEXT_USHORT( p ); + FT_TRACE4(( "tt_face_build_cmaps: %d cmaps\n", num_cmaps )); + + limit = table + face->cmap_size; + for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) + { + FT_CharMapRec charmap; + FT_UInt32 offset; + + + charmap.platform_id = TT_NEXT_USHORT( p ); + charmap.encoding_id = TT_NEXT_USHORT( p ); + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; /* will be filled later */ + offset = TT_NEXT_ULONG( p ); + + if ( offset && offset <= face->cmap_size - 2 ) + { + FT_Byte* volatile cmap = table + offset; + volatile FT_UInt format = TT_PEEK_USHORT( cmap ); + const TT_CMap_Class* volatile pclazz = tt_cmap_classes; + TT_CMap_Class volatile clazz; + + + for ( ; *pclazz; pclazz++ ) + { + clazz = *pclazz; + if ( clazz->format == format ) + { + volatile TT_ValidatorRec valid; + volatile FT_Error error = FT_Err_Ok; + + + ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, + FT_VALIDATE_DEFAULT ); + + valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs; + + if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer) == 0 ) + { + /* validate this cmap sub-table */ + error = clazz->validate( cmap, FT_VALIDATOR( &valid ) ); + } + + if ( !valid.validator.error ) + { + FT_CMap ttcmap; + + + /* It might make sense to store the single variation */ + /* selector cmap somewhere special. But it would have to be */ + /* in the public FT_FaceRec, and we can't change that. */ + + if ( !FT_CMap_New( (FT_CMap_Class)clazz, + cmap, &charmap, &ttcmap ) ) + { + /* it is simpler to directly set `flags' than adding */ + /* a parameter to FT_CMap_New */ + ((TT_CMap)ttcmap)->flags = (FT_Int)error; + } + } + else + { + FT_TRACE0(( "tt_face_build_cmaps:" + " broken cmap sub-table ignored\n" )); + } + break; + } + } + + if ( !*pclazz ) + { + FT_TRACE0(( "tt_face_build_cmaps:" + " unsupported cmap sub-table ignored\n" )); + } + } + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = FT_CMAP( charmap ); + TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; + + + if ( clazz->get_cmap_info ) + return clazz->get_cmap_info( charmap, cmap_info ); + else + return FT_THROW( Invalid_CharMap_Format ); + } + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttcmap.h b/vendor/freetype/src/sfnt/ttcmap.h new file mode 100644 index 0000000..ff52917 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttcmap.h @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * ttcmap.h + * + * TrueType character mapping table (cmap) support (specification). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTCMAP_H_ +#define TTCMAP_H_ + + +#include +#include +#include + +FT_BEGIN_HEADER + + +#define TT_CMAP_FLAG_UNSORTED 1 +#define TT_CMAP_FLAG_OVERLAPPING 2 + + typedef struct TT_CMapRec_ + { + FT_CMapRec cmap; + FT_Byte* data; /* pointer to in-memory cmap table */ + FT_Int flags; /* for format 4 only */ + + } TT_CMapRec, *TT_CMap; + + typedef const struct TT_CMap_ClassRec_* TT_CMap_Class; + + + typedef FT_Error + (*TT_CMap_ValidateFunc)( FT_Byte* data, + FT_Validator valid ); + + typedef struct TT_CMap_ClassRec_ + { + FT_CMap_ClassRec clazz; + FT_UInt format; + TT_CMap_ValidateFunc validate; + TT_CMap_Info_GetFunc get_cmap_info; + + } TT_CMap_ClassRec; + + +#define FT_DEFINE_TT_CMAP( class_, \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_, \ + format_, \ + validate_, \ + get_cmap_info_ ) \ + FT_CALLBACK_TABLE_DEF \ + const TT_CMap_ClassRec class_ = \ + { \ + { size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ \ + }, \ + \ + format_, \ + validate_, \ + get_cmap_info_ \ + }; + + +#undef TTCMAPCITEM +#define TTCMAPCITEM( a ) FT_CALLBACK_TABLE const TT_CMap_ClassRec a; +#include "ttcmapc.h" + + + typedef struct TT_ValidatorRec_ + { + FT_ValidatorRec validator; + FT_UInt num_glyphs; + + } TT_ValidatorRec, *TT_Validator; + + +#define TT_VALIDATOR( x ) ( (TT_Validator)( x ) ) +#define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs + + + FT_CALLBACK_TABLE const TT_CMap_ClassRec tt_cmap_unicode_class_rec; + + FT_LOCAL( FT_Error ) + tt_face_build_cmaps( TT_Face face ); + + /* used in tt-cmaps service */ + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + +FT_END_HEADER + +#endif /* TTCMAP_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttcmapc.h b/vendor/freetype/src/sfnt/ttcmapc.h new file mode 100644 index 0000000..0af48c2 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttcmapc.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * ttcmapc.h + * + * TT CMAP classes definitions (specification only). + * + * Copyright (C) 2009-2023 by + * Oran Agra and Mickey Gabel. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifdef TT_CONFIG_CMAP_FORMAT_0 + TTCMAPCITEM( tt_cmap0_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + TTCMAPCITEM( tt_cmap2_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + TTCMAPCITEM( tt_cmap4_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + TTCMAPCITEM( tt_cmap6_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + TTCMAPCITEM( tt_cmap8_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + TTCMAPCITEM( tt_cmap10_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + TTCMAPCITEM( tt_cmap12_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_13 + TTCMAPCITEM( tt_cmap13_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_14 + TTCMAPCITEM( tt_cmap14_class_rec ) +#endif + + + /* END */ diff --git a/vendor/freetype/src/sfnt/ttcolr.c b/vendor/freetype/src/sfnt/ttcolr.c new file mode 100644 index 0000000..281e713 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttcolr.c @@ -0,0 +1,1921 @@ +/**************************************************************************** + * + * ttcolr.c + * + * TrueType and OpenType colored glyph layer support (body). + * + * Copyright (C) 2018-2023 by + * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * `COLR' table specification: + * + * https://www.microsoft.com/typography/otspec/colr.htm + * + */ + + +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#endif + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS + +#include "ttcolr.h" + + + /* NOTE: These are the table sizes calculated through the specs. */ +#define BASE_GLYPH_SIZE 6U +#define BASE_GLYPH_PAINT_RECORD_SIZE 6U +#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U +#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U +#define COLOR_STOP_SIZE 6U +#define VAR_IDX_BASE_SIZE 4U +#define LAYER_SIZE 4U +/* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#colr-header */ +/* 3 * uint16 + 2 * Offset32 */ +#define COLRV0_HEADER_SIZE 14U +/* COLRV0_HEADER_SIZE + 5 * Offset32 */ +#define COLRV1_HEADER_SIZE 34U + + +#define ENSURE_READ_BYTES( byte_size ) \ + if ( p < colr->paints_start_v1 || \ + p > (FT_Byte*)colr->table + colr->table_size - byte_size ) \ + return 0 + + + typedef enum FT_PaintFormat_Internal_ + { + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID = 3, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT = 5, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT = 7, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT = 9, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM = 13, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE = 15, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE = 17, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER = 19, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM = 21, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER = 23, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE = 25, + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER = 27, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW = 29, + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER = 31, + + } FT_PaintFormat_Internal; + + + typedef struct BaseGlyphRecord_ + { + FT_UShort gid; + FT_UShort first_layer_index; + FT_UShort num_layers; + + } BaseGlyphRecord; + + + typedef struct BaseGlyphV1Record_ + { + FT_UShort gid; + /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */ + FT_ULong paint_offset; + + } BaseGlyphV1Record; + + + typedef struct Colr_ + { + FT_UShort version; + FT_UShort num_base_glyphs; + FT_UShort num_layers; + + FT_Byte* base_glyphs; + FT_Byte* layers; + + FT_ULong num_base_glyphs_v1; + /* Points at beginning of BaseGlyphV1List. */ + FT_Byte* base_glyphs_v1; + + FT_ULong num_layers_v1; + FT_Byte* layers_v1; + + FT_Byte* clip_list; + + /* + * Paint tables start at the minimum of the end of the LayerList and the + * end of the BaseGlyphList. Record this location in a field here for + * safety checks when accessing paint tables. + */ + FT_Byte* paints_start_v1; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Item Variation Store for variable 'COLR' v1. */ + GX_ItemVarStoreRec var_store; + GX_DeltaSetIdxMapRec delta_set_idx_map; +#endif + + /* The memory that backs up the `COLR' table. */ + void* table; + FT_ULong table_size; + + } Colr; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttcolr + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_colr( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_Byte* table = NULL; + FT_Byte* p = NULL; + /* Needed for reading array lengths in referenced tables. */ + FT_Byte* p1 = NULL; + + Colr* colr = NULL; + + FT_ULong base_glyph_offset, layer_offset; + FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1; + FT_ULong layer_offset_v1, num_layers_v1, clip_list_offset; + FT_ULong table_size; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_ULong colr_offset_in_stream; +#endif + + + /* `COLR' always needs `CPAL' */ + if ( !face->cpal ) + return FT_THROW( Invalid_File_Format ); + + error = face->goto_table( face, TTAG_COLR, stream, &table_size ); + if ( error ) + goto NoColr; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr_offset_in_stream = FT_STREAM_POS(); +#endif + + if ( table_size < COLRV0_HEADER_SIZE ) + goto NoColr; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoColr; + + p = table; + + if ( FT_NEW( colr ) ) + goto NoColr; + + colr->version = FT_NEXT_USHORT( p ); + if ( colr->version != 0 && colr->version != 1 ) + goto InvalidTable; + + colr->num_base_glyphs = FT_NEXT_USHORT( p ); + base_glyph_offset = FT_NEXT_ULONG( p ); + + if ( base_glyph_offset >= table_size ) + goto InvalidTable; + if ( colr->num_base_glyphs * BASE_GLYPH_SIZE > + table_size - base_glyph_offset ) + goto InvalidTable; + + layer_offset = FT_NEXT_ULONG( p ); + colr->num_layers = FT_NEXT_USHORT( p ); + + if ( layer_offset >= table_size ) + goto InvalidTable; + if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset ) + goto InvalidTable; + + if ( colr->version == 1 ) + { + if ( table_size < COLRV1_HEADER_SIZE ) + goto InvalidTable; + + base_glyphs_offset_v1 = FT_NEXT_ULONG( p ); + + if ( base_glyphs_offset_v1 >= table_size - 4 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + base_glyphs_offset_v1 ); + num_base_glyphs_v1 = FT_PEEK_ULONG( p1 ); + + if ( num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE > + table_size - base_glyphs_offset_v1 ) + goto InvalidTable; + + colr->num_base_glyphs_v1 = num_base_glyphs_v1; + colr->base_glyphs_v1 = p1; + + layer_offset_v1 = FT_NEXT_ULONG( p ); + + if ( layer_offset_v1 >= table_size ) + goto InvalidTable; + + if ( layer_offset_v1 ) + { + if ( layer_offset_v1 >= table_size - 4 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + layer_offset_v1 ); + num_layers_v1 = FT_PEEK_ULONG( p1 ); + + if ( num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE > + table_size - layer_offset_v1 ) + goto InvalidTable; + + colr->num_layers_v1 = num_layers_v1; + colr->layers_v1 = p1; + + colr->paints_start_v1 = + FT_MIN( colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE, + colr->layers_v1 + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ); + } + else + { + colr->num_layers_v1 = 0; + colr->layers_v1 = 0; + colr->paints_start_v1 = + colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE; + } + + clip_list_offset = FT_NEXT_ULONG( p ); + + if ( clip_list_offset >= table_size ) + goto InvalidTable; + + if ( clip_list_offset ) + colr->clip_list = (FT_Byte*)( table + clip_list_offset ); + else + colr->clip_list = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr->var_store.dataCount = 0; + colr->var_store.varData = NULL; + colr->var_store.axisCount = 0; + colr->var_store.regionCount = 0; + colr->var_store.varRegionList = 0; + + colr->delta_set_idx_map.mapCount = 0; + colr->delta_set_idx_map.outerIndex = NULL; + colr->delta_set_idx_map.innerIndex = NULL; + + if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) + { + FT_ULong var_idx_map_offset, var_store_offset; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + var_idx_map_offset = FT_NEXT_ULONG( p ); + + if ( var_idx_map_offset >= table_size ) + goto InvalidTable; + + var_store_offset = FT_NEXT_ULONG( p ); + if ( var_store_offset >= table_size ) + goto InvalidTable; + + if ( var_store_offset ) + { + /* If variation info has not been initialized yet, try doing so, */ + /* otherwise loading the variation store will fail as it */ + /* requires access to `blend` for checking the number of axes. */ + if ( !face->blend ) + if ( mm->get_mm_var( FT_FACE( face ), NULL ) ) + goto InvalidTable; + + /* Try loading `VarIdxMap` and `VarStore`. */ + error = mm->load_item_var_store( + FT_FACE( face ), + colr_offset_in_stream + var_store_offset, + &colr->var_store ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + + if ( colr->var_store.axisCount && var_idx_map_offset ) + { + error = mm->load_delta_set_idx_map( + FT_FACE( face ), + colr_offset_in_stream + var_idx_map_offset, + &colr->delta_set_idx_map, + &colr->var_store, + table_size ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + } + + colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset ); + colr->layers = (FT_Byte*)( table + layer_offset ); + colr->table = table; + colr->table_size = table_size; + + face->colr = colr; + + return FT_Err_Ok; + + InvalidTable: +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif + + error = FT_THROW( Invalid_Table ); + + NoColr: + FT_FRAME_RELEASE( table ); + FT_FREE( colr ); + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_colr( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; + + Colr* colr = (Colr*)face->colr; + + + if ( colr ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif + FT_FRAME_RELEASE( colr->table ); + FT_FREE( colr ); + } + } + + + static FT_Bool + find_base_glyph_record( FT_Byte* base_glyph_begin, + FT_UInt num_base_glyph, + FT_UInt glyph_id, + BaseGlyphRecord* record ) + { + FT_UInt min = 0; + FT_UInt max = num_base_glyph; + + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE; + + FT_UShort gid = FT_NEXT_USHORT( p ); + + + if ( gid < glyph_id ) + min = mid + 1; + else if (gid > glyph_id ) + max = mid; + else + { + record->gid = gid; + record->first_layer_index = FT_NEXT_USHORT( p ); + record->num_layers = FT_NEXT_USHORT( p ); + + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colr_layer( TT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ) + { + Colr* colr = (Colr*)face->colr; + BaseGlyphRecord glyph_record; + + + if ( !colr ) + return 0; + + if ( !iterator->p ) + { + FT_ULong offset; + + + /* first call to function */ + iterator->layer = 0; + + if ( !find_base_glyph_record( colr->base_glyphs, + colr->num_base_glyphs, + base_glyph, + &glyph_record ) ) + return 0; + + if ( glyph_record.num_layers ) + iterator->num_layers = glyph_record.num_layers; + else + return 0; + + offset = LAYER_SIZE * glyph_record.first_layer_index; + if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size ) + return 0; + + iterator->p = colr->layers + offset; + } + + if ( iterator->layer >= iterator->num_layers || + iterator->p < colr->layers || + iterator->p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + *aglyph_index = FT_NEXT_USHORT( iterator->p ); + *acolor_index = FT_NEXT_USHORT( iterator->p ); + + if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) || + ( *acolor_index != 0xFFFF && + *acolor_index >= face->palette_data.num_palette_entries ) ) + return 0; + + iterator->layer++; + + return 1; + } + + + static FT_Bool + read_color_line( Colr* colr, + FT_Byte* color_line_p, + FT_ColorLine* colorline, + FT_Bool read_variable ) + { + FT_Byte* p = color_line_p; + FT_PaintExtend paint_extend; + + + ENSURE_READ_BYTES( 3 ); + + paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p ); + if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT ) + return 0; + + colorline->extend = paint_extend; + + colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p ); + colorline->color_stop_iterator.p = p; + colorline->color_stop_iterator.current_color_stop = 0; + colorline->color_stop_iterator.read_variable = read_variable; + + return 1; + } + + + /* + * Read a paint offset for `FT_Paint*` objects that have them and check + * whether it is within reasonable limits within the font and the COLR + * table. + * + * Return 1 on success, 0 on failure. + */ + static FT_Bool + get_child_table_pointer ( Colr* colr, + FT_Byte* paint_base, + FT_Byte** p, + FT_Byte** child_table_pointer ) + { + FT_UInt32 paint_offset; + FT_Byte* child_table_p; + + + if ( !child_table_pointer ) + return 0; + + if ( *p < colr->paints_start_v1 || + *p > (FT_Byte*)colr->table + colr->table_size - 1 - 3 ) + return 0; + + paint_offset = FT_NEXT_UOFF3( *p ); + if ( !paint_offset ) + return 0; + + child_table_p = (FT_Byte*)( paint_base + paint_offset ); + + if ( child_table_p < colr->paints_start_v1 || + child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + *child_table_pointer = child_table_p; + return 1; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + static FT_Bool + get_deltas_for_var_index_base ( TT_Face face, + Colr* colr, + FT_ULong var_index_base, + FT_UInt num_deltas, + FT_ItemVarDelta* deltas ) + { + FT_UInt outer_index = 0; + FT_UInt inner_index = 0; + FT_ULong loop_var_index = var_index_base; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + FT_UInt i = 0; + + + if ( var_index_base == 0xFFFFFFFF ) + { + for ( i = 0; i < num_deltas; ++i ) + deltas[i] = 0; + return 1; + } + + for ( i = 0; i < num_deltas; ++i ) + { + loop_var_index = var_index_base + i; + + if ( colr->delta_set_idx_map.innerIndex ) + { + if ( loop_var_index >= colr->delta_set_idx_map.mapCount ) + loop_var_index = colr->delta_set_idx_map.mapCount - 1; + + outer_index = colr->delta_set_idx_map.outerIndex[loop_var_index]; + inner_index = colr->delta_set_idx_map.innerIndex[loop_var_index]; + } + else + { + outer_index = 0; + inner_index = loop_var_index; + } + + deltas[i] = mm->get_item_delta( FT_FACE( face ), &colr->var_store, + outer_index, inner_index ); + } + + return 1; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static FT_Bool + read_paint( TT_Face face, + Colr* colr, + FT_Byte* p, + FT_COLR_Paint* apaint ) + { + FT_Byte* paint_base = p; + FT_Byte* child_table_p = NULL; + FT_Bool do_read_var = FALSE; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_ULong var_index_base = 0; + /* Longest varIndexBase offset is 5 in the spec. */ + FT_ItemVarDelta item_deltas[6] = { 0, 0, 0, 0, 0, 0 }; +#else + FT_UNUSED( face ); +#endif + + + if ( !p || !colr || !colr->table ) + return 0; + + /* The last byte of the 'COLR' table is at 'size-1'; subtract 1 of */ + /* that to account for the expected format byte we are going to read. */ + if ( p < colr->paints_start_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 2 ) + return 0; + + apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p ); + + if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS ) + { + /* Initialize layer iterator/ */ + FT_Byte num_layers; + FT_UInt32 first_layer_index; + + + num_layers = FT_NEXT_BYTE( p ); + if ( num_layers > colr->num_layers_v1 ) + return 0; + + first_layer_index = FT_NEXT_ULONG( p ); + if ( first_layer_index + num_layers > colr->num_layers_v1 ) + return 0; + + apaint->u.colr_layers.layer_iterator.num_layers = num_layers; + apaint->u.colr_layers.layer_iterator.layer = 0; + /* TODO: Check whether pointer is outside colr? */ + apaint->u.colr_layers.layer_iterator.p = + colr->layers_v1 + + LAYER_V1_LIST_NUM_LAYERS_SIZE + + LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p ); + apaint->u.solid.color.alpha = FT_NEXT_SHORT( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.solid.color.alpha += (FT_F2Dot14)item_deltas[0]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SOLID; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH ) + { + ENSURE_READ_BYTES(2); + apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + /* + * Grouped below here are all paint formats that have an offset to a + * child paint table as the first entry (for example, a color line or a + * child paint table). Retrieve that and determine whether that paint + * offset is valid first. + */ + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT ) ) ) + { + if ( !read_color_line( colr, + child_table_p, + &apaint->u.linear_gradient.colorline, + do_read_var ) ) + return 0; + + /* + * In order to support variations expose these as FT_Fixed 16.16 + * values so that we can support fractional values after + * interpolation. + */ + ENSURE_READ_BYTES( 12 ); + apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.linear_gradient.p0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.linear_gradient.p0.y += INT_TO_FIXED( item_deltas[1] ); + apaint->u.linear_gradient.p1.x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.linear_gradient.p1.y += INT_TO_FIXED( item_deltas[3] ); + apaint->u.linear_gradient.p2.x += INT_TO_FIXED( item_deltas[4] ); + apaint->u.linear_gradient.p2.y += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_LINEAR_GRADIENT; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT ) ) ) + { + FT_Pos tmp; + + + if ( !read_color_line( colr, + child_table_p, + &apaint->u.radial_gradient.colorline, + do_read_var ) ) + return 0; + + + /* In the OpenType specification, `r0` and `r1` are defined as */ + /* `UFWORD`. Since FreeType doesn't have a corresponding 16.16 */ + /* format we convert to `FWORD` and replace negative values with */ + /* (32bit) `FT_INT_MAX`. */ + + ENSURE_READ_BYTES( 12 ); + + apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r0 = tmp < 0 ? FT_INT_MAX : tmp; + + apaint->u.radial_gradient.c1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.radial_gradient.c0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.radial_gradient.c0.y += INT_TO_FIXED( item_deltas[1] ); + + // TODO: Anything to be done about UFWORD deltas here? + apaint->u.radial_gradient.r0 += INT_TO_FIXED( item_deltas[2] ); + + apaint->u.radial_gradient.c1.x += INT_TO_FIXED( item_deltas[3] ); + apaint->u.radial_gradient.c1.y += INT_TO_FIXED( item_deltas[4] ); + + apaint->u.radial_gradient.r1 += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_RADIAL_GRADIENT; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT ) ) ) + { + if ( !read_color_line( colr, + child_table_p, + &apaint->u.sweep_gradient.colorline, + do_read_var) ) + return 0; + + ENSURE_READ_BYTES( 8 ); + + apaint->u.sweep_gradient.center.x = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.center.y = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + apaint->u.sweep_gradient.start_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.end_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + // TODO: Handle overflow? + apaint->u.sweep_gradient.center.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.sweep_gradient.center.y += INT_TO_FIXED( item_deltas[1] ); + + apaint->u.sweep_gradient.start_angle += + F2DOT14_TO_FIXED( item_deltas[2] ); + apaint->u.sweep_gradient.end_angle += + F2DOT14_TO_FIXED( item_deltas[3] ); + } +#endif + apaint->format = FT_COLR_PAINTFORMAT_SWEEP_GRADIENT; + + return 1; + } + + if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.glyph.paint.p = child_table_p; + apaint->u.glyph.paint.insert_root_transform = 0; + apaint->u.glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM ) + { + apaint->u.transform.paint.p = child_table_p; + apaint->u.transform.paint.insert_root_transform = 0; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + p = child_table_p; + + /* + * The following matrix coefficients are encoded as + * OpenType 16.16 fixed-point values. + */ + ENSURE_READ_BYTES( 24 ); + apaint->u.transform.affine.xx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.xy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dy = FT_NEXT_LONG( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.transform.affine.xx += (FT_Fixed)item_deltas[0]; + apaint->u.transform.affine.yx += (FT_Fixed)item_deltas[1]; + apaint->u.transform.affine.xy += (FT_Fixed)item_deltas[2]; + apaint->u.transform.affine.yy += (FT_Fixed)item_deltas[3]; + apaint->u.transform.affine.dx += (FT_Fixed)item_deltas[4]; + apaint->u.transform.affine.dy += (FT_Fixed)item_deltas[5]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE ) + { + apaint->u.translate.paint.p = child_table_p; + apaint->u.translate.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 4 ); + apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.translate.dx += INT_TO_FIXED( item_deltas[0] ); + apaint->u.translate.dy += INT_TO_FIXED( item_deltas[1] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSLATE; + + return 1; + } + + else if ( apaint->format >= FT_COLR_PAINTFORMAT_SCALE && + (FT_PaintFormat_Internal)apaint->format <= + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + apaint->u.scale.paint.p = child_table_p; + apaint->u.scale.paint.insert_root_transform = 0; + + /* All scale paints get at least one scale value. */ + ENSURE_READ_BYTES( 2 ); + apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + /* Non-uniform ones read an extra y value. */ + if ( apaint->format == FT_COLR_PAINTFORMAT_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + apaint->u.scale.scale_y = apaint->u.scale.scale_x; + + /* Scale paints that have a center read center coordinates, */ + /* otherwise the center is (0,0). */ + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + } + else + { + apaint->u.scale.center_x = 0; + apaint->u.scale.center_y = 0; + } + + /* Base values set, now handle variations. */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[3] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 3, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } +#endif + + /* FT 'COLR' v1 API output format always returns fully defined */ + /* structs; we thus set the format to the public API value. */ + apaint->format = FT_COLR_PAINTFORMAT_SCALE; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + apaint->u.rotate.paint.p = child_table_p; + apaint->u.rotate.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 2 ); + apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.rotate.center_x = 0; + apaint->u.rotate.center_y = 0; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + FT_UInt num_deltas = 0; + + + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + num_deltas = 3; + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE ) + num_deltas = 1; + + if ( num_deltas > 0 ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, + num_deltas, item_deltas ) ) + return 0; + + apaint->u.rotate.angle += F2DOT14_TO_FIXED( item_deltas[0] ); + + if ( num_deltas == 3 ) + { + apaint->u.rotate.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.rotate.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_ROTATE; + + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + apaint->u.skew.paint.p = child_table_p; + apaint->u.skew.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.skew.center_x = 0; + apaint->u.skew.center_y = 0; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.skew.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.skew.center_y += INT_TO_FIXED( item_deltas[3] ); + } + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SKEW; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE ) + { + FT_UInt composite_mode; + + + apaint->u.composite.source_paint.p = child_table_p; + apaint->u.composite.source_paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 1 ); + composite_mode = FT_NEXT_BYTE( p ); + if ( composite_mode >= FT_COLR_COMPOSITE_MAX ) + return 0; + + apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + apaint->u.composite.backdrop_paint.p = + child_table_p; + apaint->u.composite.backdrop_paint.insert_root_transform = + 0; + + return 1; + } + + return 0; + } + + + static FT_Bool + find_base_glyph_v1_record( FT_Byte * base_glyph_begin, + FT_UInt num_base_glyph, + FT_UInt glyph_id, + BaseGlyphV1Record *record ) + { + FT_UInt min = 0; + FT_UInt max = num_base_glyph; + + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + + /* + * `base_glyph_begin` is the beginning of `BaseGlyphV1List`; + * skip `numBaseGlyphV1Records` by adding 4 to start binary search + * in the array of `BaseGlyphV1Record`. + */ + FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE; + + FT_UShort gid = FT_NEXT_USHORT( p ); + + + if ( gid < glyph_id ) + min = mid + 1; + else if (gid > glyph_id ) + max = mid; + else + { + record->gid = gid; + record->paint_offset = FT_NEXT_ULONG ( p ); + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* opaque_paint ) + { + Colr* colr = (Colr*)face->colr; + BaseGlyphV1Record base_glyph_v1_record; + FT_Byte* p; + + if ( !colr || !colr->table ) + return 0; + + if ( colr->version < 1 || !colr->num_base_glyphs_v1 || + !colr->base_glyphs_v1 ) + return 0; + + if ( opaque_paint->p ) + return 0; + + if ( !find_base_glyph_v1_record( colr->base_glyphs_v1, + colr->num_base_glyphs_v1, + base_glyph, + &base_glyph_v1_record ) ) + return 0; + + if ( !base_glyph_v1_record.paint_offset || + base_glyph_v1_record.paint_offset > colr->table_size ) + return 0; + + p = (FT_Byte*)( colr->base_glyphs_v1 + + base_glyph_v1_record.paint_offset ); + if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p; + + if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM ) + opaque_paint->insert_root_transform = 1; + else + opaque_paint->insert_root_transform = 0; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + Colr* colr; + + FT_Byte *p, *p1, *clip_base, *limit; + + FT_Byte clip_list_format; + FT_ULong num_clip_boxes, i; + FT_UShort gid_start, gid_end; + FT_UInt32 clip_box_offset; + FT_Byte format; + + const FT_Byte num_corners = 4; + FT_Vector corners[4]; + FT_Byte j; + FT_BBox font_clip_box; + + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + if ( !colr->clip_list ) + return 0; + + p = colr->clip_list; + + /* Limit points to the first byte after the end of the color table. */ + /* Thus, in subsequent limit checks below we need to check whether the */ + /* read pointer is strictly greater than a position offset by certain */ + /* field sizes to the left of that position. */ + limit = (FT_Byte*)colr->table + colr->table_size; + + /* Check whether we can extract one `uint8` and one `uint32`. */ + if ( p > limit - ( 1 + 4 ) ) + return 0; + + clip_base = p; + clip_list_format = FT_NEXT_BYTE ( p ); + + /* Format byte used here to be able to upgrade ClipList for >16bit */ + /* glyph ids; for now we can expect it to be 1. */ + if ( !( clip_list_format == 1 ) ) + return 0; + + num_clip_boxes = FT_NEXT_ULONG( p ); + + /* Check whether we can extract two `uint16` and one `Offset24`, */ + /* `num_clip_boxes` times. */ + if ( colr->table_size / ( 2 + 2 + 3 ) < num_clip_boxes || + p > limit - ( 2 + 2 + 3 ) * num_clip_boxes ) + return 0; + + for ( i = 0; i < num_clip_boxes; ++i ) + { + gid_start = FT_NEXT_USHORT( p ); + gid_end = FT_NEXT_USHORT( p ); + clip_box_offset = FT_NEXT_UOFF3( p ); + + if ( base_glyph >= gid_start && base_glyph <= gid_end ) + { + p1 = (FT_Byte*)( clip_base + clip_box_offset ); + + /* Check whether we can extract one `uint8`. */ + if ( p1 > limit - 1 ) + return 0; + + format = FT_NEXT_BYTE( p1 ); + + if ( format > 2 ) + return 0; + + /* Check whether we can extract four `FWORD`. */ + if ( p1 > limit - ( 2 + 2 + 2 + 2 ) ) + return 0; + + /* `face->root.size->metrics.x_scale` and `y_scale` are factors */ + /* that scale a font unit value in integers to a 26.6 fixed value */ + /* according to the requested size, see for example */ + /* `ft_recompute_scaled_metrics`. */ + font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.y_scale ); + font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.y_scale ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( format == 2 ) + { + FT_ULong var_index_base = 0; + /* varIndexBase offset for clipbox is 3 at most. */ + FT_ItemVarDelta item_deltas[4] = { 0, 0, 0, 0 }; + + + /* Check whether we can extract a 32-bit varIndexBase now. */ + if ( p1 > limit - 4 ) + return 0; + + var_index_base = FT_NEXT_ULONG( p1 ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + font_clip_box.xMin += + FT_MulFix( item_deltas[0], face->root.size->metrics.x_scale ); + font_clip_box.yMin += + FT_MulFix( item_deltas[1], face->root.size->metrics.y_scale ); + font_clip_box.xMax += + FT_MulFix( item_deltas[2], face->root.size->metrics.x_scale ); + font_clip_box.yMax += + FT_MulFix( item_deltas[3], face->root.size->metrics.y_scale ); + } +#endif + + /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */ + /* them. If we we would only transform two corner points and */ + /* span a rectangle based on those, the rectangle may become too */ + /* small to cover the glyph. */ + corners[0].x = font_clip_box.xMin; + corners[1].x = font_clip_box.xMin; + corners[2].x = font_clip_box.xMax; + corners[3].x = font_clip_box.xMax; + + corners[0].y = font_clip_box.yMin; + corners[1].y = font_clip_box.yMax; + corners[2].y = font_clip_box.yMax; + corners[3].y = font_clip_box.yMin; + + for ( j = 0; j < num_corners; ++j ) + { + if ( face->root.internal->transform_flags & 1 ) + FT_Vector_Transform( &corners[j], + &face->root.internal->transform_matrix ); + + if ( face->root.internal->transform_flags & 2 ) + { + corners[j].x += face->root.internal->transform_delta.x; + corners[j].y += face->root.internal->transform_delta.y; + } + } + + clip_box->bottom_left = corners[0]; + clip_box->top_left = corners[1]; + clip_box->top_right = corners[2]; + clip_box->bottom_right = corners[3]; + + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* opaque_paint ) + { + FT_Byte* p = NULL; + FT_Byte* p_first_layer = NULL; + FT_Byte* p_paint = NULL; + FT_UInt32 paint_offset; + + Colr* colr; + + + if ( iterator->layer == iterator->num_layers ) + return 0; + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + /* + * We have an iterator pointing at a paint offset as part of the + * `paintOffset` array in `LayerV1List`. + */ + p = iterator->p; + + /* + * Do a cursor sanity check of the iterator. Counting backwards from + * where it stands, we need to end up at a position after the beginning + * of the `LayerV1List` table and not after the end of the + * `LayerV1List`. + */ + p_first_layer = p - + iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE - + LAYER_V1_LIST_NUM_LAYERS_SIZE; + if ( p_first_layer < (FT_Byte*)colr->layers_v1 ) + return 0; + if ( p_first_layer >= (FT_Byte*)( + colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) ) + return 0; + + /* + * Before reading, ensure that `p` is within 'COLR' v1 and we can read a + * 4-byte ULONG. + */ + if ( p < colr->layers_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 4 ) + return 0; + + paint_offset = + FT_NEXT_ULONG( p ); + opaque_paint->insert_root_transform = + 0; + + p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset ); + + if ( p_paint < colr->paints_start_v1 || + p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p_paint; + + iterator->p = p; + + iterator->layer++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator *iterator ) + { + Colr* colr = (Colr*)face->colr; + + FT_Byte* p; + FT_ULong var_index_base; + FT_Byte* last_entry_p = NULL; + FT_UInt entry_size = COLOR_STOP_SIZE; + + + if ( !colr || !colr->table || !iterator ) + return 0; + + if ( iterator->current_color_stop >= iterator->num_color_stops ) + return 0; + + if ( iterator->read_variable ) + entry_size += VAR_IDX_BASE_SIZE; + + /* Calculate the start pointer for the last to-be-read (Var)ColorStop */ + /* and check whether we can read a full (Var)ColorStop at that */ + /* position by comparing it to the position that is the size of one */ + /* (Var)ColorStop before the end of the 'COLR' table. */ + last_entry_p = + iterator->p + ( iterator->num_color_stops - 1 - + iterator->current_color_stop ) * entry_size; + if ( iterator->p < colr->paints_start_v1 || + last_entry_p > (FT_Byte*)colr->table + + colr->table_size - entry_size ) + return 0; + + /* Iterator points at first `ColorStop` of `ColorLine`. */ + p = iterator->p; + + color_stop->stop_offset = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + color_stop->color.palette_index = FT_NEXT_USHORT( p ); + + color_stop->color.alpha = FT_NEXT_SHORT( p ); + + if ( iterator->read_variable ) + { + /* Pointer p needs to be advanced independently of whether we intend */ + /* to take variable deltas into account or not. Otherwise iteration */ + /* would fail due to wrong offsets. */ + var_index_base = FT_NEXT_ULONG( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Int item_deltas[2]; + + + if ( !get_deltas_for_var_index_base( face, colr, + var_index_base, + 2, + item_deltas ) ) + return 0; + + color_stop->stop_offset += F2DOT14_TO_FIXED( item_deltas[0] ); + color_stop->color.alpha += (FT_F2Dot14)item_deltas[1]; + } +#else + FT_UNUSED( var_index_base ); +#endif + } + + iterator->p = p; + iterator->current_color_stop++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + Colr* colr = (Colr*)face->colr; + FT_OpaquePaint next_paint; + FT_Matrix ft_root_scale; + + if ( !colr || !colr->base_glyphs_v1 || !colr->table ) + return 0; + + if ( opaque_paint.insert_root_transform ) + { + /* 'COLR' v1 glyph information is returned in unscaled coordinates, + * i.e., `FT_Size` is not applied or multiplied into the values. When + * client applications draw color glyphs, they can request to include + * a top-level transform, which includes the active `x_scale` and + * `y_scale` information for scaling the glyph, as well the additional + * transform and translate configured through `FT_Set_Transform`. + * This allows client applications to apply this top-level transform + * to the graphics context first and only once, then have gradient and + * contour scaling applied correctly when performing the additional + * drawing operations for subsequenct paints. Prepare this initial + * transform here. + */ + paint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + next_paint.p = opaque_paint.p; + next_paint.insert_root_transform = 0; + paint->u.transform.paint = next_paint; + + /* `x_scale` and `y_scale` are in 26.6 format, representing the scale + * factor to get from font units to requested size. However, expected + * return values are in 16.16, so we shift accordingly with rounding. + */ + ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6; + ft_root_scale.xy = 0; + ft_root_scale.yx = 0; + ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6; + + if ( face->root.internal->transform_flags & 1 ) + FT_Matrix_Multiply( &face->root.internal->transform_matrix, + &ft_root_scale ); + + paint->u.transform.affine.xx = ft_root_scale.xx; + paint->u.transform.affine.xy = ft_root_scale.xy; + paint->u.transform.affine.yx = ft_root_scale.yx; + paint->u.transform.affine.yy = ft_root_scale.yy; + + /* The translation is specified in 26.6 format and, according to the + * documentation of `FT_Set_Translate`, is performed on the character + * size given in the last call to `FT_Set_Char_Size`. The + * 'PaintTransform' paint table's `FT_Affine23` format expects + * values in 16.16 format, thus we need to shift by 10 bits. + */ + if ( face->root.internal->transform_flags & 2 ) + { + paint->u.transform.affine.dx = + face->root.internal->transform_delta.x * ( 1 << 10 ); + paint->u.transform.affine.dy = + face->root.internal->transform_delta.y * ( 1 << 10 ); + } + else + { + paint->u.transform.affine.dx = 0; + paint->u.transform.affine.dy = 0; + } + + return 1; + } + + return read_paint( face, colr, opaque_paint.p, paint ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_colr_blend_layer( TT_Face face, + FT_UInt color_index, + FT_GlyphSlot dstSlot, + FT_GlyphSlot srcSlot ) + { + FT_Error error; + + FT_UInt x, y; + FT_Byte b, g, r, alpha; + + FT_ULong size; + FT_Byte* src; + FT_Byte* dst; + + + if ( !dstSlot->bitmap.buffer ) + { + /* Initialize destination of color bitmap */ + /* with the size of first component. */ + dstSlot->bitmap_left = srcSlot->bitmap_left; + dstSlot->bitmap_top = srcSlot->bitmap_top; + + dstSlot->bitmap.width = srcSlot->bitmap.width; + dstSlot->bitmap.rows = srcSlot->bitmap.rows; + dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4; + dstSlot->bitmap.num_grays = 256; + + size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch; + + error = ft_glyphslot_alloc_bitmap( dstSlot, size ); + if ( error ) + return error; + + FT_MEM_ZERO( dstSlot->bitmap.buffer, size ); + } + else + { + /* Resize destination if needed such that new component fits. */ + FT_Int x_min, x_max, y_min, y_max; + + + x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left ); + x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width, + srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width ); + + y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows, + srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows ); + y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top ); + + if ( x_min != dstSlot->bitmap_left || + x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width || + y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows || + y_max != dstSlot->bitmap_top ) + { + FT_Memory memory = face->root.memory; + + FT_UInt width = (FT_UInt)( x_max - x_min ); + FT_UInt rows = (FT_UInt)( y_max - y_min ); + FT_UInt pitch = width * 4; + + FT_Byte* buf = NULL; + FT_Byte* p; + FT_Byte* q; + + + size = rows * pitch; + if ( FT_ALLOC( buf, size ) ) + return error; + + p = dstSlot->bitmap.buffer; + q = buf + + (int)pitch * ( y_max - dstSlot->bitmap_top ) + + 4 * ( dstSlot->bitmap_left - x_min ); + + for ( y = 0; y < dstSlot->bitmap.rows; y++ ) + { + FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 ); + + p += dstSlot->bitmap.pitch; + q += pitch; + } + + ft_glyphslot_set_bitmap( dstSlot, buf ); + + dstSlot->bitmap_top = y_max; + dstSlot->bitmap_left = x_min; + + dstSlot->bitmap.width = width; + dstSlot->bitmap.rows = rows; + dstSlot->bitmap.pitch = (int)pitch; + + dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP; + dstSlot->format = FT_GLYPH_FORMAT_BITMAP; + } + } + + if ( color_index == 0xFFFF ) + { + if ( face->have_foreground_color ) + { + b = face->foreground_color.blue; + g = face->foreground_color.green; + r = face->foreground_color.red; + alpha = face->foreground_color.alpha; + } + else + { + if ( face->palette_data.palette_flags && + ( face->palette_data.palette_flags[face->palette_index] & + FT_PALETTE_FOR_DARK_BACKGROUND ) ) + { + /* white opaque */ + b = 0xFF; + g = 0xFF; + r = 0xFF; + alpha = 0xFF; + } + else + { + /* black opaque */ + b = 0x00; + g = 0x00; + r = 0x00; + alpha = 0xFF; + } + } + } + else + { + b = face->palette[color_index].blue; + g = face->palette[color_index].green; + r = face->palette[color_index].red; + alpha = face->palette[color_index].alpha; + } + + /* XXX Convert if srcSlot.bitmap is not grey? */ + src = srcSlot->bitmap.buffer; + dst = dstSlot->bitmap.buffer + + dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) + + 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left ); + + for ( y = 0; y < srcSlot->bitmap.rows; y++ ) + { + for ( x = 0; x < srcSlot->bitmap.width; x++ ) + { + int aa = src[x]; + int fa = alpha * aa / 255; + + int fb = b * fa / 255; + int fg = g * fa / 255; + int fr = r * fa / 255; + + int ba2 = 255 - fa; + + int bb = dst[4 * x + 0]; + int bg = dst[4 * x + 1]; + int br = dst[4 * x + 2]; + int ba = dst[4 * x + 3]; + + + dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb ); + dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg ); + dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr ); + dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa ); + } + + src += srcSlot->bitmap.pitch; + dst += dstSlot->bitmap.pitch; + } + + return FT_Err_Ok; + } + +#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_colr_dummy_; + +#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + +/* EOF */ diff --git a/vendor/freetype/src/sfnt/ttcolr.h b/vendor/freetype/src/sfnt/ttcolr.h new file mode 100644 index 0000000..20c85f0 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttcolr.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * + * ttcolr.h + * + * TrueType and OpenType colored glyph layer support (specification). + * + * Copyright (C) 2018-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef __TTCOLR_H__ +#define __TTCOLR_H__ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_colr( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_colr( TT_Face face ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colr_layer( TT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + + FT_LOCAL( FT_Error ) + tt_face_colr_blend_layer( TT_Face face, + FT_UInt color_index, + FT_GlyphSlot dstSlot, + FT_GlyphSlot srcSlot ); + + +FT_END_HEADER + + +#endif /* __TTCOLR_H__ */ + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttcpal.c b/vendor/freetype/src/sfnt/ttcpal.c new file mode 100644 index 0000000..46ae085 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttcpal.c @@ -0,0 +1,310 @@ +/**************************************************************************** + * + * ttcpal.c + * + * TrueType and OpenType color palette support (body). + * + * Copyright (C) 2018-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * `CPAL' table specification: + * + * https://www.microsoft.com/typography/otspec/cpal.htm + * + */ + + +#include +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS + +#include "ttcpal.h" + + + /* NOTE: These are the table sizes calculated through the specs. */ +#define CPAL_V0_HEADER_BASE_SIZE 12U +#define COLOR_SIZE 4U + + + /* all data from `CPAL' not covered in FT_Palette_Data */ + typedef struct Cpal_ + { + FT_UShort version; /* Table version number (0 or 1 supported). */ + FT_UShort num_colors; /* Total number of color records, */ + /* combined for all palettes. */ + FT_Byte* colors; /* RGBA array of colors */ + FT_Byte* color_indices; /* Index of each palette's first color record */ + /* in the combined color record array. */ + + /* The memory which backs up the `CPAL' table. */ + void* table; + FT_ULong table_size; + + } Cpal; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttcpal + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cpal( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_Byte* table = NULL; + FT_Byte* p = NULL; + + Cpal* cpal = NULL; + + FT_ULong colors_offset; + FT_ULong table_size; + + + error = face->goto_table( face, TTAG_CPAL, stream, &table_size ); + if ( error ) + goto NoCpal; + + if ( table_size < CPAL_V0_HEADER_BASE_SIZE ) + goto InvalidTable; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoCpal; + + p = table; + + if ( FT_NEW( cpal ) ) + goto NoCpal; + + cpal->version = FT_NEXT_USHORT( p ); + if ( cpal->version > 1 ) + goto InvalidTable; + + face->palette_data.num_palette_entries = FT_NEXT_USHORT( p ); + face->palette_data.num_palettes = FT_NEXT_USHORT( p ); + + cpal->num_colors = FT_NEXT_USHORT( p ); + colors_offset = FT_NEXT_ULONG( p ); + + if ( CPAL_V0_HEADER_BASE_SIZE + + face->palette_data.num_palettes * 2U > table_size ) + goto InvalidTable; + + if ( colors_offset >= table_size ) + goto InvalidTable; + if ( cpal->num_colors * COLOR_SIZE > table_size - colors_offset ) + goto InvalidTable; + + if ( face->palette_data.num_palette_entries > cpal->num_colors ) + goto InvalidTable; + + cpal->color_indices = p; + cpal->colors = (FT_Byte*)( table + colors_offset ); + + if ( cpal->version == 1 ) + { + FT_ULong type_offset, label_offset, entry_label_offset; + FT_UShort* array = NULL; + FT_UShort* limit; + FT_UShort* q; + + + if ( CPAL_V0_HEADER_BASE_SIZE + + face->palette_data.num_palettes * 2U + + 3U * 4 > table_size ) + goto InvalidTable; + + p += face->palette_data.num_palettes * 2U; + + type_offset = FT_NEXT_ULONG( p ); + label_offset = FT_NEXT_ULONG( p ); + entry_label_offset = FT_NEXT_ULONG( p ); + + if ( type_offset ) + { + if ( type_offset >= table_size ) + goto InvalidTable; + if ( face->palette_data.num_palettes * 2U > + table_size - type_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette_data.num_palettes ) ) + goto NoCpal; + + p = table + type_offset; + q = array; + limit = q + face->palette_data.num_palettes; + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette_data.palette_flags = array; + } + + if ( label_offset ) + { + if ( label_offset >= table_size ) + goto InvalidTable; + if ( face->palette_data.num_palettes * 2U > + table_size - label_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette_data.num_palettes ) ) + goto NoCpal; + + p = table + label_offset; + q = array; + limit = q + face->palette_data.num_palettes; + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette_data.palette_name_ids = array; + } + + if ( entry_label_offset ) + { + if ( entry_label_offset >= table_size ) + goto InvalidTable; + if ( face->palette_data.num_palette_entries * 2U > + table_size - entry_label_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette_data.num_palette_entries ) ) + goto NoCpal; + + p = table + entry_label_offset; + q = array; + limit = q + face->palette_data.num_palette_entries; + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette_data.palette_entry_name_ids = array; + } + } + + cpal->table = table; + cpal->table_size = table_size; + + face->cpal = cpal; + + /* set up default palette */ + if ( FT_NEW_ARRAY( face->palette, + face->palette_data.num_palette_entries ) ) + goto NoCpal; + + if ( tt_face_palette_set( face, 0 ) ) + goto InvalidTable; + + return FT_Err_Ok; + + InvalidTable: + error = FT_THROW( Invalid_Table ); + + NoCpal: + FT_FRAME_RELEASE( table ); + FT_FREE( cpal ); + + face->cpal = NULL; + + /* arrays in `face->palette_data' and `face->palette' */ + /* are freed in `sfnt_done_face' */ + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_cpal( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; + + Cpal* cpal = (Cpal*)face->cpal; + + + if ( cpal ) + { + FT_FRAME_RELEASE( cpal->table ); + FT_FREE( cpal ); + } + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_palette_set( TT_Face face, + FT_UInt palette_index ) + { + Cpal* cpal = (Cpal*)face->cpal; + + FT_Byte* offset; + FT_Byte* p; + + FT_Color* q; + FT_Color* limit; + + FT_UShort color_index; + + + if ( !cpal || palette_index >= face->palette_data.num_palettes ) + return FT_THROW( Invalid_Argument ); + + offset = cpal->color_indices + 2 * palette_index; + color_index = FT_PEEK_USHORT( offset ); + + if ( color_index + face->palette_data.num_palette_entries > + cpal->num_colors ) + return FT_THROW( Invalid_Table ); + + p = cpal->colors + COLOR_SIZE * color_index; + q = face->palette; + limit = q + face->palette_data.num_palette_entries; + + while ( q < limit ) + { + q->blue = FT_NEXT_BYTE( p ); + q->green = FT_NEXT_BYTE( p ); + q->red = FT_NEXT_BYTE( p ); + q->alpha = FT_NEXT_BYTE( p ); + + q++; + } + + return FT_Err_Ok; + } + + +#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_cpal_dummy_; + +#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + +/* EOF */ diff --git a/vendor/freetype/src/sfnt/ttcpal.h b/vendor/freetype/src/sfnt/ttcpal.h new file mode 100644 index 0000000..8e9913f --- /dev/null +++ b/vendor/freetype/src/sfnt/ttcpal.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * + * ttcpal.h + * + * TrueType and OpenType color palette support (specification). + * + * Copyright (C) 2018-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef __TTCPAL_H__ +#define __TTCPAL_H__ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_cpal( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_cpal( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_palette_set( TT_Face face, + FT_UInt palette_index ); + + +FT_END_HEADER + + +#endif /* __TTCPAL_H__ */ + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttkern.c b/vendor/freetype/src/sfnt/ttkern.c new file mode 100644 index 0000000..a47d08b --- /dev/null +++ b/vendor/freetype/src/sfnt/ttkern.c @@ -0,0 +1,317 @@ +/**************************************************************************** + * + * ttkern.c + * + * Load the basic TrueType kerning table. This doesn't handle + * kerning data within the GPOS table at the moment. + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ttkern.h" + +#include "sferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttkern + + +#undef TT_KERN_INDEX +#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt nn, num_tables; + FT_UInt32 avail = 0, ordered = 0; + + + /* the kern table is optional; exit silently if it is missing */ + error = face->goto_table( face, TTAG_kern, stream, &table_size ); + if ( error ) + goto Exit; + + if ( table_size < 4 ) /* the case of a malformed table */ + { + FT_ERROR(( "tt_face_load_kern:" + " kerning table is too small - ignored\n" )); + error = FT_THROW( Table_Missing ); + goto Exit; + } + + if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) + { + FT_ERROR(( "tt_face_load_kern:" + " could not extract kerning table\n" )); + goto Exit; + } + + face->kern_table_size = table_size; + + p = face->kern_table; + p_limit = p + table_size; + + p += 2; /* skip version */ + num_tables = FT_NEXT_USHORT( p ); + + if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ + num_tables = 32; + + for ( nn = 0; nn < num_tables; nn++ ) + { + FT_UInt num_pairs, length, coverage, format; + FT_Byte* p_next; + FT_UInt32 mask = (FT_UInt32)1UL << nn; + + + if ( p + 6 > p_limit ) + break; + + p_next = p; + + p += 2; /* skip version */ + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + + if ( length <= 6 + 8 ) + break; + + p_next += length; + + if ( p_next > p_limit ) /* handle broken table */ + p_next = p_limit; + + format = coverage >> 8; + + /* we currently only support format 0 kerning tables */ + if ( format != 0 ) + goto NextTable; + + /* only use horizontal kerning tables */ + if ( ( coverage & 3U ) != 0x0001 || + p + 8 > p_next ) + goto NextTable; + + num_pairs = FT_NEXT_USHORT( p ); + p += 6; + + if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */ + num_pairs = (FT_UInt)( ( p_next - p ) / 6 ); + + avail |= mask; + + /* + * Now check whether the pairs in this table are ordered. + * We then can use binary search. + */ + if ( num_pairs > 0 ) + { + FT_ULong count; + FT_ULong old_pair; + + + old_pair = FT_NEXT_ULONG( p ); + p += 2; + + for ( count = num_pairs - 1; count > 0; count-- ) + { + FT_UInt32 cur_pair; + + + cur_pair = FT_NEXT_ULONG( p ); + if ( cur_pair < old_pair ) + break; + + p += 2; + old_pair = cur_pair; + } + + if ( count == 0 ) + ordered |= mask; + } + + NextTable: + p = p_next; + } + + face->num_kern_tables = nn; + face->kern_avail_bits = avail; + face->kern_order_bits = ordered; + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_kern( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->kern_table ); + face->kern_table_size = 0; + face->num_kern_tables = 0; + face->kern_avail_bits = 0; + face->kern_order_bits = 0; + } + + + FT_LOCAL_DEF( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ) + { + FT_Int result = 0; + FT_UInt count, mask; + + FT_Byte* p; + FT_Byte* p_limit; + + + if ( !face->kern_table ) + return result; + + p = face->kern_table; + p_limit = p + face->kern_table_size; + + p += 4; + mask = 0x0001; + + for ( count = face->num_kern_tables; + count > 0 && p + 6 <= p_limit; + count--, mask <<= 1 ) + { + FT_Byte* base = p; + FT_Byte* next; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt length = FT_NEXT_USHORT( p ); + FT_UInt coverage = FT_NEXT_USHORT( p ); + FT_UInt num_pairs; + FT_Int value = 0; + + FT_UNUSED( version ); + + + next = base + length; + + if ( next > p_limit ) /* handle broken table */ + next = p_limit; + + if ( ( face->kern_avail_bits & mask ) == 0 ) + goto NextTable; + + FT_ASSERT( p + 8 <= next ); /* tested in tt_face_load_kern */ + + num_pairs = FT_NEXT_USHORT( p ); + p += 6; + + if ( ( next - p ) < 6 * (int)num_pairs ) /* handle broken count */ + num_pairs = (FT_UInt)( ( next - p ) / 6 ); + + switch ( coverage >> 8 ) + { + case 0: + { + FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); + + + if ( face->kern_order_bits & mask ) /* binary search */ + { + FT_UInt min = 0; + FT_UInt max = num_pairs; + + + while ( min < max ) + { + FT_UInt mid = ( min + max ) >> 1; + FT_Byte* q = p + 6 * mid; + FT_ULong key; + + + key = FT_NEXT_ULONG( q ); + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( q ); + goto Found; + } + if ( key < key0 ) + min = mid + 1; + else + max = mid; + } + } + else /* linear search */ + { + FT_UInt count2; + + + for ( count2 = num_pairs; count2 > 0; count2-- ) + { + FT_ULong key = FT_NEXT_ULONG( p ); + + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( p ); + goto Found; + } + p += 2; + } + } + } + break; + + /* + * We don't support format 2 because we haven't seen a single font + * using it in real life... + */ + + default: + ; + } + + goto NextTable; + + Found: + if ( coverage & 8 ) /* override or add */ + result = value; + else + result += value; + + NextTable: + p = next; + } + + return result; + } + +#undef TT_KERN_INDEX + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttkern.h b/vendor/freetype/src/sfnt/ttkern.h new file mode 100644 index 0000000..960c7da --- /dev/null +++ b/vendor/freetype/src/sfnt/ttkern.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * ttkern.h + * + * Load the basic TrueType kerning table. This doesn't handle + * kerning data within the GPOS table at the moment. + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTKERN_H_ +#define TTKERN_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_done_kern( TT_Face face ); + + FT_LOCAL( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + +#define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) + + +FT_END_HEADER + +#endif /* TTKERN_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttload.c b/vendor/freetype/src/sfnt/ttload.c new file mode 100644 index 0000000..7b44e9c --- /dev/null +++ b/vendor/freetype/src/sfnt/ttload.c @@ -0,0 +1,1496 @@ +/**************************************************************************** + * + * ttload.c + * + * Load the basic TrueType tables, i.e., tables that can be either in + * TTF or OTF fonts (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ttload.h" + +#include "sferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttload + + + /************************************************************************** + * + * @Function: + * tt_face_lookup_table + * + * @Description: + * Looks for a TrueType table by name. + * + * @Input: + * face :: + * A face object handle. + * + * tag :: + * The searched tag. + * + * @Return: + * A pointer to the table directory entry. 0 if not found. + */ + FT_LOCAL_DEF( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ) + { + TT_Table entry; + TT_Table limit; +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool zero_length = FALSE; +#endif + + + FT_TRACE4(( "tt_face_lookup_table: %p, `%c%c%c%c' -- ", + (void *)face, + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + + entry = face->dir_tables; + limit = entry + face->num_tables; + + for ( ; entry < limit; entry++ ) + { + /* For compatibility with Windows, we consider */ + /* zero-length tables the same as missing tables. */ + if ( entry->Tag == tag ) + { + if ( entry->Length != 0 ) + { + FT_TRACE4(( "found table.\n" )); + return entry; + } +#ifdef FT_DEBUG_LEVEL_TRACE + zero_length = TRUE; +#endif + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( zero_length ) + FT_TRACE4(( "ignoring empty table\n" )); + else + FT_TRACE4(( "could not find table\n" )); +#endif + + return NULL; + } + + + /************************************************************************** + * + * @Function: + * tt_face_goto_table + * + * @Description: + * Looks for a TrueType table by name, then seek a stream to it. + * + * @Input: + * face :: + * A face object handle. + * + * tag :: + * The searched tag. + * + * stream :: + * The stream to seek when the table is found. + * + * @Output: + * length :: + * The length of the table if found, undefined otherwise. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ) + { + TT_Table table; + FT_Error error; + + + table = tt_face_lookup_table( face, tag ); + if ( table ) + { + if ( length ) + *length = table->Length; + + if ( FT_STREAM_SEEK( table->Offset ) ) + goto Exit; + } + else + error = FT_THROW( Table_Missing ); + + Exit: + return error; + } + + + /* Here, we */ + /* */ + /* - check that `num_tables' is valid (and adjust it if necessary); */ + /* also return the number of valid table entries */ + /* */ + /* - look for a `head' table, check its size, and parse it to check */ + /* whether its `magic' field is correctly set */ + /* */ + /* - errors (except errors returned by stream handling) */ + /* */ + /* SFNT_Err_Unknown_File_Format: */ + /* no table is defined in directory, it is not sfnt-wrapped */ + /* data */ + /* SFNT_Err_Table_Missing: */ + /* table directory is valid, but essential tables */ + /* (head/bhed/SING) are missing */ + /* */ + static FT_Error + check_table_dir( SFNT_Header sfnt, + FT_Stream stream, + FT_UShort* valid ) + { + FT_Error error; + FT_UShort nn, valid_entries = 0; + FT_UInt has_head = 0, has_sing = 0, has_meta = 0; + FT_ULong offset = sfnt->offset + 12; + + static const FT_Frame_Field table_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_TableRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG( Tag ), + FT_FRAME_ULONG( CheckSum ), + FT_FRAME_ULONG( Offset ), + FT_FRAME_ULONG( Length ), + FT_FRAME_END + }; + + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + + for ( nn = 0; nn < sfnt->num_tables; nn++ ) + { + TT_TableRec table; + + + if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) + { + FT_TRACE2(( "check_table_dir:" + " can read only %hu table%s in font (instead of %hu)\n", + nn, nn == 1 ? "" : "s", sfnt->num_tables )); + sfnt->num_tables = nn; + break; + } + + /* we ignore invalid tables */ + + if ( table.Offset > stream->size ) + { + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); + continue; + } + else if ( table.Length > stream->size - table.Offset ) + { + /* Some tables have such a simple structure that clipping its */ + /* contents is harmless. This also makes FreeType less sensitive */ + /* to invalid table lengths (which programs like Acroread seem to */ + /* ignore in general). */ + + if ( table.Tag == TTAG_hmtx || + table.Tag == TTAG_vmtx ) + valid_entries++; + else + { + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); + continue; + } + } + else + valid_entries++; + + if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) + { + FT_UInt32 magic; + + +#ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + if ( table.Tag == TTAG_head ) +#endif + has_head = 1; + + /* + * The table length should be 0x36, but certain font tools make it + * 0x38, so we will just check that it is greater. + * + * Note that according to the specification, the table must be + * padded to 32-bit lengths, but this doesn't apply to the value of + * its `Length' field! + * + */ + if ( table.Length < 0x36 ) + { + FT_TRACE2(( "check_table_dir:" + " `head' or `bhed' table too small\n" )); + error = FT_THROW( Table_Missing ); + goto Exit; + } + + if ( FT_STREAM_SEEK( table.Offset + 12 ) || + FT_READ_ULONG( magic ) ) + goto Exit; + + if ( magic != 0x5F0F3CF5UL ) + FT_TRACE2(( "check_table_dir:" + " invalid magic number in `head' or `bhed' table\n")); + + if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) + goto Exit; + } + else if ( table.Tag == TTAG_SING ) + has_sing = 1; + else if ( table.Tag == TTAG_META ) + has_meta = 1; + } + + *valid = valid_entries; + + if ( !valid_entries ) + { + FT_TRACE2(( "check_table_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* if `sing' and `meta' tables are present, there is no `head' table */ + if ( has_head || ( has_sing && has_meta ) ) + { + error = FT_Err_Ok; + goto Exit; + } + else + { + FT_TRACE2(( "check_table_dir:" )); +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); +#else + FT_TRACE2(( " neither `head' nor `sing' table found\n" )); +#endif + error = FT_THROW( Table_Missing ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_font_dir + * + * @Description: + * Loads the header of a SFNT font file. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Output: + * sfnt :: + * The SFNT header. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * The stream cursor must be at the beginning of the font directory. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ) + { + SFNT_HeaderRec sfnt; + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort nn, valid_entries = 0; + + static const FT_Frame_Field offset_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE SFNT_HeaderRec + + FT_FRAME_START( 8 ), + FT_FRAME_USHORT( num_tables ), + FT_FRAME_USHORT( search_range ), + FT_FRAME_USHORT( entry_selector ), + FT_FRAME_USHORT( range_shift ), + FT_FRAME_END + }; + + + FT_TRACE2(( "tt_face_load_font_dir: %p\n", (void *)face )); + + /* read the offset table */ + + sfnt.offset = FT_STREAM_POS(); + + if ( FT_READ_ULONG( sfnt.format_tag ) || + FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) + goto Exit; + + /* many fonts don't have these fields set correctly */ +#if 0 + if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || + sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) + return FT_THROW( Unknown_File_Format ); +#endif + + /* load the table directory */ + + FT_TRACE2(( "-- Number of tables: %10hu\n", sfnt.num_tables )); + FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); + + if ( sfnt.format_tag != TTAG_OTTO ) + { + /* check first */ + error = check_table_dir( &sfnt, stream, &valid_entries ); + if ( error ) + { + FT_TRACE2(( "tt_face_load_font_dir:" + " invalid table directory for TrueType\n" )); + goto Exit; + } + } + else + { + valid_entries = sfnt.num_tables; + if ( !valid_entries ) + { + FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + } + + face->num_tables = valid_entries; + face->format_tag = sfnt.format_tag; + + if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) + goto Exit; + + if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || + FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) + goto Exit; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset length checksum\n" )); + FT_TRACE2(( " ----------------------------------\n" )); + + valid_entries = 0; + for ( nn = 0; nn < sfnt.num_tables; nn++ ) + { + TT_TableRec entry; + FT_UShort i; + FT_Bool duplicate; + + + entry.Tag = FT_GET_TAG4(); + entry.CheckSum = FT_GET_ULONG(); + entry.Offset = FT_GET_ULONG(); + entry.Length = FT_GET_ULONG(); + + /* ignore invalid tables that can't be sanitized */ + + if ( entry.Offset > stream->size ) + continue; + else if ( entry.Length > stream->size - entry.Offset ) + { + if ( entry.Tag == TTAG_hmtx || + entry.Tag == TTAG_vmtx ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_ULong old_length = entry.Length; +#endif + + + /* make metrics table length a multiple of 4 */ + entry.Length = ( stream->size - entry.Offset ) & ~3U; + + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx" + " (sanitized; original length %08lx)", + (FT_Char)( entry.Tag >> 24 ), + (FT_Char)( entry.Tag >> 16 ), + (FT_Char)( entry.Tag >> 8 ), + (FT_Char)( entry.Tag ), + entry.Offset, + entry.Length, + entry.CheckSum, + old_length )); + } + else + continue; + } +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx", + (FT_Char)( entry.Tag >> 24 ), + (FT_Char)( entry.Tag >> 16 ), + (FT_Char)( entry.Tag >> 8 ), + (FT_Char)( entry.Tag ), + entry.Offset, + entry.Length, + entry.CheckSum )); +#endif + + /* ignore duplicate tables – the first one wins */ + duplicate = 0; + for ( i = 0; i < valid_entries; i++ ) + { + if ( face->dir_tables[i].Tag == entry.Tag ) + { + duplicate = 1; + break; + } + } + if ( duplicate ) + { + FT_TRACE2(( " (duplicate, ignored)\n" )); + continue; + } + else + { + FT_TRACE2(( "\n" )); + + /* we finally have a valid entry */ + face->dir_tables[valid_entries++] = entry; + } + } + + /* final adjustment to number of tables */ + face->num_tables = valid_entries; + + FT_FRAME_EXIT(); + + if ( !valid_entries ) + { + FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + FT_TRACE2(( "table directory loaded\n" )); + FT_TRACE2(( "\n" )); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_any + * + * @Description: + * Loads any font table into client memory. + * + * @Input: + * face :: + * The face object to look for. + * + * tag :: + * The tag of table to load. Use the value 0 if you want + * to access the whole font file, else set this parameter + * to a valid TrueType table tag that you can forge with + * the MAKE_TT_TAG macro. + * + * offset :: + * The starting offset in the table (or the file if + * tag == 0). + * + * length :: + * The address of the decision variable: + * + * If length == NULL: + * Loads the whole table. Returns an error if + * `offset' == 0! + * + * If *length == 0: + * Exits immediately; returning the length of the given + * table or of the font file, depending on the value of + * `tag'. + * + * If *length != 0: + * Loads the next `length' bytes of table or font, + * starting at offset `offset' (in table or font too). + * + * @Output: + * buffer :: + * The address of target buffer. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Error error; + FT_Stream stream; + TT_Table table; + FT_ULong size; + + + if ( tag != 0 ) + { + /* look for tag in font directory */ + table = tt_face_lookup_table( face, tag ); + if ( !table ) + { + error = FT_THROW( Table_Missing ); + goto Exit; + } + + offset += table->Offset; + size = table->Length; + } + else + /* tag == 0 -- the user wants to access the font file directly */ + size = face->root.stream->size; + + if ( length && *length == 0 ) + { + *length = size; + + return FT_Err_Ok; + } + + if ( length ) + size = *length; + + stream = face->root.stream; + /* the `if' is syntactic sugar for picky compilers */ + if ( FT_STREAM_READ_AT( offset, buffer, size ) ) + goto Exit; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_generic_header + * + * @Description: + * Loads the TrueType table `head' or `bhed'. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + tt_face_load_generic_header( TT_Face face, + FT_Stream stream, + FT_ULong tag ) + { + FT_Error error; + TT_Header* header; + + static const FT_Frame_Field header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Header + + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Table_Version ), + FT_FRAME_ULONG ( Font_Revision ), + FT_FRAME_LONG ( CheckSum_Adjust ), + FT_FRAME_LONG ( Magic_Number ), + FT_FRAME_USHORT( Flags ), + FT_FRAME_USHORT( Units_Per_EM ), + FT_FRAME_ULONG ( Created[0] ), + FT_FRAME_ULONG ( Created[1] ), + FT_FRAME_ULONG ( Modified[0] ), + FT_FRAME_ULONG ( Modified[1] ), + FT_FRAME_SHORT ( xMin ), + FT_FRAME_SHORT ( yMin ), + FT_FRAME_SHORT ( xMax ), + FT_FRAME_SHORT ( yMax ), + FT_FRAME_USHORT( Mac_Style ), + FT_FRAME_USHORT( Lowest_Rec_PPEM ), + FT_FRAME_SHORT ( Font_Direction ), + FT_FRAME_SHORT ( Index_To_Loc_Format ), + FT_FRAME_SHORT ( Glyph_Data_Format ), + FT_FRAME_END + }; + + + error = face->goto_table( face, tag, stream, 0 ); + if ( error ) + goto Exit; + + header = &face->header; + + if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) + goto Exit; + + FT_TRACE3(( "Units per EM: %4hu\n", header->Units_Per_EM )); + FT_TRACE3(( "IndexToLoc: %4hd\n", header->Index_To_Loc_Format )); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_head ); + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_bhed ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + /************************************************************************** + * + * @Function: + * tt_face_load_maxp + * + * @Description: + * Loads the maximum profile into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_MaxProfile* maxProfile = &face->max_profile; + + static const FT_Frame_Field maxp_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_MaxProfile + + FT_FRAME_START( 6 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( numGlyphs ), + FT_FRAME_END + }; + + static const FT_Frame_Field maxp_fields_extra[] = + { + FT_FRAME_START( 26 ), + FT_FRAME_USHORT( maxPoints ), + FT_FRAME_USHORT( maxContours ), + FT_FRAME_USHORT( maxCompositePoints ), + FT_FRAME_USHORT( maxCompositeContours ), + FT_FRAME_USHORT( maxZones ), + FT_FRAME_USHORT( maxTwilightPoints ), + FT_FRAME_USHORT( maxStorage ), + FT_FRAME_USHORT( maxFunctionDefs ), + FT_FRAME_USHORT( maxInstructionDefs ), + FT_FRAME_USHORT( maxStackElements ), + FT_FRAME_USHORT( maxSizeOfInstructions ), + FT_FRAME_USHORT( maxComponentElements ), + FT_FRAME_USHORT( maxComponentDepth ), + FT_FRAME_END + }; + + + error = face->goto_table( face, TTAG_maxp, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) + goto Exit; + + maxProfile->maxPoints = 0; + maxProfile->maxContours = 0; + maxProfile->maxCompositePoints = 0; + maxProfile->maxCompositeContours = 0; + maxProfile->maxZones = 0; + maxProfile->maxTwilightPoints = 0; + maxProfile->maxStorage = 0; + maxProfile->maxFunctionDefs = 0; + maxProfile->maxInstructionDefs = 0; + maxProfile->maxStackElements = 0; + maxProfile->maxSizeOfInstructions = 0; + maxProfile->maxComponentElements = 0; + maxProfile->maxComponentDepth = 0; + + if ( maxProfile->version >= 0x10000L ) + { + if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) + goto Exit; + + /* XXX: an adjustment that is necessary to load certain */ + /* broken fonts like `Keystrokes MT' :-( */ + /* */ + /* We allocate 64 function entries by default when */ + /* the maxFunctionDefs value is smaller. */ + + if ( maxProfile->maxFunctionDefs < 64 ) + maxProfile->maxFunctionDefs = 64; + + /* we add 4 phantom points later */ + if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) + { + FT_TRACE0(( "tt_face_load_maxp:" + " too much twilight points in `maxp' table;\n" )); + FT_TRACE0(( " " + " some glyphs might be rendered incorrectly\n" )); + + maxProfile->maxTwilightPoints = 0xFFFFU - 4; + } + } + + FT_TRACE3(( "numGlyphs: %hu\n", maxProfile->numGlyphs )); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_name + * + * @Description: + * Loads the name records. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_pos, table_len; + FT_ULong storage_start, storage_limit; + TT_NameTable table; + TT_Name names = NULL; + TT_LangTag langTags = NULL; + + static const FT_Frame_Field name_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameTableRec + + FT_FRAME_START( 6 ), + FT_FRAME_USHORT( format ), + FT_FRAME_USHORT( numNameRecords ), + FT_FRAME_USHORT( storageOffset ), + FT_FRAME_END + }; + + static const FT_Frame_Field name_record_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameRec + + /* no FT_FRAME_START */ + FT_FRAME_USHORT( platformID ), + FT_FRAME_USHORT( encodingID ), + FT_FRAME_USHORT( languageID ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_USHORT( stringLength ), + FT_FRAME_USHORT( stringOffset ), + FT_FRAME_END + }; + + static const FT_Frame_Field langTag_record_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_LangTagRec + + /* no FT_FRAME_START */ + FT_FRAME_USHORT( stringLength ), + FT_FRAME_USHORT( stringOffset ), + FT_FRAME_END + }; + + + table = &face->name_table; + table->stream = stream; + + error = face->goto_table( face, TTAG_name, stream, &table_len ); + if ( error ) + goto Exit; + + table_pos = FT_STREAM_POS(); + + if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) + goto Exit; + + /* Some popular Asian fonts have an invalid `storageOffset' value (it */ + /* should be at least `6 + 12*numNameRecords'). However, the string */ + /* offsets, computed as `storageOffset + entry->stringOffset', are */ + /* valid pointers within the name table... */ + /* */ + /* We thus can't check `storageOffset' right now. */ + /* */ + storage_start = table_pos + 6 + 12 * table->numNameRecords; + storage_limit = table_pos + table_len; + + if ( storage_start > storage_limit ) + { + FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); + error = FT_THROW( Name_Table_Missing ); + goto Exit; + } + + /* `name' format 1 contains additional language tag records, */ + /* which we load first */ + if ( table->format == 1 ) + { + if ( FT_STREAM_SEEK( storage_start ) || + FT_READ_USHORT( table->numLangTagRecords ) ) + goto Exit; + + storage_start += 2 + 4 * table->numLangTagRecords; + + /* allocate language tag records array */ + if ( FT_QNEW_ARRAY( langTags, table->numLangTagRecords ) || + FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) + goto Exit; + + /* load language tags */ + { + TT_LangTag entry = langTags; + TT_LangTag limit = FT_OFFSET( entry, table->numLangTagRecords ); + + + for ( ; entry < limit; entry++ ) + { + (void)FT_STREAM_READ_FIELDS( langTag_record_fields, entry ); + + /* check that the langTag string is within the table */ + entry->stringOffset += table_pos + table->storageOffset; + if ( entry->stringOffset < storage_start || + entry->stringOffset + entry->stringLength > storage_limit ) + { + /* invalid entry; ignore it */ + entry->stringLength = 0; + } + + /* mark the string as not yet loaded */ + entry->string = NULL; + } + + table->langTags = langTags; + langTags = NULL; + } + + FT_FRAME_EXIT(); + + (void)FT_STREAM_SEEK( table_pos + 6 ); + } + + /* allocate name records array */ + if ( FT_QNEW_ARRAY( names, table->numNameRecords ) || + FT_FRAME_ENTER( table->numNameRecords * 12 ) ) + goto Exit; + + /* load name records */ + { + TT_Name entry = names; + FT_UInt count = table->numNameRecords; + FT_UInt valid = 0; + + + for ( ; count > 0; count-- ) + { + if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) + continue; + + /* check that the name is not empty */ + if ( entry->stringLength == 0 ) + continue; + + /* check that the name string is within the table */ + entry->stringOffset += table_pos + table->storageOffset; + if ( entry->stringOffset < storage_start || + entry->stringOffset + entry->stringLength > storage_limit ) + { + /* invalid entry; ignore it */ + continue; + } + + /* assure that we have a valid language tag ID, and */ + /* that the corresponding langTag entry is valid, too */ + if ( table->format == 1 && entry->languageID >= 0x8000U ) + { + if ( entry->languageID - 0x8000U >= table->numLangTagRecords || + !table->langTags[entry->languageID - 0x8000U].stringLength ) + { + /* invalid entry; ignore it */ + continue; + } + } + + /* mark the string as not yet converted */ + entry->string = NULL; + + valid++; + entry++; + } + + /* reduce array size to the actually used elements */ + FT_MEM_QRENEW_ARRAY( names, + table->numNameRecords, + valid ); + table->names = names; + names = NULL; + table->numNameRecords = valid; + } + + FT_FRAME_EXIT(); + + /* everything went well, update face->num_names */ + face->num_names = (FT_UShort)table->numNameRecords; + + Exit: + FT_FREE( names ); + FT_FREE( langTags ); + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_free_name + * + * @Description: + * Frees the name records. + * + * @Input: + * face :: + * A handle to the target face object. + */ + FT_LOCAL_DEF( void ) + tt_face_free_name( TT_Face face ) + { + FT_Memory memory = face->root.driver->root.memory; + TT_NameTable table = &face->name_table; + + + if ( table->names ) + { + TT_Name entry = table->names; + TT_Name limit = entry + table->numNameRecords; + + + for ( ; entry < limit; entry++ ) + FT_FREE( entry->string ); + + FT_FREE( table->names ); + } + + if ( table->langTags ) + { + TT_LangTag entry = table->langTags; + TT_LangTag limit = entry + table->numLangTagRecords; + + + for ( ; entry < limit; entry++ ) + FT_FREE( entry->string ); + + FT_FREE( table->langTags ); + } + + table->numNameRecords = 0; + table->numLangTagRecords = 0; + table->format = 0; + table->storageOffset = 0; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_cmap + * + * @Description: + * Loads the cmap directory in a face object. The cmaps themselves + * are loaded on demand in the `ttcmap.c' module. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + + + error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); + if ( error ) + goto Exit; + + if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) + face->cmap_size = 0; + + Exit: + return error; + } + + + + /************************************************************************** + * + * @Function: + * tt_face_load_os2 + * + * @Description: + * Loads the OS2 table. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_OS2* os2; + + static const FT_Frame_Field os2_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_OS2 + + FT_FRAME_START( 78 ), + FT_FRAME_USHORT( version ), + FT_FRAME_SHORT ( xAvgCharWidth ), + FT_FRAME_USHORT( usWeightClass ), + FT_FRAME_USHORT( usWidthClass ), + FT_FRAME_SHORT ( fsType ), + FT_FRAME_SHORT ( ySubscriptXSize ), + FT_FRAME_SHORT ( ySubscriptYSize ), + FT_FRAME_SHORT ( ySubscriptXOffset ), + FT_FRAME_SHORT ( ySubscriptYOffset ), + FT_FRAME_SHORT ( ySuperscriptXSize ), + FT_FRAME_SHORT ( ySuperscriptYSize ), + FT_FRAME_SHORT ( ySuperscriptXOffset ), + FT_FRAME_SHORT ( ySuperscriptYOffset ), + FT_FRAME_SHORT ( yStrikeoutSize ), + FT_FRAME_SHORT ( yStrikeoutPosition ), + FT_FRAME_SHORT ( sFamilyClass ), + FT_FRAME_BYTE ( panose[0] ), + FT_FRAME_BYTE ( panose[1] ), + FT_FRAME_BYTE ( panose[2] ), + FT_FRAME_BYTE ( panose[3] ), + FT_FRAME_BYTE ( panose[4] ), + FT_FRAME_BYTE ( panose[5] ), + FT_FRAME_BYTE ( panose[6] ), + FT_FRAME_BYTE ( panose[7] ), + FT_FRAME_BYTE ( panose[8] ), + FT_FRAME_BYTE ( panose[9] ), + FT_FRAME_ULONG ( ulUnicodeRange1 ), + FT_FRAME_ULONG ( ulUnicodeRange2 ), + FT_FRAME_ULONG ( ulUnicodeRange3 ), + FT_FRAME_ULONG ( ulUnicodeRange4 ), + FT_FRAME_BYTE ( achVendID[0] ), + FT_FRAME_BYTE ( achVendID[1] ), + FT_FRAME_BYTE ( achVendID[2] ), + FT_FRAME_BYTE ( achVendID[3] ), + + FT_FRAME_USHORT( fsSelection ), + FT_FRAME_USHORT( usFirstCharIndex ), + FT_FRAME_USHORT( usLastCharIndex ), + FT_FRAME_SHORT ( sTypoAscender ), + FT_FRAME_SHORT ( sTypoDescender ), + FT_FRAME_SHORT ( sTypoLineGap ), + FT_FRAME_USHORT( usWinAscent ), + FT_FRAME_USHORT( usWinDescent ), + FT_FRAME_END + }; + + /* `OS/2' version 1 and newer */ + static const FT_Frame_Field os2_fields_extra1[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_ULONG( ulCodePageRange1 ), + FT_FRAME_ULONG( ulCodePageRange2 ), + FT_FRAME_END + }; + + /* `OS/2' version 2 and newer */ + static const FT_Frame_Field os2_fields_extra2[] = + { + FT_FRAME_START( 10 ), + FT_FRAME_SHORT ( sxHeight ), + FT_FRAME_SHORT ( sCapHeight ), + FT_FRAME_USHORT( usDefaultChar ), + FT_FRAME_USHORT( usBreakChar ), + FT_FRAME_USHORT( usMaxContext ), + FT_FRAME_END + }; + + /* `OS/2' version 5 and newer */ + static const FT_Frame_Field os2_fields_extra5[] = + { + FT_FRAME_START( 4 ), + FT_FRAME_USHORT( usLowerOpticalPointSize ), + FT_FRAME_USHORT( usUpperOpticalPointSize ), + FT_FRAME_END + }; + + + /* We now support old Mac fonts where the OS/2 table doesn't */ + /* exist. Simply put, we set the `version' field to 0xFFFF */ + /* and test this value each time we need to access the table. */ + error = face->goto_table( face, TTAG_OS2, stream, 0 ); + if ( error ) + goto Exit; + + os2 = &face->os2; + + if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) + goto Exit; + + os2->ulCodePageRange1 = 0; + os2->ulCodePageRange2 = 0; + os2->sxHeight = 0; + os2->sCapHeight = 0; + os2->usDefaultChar = 0; + os2->usBreakChar = 0; + os2->usMaxContext = 0; + os2->usLowerOpticalPointSize = 0; + os2->usUpperOpticalPointSize = 0xFFFF; + + if ( os2->version >= 0x0001 ) + { + /* only version 1 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra1, os2 ) ) + goto Exit; + + if ( os2->version >= 0x0002 ) + { + /* only version 2 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) + goto Exit; + + if ( os2->version >= 0x0005 ) + { + /* only version 5 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra5, os2 ) ) + goto Exit; + } + } + } + + FT_TRACE3(( "sTypoAscender: %4hd\n", os2->sTypoAscender )); + FT_TRACE3(( "sTypoDescender: %4hd\n", os2->sTypoDescender )); + FT_TRACE3(( "usWinAscent: %4hu\n", os2->usWinAscent )); + FT_TRACE3(( "usWinDescent: %4hu\n", os2->usWinDescent )); + FT_TRACE3(( "fsSelection: 0x%2hx\n", os2->fsSelection )); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_postscript + * + * @Description: + * Loads the Postscript table. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_Postscript* post = &face->postscript; + + static const FT_Frame_Field post_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Postscript + + FT_FRAME_START( 32 ), + FT_FRAME_LONG ( FormatType ), + FT_FRAME_LONG ( italicAngle ), + FT_FRAME_SHORT( underlinePosition ), + FT_FRAME_SHORT( underlineThickness ), + FT_FRAME_ULONG( isFixedPitch ), + FT_FRAME_ULONG( minMemType42 ), + FT_FRAME_ULONG( maxMemType42 ), + FT_FRAME_ULONG( minMemType1 ), + FT_FRAME_ULONG( maxMemType1 ), + FT_FRAME_END + }; + + + error = face->goto_table( face, TTAG_post, stream, 0 ); + if ( error ) + return error; + + if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) + return error; + + if ( post->FormatType != 0x00030000L && + post->FormatType != 0x00025000L && + post->FormatType != 0x00020000L && + post->FormatType != 0x00010000L ) + return FT_THROW( Invalid_Post_Table_Format ); + + /* we don't load the glyph names, we do that in another */ + /* module (ttpost). */ + + FT_TRACE3(( "FormatType: 0x%lx\n", post->FormatType )); + FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch + ? " yes" : " no" )); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_pclt + * + * @Description: + * Loads the PCL 5 Table. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ) + { + static const FT_Frame_Field pclt_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_PCLT + + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_ULONG ( FontNumber ), + FT_FRAME_USHORT( Pitch ), + FT_FRAME_USHORT( xHeight ), + FT_FRAME_USHORT( Style ), + FT_FRAME_USHORT( TypeFamily ), + FT_FRAME_USHORT( CapHeight ), + FT_FRAME_USHORT( SymbolSet ), + FT_FRAME_BYTES ( TypeFace, 16 ), + FT_FRAME_BYTES ( CharacterComplement, 8 ), + FT_FRAME_BYTES ( FileName, 6 ), + FT_FRAME_CHAR ( StrokeWeight ), + FT_FRAME_CHAR ( WidthType ), + FT_FRAME_BYTE ( SerifStyle ), + FT_FRAME_BYTE ( Reserved ), + FT_FRAME_END + }; + + FT_Error error; + TT_PCLT* pclt = &face->pclt; + + + /* optional table */ + error = face->goto_table( face, TTAG_PCLT, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) + goto Exit; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_gasp + * + * @Description: + * Loads the `gasp' table into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort j, num_ranges; + TT_GaspRange gasp_ranges = NULL; + + + /* the gasp table is optional */ + error = face->goto_table( face, TTAG_gasp, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_FRAME_ENTER( 4L ) ) + goto Exit; + + face->gasp.version = FT_GET_USHORT(); + num_ranges = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + + /* only support versions 0 and 1 of the table */ + if ( face->gasp.version >= 2 ) + { + face->gasp.numRanges = 0; + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE3(( "numRanges: %hu\n", num_ranges )); + + if ( FT_QNEW_ARRAY( gasp_ranges, num_ranges ) || + FT_FRAME_ENTER( num_ranges * 4L ) ) + goto Exit; + + for ( j = 0; j < num_ranges; j++ ) + { + gasp_ranges[j].maxPPEM = FT_GET_USHORT(); + gasp_ranges[j].gaspFlag = FT_GET_USHORT(); + + FT_TRACE3(( "gaspRange %hu: rangeMaxPPEM %5hu, rangeGaspBehavior 0x%hx\n", + j, + gasp_ranges[j].maxPPEM, + gasp_ranges[j].gaspFlag )); + } + + face->gasp.gaspRanges = gasp_ranges; + gasp_ranges = NULL; + face->gasp.numRanges = num_ranges; + + FT_FRAME_EXIT(); + + Exit: + FT_FREE( gasp_ranges ); + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttload.h b/vendor/freetype/src/sfnt/ttload.h new file mode 100644 index 0000000..1499dd5 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttload.h @@ -0,0 +1,111 @@ +/**************************************************************************** + * + * ttload.h + * + * Load the basic TrueType tables, i.e., tables that can be either in + * TTF or OTF fonts (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTLOAD_H_ +#define TTLOAD_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ); + + FT_LOCAL( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + FT_LOCAL( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + FT_LOCAL( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_name( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ); + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + +FT_END_HEADER + +#endif /* TTLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttmtx.c b/vendor/freetype/src/sfnt/ttmtx.c new file mode 100644 index 0000000..38ee9ae --- /dev/null +++ b/vendor/freetype/src/sfnt/ttmtx.c @@ -0,0 +1,338 @@ +/**************************************************************************** + * + * ttmtx.c + * + * Load the metrics tables common to TTF and OTF fonts (body). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#endif + +#include "ttmtx.h" + +#include "sferrors.h" + + + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields, */ + /* which are different. */ + /* */ + /* This ensures that `tt_face_load_hmtx' is able to read */ + /* both the horizontal and vertical headers. */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttmtx + + + /************************************************************************** + * + * @Function: + * tt_face_load_hmtx + * + * @Description: + * Load the `hmtx' or `vmtx' table into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * vertical :: + * A boolean flag. If set, load `vmtx'. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + FT_ULong tag, table_size; + FT_ULong* ptable_offset; + FT_ULong* ptable_size; + + + if ( vertical ) + { + tag = TTAG_vmtx; + ptable_offset = &face->vert_metrics_offset; + ptable_size = &face->vert_metrics_size; + } + else + { + tag = TTAG_hmtx; + ptable_offset = &face->horz_metrics_offset; + ptable_size = &face->horz_metrics_size; + } + + error = face->goto_table( face, tag, stream, &table_size ); + if ( error ) + goto Fail; + + *ptable_size = table_size; + *ptable_offset = FT_STREAM_POS(); + + Fail: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_hhea + * + * @Description: + * Load the `hhea' or 'vhea' table into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * vertical :: + * A boolean flag. If set, load `vhea'. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + TT_HoriHeader* header; + + static const FT_Frame_Field metrics_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_HoriHeader + + FT_FRAME_START( 36 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_SHORT ( Ascender ), + FT_FRAME_SHORT ( Descender ), + FT_FRAME_SHORT ( Line_Gap ), + FT_FRAME_USHORT( advance_Width_Max ), + FT_FRAME_SHORT ( min_Left_Side_Bearing ), + FT_FRAME_SHORT ( min_Right_Side_Bearing ), + FT_FRAME_SHORT ( xMax_Extent ), + FT_FRAME_SHORT ( caret_Slope_Rise ), + FT_FRAME_SHORT ( caret_Slope_Run ), + FT_FRAME_SHORT ( caret_Offset ), + FT_FRAME_SHORT ( Reserved[0] ), + FT_FRAME_SHORT ( Reserved[1] ), + FT_FRAME_SHORT ( Reserved[2] ), + FT_FRAME_SHORT ( Reserved[3] ), + FT_FRAME_SHORT ( metric_Data_Format ), + FT_FRAME_USHORT( number_Of_HMetrics ), + FT_FRAME_END + }; + + + if ( vertical ) + { + void *v = &face->vertical; + + + error = face->goto_table( face, TTAG_vhea, stream, 0 ); + if ( error ) + goto Fail; + + header = (TT_HoriHeader*)v; + } + else + { + error = face->goto_table( face, TTAG_hhea, stream, 0 ); + if ( error ) + goto Fail; + + header = &face->horizontal; + } + + if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) + goto Fail; + + FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); + FT_TRACE3(( "Descender: %5d\n", header->Descender )); + FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); + + header->long_metrics = NULL; + header->short_metrics = NULL; + + Fail: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_get_metrics + * + * @Description: + * Return the horizontal or vertical metrics in font units for a + * given glyph. The values are the left side bearing (top side + * bearing for vertical metrics) and advance width (advance height + * for vertical metrics). + * + * @Input: + * face :: + * A pointer to the TrueType face structure. + * + * vertical :: + * If set to TRUE, get vertical metrics. + * + * gindex :: + * The glyph index. + * + * @Output: + * abearing :: + * The bearing, either left side or top side. + * + * aadvance :: + * The advance width or advance height, depending on + * the `vertical' flag. + */ + FT_LOCAL_DEF( void ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short *abearing, + FT_UShort *aadvance ) + { + FT_Error error; + FT_Stream stream = face->root.stream; + TT_HoriHeader* header; + FT_ULong table_pos, table_size, table_end; + FT_UShort k; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Service_MetricsVariations var = + (FT_Service_MetricsVariations)face->tt_var; +#endif + + + if ( vertical ) + { + void* v = &face->vertical; + + + header = (TT_HoriHeader*)v; + table_pos = face->vert_metrics_offset; + table_size = face->vert_metrics_size; + } + else + { + header = &face->horizontal; + table_pos = face->horz_metrics_offset; + table_size = face->horz_metrics_size; + } + + table_end = table_pos + table_size; + + k = header->number_Of_HMetrics; + + if ( k > 0 ) + { + if ( gindex < (FT_UInt)k ) + { + table_pos += 4 * gindex; + if ( table_pos + 4 > table_end ) + goto NoData; + + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) || + FT_READ_SHORT( *abearing ) ) + goto NoData; + } + else + { + table_pos += 4 * ( k - 1 ); + if ( table_pos + 2 > table_end ) + goto NoData; + + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) ) + goto NoData; + + table_pos += 4 + 2 * ( gindex - k ); + if ( table_pos + 2 > table_end ) + *abearing = 0; + else + { + if ( FT_STREAM_SEEK( table_pos ) ) + *abearing = 0; + else + (void)FT_READ_SHORT( *abearing ); + } + } + } + else + { + NoData: + *abearing = 0; + *aadvance = 0; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( var && face->blend ) + { + FT_Face f = FT_FACE( face ); + FT_Int a = (FT_Int)*aadvance; + FT_Int b = (FT_Int)*abearing; + + + if ( vertical ) + { + if ( var->vadvance_adjust ) + var->vadvance_adjust( f, gindex, &a ); + if ( var->tsb_adjust ) + var->tsb_adjust( f, gindex, &b ); + } + else + { + if ( var->hadvance_adjust ) + var->hadvance_adjust( f, gindex, &a ); + if ( var->lsb_adjust ) + var->lsb_adjust( f, gindex, &b ); + } + + *aadvance = (FT_UShort)a; + *abearing = (FT_Short)b; + } +#endif + } + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttmtx.h b/vendor/freetype/src/sfnt/ttmtx.h new file mode 100644 index 0000000..56d2b62 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttmtx.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * ttmtx.h + * + * Load the metrics tables common to TTF and OTF fonts (specification). + * + * Copyright (C) 2006-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTMTX_H_ +#define TTMTX_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + FT_LOCAL( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + FT_LOCAL( void ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); + +FT_END_HEADER + +#endif /* TTMTX_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttpost.c b/vendor/freetype/src/sfnt/ttpost.c new file mode 100644 index 0000000..1dfad42 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttpost.c @@ -0,0 +1,484 @@ +/**************************************************************************** + * + * ttpost.c + * + * PostScript name table processing for TrueType and OpenType fonts + * (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * The post table is not completely loaded by the core engine. This + * file loads the missing PS glyph names and implements an API to access + * them. + * + */ + + +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + +#include "ttpost.h" + +#include "sferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttpost + + + /* If this configuration macro is defined, we rely on the `psnames' */ + /* module to grab the glyph names. */ + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + +#include + +#define MAC_NAME( x ) (FT_String*)psnames->macintosh_name( (FT_UInt)(x) ) + + +#else /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + /* Otherwise, we ignore the `psnames' module, and provide our own */ + /* table of Mac names. Thus, it is possible to build a version of */ + /* FreeType without the Type 1 driver & psnames module. */ + +#define MAC_NAME( x ) (FT_String*)tt_post_default_names[x] + + /* the 258 default Mac PS glyph names; see file `tools/glnames.py' */ + + static const FT_String* const tt_post_default_names[258] = + { + /* 0 */ + ".notdef", ".null", "nonmarkingreturn", "space", "exclam", + "quotedbl", "numbersign", "dollar", "percent", "ampersand", + /* 10 */ + "quotesingle", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", + /* 20 */ + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "colon", + /* 30 */ + "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", + /* 40 */ + "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", + /* 50 */ + "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", + /* 60 */ + "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "grave", "a", "b", + /* 70 */ + "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", + /* 80 */ + "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", + /* 90 */ + "w", "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", "Adieresis", "Aring", + /* 100 */ + "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", + "aacute", "agrave", "acircumflex", "adieresis", "atilde", + /* 110 */ + "aring", "ccedilla", "eacute", "egrave", "ecircumflex", + "edieresis", "iacute", "igrave", "icircumflex", "idieresis", + /* 120 */ + "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", + "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + /* 130 */ + "dagger", "degree", "cent", "sterling", "section", + "bullet", "paragraph", "germandbls", "registered", "copyright", + /* 140 */ + "trademark", "acute", "dieresis", "notequal", "AE", + "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", + /* 150 */ + "yen", "mu", "partialdiff", "summation", "product", + "pi", "integral", "ordfeminine", "ordmasculine", "Omega", + /* 160 */ + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", + "radical", "florin", "approxequal", "Delta", "guillemotleft", + /* 170 */ + "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", + "Otilde", "OE", "oe", "endash", "emdash", + /* 180 */ + "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", + "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", + /* 190 */ + "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", + "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + /* 200 */ + "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", + "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", + /* 210 */ + "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", + "dotlessi", "circumflex", "tilde", "macron", "breve", + /* 220 */ + "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", + "caron", "Lslash", "lslash", "Scaron", "scaron", + /* 230 */ + "Zcaron", "zcaron", "brokenbar", "Eth", "eth", + "Yacute", "yacute", "Thorn", "thorn", "minus", + /* 240 */ + "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", + "onequarter", "threequarters", "franc", "Gbreve", "gbreve", + /* 250 */ + "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", + "Ccaron", "ccaron", "dcroat", + }; + + +#endif /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + static FT_Error + load_format_20( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort n; + FT_UShort num_names = 0; + + FT_UShort* glyph_indices = NULL; + FT_Byte** name_strings = NULL; + FT_Byte* q; + + + if ( (FT_ULong)num_glyphs * 2 > post_len ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* load the indices and note their maximum */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs * 2 ) ) + goto Fail; + + q = (FT_Byte*)stream->cursor; + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_UShort idx = FT_NEXT_USHORT( q ); + + + if ( idx > num_names ) + num_names = idx; + + glyph_indices[n] = idx; + } + + FT_FRAME_EXIT(); + + /* compute number of names stored in the table */ + num_names = num_names > 257 ? num_names - 257 : 0; + + /* now load the name strings */ + if ( num_names ) + { + FT_ULong p; + FT_Byte* strings; + + + post_len -= (FT_ULong)num_glyphs * 2; + + if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) + + post_len + 1 ) ) + goto Fail; + + strings = (FT_Byte*)( name_strings + num_names ); + if ( FT_STREAM_READ( strings, post_len ) ) + goto Fail; + + /* convert from Pascal- to C-strings and set pointers */ + for ( p = 0, n = 0; p < post_len && n < num_names; n++ ) + { + FT_UInt len = strings[p]; + + + if ( len > 63U ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + strings[p] = 0; + name_strings[n] = strings + p + 1; + p += len + 1; + } + strings[post_len] = 0; + + /* deal with missing or insufficient string data */ + if ( n < num_names ) + { + FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n", + num_names - n )); + + for ( ; n < num_names; n++ ) + name_strings[n] = strings + post_len; + } + } + + /* all right, set table fields and exit successfully */ + names->num_glyphs = num_glyphs; + names->num_names = num_names; + names->glyph_indices = glyph_indices; + names->glyph_names = name_strings; + + return FT_Err_Ok; + + Fail: + FT_FREE( name_strings ); + FT_FREE( glyph_indices ); + + Exit: + return error; + } + + + static FT_Error + load_format_25( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort n; + FT_UShort* glyph_indices = NULL; + FT_Byte* q; + + + /* check the number of glyphs, including the theoretical limit */ + if ( num_glyphs > post_len || + num_glyphs > 258 + 128 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* load the indices and check their Mac range */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs ) ) + goto Fail; + + q = (FT_Byte*)stream->cursor; + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Int idx = n + FT_NEXT_CHAR( q ); + + + if ( idx < 0 || idx > 257 ) + idx = 0; + + glyph_indices[n] = (FT_UShort)idx; + } + + FT_FRAME_EXIT(); + + /* OK, set table fields and exit successfully */ + names->num_glyphs = num_glyphs; + names->glyph_indices = glyph_indices; + + return FT_Err_Ok; + + Fail: + FT_FREE( glyph_indices ); + + Exit: + return error; + } + + + static FT_Error + load_post_names( TT_Face face ) + { + FT_Error error = FT_Err_Ok; + FT_Stream stream = face->root.stream; + FT_Fixed format = face->postscript.FormatType; + FT_ULong post_len; + FT_UShort num_glyphs; + + + /* seek to the beginning of the PS names table */ + error = face->goto_table( face, TTAG_post, stream, &post_len ); + if ( error ) + goto Exit; + + /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ + /* than the value in the maxp table (cf. cyberbit.ttf). */ + if ( post_len < 34 || + FT_STREAM_SKIP( 32 ) || + FT_READ_USHORT( num_glyphs ) || + num_glyphs > face->max_profile.numGlyphs || + num_glyphs == 0 ) + goto Exit; + + /* now read postscript names data */ + if ( format == 0x00020000L ) + error = load_format_20( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); + else if ( format == 0x00025000L ) + error = load_format_25( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); + + Exit: + face->postscript_names.loaded = 1; /* even if failed */ + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_ps_names( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_Post_Names names = &face->postscript_names; + + + if ( names->num_glyphs ) + { + FT_FREE( names->glyph_indices ); + names->num_glyphs = 0; + } + + if ( names->num_names ) + { + FT_FREE( names->glyph_names ); + names->num_names = 0; + } + + names->loaded = 0; + } + + + /************************************************************************** + * + * @Function: + * tt_face_get_ps_name + * + * @Description: + * Get the PostScript glyph name of a glyph. + * + * @Input: + * face :: + * A handle to the parent face. + * + * idx :: + * The glyph index. + * + * @InOut: + * PSname :: + * The address of a string pointer. Undefined in case of + * error, otherwise it is a pointer to the glyph name. + * + * You must not modify the returned string! + * + * @Output: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ) + { + FT_Error error; + FT_Fixed format; + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_Service_PsCMaps psnames; +#endif + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) + return FT_THROW( Invalid_Glyph_Index ); + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + psnames = (FT_Service_PsCMaps)face->psnames; + if ( !psnames ) + return FT_THROW( Unimplemented_Feature ); +#endif + + /* `.notdef' by default */ + *PSname = MAC_NAME( 0 ); + + format = face->postscript.FormatType; + + if ( format == 0x00010000L ) + { + if ( idx < 258 ) /* paranoid checking */ + *PSname = MAC_NAME( idx ); + } + else if ( format == 0x00020000L || + format == 0x00025000L ) + { + TT_Post_Names names = &face->postscript_names; + + + if ( !names->loaded ) + { + error = load_post_names( face ); + if ( error ) + goto End; + } + + if ( idx < (FT_UInt)names->num_glyphs ) + { + FT_UShort name_index = names->glyph_indices[idx]; + + + if ( name_index < 258 ) + *PSname = MAC_NAME( name_index ); + else /* only for version 2.0 */ + *PSname = (FT_String*)names->glyph_names[name_index - 258]; + } + } + + /* nothing to do for format == 0x00030000L */ + + End: + /* post format errors ignored */ + return FT_Err_Ok; + } + +#else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_post_dummy_; + +#endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttpost.h b/vendor/freetype/src/sfnt/ttpost.h new file mode 100644 index 0000000..528f1c5 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttpost.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * ttpost.h + * + * PostScript name table processing for TrueType and OpenType fonts + * (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTPOST_H_ +#define TTPOST_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + + FT_LOCAL( void ) + tt_face_free_ps_names( TT_Face face ); + + +FT_END_HEADER + +#endif /* TTPOST_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttsbit.c b/vendor/freetype/src/sfnt/ttsbit.c new file mode 100644 index 0000000..03f90a6 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttsbit.c @@ -0,0 +1,1685 @@ +/**************************************************************************** + * + * ttsbit.c + * + * TrueType and OpenType embedded bitmap support (body). + * + * Copyright (C) 2005-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2013 by Google, Inc. + * Google Author(s): Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + +#include "ttsbit.h" + +#include "sferrors.h" + +#include "ttmtx.h" +#include "pngshim.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttsbit + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_sbit( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + FT_ULong table_start; + + + face->sbit_table = NULL; + face->sbit_table_size = 0; + face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; + face->sbit_num_strikes = 0; + + error = face->goto_table( face, TTAG_CBLC, stream, &table_size ); + if ( !error ) + face->sbit_table_type = TT_SBIT_TABLE_TYPE_CBLC; + else + { + error = face->goto_table( face, TTAG_EBLC, stream, &table_size ); + if ( error ) + error = face->goto_table( face, TTAG_bloc, stream, &table_size ); + if ( !error ) + face->sbit_table_type = TT_SBIT_TABLE_TYPE_EBLC; + } + + if ( error ) + { + error = face->goto_table( face, TTAG_sbix, stream, &table_size ); + if ( !error ) + face->sbit_table_type = TT_SBIT_TABLE_TYPE_SBIX; + } + if ( error ) + goto Exit; + + if ( table_size < 8 ) + { + FT_ERROR(( "tt_face_load_sbit_strikes: table too short\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + table_start = FT_STREAM_POS(); + + switch ( (FT_UInt)face->sbit_table_type ) + { + case TT_SBIT_TABLE_TYPE_EBLC: + case TT_SBIT_TABLE_TYPE_CBLC: + { + FT_Byte* p; + FT_Fixed version; + FT_ULong num_strikes; + FT_UInt count; + + + if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) ) + goto Exit; + + face->sbit_table_size = table_size; + + p = face->sbit_table; + + version = FT_NEXT_LONG( p ); + num_strikes = FT_NEXT_ULONG( p ); + + /* there's at least one font (FZShuSong-Z01, version 3) */ + /* that uses the wrong byte order for the `version' field */ + if ( ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00020000UL && + ( (FT_ULong)version & 0x0000FFFFUL ) != 0x00000200UL && + ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00030000UL && + ( (FT_ULong)version & 0x0000FFFFUL ) != 0x00000300UL ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( num_strikes >= 0x10000UL ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* + * Count the number of strikes available in the table. We are a bit + * paranoid there and don't trust the data. + */ + count = (FT_UInt)num_strikes; + if ( 8 + 48UL * count > table_size ) + count = (FT_UInt)( ( table_size - 8 ) / 48 ); + + face->sbit_num_strikes = count; + } + break; + + case TT_SBIT_TABLE_TYPE_SBIX: + { + FT_UShort version; + FT_UShort flags; + FT_ULong num_strikes; + FT_UInt count; + + + if ( FT_FRAME_ENTER( 8 ) ) + goto Exit; + + version = FT_GET_USHORT(); + flags = FT_GET_USHORT(); + num_strikes = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + + if ( version < 1 ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* Bit 0 must always be `1'. */ + /* Bit 1 controls the overlay of bitmaps with outlines. */ + /* All other bits should be zero. */ + if ( !( flags == 1 || flags == 3 ) || + num_strikes >= 0x10000UL ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( flags == 3 ) + face->root.face_flags |= FT_FACE_FLAG_SBIX_OVERLAY; + + /* + * Count the number of strikes available in the table. We are a bit + * paranoid there and don't trust the data. + */ + count = (FT_UInt)num_strikes; + if ( 8 + 4UL * count > table_size ) + count = (FT_UInt)( ( table_size - 8 ) / 4 ); + + if ( FT_STREAM_SEEK( FT_STREAM_POS() - 8 ) ) + goto Exit; + + face->sbit_table_size = 8 + count * 4; + if ( FT_FRAME_EXTRACT( face->sbit_table_size, face->sbit_table ) ) + goto Exit; + + face->sbit_num_strikes = count; + } + break; + + default: + /* we ignore unknown table formats */ + error = FT_THROW( Unknown_File_Format ); + break; + } + + if ( !error ) + FT_TRACE3(( "tt_face_load_sbit_strikes: found %u strikes\n", + face->sbit_num_strikes )); + + face->ebdt_start = 0; + face->ebdt_size = 0; + + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX ) + { + /* the `sbix' table is self-contained; */ + /* it has no associated data table */ + face->ebdt_start = table_start; + face->ebdt_size = table_size; + } + else if ( face->sbit_table_type != TT_SBIT_TABLE_TYPE_NONE ) + { + FT_ULong ebdt_size; + + + error = face->goto_table( face, TTAG_CBDT, stream, &ebdt_size ); + if ( error ) + error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size ); + if ( error ) + error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size ); + + if ( !error ) + { + face->ebdt_start = FT_STREAM_POS(); + face->ebdt_size = ebdt_size; + } + } + + if ( !face->ebdt_size ) + { + FT_TRACE2(( "tt_face_load_sbit_strikes:" + " no embedded bitmap data table found;\n" )); + FT_TRACE2(( " " + " resetting number of strikes to zero\n" )); + face->sbit_num_strikes = 0; + } + + return FT_Err_Ok; + + Exit: + if ( error ) + { + if ( face->sbit_table ) + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; + } + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_sbit( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; + face->sbit_num_strikes = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ) + { + return FT_Match_Size( (FT_Face)face, req, 0, astrike_index ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ) + { + /* we have to test for the existence of `sbit_strike_map' */ + /* because the function gets also used at the very beginning */ + /* to construct `sbit_strike_map' itself */ + if ( face->sbit_strike_map ) + { + if ( strike_index >= (FT_ULong)face->root.num_fixed_sizes ) + return FT_THROW( Invalid_Argument ); + + /* map to real index */ + strike_index = face->sbit_strike_map[strike_index]; + } + else + { + if ( strike_index >= (FT_ULong)face->sbit_num_strikes ) + return FT_THROW( Invalid_Argument ); + } + + switch ( (FT_UInt)face->sbit_table_type ) + { + case TT_SBIT_TABLE_TYPE_EBLC: + case TT_SBIT_TABLE_TYPE_CBLC: + { + FT_Byte* strike; + FT_Char max_before_bl; + FT_Char min_after_bl; + + + strike = face->sbit_table + 8 + strike_index * 48; + + metrics->x_ppem = (FT_UShort)strike[44]; + metrics->y_ppem = (FT_UShort)strike[45]; + + metrics->ascender = (FT_Char)strike[16] * 64; /* hori.ascender */ + metrics->descender = (FT_Char)strike[17] * 64; /* hori.descender */ + + /* Due to fuzzy wording in the EBLC documentation, we find both */ + /* positive and negative values for `descender'. Additionally, */ + /* many fonts have both `ascender' and `descender' set to zero */ + /* (which is definitely wrong). MS Windows simply ignores all */ + /* those values... For these reasons we apply some heuristics */ + /* to get a reasonable, non-zero value for the height. */ + + max_before_bl = (FT_Char)strike[24]; + min_after_bl = (FT_Char)strike[25]; + + if ( metrics->descender > 0 ) + { + /* compare sign of descender with `min_after_bl' */ + if ( min_after_bl < 0 ) + metrics->descender = -metrics->descender; + } + + else if ( metrics->descender == 0 ) + { + if ( metrics->ascender == 0 ) + { + FT_TRACE2(( "tt_face_load_strike_metrics:" + " sanitizing invalid ascender and descender\n" )); + FT_TRACE2(( " " + " values for strike %ld (%dppem, %dppem)\n", + strike_index, + metrics->x_ppem, metrics->y_ppem )); + + /* sanitize buggy ascender and descender values */ + if ( max_before_bl || min_after_bl ) + { + metrics->ascender = max_before_bl * 64; + metrics->descender = min_after_bl * 64; + } + else + { + metrics->ascender = metrics->y_ppem * 64; + metrics->descender = 0; + } + } + } + +#if 0 + else + ; /* if we have a negative descender, simply use it */ +#endif + + metrics->height = metrics->ascender - metrics->descender; + if ( metrics->height == 0 ) + { + FT_TRACE2(( "tt_face_load_strike_metrics:" + " sanitizing invalid height value\n" )); + FT_TRACE2(( " " + " for strike (%d, %d)\n", + metrics->x_ppem, metrics->y_ppem )); + metrics->height = metrics->y_ppem * 64; + metrics->descender = metrics->ascender - metrics->height; + } + + /* Is this correct? */ + metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */ + strike[18] + /* max_width */ + (FT_Char)strike[23] /* min_advance_SB */ + ) * 64; + + /* set the scale values (in 16.16 units) so advances */ + /* from the hmtx and vmtx table are scaled correctly */ + metrics->x_scale = FT_DivFix( metrics->x_ppem * 64, + face->header.Units_Per_EM ); + metrics->y_scale = FT_DivFix( metrics->y_ppem * 64, + face->header.Units_Per_EM ); + + return FT_Err_Ok; + } + + case TT_SBIT_TABLE_TYPE_SBIX: + { + FT_Stream stream = face->root.stream; + FT_UInt offset; + FT_UShort ppem, resolution; + TT_HoriHeader *hori; + FT_Fixed scale; + + FT_Error error; + FT_Byte* p; + + + p = face->sbit_table + 8 + 4 * strike_index; + offset = FT_NEXT_ULONG( p ); + + if ( offset + 4 > face->ebdt_size ) + return FT_THROW( Invalid_File_Format ); + + if ( FT_STREAM_SEEK( face->ebdt_start + offset ) || + FT_FRAME_ENTER( 4 ) ) + return error; + + ppem = FT_GET_USHORT(); + resolution = FT_GET_USHORT(); + + FT_UNUSED( resolution ); /* What to do with this? */ + + FT_FRAME_EXIT(); + + metrics->x_ppem = ppem; + metrics->y_ppem = ppem; + + scale = FT_DivFix( ppem * 64, face->header.Units_Per_EM ); + hori = &face->horizontal; + + metrics->ascender = FT_MulFix( hori->Ascender, scale ); + metrics->descender = FT_MulFix( hori->Descender, scale ); + metrics->height = + FT_MulFix( hori->Ascender - hori->Descender + hori->Line_Gap, + scale ); + metrics->max_advance = FT_MulFix( hori->advance_Width_Max, scale ); + + /* set the scale values (in 16.16 units) so advances */ + /* from the hmtx and vmtx table are scaled correctly */ + metrics->x_scale = scale; + metrics->y_scale = scale; + + return error; + } + + default: + return FT_THROW( Unknown_File_Format ); + } + } + + + typedef struct TT_SBitDecoderRec_ + { + TT_Face face; + FT_Stream stream; + FT_Bitmap* bitmap; + TT_SBit_Metrics metrics; + FT_Bool metrics_loaded; + FT_Bool bitmap_allocated; + FT_Byte bit_depth; + + FT_ULong ebdt_start; + FT_ULong ebdt_size; + + FT_ULong strike_index_array; + FT_ULong strike_index_count; + FT_Byte* eblc_base; + FT_Byte* eblc_limit; + + } TT_SBitDecoderRec, *TT_SBitDecoder; + + + static FT_Error + tt_sbit_decoder_init( TT_SBitDecoder decoder, + TT_Face face, + FT_ULong strike_index, + TT_SBit_MetricsRec* metrics ) + { + FT_Error error = FT_ERR( Table_Missing ); + FT_Stream stream = face->root.stream; + + + strike_index = face->sbit_strike_map[strike_index]; + + if ( !face->ebdt_size ) + goto Exit; + if ( FT_STREAM_SEEK( face->ebdt_start ) ) + goto Exit; + + decoder->face = face; + decoder->stream = stream; + decoder->bitmap = &face->root.glyph->bitmap; + decoder->metrics = metrics; + + decoder->metrics_loaded = 0; + decoder->bitmap_allocated = 0; + + decoder->ebdt_start = face->ebdt_start; + decoder->ebdt_size = face->ebdt_size; + + decoder->eblc_base = face->sbit_table; + decoder->eblc_limit = face->sbit_table + face->sbit_table_size; + + /* now find the strike corresponding to the index */ + { + FT_Byte* p; + + + if ( 8 + 48 * strike_index + 3 * 4 + 34 + 1 > face->sbit_table_size ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + p = decoder->eblc_base + 8 + 48 * strike_index; + + decoder->strike_index_array = FT_NEXT_ULONG( p ); + p += 4; + decoder->strike_index_count = FT_NEXT_ULONG( p ); + p += 34; + decoder->bit_depth = *p; + + /* decoder->strike_index_array + */ + /* 8 * decoder->strike_index_count > face->sbit_table_size ? */ + if ( decoder->strike_index_array > face->sbit_table_size || + decoder->strike_index_count > + ( face->sbit_table_size - decoder->strike_index_array ) / 8 ) + error = FT_THROW( Invalid_File_Format ); + } + + Exit: + return error; + } + + + static void + tt_sbit_decoder_done( TT_SBitDecoder decoder ) + { + FT_UNUSED( decoder ); + } + + + static FT_Error + tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder, + FT_Bool metrics_only ) + { + FT_Error error = FT_Err_Ok; + FT_UInt width, height; + FT_Bitmap* map = decoder->bitmap; + FT_ULong size; + + + if ( !decoder->metrics_loaded ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + width = decoder->metrics->width; + height = decoder->metrics->height; + + map->width = width; + map->rows = height; + + switch ( decoder->bit_depth ) + { + case 1: + map->pixel_mode = FT_PIXEL_MODE_MONO; + map->pitch = (int)( ( map->width + 7 ) >> 3 ); + map->num_grays = 2; + break; + + case 2: + map->pixel_mode = FT_PIXEL_MODE_GRAY2; + map->pitch = (int)( ( map->width + 3 ) >> 2 ); + map->num_grays = 4; + break; + + case 4: + map->pixel_mode = FT_PIXEL_MODE_GRAY4; + map->pitch = (int)( ( map->width + 1 ) >> 1 ); + map->num_grays = 16; + break; + + case 8: + map->pixel_mode = FT_PIXEL_MODE_GRAY; + map->pitch = (int)( map->width ); + map->num_grays = 256; + break; + + case 32: + map->pixel_mode = FT_PIXEL_MODE_BGRA; + map->pitch = (int)( map->width * 4 ); + map->num_grays = 256; + break; + + default: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + size = map->rows * (FT_ULong)map->pitch; + + /* check that there is no empty image */ + if ( size == 0 ) + goto Exit; /* exit successfully! */ + + if ( metrics_only ) + goto Exit; /* only metrics are requested */ + + error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); + if ( error ) + goto Exit; + + decoder->bitmap_allocated = 1; + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_metrics( TT_SBitDecoder decoder, + FT_Byte* *pp, + FT_Byte* limit, + FT_Bool big ) + { + FT_Byte* p = *pp; + TT_SBit_Metrics metrics = decoder->metrics; + + + if ( p + 5 > limit ) + goto Fail; + + metrics->height = p[0]; + metrics->width = p[1]; + metrics->horiBearingX = (FT_Char)p[2]; + metrics->horiBearingY = (FT_Char)p[3]; + metrics->horiAdvance = p[4]; + + p += 5; + if ( big ) + { + if ( p + 3 > limit ) + goto Fail; + + metrics->vertBearingX = (FT_Char)p[0]; + metrics->vertBearingY = (FT_Char)p[1]; + metrics->vertAdvance = p[2]; + + p += 3; + } + else + { + /* avoid uninitialized data in case there is no vertical info -- */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + } + + decoder->metrics_loaded = 1; + *pp = p; + return FT_Err_Ok; + + Fail: + FT_TRACE1(( "tt_sbit_decoder_load_metrics: broken table\n" )); + return FT_THROW( Invalid_Argument ); + } + + + /* forward declaration */ + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count, + FT_Bool metrics_only ); + + typedef FT_Error (*TT_SBitDecoder_LoadFunc)( + TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* plimit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ); + + + static FT_Error + tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* line; + FT_Int pitch, width, height, line_bits, h; + FT_UInt bit_height, bit_width; + FT_Bitmap* bitmap; + + FT_UNUSED( recurse_count ); + + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + if ( !line ) + goto Exit; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + line_bits = width * decoder->bit_depth; + + if ( x_pos < 0 || (FT_UInt)( x_pos + width ) > bit_width || + y_pos < 0 || (FT_UInt)( y_pos + height ) > bit_height ) + { + FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned:" + " invalid bitmap dimensions\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( p + ( ( line_bits + 7 ) >> 3 ) * height > limit ) + { + FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* now do the blit */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + + if ( x_pos == 0 ) /* the easy one */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* pwrite = line; + FT_Int w; + + + for ( w = line_bits; w >= 8; w -= 8 ) + { + pwrite[0] = (FT_Byte)( pwrite[0] | *p++ ); + pwrite += 1; + } + + if ( w > 0 ) + pwrite[0] = (FT_Byte)( pwrite[0] | ( *p++ & ( 0xFF00U >> w ) ) ); + } + } + else /* x_pos > 0 */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* pwrite = line; + FT_Int w; + FT_UInt wval = 0; + + + for ( w = line_bits; w >= 8; w -= 8 ) + { + wval = (FT_UInt)( wval | *p++ ); + pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); + pwrite += 1; + wval <<= 8; + } + + if ( w > 0 ) + wval = (FT_UInt)( wval | ( *p++ & ( 0xFF00U >> w ) ) ); + + /* all bits read and there are `x_pos + w' bits to be written */ + + pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); + + if ( x_pos + w > 8 ) + { + pwrite++; + wval <<= 8; + pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); + } + } + } + + Exit: + if ( !error ) + FT_TRACE3(( "tt_sbit_decoder_load_byte_aligned: loaded\n" )); + return error; + } + + + /* + * Load a bit-aligned bitmap (with pointer `p') into a line-aligned bitmap + * (with pointer `pwrite'). In the example below, the width is 3 pixel, + * and `x_pos' is 1 pixel. + * + * p p+1 + * | | | + * | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 |... + * | | | + * +-------+ +-------+ +-------+ ... + * . . . + * . . . + * v . . + * +-------+ . . + * | | . + * | 7 6 5 4 3 2 1 0 | . + * | | . + * pwrite . . + * . . + * v . + * +-------+ . + * | | + * | 7 6 5 4 3 2 1 0 | + * | | + * pwrite+1 . + * . + * v + * +-------+ + * | | + * | 7 6 5 4 3 2 1 0 | + * | | + * pwrite+2 + * + */ + + static FT_Error + tt_sbit_decoder_load_bit_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* line; + FT_Int pitch, width, height, line_bits, h, nbits; + FT_UInt bit_height, bit_width; + FT_Bitmap* bitmap; + FT_UShort rval; + + FT_UNUSED( recurse_count ); + + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + line_bits = width * decoder->bit_depth; + + if ( x_pos < 0 || (FT_UInt)( x_pos + width ) > bit_width || + y_pos < 0 || (FT_UInt)( y_pos + height ) > bit_height ) + { + FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned:" + " invalid bitmap dimensions\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( p + ( ( line_bits * height + 7 ) >> 3 ) > limit ) + { + FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( !line_bits || !height ) + { + /* nothing to do */ + goto Exit; + } + + /* now do the blit */ + + /* adjust `line' to point to the first byte of the bitmap */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + + /* the higher byte of `rval' is used as a buffer */ + rval = 0; + nbits = 0; + + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* pwrite = line; + FT_Int w = line_bits; + + + /* handle initial byte (in target bitmap) specially if necessary */ + if ( x_pos ) + { + w = ( line_bits < 8 - x_pos ) ? line_bits : 8 - x_pos; + + if ( h == height ) + { + rval = *p++; + nbits = x_pos; + } + else if ( nbits < w ) + { + if ( p < limit ) + rval |= *p++; + nbits += 8 - w; + } + else + { + rval >>= 8; + nbits -= w; + } + + *pwrite++ |= ( ( rval >> nbits ) & 0xFF ) & + ( ~( 0xFFU << w ) << ( 8 - w - x_pos ) ); + rval <<= 8; + + w = line_bits - w; + } + + /* handle medial bytes */ + for ( ; w >= 8; w -= 8 ) + { + rval |= *p++; + *pwrite++ |= ( rval >> nbits ) & 0xFF; + + rval <<= 8; + } + + /* handle final byte if necessary */ + if ( w > 0 ) + { + if ( nbits < w ) + { + if ( p < limit ) + rval |= *p++; + *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits += 8 - w; + + rval <<= 8; + } + else + { + *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits -= w; + } + } + } + + Exit: + if ( !error ) + FT_TRACE3(( "tt_sbit_decoder_load_bit_aligned: loaded\n" )); + return error; + } + + + static FT_Error + tt_sbit_decoder_load_compound( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_UInt num_components, nn; + + FT_Char horiBearingX = (FT_Char)decoder->metrics->horiBearingX; + FT_Char horiBearingY = (FT_Char)decoder->metrics->horiBearingY; + FT_Byte horiAdvance = (FT_Byte)decoder->metrics->horiAdvance; + FT_Char vertBearingX = (FT_Char)decoder->metrics->vertBearingX; + FT_Char vertBearingY = (FT_Char)decoder->metrics->vertBearingY; + FT_Byte vertAdvance = (FT_Byte)decoder->metrics->vertAdvance; + + + if ( p + 2 > limit ) + goto Fail; + + num_components = FT_NEXT_USHORT( p ); + if ( p + 4 * num_components > limit ) + { + FT_TRACE1(( "tt_sbit_decoder_load_compound: broken table\n" )); + goto Fail; + } + + FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %d component%s\n", + num_components, + num_components == 1 ? "" : "s" )); + + for ( nn = 0; nn < num_components; nn++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + FT_Char dx = FT_NEXT_CHAR( p ); + FT_Char dy = FT_NEXT_CHAR( p ); + + + /* NB: a recursive call */ + error = tt_sbit_decoder_load_image( decoder, + gindex, + x_pos + dx, + y_pos + dy, + recurse_count + 1, + /* request full bitmap image */ + FALSE ); + if ( error ) + break; + } + + FT_TRACE3(( "tt_sbit_decoder_load_compound: done\n" )); + + decoder->metrics->horiBearingX = horiBearingX; + decoder->metrics->horiBearingY = horiBearingY; + decoder->metrics->horiAdvance = horiAdvance; + decoder->metrics->vertBearingX = vertBearingX; + decoder->metrics->vertBearingY = vertBearingY; + decoder->metrics->vertAdvance = vertAdvance; + decoder->metrics->width = (FT_Byte)decoder->bitmap->width; + decoder->metrics->height = (FT_Byte)decoder->bitmap->rows; + + Exit: + return error; + + Fail: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + +#ifdef FT_CONFIG_OPTION_USE_PNG + + static FT_Error + tt_sbit_decoder_load_png( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong png_len; + + FT_UNUSED( recurse_count ); + + + if ( limit - p < 4 ) + { + FT_TRACE1(( "tt_sbit_decoder_load_png: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + png_len = FT_NEXT_ULONG( p ); + if ( (FT_ULong)( limit - p ) < png_len ) + { + FT_TRACE1(( "tt_sbit_decoder_load_png: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + error = Load_SBit_Png( decoder->face->root.glyph, + x_pos, + y_pos, + decoder->bit_depth, + decoder->metrics, + decoder->stream->memory, + p, + png_len, + FALSE, + FALSE ); + + Exit: + if ( !error ) + FT_TRACE3(( "tt_sbit_decoder_load_png: loaded\n" )); + return error; + } + +#endif /* FT_CONFIG_OPTION_USE_PNG */ + + + static FT_Error + tt_sbit_decoder_load_bitmap( TT_SBitDecoder decoder, + FT_UInt glyph_format, + FT_ULong glyph_start, + FT_ULong glyph_size, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count, + FT_Bool metrics_only ) + { + FT_Error error; + FT_Stream stream = decoder->stream; + FT_Byte* p; + FT_Byte* p_limit; + FT_Byte* data; + + + /* seek into the EBDT table now */ + if ( !glyph_size || + glyph_start + glyph_size > decoder->ebdt_size ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) || + FT_FRAME_EXTRACT( glyph_size, data ) ) + goto Exit; + + p = data; + p_limit = p + glyph_size; + + /* read the data, depending on the glyph format */ + switch ( glyph_format ) + { + case 1: + case 2: + case 8: + case 17: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 ); + break; + + case 6: + case 7: + case 9: + case 18: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ); + break; + + default: + error = FT_Err_Ok; + } + + if ( error ) + goto Fail; + + { + TT_SBitDecoder_LoadFunc loader; + + + switch ( glyph_format ) + { + case 1: + case 6: + loader = tt_sbit_decoder_load_byte_aligned; + break; + + case 2: + case 7: + { + /* Don't trust `glyph_format'. For example, Apple's main Korean */ + /* system font, `AppleMyungJo.ttf' (version 7.0d2e6), uses glyph */ + /* format 7, but the data is format 6. We check whether we have */ + /* an excessive number of bytes in the image: If it is equal to */ + /* the value for a byte-aligned glyph, use the other loading */ + /* routine. */ + /* */ + /* Note that for some (width,height) combinations, where the */ + /* width is not a multiple of 8, the sizes for bit- and */ + /* byte-aligned data are equal, for example (7,7) or (15,6). We */ + /* then prefer what `glyph_format' specifies. */ + + FT_UInt width = decoder->metrics->width; + FT_UInt height = decoder->metrics->height; + + FT_UInt bit_size = ( width * height + 7 ) >> 3; + FT_UInt byte_size = height * ( ( width + 7 ) >> 3 ); + + + if ( bit_size < byte_size && + byte_size == (FT_UInt)( p_limit - p ) ) + loader = tt_sbit_decoder_load_byte_aligned; + else + loader = tt_sbit_decoder_load_bit_aligned; + } + break; + + case 5: + loader = tt_sbit_decoder_load_bit_aligned; + break; + + case 8: + if ( p + 1 > p_limit ) + goto Fail; + + p += 1; /* skip padding */ + FALL_THROUGH; + + case 9: + loader = tt_sbit_decoder_load_compound; + break; + + case 17: /* small metrics, PNG image data */ + case 18: /* big metrics, PNG image data */ + case 19: /* metrics in EBLC, PNG image data */ +#ifdef FT_CONFIG_OPTION_USE_PNG + loader = tt_sbit_decoder_load_png; + break; +#else + error = FT_THROW( Unimplemented_Feature ); + goto Fail; +#endif /* FT_CONFIG_OPTION_USE_PNG */ + + default: + error = FT_THROW( Invalid_Table ); + goto Fail; + } + + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder, metrics_only ); + + if ( error ) + goto Fail; + } + + if ( metrics_only ) + goto Fail; /* this is not an error */ + + error = loader( decoder, p, p_limit, x_pos, y_pos, recurse_count ); + } + + Fail: + FT_FRAME_RELEASE( data ); + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count, + FT_Bool metrics_only ) + { + FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; + FT_Byte* p_limit = decoder->eblc_limit; + FT_ULong num_ranges = decoder->strike_index_count; + FT_UInt start, end, index_format, image_format; + FT_ULong image_start = 0, image_end = 0, image_offset; + + + /* arbitrary recursion limit */ + if ( recurse_count > 100 ) + { + FT_TRACE4(( "tt_sbit_decoder_load_image:" + " recursion depth exceeded\n" )); + goto Failure; + } + + + /* First, we find the correct strike range that applies to this */ + /* glyph index. */ + for ( ; num_ranges > 0; num_ranges-- ) + { + start = FT_NEXT_USHORT( p ); + end = FT_NEXT_USHORT( p ); + + if ( glyph_index >= start && glyph_index <= end ) + goto FoundRange; + + p += 4; /* ignore index offset */ + } + goto NoBitmap; + + FoundRange: + image_offset = FT_NEXT_ULONG( p ); + + /* overflow check */ + p = decoder->eblc_base + decoder->strike_index_array; + if ( image_offset > (FT_ULong)( p_limit - p ) ) + goto Failure; + + p += image_offset; + if ( p + 8 > p_limit ) + goto NoBitmap; + + /* now find the glyph's location and extend within the ebdt table */ + index_format = FT_NEXT_USHORT( p ); + image_format = FT_NEXT_USHORT( p ); + image_offset = FT_NEXT_ULONG ( p ); + + switch ( index_format ) + { + case 1: /* 4-byte offsets relative to `image_offset' */ + p += 4 * ( glyph_index - start ); + if ( p + 8 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_ULONG( p ); + image_end = FT_NEXT_ULONG( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + break; + + case 2: /* big metrics, constant image size */ + { + FT_ULong image_size; + + + if ( p + 12 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + image_start = image_size * ( glyph_index - start ); + image_end = image_start + image_size; + } + break; + + case 3: /* 2-byte offsets relative to 'image_offset' */ + p += 2 * ( glyph_index - start ); + if ( p + 4 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_USHORT( p ); + image_end = FT_NEXT_USHORT( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + break; + + case 4: /* sparse glyph array with (glyph,offset) pairs */ + { + FT_ULong mm, num_glyphs; + + + if ( p + 4 > p_limit ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + + /* overflow check for p + ( num_glyphs + 1 ) * 4 */ + if ( p + 4 > p_limit || + num_glyphs > (FT_ULong)( ( ( p_limit - p ) >> 2 ) - 1 ) ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + { + image_start = FT_NEXT_USHORT( p ); + p += 2; + image_end = FT_PEEK_USHORT( p ); + break; + } + p += 2; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + } + break; + + case 5: /* constant metrics with sparse glyph codes */ + case 19: + { + FT_ULong image_size, mm, num_glyphs; + + + if ( p + 16 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + + /* overflow check for p + 2 * num_glyphs */ + if ( num_glyphs > (FT_ULong)( ( p_limit - p ) >> 1 ) ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + break; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + + image_start = image_size * mm; + image_end = image_start + image_size; + } + break; + + default: + goto NoBitmap; + } + + if ( image_start > image_end ) + goto NoBitmap; + + image_end -= image_start; + image_start = image_offset + image_start; + + FT_TRACE3(( "tt_sbit_decoder_load_image:" + " found sbit (format %d) for glyph index %d\n", + image_format, glyph_index )); + + return tt_sbit_decoder_load_bitmap( decoder, + image_format, + image_start, + image_end, + x_pos, + y_pos, + recurse_count, + metrics_only ); + + Failure: + return FT_THROW( Invalid_Table ); + + NoBitmap: + if ( recurse_count ) + { + FT_TRACE4(( "tt_sbit_decoder_load_image:" + " missing subglyph sbit with glyph index %d\n", + glyph_index )); + return FT_THROW( Invalid_Composite ); + } + + FT_TRACE4(( "tt_sbit_decoder_load_image:" + " no sbit found for glyph index %d\n", glyph_index )); + return FT_THROW( Missing_Bitmap ); + } + + + static FT_Error + tt_face_load_sbix_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics, + FT_Bool metrics_only ) + { + FT_UInt strike_offset, glyph_start, glyph_end; + FT_Int originOffsetX, originOffsetY; + FT_Tag graphicType; + FT_Int recurse_depth = 0; + + FT_Error error; + FT_Byte* p; + + FT_UNUSED( map ); +#ifndef FT_CONFIG_OPTION_USE_PNG + FT_UNUSED( metrics_only ); +#endif + + + strike_index = face->sbit_strike_map[strike_index]; + + metrics->width = 0; + metrics->height = 0; + + p = face->sbit_table + 8 + 4 * strike_index; + strike_offset = FT_NEXT_ULONG( p ); + + retry: + if ( glyph_index > (FT_UInt)face->root.num_glyphs ) + return FT_THROW( Invalid_Argument ); + + if ( strike_offset >= face->ebdt_size || + face->ebdt_size - strike_offset < 4 + glyph_index * 4 + 8 ) + return FT_THROW( Invalid_File_Format ); + + if ( FT_STREAM_SEEK( face->ebdt_start + + strike_offset + 4 + + glyph_index * 4 ) || + FT_FRAME_ENTER( 8 ) ) + return error; + + glyph_start = FT_GET_ULONG(); + glyph_end = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + + if ( glyph_start == glyph_end ) + return FT_THROW( Missing_Bitmap ); + if ( glyph_start > glyph_end || + glyph_end - glyph_start < 8 || + face->ebdt_size - strike_offset < glyph_end ) + return FT_THROW( Invalid_File_Format ); + + if ( FT_STREAM_SEEK( face->ebdt_start + strike_offset + glyph_start ) || + FT_FRAME_ENTER( glyph_end - glyph_start ) ) + return error; + + originOffsetX = FT_GET_SHORT(); + originOffsetY = FT_GET_SHORT(); + + graphicType = FT_GET_TAG4(); + + switch ( graphicType ) + { + case FT_MAKE_TAG( 'd', 'u', 'p', 'e' ): + if ( recurse_depth < 4 ) + { + glyph_index = FT_GET_USHORT(); + FT_FRAME_EXIT(); + recurse_depth++; + goto retry; + } + error = FT_THROW( Invalid_File_Format ); + break; + + case FT_MAKE_TAG( 'p', 'n', 'g', ' ' ): +#ifdef FT_CONFIG_OPTION_USE_PNG + error = Load_SBit_Png( face->root.glyph, + 0, + 0, + 32, + metrics, + stream->memory, + stream->cursor, + glyph_end - glyph_start - 8, + TRUE, + metrics_only ); +#else + error = FT_THROW( Unimplemented_Feature ); +#endif + break; + + case FT_MAKE_TAG( 'j', 'p', 'g', ' ' ): + case FT_MAKE_TAG( 't', 'i', 'f', 'f' ): + case FT_MAKE_TAG( 'r', 'g', 'b', 'l' ): /* used on iOS 7.1 */ + error = FT_THROW( Unknown_File_Format ); + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + FT_FRAME_EXIT(); + + if ( !error ) + { + FT_Short abearing; /* not used here */ + FT_UShort aadvance; + + + tt_face_get_metrics( face, FALSE, glyph_index, &abearing, &aadvance ); + + metrics->horiBearingX = (FT_Short)originOffsetX; + metrics->vertBearingX = (FT_Short)originOffsetX; + + metrics->horiBearingY = (FT_Short)( originOffsetY + metrics->height ); + metrics->vertBearingY = (FT_Short)originOffsetY; + + metrics->horiAdvance = (FT_UShort)( aadvance * + face->root.size->metrics.x_ppem / + face->header.Units_Per_EM ); + + if ( face->vertical_info ) + tt_face_get_metrics( face, TRUE, glyph_index, &abearing, &aadvance ); + else if ( face->os2.version != 0xFFFFU ) + aadvance = (FT_UShort)FT_ABS( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + aadvance = (FT_UShort)FT_ABS( face->horizontal.Ascender - + face->horizontal.Descender ); + + metrics->vertAdvance = (FT_UShort)( aadvance * + face->root.size->metrics.x_ppem / + face->header.Units_Per_EM ); + } + + return error; + } + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ) + { + FT_Error error = FT_Err_Ok; + + + switch ( (FT_UInt)face->sbit_table_type ) + { + case TT_SBIT_TABLE_TYPE_EBLC: + case TT_SBIT_TABLE_TYPE_CBLC: + { + TT_SBitDecoderRec decoder[1]; + + + error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); + if ( !error ) + { + error = tt_sbit_decoder_load_image( + decoder, + glyph_index, + 0, + 0, + 0, + ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); + tt_sbit_decoder_done( decoder ); + } + } + break; + + case TT_SBIT_TABLE_TYPE_SBIX: + error = tt_face_load_sbix_image( + face, + strike_index, + glyph_index, + stream, + map, + metrics, + ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); + break; + + default: + error = FT_THROW( Unknown_File_Format ); + break; + } + + /* Flatten color bitmaps if color was not requested. */ + if ( !error && + !( load_flags & FT_LOAD_COLOR ) && + !( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) && + map->pixel_mode == FT_PIXEL_MODE_BGRA ) + { + FT_Bitmap new_map; + FT_Library library = face->root.glyph->library; + + + FT_Bitmap_Init( &new_map ); + + /* Convert to 8bit grayscale. */ + error = FT_Bitmap_Convert( library, map, &new_map, 1 ); + if ( error ) + FT_Bitmap_Done( library, &new_map ); + else + { + map->pixel_mode = new_map.pixel_mode; + map->pitch = new_map.pitch; + map->num_grays = new_map.num_grays; + + ft_glyphslot_set_bitmap( face->root.glyph, new_map.buffer ); + face->root.glyph->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + } + + return error; + } + +#else /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_sbit_dummy_; + +#endif /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttsbit.h b/vendor/freetype/src/sfnt/ttsbit.h new file mode 100644 index 0000000..07e2db4 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttsbit.h @@ -0,0 +1,62 @@ +/**************************************************************************** + * + * ttsbit.h + * + * TrueType and OpenType embedded bitmap support (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTSBIT_H_ +#define TTSBIT_H_ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_sbit( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_sbit( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + + FT_LOCAL( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + + FT_LOCAL( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ); + + +FT_END_HEADER + +#endif /* TTSBIT_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttsvg.c b/vendor/freetype/src/sfnt/ttsvg.c new file mode 100644 index 0000000..4461d48 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttsvg.c @@ -0,0 +1,413 @@ +/**************************************************************************** + * + * ttsvg.c + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * 'SVG' table specification: + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/svg + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_SVG + +#include "ttsvg.h" + + + /* NOTE: These table sizes are given by the specification. */ +#define SVG_TABLE_HEADER_SIZE (10U) +#define SVG_DOCUMENT_RECORD_SIZE (12U) +#define SVG_DOCUMENT_LIST_MINIMUM_SIZE (2U + SVG_DOCUMENT_RECORD_SIZE) +#define SVG_MINIMUM_SIZE (SVG_TABLE_HEADER_SIZE + \ + SVG_DOCUMENT_LIST_MINIMUM_SIZE) + + + typedef struct Svg_ + { + FT_UShort version; /* table version (starting at 0) */ + FT_UShort num_entries; /* number of SVG document records */ + + FT_Byte* svg_doc_list; /* pointer to the start of SVG Document List */ + + void* table; /* memory that backs up SVG */ + FT_ULong table_size; + + } Svg; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttsvg + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_ULong table_size; + FT_Byte* table = NULL; + FT_Byte* p = NULL; + Svg* svg = NULL; + FT_ULong offsetToSVGDocumentList; + + + error = face->goto_table( face, TTAG_SVG, stream, &table_size ); + if ( error ) + goto NoSVG; + + if ( table_size < SVG_MINIMUM_SIZE ) + goto InvalidTable; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoSVG; + + /* Allocate memory for the SVG object */ + if ( FT_NEW( svg ) ) + goto NoSVG; + + p = table; + svg->version = FT_NEXT_USHORT( p ); + offsetToSVGDocumentList = FT_NEXT_ULONG( p ); + + if ( offsetToSVGDocumentList < SVG_TABLE_HEADER_SIZE || + offsetToSVGDocumentList > table_size - + SVG_DOCUMENT_LIST_MINIMUM_SIZE ) + goto InvalidTable; + + svg->svg_doc_list = (FT_Byte*)( table + offsetToSVGDocumentList ); + + p = svg->svg_doc_list; + svg->num_entries = FT_NEXT_USHORT( p ); + + FT_TRACE3(( "version: %d\n", svg->version )); + FT_TRACE3(( "number of entries: %d\n", svg->num_entries )); + + if ( offsetToSVGDocumentList + 2U + + svg->num_entries * SVG_DOCUMENT_RECORD_SIZE > table_size ) + goto InvalidTable; + + svg->table = table; + svg->table_size = table_size; + + face->svg = svg; + face->root.face_flags |= FT_FACE_FLAG_SVG; + + return FT_Err_Ok; + + InvalidTable: + error = FT_THROW( Invalid_Table ); + + NoSVG: + FT_FRAME_RELEASE( table ); + FT_FREE( svg ); + face->svg = NULL; + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_svg( TT_Face face ) + { + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + + Svg* svg = (Svg*)face->svg; + + + if ( svg ) + { + FT_FRAME_RELEASE( svg->table ); + FT_FREE( svg ); + } + } + + + typedef struct Svg_doc_ + { + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_ULong offset; + FT_ULong length; + + } Svg_doc; + + + static Svg_doc + extract_svg_doc( FT_Byte* stream ) + { + Svg_doc doc; + + + doc.start_glyph_id = FT_NEXT_USHORT( stream ); + doc.end_glyph_id = FT_NEXT_USHORT( stream ); + + doc.offset = FT_NEXT_ULONG( stream ); + doc.length = FT_NEXT_ULONG( stream ); + + return doc; + } + + + static FT_Int + compare_svg_doc( Svg_doc doc, + FT_UInt glyph_index ) + { + if ( glyph_index < doc.start_glyph_id ) + return -1; + else if ( glyph_index > doc.end_glyph_id ) + return 1; + else + return 0; + } + + + static FT_Error + find_doc( FT_Byte* document_records, + FT_UShort num_entries, + FT_UInt glyph_index, + FT_ULong *doc_offset, + FT_ULong *doc_length, + FT_UShort *start_glyph, + FT_UShort *end_glyph ) + { + FT_Error error; + + Svg_doc start_doc; + Svg_doc mid_doc = { 0, 0, 0, 0 }; /* pacify compiler */ + Svg_doc end_doc; + + FT_Bool found = FALSE; + FT_UInt i = 0; + + FT_UInt start_index = 0; + FT_UInt end_index = num_entries - 1; + FT_Int comp_res; + + + /* search algorithm */ + if ( num_entries == 0 ) + { + error = FT_THROW( Invalid_Table ); + return error; + } + + start_doc = extract_svg_doc( document_records + start_index * 12 ); + end_doc = extract_svg_doc( document_records + end_index * 12 ); + + if ( ( compare_svg_doc( start_doc, glyph_index ) == -1 ) || + ( compare_svg_doc( end_doc, glyph_index ) == 1 ) ) + { + error = FT_THROW( Invalid_Glyph_Index ); + return error; + } + + while ( start_index <= end_index ) + { + i = ( start_index + end_index ) / 2; + mid_doc = extract_svg_doc( document_records + i * 12 ); + comp_res = compare_svg_doc( mid_doc, glyph_index ); + + if ( comp_res == 1 ) + { + start_index = i + 1; + start_doc = extract_svg_doc( document_records + start_index * 4 ); + } + else if ( comp_res == -1 ) + { + end_index = i - 1; + end_doc = extract_svg_doc( document_records + end_index * 4 ); + } + else + { + found = TRUE; + break; + } + } + /* search algorithm end */ + + if ( found != TRUE ) + { + FT_TRACE5(( "SVG glyph not found\n" )); + error = FT_THROW( Invalid_Glyph_Index ); + } + else + { + *doc_offset = mid_doc.offset; + *doc_length = mid_doc.length; + + *start_glyph = mid_doc.start_glyph_id; + *end_glyph = mid_doc.end_glyph_id; + + error = FT_Err_Ok; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ) + { + FT_Error error = FT_Err_Ok; + TT_Face face = (TT_Face)glyph->face; + FT_Memory memory = face->root.memory; + Svg* svg = (Svg*)face->svg; + + FT_Byte* doc_list; + FT_ULong doc_limit; + + FT_Byte* doc; + FT_ULong doc_offset; + FT_ULong doc_length; + FT_UShort doc_start_glyph_id; + FT_UShort doc_end_glyph_id; + + FT_SVG_Document svg_document = (FT_SVG_Document)glyph->other; + + + FT_ASSERT( !( svg == NULL ) ); + + doc_list = svg->svg_doc_list; + + error = find_doc( doc_list + 2, svg->num_entries, glyph_index, + &doc_offset, &doc_length, + &doc_start_glyph_id, &doc_end_glyph_id ); + if ( error != FT_Err_Ok ) + goto Exit; + + doc_limit = svg->table_size - + (FT_ULong)( doc_list - (FT_Byte*)svg->table ); + if ( doc_offset > doc_limit || + doc_length > doc_limit - doc_offset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + doc = doc_list + doc_offset; + + if ( doc_length > 6 && + doc[0] == 0x1F && + doc[1] == 0x8B && + doc[2] == 0x08 ) + { +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + FT_ULong uncomp_size; + FT_Byte* uncomp_buffer = NULL; + + + /* + * Get the size of the original document. This helps in allotting the + * buffer to accommodate the uncompressed version. The last 4 bytes + * of the compressed document are equal to the original size modulo + * 2^32. Since the size of SVG documents is less than 2^32 bytes we + * can use this accurately. The four bytes are stored in + * little-endian format. + */ + FT_TRACE4(( "SVG document is GZIP compressed\n" )); + uncomp_size = (FT_ULong)doc[doc_length - 1] << 24 | + (FT_ULong)doc[doc_length - 2] << 16 | + (FT_ULong)doc[doc_length - 3] << 8 | + (FT_ULong)doc[doc_length - 4]; + + if ( FT_QALLOC( uncomp_buffer, uncomp_size ) ) + goto Exit; + + error = FT_Gzip_Uncompress( memory, + uncomp_buffer, + &uncomp_size, + doc, + doc_length ); + if ( error ) + { + FT_FREE( uncomp_buffer ); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + glyph->internal->flags |= FT_GLYPH_OWN_GZIP_SVG; + + doc = uncomp_buffer; + doc_length = uncomp_size; + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + error = FT_THROW( Unimplemented_Feature ); + goto Exit; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + } + + svg_document->svg_document = doc; + svg_document->svg_document_length = doc_length; + + svg_document->metrics = glyph->face->size->metrics; + svg_document->units_per_EM = glyph->face->units_per_EM; + + svg_document->start_glyph_id = doc_start_glyph_id; + svg_document->end_glyph_id = doc_end_glyph_id; + + svg_document->transform.xx = 0x10000; + svg_document->transform.xy = 0; + svg_document->transform.yx = 0; + svg_document->transform.yy = 0x10000; + + svg_document->delta.x = 0; + svg_document->delta.y = 0; + + FT_TRACE5(( "start_glyph_id: %d\n", doc_start_glyph_id )); + FT_TRACE5(( "end_glyph_id: %d\n", doc_end_glyph_id )); + FT_TRACE5(( "svg_document:\n" )); + FT_TRACE5(( " %.*s\n", (FT_UInt)doc_length, doc )); + + glyph->other = svg_document; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_SVG */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_svg_dummy_; + +#endif /* !FT_CONFIG_OPTION_SVG */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/ttsvg.h b/vendor/freetype/src/sfnt/ttsvg.h new file mode 100644 index 0000000..3f32321 --- /dev/null +++ b/vendor/freetype/src/sfnt/ttsvg.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * ttsvg.h + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef TTSVG_H_ +#define TTSVG_H_ + +#include +#include + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_svg( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + +FT_END_HEADER + +#endif /* TTSVG_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/woff2tags.c b/vendor/freetype/src/sfnt/woff2tags.c new file mode 100644 index 0000000..eeedd99 --- /dev/null +++ b/vendor/freetype/src/sfnt/woff2tags.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * + * woff2tags.c + * + * WOFF2 Font table tags (base). + * + * Copyright (C) 2019-2023 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + +#include "woff2tags.h" + + /* + * Return tag from index in the order given in WOFF2 specification. + * + * See + * + * https://www.w3.org/TR/WOFF2/#table_dir_format + * + * for details. + */ + FT_LOCAL_DEF( FT_Tag ) + woff2_known_tags( FT_Byte index ) + { + static const FT_Tag known_tags[63] = + { + FT_MAKE_TAG('c', 'm', 'a', 'p'), /* 0 */ + FT_MAKE_TAG('h', 'e', 'a', 'd'), /* 1 */ + FT_MAKE_TAG('h', 'h', 'e', 'a'), /* 2 */ + FT_MAKE_TAG('h', 'm', 't', 'x'), /* 3 */ + FT_MAKE_TAG('m', 'a', 'x', 'p'), /* 4 */ + FT_MAKE_TAG('n', 'a', 'm', 'e'), /* 5 */ + FT_MAKE_TAG('O', 'S', '/', '2'), /* 6 */ + FT_MAKE_TAG('p', 'o', 's', 't'), /* 7 */ + FT_MAKE_TAG('c', 'v', 't', ' '), /* 8 */ + FT_MAKE_TAG('f', 'p', 'g', 'm'), /* 9 */ + FT_MAKE_TAG('g', 'l', 'y', 'f'), /* 10 */ + FT_MAKE_TAG('l', 'o', 'c', 'a'), /* 11 */ + FT_MAKE_TAG('p', 'r', 'e', 'p'), /* 12 */ + FT_MAKE_TAG('C', 'F', 'F', ' '), /* 13 */ + FT_MAKE_TAG('V', 'O', 'R', 'G'), /* 14 */ + FT_MAKE_TAG('E', 'B', 'D', 'T'), /* 15 */ + FT_MAKE_TAG('E', 'B', 'L', 'C'), /* 16 */ + FT_MAKE_TAG('g', 'a', 's', 'p'), /* 17 */ + FT_MAKE_TAG('h', 'd', 'm', 'x'), /* 18 */ + FT_MAKE_TAG('k', 'e', 'r', 'n'), /* 19 */ + FT_MAKE_TAG('L', 'T', 'S', 'H'), /* 20 */ + FT_MAKE_TAG('P', 'C', 'L', 'T'), /* 21 */ + FT_MAKE_TAG('V', 'D', 'M', 'X'), /* 22 */ + FT_MAKE_TAG('v', 'h', 'e', 'a'), /* 23 */ + FT_MAKE_TAG('v', 'm', 't', 'x'), /* 24 */ + FT_MAKE_TAG('B', 'A', 'S', 'E'), /* 25 */ + FT_MAKE_TAG('G', 'D', 'E', 'F'), /* 26 */ + FT_MAKE_TAG('G', 'P', 'O', 'S'), /* 27 */ + FT_MAKE_TAG('G', 'S', 'U', 'B'), /* 28 */ + FT_MAKE_TAG('E', 'B', 'S', 'C'), /* 29 */ + FT_MAKE_TAG('J', 'S', 'T', 'F'), /* 30 */ + FT_MAKE_TAG('M', 'A', 'T', 'H'), /* 31 */ + FT_MAKE_TAG('C', 'B', 'D', 'T'), /* 32 */ + FT_MAKE_TAG('C', 'B', 'L', 'C'), /* 33 */ + FT_MAKE_TAG('C', 'O', 'L', 'R'), /* 34 */ + FT_MAKE_TAG('C', 'P', 'A', 'L'), /* 35 */ + FT_MAKE_TAG('S', 'V', 'G', ' '), /* 36 */ + FT_MAKE_TAG('s', 'b', 'i', 'x'), /* 37 */ + FT_MAKE_TAG('a', 'c', 'n', 't'), /* 38 */ + FT_MAKE_TAG('a', 'v', 'a', 'r'), /* 39 */ + FT_MAKE_TAG('b', 'd', 'a', 't'), /* 40 */ + FT_MAKE_TAG('b', 'l', 'o', 'c'), /* 41 */ + FT_MAKE_TAG('b', 's', 'l', 'n'), /* 42 */ + FT_MAKE_TAG('c', 'v', 'a', 'r'), /* 43 */ + FT_MAKE_TAG('f', 'd', 's', 'c'), /* 44 */ + FT_MAKE_TAG('f', 'e', 'a', 't'), /* 45 */ + FT_MAKE_TAG('f', 'm', 't', 'x'), /* 46 */ + FT_MAKE_TAG('f', 'v', 'a', 'r'), /* 47 */ + FT_MAKE_TAG('g', 'v', 'a', 'r'), /* 48 */ + FT_MAKE_TAG('h', 's', 't', 'y'), /* 49 */ + FT_MAKE_TAG('j', 'u', 's', 't'), /* 50 */ + FT_MAKE_TAG('l', 'c', 'a', 'r'), /* 51 */ + FT_MAKE_TAG('m', 'o', 'r', 't'), /* 52 */ + FT_MAKE_TAG('m', 'o', 'r', 'x'), /* 53 */ + FT_MAKE_TAG('o', 'p', 'b', 'd'), /* 54 */ + FT_MAKE_TAG('p', 'r', 'o', 'p'), /* 55 */ + FT_MAKE_TAG('t', 'r', 'a', 'k'), /* 56 */ + FT_MAKE_TAG('Z', 'a', 'p', 'f'), /* 57 */ + FT_MAKE_TAG('S', 'i', 'l', 'f'), /* 58 */ + FT_MAKE_TAG('G', 'l', 'a', 't'), /* 59 */ + FT_MAKE_TAG('G', 'l', 'o', 'c'), /* 60 */ + FT_MAKE_TAG('F', 'e', 'a', 't'), /* 61 */ + FT_MAKE_TAG('S', 'i', 'l', 'l'), /* 62 */ + }; + + + if ( index > 62 ) + return 0; + + return known_tags[index]; + } + +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int woff2tags_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + + +/* END */ diff --git a/vendor/freetype/src/sfnt/woff2tags.h b/vendor/freetype/src/sfnt/woff2tags.h new file mode 100644 index 0000000..1201848 --- /dev/null +++ b/vendor/freetype/src/sfnt/woff2tags.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * woff2tags.h + * + * WOFF2 Font table tags (specification). + * + * Copyright (C) 2019-2023 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef WOFF2TAGS_H +#define WOFF2TAGS_H + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + + FT_LOCAL( FT_Tag ) + woff2_known_tags( FT_Byte index ); + +#endif + +FT_END_HEADER + +#endif /* WOFF2TAGS_H */ + + +/* END */ diff --git a/vendor/freetype/src/smooth/ftgrays.c b/vendor/freetype/src/smooth/ftgrays.c new file mode 100644 index 0000000..0918272 --- /dev/null +++ b/vendor/freetype/src/smooth/ftgrays.c @@ -0,0 +1,2244 @@ +/**************************************************************************** + * + * ftgrays.c + * + * A new `perfect' anti-aliasing renderer (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file can be compiled without the rest of the FreeType engine, by + * defining the STANDALONE_ macro when compiling it. You also need to + * put the files `ftgrays.h' and `ftimage.h' into the current + * compilation directory. Typically, you could do something like + * + * - copy `src/smooth/ftgrays.c' (this file) to your current directory + * + * - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the + * same directory + * + * - compile `ftgrays' with the STANDALONE_ macro defined, as in + * + * cc -c -DSTANDALONE_ ftgrays.c + * + * The renderer can be initialized with a call to + * `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated + * with a call to `ft_gray_raster.raster_render'. + * + * See the comments and documentation in the file `ftimage.h' for more + * details on how the raster works. + * + */ + + /************************************************************************** + * + * This is a new anti-aliasing scan-converter for FreeType 2. The + * algorithm used here is _very_ different from the one in the standard + * `ftraster' module. Actually, `ftgrays' computes the _exact_ + * coverage of the outline on each pixel cell by straight segments. + * + * It is based on ideas that I initially found in Raph Levien's + * excellent LibArt graphics library (see https://www.levien.com/libart + * for more information, though the web pages do not tell anything + * about the renderer; you'll have to dive into the source code to + * understand how it works). + * + * Note, however, that this is a _very_ different implementation + * compared to Raph's. Coverage information is stored in a very + * different way, and I don't use sorted vector paths. Also, it doesn't + * use floating point values. + * + * Bézier segments are flattened by splitting them until their deviation + * from straight line becomes much smaller than a pixel. Therefore, the + * pixel coverage by a Bézier curve is calculated approximately. To + * estimate the deviation, we use the distance from the control point + * to the conic chord centre or the cubic chord trisection. These + * distances vanish fast after each split. In the conic case, they vanish + * predictably and the number of necessary splits can be calculated. + * + * This renderer has the following advantages: + * + * - It doesn't need an intermediate bitmap. Instead, one can supply a + * callback function that will be called by the renderer to draw gray + * spans on any target surface. You can thus do direct composition on + * any kind of bitmap, provided that you give the renderer the right + * callback. + * + * - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on + * each pixel cell by straight segments. + * + * - It performs a single pass on the outline (the `standard' FT2 + * renderer makes two passes). + * + * - It can easily be modified to render to _any_ number of gray levels + * cheaply. + * + * - For small (< 80) pixel sizes, it is faster than the standard + * renderer. + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT smooth + + +#ifdef STANDALONE_ + + + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ +#define FT_RENDER_POOL_SIZE 16384L + + + /* Auxiliary macros for token concatenation. */ +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) + +#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) +#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + + + /* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' + * algorithm. We use alpha = 1, beta = 3/8, giving us results with a + * largest error less than 7% compared to the exact value. + */ +#define FT_HYPOT( x, y ) \ + ( x = FT_ABS( x ), \ + y = FT_ABS( y ), \ + x > y ? x + ( 3 * y >> 3 ) \ + : y + ( 3 * x >> 3 ) ) + + + /* define this to dump debugging information */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + +#ifdef FT_DEBUG_LEVEL_TRACE +#include +#include +#endif + +#include +#include +#include +#include +#define FT_CHAR_BIT CHAR_BIT +#define FT_UINT_MAX UINT_MAX +#define FT_INT_MAX INT_MAX +#define FT_ULONG_MAX ULONG_MAX + +#define ADD_INT( a, b ) \ + (int)( (unsigned int)(a) + (unsigned int)(b) ) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) + + +#define ft_memset memset + +#define ft_setjmp setjmp +#define ft_longjmp longjmp +#define ft_jmp_buf jmp_buf + +typedef ptrdiff_t FT_PtrDist; + + +#define Smooth_Err_Ok 0 +#define Smooth_Err_Invalid_Outline -1 +#define Smooth_Err_Cannot_Render_Glyph -2 +#define Smooth_Err_Invalid_Argument -3 +#define Smooth_Err_Raster_Overflow -4 + +#define FT_BEGIN_HEADER +#define FT_END_HEADER + +#include "ftimage.h" +#include "ftgrays.h" + + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + + /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + void + FT_Message( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + } + + + /* empty function useful for setting a breakpoint to catch errors */ + int + FT_Throw( int error, + int line, + const char* file ) + { + FT_UNUSED( error ); + FT_UNUSED( line ); + FT_UNUSED( file ); + + return 0; + } + + + /* we don't handle tracing levels in stand-alone mode; */ +#ifndef FT_TRACE5 +#define FT_TRACE5( varformat ) FT_Message varformat +#endif +#ifndef FT_TRACE7 +#define FT_TRACE7( varformat ) FT_Message varformat +#endif +#ifndef FT_ERROR +#define FT_ERROR( varformat ) FT_Message varformat +#endif + +#define FT_THROW( e ) \ + ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ), \ + __LINE__, \ + __FILE__ ) | \ + FT_ERR_CAT( Smooth_Err_, e ) ) + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ +#define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ +#define FT_THROW( e ) FT_ERR_CAT( Smooth_Err_, e ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#define FT_Trace_Enable() do { } while ( 0 ) /* nothing */ +#define FT_Trace_Disable() do { } while ( 0 ) /* nothing */ + + +#define FT_DEFINE_OUTLINE_FUNCS( class_, \ + move_to_, line_to_, \ + conic_to_, cubic_to_, \ + shift_, delta_ ) \ + static const FT_Outline_Funcs class_ = \ + { \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ \ + }; + +#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \ + raster_new_, raster_reset_, \ + raster_set_mode_, raster_render_, \ + raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; + + +#else /* !STANDALONE_ */ + + +#include +#include FT_CONFIG_CONFIG_H +#include "ftgrays.h" +#include +#include +#include +#include + +#include "ftsmerrs.h" + + +#endif /* !STANDALONE_ */ + + +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif + +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif + +#ifndef FT_ZERO +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) +#endif + + /* as usual, for the speed hungry :-) */ + +#undef RAS_ARG +#undef RAS_ARG_ +#undef RAS_VAR +#undef RAS_VAR_ + +#ifndef FT_STATIC_RASTER + +#define RAS_ARG gray_PWorker worker +#define RAS_ARG_ gray_PWorker worker, + +#define RAS_VAR worker +#define RAS_VAR_ worker, + +#else /* FT_STATIC_RASTER */ + +#define RAS_ARG void +#define RAS_ARG_ /* empty */ +#define RAS_VAR /* empty */ +#define RAS_VAR_ /* empty */ + +#endif /* FT_STATIC_RASTER */ + + + /* must be at least 6 bits! */ +#define PIXEL_BITS 8 + +#define ONE_PIXEL ( 1 << PIXEL_BITS ) +#undef TRUNC +#define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS ) +#undef FRACT +#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) + +#if PIXEL_BITS >= 6 +#define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) ) +#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) +#else +#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) +#define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) ) +#endif + + + /* Compute `dividend / divisor' and return both its quotient and */ + /* remainder, cast to a specific type. This macro also ensures that */ + /* the remainder is always positive. We use the remainder to keep */ + /* track of accumulating errors and compensate for them. */ +#define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ + FT_BEGIN_STMNT \ + (quotient) = (type)( (dividend) / (divisor) ); \ + (remainder) = (type)( (dividend) % (divisor) ); \ + if ( (remainder) < 0 ) \ + { \ + (quotient)--; \ + (remainder) += (type)(divisor); \ + } \ + FT_END_STMNT + +#if defined( __GNUC__ ) && __GNUC__ < 7 && defined( __arm__ ) + /* Work around a bug specific to GCC which make the compiler fail to */ + /* optimize a division and modulo operation on the same parameters */ + /* into a single call to `__aeabi_idivmod'. See */ + /* */ + /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */ +#undef FT_DIV_MOD +#define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ + FT_BEGIN_STMNT \ + (quotient) = (type)( (dividend) / (divisor) ); \ + (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \ + if ( (remainder) < 0 ) \ + { \ + (quotient)--; \ + (remainder) += (type)(divisor); \ + } \ + FT_END_STMNT +#endif /* __arm__ */ + + + /* Calculating coverages for a slanted line requires a division each */ + /* time the line crosses from cell to cell. These macros speed up */ + /* the repetitive divisions by replacing them with multiplications */ + /* and right shifts so that at most two divisions are performed for */ + /* each slanted line. Nevertheless, these divisions are noticeable */ + /* in the overall performance because flattened curves produce a */ + /* very large number of slanted lines. */ + /* */ + /* The division results here are always within ONE_PIXEL. Therefore */ + /* the shift magnitude should be at least PIXEL_BITS wider than the */ + /* divisors to provide sufficient accuracy of the multiply-shift. */ + /* It should not exceed (64 - PIXEL_BITS) to prevent overflowing and */ + /* leave enough room for 64-bit unsigned multiplication however. */ +#define FT_UDIVPREP( c, b ) \ + FT_Int64 b ## _r = c ? (FT_Int64)0xFFFFFFFF / ( b ) : 0 +#define FT_UDIV( a, b ) \ + (TCoord)( ( (FT_UInt64)( a ) * (FT_UInt64)( b ## _r ) ) >> 32 ) + + + /* Scale area and apply fill rule to calculate the coverage byte. */ + /* The top fill bit is used for the non-zero rule. The eighth */ + /* fill bit is used for the even-odd rule. The higher coverage */ + /* bytes are either clamped for the non-zero-rule or discarded */ + /* later for the even-odd rule. */ +#define FT_FILL_RULE( coverage, area, fill ) \ + FT_BEGIN_STMNT \ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \ + if ( coverage & fill ) \ + coverage = ~coverage; \ + if ( coverage > 255 && fill & INT_MIN ) \ + coverage = 255; \ + FT_END_STMNT + + + /* It is faster to write small spans byte-by-byte than calling */ + /* `memset'. This is mainly due to the cost of the function call. */ +#define FT_GRAY_SET( d, s, count ) \ + FT_BEGIN_STMNT \ + unsigned char* q = d; \ + switch ( count ) \ + { \ + case 7: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 6: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 5: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 4: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 3: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 2: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 1: *q = (unsigned char)s; FALL_THROUGH; \ + case 0: break; \ + default: FT_MEM_SET( d, s, count ); \ + } \ + FT_END_STMNT + + + /************************************************************************** + * + * TYPE DEFINITIONS + */ + + /* don't change the following types to FT_Int or FT_Pos, since we might */ + /* need to define them to "float" or "double" when experimenting with */ + /* new algorithms */ + + typedef long TPos; /* subpixel coordinate */ + typedef int TCoord; /* integer scanline/pixel coordinate */ + typedef int TArea; /* cell areas, coordinate products */ + + + typedef struct TCell_* PCell; + + typedef struct TCell_ + { + TCoord x; /* same with gray_TWorker.ex */ + TCoord cover; /* same with gray_TWorker.cover */ + TArea area; + PCell next; + + } TCell; + + typedef struct TPixmap_ + { + unsigned char* origin; /* pixmap origin at the bottom-left */ + int pitch; /* pitch to go down one row */ + + } TPixmap; + + /* maximum number of gray cells in the buffer */ +#if FT_RENDER_POOL_SIZE > 2048 +#define FT_MAX_GRAY_POOL ( FT_RENDER_POOL_SIZE / sizeof ( TCell ) ) +#else +#define FT_MAX_GRAY_POOL ( 2048 / sizeof ( TCell ) ) +#endif + + /* FT_Span buffer size for direct rendering only */ +#define FT_MAX_GRAY_SPANS 16 + + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `structure was padded due to */ + /* __declspec(align())' in order to compile cleanly with */ + /* the maximum level of warnings. */ +#pragma warning( push ) +#pragma warning( disable : 4324 ) +#endif /* _MSC_VER */ + + typedef struct gray_TWorker_ + { + ft_jmp_buf jump_buffer; + + TCoord min_ex, max_ex; /* min and max integer pixel coordinates */ + TCoord min_ey, max_ey; + TCoord count_ey; /* same as (max_ey - min_ey) */ + + PCell cell; /* current cell */ + PCell cell_free; /* call allocation next free slot */ + PCell cell_null; /* last cell, used as dumpster and limit */ + + PCell* ycells; /* array of cell linked-lists; one per */ + /* vertical coordinate in the current band */ + + TPos x, y; /* last point position */ + + FT_Outline outline; /* input outline */ + TPixmap target; /* target pixmap */ + + FT_Raster_Span_Func render_span; + void* render_span_data; + + } gray_TWorker, *gray_PWorker; + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + +#ifndef FT_STATIC_RASTER +#define ras (*worker) +#else + static gray_TWorker ras; +#endif + + /* The |x| value of the null cell. Must be the largest possible */ + /* integer value stored in a `TCell.x` field. */ +#define CELL_MAX_X_VALUE INT_MAX + + +#define FT_INTEGRATE( ras, a, b ) \ + ras.cell->cover = ADD_INT( ras.cell->cover, a ), \ + ras.cell->area = ADD_INT( ras.cell->area, (a) * (TArea)(b) ) + + + typedef struct gray_TRaster_ + { + void* memory; + + } gray_TRaster, *gray_PRaster; + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* to be called while in the debugger -- */ + /* this function causes a compiler warning since it is unused otherwise */ + static void + gray_dump_cells( RAS_ARG ) + { + int y; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + + + printf( "%3d:", y ); + + for ( ; cell != ras.cell_null; cell = cell->next ) + printf( " (%3d, c:%4d, a:%6d)", + cell->x, cell->cover, cell->area ); + printf( "\n" ); + } + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * Set the current cell to a new position. + */ + static void + gray_set_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + /* Move the cell pointer to a new position in the linked list. We use */ + /* a dumpster null cell for everything outside of the clipping region */ + /* during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* Note that if a cell is to the left of the clipping region, it is */ + /* actually set to the (min_ex-1) horizontal position. */ + + TCoord ey_index = ey - ras.min_ey; + + + if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex ) + ras.cell = ras.cell_null; + else + { + PCell* pcell = ras.ycells + ey_index; + PCell cell; + + + ex = FT_MAX( ex, ras.min_ex - 1 ); + + while ( 1 ) + { + cell = *pcell; + + if ( cell->x > ex ) + break; + + if ( cell->x == ex ) + goto Found; + + pcell = &cell->next; + } + + /* insert new cell */ + cell = ras.cell_free++; + if ( cell >= ras.cell_null ) + ft_longjmp( ras.jump_buffer, 1 ); + + cell->x = ex; + cell->area = 0; + cell->cover = 0; + + cell->next = *pcell; + *pcell = cell; + + Found: + ras.cell = cell; + } + } + + +#ifndef FT_INT64 + + /************************************************************************** + * + * Render a scanline as one or more cells. + */ + static void + gray_render_scanline( RAS_ARG_ TCoord ey, + TPos x1, + TCoord y1, + TPos x2, + TCoord y2 ) + { + TCoord ex1, ex2, fx1, fx2, first, dy, delta, mod; + TPos p, dx; + int incr; + + + ex1 = TRUNC( x1 ); + ex2 = TRUNC( x2 ); + + /* trivial case. Happens often */ + if ( y1 == y2 ) + { + gray_set_cell( RAS_VAR_ ex2, ey ); + return; + } + + fx1 = FRACT( x1 ); + fx2 = FRACT( x2 ); + + /* everything is located in a single cell. That is easy! */ + /* */ + if ( ex1 == ex2 ) + goto End; + + /* ok, we'll have to render a run of adjacent cells on the same */ + /* scanline... */ + /* */ + dx = x2 - x1; + dy = y2 - y1; + + if ( dx > 0 ) + { + p = ( ONE_PIXEL - fx1 ) * dy; + first = ONE_PIXEL; + incr = 1; + } + else + { + p = fx1 * dy; + first = 0; + incr = -1; + dx = -dx; + } + + /* the fractional part of y-delta is mod/dx. It is essential to */ + /* keep track of its accumulation for accurate rendering. */ + /* XXX: y-delta and x-delta below should be related. */ + FT_DIV_MOD( TCoord, p, dx, delta, mod ); + + FT_INTEGRATE( ras, delta, fx1 + first ); + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + + if ( ex1 != ex2 ) + { + TCoord lift, rem; + + + p = ONE_PIXEL * dy; + FT_DIV_MOD( TCoord, p, dx, lift, rem ); + + do + { + delta = lift; + mod += rem; + if ( mod >= (TCoord)dx ) + { + mod -= (TCoord)dx; + delta++; + } + + FT_INTEGRATE( ras, delta, ONE_PIXEL ); + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + } while ( ex1 != ex2 ); + } + + fx1 = ONE_PIXEL - first; + + End: + FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 ); + } + + + /************************************************************************** + * + * Render a given line as a series of scanlines. + */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TCoord ey1, ey2, fy1, fy2, first, delta, mod; + TPos p, dx, dy, x, x2; + int incr; + + + ey1 = TRUNC( ras.y ); + ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ + + /* perform vertical clipping */ + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + goto End; + + fy1 = FRACT( ras.y ); + fy2 = FRACT( to_y ); + + /* everything is on a single scanline */ + if ( ey1 == ey2 ) + { + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); + goto End; + } + + dx = to_x - ras.x; + dy = to_y - ras.y; + + /* vertical line - avoid calling gray_render_scanline */ + if ( dx == 0 ) + { + TCoord ex = TRUNC( ras.x ); + TCoord two_fx = FRACT( ras.x ) << 1; + + + if ( dy > 0) + { + first = ONE_PIXEL; + incr = 1; + } + else + { + first = 0; + incr = -1; + } + + delta = first - fy1; + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; + + gray_set_cell( RAS_VAR_ ex, ey1 ); + + delta = first + first - ONE_PIXEL; + while ( ey1 != ey2 ) + { + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; + + gray_set_cell( RAS_VAR_ ex, ey1 ); + } + + delta = fy2 - ONE_PIXEL + first; + FT_INTEGRATE( ras, delta, two_fx); + + goto End; + } + + /* ok, we have to render several scanlines */ + if ( dy > 0) + { + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + } + else + { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + + /* the fractional part of x-delta is mod/dy. It is essential to */ + /* keep track of its accumulation for accurate rendering. */ + FT_DIV_MOD( TCoord, p, dy, delta, mod ); + + x = ras.x + delta; + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ); + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + + if ( ey1 != ey2 ) + { + TCoord lift, rem; + + + p = ONE_PIXEL * dx; + FT_DIV_MOD( TCoord, p, dy, lift, rem ); + + do + { + delta = lift; + mod += rem; + if ( mod >= (TCoord)dy ) + { + mod -= (TCoord)dy; + delta++; + } + + x2 = x + delta; + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + x2, first ); + x = x2; + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + } while ( ey1 != ey2 ); + } + + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + to_x, fy2 ); + + End: + ras.x = to_x; + ras.y = to_y; + } + +#else + + /************************************************************************** + * + * Render a straight line across multiple cells in any direction. + */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TPos dx, dy; + TCoord fx1, fy1, fx2, fy2; + TCoord ex1, ey1, ex2, ey2; + + + ey1 = TRUNC( ras.y ); + ey2 = TRUNC( to_y ); + + /* perform vertical clipping */ + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + goto End; + + ex1 = TRUNC( ras.x ); + ex2 = TRUNC( to_x ); + + fx1 = FRACT( ras.x ); + fy1 = FRACT( ras.y ); + + dx = to_x - ras.x; + dy = to_y - ras.y; + + if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ + ; + else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */ + { + gray_set_cell( RAS_VAR_ ex2, ey2 ); + goto End; + } + else if ( dx == 0 ) + { + if ( dy > 0 ) /* vertical line up */ + do + { + fy2 = ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); + fy1 = 0; + ey1++; + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + else /* vertical line down */ + do + { + fy2 = 0; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); + fy1 = ONE_PIXEL; + ey1--; + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + } + else /* any other line */ + { + FT_Int64 prod = dx * (FT_Int64)fy1 - dy * (FT_Int64)fx1; + FT_UDIVPREP( ex1 != ex2, dx ); + FT_UDIVPREP( ey1 != ey2, dy ); + + + /* The fundamental value `prod' determines which side and the */ + /* exact coordinate where the line exits current cell. It is */ + /* also easily updated when moving from one cell to the next. */ + do + { + if ( prod - dx * ONE_PIXEL > 0 && + prod <= 0 ) /* left */ + { + fx2 = 0; + fy2 = FT_UDIV( -prod, -dx ); + prod -= dy * ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = ONE_PIXEL; + fy1 = fy2; + ex1--; + } + else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 && + prod - dx * ONE_PIXEL <= 0 ) /* up */ + { + prod -= dx * ONE_PIXEL; + fx2 = FT_UDIV( -prod, dy ); + fy2 = ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = fx2; + fy1 = 0; + ey1++; + } + else if ( prod + dy * ONE_PIXEL >= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */ + { + prod += dy * ONE_PIXEL; + fx2 = ONE_PIXEL; + fy2 = FT_UDIV( prod, dx ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = 0; + fy1 = fy2; + ex1++; + } + else /* ( prod > 0 && + prod + dy * ONE_PIXEL < 0 ) down */ + { + fx2 = FT_UDIV( prod, -dy ); + fy2 = 0; + prod += dx * ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = fx2; + fy1 = ONE_PIXEL; + ey1--; + } + + gray_set_cell( RAS_VAR_ ex1, ey1 ); + + } while ( ex1 != ex2 || ey1 != ey2 ); + } + + fx2 = FRACT( to_x ); + fy2 = FRACT( to_y ); + + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + + End: + ras.x = to_x; + ras.y = to_y; + } + +#endif + + /* + * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs + * is slightly faster in the following cases: + * + * - When the host CPU is 64-bit. + * - When SSE2 SIMD registers and instructions are available (even on + * x86). + * + * For other cases, using binary splits is actually slightly faster. + */ +#if ( defined( __SSE2__ ) || \ + defined( __x86_64__ ) || \ + defined( _M_AMD64 ) || \ + ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 ) ) && \ + !defined( __VMS ) +# define FT_SSE2 1 +#else +# define FT_SSE2 0 +#endif + +#if FT_SSE2 || \ + defined( __aarch64__ ) || \ + defined( _M_ARM64 ) +# define BEZIER_USE_DDA 1 +#else +# define BEZIER_USE_DDA 0 +#endif + + /* + * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64` + * to be defined. If `FT_INT64` is not defined, meaning there is no + * 64-bit type available, disable it to avoid compilation errors. See for + * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. + */ +#if !defined( FT_INT64 ) +# undef BEZIER_USE_DDA +# define BEZIER_USE_DDA 0 +#endif + +#if BEZIER_USE_DDA + +#if FT_SSE2 +# include +#endif + +#define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) ) + + + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + FT_Vector p0, p1, p2; + TPos ax, ay, bx, by, dx, dy; + int shift; + + FT_Int64 rx, ry; + FT_Int64 qx, qy; + FT_Int64 px, py; + + FT_UInt count; + + + p0.x = ras.x; + p0.y = ras.y; + p1.x = UPSCALE( control->x ); + p1.y = UPSCALE( control->y ); + p2.x = UPSCALE( to->x ); + p2.y = UPSCALE( to->y ); + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( p0.y ) >= ras.max_ey && + TRUNC( p1.y ) >= ras.max_ey && + TRUNC( p2.y ) >= ras.max_ey ) || + ( TRUNC( p0.y ) < ras.min_ey && + TRUNC( p1.y ) < ras.min_ey && + TRUNC( p2.y ) < ras.min_ey ) ) + { + ras.x = p2.x; + ras.y = p2.y; + return; + } + + bx = p1.x - p0.x; + by = p1.y - p0.y; + ax = p2.x - p1.x - bx; /* p0.x + p2.x - 2 * p1.x */ + ay = p2.y - p1.y - by; /* p0.y + p2.y - 2 * p1.y */ + + dx = FT_ABS( ax ); + dy = FT_ABS( ay ); + if ( dx < dy ) + dx = dy; + + if ( dx <= ONE_PIXEL / 4 ) + { + gray_render_line( RAS_VAR_ p2.x, p2.y ); + return; + } + + /* We can calculate the number of necessary bisections because */ + /* each bisection predictably reduces deviation exactly 4-fold. */ + /* Even 32-bit deviation would vanish after 16 bisections. */ + shift = 0; + do + { + dx >>= 2; + shift += 1; + + } while ( dx > ONE_PIXEL / 4 ); + + /* + * The (P0,P1,P2) arc equation, for t in [0,1] range: + * + * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2 + * + * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2 + * = P0 + 2*B*t + A*t^2 + * + * for A = P0 + P2 - 2*P1 + * and B = P1 - P0 + * + * Let's consider the difference when advancing by a small + * parameter h: + * + * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t + * + * And then its own difference: + * + * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant) + * + * Since R is always a constant, it is possible to compute + * successive positions with: + * + * P = P0 + * Q = Q(h,0) = 2*B*h + A*h*h + * R = 2*A*h*h + * + * loop: + * P += Q + * Q += R + * EMIT(P) + * + * To ensure accurate results, perform computations on 64-bit + * values, after scaling them by 2^32. + * + * h = 1 / 2^N + * + * R << 32 = 2 * A << (32 - N - N) + * = A << (33 - 2*N) + * + * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N)) + * = (B << (33 - N)) + (A << (32 - 2*N)) + */ + +#if FT_SSE2 + /* Experience shows that for small shift values, */ + /* SSE2 is actually slower. */ + if ( shift > 2 ) + { + union + { + struct { FT_Int64 ax, ay, bx, by; } i; + struct { __m128i a, b; } vec; + + } u; + + union + { + struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i; + __m128i vec; + + } v; + + __m128i a, b; + __m128i r, q, q2; + __m128i p; + + + u.i.ax = ax; + u.i.ay = ay; + u.i.bx = bx; + u.i.by = by; + + a = _mm_load_si128( &u.vec.a ); + b = _mm_load_si128( &u.vec.b ); + + r = _mm_slli_epi64( a, 33 - 2 * shift ); + q = _mm_slli_epi64( b, 33 - shift ); + q2 = _mm_slli_epi64( a, 32 - 2 * shift ); + + q = _mm_add_epi64( q2, q ); + + v.i.px_lo = 0; + v.i.px_hi = p0.x; + v.i.py_lo = 0; + v.i.py_hi = p0.y; + + p = _mm_load_si128( &v.vec ); + + for ( count = 1U << shift; count > 0; count-- ) + { + p = _mm_add_epi64( p, q ); + q = _mm_add_epi64( q, r ); + + _mm_store_si128( &v.vec, p ); + + gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi ); + } + + return; + } +#endif /* FT_SSE2 */ + + rx = LEFT_SHIFT( ax, 33 - 2 * shift ); + ry = LEFT_SHIFT( ay, 33 - 2 * shift ); + + qx = LEFT_SHIFT( bx, 33 - shift ) + LEFT_SHIFT( ax, 32 - 2 * shift ); + qy = LEFT_SHIFT( by, 33 - shift ) + LEFT_SHIFT( ay, 32 - 2 * shift ); + + px = LEFT_SHIFT( p0.x, 32 ); + py = LEFT_SHIFT( p0.y, 32 ); + + for ( count = 1U << shift; count > 0; count-- ) + { + px += qx; + py += qy; + qx += rx; + qy += ry; + + gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ), + (FT_Pos)( py >> 32 ) ); + } + } + +#else /* !BEZIER_USE_DDA */ + + /* + * Note that multiple attempts to speed up the function below + * with SSE2 intrinsics, using various data layouts, have turned + * out to be slower than the non-SIMD code below. + */ + static void + gray_split_conic( FT_Vector* base ) + { + TPos a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; + } + + + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ + FT_Vector* arc = bez_stack; + TPos dx, dy; + int draw; + + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control->x ); + arc[1].y = UPSCALE( control->y ); + arc[2].x = ras.x; + arc[2].y = ras.y; + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( arc[0].y ) >= ras.max_ey && + TRUNC( arc[1].y ) >= ras.max_ey && + TRUNC( arc[2].y ) >= ras.max_ey ) || + ( TRUNC( arc[0].y ) < ras.min_ey && + TRUNC( arc[1].y ) < ras.min_ey && + TRUNC( arc[2].y ) < ras.min_ey ) ) + { + ras.x = arc[0].x; + ras.y = arc[0].y; + return; + } + + dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); + dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); + if ( dx < dy ) + dx = dy; + + /* We can calculate the number of necessary bisections because */ + /* each bisection predictably reduces deviation exactly 4-fold. */ + /* Even 32-bit deviation would vanish after 16 bisections. */ + draw = 1; + while ( dx > ONE_PIXEL / 4 ) + { + dx >>= 2; + draw <<= 1; + } + + /* We use decrement counter to count the total number of segments */ + /* to draw starting from 2^level. Before each draw we split as */ + /* many times as there are trailing zeros in the counter. */ + do + { + int split = draw & ( -draw ); /* isolate the rightmost 1-bit */ + + + while ( ( split >>= 1 ) ) + { + gray_split_conic( arc ); + arc += 2; + } + + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + arc -= 2; + + } while ( --draw ); + } + +#endif /* !BEZIER_USE_DDA */ + + + /* + * For cubic Bézier, binary splits are still faster than DDA + * because the splits are adaptive to how quickly each sub-arc + * approaches their chord trisection points. + * + * It might be useful to experiment with SSE2 to speed up + * `gray_split_cubic`, though. + */ + static void + gray_split_cubic( FT_Vector* base ) + { + TPos a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; + } + + + static void + gray_render_cubic( RAS_ARG_ const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to ) + { + FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */ + FT_Vector* arc = bez_stack; + + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control2->x ); + arc[1].y = UPSCALE( control2->y ); + arc[2].x = UPSCALE( control1->x ); + arc[2].y = UPSCALE( control1->y ); + arc[3].x = ras.x; + arc[3].y = ras.y; + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( arc[0].y ) >= ras.max_ey && + TRUNC( arc[1].y ) >= ras.max_ey && + TRUNC( arc[2].y ) >= ras.max_ey && + TRUNC( arc[3].y ) >= ras.max_ey ) || + ( TRUNC( arc[0].y ) < ras.min_ey && + TRUNC( arc[1].y ) < ras.min_ey && + TRUNC( arc[2].y ) < ras.min_ey && + TRUNC( arc[3].y ) < ras.min_ey ) ) + { + ras.x = arc[0].x; + ras.y = arc[0].y; + return; + } + + for (;;) + { + /* with each split, control points quickly converge towards */ + /* chord trisection points and the vanishing distances below */ + /* indicate when the segment is flat enough to draw */ + if ( FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 || + FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 || + FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 || + FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 ) + goto Split; + + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + + if ( arc == bez_stack ) + return; + + arc -= 3; + continue; + + Split: + gray_split_cubic( arc ); + arc += 3; + } + } + + + static int + gray_move_to( const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + TPos x, y; + + + /* start to a new position */ + x = UPSCALE( to->x ); + y = UPSCALE( to->y ); + + gray_set_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); + + ras.x = x; + ras.y = y; + return 0; + } + + + static int + gray_line_to( const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + + gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); + return 0; + } + + + static int + gray_conic_to( const FT_Vector* control, + const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + + gray_render_conic( RAS_VAR_ control, to ); + return 0; + } + + + static int + gray_cubic_to( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + + gray_render_cubic( RAS_VAR_ control1, control2, to ); + return 0; + } + + + static void + gray_sweep( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + unsigned char* line = ras.target.origin - ras.target.pitch * y; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, cell->x - x ); + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + line[cell->x] = (unsigned char)coverage; + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); + } + } + } + + + static void + gray_sweep_direct( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + FT_Span span[FT_MAX_GRAY_SPANS]; + int n = 0; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( cell->x - x ); + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)cell->x; + span[n].len = 1; + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( ras.max_ex - x ); + + ++n; + } + + if ( n ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + } + + +#ifdef STANDALONE_ + + /************************************************************************** + * + * The following functions should only compile in stand-alone mode, + * i.e., when building this component without the rest of FreeType. + * + */ + + /************************************************************************** + * + * @Function: + * FT_Outline_Decompose + * + * @Description: + * Walk over an outline's structure to decompose it into individual + * segments and Bézier arcs. This function is also able to emit + * `move to' and `close to' operations to indicate the start and end + * of new contours in the outline. + * + * @Input: + * outline :: + * A pointer to the source target. + * + * func_interface :: + * A table of `emitters', i.e., function pointers + * called during decomposition to indicate path + * operations. + * + * @InOut: + * user :: + * A typeless pointer which is passed to each + * emitter during the decomposition. It can be + * used to store the state during the + * decomposition. + * + * @Return: + * Error code. 0 means success. + */ + static int + FT_Outline_Decompose( const FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( (x) * ( 1L << shift ) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + int error; + + int n; /* index of contour in outline */ + int first; /* index of first point in contour */ + int last; /* index of last point in contour */ + + char tag; /* current point's state */ + + int shift; + TPos delta; + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !func_interface ) + return FT_THROW( Invalid_Argument ); + + shift = func_interface->shift; + delta = func_interface->delta; + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n )); + + first = last + 1; + last = outline->contours[n]; + if ( last < first ) + goto Invalid_Outline; + + limit = outline->points + last; + + v_start = outline->points[first]; + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + + v_last = outline->points[last]; + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + FT_TRACE5(( " move to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " line to (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0 )); + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_middle.x / 64.0, v_middle.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + FT_TRACE5(( " line to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + } + + FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); + return Smooth_Err_Ok; + + Exit: + FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); + return error; + + Invalid_Outline: + return FT_THROW( Invalid_Outline ); + } + +#endif /* STANDALONE_ */ + + + FT_DEFINE_OUTLINE_FUNCS( + func_interface, + + (FT_Outline_MoveTo_Func) gray_move_to, /* move_to */ + (FT_Outline_LineTo_Func) gray_line_to, /* line_to */ + (FT_Outline_ConicTo_Func)gray_conic_to, /* conic_to */ + (FT_Outline_CubicTo_Func)gray_cubic_to, /* cubic_to */ + + 0, /* shift */ + 0 /* delta */ + ) + + + static int + gray_convert_glyph_inner( RAS_ARG_ + int continued ) + { + volatile int error; + + + if ( ft_setjmp( ras.jump_buffer ) == 0 ) + { + if ( continued ) + FT_Trace_Disable(); + error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); + if ( continued ) + FT_Trace_Enable(); + + FT_TRACE7(( "band [%d..%d]: %td cell%s remaining/\n", + ras.min_ey, + ras.max_ey, + ras.cell_null - ras.cell_free, + ras.cell_null - ras.cell_free == 1 ? "" : "s" )); + } + else + { + error = FT_THROW( Raster_Overflow ); + + FT_TRACE7(( "band [%d..%d]: to be bisected\n", + ras.min_ey, ras.max_ey )); + } + + return error; + } + + + static int + gray_convert_glyph( RAS_ARG ) + { + const TCoord yMin = ras.min_ey; + const TCoord yMax = ras.max_ey; + + TCell buffer[FT_MAX_GRAY_POOL]; + size_t height = (size_t)( yMax - yMin ); + size_t n = FT_MAX_GRAY_POOL / 8; + TCoord y; + TCoord bands[32]; /* enough to accommodate bisections */ + TCoord* band; + + int continued = 0; + + + /* Initialize the null cell at the end of the poll. */ + ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1; + ras.cell_null->x = CELL_MAX_X_VALUE; + ras.cell_null->area = 0; + ras.cell_null->cover = 0; + ras.cell_null->next = NULL; + + /* set up vertical bands */ + ras.ycells = (PCell*)buffer; + + if ( height > n ) + { + /* two divisions rounded up */ + n = ( height + n - 1 ) / n; + height = ( height + n - 1 ) / n; + } + + for ( y = yMin; y < yMax; ) + { + ras.min_ey = y; + y += height; + ras.max_ey = FT_MIN( y, yMax ); + + band = bands; + band[1] = ras.min_ey; + band[0] = ras.max_ey; + + do + { + TCoord width = band[0] - band[1]; + TCoord w; + int error; + + + for ( w = 0; w < width; ++w ) + ras.ycells[w] = ras.cell_null; + + /* memory management: skip ycells */ + n = ( (size_t)width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / + sizeof ( TCell ); + + ras.cell_free = buffer + n; + ras.cell = ras.cell_null; + ras.min_ey = band[1]; + ras.max_ey = band[0]; + ras.count_ey = width; + + error = gray_convert_glyph_inner( RAS_VAR_ continued ); + continued = 1; + + if ( !error ) + { + if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ + gray_sweep_direct( RAS_VAR ); + else + gray_sweep( RAS_VAR ); + band--; + continue; + } + else if ( error != Smooth_Err_Raster_Overflow ) + return error; + + /* render pool overflow; we will reduce the render band by half */ + width >>= 1; + + /* this should never happen even with tiny rendering pool */ + if ( width == 0 ) + { + FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); + return FT_THROW( Raster_Overflow ); + } + + band++; + band[1] = band[0]; + band[0] += width; + } while ( band >= bands ); + } + + return Smooth_Err_Ok; + } + + + static int + gray_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + +#ifndef FT_STATIC_RASTER + gray_TWorker worker[1]; +#endif + + + if ( !raster ) + return FT_THROW( Invalid_Argument ); + + /* this version does not support monochrome rendering */ + if ( !( params->flags & FT_RASTER_FLAG_AA ) ) + return FT_THROW( Cannot_Render_Glyph ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return Smooth_Err_Ok; + + if ( !outline->contours || !outline->points ) + return FT_THROW( Invalid_Outline ); + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return FT_THROW( Invalid_Outline ); + + ras.outline = *outline; + + if ( params->flags & FT_RASTER_FLAG_DIRECT ) + { + if ( !params->gray_spans ) + return Smooth_Err_Ok; + + ras.render_span = (FT_Raster_Span_Func)params->gray_spans; + ras.render_span_data = params->user; + + ras.min_ex = params->clip_box.xMin; + ras.min_ey = params->clip_box.yMin; + ras.max_ex = params->clip_box.xMax; + ras.max_ey = params->clip_box.yMax; + } + else + { + /* if direct mode is not set, we must have a target bitmap */ + if ( !target_map ) + return FT_THROW( Invalid_Argument ); + + /* nothing to do */ + if ( !target_map->width || !target_map->rows ) + return Smooth_Err_Ok; + + if ( !target_map->buffer ) + return FT_THROW( Invalid_Argument ); + + if ( target_map->pitch < 0 ) + ras.target.origin = target_map->buffer; + else + ras.target.origin = target_map->buffer + + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch; + + ras.target.pitch = target_map->pitch; + + ras.render_span = (FT_Raster_Span_Func)NULL; + ras.render_span_data = NULL; + + ras.min_ex = 0; + ras.min_ey = 0; + ras.max_ex = (FT_Pos)target_map->width; + ras.max_ey = (FT_Pos)target_map->rows; + } + + /* exit if nothing to do */ + if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey ) + return Smooth_Err_Ok; + + return gray_convert_glyph( RAS_VAR ); + } + + + /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ + /**** a static object. *****/ + +#ifdef STANDALONE_ + + static int + gray_raster_new( void* memory, + FT_Raster* araster ) + { + static gray_TRaster the_raster; + + FT_UNUSED( memory ); + + + *araster = (FT_Raster)&the_raster; + FT_ZERO( &the_raster ); + + return 0; + } + + + static void + gray_raster_done( FT_Raster raster ) + { + /* nothing */ + FT_UNUSED( raster ); + } + +#else /* !STANDALONE_ */ + + static int + gray_raster_new( void* memory_, + FT_Raster* araster_ ) + { + FT_Memory memory = (FT_Memory)memory_; + gray_PRaster* araster = (gray_PRaster*)araster_; + + FT_Error error; + gray_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + static void + gray_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory; + + + FT_FREE( raster ); + } + +#endif /* !STANDALONE_ */ + + + static void + gray_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + static int + gray_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + + return 0; /* nothing to do */ + } + + + FT_DEFINE_RASTER_FUNCS( + ft_grays_raster, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Raster_New_Func) gray_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) gray_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)gray_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) gray_raster_render, /* raster_render */ + (FT_Raster_Done_Func) gray_raster_done /* raster_done */ + ) + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/vendor/freetype/src/smooth/ftgrays.h b/vendor/freetype/src/smooth/ftgrays.h new file mode 100644 index 0000000..a5001bf --- /dev/null +++ b/vendor/freetype/src/smooth/ftgrays.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * + * ftgrays.h + * + * FreeType smooth renderer declaration + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGRAYS_H_ +#define FTGRAYS_H_ + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifdef STANDALONE_ +#include "ftimage.h" +#else +#include +#include +#endif + + + /************************************************************************** + * + * To make ftgrays.h independent from configuration files we check + * whether FT_EXPORT_VAR has been defined already. + * + * On some systems and compilers (Win32 mostly), an extra keyword is + * necessary to compile the library as a DLL. + */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster; + + +#ifdef __cplusplus + } +#endif + +#endif /* FTGRAYS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/smooth/ftsmerrs.h b/vendor/freetype/src/smooth/ftsmerrs.h new file mode 100644 index 0000000..f4ac93d --- /dev/null +++ b/vendor/freetype/src/smooth/ftsmerrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * ftsmerrs.h + * + * smooth renderer error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the smooth renderer error enumeration + * constants. + * + */ + +#ifndef FTSMERRS_H_ +#define FTSMERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Smooth_Err_ +#define FT_ERR_BASE FT_Mod_Err_Smooth + +#include + +#endif /* FTSMERRS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/smooth/ftsmooth.c b/vendor/freetype/src/smooth/ftsmooth.c new file mode 100644 index 0000000..9b0e888 --- /dev/null +++ b/vendor/freetype/src/smooth/ftsmooth.c @@ -0,0 +1,605 @@ +/**************************************************************************** + * + * ftsmooth.c + * + * Anti-aliasing renderer interface (body). + * + * Copyright (C) 2000-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ftsmooth.h" +#include "ftgrays.h" + +#include "ftsmerrs.h" + + + /* sets render-specific mode */ + static FT_Error + ft_smooth_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + /* transform a given glyph image */ + static FT_Error + ft_smooth_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static void + ft_smooth_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_ZERO( cbox ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + typedef struct TOrigin_ + { + unsigned char* origin; /* pixmap origin at the bottom-left */ + int pitch; /* pitch to go down one row */ + + } TOrigin; + +#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + /* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + FT_Vector* sub = render->root.library->lcd_geometry; + + + /* set up default subpixel geometry for striped RGB panels. */ + sub[0].x = -21; + sub[0].y = 0; + sub[1].x = 0; + sub[1].y = 0; + sub[2].x = 21; + sub[2].y = 0; + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return 0; + } + + + /* This function writes every third byte in direct rendering mode */ + static void + ft_smooth_lcd_spans( int y, + int count, + const FT_Span* spans, + void* target_ ) /* TOrigin* */ + { + TOrigin* target = (TOrigin*)target_; + + unsigned char* dst_line = target->origin - y * target->pitch; + unsigned char* dst; + unsigned short w; + + + for ( ; count--; spans++ ) + for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 ) + *dst = spans->coverage; + } + + + static FT_Error + ft_smooth_raster_lcd( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* sub = render->root.library->lcd_geometry; + FT_Pos x, y; + + FT_Raster_Params params; + TOrigin target; + + + /* Render 3 separate coverage bitmaps, shifting the outline. */ + /* Set up direct rendering to record them on each third byte. */ + params.source = outline; + params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; + params.gray_spans = ft_smooth_lcd_spans; + params.user = ⌖ + + params.clip_box.xMin = 0; + params.clip_box.yMin = 0; + params.clip_box.xMax = bitmap->width; + params.clip_box.yMax = bitmap->rows; + + if ( bitmap->pitch < 0 ) + target.origin = bitmap->buffer; + else + target.origin = bitmap->buffer + + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; + + target.pitch = bitmap->pitch; + + FT_Outline_Translate( outline, + -sub[0].x, + -sub[0].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[0].x; + y = sub[0].y; + if ( error ) + goto Exit; + + target.origin++; + FT_Outline_Translate( outline, + sub[0].x - sub[1].x, + sub[0].y - sub[1].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[1].x; + y = sub[1].y; + if ( error ) + goto Exit; + + target.origin++; + FT_Outline_Translate( outline, + sub[1].x - sub[2].x, + sub[1].y - sub[2].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[2].x; + y = sub[2].y; + + Exit: + FT_Outline_Translate( outline, x, y ); + + return error; + } + + + static FT_Error + ft_smooth_raster_lcdv( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + int pitch = bitmap->pitch; + FT_Vector* sub = render->root.library->lcd_geometry; + FT_Pos x, y; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* Render 3 separate coverage bitmaps, shifting the outline. */ + /* Notice that the subpixel geometry vectors are rotated. */ + /* Triple the pitch to render on each third row. */ + bitmap->pitch *= 3; + bitmap->rows /= 3; + + FT_Outline_Translate( outline, + -sub[0].y, + sub[0].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[0].y; + y = -sub[0].x; + if ( error ) + goto Exit; + + bitmap->buffer += pitch; + FT_Outline_Translate( outline, + sub[0].y - sub[1].y, + sub[1].x - sub[0].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[1].y; + y = -sub[1].x; + bitmap->buffer -= pitch; + if ( error ) + goto Exit; + + bitmap->buffer += 2 * pitch; + FT_Outline_Translate( outline, + sub[1].y - sub[2].y, + sub[2].x - sub[1].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[2].y; + y = -sub[2].x; + bitmap->buffer -= 2 * pitch; + + Exit: + FT_Outline_Translate( outline, x, y ); + + bitmap->pitch /= 3; + bitmap->rows *= 3; + + return error; + } + +#else /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + + /* set up default LCD filtering */ + FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT ); + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return 0; + } + + + static FT_Error + ft_smooth_raster_lcd( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* implode outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->x *= 3; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->x /= 3; + + return error; + } + + + static FT_Error + ft_smooth_raster_lcdv( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* implode outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->y *= 3; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->y /= 3; + + return error; + } + +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + +/* Oversampling scale to be used in rendering overlaps */ +#define SCALE ( 1 << 2 ) + + /* This function averages inflated spans in direct rendering mode */ + static void + ft_smooth_overlap_spans( int y, + int count, + const FT_Span* spans, + void* target_ ) + { + TOrigin* target = (TOrigin*)target_; + + + unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch; + unsigned short x; + unsigned int cover, sum; + + + /* When accumulating the oversampled spans we need to assure that */ + /* fully covered pixels are equal to 255 and do not overflow. */ + /* It is important that the SCALE is a power of 2, each subpixel */ + /* cover can also reach a power of 2 after rounding, and the total */ + /* is clamped to 255 when it adds up to 256. */ + for ( ; count--; spans++ ) + { + cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE ); + for ( x = 0; x < spans->len; x++ ) + { + sum = dst[( spans->x + x ) / SCALE] + cover; + dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) ); + } + } + } + + + static FT_Error + ft_smooth_raster_overlap( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + TOrigin target; + + + /* Reject outlines that are too wide for 16-bit FT_Span. */ + /* Other limits are applied upstream with the same error code. */ + if ( bitmap->width * SCALE > 0x7FFF ) + return FT_THROW( Raster_Overflow ); + + /* Set up direct rendering to average oversampled spans. */ + params.source = outline; + params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; + params.gray_spans = ft_smooth_overlap_spans; + params.user = ⌖ + + params.clip_box.xMin = 0; + params.clip_box.yMin = 0; + params.clip_box.xMax = bitmap->width * SCALE; + params.clip_box.yMax = bitmap->rows * SCALE; + + if ( bitmap->pitch < 0 ) + target.origin = bitmap->buffer; + else + target.origin = bitmap->buffer + + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; + + target.pitch = bitmap->pitch; + + /* inflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x *= SCALE; + vec->y *= SCALE; + } + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x /= SCALE; + vec->y /= SCALE; + } + + return error; + } + +#undef SCALE + + static FT_Error + ft_smooth_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = render->root.memory; + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check mode */ + if ( mode != FT_RENDER_MODE_NORMAL && + mode != FT_RENDER_MODE_LIGHT && + mode != FT_RENDER_MODE_LCD && + mode != FT_RENDER_MODE_LCD_V ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) ) + { + error = FT_THROW( Raster_Overflow ); + goto Exit; + } + + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* allocate new one */ + if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + x_shift = 64 * -slot->bitmap_left; + y_shift = 64 * -slot->bitmap_top; + if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) + y_shift += 64 * (FT_Int)bitmap->rows / 3; + else + y_shift += 64 * (FT_Int)bitmap->rows; + + if ( origin ) + { + x_shift += origin->x; + y_shift += origin->y; + } + + /* translate outline to render it into the bitmap */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, x_shift, y_shift ); + + if ( mode == FT_RENDER_MODE_NORMAL || + mode == FT_RENDER_MODE_LIGHT ) + { + if ( outline->flags & FT_OUTLINE_OVERLAP ) + error = ft_smooth_raster_overlap( render, outline, bitmap ); + else + { + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + error = render->raster_render( render->raster, ¶ms ); + } + } + else + { + if ( mode == FT_RENDER_MODE_LCD ) + error = ft_smooth_raster_lcd ( render, outline, bitmap ); + else if ( mode == FT_RENDER_MODE_LCD_V ) + error = ft_smooth_raster_lcdv( render, outline, bitmap ); + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + /* finally apply filtering */ + { + FT_Byte* lcd_weights; + FT_Bitmap_LcdFilterFunc lcd_filter_func; + + + /* Per-face LCD filtering takes priority if set up. */ + if ( slot->face && slot->face->internal->lcd_filter_func ) + { + lcd_weights = slot->face->internal->lcd_weights; + lcd_filter_func = slot->face->internal->lcd_filter_func; + } + else + { + lcd_weights = slot->library->lcd_weights; + lcd_filter_func = slot->library->lcd_filter_func; + } + + if ( lcd_filter_func ) + lcd_filter_func( bitmap, lcd_weights ); + } + +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + } + + Exit: + if ( !error ) + { + /* everything is fine; the glyph is now officially a bitmap */ + slot->format = FT_GLYPH_FORMAT_BITMAP; + } + else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + return error; + } + + + FT_DEFINE_RENDERER( + ft_smooth_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + + "smooth", + 0x10000L, + 0x20000L, + + NULL, /* module specific interface */ + + (FT_Module_Constructor)ft_smooth_init, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) NULL, /* get_interface */ + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_smooth_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_smooth_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ + ) + + +/* END */ diff --git a/vendor/freetype/src/smooth/ftsmooth.h b/vendor/freetype/src/smooth/ftsmooth.h new file mode 100644 index 0000000..f8bdc99 --- /dev/null +++ b/vendor/freetype/src/smooth/ftsmooth.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * ftsmooth.h + * + * Anti-aliasing renderer interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSMOOTH_H_ +#define FTSMOOTH_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_RENDERER( ft_smooth_renderer_class ) + + +FT_END_HEADER + +#endif /* FTSMOOTH_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/smooth/module.mk b/vendor/freetype/src/smooth/module.mk new file mode 100644 index 0000000..82ab2fa --- /dev/null +++ b/vendor/freetype/src/smooth/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 smooth renderer module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += SMOOTH_RENDERER + +define SMOOTH_RENDERER +$(OPEN_DRIVER) FT_Renderer_Class, ft_smooth_renderer_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)smooth $(ECHO_DRIVER_DESC)anti-aliased bitmap renderer$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/smooth/rules.mk b/vendor/freetype/src/smooth/rules.mk new file mode 100644 index 0000000..5d89c75 --- /dev/null +++ b/vendor/freetype/src/smooth/rules.mk @@ -0,0 +1,73 @@ +# +# FreeType 2 smooth renderer module build rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# smooth driver directory +# +SMOOTH_DIR := $(SRC_DIR)/smooth + + +# compilation flags for the driver +# +SMOOTH_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(SMOOTH_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# smooth driver sources (i.e., C files) +# +SMOOTH_DRV_SRC := $(SMOOTH_DIR)/ftgrays.c \ + $(SMOOTH_DIR)/ftsmooth.c + + +# smooth driver headers +# +SMOOTH_DRV_H := $(SMOOTH_DRV_SRC:%c=%h) \ + $(SMOOTH_DIR)/ftsmerrs.h + + +# smooth driver object(s) +# +# SMOOTH_DRV_OBJ_M is used during `multi' builds. +# SMOOTH_DRV_OBJ_S is used during `single' builds. +# +SMOOTH_DRV_OBJ_M := $(SMOOTH_DRV_SRC:$(SMOOTH_DIR)/%.c=$(OBJ_DIR)/%.$O) +SMOOTH_DRV_OBJ_S := $(OBJ_DIR)/smooth.$O + +# smooth driver source file for single build +# +SMOOTH_DRV_SRC_S := $(SMOOTH_DIR)/smooth.c + + +# smooth driver - single object +# +$(SMOOTH_DRV_OBJ_S): $(SMOOTH_DRV_SRC_S) $(SMOOTH_DRV_SRC) \ + $(FREETYPE_H) $(SMOOTH_DRV_H) + $(SMOOTH_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(SMOOTH_DRV_SRC_S)) + + +# smooth driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(SMOOTH_DIR)/%.c $(FREETYPE_H) $(SMOOTH_DRV_H) + $(SMOOTH_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(SMOOTH_DRV_OBJ_S) +DRV_OBJS_M += $(SMOOTH_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/smooth/smooth.c b/vendor/freetype/src/smooth/smooth.c new file mode 100644 index 0000000..9a0b824 --- /dev/null +++ b/vendor/freetype/src/smooth/smooth.c @@ -0,0 +1,25 @@ +/**************************************************************************** + * + * smooth.c + * + * FreeType anti-aliasing rasterer module component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftgrays.c" +#include "ftsmooth.c" + + +/* END */ diff --git a/vendor/freetype/src/svg/ftsvg.c b/vendor/freetype/src/svg/ftsvg.c new file mode 100644 index 0000000..ba237f6 --- /dev/null +++ b/vendor/freetype/src/svg/ftsvg.c @@ -0,0 +1,355 @@ +/**************************************************************************** + * + * ftsvg.c + * + * The FreeType SVG renderer interface (body). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "ftsvg.h" +#include "svgtypes.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otsvg + + +#ifdef FT_CONFIG_OPTION_SVG + + /* ft_svg_init */ + static FT_Error + ft_svg_init( FT_Module module ) + { + SVG_Renderer render = (SVG_Renderer)module; + + FT_Error error = FT_Err_Ok; + + + render->loaded = FALSE; + render->hooks_set = FALSE; + + return error; + } + + + static void + ft_svg_done( FT_Module module ) + { + SVG_Renderer render = (SVG_Renderer)module; + + + if ( render->loaded == TRUE && + render->hooks_set == TRUE ) + render->hooks.free_svg( &render->state ); + + render->loaded = FALSE; + } + + + static FT_Error + ft_svg_preset_slot( FT_Module module, + FT_GlyphSlot slot, + FT_Bool cache ) + { + SVG_Renderer svg_renderer = (SVG_Renderer)module; + SVG_RendererHooks hooks = svg_renderer->hooks; + + + if ( svg_renderer->hooks_set == FALSE ) + { + FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); + return FT_THROW( Missing_SVG_Hooks ); + } + + if ( svg_renderer->loaded == FALSE ) + { + FT_TRACE3(( "ft_svg_preset_slot: first presetting call," + " calling init hook\n" )); + hooks.init_svg( &svg_renderer->state ); + + svg_renderer->loaded = TRUE; + } + + return hooks.preset_slot( slot, cache, &svg_renderer->state ); + } + + + static FT_Error + ft_svg_render( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + SVG_Renderer svg_renderer = (SVG_Renderer)renderer; + + FT_Library library = renderer->root.library; + FT_Memory memory = library->memory; + FT_Error error; + + FT_ULong size_image_buffer; + + SVG_RendererHooks hooks = svg_renderer->hooks; + + + FT_UNUSED( mode ); + FT_UNUSED( origin ); + + if ( mode != FT_RENDER_MODE_NORMAL ) + return FT_THROW( Bad_Argument ); + + if ( svg_renderer->hooks_set == FALSE ) + { + FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); + return FT_THROW( Missing_SVG_Hooks ); + } + + if ( svg_renderer->loaded == FALSE ) + { + FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" )); + error = hooks.init_svg( &svg_renderer->state ); + + svg_renderer->loaded = TRUE; + } + + ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE ); + + size_image_buffer = (FT_ULong)slot->bitmap.pitch * slot->bitmap.rows; + /* No `FT_QALLOC` here since we need a clean, empty canvas */ + /* to start with. */ + if ( FT_ALLOC( slot->bitmap.buffer, size_image_buffer ) ) + return error; + + error = hooks.render_svg( slot, &svg_renderer->state ); + if ( error ) + FT_FREE( slot->bitmap.buffer ); + else + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + return error; + } + + + static const SVG_Interface svg_interface = + { + ft_svg_preset_slot /* Preset_Bitmap_Func preset_slot */ + }; + + + static FT_Error + ft_svg_property_set( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + SVG_Renderer renderer = (SVG_Renderer)module; + + + if ( !ft_strcmp( property_name, "svg-hooks" ) ) + { + SVG_RendererHooks* hooks; + + + if ( value_is_string == TRUE ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + hooks = (SVG_RendererHooks*)value; + + if ( !hooks->init_svg || + !hooks->free_svg || + !hooks->render_svg || + !hooks->preset_slot ) + { + FT_TRACE0(( "ft_svg_property_set:" + " SVG rendering hooks not set because\n" )); + FT_TRACE0(( " " + " at least one function pointer is NULL\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + renderer->hooks = *hooks; + renderer->hooks_set = TRUE; + } + else + error = FT_THROW( Missing_Property ); + + Exit: + return error; + } + + + static FT_Error + ft_svg_property_get( FT_Module module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + SVG_Renderer renderer = (SVG_Renderer)module; + + + if ( !ft_strcmp( property_name, "svg-hooks" ) ) + { + SVG_RendererHooks* hooks = (SVG_RendererHooks*)value; + + + *hooks = renderer->hooks; + } + else + error = FT_THROW( Missing_Property ); + + return error; + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + ft_svg_service_properties, + + ft_svg_property_set, /* FT_Properties_SetFunc set_property */ + ft_svg_property_get /* FT_Properties_GetFunc get_property */ + ) + + + FT_DEFINE_SERVICEDESCREC1( + ft_svg_services, + FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties ) + + + FT_CALLBACK_DEF( FT_Module_Interface ) + ft_svg_get_interface( FT_Module module, + const char* ft_svg_interface ) + { + FT_Module_Interface result; + + + FT_UNUSED( module ); + + result = ft_service_list_lookup( ft_svg_services, ft_svg_interface ); + if ( result ) + return result; + + return 0; + } + + + static FT_Error + ft_svg_transform( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* _matrix, + const FT_Vector* _delta ) + { + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + FT_Matrix* matrix = (FT_Matrix*)_matrix; + FT_Vector* delta = (FT_Vector*)_delta; + + FT_Matrix tmp_matrix; + FT_Vector tmp_delta; + + FT_Matrix a, b; + FT_Pos x, y; + + + FT_UNUSED( renderer ); + + if ( !matrix ) + { + tmp_matrix.xx = 0x10000; + tmp_matrix.xy = 0; + tmp_matrix.yx = 0; + tmp_matrix.yy = 0x10000; + + matrix = &tmp_matrix; + } + + if ( !delta ) + { + tmp_delta.x = 0; + tmp_delta.y = 0; + + delta = &tmp_delta; + } + + a = doc->transform; + b = *matrix; + FT_Matrix_Multiply( &b, &a ); + + + x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, doc->delta.x ), + FT_MulFix( matrix->xy, doc->delta.y ) ), + delta->x ); + y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, doc->delta.x ), + FT_MulFix( matrix->yy, doc->delta.y ) ), + delta->y ); + + doc->delta.x = x; + doc->delta.y = y; + doc->transform = a; + + return FT_Err_Ok; + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_MODULE( a ) a +#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_SVG +#else +#define PUT_SVG_MODULE( a ) NULL +#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_NONE +#endif + + + FT_DEFINE_RENDERER( + ft_svg_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SVG_RendererRec ), + + "ot-svg", + 0x10000L, + 0x20000L, + + (const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */ + + PUT_SVG_MODULE( ft_svg_init ), /* FT_Module_Constructor module_init */ + PUT_SVG_MODULE( ft_svg_done ), /* FT_Module_Destructor module_done */ + PUT_SVG_MODULE( ft_svg_get_interface ), /* FT_Module_Requester get_interface */ + + SVG_GLYPH_FORMAT, + + PUT_SVG_MODULE( ft_svg_render ), /* FT_Renderer_RenderFunc render_glyph */ + PUT_SVG_MODULE( ft_svg_transform ), /* FT_Renderer_TransformFunc transform_glyph */ + NULL, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */ + NULL, /* FT_Renderer_SetModeFunc set_mode */ + NULL /* FT_Raster_Funcs* raster_class */ + ) + + +/* END */ diff --git a/vendor/freetype/src/svg/ftsvg.h b/vendor/freetype/src/svg/ftsvg.h new file mode 100644 index 0000000..9c496ca --- /dev/null +++ b/vendor/freetype/src/svg/ftsvg.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * ftsvg.h + * + * The FreeType SVG renderer interface (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTSVG_H_ +#define FTSVG_H_ + +#include +#include +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_RENDERER( ft_svg_renderer_class ) + +FT_END_HEADER + +#endif /* FTSVG_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/svg/module.mk b/vendor/freetype/src/svg/module.mk new file mode 100644 index 0000000..00beca6 --- /dev/null +++ b/vendor/freetype/src/svg/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 SVG renderer module definition +# + + +# Copyright (C) 2022-2023 by +# David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += SVG_MODULE + +define SVG_MODULE +$(OPEN_DRIVER) FT_Renderer_Class, ft_svg_renderer_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)ot-svg $(ECHO_DRIVER_DESC)OT-SVG glyph renderer module$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/svg/rules.mk b/vendor/freetype/src/svg/rules.mk new file mode 100644 index 0000000..4f44097 --- /dev/null +++ b/vendor/freetype/src/svg/rules.mk @@ -0,0 +1,70 @@ +# +# FreeType 2 SVG renderer module build rules +# + + +# Copyright (C) 2022-2023 by +# David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# SVG renderer driver directory +# +SVG_DIR := $(SRC_DIR)/svg + +# compilation flags for the driver +# +SVG_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(SVG_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + +# SVG renderer sources (i.e., C files) +# +SVG_DRV_SRC := $(SVG_DIR)/ftsvg.c + + +# SVG renderer headers +# +SVG_DRV_H := $(SVG_DIR)/ftsvg.h \ + $(SVG_DIR)/svgtypes.h + + +# SVG renderer object(s) +# +# SVG_DRV_OBJ_M is used during `multi' builds. +# SVG_DRV_OBJ_S is used during `single' builds. +# +SVG_DRV_OBJ_M := $(SVG_DRV_SRC:$(SVG_DIR)/%.c=$(OBJ_DIR)/%.$O) +SVG_DRV_OBJ_S := $(OBJ_DIR)/svg.$O + +# SVG renderer source file for single build +# +SVG_DRV_SRC_S := $(SVG_DIR)/svg.c + + +# SVG renderer - single object +# +$(SVG_DRV_OBJ_S): $(SVG_DRV_SRC_S) $(SVG_DRV_SRC) \ + $(FREETYPE_H) $(SVG_DRV_H) + $(SVG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(SVG_DRV_SRC_S)) + + +# SVG renderer - multiple objects +# +$(OBJ_DIR)/%.$O: $(SVG_DIR)/%.c $(FREETYPE_H) $(SVG_DRV_H) + $(SVG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(SVG_DRV_OBJ_S) +DRV_OBJS_M += $(SVG_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/svg/svg.c b/vendor/freetype/src/svg/svg.c new file mode 100644 index 0000000..373c28e --- /dev/null +++ b/vendor/freetype/src/svg/svg.c @@ -0,0 +1,24 @@ +/**************************************************************************** + * + * svg.c + * + * FreeType SVG renderer module component (body only). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "svgtypes.h" +#include "ftsvg.c" + + +/* END */ diff --git a/vendor/freetype/src/svg/svgtypes.h b/vendor/freetype/src/svg/svgtypes.h new file mode 100644 index 0000000..1d60803 --- /dev/null +++ b/vendor/freetype/src/svg/svgtypes.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * svgtypes.h + * + * The FreeType SVG renderer internal types (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef SVGTYPES_H_ +#define SVGTYPES_H_ + +#include +#include +#include +#include + + + typedef struct SVG_RendererRec_ + { + FT_RendererRec root; /* this inherits FT_RendererRec */ + FT_Bool loaded; + FT_Bool hooks_set; + SVG_RendererHooks hooks; /* this holds hooks for SVG rendering */ + FT_Pointer state; /* a place for hooks to store state, if needed */ + + } SVG_RendererRec; + + typedef struct SVG_RendererRec_* SVG_Renderer; + +#endif /* SVGTYPES_H_ */ + + +/* EOF */ diff --git a/vendor/freetype/src/tools/afblue.pl b/vendor/freetype/src/tools/afblue.pl new file mode 100644 index 0000000..1098e30 --- /dev/null +++ b/vendor/freetype/src/tools/afblue.pl @@ -0,0 +1,551 @@ +#! /usr/bin/perl -w +# -*- Perl -*- +# +# afblue.pl +# +# Process a blue zone character data file. +# +# Copyright (C) 2013-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, +# modified, and distributed under the terms of the FreeType project +# license, LICENSE.TXT. By continuing to use, modify, or distribute +# this file you indicate that you have read the license and +# understand and accept it fully. + +use strict; +use warnings; +use English '-no_match_vars'; +use open ':std', ':encoding(UTF-8)'; + + +my $prog = $PROGRAM_NAME; +$prog =~ s| .* / ||x; # Remove path. + +die "usage: $prog datafile < infile > outfile\n" if $#ARGV != 0; + + +my $datafile = $ARGV[0]; + +my %diversions; # The extracted and massaged data from `datafile'. +my @else_stack; # Booleans to track else-clauses. +my @name_stack; # Stack of integers used for names of aux. variables. + +my $curr_enum; # Name of the current enumeration. +my $curr_array; # Name of the current array. +my $curr_max; # Name of the current maximum value. + +my $curr_enum_element; # Name of the current enumeration element. +my $curr_offset; # The offset relative to current aux. variable. +my $curr_elem_size; # The number of non-space characters in the current string or + # the number of elements in the current block. + +my $have_sections = 0; # Boolean; set if start of a section has been seen. +my $have_strings; # Boolean; set if current section contains strings. +my $have_blocks; # Boolean; set if current section contains blocks. + +my $have_enum_element; # Boolean; set if we have an enumeration element. +my $in_string; # Boolean; set if a string has been parsed. + +my $num_sections = 0; # Number of sections seen so far. + +my $last_aux; # Name of last auxiliary variable. + + +# Regular expressions. + +# [] [] ':' [] '\n' +my $section_re = qr/ ^ \s* (\S+) \s+ (\S+) \s+ (\S+) \s* : \s* $ /x; + +# [] [] '\n' +my $enum_element_re = qr/ ^ \s* ( [A-Za-z0-9_]+ ) \s* $ /x; + +# '#' '\n' +my $preprocessor_re = qr/ ^ \# /x; + +# [] '/' '/' '\n' +my $comment_re = qr| ^ \s* // |x; + +# empty line +my $whitespace_only_re = qr/ ^ \s* $ /x; + +# [] '"' '"' [] '\n' ( doesn't contain newlines) +my $string_re = qr/ ^ \s* + " ( (?> (?: (?> [^"\\]+ ) | \\. )* ) ) " + \s* $ /x; + +# [] '{' '}' [] '\n' ( can contain newlines) +my $block_start_re = qr/ ^ \s* \{ /x; + +# We need the capturing group for `split' to make it return the separator +# tokens (i.e., the opening and closing brace) also. +my $brace_re = qr/ ( [{}] ) /x; + + +sub Warn +{ + my $message = shift; + warn "$datafile:$INPUT_LINE_NUMBER: warning: $message\n"; +} + + +sub Die +{ + my $message = shift; + die "$datafile:$INPUT_LINE_NUMBER: error: $message\n"; +} + + +my $warned_before = 0; + +sub warn_before +{ + Warn("data before first section gets ignored") unless $warned_before; + $warned_before = 1; +} + + +sub strip_newline +{ + chomp; + s/ \x0D $ //x; +} + + +sub end_curr_string +{ + # Append final null byte to string. + if ($have_strings) + { + push @{$diversions{$curr_array}}, " '\\0',\n" if $in_string; + + $curr_offset++; + $in_string = 0; + } +} + + +sub update_max_elem_size +{ + if ($curr_elem_size) + { + my $max = pop @{$diversions{$curr_max}}; + $max = $curr_elem_size if $curr_elem_size > $max; + push @{$diversions{$curr_max}}, $max; + } +} + + +sub convert_non_ascii_char +{ + # A UTF-8 character outside of the printable ASCII range, with possibly a + # leading backslash character. + my $s = shift; + + # Here we count characters, not bytes. + $curr_elem_size += length $s; + + utf8::encode($s); + $s = uc unpack 'H*', $s; + + $curr_offset += $s =~ s/\G(..)/'\\x$1', /sg; + + return $s; +} + + +sub convert_ascii_chars +{ + # A series of ASCII characters in the printable range. + my $s = shift; + + # We reduce multiple space characters to a single one. + $s =~ s/ +/ /g; + + # Count all non-space characters. Note that `()' applies a list context + # to the capture that is used to count the elements. + $curr_elem_size += () = $s =~ /[^ ]/g; + + $curr_offset += $s =~ s/\G(.)/'$1', /g; + + return $s; +} + + +sub convert_literal +{ + my $s = shift; + my $orig = $s; + + # ASCII printables and space + my $safe_re = '\x20-\x7E'; + # ASCII printables and space, no backslash + my $safe_no_backslash_re = '\x20-\x5B\x5D-\x7E'; + + $s =~ s{ + (?: \\? ( [^$safe_re] ) + | ( (?: [$safe_no_backslash_re] + | \\ [$safe_re] )+ ) ) + } + { + defined($1) ? convert_non_ascii_char($1) + : convert_ascii_chars($2) + }egx; + + # We assume that `$orig' doesn't contain `*/' + return $s . " /* $orig */"; +} + + +sub aux_name +{ + return "af_blue_" . $num_sections. "_" . join('_', @name_stack); +} + + +sub aux_name_next +{ + $name_stack[$#name_stack]++; + my $name = aux_name(); + $name_stack[$#name_stack]--; + + return $name; +} + + +sub enum_val_string +{ + # Build string that holds code to save the current offset in an + # enumeration element. + my $aux = shift; + + my $add = ($last_aux eq "af_blue_" . $num_sections . "_0" ) + ? "" + : "$last_aux + "; + + return " $aux = $add$curr_offset,\n"; +} + + + +# Process data file. + +open(DATA, $datafile) || die "$prog: can't open \`$datafile': $OS_ERROR\n"; + +while () +{ + strip_newline(); + + next if /$comment_re/; + next if /$whitespace_only_re/; + + if (/$section_re/) + { + Warn("previous section is empty") if ($have_sections + && !$have_strings + && !$have_blocks); + + end_curr_string(); + update_max_elem_size(); + + # Save captured groups from `section_re'. + $curr_enum = $1; + $curr_array = $2; + $curr_max = $3; + + $curr_enum_element = ""; + $curr_offset = 0; + + Warn("overwriting already defined enumeration \`$curr_enum'") + if exists($diversions{$curr_enum}); + Warn("overwriting already defined array \`$curr_array'") + if exists($diversions{$curr_array}); + Warn("overwriting already defined maximum value \`$curr_max'") + if exists($diversions{$curr_max}); + + $diversions{$curr_enum} = []; + $diversions{$curr_array} = []; + $diversions{$curr_max} = []; + + push @{$diversions{$curr_max}}, 0; + + @name_stack = (); + push @name_stack, 0; + + $have_sections = 1; + $have_strings = 0; + $have_blocks = 0; + + $have_enum_element = 0; + $in_string = 0; + + $num_sections++; + $curr_elem_size = 0; + + $last_aux = aux_name(); + + next; + } + + if (/$preprocessor_re/) + { + if ($have_sections) + { + # Having preprocessor conditionals complicates the computation of + # correct offset values. We have to introduce auxiliary enumeration + # elements with the name `af_blue____...' that store + # offsets to be used in conditional clauses. `' is the number of + # sections seen so far, `' is the number of `#if' and `#endif' + # conditionals seen so far in the topmost level, `' the number of + # `#if' and `#endif' conditionals seen so far one level deeper, etc. + # As a consequence, uneven values are used within a clause, and even + # values after a clause, since the C standard doesn't allow the + # redefinition of an enumeration value. For example, the name + # `af_blue_5_1_6' is used to construct enumeration values in the fifth + # section after the third (second-level) if-clause within the first + # (top-level) if-clause. After the first top-level clause has + # finished, `af_blue_5_2' is used. The current offset is then + # relative to the value stored in the current auxiliary element. + + if (/ ^ \# \s* if /x) + { + push @else_stack, 0; + + $name_stack[$#name_stack]++; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ \# \s* elif /x) + { + Die("unbalanced #elif") unless @else_stack; + + pop @name_stack; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ \# \s* else /x) + { + my $prev_else = pop @else_stack; + Die("unbalanced #else") unless defined($prev_else); + Die("#else already seen") if $prev_else; + push @else_stack, 1; + + pop @name_stack; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ (\# \s*) endif /x) + { + my $prev_else = pop @else_stack; + Die("unbalanced #endif") unless defined($prev_else); + + pop @name_stack; + + # If there is no else-clause for an if-clause, we add one. This is + # necessary to have correct offsets. + if (!$prev_else) + { + # Use amount of whitespace from `endif'. + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()) + . $1 . "else\n"; + $last_aux = aux_name(); + + $curr_offset = 0; + } + + $name_stack[$#name_stack]++; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name()); + $last_aux = aux_name(); + + $curr_offset = 0; + } + + # Handle (probably continued) preprocessor lines. + CONTINUED_LOOP: + { + do + { + strip_newline(); + + push @{$diversions{$curr_enum}}, $ARG . "\n"; + push @{$diversions{$curr_array}}, $ARG . "\n"; + + last CONTINUED_LOOP unless / \\ $ /x; + + } while (); + } + } + else + { + warn_before(); + } + + next; + } + + if (/$enum_element_re/) + { + end_curr_string(); + update_max_elem_size(); + + $curr_enum_element = $1; + $have_enum_element = 1; + $curr_elem_size = 0; + + next; + } + + if (/$string_re/) + { + if ($have_sections) + { + Die("strings and blocks can't be mixed in a section") if $have_blocks; + + # Save captured group from `string_re'. + my $string = $1; + + if ($have_enum_element) + { + push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element); + $have_enum_element = 0; + } + + $string = convert_literal($string); + + push @{$diversions{$curr_array}}, " $string\n"; + + $have_strings = 1; + $in_string = 1; + } + else + { + warn_before(); + } + + next; + } + + if (/$block_start_re/) + { + if ($have_sections) + { + Die("strings and blocks can't be mixed in a section") if $have_strings; + + my $depth = 0; + my $block = ""; + my $block_end = 0; + + # Count braces while getting the block. + BRACE_LOOP: + { + do + { + strip_newline(); + + foreach my $substring (split(/$brace_re/)) + { + if ($block_end) + { + Die("invalid data after last matching closing brace") + if $substring !~ /$whitespace_only_re/; + } + + $block .= $substring; + + if ($substring eq '{') + { + $depth++; + } + elsif ($substring eq '}') + { + $depth--; + + $block_end = 1 if $depth == 0; + } + } + + # If we are here, we have run out of substrings, so get next line + # or exit. + last BRACE_LOOP if $block_end; + + $block .= "\n"; + + } while (); + } + + if ($have_enum_element) + { + push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element); + $have_enum_element = 0; + } + + push @{$diversions{$curr_array}}, $block . ",\n"; + + $curr_offset++; + $curr_elem_size++; + + $have_blocks = 1; + } + else + { + warn_before(); + } + + next; + } + + # Garbage. We weren't able to parse the data. + Die("syntax error"); +} + +# Finalize data. +end_curr_string(); +update_max_elem_size(); + + +# Filter stdin to stdout, replacing `@...@' templates. + +sub emit_diversion +{ + my $diversion_name = shift; + return (exists($diversions{$1})) ? "@{$diversions{$1}}" + : "@" . $diversion_name . "@"; +} + + +$LIST_SEPARATOR = ''; + +my $s1 = "This file has been generated by the Perl script \`$prog',"; +my $s1len = length $s1; +my $s2 = "using data from file \`$datafile'."; +my $s2len = length $s2; +my $slen = ($s1len > $s2len) ? $s1len : $s2len; + +print "/* " . $s1 . " " x ($slen - $s1len) . " */\n" + . "/* " . $s2 . " " x ($slen - $s2len) . " */\n" + . "\n"; + +while () +{ + s/ @ ( [A-Za-z0-9_]+? ) @ / emit_diversion($1) /egx; + print; +} + +# EOF diff --git a/vendor/freetype/src/tools/apinames.c b/vendor/freetype/src/tools/apinames.c new file mode 100644 index 0000000..dfa258f --- /dev/null +++ b/vendor/freetype/src/tools/apinames.c @@ -0,0 +1,556 @@ +/* + * This little program is used to parse the FreeType headers and + * find the declaration of all public APIs. This is easy, because + * they all look like the following: + * + * FT_EXPORT( return_type ) + * function_name( function arguments ); + * + * You must pass the list of header files as arguments. Wildcards are + * accepted if you are using GCC for compilation (and probably by + * other compilers too). + * + * Author: FreeType team, 2005-2019 + * + * This code is explicitly placed into the public domain. + * + */ + +#include +#include +#include +#include +#include + +#include "vms_shorten_symbol.c" + +#define PROGRAM_NAME "apinames" +#define PROGRAM_VERSION "0.5" + +#define LINEBUFF_SIZE 1024 + + +typedef enum OutputFormat_ +{ + OUTPUT_LIST = 0, /* output the list of names, one per line */ + OUTPUT_WINDOWS_DEF, /* output a Windows .DEF file for Visual C++ or Mingw */ + OUTPUT_BORLAND_DEF, /* output a Windows .DEF file for Borland C++ */ + OUTPUT_WATCOM_LBC, /* output a Watcom Linker Command File */ + OUTPUT_VMS_OPT, /* output an OpenVMS Linker Option File */ + OUTPUT_NETWARE_IMP, /* output a NetWare ImportFile */ + OUTPUT_GNU_VERMAP /* output a version map for GNU or Solaris linker */ + +} OutputFormat; + + +static void +panic( const char* fmt, + ... ) +{ + va_list ap; + + + fprintf( stderr, "PANIC: " ); + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + + fprintf( stderr, "\n" ); + + exit(2); +} + + +typedef struct NameRec_ +{ + char* name; + unsigned int hash; + +} NameRec, *Name; + + +static Name the_names; +static int num_names; +static int max_names; + + +static void +names_add( const char* name, + const char* end ) +{ + unsigned int h; + int nn, len; + Name nm; + + + if ( end <= name ) + return; + + /* compute hash value */ + len = (int)( end - name ); + h = 0; + + for ( nn = 0; nn < len; nn++ ) + h = h * 33 + name[nn]; + + /* check for an pre-existing name */ + for ( nn = 0; nn < num_names; nn++ ) + { + nm = the_names + nn; + + if ( (int)nm->hash == h && + memcmp( name, nm->name, len ) == 0 && + nm->name[len] == 0 ) + return; + } + + /* add new name */ + if ( num_names >= max_names ) + { + max_names += ( max_names >> 1 ) + 4; + the_names = (NameRec*)realloc( the_names, + sizeof ( the_names[0] ) * max_names ); + if ( !the_names ) + panic( "not enough memory" ); + } + nm = &the_names[num_names++]; + + nm->hash = h; + nm->name = (char*)malloc( len + 1 ); + if ( !nm->name ) + panic( "not enough memory" ); + + memcpy( nm->name, name, len ); + nm->name[len] = 0; +} + + +static int +name_compare( const void* name1, + const void* name2 ) +{ + Name n1 = (Name)name1; + Name n2 = (Name)name2; + + return strcmp( n1->name, n2->name ); +} + + +static void +names_sort( void ) +{ + qsort( the_names, (size_t)num_names, + sizeof ( the_names[0] ), name_compare ); +} + + +static void +names_dump( FILE* out, + OutputFormat format, + const char* dll_name ) +{ + int nn; + + + switch ( format ) + { + case OUTPUT_WINDOWS_DEF: + if ( dll_name ) + fprintf( out, "LIBRARY %s\n", dll_name ); + + fprintf( out, "DESCRIPTION FreeType 2 DLL\n" ); + fprintf( out, "EXPORTS\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, " %s\n", the_names[nn].name ); + + break; + + case OUTPUT_BORLAND_DEF: + if ( dll_name ) + fprintf( out, "LIBRARY %s\n", dll_name ); + + fprintf( out, "DESCRIPTION FreeType 2 DLL\n" ); + fprintf( out, "EXPORTS\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, " _%s\n", the_names[nn].name ); + + break; + + case OUTPUT_WATCOM_LBC: + { + const char* dot; + + + if ( !dll_name ) + { + fprintf( stderr, + "you must provide a DLL name with the -d option!\n" ); + exit( 4 ); + } + + /* we must omit the `.dll' suffix from the library name */ + dot = strchr( dll_name, '.' ); + if ( dot ) + { + char temp[512]; + int len = dot - dll_name; + + + if ( len > (int)( sizeof ( temp ) - 1 ) ) + len = sizeof ( temp ) - 1; + + memcpy( temp, dll_name, len ); + temp[len] = 0; + + dll_name = (const char*)temp; + } + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, "++_%s.%s.%s\n", + the_names[nn].name, dll_name, the_names[nn].name ); + } + + break; + + case OUTPUT_VMS_OPT: + fprintf( out, "case_sensitive=YES\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + { + char short_symbol[32]; + + + if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 ) + panic( "could not shorten name '%s'", the_names[nn].name ); + fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol ); + + /* Also emit a 64-bit symbol, as created by the `vms_auto64` tool. */ + /* It has the string '64__' appended to its name. */ + strcat( the_names[nn].name , "64__" ); + if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 ) + panic( "could not shorten name '%s'", the_names[nn].name ); + fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol ); + } + + break; + + case OUTPUT_NETWARE_IMP: + if ( dll_name ) + fprintf( out, " (%s)\n", dll_name ); + + for ( nn = 0; nn < num_names - 1; nn++ ) + fprintf( out, " %s,\n", the_names[nn].name ); + fprintf( out, " %s\n", the_names[num_names - 1].name ); + + break; + + case OUTPUT_GNU_VERMAP: + fprintf( out, "{\n\tglobal:\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, "\t\t%s;\n", the_names[nn].name ); + + fprintf( out, "\tlocal:\n\t\t*;\n};\n" ); + + break; + + default: /* LIST */ + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, "%s\n", the_names[nn].name ); + + break; + } +} + + +/* states of the line parser */ + +typedef enum State_ +{ + STATE_START = 0, /* waiting for FT_EXPORT keyword and return type */ + STATE_TYPE /* type was read, waiting for function name */ + +} State; + + +static int +read_header_file( FILE* file, + int verbose ) +{ + static char buff[LINEBUFF_SIZE + 1]; + State state = STATE_START; + + + while ( !feof( file ) ) + { + char* p; + + + if ( !fgets( buff, LINEBUFF_SIZE, file ) ) + break; + + p = buff; + + /* skip leading whitespace */ + while ( *p && ( *p == ' ' || *p == '\\' ) ) + p++; + + /* skip empty lines */ + if ( *p == '\n' || *p == '\r' ) + continue; + + switch ( state ) + { + case STATE_START: + if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 ) + break; + + p += 10; + for (;;) + { + if ( *p == 0 || *p == '\n' || *p == '\r' ) + goto NextLine; + + if ( *p == ')' ) + { + p++; + break; + } + + p++; + } + + state = STATE_TYPE; + + /* + * Sometimes, the name is just after `FT_EXPORT(...)', so skip + * whitespace and fall-through if we find an alphanumeric character. + */ + while ( *p == ' ' || *p == '\t' ) + p++; + + if ( !isalpha( *p ) ) + break; + + /* fall-through */ + + case STATE_TYPE: + { + char* name = p; + + + while ( isalnum( *p ) || *p == '_' ) + p++; + + if ( p > name ) + { + if ( verbose ) + fprintf( stderr, ">>> %.*s\n", (int)( p - name ), name ); + + names_add( name, p ); + } + + state = STATE_START; + } + + break; + + default: + ; + } + +NextLine: + ; + } /* end of while loop */ + + return 0; +} + + +static void +usage( void ) +{ + static const char* const format = + "%s %s: extract FreeType API names from header files\n" + "\n" + "This program extracts the list of public FreeType API functions.\n" + "It receives a list of header files as an argument and\n" + "generates a sorted list of unique identifiers in various formats.\n" + "\n" + "usage: %s header1 [options] [header2 ...]\n" + "\n" + "options: - parse the contents of stdin, ignore arguments\n" + " -v verbose mode, output sent to standard error\n" + " -oFILE write output to FILE instead of standard output\n" + " -dNAME indicate DLL file name, 'freetype.dll' by default\n" + " -w output .DEF file for Visual C++ and Mingw\n" + " -wB output .DEF file for Borland C++\n" + " -wW output Watcom Linker Response File\n" + " -wV output OpenVMS Linker Options File\n" + " -wN output NetWare Import File\n" + " -wL output version map for GNU or Solaris linker\n" + "\n"; + + fprintf( stderr, + format, + PROGRAM_NAME, + PROGRAM_VERSION, + PROGRAM_NAME ); + + exit( 1 ); +} + + +int +main( int argc, + const char* const* argv ) +{ + int from_stdin = 0; + int verbose = 0; + OutputFormat format = OUTPUT_LIST; /* the default */ + FILE* out = stdout; + const char* library_name = NULL; + + + if ( argc < 2 ) + usage(); + + /* `-' used as a single argument means read source file from stdin */ + while ( argc > 1 && argv[1][0] == '-' ) + { + const char* arg = argv[1]; + + + switch ( arg[1] ) + { + case 'v': + verbose = 1; + + break; + + case 'o': + if ( arg[2] == 0 ) + { + if ( argc < 2 ) + usage(); + + arg = argv[2]; + argv++; + argc--; + } + else + arg += 2; + + out = fopen( arg, "wt" ); + if ( !out ) + { + fprintf( stderr, "could not open '%s' for writing\n", arg ); + exit( 3 ); + } + + break; + + case 'd': + if ( arg[2] == 0 ) + { + if ( argc < 2 ) + usage(); + + arg = argv[2]; + argv++; + argc--; + } + else + arg += 2; + + library_name = arg; + + break; + + case 'w': + format = OUTPUT_WINDOWS_DEF; + + switch ( arg[2] ) + { + case 'B': + format = OUTPUT_BORLAND_DEF; + break; + + case 'W': + format = OUTPUT_WATCOM_LBC; + break; + + case 'V': + format = OUTPUT_VMS_OPT; + break; + + case 'N': + format = OUTPUT_NETWARE_IMP; + break; + + case 'L': + format = OUTPUT_GNU_VERMAP; + break; + + case 0: + break; + + default: + usage(); + } + + break; + + case 0: + from_stdin = 1; + + break; + + default: + usage(); + } + + argc--; + argv++; + + } /* end of while loop */ + + if ( from_stdin ) + read_header_file( stdin, verbose ); + else + { + for ( --argc, argv++; argc > 0; argc--, argv++ ) + { + FILE* file = fopen( argv[0], "rb" ); + + + if ( !file ) + fprintf( stderr, "unable to open '%s'\n", argv[0] ); + else + { + if ( verbose ) + fprintf( stderr, "opening '%s'\n", argv[0] ); + + read_header_file( file, verbose ); + fclose( file ); + } + } + } + + if ( num_names == 0 ) + panic( "could not find exported functions\n" ); + + names_sort(); + names_dump( out, format, library_name ); + + if ( out != stdout ) + fclose( out ); + + return 0; +} + + +/* END */ diff --git a/vendor/freetype/src/tools/chktrcmp.py b/vendor/freetype/src/tools/chktrcmp.py new file mode 100644 index 0000000..d072a87 --- /dev/null +++ b/vendor/freetype/src/tools/chktrcmp.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# +# Check trace components in FreeType 2 source. +# Author: suzuki toshiya, 2009, 2013, 2020 +# +# This code is explicitly into the public domain. + +import sys +import os +import re + +SRC_FILE_LIST = [] +USED_COMPONENT = {} +KNOWN_COMPONENT = {} + +SRC_FILE_DIRS = ["src"] +TRACE_DEF_FILES = ["include/freetype/internal/fttrace.h"] + + +def usage(): + print("Usage: %s [option]" % sys.argv[0]) + print("Search used-but-defined and defined-but-not-used trace_XXX macros") + print("") + print(" --help:") + print(" Show this help") + print("") + print(" --src-dirs=dir1:dir2:...") + print(" Specify the directories of C source files to be checked") + print(" Default is %s" % ":".join(SRC_FILE_DIRS)) + print("") + print(" --def-files=file1:file2:...") + print(" Specify the header files including FT_TRACE_DEF()") + print(" Default is %s" % ":".join(TRACE_DEF_FILES)) + print("") + + +# -------------------------------------------------------------- +# Parse command line options +# +for i in range(1, len(sys.argv)): + if sys.argv[i].startswith("--help"): + usage() + exit(0) + if sys.argv[i].startswith("--src-dirs="): + SRC_FILE_DIRS = sys.argv[i].replace("--src-dirs=", "", 1).split(":") + elif sys.argv[i].startswith("--def-files="): + TRACE_DEF_FILES = sys.argv[i].replace("--def-files=", "", 1).split(":") + +# -------------------------------------------------------------- +# Scan C source and header files using trace macros. +# + +c_pathname_pat = re.compile('^.*\.[ch]$', re.IGNORECASE) +trace_use_pat = re.compile('^[ \t]*#define[ \t]+FT_COMPONENT[ \t]+') + +for d in SRC_FILE_DIRS: + for (p, dlst, flst) in os.walk(d): + for f in flst: + if c_pathname_pat.match(f) is not None: + src_pathname = os.path.join(p, f) + + line_num = 0 + for src_line in open(src_pathname, 'r'): + line_num = line_num + 1 + src_line = src_line.strip() + if trace_use_pat.match(src_line) is not None: + component_name = trace_use_pat.sub('', src_line) + if component_name in USED_COMPONENT: + USED_COMPONENT[component_name]\ + .append("%s:%d" % (src_pathname, line_num)) + else: + USED_COMPONENT[component_name] =\ + ["%s:%d" % (src_pathname, line_num)] + +# -------------------------------------------------------------- +# Scan header file(s) defining trace macros. +# + +trace_def_pat_opn = re.compile('^.*FT_TRACE_DEF[ \t]*\([ \t]*') +trace_def_pat_cls = re.compile('[ \t\)].*$') + +for f in TRACE_DEF_FILES: + line_num = 0 + for hdr_line in open(f, 'r'): + line_num = line_num + 1 + hdr_line = hdr_line.strip() + if trace_def_pat_opn.match(hdr_line) is not None: + component_name = trace_def_pat_opn.sub('', hdr_line) + component_name = trace_def_pat_cls.sub('', component_name) + if component_name in KNOWN_COMPONENT: + print("trace component %s is defined twice," + " see %s and fttrace.h:%d" % + (component_name, KNOWN_COMPONENT[component_name], + line_num)) + else: + KNOWN_COMPONENT[component_name] =\ + "%s:%d" % (os.path.basename(f), line_num) + +# -------------------------------------------------------------- +# Compare the used and defined trace macros. +# + +print("# Trace component used in the implementations but not defined in " + "fttrace.h.") +cmpnt = list(USED_COMPONENT.keys()) +cmpnt.sort() +for c in cmpnt: + if c not in KNOWN_COMPONENT: + print("Trace component %s (used in %s) is not defined." % + (c, ", ".join(USED_COMPONENT[c]))) + +print("# Trace component is defined but not used in the implementations.") +cmpnt = list(KNOWN_COMPONENT.keys()) +cmpnt.sort() +for c in cmpnt: + if c not in USED_COMPONENT: + if c != "any": + print("Trace component %s (defined in %s) is not used." % + (c, KNOWN_COMPONENT[c])) diff --git a/vendor/freetype/src/tools/cordic.py b/vendor/freetype/src/tools/cordic.py new file mode 100644 index 0000000..6511429 --- /dev/null +++ b/vendor/freetype/src/tools/cordic.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# compute arctangent table for CORDIC computations in fttrigon.c +import math + +# units = 64*65536.0 # don't change !! +units = 180 * 2 ** 16 +scale = units / math.pi +shrink = 1.0 +angles2 = [] + +print("") +print("table of arctan( 1/2^n ) for PI = " + repr(units / 65536.0) + " units") + +for n in range(1, 32): + + x = 0.5 ** n # tangent value + + angle = math.atan(x) # arctangent + angle2 = round(angle * scale) # arctangent in FT_Angle units + + if angle2 <= 0: + break + + angles2.append(repr(int(angle2))) + shrink /= math.sqrt(1 + x * x) + +print(", ".join(angles2)) +print("shrink factor = " + repr(shrink)) +print("shrink factor 2 = " + repr(int(shrink * (2 ** 32)))) +print("expansion factor = " + repr(1 / shrink)) +print("") diff --git a/vendor/freetype/src/tools/ftrandom/README b/vendor/freetype/src/tools/ftrandom/README new file mode 100644 index 0000000..7c61086 --- /dev/null +++ b/vendor/freetype/src/tools/ftrandom/README @@ -0,0 +1,69 @@ +ftrandom +======== + +This program expects a set of directories containing good fonts, and a set +of extensions of fonts to be tested. It will randomly pick a font, copy it, +introduce an error and then test it. + +The FreeType tests are quite basic; for each erroneous font ftrandom + + . forks off a new tester, + . initializes the library, + . opens each font in the file, + . loads each glyph, + . optionally reviews the contours of the glyph, + . optionally rasterizes the glyph, and + . closes the face. + +If a tester takes longer than 20 seconds, ftrandom saves the erroneous font +and continues. If the tester exits normally or with an error, then the +superstructure removes the test font and continues. + + +Command line options +-------------------- + + --all Test every font in the directory(ies) no matter + what its extension. + --check-outlines Call `FT_Outline_Decompose' on each glyph. + --dir

    Append to the list of directories to search + for good fonts. No recursive search. + --error-count Introduce single-byte errors into the + erroneous fonts (default: 1). + --error-fraction Multiply the file size of the font by and + introduce that many errors into the erroneous + font file. should be in the range [0;1] + (default: 0.0). + --ext Add to the set of font types tested. + --help Print out this list of options. + --nohints Specify FT_LOAD_NO_HINTING when loading glyphs. + --rasterize Call `FT_Render_Glyph' as well as loading it. + --result This is the directory in which test files are + placed. + --test Run a single test on a pre-generated testcase. + This is done in the current process so it can be + debugged more easily. + +The default font extensions tested by ftrandom are + + .ttf .otf .ttc .cid .pfb .pfa .bdf .pcf .pfr .fon .otb .cff + +The default font directory is controlled by the macro `GOOD_FONTS_DIR' in +the source code (and can be thus specified during compilation); its default +value is + + /usr/local/share/fonts + +The default result directory is `results' (in the current directory). + + +Compilation +----------- + +Two possible solutions. + +. Run ftrandom within a debugging tool like `valgrind' to catch various + memory issues. + +. Compile FreeType with sanitizer flags as provided by gcc or clang, for + example, then link it with ftrandom. diff --git a/vendor/freetype/src/tools/ftrandom/ftrandom.c b/vendor/freetype/src/tools/ftrandom/ftrandom.c new file mode 100644 index 0000000..0ee765e --- /dev/null +++ b/vendor/freetype/src/tools/ftrandom/ftrandom.c @@ -0,0 +1,720 @@ +/* Copyright (C) 2005, 2007, 2008, 2013 by George Williams */ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* modified by Werner Lemberg */ +/* This file is now part of the FreeType library */ + + +#define _XOPEN_SOURCE 600 /* for `kill', `strdup', `random', and `srandom' */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define true 1 +#define false 0 +#define forever for (;;) + + + static int check_outlines = false; + static int nohints = false; + static int rasterize = false; + static char* results_dir = "results"; + +#define GOOD_FONTS_DIR "/usr/local/share/fonts" + + static char* default_dir_list[] = + { + GOOD_FONTS_DIR, + NULL + }; + + static char* default_ext_list[] = + { + "ttf", + "otf", + "ttc", + "cid", + "pfb", + "pfa", + "bdf", + "pcf", + "pfr", + "fon", + "otb", + "cff", + NULL + }; + + static unsigned int error_count = 1; + static double error_fraction = 0.0; + + static FT_F26Dot6 font_size = 12 * 64; + + static struct fontlist + { + char* name; + long len; + unsigned int isbinary: 1; + unsigned int isascii: 1; + unsigned int ishex: 1; + + } *fontlist; + + static unsigned int fcnt; + + + static int + FT_MoveTo( const FT_Vector *to, + void *user ) + { + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static int + FT_LineTo( const FT_Vector *to, + void *user ) + { + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static int + FT_ConicTo( const FT_Vector *_cp, + const FT_Vector *to, + void *user ) + { + FT_UNUSED( _cp ); + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static int + FT_CubicTo( const FT_Vector *cp1, + const FT_Vector *cp2, + const FT_Vector *to, + void *user ) + { + FT_UNUSED( cp1 ); + FT_UNUSED( cp2 ); + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static FT_Outline_Funcs outlinefuncs = + { + FT_MoveTo, + FT_LineTo, + FT_ConicTo, + FT_CubicTo, + 0, 0 /* No shift, no delta */ + }; + + + static void + TestFace( FT_Face face ) + { + unsigned int gid; + int load_flags = FT_LOAD_DEFAULT; + + + if ( check_outlines && + FT_IS_SCALABLE( face ) ) + load_flags = FT_LOAD_NO_BITMAP; + + if ( nohints ) + load_flags |= FT_LOAD_NO_HINTING; + + FT_Set_Char_Size( face, 0, font_size, 72, 72 ); + + for ( gid = 0; gid < face->num_glyphs; gid++ ) + { + if ( check_outlines && + FT_IS_SCALABLE( face ) ) + { + if ( !FT_Load_Glyph( face, gid, load_flags ) ) + FT_Outline_Decompose( &face->glyph->outline, &outlinefuncs, NULL ); + } + else + FT_Load_Glyph( face, gid, load_flags ); + + if ( rasterize ) + FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + } + + FT_Done_Face( face ); + } + + + static void + ExecuteTest( char* testfont ) + { + FT_Library context; + FT_Face face; + + + if ( FT_Init_FreeType( &context ) ) + { + fprintf( stderr, "Can't initialize FreeType.\n" ); + exit( 1 ); + } + + if ( FT_New_Face( context, testfont, 0, &face ) ) + { + /* The font is erroneous, so if this fails that's ok. */ + exit( 0 ); + } + + if ( face->num_faces == 1 ) + TestFace( face ); + else + { + long i, num; + + + num = face->num_faces; + FT_Done_Face( face ); + + for ( i = 0; i < num; i++ ) + { + if ( !FT_New_Face( context, testfont, i, &face ) ) + TestFace( face ); + } + } + + FT_Done_FreeType( context ); + + exit( 0 ); + } + + + static int + extmatch( char* filename, + char** extensions ) + { + int i; + char* pt; + + + if ( !extensions ) + return true; + + pt = strrchr( filename, '.' ); + if ( !pt ) + return false; + if ( pt < strrchr( filename, '/' ) ) + return false; + + for ( i = 0; extensions[i] != NULL; i++ ) + if ( strcasecmp( pt + 1, extensions[i] ) == 0 || + strcasecmp( pt, extensions[i] ) == 0 ) + return true; + + return false; + } + + + static void + figurefiletype( struct fontlist* item ) + { + FILE* foo; + + + item->isbinary = item->isascii = item->ishex = false; + + foo = fopen( item->name, "rb" ); + if ( foo ) + { + /* Try to guess the file type from the first few characters... */ + int ch1 = getc( foo ); + int ch2 = getc( foo ); + int ch3 = getc( foo ); + int ch4 = getc( foo ); + + + fclose( foo ); + + if ( ( ch1 == 0 && ch2 == 1 && ch3 == 0 && ch4 == 0 ) || + ( ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O' ) || + ( ch1 == 't' && ch2 == 'r' && ch3 == 'u' && ch4 == 'e' ) || + ( ch1 == 't' && ch2 == 't' && ch3 == 'c' && ch4 == 'f' ) ) + { + /* ttf, otf, ttc files */ + item->isbinary = true; + } + else if ( ch1 == 0x80 && ch2 == '\01' ) + { + /* PFB header */ + item->isbinary = true; + } + else if ( ch1 == '%' && ch2 == '!' ) + { + /* Random PostScript */ + if ( strstr( item->name, ".pfa" ) || + strstr( item->name, ".PFA" ) ) + item->ishex = true; + else + item->isascii = true; + } + else if ( ch1 == 1 && ch2 == 0 && ch3 == 4 ) + { + /* Bare CFF */ + item->isbinary = true; + } + else if ( ch1 == 'S' && ch2 == 'T' && ch3 == 'A' && ch4 == 'R' ) + { + /* BDF */ + item->ishex = true; + } + else if ( ch1 == 'P' && ch2 == 'F' && ch3 == 'R' && ch4 == '0' ) + { + /* PFR */ + item->isbinary = true; + } + else if ( ( ch1 == '\1' && ch2 == 'f' && ch3 == 'c' && ch4 == 'p' ) || + ( ch1 == 'M' && ch2 == 'Z' ) ) + { + /* Windows FON */ + item->isbinary = true; + } + else + { + fprintf( stderr, + "Can't recognize file type of `%s', assuming binary\n", + item->name ); + item->isbinary = true; + } + } + else + { + fprintf( stderr, "Can't open `%s' for typing the file.\n", + item->name ); + item->isbinary = true; + } + } + + + static void + FindFonts( char** fontdirs, + char** extensions ) + { + int i; + unsigned int max; + char buffer[1025]; + struct stat statb; + + + max = 0; + fcnt = 0; + + for ( i = 0; fontdirs[i] != NULL; i++ ) + { + DIR* examples; + struct dirent* ent; + + + examples = opendir( fontdirs[i] ); + if ( !examples ) + { + fprintf( stderr, + "Can't open example font directory `%s'\n", + fontdirs[i] ); + exit( 1 ); + } + + while ( ( ent = readdir( examples ) ) != NULL ) + { + snprintf( buffer, sizeof ( buffer ), + "%s/%s", fontdirs[i], ent->d_name ); + if ( stat( buffer, &statb ) == -1 || S_ISDIR( statb.st_mode ) ) + continue; + if ( !extensions || extmatch( buffer, extensions ) ) + { + if ( fcnt >= max ) + { + max += 100; + fontlist = realloc( fontlist, max * sizeof ( struct fontlist ) ); + if ( !fontlist ) + { + fprintf( stderr, "Can't allocate memory\n" ); + exit( 1 ); + } + } + + fontlist[fcnt].name = strdup( buffer ); + fontlist[fcnt].len = statb.st_size; + + figurefiletype( &fontlist[fcnt] ); + fcnt++; + } + } + + closedir( examples ); + } + + if ( fcnt == 0 ) + { + fprintf( stderr, "Can't find matching font files.\n" ); + exit( 1 ); + } + + fontlist[fcnt].name = NULL; + } + + + static unsigned int + getErrorCnt( struct fontlist* item ) + { + if ( error_count == 0 && error_fraction == 0.0 ) + return 0; + + return error_count + (unsigned int)( error_fraction * item->len ); + } + + + static int + getRandom( int low, + int high ) + { + if ( low - high < 0x10000L ) + return low + ( ( random() >> 8 ) % ( high + 1 - low ) ); + + return low + ( random() % ( high + 1 - low ) ); + } + + + static int + copyfont( struct fontlist* item, + char* newfont ) + { + static char buffer[8096]; + FILE *good, *newf; + size_t len; + unsigned int i, err_cnt; + + + good = fopen( item->name, "r" ); + if ( !good ) + { + fprintf( stderr, "Can't open `%s'\n", item->name ); + return false; + } + + newf = fopen( newfont, "w+" ); + if ( !newf ) + { + fprintf( stderr, "Can't create temporary output file `%s'\n", + newfont ); + exit( 1 ); + } + + while ( ( len = fread( buffer, 1, sizeof ( buffer ), good ) ) > 0 ) + fwrite( buffer, 1, len, newf ); + + fclose( good ); + + err_cnt = getErrorCnt( item ); + for ( i = 0; i < err_cnt; i++ ) + { + fseek( newf, getRandom( 0, (int)( item->len - 1 ) ), SEEK_SET ); + + if ( item->isbinary ) + putc( getRandom( 0, 0xFF ), newf ); + else if ( item->isascii ) + putc( getRandom( 0x20, 0x7E ), newf ); + else + { + int hex = getRandom( 0, 15 ); + + + if ( hex < 10 ) + hex += '0'; + else + hex += 'A' - 10; + + putc( hex, newf ); + } + } + + if ( ferror( newf ) ) + { + fclose( newf ); + unlink( newfont ); + return false; + } + + fclose( newf ); + + return true; + } + + + static int child_pid; + + static void + abort_test( int sig ) + { + FT_UNUSED( sig ); + + /* If a time-out happens, then kill the child */ + kill( child_pid, SIGFPE ); + write( 2, "Timeout... ", 11 ); + } + + + static void + do_test( void ) + { + int i = getRandom( 0, (int)( fcnt - 1 ) ); + static int test_num = 0; + char buffer[1024]; + + + snprintf( buffer, 1024, "%s/test%d", results_dir, test_num++ ); + + if ( copyfont ( &fontlist[i], buffer ) ) + { + signal( SIGALRM, abort_test ); + /* Anything that takes more than 20 seconds */ + /* to parse and/or rasterize is an error. */ + alarm( 20 ); + if ( ( child_pid = fork() ) == 0 ) + ExecuteTest( buffer ); + else if ( child_pid != -1 ) + { + int status; + + + waitpid( child_pid, &status, 0 ); + alarm( 0 ); + if ( WIFSIGNALED ( status ) ) + printf( "Error found in file `%s'\n", buffer ); + else + unlink( buffer ); + } + else + { + fprintf( stderr, "Can't fork test case.\n" ); + exit( 1 ); + } + alarm( 0 ); + } + } + + + static void + usage( FILE* out, + char* name ) + { + char** d = default_dir_list; + char** e = default_ext_list; + + + fprintf( out, "%s [options] -- Generate random erroneous fonts\n" + " and attempt to parse them with FreeType.\n\n", name ); + + fprintf( out, " --all All non-directory files are assumed to be fonts.\n" ); + fprintf( out, " --check-outlines Make sure we can parse the outlines of each glyph.\n" ); + fprintf( out, " --dir Append to list of font search directories\n" + " (no recursive search).\n" ); + fprintf( out, " --error-count Introduce single byte errors into each font\n" + " (default: 1)\n" ); + fprintf( out, " --error-fraction Introduce *filesize single byte errors\n" + " into each font (default: 0.0).\n" ); + fprintf( out, " --ext Add to list of extensions indicating fonts.\n" ); + fprintf( out, " --help Print this.\n" ); + fprintf( out, " --nohints Turn off hinting.\n" ); + fprintf( out, " --rasterize Attempt to rasterize each glyph.\n" ); + fprintf( out, " --results Place the created test fonts into \n" + " (default: `results')\n" ); + fprintf( out, " --size Use the given font size for the tests.\n" ); + fprintf( out, " --test Run a single test on an already existing file.\n" ); + fprintf( out, "\n" ); + + fprintf( out, "Default font extensions:\n" ); + fprintf( out, " " ); + while ( *e ) + fprintf( out, " .%s", *e++ ); + fprintf( out, "\n" ); + + fprintf( out, "Default font directories:\n" ); + fprintf( out, " " ); + while ( *d ) + fprintf( out, " %s", *d++ ); + fprintf( out, "\n" ); + } + + + int + main( int argc, + char** argv ) + { + char **dirs, **exts; + int dcnt = 0, ecnt = 0, rset = false, allexts = false; + int i; + time_t now; + char* testfile = NULL; + + + dirs = calloc( (size_t)( argc + 1 ), sizeof ( char ** ) ); + exts = calloc( (size_t)( argc + 1 ), sizeof ( char ** ) ); + + for ( i = 1; i < argc; i++ ) + { + char* pt = argv[i]; + char* end; + + + if ( pt[0] == '-' && pt[1] == '-' ) + pt++; + + if ( strcmp( pt, "-all" ) == 0 ) + allexts = true; + else if ( strcmp( pt, "-check-outlines" ) == 0 ) + check_outlines = true; + else if ( strcmp( pt, "-dir" ) == 0 ) + dirs[dcnt++] = argv[++i]; + else if ( strcmp( pt, "-error-count" ) == 0 ) + { + if ( !rset ) + error_fraction = 0.0; + rset = true; + error_count = (unsigned int)strtoul( argv[++i], &end, 10 ); + if ( *end != '\0' ) + { + fprintf( stderr, "Bad value for error-count: %s\n", argv[i] ); + exit( 1 ); + } + } + else if ( strcmp( pt, "-error-fraction" ) == 0 ) + { + if ( !rset ) + error_count = 0; + rset = true; + error_fraction = strtod( argv[++i], &end ); + if ( *end != '\0' ) + { + fprintf( stderr, "Bad value for error-fraction: %s\n", argv[i] ); + exit( 1 ); + } + if ( error_fraction < 0.0 || error_fraction > 1.0 ) + { + fprintf( stderr, "error-fraction must be in the range [0;1]\n" ); + exit( 1 ); + } + } + else if ( strcmp( pt, "-ext" ) == 0 ) + exts[ecnt++] = argv[++i]; + else if ( strcmp( pt, "-help" ) == 0 ) + { + usage( stdout, argv[0] ); + exit( 0 ); + } + else if ( strcmp( pt, "-nohints" ) == 0 ) + nohints = true; + else if ( strcmp( pt, "-rasterize" ) == 0 ) + rasterize = true; + else if ( strcmp( pt, "-results" ) == 0 ) + results_dir = argv[++i]; + else if ( strcmp( pt, "-size" ) == 0 ) + { + font_size = (FT_F26Dot6)( strtod( argv[++i], &end ) * 64 ); + if ( *end != '\0' || font_size < 64 ) + { + fprintf( stderr, "Bad value for size: %s\n", argv[i] ); + exit( 1 ); + } + } + else if ( strcmp( pt, "-test" ) == 0 ) + testfile = argv[++i]; + else + { + usage( stderr, argv[0] ); + exit( 1 ); + } + } + + if ( allexts ) + { + free( exts ); + exts = NULL; + } + else if ( ecnt == 0 ) + { + free( exts ); + exts = default_ext_list; + } + + if ( dcnt == 0 ) + { + free( dirs ); + dirs = default_dir_list; + } + + if ( testfile ) + ExecuteTest( testfile ); /* This should never return */ + + time( &now ); + srandom( (unsigned int)now ); + + FindFonts( dirs, exts ); + mkdir( results_dir, 0755 ); + + forever + do_test(); + + return 0; + } + + +/* EOF */ diff --git a/vendor/freetype/src/tools/glnames.py b/vendor/freetype/src/tools/glnames.py new file mode 100644 index 0000000..41509db --- /dev/null +++ b/vendor/freetype/src/tools/glnames.py @@ -0,0 +1,5533 @@ +#!/usr/bin/env python3 + +# +# FreeType 2 glyph name builder +# +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +""" +usage: %s + + This python script generates the glyph names tables defined in the + `psnames' module. + + Its single argument is the name of the header file to be created. +""" + +import os.path +import struct +import sys + +# This table lists the glyphs according to the Macintosh specification. +# It is used by the TrueType Postscript names table. +# +# See +# +# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html +# +# for the official list. +# +mac_standard_names = [ + # 0 + ".notdef", ".null", "nonmarkingreturn", "space", "exclam", + "quotedbl", "numbersign", "dollar", "percent", "ampersand", + + # 10 + "quotesingle", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", + + # 20 + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "colon", + + # 30 + "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", + + # 40 + "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", + + # 50 + "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", + + # 60 + "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "grave", "a", "b", + + # 70 + "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", + + # 80 + "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", + + # 90 + "w", "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", "Adieresis", "Aring", + + # 100 + "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", + "aacute", "agrave", "acircumflex", "adieresis", "atilde", + + # 110 + "aring", "ccedilla", "eacute", "egrave", "ecircumflex", + "edieresis", "iacute", "igrave", "icircumflex", "idieresis", + + # 120 + "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", + "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + + # 130 + "dagger", "degree", "cent", "sterling", "section", + "bullet", "paragraph", "germandbls", "registered", "copyright", + + # 140 + "trademark", "acute", "dieresis", "notequal", "AE", + "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", + + # 150 + "yen", "mu", "partialdiff", "summation", "product", + "pi", "integral", "ordfeminine", "ordmasculine", "Omega", + + # 160 + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", + "radical", "florin", "approxequal", "Delta", "guillemotleft", + + # 170 + "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", + "Otilde", "OE", "oe", "endash", "emdash", + + # 180 + "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", + "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", + + # 190 + "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", + "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", + "Acircumflex", + + # 200 + "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", + "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", + + # 210 + "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", + "dotlessi", "circumflex", "tilde", "macron", "breve", + + # 220 + "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", + "caron", "Lslash", "lslash", "Scaron", "scaron", + + # 230 + "Zcaron", "zcaron", "brokenbar", "Eth", "eth", + "Yacute", "yacute", "Thorn", "thorn", "minus", + + # 240 + "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", + "onequarter", "threequarters", "franc", "Gbreve", "gbreve", + + # 250 + "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", + "Ccaron", "ccaron", "dcroat" +] + +# The list of standard `SID' glyph names. For the official list, +# see Annex A of document at +# +# https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf +# +sid_standard_names = [ + # 0 + ".notdef", "space", "exclam", "quotedbl", "numbersign", + "dollar", "percent", "ampersand", "quoteright", "parenleft", + + # 10 + "parenright", "asterisk", "plus", "comma", "hyphen", + "period", "slash", "zero", "one", "two", + + # 20 + "three", "four", "five", "six", "seven", + "eight", "nine", "colon", "semicolon", "less", + + # 30 + "equal", "greater", "question", "at", "A", + "B", "C", "D", "E", "F", + + # 40 + "G", "H", "I", "J", "K", + "L", "M", "N", "O", "P", + + # 50 + "Q", "R", "S", "T", "U", + "V", "W", "X", "Y", "Z", + + # 60 + "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", + "quoteleft", "a", "b", "c", "d", + + # 70 + "e", "f", "g", "h", "i", + "j", "k", "l", "m", "n", + + # 80 + "o", "p", "q", "r", "s", + "t", "u", "v", "w", "x", + + # 90 + "y", "z", "braceleft", "bar", "braceright", + "asciitilde", "exclamdown", "cent", "sterling", "fraction", + + # 100 + "yen", "florin", "section", "currency", "quotesingle", + "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", + + # 110 + "fl", "endash", "dagger", "daggerdbl", "periodcentered", + "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", + + # 120 + "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", + "acute", "circumflex", "tilde", "macron", "breve", + + # 130 + "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", + "ogonek", "caron", "emdash", "AE", "ordfeminine", + + # 140 + "Lslash", "Oslash", "OE", "ordmasculine", "ae", + "dotlessi", "lslash", "oslash", "oe", "germandbls", + + # 150 + "onesuperior", "logicalnot", "mu", "trademark", "Eth", + "onehalf", "plusminus", "Thorn", "onequarter", "divide", + + # 160 + "brokenbar", "degree", "thorn", "threequarters", "twosuperior", + "registered", "minus", "eth", "multiply", "threesuperior", + + # 170 + "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", + "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", + + # 180 + "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", + "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", + + # 190 + "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", + "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", + + # 200 + "aacute", "acircumflex", "adieresis", "agrave", "aring", + "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", + + # 210 + "egrave", "iacute", "icircumflex", "idieresis", "igrave", + "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", + + # 220 + "otilde", "scaron", "uacute", "ucircumflex", "udieresis", + "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", + + # 230 + "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", + "Acutesmall", + "parenleftsuperior", "parenrightsuperior", "twodotenleader", + "onedotenleader", "zerooldstyle", + + # 240 + "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", + "commasuperior", + + # 250 + "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", + "bsuperior", + "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", + + # 260 + "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", + "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", + + # 270 + "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", + "Asmall", + "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", + + # 280 + "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", + "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", + + # 290 + "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", + "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", + + # 300 + "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", + "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", + "Dieresissmall", + + # 310 + "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", + "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", + "questiondownsmall", + + # 320 + "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", + "twothirds", "zerosuperior", "foursuperior", "fivesuperior", + "sixsuperior", + + # 330 + "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", + "oneinferior", + "twoinferior", "threeinferior", "fourinferior", "fiveinferior", + "sixinferior", + + # 340 + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", + "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", + "Acircumflexsmall", + + # 350 + "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", + "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", + "Igravesmall", + + # 360 + "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", + "Ntildesmall", + "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", + "Odieresissmall", + + # 370 + "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", + "001.000", + + # 380 + "001.001", "001.002", "001.003", "Black", "Bold", + "Book", "Light", "Medium", "Regular", "Roman", + + # 390 + "Semibold" +] + +# This table maps character codes of the Adobe Standard Type 1 +# encoding to glyph indices in the sid_standard_names table. +# +t1_standard_encoding = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 0, 111, 112, 113, + 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, + 0, 123, 0, 124, 125, 126, 127, 128, 129, 130, + + 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 138, 0, 139, 0, 0, + 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, + + 148, 149, 0, 0, 0, 0 +] + +# This table maps character codes of the Adobe Expert Type 1 +# encoding to glyph indices in the sid_standard_names table. +# +t1_expert_encoding = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 229, 230, 0, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, + + 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, + 0, 0, 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, 110, 267, + 268, 269, 0, 270, 271, 272, 273, 274, 275, 276, + + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 306, 0, 0, 307, 308, 309, 310, + 311, 0, 312, 0, 0, 313, 0, 0, 314, 315, + 0, 0, 316, 317, 318, 0, 0, 0, 158, 155, + 163, 319, 320, 321, 322, 323, 324, 325, 0, 0, + + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + + 373, 374, 375, 376, 377, 378 +] + +# This data has been taken literally from the files `glyphlist.txt' +# and `zapfdingbats.txt' version 2.0, Sept 2002. It is available from +# +# https://github.com/adobe-type-tools/agl-aglfn +# +adobe_glyph_list = """\ +A;0041 +AE;00C6 +AEacute;01FC +AEmacron;01E2 +AEsmall;F7E6 +Aacute;00C1 +Aacutesmall;F7E1 +Abreve;0102 +Abreveacute;1EAE +Abrevecyrillic;04D0 +Abrevedotbelow;1EB6 +Abrevegrave;1EB0 +Abrevehookabove;1EB2 +Abrevetilde;1EB4 +Acaron;01CD +Acircle;24B6 +Acircumflex;00C2 +Acircumflexacute;1EA4 +Acircumflexdotbelow;1EAC +Acircumflexgrave;1EA6 +Acircumflexhookabove;1EA8 +Acircumflexsmall;F7E2 +Acircumflextilde;1EAA +Acute;F6C9 +Acutesmall;F7B4 +Acyrillic;0410 +Adblgrave;0200 +Adieresis;00C4 +Adieresiscyrillic;04D2 +Adieresismacron;01DE +Adieresissmall;F7E4 +Adotbelow;1EA0 +Adotmacron;01E0 +Agrave;00C0 +Agravesmall;F7E0 +Ahookabove;1EA2 +Aiecyrillic;04D4 +Ainvertedbreve;0202 +Alpha;0391 +Alphatonos;0386 +Amacron;0100 +Amonospace;FF21 +Aogonek;0104 +Aring;00C5 +Aringacute;01FA +Aringbelow;1E00 +Aringsmall;F7E5 +Asmall;F761 +Atilde;00C3 +Atildesmall;F7E3 +Aybarmenian;0531 +B;0042 +Bcircle;24B7 +Bdotaccent;1E02 +Bdotbelow;1E04 +Becyrillic;0411 +Benarmenian;0532 +Beta;0392 +Bhook;0181 +Blinebelow;1E06 +Bmonospace;FF22 +Brevesmall;F6F4 +Bsmall;F762 +Btopbar;0182 +C;0043 +Caarmenian;053E +Cacute;0106 +Caron;F6CA +Caronsmall;F6F5 +Ccaron;010C +Ccedilla;00C7 +Ccedillaacute;1E08 +Ccedillasmall;F7E7 +Ccircle;24B8 +Ccircumflex;0108 +Cdot;010A +Cdotaccent;010A +Cedillasmall;F7B8 +Chaarmenian;0549 +Cheabkhasiancyrillic;04BC +Checyrillic;0427 +Chedescenderabkhasiancyrillic;04BE +Chedescendercyrillic;04B6 +Chedieresiscyrillic;04F4 +Cheharmenian;0543 +Chekhakassiancyrillic;04CB +Cheverticalstrokecyrillic;04B8 +Chi;03A7 +Chook;0187 +Circumflexsmall;F6F6 +Cmonospace;FF23 +Coarmenian;0551 +Csmall;F763 +D;0044 +DZ;01F1 +DZcaron;01C4 +Daarmenian;0534 +Dafrican;0189 +Dcaron;010E +Dcedilla;1E10 +Dcircle;24B9 +Dcircumflexbelow;1E12 +Dcroat;0110 +Ddotaccent;1E0A +Ddotbelow;1E0C +Decyrillic;0414 +Deicoptic;03EE +Delta;2206 +Deltagreek;0394 +Dhook;018A +Dieresis;F6CB +DieresisAcute;F6CC +DieresisGrave;F6CD +Dieresissmall;F7A8 +Digammagreek;03DC +Djecyrillic;0402 +Dlinebelow;1E0E +Dmonospace;FF24 +Dotaccentsmall;F6F7 +Dslash;0110 +Dsmall;F764 +Dtopbar;018B +Dz;01F2 +Dzcaron;01C5 +Dzeabkhasiancyrillic;04E0 +Dzecyrillic;0405 +Dzhecyrillic;040F +E;0045 +Eacute;00C9 +Eacutesmall;F7E9 +Ebreve;0114 +Ecaron;011A +Ecedillabreve;1E1C +Echarmenian;0535 +Ecircle;24BA +Ecircumflex;00CA +Ecircumflexacute;1EBE +Ecircumflexbelow;1E18 +Ecircumflexdotbelow;1EC6 +Ecircumflexgrave;1EC0 +Ecircumflexhookabove;1EC2 +Ecircumflexsmall;F7EA +Ecircumflextilde;1EC4 +Ecyrillic;0404 +Edblgrave;0204 +Edieresis;00CB +Edieresissmall;F7EB +Edot;0116 +Edotaccent;0116 +Edotbelow;1EB8 +Efcyrillic;0424 +Egrave;00C8 +Egravesmall;F7E8 +Eharmenian;0537 +Ehookabove;1EBA +Eightroman;2167 +Einvertedbreve;0206 +Eiotifiedcyrillic;0464 +Elcyrillic;041B +Elevenroman;216A +Emacron;0112 +Emacronacute;1E16 +Emacrongrave;1E14 +Emcyrillic;041C +Emonospace;FF25 +Encyrillic;041D +Endescendercyrillic;04A2 +Eng;014A +Enghecyrillic;04A4 +Enhookcyrillic;04C7 +Eogonek;0118 +Eopen;0190 +Epsilon;0395 +Epsilontonos;0388 +Ercyrillic;0420 +Ereversed;018E +Ereversedcyrillic;042D +Escyrillic;0421 +Esdescendercyrillic;04AA +Esh;01A9 +Esmall;F765 +Eta;0397 +Etarmenian;0538 +Etatonos;0389 +Eth;00D0 +Ethsmall;F7F0 +Etilde;1EBC +Etildebelow;1E1A +Euro;20AC +Ezh;01B7 +Ezhcaron;01EE +Ezhreversed;01B8 +F;0046 +Fcircle;24BB +Fdotaccent;1E1E +Feharmenian;0556 +Feicoptic;03E4 +Fhook;0191 +Fitacyrillic;0472 +Fiveroman;2164 +Fmonospace;FF26 +Fourroman;2163 +Fsmall;F766 +G;0047 +GBsquare;3387 +Gacute;01F4 +Gamma;0393 +Gammaafrican;0194 +Gangiacoptic;03EA +Gbreve;011E +Gcaron;01E6 +Gcedilla;0122 +Gcircle;24BC +Gcircumflex;011C +Gcommaaccent;0122 +Gdot;0120 +Gdotaccent;0120 +Gecyrillic;0413 +Ghadarmenian;0542 +Ghemiddlehookcyrillic;0494 +Ghestrokecyrillic;0492 +Gheupturncyrillic;0490 +Ghook;0193 +Gimarmenian;0533 +Gjecyrillic;0403 +Gmacron;1E20 +Gmonospace;FF27 +Grave;F6CE +Gravesmall;F760 +Gsmall;F767 +Gsmallhook;029B +Gstroke;01E4 +H;0048 +H18533;25CF +H18543;25AA +H18551;25AB +H22073;25A1 +HPsquare;33CB +Haabkhasiancyrillic;04A8 +Hadescendercyrillic;04B2 +Hardsigncyrillic;042A +Hbar;0126 +Hbrevebelow;1E2A +Hcedilla;1E28 +Hcircle;24BD +Hcircumflex;0124 +Hdieresis;1E26 +Hdotaccent;1E22 +Hdotbelow;1E24 +Hmonospace;FF28 +Hoarmenian;0540 +Horicoptic;03E8 +Hsmall;F768 +Hungarumlaut;F6CF +Hungarumlautsmall;F6F8 +Hzsquare;3390 +I;0049 +IAcyrillic;042F +IJ;0132 +IUcyrillic;042E +Iacute;00CD +Iacutesmall;F7ED +Ibreve;012C +Icaron;01CF +Icircle;24BE +Icircumflex;00CE +Icircumflexsmall;F7EE +Icyrillic;0406 +Idblgrave;0208 +Idieresis;00CF +Idieresisacute;1E2E +Idieresiscyrillic;04E4 +Idieresissmall;F7EF +Idot;0130 +Idotaccent;0130 +Idotbelow;1ECA +Iebrevecyrillic;04D6 +Iecyrillic;0415 +Ifraktur;2111 +Igrave;00CC +Igravesmall;F7EC +Ihookabove;1EC8 +Iicyrillic;0418 +Iinvertedbreve;020A +Iishortcyrillic;0419 +Imacron;012A +Imacroncyrillic;04E2 +Imonospace;FF29 +Iniarmenian;053B +Iocyrillic;0401 +Iogonek;012E +Iota;0399 +Iotaafrican;0196 +Iotadieresis;03AA +Iotatonos;038A +Ismall;F769 +Istroke;0197 +Itilde;0128 +Itildebelow;1E2C +Izhitsacyrillic;0474 +Izhitsadblgravecyrillic;0476 +J;004A +Jaarmenian;0541 +Jcircle;24BF +Jcircumflex;0134 +Jecyrillic;0408 +Jheharmenian;054B +Jmonospace;FF2A +Jsmall;F76A +K;004B +KBsquare;3385 +KKsquare;33CD +Kabashkircyrillic;04A0 +Kacute;1E30 +Kacyrillic;041A +Kadescendercyrillic;049A +Kahookcyrillic;04C3 +Kappa;039A +Kastrokecyrillic;049E +Kaverticalstrokecyrillic;049C +Kcaron;01E8 +Kcedilla;0136 +Kcircle;24C0 +Kcommaaccent;0136 +Kdotbelow;1E32 +Keharmenian;0554 +Kenarmenian;053F +Khacyrillic;0425 +Kheicoptic;03E6 +Khook;0198 +Kjecyrillic;040C +Klinebelow;1E34 +Kmonospace;FF2B +Koppacyrillic;0480 +Koppagreek;03DE +Ksicyrillic;046E +Ksmall;F76B +L;004C +LJ;01C7 +LL;F6BF +Lacute;0139 +Lambda;039B +Lcaron;013D +Lcedilla;013B +Lcircle;24C1 +Lcircumflexbelow;1E3C +Lcommaaccent;013B +Ldot;013F +Ldotaccent;013F +Ldotbelow;1E36 +Ldotbelowmacron;1E38 +Liwnarmenian;053C +Lj;01C8 +Ljecyrillic;0409 +Llinebelow;1E3A +Lmonospace;FF2C +Lslash;0141 +Lslashsmall;F6F9 +Lsmall;F76C +M;004D +MBsquare;3386 +Macron;F6D0 +Macronsmall;F7AF +Macute;1E3E +Mcircle;24C2 +Mdotaccent;1E40 +Mdotbelow;1E42 +Menarmenian;0544 +Mmonospace;FF2D +Msmall;F76D +Mturned;019C +Mu;039C +N;004E +NJ;01CA +Nacute;0143 +Ncaron;0147 +Ncedilla;0145 +Ncircle;24C3 +Ncircumflexbelow;1E4A +Ncommaaccent;0145 +Ndotaccent;1E44 +Ndotbelow;1E46 +Nhookleft;019D +Nineroman;2168 +Nj;01CB +Njecyrillic;040A +Nlinebelow;1E48 +Nmonospace;FF2E +Nowarmenian;0546 +Nsmall;F76E +Ntilde;00D1 +Ntildesmall;F7F1 +Nu;039D +O;004F +OE;0152 +OEsmall;F6FA +Oacute;00D3 +Oacutesmall;F7F3 +Obarredcyrillic;04E8 +Obarreddieresiscyrillic;04EA +Obreve;014E +Ocaron;01D1 +Ocenteredtilde;019F +Ocircle;24C4 +Ocircumflex;00D4 +Ocircumflexacute;1ED0 +Ocircumflexdotbelow;1ED8 +Ocircumflexgrave;1ED2 +Ocircumflexhookabove;1ED4 +Ocircumflexsmall;F7F4 +Ocircumflextilde;1ED6 +Ocyrillic;041E +Odblacute;0150 +Odblgrave;020C +Odieresis;00D6 +Odieresiscyrillic;04E6 +Odieresissmall;F7F6 +Odotbelow;1ECC +Ogoneksmall;F6FB +Ograve;00D2 +Ogravesmall;F7F2 +Oharmenian;0555 +Ohm;2126 +Ohookabove;1ECE +Ohorn;01A0 +Ohornacute;1EDA +Ohorndotbelow;1EE2 +Ohorngrave;1EDC +Ohornhookabove;1EDE +Ohorntilde;1EE0 +Ohungarumlaut;0150 +Oi;01A2 +Oinvertedbreve;020E +Omacron;014C +Omacronacute;1E52 +Omacrongrave;1E50 +Omega;2126 +Omegacyrillic;0460 +Omegagreek;03A9 +Omegaroundcyrillic;047A +Omegatitlocyrillic;047C +Omegatonos;038F +Omicron;039F +Omicrontonos;038C +Omonospace;FF2F +Oneroman;2160 +Oogonek;01EA +Oogonekmacron;01EC +Oopen;0186 +Oslash;00D8 +Oslashacute;01FE +Oslashsmall;F7F8 +Osmall;F76F +Ostrokeacute;01FE +Otcyrillic;047E +Otilde;00D5 +Otildeacute;1E4C +Otildedieresis;1E4E +Otildesmall;F7F5 +P;0050 +Pacute;1E54 +Pcircle;24C5 +Pdotaccent;1E56 +Pecyrillic;041F +Peharmenian;054A +Pemiddlehookcyrillic;04A6 +Phi;03A6 +Phook;01A4 +Pi;03A0 +Piwrarmenian;0553 +Pmonospace;FF30 +Psi;03A8 +Psicyrillic;0470 +Psmall;F770 +Q;0051 +Qcircle;24C6 +Qmonospace;FF31 +Qsmall;F771 +R;0052 +Raarmenian;054C +Racute;0154 +Rcaron;0158 +Rcedilla;0156 +Rcircle;24C7 +Rcommaaccent;0156 +Rdblgrave;0210 +Rdotaccent;1E58 +Rdotbelow;1E5A +Rdotbelowmacron;1E5C +Reharmenian;0550 +Rfraktur;211C +Rho;03A1 +Ringsmall;F6FC +Rinvertedbreve;0212 +Rlinebelow;1E5E +Rmonospace;FF32 +Rsmall;F772 +Rsmallinverted;0281 +Rsmallinvertedsuperior;02B6 +S;0053 +SF010000;250C +SF020000;2514 +SF030000;2510 +SF040000;2518 +SF050000;253C +SF060000;252C +SF070000;2534 +SF080000;251C +SF090000;2524 +SF100000;2500 +SF110000;2502 +SF190000;2561 +SF200000;2562 +SF210000;2556 +SF220000;2555 +SF230000;2563 +SF240000;2551 +SF250000;2557 +SF260000;255D +SF270000;255C +SF280000;255B +SF360000;255E +SF370000;255F +SF380000;255A +SF390000;2554 +SF400000;2569 +SF410000;2566 +SF420000;2560 +SF430000;2550 +SF440000;256C +SF450000;2567 +SF460000;2568 +SF470000;2564 +SF480000;2565 +SF490000;2559 +SF500000;2558 +SF510000;2552 +SF520000;2553 +SF530000;256B +SF540000;256A +Sacute;015A +Sacutedotaccent;1E64 +Sampigreek;03E0 +Scaron;0160 +Scarondotaccent;1E66 +Scaronsmall;F6FD +Scedilla;015E +Schwa;018F +Schwacyrillic;04D8 +Schwadieresiscyrillic;04DA +Scircle;24C8 +Scircumflex;015C +Scommaaccent;0218 +Sdotaccent;1E60 +Sdotbelow;1E62 +Sdotbelowdotaccent;1E68 +Seharmenian;054D +Sevenroman;2166 +Shaarmenian;0547 +Shacyrillic;0428 +Shchacyrillic;0429 +Sheicoptic;03E2 +Shhacyrillic;04BA +Shimacoptic;03EC +Sigma;03A3 +Sixroman;2165 +Smonospace;FF33 +Softsigncyrillic;042C +Ssmall;F773 +Stigmagreek;03DA +T;0054 +Tau;03A4 +Tbar;0166 +Tcaron;0164 +Tcedilla;0162 +Tcircle;24C9 +Tcircumflexbelow;1E70 +Tcommaaccent;0162 +Tdotaccent;1E6A +Tdotbelow;1E6C +Tecyrillic;0422 +Tedescendercyrillic;04AC +Tenroman;2169 +Tetsecyrillic;04B4 +Theta;0398 +Thook;01AC +Thorn;00DE +Thornsmall;F7FE +Threeroman;2162 +Tildesmall;F6FE +Tiwnarmenian;054F +Tlinebelow;1E6E +Tmonospace;FF34 +Toarmenian;0539 +Tonefive;01BC +Tonesix;0184 +Tonetwo;01A7 +Tretroflexhook;01AE +Tsecyrillic;0426 +Tshecyrillic;040B +Tsmall;F774 +Twelveroman;216B +Tworoman;2161 +U;0055 +Uacute;00DA +Uacutesmall;F7FA +Ubreve;016C +Ucaron;01D3 +Ucircle;24CA +Ucircumflex;00DB +Ucircumflexbelow;1E76 +Ucircumflexsmall;F7FB +Ucyrillic;0423 +Udblacute;0170 +Udblgrave;0214 +Udieresis;00DC +Udieresisacute;01D7 +Udieresisbelow;1E72 +Udieresiscaron;01D9 +Udieresiscyrillic;04F0 +Udieresisgrave;01DB +Udieresismacron;01D5 +Udieresissmall;F7FC +Udotbelow;1EE4 +Ugrave;00D9 +Ugravesmall;F7F9 +Uhookabove;1EE6 +Uhorn;01AF +Uhornacute;1EE8 +Uhorndotbelow;1EF0 +Uhorngrave;1EEA +Uhornhookabove;1EEC +Uhorntilde;1EEE +Uhungarumlaut;0170 +Uhungarumlautcyrillic;04F2 +Uinvertedbreve;0216 +Ukcyrillic;0478 +Umacron;016A +Umacroncyrillic;04EE +Umacrondieresis;1E7A +Umonospace;FF35 +Uogonek;0172 +Upsilon;03A5 +Upsilon1;03D2 +Upsilonacutehooksymbolgreek;03D3 +Upsilonafrican;01B1 +Upsilondieresis;03AB +Upsilondieresishooksymbolgreek;03D4 +Upsilonhooksymbol;03D2 +Upsilontonos;038E +Uring;016E +Ushortcyrillic;040E +Usmall;F775 +Ustraightcyrillic;04AE +Ustraightstrokecyrillic;04B0 +Utilde;0168 +Utildeacute;1E78 +Utildebelow;1E74 +V;0056 +Vcircle;24CB +Vdotbelow;1E7E +Vecyrillic;0412 +Vewarmenian;054E +Vhook;01B2 +Vmonospace;FF36 +Voarmenian;0548 +Vsmall;F776 +Vtilde;1E7C +W;0057 +Wacute;1E82 +Wcircle;24CC +Wcircumflex;0174 +Wdieresis;1E84 +Wdotaccent;1E86 +Wdotbelow;1E88 +Wgrave;1E80 +Wmonospace;FF37 +Wsmall;F777 +X;0058 +Xcircle;24CD +Xdieresis;1E8C +Xdotaccent;1E8A +Xeharmenian;053D +Xi;039E +Xmonospace;FF38 +Xsmall;F778 +Y;0059 +Yacute;00DD +Yacutesmall;F7FD +Yatcyrillic;0462 +Ycircle;24CE +Ycircumflex;0176 +Ydieresis;0178 +Ydieresissmall;F7FF +Ydotaccent;1E8E +Ydotbelow;1EF4 +Yericyrillic;042B +Yerudieresiscyrillic;04F8 +Ygrave;1EF2 +Yhook;01B3 +Yhookabove;1EF6 +Yiarmenian;0545 +Yicyrillic;0407 +Yiwnarmenian;0552 +Ymonospace;FF39 +Ysmall;F779 +Ytilde;1EF8 +Yusbigcyrillic;046A +Yusbigiotifiedcyrillic;046C +Yuslittlecyrillic;0466 +Yuslittleiotifiedcyrillic;0468 +Z;005A +Zaarmenian;0536 +Zacute;0179 +Zcaron;017D +Zcaronsmall;F6FF +Zcircle;24CF +Zcircumflex;1E90 +Zdot;017B +Zdotaccent;017B +Zdotbelow;1E92 +Zecyrillic;0417 +Zedescendercyrillic;0498 +Zedieresiscyrillic;04DE +Zeta;0396 +Zhearmenian;053A +Zhebrevecyrillic;04C1 +Zhecyrillic;0416 +Zhedescendercyrillic;0496 +Zhedieresiscyrillic;04DC +Zlinebelow;1E94 +Zmonospace;FF3A +Zsmall;F77A +Zstroke;01B5 +a;0061 +aabengali;0986 +aacute;00E1 +aadeva;0906 +aagujarati;0A86 +aagurmukhi;0A06 +aamatragurmukhi;0A3E +aarusquare;3303 +aavowelsignbengali;09BE +aavowelsigndeva;093E +aavowelsigngujarati;0ABE +abbreviationmarkarmenian;055F +abbreviationsigndeva;0970 +abengali;0985 +abopomofo;311A +abreve;0103 +abreveacute;1EAF +abrevecyrillic;04D1 +abrevedotbelow;1EB7 +abrevegrave;1EB1 +abrevehookabove;1EB3 +abrevetilde;1EB5 +acaron;01CE +acircle;24D0 +acircumflex;00E2 +acircumflexacute;1EA5 +acircumflexdotbelow;1EAD +acircumflexgrave;1EA7 +acircumflexhookabove;1EA9 +acircumflextilde;1EAB +acute;00B4 +acutebelowcmb;0317 +acutecmb;0301 +acutecomb;0301 +acutedeva;0954 +acutelowmod;02CF +acutetonecmb;0341 +acyrillic;0430 +adblgrave;0201 +addakgurmukhi;0A71 +adeva;0905 +adieresis;00E4 +adieresiscyrillic;04D3 +adieresismacron;01DF +adotbelow;1EA1 +adotmacron;01E1 +ae;00E6 +aeacute;01FD +aekorean;3150 +aemacron;01E3 +afii00208;2015 +afii08941;20A4 +afii10017;0410 +afii10018;0411 +afii10019;0412 +afii10020;0413 +afii10021;0414 +afii10022;0415 +afii10023;0401 +afii10024;0416 +afii10025;0417 +afii10026;0418 +afii10027;0419 +afii10028;041A +afii10029;041B +afii10030;041C +afii10031;041D +afii10032;041E +afii10033;041F +afii10034;0420 +afii10035;0421 +afii10036;0422 +afii10037;0423 +afii10038;0424 +afii10039;0425 +afii10040;0426 +afii10041;0427 +afii10042;0428 +afii10043;0429 +afii10044;042A +afii10045;042B +afii10046;042C +afii10047;042D +afii10048;042E +afii10049;042F +afii10050;0490 +afii10051;0402 +afii10052;0403 +afii10053;0404 +afii10054;0405 +afii10055;0406 +afii10056;0407 +afii10057;0408 +afii10058;0409 +afii10059;040A +afii10060;040B +afii10061;040C +afii10062;040E +afii10063;F6C4 +afii10064;F6C5 +afii10065;0430 +afii10066;0431 +afii10067;0432 +afii10068;0433 +afii10069;0434 +afii10070;0435 +afii10071;0451 +afii10072;0436 +afii10073;0437 +afii10074;0438 +afii10075;0439 +afii10076;043A +afii10077;043B +afii10078;043C +afii10079;043D +afii10080;043E +afii10081;043F +afii10082;0440 +afii10083;0441 +afii10084;0442 +afii10085;0443 +afii10086;0444 +afii10087;0445 +afii10088;0446 +afii10089;0447 +afii10090;0448 +afii10091;0449 +afii10092;044A +afii10093;044B +afii10094;044C +afii10095;044D +afii10096;044E +afii10097;044F +afii10098;0491 +afii10099;0452 +afii10100;0453 +afii10101;0454 +afii10102;0455 +afii10103;0456 +afii10104;0457 +afii10105;0458 +afii10106;0459 +afii10107;045A +afii10108;045B +afii10109;045C +afii10110;045E +afii10145;040F +afii10146;0462 +afii10147;0472 +afii10148;0474 +afii10192;F6C6 +afii10193;045F +afii10194;0463 +afii10195;0473 +afii10196;0475 +afii10831;F6C7 +afii10832;F6C8 +afii10846;04D9 +afii299;200E +afii300;200F +afii301;200D +afii57381;066A +afii57388;060C +afii57392;0660 +afii57393;0661 +afii57394;0662 +afii57395;0663 +afii57396;0664 +afii57397;0665 +afii57398;0666 +afii57399;0667 +afii57400;0668 +afii57401;0669 +afii57403;061B +afii57407;061F +afii57409;0621 +afii57410;0622 +afii57411;0623 +afii57412;0624 +afii57413;0625 +afii57414;0626 +afii57415;0627 +afii57416;0628 +afii57417;0629 +afii57418;062A +afii57419;062B +afii57420;062C +afii57421;062D +afii57422;062E +afii57423;062F +afii57424;0630 +afii57425;0631 +afii57426;0632 +afii57427;0633 +afii57428;0634 +afii57429;0635 +afii57430;0636 +afii57431;0637 +afii57432;0638 +afii57433;0639 +afii57434;063A +afii57440;0640 +afii57441;0641 +afii57442;0642 +afii57443;0643 +afii57444;0644 +afii57445;0645 +afii57446;0646 +afii57448;0648 +afii57449;0649 +afii57450;064A +afii57451;064B +afii57452;064C +afii57453;064D +afii57454;064E +afii57455;064F +afii57456;0650 +afii57457;0651 +afii57458;0652 +afii57470;0647 +afii57505;06A4 +afii57506;067E +afii57507;0686 +afii57508;0698 +afii57509;06AF +afii57511;0679 +afii57512;0688 +afii57513;0691 +afii57514;06BA +afii57519;06D2 +afii57534;06D5 +afii57636;20AA +afii57645;05BE +afii57658;05C3 +afii57664;05D0 +afii57665;05D1 +afii57666;05D2 +afii57667;05D3 +afii57668;05D4 +afii57669;05D5 +afii57670;05D6 +afii57671;05D7 +afii57672;05D8 +afii57673;05D9 +afii57674;05DA +afii57675;05DB +afii57676;05DC +afii57677;05DD +afii57678;05DE +afii57679;05DF +afii57680;05E0 +afii57681;05E1 +afii57682;05E2 +afii57683;05E3 +afii57684;05E4 +afii57685;05E5 +afii57686;05E6 +afii57687;05E7 +afii57688;05E8 +afii57689;05E9 +afii57690;05EA +afii57694;FB2A +afii57695;FB2B +afii57700;FB4B +afii57705;FB1F +afii57716;05F0 +afii57717;05F1 +afii57718;05F2 +afii57723;FB35 +afii57793;05B4 +afii57794;05B5 +afii57795;05B6 +afii57796;05BB +afii57797;05B8 +afii57798;05B7 +afii57799;05B0 +afii57800;05B2 +afii57801;05B1 +afii57802;05B3 +afii57803;05C2 +afii57804;05C1 +afii57806;05B9 +afii57807;05BC +afii57839;05BD +afii57841;05BF +afii57842;05C0 +afii57929;02BC +afii61248;2105 +afii61289;2113 +afii61352;2116 +afii61573;202C +afii61574;202D +afii61575;202E +afii61664;200C +afii63167;066D +afii64937;02BD +agrave;00E0 +agujarati;0A85 +agurmukhi;0A05 +ahiragana;3042 +ahookabove;1EA3 +aibengali;0990 +aibopomofo;311E +aideva;0910 +aiecyrillic;04D5 +aigujarati;0A90 +aigurmukhi;0A10 +aimatragurmukhi;0A48 +ainarabic;0639 +ainfinalarabic;FECA +aininitialarabic;FECB +ainmedialarabic;FECC +ainvertedbreve;0203 +aivowelsignbengali;09C8 +aivowelsigndeva;0948 +aivowelsigngujarati;0AC8 +akatakana;30A2 +akatakanahalfwidth;FF71 +akorean;314F +alef;05D0 +alefarabic;0627 +alefdageshhebrew;FB30 +aleffinalarabic;FE8E +alefhamzaabovearabic;0623 +alefhamzaabovefinalarabic;FE84 +alefhamzabelowarabic;0625 +alefhamzabelowfinalarabic;FE88 +alefhebrew;05D0 +aleflamedhebrew;FB4F +alefmaddaabovearabic;0622 +alefmaddaabovefinalarabic;FE82 +alefmaksuraarabic;0649 +alefmaksurafinalarabic;FEF0 +alefmaksurainitialarabic;FEF3 +alefmaksuramedialarabic;FEF4 +alefpatahhebrew;FB2E +alefqamatshebrew;FB2F +aleph;2135 +allequal;224C +alpha;03B1 +alphatonos;03AC +amacron;0101 +amonospace;FF41 +ampersand;0026 +ampersandmonospace;FF06 +ampersandsmall;F726 +amsquare;33C2 +anbopomofo;3122 +angbopomofo;3124 +angkhankhuthai;0E5A +angle;2220 +anglebracketleft;3008 +anglebracketleftvertical;FE3F +anglebracketright;3009 +anglebracketrightvertical;FE40 +angleleft;2329 +angleright;232A +angstrom;212B +anoteleia;0387 +anudattadeva;0952 +anusvarabengali;0982 +anusvaradeva;0902 +anusvaragujarati;0A82 +aogonek;0105 +apaatosquare;3300 +aparen;249C +apostrophearmenian;055A +apostrophemod;02BC +apple;F8FF +approaches;2250 +approxequal;2248 +approxequalorimage;2252 +approximatelyequal;2245 +araeaekorean;318E +araeakorean;318D +arc;2312 +arighthalfring;1E9A +aring;00E5 +aringacute;01FB +aringbelow;1E01 +arrowboth;2194 +arrowdashdown;21E3 +arrowdashleft;21E0 +arrowdashright;21E2 +arrowdashup;21E1 +arrowdblboth;21D4 +arrowdbldown;21D3 +arrowdblleft;21D0 +arrowdblright;21D2 +arrowdblup;21D1 +arrowdown;2193 +arrowdownleft;2199 +arrowdownright;2198 +arrowdownwhite;21E9 +arrowheaddownmod;02C5 +arrowheadleftmod;02C2 +arrowheadrightmod;02C3 +arrowheadupmod;02C4 +arrowhorizex;F8E7 +arrowleft;2190 +arrowleftdbl;21D0 +arrowleftdblstroke;21CD +arrowleftoverright;21C6 +arrowleftwhite;21E6 +arrowright;2192 +arrowrightdblstroke;21CF +arrowrightheavy;279E +arrowrightoverleft;21C4 +arrowrightwhite;21E8 +arrowtableft;21E4 +arrowtabright;21E5 +arrowup;2191 +arrowupdn;2195 +arrowupdnbse;21A8 +arrowupdownbase;21A8 +arrowupleft;2196 +arrowupleftofdown;21C5 +arrowupright;2197 +arrowupwhite;21E7 +arrowvertex;F8E6 +asciicircum;005E +asciicircummonospace;FF3E +asciitilde;007E +asciitildemonospace;FF5E +ascript;0251 +ascriptturned;0252 +asmallhiragana;3041 +asmallkatakana;30A1 +asmallkatakanahalfwidth;FF67 +asterisk;002A +asteriskaltonearabic;066D +asteriskarabic;066D +asteriskmath;2217 +asteriskmonospace;FF0A +asterisksmall;FE61 +asterism;2042 +asuperior;F6E9 +asymptoticallyequal;2243 +at;0040 +atilde;00E3 +atmonospace;FF20 +atsmall;FE6B +aturned;0250 +aubengali;0994 +aubopomofo;3120 +audeva;0914 +augujarati;0A94 +augurmukhi;0A14 +aulengthmarkbengali;09D7 +aumatragurmukhi;0A4C +auvowelsignbengali;09CC +auvowelsigndeva;094C +auvowelsigngujarati;0ACC +avagrahadeva;093D +aybarmenian;0561 +ayin;05E2 +ayinaltonehebrew;FB20 +ayinhebrew;05E2 +b;0062 +babengali;09AC +backslash;005C +backslashmonospace;FF3C +badeva;092C +bagujarati;0AAC +bagurmukhi;0A2C +bahiragana;3070 +bahtthai;0E3F +bakatakana;30D0 +bar;007C +barmonospace;FF5C +bbopomofo;3105 +bcircle;24D1 +bdotaccent;1E03 +bdotbelow;1E05 +beamedsixteenthnotes;266C +because;2235 +becyrillic;0431 +beharabic;0628 +behfinalarabic;FE90 +behinitialarabic;FE91 +behiragana;3079 +behmedialarabic;FE92 +behmeeminitialarabic;FC9F +behmeemisolatedarabic;FC08 +behnoonfinalarabic;FC6D +bekatakana;30D9 +benarmenian;0562 +bet;05D1 +beta;03B2 +betasymbolgreek;03D0 +betdagesh;FB31 +betdageshhebrew;FB31 +bethebrew;05D1 +betrafehebrew;FB4C +bhabengali;09AD +bhadeva;092D +bhagujarati;0AAD +bhagurmukhi;0A2D +bhook;0253 +bihiragana;3073 +bikatakana;30D3 +bilabialclick;0298 +bindigurmukhi;0A02 +birusquare;3331 +blackcircle;25CF +blackdiamond;25C6 +blackdownpointingtriangle;25BC +blackleftpointingpointer;25C4 +blackleftpointingtriangle;25C0 +blacklenticularbracketleft;3010 +blacklenticularbracketleftvertical;FE3B +blacklenticularbracketright;3011 +blacklenticularbracketrightvertical;FE3C +blacklowerlefttriangle;25E3 +blacklowerrighttriangle;25E2 +blackrectangle;25AC +blackrightpointingpointer;25BA +blackrightpointingtriangle;25B6 +blacksmallsquare;25AA +blacksmilingface;263B +blacksquare;25A0 +blackstar;2605 +blackupperlefttriangle;25E4 +blackupperrighttriangle;25E5 +blackuppointingsmalltriangle;25B4 +blackuppointingtriangle;25B2 +blank;2423 +blinebelow;1E07 +block;2588 +bmonospace;FF42 +bobaimaithai;0E1A +bohiragana;307C +bokatakana;30DC +bparen;249D +bqsquare;33C3 +braceex;F8F4 +braceleft;007B +braceleftbt;F8F3 +braceleftmid;F8F2 +braceleftmonospace;FF5B +braceleftsmall;FE5B +bracelefttp;F8F1 +braceleftvertical;FE37 +braceright;007D +bracerightbt;F8FE +bracerightmid;F8FD +bracerightmonospace;FF5D +bracerightsmall;FE5C +bracerighttp;F8FC +bracerightvertical;FE38 +bracketleft;005B +bracketleftbt;F8F0 +bracketleftex;F8EF +bracketleftmonospace;FF3B +bracketlefttp;F8EE +bracketright;005D +bracketrightbt;F8FB +bracketrightex;F8FA +bracketrightmonospace;FF3D +bracketrighttp;F8F9 +breve;02D8 +brevebelowcmb;032E +brevecmb;0306 +breveinvertedbelowcmb;032F +breveinvertedcmb;0311 +breveinverteddoublecmb;0361 +bridgebelowcmb;032A +bridgeinvertedbelowcmb;033A +brokenbar;00A6 +bstroke;0180 +bsuperior;F6EA +btopbar;0183 +buhiragana;3076 +bukatakana;30D6 +bullet;2022 +bulletinverse;25D8 +bulletoperator;2219 +bullseye;25CE +c;0063 +caarmenian;056E +cabengali;099A +cacute;0107 +cadeva;091A +cagujarati;0A9A +cagurmukhi;0A1A +calsquare;3388 +candrabindubengali;0981 +candrabinducmb;0310 +candrabindudeva;0901 +candrabindugujarati;0A81 +capslock;21EA +careof;2105 +caron;02C7 +caronbelowcmb;032C +caroncmb;030C +carriagereturn;21B5 +cbopomofo;3118 +ccaron;010D +ccedilla;00E7 +ccedillaacute;1E09 +ccircle;24D2 +ccircumflex;0109 +ccurl;0255 +cdot;010B +cdotaccent;010B +cdsquare;33C5 +cedilla;00B8 +cedillacmb;0327 +cent;00A2 +centigrade;2103 +centinferior;F6DF +centmonospace;FFE0 +centoldstyle;F7A2 +centsuperior;F6E0 +chaarmenian;0579 +chabengali;099B +chadeva;091B +chagujarati;0A9B +chagurmukhi;0A1B +chbopomofo;3114 +cheabkhasiancyrillic;04BD +checkmark;2713 +checyrillic;0447 +chedescenderabkhasiancyrillic;04BF +chedescendercyrillic;04B7 +chedieresiscyrillic;04F5 +cheharmenian;0573 +chekhakassiancyrillic;04CC +cheverticalstrokecyrillic;04B9 +chi;03C7 +chieuchacirclekorean;3277 +chieuchaparenkorean;3217 +chieuchcirclekorean;3269 +chieuchkorean;314A +chieuchparenkorean;3209 +chochangthai;0E0A +chochanthai;0E08 +chochingthai;0E09 +chochoethai;0E0C +chook;0188 +cieucacirclekorean;3276 +cieucaparenkorean;3216 +cieuccirclekorean;3268 +cieuckorean;3148 +cieucparenkorean;3208 +cieucuparenkorean;321C +circle;25CB +circlemultiply;2297 +circleot;2299 +circleplus;2295 +circlepostalmark;3036 +circlewithlefthalfblack;25D0 +circlewithrighthalfblack;25D1 +circumflex;02C6 +circumflexbelowcmb;032D +circumflexcmb;0302 +clear;2327 +clickalveolar;01C2 +clickdental;01C0 +clicklateral;01C1 +clickretroflex;01C3 +club;2663 +clubsuitblack;2663 +clubsuitwhite;2667 +cmcubedsquare;33A4 +cmonospace;FF43 +cmsquaredsquare;33A0 +coarmenian;0581 +colon;003A +colonmonetary;20A1 +colonmonospace;FF1A +colonsign;20A1 +colonsmall;FE55 +colontriangularhalfmod;02D1 +colontriangularmod;02D0 +comma;002C +commaabovecmb;0313 +commaaboverightcmb;0315 +commaaccent;F6C3 +commaarabic;060C +commaarmenian;055D +commainferior;F6E1 +commamonospace;FF0C +commareversedabovecmb;0314 +commareversedmod;02BD +commasmall;FE50 +commasuperior;F6E2 +commaturnedabovecmb;0312 +commaturnedmod;02BB +compass;263C +congruent;2245 +contourintegral;222E +control;2303 +controlACK;0006 +controlBEL;0007 +controlBS;0008 +controlCAN;0018 +controlCR;000D +controlDC1;0011 +controlDC2;0012 +controlDC3;0013 +controlDC4;0014 +controlDEL;007F +controlDLE;0010 +controlEM;0019 +controlENQ;0005 +controlEOT;0004 +controlESC;001B +controlETB;0017 +controlETX;0003 +controlFF;000C +controlFS;001C +controlGS;001D +controlHT;0009 +controlLF;000A +controlNAK;0015 +controlRS;001E +controlSI;000F +controlSO;000E +controlSOT;0002 +controlSTX;0001 +controlSUB;001A +controlSYN;0016 +controlUS;001F +controlVT;000B +copyright;00A9 +copyrightsans;F8E9 +copyrightserif;F6D9 +cornerbracketleft;300C +cornerbracketlefthalfwidth;FF62 +cornerbracketleftvertical;FE41 +cornerbracketright;300D +cornerbracketrighthalfwidth;FF63 +cornerbracketrightvertical;FE42 +corporationsquare;337F +cosquare;33C7 +coverkgsquare;33C6 +cparen;249E +cruzeiro;20A2 +cstretched;0297 +curlyand;22CF +curlyor;22CE +currency;00A4 +cyrBreve;F6D1 +cyrFlex;F6D2 +cyrbreve;F6D4 +cyrflex;F6D5 +d;0064 +daarmenian;0564 +dabengali;09A6 +dadarabic;0636 +dadeva;0926 +dadfinalarabic;FEBE +dadinitialarabic;FEBF +dadmedialarabic;FEC0 +dagesh;05BC +dageshhebrew;05BC +dagger;2020 +daggerdbl;2021 +dagujarati;0AA6 +dagurmukhi;0A26 +dahiragana;3060 +dakatakana;30C0 +dalarabic;062F +dalet;05D3 +daletdagesh;FB33 +daletdageshhebrew;FB33 +dalethatafpatah;05D3 05B2 +dalethatafpatahhebrew;05D3 05B2 +dalethatafsegol;05D3 05B1 +dalethatafsegolhebrew;05D3 05B1 +dalethebrew;05D3 +dalethiriq;05D3 05B4 +dalethiriqhebrew;05D3 05B4 +daletholam;05D3 05B9 +daletholamhebrew;05D3 05B9 +daletpatah;05D3 05B7 +daletpatahhebrew;05D3 05B7 +daletqamats;05D3 05B8 +daletqamatshebrew;05D3 05B8 +daletqubuts;05D3 05BB +daletqubutshebrew;05D3 05BB +daletsegol;05D3 05B6 +daletsegolhebrew;05D3 05B6 +daletsheva;05D3 05B0 +daletshevahebrew;05D3 05B0 +dalettsere;05D3 05B5 +dalettserehebrew;05D3 05B5 +dalfinalarabic;FEAA +dammaarabic;064F +dammalowarabic;064F +dammatanaltonearabic;064C +dammatanarabic;064C +danda;0964 +dargahebrew;05A7 +dargalefthebrew;05A7 +dasiapneumatacyrilliccmb;0485 +dblGrave;F6D3 +dblanglebracketleft;300A +dblanglebracketleftvertical;FE3D +dblanglebracketright;300B +dblanglebracketrightvertical;FE3E +dblarchinvertedbelowcmb;032B +dblarrowleft;21D4 +dblarrowright;21D2 +dbldanda;0965 +dblgrave;F6D6 +dblgravecmb;030F +dblintegral;222C +dbllowline;2017 +dbllowlinecmb;0333 +dbloverlinecmb;033F +dblprimemod;02BA +dblverticalbar;2016 +dblverticallineabovecmb;030E +dbopomofo;3109 +dbsquare;33C8 +dcaron;010F +dcedilla;1E11 +dcircle;24D3 +dcircumflexbelow;1E13 +dcroat;0111 +ddabengali;09A1 +ddadeva;0921 +ddagujarati;0AA1 +ddagurmukhi;0A21 +ddalarabic;0688 +ddalfinalarabic;FB89 +dddhadeva;095C +ddhabengali;09A2 +ddhadeva;0922 +ddhagujarati;0AA2 +ddhagurmukhi;0A22 +ddotaccent;1E0B +ddotbelow;1E0D +decimalseparatorarabic;066B +decimalseparatorpersian;066B +decyrillic;0434 +degree;00B0 +dehihebrew;05AD +dehiragana;3067 +deicoptic;03EF +dekatakana;30C7 +deleteleft;232B +deleteright;2326 +delta;03B4 +deltaturned;018D +denominatorminusonenumeratorbengali;09F8 +dezh;02A4 +dhabengali;09A7 +dhadeva;0927 +dhagujarati;0AA7 +dhagurmukhi;0A27 +dhook;0257 +dialytikatonos;0385 +dialytikatonoscmb;0344 +diamond;2666 +diamondsuitwhite;2662 +dieresis;00A8 +dieresisacute;F6D7 +dieresisbelowcmb;0324 +dieresiscmb;0308 +dieresisgrave;F6D8 +dieresistonos;0385 +dihiragana;3062 +dikatakana;30C2 +dittomark;3003 +divide;00F7 +divides;2223 +divisionslash;2215 +djecyrillic;0452 +dkshade;2593 +dlinebelow;1E0F +dlsquare;3397 +dmacron;0111 +dmonospace;FF44 +dnblock;2584 +dochadathai;0E0E +dodekthai;0E14 +dohiragana;3069 +dokatakana;30C9 +dollar;0024 +dollarinferior;F6E3 +dollarmonospace;FF04 +dollaroldstyle;F724 +dollarsmall;FE69 +dollarsuperior;F6E4 +dong;20AB +dorusquare;3326 +dotaccent;02D9 +dotaccentcmb;0307 +dotbelowcmb;0323 +dotbelowcomb;0323 +dotkatakana;30FB +dotlessi;0131 +dotlessj;F6BE +dotlessjstrokehook;0284 +dotmath;22C5 +dottedcircle;25CC +doubleyodpatah;FB1F +doubleyodpatahhebrew;FB1F +downtackbelowcmb;031E +downtackmod;02D5 +dparen;249F +dsuperior;F6EB +dtail;0256 +dtopbar;018C +duhiragana;3065 +dukatakana;30C5 +dz;01F3 +dzaltone;02A3 +dzcaron;01C6 +dzcurl;02A5 +dzeabkhasiancyrillic;04E1 +dzecyrillic;0455 +dzhecyrillic;045F +e;0065 +eacute;00E9 +earth;2641 +ebengali;098F +ebopomofo;311C +ebreve;0115 +ecandradeva;090D +ecandragujarati;0A8D +ecandravowelsigndeva;0945 +ecandravowelsigngujarati;0AC5 +ecaron;011B +ecedillabreve;1E1D +echarmenian;0565 +echyiwnarmenian;0587 +ecircle;24D4 +ecircumflex;00EA +ecircumflexacute;1EBF +ecircumflexbelow;1E19 +ecircumflexdotbelow;1EC7 +ecircumflexgrave;1EC1 +ecircumflexhookabove;1EC3 +ecircumflextilde;1EC5 +ecyrillic;0454 +edblgrave;0205 +edeva;090F +edieresis;00EB +edot;0117 +edotaccent;0117 +edotbelow;1EB9 +eegurmukhi;0A0F +eematragurmukhi;0A47 +efcyrillic;0444 +egrave;00E8 +egujarati;0A8F +eharmenian;0567 +ehbopomofo;311D +ehiragana;3048 +ehookabove;1EBB +eibopomofo;311F +eight;0038 +eightarabic;0668 +eightbengali;09EE +eightcircle;2467 +eightcircleinversesansserif;2791 +eightdeva;096E +eighteencircle;2471 +eighteenparen;2485 +eighteenperiod;2499 +eightgujarati;0AEE +eightgurmukhi;0A6E +eighthackarabic;0668 +eighthangzhou;3028 +eighthnotebeamed;266B +eightideographicparen;3227 +eightinferior;2088 +eightmonospace;FF18 +eightoldstyle;F738 +eightparen;247B +eightperiod;248F +eightpersian;06F8 +eightroman;2177 +eightsuperior;2078 +eightthai;0E58 +einvertedbreve;0207 +eiotifiedcyrillic;0465 +ekatakana;30A8 +ekatakanahalfwidth;FF74 +ekonkargurmukhi;0A74 +ekorean;3154 +elcyrillic;043B +element;2208 +elevencircle;246A +elevenparen;247E +elevenperiod;2492 +elevenroman;217A +ellipsis;2026 +ellipsisvertical;22EE +emacron;0113 +emacronacute;1E17 +emacrongrave;1E15 +emcyrillic;043C +emdash;2014 +emdashvertical;FE31 +emonospace;FF45 +emphasismarkarmenian;055B +emptyset;2205 +enbopomofo;3123 +encyrillic;043D +endash;2013 +endashvertical;FE32 +endescendercyrillic;04A3 +eng;014B +engbopomofo;3125 +enghecyrillic;04A5 +enhookcyrillic;04C8 +enspace;2002 +eogonek;0119 +eokorean;3153 +eopen;025B +eopenclosed;029A +eopenreversed;025C +eopenreversedclosed;025E +eopenreversedhook;025D +eparen;24A0 +epsilon;03B5 +epsilontonos;03AD +equal;003D +equalmonospace;FF1D +equalsmall;FE66 +equalsuperior;207C +equivalence;2261 +erbopomofo;3126 +ercyrillic;0440 +ereversed;0258 +ereversedcyrillic;044D +escyrillic;0441 +esdescendercyrillic;04AB +esh;0283 +eshcurl;0286 +eshortdeva;090E +eshortvowelsigndeva;0946 +eshreversedloop;01AA +eshsquatreversed;0285 +esmallhiragana;3047 +esmallkatakana;30A7 +esmallkatakanahalfwidth;FF6A +estimated;212E +esuperior;F6EC +eta;03B7 +etarmenian;0568 +etatonos;03AE +eth;00F0 +etilde;1EBD +etildebelow;1E1B +etnahtafoukhhebrew;0591 +etnahtafoukhlefthebrew;0591 +etnahtahebrew;0591 +etnahtalefthebrew;0591 +eturned;01DD +eukorean;3161 +euro;20AC +evowelsignbengali;09C7 +evowelsigndeva;0947 +evowelsigngujarati;0AC7 +exclam;0021 +exclamarmenian;055C +exclamdbl;203C +exclamdown;00A1 +exclamdownsmall;F7A1 +exclammonospace;FF01 +exclamsmall;F721 +existential;2203 +ezh;0292 +ezhcaron;01EF +ezhcurl;0293 +ezhreversed;01B9 +ezhtail;01BA +f;0066 +fadeva;095E +fagurmukhi;0A5E +fahrenheit;2109 +fathaarabic;064E +fathalowarabic;064E +fathatanarabic;064B +fbopomofo;3108 +fcircle;24D5 +fdotaccent;1E1F +feharabic;0641 +feharmenian;0586 +fehfinalarabic;FED2 +fehinitialarabic;FED3 +fehmedialarabic;FED4 +feicoptic;03E5 +female;2640 +ff;FB00 +ffi;FB03 +ffl;FB04 +fi;FB01 +fifteencircle;246E +fifteenparen;2482 +fifteenperiod;2496 +figuredash;2012 +filledbox;25A0 +filledrect;25AC +finalkaf;05DA +finalkafdagesh;FB3A +finalkafdageshhebrew;FB3A +finalkafhebrew;05DA +finalkafqamats;05DA 05B8 +finalkafqamatshebrew;05DA 05B8 +finalkafsheva;05DA 05B0 +finalkafshevahebrew;05DA 05B0 +finalmem;05DD +finalmemhebrew;05DD +finalnun;05DF +finalnunhebrew;05DF +finalpe;05E3 +finalpehebrew;05E3 +finaltsadi;05E5 +finaltsadihebrew;05E5 +firsttonechinese;02C9 +fisheye;25C9 +fitacyrillic;0473 +five;0035 +fivearabic;0665 +fivebengali;09EB +fivecircle;2464 +fivecircleinversesansserif;278E +fivedeva;096B +fiveeighths;215D +fivegujarati;0AEB +fivegurmukhi;0A6B +fivehackarabic;0665 +fivehangzhou;3025 +fiveideographicparen;3224 +fiveinferior;2085 +fivemonospace;FF15 +fiveoldstyle;F735 +fiveparen;2478 +fiveperiod;248C +fivepersian;06F5 +fiveroman;2174 +fivesuperior;2075 +fivethai;0E55 +fl;FB02 +florin;0192 +fmonospace;FF46 +fmsquare;3399 +fofanthai;0E1F +fofathai;0E1D +fongmanthai;0E4F +forall;2200 +four;0034 +fourarabic;0664 +fourbengali;09EA +fourcircle;2463 +fourcircleinversesansserif;278D +fourdeva;096A +fourgujarati;0AEA +fourgurmukhi;0A6A +fourhackarabic;0664 +fourhangzhou;3024 +fourideographicparen;3223 +fourinferior;2084 +fourmonospace;FF14 +fournumeratorbengali;09F7 +fouroldstyle;F734 +fourparen;2477 +fourperiod;248B +fourpersian;06F4 +fourroman;2173 +foursuperior;2074 +fourteencircle;246D +fourteenparen;2481 +fourteenperiod;2495 +fourthai;0E54 +fourthtonechinese;02CB +fparen;24A1 +fraction;2044 +franc;20A3 +g;0067 +gabengali;0997 +gacute;01F5 +gadeva;0917 +gafarabic;06AF +gaffinalarabic;FB93 +gafinitialarabic;FB94 +gafmedialarabic;FB95 +gagujarati;0A97 +gagurmukhi;0A17 +gahiragana;304C +gakatakana;30AC +gamma;03B3 +gammalatinsmall;0263 +gammasuperior;02E0 +gangiacoptic;03EB +gbopomofo;310D +gbreve;011F +gcaron;01E7 +gcedilla;0123 +gcircle;24D6 +gcircumflex;011D +gcommaaccent;0123 +gdot;0121 +gdotaccent;0121 +gecyrillic;0433 +gehiragana;3052 +gekatakana;30B2 +geometricallyequal;2251 +gereshaccenthebrew;059C +gereshhebrew;05F3 +gereshmuqdamhebrew;059D +germandbls;00DF +gershayimaccenthebrew;059E +gershayimhebrew;05F4 +getamark;3013 +ghabengali;0998 +ghadarmenian;0572 +ghadeva;0918 +ghagujarati;0A98 +ghagurmukhi;0A18 +ghainarabic;063A +ghainfinalarabic;FECE +ghaininitialarabic;FECF +ghainmedialarabic;FED0 +ghemiddlehookcyrillic;0495 +ghestrokecyrillic;0493 +gheupturncyrillic;0491 +ghhadeva;095A +ghhagurmukhi;0A5A +ghook;0260 +ghzsquare;3393 +gihiragana;304E +gikatakana;30AE +gimarmenian;0563 +gimel;05D2 +gimeldagesh;FB32 +gimeldageshhebrew;FB32 +gimelhebrew;05D2 +gjecyrillic;0453 +glottalinvertedstroke;01BE +glottalstop;0294 +glottalstopinverted;0296 +glottalstopmod;02C0 +glottalstopreversed;0295 +glottalstopreversedmod;02C1 +glottalstopreversedsuperior;02E4 +glottalstopstroke;02A1 +glottalstopstrokereversed;02A2 +gmacron;1E21 +gmonospace;FF47 +gohiragana;3054 +gokatakana;30B4 +gparen;24A2 +gpasquare;33AC +gradient;2207 +grave;0060 +gravebelowcmb;0316 +gravecmb;0300 +gravecomb;0300 +gravedeva;0953 +gravelowmod;02CE +gravemonospace;FF40 +gravetonecmb;0340 +greater;003E +greaterequal;2265 +greaterequalorless;22DB +greatermonospace;FF1E +greaterorequivalent;2273 +greaterorless;2277 +greateroverequal;2267 +greatersmall;FE65 +gscript;0261 +gstroke;01E5 +guhiragana;3050 +guillemotleft;00AB +guillemotright;00BB +guilsinglleft;2039 +guilsinglright;203A +gukatakana;30B0 +guramusquare;3318 +gysquare;33C9 +h;0068 +haabkhasiancyrillic;04A9 +haaltonearabic;06C1 +habengali;09B9 +hadescendercyrillic;04B3 +hadeva;0939 +hagujarati;0AB9 +hagurmukhi;0A39 +haharabic;062D +hahfinalarabic;FEA2 +hahinitialarabic;FEA3 +hahiragana;306F +hahmedialarabic;FEA4 +haitusquare;332A +hakatakana;30CF +hakatakanahalfwidth;FF8A +halantgurmukhi;0A4D +hamzaarabic;0621 +hamzadammaarabic;0621 064F +hamzadammatanarabic;0621 064C +hamzafathaarabic;0621 064E +hamzafathatanarabic;0621 064B +hamzalowarabic;0621 +hamzalowkasraarabic;0621 0650 +hamzalowkasratanarabic;0621 064D +hamzasukunarabic;0621 0652 +hangulfiller;3164 +hardsigncyrillic;044A +harpoonleftbarbup;21BC +harpoonrightbarbup;21C0 +hasquare;33CA +hatafpatah;05B2 +hatafpatah16;05B2 +hatafpatah23;05B2 +hatafpatah2f;05B2 +hatafpatahhebrew;05B2 +hatafpatahnarrowhebrew;05B2 +hatafpatahquarterhebrew;05B2 +hatafpatahwidehebrew;05B2 +hatafqamats;05B3 +hatafqamats1b;05B3 +hatafqamats28;05B3 +hatafqamats34;05B3 +hatafqamatshebrew;05B3 +hatafqamatsnarrowhebrew;05B3 +hatafqamatsquarterhebrew;05B3 +hatafqamatswidehebrew;05B3 +hatafsegol;05B1 +hatafsegol17;05B1 +hatafsegol24;05B1 +hatafsegol30;05B1 +hatafsegolhebrew;05B1 +hatafsegolnarrowhebrew;05B1 +hatafsegolquarterhebrew;05B1 +hatafsegolwidehebrew;05B1 +hbar;0127 +hbopomofo;310F +hbrevebelow;1E2B +hcedilla;1E29 +hcircle;24D7 +hcircumflex;0125 +hdieresis;1E27 +hdotaccent;1E23 +hdotbelow;1E25 +he;05D4 +heart;2665 +heartsuitblack;2665 +heartsuitwhite;2661 +hedagesh;FB34 +hedageshhebrew;FB34 +hehaltonearabic;06C1 +heharabic;0647 +hehebrew;05D4 +hehfinalaltonearabic;FBA7 +hehfinalalttwoarabic;FEEA +hehfinalarabic;FEEA +hehhamzaabovefinalarabic;FBA5 +hehhamzaaboveisolatedarabic;FBA4 +hehinitialaltonearabic;FBA8 +hehinitialarabic;FEEB +hehiragana;3078 +hehmedialaltonearabic;FBA9 +hehmedialarabic;FEEC +heiseierasquare;337B +hekatakana;30D8 +hekatakanahalfwidth;FF8D +hekutaarusquare;3336 +henghook;0267 +herutusquare;3339 +het;05D7 +hethebrew;05D7 +hhook;0266 +hhooksuperior;02B1 +hieuhacirclekorean;327B +hieuhaparenkorean;321B +hieuhcirclekorean;326D +hieuhkorean;314E +hieuhparenkorean;320D +hihiragana;3072 +hikatakana;30D2 +hikatakanahalfwidth;FF8B +hiriq;05B4 +hiriq14;05B4 +hiriq21;05B4 +hiriq2d;05B4 +hiriqhebrew;05B4 +hiriqnarrowhebrew;05B4 +hiriqquarterhebrew;05B4 +hiriqwidehebrew;05B4 +hlinebelow;1E96 +hmonospace;FF48 +hoarmenian;0570 +hohipthai;0E2B +hohiragana;307B +hokatakana;30DB +hokatakanahalfwidth;FF8E +holam;05B9 +holam19;05B9 +holam26;05B9 +holam32;05B9 +holamhebrew;05B9 +holamnarrowhebrew;05B9 +holamquarterhebrew;05B9 +holamwidehebrew;05B9 +honokhukthai;0E2E +hookabovecomb;0309 +hookcmb;0309 +hookpalatalizedbelowcmb;0321 +hookretroflexbelowcmb;0322 +hoonsquare;3342 +horicoptic;03E9 +horizontalbar;2015 +horncmb;031B +hotsprings;2668 +house;2302 +hparen;24A3 +hsuperior;02B0 +hturned;0265 +huhiragana;3075 +huiitosquare;3333 +hukatakana;30D5 +hukatakanahalfwidth;FF8C +hungarumlaut;02DD +hungarumlautcmb;030B +hv;0195 +hyphen;002D +hypheninferior;F6E5 +hyphenmonospace;FF0D +hyphensmall;FE63 +hyphensuperior;F6E6 +hyphentwo;2010 +i;0069 +iacute;00ED +iacyrillic;044F +ibengali;0987 +ibopomofo;3127 +ibreve;012D +icaron;01D0 +icircle;24D8 +icircumflex;00EE +icyrillic;0456 +idblgrave;0209 +ideographearthcircle;328F +ideographfirecircle;328B +ideographicallianceparen;323F +ideographiccallparen;323A +ideographiccentrecircle;32A5 +ideographicclose;3006 +ideographiccomma;3001 +ideographiccommaleft;FF64 +ideographiccongratulationparen;3237 +ideographiccorrectcircle;32A3 +ideographicearthparen;322F +ideographicenterpriseparen;323D +ideographicexcellentcircle;329D +ideographicfestivalparen;3240 +ideographicfinancialcircle;3296 +ideographicfinancialparen;3236 +ideographicfireparen;322B +ideographichaveparen;3232 +ideographichighcircle;32A4 +ideographiciterationmark;3005 +ideographiclaborcircle;3298 +ideographiclaborparen;3238 +ideographicleftcircle;32A7 +ideographiclowcircle;32A6 +ideographicmedicinecircle;32A9 +ideographicmetalparen;322E +ideographicmoonparen;322A +ideographicnameparen;3234 +ideographicperiod;3002 +ideographicprintcircle;329E +ideographicreachparen;3243 +ideographicrepresentparen;3239 +ideographicresourceparen;323E +ideographicrightcircle;32A8 +ideographicsecretcircle;3299 +ideographicselfparen;3242 +ideographicsocietyparen;3233 +ideographicspace;3000 +ideographicspecialparen;3235 +ideographicstockparen;3231 +ideographicstudyparen;323B +ideographicsunparen;3230 +ideographicsuperviseparen;323C +ideographicwaterparen;322C +ideographicwoodparen;322D +ideographiczero;3007 +ideographmetalcircle;328E +ideographmooncircle;328A +ideographnamecircle;3294 +ideographsuncircle;3290 +ideographwatercircle;328C +ideographwoodcircle;328D +ideva;0907 +idieresis;00EF +idieresisacute;1E2F +idieresiscyrillic;04E5 +idotbelow;1ECB +iebrevecyrillic;04D7 +iecyrillic;0435 +ieungacirclekorean;3275 +ieungaparenkorean;3215 +ieungcirclekorean;3267 +ieungkorean;3147 +ieungparenkorean;3207 +igrave;00EC +igujarati;0A87 +igurmukhi;0A07 +ihiragana;3044 +ihookabove;1EC9 +iibengali;0988 +iicyrillic;0438 +iideva;0908 +iigujarati;0A88 +iigurmukhi;0A08 +iimatragurmukhi;0A40 +iinvertedbreve;020B +iishortcyrillic;0439 +iivowelsignbengali;09C0 +iivowelsigndeva;0940 +iivowelsigngujarati;0AC0 +ij;0133 +ikatakana;30A4 +ikatakanahalfwidth;FF72 +ikorean;3163 +ilde;02DC +iluyhebrew;05AC +imacron;012B +imacroncyrillic;04E3 +imageorapproximatelyequal;2253 +imatragurmukhi;0A3F +imonospace;FF49 +increment;2206 +infinity;221E +iniarmenian;056B +integral;222B +integralbottom;2321 +integralbt;2321 +integralex;F8F5 +integraltop;2320 +integraltp;2320 +intersection;2229 +intisquare;3305 +invbullet;25D8 +invcircle;25D9 +invsmileface;263B +iocyrillic;0451 +iogonek;012F +iota;03B9 +iotadieresis;03CA +iotadieresistonos;0390 +iotalatin;0269 +iotatonos;03AF +iparen;24A4 +irigurmukhi;0A72 +ismallhiragana;3043 +ismallkatakana;30A3 +ismallkatakanahalfwidth;FF68 +issharbengali;09FA +istroke;0268 +isuperior;F6ED +iterationhiragana;309D +iterationkatakana;30FD +itilde;0129 +itildebelow;1E2D +iubopomofo;3129 +iucyrillic;044E +ivowelsignbengali;09BF +ivowelsigndeva;093F +ivowelsigngujarati;0ABF +izhitsacyrillic;0475 +izhitsadblgravecyrillic;0477 +j;006A +jaarmenian;0571 +jabengali;099C +jadeva;091C +jagujarati;0A9C +jagurmukhi;0A1C +jbopomofo;3110 +jcaron;01F0 +jcircle;24D9 +jcircumflex;0135 +jcrossedtail;029D +jdotlessstroke;025F +jecyrillic;0458 +jeemarabic;062C +jeemfinalarabic;FE9E +jeeminitialarabic;FE9F +jeemmedialarabic;FEA0 +jeharabic;0698 +jehfinalarabic;FB8B +jhabengali;099D +jhadeva;091D +jhagujarati;0A9D +jhagurmukhi;0A1D +jheharmenian;057B +jis;3004 +jmonospace;FF4A +jparen;24A5 +jsuperior;02B2 +k;006B +kabashkircyrillic;04A1 +kabengali;0995 +kacute;1E31 +kacyrillic;043A +kadescendercyrillic;049B +kadeva;0915 +kaf;05DB +kafarabic;0643 +kafdagesh;FB3B +kafdageshhebrew;FB3B +kaffinalarabic;FEDA +kafhebrew;05DB +kafinitialarabic;FEDB +kafmedialarabic;FEDC +kafrafehebrew;FB4D +kagujarati;0A95 +kagurmukhi;0A15 +kahiragana;304B +kahookcyrillic;04C4 +kakatakana;30AB +kakatakanahalfwidth;FF76 +kappa;03BA +kappasymbolgreek;03F0 +kapyeounmieumkorean;3171 +kapyeounphieuphkorean;3184 +kapyeounpieupkorean;3178 +kapyeounssangpieupkorean;3179 +karoriisquare;330D +kashidaautoarabic;0640 +kashidaautonosidebearingarabic;0640 +kasmallkatakana;30F5 +kasquare;3384 +kasraarabic;0650 +kasratanarabic;064D +kastrokecyrillic;049F +katahiraprolongmarkhalfwidth;FF70 +kaverticalstrokecyrillic;049D +kbopomofo;310E +kcalsquare;3389 +kcaron;01E9 +kcedilla;0137 +kcircle;24DA +kcommaaccent;0137 +kdotbelow;1E33 +keharmenian;0584 +kehiragana;3051 +kekatakana;30B1 +kekatakanahalfwidth;FF79 +kenarmenian;056F +kesmallkatakana;30F6 +kgreenlandic;0138 +khabengali;0996 +khacyrillic;0445 +khadeva;0916 +khagujarati;0A96 +khagurmukhi;0A16 +khaharabic;062E +khahfinalarabic;FEA6 +khahinitialarabic;FEA7 +khahmedialarabic;FEA8 +kheicoptic;03E7 +khhadeva;0959 +khhagurmukhi;0A59 +khieukhacirclekorean;3278 +khieukhaparenkorean;3218 +khieukhcirclekorean;326A +khieukhkorean;314B +khieukhparenkorean;320A +khokhaithai;0E02 +khokhonthai;0E05 +khokhuatthai;0E03 +khokhwaithai;0E04 +khomutthai;0E5B +khook;0199 +khorakhangthai;0E06 +khzsquare;3391 +kihiragana;304D +kikatakana;30AD +kikatakanahalfwidth;FF77 +kiroguramusquare;3315 +kiromeetorusquare;3316 +kirosquare;3314 +kiyeokacirclekorean;326E +kiyeokaparenkorean;320E +kiyeokcirclekorean;3260 +kiyeokkorean;3131 +kiyeokparenkorean;3200 +kiyeoksioskorean;3133 +kjecyrillic;045C +klinebelow;1E35 +klsquare;3398 +kmcubedsquare;33A6 +kmonospace;FF4B +kmsquaredsquare;33A2 +kohiragana;3053 +kohmsquare;33C0 +kokaithai;0E01 +kokatakana;30B3 +kokatakanahalfwidth;FF7A +kooposquare;331E +koppacyrillic;0481 +koreanstandardsymbol;327F +koroniscmb;0343 +kparen;24A6 +kpasquare;33AA +ksicyrillic;046F +ktsquare;33CF +kturned;029E +kuhiragana;304F +kukatakana;30AF +kukatakanahalfwidth;FF78 +kvsquare;33B8 +kwsquare;33BE +l;006C +labengali;09B2 +lacute;013A +ladeva;0932 +lagujarati;0AB2 +lagurmukhi;0A32 +lakkhangyaothai;0E45 +lamaleffinalarabic;FEFC +lamalefhamzaabovefinalarabic;FEF8 +lamalefhamzaaboveisolatedarabic;FEF7 +lamalefhamzabelowfinalarabic;FEFA +lamalefhamzabelowisolatedarabic;FEF9 +lamalefisolatedarabic;FEFB +lamalefmaddaabovefinalarabic;FEF6 +lamalefmaddaaboveisolatedarabic;FEF5 +lamarabic;0644 +lambda;03BB +lambdastroke;019B +lamed;05DC +lameddagesh;FB3C +lameddageshhebrew;FB3C +lamedhebrew;05DC +lamedholam;05DC 05B9 +lamedholamdagesh;05DC 05B9 05BC +lamedholamdageshhebrew;05DC 05B9 05BC +lamedholamhebrew;05DC 05B9 +lamfinalarabic;FEDE +lamhahinitialarabic;FCCA +laminitialarabic;FEDF +lamjeeminitialarabic;FCC9 +lamkhahinitialarabic;FCCB +lamlamhehisolatedarabic;FDF2 +lammedialarabic;FEE0 +lammeemhahinitialarabic;FD88 +lammeeminitialarabic;FCCC +lammeemjeeminitialarabic;FEDF FEE4 FEA0 +lammeemkhahinitialarabic;FEDF FEE4 FEA8 +largecircle;25EF +lbar;019A +lbelt;026C +lbopomofo;310C +lcaron;013E +lcedilla;013C +lcircle;24DB +lcircumflexbelow;1E3D +lcommaaccent;013C +ldot;0140 +ldotaccent;0140 +ldotbelow;1E37 +ldotbelowmacron;1E39 +leftangleabovecmb;031A +lefttackbelowcmb;0318 +less;003C +lessequal;2264 +lessequalorgreater;22DA +lessmonospace;FF1C +lessorequivalent;2272 +lessorgreater;2276 +lessoverequal;2266 +lesssmall;FE64 +lezh;026E +lfblock;258C +lhookretroflex;026D +lira;20A4 +liwnarmenian;056C +lj;01C9 +ljecyrillic;0459 +ll;F6C0 +lladeva;0933 +llagujarati;0AB3 +llinebelow;1E3B +llladeva;0934 +llvocalicbengali;09E1 +llvocalicdeva;0961 +llvocalicvowelsignbengali;09E3 +llvocalicvowelsigndeva;0963 +lmiddletilde;026B +lmonospace;FF4C +lmsquare;33D0 +lochulathai;0E2C +logicaland;2227 +logicalnot;00AC +logicalnotreversed;2310 +logicalor;2228 +lolingthai;0E25 +longs;017F +lowlinecenterline;FE4E +lowlinecmb;0332 +lowlinedashed;FE4D +lozenge;25CA +lparen;24A7 +lslash;0142 +lsquare;2113 +lsuperior;F6EE +ltshade;2591 +luthai;0E26 +lvocalicbengali;098C +lvocalicdeva;090C +lvocalicvowelsignbengali;09E2 +lvocalicvowelsigndeva;0962 +lxsquare;33D3 +m;006D +mabengali;09AE +macron;00AF +macronbelowcmb;0331 +macroncmb;0304 +macronlowmod;02CD +macronmonospace;FFE3 +macute;1E3F +madeva;092E +magujarati;0AAE +magurmukhi;0A2E +mahapakhhebrew;05A4 +mahapakhlefthebrew;05A4 +mahiragana;307E +maichattawalowleftthai;F895 +maichattawalowrightthai;F894 +maichattawathai;0E4B +maichattawaupperleftthai;F893 +maieklowleftthai;F88C +maieklowrightthai;F88B +maiekthai;0E48 +maiekupperleftthai;F88A +maihanakatleftthai;F884 +maihanakatthai;0E31 +maitaikhuleftthai;F889 +maitaikhuthai;0E47 +maitholowleftthai;F88F +maitholowrightthai;F88E +maithothai;0E49 +maithoupperleftthai;F88D +maitrilowleftthai;F892 +maitrilowrightthai;F891 +maitrithai;0E4A +maitriupperleftthai;F890 +maiyamokthai;0E46 +makatakana;30DE +makatakanahalfwidth;FF8F +male;2642 +mansyonsquare;3347 +maqafhebrew;05BE +mars;2642 +masoracirclehebrew;05AF +masquare;3383 +mbopomofo;3107 +mbsquare;33D4 +mcircle;24DC +mcubedsquare;33A5 +mdotaccent;1E41 +mdotbelow;1E43 +meemarabic;0645 +meemfinalarabic;FEE2 +meeminitialarabic;FEE3 +meemmedialarabic;FEE4 +meemmeeminitialarabic;FCD1 +meemmeemisolatedarabic;FC48 +meetorusquare;334D +mehiragana;3081 +meizierasquare;337E +mekatakana;30E1 +mekatakanahalfwidth;FF92 +mem;05DE +memdagesh;FB3E +memdageshhebrew;FB3E +memhebrew;05DE +menarmenian;0574 +merkhahebrew;05A5 +merkhakefulahebrew;05A6 +merkhakefulalefthebrew;05A6 +merkhalefthebrew;05A5 +mhook;0271 +mhzsquare;3392 +middledotkatakanahalfwidth;FF65 +middot;00B7 +mieumacirclekorean;3272 +mieumaparenkorean;3212 +mieumcirclekorean;3264 +mieumkorean;3141 +mieumpansioskorean;3170 +mieumparenkorean;3204 +mieumpieupkorean;316E +mieumsioskorean;316F +mihiragana;307F +mikatakana;30DF +mikatakanahalfwidth;FF90 +minus;2212 +minusbelowcmb;0320 +minuscircle;2296 +minusmod;02D7 +minusplus;2213 +minute;2032 +miribaarusquare;334A +mirisquare;3349 +mlonglegturned;0270 +mlsquare;3396 +mmcubedsquare;33A3 +mmonospace;FF4D +mmsquaredsquare;339F +mohiragana;3082 +mohmsquare;33C1 +mokatakana;30E2 +mokatakanahalfwidth;FF93 +molsquare;33D6 +momathai;0E21 +moverssquare;33A7 +moverssquaredsquare;33A8 +mparen;24A8 +mpasquare;33AB +mssquare;33B3 +msuperior;F6EF +mturned;026F +mu;00B5 +mu1;00B5 +muasquare;3382 +muchgreater;226B +muchless;226A +mufsquare;338C +mugreek;03BC +mugsquare;338D +muhiragana;3080 +mukatakana;30E0 +mukatakanahalfwidth;FF91 +mulsquare;3395 +multiply;00D7 +mumsquare;339B +munahhebrew;05A3 +munahlefthebrew;05A3 +musicalnote;266A +musicalnotedbl;266B +musicflatsign;266D +musicsharpsign;266F +mussquare;33B2 +muvsquare;33B6 +muwsquare;33BC +mvmegasquare;33B9 +mvsquare;33B7 +mwmegasquare;33BF +mwsquare;33BD +n;006E +nabengali;09A8 +nabla;2207 +nacute;0144 +nadeva;0928 +nagujarati;0AA8 +nagurmukhi;0A28 +nahiragana;306A +nakatakana;30CA +nakatakanahalfwidth;FF85 +napostrophe;0149 +nasquare;3381 +nbopomofo;310B +nbspace;00A0 +ncaron;0148 +ncedilla;0146 +ncircle;24DD +ncircumflexbelow;1E4B +ncommaaccent;0146 +ndotaccent;1E45 +ndotbelow;1E47 +nehiragana;306D +nekatakana;30CD +nekatakanahalfwidth;FF88 +newsheqelsign;20AA +nfsquare;338B +ngabengali;0999 +ngadeva;0919 +ngagujarati;0A99 +ngagurmukhi;0A19 +ngonguthai;0E07 +nhiragana;3093 +nhookleft;0272 +nhookretroflex;0273 +nieunacirclekorean;326F +nieunaparenkorean;320F +nieuncieuckorean;3135 +nieuncirclekorean;3261 +nieunhieuhkorean;3136 +nieunkorean;3134 +nieunpansioskorean;3168 +nieunparenkorean;3201 +nieunsioskorean;3167 +nieuntikeutkorean;3166 +nihiragana;306B +nikatakana;30CB +nikatakanahalfwidth;FF86 +nikhahitleftthai;F899 +nikhahitthai;0E4D +nine;0039 +ninearabic;0669 +ninebengali;09EF +ninecircle;2468 +ninecircleinversesansserif;2792 +ninedeva;096F +ninegujarati;0AEF +ninegurmukhi;0A6F +ninehackarabic;0669 +ninehangzhou;3029 +nineideographicparen;3228 +nineinferior;2089 +ninemonospace;FF19 +nineoldstyle;F739 +nineparen;247C +nineperiod;2490 +ninepersian;06F9 +nineroman;2178 +ninesuperior;2079 +nineteencircle;2472 +nineteenparen;2486 +nineteenperiod;249A +ninethai;0E59 +nj;01CC +njecyrillic;045A +nkatakana;30F3 +nkatakanahalfwidth;FF9D +nlegrightlong;019E +nlinebelow;1E49 +nmonospace;FF4E +nmsquare;339A +nnabengali;09A3 +nnadeva;0923 +nnagujarati;0AA3 +nnagurmukhi;0A23 +nnnadeva;0929 +nohiragana;306E +nokatakana;30CE +nokatakanahalfwidth;FF89 +nonbreakingspace;00A0 +nonenthai;0E13 +nonuthai;0E19 +noonarabic;0646 +noonfinalarabic;FEE6 +noonghunnaarabic;06BA +noonghunnafinalarabic;FB9F +noonhehinitialarabic;FEE7 FEEC +nooninitialarabic;FEE7 +noonjeeminitialarabic;FCD2 +noonjeemisolatedarabic;FC4B +noonmedialarabic;FEE8 +noonmeeminitialarabic;FCD5 +noonmeemisolatedarabic;FC4E +noonnoonfinalarabic;FC8D +notcontains;220C +notelement;2209 +notelementof;2209 +notequal;2260 +notgreater;226F +notgreaternorequal;2271 +notgreaternorless;2279 +notidentical;2262 +notless;226E +notlessnorequal;2270 +notparallel;2226 +notprecedes;2280 +notsubset;2284 +notsucceeds;2281 +notsuperset;2285 +nowarmenian;0576 +nparen;24A9 +nssquare;33B1 +nsuperior;207F +ntilde;00F1 +nu;03BD +nuhiragana;306C +nukatakana;30CC +nukatakanahalfwidth;FF87 +nuktabengali;09BC +nuktadeva;093C +nuktagujarati;0ABC +nuktagurmukhi;0A3C +numbersign;0023 +numbersignmonospace;FF03 +numbersignsmall;FE5F +numeralsigngreek;0374 +numeralsignlowergreek;0375 +numero;2116 +nun;05E0 +nundagesh;FB40 +nundageshhebrew;FB40 +nunhebrew;05E0 +nvsquare;33B5 +nwsquare;33BB +nyabengali;099E +nyadeva;091E +nyagujarati;0A9E +nyagurmukhi;0A1E +o;006F +oacute;00F3 +oangthai;0E2D +obarred;0275 +obarredcyrillic;04E9 +obarreddieresiscyrillic;04EB +obengali;0993 +obopomofo;311B +obreve;014F +ocandradeva;0911 +ocandragujarati;0A91 +ocandravowelsigndeva;0949 +ocandravowelsigngujarati;0AC9 +ocaron;01D2 +ocircle;24DE +ocircumflex;00F4 +ocircumflexacute;1ED1 +ocircumflexdotbelow;1ED9 +ocircumflexgrave;1ED3 +ocircumflexhookabove;1ED5 +ocircumflextilde;1ED7 +ocyrillic;043E +odblacute;0151 +odblgrave;020D +odeva;0913 +odieresis;00F6 +odieresiscyrillic;04E7 +odotbelow;1ECD +oe;0153 +oekorean;315A +ogonek;02DB +ogonekcmb;0328 +ograve;00F2 +ogujarati;0A93 +oharmenian;0585 +ohiragana;304A +ohookabove;1ECF +ohorn;01A1 +ohornacute;1EDB +ohorndotbelow;1EE3 +ohorngrave;1EDD +ohornhookabove;1EDF +ohorntilde;1EE1 +ohungarumlaut;0151 +oi;01A3 +oinvertedbreve;020F +okatakana;30AA +okatakanahalfwidth;FF75 +okorean;3157 +olehebrew;05AB +omacron;014D +omacronacute;1E53 +omacrongrave;1E51 +omdeva;0950 +omega;03C9 +omega1;03D6 +omegacyrillic;0461 +omegalatinclosed;0277 +omegaroundcyrillic;047B +omegatitlocyrillic;047D +omegatonos;03CE +omgujarati;0AD0 +omicron;03BF +omicrontonos;03CC +omonospace;FF4F +one;0031 +onearabic;0661 +onebengali;09E7 +onecircle;2460 +onecircleinversesansserif;278A +onedeva;0967 +onedotenleader;2024 +oneeighth;215B +onefitted;F6DC +onegujarati;0AE7 +onegurmukhi;0A67 +onehackarabic;0661 +onehalf;00BD +onehangzhou;3021 +oneideographicparen;3220 +oneinferior;2081 +onemonospace;FF11 +onenumeratorbengali;09F4 +oneoldstyle;F731 +oneparen;2474 +oneperiod;2488 +onepersian;06F1 +onequarter;00BC +oneroman;2170 +onesuperior;00B9 +onethai;0E51 +onethird;2153 +oogonek;01EB +oogonekmacron;01ED +oogurmukhi;0A13 +oomatragurmukhi;0A4B +oopen;0254 +oparen;24AA +openbullet;25E6 +option;2325 +ordfeminine;00AA +ordmasculine;00BA +orthogonal;221F +oshortdeva;0912 +oshortvowelsigndeva;094A +oslash;00F8 +oslashacute;01FF +osmallhiragana;3049 +osmallkatakana;30A9 +osmallkatakanahalfwidth;FF6B +ostrokeacute;01FF +osuperior;F6F0 +otcyrillic;047F +otilde;00F5 +otildeacute;1E4D +otildedieresis;1E4F +oubopomofo;3121 +overline;203E +overlinecenterline;FE4A +overlinecmb;0305 +overlinedashed;FE49 +overlinedblwavy;FE4C +overlinewavy;FE4B +overscore;00AF +ovowelsignbengali;09CB +ovowelsigndeva;094B +ovowelsigngujarati;0ACB +p;0070 +paampssquare;3380 +paasentosquare;332B +pabengali;09AA +pacute;1E55 +padeva;092A +pagedown;21DF +pageup;21DE +pagujarati;0AAA +pagurmukhi;0A2A +pahiragana;3071 +paiyannoithai;0E2F +pakatakana;30D1 +palatalizationcyrilliccmb;0484 +palochkacyrillic;04C0 +pansioskorean;317F +paragraph;00B6 +parallel;2225 +parenleft;0028 +parenleftaltonearabic;FD3E +parenleftbt;F8ED +parenleftex;F8EC +parenleftinferior;208D +parenleftmonospace;FF08 +parenleftsmall;FE59 +parenleftsuperior;207D +parenlefttp;F8EB +parenleftvertical;FE35 +parenright;0029 +parenrightaltonearabic;FD3F +parenrightbt;F8F8 +parenrightex;F8F7 +parenrightinferior;208E +parenrightmonospace;FF09 +parenrightsmall;FE5A +parenrightsuperior;207E +parenrighttp;F8F6 +parenrightvertical;FE36 +partialdiff;2202 +paseqhebrew;05C0 +pashtahebrew;0599 +pasquare;33A9 +patah;05B7 +patah11;05B7 +patah1d;05B7 +patah2a;05B7 +patahhebrew;05B7 +patahnarrowhebrew;05B7 +patahquarterhebrew;05B7 +patahwidehebrew;05B7 +pazerhebrew;05A1 +pbopomofo;3106 +pcircle;24DF +pdotaccent;1E57 +pe;05E4 +pecyrillic;043F +pedagesh;FB44 +pedageshhebrew;FB44 +peezisquare;333B +pefinaldageshhebrew;FB43 +peharabic;067E +peharmenian;057A +pehebrew;05E4 +pehfinalarabic;FB57 +pehinitialarabic;FB58 +pehiragana;307A +pehmedialarabic;FB59 +pekatakana;30DA +pemiddlehookcyrillic;04A7 +perafehebrew;FB4E +percent;0025 +percentarabic;066A +percentmonospace;FF05 +percentsmall;FE6A +period;002E +periodarmenian;0589 +periodcentered;00B7 +periodhalfwidth;FF61 +periodinferior;F6E7 +periodmonospace;FF0E +periodsmall;FE52 +periodsuperior;F6E8 +perispomenigreekcmb;0342 +perpendicular;22A5 +perthousand;2030 +peseta;20A7 +pfsquare;338A +phabengali;09AB +phadeva;092B +phagujarati;0AAB +phagurmukhi;0A2B +phi;03C6 +phi1;03D5 +phieuphacirclekorean;327A +phieuphaparenkorean;321A +phieuphcirclekorean;326C +phieuphkorean;314D +phieuphparenkorean;320C +philatin;0278 +phinthuthai;0E3A +phisymbolgreek;03D5 +phook;01A5 +phophanthai;0E1E +phophungthai;0E1C +phosamphaothai;0E20 +pi;03C0 +pieupacirclekorean;3273 +pieupaparenkorean;3213 +pieupcieuckorean;3176 +pieupcirclekorean;3265 +pieupkiyeokkorean;3172 +pieupkorean;3142 +pieupparenkorean;3205 +pieupsioskiyeokkorean;3174 +pieupsioskorean;3144 +pieupsiostikeutkorean;3175 +pieupthieuthkorean;3177 +pieuptikeutkorean;3173 +pihiragana;3074 +pikatakana;30D4 +pisymbolgreek;03D6 +piwrarmenian;0583 +plus;002B +plusbelowcmb;031F +pluscircle;2295 +plusminus;00B1 +plusmod;02D6 +plusmonospace;FF0B +plussmall;FE62 +plussuperior;207A +pmonospace;FF50 +pmsquare;33D8 +pohiragana;307D +pointingindexdownwhite;261F +pointingindexleftwhite;261C +pointingindexrightwhite;261E +pointingindexupwhite;261D +pokatakana;30DD +poplathai;0E1B +postalmark;3012 +postalmarkface;3020 +pparen;24AB +precedes;227A +prescription;211E +primemod;02B9 +primereversed;2035 +product;220F +projective;2305 +prolongedkana;30FC +propellor;2318 +propersubset;2282 +propersuperset;2283 +proportion;2237 +proportional;221D +psi;03C8 +psicyrillic;0471 +psilipneumatacyrilliccmb;0486 +pssquare;33B0 +puhiragana;3077 +pukatakana;30D7 +pvsquare;33B4 +pwsquare;33BA +q;0071 +qadeva;0958 +qadmahebrew;05A8 +qafarabic;0642 +qaffinalarabic;FED6 +qafinitialarabic;FED7 +qafmedialarabic;FED8 +qamats;05B8 +qamats10;05B8 +qamats1a;05B8 +qamats1c;05B8 +qamats27;05B8 +qamats29;05B8 +qamats33;05B8 +qamatsde;05B8 +qamatshebrew;05B8 +qamatsnarrowhebrew;05B8 +qamatsqatanhebrew;05B8 +qamatsqatannarrowhebrew;05B8 +qamatsqatanquarterhebrew;05B8 +qamatsqatanwidehebrew;05B8 +qamatsquarterhebrew;05B8 +qamatswidehebrew;05B8 +qarneyparahebrew;059F +qbopomofo;3111 +qcircle;24E0 +qhook;02A0 +qmonospace;FF51 +qof;05E7 +qofdagesh;FB47 +qofdageshhebrew;FB47 +qofhatafpatah;05E7 05B2 +qofhatafpatahhebrew;05E7 05B2 +qofhatafsegol;05E7 05B1 +qofhatafsegolhebrew;05E7 05B1 +qofhebrew;05E7 +qofhiriq;05E7 05B4 +qofhiriqhebrew;05E7 05B4 +qofholam;05E7 05B9 +qofholamhebrew;05E7 05B9 +qofpatah;05E7 05B7 +qofpatahhebrew;05E7 05B7 +qofqamats;05E7 05B8 +qofqamatshebrew;05E7 05B8 +qofqubuts;05E7 05BB +qofqubutshebrew;05E7 05BB +qofsegol;05E7 05B6 +qofsegolhebrew;05E7 05B6 +qofsheva;05E7 05B0 +qofshevahebrew;05E7 05B0 +qoftsere;05E7 05B5 +qoftserehebrew;05E7 05B5 +qparen;24AC +quarternote;2669 +qubuts;05BB +qubuts18;05BB +qubuts25;05BB +qubuts31;05BB +qubutshebrew;05BB +qubutsnarrowhebrew;05BB +qubutsquarterhebrew;05BB +qubutswidehebrew;05BB +question;003F +questionarabic;061F +questionarmenian;055E +questiondown;00BF +questiondownsmall;F7BF +questiongreek;037E +questionmonospace;FF1F +questionsmall;F73F +quotedbl;0022 +quotedblbase;201E +quotedblleft;201C +quotedblmonospace;FF02 +quotedblprime;301E +quotedblprimereversed;301D +quotedblright;201D +quoteleft;2018 +quoteleftreversed;201B +quotereversed;201B +quoteright;2019 +quoterightn;0149 +quotesinglbase;201A +quotesingle;0027 +quotesinglemonospace;FF07 +r;0072 +raarmenian;057C +rabengali;09B0 +racute;0155 +radeva;0930 +radical;221A +radicalex;F8E5 +radoverssquare;33AE +radoverssquaredsquare;33AF +radsquare;33AD +rafe;05BF +rafehebrew;05BF +ragujarati;0AB0 +ragurmukhi;0A30 +rahiragana;3089 +rakatakana;30E9 +rakatakanahalfwidth;FF97 +ralowerdiagonalbengali;09F1 +ramiddlediagonalbengali;09F0 +ramshorn;0264 +ratio;2236 +rbopomofo;3116 +rcaron;0159 +rcedilla;0157 +rcircle;24E1 +rcommaaccent;0157 +rdblgrave;0211 +rdotaccent;1E59 +rdotbelow;1E5B +rdotbelowmacron;1E5D +referencemark;203B +reflexsubset;2286 +reflexsuperset;2287 +registered;00AE +registersans;F8E8 +registerserif;F6DA +reharabic;0631 +reharmenian;0580 +rehfinalarabic;FEAE +rehiragana;308C +rehyehaleflamarabic;0631 FEF3 FE8E 0644 +rekatakana;30EC +rekatakanahalfwidth;FF9A +resh;05E8 +reshdageshhebrew;FB48 +reshhatafpatah;05E8 05B2 +reshhatafpatahhebrew;05E8 05B2 +reshhatafsegol;05E8 05B1 +reshhatafsegolhebrew;05E8 05B1 +reshhebrew;05E8 +reshhiriq;05E8 05B4 +reshhiriqhebrew;05E8 05B4 +reshholam;05E8 05B9 +reshholamhebrew;05E8 05B9 +reshpatah;05E8 05B7 +reshpatahhebrew;05E8 05B7 +reshqamats;05E8 05B8 +reshqamatshebrew;05E8 05B8 +reshqubuts;05E8 05BB +reshqubutshebrew;05E8 05BB +reshsegol;05E8 05B6 +reshsegolhebrew;05E8 05B6 +reshsheva;05E8 05B0 +reshshevahebrew;05E8 05B0 +reshtsere;05E8 05B5 +reshtserehebrew;05E8 05B5 +reversedtilde;223D +reviahebrew;0597 +reviamugrashhebrew;0597 +revlogicalnot;2310 +rfishhook;027E +rfishhookreversed;027F +rhabengali;09DD +rhadeva;095D +rho;03C1 +rhook;027D +rhookturned;027B +rhookturnedsuperior;02B5 +rhosymbolgreek;03F1 +rhotichookmod;02DE +rieulacirclekorean;3271 +rieulaparenkorean;3211 +rieulcirclekorean;3263 +rieulhieuhkorean;3140 +rieulkiyeokkorean;313A +rieulkiyeoksioskorean;3169 +rieulkorean;3139 +rieulmieumkorean;313B +rieulpansioskorean;316C +rieulparenkorean;3203 +rieulphieuphkorean;313F +rieulpieupkorean;313C +rieulpieupsioskorean;316B +rieulsioskorean;313D +rieulthieuthkorean;313E +rieultikeutkorean;316A +rieulyeorinhieuhkorean;316D +rightangle;221F +righttackbelowcmb;0319 +righttriangle;22BF +rihiragana;308A +rikatakana;30EA +rikatakanahalfwidth;FF98 +ring;02DA +ringbelowcmb;0325 +ringcmb;030A +ringhalfleft;02BF +ringhalfleftarmenian;0559 +ringhalfleftbelowcmb;031C +ringhalfleftcentered;02D3 +ringhalfright;02BE +ringhalfrightbelowcmb;0339 +ringhalfrightcentered;02D2 +rinvertedbreve;0213 +rittorusquare;3351 +rlinebelow;1E5F +rlongleg;027C +rlonglegturned;027A +rmonospace;FF52 +rohiragana;308D +rokatakana;30ED +rokatakanahalfwidth;FF9B +roruathai;0E23 +rparen;24AD +rrabengali;09DC +rradeva;0931 +rragurmukhi;0A5C +rreharabic;0691 +rrehfinalarabic;FB8D +rrvocalicbengali;09E0 +rrvocalicdeva;0960 +rrvocalicgujarati;0AE0 +rrvocalicvowelsignbengali;09C4 +rrvocalicvowelsigndeva;0944 +rrvocalicvowelsigngujarati;0AC4 +rsuperior;F6F1 +rtblock;2590 +rturned;0279 +rturnedsuperior;02B4 +ruhiragana;308B +rukatakana;30EB +rukatakanahalfwidth;FF99 +rupeemarkbengali;09F2 +rupeesignbengali;09F3 +rupiah;F6DD +ruthai;0E24 +rvocalicbengali;098B +rvocalicdeva;090B +rvocalicgujarati;0A8B +rvocalicvowelsignbengali;09C3 +rvocalicvowelsigndeva;0943 +rvocalicvowelsigngujarati;0AC3 +s;0073 +sabengali;09B8 +sacute;015B +sacutedotaccent;1E65 +sadarabic;0635 +sadeva;0938 +sadfinalarabic;FEBA +sadinitialarabic;FEBB +sadmedialarabic;FEBC +sagujarati;0AB8 +sagurmukhi;0A38 +sahiragana;3055 +sakatakana;30B5 +sakatakanahalfwidth;FF7B +sallallahoualayhewasallamarabic;FDFA +samekh;05E1 +samekhdagesh;FB41 +samekhdageshhebrew;FB41 +samekhhebrew;05E1 +saraaathai;0E32 +saraaethai;0E41 +saraaimaimalaithai;0E44 +saraaimaimuanthai;0E43 +saraamthai;0E33 +saraathai;0E30 +saraethai;0E40 +saraiileftthai;F886 +saraiithai;0E35 +saraileftthai;F885 +saraithai;0E34 +saraothai;0E42 +saraueeleftthai;F888 +saraueethai;0E37 +saraueleftthai;F887 +sarauethai;0E36 +sarauthai;0E38 +sarauuthai;0E39 +sbopomofo;3119 +scaron;0161 +scarondotaccent;1E67 +scedilla;015F +schwa;0259 +schwacyrillic;04D9 +schwadieresiscyrillic;04DB +schwahook;025A +scircle;24E2 +scircumflex;015D +scommaaccent;0219 +sdotaccent;1E61 +sdotbelow;1E63 +sdotbelowdotaccent;1E69 +seagullbelowcmb;033C +second;2033 +secondtonechinese;02CA +section;00A7 +seenarabic;0633 +seenfinalarabic;FEB2 +seeninitialarabic;FEB3 +seenmedialarabic;FEB4 +segol;05B6 +segol13;05B6 +segol1f;05B6 +segol2c;05B6 +segolhebrew;05B6 +segolnarrowhebrew;05B6 +segolquarterhebrew;05B6 +segoltahebrew;0592 +segolwidehebrew;05B6 +seharmenian;057D +sehiragana;305B +sekatakana;30BB +sekatakanahalfwidth;FF7E +semicolon;003B +semicolonarabic;061B +semicolonmonospace;FF1B +semicolonsmall;FE54 +semivoicedmarkkana;309C +semivoicedmarkkanahalfwidth;FF9F +sentisquare;3322 +sentosquare;3323 +seven;0037 +sevenarabic;0667 +sevenbengali;09ED +sevencircle;2466 +sevencircleinversesansserif;2790 +sevendeva;096D +seveneighths;215E +sevengujarati;0AED +sevengurmukhi;0A6D +sevenhackarabic;0667 +sevenhangzhou;3027 +sevenideographicparen;3226 +seveninferior;2087 +sevenmonospace;FF17 +sevenoldstyle;F737 +sevenparen;247A +sevenperiod;248E +sevenpersian;06F7 +sevenroman;2176 +sevensuperior;2077 +seventeencircle;2470 +seventeenparen;2484 +seventeenperiod;2498 +seventhai;0E57 +sfthyphen;00AD +shaarmenian;0577 +shabengali;09B6 +shacyrillic;0448 +shaddaarabic;0651 +shaddadammaarabic;FC61 +shaddadammatanarabic;FC5E +shaddafathaarabic;FC60 +shaddafathatanarabic;0651 064B +shaddakasraarabic;FC62 +shaddakasratanarabic;FC5F +shade;2592 +shadedark;2593 +shadelight;2591 +shademedium;2592 +shadeva;0936 +shagujarati;0AB6 +shagurmukhi;0A36 +shalshelethebrew;0593 +shbopomofo;3115 +shchacyrillic;0449 +sheenarabic;0634 +sheenfinalarabic;FEB6 +sheeninitialarabic;FEB7 +sheenmedialarabic;FEB8 +sheicoptic;03E3 +sheqel;20AA +sheqelhebrew;20AA +sheva;05B0 +sheva115;05B0 +sheva15;05B0 +sheva22;05B0 +sheva2e;05B0 +shevahebrew;05B0 +shevanarrowhebrew;05B0 +shevaquarterhebrew;05B0 +shevawidehebrew;05B0 +shhacyrillic;04BB +shimacoptic;03ED +shin;05E9 +shindagesh;FB49 +shindageshhebrew;FB49 +shindageshshindot;FB2C +shindageshshindothebrew;FB2C +shindageshsindot;FB2D +shindageshsindothebrew;FB2D +shindothebrew;05C1 +shinhebrew;05E9 +shinshindot;FB2A +shinshindothebrew;FB2A +shinsindot;FB2B +shinsindothebrew;FB2B +shook;0282 +sigma;03C3 +sigma1;03C2 +sigmafinal;03C2 +sigmalunatesymbolgreek;03F2 +sihiragana;3057 +sikatakana;30B7 +sikatakanahalfwidth;FF7C +siluqhebrew;05BD +siluqlefthebrew;05BD +similar;223C +sindothebrew;05C2 +siosacirclekorean;3274 +siosaparenkorean;3214 +sioscieuckorean;317E +sioscirclekorean;3266 +sioskiyeokkorean;317A +sioskorean;3145 +siosnieunkorean;317B +siosparenkorean;3206 +siospieupkorean;317D +siostikeutkorean;317C +six;0036 +sixarabic;0666 +sixbengali;09EC +sixcircle;2465 +sixcircleinversesansserif;278F +sixdeva;096C +sixgujarati;0AEC +sixgurmukhi;0A6C +sixhackarabic;0666 +sixhangzhou;3026 +sixideographicparen;3225 +sixinferior;2086 +sixmonospace;FF16 +sixoldstyle;F736 +sixparen;2479 +sixperiod;248D +sixpersian;06F6 +sixroman;2175 +sixsuperior;2076 +sixteencircle;246F +sixteencurrencydenominatorbengali;09F9 +sixteenparen;2483 +sixteenperiod;2497 +sixthai;0E56 +slash;002F +slashmonospace;FF0F +slong;017F +slongdotaccent;1E9B +smileface;263A +smonospace;FF53 +sofpasuqhebrew;05C3 +softhyphen;00AD +softsigncyrillic;044C +sohiragana;305D +sokatakana;30BD +sokatakanahalfwidth;FF7F +soliduslongoverlaycmb;0338 +solidusshortoverlaycmb;0337 +sorusithai;0E29 +sosalathai;0E28 +sosothai;0E0B +sosuathai;0E2A +space;0020 +spacehackarabic;0020 +spade;2660 +spadesuitblack;2660 +spadesuitwhite;2664 +sparen;24AE +squarebelowcmb;033B +squarecc;33C4 +squarecm;339D +squarediagonalcrosshatchfill;25A9 +squarehorizontalfill;25A4 +squarekg;338F +squarekm;339E +squarekmcapital;33CE +squareln;33D1 +squarelog;33D2 +squaremg;338E +squaremil;33D5 +squaremm;339C +squaremsquared;33A1 +squareorthogonalcrosshatchfill;25A6 +squareupperlefttolowerrightfill;25A7 +squareupperrighttolowerleftfill;25A8 +squareverticalfill;25A5 +squarewhitewithsmallblack;25A3 +srsquare;33DB +ssabengali;09B7 +ssadeva;0937 +ssagujarati;0AB7 +ssangcieuckorean;3149 +ssanghieuhkorean;3185 +ssangieungkorean;3180 +ssangkiyeokkorean;3132 +ssangnieunkorean;3165 +ssangpieupkorean;3143 +ssangsioskorean;3146 +ssangtikeutkorean;3138 +ssuperior;F6F2 +sterling;00A3 +sterlingmonospace;FFE1 +strokelongoverlaycmb;0336 +strokeshortoverlaycmb;0335 +subset;2282 +subsetnotequal;228A +subsetorequal;2286 +succeeds;227B +suchthat;220B +suhiragana;3059 +sukatakana;30B9 +sukatakanahalfwidth;FF7D +sukunarabic;0652 +summation;2211 +sun;263C +superset;2283 +supersetnotequal;228B +supersetorequal;2287 +svsquare;33DC +syouwaerasquare;337C +t;0074 +tabengali;09A4 +tackdown;22A4 +tackleft;22A3 +tadeva;0924 +tagujarati;0AA4 +tagurmukhi;0A24 +taharabic;0637 +tahfinalarabic;FEC2 +tahinitialarabic;FEC3 +tahiragana;305F +tahmedialarabic;FEC4 +taisyouerasquare;337D +takatakana;30BF +takatakanahalfwidth;FF80 +tatweelarabic;0640 +tau;03C4 +tav;05EA +tavdages;FB4A +tavdagesh;FB4A +tavdageshhebrew;FB4A +tavhebrew;05EA +tbar;0167 +tbopomofo;310A +tcaron;0165 +tccurl;02A8 +tcedilla;0163 +tcheharabic;0686 +tchehfinalarabic;FB7B +tchehinitialarabic;FB7C +tchehmedialarabic;FB7D +tchehmeeminitialarabic;FB7C FEE4 +tcircle;24E3 +tcircumflexbelow;1E71 +tcommaaccent;0163 +tdieresis;1E97 +tdotaccent;1E6B +tdotbelow;1E6D +tecyrillic;0442 +tedescendercyrillic;04AD +teharabic;062A +tehfinalarabic;FE96 +tehhahinitialarabic;FCA2 +tehhahisolatedarabic;FC0C +tehinitialarabic;FE97 +tehiragana;3066 +tehjeeminitialarabic;FCA1 +tehjeemisolatedarabic;FC0B +tehmarbutaarabic;0629 +tehmarbutafinalarabic;FE94 +tehmedialarabic;FE98 +tehmeeminitialarabic;FCA4 +tehmeemisolatedarabic;FC0E +tehnoonfinalarabic;FC73 +tekatakana;30C6 +tekatakanahalfwidth;FF83 +telephone;2121 +telephoneblack;260E +telishagedolahebrew;05A0 +telishaqetanahebrew;05A9 +tencircle;2469 +tenideographicparen;3229 +tenparen;247D +tenperiod;2491 +tenroman;2179 +tesh;02A7 +tet;05D8 +tetdagesh;FB38 +tetdageshhebrew;FB38 +tethebrew;05D8 +tetsecyrillic;04B5 +tevirhebrew;059B +tevirlefthebrew;059B +thabengali;09A5 +thadeva;0925 +thagujarati;0AA5 +thagurmukhi;0A25 +thalarabic;0630 +thalfinalarabic;FEAC +thanthakhatlowleftthai;F898 +thanthakhatlowrightthai;F897 +thanthakhatthai;0E4C +thanthakhatupperleftthai;F896 +theharabic;062B +thehfinalarabic;FE9A +thehinitialarabic;FE9B +thehmedialarabic;FE9C +thereexists;2203 +therefore;2234 +theta;03B8 +theta1;03D1 +thetasymbolgreek;03D1 +thieuthacirclekorean;3279 +thieuthaparenkorean;3219 +thieuthcirclekorean;326B +thieuthkorean;314C +thieuthparenkorean;320B +thirteencircle;246C +thirteenparen;2480 +thirteenperiod;2494 +thonangmonthothai;0E11 +thook;01AD +thophuthaothai;0E12 +thorn;00FE +thothahanthai;0E17 +thothanthai;0E10 +thothongthai;0E18 +thothungthai;0E16 +thousandcyrillic;0482 +thousandsseparatorarabic;066C +thousandsseparatorpersian;066C +three;0033 +threearabic;0663 +threebengali;09E9 +threecircle;2462 +threecircleinversesansserif;278C +threedeva;0969 +threeeighths;215C +threegujarati;0AE9 +threegurmukhi;0A69 +threehackarabic;0663 +threehangzhou;3023 +threeideographicparen;3222 +threeinferior;2083 +threemonospace;FF13 +threenumeratorbengali;09F6 +threeoldstyle;F733 +threeparen;2476 +threeperiod;248A +threepersian;06F3 +threequarters;00BE +threequartersemdash;F6DE +threeroman;2172 +threesuperior;00B3 +threethai;0E53 +thzsquare;3394 +tihiragana;3061 +tikatakana;30C1 +tikatakanahalfwidth;FF81 +tikeutacirclekorean;3270 +tikeutaparenkorean;3210 +tikeutcirclekorean;3262 +tikeutkorean;3137 +tikeutparenkorean;3202 +tilde;02DC +tildebelowcmb;0330 +tildecmb;0303 +tildecomb;0303 +tildedoublecmb;0360 +tildeoperator;223C +tildeoverlaycmb;0334 +tildeverticalcmb;033E +timescircle;2297 +tipehahebrew;0596 +tipehalefthebrew;0596 +tippigurmukhi;0A70 +titlocyrilliccmb;0483 +tiwnarmenian;057F +tlinebelow;1E6F +tmonospace;FF54 +toarmenian;0569 +tohiragana;3068 +tokatakana;30C8 +tokatakanahalfwidth;FF84 +tonebarextrahighmod;02E5 +tonebarextralowmod;02E9 +tonebarhighmod;02E6 +tonebarlowmod;02E8 +tonebarmidmod;02E7 +tonefive;01BD +tonesix;0185 +tonetwo;01A8 +tonos;0384 +tonsquare;3327 +topatakthai;0E0F +tortoiseshellbracketleft;3014 +tortoiseshellbracketleftsmall;FE5D +tortoiseshellbracketleftvertical;FE39 +tortoiseshellbracketright;3015 +tortoiseshellbracketrightsmall;FE5E +tortoiseshellbracketrightvertical;FE3A +totaothai;0E15 +tpalatalhook;01AB +tparen;24AF +trademark;2122 +trademarksans;F8EA +trademarkserif;F6DB +tretroflexhook;0288 +triagdn;25BC +triaglf;25C4 +triagrt;25BA +triagup;25B2 +ts;02A6 +tsadi;05E6 +tsadidagesh;FB46 +tsadidageshhebrew;FB46 +tsadihebrew;05E6 +tsecyrillic;0446 +tsere;05B5 +tsere12;05B5 +tsere1e;05B5 +tsere2b;05B5 +tserehebrew;05B5 +tserenarrowhebrew;05B5 +tserequarterhebrew;05B5 +tserewidehebrew;05B5 +tshecyrillic;045B +tsuperior;F6F3 +ttabengali;099F +ttadeva;091F +ttagujarati;0A9F +ttagurmukhi;0A1F +tteharabic;0679 +ttehfinalarabic;FB67 +ttehinitialarabic;FB68 +ttehmedialarabic;FB69 +tthabengali;09A0 +tthadeva;0920 +tthagujarati;0AA0 +tthagurmukhi;0A20 +tturned;0287 +tuhiragana;3064 +tukatakana;30C4 +tukatakanahalfwidth;FF82 +tusmallhiragana;3063 +tusmallkatakana;30C3 +tusmallkatakanahalfwidth;FF6F +twelvecircle;246B +twelveparen;247F +twelveperiod;2493 +twelveroman;217B +twentycircle;2473 +twentyhangzhou;5344 +twentyparen;2487 +twentyperiod;249B +two;0032 +twoarabic;0662 +twobengali;09E8 +twocircle;2461 +twocircleinversesansserif;278B +twodeva;0968 +twodotenleader;2025 +twodotleader;2025 +twodotleadervertical;FE30 +twogujarati;0AE8 +twogurmukhi;0A68 +twohackarabic;0662 +twohangzhou;3022 +twoideographicparen;3221 +twoinferior;2082 +twomonospace;FF12 +twonumeratorbengali;09F5 +twooldstyle;F732 +twoparen;2475 +twoperiod;2489 +twopersian;06F2 +tworoman;2171 +twostroke;01BB +twosuperior;00B2 +twothai;0E52 +twothirds;2154 +u;0075 +uacute;00FA +ubar;0289 +ubengali;0989 +ubopomofo;3128 +ubreve;016D +ucaron;01D4 +ucircle;24E4 +ucircumflex;00FB +ucircumflexbelow;1E77 +ucyrillic;0443 +udattadeva;0951 +udblacute;0171 +udblgrave;0215 +udeva;0909 +udieresis;00FC +udieresisacute;01D8 +udieresisbelow;1E73 +udieresiscaron;01DA +udieresiscyrillic;04F1 +udieresisgrave;01DC +udieresismacron;01D6 +udotbelow;1EE5 +ugrave;00F9 +ugujarati;0A89 +ugurmukhi;0A09 +uhiragana;3046 +uhookabove;1EE7 +uhorn;01B0 +uhornacute;1EE9 +uhorndotbelow;1EF1 +uhorngrave;1EEB +uhornhookabove;1EED +uhorntilde;1EEF +uhungarumlaut;0171 +uhungarumlautcyrillic;04F3 +uinvertedbreve;0217 +ukatakana;30A6 +ukatakanahalfwidth;FF73 +ukcyrillic;0479 +ukorean;315C +umacron;016B +umacroncyrillic;04EF +umacrondieresis;1E7B +umatragurmukhi;0A41 +umonospace;FF55 +underscore;005F +underscoredbl;2017 +underscoremonospace;FF3F +underscorevertical;FE33 +underscorewavy;FE4F +union;222A +universal;2200 +uogonek;0173 +uparen;24B0 +upblock;2580 +upperdothebrew;05C4 +upsilon;03C5 +upsilondieresis;03CB +upsilondieresistonos;03B0 +upsilonlatin;028A +upsilontonos;03CD +uptackbelowcmb;031D +uptackmod;02D4 +uragurmukhi;0A73 +uring;016F +ushortcyrillic;045E +usmallhiragana;3045 +usmallkatakana;30A5 +usmallkatakanahalfwidth;FF69 +ustraightcyrillic;04AF +ustraightstrokecyrillic;04B1 +utilde;0169 +utildeacute;1E79 +utildebelow;1E75 +uubengali;098A +uudeva;090A +uugujarati;0A8A +uugurmukhi;0A0A +uumatragurmukhi;0A42 +uuvowelsignbengali;09C2 +uuvowelsigndeva;0942 +uuvowelsigngujarati;0AC2 +uvowelsignbengali;09C1 +uvowelsigndeva;0941 +uvowelsigngujarati;0AC1 +v;0076 +vadeva;0935 +vagujarati;0AB5 +vagurmukhi;0A35 +vakatakana;30F7 +vav;05D5 +vavdagesh;FB35 +vavdagesh65;FB35 +vavdageshhebrew;FB35 +vavhebrew;05D5 +vavholam;FB4B +vavholamhebrew;FB4B +vavvavhebrew;05F0 +vavyodhebrew;05F1 +vcircle;24E5 +vdotbelow;1E7F +vecyrillic;0432 +veharabic;06A4 +vehfinalarabic;FB6B +vehinitialarabic;FB6C +vehmedialarabic;FB6D +vekatakana;30F9 +venus;2640 +verticalbar;007C +verticallineabovecmb;030D +verticallinebelowcmb;0329 +verticallinelowmod;02CC +verticallinemod;02C8 +vewarmenian;057E +vhook;028B +vikatakana;30F8 +viramabengali;09CD +viramadeva;094D +viramagujarati;0ACD +visargabengali;0983 +visargadeva;0903 +visargagujarati;0A83 +vmonospace;FF56 +voarmenian;0578 +voicediterationhiragana;309E +voicediterationkatakana;30FE +voicedmarkkana;309B +voicedmarkkanahalfwidth;FF9E +vokatakana;30FA +vparen;24B1 +vtilde;1E7D +vturned;028C +vuhiragana;3094 +vukatakana;30F4 +w;0077 +wacute;1E83 +waekorean;3159 +wahiragana;308F +wakatakana;30EF +wakatakanahalfwidth;FF9C +wakorean;3158 +wasmallhiragana;308E +wasmallkatakana;30EE +wattosquare;3357 +wavedash;301C +wavyunderscorevertical;FE34 +wawarabic;0648 +wawfinalarabic;FEEE +wawhamzaabovearabic;0624 +wawhamzaabovefinalarabic;FE86 +wbsquare;33DD +wcircle;24E6 +wcircumflex;0175 +wdieresis;1E85 +wdotaccent;1E87 +wdotbelow;1E89 +wehiragana;3091 +weierstrass;2118 +wekatakana;30F1 +wekorean;315E +weokorean;315D +wgrave;1E81 +whitebullet;25E6 +whitecircle;25CB +whitecircleinverse;25D9 +whitecornerbracketleft;300E +whitecornerbracketleftvertical;FE43 +whitecornerbracketright;300F +whitecornerbracketrightvertical;FE44 +whitediamond;25C7 +whitediamondcontainingblacksmalldiamond;25C8 +whitedownpointingsmalltriangle;25BF +whitedownpointingtriangle;25BD +whiteleftpointingsmalltriangle;25C3 +whiteleftpointingtriangle;25C1 +whitelenticularbracketleft;3016 +whitelenticularbracketright;3017 +whiterightpointingsmalltriangle;25B9 +whiterightpointingtriangle;25B7 +whitesmallsquare;25AB +whitesmilingface;263A +whitesquare;25A1 +whitestar;2606 +whitetelephone;260F +whitetortoiseshellbracketleft;3018 +whitetortoiseshellbracketright;3019 +whiteuppointingsmalltriangle;25B5 +whiteuppointingtriangle;25B3 +wihiragana;3090 +wikatakana;30F0 +wikorean;315F +wmonospace;FF57 +wohiragana;3092 +wokatakana;30F2 +wokatakanahalfwidth;FF66 +won;20A9 +wonmonospace;FFE6 +wowaenthai;0E27 +wparen;24B2 +wring;1E98 +wsuperior;02B7 +wturned;028D +wynn;01BF +x;0078 +xabovecmb;033D +xbopomofo;3112 +xcircle;24E7 +xdieresis;1E8D +xdotaccent;1E8B +xeharmenian;056D +xi;03BE +xmonospace;FF58 +xparen;24B3 +xsuperior;02E3 +y;0079 +yaadosquare;334E +yabengali;09AF +yacute;00FD +yadeva;092F +yaekorean;3152 +yagujarati;0AAF +yagurmukhi;0A2F +yahiragana;3084 +yakatakana;30E4 +yakatakanahalfwidth;FF94 +yakorean;3151 +yamakkanthai;0E4E +yasmallhiragana;3083 +yasmallkatakana;30E3 +yasmallkatakanahalfwidth;FF6C +yatcyrillic;0463 +ycircle;24E8 +ycircumflex;0177 +ydieresis;00FF +ydotaccent;1E8F +ydotbelow;1EF5 +yeharabic;064A +yehbarreearabic;06D2 +yehbarreefinalarabic;FBAF +yehfinalarabic;FEF2 +yehhamzaabovearabic;0626 +yehhamzaabovefinalarabic;FE8A +yehhamzaaboveinitialarabic;FE8B +yehhamzaabovemedialarabic;FE8C +yehinitialarabic;FEF3 +yehmedialarabic;FEF4 +yehmeeminitialarabic;FCDD +yehmeemisolatedarabic;FC58 +yehnoonfinalarabic;FC94 +yehthreedotsbelowarabic;06D1 +yekorean;3156 +yen;00A5 +yenmonospace;FFE5 +yeokorean;3155 +yeorinhieuhkorean;3186 +yerahbenyomohebrew;05AA +yerahbenyomolefthebrew;05AA +yericyrillic;044B +yerudieresiscyrillic;04F9 +yesieungkorean;3181 +yesieungpansioskorean;3183 +yesieungsioskorean;3182 +yetivhebrew;059A +ygrave;1EF3 +yhook;01B4 +yhookabove;1EF7 +yiarmenian;0575 +yicyrillic;0457 +yikorean;3162 +yinyang;262F +yiwnarmenian;0582 +ymonospace;FF59 +yod;05D9 +yoddagesh;FB39 +yoddageshhebrew;FB39 +yodhebrew;05D9 +yodyodhebrew;05F2 +yodyodpatahhebrew;FB1F +yohiragana;3088 +yoikorean;3189 +yokatakana;30E8 +yokatakanahalfwidth;FF96 +yokorean;315B +yosmallhiragana;3087 +yosmallkatakana;30E7 +yosmallkatakanahalfwidth;FF6E +yotgreek;03F3 +yoyaekorean;3188 +yoyakorean;3187 +yoyakthai;0E22 +yoyingthai;0E0D +yparen;24B4 +ypogegrammeni;037A +ypogegrammenigreekcmb;0345 +yr;01A6 +yring;1E99 +ysuperior;02B8 +ytilde;1EF9 +yturned;028E +yuhiragana;3086 +yuikorean;318C +yukatakana;30E6 +yukatakanahalfwidth;FF95 +yukorean;3160 +yusbigcyrillic;046B +yusbigiotifiedcyrillic;046D +yuslittlecyrillic;0467 +yuslittleiotifiedcyrillic;0469 +yusmallhiragana;3085 +yusmallkatakana;30E5 +yusmallkatakanahalfwidth;FF6D +yuyekorean;318B +yuyeokorean;318A +yyabengali;09DF +yyadeva;095F +z;007A +zaarmenian;0566 +zacute;017A +zadeva;095B +zagurmukhi;0A5B +zaharabic;0638 +zahfinalarabic;FEC6 +zahinitialarabic;FEC7 +zahiragana;3056 +zahmedialarabic;FEC8 +zainarabic;0632 +zainfinalarabic;FEB0 +zakatakana;30B6 +zaqefgadolhebrew;0595 +zaqefqatanhebrew;0594 +zarqahebrew;0598 +zayin;05D6 +zayindagesh;FB36 +zayindageshhebrew;FB36 +zayinhebrew;05D6 +zbopomofo;3117 +zcaron;017E +zcircle;24E9 +zcircumflex;1E91 +zcurl;0291 +zdot;017C +zdotaccent;017C +zdotbelow;1E93 +zecyrillic;0437 +zedescendercyrillic;0499 +zedieresiscyrillic;04DF +zehiragana;305C +zekatakana;30BC +zero;0030 +zeroarabic;0660 +zerobengali;09E6 +zerodeva;0966 +zerogujarati;0AE6 +zerogurmukhi;0A66 +zerohackarabic;0660 +zeroinferior;2080 +zeromonospace;FF10 +zerooldstyle;F730 +zeropersian;06F0 +zerosuperior;2070 +zerothai;0E50 +zerowidthjoiner;FEFF +zerowidthnonjoiner;200C +zerowidthspace;200B +zeta;03B6 +zhbopomofo;3113 +zhearmenian;056A +zhebrevecyrillic;04C2 +zhecyrillic;0436 +zhedescendercyrillic;0497 +zhedieresiscyrillic;04DD +zihiragana;3058 +zikatakana;30B8 +zinorhebrew;05AE +zlinebelow;1E95 +zmonospace;FF5A +zohiragana;305E +zokatakana;30BE +zparen;24B5 +zretroflexhook;0290 +zstroke;01B6 +zuhiragana;305A +zukatakana;30BA +a100;275E +a101;2761 +a102;2762 +a103;2763 +a104;2764 +a105;2710 +a106;2765 +a107;2766 +a108;2767 +a109;2660 +a10;2721 +a110;2665 +a111;2666 +a112;2663 +a117;2709 +a118;2708 +a119;2707 +a11;261B +a120;2460 +a121;2461 +a122;2462 +a123;2463 +a124;2464 +a125;2465 +a126;2466 +a127;2467 +a128;2468 +a129;2469 +a12;261E +a130;2776 +a131;2777 +a132;2778 +a133;2779 +a134;277A +a135;277B +a136;277C +a137;277D +a138;277E +a139;277F +a13;270C +a140;2780 +a141;2781 +a142;2782 +a143;2783 +a144;2784 +a145;2785 +a146;2786 +a147;2787 +a148;2788 +a149;2789 +a14;270D +a150;278A +a151;278B +a152;278C +a153;278D +a154;278E +a155;278F +a156;2790 +a157;2791 +a158;2792 +a159;2793 +a15;270E +a160;2794 +a161;2192 +a162;27A3 +a163;2194 +a164;2195 +a165;2799 +a166;279B +a167;279C +a168;279D +a169;279E +a16;270F +a170;279F +a171;27A0 +a172;27A1 +a173;27A2 +a174;27A4 +a175;27A5 +a176;27A6 +a177;27A7 +a178;27A8 +a179;27A9 +a17;2711 +a180;27AB +a181;27AD +a182;27AF +a183;27B2 +a184;27B3 +a185;27B5 +a186;27B8 +a187;27BA +a188;27BB +a189;27BC +a18;2712 +a190;27BD +a191;27BE +a192;279A +a193;27AA +a194;27B6 +a195;27B9 +a196;2798 +a197;27B4 +a198;27B7 +a199;27AC +a19;2713 +a1;2701 +a200;27AE +a201;27B1 +a202;2703 +a203;2750 +a204;2752 +a205;276E +a206;2770 +a20;2714 +a21;2715 +a22;2716 +a23;2717 +a24;2718 +a25;2719 +a26;271A +a27;271B +a28;271C +a29;2722 +a2;2702 +a30;2723 +a31;2724 +a32;2725 +a33;2726 +a34;2727 +a35;2605 +a36;2729 +a37;272A +a38;272B +a39;272C +a3;2704 +a40;272D +a41;272E +a42;272F +a43;2730 +a44;2731 +a45;2732 +a46;2733 +a47;2734 +a48;2735 +a49;2736 +a4;260E +a50;2737 +a51;2738 +a52;2739 +a53;273A +a54;273B +a55;273C +a56;273D +a57;273E +a58;273F +a59;2740 +a5;2706 +a60;2741 +a61;2742 +a62;2743 +a63;2744 +a64;2745 +a65;2746 +a66;2747 +a67;2748 +a68;2749 +a69;274A +a6;271D +a70;274B +a71;25CF +a72;274D +a73;25A0 +a74;274F +a75;2751 +a76;25B2 +a77;25BC +a78;25C6 +a79;2756 +a7;271E +a81;25D7 +a82;2758 +a83;2759 +a84;275A +a85;276F +a86;2771 +a87;2772 +a88;2773 +a89;2768 +a8;271F +a90;2769 +a91;276C +a92;276D +a93;276A +a94;276B +a95;2774 +a96;2775 +a97;275B +a98;275C +a99;275D +a9;2720 +""" + + +# string table management +# +class StringTable: + def __init__(self, name_list, master_table_name): + self.names = name_list + self.master_table = master_table_name + self.indices = {} + index = 0 + + for name in name_list: + self.indices[name] = index + index += len(name) + 1 + + self.total = index + + def dump(self, file): + write = file.write + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const char " + self.master_table + + "[" + repr(self.total) + "]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = "" + for name in self.names: + line += " '" + line += "','".join(list(name)) + line += "', 0,\n" + + write(line) + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + def dump_sublist(self, file, table_name, macro_name, sublist): + write = file.write + write("#define " + macro_name + " " + repr(len(sublist)) + "\n\n") + + write(" /* Values are offsets into the `" + + self.master_table + "' table */\n\n") + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const short " + table_name + + "[" + macro_name + "]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = " " + comma = "" + col = 0 + + for name in sublist: + line += comma + line += "%4d" % self.indices[name] + col += 1 + comma = "," + if col == 14: + col = 0 + comma = ",\n " + + write(line) + write("\n") + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + +# We now store the Adobe Glyph List in compressed form. The list is put +# into a data structure called `trie' (because it has a tree-like +# appearance). Consider, for example, that you want to store the +# following name mapping: +# +# A => 1 +# Aacute => 6 +# Abalon => 2 +# Abstract => 4 +# +# It is possible to store the entries as follows. +# +# A => 1 +# | +# +-acute => 6 +# | +# +-b +# | +# +-alon => 2 +# | +# +-stract => 4 +# +# We see that each node in the trie has: +# +# - one or more `letters' +# - an optional value +# - zero or more child nodes +# +# The first step is to call +# +# root = StringNode( "", 0 ) +# for word in map.values(): +# root.add( word, map[word] ) +# +# which creates a large trie where each node has only one children. +# +# Executing +# +# root = root.optimize() +# +# optimizes the trie by merging the letters of successive nodes whenever +# possible. +# +# Each node of the trie is stored as follows. +# +# - First the node's letter, according to the following scheme. We +# use the fact that in the AGL no name contains character codes > 127. +# +# name bitsize description +# ---------------------------------------------------------------- +# notlast 1 Set to 1 if this is not the last letter +# in the word. +# ascii 7 The letter's ASCII value. +# +# - The letter is followed by a children count and the value of the +# current key (if any). Again we can do some optimization because all +# AGL entries are from the BMP; this means that 16 bits are sufficient +# to store its Unicode values. Additionally, no node has more than +# 127 children. +# +# name bitsize description +# ----------------------------------------- +# hasvalue 1 Set to 1 if a 16-bit Unicode value follows. +# num_children 7 Number of children. Can be 0 only if +# `hasvalue' is set to 1. +# value 16 Optional Unicode value. +# +# - A node is finished by a list of 16bit absolute offsets to the +# children, which must be sorted in increasing order of their first +# letter. +# +# For simplicity, all 16bit quantities are stored in big-endian order. +# +# The root node has first letter = 0, and no value. +# +class StringNode: + def __init__(self, letter, value): + self.letter = letter + self.value = value + self.children = {} + + def __cmp__(self, other): + return ord(self.letter[0]) - ord(other.letter[0]) + + def __lt__(self, other): + return self.letter[0] < other.letter[0] + + def add(self, word, value): + if len(word) == 0: + self.value = value + return + + letter = word[0] + word = word[1:] + + if letter in self.children: + child = self.children[letter] + else: + child = StringNode(letter, 0) + self.children[letter] = child + + child.add(word, value) + + def optimize(self): + # optimize all children first + children = list(self.children.values()) + self.children = {} + + for child in children: + self.children[child.letter[0]] = child.optimize() + + # don't optimize if there's a value, + # if we don't have any child or if we + # have more than one child + if (self.value != 0) or (not children) or len(children) > 1: + return self + + child = children[0] + + self.letter += child.letter + self.value = child.value + self.children = child.children + + return self + + def dump_debug(self, write, margin): + # this is used during debugging + line = margin + "+-" + if len(self.letter) == 0: + line += "" + else: + line += self.letter + + if self.value: + line += " => " + repr(self.value) + + write(line + "\n") + + if self.children: + margin += "| " + for child in self.children.values(): + child.dump_debug(write, margin) + + def locate(self, index): + self.index = index + if len(self.letter) > 0: + index += len(self.letter) + 1 + else: + index += 2 + + if self.value != 0: + index += 2 + + children = list(self.children.values()) + children.sort() + + index += 2 * len(children) + for child in children: + index = child.locate(index) + + return index + + def store(self, storage): + # write the letters + length = len(self.letter) + if length == 0: + storage += struct.pack("B", 0) + else: + for n in range(length): + val = ord(self.letter[n]) + if n < length - 1: + val += 128 + storage += struct.pack("B", val) + + # write the count + children = list(self.children.values()) + children.sort() + + count = len(children) + + if self.value != 0: + storage += struct.pack("!BH", count + 128, self.value) + else: + storage += struct.pack("B", count) + + for child in children: + storage += struct.pack("!H", child.index) + + for child in children: + storage = child.store(storage) + + return storage + + +def adobe_glyph_values(): + """return the list of glyph names and their unicode values""" + + lines = adobe_glyph_list.split("\n") + glyphs = [] + values = [] + + for line in lines: + if line: + fields = line.split(';') + # print fields[1] + ' - ' + fields[0] + subfields = fields[1].split(' ') + if len(subfields) == 1: + glyphs.append(fields[0]) + values.append(fields[1]) + + return glyphs, values + + +def filter_glyph_names(alist, filter): + """filter `alist' by taking _out_ all glyph names that are in `filter'""" + + count = 0 + extras = [] + + for name in alist: + try: + filtered_index = filter.index(name) + except: + extras.append(name) + + return extras + + +def dump_encoding(file, encoding_name, encoding_list): + """dump a given encoding""" + + write = file.write + write(" /* the following are indices into the SID name table */\n") + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const unsigned short " + encoding_name + + "[" + repr(len(encoding_list)) + "]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = " " + comma = "" + col = 0 + for value in encoding_list: + line += comma + line += "%3d" % value + comma = "," + col += 1 + if col == 16: + col = 0 + comma = ",\n " + + write(line) + write("\n") + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + +def dump_array(the_array, write, array_name): + """dumps a given encoding""" + + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const unsigned char " + array_name + + "[" + repr(len(the_array)) + "L]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = "" + comma = " " + col = 0 + + for value in the_array: + line += comma + line += "%3d" % value + comma = "," + col += 1 + + if col == 16: + col = 0 + comma = ",\n " + + if len(line) > 1024: + write(line) + line = "" + + write(line) + write("\n") + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + +def main(): + """main program body""" + + if len(sys.argv) != 2: + print(__doc__ % sys.argv[0]) + sys.exit(1) + + file = open(sys.argv[1], "w") + write = file.write + + count_sid = len(sid_standard_names) + + # `mac_extras' contains the list of glyph names in the Macintosh standard + # encoding which are not in the SID Standard Names. + # + mac_extras = filter_glyph_names(mac_standard_names, sid_standard_names) + + # `base_list' contains the names of our final glyph names table. + # It consists of the `mac_extras' glyph names, followed by the SID + # standard names. + # + mac_extras_count = len(mac_extras) + base_list = mac_extras + sid_standard_names + + write("/*\n") + write(" *\n") + write(" * %-71s\n" % os.path.basename(sys.argv[1])) + write(" *\n") + write(" * PostScript glyph names.\n") + write(" *\n") + write(" * Copyright 2005-2022 by\n") + write(" * David Turner, Robert Wilhelm, and Werner Lemberg.\n") + write(" *\n") + write(" * This file is part of the FreeType project, and may only be " + "used,\n") + write(" * modified, and distributed under the terms of the FreeType " + "project\n") + write(" * license, LICENSE.TXT. By continuing to use, modify, or " + "distribute\n") + write(" * this file you indicate that you have read the license and\n") + write(" * understand and accept it fully.\n") + write(" *\n") + write(" */\n") + write("\n") + write("\n") + write(" /* This file has been generated automatically -- do not edit! */" + "\n") + write("\n") + write("\n") + + # dump final glyph list (mac extras + sid standard names) + # + st = StringTable(base_list, "ft_standard_glyph_names") + + st.dump(file) + st.dump_sublist(file, "ft_mac_names", + "FT_NUM_MAC_NAMES", mac_standard_names) + st.dump_sublist(file, "ft_sid_names", + "FT_NUM_SID_NAMES", sid_standard_names) + + dump_encoding(file, "t1_standard_encoding", t1_standard_encoding) + dump_encoding(file, "t1_expert_encoding", t1_expert_encoding) + + # dump the AGL in its compressed form + # + agl_glyphs, agl_values = adobe_glyph_values() + dictionary = StringNode("", 0) + + for g in range(len(agl_glyphs)): + dictionary.add(agl_glyphs[g], eval("0x" + agl_values[g])) + + dictionary = dictionary.optimize() + dict_len = dictionary.locate(0) + dict_array = dictionary.store(b"") + + write("""\ + /* + * This table is a compressed version of the Adobe Glyph List (AGL), + * optimized for efficient searching. It has been generated by the + * `glnames.py' python script located in the `src/tools' directory. + * + * The lookup function to get the Unicode value for a given string + * is defined below the table. + */ + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + +""") + + dump_array(dict_array, write, "ft_adobe_glyph_list") + + # write the lookup routine now + # + write("""\ +#ifdef DEFINE_PS_TABLES + /* + * This function searches the compressed table efficiently. + */ + static unsigned long + ft_get_adobe_glyph_index( const char* name, + const char* limit ) + { + int c = 0; + int count, min, max; + const unsigned char* p = ft_adobe_glyph_list; + + + if ( name == 0 || name >= limit ) + goto NotFound; + + c = *name++; + count = p[1]; + p += 2; + + min = 0; + max = count; + + while ( min < max ) + { + int mid = ( min + max ) >> 1; + const unsigned char* q = p + mid * 2; + int c2; + + + q = ft_adobe_glyph_list + ( ( (int)q[0] << 8 ) | q[1] ); + + c2 = q[0] & 127; + if ( c2 == c ) + { + p = q; + goto Found; + } + if ( c2 < c ) + min = mid + 1; + else + max = mid; + } + goto NotFound; + + Found: + for (;;) + { + /* assert (*p & 127) == c */ + + if ( name >= limit ) + { + if ( (p[0] & 128) == 0 && + (p[1] & 128) != 0 ) + return (unsigned long)( ( (int)p[2] << 8 ) | p[3] ); + + goto NotFound; + } + c = *name++; + if ( p[0] & 128 ) + { + p++; + if ( c != (p[0] & 127) ) + goto NotFound; + + continue; + } + + p++; + count = p[0] & 127; + if ( p[0] & 128 ) + p += 2; + + p++; + + for ( ; count > 0; count--, p += 2 ) + { + int offset = ( (int)p[0] << 8 ) | p[1]; + const unsigned char* q = ft_adobe_glyph_list + offset; + + if ( c == ( q[0] & 127 ) ) + { + p = q; + goto NextIter; + } + } + goto NotFound; + + NextIter: + ; + } + + NotFound: + return 0; + } +#endif /* DEFINE_PS_TABLES */ + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + +""") + + if 0: # generate unit test, or don't + # + # now write the unit test to check that everything works OK + # + write("#ifdef TEST\n\n") + + write("static const char* const the_names[] = {\n") + for name in agl_glyphs: + write(' "' + name + '",\n') + write(" 0\n};\n") + + write("static const unsigned long the_values[] = {\n") + for val in agl_values: + write(' 0x' + val + ',\n') + write(" 0\n};\n") + + write(""" +#include +#include +#include + +int +main( void ) +{ +int result = 0; +const char* const* names = the_names; +const unsigned long* values = the_values; + + +for ( ; *names; names++, values++ ) +{ + const char* name = *names; + unsigned long reference = *values; + unsigned long value; + + + value = ft_get_adobe_glyph_index( name, name + strlen( name ) ); + if ( value != reference ) + { + result = 1; + fprintf( stderr, "name '%s' => %04x instead of %04x\\n", + name, value, reference ); + } +} + +return result; +} +""") + + write("#endif /* TEST */\n") + + write("\n/* END */\n") + + +# Now run the main routine +# +main() + +# END diff --git a/vendor/freetype/src/tools/make_distribution_archives.py b/vendor/freetype/src/tools/make_distribution_archives.py new file mode 100644 index 0000000..f29eb12 --- /dev/null +++ b/vendor/freetype/src/tools/make_distribution_archives.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python3 +"""Generate distribution archives for a given FreeType 2 release.""" + +from __future__ import print_function + +import argparse +import atexit +import os +import shutil +import subprocess +import sys +import tempfile + +_TOP_DIR = os.path.abspath(os.path.join(__file__, "..", "..", "..")) +_SCRIPT_DIR = os.path.dirname(os.path.join(_TOP_DIR, "builds", "meson", "")) + + +def get_cmd_output(cmd, cwd=None): + """Run a command and return its output as a string.""" + if cwd is not None: + out = subprocess.check_output(cmd, cwd=cwd) + else: + out = subprocess.check_output(cmd) + return out.decode("utf-8").rstrip() + + +def is_git_dir_clean(git_dir): + """Return True iff |git_dir| is a git directory in clean state.""" + out = get_cmd_output(["git", "status", "--porcelain"], cwd=git_dir) + return len(out) == 0 + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + parser.add_argument( + "--source_dir", default=_TOP_DIR, help="Source directory path." + ) + + parser.add_argument( + "--version", + help=( + "Specify alternate FreeType version (it is otherwise extracted" + " from current sources by default)." + ), + ) + + parser.add_argument( + "--gnu-config-dir", + help=( + "Path of input directory containing recent `config.guess` and" + " `config.sub` files from GNU config." + ), + ) + + parser.add_argument( + "--build-dir", + help="Specify build directory. Only used for debugging this script.", + ) + + parser.add_argument( + "--ignore-clean-check", + action="store_true", + help=( + "Do not check for a clean source git repository. Only used for" + " debugging this script." + ), + ) + + parser.add_argument( + "output_dir", help="Output directory for generated archives." + ) + + args = parser.parse_args() + + git_dir = args.source_dir if args.source_dir else _TOP_DIR + if not args.ignore_clean_check and not is_git_dir_clean(git_dir): + sys.stderr.write( + "ERROR: Your git repository is not in a clean state: %s\n" + % git_dir + ) + return 1 + + if args.version: + version = args.version + else: + # Extract FreeType version from sources. + version = get_cmd_output( + [ + sys.executable, + os.path.join(_SCRIPT_DIR, "extract_freetype_version.py"), + os.path.join(_TOP_DIR, "include", "freetype", "freetype.h"), + ] + ) + + # Determine the build directory. This will be a temporary file that is + # cleaned up on script exit by default, unless --build-dir=DIR is used, + # in which case we only create and empty the directory, but never remove + # its content on exit. + if args.build_dir: + build_dir = args.build_dir + if not os.path.exists(build_dir): + os.makedirs(build_dir) + else: + # Remove anything from the build directory, if any. + for item in os.listdir(build_dir): + file_path = os.path.join(build_dir, item) + if os.path.isdir(file_path): + shutil.rmtree(file_path) + else: + os.unlink(file_path) + else: + # Create a temporary directory, and ensure it is removed on exit. + build_dir = tempfile.mkdtemp(prefix="freetype-dist-") + + def clean_build_dir(): + shutil.rmtree(build_dir) + + atexit.register(clean_build_dir) + + # Copy all source files known to git into $BUILD_DIR/freetype-$VERSION + # with the exception of .gitignore and .mailmap files. + source_files = [ + f + for f in get_cmd_output(["git", "ls-files"], cwd=git_dir).split("\n") + if os.path.basename(f) not in (".gitignore", ".mailmap") + ] + + freetype_dir = "freetype-" + version + tmp_src_dir = os.path.join(build_dir, freetype_dir) + os.makedirs(tmp_src_dir) + + for src in source_files: + dst = os.path.join(tmp_src_dir, src) + dst_dir = os.path.dirname(dst) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + shutil.copy(os.path.join(git_dir, src), dst) + + # Run autogen.sh in directory. + subprocess.check_call(["/bin/sh", "autogen.sh"], cwd=tmp_src_dir) + shutil.rmtree( + os.path.join(tmp_src_dir, "builds", "unix", "autom4te.cache") + ) + + # Copy config.guess and config.sub if possible! + if args.gnu_config_dir: + for f in ("config.guess", "config.sub"): + shutil.copy( + os.path.join(args.gnu_config_dir, f), + os.path.join(tmp_src_dir, "builds", "unix", f), + ) + + # Generate reference documentation under docs/ + subprocess.check_call( + [ + sys.executable, + os.path.join(_SCRIPT_DIR, "generate_reference_docs.py"), + "--input-dir", + tmp_src_dir, + "--version", + version, + "--output-dir", + os.path.join(tmp_src_dir, "docs"), + ] + ) + + shutil.rmtree(os.path.join(tmp_src_dir, "docs", "markdown")) + os.unlink(os.path.join(tmp_src_dir, "docs", "mkdocs.yml")) + + # Generate our archives + freetype_tar = freetype_dir + ".tar" + + subprocess.check_call( + ["tar", "-H", "ustar", "-chf", freetype_tar, freetype_dir], + cwd=build_dir, + ) + + subprocess.check_call( + ["gzip", "-9", "--keep", freetype_tar], cwd=build_dir + ) + + subprocess.check_call(["xz", "--keep", freetype_tar], cwd=build_dir) + + ftwinversion = "ft" + "".join(version.split(".")) + subprocess.check_call( + ["zip", "-qlr9", ftwinversion + ".zip", freetype_dir], cwd=build_dir + ) + + # Copy file to output directory now. + if not os.path.exists(args.output_dir): + os.makedirs(args.output_dir) + + for f in ( + freetype_tar + ".gz", + freetype_tar + ".xz", + ftwinversion + ".zip", + ): + shutil.copy( + os.path.join(build_dir, f), os.path.join(args.output_dir, f) + ) + + # Done! + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vendor/freetype/src/tools/no-copyright b/vendor/freetype/src/tools/no-copyright new file mode 100644 index 0000000..e171b76 --- /dev/null +++ b/vendor/freetype/src/tools/no-copyright @@ -0,0 +1,66 @@ +# Files that don't get a copyright, or which are taken from elsewhere. +# +# All lines in this file are patterns (relative to the top-level directory), +# including the comment lines; this means that e.g. `FTL.TXT' matches all +# files that have this string in the file name (including the path relative +# to the current directory, always starting with `./'). +# +# Don't put empty lines into this file! +# +builds/unix/pkg.m4 +# +docs/FTL.TXT +docs/GPLv2.TXT +# +include/freetype/internal/fthash.h +# +src/base/fthash.c +src/base/md5.c +src/base/md5.h +# +src/bdf/bdf.c +src/bdf/bdf.h +src/bdf/bdfdrivr.c +src/bdf/bdfdrivr.h +src/bdf/bdferror.h +src/bdf/bdflib.c +src/bdf/module.mk +src/bdf/README +src/bdf/rules.mk +# +src/pcf/module.mk +src/pcf/pcf.c +src/pcf/pcf.h +src/pcf/pcfdrivr.c +src/pcf/pcfdrivr.h +src/pcf/pcferror.h +src/pcf/pcfread.c +src/pcf/pcfread.h +src/pcf/pcfutil.c +src/pcf/pcfutil.h +src/pcf/README +src/pcf/rules.mk +# +src/gzip/adler32.c +src/gzip/ftzconf.c +src/gzip/infblock.c +src/gzip/infblock.h +src/gzip/infcodes.c +src/gzip/infcodes.h +src/gzip/inffixed.h +src/gzip/inflate.c +src/gzip/inftrees.c +src/gzip/inftrees.h +src/gzip/infutil.c +src/gzip/infutil.h +src/gzip/zconf.h +src/gzip/zlib.h +src/gzip/zutil.c +src/gzip/zutil.h +# +src/tools/apinames.c +src/tools/ftrandom/ftrandom.c +# +subprojects/dlg +# +# EOF diff --git a/vendor/freetype/src/tools/test_afm.c b/vendor/freetype/src/tools/test_afm.c new file mode 100644 index 0000000..a4b2268 --- /dev/null +++ b/vendor/freetype/src/tools/test_afm.c @@ -0,0 +1,156 @@ +/* + * gcc -DFT2_BUILD_LIBRARY -I../../include -o test_afm test_afm.c \ + * -L../../objs/.libs -lfreetype -lz -static + */ +#include +#include +#include + + void dump_fontinfo( AFM_FontInfo fi ) + { + FT_UInt i; + + + printf( "This AFM is for %sCID font.\n\n", + ( fi->IsCIDFont ) ? "" : "non-" ); + + printf( "FontBBox: %.2f %.2f %.2f %.2f\n", fi->FontBBox.xMin / 65536., + fi->FontBBox.yMin / 65536., + fi->FontBBox.xMax / 65536., + fi->FontBBox.yMax / 65536. ); + printf( "Ascender: %.2f\n", fi->Ascender / 65536. ); + printf( "Descender: %.2f\n\n", fi->Descender / 65536. ); + + if ( fi->NumTrackKern ) + printf( "There are %d sets of track kernings:\n", + fi->NumTrackKern ); + else + printf( "There is no track kerning.\n" ); + + for ( i = 0; i < fi->NumTrackKern; i++ ) + { + AFM_TrackKern tk = fi->TrackKerns + i; + + + printf( "\t%2d: %5.2f %5.2f %5.2f %5.2f\n", tk->degree, + tk->min_ptsize / 65536., + tk->min_kern / 65536., + tk->max_ptsize / 65536., + tk->max_kern / 65536. ); + } + + printf( "\n" ); + + if ( fi->NumKernPair ) + printf( "There are %d kerning pairs:\n", + fi->NumKernPair ); + else + printf( "There is no kerning pair.\n" ); + + for ( i = 0; i < fi->NumKernPair; i++ ) + { + AFM_KernPair kp = fi->KernPairs + i; + + + printf( "\t%3d + %3d => (%4d, %4d)\n", kp->index1, + kp->index2, + kp->x, + kp->y ); + } + + } + + int + dummy_get_index( const char* name, + FT_Offset len, + void* user_data ) + { + if ( len ) + return name[0]; + else + return 0; + } + + FT_Error + parse_afm( FT_Library library, + FT_Stream stream, + AFM_FontInfo fi ) + { + PSAux_Service psaux; + AFM_ParserRec parser; + FT_Error error = FT_Err_Ok; + + + psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" ); + if ( !psaux || !psaux->afm_parser_funcs ) + return -1; + + error = FT_Stream_EnterFrame( stream, stream->size ); + if ( error ) + return error; + + error = psaux->afm_parser_funcs->init( &parser, + library->memory, + stream->cursor, + stream->limit ); + if ( error ) + return error; + + parser.FontInfo = fi; + parser.get_index = dummy_get_index; + + error = psaux->afm_parser_funcs->parse( &parser ); + + psaux->afm_parser_funcs->done( &parser ); + + return error; + } + + + int main( int argc, + char** argv ) + { + FT_Library library; + FT_StreamRec stream; + FT_Error error = FT_Err_Ok; + AFM_FontInfoRec fi; + + + if ( argc < 2 ) + return FT_ERR( Invalid_Argument ); + + error = FT_Init_FreeType( &library ); + if ( error ) + return error; + + FT_ZERO( &stream ); + error = FT_Stream_Open( &stream, argv[1] ); + if ( error ) + goto Exit; + stream.memory = library->memory; + + FT_ZERO( &fi ); + error = parse_afm( library, &stream, &fi ); + + if ( !error ) + { + FT_Memory memory = library->memory; + + + dump_fontinfo( &fi ); + + if ( fi.KernPairs ) + FT_FREE( fi.KernPairs ); + if ( fi.TrackKerns ) + FT_FREE( fi.TrackKerns ); + } + else + printf( "parse error\n" ); + + FT_Stream_Close( &stream ); + + Exit: + FT_Done_FreeType( library ); + + return error; + } diff --git a/vendor/freetype/src/tools/test_bbox.c b/vendor/freetype/src/tools/test_bbox.c new file mode 100644 index 0000000..d9fd932 --- /dev/null +++ b/vendor/freetype/src/tools/test_bbox.c @@ -0,0 +1,187 @@ +#include +#include + + +#include /* for clock() */ + +/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include */ +/* to get the HZ macro which is the equivalent. */ +#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4) +#include +#define CLOCKS_PER_SEC HZ +#endif + + static long + get_time( void ) + { + return clock() * 10000L / CLOCKS_PER_SEC; + } + + + + + /* test bbox computations */ + +#define XSCALE 65536 +#define XX(x) ((FT_Pos)(x*XSCALE)) +#define XVEC(x,y) { XX(x), XX(y) } +#define XVAL(x) ((x)/(1.0*XSCALE)) + + /* dummy outline #1 */ + static FT_Vector dummy_vec_1[4] = + { +#if 1 + XVEC( 408.9111, 535.3164 ), + XVEC( 455.8887, 634.396 ), + XVEC( -37.8765, 786.2207 ), + XVEC( 164.6074, 535.3164 ) +#else + { (FT_Int32)0x0198E93DL , (FT_Int32)0x021750FFL }, /* 408.9111, 535.3164 */ + { (FT_Int32)0x01C7E312L , (FT_Int32)0x027A6560L }, /* 455.8887, 634.3960 */ + { (FT_Int32)0xFFDA1F9EL , (FT_Int32)0x0312387FL }, /* -37.8765, 786.2207 */ + { (FT_Int32)0x00A49B7EL , (FT_Int32)0x021750FFL } /* 164.6074, 535.3164 */ +#endif + }; + + static char dummy_tag_1[4] = + { + FT_CURVE_TAG_ON, + FT_CURVE_TAG_CUBIC, + FT_CURVE_TAG_CUBIC, + FT_CURVE_TAG_ON + }; + + static short dummy_contour_1[1] = + { + 3 + }; + + static FT_Outline dummy_outline_1 = + { + 1, + 4, + dummy_vec_1, + dummy_tag_1, + dummy_contour_1, + 0 + }; + + + /* dummy outline #2 */ + static FT_Vector dummy_vec_2[4] = + { + XVEC( 100.0, 100.0 ), + XVEC( 100.0, 200.0 ), + XVEC( 200.0, 200.0 ), + XVEC( 200.0, 133.0 ) + }; + + static FT_Outline dummy_outline_2 = + { + 1, + 4, + dummy_vec_2, + dummy_tag_1, + dummy_contour_1, + 0 + }; + + + /* dummy outline #3 with bbox of [0 100 128 128] precisely */ + static FT_Vector dummy_vec_3[4] = + { + XVEC( 100.0, 127.0 ), + XVEC( 200.0, 127.0 ), + XVEC( 0.0, 136.0 ), + XVEC( 0.0, 100.0 ) + }; + + static FT_Outline dummy_outline_3 = + { + 1, + 4, + dummy_vec_3, + dummy_tag_1, + dummy_contour_1, + 0 + }; + + + static void + dump_outline( FT_Outline* outline ) + { + FT_BBox bbox; + + /* compute and display cbox */ + FT_Outline_Get_CBox( outline, &bbox ); + printf( "cbox = [%.2f %.2f %.2f %.2f]\n", + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + + /* compute and display bbox */ + FT_Outline_Get_BBox( outline, &bbox ); + printf( "bbox = [%.2f %.2f %.2f %.2f]\n", + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + } + + + + static void + profile_outline( FT_Outline* outline, + long repeat ) + { + FT_BBox bbox; + long count; + long time0; + + time0 = get_time(); + for ( count = repeat; count > 0; count-- ) + FT_Outline_Get_CBox( outline, &bbox ); + + time0 = get_time() - time0; + printf( "time = %6.3f cbox = [%8.4f %8.4f %8.4f %8.4f]\n", + ((double)time0/10000.0), + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + printf( "cbox_hex = [%08X %08X %08X %08X]\n", + bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax ); + + + time0 = get_time(); + for ( count = repeat; count > 0; count-- ) + FT_Outline_Get_BBox( outline, &bbox ); + + time0 = get_time() - time0; + printf( "time = %6.3f bbox = [%8.4f %8.4f %8.4f %8.4f]\n", + ((double)time0/10000.0), + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + printf( "bbox_hex = [%08X %08X %08X %08X]\n", + bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax ); + } + +#define REPEAT 1000000L + + int main( int argc, char** argv ) + { + printf( "outline #1\n" ); + profile_outline( &dummy_outline_1, REPEAT ); + + printf( "outline #2\n" ); + profile_outline( &dummy_outline_2, REPEAT ); + + printf( "outline #3\n" ); + profile_outline( &dummy_outline_3, REPEAT ); + + return 0; + } + diff --git a/vendor/freetype/src/tools/test_trig.c b/vendor/freetype/src/tools/test_trig.c new file mode 100644 index 0000000..4f3410a --- /dev/null +++ b/vendor/freetype/src/tools/test_trig.c @@ -0,0 +1,257 @@ +#include +#include + +#include +#include + +#define PI 3.14159265358979323846 +#define SPI (PI/FT_ANGLE_PI) + +/* the precision in 16.16 fixed-point checks. Expect between 2 and 5 */ +/* noise LSB bits during operations, due to rounding errors.. */ +#define THRESHOLD 64 + + static error = 0; + + static void + test_cos( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed f1, f2; + double d2; + + + f1 = FT_Cos(i); + d2 = cos( i*SPI ); + f2 = (FT_Fixed)(d2*65536.0); + + if ( abs( f2-f1 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Cos[%3d] = %.7f cos[%3d] = %.7f\n", + (i >> 16), f1/65536.0, (i >> 16), d2 ); + } + } + } + + + static void + test_sin( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed f1, f2; + double d2; + + + f1 = FT_Sin(i); + d2 = sin( i*SPI ); + f2 = (FT_Fixed)(d2*65536.0); + + if ( abs( f2-f1 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Sin[%3d] = %.7f sin[%3d] = %.7f\n", + (i >> 16), f1/65536.0, (i >> 16), d2 ); + } + } + } + + + static void + test_tan( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_PI2 - 0x2000000L; i += 0x10000L ) + { + FT_Fixed f1, f2; + double d2; + + + f1 = FT_Tan(i); + d2 = tan( i*SPI ); + f2 = (FT_Fixed)(d2*65536.0); + + if ( abs( f2-f1 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Tan[%3d] = %.7f tan[%3d] = %.7f\n", + (i >> 16), f1/65536.0, (i >> 16), d2 ); + } + } + } + + + static void + test_atan2( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed c2, s2; + double l, a, c1, s1; + int j; + + + l = 5.0; + a = i*SPI; + + c1 = l * cos(a); + s1 = l * sin(a); + + c2 = (FT_Fixed)(c1*65536.0); + s2 = (FT_Fixed)(s1*65536.0); + + j = FT_Atan2( c2, s2 ); + if ( j < 0 ) + j += FT_ANGLE_2PI; + + if ( abs( i - j ) > 1 ) + { + printf( "FT_Atan2( %.7f, %.7f ) = %.5f, atan = %.5f\n", + c2/65536.0, s2/65536.0, j/65536.0, i/65536.0 ); + } + } + } + + + static void + test_unit( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Vector v; + double a, c1, s1; + FT_Fixed c2, s2; + + + FT_Vector_Unit( &v, i ); + a = ( i*SPI ); + c1 = cos(a); + s1 = sin(a); + c2 = (FT_Fixed)(c1*65536.0); + s2 = (FT_Fixed)(s1*65536.0); + + if ( abs( v.x-c2 ) > THRESHOLD || + abs( v.y-s2 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Vector_Unit[%3d] = ( %.7f, %.7f ) vec = ( %.7f, %.7f )\n", + (i >> 16), + v.x/65536.0, v.y/65536.0, + c1, s1 ); + } + } + } + + + static void + test_length( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Vector v; + FT_Fixed l, l2; + + + l = (FT_Fixed)(500.0*65536.0); + v.x = (FT_Fixed)( l * cos( i*SPI ) ); + v.y = (FT_Fixed)( l * sin( i*SPI ) ); + l2 = FT_Vector_Length( &v ); + + if ( abs( l2-l ) > THRESHOLD ) + { + error = 1; + printf( "FT_Length( %.7f, %.7f ) = %.5f, length = %.5f\n", + v.x/65536.0, v.y/65536.0, l2/65536.0, l/65536.0 ); + } + } + } + + + static void + test_rotate( void ) + { + int rotate; + + + for ( rotate = 0; rotate < FT_ANGLE_2PI; rotate += 0x10000L ) + { + double ra, cra, sra; + int i; + + + ra = rotate*SPI; + cra = cos( ra ); + sra = sin( ra ); + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed c2, s2, c4, s4; + FT_Vector v; + double l, a, c1, s1, c3, s3; + + + l = 500.0; + a = i*SPI; + + c1 = l * cos(a); + s1 = l * sin(a); + + v.x = c2 = (FT_Fixed)(c1*65536.0); + v.y = s2 = (FT_Fixed)(s1*65536.0); + + FT_Vector_Rotate( &v, rotate ); + + c3 = c1 * cra - s1 * sra; + s3 = c1 * sra + s1 * cra; + + c4 = (FT_Fixed)(c3*65536.0); + s4 = (FT_Fixed)(s3*65536.0); + + if ( abs( c4 - v.x ) > THRESHOLD || + abs( s4 - v.y ) > THRESHOLD ) + { + error = 1; + printf( "FT_Rotate( (%.7f,%.7f), %.5f ) = ( %.7f, %.7f ), rot = ( %.7f, %.7f )\n", + c1, s1, ra, + c2/65536.0, s2/65536.0, + c4/65536.0, s4/65536.0 ); + } + } + } + } + + + int main( void ) + { + test_cos(); + test_sin(); + test_tan(); + test_atan2(); + test_unit(); + test_length(); + test_rotate(); + + if (!error) + printf( "trigonometry test ok !\n" ); + + return !error; + } diff --git a/vendor/freetype/src/tools/update-copyright b/vendor/freetype/src/tools/update-copyright new file mode 100644 index 0000000..674823c --- /dev/null +++ b/vendor/freetype/src/tools/update-copyright @@ -0,0 +1,14 @@ +#!/bin/sh + +# Run the `update-copyright-year' script on all files in the git repository, +# taking care of exceptions stored in file `no-copyright'. + +topdir=`git rev-parse --show-toplevel` +toolsdir=`dirname $0` + +git ls-files --full-name $topdir \ +| sed "s|^|$topdir/|" \ +| grep -vFf $toolsdir/no-copyright \ +| xargs $toolsdir/update-copyright-year + +# EOF diff --git a/vendor/freetype/src/tools/update-copyright-year b/vendor/freetype/src/tools/update-copyright-year new file mode 100644 index 0000000..b0b60fb --- /dev/null +++ b/vendor/freetype/src/tools/update-copyright-year @@ -0,0 +1,157 @@ +eval '(exit $?0)' && eval 'exec perl -wS -i "$0" ${1+"$@"}' + & eval 'exec perl -wS -i "$0" $argv:q' + if 0; + +# Copyright (C) 2015-2023 by +# Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# [Note: This script is expected to be called by the shell, which in turn +# calls perl automatically. The nifty start-up code above is based on +# gnulib's `update-copyright' script; it is a more portable replacement for +# the shebang, using the first `perl' program in the shell's path instead.] + +# Usage: +# +# update-copyright-year file1 [file2 ...] + + +# This script handles copyright entries like +# +# Copyright 2000 by +# foobar +# +# or +# +# /* Copyright (c) 2000, 2001, 2004-2007 by */ +# /* foobar */ +# +# and replaces them uniformly with +# +# Copyright (C) 2000-2021 +# foobar +# +# and +# +# /* Copyright (C) 2000-2021 by */ +# /* foobar */ +# +# (assuming that the current year is 2021). As can be seen, the line length +# is retained if there is non-whitespace after the word `by' on the same +# line. + +use strict; + + +my (undef, undef, undef, + undef, undef, $year, + undef, undef, undef) = localtime(time); +$year += 1900; + +my $replaced = 0; + + +# Loop over all input files; option `-i' (issued at the very beginning of +# this script) makes perl edit them in-place. +while (<>) +{ + # Only handle the first copyright notice in a file. + if (!$replaced) + { + # First try: Search multiple copyright years. + s { + (?.*) + Copyright + (?(\ + + | \ +\(C\)\ +)) + (?[12][0-9][0-9][0-9]) + (?.+) + (?[12][0-9][0-9][0-9]) + (?\ +) + by + (?\ *) + (?.*) + } + { + # Fill line to the same length (if appropriate); we skip the middle + # part but insert `(C)', three spaces, and `-'. + my $space = length($+{space1}) + + length($+{middle}) + + length($+{space2}) + + length($+{space3}) + - (length("(C)") + 3 + 1); + + print "$+{begin}"; + print "Copyright\ (C)\ $+{first}-$year\ by"; + print ' ' x $space if length($+{end}); + print "$+{end}\n"; + $replaced = 1; + }ex + || + # Second try: Search a single copyright year. + s { + (?.*) + Copyright + (?(\ + + | \ +\(C\)\ +)) + (?[12][0-9][0-9][0-9]) + (?\ +) + by + (?\ *) + (?.*) + } + { + if ($+{first} < $year) + { + # Fill line to the same length (if appropriate); we insert three + # spaces, the string `(C)', a `-', and the current year. + my $space = length($+{space1}) + + length($+{space2}) + + length($+{space3}) + - (length($year) + length("(C)") + 3 + 1); + + print "$+{begin}"; + print "Copyright\ (C)\ $+{first}-$year\ by"; + # If $space is negative this inserts nothing. + print ' ' x $space if length($+{end}); + print "$+{end}\n"; + $replaced = 1; + } + else + { + # Fill line to the same length (if appropriate); we insert three + # spaces and the string `(C)'. + my $space = length($+{space1}) + + length($+{space2}) + + length($+{space3}) + - (length("(C)") + 3); + + print "$+{begin}"; + print "Copyright\ (C)\ $+{first}\ by"; + # If $space is negative this inserts nothing. + print ' ' x $space if length($+{end}); + print "$+{end}\n"; + $replaced = 1; + } + }ex + || + # Otherwise print line unaltered. + print; + } + else + { + print; + } +} +continue +{ + # Reset $replaced before processing the next file. + $replaced = 0 if eof; +} + +# EOF diff --git a/vendor/freetype/src/tools/vms_shorten_symbol.c b/vendor/freetype/src/tools/vms_shorten_symbol.c new file mode 100644 index 0000000..81f2a71 --- /dev/null +++ b/vendor/freetype/src/tools/vms_shorten_symbol.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2010, 2017 Craig A. Berry + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* vms_shorten_symbol + * + * This program provides shortening of long symbols (> 31 characters) using the + * same mechanism as the OpenVMS C compiler. The basic procedure is to compute + * an AUTODIN II checksum of the entire symbol, encode the checksum in base32, + * and glue together a shortened symbol from the first 23 characters of the + * original symbol plus the encoded checksum appended. The output format is + * the same used in the name mangler database, stored by default in + * [.CXX_REPOSITORY]CXX$DEMANGLER_DB. + * + * To obtain the same result as CC/NAMES=SHORTENED, run like so: + * + * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name" + * PLEASE_FORGIVE_THIS_ABS1ARO4QU$Please_forgive_this_absurdly_long_symbol_name + * + * To obtain the same result as CC/NAMES=(SHORTENED,AS_IS), pass a non-zero + * value as the second argument, like so: + * + * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name" 1 + * Please_forgive_this_abs3rv8rnn$Please_forgive_this_absurdly_long_symbol_name + */ + +#include +#include +#include +#include + +#ifdef __VMS +#define UINT32 unsigned int +#else +#include +#define UINT32 uint32_t +#endif + +extern UINT32 crc32(const char *input_string); +extern int u32_to_base32(UINT32 input, char *output); +extern int vms_shorten_symbol(const char *symbol, char *shortened, char as_is_flag); + +/* + * This routine implements the AUTODIN II polynomial. + */ + +UINT32 +crc32(const char *input_string) +{ + +/* + * CRC code and data based partly on FreeBSD implementation, which + * notes: + * + * The crc32 functions and data was originally written by Spencer + * Garrett and was cleaned from the PostgreSQL source + * tree via the files contrib/ltree/crc32.[ch]. No license was + * included, therefore it is assumed that this code is public + * domain. Attribution still noted. + * + * (I think they mean "gleaned" not "cleaned".) + */ + + static const UINT32 autodin_ii_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + }; + + UINT32 crc = ~0U; + char *c; + for (c = (char *)input_string; *c; ++c) + crc = (crc >> 8) ^ autodin_ii_table[(crc ^ *c) & 0xff]; + return ~crc; +} + +/* + * This is the RFC2938 variant of base32, not RFC3548, Crockford's, or + * other newer variant. It produces an 8-byte encoded character string + * (plus trailing null) from a 32-bit integer input. + */ + +int +u32_to_base32(UINT32 input, char *output) +{ + static const char base32hex_table[32] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v' + }; + int i; + + /* + * Grab lowest 5 bits and look up conversion in table. Lather, rinse, + * repeat for a total of 7, 5-bit chunks to accommodate 32 bits of input. + */ + for (i = 0; i < 7; i++) { + output[6 - i] = base32hex_table[input & 0x1f]; + input >>= 5; /* position to look at next 5 */ + } + output[7] = '$'; /* It's DEC, so use '$' not '=' to pad. */ + output[8] = '\0'; + return 0; +} + +/* + * Take an input symbol name of arbitrary length and produce a symbol shortened + * to 31 characters. The shortened symbol consists of the first 23 characters + * of the original symbol plus the 8 characters of the encoded checksum. The + * third argument is a boolean indicating whether to emulate the compiler's + * /NAMES=AS_IS option. When false (the compiler's default), the shortened + * symbol will be upper cased. When the original symbol is 31 characters or + * fewer in length, no checksum will be appended and the original symbol is + * returned verbatim (though upper cased if the as_is_flag is false). + */ + +int +vms_shorten_symbol(const char *input_symbol, char *shortened, char as_is_flag) +{ + char b32str[9]; + UINT32 crc; + char *c, *symbol; + int symlen; + + symlen = strlen(input_symbol); + symbol = (char *)malloc(symlen + 1); + if (symbol == NULL) + return -1; + + strncpy(symbol, input_symbol, symlen); + symbol[symlen] = '\0'; + + if (!as_is_flag) { + for (c = symbol; *c; c++) + *c = toupper(*c); + } + + if (symlen <= 31) { + strncpy(shortened, symbol, symlen); + shortened[symlen] = '\0'; + free(symbol); + return 0; + } + + /* + * Compute the checksum on the whole symbol. + */ + + crc = crc32(symbol); + + /* The compiler does not use the inverted checksum, so we invert it + * back before encoding in base32. + */ + + if (u32_to_base32(~crc, (char *)&b32str) == -1) { + free(symbol); + return -1; + } + + if (!as_is_flag) { + for (c = (char *)&b32str; *c; c++) + *c = toupper(*c); + } + + sprintf(shortened, "%.23s%.8s", symbol, b32str); + shortened[31] = '\0'; + free(symbol); + return 0; +} + +#ifdef TEST_MAIN +int +main(int argc, char **argv) +{ + char short_symbol[32]; + char as_is_flag = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s []\n", argv[0]); + exit(EXIT_FAILURE); + } + if (argc > 2) + as_is_flag = 1; + + if (vms_shorten_symbol(argv[1], (char *)&short_symbol, as_is_flag) == -1) { + fprintf(stderr, "Symbol shortening failed\n"); + exit(EXIT_FAILURE); + } + + printf("%s%s\n", (char *)&short_symbol, argv[1]); +} +#endif diff --git a/vendor/freetype/src/truetype/module.mk b/vendor/freetype/src/truetype/module.mk new file mode 100644 index 0000000..5d44ac1 --- /dev/null +++ b/vendor/freetype/src/truetype/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 TrueType module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += TRUETYPE_DRIVER + +define TRUETYPE_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, tt_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)truetype $(ECHO_DRIVER_DESC)Windows/Mac font files with extension *.ttf or *.ttc$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/truetype/rules.mk b/vendor/freetype/src/truetype/rules.mk new file mode 100644 index 0000000..dde26de --- /dev/null +++ b/vendor/freetype/src/truetype/rules.mk @@ -0,0 +1,75 @@ +# +# FreeType 2 TrueType driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# TrueType driver directory +# +TT_DIR := $(SRC_DIR)/truetype + + +# compilation flags for the driver +# +TT_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(TT_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# TrueType driver sources (i.e., C files) +# +TT_DRV_SRC := $(TT_DIR)/ttdriver.c \ + $(TT_DIR)/ttgload.c \ + $(TT_DIR)/ttgxvar.c \ + $(TT_DIR)/ttinterp.c \ + $(TT_DIR)/ttobjs.c \ + $(TT_DIR)/ttpload.c + +# TrueType driver headers +# +TT_DRV_H := $(TT_DRV_SRC:%.c=%.h) \ + $(TT_DIR)/tterrors.h + + +# TrueType driver object(s) +# +# TT_DRV_OBJ_M is used during `multi' builds +# TT_DRV_OBJ_S is used during `single' builds +# +TT_DRV_OBJ_M := $(TT_DRV_SRC:$(TT_DIR)/%.c=$(OBJ_DIR)/%.$O) +TT_DRV_OBJ_S := $(OBJ_DIR)/truetype.$O + +# TrueType driver source file for single build +# +TT_DRV_SRC_S := $(TT_DIR)/truetype.c + + +# TrueType driver - single object +# +$(TT_DRV_OBJ_S): $(TT_DRV_SRC_S) $(TT_DRV_SRC) $(FREETYPE_H) $(TT_DRV_H) + $(TT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(TT_DRV_SRC_S)) + + +# driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(TT_DIR)/%.c $(FREETYPE_H) $(TT_DRV_H) + $(TT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(TT_DRV_OBJ_S) +DRV_OBJS_M += $(TT_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/truetype/truetype.c b/vendor/freetype/src/truetype/truetype.c new file mode 100644 index 0000000..fcc0ea3 --- /dev/null +++ b/vendor/freetype/src/truetype/truetype.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * truetype.c + * + * FreeType TrueType driver component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ttdriver.c" /* driver interface */ +#include "ttgload.c" /* glyph loader */ +#include "ttgxvar.c" /* gx distortable font */ +#include "ttinterp.c" +#include "ttobjs.c" /* object manager */ +#include "ttpload.c" /* tables loader */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttdriver.c b/vendor/freetype/src/truetype/ttdriver.c new file mode 100644 index 0000000..d1496fe --- /dev/null +++ b/vendor/freetype/src/truetype/ttdriver.c @@ -0,0 +1,691 @@ +/**************************************************************************** + * + * ttdriver.c + * + * TrueType font driver implementation (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "ttdriver.h" +#include "ttgload.h" +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttdriver + + + /* + * PROPERTY SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + tt_property_set( FT_Module module, /* TT_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + TT_Driver driver = (TT_Driver)module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "interpreter-version" ) ) + { + FT_UInt interpreter_version; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + + + interpreter_version = (FT_UInt)ft_strtol( s, NULL, 10 ); + } + else +#endif + { + FT_UInt* iv = (FT_UInt*)value; + + + interpreter_version = *iv; + } + + switch ( interpreter_version ) + { + case TT_INTERPRETER_VERSION_35: + driver->interpreter_version = TT_INTERPRETER_VERSION_35; + break; + + case TT_INTERPRETER_VERSION_38: + case TT_INTERPRETER_VERSION_40: +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + driver->interpreter_version = TT_INTERPRETER_VERSION_40; + break; +#endif + + default: + error = FT_ERR( Unimplemented_Feature ); + } + + return error; + } + + FT_TRACE2(( "tt_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_property_get( FT_Module module, /* TT_Driver */ + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + TT_Driver driver = (TT_Driver)module; + + FT_UInt interpreter_version = driver->interpreter_version; + + + if ( !ft_strcmp( property_name, "interpreter-version" ) ) + { + FT_UInt* val = (FT_UInt*)value; + + + *val = interpreter_version; + + return error; + } + + FT_TRACE2(( "tt_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + tt_service_properties, + + tt_property_set, /* FT_Properties_SetFunc set_property */ + tt_property_get /* FT_Properties_GetFunc get_property */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * tt_get_kerning + * + * @Description: + * A driver method used to return the kerning vector between two + * glyphs of the same face. + * + * @Input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * @Output: + * kerning :: + * The kerning vector. This is in font units for + * scalable formats, and in pixels for fixed-sizes + * formats. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only horizontal layouts (left-to-right & right-to-left) are + * supported by this function. Other layouts, or more sophisticated + * kernings, are out of scope of this method (the basic driver + * interface is meant to be simple). + * + * They can be implemented by format-specific interfaces. + */ + FT_CALLBACK_DEF( FT_Error ) + tt_get_kerning( FT_Face face, /* TT_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Face ttface = (TT_Face)face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + + kerning->x = 0; + kerning->y = 0; + + if ( sfnt ) + kerning->x = sfnt->get_kerning( ttface, left_glyph, right_glyph ); + + return 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_get_advances( FT_Face face, /* TT_Face */ + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed *advances ) + { + FT_UInt nn; + TT_Face ttface = (TT_Face)face; + + + /* XXX: TODO: check for sbits */ + + if ( flags & FT_LOAD_VERTICAL_LAYOUT ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + for ( nn = 0; nn < count; nn++ ) + { + FT_Short tsb; + FT_UShort ah; + + + /* since we don't need `tsb', we use zero for `yMax' parameter */ + TT_Get_VMetrics( ttface, start + nn, 0, &tsb, &ah ); + advances[nn] = ah; + } + } + else + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + for ( nn = 0; nn < count; nn++ ) + { + FT_Short lsb; + FT_UShort aw; + + + TT_Get_HMetrics( ttface, start + nn, &lsb, &aw ); + advances[nn] = aw; + } + } + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S I Z E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_CALLBACK_DEF( FT_Error ) + tt_size_select( FT_Size size, + FT_ULong strike_index ) + { + TT_Face ttface = (TT_Face)size->face; + TT_Size ttsize = (TT_Size)size; + FT_Error error = FT_Err_Ok; + + + ttsize->strike_index = strike_index; + + if ( FT_IS_SCALABLE( size->face ) ) + { + /* use the scaled metrics, even when tt_size_reset fails */ + FT_Select_Metrics( size->face, strike_index ); + + tt_size_reset( ttsize ); /* ignore return value */ + } + else + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + FT_Size_Metrics* size_metrics = &size->metrics; + + + error = sfnt->load_strike_metrics( ttface, + strike_index, + size_metrics ); + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + } + + return error; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + FT_CALLBACK_DEF( FT_Error ) + tt_size_request( FT_Size size, + FT_Size_Request req ) + { + TT_Size ttsize = (TT_Size)size; + FT_Error error = FT_Err_Ok; + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + TT_Face ttface = (TT_Face)size->face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + FT_ULong strike_index; + + + error = sfnt->set_sbit_strike( ttface, req, &strike_index ); + + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + else + return tt_size_select( size, strike_index ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + { + FT_Error err = FT_Request_Metrics( size->face, req ); + + + if ( err ) + { + error = err; + goto Exit; + } + } + + if ( FT_IS_SCALABLE( size->face ) ) + { + error = tt_size_reset( ttsize ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + /* for the `MPS' bytecode instruction we need the point size */ + if ( !error ) + { + FT_UInt resolution = + ttsize->metrics->x_ppem > ttsize->metrics->y_ppem + ? req->horiResolution + : req->vertResolution; + + + /* if we don't have a resolution value, assume 72dpi */ + if ( req->type == FT_SIZE_REQUEST_TYPE_SCALES || + !resolution ) + resolution = 72; + + ttsize->point_size = FT_MulDiv( ttsize->ttmetrics.ppem, + 64 * 72, + resolution ); + } +#endif + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_glyph_load + * + * @Description: + * A driver method used to load a glyph within a given glyph slot. + * + * @Input: + * slot :: + * A handle to the target slot object where the glyph + * will be loaded. + * + * size :: + * A handle to the source face size at which the glyph + * must be scaled, loaded, etc. + * + * glyph_index :: + * The index of the glyph in the font file. + * + * load_flags :: + * A flag indicating what to load for this glyph. The + * FT_LOAD_XXX constants can be used to control the + * glyph loading process (e.g., whether the outline + * should be scaled, whether to load bitmaps or not, + * whether to hint the outline, etc). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_CALLBACK_DEF( FT_Error ) + tt_glyph_load( FT_GlyphSlot slot, /* TT_GlyphSlot */ + FT_Size size, /* TT_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_GlyphSlot ttslot = (TT_GlyphSlot)slot; + TT_Size ttsize = (TT_Size)size; + FT_Face face = ttslot->face; + FT_Error error; + + + if ( !slot ) + return FT_THROW( Invalid_Slot_Handle ); + + if ( !size ) + return FT_THROW( Invalid_Size_Handle ); + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( glyph_index >= (FT_UInt)face->num_glyphs && + !face->internal->incremental_interface ) +#else + if ( glyph_index >= (FT_UInt)face->num_glyphs ) +#endif + return FT_THROW( Invalid_Argument ); + + if ( load_flags & FT_LOAD_NO_HINTING ) + { + /* both FT_LOAD_NO_HINTING and FT_LOAD_NO_AUTOHINT */ + /* are necessary to disable hinting for tricky fonts */ + + if ( FT_IS_TRICKY( face ) ) + load_flags &= ~FT_LOAD_NO_HINTING; + + if ( load_flags & FT_LOAD_NO_AUTOHINT ) + load_flags |= FT_LOAD_NO_HINTING; + } + + if ( load_flags & ( FT_LOAD_NO_RECURSE | FT_LOAD_NO_SCALE ) ) + { + load_flags |= FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE; + + if ( !FT_IS_TRICKY( face ) ) + load_flags |= FT_LOAD_NO_HINTING; + } + + /* use hinted metrics only if we load a glyph with hinting */ + ttsize->metrics = ( load_flags & FT_LOAD_NO_HINTING ) + ? &size->metrics + : &ttsize->hinted_metrics; + + /* now fill in the glyph slot with outline/bitmap/layered */ + error = TT_Load_Glyph( ttsize, ttslot, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + FT_DEFINE_SERVICE_MULTIMASTERSREC( + tt_service_gx_multi_masters, + + NULL, /* FT_Get_MM_Func get_mm */ + NULL, /* FT_Set_MM_Design_Func set_mm_design */ + TT_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + TT_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + TT_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */ + TT_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */ + TT_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */ + TT_Set_Named_Instance, /* FT_Set_Named_Instance_Func set_named_instance */ + TT_Get_Default_Named_Instance, + /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + NULL, /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + NULL, /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ + + tt_construct_ps_name, /* FT_Construct_PS_Name_Func construct_ps_name */ + tt_var_load_delta_set_index_mapping, + /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + tt_var_load_item_variation_store, + /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + tt_var_get_item_delta, /* FT_Var_Get_Item_Delta_Func get_item_delta */ + tt_var_done_item_variation_store, + /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + tt_var_done_delta_set_index_map, + /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + tt_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */ + tt_done_blend /* FT_Done_Blend_Func done_blend */ + ) + + FT_DEFINE_SERVICE_METRICSVARIATIONSREC( + tt_service_metrics_variations, + + tt_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */ + NULL, /* FT_LSB_Adjust_Func lsb_adjust */ + NULL, /* FT_RSB_Adjust_Func rsb_adjust */ + + tt_vadvance_adjust, /* FT_VAdvance_Adjust_Func vadvance_adjust */ + NULL, /* FT_TSB_Adjust_Func tsb_adjust */ + NULL, /* FT_BSB_Adjust_Func bsb_adjust */ + NULL, /* FT_VOrg_Adjust_Func vorg_adjust */ + + tt_apply_mvar, /* FT_Metrics_Adjust_Func metrics_adjust */ + tt_size_reset_height /* FT_Size_Reset_Func size_reset */ + ) + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine = + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_TRUETYPE_ENGINE_TYPE_PATENTED + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_TRUETYPE_ENGINE_TYPE_NONE + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + }; + + + FT_DEFINE_SERVICE_TTGLYFREC( + tt_service_truetype_glyf, + + (TT_Glyf_GetLocationFunc)tt_face_get_location /* get_location */ + ) + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_DEFINE_SERVICEDESCREC6( + tt_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, + FT_SERVICE_ID_MULTI_MASTERS, &tt_service_gx_multi_masters, + FT_SERVICE_ID_METRICS_VARIATIONS, &tt_service_metrics_variations, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf, + FT_SERVICE_ID_PROPERTIES, &tt_service_properties ) +#else + FT_DEFINE_SERVICEDESCREC4( + tt_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf, + FT_SERVICE_ID_PROPERTIES, &tt_service_properties ) +#endif + + + FT_CALLBACK_DEF( FT_Module_Interface ) + tt_get_interface( FT_Module driver, /* TT_Driver */ + const char* tt_interface ) + { + FT_Library library; + FT_Module_Interface result; + FT_Module sfntd; + SFNT_Service sfnt; + + + result = ft_service_list_lookup( tt_services, tt_interface ); + if ( result ) + return result; + + if ( !driver ) + return NULL; + library = driver->library; + if ( !library ) + return NULL; + + /* only return the default interface from the SFNT module */ + sfntd = FT_Get_Module( library, "sfnt" ); + if ( sfntd ) + { + sfnt = (SFNT_Service)( sfntd->clazz->module_interface ); + if ( sfnt ) + return sfnt->get_interface( driver, tt_interface ); + } + + return 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + +#ifdef TT_USE_BYTECODE_INTERPRETER +#define TT_HINTER_FLAG FT_MODULE_DRIVER_HAS_HINTER +#else +#define TT_HINTER_FLAG 0 +#endif + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#define TT_SIZE_SELECT tt_size_select +#else +#define TT_SIZE_SELECT 0 +#endif + + FT_DEFINE_DRIVER( + tt_driver_class, + + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + TT_HINTER_FLAG, + + sizeof ( TT_DriverRec ), + + "truetype", /* driver name */ + 0x10000L, /* driver version == 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or above */ + + NULL, /* module-specific interface */ + + tt_driver_init, /* FT_Module_Constructor module_init */ + tt_driver_done, /* FT_Module_Destructor module_done */ + tt_get_interface, /* FT_Module_Requester get_interface */ + + sizeof ( TT_FaceRec ), + sizeof ( TT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + tt_face_init, /* FT_Face_InitFunc init_face */ + tt_face_done, /* FT_Face_DoneFunc done_face */ + tt_size_init, /* FT_Size_InitFunc init_size */ + tt_size_done, /* FT_Size_DoneFunc done_size */ + tt_slot_init, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + tt_glyph_load, /* FT_Slot_LoadFunc load_glyph */ + + tt_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + tt_get_advances, /* FT_Face_GetAdvancesFunc get_advances */ + + tt_size_request, /* FT_Size_RequestFunc request_size */ + TT_SIZE_SELECT /* FT_Size_SelectFunc select_size */ + ) + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttdriver.h b/vendor/freetype/src/truetype/ttdriver.h new file mode 100644 index 0000000..757a66f --- /dev/null +++ b/vendor/freetype/src/truetype/ttdriver.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * ttdriver.h + * + * High-level TrueType driver interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTDRIVER_H_ +#define TTDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_DRIVER( tt_driver_class ) + +FT_END_HEADER + +#endif /* TTDRIVER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/tterrors.h b/vendor/freetype/src/truetype/tterrors.h new file mode 100644 index 0000000..008ee99 --- /dev/null +++ b/vendor/freetype/src/truetype/tterrors.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * tterrors.h + * + * TrueType error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the TrueType error enumeration + * constants. + * + */ + +#ifndef TTERRORS_H_ +#define TTERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX TT_Err_ +#define FT_ERR_BASE FT_Mod_Err_TrueType + +#include + +#endif /* TTERRORS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttgload.c b/vendor/freetype/src/truetype/ttgload.c new file mode 100644 index 0000000..dc427e8 --- /dev/null +++ b/vendor/freetype/src/truetype/ttgload.c @@ -0,0 +1,2743 @@ +/**************************************************************************** + * + * ttgload.c + * + * TrueType Glyph Loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include +#include +#include + +#include "ttgload.h" +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttgload + + + /************************************************************************** + * + * Simple glyph flags. + */ +#define ON_CURVE_POINT 0x01 /* same value as FT_CURVE_TAG_ON */ +#define X_SHORT_VECTOR 0x02 +#define Y_SHORT_VECTOR 0x04 +#define REPEAT_FLAG 0x08 +#define X_POSITIVE 0x10 /* two meanings depending on X_SHORT_VECTOR */ +#define SAME_X 0x10 +#define Y_POSITIVE 0x20 /* two meanings depending on Y_SHORT_VECTOR */ +#define SAME_Y 0x20 +#define OVERLAP_SIMPLE 0x40 /* retained as FT_OUTLINE_OVERLAP */ + + + /************************************************************************** + * + * Composite glyph flags. + */ +#define ARGS_ARE_WORDS 0x0001 +#define ARGS_ARE_XY_VALUES 0x0002 +#define ROUND_XY_TO_GRID 0x0004 +#define WE_HAVE_A_SCALE 0x0008 +/* reserved 0x0010 */ +#define MORE_COMPONENTS 0x0020 +#define WE_HAVE_AN_XY_SCALE 0x0040 +#define WE_HAVE_A_2X2 0x0080 +#define WE_HAVE_INSTR 0x0100 +#define USE_MY_METRICS 0x0200 +#define OVERLAP_COMPOUND 0x0400 /* retained as FT_OUTLINE_OVERLAP */ +#define SCALED_COMPONENT_OFFSET 0x0800 +#define UNSCALED_COMPONENT_OFFSET 0x1000 + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#define IS_DEFAULT_INSTANCE( _face ) \ + ( !( FT_IS_NAMED_INSTANCE( _face ) || \ + FT_IS_VARIATION( _face ) ) ) +#else +#define IS_DEFAULT_INSTANCE( _face ) 1 +#endif + + + /************************************************************************** + * + * Return the horizontal metrics in font units for a given glyph. + */ + FT_LOCAL_DEF( void ) + TT_Get_HMetrics( TT_Face face, + FT_UInt idx, + FT_Short* lsb, + FT_UShort* aw ) + { + ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw ); + + FT_TRACE5(( " advance width (font units): %d\n", *aw )); + FT_TRACE5(( " left side bearing (font units): %d\n", *lsb )); + } + + + /************************************************************************** + * + * Return the vertical metrics in font units for a given glyph. + * See function `tt_loader_set_pp' below for explanations. + */ + FT_LOCAL_DEF( void ) + TT_Get_VMetrics( TT_Face face, + FT_UInt idx, + FT_Pos yMax, + FT_Short* tsb, + FT_UShort* ah ) + { + if ( face->vertical_info ) + ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah ); + + else if ( face->os2.version != 0xFFFFU ) + { + *tsb = (FT_Short)( face->os2.sTypoAscender - yMax ); + *ah = (FT_UShort)FT_ABS( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + } + + else + { + *tsb = (FT_Short)( face->horizontal.Ascender - yMax ); + *ah = (FT_UShort)FT_ABS( face->horizontal.Ascender - + face->horizontal.Descender ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !face->vertical_info ) + FT_TRACE5(( " [vertical metrics missing, computing values]\n" )); +#endif + + FT_TRACE5(( " advance height (font units): %d\n", *ah )); + FT_TRACE5(( " top side bearing (font units): %d\n", *tsb )); + } + + + static FT_Error + tt_get_metrics( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = loader->face; + + FT_Error error; + FT_Stream stream = loader->stream; + + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; + + /* we must preserve the stream position */ + /* (which gets altered by the metrics functions) */ + FT_ULong pos = FT_STREAM_POS(); + + + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + loader->bbox.yMax, + &top_bearing, + &advance_height ); + + if ( FT_STREAM_SEEK( pos ) ) + return error; + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* With the incremental interface, these values are set by */ + /* a call to `tt_get_metrics_incremental'. */ + if ( face->root.internal->incremental_interface == NULL ) +#endif + { + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } + } + + return FT_Err_Ok; + } + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + static void + tt_get_metrics_incremental( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = loader->face; + + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; + + + /* If this is an incrementally loaded font check whether there are */ + /* overriding metrics for this glyph. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec incr_metrics; + FT_Error error; + + + incr_metrics.bearing_x = loader->left_bearing; + incr_metrics.bearing_y = 0; + incr_metrics.advance = loader->advance; + incr_metrics.advance_v = 0; + + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &incr_metrics ); + if ( error ) + goto Exit; + + left_bearing = (FT_Short)incr_metrics.bearing_x; + advance_width = (FT_UShort)incr_metrics.advance; + +#if 0 + + /* GWW: Do I do the same for vertical metrics? */ + incr_metrics.bearing_x = 0; + incr_metrics.bearing_y = loader->top_bearing; + incr_metrics.advance = loader->vadvance; + + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, TRUE, &incr_metrics ); + if ( error ) + goto Exit; + + top_bearing = (FT_Short)incr_metrics.bearing_y; + advance_height = (FT_UShort)incr_metrics.advance; + +#endif /* 0 */ + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } + } + + Exit: + return; + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + + /************************************************************************** + * + * The following functions are used by default with TrueType fonts. + * However, they can be replaced by alternatives if we need to support + * TrueType-compressed formats (like MicroType) in the future. + * + */ + + FT_CALLBACK_DEF( FT_Error ) + TT_Access_Glyph_Frame( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ) + { + FT_Error error; + FT_Stream stream = loader->stream; + + FT_UNUSED( glyph_index ); + + + /* the following line sets the `error' variable through macros! */ + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) ) + return error; + + loader->cursor = stream->cursor; + loader->limit = stream->limit; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + TT_Forget_Glyph_Frame( TT_Loader loader ) + { + FT_Stream stream = loader->stream; + + + FT_FRAME_EXIT(); + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Glyph_Header( TT_Loader loader ) + { + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + + + if ( p + 10 > limit ) + return FT_THROW( Invalid_Outline ); + + loader->n_contours = FT_NEXT_SHORT( p ); + + loader->bbox.xMin = FT_NEXT_SHORT( p ); + loader->bbox.yMin = FT_NEXT_SHORT( p ); + loader->bbox.xMax = FT_NEXT_SHORT( p ); + loader->bbox.yMax = FT_NEXT_SHORT( p ); + + FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); + FT_TRACE5(( " xMin: %4ld xMax: %4ld\n", loader->bbox.xMin, + loader->bbox.xMax )); + FT_TRACE5(( " yMin: %4ld yMax: %4ld\n", loader->bbox.yMin, + loader->bbox.yMax )); + loader->cursor = p; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Simple_Glyph( TT_Loader load ) + { + FT_Error error; + FT_Byte* p = load->cursor; + FT_Byte* limit = load->limit; + FT_GlyphLoader gloader = load->gloader; + FT_Outline* outline = &gloader->current.outline; + FT_Int n_contours = load->n_contours; + FT_Int n_points; + FT_UShort n_ins; + + FT_Byte *flag, *flag_limit; + FT_Byte c, count; + FT_Vector *vec, *vec_limit; + FT_Pos x, y; + FT_Short *cont, *cont_limit, last; + + + /* check that we can add the contours to the glyph */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, 0, n_contours ); + if ( error ) + goto Fail; + + /* check space for contours array + instructions count */ + if ( n_contours >= 0xFFF || p + 2 * n_contours + 2 > limit ) + goto Invalid_Outline; + + /* reading the contours' endpoints & number of points */ + cont = outline->contours; + cont_limit = cont + n_contours; + + last = -1; + for ( ; cont < cont_limit; cont++ ) + { + *cont = FT_NEXT_SHORT( p ); + + if ( *cont <= last ) + goto Invalid_Outline; + + last = *cont; + } + + n_points = last + 1; + + FT_TRACE5(( " # of points: %d\n", n_points )); + + /* note that we will add four phantom points later */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, n_points + 4, 0 ); + if ( error ) + goto Fail; + + /* space checked above */ + n_ins = FT_NEXT_USHORT( p ); + + FT_TRACE5(( " Instructions size: %u\n", n_ins )); + + /* check instructions size */ + if ( p + n_ins > limit ) + { + FT_TRACE1(( "TT_Load_Simple_Glyph: excessive instruction count\n" )); + error = FT_THROW( Too_Many_Hints ); + goto Fail; + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( IS_HINTED( load->load_flags ) ) + { + TT_ExecContext exec = load->exec; + FT_Memory memory = exec->memory; + + + if ( exec->glyphSize ) + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + /* we don't trust `maxSizeOfInstructions' in the `maxp' table */ + /* and thus allocate the bytecode array size by ourselves */ + if ( n_ins ) + { + if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) ) + return error; + + FT_MEM_COPY( exec->glyphIns, p, (FT_Long)n_ins ); + + exec->glyphSize = n_ins; + } + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + p += n_ins; + + /* reading the point tags */ + flag = (FT_Byte*)outline->tags; + flag_limit = flag + n_points; + + FT_ASSERT( flag ); + + while ( flag < flag_limit ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + *flag++ = c = FT_NEXT_BYTE( p ); + if ( c & REPEAT_FLAG ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + count = FT_NEXT_BYTE( p ); + if ( flag + (FT_Int)count > flag_limit ) + goto Invalid_Outline; + + for ( ; count > 0; count-- ) + *flag++ = c; + } + } + + /* retain the overlap flag */ + if ( n_points && outline->tags[0] & OVERLAP_SIMPLE ) + gloader->base.outline.flags |= FT_OUTLINE_OVERLAP; + + /* reading the X coordinates */ + + vec = outline->points; + vec_limit = vec + n_points; + flag = (FT_Byte*)outline->tags; + x = 0; + + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos delta = 0; + FT_Byte f = *flag; + + + if ( f & X_SHORT_VECTOR ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_BYTE( p ); + if ( !( f & X_POSITIVE ) ) + delta = -delta; + } + else if ( !( f & SAME_X ) ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_SHORT( p ); + } + + x += delta; + vec->x = x; + } + + /* reading the Y coordinates */ + + vec = outline->points; + vec_limit = vec + n_points; + flag = (FT_Byte*)outline->tags; + y = 0; + + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos delta = 0; + FT_Byte f = *flag; + + + if ( f & Y_SHORT_VECTOR ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_BYTE( p ); + if ( !( f & Y_POSITIVE ) ) + delta = -delta; + } + else if ( !( f & SAME_Y ) ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_SHORT( p ); + } + + y += delta; + vec->y = y; + + /* the cast is for stupid compilers */ + *flag = (FT_Byte)( f & ON_CURVE_POINT ); + } + + outline->n_points = (FT_Short)n_points; + outline->n_contours = (FT_Short)n_contours; + + load->cursor = p; + + Fail: + return error; + + Invalid_Outline: + error = FT_THROW( Invalid_Outline ); + goto Fail; + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Composite_Glyph( TT_Loader loader ) + { + FT_Error error; + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + FT_GlyphLoader gloader = loader->gloader; + FT_Long num_glyphs = loader->face->root.num_glyphs; + FT_SubGlyph subglyph; + FT_UInt num_subglyphs; + + + num_subglyphs = 0; + + do + { + FT_Fixed xx, xy, yy, yx; + FT_UInt count; + + + /* check that we can load a new subglyph */ + error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 ); + if ( error ) + goto Fail; + + /* check space */ + if ( p + 4 > limit ) + goto Invalid_Composite; + + subglyph = gloader->current.subglyphs + num_subglyphs; + + subglyph->arg1 = subglyph->arg2 = 0; + + subglyph->flags = FT_NEXT_USHORT( p ); + subglyph->index = FT_NEXT_USHORT( p ); + + /* we reject composites that have components */ + /* with invalid glyph indices */ + if ( subglyph->index >= num_glyphs ) + goto Invalid_Composite; + + /* check space */ + count = 2; + if ( subglyph->flags & ARGS_ARE_WORDS ) + count += 2; + if ( subglyph->flags & WE_HAVE_A_SCALE ) + count += 2; + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + count += 4; + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + count += 8; + + if ( p + count > limit ) + goto Invalid_Composite; + + /* read arguments */ + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + { + if ( subglyph->flags & ARGS_ARE_WORDS ) + { + subglyph->arg1 = FT_NEXT_SHORT( p ); + subglyph->arg2 = FT_NEXT_SHORT( p ); + } + else + { + subglyph->arg1 = FT_NEXT_CHAR( p ); + subglyph->arg2 = FT_NEXT_CHAR( p ); + } + } + else + { + if ( subglyph->flags & ARGS_ARE_WORDS ) + { + subglyph->arg1 = (FT_Int)FT_NEXT_USHORT( p ); + subglyph->arg2 = (FT_Int)FT_NEXT_USHORT( p ); + } + else + { + subglyph->arg1 = (FT_Int)FT_NEXT_BYTE( p ); + subglyph->arg2 = (FT_Int)FT_NEXT_BYTE( p ); + } + } + + /* read transform */ + xx = yy = 0x10000L; + xy = yx = 0; + + if ( subglyph->flags & WE_HAVE_A_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yy = xx; + } + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + } + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + xy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + } + + subglyph->transform.xx = xx; + subglyph->transform.xy = xy; + subglyph->transform.yx = yx; + subglyph->transform.yy = yy; + + num_subglyphs++; + + } while ( subglyph->flags & MORE_COMPONENTS ); + + gloader->current.num_subglyphs = num_subglyphs; + FT_TRACE5(( " %d component%s\n", + num_subglyphs, + num_subglyphs > 1 ? "s" : "" )); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + subglyph = gloader->current.subglyphs; + + for ( i = 0; i < num_subglyphs; i++ ) + { + if ( num_subglyphs > 1 ) + FT_TRACE7(( " subglyph %d:\n", i )); + + FT_TRACE7(( " glyph index: %d\n", subglyph->index )); + + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + FT_TRACE7(( " offset: x=%d, y=%d\n", + subglyph->arg1, + subglyph->arg2 )); + else + FT_TRACE7(( " matching points: base=%d, component=%d\n", + subglyph->arg1, + subglyph->arg2 )); + + if ( subglyph->flags & WE_HAVE_A_SCALE ) + FT_TRACE7(( " scaling: %f\n", + (double)subglyph->transform.xx / 65536 )); + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + FT_TRACE7(( " scaling: x=%f, y=%f\n", + (double)subglyph->transform.xx / 65536, + (double)subglyph->transform.yy / 65536 )); + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + { + FT_TRACE7(( " scaling: xx=%f, yx=%f\n", + (double)subglyph->transform.xx / 65536, + (double)subglyph->transform.yx / 65536 )); + FT_TRACE7(( " xy=%f, yy=%f\n", + (double)subglyph->transform.xy / 65536, + (double)subglyph->transform.yy / 65536 )); + } + + subglyph++; + } + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + { + FT_Stream stream = loader->stream; + + + /* we must undo the FT_FRAME_ENTER in order to point */ + /* to the composite instructions, if we find some. */ + /* We will process them later. */ + /* */ + loader->ins_pos = (FT_ULong)( FT_STREAM_POS() + + p - limit ); + } + +#endif + + loader->cursor = p; + + Fail: + return error; + + Invalid_Composite: + error = FT_THROW( Invalid_Composite ); + goto Fail; + } + + + FT_LOCAL_DEF( void ) + TT_Init_Glyph_Loading( TT_Face face ) + { + face->access_glyph_frame = TT_Access_Glyph_Frame; + face->read_glyph_header = TT_Load_Glyph_Header; + face->read_simple_glyph = TT_Load_Simple_Glyph; + face->read_composite_glyph = TT_Load_Composite_Glyph; + face->forget_glyph_frame = TT_Forget_Glyph_Frame; + } + + + static void + tt_prepare_zone( TT_GlyphZone zone, + FT_GlyphLoad load, + FT_UInt start_point, + FT_UInt start_contour ) + { + zone->n_points = (FT_UShort)load->outline.n_points + 4 - + (FT_UShort)start_point; + zone->n_contours = load->outline.n_contours - + (FT_Short)start_contour; + zone->org = load->extra_points + start_point; + zone->cur = load->outline.points + start_point; + zone->orus = load->extra_points2 + start_point; + zone->tags = (FT_Byte*)load->outline.tags + start_point; + zone->contours = (FT_UShort*)load->outline.contours + start_contour; + zone->first_point = (FT_UShort)start_point; + } + + + /************************************************************************** + * + * @Function: + * TT_Hint_Glyph + * + * @Description: + * Hint the glyph using the zone prepared by the caller. Note that + * the zone is supposed to include four phantom points. + */ + static FT_Error + TT_Hint_Glyph( TT_Loader loader, + FT_Bool is_composite ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + TT_Face face = loader->face; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); +#endif + + TT_GlyphZone zone = &loader->zone; + +#ifdef TT_USE_BYTECODE_INTERPRETER + TT_ExecContext exec = loader->exec; + FT_Long n_ins = exec->glyphSize; +#else + FT_UNUSED( is_composite ); +#endif + + +#ifdef TT_USE_BYTECODE_INTERPRETER + /* save original point positions in `org' array */ + if ( n_ins > 0 ) + FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); + + /* Reset graphics state. */ + exec->GS = loader->size->GS; + + /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */ + /* completely refer to the (already) hinted subglyphs. */ + if ( is_composite ) + { + exec->metrics.x_scale = 1 << 16; + exec->metrics.y_scale = 1 << 16; + + FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points ); + } + else + { + exec->metrics.x_scale = loader->size->metrics->x_scale; + exec->metrics.y_scale = loader->size->metrics->y_scale; + } +#endif + + /* round phantom points */ + zone->cur[zone->n_points - 4].x = + FT_PIX_ROUND( zone->cur[zone->n_points - 4].x ); + zone->cur[zone->n_points - 3].x = + FT_PIX_ROUND( zone->cur[zone->n_points - 3].x ); + zone->cur[zone->n_points - 2].y = + FT_PIX_ROUND( zone->cur[zone->n_points - 2].y ); + zone->cur[zone->n_points - 1].y = + FT_PIX_ROUND( zone->cur[zone->n_points - 1].y ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( n_ins > 0 ) + { + FT_Error error; + + + TT_Set_CodeRange( exec, tt_coderange_glyph, exec->glyphIns, n_ins ); + + exec->is_composite = is_composite; + exec->pts = *zone; + + error = TT_Run_Context( exec ); + if ( error && exec->pedantic_hinting ) + return error; + + /* store drop-out mode in bits 5-7; set bit 2 also as a marker */ + loader->gloader->current.outline.tags[0] |= + ( exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE; + } + +#endif + + /* Save possibly modified glyph phantom points unless in v40 backward */ + /* compatibility mode, where no movement on the x axis means no reason */ + /* to change bearings or advance widths. */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + exec->backward_compatibility ) + return FT_Err_Ok; +#endif + + loader->pp1 = zone->cur[zone->n_points - 4]; + loader->pp2 = zone->cur[zone->n_points - 3]; + loader->pp3 = zone->cur[zone->n_points - 2]; + loader->pp4 = zone->cur[zone->n_points - 1]; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Process_Simple_Glyph + * + * @Description: + * Once a simple glyph has been loaded, it needs to be processed. + * Usually, this means scaling and hinting through bytecode + * interpretation. + */ + static FT_Error + TT_Process_Simple_Glyph( TT_Loader loader ) + { + FT_Error error = FT_Err_Ok; + FT_GlyphLoader gloader = loader->gloader; + FT_Outline* outline = &gloader->current.outline; + FT_Int n_points = outline->n_points; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Memory memory = loader->face->root.memory; + FT_Vector* unrounded = NULL; +#endif + + + /* set phantom points */ + outline->points[n_points ] = loader->pp1; + outline->points[n_points + 1] = loader->pp2; + outline->points[n_points + 2] = loader->pp3; + outline->points[n_points + 3] = loader->pp4; + + n_points += 4; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) ) + { + if ( FT_QNEW_ARRAY( unrounded, n_points ) ) + goto Exit; + + /* Deltas apply to the unscaled data. */ + error = TT_Vary_Apply_Glyph_Deltas( loader, + outline, + unrounded ); + if ( error ) + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + if ( IS_HINTED( loader->load_flags ) ) + { + tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 ); + + FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur, + loader->zone.n_points ); + } + + { + FT_Vector* vec = outline->points; + FT_Vector* limit = outline->points + n_points; + + FT_Fixed x_scale = 0; /* pacify compiler */ + FT_Fixed y_scale = 0; + + FT_Bool do_scale = FALSE; + + + { + /* scale the glyph */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + x_scale = loader->size->metrics->x_scale; + y_scale = loader->size->metrics->y_scale; + + do_scale = TRUE; + } + } + + if ( do_scale ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) ) + { + FT_Vector* u = unrounded; + + + for ( ; vec < limit; vec++, u++ ) + { + vec->x = ADD_LONG( FT_MulFix( u->x, x_scale ), 32 ) >> 6; + vec->y = ADD_LONG( FT_MulFix( u->y, y_scale ), 32 ) >> 6; + } + } + else +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + { + for ( ; vec < limit; vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + } + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* if we have a HVAR table, `pp1' and/or `pp2' */ + /* are already adjusted but unscaled */ + if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) && + IS_HINTED( loader->load_flags ) ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + } + else +#endif + { + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* if we have a VVAR table, `pp3' and/or `pp4' */ + /* are already adjusted but unscaled */ + if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) && + IS_HINTED( loader->load_flags ) ) + { + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + else +#endif + { + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + } + } + + if ( IS_HINTED( loader->load_flags ) ) + error = TT_Hint_Glyph( loader, 0 ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + Exit: + FT_FREE( unrounded ); +#endif + + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Process_Composite_Component + * + * @Description: + * Once a composite component has been loaded, it needs to be + * processed. Usually, this means transforming and translating. + */ + static FT_Error + TT_Process_Composite_Component( TT_Loader loader, + FT_SubGlyph subglyph, + FT_UInt start_point, + FT_UInt num_base_points ) + { + FT_GlyphLoader gloader = loader->gloader; + FT_Outline current; + FT_Bool have_scale; + FT_Pos x, y; + + + current.points = gloader->base.outline.points + + num_base_points; + current.n_points = gloader->base.outline.n_points - + (short)num_base_points; + + have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | + WE_HAVE_AN_XY_SCALE | + WE_HAVE_A_2X2 ) ); + + /* perform the transform required for this subglyph */ + if ( have_scale ) + FT_Outline_Transform( ¤t, &subglyph->transform ); + + /* get offset */ + if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) + { + FT_UInt num_points = (FT_UInt)gloader->base.outline.n_points; + FT_UInt k = (FT_UInt)subglyph->arg1; + FT_UInt l = (FT_UInt)subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; + + + /* match l-th point of the newly loaded component to the k-th point */ + /* of the previously loaded components. */ + + /* change to the point numbers used by our outline */ + k += start_point; + l += num_base_points; + if ( k >= num_base_points || + l >= num_points ) + return FT_THROW( Invalid_Composite ); + + p1 = gloader->base.outline.points + k; + p2 = gloader->base.outline.points + l; + + x = SUB_LONG( p1->x, p2->x ); + y = SUB_LONG( p1->y, p2->y ); + } + else + { + x = subglyph->arg1; + y = subglyph->arg2; + + if ( !x && !y ) + return FT_Err_Ok; + + /* Use a default value dependent on */ + /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old */ + /* TT fonts which don't set the xxx_COMPONENT_OFFSET bit. */ + + if ( have_scale && +#ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + !( subglyph->flags & UNSCALED_COMPONENT_OFFSET ) ) +#else + ( subglyph->flags & SCALED_COMPONENT_OFFSET ) ) +#endif + { + +#if 0 + + /******************************************************************** + * + * This algorithm is what Apple documents. But it doesn't work. + */ + int a = subglyph->transform.xx > 0 ? subglyph->transform.xx + : -subglyph->transform.xx; + int b = subglyph->transform.yx > 0 ? subglyph->transform.yx + : -subglyph->transform.yx; + int c = subglyph->transform.xy > 0 ? subglyph->transform.xy + : -subglyph->transform.xy; + int d = subglyph->transform.yy > 0 ? subglyph->transform.yy + : -subglyph->transform.yy; + int m = a > b ? a : b; + int n = c > d ? c : d; + + + if ( a - b <= 33 && a - b >= -33 ) + m *= 2; + if ( c - d <= 33 && c - d >= -33 ) + n *= 2; + x = FT_MulFix( x, m ); + y = FT_MulFix( y, n ); + +#else /* 1 */ + + /******************************************************************** + * + * This algorithm is a guess and works much better than the above. + */ + FT_Fixed mac_xscale = FT_Hypot( subglyph->transform.xx, + subglyph->transform.xy ); + FT_Fixed mac_yscale = FT_Hypot( subglyph->transform.yy, + subglyph->transform.yx ); + + + x = FT_MulFix( x, mac_xscale ); + y = FT_MulFix( y, mac_yscale ); + +#endif /* 1 */ + + } + + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + FT_Fixed x_scale = loader->size->metrics->x_scale; + FT_Fixed y_scale = loader->size->metrics->y_scale; + + + x = FT_MulFix( x, x_scale ); + y = FT_MulFix( y, y_scale ); + + if ( subglyph->flags & ROUND_XY_TO_GRID ) + { + TT_Face face = loader->face; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + + + if ( IS_HINTED( loader->load_flags ) ) + { + /* + * We round the horizontal offset only if there is hinting along + * the x axis; this corresponds to integer advance width values. + * + * Theoretically, a glyph's bytecode can toggle ClearType's + * `backward compatibility' mode, which would allow modification + * of the advance width. In reality, however, applications + * neither allow nor expect modified advance widths if subpixel + * rendering is active. + * + */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_35 ) + x = FT_PIX_ROUND( x ); + + y = FT_PIX_ROUND( y ); + } + } + } + } + + if ( x || y ) + FT_Outline_Translate( ¤t, x, y ); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Process_Composite_Glyph + * + * @Description: + * This is slightly different from TT_Process_Simple_Glyph, in that + * its sole purpose is to hint the glyph. Thus this function is + * only available when bytecode interpreter is enabled. + */ + static FT_Error + TT_Process_Composite_Glyph( TT_Loader loader, + FT_UInt start_point, + FT_UInt start_contour ) + { + FT_Error error; + FT_Outline* outline = &loader->gloader->base.outline; + FT_Stream stream = loader->stream; + FT_UShort n_ins; + FT_UInt i; + + + /* make room for phantom points */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader, + outline->n_points + 4, + 0 ); + if ( error ) + return error; + + outline->points[outline->n_points ] = loader->pp1; + outline->points[outline->n_points + 1] = loader->pp2; + outline->points[outline->n_points + 2] = loader->pp3; + outline->points[outline->n_points + 3] = loader->pp4; + +#ifdef TT_USE_BYTECODE_INTERPRETER + + { + TT_ExecContext exec = loader->exec; + FT_Memory memory = exec->memory; + + + if ( exec->glyphSize ) + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + /* TT_Load_Composite_Glyph only gives us the offset of instructions */ + /* so we read them here */ + if ( FT_STREAM_SEEK( loader->ins_pos ) || + FT_READ_USHORT( n_ins ) ) + return error; + + FT_TRACE5(( " Instructions size = %hu\n", n_ins )); + + if ( !n_ins ) + return FT_Err_Ok; + + /* don't trust `maxSizeOfInstructions'; */ + /* only do a rough safety check */ + if ( n_ins > loader->byte_len ) + { + FT_TRACE1(( "TT_Process_Composite_Glyph:" + " too many instructions (%hu) for glyph with length %u\n", + n_ins, loader->byte_len )); + return FT_THROW( Too_Many_Hints ); + } + + if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) || + FT_STREAM_READ( exec->glyphIns, n_ins ) ) + return error; + + exec->glyphSize = n_ins; + } + +#endif + + tt_prepare_zone( &loader->zone, &loader->gloader->base, + start_point, start_contour ); + + /* Some points are likely touched during execution of */ + /* instructions on components. So let's untouch them. */ + for ( i = 0; i < loader->zone.n_points - 4U; i++ ) + loader->zone.tags[i] &= ~FT_CURVE_TAG_TOUCH_BOTH; + + return TT_Hint_Glyph( loader, 1 ); + } + + + /* + * Calculate the phantom points + * + * Defining the right side bearing (rsb) as + * + * rsb = aw - (lsb + xmax - xmin) + * + * (with `aw' the advance width, `lsb' the left side bearing, and `xmin' + * and `xmax' the glyph's minimum and maximum x value), the OpenType + * specification defines the initial position of horizontal phantom points + * as + * + * pp1 = (round(xmin - lsb), 0) , + * pp2 = (round(pp1 + aw), 0) . + * + * Note that the rounding to the grid (in the device space) is not + * documented currently in the specification. + * + * However, the specification lacks the precise definition of vertical + * phantom points. Greg Hitchcock provided the following explanation. + * + * - a `vmtx' table is present + * + * For any glyph, the minimum and maximum y values (`ymin' and `ymax') + * are given in the `glyf' table, the top side bearing (tsb) and advance + * height (ah) are given in the `vmtx' table. The bottom side bearing + * (bsb) is then calculated as + * + * bsb = ah - (tsb + ymax - ymin) , + * + * and the initial position of vertical phantom points is + * + * pp3 = (x, round(ymax + tsb)) , + * pp4 = (x, round(pp3 - ah)) . + * + * See below for value `x'. + * + * - no `vmtx' table in the font + * + * If there is an `OS/2' table, we set + * + * DefaultAscender = sTypoAscender , + * DefaultDescender = sTypoDescender , + * + * otherwise we use data from the `hhea' table: + * + * DefaultAscender = Ascender , + * DefaultDescender = Descender . + * + * With these two variables we can now set + * + * ah = DefaultAscender - sDefaultDescender , + * tsb = DefaultAscender - yMax , + * + * and proceed as if a `vmtx' table was present. + * + * Usually we have + * + * x = aw / 2 , (1) + * + * but there is one compatibility case where it can be set to + * + * x = -DefaultDescender - + * ((DefaultAscender - DefaultDescender - aw) / 2) . (2) + * + * and another one with + * + * x = 0 . (3) + * + * In Windows, the history of those values is quite complicated, + * depending on the hinting engine (that is, the graphics framework). + * + * framework from to formula + * ---------------------------------------------------------- + * GDI Windows 98 current (1) + * (Windows 2000 for NT) + * GDI+ Windows XP Windows 7 (2) + * GDI+ Windows 8 current (3) + * DWrite Windows 7 current (3) + * + * For simplicity, FreeType uses (1) for grayscale subpixel hinting and + * (3) for everything else. + * + */ + static void + tt_loader_set_pp( TT_Loader loader ) + { + loader->pp1.x = loader->bbox.xMin - loader->left_bearing; + loader->pp1.y = 0; + loader->pp2.x = loader->pp1.x + loader->advance; + loader->pp2.y = 0; + + loader->pp3.x = 0; + loader->pp3.y = loader->bbox.yMax + loader->top_bearing; + loader->pp4.x = 0; + loader->pp4.y = loader->pp3.y - loader->vadvance; + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + { + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face ); + + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + loader->exec && + loader->exec->subpixel_hinting_lean && + loader->exec->grayscale_cleartype ) + { + loader->pp3.x = loader->advance / 2; + loader->pp4.x = loader->advance / 2; + } + } +#endif + } + + + /* a utility function to retrieve i-th node from given FT_List */ + static FT_ListNode + ft_list_get_node_at( FT_List list, + FT_UInt idx ) + { + FT_ListNode cur; + + + if ( !list ) + return NULL; + + for ( cur = list->head; cur; cur = cur->next ) + { + if ( !idx ) + return cur; + + idx--; + } + + return NULL; + } + + + /************************************************************************** + * + * @Function: + * load_truetype_glyph + * + * @Description: + * Loads a given truetype glyph. Handles composites and uses a + * TT_Loader object. + */ + static FT_Error + load_truetype_glyph( TT_Loader loader, + FT_UInt glyph_index, + FT_UInt recurse_count, + FT_Bool header_only ) + { + FT_Error error = FT_Err_Ok; + FT_Fixed x_scale, y_scale; + FT_ULong offset; + TT_Face face = loader->face; + FT_GlyphLoader gloader = loader->gloader; + + FT_Bool opened_frame = 0; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_StreamRec inc_stream; + FT_Data glyph_data; + FT_Bool glyph_data_loaded = 0; +#endif + + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( recurse_count ) + FT_TRACE5(( " nesting level: %d\n", recurse_count )); +#endif + + /* some fonts have an incorrect value of `maxComponentDepth' */ + if ( recurse_count > face->max_profile.maxComponentDepth ) + { + FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %d\n", + recurse_count )); + face->max_profile.maxComponentDepth = (FT_UShort)recurse_count; + } + +#ifndef FT_CONFIG_OPTION_INCREMENTAL + /* check glyph index */ + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = FT_THROW( Invalid_Glyph_Index ); + goto Exit; + } +#endif + + loader->glyph_index = glyph_index; + + if ( loader->load_flags & FT_LOAD_NO_SCALE ) + { + x_scale = 0x10000L; + y_scale = 0x10000L; + } + else + { + x_scale = loader->size->metrics->x_scale; + y_scale = loader->size->metrics->y_scale; + } + + /* Set `offset' to the start of the glyph relative to the start of */ + /* the `glyf' table, and `byte_len' to the length of the glyph in */ + /* bytes. */ + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* If we are loading glyph data via the incremental interface, set */ + /* the loader stream to a memory stream reading the data returned */ + /* by the interface. */ + if ( face->root.internal->incremental_interface ) + { + error = face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, &glyph_data ); + if ( error ) + goto Exit; + + glyph_data_loaded = 1; + offset = 0; + loader->byte_len = glyph_data.length; + + FT_ZERO( &inc_stream ); + FT_Stream_OpenMemory( &inc_stream, + glyph_data.pointer, + glyph_data.length ); + + loader->stream = &inc_stream; + } + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ULong len; + + + offset = tt_face_get_location( FT_FACE( face ), glyph_index, &len ); + + loader->byte_len = (FT_UInt)len; + } + + if ( loader->byte_len > 0 ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* for the incremental interface, `glyf_offset' is always zero */ + if ( !face->glyf_offset && + !face->root.internal->incremental_interface ) +#else + if ( !face->glyf_offset ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + error = face->access_glyph_frame( loader, glyph_index, + face->glyf_offset + offset, + loader->byte_len ); + if ( error ) + goto Exit; + + /* read glyph header first */ + error = face->read_glyph_header( loader ); + + face->forget_glyph_frame( loader ); + + if ( error ) + goto Exit; + } + + /* a space glyph */ + if ( loader->byte_len == 0 || loader->n_contours == 0 ) + { + loader->bbox.xMin = 0; + loader->bbox.xMax = 0; + loader->bbox.yMin = 0; + loader->bbox.yMax = 0; + } + + /* the metrics must be computed after loading the glyph header */ + /* since we need the glyph's `yMax' value in case the vertical */ + /* metrics must be emulated */ + error = tt_get_metrics( loader, glyph_index ); + if ( error ) + goto Exit; + + if ( header_only ) + goto Exit; + + if ( loader->byte_len == 0 || loader->n_contours == 0 ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incremental( loader, glyph_index ); +#endif + tt_loader_set_pp( loader ); + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || + FT_IS_VARIATION( FT_FACE( face ) ) ) + { + /* a small outline structure with four elements for */ + /* communication with `TT_Vary_Apply_Glyph_Deltas' */ + FT_Vector points[4]; + FT_Outline outline; + + /* unrounded values */ + FT_Vector unrounded[4] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; + + + points[0] = loader->pp1; + points[1] = loader->pp2; + points[2] = loader->pp3; + points[3] = loader->pp4; + + outline.n_points = 0; + outline.n_contours = 0; + outline.points = points; + outline.tags = NULL; + outline.contours = NULL; + + /* this must be done before scaling */ + error = TT_Vary_Apply_Glyph_Deltas( loader, + &outline, + unrounded ); + if ( error ) + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* scale phantom points, if necessary; */ + /* they get rounded in `TT_Hint_Glyph' */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + + error = FT_Err_Ok; + goto Exit; + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incremental( loader, glyph_index ); +#endif + tt_loader_set_pp( loader ); + + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* we now open a frame again, right after the glyph header */ + /* (which consists of 10 bytes) */ + error = face->access_glyph_frame( loader, glyph_index, + face->glyf_offset + offset + 10, + loader->byte_len - 10 ); + if ( error ) + goto Exit; + + opened_frame = 1; + + /* if it is a simple glyph, load it */ + + if ( loader->n_contours > 0 ) + { + error = face->read_simple_glyph( loader ); + if ( error ) + goto Exit; + + /* all data have been read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + + error = TT_Process_Simple_Glyph( loader ); + if ( error ) + goto Exit; + + FT_GlyphLoader_Add( gloader ); + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* otherwise, load a composite! */ + else if ( loader->n_contours < 0 ) + { + FT_Memory memory = face->root.memory; + + FT_UInt start_point; + FT_UInt start_contour; + FT_ULong ins_pos; /* position of composite instructions, if any */ + + FT_ListNode node, node2; + + + /* normalize the `n_contours' value */ + loader->n_contours = -1; + + /* + * We store the glyph index directly in the `node->data' pointer, + * following the glib solution (cf. macro `GUINT_TO_POINTER') with a + * double cast to make this portable. Note, however, that this needs + * pointers with a width of at least 32 bits. + */ + + /* clear the nodes filled by sibling chains */ + node = ft_list_get_node_at( &loader->composites, recurse_count ); + for ( node2 = node; node2; node2 = node2->next ) + node2->data = (void*)-1; + + /* check whether we already have a composite glyph with this index */ + if ( FT_List_Find( &loader->composites, + FT_UINT_TO_POINTER( glyph_index ) ) ) + { + FT_TRACE1(( "TT_Load_Composite_Glyph:" + " infinite recursion detected\n" )); + error = FT_THROW( Invalid_Composite ); + goto Exit; + } + + else if ( node ) + node->data = FT_UINT_TO_POINTER( glyph_index ); + + else + { + if ( FT_QNEW( node ) ) + goto Exit; + node->data = FT_UINT_TO_POINTER( glyph_index ); + FT_List_Add( &loader->composites, node ); + } + + start_point = (FT_UInt)gloader->base.outline.n_points; + start_contour = (FT_UInt)gloader->base.outline.n_contours; + + /* for each subglyph, read composite header */ + error = face->read_composite_glyph( loader ); + if ( error ) + goto Exit; + + /* store the offset of instructions */ + ins_pos = loader->ins_pos; + + /* all data we need are read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || + FT_IS_VARIATION( FT_FACE( face ) ) ) + { + short i, limit; + FT_SubGlyph subglyph; + + FT_Outline outline = { 0, 0, NULL, NULL, NULL, 0 }; + FT_Vector* unrounded = NULL; + + + limit = (short)gloader->current.num_subglyphs; + + /* construct an outline structure for */ + /* communication with `TT_Vary_Apply_Glyph_Deltas' */ + if ( FT_QNEW_ARRAY( outline.points, limit + 4 ) || + FT_QNEW_ARRAY( outline.tags, limit ) || + FT_QNEW_ARRAY( outline.contours, limit ) || + FT_QNEW_ARRAY( unrounded, limit + 4 ) ) + goto Exit1; + + outline.n_contours = outline.n_points = limit; + + subglyph = gloader->current.subglyphs; + + for ( i = 0; i < limit; i++, subglyph++ ) + { + /* applying deltas for anchor points doesn't make sense, */ + /* but we don't have to specially check this since */ + /* unused delta values are zero anyways */ + outline.points[i].x = subglyph->arg1; + outline.points[i].y = subglyph->arg2; + outline.tags[i] = ON_CURVE_POINT; + outline.contours[i] = i; + } + + outline.points[i++] = loader->pp1; + outline.points[i++] = loader->pp2; + outline.points[i++] = loader->pp3; + outline.points[i ] = loader->pp4; + + /* this call provides additional offsets */ + /* for each component's translation */ + if ( FT_SET_ERROR( TT_Vary_Apply_Glyph_Deltas( loader, + &outline, + unrounded ) ) ) + goto Exit1; + + subglyph = gloader->current.subglyphs; + + for ( i = 0; i < limit; i++, subglyph++ ) + { + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + { + subglyph->arg1 = (FT_Int16)outline.points[i].x; + subglyph->arg2 = (FT_Int16)outline.points[i].y; + } + } + + Exit1: + FT_FREE( outline.points ); + FT_FREE( outline.tags ); + FT_FREE( outline.contours ); + FT_FREE( unrounded ); + + if ( error ) + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* scale phantom points, if necessary; */ + /* they get rounded in `TT_Hint_Glyph' */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + + /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ + /* `as is' in the glyph slot (the client application will be */ + /* responsible for interpreting these data)... */ + if ( loader->load_flags & FT_LOAD_NO_RECURSE ) + { + FT_GlyphLoader_Add( gloader ); + loader->glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + goto Exit; + } + + /*********************************************************************/ + /*********************************************************************/ + /*********************************************************************/ + + { + FT_UInt n, num_base_points; + FT_SubGlyph subglyph = NULL; + + FT_UInt num_points = start_point; + FT_UInt num_subglyphs = gloader->current.num_subglyphs; + FT_UInt num_base_subgs = gloader->base.num_subglyphs; + + FT_Stream old_stream = loader->stream; + FT_UInt old_byte_len = loader->byte_len; + + + FT_GlyphLoader_Add( gloader ); + + /* read each subglyph independently */ + for ( n = 0; n < num_subglyphs; n++ ) + { + FT_Vector pp[4]; + + FT_Int linear_hadvance; + FT_Int linear_vadvance; + + + /* Each time we call `load_truetype_glyph' in this loop, the */ + /* value of `gloader.base.subglyphs' can change due to table */ + /* reallocations. We thus need to recompute the subglyph */ + /* pointer on each iteration. */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + pp[0] = loader->pp1; + pp[1] = loader->pp2; + pp[2] = loader->pp3; + pp[3] = loader->pp4; + + linear_hadvance = loader->linear; + linear_vadvance = loader->vadvance; + + num_base_points = (FT_UInt)gloader->base.outline.n_points; + + error = load_truetype_glyph( loader, + (FT_UInt)subglyph->index, + recurse_count + 1, + FALSE ); + if ( error ) + goto Exit; + + /* restore subglyph pointer */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + /* restore phantom points if necessary */ + if ( !( subglyph->flags & USE_MY_METRICS ) ) + { + loader->pp1 = pp[0]; + loader->pp2 = pp[1]; + loader->pp3 = pp[2]; + loader->pp4 = pp[3]; + + loader->linear = linear_hadvance; + loader->vadvance = linear_vadvance; + } + + num_points = (FT_UInt)gloader->base.outline.n_points; + + if ( num_points == num_base_points ) + continue; + + /* gloader->base.outline consists of three parts: */ + /* */ + /* 0 ----> start_point ----> num_base_points ----> n_points */ + /* (1) (2) (3) */ + /* */ + /* (1) points that exist from the beginning */ + /* (2) component points that have been loaded so far */ + /* (3) points of the newly loaded component */ + error = TT_Process_Composite_Component( loader, + subglyph, + start_point, + num_base_points ); + if ( error ) + goto Exit; + } + + loader->stream = old_stream; + loader->byte_len = old_byte_len; + + /* process the glyph */ + loader->ins_pos = ins_pos; + if ( IS_HINTED( loader->load_flags ) && +#ifdef TT_USE_BYTECODE_INTERPRETER + subglyph && + subglyph->flags & WE_HAVE_INSTR && +#endif + num_points > start_point ) + { + error = TT_Process_Composite_Glyph( loader, + start_point, + start_contour ); + if ( error ) + goto Exit; + } + } + + /* retain the overlap flag */ + if ( gloader->base.num_subglyphs && + gloader->base.subglyphs[0].flags & OVERLAP_COMPOUND ) + gloader->base.outline.flags |= FT_OUTLINE_OVERLAP; + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + Exit: + + if ( opened_frame ) + face->forget_glyph_frame( loader ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( glyph_data_loaded ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + +#endif + + return error; + } + + + static FT_Error + compute_glyph_metrics( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = loader->face; + TT_Size size = loader->size; + TT_GlyphSlot glyph = loader->glyph; + FT_BBox bbox; + FT_Fixed y_scale; + + + y_scale = 0x10000L; + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + y_scale = size->metrics->y_scale; + + if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE ) + FT_Outline_Get_CBox( &glyph->outline, &bbox ); + else + bbox = loader->bbox; + + /* get the device-independent horizontal advance; it is scaled later */ + /* by the base layer. */ + glyph->linearHoriAdvance = loader->linear; + + glyph->metrics.horiBearingX = bbox.xMin; + glyph->metrics.horiBearingY = bbox.yMax; + if ( loader->widthp ) + glyph->metrics.horiAdvance = loader->widthp[glyph_index] * 64; + else + glyph->metrics.horiAdvance = SUB_LONG( loader->pp2.x, loader->pp1.x ); + + /* set glyph dimensions */ + glyph->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin ); + glyph->metrics.height = SUB_LONG( bbox.yMax, bbox.yMin ); + + /* Now take care of vertical metrics. In the case where there is */ + /* no vertical information within the font (relatively common), */ + /* create some metrics manually */ + { + FT_Pos top; /* scaled vertical top side bearing */ + FT_Pos advance; /* scaled vertical advance height */ + + + /* Get the unscaled top bearing and advance height. */ + if ( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ) + { + top = (FT_Short)FT_DivFix( SUB_LONG( loader->pp3.y, bbox.yMax ), + y_scale ); + + if ( loader->pp3.y <= loader->pp4.y ) + advance = 0; + else + advance = (FT_UShort)FT_DivFix( SUB_LONG( loader->pp3.y, + loader->pp4.y ), + y_scale ); + } + else + { + FT_Pos height; + + + /* XXX Compute top side bearing and advance height in */ + /* Get_VMetrics instead of here. */ + + /* NOTE: The OS/2 values are the only `portable' ones, */ + /* which is why we use them, if there is an OS/2 */ + /* table in the font. Otherwise, we use the */ + /* values defined in the horizontal header. */ + + height = (FT_Short)FT_DivFix( SUB_LONG( bbox.yMax, + bbox.yMin ), + y_scale ); + if ( face->os2.version != 0xFFFFU ) + advance = (FT_Pos)( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + advance = (FT_Pos)( face->horizontal.Ascender - + face->horizontal.Descender ); + + top = ( advance - height ) / 2; + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + { + FT_Incremental_InterfaceRec* incr; + FT_Incremental_MetricsRec incr_metrics; + FT_Error error; + + + incr = face->root.internal->incremental_interface; + + /* If this is an incrementally loaded font see if there are */ + /* overriding metrics for this glyph. */ + if ( incr && incr->funcs->get_glyph_metrics ) + { + incr_metrics.bearing_x = 0; + incr_metrics.bearing_y = top; + incr_metrics.advance = advance; + + error = incr->funcs->get_glyph_metrics( incr->object, + glyph_index, + TRUE, + &incr_metrics ); + if ( error ) + return error; + + top = incr_metrics.bearing_y; + advance = incr_metrics.advance; + } + } + + /* GWW: Do vertical metrics get loaded incrementally too? */ + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + glyph->linearVertAdvance = advance; + + /* scale the metrics */ + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + top = FT_MulFix( top, y_scale ); + advance = FT_MulFix( advance, y_scale ); + } + + /* XXX: for now, we have no better algorithm for the lsb, but it */ + /* should work fine. */ + /* */ + glyph->metrics.vertBearingX = SUB_LONG( glyph->metrics.horiBearingX, + glyph->metrics.horiAdvance / 2 ); + glyph->metrics.vertBearingY = top; + glyph->metrics.vertAdvance = advance; + } + + return FT_Err_Ok; + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + static FT_Error + load_sbit_image( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_Face face = (TT_Face)glyph->face; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + FT_Stream stream = face->root.stream; + FT_Error error; + TT_SBit_MetricsRec sbit_metrics; + + + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_UInt)load_flags, + stream, + &glyph->bitmap, + &sbit_metrics ); + if ( !error ) + { + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = (FT_Pos)sbit_metrics.width * 64; + glyph->metrics.height = (FT_Pos)sbit_metrics.height * 64; + + glyph->metrics.horiBearingX = (FT_Pos)sbit_metrics.horiBearingX * 64; + glyph->metrics.horiBearingY = (FT_Pos)sbit_metrics.horiBearingY * 64; + glyph->metrics.horiAdvance = (FT_Pos)sbit_metrics.horiAdvance * 64; + + glyph->metrics.vertBearingX = (FT_Pos)sbit_metrics.vertBearingX * 64; + glyph->metrics.vertBearingY = (FT_Pos)sbit_metrics.vertBearingY * 64; + glyph->metrics.vertAdvance = (FT_Pos)sbit_metrics.vertAdvance * 64; + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->bitmap_left = sbit_metrics.vertBearingX; + glyph->bitmap_top = sbit_metrics.vertBearingY; + } + else + { + glyph->bitmap_left = sbit_metrics.horiBearingX; + glyph->bitmap_top = sbit_metrics.horiBearingY; + } + } + + return error; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + static FT_Error + tt_loader_init( TT_Loader loader, + TT_Size size, + TT_GlyphSlot glyph, + FT_Int32 load_flags, + FT_Bool glyf_table_only ) + { + TT_Face face = (TT_Face)glyph->face; + FT_Stream stream = face->root.stream; + +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_Error error; + FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( glyph->face ); +#endif +#endif + + + FT_ZERO( loader ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /* load execution context */ + if ( IS_HINTED( load_flags ) && !glyf_table_only ) + { + TT_ExecContext exec; + FT_Bool grayscale = TRUE; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + FT_Bool subpixel_hinting_lean; + FT_Bool grayscale_cleartype; +#endif + + FT_Bool reexecute = FALSE; + + + if ( size->bytecode_ready < 0 || size->cvt_ready < 0 ) + { + error = tt_size_ready_bytecode( size, pedantic ); + if ( error ) + return error; + } + else if ( size->bytecode_ready ) + return size->bytecode_ready; + else if ( size->cvt_ready ) + return size->cvt_ready; + + /* query new execution context */ + exec = size->context; + if ( !exec ) + return FT_THROW( Could_Not_Find_Context ); + + grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + subpixel_hinting_lean = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + grayscale_cleartype = + FT_BOOL( subpixel_hinting_lean && + !( ( load_flags & + FT_LOAD_TARGET_LCD ) || + ( load_flags & + FT_LOAD_TARGET_LCD_V ) ) ); + exec->vertical_lcd_lean = + FT_BOOL( subpixel_hinting_lean && + ( load_flags & + FT_LOAD_TARGET_LCD_V ) ); + grayscale = FT_BOOL( grayscale && !subpixel_hinting_lean ); + } + else + { + subpixel_hinting_lean = FALSE; + grayscale_cleartype = FALSE; + exec->vertical_lcd_lean = FALSE; + } +#endif + + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + /* a change from mono to subpixel rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( subpixel_hinting_lean != exec->subpixel_hinting_lean ) + { + FT_TRACE4(( "tt_loader_init: subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->subpixel_hinting_lean = subpixel_hinting_lean; + reexecute = TRUE; + } + + /* a change from colored to grayscale subpixel rendering (and */ + /* vice versa) requires a re-execution of the CVT program */ + if ( grayscale_cleartype != exec->grayscale_cleartype ) + { + FT_TRACE4(( "tt_loader_init: grayscale subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale_cleartype = grayscale_cleartype; + reexecute = TRUE; + } + } +#endif + + /* a change from mono to grayscale rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale ) + { + FT_TRACE4(( "tt_loader_init: grayscale hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale = grayscale; + reexecute = TRUE; + } + } + + if ( reexecute ) + { + error = tt_size_run_prep( size, pedantic ); + if ( error ) + return error; + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + } + + /* check whether the cvt program has disabled hinting */ + if ( exec->GS.instruct_control & 1 ) + load_flags |= FT_LOAD_NO_HINTING; + + /* load default graphics state -- if needed */ + if ( exec->GS.instruct_control & 2 ) + exec->GS = tt_default_graphics_state; + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * Toggle backward compatibility according to what font wants, except + * when + * + * 1) we have a `tricky' font that heavily relies on the interpreter to + * render glyphs correctly, for example DFKai-SB, or + * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested. + * + * In those cases, backward compatibility needs to be turned off to get + * correct rendering. The rendering is then completely up to the + * font's programming. + * + */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + subpixel_hinting_lean && + !FT_IS_TRICKY( glyph->face ) ) + exec->backward_compatibility = !( exec->GS.instruct_control & 4 ); + else + exec->backward_compatibility = FALSE; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ + + exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); + loader->exec = exec; + loader->instructions = exec->glyphIns; + + /* Use the hdmx table if any unless FT_LOAD_COMPUTE_METRICS */ + /* is set or backward compatibility mode of the v38 or v40 */ + /* interpreters is active. See `ttinterp.h' for details on */ + /* backward compatibility mode. */ + if ( IS_HINTED( loader->load_flags ) && + !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + exec->backward_compatibility ) && +#endif + !face->postscript.isFixedPitch ) + { + loader->widthp = size->widthp; + } + else + loader->widthp = NULL; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + /* get face's glyph loader */ + if ( !glyf_table_only ) + { + FT_GlyphLoader gloader = glyph->internal->loader; + + + FT_GlyphLoader_Rewind( gloader ); + loader->gloader = gloader; + } + + loader->load_flags = (FT_ULong)load_flags; + + loader->face = face; + loader->size = size; + loader->glyph = (FT_GlyphSlot)glyph; + loader->stream = stream; + + loader->composites.head = NULL; + loader->composites.tail = NULL; + + return FT_Err_Ok; + } + + + static void + tt_loader_done( TT_Loader loader ) + { + FT_List_Finalize( &loader->composites, + NULL, + loader->face->root.memory, + NULL ); + } + + + /************************************************************************** + * + * @Function: + * TT_Load_Glyph + * + * @Description: + * A function used to load a single glyph within a given glyph slot, + * for a given size. + * + * @InOut: + * glyph :: + * A handle to a target slot object where the glyph + * will be loaded. + * + * @Input: + * size :: + * A handle to the source face size at which the glyph + * must be scaled/loaded. + * + * glyph_index :: + * The index of the glyph in the font file. + * + * load_flags :: + * A flag indicating what to load for this glyph. The + * FT_LOAD_XXX constants can be used to control the + * glyph loading process (e.g., whether the outline + * should be scaled, whether to load bitmaps or not, + * whether to hint the outline, etc). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_Face face = (TT_Face)glyph->face; + FT_Error error; + TT_LoaderRec loader; + + + FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index )); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* try to load embedded bitmap (if any) */ + if ( size->strike_index != 0xFFFFFFFFUL && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + IS_DEFAULT_INSTANCE( glyph->face ) ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + + error = load_sbit_image( size, glyph, glyph_index, load_flags ); + if ( FT_ERR_EQ( error, Missing_Bitmap ) ) + { + /* the bitmap strike is incomplete and misses the requested glyph; */ + /* if we have a bitmap-only font, return an empty glyph */ + if ( !FT_IS_SCALABLE( glyph->face ) ) + { + FT_Short left_bearing = 0; + FT_Short top_bearing = 0; + + FT_UShort advance_width = 0; + FT_UShort advance_height = 0; + + + /* to return an empty glyph, however, we need metrics data */ + /* from the `hmtx' (or `vmtx') table; the assumption is that */ + /* empty glyphs are missing intentionally, representing */ + /* whitespace - not having at least horizontal metrics is */ + /* thus considered an error */ + if ( !face->horz_metrics_size ) + return error; + + /* we now construct an empty bitmap glyph */ + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + 0, + &top_bearing, + &advance_height ); + + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = 0; + glyph->metrics.height = 0; + + glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale ); + glyph->metrics.horiBearingY = 0; + glyph->metrics.horiAdvance = FT_MulFix( advance_width, x_scale ); + + glyph->metrics.vertBearingX = 0; + glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advance_height, y_scale ); + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + glyph->bitmap_left = 0; + glyph->bitmap_top = 0; + + return FT_Err_Ok; + } + } + else if ( error ) + { + /* return error if font is not scalable */ + if ( !FT_IS_SCALABLE( glyph->face ) ) + return error; + } + else + { + if ( FT_IS_SCALABLE( glyph->face ) || + FT_HAS_SBIX( glyph->face ) ) + { + /* for the bbox we need the header only */ + (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); + (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); + tt_loader_done( &loader ); + glyph->linearHoriAdvance = loader.linear; + glyph->linearVertAdvance = loader.vadvance; + + /* Bitmaps from the 'sbix' table need special treatment: */ + /* if there is a glyph contour, the bitmap origin must be */ + /* shifted to be relative to the lower left corner of the */ + /* glyph bounding box, also taking the left-side bearing */ + /* (or top bearing) into account. */ + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX && + loader.n_contours > 0 ) + { + FT_Int bitmap_left; + FT_Int bitmap_top; + + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* This is a guess, since Apple's CoreText engine doesn't */ + /* really do vertical typesetting. */ + bitmap_left = loader.bbox.xMin; + bitmap_top = loader.top_bearing; + } + else + { + bitmap_left = loader.left_bearing; + bitmap_top = loader.bbox.yMin; + } + + glyph->bitmap_left += FT_MulFix( bitmap_left, x_scale ) >> 6; + glyph->bitmap_top += FT_MulFix( bitmap_top, y_scale ) >> 6; + } + + /* sanity checks: if `xxxAdvance' in the sbit metric */ + /* structure isn't set, use `linearXXXAdvance' */ + if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance ) + glyph->metrics.horiAdvance = FT_MulFix( glyph->linearHoriAdvance, + x_scale ); + if ( !glyph->metrics.vertAdvance && glyph->linearVertAdvance ) + glyph->metrics.vertAdvance = FT_MulFix( glyph->linearVertAdvance, + y_scale ); + } + + return FT_Err_Ok; + } + } + + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) + { + error = FT_THROW( Invalid_Size_Handle ); + goto Exit; + } + +#ifdef FT_CONFIG_OPTION_SVG + + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + ( load_flags & FT_LOAD_COLOR ) && + face->svg ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + + error = sfnt->load_svg_doc( glyph, glyph_index ); + if ( !error ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short leftBearing; + FT_Short topBearing; + FT_UShort advanceX; + FT_UShort advanceY; + + + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->format = FT_GLYPH_FORMAT_SVG; + + sfnt->get_metrics( face, + FALSE, + glyph_index, + &leftBearing, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &topBearing, + &advanceY ); + + glyph->linearHoriAdvance = advanceX; + glyph->linearVertAdvance = advanceY; + + glyph->metrics.horiAdvance = FT_MulFix( advanceX, x_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advanceY, y_scale ); + + return error; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + + /* return immediately if we only want SVG glyphs */ + if ( load_flags & FT_LOAD_SVG_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); + if ( error ) + goto Exit; + + /* done if we are only interested in the `hdmx` advance */ + if ( load_flags & FT_LOAD_ADVANCE_ONLY && + !( load_flags & FT_LOAD_VERTICAL_LAYOUT ) && + loader.widthp ) + { + glyph->metrics.horiAdvance = loader.widthp[glyph_index] * 64; + goto Done; + } + + glyph->format = FT_GLYPH_FORMAT_OUTLINE; + glyph->num_subglyphs = 0; + glyph->outline.flags = 0; + + /* main loading loop */ + error = load_truetype_glyph( &loader, glyph_index, 0, FALSE ); + if ( !error ) + { + if ( glyph->format == FT_GLYPH_FORMAT_COMPOSITE ) + { + glyph->num_subglyphs = loader.gloader->base.num_subglyphs; + glyph->subglyphs = loader.gloader->base.subglyphs; + } + else + { + glyph->outline = loader.gloader->base.outline; + glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; + + /* Translate array so that (0,0) is the glyph's origin. Note */ + /* that this behaviour is independent on the value of bit 1 of */ + /* the `flags' field in the `head' table -- at least major */ + /* applications like Acroread indicate that. */ + if ( loader.pp1.x ) + FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 ); + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( IS_HINTED( load_flags ) ) + { + glyph->control_data = loader.exec->glyphIns; + glyph->control_len = loader.exec->glyphSize; + + if ( loader.exec->GS.scan_control ) + { + /* convert scan conversion mode to FT_OUTLINE_XXX flags */ + switch ( loader.exec->GS.scan_type ) + { + case 0: /* simple drop-outs including stubs */ + glyph->outline.flags |= FT_OUTLINE_INCLUDE_STUBS; + break; + case 1: /* simple drop-outs excluding stubs */ + /* nothing; it's the default rendering mode */ + break; + case 4: /* smart drop-outs including stubs */ + glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS | + FT_OUTLINE_INCLUDE_STUBS; + break; + case 5: /* smart drop-outs excluding stubs */ + glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS; + break; + + default: /* no drop-out control */ + glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; + break; + } + } + else + glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + error = compute_glyph_metrics( &loader, glyph_index ); + } + + /* Set the `high precision' bit flag. */ + /* This is _critical_ to get correct output for monochrome */ + /* TrueType glyphs at all sizes using the bytecode interpreter. */ + /* */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && + size->metrics->y_ppem < 24 ) + glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + FT_TRACE1(( " subglyphs = %u, contours = %hd, points = %hd," + " flags = 0x%.3x\n", + loader.gloader->base.num_subglyphs, + glyph->outline.n_contours, + glyph->outline.n_points, + glyph->outline.flags )); + + Done: + tt_loader_done( &loader ); + + Exit: +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE1(( " failed (error code 0x%x)\n", + error )); +#endif + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttgload.h b/vendor/freetype/src/truetype/ttgload.h new file mode 100644 index 0000000..f18637d --- /dev/null +++ b/vendor/freetype/src/truetype/ttgload.h @@ -0,0 +1,61 @@ +/**************************************************************************** + * + * ttgload.h + * + * TrueType Glyph Loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTGLOAD_H_ +#define TTGLOAD_H_ + + +#include "ttobjs.h" + +#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + TT_Init_Glyph_Loading( TT_Face face ); + + FT_LOCAL( void ) + TT_Get_HMetrics( TT_Face face, + FT_UInt idx, + FT_Short* lsb, + FT_UShort* aw ); + + FT_LOCAL( void ) + TT_Get_VMetrics( TT_Face face, + FT_UInt idx, + FT_Pos yMax, + FT_Short* tsb, + FT_UShort* ah ); + + FT_LOCAL( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* TTGLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttgxvar.c b/vendor/freetype/src/truetype/ttgxvar.c new file mode 100644 index 0000000..ad4f266 --- /dev/null +++ b/vendor/freetype/src/truetype/ttgxvar.c @@ -0,0 +1,4661 @@ +/**************************************************************************** + * + * ttgxvar.c + * + * TrueType GX Font Variation loader + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * Apple documents the `fvar', `gvar', `cvar', and `avar' tables at + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html + * + * The documentation for `gvar' is not intelligible; `cvar' refers you + * to `gvar' and is thus also incomprehensible. + * + * The documentation for `avar' appears correct, but Apple has no fonts + * with an `avar' table, so it is hard to test. + * + * Many thanks to John Jenkins (at Apple) in figuring this out. + * + * + * Apple's `kern' table has some references to tuple indices, but as + * there is no indication where these indices are defined, nor how to + * interpolate the kerning values (different tuples have different + * classes) this issue is ignored. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ttpload.h" +#include "ttgxvar.h" + +#include "tterrors.h" + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + +#define FT_Stream_FTell( stream ) \ + (FT_ULong)( (stream)->cursor - (stream)->base ) +#define FT_Stream_SeekSet( stream, off ) \ + (stream)->cursor = \ + ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \ + ? (stream)->base + (off) \ + : (stream)->limit + + + /* some macros we need */ +#define FT_fdot14ToFixed( x ) \ + ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) +#define FT_intToFixed( i ) \ + ( (FT_Fixed)( (FT_ULong)(i) << 16 ) ) +#define FT_fdot6ToFixed( i ) \ + ( (FT_Fixed)( (FT_ULong)(i) << 10 ) ) +#define FT_fixedToInt( x ) \ + ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) ) +#define FT_fixedToFdot6( x ) \ + ( (FT_Pos)( ( (x) + 0x200 ) >> 10 ) ) + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttgxvar + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Internal Routines *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It + * indicates that there is a delta for every point without needing to + * enumerate all of them. + */ + + /* ensure that value `0' has the same width as a pointer */ +#define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0 + + +#define GX_PT_POINTS_ARE_WORDS 0x80U +#define GX_PT_POINT_RUN_COUNT_MASK 0x7FU + + + /************************************************************************** + * + * @Function: + * ft_var_readpackedpoints + * + * @Description: + * Read a set of points to which the following deltas will apply. + * Points are packed with a run length encoding. + * + * @Input: + * stream :: + * The data stream. + * + * size :: + * The size of the table holding the data. + * + * @Output: + * point_cnt :: + * The number of points read. A zero value means that + * all points in the glyph will be affected, without + * enumerating them individually. + * + * @Return: + * An array of FT_UShort containing the affected points or the + * special value ALL_POINTS. + */ + static FT_UShort* + ft_var_readpackedpoints( FT_Stream stream, + FT_ULong size, + FT_UInt *point_cnt ) + { + FT_UShort *points = NULL; + FT_UInt n; + FT_UInt runcnt; + FT_UInt i, j; + FT_UShort first; + FT_Memory memory = stream->memory; + FT_Error error; + + + *point_cnt = 0; + + n = FT_GET_BYTE(); + if ( n == 0 ) + return ALL_POINTS; + + if ( n & GX_PT_POINTS_ARE_WORDS ) + { + n &= GX_PT_POINT_RUN_COUNT_MASK; + n <<= 8; + n |= FT_GET_BYTE(); + } + + if ( n > size ) + { + FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" )); + return NULL; + } + + /* in the nested loops below we increase `i' twice; */ + /* it is faster to simply allocate one more slot */ + /* than to add another test within the loop */ + if ( FT_QNEW_ARRAY( points, n + 1 ) ) + return NULL; + + *point_cnt = n; + + first = 0; + i = 0; + while ( i < n ) + { + runcnt = FT_GET_BYTE(); + if ( runcnt & GX_PT_POINTS_ARE_WORDS ) + { + runcnt &= GX_PT_POINT_RUN_COUNT_MASK; + first += FT_GET_USHORT(); + points[i++] = first; + + /* first point not included in run count */ + for ( j = 0; j < runcnt; j++ ) + { + first += FT_GET_USHORT(); + points[i++] = first; + if ( i >= n ) + break; + } + } + else + { + first += FT_GET_BYTE(); + points[i++] = first; + + for ( j = 0; j < runcnt; j++ ) + { + first += FT_GET_BYTE(); + points[i++] = first; + if ( i >= n ) + break; + } + } + } + + return points; + } + + +#define GX_DT_DELTAS_ARE_ZERO 0x80U +#define GX_DT_DELTAS_ARE_WORDS 0x40U +#define GX_DT_DELTA_RUN_COUNT_MASK 0x3FU + + + /************************************************************************** + * + * @Function: + * ft_var_readpackeddeltas + * + * @Description: + * Read a set of deltas. These are packed slightly differently than + * points. In particular there is no overall count. + * + * @Input: + * stream :: + * The data stream. + * + * size :: + * The size of the table holding the data. + * + * delta_cnt :: + * The number of deltas to be read. + * + * @Return: + * An array of FT_Fixed containing the deltas for the affected + * points. (This only gets the deltas for one dimension. It will + * generally be called twice, once for x, once for y. When used in + * cvt table, it will only be called once.) + * + * We use FT_Fixed to avoid accumulation errors while summing up all + * deltas (the rounding to integer values happens as the very last + * step). + */ + static FT_Fixed* + ft_var_readpackeddeltas( FT_Stream stream, + FT_ULong size, + FT_UInt delta_cnt ) + { + FT_Fixed *deltas = NULL; + FT_UInt runcnt, cnt; + FT_UInt i, j; + FT_UInt bytes_used; + FT_Memory memory = stream->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( deltas, delta_cnt ) ) + return NULL; + + i = 0; + bytes_used = 0; + + while ( i < delta_cnt && bytes_used < size ) + { + runcnt = FT_GET_BYTE(); + cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; + + bytes_used++; + + if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) + { + /* `cnt` + 1 zeroes get added */ + for ( j = 0; j <= cnt && i < delta_cnt; j++ ) + deltas[i++] = 0; + } + else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) + { + /* `cnt` + 1 shorts from the stack */ + bytes_used += 2 * ( cnt + 1 ); + if ( bytes_used > size ) + { + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of short deltas too large\n" )); + goto Fail; + } + + for ( j = 0; j <= cnt && i < delta_cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_GET_SHORT() ); + } + else + { + /* `cnt` + 1 signed bytes from the stack */ + bytes_used += cnt + 1; + if ( bytes_used > size ) + { + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of byte deltas too large\n" )); + goto Fail; + } + + for ( j = 0; j <= cnt && i < delta_cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_GET_CHAR() ); + } + + if ( j <= cnt ) + { + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of deltas too large\n" )); + goto Fail; + } + } + + if ( i < delta_cnt ) + { + FT_TRACE1(( "ft_var_readpackeddeltas: not enough deltas\n" )); + goto Fail; + } + + return deltas; + + Fail: + FT_FREE( deltas ); + return NULL; + } + + + /************************************************************************** + * + * @Function: + * ft_var_load_avar + * + * @Description: + * Parse the `avar' table if present. It need not be, so we return + * nothing. + * + * @InOut: + * face :: + * The font face. + */ + static void + ft_var_load_avar( TT_Face face ) + { + FT_Error error; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + FT_Int i, j; + + GX_Blend blend = face->blend; + GX_AVarSegment segment; + GX_AVarTable table; + + FT_Long version; + FT_Long axisCount; + FT_ULong table_len; + +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + FT_ULong table_offset; + FT_ULong store_offset; + FT_ULong axisMap_offset; +#endif + + + FT_TRACE2(( "AVAR " )); + + blend->avar_loaded = TRUE; + error = face->goto_table( face, TTAG_avar, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + return; + } + +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + table_offset = FT_STREAM_POS(); +#endif + + if ( FT_FRAME_ENTER( table_len ) ) + return; + + version = FT_GET_LONG(); + axisCount = FT_GET_LONG(); + + if ( version != 0x00010000L +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + && version != 0x00020000L +#endif + ) + { + FT_TRACE2(( "bad table version\n" )); + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + + if ( axisCount != (FT_Long)blend->mmvar->num_axis ) + { + FT_TRACE2(( "ft_var_load_avar:" + " number of axes in `avar' and `fvar'\n" )); + FT_TRACE2(( " table are different\n" )); + goto Exit; + } + + if ( FT_NEW( blend->avar_table ) ) + goto Exit; + table = blend->avar_table; + + if ( FT_QNEW_ARRAY( table->avar_segment, axisCount ) ) + goto Exit; + + segment = &table->avar_segment[0]; + for ( i = 0; i < axisCount; i++, segment++ ) + { + FT_TRACE5(( " axis %d:\n", i )); + + segment->pairCount = FT_GET_USHORT(); + if ( (FT_ULong)segment->pairCount * 4 > table_len || + FT_QNEW_ARRAY( segment->correspondence, segment->pairCount ) ) + { + /* Failure. Free everything we have done so far. We must do */ + /* it right now since loading the `avar' table is optional. */ + + for ( j = i - 1; j >= 0; j-- ) + FT_FREE( table->avar_segment[j].correspondence ); + + FT_FREE( table->avar_segment ); + goto Exit; + } + + for ( j = 0; j < segment->pairCount; j++ ) + { + segment->correspondence[j].fromCoord = + FT_fdot14ToFixed( FT_GET_SHORT() ); + segment->correspondence[j].toCoord = + FT_fdot14ToFixed( FT_GET_SHORT() ); + + FT_TRACE5(( " mapping %.5f to %.5f\n", + (double)segment->correspondence[j].fromCoord / 65536, + (double)segment->correspondence[j].toCoord / 65536 )); + } + + FT_TRACE5(( "\n" )); + } + +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + if ( version < 0x00020000L ) + goto Exit; + + axisMap_offset = FT_GET_ULONG(); + store_offset = FT_GET_ULONG(); + + if ( store_offset ) + { + error = tt_var_load_item_variation_store( + FT_FACE( face ), + table_offset + store_offset, + &table->itemStore ); + if ( error ) + goto Exit; + } + + if ( axisMap_offset ) + { + error = tt_var_load_delta_set_index_mapping( + FT_FACE( face ), + table_offset + axisMap_offset, + &table->axisMap, + &table->itemStore, + table_len ); + if ( error ) + goto Exit; + } +#endif + + + Exit: + FT_FRAME_EXIT(); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_var_load_item_variation_store( FT_Face face, /* TT_Face */ + FT_ULong offset, + GX_ItemVarStore itemStore ) + { + TT_Face ttface = (TT_Face)face; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + FT_Error error; + FT_UShort format; + FT_ULong region_offset; + + FT_UInt data_count; + FT_UShort axis_count; + FT_UInt region_count; + + FT_UInt i, j; + FT_Bool long_words; + + GX_Blend blend = ttface->blend; + FT_ULong* dataOffsetArray = NULL; + + + if ( FT_STREAM_SEEK( offset ) || + FT_READ_USHORT( format ) ) + goto Exit; + + if ( format != 1 ) + { + FT_TRACE2(( "tt_var_load_item_variation_store: bad store format %d\n", + format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* read top level fields */ + if ( FT_READ_ULONG( region_offset ) || + FT_READ_USHORT( data_count ) ) + goto Exit; + + /* we need at least one entry in `itemStore->varData' */ + if ( !data_count ) + { + FT_TRACE2(( "tt_var_load_item_variation_store: missing varData\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* make temporary copy of item variation data offsets; */ + /* we will parse region list first, then come back */ + if ( FT_QNEW_ARRAY( dataOffsetArray, data_count ) ) + goto Exit; + + for ( i = 0; i < data_count; i++ ) + { + if ( FT_READ_ULONG( dataOffsetArray[i] ) ) + goto Exit; + } + + /* parse array of region records (region list) */ + if ( FT_STREAM_SEEK( offset + region_offset ) ) + goto Exit; + + if ( FT_READ_USHORT( axis_count ) || + FT_READ_USHORT( region_count ) ) + goto Exit; + + if ( axis_count != (FT_Long)blend->mmvar->num_axis ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " number of axes in item variation store\n" )); + FT_TRACE2(( " " + " and `fvar' table are different\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + itemStore->axisCount = axis_count; + + /* new constraint in OpenType 1.8.4 */ + if ( region_count >= 32768U ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " too many variation region tables\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_NEW_ARRAY( itemStore->varRegionList, region_count ) ) + goto Exit; + itemStore->regionCount = region_count; + + for ( i = 0; i < itemStore->regionCount; i++ ) + { + GX_AxisCoords axisCoords; + + + if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, axis_count ) ) + goto Exit; + + axisCoords = itemStore->varRegionList[i].axisList; + + for ( j = 0; j < itemStore->axisCount; j++ ) + { + FT_Short start, peak, end; + + + if ( FT_READ_SHORT( start ) || + FT_READ_SHORT( peak ) || + FT_READ_SHORT( end ) ) + goto Exit; + + axisCoords[j].startCoord = FT_fdot14ToFixed( start ); + axisCoords[j].peakCoord = FT_fdot14ToFixed( peak ); + axisCoords[j].endCoord = FT_fdot14ToFixed( end ); + } + } + + /* end of region list parse */ + + /* use dataOffsetArray now to parse varData items */ + if ( FT_NEW_ARRAY( itemStore->varData, data_count ) ) + goto Exit; + itemStore->dataCount = data_count; + + for ( i = 0; i < data_count; i++ ) + { + GX_ItemVarData varData = &itemStore->varData[i]; + + FT_UInt item_count; + FT_UShort word_delta_count; + FT_UInt region_idx_count; + FT_UInt per_region_size; + + + if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) ) + goto Exit; + + if ( FT_READ_USHORT( item_count ) || + FT_READ_USHORT( word_delta_count ) || + FT_READ_USHORT( region_idx_count ) ) + goto Exit; + + long_words = !!( word_delta_count & 0x8000 ); + word_delta_count &= 0x7FFF; + + /* check some data consistency */ + if ( word_delta_count > region_idx_count ) + { + FT_TRACE2(( "bad short count %d or region count %d\n", + word_delta_count, + region_idx_count )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( region_idx_count > itemStore->regionCount ) + { + FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n", + region_idx_count, + i )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* parse region indices */ + if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) ) + goto Exit; + varData->regionIdxCount = region_idx_count; + varData->wordDeltaCount = word_delta_count; + varData->longWords = long_words; + + for ( j = 0; j < varData->regionIdxCount; j++ ) + { + if ( FT_READ_USHORT( varData->regionIndices[j] ) ) + goto Exit; + + if ( varData->regionIndices[j] >= itemStore->regionCount ) + { + FT_TRACE2(( "bad region index %d\n", + varData->regionIndices[j] )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + per_region_size = word_delta_count + region_idx_count; + if ( long_words ) + per_region_size *= 2; + + if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) ) + goto Exit; + if ( FT_Stream_Read( stream, + varData->deltaSet, + per_region_size * item_count ) ) + { + FT_TRACE2(( "deltaSet read failed." )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + varData->itemCount = item_count; + } + + Exit: + FT_FREE( dataOffsetArray ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_var_load_delta_set_index_mapping( FT_Face face, /* TT_Face */ + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + FT_Error error; + + FT_Byte format; + FT_Byte entryFormat; + FT_UInt entrySize; + FT_UInt innerBitCount; + FT_UInt innerIndexMask; + FT_ULong i; + FT_UInt j; + + + if ( FT_STREAM_SEEK( offset ) || + FT_READ_BYTE( format ) || + FT_READ_BYTE( entryFormat ) ) + goto Exit; + + if ( format == 0 ) + { + if ( FT_READ_USHORT( map->mapCount ) ) + goto Exit; + } + else if ( format == 1 ) /* new in OpenType 1.9 */ + { + if ( FT_READ_ULONG( map->mapCount ) ) + goto Exit; + } + else + { + FT_TRACE2(( "bad map format %d\n", format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( entryFormat & 0xC0 ) + { + FT_TRACE2(( "bad entry format %d\n", format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* bytes per entry: 1, 2, 3, or 4 */ + entrySize = ( ( entryFormat & 0x30 ) >> 4 ) + 1; + innerBitCount = ( entryFormat & 0x0F ) + 1; + innerIndexMask = ( 1 << innerBitCount ) - 1; + + /* rough sanity check */ + if ( map->mapCount * entrySize > table_len ) + { + FT_TRACE1(( "tt_var_load_delta_set_index_mapping:" + " invalid number of delta-set index mappings\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) ) + goto Exit; + + if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) ) + goto Exit; + + for ( i = 0; i < map->mapCount; i++ ) + { + FT_UInt mapData = 0; + FT_UInt outerIndex, innerIndex; + + + /* read map data one unsigned byte at a time, big endian */ + for ( j = 0; j < entrySize; j++ ) + { + FT_Byte data; + + + if ( FT_READ_BYTE( data ) ) + goto Exit; + + mapData = ( mapData << 8 ) | data; + } + + /* new in OpenType 1.8.4 */ + if ( mapData == 0xFFFFFFFFUL ) + { + /* no variation data for this item */ + map->outerIndex[i] = 0xFFFFU; + map->innerIndex[i] = 0xFFFFU; + + continue; + } + + outerIndex = mapData >> innerBitCount; + + if ( outerIndex >= itemStore->dataCount ) + { + FT_TRACE2(( "outerIndex[%ld] == %d out of range\n", + i, + outerIndex )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + map->outerIndex[i] = outerIndex; + + innerIndex = mapData & innerIndexMask; + + if ( innerIndex >= itemStore->varData[outerIndex].itemCount ) + { + FT_TRACE2(( "innerIndex[%ld] == %d out of range\n", + i, + innerIndex )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + map->innerIndex[i] = innerIndex; + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * ft_var_load_hvvar + * + * @Description: + * If `vertical' is zero, parse the `HVAR' table and set + * `blend->hvar_loaded' to TRUE. On success, `blend->hvar_checked' + * is set to TRUE. + * + * If `vertical' is not zero, parse the `VVAR' table and set + * `blend->vvar_loaded' to TRUE. On success, `blend->vvar_checked' + * is set to TRUE. + * + * Some memory may remain allocated on error; it is always freed in + * `tt_done_blend', however. + * + * @InOut: + * face :: + * The font face. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + ft_var_load_hvvar( TT_Face face, + FT_Bool vertical ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + GX_Blend blend = face->blend; + + GX_HVVarTable table; + + FT_Error error; + FT_UShort majorVersion; + FT_ULong table_len; + FT_ULong table_offset; + FT_ULong store_offset; + FT_ULong widthMap_offset; + + + if ( vertical ) + { + blend->vvar_loaded = TRUE; + + FT_TRACE2(( "VVAR " )); + + error = face->goto_table( face, TTAG_VVAR, stream, &table_len ); + } + else + { + blend->hvar_loaded = TRUE; + + FT_TRACE2(( "HVAR " )); + + error = face->goto_table( face, TTAG_HVAR, stream, &table_len ); + } + + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + goto Exit; + } + + table_offset = FT_STREAM_POS(); + + /* skip minor version */ + if ( FT_READ_USHORT( majorVersion ) || + FT_STREAM_SKIP( 2 ) ) + goto Exit; + + if ( majorVersion != 1 ) + { + FT_TRACE2(( "bad table version %d\n", majorVersion )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_READ_ULONG( store_offset ) || + FT_READ_ULONG( widthMap_offset ) ) + goto Exit; + + if ( vertical ) + { + if ( FT_NEW( blend->vvar_table ) ) + goto Exit; + table = blend->vvar_table; + } + else + { + if ( FT_NEW( blend->hvar_table ) ) + goto Exit; + table = blend->hvar_table; + } + + error = tt_var_load_item_variation_store( + FT_FACE( face ), + table_offset + store_offset, + &table->itemStore ); + if ( error ) + goto Exit; + + if ( widthMap_offset ) + { + error = tt_var_load_delta_set_index_mapping( + FT_FACE( face ), + table_offset + widthMap_offset, + &table->widthMap, + &table->itemStore, + table_len ); + if ( error ) + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + error = FT_Err_Ok; + + Exit: + if ( !error ) + { + if ( vertical ) + { + blend->vvar_checked = TRUE; + + /* FreeType doesn't provide functions to quickly retrieve */ + /* TSB, BSB, or VORG values; we thus don't have to implement */ + /* support for those three item variation stores. */ + + face->variation_support |= TT_FACE_FLAG_VAR_VADVANCE; + } + else + { + blend->hvar_checked = TRUE; + + /* FreeType doesn't provide functions to quickly retrieve */ + /* LSB or RSB values; we thus don't have to implement */ + /* support for those two item variation stores. */ + + face->variation_support |= TT_FACE_FLAG_VAR_HADVANCE; + } + } + + return error; + } + + + FT_LOCAL_DEF( FT_ItemVarDelta ) + tt_var_get_item_delta( FT_Face face, /* TT_Face */ + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ) + { + TT_Face ttface = (TT_Face)face; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + + GX_ItemVarData varData; + FT_ItemVarDelta* deltaSet = NULL; + FT_ItemVarDelta deltaSetStack[16]; + + FT_Fixed* scalars = NULL; + FT_Fixed scalarsStack[16]; + + FT_UInt master, j; + FT_ItemVarDelta returnValue = 0; + FT_UInt per_region_size; + FT_Byte* bytes; + + + if ( !ttface->blend || !ttface->blend->normalizedcoords ) + return 0; + + /* OpenType 1.8.4+: No variation data for this item */ + /* as indices have special value 0xFFFF. */ + if ( outerIndex == 0xFFFF && innerIndex == 0xFFFF ) + return 0; + + /* See pseudo code from `Font Variations Overview' */ + /* in the OpenType specification. */ + + if ( outerIndex >= itemStore->dataCount ) + return 0; /* Out of range. */ + + varData = &itemStore->varData[outerIndex]; + + if ( innerIndex >= varData->itemCount ) + return 0; /* Out of range. */ + + if ( varData->regionIdxCount < 16 ) + { + deltaSet = deltaSetStack; + scalars = scalarsStack; + } + else + { + if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) ) + goto Exit; + if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) ) + goto Exit; + } + + /* Parse delta set. */ + /* */ + /* Deltas are (word_delta_count + region_idx_count) bytes each */ + /* if `longWords` isn't set, and twice as much otherwise. */ + per_region_size = varData->wordDeltaCount + varData->regionIdxCount; + if ( varData->longWords ) + per_region_size *= 2; + + bytes = varData->deltaSet + per_region_size * innerIndex; + + if ( varData->longWords ) + { + for ( master = 0; master < varData->wordDeltaCount; master++ ) + deltaSet[master] = FT_NEXT_LONG( bytes ); + for ( ; master < varData->regionIdxCount; master++ ) + deltaSet[master] = FT_NEXT_SHORT( bytes ); + } + else + { + for ( master = 0; master < varData->wordDeltaCount; master++ ) + deltaSet[master] = FT_NEXT_SHORT( bytes ); + for ( ; master < varData->regionIdxCount; master++ ) + deltaSet[master] = FT_NEXT_CHAR( bytes ); + } + + /* outer loop steps through master designs to be blended */ + for ( master = 0; master < varData->regionIdxCount; master++ ) + { + FT_Fixed scalar = 0x10000L; + FT_UInt regionIndex = varData->regionIndices[master]; + + GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList; + + + /* inner loop steps through axes in this region */ + for ( j = 0; j < itemStore->axisCount; j++, axis++ ) + { + /* compute the scalar contribution of this axis; */ + /* ignore invalid ranges */ + if ( axis->startCoord > axis->peakCoord || + axis->peakCoord > axis->endCoord ) + continue; + + else if ( axis->startCoord < 0 && + axis->endCoord > 0 && + axis->peakCoord != 0 ) + continue; + + /* peak of 0 means ignore this axis */ + else if ( axis->peakCoord == 0 ) + continue; + + else if ( ttface->blend->normalizedcoords[j] == axis->peakCoord ) + continue; + + /* ignore this region if coords are out of range */ + else if ( ttface->blend->normalizedcoords[j] <= axis->startCoord || + ttface->blend->normalizedcoords[j] >= axis->endCoord ) + { + scalar = 0; + break; + } + + /* cumulative product of all the axis scalars */ + else if ( ttface->blend->normalizedcoords[j] < axis->peakCoord ) + scalar = + FT_MulDiv( scalar, + ttface->blend->normalizedcoords[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else + scalar = + FT_MulDiv( scalar, + axis->endCoord - ttface->blend->normalizedcoords[j], + axis->endCoord - axis->peakCoord ); + + } /* per-axis loop */ + + scalars[master] = scalar; + + } /* per-region loop */ + + + /* Compute the scaled delta for this region. + * + * From: https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables: + * + * `Fixed` is a 32-bit (16.16) type and, in the general case, requires + * 32-bit deltas. As described above, the `DeltaSet` record can + * accommodate deltas that are, logically, either 16-bit or 32-bit. + * When scaled deltas are applied to `Fixed` values, the `Fixed` value + * is treated like a 32-bit integer. + * + * `FT_MulAddFix` internally uses 64-bit precision; it thus can handle + * deltas ranging from small 8-bit to large 32-bit values that are + * applied to 16.16 `FT_Fixed` / OpenType `Fixed` values. + */ + returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount ); + + Exit: + if ( scalars != scalarsStack ) + FT_FREE( scalars ); + if ( deltaSet != deltaSetStack ) + FT_FREE( deltaSet ); + + return returnValue; + } + + + /************************************************************************** + * + * @Function: + * tt_hvadvance_adjust + * + * @Description: + * Apply `HVAR' advance width or `VVAR' advance height adjustment of + * a given glyph. + * + * @Input: + * gindex :: + * The glyph index. + * + * vertical :: + * If set, handle `VVAR' table. + * + * @InOut: + * face :: + * The font face. + * + * adelta :: + * Points to width or height value that gets modified. + */ + static FT_Error + tt_hvadvance_adjust( TT_Face face, + FT_UInt gindex, + FT_Int *avalue, + FT_Bool vertical ) + { + FT_Error error = FT_Err_Ok; + FT_UInt innerIndex, outerIndex; + FT_Int delta; + + GX_HVVarTable table; + + + if ( !face->doblend || !face->blend ) + goto Exit; + + if ( vertical ) + { + if ( !face->blend->vvar_loaded ) + { + /* initialize vvar table */ + face->blend->vvar_error = ft_var_load_hvvar( face, 1 ); + } + + if ( !face->blend->vvar_checked ) + { + error = face->blend->vvar_error; + goto Exit; + } + + table = face->blend->vvar_table; + } + else + { + if ( !face->blend->hvar_loaded ) + { + /* initialize hvar table */ + face->blend->hvar_error = ft_var_load_hvvar( face, 0 ); + } + + if ( !face->blend->hvar_checked ) + { + error = face->blend->hvar_error; + goto Exit; + } + + table = face->blend->hvar_table; + } + + /* advance width or height adjustments are always present in an */ + /* `HVAR' or `VVAR' table; no need to test for this capability */ + + if ( table->widthMap.innerIndex ) + { + FT_UInt idx = gindex; + + + if ( idx >= table->widthMap.mapCount ) + idx = table->widthMap.mapCount - 1; + + /* trust that HVAR parser has checked indices */ + outerIndex = table->widthMap.outerIndex[idx]; + innerIndex = table->widthMap.innerIndex[idx]; + } + else + { + /* no widthMap data */ + outerIndex = 0; + innerIndex = gindex; + } + + delta = tt_var_get_item_delta( FT_FACE( face ), + &table->itemStore, + outerIndex, + innerIndex ); + + if ( delta ) + { + FT_TRACE5(( "%s value %d adjusted by %d unit%s (%s)\n", + vertical ? "vertical height" : "horizontal width", + *avalue, + delta, + delta == 1 ? "" : "s", + vertical ? "VVAR" : "HVAR" )); + + *avalue = ADD_INT( *avalue, delta ); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_hadvance_adjust( FT_Face face, /* TT_Face */ + FT_UInt gindex, + FT_Int *avalue ) + { + return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 0 ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_vadvance_adjust( FT_Face face, /* TT_Face */ + FT_UInt gindex, + FT_Int *avalue ) + { + return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 1 ); + } + + +#define GX_VALUE_SIZE 8 + + /* all values are FT_Short or FT_UShort entities; */ + /* we treat them consistently as FT_Short */ +#define GX_VALUE_CASE( tag, dflt ) \ + case MVAR_TAG_ ## tag : \ + p = (FT_Short*)&face->dflt; \ + break + +#define GX_GASP_CASE( idx ) \ + case MVAR_TAG_GASP_ ## idx : \ + if ( idx < face->gasp.numRanges - 1 ) \ + p = (FT_Short*)&face->gasp.gaspRanges[idx].maxPPEM; \ + else \ + p = NULL; \ + break + + + static FT_Short* + ft_var_get_value_pointer( TT_Face face, + FT_ULong mvar_tag ) + { + FT_Short* p; + + + switch ( mvar_tag ) + { + GX_GASP_CASE( 0 ); + GX_GASP_CASE( 1 ); + GX_GASP_CASE( 2 ); + GX_GASP_CASE( 3 ); + GX_GASP_CASE( 4 ); + GX_GASP_CASE( 5 ); + GX_GASP_CASE( 6 ); + GX_GASP_CASE( 7 ); + GX_GASP_CASE( 8 ); + GX_GASP_CASE( 9 ); + + GX_VALUE_CASE( CPHT, os2.sCapHeight ); + GX_VALUE_CASE( HASC, os2.sTypoAscender ); + GX_VALUE_CASE( HCLA, os2.usWinAscent ); + GX_VALUE_CASE( HCLD, os2.usWinDescent ); + GX_VALUE_CASE( HCOF, horizontal.caret_Offset ); + GX_VALUE_CASE( HCRN, horizontal.caret_Slope_Run ); + GX_VALUE_CASE( HCRS, horizontal.caret_Slope_Rise ); + GX_VALUE_CASE( HDSC, os2.sTypoDescender ); + GX_VALUE_CASE( HLGP, os2.sTypoLineGap ); + GX_VALUE_CASE( SBXO, os2.ySubscriptXOffset); + GX_VALUE_CASE( SBXS, os2.ySubscriptXSize ); + GX_VALUE_CASE( SBYO, os2.ySubscriptYOffset ); + GX_VALUE_CASE( SBYS, os2.ySubscriptYSize ); + GX_VALUE_CASE( SPXO, os2.ySuperscriptXOffset ); + GX_VALUE_CASE( SPXS, os2.ySuperscriptXSize ); + GX_VALUE_CASE( SPYO, os2.ySuperscriptYOffset ); + GX_VALUE_CASE( SPYS, os2.ySuperscriptYSize ); + GX_VALUE_CASE( STRO, os2.yStrikeoutPosition ); + GX_VALUE_CASE( STRS, os2.yStrikeoutSize ); + GX_VALUE_CASE( UNDO, postscript.underlinePosition ); + GX_VALUE_CASE( UNDS, postscript.underlineThickness ); + GX_VALUE_CASE( VASC, vertical.Ascender ); + GX_VALUE_CASE( VCOF, vertical.caret_Offset ); + GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run ); + GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise ); + GX_VALUE_CASE( VDSC, vertical.Descender ); + GX_VALUE_CASE( VLGP, vertical.Line_Gap ); + GX_VALUE_CASE( XHGT, os2.sxHeight ); + + default: + /* ignore unknown tag */ + p = NULL; + } + + return p; + } + + + /************************************************************************** + * + * @Function: + * ft_var_load_mvar + * + * @Description: + * Parse the `MVAR' table. + * + * Some memory may remain allocated on error; it is always freed in + * `tt_done_blend', however. + * + * @InOut: + * face :: + * The font face. + */ + static void + ft_var_load_mvar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + GX_Blend blend = face->blend; + GX_ItemVarStore itemStore; + GX_Value value, limit; + + FT_Error error; + FT_UShort majorVersion; + FT_ULong table_len; + FT_ULong table_offset; + FT_UShort store_offset; + FT_ULong records_offset; + + + FT_TRACE2(( "MVAR " )); + + error = face->goto_table( face, TTAG_MVAR, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + return; + } + + table_offset = FT_STREAM_POS(); + + /* skip minor version */ + if ( FT_READ_USHORT( majorVersion ) || + FT_STREAM_SKIP( 2 ) ) + return; + + if ( majorVersion != 1 ) + { + FT_TRACE2(( "bad table version %d\n", majorVersion )); + return; + } + + if ( FT_NEW( blend->mvar_table ) ) + return; + + /* skip reserved entry and value record size */ + if ( FT_STREAM_SKIP( 4 ) || + FT_READ_USHORT( blend->mvar_table->valueCount ) || + FT_READ_USHORT( store_offset ) ) + return; + + records_offset = FT_STREAM_POS(); + + error = tt_var_load_item_variation_store( + FT_FACE( face ), + table_offset + store_offset, + &blend->mvar_table->itemStore ); + if ( error ) + return; + + if ( FT_NEW_ARRAY( blend->mvar_table->values, + blend->mvar_table->valueCount ) ) + return; + + if ( FT_STREAM_SEEK( records_offset ) || + FT_FRAME_ENTER( blend->mvar_table->valueCount * GX_VALUE_SIZE ) ) + return; + + value = blend->mvar_table->values; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); + itemStore = &blend->mvar_table->itemStore; + + for ( ; value < limit; value++ ) + { + value->tag = FT_GET_ULONG(); + value->outerIndex = FT_GET_USHORT(); + value->innerIndex = FT_GET_USHORT(); + + /* new in OpenType 1.8.4 */ + if ( value->outerIndex == 0xFFFFU && value->innerIndex == 0xFFFFU ) + { + /* no variation data for this item */ + continue; + } + + if ( value->outerIndex >= itemStore->dataCount || + value->innerIndex >= itemStore->varData[value->outerIndex] + .itemCount ) + { + error = FT_THROW( Invalid_Table ); + break; + } + } + + FT_FRAME_EXIT(); + + if ( error ) + return; + + FT_TRACE2(( "loaded\n" )); + + value = blend->mvar_table->values; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); + + /* save original values of the data MVAR is going to modify */ + for ( ; value < limit; value++ ) + { + FT_Short* p = ft_var_get_value_pointer( face, value->tag ); + + + if ( p ) + value->unmodified = *p; +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE1(( "ft_var_load_mvar: Ignoring unknown tag `%c%c%c%c'\n", + (FT_Char)( value->tag >> 24 ), + (FT_Char)( value->tag >> 16 ), + (FT_Char)( value->tag >> 8 ), + (FT_Char)( value->tag ) )); +#endif + } + + face->variation_support |= TT_FACE_FLAG_VAR_MVAR; + } + + + static FT_Error + ft_size_reset_iterator( FT_ListNode node, + void* user ) + { + FT_Size size = (FT_Size)node->data; + FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)user; + + + var->size_reset( size ); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_apply_mvar + * + * @Description: + * Apply `MVAR' table adjustments. + * + * @InOut: + * face :: + * The font face. + */ + FT_LOCAL_DEF( void ) + tt_apply_mvar( FT_Face face ) /* TT_Face */ + { + TT_Face ttface = (TT_Face)face; + + GX_Blend blend = ttface->blend; + GX_Value value, limit; + + FT_Short mvar_hasc_delta = 0; + FT_Short mvar_hdsc_delta = 0; + FT_Short mvar_hlgp_delta = 0; + + + if ( !( ttface->variation_support & TT_FACE_FLAG_VAR_MVAR ) ) + return; + + value = blend->mvar_table->values; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); + + for ( ; value < limit; value++ ) + { + FT_Short* p = ft_var_get_value_pointer( ttface, value->tag ); + FT_Int delta; + + + delta = tt_var_get_item_delta( face, + &blend->mvar_table->itemStore, + value->outerIndex, + value->innerIndex ); + + if ( p && delta ) + { + FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n", + (FT_Char)( value->tag >> 24 ), + (FT_Char)( value->tag >> 16 ), + (FT_Char)( value->tag >> 8 ), + (FT_Char)( value->tag ), + value->unmodified, + value->unmodified == 1 ? "" : "s", + delta, + delta == 1 ? "" : "s" )); + + /* since we handle both signed and unsigned values as FT_Short, */ + /* ensure proper overflow arithmetic */ + *p = (FT_Short)( value->unmodified + (FT_Short)delta ); + + /* Treat hasc, hdsc and hlgp specially, see below. */ + if ( value->tag == MVAR_TAG_HASC ) + mvar_hasc_delta = (FT_Short)delta; + else if ( value->tag == MVAR_TAG_HDSC ) + mvar_hdsc_delta = (FT_Short)delta; + else if ( value->tag == MVAR_TAG_HLGP ) + mvar_hlgp_delta = (FT_Short)delta; + } + } + + /* adjust all derived values */ + { + FT_Service_MetricsVariations var = + (FT_Service_MetricsVariations)ttface->face_var; + + /* + * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender, + * descender and height attributes, no matter how they were originally + * computed. + * + * (Code that ignores those and accesses the font's metrics values + * directly is already served by the delta application code above.) + * + * The MVAR table supports variations for both typo and win metrics. + * According to Behdad Esfahbod, the thinking of the working group was + * that no one uses win metrics anymore for setting line metrics (the + * specification even calls these metrics "horizontal clipping + * ascent/descent", probably for their role on the Windows platform in + * computing clipping boxes), and new fonts should use typo metrics, so + * typo deltas should be applied to whatever sfnt_load_face decided the + * line metrics should be. + * + * Before, the following led to different line metrics between default + * outline and instances, visible when e.g. the default outlines were + * used as the regular face and instances for everything else: + * + * 1. sfnt_load_face applied the hhea metrics by default. + * 2. This code later applied the typo metrics by default, regardless of + * whether they were actually changed or the font had the OS/2 table's + * fsSelection's bit 7 (USE_TYPO_METRICS) set. + */ + FT_Short current_line_gap = face->height - face->ascender + + face->descender; + + + face->ascender = face->ascender + mvar_hasc_delta; + face->descender = face->descender + mvar_hdsc_delta; + face->height = face->ascender - face->descender + + current_line_gap + mvar_hlgp_delta; + + face->underline_position = ttface->postscript.underlinePosition - + ttface->postscript.underlineThickness / 2; + face->underline_thickness = ttface->postscript.underlineThickness; + + /* iterate over all FT_Size objects and call `var->size_reset' */ + /* to propagate the metrics changes */ + if ( var && var->size_reset ) + FT_List_Iterate( &face->sizes_list, + ft_size_reset_iterator, + (void*)var ); + } + } + + + typedef struct GX_GVar_Head_ + { + FT_Long version; + FT_UShort axisCount; + FT_UShort globalCoordCount; + FT_ULong offsetToCoord; + FT_UShort glyphCount; + FT_UShort flags; + FT_ULong offsetToData; + + } GX_GVar_Head; + + + /************************************************************************** + * + * @Function: + * ft_var_load_gvar + * + * @Description: + * Parse the `gvar' table if present. If `fvar' is there, `gvar' had + * better be there too. + * + * @InOut: + * face :: + * The font face. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + ft_var_load_gvar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + FT_Error error; + FT_UInt i, j; + FT_ULong table_len; + FT_ULong gvar_start; + FT_ULong offsetToData; + FT_ULong offsets_len; + GX_GVar_Head gvar_head; + + static const FT_Frame_Field gvar_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_GVar_Head + + FT_FRAME_START( 20 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( axisCount ), + FT_FRAME_USHORT( globalCoordCount ), + FT_FRAME_ULONG ( offsetToCoord ), + FT_FRAME_USHORT( glyphCount ), + FT_FRAME_USHORT( flags ), + FT_FRAME_ULONG ( offsetToData ), + FT_FRAME_END + }; + + + FT_TRACE2(( "GVAR " )); + + if ( FT_SET_ERROR( face->goto_table( face, + TTAG_gvar, + stream, + &table_len ) ) ) + { + FT_TRACE2(( "is missing\n" )); + goto Exit; + } + + gvar_start = FT_STREAM_POS( ); + if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) + goto Exit; + + if ( gvar_head.version != 0x00010000L ) + { + FT_TRACE1(( "bad table version\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) + { + FT_TRACE1(( "ft_var_load_gvar:" + " number of axes in `gvar' and `cvar'\n" )); + FT_TRACE1(( " table are different\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* rough sanity check, ignoring offsets */ + if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount > + table_len / 2 ) + { + FT_TRACE1(( "ft_var_load_gvar:" + " invalid number of global coordinates\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* offsets can be either 2 or 4 bytes */ + /* (one more offset than glyphs, to mark size of last) */ + offsets_len = ( gvar_head.glyphCount + 1 ) * + ( ( gvar_head.flags & 1 ) ? 4L : 2L ); + + /* rough sanity check */ + if (offsets_len > table_len ) + { + FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + + blend->gvar_size = table_len; + offsetToData = gvar_start + gvar_head.offsetToData; + + FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n", + gvar_head.globalCoordCount == 1 ? "is" : "are", + gvar_head.globalCoordCount, + gvar_head.globalCoordCount == 1 ? "" : "s" )); + + if ( FT_FRAME_ENTER( offsets_len ) ) + goto Exit; + + /* offsets (one more offset than glyphs, to mark size of last) */ + if ( FT_QNEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) ) + goto Fail2; + + if ( gvar_head.flags & 1 ) + { + FT_ULong limit = gvar_start + table_len; + FT_ULong max_offset = 0; + + + for ( i = 0; i <= gvar_head.glyphCount; i++ ) + { + blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); + + if ( max_offset <= blend->glyphoffsets[i] ) + max_offset = blend->glyphoffsets[i]; + else + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d not monotonic\n", + i )); + blend->glyphoffsets[i] = max_offset; + } + + /* use `<', not `<=' */ + if ( limit < blend->glyphoffsets[i] ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d out of range\n", + i )); + blend->glyphoffsets[i] = limit; + } + } + } + else + { + FT_ULong limit = gvar_start + table_len; + FT_ULong max_offset = 0; + + + for ( i = 0; i <= gvar_head.glyphCount; i++ ) + { + blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; + + if ( max_offset <= blend->glyphoffsets[i] ) + max_offset = blend->glyphoffsets[i]; + else + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d not monotonic\n", + i )); + blend->glyphoffsets[i] = max_offset; + } + + /* use `<', not `<=' */ + if ( limit < blend->glyphoffsets[i] ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d out of range\n", + i )); + blend->glyphoffsets[i] = limit; + } + } + } + + blend->gv_glyphcnt = gvar_head.glyphCount; + + FT_FRAME_EXIT(); + + if ( gvar_head.globalCoordCount != 0 ) + { + if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || + FT_FRAME_ENTER( gvar_head.globalCoordCount * + gvar_head.axisCount * 2L ) ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation shared tuples missing\n" )); + goto Fail; + } + + if ( FT_QNEW_ARRAY( blend->tuplecoords, + gvar_head.axisCount * gvar_head.globalCoordCount ) ) + goto Fail2; + + for ( i = 0; i < gvar_head.globalCoordCount; i++ ) + { + FT_TRACE5(( " [ " )); + for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ ) + { + blend->tuplecoords[i * gvar_head.axisCount + j] = + FT_fdot14ToFixed( FT_GET_SHORT() ); + FT_TRACE5(( "%.5f ", + (double)blend->tuplecoords[i * gvar_head.axisCount + j] / 65536 )); + } + FT_TRACE5(( "]\n" )); + } + + blend->tuplecount = gvar_head.globalCoordCount; + + FT_TRACE5(( "\n" )); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + + Fail2: + FT_FRAME_EXIT(); + + Fail: + FT_FREE( blend->glyphoffsets ); + blend->gv_glyphcnt = 0; + goto Exit; + } + + + /************************************************************************** + * + * @Function: + * ft_var_apply_tuple + * + * @Description: + * Figure out whether a given tuple (design) applies to the current + * blend, and if so, what is the scaling factor. + * + * @Input: + * blend :: + * The current blend of the font. + * + * tupleIndex :: + * A flag saying whether this is an intermediate + * tuple or not. + * + * tuple_coords :: + * The coordinates of the tuple in normalized axis + * units. + * + * im_start_coords :: + * The initial coordinates where this tuple starts + * to apply (for intermediate coordinates). + * + * im_end_coords :: + * The final coordinates after which this tuple no + * longer applies (for intermediate coordinates). + * + * @Return: + * An FT_Fixed value containing the scaling factor. + */ + static FT_Fixed + ft_var_apply_tuple( GX_Blend blend, + FT_UShort tupleIndex, + FT_Fixed* tuple_coords, + FT_Fixed* im_start_coords, + FT_Fixed* im_end_coords ) + { + FT_UInt i; + FT_Fixed apply = 0x10000L; + + + for ( i = 0; i < blend->num_axis; i++ ) + { + FT_TRACE6(( " axis %d coordinate %.5f:\n", + i, (double)blend->normalizedcoords[i] / 65536 )); + + /* It's not clear why (for intermediate tuples) we don't need */ + /* to check against start/end -- the documentation says we don't. */ + /* Similarly, it's unclear why we don't need to scale along the */ + /* axis. */ + + if ( tuple_coords[i] == 0 ) + { + FT_TRACE6(( " tuple coordinate is zero, ignore\n" )); + continue; + } + + if ( blend->normalizedcoords[i] == 0 ) + { + FT_TRACE6(( " axis coordinate is zero, stop\n" )); + apply = 0; + break; + } + + if ( blend->normalizedcoords[i] == tuple_coords[i] ) + { + FT_TRACE6(( " tuple coordinate %.5f fits perfectly\n", + (double)tuple_coords[i] / 65536 )); + /* `apply' does not change */ + continue; + } + + if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) + { + /* not an intermediate tuple */ + + if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) || + blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) ) + { + FT_TRACE6(( " tuple coordinate %.5f is exceeded, stop\n", + (double)tuple_coords[i] / 65536 )); + apply = 0; + break; + } + + FT_TRACE6(( " tuple coordinate %.5f fits\n", + (double)tuple_coords[i] / 65536 )); + apply = FT_MulDiv( apply, + blend->normalizedcoords[i], + tuple_coords[i] ); + } + else + { + /* intermediate tuple */ + + if ( blend->normalizedcoords[i] <= im_start_coords[i] || + blend->normalizedcoords[i] >= im_end_coords[i] ) + { + FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ is exceeded," + " stop\n", + (double)im_start_coords[i] / 65536, + (double)im_end_coords[i] / 65536 )); + apply = 0; + break; + } + + FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ fits\n", + (double)im_start_coords[i] / 65536, + (double)im_end_coords[i] / 65536 )); + if ( blend->normalizedcoords[i] < tuple_coords[i] ) + apply = FT_MulDiv( apply, + blend->normalizedcoords[i] - im_start_coords[i], + tuple_coords[i] - im_start_coords[i] ); + else + apply = FT_MulDiv( apply, + im_end_coords[i] - blend->normalizedcoords[i], + im_end_coords[i] - tuple_coords[i] ); + } + } + + FT_TRACE6(( " apply factor is %.5f\n", (double)apply / 65536 )); + + return apply; + } + + + /* convert from design coordinates to normalized coordinates */ + + static void + ft_var_to_normalized( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Fixed* normalized ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = face->root.memory; + FT_UInt i, j; + + GX_Blend blend; + FT_MM_Var* mmvar; + FT_Var_Axis* a; + GX_AVarSegment av; + + FT_Fixed* new_normalized = NULL; + FT_Fixed* old_normalized; + + + blend = face->blend; + mmvar = blend->mmvar; + + if ( num_coords > mmvar->num_axis ) + { + FT_TRACE2(( "ft_var_to_normalized:" + " only using first %d of %d coordinates\n", + mmvar->num_axis, num_coords )); + num_coords = mmvar->num_axis; + } + + /* Axis normalization is a two-stage process. First we normalize */ + /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ + /* Then, if there's an `avar' table, we renormalize this range. */ + + a = mmvar->axis; + for ( i = 0; i < num_coords; i++, a++ ) + { + FT_Fixed coord = coords[i]; + + + FT_TRACE5(( " %d: %.5f\n", i, (double)coord / 65536 )); + if ( coord > a->maximum || coord < a->minimum ) + { + FT_TRACE1(( "ft_var_to_normalized: design coordinate %.5f\n", + (double)coord / 65536 )); + FT_TRACE1(( " is out of range [%.5f;%.5f];" + " clamping\n", + (double)a->minimum / 65536, + (double)a->maximum / 65536 )); + } + + if ( coord > a->def ) + normalized[i] = coord >= a->maximum ? 0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->maximum, a->def ) ); + else if ( coord < a->def ) + normalized[i] = coord <= a->minimum ? -0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->def, a->minimum ) ); + else + normalized[i] = 0; + } + + FT_TRACE5(( "\n" )); + + for ( ; i < mmvar->num_axis; i++ ) + normalized[i] = 0; + + if ( blend->avar_table ) + { + GX_AVarTable table = blend->avar_table; + + + FT_TRACE5(( "normalized design coordinates" + " before applying `avar' data:\n" )); + + if ( table->avar_segment ) + { + av = table->avar_segment; + + for ( i = 0; i < mmvar->num_axis; i++, av++ ) + { + for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) + { + if ( normalized[i] < av->correspondence[j].fromCoord ) + { + FT_TRACE5(( " %.5f\n", (double)normalized[i] / 65536 )); + + normalized[i] = + FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord ) + + av->correspondence[j - 1].toCoord; + break; + } + } + } + } + + if ( table->itemStore.varData ) + { + if ( FT_QNEW_ARRAY( new_normalized, mmvar->num_axis ) ) + return; + + /* Install our half-normalized coordinates for the next */ + /* Item Variation Store to work with. */ + old_normalized = face->blend->normalizedcoords; + face->blend->normalizedcoords = normalized; + + for ( i = 0; i < mmvar->num_axis; i++ ) + { + FT_Fixed v = normalized[i]; + FT_UInt innerIndex = i; + FT_UInt outerIndex = 0; + FT_Int delta; + + + if ( table->axisMap.innerIndex ) + { + FT_UInt idx = i; + + + if ( idx >= table->axisMap.mapCount ) + idx = table->axisMap.mapCount - 1; + + outerIndex = table->axisMap.outerIndex[idx]; + innerIndex = table->axisMap.innerIndex[idx]; + } + + delta = tt_var_get_item_delta( FT_FACE( face ), + &table->itemStore, + outerIndex, + innerIndex ); + + v += delta << 2; + + /* Clamp value range. */ + v = v >= 0x10000L ? 0x10000 : v; + v = v <= -0x10000L ? -0x10000 : v; + + new_normalized[i] = v; + } + + for ( i = 0; i < mmvar->num_axis; i++ ) + { + normalized[i] = new_normalized[i]; + } + + face->blend->normalizedcoords = old_normalized; + + FT_FREE( new_normalized ); + } + } + } + + + /* convert from normalized coordinates to design coordinates */ + + static void + ft_var_to_design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Fixed* design ) + { + GX_Blend blend; + FT_MM_Var* mmvar; + FT_Var_Axis* a; + + FT_UInt i, j, nc; + + + blend = face->blend; + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "ft_var_to_design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + for ( i = 0; i < nc; i++ ) + design[i] = coords[i]; + + for ( ; i < num_coords; i++ ) + design[i] = 0; + + if ( blend->avar_table && blend->avar_table->avar_segment ) + { + GX_AVarSegment av = blend->avar_table->avar_segment; + + + FT_TRACE5(( "design coordinates" + " after removing `avar' distortion:\n" )); + + for ( i = 0; i < nc; i++, av++ ) + { + for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) + { + if ( design[i] < av->correspondence[j].toCoord ) + { + design[i] = + FT_MulDiv( design[i] - av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord ) + + av->correspondence[j - 1].fromCoord; + + FT_TRACE5(( " %.5f\n", (double)design[i] / 65536 )); + break; + } + } + } + } + + mmvar = blend->mmvar; + a = mmvar->axis; + + for ( i = 0; i < nc; i++, a++ ) + { + if ( design[i] < 0 ) + design[i] = a->def + FT_MulFix( design[i], + a->def - a->minimum ); + else if ( design[i] > 0 ) + design[i] = a->def + FT_MulFix( design[i], + a->maximum - a->def ); + else + design[i] = a->def; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct GX_FVar_Head_ + { + FT_Long version; + FT_UShort offsetToData; + FT_UShort axisCount; + FT_UShort axisSize; + FT_UShort instanceCount; + FT_UShort instanceSize; + + } GX_FVar_Head; + + + typedef struct fvar_axis_ + { + FT_ULong axisTag; + FT_Fixed minValue; + FT_Fixed defaultValue; + FT_Fixed maxValue; + FT_UShort flags; + FT_UShort nameID; + + } GX_FVar_Axis; + + + /************************************************************************** + * + * @Function: + * TT_Get_MM_Var + * + * @Description: + * Check that the font's `fvar' table is valid, parse it, and return + * those data. It also loads (and parses) the `MVAR' table, if + * possible. + * + * @InOut: + * face :: + * The font face. + * TT_Get_MM_Var initializes the blend structure. + * + * @Output: + * master :: + * The `fvar' data (must be freed by caller). Can be NULL, + * which makes this function simply load MM support. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_MM_Var( FT_Face face, /* TT_Face */ + FT_MM_Var* *master ) + { + TT_Face ttface = (TT_Face)face; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_ULong table_len; + FT_Error error = FT_Err_Ok; + FT_ULong fvar_start = 0; + FT_UInt i, j; + FT_MM_Var* mmvar = NULL; + FT_Fixed* next_coords; + FT_Fixed* nsc; + FT_String* next_name; + FT_Var_Axis* a; + FT_Fixed* c; + FT_Var_Named_Style* ns; + GX_FVar_Head fvar_head = { 0, 0, 0, 0, 0, 0 }; + FT_Bool usePsName = 0; + FT_UInt num_instances; + FT_UInt num_axes; + FT_UShort* axis_flags; + + FT_Offset mmvar_size; + FT_Offset axis_flags_size; + FT_Offset axis_size; + FT_Offset namedstyle_size; + FT_Offset next_coords_size; + FT_Offset next_name_size; + + FT_Bool need_init; + + static const FT_Frame_Field fvar_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Head + + FT_FRAME_START( 16 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT ( offsetToData ), + FT_FRAME_SKIP_SHORT, + FT_FRAME_USHORT ( axisCount ), + FT_FRAME_USHORT ( axisSize ), + FT_FRAME_USHORT ( instanceCount ), + FT_FRAME_USHORT ( instanceSize ), + FT_FRAME_END + }; + + static const FT_Frame_Field fvaraxis_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Axis + + FT_FRAME_START( 20 ), + FT_FRAME_ULONG ( axisTag ), + FT_FRAME_LONG ( minValue ), + FT_FRAME_LONG ( defaultValue ), + FT_FRAME_LONG ( maxValue ), + FT_FRAME_USHORT( flags ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_END + }; + + /* `num_instances` holds the number of all named instances including */ + /* the default instance, which might be missing in the table of named */ + /* instances (in 'fvar'). This value is validated in `sfobjs.c` and */ + /* may be reset to 0 if consistency checks fail. */ + num_instances = (FT_UInt)face->style_flags >> 16; + + /* read the font data and set up the internal representation */ + /* if not already done */ + + need_init = !ttface->blend; + + if ( need_init ) + { + FT_TRACE2(( "FVAR " )); + + if ( FT_SET_ERROR( ttface->goto_table( ttface, TTAG_fvar, + stream, &table_len ) ) ) + { + FT_TRACE1(( "is missing\n" )); + goto Exit; + } + + fvar_start = FT_STREAM_POS( ); + + /* the validity of the `fvar' header data was already checked */ + /* in function `sfnt_init_face' */ + if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) + goto Exit; + + /* If `num_instances` is larger, synthetization of the default */ + /* instance is required. If `num_instances` is smaller, */ + /* however, the value has been reset to 0 in `sfnt_init_face` */ + /* (in `sfobjs.c`); in this case we have underallocated `mmvar` */ + /* structs. */ + if ( num_instances < fvar_head.instanceCount ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + usePsName = FT_BOOL( fvar_head.instanceSize == + 6 + 4 * fvar_head.axisCount ); + + FT_TRACE2(( "loaded\n" )); + + FT_TRACE5(( "%d variation ax%s\n", + fvar_head.axisCount, + fvar_head.axisCount == 1 ? "is" : "es" )); + + if ( FT_NEW( ttface->blend ) ) + goto Exit; + + num_axes = fvar_head.axisCount; + ttface->blend->num_axis = num_axes; + } + else + num_axes = ttface->blend->num_axis; + + /* prepare storage area for MM data; this cannot overflow */ + /* 32-bit arithmetic because of the size limits used in the */ + /* `fvar' table validity check in `sfnt_init_face' */ + + /* the various `*_size' variables, which we also use as */ + /* offsets into the `mmvar' array, must be multiples of the */ + /* pointer size (except the last one); without such an */ + /* alignment there might be runtime errors due to */ + /* misaligned addresses */ +#undef ALIGN_SIZE +#define ALIGN_SIZE( n ) \ + ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) + + mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); + axis_flags_size = ALIGN_SIZE( num_axes * + sizeof ( FT_UShort ) ); + axis_size = ALIGN_SIZE( num_axes * + sizeof ( FT_Var_Axis ) ); + namedstyle_size = ALIGN_SIZE( num_instances * + sizeof ( FT_Var_Named_Style ) ); + next_coords_size = ALIGN_SIZE( num_instances * + num_axes * + sizeof ( FT_Fixed ) ); + next_name_size = num_axes * 5; + + if ( need_init ) + { + ttface->blend->mmvar_len = mmvar_size + + axis_flags_size + + axis_size + + namedstyle_size + + next_coords_size + + next_name_size; + + if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) ) + goto Exit; + ttface->blend->mmvar = mmvar; + + /* set up pointers and offsets into the `mmvar' array; */ + /* the data gets filled in later on */ + + mmvar->num_axis = + num_axes; + mmvar->num_designs = + ~0U; /* meaningless in this context; each glyph */ + /* may have a different number of designs */ + /* (or tuples, as called by Apple) */ + mmvar->num_namedstyles = + num_instances; + + /* alas, no public field in `FT_Var_Axis' for axis flags */ + axis_flags = + (FT_UShort*)( (char*)mmvar + mmvar_size ); + mmvar->axis = + (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); + mmvar->namedstyle = + (FT_Var_Named_Style*)( (char*)mmvar->axis + axis_size ); + + next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + + namedstyle_size ); + for ( i = 0; i < num_instances; i++ ) + { + mmvar->namedstyle[i].coords = next_coords; + next_coords += num_axes; + } + + next_name = (FT_String*)( (char*)mmvar->namedstyle + + namedstyle_size + next_coords_size ); + for ( i = 0; i < num_axes; i++ ) + { + mmvar->axis[i].name = next_name; + next_name += 5; + } + + /* now fill in the data */ + + if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) + goto Exit; + + a = mmvar->axis; + for ( i = 0; i < num_axes; i++ ) + { + GX_FVar_Axis axis_rec; + +#ifdef FT_DEBUG_LEVEL_TRACE + int invalid = 0; +#endif + + + if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) + goto Exit; + a->tag = axis_rec.axisTag; + a->minimum = axis_rec.minValue; + a->def = axis_rec.defaultValue; + a->maximum = axis_rec.maxValue; + a->strid = axis_rec.nameID; + + a->name[0] = (FT_String)( a->tag >> 24 ); + a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); + a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); + a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); + a->name[4] = '\0'; + + *axis_flags = axis_rec.flags; + + if ( a->minimum > a->def || + a->def > a->maximum ) + { + a->minimum = a->def; + a->maximum = a->def; + +#ifdef FT_DEBUG_LEVEL_TRACE + invalid = 1; +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( i == 0 ) + FT_TRACE5(( " idx tag " + /* " XXX `XXXX'" */ + " minimum default maximum flags\n" )); + /* " XXXX.XXXXX XXXX.XXXXX XXXX.XXXXX 0xXXXX" */ + + FT_TRACE5(( " %3d `%s'" + " %10.5f %10.5f %10.5f 0x%04X%s\n", + i, + a->name, + (double)a->minimum / 65536, + (double)a->def / 65536, + (double)a->maximum / 65536, + *axis_flags, + invalid ? " (invalid, disabled)" : "" )); +#endif + + a++; + axis_flags++; + } + + FT_TRACE5(( "\n" )); + + /* named instance coordinates are stored as design coordinates; */ + /* we have to convert them to normalized coordinates also */ + if ( FT_NEW_ARRAY( ttface->blend->normalized_stylecoords, + num_axes * num_instances ) ) + goto Exit; + + if ( fvar_head.instanceCount && !ttface->blend->avar_loaded ) + { + FT_ULong offset = FT_STREAM_POS(); + + + ft_var_load_avar( ttface ); + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + } + + FT_TRACE5(( "%d named instance%s\n", + fvar_head.instanceCount, + fvar_head.instanceCount == 1 ? "" : "s" )); + + ns = mmvar->namedstyle; + nsc = ttface->blend->normalized_stylecoords; + for ( i = 0; i < fvar_head.instanceCount; i++, ns++ ) + { + /* PostScript names add 2 bytes to the instance record size */ + if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) + + 4L * num_axes ) ) + goto Exit; + + ns->strid = FT_GET_USHORT(); + (void) /* flags = */ FT_GET_USHORT(); + + c = ns->coords; + for ( j = 0; j < num_axes; j++, c++ ) + *c = FT_GET_LONG(); + + /* valid psid values are 6, [256;32767], and 0xFFFF */ + if ( usePsName ) + ns->psid = FT_GET_USHORT(); + else + ns->psid = 0xFFFF; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + FT_String* strname = NULL; + FT_String* psname = NULL; + + FT_ULong pos; + + + pos = FT_STREAM_POS(); + + if ( ns->strid != 0xFFFF ) + { + (void)sfnt->get_name( ttface, + (FT_UShort)ns->strid, + &strname ); + if ( strname && !ft_strcmp( strname, ".notdef" ) ) + strname = NULL; + } + + if ( ns->psid != 0xFFFF ) + { + (void)sfnt->get_name( ttface, + (FT_UShort)ns->psid, + &psname ); + if ( psname && !ft_strcmp( psname, ".notdef" ) ) + psname = NULL; + } + + (void)FT_STREAM_SEEK( pos ); + + FT_TRACE5(( " named instance %d (%s%s%s, %s%s%s)\n", + i, + strname ? "name: `" : "", + strname ? strname : "unnamed", + strname ? "'" : "", + psname ? "PS name: `" : "", + psname ? psname : "no PS name", + psname ? "'" : "" )); + + FT_FREE( strname ); + FT_FREE( psname ); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + ft_var_to_normalized( ttface, num_axes, ns->coords, nsc ); + nsc += num_axes; + + FT_FRAME_EXIT(); + } + + if ( num_instances != fvar_head.instanceCount ) + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + FT_Int found, dummy1, dummy2; + FT_UInt strid = ~0U; + + + /* The default instance is missing in array the */ + /* of named instances; try to synthesize an entry. */ + /* If this fails, `default_named_instance` remains */ + /* at value zero, which doesn't do any harm. */ + found = sfnt->get_name_id( ttface, + TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, + &dummy1, + &dummy2 ); + if ( found ) + strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY; + else + { + found = sfnt->get_name_id( ttface, + TT_NAME_ID_FONT_SUBFAMILY, + &dummy1, + &dummy2 ); + if ( found ) + strid = TT_NAME_ID_FONT_SUBFAMILY; + } + + if ( found ) + { + found = sfnt->get_name_id( ttface, + TT_NAME_ID_PS_NAME, + &dummy1, + &dummy2 ); + if ( found ) + { + FT_TRACE5(( "TT_Get_MM_Var:" + " Adding default instance to named instances\n" )); + + /* named instance indices start with value 1 */ + ttface->var_default_named_instance = num_instances; + + ns = &mmvar->namedstyle[fvar_head.instanceCount]; + + ns->strid = strid; + ns->psid = TT_NAME_ID_PS_NAME; + + a = mmvar->axis; + c = ns->coords; + for ( j = 0; j < num_axes; j++, a++, c++ ) + *c = a->def; + } + } + } + + ft_var_load_mvar( ttface ); + } + + /* fill the output array if requested */ + + if ( master ) + { + FT_UInt n; + + + if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) ) + goto Exit; + FT_MEM_COPY( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len ); + + axis_flags = + (FT_UShort*)( (char*)mmvar + mmvar_size ); + mmvar->axis = + (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); + mmvar->namedstyle = + (FT_Var_Named_Style*)( (char*)mmvar->axis+ axis_size ); + + next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + + namedstyle_size ); + for ( n = 0; n < mmvar->num_namedstyles; n++ ) + { + mmvar->namedstyle[n].coords = next_coords; + next_coords += num_axes; + } + + a = mmvar->axis; + next_name = (FT_String*)( (char*)mmvar->namedstyle + + namedstyle_size + next_coords_size ); + for ( n = 0; n < num_axes; n++ ) + { + a->name = next_name; + + /* standard PostScript names for some standard apple tags */ + if ( a->tag == TTAG_wght ) + a->name = (char*)"Weight"; + else if ( a->tag == TTAG_wdth ) + a->name = (char*)"Width"; + else if ( a->tag == TTAG_opsz ) + a->name = (char*)"OpticalSize"; + else if ( a->tag == TTAG_slnt ) + a->name = (char*)"Slant"; + else if ( a->tag == TTAG_ital ) + a->name = (char*)"Italic"; + + next_name += 5; + a++; + } + + *master = mmvar; + } + + Exit: + return error; + } + + + static FT_Error + tt_set_mm_blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Bool set_design_coords ) + { + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i; + + FT_Bool all_design_coords = FALSE; + + FT_Memory memory = face->root.memory; + + enum + { + mcvt_retain, + mcvt_modify, + mcvt_load + + } manageCvt; + + + face->doblend = FALSE; + + if ( !face->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) ) + goto Exit; + } + + blend = face->blend; + mmvar = blend->mmvar; + + if ( num_coords > mmvar->num_axis ) + { + FT_TRACE2(( "TT_Set_MM_Blend:" + " only using first %d of %d coordinates\n", + mmvar->num_axis, num_coords )); + num_coords = mmvar->num_axis; + } + + FT_TRACE5(( "TT_Set_MM_Blend:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); + + for ( i = 0; i < num_coords; i++ ) + { + FT_TRACE5(( " %.5f\n", (double)coords[i] / 65536 )); + if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) + { + FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n", + (double)coords[i] / 65536 )); + FT_TRACE1(( " is out of range [-1;1]\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + FT_TRACE5(( "\n" )); + + if ( !face->is_cff2 && !blend->glyphoffsets ) + { + /* While a missing 'gvar' table is acceptable, for example for */ + /* fonts that only vary metrics information or 'COLR' v1 */ + /* `PaintVar*` tables, an incorrect SFNT table offset or size */ + /* for 'gvar', or an inconsistent 'gvar' table is not. */ + error = ft_var_load_gvar( face ); + if ( error != FT_Err_Table_Missing && error != FT_Err_Ok ) + goto Exit; + error = FT_Err_Ok; + } + + if ( !blend->coords ) + { + if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) + goto Exit; + + /* the first time we have to compute all design coordinates */ + all_design_coords = TRUE; + } + + if ( !blend->normalizedcoords ) + { + if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) ) + goto Exit; + + manageCvt = mcvt_modify; + + /* If we have not set the blend coordinates before this, then the */ + /* cvt table will still be what we read from the `cvt ' table and */ + /* we don't need to reload it. We may need to change it though... */ + } + else + { + FT_Bool have_diff = 0; + FT_UInt j; + FT_Fixed* c; + FT_Fixed* n; + + + manageCvt = mcvt_retain; + + for ( i = 0; i < num_coords; i++ ) + { + if ( blend->normalizedcoords[i] != coords[i] ) + { + manageCvt = mcvt_load; + have_diff = 1; + break; + } + } + + if ( !have_diff ) + { + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) + { + FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16; + + + c = blend->normalizedcoords + i; + n = blend->normalized_stylecoords + + ( instance_index - 1 ) * mmvar->num_axis + + i; + + for ( j = i; j < mmvar->num_axis; j++, n++, c++ ) + if ( *c != *n ) + have_diff = 1; + } + else + { + c = blend->normalizedcoords + i; + for ( j = i; j < mmvar->num_axis; j++, c++ ) + if ( *c != 0 ) + have_diff = 1; + } + } + + /* return value -1 indicates `no change' */ + if ( !have_diff ) + { + face->doblend = TRUE; + + return -1; + } + + for ( ; i < mmvar->num_axis; i++ ) + { + if ( blend->normalizedcoords[i] != 0 ) + { + manageCvt = mcvt_load; + break; + } + } + + /* If we don't change the blend coords then we don't need to do */ + /* anything to the cvt table. It will be correct. Otherwise we */ + /* no longer have the original cvt (it was modified when we set */ + /* the blend last time), so we must reload and then modify it. */ + } + + blend->num_axis = mmvar->num_axis; + if ( coords ) + FT_MEM_COPY( blend->normalizedcoords, + coords, + num_coords * sizeof ( FT_Fixed ) ); + + if ( set_design_coords ) + ft_var_to_design( face, + all_design_coords ? blend->num_axis : num_coords, + blend->normalizedcoords, + blend->coords ); + + face->doblend = TRUE; + + if ( face->cvt ) + { + switch ( manageCvt ) + { + case mcvt_load: + /* The cvt table has been loaded already; every time we change the */ + /* blend we may need to reload and remodify the cvt table. */ + FT_FREE( face->cvt ); + + error = tt_face_load_cvt( face, face->root.stream ); + break; + + case mcvt_modify: + /* The original cvt table is in memory. All we need to do is */ + /* apply the `cvar' table (if any). */ + error = tt_face_vary_cvt( face, face->root.stream ); + break; + + case mcvt_retain: + /* The cvt table is correct for this set of coordinates. */ + break; + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_MM_Blend + * + * @Description: + * Set the blend (normalized) coordinates for this instance of the + * font. Check that the `gvar' table is reasonable and does some + * initial preparation. + * + * @InOut: + * face :: + * The font. + * Initialize the blend structure with `gvar' data. + * + * @Input: + * num_coords :: + * The number of available coordinates. If it is + * larger than the number of axes, ignore the excess + * values. If it is smaller than the number of axes, + * use the default value (0) for the remaining axes. + * + * coords :: + * An array of `num_coords', each between [-1,1]. + * + * @Return: + * FreeType error code. 0 means success, -1 means success and unchanged + * axis values. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_MM_Blend( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + return tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 ); + } + + + /************************************************************************** + * + * @Function: + * TT_Get_MM_Blend + * + * @Description: + * Get the blend (normalized) coordinates for this instance of the + * font. + * + * @InOut: + * face :: + * The font. + * Initialize the blend structure with `gvar' data. + * + * @Input: + * num_coords :: + * The number of available coordinates. If it is + * larger than the number of axes, set the excess + * values to 0. + * + * coords :: + * An array of `num_coords', each between [-1,1]. + * + * @Return: + * FreeType error code. 0 means success, -1 means success and unchanged + * axis values. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_MM_Blend( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + TT_Face ttface = (TT_Face)face; + + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_UInt i, nc; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + return error; + } + + blend = ttface->blend; + + if ( !blend->coords ) + { + /* select default instance coordinates */ + /* if no instance is selected yet */ + if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) ) + return error; + } + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "TT_Get_MM_Blend:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + if ( ttface->doblend ) + { + for ( i = 0; i < nc; i++ ) + coords[i] = blend->normalizedcoords[i]; + } + else + { + for ( i = 0; i < nc; i++ ) + coords[i] = 0; + } + + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_Var_Design + * + * @Description: + * Set the coordinates for the instance, measured in the user + * coordinate system. Parse the `avar' table (if present) to convert + * from user to normalized coordinates. + * + * @InOut: + * face :: + * The font face. + * Initialize the blend struct with `gvar' data. + * + * @Input: + * num_coords :: + * The number of available coordinates. If it is + * larger than the number of axes, ignore the excess + * values. If it is smaller than the number of axes, + * use the default values for the remaining axes. + * + * coords :: + * A coordinate array with `num_coords' elements. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_Var_Design( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i; + FT_Memory memory = FT_FACE_MEMORY( face ); + + FT_Fixed* c; + FT_Fixed* n; + FT_Fixed* normalized = NULL; + + FT_Bool have_diff = 0; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + blend = ttface->blend; + mmvar = blend->mmvar; + + if ( num_coords > mmvar->num_axis ) + { + FT_TRACE2(( "TT_Set_Var_Design:" + " only using first %d of %d coordinates\n", + mmvar->num_axis, num_coords )); + num_coords = mmvar->num_axis; + } + + if ( !blend->coords ) + { + if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) + goto Exit; + } + + c = blend->coords; + n = coords; + for ( i = 0; i < num_coords; i++, n++, c++ ) + { + if ( *c != *n ) + { + *c = *n; + have_diff = 1; + } + } + + if ( FT_IS_NAMED_INSTANCE( face ) ) + { + FT_UInt instance_index; + FT_Var_Named_Style* named_style; + + + instance_index = (FT_UInt)face->face_index >> 16; + named_style = mmvar->namedstyle + instance_index - 1; + + n = named_style->coords + num_coords; + for ( ; i < mmvar->num_axis; i++, n++, c++ ) + { + if ( *c != *n ) + { + *c = *n; + have_diff = 1; + } + } + } + else + { + FT_Var_Axis* a; + + + a = mmvar->axis + num_coords; + for ( ; i < mmvar->num_axis; i++, a++, c++ ) + { + if ( *c != a->def ) + { + *c = a->def; + have_diff = 1; + } + } + } + + /* return value -1 indicates `no change'; */ + /* we can exit early if `normalizedcoords' is already computed */ + if ( blend->normalizedcoords && !have_diff ) + return -1; + + if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) + goto Exit; + + if ( !ttface->blend->avar_loaded ) + ft_var_load_avar( ttface ); + + FT_TRACE5(( "TT_Set_Var_Design:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); + ft_var_to_normalized( ttface, num_coords, blend->coords, normalized ); + + error = tt_set_mm_blend( ttface, mmvar->num_axis, normalized, 0 ); + if ( error ) + goto Exit; + + Exit: + FT_FREE( normalized ); + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Get_Var_Design + * + * @Description: + * Get the design coordinates of the currently selected interpolated + * font. + * + * @Input: + * face :: + * A handle to the source face. + * + * num_coords :: + * The number of design coordinates to retrieve. If it + * is larger than the number of axes, set the excess + * values to~0. + * + * @Output: + * coords :: + * The design coordinates array. + * + * @Return: + * FreeType error code. 0~means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_Var_Design( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_UInt i, nc; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + return error; + } + + blend = ttface->blend; + + if ( !blend->coords ) + { + /* select default instance coordinates */ + /* if no instance is selected yet */ + if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) ) + return error; + } + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "TT_Get_Var_Design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + if ( ttface->doblend ) + { + for ( i = 0; i < nc; i++ ) + coords[i] = blend->coords[i]; + } + else + { + for ( i = 0; i < nc; i++ ) + coords[i] = 0; + } + + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_Named_Instance + * + * @Description: + * Set the given named instance, also resetting any further + * variation. + * + * @Input: + * face :: + * A handle to the source face. + * + * instance_index :: + * The instance index, starting with value 1. + * Value 0 indicates to not use an instance. + * + * @Return: + * FreeType error code. 0~means success, -1 means success and unchanged + * axis values. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_Named_Instance( FT_Face face, /* TT_Face */ + FT_UInt instance_index ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error; + GX_Blend blend; + FT_MM_Var* mmvar; + + FT_Memory memory = FT_FACE_MEMORY( face ); + + FT_UInt num_instances; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + blend = ttface->blend; + mmvar = blend->mmvar; + + num_instances = (FT_UInt)face->style_flags >> 16; + + /* `instance_index' starts with value 1, thus `>' */ + if ( instance_index > num_instances ) + { + error = FT_ERR( Invalid_Argument ); + goto Exit; + } + + if ( instance_index > 0 ) + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + FT_Var_Named_Style* named_style; + FT_String* style_name; + + + named_style = mmvar->namedstyle + instance_index - 1; + + error = sfnt->get_name( ttface, + (FT_UShort)named_style->strid, + &style_name ); + if ( error ) + goto Exit; + + /* set (or replace) style name */ + FT_FREE( face->style_name ); + face->style_name = style_name; + + /* finally, select the named instance */ + error = TT_Set_Var_Design( face, + mmvar->num_axis, + named_style->coords ); + } + else + { + /* restore non-VF style name */ + FT_FREE( face->style_name ); + if ( FT_STRDUP( face->style_name, ttface->non_var_style_name ) ) + goto Exit; + error = TT_Set_Var_Design( face, 0, NULL ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Get_Default_Named_Instance + * + * @Description: + * Get the default named instance. + * + * @Input: + * face :: + * A handle to the source face. + * + * @Output: + * instance_index :: + * The default named instance index. + * + * @Return: + * FreeType error code. 0~means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + *instance_index = ttface->var_default_named_instance; + + Exit: + return error; + } + + + /* This function triggers (lazy) recomputation of the `postscript_name` */ + /* field in `TT_Face`. */ + + FT_LOCAL_DEF( void ) + tt_construct_ps_name( FT_Face face ) + { + TT_Face ttface = (TT_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( ttface->postscript_name ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GX VAR PARSING ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + static FT_Error + tt_cvt_ready_iterator( FT_ListNode node, + void* user ) + { + TT_Size size = (TT_Size)node->data; + + FT_UNUSED( user ); + + + size->cvt_ready = -1; + + return FT_Err_Ok; + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + + + /************************************************************************** + * + * @Function: + * tt_face_vary_cvt + * + * @Description: + * Modify the loaded cvt table according to the `cvar' table and the + * font's blend. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + * + * Most errors are ignored. It is perfectly valid not to have a + * `cvar' table even if there is a `gvar' and `fvar' table. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + FT_Error error; + FT_Memory memory = stream->memory; + + FT_Face root = &face->root; + + FT_ULong table_start; + FT_ULong table_len; + + FT_UInt tupleCount; + FT_ULong offsetToData; + + FT_ULong here; + FT_UInt i, j; + + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + + GX_Blend blend = face->blend; + + FT_UInt point_count; + FT_UInt spoint_count = 0; + + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; + FT_UShort* points; + + FT_Fixed* deltas = NULL; + FT_Fixed* cvt_deltas = NULL; + + + FT_TRACE2(( "CVAR " )); + + if ( !blend ) + { + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); + error = FT_Err_Ok; + goto Exit; + } + + if ( !face->cvt ) + { + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); + error = FT_Err_Ok; + goto Exit; + } + + error = face->goto_table( face, TTAG_cvar, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + + error = FT_Err_Ok; + goto Exit; + } + + if ( FT_FRAME_ENTER( table_len ) ) + { + error = FT_Err_Ok; + goto Exit; + } + + table_start = FT_Stream_FTell( stream ); + if ( FT_GET_LONG() != 0x00010000L ) + { + FT_TRACE2(( "bad table version\n" )); + + error = FT_Err_Ok; + goto FExit; + } + + FT_TRACE2(( "loaded\n" )); + + if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) + goto FExit; + + tupleCount = FT_GET_USHORT(); + offsetToData = FT_GET_USHORT(); + + /* rough sanity test */ + if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > + table_len ) + { + FT_TRACE2(( "tt_face_vary_cvt:" + " invalid CVT variation array header\n" )); + + error = FT_THROW( Invalid_Table ); + goto FExit; + } + + offsetToData += table_start; + + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + sharedpoints = ft_var_readpackedpoints( stream, + table_len, + &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "cvar: there %s %d tuple%s:\n", + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", + tupleCount & GX_TC_TUPLE_COUNT_MASK, + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); + + if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) ) + goto FExit; + + for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + + + FT_TRACE6(( " tuple %d:\n", i )); + + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); + + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; j++ ) + tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + } + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + { + FT_TRACE2(( "tt_face_vary_cvt:" + " invalid tuple index\n" )); + + error = FT_THROW( Invalid_Table ); + goto FExit; + } + else + { + if ( !blend->tuplecoords ) + { + FT_TRACE2(( "tt_face_vary_cvt:" + " no valid tuple coordinates available\n" )); + + error = FT_THROW( Invalid_Table ); + goto FExit; + } + + FT_MEM_COPY( + tuple_coords, + blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, + blend->num_axis * sizeof ( FT_Fixed ) ); + } + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; j++ ) + im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + for ( j = 0; j < blend->num_axis; j++ ) + im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + } + + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); + + if ( apply == 0 ) /* tuple isn't active for our blend */ + { + offsetToData += tupleDataSize; + continue; + } + + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) + { + localpoints = ft_var_readpackedpoints( stream, + table_len, + &point_count ); + points = localpoints; + } + else + { + localpoints = NULL; + points = sharedpoints; + point_count = spoint_count; + } + + deltas = ft_var_readpackeddeltas( stream, + table_len, + point_count == 0 ? face->cvt_size + : point_count ); + + if ( !points || !deltas ) + ; /* failure, ignore it */ + + else if ( localpoints == ALL_POINTS ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + FT_TRACE7(( " CVT deltas:\n" )); + + /* this means that there are deltas for every entry in cvt */ + for ( j = 0; j < face->cvt_size; j++ ) + { + FT_Fixed old_cvt_delta; + + + old_cvt_delta = cvt_deltas[j]; + cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( old_cvt_delta != cvt_deltas[j] ) + { + FT_TRACE7(( " %d: %f -> %f\n", + j, + (double)( FT_fdot6ToFixed( face->cvt[j] ) + + old_cvt_delta ) / 65536, + (double)( FT_fdot6ToFixed( face->cvt[j] ) + + cvt_deltas[j] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + else + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + FT_TRACE7(( " CVT deltas:\n" )); + + for ( j = 0; j < point_count; j++ ) + { + int pindex; + FT_Fixed old_cvt_delta; + + + pindex = points[j]; + if ( (FT_ULong)pindex >= face->cvt_size ) + continue; + + old_cvt_delta = cvt_deltas[pindex]; + cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( old_cvt_delta != cvt_deltas[pindex] ) + { + FT_TRACE7(( " %d: %f -> %f\n", + pindex, + (double)( FT_fdot6ToFixed( face->cvt[pindex] ) + + old_cvt_delta ) / 65536, + (double)( FT_fdot6ToFixed( face->cvt[pindex] ) + + cvt_deltas[pindex] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas ); + + offsetToData += tupleDataSize; + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "\n" )); + + for ( i = 0; i < face->cvt_size; i++ ) + face->cvt[i] += FT_fixedToFdot6( cvt_deltas[i] ); + + FExit: + FT_FRAME_EXIT(); + + Exit: + if ( sharedpoints != ALL_POINTS ) + FT_FREE( sharedpoints ); + FT_FREE( tuple_coords ); + FT_FREE( im_start_coords ); + FT_FREE( im_end_coords ); + FT_FREE( cvt_deltas ); + + /* iterate over all FT_Size objects and set `cvt_ready' to -1 */ + /* to trigger rescaling of all CVT values */ + FT_List_Iterate( &root->sizes_list, + tt_cvt_ready_iterator, + NULL ); + + return error; + +#else /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + } + + + /* Shift the original coordinates of all points between indices `p1' */ + /* and `p2', using the same difference as given by index `ref'. */ + + /* modeled after `af_iup_shift' */ + + static void + tt_delta_shift( int p1, + int p2, + int ref, + FT_Vector* in_points, + FT_Vector* out_points ) + { + int p; + FT_Vector delta; + + + delta.x = out_points[ref].x - in_points[ref].x; + delta.y = out_points[ref].y - in_points[ref].y; + + if ( delta.x == 0 && delta.y == 0 ) + return; + + for ( p = p1; p < ref; p++ ) + { + out_points[p].x += delta.x; + out_points[p].y += delta.y; + } + + for ( p = ref + 1; p <= p2; p++ ) + { + out_points[p].x += delta.x; + out_points[p].y += delta.y; + } + } + + + /* Interpolate the original coordinates of all points with indices */ + /* between `p1' and `p2', using `ref1' and `ref2' as the reference */ + /* point indices. */ + + /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ + /* `Ins_IUP' with spec differences in handling ill-defined cases. */ + static void + tt_delta_interpolate( int p1, + int p2, + int ref1, + int ref2, + FT_Vector* in_points, + FT_Vector* out_points ) + { + int p, i; + + FT_Pos out, in1, in2, out1, out2, d1, d2; + + + if ( p1 > p2 ) + return; + + /* handle both horizontal and vertical coordinates */ + for ( i = 0; i <= 1; i++ ) + { + /* shift array pointers so that we can access `foo.y' as `foo.x' */ + in_points = (FT_Vector*)( (FT_Pos*)in_points + i ); + out_points = (FT_Vector*)( (FT_Pos*)out_points + i ); + + if ( in_points[ref1].x > in_points[ref2].x ) + { + p = ref1; + ref1 = ref2; + ref2 = p; + } + + in1 = in_points[ref1].x; + in2 = in_points[ref2].x; + out1 = out_points[ref1].x; + out2 = out_points[ref2].x; + d1 = out1 - in1; + d2 = out2 - in2; + + /* If the reference points have the same coordinate but different */ + /* delta, inferred delta is zero. Otherwise interpolate. */ + if ( in1 != in2 || out1 == out2 ) + { + FT_Fixed scale = in1 != in2 ? FT_DivFix( out2 - out1, in2 - in1 ) + : 0; + + + for ( p = p1; p <= p2; p++ ) + { + out = in_points[p].x; + + if ( out <= in1 ) + out += d1; + else if ( out >= in2 ) + out += d2; + else + out = out1 + FT_MulFix( out - in1, scale ); + + out_points[p].x = out; + } + } + } + } + + + /* Interpolate points without delta values, similar to */ + /* the `IUP' hinting instruction. */ + + /* modeled after `Ins_IUP */ + + static void + tt_interpolate_deltas( FT_Outline* outline, + FT_Vector* out_points, + FT_Vector* in_points, + FT_Bool* has_delta ) + { + FT_Int first_point; + FT_Int end_point; + + FT_Int first_delta; + FT_Int cur_delta; + + FT_Int point; + FT_Short contour; + + + /* ignore empty outlines */ + if ( !outline->n_contours ) + return; + + contour = 0; + point = 0; + + do + { + end_point = outline->contours[contour]; + first_point = point; + + /* search first point that has a delta */ + while ( point <= end_point && !has_delta[point] ) + point++; + + if ( point <= end_point ) + { + first_delta = point; + cur_delta = point; + + point++; + + while ( point <= end_point ) + { + /* search next point that has a delta */ + /* and interpolate intermediate points */ + if ( has_delta[point] ) + { + tt_delta_interpolate( cur_delta + 1, + point - 1, + cur_delta, + point, + in_points, + out_points ); + cur_delta = point; + } + + point++; + } + + /* shift contour if we only have a single delta */ + if ( cur_delta == first_delta ) + tt_delta_shift( first_point, + end_point, + cur_delta, + in_points, + out_points ); + else + { + /* otherwise handle remaining points */ + /* at the end and beginning of the contour */ + tt_delta_interpolate( cur_delta + 1, + end_point, + cur_delta, + first_delta, + in_points, + out_points ); + + if ( first_delta > 0 ) + tt_delta_interpolate( first_point, + first_delta - 1, + cur_delta, + first_delta, + in_points, + out_points ); + } + } + contour++; + + } while ( contour < outline->n_contours ); + } + + + /************************************************************************** + * + * @Function: + * TT_Vary_Apply_Glyph_Deltas + * + * @Description: + * Apply the appropriate deltas to the current glyph. + * + * @InOut: + * loader :: + * A handle to the loader object. + * + * outline :: + * The outline to change, with appended phantom points. + * + * @Output: + * unrounded :: + * An array with `n_points' elements that is filled with unrounded + * point coordinates (in 26.6 format). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Vary_Apply_Glyph_Deltas( TT_Loader loader, + FT_Outline* outline, + FT_Vector* unrounded ) + { + FT_Error error; + TT_Face face = loader->face; + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + FT_UInt glyph_index = loader->glyph_index; + FT_UInt n_points = (FT_UInt)outline->n_points + 4; + + FT_Vector* points_org = NULL; /* coordinates in 16.16 format */ + FT_Vector* points_out = NULL; /* coordinates in 16.16 format */ + FT_Bool* has_delta = NULL; + + FT_ULong glyph_start; + + FT_UInt tupleCount; + FT_ULong offsetToData; + FT_ULong dataSize; + + FT_ULong here; + FT_UInt i, j; + + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + + GX_Blend blend = face->blend; + + FT_UInt point_count; + FT_UInt spoint_count = 0; + + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; + FT_UShort* points; + + FT_Fixed* deltas_x = NULL; + FT_Fixed* deltas_y = NULL; + FT_Fixed* point_deltas_x = NULL; + FT_Fixed* point_deltas_y = NULL; + + + if ( !face->doblend || !blend ) + return FT_THROW( Invalid_Argument ); + + for ( i = 0; i < n_points; i++ ) + { + unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x ); + unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y ); + } + + if ( glyph_index >= blend->gv_glyphcnt || + blend->glyphoffsets[glyph_index] == + blend->glyphoffsets[glyph_index + 1] ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " no variation data for glyph %d\n", glyph_index )); + return FT_Err_Ok; + } + + if ( FT_NEW_ARRAY( points_org, n_points ) || + FT_NEW_ARRAY( points_out, n_points ) || + FT_NEW_ARRAY( has_delta, n_points ) ) + goto Fail1; + + dataSize = blend->glyphoffsets[glyph_index + 1] - + blend->glyphoffsets[glyph_index]; + + if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || + FT_FRAME_ENTER( dataSize ) ) + goto Fail1; + + glyph_start = FT_Stream_FTell( stream ); + + /* each set of glyph variation data is formatted similarly to `cvar' */ + + if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) + goto Fail2; + + tupleCount = FT_GET_USHORT(); + offsetToData = FT_GET_USHORT(); + + /* rough sanity test */ + if ( offsetToData > dataSize || + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > dataSize ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + + error = FT_THROW( Invalid_Table ); + goto Fail2; + } + + offsetToData += glyph_start; + + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + sharedpoints = ft_var_readpackedpoints( stream, + blend->gvar_size, + &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "gvar: there %s %d tuple%s:\n", + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", + tupleCount & GX_TC_TUPLE_COUNT_MASK, + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); + + if ( FT_NEW_ARRAY( point_deltas_x, n_points ) || + FT_NEW_ARRAY( point_deltas_y, n_points ) ) + goto Fail3; + + for ( j = 0; j < n_points; j++ ) + { + points_org[j].x = FT_intToFixed( outline->points[j].x ); + points_org[j].y = FT_intToFixed( outline->points[j].y ); + } + + for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + + + FT_TRACE6(( " tuple %d:\n", i )); + + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); + + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; j++ ) + tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + } + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid tuple index\n" )); + + error = FT_THROW( Invalid_Table ); + goto Fail3; + } + else + FT_MEM_COPY( + tuple_coords, + blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, + blend->num_axis * sizeof ( FT_Fixed ) ); + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; j++ ) + im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + for ( j = 0; j < blend->num_axis; j++ ) + im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + } + + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); + + if ( apply == 0 ) /* tuple isn't active for our blend */ + { + offsetToData += tupleDataSize; + continue; + } + + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) + { + localpoints = ft_var_readpackedpoints( stream, + blend->gvar_size, + &point_count ); + points = localpoints; + } + else + { + points = sharedpoints; + point_count = spoint_count; + } + + deltas_x = ft_var_readpackeddeltas( stream, + blend->gvar_size, + point_count == 0 ? n_points + : point_count ); + deltas_y = ft_var_readpackeddeltas( stream, + blend->gvar_size, + point_count == 0 ? n_points + : point_count ); + + if ( !points || !deltas_y || !deltas_x ) + ; /* failure, ignore it */ + + else if ( points == ALL_POINTS ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + FT_TRACE7(( " point deltas:\n" )); + + /* this means that there are deltas for every point in the glyph */ + for ( j = 0; j < n_points; j++ ) + { + FT_Fixed old_point_delta_x = point_deltas_x[j]; + FT_Fixed old_point_delta_y = point_deltas_y[j]; + + FT_Fixed point_delta_x = FT_MulFix( deltas_x[j], apply ); + FT_Fixed point_delta_y = FT_MulFix( deltas_y[j], apply ); + + + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( point_delta_x || point_delta_y ) + { + FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + j, + (double)( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536, + (double)( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + else + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + /* we have to interpolate the missing deltas similar to the */ + /* IUP bytecode instruction */ + for ( j = 0; j < n_points; j++ ) + { + has_delta[j] = FALSE; + points_out[j] = points_org[j]; + } + + for ( j = 0; j < point_count; j++ ) + { + FT_UShort idx = points[j]; + + + if ( idx >= n_points ) + continue; + + has_delta[idx] = TRUE; + + points_out[idx].x += FT_MulFix( deltas_x[j], apply ); + points_out[idx].y += FT_MulFix( deltas_y[j], apply ); + } + + /* no need to handle phantom points here, */ + /* since solitary points can't be interpolated */ + tt_interpolate_deltas( outline, + points_out, + points_org, + has_delta ); + + FT_TRACE7(( " point deltas:\n" )); + + for ( j = 0; j < n_points; j++ ) + { + FT_Fixed old_point_delta_x = point_deltas_x[j]; + FT_Fixed old_point_delta_y = point_deltas_y[j]; + + FT_Pos point_delta_x = points_out[j].x - points_org[j].x; + FT_Pos point_delta_y = points_out[j].y - points_org[j].y; + + + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( point_delta_x || point_delta_y ) + { + FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + j, + (double)( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536, + (double)( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas_x ); + FT_FREE( deltas_y ); + + offsetToData += tupleDataSize; + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "\n" )); + + /* To avoid double adjustment of advance width or height, */ + /* do not move phantom points if there is HVAR or VVAR */ + /* support, respectively. */ + if ( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) + { + point_deltas_x[n_points - 4] = 0; + point_deltas_y[n_points - 4] = 0; + point_deltas_x[n_points - 3] = 0; + point_deltas_y[n_points - 3] = 0; + } + if ( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) + { + point_deltas_x[n_points - 2] = 0; + point_deltas_y[n_points - 2] = 0; + point_deltas_x[n_points - 1] = 0; + point_deltas_y[n_points - 1] = 0; + } + + for ( i = 0; i < n_points; i++ ) + { + unrounded[i].x += FT_fixedToFdot6( point_deltas_x[i] ); + unrounded[i].y += FT_fixedToFdot6( point_deltas_y[i] ); + + outline->points[i].x += FT_fixedToInt( point_deltas_x[i] ); + outline->points[i].y += FT_fixedToInt( point_deltas_y[i] ); + } + + /* To avoid double adjustment of advance width or height, */ + /* adjust phantom points only if there is no HVAR or VVAR */ + /* support, respectively. */ + if ( !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + { + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + loader->linear = FT_PIX_ROUND( unrounded[n_points - 3].x - + unrounded[n_points - 4].x ) / 64; + } + if ( !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + { + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + loader->vadvance = FT_PIX_ROUND( unrounded[n_points - 1].y - + unrounded[n_points - 2].y ) / 64; + } + + Fail3: + FT_FREE( point_deltas_x ); + FT_FREE( point_deltas_y ); + + Fail2: + if ( sharedpoints != ALL_POINTS ) + FT_FREE( sharedpoints ); + FT_FREE( tuple_coords ); + FT_FREE( im_start_coords ); + FT_FREE( im_end_coords ); + + FT_FRAME_EXIT(); + + Fail1: + FT_FREE( points_org ); + FT_FREE( points_out ); + FT_FREE( has_delta ); + + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_get_var_blend + * + * @Description: + * An extended internal version of `TT_Get_MM_Blend' that returns + * pointers instead of copying data, without any initialization of + * the MM machinery in case it isn't loaded yet. + */ + FT_LOCAL_DEF( FT_Error ) + tt_get_var_blend( FT_Face face, /* TT_Face */ + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ) + { + TT_Face ttface = (TT_Face)face; + + + if ( ttface->blend ) + { + if ( num_coords ) + *num_coords = ttface->blend->num_axis; + if ( coords ) + *coords = ttface->blend->coords; + if ( normalizedcoords ) + *normalizedcoords = ttface->blend->normalizedcoords; + if ( mm_var ) + *mm_var = ttface->blend->mmvar; + } + else + { + if ( num_coords ) + *num_coords = 0; + if ( coords ) + *coords = NULL; + if ( mm_var ) + *mm_var = NULL; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + tt_var_done_item_variation_store( FT_Face face, + GX_ItemVarStore itemStore ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_UInt i; + + + if ( itemStore->varData ) + { + for ( i = 0; i < itemStore->dataCount; i++ ) + { + FT_FREE( itemStore->varData[i].regionIndices ); + FT_FREE( itemStore->varData[i].deltaSet ); + } + + FT_FREE( itemStore->varData ); + } + + if ( itemStore->varRegionList ) + { + for ( i = 0; i < itemStore->regionCount; i++ ) + FT_FREE( itemStore->varRegionList[i].axisList ); + + FT_FREE( itemStore->varRegionList ); + } + } + + + FT_LOCAL_DEF( void ) + tt_var_done_delta_set_index_map( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( deltaSetIdxMap->innerIndex ); + FT_FREE( deltaSetIdxMap->outerIndex ); + } + + + /************************************************************************** + * + * @Function: + * tt_done_blend + * + * @Description: + * Free the blend internal data structure. + */ + FT_LOCAL_DEF( void ) + tt_done_blend( FT_Face face ) + { + TT_Face ttface = (TT_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + GX_Blend blend = ttface->blend; + + + if ( blend ) + { + FT_UInt i, num_axes; + + + /* blend->num_axis might not be set up yet */ + num_axes = blend->mmvar->num_axis; + + FT_FREE( blend->coords ); + FT_FREE( blend->normalizedcoords ); + FT_FREE( blend->normalized_stylecoords ); + FT_FREE( blend->mmvar ); + + if ( blend->avar_table ) + { + if ( blend->avar_table->avar_segment ) + { + for ( i = 0; i < num_axes; i++ ) + FT_FREE( blend->avar_table->avar_segment[i].correspondence ); + FT_FREE( blend->avar_table->avar_segment ); + } + + tt_var_done_item_variation_store( face, + &blend->avar_table->itemStore ); + + tt_var_done_delta_set_index_map( face, + &blend->avar_table->axisMap ); + + FT_FREE( blend->avar_table ); + } + + if ( blend->hvar_table ) + { + tt_var_done_item_variation_store( face, + &blend->hvar_table->itemStore ); + + tt_var_done_delta_set_index_map( face, + &blend->hvar_table->widthMap ); + FT_FREE( blend->hvar_table ); + } + + if ( blend->vvar_table ) + { + tt_var_done_item_variation_store( face, + &blend->vvar_table->itemStore ); + + tt_var_done_delta_set_index_map( face, + &blend->vvar_table->widthMap ); + FT_FREE( blend->vvar_table ); + } + + if ( blend->mvar_table ) + { + tt_var_done_item_variation_store( face, + &blend->mvar_table->itemStore ); + + FT_FREE( blend->mvar_table->values ); + FT_FREE( blend->mvar_table ); + } + + FT_FREE( blend->tuplecoords ); + FT_FREE( blend->glyphoffsets ); + FT_FREE( blend ); + } + } + +#else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_gxvar_dummy_; + +#endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttgxvar.h b/vendor/freetype/src/truetype/ttgxvar.h new file mode 100644 index 0000000..e3da6d1 --- /dev/null +++ b/vendor/freetype/src/truetype/ttgxvar.h @@ -0,0 +1,453 @@ +/**************************************************************************** + * + * ttgxvar.h + * + * TrueType GX Font Variation loader (specification) + * + * Copyright (C) 2004-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg and George Williams. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTGXVAR_H_ +#define TTGXVAR_H_ + + +#include +#include "ttobjs.h" + + +FT_BEGIN_HEADER + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /************************************************************************** + * + * @Struct: + * GX_AVarCorrespondenceRec + * + * @Description: + * A data structure representing `shortFracCorrespondence' in `avar' + * table according to the specifications from Apple. + */ + typedef struct GX_AVarCorrespondenceRec_ + { + FT_Fixed fromCoord; + FT_Fixed toCoord; + + } GX_AVarCorrespondenceRec_, *GX_AVarCorrespondence; + + + /************************************************************************** + * + * @Struct: + * GX_AVarRec + * + * @Description: + * Data from the segment field of `avar' table. + * There is one of these for each axis. + */ + typedef struct GX_AVarSegmentRec_ + { + FT_UShort pairCount; + GX_AVarCorrespondence correspondence; /* array with pairCount entries */ + + } GX_AVarSegmentRec, *GX_AVarSegment; + + + /************************************************************************** + * + * @Struct: + * GX_AVarTableRec + * + * @Description: + * Data from the `avar' table. + */ + typedef struct GX_AVarTableRec_ + { + GX_AVarSegment avar_segment; /* avar_segment[num_axis] */ + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_DeltaSetIdxMapRec axisMap; /* Axis Mapping */ + + } GX_AVarTableRec, *GX_AVarTable; + + + /************************************************************************** + * + * @Struct: + * GX_HVVarTableRec + * + * @Description: + * Data from either the `HVAR' or `VVAR' table. + */ + typedef struct GX_HVVarTableRec_ + { + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_DeltaSetIdxMapRec widthMap; /* Advance Width Mapping */ + +#if 0 + GX_DeltaSetIdxMapRec lsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec rsbMap; /* not implemented */ + + GX_DeltaSetIdxMapRec tsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec bsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec vorgMap; /* not implemented */ +#endif + + } GX_HVVarTableRec, *GX_HVVarTable; + + +#define MVAR_TAG_GASP_0 FT_MAKE_TAG( 'g', 's', 'p', '0' ) +#define MVAR_TAG_GASP_1 FT_MAKE_TAG( 'g', 's', 'p', '1' ) +#define MVAR_TAG_GASP_2 FT_MAKE_TAG( 'g', 's', 'p', '2' ) +#define MVAR_TAG_GASP_3 FT_MAKE_TAG( 'g', 's', 'p', '3' ) +#define MVAR_TAG_GASP_4 FT_MAKE_TAG( 'g', 's', 'p', '4' ) +#define MVAR_TAG_GASP_5 FT_MAKE_TAG( 'g', 's', 'p', '5' ) +#define MVAR_TAG_GASP_6 FT_MAKE_TAG( 'g', 's', 'p', '6' ) +#define MVAR_TAG_GASP_7 FT_MAKE_TAG( 'g', 's', 'p', '7' ) +#define MVAR_TAG_GASP_8 FT_MAKE_TAG( 'g', 's', 'p', '8' ) +#define MVAR_TAG_GASP_9 FT_MAKE_TAG( 'g', 's', 'p', '9' ) + +#define MVAR_TAG_CPHT FT_MAKE_TAG( 'c', 'p', 'h', 't' ) +#define MVAR_TAG_HASC FT_MAKE_TAG( 'h', 'a', 's', 'c' ) +#define MVAR_TAG_HCLA FT_MAKE_TAG( 'h', 'c', 'l', 'a' ) +#define MVAR_TAG_HCLD FT_MAKE_TAG( 'h', 'c', 'l', 'd' ) +#define MVAR_TAG_HCOF FT_MAKE_TAG( 'h', 'c', 'o', 'f' ) +#define MVAR_TAG_HCRN FT_MAKE_TAG( 'h', 'c', 'r', 'n' ) +#define MVAR_TAG_HCRS FT_MAKE_TAG( 'h', 'c', 'r', 's' ) +#define MVAR_TAG_HDSC FT_MAKE_TAG( 'h', 'd', 's', 'c' ) +#define MVAR_TAG_HLGP FT_MAKE_TAG( 'h', 'l', 'g', 'p' ) +#define MVAR_TAG_SBXO FT_MAKE_TAG( 's', 'b', 'x', 'o' ) +#define MVAR_TAG_SBXS FT_MAKE_TAG( 's', 'b', 'x', 's' ) +#define MVAR_TAG_SBYO FT_MAKE_TAG( 's', 'b', 'y', 'o' ) +#define MVAR_TAG_SBYS FT_MAKE_TAG( 's', 'b', 'y', 's' ) +#define MVAR_TAG_SPXO FT_MAKE_TAG( 's', 'p', 'x', 'o' ) +#define MVAR_TAG_SPXS FT_MAKE_TAG( 's', 'p', 'x', 's' ) +#define MVAR_TAG_SPYO FT_MAKE_TAG( 's', 'p', 'y', 'o' ) +#define MVAR_TAG_SPYS FT_MAKE_TAG( 's', 'p', 'y', 's' ) +#define MVAR_TAG_STRO FT_MAKE_TAG( 's', 't', 'r', 'o' ) +#define MVAR_TAG_STRS FT_MAKE_TAG( 's', 't', 'r', 's' ) +#define MVAR_TAG_UNDO FT_MAKE_TAG( 'u', 'n', 'd', 'o' ) +#define MVAR_TAG_UNDS FT_MAKE_TAG( 'u', 'n', 'd', 's' ) +#define MVAR_TAG_VASC FT_MAKE_TAG( 'v', 'a', 's', 'c' ) +#define MVAR_TAG_VCOF FT_MAKE_TAG( 'v', 'c', 'o', 'f' ) +#define MVAR_TAG_VCRN FT_MAKE_TAG( 'v', 'c', 'r', 'n' ) +#define MVAR_TAG_VCRS FT_MAKE_TAG( 'v', 'c', 'r', 's' ) +#define MVAR_TAG_VDSC FT_MAKE_TAG( 'v', 'd', 's', 'c' ) +#define MVAR_TAG_VLGP FT_MAKE_TAG( 'v', 'l', 'g', 'p' ) +#define MVAR_TAG_XHGT FT_MAKE_TAG( 'x', 'h', 'g', 't' ) + + + typedef struct GX_ValueRec_ + { + FT_ULong tag; + FT_UShort outerIndex; + FT_UShort innerIndex; + + FT_Short unmodified; /* values are either FT_Short or FT_UShort */ + + } GX_ValueRec, *GX_Value; + + + /************************************************************************** + * + * @Struct: + * GX_MVarTableRec + * + * @Description: + * Data from the `MVAR' table. + */ + typedef struct GX_MVarTableRec_ + { + FT_UShort valueCount; + + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_Value values; /* Value Records */ + + } GX_MVarTableRec, *GX_MVarTable; + + + /************************************************************************** + * + * @Struct: + * GX_BlendRec + * + * @Description: + * Data for interpolating a font from a distortable font specified + * by the GX *var tables ([fgcahvm]var). + * + * @Fields: + * num_axis :: + * The number of axes along which interpolation may happen. + * + * coords :: + * An array of design coordinates (in user space) indicating the + * contribution along each axis to the final interpolated font. + * `normalizedcoords' holds the same values. + * + * normalizedcoords :: + * An array of normalized values (between [-1,1]) indicating the + * contribution along each axis to the final interpolated font. + * `coords' holds the same values. + * + * mmvar :: + * Data from the `fvar' table. + * + * mmvar_len :: + * The length of the `mmvar' structure. + * + * normalized_stylecoords :: + * A two-dimensional array that holds the named instance data from + * `mmvar' as normalized values. + * + * avar_loaded :: + * A Boolean; if set, FreeType tried to load (and parse) the `avar' + * table. + * + * avar_table :: + * Data from the `avar' table. + * + * hvar_loaded :: + * A Boolean; if set, FreeType tried to load (and parse) the `hvar' + * table. + * + * hvar_checked :: + * A Boolean; if set, FreeType successfully loaded and parsed the + * `hvar' table. + * + * hvar_error :: + * If loading and parsing of the `hvar' table failed, this field + * holds the corresponding error code. + * + * hvar_table :: + * Data from the `hvar' table. + * + * vvar_loaded :: + * A Boolean; if set, FreeType tried to load (and parse) the `vvar' + * table. + * + * vvar_checked :: + * A Boolean; if set, FreeType successfully loaded and parsed the + * `vvar' table. + * + * vvar_error :: + * If loading and parsing of the `vvar' table failed, this field + * holds the corresponding error code. + * + * vvar_table :: + * Data from the `vvar' table. + * + * mvar_table :: + * Data from the `mvar' table. + * + * tuplecount :: + * The number of shared tuples in the `gvar' table. + * + * tuplecoords :: + * A two-dimensional array that holds the shared tuple coordinates + * in the `gvar' table. + * + * gv_glyphcnt :: + * The number of glyphs handled in the `gvar' table. + * + * glyphoffsets :: + * Offsets into the glyph variation data array. + * + * gvar_size :: + * The size of the `gvar' table. + */ + typedef struct GX_BlendRec_ + { + FT_UInt num_axis; + FT_Fixed* coords; + FT_Fixed* normalizedcoords; + + FT_MM_Var* mmvar; + FT_Offset mmvar_len; + + FT_Fixed* normalized_stylecoords; + /* normalized_stylecoords[num_namedstyles][num_axis] */ + + FT_Bool avar_loaded; + GX_AVarTable avar_table; + + FT_Bool hvar_loaded; + FT_Bool hvar_checked; + FT_Error hvar_error; + GX_HVVarTable hvar_table; + + FT_Bool vvar_loaded; + FT_Bool vvar_checked; + FT_Error vvar_error; + GX_HVVarTable vvar_table; + + GX_MVarTable mvar_table; + + FT_UInt tuplecount; + FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ + + FT_UInt gv_glyphcnt; + FT_ULong* glyphoffsets; /* glyphoffsets[gv_glyphcnt + 1] */ + + FT_ULong gvar_size; + + } GX_BlendRec; + + + /************************************************************************** + * + * @enum: + * GX_TupleCountFlags + * + * @Description: + * Flags used within the `TupleCount' field of the `gvar' table. + */ + typedef enum GX_TupleCountFlags_ + { + GX_TC_TUPLES_SHARE_POINT_NUMBERS = 0x8000, + GX_TC_RESERVED_TUPLE_FLAGS = 0x7000, + GX_TC_TUPLE_COUNT_MASK = 0x0FFF + + } GX_TupleCountFlags; + + + /************************************************************************** + * + * @enum: + * GX_TupleIndexFlags + * + * @Description: + * Flags used within the `TupleIndex' field of the `gvar' and `cvar' + * tables. + */ + typedef enum GX_TupleIndexFlags_ + { + GX_TI_EMBEDDED_TUPLE_COORD = 0x8000, + GX_TI_INTERMEDIATE_TUPLE = 0x4000, + GX_TI_PRIVATE_POINT_NUMBERS = 0x2000, + GX_TI_RESERVED_TUPLE_FLAG = 0x1000, + GX_TI_TUPLE_INDEX_MASK = 0x0FFF + + } GX_TupleIndexFlags; + + +#define TTAG_wght FT_MAKE_TAG( 'w', 'g', 'h', 't' ) +#define TTAG_wdth FT_MAKE_TAG( 'w', 'd', 't', 'h' ) +#define TTAG_opsz FT_MAKE_TAG( 'o', 'p', 's', 'z' ) +#define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' ) +#define TTAG_ital FT_MAKE_TAG( 'i', 't', 'a', 'l' ) + + + FT_LOCAL( FT_Error ) + TT_Set_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Get_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Set_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Get_MM_Var( FT_Face face, + FT_MM_Var* *master ); + + FT_LOCAL( FT_Error ) + TT_Get_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Set_Named_Instance( FT_Face face, + FT_UInt instance_index ); + + FT_LOCAL( FT_Error ) + TT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ); + + FT_LOCAL( void ) + tt_construct_ps_name( FT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + TT_Vary_Apply_Glyph_Deltas( TT_Loader loader, + FT_Outline* outline, + FT_Vector* unrounded ); + + FT_LOCAL( FT_Error ) + tt_hadvance_adjust( FT_Face face, + FT_UInt gindex, + FT_Int *adelta ); + + FT_LOCAL( FT_Error ) + tt_vadvance_adjust( FT_Face face, + FT_UInt gindex, + FT_Int *adelta ); + + FT_LOCAL( void ) + tt_apply_mvar( FT_Face face ); + + FT_LOCAL( FT_Error ) + tt_var_load_item_variation_store( FT_Face face, + FT_ULong offset, + GX_ItemVarStore itemStore ); + + FT_LOCAL( FT_Error ) + tt_var_load_delta_set_index_mapping( FT_Face face, + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ); + + FT_LOCAL( FT_ItemVarDelta ) + tt_var_get_item_delta( FT_Face face, + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ); + + FT_LOCAL( void ) + tt_var_done_item_variation_store( FT_Face face, + GX_ItemVarStore itemStore ); + + FT_LOCAL( void ) + tt_var_done_delta_set_index_map( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ); + + + FT_LOCAL( FT_Error ) + tt_get_var_blend( FT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ); + + FT_LOCAL( void ) + tt_done_blend( FT_Face face ); + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + +FT_END_HEADER + + +#endif /* TTGXVAR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttinterp.c b/vendor/freetype/src/truetype/ttinterp.c new file mode 100644 index 0000000..79df455 --- /dev/null +++ b/vendor/freetype/src/truetype/ttinterp.c @@ -0,0 +1,7753 @@ +/**************************************************************************** + * + * ttinterp.c + * + * TrueType bytecode interpreter (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +/* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */ +/* issues; many thanks! */ + + +#include +#include +#include +#include +#include +#include + +#include "ttinterp.h" +#include "tterrors.h" +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttinterp + + +#define NO_SUBPIXEL_HINTING \ + ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ + TT_INTERPRETER_VERSION_35 ) + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#define SUBPIXEL_HINTING_MINIMAL \ + ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ + TT_INTERPRETER_VERSION_40 ) +#endif + +#define PROJECT( v1, v2 ) \ + exc->func_project( exc, \ + SUB_LONG( (v1)->x, (v2)->x ), \ + SUB_LONG( (v1)->y, (v2)->y ) ) + +#define DUALPROJ( v1, v2 ) \ + exc->func_dualproj( exc, \ + SUB_LONG( (v1)->x, (v2)->x ), \ + SUB_LONG( (v1)->y, (v2)->y ) ) + +#define FAST_PROJECT( v ) \ + exc->func_project( exc, (v)->x, (v)->y ) + +#define FAST_DUALPROJ( v ) \ + exc->func_dualproj( exc, (v)->x, (v)->y ) + + + /************************************************************************** + * + * Two simple bounds-checking macros. + */ +#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) ) +#define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) ) + + +#undef SUCCESS +#define SUCCESS 0 + +#undef FAILURE +#define FAILURE 1 + + + /************************************************************************** + * + * CODERANGE FUNCTIONS + * + */ + + + /************************************************************************** + * + * @Function: + * TT_Goto_CodeRange + * + * @Description: + * Switches to a new code range (updates the code related elements in + * `exec', and `IP'). + * + * @Input: + * range :: + * The new execution code range. + * + * IP :: + * The new IP in the new code range. + * + * @InOut: + * exec :: + * The target execution context. + */ + FT_LOCAL_DEF( void ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ) + { + TT_CodeRange* coderange; + + + FT_ASSERT( range >= 1 && range <= 3 ); + + coderange = &exec->codeRangeTable[range - 1]; + + FT_ASSERT( coderange->base ); + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for IP <= Size instead of IP < Size. */ + /* */ + FT_ASSERT( IP <= coderange->size ); + + exec->code = coderange->base; + exec->codeSize = coderange->size; + exec->IP = IP; + exec->curRange = range; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_CodeRange + * + * @Description: + * Sets a code range. + * + * @Input: + * range :: + * The code range index. + * + * base :: + * The new code base. + * + * length :: + * The range size in bytes. + * + * @InOut: + * exec :: + * The target execution context. + */ + FT_LOCAL_DEF( void ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = (FT_Byte*)base; + exec->codeRangeTable[range - 1].size = length; + } + + + /************************************************************************** + * + * @Function: + * TT_Clear_CodeRange + * + * @Description: + * Clears a code range. + * + * @Input: + * range :: + * The code range index. + * + * @InOut: + * exec :: + * The target execution context. + */ + FT_LOCAL_DEF( void ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = NULL; + exec->codeRangeTable[range - 1].size = 0; + } + + + /************************************************************************** + * + * EXECUTION CONTEXT ROUTINES + * + */ + + + /************************************************************************** + * + * @Function: + * TT_Done_Context + * + * @Description: + * Destroys a given context. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * memory :: + * A handle to the parent memory object. + * + * @Note: + * Only the glyph loader and debugger should call this function. + */ + FT_LOCAL_DEF( void ) + TT_Done_Context( TT_ExecContext exec ) + { + FT_Memory memory = exec->memory; + + + /* points zone */ + exec->maxPoints = 0; + exec->maxContours = 0; + + /* free stack */ + FT_FREE( exec->stack ); + exec->stackSize = 0; + + /* free glyf cvt working area */ + FT_FREE( exec->glyfCvt ); + exec->glyfCvtSize = 0; + + /* free glyf storage working area */ + FT_FREE( exec->glyfStorage ); + exec->glyfStoreSize = 0; + + /* free call stack */ + FT_FREE( exec->callStack ); + exec->callSize = 0; + exec->callTop = 0; + + /* free glyph code range */ + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + exec->size = NULL; + exec->face = NULL; + + FT_FREE( exec ); + } + + + /************************************************************************** + * + * @Function: + * TT_Load_Context + * + * @Description: + * Prepare an execution context for glyph hinting. + * + * @Input: + * face :: + * A handle to the source face object. + * + * size :: + * A handle to the source size object. + * + * @InOut: + * exec :: + * A handle to the target execution context. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only the glyph loader and debugger should call this function. + * + * Note that not all members of `TT_ExecContext` get initialized. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ) + { + FT_Int i; + TT_MaxProfile* maxp; + FT_Error error; + FT_Memory memory = exec->memory; + + + exec->face = face; + maxp = &face->max_profile; + exec->size = size; + + if ( size ) + { + exec->numFDefs = size->num_function_defs; + exec->maxFDefs = size->max_function_defs; + exec->numIDefs = size->num_instruction_defs; + exec->maxIDefs = size->max_instruction_defs; + exec->FDefs = size->function_defs; + exec->IDefs = size->instruction_defs; + exec->pointSize = size->point_size; + exec->tt_metrics = size->ttmetrics; + exec->metrics = *size->metrics; + + exec->maxFunc = size->max_func; + exec->maxIns = size->max_ins; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + exec->codeRangeTable[i] = size->codeRangeTable[i]; + + /* set graphics state */ + exec->GS = size->GS; + + exec->cvtSize = size->cvt_size; + exec->cvt = size->cvt; + + exec->storeSize = size->storage_size; + exec->storage = size->storage; + + exec->twilight = size->twilight; + + /* In case of multi-threading it can happen that the old size object */ + /* no longer exists, thus we must clear all glyph zone references. */ + FT_ZERO( &exec->zp0 ); + exec->zp1 = exec->zp0; + exec->zp2 = exec->zp0; + } + + /* XXX: We reserve a little more elements on the stack to deal safely */ + /* with broken fonts like arialbs, courbs, timesbs, etc. */ + if ( FT_QRENEW_ARRAY( exec->stack, + exec->stackSize, + maxp->maxStackElements + 32 ) ) + return error; + exec->stackSize = maxp->maxStackElements + 32; + + /* free previous glyph code range */ + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; + + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + exec->zp0 = exec->pts; + + exec->instruction_trap = FALSE; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Save_Context + * + * @Description: + * Saves the code ranges in a `size' object. + * + * @Input: + * exec :: + * A handle to the source execution context. + * + * @InOut: + * size :: + * A handle to the target size object. + * + * @Note: + * Only the glyph loader and debugger should call this function. + */ + FT_LOCAL_DEF( void ) + TT_Save_Context( TT_ExecContext exec, + TT_Size size ) + { + FT_Int i; + + + /* XXX: Will probably disappear soon with all the code range */ + /* management, which is now rather obsolete. */ + /* */ + size->num_function_defs = exec->numFDefs; + size->num_instruction_defs = exec->numIDefs; + + size->max_func = exec->maxFunc; + size->max_ins = exec->maxIns; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + size->codeRangeTable[i] = exec->codeRangeTable[i]; + } + + + /************************************************************************** + * + * @Function: + * TT_Run_Context + * + * @Description: + * Executes one or more instructions in the execution context. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * @Return: + * TrueType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Run_Context( TT_ExecContext exec ) + { + TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ); + + exec->zp0 = exec->pts; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + + exec->GS.gep0 = 1; + exec->GS.gep1 = 1; + exec->GS.gep2 = 1; + + exec->GS.projVector.x = 0x4000; + exec->GS.projVector.y = 0x0000; + + exec->GS.freeVector = exec->GS.projVector; + exec->GS.dualVector = exec->GS.projVector; + + exec->GS.round_state = 1; + exec->GS.loop = 1; + + /* some glyphs leave something on the stack. so we clean it */ + /* before a new execution. */ + exec->top = 0; + exec->callTop = 0; + + return exec->face->interpreter( exec ); + } + + + /* The default value for `scan_control' is documented as FALSE in the */ + /* TrueType specification. This is confusing since it implies a */ + /* Boolean value. However, this is not the case, thus both the */ + /* default values of our `scan_type' and `scan_control' fields (which */ + /* the documentation's `scan_control' variable is split into) are */ + /* zero. */ + + const TT_GraphicsState tt_default_graphics_state = + { + 0, 0, 0, + { 0x4000, 0 }, + { 0x4000, 0 }, + { 0x4000, 0 }, + + 1, 64, 1, + TRUE, 68, 0, 0, 9, 3, + 0, FALSE, 0, 1, 1, 1 + }; + + + /* documentation is in ttinterp.h */ + + FT_EXPORT_DEF( TT_ExecContext ) + TT_New_Context( TT_Driver driver ) + { + FT_Memory memory; + FT_Error error; + + TT_ExecContext exec = NULL; + + + if ( !driver ) + goto Fail; + + memory = driver->root.root.memory; + + /* allocate object and zero everything inside */ + if ( FT_NEW( exec ) ) + goto Fail; + + /* create callStack here, other allocations delayed */ + exec->memory = memory; + exec->callSize = 32; + + if ( FT_QNEW_ARRAY( exec->callStack, exec->callSize ) ) + FT_FREE( exec ); + + Fail: + return exec; + } + + + /************************************************************************** + * + * Before an opcode is executed, the interpreter verifies that there are + * enough arguments on the stack, with the help of the `Pop_Push_Count' + * table. + * + * For each opcode, the first column gives the number of arguments that + * are popped from the stack; the second one gives the number of those + * that are pushed in result. + * + * Opcodes which have a varying number of parameters in the data stream + * (NPUSHB, NPUSHW) are handled specially; they have a negative value in + * the `opcode_length' table, and the value in `Pop_Push_Count' is set + * to zero. + * + */ + + +#undef PACK +#define PACK( x, y ) ( ( x << 4 ) | y ) + + + static + const FT_Byte Pop_Push_Count[256] = + { + /* opcodes are gathered in groups of 16 */ + /* please keep the spaces as they are */ + + /* 0x00 */ + /* SVTCA[0] */ PACK( 0, 0 ), + /* SVTCA[1] */ PACK( 0, 0 ), + /* SPVTCA[0] */ PACK( 0, 0 ), + /* SPVTCA[1] */ PACK( 0, 0 ), + /* SFVTCA[0] */ PACK( 0, 0 ), + /* SFVTCA[1] */ PACK( 0, 0 ), + /* SPVTL[0] */ PACK( 2, 0 ), + /* SPVTL[1] */ PACK( 2, 0 ), + /* SFVTL[0] */ PACK( 2, 0 ), + /* SFVTL[1] */ PACK( 2, 0 ), + /* SPVFS */ PACK( 2, 0 ), + /* SFVFS */ PACK( 2, 0 ), + /* GPV */ PACK( 0, 2 ), + /* GFV */ PACK( 0, 2 ), + /* SFVTPV */ PACK( 0, 0 ), + /* ISECT */ PACK( 5, 0 ), + + /* 0x10 */ + /* SRP0 */ PACK( 1, 0 ), + /* SRP1 */ PACK( 1, 0 ), + /* SRP2 */ PACK( 1, 0 ), + /* SZP0 */ PACK( 1, 0 ), + /* SZP1 */ PACK( 1, 0 ), + /* SZP2 */ PACK( 1, 0 ), + /* SZPS */ PACK( 1, 0 ), + /* SLOOP */ PACK( 1, 0 ), + /* RTG */ PACK( 0, 0 ), + /* RTHG */ PACK( 0, 0 ), + /* SMD */ PACK( 1, 0 ), + /* ELSE */ PACK( 0, 0 ), + /* JMPR */ PACK( 1, 0 ), + /* SCVTCI */ PACK( 1, 0 ), + /* SSWCI */ PACK( 1, 0 ), + /* SSW */ PACK( 1, 0 ), + + /* 0x20 */ + /* DUP */ PACK( 1, 2 ), + /* POP */ PACK( 1, 0 ), + /* CLEAR */ PACK( 0, 0 ), + /* SWAP */ PACK( 2, 2 ), + /* DEPTH */ PACK( 0, 1 ), + /* CINDEX */ PACK( 1, 1 ), + /* MINDEX */ PACK( 1, 0 ), + /* ALIGNPTS */ PACK( 2, 0 ), + /* INS_$28 */ PACK( 0, 0 ), + /* UTP */ PACK( 1, 0 ), + /* LOOPCALL */ PACK( 2, 0 ), + /* CALL */ PACK( 1, 0 ), + /* FDEF */ PACK( 1, 0 ), + /* ENDF */ PACK( 0, 0 ), + /* MDAP[0] */ PACK( 1, 0 ), + /* MDAP[1] */ PACK( 1, 0 ), + + /* 0x30 */ + /* IUP[0] */ PACK( 0, 0 ), + /* IUP[1] */ PACK( 0, 0 ), + /* SHP[0] */ PACK( 0, 0 ), /* loops */ + /* SHP[1] */ PACK( 0, 0 ), /* loops */ + /* SHC[0] */ PACK( 1, 0 ), + /* SHC[1] */ PACK( 1, 0 ), + /* SHZ[0] */ PACK( 1, 0 ), + /* SHZ[1] */ PACK( 1, 0 ), + /* SHPIX */ PACK( 1, 0 ), /* loops */ + /* IP */ PACK( 0, 0 ), /* loops */ + /* MSIRP[0] */ PACK( 2, 0 ), + /* MSIRP[1] */ PACK( 2, 0 ), + /* ALIGNRP */ PACK( 0, 0 ), /* loops */ + /* RTDG */ PACK( 0, 0 ), + /* MIAP[0] */ PACK( 2, 0 ), + /* MIAP[1] */ PACK( 2, 0 ), + + /* 0x40 */ + /* NPUSHB */ PACK( 0, 0 ), + /* NPUSHW */ PACK( 0, 0 ), + /* WS */ PACK( 2, 0 ), + /* RS */ PACK( 1, 1 ), + /* WCVTP */ PACK( 2, 0 ), + /* RCVT */ PACK( 1, 1 ), + /* GC[0] */ PACK( 1, 1 ), + /* GC[1] */ PACK( 1, 1 ), + /* SCFS */ PACK( 2, 0 ), + /* MD[0] */ PACK( 2, 1 ), + /* MD[1] */ PACK( 2, 1 ), + /* MPPEM */ PACK( 0, 1 ), + /* MPS */ PACK( 0, 1 ), + /* FLIPON */ PACK( 0, 0 ), + /* FLIPOFF */ PACK( 0, 0 ), + /* DEBUG */ PACK( 1, 0 ), + + /* 0x50 */ + /* LT */ PACK( 2, 1 ), + /* LTEQ */ PACK( 2, 1 ), + /* GT */ PACK( 2, 1 ), + /* GTEQ */ PACK( 2, 1 ), + /* EQ */ PACK( 2, 1 ), + /* NEQ */ PACK( 2, 1 ), + /* ODD */ PACK( 1, 1 ), + /* EVEN */ PACK( 1, 1 ), + /* IF */ PACK( 1, 0 ), + /* EIF */ PACK( 0, 0 ), + /* AND */ PACK( 2, 1 ), + /* OR */ PACK( 2, 1 ), + /* NOT */ PACK( 1, 1 ), + /* DELTAP1 */ PACK( 1, 0 ), + /* SDB */ PACK( 1, 0 ), + /* SDS */ PACK( 1, 0 ), + + /* 0x60 */ + /* ADD */ PACK( 2, 1 ), + /* SUB */ PACK( 2, 1 ), + /* DIV */ PACK( 2, 1 ), + /* MUL */ PACK( 2, 1 ), + /* ABS */ PACK( 1, 1 ), + /* NEG */ PACK( 1, 1 ), + /* FLOOR */ PACK( 1, 1 ), + /* CEILING */ PACK( 1, 1 ), + /* ROUND[0] */ PACK( 1, 1 ), + /* ROUND[1] */ PACK( 1, 1 ), + /* ROUND[2] */ PACK( 1, 1 ), + /* ROUND[3] */ PACK( 1, 1 ), + /* NROUND[0] */ PACK( 1, 1 ), + /* NROUND[1] */ PACK( 1, 1 ), + /* NROUND[2] */ PACK( 1, 1 ), + /* NROUND[3] */ PACK( 1, 1 ), + + /* 0x70 */ + /* WCVTF */ PACK( 2, 0 ), + /* DELTAP2 */ PACK( 1, 0 ), + /* DELTAP3 */ PACK( 1, 0 ), + /* DELTAC1 */ PACK( 1, 0 ), + /* DELTAC2 */ PACK( 1, 0 ), + /* DELTAC3 */ PACK( 1, 0 ), + /* SROUND */ PACK( 1, 0 ), + /* S45ROUND */ PACK( 1, 0 ), + /* JROT */ PACK( 2, 0 ), + /* JROF */ PACK( 2, 0 ), + /* ROFF */ PACK( 0, 0 ), + /* INS_$7B */ PACK( 0, 0 ), + /* RUTG */ PACK( 0, 0 ), + /* RDTG */ PACK( 0, 0 ), + /* SANGW */ PACK( 1, 0 ), + /* AA */ PACK( 1, 0 ), + + /* 0x80 */ + /* FLIPPT */ PACK( 0, 0 ), /* loops */ + /* FLIPRGON */ PACK( 2, 0 ), + /* FLIPRGOFF */ PACK( 2, 0 ), + /* INS_$83 */ PACK( 0, 0 ), + /* INS_$84 */ PACK( 0, 0 ), + /* SCANCTRL */ PACK( 1, 0 ), + /* SDPVTL[0] */ PACK( 2, 0 ), + /* SDPVTL[1] */ PACK( 2, 0 ), + /* GETINFO */ PACK( 1, 1 ), + /* IDEF */ PACK( 1, 0 ), + /* ROLL */ PACK( 3, 3 ), + /* MAX */ PACK( 2, 1 ), + /* MIN */ PACK( 2, 1 ), + /* SCANTYPE */ PACK( 1, 0 ), + /* INSTCTRL */ PACK( 2, 0 ), + /* INS_$8F */ PACK( 0, 0 ), + + /* 0x90 */ + /* INS_$90 */ PACK( 0, 0 ), + /* GETVAR */ PACK( 0, 0 ), /* will be handled specially */ + /* GETDATA */ PACK( 0, 1 ), + /* INS_$93 */ PACK( 0, 0 ), + /* INS_$94 */ PACK( 0, 0 ), + /* INS_$95 */ PACK( 0, 0 ), + /* INS_$96 */ PACK( 0, 0 ), + /* INS_$97 */ PACK( 0, 0 ), + /* INS_$98 */ PACK( 0, 0 ), + /* INS_$99 */ PACK( 0, 0 ), + /* INS_$9A */ PACK( 0, 0 ), + /* INS_$9B */ PACK( 0, 0 ), + /* INS_$9C */ PACK( 0, 0 ), + /* INS_$9D */ PACK( 0, 0 ), + /* INS_$9E */ PACK( 0, 0 ), + /* INS_$9F */ PACK( 0, 0 ), + + /* 0xA0 */ + /* INS_$A0 */ PACK( 0, 0 ), + /* INS_$A1 */ PACK( 0, 0 ), + /* INS_$A2 */ PACK( 0, 0 ), + /* INS_$A3 */ PACK( 0, 0 ), + /* INS_$A4 */ PACK( 0, 0 ), + /* INS_$A5 */ PACK( 0, 0 ), + /* INS_$A6 */ PACK( 0, 0 ), + /* INS_$A7 */ PACK( 0, 0 ), + /* INS_$A8 */ PACK( 0, 0 ), + /* INS_$A9 */ PACK( 0, 0 ), + /* INS_$AA */ PACK( 0, 0 ), + /* INS_$AB */ PACK( 0, 0 ), + /* INS_$AC */ PACK( 0, 0 ), + /* INS_$AD */ PACK( 0, 0 ), + /* INS_$AE */ PACK( 0, 0 ), + /* INS_$AF */ PACK( 0, 0 ), + + /* 0xB0 */ + /* PUSHB[0] */ PACK( 0, 1 ), + /* PUSHB[1] */ PACK( 0, 2 ), + /* PUSHB[2] */ PACK( 0, 3 ), + /* PUSHB[3] */ PACK( 0, 4 ), + /* PUSHB[4] */ PACK( 0, 5 ), + /* PUSHB[5] */ PACK( 0, 6 ), + /* PUSHB[6] */ PACK( 0, 7 ), + /* PUSHB[7] */ PACK( 0, 8 ), + /* PUSHW[0] */ PACK( 0, 1 ), + /* PUSHW[1] */ PACK( 0, 2 ), + /* PUSHW[2] */ PACK( 0, 3 ), + /* PUSHW[3] */ PACK( 0, 4 ), + /* PUSHW[4] */ PACK( 0, 5 ), + /* PUSHW[5] */ PACK( 0, 6 ), + /* PUSHW[6] */ PACK( 0, 7 ), + /* PUSHW[7] */ PACK( 0, 8 ), + + /* 0xC0 */ + /* MDRP[00] */ PACK( 1, 0 ), + /* MDRP[01] */ PACK( 1, 0 ), + /* MDRP[02] */ PACK( 1, 0 ), + /* MDRP[03] */ PACK( 1, 0 ), + /* MDRP[04] */ PACK( 1, 0 ), + /* MDRP[05] */ PACK( 1, 0 ), + /* MDRP[06] */ PACK( 1, 0 ), + /* MDRP[07] */ PACK( 1, 0 ), + /* MDRP[08] */ PACK( 1, 0 ), + /* MDRP[09] */ PACK( 1, 0 ), + /* MDRP[10] */ PACK( 1, 0 ), + /* MDRP[11] */ PACK( 1, 0 ), + /* MDRP[12] */ PACK( 1, 0 ), + /* MDRP[13] */ PACK( 1, 0 ), + /* MDRP[14] */ PACK( 1, 0 ), + /* MDRP[15] */ PACK( 1, 0 ), + + /* 0xD0 */ + /* MDRP[16] */ PACK( 1, 0 ), + /* MDRP[17] */ PACK( 1, 0 ), + /* MDRP[18] */ PACK( 1, 0 ), + /* MDRP[19] */ PACK( 1, 0 ), + /* MDRP[20] */ PACK( 1, 0 ), + /* MDRP[21] */ PACK( 1, 0 ), + /* MDRP[22] */ PACK( 1, 0 ), + /* MDRP[23] */ PACK( 1, 0 ), + /* MDRP[24] */ PACK( 1, 0 ), + /* MDRP[25] */ PACK( 1, 0 ), + /* MDRP[26] */ PACK( 1, 0 ), + /* MDRP[27] */ PACK( 1, 0 ), + /* MDRP[28] */ PACK( 1, 0 ), + /* MDRP[29] */ PACK( 1, 0 ), + /* MDRP[30] */ PACK( 1, 0 ), + /* MDRP[31] */ PACK( 1, 0 ), + + /* 0xE0 */ + /* MIRP[00] */ PACK( 2, 0 ), + /* MIRP[01] */ PACK( 2, 0 ), + /* MIRP[02] */ PACK( 2, 0 ), + /* MIRP[03] */ PACK( 2, 0 ), + /* MIRP[04] */ PACK( 2, 0 ), + /* MIRP[05] */ PACK( 2, 0 ), + /* MIRP[06] */ PACK( 2, 0 ), + /* MIRP[07] */ PACK( 2, 0 ), + /* MIRP[08] */ PACK( 2, 0 ), + /* MIRP[09] */ PACK( 2, 0 ), + /* MIRP[10] */ PACK( 2, 0 ), + /* MIRP[11] */ PACK( 2, 0 ), + /* MIRP[12] */ PACK( 2, 0 ), + /* MIRP[13] */ PACK( 2, 0 ), + /* MIRP[14] */ PACK( 2, 0 ), + /* MIRP[15] */ PACK( 2, 0 ), + + /* 0xF0 */ + /* MIRP[16] */ PACK( 2, 0 ), + /* MIRP[17] */ PACK( 2, 0 ), + /* MIRP[18] */ PACK( 2, 0 ), + /* MIRP[19] */ PACK( 2, 0 ), + /* MIRP[20] */ PACK( 2, 0 ), + /* MIRP[21] */ PACK( 2, 0 ), + /* MIRP[22] */ PACK( 2, 0 ), + /* MIRP[23] */ PACK( 2, 0 ), + /* MIRP[24] */ PACK( 2, 0 ), + /* MIRP[25] */ PACK( 2, 0 ), + /* MIRP[26] */ PACK( 2, 0 ), + /* MIRP[27] */ PACK( 2, 0 ), + /* MIRP[28] */ PACK( 2, 0 ), + /* MIRP[29] */ PACK( 2, 0 ), + /* MIRP[30] */ PACK( 2, 0 ), + /* MIRP[31] */ PACK( 2, 0 ) + }; + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* the first hex digit gives the length of the opcode name; the space */ + /* after the digit is here just to increase readability of the source */ + /* code */ + + static + const char* const opcode_name[256] = + { + /* 0x00 */ + "8 SVTCA[y]", + "8 SVTCA[x]", + "9 SPVTCA[y]", + "9 SPVTCA[x]", + "9 SFVTCA[y]", + "9 SFVTCA[x]", + "9 SPVTL[||]", + "8 SPVTL[+]", + "9 SFVTL[||]", + "8 SFVTL[+]", + "5 SPVFS", + "5 SFVFS", + "3 GPV", + "3 GFV", + "6 SFVTPV", + "5 ISECT", + + /* 0x10 */ + "4 SRP0", + "4 SRP1", + "4 SRP2", + "4 SZP0", + "4 SZP1", + "4 SZP2", + "4 SZPS", + "5 SLOOP", + "3 RTG", + "4 RTHG", + "3 SMD", + "4 ELSE", + "4 JMPR", + "6 SCVTCI", + "5 SSWCI", + "3 SSW", + + /* 0x20 */ + "3 DUP", + "3 POP", + "5 CLEAR", + "4 SWAP", + "5 DEPTH", + "6 CINDEX", + "6 MINDEX", + "8 ALIGNPTS", + "7 INS_$28", + "3 UTP", + "8 LOOPCALL", + "4 CALL", + "4 FDEF", + "4 ENDF", + "6 MDAP[]", + "9 MDAP[rnd]", + + /* 0x30 */ + "6 IUP[y]", + "6 IUP[x]", + "8 SHP[rp2]", + "8 SHP[rp1]", + "8 SHC[rp2]", + "8 SHC[rp1]", + "8 SHZ[rp2]", + "8 SHZ[rp1]", + "5 SHPIX", + "2 IP", + "7 MSIRP[]", + "A MSIRP[rp0]", + "7 ALIGNRP", + "4 RTDG", + "6 MIAP[]", + "9 MIAP[rnd]", + + /* 0x40 */ + "6 NPUSHB", + "6 NPUSHW", + "2 WS", + "2 RS", + "5 WCVTP", + "4 RCVT", + "8 GC[curr]", + "8 GC[orig]", + "4 SCFS", + "8 MD[curr]", + "8 MD[orig]", + "5 MPPEM", + "3 MPS", + "6 FLIPON", + "7 FLIPOFF", + "5 DEBUG", + + /* 0x50 */ + "2 LT", + "4 LTEQ", + "2 GT", + "4 GTEQ", + "2 EQ", + "3 NEQ", + "3 ODD", + "4 EVEN", + "2 IF", + "3 EIF", + "3 AND", + "2 OR", + "3 NOT", + "7 DELTAP1", + "3 SDB", + "3 SDS", + + /* 0x60 */ + "3 ADD", + "3 SUB", + "3 DIV", + "3 MUL", + "3 ABS", + "3 NEG", + "5 FLOOR", + "7 CEILING", + "8 ROUND[G]", + "8 ROUND[B]", + "8 ROUND[W]", + "7 ROUND[]", + "9 NROUND[G]", + "9 NROUND[B]", + "9 NROUND[W]", + "8 NROUND[]", + + /* 0x70 */ + "5 WCVTF", + "7 DELTAP2", + "7 DELTAP3", + "7 DELTAC1", + "7 DELTAC2", + "7 DELTAC3", + "6 SROUND", + "8 S45ROUND", + "4 JROT", + "4 JROF", + "4 ROFF", + "7 INS_$7B", + "4 RUTG", + "4 RDTG", + "5 SANGW", + "2 AA", + + /* 0x80 */ + "6 FLIPPT", + "8 FLIPRGON", + "9 FLIPRGOFF", + "7 INS_$83", + "7 INS_$84", + "8 SCANCTRL", + "A SDPVTL[||]", + "9 SDPVTL[+]", + "7 GETINFO", + "4 IDEF", + "4 ROLL", + "3 MAX", + "3 MIN", + "8 SCANTYPE", + "8 INSTCTRL", + "7 INS_$8F", + + /* 0x90 */ + "7 INS_$90", +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + "C GETVARIATION", + "7 GETDATA", +#else + "7 INS_$91", + "7 INS_$92", +#endif + "7 INS_$93", + "7 INS_$94", + "7 INS_$95", + "7 INS_$96", + "7 INS_$97", + "7 INS_$98", + "7 INS_$99", + "7 INS_$9A", + "7 INS_$9B", + "7 INS_$9C", + "7 INS_$9D", + "7 INS_$9E", + "7 INS_$9F", + + /* 0xA0 */ + "7 INS_$A0", + "7 INS_$A1", + "7 INS_$A2", + "7 INS_$A3", + "7 INS_$A4", + "7 INS_$A5", + "7 INS_$A6", + "7 INS_$A7", + "7 INS_$A8", + "7 INS_$A9", + "7 INS_$AA", + "7 INS_$AB", + "7 INS_$AC", + "7 INS_$AD", + "7 INS_$AE", + "7 INS_$AF", + + /* 0xB0 */ + "8 PUSHB[0]", + "8 PUSHB[1]", + "8 PUSHB[2]", + "8 PUSHB[3]", + "8 PUSHB[4]", + "8 PUSHB[5]", + "8 PUSHB[6]", + "8 PUSHB[7]", + "8 PUSHW[0]", + "8 PUSHW[1]", + "8 PUSHW[2]", + "8 PUSHW[3]", + "8 PUSHW[4]", + "8 PUSHW[5]", + "8 PUSHW[6]", + "8 PUSHW[7]", + + /* 0xC0 */ + "7 MDRP[G]", + "7 MDRP[B]", + "7 MDRP[W]", + "6 MDRP[]", + "8 MDRP[rG]", + "8 MDRP[rB]", + "8 MDRP[rW]", + "7 MDRP[r]", + "8 MDRP[mG]", + "8 MDRP[mB]", + "8 MDRP[mW]", + "7 MDRP[m]", + "9 MDRP[mrG]", + "9 MDRP[mrB]", + "9 MDRP[mrW]", + "8 MDRP[mr]", + + /* 0xD0 */ + "8 MDRP[pG]", + "8 MDRP[pB]", + "8 MDRP[pW]", + "7 MDRP[p]", + "9 MDRP[prG]", + "9 MDRP[prB]", + "9 MDRP[prW]", + "8 MDRP[pr]", + "9 MDRP[pmG]", + "9 MDRP[pmB]", + "9 MDRP[pmW]", + "8 MDRP[pm]", + "A MDRP[pmrG]", + "A MDRP[pmrB]", + "A MDRP[pmrW]", + "9 MDRP[pmr]", + + /* 0xE0 */ + "7 MIRP[G]", + "7 MIRP[B]", + "7 MIRP[W]", + "6 MIRP[]", + "8 MIRP[rG]", + "8 MIRP[rB]", + "8 MIRP[rW]", + "7 MIRP[r]", + "8 MIRP[mG]", + "8 MIRP[mB]", + "8 MIRP[mW]", + "7 MIRP[m]", + "9 MIRP[mrG]", + "9 MIRP[mrB]", + "9 MIRP[mrW]", + "8 MIRP[mr]", + + /* 0xF0 */ + "8 MIRP[pG]", + "8 MIRP[pB]", + "8 MIRP[pW]", + "7 MIRP[p]", + "9 MIRP[prG]", + "9 MIRP[prB]", + "9 MIRP[prW]", + "8 MIRP[pr]", + "9 MIRP[pmG]", + "9 MIRP[pmB]", + "9 MIRP[pmW]", + "8 MIRP[pm]", + "A MIRP[pmrG]", + "A MIRP[pmrB]", + "A MIRP[pmrW]", + "9 MIRP[pmr]" + }; + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + static + const FT_Char opcode_length[256] = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + +#undef PACK + + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + +#if defined( __arm__ ) && \ + ( defined( __thumb2__ ) || !defined( __thumb__ ) ) + +#define TT_MulFix14 TT_MulFix14_arm + + static FT_Int32 + TT_MulFix14_arm( FT_Int32 a, + FT_Int b ) + { + FT_Int32 t, t2; + + +#if defined( __CC_ARM ) || defined( __ARMCC__ ) + + __asm + { + smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ + mov a, t, asr #31 /* a = (hi >> 31) */ + add a, a, #0x2000 /* a += 0x2000 */ + adds t2, t2, a /* t2 += a */ + adc t, t, #0 /* t += carry */ + mov a, t2, lsr #14 /* a = t2 >> 14 */ + orr a, a, t, lsl #18 /* a |= t << 18 */ + } + +#elif defined( __GNUC__ ) + + __asm__ __volatile__ ( + "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ + "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ +#if defined( __clang__ ) && defined( __thumb2__ ) + "add.w %0, %0, #0x2000\n\t" /* %0 += 0x2000 */ +#else + "add %0, %0, #0x2000\n\t" /* %0 += 0x2000 */ +#endif + "adds %1, %1, %0\n\t" /* %1 += %0 */ + "adc %2, %2, #0\n\t" /* %2 += carry */ + "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */ + "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */ + : "=r"(a), "=&r"(t2), "=&r"(t) + : "r"(a), "r"(b) + : "cc" ); + +#endif + + return a; + } + +#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#if defined( __GNUC__ ) && \ + ( defined( __i386__ ) || defined( __x86_64__ ) ) + +#define TT_MulFix14 TT_MulFix14_long_long + + /* Temporarily disable the warning that C90 doesn't support `long long'. */ +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wlong-long" + + /* This is declared `noinline' because inlining the function results */ + /* in slower code. The `pure' attribute indicates that the result */ + /* only depends on the parameters. */ + static __attribute__(( noinline )) + __attribute__(( pure )) FT_Int32 + TT_MulFix14_long_long( FT_Int32 a, + FT_Int b ) + { + + long long ret = (long long)a * b; + + /* The following line assumes that right shifting of signed values */ + /* will actually preserve the sign bit. The exact behaviour is */ + /* undefined, but this is true on x86 and x86_64. */ + long long tmp = ret >> 63; + + + ret += 0x2000 + tmp; + + return (FT_Int32)( ret >> 14 ); + } + +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic pop +#endif + +#endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */ + + +#ifndef TT_MulFix14 + + /* Compute (a*b)/2^14 with maximum accuracy and rounding. */ + /* This is optimized to be faster than calling FT_MulFix() */ + /* for platforms where sizeof(int) == 2. */ + static FT_Int32 + TT_MulFix14( FT_Int32 a, + FT_Int b ) + { + FT_Int32 sign; + FT_UInt32 ah, al, mid, lo, hi; + + + sign = a ^ b; + + if ( a < 0 ) + a = -a; + if ( b < 0 ) + b = -b; + + ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU ); + al = (FT_UInt32)( a & 0xFFFFU ); + + lo = al * b; + mid = ah * b; + hi = mid >> 16; + mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */ + lo += mid; + if ( lo < mid ) + hi += 1; + + mid = ( lo >> 14 ) | ( hi << 18 ); + + return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid; + } + +#endif /* !TT_MulFix14 */ + + +#if defined( __GNUC__ ) && \ + ( defined( __i386__ ) || \ + defined( __x86_64__ ) || \ + defined( __arm__ ) ) + +#define TT_DotFix14 TT_DotFix14_long_long + +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wlong-long" + + static __attribute__(( pure )) FT_Int32 + TT_DotFix14_long_long( FT_Int32 ax, + FT_Int32 ay, + FT_Int bx, + FT_Int by ) + { + /* Temporarily disable the warning that C90 doesn't support */ + /* `long long'. */ + + long long temp1 = (long long)ax * bx; + long long temp2 = (long long)ay * by; + + + temp1 += temp2; + temp2 = temp1 >> 63; + temp1 += 0x2000 + temp2; + + return (FT_Int32)( temp1 >> 14 ); + + } + +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic pop +#endif + +#endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */ + + +#ifndef TT_DotFix14 + + /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */ + static FT_Int32 + TT_DotFix14( FT_Int32 ax, + FT_Int32 ay, + FT_Int bx, + FT_Int by ) + { + FT_Int32 m, s, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; + + + /* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx ); + m = ( ax >> 16 ) * bx; + + lo1 = l + ( (FT_UInt32)m << 16 ); + hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l ); + + /* compute ay*by as 64-bit value */ + l = (FT_UInt32)( ( ay & 0xFFFFU ) * by ); + m = ( ay >> 16 ) * by; + + lo2 = l + ( (FT_UInt32)m << 16 ); + hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l ); + + /* add them */ + lo = lo1 + lo2; + hi = hi1 + hi2 + ( lo < lo1 ); + + /* divide the result by 2^14 with rounding */ + s = hi >> 31; + l = lo + (FT_UInt32)s; + hi += s + ( l < lo ); + lo = l; + + l = lo + 0x2000U; + hi += ( l < lo ); + + return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); + } + +#endif /* TT_DotFix14 */ + + + /************************************************************************** + * + * @Function: + * Current_Ratio + * + * @Description: + * Returns the current aspect ratio scaling factor depending on the + * projection vector's state and device resolutions. + * + * @Return: + * The aspect ratio in 16.16 format, always <= 1.0 . + */ + static FT_Long + Current_Ratio( TT_ExecContext exc ) + { + if ( !exc->tt_metrics.ratio ) + { + if ( exc->GS.projVector.y == 0 ) + exc->tt_metrics.ratio = exc->tt_metrics.x_ratio; + + else if ( exc->GS.projVector.x == 0 ) + exc->tt_metrics.ratio = exc->tt_metrics.y_ratio; + + else + { + FT_F26Dot6 x, y; + + + x = TT_MulFix14( exc->tt_metrics.x_ratio, + exc->GS.projVector.x ); + y = TT_MulFix14( exc->tt_metrics.y_ratio, + exc->GS.projVector.y ); + exc->tt_metrics.ratio = FT_Hypot( x, y ); + } + } + return exc->tt_metrics.ratio; + } + + + FT_CALLBACK_DEF( FT_Long ) + Current_Ppem( TT_ExecContext exc ) + { + return exc->tt_metrics.ppem; + } + + + FT_CALLBACK_DEF( FT_Long ) + Current_Ppem_Stretched( TT_ExecContext exc ) + { + return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) ); + } + + + /************************************************************************** + * + * Functions related to the control value table (CVT). + * + */ + + + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT( TT_ExecContext exc, + FT_ULong idx ) + { + return exc->cvt[idx]; + } + + + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT_Stretched( TT_ExecContext exc, + FT_ULong idx ) + { + return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) ); + } + + + static void + Modify_CVT_Check( TT_ExecContext exc ) + { + if ( exc->iniRange == tt_coderange_glyph && + exc->cvt != exc->glyfCvt ) + { + FT_Memory memory = exc->memory; + FT_Error error; + + + FT_MEM_QRENEW_ARRAY( exc->glyfCvt, exc->glyfCvtSize, exc->cvtSize ); + exc->error = error; + if ( error ) + return; + + exc->glyfCvtSize = exc->cvtSize; + FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize ); + exc->cvt = exc->glyfCvt; + } + } + + + FT_CALLBACK_DEF( void ) + Write_CVT( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = value; + } + + + FT_CALLBACK_DEF( void ) + Write_CVT_Stretched( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) ); + } + + + FT_CALLBACK_DEF( void ) + Move_CVT( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], value ); + } + + + FT_CALLBACK_DEF( void ) + Move_CVT_Stretched( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], + FT_DivFix( value, Current_Ratio( exc ) ) ); + } + + + /************************************************************************** + * + * @Function: + * GetShortIns + * + * @Description: + * Returns a short integer taken from the instruction stream at + * address IP. + * + * @Return: + * Short read at code[IP]. + * + * @Note: + * This one could become a macro. + */ + static FT_Short + GetShortIns( TT_ExecContext exc ) + { + /* Reading a byte stream so there is no endianness (DaveP) */ + exc->IP += 2; + return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) + + exc->code[exc->IP - 1] ); + } + + + /************************************************************************** + * + * @Function: + * Ins_Goto_CodeRange + * + * @Description: + * Goes to a certain code range in the instruction stream. + * + * @Input: + * aRange :: + * The index of the code range. + * + * aIP :: + * The new IP address in the code range. + * + * @Return: + * SUCCESS or FAILURE. + */ + static FT_Bool + Ins_Goto_CodeRange( TT_ExecContext exc, + FT_Int aRange, + FT_Long aIP ) + { + TT_CodeRange* range; + + + if ( aRange < 1 || aRange > 3 ) + { + exc->error = FT_THROW( Bad_Argument ); + return FAILURE; + } + + range = &exc->codeRangeTable[aRange - 1]; + + if ( !range->base ) /* invalid coderange */ + { + exc->error = FT_THROW( Invalid_CodeRange ); + return FAILURE; + } + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for aIP <= Size, instead of aIP < Size. */ + + if ( aIP > range->size ) + { + exc->error = FT_THROW( Code_Overflow ); + return FAILURE; + } + + exc->code = range->base; + exc->codeSize = range->size; + exc->IP = aIP; + exc->curRange = aRange; + + return SUCCESS; + } + + + /* + * + * Apple's TrueType specification at + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html#order + * + * gives the following order of operations in instructions that move + * points. + * + * - check single width cut-in (MIRP, MDRP) + * + * - check control value cut-in (MIRP, MIAP) + * + * - apply engine compensation (MIRP, MDRP) + * + * - round distance (MIRP, MDRP) or value (MIAP, MDAP) + * + * - check minimum distance (MIRP,MDRP) + * + * - move point (MIRP, MDRP, MIAP, MSIRP, MDAP) + * + * For rounding instructions, engine compensation happens before rounding. + * + */ + + + /************************************************************************** + * + * @Function: + * Direct_Move + * + * @Description: + * Moves a point by a given distance along the freedom vector. The + * point will be `touched'. + * + * @Input: + * point :: + * The index of the point to move. + * + * distance :: + * The distance to apply. + * + * @InOut: + * zone :: + * The affected glyph zone. + * + * @Note: + * See `ttinterp.h' for details on backward compatibility mode. + * `Touches' the point. + */ + static void + Direct_Move( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + + + v = exc->GS.freeVector.x; + + if ( v != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Exception to the post-IUP curfew: Allow the x component of */ + /* diagonal moves, but only post-IUP. DejaVu tries to adjust */ + /* diagonal stems like on `Z' and `z' post-IUP. */ + if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + else +#endif + + if ( NO_SUBPIXEL_HINTING ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + v = exc->GS.freeVector.y; + + if ( v != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) ) +#endif + zone->cur[point].y = ADD_LONG( zone->cur[point].y, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } + + + /************************************************************************** + * + * @Function: + * Direct_Move_Orig + * + * @Description: + * Moves the *original* position of a point by a given distance along + * the freedom vector. Obviously, the point will not be `touched'. + * + * @Input: + * point :: + * The index of the point to move. + * + * distance :: + * The distance to apply. + * + * @InOut: + * zone :: + * The affected glyph zone. + */ + static void + Direct_Move_Orig( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + + + v = exc->GS.freeVector.x; + + if ( v != 0 ) + zone->org[point].x = ADD_LONG( zone->org[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + + v = exc->GS.freeVector.y; + + if ( v != 0 ) + zone->org[point].y = ADD_LONG( zone->org[point].y, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + } + + + /************************************************************************** + * + * Special versions of Direct_Move() + * + * The following versions are used whenever both vectors are both + * along one of the coordinate unit vectors, i.e. in 90% of the cases. + * See `ttinterp.h' for details on backward compatibility mode. + * + */ + + + static void + Direct_Move_X( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); + else +#endif + + if ( NO_SUBPIXEL_HINTING ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + + static void + Direct_Move_Y( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED( exc ); + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && exc->iupy_called ) ) +#endif + zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + + + /************************************************************************** + * + * Special versions of Direct_Move_Orig() + * + * The following versions are used whenever both vectors are both + * along one of the coordinate unit vectors, i.e. in 90% of the cases. + * + */ + + + static void + Direct_Move_Orig_X( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED( exc ); + + zone->org[point].x = ADD_LONG( zone->org[point].x, distance ); + } + + + static void + Direct_Move_Orig_Y( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED( exc ); + + zone->org[point].y = ADD_LONG( zone->org[point].y, distance ); + } + + /************************************************************************** + * + * @Function: + * Round_None + * + * @Description: + * Does not round, but adds engine compensation. + * + * @Input: + * distance :: + * The distance (not) to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * The compensated distance. + */ + static FT_F26Dot6 + Round_None( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ADD_LONG( distance, compensation ); + if ( val < 0 ) + val = 0; + } + else + { + val = SUB_LONG( distance, compensation ); + if ( val > 0 ) + val = 0; + } + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_To_Grid + * + * @Description: + * Rounds value to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_To_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation, + distance ) ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_To_Half_Grid + * + * @Description: + * Rounds value to half grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_To_Half_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ), + 32 ); + if ( val < 0 ) + val = 32; + } + else + { + val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, + distance ) ), + 32 ) ); + if ( val > 0 ) + val = -32; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Down_To_Grid + * + * @Description: + * Rounds value down to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_Down_To_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Up_To_Grid + * + * @Description: + * Rounds value up to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_Up_To_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation, + distance ) ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_To_Double_Grid + * + * @Description: + * Rounds value to double grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_To_Double_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ), + 32 ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Super + * + * @Description: + * Super-rounds value to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + * + * @Note: + * The TrueType specification says very little about the relationship + * between rounding and engine compensation. However, it seems from + * the description of super round that we should add the compensation + * before rounding. + */ + static FT_F26Dot6 + Round_Super( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ADD_LONG( distance, + exc->threshold - exc->phase + compensation ) & + -exc->period; + val = ADD_LONG( val, exc->phase ); + if ( val < 0 ) + val = exc->phase; + } + else + { + val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation, + distance ) & + -exc->period ); + val = SUB_LONG( val, exc->phase ); + if ( val > 0 ) + val = -exc->phase; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Super_45 + * + * @Description: + * Super-rounds value to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + * + * @Note: + * There is a separate function for Round_Super_45() as we may need + * greater precision. + */ + static FT_F26Dot6 + Round_Super_45( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ( ADD_LONG( distance, + exc->threshold - exc->phase + compensation ) / + exc->period ) * exc->period; + val = ADD_LONG( val, exc->phase ); + if ( val < 0 ) + val = exc->phase; + } + else + { + val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation, + distance ) / + exc->period ) * exc->period ); + val = SUB_LONG( val, exc->phase ); + if ( val > 0 ) + val = -exc->phase; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Compute_Round + * + * @Description: + * Sets the rounding mode. + * + * @Input: + * round_mode :: + * The rounding mode to be used. + */ + static void + Compute_Round( TT_ExecContext exc, + FT_Byte round_mode ) + { + switch ( round_mode ) + { + case TT_Round_Off: + exc->func_round = (TT_Round_Func)Round_None; + break; + + case TT_Round_To_Grid: + exc->func_round = (TT_Round_Func)Round_To_Grid; + break; + + case TT_Round_Up_To_Grid: + exc->func_round = (TT_Round_Func)Round_Up_To_Grid; + break; + + case TT_Round_Down_To_Grid: + exc->func_round = (TT_Round_Func)Round_Down_To_Grid; + break; + + case TT_Round_To_Half_Grid: + exc->func_round = (TT_Round_Func)Round_To_Half_Grid; + break; + + case TT_Round_To_Double_Grid: + exc->func_round = (TT_Round_Func)Round_To_Double_Grid; + break; + + case TT_Round_Super: + exc->func_round = (TT_Round_Func)Round_Super; + break; + + case TT_Round_Super_45: + exc->func_round = (TT_Round_Func)Round_Super_45; + break; + } + } + + + /************************************************************************** + * + * @Function: + * SetSuperRound + * + * @Description: + * Sets Super Round parameters. + * + * @Input: + * GridPeriod :: + * The grid period. + * + * selector :: + * The SROUND opcode. + */ + static void + SetSuperRound( TT_ExecContext exc, + FT_F2Dot14 GridPeriod, + FT_Long selector ) + { + switch ( (FT_Int)( selector & 0xC0 ) ) + { + case 0: + exc->period = GridPeriod / 2; + break; + + case 0x40: + exc->period = GridPeriod; + break; + + case 0x80: + exc->period = GridPeriod * 2; + break; + + /* This opcode is reserved, but... */ + case 0xC0: + exc->period = GridPeriod; + break; + } + + switch ( (FT_Int)( selector & 0x30 ) ) + { + case 0: + exc->phase = 0; + break; + + case 0x10: + exc->phase = exc->period / 4; + break; + + case 0x20: + exc->phase = exc->period / 2; + break; + + case 0x30: + exc->phase = exc->period * 3 / 4; + break; + } + + if ( ( selector & 0x0F ) == 0 ) + exc->threshold = exc->period - 1; + else + exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8; + + /* convert to F26Dot6 format */ + exc->period >>= 8; + exc->phase >>= 8; + exc->threshold >>= 8; + } + + + /************************************************************************** + * + * @Function: + * Project + * + * @Description: + * Computes the projection of vector given by (v2-v1) along the + * current projection vector. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Project( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + return TT_DotFix14( dx, dy, + exc->GS.projVector.x, + exc->GS.projVector.y ); + } + + + /************************************************************************** + * + * @Function: + * Dual_Project + * + * @Description: + * Computes the projection of the vector given by (v2-v1) along the + * current dual vector. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Dual_Project( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + return TT_DotFix14( dx, dy, + exc->GS.dualVector.x, + exc->GS.dualVector.y ); + } + + + /************************************************************************** + * + * @Function: + * Project_x + * + * @Description: + * Computes the projection of the vector given by (v2-v1) along the + * horizontal axis. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Project_x( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED( exc ); + FT_UNUSED( dy ); + + return dx; + } + + + /************************************************************************** + * + * @Function: + * Project_y + * + * @Description: + * Computes the projection of the vector given by (v2-v1) along the + * vertical axis. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Project_y( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED( exc ); + FT_UNUSED( dx ); + + return dy; + } + + + /************************************************************************** + * + * @Function: + * Compute_Funcs + * + * @Description: + * Computes the projection and movement function pointers according + * to the current graphics state. + */ + static void + Compute_Funcs( TT_ExecContext exc ) + { + if ( exc->GS.freeVector.x == 0x4000 ) + exc->F_dot_P = exc->GS.projVector.x; + else if ( exc->GS.freeVector.y == 0x4000 ) + exc->F_dot_P = exc->GS.projVector.y; + else + exc->F_dot_P = + ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x + + (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14; + + if ( exc->GS.projVector.x == 0x4000 ) + exc->func_project = (TT_Project_Func)Project_x; + else if ( exc->GS.projVector.y == 0x4000 ) + exc->func_project = (TT_Project_Func)Project_y; + else + exc->func_project = (TT_Project_Func)Project; + + if ( exc->GS.dualVector.x == 0x4000 ) + exc->func_dualproj = (TT_Project_Func)Project_x; + else if ( exc->GS.dualVector.y == 0x4000 ) + exc->func_dualproj = (TT_Project_Func)Project_y; + else + exc->func_dualproj = (TT_Project_Func)Dual_Project; + + exc->func_move = (TT_Move_Func)Direct_Move; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig; + + if ( exc->F_dot_P == 0x4000L ) + { + if ( exc->GS.freeVector.x == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_X; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; + } + else if ( exc->GS.freeVector.y == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_Y; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y; + } + } + + /* at small sizes, F_dot_P can become too small, resulting */ + /* in overflows and `spikes' in a number of glyphs like `w'. */ + + if ( FT_ABS( exc->F_dot_P ) < 0x400L ) + exc->F_dot_P = 0x4000L; + + /* Disable cached aspect ratio */ + exc->tt_metrics.ratio = 0; + } + + + /************************************************************************** + * + * @Function: + * Normalize + * + * @Description: + * Norms a vector. + * + * @Input: + * Vx :: + * The horizontal input vector coordinate. + * Vy :: + * The vertical input vector coordinate. + * + * @Output: + * R :: + * The normed unit vector. + * + * @Return: + * Returns FAILURE if a vector parameter is zero. + * + * @Note: + * In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and + * R is undefined. + */ + static FT_Bool + Normalize( FT_F26Dot6 Vx, + FT_F26Dot6 Vy, + FT_UnitVector* R ) + { + FT_Vector V; + + + if ( Vx == 0 && Vy == 0 ) + { + /* XXX: UNDOCUMENTED! It seems that it is possible to try */ + /* to normalize the vector (0,0). Return immediately. */ + return SUCCESS; + } + + V.x = Vx; + V.y = Vy; + + FT_Vector_NormLen( &V ); + + R->x = (FT_F2Dot14)( V.x / 4 ); + R->y = (FT_F2Dot14)( V.y / 4 ); + + return SUCCESS; + } + + + /************************************************************************** + * + * Here we start with the implementation of the various opcodes. + * + */ + + +#define ARRAY_BOUND_ERROR \ + do \ + { \ + exc->error = FT_THROW( Invalid_Reference ); \ + return; \ + } while (0) + + + /************************************************************************** + * + * MPPEM[]: Measure Pixel Per EM + * Opcode range: 0x4B + * Stack: --> Euint16 + */ + static void + Ins_MPPEM( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->func_cur_ppem( exc ); + } + + + /************************************************************************** + * + * MPS[]: Measure Point Size + * Opcode range: 0x4C + * Stack: --> Euint16 + */ + static void + Ins_MPS( TT_ExecContext exc, + FT_Long* args ) + { + if ( NO_SUBPIXEL_HINTING ) + { + /* Microsoft's GDI bytecode interpreter always returns value 12; */ + /* we return the current PPEM value instead. */ + args[0] = exc->func_cur_ppem( exc ); + } + else + { + /* A possible practical application of the MPS instruction is to */ + /* implement optical scaling and similar features, which should be */ + /* based on perceptual attributes, thus independent of the */ + /* resolution. */ + args[0] = exc->pointSize; + } + } + + + /************************************************************************** + * + * DUP[]: DUPlicate the stack's top element + * Opcode range: 0x20 + * Stack: StkElt --> StkElt StkElt + */ + static void + Ins_DUP( FT_Long* args ) + { + args[1] = args[0]; + } + + + /************************************************************************** + * + * POP[]: POP the stack's top element + * Opcode range: 0x21 + * Stack: StkElt --> + */ + static void + Ins_POP( void ) + { + /* nothing to do */ + } + + + /************************************************************************** + * + * CLEAR[]: CLEAR the entire stack + * Opcode range: 0x22 + * Stack: StkElt... --> + */ + static void + Ins_CLEAR( TT_ExecContext exc ) + { + exc->new_top = 0; + } + + + /************************************************************************** + * + * SWAP[]: SWAP the stack's top two elements + * Opcode range: 0x23 + * Stack: 2 * StkElt --> 2 * StkElt + */ + static void + Ins_SWAP( FT_Long* args ) + { + FT_Long L; + + + L = args[0]; + args[0] = args[1]; + args[1] = L; + } + + + /************************************************************************** + * + * DEPTH[]: return the stack DEPTH + * Opcode range: 0x24 + * Stack: --> uint32 + */ + static void + Ins_DEPTH( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->top; + } + + + /************************************************************************** + * + * LT[]: Less Than + * Opcode range: 0x50 + * Stack: int32? int32? --> bool + */ + static void + Ins_LT( FT_Long* args ) + { + args[0] = ( args[0] < args[1] ); + } + + + /************************************************************************** + * + * LTEQ[]: Less Than or EQual + * Opcode range: 0x51 + * Stack: int32? int32? --> bool + */ + static void + Ins_LTEQ( FT_Long* args ) + { + args[0] = ( args[0] <= args[1] ); + } + + + /************************************************************************** + * + * GT[]: Greater Than + * Opcode range: 0x52 + * Stack: int32? int32? --> bool + */ + static void + Ins_GT( FT_Long* args ) + { + args[0] = ( args[0] > args[1] ); + } + + + /************************************************************************** + * + * GTEQ[]: Greater Than or EQual + * Opcode range: 0x53 + * Stack: int32? int32? --> bool + */ + static void + Ins_GTEQ( FT_Long* args ) + { + args[0] = ( args[0] >= args[1] ); + } + + + /************************************************************************** + * + * EQ[]: EQual + * Opcode range: 0x54 + * Stack: StkElt StkElt --> bool + */ + static void + Ins_EQ( FT_Long* args ) + { + args[0] = ( args[0] == args[1] ); + } + + + /************************************************************************** + * + * NEQ[]: Not EQual + * Opcode range: 0x55 + * Stack: StkElt StkElt --> bool + */ + static void + Ins_NEQ( FT_Long* args ) + { + args[0] = ( args[0] != args[1] ); + } + + + /************************************************************************** + * + * ODD[]: Is ODD + * Opcode range: 0x56 + * Stack: f26.6 --> bool + */ + static void + Ins_ODD( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 64 ); + } + + + /************************************************************************** + * + * EVEN[]: Is EVEN + * Opcode range: 0x57 + * Stack: f26.6 --> bool + */ + static void + Ins_EVEN( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 0 ); + } + + + /************************************************************************** + * + * AND[]: logical AND + * Opcode range: 0x5A + * Stack: uint32 uint32 --> uint32 + */ + static void + Ins_AND( FT_Long* args ) + { + args[0] = ( args[0] && args[1] ); + } + + + /************************************************************************** + * + * OR[]: logical OR + * Opcode range: 0x5B + * Stack: uint32 uint32 --> uint32 + */ + static void + Ins_OR( FT_Long* args ) + { + args[0] = ( args[0] || args[1] ); + } + + + /************************************************************************** + * + * NOT[]: logical NOT + * Opcode range: 0x5C + * Stack: StkElt --> uint32 + */ + static void + Ins_NOT( FT_Long* args ) + { + args[0] = !args[0]; + } + + + /************************************************************************** + * + * ADD[]: ADD + * Opcode range: 0x60 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_ADD( FT_Long* args ) + { + args[0] = ADD_LONG( args[0], args[1] ); + } + + + /************************************************************************** + * + * SUB[]: SUBtract + * Opcode range: 0x61 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_SUB( FT_Long* args ) + { + args[0] = SUB_LONG( args[0], args[1] ); + } + + + /************************************************************************** + * + * DIV[]: DIVide + * Opcode range: 0x62 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_DIV( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[1] == 0 ) + exc->error = FT_THROW( Divide_By_Zero ); + else + args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] ); + } + + + /************************************************************************** + * + * MUL[]: MULtiply + * Opcode range: 0x63 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_MUL( FT_Long* args ) + { + args[0] = FT_MulDiv( args[0], args[1], 64L ); + } + + + /************************************************************************** + * + * ABS[]: ABSolute value + * Opcode range: 0x64 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_ABS( FT_Long* args ) + { + if ( args[0] < 0 ) + args[0] = NEG_LONG( args[0] ); + } + + + /************************************************************************** + * + * NEG[]: NEGate + * Opcode range: 0x65 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_NEG( FT_Long* args ) + { + args[0] = NEG_LONG( args[0] ); + } + + + /************************************************************************** + * + * FLOOR[]: FLOOR + * Opcode range: 0x66 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_FLOOR( FT_Long* args ) + { + args[0] = FT_PIX_FLOOR( args[0] ); + } + + + /************************************************************************** + * + * CEILING[]: CEILING + * Opcode range: 0x67 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_CEILING( FT_Long* args ) + { + args[0] = FT_PIX_CEIL_LONG( args[0] ); + } + + + /************************************************************************** + * + * RS[]: Read Store + * Opcode range: 0x43 + * Stack: uint32 --> uint32 + */ + static void + Ins_RS( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->storeSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + else + args[0] = 0; + } + else + args[0] = exc->storage[I]; + } + + + /************************************************************************** + * + * WS[]: Write Store + * Opcode range: 0x42 + * Stack: uint32 uint32 --> + */ + static void + Ins_WS( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->storeSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + { + if ( exc->iniRange == tt_coderange_glyph && + exc->storage != exc->glyfStorage ) + { + FT_Memory memory = exc->memory; + FT_Error error; + + + FT_MEM_QRENEW_ARRAY( exc->glyfStorage, + exc->glyfStoreSize, + exc->storeSize ); + exc->error = error; + if ( error ) + return; + + exc->glyfStoreSize = exc->storeSize; + FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize ); + exc->storage = exc->glyfStorage; + } + + exc->storage[I] = args[1]; + } + } + + + /************************************************************************** + * + * WCVTP[]: Write CVT in Pixel units + * Opcode range: 0x44 + * Stack: f26.6 uint32 --> + */ + static void + Ins_WCVTP( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + exc->func_write_cvt( exc, I, args[1] ); + } + + + /************************************************************************** + * + * WCVTF[]: Write CVT in Funits + * Opcode range: 0x70 + * Stack: uint32 uint32 --> + */ + static void + Ins_WCVTF( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale ); + } + + + /************************************************************************** + * + * RCVT[]: Read CVT + * Opcode range: 0x45 + * Stack: uint32 --> f26.6 + */ + static void + Ins_RCVT( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + else + args[0] = 0; + } + else + args[0] = exc->func_read_cvt( exc, I ); + } + + + /************************************************************************** + * + * AA[]: Adjust Angle + * Opcode range: 0x7F + * Stack: uint32 --> + */ + static void + Ins_AA( void ) + { + /* intentionally no longer supported */ + } + + + /************************************************************************** + * + * DEBUG[]: DEBUG. Unsupported. + * Opcode range: 0x4F + * Stack: uint32 --> + * + * Note: The original instruction pops a value from the stack. + */ + static void + Ins_DEBUG( TT_ExecContext exc ) + { + exc->error = FT_THROW( Debug_OpCode ); + } + + + /************************************************************************** + * + * ROUND[ab]: ROUND value + * Opcode range: 0x68-0x6B + * Stack: f26.6 --> f26.6 + */ + static void + Ins_ROUND( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->func_round( exc, args[0], exc->opcode & 3 ); + } + + + /************************************************************************** + * + * NROUND[ab]: No ROUNDing of value + * Opcode range: 0x6C-0x6F + * Stack: f26.6 --> f26.6 + */ + static void + Ins_NROUND( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = Round_None( exc, args[0], exc->opcode & 3 ); + } + + + /************************************************************************** + * + * MAX[]: MAXimum + * Opcode range: 0x8B + * Stack: int32? int32? --> int32 + */ + static void + Ins_MAX( FT_Long* args ) + { + if ( args[1] > args[0] ) + args[0] = args[1]; + } + + + /************************************************************************** + * + * MIN[]: MINimum + * Opcode range: 0x8C + * Stack: int32? int32? --> int32 + */ + static void + Ins_MIN( FT_Long* args ) + { + if ( args[1] < args[0] ) + args[0] = args[1]; + } + + + /************************************************************************** + * + * MINDEX[]: Move INDEXed element + * Opcode range: 0x26 + * Stack: int32? --> StkElt + */ + static void + Ins_MINDEX( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long L, K; + + + L = args[0]; + + if ( L <= 0 || L > exc->args ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + } + else + { + K = exc->stack[exc->args - L]; + + FT_ARRAY_MOVE( &exc->stack[exc->args - L ], + &exc->stack[exc->args - L + 1], + ( L - 1 ) ); + + exc->stack[exc->args - 1] = K; + } + } + + + /************************************************************************** + * + * CINDEX[]: Copy INDEXed element + * Opcode range: 0x25 + * Stack: int32 --> StkElt + */ + static void + Ins_CINDEX( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long L; + + + L = args[0]; + + if ( L <= 0 || L > exc->args ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + args[0] = 0; + } + else + args[0] = exc->stack[exc->args - L]; + } + + + /************************************************************************** + * + * ROLL[]: ROLL top three elements + * Opcode range: 0x8A + * Stack: 3 * StkElt --> 3 * StkElt + */ + static void + Ins_ROLL( FT_Long* args ) + { + FT_Long A, B, C; + + + A = args[2]; + B = args[1]; + C = args[0]; + + args[2] = C; + args[1] = A; + args[0] = B; + } + + + /************************************************************************** + * + * MANAGING THE FLOW OF CONTROL + * + */ + + + /************************************************************************** + * + * SLOOP[]: Set LOOP variable + * Opcode range: 0x17 + * Stack: int32? --> + */ + static void + Ins_SLOOP( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[0] < 0 ) + exc->error = FT_THROW( Bad_Argument ); + else + { + /* we heuristically limit the number of loops to 16 bits */ + exc->GS.loop = args[0] > 0xFFFFL ? 0xFFFFL : args[0]; + } + } + + + static FT_Bool + SkipCode( TT_ExecContext exc ) + { + exc->IP += exc->length; + + if ( exc->IP < exc->codeSize ) + { + exc->opcode = exc->code[exc->IP]; + + exc->length = opcode_length[exc->opcode]; + if ( exc->length < 0 ) + { + if ( exc->IP + 1 >= exc->codeSize ) + goto Fail_Overflow; + exc->length = 2 - exc->length * exc->code[exc->IP + 1]; + } + + if ( exc->IP + exc->length <= exc->codeSize ) + return SUCCESS; + } + + Fail_Overflow: + exc->error = FT_THROW( Code_Overflow ); + return FAILURE; + } + + + /************************************************************************** + * + * IF[]: IF test + * Opcode range: 0x58 + * Stack: StkElt --> + */ + static void + Ins_IF( TT_ExecContext exc, + FT_Long* args ) + { + FT_Int nIfs; + FT_Bool Out; + + + if ( args[0] != 0 ) + return; + + nIfs = 1; + Out = 0; + + do + { + if ( SkipCode( exc ) == FAILURE ) + return; + + switch ( exc->opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x1B: /* ELSE */ + Out = FT_BOOL( nIfs == 1 ); + break; + + case 0x59: /* EIF */ + nIfs--; + Out = FT_BOOL( nIfs == 0 ); + break; + } + } while ( Out == 0 ); + } + + + /************************************************************************** + * + * ELSE[]: ELSE + * Opcode range: 0x1B + * Stack: --> + */ + static void + Ins_ELSE( TT_ExecContext exc ) + { + FT_Int nIfs; + + + nIfs = 1; + + do + { + if ( SkipCode( exc ) == FAILURE ) + return; + + switch ( exc->opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x59: /* EIF */ + nIfs--; + break; + } + } while ( nIfs != 0 ); + } + + + /************************************************************************** + * + * EIF[]: End IF + * Opcode range: 0x59 + * Stack: --> + */ + static void + Ins_EIF( void ) + { + /* nothing to do */ + } + + + /************************************************************************** + * + * JMPR[]: JuMP Relative + * Opcode range: 0x1C + * Stack: int32 --> + */ + static void + Ins_JMPR( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[0] == 0 && exc->args == 0 ) + { + exc->error = FT_THROW( Bad_Argument ); + return; + } + + exc->IP = ADD_LONG( exc->IP, args[0] ); + if ( exc->IP < 0 || + ( exc->callTop > 0 && + exc->IP > exc->callStack[exc->callTop - 1].Def->end ) ) + { + exc->error = FT_THROW( Bad_Argument ); + return; + } + + exc->step_ins = FALSE; + + if ( args[0] < 0 ) + { + if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max ) + exc->error = FT_THROW( Execution_Too_Long ); + } + } + + + /************************************************************************** + * + * JROT[]: Jump Relative On True + * Opcode range: 0x78 + * Stack: StkElt int32 --> + */ + static void + Ins_JROT( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[1] != 0 ) + Ins_JMPR( exc, args ); + } + + + /************************************************************************** + * + * JROF[]: Jump Relative On False + * Opcode range: 0x79 + * Stack: StkElt int32 --> + */ + static void + Ins_JROF( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[1] == 0 ) + Ins_JMPR( exc, args ); + } + + + /************************************************************************** + * + * DEFINING AND USING FUNCTIONS AND INSTRUCTIONS + * + */ + + + /************************************************************************** + * + * FDEF[]: Function DEFinition + * Opcode range: 0x2C + * Stack: uint32 --> + */ + static void + Ins_FDEF( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong n; + TT_DefRecord* rec; + TT_DefRecord* limit; + + + /* FDEF is only allowed in `prep' or `fpgm' */ + if ( exc->iniRange == tt_coderange_glyph ) + { + exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); + return; + } + + /* some font programs are broken enough to redefine functions! */ + /* We will then parse the current table. */ + + rec = exc->FDefs; + limit = FT_OFFSET( rec, exc->numFDefs ); + n = (FT_ULong)args[0]; + + for ( ; rec < limit; rec++ ) + { + if ( rec->opc == n ) + break; + } + + if ( rec == limit ) + { + /* check that there is enough room for new functions */ + if ( exc->numFDefs >= exc->maxFDefs ) + { + exc->error = FT_THROW( Too_Many_Function_Defs ); + return; + } + exc->numFDefs++; + } + + /* Although FDEF takes unsigned 32-bit integer, */ + /* func # must be within unsigned 16-bit integer */ + if ( n > 0xFFFFU ) + { + exc->error = FT_THROW( Too_Many_Function_Defs ); + return; + } + + rec->range = exc->curRange; + rec->opc = (FT_UInt16)n; + rec->start = exc->IP + 1; + rec->active = TRUE; + + if ( n > exc->maxFunc ) + exc->maxFunc = (FT_UInt16)n; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFS & FDEFs. */ + + while ( SkipCode( exc ) == SUCCESS ) + { + switch ( exc->opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + exc->error = FT_THROW( Nested_DEFS ); + return; + + case 0x2D: /* ENDF */ + rec->end = exc->IP; + return; + } + } + } + + + /************************************************************************** + * + * ENDF[]: END Function definition + * Opcode range: 0x2D + * Stack: --> + */ + static void + Ins_ENDF( TT_ExecContext exc ) + { + TT_CallRec* pRec; + + + if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */ + { + exc->error = FT_THROW( ENDF_In_Exec_Stream ); + return; + } + + exc->callTop--; + + pRec = &exc->callStack[exc->callTop]; + + pRec->Cur_Count--; + + exc->step_ins = FALSE; + + if ( pRec->Cur_Count > 0 ) + { + exc->callTop++; + exc->IP = pRec->Def->start; + } + else + /* Loop through the current function */ + Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP ); + + /* Exit the current call frame. */ + + /* NOTE: If the last instruction of a program is a */ + /* CALL or LOOPCALL, the return address is */ + /* always out of the code range. This is a */ + /* valid address, and it is why we do not test */ + /* the result of Ins_Goto_CodeRange() here! */ + } + + + /************************************************************************** + * + * CALL[]: CALL function + * Opcode range: 0x2B + * Stack: uint32? --> + */ + static void + Ins_CALL( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + + F = (FT_ULong)args[0]; + if ( BOUNDSL( F, exc->maxFunc + 1 ) ) + goto Fail; + + if ( !exc->FDefs ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* exc->maxFunc+1 == exc->numFDefs */ + /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = exc->FDefs + F; + if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = exc->FDefs; + limit = def + exc->numFDefs; + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check the call stack */ + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + pCrec = exc->callStack + exc->callTop; + + pCrec->Caller_Range = exc->curRange; + pCrec->Caller_IP = exc->IP + 1; + pCrec->Cur_Count = 1; + pCrec->Def = def; + + exc->callTop++; + + Ins_Goto_CodeRange( exc, def->range, def->start ); + + exc->step_ins = FALSE; + + return; + + Fail: + exc->error = FT_THROW( Invalid_Reference ); + } + + + /************************************************************************** + * + * LOOPCALL[]: LOOP and CALL function + * Opcode range: 0x2A + * Stack: uint32? Eint16? --> + */ + static void + Ins_LOOPCALL( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + F = (FT_ULong)args[1]; + if ( BOUNDSL( F, exc->maxFunc + 1 ) ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* exc->maxFunc+1 == exc->numFDefs */ + /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = FT_OFFSET( exc->FDefs, F ); + if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = exc->FDefs; + limit = FT_OFFSET( def, exc->numFDefs ); + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check stack */ + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + if ( args[0] > 0 ) + { + pCrec = exc->callStack + exc->callTop; + + pCrec->Caller_Range = exc->curRange; + pCrec->Caller_IP = exc->IP + 1; + pCrec->Cur_Count = (FT_Int)args[0]; + pCrec->Def = def; + + exc->callTop++; + + Ins_Goto_CodeRange( exc, def->range, def->start ); + + exc->step_ins = FALSE; + + exc->loopcall_counter += (FT_ULong)args[0]; + if ( exc->loopcall_counter > exc->loopcall_counter_max ) + exc->error = FT_THROW( Execution_Too_Long ); + } + + return; + + Fail: + exc->error = FT_THROW( Invalid_Reference ); + } + + + /************************************************************************** + * + * IDEF[]: Instruction DEFinition + * Opcode range: 0x89 + * Stack: Eint8 --> + */ + static void + Ins_IDEF( TT_ExecContext exc, + FT_Long* args ) + { + TT_DefRecord* def; + TT_DefRecord* limit; + + + /* we enable IDEF only in `prep' or `fpgm' */ + if ( exc->iniRange == tt_coderange_glyph ) + { + exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); + return; + } + + /* First of all, look for the same function in our table */ + + def = exc->IDefs; + limit = FT_OFFSET( def, exc->numIDefs ); + + for ( ; def < limit; def++ ) + if ( def->opc == (FT_ULong)args[0] ) + break; + + if ( def == limit ) + { + /* check that there is enough room for a new instruction */ + if ( exc->numIDefs >= exc->maxIDefs ) + { + exc->error = FT_THROW( Too_Many_Instruction_Defs ); + return; + } + exc->numIDefs++; + } + + /* opcode must be unsigned 8-bit integer */ + if ( 0 > args[0] || args[0] > 0x00FF ) + { + exc->error = FT_THROW( Too_Many_Instruction_Defs ); + return; + } + + def->opc = (FT_Byte)args[0]; + def->start = exc->IP + 1; + def->range = exc->curRange; + def->active = TRUE; + + if ( (FT_ULong)args[0] > exc->maxIns ) + exc->maxIns = (FT_Byte)args[0]; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFs & FDEFs. */ + + while ( SkipCode( exc ) == SUCCESS ) + { + switch ( exc->opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + exc->error = FT_THROW( Nested_DEFS ); + return; + case 0x2D: /* ENDF */ + def->end = exc->IP; + return; + } + } + } + + + /************************************************************************** + * + * PUSHING DATA ONTO THE INTERPRETER STACK + * + */ + + + /************************************************************************** + * + * NPUSHB[]: PUSH N Bytes + * Opcode range: 0x40 + * Stack: --> uint32... + */ + static void + Ins_NPUSHB( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)exc->code[exc->IP + 1]; + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = exc->code[exc->IP + K + 1]; + + exc->new_top += L; + } + + + /************************************************************************** + * + * NPUSHW[]: PUSH N Words + * Opcode range: 0x41 + * Stack: --> int32... + */ + static void + Ins_NPUSHW( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)exc->code[exc->IP + 1]; + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + exc->IP += 2; + + for ( K = 0; K < L; K++ ) + args[K] = GetShortIns( exc ); + + exc->step_ins = FALSE; + exc->new_top += L; + } + + + /************************************************************************** + * + * PUSHB[abc]: PUSH Bytes + * Opcode range: 0xB0-0xB7 + * Stack: --> uint32... + */ + static void + Ins_PUSHB( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)( exc->opcode - 0xB0 + 1 ); + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = exc->code[exc->IP + K]; + } + + + /************************************************************************** + * + * PUSHW[abc]: PUSH Words + * Opcode range: 0xB8-0xBF + * Stack: --> int32... + */ + static void + Ins_PUSHW( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)( exc->opcode - 0xB8 + 1 ); + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + exc->IP++; + + for ( K = 0; K < L; K++ ) + args[K] = GetShortIns( exc ); + + exc->step_ins = FALSE; + } + + + /************************************************************************** + * + * MANAGING THE GRAPHICS STATE + * + */ + + + static FT_Bool + Ins_SxVTL( TT_ExecContext exc, + FT_UShort aIdx1, + FT_UShort aIdx2, + FT_UnitVector* Vec ) + { + FT_Long A, B, C; + FT_Vector* p1; + FT_Vector* p2; + + FT_Byte opcode = exc->opcode; + + + if ( BOUNDS( aIdx1, exc->zp2.n_points ) || + BOUNDS( aIdx2, exc->zp1.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return FAILURE; + } + + p1 = exc->zp1.cur + aIdx2; + p2 = exc->zp2.cur + aIdx1; + + A = SUB_LONG( p1->x, p2->x ); + B = SUB_LONG( p1->y, p2->y ); + + /* If p1 == p2, SPvTL and SFvTL behave the same as */ + /* SPvTCA[X] and SFvTCA[X], respectively. */ + /* */ + /* Confirmed by Greg Hitchcock. */ + + if ( A == 0 && B == 0 ) + { + A = 0x4000; + opcode = 0; + } + + if ( ( opcode & 1 ) != 0 ) + { + C = B; /* counter-clockwise rotation */ + B = A; + A = NEG_LONG( C ); + } + + Normalize( A, B, Vec ); + + return SUCCESS; + } + + + /************************************************************************** + * + * SVTCA[a]: Set (F and P) Vectors to Coordinate Axis + * Opcode range: 0x00-0x01 + * Stack: --> + * + * SPvTCA[a]: Set PVector to Coordinate Axis + * Opcode range: 0x02-0x03 + * Stack: --> + * + * SFvTCA[a]: Set FVector to Coordinate Axis + * Opcode range: 0x04-0x05 + * Stack: --> + */ + static void + Ins_SxyTCA( TT_ExecContext exc ) + { + FT_Short AA, BB; + + FT_Byte opcode = exc->opcode; + + + AA = (FT_Short)( ( opcode & 1 ) << 14 ); + BB = (FT_Short)( AA ^ 0x4000 ); + + if ( opcode < 4 ) + { + exc->GS.projVector.x = AA; + exc->GS.projVector.y = BB; + + exc->GS.dualVector.x = AA; + exc->GS.dualVector.y = BB; + } + + if ( ( opcode & 2 ) == 0 ) + { + exc->GS.freeVector.x = AA; + exc->GS.freeVector.y = BB; + } + + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SPvTL[a]: Set PVector To Line + * Opcode range: 0x06-0x07 + * Stack: uint32 uint32 --> + */ + static void + Ins_SPVTL( TT_ExecContext exc, + FT_Long* args ) + { + if ( Ins_SxVTL( exc, + (FT_UShort)args[1], + (FT_UShort)args[0], + &exc->GS.projVector ) == SUCCESS ) + { + exc->GS.dualVector = exc->GS.projVector; + Compute_Funcs( exc ); + } + } + + + /************************************************************************** + * + * SFvTL[a]: Set FVector To Line + * Opcode range: 0x08-0x09 + * Stack: uint32 uint32 --> + */ + static void + Ins_SFVTL( TT_ExecContext exc, + FT_Long* args ) + { + if ( Ins_SxVTL( exc, + (FT_UShort)args[1], + (FT_UShort)args[0], + &exc->GS.freeVector ) == SUCCESS ) + { + Compute_Funcs( exc ); + } + } + + + /************************************************************************** + * + * SFvTPv[]: Set FVector To PVector + * Opcode range: 0x0E + * Stack: --> + */ + static void + Ins_SFVTPV( TT_ExecContext exc ) + { + exc->GS.freeVector = exc->GS.projVector; + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SPvFS[]: Set PVector From Stack + * Opcode range: 0x0A + * Stack: f2.14 f2.14 --> + */ + static void + Ins_SPVFS( TT_ExecContext exc, + FT_Long* args ) + { + FT_Short S; + FT_Long X, Y; + + + /* Only use low 16bits, then sign extend */ + S = (FT_Short)args[1]; + Y = (FT_Long)S; + S = (FT_Short)args[0]; + X = (FT_Long)S; + + Normalize( X, Y, &exc->GS.projVector ); + + exc->GS.dualVector = exc->GS.projVector; + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SFvFS[]: Set FVector From Stack + * Opcode range: 0x0B + * Stack: f2.14 f2.14 --> + */ + static void + Ins_SFVFS( TT_ExecContext exc, + FT_Long* args ) + { + FT_Short S; + FT_Long X, Y; + + + /* Only use low 16bits, then sign extend */ + S = (FT_Short)args[1]; + Y = (FT_Long)S; + S = (FT_Short)args[0]; + X = S; + + Normalize( X, Y, &exc->GS.freeVector ); + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * GPv[]: Get Projection Vector + * Opcode range: 0x0C + * Stack: ef2.14 --> ef2.14 + */ + static void + Ins_GPV( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->GS.projVector.x; + args[1] = exc->GS.projVector.y; + } + + + /************************************************************************** + * + * GFv[]: Get Freedom Vector + * Opcode range: 0x0D + * Stack: ef2.14 --> ef2.14 + */ + static void + Ins_GFV( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->GS.freeVector.x; + args[1] = exc->GS.freeVector.y; + } + + + /************************************************************************** + * + * SRP0[]: Set Reference Point 0 + * Opcode range: 0x10 + * Stack: uint32 --> + */ + static void + Ins_SRP0( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp0 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SRP1[]: Set Reference Point 1 + * Opcode range: 0x11 + * Stack: uint32 --> + */ + static void + Ins_SRP1( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp1 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SRP2[]: Set Reference Point 2 + * Opcode range: 0x12 + * Stack: uint32 --> + */ + static void + Ins_SRP2( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp2 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SMD[]: Set Minimum Distance + * Opcode range: 0x1A + * Stack: f26.6 --> + */ + static void + Ins_SMD( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.minimum_distance = args[0]; + } + + + /************************************************************************** + * + * SCVTCI[]: Set Control Value Table Cut In + * Opcode range: 0x1D + * Stack: f26.6 --> + */ + static void + Ins_SCVTCI( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.control_value_cutin = (FT_F26Dot6)args[0]; + } + + + /************************************************************************** + * + * SSWCI[]: Set Single Width Cut In + * Opcode range: 0x1E + * Stack: f26.6 --> + */ + static void + Ins_SSWCI( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.single_width_cutin = (FT_F26Dot6)args[0]; + } + + + /************************************************************************** + * + * SSW[]: Set Single Width + * Opcode range: 0x1F + * Stack: int32? --> + */ + static void + Ins_SSW( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.single_width_value = FT_MulFix( args[0], + exc->tt_metrics.scale ); + } + + + /************************************************************************** + * + * FLIPON[]: Set auto-FLIP to ON + * Opcode range: 0x4D + * Stack: --> + */ + static void + Ins_FLIPON( TT_ExecContext exc ) + { + exc->GS.auto_flip = TRUE; + } + + + /************************************************************************** + * + * FLIPOFF[]: Set auto-FLIP to OFF + * Opcode range: 0x4E + * Stack: --> + */ + static void + Ins_FLIPOFF( TT_ExecContext exc ) + { + exc->GS.auto_flip = FALSE; + } + + + /************************************************************************** + * + * SANGW[]: Set ANGle Weight + * Opcode range: 0x7E + * Stack: uint32 --> + */ + static void + Ins_SANGW( void ) + { + /* instruction not supported anymore */ + } + + + /************************************************************************** + * + * SDB[]: Set Delta Base + * Opcode range: 0x5E + * Stack: uint32 --> + */ + static void + Ins_SDB( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.delta_base = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SDS[]: Set Delta Shift + * Opcode range: 0x5F + * Stack: uint32 --> + */ + static void + Ins_SDS( TT_ExecContext exc, + FT_Long* args ) + { + if ( (FT_ULong)args[0] > 6UL ) + exc->error = FT_THROW( Bad_Argument ); + else + exc->GS.delta_shift = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * RTHG[]: Round To Half Grid + * Opcode range: 0x19 + * Stack: --> + */ + static void + Ins_RTHG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Half_Grid; + exc->func_round = (TT_Round_Func)Round_To_Half_Grid; + } + + + /************************************************************************** + * + * RTG[]: Round To Grid + * Opcode range: 0x18 + * Stack: --> + */ + static void + Ins_RTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Grid; + exc->func_round = (TT_Round_Func)Round_To_Grid; + } + + + /************************************************************************** + * RTDG[]: Round To Double Grid + * Opcode range: 0x3D + * Stack: --> + */ + static void + Ins_RTDG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Double_Grid; + exc->func_round = (TT_Round_Func)Round_To_Double_Grid; + } + + + /************************************************************************** + * RUTG[]: Round Up To Grid + * Opcode range: 0x7C + * Stack: --> + */ + static void + Ins_RUTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Up_To_Grid; + exc->func_round = (TT_Round_Func)Round_Up_To_Grid; + } + + + /************************************************************************** + * + * RDTG[]: Round Down To Grid + * Opcode range: 0x7D + * Stack: --> + */ + static void + Ins_RDTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Down_To_Grid; + exc->func_round = (TT_Round_Func)Round_Down_To_Grid; + } + + + /************************************************************************** + * + * ROFF[]: Round OFF + * Opcode range: 0x7A + * Stack: --> + */ + static void + Ins_ROFF( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Off; + exc->func_round = (TT_Round_Func)Round_None; + } + + + /************************************************************************** + * + * SROUND[]: Super ROUND + * Opcode range: 0x76 + * Stack: Eint8 --> + */ + static void + Ins_SROUND( TT_ExecContext exc, + FT_Long* args ) + { + SetSuperRound( exc, 0x4000, args[0] ); + + exc->GS.round_state = TT_Round_Super; + exc->func_round = (TT_Round_Func)Round_Super; + } + + + /************************************************************************** + * + * S45ROUND[]: Super ROUND 45 degrees + * Opcode range: 0x77 + * Stack: uint32 --> + */ + static void + Ins_S45ROUND( TT_ExecContext exc, + FT_Long* args ) + { + SetSuperRound( exc, 0x2D41, args[0] ); + + exc->GS.round_state = TT_Round_Super_45; + exc->func_round = (TT_Round_Func)Round_Super_45; + } + + + /************************************************************************** + * + * GC[a]: Get Coordinate projected onto + * Opcode range: 0x46-0x47 + * Stack: uint32 --> f26.6 + * + * XXX: UNDOCUMENTED: Measures from the original glyph must be taken + * along the dual projection vector! + */ + static void + Ins_GC( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong L; + FT_F26Dot6 R; + + + L = (FT_ULong)args[0]; + + if ( BOUNDSL( L, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + R = 0; + } + else + { + if ( exc->opcode & 1 ) + R = FAST_DUALPROJ( &exc->zp2.org[L] ); + else + R = FAST_PROJECT( &exc->zp2.cur[L] ); + } + + args[0] = R; + } + + + /************************************************************************** + * + * SCFS[]: Set Coordinate From Stack + * Opcode range: 0x48 + * Stack: f26.6 uint32 --> + * + * Formula: + * + * OA := OA + ( value - OA.p )/( f.p ) * f + */ + static void + Ins_SCFS( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long K; + FT_UShort L; + + + L = (FT_UShort)args[0]; + + if ( BOUNDS( L, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + K = FAST_PROJECT( &exc->zp2.cur[L] ); + + exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) ); + + /* UNDOCUMENTED! The MS rasterizer does that with */ + /* twilight points (confirmed by Greg Hitchcock) */ + if ( exc->GS.gep2 == 0 ) + exc->zp2.org[L] = exc->zp2.cur[L]; + } + + + /************************************************************************** + * + * MD[a]: Measure Distance + * Opcode range: 0x49-0x4A + * Stack: uint32 uint32 --> f26.6 + * + * XXX: UNDOCUMENTED: Measure taken in the original glyph must be along + * the dual projection vector. + * + * XXX: UNDOCUMENTED: Flag attributes are inverted! + * 0 => measure distance in original outline + * 1 => measure distance in grid-fitted outline + * + * XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! + */ + static void + Ins_MD( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort K, L; + FT_F26Dot6 D; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( L, exc->zp0.n_points ) || + BOUNDS( K, exc->zp1.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + D = 0; + } + else + { + if ( exc->opcode & 1 ) + D = PROJECT( exc->zp0.cur + L, exc->zp1.cur + K ); + else + { + /* XXX: UNDOCUMENTED: twilight zone special case */ + + if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 ) + { + FT_Vector* vec1 = exc->zp0.org + L; + FT_Vector* vec2 = exc->zp1.org + K; + + + D = DUALPROJ( vec1, vec2 ); + } + else + { + FT_Vector* vec1 = exc->zp0.orus + L; + FT_Vector* vec2 = exc->zp1.orus + K; + + + if ( exc->metrics.x_scale == exc->metrics.y_scale ) + { + /* this should be faster */ + D = DUALPROJ( vec1, vec2 ); + D = FT_MulFix( D, exc->metrics.x_scale ); + } + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( vec1->x - vec2->x, exc->metrics.x_scale ); + vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale ); + + D = FAST_DUALPROJ( &vec ); + } + } + } + } + + args[0] = D; + } + + + /************************************************************************** + * + * SDPvTL[a]: Set Dual PVector to Line + * Opcode range: 0x86-0x87 + * Stack: uint32 uint32 --> + */ + static void + Ins_SDPVTL( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long A, B, C; + FT_UShort p1, p2; /* was FT_Int in pas type ERROR */ + + FT_Byte opcode = exc->opcode; + + + p1 = (FT_UShort)args[1]; + p2 = (FT_UShort)args[0]; + + if ( BOUNDS( p2, exc->zp1.n_points ) || + BOUNDS( p1, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + { + FT_Vector* v1 = exc->zp1.org + p2; + FT_Vector* v2 = exc->zp2.org + p1; + + + A = SUB_LONG( v1->x, v2->x ); + B = SUB_LONG( v1->y, v2->y ); + + /* If v1 == v2, SDPvTL behaves the same as */ + /* SVTCA[X], respectively. */ + /* */ + /* Confirmed by Greg Hitchcock. */ + + if ( A == 0 && B == 0 ) + { + A = 0x4000; + opcode = 0; + } + } + + if ( ( opcode & 1 ) != 0 ) + { + C = B; /* counter-clockwise rotation */ + B = A; + A = NEG_LONG( C ); + } + + Normalize( A, B, &exc->GS.dualVector ); + + { + FT_Vector* v1 = exc->zp1.cur + p2; + FT_Vector* v2 = exc->zp2.cur + p1; + + + A = SUB_LONG( v1->x, v2->x ); + B = SUB_LONG( v1->y, v2->y ); + + if ( A == 0 && B == 0 ) + { + A = 0x4000; + opcode = 0; + } + } + + if ( ( opcode & 1 ) != 0 ) + { + C = B; /* counter-clockwise rotation */ + B = A; + A = NEG_LONG( C ); + } + + Normalize( A, B, &exc->GS.projVector ); + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SZP0[]: Set Zone Pointer 0 + * Opcode range: 0x13 + * Stack: uint32 --> + */ + static void + Ins_SZP0( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp0 = exc->twilight; + break; + + case 1: + exc->zp0 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->GS.gep0 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SZP1[]: Set Zone Pointer 1 + * Opcode range: 0x14 + * Stack: uint32 --> + */ + static void + Ins_SZP1( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp1 = exc->twilight; + break; + + case 1: + exc->zp1 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->GS.gep1 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SZP2[]: Set Zone Pointer 2 + * Opcode range: 0x15 + * Stack: uint32 --> + */ + static void + Ins_SZP2( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp2 = exc->twilight; + break; + + case 1: + exc->zp2 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->GS.gep2 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SZPS[]: Set Zone PointerS + * Opcode range: 0x16 + * Stack: uint32 --> + */ + static void + Ins_SZPS( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp0 = exc->twilight; + break; + + case 1: + exc->zp0 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->zp1 = exc->zp0; + exc->zp2 = exc->zp0; + + exc->GS.gep0 = (FT_UShort)args[0]; + exc->GS.gep1 = (FT_UShort)args[0]; + exc->GS.gep2 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * INSTCTRL[]: INSTruction ConTRoL + * Opcode range: 0x8E + * Stack: int32 int32 --> + */ + static void + Ins_INSTCTRL( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong K, L, Kf; + + + K = (FT_ULong)args[1]; + L = (FT_ULong)args[0]; + + /* selector values cannot be `OR'ed; */ + /* they are indices starting with index 1, not flags */ + if ( K < 1 || K > 3 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + /* convert index to flag value */ + Kf = 1 << ( K - 1 ); + + if ( L != 0 ) + { + /* arguments to selectors look like flag values */ + if ( L != Kf ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + + /* INSTCTRL should only be used in the CVT program */ + if ( exc->iniRange == tt_coderange_cvt ) + { + exc->GS.instruct_control &= ~(FT_Byte)Kf; + exc->GS.instruct_control |= (FT_Byte)L; + } + + /* except to change the subpixel flags temporarily */ + else if ( exc->iniRange == tt_coderange_glyph && K == 3 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Native ClearType fonts sign a waiver that turns off all backward */ + /* compatibility hacks and lets them program points to the grid like */ + /* it's 1996. They might sign a waiver for just one glyph, though. */ + if ( SUBPIXEL_HINTING_MINIMAL ) + exc->backward_compatibility = !FT_BOOL( L == 4 ); +#endif + } + else if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + } + + + /************************************************************************** + * + * SCANCTRL[]: SCAN ConTRoL + * Opcode range: 0x85 + * Stack: uint32? --> + */ + static void + Ins_SCANCTRL( TT_ExecContext exc, + FT_Long* args ) + { + FT_Int A; + + + /* Get Threshold */ + A = (FT_Int)( args[0] & 0xFF ); + + if ( A == 0xFF ) + { + exc->GS.scan_control = TRUE; + return; + } + else if ( A == 0 ) + { + exc->GS.scan_control = FALSE; + return; + } + + if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A ) + exc->GS.scan_control = TRUE; + + if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated ) + exc->GS.scan_control = TRUE; + + if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched ) + exc->GS.scan_control = TRUE; + + if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A ) + exc->GS.scan_control = FALSE; + + if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated ) + exc->GS.scan_control = FALSE; + + if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched ) + exc->GS.scan_control = FALSE; + } + + + /************************************************************************** + * + * SCANTYPE[]: SCAN TYPE + * Opcode range: 0x8D + * Stack: uint16 --> + */ + static void + Ins_SCANTYPE( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[0] >= 0 ) + exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF; + } + + + /************************************************************************** + * + * MANAGING OUTLINES + * + */ + + + /************************************************************************** + * + * FLIPPT[]: FLIP PoinT + * Opcode range: 0x80 + * Stack: uint32... --> + */ + static void + Ins_FLIPPT( TT_ExecContext exc ) + { + FT_UShort point; + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + goto Fail; +#endif + + if ( exc->top < exc->GS.loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + goto Fail; + } + + while ( exc->GS.loop > 0 ) + { + exc->args--; + + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->pts.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + exc->pts.tags[point] ^= FT_CURVE_TAG_ON; + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * FLIPRGON[]: FLIP RanGe ON + * Opcode range: 0x81 + * Stack: uint32 uint32 --> + */ + static void + Ins_FLIPRGON( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort I, K, L; + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + return; +#endif + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, exc->pts.n_points ) || + BOUNDS( L, exc->pts.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + for ( I = L; I <= K; I++ ) + exc->pts.tags[I] |= FT_CURVE_TAG_ON; + } + + + /************************************************************************** + * + * FLIPRGOFF: FLIP RanGe OFF + * Opcode range: 0x82 + * Stack: uint32 uint32 --> + */ + static void + Ins_FLIPRGOFF( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort I, K, L; + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + return; +#endif + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, exc->pts.n_points ) || + BOUNDS( L, exc->pts.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + for ( I = L; I <= K; I++ ) + exc->pts.tags[I] &= ~FT_CURVE_TAG_ON; + } + + + static FT_Bool + Compute_Point_Displacement( TT_ExecContext exc, + FT_F26Dot6* x, + FT_F26Dot6* y, + TT_GlyphZone zone, + FT_UShort* refp ) + { + TT_GlyphZoneRec zp; + FT_UShort p; + FT_F26Dot6 d; + + + if ( exc->opcode & 1 ) + { + zp = exc->zp0; + p = exc->GS.rp1; + } + else + { + zp = exc->zp1; + p = exc->GS.rp2; + } + + if ( BOUNDS( p, zp.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + *refp = 0; + return FAILURE; + } + + *zone = zp; + *refp = p; + + d = PROJECT( zp.cur + p, zp.org + p ); + + *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P ); + *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P ); + + return SUCCESS; + } + + + /* See `ttinterp.h' for details on backward compatibility mode. */ + static void + Move_Zp2_Point( TT_ExecContext exc, + FT_UShort point, + FT_F26Dot6 dx, + FT_F26Dot6 dy, + FT_Bool touch ) + { + if ( exc->GS.freeVector.x != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) ) +#endif + exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx ); + + if ( touch ) + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + if ( exc->GS.freeVector.y != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) ) +#endif + exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy ); + + if ( touch ) + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } + + + /************************************************************************** + * + * SHP[a]: SHift Point by the last point + * Opcode range: 0x32-0x33 + * Stack: uint32... --> + */ + static void + Ins_SHP( TT_ExecContext exc ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + + FT_F26Dot6 dx, dy; + FT_UShort point; + + + if ( exc->top < exc->GS.loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + return; + + while ( exc->GS.loop > 0 ) + { + exc->args--; + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + Move_Zp2_Point( exc, point, dx, dy, TRUE ); + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * SHC[a]: SHift Contour + * Opcode range: 0x34-35 + * Stack: uint32 --> + * + * UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) + * contour in the twilight zone, namely contour number + * zero which includes all points of it. + */ + static void + Ins_SHC( TT_ExecContext exc, + FT_Long* args ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, dy; + + FT_Short contour, bounds; + FT_UShort start, limit, i; + + + contour = (FT_Short)args[0]; + bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours; + + if ( BOUNDS( contour, bounds ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + return; + + if ( contour == 0 ) + start = 0; + else + start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 - + exc->zp2.first_point ); + + /* we use the number of points if in the twilight zone */ + if ( exc->GS.gep2 == 0 ) + limit = exc->zp2.n_points; + else + limit = (FT_UShort)( exc->zp2.contours[contour] - + exc->zp2.first_point + 1 ); + + for ( i = start; i < limit; i++ ) + { + if ( zp.cur != exc->zp2.cur || refp != i ) + Move_Zp2_Point( exc, i, dx, dy, TRUE ); + } + } + + + /************************************************************************** + * + * SHZ[a]: SHift Zone + * Opcode range: 0x36-37 + * Stack: uint32 --> + */ + static void + Ins_SHZ( TT_ExecContext exc, + FT_Long* args ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + + FT_UShort limit, i; + + + if ( BOUNDS( args[0], 2 ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + return; + + /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ + /* Twilight zone has no real contours, so use `n_points'. */ + /* Normal zone's `n_points' includes phantoms, so must */ + /* use end of last contour. */ + if ( exc->GS.gep2 == 0 ) + limit = (FT_UShort)exc->zp2.n_points; + else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 ) + limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 ); + else + limit = 0; + + /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ + for ( i = 0; i < limit; i++ ) + { + if ( zp.cur != exc->zp2.cur || refp != i ) + Move_Zp2_Point( exc, i, dx, dy, FALSE ); + } + } + + + /************************************************************************** + * + * SHPIX[]: SHift points by a PIXel amount + * Opcode range: 0x38 + * Stack: f26.6 uint32... --> + */ + static void + Ins_SHPIX( TT_ExecContext exc, + FT_Long* args ) + { + FT_F26Dot6 dx, dy; + FT_UShort point; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 || + exc->GS.gep1 == 0 || + exc->GS.gep2 == 0 ); +#endif + + + + if ( exc->top < exc->GS.loop + 1 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + dx = TT_MulFix14( args[0], exc->GS.freeVector.x ); + dy = TT_MulFix14( args[0], exc->GS.freeVector.y ); + + while ( exc->GS.loop > 0 ) + { + exc->args--; + + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + /* Special case: allow SHPIX to move points in the twilight zone. */ + /* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various */ + /* fonts such as older versions of Rokkitt and DTL Argo T Light */ + /* that would glitch severely after calling ALIGNRP after a */ + /* blocked SHPIX. */ + if ( in_twilight || + ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) ) + Move_Zp2_Point( exc, point, 0, dy, TRUE ); + } + else +#endif + Move_Zp2_Point( exc, point, dx, dy, TRUE ); + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * MSIRP[a]: Move Stack Indirect Relative Position + * Opcode range: 0x3A-0x3B + * Stack: f26.6 uint32 --> + */ + static void + Ins_MSIRP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point = 0; + FT_F26Dot6 distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp1.n_points ) || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + /* UNDOCUMENTED! The MS rasterizer does that with */ + /* twilight points (confirmed by Greg Hitchcock) */ + if ( exc->GS.gep1 == 0 ) + { + exc->zp1.org[point] = exc->zp0.org[exc->GS.rp0]; + exc->func_move_orig( exc, &exc->zp1, point, args[1] ); + exc->zp1.cur[point] = exc->zp1.org[point]; + } + + distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); + + exc->func_move( exc, + &exc->zp1, + point, + SUB_LONG( args[1], distance ) ); + + exc->GS.rp1 = exc->GS.rp0; + exc->GS.rp2 = point; + + if ( ( exc->opcode & 1 ) != 0 ) + exc->GS.rp0 = point; + } + + + /************************************************************************** + * + * MDAP[a]: Move Direct Absolute Point + * Opcode range: 0x2E-0x2F + * Stack: uint32 --> + */ + static void + Ins_MDAP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point; + FT_F26Dot6 cur_dist; + FT_F26Dot6 distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + if ( ( exc->opcode & 1 ) != 0 ) + { + cur_dist = FAST_PROJECT( &exc->zp0.cur[point] ); + distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist ); + } + else + distance = 0; + + exc->func_move( exc, &exc->zp0, point, distance ); + + exc->GS.rp0 = point; + exc->GS.rp1 = point; + } + + + /************************************************************************** + * + * MIAP[a]: Move Indirect Absolute Point + * Opcode range: 0x3E-0x3F + * Stack: uint32 uint32 --> + */ + static void + Ins_MIAP( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong cvtEntry; + FT_UShort point; + FT_F26Dot6 distance; + FT_F26Dot6 org_dist; + + + cvtEntry = (FT_ULong)args[1]; + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp0.n_points ) || + BOUNDSL( cvtEntry, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + /* UNDOCUMENTED! */ + /* */ + /* The behaviour of an MIAP instruction is quite different when used */ + /* in the twilight zone. */ + /* */ + /* First, no control value cut-in test is performed as it would fail */ + /* anyway. Second, the original point, i.e. (org_x,org_y) of */ + /* zp0.point, is set to the absolute, unrounded distance found in the */ + /* CVT. */ + /* */ + /* This is used in the CVT programs of the Microsoft fonts Arial, */ + /* Times, etc., in order to re-adjust some key font heights. It */ + /* allows the use of the IP instruction in the twilight zone, which */ + /* otherwise would be invalid according to the specification. */ + /* */ + /* We implement it with a special sequence for the twilight zone. */ + /* This is a bad hack, but it seems to work. */ + /* */ + /* Confirmed by Greg Hitchcock. */ + + distance = exc->func_read_cvt( exc, cvtEntry ); + + if ( exc->GS.gep0 == 0 ) /* If in twilight zone */ + { + exc->zp0.org[point].x = TT_MulFix14( distance, + exc->GS.freeVector.x ); + exc->zp0.org[point].y = TT_MulFix14( distance, + exc->GS.freeVector.y ); + exc->zp0.cur[point] = exc->zp0.org[point]; + } + + org_dist = FAST_PROJECT( &exc->zp0.cur[point] ); + + if ( ( exc->opcode & 1 ) != 0 ) /* rounding and control cut-in flag */ + { + FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; + FT_F26Dot6 delta; + + + delta = SUB_LONG( distance, org_dist ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta > control_value_cutin ) + distance = org_dist; + + distance = exc->func_round( exc, distance, 3 ); + } + + exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) ); + + Fail: + exc->GS.rp0 = point; + exc->GS.rp1 = point; + } + + + /************************************************************************** + * + * MDRP[abcde]: Move Direct Relative Point + * Opcode range: 0xC0-0xDF + * Stack: uint32 --> + */ + static void + Ins_MDRP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point = 0; + FT_F26Dot6 org_dist, distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp1.n_points ) || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + /* XXX: Is there some undocumented feature while in the */ + /* twilight zone? */ + + /* XXX: UNDOCUMENTED: twilight zone special case */ + + if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 ) + { + FT_Vector* vec1 = &exc->zp1.org[point]; + FT_Vector* vec2 = &exc->zp0.org[exc->GS.rp0]; + + + org_dist = DUALPROJ( vec1, vec2 ); + } + else + { + FT_Vector* vec1 = &exc->zp1.orus[point]; + FT_Vector* vec2 = &exc->zp0.orus[exc->GS.rp0]; + + + if ( exc->metrics.x_scale == exc->metrics.y_scale ) + { + /* this should be faster */ + org_dist = DUALPROJ( vec1, vec2 ); + org_dist = FT_MulFix( org_dist, exc->metrics.x_scale ); + } + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( SUB_LONG( vec1->x, vec2->x ), + exc->metrics.x_scale ); + vec.y = FT_MulFix( SUB_LONG( vec1->y, vec2->y ), + exc->metrics.y_scale ); + + org_dist = FAST_DUALPROJ( &vec ); + } + } + + /* single width cut-in test */ + + /* |org_dist - single_width_value| < single_width_cutin */ + if ( exc->GS.single_width_cutin > 0 && + org_dist < exc->GS.single_width_value + + exc->GS.single_width_cutin && + org_dist > exc->GS.single_width_value - + exc->GS.single_width_cutin ) + { + if ( org_dist >= 0 ) + org_dist = exc->GS.single_width_value; + else + org_dist = -exc->GS.single_width_value; + } + + /* round flag */ + + if ( ( exc->opcode & 4 ) != 0 ) + { + distance = exc->func_round( exc, org_dist, exc->opcode & 3 ); + } + else + distance = Round_None( exc, org_dist, exc->opcode & 3 ); + + /* minimum distance flag */ + + if ( ( exc->opcode & 8 ) != 0 ) + { + FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; + + + if ( org_dist >= 0 ) + { + if ( distance < minimum_distance ) + distance = minimum_distance; + } + else + { + if ( distance > NEG_LONG( minimum_distance ) ) + distance = NEG_LONG( minimum_distance ); + } + } + + /* now move the point */ + + org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); + + exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) ); + + Fail: + exc->GS.rp1 = exc->GS.rp0; + exc->GS.rp2 = point; + + if ( ( exc->opcode & 16 ) != 0 ) + exc->GS.rp0 = point; + } + + + /************************************************************************** + * + * MIRP[abcde]: Move Indirect Relative Point + * Opcode range: 0xE0-0xFF + * Stack: int32? uint32 --> + */ + static void + Ins_MIRP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point; + FT_ULong cvtEntry; + + FT_F26Dot6 cvt_dist, + distance, + cur_dist, + org_dist; + + FT_F26Dot6 delta; + + + point = (FT_UShort)args[0]; + cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) ); + + /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ + + if ( BOUNDS( point, exc->zp1.n_points ) || + BOUNDSL( cvtEntry, exc->cvtSize + 1 ) || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + if ( !cvtEntry ) + cvt_dist = 0; + else + cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 ); + + /* single width test */ + + delta = SUB_LONG( cvt_dist, exc->GS.single_width_value ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta < exc->GS.single_width_cutin ) + { + if ( cvt_dist >= 0 ) + cvt_dist = exc->GS.single_width_value; + else + cvt_dist = -exc->GS.single_width_value; + } + + /* UNDOCUMENTED! The MS rasterizer does that with */ + /* twilight points (confirmed by Greg Hitchcock) */ + if ( exc->GS.gep1 == 0 ) + { + exc->zp1.org[point].x = ADD_LONG( + exc->zp0.org[exc->GS.rp0].x, + TT_MulFix14( cvt_dist, + exc->GS.freeVector.x ) ); + exc->zp1.org[point].y = ADD_LONG( + exc->zp0.org[exc->GS.rp0].y, + TT_MulFix14( cvt_dist, + exc->GS.freeVector.y ) ); + exc->zp1.cur[point] = exc->zp1.org[point]; + } + + org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] ); + cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] ); + + /* auto-flip test */ + + if ( exc->GS.auto_flip ) + { + if ( ( org_dist ^ cvt_dist ) < 0 ) + cvt_dist = NEG_LONG( cvt_dist ); + } + + /* control value cut-in and round */ + + if ( ( exc->opcode & 4 ) != 0 ) + { + /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ + /* refer to the same zone. */ + + if ( exc->GS.gep0 == exc->GS.gep1 ) + { + FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; + + + /* XXX: According to Greg Hitchcock, the following wording is */ + /* the right one: */ + /* */ + /* When the absolute difference between the value in */ + /* the table [CVT] and the measurement directly from */ + /* the outline is _greater_ than the cut_in value, the */ + /* outline measurement is used. */ + /* */ + /* This is from `instgly.doc'. The description in */ + /* `ttinst2.doc', version 1.66, is thus incorrect since */ + /* it implies `>=' instead of `>'. */ + + delta = SUB_LONG( cvt_dist, org_dist ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta > control_value_cutin ) + cvt_dist = org_dist; + } + + distance = exc->func_round( exc, cvt_dist, exc->opcode & 3 ); + } + else + distance = Round_None( exc, cvt_dist, exc->opcode & 3 ); + + /* minimum distance test */ + + if ( ( exc->opcode & 8 ) != 0 ) + { + FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; + + + if ( org_dist >= 0 ) + { + if ( distance < minimum_distance ) + distance = minimum_distance; + } + else + { + if ( distance > NEG_LONG( minimum_distance ) ) + distance = NEG_LONG( minimum_distance ); + } + } + + exc->func_move( exc, + &exc->zp1, + point, + SUB_LONG( distance, cur_dist ) ); + + Fail: + exc->GS.rp1 = exc->GS.rp0; + + if ( ( exc->opcode & 16 ) != 0 ) + exc->GS.rp0 = point; + + exc->GS.rp2 = point; + } + + + /************************************************************************** + * + * ALIGNRP[]: ALIGN Relative Point + * Opcode range: 0x3C + * Stack: uint32 uint32... --> + */ + static void + Ins_ALIGNRP( TT_ExecContext exc ) + { + FT_UShort point; + FT_F26Dot6 distance; + + + if ( exc->top < exc->GS.loop || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + while ( exc->GS.loop > 0 ) + { + exc->args--; + + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->zp1.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + { + distance = PROJECT( exc->zp1.cur + point, + exc->zp0.cur + exc->GS.rp0 ); + + exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) ); + } + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * ISECT[]: moves point to InterSECTion + * Opcode range: 0x0F + * Stack: 5 * uint32 --> + */ + static void + Ins_ISECT( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point, + a0, a1, + b0, b1; + + FT_F26Dot6 discriminant, dotproduct; + + FT_F26Dot6 dx, dy, + dax, day, + dbx, dby; + + FT_F26Dot6 val; + + FT_Vector R; + + + point = (FT_UShort)args[0]; + + a0 = (FT_UShort)args[1]; + a1 = (FT_UShort)args[2]; + b0 = (FT_UShort)args[3]; + b1 = (FT_UShort)args[4]; + + if ( BOUNDS( b0, exc->zp0.n_points ) || + BOUNDS( b1, exc->zp0.n_points ) || + BOUNDS( a0, exc->zp1.n_points ) || + BOUNDS( a1, exc->zp1.n_points ) || + BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + /* Cramer's rule */ + + dbx = SUB_LONG( exc->zp0.cur[b1].x, exc->zp0.cur[b0].x ); + dby = SUB_LONG( exc->zp0.cur[b1].y, exc->zp0.cur[b0].y ); + + dax = SUB_LONG( exc->zp1.cur[a1].x, exc->zp1.cur[a0].x ); + day = SUB_LONG( exc->zp1.cur[a1].y, exc->zp1.cur[a0].y ); + + dx = SUB_LONG( exc->zp0.cur[b0].x, exc->zp1.cur[a0].x ); + dy = SUB_LONG( exc->zp0.cur[b0].y, exc->zp1.cur[a0].y ); + + discriminant = ADD_LONG( FT_MulDiv( dax, NEG_LONG( dby ), 0x40 ), + FT_MulDiv( day, dbx, 0x40 ) ); + dotproduct = ADD_LONG( FT_MulDiv( dax, dbx, 0x40 ), + FT_MulDiv( day, dby, 0x40 ) ); + + /* The discriminant above is actually a cross product of vectors */ + /* da and db. Together with the dot product, they can be used as */ + /* surrogates for sine and cosine of the angle between the vectors. */ + /* Indeed, */ + /* dotproduct = |da||db|cos(angle) */ + /* discriminant = |da||db|sin(angle) . */ + /* We use these equations to reject grazing intersections by */ + /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */ + if ( MUL_LONG( 19, FT_ABS( discriminant ) ) > FT_ABS( dotproduct ) ) + { + val = ADD_LONG( FT_MulDiv( dx, NEG_LONG( dby ), 0x40 ), + FT_MulDiv( dy, dbx, 0x40 ) ); + + R.x = FT_MulDiv( val, dax, discriminant ); + R.y = FT_MulDiv( val, day, discriminant ); + + /* XXX: Block in backward_compatibility and/or post-IUP? */ + exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x ); + exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y ); + } + else + { + /* else, take the middle of the middles of A and B */ + + /* XXX: Block in backward_compatibility and/or post-IUP? */ + exc->zp2.cur[point].x = + ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ), + ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4; + exc->zp2.cur[point].y = + ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ), + ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4; + } + + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH; + } + + + /************************************************************************** + * + * ALIGNPTS[]: ALIGN PoinTS + * Opcode range: 0x27 + * Stack: uint32 uint32 --> + */ + static void + Ins_ALIGNPTS( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort p1, p2; + FT_F26Dot6 distance; + + + p1 = (FT_UShort)args[0]; + p2 = (FT_UShort)args[1]; + + if ( BOUNDS( p1, exc->zp1.n_points ) || + BOUNDS( p2, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2; + + exc->func_move( exc, &exc->zp1, p1, distance ); + exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) ); + } + + + /************************************************************************** + * + * IP[]: Interpolate Point + * Opcode range: 0x39 + * Stack: uint32... --> + */ + + /* SOMETIMES, DUMBER CODE IS BETTER CODE */ + + static void + Ins_IP( TT_ExecContext exc ) + { + FT_F26Dot6 old_range, cur_range; + FT_Vector* orus_base; + FT_Vector* cur_base; + FT_Int twilight; + + + if ( exc->top < exc->GS.loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + /* + * We need to deal in a special way with the twilight zone. + * Otherwise, by definition, the value of exc->twilight.orus[n] is (0,0), + * for every n. + */ + twilight = ( exc->GS.gep0 == 0 || + exc->GS.gep1 == 0 || + exc->GS.gep2 == 0 ); + + if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + if ( twilight ) + orus_base = &exc->zp0.org[exc->GS.rp1]; + else + orus_base = &exc->zp0.orus[exc->GS.rp1]; + + cur_base = &exc->zp0.cur[exc->GS.rp1]; + + /* XXX: There are some glyphs in some braindead but popular */ + /* fonts out there (e.g. [aeu]grave in monotype.ttf) */ + /* calling IP[] with bad values of rp[12]. */ + /* Do something sane when this odd thing happens. */ + if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) || + BOUNDS( exc->GS.rp2, exc->zp1.n_points ) ) + { + old_range = 0; + cur_range = 0; + } + else + { + if ( twilight ) + old_range = DUALPROJ( &exc->zp1.org[exc->GS.rp2], orus_base ); + else if ( exc->metrics.x_scale == exc->metrics.y_scale ) + old_range = DUALPROJ( &exc->zp1.orus[exc->GS.rp2], orus_base ); + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].x, + orus_base->x ), + exc->metrics.x_scale ); + vec.y = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].y, + orus_base->y ), + exc->metrics.y_scale ); + + old_range = FAST_DUALPROJ( &vec ); + } + + cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base ); + } + + for ( ; exc->GS.loop > 0; exc->GS.loop-- ) + { + FT_UInt point = (FT_UInt)exc->stack[--exc->args]; + FT_F26Dot6 org_dist, cur_dist, new_dist; + + + /* check point bounds */ + if ( BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + continue; + } + + if ( twilight ) + org_dist = DUALPROJ( &exc->zp2.org[point], orus_base ); + else if ( exc->metrics.x_scale == exc->metrics.y_scale ) + org_dist = DUALPROJ( &exc->zp2.orus[point], orus_base ); + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( SUB_LONG( exc->zp2.orus[point].x, + orus_base->x ), + exc->metrics.x_scale ); + vec.y = FT_MulFix( SUB_LONG( exc->zp2.orus[point].y, + orus_base->y ), + exc->metrics.y_scale ); + + org_dist = FAST_DUALPROJ( &vec ); + } + + cur_dist = PROJECT( &exc->zp2.cur[point], cur_base ); + + if ( org_dist ) + { + if ( old_range ) + new_dist = FT_MulDiv( org_dist, cur_range, old_range ); + else + { + /* This is the same as what MS does for the invalid case: */ + /* */ + /* delta = (Original_Pt - Original_RP1) - */ + /* (Current_Pt - Current_RP1) ; */ + /* */ + /* In FreeType speak: */ + /* */ + /* delta = org_dist - cur_dist . */ + /* */ + /* We move `point' by `new_dist - cur_dist' after leaving */ + /* this block, thus we have */ + /* */ + /* new_dist - cur_dist = delta , */ + /* new_dist - cur_dist = org_dist - cur_dist , */ + /* new_dist = org_dist . */ + + new_dist = org_dist; + } + } + else + new_dist = 0; + + exc->func_move( exc, + &exc->zp2, + (FT_UShort)point, + SUB_LONG( new_dist, cur_dist ) ); + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * UTP[a]: UnTouch Point + * Opcode range: 0x29 + * Stack: uint32 --> + */ + static void + Ins_UTP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point; + FT_Byte mask; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + mask = 0xFF; + + if ( exc->GS.freeVector.x != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_X; + + if ( exc->GS.freeVector.y != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_Y; + + exc->zp0.tags[point] &= mask; + } + + + /* Local variables for Ins_IUP: */ + typedef struct IUP_WorkerRec_ + { + FT_Vector* orgs; /* original and current coordinate */ + FT_Vector* curs; /* arrays */ + FT_Vector* orus; + FT_UInt max_points; + + } IUP_WorkerRec, *IUP_Worker; + + + static void + iup_worker_shift_( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt p ) + { + FT_UInt i; + FT_F26Dot6 dx; + + + dx = SUB_LONG( worker->curs[p].x, worker->orgs[p].x ); + if ( dx != 0 ) + { + for ( i = p1; i < p; i++ ) + worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx ); + + for ( i = p + 1; i <= p2; i++ ) + worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx ); + } + } + + + static void + iup_worker_interpolate_( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt ref1, + FT_UInt ref2 ) + { + FT_UInt i; + FT_F26Dot6 orus1, orus2, org1, org2, cur1, cur2, delta1, delta2; + + + if ( p1 > p2 ) + return; + + if ( BOUNDS( ref1, worker->max_points ) || + BOUNDS( ref2, worker->max_points ) ) + return; + + orus1 = worker->orus[ref1].x; + orus2 = worker->orus[ref2].x; + + if ( orus1 > orus2 ) + { + FT_F26Dot6 tmp_o; + FT_UInt tmp_r; + + + tmp_o = orus1; + orus1 = orus2; + orus2 = tmp_o; + + tmp_r = ref1; + ref1 = ref2; + ref2 = tmp_r; + } + + org1 = worker->orgs[ref1].x; + org2 = worker->orgs[ref2].x; + cur1 = worker->curs[ref1].x; + cur2 = worker->curs[ref2].x; + delta1 = SUB_LONG( cur1, org1 ); + delta2 = SUB_LONG( cur2, org2 ); + + if ( cur1 == cur2 || orus1 == orus2 ) + { + + /* trivial snap or shift of untouched points */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + + + if ( x <= org1 ) + x = ADD_LONG( x, delta1 ); + + else if ( x >= org2 ) + x = ADD_LONG( x, delta2 ); + + else + x = cur1; + + worker->curs[i].x = x; + } + } + else + { + FT_Fixed scale = 0; + FT_Bool scale_valid = 0; + + + /* interpolation */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + + + if ( x <= org1 ) + x = ADD_LONG( x, delta1 ); + + else if ( x >= org2 ) + x = ADD_LONG( x, delta2 ); + + else + { + if ( !scale_valid ) + { + scale_valid = 1; + scale = FT_DivFix( SUB_LONG( cur2, cur1 ), + SUB_LONG( orus2, orus1 ) ); + } + + x = ADD_LONG( cur1, + FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ), + scale ) ); + } + worker->curs[i].x = x; + } + } + } + + + /************************************************************************** + * + * IUP[a]: Interpolate Untouched Points + * Opcode range: 0x30-0x31 + * Stack: --> + */ + static void + Ins_IUP( TT_ExecContext exc ) + { + IUP_WorkerRec V; + FT_Byte mask; + + FT_UInt first_point; /* first point of contour */ + FT_UInt end_point; /* end point (last+1) of contour */ + + FT_UInt first_touched; /* first touched point in contour */ + FT_UInt cur_touched; /* current touched point in contour */ + + FT_UInt point; /* current point */ + FT_Short contour; /* current contour */ + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + /* Allow IUP until it has been called on both axes. Immediately */ + /* return on subsequent ones. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + if ( exc->iupx_called && exc->iupy_called ) + return; + + if ( exc->opcode & 1 ) + exc->iupx_called = TRUE; + else + exc->iupy_called = TRUE; + } +#endif + + /* ignore empty outlines */ + if ( exc->pts.n_contours == 0 ) + return; + + if ( exc->opcode & 1 ) + { + mask = FT_CURVE_TAG_TOUCH_X; + V.orgs = exc->pts.org; + V.curs = exc->pts.cur; + V.orus = exc->pts.orus; + } + else + { + mask = FT_CURVE_TAG_TOUCH_Y; + V.orgs = (FT_Vector*)( (FT_Pos*)exc->pts.org + 1 ); + V.curs = (FT_Vector*)( (FT_Pos*)exc->pts.cur + 1 ); + V.orus = (FT_Vector*)( (FT_Pos*)exc->pts.orus + 1 ); + } + V.max_points = exc->pts.n_points; + + contour = 0; + point = 0; + + do + { + end_point = exc->pts.contours[contour] - exc->pts.first_point; + first_point = point; + + if ( BOUNDS( end_point, exc->pts.n_points ) ) + end_point = exc->pts.n_points - 1; + + while ( point <= end_point && ( exc->pts.tags[point] & mask ) == 0 ) + point++; + + if ( point <= end_point ) + { + first_touched = point; + cur_touched = point; + + point++; + + while ( point <= end_point ) + { + if ( ( exc->pts.tags[point] & mask ) != 0 ) + { + iup_worker_interpolate_( &V, + cur_touched + 1, + point - 1, + cur_touched, + point ); + cur_touched = point; + } + + point++; + } + + if ( cur_touched == first_touched ) + iup_worker_shift_( &V, first_point, end_point, cur_touched ); + else + { + iup_worker_interpolate_( &V, + (FT_UShort)( cur_touched + 1 ), + end_point, + cur_touched, + first_touched ); + + if ( first_touched > 0 ) + iup_worker_interpolate_( &V, + first_point, + first_touched - 1, + cur_touched, + first_touched ); + } + } + contour++; + } while ( contour < exc->pts.n_contours ); + } + + + /************************************************************************** + * + * DELTAPn[]: DELTA exceptions P1, P2, P3 + * Opcode range: 0x5D,0x71,0x72 + * Stack: uint32 (2 * uint32)... --> + */ + static void + Ins_DELTAP( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong nump, k; + FT_UShort A; + FT_ULong C, P; + FT_Long B; + + + P = (FT_ULong)exc->func_cur_ppem( exc ); + nump = (FT_ULong)args[0]; /* some points theoretically may occur more + than once, thus UShort isn't enough */ + + for ( k = 1; k <= nump; k++ ) + { + if ( exc->args < 2 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + exc->args = 0; + goto Fail; + } + + exc->args -= 2; + + A = (FT_UShort)exc->stack[exc->args + 1]; + B = exc->stack[exc->args]; + + /* XXX: Because some popular fonts contain some invalid DeltaP */ + /* instructions, we simply ignore them when the stacked */ + /* point reference is off limit, rather than returning an */ + /* error. As a delta instruction doesn't change a glyph */ + /* in great ways, this shouldn't be a problem. */ + + if ( !BOUNDS( A, exc->zp0.n_points ) ) + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( exc->opcode ) + { + case 0x5D: + break; + + case 0x71: + C += 16; + break; + + case 0x72: + C += 32; + break; + } + + C += exc->GS.delta_base; + + if ( P == C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B *= 1L << ( 6 - exc->GS.delta_shift ); + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility */ + /* mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + if ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) ) + exc->func_move( exc, &exc->zp0, A, B ); + } + else +#endif + exc->func_move( exc, &exc->zp0, A, B ); + } + } + else + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + } + + Fail: + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * DELTACn[]: DELTA exceptions C1, C2, C3 + * Opcode range: 0x73,0x74,0x75 + * Stack: uint32 (2 * uint32)... --> + */ + static void + Ins_DELTAC( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong nump, k; + FT_ULong A, C, P; + FT_Long B; + + + P = (FT_ULong)exc->func_cur_ppem( exc ); + nump = (FT_ULong)args[0]; + + for ( k = 1; k <= nump; k++ ) + { + if ( exc->args < 2 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + exc->args = 0; + goto Fail; + } + + exc->args -= 2; + + A = (FT_ULong)exc->stack[exc->args + 1]; + B = exc->stack[exc->args]; + + if ( BOUNDSL( A, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( exc->opcode ) + { + case 0x73: + break; + + case 0x74: + C += 16; + break; + + case 0x75: + C += 32; + break; + } + + C += exc->GS.delta_base; + + if ( P == C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B *= 1L << ( 6 - exc->GS.delta_shift ); + + exc->func_move_cvt( exc, A, B ); + } + } + } + + Fail: + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * MISC. INSTRUCTIONS + * + */ + + + /************************************************************************** + * + * GETINFO[]: GET INFOrmation + * Opcode range: 0x88 + * Stack: uint32 --> uint32 + */ + static void + Ins_GETINFO( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long K; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face ); + + + K = 0; + + if ( ( args[0] & 1 ) != 0 ) + K = driver->interpreter_version; + + /********************************* + * GLYPH ROTATED + * Selector Bit: 1 + * Return Bit(s): 8 + */ + if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated ) + K |= 1 << 8; + + /********************************* + * GLYPH STRETCHED + * Selector Bit: 2 + * Return Bit(s): 9 + */ + if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched ) + K |= 1 << 9; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /********************************* + * VARIATION GLYPH + * Selector Bit: 3 + * Return Bit(s): 10 + */ + if ( (args[0] & 8 ) != 0 && exc->face->blend ) + K |= 1 << 10; +#endif + + /********************************* + * BI-LEVEL HINTING AND + * GRAYSCALE RENDERING + * Selector Bit: 5 + * Return Bit(s): 12 + */ + if ( ( args[0] & 32 ) != 0 && exc->grayscale ) + K |= 1 << 12; + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Toggle the following flags only outside of monochrome mode. */ + /* Otherwise, instructions may behave weirdly and rendering results */ + /* may differ between v35 and v40 mode, e.g., in `Times New Roman */ + /* Bold Italic'. */ + if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean ) + { + /********************************* + * HINTING FOR SUBPIXEL + * Selector Bit: 6 + * Return Bit(s): 13 + * + * v40 does subpixel hinting by default. + */ + if ( ( args[0] & 64 ) != 0 ) + K |= 1 << 13; + + /********************************* + * VERTICAL LCD SUBPIXELS? + * Selector Bit: 8 + * Return Bit(s): 15 + */ + if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean ) + K |= 1 << 15; + + /********************************* + * SUBPIXEL POSITIONED? + * Selector Bit: 10 + * Return Bit(s): 17 + * + * XXX: FreeType supports it, dependent on what client does? + */ + if ( ( args[0] & 1024 ) != 0 ) + K |= 1 << 17; + + /********************************* + * SYMMETRICAL SMOOTHING + * Selector Bit: 11 + * Return Bit(s): 18 + * + * The only smoothing method FreeType supports unless someone sets + * FT_LOAD_TARGET_MONO. + */ + if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean ) + K |= 1 << 18; + + /********************************* + * CLEARTYPE HINTING AND + * GRAYSCALE RENDERING + * Selector Bit: 12 + * Return Bit(s): 19 + * + * Grayscale rendering is what FreeType does anyway unless someone + * sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) + */ + if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype ) + K |= 1 << 19; + } +#endif + + args[0] = K; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /************************************************************************** + * + * GETVARIATION[]: get normalized variation (blend) coordinates + * Opcode range: 0x91 + * Stack: --> f2.14... + * + * XXX: UNDOCUMENTED! There is no official documentation from Apple for + * this bytecode instruction. Active only if a font has GX + * variation axes. + */ + static void + Ins_GETVARIATION( TT_ExecContext exc, + FT_Long* args ) + { + FT_UInt num_axes = exc->face->blend->num_axis; + FT_Fixed* coords = exc->face->blend->normalizedcoords; + + FT_UInt i; + + + if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + if ( coords ) + { + for ( i = 0; i < num_axes; i++ ) + args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */ + } + else + { + for ( i = 0; i < num_axes; i++ ) + args[i] = 0; + } + } + + + /************************************************************************** + * + * GETDATA[]: no idea what this is good for + * Opcode range: 0x92 + * Stack: --> 17 + * + * XXX: UNDOCUMENTED! There is no documentation from Apple for this + * very weird bytecode instruction. + */ + static void + Ins_GETDATA( FT_Long* args ) + { + args[0] = 17; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static void + Ins_UNKNOWN( TT_ExecContext exc ) + { + TT_DefRecord* def = exc->IDefs; + TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); + + + for ( ; def < limit; def++ ) + { + if ( (FT_Byte)def->opc == exc->opcode && def->active ) + { + TT_CallRec* call; + + + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + call = exc->callStack + exc->callTop++; + + call->Caller_Range = exc->curRange; + call->Caller_IP = exc->IP + 1; + call->Cur_Count = 1; + call->Def = def; + + Ins_Goto_CodeRange( exc, def->range, def->start ); + + exc->step_ins = FALSE; + return; + } + } + + exc->error = FT_THROW( Invalid_Opcode ); + } + + + /************************************************************************** + * + * RUN + * + * This function executes a run of opcodes. It will exit in the + * following cases: + * + * - Errors (in which case it returns FALSE). + * + * - Reaching the end of the main code range (returns TRUE). + * Reaching the end of a code range within a function call is an + * error. + * + * - After executing one single opcode, if the flag `Instruction_Trap' + * is set to TRUE (returns TRUE). + * + * On exit with TRUE, test IP < CodeSize to know whether it comes from + * an instruction trap or a normal termination. + * + * + * Note: The documented DEBUG opcode pops a value from the stack. This + * behaviour is unsupported; here a DEBUG opcode is always an + * error. + * + * + * THIS IS THE INTERPRETER'S MAIN LOOP. + * + */ + + + /* documentation is in ttinterp.h */ + + FT_EXPORT_DEF( FT_Error ) + TT_RunIns( void* exec ) + { + TT_ExecContext exc = (TT_ExecContext)exec; + + FT_ULong ins_counter = 0; /* executed instructions counter */ + FT_ULong num_twilight_points; + FT_UShort i; + + + /* We restrict the number of twilight points to a reasonable, */ + /* heuristic value to avoid slow execution of malformed bytecode. */ + num_twilight_points = FT_MAX( 30, + 2 * ( exc->pts.n_points + exc->cvtSize ) ); + if ( exc->twilight.n_points > num_twilight_points ) + { + if ( num_twilight_points > 0xFFFFU ) + num_twilight_points = 0xFFFFU; + + FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" )); + FT_TRACE5(( " from %d to the more reasonable value %ld\n", + exc->twilight.n_points, + num_twilight_points )); + exc->twilight.n_points = (FT_UShort)num_twilight_points; + } + + /* Set up loop detectors. We restrict the number of LOOPCALL loops */ + /* and the number of JMPR, JROT, and JROF calls with a negative */ + /* argument to values that depend on various parameters like the */ + /* size of the CVT table or the number of points in the current */ + /* glyph (if applicable). */ + /* */ + /* The idea is that in real-world bytecode you either iterate over */ + /* all CVT entries (in the `prep' table), or over all points (or */ + /* contours, in the `glyf' table) of a glyph, and such iterations */ + /* don't happen very often. */ + exc->loopcall_counter = 0; + exc->neg_jump_counter = 0; + + /* The maximum values are heuristic. */ + if ( exc->pts.n_points ) + exc->loopcall_counter_max = FT_MAX( 50, + 10 * exc->pts.n_points ) + + FT_MAX( 50, + exc->cvtSize / 10 ); + else + exc->loopcall_counter_max = 300 + 22 * exc->cvtSize; + + /* as a protection against an unreasonable number of CVT entries */ + /* we assume at most 100 control values per glyph for the counter */ + if ( exc->loopcall_counter_max > + 100 * (FT_ULong)exc->face->root.num_glyphs ) + exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs; + + FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL" + " to %ld\n", exc->loopcall_counter_max )); + + exc->neg_jump_counter_max = exc->loopcall_counter_max; + FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps" + " to %ld\n", exc->neg_jump_counter_max )); + + /* set PPEM and CVT functions */ + exc->tt_metrics.ratio = 0; + if ( exc->metrics.x_ppem != exc->metrics.y_ppem ) + { + /* non-square pixels, use the stretched routines */ + exc->func_cur_ppem = Current_Ppem_Stretched; + exc->func_read_cvt = Read_CVT_Stretched; + exc->func_write_cvt = Write_CVT_Stretched; + exc->func_move_cvt = Move_CVT_Stretched; + } + else + { + /* square pixels, use normal routines */ + exc->func_cur_ppem = Current_Ppem; + exc->func_read_cvt = Read_CVT; + exc->func_write_cvt = Write_CVT; + exc->func_move_cvt = Move_CVT; + } + + exc->iniRange = exc->curRange; + + Compute_Funcs( exc ); + Compute_Round( exc, (FT_Byte)exc->GS.round_state ); + + /* These flags cancel execution of some opcodes after IUP is called */ +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + exc->iupx_called = FALSE; + exc->iupy_called = FALSE; +#endif + + do + { + exc->opcode = exc->code[exc->IP]; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ft_trace_levels[trace_ttinterp] >= 6 ) + { + FT_Long cnt = FT_MIN( 8, exc->top ); + FT_Long n; + + + /* if tracing level is 7, show current code position */ + /* and the first few stack elements also */ + FT_TRACE6(( " " )); + FT_TRACE7(( "%06ld ", exc->IP )); + FT_TRACE6(( "%s", opcode_name[exc->opcode] + 2 )); + FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A' + ? 2 + : 12 - ( *opcode_name[exc->opcode] - '0' ), + "#" )); + for ( n = 1; n <= cnt; n++ ) + FT_TRACE7(( " %ld", exc->stack[exc->top - n] )); + FT_TRACE6(( "\n" )); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + if ( ( exc->length = opcode_length[exc->opcode] ) < 0 ) + { + if ( exc->IP + 1 >= exc->codeSize ) + goto LErrorCodeOverflow_; + + exc->length = 2 - exc->length * exc->code[exc->IP + 1]; + } + + if ( exc->IP + exc->length > exc->codeSize ) + goto LErrorCodeOverflow_; + + /* First, let's check for empty stack and overflow */ + exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 ); + + /* `args' is the top of the stack once arguments have been popped. */ + /* One can also interpret it as the index of the last argument. */ + if ( exc->args < 0 ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Too_Few_Arguments ); + goto LErrorLabel_; + } + + /* push zeroes onto the stack */ + for ( i = 0; i < Pop_Push_Count[exc->opcode] >> 4; i++ ) + exc->stack[i] = 0; + exc->args = 0; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( exc->opcode == 0x91 ) + { + /* this is very special: GETVARIATION returns */ + /* a variable number of arguments */ + + /* it is the job of the application to `activate' GX handling, */ + /* that is, calling any of the GX API functions on the current */ + /* font to select a variation instance */ + if ( exc->face->blend ) + exc->new_top = exc->args + exc->face->blend->num_axis; + } + else +#endif + exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 ); + + /* `new_top' is the new top of the stack, after the instruction's */ + /* execution. `top' will be set to `new_top' after the `switch' */ + /* statement. */ + if ( exc->new_top > exc->stackSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + goto LErrorLabel_; + } + + exc->step_ins = TRUE; + exc->error = FT_Err_Ok; + + { + FT_Long* args = exc->stack + exc->args; + FT_Byte opcode = exc->opcode; + + + switch ( opcode ) + { + case 0x00: /* SVTCA y */ + case 0x01: /* SVTCA x */ + case 0x02: /* SPvTCA y */ + case 0x03: /* SPvTCA x */ + case 0x04: /* SFvTCA y */ + case 0x05: /* SFvTCA x */ + Ins_SxyTCA( exc ); + break; + + case 0x06: /* SPvTL // */ + case 0x07: /* SPvTL + */ + Ins_SPVTL( exc, args ); + break; + + case 0x08: /* SFvTL // */ + case 0x09: /* SFvTL + */ + Ins_SFVTL( exc, args ); + break; + + case 0x0A: /* SPvFS */ + Ins_SPVFS( exc, args ); + break; + + case 0x0B: /* SFvFS */ + Ins_SFVFS( exc, args ); + break; + + case 0x0C: /* GPv */ + Ins_GPV( exc, args ); + break; + + case 0x0D: /* GFv */ + Ins_GFV( exc, args ); + break; + + case 0x0E: /* SFvTPv */ + Ins_SFVTPV( exc ); + break; + + case 0x0F: /* ISECT */ + Ins_ISECT( exc, args ); + break; + + case 0x10: /* SRP0 */ + Ins_SRP0( exc, args ); + break; + + case 0x11: /* SRP1 */ + Ins_SRP1( exc, args ); + break; + + case 0x12: /* SRP2 */ + Ins_SRP2( exc, args ); + break; + + case 0x13: /* SZP0 */ + Ins_SZP0( exc, args ); + break; + + case 0x14: /* SZP1 */ + Ins_SZP1( exc, args ); + break; + + case 0x15: /* SZP2 */ + Ins_SZP2( exc, args ); + break; + + case 0x16: /* SZPS */ + Ins_SZPS( exc, args ); + break; + + case 0x17: /* SLOOP */ + Ins_SLOOP( exc, args ); + break; + + case 0x18: /* RTG */ + Ins_RTG( exc ); + break; + + case 0x19: /* RTHG */ + Ins_RTHG( exc ); + break; + + case 0x1A: /* SMD */ + Ins_SMD( exc, args ); + break; + + case 0x1B: /* ELSE */ + Ins_ELSE( exc ); + break; + + case 0x1C: /* JMPR */ + Ins_JMPR( exc, args ); + break; + + case 0x1D: /* SCVTCI */ + Ins_SCVTCI( exc, args ); + break; + + case 0x1E: /* SSWCI */ + Ins_SSWCI( exc, args ); + break; + + case 0x1F: /* SSW */ + Ins_SSW( exc, args ); + break; + + case 0x20: /* DUP */ + Ins_DUP( args ); + break; + + case 0x21: /* POP */ + Ins_POP(); + break; + + case 0x22: /* CLEAR */ + Ins_CLEAR( exc ); + break; + + case 0x23: /* SWAP */ + Ins_SWAP( args ); + break; + + case 0x24: /* DEPTH */ + Ins_DEPTH( exc, args ); + break; + + case 0x25: /* CINDEX */ + Ins_CINDEX( exc, args ); + break; + + case 0x26: /* MINDEX */ + Ins_MINDEX( exc, args ); + break; + + case 0x27: /* ALIGNPTS */ + Ins_ALIGNPTS( exc, args ); + break; + + case 0x28: /* RAW */ + Ins_UNKNOWN( exc ); + break; + + case 0x29: /* UTP */ + Ins_UTP( exc, args ); + break; + + case 0x2A: /* LOOPCALL */ + Ins_LOOPCALL( exc, args ); + break; + + case 0x2B: /* CALL */ + Ins_CALL( exc, args ); + break; + + case 0x2C: /* FDEF */ + Ins_FDEF( exc, args ); + break; + + case 0x2D: /* ENDF */ + Ins_ENDF( exc ); + break; + + case 0x2E: /* MDAP */ + case 0x2F: /* MDAP */ + Ins_MDAP( exc, args ); + break; + + case 0x30: /* IUP */ + case 0x31: /* IUP */ + Ins_IUP( exc ); + break; + + case 0x32: /* SHP */ + case 0x33: /* SHP */ + Ins_SHP( exc ); + break; + + case 0x34: /* SHC */ + case 0x35: /* SHC */ + Ins_SHC( exc, args ); + break; + + case 0x36: /* SHZ */ + case 0x37: /* SHZ */ + Ins_SHZ( exc, args ); + break; + + case 0x38: /* SHPIX */ + Ins_SHPIX( exc, args ); + break; + + case 0x39: /* IP */ + Ins_IP( exc ); + break; + + case 0x3A: /* MSIRP */ + case 0x3B: /* MSIRP */ + Ins_MSIRP( exc, args ); + break; + + case 0x3C: /* AlignRP */ + Ins_ALIGNRP( exc ); + break; + + case 0x3D: /* RTDG */ + Ins_RTDG( exc ); + break; + + case 0x3E: /* MIAP */ + case 0x3F: /* MIAP */ + Ins_MIAP( exc, args ); + break; + + case 0x40: /* NPUSHB */ + Ins_NPUSHB( exc, args ); + break; + + case 0x41: /* NPUSHW */ + Ins_NPUSHW( exc, args ); + break; + + case 0x42: /* WS */ + Ins_WS( exc, args ); + break; + + case 0x43: /* RS */ + Ins_RS( exc, args ); + break; + + case 0x44: /* WCVTP */ + Ins_WCVTP( exc, args ); + break; + + case 0x45: /* RCVT */ + Ins_RCVT( exc, args ); + break; + + case 0x46: /* GC */ + case 0x47: /* GC */ + Ins_GC( exc, args ); + break; + + case 0x48: /* SCFS */ + Ins_SCFS( exc, args ); + break; + + case 0x49: /* MD */ + case 0x4A: /* MD */ + Ins_MD( exc, args ); + break; + + case 0x4B: /* MPPEM */ + Ins_MPPEM( exc, args ); + break; + + case 0x4C: /* MPS */ + Ins_MPS( exc, args ); + break; + + case 0x4D: /* FLIPON */ + Ins_FLIPON( exc ); + break; + + case 0x4E: /* FLIPOFF */ + Ins_FLIPOFF( exc ); + break; + + case 0x4F: /* DEBUG */ + Ins_DEBUG( exc ); + break; + + case 0x50: /* LT */ + Ins_LT( args ); + break; + + case 0x51: /* LTEQ */ + Ins_LTEQ( args ); + break; + + case 0x52: /* GT */ + Ins_GT( args ); + break; + + case 0x53: /* GTEQ */ + Ins_GTEQ( args ); + break; + + case 0x54: /* EQ */ + Ins_EQ( args ); + break; + + case 0x55: /* NEQ */ + Ins_NEQ( args ); + break; + + case 0x56: /* ODD */ + Ins_ODD( exc, args ); + break; + + case 0x57: /* EVEN */ + Ins_EVEN( exc, args ); + break; + + case 0x58: /* IF */ + Ins_IF( exc, args ); + break; + + case 0x59: /* EIF */ + Ins_EIF(); + break; + + case 0x5A: /* AND */ + Ins_AND( args ); + break; + + case 0x5B: /* OR */ + Ins_OR( args ); + break; + + case 0x5C: /* NOT */ + Ins_NOT( args ); + break; + + case 0x5D: /* DELTAP1 */ + Ins_DELTAP( exc, args ); + break; + + case 0x5E: /* SDB */ + Ins_SDB( exc, args ); + break; + + case 0x5F: /* SDS */ + Ins_SDS( exc, args ); + break; + + case 0x60: /* ADD */ + Ins_ADD( args ); + break; + + case 0x61: /* SUB */ + Ins_SUB( args ); + break; + + case 0x62: /* DIV */ + Ins_DIV( exc, args ); + break; + + case 0x63: /* MUL */ + Ins_MUL( args ); + break; + + case 0x64: /* ABS */ + Ins_ABS( args ); + break; + + case 0x65: /* NEG */ + Ins_NEG( args ); + break; + + case 0x66: /* FLOOR */ + Ins_FLOOR( args ); + break; + + case 0x67: /* CEILING */ + Ins_CEILING( args ); + break; + + case 0x68: /* ROUND */ + case 0x69: /* ROUND */ + case 0x6A: /* ROUND */ + case 0x6B: /* ROUND */ + Ins_ROUND( exc, args ); + break; + + case 0x6C: /* NROUND */ + case 0x6D: /* NROUND */ + case 0x6E: /* NRRUND */ + case 0x6F: /* NROUND */ + Ins_NROUND( exc, args ); + break; + + case 0x70: /* WCVTF */ + Ins_WCVTF( exc, args ); + break; + + case 0x71: /* DELTAP2 */ + case 0x72: /* DELTAP3 */ + Ins_DELTAP( exc, args ); + break; + + case 0x73: /* DELTAC0 */ + case 0x74: /* DELTAC1 */ + case 0x75: /* DELTAC2 */ + Ins_DELTAC( exc, args ); + break; + + case 0x76: /* SROUND */ + Ins_SROUND( exc, args ); + break; + + case 0x77: /* S45Round */ + Ins_S45ROUND( exc, args ); + break; + + case 0x78: /* JROT */ + Ins_JROT( exc, args ); + break; + + case 0x79: /* JROF */ + Ins_JROF( exc, args ); + break; + + case 0x7A: /* ROFF */ + Ins_ROFF( exc ); + break; + + case 0x7B: /* ???? */ + Ins_UNKNOWN( exc ); + break; + + case 0x7C: /* RUTG */ + Ins_RUTG( exc ); + break; + + case 0x7D: /* RDTG */ + Ins_RDTG( exc ); + break; + + case 0x7E: /* SANGW */ + Ins_SANGW(); + break; + + case 0x7F: /* AA */ + Ins_AA(); + break; + + case 0x80: /* FLIPPT */ + Ins_FLIPPT( exc ); + break; + + case 0x81: /* FLIPRGON */ + Ins_FLIPRGON( exc, args ); + break; + + case 0x82: /* FLIPRGOFF */ + Ins_FLIPRGOFF( exc, args ); + break; + + case 0x83: /* UNKNOWN */ + case 0x84: /* UNKNOWN */ + Ins_UNKNOWN( exc ); + break; + + case 0x85: /* SCANCTRL */ + Ins_SCANCTRL( exc, args ); + break; + + case 0x86: /* SDPvTL */ + case 0x87: /* SDPvTL */ + Ins_SDPVTL( exc, args ); + break; + + case 0x88: /* GETINFO */ + Ins_GETINFO( exc, args ); + break; + + case 0x89: /* IDEF */ + Ins_IDEF( exc, args ); + break; + + case 0x8A: /* ROLL */ + Ins_ROLL( args ); + break; + + case 0x8B: /* MAX */ + Ins_MAX( args ); + break; + + case 0x8C: /* MIN */ + Ins_MIN( args ); + break; + + case 0x8D: /* SCANTYPE */ + Ins_SCANTYPE( exc, args ); + break; + + case 0x8E: /* INSTCTRL */ + Ins_INSTCTRL( exc, args ); + break; + + case 0x8F: /* ADJUST */ + case 0x90: /* ADJUST */ + Ins_UNKNOWN( exc ); + break; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + case 0x91: + /* it is the job of the application to `activate' GX handling, */ + /* that is, calling any of the GX API functions on the current */ + /* font to select a variation instance */ + if ( exc->face->blend ) + Ins_GETVARIATION( exc, args ); + else + Ins_UNKNOWN( exc ); + break; + + case 0x92: + /* there is at least one MS font (LaoUI.ttf version 5.01) that */ + /* uses IDEFs for 0x91 and 0x92; for this reason we activate */ + /* GETDATA for GX fonts only, similar to GETVARIATION */ + if ( exc->face->blend ) + Ins_GETDATA( args ); + else + Ins_UNKNOWN( exc ); + break; +#endif + + default: + if ( opcode >= 0xE0 ) + Ins_MIRP( exc, args ); + else if ( opcode >= 0xC0 ) + Ins_MDRP( exc, args ); + else if ( opcode >= 0xB8 ) + Ins_PUSHW( exc, args ); + else if ( opcode >= 0xB0 ) + Ins_PUSHB( exc, args ); + else + Ins_UNKNOWN( exc ); + } + } + + if ( exc->error ) + { + switch ( exc->error ) + { + /* looking for redefined instructions */ + case FT_ERR( Invalid_Opcode ): + { + TT_DefRecord* def = exc->IDefs; + TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); + + + for ( ; def < limit; def++ ) + { + if ( def->active && exc->opcode == (FT_Byte)def->opc ) + { + TT_CallRec* callrec; + + + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Invalid_Reference ); + goto LErrorLabel_; + } + + callrec = &exc->callStack[exc->callTop]; + + callrec->Caller_Range = exc->curRange; + callrec->Caller_IP = exc->IP + 1; + callrec->Cur_Count = 1; + callrec->Def = def; + + if ( Ins_Goto_CodeRange( exc, + def->range, + def->start ) == FAILURE ) + goto LErrorLabel_; + + goto LSuiteLabel_; + } + } + } + + exc->error = FT_THROW( Invalid_Opcode ); + goto LErrorLabel_; + +#if 0 + break; /* Unreachable code warning suppression. */ + /* Leave to remind in case a later change the editor */ + /* to consider break; */ +#endif + + default: + goto LErrorLabel_; + +#if 0 + break; +#endif + } + } + + exc->top = exc->new_top; + + if ( exc->step_ins ) + exc->IP += exc->length; + + /* increment instruction counter and check if we didn't */ + /* run this program for too long (e.g. infinite loops). */ + if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) + { + exc->error = FT_THROW( Execution_Too_Long ); + goto LErrorLabel_; + } + + LSuiteLabel_: + if ( exc->IP >= exc->codeSize ) + { + if ( exc->callTop > 0 ) + { + exc->error = FT_THROW( Code_Overflow ); + goto LErrorLabel_; + } + else + goto LNo_Error_; + } + } while ( !exc->instruction_trap ); + + LNo_Error_: + FT_TRACE4(( " %ld instruction%s executed\n", + ins_counter, + ins_counter == 1 ? "" : "s" )); + + return FT_Err_Ok; + + LErrorCodeOverflow_: + exc->error = FT_THROW( Code_Overflow ); + + LErrorLabel_: + if ( exc->error && !exc->instruction_trap ) + FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error )); + + return exc->error; + } + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_interp_dummy_; + +#endif /* !TT_USE_BYTECODE_INTERPRETER */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttinterp.h b/vendor/freetype/src/truetype/ttinterp.h new file mode 100644 index 0000000..e98e258 --- /dev/null +++ b/vendor/freetype/src/truetype/ttinterp.h @@ -0,0 +1,465 @@ +/**************************************************************************** + * + * ttinterp.h + * + * TrueType bytecode interpreter (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTINTERP_H_ +#define TTINTERP_H_ + +#include "ttobjs.h" + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * Rounding mode constants. + */ +#define TT_Round_Off 5 +#define TT_Round_To_Half_Grid 0 +#define TT_Round_To_Grid 1 +#define TT_Round_To_Double_Grid 2 +#define TT_Round_Up_To_Grid 4 +#define TT_Round_Down_To_Grid 3 +#define TT_Round_Super 6 +#define TT_Round_Super_45 7 + + + /************************************************************************** + * + * Function types used by the interpreter, depending on various modes + * (e.g. the rounding mode, whether to render a vertical or horizontal + * line etc). + * + */ + + /* Rounding function */ + typedef FT_F26Dot6 + (*TT_Round_Func)( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ); + + /* Point displacement along the freedom vector routine */ + typedef void + (*TT_Move_Func)( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ); + + /* Distance projection along one of the projection vectors */ + typedef FT_F26Dot6 + (*TT_Project_Func)( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ); + + /* getting current ppem. Take care of non-square pixels if necessary */ + typedef FT_Long + (*TT_Cur_Ppem_Func)( TT_ExecContext exc ); + + /* reading a cvt value. Take care of non-square pixels if necessary */ + typedef FT_F26Dot6 + (*TT_Get_CVT_Func)( TT_ExecContext exc, + FT_ULong idx ); + + /* setting or moving a cvt value. Take care of non-square pixels */ + /* if necessary */ + typedef void + (*TT_Set_CVT_Func)( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ); + + + /************************************************************************** + * + * This structure defines a call record, used to manage function calls. + */ + typedef struct TT_CallRec_ + { + FT_Int Caller_Range; + FT_Long Caller_IP; + FT_Long Cur_Count; + + TT_DefRecord *Def; /* either FDEF or IDEF */ + + } TT_CallRec, *TT_CallStack; + + + /************************************************************************** + * + * The main structure for the interpreter which collects all necessary + * variables and states. + * + * Members that are initialized by `TT_Load_Context` are marked with '!'. + * Members that are initialized by `TT_Run_Context` are marked with '@'. + */ + typedef struct TT_ExecContextRec_ + { + TT_Face face; /* ! */ + TT_Size size; /* ! */ + FT_Memory memory; + + /* instructions state */ + + FT_Error error; /* last execution error */ + + FT_Long top; /* @ top of exec. stack */ + + FT_Long stackSize; /* ! size of exec. stack */ + FT_Long* stack; /* ! current exec. stack */ + + FT_Long args; + FT_Long new_top; /* new top after exec. */ + + TT_GlyphZoneRec zp0, /* @! zone records */ + zp1, /* @! */ + zp2, /* @! */ + pts, /* ! */ + twilight; /* ! */ + + FT_Long pointSize; /* ! in 26.6 format */ + FT_Size_Metrics metrics; /* ! */ + TT_Size_Metrics tt_metrics; /* ! size metrics */ + + TT_GraphicsState GS; /* !@ current graphics state */ + + FT_Int iniRange; /* initial code range number */ + FT_Int curRange; /* current code range number */ + FT_Byte* code; /* current code range */ + FT_Long IP; /* current instruction pointer */ + FT_Long codeSize; /* size of current range */ + + FT_Byte opcode; /* current opcode */ + FT_Int length; /* length of current opcode */ + + FT_Bool step_ins; /* true if the interpreter must */ + /* increment IP after ins. exec */ + FT_ULong cvtSize; /* ! */ + FT_Long* cvt; /* ! */ + FT_ULong glyfCvtSize; + FT_Long* glyfCvt; /* cvt working copy for glyph */ + + FT_UInt glyphSize; /* ! glyph instructions buffer size */ + FT_Byte* glyphIns; /* ! glyph instructions buffer */ + + FT_UInt numFDefs; /* ! number of function defs */ + FT_UInt maxFDefs; /* ! maximum number of function defs */ + TT_DefArray FDefs; /* table of FDefs entries */ + + FT_UInt numIDefs; /* ! number of instruction defs */ + FT_UInt maxIDefs; /* ! maximum number of ins defs */ + TT_DefArray IDefs; /* table of IDefs entries */ + + FT_UInt maxFunc; /* ! maximum function index */ + FT_UInt maxIns; /* ! maximum instruction index */ + + FT_Int callTop, /* @ top of call stack during execution */ + callSize; /* size of call stack */ + TT_CallStack callStack; /* call stack */ + + FT_UShort maxPoints; /* capacity of this context's `pts' */ + FT_Short maxContours; /* record, expressed in points and */ + /* contours. */ + + TT_CodeRangeTable codeRangeTable; /* ! table of valid code ranges */ + /* useful for the debugger */ + + FT_UShort storeSize; /* ! size of current storage */ + FT_Long* storage; /* ! storage area */ + FT_UShort glyfStoreSize; + FT_Long* glyfStorage; /* storage working copy for glyph */ + + FT_F26Dot6 period; /* values used for the */ + FT_F26Dot6 phase; /* `SuperRounding' */ + FT_F26Dot6 threshold; + + FT_Bool instruction_trap; /* ! If `True', the interpreter */ + /* exits after each instruction */ + + TT_GraphicsState default_GS; /* graphics state resulting from */ + /* the prep program */ + FT_Bool is_composite; /* true if the glyph is composite */ + FT_Bool pedantic_hinting; /* true if pedantic interpretation */ + + /* latest interpreter additions */ + + FT_Long F_dot_P; /* dot product of freedom and projection */ + /* vectors */ + TT_Round_Func func_round; /* current rounding function */ + + TT_Project_Func func_project, /* current projection function */ + func_dualproj, /* current dual proj. function */ + func_freeProj; /* current freedom proj. func */ + + TT_Move_Func func_move; /* current point move function */ + TT_Move_Func func_move_orig; /* move original position function */ + + TT_Cur_Ppem_Func func_cur_ppem; /* get current proj. ppem value */ + + TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */ + TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ + TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ + + FT_Bool grayscale; /* bi-level hinting and */ + /* grayscale rendering */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * FreeType supports ClearType-like hinting of TrueType fonts through + * the version 40 interpreter. This is achieved through several hacks + * in the base (v35) interpreter, as detailed below. + * + * ClearType is an umbrella term for several rendering techniques + * employed by Microsoft's various GUI and rendering toolkit + * implementations, most importantly: subpixel rendering for using the + * RGB subpixels of LCDs to approximately triple the perceived + * resolution on the x-axis and subpixel hinting for positioning stems + * on subpixel borders. TrueType programming is explicit, i.e., fonts + * must be programmed to take advantage of ClearType's possibilities. + * + * When ClearType was introduced, it seemed unlikely that all fonts + * would be reprogrammed, so Microsoft decided to implement a backward + * compatibility mode. It employs several simple to complicated + * assumptions and tricks, many of them font-dependent, that modify the + * interpretation of the bytecode contained in these fonts to retrofit + * them into a ClearType-y look. The quality of the results varies. + * Most (web)fonts that were released since then have come to rely on + * these hacks to render correctly, even some of Microsoft's flagship + * fonts (e.g., Calibri, Cambria, Segoe UI). + * + * FreeType's minimal subpixel hinting code (interpreter version 40) + * employs a small list of font-agnostic hacks loosely based on the + * public information available on Microsoft's compatibility mode[2]. + * The focus is on modern (web)fonts rather than legacy fonts that were + * made for monochrome rendering. It will not match ClearType rendering + * exactly. Unlike the `Infinality' code (interpreter version 38) that + * came before, it will not try to toggle hacks for specific fonts for + * performance and complexity reasons. It will fall back to version 35 + * behavior for tricky fonts[1] or when monochrome rendering is + * requested. + * + * Major hacks + * + * - Any point movement on the x axis is ignored (cf. `Direct_Move' and + * `Direct_Move_X'). This has the smallest code footprint and single + * biggest effect. The ClearType way to increase resolution is + * supersampling the x axis, the FreeType way is ignoring instructions + * on the x axis, which gives the same result in the majority of + * cases. + * + * - Points are not moved post-IUP (neither on the x nor on the y axis), + * except the x component of diagonal moves post-IUP (cf. + * `Direct_Move', `Direct_Move_Y', `Move_Zp2_Point'). Post-IUP + * changes are commonly used to `fix' pixel patterns which has little + * use outside monochrome rendering. + * + * - SHPIX and DELTAP don't execute unless moving a composite on the + * y axis or moving a previously y touched point. SHPIX additionally + * denies movement on the x axis (cf. `Ins_SHPIX' and `Ins_DELTAP'). + * Both instructions are commonly used to `fix' pixel patterns for + * monochrome or Windows's GDI rendering but make little sense for + * FreeType rendering. Both can distort the outline. See [2] for + * details. + * + * - The hdmx table and modifications to phantom points are ignored. + * Bearings and advance widths remain unchanged (except rounding them + * outside the interpreter!), cf. `compute_glyph_metrics' and + * `TT_Hint_Glyph'. Letting non-native-ClearType fonts modify spacing + * might mess up spacing. + * + * Minor hacks + * + * - FLIPRGON, FLIPRGOFF, and FLIPPT don't execute post-IUP. This + * prevents dents in e.g. Arial-Regular's `D' and `G' glyphs at + * various sizes. + * + * (Post-IUP is the state after both IUP[x] and IUP[y] have been + * executed.) + * + * The best results are achieved for fonts that were from the outset + * designed with ClearType in mind, meaning they leave the x axis mostly + * alone and don't mess with the `final' outline to produce more + * pleasing pixel patterns. The harder the designer tried to produce + * very specific patterns (`superhinting') for pre-ClearType-displays, + * the worse the results. + * + * Microsoft defines a way to turn off backward compatibility and + * interpret instructions as before (called `native ClearType')[2][3]. + * The font designer then regains full control and is responsible for + * making the font work correctly with ClearType without any + * hand-holding by the interpreter or rasterizer[4]. The v40 + * interpreter assumes backward compatibility by default, which can be + * turned off the same way by executing the following in the control + * program (cf. `Ins_INSTCTRL'). + * + * #PUSH 4,3 + * INSTCTRL[] + * + * [1] Tricky fonts as FreeType defines them rely on the bytecode + * interpreter to display correctly. Hacks can interfere with them, + * so they get treated like native ClearType fonts (v40 with + * backward compatibility turned off). Cf. `TT_RunIns'. + * + * [2] Proposed by Microsoft's Greg Hitchcock in + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + * + * [3] Beat Stamm describes it in more detail: + * http://rastertragedy.com/RTRCh4.htm#Sec12. + * + * [4] The list of `native ClearType' fonts is small at the time of this + * writing; I found the following on a Windows 10 Update 1511 + * installation: Constantia, Corbel, Sitka, Malgun Gothic, Microsoft + * JhengHei (Bold and UI Bold), Microsoft YaHei (Bold and UI Bold), + * SimSun, NSimSun, and Yu Gothic. + * + */ + + /* Using v40 implies subpixel hinting, unless FT_RENDER_MODE_MONO has been + * requested. Used to detect interpreter */ + /* version switches. `_lean' to differentiate from the Infinality */ + /* `subpixel_hinting', which is managed differently. */ + FT_Bool subpixel_hinting_lean; + + /* Long side of a LCD subpixel is vertical (e.g., screen is rotated). */ + /* `_lean' to differentiate from the Infinality `vertical_lcd', which */ + /* is managed differently. */ + FT_Bool vertical_lcd_lean; + + /* Default to backward compatibility mode in v40 interpreter. If */ + /* this is false, it implies the interpreter is in v35 or in native */ + /* ClearType mode. */ + FT_Bool backward_compatibility; + + /* Useful for detecting and denying post-IUP trickery that is usually */ + /* used to fix pixel patterns (`superhinting'). */ + FT_Bool iupx_called; + FT_Bool iupy_called; + + /* ClearType hinting and grayscale rendering, as used by Universal */ + /* Windows Platform apps (Windows 8 and above). Like the standard */ + /* colorful ClearType mode, it utilizes a vastly increased virtual */ + /* resolution on the x axis. Different from bi-level hinting and */ + /* grayscale rendering, the old mode from Win9x days that roughly */ + /* adheres to the physical pixel grid on both axes. */ + FT_Bool grayscale_cleartype; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ + + /* We maintain two counters (in addition to the instruction counter) */ + /* that act as loop detectors for LOOPCALL and jump opcodes with */ + /* negative arguments. */ + FT_ULong loopcall_counter; + FT_ULong loopcall_counter_max; + FT_ULong neg_jump_counter; + FT_ULong neg_jump_counter_max; + + } TT_ExecContextRec; + + + extern const TT_GraphicsState tt_default_graphics_state; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_LOCAL( void ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ); + + FT_LOCAL( void ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ); + + FT_LOCAL( void ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ); +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /************************************************************************** + * + * @Function: + * TT_New_Context + * + * @Description: + * Create a `TT_ExecContext`. Note that there is now an execution + * context per `TT_Size` that is not shared among faces. + * + * @Input: + * driver :: + * A handle to the driver, used for memory allocation. + * + * @Return: + * A handle to a new empty execution context. + * + * @Note: + * Only the glyph loader and debugger should call this function. + * (And right now only the glyph loader uses it.) + */ + FT_EXPORT( TT_ExecContext ) + TT_New_Context( TT_Driver driver ); + + +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_LOCAL( void ) + TT_Done_Context( TT_ExecContext exec ); + + FT_LOCAL( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ); + + FT_LOCAL( void ) + TT_Save_Context( TT_ExecContext exec, + TT_Size ins ); + + FT_LOCAL( FT_Error ) + TT_Run_Context( TT_ExecContext exec ); +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /************************************************************************** + * + * @Function: + * TT_RunIns + * + * @Description: + * Executes one or more instruction in the execution context. This + * is the main function of the TrueType opcode interpreter. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only the object manager and debugger should call this function. + * + * This function is publicly exported because it is directly + * invoked by the TrueType debugger. + */ + FT_EXPORT( FT_Error ) + TT_RunIns( void* exec ); + + +FT_END_HEADER + +#endif /* TTINTERP_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttobjs.c b/vendor/freetype/src/truetype/ttobjs.c new file mode 100644 index 0000000..5b56af7 --- /dev/null +++ b/vendor/freetype/src/truetype/ttobjs.c @@ -0,0 +1,1539 @@ +/**************************************************************************** + * + * ttobjs.c + * + * Objects manager (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "ttgload.h" +#include "ttpload.h" + +#include "tterrors.h" + +#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttobjs + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /************************************************************************** + * + * GLYPH ZONE FUNCTIONS + * + */ + + + /************************************************************************** + * + * @Function: + * tt_glyphzone_done + * + * @Description: + * Deallocate a glyph zone. + * + * @Input: + * zone :: + * A pointer to the target glyph zone. + */ + FT_LOCAL_DEF( void ) + tt_glyphzone_done( TT_GlyphZone zone ) + { + FT_Memory memory = zone->memory; + + + if ( memory ) + { + FT_FREE( zone->contours ); + FT_FREE( zone->tags ); + FT_FREE( zone->cur ); + FT_FREE( zone->org ); + FT_FREE( zone->orus ); + + zone->max_points = zone->n_points = 0; + zone->max_contours = zone->n_contours = 0; + zone->memory = NULL; + } + } + + + /************************************************************************** + * + * @Function: + * tt_glyphzone_new + * + * @Description: + * Allocate a new glyph zone. + * + * @Input: + * memory :: + * A handle to the current memory object. + * + * maxPoints :: + * The capacity of glyph zone in points. + * + * maxContours :: + * The capacity of glyph zone in contours. + * + * @Output: + * zone :: + * A pointer to the target glyph zone record. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone zone ) + { + FT_Error error; + + + FT_ZERO( zone ); + zone->memory = memory; + + if ( FT_NEW_ARRAY( zone->org, maxPoints ) || + FT_NEW_ARRAY( zone->cur, maxPoints ) || + FT_NEW_ARRAY( zone->orus, maxPoints ) || + FT_NEW_ARRAY( zone->tags, maxPoints ) || + FT_NEW_ARRAY( zone->contours, maxContours ) ) + { + tt_glyphzone_done( zone ); + } + else + { + zone->max_points = maxPoints; + zone->max_contours = maxContours; + } + + return error; + } + + + /* + * Fonts embedded in PDFs are made unique by prepending randomization + * prefixes to their names: as defined in Section 5.5.3, 'Font Subsets', + * of the PDF Reference, they consist of 6 uppercase letters followed by + * the `+` sign. For safety, we do not skip prefixes violating this rule. + */ + + static const FT_String* + tt_skip_pdffont_random_tag( const FT_String* name ) + { + unsigned int i; + + + if ( ft_strlen( name ) < 8 || name[6] != '+' ) + return name; + + for ( i = 0; i < 6; i++ ) + if ( !ft_isupper( name[i] ) ) + return name; + + FT_TRACE7(( "name without randomization tag: %s\n", name + 7 )); + return name + 7; + } + + + /* Compare the face with a list of well-known `tricky' fonts. */ + /* This list shall be expanded as we find more of them. */ + + static FT_Bool + tt_check_trickyness_family( const FT_String* name ) + { + +#define TRICK_NAMES_MAX_CHARACTERS 19 +#define TRICK_NAMES_COUNT 20 + + static const char trick_names[TRICK_NAMES_COUNT] + [TRICK_NAMES_MAX_CHARACTERS + 1] = + { + /* + PostScript names are given in brackets if they differ from the + family name. The version numbers, together with the copyright or + release year data, are taken from fonts available to the + developers. + + Note that later versions of the fonts might be no longer tricky; + for example, `MingLiU' version 7.00 (file `mingliu.ttc' from + Windows 7) is an ordinary TTC with non-tricky subfonts. + */ + + "cpop", /* dftt-p7.ttf; version 1.00, 1992 [DLJGyShoMedium] */ + "DFGirl-W6-WIN-BF", /* dftt-h6.ttf; version 1.00, 1993 */ + "DFGothic-EB", /* DynaLab Inc. 1992-1995 */ + "DFGyoSho-Lt", /* DynaLab Inc. 1992-1995 */ + "DFHei", /* DynaLab Inc. 1992-1995 [DFHei-Bd-WIN-HK-BF] */ + /* covers "DFHei-Md-HK-BF", maybe DynaLab Inc. */ + + "DFHSGothic-W5", /* DynaLab Inc. 1992-1995 */ + "DFHSMincho-W3", /* DynaLab Inc. 1992-1995 */ + "DFHSMincho-W7", /* DynaLab Inc. 1992-1995 */ + "DFKaiSho-SB", /* dfkaisb.ttf */ + "DFKaiShu", /* covers "DFKaiShu-Md-HK-BF", maybe DynaLab Inc. */ + "DFKai-SB", /* kaiu.ttf; version 3.00, 1998 [DFKaiShu-SB-Estd-BF] */ + + "DFMing", /* DynaLab Inc. 1992-1995 [DFMing-Md-WIN-HK-BF] */ + /* covers "DFMing-Bd-HK-BF", maybe DynaLab Inc. */ + + "DLC", /* dftt-m7.ttf; version 1.00, 1993 [DLCMingBold] */ + /* dftt-f5.ttf; version 1.00, 1993 [DLCFongSung] */ + /* covers following */ + /* "DLCHayMedium", dftt-b5.ttf; version 1.00, 1993 */ + /* "DLCHayBold", dftt-b7.ttf; version 1.00, 1993 */ + /* "DLCKaiMedium", dftt-k5.ttf; version 1.00, 1992 */ + /* "DLCLiShu", dftt-l5.ttf; version 1.00, 1992 */ + /* "DLCRoundBold", dftt-r7.ttf; version 1.00, 1993 */ + + "HuaTianKaiTi?", /* htkt2.ttf */ + "HuaTianSongTi?", /* htst3.ttf */ + "Ming(for ISO10646)", /* hkscsiic.ttf; version 0.12, 2007 [Ming] */ + /* iicore.ttf; version 0.07, 2007 [Ming] */ + "MingLiU", /* mingliu.ttf */ + /* mingliu.ttc; version 3.21, 2001 */ + "MingMedium", /* dftt-m5.ttf; version 1.00, 1993 [DLCMingMedium] */ + "PMingLiU", /* mingliu.ttc; version 3.21, 2001 */ + "MingLi43", /* mingli.ttf; version 1.00, 1992 */ + }; + + int nn; + const FT_String* name_without_tag; + + + name_without_tag = tt_skip_pdffont_random_tag( name ); + for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) + if ( ft_strstr( name_without_tag, trick_names[nn] ) ) + return TRUE; + + return FALSE; + } + + + /* XXX: This function should be in the `sfnt' module. */ + + /* Some PDF generators clear the checksums in the TrueType header table. */ + /* For example, Quartz ContextPDF clears all entries, or Bullzip PDF */ + /* Printer clears the entries for subsetted subtables. We thus have to */ + /* recalculate the checksums where necessary. */ + + static FT_UInt32 + tt_synth_sfnt_checksum( FT_Stream stream, + FT_ULong length ) + { + FT_Error error; + FT_UInt32 checksum = 0; + FT_UInt i; + + + if ( FT_FRAME_ENTER( length ) ) + return 0; + + for ( ; length > 3; length -= 4 ) + checksum += (FT_UInt32)FT_GET_ULONG(); + + for ( i = 3; length > 0; length--, i-- ) + checksum += (FT_UInt32)FT_GET_BYTE() << ( i * 8 ); + + FT_FRAME_EXIT(); + + return checksum; + } + + + /* XXX: This function should be in the `sfnt' module. */ + + static FT_ULong + tt_get_sfnt_checksum( TT_Face face, + FT_UShort i ) + { +#if 0 /* if we believe the written value, use following part. */ + if ( face->dir_tables[i].CheckSum ) + return face->dir_tables[i].CheckSum; +#endif + + if ( !face->goto_table ) + return 0; + + if ( face->goto_table( face, + face->dir_tables[i].Tag, + face->root.stream, + NULL ) ) + return 0; + + return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, + face->dir_tables[i].Length ); + } + + + typedef struct tt_sfnt_id_rec_ + { + FT_ULong CheckSum; + FT_ULong Length; + + } tt_sfnt_id_rec; + + + static FT_Bool + tt_check_trickyness_sfnt_ids( TT_Face face ) + { +#define TRICK_SFNT_IDS_PER_FACE 3 +#define TRICK_SFNT_IDS_NUM_FACES 31 + + static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] + [TRICK_SFNT_IDS_PER_FACE] = + { + +#define TRICK_SFNT_ID_cvt 0 +#define TRICK_SFNT_ID_fpgm 1 +#define TRICK_SFNT_ID_prep 2 + + { /* MingLiU 1995 */ + { 0x05BCF058UL, 0x000002E4UL }, /* cvt */ + { 0x28233BF1UL, 0x000087C4UL }, /* fpgm */ + { 0xA344A1EAUL, 0x000001E1UL } /* prep */ + }, + { /* MingLiU 1996- */ + { 0x05BCF058UL, 0x000002E4UL }, /* cvt */ + { 0x28233BF1UL, 0x000087C4UL }, /* fpgm */ + { 0xA344A1EBUL, 0x000001E1UL } /* prep */ + }, + { /* DFGothic-EB */ + { 0x12C3EBB2UL, 0x00000350UL }, /* cvt */ + { 0xB680EE64UL, 0x000087A7UL }, /* fpgm */ + { 0xCE939563UL, 0x00000758UL } /* prep */ + }, + { /* DFGyoSho-Lt */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0xCE5956E9UL, 0x0000BC85UL }, /* fpgm */ + { 0x8272F416UL, 0x00000045UL } /* prep */ + }, + { /* DFHei-Md-HK-BF */ + { 0x1257EB46UL, 0x00000350UL }, /* cvt */ + { 0xF699D160UL, 0x0000715FUL }, /* fpgm */ + { 0xD222F568UL, 0x000003BCUL } /* prep */ + }, + { /* DFHSGothic-W5 */ + { 0x1262EB4EUL, 0x00000350UL }, /* cvt */ + { 0xE86A5D64UL, 0x00007940UL }, /* fpgm */ + { 0x7850F729UL, 0x000005FFUL } /* prep */ + }, + { /* DFHSMincho-W3 */ + { 0x122DEB0AUL, 0x00000350UL }, /* cvt */ + { 0x3D16328AUL, 0x0000859BUL }, /* fpgm */ + { 0xA93FC33BUL, 0x000002CBUL } /* prep */ + }, + { /* DFHSMincho-W7 */ + { 0x125FEB26UL, 0x00000350UL }, /* cvt */ + { 0xA5ACC982UL, 0x00007EE1UL }, /* fpgm */ + { 0x90999196UL, 0x0000041FUL } /* prep */ + }, + { /* DFKaiShu */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0x5A30CA3BUL, 0x00009063UL }, /* fpgm */ + { 0x13A42602UL, 0x0000007EUL } /* prep */ + }, + { /* DFKaiShu, variant */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0xA6E78C01UL, 0x00008998UL }, /* fpgm */ + { 0x13A42602UL, 0x0000007EUL } /* prep */ + }, + { /* DFKaiShu-Md-HK-BF */ + { 0x11E5EAD4UL, 0x00000360UL }, /* cvt */ + { 0x9DB282B2UL, 0x0000C06EUL }, /* fpgm */ + { 0x53E6D7CAUL, 0x00000082UL } /* prep */ + }, + { /* DFMing-Bd-HK-BF */ + { 0x1243EB18UL, 0x00000350UL }, /* cvt */ + { 0xBA0A8C30UL, 0x000074ADUL }, /* fpgm */ + { 0xF3D83409UL, 0x0000037BUL } /* prep */ + }, + { /* DLCLiShu */ + { 0x07DCF546UL, 0x00000308UL }, /* cvt */ + { 0x40FE7C90UL, 0x00008E2AUL }, /* fpgm */ + { 0x608174B5UL, 0x0000007AUL } /* prep */ + }, + { /* DLCHayBold */ + { 0xEB891238UL, 0x00000308UL }, /* cvt */ + { 0xD2E4DCD4UL, 0x0000676FUL }, /* fpgm */ + { 0x8EA5F293UL, 0x000003B8UL } /* prep */ + }, + { /* HuaTianKaiTi */ + { 0xFFFBFFFCUL, 0x00000008UL }, /* cvt */ + { 0x9C9E48B8UL, 0x0000BEA2UL }, /* fpgm */ + { 0x70020112UL, 0x00000008UL } /* prep */ + }, + { /* HuaTianSongTi */ + { 0xFFFBFFFCUL, 0x00000008UL }, /* cvt */ + { 0x0A5A0483UL, 0x00017C39UL }, /* fpgm */ + { 0x70020112UL, 0x00000008UL } /* prep */ + }, + { /* NEC fadpop7.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x40C92555UL, 0x000000E5UL }, /* fpgm */ + { 0xA39B58E3UL, 0x0000117CUL } /* prep */ + }, + { /* NEC fadrei5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x33C41652UL, 0x000000E5UL }, /* fpgm */ + { 0x26D6C52AUL, 0x00000F6AUL } /* prep */ + }, + { /* NEC fangot7.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x6DB1651DUL, 0x0000019DUL }, /* fpgm */ + { 0x6C6E4B03UL, 0x00002492UL } /* prep */ + }, + { /* NEC fangyo5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x40C92555UL, 0x000000E5UL }, /* fpgm */ + { 0xDE51FAD0UL, 0x0000117CUL } /* prep */ + }, + { /* NEC fankyo5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x85E47664UL, 0x000000E5UL }, /* fpgm */ + { 0xA6C62831UL, 0x00001CAAUL } /* prep */ + }, + { /* NEC fanrgo5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x2D891CFDUL, 0x0000019DUL }, /* fpgm */ + { 0xA0604633UL, 0x00001DE8UL } /* prep */ + }, + { /* NEC fangot5.ttc */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x40AA774CUL, 0x000001CBUL }, /* fpgm */ + { 0x9B5CAA96UL, 0x00001F9AUL } /* prep */ + }, + { /* NEC fanmin3.ttc */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x0D3DE9CBUL, 0x00000141UL }, /* fpgm */ + { 0xD4127766UL, 0x00002280UL } /* prep */ + }, + { /* NEC FA-Gothic, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x4A692698UL, 0x000001F0UL }, /* fpgm */ + { 0x340D4346UL, 0x00001FCAUL } /* prep */ + }, + { /* NEC FA-Minchou, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0xCD34C604UL, 0x00000166UL }, /* fpgm */ + { 0x6CF31046UL, 0x000022B0UL } /* prep */ + }, + { /* NEC FA-RoundGothicB, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x5DA75315UL, 0x0000019DUL }, /* fpgm */ + { 0x40745A5FUL, 0x000022E0UL } /* prep */ + }, + { /* NEC FA-RoundGothicM, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0xF055FC48UL, 0x000001C2UL }, /* fpgm */ + { 0x3900DED3UL, 0x00001E18UL } /* prep */ + }, + { /* MINGLI.TTF, 1992 */ + { 0x00170003UL, 0x00000060UL }, /* cvt */ + { 0xDBB4306EUL, 0x000058AAUL }, /* fpgm */ + { 0xD643482AUL, 0x00000035UL } /* prep */ + }, + { /* DFHei-Bd-WIN-HK-BF, issue #1087 */ + { 0x1269EB58UL, 0x00000350UL }, /* cvt */ + { 0x5CD5957AUL, 0x00006A4EUL }, /* fpgm */ + { 0xF758323AUL, 0x00000380UL } /* prep */ + }, + { /* DFMing-Md-WIN-HK-BF, issue #1087 */ + { 0x122FEB0BUL, 0x00000350UL }, /* cvt */ + { 0x7F10919AUL, 0x000070A9UL }, /* fpgm */ + { 0x7CD7E7B7UL, 0x0000025CUL } /* prep */ + } + }; + + FT_ULong checksum; + int num_matched_ids[TRICK_SFNT_IDS_NUM_FACES]; + FT_Bool has_cvt, has_fpgm, has_prep; + FT_UShort i; + int j, k; + + + FT_MEM_SET( num_matched_ids, 0, + sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES ); + has_cvt = FALSE; + has_fpgm = FALSE; + has_prep = FALSE; + + for ( i = 0; i < face->num_tables; i++ ) + { + checksum = 0; + + switch( face->dir_tables[i].Tag ) + { + case TTAG_cvt: + k = TRICK_SFNT_ID_cvt; + has_cvt = TRUE; + break; + + case TTAG_fpgm: + k = TRICK_SFNT_ID_fpgm; + has_fpgm = TRUE; + break; + + case TTAG_prep: + k = TRICK_SFNT_ID_prep; + has_prep = TRUE; + break; + + default: + continue; + } + + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + if ( face->dir_tables[i].Length == sfnt_id[j][k].Length ) + { + if ( !checksum ) + checksum = tt_get_sfnt_checksum( face, i ); + + if ( sfnt_id[j][k].CheckSum == checksum ) + num_matched_ids[j]++; + + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + } + + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + { + if ( !has_cvt && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length ) + num_matched_ids[j]++; + if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length ) + num_matched_ids[j]++; + if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length ) + num_matched_ids[j]++; + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + + return FALSE; + } + + + static FT_Bool + tt_check_trickyness( FT_Face face ) + { + if ( !face ) + return FALSE; + + /* For first, check the face name for quick check. */ + if ( face->family_name && + tt_check_trickyness_family( face->family_name ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its family name: %s\n", face->family_name )); + return TRUE; + } + + /* Type42 fonts may lack `name' tables, we thus try to identify */ + /* tricky fonts by checking the checksums of Type42-persistent */ + /* sfnt tables (`cvt', `fpgm', and `prep'). */ + if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its cvt/fpgm/prep table checksum\n" )); + return TRUE; + } + + return FALSE; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /* Check whether `.notdef' is the only glyph in the `loca' table. */ + static FT_Bool + tt_check_single_notdef( FT_Face ttface ) + { + FT_Bool result = FALSE; + + TT_Face face = (TT_Face)ttface; + FT_ULong asize; + FT_ULong i; + FT_ULong glyph_index = 0; + FT_UInt count = 0; + + + for( i = 0; i < face->num_locations; i++ ) + { + tt_face_get_location( ttface, i, &asize ); + if ( asize > 0 ) + { + count += 1; + if ( count > 1 ) + break; + glyph_index = i; + } + } + + /* Only have a single outline. */ + if ( count == 1 ) + { + if ( glyph_index == 0 ) + result = TRUE; + else + { + /* FIXME: Need to test glyphname == .notdef ? */ + FT_Error error; + char buf[8]; + + + error = FT_Get_Glyph_Name( ttface, glyph_index, buf, 8 ); + if ( !error && + buf[0] == '.' && !ft_strncmp( buf, ".notdef", 8 ) ) + result = TRUE; + } + } + + return result; + } + + + /************************************************************************** + * + * @Function: + * tt_face_init + * + * @Description: + * Initialize a given TrueType face object. + * + * @Input: + * stream :: + * The source font stream. + * + * face_index :: + * The index of the TrueType font, if we are opening a + * collection, in bits 0-15. The numbered instance + * index~+~1 of a GX (sub)font, if applicable, in bits + * 16-30. + * + * num_params :: + * Number of additional generic parameters. Ignored. + * + * params :: + * Additional generic parameters. Ignored. + * + * @InOut: + * face :: + * The newly built face object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_init( FT_Stream stream, + FT_Face ttface, /* TT_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library; + SFNT_Service sfnt; + TT_Face face = (TT_Face)ttface; + + + FT_TRACE2(( "TTF driver\n" )); + + library = ttface->driver->root.library; + + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "tt_face_init: cannot access `sfnt' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + /* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + /* check that we have a valid TrueType file */ + FT_TRACE2(( " " )); + error = sfnt->init_face( stream, face, face_index, num_params, params ); + + /* Stream may have changed. */ + stream = face->root.stream; + + if ( error ) + goto Exit; + + /* We must also be able to accept Mac/GX fonts, as well as OT ones. */ + /* The 0x00020000 tag is completely undocumented; some fonts from */ + /* Arphic made for Chinese Windows 3.1 have this. */ + if ( face->format_tag != 0x00010000L && /* MS fonts */ + face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ + face->format_tag != TTAG_true && /* Mac fonts */ + face->format_tag != TTAG_0xA5kbd && /* `Keyboard.dfont' (legacy Mac OS X) */ + face->format_tag != TTAG_0xA5lst ) /* `LastResort.dfont' (legacy Mac OS X) */ + { + FT_TRACE2(( " not a TTF font\n" )); + goto Bad_Format; + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + ttface->face_flags |= FT_FACE_FLAG_HINTER; +#endif + + /* If we are performing a simple font format check, exit immediately. */ + if ( face_index < 0 ) + return FT_Err_Ok; + + /* Load font directory */ + error = sfnt->load_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; + +#ifdef TT_USE_BYTECODE_INTERPRETER + if ( tt_check_trickyness( ttface ) ) + ttface->face_flags |= FT_FACE_FLAG_TRICKY; +#endif + + error = tt_face_load_hdmx( face, stream ); + if ( error ) + goto Exit; + + if ( FT_IS_SCALABLE( ttface ) || + FT_HAS_SBIX( ttface ) ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( !ttface->internal->incremental_interface ) +#endif + { + error = tt_face_load_loca( face, stream ); + + /* having a (non-zero) `glyf' table without */ + /* a `loca' table is not valid */ + if ( face->glyf_len && FT_ERR_EQ( error, Table_Missing ) ) + goto Exit; + if ( error ) + goto Exit; + } + + /* `fpgm', `cvt', and `prep' are optional */ + error = tt_face_load_cvt( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + error = tt_face_load_fpgm( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + error = tt_face_load_prep( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + /* Check the scalable flag based on `loca'. */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( !ttface->internal->incremental_interface ) +#endif + { + if ( ttface->num_fixed_sizes && + face->glyph_locations && + tt_check_single_notdef( ttface ) ) + { + FT_TRACE5(( "tt_face_init:" + " Only the `.notdef' glyph has an outline.\n" )); + FT_TRACE5(( " " + " Resetting scalable flag to FALSE.\n" )); + + ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + } + } + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_UInt instance_index = (FT_UInt)face_index >> 16; + + + if ( FT_HAS_MULTIPLE_MASTERS( ttface ) && + instance_index > 0 ) + { + error = FT_Set_Named_Instance( ttface, instance_index ); + if ( error ) + goto Exit; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* initialize standard glyph loading routines */ + TT_Init_Glyph_Loading( face ); + + Exit: + return error; + + Bad_Format: + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + + /************************************************************************** + * + * @Function: + * tt_face_done + * + * @Description: + * Finalize a given face object. + * + * @Input: + * face :: + * A pointer to the face object to destroy. + */ + FT_LOCAL_DEF( void ) + tt_face_done( FT_Face ttface ) /* TT_Face */ + { + TT_Face face = (TT_Face)ttface; + FT_Memory memory; + FT_Stream stream; + SFNT_Service sfnt; + + + if ( !face ) + return; + + memory = ttface->memory; + stream = ttface->stream; + sfnt = (SFNT_Service)face->sfnt; + + /* for `extended TrueType formats' (i.e. compressed versions) */ + if ( face->extra.finalizer ) + face->extra.finalizer( face->extra.data ); + + if ( sfnt ) + sfnt->done_face( face ); + + /* freeing the locations table */ + tt_face_done_loca( face ); + + tt_face_free_hdmx( face ); + + /* freeing the CVT */ + FT_FREE( face->cvt ); + face->cvt_size = 0; + + /* freeing the programs */ + FT_FRAME_RELEASE( face->font_program ); + FT_FRAME_RELEASE( face->cvt_program ); + face->font_program_size = 0; + face->cvt_program_size = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + tt_done_blend( ttface ); + face->blend = NULL; +#endif + } + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /************************************************************************** + * + * @Function: + * tt_size_run_fpgm + * + * @Description: + * Run the font program. + * + * @Input: + * size :: + * A handle to the size object. + * + * pedantic :: + * Set if bytecode execution should be pedantic. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; + + + exec = size->context; + + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + + exec->callTop = 0; + exec->top = 0; + + exec->period = 64; + exec->phase = 0; + exec->threshold = 0; + + exec->instruction_trap = FALSE; + exec->F_dot_P = 0x4000L; + + exec->pedantic_hinting = pedantic; + + { + FT_Size_Metrics* size_metrics = &exec->metrics; + TT_Size_Metrics* tt_metrics = &exec->tt_metrics; + + + size_metrics->x_ppem = 0; + size_metrics->y_ppem = 0; + size_metrics->x_scale = 0; + size_metrics->y_scale = 0; + + tt_metrics->ppem = 0; + tt_metrics->scale = 0; + tt_metrics->ratio = 0x10000L; + } + + /* allow font program execution */ + TT_Set_CodeRange( exec, + tt_coderange_font, + face->font_program, + (FT_Long)face->font_program_size ); + + /* disable CVT and glyph programs coderange */ + TT_Clear_CodeRange( exec, tt_coderange_cvt ); + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + if ( face->font_program_size > 0 ) + { + TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); + + FT_TRACE4(( "Executing `fpgm' table.\n" )); + error = face->interpreter( exec ); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE4(( " interpretation failed with error code 0x%x\n", + error )); +#endif + } + else + error = FT_Err_Ok; + + size->bytecode_ready = error; + + if ( !error ) + TT_Save_Context( exec, size ); + + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_size_run_prep + * + * @Description: + * Run the control value program. + * + * @Input: + * size :: + * A handle to the size object. + * + * pedantic :: + * Set if bytecode execution should be pedantic. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; + FT_UInt i; + + /* unscaled CVT values are already stored in 26.6 format */ + FT_Fixed scale = size->ttmetrics.scale >> 6; + + + /* Scale the cvt values to the new ppem. */ + /* By default, we use the y ppem value for scaling. */ + FT_TRACE6(( "CVT values:\n" )); + for ( i = 0; i < size->cvt_size; i++ ) + { + size->cvt[i] = FT_MulFix( face->cvt[i], scale ); + FT_TRACE6(( " %3d: %f (%f)\n", + i, (double)face->cvt[i] / 64, (double)size->cvt[i] / 64 )); + } + FT_TRACE6(( "\n" )); + + exec = size->context; + + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + + exec->callTop = 0; + exec->top = 0; + + exec->instruction_trap = FALSE; + + exec->pedantic_hinting = pedantic; + + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + (FT_Long)face->cvt_program_size ); + + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + if ( face->cvt_program_size > 0 ) + { + TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + + FT_TRACE4(( "Executing `prep' table.\n" )); + error = face->interpreter( exec ); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE4(( " interpretation failed with error code 0x%x\n", + error )); +#endif + } + else + error = FT_Err_Ok; + + size->cvt_ready = error; + + /* UNDOCUMENTED! The MS rasterizer doesn't allow the following */ + /* graphics state variables to be modified by the CVT program. */ + + exec->GS.dualVector.x = 0x4000; + exec->GS.dualVector.y = 0; + exec->GS.projVector.x = 0x4000; + exec->GS.projVector.y = 0x0; + exec->GS.freeVector.x = 0x4000; + exec->GS.freeVector.y = 0x0; + + exec->GS.rp0 = 0; + exec->GS.rp1 = 0; + exec->GS.rp2 = 0; + + exec->GS.gep0 = 1; + exec->GS.gep1 = 1; + exec->GS.gep2 = 1; + + exec->GS.loop = 1; + + /* save as default graphics state */ + size->GS = exec->GS; + + TT_Save_Context( exec, size ); + + return error; + } + + + static void + tt_size_done_bytecode( FT_Size ftsize ) + { + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + + if ( size->context ) + { + TT_Done_Context( size->context ); + size->context = NULL; + } + + FT_FREE( size->cvt ); + size->cvt_size = 0; + + /* free storage area */ + FT_FREE( size->storage ); + size->storage_size = 0; + + /* twilight zone */ + tt_glyphzone_done( &size->twilight ); + + FT_FREE( size->function_defs ); + FT_FREE( size->instruction_defs ); + + size->num_function_defs = 0; + size->max_function_defs = 0; + size->num_instruction_defs = 0; + size->max_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + + size->bytecode_ready = -1; + size->cvt_ready = -1; + } + + + /* Initialize bytecode-related fields in the size object. */ + /* We do this only if bytecode interpretation is really needed. */ + static FT_Error + tt_size_init_bytecode( FT_Size ftsize, + FT_Bool pedantic ) + { + FT_Error error; + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + + FT_UShort n_twilight; + TT_MaxProfile* maxp = &face->max_profile; + + + /* clean up bytecode related data */ + FT_FREE( size->function_defs ); + FT_FREE( size->instruction_defs ); + FT_FREE( size->cvt ); + FT_FREE( size->storage ); + + if ( size->context ) + TT_Done_Context( size->context ); + tt_glyphzone_done( &size->twilight ); + + size->bytecode_ready = -1; + size->cvt_ready = -1; + + size->context = TT_New_Context( (TT_Driver)face->root.driver ); + + size->max_function_defs = maxp->maxFunctionDefs; + size->max_instruction_defs = maxp->maxInstructionDefs; + + size->num_function_defs = 0; + size->num_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + + size->cvt_size = face->cvt_size; + size->storage_size = maxp->maxStorage; + + /* Set default metrics */ + { + TT_Size_Metrics* tt_metrics = &size->ttmetrics; + + + tt_metrics->rotated = FALSE; + tt_metrics->stretched = FALSE; + + /* Set default engine compensation. Value 3 is not described */ + /* in the OpenType specification (as of Mai 2019), but Greg */ + /* says that MS handles it the same as `gray'. */ + /* */ + /* The Apple specification says that the compensation for */ + /* `gray' is always zero. FreeType doesn't do any */ + /* compensation at all. */ + tt_metrics->compensations[0] = 0; /* gray */ + tt_metrics->compensations[1] = 0; /* black */ + tt_metrics->compensations[2] = 0; /* white */ + tt_metrics->compensations[3] = 0; /* zero */ + } + + /* allocate function defs, instruction defs, cvt, and storage area */ + if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || + FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || + FT_NEW_ARRAY( size->cvt, size->cvt_size ) || + FT_NEW_ARRAY( size->storage, size->storage_size ) ) + goto Exit; + + /* reserve twilight zone */ + n_twilight = maxp->maxTwilightPoints; + + /* there are 4 phantom points (do we need this?) */ + n_twilight += 4; + + error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight ); + if ( error ) + goto Exit; + + size->twilight.n_points = n_twilight; + + size->GS = tt_default_graphics_state; + + /* set `face->interpreter' according to the debug hook present */ + { + FT_Library library = face->root.driver->root.library; + + + face->interpreter = (TT_Interpreter) + library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; + if ( !face->interpreter ) + face->interpreter = (TT_Interpreter)TT_RunIns; + } + + /* Fine, now run the font program! */ + + /* In case of an error while executing `fpgm', we intentionally don't */ + /* clean up immediately – bugs in the `fpgm' are so fundamental that */ + /* all following hinting calls should fail. Additionally, `fpgm' is */ + /* to be executed just once; calling it again is completely useless */ + /* and might even lead to extremely slow behaviour if it is malformed */ + /* (containing an infinite loop, for example). */ + error = tt_size_run_fpgm( size, pedantic ); + return error; + + Exit: + if ( error ) + tt_size_done_bytecode( ftsize ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ) + { + FT_Error error = FT_Err_Ok; + + + if ( size->bytecode_ready < 0 ) + error = tt_size_init_bytecode( (FT_Size)size, pedantic ); + else + error = size->bytecode_ready; + + if ( error ) + goto Exit; + + /* rescale CVT when needed */ + if ( size->cvt_ready < 0 ) + { + FT_UShort i; + + + /* all twilight points are originally zero */ + for ( i = 0; i < size->twilight.n_points; i++ ) + { + size->twilight.org[i].x = 0; + size->twilight.org[i].y = 0; + size->twilight.cur[i].x = 0; + size->twilight.cur[i].y = 0; + } + + /* clear storage area */ + for ( i = 0; i < size->storage_size; i++ ) + size->storage[i] = 0; + + size->GS = tt_default_graphics_state; + + error = tt_size_run_prep( size, pedantic ); + } + else + error = size->cvt_ready; + + Exit: + return error; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /************************************************************************** + * + * @Function: + * tt_size_init + * + * @Description: + * Initialize a new TrueType size object. + * + * @InOut: + * size :: + * A handle to the size object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_init( FT_Size ttsize ) /* TT_Size */ + { + TT_Size size = (TT_Size)ttsize; + FT_Error error = FT_Err_Ok; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + size->bytecode_ready = -1; + size->cvt_ready = -1; +#endif + + size->ttmetrics.valid = FALSE; + size->strike_index = 0xFFFFFFFFUL; + + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_size_done + * + * @Description: + * The TrueType size object finalizer. + * + * @Input: + * size :: + * A handle to the target size object. + */ + FT_LOCAL_DEF( void ) + tt_size_done( FT_Size ttsize ) /* TT_Size */ + { + TT_Size size = (TT_Size)ttsize; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + tt_size_done_bytecode( ttsize ); +#endif + + size->ttmetrics.valid = FALSE; + } + + + /************************************************************************** + * + * @Function: + * tt_size_reset_height + * + * @Description: + * Recompute a TrueType size's ascender, descender, and height + * when resolutions and character dimensions have been changed. + * Used for variation fonts as an iterator function. + * + * @Input: + * ft_size :: + * A handle to the target TT_Size object. This function will be called + * through a `FT_Size_Reset_Func` pointer which takes `FT_Size`. This + * function must take `FT_Size` as a result. The passed `FT_Size` is + * expected to point to a `TT_Size`. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_reset_height( FT_Size ft_size ) + { + TT_Size size = (TT_Size)ft_size; + TT_Face face = (TT_Face)size->root.face; + FT_Size_Metrics* size_metrics = &size->hinted_metrics; + + size->ttmetrics.valid = FALSE; + + /* copy the result from base layer */ + *size_metrics = size->root.metrics; + + if ( size_metrics->x_ppem < 1 || size_metrics->y_ppem < 1 ) + return FT_THROW( Invalid_PPem ); + + /* This bit flag, if set, indicates that the ppems must be */ + /* rounded to integers. Nearly all TrueType fonts have this bit */ + /* set, as hinting won't work really well otherwise. */ + /* */ + if ( face->header.Flags & 8 ) + { + /* the TT spec always asks for ROUND, not FLOOR or CEIL */ + size_metrics->ascender = FT_PIX_ROUND( + FT_MulFix( face->root.ascender, + size_metrics->y_scale ) ); + size_metrics->descender = FT_PIX_ROUND( + FT_MulFix( face->root.descender, + size_metrics->y_scale ) ); + size_metrics->height = FT_PIX_ROUND( + FT_MulFix( face->root.height, + size_metrics->y_scale ) ); + } + + size->ttmetrics.valid = TRUE; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_size_reset + * + * @Description: + * Reset a TrueType size when resolutions and character dimensions + * have been changed. + * + * @Input: + * size :: + * A handle to the target size object. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_reset( TT_Size size ) + { + FT_Error error; + TT_Face face = (TT_Face)size->root.face; + FT_Size_Metrics* size_metrics = &size->hinted_metrics; + + + error = tt_size_reset_height( (FT_Size)size ); + if ( error ) + return error; + + if ( face->header.Flags & 8 ) + { + /* base scaling values on integer ppem values, */ + /* as mandated by the TrueType specification */ + size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6, + face->root.units_per_EM ); + size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6, + face->root.units_per_EM ); + + size_metrics->max_advance = FT_PIX_ROUND( + FT_MulFix( face->root.max_advance_width, + size_metrics->x_scale ) ); + } + + /* compute new transformation */ + if ( size_metrics->x_ppem >= size_metrics->y_ppem ) + { + size->ttmetrics.scale = size_metrics->x_scale; + size->ttmetrics.ppem = size_metrics->x_ppem; + size->ttmetrics.x_ratio = 0x10000L; + size->ttmetrics.y_ratio = FT_DivFix( size_metrics->y_ppem, + size_metrics->x_ppem ); + } + else + { + size->ttmetrics.scale = size_metrics->y_scale; + size->ttmetrics.ppem = size_metrics->y_ppem; + size->ttmetrics.x_ratio = FT_DivFix( size_metrics->x_ppem, + size_metrics->y_ppem ); + size->ttmetrics.y_ratio = 0x10000L; + } + + size->widthp = tt_face_get_device_metrics( face, size_metrics->x_ppem, 0 ); + + size->metrics = size_metrics; + +#ifdef TT_USE_BYTECODE_INTERPRETER + size->cvt_ready = -1; +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_driver_init + * + * @Description: + * Initialize a given TrueType driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_driver_init( FT_Module ttdriver ) /* TT_Driver */ + { + +#ifdef TT_USE_BYTECODE_INTERPRETER + + TT_Driver driver = (TT_Driver)ttdriver; + + driver->interpreter_version = TT_INTERPRETER_VERSION_35; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + driver->interpreter_version = TT_INTERPRETER_VERSION_40; +#endif + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( ttdriver ); + +#endif /* !TT_USE_BYTECODE_INTERPRETER */ + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_driver_done + * + * @Description: + * Finalize a given TrueType driver. + * + * @Input: + * driver :: + * A handle to the target TrueType driver. + */ + FT_LOCAL_DEF( void ) + tt_driver_done( FT_Module ttdriver ) /* TT_Driver */ + { + FT_UNUSED( ttdriver ); + } + + + /************************************************************************** + * + * @Function: + * tt_slot_init + * + * @Description: + * Initialize a new slot object. + * + * @InOut: + * slot :: + * A handle to the slot object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ) + { + return FT_GlyphLoader_CreateExtra( slot->internal->loader ); + } + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttobjs.h b/vendor/freetype/src/truetype/ttobjs.h new file mode 100644 index 0000000..40eb37b --- /dev/null +++ b/vendor/freetype/src/truetype/ttobjs.h @@ -0,0 +1,426 @@ +/**************************************************************************** + * + * ttobjs.h + * + * Objects manager (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTOBJS_H_ +#define TTOBJS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Type: + * TT_Driver + * + * @Description: + * A handle to a TrueType driver object. + */ + typedef struct TT_DriverRec_* TT_Driver; + + + /************************************************************************** + * + * @Type: + * TT_GlyphSlot + * + * @Description: + * A handle to a TrueType glyph slot object. + * + * @Note: + * This is a direct typedef of FT_GlyphSlot, as there is nothing + * specific about the TrueType glyph slot. + */ + typedef FT_GlyphSlot TT_GlyphSlot; + + + /************************************************************************** + * + * @Struct: + * TT_GraphicsState + * + * @Description: + * The TrueType graphics state used during bytecode interpretation. + */ + typedef struct TT_GraphicsState_ + { + FT_UShort rp0; + FT_UShort rp1; + FT_UShort rp2; + + FT_UnitVector dualVector; + FT_UnitVector projVector; + FT_UnitVector freeVector; + + FT_Long loop; + FT_F26Dot6 minimum_distance; + FT_Int round_state; + + FT_Bool auto_flip; + FT_F26Dot6 control_value_cutin; + FT_F26Dot6 single_width_cutin; + FT_F26Dot6 single_width_value; + FT_UShort delta_base; + FT_UShort delta_shift; + + FT_Byte instruct_control; + /* According to Greg Hitchcock from Microsoft, the `scan_control' */ + /* variable as documented in the TrueType specification is a 32-bit */ + /* integer; the high-word part holds the SCANTYPE value, the low-word */ + /* part the SCANCTRL value. We separate it into two fields. */ + FT_Bool scan_control; + FT_Int scan_type; + + FT_UShort gep0; + FT_UShort gep1; + FT_UShort gep2; + + } TT_GraphicsState; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_LOCAL( void ) + tt_glyphzone_done( TT_GlyphZone zone ); + + FT_LOCAL( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone zone ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + + /************************************************************************** + * + * EXECUTION SUBTABLES + * + * These sub-tables relate to instruction execution. + * + */ + + +#define TT_MAX_CODE_RANGES 3 + + + /************************************************************************** + * + * There can only be 3 active code ranges at once: + * - the Font Program + * - the CVT Program + * - a glyph's instructions set + */ + typedef enum TT_CodeRange_Tag_ + { + tt_coderange_none = 0, + tt_coderange_font, + tt_coderange_cvt, + tt_coderange_glyph + + } TT_CodeRange_Tag; + + + typedef struct TT_CodeRange_ + { + FT_Byte* base; + FT_Long size; + + } TT_CodeRange; + + typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; + + + /************************************************************************** + * + * Defines a function/instruction definition record. + */ + typedef struct TT_DefRecord_ + { + FT_Int range; /* in which code range is it located? */ + FT_Long start; /* where does it start? */ + FT_Long end; /* where does it end? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ + + } TT_DefRecord, *TT_DefArray; + + + /************************************************************************** + * + * Subglyph transformation record. + */ + typedef struct TT_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } TT_Transform; + + + /************************************************************************** + * + * A note regarding non-squared pixels: + * + * (This text will probably go into some docs at some time; for now, it + * is kept here to explain some definitions in the TT_Size_Metrics + * record). + * + * The CVT is a one-dimensional array containing values that control + * certain important characteristics in a font, like the height of all + * capitals, all lowercase letter, default spacing or stem width/height. + * + * These values are found in FUnits in the font file, and must be scaled + * to pixel coordinates before being used by the CVT and glyph programs. + * Unfortunately, when using distinct x and y resolutions (or distinct x + * and y pointsizes), there are two possible scalings. + * + * A first try was to implement a `lazy' scheme where all values were + * scaled when first used. However, while some values are always used + * in the same direction, some others are used under many different + * circumstances and orientations. + * + * I have found a simpler way to do the same, and it even seems to work + * in most of the cases: + * + * - All CVT values are scaled to the maximum ppem size. + * + * - When performing a read or write in the CVT, a ratio factor is used + * to perform adequate scaling. Example: + * + * x_ppem = 14 + * y_ppem = 10 + * + * We choose ppem = x_ppem = 14 as the CVT scaling size. All cvt + * entries are scaled to it. + * + * x_ratio = 1.0 + * y_ratio = y_ppem/ppem (< 1.0) + * + * We compute the current ratio like: + * + * - If projVector is horizontal, + * ratio = x_ratio = 1.0 + * + * - if projVector is vertical, + * ratio = y_ratio + * + * - else, + * ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) + * + * Reading a cvt value returns + * ratio * cvt[index] + * + * Writing a cvt value in pixels: + * cvt[index] / ratio + * + * The current ppem is simply + * ratio * ppem + * + */ + + + /************************************************************************** + * + * Metrics used by the TrueType size and context objects. + */ + typedef struct TT_Size_Metrics_ + { + /* for non-square pixels */ + FT_Long x_ratio; + FT_Long y_ratio; + + FT_UShort ppem; /* maximum ppem size */ + FT_Long ratio; /* current ratio */ + FT_Fixed scale; + + FT_F26Dot6 compensations[4]; /* device-specific compensations */ + + FT_Bool valid; + + FT_Bool rotated; /* `is the glyph rotated?'-flag */ + FT_Bool stretched; /* `is the glyph stretched?'-flag */ + + } TT_Size_Metrics; + + + /************************************************************************** + * + * TrueType size class. + */ + typedef struct TT_SizeRec_ + { + FT_SizeRec root; + + /* we have our own copy of metrics so that we can modify */ + /* it without affecting auto-hinting (when used) */ + FT_Size_Metrics* metrics; /* for the current rendering mode */ + FT_Size_Metrics hinted_metrics; /* for the hinted rendering mode */ + + TT_Size_Metrics ttmetrics; + + FT_Byte* widthp; /* glyph widths from the hdmx table */ + + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Long point_size; /* for the `MPS' bytecode instruction */ + + FT_UInt num_function_defs; /* number of function definitions */ + FT_UInt max_function_defs; + TT_DefArray function_defs; /* table of function definitions */ + + FT_UInt num_instruction_defs; /* number of ins. definitions */ + FT_UInt max_instruction_defs; + TT_DefArray instruction_defs; /* table of ins. definitions */ + + FT_UInt max_func; + FT_UInt max_ins; + + TT_CodeRangeTable codeRangeTable; + + TT_GraphicsState GS; + + FT_ULong cvt_size; /* the scaled control value table */ + FT_Long* cvt; + + FT_UShort storage_size; /* The storage area is now part of */ + FT_Long* storage; /* the instance */ + + TT_GlyphZoneRec twilight; /* The instance's twilight zone */ + + TT_ExecContext context; + + /* if negative, `fpgm' (resp. `prep'), wasn't executed yet; */ + /* otherwise it is the returned error code */ + FT_Error bytecode_ready; + FT_Error cvt_ready; + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + } TT_SizeRec; + + + /************************************************************************** + * + * TrueType driver class. + */ + typedef struct TT_DriverRec_ + { + FT_DriverRec root; + + TT_GlyphZoneRec zone; /* glyph loader points zone */ + + FT_UInt interpreter_version; + + } TT_DriverRec; + + + /* Note: All of the functions below (except tt_size_reset()) are used */ + /* as function pointers in a FT_Driver_ClassRec. Therefore their */ + /* parameters are of types FT_Face, FT_Size, etc., rather than TT_Face, */ + /* TT_Size, etc., so that the compiler can confirm that the types and */ + /* number of parameters are correct. In all cases the FT_xxx types are */ + /* cast to their TT_xxx counterparts inside the functions since FreeType */ + /* will always use the TT driver to create them. */ + + + /************************************************************************** + * + * Face functions + */ + FT_LOCAL( FT_Error ) + tt_face_init( FT_Stream stream, + FT_Face ttface, /* TT_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + tt_face_done( FT_Face ttface ); /* TT_Face */ + + + /************************************************************************** + * + * Size functions + */ + FT_LOCAL( FT_Error ) + tt_size_init( FT_Size ttsize ); /* TT_Size */ + + FT_LOCAL( void ) + tt_size_done( FT_Size ttsize ); /* TT_Size */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_LOCAL( FT_Error ) + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ); + + FT_LOCAL( FT_Error ) + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ); + + FT_LOCAL( FT_Error ) + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + FT_LOCAL( FT_Error ) + tt_size_reset_height( FT_Size size ); + + FT_LOCAL( FT_Error ) + tt_size_reset( TT_Size size ); + + + /************************************************************************** + * + * Driver functions + */ + FT_LOCAL( FT_Error ) + tt_driver_init( FT_Module ttdriver ); /* TT_Driver */ + + FT_LOCAL( void ) + tt_driver_done( FT_Module ttdriver ); /* TT_Driver */ + + + /************************************************************************** + * + * Slot functions + */ + FT_LOCAL( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ); + + + /* auxiliary */ +#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) + + +FT_END_HEADER + +#endif /* TTOBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttpload.c b/vendor/freetype/src/truetype/ttpload.c new file mode 100644 index 0000000..54a64c7 --- /dev/null +++ b/vendor/freetype/src/truetype/ttpload.c @@ -0,0 +1,665 @@ +/**************************************************************************** + * + * ttpload.c + * + * TrueType-specific tables loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttpload + + + /************************************************************************** + * + * @Function: + * tt_face_load_loca + * + * @Description: + * Load the locations table. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_len; + FT_Int shift; + + + /* we need the size of the `glyf' table for malformed `loca' tables */ + error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); + + /* it is possible that a font doesn't have a glyf table at all */ + /* or its size is zero */ + if ( FT_ERR_EQ( error, Table_Missing ) ) + { + face->glyf_len = 0; + face->glyf_offset = 0; + } + else if ( error ) + goto Exit; + else + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( face->root.internal->incremental_interface ) + face->glyf_offset = 0; + else +#endif + face->glyf_offset = FT_STREAM_POS(); + } + + FT_TRACE2(( "Locations " )); + error = face->goto_table( face, TTAG_loca, stream, &table_len ); + if ( error ) + { + error = FT_THROW( Locations_Missing ); + goto Exit; + } + + shift = face->header.Index_To_Loc_Format != 0 ? 2 : 1; + + if ( table_len > 0x10000UL << shift ) + { + FT_TRACE2(( "table too large\n" )); + table_len = 0x10000UL << shift; + } + + face->num_locations = table_len >> shift; + + if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) + { + FT_TRACE2(( "glyph count mismatch! loca: %ld, maxp: %ld\n", + face->num_locations - 1, face->root.num_glyphs )); + + /* we only handle the case where `maxp' gives a larger value */ + if ( face->num_locations < (FT_ULong)face->root.num_glyphs + 1 ) + { + FT_ULong new_loca_len = + ( (FT_ULong)face->root.num_glyphs + 1 ) << shift; + + TT_Table entry = face->dir_tables; + TT_Table limit = entry + face->num_tables; + + FT_Long pos = (FT_Long)FT_STREAM_POS(); + FT_Long dist = 0x7FFFFFFFL; + FT_Bool found = 0; + + + /* compute the distance to next table in font file */ + for ( ; entry < limit; entry++ ) + { + FT_Long diff = (FT_Long)entry->Offset - pos; + + + if ( diff > 0 && diff < dist ) + { + dist = diff; + found = 1; + } + } + + if ( !found ) + { + /* `loca' is the last table */ + dist = (FT_Long)stream->size - pos; + } + + if ( new_loca_len <= (FT_ULong)dist ) + { + face->num_locations = (FT_ULong)face->root.num_glyphs + 1; + table_len = new_loca_len; + + FT_TRACE2(( "adjusting num_locations to %ld\n", + face->num_locations )); + } + else + { + face->root.num_glyphs = face->num_locations + ? (FT_Long)face->num_locations - 1 : 0; + + FT_TRACE2(( "adjusting num_glyphs to %ld\n", + face->root.num_glyphs )); + } + } + } + + /* + * Extract the frame. We don't need to decompress it since + * we are able to parse it directly. + */ + if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) + goto Exit; + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_ULong ) + tt_face_get_location( FT_Face face, /* TT_Face */ + FT_UInt gindex, + FT_ULong *asize ) + { + TT_Face ttface = (TT_Face)face; + FT_ULong pos1, pos2; + FT_Byte* p; + FT_Byte* p_limit; + + + pos1 = pos2 = 0; + + if ( gindex < ttface->num_locations ) + { + if ( ttface->header.Index_To_Loc_Format != 0 ) + { + p = ttface->glyph_locations + gindex * 4; + p_limit = ttface->glyph_locations + ttface->num_locations * 4; + + pos1 = FT_NEXT_ULONG( p ); + pos2 = pos1; + + if ( p + 4 <= p_limit ) + pos2 = FT_NEXT_ULONG( p ); + } + else + { + p = ttface->glyph_locations + gindex * 2; + p_limit = ttface->glyph_locations + ttface->num_locations * 2; + + pos1 = FT_NEXT_USHORT( p ); + pos2 = pos1; + + if ( p + 2 <= p_limit ) + pos2 = FT_NEXT_USHORT( p ); + + pos1 <<= 1; + pos2 <<= 1; + } + } + + /* Check broken location data. */ + if ( pos1 > ttface->glyf_len ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset (0x%08lx) found for glyph index %d,\n", + pos1, gindex )); + FT_TRACE1(( " " + " exceeding the end of `glyf' table (0x%08lx)\n", + ttface->glyf_len )); + *asize = 0; + return 0; + } + + if ( pos2 > ttface->glyf_len ) + { + /* We try to sanitize the last `loca' entry. */ + if ( gindex == ttface->num_locations - 2 ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large size (%ld bytes) found for glyph index %d,\n", + pos2 - pos1, gindex )); + FT_TRACE1(( " " + " truncating at the end of `glyf' table to %ld bytes\n", + ttface->glyf_len - pos1 )); + pos2 = ttface->glyf_len; + } + else + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset (0x%08lx) found for glyph index %d,\n", + pos2, gindex + 1 )); + FT_TRACE1(( " " + " exceeding the end of `glyf' table (0x%08lx)\n", + ttface->glyf_len )); + *asize = 0; + return 0; + } + } + + /* The `loca' table must be ordered; it refers to the length of */ + /* an entry as the difference between the current and the next */ + /* position. However, there do exist (malformed) fonts which */ + /* don't obey this rule, so we are only able to provide an */ + /* upper bound for the size. */ + /* */ + /* We get (intentionally) a wrong, non-zero result in case the */ + /* `glyf' table is missing. */ + if ( pos2 >= pos1 ) + *asize = (FT_ULong)( pos2 - pos1 ); + else + *asize = (FT_ULong)( ttface->glyf_len - pos1 ); + + return pos1; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_loca( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->glyph_locations ); + face->num_locations = 0; + } + + + + /************************************************************************** + * + * @Function: + * tt_face_load_cvt + * + * @Description: + * Load the control value table into a face object. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_len; + + + FT_TRACE2(( "CVT " )); + + error = face->goto_table( face, TTAG_cvt, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + + face->cvt_size = 0; + face->cvt = NULL; + error = FT_Err_Ok; + + goto Exit; + } + + face->cvt_size = table_len / 2; + + if ( FT_QNEW_ARRAY( face->cvt, face->cvt_size ) ) + goto Exit; + + if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) + goto Exit; + + { + FT_Int32* cur = face->cvt; + FT_Int32* limit = cur + face->cvt_size; + + + for ( ; cur < limit; cur++ ) + *cur = FT_GET_SHORT() * 64; + } + + FT_FRAME_EXIT(); + FT_TRACE2(( "loaded\n" )); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( face->doblend ) + error = tt_face_vary_cvt( face, stream ); +#endif + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_fpgm + * + * @Description: + * Load the font program. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_ULong table_len; + + + FT_TRACE2(( "Font program " )); + + /* The font program is optional */ + error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); + if ( error ) + { + face->font_program = NULL; + face->font_program_size = 0; + error = FT_Err_Ok; + + FT_TRACE2(( "is missing\n" )); + } + else + { + face->font_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12ld bytes\n", face->font_program_size )); + } + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_prep + * + * @Description: + * Load the cvt program. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_ULong table_len; + + + FT_TRACE2(( "Prep program " )); + + error = face->goto_table( face, TTAG_prep, stream, &table_len ); + if ( error ) + { + face->cvt_program = NULL; + face->cvt_program_size = 0; + error = FT_Err_Ok; + + FT_TRACE2(( "is missing\n" )); + } + else + { + face->cvt_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12ld bytes\n", face->cvt_program_size )); + } + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif + } + + + FT_COMPARE_DEF( int ) + compare_ppem( const void* a, + const void* b ) + { + return **(FT_Byte**)a - **(FT_Byte**)b; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_hdmx + * + * @Description: + * Load the `hdmx' table into the face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt nn, num_records; + FT_ULong table_size, record_size; + FT_Byte* p; + FT_Byte* limit; + + + /* this table is optional */ + error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); + if ( error || table_size < 8 ) + return FT_Err_Ok; + + if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) + goto Exit; + + p = face->hdmx_table; + limit = p + table_size; + + /* Given that `hdmx' tables are losing its importance (for example, */ + /* variation fonts introduced in OpenType 1.8 must not have this */ + /* table) we no longer test for a correct `version' field. */ + p += 2; + num_records = FT_NEXT_USHORT( p ); + record_size = FT_NEXT_ULONG( p ); + + /* There are at least two fonts, HANNOM-A and HANNOM-B version */ + /* 2.0 (2005), which get this wrong: The upper two bytes of */ + /* the size value are set to 0xFF instead of 0x00. We catch */ + /* and fix this. */ + + if ( record_size >= 0xFFFF0000UL ) + record_size &= 0xFFFFU; + + FT_TRACE2(( "Hdmx " )); + + /* The limit for `num_records' is a heuristic value. */ + if ( num_records > 255 || num_records == 0 ) + { + FT_TRACE2(( "with unreasonable %u records rejected\n", num_records )); + goto Fail; + } + + /* Out-of-spec tables are rejected. The record size must be */ + /* equal to the number of glyphs + 2 + 32-bit padding. */ + if ( (FT_Long)record_size != ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) ) + { + FT_TRACE2(( "with record size off by %ld bytes rejected\n", + (FT_Long)record_size - + ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) )); + goto Fail; + } + + if ( FT_QNEW_ARRAY( face->hdmx_records, num_records ) ) + goto Fail; + + for ( nn = 0; nn < num_records; nn++ ) + { + if ( p + record_size > limit ) + break; + face->hdmx_records[nn] = p; + p += record_size; + } + + /* The records must be already sorted by ppem but it does not */ + /* hurt to make sure so that the binary search works later. */ + ft_qsort( face->hdmx_records, nn, sizeof ( FT_Byte* ), compare_ppem ); + + face->hdmx_record_count = nn; + face->hdmx_table_size = table_size; + face->hdmx_record_size = record_size; + + FT_TRACE2(( "%ux%lu loaded\n", num_records, record_size )); + + Exit: + return error; + + Fail: + FT_FRAME_RELEASE( face->hdmx_table ); + face->hdmx_table_size = 0; + goto Exit; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_hdmx( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + + + FT_FREE( face->hdmx_records ); + FT_FRAME_RELEASE( face->hdmx_table ); + } + + + /************************************************************************** + * + * Return the advance width table for a given pixel size if it is found + * in the font's `hdmx' table (if any). The records must be sorted for + * the binary search to work properly. + */ + FT_LOCAL_DEF( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ) + { + FT_UInt min = 0; + FT_UInt max = face->hdmx_record_count; + FT_UInt mid; + FT_Byte* result = NULL; + + + while ( min < max ) + { + mid = ( min + max ) >> 1; + + if ( face->hdmx_records[mid][0] > ppem ) + max = mid; + else if ( face->hdmx_records[mid][0] < ppem ) + min = mid + 1; + else + { + result = face->hdmx_records[mid] + 2 + gindex; + break; + } + } + + return result; + } + + +/* END */ diff --git a/vendor/freetype/src/truetype/ttpload.h b/vendor/freetype/src/truetype/ttpload.h new file mode 100644 index 0000000..ed229fa --- /dev/null +++ b/vendor/freetype/src/truetype/ttpload.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * + * ttpload.h + * + * TrueType-specific tables loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTPLOAD_H_ +#define TTPLOAD_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( FT_ULong ) + tt_face_get_location( FT_Face face, + FT_UInt gindex, + FT_ULong *asize ); + + FT_LOCAL( void ) + tt_face_done_loca( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( void ) + tt_face_free_hdmx( TT_Face face ); + + + FT_LOCAL( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ); + +FT_END_HEADER + +#endif /* TTPLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/module.mk b/vendor/freetype/src/type1/module.mk new file mode 100644 index 0000000..33bceff --- /dev/null +++ b/vendor/freetype/src/type1/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 Type1 module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += TYPE1_DRIVER + +define TYPE1_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, t1_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)type1 $(ECHO_DRIVER_DESC)Postscript font files with extension *.pfa or *.pfb$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/type1/rules.mk b/vendor/freetype/src/type1/rules.mk new file mode 100644 index 0000000..efe744b --- /dev/null +++ b/vendor/freetype/src/type1/rules.mk @@ -0,0 +1,76 @@ +# +# FreeType 2 Type1 driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Type1 driver directory +# +T1_DIR := $(SRC_DIR)/type1 + + +# compilation flags for the driver +# +T1_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(T1_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# Type1 driver sources (i.e., C files) +# +T1_DRV_SRC := $(T1_DIR)/t1parse.c \ + $(T1_DIR)/t1load.c \ + $(T1_DIR)/t1driver.c \ + $(T1_DIR)/t1afm.c \ + $(T1_DIR)/t1gload.c \ + $(T1_DIR)/t1objs.c + +# Type1 driver headers +# +T1_DRV_H := $(T1_DRV_SRC:%.c=%.h) \ + $(T1_DIR)/t1tokens.h \ + $(T1_DIR)/t1errors.h + + +# Type1 driver object(s) +# +# T1_DRV_OBJ_M is used during `multi' builds +# T1_DRV_OBJ_S is used during `single' builds +# +T1_DRV_OBJ_M := $(T1_DRV_SRC:$(T1_DIR)/%.c=$(OBJ_DIR)/%.$O) +T1_DRV_OBJ_S := $(OBJ_DIR)/type1.$O + +# Type1 driver source file for single build +# +T1_DRV_SRC_S := $(T1_DIR)/type1.c + + +# Type1 driver - single object +# +$(T1_DRV_OBJ_S): $(T1_DRV_SRC_S) $(T1_DRV_SRC) $(FREETYPE_H) $(T1_DRV_H) + $(T1_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(T1_DRV_SRC_S)) + + +# Type1 driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(T1_DIR)/%.c $(FREETYPE_H) $(T1_DRV_H) + $(T1_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(T1_DRV_OBJ_S) +DRV_OBJS_M += $(T1_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/type1/t1afm.c b/vendor/freetype/src/type1/t1afm.c new file mode 100644 index 0000000..d9b9398 --- /dev/null +++ b/vendor/freetype/src/type1/t1afm.c @@ -0,0 +1,413 @@ +/**************************************************************************** + * + * t1afm.c + * + * AFM support for Type 1 fonts (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1afm.h" +#include +#include +#include +#include "t1errors.h" + + +#ifndef T1_CONFIG_OPTION_NO_AFM + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1afm + + + FT_LOCAL_DEF( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + + FT_FREE( fi ); + } + + + /* read a glyph name and return the equivalent glyph index */ + static FT_Int + t1_get_index( const char* name, + FT_Offset len, + void* user_data ) + { + T1_Font type1 = (T1_Font)user_data; + FT_Int n; + + + /* PS string/name length must be < 16-bit */ + if ( len > 0xFFFFU ) + return 0; + + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + + + if ( gname && gname[0] == name[0] && + ft_strlen( gname ) == len && + ft_strncmp( gname, name, len ) == 0 ) + return n; + } + + return 0; + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + + + /* compare two kerning pairs */ + FT_COMPARE_DEF( int ) + compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair pair1 = (AFM_KernPair)a; + AFM_KernPair pair2 = (AFM_KernPair)b; + + FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 ); + FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 ); + + + if ( index1 > index2 ) + return 1; + else if ( index1 < index2 ) + return -1; + else + return 0; + } + + + /* parse a PFM file -- for now, only read the kerning pairs */ + static FT_Error + T1_Read_PFM( FT_Face t1_face, + FT_Stream stream, + AFM_FontInfo fi ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + AFM_KernPair kp; + FT_Int width_table_length; + FT_CharMap oldcharmap; + FT_CharMap charmap; + FT_Int n; + + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + + /* Figure out how long the width table is. */ + /* This info is a little-endian short at offset 99. */ + p = start + 99; + if ( p + 2 > limit ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + width_table_length = FT_PEEK_USHORT_LE( p ); + + p += 18 + width_table_length; + if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) + /* extension table is probably optional */ + goto Exit; + + /* Kerning offset is 14 bytes from start of extensions table. */ + p += 14; + p = start + FT_PEEK_ULONG_LE( p ); + + if ( p == start ) + /* zero offset means no table */ + goto Exit; + + if ( p + 2 > limit ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + fi->NumKernPair = FT_PEEK_USHORT_LE( p ); + p += 2; + if ( p + 4 * fi->NumKernPair > limit ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* Actually, kerning pairs are simply optional! */ + if ( fi->NumKernPair == 0 ) + goto Exit; + + /* allocate the pairs */ + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + goto Exit; + + /* now, read each kern pair */ + kp = fi->KernPairs; + limit = p + 4 * fi->NumKernPair; + + /* PFM kerning data are stored by encoding rather than glyph index, */ + /* so find the PostScript charmap of this font and install it */ + /* temporarily. If we find no PostScript charmap, then just use */ + /* the default and hope it is the right one. */ + oldcharmap = t1_face->charmap; + + for ( n = 0; n < t1_face->num_charmaps; n++ ) + { + charmap = t1_face->charmaps[n]; + /* check against PostScript pseudo platform */ + if ( charmap->platform_id == 7 ) + { + t1_face->charmap = charmap; + break; + } + } + + /* Kerning info is stored as: */ + /* */ + /* encoding of first glyph (1 byte) */ + /* encoding of second glyph (1 byte) */ + /* offset (little-endian short) */ + for ( ; p < limit; p += 4 ) + { + kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); + kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); + + kp->x = (FT_Int)FT_PEEK_SHORT_LE( p + 2 ); + kp->y = 0; + + kp++; + } + + t1_face->charmap = oldcharmap; + + /* now, sort the kern pairs according to their glyph indices */ + ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), + compare_kern_pairs ); + + Exit: + if ( error ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + } + + return error; + } + + + /* parse a metrics file -- either AFM or PFM depending on what */ + /* it turns out to be */ + FT_LOCAL_DEF( FT_Error ) + T1_Read_Metrics( FT_Face t1_face, + FT_Stream stream ) + { + PSAux_Service psaux; + FT_Memory memory = stream->memory; + AFM_ParserRec parser; + AFM_FontInfo fi = NULL; + FT_Error error = FT_ERR( Unknown_File_Format ); + T1_Face face = (T1_Face)t1_face; + T1_Font t1_font = &face->type1; + + + if ( face->afm_data ) + { + FT_TRACE1(( "T1_Read_Metrics:" + " Freeing previously attached metrics data.\n" )); + T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data ); + + face->afm_data = NULL; + } + + if ( FT_NEW( fi ) || + FT_FRAME_ENTER( stream->size ) ) + goto Exit; + + fi->FontBBox = t1_font->font_bbox; + fi->Ascender = t1_font->font_bbox.yMax; + fi->Descender = t1_font->font_bbox.yMin; + + psaux = (PSAux_Service)face->psaux; + if ( psaux->afm_parser_funcs ) + { + error = psaux->afm_parser_funcs->init( &parser, + stream->memory, + stream->cursor, + stream->limit ); + + if ( !error ) + { + parser.FontInfo = fi; + parser.get_index = t1_get_index; + parser.user_data = t1_font; + + error = psaux->afm_parser_funcs->parse( &parser ); + psaux->afm_parser_funcs->done( &parser ); + } + } + + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + FT_Byte* start = stream->cursor; + + + /* MS Windows allows versions up to 0x3FF without complaining */ + if ( stream->size > 6 && + start[1] < 4 && + FT_PEEK_ULONG_LE( start + 2 ) == stream->size ) + error = T1_Read_PFM( t1_face, stream, fi ); + } + + if ( !error ) + { + t1_font->font_bbox = fi->FontBBox; + + t1_face->bbox.xMin = fi->FontBBox.xMin >> 16; + t1_face->bbox.yMin = fi->FontBBox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16; + t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16; + + /* ascender and descender are optional and could both be zero */ + /* check if values are meaningful before overriding defaults */ + if ( fi->Ascender > fi->Descender ) + { + /* no `U' suffix here to 0x8000! */ + t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 ); + t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 ); + } + + if ( fi->NumKernPair ) + { + t1_face->face_flags |= FT_FACE_FLAG_KERNING; + face->afm_data = fi; + fi = NULL; + } + } + + FT_FRAME_EXIT(); + + Exit: + if ( fi ) + T1_Done_Metrics( memory, fi ); + + return error; + } + + + /* find the kerning for a given glyph pair */ + FT_LOCAL_DEF( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + AFM_KernPair min, mid, max; + FT_ULong idx = KERN_INDEX( glyph1, glyph2 ); + + + /* simple binary search */ + min = fi->KernPairs; + max = min + fi->NumKernPair - 1; + + while ( min <= max ) + { + FT_ULong midi; + + + mid = min + ( max - min ) / 2; + midi = KERN_INDEX( mid->index1, mid->index2 ); + + if ( midi == idx ) + { + kerning->x = mid->x; + kerning->y = mid->y; + + return; + } + + if ( midi < idx ) + min = mid + 1; + else + max = mid - 1; + } + + kerning->x = 0; + kerning->y = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ) + { + AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data; + FT_UInt i; + + + if ( !fi ) + return FT_THROW( Invalid_Argument ); + + for ( i = 0; i < fi->NumTrackKern; i++ ) + { + AFM_TrackKern tk = fi->TrackKerns + i; + + + if ( tk->degree != degree ) + continue; + + if ( ptsize < tk->min_ptsize ) + *kerning = tk->min_kern; + else if ( ptsize > tk->max_ptsize ) + *kerning = tk->max_kern; + else + { + *kerning = FT_MulDiv( ptsize - tk->min_ptsize, + tk->max_kern - tk->min_kern, + tk->max_ptsize - tk->min_ptsize ) + + tk->min_kern; + } + } + + return FT_Err_Ok; + } + +#else /* T1_CONFIG_OPTION_NO_AFM */ + + /* ANSI C doesn't like empty source files */ + typedef int t1_afm_dummy_; + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1afm.h b/vendor/freetype/src/type1/t1afm.h new file mode 100644 index 0000000..e0d5aa5 --- /dev/null +++ b/vendor/freetype/src/type1/t1afm.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * + * t1afm.h + * + * AFM support for Type 1 fonts (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1AFM_H_ +#define T1AFM_H_ + +#include "t1objs.h" +#include + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + T1_Read_Metrics( FT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ); + + FT_LOCAL( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + FT_LOCAL( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ); + +FT_END_HEADER + +#endif /* T1AFM_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1driver.c b/vendor/freetype/src/type1/t1driver.c new file mode 100644 index 0000000..a4cdf37 --- /dev/null +++ b/vendor/freetype/src/type1/t1driver.c @@ -0,0 +1,813 @@ +/**************************************************************************** + * + * t1driver.c + * + * Type 1 driver interface (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1driver.h" +#include "t1gload.h" +#include "t1load.h" + +#include "t1errors.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1driver + + /* + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + t1_get_glyph_name( FT_Face face, /* T1_Face */ + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + T1_Face t1face = (T1_Face)face; + + + FT_STRCPYN( buffer, t1face->type1.glyph_names[glyph_index], buffer_max ); + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_get_name_index( FT_Face face, /* T1_Face */ + const FT_String* glyph_name ) + { + T1_Face t1face = (T1_Face)face; + FT_Int i; + + + for ( i = 0; i < t1face->type1.num_glyphs; i++ ) + { + FT_String* gname = t1face->type1.glyph_names[i]; + + + if ( !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)i; + } + + return 0; + } + + + static const FT_Service_GlyphDictRec t1_service_glyph_dict = + { + t1_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + t1_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ + }; + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + static const char* + t1_get_ps_name( FT_Face face ) /* T1_Face */ + { + T1_Face t1face = (T1_Face)face; + + + return (const char*) t1face->type1.font_name; + } + + + static const FT_Service_PsFontNameRec t1_service_ps_name = + { + (FT_PsName_GetFunc)t1_get_ps_name /* get_ps_font_name */ + }; + + + /* + * MULTIPLE MASTERS SERVICE + * + */ + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + static const FT_Service_MultiMastersRec t1_service_multi_masters = + { + T1_Get_Multi_Master, /* FT_Get_MM_Func get_mm */ + T1_Set_MM_Design, /* FT_Set_MM_Design_Func set_mm_design */ + T1_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + T1_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + T1_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */ + T1_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */ + T1_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */ + T1_Reset_MM_Blend, /* FT_Set_Named_Instance_Func set_named_instance */ + NULL, /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + T1_Set_MM_WeightVector, + /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + T1_Get_MM_WeightVector, + /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ + + NULL, /* FT_Construct_PS_Name_Func construct_ps_name */ + NULL, /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + NULL, /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + NULL, /* FT_Var_Get_Item_Delta_Func get_item_delta */ + NULL, /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + NULL, /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + NULL, /* FT_Get_Var_Blend_Func get_var_blend */ + T1_Done_Blend /* FT_Done_Blend_Func done_blend */ + }; +#endif + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + static FT_Error + t1_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T1_Face)face)->type1.font_info; + + return FT_Err_Ok; + } + + + static FT_Error + t1_ps_get_font_extra( FT_Face face, + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ((T1_Face)face)->type1.font_extra; + + return FT_Err_Ok; + } + + + static FT_Int + t1_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + + return 1; + } + + + static FT_Error + t1_ps_get_font_private( FT_Face face, + PS_PrivateRec* afont_private ) + { + *afont_private = ((T1_Face)face)->type1.private_dict; + + return FT_Err_Ok; + } + + + static FT_Long + t1_ps_get_font_value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len_ ) + { + FT_ULong retval = 0; /* always >= 1 if valid */ + FT_ULong value_len = value_len_ < 0 ? 0 : (FT_ULong)value_len_; + + T1_Face t1face = (T1_Face)face; + T1_Font type1 = &t1face->type1; + + + switch ( key ) + { + case PS_DICT_FONT_TYPE: + retval = sizeof ( type1->font_type ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->font_type; + break; + + case PS_DICT_FONT_MATRIX: + if ( idx < sizeof ( type1->font_matrix ) / + sizeof ( type1->font_matrix.xx ) ) + { + FT_Fixed val = 0; + + + retval = sizeof ( val ); + if ( value && value_len >= retval ) + { + switch ( idx ) + { + case 0: + val = type1->font_matrix.xx; + break; + case 1: + val = type1->font_matrix.xy; + break; + case 2: + val = type1->font_matrix.yx; + break; + case 3: + val = type1->font_matrix.yy; + break; + } + *((FT_Fixed *)value) = val; + } + } + break; + + case PS_DICT_FONT_BBOX: + if ( idx < sizeof ( type1->font_bbox ) / + sizeof ( type1->font_bbox.xMin ) ) + { + FT_Fixed val = 0; + + + retval = sizeof ( val ); + if ( value && value_len >= retval ) + { + switch ( idx ) + { + case 0: + val = type1->font_bbox.xMin; + break; + case 1: + val = type1->font_bbox.yMin; + break; + case 2: + val = type1->font_bbox.xMax; + break; + case 3: + val = type1->font_bbox.yMax; + break; + } + *((FT_Fixed *)value) = val; + } + } + break; + + case PS_DICT_PAINT_TYPE: + retval = sizeof ( type1->paint_type ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->paint_type; + break; + + case PS_DICT_FONT_NAME: + if ( type1->font_name ) + { + retval = ft_strlen( type1->font_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_name ), retval ); + } + break; + + case PS_DICT_UNIQUE_ID: + retval = sizeof ( type1->private_dict.unique_id ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.unique_id; + break; + + case PS_DICT_NUM_CHAR_STRINGS: + retval = sizeof ( type1->num_glyphs ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->num_glyphs; + break; + + case PS_DICT_CHAR_STRING_KEY: + if ( idx < (FT_UInt)type1->num_glyphs ) + { + retval = ft_strlen( type1->glyph_names[idx] ) + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->glyph_names[idx] ), retval ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + + case PS_DICT_CHAR_STRING: + if ( idx < (FT_UInt)type1->num_glyphs ) + { + retval = type1->charstrings_len[idx] + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->charstrings[idx] ), + retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + + case PS_DICT_ENCODING_TYPE: + retval = sizeof ( type1->encoding_type ); + if ( value && value_len >= retval ) + *((T1_EncodingType *)value) = type1->encoding_type; + break; + + case PS_DICT_ENCODING_ENTRY: + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY && + idx < (FT_UInt)type1->encoding.num_chars ) + { + retval = ft_strlen( type1->encoding.char_name[idx] ) + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->encoding.char_name[idx] ), + retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + + case PS_DICT_NUM_SUBRS: + retval = sizeof ( type1->num_subrs ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->num_subrs; + break; + + case PS_DICT_SUBR: + { + FT_Bool ok = 0; + + + if ( type1->subrs_hash ) + { + /* convert subr index to array index */ + size_t* val = ft_hash_num_lookup( (FT_Int)idx, + type1->subrs_hash ); + + + if ( val ) + { + idx = *val; + ok = 1; + } + } + else + { + if ( idx < (FT_UInt)type1->num_subrs ) + ok = 1; + } + + if ( ok && type1->subrs ) + { + retval = type1->subrs_len[idx] + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->subrs[idx] ), retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + } + break; + + case PS_DICT_STD_HW: + retval = sizeof ( type1->private_dict.standard_width[0] ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->private_dict.standard_width[0]; + break; + + case PS_DICT_STD_VW: + retval = sizeof ( type1->private_dict.standard_height[0] ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->private_dict.standard_height[0]; + break; + + case PS_DICT_NUM_BLUE_VALUES: + retval = sizeof ( type1->private_dict.num_blue_values ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_blue_values; + break; + + case PS_DICT_BLUE_VALUE: + if ( idx < type1->private_dict.num_blue_values ) + { + retval = sizeof ( type1->private_dict.blue_values[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.blue_values[idx]; + } + break; + + case PS_DICT_BLUE_SCALE: + retval = sizeof ( type1->private_dict.blue_scale ); + if ( value && value_len >= retval ) + *((FT_Fixed *)value) = type1->private_dict.blue_scale; + break; + + case PS_DICT_BLUE_FUZZ: + retval = sizeof ( type1->private_dict.blue_fuzz ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.blue_fuzz; + break; + + case PS_DICT_BLUE_SHIFT: + retval = sizeof ( type1->private_dict.blue_shift ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.blue_shift; + break; + + case PS_DICT_NUM_OTHER_BLUES: + retval = sizeof ( type1->private_dict.num_other_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_other_blues; + break; + + case PS_DICT_OTHER_BLUE: + if ( idx < type1->private_dict.num_other_blues ) + { + retval = sizeof ( type1->private_dict.other_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.other_blues[idx]; + } + break; + + case PS_DICT_NUM_FAMILY_BLUES: + retval = sizeof ( type1->private_dict.num_family_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_family_blues; + break; + + case PS_DICT_FAMILY_BLUE: + if ( idx < type1->private_dict.num_family_blues ) + { + retval = sizeof ( type1->private_dict.family_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.family_blues[idx]; + } + break; + + case PS_DICT_NUM_FAMILY_OTHER_BLUES: + retval = sizeof ( type1->private_dict.num_family_other_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_family_other_blues; + break; + + case PS_DICT_FAMILY_OTHER_BLUE: + if ( idx < type1->private_dict.num_family_other_blues ) + { + retval = sizeof ( type1->private_dict.family_other_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.family_other_blues[idx]; + } + break; + + case PS_DICT_NUM_STEM_SNAP_H: + retval = sizeof ( type1->private_dict.num_snap_widths ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_snap_widths; + break; + + case PS_DICT_STEM_SNAP_H: + if ( idx < type1->private_dict.num_snap_widths ) + { + retval = sizeof ( type1->private_dict.snap_widths[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.snap_widths[idx]; + } + break; + + case PS_DICT_NUM_STEM_SNAP_V: + retval = sizeof ( type1->private_dict.num_snap_heights ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_snap_heights; + break; + + case PS_DICT_STEM_SNAP_V: + if ( idx < type1->private_dict.num_snap_heights ) + { + retval = sizeof ( type1->private_dict.snap_heights[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.snap_heights[idx]; + } + break; + + case PS_DICT_RND_STEM_UP: + retval = sizeof ( type1->private_dict.round_stem_up ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->private_dict.round_stem_up; + break; + + case PS_DICT_FORCE_BOLD: + retval = sizeof ( type1->private_dict.force_bold ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->private_dict.force_bold; + break; + + case PS_DICT_MIN_FEATURE: + if ( idx < sizeof ( type1->private_dict.min_feature ) / + sizeof ( type1->private_dict.min_feature[0] ) ) + { + retval = sizeof ( type1->private_dict.min_feature[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.min_feature[idx]; + } + break; + + case PS_DICT_LEN_IV: + retval = sizeof ( type1->private_dict.lenIV ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.lenIV; + break; + + case PS_DICT_PASSWORD: + retval = sizeof ( type1->private_dict.password ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->private_dict.password; + break; + + case PS_DICT_LANGUAGE_GROUP: + retval = sizeof ( type1->private_dict.language_group ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->private_dict.language_group; + break; + + case PS_DICT_IS_FIXED_PITCH: + retval = sizeof ( type1->font_info.is_fixed_pitch ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->font_info.is_fixed_pitch; + break; + + case PS_DICT_UNDERLINE_POSITION: + retval = sizeof ( type1->font_info.underline_position ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->font_info.underline_position; + break; + + case PS_DICT_UNDERLINE_THICKNESS: + retval = sizeof ( type1->font_info.underline_thickness ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->font_info.underline_thickness; + break; + + case PS_DICT_FS_TYPE: + retval = sizeof ( type1->font_extra.fs_type ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->font_extra.fs_type; + break; + + case PS_DICT_VERSION: + if ( type1->font_info.version ) + { + retval = ft_strlen( type1->font_info.version ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.version ), retval ); + } + break; + + case PS_DICT_NOTICE: + if ( type1->font_info.notice ) + { + retval = ft_strlen( type1->font_info.notice ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.notice ), retval ); + } + break; + + case PS_DICT_FULL_NAME: + if ( type1->font_info.full_name ) + { + retval = ft_strlen( type1->font_info.full_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.full_name ), retval ); + } + break; + + case PS_DICT_FAMILY_NAME: + if ( type1->font_info.family_name ) + { + retval = ft_strlen( type1->font_info.family_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.family_name ), + retval ); + } + break; + + case PS_DICT_WEIGHT: + if ( type1->font_info.weight ) + { + retval = ft_strlen( type1->font_info.weight ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.weight ), retval ); + } + break; + + case PS_DICT_ITALIC_ANGLE: + retval = sizeof ( type1->font_info.italic_angle ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->font_info.italic_angle; + break; + } + + return retval == 0 ? -1 : (FT_Long)retval; + } + + + static const FT_Service_PsInfoRec t1_service_ps_info = + { + t1_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + t1_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + t1_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ + t1_ps_get_font_private, /* PS_GetFontPrivateFunc ps_get_font_private */ + t1_ps_get_font_value, /* PS_GetFontValueFunc ps_get_font_value */ + }; + + +#ifndef T1_CONFIG_OPTION_NO_AFM + static const FT_Service_KerningRec t1_service_kerning = + { + T1_Get_Track_Kerning, /* get_track */ + }; +#endif + + + /* + * PROPERTY SERVICE + * + */ + + FT_DEFINE_SERVICE_PROPERTIESREC( + t1_service_properties, + + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec t1_services[] = + { + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t1_service_ps_name }, + { FT_SERVICE_ID_GLYPH_DICT, &t1_service_glyph_dict }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TYPE_1 }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t1_service_ps_info }, + { FT_SERVICE_ID_PROPERTIES, &t1_service_properties }, + +#ifndef T1_CONFIG_OPTION_NO_AFM + { FT_SERVICE_ID_KERNING, &t1_service_kerning }, +#endif + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + { FT_SERVICE_ID_MULTI_MASTERS, &t1_service_multi_masters }, +#endif + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + Get_Interface( FT_Module module, + const FT_String* t1_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( t1_services, t1_interface ); + } + + +#ifndef T1_CONFIG_OPTION_NO_AFM + + /************************************************************************** + * + * @Function: + * Get_Kerning + * + * @Description: + * A driver method used to return the kerning vector between two + * glyphs of the same face. + * + * @Input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * @Output: + * kerning :: + * The kerning vector. This is in font units for + * scalable formats, and in pixels for fixed-sizes + * formats. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only horizontal layouts (left-to-right & right-to-left) are + * supported by this function. Other layouts, or more sophisticated + * kernings are out of scope of this method (the basic driver + * interface is meant to be simple). + * + * They can be implemented by format-specific interfaces. + */ + static FT_Error + Get_Kerning( FT_Face t1face, /* T1_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + T1_Face face = (T1_Face)t1face; + + + kerning->x = 0; + kerning->y = 0; + + if ( face->afm_data ) + T1_Get_Kerning( (AFM_FontInfo)face->afm_data, + left_glyph, + right_glyph, + kerning ); + + return FT_Err_Ok; + } + + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec t1_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + + sizeof ( PS_DriverRec ), + + "type1", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + T1_Driver_Init, /* FT_Module_Constructor module_init */ + T1_Driver_Done, /* FT_Module_Destructor module_done */ + Get_Interface, /* FT_Module_Requester get_interface */ + }, + + sizeof ( T1_FaceRec ), + sizeof ( T1_SizeRec ), + sizeof ( T1_GlyphSlotRec ), + + T1_Face_Init, /* FT_Face_InitFunc init_face */ + T1_Face_Done, /* FT_Face_DoneFunc done_face */ + T1_Size_Init, /* FT_Size_InitFunc init_size */ + T1_Size_Done, /* FT_Size_DoneFunc done_size */ + T1_GlyphSlot_Init, /* FT_Slot_InitFunc init_slot */ + T1_GlyphSlot_Done, /* FT_Slot_DoneFunc done_slot */ + + T1_Load_Glyph, /* FT_Slot_LoadFunc load_glyph */ + +#ifdef T1_CONFIG_OPTION_NO_AFM + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ +#else + Get_Kerning, /* FT_Face_GetKerningFunc get_kerning */ + T1_Read_Metrics, /* FT_Face_AttachFunc attach_file */ +#endif + T1_Get_Advances, /* FT_Face_GetAdvancesFunc get_advances */ + + T1_Size_Request, /* FT_Size_RequestFunc request_size */ + NULL /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/vendor/freetype/src/type1/t1driver.h b/vendor/freetype/src/type1/t1driver.h new file mode 100644 index 0000000..ee7fcf4 --- /dev/null +++ b/vendor/freetype/src/type1/t1driver.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * t1driver.h + * + * High-level Type 1 driver interface (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1DRIVER_H_ +#define T1DRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t1_driver_class; + +FT_END_HEADER + +#endif /* T1DRIVER_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1errors.h b/vendor/freetype/src/type1/t1errors.h new file mode 100644 index 0000000..2fbd1e5 --- /dev/null +++ b/vendor/freetype/src/type1/t1errors.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * t1errors.h + * + * Type 1 error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Type 1 error enumeration constants. + * + */ + +#ifndef T1ERRORS_H_ +#define T1ERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX T1_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type1 + +#include + +#endif /* T1ERRORS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1gload.c b/vendor/freetype/src/type1/t1gload.c new file mode 100644 index 0000000..a32a464 --- /dev/null +++ b/vendor/freetype/src/type1/t1gload.c @@ -0,0 +1,606 @@ +/**************************************************************************** + * + * t1gload.c + * + * Type 1 Glyph Loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1gload.h" +#include +#include +#include +#include +#include +#include +#include + +#include "t1errors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1gload + + + static FT_Error + T1_Parse_Glyph_And_Get_Char_String( T1_Decoder decoder, + FT_UInt glyph_index, + FT_Data* char_string, + FT_Bool* force_scaling ) + { + T1_Face face = (T1_Face)decoder->builder.face; + T1_Font type1 = &face->type1; + FT_Error error = FT_Err_Ok; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; + PS_Decoder psdecoder; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; +#endif + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); +#endif + + + decoder->font_matrix = type1->font_matrix; + decoder->font_offset = type1->font_offset; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( inc ) + error = inc->funcs->get_glyph_data( inc->object, + glyph_index, char_string ); + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + /* For ordinary fonts get the character data stored in the face record. */ + { + char_string->pointer = type1->charstrings[glyph_index]; + char_string->length = type1->charstrings_len[glyph_index]; + } + + if ( !error ) + { + /* choose which renderer to use */ +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + if ( driver->hinting_engine == FT_HINTING_FREETYPE || + decoder->builder.metrics_only ) + error = decoder_funcs->parse_charstrings_old( + decoder, + (FT_Byte*)char_string->pointer, + (FT_UInt)char_string->length ); +#else + if ( decoder->builder.metrics_only ) + error = decoder_funcs->parse_metrics( + decoder, + (FT_Byte*)char_string->pointer, + (FT_UInt)char_string->length ); +#endif + else + { + CFF_SubFontRec subfont; + + + psaux->ps_decoder_init( &psdecoder, decoder, TRUE ); + + psaux->t1_make_subfont( FT_FACE( face ), + &face->type1.private_dict, &subfont ); + psdecoder.current_subfont = &subfont; + + error = decoder_funcs->parse_charstrings( + &psdecoder, + (FT_Byte*)char_string->pointer, + (FT_ULong)char_string->length ); + + /* Adobe's engine uses 16.16 numbers everywhere; */ + /* as a consequence, glyphs larger than 2000ppem get rejected */ + if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) + { + /* this time, we retry unhinted and scale up the glyph later on */ + /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ + /* 0x400 for both `x_scale' and `y_scale' in this case) */ + ((T1_GlyphSlot)decoder->builder.glyph)->hint = FALSE; + + *force_scaling = TRUE; + + error = decoder_funcs->parse_charstrings( + &psdecoder, + (FT_Byte*)char_string->pointer, + (FT_ULong)char_string->length ); + } + } + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && inc && inc->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = FIXED_TO_INT( decoder->builder.left_bearing.x ); + metrics.bearing_y = 0; + metrics.advance = FIXED_TO_INT( decoder->builder.advance.x ); + metrics.advance_v = FIXED_TO_INT( decoder->builder.advance.y ); + + error = inc->funcs->get_glyph_metrics( inc->object, + glyph_index, FALSE, &metrics ); + + decoder->builder.left_bearing.x = INT_TO_FIXED( metrics.bearing_x ); + decoder->builder.advance.x = INT_TO_FIXED( metrics.advance ); + decoder->builder.advance.y = INT_TO_FIXED( metrics.advance_v ); + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + T1_Parse_Glyph( T1_Decoder decoder, + FT_UInt glyph_index ) + { + FT_Data glyph_data; + FT_Bool force_scaling = FALSE; + FT_Error error = T1_Parse_Glyph_And_Get_Char_String( + decoder, glyph_index, &glyph_data, + &force_scaling ); + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( !error ) + { + T1_Face face = (T1_Face)decoder->builder.face; + + + if ( face->root.internal->incremental_interface ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ) + { + FT_Error error; + T1_DecoderRec decoder; + FT_Int glyph_index; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + *max_advance = 0; + + /* initialize load decoder */ + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + (FT_Byte**)type1->glyph_names, + face->blend, + 0, + FT_RENDER_MODE_NORMAL, + T1_Parse_Glyph ); + if ( error ) + return error; + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + *max_advance = 0; + + FT_TRACE6(( "T1_Compute_Max_Advance:\n" )); + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) + { + /* now get load the unscaled outline */ + (void)T1_Parse_Glyph( &decoder, (FT_UInt)glyph_index ); + if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance ) + *max_advance = decoder.builder.advance.x; + + /* ignore the error if one occurred - skip to next glyph */ + } + + FT_TRACE6(( "T1_Compute_Max_Advance: max advance: %f\n", + (double)*max_advance / 65536 )); + + psaux->t1_decoder_funcs->done( &decoder ); + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Advances( FT_Face t1face, /* T1_Face */ + FT_UInt first, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed* advances ) + { + T1_Face face = (T1_Face)t1face; + T1_DecoderRec decoder; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_UInt nn; + FT_Error error; + + + FT_TRACE5(( "T1_Get_Advances:\n" )); + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + for ( nn = 0; nn < count; nn++ ) + { + advances[nn] = 0; + + FT_TRACE5(( " idx %d: advance height 0 font units\n", + first + nn )); + } + + return FT_Err_Ok; + } + + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + (FT_Byte**)type1->glyph_names, + face->blend, + 0, + FT_RENDER_MODE_NORMAL, + T1_Parse_Glyph ); + if ( error ) + return error; + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + for ( nn = 0; nn < count; nn++ ) + { + error = T1_Parse_Glyph( &decoder, first + nn ); + if ( !error ) + advances[nn] = FIXED_TO_INT( decoder.builder.advance.x ); + else + advances[nn] = 0; + + FT_TRACE5(( " idx %d: advance width %ld font unit%s\n", + first + nn, + advances[nn], + advances[nn] == 1 ? "" : "s" )); + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Load_Glyph( FT_GlyphSlot t1glyph, /* T1_GlyphSlot */ + FT_Size t1size, /* T1_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + T1_GlyphSlot glyph = (T1_GlyphSlot)t1glyph; + FT_Error error; + T1_DecoderRec decoder; + T1_Face face = (T1_Face)t1glyph->face; + FT_Bool hinting; + FT_Bool scaled; + FT_Bool force_scaling = FALSE; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; + + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_Data glyph_data; + FT_Bool must_finish_decoder = FALSE; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Bool glyph_data_loaded = 0; +#endif + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( glyph_index >= (FT_UInt)face->root.num_glyphs && + !face->root.internal->incremental_interface ) +#else + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_TRACE1(( "T1_Load_Glyph: glyph index %d\n", glyph_index )); + + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + if ( t1size ) + { + glyph->x_scale = t1size->metrics.x_scale; + glyph->y_scale = t1size->metrics.y_scale; + } + else + { + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + } + + t1glyph->outline.n_points = 0; + t1glyph->outline.n_contours = 0; + + hinting = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) && + !( load_flags & FT_LOAD_NO_HINTING ) ); + scaled = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); + + glyph->hint = hinting; + glyph->scaled = scaled; + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + + error = decoder_funcs->init( &decoder, + t1glyph->face, + t1size, + t1glyph, + (FT_Byte**)type1->glyph_names, + face->blend, + hinting, + FT_LOAD_TARGET_MODE( load_flags ), + T1_Parse_Glyph ); + if ( error ) + goto Exit; + + must_finish_decoder = TRUE; + + decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + /* now load the unscaled outline */ + error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index, + &glyph_data, + &force_scaling ); + if ( error ) + goto Exit; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + glyph_data_loaded = 1; +#endif + + hinting = glyph->hint; + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; + + /* save new glyph tables */ + decoder_funcs->done( &decoder ); + + must_finish_decoder = FALSE; + + /* now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + if ( !error ) + { + t1glyph->outline.flags &= FT_OUTLINE_OWNER; + t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = t1glyph->internal; + + + t1glyph->metrics.horiBearingX = + FIXED_TO_INT( decoder.builder.left_bearing.x ); + t1glyph->metrics.horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &t1glyph->metrics; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + t1glyph->linearHoriAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + t1glyph->internal->glyph_transformed = 0; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* make up vertical ones */ + metrics->vertAdvance = ( face->type1.font_bbox.yMax - + face->type1.font_bbox.yMin ) >> 16; + t1glyph->linearVertAdvance = metrics->vertAdvance; + } + else + { + metrics->vertAdvance = + FIXED_TO_INT( decoder.builder.advance.y ); + t1glyph->linearVertAdvance = + FIXED_TO_INT( decoder.builder.advance.y ); + } + + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + + if ( t1size && t1size->metrics.y_ppem < 24 ) + t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + +#if 1 + /* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + { + FT_Outline_Transform( &t1glyph->outline, &font_matrix ); + + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + font_matrix.xx ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, + font_matrix.yy ); + } + + if ( font_offset.x || font_offset.y ) + { + FT_Outline_Translate( &t1glyph->outline, + font_offset.x, + font_offset.y ); + + metrics->horiAdvance += font_offset.x; + metrics->vertAdvance += font_offset.y; + } +#endif + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points, if we are not hinting */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &t1glyph->outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* make up vertical ones */ + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + + /* Set control data to the glyph charstrings. Note that this is */ + /* _not_ zero-terminated. */ + t1glyph->control_data = (FT_Byte*)glyph_data.pointer; + t1glyph->control_len = glyph_data.length; + } + + + Exit: + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( glyph_data_loaded && face->root.internal->incremental_interface ) + { + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + + /* Set the control data to null - it is no longer available if */ + /* loaded incrementally. */ + t1glyph->control_data = NULL; + t1glyph->control_len = 0; + } +#endif + + if ( must_finish_decoder ) + decoder_funcs->done( &decoder ); + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/type1/t1gload.h b/vendor/freetype/src/type1/t1gload.h new file mode 100644 index 0000000..c064847 --- /dev/null +++ b/vendor/freetype/src/type1/t1gload.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * t1gload.h + * + * Type 1 Glyph Loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1GLOAD_H_ +#define T1GLOAD_H_ + + +#include "t1objs.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ); + + FT_LOCAL( FT_Error ) + T1_Get_Advances( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed* advances ); + + FT_LOCAL( FT_Error ) + T1_Load_Glyph( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* T1GLOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1load.c b/vendor/freetype/src/type1/t1load.c new file mode 100644 index 0000000..be7cd0f --- /dev/null +++ b/vendor/freetype/src/type1/t1load.c @@ -0,0 +1,2761 @@ +/**************************************************************************** + * + * t1load.c + * + * Type 1 font loader (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This is the new and improved Type 1 data loader for FreeType 2. The + * old loader has several problems: it is slow, complex, difficult to + * maintain, and contains incredible hacks to make it accept some + * ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of + * the Type 1 fonts on my machine still aren't loaded correctly by it. + * + * This version is much simpler, much faster and also easier to read and + * maintain by a great order of magnitude. The idea behind it is to + * _not_ try to read the Type 1 token stream with a state machine (i.e. + * a Postscript-like interpreter) but rather to perform simple pattern + * matching. + * + * Indeed, nearly all data definitions follow a simple pattern like + * + * ... /Field ... + * + * where can be a number, a boolean, a string, or an array of + * numbers. There are a few exceptions, namely the encoding, font name, + * charstrings, and subrs; they are handled with a special pattern + * matching routine. + * + * All other common cases are handled very simply. The matching rules + * are defined in the file `t1tokens.h' through the use of several + * macros calls PARSE_XXX. This file is included twice here; the first + * time to generate parsing callback functions, the second time to + * generate a table of keywords (with pointers to the associated + * callback functions). + * + * The function `parse_dict' simply scans *linearly* a given dictionary + * (either the top-level or private one) and calls the appropriate + * callback when it encounters an immediate keyword. + * + * This is by far the fastest way one can find to parse and read all + * data. + * + * This led to tremendous code size reduction. Note that later, the + * glyph loader will also be _greatly_ simplified, and the automatic + * hinter will replace the clumsy `t1hinter'. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include + +#include "t1load.h" +#include "t1errors.h" + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL +#define IS_INCREMENTAL \ + FT_BOOL( FT_FACE( face )->internal->incremental_interface ) +#else +#define IS_INCREMENTAL 0 +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1load + + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SUPPORT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + t1_allocate_blend( T1_Face face, + FT_UInt num_designs, + FT_UInt num_axis ) + { + PS_Blend blend; + FT_Memory memory = face->root.memory; + FT_Error error = FT_Err_Ok; + + + blend = face->blend; + if ( !blend ) + { + if ( FT_NEW( blend ) ) + goto Exit; + + blend->num_default_design_vector = 0; + blend->weight_vector = NULL; + blend->default_weight_vector = NULL; + blend->design_pos[0] = NULL; + + face->blend = blend; + } + + /* allocate design data if needed */ + if ( num_designs > 0 ) + { + if ( blend->num_designs == 0 ) + { + FT_UInt nn; + + + /* allocate the blend `private' and `font_info' dictionaries */ + if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || + FT_NEW_ARRAY( blend->privates [1], num_designs ) || + FT_NEW_ARRAY( blend->bboxes [1], num_designs ) ) + goto Exit; + + blend->font_infos[0] = &face->type1.font_info; + blend->privates [0] = &face->type1.private_dict; + blend->bboxes [0] = &face->type1.font_bbox; + + for ( nn = 2; nn <= num_designs; nn++ ) + { + blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; + blend->privates [nn] = blend->privates [nn - 1] + 1; + blend->bboxes [nn] = blend->bboxes [nn - 1] + 1; + } + + blend->num_designs = num_designs; + } + else if ( blend->num_designs != num_designs ) + goto Fail; + } + + /* allocate axis data if needed */ + if ( num_axis > 0 ) + { + if ( blend->num_axis != 0 && blend->num_axis != num_axis ) + goto Fail; + + blend->num_axis = num_axis; + } + + Exit: + return error; + + Fail: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Multi_Master( FT_Face face, /* T1_Face */ + FT_Multi_Master* master ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + FT_UInt n; + FT_Error error; + + + error = FT_THROW( Invalid_Argument ); + + if ( blend ) + { + master->num_axis = blend->num_axis; + master->num_designs = blend->num_designs; + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_MM_Axis* axis = master->axis + n; + PS_DesignMap map = blend->design_map + n; + + + axis->name = blend->axis_names[n]; + axis->minimum = map->design_points[0]; + axis->maximum = map->design_points[map->num_points - 1]; + } + + error = FT_Err_Ok; + } + + return error; + } + + + /************************************************************************** + * + * Given a normalized (blend) coordinate, figure out the design + * coordinate appropriate for that value. + */ + static FT_Fixed + mm_axis_unmap( PS_DesignMap axismap, + FT_Fixed ncv ) + { + int j; + + + if ( ncv <= axismap->blend_points[0] ) + return INT_TO_FIXED( axismap->design_points[0] ); + + for ( j = 1; j < axismap->num_points; j++ ) + { + if ( ncv <= axismap->blend_points[j] ) + return INT_TO_FIXED( axismap->design_points[j - 1] + + FT_MulDiv( ncv - axismap->blend_points[j - 1], + axismap->design_points[j] - + axismap->design_points[j - 1], + axismap->blend_points[j] - + axismap->blend_points[j - 1] ) ); + } + + return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); + } + + + /************************************************************************** + * + * Given a vector of weights, one for each design, figure out the + * normalized axis coordinates which gave rise to those weights. + */ + static void + mm_weights_unmap( FT_Fixed* weights, + FT_Fixed* axiscoords, + FT_UInt axis_count ) + { + FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); + + if ( axis_count == 1 ) + axiscoords[0] = weights[1]; + + else if ( axis_count == 2 ) + { + axiscoords[0] = weights[3] + weights[1]; + axiscoords[1] = weights[3] + weights[2]; + } + + else if ( axis_count == 3 ) + { + axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; + } + + else + { + axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + + weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + + weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[7] + weights[6] + weights[5] + weights[4]; + axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[11] + weights[10] + weights[9] + weights[8]; + } + } + + + /************************************************************************** + * + * Just a wrapper around T1_Get_Multi_Master to support the different + * arguments needed by the GX var distortable fonts. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Var( FT_Face face, /* T1_Face */ + FT_MM_Var* *master ) + { + T1_Face t1face = (T1_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_MM_Var *mmvar = NULL; + FT_Multi_Master mmaster; + FT_Error error; + FT_UInt i; + FT_Fixed axiscoords[T1_MAX_MM_AXIS]; + PS_Blend blend = t1face->blend; + FT_UShort* axis_flags; + + FT_Offset mmvar_size; + FT_Offset axis_flags_size; + FT_Offset axis_size; + + + error = T1_Get_Multi_Master( face, &mmaster ); + if ( error ) + goto Exit; + + /* the various `*_size' variables, which we also use as */ + /* offsets into the `mmvar' array, must be multiples of the */ + /* pointer size (except the last one); without such an */ + /* alignment there might be runtime errors due to */ + /* misaligned addresses */ +#undef ALIGN_SIZE +#define ALIGN_SIZE( n ) \ + ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) + + mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); + axis_flags_size = ALIGN_SIZE( mmaster.num_axis * + sizeof ( FT_UShort ) ); + axis_size = mmaster.num_axis * sizeof ( FT_Var_Axis ); + + if ( FT_QALLOC( mmvar, mmvar_size + + axis_flags_size + + axis_size ) ) + goto Exit; + + mmvar->num_axis = mmaster.num_axis; + mmvar->num_designs = mmaster.num_designs; + mmvar->num_namedstyles = 0; /* Not supported */ + + /* while axis flags are meaningless here, we have to provide the array */ + /* to make `FT_Get_Var_Axis_Flags' work: the function expects that the */ + /* values directly follow the data of `FT_MM_Var' */ + axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size ); + FT_ARRAY_ZERO( axis_flags, mmaster.num_axis ); + + mmvar->axis = (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); + mmvar->namedstyle = NULL; + + for ( i = 0; i < mmaster.num_axis; i++ ) + { + mmvar->axis[i].name = mmaster.axis[i].name; + mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum ); + mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum ); + mmvar->axis[i].strid = ~0U; /* Does not apply */ + mmvar->axis[i].tag = ~0U; /* Does not apply */ + + if ( !mmvar->axis[i].name ) + continue; + + if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); + else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Slant" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 's', 'l', 'n', 't' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Italic" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'i', 't', 'a', 'l' ); + } + + mm_weights_unmap( blend->default_weight_vector, + axiscoords, + blend->num_axis ); + + for ( i = 0; i < mmaster.num_axis; i++ ) + mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], + axiscoords[i] ); + + *master = mmvar; + + Exit: + return error; + } + + + static FT_Error + t1_set_mm_blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + PS_Blend blend = face->blend; + FT_UInt n, m; + + FT_Bool have_diff = 0; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( num_coords > blend->num_axis ) + num_coords = blend->num_axis; + + /* recompute the weight vector from the blend coordinates */ + for ( n = 0; n < blend->num_designs; n++ ) + { + FT_Fixed result = 0x10000L; /* 1.0 fixed */ + FT_Fixed factor; + + + for ( m = 0; m < blend->num_axis; m++ ) + { + /* use a default value if we don't have a coordinate */ + if ( m >= num_coords ) + { + result >>= 1; + continue; + } + + /* get current blend axis position */ + factor = coords[m]; + if ( ( n & ( 1 << m ) ) == 0 ) + factor = 0x10000L - factor; + + if ( factor <= 0 ) + { + result = 0; + break; + } + else if ( factor >= 0x10000L ) + continue; + + result = FT_MulFix( result, factor ); + } + + if ( blend->weight_vector[n] != result ) + { + blend->weight_vector[n] = result; + have_diff = 1; + } + } + + /* return value -1 indicates `no change' */ + return have_diff ? FT_Err_Ok : -1; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Blend( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + return t1_set_mm_blend( (T1_Face)face, num_coords, coords ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Blend( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + + FT_Fixed axiscoords[4]; + FT_UInt i, nc; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + mm_weights_unmap( blend->weight_vector, + axiscoords, + blend->num_axis ); + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "T1_Get_MM_Blend: only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + for ( i = 0; i < nc; i++ ) + coords[i] = axiscoords[i]; + for ( ; i < num_coords; i++ ) + coords[i] = 0x8000; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_WeightVector( FT_Face face, /* T1_Face */ + FT_UInt len, + FT_Fixed* weightvector ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + FT_UInt i, n; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( !len && !weightvector ) + { + for ( i = 0; i < blend->num_designs; i++ ) + blend->weight_vector[i] = blend->default_weight_vector[i]; + } + else + { + if ( !weightvector ) + return FT_THROW( Invalid_Argument ); + + n = len < blend->num_designs ? len : blend->num_designs; + + for ( i = 0; i < n; i++ ) + blend->weight_vector[i] = weightvector[i]; + + for ( ; i < blend->num_designs; i++ ) + blend->weight_vector[i] = (FT_Fixed)0; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_WeightVector( FT_Face face, /* T1_Face */ + FT_UInt* len, + FT_Fixed* weightvector ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + FT_UInt i; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( *len < blend->num_designs ) + { + *len = blend->num_designs; + return FT_THROW( Invalid_Argument ); + } + + for ( i = 0; i < blend->num_designs; i++ ) + weightvector[i] = blend->weight_vector[i]; + for ( ; i < *len; i++ ) + weightvector[i] = (FT_Fixed)0; + + *len = blend->num_designs; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Design( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Long* coords ) + { + T1_Face t1face = (T1_Face)face; + FT_Error error; + PS_Blend blend = t1face->blend; + FT_UInt n; + FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( num_coords > blend->num_axis ) + num_coords = blend->num_axis; + + /* compute the blend coordinates through the blend design map */ + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_Long design; + FT_Fixed the_blend; + PS_DesignMap map = blend->design_map + n; + FT_Long* designs = map->design_points; + FT_Fixed* blends = map->blend_points; + FT_Int p, before = -1, after = -1; + + + /* use a default value if we don't have a coordinate */ + if ( n < num_coords ) + design = coords[n]; + else + design = ( designs[map->num_points - 1] - designs[0] ) / 2; + + for ( p = 0; p < (FT_Int)map->num_points; p++ ) + { + FT_Long p_design = designs[p]; + + + /* exact match? */ + if ( design == p_design ) + { + the_blend = blends[p]; + goto Found; + } + + if ( design < p_design ) + { + after = p; + break; + } + + before = p; + } + + /* now interpolate if necessary */ + if ( before < 0 ) + the_blend = blends[0]; + + else if ( after < 0 ) + the_blend = blends[map->num_points - 1]; + + else + the_blend = FT_MulDiv( design - designs[before], + blends [after] - blends [before], + designs[after] - designs[before] ); + + Found: + final_blends[n] = the_blend; + } + + error = t1_set_mm_blend( t1face, blend->num_axis, final_blends ); + if ( error ) + return error; + + return FT_Err_Ok; + } + + + /* MM fonts don't have named instances, so only the design is reset */ + + FT_LOCAL_DEF( FT_Error ) + T1_Reset_MM_Blend( FT_Face face, + FT_UInt instance_index ) + { + FT_UNUSED( instance_index ); + + return T1_Set_MM_Blend( face, 0, NULL ); + } + + + /************************************************************************** + * + * Just a wrapper around T1_Set_MM_Design to support the different + * arguments needed by the GX var distortable fonts. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Set_Var_Design( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Long lcoords[T1_MAX_MM_AXIS]; + FT_UInt i; + + + if ( num_coords > T1_MAX_MM_AXIS ) + num_coords = T1_MAX_MM_AXIS; + + for ( i = 0; i < num_coords; i++ ) + lcoords[i] = FIXED_TO_INT( coords[i] ); + + return T1_Set_MM_Design( face, num_coords, lcoords ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Var_Design( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + + FT_Fixed axiscoords[4]; + FT_UInt i, nc; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + mm_weights_unmap( blend->weight_vector, + axiscoords, + blend->num_axis ); + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "T1_Get_Var_Design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + for ( i = 0; i < nc; i++ ) + coords[i] = mm_axis_unmap( &blend->design_map[i], axiscoords[i] ); + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + T1_Done_Blend( FT_Face face ) /* T1_Face */ + { + T1_Face t1face = (T1_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_Blend blend = t1face->blend; + + + if ( blend ) + { + FT_UInt num_designs = blend->num_designs; + FT_UInt num_axis = blend->num_axis; + FT_UInt n; + + + /* release design pos table */ + FT_FREE( blend->design_pos[0] ); + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = NULL; + + /* release blend `private' and `font info' dictionaries */ + FT_FREE( blend->privates[1] ); + FT_FREE( blend->font_infos[1] ); + FT_FREE( blend->bboxes[1] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->privates [n] = NULL; + blend->font_infos[n] = NULL; + blend->bboxes [n] = NULL; + } + + /* release weight vectors */ + FT_FREE( blend->weight_vector ); + blend->default_weight_vector = NULL; + + /* release axis names */ + for ( n = 0; n < num_axis; n++ ) + FT_FREE( blend->axis_names[n] ); + + /* release design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap dmap = blend->design_map + n; + + + FT_FREE( dmap->design_points ); + dmap->num_points = 0; + } + + FT_FREE( t1face->blend ); + } + } + + + static void + parse_blend_axis_types( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Error error = FT_Err_Ok; + PS_Blend blend; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + /* take an array of objects */ + T1_ToTokenArray( &loader->parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", + num_axis )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* allocate blend if necessary */ + error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); + if ( error ) + goto Exit; + + FT_TRACE4(( " [" )); + + blend = t1face->blend; + + /* each token is an immediate containing the name of the axis */ + for ( n = 0; n < num_axis; n++ ) + { + T1_Token token = axis_tokens + n; + FT_Byte* name; + FT_UInt len; + + + /* skip first slash, if any */ + if ( token->start[0] == '/' ) + token->start++; + + len = (FT_UInt)( token->limit - token->start ); + if ( len == 0 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_TRACE4(( " /%.*s", len, token->start )); + + name = (FT_Byte*)blend->axis_names[n]; + if ( name ) + { + FT_TRACE0(( "parse_blend_axis_types:" + " overwriting axis name `%s' with `%.*s'\n", + name, len, token->start )); + FT_FREE( name ); + } + + if ( FT_QALLOC( blend->axis_names[n], len + 1 ) ) + goto Exit; + + name = (FT_Byte*)blend->axis_names[n]; + FT_MEM_COPY( name, token->start, len ); + name[len] = '\0'; + } + + FT_TRACE4(( "]\n" )); + + Exit: + loader->parser.root.error = error; + } + + + static void + parse_blend_design_positions( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Int num_axis = 0; /* make compiler happy */ + T1_Parser parser = &loader->parser; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + + + design_pos[0] = NULL; + + /* get the array of design tokens -- compute number of designs */ + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_blend_design_positions:" + " incorrect number of designs: %d\n", + num_designs )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + { + FT_Byte* old_cursor = parser->root.cursor; + FT_Byte* old_limit = parser->root.limit; + FT_Int n, nn; + PS_Blend blend; + + + FT_TRACE4(( " [" )); + + for ( n = 0; n < num_designs; n++ ) + { + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + T1_Token token; + FT_Int axis, n_axis; + + + /* read axis/coordinates tokens */ + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); + + if ( n == 0 ) + { + if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_positions:" + " invalid number of axes: %d\n", + n_axis )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + num_axis = n_axis; + error = t1_allocate_blend( t1face, + (FT_UInt)num_designs, + (FT_UInt)num_axis ); + if ( error ) + goto Exit; + + /* allocate a blend design pos table */ + if ( FT_QNEW_ARRAY( design_pos[0], num_designs * num_axis ) ) + goto Exit; + + for ( nn = 1; nn < num_designs; nn++ ) + design_pos[nn] = design_pos[0] + num_axis * nn; + } + else if ( n_axis != num_axis ) + { + FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* now read each axis token into the design position */ + FT_TRACE4(( " [" )) ; + for ( axis = 0; axis < n_axis; axis++ ) + { + T1_Token token2 = axis_tokens + axis; + + + parser->root.cursor = token2->start; + parser->root.limit = token2->limit; + design_pos[n][axis] = T1_ToFixed( parser, 0 ); + FT_TRACE4(( " %f", (double)design_pos[n][axis] / 65536 )); + } + FT_TRACE4(( "]" )) ; + } + + FT_TRACE4(( "]\n" )); + + loader->parser.root.cursor = old_cursor; + loader->parser.root.limit = old_limit; + + /* a valid BlendDesignPosition has been parsed */ + blend = t1face->blend; + if ( blend->design_pos[0] ) + FT_FREE( blend->design_pos[0] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->design_pos[n] = design_pos[n]; + design_pos[n] = NULL; + } + } + + Exit: + FT_FREE( design_pos[0] ); + loader->parser.root.error = error; + } + + + static void + parse_blend_design_map( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + FT_Error error = FT_Err_Ok; + T1_Parser parser = &loader->parser; + PS_Blend blend; + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Byte* old_cursor; + FT_Byte* old_limit; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + T1_ToTokenArray( parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", + num_axis )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + + error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); + if ( error ) + goto Exit; + blend = t1face->blend; + + FT_TRACE4(( " [" )); + + /* now read each axis design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap map = blend->design_map + n; + T1_Token axis_token; + T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; + FT_Int p, num_points; + + + axis_token = axis_tokens + n; + + parser->root.cursor = axis_token->start; + parser->root.limit = axis_token->limit; + T1_ToTokenArray( parser, point_tokens, + T1_MAX_MM_MAP_POINTS, &num_points ); + + FT_TRACE4(( " [" )); + + if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( map->design_points ) + { + FT_ERROR(( "parse_blend_design_map: duplicate table\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* allocate design map data */ + if ( FT_QNEW_ARRAY( map->design_points, num_points * 2 ) ) + goto Exit; + map->blend_points = map->design_points + num_points; + map->num_points = (FT_Byte)num_points; + + for ( p = 0; p < num_points; p++ ) + { + T1_Token point_token; + + + point_token = point_tokens + p; + + /* don't include delimiting brackets */ + parser->root.cursor = point_token->start + 1; + parser->root.limit = point_token->limit - 1; + + map->design_points[p] = T1_ToInt( parser ); + map->blend_points [p] = T1_ToFixed( parser, 0 ); + + FT_TRACE4(( " [%ld %f]", + map->design_points[p], + (double)map->blend_points[p] / 65536 )); + } + + FT_TRACE4(( "]" )); + } + + FT_TRACE4(( "]\n" )); + + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + + Exit: + parser->root.error = error; + } + + + static void + parse_weight_vector( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_FACE_MEMORY( face ); + T1_Parser parser = &loader->parser; + PS_Blend blend = t1face->blend; + T1_Token token; + FT_Int n; + FT_Byte* old_cursor; + FT_Byte* old_limit; + + + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_weight_vector:" + " incorrect number of designs: %d\n", + num_designs )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( !blend || !blend->num_designs ) + { + error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 ); + if ( error ) + goto Exit; + blend = t1face->blend; + } + else if ( blend->num_designs != (FT_UInt)num_designs ) + { + FT_ERROR(( "parse_weight_vector:" + " /BlendDesignPosition and /WeightVector have\n" )); + FT_ERROR(( " " + " different number of elements\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( !blend->weight_vector ) + if ( FT_QNEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) + goto Exit; + + blend->default_weight_vector = blend->weight_vector + num_designs; + + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + + FT_TRACE4(( "[" )); + + for ( n = 0; n < num_designs; n++ ) + { + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + + blend->default_weight_vector[n] = + blend->weight_vector[n] = T1_ToFixed( parser, 0 ); + + FT_TRACE4(( " %f", (double)blend->weight_vector[n] / 65536 )); + } + + FT_TRACE4(( "]\n" )); + + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + + Exit: + parser->root.error = error; + } + + + /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ + /* we're only interested in the number of array elements */ + static void + parse_buildchar( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + + + t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser, + 0, NULL, 0 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + FT_TRACE4(( " [" )); + for ( i = 0; i < t1face->len_buildchar; i++ ) + FT_TRACE4(( " 0" )); + + FT_TRACE4(( "]\n" )); + } +#endif + + return; + } + + +#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + t1_load_keyword( T1_Face face, + T1_Loader loader, + const T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects; + PS_Blend blend = face->blend; + + + if ( blend && blend->num_designs == 0 ) + blend = NULL; + + /* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + FT_TRACE4(( " %s", field->ident )); + + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } + + /* now, the keyword is either a simple field, or a table of fields; */ + /* we are now going to take care of it */ + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->font_infos; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_FONT_EXTRA: + dummy_object = &face->type1.font_extra; + objects = &dummy_object; + max_objects = 0; + break; + + case T1_FIELD_LOCATION_PRIVATE: + dummy_object = &face->type1.private_dict; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->privates; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->bboxes; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_LOADER: + dummy_object = loader; + objects = &dummy_object; + max_objects = 0; + break; + + case T1_FIELD_LOCATION_FACE: + dummy_object = face; + objects = &dummy_object; + max_objects = 0; + break; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + case T1_FIELD_LOCATION_BLEND: + dummy_object = face->blend; + objects = &dummy_object; + max_objects = 0; + break; +#endif + + default: + dummy_object = &face->type1; + objects = &dummy_object; + max_objects = 0; + } + + FT_TRACE4(( " %s", field->ident )); + + if ( *objects ) + { + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + } + else + { + FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'" + " which is not valid at this point\n", + field->ident )); + FT_TRACE1(( " (probably due to missing keywords)\n" )); + error = FT_Err_Ok; + } + + FT_TRACE4(( "\n" )); + + Exit: + return error; + } + + + static void + parse_private( FT_Face face, + void* loader_ ) + { + T1_Loader loader = (T1_Loader)loader_; + FT_UNUSED( face ); + + loader->keywords_encountered |= T1_PRIVATE; + + FT_TRACE4(( "\n" )); + } + + + /* return 1 in case of success */ + + static int + read_binary_data( T1_Parser parser, + FT_ULong* size, + FT_Byte** base, + FT_Bool incremental ) + { + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + + /* the binary data has one of the following formats */ + /* */ + /* `size' [white*] RD white ....... ND */ + /* `size' [white*] -| white ....... |- */ + /* */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + + if ( cur < limit && ft_isdigit( *cur ) ) + { + FT_Long s = T1_ToInt( parser ); + + + T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ + + /* there is only one whitespace char after the */ + /* `RD' or `-|' token */ + *base = parser->root.cursor + 1; + + if ( s >= 0 && s < limit - *base ) + { + parser->root.cursor += s + 1; + *size = (FT_ULong)s; + return !parser->root.error; + } + } + + if( !incremental ) + { + FT_ERROR(( "read_binary_data: invalid size field\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + } + + return 0; + } + + + /* We now define the routines to handle the `/Encoding', `/Subrs', */ + /* and `/CharStrings' dictionaries. */ + + static void + t1_parse_font_matrix( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + FT_Matrix* matrix = &t1face->type1.font_matrix; + FT_Vector* offset = &t1face->type1.font_offset; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + FT_Int result; + + + /* input is scaled by 1000 to accommodate default FontMatrix */ + result = T1_ToFixedArray( parser, 6, temp, 3 ); + + if ( result < 6 ) + { + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + FT_TRACE4(( " [%f %f %f %f %f %f]\n", + (double)temp[0] / 65536 / 1000, + (double)temp[1] / 65536 / 1000, + (double)temp[2] / 65536 / 1000, + (double)temp[3] / 65536 / 1000, + (double)temp[4] / 65536 / 1000, + (double)temp[5] / 65536 / 1000 )); + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* atypical case */ + if ( temp_scale != 0x10000L ) + { + /* set units per EM based on FontMatrix values */ + face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); + + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; + } + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + + static void + parse_encoding( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + PSAux_Service psaux = (PSAux_Service)t1face->psaux; + + + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "parse_encoding: out of bounds\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* if we have a number or `[', the encoding is an array, */ + /* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &t1face->type1.encoding; + FT_Int count, array_size, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; + + + /* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_Int)T1_ToInt( parser ); + + array_size = count; + if ( count > 256 ) + { + FT_TRACE2(( "parse_encoding:" + " only using first 256 encoding array entries\n" )); + array_size = 256; + } + + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; + + /* PostScript happily allows overwriting of encoding arrays */ + if ( encode->char_index ) + { + FT_FREE( encode->char_index ); + FT_FREE( encode->char_name ); + T1_Release_Table( char_table ); + } + + /* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = array_size; + if ( FT_QNEW_ARRAY( encode->char_index, array_size ) || + FT_QNEW_ARRAY( encode->char_name, array_size ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, array_size, memory ) ) ) + { + parser->root.error = error; + return; + } + + /* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < array_size; n++ ) + (void)T1_Add_Table( char_table, n, ".notdef", 8 ); + + /* Now we need to read records of the form */ + /* */ + /* ... charcode /charname ... */ + /* */ + /* for each entry in our table. */ + /* */ + /* We simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type1 fonts: */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else. */ + /* */ + /* Alternatively, if the array is directly given as */ + /* */ + /* /Encoding [ ... ] */ + /* */ + /* we only read immediates. */ + + n = 0; + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + + /* we stop when we encounter a `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + IS_PS_DELIM( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } + + /* check whether we've found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + + + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + + /* protect against invalid charcode */ + if ( cur == parser->root.cursor ) + { + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + + cur = parser->root.cursor; + + if ( cur + 2 < limit && *cur == '/' && n < count ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + return; + if ( parser->root.error ) + return; + + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( n < array_size ) + { + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + } + + n++; + } + else if ( only_immediates ) + { + /* Since the current position is not updated for */ + /* immediates-only mode we would get an infinite loop if */ + /* we don't do anything here. */ + /* */ + /* This encoding array is not valid according to the type1 */ + /* specification (it might be an encoding for a CID type1 */ + /* font, however), so we conclude that this font is NOT a */ + /* type1 font. */ + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + + T1_Skip_Spaces( parser ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " [" )); + + /* XXX show encoding vector */ + FT_TRACE4(( "..." )); + + FT_TRACE4(( "]\n" )); +#endif + + t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } + + /* Otherwise, we should have either `StandardEncoding', */ + /* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + { + t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + FT_TRACE4(( " StandardEncoding\n" )); + } + + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + { + t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + FT_TRACE4(( " ExpertEncoding\n" )); + } + + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + { + t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + FT_TRACE4(( " ISOLatin1Encoding\n" )); + } + + else + { + parser->root.error = FT_ERR( Ignore ); + FT_TRACE4(( "\n" )); + } + } + } + + + static void + parse_subrs( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + PS_Table table = &loader->subrs; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Int num_subrs; + FT_UInt count; + + PSAux_Service psaux = (PSAux_Service)t1face->psaux; + + + T1_Skip_Spaces( parser ); + + /* test for empty array */ + if ( parser->root.cursor < parser->root.limit && + *parser->root.cursor == '[' ) + { + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + if ( parser->root.cursor >= parser->root.limit || + *parser->root.cursor != ']' ) + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + num_subrs = (FT_Int)T1_ToInt( parser ); + if ( num_subrs < 0 ) + { + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* we certainly need more than 8 bytes per subroutine */ + if ( parser->root.limit >= parser->root.cursor && + num_subrs > ( parser->root.limit - parser->root.cursor ) >> 3 ) + { + /* + * There are two possibilities. Either the font contains an invalid + * value for `num_subrs', or we have a subsetted font where the + * subroutine indices are not adjusted, e.g. + * + * /Subrs 812 array + * dup 0 { ... } NP + * dup 51 { ... } NP + * dup 681 { ... } NP + * ND + * + * In both cases, we use a number hash that maps from subr indices to + * actual array elements. + */ + + FT_TRACE0(( "parse_subrs: adjusting number of subroutines" + " (from %d to %zu)\n", + num_subrs, + ( parser->root.limit - parser->root.cursor ) >> 3 )); + num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3; + + if ( !loader->subrs_hash ) + { + if ( FT_QNEW( loader->subrs_hash ) ) + goto Fail; + + error = ft_hash_num_init( loader->subrs_hash, memory ); + if ( error ) + goto Fail; + } + } + + /* position the parser right before the `dup' of the first subr */ + T1_Skip_PS_Token( parser ); /* `array' */ + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + + /* initialize subrs array -- with synthetic fonts it is possible */ + /* we get here twice */ + if ( !loader->num_subrs ) + { + error = psaux->ps_table_funcs->init( table, num_subrs, memory ); + if ( error ) + goto Fail; + } + + /* the format is simple: */ + /* */ + /* `index' + binary data */ + /* */ + for ( count = 0; ; count++ ) + { + FT_Long idx; + FT_ULong size; + FT_Byte* base; + + + /* If we are out of data, or if the next token isn't `dup', */ + /* we are done. */ + if ( parser->root.cursor + 4 >= parser->root.limit || + ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) + break; + + T1_Skip_PS_Token( parser ); /* `dup' */ + + idx = T1_ToInt( parser ); + + if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) + return; + + /* The binary string is followed by one token, e.g. `NP' */ + /* (bound to `noaccess put') or by two separate tokens: */ + /* `noaccess' & `put'. We position the parser right */ + /* before the next `dup', if any. */ + T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ + if ( parser->root.error ) + return; + T1_Skip_Spaces ( parser ); + + if ( parser->root.cursor + 4 < parser->root.limit && + ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) + { + T1_Skip_PS_Token( parser ); /* skip `put' */ + T1_Skip_Spaces ( parser ); + } + + /* if we use a hash, the subrs index is the key, and a running */ + /* counter specified for `T1_Add_Table' acts as the value */ + if ( loader->subrs_hash ) + { + ft_hash_num_insert( idx, count, loader->subrs_hash, memory ); + idx = count; + } + + /* with synthetic fonts it is possible we get here twice */ + if ( loader->num_subrs ) + continue; + + /* some fonts use a value of -1 for lenIV to indicate that */ + /* the charstrings are unencoded */ + /* */ + /* thanks to Tom Kacvinsky for pointing this out */ + /* */ + if ( t1face->type1.private_dict.lenIV >= 0 ) + { + FT_Byte* temp = NULL; + + + /* some fonts define empty subr records -- this is not totally */ + /* compliant to the specification (which says they should at */ + /* least contain a `return'), but we support them anyway */ + if ( size < (FT_ULong)t1face->type1.private_dict.lenIV ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_QALLOC( temp, size ) ) + goto Fail; + FT_MEM_COPY( temp, base, size ); + psaux->t1_decrypt( temp, size, 4330 ); + size -= (FT_ULong)t1face->type1.private_dict.lenIV; + error = T1_Add_Table( table, + (FT_Int)idx, + temp + t1face->type1.private_dict.lenIV, + size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( table, (FT_Int)idx, base, size ); + if ( error ) + goto Fail; + } + + if ( !loader->num_subrs ) + loader->num_subrs = num_subrs; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " <" )); + + /* XXX show subrs? */ + FT_TRACE4(( "%d elements", num_subrs )); + + FT_TRACE4(( ">\n" )); +#endif + + return; + + Fail: + parser->root.error = error; + } + + +#define TABLE_EXTEND 5 + + + static void + parse_charstrings( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)t1face->psaux; + + FT_Byte* cur = parser->root.cursor; + FT_Byte* limit = parser->root.limit; + FT_Int n, num_glyphs; + FT_Int notdef_index = 0; + FT_Byte notdef_found = 0; + + + num_glyphs = (FT_Int)T1_ToInt( parser ); + if ( num_glyphs < 0 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* we certainly need more than 8 bytes per glyph */ + if ( num_glyphs > ( limit - cur ) >> 3 ) + { + FT_TRACE0(( "parse_charstrings: adjusting number of glyphs" + " (from %d to %zu)\n", + num_glyphs, ( limit - cur ) >> 3 )); + num_glyphs = ( limit - cur ) >> 3; + } + + /* some fonts like Optima-Oblique not only define the /CharStrings */ + /* array but access it also */ + if ( num_glyphs == 0 || parser->root.error ) + return; + + /* initialize tables, leaving space for addition of .notdef, */ + /* if necessary, and a few other glyphs to handle buggy */ + /* fonts which have more glyphs than specified. */ + + /* for some non-standard fonts like `Optima' which provides */ + /* different outlines depending on the resolution it is */ + /* possible to get here twice */ + if ( !loader->num_glyphs ) + { + error = psaux->ps_table_funcs->init( + code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; + + error = psaux->ps_table_funcs->init( + name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; + + /* Initialize table for swapping index notdef_index and */ + /* index 0 names and codes (if necessary). */ + + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + } + + n = 0; + + for (;;) + { + FT_ULong size; + FT_Byte* base; + + + /* the format is simple: */ + /* `/glyphname' + binary data */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + if ( cur >= limit ) + break; + + /* we stop when we find a `def' or `end' keyword */ + if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) + { + if ( cur[0] == 'd' && + cur[1] == 'e' && + cur[2] == 'f' ) + { + /* There are fonts which have this: */ + /* */ + /* /CharStrings 118 dict def */ + /* Private begin */ + /* CharStrings begin */ + /* ... */ + /* */ + /* To catch this we ignore `def' if */ + /* no charstring has actually been */ + /* seen. */ + if ( n ) + break; + } + + if ( cur[0] == 'e' && + cur[1] == 'n' && + cur[2] == 'd' ) + break; + } + + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + if ( parser->root.error ) + return; + + if ( *cur == '/' ) + { + FT_UInt len; + + + if ( cur + 2 >= limit ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + cur++; /* skip `/' */ + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) + return; + + /* for some non-standard fonts like `Optima' which provides */ + /* different outlines depending on the resolution it is */ + /* possible to get here twice */ + if ( loader->num_glyphs ) + continue; + + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + /* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)( name_table->elements[n] ) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + + if ( t1face->type1.private_dict.lenIV >= 0 && + n < num_glyphs + TABLE_EXTEND ) + { + FT_Byte* temp = NULL; + + + if ( size <= (FT_ULong)t1face->type1.private_dict.lenIV ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_QALLOC( temp, size ) ) + goto Fail; + FT_MEM_COPY( temp, base, size ); + psaux->t1_decrypt( temp, size, 4330 ); + size -= (FT_ULong)t1face->type1.private_dict.lenIV; + error = T1_Add_Table( code_table, + n, + temp + t1face->type1.private_dict.lenIV, + size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( code_table, n, base, size ); + if ( error ) + goto Fail; + + n++; + } + } + + if ( !n ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + loader->num_glyphs = n; + + /* if /.notdef is found but does not occupy index 0, do our magic. */ + if ( notdef_found && + ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) + { + /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ + /* name and code entries to swap_table. Then place notdef_index */ + /* name and code entries into swap_table. Then swap name and code */ + /* entries at indices notdef_index and 0 using values stored in */ + /* swap_table. */ + + /* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + /* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + + } + else if ( !notdef_found ) + { + /* notdef_index is already 0, or /.notdef is undefined in */ + /* charstrings dictionary. Worry about /.notdef undefined. */ + /* We take index 0 and add it to the end of the table(s) */ + /* and add our own /.notdef glyph to index 0. */ + + /* 0 333 hsbw endchar */ + FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E }; + + + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, ".notdef", 8 ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); + + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, n, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, n, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + /* we added a glyph. */ + loader->num_glyphs += 1; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " <" )); + + /* XXX show charstrings? */ + FT_TRACE4(( "%d elements", loader->num_glyphs )); + + FT_TRACE4(( ">\n" )); +#endif + + return; + + Fail: + parser->root.error = error; + } + + + /************************************************************************** + * + * Define the token field static variables. This is a set of + * T1_FieldRec variables. + * + */ + + + static + const T1_FieldRec t1_keywords[] = + { + +#include "t1tokens.h" + + /* now add the special functions... */ + T1_FIELD_CALLBACK( "FontMatrix", t1_parse_font_matrix, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Encoding", parse_encoding, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Subrs", parse_subrs, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "CharStrings", parse_charstrings, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "Private", parse_private, + T1_FIELD_DICT_FONTDICT ) + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar, + T1_FIELD_DICT_PRIVATE ) +#endif + + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; + + + static FT_Error + parse_dict( T1_Face face, + T1_Loader loader, + FT_Byte* base, + FT_ULong size ) + { + T1_Parser parser = &loader->parser; + FT_Byte *limit, *start_binary = NULL; + FT_Bool have_integer = 0; + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = FT_Err_Ok; + + limit = parser->root.limit; + + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + + + cur = parser->root.cursor; + + /* look for `eexec' */ + if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) + break; + + /* look for `closefile' which ends the eexec section */ + else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) + break; + + /* in a synthetic font the base font starts after a */ + /* `FontDictionary' token that is placed after a Private dict */ + else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) + { + if ( loader->keywords_encountered & T1_PRIVATE ) + loader->keywords_encountered |= + T1_FONTDIR_AFTER_PRIVATE; + parser->root.cursor += 13; + } + + /* check whether we have an integer */ + else if ( ft_isdigit( *cur ) ) + { + start_binary = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 1; + } + + /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ + /* since those tokens are handled by parse_subrs and */ + /* parse_charstrings */ + else if ( *cur == 'R' && cur + 6 < limit && *( cur + 1 ) == 'D' && + have_integer ) + { + FT_ULong s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) + return FT_THROW( Invalid_File_Format ); + have_integer = 0; + } + + else if ( *cur == '-' && cur + 6 < limit && *( cur + 1 ) == '|' && + have_integer ) + { + FT_ULong s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) + return FT_THROW( Invalid_File_Format ); + have_integer = 0; + } + + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { + /* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)t1_keywords; + + + for (;;) + { + FT_Byte* name; + + + name = (FT_Byte*)keyword->ident; + if ( !name ) + break; + + if ( cur[0] == name[0] && + len == ft_strlen( (const char *)name ) && + ft_memcmp( cur, name, len ) == 0 ) + { + /* We found it -- run the parsing callback! */ + /* We record every instance of every field */ + /* (until we reach the base font of a */ + /* synthetic font) to deal adequately with */ + /* multiple master fonts; this is also */ + /* necessary because later PostScript */ + /* definitions override earlier ones. */ + + /* Once we encounter `FontDirectory' after */ + /* `/Private', we know that this is a synthetic */ + /* font; except for `/CharStrings' we are not */ + /* interested in anything that follows this */ + /* `FontDirectory'. */ + + /* MM fonts have more than one /Private token at */ + /* the top level; let's hope that all the junk */ + /* that follows the first /Private token is not */ + /* interesting to us. */ + + /* According to Adobe Tech Note #5175 (CID-Keyed */ + /* Font Installation for ATM Software) a `begin' */ + /* must be followed by exactly one `end', and */ + /* `begin' -- `end' pairs must be accurately */ + /* paired. We could use this to distinguish */ + /* between the global Private and the Private */ + /* dict that is a member of the Blend dict. */ + + const FT_UInt dict = + ( loader->keywords_encountered & T1_PRIVATE ) + ? T1_FIELD_DICT_PRIVATE + : T1_FIELD_DICT_FONTDICT; + + + if ( !( dict & keyword->dict ) ) + { + FT_TRACE1(( "parse_dict: found `%s' but ignoring it" + " since it is in the wrong dictionary\n", + keyword->ident )); + break; + } + + if ( !( loader->keywords_encountered & + T1_FONTDIR_AFTER_PRIVATE ) || + ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) + { + parser->root.error = t1_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + { + if ( FT_ERR_EQ( parser->root.error, Ignore ) ) + parser->root.error = FT_Err_Ok; + else + return parser->root.error; + } + } + break; + } + + keyword++; + } + } + + have_integer = 0; + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 0; + } + + T1_Skip_Spaces( parser ); + } + + Exit: + return parser->root.error; + } + + + static void + t1_init_loader( T1_Loader loader, + T1_Face face ) + { + FT_UNUSED( face ); + + FT_ZERO( loader ); + } + + + static void + t1_done_loader( T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; + + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); + T1_Release_Table( &loader->subrs ); + + /* finalize hash */ + ft_hash_num_free( loader->subrs_hash, memory ); + FT_FREE( loader->subrs_hash ); + + /* finalize parser */ + T1_Finalize_Parser( parser ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Open_Face( T1_Face face ) + { + T1_LoaderRec loader; + T1_Parser parser; + T1_Font type1 = &face->type1; + PS_Private priv = &type1->private_dict; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t1_init_loader( &loader, face ); + + /* default values */ + face->ndv_idx = -1; + face->cdv_idx = -1; + face->len_buildchar = 0; + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = 4; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + + parser = &loader.parser; + error = T1_New_Parser( parser, + face->root.stream, + face->root.memory, + psaux ); + if ( error ) + goto Exit; + + FT_TRACE4(( " top dictionary:\n" )); + error = parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + + error = T1_Get_Private_Dict( parser, psaux ); + if ( error ) + goto Exit; + + FT_TRACE4(( " private dictionary:\n" )); + error = parse_dict( face, &loader, + parser->private_dict, parser->private_len ); + if ( error ) + goto Exit; + + /* ensure even-ness of `num_blue_values' */ + priv->num_blue_values &= ~1; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + /* we don't support Multiple Master fonts with intermediate designs; */ + /* this implies that `num_designs' must be equal to `2^^num_axis' */ + if ( face->blend && + face->blend->num_designs != ( 1U << face->blend->num_axis ) ) + { + FT_ERROR(( "T1_Open_Face:" + " number-of-designs != 2 ^^ number-of-axes\n" )); + T1_Done_Blend( FT_FACE( face ) ); + } + + if ( face->blend && + face->blend->num_default_design_vector != 0 && + face->blend->num_default_design_vector != face->blend->num_axis ) + { + /* we don't use it currently so just warn, reset, and ignore */ + FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " + "while there are %u axes.\n", + face->blend->num_default_design_vector, + face->blend->num_axis )); + + face->blend->num_default_design_vector = 0; + } + + /* the following can happen for MM instances; we then treat the */ + /* font as a normal PS font */ + if ( face->blend && + ( !face->blend->num_designs || !face->blend->num_axis ) ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid WeightVector */ + if ( face->blend && !face->blend->weight_vector ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid BlendDesignPositions */ + if ( face->blend && !face->blend->design_pos[0] ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid BlendDesignMap */ + if ( face->blend ) + { + FT_UInt i; + + + for ( i = 0; i < face->blend->num_axis; i++ ) + if ( !face->blend->design_map[i].num_points ) + { + T1_Done_Blend( FT_FACE( face ) ); + break; + } + } + + if ( face->blend ) + { + if ( face->len_buildchar > 0 ) + { + FT_Memory memory = face->root.memory; + + + if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) + { + FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); + face->len_buildchar = 0; + goto Exit; + } + } + } + else + face->len_buildchar = 0; + +#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + /* now, propagate the subrs, charstrings, and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( loader.subrs.init ) + { + type1->num_subrs = loader.num_subrs; + type1->subrs_block = loader.subrs.block; + type1->subrs = loader.subrs.elements; + type1->subrs_len = loader.subrs.lengths; + type1->subrs_hash = loader.subrs_hash; + + /* prevent `t1_done_loader' from freeing the propagated data */ + loader.subrs.init = 0; + loader.subrs_hash = NULL; + } + + if ( !IS_INCREMENTAL ) + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" )); + error = FT_THROW( Invalid_File_Format ); + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = NULL; + loader.glyph_names.elements = NULL; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* the index is then stored in type1.encoding.char_index, and */ + /* the name to type1.encoding.char_name */ + + min_char = 0; + max_char = 0; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + const FT_String* char_name = + (const FT_String*)loader.encoding_table.elements[charcode]; + + + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = ".notdef"; + + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + const FT_String* glyph_name = type1->glyph_names[idx]; + + + if ( ft_strcmp( char_name, glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( ".notdef", glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode >= max_char ) + max_char = charcode + 1; + } + break; + } + } + } + + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + /* some sanitizing to avoid overflows later on; */ + /* the upper limits are ad-hoc values */ + if ( priv->blue_shift > 1000 || priv->blue_shift < 0 ) + { + FT_TRACE2(( "T1_Open_Face:" + " setting unlikely BlueShift value %d to default (7)\n", + priv->blue_shift )); + priv->blue_shift = 7; + } + + if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 ) + { + FT_TRACE2(( "T1_Open_Face:" + " setting unlikely BlueFuzz value %d to default (1)\n", + priv->blue_fuzz )); + priv->blue_fuzz = 1; + } + + Exit: + t1_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/type1/t1load.h b/vendor/freetype/src/type1/t1load.h new file mode 100644 index 0000000..d8c9d2d --- /dev/null +++ b/vendor/freetype/src/type1/t1load.h @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * t1load.h + * + * Type 1 font loader (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1LOAD_H_ +#define T1LOAD_H_ + + +#include +#include +#include + +#include "t1parse.h" + + +FT_BEGIN_HEADER + + + typedef struct T1_Loader_ + { + T1_ParserRec parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + PS_TableRec encoding_table; /* PS_Table used to store the */ + /* encoding character names */ + + FT_Int num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; + PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */ + + FT_Int num_subrs; + PS_TableRec subrs; + FT_Hash subrs_hash; + FT_Bool fontdata; + + FT_UInt keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */ + + } T1_LoaderRec, *T1_Loader; + + + /* treatment of some keywords differs depending on whether */ + /* they precede or follow certain other keywords */ + +#define T1_PRIVATE ( 1 << 0 ) +#define T1_FONTDIR_AFTER_PRIVATE ( 1 << 1 ) + + + FT_LOCAL( FT_Error ) + T1_Open_Face( T1_Face face ); + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + FT_LOCAL( FT_Error ) + T1_Get_Multi_Master( FT_Face face, + FT_Multi_Master* master ); + + FT_LOCAL( FT_Error ) + T1_Get_MM_Var( FT_Face face, + FT_MM_Var* *master ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + T1_Get_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_Design( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + FT_LOCAL( FT_Error ) + T1_Reset_MM_Blend( FT_Face face, + FT_UInt instance_index ); + + FT_LOCAL( FT_Error ) + T1_Get_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + T1_Set_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( void ) + T1_Done_Blend( FT_Face face ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ); + + FT_LOCAL( FT_Error ) + T1_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ); + +#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + +FT_END_HEADER + +#endif /* T1LOAD_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1objs.c b/vendor/freetype/src/type1/t1objs.c new file mode 100644 index 0000000..69e4fd5 --- /dev/null +++ b/vendor/freetype/src/type1/t1objs.c @@ -0,0 +1,655 @@ +/**************************************************************************** + * + * t1objs.c + * + * Type 1 objects manager (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "t1gload.h" +#include "t1load.h" + +#include "t1errors.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.h" +#endif + +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1objs + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + + + static PSH_Globals_Funcs + T1_Size_Get_Globals_Funcs( T1_Size size ) + { + T1_Face face = (T1_Face)size->root.face; + PSHinter_Service pshinter = (PSHinter_Service)face->pshinter; + FT_Module module; + + + module = FT_Get_Module( size->root.face->driver->root.library, + "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + T1_Size_Done( FT_Size t1size ) /* T1_Size */ + { + T1_Size size = (T1_Size)t1size; + + + if ( t1size->internal->module_data ) + { + PSH_Globals_Funcs funcs; + + + funcs = T1_Size_Get_Globals_Funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)t1size->internal->module_data ); + + t1size->internal->module_data = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Size_Init( FT_Size t1size ) /* T1_Size */ + { + T1_Size size = (T1_Size)t1size; + FT_Error error = FT_Err_Ok; + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + + + if ( funcs ) + { + PSH_Globals globals; + T1_Face face = (T1_Face)size->root.face; + + + error = funcs->create( size->root.face->memory, + &face->type1.private_dict, &globals ); + if ( !error ) + t1size->internal->module_data = globals; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Size_Request( FT_Size t1size, /* T1_Size */ + FT_Size_Request req ) + { + FT_Error error; + + T1_Size size = (T1_Size)t1size; + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + + + error = FT_Request_Metrics( size->root.face, req ); + if ( error ) + goto Exit; + + if ( funcs ) + funcs->set_scale( (PSH_Globals)t1size->internal->module_data, + size->root.metrics.x_scale, + size->root.metrics.y_scale, + 0, 0 ); + + Exit: + return error; + } + + + /************************************************************************** + * + * SLOT FUNCTIONS + * + */ + + FT_LOCAL_DEF( void ) + T1_GlyphSlot_Done( FT_GlyphSlot slot ) + { + /* `slot->internal` might be NULL in out-of-memory situations. */ + if ( slot->internal ) + slot->internal->glyph_hints = NULL; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_GlyphSlot_Init( FT_GlyphSlot slot ) + { + T1_Face face; + PSHinter_Service pshinter; + + + face = (T1_Face)slot->face; + pshinter = (PSHinter_Service)face->pshinter; + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->library, "pshinter" ); + if ( module ) + { + T1_Hints_Funcs funcs; + + + funcs = pshinter->get_t1_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return 0; + } + + + /************************************************************************** + * + * FACE FUNCTIONS + * + */ + + + /************************************************************************** + * + * @Function: + * T1_Face_Done + * + * @Description: + * The face object destructor. + * + * @Input: + * face :: + * A typeless pointer to the face object to destroy. + */ + FT_LOCAL_DEF( void ) + T1_Face_Done( FT_Face t1face ) /* T1_Face */ + { + T1_Face face = (T1_Face)t1face; + FT_Memory memory; + T1_Font type1; + + + if ( !face ) + return; + + memory = face->root.memory; + type1 = &face->type1; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + /* release multiple masters information */ + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + if ( face->buildchar ) + { + FT_FREE( face->buildchar ); + + face->len_buildchar = 0; + } + + T1_Done_Blend( t1face ); + face->blend = NULL; +#endif + + /* release font info strings */ + { + PS_FontInfo info = &type1->font_info; + + + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + } + + /* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + + FT_FREE( type1->subrs ); + FT_FREE( type1->subrs_len ); + + ft_hash_num_free( type1->subrs_hash, memory ); + FT_FREE( type1->subrs_hash ); + + FT_FREE( type1->subrs_block ); + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + +#ifndef T1_CONFIG_OPTION_NO_AFM + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data ); +#endif + + /* release unicode map, if any */ +#if 0 + FT_FREE( face->unicode_map_rec.maps ); + face->unicode_map_rec.num_maps = 0; + face->unicode_map = NULL; +#endif + + face->root.family_name = NULL; + face->root.style_name = NULL; + } + + + /************************************************************************** + * + * @Function: + * T1_Face_Init + * + * @Description: + * The face object constructor. + * + * @Input: + * stream :: + * Dummy argument for compatibility with the `FT_Face_InitFunc` API. + * Ignored. The stream should be passed through `face->root.stream`. + * + * face_index :: + * The index of the font face in the resource. + * + * num_params :: + * Number of additional generic parameters. Ignored. + * + * params :: + * Additional generic parameters. Ignored. + * + * @InOut: + * face :: + * The face record to build. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Face_Init( FT_Stream stream, + FT_Face t1face, /* T1_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + T1_Face face = (T1_Face)t1face; + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + + + face->root.num_faces = 1; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + FT_ERROR(( "T1_Face_Init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + face->pshinter = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "pshinter" ); + + FT_TRACE2(( "Type 1 driver\n" )); + + /* open the tokenizer; this will also check the font format */ + error = T1_Open_Face( face ); + if ( error ) + goto Exit; + + FT_TRACE2(( "T1_Face_Init: %p (index %d)\n", + (void *)face, + face_index )); + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "T1_Face_Init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* now load the font program into the face object */ + + /* initialize the face object fields */ + + /* set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + + + root->num_glyphs = type1->num_glyphs; + root->face_index = 0; + + root->face_flags |= FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES | + FT_FACE_FLAG_HINTER; + + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( face->blend ) + root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; + + /* The following code to extract the family and the style is very */ + /* simplistic and might get some things wrong. For a full-featured */ + /* algorithm you might have a look at the whitepaper given at */ + /* */ + /* https://blogs.msdn.com/text/archive/2007/04/23/wpf-font-selection-model.aspx */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; + root->style_name = NULL; + + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + + + if ( full ) + { + FT_Bool the_same = TRUE; + + + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + the_same = FALSE; + + if ( !*family ) + root->style_name = full; + break; + } + } + } + + if ( the_same ) + root->style_name = (char *)"Regular"; + } + } + else + { + /* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } + + if ( !root->style_name ) + { + if ( info->weight ) + root->style_name = info->weight; + else + /* assume `Regular' style because we don't know better */ + root->style_name = (char *)"Regular"; + } + + /* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( info->weight ) + { + if ( !ft_strcmp( info->weight, "Bold" ) || + !ft_strcmp( info->weight, "Black" ) ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = NULL; + + root->bbox.xMin = type1->font_bbox.xMin >> 16; + root->bbox.yMin = type1->font_bbox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + root->bbox.xMax = ( type1->font_bbox.xMax + 0xFFFF ) >> 16; + root->bbox.yMax = ( type1->font_bbox.yMax + 0xFFFF ) >> 16; + + /* Set units_per_EM if we didn't set it in t1_parse_font_matrix. */ + if ( !root->units_per_EM ) + root->units_per_EM = 1000; + + root->ascender = (FT_Short)( root->bbox.yMax ); + root->descender = (FT_Short)( root->bbox.yMin ); + + root->height = (FT_Short)( ( root->units_per_EM * 12 ) / 10 ); + if ( root->height < root->ascender - root->descender ) + root->height = (FT_Short)( root->ascender - root->descender ); + + /* now compute the maximum advance width */ + root->max_advance_width = + (FT_Short)( root->bbox.xMax ); + { + FT_Pos max_advance; + + + error = T1_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if ( !error ) + root->max_advance_width = (FT_Short)FIXED_TO_INT( max_advance ); + else + error = FT_Err_Ok; /* clear error */ + } + + root->max_advance_height = root->height; + + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; + } + + { + FT_Face root = &face->root; + + + if ( psnames ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + + + charmap.face = root; + + /* first of all, try to synthesize a Unicode charmap */ + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + + error = FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + + /* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = TT_PLATFORM_ADOBE; + clazz = NULL; + + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + clazz = cmap_classes->standard; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = TT_ADOBE_ID_EXPERT; + clazz = cmap_classes->expert; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = TT_ADOBE_ID_CUSTOM; + clazz = cmap_classes->custom; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = TT_ADOBE_ID_LATIN_1; + clazz = cmap_classes->unicode; + break; + + default: + ; + } + + if ( clazz ) + error = FT_CMap_New( clazz, NULL, &charmap, NULL ); + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * T1_Driver_Init + * + * @Description: + * Initializes a given Type 1 driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Driver_Init( FT_Module module ) + { + PS_Driver driver = (PS_Driver)module; + + FT_UInt32 seed; + + + /* set default property values, cf. `ftt1drv.h' */ + driver->hinting_engine = FT_HINTING_ADOBE; + + driver->no_stem_darkening = TRUE; + + driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&module ^ + (FT_Offset)(char*)module->memory ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + + driver->random_seed = (FT_Int32)seed; + if ( driver->random_seed < 0 ) + driver->random_seed = -driver->random_seed; + else if ( driver->random_seed == 0 ) + driver->random_seed = 123456789; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * T1_Driver_Done + * + * @Description: + * Finalizes a given Type 1 driver. + * + * @Input: + * driver :: + * A handle to the target Type 1 driver. + */ + FT_LOCAL_DEF( void ) + T1_Driver_Done( FT_Module driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/vendor/freetype/src/type1/t1objs.h b/vendor/freetype/src/type1/t1objs.h new file mode 100644 index 0000000..03847b2 --- /dev/null +++ b/vendor/freetype/src/type1/t1objs.h @@ -0,0 +1,160 @@ +/**************************************************************************** + * + * t1objs.h + * + * Type 1 objects manager (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1OBJS_H_ +#define T1OBJS_H_ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + /* The following structures must be defined by the hinter */ + typedef struct T1_Size_Hints_ T1_Size_Hints; + typedef struct T1_Glyph_Hints_ T1_Glyph_Hints; + + + /************************************************************************** + * + * @Type: + * T1_Size + * + * @Description: + * A handle to a Type 1 size object. + */ + typedef struct T1_SizeRec_* T1_Size; + + + /************************************************************************** + * + * @Type: + * T1_GlyphSlot + * + * @Description: + * A handle to a Type 1 glyph slot object. + */ + typedef struct T1_GlyphSlotRec_* T1_GlyphSlot; + + + /************************************************************************** + * + * @Type: + * T1_CharMap + * + * @Description: + * A handle to a Type 1 character mapping object. + * + * @Note: + * The Type 1 format doesn't use a charmap but an encoding table. + * The driver is responsible for making up charmap objects + * corresponding to these tables. + */ + typedef struct T1_CharMapRec_* T1_CharMap; + + + /************************************************************************** + * + * HERE BEGINS THE TYPE1 SPECIFIC STUFF + * + */ + + + /************************************************************************** + * + * @Type: + * T1_SizeRec + * + * @Description: + * Type 1 size record. + */ + typedef struct T1_SizeRec_ + { + FT_SizeRec root; + + } T1_SizeRec; + + + FT_LOCAL( void ) + T1_Size_Done( FT_Size size ); + + FT_LOCAL( FT_Error ) + T1_Size_Request( FT_Size size, + FT_Size_Request req ); + + FT_LOCAL( FT_Error ) + T1_Size_Init( FT_Size size ); + + + /************************************************************************** + * + * @Type: + * T1_GlyphSlotRec + * + * @Description: + * Type 1 glyph slot record. + */ + typedef struct T1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + FT_Int max_points; + FT_Int max_contours; + + } T1_GlyphSlotRec; + + + FT_LOCAL( FT_Error ) + T1_Face_Init( FT_Stream stream, + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + T1_Face_Done( FT_Face face ); + + FT_LOCAL( FT_Error ) + T1_GlyphSlot_Init( FT_GlyphSlot slot ); + + FT_LOCAL( void ) + T1_GlyphSlot_Done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + T1_Driver_Init( FT_Module driver ); + + FT_LOCAL( void ) + T1_Driver_Done( FT_Module driver ); + + +FT_END_HEADER + +#endif /* T1OBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1parse.c b/vendor/freetype/src/type1/t1parse.c new file mode 100644 index 0000000..6dec6c1 --- /dev/null +++ b/vendor/freetype/src/type1/t1parse.c @@ -0,0 +1,487 @@ +/**************************************************************************** + * + * t1parse.c + * + * Type 1 parser (body). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * The Type 1 parser is in charge of the following: + * + * - provide an implementation of a growing sequence of objects called + * a `T1_Table' (used to build various tables needed by the loader). + * + * - opening .pfb and .pfa files to extract their top-level and private + * dictionaries. + * + * - read numbers, arrays & strings from any dictionary. + * + * See `t1load.c' to see how data is loaded from the font file. + * + */ + + +#include +#include +#include + +#include "t1parse.h" + +#include "t1errors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1parse + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* see Adobe Technical Note 5040.Download_Fonts.pdf */ + + static FT_Error + read_pfb_tag( FT_Stream stream, + FT_UShort *atag, + FT_ULong *asize ) + { + FT_Error error; + FT_UShort tag; + FT_ULong size; + + + *atag = 0; + *asize = 0; + + if ( !FT_READ_USHORT( tag ) ) + { + if ( tag == 0x8001U || tag == 0x8002U ) + { + if ( !FT_READ_ULONG_LE( size ) ) + *asize = size; + } + + *atag = tag; + } + + return error; + } + + + static FT_Error + check_type1_format( FT_Stream stream, + const char* header_string, + size_t header_length ) + { + FT_Error error; + FT_UShort tag; + FT_ULong dummy; + + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &dummy ); + if ( error ) + goto Exit; + + /* We assume that the first segment in a PFB is always encoded as */ + /* text. This might be wrong (and the specification doesn't insist */ + /* on that), but we have never seen a counterexample. */ + if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) ) + goto Exit; + + if ( !FT_FRAME_ENTER( header_length ) ) + { + error = FT_Err_Ok; + + if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 ) + error = FT_THROW( Unknown_File_Format ); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error; + FT_UShort tag; + FT_ULong size; + + + psaux->ps_parser_funcs->init( &parser->root, NULL, NULL, memory ); + + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = NULL; + parser->private_len = 0; + parser->private_dict = NULL; + parser->in_pfb = 0; + parser->in_memory = 0; + parser->single_block = 0; + + /* check the header format */ + error = check_type1_format( stream, "%!PS-AdobeFont", 14 ); + if ( error ) + { + if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) + goto Exit; + + error = check_type1_format( stream, "%!FontType", 10 ); + if ( error ) + { + FT_TRACE2(( " not a Type 1 font\n" )); + goto Exit; + } + } + + /******************************************************************* + * + * Here a short summary of what is going on: + * + * When creating a new Type 1 parser, we try to locate and load + * the base dictionary if this is possible (i.e., for PFB + * files). Otherwise, we load the whole font into memory. + * + * When `loading' the base dictionary, we only setup pointers + * in the case of a memory-based stream. Otherwise, we + * allocate and load the base dictionary in it. + * + * parser->in_pfb is set if we are in a binary (`.pfb') font. + * parser->in_memory is set if we have a memory stream. + */ + + /* try to compute the size of the base dictionary; */ + /* look for a Postscript binary file tag, i.e., 0x8001 */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Exit; + + if ( tag != 0x8001U ) + { + /* assume that this is a PFA file for now; an error will */ + /* be produced later when more things are checked */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + size = stream->size; + } + else + parser->in_pfb = 1; + + /* now, try to load `size' bytes of the `base' dictionary we */ + /* found previously */ + + /* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { + /* read segment in memory -- this is clumsy, but so does the format */ + if ( FT_QALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + parser->base_len = size; + } + + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + + return error; + } + + + FT_LOCAL_DEF( void ) + T1_Finalize_Parser( T1_Parser parser ) + { + FT_Memory memory = parser->root.memory; + + + /* always free the private dictionary */ + FT_FREE( parser->private_dict ); + + /* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + + parser->root.funcs.done( &parser->root ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ) + { + FT_Stream stream = parser->stream; + FT_Memory memory = parser->root.memory; + FT_Error error = FT_Err_Ok; + FT_ULong size; + + + if ( parser->in_pfb ) + { + /* in the case of the PFB format, the private dictionary can be */ + /* made of several segments. We thus first read the number of */ + /* segments to compute the total size of the private dictionary */ + /* then re-read them into memory. */ + FT_ULong start_pos = FT_STREAM_POS(); + FT_UShort tag; + + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Fail; + + if ( tag != 0x8002U ) + break; + + parser->private_len += size; + + if ( FT_STREAM_SKIP( size ) ) + goto Fail; + } + + /* Check that we have a private dictionary there */ + /* and allocate private dictionary buffer */ + if ( parser->private_len == 0 ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " invalid private dictionary section\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( FT_STREAM_SEEK( start_pos ) || + FT_QALLOC( parser->private_dict, parser->private_len ) ) + goto Fail; + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error || tag != 0x8002U ) + { + error = FT_Err_Ok; + break; + } + + if ( FT_STREAM_READ( parser->private_dict + parser->private_len, + size ) ) + goto Fail; + + parser->private_len += size; + } + } + else + { + /* We have already `loaded' the whole PFA font file into memory; */ + /* if this is a memory resource, allocate a new block to hold */ + /* the private dict. Otherwise, simply overwrite into the base */ + /* dictionary block in the heap. */ + + /* First look for the `eexec' keyword. Ensure `eexec' is real -- */ + /* it could be in a comment or string (as e.g. in u003043t.gsf */ + /* from ghostscript). */ + FT_Byte* cur = parser->base_dict; + FT_Byte* limit = cur + parser->base_len; + FT_Pointer pos_lf; + FT_Bool test_cr; + + + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->base_dict + parser->base_len; + + cur = parser->root.cursor; + limit = parser->root.limit; + + while ( cur < limit ) + { + /* 9 = 5 letters for `eexec' + whitespace + 4 chars */ + if ( cur[0] == 'e' && cur + 9 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'x' && + cur[3] == 'e' && + cur[4] == 'c' ) + goto Found; + } + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + break; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + + FT_ERROR(( "T1_Get_Private_Dict: could not find `eexec' keyword\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + + /* now determine where to write the _encrypted_ binary private */ + /* dictionary. We overwrite the base dictionary for disk-based */ + /* resources and allocate a new block otherwise */ + + Found: + parser->root.limit = parser->base_dict + parser->base_len; + + T1_Skip_PS_Token( parser ); + cur = parser->root.cursor; + limit = parser->root.limit; + + /* According to the Type 1 spec, the first cipher byte must not be */ + /* an ASCII whitespace character code (blank, tab, carriage return */ + /* or line feed). We have seen Type 1 fonts with two line feed */ + /* characters... So skip now all whitespace character codes. */ + /* */ + /* On the other hand, Adobe's Type 1 parser handles fonts just */ + /* fine that are violating this limitation, so we add a heuristic */ + /* test to stop at \r only if it is not used for EOL. */ + + pos_lf = ft_memchr( cur, '\n', (size_t)( limit - cur ) ); + test_cr = FT_BOOL( !pos_lf || + pos_lf > ft_memchr( cur, + '\r', + (size_t)( limit - cur ) ) ); + + while ( cur < limit && + ( *cur == ' ' || + *cur == '\t' || + (test_cr && *cur == '\r' ) || + *cur == '\n' ) ) + cur++; + if ( cur >= limit ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " `eexec' not properly terminated\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + size = parser->base_len - (FT_ULong)( cur - parser->base_dict ); + + if ( parser->in_memory ) + { + /* note that we allocate one more byte to put a terminating `0' */ + if ( FT_QALLOC( parser->private_dict, size + 1 ) ) + goto Fail; + parser->private_len = size; + } + else + { + parser->single_block = 1; + parser->private_dict = parser->base_dict; + parser->private_len = size; + parser->base_dict = NULL; + parser->base_len = 0; + } + + /* now determine whether the private dictionary is encoded in binary */ + /* or hexadecimal ASCII format -- decode it accordingly */ + + /* we need to access the next 4 bytes (after the final whitespace */ + /* following the `eexec' keyword); if they all are hexadecimal */ + /* digits, then we have a case of ASCII storage */ + + if ( cur + 3 < limit && + ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) && + ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) ) + { + /* ASCII hexadecimal encoding */ + FT_ULong len; + + + parser->root.cursor = cur; + (void)psaux->ps_parser_funcs->to_bytes( &parser->root, + parser->private_dict, + parser->private_len, + &len, + 0 ); + parser->private_len = len; + + /* put a safeguard */ + parser->private_dict[len] = '\0'; + } + else + /* binary encoding -- copy the private dict */ + FT_MEM_MOVE( parser->private_dict, cur, size ); + } + + /* we now decrypt the encoded binary private dictionary */ + psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U ); + + if ( parser->private_len < 4 ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " invalid private dictionary section\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* replace the four random bytes at the beginning with whitespace */ + parser->private_dict[0] = ' '; + parser->private_dict[1] = ' '; + parser->private_dict[2] = ' '; + parser->private_dict[3] = ' '; + + parser->root.base = parser->private_dict; + parser->root.cursor = parser->private_dict; + parser->root.limit = parser->root.cursor + parser->private_len; + + Fail: + Exit: + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/type1/t1parse.h b/vendor/freetype/src/type1/t1parse.h new file mode 100644 index 0000000..0d9a286 --- /dev/null +++ b/vendor/freetype/src/type1/t1parse.h @@ -0,0 +1,137 @@ +/**************************************************************************** + * + * t1parse.h + * + * Type 1 parser (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1PARSE_H_ +#define T1PARSE_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Struct: + * T1_ParserRec + * + * @Description: + * A PS_ParserRec is an object used to parse a Type 1 fonts very + * quickly. + * + * @Fields: + * root :: + * The root parser. + * + * stream :: + * The current input stream. + * + * base_dict :: + * A pointer to the top-level dictionary. + * + * base_len :: + * The length in bytes of the top dictionary. + * + * private_dict :: + * A pointer to the private dictionary. + * + * private_len :: + * The length in bytes of the private dictionary. + * + * in_pfb :: + * A boolean. Indicates that we are handling a PFB + * file. + * + * in_memory :: + * A boolean. Indicates a memory-based stream. + * + * single_block :: + * A boolean. Indicates that the private dictionary + * is stored in lieu of the base dictionary. + */ + typedef struct T1_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* base_dict; + FT_ULong base_len; + + FT_Byte* private_dict; + FT_ULong private_len; + + FT_Bool in_pfb; + FT_Bool in_memory; + FT_Bool single_block; + + } T1_ParserRec, *T1_Parser; + + +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) + + +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) + +#define T1_ToCoordArray( p, m, c ) \ + (p)->root.funcs.to_coord_array( &(p)->root, m, c ) +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define T1_ToTokenArray( p, t, m, c ) \ + (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) + +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) + +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) + + + FT_LOCAL( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ); + + FT_LOCAL( void ) + T1_Finalize_Parser( T1_Parser parser ); + + +FT_END_HEADER + +#endif /* T1PARSE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type1/t1tokens.h b/vendor/freetype/src/type1/t1tokens.h new file mode 100644 index 0000000..40f3609 --- /dev/null +++ b/vendor/freetype/src/type1/t1tokens.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * + * t1tokens.h + * + * Type 1 tokenizer (specification). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Notice", notice, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FullName", full_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FamilyName", family_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Weight", weight, + T1_FIELD_DICT_FONTDICT ) + + /* we use pointers to detect modifications made by synthetic fonts */ + T1_FIELD_NUM ( "ItalicAngle", italic_angle, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, + T1_FIELD_DICT_FONTDICT ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontExtraRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA + + T1_FIELD_NUM ( "FSType", fs_type, + T1_FIELD_DICT_FONTDICT ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_PrivateRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_PRIVATE + + T1_FIELD_NUM ( "UniqueID", unique_id, + T1_FIELD_DICT_FONTDICT | T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "lenIV", lenIV, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "LanguageGroup", language_group, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "password", password, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_FIXED_1000( "BlueScale", blue_scale, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueShift", blue_shift, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_FIXED ( "ExpansionFactor", expansion_factor, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_BOOL ( "ForceBold", force_bold, + T1_FIELD_DICT_PRIVATE ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_KEY ( "FontName", font_name, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "PaintType", paint_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "FontType", font_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, T1_FIELD_DICT_FONTDICT ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, T1_FIELD_DICT_FONTDICT ) + + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FaceRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FACE + + T1_FIELD_NUM( "NDV", ndv_idx, T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM( "CDV", cdv_idx, T1_FIELD_DICT_PRIVATE ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_BlendRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BLEND + + T1_FIELD_NUM_TABLE( "DesignVector", default_design_vector, + T1_MAX_MM_DESIGNS, T1_FIELD_DICT_FONTDICT ) + + +#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + +/* END */ diff --git a/vendor/freetype/src/type1/type1.c b/vendor/freetype/src/type1/type1.c new file mode 100644 index 0000000..d9bd8ca --- /dev/null +++ b/vendor/freetype/src/type1/type1.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * type1.c + * + * FreeType Type 1 driver component (body only). + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "t1afm.c" +#include "t1driver.c" +#include "t1gload.c" +#include "t1load.c" +#include "t1objs.c" +#include "t1parse.c" + + +/* END */ diff --git a/vendor/freetype/src/type42/module.mk b/vendor/freetype/src/type42/module.mk new file mode 100644 index 0000000..d98b123 --- /dev/null +++ b/vendor/freetype/src/type42/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 Type42 module definition +# + + +# Copyright (C) 2002-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += TYPE42_DRIVER + +define TYPE42_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, t42_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)type42 $(ECHO_DRIVER_DESC)Type 42 font files with no known extension$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/type42/rules.mk b/vendor/freetype/src/type42/rules.mk new file mode 100644 index 0000000..41cb358 --- /dev/null +++ b/vendor/freetype/src/type42/rules.mk @@ -0,0 +1,73 @@ +# +# FreeType 2 Type42 driver configuration rules +# + + +# Copyright (C) 2002-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Type42 driver directory +# +T42_DIR := $(SRC_DIR)/type42 + + +# compilation flags for the driver +# +T42_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(T42_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# Type42 driver source +# +T42_DRV_SRC := $(T42_DIR)/t42objs.c \ + $(T42_DIR)/t42parse.c \ + $(T42_DIR)/t42drivr.c + +# Type42 driver headers +# +T42_DRV_H := $(T42_DRV_SRC:%.c=%.h) \ + $(T42_DIR)/t42error.h \ + $(T42_DIR)/t42types.h + + +# Type42 driver object(s) +# +# T42_DRV_OBJ_M is used during `multi' builds +# T42_DRV_OBJ_S is used during `single' builds +# +T42_DRV_OBJ_M := $(T42_DRV_SRC:$(T42_DIR)/%.c=$(OBJ_DIR)/%.$O) +T42_DRV_OBJ_S := $(OBJ_DIR)/type42.$O + +# Type42 driver source file for single build +# +T42_DRV_SRC_S := $(T42_DIR)/type42.c + + +# Type42 driver - single object +# +$(T42_DRV_OBJ_S): $(T42_DRV_SRC_S) $(T42_DRV_SRC) $(FREETYPE_H) $(T42_DRV_H) + $(T42_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(T42_DRV_SRC_S)) + + +# Type42 driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(T42_DIR)/%.c $(FREETYPE_H) $(T42_DRV_H) + $(T42_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(T42_DRV_OBJ_S) +DRV_OBJS_M += $(T42_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/type42/t42drivr.c b/vendor/freetype/src/type42/t42drivr.c new file mode 100644 index 0000000..ee5fd44 --- /dev/null +++ b/vendor/freetype/src/type42/t42drivr.c @@ -0,0 +1,248 @@ +/**************************************************************************** + * + * t42drivr.c + * + * High-level Type 42 driver interface (body). + * + * Copyright (C) 2002-2023 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This driver implements Type42 fonts as described in the + * Technical Note #5012 from Adobe, with these limitations: + * + * 1) CID Fonts are not currently supported. + * 2) Incremental fonts making use of the GlyphDirectory keyword + * will be loaded, but the rendering will be using the TrueType + * tables. + * 3) As for Type1 fonts, CDevProc is not supported. + * 4) The Metrics dictionary is not supported. + * 5) AFM metrics are not supported. + * + * In other words, this driver supports Type42 fonts derived from + * TrueType fonts in a non-CID manner, as done by usual conversion + * programs. + * + */ + + +#include "t42drivr.h" +#include "t42objs.h" +#include "t42error.h" +#include + +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT t42 + + + /* + * + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + t42_get_glyph_name( FT_Face face, /* T42_Face */ + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + T42_Face t42face = (T42_Face)face; + + + FT_STRCPYN( buffer, + t42face->type1.glyph_names[glyph_index], + buffer_max ); + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t42_get_name_index( FT_Face face, /* T42_Face */ + const FT_String* glyph_name ) + { + T42_Face t42face = (T42_Face)face; + FT_Int i; + + + for ( i = 0; i < t42face->type1.num_glyphs; i++ ) + { + FT_String* gname = t42face->type1.glyph_names[i]; + + + if ( glyph_name[0] == gname[0] && !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)ft_strtol( + (const char *)t42face->type1.charstrings[i], + NULL, + 10 ); + } + + return 0; + } + + + static const FT_Service_GlyphDictRec t42_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) t42_get_glyph_name, /* get_name */ + (FT_GlyphDict_NameIndexFunc)t42_get_name_index /* name_index */ + }; + + + /* + * + * POSTSCRIPT NAME SERVICE + * + */ + + FT_CALLBACK_DEF( const char* ) + t42_get_ps_font_name( FT_Face face ) /* T42_Face */ + { + T42_Face t42face = (T42_Face)face; + + + return (const char*)t42face->type1.font_name; + } + + + static const FT_Service_PsFontNameRec t42_service_ps_font_name = + { + (FT_PsName_GetFunc)t42_get_ps_font_name /* get_ps_font_name */ + }; + + + /* + * + * POSTSCRIPT INFO SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + t42_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T42_Face)face)->type1.font_info; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + t42_ps_get_font_extra( FT_Face face, + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ((T42_Face)face)->type1.font_extra; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Int ) + t42_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + + return 1; + } + + + static const FT_Service_PsInfoRec t42_service_ps_info = + { + (PS_GetFontInfoFunc) t42_ps_get_font_info, /* ps_get_font_info */ + (PS_GetFontExtraFunc) t42_ps_get_font_extra, /* ps_get_font_extra */ + (PS_HasGlyphNamesFunc) t42_ps_has_glyph_names, /* ps_has_glyph_names */ + /* Type42 fonts don't have a Private dict */ + (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */ + /* not implemented */ + (PS_GetFontValueFunc) NULL /* ps_get_font_value */ + }; + + + /* + * + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec t42_services[] = + { + { FT_SERVICE_ID_GLYPH_DICT, &t42_service_glyph_dict }, + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t42_service_ps_font_name }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t42_service_ps_info }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TYPE_42 }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + T42_Get_Interface( FT_Module module, + const FT_String* t42_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( t42_services, t42_interface ); + } + + + const FT_Driver_ClassRec t42_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_MODULE_DRIVER_HAS_HINTER, +#else + 0, +#endif + + sizeof ( T42_DriverRec ), + + "type42", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + T42_Driver_Init, /* FT_Module_Constructor module_init */ + T42_Driver_Done, /* FT_Module_Destructor module_done */ + T42_Get_Interface, /* FT_Module_Requester get_interface */ + }, + + sizeof ( T42_FaceRec ), + sizeof ( T42_SizeRec ), + sizeof ( T42_GlyphSlotRec ), + + T42_Face_Init, /* FT_Face_InitFunc init_face */ + T42_Face_Done, /* FT_Face_DoneFunc done_face */ + T42_Size_Init, /* FT_Size_InitFunc init_size */ + T42_Size_Done, /* FT_Size_DoneFunc done_size */ + T42_GlyphSlot_Init, /* FT_Slot_InitFunc init_slot */ + T42_GlyphSlot_Done, /* FT_Slot_DoneFunc done_slot */ + + T42_GlyphSlot_Load, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + T42_Size_Request, /* FT_Size_RequestFunc request_size */ + T42_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/vendor/freetype/src/type42/t42drivr.h b/vendor/freetype/src/type42/t42drivr.h new file mode 100644 index 0000000..ec7da18 --- /dev/null +++ b/vendor/freetype/src/type42/t42drivr.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * t42drivr.h + * + * High-level Type 42 driver interface (specification). + * + * Copyright (C) 2002-2023 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42DRIVR_H_ +#define T42DRIVR_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t42_driver_class; + +FT_END_HEADER + + +#endif /* T42DRIVR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type42/t42error.h b/vendor/freetype/src/type42/t42error.h new file mode 100644 index 0000000..dcea9c4 --- /dev/null +++ b/vendor/freetype/src/type42/t42error.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * t42error.h + * + * Type 42 error codes (specification only). + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Type 42 error enumeration constants. + * + */ + +#ifndef T42ERROR_H_ +#define T42ERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX T42_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type42 + +#include + +#endif /* T42ERROR_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type42/t42objs.c b/vendor/freetype/src/type42/t42objs.c new file mode 100644 index 0000000..bf4028e --- /dev/null +++ b/vendor/freetype/src/type42/t42objs.c @@ -0,0 +1,698 @@ +/**************************************************************************** + * + * t42objs.c + * + * Type 42 objects manager (body). + * + * Copyright (C) 2002-2023 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t42objs.h" +#include "t42parse.h" +#include "t42error.h" +#include +#include +#include + + +#undef FT_COMPONENT +#define FT_COMPONENT t42 + + + static FT_Error + T42_Open_Face( T42_Face face ) + { + T42_LoaderRec loader; + T42_Parser parser; + T1_Font type1 = &face->type1; + FT_Memory memory = face->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t42_loader_init( &loader, face ); + + parser = &loader.parser; + + face->ttf_data = NULL; + face->ttf_size = 0; + + error = t42_parser_init( parser, + face->root.stream, + memory, + psaux); + if ( error ) + goto Exit; + + error = t42_parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + + if ( type1->font_type != 42 ) + { + FT_ERROR(( "T42_Open_Face: cannot handle FontType %d\n", + type1->font_type )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* now, propagate the charstrings and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T42_Open_Face: no charstrings array in face\n" )); + error = FT_THROW( Invalid_File_Format ); + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = NULL; + loader.glyph_names.elements = NULL; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* as defined in the CharStrings array. */ + /* The index is then stored in type1.encoding.char_index, and */ + /* the name in type1.encoding.char_name */ + + min_char = 0; + max_char = 0; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + const FT_String* char_name = + (const FT_String*)loader.encoding_table.elements[charcode]; + + + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = ".notdef"; + + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + const FT_String* glyph_name = type1->glyph_names[idx]; + + + if ( ft_strcmp( char_name, glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( ".notdef", glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode >= max_char ) + max_char = charcode + 1; + } + break; + } + } + } + + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t42_loader_done( &loader ); + if ( error ) + { + FT_FREE( face->ttf_data ); + face->ttf_size = 0; + } + return error; + } + + + /***************** Driver Functions *************/ + + + FT_LOCAL_DEF( FT_Error ) + T42_Face_Init( FT_Stream stream, + FT_Face t42face, /* T42_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + T42_Face face = (T42_Face)t42face; + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + FT_Face root = (FT_Face)&face->root; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + + + face->ttf_face = NULL; + face->root.num_faces = 1; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + FT_ERROR(( "T42_Face_Init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + FT_TRACE2(( "Type 42 driver\n" )); + + /* open the tokenizer, this will also check the font format */ + error = T42_Open_Face( face ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "T42_Face_Init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* Now load the font program into the face object */ + + /* Init the face object fields */ + /* Now set up root face fields */ + + root->num_glyphs = type1->num_glyphs; + root->num_charmaps = 0; + root->face_index = 0; + + root->face_flags |= FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES; + + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + root->face_flags |= FT_FACE_FLAG_HINTER; +#endif + + /* XXX: TODO -- add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; + /* assume "Regular" style if we don't know better */ + root->style_name = (char *)"Regular"; + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + + + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + root->style_name = full; + break; + } + } + } + } + } + else + { + /* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = NULL; + + /* Load the TTF font embedded in the T42 font */ + { + FT_Open_Args args; + + + args.flags = FT_OPEN_MEMORY | FT_OPEN_DRIVER; + args.driver = FT_Get_Module( FT_FACE_LIBRARY( face ), + "truetype" ); + args.memory_base = face->ttf_data; + args.memory_size = face->ttf_size; + + if ( num_params ) + { + args.flags |= FT_OPEN_PARAMS; + args.num_params = num_params; + args.params = params; + } + + error = FT_Open_Face( FT_FACE_LIBRARY( face ), + &args, 0, &face->ttf_face ); + } + + if ( error ) + goto Exit; + + FT_Done_Size( face->ttf_face->size ); + + /* Ignore info in FontInfo dictionary and use the info from the */ + /* loaded TTF font. The PostScript interpreter also ignores it. */ + root->bbox = face->ttf_face->bbox; + root->units_per_EM = face->ttf_face->units_per_EM; + + root->ascender = face->ttf_face->ascender; + root->descender = face->ttf_face->descender; + root->height = face->ttf_face->height; + + root->max_advance_width = face->ttf_face->max_advance_width; + root->max_advance_height = face->ttf_face->max_advance_height; + + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; + + /* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL ) + root->face_flags |= FT_FACE_FLAG_VERTICAL; + + { + if ( psnames ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + + + charmap.face = root; + + /* first of all, try to synthesize a Unicode charmap */ + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + + error = FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + + /* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = TT_PLATFORM_ADOBE; + clazz = NULL; + + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + clazz = cmap_classes->standard; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = TT_ADOBE_ID_EXPERT; + clazz = cmap_classes->expert; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = TT_ADOBE_ID_CUSTOM; + clazz = cmap_classes->custom; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = TT_ADOBE_ID_LATIN_1; + clazz = cmap_classes->unicode; + break; + + default: + ; + } + + if ( clazz ) + error = FT_CMap_New( clazz, NULL, &charmap, NULL ); + } + } + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + T42_Face_Done( FT_Face t42face ) + { + T42_Face face = (T42_Face)t42face; + T1_Font type1; + PS_FontInfo info; + FT_Memory memory; + + + if ( !face ) + return; + + type1 = &face->type1; + info = &type1->font_info; + memory = face->root.memory; + + /* delete internal ttf face prior to freeing face->ttf_data */ + if ( face->ttf_face ) + FT_Done_Face( face->ttf_face ); + + /* release font info strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + + /* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + + FT_FREE( face->ttf_data ); + +#if 0 + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); +#endif + + /* release unicode map, if any */ + FT_FREE( face->unicode_map.maps ); + face->unicode_map.num_maps = 0; + + face->root.family_name = NULL; + face->root.style_name = NULL; + } + + + /************************************************************************** + * + * @Function: + * T42_Driver_Init + * + * @Description: + * Initializes a given Type 42 driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + T42_Driver_Init( FT_Module module ) /* T42_Driver */ + { + T42_Driver driver = (T42_Driver)module; + FT_Module ttmodule; + + + ttmodule = FT_Get_Module( module->library, "truetype" ); + if ( !ttmodule ) + { + FT_ERROR(( "T42_Driver_Init: cannot access `truetype' module\n" )); + return FT_THROW( Missing_Module ); + } + + driver->ttclazz = (FT_Driver_Class)ttmodule->clazz; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + T42_Driver_Done( FT_Module module ) + { + FT_UNUSED( module ); + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Init( FT_Size size ) /* T42_Size */ + { + T42_Size t42size = (T42_Size)size; + FT_Face face = size->face; + T42_Face t42face = (T42_Face)face; + FT_Size ttsize; + FT_Error error; + + + error = FT_New_Size( t42face->ttf_face, &ttsize ); + if ( !error ) + t42size->ttsize = ttsize; + + FT_Activate_Size( ttsize ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Request( FT_Size t42size, /* T42_Size */ + FT_Size_Request req ) + { + T42_Size size = (T42_Size)t42size; + T42_Face face = (T42_Face)t42size->face; + FT_Error error; + + + FT_Activate_Size( size->ttsize ); + + error = FT_Request_Size( face->ttf_face, req ); + if ( !error ) + t42size->metrics = face->ttf_face->size->metrics; + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Select( FT_Size t42size, /* T42_Size */ + FT_ULong strike_index ) + { + T42_Size size = (T42_Size)t42size; + T42_Face face = (T42_Face)t42size->face; + FT_Error error; + + + FT_Activate_Size( size->ttsize ); + + error = FT_Select_Size( face->ttf_face, (FT_Int)strike_index ); + if ( !error ) + t42size->metrics = face->ttf_face->size->metrics; + + return error; + + } + + + FT_LOCAL_DEF( void ) + T42_Size_Done( FT_Size t42size ) /* T42_Size */ + { + T42_Size size = (T42_Size)t42size; + FT_Face face = t42size->face; + T42_Face t42face = (T42_Face)face; + FT_ListNode node; + + + node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize ); + if ( node ) + { + FT_Done_Size( size->ttsize ); + size->ttsize = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Init( FT_GlyphSlot t42slot ) /* T42_GlyphSlot */ + { + T42_GlyphSlot slot = (T42_GlyphSlot)t42slot; + FT_Face face = t42slot->face; + T42_Face t42face = (T42_Face)face; + FT_GlyphSlot ttslot; + FT_Memory memory = face->memory; + FT_Error error = FT_Err_Ok; + + + if ( !face->glyph ) + { + /* First glyph slot for this face */ + slot->ttslot = t42face->ttf_face->glyph; + } + else + { + error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot ); + if ( !error ) + slot->ttslot = ttslot; + } + + /* share the loader so that the autohinter can see it */ + FT_GlyphLoader_Done( slot->ttslot->internal->loader ); + FT_FREE( slot->ttslot->internal ); + slot->ttslot->internal = t42slot->internal; + + return error; + } + + + FT_LOCAL_DEF( void ) + T42_GlyphSlot_Done( FT_GlyphSlot t42slot ) /* T42_GlyphSlot */ + { + T42_GlyphSlot slot = (T42_GlyphSlot)t42slot; + + + /* do not destroy the inherited internal structure just yet */ + slot->ttslot->internal = NULL; + FT_Done_GlyphSlot( slot->ttslot ); + } + + + static void + t42_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* clear all public fields in the glyph slot */ + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + FT_ZERO( &slot->bitmap ); + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = NULL; + slot->control_data = NULL; + slot->control_len = 0; + slot->other = NULL; + slot->format = FT_GLYPH_FORMAT_NONE; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + T42_GlyphSlot t42slot = (T42_GlyphSlot)glyph; + T42_Size t42size = (T42_Size)size; + T42_Face t42face = (T42_Face)size->face; + FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz; + + + FT_TRACE1(( "T42_GlyphSlot_Load: glyph index %d\n", glyph_index )); + + /* map T42 glyph index to embedded TTF's glyph index */ + glyph_index = (FT_UInt)ft_strtol( + (const char *)t42face->type1.charstrings[glyph_index], + NULL, 10 ); + + t42_glyphslot_clear( t42slot->ttslot ); + error = ttclazz->load_glyph( t42slot->ttslot, + t42size->ttsize, + glyph_index, + load_flags | FT_LOAD_NO_BITMAP ); + + if ( !error ) + { + glyph->metrics = t42slot->ttslot->metrics; + + glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance; + glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance; + + glyph->format = t42slot->ttslot->format; + glyph->outline = t42slot->ttslot->outline; + + glyph->bitmap = t42slot->ttslot->bitmap; + glyph->bitmap_left = t42slot->ttslot->bitmap_left; + glyph->bitmap_top = t42slot->ttslot->bitmap_top; + + glyph->num_subglyphs = t42slot->ttslot->num_subglyphs; + glyph->subglyphs = t42slot->ttslot->subglyphs; + + glyph->control_data = t42slot->ttslot->control_data; + glyph->control_len = t42slot->ttslot->control_len; + } + + return error; + } + + +/* END */ diff --git a/vendor/freetype/src/type42/t42objs.h b/vendor/freetype/src/type42/t42objs.h new file mode 100644 index 0000000..33e6215 --- /dev/null +++ b/vendor/freetype/src/type42/t42objs.h @@ -0,0 +1,123 @@ +/**************************************************************************** + * + * t42objs.h + * + * Type 42 objects manager (specification). + * + * Copyright (C) 2002-2023 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42OBJS_H_ +#define T42OBJS_H_ + +#include +#include +#include +#include "t42types.h" +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + /* Type42 size */ + typedef struct T42_SizeRec_ + { + FT_SizeRec root; + FT_Size ttsize; + + } T42_SizeRec, *T42_Size; + + + /* Type42 slot */ + typedef struct T42_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + FT_GlyphSlot ttslot; + + } T42_GlyphSlotRec, *T42_GlyphSlot; + + + /* Type 42 driver */ + typedef struct T42_DriverRec_ + { + FT_DriverRec root; + FT_Driver_Class ttclazz; + + } T42_DriverRec, *T42_Driver; + + + /* */ + + + FT_LOCAL( FT_Error ) + T42_Face_Init( FT_Stream stream, + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + FT_LOCAL( void ) + T42_Face_Done( FT_Face face ); + + + FT_LOCAL( FT_Error ) + T42_Size_Init( FT_Size size ); + + + FT_LOCAL( FT_Error ) + T42_Size_Request( FT_Size size, + FT_Size_Request req ); + + + FT_LOCAL( FT_Error ) + T42_Size_Select( FT_Size size, + FT_ULong strike_index ); + + + FT_LOCAL( void ) + T42_Size_Done( FT_Size size ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Init( FT_GlyphSlot slot ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + FT_LOCAL( void ) + T42_GlyphSlot_Done( FT_GlyphSlot slot ); + + + FT_LOCAL( FT_Error ) + T42_Driver_Init( FT_Module module ); + + FT_LOCAL( void ) + T42_Driver_Done( FT_Module module ); + + /* */ + +FT_END_HEADER + + +#endif /* T42OBJS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type42/t42parse.c b/vendor/freetype/src/type42/t42parse.c new file mode 100644 index 0000000..f96a43b --- /dev/null +++ b/vendor/freetype/src/type42/t42parse.c @@ -0,0 +1,1355 @@ +/**************************************************************************** + * + * t42parse.c + * + * Type 42 font parser (body). + * + * Copyright (C) 2002-2023 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t42parse.h" +#include "t42error.h" +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t42 + + + static void + t42_parse_font_matrix( FT_Face face, + void* loader_ ); + static void + t42_parse_encoding( FT_Face face, + void* loader_ ); + + static void + t42_parse_charstrings( FT_Face face, + void* loader_ ); + + static void + t42_parse_sfnts( FT_Face face, + void* loader_ ); + + + /* as Type42 fonts have no Private dict, */ + /* we set the last argument of T1_FIELD_XXX to 0 */ + static const + T1_FieldRec t42_keywords[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontInfo +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, 0 ) + T1_FIELD_STRING( "Notice", notice, 0 ) + T1_FIELD_STRING( "FullName", full_name, 0 ) + T1_FIELD_STRING( "FamilyName", family_name, 0 ) + T1_FIELD_STRING( "Weight", weight, 0 ) + T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontExtraRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA + + T1_FIELD_NUM ( "FSType", fs_type, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_KEY ( "FontName", font_name, 0 ) + T1_FIELD_NUM ( "PaintType", paint_type, 0 ) + T1_FIELD_NUM ( "FontType", font_type, 0 ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, 0 ) + + T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix, 0 ) + T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding, 0 ) + T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 ) + T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts, 0 ) + + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; + + +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) + +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define T1_ToInt( p ) \ + (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToBytes( p, b, m, n, d ) \ + (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d ) + +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) + +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) + + + /********************* Parsing Functions ******************/ + + FT_LOCAL_DEF( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error = FT_Err_Ok; + FT_Long size; + + + psaux->ps_parser_funcs->init( &parser->root, NULL, NULL, memory ); + + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = NULL; + parser->in_memory = 0; + + /******************************************************************** + * + * Here a short summary of what is going on: + * + * When creating a new Type 42 parser, we try to locate and load + * the base dictionary, loading the whole font into memory. + * + * When `loading' the base dictionary, we only set up pointers + * in the case of a memory-based stream. Otherwise, we allocate + * and load the base dictionary in it. + * + * parser->in_memory is set if we have a memory stream. + */ + + if ( FT_STREAM_SEEK( 0L ) || + FT_FRAME_ENTER( 17 ) ) + goto Exit; + + if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) + { + FT_TRACE2(( " not a Type42 font\n" )); + error = FT_THROW( Unknown_File_Format ); + } + + FT_FRAME_EXIT(); + + if ( error || FT_STREAM_SEEK( 0 ) ) + goto Exit; + + size = (FT_Long)stream->size; + + /* now, try to load `size' bytes of the `base' dictionary we */ + /* found previously */ + + /* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { + /* read segment in memory */ + if ( FT_QALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + + parser->base_len = size; + } + + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + + return error; + } + + + FT_LOCAL_DEF( void ) + t42_parser_done( T42_Parser parser ) + { + FT_Memory memory = parser->root.memory; + + + /* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + + if ( parser->root.funcs.done ) + parser->root.funcs.done( &parser->root ); + } + + + static int + t42_is_space( FT_Byte c ) + { + return ( c == ' ' || c == '\t' || + c == '\r' || c == '\n' || c == '\f' || + c == '\0' ); + } + + + static void + t42_parse_font_matrix( FT_Face face, /* T42_Face */ + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + FT_Matrix* matrix = &t42face->type1.font_matrix; + FT_Vector* offset = &t42face->type1.font_offset; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + FT_Int result; + + + result = T1_ToFixedArray( parser, 6, temp, 0 ); + + if ( result < 6 ) + { + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* atypical case */ + if ( temp_scale != 0x10000L ) + { + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; + } + + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + + static void + t42_parse_encoding( FT_Face face, + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + PSAux_Service psaux = (PSAux_Service)t42face->psaux; + + + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "t42_parse_encoding: out of bounds\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* if we have a number or `[', the encoding is an array, */ + /* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &t42face->type1.encoding; + FT_Int count, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; + + + /* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_Int)T1_ToInt( parser ); + + /* only composite fonts (which we don't support) */ + /* can have larger values */ + if ( count > 256 ) + { + FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; + + /* PostScript happily allows overwriting of encoding arrays */ + if ( encode->char_index ) + { + FT_FREE( encode->char_index ); + FT_FREE( encode->char_name ); + T1_Release_Table( char_table ); + } + + /* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = count; + if ( FT_QNEW_ARRAY( encode->char_index, count ) || + FT_QNEW_ARRAY( encode->char_name, count ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, count, memory ) ) ) + { + parser->root.error = error; + return; + } + + /* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < count; n++ ) + (void)T1_Add_Table( char_table, n, ".notdef", 8 ); + + /* Now we need to read records of the form */ + /* */ + /* ... charcode /charname ... */ + /* */ + /* for each entry in our table. */ + /* */ + /* We simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type42 fonts: */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else. */ + /* */ + /* Alternatively, if the array is directly given as */ + /* */ + /* /Encoding [ ... ] */ + /* */ + /* we only read immediates. */ + + n = 0; + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + + /* we stop when we encounter `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + t42_is_space( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } + + /* check whether we have found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + + + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + + /* protect against invalid charcode */ + if ( cur == parser->root.cursor ) + { + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + + cur = parser->root.cursor; + + if ( cur + 2 < limit && *cur == '/' && n < count ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + return; + if ( parser->root.error ) + return; + + len = (FT_UInt)( parser->root.cursor - cur ); + + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + + n++; + } + else if ( only_immediates ) + { + /* Since the current position is not updated for */ + /* immediates-only mode we would get an infinite loop if */ + /* we don't do anything here. */ + /* */ + /* This encoding array is not valid according to the */ + /* type42 specification (it might be an encoding for a CID */ + /* type42 font, however), so we conclude that this font is */ + /* NOT a type42 font. */ + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + + T1_Skip_Spaces( parser ); + } + + t42face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } + + /* Otherwise, we should have either `StandardEncoding', */ + /* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + t42face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + t42face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + t42face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + + else + parser->root.error = FT_ERR( Ignore ); + } + } + + + typedef enum T42_Load_Status_ + { + BEFORE_START, + BEFORE_TABLE_DIR, + OTHER_TABLES + + } T42_Load_Status; + + + static void + t42_parse_sfnts( FT_Face face, + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Error error; + FT_Int num_tables = 0; + FT_Long ttf_count; + FT_Long ttf_reserved; + + FT_ULong n, string_size, old_string_size, real_size; + FT_Byte* string_buf = NULL; + FT_Bool allocated = 0; + + T42_Load_Status status; + + /** There should only be one sfnts array, but free any previous. */ + FT_FREE( t42face->ttf_data ); + t42face->ttf_size = 0; + + /* The format is */ + /* */ + /* /sfnts [ ... ] def */ + /* */ + /* or */ + /* */ + /* /sfnts [ */ + /* RD */ + /* RD */ + /* ... */ + /* ] def */ + /* */ + /* with exactly one space after the `RD' token. */ + + T1_Skip_Spaces( parser ); + + if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) + { + FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + T1_Skip_Spaces( parser ); + status = BEFORE_START; + string_size = 0; + old_string_size = 0; + ttf_count = 0; + ttf_reserved = 12; + if ( FT_QALLOC( t42face->ttf_data, ttf_reserved ) ) + goto Fail; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( "t42_parse_sfnts:\n" )); + + while ( parser->root.cursor < limit ) + { + FT_ULong size; + + + cur = parser->root.cursor; + + if ( *cur == ']' ) + { + parser->root.cursor++; + t42face->ttf_size = ttf_count; + goto Exit; + } + + else if ( *cur == '<' ) + { + if ( string_buf && !allocated ) + { + FT_ERROR(( "t42_parse_sfnts: " + "can't handle mixed binary and hex strings\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + /* don't include delimiters */ + string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); + if ( !string_size ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + if ( FT_QREALLOC( string_buf, old_string_size, string_size ) ) + goto Fail; + + allocated = 1; + + parser->root.cursor = cur; + (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); + old_string_size = string_size; + string_size = real_size; + } + + else if ( ft_isdigit( *cur ) ) + { + FT_Long tmp; + + + if ( allocated ) + { + FT_ERROR(( "t42_parse_sfnts: " + "can't handle mixed binary and hex strings\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + tmp = T1_ToInt( parser ); + if ( tmp < 0 ) + { + FT_ERROR(( "t42_parse_sfnts: invalid string size\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + else + string_size = (FT_ULong)tmp; + + T1_Skip_PS_Token( parser ); /* `RD' */ + if ( parser->root.error ) + return; + + string_buf = parser->root.cursor + 1; /* one space after `RD' */ + + if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size ) + { + FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + else + parser->root.cursor += string_size + 1; + } + + if ( !string_buf ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* A string can have a trailing zero (odd) byte for padding. */ + /* Ignore it. */ + if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 ) + string_size--; + + if ( !string_size ) + { + FT_ERROR(( "t42_parse_sfnts: invalid string\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + FT_TRACE2(( " PS string size %5lu bytes, offset 0x%08lx (%lu)\n", + string_size, ttf_count, ttf_count )); + + /* The whole TTF is now loaded into `string_buf'. We are */ + /* checking its contents while copying it to `ttf_data'. */ + + size = (FT_ULong)( limit - parser->root.cursor ); + + for ( n = 0; n < string_size; n++ ) + { + switch ( status ) + { + case BEFORE_START: + /* load offset table, 12 bytes */ + if ( ttf_count < 12 ) + { + t42face->ttf_data[ttf_count++] = string_buf[n]; + continue; + } + else + { + FT_Long ttf_reserved_prev = ttf_reserved; + + + num_tables = 16 * t42face->ttf_data[4] + t42face->ttf_data[5]; + status = BEFORE_TABLE_DIR; + ttf_reserved = 12 + 16 * num_tables; + + FT_TRACE2(( " SFNT directory contains %d tables\n", + num_tables )); + + if ( (FT_Long)size < ttf_reserved ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev, + ttf_reserved ) ) + goto Fail; + } + FALL_THROUGH; + + case BEFORE_TABLE_DIR: + /* the offset table is read; read the table directory */ + if ( ttf_count < ttf_reserved ) + { + t42face->ttf_data[ttf_count++] = string_buf[n]; + continue; + } + else + { + int i; + FT_ULong len; + FT_Long ttf_reserved_prev = ttf_reserved; + + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " table length\n" )); + FT_TRACE2(( " ------------------------------\n" )); + + for ( i = 0; i < num_tables; i++ ) + { + FT_Byte* p = t42face->ttf_data + 12 + 16 * i + 12; + + + len = FT_PEEK_ULONG( p ); + FT_TRACE2(( " %4i 0x%08lx (%lu)\n", i, len, len )); + + if ( len > size || + ttf_reserved > (FT_Long)( size - len ) ) + { + FT_ERROR(( "t42_parse_sfnts:" + " invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* Pad to a 4-byte boundary length */ + ttf_reserved += (FT_Long)( ( len + 3 ) & ~3U ); + } + ttf_reserved += 1; + + status = OTHER_TABLES; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " allocating %ld bytes\n", ttf_reserved )); + FT_TRACE2(( "\n" )); + + if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev, + ttf_reserved ) ) + goto Fail; + } + FALL_THROUGH; + + case OTHER_TABLES: + /* all other tables are just copied */ + if ( ttf_count >= ttf_reserved ) + { + FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + t42face->ttf_data[ttf_count++] = string_buf[n]; + } + } + + T1_Skip_Spaces( parser ); + } + + /* if control reaches this point, the format was not valid */ + error = FT_THROW( Invalid_File_Format ); + + Fail: + parser->root.error = error; + + Exit: + if ( parser->root.error ) + { + FT_FREE( t42face->ttf_data ); + t42face->ttf_size = 0; + } + if ( allocated ) + FT_FREE( string_buf ); + } + + + static void + t42_parse_charstrings( FT_Face face, /* T42_Face */ + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)t42face->psaux; + + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Int n; + FT_Int notdef_index = 0; + FT_Byte notdef_found = 0; + + + T1_Skip_Spaces( parser ); + + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( ft_isdigit( *parser->root.cursor ) ) + { + loader->num_glyphs = T1_ToInt( parser ); + if ( parser->root.error ) + return; + if ( loader->num_glyphs < 0 ) + { + FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* we certainly need more than 4 bytes per glyph */ + if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 ) + { + FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs" + " (from %d to %zu)\n", + loader->num_glyphs, + ( limit - parser->root.cursor ) >> 2 )); + loader->num_glyphs = ( limit - parser->root.cursor ) >> 2; + } + + } + else if ( *parser->root.cursor == '<' ) + { + /* We have `<< ... >>'. Count the number of `/' in the dictionary */ + /* to get its size. */ + FT_Int count = 0; + + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + + while ( parser->root.cursor < limit ) + { + if ( *parser->root.cursor == '/' ) + count++; + else if ( *parser->root.cursor == '>' ) + { + loader->num_glyphs = count; + parser->root.cursor = cur; /* rewind */ + break; + } + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + } + } + else + { + FT_ERROR(( "t42_parse_charstrings: invalid token\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* initialize tables */ + + /* contrary to Type1, we disallow multiple CharStrings arrays */ + if ( swap_table->init ) + { + FT_ERROR(( "t42_parse_charstrings:" + " only one CharStrings array allowed\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + error = psaux->ps_table_funcs->init( code_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + error = psaux->ps_table_funcs->init( name_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + /* Initialize table for swapping index notdef_index and */ + /* index 0 names and codes (if necessary). */ + + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + + n = 0; + + for (;;) + { + /* We support two formats. */ + /* */ + /* `/glyphname' + index [+ `def'] */ + /* `(glyphname)' [+ `cvn'] + index [+ `def'] */ + /* */ + /* The latter format gets created by the */ + /* LilyPond typesetting program. */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + if ( cur >= limit ) + break; + + /* We stop when we find an `end' keyword or '>' */ + if ( *cur == 'e' && + cur + 3 < limit && + cur[1] == 'n' && + cur[2] == 'd' && + t42_is_space( cur[3] ) ) + break; + if ( *cur == '>' ) + break; + + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + if ( parser->root.error ) + return; + + if ( *cur == '/' || *cur == '(' ) + { + FT_UInt len; + FT_Bool have_literal = FT_BOOL( *cur == '(' ); + + + if ( cur + ( have_literal ? 3 : 2 ) >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + cur++; /* skip `/' */ + len = (FT_UInt)( parser->root.cursor - cur ); + if ( have_literal ) + len--; + + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + /* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)( name_table->elements[n] ) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + + T1_Skip_Spaces( parser ); + + if ( have_literal ) + T1_Skip_PS_Token( parser ); + + cur = parser->root.cursor; + + (void)T1_ToInt( parser ); + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + len = (FT_UInt)( parser->root.cursor - cur ); + + error = T1_Add_Table( code_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + code_table->elements[n][len] = '\0'; + + n++; + if ( n >= loader->num_glyphs ) + break; + } + } + + loader->num_glyphs = n; + + if ( !notdef_found ) + { + FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* if /.notdef does not occupy index 0, do our magic. */ + if ( ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) + { + /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ + /* name and code entries to swap_table. Then place notdef_index */ + /* name and code entries into swap_table. Then swap name and code */ + /* entries at indices notdef_index and 0 using values stored in */ + /* swap_table. */ + + /* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + /* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + + } + + return; + + Fail: + parser->root.error = error; + } + + + static FT_Error + t42_load_keyword( T42_Face face, + T42_Loader loader, + T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects = 0; + + + /* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } + + /* now the keyword is either a simple field or a table of fields; */ + /* we are now going to take care of it */ + + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + break; + + case T1_FIELD_LOCATION_FONT_EXTRA: + dummy_object = &face->type1.font_extra; + break; + + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + break; + + default: + dummy_object = &face->type1; + } + + objects = &dummy_object; + + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ) + { + T42_Parser parser = &loader->parser; + FT_Byte* limit; + FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / + sizeof ( t42_keywords[0] ) ); + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = FT_Err_Ok; + + limit = parser->root.limit; + + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + + + cur = parser->root.cursor; + + /* look for `FontDirectory' which causes problems for some fonts */ + if ( *cur == 'F' && cur + 25 < limit && + ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + { + FT_Byte* cur2; + + + /* skip the `FontDirectory' keyword */ + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + cur = cur2 = parser->root.cursor; + + /* look up the `known' keyword */ + while ( cur < limit ) + { + if ( *cur == 'k' && cur + 5 < limit && + ft_strncmp( (char*)cur, "known", 5 ) == 0 ) + break; + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + + if ( cur < limit ) + { + T1_TokenRec token; + + + /* skip the `known' keyword and the token following it */ + T1_Skip_PS_Token( parser ); + T1_ToToken( parser, &token ); + + /* if the last token was an array, skip it! */ + if ( token.type == T1_TOKEN_TYPE_ARRAY ) + cur2 = parser->root.cursor; + } + parser->root.cursor = cur2; + } + + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { + int i; + + + /* now compare the immediate name to the keyword table */ + + /* loop through all known keywords */ + for ( i = 0; i < n_keywords; i++ ) + { + T1_Field keyword = (T1_Field)&t42_keywords[i]; + FT_Byte *name = (FT_Byte*)keyword->ident; + + + if ( !name ) + continue; + + if ( cur[0] == name[0] && + len == ft_strlen( (const char *)name ) && + ft_memcmp( cur, name, len ) == 0 ) + { + /* we found it -- run the parsing callback! */ + parser->root.error = t42_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; + } + } + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + } + + T1_Skip_Spaces( parser ); + } + + Exit: + return parser->root.error; + } + + + FT_LOCAL_DEF( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ) + { + FT_UNUSED( face ); + + FT_ZERO( loader ); + loader->num_glyphs = 0; + loader->num_chars = 0; + + /* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + } + + + FT_LOCAL_DEF( void ) + t42_loader_done( T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); + + /* finalize parser */ + t42_parser_done( parser ); + } + + +/* END */ diff --git a/vendor/freetype/src/type42/t42parse.h b/vendor/freetype/src/type42/t42parse.h new file mode 100644 index 0000000..5741c54 --- /dev/null +++ b/vendor/freetype/src/type42/t42parse.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * t42parse.h + * + * Type 42 font parser (specification). + * + * Copyright (C) 2002-2023 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42PARSE_H_ +#define T42PARSE_H_ + + +#include "t42objs.h" +#include + + +FT_BEGIN_HEADER + + typedef struct T42_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* base_dict; + FT_Long base_len; + + FT_Bool in_memory; + + } T42_ParserRec, *T42_Parser; + + + typedef struct T42_Loader_ + { + T42_ParserRec parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + PS_TableRec encoding_table; /* PS_Table used to store the */ + /* encoding character names */ + + FT_Int num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; + PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */ + + } T42_LoaderRec, *T42_Loader; + + + FT_LOCAL( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( void ) + t42_parser_done( T42_Parser parser ); + + + FT_LOCAL( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ); + + + FT_LOCAL( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ); + + FT_LOCAL( void ) + t42_loader_done( T42_Loader loader ); + + + /* */ + +FT_END_HEADER + + +#endif /* T42PARSE_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type42/t42types.h b/vendor/freetype/src/type42/t42types.h new file mode 100644 index 0000000..0bfe14e --- /dev/null +++ b/vendor/freetype/src/type42/t42types.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * t42types.h + * + * Type 42 font data types (specification only). + * + * Copyright (C) 2002-2023 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42TYPES_H_ +#define T42TYPES_H_ + + +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + typedef struct T42_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; +#if 0 + const void* afm_data; +#endif + FT_Byte* ttf_data; + FT_Long ttf_size; + FT_Face ttf_face; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + PS_UnicodesRec unicode_map; + + } T42_FaceRec, *T42_Face; + + +FT_END_HEADER + +#endif /* T42TYPES_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/type42/type42.c b/vendor/freetype/src/type42/type42.c new file mode 100644 index 0000000..8d2302c --- /dev/null +++ b/vendor/freetype/src/type42/type42.c @@ -0,0 +1,26 @@ +/**************************************************************************** + * + * type42.c + * + * FreeType Type 42 driver component. + * + * Copyright (C) 2002-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "t42drivr.c" +#include "t42objs.c" +#include "t42parse.c" + + +/* END */ diff --git a/vendor/freetype/src/winfonts/fnterrs.h b/vendor/freetype/src/winfonts/fnterrs.h new file mode 100644 index 0000000..dafdb07 --- /dev/null +++ b/vendor/freetype/src/winfonts/fnterrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * fnterrs.h + * + * Win FNT/FON error codes (specification only). + * + * Copyright (C) 2001-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Windows FNT/FON error enumeration + * constants. + * + */ + +#ifndef FNTERRS_H_ +#define FNTERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX FNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_Winfonts + +#include + +#endif /* FNTERRS_H_ */ + + +/* END */ diff --git a/vendor/freetype/src/winfonts/module.mk b/vendor/freetype/src/winfonts/module.mk new file mode 100644 index 0000000..78a2900 --- /dev/null +++ b/vendor/freetype/src/winfonts/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 Windows FNT/FON module definition +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +FTMODULE_H_COMMANDS += WINDOWS_DRIVER + +define WINDOWS_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, winfnt_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)winfnt $(ECHO_DRIVER_DESC)Windows bitmap fonts with extension *.fnt or *.fon$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/vendor/freetype/src/winfonts/rules.mk b/vendor/freetype/src/winfonts/rules.mk new file mode 100644 index 0000000..b39c519 --- /dev/null +++ b/vendor/freetype/src/winfonts/rules.mk @@ -0,0 +1,68 @@ +# +# FreeType 2 Windows FNT/FON driver configuration rules +# + + +# Copyright (C) 1996-2023 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# Windows driver directory +# +FNT_DIR := $(SRC_DIR)/winfonts + + +FNT_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(FNT_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# Windows driver sources (i.e., C files) +# +FNT_DRV_SRC := $(FNT_DIR)/winfnt.c + +# Windows driver headers +# +FNT_DRV_H := $(FNT_DRV_SRC:%.c=%.h) \ + $(FNT_DIR)/fnterrs.h + + +# Windows driver object(s) +# +# FNT_DRV_OBJ_M is used during `multi' builds +# FNT_DRV_OBJ_S is used during `single' builds +# +FNT_DRV_OBJ_M := $(FNT_DRV_SRC:$(FNT_DIR)/%.c=$(OBJ_DIR)/%.$O) +FNT_DRV_OBJ_S := $(OBJ_DIR)/winfnt.$O + +# Windows driver source file for single build +# +FNT_DRV_SRC_S := $(FNT_DIR)/winfnt.c + + +# Windows driver - single object +# +$(FNT_DRV_OBJ_S): $(FNT_DRV_SRC_S) $(FNT_DRV_SRC) $(FREETYPE_H) $(FNT_DRV_H) + $(FNT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(FNT_DRV_SRC_S)) + + +# Windows driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(FNT_DIR)/%.c $(FREETYPE_H) $(FNT_DRV_H) + $(FNT_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(FNT_DRV_OBJ_S) +DRV_OBJS_M += $(FNT_DRV_OBJ_M) + + +# EOF diff --git a/vendor/freetype/src/winfonts/winfnt.c b/vendor/freetype/src/winfonts/winfnt.c new file mode 100644 index 0000000..1160e4e --- /dev/null +++ b/vendor/freetype/src/winfonts/winfnt.c @@ -0,0 +1,1219 @@ +/**************************************************************************** + * + * winfnt.c + * + * FreeType font driver for Windows FNT/FON files + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright 2003 Huw D M Davies for Codeweavers + * Copyright 2007 Dmitry Timoshkov for Codeweavers + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "winfnt.h" +#include "fnterrs.h" +#include +#include + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT winfnt + + + static const FT_Frame_Field winmz_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinMZ_HeaderRec + + FT_FRAME_START( 64 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 29 * 2 ), + FT_FRAME_ULONG_LE ( lfanew ), + FT_FRAME_END + }; + + static const FT_Frame_Field winne_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinNE_HeaderRec + + FT_FRAME_START( 40 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 34 ), + FT_FRAME_USHORT_LE ( resource_tab_offset ), + FT_FRAME_USHORT_LE ( rname_tab_offset ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe32_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_HeaderRec + + FT_FRAME_START( 248 ), + FT_FRAME_ULONG_LE ( magic ), /* PE00 */ + FT_FRAME_USHORT_LE ( machine ), /* 0x014C - i386 */ + FT_FRAME_USHORT_LE ( number_of_sections ), + FT_FRAME_SKIP_BYTES( 12 ), + FT_FRAME_USHORT_LE ( size_of_optional_header ), + FT_FRAME_SKIP_BYTES( 2 ), + FT_FRAME_USHORT_LE ( magic32 ), /* 0x10B */ + FT_FRAME_SKIP_BYTES( 110 ), + FT_FRAME_ULONG_LE ( rsrc_virtual_address ), + FT_FRAME_ULONG_LE ( rsrc_size ), + FT_FRAME_SKIP_BYTES( 104 ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe32_section_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_SectionRec + + FT_FRAME_START( 40 ), + FT_FRAME_BYTES ( name, 8 ), + FT_FRAME_SKIP_BYTES( 4 ), + FT_FRAME_ULONG_LE ( virtual_address ), + FT_FRAME_ULONG_LE ( size_of_raw_data ), + FT_FRAME_ULONG_LE ( pointer_to_raw_data ), + FT_FRAME_SKIP_BYTES( 16 ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_dir_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE ( characteristics ), + FT_FRAME_ULONG_LE ( time_date_stamp ), + FT_FRAME_USHORT_LE( major_version ), + FT_FRAME_USHORT_LE( minor_version ), + FT_FRAME_USHORT_LE( number_of_named_entries ), + FT_FRAME_USHORT_LE( number_of_id_entries ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirEntryRec + + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( name ), + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_data_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDataEntryRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( offset_to_data ), + FT_FRAME_ULONG_LE( size ), + FT_FRAME_ULONG_LE( code_page ), + FT_FRAME_ULONG_LE( reserved ), + FT_FRAME_END + }; + + static const FT_Frame_Field winfnt_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_WinFNT_HeaderRec + + FT_FRAME_START( 148 ), + FT_FRAME_USHORT_LE( version ), + FT_FRAME_ULONG_LE ( file_size ), + FT_FRAME_BYTES ( copyright, 60 ), + FT_FRAME_USHORT_LE( file_type ), + FT_FRAME_USHORT_LE( nominal_point_size ), + FT_FRAME_USHORT_LE( vertical_resolution ), + FT_FRAME_USHORT_LE( horizontal_resolution ), + FT_FRAME_USHORT_LE( ascent ), + FT_FRAME_USHORT_LE( internal_leading ), + FT_FRAME_USHORT_LE( external_leading ), + FT_FRAME_BYTE ( italic ), + FT_FRAME_BYTE ( underline ), + FT_FRAME_BYTE ( strike_out ), + FT_FRAME_USHORT_LE( weight ), + FT_FRAME_BYTE ( charset ), + FT_FRAME_USHORT_LE( pixel_width ), + FT_FRAME_USHORT_LE( pixel_height ), + FT_FRAME_BYTE ( pitch_and_family ), + FT_FRAME_USHORT_LE( avg_width ), + FT_FRAME_USHORT_LE( max_width ), + FT_FRAME_BYTE ( first_char ), + FT_FRAME_BYTE ( last_char ), + FT_FRAME_BYTE ( default_char ), + FT_FRAME_BYTE ( break_char ), + FT_FRAME_USHORT_LE( bytes_per_row ), + FT_FRAME_ULONG_LE ( device_offset ), + FT_FRAME_ULONG_LE ( face_name_offset ), + FT_FRAME_ULONG_LE ( bits_pointer ), + FT_FRAME_ULONG_LE ( bits_offset ), + FT_FRAME_BYTE ( reserved ), + FT_FRAME_ULONG_LE ( flags ), + FT_FRAME_USHORT_LE( A_space ), + FT_FRAME_USHORT_LE( B_space ), + FT_FRAME_USHORT_LE( C_space ), + FT_FRAME_ULONG_LE ( color_table_offset ), + FT_FRAME_BYTES ( reserved1, 16 ), + FT_FRAME_END + }; + + + static void + fnt_font_done( FNT_Face face ) + { + FT_Memory memory = FT_FACE( face )->memory; + FT_Stream stream = FT_FACE( face )->stream; + FNT_Font font = face->font; + + + if ( !font ) + return; + + if ( font->fnt_frame ) + FT_FRAME_RELEASE( font->fnt_frame ); + FT_FREE( font->family_name ); + + FT_FREE( font ); + face->font = NULL; + } + + + static FT_Error + fnt_font_load( FNT_Font font, + FT_Stream stream ) + { + FT_Error error; + FT_WinFNT_Header header = &font->header; + FT_Bool new_format; + FT_UInt size; + + + /* first of all, read the FNT header */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* check header */ + if ( header->version != 0x200 && + header->version != 0x300 ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + new_format = FT_BOOL( font->header.version == 0x300 ); + size = new_format ? 148 : 118; + + if ( header->file_size < size ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* Version 2 doesn't have these fields */ + if ( header->version == 0x200 ) + { + header->flags = 0; + header->A_space = 0; + header->B_space = 0; + header->C_space = 0; + + header->color_table_offset = 0; + } + + if ( header->file_type & 1 ) + { + FT_TRACE2(( "[can't handle vector FNT fonts]\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* this is a FNT file/table; extract its frame */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) ) + goto Exit; + + Exit: + return error; + } + + + static FT_Error + fnt_face_get_dll_font( FNT_Face face, + FT_Int face_instance_index ) + { + FT_Error error; + FT_Stream stream = FT_FACE( face )->stream; + FT_Memory memory = FT_FACE( face )->memory; + WinMZ_HeaderRec mz_header; + FT_Long face_index; + + + face->font = NULL; + + face_index = FT_ABS( face_instance_index ) & 0xFFFF; + + /* does it begin with an MZ header? */ + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) + { + error = FT_ERR( Unknown_File_Format ); + goto Exit; + } + + error = FT_ERR( Unknown_File_Format ); + if ( mz_header.magic == WINFNT_MZ_MAGIC ) + { + /* yes, now look for an NE header in the file */ + WinNE_HeaderRec ne_header; + + + FT_TRACE2(( "MZ signature found\n" )); + + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) + goto Exit; + + error = FT_ERR( Unknown_File_Format ); + if ( ne_header.magic == WINFNT_NE_MAGIC ) + { + /* good, now look into the resource table for each FNT resource */ + FT_ULong res_offset = mz_header.lfanew + + ne_header.resource_tab_offset; + FT_UShort size_shift; + FT_UShort font_count = 0; + FT_ULong font_offset = 0; + + + FT_TRACE2(( "NE signature found\n" )); + + if ( FT_STREAM_SEEK( res_offset ) || + FT_FRAME_ENTER( ne_header.rname_tab_offset - + ne_header.resource_tab_offset ) ) + goto Exit; + + size_shift = FT_GET_USHORT_LE(); + + /* Microsoft's specification of the executable-file header format */ + /* for `New Executable' (NE) doesn't give a limit for the */ + /* alignment shift count; however, in 1985, the year of the */ + /* specification release, only 32bit values were supported, thus */ + /* anything larger than 16 doesn't make sense in general, given */ + /* that file offsets are 16bit values, shifted by the alignment */ + /* shift count */ + if ( size_shift > 16 ) + { + FT_TRACE2(( "invalid alignment shift count for resource data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit1; + } + + + for (;;) + { + FT_UShort type_id, count; + + + type_id = FT_GET_USHORT_LE(); + if ( !type_id ) + break; + + count = FT_GET_USHORT_LE(); + + FT_TRACE2(( type_id == 0x8007U ? "RT_FONTDIR count %hu\n" : + type_id == 0x8008U ? "RT_FONT count %hu\n" : "", + count )); + + if ( type_id == 0x8008U ) + { + font_count = count; + font_offset = FT_STREAM_POS() + 4 + + (FT_ULong)( stream->cursor - stream->limit ); + break; + } + + stream->cursor += 4 + count * 12; + } + + FT_FRAME_EXIT(); + + if ( !font_count || !font_offset ) + { + FT_TRACE2(( "this file doesn't contain any FNT resources\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* loading `winfnt_header_fields' needs at least 118 bytes; */ + /* use this as a rough measure to check the expected font size */ + if ( font_count * 118UL > stream->size ) + { + FT_TRACE2(( "invalid number of faces\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + face->root.num_faces = font_count; + + if ( face_instance_index < 0 ) + goto Exit; + + if ( face_index >= font_count ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_NEW( face->font ) ) + goto Exit; + + if ( FT_STREAM_SEEK( font_offset + (FT_ULong)face_index * 12 ) || + FT_FRAME_ENTER( 12 ) ) + goto Fail; + + face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + + stream->cursor += 8; + + FT_FRAME_EXIT(); + + error = fnt_font_load( face->font, stream ); + } + else if ( ne_header.magic == WINFNT_PE_MAGIC ) + { + WinPE32_HeaderRec pe32_header; + WinPE32_SectionRec pe32_section; + WinPE_RsrcDirRec root_dir, name_dir, lang_dir; + WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3; + WinPE_RsrcDataEntryRec data_entry; + + FT_ULong root_dir_offset, name_dir_offset, lang_dir_offset; + FT_UShort i, j, k; + + + FT_TRACE2(( "PE signature found\n" )); + + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) ) + goto Exit; + + FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, " + "size_of_optional_header %02x\n", + pe32_header.magic, pe32_header.machine, + pe32_header.number_of_sections, + pe32_header.size_of_optional_header )); + FT_TRACE2(( "magic32 %02x, rsrc_virtual_address %04lx, " + "rsrc_size %04lx\n", + pe32_header.magic32, pe32_header.rsrc_virtual_address, + pe32_header.rsrc_size )); + + if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ || + pe32_header.machine != 0x014C /* i386 */ || + pe32_header.size_of_optional_header != 0xE0 /* FIXME */ || + pe32_header.magic32 != 0x10B ) + { + FT_TRACE2(( "this file has an invalid PE header\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + face->root.num_faces = 0; + + for ( i = 0; i < pe32_header.number_of_sections; i++ ) + { + if ( FT_STREAM_READ_FIELDS( winpe32_section_fields, + &pe32_section ) ) + goto Exit; + + FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n", + pe32_section.name, pe32_section.virtual_address, + pe32_section.size_of_raw_data, + pe32_section.pointer_to_raw_data )); + + if ( pe32_header.rsrc_virtual_address == + pe32_section.virtual_address ) + goto Found_rsrc_section; + } + + FT_TRACE2(( "this file doesn't contain any resources\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + + Found_rsrc_section: + FT_TRACE2(( "found resources section %.8s\n", pe32_section.name )); + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) ) + goto Exit; + + root_dir_offset = pe32_section.pointer_to_raw_data; + + for ( i = 0; i < root_dir.number_of_named_entries + + root_dir.number_of_id_entries; i++ ) + { + if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry1 ) ) + goto Exit; + + if ( !( dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + dir_entry1.offset &= ~0x80000000UL; + + name_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry1.offset; + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry1.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) ) + goto Exit; + + for ( j = 0; j < name_dir.number_of_named_entries + + name_dir.number_of_id_entries; j++ ) + { + if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry2 ) ) + goto Exit; + + if ( !( dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + dir_entry2.offset &= ~0x80000000UL; + + lang_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry2.offset; + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry2.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) ) + goto Exit; + + for ( k = 0; k < lang_dir.number_of_named_entries + + lang_dir.number_of_id_entries; k++ ) + { + if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry3 ) ) + goto Exit; + + if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( dir_entry1.name == 8 /* RT_FONT */ ) + { + if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields, + &data_entry ) ) + goto Exit; + + FT_TRACE2(( "found font #%lu, offset %04lx, " + "size %04lx, cp %lu\n", + dir_entry2.name, + pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address, + data_entry.size, data_entry.code_page )); + + if ( face_index == face->root.num_faces ) + { + if ( FT_NEW( face->font ) ) + goto Exit; + + face->font->offset = pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address; + face->font->fnt_size = data_entry.size; + + error = fnt_font_load( face->font, stream ); + if ( error ) + { + FT_TRACE2(( "font #%lu load error 0x%x\n", + dir_entry2.name, error )); + goto Fail; + } + else + FT_TRACE2(( "font #%lu successfully loaded\n", + dir_entry2.name )); + } + + face->root.num_faces++; + } + } + } + } + } + + if ( !face->root.num_faces ) + { + FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( face_index >= face->root.num_faces ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + Fail: + if ( error ) + fnt_font_done( face ); + + Exit: + return error; + + Exit1: + FT_FRAME_EXIT(); + goto Exit; + } + + + typedef struct FNT_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt32 first; + FT_UInt32 count; + + } FNT_CMapRec, *FNT_CMap; + + + static FT_Error + fnt_cmap_init( FT_CMap cmap, /* FNT_CMap */ + FT_Pointer pointer ) + { + FNT_CMap fntcmap = (FNT_CMap)cmap; + FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); + FNT_Font font = face->font; + + FT_UNUSED( pointer ); + + + fntcmap->first = (FT_UInt32)font->header.first_char; + fntcmap->count = (FT_UInt32)( font->header.last_char - + fntcmap->first + 1 ); + + return 0; + } + + + static FT_UInt + fnt_cmap_char_index( FT_CMap cmap, /* FNT_CMap */ + FT_UInt32 char_code ) + { + FNT_CMap fntcmap = (FNT_CMap)cmap; + FT_UInt gindex = 0; + + + char_code -= fntcmap->first; + if ( char_code < fntcmap->count ) + /* we artificially increase the glyph index; */ + /* FNT_Load_Glyph reverts to the right one */ + gindex = (FT_UInt)( char_code + 1 ); + return gindex; + } + + + static FT_UInt + fnt_cmap_char_next( FT_CMap cmap, /* FNT_CMap */ + FT_UInt32 *pchar_code ) + { + FNT_CMap fntcmap = (FNT_CMap)cmap; + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + if ( char_code <= fntcmap->first ) + { + result = fntcmap->first; + gindex = 1; + } + else + { + char_code -= fntcmap->first; + if ( char_code < fntcmap->count ) + { + result = fntcmap->first + char_code; + gindex = (FT_UInt)( char_code + 1 ); + } + } + + *pchar_code = result; + return gindex; + } + + + static const FT_CMap_ClassRec fnt_cmap_class_rec = + { + sizeof ( FNT_CMapRec ), + + (FT_CMap_InitFunc) fnt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)fnt_cmap_char_index, + (FT_CMap_CharNextFunc) fnt_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL + }; + + static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec; + + + static void + FNT_Face_Done( FT_Face fntface ) /* FNT_Face */ + { + FNT_Face face = (FNT_Face)fntface; + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + fnt_font_done( face ); + + FT_FREE( fntface->available_sizes ); + fntface->num_fixed_sizes = 0; + } + + + static FT_Error + FNT_Face_Init( FT_Stream stream, + FT_Face fntface, /* FNT_Face */ + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ) + { + FNT_Face face = (FNT_Face)fntface; + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Int face_index; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "Windows FNT driver\n" )); + + face_index = FT_ABS( face_instance_index ) & 0xFFFF; + + /* try to load font from a DLL */ + error = fnt_face_get_dll_font( face, face_instance_index ); + if ( !error && face_instance_index < 0 ) + goto Exit; + + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + /* this didn't work; try to load a single FNT font */ + FNT_Font font; + + if ( FT_NEW( face->font ) ) + goto Exit; + + fntface->num_faces = 1; + + font = face->font; + font->offset = 0; + font->fnt_size = stream->size; + + error = fnt_font_load( font, stream ); + + if ( !error ) + { + if ( face_instance_index < 0 ) + goto Exit; + + if ( face_index > 0 ) + error = FT_THROW( Invalid_Argument ); + } + } + + if ( error ) + goto Fail; + + /* sanity check */ + if ( !face->font->header.pixel_height ) + { + FT_TRACE2(( "invalid pixel height\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* we now need to fill the root FT_Face fields */ + /* with relevant information */ + { + FT_Face root = FT_FACE( face ); + FNT_Font font = face->font; + FT_ULong family_size; + + + root->face_index = face_index; + + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + if ( font->header.avg_width == font->header.max_width ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( font->header.italic ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( font->header.weight >= 800 ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + /* set up the `fixed_sizes' array */ + if ( FT_QNEW( root->available_sizes ) ) + goto Fail; + + root->num_fixed_sizes = 1; + + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_UShort x_res, y_res; + + + bsize->width = (FT_Short)font->header.avg_width; + bsize->height = (FT_Short)( font->header.pixel_height + + font->header.external_leading ); + bsize->size = font->header.nominal_point_size << 6; + + x_res = font->header.horizontal_resolution; + if ( !x_res ) + x_res = 72; + + y_res = font->header.vertical_resolution; + if ( !y_res ) + y_res = 72; + + bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 ); + bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem ); + + /* + * this reads: + * + * the nominal height is larger than the bbox's height + * + * => nominal_point_size contains incorrect value; + * use pixel_height as the nominal height + */ + if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) ) + { + FT_TRACE2(( "use pixel_height as the nominal height\n" )); + + bsize->y_ppem = font->header.pixel_height << 6; + bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res ); + } + + bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 ); + bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem ); + } + + { + FT_CharMapRec charmap; + + + charmap.encoding = FT_ENCODING_NONE; + /* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + charmap.face = root; + + if ( font->header.charset == FT_WinFNT_ID_MAC ) + { + charmap.encoding = FT_ENCODING_APPLE_ROMAN; + charmap.platform_id = TT_PLATFORM_MACINTOSH; +/* charmap.encoding_id = TT_MAC_ID_ROMAN; */ + } + + error = FT_CMap_New( fnt_cmap_class, + NULL, + &charmap, + NULL ); + if ( error ) + goto Fail; + } + + /* set up remaining flags */ + + if ( font->header.last_char < font->header.first_char ) + { + FT_TRACE2(( "invalid number of glyphs\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* reserve one slot for the .notdef glyph at index 0 */ + root->num_glyphs = font->header.last_char - + font->header.first_char + 1 + 1; + + if ( font->header.face_name_offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid family name offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + family_size = font->header.file_size - font->header.face_name_offset; + /* Some broken fonts don't delimit the face name with a final */ + /* null byte -- the frame is erroneously one byte too small. */ + /* We thus allocate one more byte, setting it explicitly to */ + /* zero. */ + if ( FT_QALLOC( font->family_name, family_size + 1 ) ) + goto Fail; + + FT_MEM_COPY( font->family_name, + font->fnt_frame + font->header.face_name_offset, + family_size ); + + font->family_name[family_size] = '\0'; + + /* shrink it to the actual length */ + if ( FT_QREALLOC( font->family_name, + family_size + 1, + ft_strlen( font->family_name ) + 1 ) ) + goto Fail; + + root->family_name = font->family_name; + root->style_name = (char *)"Regular"; + + if ( root->style_flags & FT_STYLE_FLAG_BOLD ) + { + if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Bold Italic"; + else + root->style_name = (char *)"Bold"; + } + else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Italic"; + } + goto Exit; + + Fail: + FNT_Face_Done( fntface ); + + Exit: + return error; + } + + + static FT_Error + FNT_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + + FT_UNUSED( strike_index ); + + + FT_Select_Metrics( size->face, 0 ); + + size->metrics.ascender = header->ascent * 64; + size->metrics.descender = -( header->pixel_height - + header->ascent ) * 64; + size->metrics.max_advance = header->max_width * 64; + + return FT_Err_Ok; + } + + + static FT_Error + FNT_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = FT_ERR( Invalid_Pixel_Size ); + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = FT_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == header->pixel_height ) + error = FT_Err_Ok; + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + if ( error ) + return error; + else + return FNT_Size_Select( size, 0 ); + } + + + static FT_Error + FNT_Load_Glyph( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); + FNT_Font font; + FT_Error error = FT_Err_Ok; + FT_Byte* p; + FT_UInt len; + FT_Bitmap* bitmap = &slot->bitmap; + FT_ULong offset; + FT_Bool new_format; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + font = face->font; + + if ( !font || + glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_TRACE1(( "FNT_Load_Glyph: glyph index %d\n", glyph_index )); + + if ( glyph_index > 0 ) + glyph_index--; /* revert to real index */ + else + glyph_index = font->header.default_char; /* the `.notdef' glyph */ + + new_format = FT_BOOL( font->header.version == 0x300 ); + len = new_format ? 6 : 4; + + /* get glyph width and offset */ + offset = ( new_format ? 148 : 118 ) + len * glyph_index; + + if ( offset >= font->header.file_size - 2 - ( new_format ? 4 : 2 ) ) + { + FT_TRACE2(( "invalid FNT offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + p = font->fnt_frame + offset; + + bitmap->width = FT_NEXT_USHORT_LE( p ); + + /* jump to glyph entry */ + if ( new_format ) + offset = FT_NEXT_ULONG_LE( p ); + else + offset = FT_NEXT_USHORT_LE( p ); + + if ( offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid FNT offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + bitmap->rows = font->header.pixel_height; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + + slot->bitmap_left = 0; + slot->bitmap_top = font->header.ascent; + slot->format = FT_GLYPH_FORMAT_BITMAP; + + /* now set up metrics */ + slot->metrics.width = (FT_Pos)( bitmap->width << 6 ); + slot->metrics.height = (FT_Pos)( bitmap->rows << 6 ); + slot->metrics.horiAdvance = (FT_Pos)( bitmap->width << 6 ); + slot->metrics.horiBearingX = 0; + slot->metrics.horiBearingY = slot->bitmap_top << 6; + + ft_synthesize_vertical_metrics( &slot->metrics, + (FT_Pos)( bitmap->rows << 6 ) ); + + if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) + goto Exit; + + /* jump to glyph data */ + p = font->fnt_frame + /* font->header.bits_offset */ + offset; + + /* allocate and build bitmap */ + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_UInt pitch = ( bitmap->width + 7 ) >> 3; + FT_Byte* column; + FT_Byte* write; + + + bitmap->pitch = (int)pitch; + if ( !pitch || + offset + pitch * bitmap->rows > font->header.file_size ) + { + FT_TRACE2(( "invalid bitmap width\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* note: since glyphs are stored in columns and not in rows we */ + /* can't use ft_glyphslot_set_bitmap */ + if ( FT_QALLOC_MULT( bitmap->buffer, bitmap->rows, pitch ) ) + goto Exit; + + column = (FT_Byte*)bitmap->buffer; + + for ( ; pitch > 0; pitch--, column++ ) + { + FT_Byte* limit = p + bitmap->rows; + + + for ( write = column; p < limit; p++, write += bitmap->pitch ) + *write = *p; + } + + slot->internal->flags = FT_GLYPH_OWN_BITMAP; + } + + Exit: + return error; + } + + + static FT_Error + winfnt_get_header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ) + { + FNT_Font font = ((FNT_Face)face)->font; + + + *aheader = font->header; + + return 0; + } + + + static const FT_Service_WinFntRec winfnt_service_rec = + { + winfnt_get_header /* get_header */ + }; + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec winfnt_services[] = + { + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_WINFNT }, + { FT_SERVICE_ID_WINFNT, &winfnt_service_rec }, + { NULL, NULL } + }; + + + static FT_Module_Interface + winfnt_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( winfnt_services, service_id ); + } + + + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec winfnt_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + + "winfonts", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + winfnt_get_service /* FT_Module_Requester get_interface */ + }, + + sizeof ( FNT_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + FNT_Face_Init, /* FT_Face_InitFunc init_face */ + FNT_Face_Done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + NULL, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + FNT_Load_Glyph, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + FNT_Size_Request, /* FT_Size_RequestFunc request_size */ + FNT_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/vendor/freetype/src/winfonts/winfnt.h b/vendor/freetype/src/winfonts/winfnt.h new file mode 100644 index 0000000..2f75b9e --- /dev/null +++ b/vendor/freetype/src/winfonts/winfnt.h @@ -0,0 +1,164 @@ +/**************************************************************************** + * + * winfnt.h + * + * FreeType font driver for Windows FNT/FON files + * + * Copyright (C) 1996-2023 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright 2007 Dmitry Timoshkov for Codeweavers + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef WINFNT_H_ +#define WINFNT_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + typedef struct WinMZ_HeaderRec_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort lfanew; + + } WinMZ_HeaderRec; + + + typedef struct WinNE_HeaderRec_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort resource_tab_offset; + FT_UShort rname_tab_offset; + + } WinNE_HeaderRec; + + + typedef struct WinPE32_HeaderRec_ + { + FT_ULong magic; + FT_UShort machine; + FT_UShort number_of_sections; + /* skipped content */ + FT_UShort size_of_optional_header; + /* skipped content */ + FT_UShort magic32; + /* skipped content */ + FT_ULong rsrc_virtual_address; + FT_ULong rsrc_size; + /* skipped content */ + + } WinPE32_HeaderRec; + + + typedef struct WinPE32_SectionRec_ + { + FT_Byte name[8]; + /* skipped content */ + FT_ULong virtual_address; + FT_ULong size_of_raw_data; + FT_ULong pointer_to_raw_data; + /* skipped content */ + + } WinPE32_SectionRec; + + + typedef struct WinPE_RsrcDirRec_ + { + FT_ULong characteristics; + FT_ULong time_date_stamp; + FT_UShort major_version; + FT_UShort minor_version; + FT_UShort number_of_named_entries; + FT_UShort number_of_id_entries; + + } WinPE_RsrcDirRec; + + + typedef struct WinPE_RsrcDirEntryRec_ + { + FT_ULong name; + FT_ULong offset; + + } WinPE_RsrcDirEntryRec; + + + typedef struct WinPE_RsrcDataEntryRec_ + { + FT_ULong offset_to_data; + FT_ULong size; + FT_ULong code_page; + FT_ULong reserved; + + } WinPE_RsrcDataEntryRec; + + + typedef struct WinNameInfoRec_ + { + FT_UShort offset; + FT_UShort length; + FT_UShort flags; + FT_UShort id; + FT_UShort handle; + FT_UShort usage; + + } WinNameInfoRec; + + + typedef struct WinResourceInfoRec_ + { + FT_UShort type_id; + FT_UShort count; + + } WinResourceInfoRec; + + +#define WINFNT_MZ_MAGIC 0x5A4D +#define WINFNT_NE_MAGIC 0x454E +#define WINFNT_PE_MAGIC 0x4550 + + + typedef struct FNT_FontRec_ + { + FT_ULong offset; + + FT_WinFNT_HeaderRec header; + + FT_Byte* fnt_frame; + FT_ULong fnt_size; + FT_String* family_name; + + } FNT_FontRec, *FNT_Font; + + + typedef struct FNT_FaceRec_ + { + FT_FaceRec root; + FNT_Font font; + + } FNT_FaceRec, *FNT_Face; + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) winfnt_driver_class; + + +FT_END_HEADER + + +#endif /* WINFNT_H_ */ + + +/* END */ diff --git a/vendor/freetype/subprojects/harfbuzz.wrap b/vendor/freetype/subprojects/harfbuzz.wrap new file mode 100644 index 0000000..341be63 --- /dev/null +++ b/vendor/freetype/subprojects/harfbuzz.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = harfbuzz-5.2.0 +source_url = https://github.com/harfbuzz/harfbuzz/releases/download/5.2.0/harfbuzz-5.2.0.tar.xz +source_filename = harfbuzz-5.2.0.tar.xz +source_hash = 735a94917b47936575acb4d4fa7e7986522f8a89527e4635721474dee2bc942c +wrapdb_version = 5.2.0-1 + +[provide] +harfbuzz = libharfbuzz_dep +harfbuzz-icu = libharfbuzz_icu_dep +harfbuzz-subset = libharfbuzz_subset_dep +harfbuzz-gobject = libharfbuzz_gobject_dep diff --git a/vendor/freetype/subprojects/libpng.wrap b/vendor/freetype/subprojects/libpng.wrap new file mode 100644 index 0000000..eb0785d --- /dev/null +++ b/vendor/freetype/subprojects/libpng.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = libpng-1.6.40 +source_url = https://github.com/glennrp/libpng/archive/v1.6.40.tar.gz +source_filename = libpng-1.6.40.tar.gz +source_hash = 62d25af25e636454b005c93cae51ddcd5383c40fa14aa3dae8f6576feb5692c2 +patch_filename = libpng_1.6.40-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libpng_1.6.40-1/get_patch +patch_hash = bad558070e0a82faa5c0ae553bcd12d49021fc4b628f232a8e58c3fbd281aae1 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libpng_1.6.40-1/libpng-1.6.40.tar.gz +wrapdb_version = 1.6.40-1 + +[provide] +libpng = libpng_dep diff --git a/vendor/freetype/subprojects/zlib.wrap b/vendor/freetype/subprojects/zlib.wrap new file mode 100644 index 0000000..f9f1180 --- /dev/null +++ b/vendor/freetype/subprojects/zlib.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = zlib-1.3 +source_url = http://zlib.net/fossils/zlib-1.3.tar.gz +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/zlib_1.3-1/zlib-1.3.tar.gz +source_filename = zlib-1.3.tar.gz +source_hash = ff0ba4c292013dbc27530b3a81e1f9a813cd39de01ca5e0f8bf355702efa593e +patch_filename = zlib_1.3-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3-1/get_patch +patch_hash = ab9d6b8167bb34a7c52b60b0cd6138aa4e0c2d31f997343a5f506f3b97b32008 +wrapdb_version = 1.3-1 + +[provide] +zlib = zlib_dep diff --git a/vendor/ogg/AUTHORS b/vendor/ogg/AUTHORS new file mode 100644 index 0000000..a0023f2 --- /dev/null +++ b/vendor/ogg/AUTHORS @@ -0,0 +1,7 @@ +Monty +Greg Maxwell +Ralph Giles +Cristian Adam +Tim Terriberry + +and the rest of the Xiph.Org Foundation. diff --git a/vendor/ogg/COPYING b/vendor/ogg/COPYING new file mode 100644 index 0000000..6111c6c --- /dev/null +++ b/vendor/ogg/COPYING @@ -0,0 +1,28 @@ +Copyright (c) 2002, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/ogg/README.md b/vendor/ogg/README.md new file mode 100644 index 0000000..0101cb1 --- /dev/null +++ b/vendor/ogg/README.md @@ -0,0 +1,160 @@ +# Ogg + +[![Travis Build Status](https://travis-ci.org/xiph/ogg.svg?branch=master)](https://travis-ci.org/xiph/ogg) +[![Jenkins Build Status](https://mf4.xiph.org/jenkins/job/libogg/badge/icon)](https://mf4.xiph.org/jenkins/job/libogg/) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/xiph/ogg?branch=master&svg=true)](https://ci.appveyor.com/project/rillian/ogg) + +Ogg project codecs use the Ogg bitstream format to arrange the raw, +compressed bitstream into a more robust, useful form. For example, +the Ogg bitstream makes seeking, time stamping and error recovery +possible, as well as mixing several sepearate, concurrent media +streams into a single physical bitstream. + +## What's here ## +This source distribution includes libogg and nothing else. Other modules +(eg, the modules libvorbis, vorbis-tools for the Vorbis music codec, +libtheora for the Theora video codec) contain the codec libraries for +use with Ogg bitstreams. + +Directory: + +- `src` The source for libogg, a BSD-license inplementation of the public domain Ogg bitstream format + +- `include` Library API headers + +- `doc` Ogg specification and libogg API documents + +- `win32` Win32 projects and build automation + +## Contact ## + +The Ogg homepage is located at https://www.xiph.org/ogg/ . +Up to date technical documents, contact information, source code and +pre-built utilities may be found there. + +## Building ## + +#### Building from tarball distributions #### + + ./configure + make + +and optionally (as root): + + make install + +This will install the Ogg libraries (static and shared) into +/usr/local/lib, includes into /usr/local/include and API +documentation into /usr/local/share/doc. + +#### Building from repository source #### + +A standard svn build should consist of nothing more than: + + ./autogen.sh + ./configure + make + +and as root if desired : + + make install + +#### Building on Windows #### + +Use the project file in the win32 directory. It should compile out of the box. + +#### Cross-compiling from Linux to Windows #### + +It is also possible to cross compile from Linux to windows using the MinGW +cross tools and even to run the test suite under Wine, the Linux/*nix +windows emulator. + +On Debian and Ubuntu systems, these cross compiler tools can be installed +by doing: + + sudo apt-get mingw32 mingw32-binutils mingw32-runtime wine + +Once these tools are installed its possible to compile and test by +executing the following commands, or something similar depending on +your system: + + ./configure --host=i586-mingw32msvc --target=i586-mingw32msvc --build=i586-linux + make + make check + +(Build instructions for Ogg codecs such as vorbis are similar and may +be found in those source modules' README files) + +## Building with CMake ## + +Ogg supports building using [CMake](http://www.cmake.org/). CMake is a meta build system that generates native projects for each platform. +To generate projects just run cmake replacing `YOUR-PROJECT-GENERATOR` with a proper generator from a list [here](http://www.cmake.org/cmake/help/v3.2/manual/cmake-generators.7.html): + + mkdir build + cd build + cmake -G YOUR-PROJECT-GENERATOR .. + +Note that by default cmake generates projects that will build static libraries. +To generate projects that will build dynamic library use `BUILD_SHARED_LIBS` option like this: + + cmake -G YOUR-PROJECT-GENERATOR -DBUILD_SHARED_LIBS=1 .. + +After projects are generated use them as usual + +#### Building on Windows #### + +Use proper generator for your Visual Studio version like: + + cmake -G "Visual Studio 12 2013" .. + +#### Building on Mac OS X #### + +Use Xcode generator. To build framework run: + + cmake -G Xcode -DBUILD_FRAMEWORK=1 .. + +#### Building on Linux #### + +Use Makefile generator which is default one. + + cmake .. + make + +## Testing ## + +This package includes a collection of automated tests. +Running them is not part of building nor installation but optional. + +### Unix-like System or MinGW ### + +If build under automake: + + make check + +If build under CMake: + + make test + +or: + + ctest + +### Windows with MSBuild ### + +If build with configuration type "Debug", then: + + ctest -C Debug + +If build with configuration type "Release", then: + + ctest -C Release + +## License ## + +THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. +USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS +GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE +IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. + +THE OggVorbis SOURCE CODE IS COPYRIGHT (C) 1994-2019 +by the Xiph.Org Foundation https://www.xiph.org/ diff --git a/vendor/ogg/build-ogg.lua b/vendor/ogg/build-ogg.lua new file mode 100644 index 0000000..5110a18 --- /dev/null +++ b/vendor/ogg/build-ogg.lua @@ -0,0 +1,20 @@ +project"ogg" + cppdialect"c++17" + kind"staticLib" + targetdir"lib" + staticruntime "off" + + includedirs"include" + files + { + "src/**.h", + "src/**.c" + } + + filter "configurations:Debug" + runtime "Debug" + symbols "on" + + filter "configurations:Release" + runtime "Release" + optimize "Speed" \ No newline at end of file diff --git a/vendor/ogg/include/Makefile.am b/vendor/ogg/include/Makefile.am new file mode 100644 index 0000000..0084e4d --- /dev/null +++ b/vendor/ogg/include/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = ogg diff --git a/vendor/ogg/include/ogg/Makefile.am b/vendor/ogg/include/ogg/Makefile.am new file mode 100644 index 0000000..142699d --- /dev/null +++ b/vendor/ogg/include/ogg/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +oggincludedir = $(includedir)/ogg + +ogginclude_HEADERS = ogg.h os_types.h +nodist_ogginclude_HEADERS = config_types.h diff --git a/vendor/ogg/include/ogg/config_types.h.in b/vendor/ogg/include/ogg/config_types.h.in new file mode 100644 index 0000000..898c3f1 --- /dev/null +++ b/vendor/ogg/include/ogg/config_types.h.in @@ -0,0 +1,26 @@ +#ifndef __CONFIG_TYPES_H__ +#define __CONFIG_TYPES_H__ + +/* these are filled in by configure or cmake*/ +#define INCLUDE_INTTYPES_H @INCLUDE_INTTYPES_H@ +#define INCLUDE_STDINT_H @INCLUDE_STDINT_H@ +#define INCLUDE_SYS_TYPES_H @INCLUDE_SYS_TYPES_H@ + +#if INCLUDE_INTTYPES_H +# include +#endif +#if INCLUDE_STDINT_H +# include +#endif +#if INCLUDE_SYS_TYPES_H +# include +#endif + +typedef @SIZE16@ ogg_int16_t; +typedef @USIZE16@ ogg_uint16_t; +typedef @SIZE32@ ogg_int32_t; +typedef @USIZE32@ ogg_uint32_t; +typedef @SIZE64@ ogg_int64_t; +typedef @USIZE64@ ogg_uint64_t; + +#endif diff --git a/vendor/ogg/include/ogg/ogg.h b/vendor/ogg/include/ogg/ogg.h new file mode 100644 index 0000000..c4325aa --- /dev/null +++ b/vendor/ogg/include/ogg/ogg.h @@ -0,0 +1,209 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * 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/ * + * * + ******************************************************************** + + function: toplevel libogg include + + ********************************************************************/ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + void *iov_base; + size_t iov_len; +} ogg_iovec_t; + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern int oggpack_writecheck(oggpack_buffer *b); +extern void oggpack_writetrunc(oggpack_buffer *b,long bits); +extern void oggpack_writealign(oggpack_buffer *b); +extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); + +extern void oggpackB_writeinit(oggpack_buffer *b); +extern int oggpackB_writecheck(oggpack_buffer *b); +extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); +extern void oggpackB_writealign(oggpack_buffer *b); +extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpackB_reset(oggpack_buffer *b); +extern void oggpackB_writeclear(oggpack_buffer *b); +extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpackB_look(oggpack_buffer *b,int bits); +extern long oggpackB_look1(oggpack_buffer *b); +extern void oggpackB_adv(oggpack_buffer *b,int bits); +extern void oggpackB_adv1(oggpack_buffer *b); +extern long oggpackB_read(oggpack_buffer *b,int bits); +extern long oggpackB_read1(oggpack_buffer *b); +extern long oggpackB_bytes(oggpack_buffer *b); +extern long oggpackB_bits(oggpack_buffer *b); +extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, + int count, long e_o_s, ogg_int64_t granulepos); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_check(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); +extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_check(ogg_stream_state *os); +extern int ogg_stream_eos(ogg_stream_state *os); + +extern void ogg_page_checksum_set(ogg_page *og); + +extern int ogg_page_version(const ogg_page *og); +extern int ogg_page_continued(const ogg_page *og); +extern int ogg_page_bos(const ogg_page *og); +extern int ogg_page_eos(const ogg_page *og); +extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); +extern int ogg_page_serialno(const ogg_page *og); +extern long ogg_page_pageno(const ogg_page *og); +extern int ogg_page_packets(const ogg_page *og); + +extern void ogg_packet_clear(ogg_packet *op); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/vendor/ogg/include/ogg/os_types.h b/vendor/ogg/include/ogg/os_types.h new file mode 100644 index 0000000..e655a1d --- /dev/null +++ b/vendor/ogg/include/ogg/os_types.h @@ -0,0 +1,158 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: Define a consistent set of types on each platform. + + ********************************************************************/ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _ogg_malloc malloc +#define _ogg_calloc calloc +#define _ogg_realloc realloc +#define _ogg_free free + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# elif defined(__MINGW32__) +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; +# elif defined(__MWERKS__) + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# else + /* MSVC/Borland */ + typedef __int64 ogg_int64_t; + typedef __int32 ogg_int32_t; + typedef unsigned __int32 ogg_uint32_t; + typedef unsigned __int64 ogg_uint64_t; + typedef __int16 ogg_int16_t; + typedef unsigned __int16 ogg_uint16_t; +# endif +# endif + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t ogg_int16_t; + typedef u_int16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef u_int32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef u_int64_t ogg_uint64_t; + +#elif defined(__HAIKU__) + + /* Haiku */ +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short ogg_int16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef long ogg_int64_t; + typedef unsigned long ogg_uint64_t; + typedef int ogg_int32_t; + typedef unsigned ogg_uint32_t; + typedef short ogg_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + typedef unsigned long long int ogg_uint64_t; + +#elif defined(__TMS320C6X__) + + /* TI C64x compiler */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + typedef unsigned long long int ogg_uint64_t; + +#else + +# include + +#endif + +#endif /* _OS_TYPES_H */ diff --git a/vendor/ogg/lib/ogg.idb b/vendor/ogg/lib/ogg.idb new file mode 100644 index 0000000000000000000000000000000000000000..b4a43e856d12a3d12c6ae7ad7bd4ca2558f3bb32 GIT binary patch literal 68608 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 Yy?`WPU@0-McPVvN`YH?v12-`6KZEOTh5!Hn literal 0 HcmV?d00001 diff --git a/vendor/ogg/lib/ogg.lib b/vendor/ogg/lib/ogg.lib new file mode 100644 index 0000000000000000000000000000000000000000..0e24564877a983e225b267f0125fc8a6e878aaed GIT binary patch literal 107644 zcmeEvd0bRg`1c(K5NAdPP!Saq6%EA@g%HGr5s*PZaNkfsKqL`}#U-~ zOw-EJGBdRVSJX^gv&0k3RCV&IeRb{{6cij77!vGX8#j472ZjXjkYtr4Nl}udasU73R%rK0{~z5s z85v2rDXHVr3zAZ^(o^yz4rHV!jmgP3ds4@xr;g7roRE~CUSNUdWEW&+7pA9~p>)ew z8F?w$g<0vjmKcASh3MRrjP&drvxNNgyv&p=OJrhtUVdgyHe<;z$V*R|ki^nc3lNEy zInvVM$eCivV@jLMF*d6(f1G7F1CqvOW@TBTnc0~<%W|~LoQdhFnYB{G^JELlDXbNj zGv=nJkGFgRm4J2RjP!@1GU%b?<)xddL{1+AP)`=6m_H>uHEB%Y*sov`jVgretMiuioiibnBN=Jq)3rB`5%7!Dg9&AxE|Gq~E2ogPl9l8W} zjU?^UDyVCa6#vOTJL$jq_rLlW9g?Mjen{b&8ik4LfA#VI>f`^_$Gl(VYE$$a4|i9x zrX_2xHkauB&1yaMU+7~i6a8@(dSI~0a!*#}jCn3`KsvgE{Pe`Jc_|YzvorjFNtQTz zx=ES&=?w2=GV^5-bv>)Izkg6rke63bP+;c}#+$54oA-tkcsV|E-uII9g#yYSmtR_5 zdTPPMbncU+PH^0BV)DsUA11>O^~ zO?+$Mmww4zG0RzCZ)Q9tVf`qv|EDuSSK58#X#T_`GBZw_|lOb;p zc)CBs`Mf}E$#XzCO!JeZS(I^HR4lgSy@CKEcv^O5Y?2FzEqTu1+bQ#KPTTVIN=Z80 zMUol^aV{zzTk@zl7I#H`;ijvu^!=P~`-%5Mb%+kx+@ z%uD5LOWsuA9lA-<8r*bIJFq1$4GI4OJT1C2Hpv;pmOM(|dYOlF+Ll*|z|G*B(}Q!> zl|GVJCi6T>9_9BC_?Gm1w7ek*J|goxN?ro;+qRb^6^3yxm|QmVOVxix=HZ;S^Xmb5 zZFG_p+M9FLRljWzyh7%Al)SGIxC?v>!#P)7YOWpwRg}^X2l5vd79=9!d9Z?^j zg6AhaW2>`0k3{hJXxQ7h>8eZrB|_e9@C=IKe0Av;%I{w?59hR7#b)FiMh6;--u8VXJ-vp~%{fmZagy#3e~j;kG63 zJEU)JiX@FrXKZ!0mqAGQJn(#<$@x0gA&=Dj%i~dgxaq2^{JK;5fk!)m^VL-!O%a>~ zp2;#_UGl;ZFdIC(vL7w)K7!qHIFISqR{2$;{G4+o>Bl_I1$8twD}D67#k_*HkDIQ#>Q|2kEd|eyuW~*Oh%I?; zz=tg5Jf>e;`8|Qaap3Fz8t1Ajzen-h$>528gY%)-ZRU3lDk=j!)o*h?GRJJCuMF}! ztwft%#rf)z_d4V?cn5afTFw_(hrDLMH>~44re9n6b-{D@gYVn*oU5+`kkDXQjlVfPwo7g%ws~sT>QiQa%=NZeclG2{fC^3%7yV+$!i3> zwamjgWj-77g231N3FIY%r@)%ehP;=-v)r1`Dt#_U)DG}`ZOvyx-evIIwC1ytN9EUO zgDIz+)>VF<;Pa7r>ncBz*XIf4^#k9C$H>z_-sC5gHwS!+9wU$H_apG^vgWf^ktodxz$LrvE*P72N zeI#!ecuraK*^u`a@odD6tFHV~`8@@mAZtDw@&Mjo}7v?r981-{8oAaCgt z%3BV;_n$ys#S_Y_1m6#jkw@+CE_j?j;iV_a*+zYI1W&LvpN;w*0-mwfd^Y6G0nZ|9 zJ}Y@tA0Np)JcV`F?-uawdW<}3FI7({?|1OsevCX9$aDYHlrm21YJcs(*G1+P?f4B9DMITMjn-4#S_Xq0luoo$fNf64|v=*^Rg4=VxztIgQvSS zpH=yhyb<8Zw&t@TZvl8-x8}1UZwq)1TJzbEcM&{)S@T)RqxRzV8Ein@bUiA+Vc?0i z=F6*XcS>H8^qkDY1mY)5N(htZ#|N1(ay)m^C zbc%@VqZ=GMC^ouxx7Kk3hlCFp)Vekp9~;q67Z*9OwHFQhuH!Do-B(h$lKk*)iG#7R zB0n*ITuNF_VnllW_=23=#I*E@iTT+nwW!g5)oo7CM^N|vNb zsiD+ST3P~QU#4-Hsd+j1Ib#dFd`oRIkfRztkPb0*|wW?}CJrN`)poFm;J5apOiW-B@h0FvRo1)WYfd?%Cc!c2zxq7Ar2~0TtAKCp3+)=W-Gu(RFO|#$8vO5y)SlRs++;OrSBS&d~?5=@3 zQFaI6*;FQ!hCaAcWcMt%(`EM}C5E!H`$M?@Li}7%RK4V-^ioIf`s3L6{pdwZAtZX3a0IRpTZlzvZ=RNA$kK_wuzv&T8KpxYpYYU!<-UHUcXAwN{VSxesc@m%ay-QYJGi7*{0*I@4T{eX~M^;7>Y8!*SB=od$0H6 zrJhZH|GWH?3%bo+@7Q|{y1pj+%LfgrpZ|Ro+8&gXm$GzYaPeQ4-q`%+ojrd(d+IyS zABw_OEgIse%t`O``C>Z_rUr@_-}dSiGyJX(ZyQ!Wd{y@PU%q+n<4$u{{T7q?Y0rUc z_GJ3Efx2XTjVC_X?EFdFpZ*RkIn(K+pKkwl@9P&@{klG}agtBzwC@c{WG)#rS%)oN@K;vD}yEM_0Vr!RwW; zcmG-3e$(ml*KU4OP;~j2Pb`KOjBmDILg=isQ+rIm)BT-J-yF~A(0`CV{)E?{ldn9L zvg}CK4ouZBzIXmv+~kLLVdui{v|Qh>g~R=4ow|7JTKhu8gfD)H{r$Ho=t2f#PQ^=k zcxBq~gTdoGq;E#Qp4)xwz}SLy%J*^ty`GqN2 zUIPmX(=u}syZCqMk_df0p%A+Urz8#uPaKq!lLdZsHi?}B{Q?910-o*S-!(BaJ2k5? z4LwFmTKd?0zi|&e!pmoJa8Ucip_%AWCgpp@U{hRTXaB@#IbLUfKYzb2L0IJW^G_^H z%_~Su&A~c$UP00%?4F@D^oK?Mcd5=o*HrMIrg}n3R#r|bPxKS_v8F;qw?TdG|4Z!r zq=G5A>9(@;-<4W^K^i(Y8x`}f>$=V={@0RBt!6^{gq*x7|3%s?B&Oz0NwQU>|2mbd zU$>FC|E_K(ree<}EUt9gR%ZM4`PZp7l?2|%w5-fA|FU`J=cS7MFsc8_^rV!(Df0Q;T(Emb`oHiSx{s&sw|L9ZlQ?mX?<)`Lk zrxxbrrDvy3;g6zm2~Bf2O0lk4uv_1Sdoye|wX{xlsU&?#qPNpfebMh;dgFJ-XeVR2 z@2=2r&CHowYiep{!d)@5b*a6p-l* zC~%Y^V~j^_ua|{4;FxafWTZlGJamx+(1U99#zb#_ebFATq}?S`o%AJ21_YFGs0Y|+ zdB$E!!0&s^l_Xr*!Ziaf8e-a0BH6I)b3Eu-sSg__0%F%1{L-q->$u}lEc`Mg<>cdV zMcS04^vSs?*=Z=Hp0526tdMX{!cEe-MnhHu#=JHfs$wlAQ%AUG+rTc8sZAWn_a%(be2ZTen&PD;Vgx?_LIW{ zS$K%6yw5>0`Lis-?WA~D=>~wwGDw8#jfQ75Q)FVs@X1=xorvpz}cwfxZm7AM{nw3Q%engm(lzj9V>H0gy{24HH90 z*t-Pvt+vuRZjaMBeTB}UriqC<=$sC9D3b)nFkV!(mH+FL$T%8g=-z|H*1}At8nf&hfkKnO1X3t9#GA?VMbn?Qd9 zEeHJt6q-x=6_nZ%;T=Ko99c_|OC^mE*l5|MlClMsC$N_UwnShn1h!gW^lbhNdOCjw zwR(=+wBZSvJB0JlMj4>R%(p4 zq&tA~0dATC<`+|Ag|upso`m5I(=LSwQb^=;hpEC97;!r&MoFzPZ>nU9Y#ii`VnSLo zMdsy5vE*ZfWC6v1fnQwn4S-+GfV;57db-lwvVzSf3wfN~iTN|Zj>5zB0EO!&Qp|b8 zFDxDx7&XL6>5f-Wy2;F;2$ZIHg`6f=fT%Nxo*S>AS!|{gZooSXx9OsCB9%ZAsY{{j z3SL!8`c+VW&_6&a@7F=8soexU26`8?3iKW*l{0SkiXVZS8zSW5h6u;V5aC#^>{7D? za*WIm&iAU|TP3hH0xJ{P9)VQ~?1aE*dncC{CcF3;!edBmYX3l;@tWTFeXQ|7L`Z-C zne}16qk(yi-mN$4Jo=S-F4C7w^Y+jgL$%v}Q{}hR*UX|OpeyaI&>Im@q6-v*0g5#D zOrg`#MK85Eshf41rtu5gj~#1n^2TucxYCjK zx|&^h^XBf=MxKmNme0CFj0NZPM#zBd0>6@hE+tbn(WyF@Xr%&Uj%XuG519wiMx9r5 z>Os9xQ=u=3@rWo1M@kABMk;hJl-y`Ji6_Wq}4wd~8N(+HQBFV%1@G9A5th>(J*GcD^kGK zhZr^yK#8R4!Z<3IsT?l=T$fN)F!KVNlt_jsc^DROlQwAq_%8~>h1DkmwWCi!DUq8& zF~KiYfwl(S0vZgu4KxOHJ7|I&J{0sT_|ri5f#!hj2PNa>04UYpLC|HOhd`;qz6K?8 z;4tW?pp~FoL63rN2R#P*73gu$3eXdv$3ahmo&!AvdI1!h(hZkEzXydTl+J)set!TZ zZTAx>y&IGdGHhTt$y$$GDrum=C>I<{6$}W`@Hc*}s(i`jZk(hR9SwNZARjG9icOeByBdL+hZg>wRVzwLB z!51V&xq^tx2QF%@)H0t#`{$Q|R+Z^kqxi-J={|Ztm^!2PkJMRx#{Cp~|ID*3_1XL9 zC5s|r@&2JhH%(iJ*NtW%U_7zQWXn^_qqoF#Q99{OBMnZikFMX*5-AB+KpTTz1*Lra zA-B-4;pY7^xm40{{BmrR>{3aY0-GSPcLhcz#^de~Sed}|Mum1um_t#O-EK5eYknCkxL~F78n&E$LNLSeDuO{jOGywx7V5LT>f%4ZEi5uYp{dvr@Cm#Iqr01|3dB~yV>mWk4i1AdvS zgnfO%^z9a^o1wPrhIf^5con#i=j6ImNG~vv3gA82_7aIKZhQ%X*Dk$+{TK&-dEDTR zWd8b)Fv1lz#jJR;>ITgJ6p(zc1 z0P2JG0#$)h8a1H(K^uS$0mU~U3}lOA8j>}a-Ei~fLN1j=!&;7wkzIU%%dtFx%@BOE z1-4RP?+R?Az%~nvv^tmPB)eegn%+i*cpG0tgkY1qP;x) zG8YS(UH^4~Jc*LR)Qo}Bf|kjOqmx`5`+@P|AQx9s93v&gF;Y?-BPGQ#z0nn8ca3&S zUndM&dN+_~1mIMgohq}lJ~^Y+m@24p(yPl6ub$cIC_6>T{)y*=ST#6$XXqj|N;{+Y zWiDBZFFrl8fEz-Sv|*7gV$cvlk5`~O3up%YPQz;_sTuGDp_V#I_9!fDErX%z#EgF$ zI%BwCTF#)sypo9+_4x7>!6d-`fJ)BQOf#@@@L+c1Aqju3O zZf;pYJAKiv<}|M)Mz4l$HKlrm9#b~j@CsvjbkRjcVYR6J9guBpUj+f9>sj2i^N(NV z+UG{rBi}7AHX`baah4a0?T%vQqo@MrPtCzHJnML({-g|0Vv$$rXf8vLZT4&mmtNG@)Jag1y*j*$(S!2AR>;-LTa=0;vsGj+V^sLp($zLdL{?hhDepyxz`_kGYUd(!r zD(Sk+Gxoyxn;r*B>9DrXB2k3I(g(CPC`=nxqzB>VMM^F{-NZ3^ML71B>{3fB1;&dC z6P~?YO(mo?Ih<=3RS6<>eMC`Fv*DMysKn>f{`10mxZ|`{Ts`IDg6+bJD_kzF14t+@ zE^_e+c#e^!!m*XIOU>5dImSCqbFWzp9_zQ8ULm?jkI^n!ewoX}^clWK6p7RSP5ZI# zIVm01&8L-I9%wpD&!Ws&^C4Zx%Y$6}jpP`;ksPDu!?BeDBlEri3PpeGbn~)Xr)w&9 zvk5`*df6%;55%U6X0d3;FTYs%$RDiY-#Mf55$pLhx-^d_J)W?9#B2^t)lm6_$xkCf z>7eo9Oxwsq&QcAy2*Y@FZoG>mE-2+MJ`@m9Ha8$7?l^tRtn5KPDjCY z$6(!Jp9NM_|HUp0zSUynZpy`bxb4~21MVUn&0SCvR?D3gK&)Hr0ASQB$Ks|v1pKO1 zBkVJC57mfyyswuBIi|>u9Pe8UQA7>Vc;8))ZCcxFYvni9lI46rg6WB%ln<&=dh;S= z{2kO-eYjVHI)lCo>Iu3A)E9IuD69!4FvqBdIhHB-sE^_p zfxqNulUw9}|Do5i<8;gPm3*s`WAQ51#d7M;K+ zbdA^-ptp!^>JA)%b(e7uJIO%Krl4xjW}wt9GzX<_fpF>;$WQgR3pcMna;YSm^yV0~ z3XYWtj8p)}bYIY1k&YGUC7^6|rxMgWPfLu}dYh6$mj?F`2;i6HE62ah`_Kz#?nzyd zUaOfb^CB)4;|R91Y%ruhdPVl3LMDLHRC^MNy)Hhcq=Hf&=ykz=Jb_3_1g&i(X;M4!<5M zXa0%JM-;a6qYB#@s?W4Sp3OdDIZX?+x?|EfQ$+U~jW2kPB zZm@2Mj!i2^7@zO>RSlv?gx-ua{upVztutPV(8m85YrGs8a15Jdb;i5V`^(s-)sPVF zoNZ`nk#o;z=WK!_!nlgQ|DiJ;i=6vwVW&vrE(Fb(sy9yYuvniq?usbwtI!#bYPV?S zhklbcGBWhgw9D0lbjBMx9wR#R!3>9@+xFAD=#AkXv8e}p8#Tq+EeDi$_$qe3GjOk( zef^B~6~=wELuFUZE?wyHY5S`kbvuy)Y1UoJL_z(?xi#83?nv7H@Zk82jDfMGQ-jAw zlnm_NnlsS@)ltvVX z_lz{&h%UeF1ZOXqhRIYX)7~--muZAdBaKDL5L6uA2l0!;qu8&W{YD#&X$UI1Q=`*H z94yr-N{Yx|9MiY_j#F_=4Ev2`zj4S&zv6)ditgG?8(7-=pE%>eqZeaK!w1!r#Tmah z-Y)GZ(bNiMG_EuZ+h9gIVLME$^0uy6|3G=2@ZRtj+ea6b+eIj^1O7)}^oOGGaOmY} z^{YMR9-Gk!GG#tZv936_>A(o%(YTW7QfcqzB}IdfFrD(It|Zb)r@Wz0#oCxs8C??T zqAMx%Fot&|8{Bu7KJ{*FY8fW^>`DNYHu~ZsiV&%a@rq3i?+9E8@D2kN`7QwmqK%Of zt!Z%DM5Z1xZ3;RHTazMbU4un}8><@8#=#b=8qvl$$+V)u-SUzKd9bFz`i5#dzC$B{ z_CyTRVik?`enC=NPIfv=A6X8|nV5dagBQ}RWO;EF>277$5{3os*yo9m=T*4~ zQ{ho3goQO0wTX!8Z#P`phtuk&T`6KBi=xq!Uu0$47RIHCg(lAN=N72qsBqUX2BQ>% z$$!eV8)Wl}m;oL?Y}#?cCLHsAf7!ULuP5WSwM77}MLIT8&R*_lr|hDRSGQ4jgc01J zzV(`5-K&Z}vG&lMwGT?#Ddw*)%xEuQrpw3VkR+JV&Nx{>%#=7v2N`t<@C#F#fMEcH zl}Cm}G5~H^@HdsPaRRe2HkdVdn-vs-agpw!)=UOCf0wZ15LO21qhwIh1u3AUWX6E% zKvO~K?MVmi4>}ff1n2}%8lmHjFl2#3HyEA=%>`X7`OFRV9t151{RR}9a1BR6D?q7X9sq5FvL`=j9rEiyzXpv2Jq$Vw6mboy zphrM6K(SlJ@Eqs~(0QOIL6?D^0$mRJJt%$T?<^=O2FgEm06&6uL^)8|@j(;0_@I|# zNph%)4Rtw|FR+=iODz=%>@9(<6d2VVkGoM|Uki*v=vGNT2&_tA*97*Lz+6yP6hkeM zh05dl2&|*PsO~slcYzHP7+GdK?l^&E3G8KoEfpB*TbB2cz^ESiGmZ%i1U5-vQw4_ILGm+h2<#t$+1Z=Yw@7xWrB?)IK8a_% zi(v-lN3?U+pw% zv`6P&PeX-vB})@hkK~Q=4Kbg@gu#@IRwx2Gf=6sLi;5Nqe~4=|^P9uD-yA;DDxCYx z;S1z&(}X&=bzlmz=Y_bwZxJp=|C42q2-Oqy$5dEZ1mK#Bu9E6t9w-&$d{COHH-b{X zjE5THL9tqENCABbbPDJzpro_W=Ne{#Volya30wqPCi^>rQVZh!0lD~6CdU%xP!&rH z$8rUR=g4uF2yBJGRtu~R+9QwqwCqwzw9}JgT?G~{uqc5I6d3LPq!=o)KjgR>0?QZJ zB!LwPY`(yj2n<$$EN`{I-V+%5ZuuEy0*fe#_4XP#c*syO8R8#sGnVP12;)trj+Ub# z#Ts4X<{s0|c^Pg!IVQsqoq92HZrO}b-4?Q{U=+;>VgF$!es!n;T{BFGn<7G@}lwWBXp}ee59q1B) zjsLlGj}K?rD)p%`8og2-YpjR;fVY_tI7?@`D8e=RqAQBRA0tcS=rE0TVH3oQElKm9tSh=> zr=3lGW2|u?&MR(*@h8Qmj_im@2W%Fs7iSFCmqd8`=t{$DVoL^jd+C(r@ulA1>r*SD zOYL8ZF70?QzO>Pb*wCs;^`k>CYm2Dr^u}-FjFoY~8bya*)D}@?>r0m~(WL`D^rbi% zY1|cOyc`?)^Q30_&`a8)1QzYCzO;zA;*7guOUDyqM`F?Fv5AqmIv|WvqBmYfI**j}%wx{ZdS+W<_*p1&KZx z7kW-xbOih|OKd4h041tU&Kid^}UbPP=H2KcBBj8a-+xUoN-8wt?{kZhN)?=`eGh!S6TBMJYYbT&51T2CdzCHIBX} zPrV)v21o;4;9ys+4p#pAdp7&n=8XMI<$5JQS<;sh&#vZd_JF>^rI7F~GB&0(uNZi+ z;VKULzl${ha*tEb<4DMOK20dn)$H0j*u}z6ej9;HJ8FYl?D+V-II!hPX><^7y z6;gUqP7bZC3VF@~I=5q`{F8Tq+zcG)*YT$9Ba`3r#yLWn6rNFb25PiQ=lS;L{Q&DR!(l zCO|4L@)PKEJ0Uf_U30FXm`*Spb4N)fhL2t1kDBY z0-Xuk8kEW#gLA`L(DtAofkJH?HiG(sQj>iKv>dcE=x?AQpw~dVf#Q9VLP6a?dx83a z>Oe_Rk$)x9jC>fVC6T{e_WuG(eD`FW>XrB!f)XAC8V=eYGy-%QXcQ>*`q7|ofX0HZ z1nmb(t*t-kUeGR}q$kKv2G|Fi%1M&?9uP0xpER^ zUT3}npY?9#u8e~p*c;>m54$Wo6F#$wKfYS4HzB2D?m4=!z*^^p%pHdh>sIK4j+jn| zmLSdR54ULnn))zOLwfe;hkl@j>YSPsM~X-nkxY6D*F{Wq@GTq`It{xVx$>Y6mR<>e&<% zho@YO--cXY`J_n_vqo%&f(M9QuB^F0VbtwE! z^|0g27t1bf9lbT(R2qk#=7Yzkv(@N2rB*CqC(vZv*z?IcUBocHR@q;nVB4-JRi=+2 z*gR`Z`}lRPjSw}LMdy3{Y5jw|DDv+(HfH^&At%$zXGbJpFMluh__RReIDtV{Db zYkJZe#>3B9TS~=;kC|pBV+%_x7U!(97&4WmmDc>o(xF)^G9Yc}hK4HBrY(BQZCqBX zO;k%J6;Mkj&>Kwk&JJY@onYB7P@5y2V7Zg)H@x%IaxQ|l0KEh{6!bD^qU^sW`$;!! z$IW#Ex%ieAj*XE+`2jYL&QLV0#2sAuufP$Z<~#3|oO@ z?5@BZQTF^9sB`%l#R6L(urM}xW!}pZ9Bb@`iS$@wo=dF?XM6^%sh}*wpd|)VBMbOU0GM*F`{Gqo2!nO0u z;nSz?VClq6T@z^yqYNnh}ZgJ!l-L z!BkJbQu{?H8VMVD?0qXs24ap5U$D7Sw4EZ>VC#)PHrEt1!ps&$!vqfX6E)!-Yr_3Q zvb?r(;ciWy)2zG1TIe4ca7912roboQ81M6FYf!i5rICtQ z<#pfd#*4hW%X6Yx%g}G9RpEmmPuHGuJdQlmv|==1%q*tvW0_UtYxJonbziV8W1-(p zpQ3F^g+rWd(x;DhOGLNk5heD;GUBD*Z(l*&k#nyUxS81GNgMbo^!rGi#e66QH1%-iAsG%J!>vBmeP z_t%w1c+1N_M4@LbRiK4lYXIM%?G0$PO@y2rchgKA+N2aM664{#hJJ z3{xkF*&U^uV8G`{3o^3{)A@HWsYYWNkDEpDnhXF+Vs92|UUQ>tXG}=XF5opl04mJkm%kw>lIS?2GC{X;FK z=dq*094U)O8UzMU#KS|b+Kx+#_;&hoYgnkHrA163L(!8ECgYDk$VS7JlRxX)xbum(;h z>ATE746(x5iD0tbHZp7{5NFI=*26ay9au_fLe(;i@J1GY`_$BKi6g!A#`pM zCbW}bo2GdaO}(cnyro4r9Tr5m!!sIXV@P95fCCY#w`Vhe9ILs6Uk~3dSA=uP63w```}59fms=H$BDO;wgQ2Qk1bFVQs`Nf7D_9X3Kbs}F;xIr$p-M%vXYAdh&@?+n&So_UYT&< zBE3y!@<6zGqrhx2%wc+Qv0sNBY;XW2^;Qqm3seQ#7PLNS2T<(MU>{0!2JIsIgXHiY zpv2z`R0G-@l=vcLKP_fcIB6N|2V&>E$v<57uLmXmjk2G#F!^b~jU6F|U9$hE>?f7! z0-Tfug_8<&18syh;SNf#Yco(UP-uOF52z<-2hbLv^v*v8N=m5}Xb;dfptSeO8+15m zJ5XBgYY#dJv;*i=P+w3ot^Gk?1nms^I%ojsr=XagHS7WH26_}U6!dS`S7C-qykXtS*L)a?4+rnC<6)8)P}yGGeK#Mc@`*jZIoWJCuW0o zL_L0in-9mx#n0<f1V$4Y{JGSj@VL(ltWaRH1U6S-iv{+oz*Y%tjlebu>@$JU zgf)NeDS^>Yj$<^G<7uI3YL3w~HOIONEL31o0*evYP=SpUSdPGGvWUx@DX=1etrQrw zPR_SmVEYADC9q!wc1>V^39K>N63<6d*`<=&3XEDLe+J$^nJ-dcw4}o0QVZpLw3m!y zXvs1*UtmUoZ5P;1fgKXq5rO?AFicX)^6m+&MqnRe;KQH0QFh^z&#=ikRw=twQY5D4 zFp1nNHbha-Eh2=S*DG+12+?&cY{n0pT|%ps2q@4ZoOUA?I`YY8i*QUiw*gxvZhI+Q zxbSFZ+BHBd>xJjO2&0R%`!MuQ{IVVmJZ9>-@1xBBzA#cu23GBp04OG0QMRV0RZ7ba zn2t5j{U1zETXnK*NAozIY4%IyLA|UBlqQ*bRj5s~>Gwa;@@Vzk z14TsRyjo}Z9%_tKuGWnaRyS*e&Y+YH9IG}^k;7s&v;=Jo>Mi>NKpVmzBI7+li9ZY! z<_l|#8{p=Rkz6V%8NVD$lU*u_mcKYQOJHvcY?Z)>hx2U`*kOT@;YXp^4u~q^e6)_v zG17k_Y!NLWpltuFGz72-of4f!U!vft-ULJe88DCF$We8Z{_5AcwYV>a^5)SYH3{{2M|Y(i zj_tI@D6k&1wat~0$5uGTf|loSNHUH2s3OIfk2V=o7P$@(ITGt52?#S?rY?z=u}!Ub z4QiCa*Md?@cn_3nejO;)`1_#5OX1Y@ke^z>PTaf&kV_?v5!hJSrJ@bPGGB?nI-4r~Z#HQ}TOn3c@c#32UciK-QXSfDp8a?#dj10`PZ>{-*{gIq&Gds@OCn1;)f$pQ` zsKzEtzKg!PK4w?t4fXh2IUTJ3oCTh)9ZH{8rSGfa04df+<<#j*lqLDtr;7ckN+rkf znQXR2fAnrDwG+7Qr6T;UXRd|#UB_Ij@cSNf+2i**Zs_HQw$1+toD2z?s7+#-g9Bd# zHvLsn`LpNLj`IBvA!~9D_e5ruYp0W)F>Nb zT8UmtG6TKXGx!g^S@LD^?on)#PVb&Sf~kbD2ss6s!SXNc$disCuCrtjroVK-{SR-> zH*Nl3!1&GKE9CgJS>HmZSIICDY7eB-n}Sl?q6-5s1GSM@&<3)f>XrOtC1iuP0gVUk z42o$4_5mEML@^yd05kzO4*RebQcN!xlHtc7&Oig}B+!YV$)GbpQ$XpxP6d4#G!2x7 z*y*4fLC1oABKx<1((}tf$ARtv%>>;KIsug0HHDLAp&>cfEac+H063N?hpMDp!ADJm z^U=C1=UXB$DoT#67TBi(`&?ir1@@i5t_Y0YO8$(7XwqCB^*bDUT41zh%drCjJ1ns8 z1cn1~GT$YET@lzFfjtmdebhC7E@=n;3~zz?2rQs1MCYV^yA0psGO3e!NWAsuSxC{- zMa_j;Howg3#QYsDp-pHuohDiN^`xI67O#qVCeq&|1C-K1%~%QQE#rOA49JO@1=gIS zF*t)_qaic*LqOZXkL`x+HQWR@FK=@3^5z(oH^(w$mzsT?h-2>vj7pAU zI|NoHuv+!f>Y;kU8npZobKWCATtU7NRlBOr0kO8$y8@%C>Wq7ojjFQzHdP&!^~^(+ zHyQaS_V(%lF*FI{q}q#^j_*a+FBl1Pbh zY^A{1k<&Upgi|!d35T5U*HZ3i7tDi(!M=k<`qX&Xr!6ClGc^&ucWy`gZbYZHlsHVAg0rrSXv!+Y*4+vpwC6%NLQ36ZE!fne8rLO#)|SwPQ`Ieh_cV3#Ca4)HVqx+ zUJzC?%H7yfR~l6lS>i|AWJ=={+u}(^NscFrPFp2l#%ple3&o)^p4Kbzm0sW7B~dQE zm#VwPVKYt3=#q}uis`7s<{_u(R7bsXZ#0}PNCrXp132!=p`MDNF2>6c+Xzo0>2t5l zY*x@RA|$7gcJ7jYYHIdJ(Ml8l^O)83x03s@-)s2=Oh<6rGn1dY{1KC09`mk?Yv>rQ z6&kG~d4g**=ol9`*k$f}=xY?FS=Kt$*{=&W>5=c`lI1F)~tQQ6Va zN$KF&6StkRrMj&;R{gYN0Jz(#z12QyUxYegYbSj~!;}g0e#nMM@^qFB{waUjBooTA z(OW^;qM?sJ^RGgQ4PY33WQJpJFwDGFBs+aFFCFUkX)TfL91=sSs4Me(V${SJ=;?#b zCeilNaD`b6`z$v_qdkAo?CBv2Ck6j=LH!Wz6DCT-&JPu^aK1;voUcr9Ol2W_hXJkb z^H?pRgG>{fe9r>Sh0SNYgIU$maV!%rRXlyR+DXd7UzTu}!d*#g0FX$((}9AqXaLO^ zPJisc^j9aAC_X_*8$~yCcs*UGP=J&=Zan^^0xOS3@E#=$C&Z#q;FMX~it5j>5=A{} zh@zcEE8*Wo(I^e4GJ%lhm5Y+@~6% z_Dl`o8uQa$ApZB2s+r#oBeH&MP2YO#=)=O<55|seSi>i)meNWVb_#ClSQ3DVj)j0> z0BS8I+yG#}ZMx`vr*4LZbi8^|+~`h72mA`^1xkK;mC5f9S`Au?c)x?vY9Us}3`;<7 zg1!xU3-n#k+n^tSUInE}z5z;l0LRD};MhEYy(qAy z0;91%=ObI4$E9D6?Gadoz-XnN^Uai9D*Eb*jJ+hVWdd6vu#W{s>+$><#{@>Jpd33V zunPjCl~Mj&S{dbhv`Wvh7P3o4-M)-<78r)nGDhp6JT8XHGL|7QS_S3uiUjtOz?KMX zlfXU`*a3kZ78vSKmWSGwpX-RG$e*E-T`DO}VB-Xa)q0ta&WiIi&kjJa4 zH^p_5UGl^pnJqXkTj1?g>-&BBRGkYmTbjahi7;luP`OB^46GETb^*6iqG6>x&#aVz zx}pcxR?0QB53`kWiCZZF2VkT;WgO}mTN>G1-iE4BR@Ri43}t3XXvMTkut>--(e1=b ziA}isb;culWjQxe=$ur7F7&YWr78qIp``-z$G619cWu=0ywacr;PGc*hQ2?!H{tT@ibW}!|1DW$#ghm9FBKb zd{yog(#LI+UxlkP-h|p#iZ|MT_1@4ja8dSFgOcv!S8XdLKRtas)QiQGW$i(6d!~EI zOre1aj==sKGi4d}6h7R;lP&%-1d=kQZe{}9&yZJ|s7P1v^B1%~k&;bYB`HC4nwI;U zvbj<(R)ef}ClNHu`7C3n6VklDpdLS*VM>cAtS2Xl6in)x=4MSjdoc5lS2R-a8CvSu z`BVAH;JSPE=UB{KmR9Q7SFr~_+_O_BSIBsuWs|kGd-9Wv<7=$U>XA0;;dxKa)1s}r z2PeHve;_wXif2io9-K#_ErsUw5qX~0-XF(rs4w-l2opW~0aMSOp>F?#{W=vSWwDBq zfvvep42P+(sW1P9VdlP^2BtK(YHPG^(T`)n&9wev>c<;N4%CL|^3I=4U}+Z*Moiyx)zi)0Qt#Adk>VF z2>H=6qz^$IK{tY`K@Wk_Vca92^j1`Yb^|>M+6VMFDA~U!KnH+Qyb++=L6bmtfTn`( z1f3(}C7`?Er+syMK&hAC3rc64)7m{Uk85BzfFF1g1jTIp!?8RCF9&###%khro0K zBMr&p_7_-+z|sXaUtnZAQ4AG*gHDc1rOGj~leoOk1$I(kG>y&qt_bY9z?{*Zd0aQy zrIK0;tewEn{$##41@^wcJ`xyxw3o~KN?@>B@f}X8U)qUCE|nCFK8W*mmt87}tcmH4 z{O?j=iixlPH!9J2is_{f5Z8Kcw;3?HXlaFxoAJxsbD0lj@(tF^cw?nL&zTdlHJq1_>4sDXpYI>VZbc_*^W|l5-xY8gwD31{Bttf%M~xpfp}z07`kJ zaC&1t!Oh4;@n?EK-yZjT7p zaZ^LLF6b7(=puEOY@?tj<>eHlBT04I2h=_DE*^i2T6`Ck^gX{cvi?`dXH6V!RgC## zn5Jk}^l=qKn{X)gZn*LHr&&7KjNuIc!z_eReyOsYKx1V*7wU?f&x6(n%>$+WB_FgA zXaOiyRv~B;Ih@Li{8VXMaPvwd7q2vqQKfNglHi*vFj8}z&nPf^yu=)Hl3glE0nmOn zSa5aag#DhvuM!hg_}C+JQJ%dN}LPRaEW9Q_f%{@^N6y1vED zV{;e9zRIvxSeA9zqlMcXgF-nUHDm6g0_QPWBCYfd4AW&x_Fo88O08rTia{5p-u!&? z6S!QG`Q2mW-h~9@*wIdM>|)1q=|_U)>oh3OC3jIiU=vxz=qhs)p|wXIgS#jOb*^}Z z%3e|h){|6S9FqZJIoy1G4=0bsT@*{hVzJUJVCJfbL7|+FN|U>&GEcqji==pSDX#S;*D(#QsjKQ&)+=+!wNF+i z@Ve#)DZt1s>fX5o?ji{txCDBKP*`*YaKe78@XKRx7sa3{V6;@Q+jE0o#Gp{lNA<>C zRBt>6$xXyGgHfrF=vyC?Wh{6vkta z>jm7V%a-gcE?Z_X$+d@{bJun%YhT- zrXd%P!Ce&NMIPfZTCIacpH(TOa2H8g#HCQ)uK!)T@CH9j zv~M_m{N5&?#La8wkP!9M)+ zjBD)veUFl))mZiG7jL2vd z)?&))Q9n$7Vd{$9!(&GmRBdVV`p^%~y|u7()#8vv$**=Vd)jC`d*P)4_twlle<5w& zu#vuB{n6+0wxHzopU;{;?$bHXblMQ$e|7z3_YLokQfIAPG@;9hr*r?T{Ab9CVXKHIn6yS{cx&0jZr{v2LibNZkW{ku1N++j-hYx7#eel}kja!CH%Usm>`5#M96rMS|WPDcHfSk`RxQ?;A zS2=cPpB1B>MvfkFbb5=SW0QXvnCibQ?!+@Aq8q52Mr?CG9roJ3H6MDNNn3a4!P9H{ zRb5yWvvJkV`x}zCw>7re^77JipLFuw@Z#%1SqpV8or-QYxH|vOQS0A`2pjkI+hctf zb(nhjmET%yu1b&!e=TVjbg5_Ptt+A9H~zU`;`6r#Cv>@cF7D5NlCJI8ck#;fU7Zj0 zJTmW8&7q=sTTccqn{xEZm)(9CvGU&Ot5urJ;SUZ^Fq~PK+;v}kT9>6xFU&O_n31^Q z#r*1xF_VTgu#f-QWp7My(7Zk``9}4AajKNqV{G}bU&Ce(9yltz|MJilZQHl|q182M zMaQTXqkVeEH4XYZ;dGad6PNW`Hhx5CyHkyoiw~Wsr@!)=s^;1d=esLiUE;p1Z1l>q zB~9DR8_>deNT=&x#9aM5dBTR<-{xlBKj!6oF1^R)3p<*xuU0#b`(w-Yr@vLKy>R@r zVa<;@Z>N3#+~GER&Q_i)v%k6O@Tb+u2WFJ^{PMt}nlD_o?AZL?2h%scbFbS+jW67L z|Ld}??@c{BW%a(~pk>cbzqMlB$jvXe>{Gb3nR}Pw4eCD^6g;zW)^7jj=f1J%#Zi8x zF~e_t;4~;~%YlT*3k&<*xEJ5o_pB!Bt+K=6t)|bOx->a_W_%wh@Ak;@i4WBC#`SfN z%39)YpW^+@-tFu+kfqnt{1is z2n9S-8|8LO1t%YzX=^z-lT=^*DIyV6>AbUoN|lH zI(BG$r=O-xyn3em(5hc1o=X1h<7;g$dt5npwZ)ffuD!o9?XUcKPv6aT*e7me27xd>l6UJ`d z@%_}ot;$hBpKT7iwTa&UAIh5^(=NZU@_15p-uhPFk%d(~UR%5K)cF@?9O*hBT>s+2 z+5Lx&I=ijIEYH=q?~Tbi^7QJ$7JuDep5xPF{+A7x^>;ZkLchz?VfDtcJ=?}?+g3Pu z?9{CJpLx&!JM;YVr*)^BzWH`jN#Czeb+?!2-?(`3PLH1ggS{L4mT_ce=-N{o+6Arl zx_fKejrQyM8~)DJ4|u7`{PcmRmVa(2DcqZ=&uUUoSpELG%{L}bt!}D%uY+{@?4Tom zC|*6)!Qr01lAi++D@#QBsh%kF=gzNbm~7Y@!1cTX+%Zn^FB&9Bb~%yIGVFeJF? zhU#BWZw~1?KPjfVPoFmy2bX*lcW2SGaGJEyuuSSn4&noTF;i>-j1HOL! z^n%$DO3&Z&1+WO=(?*?3;v%NTz4<)O3pgv~kIsmn0WpsLnm?tJ^t>MDn4?yDzV@8P!Q zJLy#qhw=pnPc6^bs!E#iTyCpPqdu%!_tMOr;SW~N7}4pgtDW8%(j2IZ+e+kJG< z;jekOW=D?*TDGhtGxyTqb(x`^POa7a*<|OBUiv{F-Y?*u;ULm z&+HqsGk@_5&+Yucb6I$+v$GeETphP|{+K}pgL>?AEWW??#LDtknbV};?H?x{Kajut zVDtJ_4joUn^8Ckf#;pb4@4Pzt=cd7b_Bh?D)z$e22X^Ume3m}gbIU7t9MYoJUUgrV zacj?~BXXzYEX(|0$DY~WB|9urH=8=B`@U^)R~w&S`_=*Po&D(jpa0=$h4b)D%96h` z?L0pjQ*YT*+Z^4hkK4Z*rFIBT+v~iuqJ=i7M?r&4i$BzOpL(zU>KA4@b$H2LwV};7 z>fDMKTii+;;5lP)=u>xk{L(V(g^SIqPx&_=(`I@;@QC!9Tc5xGaVa0( z&UMgJ&onyz$={7fM7`DIY;}Zt)uP6s8Ql+eyL#Z=;LP-CA@^HP>OOVh$31RL-Pfz| z+oyV-{;TrYq+w2hr#7Sn^;dk+bx)s9x`bbTF5qBGW#_n0&-gDIwxV5=zoMRAuJCKy zbi+;W1(zSRQuk@=HT%=p)($OSX|t~T2%k=iX18CPUhUiJKtPAh3xhiaw65~o_H9YW z9#i{2Q`X9NVpQp$lfIe!W?}S+-UUA_iGF@$uf@5?4&KfiJk~4!cI4H`GcN^Ax#^iS z_4$qSU-4>BztY@8TVd`3$cC| zU+T9$VrYDKWn$m$AJ2*DGU7_~XE&eKdz`!%zG6z7-tG(fhAsAbS!bW|MnuseU8Jg~ zPgLp4*ZL$(*_`n0$*lgPy&ML9x8Ur6*h8m=9?EbY();C%L3?}d96YYY^P~URv_5HU zMA@jHFM1>veB5yOpUOkSUby+rhzBEH7-$UFE+Lxb!qF-%4aU3ez>_1~@;f4DyB zY5Qyc9Gh@s%8bwc{5|BWo8w;{d+S`X_V4tszx}J?kES*8;pPAA+p_Myu37Gb6Qicy z9(aBAo$u`r-W#>f?QZh%@Na*cx$IQ-i#JYOYS-c9w3Jqr_YU7Vnist2_}{PSj}7~L z-giGWAANer)vn(k?fu7@2!~&P+`Yd0Pkj>ypFMo7^aq#b2M)gWx$B{)dQU#^f4F<= zxGJ9SfBar9c>!rbML|U*6hT2j3@)L7C<=&$A|;@dl%j|zir^KyyBk| z!o=ct&dlDuiN0R%&+GC1<2SH-W}kD;nc0amv9o&@y{H2`6@k6_s?H`>^h8Vf#rygWa0&z(6>Oq6C1e=}m{8^P{b z_M5*>*{9kjx68+FlMaL~pWMo1UiOwfJts61SmdmG^K+v5#kTn~!e8a7F36cW!F7<( zFthjcIpujX8n&n?SeEZHZDn=Ls+L1`tlYNc_G)W2?wZ4H{PnI?S2pZwaA=*=-iWme z=NE1_>zKA}{w33`dJ!iJCs|zD$jdX{G<96o7VXRHHp zUiP6L7X1&FTz1&+HSXns7eiX^O02Hk{Y-8C&af@Lc6_Sx+MD9GY|r<-pNhscXtfX9 z|GvfX_ikG?Je;s=)KC?_&zZY!EL?dn@?G(W-xE#w3t!b7QJT`?>W=qbkv7W~>0C3L zyuVlSfEzzmT*8LMJYCb;@T=jz4BIg(^?F=b5wT!>ScOpU$FzRqeSUN}b9MgfO?!XW zYtm-Um84~ryGqsa6Smf9CO3*0wk_?l-o=t0nff2Py?oW}-lX<13%A%OU=GC*gh{VHRbp0FNr?tOLn(BSao%#`2?MS5x*Kg z{V?;m(Bt{4PPeCy>(^2}?9q{^Bhz*C@4L(!&+Y%wxbj`>80QIhwfnah44pLi*yDw- zTFmgAwBVaXJMDSj`pz`C{FtAmJ#D{6ylb<_oxSfpD}3HfI5Pj!PrWV)vo3_H*I2!n zJ@-?t`IEU02d8@v^wbJ^^B^oQC$9br$1h_YzZ_As6to=vz0JJFix=u7b^G|CdZ6cs z6}dLIUp!mpF}dT<7H=N*IF`+8q5U;t_JYO7YGO^+^!k`K-dvz$w%~5!iM2PryBhc{ zcs}m;qbX&P1%p;C*6CiK6TW2hE~6iptVXxo)=Rgf!L@NsMh)X<75|K0y+!HiQPYKa z;mJ0&N~d zUt=DoFWyr%R>yBpMfgmoK%@5)&yH^Ovcq@#A%zR7?9Cocn=-ke_p>KY_x8!ii|u-@ zRwJ*^?CVdq>z)mA8fVmT3O}u&ar7qt;6{hOollRRpT$*cS{ZlOx8d8;U)ed0=Cu7Z z)?(wL4PF;NxK{@)UB2|$>)*DSxy{@rDtGy668m`3<|Y&E>{Et#7k(a9+hO6BS(D$L zvoxD%+_QqC`F(8s&ADeA?rR=6YJ|I!+4RrblLMACR%zR6O3d5t8Lz6}Kbc~;ywCey z*5{VZew|&B9nx@GNZXA+I!$gn|Iyp?hCc@cXP9@Wtml@U6|uC!L^C6J;;?nj_Ijsg zY|d;@8T4Bv@Zy}?oii&BOnsIgb>Ow>vU(#&3WlCgZF+OSh+l^{ysXgdJgIZkjE{q_ z7%iW$JLOBH^2;UrhYzZ{b^rJT<)W@U6Yjc%lZnO+*4`>e9o_J>`tZV#sG<{Z^>3u6 zj^~?A{Z)UX?#!~&tDkQk={z-EcgW*88&1yfKb!uoO;**sk4E~&?^frHX?MP(cHr2R zLuX+7FNoImX?UsO>;)T*@8;xuGOt%z6T8Uo?Jh&xCqGoxUJ8UmE7eWUe7rhq`|rh* zCp8XJf1+!(qKDc?{Z{;gTJ^5vOo)A0R{!`Jy(Q~U^`B8-xkl-g?W=k2og7SBIE?0N zxRy*wXfM<~-L&_zRjnH2PrdY5`Ax}|IbPS3nl!uRvYi{nYc?##ckjjVvz#|2-)c2+ zR`XR)mkw{=Q@HbxP42f%s?*#p!X{|$K0Cj>%eEzpY$lHm-|#ri*4{V#{gKv*2iEB9 z%eIR-c=kYXp}ymWm4nQud8{ma-RosXj{$A>SphF2JeD2vT_wV1&?qb>ddAr0?e~Uf7R@T4zD>v_c zJ;JV@`#G2Em$o`Cy*uS*bnv4)cE`OheD-Tod^kYcWb(t|M(4dtl#EZU(;0Gkdeyp+ zmlaj#1YbIIv;2`2#Q$*ecKpwRUZ-9MpIH6O>}I}7<-oVbHJ`0YE=_T0r)Y|X&SCwv_W5RoAzbOm3F|@GHiqza)ku?>^ zS||8y{PM(Z-LYR<<8qTmBwc!bBHD2H+Tnw&u-==0C-;)*S4co$DUhzZtS$S`MR_so$Z%gV^-&GE#5o0>4yD=PSXax+y6Rv zeH#zKxYZVZjs|KU>MbAov%AKb*GngDe|CN5Bo({HPt>EQ_AooF)=K}g5y!-TVYHE| z&LyS$6F2J2ou5;c*r>9?a+=?lUtHTCd(1SN7tBtuJE?No#Vl`?WAM_cHw*RN+^Nj< zy3kd#S#f%UdS&P5#+FXz9WNg;ef@po#RXlej9;}|m+fwmrQO21!(){pnu+0o?%&Eh z7o`>Yl!xVRwymnz5I)vt$AK?)N8VQ|?emR|I>`Hdq3~A9=9ROeCwL5h^{iL(alHn7 zdv6`I^R4Ezyok67$3LB%-!Nm%lEC=9(HkGVORE^wJ-p+0^Td=FT2W`CM#N-SpBO)A z{Muyw5i@4JeD-4L%8_ouu|Hepw(Y6xs$Lw?UeNDc)5UkTwz_(8$|Wn0MZaz>w<$lVyEdn+Y`AvL;F5;@%hws}ot*yZmCwtXH4g-DM+aIy zalrOJTHC78`-Z*S=NXS~{m5x$+(PHPQMzs34~%JcOHe$*?e_j*F(vjRb>DesI)5@B z@@Q}Wz%$#*J$K}6^jWyDLz$q+zcjY6v|KOy*nO8JH)|{IY_C3hyyerKRiQ5yef_$M zn>b^ub*kE-J_E)VWw;y9UBydWlyCBU`Uj^KIk)X@=ex(OnlwDcdXD~(KFd3Lxg371 zEZA9Qc6R-)wmY{hwr=oPX=m6wo6Rr31x%UsdCbz9o2&0nxHI*%#)azFBa836f9t_} zFu#}WsU`ygUknQx`>|g7nqBE*g`0lIeVmjVc6WuHm4{kzixH*|+8Q{l@9JuEvGJ1; zMY`vbx~T0Q+>O7a+b)C2Ead*Ts`**&A8Ub*$m3h(C>*l=KD@5#4M4*PYjYFyfhxxKY79_|rU70GX0 z;iot6i({uZKTKPC?V5C~^RcaK_intFe_`Fv+3TiQT)jV4>rCHesZU$a4Ea4`ap``8 z1@G1@$zCx1Nx`vs!tK%5KCbq^GHG@AR!6^Q)*E(6nb&LOG{g1egsh2v(&Mi0l5QXSe2lc!6~^*3d0AsE$EE~!u6#e$VCk>b z>V~iGw1|6N-9`D7&G^hSN|B!)j`5jxB_P0JNm*IQ{KuECO<4SM>$F|ZPi`B&{_q<2 zBaVAI&h$H=FXZpezmR-%)s63)ZvU9L_QRuBxz?*@3%LgyF3ngFKC92PvRh{jcU`a0 z=~%L;nfs-kE;essM+ZC-MBMr6(rfj1y}q3@&W!a+eKhn!#KN9?6LtjO_lq%JCvekh z9qin+?;zcdzx4A~Pc~b5KwJIR+%%QWSVpzhg zc1=89c4^;#g6Z1^HF~F&MyeidqoFz9ag}?$t+)Lx_x0&NWU+PM^a+Ad+lpPrKnZ%&+_=il({|e^+gM^zr2Gn99S;bzjb%JY#szEnlOfc8pJI zyi9GJQ*L7Dn^NO|Q}XMFKhDVew+31?m25q{vE+cco)sEP_vcCW9PXC+gbm7lc_Ut z=kq47o^5O$V3yITqj&qCU0XkR({IeI2k&y+E={?n)1uz@WXEBJoz)%$Rn;%zt+}y# zSdY@X4$7Y*&Rl=0xnl8&v=iJbjpz2NSQo$I{e_O@_Gdz!o32zJrEl_KJuhkf%hQ@$ zLvBX=FsQt%RPuRu-vXy1`zVVC(Kg1zmj6(#cXp3?(!4efCM83aR=VyqI1~5#>IIGZ zCF_O^_|SMm-lMelrTm`{4mO&b|JkZll7)+B%MmpK_na5jM(6L&s%l(Tb10x{%JZ|o z-tEY}*w3fm!>&zC%sP&JUoW85vCglqC$yS4v1!!X^46)jQ^LD<$=V$pZ2fb7pr7Fs z*G7Z(di-YT!|#XDN-&PcLKiw<*ZW)<-5ZjHyxX+@hFtUkAY z~&`gd<%(@#$arLNf=bAI61jJ4X12Uf-0+jzF?oFyYqyH9N}OM7edh51Kx z7T=z}FG79AL&xr+clvDawM+HUIDV}|T=>SU+}F9h1v!`f*1B3P+Z#CkN?LHkj*(q@ zruEC+v$osYC$ERjJeD-_+l#L5ZhCJ6t-7t6)4I9OM6XoUoxcihuAFyg;WXp^2bPW3 z`LeC_OUq;1SH+Cqd@?(sWX`3*V}>{J)9>78cwAW7SmpMUy$@ds8gOl4qeYj0eat(s z`S2lbVEpD-|JCWc2Nw-n?NnhstH9)2_EZ0T>z5d`+V{~j zVp5MIyXG~2^{cPt3?t88w+4>-(o{HXdHTsUPcujEDzNP`!RgAonS&>*Gtna4__^6e%p0JkLjs%KaN^Ad5QU}ME!aTvc?R! z)w5)!M#$!`-Ii{jy{(}1RK?Npo$R+8j~JgH+o5tHcj%Ta2NsPvc=@8!m}^_^k2w5u zc7J6R51+UIe3;59ySHl4+yfr_hD1HCT9MFgc;8*m9W-yM+&`|lHn+?DY1ck+ThG`W zc`0J({siY$yUUJ_NF4FhiJz}gd&4T=+=g3)+_4#7LYpjUIIpCmAn5G!(&a{7mlh}8 zPvURQwEa9LD5LB8&&|S47+>6CRy1$8p}xV&GrPTi7xr1}IP!gM(}1MV*V8X6?|t3w z#rO`hcOUK4-YNCbf&`n%X%im}xOUrY#!un(z`^Ch_QyI2UNwo%t~glX+quy}!~QkF z4<_~3e)V}{wYjy%rYyhLUVCQxHc4CZcHyz^{wFG$6}GYct(AJs%EGeAr^(~oW<}4M z+VgZ-k8a_96BeH^epuV|hf(wFmF{aF9nBjpczUDp8V%FqN&)xF)?YKOuQtOcn=FFC~kAVnd$W0C&o4$>vO_EqqfEFJCb~+Dxc?U;PG&gcjJR&*WMg< zr?!54R>r-Z51UQA*7>5h`qFv(9_%R{r)0FWdGyz$mxqFFt#(uwK8_3ga#&+$!}ROA zf`~6OD>m6U9Q^8kHMsMfWbK~|ZwT9ajw+97I2oKcW>xZ$?Z8Sc3@T6 z{Ani_hV+g)q2x5B&6$^$sTz+bR-fq7eABW)$G!SZ8QP>>Urt6%{;Fmhsyr^n+drPS z)wP?!u;$7}Lbt9@Keo89;Zl_oP_bv1-sv02B zA3kTg?_AXB5fXM@+BrkwJP?soBQ z#Wa2YgI7is2Agcr(tbY9BDD3Y$;v4wqhA~_IlX(dLAcYdOD7VlHaDGUnVx-nXb*JiDr&-B`Icbklc z%Z1H6f5cv#-tx@6gTc=uOIt-l>{Nu2tcE^1ah3`i+ zFW*-0c&ErKL!)sYK`)Mx(ZF<{ylw_c{#&{i-h7nv6n9#4JUWK-g)cp&grvlTMJ9%L zMx~5MO-u@jj7kqlNeCMe6_Os65Sf@90-py8iHi+KYL^rl&Po5WZN?k4MZ}vunSRaN^8?d$)97w!QRV#ij3an@lzBTNKlCL9NYbkB@u8 z9#nrncJWyS{J`hasEo-I;ykZZ&+f3q&ny4Tnnssq^yD|c+Hn4^-QRL`l{S@)H*Kpo zHZ?1{Val#E3kxTGYjAUv;ili?TlkkBN_*jReWua6{=(u~*S_B;JwJc9R`2xdqMyN0 zwu!CRF6r6RU;Du9lWj-dXdVA-$A=epjvv5cL(*>do_+9SO_j=i%lBju`HNXVGV z7gcK5))n*Gau$Yu9yGu*{o?$a3q3;&KJO|tE=uw1@TB;fyTLr&4sR;H zWgHn2e@ESl^S#}1*Jg#Y->mp~Xla}J*Zb;ioRv8K>NDHY_U@PGRx7{HYFkg|T|vMm zhp$0>J4JW(Sg_+_#g_U{Ms_+IFi_9=qsvzJFIx>F%j%YPGLy8n$lrQYCut*Qm+qiNQO} zEn7Ibj4Zs`)nc)P4#k$bNX54yHYP@ z;o|2W+AoH5K6oT{QOuOb-n@+B!waw5nY8RNVB+&r4#7{iujz9+E2xpXam|*VPqgjE zL@zD8mtWI75HRiwA z9^Cf$yLb2cmrb?09k*{~d5_Om>hGMS5;wvB;rfm9v^Hd>cUDR<4t;O+C__i!KPdF9 zr}Znoar_jh+fRmI7EQQJk=@x=x`TXcyJ&&>3^(0*Z?RbF3;e=i-nA?#P9 z&u&8|9)0lj*TNJ1<9j$(=Z(-zdevY^S(}}%2R|l17RgVDbvhCeI?hoPUqs@_N{ujs z77>@qukrKOMDGjjv551z`J=5LooqfF(DD8(*tgeq)AW&|{JDJAvwv*bP0b#WFEZO7 z)CnH$s&(mgXPxsdBM)}jT2WIJ)F0>^N1b3H_yP)#YXxUa z&)9RP=E&>8p)QY$d-PEwI!!q}Pzb<-+R&XjHxAz7LXDF7QxC3r+%s^dyHxR&dD(o{ zAw0Ny6iYWaW$OWXJ(w#zZX~Ejjp%gb^ymR9PLJlo-f8lB@P!Z_w;ax*^ytayF_6;J zE3PFJj_iHmPHE};GLX|_M0kSXjIJPfR!@07^&y1E?G5V5f{ooxC1w zRnqy~NKOyFd&A>m%}2NO<#V`E*?evSA=2q-ET_ke@L&$0ySi+cf^s*95FYm)oJIF# zCa0$<;lbVAXdOELT8R2OK$rRPYrgC~PXLwxP^NlrqMZu;h`TMdUJRzV*)ZUxR z>1jcDMECWxpVLiwJ(h$A-whJoR|`2kEeQ{{4q)Rn&YKHwF`!SfouW11aS;}kM@u<9 z)`SP|8>P?c`NYZVu^~Lpz#yuJ)^d7m2@mdx#(X|>xe;WBY_E2pP5 zptO!*nxBuW0COd)$Byv8s}IbtJmZ_?vi1ji93B_nE5h_BTj!j6^>JVC&KDMQyr zP7gjF;Bh;^8B_6f@jYlLvgv6{c<@~aQ9e7!>A_`29(A^eVapA`$NF7^q>!ypm9%sUn2{$ErI|6^Q zNxDA;G0@`+XNV4b?ocIV^QR*TnFg?^{SM)&-1$KUdLx@v5tw#%S%pAcfy0U2+O_4rzOwi^>`B=eDg;OeCWE%>G1)S2j6$1 zZhw#xR5jWB!BXIHufbVVUOsYqdJrCb(+skaGwtE_H;jfFMl~beFzWs zs_0T`LZETW>cQ5@<6^%fDz8374@zLI6FDp?9Ak+cMNGv2DNXTPDh?cT2EjIit__P| z%Fwy6NF)W|!%`xtOa^JmA_WX$%_3_U#D_(8GKd$86f=lFi(F!m?kw_%K|EOG9fJs1 z1g0m%^0fV$)5&UETIvp0_(ZYsrt%yp;kU{iVq$PuBvk3OG=nPl{ zzGF$85sUO?kVY(mA6-J%fJH_zh%t-62Q`S(WD)qZ1aUk-uoaV!Ul6LoBJlYN;?!8A zj6rN!Ed!y=B#0x9JkSZ?pl$yJq#5fX+8@H>guO31il7faGljDO zv~^UoJ)>HTI54WwG83M5IATDDlpt+Iv9}f>4x+ng$|9nfNpltv-8|Y4qDKV4ED{mB z(UD=PVc-Q92#0tUFl+np<#a@ZVJfs}DGvvhOIfKPB87bgvP2G4pCOiN%199&skr(Q zDML7;D?Os=L`QLWg`cQEM|h;-3I>$N6~)!gs){F;>c>bC9;vwc5h;udS(KVpMv0|H zGE#&`Dz5%gaoN1_z95z=V5A6-R9pjylr9t3!;(V>#ZsFXDZ(Qa*FdSb{3rVPilt65 zQiMk;E}Ykh%WKWX+n;EU4=|^Kks>@&afL|56`Az2N-Xt_ks>@&aSfJ>i;fB~u6j&& zMR=s*8X_GR)D5vzOGb+DNW~S(N}=}3db>W-kriHbWuyp?R9r(LR9rXwN9>l6>c>bC z9;vvn>hrjwx)F5g!U1ty35*osk%}u^Dy|1<>+Xo9rZ7^3M=GueskpwaX!1)ewUUt{ zJW_E*O2yUZ{rp>EsRN7@;gO0fib#pZ2*-k^52d3WfH_wfDZ(Qa*D$HLa{Mme6H8Sw zQiMk;u4t*a;_pt;q$4zpOGO3G@B?{pz#5~3-H1ViZOiS)6~~FCnlMs?M=GvZB4q++ zbnzAKw$s@SUbSbW2#-`;!y!~0*VK*8oyAhU87aae71szNC7LDZ?Fk)EXJi;xEF(pD zq~eN`ifeh0yQWxb3L`~$q~eMvQlfhJeRFEDSZXaJMR=s*N|1_coKlxCvD67hittFq zl_(Y0ir1}wiKQMhQiMk;t|Y0r0uGE>C6EBUC=F0s^7MvCxA#g#4<7kA;SRI$_{MvCxA#WjkR0uQIfg#j(-$_ZZGVWbF; zR9vGWRGf#V>5WyzQq_zU;gO092Uya5N>g@LqM?Q{!jDzLA>Ee8Ai}ogL!WrYVyR|~ z6ycGIYb=oxwJ+?y=*k@&agCFT>qm{*2p#sm z5*aDNBNbPcR9vNgwH4Xv5El?BjyVu;MU}Os)Q9Isj1=J!t*-`Q$U-<^ zogckY&JI6~-rkX5i{K2;{+N-enC&%a4GoQrPYNBD92LcQ}dsr4alz1OkY%Av#L-jxl58 z*bq#@Zxl-ii*JT1leirUNZgPFApWUA30+b*%czTqijaygDlvsbk9QVIG6TMv58CJ* z5i}ikg2g7%Ql)H(2~f&uQITTFa7i^%I-`@r64K(Lk|Y_}UlGK_5|wyLNEGX%RY{aI z%qXT{LlaX%!xJMjLZe0}g(XCC@H#FGYFM-+l7`bHxS!+*$-JeNCziuhR4fniH+C(Y zTqLg??AviH(h^3+CPZ3DWGP$4EyzSnage;2s1?Xdu^|yLVX+Ao_L3UeFdCQQFe>Np z2RX%Il8F?z8_5Jppt8)OnkCE5;<5rvyOQM>!BRJm@rnYZ?p!i}O0=c7Eg3*16a>g7 z39B4w%d&|Q2PhIDwML@wF>aI~xTFAWa2N!}Kr#;L07W9KVNfI{4wT9@kydfARNl!4 zOXZ+^uv9+E2UBTB$!bU21~F(%y6X(4(oTPtt}~cQxBs(rox$=MPHe7xR#RA>otk8M zeg>BpU|WSmwV^r6hDZoujghv*5>Y7#q`5(jgMwhmTA(19N>dY|Aec(m87!4-2`ep? zVo974khS6rzZ@*VE^Xu`1Y`mvL?n6v34TdbBK^!5M$|`0+<|O}CJCG3G@zalCX zNla7}k{IP{YaxkIK52~dwNt<+jZr>F1$xU204b9F)3obloNQF=9wC9A6n8yhdlP+k2?w9w5YU2V&1Au##_v zSM+JTo36Y*V+b2yjvQjANZ)%1PBQ0khBl>qxCEp~9}dWuGCY)1ar&wta2@c?YDT&0 z(x(r>7Z{#D>BICr1inkn|Ev!eC^aoankZFtzxNazq=SNaTG zU>6)5=s>-~`^BArFevAA?nv0kZX-qd>O*h=!$Ub0>x0iEbJhUg23N{e*ZpGEdjdR~ zohV;j>BDEzM!?g$Gv%wRJkV6l0-kLQA5=4i_v;4wN`ObH>!0??qu^ne3hUHY*8Edrho?v$^t_S+wV$9Yg5(OFS_2?BlBfzKKf z0In{5XrK2oJcJQWiuBzA{5`sNLWyoLi^UFCuH zc^~i`8$$W&>VF$RuudrD5uFv?FOD~?fKPcS<*Ms`(LTEYPYlCXSNgDjO9q}{Vc-E* zS9vssurlCz&hSAtDa=1Ni0B9KxJID1y7jpO-wNQVh@^aVmB%Cqs0E&!7|KWPOTqXQ z?Y+Tp_-#%&(1Ch|=`)0YK;VfULD=dXZ=flC2s{>Xl&>y*Xz%TSCpVt*vG!SF#}kHN zx$7rT9?{uN*WOKXuL9!Oz8V6bCBuvPLiiNu^ZbYU{D80jKhT%{5A|gM-_*b8GlX<+ z{D=Au1K*jy=)-(@_7C+{1K;nz=)?4xCc-Z_z=4j|A9WGB$1{+>*E7oeTJ9K7X|5a{D=BF z0iX9@^kI1n`-l3*0AKE3^yz}Wwf|7x9^fnfi#|->gMX;68u)(yMIZJbrXyjOI2`EM zd{$6j0)S_TET2qy=z@++;F%`Nr$FCk;3<;jlhKFiy9PW}vV02k@spvxz=4jv4;g)! ze~!T8Ez74s-!R}wmgSRp(ueVEg<~eegV*TXIKADN^^G8kz^{3Lr&EgPic+#(BJq3= zQT$oenKFFX8N%vL8&9upg1&x1em?FUoAnF~_6P`SCJp-gdG-?Y^a^Zdt_-R^pgK5w zIb1y;|LQ{liQ&UT0;1sQTuM|(cx>vZ*pw(cz~H5XPI{c7U=m=nbt}&NeB5+RY0ub* z`T6&&XPl$^TOBn%5wDi2B zAZK@&VyNpi2OfB!H6|()e?41WuPI!Qf@QO0xHf|8#vlYwd~kJ7^cVu!Qh_ZhIXNK_ z*t8inj276U41q~-pi=^Q{28v6;8$k+ZNaa@_}_vbf6xngYQS&6_?4i$ZNT{Zg1-^t zj|G2I#{UKU%^3f8@P7h%d_fkx9CMzzrccScDI|l~a$ThrI1rG46@4t=ZYj3kIY#t-f3dQ>{S4=Xs>jUX$nc2Q?pgee&(@ zl)GI0>viA#A=VR$ZAtE$VbKa=Q=kIt9>}6;3YHDrbyVr;Ewl-DwRK4JJu0>MEL$%!=z>t&hxulP^ zYY?&jUG$Rh>yI;cm6tVsw%*t^&3Q@2+3RU{X8(j`N5VJJuD9!i`(rzgtLe15&Bd$H zHhqG;{jZq^U7y<|Y{{j#!>~LAb5?WS>ff`B?^(J%_NX!2)T^<|Pbc-ZCMD~~c*Y-i z;#c)NV=w%i4dMH(dh&kD6AweyAH8nl;hN|D(a!LVP6z#Rovfi2^}Cxk0$V`%F070k zQ05$C!nrtPVN$1IfqtnQd7GnbuN}5^RJ-r>rW*`#V2)tU>uQ$u_WPBj*;9PZEVeP9 zd;Y}7JnNmejxYFfF*WDa6)QjZnIOW~WYg*=Hi^{>3p13%v`TfY$~Nsxc3IqS=_bCu zcB6(>`W((jXdh337Y$qQ;F%5BWv~zT{YvZIs013;Fx0D2U~ME{Bw;u;hps1seamYLpTd zr$GO|PBBy%=oS=c`tMR2k(dyXmYf`w5RpL>4c#1$=W#l&%JI|d4CBhR;1|FcOp~*b z@$t#89^;ahCg%`f=;L!dg+9uD!s9|86Hi{5@VJ*yS5VML?f7?|ZHcFAd6uD1sT*hm zUHR&QQa60?!Z{%j9v9?Ps4eo!_g2n%ti~%j{*C7yaYn!^@!@*w3i3H8V6Z__gg>C# zmeZZgFi;CRSO+Bz*I^qH-FTVJ4Ak92!y?lmU0w8W)C|AY3nP1ho-f8r9Q~zs{4|Lg zx%P)4d>1mL2VUsd2)hBp3^P9Xy*lv^%HyCMej{F)quE_mS4+Ktsy5G1Rar}gr#S#% zHBAMoaLlev)Y)-FzX8u`m-e`cf0r2}st3RJizR~h0l)SOGaLHrzc~GXYfLNqP zAg&@fM{XxmMesQhy83XKLiSN7RYe^BP)Cg6SDeL#j`^<%6DlZS4fwUxUV5e+eO9MP zH$x?g5XEGR5X-9?SnVamFs)czFs|oVF!)F)4)nrrOOoGYP63M9594bl`_acIZ*@`( z7yKz!%=qXJXH!h5Cln|bD3`PC3fr`7reS?Shjq?^y+LuNks4Qb!_t6xwm8#pY6=;q z{x9l0iu{ud!*t4Km=gR*HNYHr#XB3*59LHMtQh>XzM_w27{xHdD27=?F+AhJ=RkJl z6ss)~87Cf>&ACkwF8lN1FkK)H%~W$mIY)k}yY8&hm&!Vv;X~Hx{fn$a5k*-C>5;8& zm{!@``^{9hTA;+#GP!pQcxmpTk54Qw#RkGP#fljpt!@P&m2sbZ05iMLpCN>6DX!vi^-hhh>@0zK0ap< zoGBK{`1oY~j$%7lOmN5?{GPUV1UWyZ$+AX>ClH=x5c4c!ugPaq^#Kl0Ca=o~Y|dVN<*8XB5T3hSBe?oPP|$-* zJ;LG>`)k3mg{sDtw;xB~PS9a{s;{6>ag!P3lelBnm+F|0z_(G7WIJPI5qHK%IP*Bo zprRwj<*X*L8NtJgE_%&~KNFd6z>cAyKEbv?SVQ2bphH1s1MMtKsy1&JLwEG z5NH>mVL-bA9R}15DBc~6)Uq>x!k8>O7btw5BYP%LPoS7j-aw0hqTYQ#F@7v3yvB~@ z035V3qmSB2iVa{w`JB-#UnYx9V=;`4%5G+{Z7g=0#bD`-;WLGjpmCTpKD4_g-onc+ z+)Pzk-@JwHx(9HeV&ki}VtD~Z{^ ztR$iy-VGDMI7|~(2(&Ja3f5Dr=}=%Xf>Vgs2_ zJ_joT#fGyOcJLI#Du_Nl$2&j7Lftz*)k4=hKhwhGm^q-H!ZO?Me!|N+wP1^$0w8n{ z_ECnRJldp!Zps4J;!GPsfq=0@0@wFCGmZiqn2t34cE#R8R4GK2LQo0TX@G8lFB&Hv z7$-qaje1s3Ffbn60$*yJ0MgCsh>%i&FEvg8nPjy@h$k!~#t9JfEThR+QuPp}#>uAa z>I*P#;;DnLkJfBM{oOh{!R2mp$ zLKP4XGNB#GjhApUAr_rB&?XA18oUSpiv3T6*t+h@!{TZpp> zI=D6E?%{MLwvUcJ(Doq*+P;yHD%hX}KZ&kR53TNP*qfQN=c_X_c4~};y_JbA_7nEjwJD`W&by&=){`fW89SALwhKLx8>kig|}}SR>Iu(;A6B z+G$X1AQQ?bKW9&|1Qx^lpx87P+XcRxaADE%)j?(sU<9J*&=?ukQRw8o8_6M~bQ#mJpSdbo=SdqzY5;cK)EU7w zyRt)OV4^x83YVPa?5b!ZM6iG``C@L_u|EGn5g0h9eHde{}#`MbO_h(p31Q;LWXXAZ*1&WPoFB~+# z(MKB<#jsIP>?F&FogBrOQCA#}x>7An`g!M6nfpY%7rycq-p=_Aqpsh;3d^Sjf}bwD zOmFX;vAP_cNlH)-6KZOI*N)ejaUU28CV++Gcnf=|dqo@SR*xIFKL-du?3nOc5|^6LiVwqP!*N^eZ3U$KrJPe;!KZX(3O z-dh-F;f!NUH}9O2=AkG0!ksLGLz$BWX8~l3GRF?iSe=#OkM=VL(2QiOCk(cUxq(>~ zM?*pN9F-iK8YNdfeSjOsA@J!8uC)EZAsn51ayjW?acNO-EjeFpKt^O}=^GIF=G=Hl zIgY|&KxZz&mO*?xm|M|_M|~(rOdVD*YOO@qMzT|5495D2w+)Z+NmPCyiWnw!5^T?* zDhL24V{+}s6{*xAT_g{z6s$BdQ)h3`fR+TNmW10IxSNv%*-5oc+_nOyQfESQIIHQ4 z+NL=Xr6+ZiUi3P34anVD2hRzYfSrhPrV&sf<0!=_exVp#S<2ZEW3H6Kg!{dRrfv^ccu|J*& zv>VVIpqN>cfQAEw63xc(9jtMa5oiI>)o?un=mwxOfgS)l3n=!Vvw@Zaodfhb(78Y> zfzAW^66k!OpMWj^stoB|1Qfah&I+JLKvx3AE%U2@HU$cCWn*Ej1&Xz39Z)n~`{AIb z3w_jdQ4CEN#fGtbIEkbf+z%s*<7bLNniy;`i*05xobgk>5*9nnVpmw~28-dC5G6EW zCL)rBI>%rtjE~R3`=xvhSgZw$S+kf2i*;wQKo;xAVjIDCnZ&!5@$otDSUwnuG4}y$ zqD;Kd0Wp{kTNPeN;)fK8Oy~LvFN(f1U>_ z>QQk%=SDQq6Q&tk6ZSif3|25e^Ekz$)P^DNX z6Uv7ft%wh8Kjp)&mhzovF*ms?(s`~ zsfB#p@(0#Y8w}4s9l4;0qI{<7_->d$#$kG8bGifMBnCSJ)dA`P6mJEu@xJgHa~g7- z$!YY_oTeD&G{sJ`e3-u!a|^`53yfR5g+A)u3Oj7*p$DBX1PSTh_$nZ>Ic^0Q*1~3R zh}ZFD>NkCpUN*(fcv1>Q;HC8)eY6xPhNVC;e1C&ti7a-B#V}VX-wPJ2 zVlgNyXTJjS?77s_!W^2hqKIVtuf(%HC3SX zuuc&tTUd$kQDND#5|@n$ESGiB!|?`}laiR096`rR;u#w?R+z~W&*IToQD*|Wsj%53El)crKfHrBKrsq9NO|r6KP^x6(ek7imM6uAGd@jD0*hT{ zvFj{W!D5*ER2JJB)rX}>F;8I$EXxbv*&i&-)1C|_K|bp41CuycI!eRaL^eU-iPm2`@fCz^9lz>Sa{I^rV#0f?*(_CjHBo^Yt?5-*%&iaZsz z$3^_1U2Bsv$CYfl(Z!jJIb@o#fk-(s(}@LktZeWs3&guHrj;&@h^8%QMd2>~<+w!j zoKB`ylPBS50z?k)9jgJRq7wslgPTWhcc6GPz)u!ke1TfSbx)v}SN=d-0o?@$tsdy3 zHk@K;!zqR~oMMSAHkHMuvlyBH%7-R^${u8~qb!DIf%2hQpnQJ9v!22$p1eNFu#$kg zuo`&5(_^ec0^4Fw*IT#`OF+t3kgp*SJ>3upO9ZgR0rp|_k$jjU;GOW{`oKOc@uRjE z5W9m+m(U+Dbp7DK{Yun{>ds%bVev?v!O0gbBujdi_>ZQ7~2+^DnwL)Pa7iCuo=a5C8{nWn^Q$2?mNOf;Dy0w+{ts z1J@Bi(aa143ZpI#thAHox`<=F*#rlzH|XP&Pr*|RbCY5bEMGK>O=PiL7Msmt^I7aL z_|C$i$th-heA2DcIMCG4IR3J?3Zs+VeuqPLboJptLrk4yu}d%2OOMZt|59-OZ19U| zz#>rr>d2%33`#b7p^}i{Rvb`l!tp>ct%*P}>o>zevmSkP3me6-peeSH<-=Z+Vsd+^ z6lIPEu%pAeg8P}MV>9QkTd4jp1A|&!cjnlOq5_I(knP^!4WVpg`2iHu_LIpBoC(p) zKp)KvieY9@3^Rjbm>CqSdw*08@W}2g(+3P4Hc9NKsT1eQU$;m757|-;kx1qWra?AW z;2o-LOv_iGn6__Bt`vfw<_h}g6FrIzfNP3ju22kfge9bsX8MW+l$3;B%r zzi)f0qmsyG2Bt$cGgOsmW~c$h^g%djFWbRSGXs5e1Vk|$0Z|OIfMP3IEay9{ZSRCj z+)3b9fP-kVSr~RWc}JAMRwpl^X^!H(PFa$Bopg%MGLIT@uTu!@2yo}p?Mk+ytxURE zUI;54z$_K8ut}C3!n^|}Qn2*KCvzt3F>HMDY7SeIMT-SQ7Z^(M0IEJ*$y&o=5Jz_m z4kP&z{mY)GV)!MKMA@ECde2iaXFW{O(1_xmr`;qnHL`HqjQB+hw>V7-APC)bKtsiQ zo?4Kwc|_9)SYX4E1&)3G(6pFo6xs{Xh`Ww1la8@>5S8>)3};UTfKCPq zOP}NczXi}$a1G0Y*_dJ0Ko0;#y?EOgKb99>V~>DKv$Tezj~YRWp%J9mD3%XrZxj=< z*bElKZk5WSNuYeESnMo|;jDo2-DWXdtEQMe<0BiQBzHpzbaje+qB52zNYMy0?56s9mCv%8Z6e28!T@^So zcb6QQd-KlWBQaf^?s+!9SfJ&M`=RprOd`p)CP=R0%}k*uFna}1wZtYZ6s}}V8a`3L zvF&d-@C|6{*xvdt+nTh9g~7=n7B1|N`t!CX4f5QoH?ZTd1(ssC&EWNK(MBd)g1zUg zf_XV^^TbYE{HzM6kZ2F^K?<%qiA)|!;|P(OylWtrVe3Cvy{ z(+BaKLbT-xvq#c4VoxJ8ognkhVxpOzFn_U8;KY3ogQqi%VGK|ltY!hl%9;(-8)yzt zf1oRX4g#7B6mNYB&_tklKyfiCA1Io_sX*re6#`uXbQ;htKnsBG1v(ulnx(lw&j6hd z^dZm%KtBP+crdG$0>yfO*Vrgg2W^z-qo$H#Xeucd$@0ap7#b+bH-*LKu-F0?L-R-Z z@J#ig(WKY~7JJHKFIlXH#eT6EbP1d?xYFdbWPE&%Gx*LC44;vqkIzX3AB|%)_8cNIds8rm?>_0(l%RqA5#9rA3F`4emOkPNMAow%_UBWj#B{@)kt}6w`otihVW?qtU&E zt^?^iplU$h1Jwcg0VsB&&{)Z{*N;FkZ`Z&<^A>%yp->DP3dI((d^p&m*k3m{K?L%f zo4x`l+T3&n`~`JvZYn~)x;8g?(??s)TkV9+NHE|!b>$K71KrFt4EG_?L0J!F;dOR5 zQ!j#JG1-c6vYn|t!7(3MoNQ@oBHq%ZbHE&f%dWn0%ZvGcv7-rlF6_C*W3^X+$aWar z0K+!o090MR{{3x3Q^Wt`h9(p49jJCVImL}jm_#OrZhS#Oa>la8cHR)K z?lE`(v|m&32Li>85;{S$QwcgjvQr51GE$sQN?2KS?ni^VUI%jU>So+A1qujm<@~JPDRQ$9(A zK0fC(%U8zo!Qh6`cZbEEu^3tfst;y43?IDx%3y!mfrL_G>#`fJWS1+^BBC>f1HRJE zIJS5DZ#N*J`T9d|s9-UQ?G4>TNdt;$mK|YifZByD8-enHLM3e3)YtJIrFmEGDyY2ymH=L)3EMxT6FP zu?>NQ%Dv`+Yfj2=U=`7>t04aWv2Td<*jNEX4(}Zcmj~2>0iQu3Vtzaaih1$^C>H!` zIB21wkG{@9vB69z-Tg?hEEZeD_%z9$cq)rME#<=<0u;lMx=BAlkf5(1SU_Gv@DoM#}T^5D(% z!OU9;`5q?hiwUXT-coNPJ%Av z@f4o&7M>H--t?|5^>O```RcXLAKwiaif;r6LIpzvg9Rb5NGt52+f#VTM|cBr6<3%? zz>=+pt|!;_G(-vux&6H+SEicfWLhM_OA#kMbc%wUIH?)}n<|(;T(}BvWRSSweS_Y( z%qpWj8dNTWLz!~|&P#|7=2zrO+y-VS!CTs#Zh8>FI(Nt@G@0=BHwU+_Q72=Jpbdn^ zM8ze+w=5-160Y!|Ny54U9VGWCjCQ3TssD9boe^124F)AfL`h5TS+I>bO2s)JuYE*&RT5*YMyTKE8v_kXr<~jtju@FDt;v6PyQ$ALju3$@Nr@E9jJb znMkx1G<$!Y^8j(eI567ab7J)H{_1*Rp*MtyEIsZn><`y+y9r~Q z=+7O+!KD@019=VJd`^LbP!xa%gV+wfRSuA z-pW~^Xq{kzEPD>na-b`LUIvQu`71!NjGh1mj8h2|4opY(N1)e%Vn1>N=x?AmfkLrz z?gG^WdJibBpx*}y5BfL{f#T>I^`IRsfrHvn^zk`ESuB$A!D=syjb^cVEQS`9%C2KE zoHtPH42zv-v0E$#sbl!QvDi-*Q-^fY^l33ZK6!JAVr^Lrn<~WyvKX#QQ!JCkVAY?& zV11wX`1r0V2h*d8Z;uimpVLE0#OKfWV5b_3g|gTP7E5HYu`D*8#e^(|)~*C%<8#)s z*hUunuQsdhgBWCAA8ikqDjfE3;NDQ`q;0CgWm7b!T7+AEuj;=a-x#D^RE^utAn?N`?F))ng@Kw0fYA z&JQRy1g(QVoOUvseL(p)p(u2OVCbk54|@LNVwh7+D;0QVfTj=;L#^s!ANy zwn|uYNwr6c?j#&Mjxy_02OpSsz__p)uN)3uaE&P;=TmT|64Zwh6$F!v1DX%(pj%=j zs1GHc6O3!9&M}OHBS?*7=%~suY^$4uVz|5}a%aFpDvzTY2?vo8e~b_% zvDr{5>O(2)(s-PvDoPv`{Lvb4!Q>3343zR|u|BNqR06rM8x%Q3x@#a1bTcd>y_m1! z_{A|$y{HqrPmxokw-y4SEb1t|izF0dp+3A170_6B>0M$as1GHuE0>PL3Q&O%<}jDbWQr6(SWk|72o4TBBvp)~9+=N{IgkoN2t&hm!aS z4Up7V=jc0XarE2Pd$09~U#?zEYrsSzM^7cJH1(l0F5^QP=_qq_A~iWGL43k0lG1`J z%8MmWeb}<86mso{L*!^U<~;SGeru|qVL=IW(ma$K{YrAW@vg)vrasIans(HS!&i}0q}!F~Mh;};!J!6+4jg81fYs!T zhXZSQEilvqLoG1W0z)k@)B-~-Fw_D=EilvqLoG1W0z)k@)B-~-Fu>=~@ZiG1gF_7t z9XQP3=nBVpI6wn+*+7cncm&6LIKIJw!@}QiAQP5XFOHGXz;vIyZU##JTe=tCe3bL_ z1EwFoKmL!u8w?++{{Jew`mijjEdI`ph`DJXnhB;TZ>fZQ$d@LH@*x6-R-maEB50_9 zN?=-=DfmH=wt{6#mX9QwuBa5Yex*w#k{P&|%BH!ZnfX<2ew6Lwv*(<9@66oyz7IZo z{+M^>cYo)cJ7?~kJ9FQex%5rv*_l&pb8m0`W9-Q9>wX@+X+dF|s)=`eU+7p=nlx$5 zxurF}?fuH!PJVZ`YU0Ie-?N97y=y=3a{bJO%JHK{blTas?`PZd$83Ejp+06tbH$>S z`;Y8>q~*Ev|Bkr)`q3NHj<2u&<F^-1Tfg{EA}@WeGQy{v+jmZJcZP>8DmE){dE&zhlYCrHguOU-!ks zZF?@R^-L_hmHlSQfxM3vgv{_f*RQlqeA&&qo#hGDVY@eWt~Yo3Cz+2=eNB ztkM3+wUH?UD}T*)n?Ja{-?9SurVcf&%2dB-sL}@r`&!$d28<* zTdT9CohVz`=}r3}pXTWqF8+CYzS{bHOz&GMmus%&ywlXPeob-b*TZHdex6hu)!=dF z{K%fg$+-ntB0kxBg2xAE{FEl*GofW&W7lqzN<@4r!u)6M^nQ7Rh|i3p`%btIJyY`S zH*1oPx-ZW=7BD1d!pdb^znu4RSl+*m>{}Q(Hu}-TmdX`J8qP0`-F3CGPe}BtM{g+pkC-fgT zcHpe0FY+QN{%9v2UNRCv&DN$N{p z)mf8c+&67p^M2G zPyP77i^AUj>+jg?#&>4AR$Y5(_Jras0bSzbvXXc9I-2)&?!L2KhVQ&L?BEaE7L^<+ z9N2vH*b83u2kf7;uV~je*|+%j3T;I9+66EE{QHex{XW33W|eCp@QGsn+q(hc5qwQ@J}I>rmNNQs-3n_qHCDz za1F&pv4dGz*B+o!7<0dO1@6mnU#<1Q-ayx`!cy3ARqUVzUBh7(lwV>};6m2X4)(ip zeI8KkK=6QrdxsKtI{YWq4n{@SPQy~v2YPkbvc?C(3LLyPMk$?FTBO?P2qn699IA<0#*kkG1V^j(snP~a@0M!omjJkFSmKZ6NhZH+F7O89EI;VbJ;RV$WMo-tgp&8-z z2a3C5#{*CuKF`6VYR(&fB#QO}kB|XojSr4O>KYr1ggb*YZ}=zK(ayuf zc@AK9#e`#*j&`sG>YBI%U$uC*ll{U{UAqZOalE=JcDfMDH^q(@psYT)H-28HvsF9YiGu?{;&^!}cJR(e*DwMoKQ4T`S+&yxN_4zkGWP3H z#ZFJ+^o1qXC-K`(>r^}5#KFJfMVxyoc6t#9YlT_n%)ZyJt9E)5XPCuKFU5`zal&AU z^|^X{hM#K3P8>fVi1y>7*ugVG*J8Py>vy}aR_)+X(lu;9;{19{vD1ffV2ScUO(|TG zVa=@h2cxHJ$rd|(6g&Nh(|SJiCC({Wigwsfu>-?A;0v=Eit~I3Ap_1~SPDB&D0cc2 zr}cd3uh{9Y*ufs>e)%wvIA6n3)F(i(6GWVYu*B%TSKTc~jWeV+@CDC-!k9RdAjM8F zaj@m1xTl=}w~ogv1WI(x8s}iePAGBkE*Q0&?+NYp`Nx2yt*c z1oNSbYtw#pzlIX$62u43e3T)Iok&3Mmk);#$C?i#6+6R;gIOA-XoK4hwLVc$BKOO~ z6+6+yX+0mt5C{7U5$9;d4rU%*6ZvrKq@^#a^?@b@9P9ClRqVtO2k&Mv&NsT0m8f<` z5~m0VSZ|a##ZEk+y4HGLO(0HZ@bw@X0f|@aBm#QBygG_F*1VcXcF^Vjy)K2{Mr590@j%7LN2W5a=XH`WXn0y`h8}2)28aa09`I<52n=2>!{1@`Ql| zaU{S%VmRVsAoy1-%A*D{lOvBA2tI&@;$0%(?aip7p z;A3hi9Sr0*jyz-_@a8FrZXlgG;$k4ZIpS_0fgJHLkVuX^U?52xaW#-sj{Mm`W^*JC z5Zwkdh~>b?j#-6>V;_}-oeK$`acyl@1akr*cp8#mwgCj*6tV}0(4(oCSBVphJsAo^ zaIF};_l94*CSjR*4Ip^-V{gUn3<#q!VUCPS8Xzjf5Fpw%fEHfyVBaLy$44MSiAIiz zgPjx!UNLfCP-h%*!>mgjqs|OLdKLKchF{EHtj>D?!3=?S9NZ4nxjoq7h^5X90ivyr z*BS3Gg!gb7`NRy_*5+@SW%VgQbgdmMQ7Se!-(-0Vx0=8X3UO@KIj55V)ium~Sl7D~ zHbk3R*SHpOBwv_yOkY8ZR)n)04zLaW1|T7hkb-!4@ zgH8r0Y9(_m;z+)pC9TeA8f1BN#!c3D<5n)$B97!M8A{Fl`u^b3 zcvB1eClumHzES{XT3EiI+kq48ItsVmPzFxfXFGU(ZRtez_Aj$J9E-wTL768c$kyt%{UwZasWWt?OKiIFhdklCP%h z-PNX68{T~qNAfk1w5)A|-4g+9^W<8@k$j~}zOc=kTA^HvIFhePk}quY>^=^Cjpka! zk$gQb`+_!aYR%wU#F2cZNxtx0X7`@xtB7k6NAfk9w8XiLZQj&c&$Wmn`AR1(Ynx~H z?*QBOaxLOWzNV0t@OAaKKO#-7e{wD2NWL;i3)=?D$FY8|u(1@}y2Q1JBl*gNQnStb zriE@ZweE2(;z+)*hhl9Wt%rGx^=H?IxaHx3OL~|eTB$W3P6O2RwP{HYcT+2bYY|8C z^#W<({RKAg$mp3@Os!U0y2rJMBl&_`UrUav zXfE7uYI(CxlpffSk5{hb>vB!gLQ^Y>YZ1rhZ<#@S7HRzrmMFJ9D~s70O^VG{;p-E4 zG!cP0vFZIyhVU^EOz1Ex57wDhanlfg%k1KF0M#{|UtE?Aoe*_3Ch5Siv^N56<^2`TjYv;VNyW& zcDw4_(4g;m2rg~}8AUklpeTWLvw&Wh7bUo17O~Hri8A^+kl3(%3x-2cX-a4~B*lhf zQgApXMMvmb!V{Gy#YZscF?pjBjuGN4vF}l7))=uZV~5$~jD{&|n9z56rfEeAR8*Q2 zDcHpCKO1(`Sg}yyp%>588lM5PhuX~b0oIK$OF_70-H}v~`x4B|Z0GJRN5wunGd(}u zS%EVZYM9PcSbmX+yelF?8ZDBE??RGl; +Source: http://www.vorbis.com/files/1.0.1/unix/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +# We're forced to use an epoch since both Red Hat and Ximian use it in their +# rc packages +Epoch: 2 +# Dirty trick to tell rpm that this package actually provides what the +# last rc and beta was offering +Provides: %{name} = %{epoch}:1.0rc3-%{release} +Provides: %{name} = %{epoch}:1.0beta4-%{release} + +%description +Libogg is a library for manipulating ogg bitstreams. It handles +both making ogg bitstreams and getting packets from ogg bitstreams. + +%package devel +Summary: Ogg Bitstream Library Development +Group: Development/Libraries +Requires: libogg = %{version} +# Dirty trick to tell rpm that this package actually provides what the +# last rc and beta was offering +Provides: %{name}-devel = %{epoch}:1.0rc3-%{release} +Provides: %{name}-devel = %{epoch}:1.0beta4-%{release} + +%description devel +The libogg-devel package contains the header files, static libraries +and documentation needed to develop applications with libogg. + +%prep +%setup -q -n %{name}-%{version} + +%build +CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix} --enable-static +make + +%install +rm -rf $RPM_BUILD_ROOT + +make DESTDIR=$RPM_BUILD_ROOT install + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%doc AUTHORS CHANGES COPYING README +%{_libdir}/libogg.so.* + +%files devel +%defattr(-,root,root) +%doc doc/index.html +%doc doc/framing.html +%doc doc/oggstream.html +%doc doc/white-ogg.png +%doc doc/white-xifish.png +%doc doc/stream.png +%doc doc/libogg/*.html +%doc doc/libogg/style.css +%dir %{_includedir}/ogg +%{_includedir}/ogg/ogg.h +%{_includedir}/ogg/os_types.h +%{_includedir}/ogg/config_types.h +%{_libdir}/libogg.a +%{_libdir}/libogg.la +%{_libdir}/libogg.so +%{_libdir}/pkgconfig/ogg.pc +%{_datadir}/aclocal/ogg.m4 + +%changelog +* Thu Nov 08 2007 Conrad Parker +- update doc dir (reported by thosmos on #vorbis) + +* Thu Jun 10 2004 Thomas Vander Stichele +- autogenerate from configure +- fix download location +- remove Prefix +- own include dir +- move ldconfig runs to -p scripts +- change Release tag to include xiph + +* Tue Oct 07 2003 Warren Dukes +- update for 1.1 release + +* Sun Jul 14 2002 Thomas Vander Stichele +- update for 1.0 release +- conform Group to Red Hat's idea of it +- take out case where configure doesn't exist; a tarball should have it + +* Tue Dec 18 2001 Jack Moffitt +- Update for RC3 release + +* Sun Oct 07 2001 Jack Moffitt +- add support for configurable prefixes + +* Sat Sep 02 2000 Jack Moffitt +- initial spec file created diff --git a/vendor/ogg/ogg-uninstalled.pc.in b/vendor/ogg/ogg-uninstalled.pc.in new file mode 100644 index 0000000..7acad78 --- /dev/null +++ b/vendor/ogg/ogg-uninstalled.pc.in @@ -0,0 +1,14 @@ +# ogg uninstalled pkg-config file + +prefix= +exec_prefix= +libdir=${pcfiledir}/src +includedir=${pcfiledir}/@top_srcdir@/include + +Name: ogg +Description: ogg is a library for manipulating ogg bitstreams (not installed) +Version: @VERSION@ +Requires: +Conflicts: +Libs: ${libdir}/.libs/libogg.la +Cflags: -I${includedir} diff --git a/vendor/ogg/ogg.m4 b/vendor/ogg/ogg.m4 new file mode 100644 index 0000000..17235da --- /dev/null +++ b/vendor/ogg/ogg.m4 @@ -0,0 +1,116 @@ +# Configure paths for libogg +# Jack Moffitt 10-21-2000 +# Shamelessly stolen from Owen Taylor and Manish Singh + +dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS +dnl +AC_DEFUN([XIPH_PATH_OGG], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(ogg,AC_HELP_STRING([--with-ogg=PFX],[Prefix where libogg is installed (optional)]), ogg_prefix="$withval", ogg_prefix="") +AC_ARG_WITH(ogg-libraries,AC_HELP_STRING([--with-ogg-libraries=DIR],[Directory where libogg library is installed (optional)]), ogg_libraries="$withval", ogg_libraries="") +AC_ARG_WITH(ogg-includes,AC_HELP_STRING([--with-ogg-includes=DIR],[Directory where libogg header files are installed (optional)]), ogg_includes="$withval", ogg_includes="") +AC_ARG_ENABLE(oggtest,AC_HELP_STRING([--disable-oggtest],[Do not try to compile and run a test Ogg program]),, enable_oggtest=yes) + + if test "x$ogg_libraries" != "x" ; then + OGG_LIBS="-L$ogg_libraries" + elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then + OGG_LIBS="" + elif test "x$ogg_prefix" != "x" ; then + OGG_LIBS="-L$ogg_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + OGG_LIBS="-L$prefix/lib" + fi + + if test "x$ogg_prefix" != "xno" ; then + OGG_LIBS="$OGG_LIBS -logg" + fi + + if test "x$ogg_includes" != "x" ; then + OGG_CFLAGS="-I$ogg_includes" + elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then + OGG_CFLAGS="" + elif test "x$ogg_prefix" != "x" ; then + OGG_CFLAGS="-I$ogg_prefix/include" + elif test "x$prefix" != "xNONE"; then + OGG_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for Ogg) + if test "x$ogg_prefix" = "xno" ; then + no_ogg="disabled" + enable_oggtest="no" + else + no_ogg="" + fi + + + if test "x$enable_oggtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $OGG_CFLAGS" + LIBS="$LIBS $OGG_LIBS" +dnl +dnl Now check if the installed Ogg is sufficiently new. +dnl + rm -f conf.oggtest + AC_TRY_RUN([ +#include +#include +#include +#include + +int main () +{ + system("touch conf.oggtest"); + return 0; +} + +],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_ogg" = "xdisabled" ; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + elif test "x$no_ogg" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.oggtest ; then + : + else + echo "*** Could not run Ogg test program, checking why..." + CFLAGS="$CFLAGS $OGG_CFLAGS" + LIBS="$LIBS $OGG_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Ogg or finding the wrong" + echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means Ogg was incorrectly installed" + echo "*** or that you have moved Ogg since it was installed." ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + OGG_CFLAGS="" + OGG_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(OGG_CFLAGS) + AC_SUBST(OGG_LIBS) + rm -f conf.oggtest +]) diff --git a/vendor/ogg/ogg.pc.in b/vendor/ogg/ogg.pc.in new file mode 100644 index 0000000..9e84375 --- /dev/null +++ b/vendor/ogg/ogg.pc.in @@ -0,0 +1,14 @@ +# ogg pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ogg +Description: ogg is a library for manipulating ogg bitstreams +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -logg +Cflags: -I${includedir} diff --git a/vendor/ogg/releases.sha2 b/vendor/ogg/releases.sha2 new file mode 100644 index 0000000..451b3bb --- /dev/null +++ b/vendor/ogg/releases.sha2 @@ -0,0 +1,40 @@ +c8a4157b0194962aa885e2088cf8561c65ce2eee36a77ca6325c6c36c842b2a9 libogg-1.0beta4.tar.gz +37bec40bf26ba6af8e98f2996051079cd2fbc4c401960fadb15c9e75383f3361 libogg-1.0rc1.tar.gz +c5f5924f25402a59a2586c3d037d3e79dae97de30531b8dd8b8b4abc20d5f036 libogg-1.0rc2.tar.gz +e907b7bc56de5a9dd0c5f062c7b0340a6295671cf2c6ad994d5f62919c9e1b0b libogg-1.0rc3.tar.gz +920fa2a0924d66884825d36a2e843de069cfdf1af01945d05da25999bbd6396c libogg-1.0.tar.gz +269f8f6b11b8ac737cbd8ed8cfa244cc51ca42b6da6683336ba1413d2a00ceb3 libogg-1.1.1.tar.gz +b72f4d716d8e1339469a874962aae5f055ba618772f00f43d3c6d0b543cdfadd libogg-1.1.1.zip +7934f3bf689c6ea0870bc73fcf40b00d5050044b03e558819a1ed333dc3cfadf libogg-1.1.2.tar.gz +01e97dd79336db38b31003ff956c7e29ebcfd8ceef8175cf17cf4f339a8c1a54 libogg-1.1.2.zip +bae29e79fbc50bbedf1235852094b71c8c910a1ef0cd42fe4163b7b545630b65 libogg-1.1.3.tar.gz +11c0202bc8f8e6fa361051a7d2dbc7ec95195b126c0407c5fc851d01c2a2ad6b libogg-1.1.3.zip +253d138b8c062db4d8446be1522162940dd89cad35c8332c3127d2e842850f31 libogg-1.1.4rc1.tar.gz +6bb65e5eafc75cc2ef7ccc37aea81749f1e72e503f7614e6748c06f532c42707 libogg-1.1.4rc1.zip +9354c183fd88417c2860778b60b7896c9487d8f6e58b9fec3fdbf971142ce103 libogg-1.1.4.tar.gz +0e9eb2370ba8d28ee6f6ccf27779c154fbfbd9c5e9d3a09e4419a85112a900ce libogg-1.1.4.zip +01453d561255b5fcb361997904752860e4f8c6b9742f290578a44615fcc94356 libogg-1.1.tar.gz +f30d983e238acd94e80ae551327ea2f83cdc330470b4188564bef28fec59eb69 libogg-1.2.0.tar.gz +6bf8650f0f3651fa4714ab9d03a5f781879e697d85d776f4dabc31877f42a0b2 libogg-1.2.0.zip +da222202be8be48149f0a0668f3d2445a166b1f9f40a25e27cd222bfa9c1d4d4 libogg-1.2.1.tar.bz2 +6858848617bca6eab01e7d8526bc0d2a417e95070a255cbf9c881881365e36c0 libogg-1.2.1.tar.gz +21e0a61e15e9dd294587bcd39d81fbe1998b27b1c525e15ecfaba94344f921b4 libogg-1.2.1.tar.xz +2d799a043865edc030ae56186a44624deb6365d59bcd8b3ae96384ccf613189d libogg-1.2.1.zip +ab000574bc26d5f01284f5b0f50e12dc761d035c429f2e9c70cb2a9487d8cfba libogg-1.2.2.tar.gz +559f1ea72a559520298e518865e488eb9a7185c6b9279f70602b01a87f7defed libogg-1.2.2.tar.xz +3f3bec05106d852da5ae3899ac2047dd14e2009bba872524eeade2d0bda42da0 libogg-1.2.2.zip +a8de807631014615549d2356fd36641833b8288221cea214f8a72750efe93780 libogg-1.3.0.tar.gz +231725029c843492914f24e74085e734bca6f1d6446ac72df39b0c3a9d4bc74b libogg-1.3.0.tar.xz +56db84601e7e855d1b9095ccba73d8ef98f063a2384f2239a7042070a3f1cde3 libogg-1.3.0.zip +4e343f07aa5a1de8e0fa1107042d472186b3470d846b20b115b964eba5bae554 libogg-1.3.1.tar.gz +3a5bad78d81afb78908326d11761c0fb1a0662ee7150b6ad587cc586838cdcfa libogg-1.3.1.tar.xz +131ae1f65f65e0ed70db03fbe3a9d9f2e8c24ac43754ae5e055fc55e6f750bc7 libogg-1.3.1.zip +e19ee34711d7af328cb26287f4137e70630e7261b17cbe3cd41011d73a654692 libogg-1.3.2.tar.gz +3f687ccdd5ac8b52d76328fbbfebc70c459a40ea891dbf3dccb74a210826e79b libogg-1.3.2.tar.xz +957b4168a03932e02853db340cfddd0fa89b6ca80073a54f7c827372c3606350 libogg-1.3.2.zip +c2e8a485110b97550f453226ec644ebac6cb29d1caef2902c007edab4308d985 libogg-1.3.3.tar.gz +4f3fc6178a533d392064f14776b23c397ed4b9f48f5de297aba73b643f955c08 libogg-1.3.3.tar.xz +ddbb0884406ea2b30d831dc7304fd4a958a05d62f24429d8fa83e1c9d620e7f8 libogg-1.3.3.zip +fe5670640bd49e828d64d2879c31cb4dde9758681bb664f9bdbf159a01b0c76e libogg-1.3.4.tar.gz +c163bc12bc300c401b6aa35907ac682671ea376f13ae0969a220f7ddf71893fe libogg-1.3.4.tar.xz +dd74e3ae52beab6c894d4b721db786961e64f073f28ef823c5d2a3558d4fab2d libogg-1.3.4.zip diff --git a/vendor/ogg/src/Makefile.am b/vendor/ogg/src/Makefile.am new file mode 100644 index 0000000..d171fe7 --- /dev/null +++ b/vendor/ogg/src/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include + +lib_LTLIBRARIES = libogg.la + +libogg_la_SOURCES = framing.c bitwise.c crctable.h +libogg_la_LDFLAGS = -no-undefined -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ + +# build and run the self tests on 'make check' + +noinst_PROGRAMS = test_bitwise test_framing + +test_bitwise_SOURCES = bitwise.c +test_bitwise_CFLAGS = -D_V_SELFTEST + +test_framing_SOURCES = framing.c crctable.h +test_framing_CFLAGS = -D_V_SELFTEST + +check: $(noinst_PROGRAMS) + ./test_bitwise$(EXEEXT) + ./test_framing$(EXEEXT) + +debug: + $(MAKE) all CFLAGS="@DEBUG@" + +profile: + $(MAKE) all CFLAGS="@PROFILE@" diff --git a/vendor/ogg/src/bitwise.c b/vendor/ogg/src/bitwise.c new file mode 100644 index 0000000..f5ef791 --- /dev/null +++ b/vendor/ogg/src/bitwise.c @@ -0,0 +1,1087 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: packing variable sized words into an octet stream + + ********************************************************************/ + +/* We're 'LSb' endian; if we write a word but read individual bits, + then we'll read the lsb first */ + +#include +#include +#include +#include + +#define BUFFER_INCREMENT 256 + +static const unsigned long mask[]= +{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, + 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, + 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, + 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, + 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, + 0x3fffffff,0x7fffffff,0xffffffff }; + +static const unsigned int mask8B[]= +{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; + +void oggpack_writeinit(oggpack_buffer *b){ + memset(b,0,sizeof(*b)); + b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT); + b->buffer[0]='\0'; + b->storage=BUFFER_INCREMENT; +} + +void oggpackB_writeinit(oggpack_buffer *b){ + oggpack_writeinit(b); +} + +int oggpack_writecheck(oggpack_buffer *b){ + if(!b->ptr || !b->storage)return -1; + return 0; +} + +int oggpackB_writecheck(oggpack_buffer *b){ + return oggpack_writecheck(b); +} + +void oggpack_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask[bits]; + } +} + +void oggpackB_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask8B[bits]; + } +} + +/* Takes only up to 32 bits. */ +void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value&=mask[bits]; + bits+=b->endbit; + + b->ptr[0]|=value<endbit; + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +/* Takes only up to 32 bits. */ +void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value=(value&mask[bits])<<(32-bits); + bits+=b->endbit; + + b->ptr[0]|=value>>(24+b->endbit); + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpack_write(b,0,bits); +} + +void oggpackB_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpackB_write(b,0,bits); +} + +static void oggpack_writecopy_helper(oggpack_buffer *b, + void *source, + long bits, + void (*w)(oggpack_buffer *, + unsigned long, + int), + int msb){ + unsigned char *ptr=(unsigned char *)source; + + long bytes=bits/8; + long pbytes=(b->endbit+bits)/8; + bits-=bytes*8; + + /* expand storage up-front */ + if(b->endbyte+pbytes>=b->storage){ + void *ret; + if(!b->ptr) goto err; + if(b->storage>b->endbyte+pbytes+BUFFER_INCREMENT) goto err; + b->storage=b->endbyte+pbytes+BUFFER_INCREMENT; + ret=_ogg_realloc(b->buffer,b->storage); + if(!ret) goto err; + b->buffer=ret; + b->ptr=b->buffer+b->endbyte; + } + + /* copy whole octets */ + if(b->endbit){ + int i; + /* unaligned copy. Do it the hard way. */ + for(i=0;iptr,source,bytes); + b->ptr+=bytes; + b->endbyte+=bytes; + *b->ptr=0; + } + + /* copy trailing bits */ + if(bits){ + if(msb) + w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); + else + w(b,(unsigned long)(ptr[bytes]),bits); + } + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpack_write,0); +} + +void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); +} + +void oggpack_reset(oggpack_buffer *b){ + if(!b->ptr)return; + b->ptr=b->buffer; + b->buffer[0]=0; + b->endbit=b->endbyte=0; +} + +void oggpackB_reset(oggpack_buffer *b){ + oggpack_reset(b); +} + +void oggpack_writeclear(oggpack_buffer *b){ + if(b->buffer)_ogg_free(b->buffer); + memset(b,0,sizeof(*b)); +} + +void oggpackB_writeclear(oggpack_buffer *b){ + oggpack_writeclear(b); +} + +void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + memset(b,0,sizeof(*b)); + b->buffer=b->ptr=buf; + b->storage=bytes; +} + +void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + oggpack_readinit(b,buf,bytes); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpack_look(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m; + + if(bits<0 || bits>32) return -1; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + return(m&ret); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpackB_look(oggpack_buffer *b,int bits){ + unsigned long ret; + int m=32-bits; + + if(m<0 || m>32) return -1; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); +} + +long oggpack_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>b->endbit)&1); +} + +long oggpackB_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>(7-b->endbit))&1); +} + +void oggpack_adv(oggpack_buffer *b,int bits){ + bits+=b->endbit; + + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; +} + +void oggpackB_adv(oggpack_buffer *b,int bits){ + oggpack_adv(b,bits); +} + +void oggpack_adv1(oggpack_buffer *b){ + if(++(b->endbit)>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } +} + +void oggpackB_adv1(oggpack_buffer *b){ + oggpack_adv1(b); +} + +/* bits <= 32 */ +long oggpack_read(oggpack_buffer *b,int bits){ + long ret; + unsigned long m; + + if(bits<0 || bits>32) goto err; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit){ + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + } + ret&=m; + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +/* bits <= 32 */ +long oggpackB_read(oggpack_buffer *b,int bits){ + long ret; + long m=32-bits; + + if(m<0 || m>32) goto err; + bits+=b->endbit; + + if(b->endbyte+4>=b->storage){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>b->endbit)&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpackB_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>(7-b->endbit))&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_bytes(oggpack_buffer *b){ + return(b->endbyte+(b->endbit+7)/8); +} + +long oggpack_bits(oggpack_buffer *b){ + return(b->endbyte*8+b->endbit); +} + +long oggpackB_bytes(oggpack_buffer *b){ + return oggpack_bytes(b); +} + +long oggpackB_bits(oggpack_buffer *b){ + return oggpack_bits(b); +} + +unsigned char *oggpack_get_buffer(oggpack_buffer *b){ + return(b->buffer); +} + +unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ + return oggpack_get_buffer(b); +} + +/* Self test of the bitwise routines; everything else is based on + them, so they damned well better be solid. */ + +#ifdef _V_SELFTEST +#include + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +oggpack_buffer o; +oggpack_buffer r; + +void report(char *in){ + fprintf(stderr,"%s",in); + exit(1); +} + +void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ + long bytes,i; + unsigned char *buffer; + + oggpack_reset(&o); + for(i=0;i + +static const ogg_uint32_t crc_lookup[8][256]={ +{0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, + 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, + 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, + 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, + 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, + 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, + 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, + 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, + 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, + 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, + 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, + 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, + 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, + 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, + 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, + 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, + 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, + 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, + 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, + 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, + 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, + 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, + 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, + 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, + 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, + 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, + 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, + 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, + 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, + 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, + 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, + 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}, + +{0x00000000,0xd219c1dc,0xa0f29e0f,0x72eb5fd3,0x452421a9,0x973de075,0xe5d6bfa6,0x37cf7e7a, + 0x8a484352,0x5851828e,0x2abadd5d,0xf8a31c81,0xcf6c62fb,0x1d75a327,0x6f9efcf4,0xbd873d28, + 0x10519b13,0xc2485acf,0xb0a3051c,0x62bac4c0,0x5575baba,0x876c7b66,0xf58724b5,0x279ee569, + 0x9a19d841,0x4800199d,0x3aeb464e,0xe8f28792,0xdf3df9e8,0x0d243834,0x7fcf67e7,0xadd6a63b, + 0x20a33626,0xf2baf7fa,0x8051a829,0x524869f5,0x6587178f,0xb79ed653,0xc5758980,0x176c485c, + 0xaaeb7574,0x78f2b4a8,0x0a19eb7b,0xd8002aa7,0xefcf54dd,0x3dd69501,0x4f3dcad2,0x9d240b0e, + 0x30f2ad35,0xe2eb6ce9,0x9000333a,0x4219f2e6,0x75d68c9c,0xa7cf4d40,0xd5241293,0x073dd34f, + 0xbabaee67,0x68a32fbb,0x1a487068,0xc851b1b4,0xff9ecfce,0x2d870e12,0x5f6c51c1,0x8d75901d, + 0x41466c4c,0x935fad90,0xe1b4f243,0x33ad339f,0x04624de5,0xd67b8c39,0xa490d3ea,0x76891236, + 0xcb0e2f1e,0x1917eec2,0x6bfcb111,0xb9e570cd,0x8e2a0eb7,0x5c33cf6b,0x2ed890b8,0xfcc15164, + 0x5117f75f,0x830e3683,0xf1e56950,0x23fca88c,0x1433d6f6,0xc62a172a,0xb4c148f9,0x66d88925, + 0xdb5fb40d,0x094675d1,0x7bad2a02,0xa9b4ebde,0x9e7b95a4,0x4c625478,0x3e890bab,0xec90ca77, + 0x61e55a6a,0xb3fc9bb6,0xc117c465,0x130e05b9,0x24c17bc3,0xf6d8ba1f,0x8433e5cc,0x562a2410, + 0xebad1938,0x39b4d8e4,0x4b5f8737,0x994646eb,0xae893891,0x7c90f94d,0x0e7ba69e,0xdc626742, + 0x71b4c179,0xa3ad00a5,0xd1465f76,0x035f9eaa,0x3490e0d0,0xe689210c,0x94627edf,0x467bbf03, + 0xfbfc822b,0x29e543f7,0x5b0e1c24,0x8917ddf8,0xbed8a382,0x6cc1625e,0x1e2a3d8d,0xcc33fc51, + 0x828cd898,0x50951944,0x227e4697,0xf067874b,0xc7a8f931,0x15b138ed,0x675a673e,0xb543a6e2, + 0x08c49bca,0xdadd5a16,0xa83605c5,0x7a2fc419,0x4de0ba63,0x9ff97bbf,0xed12246c,0x3f0be5b0, + 0x92dd438b,0x40c48257,0x322fdd84,0xe0361c58,0xd7f96222,0x05e0a3fe,0x770bfc2d,0xa5123df1, + 0x189500d9,0xca8cc105,0xb8679ed6,0x6a7e5f0a,0x5db12170,0x8fa8e0ac,0xfd43bf7f,0x2f5a7ea3, + 0xa22feebe,0x70362f62,0x02dd70b1,0xd0c4b16d,0xe70bcf17,0x35120ecb,0x47f95118,0x95e090c4, + 0x2867adec,0xfa7e6c30,0x889533e3,0x5a8cf23f,0x6d438c45,0xbf5a4d99,0xcdb1124a,0x1fa8d396, + 0xb27e75ad,0x6067b471,0x128ceba2,0xc0952a7e,0xf75a5404,0x254395d8,0x57a8ca0b,0x85b10bd7, + 0x383636ff,0xea2ff723,0x98c4a8f0,0x4add692c,0x7d121756,0xaf0bd68a,0xdde08959,0x0ff94885, + 0xc3cab4d4,0x11d37508,0x63382adb,0xb121eb07,0x86ee957d,0x54f754a1,0x261c0b72,0xf405caae, + 0x4982f786,0x9b9b365a,0xe9706989,0x3b69a855,0x0ca6d62f,0xdebf17f3,0xac544820,0x7e4d89fc, + 0xd39b2fc7,0x0182ee1b,0x7369b1c8,0xa1707014,0x96bf0e6e,0x44a6cfb2,0x364d9061,0xe45451bd, + 0x59d36c95,0x8bcaad49,0xf921f29a,0x2b383346,0x1cf74d3c,0xceee8ce0,0xbc05d333,0x6e1c12ef, + 0xe36982f2,0x3170432e,0x439b1cfd,0x9182dd21,0xa64da35b,0x74546287,0x06bf3d54,0xd4a6fc88, + 0x6921c1a0,0xbb38007c,0xc9d35faf,0x1bca9e73,0x2c05e009,0xfe1c21d5,0x8cf77e06,0x5eeebfda, + 0xf33819e1,0x2121d83d,0x53ca87ee,0x81d34632,0xb61c3848,0x6405f994,0x16eea647,0xc4f7679b, + 0x79705ab3,0xab699b6f,0xd982c4bc,0x0b9b0560,0x3c547b1a,0xee4dbac6,0x9ca6e515,0x4ebf24c9}, + +{0x00000000,0x01d8ac87,0x03b1590e,0x0269f589,0x0762b21c,0x06ba1e9b,0x04d3eb12,0x050b4795, + 0x0ec56438,0x0f1dc8bf,0x0d743d36,0x0cac91b1,0x09a7d624,0x087f7aa3,0x0a168f2a,0x0bce23ad, + 0x1d8ac870,0x1c5264f7,0x1e3b917e,0x1fe33df9,0x1ae87a6c,0x1b30d6eb,0x19592362,0x18818fe5, + 0x134fac48,0x129700cf,0x10fef546,0x112659c1,0x142d1e54,0x15f5b2d3,0x179c475a,0x1644ebdd, + 0x3b1590e0,0x3acd3c67,0x38a4c9ee,0x397c6569,0x3c7722fc,0x3daf8e7b,0x3fc67bf2,0x3e1ed775, + 0x35d0f4d8,0x3408585f,0x3661add6,0x37b90151,0x32b246c4,0x336aea43,0x31031fca,0x30dbb34d, + 0x269f5890,0x2747f417,0x252e019e,0x24f6ad19,0x21fdea8c,0x2025460b,0x224cb382,0x23941f05, + 0x285a3ca8,0x2982902f,0x2beb65a6,0x2a33c921,0x2f388eb4,0x2ee02233,0x2c89d7ba,0x2d517b3d, + 0x762b21c0,0x77f38d47,0x759a78ce,0x7442d449,0x714993dc,0x70913f5b,0x72f8cad2,0x73206655, + 0x78ee45f8,0x7936e97f,0x7b5f1cf6,0x7a87b071,0x7f8cf7e4,0x7e545b63,0x7c3daeea,0x7de5026d, + 0x6ba1e9b0,0x6a794537,0x6810b0be,0x69c81c39,0x6cc35bac,0x6d1bf72b,0x6f7202a2,0x6eaaae25, + 0x65648d88,0x64bc210f,0x66d5d486,0x670d7801,0x62063f94,0x63de9313,0x61b7669a,0x606fca1d, + 0x4d3eb120,0x4ce61da7,0x4e8fe82e,0x4f5744a9,0x4a5c033c,0x4b84afbb,0x49ed5a32,0x4835f6b5, + 0x43fbd518,0x4223799f,0x404a8c16,0x41922091,0x44996704,0x4541cb83,0x47283e0a,0x46f0928d, + 0x50b47950,0x516cd5d7,0x5305205e,0x52dd8cd9,0x57d6cb4c,0x560e67cb,0x54679242,0x55bf3ec5, + 0x5e711d68,0x5fa9b1ef,0x5dc04466,0x5c18e8e1,0x5913af74,0x58cb03f3,0x5aa2f67a,0x5b7a5afd, + 0xec564380,0xed8eef07,0xefe71a8e,0xee3fb609,0xeb34f19c,0xeaec5d1b,0xe885a892,0xe95d0415, + 0xe29327b8,0xe34b8b3f,0xe1227eb6,0xe0fad231,0xe5f195a4,0xe4293923,0xe640ccaa,0xe798602d, + 0xf1dc8bf0,0xf0042777,0xf26dd2fe,0xf3b57e79,0xf6be39ec,0xf766956b,0xf50f60e2,0xf4d7cc65, + 0xff19efc8,0xfec1434f,0xfca8b6c6,0xfd701a41,0xf87b5dd4,0xf9a3f153,0xfbca04da,0xfa12a85d, + 0xd743d360,0xd69b7fe7,0xd4f28a6e,0xd52a26e9,0xd021617c,0xd1f9cdfb,0xd3903872,0xd24894f5, + 0xd986b758,0xd85e1bdf,0xda37ee56,0xdbef42d1,0xdee40544,0xdf3ca9c3,0xdd555c4a,0xdc8df0cd, + 0xcac91b10,0xcb11b797,0xc978421e,0xc8a0ee99,0xcdaba90c,0xcc73058b,0xce1af002,0xcfc25c85, + 0xc40c7f28,0xc5d4d3af,0xc7bd2626,0xc6658aa1,0xc36ecd34,0xc2b661b3,0xc0df943a,0xc10738bd, + 0x9a7d6240,0x9ba5cec7,0x99cc3b4e,0x981497c9,0x9d1fd05c,0x9cc77cdb,0x9eae8952,0x9f7625d5, + 0x94b80678,0x9560aaff,0x97095f76,0x96d1f3f1,0x93dab464,0x920218e3,0x906bed6a,0x91b341ed, + 0x87f7aa30,0x862f06b7,0x8446f33e,0x859e5fb9,0x8095182c,0x814db4ab,0x83244122,0x82fceda5, + 0x8932ce08,0x88ea628f,0x8a839706,0x8b5b3b81,0x8e507c14,0x8f88d093,0x8de1251a,0x8c39899d, + 0xa168f2a0,0xa0b05e27,0xa2d9abae,0xa3010729,0xa60a40bc,0xa7d2ec3b,0xa5bb19b2,0xa463b535, + 0xafad9698,0xae753a1f,0xac1ccf96,0xadc46311,0xa8cf2484,0xa9178803,0xab7e7d8a,0xaaa6d10d, + 0xbce23ad0,0xbd3a9657,0xbf5363de,0xbe8bcf59,0xbb8088cc,0xba58244b,0xb831d1c2,0xb9e97d45, + 0xb2275ee8,0xb3fff26f,0xb19607e6,0xb04eab61,0xb545ecf4,0xb49d4073,0xb6f4b5fa,0xb72c197d}, + +{0x00000000,0xdc6d9ab7,0xbc1a28d9,0x6077b26e,0x7cf54c05,0xa098d6b2,0xc0ef64dc,0x1c82fe6b, + 0xf9ea980a,0x258702bd,0x45f0b0d3,0x999d2a64,0x851fd40f,0x59724eb8,0x3905fcd6,0xe5686661, + 0xf7142da3,0x2b79b714,0x4b0e057a,0x97639fcd,0x8be161a6,0x578cfb11,0x37fb497f,0xeb96d3c8, + 0x0efeb5a9,0xd2932f1e,0xb2e49d70,0x6e8907c7,0x720bf9ac,0xae66631b,0xce11d175,0x127c4bc2, + 0xeae946f1,0x3684dc46,0x56f36e28,0x8a9ef49f,0x961c0af4,0x4a719043,0x2a06222d,0xf66bb89a, + 0x1303defb,0xcf6e444c,0xaf19f622,0x73746c95,0x6ff692fe,0xb39b0849,0xd3ecba27,0x0f812090, + 0x1dfd6b52,0xc190f1e5,0xa1e7438b,0x7d8ad93c,0x61082757,0xbd65bde0,0xdd120f8e,0x017f9539, + 0xe417f358,0x387a69ef,0x580ddb81,0x84604136,0x98e2bf5d,0x448f25ea,0x24f89784,0xf8950d33, + 0xd1139055,0x0d7e0ae2,0x6d09b88c,0xb164223b,0xade6dc50,0x718b46e7,0x11fcf489,0xcd916e3e, + 0x28f9085f,0xf49492e8,0x94e32086,0x488eba31,0x540c445a,0x8861deed,0xe8166c83,0x347bf634, + 0x2607bdf6,0xfa6a2741,0x9a1d952f,0x46700f98,0x5af2f1f3,0x869f6b44,0xe6e8d92a,0x3a85439d, + 0xdfed25fc,0x0380bf4b,0x63f70d25,0xbf9a9792,0xa31869f9,0x7f75f34e,0x1f024120,0xc36fdb97, + 0x3bfad6a4,0xe7974c13,0x87e0fe7d,0x5b8d64ca,0x470f9aa1,0x9b620016,0xfb15b278,0x277828cf, + 0xc2104eae,0x1e7dd419,0x7e0a6677,0xa267fcc0,0xbee502ab,0x6288981c,0x02ff2a72,0xde92b0c5, + 0xcceefb07,0x108361b0,0x70f4d3de,0xac994969,0xb01bb702,0x6c762db5,0x0c019fdb,0xd06c056c, + 0x3504630d,0xe969f9ba,0x891e4bd4,0x5573d163,0x49f12f08,0x959cb5bf,0xf5eb07d1,0x29869d66, + 0xa6e63d1d,0x7a8ba7aa,0x1afc15c4,0xc6918f73,0xda137118,0x067eebaf,0x660959c1,0xba64c376, + 0x5f0ca517,0x83613fa0,0xe3168dce,0x3f7b1779,0x23f9e912,0xff9473a5,0x9fe3c1cb,0x438e5b7c, + 0x51f210be,0x8d9f8a09,0xede83867,0x3185a2d0,0x2d075cbb,0xf16ac60c,0x911d7462,0x4d70eed5, + 0xa81888b4,0x74751203,0x1402a06d,0xc86f3ada,0xd4edc4b1,0x08805e06,0x68f7ec68,0xb49a76df, + 0x4c0f7bec,0x9062e15b,0xf0155335,0x2c78c982,0x30fa37e9,0xec97ad5e,0x8ce01f30,0x508d8587, + 0xb5e5e3e6,0x69887951,0x09ffcb3f,0xd5925188,0xc910afe3,0x157d3554,0x750a873a,0xa9671d8d, + 0xbb1b564f,0x6776ccf8,0x07017e96,0xdb6ce421,0xc7ee1a4a,0x1b8380fd,0x7bf43293,0xa799a824, + 0x42f1ce45,0x9e9c54f2,0xfeebe69c,0x22867c2b,0x3e048240,0xe26918f7,0x821eaa99,0x5e73302e, + 0x77f5ad48,0xab9837ff,0xcbef8591,0x17821f26,0x0b00e14d,0xd76d7bfa,0xb71ac994,0x6b775323, + 0x8e1f3542,0x5272aff5,0x32051d9b,0xee68872c,0xf2ea7947,0x2e87e3f0,0x4ef0519e,0x929dcb29, + 0x80e180eb,0x5c8c1a5c,0x3cfba832,0xe0963285,0xfc14ccee,0x20795659,0x400ee437,0x9c637e80, + 0x790b18e1,0xa5668256,0xc5113038,0x197caa8f,0x05fe54e4,0xd993ce53,0xb9e47c3d,0x6589e68a, + 0x9d1cebb9,0x4171710e,0x2106c360,0xfd6b59d7,0xe1e9a7bc,0x3d843d0b,0x5df38f65,0x819e15d2, + 0x64f673b3,0xb89be904,0xd8ec5b6a,0x0481c1dd,0x18033fb6,0xc46ea501,0xa419176f,0x78748dd8, + 0x6a08c61a,0xb6655cad,0xd612eec3,0x0a7f7474,0x16fd8a1f,0xca9010a8,0xaae7a2c6,0x768a3871, + 0x93e25e10,0x4f8fc4a7,0x2ff876c9,0xf395ec7e,0xef171215,0x337a88a2,0x530d3acc,0x8f60a07b}, + +{0x00000000,0x490d678d,0x921acf1a,0xdb17a897,0x20f48383,0x69f9e40e,0xb2ee4c99,0xfbe32b14, + 0x41e90706,0x08e4608b,0xd3f3c81c,0x9afeaf91,0x611d8485,0x2810e308,0xf3074b9f,0xba0a2c12, + 0x83d20e0c,0xcadf6981,0x11c8c116,0x58c5a69b,0xa3268d8f,0xea2bea02,0x313c4295,0x78312518, + 0xc23b090a,0x8b366e87,0x5021c610,0x192ca19d,0xe2cf8a89,0xabc2ed04,0x70d54593,0x39d8221e, + 0x036501af,0x4a686622,0x917fceb5,0xd872a938,0x2391822c,0x6a9ce5a1,0xb18b4d36,0xf8862abb, + 0x428c06a9,0x0b816124,0xd096c9b3,0x999bae3e,0x6278852a,0x2b75e2a7,0xf0624a30,0xb96f2dbd, + 0x80b70fa3,0xc9ba682e,0x12adc0b9,0x5ba0a734,0xa0438c20,0xe94eebad,0x3259433a,0x7b5424b7, + 0xc15e08a5,0x88536f28,0x5344c7bf,0x1a49a032,0xe1aa8b26,0xa8a7ecab,0x73b0443c,0x3abd23b1, + 0x06ca035e,0x4fc764d3,0x94d0cc44,0xddddabc9,0x263e80dd,0x6f33e750,0xb4244fc7,0xfd29284a, + 0x47230458,0x0e2e63d5,0xd539cb42,0x9c34accf,0x67d787db,0x2edae056,0xf5cd48c1,0xbcc02f4c, + 0x85180d52,0xcc156adf,0x1702c248,0x5e0fa5c5,0xa5ec8ed1,0xece1e95c,0x37f641cb,0x7efb2646, + 0xc4f10a54,0x8dfc6dd9,0x56ebc54e,0x1fe6a2c3,0xe40589d7,0xad08ee5a,0x761f46cd,0x3f122140, + 0x05af02f1,0x4ca2657c,0x97b5cdeb,0xdeb8aa66,0x255b8172,0x6c56e6ff,0xb7414e68,0xfe4c29e5, + 0x444605f7,0x0d4b627a,0xd65ccaed,0x9f51ad60,0x64b28674,0x2dbfe1f9,0xf6a8496e,0xbfa52ee3, + 0x867d0cfd,0xcf706b70,0x1467c3e7,0x5d6aa46a,0xa6898f7e,0xef84e8f3,0x34934064,0x7d9e27e9, + 0xc7940bfb,0x8e996c76,0x558ec4e1,0x1c83a36c,0xe7608878,0xae6deff5,0x757a4762,0x3c7720ef, + 0x0d9406bc,0x44996131,0x9f8ec9a6,0xd683ae2b,0x2d60853f,0x646de2b2,0xbf7a4a25,0xf6772da8, + 0x4c7d01ba,0x05706637,0xde67cea0,0x976aa92d,0x6c898239,0x2584e5b4,0xfe934d23,0xb79e2aae, + 0x8e4608b0,0xc74b6f3d,0x1c5cc7aa,0x5551a027,0xaeb28b33,0xe7bfecbe,0x3ca84429,0x75a523a4, + 0xcfaf0fb6,0x86a2683b,0x5db5c0ac,0x14b8a721,0xef5b8c35,0xa656ebb8,0x7d41432f,0x344c24a2, + 0x0ef10713,0x47fc609e,0x9cebc809,0xd5e6af84,0x2e058490,0x6708e31d,0xbc1f4b8a,0xf5122c07, + 0x4f180015,0x06156798,0xdd02cf0f,0x940fa882,0x6fec8396,0x26e1e41b,0xfdf64c8c,0xb4fb2b01, + 0x8d23091f,0xc42e6e92,0x1f39c605,0x5634a188,0xadd78a9c,0xe4daed11,0x3fcd4586,0x76c0220b, + 0xccca0e19,0x85c76994,0x5ed0c103,0x17dda68e,0xec3e8d9a,0xa533ea17,0x7e244280,0x3729250d, + 0x0b5e05e2,0x4253626f,0x9944caf8,0xd049ad75,0x2baa8661,0x62a7e1ec,0xb9b0497b,0xf0bd2ef6, + 0x4ab702e4,0x03ba6569,0xd8adcdfe,0x91a0aa73,0x6a438167,0x234ee6ea,0xf8594e7d,0xb15429f0, + 0x888c0bee,0xc1816c63,0x1a96c4f4,0x539ba379,0xa878886d,0xe175efe0,0x3a624777,0x736f20fa, + 0xc9650ce8,0x80686b65,0x5b7fc3f2,0x1272a47f,0xe9918f6b,0xa09ce8e6,0x7b8b4071,0x328627fc, + 0x083b044d,0x413663c0,0x9a21cb57,0xd32cacda,0x28cf87ce,0x61c2e043,0xbad548d4,0xf3d82f59, + 0x49d2034b,0x00df64c6,0xdbc8cc51,0x92c5abdc,0x692680c8,0x202be745,0xfb3c4fd2,0xb231285f, + 0x8be90a41,0xc2e46dcc,0x19f3c55b,0x50fea2d6,0xab1d89c2,0xe210ee4f,0x390746d8,0x700a2155, + 0xca000d47,0x830d6aca,0x581ac25d,0x1117a5d0,0xeaf48ec4,0xa3f9e949,0x78ee41de,0x31e32653}, + +{0x00000000,0x1b280d78,0x36501af0,0x2d781788,0x6ca035e0,0x77883898,0x5af02f10,0x41d82268, + 0xd9406bc0,0xc26866b8,0xef107130,0xf4387c48,0xb5e05e20,0xaec85358,0x83b044d0,0x989849a8, + 0xb641ca37,0xad69c74f,0x8011d0c7,0x9b39ddbf,0xdae1ffd7,0xc1c9f2af,0xecb1e527,0xf799e85f, + 0x6f01a1f7,0x7429ac8f,0x5951bb07,0x4279b67f,0x03a19417,0x1889996f,0x35f18ee7,0x2ed9839f, + 0x684289d9,0x736a84a1,0x5e129329,0x453a9e51,0x04e2bc39,0x1fcab141,0x32b2a6c9,0x299aabb1, + 0xb102e219,0xaa2aef61,0x8752f8e9,0x9c7af591,0xdda2d7f9,0xc68ada81,0xebf2cd09,0xf0dac071, + 0xde0343ee,0xc52b4e96,0xe853591e,0xf37b5466,0xb2a3760e,0xa98b7b76,0x84f36cfe,0x9fdb6186, + 0x0743282e,0x1c6b2556,0x311332de,0x2a3b3fa6,0x6be31dce,0x70cb10b6,0x5db3073e,0x469b0a46, + 0xd08513b2,0xcbad1eca,0xe6d50942,0xfdfd043a,0xbc252652,0xa70d2b2a,0x8a753ca2,0x915d31da, + 0x09c57872,0x12ed750a,0x3f956282,0x24bd6ffa,0x65654d92,0x7e4d40ea,0x53355762,0x481d5a1a, + 0x66c4d985,0x7decd4fd,0x5094c375,0x4bbcce0d,0x0a64ec65,0x114ce11d,0x3c34f695,0x271cfbed, + 0xbf84b245,0xa4acbf3d,0x89d4a8b5,0x92fca5cd,0xd32487a5,0xc80c8add,0xe5749d55,0xfe5c902d, + 0xb8c79a6b,0xa3ef9713,0x8e97809b,0x95bf8de3,0xd467af8b,0xcf4fa2f3,0xe237b57b,0xf91fb803, + 0x6187f1ab,0x7aaffcd3,0x57d7eb5b,0x4cffe623,0x0d27c44b,0x160fc933,0x3b77debb,0x205fd3c3, + 0x0e86505c,0x15ae5d24,0x38d64aac,0x23fe47d4,0x622665bc,0x790e68c4,0x54767f4c,0x4f5e7234, + 0xd7c63b9c,0xccee36e4,0xe196216c,0xfabe2c14,0xbb660e7c,0xa04e0304,0x8d36148c,0x961e19f4, + 0xa5cb3ad3,0xbee337ab,0x939b2023,0x88b32d5b,0xc96b0f33,0xd243024b,0xff3b15c3,0xe41318bb, + 0x7c8b5113,0x67a35c6b,0x4adb4be3,0x51f3469b,0x102b64f3,0x0b03698b,0x267b7e03,0x3d53737b, + 0x138af0e4,0x08a2fd9c,0x25daea14,0x3ef2e76c,0x7f2ac504,0x6402c87c,0x497adff4,0x5252d28c, + 0xcaca9b24,0xd1e2965c,0xfc9a81d4,0xe7b28cac,0xa66aaec4,0xbd42a3bc,0x903ab434,0x8b12b94c, + 0xcd89b30a,0xd6a1be72,0xfbd9a9fa,0xe0f1a482,0xa12986ea,0xba018b92,0x97799c1a,0x8c519162, + 0x14c9d8ca,0x0fe1d5b2,0x2299c23a,0x39b1cf42,0x7869ed2a,0x6341e052,0x4e39f7da,0x5511faa2, + 0x7bc8793d,0x60e07445,0x4d9863cd,0x56b06eb5,0x17684cdd,0x0c4041a5,0x2138562d,0x3a105b55, + 0xa28812fd,0xb9a01f85,0x94d8080d,0x8ff00575,0xce28271d,0xd5002a65,0xf8783ded,0xe3503095, + 0x754e2961,0x6e662419,0x431e3391,0x58363ee9,0x19ee1c81,0x02c611f9,0x2fbe0671,0x34960b09, + 0xac0e42a1,0xb7264fd9,0x9a5e5851,0x81765529,0xc0ae7741,0xdb867a39,0xf6fe6db1,0xedd660c9, + 0xc30fe356,0xd827ee2e,0xf55ff9a6,0xee77f4de,0xafafd6b6,0xb487dbce,0x99ffcc46,0x82d7c13e, + 0x1a4f8896,0x016785ee,0x2c1f9266,0x37379f1e,0x76efbd76,0x6dc7b00e,0x40bfa786,0x5b97aafe, + 0x1d0ca0b8,0x0624adc0,0x2b5cba48,0x3074b730,0x71ac9558,0x6a849820,0x47fc8fa8,0x5cd482d0, + 0xc44ccb78,0xdf64c600,0xf21cd188,0xe934dcf0,0xa8ecfe98,0xb3c4f3e0,0x9ebce468,0x8594e910, + 0xab4d6a8f,0xb06567f7,0x9d1d707f,0x86357d07,0xc7ed5f6f,0xdcc55217,0xf1bd459f,0xea9548e7, + 0x720d014f,0x69250c37,0x445d1bbf,0x5f7516c7,0x1ead34af,0x058539d7,0x28fd2e5f,0x33d52327}, + +{0x00000000,0x4f576811,0x9eaed022,0xd1f9b833,0x399cbdf3,0x76cbd5e2,0xa7326dd1,0xe86505c0, + 0x73397be6,0x3c6e13f7,0xed97abc4,0xa2c0c3d5,0x4aa5c615,0x05f2ae04,0xd40b1637,0x9b5c7e26, + 0xe672f7cc,0xa9259fdd,0x78dc27ee,0x378b4fff,0xdfee4a3f,0x90b9222e,0x41409a1d,0x0e17f20c, + 0x954b8c2a,0xda1ce43b,0x0be55c08,0x44b23419,0xacd731d9,0xe38059c8,0x3279e1fb,0x7d2e89ea, + 0xc824f22f,0x87739a3e,0x568a220d,0x19dd4a1c,0xf1b84fdc,0xbeef27cd,0x6f169ffe,0x2041f7ef, + 0xbb1d89c9,0xf44ae1d8,0x25b359eb,0x6ae431fa,0x8281343a,0xcdd65c2b,0x1c2fe418,0x53788c09, + 0x2e5605e3,0x61016df2,0xb0f8d5c1,0xffafbdd0,0x17cab810,0x589dd001,0x89646832,0xc6330023, + 0x5d6f7e05,0x12381614,0xc3c1ae27,0x8c96c636,0x64f3c3f6,0x2ba4abe7,0xfa5d13d4,0xb50a7bc5, + 0x9488f9e9,0xdbdf91f8,0x0a2629cb,0x457141da,0xad14441a,0xe2432c0b,0x33ba9438,0x7cedfc29, + 0xe7b1820f,0xa8e6ea1e,0x791f522d,0x36483a3c,0xde2d3ffc,0x917a57ed,0x4083efde,0x0fd487cf, + 0x72fa0e25,0x3dad6634,0xec54de07,0xa303b616,0x4b66b3d6,0x0431dbc7,0xd5c863f4,0x9a9f0be5, + 0x01c375c3,0x4e941dd2,0x9f6da5e1,0xd03acdf0,0x385fc830,0x7708a021,0xa6f11812,0xe9a67003, + 0x5cac0bc6,0x13fb63d7,0xc202dbe4,0x8d55b3f5,0x6530b635,0x2a67de24,0xfb9e6617,0xb4c90e06, + 0x2f957020,0x60c21831,0xb13ba002,0xfe6cc813,0x1609cdd3,0x595ea5c2,0x88a71df1,0xc7f075e0, + 0xbadefc0a,0xf589941b,0x24702c28,0x6b274439,0x834241f9,0xcc1529e8,0x1dec91db,0x52bbf9ca, + 0xc9e787ec,0x86b0effd,0x574957ce,0x181e3fdf,0xf07b3a1f,0xbf2c520e,0x6ed5ea3d,0x2182822c, + 0x2dd0ee65,0x62878674,0xb37e3e47,0xfc295656,0x144c5396,0x5b1b3b87,0x8ae283b4,0xc5b5eba5, + 0x5ee99583,0x11befd92,0xc04745a1,0x8f102db0,0x67752870,0x28224061,0xf9dbf852,0xb68c9043, + 0xcba219a9,0x84f571b8,0x550cc98b,0x1a5ba19a,0xf23ea45a,0xbd69cc4b,0x6c907478,0x23c71c69, + 0xb89b624f,0xf7cc0a5e,0x2635b26d,0x6962da7c,0x8107dfbc,0xce50b7ad,0x1fa90f9e,0x50fe678f, + 0xe5f41c4a,0xaaa3745b,0x7b5acc68,0x340da479,0xdc68a1b9,0x933fc9a8,0x42c6719b,0x0d91198a, + 0x96cd67ac,0xd99a0fbd,0x0863b78e,0x4734df9f,0xaf51da5f,0xe006b24e,0x31ff0a7d,0x7ea8626c, + 0x0386eb86,0x4cd18397,0x9d283ba4,0xd27f53b5,0x3a1a5675,0x754d3e64,0xa4b48657,0xebe3ee46, + 0x70bf9060,0x3fe8f871,0xee114042,0xa1462853,0x49232d93,0x06744582,0xd78dfdb1,0x98da95a0, + 0xb958178c,0xf60f7f9d,0x27f6c7ae,0x68a1afbf,0x80c4aa7f,0xcf93c26e,0x1e6a7a5d,0x513d124c, + 0xca616c6a,0x8536047b,0x54cfbc48,0x1b98d459,0xf3fdd199,0xbcaab988,0x6d5301bb,0x220469aa, + 0x5f2ae040,0x107d8851,0xc1843062,0x8ed35873,0x66b65db3,0x29e135a2,0xf8188d91,0xb74fe580, + 0x2c139ba6,0x6344f3b7,0xb2bd4b84,0xfdea2395,0x158f2655,0x5ad84e44,0x8b21f677,0xc4769e66, + 0x717ce5a3,0x3e2b8db2,0xefd23581,0xa0855d90,0x48e05850,0x07b73041,0xd64e8872,0x9919e063, + 0x02459e45,0x4d12f654,0x9ceb4e67,0xd3bc2676,0x3bd923b6,0x748e4ba7,0xa577f394,0xea209b85, + 0x970e126f,0xd8597a7e,0x09a0c24d,0x46f7aa5c,0xae92af9c,0xe1c5c78d,0x303c7fbe,0x7f6b17af, + 0xe4376989,0xab600198,0x7a99b9ab,0x35ced1ba,0xddabd47a,0x92fcbc6b,0x43050458,0x0c526c49}, + +{0x00000000,0x5ba1dcca,0xb743b994,0xece2655e,0x6a466e9f,0x31e7b255,0xdd05d70b,0x86a40bc1, + 0xd48cdd3e,0x8f2d01f4,0x63cf64aa,0x386eb860,0xbecab3a1,0xe56b6f6b,0x09890a35,0x5228d6ff, + 0xadd8a7cb,0xf6797b01,0x1a9b1e5f,0x413ac295,0xc79ec954,0x9c3f159e,0x70dd70c0,0x2b7cac0a, + 0x79547af5,0x22f5a63f,0xce17c361,0x95b61fab,0x1312146a,0x48b3c8a0,0xa451adfe,0xfff07134, + 0x5f705221,0x04d18eeb,0xe833ebb5,0xb392377f,0x35363cbe,0x6e97e074,0x8275852a,0xd9d459e0, + 0x8bfc8f1f,0xd05d53d5,0x3cbf368b,0x671eea41,0xe1bae180,0xba1b3d4a,0x56f95814,0x0d5884de, + 0xf2a8f5ea,0xa9092920,0x45eb4c7e,0x1e4a90b4,0x98ee9b75,0xc34f47bf,0x2fad22e1,0x740cfe2b, + 0x262428d4,0x7d85f41e,0x91679140,0xcac64d8a,0x4c62464b,0x17c39a81,0xfb21ffdf,0xa0802315, + 0xbee0a442,0xe5417888,0x09a31dd6,0x5202c11c,0xd4a6cadd,0x8f071617,0x63e57349,0x3844af83, + 0x6a6c797c,0x31cda5b6,0xdd2fc0e8,0x868e1c22,0x002a17e3,0x5b8bcb29,0xb769ae77,0xecc872bd, + 0x13380389,0x4899df43,0xa47bba1d,0xffda66d7,0x797e6d16,0x22dfb1dc,0xce3dd482,0x959c0848, + 0xc7b4deb7,0x9c15027d,0x70f76723,0x2b56bbe9,0xadf2b028,0xf6536ce2,0x1ab109bc,0x4110d576, + 0xe190f663,0xba312aa9,0x56d34ff7,0x0d72933d,0x8bd698fc,0xd0774436,0x3c952168,0x6734fda2, + 0x351c2b5d,0x6ebdf797,0x825f92c9,0xd9fe4e03,0x5f5a45c2,0x04fb9908,0xe819fc56,0xb3b8209c, + 0x4c4851a8,0x17e98d62,0xfb0be83c,0xa0aa34f6,0x260e3f37,0x7dafe3fd,0x914d86a3,0xcaec5a69, + 0x98c48c96,0xc365505c,0x2f873502,0x7426e9c8,0xf282e209,0xa9233ec3,0x45c15b9d,0x1e608757, + 0x79005533,0x22a189f9,0xce43eca7,0x95e2306d,0x13463bac,0x48e7e766,0xa4058238,0xffa45ef2, + 0xad8c880d,0xf62d54c7,0x1acf3199,0x416eed53,0xc7cae692,0x9c6b3a58,0x70895f06,0x2b2883cc, + 0xd4d8f2f8,0x8f792e32,0x639b4b6c,0x383a97a6,0xbe9e9c67,0xe53f40ad,0x09dd25f3,0x527cf939, + 0x00542fc6,0x5bf5f30c,0xb7179652,0xecb64a98,0x6a124159,0x31b39d93,0xdd51f8cd,0x86f02407, + 0x26700712,0x7dd1dbd8,0x9133be86,0xca92624c,0x4c36698d,0x1797b547,0xfb75d019,0xa0d40cd3, + 0xf2fcda2c,0xa95d06e6,0x45bf63b8,0x1e1ebf72,0x98bab4b3,0xc31b6879,0x2ff90d27,0x7458d1ed, + 0x8ba8a0d9,0xd0097c13,0x3ceb194d,0x674ac587,0xe1eece46,0xba4f128c,0x56ad77d2,0x0d0cab18, + 0x5f247de7,0x0485a12d,0xe867c473,0xb3c618b9,0x35621378,0x6ec3cfb2,0x8221aaec,0xd9807626, + 0xc7e0f171,0x9c412dbb,0x70a348e5,0x2b02942f,0xada69fee,0xf6074324,0x1ae5267a,0x4144fab0, + 0x136c2c4f,0x48cdf085,0xa42f95db,0xff8e4911,0x792a42d0,0x228b9e1a,0xce69fb44,0x95c8278e, + 0x6a3856ba,0x31998a70,0xdd7bef2e,0x86da33e4,0x007e3825,0x5bdfe4ef,0xb73d81b1,0xec9c5d7b, + 0xbeb48b84,0xe515574e,0x09f73210,0x5256eeda,0xd4f2e51b,0x8f5339d1,0x63b15c8f,0x38108045, + 0x9890a350,0xc3317f9a,0x2fd31ac4,0x7472c60e,0xf2d6cdcf,0xa9771105,0x4595745b,0x1e34a891, + 0x4c1c7e6e,0x17bda2a4,0xfb5fc7fa,0xa0fe1b30,0x265a10f1,0x7dfbcc3b,0x9119a965,0xcab875af, + 0x3548049b,0x6ee9d851,0x820bbd0f,0xd9aa61c5,0x5f0e6a04,0x04afb6ce,0xe84dd390,0xb3ec0f5a, + 0xe1c4d9a5,0xba65056f,0x56876031,0x0d26bcfb,0x8b82b73a,0xd0236bf0,0x3cc10eae,0x6760d264}}; diff --git a/vendor/ogg/src/framing.c b/vendor/ogg/src/framing.c new file mode 100644 index 0000000..724d116 --- /dev/null +++ b/vendor/ogg/src/framing.c @@ -0,0 +1,2114 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: code raw packets into framed OggSquish stream and + decode Ogg streams back into raw packets + + note: The CRC code is directly derived from public domain code by + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html + for details. + + ********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +/* A complete description of Ogg framing exists in docs/framing.html */ + +int ogg_page_version(const ogg_page *og){ + return((int)(og->header[4])); +} + +int ogg_page_continued(const ogg_page *og){ + return((int)(og->header[5]&0x01)); +} + +int ogg_page_bos(const ogg_page *og){ + return((int)(og->header[5]&0x02)); +} + +int ogg_page_eos(const ogg_page *og){ + return((int)(og->header[5]&0x04)); +} + +ogg_int64_t ogg_page_granulepos(const ogg_page *og){ + unsigned char *page=og->header; + ogg_uint64_t granulepos=page[13]&(0xff); + granulepos= (granulepos<<8)|(page[12]&0xff); + granulepos= (granulepos<<8)|(page[11]&0xff); + granulepos= (granulepos<<8)|(page[10]&0xff); + granulepos= (granulepos<<8)|(page[9]&0xff); + granulepos= (granulepos<<8)|(page[8]&0xff); + granulepos= (granulepos<<8)|(page[7]&0xff); + granulepos= (granulepos<<8)|(page[6]&0xff); + return((ogg_int64_t)granulepos); +} + +int ogg_page_serialno(const ogg_page *og){ + return((int)((ogg_uint32_t)og->header[14]) | + ((ogg_uint32_t)og->header[15]<<8) | + ((ogg_uint32_t)og->header[16]<<16) | + ((ogg_uint32_t)og->header[17]<<24)); +} + +long ogg_page_pageno(const ogg_page *og){ + return((long)((ogg_uint32_t)og->header[18]) | + ((ogg_uint32_t)og->header[19]<<8) | + ((ogg_uint32_t)og->header[20]<<16) | + ((ogg_uint32_t)og->header[21]<<24)); +} + + + +/* returns the number of packets that are completed on this page (if + the leading packet is begun on a previous page, but ends on this + page, it's counted */ + +/* NOTE: + If a page consists of a packet begun on a previous page, and a new + packet begun (but not completed) on this page, the return will be: + ogg_page_packets(page) ==1, + ogg_page_continued(page) !=0 + + If a page happens to be a single packet that was begun on a + previous page, and spans to the next page (in the case of a three or + more page packet), the return will be: + ogg_page_packets(page) ==0, + ogg_page_continued(page) !=0 +*/ + +int ogg_page_packets(const ogg_page *og){ + int i,n=og->header[26],count=0; + for(i=0;iheader[27+i]<255)count++; + return(count); +} + + +#if 0 +/* helper to initialize lookup for direct-table CRC (illustrative; we + use the static init in crctable.h) */ + +static void _ogg_crc_init(){ + int i, j; + ogg_uint32_t polynomial, crc; + polynomial = 0x04c11db7; /* The same as the ethernet generator + polynomial, although we use an + unreflected alg and an init/final + of 0, not 0xffffffff */ + for (i = 0; i <= 0xFF; i++){ + crc = i << 24; + + for (j = 0; j < 8; j++) + crc = (crc << 1) ^ (crc & (1 << 31) ? polynomial : 0); + + crc_lookup[0][i] = crc; + } + + for (i = 0; i <= 0xFF; i++) + for (j = 1; j < 8; j++) + crc_lookup[j][i] = crc_lookup[0][(crc_lookup[j - 1][i] >> 24) & 0xFF] ^ (crc_lookup[j - 1][i] << 8); +} +#endif + +#include "crctable.h" + +/* init the encode/decode logical stream state */ + +int ogg_stream_init(ogg_stream_state *os,int serialno){ + if(os){ + memset(os,0,sizeof(*os)); + os->body_storage=16*1024; + os->lacing_storage=1024; + + os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); + os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); + os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); + + if(!os->body_data || !os->lacing_vals || !os->granule_vals){ + ogg_stream_clear(os); + return -1; + } + + os->serialno=serialno; + + return(0); + } + return(-1); +} + +/* async/delayed error detection for the ogg_stream_state */ +int ogg_stream_check(ogg_stream_state *os){ + if(!os || !os->body_data) return -1; + return 0; +} + +/* _clear does not free os, only the non-flat storage within */ +int ogg_stream_clear(ogg_stream_state *os){ + if(os){ + if(os->body_data)_ogg_free(os->body_data); + if(os->lacing_vals)_ogg_free(os->lacing_vals); + if(os->granule_vals)_ogg_free(os->granule_vals); + + memset(os,0,sizeof(*os)); + } + return(0); +} + +int ogg_stream_destroy(ogg_stream_state *os){ + if(os){ + ogg_stream_clear(os); + _ogg_free(os); + } + return(0); +} + +/* Helpers for ogg_stream_encode; this keeps the structure and + what's happening fairly clear */ + +static int _os_body_expand(ogg_stream_state *os,long needed){ + if(os->body_storage-needed<=os->body_fill){ + long body_storage; + void *ret; + if(os->body_storage>LONG_MAX-needed){ + ogg_stream_clear(os); + return -1; + } + body_storage=os->body_storage+needed; + if(body_storagebody_data,body_storage*sizeof(*os->body_data)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->body_storage=body_storage; + os->body_data=ret; + } + return 0; +} + +static int _os_lacing_expand(ogg_stream_state *os,long needed){ + if(os->lacing_storage-needed<=os->lacing_fill){ + long lacing_storage; + void *ret; + if(os->lacing_storage>LONG_MAX-needed){ + ogg_stream_clear(os); + return -1; + } + lacing_storage=os->lacing_storage+needed; + if(lacing_storagelacing_vals,lacing_storage*sizeof(*os->lacing_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->lacing_vals=ret; + ret=_ogg_realloc(os->granule_vals,lacing_storage* + sizeof(*os->granule_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->granule_vals=ret; + os->lacing_storage=lacing_storage; + } + return 0; +} + +/* checksum the page */ +/* Direct table CRC; note that this will be faster in the future if we + perform the checksum simultaneously with other copies */ + +static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int size){ + while (size>=8){ + crc^=((ogg_uint32_t)buffer[0]<<24)|((ogg_uint32_t)buffer[1]<<16)|((ogg_uint32_t)buffer[2]<<8)|((ogg_uint32_t)buffer[3]); + + crc=crc_lookup[7][ crc>>24 ]^crc_lookup[6][(crc>>16)&0xFF]^ + crc_lookup[5][(crc>> 8)&0xFF]^crc_lookup[4][ crc &0xFF]^ + crc_lookup[3][buffer[4] ]^crc_lookup[2][buffer[5] ]^ + crc_lookup[1][buffer[6] ]^crc_lookup[0][buffer[7] ]; + + buffer+=8; + size-=8; + } + + while (size--) + crc=(crc<<8)^crc_lookup[0][((crc >> 24)&0xff)^*buffer++]; + return crc; +} + +void ogg_page_checksum_set(ogg_page *og){ + if(og){ + ogg_uint32_t crc_reg=0; + + /* safety; needed for API behavior, but not framing code */ + og->header[22]=0; + og->header[23]=0; + og->header[24]=0; + og->header[25]=0; + + crc_reg=_os_update_crc(crc_reg,og->header,og->header_len); + crc_reg=_os_update_crc(crc_reg,og->body,og->body_len); + + og->header[22]=(unsigned char)(crc_reg&0xff); + og->header[23]=(unsigned char)((crc_reg>>8)&0xff); + og->header[24]=(unsigned char)((crc_reg>>16)&0xff); + og->header[25]=(unsigned char)((crc_reg>>24)&0xff); + } +} + +/* submit data to the internal buffer of the framing engine */ +int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, + long e_o_s, ogg_int64_t granulepos){ + + long bytes = 0, lacing_vals; + int i; + + if(ogg_stream_check(os)) return -1; + if(!iov) return 0; + + for (i = 0; i < count; ++i){ + if(iov[i].iov_len>LONG_MAX) return -1; + if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1; + bytes += (long)iov[i].iov_len; + } + lacing_vals=bytes/255+1; + + if(os->body_returned){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + os->body_fill-=os->body_returned; + if(os->body_fill) + memmove(os->body_data,os->body_data+os->body_returned, + os->body_fill); + os->body_returned=0; + } + + /* make sure we have the buffer storage */ + if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) + return -1; + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + for (i = 0; i < count; ++i) { + memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len); + os->body_fill += (int)iov[i].iov_len; + } + + /* Store lacing vals for this packet */ + for(i=0;ilacing_vals[os->lacing_fill+i]=255; + os->granule_vals[os->lacing_fill+i]=os->granulepos; + } + os->lacing_vals[os->lacing_fill+i]=bytes%255; + os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos; + + /* flag the first segment as the beginning of the packet */ + os->lacing_vals[os->lacing_fill]|= 0x100; + + os->lacing_fill+=lacing_vals; + + /* for the sake of completeness */ + os->packetno++; + + if(e_o_s)os->e_o_s=1; + + return(0); +} + +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ + ogg_iovec_t iov; + iov.iov_base = op->packet; + iov.iov_len = op->bytes; + return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos); +} + +/* Conditionally flush a page; force==0 will only flush nominal-size + pages, force==1 forces us to flush a page regardless of page size + so long as there's any data available at all. */ +static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ + int i; + int vals=0; + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); + int bytes=0; + long acc=0; + ogg_int64_t granule_pos=-1; + + if(ogg_stream_check(os)) return(0); + if(maxvals==0) return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(os->b_o_s==0){ /* 'initial header page' case */ + granule_pos=0; + for(vals=0;valslacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + }else{ + + /* The extra packets_done, packet_just_done logic here attempts to do two things: + 1) Don't unnecessarily span pages. + 2) Unless necessary, don't flush pages if there are less than four packets on + them; this expands page size to reduce unnecessary overhead if incoming packets + are large. + These are not necessary behaviors, just 'always better than naive flushing' + without requiring an application to explicitly request a specific optimized + behavior. We'll want an explicit behavior setup pathway eventually as well. */ + + int packets_done=0; + int packet_just_done=0; + for(vals=0;valsnfill && packet_just_done>=4){ + force=1; + break; + } + acc+=os->lacing_vals[vals]&0x0ff; + if((os->lacing_vals[vals]&0xff)<255){ + granule_pos=os->granule_vals[vals]; + packet_just_done=++packets_done; + }else + packet_just_done=0; + } + if(vals==255)force=1; + } + + if(!force) return(0); + + /* construct the header in temp storage */ + memcpy(os->header,"OggS",4); + + /* stream structure version */ + os->header[4]=0x00; + + /* continued packet flag? */ + os->header[5]=0x00; + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; + /* first page flag? */ + if(os->b_o_s==0)os->header[5]|=0x02; + /* last page flag? */ + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; + os->b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + os->header[i]=(unsigned char)(granule_pos&0xff); + granule_pos>>=8; + } + + /* 32 bits of stream serial number */ + { + long serialno=os->serialno; + for(i=14;i<18;i++){ + os->header[i]=(unsigned char)(serialno&0xff); + serialno>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(os->pageno==-1)os->pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + long pageno=os->pageno++; + for(i=18;i<22;i++){ + os->header[i]=(unsigned char)(pageno&0xff); + pageno>>=8; + } + } + + /* zero for computation; filled in later */ + os->header[22]=0; + os->header[23]=0; + os->header[24]=0; + os->header[25]=0; + + /* segment table */ + os->header[26]=(unsigned char)(vals&0xff); + for(i=0;iheader[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); + + /* set pointers in the ogg_page struct */ + og->header=os->header; + og->header_len=os->header_fill=vals+27; + og->body=os->body_data+os->body_returned; + og->body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + + os->lacing_fill-=vals; + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); + os->body_returned+=bytes; + + /* calculate the checksum */ + + ogg_page_checksum_set(og); + + /* done */ + return(1); +} + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not guarantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + since ogg_stream_flush will flush the last page in a stream even if + it's undersized, you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you specifically need to flush + a page regardless of size in the middle of a stream. */ + +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ + return ogg_stream_flush_i(os,og,1,4096); +} + +/* Like the above, but an argument is provided to adjust the nominal + page size for applications which are smart enough to provide their + own delay based flushing */ + +int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ + return ogg_stream_flush_i(os,og,1,nfill); +} + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,4096)); +} + +/* Like the above, but an argument is provided to adjust the nominal +page size for applications which are smart enough to provide their +own delay based flushing */ + +int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,nfill)); +} + +int ogg_stream_eos(ogg_stream_state *os){ + if(ogg_stream_check(os)) return 1; + return os->e_o_s; +} + +/* DECODING PRIMITIVES: packet streaming layer **********************/ + +/* This has two layers to place more of the multi-serialno and paging + control in the application's hands. First, we expose a data buffer + using ogg_sync_buffer(). The app either copies into the + buffer, or passes it directly to read(), etc. We then call + ogg_sync_wrote() to tell how many bytes we just added. + + Pages are returned (pointers into the buffer in ogg_sync_state) + by ogg_sync_pageout(). The page is then submitted to + ogg_stream_pagein() along with the appropriate + ogg_stream_state* (ie, matching serialno). We then get raw + packets out calling ogg_stream_packetout() with a + ogg_stream_state. */ + +/* initialize the struct to a known state */ +int ogg_sync_init(ogg_sync_state *oy){ + if(oy){ + oy->storage = -1; /* used as a readiness flag */ + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +/* clear non-flat storage within */ +int ogg_sync_clear(ogg_sync_state *oy){ + if(oy){ + if(oy->data)_ogg_free(oy->data); + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +int ogg_sync_destroy(ogg_sync_state *oy){ + if(oy){ + ogg_sync_clear(oy); + _ogg_free(oy); + } + return(0); +} + +int ogg_sync_check(ogg_sync_state *oy){ + if(oy->storage<0) return -1; + return 0; +} + +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ + if(ogg_sync_check(oy)) return NULL; + + /* first, clear out any space that has been previously returned */ + if(oy->returned){ + oy->fill-=oy->returned; + if(oy->fill>0) + memmove(oy->data,oy->data+oy->returned,oy->fill); + oy->returned=0; + } + + if(size>oy->storage-oy->fill){ + /* We need to extend the internal buffer */ + 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 + ret=_ogg_malloc(newsize); + if(!ret){ + ogg_sync_clear(oy); + return NULL; + } + oy->data=ret; + oy->storage=newsize; + } + + /* expose a segment at least as large as requested at the fill mark */ + return((char *)oy->data+oy->fill); +} + +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ + if(ogg_sync_check(oy))return -1; + if(oy->fill+bytes>oy->storage)return -1; + oy->fill+=bytes; + return(0); +} + +/* sync the stream. This is meant to be useful for finding page + boundaries. + + return values for this: + -n) skipped n bytes + 0) page not ready; more data (no bytes skipped) + n) page synced at current location; page length n bytes + +*/ + +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ + unsigned char *page=oy->data+oy->returned; + unsigned char *next; + long bytes=oy->fill-oy->returned; + + if(ogg_sync_check(oy))return 0; + + if(oy->headerbytes==0){ + int headerbytes,i; + if(bytes<27)return(0); /* not enough for a header */ + + /* verify capture pattern */ + if(memcmp(page,"OggS",4))goto sync_fail; + + headerbytes=page[26]+27; + if(bytesbodybytes+=page[27+i]; + oy->headerbytes=headerbytes; + } + + if(oy->bodybytes+oy->headerbytes>bytes)return(0); + + /* The whole test page is buffered. Verify the checksum */ + { + /* Grab the checksum bytes, set the header field to zero */ + char chksum[4]; + ogg_page log; + + memcpy(chksum,page+22,4); + memset(page+22,0,4); + + /* set up a temp page struct and recompute the checksum */ + log.header=page; + log.header_len=oy->headerbytes; + log.body=page+oy->headerbytes; + log.body_len=oy->bodybytes; + ogg_page_checksum_set(&log); + + /* Compare */ + if(memcmp(chksum,page+22,4)){ + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page + at all) */ + /* replace the computed checksum with the one actually read in */ + memcpy(page+22,chksum,4); + +#ifndef DISABLE_CRC + /* Bad checksum. Lose sync */ + goto sync_fail; +#endif + } + } + + /* yes, have a whole page all ready to go */ + { + if(og){ + og->header=page; + og->header_len=oy->headerbytes; + og->body=page+oy->headerbytes; + og->body_len=oy->bodybytes; + } + + oy->unsynced=0; + oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); + oy->headerbytes=0; + oy->bodybytes=0; + return(bytes); + } + + sync_fail: + + oy->headerbytes=0; + oy->bodybytes=0; + + /* search for possible capture */ + next=memchr(page+1,'O',bytes-1); + if(!next) + next=oy->data+oy->fill; + + oy->returned=(int)(next-oy->data); + return((long)-(next-page)); +} + +/* sync the stream and get a page. Keep trying until we find a page. + Suppress 'sync errors' after reporting the first. + + return values: + -1) recapture (hole in data) + 0) need more data + 1) page returned + + Returns pointers into buffered data; invalidated by next call to + _stream, _clear, _init, or _buffer */ + +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ + + if(ogg_sync_check(oy))return 0; + + /* all we need to do is verify a page at the head of the stream + buffer. If it doesn't verify, we look for the next potential + frame */ + + for(;;){ + long ret=ogg_sync_pageseek(oy,og); + if(ret>0){ + /* have a page */ + return(1); + } + if(ret==0){ + /* need more data */ + return(0); + } + + /* head did not start a synced page... skipped some bytes */ + if(!oy->unsynced){ + oy->unsynced=1; + return(-1); + } + + /* loop. keep looking */ + + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ + unsigned char *header=og->header; + unsigned char *body=og->body; + long bodysize=og->body_len; + int segptr=0; + + int version=ogg_page_version(og); + int continued=ogg_page_continued(og); + int bos=ogg_page_bos(og); + int eos=ogg_page_eos(og); + ogg_int64_t granulepos=ogg_page_granulepos(og); + int serialno=ogg_page_serialno(og); + long pageno=ogg_page_pageno(og); + int segments=header[26]; + + if(ogg_stream_check(os)) return -1; + + /* clean up 'returned data' */ + { + long lr=os->lacing_returned; + long br=os->body_returned; + + /* body data */ + if(br){ + os->body_fill-=br; + if(os->body_fill) + memmove(os->body_data,os->body_data+br,os->body_fill); + os->body_returned=0; + } + + if(lr){ + /* segment table */ + if(os->lacing_fill-lr){ + memmove(os->lacing_vals,os->lacing_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->granule_vals)); + } + os->lacing_fill-=lr; + os->lacing_packet-=lr; + os->lacing_returned=0; + } + } + + /* check the serial number */ + if(serialno!=os->serialno)return(-1); + if(version>0)return(-1); + + if(_os_lacing_expand(os,segments+1)) return -1; + + /* are we in sequence? */ + if(pageno!=os->pageno){ + int i; + + /* unroll previous partial packet (if any) */ + for(i=os->lacing_packet;ilacing_fill;i++) + os->body_fill-=os->lacing_vals[i]&0xff; + os->lacing_fill=os->lacing_packet; + + /* make a note of dropped data in segment table */ + if(os->pageno!=-1){ + os->lacing_vals[os->lacing_fill++]=0x400; + os->lacing_packet++; + } + } + + /* are we a 'continued packet' page? If so, we may need to skip + some segments */ + if(continued){ + if(os->lacing_fill<1 || + (os->lacing_vals[os->lacing_fill-1]&0xff)<255 || + os->lacing_vals[os->lacing_fill-1]==0x400){ + bos=0; + for(;segptrbody_data+os->body_fill,body,bodysize); + os->body_fill+=bodysize; + } + + { + int saved=-1; + while(segptrlacing_vals[os->lacing_fill]=val; + os->granule_vals[os->lacing_fill]=-1; + + if(bos){ + os->lacing_vals[os->lacing_fill]|=0x100; + bos=0; + } + + if(val<255)saved=os->lacing_fill; + + os->lacing_fill++; + segptr++; + + if(val<255)os->lacing_packet=os->lacing_fill; + } + + /* set the granulepos on the last granuleval of the last full packet */ + if(saved!=-1){ + os->granule_vals[saved]=granulepos; + } + + } + + if(eos){ + os->e_o_s=1; + if(os->lacing_fill>0) + os->lacing_vals[os->lacing_fill-1]|=0x200; + } + + os->pageno=pageno+1; + + return(0); +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int ogg_sync_reset(ogg_sync_state *oy){ + if(ogg_sync_check(oy))return -1; + + oy->fill=0; + oy->returned=0; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return(0); +} + +int ogg_stream_reset(ogg_stream_state *os){ + if(ogg_stream_check(os)) return -1; + + os->body_fill=0; + os->body_returned=0; + + os->lacing_fill=0; + os->lacing_packet=0; + os->lacing_returned=0; + + os->header_fill=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->granulepos=0; + + return(0); +} + +int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ + if(ogg_stream_check(os)) return -1; + ogg_stream_reset(os); + os->serialno=serialno; + return(0); +} + +static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ + + /* The last part of decode. We have the stream broken into packet + segments. Now we need to group them into packets (or return the + out of sync markers) */ + + int ptr=os->lacing_returned; + + if(os->lacing_packet<=ptr)return(0); + + if(os->lacing_vals[ptr]&0x400){ + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + os->lacing_returned++; + os->packetno++; + return(-1); + } + + if(!op && !adv)return(1); /* just using peek as an inexpensive way + to ask if there's a whole packet + waiting */ + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=os->lacing_vals[ptr]&0xff; + long bytes=size; + int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ + int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ + + while(size==255){ + int val=os->lacing_vals[++ptr]; + size=val&0xff; + if(val&0x200)eos=0x200; + bytes+=size; + } + + if(op){ + op->e_o_s=eos; + op->b_o_s=bos; + op->packet=os->body_data+os->body_returned; + op->packetno=os->packetno; + op->granulepos=os->granule_vals[ptr]; + op->bytes=bytes; + } + + if(adv){ + os->body_returned+=bytes; + os->lacing_returned=ptr+1; + os->packetno++; + } + } + return(1); +} + +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,1); +} + +int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,0); +} + +void ogg_packet_clear(ogg_packet *op) { + _ogg_free(op->packet); + memset(op, 0, sizeof(*op)); +} + +#ifdef _V_SELFTEST +#include + +ogg_stream_state os_en, os_de; +ogg_sync_state oy; + +void checkpacket(ogg_packet *op,long len, int no, long pos){ + long j; + static int sequence=0; + static int lastno=0; + + if(op->bytes!=len){ + fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len); + exit(1); + } + if(op->granulepos!=pos){ + fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos); + exit(1); + } + + /* packet number just follows sequence/gap; adjust the input number + for that */ + if(no==0){ + sequence=0; + }else{ + sequence++; + if(no>lastno+1) + sequence++; + } + lastno=no; + if(op->packetno!=sequence){ + fprintf(stderr,"incorrect packet sequence %ld != %d\n", + (long)(op->packetno),sequence); + exit(1); + } + + /* Test data */ + for(j=0;jbytes;j++) + if(op->packet[j]!=((j+no)&0xff)){ + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", + j,op->packet[j],(j+no)&0xff); + exit(1); + } +} + +void check_page(unsigned char *data,const int *header,ogg_page *og){ + long j; + /* Test data */ + for(j=0;jbody_len;j++) + if(og->body[j]!=data[j]){ + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", + j,data[j],og->body[j]); + exit(1); + } + + /* Test header */ + for(j=0;jheader_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;jheader[j]); + fprintf(stderr,"\n"); + exit(1); + } + } + if(og->header_len!=header[26]+27){ + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", + og->header_len,header[26]+27); + exit(1); + } +} + +void print_header(ogg_page *og){ + int j; + fprintf(stderr,"\nHEADER:\n"); + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", + og->header[0],og->header[1],og->header[2],og->header[3], + (int)og->header[4],(int)og->header[5]); + + fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", + (og->header[9]<<24)|(og->header[8]<<16)| + (og->header[7]<<8)|og->header[6], + (og->header[17]<<24)|(og->header[16]<<16)| + (og->header[15]<<8)|og->header[14], + ((long)(og->header[21])<<24)|(og->header[20]<<16)| + (og->header[19]<<8)|og->header[18]); + + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", + (int)og->header[22],(int)og->header[23], + (int)og->header[24],(int)og->header[25], + (int)og->header[26]); + + for(j=27;jheader_len;j++) + fprintf(stderr,"%d ",(int)og->header[j]); + fprintf(stderr,")\n\n"); +} + +void copy_page(ogg_page *og){ + unsigned char *temp=_ogg_malloc(og->header_len); + memcpy(temp,og->header,og->header_len); + og->header=temp; + + temp=_ogg_malloc(og->body_len); + memcpy(temp,og->body,og->body_len); + og->body=temp; +} + +void free_page(ogg_page *og){ + _ogg_free (og->header); + _ogg_free (og->body); +} + +void error(void){ + fprintf(stderr,"error!\n"); + exit(1); +} + +/* 17 only */ +const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x15,0xed,0xec,0x91, + 1, + 17}; + +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ +const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x59,0x10,0x6c,0x2c, + 1, + 17}; +const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x89,0x33,0x85,0xce, + 13, + 254,255,0,255,1,255,245,255,255,0, + 255,255,90}; + +/* nil packets; beginning,middle,end */ +const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; +const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x5c,0x3f,0x66,0xcb, + 17, + 17,254,255,0,0,255,1,0,255,245,255,255,0, + 255,255,90,0}; + +/* large initial packet */ +const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x01,0x27,0x31,0xaa, + 18, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10}; + +const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x7f,0x4e,0x8a,0xd2, + 4, + 255,4,255,0}; + + +/* continuing packet test */ +const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xf8,0x3c,0x19,0x79, + 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,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,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,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,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}; + +const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x38,0xe6,0xb6,0x28, + 6, + 255,220,255,4,255,0}; + + +/* spill expansion test */ +const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xce,0x8f,0x17,0x1a, + 23, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0}; + + +const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x9b,0xb2,0x50,0xa1, + 1, + 0}; + +/* page with the 255 segment limit */ +const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xed,0x2a,0x2e,0xa7, + 255, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10}; + +const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x6c,0x3b,0x82,0x3d, + 1, + 50}; + + +/* packet that overspans over an entire page */ +const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 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,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,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,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, + 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}; + +const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xf4,0x87,0xba,0xf3, + 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,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,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,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,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}; + +const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,3,0,0,0, + 0xf7,0x2f,0x6c,0x60, + 5, + 254,255,4,255,0}; + +/* packet that overspans over an entire page */ +const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 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,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,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,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, + 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}; + +const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xd4,0xe0,0x60,0xe5, + 1, + 0}; + +int compare_packet(const ogg_packet *op1, const ogg_packet *op2){ + if(op1->packet!=op2->packet){ + fprintf(stderr,"op1->packet != op2->packet\n"); + return(1); + } + if(op1->bytes!=op2->bytes){ + fprintf(stderr,"op1->bytes != op2->bytes\n"); + return(1); + } + if(op1->b_o_s!=op2->b_o_s){ + fprintf(stderr,"op1->b_o_s != op2->b_o_s\n"); + return(1); + } + if(op1->e_o_s!=op2->e_o_s){ + fprintf(stderr,"op1->e_o_s != op2->e_o_s\n"); + return(1); + } + if(op1->granulepos!=op2->granulepos){ + fprintf(stderr,"op1->granulepos != op2->granulepos\n"); + return(1); + } + if(op1->packetno!=op2->packetno){ + fprintf(stderr,"op1->packetno != op2->packetno\n"); + return(1); + } + return(0); +} + +void test_pack(const int *pl, const int **headers, int byteskip, + int pageskip, int packetskip){ + unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ + long inptr=0; + long outptr=0; + long deptr=0; + long depacket=0; + long granule_pos=7,pageno=0; + int i,j,packets,pageout=pageskip; + int eosflag=0; + int bosflag=0; + + int byteskipcount=0; + + ogg_stream_reset(&os_en); + ogg_stream_reset(&os_de); + ogg_sync_reset(&oy); + + for(packets=0;packetsbyteskip){ + memcpy(next,og.header,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + byteskipcount+=og.body_len; + if(byteskipcount>byteskip){ + memcpy(next,og.body,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + ogg_sync_wrote(&oy,(long)(next-buf)); + + while(1){ + int ret=ogg_sync_pageout(&oy,&og_de); + if(ret==0)break; + if(ret<0)continue; + /* got a page. Happy happy. Verify that it's good. */ + + fprintf(stderr,"(%d), ",pageout); + + check_page(data+deptr,headers[pageout],&og_de); + deptr+=og_de.body_len; + pageout++; + + /* submit it to deconstitution */ + ogg_stream_pagein(&os_de,&og_de); + + /* packets out? */ + while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ + ogg_stream_packetpeek(&os_de,NULL); + ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ + + /* verify peek and out match */ + if(compare_packet(&op_de,&op_de2)){ + fprintf(stderr,"packetout != packetpeek! pos=%ld\n", + depacket); + exit(1); + } + + /* verify the packet! */ + /* check data */ + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", + depacket); + exit(1); + } + /* check bos flag */ + if(bosflag==0 && op_de.b_o_s==0){ + fprintf(stderr,"b_o_s flag not set on packet!\n"); + exit(1); + } + if(bosflag && op_de.b_o_s){ + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); + exit(1); + } + bosflag=1; + depacket+=op_de.bytes; + + /* check eos flag */ + if(eosflag){ + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); + exit(1); + } + + if(op_de.e_o_s)eosflag=1; + + /* check granulepos flag */ + if(op_de.granulepos!=-1){ + fprintf(stderr," granule:%ld ",(long)op_de.granulepos); + } + } + } + } + } + } + } + _ogg_free(data); + if(headers[pageno]!=NULL){ + fprintf(stderr,"did not write last page!\n"); + exit(1); + } + if(headers[pageout]!=NULL){ + fprintf(stderr,"did not decode last page!\n"); + exit(1); + } + if(inptr!=outptr){ + fprintf(stderr,"encoded page data incomplete!\n"); + exit(1); + } + if(inptr!=deptr){ + fprintf(stderr,"decoded page data incomplete!\n"); + exit(1); + } + if(inptr!=depacket){ + fprintf(stderr,"decoded packet data incomplete!\n"); + exit(1); + } + if(!eosflag){ + fprintf(stderr,"Never got a packet with EOS set!\n"); + exit(1); + } + fprintf(stderr,"ok.\n"); +} + +int main(void){ + + ogg_stream_init(&os_en,0x04030201); + ogg_stream_init(&os_de,0x04030201); + ogg_sync_init(&oy); + + /* Exercise each code path in the framing code. Also verify that + the checksums are working. */ + + { + /* 17 only */ + const int packets[]={17, -1}; + const int *headret[]={head1_0,NULL}; + + fprintf(stderr,"testing single page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; + const int *headret[]={head1_1,head2_1,NULL}; + + fprintf(stderr,"testing basic page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* nil packets; beginning,middle,end */ + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; + const int *headret[]={head1_2,head2_2,NULL}; + + fprintf(stderr,"testing basic nil packets... "); + test_pack(packets,headret,0,0,0); + } + + { + /* large initial packet */ + const int packets[]={4345,259,255,-1}; + const int *headret[]={head1_3,head2_3,NULL}; + + fprintf(stderr,"testing initial-packet lacing > 4k... "); + test_pack(packets,headret,0,0,0); + } + + { + /* continuing packet test; with page spill expansion, we have to + overflow the lacing table. */ + const int packets[]={0,65500,259,255,-1}; + const int *headret[]={head1_4,head2_4,head3_4,NULL}; + + fprintf(stderr,"testing single packet page span... "); + test_pack(packets,headret,0,0,0); + } + + { + /* spill expand packet test */ + const int packets[]={0,4345,259,255,0,0,-1}; + const int *headret[]={head1_4b,head2_4b,head3_4b,NULL}; + + fprintf(stderr,"testing page spill expansion... "); + test_pack(packets,headret,0,0,0); + } + + /* page with the 255 segment limit */ + { + + const int packets[]={0,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,50,-1}; + const int *headret[]={head1_5,head2_5,head3_5,NULL}; + + fprintf(stderr,"testing max packet segments... "); + test_pack(packets,headret,0,0,0); + } + + { + /* packet that overspans over an entire page */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing very large packets... "); + test_pack(packets,headret,0,0,0); + } + +#ifndef DISABLE_CRC + { + /* test for the libogg 1.1.1 resync in large continuation bug + found by Josh Coalson) */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing continuation resync in very large packets... "); + test_pack(packets,headret,100,2,3); + } +#else + fprintf(stderr,"Skipping continuation resync test due to --disable-crc\n"); +#endif + + { + /* term only page. why not? */ + const int packets[]={0,100,64770,-1}; + const int *headret[]={head1_7,head2_7,head3_7,NULL}; + + fprintf(stderr,"testing zero data page (1 nil packet)... "); + test_pack(packets,headret,0,0,0); + } + + + + { + /* build a bunch of pages for testing */ + unsigned char *data=_ogg_malloc(1024*1024); + int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; + int inptr=0,i,j; + ogg_page og[5]; + + ogg_stream_reset(&os_en); + + for(i=0;pl[i]!=-1;i++){ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.granulepos=(i+1)*1000; + + for(j=0;j0)error(); + + /* Test fractional page inputs: incomplete fixed header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, + 5); + ogg_sync_wrote(&oy,5); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete body */ + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, + og[1].header_len-28); + ogg_sync_wrote(&oy,og[1].header_len-28); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); + ogg_sync_wrote(&oy,1000); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, + og[1].body_len-1000); + ogg_sync_wrote(&oy,og[1].body_len-1000); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test fractional page inputs: page + incomplete capture */ + { + ogg_page og_de; + fprintf(stderr,"Testing sync on 1+partial inputs... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, + og[1].header_len-20); + ogg_sync_wrote(&oy,og[1].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing search for capture... "); + ogg_sync_reset(&oy); + + /* 'garbage' */ + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, + og[2].header_len-20); + ogg_sync_wrote(&oy,og[2].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len); + ogg_sync_wrote(&oy,og[2].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + +#ifndef DISABLE_CRC + /* Test recapture: page + garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing recapture... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len-5); + ogg_sync_wrote(&oy,og[2].body_len-5); + + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, + og[3].header_len); + ogg_sync_wrote(&oy,og[3].header_len); + + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, + og[3].body_len); + ogg_sync_wrote(&oy,og[3].body_len); + + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } +#else + fprintf(stderr,"Skipping recapture test due to --disable-crc\n"); +#endif + + /* Free page data that was previously copied */ + { + for(i=0;i<5;i++){ + free_page(&og[i]); + } + } + } + ogg_sync_clear(&oy); + ogg_stream_clear(&os_en); + ogg_stream_clear(&os_de); + + return(0); +} + +#endif diff --git a/vendor/vorbis/AUTHORS b/vendor/vorbis/AUTHORS new file mode 100644 index 0000000..0da1036 --- /dev/null +++ b/vendor/vorbis/AUTHORS @@ -0,0 +1,3 @@ +Monty + +and the rest of the Xiph.org Foundation. diff --git a/vendor/vorbis/COPYING b/vendor/vorbis/COPYING new file mode 100644 index 0000000..fb456a8 --- /dev/null +++ b/vendor/vorbis/COPYING @@ -0,0 +1,28 @@ +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 +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/vorbis/README.md b/vendor/vorbis/README.md new file mode 100644 index 0000000..30c88d3 --- /dev/null +++ b/vendor/vorbis/README.md @@ -0,0 +1,147 @@ +# Vorbis + +[![GitLab Build Status](https://gitlab.xiph.org/xiph/vorbis/badges/master/pipeline.svg)](https://gitlab.xiph.org/xiph/vorbis/-/pipelines) +[![Travis Build Status](https://travis-ci.org/xiph/vorbis.svg?branch=master)](https://travis-ci.org/xiph/vorbis) +[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/github/xiph/vorbis?branch=master&svg=true)](https://ci.appveyor.com/project/rillian/vorbis) + +Vorbis is a general purpose audio and music encoding format +contemporary to MPEG-4's AAC and TwinVQ, the next generation beyond +MPEG audio layer 3. Unlike the MPEG sponsored formats (and other +proprietary formats such as RealAudio G2 and Windows' flavor of the +month), the Vorbis CODEC specification belongs to the public domain. +All the technical details are published and documented, and any +software entity may make full use of the format without license +fee, royalty or patent concerns. + +This package contains: + +- libvorbis, a BSD-style license software implementation of + the Vorbis specification by the Xiph.Org Foundation + (https://xiph.org/) + +- libvorbisfile, a BSD-style license convenience library + built on Vorbis designed to simplify common uses + +- libvorbisenc, a BSD-style license library that provides a simple, + programmatic encoding setup interface + +- example code making use of libogg, libvorbis, libvorbisfile and + libvorbisenc + +## What's here ## + +This source distribution includes libvorbis and an example +encoder/player to demonstrate use of libvorbis as well as +documentation on the Ogg Vorbis audio coding format. + +You'll need libogg (distributed separately) to compile this library. +A more comprehensive set of utilities is available in the vorbis-tools +package. + +Directory: + +- `lib` The source for the libraries, a BSD-license implementation of the public domain Ogg Vorbis audio encoding format. + +- `include` Library API headers + +- `debian` Rules/spec files for building Debian .deb packages + +- `doc` Vorbis documentation + +- `examples` Example code illustrating programmatic use of libvorbis, libvorbisfile and libvorbisenc + +- `macosx` Project files for MacOS X. + +- `win32` Win32 projects files and build automation + +- `vq` Internal utilities for training/building new LSP/residue and auxiliary codebooks. + +## Contact ## + +The Ogg homepage is located at 'https://xiph.org/ogg/'. +Vorbis's homepage is located at 'https://xiph.org/vorbis/'. +Up to date technical documents, contact information, source code and +pre-built utilities may be found there. + +## Building ## + +#### Building from master #### + +Development source is under git revision control at +https://gitlab.xiph.org/xiph/vorbis.git. You will also need the +newest versions of autoconf, automake, libtool and pkg-config in +order to compile Vorbis from development source. A configure script +is provided for you in the source tarball distributions. + + ./autogen.sh + ./configure + make + +and as root if desired: + + make install + +This will install the Vorbis libraries (static and shared) into +/usr/local/lib, includes into /usr/local/include and API manpages +(once we write some) into /usr/local/man. + +Documentation building requires xsltproc and pdfxmltex. + +#### Building from tarball distributions #### + + ./configure + make + +and optionally (as root): + + make install + +#### Building RPM packages #### + +after normal configuring: + + make dist + rpm -ta libvorbis-.tar.gz + +## Building with CMake ## + +Ogg supports building using [CMake](https://cmake.org/). CMake is a meta build system that generates native projects for each platform. +To generate projects just run cmake replacing `YOUR-PROJECT-GENERATOR` with a proper generator from a list [here](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html): + + cmake -G YOUR-PROJECT-GENERATOR . + +Note that by default cmake generates projects that will build static libraries. +To generate projects that will build dynamic library use `BUILD_SHARED_LIBS` option like this: + + cmake -G YOUR-PROJECT-GENERATOR -DBUILD_SHARED_LIBS=1 . + +After projects are generated use them as usual + +#### Building on Windows #### + +Use proper generator for your Visual Studio version like: + + cmake -G "Visual Studio 12 2013" . + +#### Building on Mac OS X #### + +Use Xcode generator. To build framework run: + + cmake -G Xcode -DBUILD_FRAMEWORK=1 . + +#### Building on Linux #### + +Use Makefile generator which is default one. + + cmake . + make + +## License ## + +THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. +USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS +GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE +IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. + +THE OggVorbis SOURCE CODE IS COPYRIGHT (C) 1994-2020 +by the Xiph.Org Foundation https://xiph.org/ diff --git a/vendor/vorbis/build-vorbis.lua b/vendor/vorbis/build-vorbis.lua new file mode 100644 index 0000000..8470dee --- /dev/null +++ b/vendor/vorbis/build-vorbis.lua @@ -0,0 +1,64 @@ +project"vorbis" + cppdialect"c++17" + kind"staticLib" + targetdir"bin" + staticruntime "off" + + includedirs + { + "include", + "../ogg/include" + } + + files + { + "lib/envelope.h", + "lib/lpc.h", + "lib/lsp.h", + "lib/codebook.h", + "lib/misc.h", + "lib/psy.h", + "lib/masking.h", + "lib/os.h", + "lib/mdct.h", + "lib/smallft.h", + "lib/highlevel.h", + "lib/registry.h", + "lib/scales.h", + "lib/window.h", + "lib/lookup.h", + "lib/lookup_data.h", + "lib/codec_internal.h", + "lib/backends.h", + "lib/bitrate.h", + "lib/mdct.c", + "lib/smallft.c", + "lib/block.c", + "lib/envelope.c", + "lib/window.c", + "lib/lsp.c", + "lib/lpc.c", + "lib/analysis.c", + "lib/synthesis.c", + "lib/psy.c", + "lib/info.c", + "lib/floor1.c", + "lib/floor0.c", + "lib/res0.c", + "lib/mapping0.c", + "lib/registry.c", + "lib/codebook.c", + "lib/sharedbook.c", + "lib/lookup.c", + "lib/bitrate.c", + "lib/vorbisfile.c", + "lib/vorbisenc.c", + } + + filter "configurations:Debug" + runtime "Debug" + symbols "on" + + filter "configurations:Release" + runtime "Release" + optimize "Speed" \ No newline at end of file diff --git a/vendor/vorbis/contrib/oss-fuzz/build.sh b/vendor/vorbis/contrib/oss-fuzz/build.sh new file mode 100644 index 0000000..1f76b4a --- /dev/null +++ b/vendor/vorbis/contrib/oss-fuzz/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash -eu + +pushd $SRC +mv people.xiph.org/*.ogg decode_corpus/ +zip -r "$OUT/decode_fuzzer_seed_corpus.zip" decode_corpus/ +popd + +pushd $SRC/ogg +./autogen.sh +./configure --prefix="$WORK" --enable-static --disable-shared --disable-crc +make clean +make -j$(nproc) +make install +popd + + +./autogen.sh +./configure --prefix="$WORK" --enable-static --disable-shared +make clean +make -j$(nproc) +make install + +$CXX $CXXFLAGS $SRC/vorbis/contrib/oss-fuzz/decode_fuzzer.cc -o $OUT/decode_fuzzer -L"$WORK/lib" -I"$WORK/include" $LIB_FUZZING_ENGINE -lvorbisfile -lvorbis -logg diff --git a/vendor/vorbis/contrib/oss-fuzz/decode_fuzzer.cc b/vendor/vorbis/contrib/oss-fuzz/decode_fuzzer.cc new file mode 100644 index 0000000..b8840c1 --- /dev/null +++ b/vendor/vorbis/contrib/oss-fuzz/decode_fuzzer.cc @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +struct vorbis_data { + const uint8_t *current; + const uint8_t *data; + size_t size; +}; + +size_t read_func(void *ptr, size_t size1, size_t size2, void *datasource) { + vorbis_data* vd = (vorbis_data *)(datasource); + size_t len = size1 * size2; + if (vd->current + len > vd->data + vd->size) { + len = vd->data + vd->size - vd->current; + } + memcpy(ptr, vd->current, len); + vd->current += len; + return len; +} + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + ov_callbacks memory_callbacks = {0}; + memory_callbacks.read_func = read_func; + vorbis_data data_st; + data_st.size = Size; + data_st.current = Data; + data_st.data = Data; + OggVorbis_File vf; + int result = ov_open_callbacks(&data_st, &vf, NULL, 0, memory_callbacks); + if (result < 0) { + return 0; + } + int current_section = 0; + int eof = 0; + char buf[4096]; + int read_result; + while (!eof) { + read_result = ov_read(&vf, buf, sizeof(buf), 0, 2, 1, ¤t_section); + if (read_result != OV_HOLE && read_result <= 0) { + eof = 1; + } + } + ov_clear(&vf); + return 0; +} diff --git a/vendor/vorbis/debian/changelog b/vendor/vorbis/debian/changelog new file mode 100644 index 0000000..fae34ba --- /dev/null +++ b/vendor/vorbis/debian/changelog @@ -0,0 +1,208 @@ +libvorbis (1.2.0.dfsg-3.1) unstable; urgency=high + + * Non-maintainer upload by the security team + * Fix integer overflows (and possible DoS attacks) via crafted + OGG files (Closes: #482518) + Fixes: CVE-2008-1423, CVE-2008-1420, CVE-2008-1419 + + -- Steffen Joeris Mon, 26 May 2008 12:48:06 +0000 + +libvorbis (1.2.0.dfsg-3) unstable; urgency=low + + * Use dpkg-gensymbols, with symbol files obtained from Mole (stripping + debian revision and .dfsg suffix). + + * Install upstream CHANGES file as changelog.gz. (Closes: #302037) + + * Bump debian/compat to 5, and Standards-Version to 3.7.3 (no changes + needed). + + * Use quilt.make in debian/rules. + + -- Adeodato Simó Thu, 27 Dec 2007 14:33:45 +0100 + +libvorbis (1.2.0.dfsg-2) unstable; urgency=high + + * Bump shlibs for libvorbis0a due to new vorbis_synthesis_idheader header. + (Closes: #436083) + + -- Adeodato Simó Tue, 14 Aug 2007 20:55:54 +0200 + +libvorbis (1.2.0.dfsg-1) unstable; urgency=low + + [ Adeodato Simó ] + * Use ${binary:Version} instead of ${Source-Version}. + + [ Clint Adams ] + * New upstream release. + - Remove upstream_r13198-fix_segfault_in_ov_time_seek.diff . + * Bump shlibs for libvorbisfile3 to >= 1.2.0 due to new ov_fopen + function. + + -- Clint Adams Fri, 27 Jul 2007 02:57:44 -0400 + +libvorbis (1.1.2.dfsg-2) unstable; urgency=low + + * Bump to Standards-Version 3.7.2. + * Add upstream_r13198-fix_segfault_in_ov_time_seek.diff. closes: #281995. + + -- Clint Adams Fri, 29 Jun 2007 09:46:12 -0400 + +libvorbis (1.1.2.dfsg-1.2) unstable; urgency=high + + * Fix shlibs files for libvorbisenc and libvorbisfile, which were broken + by my first NMU to have dependencies for libvorbis0a. Closes: #395048 + + -- Joey Hess Tue, 24 Oct 2006 19:55:19 -0400 + +libvorbis (1.1.2.dfsg-1.1) unstable; urgency=low + + * NMU + * Remove draft RFC files, as they are not under a free license. + Closes: #390660 + * Repackage the source package without these files. + * Add README.Source documenting how the upstream source is repackaged. + * Modify dh_makeshlibs call to avoid generating a shlibs file that has + an unncessarily tight versioned dependency on this new pseudo-version + of libvorbis. + + -- Joey Hess Sun, 15 Oct 2006 17:21:37 -0400 + +libvorbis (1.1.2-1) unstable; urgency=low + + * Switch maintenance to the Debian Xiph.org Maintainers (alioth/pkg-xiph). + + * New upstream release packaged. (Closes: #327586) + + * Move HTML documentation from /usr/share/doc/libvorbis-dev itself to an + html/ subdirectory of it. + + * Update debian/control: + + drop unnecessary build-dependency on devscripts. + + drop version restriction on debhelper and libogg-dev build-dependencies, + since they're already satisfied with stable. + + * Overhaul debian/rules, and switch to quilt for patch management. + + * Add debian/compat file, instead of exporting DH_COMPAT. + + * Update download URL in debian/copyright. + + * Add debian/watch file. + + * Bumped Standards-Version to 3.6.2 (no changes required). + + -- Adeodato Simó Thu, 26 Jan 2006 01:35:39 +0100 + +libvorbis (1.1.0-1) unstable; urgency=low + + * New upstream. + + -- Christopher L Cheney Thu, 17 Mar 2005 21:30:00 -0600 + +libvorbis (1.0.1-1) unstable; urgency=low + + * New upstream. + * Improved descriptions. (Closes: #166649) + * Updated DEB_BUILD_OPTIONS support. (Closes: #188464) + + -- Christopher L Cheney Tue, 9 Dec 2003 01:00:00 -0600 + +libvorbis (1.0.0-3) unstable; urgency=low + + * Add libvorbis0 conflict to libvorbis0a. + + -- Christopher L Cheney Wed, 12 Mar 2003 17:00:00 -0600 + +libvorbis (1.0.0-2) unstable; urgency=low + + * Rename libvorbis0 -> libvorbis0a to keep packages from upgrading to it + by mistake. (Closes: #156227, #156365, #161961, #171548, #172466, + #172469, #178756) + * GNU config automated update: config.sub (20020621 to 20030103), + config.guess (20020529 to 20030110) + + -- Christopher L Cheney Sat, 8 Mar 2003 13:00:00 -0600 + +libvorbis (1.0.0-1) unstable; urgency=low + + * New upstream. + * Split libvorbis package into libvorbis libvorbisenc libvorbisfile due to + shared object major versions going out of sync. + + -- Christopher L Cheney Fri, 19 Jul 2002 09:00:00 -0500 + +libvorbis (1.0rc3-1) unstable; urgency=low + + * New upstream. (Closes: #121995, #123472) + * added autotools target (config.* updater) to rules + + -- Christopher L Cheney Mon, 24 Dec 2001 11:00:00 -0600 + +libvorbis (1.0rc2-1) unstable; urgency=low + + * New upstream. + + -- Christopher L Cheney Sun, 12 Aug 2001 22:00:00 -0500 + +libvorbis (1.0rc1-1) unstable; urgency=low + + * New upstream. (Closes: #84977, #95330) + * Upstream says lame at fault. See bug details. (Closes: #98010) + * Fixed versioned depends. + * Changed clean method to distclean. + + -- Christopher L Cheney Sun, 17 Jun 2001 20:00:00 -0500 + +libvorbis (1.0beta4-1) unstable; urgency=low + + * New upstream. + * Appears to be fixed, can't reproduce bug (closes: #78848) + + -- Christopher L Cheney Mon, 26 Feb 2001 08:00:00 -0600 + +libvorbis (1.0beta3-3) unstable; urgency=low + + * Fixed Build-Depends libogg-dev version dependency. + * Fixed Sections. + * Updated to Standards-Version to 3.5.1.0 + + -- Christopher L Cheney Sat, 17 Feb 2001 18:14:53 -0600 + +libvorbis (1.0beta3-2) unstable; urgency=low + + * Added dependency for libogg-dev (closes: #78262) + * Added dependency for libogg-dev (closes: #81432) + * Corrected development library package name (closes: #82464) + + -- Christopher L Cheney Sat, 3 Feb 2001 13:29:30 -0600 + +libvorbis (1.0beta3-1) unstable; urgency=low + + * New Maintainer. + * Upstream source was reorganized. + * Package split according to the upstream reorganization. + + -- Christopher L Cheney Tue, 31 Oct 2000 15:08:22 -0600 + +vorbis (1.0beta2-1) unstable; urgency=low + + * New upstream version. Closes: #67326, #68416 + * Changed xmms-vorbis to Architechture: any. Closes: #67395 + * Added Build-deps. Closes: #66628 + * Moved vorbize to vorbis-tools along with oggenc and vorbiscomment + + -- Michael Beattie Wed, 9 Aug 2000 00:30:15 +1200 + +vorbis (1.0beta1-1) unstable; urgency=low + + * First Beta, Ready for debian release. + + -- Michael Beattie Fri, 30 Jun 2000 19:26:59 +1200 + +vorbis (0.0-1) unstable; urgency=low + + * Initial Release. + * Initial package, not placed in archive. + + -- Michael Beattie Mon, 26 Jun 2000 18:59:56 +1200 diff --git a/vendor/vorbis/debian/control b/vendor/vorbis/debian/control new file mode 100644 index 0000000..b3f2646 --- /dev/null +++ b/vendor/vorbis/debian/control @@ -0,0 +1,60 @@ +Source: libvorbis +Section: libs +Priority: optional +Maintainer: Christopher L Cheney +Build-Depends: autotools-dev, debhelper (>> 4.0.18), devscripts, libogg-dev (>> 1.1.0) +Standards-Version: 3.6.1.0 + +Package: libvorbis0a +Architecture: any +Section: libs +Depends: ${shlibs:Depends} +Conflicts: libvorbis0 +Replaces: libvorbis0 +Description: The Vorbis General Audio Compression Codec + Ogg Vorbis is a fully open, non-proprietary, patent-and-royalty-free, + general-purpose compressed audio format for audio and music at fixed + and variable bitrates from 16 to 128 kbps/channel. + . + The Vorbis library is the primary Ogg Vorbis library. + +Package: libvorbisenc2 +Architecture: any +Section: libs +Depends: ${shlibs:Depends} +Conflicts: libvorbis0 (<< 1.0.0) +Replaces: libvorbis0 (<< 1.0.0) +Description: The Vorbis General Audio Compression Codec + Ogg Vorbis is a fully open, non-proprietary, patent-and-royalty-free, + general-purpose compressed audio format for audio and music at fixed + and variable bitrates from 16 to 128 kbps/channel. + . + The Vorbisenc library provides a convenient API for setting up an encoding + environment using libvorbis. + +Package: libvorbisfile3 +Architecture: any +Section: libs +Depends: ${shlibs:Depends} +Conflicts: libvorbis0 (<< 1.0.0) +Replaces: libvorbis0 (<< 1.0.0) +Description: The Vorbis General Audio Compression Codec + Ogg Vorbis is a fully open, non-proprietary, patent-and-royalty-free, + general-purpose compressed audio format for audio and music at fixed + and variable bitrates from 16 to 128 kbps/channel. + . + The Vorbisfile library provides a convenient high-level API for decoding + and basic manipulation of all Vorbis I audio streams. + +Package: libvorbis-dev +Architecture: any +Section: libdevel +Depends: libogg-dev, libvorbis0a (= ${Source-Version}), libvorbisenc2 (= ${Source-Version}), libvorbisfile3 (= ${Source-Version}) +Description: The Vorbis General Audio Compression Codec (development files) + Ogg Vorbis is a fully open, non-proprietary, patent-and-royalty-free, + general-purpose compressed audio format for audio and music at fixed + and variable bitrates from 16 to 128 kbps/channel. + . + This package contains the header files and documentation needed to develop + applications with libvorbis. + diff --git a/vendor/vorbis/debian/copyright b/vendor/vorbis/debian/copyright new file mode 100644 index 0000000..c6bf857 --- /dev/null +++ b/vendor/vorbis/debian/copyright @@ -0,0 +1,38 @@ +This package was debianized by Christopher L Cheney on +Tue, 31 Oct 2000 15:08:22 -0600. + +It was downloaded from https://downloads.xiph.org/releases/vorbis/ + +Upstream Author: Monty + +Copyright: + +Copyright (c) 2020, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/vorbis/debian/libvorbis-dev.docs b/vendor/vorbis/debian/libvorbis-dev.docs new file mode 100644 index 0000000..d1df571 --- /dev/null +++ b/vendor/vorbis/debian/libvorbis-dev.docs @@ -0,0 +1 @@ +debian/tmp/usr/share/doc/libvorbis-*/* diff --git a/vendor/vorbis/debian/libvorbis-dev.examples b/vendor/vorbis/debian/libvorbis-dev.examples new file mode 100644 index 0000000..1ae77b5 --- /dev/null +++ b/vendor/vorbis/debian/libvorbis-dev.examples @@ -0,0 +1,2 @@ +examples/*.c +examples/*.pl diff --git a/vendor/vorbis/debian/libvorbis-dev.install b/vendor/vorbis/debian/libvorbis-dev.install new file mode 100644 index 0000000..db22e50 --- /dev/null +++ b/vendor/vorbis/debian/libvorbis-dev.install @@ -0,0 +1,16 @@ +debian/tmp/usr/include/vorbis/codec.h +debian/tmp/usr/include/vorbis/vorbisenc.h +debian/tmp/usr/include/vorbis/vorbisfile.h +debian/tmp/usr/lib/libvorbis.a +debian/tmp/usr/lib/libvorbis.la +debian/tmp/usr/lib/libvorbis.so +debian/tmp/usr/lib/libvorbisenc.a +debian/tmp/usr/lib/libvorbisenc.la +debian/tmp/usr/lib/libvorbisenc.so +debian/tmp/usr/lib/libvorbisfile.a +debian/tmp/usr/lib/libvorbisfile.la +debian/tmp/usr/lib/libvorbisfile.so +debian/tmp/usr/lib/pkgconfig/vorbis.pc +debian/tmp/usr/lib/pkgconfig/vorbisenc.pc +debian/tmp/usr/lib/pkgconfig/vorbisfile.pc +debian/tmp/usr/share/aclocal/vorbis.m4 diff --git a/vendor/vorbis/debian/libvorbis0a.install b/vendor/vorbis/debian/libvorbis0a.install new file mode 100644 index 0000000..ad38b8b --- /dev/null +++ b/vendor/vorbis/debian/libvorbis0a.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libvorbis.so.* diff --git a/vendor/vorbis/debian/libvorbisenc2.install b/vendor/vorbis/debian/libvorbisenc2.install new file mode 100644 index 0000000..eb70258 --- /dev/null +++ b/vendor/vorbis/debian/libvorbisenc2.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libvorbisenc.so.* diff --git a/vendor/vorbis/debian/libvorbisfile3.install b/vendor/vorbis/debian/libvorbisfile3.install new file mode 100644 index 0000000..83bf445 --- /dev/null +++ b/vendor/vorbis/debian/libvorbisfile3.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libvorbisfile.so.* diff --git a/vendor/vorbis/debian/rules b/vendor/vorbis/debian/rules new file mode 100644 index 0000000..419ca7a --- /dev/null +++ b/vendor/vorbis/debian/rules @@ -0,0 +1,154 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. +# +# Modified to make a template file for a multi-binary package with separated +# build-arch and build-indep targets by Bill Allombert 2001 + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=4 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +objdir = $(CURDIR)/obj-$(DEB_BUILD_GNU_TYPE) + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: configure-stamp +configure-stamp: + dh_testdir + + # make build directory + mkdir $(objdir) + + # run configure with build tree $(objdir) + # change ../configure to ../autogen.sh for CVS build + cd $(objdir) && \ + ../configure --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE) \ + --prefix=/usr --enable-static + + touch configure-stamp + +#Architecture +build: build-arch build-indep + +build-arch: build-arch-stamp +build-arch-stamp: configure-stamp + + cd $(objdir) && \ + $(MAKE) + + touch build-arch-stamp + +build-indep: build-indep-stamp +build-indep-stamp: configure-stamp + + # Add here commands to compile the indep part of the package. + #$(MAKE) doc + touch build-indep-stamp + +debian-clean: + dh_testdir + dh_testroot + + dh_clean + +clean: + dh_testdir + dh_testroot + rm -f build-arch-stamp build-indep-stamp configure-stamp + + # Remove build tree + rm -rf $(objdir) + + # if Makefile exists run distclean + if test -f Makefile; then \ + $(MAKE) distclean; \ + fi + + #if test -d CVS; then \ + $(MAKE) cvs-clean ;\ + fi + + dh_clean + +install: install-indep install-arch +install-indep: + dh_testdir + dh_testroot +# dh_clean -k -i +# dh_installdirs -i + +# dh_install -i --list-missing + +install-arch: + dh_testdir + dh_testroot + dh_clean -k -s + dh_installdirs -s + + cd $(objdir) && \ + $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp + + dh_install -s --list-missing + +# Must not depend on anything. This is to be called by +# binary-arch/binary-indep +# in another 'make' thread. +binary-common: + dh_testdir + dh_testroot + dh_installchangelogs CHANGES + dh_installdocs + dh_installexamples +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_perl +# dh_python + dh_makeshlibs -V + dh_installdeb + dh_shlibdeps -ldebian/libvorbis0a/usr/lib + dh_gencontrol + dh_md5sums + dh_builddeb + +# Build architecture independant packages using the common target. +binary-indep: build-indep install-indep +# $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common + +# Build architecture dependant packages using the common target. +binary-arch: build-arch install-arch + $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common + +binary: binary-arch binary-indep +.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure diff --git a/vendor/vorbis/debian/watch b/vendor/vorbis/debian/watch new file mode 100644 index 0000000..3a05084 --- /dev/null +++ b/vendor/vorbis/debian/watch @@ -0,0 +1,3 @@ +version=2 + +https://downloads.xiph.org/releases/vorbis/libvorbis-(.*)\.tar\.gz debian uupdate diff --git a/vendor/vorbis/include/Makefile.am b/vendor/vorbis/include/Makefile.am new file mode 100644 index 0000000..0f34fab --- /dev/null +++ b/vendor/vorbis/include/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = vorbis diff --git a/vendor/vorbis/include/vorbis/Makefile.am b/vendor/vorbis/include/vorbis/Makefile.am new file mode 100644 index 0000000..dbba34e --- /dev/null +++ b/vendor/vorbis/include/vorbis/Makefile.am @@ -0,0 +1,7 @@ +## Process this file with automake to produce Makefile.in + +vorbisincludedir = $(includedir)/vorbis + +vorbisinclude_HEADERS = codec.h vorbisfile.h vorbisenc.h + + diff --git a/vendor/vorbis/include/vorbis/codec.h b/vendor/vorbis/include/vorbis/codec.h new file mode 100644 index 0000000..f8a912b --- /dev/null +++ b/vendor/vorbis/include/vorbis/codec.h @@ -0,0 +1,242 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + + ******************************************************************** + + function: libvorbis codec headers + + ********************************************************************/ + +#ifndef _vorbis_codec_h_ +#define _vorbis_codec_h_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include + +typedef struct vorbis_info{ + int version; + int channels; + long rate; + + /* The below bitrate declarations are *hints*. + Combinations of the three values carry the following implications: + + all three set to the same value: + implies a fixed rate bitstream + only nominal set: + implies a VBR stream that averages the nominal bitrate. No hard + upper/lower limit + upper and or lower set: + implies a VBR bitstream that obeys the bitrate limits. nominal + may also be set to give a nominal rate. + none set: + the coder does not care to speculate. + */ + + long bitrate_upper; + long bitrate_nominal; + long bitrate_lower; + long bitrate_window; + + void *codec_setup; +} vorbis_info; + +/* vorbis_dsp_state buffers the current vorbis audio + analysis/synthesis state. The DSP state belongs to a specific + logical bitstream ****************************************************/ +typedef struct vorbis_dsp_state{ + int analysisp; + vorbis_info *vi; + + float **pcm; + float **pcmret; + int pcm_storage; + int pcm_current; + int pcm_returned; + + int preextrapolate; + int eofflag; + + long lW; + long W; + long nW; + long centerW; + + ogg_int64_t granulepos; + ogg_int64_t sequence; + + ogg_int64_t glue_bits; + ogg_int64_t time_bits; + ogg_int64_t floor_bits; + ogg_int64_t res_bits; + + void *backend_state; +} vorbis_dsp_state; + +typedef struct vorbis_block{ + /* necessary stream state for linking to the framing abstraction */ + float **pcm; /* this is a pointer into local storage */ + oggpack_buffer opb; + + long lW; + long W; + long nW; + int pcmend; + int mode; + + int eofflag; + ogg_int64_t granulepos; + ogg_int64_t sequence; + vorbis_dsp_state *vd; /* For read-only access of configuration */ + + /* local storage to avoid remallocing; it's up to the mapping to + structure it */ + void *localstore; + long localtop; + long localalloc; + long totaluse; + struct alloc_chain *reap; + + /* bitmetrics for the frame */ + long glue_bits; + long time_bits; + long floor_bits; + long res_bits; + + void *internal; + +} vorbis_block; + +/* vorbis_block is a single block of data to be processed as part of +the analysis/synthesis stream; it belongs to a specific logical +bitstream, but is independent from other vorbis_blocks belonging to +that logical bitstream. *************************************************/ + +struct alloc_chain{ + void *ptr; + struct alloc_chain *next; +}; + +/* vorbis_info contains all the setup information specific to the + specific compression/decompression mode in progress (eg, + psychoacoustic settings, channel setup, options, codebook + etc). vorbis_info and substructures are in backends.h. +*********************************************************************/ + +/* the comments are not part of vorbis_info so that vorbis_info can be + static storage */ +typedef struct vorbis_comment{ + /* unlimited user comment fields. libvorbis writes 'libvorbis' + whatever vendor is set to in encode */ + char **user_comments; + int *comment_lengths; + int comments; + char *vendor; + +} vorbis_comment; + + +/* libvorbis encodes in two abstraction layers; first we perform DSP + and produce a packet (see docs/analysis.txt). The packet is then + coded into a framed OggSquish bitstream by the second layer (see + docs/framing.txt). Decode is the reverse process; we sync/frame + the bitstream and extract individual packets, then decode the + packet back into PCM audio. + + The extra framing/packetizing is used in streaming formats, such as + files. Over the net (such as with UDP), the framing and + packetization aren't necessary as they're provided by the transport + and the streaming layer is not used */ + +/* Vorbis PRIMITIVES: general ***************************************/ + +extern void vorbis_info_init(vorbis_info *vi); +extern void vorbis_info_clear(vorbis_info *vi); +extern int vorbis_info_blocksize(vorbis_info *vi,int zo); +extern void vorbis_comment_init(vorbis_comment *vc); +extern void vorbis_comment_add(vorbis_comment *vc, const char *comment); +extern void vorbis_comment_add_tag(vorbis_comment *vc, + const char *tag, const char *contents); +extern char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count); +extern int vorbis_comment_query_count(vorbis_comment *vc, const char *tag); +extern void vorbis_comment_clear(vorbis_comment *vc); + +extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); +extern int vorbis_block_clear(vorbis_block *vb); +extern void vorbis_dsp_clear(vorbis_dsp_state *v); +extern double vorbis_granule_time(vorbis_dsp_state *v, + ogg_int64_t granulepos); + +extern const char *vorbis_version_string(void); + +/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ + +extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi); +extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op); +extern int vorbis_analysis_headerout(vorbis_dsp_state *v, + vorbis_comment *vc, + ogg_packet *op, + ogg_packet *op_comm, + ogg_packet *op_code); +extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals); +extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals); +extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb); +extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op); + +extern int vorbis_bitrate_addblock(vorbis_block *vb); +extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, + ogg_packet *op); + +/* Vorbis PRIMITIVES: synthesis layer *******************************/ +extern int vorbis_synthesis_idheader(ogg_packet *op); +extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, + ogg_packet *op); + +extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); +extern int vorbis_synthesis_restart(vorbis_dsp_state *v); +extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); +extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op); +extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); +extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm); +extern int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm); +extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); +extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); + +extern int vorbis_synthesis_halfrate(vorbis_info *v,int flag); +extern int vorbis_synthesis_halfrate_p(vorbis_info *v); + +/* Vorbis ERRORS and return codes ***********************************/ + +#define OV_FALSE -1 +#define OV_EOF -2 +#define OV_HOLE -3 + +#define OV_EREAD -128 +#define OV_EFAULT -129 +#define OV_EIMPL -130 +#define OV_EINVAL -131 +#define OV_ENOTVORBIS -132 +#define OV_EBADHEADER -133 +#define OV_EVERSION -134 +#define OV_ENOTAUDIO -135 +#define OV_EBADPACKET -136 +#define OV_EBADLINK -137 +#define OV_ENOSEEK -138 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/vendor/vorbis/include/vorbis/vorbisenc.h b/vendor/vorbis/include/vorbis/vorbisenc.h new file mode 100644 index 0000000..085b15e --- /dev/null +++ b/vendor/vorbis/include/vorbis/vorbisenc.h @@ -0,0 +1,435 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: vorbis encode-engine setup + + ********************************************************************/ + +/** \file + * Libvorbisenc is a convenient API for setting up an encoding + * environment using libvorbis. Libvorbisenc encapsulates the + * actions needed to set up the encoder properly. + */ + +#ifndef _OV_ENC_H_ +#define _OV_ENC_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include "codec.h" + +/** + * This is the primary function within libvorbisenc for setting up managed + * bitrate modes. + * + * Before this function is called, the \ref vorbis_info + * struct should be initialized by using vorbis_info_init() from the libvorbis + * API. After encoding, vorbis_info_clear() should be called. + * + * The max_bitrate, nominal_bitrate, and min_bitrate settings are used to set + * constraints for the encoded file. This function uses these settings to + * select the appropriate encoding mode and set it up. + * + * \param vi Pointer to an initialized \ref vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param max_bitrate Desired maximum bitrate (limit). -1 indicates unset. + * \param nominal_bitrate Desired average, or central, bitrate. -1 indicates unset. + * \param min_bitrate Desired minimum bitrate. -1 indicates unset. + * + * \return Zero for success, and negative values for failure. + * + * \retval 0 Success. + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with bitrate request. + */ +extern int vorbis_encode_init(vorbis_info *vi, + long channels, + long rate, + + long max_bitrate, + long nominal_bitrate, + long min_bitrate); + +/** + * This function performs step-one of a three-step bitrate-managed encode + * setup. It functions similarly to the one-step setup performed by \ref + * vorbis_encode_init but allows an application to make further encode setup + * tweaks using \ref vorbis_encode_ctl before finally calling \ref + * vorbis_encode_setup_init to complete the setup process. + * + * Before this function is called, the \ref vorbis_info struct should be + * initialized by using vorbis_info_init() from the libvorbis API. After + * encoding, vorbis_info_clear() should be called. + * + * The max_bitrate, nominal_bitrate, and min_bitrate settings are used to set + * constraints for the encoded file. This function uses these settings to + * select the appropriate encoding mode and set it up. + * + * \param vi Pointer to an initialized vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param max_bitrate Desired maximum bitrate (limit). -1 indicates unset. + * \param nominal_bitrate Desired average, or central, bitrate. -1 indicates unset. + * \param min_bitrate Desired minimum bitrate. -1 indicates unset. + * + * \return Zero for success, and negative for failure. + * + * \retval 0 Success + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with bitrate request. + */ +extern int vorbis_encode_setup_managed(vorbis_info *vi, + long channels, + long rate, + + long max_bitrate, + long nominal_bitrate, + long min_bitrate); + +/** + * This function performs step-one of a three-step variable bitrate + * (quality-based) encode setup. It functions similarly to the one-step setup + * performed by \ref vorbis_encode_init_vbr() but allows an application to + * make further encode setup tweaks using \ref vorbis_encode_ctl() before + * finally calling \ref vorbis_encode_setup_init to complete the setup + * process. + * + * Before this function is called, the \ref vorbis_info struct should be + * initialized by using \ref vorbis_info_init() from the libvorbis API. After + * encoding, vorbis_info_clear() should be called. + * + * \param vi Pointer to an initialized vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param quality Desired quality level, currently from -0.1 to 1.0 (lo to hi). + * + * \return Zero for success, and negative values for failure. + * + * \retval 0 Success + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with quality level request. + */ +extern int vorbis_encode_setup_vbr(vorbis_info *vi, + long channels, + long rate, + + float quality + ); + +/** + * This is the primary function within libvorbisenc for setting up variable + * bitrate ("quality" based) modes. + * + * + * Before this function is called, the vorbis_info struct should be + * initialized by using vorbis_info_init() from the libvorbis API. After + * encoding, vorbis_info_clear() should be called. + * + * \param vi Pointer to an initialized vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param base_quality Desired quality level, currently from -0.1 to 1.0 (lo to hi). + * + * + * \return Zero for success, or a negative number for failure. + * + * \retval 0 Success + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with quality level request. + */ +extern int vorbis_encode_init_vbr(vorbis_info *vi, + long channels, + long rate, + + float base_quality + ); + +/** + * This function performs the last stage of three-step encoding setup, as + * described in the API overview under managed bitrate modes. + * + * Before this function is called, the \ref vorbis_info struct should be + * initialized by using vorbis_info_init() from the libvorbis API, one of + * \ref vorbis_encode_setup_managed() or \ref vorbis_encode_setup_vbr() called to + * initialize the high-level encoding setup, and \ref vorbis_encode_ctl() + * called if necessary to make encoding setup changes. + * vorbis_encode_setup_init() finalizes the highlevel encoding structure into + * a complete encoding setup after which the application may make no further + * setup changes. + * + * After encoding, vorbis_info_clear() should be called. + * + * \param vi Pointer to an initialized \ref vorbis_info struct. + * + * \return Zero for success, and negative values for failure. + * + * \retval 0 Success. + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * + * \retval OV_EINVAL Attempt to use vorbis_encode_setup_init() without first + * calling one of vorbis_encode_setup_managed() or vorbis_encode_setup_vbr() to + * initialize the high-level encoding setup + * + */ +extern int vorbis_encode_setup_init(vorbis_info *vi); + +/** + * This function implements a generic interface to miscellaneous encoder + * settings similar to the classic UNIX 'ioctl()' system call. Applications + * may use vorbis_encode_ctl() to query or set bitrate management or quality + * mode details by using one of several \e request arguments detailed below. + * vorbis_encode_ctl() must be called after one of + * vorbis_encode_setup_managed() or vorbis_encode_setup_vbr(). When used + * to modify settings, \ref vorbis_encode_ctl() must be called before \ref + * vorbis_encode_setup_init(). + * + * \param vi Pointer to an initialized vorbis_info struct. + * + * \param number Specifies the desired action; See \ref encctlcodes "the list + * of available requests". + * + * \param arg void * pointing to a data structure matching the request + * argument. + * + * \retval 0 Success. Any further return information (such as the result of a + * query) is placed into the storage pointed to by *arg. + * + * \retval OV_EINVAL Invalid argument, or an attempt to modify a setting after + * calling vorbis_encode_setup_init(). + * + * \retval OV_EIMPL Unimplemented or unknown request + */ +extern int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg); + +/** + * \deprecated This is a deprecated interface. Please use vorbis_encode_ctl() + * with the \ref ovectl_ratemanage2_arg struct and \ref + * OV_ECTL_RATEMANAGE2_GET and \ref OV_ECTL_RATEMANAGE2_SET calls in new code. + * + * The \ref ovectl_ratemanage_arg structure is used with vorbis_encode_ctl() + * and the \ref OV_ECTL_RATEMANAGE_GET, \ref OV_ECTL_RATEMANAGE_SET, \ref + * OV_ECTL_RATEMANAGE_AVG, \ref OV_ECTL_RATEMANAGE_HARD calls in order to + * query and modify specifics of the encoder's bitrate management + * configuration. +*/ +struct ovectl_ratemanage_arg { + int management_active; /**< nonzero if bitrate management is active*/ +/** hard lower limit (in kilobits per second) below which the stream bitrate + will never be allowed for any given bitrate_hard_window seconds of time.*/ + long bitrate_hard_min; +/** hard upper limit (in kilobits per second) above which the stream bitrate + will never be allowed for any given bitrate_hard_window seconds of time.*/ + long bitrate_hard_max; +/** the window period (in seconds) used to regulate the hard bitrate minimum + and maximum*/ + double bitrate_hard_window; +/** soft lower limit (in kilobits per second) below which the average bitrate + tracker will start nudging the bitrate higher.*/ + long bitrate_av_lo; +/** soft upper limit (in kilobits per second) above which the average bitrate + tracker will start nudging the bitrate lower.*/ + long bitrate_av_hi; +/** the window period (in seconds) used to regulate the average bitrate + minimum and maximum.*/ + double bitrate_av_window; +/** Regulates the relative centering of the average and hard windows; in + libvorbis 1.0 and 1.0.1, the hard window regulation overlapped but + followed the average window regulation. In libvorbis 1.1 a bit-reservoir + interface replaces the old windowing interface; the older windowing + interface is simulated and this field has no effect.*/ + double bitrate_av_window_center; +}; + +/** + * \name struct ovectl_ratemanage2_arg + * + * The ovectl_ratemanage2_arg structure is used with vorbis_encode_ctl() and + * the OV_ECTL_RATEMANAGE2_GET and OV_ECTL_RATEMANAGE2_SET calls in order to + * query and modify specifics of the encoder's bitrate management + * configuration. + * +*/ +struct ovectl_ratemanage2_arg { + int management_active; /**< nonzero if bitrate management is active */ +/** Lower allowed bitrate limit in kilobits per second */ + long bitrate_limit_min_kbps; +/** Upper allowed bitrate limit in kilobits per second */ + long bitrate_limit_max_kbps; + long bitrate_limit_reservoir_bits; /**struct ovectl_ratemanage2_arg * + * + * Used to query the current encoder bitrate management setting. Also used to + * initialize fields of an ovectl_ratemanage2_arg structure for use with + * \ref OV_ECTL_RATEMANAGE2_SET. + */ +#define OV_ECTL_RATEMANAGE2_GET 0x14 + +/** + * Set the current encoder bitrate management settings. + * + * Argument: struct ovectl_ratemanage2_arg * + * + * Used to set the current encoder bitrate management settings to the values + * listed in the ovectl_ratemanage2_arg. Passing a NULL pointer will disable + * bitrate management. +*/ +#define OV_ECTL_RATEMANAGE2_SET 0x15 + +/** + * Returns the current encoder hard-lowpass setting (kHz) in the double + * pointed to by arg. + * + * Argument: double * +*/ +#define OV_ECTL_LOWPASS_GET 0x20 + +/** + * Sets the encoder hard-lowpass to the value (kHz) pointed to by arg. Valid + * lowpass settings range from 2 to 99. + * + * Argument: double * +*/ +#define OV_ECTL_LOWPASS_SET 0x21 + +/** + * Returns the current encoder impulse block setting in the double pointed + * to by arg. + * + * Argument: double * +*/ +#define OV_ECTL_IBLOCK_GET 0x30 + +/** + * Sets the impulse block bias to the the value pointed to by arg. + * + * Argument: double * + * + * Valid range is -15.0 to 0.0 [default]. A negative impulse block bias will + * direct to encoder to use more bits when incoding short blocks that contain + * strong impulses, thus improving the accuracy of impulse encoding. + */ +#define OV_ECTL_IBLOCK_SET 0x31 + +/** + * Returns the current encoder coupling setting in the int pointed + * to by arg. + * + * Argument: int * +*/ +#define OV_ECTL_COUPLING_GET 0x40 + +/** + * Enables/disables channel coupling in multichannel encoding according to arg. + * + * Argument: int * + * + * Zero disables channel coupling for multichannel inputs, nonzer enables + * channel coupling. Setting has no effect on monophonic encoding or + * multichannel counts that do not offer coupling. At present, coupling is + * available for stereo and 5.1 encoding. + */ +#define OV_ECTL_COUPLING_SET 0x41 + + /* deprecated rate management supported only for compatibility */ + +/** + * Old interface to querying bitrate management settings. + * + * Deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_GET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_GET 0x10 +/** + * Old interface to modifying bitrate management settings. + * + * deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + * + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_SET 0x11 +/** + * Old interface to setting average-bitrate encoding mode. + * + * Deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + * + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_AVG 0x12 +/** + * Old interface to setting bounded-bitrate encoding modes. + * + * deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + * + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_HARD 0x13 + +/*@}*/ + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/vendor/vorbis/include/vorbis/vorbisfile.h b/vendor/vorbis/include/vorbis/vorbisfile.h new file mode 100644 index 0000000..3d65393 --- /dev/null +++ b/vendor/vorbis/include/vorbis/vorbisfile.h @@ -0,0 +1,205 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + + ********************************************************************/ + +#ifndef _OV_FILE_H_ +#define _OV_FILE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include +#include "codec.h" + +/* The function prototypes for the callbacks are basically the same as for + * the stdio functions fread, fseek, fclose, ftell. + * The one difference is that the FILE * arguments have been replaced with + * a void * - this is to be used as a pointer to whatever internal data these + * functions might need. In the stdio case, it's just a FILE * cast to a void * + * + * If you use other functions, check the docs for these functions and return + * the right values. For seek_func(), you *MUST* return -1 if the stream is + * unseekable + */ +typedef struct { + size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); + int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); + int (*close_func) (void *datasource); + long (*tell_func) (void *datasource); +} ov_callbacks; + +#ifndef OV_EXCLUDE_STATIC_CALLBACKS + +/* a few sets of convenient callbacks, especially for use under + * Windows where ov_open_callbacks() should always be used instead of + * ov_open() to avoid problems with incompatible crt.o version linking + * issues. */ + +static int _ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){ + if(f==NULL)return(-1); + +#ifdef __MINGW32__ + return fseeko64(f,off,whence); +#elif defined (_WIN32) + return _fseeki64(f,off,whence); +#else + return fseek(f,off,whence); +#endif +} + +/* These structs below (OV_CALLBACKS_DEFAULT etc) are defined here as + * static data. That means that every file which includes this header + * will get its own copy of these structs whether it uses them or + * not unless it #defines OV_EXCLUDE_STATIC_CALLBACKS. + * These static symbols are essential on platforms such as Windows on + * which several different versions of stdio support may be linked to + * by different DLLs, and we need to be certain we know which one + * we're using (the same one as the main application). + */ + +static ov_callbacks OV_CALLBACKS_DEFAULT = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap, + (int (*)(void *)) fclose, + (long (*)(void *)) ftell +}; + +static ov_callbacks OV_CALLBACKS_NOCLOSE = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap, + (int (*)(void *)) NULL, + (long (*)(void *)) ftell +}; + +static ov_callbacks OV_CALLBACKS_STREAMONLY = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) NULL, + (int (*)(void *)) fclose, + (long (*)(void *)) NULL +}; + +static ov_callbacks OV_CALLBACKS_STREAMONLY_NOCLOSE = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) NULL, + (int (*)(void *)) NULL, + (long (*)(void *)) NULL +}; + +#endif + +#define NOTOPEN 0 +#define PARTOPEN 1 +#define OPENED 2 +#define STREAMSET 3 +#define INITSET 4 + +typedef struct OggVorbis_File { + void *datasource; /* Pointer to a FILE *, etc. */ + int seekable; + ogg_int64_t offset; + ogg_int64_t end; + ogg_sync_state oy; + + /* If the FILE handle isn't seekable (eg, a pipe), only the current + stream appears */ + int links; + ogg_int64_t *offsets; + ogg_int64_t *dataoffsets; + long *serialnos; + ogg_int64_t *pcmlengths; /* overloaded to maintain binary + compatibility; x2 size, stores both + beginning and end values */ + vorbis_info *vi; + vorbis_comment *vc; + + /* Decoding working state local storage */ + ogg_int64_t pcm_offset; + int ready_state; + long current_serialno; + int current_link; + + double bittrack; + double samptrack; + + ogg_stream_state os; /* take physical pages, weld into a logical + stream of packets */ + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + ov_callbacks callbacks; + +} OggVorbis_File; + + +extern int ov_clear(OggVorbis_File *vf); +extern int ov_fopen(const char *path,OggVorbis_File *vf); +extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); +extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf, + const char *initial, long ibytes, ov_callbacks callbacks); + +extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); +extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf, + const char *initial, long ibytes, ov_callbacks callbacks); +extern int ov_test_open(OggVorbis_File *vf); + +extern long ov_bitrate(OggVorbis_File *vf,int i); +extern long ov_bitrate_instant(OggVorbis_File *vf); +extern long ov_streams(OggVorbis_File *vf); +extern long ov_seekable(OggVorbis_File *vf); +extern long ov_serialnumber(OggVorbis_File *vf,int i); + +extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i); +extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i); +extern double ov_time_total(OggVorbis_File *vf,int i); + +extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_time_seek(OggVorbis_File *vf,double pos); +extern int ov_time_seek_page(OggVorbis_File *vf,double pos); + +extern int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_time_seek_lap(OggVorbis_File *vf,double pos); +extern int ov_time_seek_page_lap(OggVorbis_File *vf,double pos); + +extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf); +extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf); +extern double ov_time_tell(OggVorbis_File *vf); + +extern vorbis_info *ov_info(OggVorbis_File *vf,int link); +extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); + +extern long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int samples, + int *bitstream); +extern long ov_read_filter(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream, + void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param); +extern long ov_read(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream); +extern int ov_crosslap(OggVorbis_File *vf1,OggVorbis_File *vf2); + +extern int ov_halfrate(OggVorbis_File *vf,int flag); +extern int ov_halfrate_p(OggVorbis_File *vf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/vendor/vorbis/lib/Makefile.am b/vendor/vorbis/lib/Makefile.am new file mode 100644 index 0000000..e22895e --- /dev/null +++ b/vendor/vorbis/lib/Makefile.am @@ -0,0 +1,63 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = modes books + +AM_CPPFLAGS = -I$(top_srcdir)/include @OGG_CFLAGS@ + +lib_LTLIBRARIES = libvorbis.la libvorbisfile.la libvorbisenc.la + +libvorbis_la_SOURCES = mdct.c smallft.c block.c envelope.c window.c lsp.c \ + lpc.c analysis.c synthesis.c psy.c info.c \ + floor1.c floor0.c\ + res0.c mapping0.c registry.c codebook.c sharedbook.c\ + lookup.c bitrate.c\ + envelope.h lpc.h lsp.h codebook.h misc.h psy.h\ + masking.h os.h mdct.h smallft.h highlevel.h\ + registry.h scales.h window.h lookup.h lookup_data.h\ + codec_internal.h backends.h bitrate.h +libvorbis_la_LDFLAGS = -no-undefined -version-info @V_LIB_CURRENT@:@V_LIB_REVISION@:@V_LIB_AGE@ +libvorbis_la_LIBADD = @VORBIS_LIBS@ @OGG_LIBS@ + +libvorbisfile_la_SOURCES = vorbisfile.c +libvorbisfile_la_LDFLAGS = -no-undefined -version-info @VF_LIB_CURRENT@:@VF_LIB_REVISION@:@VF_LIB_AGE@ +libvorbisfile_la_LIBADD = libvorbis.la @OGG_LIBS@ + +libvorbisenc_la_SOURCES = vorbisenc.c +libvorbisenc_la_LDFLAGS = -no-undefined -version-info @VE_LIB_CURRENT@:@VE_LIB_REVISION@:@VE_LIB_AGE@ +libvorbisenc_la_LIBADD = libvorbis.la @OGG_LIBS@ + +EXTRA_PROGRAMS = barkmel tone psytune +CLEANFILES = $(EXTRA_PROGRAMS) + +barkmel_SOURCES = barkmel.c +tone_SOURCES = tone.c +psytune_SOURCES = psytune.c +psytune_LDFLAGS = -static +psytune_LDADD = libvorbis.la + +EXTRA_DIST = lookups.pl CMakeLists.txt + +# build and run the self tests on 'make check' + +#vorbis_selftests = test_codebook test_sharedbook +vorbis_selftests = test_sharedbook + +noinst_PROGRAMS = $(vorbis_selftests) + +check: $(noinst_PROGRAMS) + ./test_sharedbook$(EXEEXT) + +#test_codebook_SOURCES = codebook.c +#test_codebook_CFLAGS = -D_V_SELFTEST + +test_sharedbook_SOURCES = sharedbook.c +test_sharedbook_CFLAGS = -D_V_SELFTEST +test_sharedbook_LDADD = @VORBIS_LIBS@ + +# recurse for alternate targets + +debug: + $(MAKE) all CFLAGS="@DEBUG@" + +profile: + $(MAKE) all CFLAGS="@PROFILE@" diff --git a/vendor/vorbis/lib/analysis.c b/vendor/vorbis/lib/analysis.c new file mode 100644 index 0000000..1491973 --- /dev/null +++ b/vendor/vorbis/lib/analysis.c @@ -0,0 +1,119 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: single-block PCM analysis mode dispatch + + ********************************************************************/ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "registry.h" +#include "scales.h" +#include "os.h" +#include "misc.h" + +/* decides between modes, dispatches to the appropriate mapping. */ +int vorbis_analysis(vorbis_block *vb, ogg_packet *op){ + int ret,i; + vorbis_block_internal *vbi=vb->internal; + + vb->glue_bits=0; + vb->time_bits=0; + vb->floor_bits=0; + vb->res_bits=0; + + /* first things first. Make sure encode is ready */ + for(i=0;ipacketblob[i]); + + /* we only have one mapping type (0), and we let the mapping code + itself figure out what soft mode to use. This allows easier + bitrate management */ + + if((ret=_mapping_P[0]->forward(vb))) + return(ret); + + if(op){ + if(vorbis_bitrate_managed(vb)) + /* The app is using a bitmanaged mode... but not using the + bitrate management interface. */ + return(OV_EINVAL); + + op->packet=oggpack_get_buffer(&vb->opb); + op->bytes=oggpack_bytes(&vb->opb); + op->b_o_s=0; + op->e_o_s=vb->eofflag; + op->granulepos=vb->granulepos; + op->packetno=vb->sequence; /* for sake of completeness */ + } + return(0); +} + +#ifdef ANALYSIS +int analysis_noisy=1; + +/* there was no great place to put this.... */ +void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off){ + int j; + FILE *of; + char buffer[80]; + + sprintf(buffer,"%s_%d.m",base,i); + of=fopen(buffer,"w"); + + if(!of)perror("failed to open data dump file"); + + for(j=0;j +#include "scales.h" +int main(){ + int i; + double rate; + for(i=64;i<32000;i*=2){ + rate=48000.f; + fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", + rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); + + rate=44100.f; + fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", + rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); + + rate=32000.f; + fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", + rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); + + rate=22050.f; + fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", + rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); + + rate=16000.f; + fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", + rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); + + rate=11025.f; + fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", + rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); + + rate=8000.f; + fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n\n", + rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); + + + } + { + float i; + int j; + for(i=0.,j=0;i<28;i+=1,j++){ + fprintf(stderr,"(%d) bark=%f %gHz (%d of 128)\n", + j,i,fromBARK(i),(int)(fromBARK(i)/22050.*128.)); + } + } + return(0); +} + diff --git a/vendor/vorbis/lib/bitrate.c b/vendor/vorbis/lib/bitrate.c new file mode 100644 index 0000000..132553c --- /dev/null +++ b/vendor/vorbis/lib/bitrate.c @@ -0,0 +1,252 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: bitrate tracking and management + + ********************************************************************/ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "os.h" +#include "misc.h" +#include "bitrate.h" + +/* compute bitrate tracking setup */ +void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ + codec_setup_info *ci=vi->codec_setup; + bitrate_manager_info *bi=&ci->bi; + + memset(bm,0,sizeof(*bm)); + + if(bi && (bi->reservoir_bits>0)){ + long ratesamples=vi->rate; + int halfsamples=ci->blocksizes[0]>>1; + + bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0]; + bm->managed=1; + + bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples); + bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples); + bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples); + + bm->avgfloat=PACKETBLOBS/2; + + /* not a necessary fix, but one that leads to a more balanced + typical initialization */ + { + long desired_fill=bi->reservoir_bits*bi->reservoir_bias; + bm->minmax_reservoir=desired_fill; + bm->avg_reservoir=desired_fill; + } + + } +} + +void vorbis_bitrate_clear(bitrate_manager_state *bm){ + memset(bm,0,sizeof(*bm)); + return; +} + +int vorbis_bitrate_managed(vorbis_block *vb){ + vorbis_dsp_state *vd=vb->vd; + private_state *b=vd->backend_state; + bitrate_manager_state *bm=&b->bms; + + if(bm && bm->managed)return(1); + return(0); +} + +/* finish taking in the block we just processed */ +int vorbis_bitrate_addblock(vorbis_block *vb){ + vorbis_block_internal *vbi=vb->internal; + vorbis_dsp_state *vd=vb->vd; + private_state *b=vd->backend_state; + bitrate_manager_state *bm=&b->bms; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + bitrate_manager_info *bi=&ci->bi; + + int choice=rint(bm->avgfloat); + long this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper); + long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper); + int samples=ci->blocksizes[vb->W]>>1; + long desired_fill=bi->reservoir_bits*bi->reservoir_bias; + if(!bm->managed){ + /* not a bitrate managed stream, but for API simplicity, we'll + buffer the packet to keep the code path clean */ + + if(bm->vb)return(-1); /* one has been submitted without + being claimed */ + bm->vb=vb; + return(0); + } + + bm->vb=vb; + + /* look ahead for avg floater */ + if(bm->avg_bitsper>0){ + double slew=0.; + long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); + double slewlimit= 15./bi->slew_damp; + + /* choosing a new floater: + if we're over target, we slew down + if we're under target, we slew up + + choose slew as follows: look through packetblobs of this frame + and set slew as the first in the appropriate direction that + gives us the slew we want. This may mean no slew if delta is + already favorable. + + Then limit slew to slew max */ + + if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ + while(choice>0 && this_bits>avg_target_bits && + bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ + choice--; + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + } + }else if(bm->avg_reservoir+(this_bits-avg_target_bits)avg_reservoir+(this_bits-avg_target_bits)packetblob[choice])*8; + } + } + + slew=rint(choice-bm->avgfloat)/samples*vi->rate; + if(slew<-slewlimit)slew=-slewlimit; + if(slew>slewlimit)slew=slewlimit; + choice=rint(bm->avgfloat+= slew/vi->rate*samples); + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + } + + + + /* enforce min(if used) on the current floater (if used) */ + if(bm->min_bitsper>0){ + /* do we need to force the bitrate up? */ + if(this_bitsminmax_reservoir-(min_target_bits-this_bits)<0){ + choice++; + if(choice>=PACKETBLOBS)break; + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + } + } + } + + /* enforce max (if used) on the current floater (if used) */ + if(bm->max_bitsper>0){ + /* do we need to force the bitrate down? */ + if(this_bits>max_target_bits){ + while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){ + choice--; + if(choice<0)break; + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + } + } + } + + /* Choice of packetblobs now made based on floater, and min/max + requirements. Now boundary check extreme choices */ + + if(choice<0){ + /* choosing a smaller packetblob is insufficient to trim bitrate. + frame will need to be truncated */ + long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8; + bm->choice=choice=0; + + if(oggpack_bytes(vbi->packetblob[choice])>maxsize){ + + oggpack_writetrunc(vbi->packetblob[choice],maxsize*8); + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + } + }else{ + long minsize=(min_target_bits-bm->minmax_reservoir+7)/8; + if(choice>=PACKETBLOBS) + choice=PACKETBLOBS-1; + + bm->choice=choice; + + /* prop up bitrate according to demand. pad this frame out with zeroes */ + minsize-=oggpack_bytes(vbi->packetblob[choice]); + while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8); + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + + } + + /* now we have the final packet and the final packet size. Update statistics */ + /* min and max reservoir */ + if(bm->min_bitsper>0 || bm->max_bitsper>0){ + + if(max_target_bits>0 && this_bits>max_target_bits){ + bm->minmax_reservoir+=(this_bits-max_target_bits); + }else if(min_target_bits>0 && this_bitsminmax_reservoir+=(this_bits-min_target_bits); + }else{ + /* inbetween; we want to take reservoir toward but not past desired_fill */ + if(bm->minmax_reservoir>desired_fill){ + if(max_target_bits>0){ /* logical bulletproofing against initialization state */ + bm->minmax_reservoir+=(this_bits-max_target_bits); + if(bm->minmax_reservoirminmax_reservoir=desired_fill; + }else{ + bm->minmax_reservoir=desired_fill; + } + }else{ + if(min_target_bits>0){ /* logical bulletproofing against initialization state */ + bm->minmax_reservoir+=(this_bits-min_target_bits); + if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill; + }else{ + bm->minmax_reservoir=desired_fill; + } + } + } + } + + /* avg reservoir */ + if(bm->avg_bitsper>0){ + long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); + bm->avg_reservoir+=this_bits-avg_target_bits; + } + + return(0); +} + +int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ + private_state *b=vd->backend_state; + bitrate_manager_state *bm=&b->bms; + vorbis_block *vb=bm->vb; + int choice=PACKETBLOBS/2; + if(!vb)return 0; + + if(op){ + vorbis_block_internal *vbi=vb->internal; + + if(vorbis_bitrate_managed(vb)) + choice=bm->choice; + + op->packet=oggpack_get_buffer(vbi->packetblob[choice]); + op->bytes=oggpack_bytes(vbi->packetblob[choice]); + op->b_o_s=0; + op->e_o_s=vb->eofflag; + op->granulepos=vb->granulepos; + op->packetno=vb->sequence; /* for sake of completeness */ + } + + bm->vb=0; + return(1); +} diff --git a/vendor/vorbis/lib/bitrate.h b/vendor/vorbis/lib/bitrate.h new file mode 100644 index 0000000..48fa150 --- /dev/null +++ b/vendor/vorbis/lib/bitrate.h @@ -0,0 +1,58 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: bitrate tracking and management + + ********************************************************************/ + +#ifndef _V_BITRATE_H_ +#define _V_BITRATE_H_ + +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "os.h" + +/* encode side bitrate tracking */ +typedef struct bitrate_manager_state { + int managed; + + long avg_reservoir; + long minmax_reservoir; + long avg_bitsper; + long min_bitsper; + long max_bitsper; + + long short_per_long; + double avgfloat; + + vorbis_block *vb; + int choice; +} bitrate_manager_state; + +typedef struct bitrate_manager_info{ + long avg_rate; + long min_rate; + long max_rate; + long reservoir_bits; + double reservoir_bias; + + double slew_damp; + +} bitrate_manager_info; + +extern void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bs); +extern void vorbis_bitrate_clear(bitrate_manager_state *bs); +extern int vorbis_bitrate_managed(vorbis_block *vb); +extern int vorbis_bitrate_addblock(vorbis_block *vb); +extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, ogg_packet *op); + +#endif diff --git a/vendor/vorbis/lib/block.c b/vendor/vorbis/lib/block.c new file mode 100644 index 0000000..6a50da0 --- /dev/null +++ b/vendor/vorbis/lib/block.c @@ -0,0 +1,1046 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: PCM data vector blocking, windowing and dis/reassembly + + Handle windowing, overlap-add, etc of the PCM vectors. This is made + more amusing by Vorbis' current two allowed block sizes. + + ********************************************************************/ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" + +#include "window.h" +#include "mdct.h" +#include "lpc.h" +#include "registry.h" +#include "misc.h" + +/* pcm accumulator examples (not exhaustive): + + <-------------- lW ----------------> + <--------------- W ----------------> +: .....|..... _______________ | +: .''' | '''_--- | |\ | +:.....''' |_____--- '''......| | \_______| +:.................|__________________|_______|__|______| + |<------ Sl ------>| > Sr < |endW + |beginSl |endSl | |endSr + |beginW |endlW |beginSr + + + |< lW >| + <--------------- W ----------------> + | | .. ______________ | + | | ' `/ | ---_ | + |___.'___/`. | ---_____| + |_______|__|_______|_________________| + | >|Sl|< |<------ Sr ----->|endW + | | |endSl |beginSr |endSr + |beginW | |endlW + mult[0] |beginSl mult[n] + + <-------------- lW -----------------> + |<--W-->| +: .............. ___ | | +: .''' |`/ \ | | +:.....''' |/`....\|...| +:.........................|___|___|___| + |Sl |Sr |endW + | | |endSr + | |beginSr + | |endSl + |beginSl + |beginW +*/ + +/* block abstraction setup *********************************************/ + +#ifndef WORD_ALIGN +#define WORD_ALIGN 8 +#endif + +int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){ + int i; + memset(vb,0,sizeof(*vb)); + vb->vd=v; + vb->localalloc=0; + vb->localstore=NULL; + if(v->analysisp){ + vorbis_block_internal *vbi= + vb->internal=_ogg_calloc(1,sizeof(vorbis_block_internal)); + vbi->ampmax=-9999; + + for(i=0;ipacketblob[i]=&vb->opb; + }else{ + vbi->packetblob[i]= + _ogg_calloc(1,sizeof(oggpack_buffer)); + } + oggpack_writeinit(vbi->packetblob[i]); + } + } + + return(0); +} + +void *_vorbis_block_alloc(vorbis_block *vb,long bytes){ + bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1); + if(bytes+vb->localtop>vb->localalloc){ + /* can't just _ogg_realloc... there are outstanding pointers */ + if(vb->localstore){ + struct alloc_chain *link=_ogg_malloc(sizeof(*link)); + vb->totaluse+=vb->localtop; + link->next=vb->reap; + link->ptr=vb->localstore; + vb->reap=link; + } + /* highly conservative */ + vb->localalloc=bytes; + vb->localstore=_ogg_malloc(vb->localalloc); + vb->localtop=0; + } + { + void *ret=(void *)(((char *)vb->localstore)+vb->localtop); + vb->localtop+=bytes; + return ret; + } +} + +/* reap the chain, pull the ripcord */ +void _vorbis_block_ripcord(vorbis_block *vb){ + /* reap the chain */ + struct alloc_chain *reap=vb->reap; + while(reap){ + struct alloc_chain *next=reap->next; + _ogg_free(reap->ptr); + memset(reap,0,sizeof(*reap)); + _ogg_free(reap); + reap=next; + } + /* consolidate storage */ + if(vb->totaluse){ + vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc); + vb->localalloc+=vb->totaluse; + vb->totaluse=0; + } + + /* pull the ripcord */ + vb->localtop=0; + vb->reap=NULL; +} + +int vorbis_block_clear(vorbis_block *vb){ + int i; + vorbis_block_internal *vbi=vb->internal; + + _vorbis_block_ripcord(vb); + if(vb->localstore)_ogg_free(vb->localstore); + + if(vbi){ + for(i=0;ipacketblob[i]); + if(i!=PACKETBLOBS/2)_ogg_free(vbi->packetblob[i]); + } + _ogg_free(vbi); + } + memset(vb,0,sizeof(*vb)); + return(0); +} + +/* Analysis side code, but directly related to blocking. Thus it's + here and not in analysis.c (which is for analysis transforms only). + The init is here because some of it is shared */ + +static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){ + int i; + codec_setup_info *ci=vi->codec_setup; + private_state *b=NULL; + int hs; + + if(ci==NULL|| + ci->modes<=0|| + ci->blocksizes[0]<64|| + ci->blocksizes[1]blocksizes[0]){ + return 1; + } + hs=ci->halfrate_flag; + + memset(v,0,sizeof(*v)); + b=v->backend_state=_ogg_calloc(1,sizeof(*b)); + + v->vi=vi; + b->modebits=ov_ilog(ci->modes-1); + + b->transform[0]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0])); + b->transform[1]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1])); + + /* MDCT is tranform 0 */ + + b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup)); + b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup)); + mdct_init(b->transform[0][0],ci->blocksizes[0]>>hs); + mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs); + + /* Vorbis I uses only window type 0 */ + /* note that the correct computation below is technically: + b->window[0]=ov_ilog(ci->blocksizes[0]-1)-6; + b->window[1]=ov_ilog(ci->blocksizes[1]-1)-6; + but since blocksizes are always powers of two, + the below is equivalent. + */ + b->window[0]=ov_ilog(ci->blocksizes[0])-7; + b->window[1]=ov_ilog(ci->blocksizes[1])-7; + + if(encp){ /* encode/decode differ here */ + + /* analysis always needs an fft */ + drft_init(&b->fft_look[0],ci->blocksizes[0]); + drft_init(&b->fft_look[1],ci->blocksizes[1]); + + /* finish the codebooks */ + if(!ci->fullbooks){ + ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); + for(i=0;ibooks;i++) + vorbis_book_init_encode(ci->fullbooks+i,ci->book_param[i]); + } + + b->psy=_ogg_calloc(ci->psys,sizeof(*b->psy)); + for(i=0;ipsys;i++){ + _vp_psy_init(b->psy+i, + ci->psy_param[i], + &ci->psy_g_param, + ci->blocksizes[ci->psy_param[i]->blockflag]/2, + vi->rate); + } + + v->analysisp=1; + }else{ + /* finish the codebooks */ + if(!ci->fullbooks){ + ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); + for(i=0;ibooks;i++){ + if(ci->book_param[i]==NULL) + goto abort_books; + if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i])) + goto abort_books; + /* decode codebooks are now standalone after init */ + vorbis_staticbook_destroy(ci->book_param[i]); + ci->book_param[i]=NULL; + } + } + } + + /* initialize the storage vectors. blocksize[1] is small for encode, + but the correct size for decode */ + v->pcm_storage=ci->blocksizes[1]; + v->pcm=_ogg_malloc(vi->channels*sizeof(*v->pcm)); + v->pcmret=_ogg_malloc(vi->channels*sizeof(*v->pcmret)); + { + int i; + for(i=0;ichannels;i++) + v->pcm[i]=_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i])); + } + + /* all 1 (large block) or 0 (small block) */ + /* explicitly set for the sake of clarity */ + v->lW=0; /* previous window size */ + v->W=0; /* current window size */ + + /* all vector indexes */ + v->centerW=ci->blocksizes[1]/2; + + v->pcm_current=v->centerW; + + /* initialize all the backend lookups */ + b->flr=_ogg_calloc(ci->floors,sizeof(*b->flr)); + b->residue=_ogg_calloc(ci->residues,sizeof(*b->residue)); + + for(i=0;ifloors;i++) + b->flr[i]=_floor_P[ci->floor_type[i]]-> + look(v,ci->floor_param[i]); + + for(i=0;iresidues;i++) + b->residue[i]=_residue_P[ci->residue_type[i]]-> + look(v,ci->residue_param[i]); + + return 0; + abort_books: + for(i=0;ibooks;i++){ + if(ci->book_param[i]!=NULL){ + vorbis_staticbook_destroy(ci->book_param[i]); + ci->book_param[i]=NULL; + } + } + vorbis_dsp_clear(v); + return -1; +} + +/* arbitrary settings and spec-mandated numbers get filled in here */ +int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){ + private_state *b=NULL; + + if(_vds_shared_init(v,vi,1))return 1; + b=v->backend_state; + b->psy_g_look=_vp_global_look(vi); + + /* Initialize the envelope state storage */ + b->ve=_ogg_calloc(1,sizeof(*b->ve)); + _ve_envelope_init(b->ve,vi); + + vorbis_bitrate_init(vi,&b->bms); + + /* compressed audio packets start after the headers + with sequence number 3 */ + v->sequence=3; + + return(0); +} + +void vorbis_dsp_clear(vorbis_dsp_state *v){ + int i; + if(v){ + vorbis_info *vi=v->vi; + codec_setup_info *ci=(vi?vi->codec_setup:NULL); + private_state *b=v->backend_state; + + if(b){ + + if(b->ve){ + _ve_envelope_clear(b->ve); + _ogg_free(b->ve); + } + + if(b->transform[0]){ + mdct_clear(b->transform[0][0]); + _ogg_free(b->transform[0][0]); + _ogg_free(b->transform[0]); + } + if(b->transform[1]){ + mdct_clear(b->transform[1][0]); + _ogg_free(b->transform[1][0]); + _ogg_free(b->transform[1]); + } + + if(b->flr){ + if(ci) + for(i=0;ifloors;i++) + _floor_P[ci->floor_type[i]]-> + free_look(b->flr[i]); + _ogg_free(b->flr); + } + if(b->residue){ + if(ci) + for(i=0;iresidues;i++) + _residue_P[ci->residue_type[i]]-> + free_look(b->residue[i]); + _ogg_free(b->residue); + } + if(b->psy){ + if(ci) + for(i=0;ipsys;i++) + _vp_psy_clear(b->psy+i); + _ogg_free(b->psy); + } + + if(b->psy_g_look)_vp_global_free(b->psy_g_look); + vorbis_bitrate_clear(&b->bms); + + drft_clear(&b->fft_look[0]); + drft_clear(&b->fft_look[1]); + + } + + if(v->pcm){ + if(vi) + for(i=0;ichannels;i++) + if(v->pcm[i])_ogg_free(v->pcm[i]); + _ogg_free(v->pcm); + if(v->pcmret)_ogg_free(v->pcmret); + } + + if(b){ + /* free header, header1, header2 */ + if(b->header)_ogg_free(b->header); + if(b->header1)_ogg_free(b->header1); + if(b->header2)_ogg_free(b->header2); + _ogg_free(b); + } + + memset(v,0,sizeof(*v)); + } +} + +float **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){ + int i; + vorbis_info *vi=v->vi; + private_state *b=v->backend_state; + + /* free header, header1, header2 */ + if(b->header)_ogg_free(b->header);b->header=NULL; + if(b->header1)_ogg_free(b->header1);b->header1=NULL; + if(b->header2)_ogg_free(b->header2);b->header2=NULL; + + /* Do we have enough storage space for the requested buffer? If not, + expand the PCM (and envelope) storage */ + + if(v->pcm_current+vals>=v->pcm_storage){ + v->pcm_storage=v->pcm_current+vals*2; + + for(i=0;ichannels;i++){ + v->pcm[i]=_ogg_realloc(v->pcm[i],v->pcm_storage*sizeof(*v->pcm[i])); + } + } + + for(i=0;ichannels;i++) + v->pcmret[i]=v->pcm[i]+v->pcm_current; + + return(v->pcmret); +} + +static void _preextrapolate_helper(vorbis_dsp_state *v){ + int i; + int order=16; + float *lpc=alloca(order*sizeof(*lpc)); + float *work=alloca(v->pcm_current*sizeof(*work)); + long j; + v->preextrapolate=1; + + if(v->pcm_current-v->centerW>order*2){ /* safety */ + for(i=0;ivi->channels;i++){ + /* need to run the extrapolation in reverse! */ + for(j=0;jpcm_current;j++) + work[j]=v->pcm[i][v->pcm_current-j-1]; + + /* prime as above */ + vorbis_lpc_from_data(work,lpc,v->pcm_current-v->centerW,order); + +#if 0 + if(v->vi->channels==2){ + if(i==0) + _analysis_output("predataL",0,work,v->pcm_current-v->centerW,0,0,0); + else + _analysis_output("predataR",0,work,v->pcm_current-v->centerW,0,0,0); + }else{ + _analysis_output("predata",0,work,v->pcm_current-v->centerW,0,0,0); + } +#endif + + /* run the predictor filter */ + vorbis_lpc_predict(lpc,work+v->pcm_current-v->centerW-order, + order, + work+v->pcm_current-v->centerW, + v->centerW); + + for(j=0;jpcm_current;j++) + v->pcm[i][v->pcm_current-j-1]=work[j]; + + } + } +} + + +/* call with val<=0 to set eof */ + +int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){ + vorbis_info *vi=v->vi; + codec_setup_info *ci=vi->codec_setup; + + if(vals<=0){ + int order=32; + int i; + float *lpc=alloca(order*sizeof(*lpc)); + + /* if it wasn't done earlier (very short sample) */ + if(!v->preextrapolate) + _preextrapolate_helper(v); + + /* We're encoding the end of the stream. Just make sure we have + [at least] a few full blocks of zeroes at the end. */ + /* actually, we don't want zeroes; that could drop a large + amplitude off a cliff, creating spread spectrum noise that will + suck to encode. Extrapolate for the sake of cleanliness. */ + + vorbis_analysis_buffer(v,ci->blocksizes[1]*3); + v->eofflag=v->pcm_current; + v->pcm_current+=ci->blocksizes[1]*3; + + for(i=0;ichannels;i++){ + if(v->eofflag>order*2){ + /* extrapolate with LPC to fill in */ + long n; + + /* make a predictor filter */ + n=v->eofflag; + if(n>ci->blocksizes[1])n=ci->blocksizes[1]; + vorbis_lpc_from_data(v->pcm[i]+v->eofflag-n,lpc,n,order); + + /* run the predictor filter */ + vorbis_lpc_predict(lpc,v->pcm[i]+v->eofflag-order,order, + v->pcm[i]+v->eofflag,v->pcm_current-v->eofflag); + }else{ + /* not enough data to extrapolate (unlikely to happen due to + guarding the overlap, but bulletproof in case that + assumtion goes away). zeroes will do. */ + memset(v->pcm[i]+v->eofflag,0, + (v->pcm_current-v->eofflag)*sizeof(*v->pcm[i])); + + } + } + }else{ + + if(v->pcm_current+vals>v->pcm_storage) + return(OV_EINVAL); + + v->pcm_current+=vals; + + /* we may want to reverse extrapolate the beginning of a stream + too... in case we're beginning on a cliff! */ + /* clumsy, but simple. It only runs once, so simple is good. */ + if(!v->preextrapolate && v->pcm_current-v->centerW>ci->blocksizes[1]) + _preextrapolate_helper(v); + + } + return(0); +} + +/* do the deltas, envelope shaping, pre-echo and determine the size of + the next block on which to continue analysis */ +int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){ + int i; + vorbis_info *vi=v->vi; + codec_setup_info *ci=vi->codec_setup; + private_state *b=v->backend_state; + vorbis_look_psy_global *g=b->psy_g_look; + long beginW=v->centerW-ci->blocksizes[v->W]/2,centerNext; + vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal; + + /* check to see if we're started... */ + if(!v->preextrapolate)return(0); + + /* check to see if we're done... */ + if(v->eofflag==-1)return(0); + + /* By our invariant, we have lW, W and centerW set. Search for + the next boundary so we can determine nW (the next window size) + which lets us compute the shape of the current block's window */ + + /* we do an envelope search even on a single blocksize; we may still + be throwing more bits at impulses, and envelope search handles + marking impulses too. */ + { + long bp=_ve_envelope_search(v); + if(bp==-1){ + + if(v->eofflag==0)return(0); /* not enough data currently to search for a + full long block */ + v->nW=0; + }else{ + + if(ci->blocksizes[0]==ci->blocksizes[1]) + v->nW=0; + else + v->nW=bp; + } + } + + centerNext=v->centerW+ci->blocksizes[v->W]/4+ci->blocksizes[v->nW]/4; + + { + /* center of next block + next block maximum right side. */ + + long blockbound=centerNext+ci->blocksizes[v->nW]/2; + if(v->pcm_currentlW=v->lW; + vb->W=v->W; + vb->nW=v->nW; + + if(v->W){ + if(!v->lW || !v->nW){ + vbi->blocktype=BLOCKTYPE_TRANSITION; + /*fprintf(stderr,"-");*/ + }else{ + vbi->blocktype=BLOCKTYPE_LONG; + /*fprintf(stderr,"_");*/ + } + }else{ + if(_ve_envelope_mark(v)){ + vbi->blocktype=BLOCKTYPE_IMPULSE; + /*fprintf(stderr,"|");*/ + + }else{ + vbi->blocktype=BLOCKTYPE_PADDING; + /*fprintf(stderr,".");*/ + + } + } + + vb->vd=v; + vb->sequence=v->sequence++; + vb->granulepos=v->granulepos; + vb->pcmend=ci->blocksizes[v->W]; + + /* copy the vectors; this uses the local storage in vb */ + + /* this tracks 'strongest peak' for later psychoacoustics */ + /* moved to the global psy state; clean this mess up */ + if(vbi->ampmax>g->ampmax)g->ampmax=vbi->ampmax; + g->ampmax=_vp_ampmax_decay(g->ampmax,v); + vbi->ampmax=g->ampmax; + + vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels); + vbi->pcmdelay=_vorbis_block_alloc(vb,sizeof(*vbi->pcmdelay)*vi->channels); + for(i=0;ichannels;i++){ + vbi->pcmdelay[i]= + _vorbis_block_alloc(vb,(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i])); + memcpy(vbi->pcmdelay[i],v->pcm[i],(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i])); + vb->pcm[i]=vbi->pcmdelay[i]+beginW; + + /* before we added the delay + vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i])); + memcpy(vb->pcm[i],v->pcm[i]+beginW,ci->blocksizes[v->W]*sizeof(*vb->pcm[i])); + */ + + } + + /* handle eof detection: eof==0 means that we've not yet received EOF + eof>0 marks the last 'real' sample in pcm[] + eof<0 'no more to do'; doesn't get here */ + + if(v->eofflag){ + if(v->centerW>=v->eofflag){ + v->eofflag=-1; + vb->eofflag=1; + return(1); + } + } + + /* advance storage vectors and clean up */ + { + int new_centerNext=ci->blocksizes[1]/2; + int movementW=centerNext-new_centerNext; + + if(movementW>0){ + + _ve_envelope_shift(b->ve,movementW); + v->pcm_current-=movementW; + + for(i=0;ichannels;i++) + memmove(v->pcm[i],v->pcm[i]+movementW, + v->pcm_current*sizeof(*v->pcm[i])); + + + v->lW=v->W; + v->W=v->nW; + v->centerW=new_centerNext; + + if(v->eofflag){ + v->eofflag-=movementW; + if(v->eofflag<=0)v->eofflag=-1; + /* do not add padding to end of stream! */ + if(v->centerW>=v->eofflag){ + v->granulepos+=movementW-(v->centerW-v->eofflag); + }else{ + v->granulepos+=movementW; + } + }else{ + v->granulepos+=movementW; + } + } + } + + /* done */ + return(1); +} + +int vorbis_synthesis_restart(vorbis_dsp_state *v){ + vorbis_info *vi=v->vi; + codec_setup_info *ci; + int hs; + + if(!v->backend_state)return -1; + if(!vi)return -1; + ci=vi->codec_setup; + if(!ci)return -1; + hs=ci->halfrate_flag; + + v->centerW=ci->blocksizes[1]>>(hs+1); + v->pcm_current=v->centerW>>hs; + + v->pcm_returned=-1; + v->granulepos=-1; + v->sequence=-1; + v->eofflag=0; + ((private_state *)(v->backend_state))->sample_count=-1; + + return(0); +} + +int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){ + if(_vds_shared_init(v,vi,0)){ + vorbis_dsp_clear(v); + return 1; + } + vorbis_synthesis_restart(v); + return 0; +} + +/* Unlike in analysis, the window is only partially applied for each + block. The time domain envelope is not yet handled at the point of + calling (as it relies on the previous block). */ + +int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ + vorbis_info *vi=v->vi; + codec_setup_info *ci=vi->codec_setup; + private_state *b=v->backend_state; + int hs=ci->halfrate_flag; + int i,j; + + if(!vb)return(OV_EINVAL); + if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL); + + v->lW=v->W; + v->W=vb->W; + v->nW=-1; + + if((v->sequence==-1)|| + (v->sequence+1 != vb->sequence)){ + v->granulepos=-1; /* out of sequence; lose count */ + b->sample_count=-1; + } + + v->sequence=vb->sequence; + + if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly + was called on block */ + int n=ci->blocksizes[v->W]>>(hs+1); + int n0=ci->blocksizes[0]>>(hs+1); + int n1=ci->blocksizes[1]>>(hs+1); + + int thisCenter; + int prevCenter; + + v->glue_bits+=vb->glue_bits; + v->time_bits+=vb->time_bits; + v->floor_bits+=vb->floor_bits; + v->res_bits+=vb->res_bits; + + if(v->centerW){ + thisCenter=n1; + prevCenter=0; + }else{ + thisCenter=0; + prevCenter=n1; + } + + /* v->pcm is now used like a two-stage double buffer. We don't want + to have to constantly shift *or* adjust memory usage. Don't + accept a new block until the old is shifted out */ + + for(j=0;jchannels;j++){ + /* the overlap/add section */ + if(v->lW){ + if(v->W){ + /* large/large */ + const float *w=_vorbis_window_get(b->window[1]-hs); + float *pcm=v->pcm[j]+prevCenter; + float *p=vb->pcm[j]; + for(i=0;iwindow[0]-hs); + float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2; + float *p=vb->pcm[j]; + for(i=0;iW){ + /* small/large */ + const float *w=_vorbis_window_get(b->window[0]-hs); + float *pcm=v->pcm[j]+prevCenter; + float *p=vb->pcm[j]+n1/2-n0/2; + for(i=0;iwindow[0]-hs); + float *pcm=v->pcm[j]+prevCenter; + float *p=vb->pcm[j]; + for(i=0;ipcm[j]+thisCenter; + float *p=vb->pcm[j]+n; + for(i=0;icenterW) + v->centerW=0; + else + v->centerW=n1; + + /* deal with initial packet state; we do this using the explicit + pcm_returned==-1 flag otherwise we're sensitive to first block + being short or long */ + + if(v->pcm_returned==-1){ + v->pcm_returned=thisCenter; + v->pcm_current=thisCenter; + }else{ + v->pcm_returned=prevCenter; + v->pcm_current=prevCenter+ + ((ci->blocksizes[v->lW]/4+ + ci->blocksizes[v->W]/4)>>hs); + } + + } + + /* track the frame number... This is for convenience, but also + making sure our last packet doesn't end with added padding. If + the last packet is partial, the number of samples we'll have to + return will be past the vb->granulepos. + + This is not foolproof! It will be confused if we begin + decoding at the last page after a seek or hole. In that case, + we don't have a starting point to judge where the last frame + is. For this reason, vorbisfile will always try to make sure + it reads the last two marked pages in proper sequence */ + + if(b->sample_count==-1){ + b->sample_count=0; + }else{ + b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; + } + + if(v->granulepos==-1){ + if(vb->granulepos!=-1){ /* only set if we have a position to set to */ + + v->granulepos=vb->granulepos; + + /* is this a short page? */ + if(b->sample_count>v->granulepos){ + /* corner case; if this is both the first and last audio page, + then spec says the end is cut, not beginning */ + long extra=b->sample_count-vb->granulepos; + + /* we use ogg_int64_t for granule positions because a + uint64 isn't universally available. Unfortunately, + that means granposes can be 'negative' and result in + extra being negative */ + if(extra<0) + extra=0; + + if(vb->eofflag){ + /* trim the end */ + /* no preceding granulepos; assume we started at zero (we'd + have to in a short single-page stream) */ + /* granulepos could be -1 due to a seek, but that would result + in a long count, not short count */ + + /* Guard against corrupt/malicious frames that set EOP and + a backdated granpos; don't rewind more samples than we + actually have */ + if(extra > (v->pcm_current - v->pcm_returned)<pcm_current - v->pcm_returned)<pcm_current-=extra>>hs; + }else{ + /* trim the beginning */ + v->pcm_returned+=extra>>hs; + if(v->pcm_returned>v->pcm_current) + v->pcm_returned=v->pcm_current; + } + + } + + } + }else{ + v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; + if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){ + + if(v->granulepos>vb->granulepos){ + long extra=v->granulepos-vb->granulepos; + + if(extra) + if(vb->eofflag){ + /* partial last frame. Strip the extra samples off */ + + /* Guard against corrupt/malicious frames that set EOP and + a backdated granpos; don't rewind more samples than we + actually have */ + if(extra > (v->pcm_current - v->pcm_returned)<pcm_current - v->pcm_returned)<pcm_current-=extra>>hs; + } /* else {Shouldn't happen *unless* the bitstream is out of + spec. Either way, believe the bitstream } */ + } /* else {Shouldn't happen *unless* the bitstream is out of + spec. Either way, believe the bitstream } */ + v->granulepos=vb->granulepos; + } + } + + /* Update, cleanup */ + + if(vb->eofflag)v->eofflag=1; + return(0); + +} + +/* pcm==NULL indicates we just want the pending samples, no more */ +int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){ + vorbis_info *vi=v->vi; + + if(v->pcm_returned>-1 && v->pcm_returnedpcm_current){ + if(pcm){ + int i; + for(i=0;ichannels;i++) + v->pcmret[i]=v->pcm[i]+v->pcm_returned; + *pcm=v->pcmret; + } + return(v->pcm_current-v->pcm_returned); + } + return(0); +} + +int vorbis_synthesis_read(vorbis_dsp_state *v,int n){ + if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL); + v->pcm_returned+=n; + return(0); +} + +/* intended for use with a specific vorbisfile feature; we want access + to the [usually synthetic/postextrapolated] buffer and lapping at + the end of a decode cycle, specifically, a half-short-block worth. + This funtion works like pcmout above, except it will also expose + this implicit buffer data not normally decoded. */ +int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){ + vorbis_info *vi=v->vi; + codec_setup_info *ci=vi->codec_setup; + int hs=ci->halfrate_flag; + + int n=ci->blocksizes[v->W]>>(hs+1); + int n0=ci->blocksizes[0]>>(hs+1); + int n1=ci->blocksizes[1]>>(hs+1); + int i,j; + + if(v->pcm_returned<0)return 0; + + /* our returned data ends at pcm_returned; because the synthesis pcm + buffer is a two-fragment ring, that means our data block may be + fragmented by buffering, wrapping or a short block not filling + out a buffer. To simplify things, we unfragment if it's at all + possibly needed. Otherwise, we'd need to call lapout more than + once as well as hold additional dsp state. Opt for + simplicity. */ + + /* centerW was advanced by blockin; it would be the center of the + *next* block */ + if(v->centerW==n1){ + /* the data buffer wraps; swap the halves */ + /* slow, sure, small */ + for(j=0;jchannels;j++){ + float *p=v->pcm[j]; + for(i=0;ipcm_current-=n1; + v->pcm_returned-=n1; + v->centerW=0; + } + + /* solidify buffer into contiguous space */ + if((v->lW^v->W)==1){ + /* long/short or short/long */ + for(j=0;jchannels;j++){ + float *s=v->pcm[j]; + float *d=v->pcm[j]+(n1-n0)/2; + for(i=(n1+n0)/2-1;i>=0;--i) + d[i]=s[i]; + } + v->pcm_returned+=(n1-n0)/2; + v->pcm_current+=(n1-n0)/2; + }else{ + if(v->lW==0){ + /* short/short */ + for(j=0;jchannels;j++){ + float *s=v->pcm[j]; + float *d=v->pcm[j]+n1-n0; + for(i=n0-1;i>=0;--i) + d[i]=s[i]; + } + v->pcm_returned+=n1-n0; + v->pcm_current+=n1-n0; + } + } + + if(pcm){ + int i; + for(i=0;ichannels;i++) + v->pcmret[i]=v->pcm[i]+v->pcm_returned; + *pcm=v->pcmret; + } + + return(n1+n-v->pcm_returned); + +} + +const float *vorbis_window(vorbis_dsp_state *v,int W){ + vorbis_info *vi=v->vi; + codec_setup_info *ci=vi->codec_setup; + int hs=ci->halfrate_flag; + private_state *b=v->backend_state; + + if(b->window[W]-1<0)return NULL; + return _vorbis_window_get(b->window[W]-hs); +} diff --git a/vendor/vorbis/lib/books/Makefile.am b/vendor/vorbis/lib/books/Makefile.am new file mode 100644 index 0000000..3697a71 --- /dev/null +++ b/vendor/vorbis/lib/books/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = coupled uncoupled floor diff --git a/vendor/vorbis/lib/books/coupled/Makefile.am b/vendor/vorbis/lib/books/coupled/Makefile.am new file mode 100644 index 0000000..1115201 --- /dev/null +++ b/vendor/vorbis/lib/books/coupled/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = res_books_stereo.h res_books_51.h diff --git a/vendor/vorbis/lib/books/coupled/res_books_51.h b/vendor/vorbis/lib/books/coupled/res_books_51.h new file mode 100644 index 0000000..eb569c6 --- /dev/null +++ b/vendor/vorbis/lib/books/coupled/res_books_51.h @@ -0,0 +1,12273 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + * + * function: static codebooks for 5.1 surround + * + ********************************************************************/ + +static const long _vq_quantlist__44p0_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p0_l0_0[] = { + 1, 3, 4, 7, 7, 8, 8, 9, 9, 9,10,10,10, 5, 6, 5, + 8, 7, 9, 8, 9, 9,10, 9,11,10, 5, 5, 7, 7, 8, 8, + 9, 9, 9, 9,10,10,11, 8, 9, 8,10, 9,10, 9,10, 9, + 11,10,11,10, 8, 8, 9, 9,10, 9,10, 9,11,10,11,10, + 11,10,11,11,11,11,11,11,11,11,11,11,11,11,10,11, + 11,11,12,11,11,11,11,11,11,10,12,12,12,12,12,12, + 12,11,12,12,12,11,11,11,12,12,12,12,12,12,12,11, + 12,11,12,11,11,13,12,12,12,13,12,12,12,12,11,12, + 11,11,13,13,13,12,12,12,12,12,12,11,11,11,10,13, + 13,13,12,13,12,13,11,13,10,12,11,11,13,13,12,13, + 12,12,12,12,11,12,11,11,11, +}; + +static const static_codebook _44p0_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p0_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p0_l0_0, + 0 +}; + +static const long _vq_quantlist__44p0_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p0_l0_1[] = { + 1, 4, 4, 6, 6, 5, 5, 5, 7, 5, 5, 5, 5, 6, 7, 7, + 6, 7, 7, 7, 6, 7, 7, 7, 7, +}; + +static const static_codebook _44p0_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p0_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p0_l0_1, + 0 +}; + +static const long _vq_quantlist__44p0_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_l1_0[] = { + 1, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const static_codebook _44p0_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44p0_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p0_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p0_lfe[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book__44p0_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p0_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p0_long[] = { + 2, 3, 6, 7,10,14,16, 3, 2, 5, 7,11,14,17, 6, 5, + 5, 7,10,12,14, 7, 7, 6, 6, 7, 9,13,10,11, 9, 6, + 6, 9,11,15,15,13,10, 9,10,12,18,18,16,14,12,13, + 16, +}; + +static const static_codebook _huff_book__44p0_long = { + 2, 49, + (char *)_huff_lengthlist__44p0_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p0_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_p1_0[] = { + 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p0_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p0_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p0_p1_0, + 0 +}; + +static const long _vq_quantlist__44p0_p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_p2_0[] = { + 1, 5, 5, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0,12,12, 0, + 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 0, 6, 6, 0,11, + 11, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0,12,12, + 0,15,15, 0,12,12, 0, 5, 5, 0, 5, 5, 0, 6, 6, 0, + 7, 7, 0,11,11, 0, 6, 6, 0, 7, 7, 0,10,11, 0, 6, + 6, 0, 7, 7, 0,11,11, 0,12,12, 0,11,11, 0,15,15, + 0,10,10, 0,12,12, 0,15,15, 0,12,12, 0, 6, 6, 0, + 12,12, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0,12, + 12, 0,15,15, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 8, 0,12,12, 0,12,12, 0,12,12, 0,15, + 15, 0,12,12, 0,11,12, 0,15,16, 0,11,11, 0, 6, 6, + 0,11,12, 0,12,12, 0,12,12, 0,16,15, 0,12,12, 0, + 13,12, 0,15,14, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p0_p2_0 = { + 5, 243, + (char *)_vq_lengthlist__44p0_p2_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p0_p2_0, + 0 +}; + +static const long _vq_quantlist__44p0_p2_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_p2_1[] = { + 1, 3, 3, 0, 9, 9, 0, 9, 9, 0,10,10, 0, 9, 9, 0, + 10,10, 0,10,10, 0, 9, 9, 0,10,10, 0, 7, 7, 0, 7, + 7, 0, 6, 6, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 9, + 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 9, 9, 0, 8, 8, 0, + 10,10, 0, 9, 9, 0,10,10, 0,10,10, 0, 9, 9, 0,10, + 10, 0, 9, 9, 0,11,11, 0,11,11, 0,12,12, 0,11,11, + 0,12,12, 0,13,13, 0,12,12, 0,13,12, 0, 8, 8, 0, + 12,12, 0,12,12, 0,13,13, 0,12,12, 0,13,13, 0,13, + 13, 0,13,13, 0,13,13, 0, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 0,11,11, 0,12,12, 0,13,13, 0,12, + 12, 0,13,13, 0,13,13, 0,12,12, 0,12,12, 0, 8, 8, + 0,12,12, 0,12,12, 0,13,13, 0,13,13, 0,13,14, 0, + 14,13, 0,13,13, 0,13,13, 0, 7, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p0_p2_1 = { + 5, 243, + (char *)_vq_lengthlist__44p0_p2_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p0_p2_1, + 0 +}; + +static const long _vq_quantlist__44p0_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_p3_0[] = { + 1, 6, 6, 7, 8, 8, 7, 8, 8, 7, 9, 9,10,12,11, 9, + 8, 8, 7, 9, 9,11,12,12, 9, 9, 9, 6, 7, 7,10,11, + 11,10,11,11,10,11,11,13,13,14,12,12,12,11,11,11, + 14,14,14,12,12,12, 6, 5, 5, 9, 6, 5, 9, 6, 6, 9, + 7, 7,12,10,10,11, 6, 6,10, 7, 7,13,10,10,12, 7, + 7, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13, + 13, 9, 9,12,11,11,16,13,13,15,11,11, 8, 7, 7,12, + 12,12,12,11,11,12,11,11,14,14,14,14,12,12,12,12, + 12,16,15,15,14,12,12, 0,10,10, 0,12,12, 0,12,12, + 0,11,11, 0,14,14, 0,11,11, 0,12,12, 0,15,15, 0, + 11,11, 8, 8, 8,13,11,11,13,10,10,13,11,11,15,13, + 13,14,11,11,12,10,10,16,14,14,14,10,10, 9, 7, 7, + 13,11,11,13,11,11,12,11,11,16,14,14,14,12,12,13, + 12,12,15,14,14,15,13,12, 0,11,11, 0,12,12, 0,12, + 12, 0,12,12, 0,15,15, 0,12,12, 0,13,12, 0,14,15, + 0,12,12, +}; + +static const static_codebook _44p0_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p0_p3_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p0_p3_0, + 0 +}; + +static const long _vq_quantlist__44p0_p3_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p0_p3_1[] = { + 2, 4, 4, 8, 8,10,12,12,11,11, 9,11,11,12,13,11, + 12,12,11,11,11,12,12,12,12,10,13,12,13,13,11,12, + 12,13,13,11,12,12,13,13,11,12,13,13,13,11,13,13, + 13,13,10,13,13,12,13,11,12,12,14,14,11,13,12,12, + 12,11,12,12,13,13,11,13,13,12,12,11,13,13,13,13, + 11,12,12,13,13,11,13,13,12,12,11,12,12,13,13,11, + 13,13,12,12,11,13,13,13,13,11,12,12,14,14,11,13, + 13,12,12,11,12,12,13,13,11,13,13,12,12,11,10,10, + 10,10,12,10,10,11,11,11, 8, 8,11,11,13,10,10,10, + 10,12,10,10,10,10,13,11,11,11,11,13,10,10,11,11, + 13,11,11,12,12,13,11,11,11,11,13,11,11,12,12,13, + 11,11,12,12,13,10,10,11,11,13,11,11,11,11,13,11, + 10,11,11,13,11,11,11,11,13,11,11,11,11,13,10,10, + 11,11,13,11,11,11,11,12,10,11,11,11,13,11,11,11, + 11,13,11,11,11,11,13,10,10,11,11,13,11,11,11,11, + 13,11,11,11,11,13,11,11,11,11,11,10,10,10,10,12, + 10,10, 9, 9,12,12,12,11,11,13,12,12, 9, 9,13,12, + 12,10,10,12,12,12,12,12,13,13,13,14,14,13,12,12, + 11,11,13,13,13,12,12,13,12,12,11,11,13,12,13,11, + 11,13,13,13,14,14,13,12,12,10,10,13,13,13,11,11, + 13,12,12,10,10,13,13,13,11,11,13,13,13,14,14,13, + 12,12,10,10,13,13,13,11,11,13,12,13,10,10,13,13, + 13,11,11,13,13,13,14,14,13,12,12,10,10,13,13,13, + 11,11,13,13,12,10,10,14,12,12, 8, 8,14,12,12, 9, + 9,14,11,11, 9, 9,14,12,12, 8, 8,14,11,11, 7, 7, + 14,13,13,10,10,15,12,12,10,10,15,13,13,10,10,15, + 12,12, 9, 9,15,13,13,10,10,15,13,13,10,10,15,12, + 12,10,10,15,13,13,10,10,14,12,12, 9, 9,14,13,13, + 9, 9,14,13,13, 9, 9,15,12,12, 9, 9,15,13,13, 9, + 9,14,12,12, 9, 9,14,13,13, 9, 9,14,13,13, 9, 9, + 15,12,12, 9, 9,14,13,13, 9, 9,14,12,12, 9, 9,14, + 13,13, 9, 9,13,12,12, 8, 8,13,13,13, 8, 8,14,13, + 13, 9, 9,13,13,13, 7, 7,14,13,13, 8, 8,14,14,14, + 10,10,14,14,14,11,11,14,14,14, 9, 9,14,14,14,10, + 10,14,14,14, 9, 9,14,14,14,10, 9,15,14,14,11,11, + 14,14,14, 9, 9,14,14,14,10,10,14,14,14, 9, 9,14, + 14,14, 9, 9,15,14,14,11,11,14,14,14, 8, 8,14,14, + 14, 9, 9,14,14,14, 8, 8,14,14,14, 9, 9,15,14,14, + 11,11,14,14,14, 8, 8,14,14,14, 9, 9,14,14,14, 8, + 8,12,12,12,13,13,16,15,15,11,11,16,15,16,12,12, + 17,16,16,11,11,17,15,15,12,11,16,16,16,12,13,16, + 15,15,13,13,16,16,16,12,12,16,16,15,13,13,16,16, + 16,12,12,16,16,16,13,13,17,16,16,14,14,17,17,16, + 12,12,17,16,16,13,13,17,17,16,12,13,16,16,17,13, + 12,17,16,16,14,13,17,16,16,12,12,17,16,16,12,12, + 17,16,17,12,12,17,17,17,13,13,16,16,16,13,14,17, + 17,16,12,12,16,16,16,13,13,17,17,17,12,12,13,14, + 14,10,10,16,14,14,12,12,16,15,15,14,14,16,14,14, + 12,12,15,14,14,13,13,17,15,15,14,13,16,16,15,15, + 15,16,15,15,14,14,16,15,15,14,14,17,15,15,14,14, + 16,15,15,14,14,16,16,15,15,15,17,15,15,13,13,16, + 15,15,14,14,17,15,15,13,13,17,15,15,14,14,16,15, + 15,15,15,16,14,14,13,13,16,15,15,14,14,16,14,14, + 13,13,17,15,15,14,14,16,16,15,15,15,17,14,14,13, + 13,16,15,15,14,14,17,14,14,13,13,13,11,11,10,10, + 16,14,14,13,13,15,14,14,13,13,16,14,14,12,12,16, + 14,14,12,12,15,15,15,14,14,16,14,14,14,14,16,15, + 14,14,14,16,14,14,14,14,16,15,15,14,13,16,15,15, + 14,14,16,14,14,14,14,17,15,15,14,14,16,14,14,14, + 14,16,15,15,13,14,16,15,15,14,14,16,14,14,14,14, + 16,15,15,13,13,16,14,14,13,13,16,15,15,13,13,16, + 15,15,14,14,16,14,14,14,14,17,15,15,13,13,16,15, + 14,13,13,17,15,15,13,13,14,14,14, 9, 9,14,14,14, + 17,17,14,15,15,18,18,14,14,14,18,19,14,14,14,18, + 18,15,15,15,19,18,15,16,15,18,20,15,15,15,18,19, + 15,15,15,19,19,15,15,15,18,20,15,15,15,18,19,15, + 15,16,20,18,15,15,15,18,18,15,15,15,19,19,15,15, + 15,18,19,15,15,15,18,19,15,15,15,19,19,14,15,14, + 19,19,15,15,15,20,19,15,14,14,19,18,14,15,15,18, + 19,15,15,16,20,20,14,14,14,18,19,15,15,15,19,18, + 14,14,14,18,18,14,12,12, 9, 9,13,14,14,18,18,14, + 13,13,18,19,14,14,14,18,18,14,14,14,18,18,15,15, + 15,19,19,15,14,14,19,18,14,15,15,19,18,15,14,14, + 18,18,15,15,15,19,18,14,15,15,19,19,15,14,14,19, + 18,14,15,15,19,18,15,14,14,19,18,14,15,15,19,18, + 15,15,15,21,18,15,14,14,19,18,14,15,15,18,19,14, + 15,14,20,19,14,15,15,18,19,14,15,15,19,19,15,14, + 14,19,20,14,15,15,18,18,14,14,14,19,19,14,15,15, + 19,18,12,12,12,13,13,16,15,15,11,11,16,15,15,12, + 12,16,16,16,11,11,16,15,15,11,11,16,16,16,13,13, + 17,16,16,13,13,17,17,17,12,12,16,16,16,13,13,17, + 16,17,13,12,15,16,16,12,12,16,15,15,13,13,17,16, + 16,12,12,16,16,15,12,12,16,16,16,12,12,17,17,16, + 13,12,16,16,16,13,13,17,16,16,12,12,17,16,16,12, + 12,17,17,16,12,12,16,17,16,12,12,17,15,15,13,13, + 17,16,16,12,12,16,16,16,12,12,16,16,16,12,12,13, + 13,13, 9, 9,15,14,14,13,13,16,15,14,14,14,16,14, + 14,13,13,15,14,14,13,13,17,15,15,14,14,16,15,15, + 15,15,16,15,15,14,14,16,15,15,15,15,17,15,15,14, + 14,16,15,15,14,14,16,15,15,15,15,17,14,15,14,14, + 16,15,15,14,14,17,15,15,13,14,17,15,15,14,14,16, + 15,15,15,15,17,14,14,13,13,16,15,15,14,14,17,14, + 14,13,13,17,15,15,14,14,16,15,16,15,15,17,14,14, + 13,13,16,15,15,14,14,18,14,14,13,13,13,11,11,11, + 11,15,14,14,12,12,15,14,14,13,13,16,14,14,12,12, + 16,13,14,12,12,16,15,15,13,13,16,14,14,14,14,16, + 15,15,13,13,16,14,14,13,13,16,14,15,13,13,15,15, + 15,13,13,16,14,14,14,13,16,14,14,13,13,16,14,14, + 13,13,16,15,15,13,13,16,15,15,13,13,16,14,14,14, + 14,16,15,15,12,12,16,14,14,13,13,16,15,15,12,12, + 16,15,15,13,13,16,14,14,14,14,17,15,14,12,12,16, + 14,14,13,13,16,15,15,12,12,14,14,14, 8, 8,14,14, + 14,17,18,14,15,15,17,18,14,14,14,17,18,14,14,14, + 18,18,14,15,15,18,18,14,16,15,19,19,15,15,15,18, + 19,15,16,15,20,19,15,15,15,18,18,14,15,15,18,19, + 15,16,16,20,19,15,15,15,19,17,14,15,15,20,18,14, + 15,15,18,18,14,15,15,18,19,14,15,15,19,20,14,14, + 14,18,18,14,15,15,18,19,14,14,14,18,19,14,15,15, + 19,18,15,16,16,20,21,14,14,15,19,19,14,15,15,19, + 19,14,14,14,19,18,13,12,12, 9, 9,13,14,14,18,19, + 14,14,14,18,19,14,14,14,18,18,14,14,14,18,18,14, + 15,15,19,19,15,14,14,19,18,15,15,15,19,19,15,14, + 14,19,20,14,15,15,18,19,14,15,15,20,18,15,14,14, + 18,18,14,15,15,18,18,14,14,14,19,19,14,15,15,18, + 18,14,15,15,19,18,15,14,14,19,19,14,15,15,19,18, + 15,14,14,19,18,14,14,15,18,19,14,15,15,19,18,15, + 14,14,18,19,14,15,14,19,20,14,14,14,19,19,14,15, + 15,19,19,12,12,12,13,13,16,16,16,11,11,16,16,16, + 12,12,17,16,16,11,11,17,15,15,11,11,16,16,16,13, + 13,17,15,16,13,13,16,16,16,12,12,17,16,16,13,13, + 17,17,16,12,12,17,17,16,13,13,17,16,16,13,13,17, + 17,17,12,12,17,16,16,13,13,17,17,17,12,12,16,16, + 16,12,12,17,15,15,13,13,17,16,16,11,11,17,16,16, + 12,12,16,16,16,11,11,16,17,16,12,12,17,16,16,13, + 13,17,17,16,12,12,17,17,16,12,12,17,16,16,11,11, + 13,14,14, 9, 9,16,14,14,13,13,16,14,15,14,14,16, + 14,14,12,12,16,14,14,13,13,17,15,15,14,14,16,15, + 15,15,15,17,15,15,14,14,16,15,15,14,14,17,15,15, + 14,14,16,15,15,14,14,16,15,15,15,16,17,14,15,14, + 14,16,15,15,14,14,17,15,15,14,14,16,15,15,14,14, + 16,15,15,15,15,17,14,14,13,13,16,15,15,14,14,16, + 14,14,13,13,17,15,15,14,14,16,16,15,15,15,17,14, + 14,13,13,16,15,15,14,14,17,14,14,13,13,13,11,11, + 10,10,16,14,14,12,12,15,13,13,13,12,16,14,14,11, + 11,16,14,14,11,11,16,14,15,13,14,16,14,14,13,13, + 16,15,15,13,13,16,14,14,13,13,16,15,15,13,13,16, + 15,15,13,13,17,14,14,14,14,17,15,15,13,13,16,14, + 15,13,13,16,15,15,13,13,16,15,15,13,13,16,14,14, + 13,13,17,15,15,12,12,16,14,14,12,12,16,15,15,12, + 12,16,15,15,13,13,16,14,14,13,13,17,15,15,12,12, + 17,14,14,12,12,16,15,15,12,12,13,14,14, 8, 8,13, + 14,14,18,18,13,15,15,17,18,14,14,14,18,19,14,14, + 14,19,18,14,15,15,19,18,15,15,16,21,18,15,15,15, + 19,19,14,16,16,19,19,14,15,15,18,19,14,15,15,19, + 20,14,16,16,19,18,15,15,15,18,19,14,15,15,19,18, + 15,15,15,18,18,15,15,15,20,18,15,16,16,20,19,14, + 15,14,18,19,14,15,16,19,20,14,15,15,19,18,15,15, + 15,19,18,15,16,16,20,19,15,14,14,18,18,14,15,15, + 19,19,14,15,15,18,18,13,12,12, 8, 8,13,14,14,19, + 18,14,13,13,20,18,14,14,14,19,18,14,13,13,18,19, + 14,15,15,20,19,15,14,14,19,19,14,15,15,19,18,15, + 14,14,20,20,15,15,15,19,18,14,15,15,19,18,15,14, + 14,19,18,14,15,15,20,19,14,14,14,20,19,14,15,15, + 19,18,15,15,15,18,18,15,14,14,18,18,14,15,15,19, + 19,14,14,14,19,19,14,15,15,19,19,15,15,15,19,18, + 15,14,14,20,19,15,15,15,19,19,14,14,14,20,19,14, + 15,15,20,20,12,12,12,13,13,17,16,16,11,11,16,16, + 15,12,12,17,16,16,11,11,17,15,15,11,11,17,17,17, + 13,13,17,16,16,13,13,17,17,17,12,12,17,16,16,13, + 13,17,17,16,12,13,16,17,16,13,13,17,16,15,13,13, + 17,16,16,12,12,17,16,16,12,13,17,16,17,12,12,17, + 17,17,12,12,17,16,15,13,13,17,16,16,12,12,17,16, + 16,12,12,17,16,16,11,11,16,16,16,12,12,17,15,15, + 13,13,17,16,15,11,11,16,16,16,12,12,17,16,16,11, + 11,13,14,14, 9, 9,16,14,14,13,13,16,14,15,14,14, + 16,14,14,12,12,16,14,14,13,13,17,15,15,14,15,16, + 15,15,15,15,17,15,15,14,14,16,15,15,15,14,16,15, + 15,14,14,16,15,15,14,14,16,15,16,15,15,17,15,14, + 14,14,16,15,15,14,14,17,15,15,13,13,16,15,15,14, + 14,16,16,16,15,15,17,14,14,13,13,16,15,15,14,14, + 18,14,15,13,13,16,15,15,14,14,16,16,15,15,15,16, + 14,14,13,13,16,15,15,14,14,17,14,15,13,13,13,11, + 11,10,10,15,14,14,12,12,15,14,14,13,13,16,14,14, + 12,12,16,13,14,12,12,16,14,15,14,13,16,14,14,14, + 14,16,15,15,13,13,16,14,14,13,13,16,15,15,13,13, + 15,15,15,13,13,16,14,14,14,14,17,15,15,13,13,16, + 14,14,13,13,16,15,15,13,13,16,15,15,13,13,16,14, + 14,13,13,17,15,15,12,12,16,14,14,12,12,16,14,15, + 12,12,16,15,15,13,13,16,14,14,13,13,17,15,15,12, + 12,16,14,14,12,12,16,15,15,12,12,14,14,14, 8, 8, + 14,14,14,17,17,14,15,15,18,18,14,14,14,18,17,14, + 14,14,18,18,14,15,15,18,20,15,16,15,19,18,15,15, + 15,19,18,15,15,16,19,18,15,15,15,18,18,14,15,15, + 18,18,15,16,16,18,19,15,15,15,18,18,15,15,15,19, + 20,15,15,15,18,18,15,15,15,18,18,15,16,16,19,19, + 15,14,15,19,19,15,15,15,19,20,14,14,15,18,18,15, + 15,15,19,19,15,16,16,19,19,15,15,14,18,19,15,15, + 15,20,20,15,15,14,18,18,13,12,12, 8, 8,13,14,14, + 18,18,14,14,14,18,18,14,14,14,18,20,14,14,14,18, + 18,14,15,15,19,18,15,14,14,18,19,15,15,15,18,19, + 15,14,14,18,19,15,15,15,18,18,14,15,14,18,19,15, + 14,14,21,19,15,15,15,19,18,14,14,14,19,18,14,15, + 15,19,18,15,15,15,20,19,15,14,14,20,18,14,15,15, + 18,19,14,14,14,19,18,14,15,15,18,19,15,15,15,18, + 19,15,14,14,19,19,15,15,15,19,19,14,14,14,19,20, + 14,15,15,18,19, +}; + +static const static_codebook _44p0_p3_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p0_p3_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p0_p3_1, + 0 +}; + +static const long _vq_quantlist__44p0_p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p0_p4_0[] = { + 2, 6, 6,14,14, 6, 8, 8,14,14, 7, 7, 7,14,14, 0, + 13,13,15,16, 0,13,13,15,15, 7, 8, 8,15,15, 9,10, + 10,16,16, 9, 8, 8,14,15, 0,13,13,17,17, 0,13,13, + 16,16, 8, 8, 8,15,15,12,11,11,16,16, 9, 8, 8,14, + 14, 0,13,13,17,17, 0,13,13,15,15, 0,14,14,16,16, + 0, 0, 0,18,19, 0,12,12,16,15, 0,16,16, 0,20, 0, + 14,14,16,16, 0,14,14,17,17, 0, 0, 0,19,19, 0,12, + 12,15,15, 0,18,17,21,21, 0,14,14,16,16, 5, 7, 7, + 12,13, 9,10, 9,14,14,11,10,10,14,14, 0, 0, 0,18, + 17, 0,20,21,18,18, 9,10,10,14,14,12,12,12,17,16, + 12,10,10,14,14, 0,20,20,18,17, 0,21,21,17,17,11, + 10,10,14,14,15,13,13,18,18,13,11,11,14,14, 0,20, + 0,18,18, 0,20,21,18,17, 0,21, 0,18,19, 0, 0, 0, + 0,21, 0,21,20,16,17, 0, 0, 0,21,21, 0, 0, 0,20, + 18, 0,20, 0,17,18, 0, 0, 0, 0, 0, 0, 0,20,16,17, + 0, 0, 0,20, 0, 0, 0, 0,18,18, 6, 6, 6,13,13, 8, + 5, 5,11,11, 9, 6, 6,13,13, 0, 9, 9,12,12, 0,10, + 10,14,14, 9, 7, 7,13,13,12, 9, 9,13,13,10, 6, 6, + 13,13, 0,10,10,14,14, 0,10,10,13,13, 9, 7, 7,13, + 13,13,10,10,13,13,11, 6, 6,13,13, 0,10,10,15,15, + 0,10,10,13,13, 0,12,11,15,15, 0,20,19,17,16, 0, + 9, 9,13,13, 0,13,13,20,19, 0,11,11,13,13, 0,11, + 11,15,15, 0,20,19,17,17, 0,10,10,13,13, 0,14,15, + 0,21, 0,12,12,13,13, 0,10,10,12,12, 0,11,11,15, + 15, 0,11,11,15,15, 0,15,15,20,20, 0,16,16, 0, 0, + 0,11,11,15,15, 0,14,14,17,17, 0,11,11,15,15, 0, + 15,15,20,21, 0,16,16,21,21, 0,12,12,15,15, 0,15, + 15,18,20, 0,11,11,16,15, 0,15,15,21,21, 0,16,16, + 0,21, 0,16,16, 0, 0, 0, 0, 0, 0, 0, 0,14,14,21, + 21, 0,17,18, 0, 0, 0,16,17,20, 0, 0,16,16, 0, 0, + 0, 0, 0, 0, 0, 0,15,15,20,20, 0,19,18, 0,21, 0, + 18,17, 0, 0, 0,10,10,11,11, 0,10,10,10,10, 0,11, + 11,12,12, 0,11,11, 9, 9, 0,13,13,12,12, 0,11,11, + 12,12, 0,13,13,12,12, 0,10,10,12,12, 0,12,12,13, + 13, 0,12,12,12,12, 0,11,11,12,12, 0,13,13,12,12, + 0,10,10,12,12, 0,13,13,13,13, 0,12,12,12,12, 0, + 14,13,13,13, 0,19,21,15,15, 0,12,11,12,12, 0,16, + 15,19,19, 0,13,13,11,11, 0,13,13,13,13, 0, 0,21, + 15,16, 0,12,12,12,12, 0,16,16,19,21, 0,13,13,12, + 12, 7, 7, 7,16,16,11, 9, 9,16,16,12, 9, 9,16,16, + 0,13,13,16,16, 0,14,14,17,16,11, 9, 9,16,16,14, + 12,11,17,17,13, 8, 9,15,15, 0,13,13,19,19, 0,13, + 13,16,15,12,10,10,17,17,15,12,12,19,18,14, 9, 9, + 17,16, 0,14,14,18, 0, 0,14,13,16,16, 0,14,15,18, + 17, 0,21, 0,19,21, 0,12,12,16,16, 0,16,16, 0, 0, + 0,14,14,16,16, 0,14,14,18,18, 0, 0,21,20, 0, 0, + 13,13,16,17, 0,18,18, 0, 0, 0,15,14,17,16, 8, 7, + 7,14,14,11,10,10,15,15,13,10,10,15,15, 0,21,20, + 19,19, 0,21, 0,17,18,11,10,10,15,16,14,12,12,18, + 18,14,11,11,15,14, 0,21,20,18,19, 0, 0,21,18,18, + 12,11,11,16,16,16,14,14,18,20,14,11,11,16,15, 0, + 20,20,19,19, 0, 0,20,18,18, 0,21, 0,18,19, 0, 0, + 0, 0, 0, 0,20,20,17,18, 0, 0, 0,20,20, 0, 0, 0, + 19,19, 0, 0, 0,20,18, 0, 0, 0, 0, 0, 0, 0,21,18, + 18, 0,21,21, 0,21, 0, 0, 0,19,20,11, 9, 9,14,14, + 13,10,10,14,14,13,11,11,15,15, 0,13,13,13,13, 0, + 14,14,16,16,13,11,11,15,15,16,12,12,15,15,14,10, + 10,14,14, 0,14,14,16,16, 0,14,14,15,15,13,10,10, + 15,15,17,13,14,15,16,15,10,10,15,15, 0,14,14,17, + 16, 0,14,14,15,15, 0,15,15,17,17, 0, 0,21,18,18, + 0,13,13,15,15, 0,16,16,21,20, 0,14,14,15,14, 0, + 15,14,16,17, 0, 0,20,20,19, 0,13,13,15,15, 0,19, + 18, 0, 0, 0,15,15,15,15, 0,11,11,14,14, 0,12,12, + 16,16, 0,12,12,16,16, 0,15,16,21,21, 0,16,17,21, + 0, 0,12,12,17,16, 0,14,14,18,19, 0,11,11,16,16, + 0,15,15,20,21, 0,16,16,21, 0, 0,12,12,17,16, 0, + 15,15,19,19, 0,12,12,16,17, 0,16,15, 0, 0, 0,16, + 16, 0, 0, 0,17,17, 0,21, 0, 0, 0, 0, 0, 0,14,15, + 20, 0, 0,17,17, 0, 0, 0,17,17, 0, 0, 0,17,16, 0, + 0, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0,18,18, 0, 0, + 0,18,17, 0, 0, 0,11,11,14,14, 0,12,12,15,15, 0, + 12,12,15,15, 0,13,13,14,14, 0,14,14,17,17, 0,12, + 12,16,16, 0,14,14,16,16, 0,11,11,15,15, 0,13,13, + 16,17, 0,13,13,16,16, 0,12,12,15,15, 0,14,14,17, + 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,16,16, + 0,15,15,17,18, 0,21,20,20,21, 0,12,12,15,15, 0, + 16,16,20,21, 0,14,14,15,15, 0,14,14,17,17, 0, 0, + 0,18,19, 0,12,13,15,15, 0,18,17,21, 0, 0,14,15, + 15,15, 8, 8, 8,16,16,12,10,10,16,16,13, 9, 9,16, + 16, 0,14,14,18,17, 0,14,14,16,17,12,10,10,18,17, + 14,12,11,18,18,14, 9, 9,16,16, 0,13,13,18,18, 0, + 13,13,17,16,12, 9, 9,16,17,17,13,13,17,17,14, 9, + 9,15,15, 0,14,14,20,19, 0,13,13,16,16, 0,15,15, + 19,18, 0, 0, 0,20,19, 0,12,13,17,17, 0,16,16,20, + 0, 0,14,14,16,17, 0,14,14,19,18, 0, 0, 0,20,20, + 0,13,13,16,16, 0,18,17, 0, 0, 0,15,15,16,16, 9, + 7, 7,14,14,12,10,10,15,15,13,10,10,15,15, 0,21, + 0,18,19, 0,20,21,19,18,12,10,10,16,15,15,13,13, + 18,18,14,11,11,15,15, 0, 0, 0,19,18, 0, 0,21,18, + 18,13,11,11,15,15,16,14,14,17,19,15,11,11,15,15, + 0,21,21,20,18, 0, 0,21,18,18, 0, 0,21,21,19, 0, + 0, 0, 0, 0, 0,19,20,18,17, 0, 0, 0,21,21, 0,21, + 0,20,18, 0, 0,21,19,19, 0, 0, 0, 0, 0, 0,20,21, + 17,17, 0, 0, 0, 0, 0, 0,21, 0,18,20, 0,10,10,14, + 14, 0,11,11,15,15, 0,11,11,15,15, 0,14,14,15,15, + 0,15,15,16,16, 0,11,12,16,16, 0,13,13,16,16, 0, + 11,11,15,15, 0,14,14,17,17, 0,14,14,15,15, 0,11, + 11,16,15, 0,14,14,15,15, 0,11,11,15,15, 0,15,15, + 17,17, 0,14,14,15,15, 0,16,16,18,18, 0, 0, 0,20, + 19, 0,14,13,16,15, 0,17,17,21, 0, 0,15,15,15,15, + 0,16,15,17,16, 0,20, 0,20,18, 0,13,14,15,15, 0, + 19,18, 0,21, 0,15,15,15,15, 0,11,11,14,14, 0,12, + 12,16,16, 0,12,12,16,16, 0,16,15,20,21, 0,17,16, + 0, 0, 0,12,12,16,16, 0,14,14,18,18, 0,11,11,16, + 16, 0,15,15,21,20, 0,16,16, 0, 0, 0,12,12,16,17, + 0,15,14,19,19, 0,11,12,16,16, 0,15,15,21, 0, 0, + 16,16, 0, 0, 0,16,17, 0, 0, 0, 0, 0, 0, 0, 0,15, + 15,21, 0, 0,17,17, 0, 0, 0,17,17, 0, 0, 0,17,16, + 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0,20, 0,19,20, 0, + 0, 0,17,17, 0, 0, 0,12,12,15,15, 0,12,12,15,15, + 0,12,12,16,16, 0,13,13,15,15, 0,15,15,17,17, 0, + 13,13,17,16, 0,14,14,17,17, 0,11,11,16,16, 0,14, + 14,17,17, 0,13,13,16,16, 0,12,12,16,16, 0,15,15, + 16,17, 0,11,11,15,16, 0,14,14,17,17, 0,13,14,16, + 16, 0,15,15,18,18, 0,21,20,20,19, 0,13,13,16,17, + 0,16,16, 0, 0, 0,14,14,16,16, 0,15,15,18,18, 0, + 0, 0,20,19, 0,13,13,16,16, 0,17,17, 0, 0, 0,14, + 14,16,16, 0,11,11,16,16, 0,13,13,18,17, 0,13,13, + 17,17, 0,16,16,17,17, 0,16,16,17,18, 0,12,12,17, + 17, 0,15,15,18,18, 0,12,12,16,16, 0,16,16,19,19, + 0,15,15,16,17, 0,12,12,17,17, 0,17,17,18,18, 0, + 12,12,17,17, 0,16,16,19,19, 0,15,16,17,17, 0,16, + 16,18,17, 0, 0, 0,21,21, 0,13,13,16,16, 0,17,17, + 0,20, 0,15,15,16,17, 0,16,16,19,18, 0, 0,21,20, + 21, 0,14,14,17,16, 0,20, 0, 0, 0, 0,15,16,16,17, + 0, 9, 9,14,14, 0,13,13,16,16, 0,14,14,15,15, 0, + 0,20,19,19, 0, 0, 0,19,19, 0,12,12,15,15, 0,15, + 16,19,18, 0,14,14,15,15, 0,21, 0,18,18, 0,20, 0, + 17,18, 0,13,13,16,16, 0,17,17,17,19, 0,14,14,16, + 15, 0,21,20,20,19, 0, 0, 0,19,19, 0, 0, 0,19,18, + 0, 0, 0, 0, 0, 0,20,20,17,18, 0, 0, 0,21,21, 0, + 0, 0,18,18, 0,21, 0,18,19, 0, 0, 0, 0, 0, 0,20, + 21,18,18, 0, 0, 0,20,21, 0, 0, 0,19,19, 0,18,18, + 15,15, 0,20,21,17,17, 0,19,21,17,17, 0, 0, 0,17, + 18, 0, 0, 0,20,19, 0,19,19,17,17, 0, 0, 0,18,18, + 0,19,20,16,17, 0, 0,21,20,20, 0,19,20,19,18, 0, + 19,20,16,16, 0, 0, 0,18,19, 0,19,20,17,17, 0, 0, + 21, 0,20, 0,21,21,17,19, 0,20, 0,19,20, 0, 0, 0, + 20, 0, 0,19,18,17,16, 0, 0, 0, 0, 0, 0, 0,20,17, + 17, 0,20,21,18,20, 0, 0, 0, 0,21, 0,19,20,17,17, + 0, 0, 0, 0, 0, 0,20,21,17,17, 0,11,11,14,14, 0, + 13,13,16,17, 0,13,13,16,16, 0,17,17, 0,21, 0,18, + 17,21, 0, 0,13,13,16,16, 0,15,15,18,18, 0,12,12, + 16,16, 0,17,16,21, 0, 0,17,17, 0, 0, 0,12,12,17, + 17, 0,17,17,19,21, 0,13,12,16,16, 0,17,17, 0, 0, + 0,17,17, 0, 0, 0,18,17, 0,21, 0, 0, 0, 0, 0, 0, + 15,15,20, 0, 0,20,18, 0, 0, 0,17,18, 0, 0, 0,16, + 17, 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0,19,19, + 0, 0, 0,18,18, 0, 0, 0,14,14,18,18, 0,16,16, 0, + 21, 0,16,16,21,21, 0,17,17, 0,20, 0,17,17,20, 0, + 0,16,15, 0, 0, 0,20,20, 0, 0, 0,15,15,20,20, 0, + 17,17,21, 0, 0,17,18,20,20, 0,15,15,20,20, 0,18, + 18, 0, 0, 0,15,15,19,20, 0,17,18, 0, 0, 0,17,17, + 20,20, 0,18,17,21, 0, 0, 0, 0, 0,21, 0,15,15,20, + 20, 0,19,19, 0, 0, 0,17,17,21, 0, 0,17,17, 0, 0, + 0, 0, 0,21, 0, 0,15,15,19,19, 0,20,21, 0, 0, 0, + 18,17,21,21, 0,12,12,16,16, 0,14,14,17,17, 0,13, + 13,17,18, 0,16,16,18,17, 0,16,16,18,18, 0,13,13, + 18,18, 0,15,16,19,18, 0,13,13,16,16, 0,16,16,20, + 18, 0,16,16,17,17, 0,12,13,17,17, 0,17,16,18,18, + 0,12,12,16,16, 0,17,16,20,19, 0,16,16,16,16, 0, + 16,17,18,20, 0, 0, 0,21,20, 0,14,14,17,16, 0,19, + 18, 0,20, 0,16,16,17,16, 0,16,16,17,18, 0, 0,21, + 21,21, 0,14,14,16,16, 0,20,20,21, 0, 0,16,16,16, + 16, 0,10,10,14,14, 0,14,14,15,16, 0,14,14,15,15, + 0, 0,21,18,18, 0, 0,21,18,19, 0,13,13,16,16, 0, + 16,16,18,18, 0,14,14,15,15, 0,21, 0,18,18, 0,21, + 0,18,18, 0,13,13,16,16, 0,17,17,19,20, 0,14,14, + 15,15, 0, 0, 0,18,20, 0, 0,21,18,18, 0, 0,21,19, + 18, 0, 0, 0, 0, 0, 0,20,21,18,17, 0, 0, 0,21,21, + 0, 0, 0,19,19, 0,21, 0,18,19, 0, 0, 0, 0, 0, 0, + 21,20,17,17, 0, 0,21,20, 0, 0, 0, 0,19,19, 0,19, + 20,15,16, 0, 0,20,18,17, 0,20,21,17,18, 0,21, 0, + 18,18, 0, 0, 0,19,19, 0,20,20,17,18, 0, 0, 0,18, + 19, 0,20,20,18,17, 0, 0, 0, 0,20, 0, 0,21,17,18, + 0,20,21,17,17, 0, 0, 0,18,18, 0,19,19,17,17, 0, + 0, 0,21,21, 0,20,20,17,17, 0, 0, 0,21,19, 0, 0, + 0,20,19, 0,21,20,17,18, 0, 0, 0, 0, 0, 0, 0,20, + 18,17, 0,21,20,18,18, 0, 0, 0,20,21, 0,20,20,17, + 17, 0, 0, 0, 0, 0, 0,20, 0,17,17, 0,11,11,13,14, + 0,13,13,16,16, 0,13,13,16,16, 0,17,17, 0, 0, 0, + 17,18, 0, 0, 0,13,13,16,16, 0,15,16,18,18, 0,13, + 13,16,17, 0,16,17,20, 0, 0,17,18,20, 0, 0,13,13, + 17,17, 0,16,16,20,21, 0,13,13,16,16, 0,17,17,21, + 0, 0,17,18, 0, 0, 0,17,18, 0,21, 0, 0, 0, 0, 0, + 0,15,15,20, 0, 0,19,19, 0, 0, 0,17,17, 0, 0, 0, + 18,17,21,20, 0, 0, 0, 0, 0, 0,16,16,20,21, 0,21, + 20, 0,21, 0,19,21, 0, 0, 0,15,15, 0, 0, 0,16,17, + 0,19, 0,16,16, 0, 0, 0,17,17, 0, 0, 0,19,18, 0, + 0, 0,16,16,20,20, 0,20,18,21, 0, 0,15,15,21,21, + 0,18,18, 0, 0, 0,18,19, 0, 0, 0,16,15, 0,21, 0, + 20,19, 0, 0, 0,16,16, 0, 0, 0,20,18, 0,21, 0,17, + 18,21, 0, 0,18,19, 0, 0, 0, 0, 0, 0, 0, 0,16,16, + 20,20, 0,19,20, 0, 0, 0,17,17, 0, 0, 0,18,17,20, + 21, 0, 0, 0, 0, 0, 0,16,16, 0,20, 0,20,22, 0, 0, + 0,18,18, 0,22, +}; + +static const static_codebook _44p0_p4_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p0_p4_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p0_p4_0, + 0 +}; + +static const long _vq_quantlist__44p0_p4_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p0_p4_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p0_p4_1 = { + 1, 7, + (char *)_vq_lengthlist__44p0_p4_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p0_p4_1, + 0 +}; + +static const long _vq_quantlist__44p0_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_p5_0[] = { + 1, 6, 6, 6, 8, 8, 7, 8, 8, 7, 9, 8,10,11,11, 9, + 8, 8, 7, 8, 8,11,11,11, 9, 8, 8, 6, 7, 7,10,10, + 10,10,10,10,10,10,10,14,13,13,12,11,11,10,10,10, + 14,14,13,13,11,11, 6, 6, 6, 8, 5, 5, 8, 7, 7, 8, + 7, 7,11, 9, 9, 9, 7, 7, 8, 7, 7,12,10,10,10, 7, + 7, 7, 8, 8,12,11,11,12,10,10,11,10,10,14,13,13, + 13,10,10,11,10,11,16,14,14,13,10,10, 7, 8, 7,12, + 12,12,12,11,11,12,11,11,16,14,15,13,12,12,11,11, + 11,17,15,14,14,13,13,10, 9, 9,13,11,11,13,11,11, + 12,11,11,16,14,13,14,11,11,12,11,11,16,15,14,14, + 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,16,14, + 13,13,11,11,12,10,10,16,14,14,13,10,10, 8, 8, 8, + 12,12,12,12,11,11,12,11,11,16,14,15,14,12,12,12, + 11,11,16,15,15,14,12,12,10,10,10,13,11,11,13,11, + 11,12,12,12,16,14,14,14,11,11,12,11,11,17,14,15, + 14,11,11, +}; + +static const static_codebook _44p0_p5_0 = { + 5, 243, + (char *)_vq_lengthlist__44p0_p5_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p0_p5_0, + 0 +}; + +static const long _vq_quantlist__44p0_p5_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_p5_1[] = { + 2, 7, 7, 7, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 9, 8, + 7, 7, 8, 8, 8, 9, 9, 9, 9, 7, 7, 6, 6, 6, 9, 7, + 7, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8, + 10, 8, 8,10, 8, 8, 7, 6, 6, 9, 6, 6, 9, 6, 6, 9, + 7, 7,10, 8, 8, 9, 6, 6, 9, 7, 7,10, 8, 8, 9, 7, + 7, 7, 8, 8,11, 9, 9,11, 9, 9,11, 9, 9,12, 9, 9, + 12, 8, 8,12, 9, 9,12,10, 9,12, 8, 8, 8, 7, 7,10, + 9, 9,11, 9, 9,11, 9, 9,11,11,10,11, 9, 9,11,10, + 9,11,10,11,11, 9, 9,10, 8, 8,11, 9, 9,11, 9, 9, + 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11, + 9, 9, 9, 8, 8,12, 9, 9,12, 9, 9,11, 9, 9,12, 9, + 9,12, 8, 8,12, 9, 9,12, 9, 9,12, 8, 8, 9, 7, 7, + 11, 9,10,11,10, 9,11, 9, 9,11,11,11,11, 9, 9,11, + 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11,10, + 10,11,10, 9,11,10,10,11, 9, 9,11,10,10,11,10,11, + 11, 9, 9, +}; + +static const static_codebook _44p0_p5_1 = { + 5, 243, + (char *)_vq_lengthlist__44p0_p5_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p0_p5_1, + 0 +}; + +static const long _vq_quantlist__44p0_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p0_p6_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 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, 8, 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, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, +}; + +static const static_codebook _44p0_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p0_p6_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p0_p6_0, + 0 +}; + +static const long _vq_quantlist__44p0_p6_1[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p0_p6_1[] = { + 1, 3, 2, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11, + 11,12,12,12,14,14,14,15,15, +}; + +static const static_codebook _44p0_p6_1 = { + 1, 25, + (char *)_vq_lengthlist__44p0_p6_1, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p0_p6_1, + 0 +}; + +static const long _vq_quantlist__44p0_p6_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p0_p6_2[] = { + 3, 4, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44p0_p6_2 = { + 1, 25, + (char *)_vq_lengthlist__44p0_p6_2, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p0_p6_2, + 0 +}; + +static const char _huff_lengthlist__44p0_short[] = { + 3, 3, 7, 8,10,13,16, 3, 2, 5, 7, 9,13,16, 6, 4, + 4, 6,10,14,15, 7, 5, 5, 7,10,13,14, 9, 8, 9, 9, + 9,11,13,12,11,12, 9, 7, 8,11,14,12,10, 6, 5, 7, + 10, +}; + +static const static_codebook _huff_book__44p0_short = { + 2, 49, + (char *)_huff_lengthlist__44p0_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p1_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p1_l0_0[] = { + 1, 4, 4, 7, 7, 8, 8, 9, 9,10,10,11,11, 4, 6, 5, + 8, 6, 9, 8,10, 9,10,10,11,10, 5, 5, 6, 6, 8, 8, + 9, 9,10,10,10,10,11, 7, 8, 8, 9, 8,10, 9,10, 9, + 11,10,11,10, 7, 8, 8, 8,10, 9,10,10,10,10,11,10, + 11, 9,10,10,11,11,11,11,12,11,12,11,12,11, 9,10, + 10,11,11,11,11,11,11,11,12,11,12,11,11,11,12,12, + 12,12,12,12,12,12,12,11,11,12,11,12,12,12,12,12, + 12,12,12,11,12,12,12,12,12,13,12,13,12,12,12,12, + 12,12,12,12,12,13,13,13,13,12,13,12,12,12,12,12, + 13,13,12,13,12,13,12,13,12,12,12,12,13,13,13,13, + 13,13,12,12,12,12,12,11,12, +}; + +static const static_codebook _44p1_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p1_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p1_l0_0, + 0 +}; + +static const long _vq_quantlist__44p1_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p1_l0_1[] = { + 1, 4, 4, 6, 6, 5, 5, 5, 6, 6, 5, 6, 5, 6, 6, 6, + 6, 7, 7, 7, 6, 7, 6, 7, 7, +}; + +static const static_codebook _44p1_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p1_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p1_l0_1, + 0 +}; + +static const long _vq_quantlist__44p1_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_l1_0[] = { + 1, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const static_codebook _44p1_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44p1_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p1_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p1_lfe[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book__44p1_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p1_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p1_long[] = { + 3, 3, 7, 7, 9,13,16, 3, 2, 4, 6,10,13,17, 7, 4, + 4, 6, 9,12,14, 7, 6, 6, 5, 7, 9,12,10,10, 9, 6, + 6, 9,12,14,14,13, 9, 8,10,11,18,18,15,13,11,10, + 11, +}; + +static const static_codebook _huff_book__44p1_long = { + 2, 49, + (char *)_huff_lengthlist__44p1_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p1_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_p1_0[] = { + 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p1_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p1_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p1_p1_0, + 0 +}; + +static const long _vq_quantlist__44p1_p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_p2_0[] = { + 1, 4, 4, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0,12,12, 0, + 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 0, 6, 6, 0,11, + 11, 0,11,11, 0,12,12, 0,14,14, 0,11,11, 0,12,12, + 0,14,14, 0,11,11, 0, 6, 6, 0, 6, 5, 0, 7, 6, 0, + 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,10,10, 0, 7, + 7, 0, 7, 7, 0,10,10, 0,11,11, 0,11,11, 0,14,14, + 0,10,10, 0,12,12, 0,14,14, 0,12,12, 0, 6, 6, 0, + 11,11, 0,11,11, 0,12,12, 0,14,14, 0,11,11, 0,12, + 12, 0,15,15, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 8, 0,11,11, 0,11,11, 0,12,12, 0,15, + 15, 0,12,12, 0,11,11, 0,15,15, 0,11,11, 0, 6, 6, + 0,11,11, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0, + 12,12, 0,14,14, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p1_p2_0 = { + 5, 243, + (char *)_vq_lengthlist__44p1_p2_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p1_p2_0, + 0 +}; + +static const long _vq_quantlist__44p1_p2_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_p2_1[] = { + 1, 3, 3, 0, 8, 8, 0, 8, 8, 0,10,10, 0, 9, 9, 0, + 10,10, 0,10,10, 0, 9, 9, 0,10,10, 0, 7, 7, 0, 7, + 7, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 9, 9, + 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, + 10,10, 0, 9, 9, 0, 9, 9, 0,10,10, 0, 9, 9, 0,10, + 10, 0, 8, 8, 0,11,11, 0,11,11, 0,12,12, 0,11,11, + 0,12,12, 0,12,12, 0,12,12, 0,12,12, 0, 8, 8, 0, + 11,11, 0,11,11, 0,13,12, 0,12,12, 0,13,12, 0,13, + 13, 0,12,12, 0,13,13, 0, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 8, 0,11,11, 0,11,11, 0,13,12, 0,12, + 12, 0,12,12, 0,12,12, 0,11,11, 0,12,12, 0, 8, 8, + 0,12,12, 0,12,12, 0,13,13, 0,12,12, 0,13,13, 0, + 13,13, 0,12,13, 0,13,13, 0, 7, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p1_p2_1 = { + 5, 243, + (char *)_vq_lengthlist__44p1_p2_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p1_p2_1, + 0 +}; + +static const long _vq_quantlist__44p1_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_p3_0[] = { + 1, 6, 6, 6, 7, 7, 7, 8, 8, 7, 8, 8,10,11,11, 9, + 8, 8, 7, 9, 9,11,12,12, 9, 8, 8, 6, 7, 7, 9,11, + 11,10,11,11,10,11,11,13,13,13,11,12,12,10,11,11, + 13,14,14,12,12,12, 6, 6, 6, 8, 6, 6, 8, 6, 6, 9, + 7, 7,12,10,10,10, 6, 6, 9, 7, 7,12,10,10,11, 7, + 6, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13, + 13,10,10,12,11,11,15,13,13,14,11,11, 8, 7, 7,12, + 11,11,12,11,11,11,11,11,14,14,14,13,12,12,12,11, + 11,16,15,15,14,12,12, 0,10,10, 0,11,11, 0,12,12, + 0,11,11, 0,14,14, 0,11,11, 0,11,11, 0,15,15, 0, + 11,11, 7, 8, 8,13,10,10,12,10,10,12,11,11,15,13, + 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7, + 12,11,11,13,11,11,12,11,11,15,14,14,14,12,12,13, + 12,12,15,14,14,15,12,12, 0,11,11, 0,12,12, 0,12, + 12, 0,12,12, 0,15,15, 0,12,12, 0,12,12, 0,15,14, + 0,12,12, +}; + +static const static_codebook _44p1_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p1_p3_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p1_p3_0, + 0 +}; + +static const long _vq_quantlist__44p1_p3_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p1_p3_1[] = { + 2, 3, 4, 7, 7,10,12,12,12,12,10,11,11,13,13,11, + 12,12,11,11,12,12,12,12,12,11,13,13,13,13,12,12, + 12,13,14,12,13,13,13,13,12,13,13,13,13,12,13,13, + 13,13,11,13,13,13,13,12,12,12,14,14,12,13,13,12, + 12,12,12,13,13,13,12,13,13,13,13,12,13,13,13,13, + 12,12,12,14,14,12,13,13,12,12,12,13,13,13,13,12, + 13,13,12,12,12,13,13,13,13,12,12,12,14,14,12,13, + 13,12,12,12,13,13,13,13,12,13,13,12,12,10,10,11, + 10,10,11,11,11,11,11,11, 9, 9,10,10,12,11,11,10, + 10,12,10,10,10,10,13,12,12,12,12,13,11,11,11,11, + 13,12,12,12,12,13,11,11,11,11,13,12,12,12,12,13, + 12,12,12,12,13,11,11,11,11,13,12,12,12,12,13,11, + 11,11,11,13,12,12,11,11,13,12,12,11,11,13,11,11, + 11,11,13,12,12,11,11,13,11,11,11,11,13,12,12,11, + 11,13,12,12,11,11,13,11,11,11,11,13,12,12,11,11, + 13,11,11,11,11,13,12,12,11,11,11,11,11,10,10,11, + 11,11, 9, 9,11,12,12,11,11,12,12,12, 9, 9,13,13, + 13,10,10,13,13,13,11,11,13,13,13,14,14,13,13,13, + 11,10,13,13,14,12,12,13,13,13,11,11,13,13,13,11, + 11,13,13,13,14,14,13,13,13,10,10,13,13,13,11,11, + 13,13,13,10,10,13,14,13,11,11,13,14,14,14,14,13, + 13,13,10,10,13,14,14,11,11,13,13,13,10,10,13,14, + 14,11,11,13,13,13,14,14,14,13,13,10,10,13,14,14, + 11,11,13,13,13,10,10,14,12,12, 9, 9,14,12,12, 9, + 9,14,11,11, 9, 9,14,12,12, 8, 8,14,11,11, 7, 7, + 15,13,13,10,10,15,12,12,10,10,15,13,13,10,10,15, + 12,12,10,10,15,13,13,10,10,15,13,13,10,10,15,12, + 12,10,10,15,13,13,10,10,15,12,12,10,10,15,13,13, + 10,10,15,13,13,10,10,15,12,12,10,10,15,13,13, 9, + 9,15,12,12, 9, 9,14,13,13, 9, 9,15,13,13,10,10, + 15,12,12,10,10,15,13,13, 9, 9,15,12,12, 9, 9,15, + 13,13, 9, 9,13,12,12, 9, 9,13,13,13, 8, 8,13,13, + 13, 9, 9,13,13,13, 7, 7,14,13,13, 8, 8,14,14,14, + 10,10,15,14,14,11,11,14,14,14, 9, 9,15,14,14,10, + 10,15,14,14, 9, 9,14,14,14,10,10,15,14,14,11,11, + 15,14,14, 9, 9,14,14,14,10,10,14,14,14, 9, 9,15, + 14,15,10,10,15,14,14,11,11,14,14,14, 9, 9,14,14, + 14, 9, 9,14,14,14, 8, 8,15,14,14,10,10,15,14,14, + 11,11,14,14,14, 9, 9,15,14,14, 9, 9,14,14,14, 8, + 8,12,12,12,13,13,16,16,16,11,11,17,16,16,12,12, + 17,16,16,11,11,17,16,16,11,11,17,17,16,13,13,17, + 16,16,13,13,18,17,16,12,12,17,16,16,13,13,17,16, + 17,12,12,18,17,17,13,13,17,16,16,14,14,18,17,17, + 12,12,18,16,16,13,13,17,17,17,13,12,17,17,17,13, + 13,17,16,16,13,13,18,17,17,12,12,17,16,16,13,12, + 17,17,17,12,12,18,17,17,13,13,18,16,16,14,14,18, + 17,17,12,12,17,17,17,13,13,18,17,18,12,12,13,14, + 14,10,10,16,14,14,13,13,17,15,15,14,14,17,14,14, + 12,13,16,14,14,13,13,17,15,15,14,14,16,16,16,15, + 15,17,15,15,14,14,17,16,16,14,15,17,15,15,14,14, + 17,15,16,14,14,17,16,16,15,15,17,15,15,13,13,17, + 15,15,14,14,18,15,15,13,14,17,15,15,14,14,16,16, + 16,15,15,17,15,15,13,13,17,15,15,14,14,17,15,15, + 13,13,17,15,15,14,14,16,16,16,15,15,17,15,15,13, + 13,17,15,15,14,14,18,15,15,13,13,13,11,11,10,10, + 16,14,14,13,12,16,14,14,13,13,16,15,14,12,12,16, + 14,14,12,12,16,15,15,14,14,16,14,14,14,14,17,15, + 15,13,13,16,15,15,14,14,17,15,15,13,14,17,15,15, + 14,14,17,15,14,14,14,17,15,15,13,13,17,15,15,14, + 14,17,15,15,13,13,17,15,15,14,14,17,14,14,14,14, + 17,15,15,13,13,17,15,15,13,13,17,15,15,13,13,17, + 15,15,14,14,17,15,15,14,14,17,15,15,13,13,17,15, + 15,13,13,17,15,15,13,13,14,14,15, 8, 8,14,14,14, + 19,19,14,15,15,18,19,14,14,14,19,18,14,14,14,19, + 19,15,15,15,19,18,15,16,16,19,19,15,15,15,19,19, + 15,16,16,20,19,15,15,15,19,19,15,15,15,19,19,16, + 16,16,20,19,15,15,15,19,18,15,16,16,20,19,15,15, + 15,18,18,15,15,15,19,20,15,16,16,19,19,15,15,15, + 20,19,15,15,15,20,19,15,15,15,19,18,15,15,15,19, + 19,15,16,16,19,20,15,15,15,19,19,15,15,15,19,20, + 15,15,15,19,19,14,12,12, 9, 9,14,14,14,19,19,14, + 14,14,19,19,14,14,15,20,19,15,14,14,18,19,15,15, + 15,19,19,15,15,14,20,19,15,15,15,20,19,15,15,14, + 20,19,15,15,15,20,19,15,15,15,19,20,15,14,14,19, + 20,15,15,15,20,20,15,14,14,20,19,15,15,15,19,19, + 15,15,15,19,19,15,14,14,19,19,15,15,15,19,20,15, + 15,15,20,20,15,15,15,19,19,15,15,15,20,19,16,14, + 14,19,19,15,15,15,20,19,15,14,15,20,19,14,15,15, + 20,19,12,12,12,13,13,16,16,16,11,11,16,16,16,12, + 12,17,16,16,11,11,17,15,16,11,11,17,17,17,13,13, + 18,16,17,13,13,18,17,17,13,12,17,16,17,13,13,17, + 17,17,13,13,16,16,16,12,12,17,16,16,13,13,17,16, + 16,12,12,17,16,16,12,13,17,17,17,12,12,17,17,17, + 13,13,18,16,16,13,13,18,17,17,12,12,18,17,17,12, + 12,17,17,17,12,12,17,17,17,12,12,17,16,16,13,13, + 17,17,17,12,12,17,16,16,12,12,17,17,17,12,12,13, + 14,14, 9, 9,16,14,14,13,13,16,15,15,14,14,17,14, + 14,13,13,16,14,14,13,13,17,15,15,15,15,16,16,16, + 15,15,17,15,15,14,14,17,15,15,15,15,17,15,15,14, + 14,17,15,15,14,14,16,16,16,15,15,17,15,15,14,14, + 17,15,15,14,14,17,15,15,14,14,17,15,15,14,14,16, + 16,16,15,15,18,15,15,14,13,17,15,15,14,14,17,15, + 15,13,13,17,15,15,14,14,16,16,16,15,15,17,15,15, + 14,13,17,15,15,14,14,17,15,15,13,13,13,11,11,11, + 11,16,14,14,12,12,16,14,14,13,13,16,15,14,12,12, + 17,14,14,12,12,17,15,15,13,13,17,14,14,14,14,17, + 15,15,13,13,17,14,15,14,13,17,15,15,13,13,16,15, + 15,13,13,16,14,14,14,14,17,15,15,13,13,16,14,14, + 13,13,16,15,15,13,13,17,15,15,13,13,17,14,14,14, + 14,17,15,15,12,12,17,15,15,13,13,17,15,15,12,12, + 16,15,15,13,13,17,14,14,13,14,17,15,15,12,12,17, + 14,14,13,13,17,15,15,12,12,14,14,14, 8, 8,14,14, + 14,18,18,14,15,15,19,19,14,14,14,19,19,14,15,14, + 18,19,15,15,15,18,19,15,16,16,20,20,15,15,15,19, + 20,15,16,16,19,20,15,15,15,19,20,15,15,16,19,19, + 15,16,16,20,20,15,15,15,20,19,15,16,16,20,19,15, + 15,15,19,20,15,15,15,19,19,15,16,16,20,19,15,15, + 15,19,19,15,16,15,20,19,15,15,15,19,19,15,15,15, + 19,20,15,16,16,20,20,15,15,15,19,19,15,15,15,20, + 20,15,15,15,19,19,14,12,12, 9, 9,14,14,14,18,18, + 14,14,14,19,20,14,14,14,18,18,14,14,14,18,19,15, + 15,15,19,20,15,14,14,19,19,15,15,15,19,19,15,14, + 15,19,19,15,15,15,18,20,15,15,15,19,19,15,14,14, + 19,19,15,15,15,20,19,15,15,14,20,20,15,15,15,19, + 19,15,15,15,19,19,15,14,14,19,19,15,15,15,19,19, + 15,14,14,19,20,14,15,15,19,19,15,15,15,19,19,15, + 14,14,20,19,15,15,15,19,19,15,14,14,20,19,15,15, + 15,19,19,13,12,12,13,13,17,17,16,11,11,16,16,16, + 12,12,17,17,16,11,11,17,16,16,11,11,17,17,17,13, + 13,17,16,16,13,13,18,17,17,12,12,17,16,16,13,13, + 18,17,17,12,12,18,17,17,13,13,18,16,17,13,13,17, + 17,17,12,12,18,17,17,13,13,18,17,17,12,12,17,16, + 17,12,12,17,16,16,13,13,17,16,16,11,11,17,16,16, + 12,12,17,17,17,11,11,17,17,17,12,12,18,16,16,13, + 13,18,17,17,12,11,17,16,16,12,12,18,17,17,11,11, + 13,14,14, 9, 9,16,14,14,13,13,16,15,15,14,14,17, + 14,14,12,12,16,14,14,13,13,17,15,15,14,14,17,16, + 16,15,16,18,15,15,14,14,17,15,15,14,14,17,15,15, + 14,14,18,15,15,14,14,16,16,16,15,16,18,15,15,14, + 14,17,16,15,14,14,18,15,15,14,14,17,15,15,14,14, + 17,16,16,15,15,18,14,15,13,13,17,15,15,14,14,18, + 15,15,13,13,17,15,15,14,14,17,16,15,15,15,17,15, + 15,13,13,17,15,15,14,14,18,15,15,13,13,13,11,11, + 10,10,16,14,14,12,12,16,14,14,12,12,17,14,15,11, + 11,17,14,14,11,11,17,15,15,13,13,17,14,14,14,13, + 17,15,15,13,13,16,15,15,13,13,17,15,15,13,13,17, + 15,15,13,13,17,14,14,14,14,17,15,15,13,13,17,14, + 15,13,13,16,15,15,13,13,17,15,15,13,13,17,14,14, + 13,13,17,15,15,12,12,16,14,14,12,12,17,15,15,12, + 12,17,15,15,13,13,17,14,14,13,13,17,15,15,12,12, + 17,14,14,12,12,17,15,15,12,12,13,15,14, 8, 8,14, + 14,14,19,19,14,15,15,18,19,14,14,14,18,19,14,15, + 14,19,19,15,16,15,19,19,15,16,16,19,20,15,15,15, + 19,19,15,16,16,19,19,15,16,16,19,19,15,15,15,19, + 19,15,16,16,20,20,15,15,15,19,19,15,15,15,19,19, + 15,15,15,19,19,15,15,15,19,19,15,16,16,20,19,15, + 15,15,19,19,15,15,15,19,19,15,15,15,19,19,15,16, + 15,19,19,15,16,16,21,19,15,15,15,20,20,15,15,15, + 20,21,15,15,15,19,20,14,12,12, 8, 8,14,14,14,19, + 19,14,13,13,19,19,14,14,14,19,19,14,13,14,19,19, + 15,15,15,20,20,15,14,14,20,19,15,15,15,19,20,15, + 14,14,19,20,15,15,15,20,19,15,15,15,19,20,15,14, + 14,20,20,15,15,15,20,19,15,14,14,19,19,15,15,15, + 19,19,15,15,15,20,19,15,14,14,21,19,15,15,15,20, + 21,15,14,14,21,19,15,15,15,19,19,15,15,15,20,20, + 15,14,14,19,21,15,15,15,19,19,15,14,14,19,20,15, + 15,15,19,19,13,12,12,13,13,17,16,16,11,11,17,16, + 15,12,12,18,16,16,11,11,17,16,16,11,11,18,17,17, + 13,13,18,16,16,13,13,17,17,17,12,13,18,17,16,13, + 13,18,17,17,13,13,17,17,17,13,13,17,16,16,13,13, + 18,16,17,12,12,17,16,16,13,12,17,17,17,12,12,18, + 17,17,13,12,18,16,16,13,13,18,17,17,12,12,17,16, + 16,12,12,17,17,17,11,11,17,16,16,12,12,17,16,16, + 13,13,17,16,16,11,11,17,16,16,12,12,17,17,17,11, + 11,13,14,14, 9, 9,16,14,14,13,13,16,15,15,14,14, + 17,14,14,12,12,16,14,14,13,13,17,15,15,14,14,17, + 15,16,15,15,17,15,15,14,14,17,15,16,14,15,18,15, + 15,14,14,17,15,15,14,14,16,16,16,15,15,18,15,15, + 13,14,17,15,15,14,14,18,15,15,14,14,17,15,15,14, + 14,17,16,16,15,15,17,15,15,13,13,17,15,15,14,14, + 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,17, + 15,15,13,13,17,15,15,14,14,18,15,15,13,13,13,11, + 11,10,10,16,14,14,12,12,16,14,14,13,13,17,14,14, + 11,11,17,14,14,12,12,17,15,15,14,14,17,14,14,14, + 14,17,15,15,13,13,17,15,14,13,13,16,15,15,13,13, + 16,15,15,13,13,17,14,14,14,14,17,15,15,13,13,17, + 14,14,13,13,16,15,15,13,13,16,15,15,13,13,17,14, + 14,13,13,17,15,15,12,12,17,14,14,12,12,16,15,15, + 12,12,17,15,15,13,13,17,14,14,13,13,17,15,15,12, + 12,17,14,14,12,12,16,15,15,12,12,14,14,14, 8, 8, + 14,14,14,18,18,14,15,15,19,18,14,14,14,18,18,14, + 14,14,18,19,15,16,15,19,19,15,17,16,20,20,15,15, + 15,19,19,15,16,16,19,19,15,15,15,19,19,15,16,15, + 18,19,15,16,16,20,20,15,15,15,19,19,15,16,16,19, + 20,15,15,15,19,19,15,15,16,19,19,15,16,16,20,20, + 15,15,15,19,19,15,15,15,19,20,15,15,15,19,19,15, + 15,15,19,19,15,16,16,20,20,15,15,15,19,20,15,16, + 16,20,20,15,15,15,19,19,13,12,12, 8, 8,14,14,14, + 19,20,14,14,14,19,19,14,14,14,18,19,14,14,14,19, + 20,15,15,15,19,20,15,14,14,21,20,15,15,15,20,20, + 15,15,14,19,19,15,15,15,19,19,15,15,15,19,19,15, + 14,14,19,20,15,15,15,19,20,15,14,14,19,19,15,15, + 15,19,19,15,15,15,19,19,16,14,14,19,19,15,15,15, + 20,20,15,14,14,21,19,15,15,15,19,19,15,15,15,19, + 20,16,14,14,19,20,15,15,15,19,19,15,14,14,19,19, + 15,15,15,20,19, +}; + +static const static_codebook _44p1_p3_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p1_p3_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p1_p3_1, + 0 +}; + +static const long _vq_quantlist__44p1_p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p1_p4_0[] = { + 2, 6, 6,14,14, 6, 7, 7,14,14, 7, 7, 7,14,14, 0, + 13,13,16,16, 0,13,13,15,14, 7, 8, 8,15,15, 9,10, + 10,16,16, 9, 8, 8,15,15, 0,13,13,17,16, 0,13,13, + 15,16, 8, 8, 8,15,15,12,11,11,16,16, 9, 8, 8,14, + 14, 0,13,13,17,18, 0,13,13,15,15, 0,14,14,16,16, + 0, 0, 0,19,18, 0,12,12,16,15, 0,15,16, 0,20, 0, + 14,14,16,16, 0,14,14,17,17, 0, 0, 0,19,18, 0,12, + 12,15,15, 0,17,17, 0,20, 0,14,14,16,16, 5, 6, 7, + 12,12, 9, 9, 9,14,14,10,10,10,14,14, 0,21,21,18, + 17, 0,20,20,18,17, 9,10,10,14,14,12,12,12,16,16, + 12,10,10,14,14, 0,20,19,18,17, 0, 0,20,17,18,11, + 10,10,14,14,14,13,13,18,18,13,11,11,14,14, 0,20, + 20,17,18, 0,21,21,17,17, 0,21, 0,18,18, 0, 0, 0, + 0, 0, 0,20,19,16,17, 0, 0, 0,19,19, 0, 0, 0,18, + 18, 0,21,21,18,18, 0, 0, 0, 0, 0, 0,20,20,16,17, + 0, 0, 0,21,21, 0, 0, 0,18,19, 6, 6, 6,13,12, 8, + 6, 6,11,11, 8, 6, 6,13,13, 0, 9, 9,11,11, 0,11, + 10,14,14, 9, 7, 7,13,13,11, 9, 9,13,13,10, 6, 6, + 13,13, 0,10,10,14,15, 0,10,10,13,13, 9, 7, 7,13, + 13,13,10, 9,13,13,10, 6, 6,13,13, 0,10,10,15,14, + 0,10,10,13,13, 0,11,11,15,15, 0,19,20,17,17, 0, + 9, 9,13,13, 0,13,13,20,20, 0,11,11,13,13, 0,11, + 11,15,15, 0,19,19,17,17, 0,10,10,13,13, 0,15,15, + 20,20, 0,12,12,13,13, 0,10,10,12,12, 0,11,11,15, + 15, 0,11,11,15,15, 0,15,15,20, 0, 0,16,16, 0,21, + 0,11,11,15,15, 0,14,14,18,17, 0,11,11,15,15, 0, + 15,16,19,20, 0,16,16,21,21, 0,12,12,15,15, 0,15, + 14,18,18, 0,11,11,16,16, 0,15,15,21,21, 0,16,15, + 0, 0, 0,16,16,21, 0, 0, 0, 0, 0, 0, 0,14,14,20, + 20, 0,18,18, 0, 0, 0,16,17,21, 0, 0,16,16,21,21, + 0, 0, 0, 0, 0, 0,15,15,21,21, 0,20,19, 0,21, 0, + 17,17, 0, 0, 0,10,10,12,11, 0,10,10,10,11, 0,11, + 11,12,12, 0,11,11, 9, 9, 0,13,13,11,12, 0,11,11, + 12,12, 0,13,13,12,12, 0,10,10,12,12, 0,12,12,13, + 13, 0,12,12,12,12, 0,11,11,12,12, 0,13,13,12,12, + 0,10,10,12,12, 0,13,13,14,14, 0,12,12,12,12, 0, + 14,14,14,13, 0,19,20,15,15, 0,12,11,12,12, 0,15, + 15,21,20, 0,13,13,11,11, 0,13,13,13,13, 0,19, 0, + 15,15, 0,12,12,12,12, 0,17,16,19, 0, 0,13,13,12, + 12, 7, 7, 7,16,16,11, 9, 9,15,15,12, 9, 9,16,16, + 0,13,13,15,14, 0,14,14,17,16,10, 9, 9,16,16,14, + 11,11,17,16,12, 9, 8,15,15, 0,13,13,18,18, 0,13, + 13,15,15,12,10,10,18,17,15,12,12,17,17,14, 9, 9, + 16,16, 0,13,13,18,19, 0,14,13,17,16, 0,14,14,18, + 18, 0, 0, 0,20,21, 0,12,12,16,16, 0,16,16,20,21, + 0,14,14,17,16, 0,14,14,18,19, 0, 0, 0,19,21, 0, + 13,13,17,17, 0,17,17, 0,21, 0,15,15,16,16, 8, 7, + 7,14,14,11,10,10,15,15,12,10,10,15,15, 0,20,20, + 18,18, 0, 0, 0,17,17,11,10,10,16,16,14,12,12,18, + 17,14,11,11,15,15, 0,20,21,18,18, 0, 0,19,18,17, + 12,10,10,16,16,17,14,14,19,19,14,11,11,15,15, 0, + 21,21,19,19, 0,21,20,19,18, 0,21, 0,18,19, 0, 0, + 0, 0, 0, 0,20,20,18,17, 0,21, 0, 0, 0, 0, 0, 0, + 19,18, 0, 0, 0,18,19, 0, 0, 0, 0, 0, 0, 0,21,17, + 18, 0, 0, 0, 0,21, 0, 0,21,18,19,11, 9, 9,14,14, + 13,10,10,13,13,13,11,11,15,15, 0,13,13,12,12, 0, + 15,15,16,16,13,10,10,15,15,16,12,12,15,15,15,10, + 10,15,15, 0,14,13,16,15, 0,14,13,15,15,13,10,10, + 15,15,18,14,14,15,15,15,10,10,14,15, 0,14,14,16, + 16, 0,14,14,16,15, 0,15,15,17,16, 0,21, 0,18,18, + 0,12,13,15,15, 0,16,16, 0, 0, 0,14,14,15,15, 0, + 15,15,16,16, 0,21,20,18,18, 0,13,13,15,15, 0,19, + 18, 0, 0, 0,15,15,15,15, 0,11,11,13,13, 0,12,12, + 16,16, 0,12,12,16,16, 0,15,16,20, 0, 0,16,17, 0, + 0, 0,12,12,16,16, 0,14,14,18,18, 0,11,11,16,17, + 0,15,15,20, 0, 0,16,16, 0, 0, 0,12,12,16,16, 0, + 15,15,19,19, 0,11,11,17,17, 0,16,16,21, 0, 0,16, + 16, 0, 0, 0,17,17,20,20, 0, 0, 0, 0, 0, 0,15,15, + 20, 0, 0,17,18, 0, 0, 0,17,17, 0, 0, 0,16,16, 0, + 21, 0, 0, 0, 0, 0, 0,15,15,21, 0, 0,19,18, 0, 0, + 0,18,17, 0, 0, 0,11,11,14,14, 0,11,11,15,15, 0, + 12,12,16,16, 0,13,13,14,14, 0,14,14,17,17, 0,12, + 12,16,16, 0,14,14,16,16, 0,11,11,16,15, 0,13,13, + 16,17, 0,13,13,16,16, 0,12,12,15,16, 0,15,14,16, + 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,16,16, + 0,15,14,18,18, 0,21, 0,19,19, 0,13,13,15,15, 0, + 16,16,20,20, 0,14,14,16,15, 0,14,14,17,17, 0,21, + 0,20,18, 0,13,13,15,15, 0,17,17, 0, 0, 0,14,14, + 16,15, 8, 8, 8,16,16,12, 9, 9,16,16,13, 9, 9,16, + 16, 0,14,14,18,17, 0,14,14,16,17,12,10,10,18,17, + 14,11,11,18,18,14, 9, 9,16,16, 0,13,13,18,18, 0, + 13,13,17,16,12, 9, 9,16,17,17,13,13,16,16,14, 9, + 9,15,15, 0,14,14,20,20, 0,13,13,15,15, 0,15,14, + 18,18, 0, 0, 0,20,21, 0,12,13,16,17, 0,16,16,20, + 21, 0,14,14,16,17, 0,14,14,18,17, 0, 0, 0,20,21, + 0,13,13,16,16, 0,19,17, 0,21, 0,14,15,16,16, 8, + 7, 7,14,13,12,10,10,15,15,13,10,10,15,15, 0,21, + 21,18,19, 0,20,21,18,18,12,10,10,16,15,15,12,12, + 17,17,14,11,11,15,15, 0,21,21,19,18, 0, 0,21,17, + 18,13,11,11,15,15,16,13,13,18,19,15,11,11,15,14, + 0,21, 0,19,19, 0, 0,21,18,18, 0, 0,21,19,19, 0, + 0, 0, 0, 0, 0,20,19,17,17, 0, 0, 0,21, 0, 0,21, + 0,18,19, 0, 0,20,20,19, 0, 0, 0, 0, 0, 0,21,20, + 18,17, 0, 0, 0, 0,20, 0, 0, 0,18,19, 0,10,10,15, + 14, 0,11,11,14,14, 0,11,11,15,16, 0,14,14,15,15, + 0,15,15,16,16, 0,11,11,16,16, 0,14,13,16,16, 0, + 11,11,15,15, 0,14,14,16,16, 0,14,14,15,15, 0,11, + 11,15,15, 0,13,13,15,15, 0,11,11,15,15, 0,15,15, + 18,17, 0,14,14,15,15, 0,15,16,18,18, 0, 0, 0,20, + 20, 0,14,13,16,15, 0,17,17,21, 0, 0,15,15,15,15, + 0,16,15,17,17, 0, 0, 0,19,19, 0,13,13,15,15, 0, + 20,19, 0, 0, 0,15,15,15,15, 0,11,11,13,13, 0,12, + 12,16,16, 0,12,12,16,16, 0,15,15,21,21, 0,17,16, + 0, 0, 0,12,12,16,16, 0,14,14,17,17, 0,11,11,16, + 16, 0,15,15, 0, 0, 0,16,16,21, 0, 0,12,12,17,16, + 0,14,15,20,20, 0,11,11,16,16, 0,15,15, 0,20, 0, + 16,16, 0,21, 0,16,17,21, 0, 0, 0, 0, 0, 0, 0,15, + 15, 0,21, 0,18,18, 0, 0, 0,17,16, 0, 0, 0,17,17, + 21, 0, 0, 0, 0, 0, 0, 0,15,15, 0,20, 0,19,20,21, + 0, 0,17,18, 0, 0, 0,12,12,15,15, 0,12,12,15,15, + 0,12,12,16,16, 0,13,13,15,15, 0,15,15,17,17, 0, + 13,12,17,16, 0,14,14,17,16, 0,11,11,16,16, 0,14, + 14,17,17, 0,14,14,17,17, 0,12,12,16,16, 0,15,15, + 17,17, 0,11,11,16,16, 0,14,14,17,17, 0,14,14,16, + 16, 0,15,15,18,17, 0, 0, 0,19, 0, 0,13,13,16,16, + 0,16,16, 0,21, 0,14,14,16,16, 0,15,15,18,17, 0, + 0, 0,19,19, 0,13,13,16,16, 0,18,17, 0,21, 0,14, + 15,16,16, 0,11,11,16,16, 0,13,13,17,17, 0,13,13, + 17,17, 0,16,16,16,17, 0,16,16,18,18, 0,12,12,17, + 17, 0,16,15,18,17, 0,12,12,16,16, 0,16,15,19,19, + 0,16,15,17,17, 0,12,12,17,18, 0,16,16,18,18, 0, + 12,12,16,16, 0,16,16,19,19, 0,15,16,17,17, 0,15, + 16,18,18, 0, 0, 0,20,20, 0,13,13,16,16, 0,18,18, + 21,20, 0,15,15,16,16, 0,16,16,19,18, 0, 0, 0,19, + 20, 0,14,14,17,17, 0,19,19, 0,21, 0,15,16,16,16, + 0, 9, 9,14,14, 0,13,13,15,15, 0,14,14,15,15, 0, + 0,21,19,19, 0, 0,21,18,18, 0,12,12,15,15, 0,15, + 15,18,18, 0,14,13,15,15, 0,21,21,18,19, 0,21,20, + 18,18, 0,13,13,16,16, 0,17,17,18,19, 0,14,14,15, + 15, 0, 0,21,19,19, 0,21,20,18,19, 0,20,20,19,19, + 0, 0, 0, 0, 0, 0,19,20,17,17, 0, 0, 0,21,21, 0, + 21, 0,18,20, 0,21, 0,18,21, 0, 0, 0, 0, 0, 0,21, + 21,19,18, 0, 0, 0, 0, 0, 0, 0, 0,19,19, 0,18,18, + 15,15, 0,18,20,17,16, 0,20, 0,17,17, 0,21, 0,17, + 17, 0,21,20,19,20, 0,19,19,16,16, 0,21,21,17,18, + 0,19,19,17,17, 0,20,21,21,21, 0,20,20,18,18, 0, + 19,19,16,16, 0, 0,21,18,19, 0,18,19,16,17, 0,21, + 21,19,20, 0,21,19,18,18, 0,21,20,19,21, 0, 0, 0, + 20,21, 0,19,19,17,16, 0, 0, 0, 0, 0, 0,21,20,17, + 17, 0,20,21,19,18, 0, 0, 0, 0,21, 0,19,18,16,17, + 0, 0, 0, 0, 0, 0,20,20,17,17, 0,11,11,14,14, 0, + 13,13,16,16, 0,13,13,16,16, 0,17,17,21, 0, 0,17, + 18, 0, 0, 0,12,12,16,16, 0,15,15,17,18, 0,12,12, + 16,16, 0,16,16, 0,20, 0,17,17, 0,21, 0,12,12,17, + 17, 0,16,16,19,20, 0,12,12,17,17, 0,17,17, 0,20, + 0,17,17, 0, 0, 0,17,17,21, 0, 0, 0, 0, 0, 0, 0, + 15,15, 0,20, 0,19,19, 0, 0, 0,18,18, 0, 0, 0,17, + 17, 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0,20,19, + 0, 0, 0,19,18, 0, 0, 0,14,14,21,19, 0,16,16,20, + 21, 0,16,16,20,20, 0,17,17,20, 0, 0,17,17,20,20, + 0,15,15,20,20, 0,19,18,20, 0, 0,15,15,20,20, 0, + 17,18,21,20, 0,17,17,20,21, 0,15,15,19,19, 0,19, + 18,21,21, 0,15,15,19,20, 0,17,18, 0, 0, 0,17,17, + 20,20, 0,17,18,20,21, 0, 0, 0, 0, 0, 0,15,15,20, + 20, 0,19,19, 0, 0, 0,17,17,19,21, 0,17,17, 0,21, + 0, 0, 0, 0,21, 0,15,15,20,19, 0, 0,20, 0, 0, 0, + 17,17,21,20, 0,12,12,16,16, 0,14,14,17,17, 0,13, + 13,17,17, 0,16,16,17,18, 0,17,16,18,18, 0,13,13, + 18,17, 0,15,16,19,18, 0,13,13,16,16, 0,16,16,19, + 19, 0,16,16,17,17, 0,13,12,17,17, 0,16,16,18,17, + 0,12,12,16,16, 0,17,17,19,18, 0,16,15,16,16, 0, + 16,17,18,19, 0, 0, 0,20,20, 0,14,14,17,16, 0,18, + 18,21, 0, 0,16,16,16,16, 0,16,16,18,17, 0, 0,21, + 21,21, 0,14,14,16,16, 0,21,20,21, 0, 0,16,16,16, + 16, 0,10,10,14,14, 0,14,14,15,16, 0,14,14,15,15, + 0, 0,21,18,18, 0, 0,21,18,19, 0,13,13,16,16, 0, + 16,16,18,17, 0,14,14,15,15, 0,20, 0,18,18, 0,21, + 0,18,17, 0,13,13,16,15, 0,17,17,19,19, 0,14,14, + 15,15, 0,20,20,18,19, 0, 0, 0,18,17, 0, 0,21,18, + 18, 0, 0, 0, 0, 0, 0,20,21,18,17, 0, 0, 0, 0, 0, + 0, 0, 0,19,19, 0, 0,21,18,18, 0, 0, 0, 0, 0, 0, + 21, 0,18,17, 0, 0, 0, 0,21, 0, 0, 0,19,20, 0,19, + 19,16,16, 0, 0,21,18,17, 0,21, 0,18,18, 0,20, 0, + 19,18, 0,21,20,19,19, 0,21,19,17,18, 0, 0,21,19, + 19, 0,21,19,18,18, 0,21, 0,20,18, 0, 0,21,18,18, + 0,20,21,17,17, 0,21, 0,18,18, 0,21,19,17,17, 0, + 21, 0, 0,20, 0, 0,20,17,18, 0, 0, 0,19,20, 0, 0, + 0,20,19, 0,19,21,17,18, 0,21, 0, 0, 0, 0,21,21, + 18,17, 0, 0,21,18,18, 0, 0, 0, 0,21, 0,20,19,16, + 17, 0, 0, 0, 0, 0, 0,21,20,17,17, 0,11,11,13,13, + 0,13,13,16,16, 0,13,13,16,16, 0,17,17, 0,21, 0, + 18,19,21, 0, 0,12,12,16,16, 0,15,15,19,18, 0,13, + 13,16,16, 0,16,17,21,19, 0,17,17,21,21, 0,13,13, + 16,16, 0,16,16,20,18, 0,13,13,16,16, 0,17,17, 0, + 0, 0,18,18, 0, 0, 0,18,17, 0,20, 0, 0, 0, 0, 0, + 0,15,15,21,21, 0,19,18, 0, 0, 0,17,17,21,21, 0, + 17,17, 0, 0, 0, 0, 0, 0, 0, 0,15,15,20,21, 0,20, + 20, 0, 0, 0,19,19, 0, 0, 0,14,15,21,19, 0,16,16, + 0,21, 0,17,16,21,21, 0,17,18,21,20, 0,18,18, 0, + 21, 0,16,16, 0,20, 0,19,19, 0, 0, 0,16,15, 0,20, + 0,18,18, 0, 0, 0,17,17, 0,21, 0,16,16,20,20, 0, + 20,19, 0, 0, 0,15,16,21,22, 0,18,18, 0, 0, 0,18, + 17, 0, 0, 0,18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, + 21,20, 0,19,20, 0, 0, 0,18,17,21, 0, 0,17,18, 0, + 0, 0, 0, 0, 0, 0, 0,16,16, 0,20, 0, 0,20, 0, 0, + 0,18,18,22, 0, +}; + +static const static_codebook _44p1_p4_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p1_p4_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p1_p4_0, + 0 +}; + +static const long _vq_quantlist__44p1_p4_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p1_p4_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p1_p4_1 = { + 1, 7, + (char *)_vq_lengthlist__44p1_p4_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p1_p4_1, + 0 +}; + +static const long _vq_quantlist__44p1_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_p5_0[] = { + 1, 6, 6, 7, 8, 8, 7, 8, 8, 7, 9, 8,10,11,11, 9, + 8, 8, 7, 8, 8,11,11,11, 9, 8, 8, 6, 7, 7,10,10, + 10,10,10,10,10,10,10,14,13,13,12,11,11,10,10,10, + 14,14,13,12,11,11, 6, 6, 6, 8, 5, 5, 8, 7, 7, 9, + 7, 7,11,10,10, 9, 7, 7, 9, 7, 7,12,10,10,10, 7, + 7, 7, 8, 8,12,11,10,12,10,10,11,10,10,15,13,13, + 13,10,10,11,10,10,17,14,13,13,10,10, 7, 7, 7,12, + 11,12,12,11,11,12,11,11,16,14,14,13,12,12,12,11, + 11,17,15,14,14,12,12,10, 9, 9,13,11,11,13,11,11, + 13,11,11,17,14,13,14,11,11,12,11,11,16,15,14,14, + 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,15,13, + 13,14,11,10,12,10,10,16,14,14,14,10,10, 8, 7, 7, + 12,11,11,12,11,11,12,11,11,17,14,14,14,12,12,12, + 11,11,16,15,15,14,12,12,10,10,10,13,11,11,13,11, + 11,13,11,12,16,14,14,14,11,11,13,12,11,16,15,15, + 14,11,11, +}; + +static const static_codebook _44p1_p5_0 = { + 5, 243, + (char *)_vq_lengthlist__44p1_p5_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p1_p5_0, + 0 +}; + +static const long _vq_quantlist__44p1_p5_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_p5_1[] = { + 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 8, 8, 8, + 7, 7, 8, 8, 8, 9, 8, 8, 9, 7, 7, 6, 6, 6, 9, 8, + 7, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8, + 10, 8, 8,10, 8, 8, 7, 6, 6, 9, 6, 6, 9, 7, 7, 9, + 7, 7,10, 8, 8, 9, 6, 6, 9, 7, 7,10, 8, 8, 9, 7, + 7, 7, 8, 8,11, 9, 9,11, 9, 9,11, 8, 9,12, 9, 9, + 12, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7,10, + 9, 9,10,10, 9,10, 9, 9,11,10,10,11, 9, 9,11, 9, + 9,11,10,11,11, 9, 9,10, 8, 8,11, 9, 9,10, 9, 9, + 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11, + 9, 9, 9, 8, 8,11, 9, 9,12, 9, 9,11, 9, 9,12, 9, + 9,12, 8, 8,12, 9, 9,12, 9, 9,12, 8, 8, 9, 7, 7, + 11, 9, 9,11,10,10,11, 9, 9,11,11,11,11, 9, 9,11, + 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11,10, + 10,11, 9, 9,11,10,10,11, 9, 9,11, 9,10,11,10,10, + 11, 9, 9, +}; + +static const static_codebook _44p1_p5_1 = { + 5, 243, + (char *)_vq_lengthlist__44p1_p5_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p1_p5_1, + 0 +}; + +static const long _vq_quantlist__44p1_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p1_p6_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 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, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, +}; + +static const static_codebook _44p1_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p1_p6_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p1_p6_0, + 0 +}; + +static const long _vq_quantlist__44p1_p6_1[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p1_p6_1[] = { + 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,13,14,16,16,16,16, +}; + +static const static_codebook _44p1_p6_1 = { + 1, 25, + (char *)_vq_lengthlist__44p1_p6_1, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p1_p6_1, + 0 +}; + +static const long _vq_quantlist__44p1_p6_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p1_p6_2[] = { + 3, 4, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44p1_p6_2 = { + 1, 25, + (char *)_vq_lengthlist__44p1_p6_2, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p1_p6_2, + 0 +}; + +static const char _huff_lengthlist__44p1_short[] = { + 4, 5, 7, 8,10,13,14, 4, 2, 4, 6, 8,11,12, 7, 4, + 3, 5, 8,12,14, 8, 5, 4, 4, 8,12,12, 9, 7, 7, 7, + 9,10,11,13,11,11, 9, 7, 8,10,13,11,10, 6, 5, 7, + 9, +}; + +static const static_codebook _huff_book__44p1_short = { + 2, 49, + (char *)_huff_lengthlist__44p1_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p2_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p2_l0_0[] = { + 1, 4, 4, 7, 7, 8, 8, 9, 9,10,10,11,11, 4, 6, 5, + 8, 7, 9, 8,10, 9,11,10,11,11, 4, 5, 6, 7, 8, 8, + 9, 9,10,10,10,10,11, 8, 9, 8,10, 8,10, 9,11,10, + 11,11,11,11, 8, 8, 9, 8,10, 9,10,10,11,11,11,11, + 11, 9,10,10,11,11,11,11,11,11,12,11,12,11, 9,10, + 10,10,11,11,11,11,11,11,12,11,12,10,11,11,12,11, + 12,12,12,12,12,12,12,12,10,11,11,11,11,12,12,12, + 13,12,12,12,12,11,12,12,12,12,13,13,12,12,12,12, + 12,12,11,12,12,12,12,13,13,12,13,12,12,12,12,12, + 13,13,13,13,13,13,12,13,12,13,12,12,12,13,13,13, + 13,13,13,13,12,13,12,12,12, +}; + +static const static_codebook _44p2_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p2_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p2_l0_0, + 0 +}; + +static const long _vq_quantlist__44p2_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p2_l0_1[] = { + 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5, + 5, 6, 6, 6, 5, 6, 5, 6, 6, +}; + +static const static_codebook _44p2_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p2_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p2_l0_1, + 0 +}; + +static const long _vq_quantlist__44p2_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_l1_0[] = { + 1, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const static_codebook _44p2_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44p2_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p2_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p2_lfe[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book__44p2_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p2_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p2_long[] = { + 3, 4, 9, 8, 8,10,13,16, 4, 2, 9, 5, 7,10,14,18, + 9, 7, 6, 5, 7, 9,12,16, 7, 5, 5, 3, 5, 8,11,13, + 8, 7, 7, 5, 5, 7, 9,11,10,10, 9, 8, 6, 6, 8,10, + 13,14,13,11, 9, 8, 9,10,17,18,16,14,11,10,10,10, +}; + +static const static_codebook _huff_book__44p2_long = { + 2, 64, + (char *)_huff_lengthlist__44p2_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p2_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p1_0[] = { + 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p2_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p2_p1_0, + 0 +}; + +static const long _vq_quantlist__44p2_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p2_p2_0[] = { + 1, 4, 4, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, + 10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, 0, 0, 0, + 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, + 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, + 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0,11,11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, + 6, 6, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, + 0, 0,10,10, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 11,11, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0,11,10, 0, 0, 0, 0, 0, + 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, + 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0, 0,11,11, 0, 0, + 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0, + 0, 0, 0, 0, 0,10,10, 0, 0, 0,13,13, 0, 0, 0, 0, + 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12, + 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0, + 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,13,13, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, + 0, 0, 0,12,12, 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, + 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,11, 0, 0, + 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0, 0, 0, + 0, 0, 0, 0, 0,12,12, 0, 0, 0,13,13, 0, 0, 0, 0, + 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12, + 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0, 0,11,11, 0, + 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0, 0, + 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,13,13, 0, 0, 0, + 0, 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,10, + 10, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,14,13, + 0, 0, 0, 0, 0, 0, 0, 0,13,12, 0, 0, 0,13,13, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11, + 11, 0, 0, 0,12,12, 0, 0, 0,12,12, 0, 0, 0, 0, 0, + 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0, + 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,13,13, 0, 0, + 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,12,12, 0, 0, 0, + 0, 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12, + 12, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, 0,12,12, + 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0, + 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,14,14, 0, 0, + 0, 0, 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, + 12,12, 0, 0, 0,12,13, 0, 0, 0, 0, 0, 0, 0, 0,12, + 12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,14,13, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 11,11, 0, 0, 0,12,12, 0, 0, 0,13,13, 0, 0, 0, 0, + 0, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12, + 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0, + 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0,14,14, 0, 0, + 0, 0, 0, 0, 0, 0,14,14, 0, 0, 0, 0, 0, 0, 0, 0, + 12,12, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, +}; + +static const static_codebook _44p2_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p2_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p2_p2_0, + 0 +}; + +static const long _vq_quantlist__44p2_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p3_0[] = { + 1, 5, 5, 6, 7, 7, 0, 8, 8, 6, 9, 9, 8,11,11, 0, + 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 5, 7, 7, 7,10, + 10, 0,12,12, 8,11,11, 9,12,12, 0,11,12, 0,12,12, + 0,15,15, 0,12,12, 0, 6, 6, 0, 6, 6, 0, 7, 7, 0, + 7, 7, 0,10,10, 0, 7, 7, 0, 8, 8, 0,11,11, 0, 7, + 7, 6, 7, 7,10, 9, 9, 0,11,10,10, 9, 9,12,12,12, + 0,10,10, 0,11,11, 0,13,13, 0,11,11, 7, 6, 6,10, + 10,10, 0,11,11,11,11,11,12,12,12, 0,11,11, 0,12, + 12, 0,15,15, 0,11,11, 0,11,11, 0,11,11, 0,12,12, + 0,12,12, 0,14,14, 0,12,12, 0,12,12, 0,15,15, 0, + 11,11, 0, 8, 8, 0,10,10, 0,11,11, 0,11,11, 0,12, + 12, 0,12,12, 0,11,11, 0,15,15, 0,11,11, 0, 6, 6, + 0,10,10, 0,12,12, 0,10,10, 0,13,13, 0,12,12, 0, + 13,13, 0,14,14, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p2_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p2_p3_0, + 0 +}; + +static const long _vq_quantlist__44p2_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p3_1[] = { + 2, 3, 3, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0, 9, 9, 0, + 9, 9, 0, 9, 9, 0, 9, 9, 0, 8, 8, 0, 6, 6, 0, 7, + 7, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, + 0, 8, 8, 0, 8, 8, 0, 6, 6, 0, 6, 6, 0, 6, 6, 0, + 8, 8, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 6, + 6, 0, 8, 8, 0, 9, 9, 0, 9, 9, 0,10,10, 0,10,10, + 0,10,10, 0,10,10, 0,11,11, 0, 9, 9, 0, 7, 7, 0, + 10,10, 0,10,10, 0,12,11, 0,12,12, 0,11,11, 0,11, + 11, 0,12,12, 0,10,10, 0, 7, 7, 0,10,10, 0,10,10, + 0,12,12, 0,11,12, 0,11,11, 0,11,11, 0,11,11, 0, + 10,10, 0, 8, 8, 0, 9, 9, 0, 9, 9, 0,10,10, 0,10, + 10, 0,10, 9, 0,10,10, 0,10,10, 0, 9, 9, 0, 6, 6, + 0,10,10, 0,10,10, 0,11,11, 0,12,12, 0,11,11, 0, + 11,11, 0,12,12, 0,11,11, 0, 7, 7, 0, 9, 9, 0, 9, + 9, 0,11,11, 0,11,11, 0,10,10, 0,10,10, 0,11,11, + 0, 9, 9, +}; + +static const static_codebook _44p2_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p2_p3_1, + 0 +}; + +static const long _vq_quantlist__44p2_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p4_0[] = { + 1, 6, 6, 6, 7, 7, 7, 8, 8, 7, 8, 8,10,11,11, 9, + 8, 8, 7, 8, 8,11,11,11, 9, 8, 8, 6, 7, 7, 9,11, + 11, 9,11,11,10,11,11,12,13,13,11,12,12,10,11,11, + 13,14,14,12,12,12, 6, 6, 6, 8, 6, 6, 8, 7, 7, 9, + 7, 7,11,10,10,10, 6, 6, 9, 7, 7,12,10,10,11, 6, + 7, 7, 7, 7,11,10,10,12,10,10,11,10,10,14,13,13, + 13,10,10,12,11,11,15,13,13,14,10,10, 8, 7, 7,12, + 11,11,12,11,11,11,11,11,14,14,14,13,12,12,12,11, + 11,15,15,15,13,12,12, 0,10,10, 0,11,11, 0,11,11, + 0,11,11, 0,14,14, 0,11,11, 0,11,11, 0,15,15, 0, + 11,11, 7, 8, 8,12,10,10,12,10,10,12,11,11,15,13, + 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7, + 12,11,11,12,11,11,12,11,11,16,14,14,14,12,12,13, + 12,12,15,14,14,15,12,12, 0,11,11, 0,12,12, 0,12, + 12, 0,12,12, 0,15,15, 0,12,12, 0,12,12, 0,14,14, + 0,12,12, +}; + +static const static_codebook _44p2_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p2_p4_0, + 0 +}; + +static const long _vq_quantlist__44p2_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p2_p4_1[] = { + 3, 4, 4, 8, 8,11, 9, 9,12,12,11,10,10,12,12,12, + 10,10,11,11,12,12,12,12,12,12,11,11,13,13,12,12, + 12,13,13,12,10,10,12,12,12,11,11,13,13,12,13,13, + 13,13,12,11,11,13,13,12,12,12,13,13,12,10,10,12, + 12,12,11,11,13,13,12,13,13,12,12,12,11,11,13,13, + 12,13,13,13,13,12,11,11,12,12,12,11,11,12,12,12, + 13,13,12,12,12,13,13,13,13,12,13,13,13,13,13,13, + 13,12,12,12,13,13,13,13,12,13,13,12,12,11, 8, 8, + 10,10,12,11,11,11,11,12,10,10,10,10,13,11,11,10, + 10,13,11,11,10,10,13,12,12,12,12,13,11,11,11,11, + 13,12,12,11,11,13,12,12,11,11,13,12,12,12,11,13, + 12,12,12,12,13,11,11,11,11,13,12,12,11,11,13,11, + 12,11,11,13,12,12,11,11,14,12,12,11,11,13,11,11, + 11,11,14,12,12,11,11,13,11,12,10,10,14,12,12,11, + 11,14,12,12,11,11,14,11,11,11,11,14,12,12,11,11, + 13,12,12,11,11,14,12,12,11,11,11, 8, 8,10,10,12, + 7, 7,10,10,12, 9, 9,11,11,13, 9, 9, 9, 9,13,13, + 13,10,10,13, 9, 9,12,12,13,13,13,12,12,13, 9, 8, + 11,11,13,10,10,12,12,14,13,13,11,11,13, 9, 9,11, + 11,13,13,13,12,12,13, 9, 9,10,10,13,10,10,11,11, + 13,13,13,10,10,14,10,10,11,11,14,14,14,12,12,13, + 9, 9,10,10,13,10,10,11,11,14,13,14,10,10,14,14, + 14,11,12,14,14,14,14,14,14,13,13,10,10,13,14,14, + 11,11,14,14,14,10,10,14, 9, 9, 9, 9,14, 9, 9, 9, + 9,14,10,10, 9, 9,14,10,10, 8, 8,14,11,11, 8, 8, + 15,11,11,10,10,15,12,12,10,10,15,10,10,10,10,15, + 11,11,10,10,15,13,13,10,10,15,11,11,10,10,15,12, + 12,10,10,15,10,10,10,10,15,11,11,10,10,15,13,13, + 10,10,15,11,11,10,10,15,12,12,10,10,15,11,11, 9, + 9,15,11,11, 9, 9,15,13,13, 9, 9,15,13,13,10,10, + 15,12,12,10,10,15,13,13,10,10,15,13,12, 9, 9,15, + 13,13, 9, 9,14,12,12, 9, 9,14,13,13, 9, 9,14,13, + 13, 9, 9,14,13,13, 7, 7,14,13,13, 8, 8,15,14,14, + 10,10,15,14,14,10,10,15,14,14,10,10,15,14,14,10, + 10,15,14,14, 9, 9,15,14,14,10,10,15,14,14,10,10, + 14,14,14, 9, 9,15,14,14,10,10,14,14,14, 9, 9,15, + 14,14,10,10,15,14,14,10,10,14,14,14, 9, 9,14,14, + 14, 9, 9,14,14,14, 8, 8,15,14,14,10,10,15,14,14, + 11,11,15,14,14, 9, 9,15,14,14, 9, 9,14,14,14, 8, + 8,13, 9, 9,12,12,17,11,11,12,12,17,12,12,12,12, + 17,12,12,11,11,18,15,15,12,12,17,12,12,12,12,17, + 14,15,13,13,17,12,12,12,12,17,13,13,12,13,17,15, + 15,12,12,18,13,13,13,13,18,15,15,13,13,18,12,12, + 12,12,18,13,13,13,13,18,15,15,12,12,18,13,13,12, + 12,18,15,15,13,13,18,13,13,12,12,17,13,13,12,12, + 17,15,15,12,12,18,15,15,13,13,18,15,15,13,14,18, + 15,16,12,12,18,15,15,12,12,18,16,16,12,12,13, 8, + 8,10,10,14,15,14,11,11,14,15,15,12,12,15,14,14, + 12,11,15,15,15,12,12,15,15,15,12,12,15,15,15,13, + 13,15,15,15,12,12,15,15,15,13,13,15,15,15,13,13, + 15,15,15,13,13,15,15,16,13,13,15,15,15,12,12,15, + 15,15,13,13,15,15,15,13,13,15,15,15,13,13,15,15, + 15,13,13,15,15,14,12,12,15,15,15,12,12,16,15,14, + 12,12,16,15,15,13,13,16,16,16,13,13,16,15,15,12, + 12,15,15,15,13,13,15,15,15,12,12,13,12,12,10,10, + 14,14,14,11,11,15,14,14,12,12,15,14,14,11,11,15, + 14,14,11,11,15,15,15,13,13,15,14,14,13,13,15,15, + 15,12,12,15,14,15,13,13,16,15,15,12,12,15,15,15, + 13,13,16,14,14,13,13,15,15,15,12,12,15,15,15,13, + 13,16,15,15,12,12,16,15,15,12,12,16,14,14,13,13, + 15,15,15,11,11,15,15,15,12,12,16,15,15,11,11,16, + 15,15,13,13,16,14,15,14,14,16,15,15,12,12,16,15, + 14,12,12,16,15,15,12,12,14,10,10, 9, 9,14,11,11, + 12,12,14,12,12,13,13,14,12,12,12,12,15,14,14,13, + 13,15,13,13,14,14,15,14,14,15,15,15,12,12,13,13, + 15,13,13,14,14,15,14,14,13,13,15,13,13,13,14,15, + 14,14,15,15,15,12,12,13,13,15,13,13,14,14,15,14, + 14,13,13,15,13,13,14,14,15,14,14,15,15,15,13,13, + 12,12,15,13,13,13,13,15,14,14,13,12,15,15,15,14, + 15,15,15,14,20,20,15,14,14,13,13,15,14,14,13,13, + 15,14,14,13,13,14,12,12, 9, 9,14,14,14,12,12,14, + 13,13,12,13,14,14,14,12,12,15,14,14,12,12,15,14, + 14,14,13,15,14,14,14,14,15,14,14,13,13,15,14,14, + 13,13,15,15,15,14,14,15,14,14,13,13,15,14,14,14, + 14,15,14,14,13,13,15,14,14,13,13,15,15,15,15,14, + 15,15,15,13,13,15,14,14,14,14,15,14,14,13,13,15, + 14,14,13,13,14,15,15,14,14,15,15,15,14,14,15,14, + 14,14,14,15,15,15,14,14,15,14,14,13,14,15,15,15, + 14,14,13,10,10,12,12,17,11,11,12,12,17,12,12,12, + 12,17,12,12,11,11,17,15,15,12,11,18,13,13,13,13, + 18,15,15,13,13,17,12,12,12,12,18,13,13,13,13,17, + 15,15,12,12,17,12,12,12,12,17,15,15,13,13,17,12, + 12,12,12,17,13,13,12,12,17,15,15,12,12,18,14,13, + 12,12,18,15,15,13,13,18,13,13,12,12,18,13,13,12, + 12,18,16,16,12,12,18,16,16,12,12,18,15,15,13,13, + 18,16,16,12,12,17,15,15,12,12,17,16,16,12,12,13, + 8, 8,10,10,14,14,15,12,12,14,15,15,12,12,15,14, + 14,12,12,15,15,14,12,12,15,15,15,13,13,15,15,15, + 13,13,15,15,15,12,12,16,15,15,13,13,16,15,15,13, + 13,15,15,15,12,12,15,15,15,14,14,15,15,15,12,12, + 15,15,15,13,13,16,15,15,13,13,15,15,15,13,13,16, + 15,15,13,13,15,15,14,12,12,15,15,15,12,12,16,14, + 15,13,13,16,15,15,13,13,15,16,15,13,13,16,15,14, + 13,13,16,15,15,13,13,16,15,15,13,13,13,12,12,11, + 11,14,14,14,11,11,14,14,14,12,12,15,14,14,11,11, + 16,14,14,11,11,15,15,15,12,13,16,14,14,13,13,15, + 15,15,12,12,15,14,14,13,13,16,15,15,12,12,15,15, + 15,12,12,15,14,14,13,13,15,15,15,12,12,15,14,14, + 12,12,16,15,15,12,12,16,15,15,12,12,16,14,14,13, + 13,15,15,15,11,11,15,15,14,12,12,16,15,15,11,11, + 16,15,15,12,12,16,14,14,13,13,16,15,15,11,11,16, + 14,14,12,12,16,15,15,11,11,14,10,10, 9, 9,14,11, + 11,12,12,14,12,12,13,14,14,12,12,12,12,14,14,14, + 13,13,15,13,13,14,14,15,14,14,15,15,15,12,12,13, + 13,15,13,13,14,14,15,15,15,14,14,15,13,13,14,14, + 15,15,15,15,15,15,12,12,13,13,15,13,13,14,14,15, + 14,14,13,13,15,13,13,14,14,15,14,14,15,15,15,12, + 12,13,13,15,13,13,13,13,14,14,14,13,13,15,15,15, + 14,15,15,15,15,21,19,15,14,14,13,13,15,14,14,14, + 14,14,14,14,13,13,14,12,12, 9, 9,14,14,14,12,12, + 14,14,13,13,13,14,14,14,12,12,14,14,14,12,12,15, + 14,14,13,13,15,14,14,14,14,15,14,14,13,13,15,14, + 14,13,13,15,15,15,15,15,15,14,14,13,13,15,14,14, + 14,14,15,14,14,13,13,15,14,14,13,13,14,15,15,15, + 15,15,14,15,13,13,15,14,14,14,14,15,14,14,13,13, + 15,14,14,13,13,14,15,15,14,14,15,15,15,14,14,15, + 14,14,14,14,15,15,15,15,15,15,14,14,14,13,14,15, + 15,14,14,13,10,10,12,12,18,12,12,12,12,17,12,12, + 12,12,18,13,13,11,11,18,15,14,11,11,17,13,13,13, + 13,18,15,15,12,12,18,12,12,12,12,17,13,13,12,12, + 18,15,15,12,12,18,13,13,13,12,18,15,15,13,13,18, + 13,13,12,12,18,13,13,12,12,18,15,15,12,12,17,13, + 13,12,12,17,15,15,12,12,17,12,12,11,11,17,13,13, + 11,11,17,15,15,11,11,18,16,16,12,12,18,15,15,13, + 13,18,15,15,11,11,17,15,15,12,12,18,15,15,11,11, + 13, 8, 8,10,10,14,14,14,11,11,15,15,15,12,12,15, + 14,14,11,11,16,14,14,12,12,15,15,15,12,12,15,15, + 15,13,13,15,15,15,12,12,15,15,15,12,12,16,15,15, + 13,13,15,15,15,12,12,15,15,15,13,13,16,15,15,12, + 12,15,15,15,12,12,16,15,15,13,13,16,15,15,12,12, + 15,15,15,13,13,15,14,14,12,12,15,15,15,12,12,16, + 15,14,12,12,16,15,15,13,13,16,16,16,13,13,16,14, + 15,13,13,15,15,15,13,13,16,15,15,12,12,13,12,12, + 10,10,14,14,14,11,11,15,14,14,12,12,15,14,14,11, + 11,16,14,14,11,11,15,14,15,12,12,15,14,14,13,13, + 15,15,15,12,12,15,14,14,12,12,15,14,15,12,12,15, + 15,15,12,12,16,14,14,13,13,15,15,15,11,12,16,14, + 14,12,12,16,15,15,12,12,15,15,15,12,12,16,14,14, + 12,12,15,15,15,11,11,15,14,14,11,12,15,15,14,11, + 11,16,15,15,12,12,16,14,14,13,13,16,15,15,11,11, + 16,14,14,12,12,16,15,15,11,11,13,10,10, 8, 8,14, + 12,12,12,12,14,12,12,13,13,14,12,12,12,12,14,14, + 14,13,13,15,13,13,14,14,15,15,14,15,15,15,13,13, + 13,13,15,13,13,14,14,15,14,15,14,14,15,13,13,13, + 13,15,15,15,15,15,15,12,12,13,12,15,13,13,14,14, + 15,14,14,13,13,15,13,13,14,13,15,15,15,16,16,15, + 13,13,12,12,15,13,13,13,13,14,14,14,12,12,15,15, + 15,14,14,15,15,15,20,20,15,14,14,13,13,15,15,14, + 14,14,15,14,14,13,13,13,12,12, 9, 9,14,13,13,12, + 12,14,13,13,12,12,14,14,14,12,12,14,14,14,13,13, + 15,14,14,13,13,15,14,14,14,14,15,15,14,12,12,15, + 14,14,13,13,15,14,15,14,15,15,14,14,13,13,15,14, + 14,14,14,15,14,14,12,12,15,14,14,13,13,14,15,14, + 15,14,15,14,14,13,13,15,14,14,14,14,15,14,14,12, + 12,15,14,14,13,13,15,15,15,14,14,15,15,15,14,14, + 16,14,14,14,14,15,15,15,14,14,15,14,14,14,14,14, + 15,15,14,14,13,13,13,12,13,17,15,15,12,12,17,15, + 15,12,12,18,15,15,11,11,17,16,16,11,11,18,16,16, + 13,13,18,17,16,13,13,18,16,16,12,12,18,16,16,12, + 12,18,17,17,12,12,17,16,16,12,13,17,16,16,12,13, + 17,16,16,12,12,17,16,16,12,12,18,17,16,12,12,18, + 16,16,12,12,17,16,17,12,12,18,15,15,11,11,18,15, + 15,12,12,17,17,17,11,11,17,17,17,12,12,17,16,16, + 13,13,18,16,16,11,11,18,16,16,12,12,18,17,16,11, + 11,14,14,14,10,10,16,15,14,11,11,16,15,15,12,12, + 16,14,14,12,12,17,14,14,13,13,17,15,15,13,13,17, + 15,15,14,14,16,15,15,12,12,16,15,15,13,13,18,15, + 15,14,14,16,15,15,12,12,16,15,15,14,14,16,15,15, + 12,12,16,15,15,13,13,17,15,15,13,13,17,15,15,13, + 13,17,15,15,14,14,16,14,14,12,12,17,15,15,12,12, + 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,17, + 15,14,13,13,17,15,15,14,14,17,15,15,13,13,14,12, + 12,11,11,15,14,14,12,12,16,14,14,12,12,16,14,14, + 11,11,17,14,14,12,12,16,15,14,13,13,16,14,14,13, + 13,16,15,15,12,12,16,14,14,13,13,17,15,15,13,13, + 16,15,15,13,13,17,14,14,13,13,16,15,15,12,12,16, + 14,14,12,12,16,15,15,12,12,17,15,15,12,12,17,14, + 14,13,13,16,15,15,12,12,16,14,14,12,12,16,15,15, + 12,12,17,15,15,13,13,17,14,14,13,13,17,15,15,12, + 12,17,14,14,12,12,17,15,15,12,12,14,14,14, 8, 8, + 14,14,14,13,13,14,15,15,14,14,14,14,14,14,14,15, + 15,15,19,19,15,15,15,14,14,15,15,16,20,19,15,15, + 15,14,14,15,16,16,15,15,15,15,15,19,19,15,15,15, + 14,14,15,16,16,19,20,15,15,15,14,14,15,15,15,15, + 15,15,15,15,19,19,15,15,15,15,15,15,15,16,19,20, + 15,14,15,14,14,15,15,15,15,15,15,15,15,20,19,15, + 15,15,21,19,15,16,16,20,20,15,15,14,19,19,15,15, + 16,20,21,15,15,15,20,19,13,12,12, 9, 9,14,14,14, + 12,12,14,13,13,13,13,14,14,14,13,13,15,14,14,20, + 19,15,14,14,14,13,15,14,14,19,19,15,15,14,13,13, + 15,14,14,14,14,15,15,15,19,20,15,14,14,13,13,15, + 14,14,20,19,14,15,14,13,13,15,14,14,14,13,15,15, + 15,19,20,15,15,14,14,14,15,14,14,21,19,15,15,15, + 13,13,15,14,14,14,14,14,15,15,20,20,15,15,15,21, + 20,15,14,14,19,20,15,15,15,20,20,15,14,14,19,20, + 15,15,15,21,19, +}; + +static const static_codebook _44p2_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p2_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p2_p4_1, + 0 +}; + +static const long _vq_quantlist__44p2_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p2_p5_0[] = { + 2, 6, 6,14,14, 6, 7, 7,14,14, 7, 7, 7,15,15, 0, + 13,13,16,16, 0,13,13,15,15, 7, 8, 8,15,15, 9,10, + 10,17,16, 9, 8, 8,15,15, 0,13,13,18,17, 0,13,13, + 16,16, 8, 8, 8,15,15,12,11,11,16,17, 9, 8, 8,14, + 14, 0,13,13,18,17, 0,13,13,16,15, 0,14,14,18,17, + 0,20,22,18,20, 0,12,12,16,16, 0,16,16,22,20, 0, + 14,14,16,16, 0,14,14,17,17, 0,22,22,22,19, 0,12, + 13,16,16, 0,17,17, 0, 0, 0,15,15,16,16, 5, 7, 7, + 13,13, 9, 9, 9,15,14,10,10,10,14,14, 0,21,21,18, + 17, 0,21,22,18,17, 9,10,10,14,14,12,12,12,17,17, + 12,10,10,14,14, 0,19,21,18,17, 0,20,22,18,18,11, + 10,10,14,14,14,13,13,18,17,12,11,11,14,14, 0,22, + 19,17,18, 0,20, 0,18,17, 0,22,21,17,17, 0, 0, 0, + 0, 0, 0,20,22,17,17, 0,22, 0,21,19, 0,22, 0,18, + 18, 0, 0,22,18,19, 0, 0, 0, 0, 0, 0,19,21,17,17, + 0, 0, 0,20,20, 0, 0, 0,18,18, 6, 6, 6,13,12, 8, + 6, 6,11,11, 8, 6, 6,13,13, 0, 9, 9,11,11, 0,11, + 11,14,14, 9, 7, 7,13,13,11, 9, 9,13,13,10, 6, 6, + 13,13, 0,10,10,14,14, 0,10,10,13,13, 9, 7, 7,13, + 14,13, 9, 9,13,13,10, 6, 6,13,12, 0,11,11,15,15, + 0,10,10,13,13, 0,12,12,15,15, 0,19, 0,17,17, 0, + 9, 9,13,13, 0,13,14,19,20, 0,11,11,13,13, 0,11, + 11,14,14, 0,19,20,17,18, 0,10,10,13,13, 0,15,15, + 21,19, 0,12,12,13,13, 0,10,10,12,13, 0,11,11,15, + 15, 0,11,11,15,15, 0,15,15,22, 0, 0,16,17,22, 0, + 0,11,11,15,15, 0,14,14,18,17, 0,11,11,15,16, 0, + 15,15,22,21, 0,16,16, 0,20, 0,12,12,16,15, 0,15, + 14,19,19, 0,11,11,16,16, 0,15,15,21, 0, 0,16,15, + 0, 0, 0,16,16,22,21, 0, 0, 0, 0, 0, 0,15,15,20, + 20, 0,18,18, 0, 0, 0,16,17, 0, 0, 0,17,17, 0,22, + 0, 0, 0, 0, 0, 0,15,15,21,22, 0,20,18, 0, 0, 0, + 18,17,22, 0, 0,10,10,12,11, 0,10,10,10,10, 0,11, + 11,12,12, 0,11,11, 9, 9, 0,13,13,12,12, 0,11,11, + 12,12, 0,13,13,12,12, 0,10,10,12,12, 0,13,12,13, + 13, 0,12,12,12,12, 0,11,11,12,12, 0,13,13,12,12, + 0,10,10,12,12, 0,13,13,13,14, 0,12,12,12,12, 0, + 13,14,14,14, 0,20,21,15,15, 0,12,11,12,12, 0,15, + 16,20,22, 0,13,12,11,11, 0,13,13,14,13, 0,20, 0, + 16,15, 0,12,12,12,12, 0,16,16,22,21, 0,13,13,12, + 12, 6, 7, 7,16,16,11, 9, 9,15,15,12, 9, 9,16,16, + 0,13,13,14,14, 0,14,14,16,17,10, 9, 9,16,16,14, + 12,12,16,16,12, 9, 9,15,15, 0,13,13,18,18, 0,13, + 13,15,16,12,10,10,17,18,15,12,12,17,17,13, 9, 9, + 16,16, 0,13,13,17,18, 0,14,14,16,16, 0,15,15,18, + 18, 0,22, 0,20,20, 0,12,12,16,16, 0,16,16,20,22, + 0,14,14,16,16, 0,15,14,18,18, 0, 0,22,19,21, 0, + 13,13,16,17, 0,17,17,22,22, 0,15,15,16,16, 7, 7, + 7,14,14,11,10,10,15,15,12,10,10,15,14, 0,22, 0, + 18,18, 0, 0,21,17,18,11,10,10,15,15,14,12,12,17, + 17,14,11,11,15,15, 0,22,20,18,18, 0, 0,20,18,17, + 12,10,10,16,16,17,14,14,19,18,14,11,11,15,15, 0, + 21,22,19,19, 0,21,22,18,18, 0,22, 0,19,21, 0, 0, + 0, 0, 0, 0,22,22,18,17, 0, 0, 0,21,20, 0,22,22, + 20,19, 0, 0,22,20,20, 0, 0, 0, 0, 0, 0,20,21,17, + 17, 0, 0,22,21,21, 0, 0, 0,18,18,10, 9, 9,14,14, + 13,10,10,13,13,13,10,11,14,14, 0,13,13,12,12, 0, + 15,15,16,16,13,10,10,15,15,15,12,12,14,14,15,10, + 10,14,15, 0,14,14,16,15, 0,14,14,15,15,13,10,10, + 15,15,18,13,13,15,15,15,10,10,14,15, 0,14,14,16, + 16, 0,14,14,15,15, 0,15,15,16,16, 0,22, 0,18,18, + 0,12,13,14,14, 0,17,17,22, 0, 0,14,14,14,14, 0, + 15,15,16,16, 0,22, 0,18,17, 0,13,13,14,14, 0,19, + 18,21,22, 0,15,15,14,14, 0,11,11,13,13, 0,12,12, + 16,16, 0,12,12,16,16, 0,15,16,21, 0, 0,16,17, 0, + 22, 0,12,12,16,16, 0,14,14,17,18, 0,11,11,16,16, + 0,15,15,21,22, 0,16,16, 0, 0, 0,12,12,16,16, 0, + 15,15, 0,19, 0,12,12,16,17, 0,16,16,22, 0, 0,16, + 16, 0,22, 0,17,17, 0,22, 0, 0, 0, 0, 0, 0,15,15, + 20,19, 0,18,18, 0, 0, 0,17,18, 0, 0, 0,17,17, 0, + 0, 0, 0, 0, 0, 0, 0,15,15, 0,22, 0,20,18, 0, 0, + 0,18,18,22,22, 0,11,11,14,14, 0,12,12,14,14, 0, + 12,12,15,15, 0,13,13,14,14, 0,14,14,17,16, 0,12, + 12,16,16, 0,14,14,16,16, 0,11,11,15,15, 0,13,13, + 16,16, 0,13,13,15,15, 0,12,12,15,15, 0,15,14,16, + 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,15,15, + 0,15,15,17,17, 0, 0, 0,19,18, 0,13,12,15,15, 0, + 16,16, 0, 0, 0,14,14,15,15, 0,14,14,16,17, 0,22, + 0,18,18, 0,13,13,15,15, 0,17,17, 0, 0, 0,14,14, + 15,15, 8, 8, 8,16,16,12,10,10,16,16,13, 9, 9,16, + 16, 0,14,14,17,17, 0,14,14,17,16,12,10,10,18,17, + 14,11,11,18,18,14, 9,10,16,16, 0,13,13,18,19, 0, + 14,13,16,16,12, 9, 9,16,16,17,13,13,17,17,14, 9, + 9,15,15, 0,14,14,19,20, 0,13,13,15,15, 0,15,15, + 18,19, 0, 0,22,22,22, 0,13,13,17,17, 0,16,16,19, + 21, 0,14,14,16,16, 0,14,14,18,18, 0, 0, 0, 0, 0, + 0,13,13,16,16, 0,18,18, 0, 0, 0,15,15,16,16, 8, + 7, 7,14,14,12,10,10,15,15,13,10,10,15,14, 0,22, + 0,18,18, 0,22, 0,18,18,12,10,10,16,15,15,12,12, + 17,17,14,11,11,15,15, 0,20,21,19,18, 0, 0, 0,17, + 18,13,11,11,15,15,16,13,13,18,18,15,11,11,14,14, + 0,22,21,19,19, 0,21,22,18,18, 0,22,22,20,18, 0, + 0, 0, 0, 0, 0,22,19,17,17, 0, 0, 0,22,21, 0, 0, + 22,19,17, 0, 0,22,19,19, 0, 0, 0, 0, 0, 0,22,21, + 18,17, 0, 0, 0,22, 0, 0, 0, 0,19,19, 0,10,10,14, + 14, 0,11,11,15,14, 0,11,11,15,15, 0,14,14,15,14, + 0,15,15,16,16, 0,11,11,16,16, 0,13,13,16,16, 0, + 11,11,15,15, 0,14,14,17,16, 0,14,14,15,15, 0,11, + 11,16,16, 0,14,13,15,15, 0,11,11,15,15, 0,15,15, + 17,17, 0,14,14,15,14, 0,16,16,17,17, 0, 0,22,18, + 18, 0,13,13,15,15, 0,17,17,22, 0, 0,15,15,15,14, + 0,15,16,16,17, 0, 0,22,18,19, 0,13,13,15,15, 0, + 20,18,21, 0, 0,15,15,14,14, 0,11,11,13,13, 0,12, + 12,16,16, 0,12,12,16,15, 0,15,16,22,22, 0,17,17, + 0, 0, 0,12,12,16,16, 0,14,14,18,18, 0,11,11,16, + 16, 0,15,16,22,20, 0,16,16, 0,22, 0,12,12,16,16, + 0,15,15,18,20, 0,11,11,16,16, 0,15,15, 0, 0, 0, + 16,16, 0, 0, 0,17,17,22, 0, 0, 0, 0, 0, 0, 0,15, + 15, 0,21, 0,18,18, 0, 0, 0,17,16, 0, 0, 0,17,17, + 22,22, 0, 0, 0, 0, 0, 0,15,15,21, 0, 0,20,22, 0, + 0, 0,18,18, 0, 0, 0,12,12,15,15, 0,12,12,15,15, + 0,12,12,16,16, 0,13,13,15,15, 0,15,15,17,17, 0, + 13,12,16,16, 0,14,14,16,16, 0,12,11,16,16, 0,14, + 14,17,17, 0,14,14,16,16, 0,12,12,16,16, 0,15,15, + 17,16, 0,11,11,15,16, 0,14,14,17,17, 0,14,14,16, + 16, 0,15,15,18,18, 0, 0, 0,22,19, 0,13,13,15,16, + 0,16,17, 0, 0, 0,14,14,16,16, 0,15,15,18,17, 0, + 0, 0,20,20, 0,13,13,16,15, 0,17,17,22,22, 0,14, + 14,15,15, 0,11,11,16,16, 0,13,13,16,17, 0,13,13, + 17,18, 0,16,16,17,17, 0,17,17,18,18, 0,12,12,17, + 17, 0,16,15,18,18, 0,12,12,16,16, 0,16,16,18,18, + 0,15,15,17,17, 0,12,12,17,17, 0,16,16,19,18, 0, + 12,12,16,17, 0,16,16,19,19, 0,15,16,16,17, 0,16, + 16,19,17, 0, 0, 0,20,22, 0,13,13,16,16, 0,19,18, + 21, 0, 0,15,15,16,16, 0,16,16,18,18, 0, 0, 0,22, + 21, 0,14,14,16,16, 0,21,19,21,22, 0,16,16,16,16, + 0, 9, 9,14,14, 0,13,13,15,15, 0,14,14,15,15, 0, + 0,20,18,19, 0, 0,22,18,18, 0,12,12,15,15, 0,15, + 15,17,18, 0,14,13,14,14, 0,20, 0,18,18, 0,21, 0, + 18,17, 0,13,13,15,16, 0,17,17,18,18, 0,14,14,15, + 15, 0,22,22,20,19, 0,20,21,18,18, 0,20,22,19,19, + 0, 0, 0, 0, 0, 0,20,20,17,17, 0, 0,22,22,21, 0, + 22, 0,18,18, 0,20,22,19,19, 0, 0, 0, 0, 0, 0,21, + 21,17,18, 0, 0, 0,21,20, 0, 0,22,19,18, 0,18,18, + 15,15, 0,22,21,17,16, 0, 0,22,17,17, 0,20,22,18, + 18, 0, 0,22,20,20, 0,21,19,16,16, 0,21,21,18,18, + 0,19,19,17,17, 0, 0,22,19,19, 0,22,20,17,17, 0, + 21,19,16,16, 0,22,22,19,18, 0,19,20,16,16, 0,22, + 21,19,21, 0,21,22,17,18, 0,21,20,18,18, 0, 0, 0, + 19,20, 0,20,19,16,16, 0,22,22, 0, 0, 0,21,21,17, + 16, 0,22,20,19,18, 0, 0, 0,20,20, 0,20,19,16,16, + 0, 0, 0, 0, 0, 0,21,22,17,17, 0,11,11,13,13, 0, + 13,13,15,16, 0,13,13,16,16, 0,17,18,21, 0, 0,17, + 18, 0, 0, 0,12,12,15,16, 0,15,15,19,18, 0,12,12, + 16,16, 0,17,17,22, 0, 0,17,17, 0,22, 0,12,12,17, + 16, 0,16,16,19,20, 0,12,12,16,16, 0,17,17, 0, 0, + 0,17,17, 0,21, 0,17,16,22, 0, 0, 0, 0, 0, 0, 0, + 15,15,20,22, 0,20,18, 0, 0, 0,18,18, 0, 0, 0,17, + 17,21, 0, 0, 0, 0, 0, 0, 0,15,15,21,22, 0,19,20, + 22, 0, 0,19,18, 0, 0, 0,14,14,18,18, 0,16,16,22, + 20, 0,16,16,22,19, 0,17,17,20,22, 0,19,19, 0, 0, + 0,15,15,20, 0, 0,18,21, 0,20, 0,15,15,21,20, 0, + 18,17, 0, 0, 0,17,17, 0,22, 0,15,15,19,19, 0,19, + 18, 0, 0, 0,15,15,20, 0, 0,18,18,22,22, 0,17,17, + 0,20, 0,18,18, 0, 0, 0, 0,22, 0, 0, 0,15,15,19, + 20, 0,20,19, 0, 0, 0,17,17,20,21, 0,17,18,20,22, + 0, 0, 0, 0,22, 0,15,15,20,20, 0,22,20, 0, 0, 0, + 17,18,20, 0, 0,12,12,17,16, 0,14,14,17,17, 0,13, + 13,17,17, 0,16,16,18,18, 0,17,16,17,17, 0,13,13, + 17,17, 0,15,16,18,18, 0,13,13,16,16, 0,16,16,18, + 18, 0,16,16,17,16, 0,13,13,16,16, 0,17,17,18,17, + 0,12,12,15,16, 0,17,17,19,19, 0,16,16,16,16, 0, + 16,17,19,18, 0, 0, 0,21,22, 0,14,14,16,16, 0,18, + 18, 0,22, 0,16,16,16,16, 0,16,16,18,17, 0, 0, 0, + 21,20, 0,14,14,16,16, 0,21,22,22, 0, 0,16,16,16, + 16, 0, 9, 9,14,13, 0,13,14,15,16, 0,14,13,15,14, + 0,22, 0,18,18, 0,21, 0,17,18, 0,13,13,15,15, 0, + 15,16,18,17, 0,14,14,15,14, 0,20,22,18,18, 0,22, + 21,17,17, 0,13,13,15,15, 0,17,17,19,19, 0,14,14, + 14,14, 0, 0,22,18,18, 0, 0,22,17,17, 0, 0,22,19, + 20, 0, 0, 0, 0, 0, 0,21,20,17,16, 0, 0, 0,21,22, + 0, 0, 0,18,19, 0, 0, 0,18,18, 0, 0, 0, 0, 0, 0, + 22, 0,17,17, 0, 0, 0,20,22, 0, 0, 0,18,19, 0,18, + 19,16,16, 0,22,20,17,17, 0,22,22,17,18, 0,22,22, + 18,17, 0, 0,22,18,19, 0,20,20,17,18, 0, 0,22,19, + 18, 0,22,22,17,17, 0,22, 0,19,19, 0, 0,22,18,18, + 0,20,22,17,17, 0, 0,22,18,18, 0,19,20,17,17, 0, + 22, 0,20,19, 0,22,21,17,17, 0, 0, 0,18,18, 0, 0, + 0,22,19, 0,20, 0,17,17, 0,22, 0, 0,22, 0, 0,20, + 17,18, 0,22, 0,19,19, 0, 0, 0, 0,19, 0,19,21,17, + 17, 0, 0, 0, 0, 0, 0,20,21,17,16, 0,11,11,13,13, + 0,13,13,16,16, 0,13,13,15,16, 0,17,17,21,22, 0, + 17,18, 0, 0, 0,12,12,16,16, 0,15,15,18,18, 0,13, + 13,16,16, 0,17,16,21,21, 0,17,17, 0, 0, 0,13,13, + 16,16, 0,16,16,19,18, 0,13,13,16,16, 0,17,17, 0, + 22, 0,17,18,20,22, 0,17,18, 0, 0, 0, 0, 0, 0, 0, + 0,15,15,20, 0, 0,18,19, 0, 0, 0,17,17, 0, 0, 0, + 18,17,22, 0, 0, 0, 0, 0, 0, 0,15,16,21,20, 0,20, + 20, 0, 0, 0,18,19, 0, 0, 0,15,15,22,22, 0,17,16, + 20,22, 0,17,17,20,22, 0,18,18, 0,21, 0,19,18, 0, + 0, 0,16,16,20,20, 0,19,19,22, 0, 0,15,16,21,22, + 0,18,19,22, 0, 0,17,18, 0, 0, 0,16,16,22, 0, 0, + 19,19, 0,21, 0,15,16,20, 0, 0,18,18, 0,22, 0,18, + 17, 0, 0, 0,18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, + 22,21, 0,20,21, 0, 0, 0,17,18,22, 0, 0,18,18, 0, + 0, 0, 0, 0, 0, 0, 0,16,16,20,19, 0,22,21, 0, 0, + 0,18,18,22,22, +}; + +static const static_codebook _44p2_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p2_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p2_p5_0, + 0 +}; + +static const long _vq_quantlist__44p2_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p2_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p2_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p2_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p2_p5_1, + 0 +}; + +static const long _vq_quantlist__44p2_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p6_0[] = { + 1, 7, 7, 7, 8, 8, 7, 8, 8, 7, 9, 9,10,11,11, 9, + 8, 8, 7, 8, 9,11,11,11, 9, 8, 8, 6, 7, 7,10,10, + 10,10,10,10,10,10,10,14,14,14,12,11,11,10,11,11, + 15,14,14,13,11,11, 6, 6, 6, 8, 5, 5, 8, 7, 7, 8, + 7, 7,11,10,10, 9, 7, 7, 9, 7, 7,12,10,10,10, 7, + 7, 6, 8, 7,12,10,10,12,10,10,11,10,10,15,14,13, + 13,10,10,11,10,10,16,14,14,14,10,10, 7, 7, 7,12, + 11,11,12,11,11,11,11,11,16,14,14,13,12,12,11,11, + 11,17,15,15,14,12,12,10, 9, 9,13,11,11,13,11,11, + 12,11,11,16,14,13,14,11,11,12,11,11,17,15,14,14, + 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,16,13, + 14,13,10,10,11,10,10,17,14,14,14,10,10, 7, 7, 7, + 12,11,11,12,11,11,12,11,11,15,14,15,14,12,12,12, + 11,11,17,15,15,14,12,12,10,10, 9,13,11,11,13,11, + 11,13,11,11,16,14,14,14,11,11,13,11,11,16,15,15, + 15,11,11, +}; + +static const static_codebook _44p2_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p2_p6_0, + 0 +}; + +static const long _vq_quantlist__44p2_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p6_1[] = { + 2, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 8, + 7, 7, 8, 8, 8, 9, 9, 9, 9, 8, 8, 6, 7, 7, 9, 8, + 8, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8, + 10, 8, 9,10, 8, 8, 7, 6, 6, 8, 6, 6, 9, 6, 6, 9, + 7, 7,10, 8, 8, 9, 6, 6, 9, 7, 7,10, 9, 8, 9, 7, + 7, 7, 7, 7,11, 8, 8,11, 9, 9,10, 9, 9,12, 9, 9, + 12, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7,10, + 9, 9,10, 9, 9,10, 9, 9,11,10,11,11, 9, 9,11, 9, + 9,11,11,11,11, 9, 9,10, 8, 8,11, 9, 9,10, 9, 9, + 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,12,10,10,11, + 9, 9, 8, 8, 8,11, 9, 9,12, 9, 9,11, 9, 9,12, 9, + 9,12, 8, 8,12, 9, 9,12, 9,10,12, 8, 8, 9, 7, 7, + 11, 9, 9,11,10,10,11, 9, 9,11,11,11,11, 9, 9,11, + 10,10,12,11,11,11, 9,10,10, 9, 9,11, 9, 9,11,10, + 10,11,10,10,11,11,11,11, 9, 9,11, 9,10,11,11,11, + 11, 9, 9, +}; + +static const static_codebook _44p2_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p2_p6_1, + 0 +}; + +static const long _vq_quantlist__44p2_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 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, +}; + +static const static_codebook _44p2_p7_0 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p7_0, + 1, -513979392, 1633504256, 2, 0, + (long *)_vq_quantlist__44p2_p7_0, + 0 +}; + +static const long _vq_quantlist__44p2_p7_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p2_p7_1[] = { + 1, 9, 9, 6, 9, 9, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10, +}; + +static const static_codebook _44p2_p7_1 = { + 5, 243, + (char *)_vq_lengthlist__44p2_p7_1, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p2_p7_1, + 0 +}; + +static const long _vq_quantlist__44p2_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p2_p7_2[] = { + 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _44p2_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p2_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p2_p7_2, + 0 +}; + +static const long _vq_quantlist__44p2_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p2_p7_3[] = { + 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44p2_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p2_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p2_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p2_short[] = { + 4, 4,12, 9, 8,12,15,17, 4, 2,11, 6, 5, 9,13,15, + 11, 7, 8, 7, 7,10,14,13, 8, 5, 7, 5, 5, 8,12,12, + 8, 4, 7, 4, 3, 6,11,12,11, 8, 9, 7, 6, 8,11,12, + 15,13,14,12, 9, 7,10,13,16,12,17,12, 7, 5, 8,11, +}; + +static const static_codebook _huff_book__44p2_short = { + 2, 64, + (char *)_huff_lengthlist__44p2_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p3_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p3_l0_0[] = { + 1, 4, 4, 8, 8, 8, 8, 9, 9,10,10,10,10, 4, 6, 5, + 8, 7, 9, 9, 9, 9,10, 9,11, 9, 4, 5, 6, 7, 8, 9, + 9, 9, 9, 9,10, 9,10, 8, 9, 8, 9, 8,10, 9,11, 9, + 12,10,12,10, 8, 8, 9, 8, 9, 9,10, 9,11,10,12,10, + 12, 9,10,10,11,10,12,11,12,11,12,12,12,12, 9,10, + 10,11,11,11,11,11,12,12,12,12,12,10,11,11,12,12, + 12,12,12,12,12,12,12,12,10,11,11,12,12,12,12,12, + 12,12,12,12,12,11,12,12,12,12,12,13,12,13,12,13, + 12,12,11,12,12,12,12,12,12,13,12,12,12,12,12,12, + 12,12,13,13,12,13,12,13,12,13,12,12,12,13,12,13, + 12,13,12,13,12,13,12,12,12, +}; + +static const static_codebook _44p3_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p3_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p3_l0_0, + 0 +}; + +static const long _vq_quantlist__44p3_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p3_l0_1[] = { + 3, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5, + 5, 6, 5, 6, 5, 6, 5, 6, 5, +}; + +static const static_codebook _44p3_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p3_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p3_l0_1, + 0 +}; + +static const long _vq_quantlist__44p3_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_l1_0[] = { + 1, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const static_codebook _44p3_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44p3_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p3_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p3_lfe[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book__44p3_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p3_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p3_long[] = { + 3, 4,13, 9, 9,12,15,17, 4, 2,18, 5, 7,10,14,18, + 11, 8, 6, 5, 6, 8,11,14, 8, 5, 5, 3, 5, 8,11,13, + 9, 6, 7, 5, 5, 7, 9,10,11,10, 9, 8, 6, 6, 8,10, + 14,14,11,11, 9, 8, 9,10,17,17,14,13,10, 9,10,10, +}; + +static const static_codebook _huff_book__44p3_long = { + 2, 64, + (char *)_huff_lengthlist__44p3_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p3_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p1_0[] = { + 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p3_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p3_p1_0, + 0 +}; + +static const long _vq_quantlist__44p3_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p3_p2_0[] = { + 3, 7, 7, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0, + 11,11, 0, 0, 0, 0, 0, 0, 0, 0,10, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0,10,11, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0, + 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,12,12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, + 5, 5, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0, 9, 9, 0, + 0, 0,10,10, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, + 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 0,11,12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, + 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, 0, + 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 7, 7, + 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, + 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, + 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 7, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,11,11, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 7, + 7, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 9, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,10,10, 0, 0, 0, 9, 9, 0, 0, 0,10,10, + 0, 0, 0,11,12, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,11,11, 0, 0, + 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,11, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,12,12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, + 9, 9, 0, 0, 0,10,10, 0, 0, 0,12,12, 0, 0, 0, 0, + 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, + 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, + 0, 0, 0, 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 10,10, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, +}; + +static const static_codebook _44p3_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p3_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p3_p2_0, + 0 +}; + +static const long _vq_quantlist__44p3_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p3_0[] = { + 1, 5, 5, 5, 8, 8, 0, 8, 8, 6, 9, 9, 8,10,10, 0, + 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 4, 7, 7, 6,10, + 10, 0,12,12, 7,11,11, 9,12,12, 0,12,12, 0,13,13, + 0,15,15, 0,12,12, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0, + 8, 8, 0,10,10, 0, 7, 7, 0, 8, 8, 0,11,11, 0, 7, + 7, 5, 7, 7, 9, 9, 9, 0,11,10, 9, 9, 9,11,12,12, + 0,10,10, 0,11,11, 0,13,13, 0,11,11, 6, 7, 7, 9, + 10,10, 0,12,12,10,11,11,11,12,12, 0,12,12, 0,13, + 13, 0,15,15, 0,12,12, 0,10,10, 0,11,11, 0,11,11, + 0,12,12, 0,13,13, 0,11,11, 0,12,12, 0,15,15, 0, + 11,11, 0, 8, 8, 0,10,10, 0,12,12, 0,11,11, 0,12, + 12, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0, 7, 7, + 0,10,10, 0,12,12, 0,10,10, 0,12,13, 0,12,12, 0, + 13,13, 0,14,14, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p3_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p3_p3_0, + 0 +}; + +static const long _vq_quantlist__44p3_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p3_1[] = { + 3, 4, 4, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0,10,10, 0, + 8, 8, 0, 9, 9, 0,10,10, 0, 8, 8, 0, 7, 7, 0, 8, + 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, + 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 6, 6, 0, 7, 7, 0, + 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,10,10, 0, 6, + 5, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 9, 9, + 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 6, 6, 0, + 9,10, 0,10,10, 0,10,10, 0,11,11, 0, 9, 9, 0,10, + 10, 0,11,11, 0, 9, 9, 0, 8, 8, 0, 8, 8, 0, 8, 8, + 0, 9, 9, 0, 9, 9, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0, + 7, 7, 0, 8, 8, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0, 9, + 9, 0, 7, 7, 0, 7, 7, 0, 9, 9, 0, 6, 6, 0, 6, 6, + 0,10,10, 0,10,10, 0,10,10, 0,12,12, 0, 9, 9, 0, + 10,10, 0,12,12, 0, 9, 9, 0, 8, 8, 0, 7, 7, 0, 8, + 8, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9, + 0, 7, 7, +}; + +static const static_codebook _44p3_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p3_p3_1, + 0 +}; + +static const long _vq_quantlist__44p3_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p4_0[] = { + 1, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8,10,11,11, 9, + 8, 8, 8, 8, 8,11,11,11,10, 8, 8, 5, 7, 7, 9,11, + 11,10,11,11,10,11,11,12,13,14,11,12,12,10,11,11, + 13,14,14,12,12,12, 5, 6, 6, 8, 6, 6, 8, 7, 7, 8, + 7, 7,11,10,10,10, 7, 7, 9, 7, 7,12,11,11,11, 7, + 7, 7, 7, 7,11,10,10,12,10,10,11,10,10,15,13,13, + 13,10,10,12,11,11,15,13,13,14,11,11, 7, 7, 7,11, + 11,11,12,11,11,12,11,11,14,14,14,14,12,12,12,12, + 12,16,15,15,14,12,12, 0,10,10, 0,11,11, 0,11,12, + 0,11,11, 0,14,14, 0,11,11, 0,12,12, 0,15,15, 0, + 11,11, 8, 8, 8,12,10,10,12,10,10,13,11,11,15,13, + 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7, + 12,11,11,13,11,11,12,11,11,15,14,14,14,12,12,13, + 12,12,15,14,14,15,12,12, 0,11,11, 0,12,12, 0,12, + 12, 0,12,12, 0,15,15, 0,12,12, 0,13,13, 0,14,15, + 0,12,12, +}; + +static const static_codebook _44p3_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p3_p4_0, + 0 +}; + +static const long _vq_quantlist__44p3_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p3_p4_1[] = { + 3, 4, 5, 8, 8,12,10,10,12,12,12,10,10,12,12,13, + 11,11,12,12,13,12,12,12,12,13,10,10,13,13,13,13, + 13,13,13,13,10,10,13,13,13,11,11,13,13,14,13,13, + 12,12,13,10,10,13,13,13,13,13,13,13,13,10,10,12, + 12,13,11,11,13,13,13,13,13,12,12,13,12,12,13,13, + 13,13,13,13,13,14,11,11,12,12,14,12,12,13,12,14, + 14,14,12,12,13,14,14,13,13,14,13,13,13,13,14,14, + 14,12,12,14,13,13,13,13,14,14,14,12,12,12, 8, 8, + 11,11,12,12,12,11,11,12,11,11,10,10,13,12,12,10, + 10,13,12,12,10,10,13,12,12,12,12,14,12,12,12,12, + 13,13,13,11,11,14,12,12,11,11,14,12,12,12,12,14, + 12,12,12,12,13,12,12,12,12,13,13,13,11,11,14,12, + 12,11,11,14,12,12,12,12,14,13,13,12,12,14,12,12, + 12,11,14,13,13,11,11,14,13,12,11,11,14,13,13,11, + 11,14,13,13,12,12,14,12,12,12,12,15,13,13,12,12, + 14,12,12,11,11,14,13,13,11,11,12, 9, 9,10,10,12, + 7, 7,11,11,12, 9, 9,12,12,13,10,10,10,10,14,14, + 14,11,11,13, 9, 9,12,12,14,14,14,12,12,13, 8, 8, + 11,11,14, 9, 9,12,12,14,14,14,11,11,13, 9, 9,12, + 12,14,14,14,12,12,14, 8, 8,11,11,14, 9, 9,12,12, + 14,14,14,11,11,14,10,10,12,12,14,14,14,13,13,14, + 9, 9,11,11,14,10,10,12,12,14,14,14,11,11,14,14, + 15,12,12,15,14,14,14,14,15,14,14,11,11,14,14,14, + 12,12,14,14,14,11,11,14,11,11,10,10,14,10,10,10, + 10,14,10,10,10,10,15,11,11, 9, 9,14,12,12, 9, 9, + 15,11,11,11,11,15,13,13,11,11,15,10,10,10,10,15, + 11,11,10,10,15,13,13,11,11,15,11,11,11,11,15,13, + 13,11,11,15,10,10,10,10,15,11,11,10,10,15,13,13, + 11,11,15,12,12,11,11,15,13,13,11,11,15,11,11,10, + 10,15,12,12,10,10,15,13,13,10,10,15,14,14,11,11, + 15,13,13,11,11,15,14,14,10,11,15,13,13,10,10,15, + 13,14,10,10,14,13,13,10,10,14,13,13,10,10,14,13, + 13,10,10,14,13,13, 9, 9,14,14,14, 9, 9,15,14,14, + 11,11,15,14,14,10,10,15,14,14,10,10,15,14,14,11, + 11,15,14,14,10,10,15,14,14,11,11,15,14,14,10,10, + 14,14,14,10,10,15,14,14,10,10,14,14,14,10,10,15, + 14,14,11,11,15,14,14,11,11,14,14,14,10,10,15,14, + 14,10,10,14,14,14, 9, 9,15,15,15,11,11,15,14,14, + 12,12,15,15,14,10,10,15,14,14,10,10,14,15,15, 9, + 9,14,10,10,12,12,17, 9, 9,12,12,17,10,10,13,13, + 17,11,11,12,12,18,14,14,12,12,17,10,10,13,13,17, + 14,14,12,12,17, 9, 9,12,12,17,11,11,12,12,17,14, + 14,12,12,18,10,10,13,13,18,14,14,13,13,18, 9, 9, + 12,12,18,10,10,13,13,18,14,14,12,12,18,11,11,13, + 13,18,14,14,13,13,18,10,10,12,12,17,11,11,12,12, + 17,14,14,12,12,18,15,15,13,13,18,14,14,14,14,18, + 15,15,12,12,18,14,14,12,12,18,15,15,12,12,13, 7, + 7,11,11,14,15,15,11,11,14,15,15,12,12,14,15,15, + 11,11,15,15,15,11,11,14,15,15,12,12,14,15,15,12, + 12,14,15,15,11,11,14,15,15,11,11,15,15,15,12,12, + 14,15,15,12,12,14,15,15,12,12,14,15,15,11,11,14, + 15,15,11,11,15,15,15,12,12,15,15,15,12,12,14,15, + 15,12,12,14,15,14,12,12,14,15,15,11,11,15,14,14, + 12,12,15,15,15,12,12,15,16,16,12,12,15,15,15,12, + 12,15,15,15,12,12,15,15,15,12,12,13,13,13,11,10, + 14,14,15,11,11,14,14,14,12,12,15,14,14,10,10,15, + 15,15,11,11,14,15,15,12,12,14,14,14,11,11,14,15, + 15,11,11,14,15,15,12,12,15,15,15,11,11,14,15,15, + 12,12,14,14,14,12,12,14,15,15,11,11,14,15,15,12, + 12,15,15,15,11,11,15,15,15,12,12,15,14,14,12,12, + 14,15,15,11,11,14,15,15,11,11,15,15,15,10,10,15, + 15,16,12,12,15,15,15,14,14,15,15,15,11,11,15,15, + 15,12,12,15,15,15,11,11,14,11,11,10,10,15, 9, 9, + 12,12,15,10,10,12,12,15,11,11,11,11,15,14,14,12, + 12,15,10,10,13,13,15,14,14,12,12,15, 9, 9,12,12, + 15,10,10,13,13,15,13,13,12,11,15,10,10,12,12,15, + 14,14,12,12,15, 9, 9,11,11,15,11,11,12,12,15,13, + 13,11,11,15,11,11,13,13,15,13,14,13,14,15,11,11, + 11,11,15,11,11,12,12,15,14,14,11,11,15,14,14,13, + 13,15,14,14,20,20,15,14,14,12,12,15,14,14,12,12, + 15,14,14,11,11,14,13,13,10,10,14,13,13,12,12,14, + 14,13,12,12,15,14,14,12,12,15,14,14,11,11,15,14, + 14,12,12,15,14,14,13,13,15,14,14,12,11,15,14,14, + 11,11,15,14,14,13,13,15,14,14,12,12,15,14,14,13, + 13,15,14,14,12,11,15,14,14,12,12,15,14,14,13,13, + 15,14,14,13,13,15,14,14,12,12,15,14,14,12,12,15, + 14,14,12,12,15,15,15,13,13,15,15,15,13,13,15,14, + 14,13,13,15,15,15,13,13,15,14,15,12,12,15,15,15, + 13,13,14,10,10,12,13,17, 9, 9,12,12,17,10,10,13, + 13,17,11,11,12,12,18,14,14,12,12,18,10,10,13,13, + 18,14,14,12,12,17, 9, 9,12,12,18,10,11,13,13,18, + 14,14,12,12,17,10,10,12,12,17,14,14,12,12,17, 9, + 9,12,12,17,11,11,12,12,17,14,14,12,12,18,11,11, + 12,12,18,14,14,13,13,18,11,11,12,12,18,11,11,12, + 12,18,14,14,12,12,18,15,15,12,12,18,14,14,13,13, + 18,15,15,12,12,17,14,14,12,12,17,15,15,12,12,13, + 7, 7,11,11,14,15,15,11,11,14,15,15,11,11,14,15, + 14,12,12,15,15,15,12,11,14,15,15,12,12,14,15,15, + 12,12,14,15,15,11,11,14,15,15,11,11,15,15,15,13, + 13,14,15,15,11,11,14,15,15,13,12,14,15,15,11,11, + 14,15,15,11,11,15,15,15,13,13,14,15,15,12,12,15, + 15,15,12,12,15,15,15,11,11,15,15,15,11,11,15,15, + 15,12,12,15,15,15,13,13,15,16,16,12,12,15,15,15, + 12,13,15,15,15,12,12,15,15,15,12,12,13,13,13,11, + 11,14,14,14,11,11,14,14,14,12,12,14,14,14,10,10, + 15,14,14,11,11,14,15,15,12,12,14,14,14,12,12,14, + 15,15,11,11,14,15,14,12,12,15,14,14,11,11,14,15, + 15,12,12,14,14,14,11,11,14,15,15,11,11,14,14,14, + 12,12,15,15,14,11,11,15,15,15,12,12,15,14,14,12, + 12,14,15,15,11,11,14,15,14,11,11,15,15,15,10,10, + 15,15,15,12,12,15,14,14,14,13,15,15,15,11,11,15, + 15,15,11,11,15,15,15,10,10,14,11,11,10,10,15, 9, + 9,12,12,15,10,10,12,12,15,11,11,11,11,15,14,14, + 12,12,15,10,10,13,13,15,13,13,12,12,15, 9, 9,12, + 12,15,11,11,13,13,15,14,14,12,12,15,10,10,13,13, + 15,13,14,12,12,15, 9, 9,12,12,15,10,10,13,13,15, + 13,13,11,11,15,11,11,13,13,15,14,14,13,13,15,10, + 10,11,11,15,11,11,12,12,15,14,14,11,11,15,14,14, + 13,13,15,14,14,21,20,15,14,14,11,11,15,14,14,12, + 12,15,14,14,11,11,14,13,13,10,10,14,13,13,11,11, + 15,14,14,12,12,15,14,14,12,12,14,14,14,12,12,15, + 14,14,12,12,15,14,14,13,13,14,14,14,11,11,15,14, + 14,11,11,15,14,14,13,13,15,14,14,12,12,15,14,14, + 13,13,14,14,14,11,11,15,14,14,11,11,14,14,14,13, + 13,15,14,14,12,12,15,14,14,12,12,15,14,14,12,12, + 15,14,14,12,12,14,14,14,13,13,15,15,15,13,13,16, + 14,14,12,13,15,15,15,13,13,15,14,14,12,12,15,15, + 15,13,13,15,11,11,13,12,18,10,10,12,12,17,11,11, + 12,12,18,12,12,11,11,18,14,14,12,12,18,11,11,13, + 13,17,14,14,12,12,18,10,10,12,12,18,12,12,12,12, + 18,14,15,12,12,18,11,11,13,13,18,14,14,12,12,17, + 10,10,12,12,18,11,11,12,12,18,15,14,12,12,17,12, + 12,12,12,17,14,14,12,12,17,11,11,11,11,17,12,12, + 12,11,17,15,15,11,11,18,15,15,12,12,18,14,15,13, + 13,18,15,15,11,11,17,15,15,12,12,18,15,15,11,11, + 14, 9, 9,11,11,14,15,15,11,11,15,15,15,11,11,15, + 15,15,12,11,15,15,15,12,12,15,15,15,11,11,15,15, + 15,13,13,14,15,15,11,11,15,15,15,11,11,15,15,15, + 13,13,15,15,15,11,11,15,15,15,13,13,15,15,15,11, + 11,15,15,15,11,11,15,15,15,13,13,15,15,15,12,12, + 15,15,15,13,13,15,15,14,11,11,15,15,15,12,12,15, + 15,15,12,12,16,15,15,13,13,15,16,16,13,13,16,15, + 15,12,12,15,15,15,13,12,15,15,15,12,12,13,12,12, + 11,11,14,14,14,11,11,14,14,14,12,12,15,14,14,11, + 11,15,14,14,12,12,15,14,14,12,12,15,14,14,12,12, + 14,15,15,11,11,15,14,14,12,12,15,14,14,11,11,15, + 14,14,12,12,15,14,14,12,12,14,15,15,11,11,15,14, + 14,12,12,15,14,14,11,11,15,15,15,12,12,15,14,14, + 12,12,15,15,15,11,11,15,14,14,11,11,15,14,15,11, + 11,15,15,15,12,12,15,14,14,13,13,16,15,15,11,11, + 15,14,14,12,12,15,15,15,11,11,14,11,11, 9, 9,15, + 10,10,12,12,14,11,11,12,12,15,12,12,12,12,15,14, + 14,13,13,15,11,11,13,13,15,14,14,13,13,15,10,10, + 12,12,15,12,12,13,13,15,14,14,13,13,15,11,11,12, + 12,15,14,14,13,13,14,10,10,12,12,15,12,12,13,13, + 15,14,14,12,12,15,12,12,13,13,15,14,14,15,15,15, + 11,11,12,12,15,12,12,12,13,15,14,14,12,12,15,15, + 15,14,14,15,14,14,20,20,15,14,14,12,12,15,14,14, + 13,13,15,14,14,12,12,14,13,13,10,10,14,13,13,11, + 11,14,13,13,12,12,14,14,14,12,12,15,14,14,13,13, + 15,14,14,12,12,14,14,14,14,14,14,14,14,11,11,15, + 14,14,12,12,15,14,14,14,14,15,14,14,12,12,14,14, + 14,14,14,14,14,14,11,11,15,14,14,12,12,14,14,14, + 14,14,15,14,14,12,12,15,14,14,13,13,15,14,14,12, + 12,15,14,14,12,12,14,14,14,14,13,15,15,15,14,14, + 15,14,14,13,13,15,15,15,14,14,15,14,14,13,13,15, + 15,15,13,13,14,13,13,13,13,18,15,15,12,12,18,15, + 15,13,12,18,15,16,11,11,18,16,17,12,12,18,15,15, + 13,13,18,17,17,12,12,18,15,15,12,12,17,15,15,12, + 12,18,17,17,12,12,18,15,15,13,13,18,16,17,12,12, + 17,15,15,12,12,18,15,15,12,12,18,16,17,11,12,18, + 16,16,12,12,17,16,17,12,12,18,15,15,11,11,18,15, + 15,12,12,18,17,17,11,11,17,17,17,12,12,18,16,16, + 13,13,18,17,17,11,11,18,16,16,12,12,18,17,17,11, + 11,15,14,14,11,11,16,15,15,11,11,16,15,15,12,12, + 16,15,15,12,12,17,15,15,14,13,16,15,15,12,12,17, + 15,15,14,14,16,15,15,11,11,16,15,15,12,12,18,15, + 15,13,13,16,15,15,11,11,17,15,15,14,14,16,15,15, + 11,11,16,15,15,12,12,17,15,15,13,13,16,15,15,12, + 12,17,16,15,14,14,16,14,15,12,12,16,15,15,12,12, + 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,17, + 15,15,13,13,17,15,15,14,14,18,15,15,13,13,15,12, + 13,11,11,15,14,14,12,12,16,14,14,12,12,16,14,14, + 12,12,16,14,14,12,12,16,14,14,13,12,17,14,14,13, + 13,16,15,15,12,12,16,14,14,12,12,17,14,14,12,12, + 16,14,14,12,12,17,14,14,13,13,15,15,15,12,12,16, + 14,14,12,12,17,14,14,12,12,17,15,15,12,12,17,14, + 14,13,13,16,15,15,12,12,16,14,14,12,12,17,15,15, + 12,12,18,15,15,13,13,17,14,14,13,13,17,15,15,12, + 12,17,14,14,12,12,17,15,15,12,12,14,15,15, 9, 9, + 15,15,15,12,12,15,15,15,13,13,15,15,15,14,14,15, + 15,15,19,19,15,15,16,13,13,15,15,16,19,20,15,15, + 15,13,12,15,16,16,14,14,15,15,15,19,19,15,15,15, + 13,13,15,16,15,20,19,14,15,15,13,13,15,15,15,14, + 14,15,15,15,19,19,15,15,15,14,14,15,16,16,19,20, + 15,15,15,14,14,15,15,15,14,14,15,15,15,19,19,15, + 15,15,20,19,15,16,16,20,19,15,15,15,19,19,15,16, + 16,20,20,15,15,15,19,20,14,13,13,10,10,14,14,14, + 11,11,14,14,14,12,12,15,14,14,13,13,15,14,14,19, + 20,15,14,14,12,12,14,14,14,20,19,14,14,14,11,11, + 15,14,14,12,12,15,14,14,20,20,15,14,14,12,12,14, + 14,14,20,19,14,14,14,11,11,15,14,14,12,12,15,14, + 14,19,20,15,14,14,13,13,15,14,14,22,19,15,15,14, + 12,12,15,14,14,13,13,14,15,15,22,20,15,15,15,20, + 20,15,14,14,21,20,15,15,15,20,21,15,14,14,20,20, + 14,15,15,20,20, +}; + +static const static_codebook _44p3_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p3_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p3_p4_1, + 0 +}; + +static const long _vq_quantlist__44p3_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p3_p5_0[] = { + 2, 6, 6,14,14, 6, 7, 7,14,14, 7, 7, 7,15,15, 0, + 12,12,15,15, 0,13,13,15,15, 7, 8, 8,15,15,10,10, + 10,16,16, 9, 8, 8,15,15, 0,13,13,18,17, 0,13,13, + 16,16, 8, 8, 8,15,15,12,11,11,16,16, 9, 8, 8,15, + 15, 0,13,13,18,18, 0,13,13,16,16, 0,14,14,17,17, + 0,20, 0,19,20, 0,12,12,16,16, 0,16,16,20,22, 0, + 14,14,16,16, 0,14,14,17,17, 0,20,22,20,19, 0,13, + 13,15,16, 0,17,18, 0,21, 0,15,15,16,16, 5, 7, 7, + 13,13, 8, 9, 9,14,14,10,10,10,14,14, 0,20,22,18, + 18, 0,22,21,18,17, 9,10,10,14,14,12,12,12,17,17, + 12,10,10,14,14, 0, 0,20,17,17, 0,22,21,17,18,11, + 10,10,14,14,14,13,13,18,18,12,11,11,14,14, 0,22, + 21,18,19, 0,20, 0,17,17, 0,22, 0,18,18, 0, 0, 0, + 0, 0, 0,20,20,17,17, 0,22, 0,22,21, 0,21, 0,19, + 18, 0,22,22,18,18, 0, 0, 0, 0, 0, 0,21, 0,17,17, + 0,22, 0,20,20, 0, 0, 0,19,18, 6, 6, 6,12,12, 8, + 6, 6,10,10, 8, 6, 6,13,12, 0,10,10,11,11, 0,11, + 11,13,13, 8, 7, 7,13,13,11, 9, 9,13,13,10, 6, 6, + 12,12, 0,10,10,14,14, 0,10,10,13,13, 9, 7, 7,13, + 13,12,10,10,13,13,10, 6, 6,12,12, 0,11,11,15,15, + 0,10,10,13,13, 0,12,12,15,14, 0,19,20,16,17, 0, + 9, 9,13,13, 0,14,14,20,21, 0,12,11,13,12, 0,12, + 12,15,14, 0,20,19,17,17, 0,10,10,12,13, 0,15,15, + 22,21, 0,12,12,12,13, 0,10,10,12,12, 0,11,11,15, + 15, 0,11,11,15,15, 0,15,15,22,22, 0,16,17, 0, 0, + 0,11,11,15,15, 0,14,14,18,18, 0,11,11,16,16, 0, + 16,15, 0,21, 0,16,16, 0, 0, 0,12,12,15,15, 0,14, + 14,19,19, 0,11,11,15,15, 0,15,15,22, 0, 0,16,16, + 22, 0, 0,16,16, 0,21, 0, 0, 0, 0, 0, 0,15,15,19, + 20, 0,18,18, 0, 0, 0,17,17, 0, 0, 0,17,17, 0, 0, + 0, 0, 0, 0, 0, 0,16,15,22,21, 0,20,20, 0, 0, 0, + 18,18, 0, 0, 0,10,10,12,12, 0,10,10,11,11, 0,11, + 11,12,12, 0,11,11, 9, 9, 0,13,12,12,12, 0,11,11, + 13,13, 0,13,13,12,12, 0,10,10,12,12, 0,13,12,13, + 13, 0,12,12,12,12, 0,11,11,13,13, 0,13,13,12,12, + 0,10,10,12,12, 0,13,13,14,13, 0,12,12,12,12, 0, + 14,13,13,14, 0,20,21,15,15, 0,11,11,12,12, 0,15, + 16,20,20, 0,12,13,10,10, 0,13,13,14,13, 0,20,20, + 15,15, 0,11,11,12,12, 0,16,17,21,21, 0,13,13,11, + 11, 6, 7, 7,16,15,11, 9, 9,14,15,12, 9, 9,16,16, + 0,13,13,15,15, 0,14,14,17,17,10, 9, 9,16,16,14, + 12,12,16,16,12, 9, 9,15,15, 0,13,13,17,18, 0,13, + 13,15,15,12,10,10,17,17,15,12,12,17,17,13, 9, 9, + 16,16, 0,13,13,18,19, 0,14,14,16,16, 0,15,15,18, + 18, 0, 0, 0,20,19, 0,12,12,17,16, 0,16,17, 0,21, + 0,14,15,16,16, 0,15,15,18,18, 0, 0,22,19,21, 0, + 13,13,16,16, 0,18,17,22,22, 0,15,15,16,16, 7, 7, + 7,13,13,11,10,10,15,15,12,10,10,14,14, 0,21, 0, + 18,17, 0,21,22,18,18,11,10,10,15,15,14,12,12,17, + 17,14,11,11,14,14, 0,21,20,18,18, 0,22,21,18,17, + 12,11,10,16,16,16,14,14,17,19,14,11,11,15,15, 0, + 0,22,19,19, 0,21,22,18,18, 0,21, 0,18,19, 0, 0, + 0,22, 0, 0,22,21,17,17, 0, 0, 0,20,22, 0, 0,21, + 18,18, 0, 0, 0,19,20, 0, 0, 0, 0, 0, 0, 0,21,17, + 17, 0, 0, 0,22,21, 0, 0, 0,19,19,10, 9, 9,14,13, + 13,10,10,12,12,13,10,10,14,14, 0,13,13,12,12, 0, + 15,14,16,15,13,10,10,14,14,15,12,12,14,14,15,10, + 10,14,14, 0,14,14,15,15, 0,14,13,14,14,13,10,10, + 15,15,17,13,13,15,15,14,10,10,14,14, 0,14,14,15, + 16, 0,14,14,15,15, 0,15,15,16,16, 0,21,22,17,18, + 0,12,12,14,14, 0,17,17,20,21, 0,14,14,14,14, 0, + 15,15,16,16, 0,21,22,18,18, 0,13,13,14,14, 0,18, + 18,22, 0, 0,15,15,14,14, 0,11,11,13,13, 0,12,12, + 16,15, 0,12,12,16,16, 0,16,16, 0, 0, 0,16,17, 0, + 22, 0,12,12,16,16, 0,14,14,17,18, 0,11,11,16,16, + 0,15,15, 0,21, 0,16,16,21,22, 0,12,12,16,16, 0, + 15,15,19,19, 0,12,12,17,16, 0,16,16,21,22, 0,16, + 16, 0, 0, 0,17,17, 0,22, 0, 0, 0, 0, 0, 0,15,15, + 19,20, 0,17,19, 0, 0, 0,17,17,22, 0, 0,17,17, 0, + 22, 0, 0, 0, 0, 0, 0,15,15,21, 0, 0,19,20, 0, 0, + 0,19,18,22, 0, 0,11,12,14,14, 0,11,11,14,14, 0, + 12,12,15,15, 0,13,13,13,13, 0,14,14,16,16, 0,12, + 12,15,15, 0,14,14,16,15, 0,11,11,15,15, 0,13,13, + 16,16, 0,13,13,15,15, 0,12,12,15,15, 0,15,14,16, + 16, 0,11,11,15,15, 0,14,14,17,17, 0,13,13,15,15, + 0,15,15,16,16, 0, 0, 0,18,18, 0,12,12,14,14, 0, + 16,16,22, 0, 0,14,14,15,15, 0,15,15,16,17, 0,21, + 22,18,18, 0,13,13,15,14, 0,18,17,22, 0, 0,14,14, + 15,15, 8, 8, 8,16,15,12,10,10,16,15,12,10,10,16, + 16, 0,14,14,16,17, 0,14,14,17,16,12,10,10,17,18, + 14,12,12,18,18,14,10,10,16,16, 0,14,14,18,18, 0, + 14,14,16,16,12, 9, 9,16,16,17,13,13,16,17,14, 9, + 9,15,15, 0,14,14,18,19, 0,13,13,15,15, 0,15,15, + 18,19, 0, 0, 0,22,21, 0,13,13,16,16, 0,16,16,22, + 0, 0,15,15,16,16, 0,14,14,18,17, 0, 0, 0,20, 0, + 0,13,13,16,16, 0,18,18, 0, 0, 0,15,15,16,16, 8, + 7, 7,13,13,12,10,10,15,15,12,10,10,14,14, 0,22, + 22,19,18, 0, 0, 0,18,18,12,10,10,15,15,14,13,13, + 17,17,14,11,11,15,15, 0,19,20,18,18, 0,22,21,17, + 18,13,11,11,15,15,16,13,13,18,18,14,11,11,14,15, + 0,22,21,20,19, 0,22,21,17,17, 0, 0,22,19,18, 0, + 0, 0, 0, 0, 0,22,20,17,17, 0, 0, 0,21,20, 0, 0, + 0,19,17, 0, 0,22,19,19, 0, 0, 0, 0, 0, 0,22,20, + 18,17, 0, 0, 0, 0, 0, 0, 0, 0,18,18, 0,10,10,14, + 14, 0,11,11,14,14, 0,11,11,15,15, 0,14,14,14,14, + 0,15,15,16,16, 0,11,11,16,16, 0,13,13,16,16, 0, + 11,11,15,15, 0,14,14,16,16, 0,14,14,15,15, 0,11, + 11,15,15, 0,13,13,15,15, 0,10,10,15,15, 0,15,15, + 17,17, 0,14,14,14,14, 0,16,16,16,16, 0, 0,22,19, + 19, 0,13,13,14,14, 0,17,17, 0, 0, 0,15,15,14,14, + 0,16,16,17,17, 0, 0,22,18,18, 0,13,13,14,14, 0, + 21,18, 0, 0, 0,15,15,14,14, 0,11,11,13,13, 0,12, + 12,15,15, 0,12,12,16,15, 0,16,16, 0, 0, 0,17,17, + 22,22, 0,12,12,16,16, 0,14,14,18,18, 0,11,12,16, + 16, 0,15,16, 0,21, 0,16,16,22,21, 0,12,12,16,16, + 0,15,15,19,20, 0,11,12,16,16, 0,15,15,20,22, 0, + 16,16, 0,22, 0,17,17,22, 0, 0, 0, 0, 0, 0, 0,15, + 15,21,22, 0,19,18, 0, 0, 0,17,17, 0, 0, 0,17,17, + 0,22, 0, 0, 0, 0, 0, 0,16,15,22, 0, 0,19,19, 0, + 0, 0,17,18, 0, 0, 0,12,12,15,15, 0,12,12,15,15, + 0,12,12,15,15, 0,13,13,14,14, 0,15,15,16,17, 0, + 12,12,16,16, 0,14,14,16,16, 0,12,11,15,16, 0,14, + 14,16,17, 0,14,14,16,16, 0,13,12,16,16, 0,15,15, + 16,16, 0,11,11,15,15, 0,14,14,16,16, 0,14,14,15, + 15, 0,15,15,18,17, 0, 0,22, 0,20, 0,13,13,15,15, + 0,16,17,22,22, 0,14,14,15,15, 0,15,15,17,18, 0, + 20, 0,19,19, 0,13,13,15,15, 0,18,18,22, 0, 0,14, + 14,15,15, 0,11,11,16,16, 0,14,14,17,16, 0,13,13, + 17,17, 0,16,16,17,17, 0,17,17,18,19, 0,12,12,16, + 17, 0,15,15,18,18, 0,12,12,16,16, 0,16,16,19,18, + 0,16,16,17,16, 0,12,13,17,17, 0,17,16,18,17, 0, + 13,12,16,16, 0,16,16,18,19, 0,16,16,16,17, 0,16, + 16,18,18, 0,22, 0,22,22, 0,13,13,16,16, 0,19,18, + 22,20, 0,16,15,16,16, 0,16,17,18,18, 0, 0, 0,22, + 20, 0,14,14,16,16, 0,19,19, 0, 0, 0,16,16,16,16, + 0, 9, 9,13,13, 0,13,13,15,15, 0,14,14,15,15, 0, + 0,22,17,18, 0,22, 0,18,19, 0,12,12,15,15, 0,15, + 16,17,17, 0,14,14,14,14, 0,22, 0,18,18, 0,21,22, + 17,17, 0,13,13,15,15, 0,17,17,17,18, 0,14,14,15, + 15, 0,22,21,21,19, 0,20,21,17,17, 0,21,21,19,18, + 0, 0, 0, 0, 0, 0,21,21,17,17, 0, 0, 0,22,22, 0, + 0,22,19,18, 0, 0,21,19,18, 0, 0, 0, 0,22, 0,19, + 20,17,17, 0, 0, 0, 0,22, 0, 0, 0,19,18, 0,19,19, + 15,16, 0,21,19,16,17, 0, 0,21,17,17, 0, 0,22,17, + 17, 0,22,22,18,19, 0,20,20,16,16, 0, 0,22,18,18, + 0,20,19,16,17, 0,22,21,20,19, 0, 0,21,17,17, 0, + 21,20,17,17, 0, 0, 0,18,18, 0,19,19,17,16, 0,22, + 0,19,19, 0,21,22,17,18, 0, 0,22,19,18, 0, 0, 0, + 19,20, 0,19,19,16,16, 0,22,22,22, 0, 0,20,22,16, + 16, 0,22,20,18,19, 0, 0, 0,20,19, 0,20,20,16,16, + 0, 0, 0, 0, 0, 0,22,20,17,16, 0,11,11,13,13, 0, + 14,13,15,15, 0,13,13,16,15, 0,18,17,21, 0, 0,18, + 18,21, 0, 0,12,12,15,15, 0,15,16,17,18, 0,12,12, + 15,15, 0,17,17,22,20, 0,17,18,22, 0, 0,12,12,17, + 16, 0,16,17,19,19, 0,13,13,16,16, 0,17,17, 0,22, + 0,17,17, 0,21, 0,18,18,20,22, 0, 0, 0, 0, 0, 0, + 15,15,21,20, 0,20,19, 0, 0, 0,18,18,22, 0, 0,17, + 17,22, 0, 0, 0, 0, 0, 0, 0,15,16,20,22, 0,20,21, + 0, 0, 0,19,18, 0, 0, 0,15,15,19,19, 0,17,16,20, + 20, 0,16,17,20,21, 0,18,17, 0, 0, 0,19,19, 0, 0, + 0,15,15,21,19, 0,19,19, 0, 0, 0,15,15,22,22, 0, + 18,18, 0,22, 0,17,18,22,21, 0,15,15,20,19, 0,19, + 19, 0, 0, 0,15,15,20,22, 0,18,19,20, 0, 0,18,17, + 21,21, 0,18,18,19,22, 0, 0, 0, 0, 0, 0,15,15,20, + 19, 0,19,19, 0, 0, 0,18,18,21,22, 0,18,18,22, 0, + 0, 0, 0, 0, 0, 0,15,15,19,20, 0,21,21, 0, 0, 0, + 17,17,20,20, 0,12,12,17,17, 0,14,14,16,17, 0,13, + 14,17,17, 0,16,16,17,17, 0,17,17,17,19, 0,13,13, + 17,17, 0,16,16,18,18, 0,13,13,16,16, 0,16,16,18, + 18, 0,16,16,17,17, 0,13,13,17,17, 0,17,17,18,17, + 0,12,12,15,16, 0,17,18,19,20, 0,16,16,16,16, 0, + 17,16,18,19, 0, 0,22,21,22, 0,14,14,16,16, 0,19, + 19, 0, 0, 0,16,16,16,16, 0,16,16,18,17, 0, 0,22, + 21,21, 0,14,14,16,16, 0,22,20,22, 0, 0,16,16,15, + 15, 0, 9, 9,13,13, 0,14,14,15,15, 0,14,14,14,14, + 0,22,22,18,18, 0, 0,22,18,18, 0,12,12,15,15, 0, + 16,16,18,17, 0,14,14,14,14, 0,20,21,18,18, 0,22, + 21,17,17, 0,13,13,15,15, 0,17,17,18,18, 0,14,14, + 14,14, 0, 0,21,18,19, 0, 0,22,17,17, 0,22,22,19, + 18, 0, 0, 0, 0, 0, 0,19,21,17,17, 0, 0, 0,22,20, + 0, 0,21,18,19, 0, 0,22,18,18, 0, 0, 0, 0,22, 0, + 20,22,17,17, 0, 0, 0,20,22, 0, 0, 0,18,18, 0,19, + 21,16,16, 0,20,22,16,17, 0,20, 0,17,17, 0,22, 0, + 18,17, 0,21, 0,18,19, 0,20,20,17,17, 0,22, 0,18, + 18, 0,21,20,17,17, 0, 0,20,20,19, 0, 0,21,18,17, + 0,21,21,17,17, 0,22, 0,18,17, 0,19,19,17,17, 0, + 0,22,20,21, 0, 0,21,17,17, 0,22, 0,18,18, 0, 0, + 0,20,22, 0,20,19,16,16, 0, 0, 0, 0, 0, 0,22,22, + 17,17, 0,22, 0,18,19, 0, 0, 0,21,20, 0,19,21,16, + 17, 0, 0, 0, 0, 0, 0,22,22,17,16, 0,11,11,13,13, + 0,13,13,15,15, 0,13,13,15,15, 0,17,17,22,21, 0, + 18,18,22, 0, 0,12,13,16,15, 0,15,16,18,18, 0,13, + 13,16,16, 0,17,17, 0,22, 0,17,17,22,22, 0,13,13, + 16,16, 0,16,16,19,18, 0,13,13,16,16, 0,18,17, 0, + 20, 0,18,17,20, 0, 0,17,17,21, 0, 0, 0, 0, 0, 0, + 0,15,15,21,22, 0,19,20, 0, 0, 0,18,18, 0, 0, 0, + 18,17, 0, 0, 0, 0, 0, 0, 0, 0,16,16,22,22, 0,20, + 20, 0, 0, 0,21,19, 0, 0, 0,15,15,20,19, 0,16,16, + 22,20, 0,17,17, 0,22, 0,18,18, 0,22, 0,19,17, 0, + 0, 0,15,16,22,20, 0,18,19, 0, 0, 0,16,16,22,20, + 0,18,18, 0,22, 0,18,18,22, 0, 0,16,16,21,20, 0, + 19,20, 0,22, 0,16,16, 0,22, 0,18,18, 0,22, 0,18, + 18, 0,21, 0,19,18, 0,22, 0, 0, 0, 0, 0, 0,16,16, + 21,20, 0,20, 0, 0, 0, 0,18,18,21, 0, 0,18,18, 0, + 0, 0, 0, 0, 0, 0, 0,16,16,21,19, 0, 0, 0, 0, 0, + 0,18,18, 0,21, +}; + +static const static_codebook _44p3_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p3_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p3_p5_0, + 0 +}; + +static const long _vq_quantlist__44p3_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p3_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p3_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p3_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p3_p5_1, + 0 +}; + +static const long _vq_quantlist__44p3_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p6_0[] = { + 1, 6, 6, 7, 7, 7, 7, 8, 8, 7, 9, 9,11,11,11, 9, + 8, 8, 8, 9, 9,12,11,11, 9, 8, 8, 6, 7, 7,10,11, + 10,10,10,10,11,11,10,14,13,14,12,11,11,11,11,11, + 15,14,14,13,12,12, 5, 6, 6, 8, 5, 5, 8, 7, 7, 8, + 8, 8,12,10,10, 9, 7, 7, 9, 7, 8,12,10,10,10, 7, + 7, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13, + 13,10,10,11,10,10,16,13,14,14,10,10, 7, 7, 7,12, + 11,11,12,11,11,11,11,11,16,15,15,14,12,12,12,11, + 11,16,15,16,14,12,12,10, 9, 9,14,11,11,13,11,11, + 12,11,11,16,14,14,14,11,11,12,11,11,17,15,15,14, + 11,11, 7, 8, 8,12,11,11,12,10,10,12,10,10,16,14, + 13,14,10,10,12,10,10,17,14,14,14,10,10, 8, 7, 7, + 13,11,11,12,11,11,12,11,11,16,15,14,14,12,12,12, + 11,11,16,15,14,15,12,12,11,10,10,13,11,11,13,12, + 11,13,11,11,17,14,14,14,11,11,13,11,11,17,14,15, + 14,11,11, +}; + +static const static_codebook _44p3_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p3_p6_0, + 0 +}; + +static const long _vq_quantlist__44p3_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p6_1[] = { + 2, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, + 7, 7, 8, 8, 8, 9, 9, 9, 9, 7, 8, 6, 7, 7, 8, 8, + 8, 8, 8, 8, 9, 8, 8,10, 9, 9,10, 8, 8,10, 8, 8, + 10, 9, 9,10, 8, 8, 6, 6, 6, 8, 6, 6, 8, 7, 7, 8, + 7, 7,10, 8, 8, 9, 7, 7, 9, 7, 7,10, 8, 9, 9, 7, + 7, 7, 7, 7,10, 8, 8,11, 8, 8,10, 8, 8,12, 9, 9, + 12, 8, 8,11, 9, 9,12, 9, 9,11, 8, 8, 7, 7, 7,10, + 9, 9,10, 9, 9,10, 9, 9,11,10,10,10, 9, 9,11, 9, + 9,11,10,10,11, 9, 9, 9, 8, 8,10, 9, 9,10, 9, 9, + 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11, + 9, 9, 8, 8, 8,11, 9, 9,11, 9, 9,11, 9, 9,12, 9, + 9,12, 8, 8,12, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7, + 10, 9, 9,10, 9, 9,11, 9, 9,11,11,11,11, 9, 9,11, + 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11, 9, + 10,11,10, 9,11,10,10,11, 9, 9,11, 9,10,11,10,10, + 11, 9, 9, +}; + +static const static_codebook _44p3_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p3_p6_1, + 0 +}; + +static const long _vq_quantlist__44p3_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 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, +}; + +static const static_codebook _44p3_p7_0 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p7_0, + 1, -513979392, 1633504256, 2, 0, + (long *)_vq_quantlist__44p3_p7_0, + 0 +}; + +static const long _vq_quantlist__44p3_p7_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p3_p7_1[] = { + 1, 9, 9, 6, 9, 9, 5, 9, 9, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 8, 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, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10, +}; + +static const static_codebook _44p3_p7_1 = { + 5, 243, + (char *)_vq_lengthlist__44p3_p7_1, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p3_p7_1, + 0 +}; + +static const long _vq_quantlist__44p3_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p3_p7_2[] = { + 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _44p3_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p3_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p3_p7_2, + 0 +}; + +static const long _vq_quantlist__44p3_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p3_p7_3[] = { + 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, +}; + +static const static_codebook _44p3_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p3_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p3_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p3_short[] = { + 4, 5,16, 9, 9,12,17,18, 4, 2,18, 6, 5, 9,13,15, + 10, 7, 7, 6, 7, 9,13,13, 8, 5, 6, 5, 5, 7,11,12, + 8, 4, 7, 4, 3, 6,10,12,11, 8, 9, 7, 6, 8,11,12, + 15,13,13,11, 9, 7,10,12,16,12,16,12, 6, 5, 8,11, +}; + +static const static_codebook _huff_book__44p3_short = { + 2, 64, + (char *)_huff_lengthlist__44p3_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p4_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p4_l0_0[] = { + 1, 4, 4, 8, 8, 9, 8, 9, 9,10,10,10,10, 4, 6, 5, + 8, 7, 9, 9, 9, 9,10, 9,10,10, 4, 5, 6, 7, 8, 9, + 9, 9, 9, 9,10, 9,10, 8, 9, 8, 9, 8,10, 9,11, 9, + 12,10,11,10, 8, 8, 9, 8, 9, 9,10, 9,11,10,11,10, + 12, 9,10,10,11,10,11,11,12,11,12,12,12,12, 9,10, + 10,11,11,11,11,11,12,12,12,12,12,10,11,11,12,12, + 12,12,12,12,12,12,12,12,10,11,11,12,12,12,12,12, + 12,12,12,12,12,11,12,12,12,12,12,12,12,12,12,13, + 12,12,11,12,11,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,13,12,12,12,12,12,12,11,13,12,12, + 12,13,12,12,12,12,12,12,12, +}; + +static const static_codebook _44p4_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p4_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p4_l0_0, + 0 +}; + +static const long _vq_quantlist__44p4_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p4_l0_1[] = { + 3, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5, + 5, 6, 5, 6, 5, 6, 5, 6, 5, +}; + +static const static_codebook _44p4_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p4_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p4_l0_1, + 0 +}; + +static const long _vq_quantlist__44p4_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_l1_0[] = { + 1, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const static_codebook _44p4_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44p4_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p4_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p4_lfe[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book__44p4_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p4_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p4_long[] = { + 3, 5,13, 9, 9,12,16,18, 4, 2,20, 6, 7,10,15,20, + 10, 7, 5, 5, 6, 8,10,13, 8, 5, 5, 3, 5, 7,10,11, + 9, 7, 6, 5, 5, 7, 9, 9,11,10, 8, 7, 6, 6, 8, 8, + 15,15,10,10, 9, 7, 8, 9,17,19,13,12,10, 8, 9, 9, +}; + +static const static_codebook _huff_book__44p4_long = { + 2, 64, + (char *)_huff_lengthlist__44p4_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p4_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p1_0[] = { + 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p4_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p4_p1_0, + 0 +}; + +static const long _vq_quantlist__44p4_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p4_p2_0[] = { + 3, 9, 9, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, + 12,12, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, 0, 0, 0, + 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, + 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0,12,12, 0, 0, + 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0,12,12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, + 5, 5, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0, 9, 9, 0, + 0, 0,10,10, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, + 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0,11,11, 0, + 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, 0, + 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,11,11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 7, 7, + 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, + 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, + 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 0, 0, 0, 7, 7, 0, 0, 0, 8, 8, 0, + 0, 0,10,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,11,11, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 7, + 7, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 9, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,10,10, 0, 0, 0, 9, 9, 0, 0, 0,10,10, + 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0, + 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,11, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0,12,12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0, 0, + 9, 9, 0, 0, 0,10,10, 0, 0, 0,12,12, 0, 0, 0, 0, + 0, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, + 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0, + 0, 0, 0, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, + 10,10, 0, 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, +}; + +static const static_codebook _44p4_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p4_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p4_p2_0, + 0 +}; + +static const long _vq_quantlist__44p4_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p3_0[] = { + 1, 6, 6, 5, 7, 8, 0, 8, 8, 6, 9, 9, 7,10,10, 0, + 8, 8, 0, 9, 9, 0,12,12, 0, 8, 8, 4, 7, 7, 6,10, + 10, 0,12,12, 7,11,11, 8,12,12, 0,12,12, 0,13,12, + 0,15,15, 0,12,12, 0, 7, 7, 0, 7, 7, 0, 7, 7, 0, + 8, 8, 0,10,10, 0, 7, 7, 0, 8, 8, 0,11,11, 0, 7, + 7, 5, 7, 7, 8, 9, 9, 0,10,10, 8, 9, 9,11,11,11, + 0,10, 9, 0,11,11, 0,13,13, 0,10,10, 6, 7, 7, 8, + 10,10, 0,12,12, 9,10,10,10,12,12, 0,12,12, 0,12, + 12, 0,15,15, 0,12,12, 0,10,10, 0,11,11, 0,11,11, + 0,11,11, 0,13,13, 0,11,11, 0,11,11, 0,15,15, 0, + 10,10, 0, 8, 8, 0,10,10, 0,12,12, 0,11,11, 0,12, + 12, 0,12,12, 0,12,12, 0,15,15, 0,11,11, 0, 7, 7, + 0,10,10, 0,12,12, 0,10,10, 0,12,12, 0,12,12, 0, + 13,13, 0,14,14, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44p4_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p4_p3_0, + 0 +}; + +static const long _vq_quantlist__44p4_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p3_1[] = { + 3, 5, 5, 0, 8, 8, 0, 8, 8, 0, 9, 9, 0,10,10, 0, + 8, 8, 0, 8, 8, 0,10,10, 0, 8, 8, 0, 7, 7, 0, 8, + 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, + 0, 8, 8, 0, 8, 8, 0, 7, 7, 0, 6, 6, 0, 7, 7, 0, + 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,10,10, 0, 5, + 5, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, 0, 9, 9, + 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 6, 6, 0, + 9,10, 0,10,10, 0,10,10, 0,11,11, 0, 9, 9, 0,10, + 10, 0,11,11, 0, 9, 9, 0, 8, 8, 0, 8, 8, 0, 8, 8, + 0, 9, 9, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, + 7, 7, 0, 8, 8, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0, 9, + 9, 0, 7, 7, 0, 7, 7, 0, 8, 8, 0, 6, 6, 0, 6, 6, + 0,10,10, 0,10,10, 0,10,10, 0,12,12, 0, 9, 9, 0, + 10,10, 0,12,12, 0, 9, 9, 0, 8, 8, 0, 7, 7, 0, 7, + 7, 0, 8, 8, 0, 9, 9, 0, 7, 7, 0, 8, 8, 0, 9, 9, + 0, 6, 6, +}; + +static const static_codebook _44p4_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p4_p3_1, + 0 +}; + +static const long _vq_quantlist__44p4_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p4_0[] = { + 1, 6, 6, 6, 7, 7, 7, 8, 8, 7, 8, 8,10,11,11, 9, + 8, 8, 8, 8, 8,11,11,12, 9, 8, 8, 5, 7, 7, 9,11, + 11,10,11,11,10,11,11,12,14,14,11,12,12,10,12,12, + 13,14,14,12,12,12, 5, 6, 6, 7, 6, 6, 8, 7, 7, 8, + 7, 7,11,10,10,10, 7, 7, 9, 8, 8,12,11,11,10, 7, + 7, 7, 7, 7,11,10,10,12,10,10,11,10,10,15,13,13, + 13,10,10,12,11,11,15,13,13,14,11,11, 7, 7, 7,11, + 11,11,12,11,11,12,11,11,14,14,14,13,12,12,12,12, + 12,16,15,15,14,12,12, 0,10,10, 0,11,11, 0,12,12, + 0,11,11, 0,14,14, 0,11,11, 0,12,12, 0,15,15, 0, + 11,11, 7, 8, 8,12,11,10,12,10,10,12,11,11,15,13, + 13,14,11,11,12,10,10,16,14,14,14,10,10, 8, 7, 7, + 12,11,11,12,11,11,12,11,11,15,14,14,14,12,12,13, + 12,12,15,14,14,15,13,13, 0,11,11, 0,12,12, 0,12, + 12, 0,12,12, 0,15,15, 0,12,12, 0,13,13, 0,15,14, + 0,12,12, +}; + +static const static_codebook _44p4_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p4_p4_0, + 0 +}; + +static const long _vq_quantlist__44p4_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p4_p4_1[] = { + 4, 5, 5, 9, 9,12, 9, 9,12,12,12,10,10,13,13,13, + 11,11,12,12,13,13,13,12,12,13,10,10,13,13,13,13, + 13,13,13,13,10,10,13,12,13,11,11,13,13,13,14,14, + 13,12,13,10,10,13,13,12,13,13,13,13,13,10,10,12, + 12,13,11,11,13,13,13,14,14,12,12,13,12,12,13,13, + 13,13,13,13,13,13,11,11,12,12,13,11,11,13,13,13, + 14,14,12,12,13,14,14,13,13,14,13,13,14,14,14,14, + 14,12,12,13,14,14,13,13,14,14,14,12,12,12, 8, 8, + 12,12,13,12,12,11,11,13,11,11,11,11,14,12,12,11, + 11,14,12,12,10,11,14,12,12,12,12,14,12,12,12,12, + 13,13,13,11,11,14,12,12,11,11,14,12,12,12,12,14, + 12,12,12,12,14,12,12,12,12,14,13,13,11,11,14,12, + 12,11,11,14,12,12,12,12,14,13,13,12,12,14,12,12, + 12,12,14,13,13,11,11,14,12,12,11,11,14,13,13,11, + 11,15,13,13,12,12,14,12,12,12,12,15,13,13,12,12, + 14,12,12,11,11,15,13,13,11,11,12, 9, 9,11,11,13, + 7, 7,11,11,13, 8, 8,12,12,14,10,10,10,10,14,14, + 14,11,11,14, 8, 8,12,12,14,14,14,12,12,14, 7, 7, + 11,11,14, 9, 9,12,12,14,14,14,11,11,14, 8, 8,12, + 12,14,14,14,12,12,14, 7, 7,11,11,14, 9, 9,12,12, + 14,14,14,11,11,14,10,10,12,12,14,14,14,13,13,14, + 9, 9,11,11,14,10,10,12,11,15,14,14,11,11,14,15, + 15,12,12,15,14,14,14,14,15,14,14,11,11,15,14,14, + 12,12,15,14,14,11,11,14,11,11,10,10,15,10,10,10, + 10,15,10,10,10,10,15,11,11, 9, 9,15,12,13, 9, 9, + 15,11,11,11,11,15,13,13,11,11,15,10,10,10,10,15, + 11,11,10,10,15,13,13,11,11,15,11,11,11,11,15,13, + 13,11,11,15,10,10,10,10,15,11,11,10,10,15,13,13, + 10,11,15,12,12,11,11,15,13,13,11,10,15,11,11,10, + 10,15,11,12,10, 9,15,13,13,10,10,15,14,14,11,11, + 15,13,13,11,11,15,14,14,10,10,15,13,13,10,10,15, + 14,14,10,10,14,13,13,10,10,15,13,13,10,10,15,13, + 13,10,10,14,14,14, 8, 9,15,14,14, 9, 9,15,14,14, + 11,11,15,14,14,10,10,15,14,14,10,10,15,14,14,11, + 11,15,14,14,10,10,15,14,14,11,11,15,14,14,10,10, + 15,14,14,10,10,15,14,14,10,10,15,14,14, 9, 9,15, + 14,14,11,11,15,14,14,11,11,15,14,14,10,10,15,14, + 14,10,10,14,14,14, 9, 9,15,15,15,11,11,15,14,14, + 12,12,15,15,15,10,10,15,14,15,10,10,15,15,15, 9, + 9,15,10,10,13,13,17, 8, 8,12,12,17,10, 9,13,13, + 18,11,11,12,12,18,14,14,12,12,17, 9, 9,13,13,17, + 13,13,12,12,18, 8, 8,12,12,18,10,10,12,12,18,14, + 14,12,12,18,10,10,13,13,18,13,13,13,13,18, 9, 9, + 12,12,18,10,10,13,13,18,14,14,12,12,18,11,11,13, + 13,18,14,14,13,13,18,10,10,12,12,17,11,11,12,12, + 18,14,14,12,12,18,14,14,13,13,18,14,14,13,13,19, + 14,15,12,12,18,14,14,12,12,18,15,15,12,12,13, 7, + 7,11,11,14,15,15,11,11,14,16,15,11,11,14,15,15, + 11,11,14,15,15,11,11,14,15,15,11,12,14,15,15,12, + 12,13,15,15,11,11,14,15,15,11,11,15,15,15,12,12, + 14,15,15,12,12,14,16,16,12,12,14,15,15,11,11,14, + 15,15,11,11,15,15,15,12,12,15,15,15,12,12,14,15, + 15,12,12,14,15,15,11,11,14,15,15,11,11,15,14,15, + 12,12,15,15,15,12,12,15,16,16,12,12,15,15,15,12, + 12,14,15,15,12,12,15,15,15,12,12,13,13,13,11,11, + 14,14,15,11,11,14,14,14,12,12,14,15,15,10,10,15, + 15,15,11,11,14,15,15,12,12,14,14,14,11,11,14,15, + 15,11,11,14,15,15,12,12,15,15,15,11,11,14,15,15, + 12,12,14,14,15,11,11,14,15,15,11,11,14,15,15,12, + 12,15,15,15,11,11,15,15,15,12,12,14,15,15,12,12, + 14,15,15,10,10,14,15,15,11,11,15,15,15,10,10,15, + 15,15,12,12,15,15,15,14,14,15,15,15,11,11,15,15, + 15,11,11,15,15,15,11,11,14,10,10,10,10,15, 9, 9, + 12,11,15,10,10,12,12,15,11,11,11,11,15,13,13,12, + 12,16,10,10,12,12,15,13,13,12,12,15, 9, 9,11,11, + 15,10,10,13,12,15,13,13,11,11,15,10,10,12,12,15, + 13,13,12,12,15, 9, 9,11,11,15,10,10,12,12,15,13, + 13,11,11,15,11,11,12,12,15,13,13,13,13,15,10,10, + 11,11,15,11,11,12,12,15,13,14,11,11,15,14,14,13, + 13,16,14,14,20,19,15,14,14,11,11,15,13,14,12,12, + 15,14,14,11,11,14,13,13,10,10,14,14,13,11,11,15, + 13,14,12,12,15,14,14,12,12,15,14,14,11,11,15,14, + 14,12,12,15,15,14,13,13,15,14,14,11,11,15,14,14, + 11,11,15,14,14,13,13,15,14,14,12,12,15,14,14,13, + 13,15,14,14,11,11,15,14,14,11,11,15,14,14,13,13, + 15,14,14,12,12,15,14,14,12,12,15,14,14,12,12,15, + 14,14,11,11,15,15,15,12,12,15,15,15,13,13,16,14, + 14,12,12,15,15,15,13,13,15,15,15,12,12,15,15,15, + 12,12,14,10,10,13,13,17, 9, 9,12,12,17, 9, 9,13, + 13,17,11,11,12,12,18,14,14,12,12,18,10,10,13,13, + 18,14,13,12,12,18, 9, 9,12,12,18,10,10,12,13,18, + 14,14,12,12,17, 9, 9,12,12,17,13,14,12,12,17, 9, + 9,12,12,17,10,10,12,12,17,14,14,11,11,18,11,11, + 12,12,18,14,14,12,13,18,10,10,12,12,18,11,11,12, + 12,18,14,14,11,11,18,15,15,12,12,18,14,14,13,13, + 18,14,15,12,12,17,14,14,12,12,17,15,15,12,12,13, + 7, 7,11,11,14,15,15,11,11,14,15,15,11,11,14,15, + 15,11,11,14,15,15,11,11,14,15,15,11,11,14,15,15, + 12,12,14,15,15,11,11,14,15,15,11,11,15,15,15,12, + 12,14,15,15,11,11,14,15,15,12,12,14,15,15,11,11, + 15,15,15,11,11,15,15,15,12,12,14,15,15,12,12,14, + 15,16,12,12,14,15,15,11,11,14,15,15,11,11,15,15, + 15,12,12,15,15,15,12,12,15,16,16,12,12,15,15,15, + 12,12,15,15,15,12,12,15,15,15,12,12,13,13,13,12, + 12,14,14,14,11,11,14,14,14,12,12,14,14,14,10,10, + 15,15,15,11,11,14,15,15,12,12,14,14,14,11,11,14, + 15,15,11,11,14,14,14,12,12,15,15,14,11,11,14,15, + 15,12,12,14,14,14,11,11,14,15,15,11,11,14,14,14, + 11,11,15,14,14,10,10,14,15,15,12,12,14,14,14,12, + 12,14,15,15,10,10,14,15,15,11,11,15,15,15,10,10, + 15,15,15,12,12,15,14,14,13,13,15,15,15,10,10,15, + 14,14,11,11,15,15,15,10,10,14,10,10,10,10,14, 9, + 9,12,12,15,10,10,12,12,14,11,11,11,11,15,13,14, + 12,12,15,10,10,13,13,15,13,13,12,12,15, 9, 9,12, + 12,15,10,10,13,13,15,13,14,11,11,15,10,10,12,12, + 15,13,13,12,12,15, 9, 9,11,11,15,10,10,12,12,15, + 13,13,11,11,15,11,11,12,12,15,13,13,13,13,15,10, + 10,11,11,15,11,11,12,12,15,14,14,11,11,15,14,14, + 13,13,15,14,14,20,19,15,14,14,11,11,15,14,14,12, + 12,15,14,14,11,11,14,13,13,11,11,15,13,13,11,11, + 15,14,13,12,12,15,14,14,11,12,15,14,14,11,11,15, + 14,14,12,12,14,14,14,13,13,15,14,14,11,11,15,14, + 14,11,11,15,14,14,13,13,15,14,14,12,12,15,14,14, + 13,13,14,14,14,11,11,15,14,14,11,11,15,14,14,13, + 13,15,14,14,12,12,15,14,14,12,12,15,14,14,12,12, + 15,14,14,11,11,14,14,14,12,12,15,15,15,13,13,16, + 14,14,12,12,15,15,15,13,13,15,14,14,12,12,15,15, + 15,12,12,15,11,11,13,13,18,10,10,12,12,17,11,11, + 12,12,18,12,12,11,11,18,14,14,12,12,18,10,10,13, + 13,18,14,14,12,12,18,10,10,12,12,18,11,11,12,12, + 18,14,14,12,12,18,11,11,12,13,18,14,14,12,12,18, + 10,10,12,12,18,11,11,12,12,18,14,14,11,11,18,11, + 11,12,12,18,14,14,12,12,17,10,10,11,11,17,12,12, + 11,11,17,14,14,11,11,18,15,15,12,12,18,14,14,13, + 13,18,15,15,11,11,18,15,14,12,12,18,15,15,11,11, + 14, 8, 8,11,11,14,15,15,10,10,14,15,15,11,11,14, + 15,15,11,11,15,15,15,12,12,15,15,15,11,11,15,15, + 15,12,12,14,15,15,10,10,15,15,15,11,11,15,15,15, + 12,12,15,15,15,11,11,15,15,15,13,13,14,15,15,10, + 10,15,15,15,11,11,15,15,15,12,12,15,15,15,12,12, + 15,16,16,12,12,15,14,14,11,11,15,15,15,11,11,15, + 15,15,12,12,16,15,15,13,13,15,16,16,13,13,16,15, + 15,12,12,15,15,15,12,12,15,15,15,12,12,14,13,13, + 11,11,14,14,14,11,11,14,14,14,12,12,15,14,14,11, + 11,15,15,14,11,11,15,14,14,12,12,15,14,14,12,12, + 14,15,15,11,11,15,14,14,12,12,15,14,14,11,11,15, + 14,15,12,12,15,14,14,12,12,14,15,15,11,11,15,14, + 14,11,11,15,14,14,11,11,15,15,14,12,12,15,14,14, + 12,12,15,15,15,10,11,15,14,14,11,11,15,15,15,10, + 10,15,15,15,12,12,16,14,14,13,13,15,15,15,11,11, + 15,14,14,11,11,15,15,15,11,11,14,11,11, 9, 9,14, + 10,10,12,12,15,11,11,12,12,15,12,12,12,12,15,14, + 14,13,13,15,11,11,12,12,15,14,14,13,13,14,10,10, + 12,12,15,11,11,13,13,15,14,14,12,12,15,10,10,12, + 12,14,14,14,13,13,14,10,10,11,11,15,11,11,12,12, + 15,14,14,12,12,15,12,12,13,13,15,14,14,14,14,15, + 11,11,11,11,15,12,11,12,12,15,14,14,11,11,15,15, + 15,13,14,15,14,14,20,19,15,14,14,12,12,15,14,14, + 13,13,15,14,14,12,12,14,13,13,10,10,14,13,13,11, + 11,14,13,13,11,11,15,14,14,12,12,15,14,14,12,12, + 15,14,14,12,11,14,14,14,13,13,15,14,14,11,11,15, + 14,14,11,11,15,14,14,14,14,15,14,14,11,12,15,14, + 14,13,13,14,14,14,11,11,15,14,14,11,11,15,14,14, + 14,14,15,14,14,12,12,15,14,14,13,13,15,14,14,11, + 11,14,14,14,12,12,15,14,14,13,13,15,15,15,13,13, + 15,14,14,13,13,15,15,15,13,13,15,14,14,13,13,15, + 15,15,13,13,15,14,14,13,13,18,15,15,12,12,18,15, + 15,12,12,18,16,16,11,11,18,17,17,12,12,18,15,15, + 13,13,18,17,17,12,12,18,15,15,12,12,18,15,16,12, + 12,18,17,17,12,12,18,15,15,13,12,17,16,17,12,12, + 17,15,15,11,12,18,15,15,12,12,18,17,17,11,11,18, + 16,16,12,12,18,17,16,12,12,18,15,15,11,11,18,15, + 15,12,12,18,17,17,11,11,18,17,17,12,12,18,16,16, + 13,13,18,17,17,11,11,17,16,16,11,11,18,17,17,11, + 11,15,15,15,11,11,16,15,15,11,11,16,15,15,11,11, + 16,15,15,12,12,17,15,15,14,14,16,15,15,11,11,17, + 15,15,14,14,16,15,15,11,11,16,15,15,12,12,18,15, + 15,13,13,16,15,15,11,11,17,15,15,14,14,16,15,15, + 11,11,16,15,15,12,12,17,15,15,13,13,16,15,15,12, + 12,17,16,15,14,14,16,15,15,11,11,16,15,15,12,12, + 18,15,15,13,13,17,15,15,14,14,17,16,16,15,15,18, + 14,15,13,13,18,15,15,14,14,18,15,15,13,13,15,13, + 13,12,12,15,14,14,12,12,16,14,14,12,12,16,14,14, + 12,12,17,14,15,12,12,16,14,14,12,12,17,14,14,13, + 13,16,15,15,12,12,16,14,14,12,12,17,14,14,12,12, + 16,14,14,12,12,17,14,14,13,13,15,15,15,11,11,16, + 14,14,12,12,17,14,14,12,12,16,15,15,12,12,17,14, + 14,13,12,16,15,15,11,11,16,14,14,12,12,17,15,15, + 11,11,17,15,15,13,13,17,14,14,13,13,18,15,15,12, + 12,17,14,14,12,12,17,15,15,12,12,14,15,15, 9, 9, + 14,15,15,12,12,15,16,15,13,13,15,15,15,14,14,15, + 15,15,21,19,15,15,15,13,13,15,15,15,19,19,15,15, + 15,12,12,15,16,16,14,14,15,15,15,19,19,15,16,15, + 13,13,15,16,16,19,20,15,15,15,12,13,15,16,16,14, + 14,15,15,15,20,19,15,15,15,14,14,15,16,16,19,19, + 15,15,15,14,13,15,15,15,14,14,15,15,15,19,19,15, + 16,16,20,19,15,17,16,21,20,15,15,15,20,19,15,16, + 16,20,20,15,15,15,19,20,14,13,13,10,10,14,14,14, + 11,11,14,14,14,12,12,15,14,14,13,13,15,15,14,20, + 20,15,14,14,12,12,14,14,14,19,19,15,14,14,11,11, + 15,14,14,12,12,15,14,14,20,19,15,14,14,12,12,14, + 14,14,20,20,14,14,14,11,11,15,14,14,12,12,15,14, + 14,20,21,15,14,14,13,13,15,14,14,20,20,15,14,14, + 12,12,15,14,14,13,13,14,15,15,20,20,15,15,15,20, + 19,15,14,14,20,19,15,15,15,20,20,15,14,14,21,20, + 15,15,15,20,20, +}; + +static const static_codebook _44p4_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p4_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p4_p4_1, + 0 +}; + +static const long _vq_quantlist__44p4_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p4_p5_0[] = { + 1, 7, 6,15,15, 7, 8, 8,15,15, 8, 8, 8,15,15, 0, + 13,13,16,16, 0,14,14,16,16, 7, 9, 9,16,16,10,11, + 11,17,17,10, 8, 8,15,16, 0,14,14,18,18, 0,14,14, + 16,16, 9, 9, 9,16,16,12,11,11,17,17,10, 9, 9,15, + 15, 0,14,14,19,19, 0,14,14,16,16, 0,15,15,18,17, + 0, 0, 0,20,20, 0,13,13,16,16, 0,17,17,22,20, 0, + 15,15,17,17, 0,15,15,18,18, 0,22,21,20,21, 0,13, + 13,16,16, 0,18,18, 0,22, 0,15,15,17,17, 6, 7, 7, + 13,13, 9,10,10,15,15,11,10,10,15,15, 0,21,22,18, + 18, 0, 0, 0,18,18,10,10,10,15,15,12,13,13,17,17, + 12,11,11,15,15, 0,22,22,18,18, 0, 0,21,18,18,12, + 11,11,15,15,15,14,14,18,18,13,11,11,15,15, 0, 0, + 21,18,19, 0,21,22,18,19, 0,22, 0,18,19, 0, 0, 0, + 0, 0, 0,21,21,18,18, 0,22, 0, 0,21, 0, 0, 0,19, + 18, 0, 0, 0,18,19, 0, 0, 0, 0, 0, 0,20,20,18,17, + 0, 0,22, 0,21, 0, 0, 0,19,19, 6, 6, 6,13,13, 8, + 6, 6,11,11, 9, 7, 7,13,13, 0,10,10,11,11, 0,12, + 12,14,14, 9, 8, 8,14,14,12,10,10,13,13,10, 7, 7, + 13,13, 0,11,11,15,15, 0,11,11,13,13, 9, 8, 8,14, + 14,13,10,10,13,14,11, 7, 7,13,13, 0,11,11,15,15, + 0,11,11,13,13, 0,12,12,15,15, 0,21,21,17,17, 0, + 10,10,13,13, 0,14,14,20,20, 0,12,12,13,13, 0,12, + 12,15,15, 0,21,22,17,18, 0,10,10,13,13, 0,16,16, + 20,21, 0,12,12,13,13, 0,11,11,13,13, 0,12,12,16, + 16, 0,12,12,16,16, 0,16,16, 0,21, 0,17,18, 0, 0, + 0,12,12,15,15, 0,15,15,18,18, 0,12,12,16,16, 0, + 16,16,21,22, 0,17,17,22,21, 0,12,12,16,16, 0,15, + 15,19,19, 0,12,12,16,16, 0,16,16,22,22, 0,17,16, + 22, 0, 0,17,18, 0, 0, 0, 0, 0, 0, 0, 0,15,15,21, + 20, 0,19,20, 0,22, 0,18,18, 0, 0, 0,18,17, 0, 0, + 0, 0, 0, 0, 0, 0,16,16,22,21, 0,20,20, 0,22, 0, + 20,19, 0, 0, 0,11,11,12,12, 0,10,10,11,11, 0,11, + 11,12,12, 0,12,12,10,10, 0,13,13,12,12, 0,11,11, + 13,13, 0,13,13,12,12, 0,10,10,12,12, 0,13,13,14, + 13, 0,12,12,12,12, 0,12,12,13,13, 0,14,14,13,13, + 0,10,10,12,12, 0,13,13,14,14, 0,13,12,12,12, 0, + 14,14,14,14, 0,21,21,16,16, 0,12,12,12,12, 0,16, + 16,20,21, 0,13,13,11,11, 0,14,14,14,14, 0,20,20, + 16,15, 0,12,12,12,12, 0,17,17,20,20, 0,13,13,11, + 11, 7, 8, 8,16,16,11,10,10,15,15,12,10,10,17,17, + 0,14,14,16,15, 0,15,15,17,17,11, 9, 9,16,16,14, + 12,12,17,17,13, 9, 9,16,15, 0,14,14,19,18, 0,14, + 14,16,16,12,10,10,17,18,16,13,13,17,18,14,10,10, + 16,16, 0,14,14,19,19, 0,14,15,17,17, 0,15,15,18, + 19, 0, 0, 0,20,20, 0,13,13,17,17, 0,17,18, 0,22, + 0,15,15,16,17, 0,15,15,18,18, 0, 0, 0,20,21, 0, + 14,14,17,17, 0,19,18, 0, 0, 0,16,16,17,17, 8, 7, + 7,14,14,12,11,11,15,15,13,11,11,15,15, 0, 0, 0, + 18,19, 0,21,20,18,18,12,10,11,15,16,14,13,13,18, + 18,14,11,11,15,15, 0,20,20,19,18, 0,20, 0,18,18, + 13,11,11,16,16,17,15,15,19,19,14,12,12,15,15, 0, + 21, 0,18,20, 0,22,22,18,19, 0,22,22,19,19, 0, 0, + 0, 0, 0, 0,21,22,19,18, 0, 0, 0, 0,21, 0, 0, 0, + 19,19, 0, 0,22,20,20, 0, 0, 0, 0, 0, 0,22, 0,18, + 18, 0, 0, 0, 0,22, 0, 0, 0,19,20,11,10,10,14,14, + 14,11,11,13,13,14,11,11,15,15, 0,14,13,12,12, 0, + 15,15,16,16,13,11,11,15,15,16,13,13,15,15,15,10, + 10,14,15, 0,14,14,16,16, 0,14,14,15,15,13,11,11, + 15,15,18,14,14,15,15,15,10,10,15,14, 0,14,14,16, + 16, 0,14,14,15,15, 0,15,15,17,16, 0,21,22,18,18, + 0,13,13,14,14, 0,18,17,20,21, 0,15,15,14,14, 0, + 15,16,16,17, 0, 0, 0,19,18, 0,13,13,15,14, 0,19, + 19, 0, 0, 0,15,15,14,14, 0,12,12,14,13, 0,13,13, + 16,16, 0,12,12,16,16, 0,16,16,22, 0, 0,17,18, 0, + 22, 0,13,13,16,16, 0,15,15,18,18, 0,12,12,16,16, + 0,16,16,22,22, 0,17,17, 0, 0, 0,13,13,17,17, 0, + 16,16,19,20, 0,12,12,17,17, 0,17,17,22, 0, 0,17, + 17,22,21, 0,18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, + 21,21, 0,19,19, 0, 0, 0,18,18, 0,22, 0,18,18, 0, + 22, 0, 0, 0, 0, 0, 0,16,16,22, 0, 0,20,20, 0, 0, + 0,19,18, 0, 0, 0,12,12,15,15, 0,12,12,15,14, 0, + 13,13,15,15, 0,14,14,14,14, 0,15,15,16,16, 0,13, + 13,15,16, 0,15,15,16,16, 0,12,12,15,15, 0,14,14, + 16,16, 0,14,14,15,15, 0,13,13,15,16, 0,15,15,16, + 16, 0,12,12,15,15, 0,15,15,17,17, 0,14,14,15,15, + 0,15,15,17,17, 0,21,21,19,19, 0,13,13,14,14, 0, + 17,17,22, 0, 0,14,14,15,15, 0,15,15,17,17, 0,22, + 0,18,20, 0,13,13,15,15, 0,18,18, 0,22, 0,15,15, + 14,15, 8, 8, 8,17,16,12,10,10,16,16,13,10,10,17, + 16, 0,15,15,17,17, 0,15,15,17,17,12,11,11,18,18, + 15,12,12,18,18,15,10,10,16,17, 0,14,14,18,18, 0, + 14,14,17,17,13,10,10,16,16,17,14,14,17,17,15,10, + 10,16,15, 0,15,15,19,20, 0,14,14,15,16, 0,16,16, + 19,19, 0, 0, 0,21,22, 0,13,13,17,17, 0,18,17, 0, + 21, 0,15,15,17,17, 0,15,15,18,19, 0, 0,22, 0,21, + 0,13,13,16,17, 0,19,19, 0,22, 0,16,15,16,16, 9, + 8, 8,14,14,12,11,11,15,15,13,11,11,15,15, 0,21, + 20,19,18, 0, 0, 0,19,18,12,11,11,16,15,15,13,13, + 17,18,14,11,11,15,15, 0,22,22,19,18, 0,22,21,18, + 18,14,11,11,15,15,17,14,14,18,18,15,12,12,15,15, + 0,22,22,20,19, 0, 0,21,18,18, 0, 0,22,20,20, 0, + 0, 0, 0, 0, 0,20,21,18,18, 0, 0, 0,21,21, 0, 0, + 0,20,19, 0,22,21,19,19, 0, 0, 0, 0, 0, 0, 0,22, + 17,18, 0, 0,22, 0,22, 0,22, 0,19,19, 0,11,11,15, + 15, 0,11,11,14,14, 0,12,12,15,15, 0,15,15,14,14, + 0,16,16,16,16, 0,12,12,16,16, 0,14,14,16,16, 0, + 11,11,15,15, 0,15,15,17,17, 0,15,15,15,15, 0,12, + 12,16,16, 0,14,14,15,15, 0,11,11,15,15, 0,15,15, + 17,17, 0,15,15,14,15, 0,16,16,17,17, 0, 0, 0,19, + 19, 0,14,14,15,15, 0,18,18,21, 0, 0,15,15,14,15, + 0,16,16,17,17, 0,21, 0,19,19, 0,14,14,15,15, 0, + 20,20,22, 0, 0,16,15,14,14, 0,12,12,13,13, 0,12, + 12,16,16, 0,12,12,16,16, 0,16,16,22,21, 0,18,17, + 21, 0, 0,13,13,16,16, 0,15,15,18,19, 0,12,12,16, + 16, 0,16,17,22, 0, 0,17,17, 0,22, 0,13,13,17,16, + 0,15,15,19,19, 0,12,12,16,16, 0,16,16,21,20, 0, + 17,16,22, 0, 0,18,18,22,21, 0, 0, 0, 0, 0, 0,15, + 16,21,21, 0,19,19, 0, 0, 0,18,17, 0, 0, 0,18,18, + 21, 0, 0, 0, 0, 0, 0, 0,16,16,22,22, 0,20,21, 0, + 0, 0,18,19, 0,22, 0,13,13,16,16, 0,12,12,15,15, + 0,13,13,16,16, 0,14,14,15,15, 0,15,15,17,17, 0, + 13,13,17,16, 0,15,15,17,17, 0,12,12,16,16, 0,15, + 15,17,17, 0,14,14,16,16, 0,13,13,16,17, 0,15,15, + 17,17, 0,12,12,16,16, 0,14,14,17,17, 0,14,14,16, + 16, 0,16,16,17,17, 0,21, 0,21,19, 0,13,13,16,16, + 0,17,17, 0, 0, 0,15,15,16,16, 0,16,15,18,18, 0, + 22, 0,20,20, 0,13,13,15,15, 0,18,18, 0, 0, 0,15, + 15,15,15, 0,12,12,17,17, 0,14,14,17,17, 0,14,14, + 17,17, 0,17,17,18,17, 0,17,17,19,18, 0,13,13,17, + 17, 0,16,16,18,18, 0,13,13,16,16, 0,17,17,19,19, + 0,16,16,17,17, 0,13,13,18,18, 0,17,17,18,18, 0, + 13,13,17,17, 0,17,17,19,19, 0,16,17,17,17, 0,17, + 17,19,19, 0,21, 0,21,19, 0,14,14,16,16, 0,20,19, + 0,21, 0,16,16,16,16, 0,17,18,19,19, 0, 0, 0, 0, + 21, 0,15,15,16,17, 0,21,20, 0, 0, 0,17,18,16,17, + 0, 9, 9,14,14, 0,14,14,15,16, 0,14,14,15,15, 0, + 0, 0,18,18, 0,21, 0,18,19, 0,12,12,15,15, 0,16, + 16,17,17, 0,14,14,14,14, 0,22, 0,19,18, 0,22, 0, + 17,18, 0,14,14,16,15, 0,18,18,19,18, 0,14,15,15, + 15, 0, 0,21,20,20, 0, 0, 0,18,18, 0,21,21,19,19, + 0, 0, 0, 0, 0, 0,21,21,18,18, 0,22, 0,20,20, 0, + 22, 0,19,19, 0,22, 0,19,20, 0, 0, 0, 0, 0, 0, 0, + 21,17,18, 0, 0, 0,22,22, 0, 0, 0,19,18, 0,18,20, + 16,16, 0,21,20,17,17, 0, 0,21,18,18, 0,22,21,18, + 18, 0, 0,22,19,19, 0,20,20,17,17, 0, 0, 0,18,18, + 0,19,20,17,17, 0,22, 0,19,21, 0,22,21,18,18, 0, + 20,19,17,18, 0, 0, 0,19,19, 0,20,20,17,17, 0,22, + 22,21,21, 0,20, 0,18,18, 0,22,22,18,18, 0, 0, 0, + 20,22, 0,20,20,16,16, 0, 0, 0,21, 0, 0,21,20,16, + 17, 0,22, 0,19,20, 0, 0, 0,21,20, 0,19,21,17,17, + 0, 0, 0, 0, 0, 0,21,21,17,17, 0,12,12,13,13, 0, + 14,14,16,16, 0,14,14,16,16, 0,18,18, 0, 0, 0,19, + 18,22, 0, 0,13,13,16,16, 0,16,16,18,18, 0,13,13, + 16,16, 0,17,18,21, 0, 0,18,18,21, 0, 0,13,13,16, + 16, 0,17,17,19,20, 0,13,13,16,17, 0,18,18,21, 0, + 0,18,18,21, 0, 0,18,19, 0,21, 0, 0, 0, 0, 0, 0, + 16,16,21,20, 0,20,20, 0, 0, 0,18,19, 0, 0, 0,18, + 18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, 0,21, 0,22,22, + 0, 0, 0,19,19, 0, 0, 0,16,16,19,20, 0,17,16,22, + 21, 0,17,17,21,20, 0,19,18, 0,22, 0,19,19,22,22, + 0,16,15,22,22, 0,19,19, 0,21, 0,15,15,20,20, 0, + 18,19, 0,21, 0,18,18,22,22, 0,16,16,21,20, 0,20, + 19,21,22, 0,16,15,20,20, 0,19,19, 0,22, 0,18,18, + 21, 0, 0,19,18,21,22, 0, 0, 0, 0, 0, 0,16,16,19, + 21, 0,20,22, 0,22, 0,18,18,20,21, 0,19,18, 0,22, + 0, 0, 0,22, 0, 0,16,16,20,20, 0,21,21, 0, 0, 0, + 18,18,21, 0, 0,12,12,17,17, 0,15,14,17,17, 0,14, + 14,18,18, 0,17,17,17,18, 0,18,18,18,18, 0,13,13, + 18,18, 0,16,17,19,18, 0,13,13,16,17, 0,17,17,18, + 19, 0,17,17,17,17, 0,13,13,17,17, 0,17,18,18,18, + 0,13,13,16,16, 0,18,18,19,20, 0,16,17,17,16, 0, + 17,18,19,18, 0, 0, 0,22,21, 0,15,15,16,16, 0,20, + 20,21,22, 0,17,17,16,16, 0,16,17,18,18, 0, 0, 0, + 21,21, 0,15,15,16,16, 0,21,20, 0, 0, 0,17,17,16, + 16, 0,10,10,14,14, 0,14,14,15,15, 0,14,14,15,15, + 0,22, 0,18,18, 0, 0, 0,19,19, 0,13,13,15,16, 0, + 17,16,18,18, 0,14,14,15,15, 0,21,21,19,18, 0,22, + 21,18,17, 0,14,14,15,15, 0,18,18,19,18, 0,15,15, + 14,14, 0,22,21,19,19, 0,22,21,17,18, 0, 0, 0,19, + 19, 0, 0, 0, 0, 0, 0,20,22,17,17, 0, 0,22,22,20, + 0, 0, 0,19,18, 0,21,22,19,18, 0, 0, 0, 0, 0, 0, + 22,22,17,18, 0, 0, 0,21,22, 0, 0, 0,19,18, 0,20, + 20,17,17, 0,21,21,17,18, 0,21,22,18,18, 0,21, 0, + 18,18, 0,22, 0,19,19, 0,19,21,18,18, 0, 0,22,18, + 18, 0,22,21,17,17, 0,22, 0,20,20, 0, 0, 0,18,18, + 0,22,21,18,18, 0,21, 0,19,19, 0,20,21,17,17, 0, + 0,22,22,20, 0,21,22,17,17, 0, 0,21,19,18, 0, 0, + 0,21,21, 0,21,20,16,17, 0, 0, 0, 0, 0, 0,21, 0, + 17,17, 0,21, 0,19,20, 0, 0, 0,20,22, 0,20,20,17, + 17, 0, 0, 0, 0, 0, 0,21,21,17,17, 0,12,12,13,13, + 0,14,14,16,16, 0,14,14,16,16, 0,18,18,21, 0, 0, + 19,19,22, 0, 0,13,13,16,16, 0,16,16,18,18, 0,13, + 13,16,16, 0,18,18,21,22, 0,18,18, 0,22, 0,13,13, + 16,16, 0,17,17,20,18, 0,13,13,16,16, 0,19,18, 0, + 22, 0,18,18,22,21, 0,18,19, 0, 0, 0, 0, 0, 0, 0, + 0,16,16,21,21, 0,21,21, 0, 0, 0,18,19, 0, 0, 0, + 19,19,21, 0, 0, 0, 0, 0, 0, 0,16,16, 0,21, 0,20, + 20, 0, 0, 0,20,20, 0, 0, 0,16,16,21,20, 0,18,17, + 21,22, 0,17,18, 0,21, 0,18,19,22,22, 0,19,19, 0, + 22, 0,16,17,21,22, 0,20,19, 0, 0, 0,16,16,20,21, + 0,19,19, 0, 0, 0,19,19, 0,22, 0,17,17,21,21, 0, + 19,20, 0, 0, 0,16,16, 0,20, 0,19,20, 0,21, 0,18, + 18, 0,22, 0,19,20,22,22, 0, 0, 0, 0,22, 0,17,17, + 0,21, 0,21,21, 0, 0, 0,18,19,23,21, 0,20,19, 0, + 0, 0, 0, 0, 0, 0, 0,17,17, 0,20, 0, 0, 0, 0, 0, + 0,19,19,23,22, +}; + +static const static_codebook _44p4_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p4_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p4_p5_0, + 0 +}; + +static const long _vq_quantlist__44p4_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p4_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p4_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p4_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p4_p5_1, + 0 +}; + +static const long _vq_quantlist__44p4_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p6_0[] = { + 1, 7, 7, 7, 8, 8, 7, 8, 8, 7, 9, 9,11,11,11, 9, + 8, 8, 8, 9, 9,12,11,12, 9, 8, 8, 6, 7, 7,10,11, + 11,10,10,10,11,11,11,14,14,14,12,11,12,11,11,11, + 15,15,14,13,12,12, 5, 6, 6, 8, 5, 5, 8, 7, 7, 8, + 7, 7,12,10,10,10, 7, 6, 9, 8, 8,12,10,10,10, 6, + 6, 7, 8, 8,12,10,10,12,10,10,11,10,10,16,14,14, + 13,10,10,12,10,10,15,14,14,14,10,10, 7, 7, 7,13, + 11,11,13,11,11,12,11,11,16,14,14,14,12,12,12,11, + 11,18,15,15,14,12,12,10, 9,10,14,11,11,13,11,11, + 12,11,11,17,14,14,14,11,11,13,11,11,16,15,15,14, + 11,11, 7, 8, 8,13,11,11,12,10,10,12,10,10,16,14, + 13,13,10,10,12,10,10,17,14,14,14,10,10, 8, 7, 7, + 12,11,11,13,11,11,12,11,11,16,15,14,14,12,12,12, + 11,11,16,15,15,14,12,12,11,10,10,14,11,11,13,11, + 11,13,11,11,17,14,14,14,11,11,13,11,11,18,14,15, + 15,11,10, +}; + +static const static_codebook _44p4_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p4_p6_0, + 0 +}; + +static const long _vq_quantlist__44p4_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p6_1[] = { + 2, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, + 7, 7, 8, 8, 8, 9, 9, 9, 9, 8, 8, 6, 7, 7, 8, 8, + 8, 8, 8, 8, 9, 8, 8, 9, 8, 9, 9, 8, 8,10, 8, 8, + 10, 9, 9,10, 8, 8, 6, 6, 6, 8, 6, 6, 8, 7, 7, 8, + 7, 7,10, 8, 8, 9, 7, 7, 9, 7, 7,10, 8, 8, 9, 7, + 7, 7, 7, 7,10, 8, 8,11, 9, 9,10, 9, 9,11, 9, 9, + 11, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 7, 7, 7,10, + 9, 9,10, 9, 9,10, 9, 9,11,10,10,10, 9, 9,11, 9, + 10,11,10,11,10, 9, 9, 9, 8, 8,10, 9, 9,10, 9, 9, + 11, 9, 9,11,10,10,11, 9, 9,11, 9, 9,11,10,10,11, + 9, 9, 8, 8, 8,11, 9, 9,11, 9, 9,11, 9, 9,12, 9, + 9,12, 8, 8,11, 9, 9,12, 9, 9,12, 8, 8, 8, 7, 7, + 10, 9, 9,10, 9, 9,10, 9, 9,11,11,11,11, 9, 9,11, + 10,10,11,11,11,11, 9, 9,10, 9, 9,11, 9, 9,11, 9, + 10,11,10,10,11,10,10,11, 9, 9,11,10,10,11,10,10, + 11, 9, 9, +}; + +static const static_codebook _44p4_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p4_p6_1, + 0 +}; + +static const long _vq_quantlist__44p4_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 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, +}; + +static const static_codebook _44p4_p7_0 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p7_0, + 1, -513979392, 1633504256, 2, 0, + (long *)_vq_quantlist__44p4_p7_0, + 0 +}; + +static const long _vq_quantlist__44p4_p7_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p4_p7_1[] = { + 1, 9, 9, 7, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, + 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 7, 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, 6, 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, 5, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 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, 5,10, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 8,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10, +}; + +static const static_codebook _44p4_p7_1 = { + 5, 243, + (char *)_vq_lengthlist__44p4_p7_1, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p4_p7_1, + 0 +}; + +static const long _vq_quantlist__44p4_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p4_p7_2[] = { + 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _44p4_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p4_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p4_p7_2, + 0 +}; + +static const long _vq_quantlist__44p4_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p4_p7_3[] = { + 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, +}; + +static const static_codebook _44p4_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p4_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p4_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p4_short[] = { + 3, 5,16, 9, 9,13,18,21, 4, 2,21, 6, 6,10,15,21, + 16,19, 6, 5, 7,10,13,16, 8, 6, 5, 4, 4, 8,13,16, + 8, 5, 6, 4, 4, 7,12,15,13,10, 9, 7, 7, 9,13,16, + 18,15,13,12, 9, 7,10,14,21,18,13,13, 7, 5, 8,12, +}; + +static const static_codebook _huff_book__44p4_short = { + 2, 64, + (char *)_huff_lengthlist__44p4_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p5_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p5_l0_0[] = { + 1, 4, 4, 8, 8,10,10,10,10, 9, 8,11,11, 4, 6, 5, + 8, 6,10,10,10,10,10, 9,10, 9, 4, 5, 6, 6, 9,10, + 10,10,10, 9,10, 9,10, 8, 9, 8, 9, 8, 9, 9,10, 9, + 11,10,12,10, 8, 8, 9, 8, 9, 9, 9, 9,10,10,11,10, + 12, 9,10,10,11,10,11,10,12,11,12,11,13,11, 9,10, + 10,10,11,10,11,11,12,11,12,11,12,11,12,12,12,12, + 13,12,13,12,13,12,13,13,11,12,12,12,12,12,12,12, + 13,13,13,13,13,12,12,12,13,13,13,13,13,13,13,13, + 13,13,12,13,12,13,13,13,13,13,13,13,13,13,13,12, + 13,13,13,14,14,13,13,13,13,13,13,13,12,13,12,13, + 13,13,13,13,13,13,13,13,13, +}; + +static const static_codebook _44p5_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p5_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p5_l0_0, + 0 +}; + +static const long _vq_quantlist__44p5_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p5_l0_1[] = { + 4, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 4, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44p5_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p5_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p5_l0_1, + 0 +}; + +static const long _vq_quantlist__44p5_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_l1_0[] = { + 1, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const static_codebook _44p5_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44p5_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p5_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p5_lfe[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book__44p5_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p5_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p5_long[] = { + 3, 7,12,14,14,16,18,19, 6, 2, 4, 6, 8, 9,12,14, + 12, 3, 3, 5, 7, 8,11,13,13, 6, 4, 5, 7, 8,10,11, + 14, 8, 7, 7, 7, 7, 9,10,15, 9, 8, 7, 7, 6, 8, 9, + 17,11,11,10, 9, 8, 9, 9,19,14,13,11,10, 9, 9, 9, +}; + +static const static_codebook _huff_book__44p5_long = { + 2, 64, + (char *)_huff_lengthlist__44p5_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p5_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p1_0[] = { + 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 8, 9, + 10, 8, 9,10, 8, 9,10, 9,10,12,10,11,11, 8,10,10, + 10,11,11, 9,11,11, 5, 8, 7, 8, 9, 9, 8,10, 9, 8, + 10,10, 9,11,11,10,11,11, 8,10, 9,10,11,11, 9,12, + 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9, 9, 9,10,11, + 9,11,11, 8,10, 9,10,11,11,10,11,11, 7, 9, 9, 9, + 10,11, 9,11,11, 9, 9,11,10,10,13,11,11,12, 9,11, + 11,11,12,13,11,13,12, 7, 9, 9, 9,11,11, 9,11,10, + 9,11,10,10,11,12,11,13,12, 9,11,11,11,12,13,11, + 13,11, 5, 8, 8, 8, 9,10, 7,10, 9, 8, 9,10,10,11, + 11,10,11,11, 7, 9, 9, 9,11,11, 9,11,10, 7, 9, 9, + 9,10,11, 9,11,11, 9,11,11,11,11,13,11,13,12, 9, + 10,11,11,12,13,10,12,11, 7, 9, 9, 9,11,11, 9,11, + 10, 9,11,11,11,12,13,11,13,12, 9,11, 9,11,12,11, + 10,13,10, +}; + +static const static_codebook _44p5_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p5_p1_0, + 0 +}; + +static const long _vq_quantlist__44p5_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p5_p2_0[] = { + 4, 6, 6, 9, 9, 6, 7, 8,10,10, 6, 8, 7,10,10, 8, + 10,10,12,13, 8,10,10,13,12, 6, 7, 8,10,10, 7, 8, + 9,10,11, 8, 9, 9,11,11,10,10,11,12,14,10,11,11, + 14,13, 6, 8, 7,10,10, 8, 9, 9,11,11, 7, 9, 8,11, + 10,10,11,11,13,14,10,11,10,14,12, 9,10,10,12,12, + 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,13, + 14,13,15,14, 9,10,10,12,12,10,11,11,13,13,10,11, + 10,13,12,13,13,14,14,15,12,13,12,15,12, 6, 7, 8, + 10,11, 8, 9,10,11,12, 8, 9, 9,11,12,10,11,12,13, + 14,10,11,11,14,13, 8, 9,10,11,12, 9,10,11,12,13, + 9,10,11,12,13,11,12,13,13,15,12,12,13,15,14, 8, + 9, 9,12,12, 9,10,11,12,13, 9,10,10,13,12,12,12, + 13,14,15,11,12,12,14,14,11,11,12,13,14,11,12,13, + 13,15,12,13,13,14,15,14,13,15,14,16,14,15,15,16, + 16,11,12,11,14,13,12,13,13,15,14,11,13,12,14,13, + 14,15,15,15,16,13,14,14,16,14, 6, 8, 7,11,10, 8, + 9, 9,11,12, 8,10, 9,12,11,10,11,11,13,14,10,12, + 11,14,13, 8, 9, 9,12,12, 9,10,10,12,13, 9,11,10, + 13,12,11,12,12,13,14,12,13,12,15,14, 8,10, 9,12, + 11, 9,11,10,13,12, 9,11,10,13,12,12,13,12,14,15, + 11,13,12,15,13,11,11,12,13,14,11,12,13,13,15,12, + 13,13,14,15,13,14,14,14,16,14,15,15,16,16,11,12, + 11,14,13,12,13,13,15,14,11,13,12,15,13,14,15,15, + 16,16,13,15,13,16,14, 9,10,11,12,14,11,11,12,13, + 15,11,12,12,13,14,13,14,15,15,17,13,14,14,15,16, + 11,11,12,13,15,12,12,13,14,16,12,13,13,14,15,14, + 14,16,15,17,15,15,15,16,17,11,12,12,14,14,12,13, + 13,15,16,12,13,13,15,15,15,15,15,16,17,14,15,15, + 16,16,14,14,15,15,17,14,15,15,15,17,15,15,16,16, + 17,16,16,17,16,18,17,17,17,18,18,14,15,14,16,16, + 15,15,16,17,17,14,15,15,17,16,17,17,17,18,18,16, + 16,16,17,17, 9,11,10,14,12,11,12,12,14,13,11,12, + 11,15,13,13,14,14,16,15,13,15,14,17,15,11,12,12, + 15,14,12,13,13,15,15,12,13,13,15,15,14,15,15,16, + 16,15,15,15,17,16,11,12,11,15,13,12,13,13,15,14, + 12,13,12,16,14,15,15,15,17,16,14,15,14,17,15,14, + 14,15,16,16,14,15,15,16,16,15,16,15,17,17,16,16, + 16,17,17,17,17,17,18,17,14,15,14,16,15,15,15,15, + 17,16,15,15,15,17,15,17,17,17,18,18,16,17,16,18, + 16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,11, + 10,11,11,13,14,10,12,11,14,13, 7, 9, 9,11,12, 9, + 10,10,12,13, 9,10,10,13,13,11,11,12,13,15,11,12, + 12,15,14, 8, 9, 9,12,11, 9,11,10,13,13, 9,11,10, + 13,12,12,13,12,14,15,11,13,12,15,13,10,11,12,13, + 14,11,12,12,13,15,12,12,13,14,15,13,13,14,14,16, + 14,15,15,16,16,11,12,11,14,13,12,13,13,15,14,11, + 13,12,15,13,14,15,15,15,16,13,14,14,16,14, 7, 9, + 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12,12, + 14,15,11,12,12,15,14, 9, 9,11,11,13,10,10,12,12, + 14,10,11,12,13,14,12,12,13,14,16,12,13,13,15,15, + 9,11,10,13,13,10,12,12,13,14,10,12,11,14,13,12, + 13,13,15,16,12,13,13,15,14,11,11,13,13,15,12,12, + 14,13,16,13,13,13,14,15,14,14,15,14,17,15,15,15, + 16,16,12,13,12,15,14,13,14,14,15,15,12,14,13,16, + 14,15,15,16,16,17,14,15,14,17,15, 7, 9, 9,12,11, + 9,10,10,12,13, 9,11,10,13,12,11,12,12,14,14,11, + 13,12,15,14, 9,10,10,13,12,10,10,11,12,13,10,12, + 11,14,13,12,12,13,13,15,12,14,13,16,15, 9,10,10, + 13,12,11,11,12,13,13,10,12,10,14,12,13,13,13,15, + 15,12,13,12,15,13,11,12,12,14,14,12,12,13,14,15, + 13,14,13,15,15,14,13,15,13,16,15,16,15,17,16,12, + 13,12,14,14,13,14,14,15,15,12,13,12,15,14,15,15, + 16,16,17,14,15,13,16,13,10,11,12,13,14,11,12,13, + 14,15,12,13,13,15,15,14,14,15,15,17,14,15,15,16, + 16,12,12,13,12,15,12,12,14,13,16,13,13,14,14,16, + 14,14,16,15,17,15,15,16,16,17,12,13,13,15,15,13, + 14,14,16,16,13,14,13,16,15,15,16,16,17,17,14,15, + 15,17,16,14,14,15,14,17,15,15,16,15,17,15,15,16, + 15,17,16,16,17,16,18,17,17,17,17,18,14,15,15,17, + 16,15,16,16,17,17,15,16,15,17,16,17,17,17,18,18, + 16,17,16,18,17,10,12,11,14,14,12,13,13,15,15,12, + 13,12,15,14,14,15,15,16,16,14,15,15,17,16,11,13, + 12,15,14,12,13,13,15,15,13,14,13,16,14,15,15,15, + 16,16,15,16,15,17,16,12,13,13,15,15,13,14,14,16, + 16,12,14,13,16,15,15,16,16,17,17,15,16,15,17,16, + 14,15,15,16,16,14,15,15,16,16,15,16,16,17,16,16, + 16,16,16,17,17,18,17,18,17,14,15,15,17,16,15,16, + 16,17,17,15,16,15,17,16,17,17,18,18,18,16,17,16, + 18,16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12, + 11,10,11,12,13,14,10,11,11,14,13, 8, 9, 9,11,12, + 9,10,11,12,13, 9,10,11,13,13,11,12,13,13,15,12, + 12,12,15,14, 7, 9, 9,12,11, 9,10,10,13,13, 9,10, + 10,13,12,11,12,12,14,15,11,12,11,15,13,11,11,12, + 13,14,11,12,13,13,15,12,13,13,14,15,13,14,14,14, + 16,14,15,15,16,16,10,12,11,14,13,12,13,12,14,14, + 11,12,12,15,13,14,15,15,16,16,13,14,13,16,14, 7, + 9, 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12, + 13,14,15,11,12,12,14,14, 9,10,10,12,13,10,10,12, + 12,14,11,12,11,13,13,12,12,14,13,15,13,13,13,15, + 15, 9,10,10,12,13,10,11,12,13,14,10,11,10,13,12, + 13,13,14,15,16,12,13,12,15,13,12,13,13,14,14,12, + 12,13,14,15,13,14,14,15,15,14,13,15,13,16,15,16, + 15,17,16,11,12,12,14,14,13,13,14,15,15,12,13,12, + 15,14,15,15,16,16,17,14,14,13,16,13, 7, 9, 9,12, + 11, 9,10,10,12,13, 9,11,10,13,12,11,12,12,14,15, + 11,12,12,15,14, 9,10,11,13,13,10,11,12,13,14,10, + 12,12,14,13,12,13,13,14,16,12,13,13,16,15, 9,11, + 9,13,11,10,12,11,13,13,10,12,10,14,12,12,13,13, + 15,15,12,13,12,16,14,12,12,13,14,15,12,13,14,14, + 15,13,14,14,15,15,14,14,15,15,17,15,16,15,17,16, + 11,13,11,15,13,13,14,13,15,14,12,14,12,16,13,15, + 15,15,16,16,14,15,14,17,14,10,11,12,14,14,12,12, + 13,14,15,12,13,13,15,15,14,15,15,16,17,14,15,15, + 16,16,12,12,13,15,15,13,13,14,15,16,13,14,14,16, + 16,15,15,16,16,17,15,16,16,17,17,11,12,13,14,15, + 13,13,14,15,16,12,13,13,15,15,15,15,16,16,17,15, + 15,15,16,16,14,15,15,16,17,15,15,16,16,17,15,16, + 16,17,17,16,16,17,16,18,17,17,17,18,18,14,15,15, + 16,16,15,16,16,16,17,15,15,15,16,16,17,17,17,18, + 18,16,16,16,17,16,10,12,11,14,13,12,13,13,15,15, + 11,13,12,15,14,14,15,15,16,16,14,15,14,17,15,12, + 13,13,15,15,13,13,14,16,16,13,14,14,16,16,15,15, + 15,16,17,15,16,16,17,17,12,13,12,15,12,13,14,13, + 16,14,12,14,12,16,13,15,16,15,17,16,14,16,14,17, + 15,14,15,15,16,17,15,15,16,17,17,15,16,16,17,17, + 16,16,17,17,18,17,18,17,18,18,14,15,14,17,14,15, + 16,15,17,15,15,16,15,17,15,17,17,17,18,17,16,17, + 16,18,16, 9,11,11,14,14,11,12,12,14,14,11,12,12, + 15,14,13,14,14,16,16,13,15,14,16,16,10,11,12,14, + 14,11,12,13,15,15,12,13,13,15,15,13,14,15,16,17, + 14,15,15,17,16,11,12,12,15,14,12,13,13,15,15,12, + 13,13,15,15,14,15,15,16,16,14,15,15,17,16,12,13, + 14,15,16,13,14,14,15,16,13,14,15,16,16,15,15,16, + 16,18,16,16,16,18,17,14,14,14,16,15,15,15,15,17, + 16,14,15,15,17,16,16,17,17,18,17,16,16,16,18,16, + 10,12,12,14,14,11,12,13,15,15,12,13,13,15,15,13, + 14,15,16,17,14,15,15,17,16,11,12,13,14,15,12,12, + 14,15,16,13,13,14,15,16,14,14,15,16,17,15,15,16, + 17,17,12,13,13,15,15,13,14,14,16,16,13,14,13,16, + 15,15,16,15,17,17,15,16,15,17,16,13,13,15,14,17, + 14,13,16,15,17,15,14,16,15,17,15,15,17,16,18,16, + 16,17,17,18,14,15,15,17,16,15,16,16,17,17,15,16, + 15,17,16,17,17,17,18,18,16,17,16,18,17,10,12,11, + 14,14,11,12,13,15,15,12,13,12,15,15,14,15,15,16, + 16,14,15,15,17,16,11,12,12,15,15,12,13,13,15,15, + 13,14,13,16,15,14,15,15,16,16,15,16,15,17,16,11, + 13,13,15,15,13,14,14,15,15,12,14,13,16,15,15,16, + 15,17,17,15,16,15,17,16,13,15,14,16,16,14,15,14, + 16,16,15,16,15,17,16,15,16,16,16,17,16,17,16,18, + 17,14,15,15,16,16,15,16,16,17,17,15,15,15,17,16, + 17,17,17,18,18,16,16,16,18,16,12,13,13,15,16,13, + 14,14,15,16,13,14,14,16,16,15,15,16,16,18,15,16, + 16,17,17,13,13,14,15,16,14,14,15,15,17,14,15,15, + 16,17,15,15,17,16,18,16,16,17,17,17,13,14,14,16, + 16,14,15,15,17,17,14,15,14,17,16,16,17,16,17,18, + 16,17,16,18,17,15,15,16,14,17,16,15,17,14,18,16, + 16,16,15,18,16,16,18,15,19,18,18,18,17,19,15,16, + 16,18,17,16,17,17,18,17,16,17,16,18,17,18,18,18, + 19,19,17,18,16,18,17,11,12,12,15,15,13,13,14,15, + 16,13,14,13,16,15,15,16,16,16,17,15,16,16,17,16, + 12,14,13,16,15,13,13,14,15,16,14,15,14,17,15,15, + 15,16,16,17,16,17,16,18,17,12,13,14,15,16,14,15, + 15,16,16,13,14,13,16,15,16,16,16,17,17,15,16,15, + 17,15,15,16,15,17,16,15,15,15,16,16,16,17,16,18, + 16,16,15,16,15,17,17,18,17,18,17,15,15,16,17,17, + 16,16,17,17,17,15,16,15,17,16,18,18,18,18,18,16, + 17,16,18,15, 9,11,11,14,14,11,12,12,14,15,10,12, + 12,15,14,13,14,15,16,16,13,14,14,16,16,11,12,12, + 14,15,12,12,13,15,15,12,13,13,15,15,14,15,15,16, + 17,14,15,15,16,16,10,12,12,14,14,12,13,13,15,15, + 11,13,12,15,15,14,15,15,16,17,13,15,14,16,16,14, + 14,14,15,16,14,15,15,16,17,14,15,15,16,17,16,16, + 17,16,18,16,17,17,17,17,12,14,13,16,15,13,15,14, + 16,16,13,14,14,16,15,16,16,16,17,17,15,16,15,17, + 16,10,11,11,14,14,12,12,13,14,15,11,13,12,15,14, + 14,15,15,16,17,14,15,15,16,16,12,13,13,15,15,12, + 13,14,15,16,13,14,14,15,15,15,15,16,16,17,15,15, + 16,17,17,11,12,12,15,15,13,13,14,15,16,12,13,13, + 15,15,15,15,16,16,17,14,15,15,16,16,14,15,15,16, + 16,15,15,15,16,17,15,16,16,17,17,16,16,17,16,18, + 17,17,17,17,18,13,14,15,16,16,15,15,16,16,17,14, + 14,14,16,16,16,16,17,17,18,16,16,16,17,16,10,12, + 12,14,14,12,13,13,15,15,11,13,12,15,15,14,15,15, + 16,17,13,15,14,17,16,12,13,13,15,15,13,13,14,15, + 16,13,14,14,16,16,15,15,16,16,17,15,15,16,17,17, + 11,13,12,15,14,13,14,13,16,15,12,14,12,16,15,15, + 16,15,17,17,14,15,14,17,16,14,15,15,16,17,15,15, + 16,16,17,15,16,16,17,17,16,16,17,17,18,17,17,17, + 18,18,13,15,13,17,14,14,16,14,17,16,14,15,13,17, + 15,16,17,16,18,17,15,17,15,18,16,11,12,12,15,15, + 13,13,14,15,16,13,14,13,16,15,15,16,16,16,17,15, + 16,16,17,16,12,14,13,16,15,13,13,14,15,16,14,15, + 15,16,16,16,15,16,16,17,16,16,16,17,17,12,13,14, + 15,16,14,14,15,15,17,13,14,13,16,15,16,16,17,17, + 18,15,16,15,17,15,15,16,15,17,17,15,15,16,16,17, + 16,17,16,17,17,16,15,17,15,18,17,18,17,18,18,15, + 15,16,16,17,16,16,17,16,18,15,15,15,16,16,17,17, + 18,17,18,16,16,15,17,15,12,13,13,15,15,13,14,14, + 16,16,13,14,14,16,16,15,16,16,17,18,15,16,15,18, + 16,13,14,14,16,16,14,14,15,16,17,14,15,15,17,17, + 16,16,17,17,18,16,16,17,18,17,13,14,13,16,14,14, + 15,15,17,16,14,15,14,17,15,16,17,17,18,17,15,17, + 15,18,16,15,16,16,17,17,16,16,17,17,18,16,17,17, + 18,18,17,16,18,17,19,18,18,18,18,18,15,16,15,17, + 14,16,16,16,18,15,16,17,15,18,14,18,18,18,18,17, + 17,18,16,19,15, +}; + +static const static_codebook _44p5_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p5_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p5_p2_0, + 0 +}; + +static const long _vq_quantlist__44p5_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p3_0[] = { + 1, 5, 6, 5, 7, 8, 5, 8, 7, 5, 7, 8, 7, 8,10, 8, + 10,10, 5, 8, 7, 8,10,10, 7,10, 8, 6, 8, 9, 8,10, + 11, 9,10,10, 9,10,11,10,11,12,11,12,12, 9,11,10, + 11,12,12,10,12,11, 6, 9, 8, 9,10,10, 8,11,10, 9, + 10,11,10,11,12,11,12,12, 9,11,10,11,12,12,10,12, + 11, 6, 9, 9, 8,10,11, 9,11,10, 8,10,10,10,10,12, + 11,12,12, 9,11,10,11,12,12,10,12,11, 8,10,10,10, + 11,12,10,12,11,10,10,12,11,11,13,12,13,13,10,12, + 11,12,13,13,11,13,11, 7,10,10,10,11,12,10,12,11, + 10,12,11,11,11,12,12,14,13,10,12,12,12,14,14,11, + 13,11, 6, 9, 9, 9,10,11, 8,11,10, 9,10,11,10,11, + 12,11,12,12, 8,11,10,11,12,12,10,12,10, 7,10,10, + 10,11,12,10,12,11,10,12,12,11,11,13,12,13,13,10, + 11,12,12,13,14,11,12,11, 8,10,10,10,11,12,10,12, + 11,10,11,12,11,11,13,12,13,13,10,12,10,12,13,13, + 11,13,11, +}; + +static const static_codebook _44p5_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p5_p3_0, + 0 +}; + +static const long _vq_quantlist__44p5_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p3_1[] = { + 5, 6, 6, 6, 7, 7, 6, 7, 7, 6, 7, 7, 7, 7, 8, 7, + 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, + 8, 9, 9, 8, 9, 9, 7, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, + 8, 6, 8, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 9, + 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8, + 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 7, 8, 8, 8, 8, 9, 8, 9, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, 8, + 9, 9, 6, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, + 8, 8, 9, 8, 9, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 8, + 8, 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, + 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, + 9, 9, 9, +}; + +static const static_codebook _44p5_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p5_p3_1, + 0 +}; + +static const long _vq_quantlist__44p5_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p4_0[] = { + 1, 5, 5, 5, 7, 9, 5, 9, 7, 5, 7, 8, 7, 7,10, 9, + 10,10, 5, 8, 7, 9,10,10, 7,10, 7, 6, 8, 9, 9,10, + 12, 9,11,11, 9,10,11,11,11,13,12,13,13, 9,11,11, + 11,12,13,11,13,11, 6, 9, 8, 9,11,11, 9,12,10, 9, + 11,11,11,11,13,11,13,12, 9,11,10,12,13,13,11,13, + 11, 6, 9, 9, 8,10,11, 9,12,11, 9,10,11,10,10,12, + 11,13,13, 9,11,11,11,13,12,11,13,11, 8,10,10, 9, + 10,12,10,12,11,10,10,12,10,10,13,12,13,13,10,12, + 11,12,13,13,10,13,10, 7,10,10,11,11,13,11,14,11, + 10,12,11,11,11,13,13,14,13,10,12,12,14,14,14,11, + 14,11, 6, 9, 9, 9,11,12, 8,11,10, 9,11,11,11,11, + 13,11,12,13, 8,11,10,11,13,13,10,12,10, 7,10,10, + 11,11,14,11,13,11,10,12,12,11,11,14,14,14,14,10, + 11,12,13,13,14,11,13,11, 8,10,10,10,11,12, 9,12, + 10,10,11,12,11,10,13,12,13,13,10,12,10,12,13,13, + 11,13,10, +}; + +static const static_codebook _44p5_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p5_p4_0, + 0 +}; + +static const long _vq_quantlist__44p5_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p5_p4_1[] = { + 5, 7, 7,10,10, 7, 8, 9,10,11, 7, 9, 8,11,10, 9, + 10,10,11,11, 9,10,10,11,11, 7, 9, 9,10,10, 8, 9, + 10,10,11, 9,10,10,11,11,10,10,11,11,11,10,11,11, + 12,12, 7, 9, 9,10,10, 9,10,10,11,11, 8,10, 9,11, + 10,10,11,11,11,11,10,11,10,11,11,10,10,10,11,11, + 10,10,11,11,11,11,11,11,11,11,11,11,12,11,12,11, + 12,11,12,12,10,10,10,11,11,10,11,11,11,11,10,11, + 10,11,11,11,12,11,12,12,11,12,11,12,11, 8, 9, 9, + 11,11, 9,10,10,11,12, 9,10,10,11,11,10,11,11,12, + 12,10,11,11,12,12, 9,10,10,11,11,10,10,11,11,12, + 10,11,11,12,12,11,11,12,12,12,11,12,12,12,12, 9, + 10,10,11,11,10,11,11,12,12,10,11,10,12,12,11,12, + 12,12,12,11,12,12,12,12,11,11,11,12,12,11,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12, 8, 9, 9,11,11, 9, + 10,10,11,11, 9,10,10,11,11,10,11,11,12,12,10,11, + 11,12,12, 9,10,10,11,11,10,10,11,12,12,10,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12, 9,10,10,11, + 11,10,11,11,12,12,10,11,10,12,11,11,12,12,12,12, + 11,12,11,12,12,11,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11, + 11,12,12,11,12,12,12,12,11,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,10,11,11,12,12,11,12,12,12, + 12,11,12,12,12,12,12,12,13,13,13,12,12,12,13,13, + 11,12,12,12,12,12,12,12,12,13,12,12,12,13,13,12, + 12,13,13,13,12,13,13,13,13,11,12,12,12,12,12,12, + 12,13,13,12,12,12,13,13,12,13,13,13,13,12,13,13, + 13,13,12,12,12,12,13,12,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,12,12,12,13,12, + 13,13,13,13,13,12,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,10,11,11,12,12,11,12,12,12,12,11,12, + 11,12,12,12,12,12,13,12,12,12,12,13,13,11,12,12, + 12,12,12,12,12,13,13,12,12,12,13,13,12,13,13,13, + 13,12,13,13,13,13,11,12,12,12,12,12,12,12,13,13, + 12,12,12,13,12,12,13,13,13,13,12,13,12,13,13,12, + 12,12,12,13,12,13,13,13,13,12,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,12,12,12,13,12,13,13,13, + 13,13,12,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13, 8, 9, 9,11,11, 9,10,10,11,11, 9,10,10,12,11, + 10,11,11,12,12,10,11,11,12,12, 9,10,10,11,11,10, + 10,11,11,12,10,11,11,12,12,11,11,12,12,12,11,12, + 12,12,12, 9,10,10,11,11,10,11,11,12,12,10,11,10, + 12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,12, + 12,11,11,12,12,12,11,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12, 9,10, + 10,11,11,10,10,11,12,12,10,11,11,12,12,11,11,12, + 12,12,11,12,12,12,12,10,10,11,11,12,11,11,12,12, + 12,11,11,12,12,12,11,11,12,12,13,12,12,12,12,12, + 10,11,11,12,12,11,12,11,12,12,11,12,11,12,12,12, + 12,12,12,12,12,12,12,12,12,11,11,12,12,12,12,12, + 12,12,12,12,12,12,12,13,12,12,13,12,13,12,12,13, + 13,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,13,12,12,12,12,13,12, 8,10,10,11,11, + 10,11,11,12,12,10,11,10,12,12,11,12,12,12,12,11, + 12,12,12,12,10,11,10,12,12,10,10,11,12,12,11,12, + 12,12,12,12,12,12,12,13,12,12,12,13,13,10,11,11, + 12,12,11,12,12,12,12,10,12,11,12,12,12,12,12,13, + 13,12,13,12,13,12,11,12,12,12,12,11,12,12,12,13, + 12,12,12,13,13,12,12,13,12,13,12,13,13,13,13,11, + 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,13, + 13,13,13,12,13,12,13,12,11,11,11,12,12,11,12,12, + 12,13,11,12,12,12,12,12,12,12,13,13,12,12,13,13, + 13,11,12,12,12,12,12,12,12,12,13,12,12,13,13,13, + 12,12,13,13,13,13,13,13,13,13,11,12,12,12,12,12, + 13,12,13,13,12,12,12,13,13,12,13,13,13,13,12,13, + 13,13,13,12,12,12,12,13,12,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,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,10,11,11,12,12,11,12,12,12,13,11, + 12,12,13,12,12,13,13,13,13,12,13,13,13,13,11,12, + 12,12,12,12,12,12,13,13,12,13,12,13,13,13,13,13, + 13,13,13,13,13,13,13,11,12,12,13,12,12,13,12,13, + 13,12,13,12,13,13,13,13,13,13,13,13,13,13,13,13, + 12,13,13,13,13,12,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,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, 8, 9, 9,11,11, 9,10,10,11,12, 9,10,10,11, + 11,10,11,11,12,12,10,11,11,12,12, 9,10,10,11,11, + 10,10,11,12,12,10,11,11,12,12,11,11,12,12,12,11, + 12,12,12,12, 9,10,10,11,11,10,11,11,12,12,10,11, + 10,12,12,11,12,12,12,12,11,12,11,12,12,11,11,11, + 12,12,11,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12, + 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12, 8, + 10,10,11,11,10,10,11,12,12,10,11,11,12,12,11,12, + 12,12,12,11,12,12,12,12,10,11,11,12,12,10,11,12, + 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13, + 13,10,10,11,12,12,11,12,12,12,12,10,11,10,12,12, + 12,12,12,13,13,12,12,12,13,12,11,12,12,12,12,11, + 12,12,12,13,12,12,12,13,13,12,12,13,12,13,12,13, + 13,13,13,11,12,12,12,12,12,12,12,13,13,11,12,12, + 13,12,12,13,13,13,13,12,13,12,13,12, 9,10,10,11, + 11,10,11,11,12,12,10,11,11,12,12,11,12,12,12,12, + 11,12,11,12,12,10,11,11,12,12,11,11,12,12,12,11, + 11,12,12,12,12,12,12,12,13,12,12,12,13,12,10,11, + 10,12,11,11,12,11,12,12,11,12,11,12,12,12,12,12, + 12,12,12,12,11,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,13,12,13,12,13,13,13,13, + 11,12,11,12,12,12,12,12,13,12,12,12,12,12,12,12, + 13,12,13,13,12,12,12,13,12,10,11,11,12,12,11,12, + 12,12,13,11,12,12,13,12,12,12,13,13,13,12,13,13, + 13,13,11,12,12,12,13,12,12,13,13,13,12,12,13,13, + 13,13,13,13,13,13,13,13,13,13,13,11,12,12,12,12, + 12,12,13,13,13,12,13,12,13,13,13,13,13,13,13,13, + 13,13,13,13,12,13,13,13,13,12,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,13, + 13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,11,11,11,12,12,11,12,12,12,12, + 11,12,12,12,12,12,12,13,13,13,12,13,12,13,13,11, + 12,12,12,12,12,12,13,13,13,12,12,13,13,13,12,13, + 13,13,13,12,13,13,13,13,11,12,12,12,12,12,13,12, + 13,13,12,12,12,13,12,13,13,13,13,13,12,13,12,13, + 13,12,12,12,13,13,12,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,12,12,12,13,12,13, + 13,13,13,13,12,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,10,11,11,12,12,11,12,12,12,12,11,12,12, + 12,12,12,12,12,13,13,12,12,12,13,13,11,12,12,12, + 12,11,12,12,13,13,12,12,12,13,13,12,12,13,13,13, + 12,13,13,13,13,11,12,12,12,12,12,12,12,13,13,12, + 12,12,13,12,12,13,13,13,13,12,13,12,13,13,12,12, + 12,12,12,12,12,13,13,13,12,13,13,13,13,12,13,13, + 13,13,13,13,13,13,13,12,12,12,13,12,12,13,13,13, + 13,12,13,12,13,13,13,13,13,13,13,13,13,13,13,13, + 10,11,11,12,12,11,12,12,12,13,11,12,12,13,12,12, + 12,12,13,13,12,12,12,13,13,11,12,12,12,12,12,12, + 13,13,13,12,12,12,13,13,12,12,13,13,13,12,13,13, + 13,13,11,12,12,12,12,12,12,12,13,13,12,12,12,13, + 13,12,13,13,13,13,12,13,13,13,13,12,12,12,12,13, + 12,12,13,13,13,12,13,13,13,13,12,13,13,13,13,13, + 13,13,13,13,12,12,12,13,13,13,13,13,13,13,12,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,10,11,11, + 12,12,11,12,12,12,13,11,12,12,13,12,12,13,13,13, + 13,12,13,12,13,13,11,12,12,13,13,12,12,12,13,13, + 12,12,13,13,13,12,13,13,13,13,13,13,13,13,13,11, + 12,12,13,12,12,13,12,13,13,12,13,12,13,13,13,13, + 13,13,13,12,13,13,13,13,12,12,12,13,13,12,13,13, + 13,13,12,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,12,12,12,13,13,12,13,13,13,13,12,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,11,11,11,12,12,11, + 12,12,12,12,11,12,12,12,12,12,12,12,13,13,12,12, + 12,13,13,11,12,12,12,12,12,12,12,12,13,12,12,12, + 13,13,12,12,13,13,13,12,13,13,13,13,11,12,12,12, + 12,12,12,12,13,13,12,12,12,13,12,12,13,13,13,13, + 12,13,12,13,13,12,12,12,12,12,12,12,13,12,13,12, + 13,13,13,13,12,13,13,12,13,13,13,13,13,13,12,12, + 12,12,12,12,13,13,13,13,12,13,12,13,13,13,13,13, + 13,13,12,13,13,13,12,10,11,11,12,12,11,12,12,12, + 12,11,12,12,12,12,12,12,12,13,13,12,13,12,13,13, + 11,12,12,12,12,12,12,12,13,13,12,12,12,13,13,12, + 12,13,13,13,13,13,13,13,13,11,12,12,12,12,12,13, + 12,13,13,12,13,12,13,13,12,13,13,13,13,12,13,12, + 13,13,12,12,12,12,12,12,13,13,13,13,12,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,12,12,12,13,12, + 12,13,13,13,13,12,13,12,13,13,13,13,13,13,13,13, + 13,13,13,13,10,11,11,12,12,11,12,12,12,12,11,12, + 12,12,12,12,12,12,13,13,12,12,12,13,13,11,12,12, + 12,12,12,12,12,13,13,12,12,12,13,13,12,12,13,13, + 13,12,12,13,13,13,11,12,11,12,12,12,12,12,13,13, + 11,12,12,13,13,12,13,13,13,13,12,13,12,13,13,12, + 12,12,12,12,12,13,13,13,13,12,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,12,12,12,13,12,12,13,13, + 13,13,12,13,12,13,13,13,13,13,13,13,12,13,13,13, + 13,10,11,11,12,12,11,12,12,12,13,11,12,12,13,12, + 12,12,13,13,13,12,13,13,13,13,11,12,12,13,13,12, + 12,13,13,13,12,12,13,13,13,12,13,13,13,13,13,13, + 13,13,13,11,12,12,13,12,12,13,12,13,13,12,12,12, + 13,13,12,13,13,13,13,13,13,13,13,13,12,12,13,13, + 13,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,12,12,12,13,13,13,13,13,13,13,12, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,10,12, + 11,12,12,11,12,12,12,13,11,12,12,12,12,12,12,12, + 13,13,12,12,12,13,13,11,12,12,12,13,12,12,12,13, + 13,12,12,12,13,13,12,13,13,13,13,12,13,13,13,13, + 11,12,12,13,12,12,12,12,13,13,12,12,12,13,13,12, + 13,13,13,13,12,13,12,13,13,12,13,12,13,13,12,13, + 13,13,13,12,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,12,12,12,13,12,13,13,13,13,13,12,13,12,13, + 13,13,13,13,13,13,12,13,13,13,13,10,11,11,12,12, + 11,12,12,12,13,11,12,12,12,12,12,12,12,13,13,12, + 12,12,13,13,11,12,12,12,12,12,12,13,13,13,12,13, + 13,13,13,12,12,13,13,13,13,13,13,13,13,11,12,12, + 12,12,12,13,12,13,13,12,12,12,13,13,12,13,13,13, + 13,12,13,12,13,13,12,12,12,12,13,12,13,13,13,13, + 12,13,13,13,13,12,13,13,13,13,13,13,13,13,13,12, + 12,12,12,12,12,13,13,13,13,12,13,13,13,13,13,13, + 13,13,13,12,13,13,13,13,11,12,11,12,12,11,12,12, + 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13, + 12,11,12,12,12,12,12,12,12,12,13,12,12,12,13,13, + 12,12,13,13,13,12,13,13,13,13,11,12,12,12,12,12, + 12,12,13,13,12,12,12,13,12,12,13,13,13,13,12,13, + 12,13,13,12,12,12,12,12,12,12,13,13,13,12,13,13, + 13,13,13,13,13,12,13,13,13,13,13,13,12,12,12,12, + 12,12,13,13,13,13,12,13,12,13,12,13,13,13,13,13, + 13,13,13,13,12, +}; + +static const static_codebook _44p5_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p5_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p5_p4_1, + 0 +}; + +static const long _vq_quantlist__44p5_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p5_p5_0[] = { + 1, 6, 6,10,10, 6, 7, 9,11,13, 5, 9, 7,13,11, 8, + 11,12,13,15, 8,12,11,15,13, 6, 7, 8,11,11, 7, 8, + 10,11,13, 9,10,10,13,13,11,11,13,12,16,12,13,13, + 16,15, 6, 8, 7,11,11, 9,10,10,13,13, 7,10, 7,13, + 11,12,13,13,15,16,11,13,11,16,12,10,11,11,11,13, + 11,11,13,12,15,13,13,13,14,15,13,12,15,12,17,15, + 16,16,16,16,10,11,11,14,11,13,13,13,15,14,11,13, + 11,15,12,15,15,16,16,16,13,15,12,17,12, 6, 8, 9, + 12,12, 9,10,12,13,15, 9,11,11,15,14,12,13,15,16, + 18,13,14,14,17,16, 9,10,11,13,14,11,10,13,14,16, + 11,12,12,15,15,14,13,16,15,18,14,15,15,17,17, 9, + 11,11,14,14,11,12,13,15,16,11,13,11,15,14,15,15, + 15,17,18,14,15,14,17,15,13,14,14,15,16,14,14,15, + 15,17,15,16,15,17,17,16,16,17,15,19,17,18,18,19, + 18,13,14,14,16,15,15,15,16,17,17,14,15,14,18,15, + 17,17,17,19,19,16,17,15,19,16, 6, 9, 8,13,12, 9, + 11,11,14,15, 9,12,10,15,13,13,14,14,16,17,12,15, + 13,18,16, 9,11,11,14,14,11,11,13,14,15,11,13,12, + 16,15,14,14,15,15,18,14,15,15,18,17, 9,11,10,14, + 13,11,12,12,15,15,11,13,10,16,14,14,15,15,16,18, + 14,16,13,18,15,13,14,14,16,16,14,14,15,15,17,15, + 16,15,17,17,16,16,17,16,19,17,18,17,18,19,13,14, + 14,16,15,15,15,15,17,17,14,15,14,17,15,17,17,17, + 18,19,16,17,15,19,15,11,13,13,15,16,13,14,15,16, + 18,14,15,15,17,17,16,16,18,18,20,17,18,17,19,20, + 13,14,14,16,17,15,15,16,17,18,15,16,16,17,17,18, + 17,19,18,19,18,18,18,19,21,14,14,15,16,17,15,15, + 16,18,18,15,16,16,17,18,18,18,19,19,21,18,19,19, + 22,20,16,16,17,17,19,17,17,17,18,20,17,18,18,20, + 19,19,19,20,19, 0,19,19,20,20,21,17,17,17,19,18, + 18,18,20,19,19,18,18,18,20,20,19,19,20,20,20,20, + 21,20,21,19,11,13,13,16,15,14,15,15,17,17,14,15, + 14,18,16,16,18,18,20,19,16,19,17,21,18,13,14,15, + 16,17,15,15,16,18,18,15,16,15,19,18,18,18,18,19, + 19,18,18,18,22,20,13,14,14,16,16,15,16,16,18,17, + 15,16,15,18,17,18,18,18,19,19,17,18,17,21,18,16, + 17,17,18,18,17,18,19,19,19,18,20,18,19,19,19,20, + 21,19,21,20,20,20, 0,21,16,17,17,19,19,18,18,18, + 19,21,17,18,18,19,18,20,19,21,20,21,19,20,20,22, + 19, 7, 9, 9,13,13, 8,10,11,14,15, 9,12,11,15,14, + 11,13,14,16,17,13,15,14,17,16, 8,10,11,14,14,10, + 10,12,14,16,11,12,12,16,15,13,12,15,15,18,14,15, + 15,19,17, 9,11,11,14,14,11,12,12,15,15,11,13,11, + 16,14,14,15,14,17,17,14,16,14,18,15,12,13,14,15, + 16,13,13,15,14,17,15,15,15,17,17,15,14,17,14,19, + 17,18,18,19,18,13,14,14,16,16,15,15,15,17,17,14, + 15,14,18,15,17,18,17,18,17,16,18,16,19,15, 7,10, + 10,13,13, 9,10,12,14,15,10,12,11,15,14,12,13,14, + 16,17,13,15,14,18,16,10,10,12,13,14,10,10,13,13, + 16,12,12,13,15,15,13,12,15,15,18,15,15,16,18,17, + 10,11,11,14,14,12,13,13,15,16,10,13,10,16,14,14, + 15,15,17,17,14,15,13,17,15,13,13,14,15,16,14,13, + 15,14,18,15,15,16,16,17,16,15,18,15,18,17,18,18, + 18,18,13,15,14,17,16,15,16,16,17,17,14,15,13,17, + 15,17,17,18,18,18,16,17,14,20,14, 8,10,10,14,14, + 11,11,13,14,16,11,13,11,16,14,14,15,16,16,18,14, + 16,15,18,16,10,12,11,15,14,11,11,13,14,16,13,14, + 13,16,15,15,14,16,15,19,16,17,16,20,18,10,11,12, + 14,15,13,13,14,16,16,11,14,11,16,14,16,16,17,18, + 19,15,17,14,20,15,14,15,14,17,16,13,14,15,15,18, + 16,17,16,19,18,16,15,18,15,19,18,19,18,21,21,14, + 14,15,16,17,16,16,17,18,18,13,15,14,17,15,18,18, + 19,18,22,16,18,15,21,15,12,13,14,16,16,14,14,16, + 16,18,14,15,15,17,18,16,16,18,18,20,18,18,17,20, + 20,13,14,15,15,17,15,14,16,16,18,16,16,16,17,19, + 17,15,18,17,21,18,18,18,19,19,14,15,15,18,17,15, + 16,16,18,19,15,16,15,18,18,17,18,18,20,21,17,19, + 17,20,19,16,16,17,16,19,17,17,18,17,20,18,18,18, + 18,19,19,18,20,17,22,20,20,19,20,20,17,17,18,18, + 19,18,18,20,21,20,17,18,17,20,20,21,21,21,21,21, + 19,21,18,22,20,11,13,13,17,16,14,14,16,16,18,14, + 16,14,18,16,17,18,19,19,20,18,19,18,21,19,14,15, + 14,17,16,14,14,16,18,18,16,17,16,18,17,18,17,19, + 18,20,19,19,18,20,20,13,14,15,16,17,16,16,17,18, + 19,14,16,14,19,17,18,19,18,20,20,18,20,17,21,18, + 17,17,17,19,18,16,17,18,18,19,18,19,18,21,21,18, + 18,20,17,21,19,20,20,22,21,16,17,18,18,19,18,18, + 19,21,20,16,17,17,20,18,21,21,22,21,22,18,21,18, + 0,18, 7, 9, 9,13,13, 9,11,12,14,15, 8,11,10,15, + 14,13,14,15,16,18,11,14,13,17,15, 9,11,11,14,14, + 11,11,13,14,16,11,12,12,15,15,14,14,16,15,18,14, + 14,15,17,17, 8,11,10,14,14,11,12,12,15,15,10,12, + 10,16,14,14,15,15,17,18,13,15,12,18,15,13,14,14, + 16,16,14,14,15,15,17,15,15,15,16,17,16,15,17,15, + 19,17,17,17,18,18,12,14,13,16,15,15,15,15,17,17, + 13,15,13,17,14,17,18,18,18,19,15,17,14,19,14, 8, + 10,10,14,14,11,11,13,14,16,11,13,11,16,14,14,15, + 16,17,19,14,16,15,18,17,10,12,11,15,14,11,11,14, + 14,17,13,14,13,17,15,15,14,17,15,19,16,17,16,19, + 17,10,11,12,14,15,13,13,14,15,17,11,13,11,17,14, + 16,16,17,18,19,15,16,14,18,15,14,15,14,16,16,13, + 14,15,15,18,16,16,16,18,18,16,15,18,15,20,18,19, + 18,21,18,14,14,15,16,17,16,16,17,17,18,13,15,14, + 17,16,19,19,19,19,19,15,18,15,20,15, 7,10,10,13, + 13,10,11,12,14,15, 9,12,10,15,14,13,14,15,16,17, + 12,15,13,17,16,10,11,11,14,14,10,10,13,14,16,12, + 13,13,16,15,14,13,16,15,18,15,15,16,17,17,10,12, + 10,14,13,12,13,12,15,15,10,13,10,16,13,15,16,15, + 17,18,13,16,12,18,15,13,14,14,16,17,14,13,15,15, + 18,15,16,15,17,17,16,14,17,15,19,17,18,18,19,19, + 13,15,13,17,14,15,15,15,18,17,14,15,13,17,14,18, + 17,18,18,19,15,17,15,19,15,11,13,13,16,17,14,14, + 16,16,18,14,16,15,18,17,17,18,19,18,21,18,18,17, + 20,18,13,15,14,17,16,14,14,16,17,18,16,17,16,19, + 17,18,17,19,18,22,18,19,19,21,21,13,14,15,16,18, + 16,16,17,17,20,14,16,14,18,17,18,18,19,19,21,17, + 18,17,21,18,17,18,17,19,18,16,17,17,18,19,18,18, + 18,22,22,18,17,19,17, 0,20,21,19,21,20,17,17,18, + 18,21,18,18,18,19,21,17,17,17,19,19,20,20,22,21, + 21,19,20,18,20,17,12,14,13,17,16,14,15,15,17,18, + 14,16,14,18,16,17,18,18,21,20,16,18,16,21,18,14, + 15,15,17,17,15,15,16,18,18,15,17,16,18,18,17,17, + 19,19,20,18,19,18,20,19,14,15,14,17,15,15,16,16, + 18,17,15,16,14,19,15,18,18,18,19,20,17,20,15,21, + 17,16,17,18,18,19,17,17,18,18,20,18,19,18,19,21, + 19,18,19,19,21,20, 0,19,21,20,16,17,16,19,16,18, + 18,18,19,19,17,18,17,20,17,19,20,20,22, 0,19,20, + 17,21,17,11,13,14,16,17,14,15,15,17,18,14,15,15, + 18,18,16,17,17,19,20,16,18,17,19,21,13,14,15,17, + 17,14,15,16,17,19,15,16,16,18,19,16,17,18,19,21, + 17,18,20,21,21,13,15,15,17,17,15,16,16,18,19,15, + 16,16,18,19,17,17,18,19,22,17,19,18,22,19,15,16, + 17,19,19,16,17,18,18,20,17,18,18,19,20,19,18,20, + 18,22,20,19,19,22,21,16,17,17,18,19,18,18,18,19, + 20,17,18,18,20,19,20,19,20,22,20,19,20,21,21,20, + 12,14,14,16,16,13,14,16,17,18,14,16,15,18,18,15, + 17,17,19,19,17,18,18,19,19,13,14,15,16,17,14,14, + 16,16,20,15,16,16,17,19,16,15,18,17,20,18,17,19, + 19,19,14,15,15,17,17,16,16,16,18,18,15,16,15,19, + 18,17,18,18,20,21,17,18,17,21,18,16,15,17,17,19, + 17,15,18,17,20,19,17,18,19,20,18,16,19,17,22,20, + 19,20,19,20,17,17,18,19,19,18,18,19,20,20,17,18, + 17,18,18,21,21,20,20,21,18,20,17,21,19,11,14,14, + 16,17,15,14,16,17,19,14,16,14,18,17,18,18,19,19, + 21,17,19,18,20,20,13,15,14,17,17,14,14,16,17,18, + 16,17,16,19,18,18,17,19,18,20,18,21,18,20,20,13, + 15,15,16,17,16,16,17,18,19,14,16,15,19,18,19,19, + 19,21,20,18,19,17,20,18,16,17,16,19,18,16,17,17, + 19,20,17,19,18,20,19,18,17,21,18, 0,21,20,20, 0, + 20,17,17,18,18,19,18,19,19,20,22,16,17,17,20,18, + 21,22,20,20,22,18,22,18,22,18,12,14,14,17,17,14, + 15,16,17,19,14,16,15,17,17,17,17,18,18,21,17,19, + 17,20,19,14,15,15,16,18,15,14,16,16,19,16,17,16, + 19,18,17,16,20,17,20,18,20,19,19,20,14,15,15,18, + 17,16,16,17,18,19,14,16,15,19,17,18,21,18,19,21, + 17,18,17,19,18,17,17,18,17,20,17,16,18,17,21,18, + 19,19,19,19,18,17,19,17,20,20,21,20,21,20,17,17, + 17,19,19,19,18,18,20,21,16,18,16,19,18,20,20,21, + 21,20,18,19,16, 0,17,12,14,14,17,17,15,15,18,17, + 19,15,18,15,20,16,20,19,21,18,22,20,20,20,22,19, + 14,16,14,20,17,14,15,17,17,20,18,18,17,20,18,18, + 17,19,17,21,20,21,20, 0,21,14,15,16,17,19,18,17, + 19,18,21,14,18,15,21,17,21,20,21,20, 0,18,21,17, + 21,17,18,19,17,20,18,16,17,17,19,19,19,21,20, 0, + 20,18,17,21,17, 0,22, 0,21, 0,22,17,17,19,18,20, + 20,20,21,19,22,16,17,18,20,18,22,22, 0,22, 0,17, + 21,17,22,17,11,14,13,16,16,14,15,15,17,18,14,15, + 14,18,17,17,18,18,19,20,16,17,17,21,19,13,14,15, + 17,17,15,16,16,18,18,15,16,16,19,18,18,18,18,19, + 20,17,18,18,20,19,13,15,14,17,17,15,16,16,17,18, + 14,16,15,19,17,17,18,19,21,21,17,18,17,20,18,16, + 17,17,19,19,17,18,19,19,20,18,19,18,21,21,21,20, + 19,21,22,20,20,19,21,20,15,17,16,19,19,17,18,18, + 20,21,16,18,17,20,18,19,19,21,21,21,19,19,19,20, + 18,11,14,13,17,16,14,14,16,16,19,14,16,15,19,16, + 18,18,18,19,22,17,18,17,20,19,13,15,14,17,17,15, + 15,16,17,19,16,17,16,20,18,18,17,19,18,21,19,19, + 18,22, 0,13,14,15,17,18,16,16,17,17,19,14,16,15, + 19,18,18,19,19,20,21,18,18,17,20,18,17,18,17,20, + 18,16,17,17,18,20,18,19,18,20,20,18,18,21,17,21, + 20,21,21, 0,19,16,16,18,18,19,19,18,20,19,20,16, + 17,17,20,18,21,20,21,22,22,18,20,17,21,17,12,14, + 14,17,16,14,15,16,18,18,13,15,14,18,17,17,18,18, + 19,19,15,17,16,19,19,14,15,15,17,17,15,15,16,18, + 19,15,16,16,19,18,17,17,18,18,20,18,18,18,21,20, + 13,15,14,17,16,15,16,15,18,18,14,16,14,18,17,18, + 18,18,19,21,16,18,16,20,17,17,18,17,18,19,17,17, + 18,18,19,18,19,19,21,19,19,18,20,18,21,21,20,20, + 21,20,16,17,15,20,17,17,19,17,19,19,17,18,15,20, + 17,19,20,19,21,22,17,20,16, 0,17,12,14,14,17,18, + 16,15,18,16,20,16,18,15,21,17,20,18,21,19,22,19, + 21,19, 0,19,14,16,15,19,17,14,15,17,16,21,18,19, + 18,21,17,19,17,21,17,22,20,21,21, 0,21,14,15,16, + 17,19,18,17,19,18,21,14,17,15,20,17,21,22,21,20, + 22,18,21,17,21,17,17,19,17,21,18,16,17,17,19,20, + 19,21,20,21,20,17,18,20,17,21, 0,22,20,21,22,17, + 17,20,18,21,21,20,22,20,21,16,17,17,21,19, 0,22, + 0,21,21,18,22,17,21,17,12,14,14,17,16,14,15,16, + 17,18,14,16,15,18,17,17,17,20,19,20,16,18,17,21, + 18,14,15,15,17,17,14,15,16,17,19,16,17,16,18,18, + 17,16,19,18,19,18,19,18,21,20,14,15,15,18,17,16, + 16,16,19,18,15,16,14,20,16,18,18,19,19,20,16,19, + 16,21,17,17,17,18,19,19,16,16,18,18,19,19,19,18, + 20,20,18,16,19,18,20,22,21,20,19,20,16,18,17,20, + 16,18,19,18,19,18,16,18,16,20,17,21,20,21,20,20, + 18,19,17,21,16, +}; + +static const static_codebook _44p5_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p5_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p5_p5_0, + 0 +}; + +static const long _vq_quantlist__44p5_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p5_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p5_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p5_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p5_p5_1, + 0 +}; + +static const long _vq_quantlist__44p5_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p6_0[] = { + 1, 5, 5, 5, 7, 9, 5, 9, 7, 5, 7, 8, 7, 7,10, 9, + 9,10, 5, 8, 7, 9,10, 9, 7,10, 7, 6, 9, 9, 9,10, + 12,10,12,11, 9,10,11,11,10,13,12,12,13,10,11,11, + 12,13,13,11,13,11, 6, 9, 9,10,11,12, 9,12,11,10, + 11,11,11,11,13,12,13,13, 9,11,10,12,13,13,11,13, + 10, 6, 9,10, 9,11,12,10,12,11, 9,10,11,10,10,13, + 11,13,13,10,11,11,12,13,12,11,13,11, 7, 9,10, 9, + 10,12,10,11,11,10,10,11,10,10,12,12,11,12,10,11, + 10,12,12,12,10,12,10, 7,10,10,11,11,13,11,13,11, + 10,12,11,11,10,13,13,14,13,10,11,12,13,13,14,11, + 13,10, 6,10, 9,10,11,12, 9,12,11, 9,11,11,11,11, + 13,12,12,13, 9,11,10,12,13,13,10,13,10, 7,10,10, + 11,11,14,11,13,11,10,12,11,11,10,14,13,14,13,10, + 11,12,13,13,14,11,13,10, 7,10, 9,10,10,12, 9,12, + 10,10,11,11,10,10,12,12,12,12, 9,11,10,11,12,12, + 10,12, 9, +}; + +static const static_codebook _44p5_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p5_p6_0, + 0 +}; + +static const long _vq_quantlist__44p5_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p6_1[] = { + 2, 6, 6, 5, 7, 8, 5, 8, 7, 6, 7, 7, 7, 7, 8, 8, + 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 7, 6, 8, 8, 8, 9, + 10, 8, 9, 9, 8, 9, 9, 9, 9,10,10,10,10, 8, 9, 9, + 10,10,10, 9,10,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 9, + 9, 9, 9, 9,10,10,10,10, 8, 9, 9,10,10,10, 9,10, + 9, 6, 8, 9, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9,10, + 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 8, 9, 8, + 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 7, 9, 9, 9,10,10, 9,10,10, + 9,10, 9, 9, 9,10,10,10,10, 9,10, 9,10,10,10, 9, + 10, 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9, + 10, 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9, + 9,10,10, 9,10, 9, 9, 9,10,10, 9,10,10,10,10, 9, + 9, 9,10,10,10, 9,10, 9, 7, 9, 8, 8, 9, 9, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, + 9, 9, 9, +}; + +static const static_codebook _44p5_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p5_p6_1, + 0 +}; + +static const long _vq_quantlist__44p5_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 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, +}; + +static const static_codebook _44p5_p7_0 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p7_0, + 1, -513979392, 1633504256, 2, 0, + (long *)_vq_quantlist__44p5_p7_0, + 0 +}; + +static const long _vq_quantlist__44p5_p7_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p5_p7_1[] = { + 1, 7, 7, 6, 9, 9, 7, 9, 9, 6, 9, 9, 9, 9, 9, 9, + 9, 9, 8, 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, 8, 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, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 7, 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,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10, +}; + +static const static_codebook _44p5_p7_1 = { + 5, 243, + (char *)_vq_lengthlist__44p5_p7_1, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p5_p7_1, + 0 +}; + +static const long _vq_quantlist__44p5_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p5_p7_2[] = { + 1, 2, 3, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11, + 11,12,12,13,13,14,14,14,14, +}; + +static const static_codebook _44p5_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p5_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p5_p7_2, + 0 +}; + +static const long _vq_quantlist__44p5_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p5_p7_3[] = { + 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, +}; + +static const static_codebook _44p5_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p5_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p5_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p5_short[] = { + 4, 7,12,14,15,18,20,20, 5, 3, 4, 6, 9,11,15,19, + 9, 4, 3, 4, 7, 9,13,18,11, 6, 3, 3, 5, 8,13,19, + 14, 9, 6, 5, 7,10,16,20,16,11, 9, 8,10,10,14,16, + 21,14,13,11, 8, 7,11,14,21,14,13, 9, 6, 5,10,12, +}; + +static const static_codebook _huff_book__44p5_short = { + 2, 64, + (char *)_huff_lengthlist__44p5_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p6_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p6_l0_0[] = { + 1, 4, 4, 7, 7,10,10,12,12,12,12,13,12, 5, 5, 5, + 8, 6,11, 9,12,12,13,12,12,12, 4, 5, 5, 6, 8, 9, + 11,12,12,13,12,12,12, 7, 7, 8, 9, 9,11, 8,12, 9, + 12,12,12,12, 7, 8, 8, 9, 9, 8,11, 9,12,12,12,11, + 12,10,10,10,11,11,11,11,11,10,11,11,12,11,10,10, + 10,11,11,11,11,10,11,11,11,11,12,11,11,11,12,11, + 12,11,12,11,13,11,13,11,11,11,11,11,12,11,12,10, + 13,11,12,11,13,12,12,12,13,12,13,13,13,12,14,12, + 14,13,12,12,12,12,13,13,13,12,14,12,14,13,14,13, + 14,14,14,14,14,14,14,14,15,14,15,14,13,14,13,14, + 14,14,14,14,15,14,14,14,15, +}; + +static const static_codebook _44p6_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p6_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p6_l0_0, + 0 +}; + +static const long _vq_quantlist__44p6_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p6_l0_1[] = { + 4, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, + 5, 5, 4, 5, 5, 5, 5, 5, 4, +}; + +static const static_codebook _44p6_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p6_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p6_l0_1, + 0 +}; + +static const long _vq_quantlist__44p6_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_l1_0[] = { + 1, 3, 2, 5, 5, 6, 6, 6, 6, +}; + +static const static_codebook _44p6_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44p6_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p6_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p6_lfe[] = { + 2, 3, 1, 3, +}; + +static const static_codebook _huff_book__44p6_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p6_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p6_long[] = { + 2, 7,13,15,16,17,19,20, 6, 3, 4, 7, 9,10,12,15, + 13, 4, 3, 4, 7, 8,11,13,14, 7, 4, 4, 6, 7,10,11, + 16, 9, 7, 6, 7, 8, 9,10,16, 9, 8, 7, 7, 6, 8, 8, + 18,12,10,10, 9, 8, 8, 9,20,14,13,12,11, 8, 9, 9, +}; + +static const static_codebook _huff_book__44p6_long = { + 2, 64, + (char *)_huff_lengthlist__44p6_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p6_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p1_0[] = { + 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 8, 9, + 10, 8, 9, 9, 8, 9,10, 9,10,12,10,11,11, 8, 9,10, + 10,11,11, 9,11,11, 5, 8, 7, 8, 9, 9, 8,10, 9, 8, + 10, 9, 9,11,11,10,11,11, 8,10, 9,10,11,11, 9,12, + 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9, 9, 9,10,11, + 9,11,11, 8,10,10,10,11,11,10,12,11, 7, 9, 9, 9, + 10,11, 9,11,11, 9, 9,11,10,10,13,11,11,12, 9,11, + 11,11,12,13,11,13,12, 7, 9, 9, 9,11,11, 9,12,10, + 9,11,10,10,11,12,11,13,12, 9,11,11,11,13,13,11, + 13,11, 5, 8, 8, 8, 9,10, 7,10, 9, 8,10,10,10,11, + 11,10,11,11, 7, 9, 9, 9,11,11, 9,11,10, 7, 9, 9, + 9,10,12, 9,11,11, 9,11,11,11,11,13,11,13,13, 9, + 10,11,11,12,13,10,12,11, 7, 9, 9, 9,11,11, 9,11, + 10, 9,11,11,11,12,13,11,13,12, 9,11, 9,11,12,11, + 10,13,10, +}; + +static const static_codebook _44p6_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p6_p1_0, + 0 +}; + +static const long _vq_quantlist__44p6_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p6_p2_0[] = { + 4, 6, 6, 9, 9, 6, 7, 8,10,10, 6, 8, 7,10,10, 8, + 10,10,12,13, 8,10,10,13,12, 6, 8, 8,10,10, 7, 8, + 9,10,11, 8, 9, 9,11,11,10,10,11,12,13,10,11,11, + 14,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 9, 8,11, + 10,10,11,11,13,14,10,11,10,13,12, 9,10,10,12,12, + 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,13, + 14,13,15,14, 9,10,10,13,12,10,11,11,13,13,10,11, + 10,13,12,13,13,14,14,15,12,13,12,15,12, 6, 8, 8, + 10,11, 8, 9,10,11,12, 8, 9, 9,11,11,10,11,12,13, + 14,10,11,11,14,13, 8, 9, 9,11,12, 9,10,11,12,13, + 9,10,11,12,13,11,11,13,13,15,11,12,12,14,14, 8, + 9, 9,12,12, 9,10,11,12,13, 9,10,10,13,12,11,12, + 13,14,15,11,12,12,14,14,11,11,12,13,14,11,12,13, + 13,15,12,13,13,14,15,13,13,14,14,16,14,15,15,16, + 16,11,12,11,14,13,12,13,13,14,14,11,13,12,14,13, + 14,15,15,16,16,13,14,14,16,14, 6, 8, 8,11,10, 8, + 9, 9,12,11, 8,10, 9,12,11,10,11,11,13,13,10,12, + 11,14,13, 8, 9, 9,12,12, 9,10,10,12,13, 9,11,10, + 13,12,11,12,12,14,14,11,13,12,15,14, 8, 9, 9,12, + 11, 9,10,10,13,12, 9,11,10,13,12,12,12,12,14,14, + 11,13,12,15,13,11,11,12,13,14,11,12,13,13,14,12, + 13,13,14,15,13,13,14,14,16,14,15,15,16,16,11,12, + 11,14,13,12,13,13,15,14,11,13,12,15,13,14,15,15, + 16,16,13,15,13,16,14, 9,10,11,12,13,11,11,12,13, + 14,11,12,12,13,14,13,13,14,14,16,13,14,14,15,16, + 11,11,12,13,14,12,12,13,14,15,12,13,13,14,15,14, + 14,15,15,17,14,15,15,16,17,11,12,12,14,14,12,13, + 13,14,15,12,13,12,15,15,14,15,15,16,17,14,15,15, + 16,16,13,14,14,15,16,14,14,15,15,17,15,15,15,16, + 17,16,16,17,16,18,16,17,17,18,18,13,14,14,16,15, + 14,15,15,17,16,14,15,15,16,16,16,17,17,18,18,16, + 16,16,17,16, 9,11,10,13,12,11,12,12,14,13,11,12, + 11,15,13,13,14,14,16,15,13,14,13,17,14,11,12,12, + 14,14,12,12,13,15,15,12,13,13,15,14,14,14,15,16, + 16,14,15,15,17,16,11,12,11,14,13,12,13,13,15,14, + 12,13,12,15,13,14,15,15,16,16,14,15,14,17,15,13, + 14,14,15,16,14,15,15,16,17,14,15,15,16,17,16,16, + 16,17,17,16,17,17,18,18,13,15,14,16,15,15,15,15, + 17,16,14,15,14,17,15,16,17,17,18,18,16,17,16,18, + 16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,11, + 10,11,11,13,14,10,12,11,14,13, 7, 9, 9,11,12, 9, + 10,10,12,13, 9,10,10,13,12,11,11,12,13,15,11,12, + 12,15,14, 8, 9, 9,12,11, 9,10,10,13,13, 9,11,10, + 13,12,12,12,12,14,15,11,13,12,15,13,10,11,11,13, + 14,11,12,12,13,15,11,12,12,14,14,13,13,14,14,16, + 14,15,14,16,16,11,12,11,14,13,12,13,13,15,14,11, + 13,12,15,13,14,15,15,16,16,13,14,14,16,14, 8, 9, + 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12,13, + 14,15,11,12,12,15,14, 9, 9,11,11,13,10,10,12,12, + 14,10,10,11,13,14,12,12,13,14,16,12,13,13,15,15, + 9,11,10,13,12,10,11,11,13,14,10,12,11,14,13,12, + 13,13,15,16,12,13,13,15,15,11,11,13,13,15,12,12, + 14,13,15,13,13,14,14,15,14,14,15,14,17,15,15,15, + 16,16,12,13,12,15,14,13,14,14,15,15,12,14,13,15, + 14,15,15,15,17,17,14,15,14,17,15, 7, 9, 9,12,11, + 9,10,10,12,12, 9,11,10,13,12,11,12,12,14,14,11, + 13,12,15,14, 9,10,10,12,12,10,10,11,12,13,10,11, + 11,14,13,12,12,13,14,15,12,13,13,16,15, 9,10,10, + 13,12,10,11,11,13,13,10,11,10,14,12,13,13,13,15, + 15,12,13,12,15,14,11,12,12,14,14,12,12,13,14,15, + 13,14,13,15,15,14,13,15,14,16,15,16,15,17,16,12, + 12,12,14,14,13,13,14,15,15,12,13,12,15,14,15,15, + 16,16,17,14,15,14,17,14,10,11,12,13,14,11,12,13, + 14,15,11,12,13,14,15,13,14,15,15,17,14,15,15,16, + 16,11,12,13,12,15,12,12,14,13,16,13,13,14,13,16, + 14,14,16,14,18,15,15,16,16,17,12,13,12,15,15,13, + 14,14,15,16,13,14,13,16,15,15,15,16,17,18,15,15, + 15,17,16,14,14,15,14,17,15,14,16,14,17,15,15,16, + 15,18,16,16,17,16,19,17,17,17,17,18,14,15,15,17, + 16,15,16,16,17,17,15,16,15,18,16,17,17,18,18,18, + 16,17,16,18,17,10,11,11,14,13,11,12,12,15,14,11, + 13,12,15,14,14,15,15,16,16,14,15,15,17,16,11,12, + 12,15,14,12,13,13,15,14,13,14,13,16,14,14,15,15, + 16,16,15,16,15,18,16,11,13,12,15,15,13,14,14,15, + 15,12,14,13,16,15,15,16,16,17,17,15,16,15,17,16, + 14,15,14,16,16,14,15,15,16,16,15,16,15,17,16,16, + 16,17,16,17,17,18,17,19,18,14,15,15,17,16,15,16, + 16,17,17,15,15,15,18,16,17,18,18,18,18,16,17,16, + 19,16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12, + 11,10,11,12,13,14,10,11,11,14,13, 8, 9, 9,11,12, + 9,10,11,12,13, 9,10,10,13,13,11,12,13,13,15,11, + 12,12,15,14, 7, 9, 9,12,11, 9,10,10,12,13, 9,10, + 10,13,12,11,12,12,14,15,11,12,11,14,13,11,11,12, + 13,14,11,12,13,13,15,12,13,13,14,15,13,14,14,14, + 16,14,15,15,16,16,10,11,11,14,13,11,12,12,14,14, + 11,12,12,15,13,14,14,14,16,16,13,14,13,16,14, 7, + 9, 9,11,12, 9,10,10,12,13, 9,10,10,12,12,11,12, + 13,14,15,11,12,12,14,14, 9,10,10,12,13,10,10,11, + 12,14,10,11,11,13,13,12,12,13,14,15,13,13,13,15, + 15, 9,10,10,12,12,10,11,11,13,14,10,11,10,13,12, + 12,13,13,15,16,12,13,12,15,14,11,12,13,14,14,12, + 12,13,14,15,13,14,13,15,15,14,14,15,14,17,15,16, + 15,17,16,11,12,12,14,14,13,13,13,15,15,12,13,12, + 15,14,15,15,15,16,17,14,15,14,16,14, 8, 9, 9,12, + 11, 9,10,10,12,13, 9,11,10,13,12,11,12,12,14,15, + 11,12,12,15,14, 9,10,11,13,13,10,11,12,13,14,10, + 11,11,14,13,12,13,13,15,15,12,13,13,16,15, 9,11, + 9,13,11,10,11,10,14,13,10,12,10,14,12,12,13,13, + 15,15,12,13,12,16,14,12,12,13,14,15,12,13,14,14, + 16,13,14,14,15,15,14,14,15,15,17,15,16,15,17,16, + 11,13,11,15,13,13,14,13,15,14,12,14,12,16,13,15, + 15,15,16,16,14,15,14,17,14,10,11,11,13,14,11,12, + 13,14,15,11,12,12,14,15,14,14,15,16,17,14,15,15, + 16,16,11,12,13,14,15,12,13,14,15,16,13,14,14,15, + 16,15,15,16,16,18,15,16,16,17,17,11,12,12,14,15, + 13,13,14,14,16,12,13,13,15,15,15,15,16,16,18,14, + 15,15,16,16,14,15,15,16,17,15,15,16,16,17,15,16, + 16,17,17,16,16,17,16,19,17,18,17,18,18,14,14,15, + 16,16,15,15,16,16,17,14,15,15,16,16,17,17,18,18, + 19,16,17,16,17,16,10,12,11,14,13,11,13,12,15,14, + 11,13,12,15,14,14,15,15,16,16,13,15,14,17,15,12, + 13,13,15,15,13,13,14,15,16,13,14,14,16,16,14,15, + 15,17,17,15,16,16,17,17,11,13,12,15,12,13,14,13, + 16,13,12,14,12,16,13,15,16,15,17,16,14,16,14,18, + 14,14,15,15,16,17,15,15,16,16,17,15,16,16,17,17, + 16,16,17,17,18,17,18,17,18,18,14,15,14,17,14,15, + 16,15,18,15,15,16,15,18,14,17,17,17,18,17,16,17, + 16,19,16, 9,11,11,13,13,10,12,12,14,14,11,12,12, + 15,14,13,14,14,16,16,13,14,14,16,16,10,11,12,14, + 14,11,12,13,14,15,12,13,13,15,15,13,14,15,16,16, + 14,15,15,17,16,11,12,12,15,14,12,13,13,15,15,12, + 13,12,15,15,14,15,15,16,17,14,15,14,17,16,12,13, + 14,15,16,13,13,14,15,16,13,14,15,16,16,14,15,16, + 16,18,15,16,16,18,18,13,14,14,16,15,14,15,15,17, + 16,14,15,15,17,16,16,17,17,18,18,16,17,16,18,17, + 10,12,12,14,14,11,12,13,15,15,12,13,13,15,15,13, + 14,15,16,17,14,15,15,17,16,11,11,13,14,15,12,12, + 14,15,16,13,13,14,15,16,14,14,15,16,17,15,15,16, + 17,17,12,13,12,15,15,13,14,14,16,16,13,14,13,16, + 15,15,16,15,17,17,15,16,15,18,16,13,12,15,14,17, + 14,13,16,14,17,14,14,16,15,18,15,14,17,16,18,16, + 16,17,17,18,14,15,15,17,16,15,16,16,17,17,15,16, + 15,18,16,17,17,17,18,18,16,17,16,19,17,10,11,11, + 14,14,11,12,12,15,15,11,13,12,15,15,14,15,14,16, + 16,14,15,15,17,16,11,12,12,15,14,12,12,13,15,15, + 13,14,13,16,15,14,15,15,16,16,15,16,15,18,17,11, + 13,12,15,15,13,14,13,15,15,12,14,13,16,15,15,16, + 15,17,17,15,16,15,18,16,13,14,13,16,16,14,15,14, + 16,16,14,15,15,17,16,16,16,16,16,18,16,18,17,19, + 18,14,15,15,17,16,15,16,16,17,17,15,15,15,17,16, + 17,17,18,18,19,16,17,16,18,16,12,13,13,15,16,13, + 14,14,16,17,13,14,14,16,16,15,15,16,17,18,15,16, + 16,18,17,13,13,14,14,17,14,14,15,15,17,14,14,15, + 16,17,15,15,17,16,18,16,17,17,18,18,13,14,14,17, + 16,14,15,15,17,17,14,15,14,17,16,16,17,17,18,18, + 16,17,16,18,17,15,14,16,13,18,16,15,17,14,19,16, + 16,17,15,18,17,16,18,15,19,18,18,18,17,19,15,16, + 16,18,17,16,17,17,18,18,16,17,16,19,17,18,19,18, + 19,19,17,18,17,20,18,11,12,12,15,15,13,13,14,15, + 16,13,14,13,16,15,15,16,16,17,17,15,16,16,18,17, + 12,14,13,16,15,13,13,14,15,16,14,15,14,17,16,16, + 16,16,16,17,16,17,17,19,17,12,13,14,16,16,14,15, + 15,16,17,13,15,13,17,15,16,17,17,18,18,16,17,16, + 18,16,15,16,15,17,16,15,15,15,17,17,16,17,16,18, + 17,17,16,17,16,18,18,19,18,20,18,15,16,16,17,17, + 16,17,17,18,18,15,16,15,18,17,18,18,19,19,19,17, + 18,16,19,16, 9,11,11,13,13,11,12,12,14,15,10,12, + 12,14,14,13,14,14,16,16,13,14,14,16,16,11,12,12, + 14,14,12,12,13,15,15,12,13,13,15,15,14,15,15,16, + 17,14,15,15,16,16,10,12,11,14,14,12,13,13,15,15, + 11,13,12,15,14,14,15,15,16,17,13,15,14,17,16,13, + 14,14,15,16,14,15,15,16,17,14,15,15,16,17,16,16, + 17,17,18,16,17,17,18,18,12,14,13,16,15,13,15,14, + 17,16,13,14,13,17,15,15,16,16,18,18,15,16,15,18, + 16,10,11,11,14,14,11,12,13,14,15,11,12,12,15,15, + 14,15,15,16,17,14,15,15,16,16,11,12,13,15,15,12, + 13,14,15,16,13,14,14,15,16,15,15,16,16,18,15,15, + 16,17,17,11,12,12,14,15,13,13,14,15,16,12,13,13, + 15,15,15,15,16,17,18,14,15,15,17,16,14,15,15,16, + 17,15,15,16,16,17,15,16,16,17,17,16,16,17,16,19, + 17,17,18,19,18,13,13,14,16,16,14,15,16,17,17,14, + 14,15,16,16,16,16,17,18,18,16,16,16,18,16,10,12, + 12,14,14,12,13,13,15,15,11,13,12,15,15,14,15,15, + 16,17,13,15,14,17,16,12,13,13,15,15,13,13,14,15, + 16,13,14,14,16,16,15,15,16,17,18,15,15,16,17,17, + 11,13,12,15,14,13,14,13,16,15,12,14,12,16,14,15, + 16,15,17,17,14,16,14,17,16,14,15,15,16,17,15,15, + 16,16,18,15,16,16,17,17,16,17,17,17,19,17,17,17, + 18,18,13,15,12,17,14,14,16,14,17,15,14,15,13,17, + 14,16,17,16,18,17,15,17,14,19,15,11,12,12,15,15, + 13,13,14,15,16,13,14,13,16,15,15,16,16,17,18,15, + 16,16,17,17,12,14,13,16,16,13,13,15,15,17,14,15, + 15,17,16,16,16,17,16,19,16,17,17,18,18,12,13,14, + 15,16,14,14,15,16,17,13,14,13,16,15,16,17,17,18, + 19,15,16,16,17,16,15,16,16,18,17,15,15,16,17,18, + 16,17,17,18,18,16,16,18,16,19,18,19,19,20,19,15, + 15,16,16,17,16,16,17,17,18,15,15,15,17,16,18,18, + 19,18,20,17,17,16,18,16,12,13,13,16,15,13,14,14, + 16,16,13,14,14,16,16,15,16,16,17,18,15,16,15,18, + 17,13,14,14,16,16,14,15,15,16,17,14,15,15,17,17, + 16,17,17,18,18,16,17,17,18,18,13,14,13,17,14,14, + 15,14,17,16,14,15,14,17,15,16,17,17,18,18,15,17, + 15,19,15,16,16,16,17,18,16,16,17,17,19,16,17,17, + 18,19,17,17,18,18,20,18,18,18,19,19,15,16,14,18, + 13,16,17,16,19,15,16,17,15,19,14,18,18,18,19,17, + 17,18,16,20,15, +}; + +static const static_codebook _44p6_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p6_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p6_p2_0, + 0 +}; + +static const long _vq_quantlist__44p6_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p3_0[] = { + 1, 5, 5, 5, 7, 8, 5, 8, 7, 5, 7, 8, 8, 8,10, 8, + 10,10, 5, 8, 7, 8,10,10, 8,10, 8, 6, 8, 9, 8,10, + 12, 9,11,11, 9,10,11,11,11,13,12,13,13, 9,11,11, + 11,13,13,11,13,12, 6, 9, 8, 9,11,11, 8,12,10, 9, + 11,11,11,12,13,11,13,13, 9,11,10,11,13,13,11,13, + 11, 5, 9, 9, 8,11,11, 9,12,11, 8,10,11,10,11,13, + 11,13,13, 9,11,11,11,13,13,11,13,12, 8,10,11,10, + 12,13,10,13,12,10,10,13,11,11,14,12,13,14,11,13, + 12,13,14,14,12,14,12, 8,11,10,11,12,13,11,14,12, + 10,13,12,12,12,13,13,15,14,11,12,13,13,14,15,12, + 14,12, 5, 9, 9, 9,11,12, 8,11,11, 9,11,11,11,12, + 13,11,13,13, 8,11,10,11,13,13,10,13,11, 8,10,11, + 11,12,14,11,13,12,11,13,12,12,12,14,13,15,14,10, + 12,13,13,14,15,12,13,12, 8,11,10,10,12,13,10,13, + 12,11,12,13,12,12,14,13,14,14,10,13,10,12,14,13, + 11,14,11, +}; + +static const static_codebook _44p6_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p6_p3_0, + 0 +}; + +static const long _vq_quantlist__44p6_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p3_1[] = { + 5, 7, 7, 6, 7, 7, 6, 7, 7, 6, 7, 7, 7, 8, 8, 7, + 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 8, 7, 7, 8, 7, 8, + 8, 7, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, + 8, 9, 9, 8, 9, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 8, + 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, + 8, 6, 8, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 9, + 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8, + 8, 9, 8, 9, 9, 8, 8, 9, 8, 9, 9, 9, 9, 9, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, 9, + 9, 9, 6, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, + 8, 8, 9, 8, 9, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, + 8, 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, + 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, + 9, 9, 9, +}; + +static const static_codebook _44p6_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p6_p3_1, + 0 +}; + +static const long _vq_quantlist__44p6_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p4_0[] = { + 2, 5, 5, 5, 7, 8, 5, 8, 7, 5, 7, 7, 7, 7, 9, 7, + 9, 9, 5, 7, 7, 8, 9, 9, 7, 9, 7, 6, 8, 8, 8, 9, + 10, 8, 9, 9, 8, 9,10, 9, 9,11,10,11,11, 8, 9, 9, + 10,11,11, 9,11,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 8, + 9, 9, 9,10,11,10,11,10, 8,10, 9,10,11,11, 9,11, + 9, 6, 8, 8, 7, 9, 9, 8,10, 9, 7, 9, 9, 9, 9,10, + 9,10,10, 8, 9, 9, 9,10,10, 9,11,10, 7, 9, 9, 8, + 10,10, 9,10,10, 9, 9,10,10,10,11,10,11,11, 9,10, + 10,10,11,11,10,11,10, 7, 9, 9, 9, 9,10, 9,10, 9, + 8,10, 9, 9, 9,11,10,11,11, 9,10,10,10,11,11, 9, + 11, 9, 6, 8, 8, 8, 9,10, 7, 9, 9, 8, 9, 9, 9,10, + 10, 9,10,10, 7, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9, + 9, 9,10, 9,10, 9, 9,10,10, 9, 9,11,10,11,11, 8, + 9,10,10,11,11, 9,11, 9, 7, 9, 9, 9,10,10, 8,10, + 10, 9,10,10,10,10,11,10,11,11, 9,10, 9,10,11,11, + 10,11,10, +}; + +static const static_codebook _44p6_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p6_p4_0, + 0 +}; + +static const long _vq_quantlist__44p6_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p6_p4_1[] = { + 6, 8, 8,10,10, 8, 9, 9,10,11, 8,10, 9,11,10, 9, + 10,10,11,11, 9,10,10,11,11, 8, 9, 9,10,10, 9, 9, + 10,11,11,10,10,10,11,11,10,11,11,11,11,10,11,11, + 11,11, 8, 9, 9,11,10,10,10,10,11,11, 9,10, 9,11, + 11,10,11,11,11,11,10,11,10,11,11,10,10,11,11,11, + 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,10,11,10,11,11,11,11,11,11,11,10,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11, 8, 9,10, + 11,11,10,10,11,11,11,10,10,10,11,11,10,11,11,12, + 12,10,11,11,12,12,10,10,11,11,11,10,10,11,11,12, + 11,11,11,12,12,11,11,12,12,12,11,11,12,12,12,10, + 10,10,11,11,11,11,11,12,12,10,11,11,12,12,11,12, + 12,12,12,11,12,11,12,12,11,11,11,11,12,11,11,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,11,11,12,11,11,12,12,12,12,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12, 8,10, 9,11,11,10, + 10,10,11,11,10,11,10,11,11,10,11,11,12,12,10,11, + 11,12,12,10,10,10,11,11,10,11,11,12,12,11,11,11, + 12,12,11,11,12,12,12,11,12,12,12,12,10,11,10,11, + 11,11,11,11,12,12,10,11,10,12,11,11,12,11,12,12, + 11,12,11,12,12,11,11,11,12,12,11,11,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11, + 11,12,11,11,12,12,12,12,11,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,10,11,11,11,12,11,11,12,12, + 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12, + 11,11,12,12,12,11,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,13,11,12,11,12,12,12,12, + 12,12,12,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,13,12,13,12,12,12,12,13,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,12, + 12,12,13,12,10,11,11,12,11,11,11,12,12,12,11,12, + 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,11,12,11,12,12,12,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,12,12,12,12,13,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,13,12,13,12,13, + 12, 8,10,10,11,11,10,10,11,11,11,10,11,10,11,11, + 10,11,11,12,12,10,11,11,12,12, 9,10,11,11,11,10, + 10,11,12,12,10,11,11,12,12,11,11,12,12,12,11,12, + 12,12,12,10,11,10,11,11,11,11,11,12,12,10,11,11, + 12,12,11,12,12,12,12,11,12,11,12,12,11,11,11,12, + 12,11,11,12,12,12,11,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12, 9,10, + 10,11,11,10,11,11,12,12,10,11,11,12,12,11,11,12, + 12,12,11,12,12,12,12,10,11,11,12,12,11,11,12,12, + 12,11,11,12,12,12,11,11,12,12,12,12,12,12,12,12, + 10,11,11,12,12,11,12,12,12,12,11,12,11,12,12,12, + 12,12,12,12,12,12,12,12,12,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,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, 9,10,10,11,11, + 10,11,11,12,12,10,11,11,12,11,11,12,12,12,12,11, + 12,12,12,12,10,11,11,12,12,11,11,11,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,10,11,11, + 12,12,11,12,12,12,12,11,12,11,12,12,12,12,12,12, + 12,12,12,12,12,12,11,12,12,12,12,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,11,11,11,12,12,11,12,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,12,13,12,12,13,13,13,11,12,12,12,12,12, + 12,12,13,13,12,12,12,13,12,12,12,12,13,13,12,13, + 12,13,13,12,12,12,12,12,12,12,12,12,13,12,13,13, + 13,13,12,13,13,13,13,13,13,13,13,13,12,12,12,12, + 12,12,12,13,13,13,12,13,12,13,13,12,13,13,13,13, + 12,13,13,13,13,11,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 12,13,12,12,12,13,13,11,12,12,12,12,12,12,12,12, + 13,12,12,12,13,12,12,13,12,13,13,12,13,12,13,13, + 12,12,12,12,12,12,12,13,13,13,12,12,13,13,13,12, + 13,13,12,13,13,13,13,13,13,12,12,12,12,12,12,13, + 12,13,13,12,13,12,13,12,12,13,13,13,13,12,13,13, + 13,13, 8,10,10,11,11,10,10,11,11,11, 9,11,10,11, + 11,10,11,11,12,12,10,11,11,12,12,10,10,11,11,11, + 10,11,11,12,12,11,11,11,12,12,11,11,12,12,12,11, + 12,12,12,12, 9,11,10,11,11,10,11,11,12,12,10,11, + 10,12,12,11,12,12,12,12,11,12,11,12,12,11,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12, + 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12, 9, + 10,10,11,11,10,11,11,12,12,10,11,11,12,12,11,12, + 12,12,12,11,12,12,12,12,10,11,11,12,12,11,11,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,10,11,11,12,12,11,11,12,12,12,11,11,11,12,12, + 12,12,12,12,12,11,12,12,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,11,12,12,12,12,12,12,12,12,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12, 9,10,10,11, + 11,10,11,11,12,12,10,11,11,12,12,11,12,12,12,12, + 11,12,11,12,12,10,11,11,12,12,11,11,12,12,12,11, + 11,12,12,12,12,12,12,12,12,12,12,12,12,12,10,11, + 11,12,12,11,12,11,12,12,11,12,11,12,12,12,12,12, + 12,12,11,12,11,12,12,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, + 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,12, + 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,12,12,12,13,13,12,12,13,13,13,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,13,12,13,13,12, + 12,12,13,12,12,12,12,12,12,12,12,13,13,13,12,12, + 13,13,13,12,13,13,12,13,12,13,13,13,13,12,12,12, + 12,12,12,12,13,13,13,12,12,12,13,12,12,13,13,13, + 13,12,13,13,13,13,11,11,11,12,12,11,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12, + 13,13,13,12,12,12,13,13,11,12,12,12,12,12,12,12, + 13,12,12,12,12,13,12,12,13,12,13,13,12,13,12,13, + 12,12,12,12,12,12,12,12,13,13,13,12,13,13,13,13, + 12,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12, + 13,12,13,12,12,13,12,13,12,13,13,13,13,13,12,13, + 13,13,13,10,11,11,12,12,11,12,12,12,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,11,11,12,12, + 12,11,12,12,12,12,12,12,12,12,12,12,12,12,13,13, + 12,12,12,13,13,11,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,12, + 12,12,12,12,12,12,12,13,12,12,12,12,13,12,12,13, + 12,13,12,13,13,13,13,12,12,12,12,12,12,12,12,13, + 12,12,12,12,13,12,12,13,13,13,13,12,13,12,13,13, + 11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12, + 12,12,12,13,12,12,12,13,12,11,12,12,12,12,12,12, + 12,12,13,12,12,12,12,13,12,12,13,13,13,12,12,13, + 13,13,11,12,12,12,12,12,12,12,12,13,12,12,12,13, + 12,12,13,12,13,13,12,13,12,13,13,12,12,12,12,12, + 12,12,13,12,13,12,12,13,13,13,12,12,13,13,13,13, + 13,13,13,13,12,12,12,12,12,12,13,13,13,13,12,13, + 12,13,12,12,13,13,13,13,12,13,13,13,13,11,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,13,11,12,12,12,12,12,12,12,12,13, + 12,12,12,13,13,12,12,13,13,13,12,12,13,13,13,11, + 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,13, + 12,13,13,12,13,12,13,13,12,12,12,12,12,12,12,12, + 12,13,12,13,12,13,13,12,13,13,13,13,12,13,13,13, + 13,12,12,12,12,12,12,13,12,13,13,12,12,12,13,13, + 12,13,13,13,13,12,13,12,13,13,11,12,12,12,12,11, + 12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,13,12,13,12,12,12,13,13,11,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13, + 12,13,12,13,13,12,12,12,12,12,12,12,13,12,13,12, + 12,13,12,13,12,12,13,12,13,12,13,13,13,13,12,12, + 12,12,12,12,12,12,12,12,12,12,12,13,12,12,13,13, + 13,13,12,13,12,13,12,11,11,11,12,12,11,12,12,12, + 12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,13,13,11,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12, + 13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,13,12,12,12,13,12,12,12,12,12,12,12,12, + 12,12,12,13,12,12,12,12,13,12,12,13,12,13,12,12, + 13,12,13,12,10,11,11,12,12,11,12,12,12,12,11,12, + 11,12,12,11,12,12,12,12,11,12,12,12,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,12,12,12,13,13,11,12,11,12,12,12,12,12,12,12, + 11,12,12,12,12,12,12,12,13,13,12,12,12,13,12,12, + 12,12,12,12,12,12,12,12,13,12,12,12,12,13,12,13, + 13,12,13,12,13,13,13,13,12,12,12,12,12,12,12,12, + 13,13,12,12,12,13,12,12,13,13,13,13,12,13,12,13, + 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12, + 12,12,12,13,13,12,12,12,13,12,11,12,12,12,12,12, + 12,12,12,13,12,12,12,13,13,12,12,13,13,13,12,12, + 13,13,13,11,12,12,12,12,12,12,12,13,13,12,12,12, + 13,12,12,13,12,13,13,12,12,12,13,13,12,12,12,12, + 12,12,12,13,13,13,12,12,13,13,13,12,12,13,13,13, + 12,13,13,13,13,12,12,12,12,12,12,12,13,13,13,12, + 12,12,13,12,12,13,13,13,13,12,13,13,13,13,11,11, + 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12, + 12,13,12,12,12,13,13,11,12,12,12,12,12,12,12,12, + 13,12,12,12,13,13,12,12,13,13,13,12,12,13,13,13, + 11,12,12,12,12,12,12,12,13,12,12,12,12,13,12,12, + 13,12,13,13,12,13,12,13,13,12,12,12,12,12,12,12, + 12,13,13,12,13,12,13,13,12,13,13,13,13,13,13,13, + 13,13,12,12,12,12,12,12,13,12,13,13,12,13,12,13, + 12,12,13,13,13,13,12,13,12,13,13,11,11,11,12,12, + 11,12,12,12,12,11,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,13,12,12,12,13,13,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 12,12,12,12,13,12,12,12,12,13,12,12,13,12,13,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,12,12,12,13,12,12,12,11,12,11,12,12,11,12,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,12,12,12,12,12,12,12,12,13,12,12,12,12,12, + 12,12,12,13,13,12,12,12,13,13,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,12,13,13,12,12, + 12,13,12,12,12,12,12,12,12,12,12,12,13,12,12,12, + 13,13,12,12,13,12,13,12,13,13,13,13,12,12,12,12, + 12,12,12,12,13,12,12,12,12,13,12,12,13,12,13,13, + 12,13,12,13,12, +}; + +static const static_codebook _44p6_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p6_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p6_p4_1, + 0 +}; + +static const long _vq_quantlist__44p6_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p6_p5_0[] = { + 2, 6, 6,10,10, 5, 7, 8,11,12, 5, 8, 7,12,11, 9, + 11,11,13,15, 9,11,11,15,13, 6, 7, 8,11,11, 7, 7, + 9,11,13, 8, 9, 9,13,12,11,11,12,12,15,11,12,12, + 15,14, 6, 8, 7,11,11, 8, 9, 9,12,13, 7, 9, 7,13, + 11,11,12,12,14,15,11,12,11,15,12,10,11,11,12,14, + 10,11,12,12,15,12,13,13,14,15,13,12,14,12,16,15, + 15,15,16,16,10,11,11,14,12,12,13,13,15,14,10,12, + 11,15,12,15,15,15,16,17,13,14,12,17,12, 6, 8, 8, + 12,12, 8, 9,10,13,13, 8, 9, 9,13,13,12,12,13,15, + 16,12,13,13,16,15, 8, 9,10,12,13, 9, 9,11,13,14, + 10,11,11,14,14,13,13,14,15,16,13,14,14,16,16, 8, + 10, 9,13,13,10,11,11,14,14, 9,10,10,14,13,13,14, + 14,16,17,13,13,13,16,15,12,13,13,14,16,13,13,14, + 14,16,14,14,14,16,16,15,15,16,15,18,16,17,17,18, + 18,12,13,13,15,15,14,14,14,16,16,13,14,13,16,15, + 16,16,17,18,18,15,16,15,18,15, 6, 8, 8,12,12, 8, + 9, 9,13,13, 8,10, 9,13,13,12,13,13,15,16,12,13, + 12,16,15, 8, 9,10,13,13, 9,10,10,13,14,10,11,11, + 14,14,13,13,13,15,16,13,14,14,17,16, 8,10, 9,13, + 13,10,11,11,14,14, 9,11, 9,14,13,13,14,14,16,16, + 13,14,13,16,14,12,13,13,15,16,13,13,14,15,16,14, + 14,14,16,16,15,15,16,15,18,17,17,17,18,18,12,13, + 13,16,14,14,14,14,16,16,13,14,13,16,14,16,17,17, + 18,18,15,16,15,18,15,11,12,13,14,16,13,13,14,15, + 17,13,14,14,16,17,16,16,17,17,19,16,17,17,18,19, + 13,13,14,16,16,14,14,15,16,17,14,15,15,17,17,17, + 16,17,17,19,17,17,18,19,19,13,14,14,16,16,14,14, + 15,17,18,14,15,14,17,17,17,17,18,18,19,17,17,17, + 18,19,16,16,16,17,18,17,17,17,18,19,17,17,17,18, + 19,18,18,19,18,20,19,20,19,21,20,16,17,17,18,18, + 17,17,18,19,19,17,17,17,19,18,19,19,19,19,20,19, + 19,19,20,19,11,13,12,16,14,13,14,14,17,16,13,14, + 13,17,15,16,17,17,18,18,16,17,16,19,17,13,14,14, + 16,16,14,14,14,17,17,14,15,15,17,16,17,17,17,19, + 19,17,18,17,19,18,13,14,13,17,16,14,15,15,17,17, + 14,15,14,18,16,17,17,17,19,19,17,17,16,19,17,16, + 17,17,18,19,17,17,17,18,18,17,18,17,19,18,18,19, + 18,19,19,19,20,19,20,20,16,17,16,18,17,17,17,17, + 18,18,17,18,17,19,17,19,19,19,19,20,18,19,19,20, + 18, 6, 8, 8,12,12, 8, 9, 9,13,13, 8,10, 9,13,13, + 11,13,13,15,16,12,13,13,16,15, 8, 9, 9,13,13, 9, + 9,10,13,14,10,11,11,14,14,12,12,13,14,16,13,14, + 14,17,16, 8,10, 9,13,13,10,11,11,14,14, 9,11,10, + 14,13,13,14,14,16,16,13,14,13,16,15,12,13,13,14, + 16,12,13,14,14,16,13,14,14,16,16,15,14,16,15,18, + 16,17,17,18,17,12,13,13,16,15,14,14,14,16,16,13, + 14,13,16,15,16,16,17,17,17,15,16,15,18,15, 7, 9, + 9,13,13, 9, 9,11,13,14, 9,10,10,14,13,12,13,14, + 15,16,12,14,13,17,15, 9, 9,10,13,14,10, 9,11,13, + 15,11,11,11,14,14,13,12,14,14,17,14,14,14,17,16, + 9,10,10,14,13,11,11,11,14,14,10,11,10,15,13,14, + 14,14,16,17,13,14,13,17,14,13,13,14,14,16,13,13, + 14,14,17,14,14,14,16,16,15,14,16,15,18,17,17,17, + 18,18,13,14,13,16,15,14,14,15,17,16,13,14,13,17, + 15,17,16,17,17,17,15,16,14,18,14, 7, 9, 9,13,13, + 9,10,10,13,14, 9,11,10,14,13,13,14,14,16,16,13, + 14,14,17,15, 9,10,10,14,13, 9,10,11,13,14,11,12, + 11,15,14,13,13,14,14,16,14,15,15,17,17, 9,10,10, + 14,14,11,12,12,14,15,10,11,10,15,13,14,15,15,17, + 17,14,15,13,17,14,13,14,13,16,16,13,13,14,15,16, + 14,15,15,17,17,15,14,16,15,18,17,18,17,20,18,13, + 14,14,16,16,15,15,15,17,17,13,14,13,17,15,17,17, + 18,18,18,15,16,14,19,14,12,13,13,15,16,13,13,15, + 16,17,13,14,14,16,16,15,15,17,17,19,16,17,17,19, + 18,13,13,14,15,17,14,13,15,15,17,14,15,15,16,17, + 16,15,18,16,19,17,17,17,18,19,13,14,14,17,16,14, + 15,15,17,17,14,15,14,17,16,17,17,17,18,19,16,17, + 16,19,17,16,16,17,16,18,16,16,17,16,19,17,17,18, + 18,19,18,17,18,17,21,19,19,19,20,19,16,17,17,18, + 18,17,17,18,18,19,16,17,16,18,18,19,19,19,19,20, + 18,18,17,20,18,11,13,13,16,15,13,14,14,16,17,13, + 15,14,17,16,16,17,17,18,18,17,17,17,19,18,13,14, + 13,17,16,14,13,14,16,17,15,16,15,18,16,17,16,17, + 17,19,18,18,18,20,18,13,14,14,16,17,15,15,15,17, + 18,14,15,14,18,16,18,18,18,19,20,17,18,16,20,17, + 16,17,16,18,18,16,16,17,18,18,17,18,18,19,18,18, + 17,19,17,20,19,20,19,22,20,16,16,17,18,18,18,17, + 17,19,19,16,17,16,18,17,19,20,19,22,21,18,19,18, + 21,17, 6, 8, 8,12,12, 8, 9,10,13,13, 8, 9, 9,13, + 13,12,13,13,15,16,11,13,13,16,15, 8, 9,10,13,13, + 9,10,11,13,14,10,11,11,14,14,13,13,14,15,16,13, + 14,14,16,16, 8, 9, 9,13,13,10,11,11,14,14, 9,10, + 9,14,13,13,14,14,16,17,12,14,12,16,14,12,13,13, + 15,16,13,13,14,15,16,13,14,14,15,17,15,15,16,15, + 18,16,16,17,17,17,12,13,13,16,14,13,14,14,16,16, + 12,14,13,16,14,16,17,17,18,18,15,15,14,18,14, 7, + 9, 9,13,13, 9,10,11,13,14, 9,10,10,14,13,13,14, + 14,15,17,13,14,14,16,15, 9,10,10,14,14,10,10,11, + 13,15,11,12,12,15,14,14,13,15,14,17,14,15,15,17, + 17, 9,10,10,13,14,11,11,12,14,15, 9,11,10,14,13, + 14,15,15,16,18,13,14,13,16,14,13,14,14,16,16,13, + 13,14,15,17,15,15,15,16,17,15,14,16,15,18,17,17, + 18,19,18,13,14,14,16,16,14,15,15,17,17,13,14,13, + 16,15,17,17,18,18,18,15,16,14,18,15, 7, 9, 9,13, + 13, 9,10,10,13,14, 9,11,10,14,13,12,13,14,15,16, + 12,14,13,16,15, 9,10,10,13,14,10,10,11,13,14,11, + 11,11,15,14,13,13,14,14,16,14,14,14,17,16, 9,10, + 9,14,13,11,11,11,14,14,10,11, 9,15,13,14,14,14, + 16,16,13,14,12,17,14,13,13,14,15,16,13,13,14,15, + 16,14,15,14,16,17,15,14,16,14,18,16,17,17,18,18, + 13,14,13,16,14,14,14,14,16,16,13,14,13,17,14,17, + 17,17,18,18,15,16,14,18,15,11,13,13,16,16,13,14, + 15,16,17,13,14,14,17,16,16,17,17,18,19,17,17,17, + 19,18,13,14,14,17,17,13,13,15,16,18,15,15,15,17, + 17,17,16,18,17,20,18,17,18,19,19,13,14,14,16,17, + 15,15,16,16,18,14,15,14,16,16,17,17,18,18,20,17, + 18,16,18,17,16,17,16,19,18,16,16,17,18,19,18,18, + 18,19,19,18,17,18,17,21,20,19,19,21,21,16,16,17, + 18,18,17,17,18,19,19,16,17,16,19,18,20,20,20,19, + 21,18,18,17,20,18,12,13,13,16,15,13,14,14,16,16, + 13,14,13,17,16,16,17,17,18,18,15,17,15,19,17,13, + 14,14,16,17,14,14,15,16,17,14,15,15,17,17,16,16, + 17,17,18,17,17,17,19,19,13,14,13,17,15,14,15,15, + 17,16,14,15,13,17,15,17,18,17,19,18,16,17,15,20, + 16,16,17,17,18,18,16,16,17,18,18,17,18,17,19,18, + 17,17,18,18,20,19,20,19,20,19,16,16,16,19,16,17, + 17,17,19,18,16,17,16,19,16,19,19,19,19,19,18,19, + 17,19,17,11,13,13,16,16,13,14,14,17,17,13,14,14, + 17,17,15,17,17,19,19,16,18,17,20,19,12,14,14,17, + 17,13,14,15,17,18,14,15,15,17,18,16,16,17,18,20, + 17,18,18,20,18,13,14,14,17,17,14,15,15,17,18,14, + 15,15,17,17,17,18,17,19,19,17,18,17,19,19,15,16, + 16,18,18,15,16,17,18,19,16,17,17,19,19,17,17,18, + 18,21,18,19,19,21,19,16,17,17,18,18,17,17,18,19, + 19,17,18,17,19,19,19,19,19,20,20,18,19,18,21,19, + 12,13,13,16,16,13,14,14,16,17,13,15,14,17,16,15, + 16,17,17,19,16,17,17,19,18,13,13,14,16,17,14,13, + 15,16,17,14,15,15,17,17,15,15,17,17,20,17,17,18, + 19,18,13,14,14,17,16,15,15,15,17,18,14,15,14,17, + 16,17,17,17,18,18,16,17,16,19,17,16,15,17,17,19, + 16,15,17,16,19,17,16,17,18,19,17,16,19,16,20,19, + 18,19,19,19,16,17,17,18,18,17,17,17,18,19,16,17, + 16,19,18,20,19,19,20,19,18,18,17,20,17,11,13,13, + 16,16,13,14,15,16,17,14,15,14,18,16,17,17,17,18, + 21,17,18,17,20,19,13,14,14,17,16,13,14,15,16,18, + 15,16,15,18,17,17,16,17,17,19,17,18,18,20,19,13, + 14,14,16,17,15,15,16,17,18,14,15,14,18,17,17,18, + 18,19,20,17,18,16,19,17,16,17,15,19,18,16,16,16, + 18,18,17,18,17,20,19,18,17,18,17,20,20,20,19,22, + 20,16,17,17,18,19,18,18,18,19,20,16,17,16,19,18, + 20,19,19,20,20,18,19,17,20,17,13,14,14,16,17,14, + 14,16,16,18,14,16,15,17,16,16,16,17,17,18,17,17, + 16,19,18,14,14,15,16,17,14,14,16,16,18,16,16,16, + 17,17,16,15,17,16,19,18,18,18,19,19,14,15,15,17, + 17,15,16,16,17,18,14,16,14,18,16,17,17,18,18,19, + 16,17,16,19,17,16,16,17,16,18,16,16,17,16,19,18, + 18,18,17,18,17,16,18,16,20,19,19,19,19,19,16,17, + 17,18,18,17,17,18,19,19,16,17,16,19,17,18,19,19, + 19,20,17,18,16,20,16,11,14,13,17,17,14,14,16,16, + 18,14,16,14,19,16,18,18,19,18,19,18,19,18,21,18, + 13,15,14,18,16,14,14,16,16,18,16,17,16,19,17,18, + 16,19,17,20,19,19,19,21,19,13,14,15,17,18,17,16, + 17,17,19,14,16,14,18,16,20,19,19,20,21,18,19,16, + 21,17,17,18,16,19,17,16,16,17,18,18,19,19,18,21, + 18,17,17,18,17,20,20,20,20,22,20,17,17,18,18,20, + 19,19,19,18,20,16,17,17,19,19,21,21,21,20,21,17, + 19,17,23,17,11,13,13,16,16,13,14,14,17,17,13,14, + 14,17,17,16,17,17,19,20,15,16,16,19,19,13,14,14, + 16,17,14,15,15,17,18,14,15,15,17,17,17,17,18,19, + 19,17,17,18,19,19,13,14,14,17,16,14,15,15,17,17, + 13,15,14,18,17,17,18,18,19,20,16,17,16,19,18,16, + 16,17,18,18,17,17,17,18,19,17,18,17,19,19,19,19, + 19,19,20,19,20,19,20,20,15,16,16,18,17,16,17,17, + 20,18,15,16,16,19,17,19,19,19,20,20,17,18,17,21, + 17,11,13,13,16,16,13,14,15,16,17,13,15,14,17,16, + 17,17,18,18,20,17,17,17,19,19,13,14,14,17,17,14, + 14,15,17,18,15,15,15,18,17,17,17,18,17,20,18,18, + 17,20,18,13,14,14,16,17,15,15,16,17,18,14,15,13, + 17,17,17,18,18,19,20,17,17,16,19,17,16,17,17,18, + 18,16,16,17,18,18,18,18,18,19,19,18,17,19,18,21, + 19,20,20,20,20,16,15,17,18,18,17,17,18,18,20,16, + 16,16,18,17,20,19,20,21,22,17,18,17,20,17,12,13, + 13,16,16,13,14,15,16,17,13,14,14,17,16,16,17,18, + 18,19,15,16,16,19,18,13,14,14,16,17,14,14,15,16, + 17,14,15,15,17,17,16,16,17,17,19,17,17,17,19,18, + 13,14,13,17,16,14,15,15,17,17,13,15,13,17,16,17, + 17,17,19,19,15,17,15,19,17,16,17,17,18,18,16,16, + 17,17,19,17,18,17,19,19,18,17,19,17,19,19,19,19, + 20,19,15,17,15,19,16,17,17,16,19,18,16,17,15,18, + 16,19,19,19,20,19,17,19,16,19,16,11,14,14,17,17, + 15,14,16,16,18,15,16,14,18,16,18,18,19,18,21,18, + 19,18,20,18,13,15,14,18,17,14,14,16,16,18,16,17, + 16,19,17,17,17,19,17,22,19,19,19,21,19,13,14,15, + 17,18,17,16,17,17,19,14,16,14,18,16,19,19,19,20, + 21,18,18,16,20,17,17,18,16,19,18,15,17,17,19,19, + 19,19,18,21,19,18,17,20,17,21,22,21,20,21,21,17, + 16,19,18,20,19,18,19,18,20,16,17,16,19,18,21,20, + 21,19,23,18,19,16,20,17,13,14,14,17,16,14,14,15, + 16,18,14,16,14,17,16,16,16,17,17,19,16,17,16,19, + 17,14,15,15,17,17,14,14,16,16,17,15,16,16,18,17, + 16,16,17,17,19,17,18,17,19,18,14,15,14,17,16,16, + 16,16,17,17,14,16,14,17,16,18,18,18,18,19,16,17, + 15,19,16,17,17,17,18,18,16,15,17,17,18,18,18,18, + 19,19,17,16,18,16,19,19,19,19,19,19,16,17,16,19, + 16,18,18,17,19,18,16,17,16,19,16,19,19,20,19,19, + 17,18,16,20,16, +}; + +static const static_codebook _44p6_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p6_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p6_p5_0, + 0 +}; + +static const long _vq_quantlist__44p6_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p6_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p6_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p6_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p6_p5_1, + 0 +}; + +static const long _vq_quantlist__44p6_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p6_0[] = { + 1, 5, 5, 5, 7, 9, 5, 9, 7, 5, 7, 8, 7, 7,10, 9, + 10,10, 5, 8, 7, 9,10,10, 7,10, 7, 6, 9, 9, 9,10, + 12, 9,11,11, 9,10,11,11,11,13,12,13,13, 9,11,11, + 12,13,13,11,13,11, 6, 9, 9, 9,11,11, 9,12,10, 9, + 11,11,11,11,13,12,13,13, 9,11,10,12,13,13,11,13, + 11, 6, 9, 9, 9,11,12, 9,12,11, 9,10,11,10,10,13, + 12,13,13, 9,11,11,12,13,12,11,13,11, 7, 9,10, 9, + 10,12,10,12,11,10,10,12,10,10,12,12,12,13,10,11, + 11,12,12,13,10,12,10, 7,10,10,11,11,14,11,14,11, + 10,12,11,11,11,14,14,14,14,10,11,12,14,14,14,11, + 14,11, 6, 9, 9, 9,11,12, 9,12,11, 9,11,11,11,11, + 13,12,12,13, 9,11,10,12,13,13,10,13,10, 7,10,10, + 11,11,14,11,14,11,10,12,11,11,11,14,14,15,14,10, + 11,12,13,14,15,11,14,11, 7,10, 9,10,11,12, 9,12, + 10,10,11,11,10,10,12,12,13,12, 9,12,10,12,13,12, + 10,12,10, +}; + +static const static_codebook _44p6_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p6_p6_0, + 0 +}; + +static const long _vq_quantlist__44p6_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p6_1[] = { + 2, 6, 6, 6, 7, 8, 6, 8, 7, 6, 7, 7, 7, 7, 8, 7, + 8, 8, 6, 7, 7, 7, 8, 8, 7, 8, 7, 6, 8, 8, 8, 9, + 9, 8, 9, 9, 8, 9, 9, 9, 9,10, 9,10,10, 8, 9, 9, + 9,10,10, 9,10, 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8, + 9, 9, 9, 9,10, 9,10,10, 8, 9, 9, 9,10, 9, 9,10, + 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9,10, + 9, 9,10, 8, 9, 9, 9,10, 9, 9,10, 9, 7, 8, 8, 8, + 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, 9, + 9, 9,10, 9, 9, 9, 9, 7, 9, 9, 9, 9,10, 9,10, 9, + 9, 9, 9, 9, 9,10,10,10,10, 9, 9, 9,10,10,10, 9, + 10, 9, 6, 8, 8, 8, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9, + 10, 9,10,10, 8, 9, 9, 9,10, 9, 9,10, 9, 7, 9, 9, + 9, 9,10, 9,10, 9, 9, 9, 9, 9, 9,10,10,10,10, 9, + 9, 9,10,10,10, 9,10, 9, 7, 8, 8, 8, 9, 9, 8, 9, + 9, 8, 9, 9, 9, 9,10, 9, 9,10, 8, 9, 8, 9, 9, 9, + 9,10, 9, +}; + +static const static_codebook _44p6_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p6_p6_1, + 0 +}; + +static const long _vq_quantlist__44p6_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 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, +}; + +static const static_codebook _44p6_p7_0 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p7_0, + 1, -513979392, 1633504256, 2, 0, + (long *)_vq_quantlist__44p6_p7_0, + 0 +}; + +static const long _vq_quantlist__44p6_p7_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p6_p7_1[] = { + 1, 4, 5, 5,10,10, 5,10,10, 5,10,10,10,10,10,10, + 10,10, 5,10,10,10,10,10,10,10,10, 7,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10, 6,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10, 9,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10, 9,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 9,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, 9,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11, + 11,11,11, +}; + +static const static_codebook _44p6_p7_1 = { + 5, 243, + (char *)_vq_lengthlist__44p6_p7_1, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p6_p7_1, + 0 +}; + +static const long _vq_quantlist__44p6_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p6_p7_2[] = { + 1, 2, 3, 4, 5, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _44p6_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p6_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p6_p7_2, + 0 +}; + +static const long _vq_quantlist__44p6_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p6_p7_3[] = { + 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, +}; + +static const static_codebook _44p6_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p6_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p6_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p6_short[] = { + 2, 8,13,15,16,18,21,22, 5, 4, 6, 8,10,12,17,21, + 9, 5, 5, 6, 8,11,15,19,11, 6, 5, 5, 6, 7,12,14, + 14, 8, 7, 5, 4, 4, 9,11,16,11, 9, 7, 4, 3, 7,10, + 22,15,14,12, 8, 7, 9,11,21,16,15,12, 9, 5, 6, 8, +}; + +static const static_codebook _huff_book__44p6_short = { + 2, 64, + (char *)_huff_lengthlist__44p6_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p7_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p7_l0_0[] = { + 2, 4, 4, 7, 7, 8, 8,10,10,11,11,12,12, 4, 5, 5, + 7, 7, 9, 9,11, 9,12,11,12,12, 4, 5, 5, 7, 7, 9, + 9, 9,10,10,11,12,12, 7, 7, 7, 7, 8, 9, 8,11, 5, + 12, 6,12,10, 7, 7, 7, 8, 7, 8, 9, 5,11, 6,12,10, + 12, 8, 9, 9, 9, 9,10,10,11, 7,11, 7,12, 9, 8, 9, + 8, 9, 9,10,10, 7,11, 7,11, 9,11,10,10,10,10,10, + 10,10,11,10,11, 8,11, 9,10,10,10,10,10,10,10,10, + 11, 8,10, 9,11,10,11,11,11,11,11,10,11,10,12,10, + 12,11,10,11,11,11,11,10,11,10,11,10,12,11,12,11, + 12,12,12,12,12,12,12,12,12,12,13,12,11,12,11,12, + 12,12,12,12,11,12,11,12,13, +}; + +static const static_codebook _44p7_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p7_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p7_l0_0, + 0 +}; + +static const long _vq_quantlist__44p7_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p7_l0_1[] = { + 4, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44p7_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p7_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p7_l0_1, + 0 +}; + +static const long _vq_quantlist__44p7_l1_0[] = { + 54, + 29, + 79, + 0, + 108, +}; + +static const char _vq_lengthlist__44p7_l1_0[] = { + 1, 2, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44p7_l1_0 = { + 2, 25, + (char *)_vq_lengthlist__44p7_l1_0, + 1, -514516992, 1620639744, 7, 0, + (long *)_vq_quantlist__44p7_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p7_lfe[] = { + 2, 3, 1, 3, +}; + +static const static_codebook _huff_book__44p7_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p7_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p7_long[] = { + 2, 7,14,16,17,17,18,20, 6, 3, 5, 8,10,11,13,15, + 13, 5, 3, 5, 8, 9,11,12,15, 7, 4, 3, 5, 7, 9,11, + 16,10, 7, 5, 6, 7, 9,10,17,11, 8, 7, 7, 6, 8, 8, + 19,13,11, 9, 9, 8, 8, 9,20,14,13,11,10, 8, 9, 9, +}; + +static const static_codebook _huff_book__44p7_long = { + 2, 64, + (char *)_huff_lengthlist__44p7_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p7_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p1_0[] = { + 2, 5, 5, 4, 7, 7, 4, 7, 7, 5, 7, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 6, 7, 8, 8, 9, + 10, 8, 9,10, 8, 9,10,10,10,12,10,11,11, 8,10,10, + 10,11,12,10,11,11, 6, 8, 7, 8,10, 9, 8,10, 9, 8, + 10,10,10,11,11,10,12,11, 8,10, 9,10,11,11,10,12, + 10, 5, 8, 8, 8,10,10, 8,10,10, 7, 9,10, 9,10,11, + 9,11,11, 8,10,10,10,11,12,10,12,11, 7, 9, 9, 9, + 10,11, 9,11,11, 9, 9,11,10,11,12,11,11,12, 9,11, + 11,11,12,12,11,12,12, 7, 9, 9,10,11,11,10,12,11, + 9,11,10,11,11,12,11,13,12,10,11,11,12,13,13,11, + 13,11, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11, + 12,10,12,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9, + 10,11,12,10,11,11,10,11,11,11,11,13,12,13,13, 9, + 10,11,11,12,13,11,12,11, 7, 9, 9, 9,11,11, 9,11, + 10, 9,11,11,11,12,12,11,12,12, 9,11, 9,11,12,11, + 10,12,11, +}; + +static const static_codebook _44p7_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p7_p1_0, + 0 +}; + +static const long _vq_quantlist__44p7_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p7_p2_0[] = { + 4, 6, 6, 9, 9, 6, 8, 8,10,10, 6, 8, 8,10,10, 8, + 10,10,12,13, 8,10,10,13,12, 6, 8, 8,10,10, 8, 8, + 9,10,11, 8, 9, 9,11,11,10,10,11,12,13,10,11,11, + 13,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 8, 9, 8,11, + 10,10,11,11,13,13,10,11,10,13,12, 9,10,10,12,12, + 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,13, + 13,13,15,14, 9,10,10,12,12,10,11,11,13,13,10,11, + 10,13,12,12,13,13,14,15,12,13,12,15,12, 6, 8, 8, + 10,11, 8, 9,10,11,12, 8, 9, 9,11,11,10,11,12,13, + 14,10,11,11,13,13, 8, 9, 9,11,12, 9,10,11,12,13, + 9,10,10,12,13,11,12,13,13,15,11,12,12,14,14, 8, + 9, 9,11,12, 9,10,11,12,13, 9,10,10,13,12,11,12, + 13,14,15,11,12,12,14,13,10,11,12,13,14,11,12,13, + 13,15,12,13,13,14,14,13,13,14,14,16,14,15,14,16, + 15,10,12,11,14,13,12,12,13,14,14,11,12,12,14,14, + 14,14,15,15,16,13,14,14,16,14, 6, 8, 8,11,10, 8, + 9, 9,11,11, 8,10, 9,12,11,10,11,11,13,13,10,12, + 11,14,13, 8, 9, 9,12,11, 9,10,10,12,13, 9,11,10, + 13,12,11,12,12,14,14,11,13,12,15,14, 8, 9, 9,12, + 11, 9,10,10,13,12, 9,11,10,13,12,11,12,12,14,14, + 11,13,12,15,13,10,11,12,13,14,11,12,13,13,14,12, + 13,12,14,14,13,13,14,14,16,14,15,14,16,16,10,12, + 11,14,13,12,13,13,14,14,11,13,12,15,13,14,14,15, + 16,16,13,14,13,16,14, 9,10,11,12,13,11,11,12,13, + 14,11,11,12,13,14,13,13,14,14,16,13,14,14,15,15, + 11,11,12,13,14,12,12,13,13,15,12,13,13,14,15,14, + 14,15,15,17,14,14,15,16,16,11,12,12,13,14,12,12, + 13,14,15,12,13,12,14,15,14,14,15,15,17,14,15,14, + 16,16,13,14,14,15,16,14,14,15,15,17,14,15,15,16, + 16,15,16,17,16,18,16,17,16,17,17,13,14,14,16,15, + 14,15,15,16,16,14,15,14,16,15,16,16,17,17,18,16, + 16,16,17,16, 9,11,10,13,12,11,12,11,14,13,11,12, + 11,14,13,13,14,14,16,15,13,14,13,16,14,11,12,12, + 14,13,12,12,13,14,14,12,13,13,15,14,14,14,15,16, + 16,14,15,14,17,15,11,12,11,14,13,12,13,13,15,14, + 12,13,12,15,13,14,15,14,16,16,14,15,14,17,15,13, + 14,14,15,16,14,14,15,16,16,14,15,15,16,16,15,16, + 16,16,17,16,16,16,17,17,13,14,14,16,15,14,15,15, + 17,16,14,15,14,17,15,16,17,17,17,17,16,16,16,18, + 16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12,11, + 10,11,11,13,14,10,11,11,14,13, 8, 9, 9,11,12, 9, + 10,10,12,13, 9,10,10,13,12,11,11,12,13,15,11,12, + 12,15,14, 8, 9, 9,12,11, 9,10,11,12,13, 9,11,10, + 13,12,11,12,12,14,15,11,13,12,15,14,10,11,11,13, + 14,11,12,12,13,14,11,12,12,14,14,13,13,14,14,16, + 13,14,14,16,15,11,12,11,14,13,12,13,13,14,14,11, + 13,12,14,13,14,14,15,16,16,13,14,14,16,14, 8, 9, + 9,11,12, 9,10,10,12,13, 9,10,10,13,12,11,12,12, + 14,15,11,12,12,14,14, 9, 9,10,11,13,10,10,12,12, + 14,10,10,11,13,13,12,12,13,14,16,12,12,13,15,15, + 9,10,10,13,12,10,11,11,13,14,10,12,11,14,13,12, + 13,13,15,15,12,13,13,15,15,11,11,12,13,15,12,12, + 13,13,15,12,13,13,14,15,14,14,15,15,17,14,15,15, + 16,16,11,13,12,15,14,13,13,13,15,15,12,14,13,15, + 14,15,15,15,16,16,14,15,15,17,15, 7, 9, 9,12,11, + 9,10,10,12,12, 9,11,10,13,12,11,12,12,14,14,11, + 13,12,15,14, 9,10,10,12,12,10,10,11,12,13,10,11, + 11,14,13,12,12,13,14,15,12,13,13,15,14, 9,10,10, + 12,12,10,11,11,13,13,10,11,10,14,12,12,13,13,15, + 15,12,13,12,15,13,11,12,12,14,14,12,12,13,14,15, + 12,13,13,15,15,14,13,14,13,16,14,15,15,16,16,11, + 12,12,14,14,13,13,14,15,15,12,13,12,15,14,15,15, + 15,16,16,14,15,14,17,14,10,11,12,13,14,11,12,13, + 14,15,11,12,12,14,15,13,14,15,15,17,14,14,14,16, + 16,11,12,13,12,15,12,12,14,13,16,13,13,14,13,16, + 14,14,15,14,17,15,15,15,15,17,11,13,12,15,15,13, + 13,14,15,16,12,14,13,16,15,15,15,15,17,17,15,15, + 15,17,16,14,14,15,14,16,14,14,16,14,17,15,15,15, + 14,17,16,16,17,15,18,17,17,17,16,18,14,15,15,17, + 16,15,16,16,17,17,15,16,15,17,16,17,17,17,18,18, + 16,17,16,18,17,10,11,11,14,13,11,12,12,14,14,11, + 13,12,15,14,14,14,14,16,16,14,15,14,16,15,11,12, + 12,15,13,12,13,13,15,14,13,14,13,16,14,14,15,15, + 16,16,15,16,15,17,16,11,13,12,15,14,13,13,14,15, + 15,12,14,13,16,14,15,15,15,17,17,14,16,15,17,16, + 14,14,14,16,15,14,15,15,16,16,15,16,15,17,16,16, + 16,16,16,17,16,17,17,18,17,14,15,15,16,16,15,15, + 16,17,16,14,15,15,17,16,17,17,17,18,18,16,17,16, + 18,16, 6, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12, + 11,10,11,12,13,14,10,11,11,14,13, 8, 9, 9,11,12, + 9,10,11,12,13, 9,11,10,13,12,11,12,13,14,15,11, + 12,12,15,14, 8, 9, 9,12,11, 9,10,10,12,13, 9,10, + 10,13,12,11,12,12,14,15,11,12,12,14,13,11,11,12, + 13,14,11,12,13,13,15,12,13,13,14,14,13,14,14,14, + 16,14,15,14,16,16,10,11,11,14,13,11,12,12,14,14, + 11,12,12,14,13,13,14,14,15,16,13,14,13,16,14, 7, + 9, 9,11,11, 9,10,11,12,13, 9,10,10,12,12,11,12, + 13,14,15,11,12,12,14,14, 9,10,10,12,12,10,10,11, + 12,13,10,11,11,13,13,12,12,13,13,15,12,13,13,15, + 15, 9,10,10,12,12,10,11,11,13,13,10,11,10,13,12, + 12,13,13,14,15,12,13,12,15,13,11,12,12,14,14,12, + 12,13,14,15,13,14,13,15,15,14,13,15,13,16,15,15, + 15,16,16,11,12,12,14,14,12,13,13,14,15,12,13,12, + 15,14,14,15,15,16,17,13,14,13,16,13, 8, 9, 9,12, + 11, 9,10,10,12,13, 9,10,10,13,12,11,12,12,14,15, + 11,12,12,15,14, 9,10,10,12,13,10,11,12,13,14,10, + 11,11,14,13,12,13,13,15,15,12,13,13,15,15, 9,10, + 9,13,11,10,11,10,13,13,10,12,10,14,12,12,13,12, + 15,15,12,13,12,15,14,11,12,13,14,15,12,13,14,14, + 15,13,13,13,15,15,14,15,15,15,17,15,15,15,16,16, + 11,12,11,15,13,12,13,13,15,14,12,13,12,16,13,14, + 15,15,16,16,14,15,14,17,14,10,11,11,13,14,11,12, + 13,14,15,11,12,12,14,14,14,14,15,15,17,14,14,14, + 15,16,11,12,13,14,15,12,13,14,14,16,13,14,13,15, + 15,14,15,16,15,17,15,15,15,17,17,11,12,12,13,15, + 13,13,14,14,16,12,13,13,14,15,15,15,15,16,17,14, + 15,15,16,16,14,15,15,16,16,14,15,15,16,17,15,15, + 16,16,17,16,16,17,16,18,17,17,17,18,18,14,14,15, + 15,16,15,15,15,16,17,14,15,15,16,16,16,17,17,17, + 18,16,16,16,17,16,10,11,11,14,13,11,13,12,15,14, + 11,13,12,15,14,14,15,14,16,16,13,15,14,17,15,11, + 12,13,15,15,12,13,14,15,16,13,14,13,16,15,15,15, + 15,16,17,15,15,15,17,16,11,13,11,15,12,13,14,13, + 16,13,12,14,12,16,13,15,15,15,17,15,14,16,14,17, + 14,14,15,15,16,17,15,15,16,16,17,15,16,15,17,17, + 16,16,17,17,18,16,17,17,18,18,14,15,14,17,13,15, + 16,15,17,15,15,16,15,17,14,16,17,16,18,16,16,17, + 16,18,15, 9,11,11,13,13,10,12,12,14,14,11,12,12, + 14,14,13,14,14,15,16,13,14,14,16,16,10,11,12,14, + 14,11,12,13,14,15,11,13,13,15,15,13,14,14,15,16, + 14,15,15,16,16,11,12,12,14,14,12,13,13,15,15,12, + 13,12,15,14,14,15,15,16,16,14,15,14,17,16,12,13, + 13,15,16,13,13,14,15,16,13,14,14,16,16,14,15,16, + 16,17,15,16,16,17,17,13,14,14,16,15,14,15,15,17, + 16,14,15,14,17,15,16,16,17,17,17,16,16,16,18,16, + 10,11,12,14,14,11,12,13,14,15,11,13,12,15,15,13, + 14,15,16,16,14,15,15,17,16,11,11,13,14,15,12,12, + 14,14,16,12,13,14,15,15,14,14,15,16,17,15,15,15, + 17,17,12,13,12,15,15,13,14,14,16,15,13,14,13,16, + 15,15,16,15,17,17,15,16,15,17,16,13,12,15,14,16, + 14,13,15,14,17,14,13,15,15,17,15,14,17,15,18,16, + 15,17,17,18,14,15,15,17,16,15,16,16,17,17,15,16, + 15,17,16,16,17,17,18,18,16,17,16,18,17,10,11,11, + 14,14,11,12,12,14,15,11,13,12,15,14,13,14,14,16, + 16,14,15,14,16,16,11,12,12,14,14,12,12,13,15,15, + 12,13,13,15,15,14,14,15,16,16,14,15,15,17,16,11, + 12,12,15,15,13,13,13,15,15,12,13,13,15,15,15,15, + 15,17,17,14,15,15,17,16,13,14,13,16,15,14,14,14, + 16,16,14,15,14,17,16,15,15,16,16,17,16,17,16,18, + 17,14,15,15,16,16,15,15,15,17,17,14,15,15,17,16, + 16,17,17,18,18,16,17,16,18,16,12,13,13,15,15,13, + 14,14,16,16,13,14,14,16,16,14,15,16,16,18,15,16, + 16,17,17,13,13,14,14,16,14,14,15,15,17,14,14,15, + 15,17,15,15,17,15,18,16,16,17,17,18,13,14,14,16, + 16,14,15,15,16,17,14,15,15,17,16,16,17,16,17,18, + 16,17,16,18,17,15,14,16,13,18,16,15,17,14,18,16, + 15,17,14,18,17,16,18,15,19,17,17,18,16,19,15,16, + 16,17,17,16,17,17,18,18,16,17,16,18,17,18,18,18, + 19,18,17,18,17,19,17,11,12,12,15,15,13,13,14,15, + 16,13,14,13,16,15,15,15,15,16,17,15,16,15,17,16, + 12,13,13,15,15,13,13,14,15,16,14,15,14,16,15,15, + 15,16,16,17,16,16,16,18,17,12,13,13,15,15,14,14, + 15,16,16,13,14,13,16,15,16,16,16,17,17,15,16,15, + 18,16,15,15,15,17,15,14,15,15,16,16,16,17,16,17, + 16,16,16,17,16,17,17,18,17,19,18,15,15,16,17,17, + 16,16,16,17,17,15,16,15,17,16,17,18,18,18,18,16, + 17,16,18,16, 9,11,11,13,13,11,12,12,14,14,10,12, + 12,14,14,13,14,14,15,16,13,14,14,16,15,11,12,12, + 14,14,12,12,13,14,15,12,13,13,15,15,14,14,15,16, + 17,14,15,15,16,16,10,12,11,14,14,11,13,13,15,15, + 11,13,12,15,14,14,14,15,16,16,13,14,14,16,15,13, + 14,14,15,16,14,14,15,15,17,14,15,15,16,17,16,16, + 16,16,18,16,16,17,17,17,12,13,13,16,15,13,14,14, + 16,16,12,14,13,16,15,15,16,16,17,17,14,16,15,17, + 16,10,11,11,14,14,11,12,13,14,15,11,12,12,15,14, + 14,14,15,16,16,13,14,14,16,16,11,12,12,14,15,12, + 13,14,15,15,13,13,13,15,15,14,15,15,16,17,15,15, + 15,16,17,11,12,12,14,14,12,13,13,15,15,12,13,12, + 15,15,14,15,15,16,17,14,15,14,16,16,14,14,15,16, + 16,14,15,15,16,17,15,16,15,17,17,16,16,17,16,18, + 16,17,17,18,18,13,13,14,15,16,14,14,15,16,17,14, + 14,14,16,15,16,16,17,17,18,15,16,15,17,16,10,12, + 11,14,14,11,13,13,15,15,11,13,12,15,15,14,15,15, + 16,16,13,15,14,16,16,12,12,13,15,15,13,13,14,15, + 16,13,14,14,16,15,15,15,16,16,17,15,15,15,17,17, + 11,13,11,15,14,12,14,13,16,15,12,14,12,16,14,15, + 15,15,17,17,14,15,14,17,15,14,15,15,16,17,15,15, + 16,16,17,15,16,16,17,17,16,16,17,17,18,16,17,17, + 18,18,13,14,12,16,14,14,15,13,17,15,14,15,13,17, + 14,16,17,15,18,17,15,17,14,18,15,11,12,12,14,15, + 13,13,14,15,16,13,14,13,16,15,15,15,16,16,17,15, + 15,15,16,16,12,13,13,15,15,13,13,14,15,16,14,15, + 14,16,16,15,15,16,16,18,16,16,16,18,17,12,13,13, + 15,15,14,14,15,15,16,13,14,13,15,15,16,16,16,17, + 18,15,16,15,17,16,15,16,15,17,16,15,15,16,16,17, + 16,17,16,17,17,16,16,17,16,18,17,18,18,18,18,14, + 15,15,15,17,16,15,17,16,17,14,15,15,16,16,17,17, + 18,18,19,16,16,16,17,16,12,13,13,15,15,13,14,14, + 16,16,13,14,14,16,16,15,16,16,17,17,15,16,15,18, + 16,13,14,14,16,16,14,15,15,16,17,14,15,15,17,16, + 16,16,17,17,18,16,17,16,18,18,13,14,13,16,14,14, + 15,14,17,15,14,15,14,17,14,16,17,16,18,17,15,17, + 15,18,15,15,16,16,17,18,16,16,17,17,18,16,17,17, + 17,18,17,17,18,18,19,17,18,18,19,18,15,16,14,17, + 13,16,17,15,18,14,16,17,15,18,14,18,18,17,19,16, + 17,18,16,19,15, +}; + +static const static_codebook _44p7_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p7_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p7_p2_0, + 0 +}; + +static const long _vq_quantlist__44p7_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p3_0[] = { + 2, 5, 5, 4, 7, 7, 4, 7, 7, 5, 7, 8, 7, 8,10, 8, + 9, 9, 5, 7, 7, 8, 9, 9, 7,10, 8, 5, 7, 8, 8, 9, + 10, 8,10,10, 8, 9,10,10,10,12,10,12,12, 8,10,10, + 10,12,12,10,12,11, 5, 8, 7, 8,10,10, 8,10, 9, 8, + 10,10,10,11,12,10,12,12, 8,10, 9,10,12,12,10,12, + 10, 5, 8, 8, 7,10,10, 8,10,10, 7, 9,10, 9,10,12, + 10,12,12, 8,10,10,10,12,12,10,12,11, 7, 9,10, 9, + 11,12,10,12,11, 9, 9,12,11,10,14,12,12,13,10,12, + 11,12,13,13,11,14,12, 7,10, 9,10,11,11,10,12,11, + 9,11,11,11,11,13,12,14,13,10,12,12,12,14,14,11, + 14,12, 5, 8, 8, 8,10,10, 7,10,10, 8,10,10,10,11, + 12,10,12,12, 7,10, 9,10,12,12, 9,12,10, 7, 9,10, + 10,11,12,10,11,11,10,12,12,11,12,14,12,14,14, 9, + 11,11,12,13,14,11,13,11, 7,10, 9,10,11,12, 9,12, + 11,10,11,12,11,12,14,12,13,13, 9,12, 9,12,13,12, + 11,14,10, +}; + +static const static_codebook _44p7_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p7_p3_0, + 0 +}; + +static const long _vq_quantlist__44p7_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p3_1[] = { + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 8, 7, + 8, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, + 8, 8, 8, 8, 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, + 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 7, 8, 8, 8, + 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, + 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, + 9, 8, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 9, 8, 8, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, + 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8, 8, 8, 8, 9, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, + 8, 9, 8, +}; + +static const static_codebook _44p7_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p7_p3_1, + 0 +}; + +static const long _vq_quantlist__44p7_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p4_0[] = { + 1, 5, 5, 5, 7, 8, 5, 8, 7, 5, 7, 8, 7, 8,10, 8, + 10,10, 5, 8, 7, 8,10,10, 7,10, 8, 6, 8, 9, 9,10, + 12, 9,11,11, 9,10,11,11,11,13,11,13,13, 9,11,11, + 11,12,13,11,13,11, 6, 9, 8, 9,11,11, 9,12,10, 9, + 11,11,11,11,13,11,13,13, 9,11,10,11,13,13,11,13, + 11, 6, 9, 9, 8,10,11, 9,12,11, 8,10,11,10,11,13, + 11,13,13, 9,11,11,11,13,12,11,13,11, 8,10,10, 9, + 11,12,10,12,12,10,10,12,11,11,14,12,13,14,10,12, + 12,12,13,13,11,14,11, 8,11,10,11,12,13,11,14,12, + 10,12,11,11,12,14,13,15,14,10,12,12,13,14,15,12, + 14,12, 5, 9, 9, 9,11,12, 8,11,10, 9,11,11,11,11, + 13,11,12,13, 8,11,10,11,13,13,10,13,11, 8,10,11, + 11,12,14,11,13,12,10,12,12,12,12,14,14,15,14,10, + 11,12,13,14,15,11,14,12, 8,10,10,10,12,12, 9,12, + 11,10,12,12,11,11,14,12,13,13,10,12,10,12,14,13, + 11,13,11, +}; + +static const static_codebook _44p7_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p7_p4_0, + 0 +}; + +static const long _vq_quantlist__44p7_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p7_p4_1[] = { + 7, 8, 8,10,10, 8, 9, 9,10,11, 8, 9, 9,10,10, 9, + 10,10,11,11, 9,10,10,11,11, 8, 9, 9,10,10, 9, 9, + 10,11,11, 9,10,10,11,11,10,10,11,11,11,10,11,11, + 11,11, 8, 9, 9,10,10, 9,10,10,11,11, 9,10, 9,11, + 11,10,11,11,11,11,10,11,10,11,11,10,10,10,11,11, + 10,11,11,11,11,10,11,11,11,11,11,11,11,11,12,11, + 11,11,11,12,10,10,10,11,11,10,11,11,11,11,10,11, + 11,11,11,11,11,11,12,11,11,11,11,12,11, 8, 9,10, + 11,11, 9,10,11,11,11, 9,10,10,11,11,10,11,11,12, + 12,10,11,11,12,12,10,10,10,11,11,10,10,11,11,12, + 10,11,11,12,12,11,11,12,12,12,11,11,12,12,12,10, + 10,10,11,11,10,11,11,12,12,10,11,11,12,11,11,12, + 12,12,12,11,12,11,12,12,11,11,11,11,12,11,11,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,11,11,12,12,11,12,12,12,12,11,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12, 8,10, 9,11,11, 9, + 10,10,11,11, 9,10,10,11,11,10,11,11,12,12,10,11, + 11,12,12,10,10,10,11,11,10,11,11,12,12,10,11,11, + 12,12,11,11,12,12,12,11,12,12,12,12,10,10,10,11, + 11,10,11,11,12,12,10,11,10,12,11,11,12,11,12,12, + 11,12,11,12,12,11,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11, + 11,12,11,11,12,12,12,12,11,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,10,11,11,11,12,11,11,12,12, + 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12, + 11,11,12,12,12,11,12,12,12,12,12,12,12,12,12,12, + 12,13,12,13,12,12,12,13,13,11,12,11,12,12,11,12, + 12,12,12,11,12,12,12,12,12,12,12,13,13,12,12,12, + 13,13,12,12,12,12,12,12,12,12,12,13,12,12,13,13, + 13,12,13,13,13,13,12,13,13,13,13,12,12,12,12,12, + 12,12,13,13,13,12,12,12,13,12,12,13,13,13,13,12, + 13,13,13,13,10,11,11,12,11,11,11,11,12,12,11,12, + 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,12,12,12,13,13,11,12,11,12,12,12,12,12,12,12, + 11,12,11,12,12,12,12,12,13,13,12,12,12,13,12,12, + 12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,13, + 13,13,13,12,13,13,13,13,12,12,12,12,12,12,12,12, + 13,13,12,13,12,13,12,12,13,13,13,13,13,13,13,13, + 13, 8,10,10,11,11, 9,10,10,11,11, 9,10,10,11,11, + 10,11,11,12,12,10,11,11,12,12, 9,10,10,11,11,10, + 10,11,11,12,10,11,11,12,12,11,11,12,12,12,11,11, + 12,12,12,10,10,10,11,11,10,11,11,12,12,10,11,10, + 12,11,11,12,11,12,12,11,12,11,12,12,11,11,11,12, + 12,11,11,12,12,12,11,12,12,12,12,11,12,12,12,12, + 12,12,12,12,12,11,11,11,12,11,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12, 9,10, + 10,11,11,10,11,11,11,12,10,11,11,12,12,11,11,11, + 12,12,11,11,11,12,12,10,10,11,11,12,11,11,12,12, + 12,11,11,11,12,12,11,11,12,12,12,11,12,12,12,12, + 10,11,11,12,12,11,11,11,12,12,11,12,11,12,12,11, + 12,12,12,12,11,12,12,12,12,11,11,12,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12, + 12,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,13,12, 9,10,10,11,11, + 10,11,11,12,12,10,11,11,12,11,11,12,11,12,12,11, + 12,11,12,12,10,11,11,12,12,11,11,11,12,12,11,12, + 11,12,12,11,12,12,12,12,12,12,12,12,12,10,11,11, + 12,12,11,12,11,12,12,11,12,11,12,12,12,12,12,13, + 12,12,12,12,12,12,11,12,11,12,12,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,13,12,12,12,12,13,11, + 12,12,12,12,12,12,12,13,12,11,12,12,12,12,12,12, + 12,13,12,12,12,12,13,12,10,11,11,12,12,11,12,12, + 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13, + 13,11,11,12,12,12,12,12,12,12,13,12,12,12,12,12, + 12,12,13,12,13,12,12,13,13,13,11,12,12,12,12,12, + 12,12,13,13,12,12,12,13,12,12,13,12,13,13,12,13, + 12,13,13,12,12,12,12,12,12,12,13,12,13,12,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,13, + 13,12,13,13,13,13,12,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,10,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,13,13,12,12,12,13,13,11,12, + 12,12,12,12,12,12,12,13,12,12,12,13,12,12,12,13, + 13,13,12,13,13,13,13,11,12,12,12,12,12,12,12,13, + 13,12,12,12,13,12,12,13,13,13,13,12,13,12,13,13, + 12,12,12,12,12,12,13,13,13,13,12,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,12,12,12,13,12,12,13, + 13,13,13,12,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13, 8,10,10,11,11, 9,10,10,11,11, 9,10,10,11, + 11,10,11,11,12,12,10,11,11,12,12,10,10,10,11,11, + 10,11,11,11,12,10,11,11,12,12,11,11,12,12,12,11, + 11,12,12,12, 9,10,10,11,11,10,11,11,12,12,10,11, + 10,12,11,11,12,11,12,12,11,12,11,12,12,11,11,11, + 12,12,11,11,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,11,11,11,12,11,11,12,12,12,12, + 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12, 9, + 10,10,11,11,10,11,11,12,12,10,11,11,12,12,11,11, + 12,12,12,11,12,12,12,12,10,11,11,12,12,11,11,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,10,11,11,12,12,11,11,12,12,12,11,11,11,12,12, + 12,12,12,12,12,11,12,12,12,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,13,12,13,12,12, + 12,13,12,11,12,12,12,12,12,12,12,12,12,11,12,12, + 12,12,12,12,12,13,12,12,12,12,13,12, 9,10,10,11, + 11,10,11,11,12,12,10,11,11,12,12,11,11,11,12,12, + 11,12,11,12,12,10,11,11,12,12,11,11,12,12,12,11, + 11,11,12,12,11,12,12,12,12,11,12,12,12,12,10,11, + 10,12,11,11,11,11,12,12,11,12,11,12,12,11,12,12, + 12,12,11,12,11,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,12,12,12,12,13, + 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12, + 12,12,13,12,12,12,12,13,12,10,11,11,12,12,11,12, + 12,12,12,11,12,12,12,12,12,12,12,13,13,12,12,12, + 13,13,11,12,12,12,12,12,12,12,12,13,12,12,12,13, + 13,12,12,13,13,13,12,13,13,13,13,11,12,12,12,12, + 12,12,12,12,13,12,12,12,12,12,12,13,13,13,13,12, + 13,12,13,13,12,12,12,12,13,12,13,13,13,13,12,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12, + 12,12,12,13,13,13,13,12,13,12,13,13,13,13,13,13, + 13,13,13,13,13,13,11,11,11,12,12,11,12,12,12,12, + 11,12,12,12,12,12,12,12,13,13,12,12,12,13,12,11, + 12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,12, + 13,13,13,12,13,13,13,13,11,12,11,12,12,12,12,12, + 13,12,12,12,12,13,12,12,13,12,13,13,12,13,12,13, + 12,12,12,12,12,13,12,12,13,13,13,12,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12, + 13,13,13,13,12,13,12,13,12,13,13,13,13,13,13,13, + 13,13,13,10,11,11,12,12,10,11,11,12,12,10,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,12, + 12,11,11,12,12,12,11,12,12,12,12,12,12,12,13,13, + 12,12,12,13,13,11,11,11,12,12,11,12,12,12,12,11, + 12,11,13,12,12,12,12,13,13,12,12,12,13,13,11,12, + 12,12,12,12,12,12,12,13,12,12,12,13,13,12,12,13, + 13,13,12,13,12,13,13,11,12,12,12,12,12,12,12,13, + 12,12,12,12,13,12,12,13,13,13,13,12,13,13,13,13, + 10,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12, + 12,12,13,13,12,12,12,13,13,11,11,12,12,12,11,12, + 12,12,13,12,12,12,13,13,12,12,13,13,13,12,12,13, + 13,13,11,12,12,12,12,12,12,12,13,13,12,12,12,13, + 13,12,13,13,13,13,12,13,12,13,13,12,12,12,12,13, + 12,12,13,12,13,12,12,13,13,13,12,12,13,13,13,12, + 13,13,13,13,12,12,12,12,13,12,12,13,13,13,12,12, + 12,13,13,13,13,13,13,13,12,13,13,13,13,10,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,13, + 13,12,12,12,13,13,11,12,12,12,12,11,12,12,12,13, + 12,12,12,13,13,12,12,13,13,13,12,13,13,13,13,11, + 12,12,12,12,12,12,12,13,13,12,12,12,13,12,12,13, + 12,13,13,12,13,12,13,13,12,12,12,12,12,12,12,12, + 13,13,12,13,12,13,13,12,13,13,13,13,13,13,13,13, + 13,12,12,12,13,12,12,13,13,13,13,12,13,12,13,13, + 13,13,13,13,13,13,13,13,13,13,11,11,11,12,12,11, + 12,12,12,12,11,12,12,12,12,12,12,12,13,13,12,12, + 12,13,13,11,12,12,12,12,12,12,12,12,13,12,12,12, + 13,13,12,12,13,13,13,12,12,13,13,13,11,12,12,12, + 12,12,12,12,13,13,12,12,12,13,13,12,13,13,13,13, + 12,13,12,13,13,12,12,12,12,12,12,12,13,12,13,12, + 13,13,13,13,12,13,13,12,13,13,13,13,13,13,12,12, + 12,12,12,12,13,13,13,13,12,13,12,13,13,13,13,13, + 13,13,13,13,13,13,13,10,11,11,12,12,11,12,12,12, + 13,11,12,12,13,12,12,12,12,13,13,12,12,12,13,13, + 11,12,12,12,12,12,12,12,13,13,12,13,12,13,13,12, + 12,13,13,13,12,13,13,13,13,11,12,12,12,13,12,12, + 12,13,13,12,12,12,13,12,12,13,13,13,13,12,13,12, + 13,13,12,12,12,12,12,12,12,13,13,13,12,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,12,12,12,13,12, + 12,13,13,13,13,12,13,12,13,13,13,13,13,13,13,13, + 13,13,13,13,10,11,11,12,12,10,11,11,12,12,10,11, + 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11, + 12,12,11,11,12,12,13,11,12,12,12,12,12,12,12,13, + 13,12,12,12,13,13,10,11,11,12,12,11,12,12,12,12, + 11,12,11,12,12,12,12,12,13,13,12,12,12,13,12,11, + 12,12,12,12,12,12,12,12,13,12,12,12,13,13,12,12, + 13,13,13,12,13,13,13,13,11,12,12,12,12,12,12,12, + 13,13,12,12,12,13,12,12,13,13,13,13,12,13,12,13, + 13,10,11,11,12,12,11,12,12,12,12,11,12,12,12,12, + 12,12,12,13,13,12,12,12,13,13,11,12,12,12,12,12, + 12,12,12,13,12,12,12,13,13,12,12,13,13,13,12,12, + 13,13,13,11,12,12,12,12,12,12,12,13,13,11,12,12, + 13,12,12,13,13,13,13,12,13,12,13,13,12,12,12,12, + 13,12,12,13,13,13,12,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,12,12,12,13,12,12,12,13,13,13,12, + 12,12,13,13,13,13,13,13,13,12,13,13,13,13,10,11, + 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12, + 13,13,12,12,12,13,13,11,12,12,12,12,12,12,12,12, + 13,12,12,12,13,13,12,12,13,13,13,12,12,13,13,13, + 11,12,11,12,12,12,12,12,13,13,11,12,12,13,12,12, + 13,12,13,13,12,13,12,13,13,12,12,12,12,12,12,12, + 13,13,13,12,13,12,13,13,12,13,13,13,13,13,13,13, + 13,13,12,12,12,13,12,12,13,12,13,13,12,13,12,13, + 13,13,13,13,13,13,12,13,12,13,13,10,11,11,12,12, + 11,12,12,12,12,11,12,12,13,12,12,12,12,13,13,12, + 12,12,13,13,11,12,12,12,12,12,12,12,12,13,12,12, + 12,13,13,12,12,13,13,13,12,13,13,13,13,11,12,12, + 12,12,12,12,12,13,13,12,12,12,13,12,12,13,13,13, + 13,12,13,12,13,13,12,12,12,12,13,12,12,13,13,13, + 12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,12, + 12,12,12,12,12,13,13,13,13,12,13,12,13,13,13,13, + 13,13,13,13,13,13,13,13,11,11,11,12,12,11,12,12, + 12,12,11,12,12,12,12,12,12,12,13,13,12,12,12,13, + 13,11,12,12,12,12,12,12,12,13,13,12,12,12,13,13, + 12,12,13,13,13,12,13,13,13,13,11,12,12,12,12,12, + 12,12,13,13,12,12,12,13,12,12,13,12,13,13,12,13, + 12,13,13,12,12,12,12,12,12,13,13,13,13,12,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12, + 12,12,13,13,13,13,12,13,12,13,12,13,13,13,13,13, + 13,13,13,13,12, +}; + +static const static_codebook _44p7_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p7_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p7_p4_1, + 0 +}; + +static const long _vq_quantlist__44p7_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p7_p5_0[] = { + 2, 6, 6, 9, 9, 5, 7, 8,10,11, 5, 8, 7,11,10, 8, + 10,11,12,13, 8,11,10,13,12, 6, 7, 8,10,11, 7, 8, + 10,10,12, 8, 9, 9,12,11,10,10,12,11,14,10,11,12, + 14,13, 6, 8, 7,11,10, 8, 9, 9,11,12, 7,10, 8,12, + 10,10,12,12,13,14,10,12,10,14,11, 9,10,11,11,12, + 10,10,11,11,13,11,12,12,13,13,12,11,13,11,15,13, + 14,13,14,14, 9,11,10,12,11,11,12,12,13,13,10,11, + 10,13,11,13,13,14,14,14,12,13,11,14,11, 7, 8, 9, + 11,12, 9, 9,11,12,13, 9,10,10,13,12,11,12,13,13, + 15,11,12,12,14,14, 9,10,10,12,13,10,10,12,12,14, + 11,11,11,13,13,12,12,13,13,15,12,13,13,15,14, 9, + 10,10,12,13,10,11,11,13,14,10,12,11,14,13,12,13, + 13,14,15,12,13,13,15,14,12,12,13,13,14,12,13,13, + 13,15,13,14,14,14,15,14,14,15,14,16,14,15,15,16, + 16,12,13,13,14,14,13,13,14,15,14,12,13,13,15,14, + 14,15,15,15,16,14,15,14,16,14, 7, 9, 8,12,11, 9, + 10,10,12,13, 9,11, 9,13,12,11,12,12,14,14,11,13, + 12,15,13, 9,10,10,13,12,10,11,12,13,14,10,12,11, + 14,13,12,13,13,14,15,13,13,13,15,14, 9,10,10,13, + 12,11,11,11,13,13,10,12,10,14,12,13,13,13,14,15, + 12,13,12,15,13,12,13,13,14,14,12,13,13,14,15,13, + 14,13,15,15,14,14,15,14,16,14,15,15,16,15,12,13, + 12,14,13,13,13,13,15,14,12,13,13,15,13,14,15,15, + 16,15,14,15,14,16,14,11,12,12,13,14,12,13,14,14, + 15,12,13,13,14,15,14,14,15,15,16,14,15,15,16,16, + 12,13,13,14,15,13,13,14,14,16,13,14,14,15,15,15, + 15,16,15,17,15,15,15,16,16,12,13,13,14,15,13,14, + 14,15,16,13,14,14,15,15,15,15,16,16,17,15,15,15, + 17,16,14,15,15,16,16,15,15,16,15,16,15,16,16,16, + 17,16,16,17,16,18,16,16,17,18,17,14,15,15,16,16, + 15,16,16,16,17,15,16,15,17,16,16,17,17,17,18,16, + 16,16,17,16,11,12,12,14,13,12,13,13,15,14,12,14, + 13,15,14,14,15,15,16,16,14,15,14,16,15,12,13,13, + 15,14,13,14,14,15,15,13,14,14,16,15,15,15,15,16, + 16,15,16,15,17,16,12,13,13,15,14,13,14,14,15,15, + 13,14,13,16,14,15,15,15,16,16,15,15,15,17,15,14, + 15,15,16,16,15,15,15,16,16,15,16,16,17,17,16,16, + 17,17,17,16,17,17,18,17,14,15,15,16,15,15,15,16, + 16,16,15,15,15,17,15,17,17,17,18,17,16,17,16,18, + 16, 6, 9, 9,12,12, 8,10,10,12,13, 9,11,10,13,12, + 10,12,12,14,14,11,13,12,14,14, 8,10,10,12,12, 9, + 10,11,12,14,10,11,11,13,13,12,12,13,13,15,12,13, + 13,15,14, 9,10,10,13,13,10,11,11,13,13,10,12,10, + 14,13,12,13,13,14,15,12,13,13,15,14,11,12,12,13, + 14,12,12,13,13,15,12,13,13,14,14,13,13,14,13,16, + 14,15,15,16,15,11,12,12,14,14,13,13,13,15,14,12, + 13,13,15,14,14,15,15,16,15,14,14,14,16,14, 7, 9, + 10,12,12, 9,10,11,13,13, 9,11,10,13,13,11,12,13, + 14,15,12,13,13,15,14, 9,10,11,12,13,10,10,12,13, + 14,11,11,12,14,14,12,12,14,14,15,13,13,13,15,15, + 9,11,11,13,13,11,12,12,14,14,10,12,10,14,13,13, + 14,13,15,15,12,14,13,15,14,12,12,13,13,15,12,12, + 14,13,15,13,14,14,15,15,14,14,15,14,17,14,15,15, + 16,16,12,13,13,15,14,13,14,14,15,15,12,14,13,15, + 14,14,15,15,16,16,14,15,14,16,14, 7,10,10,12,12, + 10,11,11,12,13,10,12,10,14,12,12,13,13,14,15,12, + 13,13,15,14, 9,11,10,13,12,10,10,12,12,14,11,13, + 12,14,13,13,13,14,13,15,13,14,14,15,14,10,11,11, + 13,13,12,12,12,13,14,10,12,10,14,12,13,14,14,15, + 15,13,14,13,15,13,12,13,13,14,14,12,12,13,14,15, + 13,14,14,15,15,13,13,14,13,15,14,15,15,16,16,12, + 13,13,14,14,13,14,14,15,15,12,13,13,15,13,15,15, + 15,16,16,13,14,13,16,13,11,12,13,14,14,12,13,14, + 14,15,12,13,13,15,15,14,14,15,15,17,14,15,15,16, + 16,12,13,14,14,15,13,13,14,14,16,13,14,14,15,16, + 14,14,16,15,17,15,15,16,16,16,12,13,13,15,15,13, + 14,14,15,16,13,14,14,15,16,15,15,16,17,17,15,16, + 15,17,16,14,15,15,15,16,15,15,16,15,17,15,15,16, + 16,17,16,16,16,16,18,16,16,17,17,17,14,15,15,16, + 16,15,16,16,16,17,15,16,15,17,16,16,17,17,17,17, + 16,17,16,18,17,11,12,12,14,14,13,13,14,14,15,13, + 14,13,15,14,14,15,15,15,16,14,15,15,17,15,12,13, + 13,15,14,13,13,14,15,15,14,15,14,16,15,15,15,15, + 15,16,15,16,15,17,16,12,13,13,15,15,14,14,14,15, + 16,13,14,13,16,15,15,15,16,16,17,15,16,15,17,15, + 14,15,15,16,16,14,15,15,16,16,15,16,16,17,16,15, + 15,16,15,17,16,17,17,18,17,14,15,15,16,16,15,16, + 16,16,17,14,15,15,17,16,17,17,17,17,18,15,16,16, + 18,15, 6, 9, 9,12,12, 9,10,11,12,13, 8,10,10,13, + 12,11,12,13,14,14,10,12,12,14,13, 9,10,10,12,13, + 10,10,12,13,14,10,11,11,13,13,12,13,13,14,15,12, + 13,13,15,14, 8,10,10,12,12,10,11,11,13,13, 9,11, + 10,13,13,12,13,13,14,15,12,13,12,15,13,11,12,12, + 14,14,12,13,13,13,15,13,13,13,14,15,14,14,15,14, + 16,14,15,15,15,15,11,12,12,14,13,12,13,13,15,14, + 12,13,12,15,13,14,14,15,16,16,13,14,13,16,13, 7, + 10,10,12,12,10,10,12,12,14,10,11,11,13,12,12,13, + 13,13,15,12,13,13,15,14,10,11,11,13,13,10,10,12, + 12,14,12,12,12,14,13,13,13,14,13,15,13,14,14,15, + 14, 9,10,11,13,13,11,12,12,13,14,10,12,10,14,12, + 13,13,14,14,15,13,13,12,15,13,12,13,13,14,14,12, + 13,13,14,15,13,14,14,15,15,13,13,15,13,16,15,15, + 15,16,16,12,13,13,14,14,13,14,14,15,15,12,13,12, + 15,14,15,15,15,16,16,13,14,13,15,13, 7,10, 9,12, + 12, 9,10,11,13,13, 9,11,10,13,13,11,13,13,14,15, + 11,13,12,15,14, 9,11,11,13,13,10,10,12,13,14,11, + 12,12,14,14,12,13,14,14,15,13,13,13,15,15, 9,11, + 10,13,12,11,12,11,14,14,10,12,10,14,13,13,14,13, + 15,15,12,14,12,15,14,12,13,13,14,15,13,13,14,14, + 15,13,14,14,15,15,14,14,15,14,17,14,15,15,16,16, + 12,13,12,15,13,13,14,14,15,15,12,14,13,15,13,14, + 15,15,16,16,14,15,14,16,14,11,12,12,14,14,13,13, + 14,14,15,13,14,13,15,15,14,15,15,16,17,14,15,15, + 16,15,12,13,13,15,15,13,13,14,15,16,14,14,14,16, + 15,15,15,16,15,17,15,16,15,17,16,12,13,13,14,15, + 14,14,15,15,16,13,14,13,15,15,15,15,16,16,17,15, + 15,15,16,15,14,15,15,16,16,14,15,15,16,17,15,16, + 16,17,17,16,15,16,15,17,16,17,17,17,17,14,15,15, + 15,16,15,15,16,16,17,14,15,15,16,16,16,16,17,17, + 18,15,16,15,17,15,11,13,12,14,14,12,13,13,15,15, + 12,14,13,15,14,14,15,15,16,16,14,15,14,16,15,12, + 13,13,15,15,13,14,14,15,16,13,14,14,16,16,15,15, + 16,16,17,15,16,15,17,16,12,13,13,15,14,13,14,14, + 16,15,13,14,13,16,14,15,16,15,17,16,15,15,14,18, + 15,14,15,15,16,16,15,15,16,16,17,15,16,15,17,16, + 16,16,17,17,18,16,17,17,18,17,14,15,15,16,15,15, + 16,15,17,16,15,15,15,17,15,16,17,17,18,17,16,17, + 16,18,15,10,12,12,14,14,12,13,13,14,14,12,13,13, + 14,14,13,14,14,15,15,13,14,14,16,15,11,12,13,14, + 14,12,13,13,15,15,12,13,13,15,15,13,14,15,15,16, + 14,15,15,16,16,12,13,13,14,14,13,13,14,15,15,13, + 14,13,15,15,14,15,15,16,16,14,15,14,16,15,13,14, + 14,15,15,13,14,14,15,16,14,14,15,16,16,14,15,15, + 15,17,15,16,16,17,17,13,14,14,15,15,14,15,15,16, + 16,14,15,15,16,16,15,16,16,16,17,15,16,15,17,16, + 11,12,12,14,14,12,13,13,14,15,12,13,13,15,14,13, + 14,14,15,16,13,14,14,16,15,12,13,13,14,15,13,13, + 14,15,15,13,14,14,15,15,14,14,15,15,17,14,15,15, + 16,16,12,13,13,15,15,13,14,14,15,15,13,14,13,15, + 15,14,15,15,16,17,14,15,15,16,16,13,13,14,15,16, + 14,14,15,15,16,14,15,15,16,16,15,15,16,15,18,15, + 16,16,17,17,14,15,15,16,16,15,15,15,16,16,14,15, + 15,17,16,16,16,16,17,17,15,16,16,17,16,10,12,12, + 14,14,12,13,13,14,15,12,13,13,15,14,14,14,15,15, + 16,14,15,14,16,15,12,13,13,15,14,13,13,14,15,15, + 13,14,14,15,15,14,14,15,15,16,14,15,15,16,16,12, + 13,13,15,15,13,14,14,15,16,13,14,13,15,14,15,15, + 15,16,16,14,15,15,16,15,13,14,14,16,15,14,14,14, + 15,16,14,15,15,16,16,15,15,16,15,17,16,17,16,17, + 17,14,14,15,15,16,15,15,16,16,16,14,15,14,16,15, + 16,16,16,17,17,15,16,15,17,15,11,13,13,14,15,13, + 13,14,15,15,13,14,13,15,15,14,15,15,15,16,14,15, + 15,17,15,13,13,14,15,15,13,14,15,15,16,14,14,14, + 16,16,15,14,16,15,17,15,16,16,17,16,13,14,14,15, + 15,14,14,14,16,16,13,15,14,16,15,15,15,16,17,17, + 15,16,15,17,16,14,15,15,15,16,15,15,16,15,17,15, + 16,16,16,17,16,16,17,15,18,16,17,17,17,17,14,15, + 15,16,16,15,16,16,17,17,15,16,15,17,16,16,17,17, + 18,18,16,17,15,18,16,10,12,12,14,14,13,13,14,14, + 15,13,14,13,15,14,14,15,15,15,16,15,15,15,16,15, + 12,13,13,15,14,12,12,14,14,15,14,15,14,16,15,15, + 14,15,14,17,15,16,16,17,16,12,13,13,14,15,14,14, + 15,15,16,13,14,12,16,14,15,16,16,16,17,15,16,14, + 17,15,14,15,14,16,15,14,14,15,15,15,15,16,15,17, + 16,15,14,16,14,16,16,17,17,18,17,14,14,15,15,16, + 15,16,16,16,17,14,15,14,16,15,16,16,17,17,17,15, + 16,14,17,14,10,12,12,14,13,12,13,13,14,14,11,13, + 12,14,14,13,14,14,15,16,13,14,14,16,15,12,13,13, + 14,14,13,13,14,15,15,13,14,13,15,15,14,14,15,15, + 16,14,15,15,16,16,11,13,12,14,14,12,13,13,15,15, + 12,13,13,15,15,14,15,15,16,16,13,14,14,16,15,13, + 14,14,15,15,14,15,15,15,16,14,15,15,16,16,15,16, + 16,16,17,16,16,16,17,17,13,14,14,15,15,14,15,15, + 16,16,13,14,14,16,15,15,16,16,17,17,15,15,15,17, + 15,11,12,12,14,14,12,13,13,14,15,12,13,13,15,14, + 14,14,15,15,16,14,14,14,16,15,12,13,13,15,14,13, + 13,14,15,15,13,14,14,16,15,14,15,15,15,16,15,15, + 15,16,16,12,13,13,14,15,13,13,14,15,15,13,14,13, + 15,15,15,15,15,16,16,14,15,14,16,15,14,14,15,16, + 16,14,15,15,15,16,15,16,15,16,16,15,15,16,15,17, + 16,16,16,17,17,13,14,14,15,16,14,15,15,16,16,14, + 14,14,16,16,16,16,16,17,17,15,15,15,17,15,11,12, + 12,14,14,12,13,13,14,15,12,13,13,15,14,14,14,14, + 15,16,13,14,14,16,15,12,13,13,15,15,13,13,14,15, + 16,13,14,14,15,15,14,15,15,16,17,14,15,15,17,16, + 12,13,13,15,14,13,14,14,15,15,13,14,13,15,15,14, + 15,15,16,16,14,15,14,17,15,14,15,15,16,16,14,15, + 15,16,17,15,15,15,17,17,15,16,16,16,17,16,17,16, + 17,17,13,15,14,16,15,14,15,15,16,16,14,15,14,16, + 15,16,16,16,17,17,15,16,15,17,15,10,12,12,14,14, + 13,13,14,14,15,13,14,13,15,14,14,15,15,15,17,14, + 15,15,16,15,12,13,13,15,14,12,12,14,14,15,14,15, + 14,16,15,15,14,16,15,17,15,16,16,17,16,12,13,13, + 14,15,14,14,15,15,16,12,14,12,15,14,15,16,16,16, + 17,15,16,14,17,14,14,15,14,16,16,14,14,15,15,16, + 15,16,16,17,16,15,14,16,14,17,16,17,17,18,17,14, + 14,15,15,16,15,15,16,16,17,14,15,14,16,15,16,17, + 17,17,18,15,16,14,17,14,11,13,13,15,14,13,13,14, + 15,15,12,14,13,15,15,14,15,15,15,17,14,15,14,16, + 15,13,14,14,15,15,13,14,15,15,16,14,15,14,16,16, + 15,15,16,16,17,15,16,16,17,17,13,14,13,15,15,14, + 14,14,16,16,13,15,14,16,15,15,16,16,17,17,15,16, + 14,17,15,15,15,15,16,17,15,15,16,16,17,15,16,16, + 17,17,16,15,17,16,17,17,17,17,18,18,14,15,15,17, + 15,15,16,16,17,16,15,16,15,17,15,16,17,17,17,17, + 16,17,15,18,15, +}; + +static const static_codebook _44p7_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p7_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p7_p5_0, + 0 +}; + +static const long _vq_quantlist__44p7_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p7_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p7_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p7_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p7_p5_1, + 0 +}; + +static const long _vq_quantlist__44p7_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p6_0[] = { + 2, 5, 6, 5, 7, 8, 5, 8, 7, 5, 7, 7, 7, 7, 9, 8, + 9, 9, 5, 7, 7, 8, 9, 9, 7, 9, 7, 6, 8, 8, 8, 9, + 10, 8, 9, 9, 8, 9,10, 9, 9,11,10,10,11, 8,10, 9, + 10,10,11, 9,10,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 8, + 9,10, 9,10,10,10,11,10, 8,10, 9,10,11,10, 9,11, + 9, 6, 8, 8, 7, 9, 9, 8, 9, 9, 7, 9, 9, 9, 9,10, + 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9, 9, + 10,10, 9,10,10, 9, 9,10,10, 9,11,10,11,11, 9,10, + 10,10,11,11,10,11,10, 6, 9, 8, 9,10,10, 9,10, 9, + 8,10,10, 9, 9,10,10,11,11, 9,10,10,10,11,11, 9, + 11, 9, 6, 8, 8, 8, 9, 9, 7, 9, 9, 8, 9, 9, 9, 9, + 10, 9,10,10, 7, 9, 9, 9,10,10, 9,10, 9, 6, 8, 9, + 9, 9,10, 9,10,10, 9,10,10, 9, 9,11,10,11,11, 8, + 10,10,10,11,11, 9,10, 9, 7, 9, 9, 9,10,10, 9,10, + 10, 9,10,10,10,10,11,10,11,11, 9,10, 9,10,11,11, + 10,11, 9, +}; + +static const static_codebook _44p7_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p7_p6_0, + 0 +}; + +static const long _vq_quantlist__44p7_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p6_1[] = { + 4, 7, 7, 6, 7, 8, 6, 8, 7, 7, 7, 8, 7, 7, 8, 8, + 8, 8, 7, 7, 7, 8, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, + 8, 9, 9, 8, 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, + 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, 8, + 8, 9, 8, 9, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, + 8, 9, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, + 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, + 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 9, 9, 9, + 8, 9, 8, +}; + +static const static_codebook _44p7_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p7_p6_1, + 0 +}; + +static const long _vq_quantlist__44p7_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 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, +}; + +static const static_codebook _44p7_p7_0 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p7_0, + 1, -513979392, 1633504256, 2, 0, + (long *)_vq_quantlist__44p7_p7_0, + 0 +}; + +static const long _vq_quantlist__44p7_p7_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p7_p7_1[] = { + 1, 5, 5, 4,10,10, 5,10,10, 5,10,10,10,10,10,10, + 10,10, 5,10,10,10,10,10, 9,10,10, 6,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10, 7,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,11,11, +}; + +static const static_codebook _44p7_p7_1 = { + 5, 243, + (char *)_vq_lengthlist__44p7_p7_1, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44p7_p7_1, + 0 +}; + +static const long _vq_quantlist__44p7_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p7_p7_2[] = { + 1, 3, 2, 4, 5, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _44p7_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p7_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p7_p7_2, + 0 +}; + +static const long _vq_quantlist__44p7_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p7_p7_3[] = { + 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, +}; + +static const static_codebook _44p7_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p7_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p7_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p7_short[] = { + 3, 9,14,16,17,19,22,22, 5, 4, 6, 9,11,13,17,20, + 9, 5, 5, 6, 9,11,15,19,11, 7, 5, 5, 7, 9,13,17, + 14, 9, 7, 6, 6, 7,11,14,16,11, 9, 7, 6, 4, 4, 8, + 19,15,13,11, 9, 4, 3, 4,21,16,16,15,12, 6, 4, 4, +}; + +static const static_codebook _huff_book__44p7_short = { + 2, 64, + (char *)_huff_lengthlist__44p7_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p8_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p8_l0_0[] = { + 2, 4, 4, 7, 7, 8, 8,10,10,11,11,12,12, 4, 5, 5, + 7, 7, 9, 9,10, 9,12,10,12,12, 4, 5, 5, 7, 7, 9, + 9, 9,10,10,12,12,12, 7, 7, 7, 7, 8, 9, 8,11, 5, + 12, 6,12,10, 7, 7, 7, 8, 7, 8, 9, 5,11, 6,12,10, + 12, 8, 9, 9, 9, 9, 9, 9,11, 7,11, 7,11, 9, 8, 9, + 9, 9, 9, 9, 9, 7,10, 7,11, 9,11,10,10,10,10,10, + 10,10,11,10,11, 8,12, 9,10,10,10,10,10,10,10,10, + 11, 8,11, 9,12,10,11,11,11,11,11,11,11,11,12,10, + 12,11,10,11,11,11,11,11,11,11,11,10,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,11,12,12,12, + 12,12,12,12,12,12,11,12,12, +}; + +static const static_codebook _44p8_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p8_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p8_l0_0, + 0 +}; + +static const long _vq_quantlist__44p8_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p8_l0_1[] = { + 4, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44p8_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p8_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p8_l0_1, + 0 +}; + +static const long _vq_quantlist__44p8_l1_0[] = { + 54, + 29, + 79, + 0, + 108, +}; + +static const char _vq_lengthlist__44p8_l1_0[] = { + 1, 2, 3, 6, 7, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44p8_l1_0 = { + 2, 25, + (char *)_vq_lengthlist__44p8_l1_0, + 1, -514516992, 1620639744, 7, 0, + (long *)_vq_quantlist__44p8_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p8_lfe[] = { + 2, 3, 1, 3, +}; + +static const static_codebook _huff_book__44p8_lfe = { + 2, 4, + (char *)_huff_lengthlist__44p8_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p8_long[] = { + 2, 7,14,16,17,18,20,21, 7, 4, 6, 8,11,12,14,16, + 13, 5, 4, 4, 8, 9,11,13,15, 8, 4, 3, 5, 7, 9,10, + 17,11, 8, 4, 4, 6, 9, 9,17,11, 9, 7, 6, 5, 7, 8, + 19,13,11, 9, 9, 7, 8, 8,21,15,13,11,10, 8, 8, 7, +}; + +static const static_codebook _huff_book__44p8_long = { + 2, 64, + (char *)_huff_lengthlist__44p8_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p8_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p8_p1_0[] = { + 2, 5, 5, 4, 7, 7, 4, 7, 7, 5, 7, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 6, 7, 8, 8, 9, + 10, 8, 9,10, 8, 9,10,10,10,12,10,11,12, 8,10,10, + 10,11,12,10,11,11, 6, 8, 7, 8,10, 9, 8,10, 9, 8, + 10,10,10,11,11,10,12,11, 8,10, 9,10,12,11,10,12, + 10, 5, 8, 8, 8,10,10, 8,10,10, 7, 9,10, 9,10,11, + 9,11,11, 8,10,10,10,12,12,10,12,11, 7, 9, 9, 9, + 10,11, 9,11,11, 9, 9,11,10,11,12,10,11,12, 9,11, + 11,11,12,12,11,12,12, 7, 9, 9,10,11,11,10,12,11, + 9,11,10,11,11,12,11,13,12,10,11,11,12,13,13,11, + 13,11, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11, + 12,10,12,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9, + 10,11,12,10,11,11,10,11,11,11,11,13,12,13,13, 9, + 10,11,12,12,13,11,12,11, 7, 9, 9, 9,11,11, 9,11, + 10, 9,11,11,11,12,12,11,12,12, 9,11, 9,10,12,11, + 10,12,11, +}; + +static const static_codebook _44p8_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p8_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p8_p1_0, + 0 +}; + +static const long _vq_quantlist__44p8_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p8_p2_0[] = { + 4, 6, 6, 9, 9, 6, 8, 8,10,10, 6, 8, 8,10,10, 8, + 9,10,12,12, 8,10, 9,12,12, 6, 8, 8,10,10, 8, 8, + 9,10,11, 8, 9, 9,11,11, 9,10,11,12,13,10,11,11, + 13,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 8, 9, 8,11, + 10,10,11,11,13,13, 9,11,10,13,12, 9,10,10,12,12, + 10,10,11,12,13,10,11,11,13,13,12,12,13,12,15,12, + 13,13,15,14, 9,10,10,12,12,10,11,11,13,13,10,11, + 10,13,12,12,13,13,14,15,12,13,12,15,12, 7, 8, 8, + 10,11, 8, 9,10,11,12, 8, 9, 9,11,11,10,11,11,13, + 14,10,11,11,13,13, 8, 9, 9,11,12, 9,10,11,11,13, + 9,10,10,12,12,11,11,12,13,15,11,12,12,14,14, 8, + 9, 9,11,11, 9,10,11,12,13, 9,10,10,12,12,11,12, + 12,14,15,11,12,12,14,14,10,11,12,13,13,11,12,12, + 13,14,12,12,12,14,14,13,13,14,14,16,14,14,14,16, + 15,10,11,11,13,13,12,12,12,14,14,11,12,12,14,13, + 14,14,14,15,16,13,14,13,16,14, 7, 8, 8,11,10, 8, + 9, 9,11,11, 8,10, 9,12,11,10,11,11,13,13,10,11, + 11,14,13, 8, 9, 9,12,11, 9,10,10,12,12, 9,11,10, + 13,12,11,12,12,13,14,11,12,12,15,14, 8, 9, 9,12, + 11, 9,10,10,12,12, 9,11,10,13,11,11,12,12,14,14, + 11,12,12,14,13,10,11,11,13,13,11,12,12,13,14,12, + 13,12,14,14,13,13,14,14,16,13,14,14,16,15,10,11, + 11,13,13,12,12,12,14,14,11,12,12,14,13,13,14,14, + 15,15,13,14,13,16,14, 9,10,11,12,13,11,11,12,12, + 14,11,11,12,13,14,13,13,14,14,16,13,13,14,15,15, + 11,11,12,12,14,12,12,13,13,15,12,12,13,13,15,14, + 14,15,15,16,14,14,14,15,16,11,12,12,13,14,12,12, + 13,14,15,12,13,12,14,14,14,14,15,15,16,14,14,14, + 16,16,13,13,14,15,16,14,14,15,15,16,14,15,15,16, + 16,15,15,16,16,18,16,16,16,17,17,13,14,14,15,15, + 14,14,15,16,16,14,15,14,16,16,16,16,16,17,18,15, + 16,16,17,16, 9,11,10,13,12,11,12,11,14,13,11,12, + 11,14,12,13,14,13,15,14,13,14,13,16,14,11,12,12, + 14,13,12,12,13,14,14,12,13,12,15,14,14,14,14,16, + 16,14,15,14,17,15,11,12,11,14,12,12,13,12,15,13, + 12,13,12,15,13,14,14,14,16,15,14,15,14,16,15,13, + 14,14,15,15,14,14,15,16,16,14,15,14,16,16,15,15, + 16,16,17,16,16,16,17,17,13,14,14,16,15,14,15,15, + 16,16,14,15,14,17,15,16,16,16,17,17,15,16,15,18, + 16, 7, 8, 8,10,11, 8, 9, 9,11,12, 8, 9, 9,12,11, + 10,11,11,13,14,10,11,11,14,13, 8, 9, 9,11,11, 9, + 10,10,12,12, 9,10,10,12,12,11,12,12,13,14,11,12, + 12,14,14, 8, 9, 9,12,11, 9,10,11,12,13, 9,11,10, + 13,12,11,12,12,14,14,11,12,12,14,13,10,11,11,13, + 13,11,12,12,13,14,11,12,12,14,14,13,13,14,14,16, + 13,14,14,16,15,10,12,11,13,13,12,12,12,14,14,11, + 12,12,14,13,14,14,14,15,16,13,14,14,16,14, 8, 9, + 9,11,11, 9,10,10,12,12, 9,10,10,12,12,11,11,12, + 13,14,11,12,12,14,14, 9, 9,10,11,12,10,10,11,12, + 13,10,10,11,12,13,12,12,13,14,15,12,12,13,14,15, + 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12, + 13,13,15,15,12,13,13,15,14,11,11,12,13,14,12,12, + 13,13,15,12,12,13,14,15,14,14,15,14,16,14,14,15, + 15,16,11,12,12,14,14,12,13,13,15,15,12,13,13,15, + 14,14,15,15,16,16,14,15,14,17,15, 8, 9, 9,11,11, + 9,10,10,12,12, 9,11,10,13,12,11,12,12,14,14,11, + 13,12,15,13, 9,10,10,12,12,10,10,11,12,13,10,12, + 11,13,13,12,12,13,13,15,12,13,13,15,14, 9,10,10, + 12,12,11,11,12,13,13,10,12,10,13,12,12,13,13,15, + 15,12,13,13,15,13,11,12,12,14,14,12,12,13,14,14, + 12,13,13,15,14,13,13,14,13,16,14,15,14,16,16,11, + 12,12,14,14,13,13,13,15,15,12,13,12,15,14,14,15, + 15,16,17,14,15,13,16,13,10,11,11,13,14,11,12,12, + 13,15,11,12,12,14,14,13,14,14,15,16,13,14,14,16, + 16,11,11,12,12,14,12,12,13,13,15,12,13,13,13,15, + 14,14,15,14,17,14,14,15,15,16,11,12,12,14,14,12, + 13,13,15,15,12,13,13,15,15,14,15,15,16,17,14,15, + 15,16,16,13,14,14,14,16,14,14,15,14,17,14,15,15, + 14,17,16,16,17,15,18,16,16,17,16,18,13,14,14,16, + 16,14,15,15,17,16,14,15,15,17,16,16,17,17,18,18, + 16,17,16,18,17,10,11,11,14,13,11,12,12,14,14,11, + 13,12,15,14,14,14,14,16,15,14,15,14,16,15,11,12, + 12,14,13,12,13,13,15,14,13,14,13,15,14,14,15,15, + 16,16,14,15,15,17,15,11,12,12,14,14,13,13,13,15, + 15,12,13,13,15,14,15,15,15,17,17,14,15,15,17,15, + 13,14,14,16,15,14,15,15,16,16,15,15,15,17,16,16, + 16,16,16,17,16,17,16,18,17,14,14,14,16,16,15,15, + 15,16,16,14,15,14,17,16,16,17,17,17,18,16,17,16, + 18,16, 7, 8, 8,11,11, 8, 9, 9,11,12, 8, 9, 9,12, + 11,10,11,11,13,14,10,11,11,14,13, 8, 9, 9,11,12, + 9,10,11,12,13, 9,11,10,13,12,11,12,12,13,14,11, + 12,12,14,14, 8, 9, 9,11,11, 9,10,10,12,12, 9,10, + 10,13,12,11,12,12,14,14,11,12,11,14,13,10,11,12, + 13,13,11,12,12,13,14,12,13,12,14,14,13,13,14,14, + 16,13,14,14,16,15,10,11,11,13,13,11,12,12,14,14, + 11,12,12,14,13,13,14,14,15,16,13,14,13,16,14, 8, + 9, 9,11,11, 9,10,11,12,13, 9,10,10,12,12,11,12, + 13,13,14,11,12,12,14,14, 9,10,10,12,12,10,10,11, + 12,13,11,12,11,13,13,12,12,13,13,15,12,13,13,15, + 15, 9,10,10,12,12,10,11,12,13,14,10,11,10,13,12, + 12,13,13,14,15,12,13,12,15,13,12,12,12,14,14,12, + 12,13,14,15,13,13,13,15,15,14,14,15,13,16,14,15, + 15,16,16,11,12,12,14,14,12,13,13,14,15,12,13,12, + 14,14,14,14,15,16,16,13,14,13,16,14, 8, 9, 9,11, + 11, 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,14, + 11,12,11,14,14, 9,10,10,12,12,10,11,11,13,13,10, + 11,11,13,13,12,13,13,14,15,12,13,13,15,14, 9,10, + 9,12,11,10,11,10,13,12,10,11,10,13,12,12,13,12, + 15,14,12,13,12,15,14,11,12,12,14,14,12,13,13,14, + 15,12,13,13,15,15,14,14,15,15,17,14,15,15,16,16, + 11,12,11,14,13,12,13,12,15,14,12,13,12,15,13,14, + 15,14,16,15,13,15,14,17,14,10,11,11,13,14,11,12, + 13,13,15,11,12,12,14,14,14,14,15,15,17,13,14,14, + 15,16,11,12,12,14,14,12,12,13,14,15,13,13,13,15, + 15,14,15,15,15,17,15,15,15,16,16,11,12,12,13,14, + 13,13,14,14,15,12,13,13,14,15,14,15,15,16,17,14, + 15,15,16,16,14,14,14,16,16,14,14,15,15,17,15,15, + 15,17,16,16,16,17,16,18,16,17,17,18,17,13,14,14, + 15,16,14,15,15,16,17,14,15,15,16,16,16,17,17,17, + 18,16,16,16,17,16,10,11,11,14,13,11,12,12,14,14, + 11,12,12,15,13,13,14,14,16,15,13,14,14,16,15,11, + 12,12,14,14,12,13,13,15,15,12,13,13,15,15,14,15, + 15,16,17,14,15,15,17,16,11,12,11,14,12,12,13,13, + 15,13,12,13,12,15,13,14,15,15,16,15,14,15,14,17, + 14,13,14,14,16,16,14,15,15,16,17,14,15,15,16,17, + 16,16,17,17,18,16,17,17,18,18,13,14,14,16,13,14, + 15,15,17,14,14,15,14,17,14,16,17,16,17,16,16,17, + 16,18,15, 8,11,11,13,13,10,12,12,14,14,11,12,12, + 14,14,13,13,14,15,16,13,14,14,16,15,10,11,11,14, + 14,11,12,12,14,15,11,12,12,15,14,13,14,14,15,16, + 13,14,14,16,16,11,12,12,14,14,12,13,13,15,15,12, + 13,12,15,14,14,14,15,16,16,14,15,14,16,16,12,13, + 13,15,15,12,13,14,15,16,13,14,14,16,16,14,15,15, + 16,17,15,15,16,17,17,13,14,14,16,15,14,15,15,16, + 16,14,15,14,16,16,16,16,16,17,17,15,16,16,18,16, + 10,11,11,13,14,11,12,12,14,15,11,12,12,15,14,13, + 14,14,16,16,13,14,14,16,16,11,11,12,14,14,12,12, + 13,14,15,12,13,13,15,15,14,14,15,15,17,14,14,15, + 16,16,11,12,12,15,14,12,13,13,15,15,12,13,13,15, + 15,14,15,15,17,17,14,15,15,17,16,13,12,14,14,16, + 13,13,15,14,17,14,13,15,15,17,15,14,16,15,18,16, + 15,16,16,18,13,14,14,16,16,14,15,15,17,17,14,15, + 15,17,16,16,17,17,18,18,16,17,16,18,17,10,11,11, + 14,13,11,12,12,14,14,11,13,12,15,14,13,14,14,15, + 16,13,14,14,16,16,11,12,12,14,14,12,13,13,14,15, + 12,13,13,15,15,14,14,15,15,16,14,15,15,17,16,11, + 12,12,14,14,13,13,13,15,15,12,13,13,15,14,14,15, + 15,16,17,14,15,14,17,15,13,14,13,16,15,14,14,14, + 15,16,14,15,14,16,16,15,15,16,16,17,16,16,16,18, + 17,14,14,14,16,16,15,15,15,17,16,14,15,14,17,16, + 16,16,17,17,18,16,17,16,18,16,11,13,13,15,15,12, + 13,14,15,16,12,14,14,15,15,14,15,15,16,17,14,15, + 15,17,17,12,13,14,14,16,13,14,14,14,16,14,14,14, + 15,16,15,15,16,15,18,15,16,16,17,17,13,14,14,16, + 16,14,14,15,16,16,14,15,14,16,16,15,16,16,17,18, + 15,16,16,18,17,14,14,16,13,17,15,15,16,14,18,15, + 15,16,14,18,16,16,18,15,19,17,17,18,16,18,15,16, + 15,17,17,15,16,17,18,18,16,16,16,18,17,17,18,18, + 19,19,17,18,17,19,18,11,12,12,15,14,13,13,14,15, + 16,13,14,13,16,14,15,15,15,16,17,15,16,15,17,16, + 12,13,13,15,14,13,13,14,15,15,14,15,14,16,15,15, + 15,16,16,17,16,16,16,18,17,12,13,13,15,15,14,14, + 15,16,16,13,14,13,16,15,16,16,16,17,18,15,16,15, + 17,16,14,15,14,17,15,14,15,15,16,16,15,16,15,17, + 16,16,15,16,15,17,17,18,17,18,17,15,15,15,16,17, + 16,16,16,17,17,15,16,15,17,16,17,18,18,18,18,16, + 17,16,18,15, 8,11,11,13,13,11,12,12,14,14,10,12, + 12,14,14,13,14,14,15,16,13,14,13,16,15,11,12,12, + 14,14,12,12,13,14,15,12,13,13,15,15,14,14,15,15, + 16,14,14,14,16,16,10,11,11,14,14,11,12,12,14,15, + 11,12,12,15,14,13,14,14,16,16,13,14,14,16,15,13, + 14,14,15,16,14,14,15,16,16,14,15,15,16,16,15,16, + 16,16,18,16,16,16,17,17,12,13,13,15,15,13,14,14, + 16,16,12,14,13,16,15,15,16,15,17,17,14,16,15,17, + 16,10,11,11,13,14,11,12,13,14,15,11,13,12,14,14, + 14,14,15,16,16,13,14,14,16,16,11,12,12,14,14,12, + 13,13,14,15,13,14,13,15,15,14,15,15,16,17,14,15, + 15,17,16,11,12,12,14,14,12,13,13,15,15,12,13,12, + 15,14,14,15,15,16,17,14,15,15,16,16,14,14,14,16, + 16,14,14,15,16,16,15,15,15,16,16,16,16,17,16,18, + 16,17,17,18,18,13,13,14,15,16,14,14,15,16,17,13, + 14,14,16,16,16,16,17,17,18,15,16,15,17,16,10,11, + 11,14,13,11,12,12,14,14,11,12,12,15,14,13,14,14, + 16,16,13,14,14,16,16,11,12,12,14,14,12,13,13,15, + 15,12,13,13,15,15,14,15,15,16,17,14,15,15,17,16, + 11,12,11,14,14,12,13,13,15,15,12,13,12,15,14,14, + 15,14,16,16,14,15,14,17,16,14,14,14,16,16,14,15, + 15,16,17,14,15,15,17,17,16,16,17,17,18,16,17,17, + 18,18,13,14,12,16,14,14,15,13,17,15,13,15,13,17, + 14,16,16,15,18,16,15,17,14,18,15,11,12,12,14,15, + 13,13,14,14,16,13,14,13,15,14,15,15,16,16,17,15, + 16,15,17,16,12,13,13,15,15,13,13,14,15,16,14,15, + 14,16,16,15,15,16,15,18,16,16,16,18,17,12,13,13, + 15,15,14,14,15,15,16,13,14,13,15,15,16,16,16,16, + 18,15,16,15,17,16,15,15,15,17,16,15,15,16,16,17, + 16,16,16,18,17,16,16,17,15,18,17,18,17,19,18,14, + 14,15,15,17,15,15,16,16,17,14,15,15,16,16,17,17, + 18,17,19,16,17,15,17,15,11,13,12,15,15,12,14,14, + 15,15,12,14,13,16,15,15,15,15,17,17,14,15,15,17, + 16,12,14,14,16,16,14,14,15,16,16,14,14,14,16,16, + 15,16,17,17,18,15,16,16,18,17,12,14,13,16,14,13, + 14,14,16,15,13,15,14,16,14,15,16,16,17,17,15,16, + 15,18,15,15,15,16,17,17,15,16,16,17,18,16,16,16, + 18,18,17,17,18,18,19,17,17,18,19,19,14,15,14,17, + 13,15,16,15,18,14,15,16,15,18,14,17,18,17,18,16, + 16,18,16,19,15, +}; + +static const static_codebook _44p8_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p8_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p8_p2_0, + 0 +}; + +static const long _vq_quantlist__44p8_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p8_p3_0[] = { + 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 7, 9, + 10, 8, 9, 9, 8, 9,10, 9,10,12,10,11,11, 8,10, 9, + 10,11,12, 9,11,10, 5, 8, 7, 8,10, 9, 7,10, 9, 8, + 9,10, 9,10,11,10,12,11, 8,10, 9,10,11,11, 9,12, + 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9,10, 9,10,11, + 9,11,11, 8,10, 9,10,11,11,10,12,10, 7, 9,10, 9, + 10,12, 9,11,11, 9, 9,12,11,10,13,11,11,13,10,12, + 11,11,13,13,11,13,12, 7, 9, 9, 9,11,11, 9,12,11, + 9,11,10,10,11,12,11,13,12, 9,11,11,12,13,13,11, + 13,11, 5, 8, 8, 8, 9,10, 7,10, 9, 8, 9,10,10,10, + 12,10,11,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9, + 9,11,12, 9,11,11, 9,11,11,11,11,13,12,13,13, 9, + 10,11,11,12,13,10,12,11, 7,10, 9, 9,11,11, 9,12, + 10,10,11,12,11,12,13,12,13,13, 9,12, 9,11,13,11, + 10,13,10, +}; + +static const static_codebook _44p8_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p8_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p8_p3_0, + 0 +}; + +static const long _vq_quantlist__44p8_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p8_p3_1[] = { + 6, 7, 7, 7, 7, 8, 7, 8, 7, 7, 7, 8, 7, 8, 8, 8, + 8, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, + 8, 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 9, 9, 8, + 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, + 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 8, + 8, 9, 8, +}; + +static const static_codebook _44p8_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p8_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p8_p3_1, + 0 +}; + +static const long _vq_quantlist__44p8_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p8_p4_0[] = { + 2, 5, 5, 4, 7, 8, 4, 8, 7, 5, 7, 8, 7, 7,10, 8, + 9, 9, 5, 7, 7, 8, 9, 9, 7,10, 7, 5, 7, 8, 8, 9, + 11, 8,10,10, 8, 9,10,10,10,12,11,12,12, 8,10,10, + 10,12,12,10,12,11, 5, 8, 7, 8,10,10, 8,11, 9, 8, + 10,10,10,11,12,10,12,12, 8,10, 9,11,12,12,10,12, + 10, 5, 8, 8, 7,10,10, 8,11,10, 7, 9,10, 9,10,12, + 10,12,12, 8,10,10,10,12,12,10,12,11, 7, 9,10, 9, + 11,12,10,12,11, 9, 9,12,10,10,13,12,12,13,10,12, + 11,12,13,13,11,13,11, 7,10, 9,10,11,12,10,13,11, + 9,11,11,11,11,13,12,14,13,10,11,11,12,14,14,11, + 14,11, 5, 8, 8, 8,10,11, 7,10,10, 8,10,10,10,11, + 12,10,12,12, 7,10, 9,10,12,12, 9,12,10, 7, 9,10, + 10,11,13,10,12,11,10,11,11,11,11,14,12,14,14, 9, + 11,11,12,13,14,11,13,11, 7,10, 9,10,11,12, 9,12, + 10,10,11,12,11,11,13,12,13,13, 9,12, 9,12,13,12, + 10,13,10, +}; + +static const static_codebook _44p8_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p8_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p8_p4_0, + 0 +}; + +static const long _vq_quantlist__44p8_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p8_p4_1[] = { + 7, 9, 9,10,10, 9,10,10,10,11, 9,10,10,11,10, 9, + 10,10,11,11, 9,10,10,11,11, 9,10,10,11,11,10,10, + 10,11,11,10,10,10,11,11,10,11,11,11,11,10,11,11, + 11,11, 9,10,10,11,11,10,10,10,11,11, 9,10,10,11, + 11,10,11,11,11,11,10,11,11,11,11,10,11,11,11,11, + 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,12,10,11,11,11,11,11,11,11,11,11,10,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11, 9,10,10, + 11,11,10,10,11,11,11,10,10,11,11,11,10,11,11,11, + 12,10,11,11,12,12,10,10,11,11,11,10,11,11,11,12, + 11,11,11,12,12,11,11,12,12,12,11,11,12,12,12,10, + 11,11,11,11,11,11,11,12,12,10,11,11,12,12,11,12, + 11,12,12,11,12,11,12,12,11,11,11,11,12,11,11,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,11,11,12,12,11,12,12,12,12,11,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12, 9,10,10,11,11,10, + 11,10,11,11,10,11,10,11,11,10,11,11,12,12,10,11, + 11,12,11,10,11,11,11,11,10,11,11,11,12,11,11,11, + 12,12,11,11,12,12,12,11,11,11,12,12,10,11,10,11, + 11,11,11,11,12,12,10,11,11,12,11,11,12,11,12,12, + 11,12,11,12,12,11,11,11,12,12,11,11,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11, + 11,12,11,11,12,12,12,12,11,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,10,11,11,11,11,11,11,11,12, + 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12, + 11,11,11,12,12,11,11,12,12,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,12, + 12,12,12,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,13,12,13,12,12,12,12,13,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,12,10,11,11,11,11,11,11,11,12,12,11,11, + 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12, + 11,12,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,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,12,12,13,12,13, + 12, 9,10,10,11,11,10,10,11,11,11,10,11,10,11,11, + 10,11,11,12,12,10,11,11,12,12,10,10,11,11,11,10, + 11,11,11,12,10,11,11,12,12,11,11,12,12,12,11,11, + 11,12,12,10,11,10,11,11,11,11,11,12,12,10,11,11, + 12,11,11,12,11,12,12,11,12,11,12,12,11,11,11,11, + 12,11,11,12,12,12,11,12,12,12,12,11,12,12,12,12, + 11,12,12,12,12,11,11,11,12,11,11,12,12,12,12,11, + 12,11,12,12,12,12,12,12,12,12,12,12,12,12,10,10, + 11,11,11,10,11,11,12,12,10,11,11,12,12,11,11,11, + 12,12,11,11,12,12,12,10,11,11,11,12,11,11,12,12, + 12,11,11,12,12,12,11,11,12,12,12,11,12,12,12,12, + 11,11,11,12,12,11,12,12,12,12,11,12,11,12,12,11, + 12,12,12,12,11,12,12,12,12,11,11,12,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,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, 9,10,10,11,11, + 10,11,11,11,12,10,11,11,12,11,11,12,11,12,12,11, + 12,11,12,12,10,11,11,12,11,11,11,11,12,12,11,12, + 11,12,12,11,12,12,12,12,11,12,12,12,12,10,11,11, + 12,12,11,12,11,12,12,11,12,11,12,12,12,12,12,12, + 12,11,12,12,12,12,11,12,11,12,12,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,11,11,11,12,12,11,12,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,13,12,12,12,12,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,13,13,12,12, + 12,13,13,12,12,12,12,12,12,12,12,12,13,12,12,12, + 12,13,12,12,13,12,13,12,13,13,13,13,12,12,12,12, + 12,12,12,12,13,12,12,12,12,13,12,12,13,13,13,13, + 12,13,13,13,13,10,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,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,11,12,12,12,12,12,12,12,12, + 12,12,12,12,13,12,12,12,12,13,13,12,12,12,13,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,12, + 13,13,12,13,12,13,13,13,13,12,12,12,12,12,12,12, + 12,13,12,12,12,12,13,12,12,13,13,13,13,12,13,13, + 13,13, 9,10,10,11,11,10,10,11,11,11,10,11,10,11, + 11,10,11,11,12,12,10,11,11,12,12,10,11,11,11,11, + 10,11,11,12,12,11,11,11,12,12,11,11,12,12,12,11, + 11,12,12,12,10,11,10,11,11,10,11,11,12,12,10,11, + 11,12,11,11,12,11,12,12,11,11,11,12,12,11,11,11, + 11,12,11,11,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,11,11,11,12,11,11,12,12,12,12, + 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12, 9, + 10,10,11,11,10,11,11,11,12,10,11,11,12,11,11,11, + 12,12,12,11,11,12,12,12,10,11,11,12,12,11,11,12, + 12,12,11,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,10,11,11,12,12,11,11,11,12,12,11,11,11,12,12, + 11,12,12,12,12,11,12,12,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,11,11,12,12,12,12,12,12,12,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,10,11,10,11, + 11,10,11,11,12,12,10,11,11,12,12,11,11,11,12,12, + 11,12,11,12,12,11,11,11,12,12,11,11,12,12,12,11, + 11,12,12,12,11,12,12,12,12,11,12,12,12,12,10,11, + 11,12,11,11,12,11,12,12,11,12,11,12,12,11,12,12, + 12,12,11,12,11,12,12,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, + 11,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,11, + 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,11,12,12,12,12,12,12,12,12,13,12,12,12,12, + 12,12,12,12,13,13,12,12,12,13,13,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,12, + 12,12,12,12,12,12,12,12,12,12,12,13,12,13,12,12, + 12,13,13,12,13,13,12,13,12,13,13,13,13,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13, + 13,12,13,12,13,12,11,11,11,12,12,11,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,13,13,12,12,12,13,13,11,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,12,12,12,12,13, + 12,12,12,12,12,12,12,12,12,13,13,12,12,12,12,13, + 12,13,13,13,13,12,13,13,13,13,12,12,12,12,12,12, + 12,12,13,12,12,12,12,13,12,12,13,13,13,13,12,13, + 13,13,12,10,11,11,12,12,11,11,11,12,12,11,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,11,11,11,12, + 12,11,11,12,12,12,11,12,12,12,12,11,12,12,12,12, + 12,12,12,12,12,11,11,11,12,12,11,12,12,12,12,11, + 12,11,12,12,12,12,12,12,12,12,12,12,12,12,11,12, + 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,13,12,12,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,13,12,12,12,12,12,12, + 11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12, + 12,12,12,12,11,12,12,12,12,11,11,12,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12, + 13,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,13,13,12,12,12,13,13,12,12,12,12,12, + 12,12,12,12,13,12,12,12,12,13,12,12,13,12,13,12, + 12,13,13,13,12,12,12,12,12,12,12,12,12,13,12,12, + 12,13,12,12,13,13,13,13,12,13,13,13,13,10,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,11,12,12,12, + 12,12,12,12,12,12,11,11,12,12,12,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,13,12,12,12,13,13,11, + 12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12, + 12,13,13,12,12,12,13,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,13,12,12,12,12,12,13,12,13,12,13, + 13,12,12,12,12,12,12,12,12,13,12,12,12,12,13,12, + 12,13,12,13,13,12,13,12,13,12,11,11,11,12,12,11, + 12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,13,12,13,12,12,13,13,13,11,12,12,12, + 12,12,12,12,12,12,12,12,12,13,12,12,12,12,13,13, + 12,12,12,13,12,12,12,12,12,12,12,12,13,12,13,12, + 12,12,12,13,12,12,13,12,13,12,13,13,12,13,12,12, + 12,12,12,12,13,13,13,12,12,12,12,13,12,12,13,13, + 13,13,12,13,13,13,12,11,11,11,12,12,11,12,12,12, + 12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,13,12,12,13,13,13,11,12,12,12,12,12,12, + 12,12,13,12,12,12,13,12,12,13,12,13,13,12,13,12, + 13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,13,12,13,12,13,13,13,12,12,12,12,12,12, + 12,13,12,13,12,12,12,12,13,12,12,13,13,13,12,12, + 13,12,13,12,10,11,11,12,12,11,11,11,12,12,11,11, + 11,12,12,11,12,12,12,12,11,12,12,12,12,11,11,11, + 12,12,11,11,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,11,11,11,12,12,11,12,12,12,12, + 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,12,12,12,12,12,11,12,12,12,12,12,12,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,10,11,11,12,12,11,11,12,12,12,11,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,11,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12, + 12,13,13,11,11,11,12,12,12,12,12,12,12,11,12,12, + 12,12,12,12,12,13,13,12,12,12,13,13,12,12,12,12, + 12,12,12,12,12,13,12,12,12,12,13,12,12,13,12,13, + 12,12,13,13,13,12,12,12,12,12,12,12,12,12,13,12, + 12,12,12,12,12,12,13,13,13,12,12,12,13,12,11,11, + 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12, + 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,13,13,12,12,12,13,13, + 11,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12, + 12,12,13,13,12,12,12,13,12,12,12,12,12,12,12,12, + 12,12,13,12,12,12,13,13,12,13,13,13,13,12,13,13, + 13,13,12,12,12,12,12,12,12,12,13,12,12,12,12,13, + 12,12,13,12,13,13,12,13,12,13,12,11,11,11,12,12, + 11,12,12,12,12,11,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,11,12,12,12,12,12,12,12,12,13,12,12, + 12,13,13,12,12,13,12,13,12,12,13,13,13,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,12,12,12,13,12,12,12,12,12,12,12,12,12,12,13, + 12,12,12,13,13,12,12,13,12,13,12,13,13,13,13,12, + 12,12,12,12,12,12,13,12,13,12,12,12,12,12,12,13, + 13,12,12,12,13,12,12,12,11,11,11,12,12,11,12,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,12,12,12,12,12,12,12,12,13,12,12,12,12,13, + 12,12,13,13,13,12,12,12,13,13,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,12,13,13,12,13, + 12,13,12,12,12,12,12,12,12,12,12,12,13,12,13,12, + 13,13,12,13,13,12,13,12,13,13,13,13,12,12,12,12, + 12,12,12,12,13,12,12,13,12,13,12,12,13,12,13,12, + 12,13,12,13,12, +}; + +static const static_codebook _44p8_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p8_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p8_p4_1, + 0 +}; + +static const long _vq_quantlist__44p8_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p8_p5_0[] = { + 2, 6, 6, 9, 9, 5, 7, 8,10,11, 5, 8, 7,11,10, 8, + 10,11,12,13, 8,11,10,13,12, 6, 7, 8,10,11, 7, 8, + 10,10,12, 8, 9, 9,12,12,10,10,12,12,14,10,12,12, + 14,13, 6, 8, 7,11,10, 8, 9, 9,12,12, 7,10, 8,12, + 11,10,12,12,13,14,10,12,10,14,12, 9,10,11,11,13, + 10,10,11,11,13,11,12,12,13,14,12,12,13,11,15,13, + 14,14,15,14, 9,11,10,13,11,11,12,12,13,13,10,11, + 10,13,11,13,14,14,15,15,12,13,12,15,11, 6, 8, 9, + 11,12, 8, 9,11,12,13, 8,10,10,13,13,11,12,13,14, + 15,11,12,13,14,14, 9, 9,10,12,13,10,10,12,12,14, + 10,11,11,13,14,12,12,14,14,15,13,13,14,15,15, 9, + 10,10,13,13,10,11,11,13,14,10,11,10,14,13,13,13, + 14,15,15,12,14,13,15,14,12,12,13,13,14,12,13,14, + 13,15,13,14,14,15,15,14,14,15,14,16,15,15,15,16, + 16,12,13,13,14,14,13,14,14,15,15,12,14,13,15,14, + 14,15,15,16,16,14,15,14,16,14, 6, 9, 8,12,11, 8, + 10,10,13,13, 8,11, 9,13,12,11,12,12,14,14,11,13, + 12,15,14, 9,10,10,13,13,10,10,11,13,14,10,12,11, + 14,13,12,13,14,14,15,13,13,13,15,14, 9,10, 9,13, + 12,10,11,11,14,13,10,12,10,14,12,13,14,13,15,15, + 12,14,12,15,14,12,13,13,14,14,13,13,13,14,15,13, + 14,14,15,15,14,14,15,14,16,14,15,15,16,16,12,13, + 12,14,13,13,14,14,15,15,12,14,13,15,13,15,15,15, + 16,16,14,15,14,16,14,11,12,12,13,14,12,13,14,14, + 16,12,13,13,15,15,14,14,16,15,17,14,15,15,16,16, + 12,13,14,14,15,13,13,15,15,16,14,14,14,15,16,15, + 15,16,16,17,15,15,16,16,17,13,13,13,15,15,14,14, + 15,15,16,13,14,14,15,16,15,15,16,16,17,15,16,15, + 17,16,14,15,15,16,16,15,15,16,16,17,15,16,16,17, + 17,16,16,17,16,18,16,17,17,17,17,15,15,15,16,16, + 15,16,16,17,17,15,16,16,17,16,16,17,17,18,18,16, + 17,16,17,16,11,12,12,15,13,13,13,13,15,15,12,14, + 13,16,14,14,15,15,16,16,14,15,14,17,15,13,13,13, + 15,14,13,14,14,16,15,14,14,14,16,15,15,15,16,16, + 17,15,16,15,17,16,12,14,13,15,14,14,14,14,16,15, + 13,14,13,16,15,15,16,16,17,16,15,16,15,17,16,15, + 15,15,16,16,15,15,16,16,17,15,16,16,17,17,16,16, + 17,17,17,17,17,17,18,17,14,15,15,16,16,15,16,16, + 17,16,15,16,15,17,16,17,17,17,18,17,16,17,16,18, + 16, 6, 9, 9,12,12, 8,10,10,12,13, 8,10,10,13,12, + 10,12,12,14,15,11,13,12,15,14, 8, 9,10,12,13, 9, + 10,11,13,14,10,11,11,14,13,12,12,13,14,15,12,13, + 13,15,15, 8,10,10,13,13,10,11,11,13,14,10,12,10, + 14,13,12,13,13,15,15,12,14,13,15,14,11,12,12,13, + 14,12,12,13,13,15,12,13,13,15,15,14,13,15,14,16, + 14,15,15,16,16,12,13,13,14,14,13,13,14,15,14,12, + 14,13,15,14,14,15,15,16,15,14,15,14,16,14, 7, 9, + 10,12,12, 9,10,11,13,14, 9,11,10,13,13,11,12,13, + 14,15,12,13,13,15,14, 9,10,11,12,13,10,10,12,13, + 14,11,11,12,14,14,12,12,14,14,15,13,13,14,15,15, + 9,11,11,13,13,11,12,12,14,14,10,12,10,14,13,13, + 14,14,15,15,13,14,13,16,14,12,12,13,14,15,13,13, + 14,14,16,13,14,14,15,15,14,14,15,14,17,14,15,15, + 16,16,12,13,13,15,14,13,14,14,15,15,13,14,13,16, + 14,15,15,15,16,16,14,15,14,16,14, 7,10, 9,13,12, + 10,11,12,12,14,10,12,11,14,12,12,13,13,14,15,12, + 14,13,15,14, 9,11,10,13,13,10,11,12,13,14,12,13, + 12,15,13,13,13,14,13,15,13,14,14,16,15,10,11,11, + 13,13,12,12,13,14,14,11,12,11,14,13,14,14,14,15, + 16,13,14,13,16,13,12,13,13,14,14,12,13,13,14,15, + 14,14,14,15,15,14,13,15,13,16,15,15,15,17,16,13, + 13,13,14,14,14,14,14,15,15,12,13,13,15,14,15,16, + 16,16,16,14,15,14,16,13,11,12,13,14,15,12,13,14, + 15,16,13,14,14,15,15,14,14,15,15,17,14,15,15,16, + 16,13,13,14,14,15,13,13,15,14,16,14,14,15,15,16, + 15,14,16,15,17,15,16,16,16,17,13,14,14,15,15,14, + 14,15,16,16,13,15,14,16,16,15,16,16,17,17,15,16, + 15,17,16,14,15,15,15,17,15,15,16,15,17,15,16,16, + 16,17,16,16,17,16,18,17,17,17,17,18,15,15,15,17, + 16,15,16,16,17,17,15,16,16,17,16,16,17,17,18,18, + 16,17,16,18,17,11,13,12,15,14,13,13,14,15,15,13, + 14,13,16,14,15,15,15,16,16,15,16,15,17,16,13,14, + 13,15,14,13,13,14,15,15,14,15,14,16,15,15,15,16, + 16,16,15,16,15,18,16,13,14,14,15,15,14,15,15,15, + 16,13,15,13,16,15,15,16,16,17,17,15,16,15,17,16, + 15,15,15,16,16,15,15,15,16,17,16,16,16,17,16,16, + 16,17,16,17,17,17,17,18,17,15,15,15,16,16,16,16, + 16,17,17,15,16,15,17,16,17,17,17,18,18,16,17,16, + 17,15, 6, 9, 9,12,12, 8,10,10,12,13, 8,10,10,13, + 12,11,12,13,14,15,10,12,12,14,14, 9,10,10,13,13, + 10,10,12,13,14,10,11,11,14,13,12,13,14,14,15,12, + 13,13,15,15, 8,10, 9,13,12,10,11,11,13,14, 9,11, + 10,14,13,12,13,13,15,15,12,13,12,15,14,12,13,13, + 14,14,12,13,13,14,15,13,14,14,14,15,14,14,15,14, + 16,14,15,15,16,16,11,12,12,14,13,13,13,13,15,15, + 12,13,12,15,13,14,15,15,16,16,14,15,14,16,14, 7, + 9,10,12,13,10,10,12,12,14,10,12,11,14,13,12,13, + 14,14,15,12,13,13,15,14,10,11,11,13,13,11,11,12, + 13,14,12,13,12,14,14,13,13,14,13,16,14,14,14,15, + 15, 9,10,11,13,14,12,12,13,13,15,10,12,10,14,13, + 13,14,14,15,16,13,14,13,15,13,13,14,13,14,15,12, + 13,13,14,15,14,14,14,15,15,14,13,15,13,16,15,16, + 16,16,16,12,13,13,14,14,14,14,14,15,15,12,13,13, + 15,14,15,15,16,16,16,14,15,13,16,13, 7,10, 9,12, + 12, 9,10,11,13,13, 9,11,10,14,13,12,13,13,14,15, + 11,13,12,15,14, 9,11,11,13,13,10,10,12,13,14,11, + 12,12,14,14,13,13,14,14,16,13,14,14,16,15, 9,11, + 10,13,12,11,12,11,14,14,10,12,10,14,13,13,14,13, + 15,15,12,14,12,16,14,12,13,13,14,15,13,13,14,14, + 16,13,14,14,15,15,14,14,15,14,16,15,15,15,16,16, + 12,13,12,15,14,13,14,14,15,15,12,14,13,16,14,14, + 15,15,16,16,14,15,14,17,14,11,12,13,14,15,13,13, + 14,14,16,13,14,13,15,15,15,15,16,16,17,15,15,15, + 16,16,13,14,13,15,15,13,13,15,15,16,14,15,15,16, + 16,15,15,16,15,17,16,16,16,17,17,13,13,14,14,15, + 14,14,15,15,16,13,14,13,15,15,15,16,16,16,17,15, + 16,15,16,16,15,15,15,16,16,15,15,16,16,17,16,16, + 16,17,17,16,16,17,16,18,17,17,17,18,18,15,15,15, + 16,16,16,16,16,17,17,15,15,15,16,16,17,17,17,17, + 18,16,16,16,17,15,11,13,12,15,14,13,13,14,15,15, + 12,14,13,16,14,14,15,15,16,16,14,15,14,16,15,13, + 14,14,15,15,13,14,14,16,16,14,15,14,16,16,15,15, + 16,17,17,15,16,16,17,17,13,14,13,15,14,14,14,14, + 16,15,13,15,13,16,14,15,16,15,17,16,15,16,14,17, + 15,14,16,15,16,17,15,16,16,16,17,15,16,16,17,17, + 16,16,17,17,18,16,17,17,18,17,14,15,15,17,15,15, + 16,16,17,16,15,16,15,17,15,16,17,17,18,17,16,17, + 16,18,15,10,12,12,14,14,12,13,13,15,15,12,13,13, + 15,15,13,14,14,15,16,14,15,14,16,16,12,13,13,15, + 15,12,13,14,15,15,13,14,14,15,15,14,14,15,16,17, + 14,15,15,17,16,12,13,13,15,15,13,14,14,15,16,13, + 14,14,16,15,14,15,15,16,17,14,15,15,17,16,13,14, + 14,15,16,14,14,15,15,16,14,15,15,16,16,15,15,16, + 16,17,15,16,16,17,17,14,15,15,16,16,15,15,15,16, + 16,15,15,15,16,16,16,17,16,17,17,16,16,16,18,16, + 11,12,12,14,14,12,13,14,15,15,12,13,13,15,15,13, + 14,15,16,16,14,15,15,16,16,12,13,13,15,15,13,13, + 14,15,16,13,14,14,15,16,14,14,15,16,17,15,15,15, + 16,17,12,13,13,15,15,13,14,14,15,16,13,14,14,16, + 15,15,15,15,16,17,15,16,15,17,16,14,14,15,15,16, + 14,14,15,15,17,15,15,16,16,17,15,15,16,15,18,16, + 16,16,17,17,14,15,15,16,16,15,16,16,17,17,15,15, + 15,17,16,16,17,16,17,17,16,16,16,18,16,11,12,12, + 14,14,13,13,14,15,15,13,14,13,15,15,14,15,15,16, + 16,14,15,15,16,16,12,13,13,15,15,13,13,14,15,15, + 14,14,14,16,15,15,15,15,15,16,15,16,15,17,16,12, + 13,13,15,15,14,14,15,15,16,13,14,13,16,15,15,15, + 16,16,17,15,16,15,17,15,14,15,14,16,16,14,15,15, + 16,16,15,16,15,17,16,15,15,16,15,17,16,17,16,17, + 17,14,15,15,16,16,15,16,16,16,17,14,15,15,16,16, + 16,17,17,17,18,16,16,16,17,16,12,13,13,15,15,13, + 13,14,15,16,13,14,14,16,15,14,15,15,16,17,14,15, + 15,17,16,13,14,14,15,16,14,14,15,15,17,14,15,15, + 16,16,15,14,16,15,17,15,16,16,17,17,13,14,14,16, + 16,14,15,15,16,16,14,15,14,16,16,15,16,16,17,17, + 15,16,15,17,16,15,15,16,15,17,15,15,16,15,17,15, + 16,16,16,17,16,15,17,15,18,17,17,17,17,17,15,15, + 15,17,17,16,16,16,17,17,15,16,15,17,17,16,17,17, + 18,18,16,17,15,18,15,11,12,12,15,15,13,13,15,14, + 16,13,14,13,16,14,15,15,16,16,17,15,16,15,17,15, + 12,14,13,16,14,13,13,14,14,16,14,15,14,16,15,15, + 15,16,15,17,16,16,16,17,16,12,13,14,15,16,15,15, + 15,15,16,13,15,13,16,14,16,16,16,17,17,15,16,15, + 17,15,15,16,15,16,15,14,14,15,16,16,16,16,16,17, + 16,15,15,16,15,17,17,17,17,18,17,15,15,15,16,16, + 16,16,16,16,17,14,15,15,17,16,17,17,17,17,18,15, + 16,15,18,14,10,12,12,14,14,12,13,13,15,15,12,13, + 13,15,15,14,14,15,15,16,13,15,14,16,16,12,13,13, + 15,15,13,14,14,15,16,13,14,14,15,15,14,15,15,16, + 17,14,15,15,17,16,12,13,13,15,15,13,14,14,15,15, + 12,14,13,15,15,14,15,15,16,17,14,15,14,17,15,14, + 15,15,16,16,14,15,15,16,17,15,15,15,17,16,16,16, + 16,16,17,16,16,16,17,17,13,14,14,16,15,14,15,15, + 16,16,14,15,14,16,16,15,16,16,17,17,15,16,15,17, + 16,11,12,12,14,15,13,13,14,14,15,13,14,13,15,15, + 14,15,15,16,16,14,15,15,16,16,12,14,13,15,15,13, + 13,14,15,16,14,15,14,16,15,15,15,16,15,17,15,16, + 16,17,16,12,13,13,15,15,14,14,15,15,16,13,14,13, + 16,15,15,15,16,16,17,15,15,15,16,16,14,15,15,16, + 16,14,15,15,16,16,15,16,16,17,17,16,16,16,16,17, + 16,17,17,18,17,14,14,15,15,16,15,15,16,16,17,14, + 15,15,16,16,16,16,16,17,17,15,16,15,17,15,11,12, + 12,14,14,12,13,14,15,15,12,13,13,15,15,14,15,15, + 16,16,13,15,14,16,16,12,13,13,15,15,13,14,14,15, + 16,13,14,14,16,16,15,15,15,16,17,15,15,15,17,16, + 12,13,13,15,15,13,14,14,16,15,13,14,13,16,15,15, + 16,15,17,17,14,15,14,17,16,14,15,15,16,16,15,15, + 16,16,17,15,16,16,17,17,16,16,16,16,18,16,17,16, + 18,17,14,15,14,16,15,15,15,15,17,16,14,15,14,17, + 15,16,17,16,17,17,15,16,15,17,15,11,12,12,15,15, + 13,13,15,14,16,13,15,13,16,14,15,15,16,15,17,15, + 16,15,17,16,12,14,13,15,15,13,13,15,15,16,15,15, + 15,16,15,15,15,16,15,17,16,16,16,17,16,12,13,14, + 15,16,14,14,15,15,16,13,14,13,16,14,16,16,16,16, + 17,15,16,15,17,15,15,16,15,16,16,14,15,15,16,16, + 16,16,16,17,16,15,15,16,15,17,17,17,17,18,17,15, + 15,15,15,16,16,16,16,16,17,14,15,14,16,15,17,17, + 17,17,18,15,16,15,17,15,12,13,13,15,15,13,14,14, + 15,16,13,14,14,16,15,14,15,15,16,17,14,15,15,17, + 16,13,14,14,16,15,13,14,15,16,16,14,15,15,16,16, + 15,15,16,16,17,15,16,16,17,17,13,14,13,16,15,14, + 15,15,16,16,13,15,14,16,15,15,16,16,17,17,15,16, + 14,17,15,15,15,16,17,17,15,15,16,16,17,16,16,16, + 17,17,16,15,17,16,18,17,17,17,18,18,15,15,15,17, + 14,16,16,16,17,16,15,16,15,17,15,16,17,17,18,17, + 16,17,15,18,15, +}; + +static const static_codebook _44p8_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p8_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p8_p5_0, + 0 +}; + +static const long _vq_quantlist__44p8_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p8_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p8_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p8_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p8_p5_1, + 0 +}; + +static const long _vq_quantlist__44p8_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p8_p6_0[] = { + 2, 6, 6, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 7, 9, 7, + 9, 9, 6, 7, 7, 8, 9, 9, 7, 9, 7, 6, 8, 8, 8, 9, + 10, 8, 9, 9, 8, 9,10, 9, 9,10,10,10,10, 8, 9, 9, + 10,10,11, 9,10,10, 6, 8, 8, 8, 9, 9, 8,10, 9, 8, + 9, 9, 9,10,10,10,11,10, 8,10, 9,10,11,10, 9,11, + 9, 6, 8, 8, 7, 9, 9, 7, 9, 9, 7, 9, 9, 8, 9,10, + 9,10,10, 8, 9, 9, 9,10,10, 9,10, 9, 7, 9, 9, 9, + 9,10, 9,10,10, 9, 9,10,10, 9,11,10,11,11, 9,10, + 10,10,11,11,10,11,10, 6, 9, 8, 9, 9,10, 9,10, 9, + 8,10,10, 9, 9,10,10,11,11, 9,10,10,10,11,11, 9, + 11, 9, 6, 8, 8, 7, 9, 9, 7, 9, 9, 8, 9, 9, 9, 9, + 10, 9,10,10, 7, 9, 9, 9,10,10, 8,10, 9, 6, 8, 9, + 9, 9,10, 9,10, 9, 9,10,10, 9, 9,11,10,11,11, 8, + 9,10,10,11,11, 9,10, 9, 7, 9, 9, 9,10,10, 9,10, + 9, 9,10,10,10,10,11,10,11,11, 9,10, 9,10,11,11, + 10,11, 9, +}; + +static const static_codebook _44p8_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p8_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p8_p6_0, + 0 +}; + +static const long _vq_quantlist__44p8_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p8_p6_1[] = { + 4, 7, 7, 7, 7, 8, 7, 8, 7, 7, 7, 8, 7, 8, 8, 8, + 8, 8, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, + 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, + 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 8, 8, 9, 8, 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, 8, + 8, 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 8, 9, 8, 8, 8, 8, 8, 9, 9, 8, + 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 8, 9, 9, 8, 8, 8, 8, 9, 8, 8, 9, 8, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, + 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, + 8, 9, 8, +}; + +static const static_codebook _44p8_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p8_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p8_p6_1, + 0 +}; + +static const long _vq_quantlist__44p8_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p8_p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 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, +}; + +static const static_codebook _44p8_p7_0 = { + 5, 243, + (char *)_vq_lengthlist__44p8_p7_0, + 1, -512202240, 1635281408, 2, 0, + (long *)_vq_quantlist__44p8_p7_0, + 0 +}; + +static const long _vq_quantlist__44p8_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p8_p7_1[] = { + 1, 7, 7,12,12, 5,11,12,12,12, 5,12,11,12,12,12, + 12,12,12,12,12,13,13,13,13, 7,11,11,13,13,13,12, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13, 7,13,10,13,13,13,13,13,13,13,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, 7,13,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,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, + 13,13,13,13,13,13,13,13,13,13, 8,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,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,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,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,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,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,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,13,13,13, + 13, 8,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,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,13,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,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,10,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,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,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,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,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,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, 8,13,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,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,11, + 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, + 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,11,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13, +}; + +static const static_codebook _44p8_p7_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p8_p7_1, + 1, -514619392, 1630767104, 3, 0, + (long *)_vq_quantlist__44p8_p7_1, + 0 +}; + +static const long _vq_quantlist__44p8_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p8_p7_2[] = { + 1, 3, 2, 4, 5, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _44p8_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p8_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p8_p7_2, + 0 +}; + +static const long _vq_quantlist__44p8_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p8_p7_3[] = { + 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, +}; + +static const static_codebook _44p8_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p8_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p8_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p8_short[] = { + 3, 9,15,17,20,21,22,23, 5, 5, 7, 9,11,13,17,20, + 9, 5, 5, 6, 8,10,15,18,11, 7, 5, 4, 6, 9,13,17, + 14, 9, 7, 5, 6, 7,10,14,17,10, 8, 6, 6, 4, 5, 8, + 20,14,13,10, 8, 4, 3, 4,23,17,16,14,12, 6, 4, 4, +}; + +static const static_codebook _huff_book__44p8_short = { + 2, 64, + (char *)_huff_lengthlist__44p8_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p9_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44p9_l0_0[] = { + 2, 5, 5, 7, 6, 8, 8, 9, 9,10,10,11,11, 4, 5, 5, + 6, 7, 8, 8, 9, 9,10,10,11,10, 4, 5, 5, 7, 6, 8, + 8, 9, 9,10,10,10,10, 6, 6, 7, 6, 7, 8, 8, 9, 9, + 10, 9,11, 9, 6, 6, 6, 7, 6, 8, 8, 9, 9, 9,10, 9, + 11, 7, 7, 8, 8, 8, 8, 9, 9, 9,10, 9,11, 9, 7, 8, + 8, 8, 8, 9, 8, 9, 9, 9,10, 9,11, 8, 9, 9, 9, 9, + 9, 9,10,10,11,10,12,10, 8, 9, 9, 9, 9, 9, 9,10, + 9,10,11,11,12, 9,10,10,10,10,10,10,10,11,11,11, + 11,12, 9,10,10,10,10,11,10,11,10,11,11,12,11,11, + 11,11,11,11,11,11,11,12,11,12,11,12,11,11,11,11, + 11,11,11,12,11,12,11,12,11, +}; + +static const static_codebook _44p9_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44p9_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44p9_l0_0, + 0 +}; + +static const long _vq_quantlist__44p9_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p9_l0_1[] = { + 4, 4, 4, 5, 5, 4, 4, 5, 5, 5, 4, 5, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44p9_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44p9_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p9_l0_1, + 0 +}; + +static const long _vq_quantlist__44p9_l1_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p9_l1_0[] = { + 1, 2, 3, 5, 9, 9, 4, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44p9_l1_0 = { + 2, 25, + (char *)_vq_lengthlist__44p9_l1_0, + 1, -514619392, 1630767104, 3, 0, + (long *)_vq_quantlist__44p9_l1_0, + 0 +}; + +static const char _huff_lengthlist__44p9_lfe[] = { + 1, 1, +}; + +static const static_codebook _huff_book__44p9_lfe = { + 1, 2, + (char *)_huff_lengthlist__44p9_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44p9_long[] = { + 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _huff_book__44p9_long = { + 1, 8, + (char *)_huff_lengthlist__44p9_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44p9_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p9_p1_0[] = { + 1, 5, 5, 4, 8, 8, 4, 8, 8, 5, 7, 8, 8, 9,10, 8, + 10,10, 5, 8, 7, 8,10,10, 8,10, 9, 7, 9, 9, 9,11, + 11, 9,11,11, 9,11,11,11,12,13,11,13,13, 9,11,11, + 11,13,13,11,13,13, 7, 9, 9, 9,11,11, 9,11,11, 9, + 11,11,11,13,13,11,13,13, 9,11,11,11,13,13,11,13, + 12, 5, 9, 9, 9,11,11, 9,11,11, 9,11,11,11,12,13, + 11,13,13, 9,11,11,11,13,13,11,13,13, 9,11,12,11, + 13,13,12,13,13,11,12,13,13,14,15,13,14,14,12,13, + 13,13,15,15,13,15,14, 8,10,10,11,13,13,12,14,13, + 11,12,12,13,14,15,13,15,15,11,12,12,13,15,15,13, + 15,14, 5, 9, 9, 9,11,11, 9,11,11, 9,11,11,11,13, + 13,11,13,13, 9,11,10,11,13,13,11,13,12, 8,10,10, + 11,13,13,12,13,13,11,12,12,13,14,15,14,15,15,10, + 12,12,13,14,15,13,15,14, 9,12,11,12,13,13,11,13, + 13,12,13,13,13,15,15,13,14,15,11,13,12,13,15,14, + 13,15,14, +}; + +static const static_codebook _44p9_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44p9_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p9_p1_0, + 0 +}; + +static const long _vq_quantlist__44p9_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p9_p2_0[] = { + 4, 6, 6, 8, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 6, + 8, 8,11,11, 6, 8, 8,11,11, 6, 7, 7, 9, 9, 7, 8, + 9,10,11, 7, 9, 9,11,10, 8, 9,10,12,12, 8,10,10, + 12,12, 6, 7, 7, 9, 9, 7, 9, 9,10,10, 7, 9, 8,11, + 10, 8,10,10,12,12, 8,10, 9,12,12, 8, 9, 9,11,11, + 9,10,10,12,12, 9,11,11,12,13,11,12,12,13,14,11, + 12,12,14,14, 8, 9, 9,11,11, 9,11,10,13,12, 9,10, + 10,13,12,11,12,12,14,14,11,12,12,14,13, 7, 8, 9, + 10,10, 8,10,10,11,11, 8,10,10,11,11,10,11,11,13, + 13,10,11,11,13,13, 8, 9,10,10,11,10,11,11,12,13, + 10,11,11,12,12,11,11,12,13,14,11,12,12,14,14, 8, + 10,10,11,11,10,11,11,12,13,10,11,11,12,12,11,12, + 12,14,14,11,12,12,14,14,10,11,11,12,13,11,12,12, + 13,14,12,13,13,14,14,13,13,14,14,16,13,14,14,15, + 16,10,11,11,13,13,12,12,12,14,14,11,12,12,14,14, + 13,14,14,15,16,13,14,14,16,15, 7, 8, 8,10,10, 8, + 10,10,11,11, 8,10,10,12,11,10,11,11,13,13,10,11, + 11,13,13, 8,10,10,11,11,10,11,11,12,12,10,11,11, + 12,12,11,12,12,14,14,11,12,12,14,14, 8,10, 9,11, + 10,10,11,11,13,12,10,11,10,13,12,11,12,12,14,14, + 11,12,11,14,13,10,11,11,13,13,11,12,12,14,14,12, + 12,12,14,14,13,14,14,15,16,13,14,14,15,15,10,11, + 11,13,12,12,12,12,14,14,11,12,12,14,13,13,14,14, + 16,15,13,14,13,16,14,10,11,11,13,13,12,12,13,14, + 15,12,13,13,14,15,13,14,15,15,16,13,14,14,16,16, + 11,12,13,14,14,13,13,14,15,16,13,14,14,15,16,14, + 15,15,16,17,14,15,16,17,17,11,12,12,14,14,13,14, + 14,15,16,13,14,14,15,15,14,15,15,16,18,14,15,15, + 17,16,13,14,15,15,16,15,15,16,16,18,15,15,15,17, + 17,16,16,17,17,18,16,16,16,18,18,14,14,14,16,16, + 15,15,15,16,17,15,15,15,16,17,16,17,17,18,18,16, + 16,17,18,17,10,11,11,14,13,12,13,13,15,14,11,13, + 13,15,14,13,15,15,16,16,13,14,14,16,16,11,12,12, + 14,14,13,13,13,15,15,13,14,13,15,15,15,15,15,17, + 16,14,15,15,17,16,11,13,12,14,14,13,14,13,15,15, + 13,14,13,15,15,14,15,15,17,17,14,15,15,17,16,14, + 14,14,16,16,14,15,15,17,17,15,15,16,17,16,17,16, + 17,18,18,16,17,17,18,18,13,14,14,16,15,15,15,15, + 17,17,14,16,15,16,16,17,17,17,18,18,16,17,16,20, + 19, 6, 8, 8,10,10, 8,10,10,11,11, 8,10,10,12,11, + 10,11,11,13,13,10,11,11,13,13, 8, 9,10,11,11,10, + 11,11,12,12,10,11,11,13,12,11,12,12,14,14,11,12, + 12,14,14, 9,10,10,11,11,10,11,11,12,12,10,11,11, + 13,12,11,12,12,14,14,11,12,12,14,14,10,10,11,12, + 13,11,12,12,14,14,11,12,12,14,14,13,14,14,15,16, + 13,14,14,15,16,10,11,11,13,13,12,12,12,14,14,12, + 13,12,14,14,13,14,14,16,16,13,14,14,15,15, 9,10, + 10,11,12,10,11,11,12,13,10,11,11,13,12,11,12,12, + 14,14,11,12,12,14,14,10,10,11,12,13,11,12,12,13, + 14,11,12,12,13,14,12,13,14,14,15,12,13,13,15,15, + 10,11,11,13,13,11,12,12,13,14,11,12,12,14,13,12, + 13,13,15,15,12,13,13,15,15,12,11,13,12,14,13,13, + 14,14,15,13,13,14,14,15,14,15,15,16,17,14,15,15, + 16,17,12,13,12,14,14,13,14,14,15,15,13,14,14,15, + 15,14,15,15,16,17,14,15,15,16,17, 8, 9, 9,11,11, + 10,11,11,12,13,10,11,11,13,12,12,13,13,14,15,11, + 13,12,15,14, 9,11,10,12,12,11,12,12,13,14,11,12, + 12,14,13,13,13,14,15,15,13,14,13,15,15, 9,11,11, + 12,12,11,12,12,14,14,11,12,12,14,13,13,14,14,15, + 16,13,14,13,15,14,11,12,12,14,13,12,13,13,14,15, + 13,14,14,16,15,15,15,15,15,16,15,16,15,17,17,11, + 12,12,14,14,13,14,14,15,15,12,13,13,15,14,15,15, + 15,17,17,14,15,15,17,15,11,12,12,14,14,12,13,13, + 15,15,12,13,13,15,15,14,15,15,17,17,14,15,15,16, + 16,12,13,13,14,15,13,14,14,16,16,14,14,14,15,16, + 15,16,16,17,17,15,16,16,17,17,12,13,13,15,15,14, + 14,14,16,16,14,14,15,16,16,15,16,16,17,17,15,16, + 16,17,17,14,15,15,15,16,15,15,16,16,18,15,16,16, + 17,17,17,17,17,18,18,16,17,17,19,18,14,15,15,16, + 17,15,16,16,17,17,15,16,16,18,17,16,17,17,19,18, + 17,17,17,19,18,10,12,12,14,14,13,13,14,15,15,12, + 14,13,16,15,15,15,15,17,17,14,15,15,17,16,12,13, + 13,15,14,13,14,14,16,16,14,14,15,17,16,15,16,16, + 17,17,15,16,16,18,17,12,13,13,15,14,14,15,15,16, + 16,13,15,14,16,15,16,17,16,19,17,15,16,16,17,17, + 14,15,15,17,15,15,16,15,17,17,16,17,16,18,17,17, + 17,18,18,18,17,17,18,19,18,14,15,15,16,16,15,16, + 16,17,18,15,16,16,18,16,17,18,18,19,19,17,18,17, + 18,19, 6, 8, 8,10,10, 8,10,10,11,11, 8,10,10,12, + 11,10,11,11,13,13, 9,11,11,13,13, 9,10,10,11,11, + 10,11,11,12,12,10,11,11,12,12,11,12,12,14,14,11, + 12,12,14,14, 8,10, 9,11,11,10,11,11,12,12,10,11, + 11,12,12,11,12,12,14,14,11,12,12,14,14,10,11,11, + 13,13,11,12,13,14,14,12,12,12,14,14,13,14,14,15, + 16,13,14,14,16,16,10,11,10,13,12,11,12,12,14,14, + 11,12,12,14,14,13,14,14,15,16,13,14,14,16,15, 8, + 9, 9,11,11,10,11,11,12,13,10,11,11,13,12,12,13, + 13,14,15,12,13,13,15,14,10,11,11,12,12,11,11,12, + 13,14,11,12,12,14,14,13,13,14,15,16,13,14,14,15, + 15, 9,10,11,12,12,11,12,12,13,14,11,12,12,14,13, + 13,14,14,15,16,12,14,13,15,15,11,12,12,14,14,12, + 13,13,14,15,13,14,14,16,15,14,15,15,15,17,15,15, + 16,16,17,11,12,12,13,14,13,14,14,15,15,12,13,13, + 15,14,15,16,15,16,17,14,16,15,17,15, 9,10,10,12, + 11,10,11,11,13,13,10,11,11,13,12,11,12,12,14,14, + 11,12,12,14,14,10,11,11,12,13,11,12,12,13,14,11, + 12,12,14,14,12,13,13,15,15,12,13,13,15,15,10,11, + 10,13,12,11,12,12,13,13,11,12,12,14,13,12,13,13, + 15,15,12,13,13,15,14,12,13,12,14,14,13,14,14,15, + 15,13,14,14,15,15,14,15,15,16,16,14,15,15,16,16, + 11,13,11,14,12,13,13,13,15,14,12,14,13,15,14,15, + 15,15,17,16,14,15,14,17,15,10,12,12,14,14,13,13, + 14,15,16,12,14,13,15,15,14,15,16,17,17,14,15,16, + 17,17,12,13,13,14,15,13,14,14,16,16,14,14,15,16, + 16,16,16,16,17,17,16,16,16,18,18,12,13,13,14,15, + 14,14,15,16,16,13,14,14,16,15,16,16,16,17,18,15, + 16,16,17,17,14,15,15,16,16,15,15,16,17,17,15,16, + 16,17,18,17,18,18,18,19,17,18,18,19,19,14,15,15, + 16,16,15,16,16,17,17,15,16,16,17,17,17,17,18,20, + 18,17,18,17,18,18,11,12,12,14,14,12,13,14,15,15, + 12,13,13,15,15,14,15,15,16,17,14,15,15,16,17,12, + 13,13,15,15,14,14,14,16,16,14,14,14,16,16,15,16, + 16,17,17,15,16,16,17,17,12,13,13,15,14,13,14,14, + 16,15,14,15,14,16,15,15,16,16,17,17,15,16,16,17, + 16,14,15,15,16,16,15,16,16,17,17,16,16,16,17,17, + 17,17,17,19,18,17,17,17,18,19,14,15,14,17,15,15, + 16,16,17,17,15,16,15,17,17,16,17,17,18,18,16,17, + 17,18,17, 6,11,11,13,13,11,12,12,14,14,11,12,12, + 14,14,13,14,14,16,16,13,14,14,16,16,11,12,12,14, + 14,12,13,13,15,15,12,13,13,15,15,14,15,15,16,17, + 14,15,15,17,18,11,12,12,14,14,12,13,13,15,15,12, + 13,13,15,15,14,15,15,17,17,14,15,15,16,16,13,14, + 14,15,16,14,15,15,16,17,14,15,15,17,16,15,16,17, + 18,17,16,16,16,18,17,14,14,15,16,16,14,15,15,18, + 16,14,15,15,17,16,16,17,17,18,18,16,17,16,18,17, + 11,12,12,14,14,12,13,13,15,15,12,13,13,15,15,14, + 15,15,17,17,14,15,15,16,16,12,13,13,15,15,13,14, + 14,15,16,13,14,14,16,16,15,16,16,17,17,15,15,16, + 17,17,12,13,13,15,15,14,14,14,16,16,13,14,14,16, + 16,15,16,16,17,17,15,16,16,17,17,14,14,15,15,16, + 15,15,16,16,17,15,15,16,16,17,16,17,17,17,18,16, + 17,17,18,18,14,15,15,16,16,15,16,16,17,17,15,16, + 16,17,17,17,17,17,18,19,17,17,17,18,18,10,12,12, + 14,14,12,13,14,15,16,13,14,13,15,15,14,15,15,17, + 17,14,15,16,17,17,12,13,13,15,15,13,14,14,15,15, + 14,15,14,16,16,15,16,16,17,18,15,17,16,18,17,12, + 13,13,15,15,14,14,14,16,16,13,14,14,16,15,15,16, + 16,17,18,15,16,16,17,17,14,14,14,16,16,15,15,16, + 17,17,15,16,16,17,17,17,17,17,18,20,17,17,17,19, + 19,14,15,15,16,16,15,17,16,18,18,15,16,15,17,16, + 17,18,19,19,19,17,17,17,18,17,13,14,14,16,16,14, + 15,15,17,17,14,15,15,16,17,15,17,17,18,18,16,16, + 17,18,17,14,15,15,16,17,15,16,16,17,17,15,16,16, + 17,17,16,17,17,18,18,17,17,17,18,19,14,15,15,16, + 17,15,16,16,17,17,15,16,16,17,17,16,17,17,18,18, + 17,17,17,19,19,16,16,16,16,18,16,17,17,17,18,17, + 17,17,17,19,18,18,18,19,19,18,18,18,19,20,16,16, + 17,18,18,16,18,17,18,18,17,17,17,20,19,18,18,19, + 21,20,18,20,18,18,19,10,12,12,14,14,14,14,15,15, + 17,14,15,14,17,15,16,16,17,18,18,16,18,17,19,18, + 12,14,13,16,15,14,14,15,15,17,15,16,16,18,17,16, + 17,18,17,19,17,19,18,20,19,12,13,13,15,15,15,16, + 17,17,18,14,16,14,17,16,17,18,18,19,19,17,17,17, + 18,18,15,15,15,17,16,15,16,16,17,17,17,19,17,18, + 18,18,18,18,18,21,19,20,19,20,19,15,15,16,16,17, + 17,17,18,20,20,15,16,16,18,17,18,19,19,19,20,18, + 19,18,19,17, 6,11,11,13,13,11,12,12,14,14,11,12, + 12,14,14,13,14,14,16,16,13,14,14,16,16,11,12,12, + 14,14,12,13,13,15,15,12,13,13,15,15,14,15,15,17, + 17,14,15,15,17,16,11,12,12,14,14,12,13,13,15,15, + 12,13,13,15,15,14,15,15,16,16,14,15,15,16,16,13, + 14,14,16,16,15,15,15,16,16,14,15,15,17,16,16,17, + 17,19,18,16,17,17,18,18,13,14,14,15,15,14,15,15, + 17,16,14,15,15,17,16,16,17,16,17,18,15,16,16,18, + 18,10,12,12,14,14,12,13,14,15,15,12,13,13,15,15, + 14,15,15,17,17,14,15,15,17,16,12,13,13,15,15,14, + 14,14,15,16,14,15,15,16,16,15,16,16,17,18,16,16, + 16,18,18,12,13,13,14,14,14,14,15,16,16,13,14,14, + 16,16,15,16,16,18,18,15,16,16,19,17,14,15,15,16, + 17,15,15,16,17,17,16,17,16,17,18,17,17,18,17,19, + 17,17,18,18,19,14,14,14,16,16,15,16,16,17,17,15, + 16,15,17,17,17,17,17,19,20,16,17,17,18,18,11,12, + 12,14,14,12,13,13,15,15,12,13,13,15,15,14,15,15, + 16,16,14,15,14,16,16,12,13,13,15,15,14,14,14,16, + 16,13,14,14,16,16,15,16,16,18,17,15,16,16,17,17, + 12,13,13,15,15,13,14,14,16,16,13,14,14,16,16,15, + 16,15,18,18,15,16,15,17,16,14,15,15,16,16,15,16, + 16,17,17,15,16,16,18,17,16,17,17,18,18,16,17,17, + 18,18,14,15,14,16,15,15,16,15,17,17,15,16,15,17, + 16,16,17,17,18,18,17,17,16,19,17,10,12,12,14,15, + 14,14,15,15,17,14,15,14,17,15,16,17,17,17,18,16, + 17,17,18,18,12,14,13,16,15,14,14,16,15,17,15,17, + 16,18,17,17,17,18,17,19,18,18,18,19,18,12,13,14, + 15,15,15,16,16,16,17,14,15,14,18,16,18,17,18,19, + 19,17,18,17,20,18,15,15,15,17,17,15,16,16,17,18, + 18,18,18,19,18,18,18,19,18,20,18,19,19,21,21,15, + 15,16,16,17,17,18,18,18,18,15,16,16,17,17,17,19, + 20,19,20,17,18,18,19,17,13,14,14,16,16,14,15,15, + 16,17,14,15,15,17,17,16,16,17,17,18,15,17,16,17, + 17,14,15,15,16,16,15,16,16,17,17,16,16,16,17,17, + 17,17,18,17,18,17,17,17,18,20,14,15,15,17,16,15, + 16,16,17,17,15,16,16,17,17,17,17,17,18,18,16,17, + 17,19,18,16,16,17,17,17,17,18,17,19,18,17,17,17, + 18,19,17,20,18,19,21,17,19,18,19,20,15,17,15,17, + 16,16,17,17,18,18,17,17,17,18,17,18,19,18,19,21, + 18,18,17,19,19, +}; + +static const static_codebook _44p9_p2_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p9_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p9_p2_0, + 0 +}; + +static const long _vq_quantlist__44p9_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p9_p3_0[] = { + 2, 5, 4, 4, 7, 7, 4, 7, 6, 5, 6, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 6, 7, 9, 9, 7, 9, 8, 6, 8, 8, 8,10, + 10, 8,10,10, 8, 9,10,10,11,12,10,12,12, 8,10,10, + 10,12,12,10,12,11, 6, 8, 8, 8,10,10, 8,10,10, 8, + 10,10,10,11,12,10,12,12, 8,10, 9,10,12,11,10,12, + 11, 5, 8, 8, 8,10,10, 8,10,10, 8, 9,10,10,11,11, + 10,11,11, 8,10,10,10,11,12,10,12,11, 8,10,10,10, + 11,11,10,11,11,10,11,11,11,12,13,11,12,13,10,11, + 11,11,13,13,11,13,13, 7, 9, 9,10,11,12,10,12,11, + 9,11,11,11,12,13,12,14,13, 9,11,11,12,13,14,11, + 13,12, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11, + 12,10,12,12, 8,10, 9,10,12,11, 9,11,11, 7, 9, 9, + 10,11,12,10,12,11, 9,11,11,11,12,13,12,14,13, 9, + 11,11,12,13,14,11,13,12, 8,10,10,10,11,11,10,11, + 11,10,11,11,11,13,13,11,13,13,10,11,10,11,13,12, + 11,13,12, +}; + +static const static_codebook _44p9_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44p9_p3_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44p9_p3_0, + 0 +}; + +static const long _vq_quantlist__44p9_p3_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p9_p3_1[] = { + 4, 6, 6, 6, 7, 7, 6, 7, 7, 6, 7, 7, 7, 7, 8, 7, + 7, 8, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, + 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, + 9, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, + 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, + 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 7, 8, 8, 8, 9, 9, 8, 9, 9, + 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 9, 8, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, 9, 7, 8, 8, + 8, 9, 9, 8, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 8, + 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, 8, 9, + 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, + 9, 9, 9, +}; + +static const static_codebook _44p9_p3_1 = { + 5, 243, + (char *)_vq_lengthlist__44p9_p3_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44p9_p3_1, + 0 +}; + +static const long _vq_quantlist__44p9_p4_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p9_p4_0[] = { + 2, 5, 5, 4, 7, 7, 4, 7, 6, 5, 7, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 6, 7, 8, 8, 9, + 10, 8,10,10, 8, 9,10,10,11,12,10,11,12, 8,10,10, + 10,11,12,10,12,11, 6, 8, 7, 8,10,10, 8,10, 9, 8, + 10,10,10,11,12,10,12,12, 8,10, 9,10,12,11,10,12, + 11, 5, 8, 8, 8,10,10, 8,10,10, 7, 9,10, 9,10,11, + 10,11,11, 8,10,10,10,12,12,10,12,11, 7, 9, 9, 9, + 11,11, 9,11,11, 9,10,11,11,11,12,11,12,12, 9,11, + 11,11,12,12,11,12,12, 7, 9, 9,10,11,12,10,12,11, + 9,11,10,11,11,12,12,13,13, 9,11,11,12,13,13,11, + 13,11, 5, 8, 8, 8,10,10, 8,10,10, 8,10,10,10,11, + 12,10,12,12, 7, 9, 9, 9,11,11, 9,11,10, 7, 9, 9, + 10,11,12,10,12,11, 9,11,11,11,11,13,12,13,13, 9, + 10,11,12,13,13,11,12,11, 7, 9, 9, 9,11,11, 9,11, + 11, 9,11,11,11,12,12,11,12,12, 9,11,10,11,12,12, + 10,12,11, +}; + +static const static_codebook _44p9_p4_0 = { + 5, 243, + (char *)_vq_lengthlist__44p9_p4_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44p9_p4_0, + 0 +}; + +static const long _vq_quantlist__44p9_p4_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p9_p4_1[] = { + 6, 8, 8,10, 9, 8, 9, 9,10,10, 8, 9, 9,10,10, 8, + 10,10,10,10, 8,10,10,10,10, 9, 9, 9,10,10, 9,10, + 10,10,11, 9,10,10,11,11,10,10,10,11,11,10,10,10, + 11,11, 9, 9, 9,10,10, 9,10,10,11,11, 9,10,10,11, + 10,10,10,10,11,11,10,10,10,11,11,10,10,10,10,11, + 10,10,11,11,11,10,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,10,10,10,11,10,10,11,11,11,11,10,11, + 10,11,11,11,11,11,11,11,10,11,11,11,11, 9,10,10, + 10,11,10,10,11,11,11,10,11,11,11,11,10,11,11,11, + 11,10,11,11,11,11,10,10,11,11,11,11,11,11,11,11, + 11,11,11,11,12,11,11,12,12,12,11,11,11,12,12,10, + 11,11,11,11,11,11,11,12,12,11,11,11,11,11,11,11, + 11,12,12,11,11,11,12,12,11,11,11,11,11,11,12,12, + 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,12, + 12,11,11,11,11,11,11,12,12,12,12,11,12,11,12,12, + 11,12,12,12,12,12,12,12,12,12, 9,10,10,11,10,10, + 11,11,11,11,10,11,11,11,11,10,11,11,11,11,10,11, + 11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11, + 12,12,11,11,12,12,12,11,11,11,12,12,10,11,10,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12, + 11,11,11,12,12,11,11,11,11,11,11,12,12,12,12,11, + 12,12,12,12,11,12,12,12,12,12,12,12,12,12,11,11, + 11,11,11,11,12,12,12,12,11,12,11,12,12,12,12,12, + 12,12,11,12,12,12,12,11,11,11,11,11,11,12,12,12, + 12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,13,12,12,12,13,13,11,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12, + 13,13,12,12,12,12,12,12,12,12,12,13,12,12,12,13, + 13,12,13,13,13,13,12,13,13,13,13,12,12,12,12,12, + 12,12,12,13,13,12,12,12,13,13,12,13,13,13,13,12, + 13,13,13,13,11,11,11,11,11,11,12,12,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,12,12,12,13,13,11,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,13,13,12,12,12,13,13,12, + 12,12,12,12,12,12,12,13,13,12,12,12,13,13,12,13, + 13,13,13,12,13,13,13,13,12,12,12,12,12,12,12,12, + 13,13,12,12,12,13,12,12,13,13,13,13,12,13,13,13, + 13, 7,10,10,11,11,10,10,11,11,11,10,11,11,11,11, + 10,11,11,11,11,10,11,11,11,11,10,10,10,11,11,10, + 11,11,11,11,11,11,11,11,12,11,11,11,12,12,11,11, + 11,12,12,10,11,11,11,11,11,11,11,12,11,11,11,11, + 12,11,11,11,11,12,12,11,11,11,12,12,11,11,11,11, + 11,11,11,11,12,12,11,11,12,12,12,11,12,12,12,12, + 11,12,12,12,12,11,11,11,11,11,11,12,12,12,12,11, + 11,12,12,12,11,12,12,12,12,11,12,12,12,12,10,11, + 11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11, + 12,12,11,11,11,12,12,11,11,11,11,11,11,11,12,12, + 12,11,11,11,12,12,11,12,12,12,12,11,12,12,12,12, + 11,11,11,11,11,11,12,11,12,12,11,11,11,12,12,11, + 12,12,12,12,11,12,12,12,12,11,11,11,11,12,11,12, + 12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,11,11,11,12,12,11,12,12,12,12,11,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,10,11,10,11,11, + 11,11,11,12,12,11,11,11,12,12,11,12,12,12,12,11, + 12,12,12,12,10,11,11,12,11,11,11,12,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11, + 12,11,11,12,12,12,12,11,12,11,12,12,12,12,12,12, + 12,12,12,12,12,12,11,12,11,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,13,12,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,12,12,12,13,12,11,11,11,12,12,12,12,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,13,13,12,12,12,13,13,11,12,12,12,12,12, + 12,12,12,13,12,12,12,12,12,12,12,13,13,13,12,13, + 12,13,13,12,12,12,12,12,12,12,12,13,13,12,12,12, + 13,13,12,13,13,13,13,12,13,13,13,13,12,12,12,12, + 12,12,12,12,13,13,12,13,12,13,13,12,13,13,13,13, + 12,13,13,13,13,11,11,11,12,12,12,12,12,12,12,11, + 12,12,12,12,12,12,12,13,13,12,12,12,13,13,11,12, + 12,12,12,12,12,12,12,12,12,12,12,13,13,12,13,12, + 13,13,12,13,13,13,13,11,12,12,12,12,12,12,12,13, + 13,12,12,12,13,12,12,13,13,13,13,12,13,13,13,13, + 12,12,12,12,12,12,12,13,13,13,12,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,13, + 13,13,13,12,12,12,13,13,13,13,13,13,13,13,13,13, + 13,13, 7,10,10,11,11,10,11,11,11,11,10,11,11,11, + 11,10,11,11,11,11,10,11,11,11,11,10,11,11,11,11, + 11,11,11,11,11,11,11,11,12,11,11,11,12,12,12,11, + 11,11,12,12,10,10,10,11,11,11,11,11,12,11,10,11, + 11,11,11,11,11,11,12,12,11,11,11,12,12,11,11,11, + 11,11,11,11,12,12,12,11,12,11,12,12,11,12,12,12, + 12,11,12,12,12,12,11,11,11,11,11,11,11,11,12,12, + 11,12,11,12,12,11,12,12,12,12,11,12,12,12,12,10, + 10,10,11,11,11,11,11,12,12,11,11,11,12,12,11,12, + 12,12,12,11,12,12,12,12,11,11,11,11,11,11,11,12, + 12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,11,11,11,11,11,11,12,12,12,12,11,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12, + 12,13,12,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,10,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12, + 11,11,11,12,12,11,11,11,11,11,11,11,12,12,12,11, + 12,11,12,12,11,12,12,12,12,11,12,12,12,12,11,11, + 11,11,11,11,11,11,12,12,11,11,11,12,12,11,12,12, + 12,12,11,12,12,12,12,11,11,11,12,11,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 11,11,11,12,11,11,12,12,12,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,11,11,11,12,12,11,12, + 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12, + 13,12,11,12,12,12,12,12,12,12,12,13,12,12,12,13, + 13,12,13,13,13,13,12,13,13,13,13,11,12,12,12,12, + 12,12,12,12,13,12,12,12,12,12,12,13,13,13,13,12, + 13,13,13,13,12,12,12,12,12,12,12,13,13,13,12,13, + 12,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12, + 12,12,12,13,13,13,13,12,13,12,13,13,13,13,13,13, + 13,13,13,13,13,13,11,11,11,12,12,11,12,12,12,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 12,13,13,12,12,12,13,13,11,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,13,12,13,12,13, + 13,12,12,12,12,12,12,12,12,13,13,12,12,12,13,13, + 13,13,13,13,13,12,13,13,13,13,12,12,12,12,12,12, + 13,12,13,13,12,13,12,13,12,12,13,13,13,13,12,13, + 13,13,13, 8,11,11,12,12,11,12,12,12,12,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,12, + 12,11,12,12,12,12,12,12,12,12,12,12,12,12,13,13, + 12,12,12,13,13,11,11,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,13,13,12,12,12,13,13,11,12, + 12,12,12,12,12,12,12,13,12,12,12,12,12,12,12,13, + 13,13,12,12,13,13,13,11,12,12,12,12,12,12,12,13, + 12,12,12,12,13,13,12,13,13,13,13,12,13,13,13,13, + 11,11,11,12,12,11,12,12,12,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,13,13,12,12,12, + 13,13,11,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,12,13,13,12,13,12,13,13,12,12,12,12,12, + 12,12,12,12,13,12,12,12,13,13,12,13,13,13,13,12, + 13,13,13,13,12,12,12,12,12,12,12,12,13,13,12,12, + 12,13,13,12,13,13,13,13,12,13,13,13,13,11,11,11, + 12,12,11,12,12,12,12,11,12,12,12,12,12,12,12,13, + 12,12,12,12,12,13,11,12,12,12,12,12,12,12,12,13, + 12,12,12,12,13,12,13,13,13,13,12,13,13,13,13,11, + 12,12,12,12,12,12,12,12,13,12,12,12,13,12,12,13, + 13,13,13,12,13,13,13,13,12,12,12,12,12,12,12,12, + 13,13,12,12,13,13,13,12,13,13,13,13,12,13,13,13, + 13,12,12,12,12,12,12,13,13,13,13,12,13,12,13,13, + 12,13,13,13,13,13,13,13,13,13,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,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,13,13,13,12,13,13,13,13,11,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13, + 12,13,12,13,13,12,12,12,12,12,12,12,12,13,13,12, + 12,12,13,13,12,13,13,13,13,12,13,13,13,13,12,12, + 12,12,12,12,13,12,13,13,12,12,12,13,13,13,13,13, + 13,13,12,13,13,13,13,11,11,11,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,12,12,12,13,12, + 11,12,12,12,12,12,12,12,12,12,12,12,12,13,13,12, + 12,13,13,13,12,13,13,13,13,11,12,12,12,12,12,12, + 12,12,13,12,12,12,13,12,12,13,13,13,13,12,13,13, + 13,13,12,12,12,12,12,12,12,12,13,13,12,12,12,13, + 13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12, + 12,13,13,13,13,12,13,12,13,13,13,13,13,13,13,13, + 13,13,13,13, 8,11,11,11,11,11,12,12,12,12,11,12, + 12,12,12,12,12,12,12,12,11,12,12,12,12,11,11,11, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,12,12,12,13,13,11,11,11,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,13,13,12,12,12,13,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,13,13,12,13, + 13,13,13,12,13,13,13,13,11,12,12,12,12,12,12,12, + 12,13,12,12,12,13,12,12,13,13,13,13,12,13,12,13, + 13,11,11,11,12,12,12,12,12,12,12,11,12,12,12,12, + 12,12,12,13,13,12,12,12,13,12,11,12,12,12,12,12, + 12,12,12,12,12,12,12,13,13,12,12,13,13,13,12,13, + 13,13,13,11,12,12,12,12,12,12,12,13,13,12,12,12, + 12,12,12,13,13,13,13,12,13,13,13,13,12,12,12,12, + 12,12,12,13,13,13,12,12,13,13,13,13,13,13,13,13, + 12,13,13,13,13,12,12,12,12,12,12,13,12,13,13,12, + 12,12,13,13,13,13,13,13,13,12,13,13,13,13,11,11, + 11,12,12,11,12,12,12,12,11,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,13,12,13,13,12,12,12,13,13, + 11,12,12,12,12,12,12,12,12,13,12,12,12,12,12,12, + 12,12,13,13,12,13,12,13,13,12,12,12,12,12,12,12, + 12,13,12,12,12,12,13,13,12,13,13,13,13,12,13,13, + 13,13,12,12,12,12,12,12,12,12,13,13,12,12,12,13, + 12,12,13,13,13,13,12,13,13,13,13,11,11,11,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,13,13,11,12,12,12,12,12,12,12,12,13,12,12, + 12,12,12,12,13,13,13,13,12,13,13,13,13,11,12,12, + 12,12,12,12,12,12,13,12,12,12,12,12,12,13,13,13, + 13,12,13,13,13,13,12,12,12,12,12,12,12,12,13,13, + 12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,12, + 12,12,12,12,12,13,13,13,13,12,12,12,13,12,13,13, + 13,13,13,12,13,13,13,13,11,11,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,11,12,12,12,12,12,12,12,12,12,12,12,12,13,12, + 12,12,12,13,13,12,13,13,13,13,11,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,13,13,13,13,12,13, + 12,13,13,12,12,12,12,12,12,12,13,13,13,12,13,12, + 13,13,12,13,13,13,13,13,13,13,13,13,12,12,12,12, + 12,12,12,12,12,13,12,12,12,13,13,13,13,13,13,13, + 12,13,13,13,13, +}; + +static const static_codebook _44p9_p4_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p9_p4_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44p9_p4_1, + 0 +}; + +static const long _vq_quantlist__44p9_p5_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p9_p5_0[] = { + 4, 6, 6, 9, 9, 6, 7, 8,10,11, 6, 8, 7,10,10, 8, + 10,10,12,12, 8,10,10,12,12, 6, 7, 8,10,10, 7, 8, + 9,10,11, 8, 9, 9,11,11,10,10,11,12,13,10,11,11, + 13,13, 6, 8, 7,10,10, 8, 9, 9,11,11, 7, 9, 8,11, + 10,10,11,11,13,13,10,11,10,13,12, 9,10,10,11,12, + 10,10,11,12,13,10,11,11,12,13,12,12,13,12,14,12, + 13,13,14,14, 9,10,10,12,11,10,11,11,13,12,10,11, + 10,13,12,12,13,13,14,14,12,13,12,14,12, 7, 8, 8, + 10,11, 8, 9,10,11,12, 8, 9, 9,11,12,10,11,12,13, + 14,10,11,11,13,13, 8, 9,10,11,12, 9,10,11,12,13, + 10,10,11,12,12,11,12,12,13,14,11,12,12,14,14, 8, + 9, 9,11,12,10,10,11,12,13, 9,10,10,12,12,11,12, + 12,14,14,11,12,12,14,13,11,11,12,12,13,11,12,12, + 13,14,12,12,13,14,14,13,13,14,14,16,13,14,14,15, + 15,11,12,11,13,13,12,12,12,14,14,11,12,12,14,13, + 13,14,14,15,15,13,14,13,15,14, 7, 8, 8,11,10, 8, + 10, 9,12,11, 8,10, 9,12,11,10,11,11,13,13,10,12, + 11,14,13, 8, 9, 9,12,11, 9,10,10,12,12,10,11,10, + 13,12,11,12,12,13,14,11,12,12,14,14, 8,10, 9,12, + 11,10,11,10,12,12, 9,11,10,13,11,11,12,12,14,14, + 11,12,12,14,13,11,11,12,13,13,11,12,12,13,14,12, + 12,12,14,14,13,13,14,14,15,13,14,14,15,15,11,12, + 11,13,12,12,12,12,14,14,11,12,12,14,13,13,14,14, + 15,15,13,14,13,15,14,10,11,11,12,13,11,12,12,13, + 14,11,12,12,13,14,13,13,14,14,16,13,14,14,15,15, + 11,12,12,12,14,12,12,13,13,15,12,13,13,13,15,14, + 14,15,15,16,14,14,15,15,16,11,12,12,13,14,12,13, + 13,14,15,12,13,13,14,14,14,14,15,15,16,14,14,14, + 15,15,13,14,14,14,15,14,14,15,15,16,14,15,15,15, + 16,15,15,16,16,18,16,16,16,17,17,13,14,14,15,15, + 14,14,15,16,16,14,14,14,16,15,16,16,16,17,17,15, + 16,16,17,16,10,11,11,13,12,11,12,12,14,13,11,12, + 12,14,13,13,14,14,15,15,13,14,13,16,14,11,12,12, + 14,13,12,13,13,14,14,12,13,13,15,14,14,14,14,15, + 15,14,15,14,16,15,11,12,12,14,12,12,13,13,15,14, + 12,13,12,15,13,14,15,14,16,15,14,15,14,16,15,13, + 14,14,15,15,14,14,14,15,16,14,15,14,16,16,15,16, + 16,16,17,16,16,16,17,17,13,14,14,15,14,14,15,15, + 16,15,14,15,14,16,15,16,16,16,17,17,15,16,15,18, + 16, 6, 8, 8,11,11, 8, 9,10,11,12, 8,10, 9,12,12, + 10,11,11,13,13,10,12,11,14,13, 8, 9, 9,11,12, 9, + 10,10,12,12, 9,10,10,12,12,11,11,12,13,14,11,12, + 12,14,14, 8,10, 9,12,11,10,11,11,12,12, 9,11,10, + 13,12,11,12,12,14,14,11,12,12,14,13,10,11,11,13, + 13,11,12,12,13,14,11,12,12,14,14,13,13,14,13,15, + 13,14,14,15,15,11,12,11,13,13,12,12,12,14,14,11, + 12,12,14,13,13,14,14,15,15,13,14,13,15,14, 8, 9, + 9,11,11, 9,10,10,12,12, 9,10,10,12,12,11,12,12, + 13,14,11,12,12,14,14, 9, 9,10,11,12,10,10,11,12, + 13,10,10,11,12,13,12,12,13,13,15,12,12,13,14,14, + 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12, + 13,13,14,15,12,13,12,14,14,11,11,12,12,14,12,12, + 13,13,14,12,12,13,13,14,13,13,14,14,16,14,14,14, + 15,15,11,12,12,14,13,12,13,13,14,14,12,13,13,15, + 14,14,14,14,16,16,13,14,14,16,14, 7, 9, 9,12,11, + 9,10,10,12,12, 9,11,10,13,12,11,12,12,13,14,11, + 13,12,14,13, 9,10,10,12,12,10,10,11,12,13,10,12, + 11,13,13,12,12,13,13,14,12,13,13,15,14, 9,10,10, + 12,12,11,11,11,13,13,10,12,10,13,12,12,13,13,14, + 15,12,13,12,15,13,11,12,12,14,13,12,12,13,13,14, + 12,13,13,15,14,13,13,14,13,16,14,15,14,16,15,12, + 12,12,14,14,13,13,13,14,14,12,13,12,14,13,14,15, + 15,16,16,13,14,13,16,13,10,11,12,13,14,11,12,13, + 13,15,12,12,13,14,14,13,14,14,15,16,13,14,14,16, + 15,12,12,13,12,14,12,12,13,13,15,13,13,13,13,15, + 14,14,15,14,16,14,15,15,15,16,12,13,12,14,14,13, + 13,13,15,15,12,13,13,15,15,14,15,15,16,16,14,15, + 15,16,16,13,14,14,13,16,14,14,15,14,16,14,14,15, + 14,16,15,15,16,15,18,16,16,16,16,17,14,14,14,16, + 15,14,15,15,16,16,14,15,15,16,16,16,16,16,17,17, + 15,16,16,17,16,10,12,11,14,13,12,13,13,14,14,12, + 13,12,15,14,14,14,14,15,15,14,15,14,16,15,12,13, + 12,14,13,12,13,13,15,14,13,14,13,15,14,14,15,15, + 16,16,14,15,15,17,15,12,13,12,14,14,13,14,14,15, + 15,13,14,13,15,14,15,15,15,16,16,14,15,15,17,15, + 14,14,14,16,15,14,15,15,16,16,14,15,15,16,15,16, + 16,16,16,17,16,17,16,18,17,14,14,14,16,15,15,15, + 15,16,16,14,15,14,16,15,16,16,17,17,17,15,16,15, + 17,16, 6, 8, 8,11,11, 8, 9,10,12,12, 8,10, 9,12, + 11,10,11,12,13,13,10,11,11,13,13, 8, 9,10,11,12, + 9,10,11,12,13,10,11,11,12,12,11,12,12,13,14,11, + 12,12,14,14, 8, 9, 9,12,11, 9,10,10,12,12, 9,10, + 10,12,12,11,12,12,14,14,11,12,11,14,13,11,11,12, + 13,13,11,12,12,13,14,12,12,12,14,14,13,13,14,14, + 15,13,14,14,15,15,10,11,11,13,13,11,12,12,14,14, + 11,12,12,14,13,13,14,14,15,15,13,14,13,15,13, 7, + 9, 9,11,12, 9,10,11,12,13, 9,10,10,12,12,11,12, + 13,13,14,11,12,12,14,14, 9,10,10,12,12,10,10,11, + 12,13,11,12,11,13,13,12,12,13,13,15,12,13,13,15, + 14, 9,10,10,12,12,10,11,12,13,13,10,11,10,13,12, + 12,13,13,14,15,12,13,12,14,13,12,12,12,14,14,12, + 12,13,13,14,13,13,13,15,14,14,13,14,13,16,14,15, + 15,16,16,11,12,12,13,14,12,13,13,14,15,12,13,12, + 14,13,14,14,15,15,16,13,14,13,15,13, 8, 9, 9,11, + 11, 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,14, + 11,12,11,14,13, 9,10,10,12,12,10,11,11,13,13,10, + 11,11,13,13,12,12,13,14,15,12,13,13,15,14, 9,10, + 9,12,11,10,11,10,13,12,10,11,10,13,12,12,13,12, + 14,14,12,13,12,15,13,11,12,12,13,14,12,13,13,14, + 14,12,13,13,14,14,14,14,14,14,16,14,14,14,16,15, + 11,12,11,14,12,12,13,12,15,13,12,13,12,15,13,14, + 14,14,16,15,13,14,13,16,14,10,11,12,13,14,12,12, + 13,13,15,12,13,13,14,14,14,14,15,15,16,14,14,14, + 15,16,12,12,13,14,14,12,13,14,14,15,13,14,14,15, + 15,14,15,15,15,17,15,15,15,16,16,12,12,13,13,14, + 13,13,14,14,15,12,13,13,14,15,15,15,15,15,17,14, + 15,15,15,15,14,14,14,16,16,14,15,15,15,16,15,15, + 15,16,16,16,15,16,16,18,16,16,17,17,17,14,14,14, + 15,16,15,15,15,16,17,14,15,14,16,16,16,16,17,17, + 18,16,16,15,17,16,10,12,11,14,13,12,12,12,14,14, + 11,13,12,14,13,13,14,14,15,15,13,14,13,16,15,12, + 12,13,14,14,12,13,13,15,15,13,13,13,15,15,14,15, + 15,16,16,14,15,15,17,16,12,13,12,14,12,13,13,13, + 15,13,12,13,12,15,13,14,15,15,16,15,14,15,14,16, + 14,14,14,14,16,16,14,15,15,16,16,14,15,15,16,16, + 15,16,16,16,17,16,17,16,18,17,13,14,14,16,13,14, + 15,15,16,14,14,15,14,16,14,16,16,16,17,16,15,16, + 15,18,15, 9,11,11,13,13,11,12,12,14,14,11,12,12, + 14,14,13,14,14,15,15,13,14,14,15,15,11,12,12,14, + 14,11,12,13,14,15,12,13,13,15,14,13,14,14,15,16, + 13,14,14,16,16,11,12,12,14,14,12,13,13,15,15,12, + 13,13,15,14,14,14,14,16,16,14,15,14,16,15,12,13, + 13,14,15,12,13,14,15,16,13,14,14,16,16,14,14,15, + 16,17,15,15,15,17,17,13,14,14,15,15,14,15,14,16, + 16,14,15,14,16,15,15,16,16,17,17,15,16,15,17,16, + 10,12,12,13,14,11,12,13,14,14,12,13,12,14,14,13, + 14,14,15,16,13,14,14,16,15,11,12,12,14,14,12,12, + 13,14,15,12,13,13,15,15,13,13,15,15,17,14,14,15, + 16,16,12,13,12,14,14,12,13,13,15,15,12,13,13,15, + 14,14,15,15,16,16,14,15,14,16,16,13,12,14,13,16, + 13,13,15,14,16,14,13,15,15,16,14,14,16,15,17,15, + 15,16,16,17,13,14,14,16,15,14,15,15,16,16,14,15, + 14,16,15,16,16,16,17,17,15,16,16,18,16,10,12,12, + 14,14,12,12,13,14,14,12,13,12,15,14,13,14,14,15, + 16,14,15,14,16,15,11,12,12,14,14,12,13,13,14,15, + 13,14,13,15,15,14,14,15,15,16,14,15,15,17,16,12, + 13,13,14,14,13,13,14,15,15,12,14,13,15,15,14,15, + 15,16,16,14,15,15,17,15,13,14,13,15,15,13,14,14, + 15,16,14,15,14,17,16,15,15,15,15,17,16,16,16,18, + 17,14,14,14,16,16,15,15,15,16,16,14,15,14,16,16, + 16,16,17,17,17,16,16,16,17,16,11,12,13,14,14,12, + 13,13,15,15,12,13,13,15,15,14,15,15,16,16,14,15, + 15,17,16,12,13,13,14,15,13,13,14,14,16,13,14,14, + 15,16,15,14,16,15,17,15,15,16,16,17,12,13,13,15, + 15,13,14,14,16,16,13,14,14,16,15,15,15,16,17,17, + 15,16,15,17,16,14,14,15,13,16,15,14,16,14,17,15, + 15,16,14,17,16,15,17,15,18,16,16,17,16,18,14,15, + 15,17,16,15,16,16,17,17,15,16,15,17,16,16,17,17, + 18,18,16,17,15,18,16,11,12,12,14,14,13,13,14,14, + 15,13,14,13,16,14,15,15,15,16,16,15,16,15,17,16, + 12,13,13,15,14,13,13,14,15,15,14,15,14,16,15,15, + 15,16,15,16,16,16,16,18,16,12,13,13,15,15,14,14, + 15,15,16,13,14,13,16,15,16,16,16,17,17,15,16,15, + 17,15,14,15,14,16,15,14,15,15,16,16,15,16,15,17, + 16,16,15,16,15,17,17,18,17,18,17,15,15,15,16,16, + 16,16,16,17,17,14,15,15,17,16,17,17,18,18,18,16, + 17,15,18,15, 9,11,11,13,13,11,12,12,14,14,11,12, + 12,14,14,13,14,14,15,16,13,14,14,15,15,11,12,12, + 14,14,12,13,13,14,15,12,13,13,14,14,14,14,15,15, + 16,14,14,14,16,16,11,12,12,14,14,12,13,13,14,15, + 11,13,12,14,14,13,14,14,16,16,13,14,14,16,15,13, + 14,14,15,15,14,14,15,15,16,14,15,14,16,16,15,15, + 16,16,17,15,16,16,17,17,12,13,13,15,15,13,14,14, + 16,15,12,14,13,16,15,15,16,15,17,17,14,15,15,17, + 15,10,12,12,14,14,12,12,13,14,15,12,13,12,14,14, + 14,14,15,15,16,13,14,14,16,16,12,13,13,14,14,13, + 13,14,14,15,13,14,13,15,15,14,15,15,15,17,14,15, + 15,16,16,11,12,12,14,14,13,13,14,15,15,12,13,13, + 15,14,14,15,15,16,17,14,15,14,16,15,14,14,14,16, + 16,14,15,15,16,16,15,15,15,16,16,15,16,16,16,18, + 16,17,16,18,17,13,13,14,15,15,14,14,15,16,16,13, + 14,14,16,15,16,16,17,17,17,15,15,15,17,15,10,12, + 12,14,13,12,12,13,14,14,11,13,12,14,14,13,14,14, + 16,16,13,14,14,16,15,12,12,13,14,14,12,13,13,14, + 15,13,13,13,15,15,14,14,15,16,16,14,15,15,16,16, + 11,12,12,14,14,12,13,13,15,15,12,13,12,15,14,14, + 15,14,16,16,13,15,13,16,15,13,14,14,15,16,14,15, + 15,15,17,14,15,15,16,16,16,15,16,16,17,16,16,16, + 17,17,13,14,12,16,13,14,15,13,16,15,13,15,13,16, + 14,15,16,15,17,16,15,16,14,17,15,11,12,12,14,15, + 13,13,14,14,16,13,14,13,15,14,15,15,16,16,17,15, + 15,15,16,16,12,13,13,15,15,13,13,14,15,16,14,15, + 14,16,15,15,15,16,15,17,16,16,16,17,17,12,13,13, + 14,15,14,14,15,15,16,13,14,13,15,15,16,16,16,17, + 17,15,16,15,16,15,15,15,15,16,16,14,15,15,16,17, + 16,16,16,17,17,16,15,17,15,18,17,18,17,18,18,14, + 14,15,15,17,15,15,16,16,17,14,15,15,16,16,17,17, + 17,17,18,16,16,15,17,15,11,12,12,14,14,12,13,13, + 15,15,12,13,13,15,15,14,15,15,16,16,14,15,14,17, + 16,13,13,13,15,15,13,14,14,15,16,13,14,14,16,16, + 15,15,16,16,17,15,16,16,17,17,12,13,13,15,14,13, + 14,14,16,15,13,14,13,16,14,15,16,16,17,16,15,16, + 14,17,15,14,15,15,16,17,15,15,16,16,17,15,16,16, + 17,17,16,15,17,16,18,16,17,17,18,18,14,15,14,16, + 13,15,16,15,17,14,15,16,14,17,14,16,17,16,18,16, + 16,17,15,18,15, +}; + +static const static_codebook _44p9_p5_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p9_p5_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44p9_p5_0, + 0 +}; + +static const long _vq_quantlist__44p9_p5_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44p9_p5_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44p9_p5_1 = { + 1, 7, + (char *)_vq_lengthlist__44p9_p5_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44p9_p5_1, + 0 +}; + +static const long _vq_quantlist__44p9_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p9_p6_0[] = { + 2, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 8, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 8, 5, 7, 8, 8, 9, + 10, 8, 9,10, 8, 9,10,10,10,12,10,11,11, 8,10,10, + 10,11,12,10,11,10, 5, 8, 7, 8,10,10, 8,10, 9, 8, + 10,10,10,10,11,10,12,11, 8,10, 9,10,11,11,10,12, + 10, 5, 8, 8, 7, 9,10, 8,10, 9, 7, 9,10, 9,10,11, + 9,11,11, 8,10, 9,10,11,11, 9,11,10, 7, 9, 9, 9, + 10,11, 9,11,11, 9, 9,11,10,10,13,11,12,12, 9,11, + 11,11,12,13,11,13,11, 7, 9, 9, 9,10,11, 9,11,10, + 9,11,10,10,10,12,11,13,12, 9,11,11,11,12,12,10, + 12,10, 5, 8, 8, 8, 9,10, 7,10, 9, 8, 9,10, 9,10, + 11,10,11,11, 7,10, 9, 9,11,11, 9,11,10, 7, 9, 9, + 9,10,11, 9,11,10, 9,11,11,10,10,12,11,12,12, 9, + 10,11,11,12,13,10,12,10, 7, 9, 9, 9,11,11, 9,11, + 10, 9,11,11,11,11,13,11,13,12, 9,11, 9,11,12,12, + 10,13,10, +}; + +static const static_codebook _44p9_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44p9_p6_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44p9_p6_0, + 0 +}; + +static const long _vq_quantlist__44p9_p6_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44p9_p6_1[] = { + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 8, 7, + 8, 8, 7, 8, 7, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 8, 8, + 8, 8, 9, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 9, 9, 8, + 9, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 9, 8, + 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 8, 8, 8, 8, 9, 8, + 8, 9, 8, +}; + +static const static_codebook _44p9_p6_1 = { + 5, 243, + (char *)_vq_lengthlist__44p9_p6_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44p9_p6_1, + 0 +}; + +static const long _vq_quantlist__44p9_p7_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p9_p7_0[] = { + 1,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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, +}; + +static const static_codebook _44p9_p7_0 = { + 5, 3125, + (char *)_vq_lengthlist__44p9_p7_0, + 1, -510105088, 1635281408, 3, 0, + (long *)_vq_quantlist__44p9_p7_0, + 0 +}; + +static const long _vq_quantlist__44p9_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44p9_p7_1[] = { + 1, 4, 4,16,16, 4, 9,11,15,16, 4,12, 8,16,16,12, + 16,16,16,16,13,16,16,16,16, 5, 8,10,16,16, 9, 9, + 14,15,16,12,14,14,16,16,16,16,16,16,16,16,16,16, + 16,16, 5,11, 8,16,15,12,14,16,16,16, 9,15, 9,16, + 16,16,16,16,16,16,16,16,16,16,16,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, 6,11,11, + 16,16,12,13,16,16,16,12,16,14,16,16,16,16,16,16, + 16,16,16,16,16,16,11,15,15,16,16,14,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,12, + 15,16,16,16,16,16,16,16,16,14,16,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, 5,11,11,16,16,12, + 15,16,16,16,12,16,14,16,16,16,16,16,16,16,16,16, + 16,16,16,12,15,15,16,16,14,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,11,15,15,16, + 16,16,16,16,16,16,15,16,14,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,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,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,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, 6,11,12,16,16,11,15,16,16,16,13,16,14,16,16, + 16,16,16,16,16,16,16,16,16,16,11,16,14,16,16,14, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,12,14,14,16,16,16,16,16,16,16,15,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,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, 8,13, + 15,16,16,15,15,16,16,16,14,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,14,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 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, 7,12,12,16,16, + 13,12,16,16,16,14,16,14,16,16,16,16,16,16,16,16, + 16,16,16,16,13,16,16,16,16,14,14,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,12,14,16, + 16,16,16,16,16,16,16,14,16,14,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,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,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,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, 6,11,11,16,16,13,15,16,16,16,11,15,14,16, + 16,16,16,16,16,16,14,16,16,16,16,11,16,16,16,16, + 16,16,16,16,16,15,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,11,16,14,16,16,14,16,16,16,16,13,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, 7, + 11,11,16,16,13,13,16,16,16,13,16,13,16,16,16,16, + 16,16,16,16,16,16,16,16,12,16,15,16,16,14,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,12,14,16,16,16,16,16,16,16,16,14,16,13,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, 8,13,14,16, + 16,15,16,16,16,16,14,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,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,15,16, + 15,16,16,16,16,16,16,16,16,16,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,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,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,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,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,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,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,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,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,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,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,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,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, +}; + +static const static_codebook _44p9_p7_1 = { + 5, 3125, + (char *)_vq_lengthlist__44p9_p7_1, + 1, -514619392, 1630767104, 3, 0, + (long *)_vq_quantlist__44p9_p7_1, + 0 +}; + +static const long _vq_quantlist__44p9_p7_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p9_p7_2[] = { + 1, 3, 2, 5, 4, 7, 7, 8, 8, 9,10,10,10,11,11,11, + 12,12,12,13,13,13,13,13,13, +}; + +static const static_codebook _44p9_p7_2 = { + 1, 25, + (char *)_vq_lengthlist__44p9_p7_2, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44p9_p7_2, + 0 +}; + +static const long _vq_quantlist__44p9_p7_3[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44p9_p7_3[] = { + 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, +}; + +static const static_codebook _44p9_p7_3 = { + 1, 25, + (char *)_vq_lengthlist__44p9_p7_3, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44p9_p7_3, + 0 +}; + +static const char _huff_lengthlist__44p9_short[] = { + 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _huff_book__44p9_short = { + 1, 8, + (char *)_huff_lengthlist__44p9_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44pn1_l0_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44pn1_l0_0[] = { + 1, 3, 3, 8, 8,10,10,10,10,10,10,10,10, 5, 7, 5, + 9, 8,10,10,10,10,11,10,11,10, 5, 5, 7, 8, 9,10, + 10,11,10,10,11,10,11,10,10,10,11,11,11,11,11,11, + 11,10,11,11,10,10,10,10,11,11,11,11,11,10,11,11, + 11,11,11,11,11,11,12,11,10,11,11,11,11,11,11,11, + 11,11,11,11,11,10,10,11,11,12,11,11,11,11,11,11, + 12,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11, + 10,11,10,11,11,11,11,11,11,11,11,11,11,12,11,11, + 12,12,11,11,11,11,11,11,11,11,11,11,11,11,12,11, + 10,11,11,11,11,11,11,11,12,11,13,11,11,11,11,11, + 11,11,11,11,11,11,12,11,13, +}; + +static const static_codebook _44pn1_l0_0 = { + 2, 169, + (char *)_vq_lengthlist__44pn1_l0_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44pn1_l0_0, + 0 +}; + +static const long _vq_quantlist__44pn1_l0_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44pn1_l0_1[] = { + 1, 4, 4, 7, 7, 4, 5, 6, 7, 7, 4, 6, 5, 7, 7, 7, + 6, 7, 6, 7, 7, 7, 6, 7, 6, +}; + +static const static_codebook _44pn1_l0_1 = { + 2, 25, + (char *)_vq_lengthlist__44pn1_l0_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44pn1_l0_1, + 0 +}; + +static const long _vq_quantlist__44pn1_l1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_l1_0[] = { + 1, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const static_codebook _44pn1_l1_0 = { + 2, 9, + (char *)_vq_lengthlist__44pn1_l1_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44pn1_l1_0, + 0 +}; + +static const char _huff_lengthlist__44pn1_lfe[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book__44pn1_lfe = { + 2, 4, + (char *)_huff_lengthlist__44pn1_lfe, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44pn1_long[] = { + 2, 3, 6, 7, 9,13,17, 3, 2, 5, 7, 9,13,17, 6, 5, + 5, 6, 9,12,16, 7, 7, 6, 6, 7,10,13,10,10, 9, 7, + 6,10,13,13,13,12,10,10,11,15,17,17,17,14,14,15, + 17, +}; + +static const static_codebook _huff_book__44pn1_long = { + 2, 49, + (char *)_huff_lengthlist__44pn1_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44pn1_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_p1_0[] = { + 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44pn1_p1_0 = { + 5, 243, + (char *)_vq_lengthlist__44pn1_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44pn1_p1_0, + 0 +}; + +static const long _vq_quantlist__44pn1_p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_p2_0[] = { + 1, 5, 5, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0,12,12, 0, + 8, 8, 0, 9, 9, 0,13,13, 0, 8, 8, 0, 6, 6, 0,11, + 11, 0,12,12, 0,12,12, 0,14,14, 0,11,12, 0,12,12, + 0,15,15, 0,12,12, 0, 5, 5, 0, 5, 5, 0, 6, 6, 0, + 7, 7, 0,10,10, 0, 6, 6, 0, 7, 7, 0,11,11, 0, 6, + 6, 0, 7, 7, 0,11,11, 0,12,11, 0,11,11, 0,14,14, + 0,10,10, 0,12,12, 0,15,15, 0,12,12, 0, 6, 6, 0, + 12,12, 0,12,12, 0,12,12, 0,14,14, 0,11,11, 0,12, + 12, 0,16,16, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 8, 0,12,12, 0,12,12, 0,12,12, 0,15, + 15, 0,12,12, 0,11,11, 0,16,16, 0,11,11, 0, 6, 6, + 0,12,12, 0,12,12, 0,13,13, 0,15,15, 0,12,12, 0, + 13,13, 0,15,15, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44pn1_p2_0 = { + 5, 243, + (char *)_vq_lengthlist__44pn1_p2_0, + 1, -533200896, 1614282752, 2, 0, + (long *)_vq_quantlist__44pn1_p2_0, + 0 +}; + +static const long _vq_quantlist__44pn1_p2_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_p2_1[] = { + 1, 3, 3, 0, 9, 9, 0, 9, 9, 0,10,10, 0, 9, 9, 0, + 10,10, 0,10,10, 0,10,10, 0,10,10, 0, 7, 7, 0, 7, + 7, 0, 6, 6, 0, 8, 8, 0, 7, 7, 0, 8, 8, 0, 8, 8, + 0, 7, 7, 0, 8, 8, 0, 7, 7, 0, 9, 9, 0, 8, 9, 0, + 10,10, 0, 9, 9, 0,10,10, 0,10,11, 0, 9, 9, 0,10, + 10, 0, 9, 9, 0,11,11, 0,12,12, 0,12,12, 0,11,11, + 0,12,12, 0,13,13, 0,12,12, 0,13,13, 0, 8, 8, 0, + 12,12, 0,12,12, 0,13,13, 0,13,13, 0,13,13, 0,13, + 13, 0,13,13, 0,13,13, 0, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 0,11,11, 0,12,12, 0,13,13, 0,12, + 12, 0,13,13, 0,13,13, 0,12,12, 0,12,12, 0, 9, 9, + 0,12,12, 0,13,13, 0,14,14, 0,13,13, 0,14,14, 0, + 14,14, 0,13,13, 0,14,14, 0, 7, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const static_codebook _44pn1_p2_1 = { + 5, 243, + (char *)_vq_lengthlist__44pn1_p2_1, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44pn1_p2_1, + 0 +}; + +static const long _vq_quantlist__44pn1_p3_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_p3_0[] = { + 1, 6, 6, 6, 8, 8, 6, 8, 8, 7, 9, 9,10,11,11, 8, + 8, 8, 7, 9, 9,11,12,12, 9, 9, 9, 6, 7, 7,10,11, + 11,10,11,11,10,11,11,13,13,13,12,12,12,10,12,11, + 14,14,14,12,12,12, 6, 5, 5, 9, 6, 6, 9, 6, 6, 9, + 7, 7,12,10,10,11, 7, 6, 9, 7, 7,13,11,11,12, 7, + 7, 7, 8, 8,12,10,10,12,10,10,11,10,10,15,13,13, + 13, 9, 9,12,11,11,15,14,14,15,11,11, 8, 7, 7,12, + 11,11,12,11,11,11,11,11,14,13,14,14,12,12,12,11, + 11,16,15,15,14,12,12, 0,10,10, 0,12,12, 0,12,12, + 0,11,11, 0,14,14, 0,11,11, 0,11,11, 0,15,15, 0, + 11,11, 7, 8, 8,13,11,11,12,10,10,12,11,11,15,13, + 13,14,11,11,12,10,10,16,14,14,15,10,10, 9, 7, 7, + 13,11,12,13,12,11,12,11,11,15,14,14,14,12,12,13, + 12,12,16,15,15,15,12,12, 0,11,11, 0,12,12, 0,12, + 13, 0,12,12, 0,15,15, 0,12,12, 0,12,12, 0,16,15, + 0,12,12, +}; + +static const static_codebook _44pn1_p3_0 = { + 5, 243, + (char *)_vq_lengthlist__44pn1_p3_0, + 1, -531365888, 1616117760, 2, 0, + (long *)_vq_quantlist__44pn1_p3_0, + 0 +}; + +static const long _vq_quantlist__44pn1_p3_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44pn1_p3_1[] = { + 2, 3, 4, 9, 9,10,12,12,12,11,10,12,12,13,12,11, + 13,12,11,11,11,12,12,12,11,11,13,13,13,13,11,12, + 12,14,14,12,13,13,13,13,11,13,13,13,13,11,13,13, + 13,13,11,13,13,13,13,11,12,12,14,14,12,13,13,12, + 12,11,13,13,13,13,11,13,13,12,12,11,13,13,13,13, + 12,12,13,14,14,12,13,13,12,12,11,13,13,13,13,11, + 13,13,12,12,11,13,13,13,13,12,13,13,14,14,12,13, + 13,12,12,11,13,13,13,13,11,13,13,12,12,11,10,10, + 10,10,12,10,10,11,11,12, 9, 9,11,11,13,11,11,10, + 10,13,10,10,10,10,13,11,11,12,12,13,10,10,12,12, + 14,12,11,12,12,13,11,11,11,12,13,12,12,12,12,13, + 11,11,12,12,13,10,10,12,12,14,11,11,12,12,13,11, + 11,12,12,13,11,11,12,12,14,12,12,12,12,14,10,10, + 11,11,14,12,11,11,11,13,11,11,11,11,13,12,12,11, + 11,14,12,12,12,11,14,10,10,11,11,14,12,11,11,11, + 13,11,11,11,11,13,12,12,11,11,11,11,11,10,10,12, + 10,11, 9, 9,12,12,12,11,11,13,12,12, 9, 9,13,13, + 13,10,10,13,13,13,12,12,13,13,13,14,14,13,12,12, + 11,11,14,13,13,12,12,14,13,13,11,11,13,13,13,12, + 11,13,13,13,14,14,13,12,12,10,10,14,13,13,11,11, + 13,13,13,10,10,13,13,13,11,11,14,13,13,14,14,14, + 12,12,10,10,13,13,13,11,11,13,13,13,10,10,13,13, + 13,11,11,14,13,13,14,14,14,13,13,10,10,13,13,13, + 11,11,13,13,13,10,10,14,12,12, 8, 8,14,12,12, 9, + 9,14,11,11, 9, 9,14,12,12, 8, 8,14,12,12, 7, 7, + 15,13,13,10,10,15,12,12,10,10,15,13,13,10,10,15, + 12,13, 9, 9,15,13,13,10,10,15,13,13,10,10,15,12, + 12,10,10,15,13,13,10,10,15,13,13, 9, 9,15,13,13, + 10,10,15,13,13,10,10,15,12,12,10,10,15,13,13, 9, + 9,14,13,12, 9, 9,14,13,13, 9, 9,15,13,13,10,10, + 15,12,12,10,10,15,13,13, 9, 9,15,13,13, 9, 9,14, + 13,13, 9, 9,14,12,12, 8, 8,13,13,13, 8, 8,14,14, + 13, 9, 9,14,14,13, 7, 7,14,14,14, 8, 8,14,14,14, + 10,10,15,14,14,12,12,14,14,14, 9, 9,15,14,14,10, + 10,14,14,14, 9, 9,14,14,14,10, 9,15,14,14,12,12, + 14,14,14, 9, 9,15,14,14,10,10,14,14,14, 9, 9,15, + 14,15, 9, 9,15,14,14,11,11,14,14,14, 8, 8,14,14, + 14, 9, 9,14,14,14, 8, 8,14,15,14,10,10,15,14,14, + 11,11,14,14,14, 8, 8,15,14,14, 9, 9,14,14,14, 8, + 8,12,12,12,13,13,16,16,15,12,12,17,16,16,13,13, + 17,16,16,11,11,17,16,16,12,12,17,16,17,13,13,17, + 16,16,14,14,17,17,16,12,12,18,16,16,13,13,17,16, + 17,12,12,17,17,17,13,13,18,16,16,14,14,18,17,17, + 12,12,17,17,17,13,13,18,17,17,13,13,17,17,17,13, + 13,17,16,16,14,14,17,17,17,12,12,16,16,17,13,13, + 17,17,16,12,12,18,17,17,13,13,18,16,16,14,14,18, + 17,17,12,12,19,16,17,13,13,17,16,17,12,12,13,14, + 14,10,10,16,14,14,13,13,17,15,15,14,14,17,14,14, + 13,13,16,14,14,13,13,17,16,15,14,14,16,16,16,15, + 15,17,15,15,14,14,17,15,15,14,14,17,15,15,14,14, + 17,16,15,14,14,16,16,16,15,15,18,15,15,13,13,16, + 16,15,14,14,17,15,15,14,13,17,15,15,14,14,16,16, + 16,15,15,18,15,14,13,13,17,15,15,14,14,18,14,15, + 13,13,18,15,15,14,14,16,16,16,15,15,17,15,15,13, + 13,17,15,15,14,14,17,15,15,13,13,13,11,11,10,10, + 16,14,14,13,13,17,14,15,14,14,17,15,15,12,12,17, + 14,14,12,12,16,15,15,14,14,16,14,14,14,14,16,15, + 15,14,14,16,15,15,14,14,16,15,15,14,14,16,15,15, + 14,14,16,15,14,15,15,17,15,15,14,14,17,15,15,14, + 14,17,15,15,14,14,17,15,16,14,14,16,14,14,14,14, + 17,15,15,13,13,17,15,15,13,13,16,15,15,13,13,17, + 16,16,14,14,17,15,14,15,14,17,15,15,13,13,17,15, + 15,13,13,17,15,15,13,13,14,14,14, 9, 9,14,14,14, + 18,19,14,15,15,19,18,14,14,14,19,19,15,14,14,19, + 19,15,16,16,19,19,15,16,16,19,19,15,15,15,19,19, + 15,16,16,19,20,15,15,15,19,19,15,15,15,19,19,15, + 16,16,20,20,15,15,15,18,19,15,15,16,19,20,15,15, + 15,19,18,15,15,15,18,18,15,16,16,21,20,15,15,15, + 19,19,15,15,15,19,19,15,15,14,19,20,15,15,15,20, + 19,15,16,16,19,20,15,15,15,19,19,15,15,15,20,21, + 15,14,15,19,19,14,12,12, 9, 9,14,14,15,21,19,14, + 14,14,18,19,14,15,15,19,20,14,14,14,19,19,15,15, + 15,19,20,15,15,14,21,19,15,15,15,20,19,15,14,15, + 20,21,15,15,15,18,18,15,15,15,20,21,16,14,14,18, + 19,15,15,15,20,19,15,15,15,18,21,15,15,15,19,19, + 15,15,15,19,20,16,15,14,20,19,15,16,15,19,19,15, + 15,15,19, 0,14,15,15,19,19,15,15,15,19,19,15,15, + 14,20,19,15,15,15,20,19,15,15,15,19,19,15,15,15, + 20,19,12,12,12,13,13,16,15,16,11,11,16,16,16,12, + 12,17,16,16,11,11,17,16,16,12,11,17,17,17,13,13, + 18,16,16,14,14,18,18,17,13,13,17,16,16,13,13,17, + 17,17,13,13,17,16,17,12,12,17,15,16,13,13,17,16, + 17,12,12,17,16,16,13,12,17,16,16,12,12,18,17,17, + 13,13,18,16,16,13,14,18,17,17,12,12,17,16,16,12, + 12,17,17,17,12,12,18,17,17,13,13,17,16,16,14,14, + 17,17,17,12,12,17,16,16,12,12,18,17,17,12,12,13, + 14,14, 9, 9,16,14,14,13,13,16,15,15,14,14,16,14, + 14,13,13,16,14,14,13,13,17,16,15,15,15,16,15,16, + 16,15,17,15,15,14,14,17,15,15,15,15,17,15,15,14, + 14,17,15,15,14,14,16,15,16,16,16,17,15,15,14,14, + 16,15,15,14,15,16,15,15,14,14,17,15,15,15,15,16, + 16,16,15,16,18,15,14,13,14,17,15,15,14,14,17,14, + 14,13,13,17,15,15,14,14,16,15,15,15,15,17,15,14, + 14,14,17,15,15,14,14,17,14,14,13,13,13,11,11,11, + 11,16,14,14,12,12,16,14,14,13,13,16,14,14,12,12, + 16,14,14,12,12,16,15,15,13,13,17,14,14,14,14,17, + 15,15,13,13,16,15,15,14,13,16,15,15,13,13,16,15, + 15,13,13,16,14,14,14,14,16,15,15,13,13,16,14,15, + 13,13,17,15,15,13,13,17,15,15,13,13,16,14,14,14, + 14,17,15,15,12,12,17,14,15,13,13,17,15,15,12,12, + 16,15,15,13,13,17,14,14,14,14,17,15,15,12,12,17, + 15,15,13,13,16,15,15,12,12,14,15,15, 8, 8,14,14, + 14,19,18,14,15,15,19,20,14,14,14,19,19,14,14,15, + 19,20,15,16,15,19,21,15,16,16,21,19,15,15,15,20, + 19,15,16,16,19,20,15,15,15,19,18,15,16,15,20,19, + 15,16,16,19,20,15,15,15,19,19,15,16,15,20,20,14, + 15,15,19,19,15,15,15,21,19,15,17,16,19,20,15,14, + 15, 0,21,15,15,15,19,20,14,14,14,19,19,15,15,15, + 20,19,15,16,16,19,19,15,15,15,19,18,15,15,15,20, + 19,14,14,15,18,18,14,12,12, 9, 9,14,14,14,18,18, + 14,14,14,18,18,14,15,14,19,18,14,14,14,19,18,15, + 15,15,19,20,15,14,14,18,18,15,15,15,20,19,15,15, + 15,18,20,15,15,15,19,18,15,15,15,19,19,15,14,14, + 19,21,15,15,15,20,20,15,15,15,18,19,14,15,15,19, + 20,15,15,15,20,19,15,14,14,19,21,15,15,15,18,19, + 15,14,15,20,19,14,15,15,21,21,14,15,15,19,20,15, + 14,14,19,20,15,15,15,19,20,15,15,14,20,20,14,15, + 15,20,19,13,12,12,13,13,17,16,16,11,11,17,16,16, + 12,12,18,17,16,11,11,18,16,16,11,11,17,17,17,13, + 13,18,16,16,13,13,18,17,17,12,12,18,16,16,13,13, + 18,17,17,12,12,18,17,17,13,13,18,16,16,14,14,18, + 16,17,12,12,18,17,17,13,13,17,17,17,12,12,17,17, + 17,12,12,17,16,15,13,13,18,16,16,11,11,17,16,16, + 12,12,17,16,17,11,11,18,17,17,13,12,17,16,16,13, + 13,17,17,17,12,12,17,16,17,12,12,18,17,17,11,11, + 14,14,14, 9, 9,16,14,14,13,13,17,15,15,14,14,17, + 14,14,13,13,16,14,14,13,13,17,15,15,14,14,16,16, + 16,16,15,18,15,15,14,14,17,16,15,15,15,17,15,15, + 14,14,17,15,15,14,15,16,16,16,15,16,18,15,15,14, + 14,17,15,15,14,15,17,15,15,14,14,17,15,15,14,14, + 16,16,16,15,16,17,14,14,13,13,17,15,15,14,14,18, + 15,15,13,13,17,15,15,14,14,16,16,16,15,15,17,14, + 14,13,13,17,15,15,14,14,17,14,14,13,13,13,11,11, + 11,11,16,14,14,12,12,16,14,14,12,13,17,15,14,11, + 11,17,14,14,11,11,17,15,15,13,14,17,14,14,14,14, + 17,15,15,13,13,17,14,14,13,13,17,15,15,13,13,17, + 15,15,13,13,17,14,14,14,14,17,15,15,13,13,18,14, + 15,13,13,17,15,15,13,13,16,15,15,13,13,17,14,14, + 13,13,17,15,15,12,12,16,14,14,12,12,16,15,15,12, + 12,17,16,15,13,13,17,14,14,13,13,17,15,15,12,12, + 16,15,15,12,12,16,15,15,12,12,13,15,15, 8, 8,14, + 14,14,18,19,14,15,15,19,20,14,14,14,18,18,14,15, + 15,18,18,15,16,16,19,19,15,16,17,20,20,15,15,15, + 19,19,15,16,16,18,20,15,15,15,19,19,15,15,16,18, + 18,15,17,16,19,19,15,15,15,18,21,15,16,16,21,20, + 15,15,15,19,21,15,16,15,20,19,15,16,17,20,20,15, + 15,15,19,19,15,16,16,21,20,15,15,15,19,20,15,15, + 15,19,19,15,16,16,20,19,15,15,15,19,19,15,16,15, + 20,21,15,15,15,21,19,14,12,12, 8, 8,14,14,14,20, + 18,14,13,13,19,19,14,14,14,19,18,15,14,14,19,20, + 14,15,15,20,20,15,14,14,21,20,15,15,15,20,20,15, + 15,14,21,19,15,15,15,19,19,15,15,15,19,20,15,14, + 14,20,20,15,15,15,19,20,15,14,14,19,20,15,15,15, + 20,20,15,15,15,20,19,15,14,14,20,21,15,15,15,20, + 21,15,14,14,20, 0,15,16,15,20,21,15,15,15,19,20, + 15,14,14,19,19,15,15,15,19,20,15,15,15,19,19,15, + 15,15,18,20,13,12,12,13,13,18,16,17,12,12,17,16, + 16,12,12,17,17,16,11,11,18,16,16,11,11,17,17,18, + 13,13,18,16,16,14,14,18,17,17,13,13,18,16,16,13, + 13,18,17,17,12,12,17,17,16,13,13,17,16,16,13,14, + 18,17,17,12,12,18,16,16,12,13,17,16,17,12,12,17, + 18,17,13,13,18,16,16,13,13,18,17,17,12,12,17,16, + 16,12,12,17,17,17,11,11,17,16,17,12,12,17,16,16, + 13,13,17,16,16,11,11,17,16,16,12,12,18,16,17,11, + 11,14,14,14, 9, 9,16,14,15,13,13,17,15,15,14,14, + 17,14,14,12,12,16,14,14,13,13,18,15,15,15,15,17, + 15,16,15,16,18,15,15,14,14,17,15,16,15,15,17,15, + 15,14,14,18,15,15,14,14,16,16,16,16,15,17,15,15, + 14,14,16,15,15,14,14,17,15,15,14,14,17,15,15,14, + 14,17,16,16,15,15,17,15,14,13,13,17,15,15,14,14, + 17,15,15,13,13,17,15,15,14,14,16,16,16,15,15,18, + 15,14,14,14,17,15,15,14,14,18,15,15,13,13,13,12, + 12,11,11,16,14,14,12,12,16,14,14,13,13,17,15,15, + 12,12,17,14,14,12,12,17,15,15,14,14,17,14,14,14, + 14,17,15,15,13,13,17,15,14,13,13,17,15,15,13,13, + 17,15,15,13,13,16,14,14,14,14,17,15,15,13,13,16, + 14,14,13,13,16,15,15,13,13,17,15,16,13,13,17,14, + 14,14,13,17,15,15,12,12,16,15,14,12,12,17,15,15, + 12,12,16,15,16,13,13,16,14,14,14,13,17,15,15,12, + 12,16,14,14,12,12,17,15,15,12,12,14,15,15, 8, 8, + 14,14,14,18,18,14,15,15,19,18,14,14,14,18,18,14, + 15,15,19,20,15,16,15,21,18,15,16,16,18, 0,15,15, + 15,19,20,15,16,16,20, 0,15,16,15,19,18,15,15,15, + 19,19,15,16,16,21,19,15,15,15,19,19,15,16,16,20, + 20,15,15,15,19,19,15,15,15,19,18,15,16,16,20,20, + 15,14,15,20,19,15,15,15,19,20,15,15,15,19,19,15, + 16,15,19,20,15,16,16,19,20,15,15,15,19,19,15,16, + 15,20,20,15,15,15,20,18,13,12,12, 8, 8,14,14,14, + 19,20,14,14,14,19,19,14,15,15,20,20,14,14,14,18, + 19,15,15,15,20, 0,15,14,14,18,20,15,15,15,19,19, + 15,15,15,21,19,15,15,15,19,20,15,15,15,20,21,15, + 14,14,20,19,15,15,15,20,19,15,15,14,21,19,15,15, + 15,19,18,15,15,15,20,19,15,14,14,19,19,15,15,16, + 20,19,15,15,15,20, 0,15,15,15,19,21,15,15,15,22, + 20,15,14,14,22,19,15,15,15,19,20,15,14,14,20,19, + 14,15,15,19,21, +}; + +static const static_codebook _44pn1_p3_1 = { + 5, 3125, + (char *)_vq_lengthlist__44pn1_p3_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44pn1_p3_1, + 0 +}; + +static const long _vq_quantlist__44pn1_p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44pn1_p4_0[] = { + 1, 7, 7,14,14, 6, 8, 8,15,16, 7, 8, 8,16,15, 0, + 14,14,17,17, 0,14,14,16,16, 7, 9, 9,16,16,10,11, + 11,17,18, 9, 8, 8,16,16, 0,14,14,19,19, 0,14,14, + 17,16, 8, 9, 9,16,16,12,12,12,17,17,10, 9, 9,16, + 16, 0,15,14,18,20, 0,14,14,17,17, 0,15,15,18,17, + 0,21, 0, 0,21, 0,13,13,17,17, 0,17,17, 0, 0, 0, + 15,15,17,17, 0,15,15,17,18, 0, 0, 0, 0,21, 0,13, + 13,17,17, 0,18,18, 0,21, 0,16,15,17,18, 6, 7, 7, + 14,14, 9,10,10,16,16,11,10,10,15,15, 0,21, 0,20, + 21, 0, 0, 0,18,20,10,10,10,15,16,12,13,13,18,18, + 12,11,11,15,15, 0, 0, 0,20,20, 0, 0,21,19,19,12, + 11,11,15,15,15,14,14,18,18,13,11,11,15,16, 0, 0, + 0,20,19, 0, 0, 0,20,21, 0, 0,20,19,19, 0, 0, 0, + 0, 0, 0,20, 0,17,18, 0, 0,21, 0, 0, 0, 0, 0,21, + 0, 0,21, 0,20,19, 0, 0, 0, 0, 0, 0,21, 0,18,18, + 0, 0, 0,21, 0, 0, 0, 0, 0,20, 7, 6, 6,13,13, 9, + 6, 6,12,12, 9, 7, 7,14,14, 0,10,10,12,12, 0,11, + 11,15,15, 9, 7, 7,14,14,12, 9, 9,14,14,10, 7, 7, + 14,13, 0,11,11,16,15, 0,11,11,14,14, 9, 7, 7,14, + 14,13,10,10,14,14,11, 7, 7,14,13, 0,11,11,16,16, + 0,11,11,14,14, 0,12,12,16,16, 0,19, 0,17,18, 0, + 10,10,14,14, 0,15,14, 0, 0, 0,12,12,14,14, 0,12, + 12,15,15, 0,20, 0,18,19, 0,10,10,14,14, 0,16,15, + 0,20, 0,13,13,14,14, 0,11,11,13,13, 0,12,13,16, + 16, 0,12,12,16,16, 0,16,16, 0,21, 0,17,18, 0, 0, + 0,12,12,16,16, 0,15,15,18, 0, 0,12,12,16,16, 0, + 17,16,21,21, 0,16,17, 0, 0, 0,13,13,17,16, 0,16, + 16,20,21, 0,12,12,17,16, 0,17,17, 0,21, 0,17,17, + 21,21, 0,17,18, 0, 0, 0, 0, 0, 0, 0, 0,15,15, 0, + 0, 0,18,21, 0, 0, 0,18,19, 0, 0, 0,18,17,21,21, + 0, 0, 0, 0, 0, 0,16,16, 0, 0, 0, 0, 0, 0, 0, 0, + 19,19, 0, 0, 0,11,11,12,12, 0,11,11,10,10, 0,12, + 12,13,13, 0,12,12, 9, 9, 0,14,14,13,13, 0,12,12, + 13,13, 0,14,14,12,13, 0,11,11,12,12, 0,13,13,13, + 13, 0,13,13,13,13, 0,12,12,13,13, 0,14,14,12,12, + 0,11,11,12,12, 0,14,13,14,14, 0,13,13,13,13, 0, + 15,15,14,15, 0, 0, 0,16,16, 0,12,12,13,13, 0,16, + 17,20,21, 0,14,13,12,12, 0,14,14,14,14, 0,21, 0, + 16,16, 0,12,12,13,13, 0,18,17,21, 0, 0,14,14,13, + 13, 7, 8, 8,17,17,11,10,10,18,18,12,10,10,17,17, + 0,15,15,20,18, 0,15,15,17,17,11, 9, 9,17,17,14, + 12,12,19,19,13, 9, 9,16,16, 0,15,14, 0,19, 0,14, + 14,16,16,12,10,10,20,18,16,13,13,21,20,14,10,10, + 17,17, 0,15,15,21,20, 0,15,14,17,17, 0,15,15,21, + 21, 0, 0,21, 0, 0, 0,13,13,18,18, 0,19,16, 0, 0, + 0,15,15,17,16, 0,16,16, 0,21, 0, 0, 0, 0,21, 0, + 13,14,18,17, 0,20,19, 0, 0, 0,15,15,18,18, 8, 7, + 7,15,15,12,11,11,17,16,13,11,11,16,16, 0, 0, 0, + 21,20, 0, 0, 0, 0,20,11,10,10,17,17,14,13,13,19, + 18,14,11,11,16,16, 0,20, 0,21,19, 0, 0,21, 0,20, + 12,11,11,17,17,16,15,15, 0,19,14,11,11,17,16, 0, + 21, 0, 0,19, 0, 0, 0,21,20, 0, 0,21,20, 0, 0, 0, + 0, 0, 0, 0, 0, 0,19,21, 0, 0, 0, 0, 0, 0, 0, 0, + 19,20, 0, 0, 0,20,21, 0, 0, 0, 0, 0, 0,20, 0,19, + 21, 0, 0, 0, 0, 0, 0, 0, 0,21,20,11,10, 9,15,15, + 14,11,11,15,15,14,11,11,16,16, 0,14,14,14,14, 0, + 16,15,17,16,13,11,11,16,16,16,13,13,16,16,15,10, + 10,15,15, 0,14,15,17,17, 0,14,14,16,15,13,11,11, + 16,16,17,15,14,16,16,15,10,10,15,15, 0,15,15,17, + 18, 0,15,15,16,16, 0,16,16,17,17, 0,21, 0,21,20, + 0,13,13,15,15, 0,18,18, 0,21, 0,15,15,15,15, 0, + 16,16,17,17, 0, 0, 0, 0,18, 0,13,13,15,15, 0,19, + 18, 0, 0, 0,15,15,16,16, 0,12,12,15,15, 0,13,13, + 17,17, 0,13,13,17,18, 0,16,17,21, 0, 0,20,18, 0, + 0, 0,13,13,17,17, 0,15,15, 0,18, 0,12,12,17,18, + 0,16,16, 0, 0, 0,17,17,21, 0, 0,13,13,18,18, 0, + 16,16,21,21, 0,12,12,17,18, 0,16,17,21, 0, 0,17, + 17, 0,21, 0,17,18, 0, 0, 0, 0, 0, 0, 0, 0,16,15, + 0,21, 0,21,19, 0, 0, 0,18,18, 0, 0, 0,18,19, 0, + 0, 0, 0, 0, 0, 0, 0,16,16,21,21, 0,20,19, 0, 0, + 0,19,21, 0,21, 0,12,12,15,15, 0,12,12,15,16, 0, + 13,13,16,16, 0,14,14,15,15, 0,16,15,17,17, 0,13, + 13,17,17, 0,15,15,16,18, 0,12,12,16,16, 0,14,14, + 17,17, 0,15,14,16,16, 0,13,13,16,16, 0,16,15,17, + 17, 0,12,12,16,16, 0,15,15,18,18, 0,14,14,17,16, + 0,16,16,17,18, 0, 0, 0,20,21, 0,13,13,16,17, 0, + 17,17, 0, 0, 0,15,15,16,16, 0,15,16,17,17, 0, 0, + 0,19, 0, 0,13,13,15,16, 0,19,18, 0, 0, 0,16,15, + 16,17, 8, 8, 8,17,17,13,11,10,17,18,13,10,10,17, + 17, 0,15,15,20,19, 0,15,15,17,17,12,10,10,19,18, + 15,12,12,20,18,14,10,10,17,16, 0,15,15,20,20, 0, + 14,15,16,16,13,10,10,17,17,17,14,14, 0,18,15,10, + 10,17,17, 0,16,15,20,20, 0,14,14,17,17, 0,15,16, + 20,20, 0, 0,21, 0, 0, 0,13,13,17,17, 0,18,17, 0, + 0, 0,15,16,17,18, 0,15,15,18,21, 0, 0, 0,21, 0, + 0,13,13,18,18, 0,19,19, 0, 0, 0,16,16,18,17, 9, + 8, 8,15,15,12,11,11,16,16,13,11,11,16,15, 0, 0, + 0, 0,21, 0,21, 0,19,19,12,11,11,17,18,15,13,13, + 18,19,14,11,11,16,16, 0, 0,21,21,19, 0, 0, 0,21, + 20,13,11,11,18,17,17,14,15,20,21,15,11,12,16,16, + 0, 0, 0,20, 0, 0, 0,21, 0,19, 0, 0, 0, 0,19, 0, + 0, 0, 0, 0, 0,21,21,19,19, 0, 0, 0,21, 0, 0, 0, + 0,19,21, 0, 0, 0,19,20, 0, 0, 0,21, 0, 0, 0,21, + 19,19, 0, 0, 0, 0, 0, 0, 0, 0,21,20, 0,11,11,15, + 15, 0,12,12,15,16, 0,12,12,16,16, 0,15,15,16,15, + 0,16,16,17,17, 0,12,12,17,17, 0,14,14,17,17, 0, + 11,11,16,16, 0,15,15,19,18, 0,15,15,16,16, 0,12, + 12,17,16, 0,14,15,16,16, 0,11,11,15,15, 0,16,16, + 18,19, 0,15,15,15,16, 0,17,17,18,20, 0,21, 0,21, + 19, 0,14,14,16,16, 0,18,18, 0, 0, 0,16,16,15,15, + 0,16,16,18,17, 0, 0, 0,19,20, 0,14,14,16,16, 0, + 19,19, 0, 0, 0,16,17,15,15, 0,12,12,14,15, 0,13, + 13,16,17, 0,12,12,17,17, 0,17,16, 0, 0, 0,18,17, + 21, 0, 0,13,13,19,17, 0,15,15,20,21, 0,12,12,17, + 17, 0,17,17, 0, 0, 0,17,17, 0, 0, 0,13,13,17,18, + 0,16,16,21, 0, 0,12,12,17,17, 0,17,17, 0, 0, 0, + 17,17, 0, 0, 0,18,21, 0, 0, 0, 0, 0, 0, 0, 0,15, + 15,21, 0, 0,20,21, 0, 0, 0,18,19, 0, 0, 0,18,17, + 0, 0, 0, 0, 0, 0, 0, 0,16,16,21, 0, 0,21,21, 0, + 0, 0,18,19, 0, 0, 0,12,12,16,16, 0,13,13,16,17, + 0,13,13,17,16, 0,14,14,16,16, 0,16,15,19,18, 0, + 13,13,17,17, 0,15,15,18,18, 0,12,12,16,16, 0,15, + 15,18,19, 0,15,15,17,16, 0,13,13,17,17, 0,16,16, + 18,17, 0,12,12,17,16, 0,15,15,18,18, 0,15,15,17, + 17, 0,16,16, 0,19, 0, 0, 0, 0, 0, 0,14,14,16,17, + 0,18,18, 0, 0, 0,15,15,17,17, 0,16,16,21,19, 0, + 21, 0,21,21, 0,13,14,16,16, 0,19,19, 0, 0, 0,15, + 16,16,16, 0,11,11,17,16, 0,15,14,19,18, 0,14,14, + 19,19, 0,18,17,18,20, 0,17,17,18,19, 0,13,13,17, + 17, 0,16,17,21,18, 0,13,13,17,16, 0,18,17,19, 0, + 0,16,17,18,18, 0,12,12,19,18, 0,18,18,20,20, 0, + 13,13,17,17, 0,17,17,21, 0, 0,16,17,17,18, 0,18, + 17,19,18, 0, 0, 0, 0, 0, 0,14,14,17,17, 0,19,19, + 21, 0, 0,16,16,16,17, 0,17,17,19,20, 0, 0, 0, 0, + 21, 0,15,15,17,18, 0,21,21, 0, 0, 0,17,17,17,18, + 0,10,10,15,15, 0,15,14,17,18, 0,14,14,16,16, 0, + 0, 0,18, 0, 0,21, 0,19, 0, 0,13,13,17,16, 0,17, + 17,18, 0, 0,14,14,16,15, 0, 0, 0,21, 0, 0,21, 0, + 19,18, 0,13,13,17,17, 0,18,18,20,20, 0,15,15,16, + 16, 0, 0, 0,21,21, 0, 0, 0,20,20, 0, 0, 0,19, 0, + 0, 0, 0, 0, 0, 0,21,20,18,18, 0, 0, 0, 0, 0, 0, + 0, 0, 0,20, 0, 0, 0, 0,20, 0, 0, 0, 0, 0, 0, 0, + 0,19,18, 0, 0, 0, 0,21, 0, 0, 0,18,20, 0,18,19, + 16,17, 0,21,19,17,17, 0, 0,21,18,18, 0, 0,21,20, + 19, 0, 0, 0,20,20, 0, 0,21,17,17, 0, 0, 0,19,19, + 0,20,20,17,17, 0, 0, 0, 0,20, 0, 0,20,18,18, 0, + 21,20,17,17, 0, 0, 0,20,21, 0,19, 0,17,17, 0, 0, + 21, 0, 0, 0,20, 0,18,19, 0, 0, 0,21,21, 0, 0, 0, + 0,21, 0,20,20,17,17, 0, 0, 0, 0, 0, 0,21, 0,18, + 17, 0, 0, 0,20,19, 0, 0, 0, 0,21, 0,20,20,17,17, + 0, 0, 0, 0, 0, 0,21,21,18,18, 0,12,12,15,14, 0, + 14,14,17,17, 0,14,14,17,16, 0,18,18,21, 0, 0,19, + 20, 0, 0, 0,13,13,18,17, 0,16,16,19,18, 0,13,13, + 17,17, 0,17,17, 0, 0, 0,17,17,21, 0, 0,13,13,17, + 17, 0,17,17,21,20, 0,13,13,18,17, 0,18,19,21,21, + 0,19,18, 0, 0, 0,18,17, 0, 0, 0, 0, 0, 0, 0, 0, + 15,16, 0, 0, 0,21,21, 0, 0, 0,20,18,21, 0, 0,17, + 18, 0, 0, 0, 0, 0, 0, 0, 0,15,16, 0, 0, 0, 0,20, + 0, 0, 0, 0,19, 0, 0, 0,15,15,18,19, 0,18,17,21, + 0, 0,16,18, 0,20, 0,17,18,21, 0, 0,18,20, 0, 0, + 0,16,16,21,21, 0,19,20,21, 0, 0,16,15, 0,21, 0, + 18,20, 0, 0, 0,18,19, 0, 0, 0,16,15,21,21, 0,21, + 0, 0, 0, 0,16,15,21, 0, 0,20,19, 0, 0, 0,18,21, + 21, 0, 0,20,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, 0, + 20, 0,21, 0, 0, 0, 0,17,18,20,21, 0,18,18,21,21, + 0, 0, 0, 0, 0, 0,16,16,20, 0, 0, 0,21, 0, 0, 0, + 21,18, 0, 0, 0,12,12,20,17, 0,15,15,19,18, 0,14, + 14,19,18, 0,18,17,21,19, 0,17,17,21,17, 0,13,13, + 21,19, 0,16,17,20,19, 0,13,13,16,16, 0,17,17,20, + 21, 0,16,16,19,17, 0,13,13,18,18, 0,17,19,19,19, + 0,13,13,17,17, 0,18,18, 0,19, 0,16,17,18,18, 0, + 16,17,19,21, 0, 0, 0, 0, 0, 0,15,15,16,17, 0,20, + 19,21, 0, 0,17,17,17,17, 0,17,17,21,19, 0, 0, 0, + 0, 0, 0,15,15,17,17, 0,21, 0, 0, 0, 0,18,18,17, + 17, 0,10,10,15,15, 0,15,15,17,17, 0,15,14,16,16, + 0, 0, 0,21,19, 0,21,21,19,21, 0,13,13,17,16, 0, + 17,17,18,19, 0,14,15,16,15, 0, 0, 0,21,19, 0,21, + 21,18,19, 0,14,14,16,17, 0,18,18,18,19, 0,15,15, + 15,16, 0, 0,21, 0,21, 0, 0, 0,19,20, 0, 0, 0,21, + 19, 0, 0, 0, 0, 0, 0,21,21,19,17, 0, 0, 0, 0, 0, + 0, 0, 0,21,21, 0,21, 0, 0,21, 0, 0, 0, 0, 0, 0, + 21,21,19,18, 0, 0, 0, 0, 0, 0, 0, 0, 0,19, 0,21, + 18,18,17, 0,21, 0,20,20, 0, 0, 0,18,20, 0, 0,21, + 18,21, 0, 0, 0,21,18, 0, 0, 0, 0,19, 0, 0, 0,21, + 21, 0,20,21,17,19, 0,21, 0,21, 0, 0,21, 0,18,18, + 0,20,21,17,18, 0, 0, 0,21,19, 0,20,21,17,18, 0, + 0, 0,21,21, 0, 0, 0,20,19, 0, 0, 0,21,21, 0, 0, + 0, 0, 0, 0,21,21,19,18, 0, 0, 0, 0, 0, 0, 0,21, + 19,18, 0,21,21,19, 0, 0, 0, 0,21, 0, 0,21,21,18, + 17, 0, 0, 0, 0, 0, 0,21, 0,21,18, 0,12,12,14,14, + 0,15,14,17,17, 0,14,14,17,16, 0,19,17, 0, 0, 0, + 19,19, 0, 0, 0,13,13,17,17, 0,17,17,20,20, 0,13, + 13,18,18, 0,18,17, 0, 0, 0,18,21, 0, 0, 0,13,13, + 17,17, 0,18,18,21,20, 0,14,14,18,19, 0,19,18,21, + 0, 0,19,19, 0, 0, 0,20,18,20, 0, 0, 0, 0, 0, 0, + 0,15,16, 0, 0, 0,21,21, 0, 0, 0,19,19, 0, 0, 0, + 18,18, 0, 0, 0, 0, 0, 0, 0, 0,16,16, 0,21, 0, 0, + 0, 0, 0, 0,19,20, 0, 0, 0,15,15,20,21, 0,17,17, + 21,21, 0,17,17, 0, 0, 0,19,18, 0, 0, 0,18,19, 0, + 0, 0,17,16, 0,21, 0, 0,20, 0, 0, 0,16,16, 0,20, + 0,19,19, 0,21, 0,19,18, 0,21, 0,16,16, 0, 0, 0, + 21,21, 0, 0, 0,16,16, 0, 0, 0,21,21, 0, 0, 0,19, + 19, 0, 0, 0,20, 0, 0, 0, 0, 0, 0, 0, 0, 0,17,17, + 0,21, 0, 0,20, 0, 0, 0,20,18,21,21, 0,19,18, 0, + 20, 0, 0, 0, 0, 0, 0,16,17,21, 0, 0, 0,21, 0, 0, + 0,19,20,21,20, +}; + +static const static_codebook _44pn1_p4_0 = { + 5, 3125, + (char *)_vq_lengthlist__44pn1_p4_0, + 1, -528744448, 1616642048, 3, 0, + (long *)_vq_quantlist__44pn1_p4_0, + 0 +}; + +static const long _vq_quantlist__44pn1_p4_1[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44pn1_p4_1[] = { + 2, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _44pn1_p4_1 = { + 1, 7, + (char *)_vq_lengthlist__44pn1_p4_1, + 1, -533200896, 1611661312, 3, 0, + (long *)_vq_quantlist__44pn1_p4_1, + 0 +}; + +static const long _vq_quantlist__44pn1_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_p5_0[] = { + 1, 7, 7, 6, 8, 8, 7, 8, 8, 7, 9, 9,11,11,11, 9, + 8, 8, 7, 9, 9,11,12,11, 9, 9, 9, 6, 7, 7,10,11, + 11,10,10,10,10,11,11,15,14,14,12,12,12,11,11,11, + 14,14,14,12,12,12, 5, 6, 6, 8, 5, 5, 8, 7, 7, 8, + 8, 8,12,10,10,10, 7, 7, 8, 7, 7,12,10,10,10, 7, + 7, 6, 7, 7,12,11,11,12,10,10,11,10,10,14,14,13, + 13,10,10,11,10,10,16,14,14,14,11,10, 7, 7, 7,13, + 12,12,12,12,11,11,11,11,15,14,17,13,12,12,12,11, + 11,15,15,15,14,13,13,10, 9, 9,14,12,11,13,11,11, + 12,11,11,16,15,14,14,11,11,12,11,11,17,14,14,15, + 11,11, 7, 8, 8,12,11,11,13,10,10,11,10,10,17,14, + 13,14,10,10,12,10,10,18,15,15,14,10,10, 8, 7, 7, + 13,12,12,13,11,11,12,11,11,16,14,15,14,12,12,12, + 11,11,18,16,16,14,12,12,11,10,10,13,12,11,13,11, + 11,13,12,12, 0,15,14,14,11,11,13,11,11,16,15,15, + 15,11,11, +}; + +static const static_codebook _44pn1_p5_0 = { + 5, 243, + (char *)_vq_lengthlist__44pn1_p5_0, + 1, -527106048, 1620377600, 2, 0, + (long *)_vq_quantlist__44pn1_p5_0, + 0 +}; + +static const long _vq_quantlist__44pn1_p5_1[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_p5_1[] = { + 2, 6, 7, 6, 8, 8, 7, 7, 8, 7, 8, 8, 9, 9, 9, 8, + 7, 7, 8, 8, 8, 9, 9, 9, 9, 8, 8, 6, 6, 6, 9, 7, + 7, 9, 7, 7, 9, 8, 8,10, 8, 8,10, 8, 8,10, 8, 8, + 10, 9, 8,10, 8, 8, 7, 6, 6, 9, 6, 6, 9, 6, 6, 9, + 7, 7,10, 8, 8,10, 6, 6, 9, 7, 7,10, 8, 8,10, 6, + 6, 7, 7, 7,11, 9, 9,11, 9, 9,10, 9, 9,12,10,10, + 12, 8, 8,11, 9, 9,13, 9,10,12, 8, 8, 8, 7, 7,11, + 9,10,11,10,10,10, 9, 9,11,11,11,11, 9, 9,11,10, + 9,12,11,11,11, 9,10,10, 8, 8,11, 9,10,11, 9, 9, + 11, 9, 9,12,10,10,11, 9, 9,11, 9, 9,12,10,11,11, + 9, 9, 8, 8, 8,12, 9, 9,12, 9, 9,11, 9, 9,13, 9, + 9,13, 8, 8,12, 9, 9,13,10,10,12, 8, 8, 9, 7, 7, + 11,10,10,11,10,10,11,10,10,12,11,11,11,10, 9,11, + 10,10,11,11,11,11, 9, 9,11, 9, 9,12,10,10,11,10, + 10,12,10,10,11,11,11,11, 9, 9,11,10,10,12,11,11, + 11, 9, 9, +}; + +static const static_codebook _44pn1_p5_1 = { + 5, 243, + (char *)_vq_lengthlist__44pn1_p5_1, + 1, -530841600, 1616642048, 2, 0, + (long *)_vq_quantlist__44pn1_p5_1, + 0 +}; + +static const long _vq_quantlist__44pn1_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44pn1_p6_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, +}; + +static const static_codebook _44pn1_p6_0 = { + 5, 243, + (char *)_vq_lengthlist__44pn1_p6_0, + 1, -516716544, 1630767104, 2, 0, + (long *)_vq_quantlist__44pn1_p6_0, + 0 +}; + +static const long _vq_quantlist__44pn1_p6_1[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44pn1_p6_1[] = { + 1, 3, 2, 5, 4, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _44pn1_p6_1 = { + 1, 25, + (char *)_vq_lengthlist__44pn1_p6_1, + 1, -518864896, 1620639744, 5, 0, + (long *)_vq_quantlist__44pn1_p6_1, + 0 +}; + +static const long _vq_quantlist__44pn1_p6_2[] = { + 12, + 11, + 13, + 10, + 14, + 9, + 15, + 8, + 16, + 7, + 17, + 6, + 18, + 5, + 19, + 4, + 20, + 3, + 21, + 2, + 22, + 1, + 23, + 0, + 24, +}; + +static const char _vq_lengthlist__44pn1_p6_2[] = { + 3, 5, 4, 5, 4, 5, 4, 5, 5, 5, 4, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44pn1_p6_2 = { + 1, 25, + (char *)_vq_lengthlist__44pn1_p6_2, + 1, -529006592, 1611661312, 5, 0, + (long *)_vq_quantlist__44pn1_p6_2, + 0 +}; + +static const char _huff_lengthlist__44pn1_short[] = { + 4, 3, 7, 9,12,16,16, 3, 2, 5, 7,11,14,15, 7, 4, + 5, 6, 9,12,15, 8, 5, 5, 5, 8,10,14, 9, 7, 6, 6, + 8,10,12,12,10,10, 7, 6, 8,10,15,12,10, 6, 4, 7, + 9, +}; + +static const static_codebook _huff_book__44pn1_short = { + 2, 49, + (char *)_huff_lengthlist__44pn1_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + diff --git a/vendor/vorbis/lib/books/coupled/res_books_stereo.h b/vendor/vorbis/lib/books/coupled/res_books_stereo.h new file mode 100644 index 0000000..7b53cb9 --- /dev/null +++ b/vendor/vorbis/lib/books/coupled/res_books_stereo.h @@ -0,0 +1,15782 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: static codebooks autogenerated by huff/huffbuld + + ********************************************************************/ + +#include "codebook.h" + +static const long _vq_quantlist__16c0_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16c0_s_p1_0[] = { + 1, 4, 4, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9,10, 0, 0, 0, + 0, 0, 0, 7, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 8, 0, 0, 0, 0, + 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,10,10, 0, 0, 0, + 0, 0, 0, 9, 9,12, 0, 0, 0, 0, 0, 0,10,12,11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,10,10, 0, 0, + 0, 0, 0, 0, 9,12,10, 0, 0, 0, 0, 0, 0,10,11,12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, + 0, 0, 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7,10,10, 0, 0, 0, 0, 0, 0,10,12,11, 0, + 0, 0, 0, 0, 0, 9,10,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7,10,10, 0, 0, 0, 0, 0, 0,10,11,12, + 0, 0, 0, 0, 0, 0, 9,12, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c0_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__16c0_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16c0_s_p1_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16c0_s_p3_0[] = { + 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 6, 7, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 6, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c0_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__16c0_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16c0_s_p3_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16c0_s_p4_0[] = { + 1, 3, 2, 7, 8, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c0_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__16c0_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16c0_s_p4_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16c0_s_p5_0[] = { + 1, 3, 3, 6, 6, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7, + 8, 8, 0, 0, 0, 7, 7, 7, 7, 8, 8, 0, 0, 0, 7, 7, + 8, 8, 9, 9, 0, 0, 0, 7, 7, 8, 8, 9, 9, 0, 0, 0, + 8, 9, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, + 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10, + 10, +}; + +static const static_codebook _16c0_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__16c0_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16c0_s_p5_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__16c0_s_p6_0[] = { + 1, 3, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,11, + 11,11, 0, 0, 0, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11, + 11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10, + 11,11,12,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10, + 10,11,11,12,12,12,13, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,10,10,10, + 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 10,10,11,11,12,12,13,13,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,11,11,12,12,13,13,13,14, 0, 0, 0, 0, 0, + 10,10,10,11,11,11,12,12,13,13,13,14, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,12,12,13,13,14,14, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,13,13,13,13,14,14, 0, 0, + 0, 0, 0, 0, 0,11,11,12,12,12,13,13,14,15,14, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,14,14,15, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,14,13,14, + 14, +}; + +static const static_codebook _16c0_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__16c0_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__16c0_s_p6_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16c0_s_p7_0[] = { + 1, 4, 4, 6, 6, 6, 7, 6, 6, 4, 7, 7,11,10,10,11, + 11,10, 4, 7, 7,10,10,10,11,10,10, 6,10,10,11,11, + 11,11,11,10, 6, 9, 9,11,12,12,11, 9, 9, 6, 9,10, + 11,12,12,11, 9,10, 7,11,11,11,11,11,12,13,12, 6, + 9,10,11,10,10,12,13,13, 6,10, 9,11,10,10,11,12, + 13, +}; + +static const static_codebook _16c0_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__16c0_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__16c0_s_p7_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16c0_s_p7_1[] = { + 1, 3, 4, 6, 6, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, + 8, 8, 8, 9, 9, 9,10,10,10, 6, 7, 8, 8, 8, 8, 9, + 8,10,10,10, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10, 7, + 7, 8, 8, 9, 9, 8, 9,10,10,10, 8, 8, 9, 9, 9, 9, + 9, 9,11,11,11, 8, 8, 9, 9, 9, 9, 9,10,10,11,11, + 9, 9, 9, 9, 9, 9, 9,10,11,11,11,10,11, 9, 9, 9, + 9,10, 9,11,11,11,10,11,10,10, 9, 9,10,10,11,11, + 11,11,11, 9, 9, 9, 9,10,10, +}; + +static const static_codebook _16c0_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__16c0_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16c0_s_p7_1, + 0 +}; + +static const long _vq_quantlist__16c0_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16c0_s_p8_0[] = { + 1, 4, 4, 7, 7, 7, 7, 7, 6, 8, 8,10,10, 6, 5, 6, + 8, 8, 8, 8, 8, 8, 8, 9,10,10, 7, 6, 6, 8, 8, 8, + 8, 8, 8, 8, 8,10,10, 0, 8, 8, 8, 8, 9, 8, 9, 9, + 9,10,10,10, 0, 9, 8, 8, 8, 9, 9, 8, 8, 9, 9,10, + 10, 0,12,11, 8, 8, 9, 9, 9, 9,10,10,11,10, 0,12, + 13, 8, 8, 9,10, 9, 9,11,11,11,12, 0, 0, 0, 8, 8, + 8, 8,10, 9,12,13,12,14, 0, 0, 0, 8, 8, 8, 9,10, + 10,12,12,13,14, 0, 0, 0,13,13, 9, 9,11,11, 0, 0, + 14, 0, 0, 0, 0,14,14,10,10,12,11,12,14,14,14, 0, + 0, 0, 0, 0,11,11,13,13,14,13,14,14, 0, 0, 0, 0, + 0,12,13,13,12,13,14,14,14, +}; + +static const static_codebook _16c0_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__16c0_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__16c0_s_p8_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16c0_s_p8_1[] = { + 1, 4, 3, 5, 5, 7, 7, 7, 6, 6, 7, 7, 7, 5, 5, 7, + 7, 7, 6, 6, 7, 7, 7, 6, 6, +}; + +static const static_codebook _16c0_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__16c0_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16c0_s_p8_1, + 0 +}; + +static const long _vq_quantlist__16c0_s_p9_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16c0_s_p9_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 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 static_codebook _16c0_s_p9_0 = { + 4, 81, + (char *)_vq_lengthlist__16c0_s_p9_0, + 1, -518803456, 1628680192, 2, 0, + (long *)_vq_quantlist__16c0_s_p9_0, + 0 +}; + +static const long _vq_quantlist__16c0_s_p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16c0_s_p9_1[] = { + 1, 5, 5, 5, 5, 9,11,11,10,10,10,10,10,10,10, 7, + 6, 6, 6, 6,10,10,10,10,10,10,10,10,10,10, 7, 6, + 6, 6, 6,10, 9,10,10,10,10,10,10,10,10,10, 7, 7, + 8, 9,10,10,10,10,10,10,10,10,10,10,10, 8, 7,10, + 10,10, 9,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _16c0_s_p9_1 = { + 2, 225, + (char *)_vq_lengthlist__16c0_s_p9_1, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__16c0_s_p9_1, + 0 +}; + +static const long _vq_quantlist__16c0_s_p9_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__16c0_s_p9_2[] = { + 1, 5, 5, 7, 8, 8, 7, 9, 9, 9,12,12,11,12,12,10, + 10,11,12,12,12,11,12,12, 8, 9, 8, 7, 9,10,10,11, + 11,10,11,12,10,12,10,12,12,12,11,12,11, 9, 8, 8, + 9,10, 9, 8, 9,10,12,12,11,11,12,11,10,11,12,11, + 12,12, 8, 9, 9, 9,10,11,12,11,12,11,11,11,11,12, + 12,11,11,12,12,11,11, 9, 9, 8, 9, 9,11, 9, 9,10, + 9,11,11,11,11,12,11,11,10,12,12,12, 9,12,11,10, + 11,11,11,11,12,12,12,11,11,11,12,10,12,12,12,10, + 10, 9,10, 9,10,10, 9, 9, 9,10,10,12,10,11,11, 9, + 11,11,10,11,11,11,10,10,10, 9, 9,10,10, 9, 9,10, + 11,11,10,11,10,11,10,11,11,10,11,11,11,10, 9,10, + 10, 9,10, 9, 9,11, 9, 9,11,10,10,11,11,10,10,11, + 10,11, 8, 9,11,11,10, 9,10,11,11,10,11,11,10,10, + 10,11,10, 9,10,10,11, 9,10,10, 9,11,10,10,10,10, + 11,10,11,11, 9,11,10,11,10,10,11,11,10,10,10, 9, + 10,10,11,11,11, 9,10,10,10,10,10,11,10,10,10, 9, + 10,10,11,10,10,10,10,10, 9,10,11,10,10,10,10,11, + 11,11,10,10,10,10,10,11,10,11,10,11,10,10,10, 9, + 11,11,10,10,10,11,11,10,10,10,10,10,10,10,10,11, + 11, 9,10,10,10,11,10,11,10,10,10,11, 9,10,11,10, + 11,10,10, 9,10,10,10,11,10,11,10,10,10,10,10,11, + 11,10,11,11,10,10,11,11,10, 9, 9,10,10,10,10,10, + 9,11, 9,10,10,10,11,11,10,10,10,10,11,11,11,10, + 9, 9,10,10,11,10,10,10,10,10,11,11,11,10,10,10, + 11,11,11, 9,10,10,10,10, 9,10, 9,10,11,10,11,10, + 10,11,11,10,11,11,11,11,11,10,11,10,10,10, 9,11, + 11,10,11,11,11,11,11,11,11,11,11,10,11,10,10,10, + 10,11,10,10,11, 9,10,10,10, +}; + +static const static_codebook _16c0_s_p9_2 = { + 2, 441, + (char *)_vq_lengthlist__16c0_s_p9_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__16c0_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__16c0_s_single[] = { + 3, 4,19, 7, 9, 7, 8,11, 9,12, 4, 1,19, 6, 7, 7, + 8,10,11,13,18,18,18,18,18,18,18,18,18,18, 8, 6, + 18, 8, 9, 9,11,12,14,18, 9, 6,18, 9, 7, 8, 9,11, + 12,18, 7, 6,18, 8, 7, 7, 7, 9,11,17, 8, 8,18, 9, + 7, 6, 6, 8,11,17,10,10,18,12, 9, 8, 7, 9,12,18, + 13,15,18,15,13,11,10,11,15,18,14,18,18,18,18,18, + 16,16,18,18, +}; + +static const static_codebook _huff_book__16c0_s_single = { + 2, 100, + (char *)_huff_lengthlist__16c0_s_single, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__16c1_s_long[] = { + 2, 5,20, 7,10, 7, 8,10,11,11, 4, 2,20, 5, 8, 6, + 7, 9,10,10,20,20,20,20,19,19,19,19,19,19, 7, 5, + 19, 6,10, 7, 9,11,13,17,11, 8,19,10, 7, 7, 8,10, + 11,15, 7, 5,19, 7, 7, 5, 6, 9,11,16, 7, 6,19, 8, + 7, 6, 6, 7, 9,13, 9, 9,19,11, 9, 8, 6, 7, 8,13, + 12,14,19,16,13,10, 9, 8, 9,13,14,17,19,18,18,17, + 12,11,11,13, +}; + +static const static_codebook _huff_book__16c1_s_long = { + 2, 100, + (char *)_huff_lengthlist__16c1_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__16c1_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16c1_s_p1_0[] = { + 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 7, 0, 0, 0, 0, + 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 9, 9,11, 0, 0, 0, 0, 0, 0, 9,11,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8,11, 9, 0, 0, 0, 0, 0, 0, 9,10,11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,10, 0, + 0, 0, 0, 0, 0, 8, 9,11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,11, + 0, 0, 0, 0, 0, 0, 9,11, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c1_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__16c1_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16c1_s_p1_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16c1_s_p3_0[] = { + 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 7, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c1_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__16c1_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16c1_s_p3_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16c1_s_p4_0[] = { + 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c1_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__16c1_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16c1_s_p4_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16c1_s_p5_0[] = { + 1, 3, 3, 5, 5, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7, + 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0, 8, 8, + 8, 8, 9, 9, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0, + 9, 9, 8, 8,10,10, 0, 0, 0, 9, 9, 8, 8,10,10, 0, + 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10, + 10, +}; + +static const static_codebook _16c1_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__16c1_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16c1_s_p5_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__16c1_s_p6_0[] = { + 1, 3, 3, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,11,12, + 12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11, + 12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11, + 11,12,12, 0, 0, 0, 8, 8, 8, 9,10, 9,10,10,10,10, + 11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10,11, + 11,11,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10, + 11,11,12,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10, + 10,11,11,12,12,13,13, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, 0, + 10,10,11,10,11,11,12,12,13,13,13,13, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,12,12,13,13,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14, 0, 0, + 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,13,13,14, + 14, +}; + +static const static_codebook _16c1_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__16c1_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__16c1_s_p6_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16c1_s_p7_0[] = { + 1, 4, 4, 6, 6, 6, 7, 6, 6, 4, 7, 7,10, 9,10,10, + 10, 9, 4, 7, 7,10,10,10,11,10,10, 6,10,10,11,11, + 11,11,10,10, 6,10, 9,11,11,11,11,10,10, 6,10,10, + 11,11,11,11,10,10, 7,11,11,11,11,11,12,12,11, 6, + 10,10,11,10,10,11,11,11, 6,10,10,10,11,10,11,11, + 11, +}; + +static const static_codebook _16c1_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__16c1_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__16c1_s_p7_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16c1_s_p7_1[] = { + 2, 3, 3, 5, 6, 7, 7, 7, 7, 8, 8,10,10,10, 6, 6, + 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8, + 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 9, 9,10,10,10,10,10, 8, 8, 8, + 8, 9, 9,10,10,10,10,10, 9, 9, 8, 8, 9, 9,10,10, + 10,10,10, 8, 8, 8, 8, 9, 9, +}; + +static const static_codebook _16c1_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__16c1_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16c1_s_p7_1, + 0 +}; + +static const long _vq_quantlist__16c1_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16c1_s_p8_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 6, 5, 5, + 7, 8, 8, 9, 8, 8, 9, 9,10,11, 6, 5, 5, 8, 8, 9, + 9, 8, 8, 9,10,10,11, 0, 8, 8, 8, 9, 9, 9, 9, 9, + 10,10,11,11, 0, 9, 9, 9, 8, 9, 9, 9, 9,10,10,11, + 11, 0,13,13, 9, 9,10,10,10,10,11,11,12,12, 0,14, + 13, 9, 9,10,10,10,10,11,11,12,12, 0, 0, 0,10,10, + 9, 9,11,11,12,12,13,12, 0, 0, 0,10,10, 9, 9,10, + 10,12,12,13,13, 0, 0, 0,13,14,11,10,11,11,12,12, + 13,14, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0, + 0, 0, 0, 0,12,12,12,12,13,13,14,15, 0, 0, 0, 0, + 0,12,12,12,12,13,13,14,15, +}; + +static const static_codebook _16c1_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__16c1_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__16c1_s_p8_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16c1_s_p8_1[] = { + 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6, + 6, 6, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _16c1_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__16c1_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16c1_s_p8_1, + 0 +}; + +static const long _vq_quantlist__16c1_s_p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16c1_s_p9_0[] = { + 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _16c1_s_p9_0 = { + 2, 169, + (char *)_vq_lengthlist__16c1_s_p9_0, + 1, -513964032, 1628680192, 4, 0, + (long *)_vq_quantlist__16c1_s_p9_0, + 0 +}; + +static const long _vq_quantlist__16c1_s_p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16c1_s_p9_1[] = { + 1, 4, 4, 4, 4, 8, 8,12,13,14,14,14,14,14,14, 6, + 6, 6, 6, 6,10, 9,14,14,14,14,14,14,14,14, 7, 6, + 5, 6, 6,10, 9,12,13,13,13,13,13,13,13,13, 7, 7, + 9, 9,11,11,12,13,13,13,13,13,13,13,13, 7, 7, 8, + 8,11,12,13,13,13,13,13,13,13,13,13,12,12,10,10, + 13,12,13,13,13,13,13,13,13,13,13,12,12,10,10,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,12,13,12, + 13,13,13,13,13,13,13,13,13,13,13,13,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,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,12,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13, +}; + +static const static_codebook _16c1_s_p9_1 = { + 2, 225, + (char *)_vq_lengthlist__16c1_s_p9_1, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__16c1_s_p9_1, + 0 +}; + +static const long _vq_quantlist__16c1_s_p9_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__16c1_s_p9_2[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9,10, + 10,10, 9,10,10,11,12,12, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,10,10,10,11,11,10,12,11,11,13,11, 7, 7, 8, + 8, 8, 8, 9, 9, 9,10,10,10,10, 9,10,10,11,11,12, + 11,11, 8, 8, 8, 8, 9, 9,10,10,10,10,11,11,11,11, + 11,11,11,12,11,12,12, 8, 8, 9, 9, 9, 9, 9,10,10, + 10,10,10,10,11,11,11,11,11,11,12,11, 9, 9, 9, 9, + 10,10,10,10,11,10,11,11,11,11,11,11,12,12,12,12, + 11, 9, 9, 9, 9,10,10,10,10,11,11,11,11,11,11,11, + 11,11,12,12,12,13, 9,10,10, 9,11,10,10,10,10,11, + 11,11,11,11,10,11,12,11,12,12,11,12,11,10, 9,10, + 10,11,10,11,11,11,11,11,11,11,11,11,12,12,11,12, + 12,12,10,10,10,11,10,11,11,11,11,11,11,11,11,11, + 11,11,12,13,12,12,11, 9,10,10,11,11,10,11,11,11, + 12,11,11,11,11,11,12,12,13,13,12,13,10,10,12,10, + 11,11,11,11,11,11,11,11,11,12,12,11,13,12,12,12, + 12,13,12,11,11,11,11,11,11,12,11,12,11,11,11,11, + 12,12,13,12,11,12,12,11,11,11,11,11,12,11,11,11, + 11,12,11,11,12,11,12,13,13,12,12,12,12,11,11,11, + 11,11,12,11,11,12,11,12,11,11,11,11,13,12,12,12, + 12,13,11,11,11,12,12,11,11,11,12,11,12,12,12,11, + 12,13,12,11,11,12,12,11,12,11,11,11,12,12,11,12, + 11,11,11,12,12,12,12,13,12,13,12,12,12,12,11,11, + 12,11,11,11,11,11,11,12,12,12,13,12,11,13,13,12, + 12,11,12,10,11,11,11,11,12,11,12,12,11,12,12,13, + 12,12,13,12,12,12,12,12,11,12,12,12,11,12,11,11, + 11,12,13,12,13,13,13,13,13,12,13,13,12,12,13,11, + 11,11,11,11,12,11,11,12,11, +}; + +static const static_codebook _16c1_s_p9_2 = { + 2, 441, + (char *)_vq_lengthlist__16c1_s_p9_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__16c1_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__16c1_s_short[] = { + 5, 6,17, 8,12, 9,10,10,12,13, 5, 2,17, 4, 9, 5, + 7, 8,11,13,16,16,16,16,16,16,16,16,16,16, 6, 4, + 16, 5,10, 5, 7,10,14,16,13, 9,16,11, 8, 7, 8, 9, + 13,16, 7, 4,16, 5, 7, 4, 6, 8,11,13, 8, 6,16, 7, + 8, 5, 5, 7, 9,13, 9, 8,16, 9, 8, 6, 6, 7, 9,13, + 11,11,16,10,10, 7, 7, 7, 9,13,13,13,16,13,13, 9, + 9, 9,10,13, +}; + +static const static_codebook _huff_book__16c1_s_short = { + 2, 100, + (char *)_huff_lengthlist__16c1_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__16c2_s_long[] = { + 4, 7, 9, 9, 9, 8, 9,10,13,16, 5, 4, 5, 6, 7, 7, + 8, 9,12,16, 6, 5, 5, 5, 7, 7, 9,10,12,15, 7, 6, + 5, 4, 5, 6, 8, 9,10,13, 8, 7, 7, 5, 5, 5, 7, 9, + 10,12, 7, 7, 7, 6, 5, 5, 6, 7,10,12, 8, 8, 8, 7, + 7, 5, 5, 6, 9,11, 8, 9, 9, 8, 8, 6, 6, 5, 8,11, + 10,11,12,12,11, 9, 9, 8, 9,12,13,14,15,15,14,12, + 12,11,11,13, +}; + +static const static_codebook _huff_book__16c2_s_long = { + 2, 100, + (char *)_huff_lengthlist__16c2_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__16c2_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16c2_s_p1_0[] = { + 1, 3, 3, 0, 0, 0, 0, 0, 0, 4, 5, 5, 0, 0, 0, 0, + 0, 0, 4, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c2_s_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__16c2_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16c2_s_p1_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16c2_s_p2_0[] = { + 2, 4, 4, 7, 7, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, + 0, 0, 8, 8, 0, 0, 0, 8, 8, 4, 4, 4, 8, 7, 0, 0, + 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, + 9, 9, 4, 4, 4, 7, 8, 0, 0, 0, 8, 8, 0, 0, 0, 8, + 8, 0, 0, 0, 9, 9, 0, 0, 0, 9, 9, 7, 8, 8,10, 9, + 0, 0, 0,12,11, 0, 0, 0,11,12, 0, 0, 0,14,13, 0, + 0, 0,14,14, 7, 8, 8, 9,10, 0, 0, 0,11,12, 0, 0, + 0,11,11, 0, 0, 0,14,14, 0, 0, 0,14,14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8,11,11, 0, 0, 0, + 12,11, 0, 0, 0,12,12, 0, 0, 0,13,12, 0, 0, 0,13, + 13, 8, 8, 8,11,11, 0, 0, 0,11,11, 0, 0, 0,12,12, + 0, 0, 0,13,13, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 9, 8,12,11, 0, 0, 0,12,12, 0, + 0, 0,12,11, 0, 0, 0,13,13, 0, 0, 0,13,13, 8, 8, + 8,11,12, 0, 0, 0,11,12, 0, 0, 0,11,12, 0, 0, 0, + 13,14, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 9, 9,14,14, 0, 0, 0,13,13, 0, 0, 0,13, + 13, 0, 0, 0,13,12, 0, 0, 0,13,13, 8, 9, 9,14,14, + 0, 0, 0,13,13, 0, 0, 0,13,13, 0, 0, 0,12,13, 0, + 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 9, 9,14,14, 0, 0, 0,13,13, 0, 0, 0,13,13, 0, 0, + 0,13,13, 0, 0, 0,13,12, 8, 9, 9,14,14, 0, 0, 0, + 13,13, 0, 0, 0,13,13, 0, 0, 0,13,13, 0, 0, 0,12, + 12, +}; + +static const static_codebook _16c2_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__16c2_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16c2_s_p2_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16c2_s_p3_0[] = { + 1, 3, 3, 5, 5, 7, 7, 8, 8, 0, 0, 0, 6, 6, 8, 8, + 9, 9, 0, 0, 0, 6, 6, 8, 8, 9, 9, 0, 0, 0, 7, 7, + 8, 9,10,10, 0, 0, 0, 7, 7, 9, 9,10,10, 0, 0, 0, + 8, 8, 9, 9,11,11, 0, 0, 0, 7, 7, 9, 9,11,11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c2_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__16c2_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16c2_s_p3_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__16c2_s_p4_0[] = { + 2, 3, 3, 5, 5, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, + 9, 0, 0, 0, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10, + 11,10, 0, 0, 0, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10, + 10,10,10, 0, 0, 0, 6, 6, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,11, 0, 0, 0, 7, 6, 8, 8, 9, 9, 9, 9,10, + 10,11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10, + 11,11,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10, + 10,11,11,11,11,12,12, 0, 0, 0, 7, 8, 8, 8, 9, 9, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9, + 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _16c2_s_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__16c2_s_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__16c2_s_p4_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16c2_s_p5_0[] = { + 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 6, 6,10,11,10,10, + 10,11, 4, 6, 6,10,10,11,10,11,10, 5,10,10, 9,12, + 11,10,12,12, 7,10,10,12,12,12,12,13,13, 7,11,10, + 11,12,12,12,13,13, 6,11,10,10,12,12,11,12,12, 7, + 11,10,12,13,13,12,12,12, 7,10,11,12,13,13,12,12, + 12, +}; + +static const static_codebook _16c2_s_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__16c2_s_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__16c2_s_p5_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16c2_s_p5_1[] = { + 2, 3, 3, 6, 6, 6, 6, 7, 7, 7, 7,11,10,10, 6, 6, + 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8, + 8,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9,11,11,11, 6, + 7, 8, 8, 8, 8, 9, 9,11,11,11, 7, 7, 8, 8, 8, 8, + 8, 8,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9,11,11,11, + 8, 8, 8, 8, 8, 8, 8, 8,11,11,11,11,11, 8, 8, 8, + 8, 8, 8,12,11,11,11,11, 8, 8, 8, 8, 8, 8,12,11, + 11,11,11, 7, 7, 8, 8, 8, 8, +}; + +static const static_codebook _16c2_s_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__16c2_s_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16c2_s_p5_1, + 0 +}; + +static const long _vq_quantlist__16c2_s_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16c2_s_p6_0[] = { + 1, 4, 4, 6, 6, 8, 7, 8, 8, 9, 9,10,10, 5, 5, 5, + 7, 7, 9, 9, 9, 9,11,11,12,12, 6, 5, 5, 7, 7, 9, + 9,10, 9,11,11,12,12, 0, 7, 7, 7, 7, 9, 9,10,10, + 11,11,12,12, 0, 7, 7, 7, 7, 9, 9,10,10,11,11,12, + 12, 0,11,11, 8, 8,10,10,11,11,12,12,13,13, 0,12, + 12, 9, 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const static_codebook _16c2_s_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__16c2_s_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__16c2_s_p6_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16c2_s_p6_1[] = { + 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6, + 6, 6, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _16c2_s_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__16c2_s_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16c2_s_p6_1, + 0 +}; + +static const long _vq_quantlist__16c2_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16c2_s_p7_0[] = { + 1, 4, 4, 7, 7, 8, 8, 8, 8,10, 9,10,10, 5, 5, 5, + 7, 7, 9, 9,10,10,11,10,12,11, 6, 5, 5, 7, 7, 9, + 9,10,10,11,11,12,12,20, 7, 7, 7, 7, 9, 9,10,10, + 11,11,12,12,20, 7, 7, 7, 7, 9, 9,11,10,12,11,12, + 12,20,11,11, 8, 8,10,10,11,11,12,12,13,13,20,12, + 12, 8, 8, 9, 9,11,11,12,12,13,13,20,20,21,10,10, + 10,10,11,11,12,12,13,13,21,21,21,10,10,10,10,11, + 11,12,12,13,13,21,21,21,14,14,11,11,12,12,13,13, + 13,14,21,21,21,16,15,11,11,12,11,13,13,14,14,21, + 21,21,21,21,13,13,12,12,13,13,14,14,21,21,21,21, + 21,13,13,12,12,13,13,14,14, +}; + +static const static_codebook _16c2_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__16c2_s_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__16c2_s_p7_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16c2_s_p7_1[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 6, 7, + 7, 7, 7, 7, 8, 8, 9, 9, 9, 6, 6, 7, 7, 7, 7, 8, + 8, 9, 9, 9, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 7, + 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 7, 7, 7, 7, 8, 8, + 8, 8, 9, 9, 9, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, + 7, 7, 8, 8, 7, 7, 8, 8, 9, 9, 9, 9, 9, 8, 8, 7, + 7, 8, 8, 9, 9, 9, 9, 9, 8, 8, 7, 7, 8, 8, 9, 9, + 9, 9, 9, 7, 7, 7, 7, 8, 8, +}; + +static const static_codebook _16c2_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__16c2_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16c2_s_p7_1, + 0 +}; + +static const long _vq_quantlist__16c2_s_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16c2_s_p8_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9,10,10, 6, + 6, 6, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11,11, 6, 5, + 5, 8, 7, 9, 9, 8, 8, 9, 9,10,10,11,11,20, 8, 8, + 8, 8, 9, 9, 9, 9,10,10,11,10,12,11,20, 8, 8, 8, + 8, 9, 9, 9, 9,10,10,11,11,12,12,20,12,12, 9, 9, + 10,10,10,10,11,11,12,12,13,12,20,13,13, 9, 9,10, + 10,10,10,11,11,12,12,13,13,20,20,20, 9, 9, 9, 9, + 10,10,11,11,12,12,13,12,20,20,20, 9, 9, 9, 8,10, + 10,12,11,12,12,13,13,20,20,20,13,13,10,10,11,11, + 12,12,13,13,13,13,20,20,20,13,13,10,10,11,10,12, + 11,13,13,14,14,20,20,20,20,20,11,11,11,11,12,12, + 13,13,14,14,20,20,20,20,20,11,10,11,11,13,11,13, + 13,14,14,20,20,21,21,21,14,14,11,12,13,13,13,13, + 14,14,21,21,21,21,21,15,15,12,11,13,12,14,13,15, + 14, +}; + +static const static_codebook _16c2_s_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__16c2_s_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__16c2_s_p8_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__16c2_s_p8_1[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,10, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, + 11,11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9,11,11,11, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9,10, 9,10,10,10,10,11,11,11, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,11,11, + 11, 8, 8, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10, + 10,10,10,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9,10,10, + 10,10,10,10,10,10,10,10,11,11,11,11,11, 9, 9, 9, + 9, 9, 9,10,10,10,10,10,10,10,10,10,10,11,11,11, + 11,11, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10, + 10,10,11,11,11,11,11, 9, 9, 9, 9,10,10,10,10,10, + 10,10,10,10,10,10,10,11,11,11,11,11,10, 9,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11, + 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,11,11,11,11,11,11,11,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11, + 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10, + 10,10,10,10,10,11,11,11,11,11,11,11,11,11,10,10, + 10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,11, + 11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10, + 10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _16c2_s_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__16c2_s_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__16c2_s_p8_1, + 0 +}; + +static const long _vq_quantlist__16c2_s_p9_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__16c2_s_p9_0[] = { + 1, 4, 3,10, 8,10,10,10,10,10,10,10,10,10,10,10, + 10, 6,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10, 6,10, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _16c2_s_p9_0 = { + 2, 289, + (char *)_vq_lengthlist__16c2_s_p9_0, + 1, -509798400, 1631393792, 5, 0, + (long *)_vq_quantlist__16c2_s_p9_0, + 0 +}; + +static const long _vq_quantlist__16c2_s_p9_1[] = { + 9, + 8, + 10, + 7, + 11, + 6, + 12, + 5, + 13, + 4, + 14, + 3, + 15, + 2, + 16, + 1, + 17, + 0, + 18, +}; + +static const char _vq_lengthlist__16c2_s_p9_1[] = { + 1, 4, 4, 7, 7, 7, 7, 7, 7, 8, 8,10, 9,11,10,13, + 11,14,13, 6, 6, 6, 8, 8, 8, 8, 8, 7, 9, 8,11, 9, + 13,11,14,12,14,13, 5, 6, 6, 8, 8, 8, 8, 8, 8, 9, + 9,11,11,13,11,14,13,15,15,17, 8, 8, 8, 8, 9, 9, + 9, 8,11, 9,12,10,13,11,14,12,14,13,17, 8, 8, 8, + 8, 9, 9, 9, 9,10,10,11,11,13,13,13,14,16,15,17, + 12,12, 8, 8, 9, 9,10,10,11,11,12,11,13,12,13,12, + 14,13,16,12,12, 8, 8, 9, 9,10,10,11,11,12,12,13, + 13,14,14,15,15,17,17,17, 9, 9, 9, 9,11,11,12,12, + 12,13,13,13,16,14,14,14,17,17,17, 9, 8, 9, 8,11, + 10,12,12,13,13,14,14,15,15,16,16,17,17,17,12,12, + 10,10,11,12,12,13,13,14,13,15,15,14,16,15,17,17, + 17,12,12,10, 8,12, 9,13,12,14,14,15,14,15,16,16, + 16,17,17,17,17,17,11,11,12,12,14,14,14,16,15,16, + 15,16,15,17,17,17,17,17,17,11, 9,12,10,13,11,15, + 14,16,16,17,16,16,15,17,17,17,17,17,15,15,12,12, + 14,14,15,16,16,15,16,16,17,17,17,17,17,17,17,14, + 14,12,10,14,11,15,12,17,16,15,16,17,16,17,17,17, + 17,17,17,17,13,13,14,14,14,16,17,17,16,17,17,17, + 17,17,17,17,17,17,17,13, 9,13,12,15,13,16,16,17, + 17,17,17,17,17,17,17,17,17,17,15,17,14,14,15,16, + 16,17,16,17,16,17,17,17,17,17,17,17,17,17,17,14, + 13,15,16,16,17,16,17,17,17, +}; + +static const static_codebook _16c2_s_p9_1 = { + 2, 361, + (char *)_vq_lengthlist__16c2_s_p9_1, + 1, -518287360, 1622704128, 5, 0, + (long *)_vq_quantlist__16c2_s_p9_1, + 0 +}; + +static const long _vq_quantlist__16c2_s_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__16c2_s_p9_2[] = { + 2, 4, 4, 4, 4, 5, 5, 5, 5, 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, +}; + +static const static_codebook _16c2_s_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__16c2_s_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__16c2_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__16c2_s_short[] = { + 7,10,12,11,12,13,15,16,18,15,10, 8, 8, 8, 9,10, + 12,13,14,17,10, 7, 7, 7, 7, 8,10,12,15,18,10, 7, + 7, 5, 5, 6, 8,10,13,15,10, 7, 6, 5, 4, 4, 6, 9, + 12,15,11, 7, 7, 5, 4, 3, 4, 7,11,13,12, 9, 8, 7, + 5, 4, 4, 5,10,13,11,11,11, 9, 7, 5, 5, 5, 9,12, + 13,12,13,12,10, 8, 8, 7, 9,13,14,14,14,14,13,11, + 11,10,10,13, +}; + +static const static_codebook _huff_book__16c2_s_short = { + 2, 100, + (char *)_huff_lengthlist__16c2_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__8c0_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8c0_s_p1_0[] = { + 1, 5, 4, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, + 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 7, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 8, 0, 0, 0, 0, + 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,10, 9, 0, 0, 0, + 0, 0, 0, 8, 9,11, 0, 0, 0, 0, 0, 0, 9,11,11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9,10, 0, 0, + 0, 0, 0, 0, 9,11,10, 0, 0, 0, 0, 0, 0, 9,11,11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,11, 0, + 0, 0, 0, 0, 0, 9,10,11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9,10, 0, 0, 0, 0, 0, 0, 9,11,11, + 0, 0, 0, 0, 0, 0, 8,11, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _8c0_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__8c0_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__8c0_s_p1_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8c0_s_p3_0[] = { + 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 7, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _8c0_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__8c0_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8c0_s_p3_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__8c0_s_p4_0[] = { + 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 9, 8, 0, 0, 0, 0, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _8c0_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__8c0_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__8c0_s_p4_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__8c0_s_p5_0[] = { + 1, 3, 3, 5, 5, 7, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7, + 8, 8, 0, 0, 0, 7, 7, 7, 7, 8, 9, 0, 0, 0, 8, 8, + 8, 8, 9, 9, 0, 0, 0, 8, 8, 8, 8, 9, 9, 0, 0, 0, + 9, 9, 8, 8,10,10, 0, 0, 0, 9, 9, 8, 8,10,10, 0, + 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10, + 10, +}; + +static const static_codebook _8c0_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__8c0_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__8c0_s_p5_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__8c0_s_p6_0[] = { + 1, 3, 3, 6, 6, 8, 8, 9, 9, 8, 8,10, 9,10,10,11, + 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11, + 11,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11, + 11,12,11, 0, 0, 0, 8, 8, 9, 9,10,10, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10, 9, 9,11, + 10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,10,10, + 11,11,11,12,12,12, 0, 0, 0, 9, 9, 9, 9,10,10,10, + 10,11,11,12,12,13,13, 0, 0, 0,10,10,10,10,11,11, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0,10, 9,10, + 11,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 10, 9,10,11,12,12,13,13,14,13, 0, 0, 0, 0, 0, 9, + 9, 9,10,10,10,11,11,13,12,13,13, 0, 0, 0, 0, 0, + 10,10,10,10,11,11,12,12,13,13,14,14, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,12,12,13,13,13,14, 0, 0, 0, + 0, 0, 0, 0,11,11,11,11,12,12,13,14,14,14, 0, 0, + 0, 0, 0, 0, 0,11,11,11,11,12,12,13,13,14,13, 0, + 0, 0, 0, 0, 0, 0,11,11,12,12,13,13,14,14,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14, + 14, +}; + +static const static_codebook _8c0_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__8c0_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__8c0_s_p6_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8c0_s_p7_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,11, 9,10,12, + 9,10, 4, 7, 7,10,10,10,11, 9, 9, 6,11,10,11,11, + 12,11,11,11, 6,10,10,11,11,12,11,10,10, 6, 9,10, + 11,11,11,11,10,10, 7,10,11,12,11,11,12,11,12, 6, + 9, 9,10, 9, 9,11,10,10, 6, 9, 9,10,10,10,11,10, + 10, +}; + +static const static_codebook _8c0_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__8c0_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__8c0_s_p7_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__8c0_s_p7_1[] = { + 1, 3, 3, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10, 7, 7, + 8, 8, 9, 9, 9, 9,10,10, 9, 7, 7, 8, 8, 9, 9, 9, + 9,10,10,10, 8, 8, 9, 9, 9, 9, 9, 9,10,10,10, 8, + 8, 9, 9, 9, 9, 8, 9,10,10,10, 8, 8, 9, 9, 9,10, + 10,10,10,10,10, 9, 9, 9, 9, 9, 9,10,10,11,10,11, + 9, 9, 9, 9,10,10,10,10,11,11,11,10,10, 9, 9,10, + 10,10, 9,11,10,10,10,10,10,10, 9, 9,10,10,11,11, + 10,10,10, 9, 9, 9,10,10,10, +}; + +static const static_codebook _8c0_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__8c0_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__8c0_s_p7_1, + 0 +}; + +static const long _vq_quantlist__8c0_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__8c0_s_p8_0[] = { + 1, 4, 4, 7, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 6, 6, + 7, 7, 8, 8, 7, 7, 8, 9,10,10, 7, 6, 6, 7, 7, 8, + 7, 7, 7, 9, 9,10,12, 0, 8, 8, 8, 8, 8, 9, 8, 8, + 9, 9,10,10, 0, 8, 8, 8, 8, 8, 9, 8, 9, 9, 9,11, + 10, 0, 0,13, 9, 8, 9, 9, 9, 9,10,10,11,11, 0,13, + 0, 9, 9, 9, 9, 9, 9,11,10,11,11, 0, 0, 0, 8, 9, + 10, 9,10,10,13,11,12,12, 0, 0, 0, 8, 9, 9, 9,10, + 10,13,12,12,13, 0, 0, 0,12, 0,10,10,12,11,10,11, + 12,12, 0, 0, 0,13,13,10,10,10,11,12, 0,13, 0, 0, + 0, 0, 0, 0,13,11, 0,12,12,12,13,12, 0, 0, 0, 0, + 0, 0,13,13,11,13,13,11,12, +}; + +static const static_codebook _8c0_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__8c0_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__8c0_s_p8_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8c0_s_p8_1[] = { + 1, 3, 4, 5, 5, 7, 6, 6, 6, 5, 7, 7, 7, 6, 6, 7, + 7, 7, 6, 6, 7, 7, 7, 6, 6, +}; + +static const static_codebook _8c0_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__8c0_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8c0_s_p8_1, + 0 +}; + +static const long _vq_quantlist__8c0_s_p9_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8c0_s_p9_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 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 static_codebook _8c0_s_p9_0 = { + 4, 81, + (char *)_vq_lengthlist__8c0_s_p9_0, + 1, -518803456, 1628680192, 2, 0, + (long *)_vq_quantlist__8c0_s_p9_0, + 0 +}; + +static const long _vq_quantlist__8c0_s_p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__8c0_s_p9_1[] = { + 1, 4, 4, 5, 5,10, 8,11,11,11,11,11,11,11,11, 6, + 6, 6, 7, 6,11,10,11,11,11,11,11,11,11,11, 7, 5, + 6, 6, 6, 8, 7,11,11,11,11,11,11,11,11,11, 7, 8, + 8, 8, 9, 9,11,11,11,11,11,11,11,11,11, 9, 8, 7, + 8, 9,11,11,11,11,11,11,11,11,11,11,11,10,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,10,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, + 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,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, +}; + +static const static_codebook _8c0_s_p9_1 = { + 2, 225, + (char *)_vq_lengthlist__8c0_s_p9_1, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__8c0_s_p9_1, + 0 +}; + +static const long _vq_quantlist__8c0_s_p9_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__8c0_s_p9_2[] = { + 1, 5, 5, 7, 7, 8, 7, 8, 8,10,10, 9, 9,10,10,10, + 11,11,10,12,11,12,12,12, 9, 8, 8, 8, 8, 8, 9,10, + 10,10,10,11,11,11,10,11,11,12,12,11,12, 8, 8, 7, + 7, 8, 9,10,10,10, 9,10,10, 9,10,10,11,11,11,11, + 11,11, 9, 9, 9, 9, 8, 9,10,10,11,10,10,11,11,12, + 10,10,12,12,11,11,10, 9, 9,10, 8, 9,10,10,10, 9, + 10,10,11,11,10,11,10,10,10,12,12,12, 9,10, 9,10, + 9, 9,10,10,11,11,11,11,10,10,10,11,12,11,12,11, + 12,10,11,10,11, 9,10, 9,10, 9,10,10, 9,10,10,11, + 10,11,11,11,11,12,11, 9,10,10,10,10,11,11,11,11, + 11,10,11,11,11,11,10,12,10,12,12,11,12,10,10,11, + 10, 9,11,10,11, 9,10,11,10,10,10,11,11,11,11,12, + 12,10, 9, 9,11,10, 9,12,11,10,12,12,11,11,11,11, + 10,11,11,12,11,10,12, 9,11,10,11,10,10,11,10,11, + 9,10,10,10,11,12,11,11,12,11,10,10,11,11, 9,10, + 10,12,10,11,10,10,10, 9,10,10,10,10, 9,10,10,11, + 11,11,11,12,11,10,10,10,10,11,11,10,11,11, 9,11, + 10,12,10,12,11,10,11,10,10,10,11,10,10,11,11,10, + 11,10,10,10,10,11,11,12,10,10,10,11,10,11,12,11, + 10,11,10,10,11,11,10,12,10, 9,10,10,11,11,11,10, + 12,10,10,11,11,11,10,10,11,10,10,10,11,10,11,10, + 12,11,11,10,10,10,12,10,10,11, 9,10,11,11,11,10, + 10,11,10,10, 9,11,11,12,12,11,12,11,11,11,11,11, + 11, 9,10,11,10,12,10,10,10,10,11,10,10,11,10,10, + 12,10,10,10,10,10, 9,12,10,10,10,10,12, 9,11,10, + 10,11,10,12,12,10,12,12,12,10,10,10,10, 9,10,11, + 10,10,12,10,10,12,11,10,11,10,10,12,11,10,12,10, + 10,11, 9,11,10, 9,10, 9,10, +}; + +static const static_codebook _8c0_s_p9_2 = { + 2, 441, + (char *)_vq_lengthlist__8c0_s_p9_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__8c0_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__8c0_s_single[] = { + 4, 5,18, 7,10, 6, 7, 8, 9,10, 5, 2,18, 5, 7, 5, + 6, 7, 8,11,17,17,17,17,17,17,17,17,17,17, 7, 4, + 17, 6, 9, 6, 8,10,12,15,11, 7,17, 9, 6, 6, 7, 9, + 11,15, 6, 4,17, 6, 6, 4, 5, 8,11,16, 6, 6,17, 8, + 6, 5, 6, 9,13,16, 8, 9,17,11, 9, 8, 8,11,13,17, + 9,12,17,15,14,13,12,13,14,17,12,15,17,17,17,17, + 17,16,17,17, +}; + +static const static_codebook _huff_book__8c0_s_single = { + 2, 100, + (char *)_huff_lengthlist__8c0_s_single, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__8c1_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8c1_s_p1_0[] = { + 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, + 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0, + 0, 0, 0, 0, 7, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 8, 0, 0, 0, 0, + 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 8, 8,10, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 8,10, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _8c1_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__8c1_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__8c1_s_p1_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8c1_s_p3_0[] = { + 2, 4, 4, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _8c1_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__8c1_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8c1_s_p3_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__8c1_s_p4_0[] = { + 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 9, 8, 0, 0, 0, 0, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _8c1_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__8c1_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__8c1_s_p4_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__8c1_s_p5_0[] = { + 1, 3, 3, 4, 5, 6, 6, 8, 8, 0, 0, 0, 8, 8, 7, 7, + 9, 9, 0, 0, 0, 8, 8, 7, 7, 9, 9, 0, 0, 0, 9,10, + 8, 8, 9, 9, 0, 0, 0,10,10, 8, 8, 9, 9, 0, 0, 0, + 11,10, 8, 8,10,10, 0, 0, 0,11,11, 8, 8,10,10, 0, + 0, 0,12,12, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10, + 10, +}; + +static const static_codebook _8c1_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__8c1_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__8c1_s_p5_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__8c1_s_p6_0[] = { + 1, 3, 3, 5, 5, 8, 8, 8, 8, 9, 9,10,10,11,11,11, + 11, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,11, + 12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11,12,12, 0, 0, 0, 9, 9, 8, 8,10,10,10,10,11,11, + 12,12,12,12, 0, 0, 0, 9, 9, 8, 8,10,10,10,10,11, + 11,12,12,12,12, 0, 0, 0,10,10, 9, 9,10,10,10,10, + 11,11,12,12,13,13, 0, 0, 0,10,10, 9, 9,10,10,10, + 10,11,11,12,12,13,13, 0, 0, 0,11,11, 9, 9,10,10, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,11,11,12,11,12,12,13,13, 0, 0, 0, 0, 0, + 10,10,11,11,11,11,12,12,13,12,13,13, 0, 0, 0, 0, + 0, 0, 0,11,10,11,11,12,12,13,13,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, 0, + 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,13, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,13,13,14, + 14, +}; + +static const static_codebook _8c1_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__8c1_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__8c1_s_p6_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8c1_s_p7_0[] = { + 1, 4, 4, 6, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,10, + 9, 9, 5, 7, 7,10, 9, 9,10, 9, 9, 6,10,10,10,10, + 10,11,10,10, 6, 9, 9,10, 9,10,11,10,10, 6, 9, 9, + 10, 9, 9,11, 9,10, 7,10,10,11,11,11,11,10,10, 6, + 9, 9,10,10,10,11, 9, 9, 6, 9, 9,10,10,10,10, 9, + 9, +}; + +static const static_codebook _8c1_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__8c1_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__8c1_s_p7_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__8c1_s_p7_1[] = { + 2, 3, 3, 5, 5, 7, 7, 7, 7, 7, 7,10,10, 9, 7, 7, + 7, 7, 8, 8, 8, 8, 9, 9, 9, 7, 7, 7, 7, 8, 8, 8, + 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, + 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 8, 8, 8, 8, 8, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _8c1_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__8c1_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__8c1_s_p7_1, + 0 +}; + +static const long _vq_quantlist__8c1_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__8c1_s_p8_0[] = { + 1, 4, 4, 6, 6, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 5, + 7, 7, 8, 8, 8, 8, 9,10,11,11, 7, 5, 5, 7, 7, 8, + 8, 9, 9,10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 9,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9, 9, 9,10, 9,10,11,11,11, 0,13, + 12, 9, 8, 9, 9,10,10,11,11,12,11, 0, 0, 0, 9, 9, + 9, 9,10,10,11,11,12,12, 0, 0, 0,10,10, 9, 9,10, + 10,11,11,12,12, 0, 0, 0,13,13,10,10,11,11,12,11, + 13,12, 0, 0, 0,14,14,10,10,11,10,11,11,12,12, 0, + 0, 0, 0, 0,12,12,11,11,12,12,13,13, 0, 0, 0, 0, + 0,12,12,11,10,12,11,13,12, +}; + +static const static_codebook _8c1_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__8c1_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__8c1_s_p8_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8c1_s_p8_1[] = { + 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6, + 6, 6, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _8c1_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__8c1_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8c1_s_p8_1, + 0 +}; + +static const long _vq_quantlist__8c1_s_p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__8c1_s_p9_0[] = { + 1, 3, 3,10,10,10,10,10,10,10,10,10,10, 5, 6, 6, + 10,10,10,10,10,10,10,10,10,10, 6, 7, 8,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10, 9, 9, 9, 9, +}; + +static const static_codebook _8c1_s_p9_0 = { + 2, 169, + (char *)_vq_lengthlist__8c1_s_p9_0, + 1, -513964032, 1628680192, 4, 0, + (long *)_vq_quantlist__8c1_s_p9_0, + 0 +}; + +static const long _vq_quantlist__8c1_s_p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__8c1_s_p9_1[] = { + 1, 4, 4, 5, 5, 7, 7, 9, 9,11,11,12,12,13,13, 6, + 5, 5, 6, 6, 9, 9,10,10,12,12,12,13,15,14, 6, 5, + 5, 7, 7, 9, 9,10,10,12,12,12,13,14,13,17, 7, 7, + 8, 8,10,10,11,11,12,13,13,13,13,13,17, 7, 7, 8, + 8,10,10,11,11,13,13,13,13,14,14,17,11,11, 9, 9, + 11,11,12,12,12,13,13,14,15,13,17,12,12, 9, 9,11, + 11,12,12,13,13,13,13,14,16,17,17,17,11,12,12,12, + 13,13,13,14,15,14,15,15,17,17,17,12,12,11,11,13, + 13,14,14,15,14,15,15,17,17,17,15,15,13,13,14,14, + 15,14,15,15,16,15,17,17,17,15,15,13,13,13,14,14, + 15,15,15,15,16,17,17,17,17,16,14,15,14,14,15,14, + 14,15,15,15,17,17,17,17,17,14,14,16,14,15,15,15, + 15,15,15,17,17,17,17,17,17,16,16,15,17,15,15,14, + 17,15,17,16,17,17,17,17,16,15,14,15,15,15,15,15, + 15, +}; + +static const static_codebook _8c1_s_p9_1 = { + 2, 225, + (char *)_vq_lengthlist__8c1_s_p9_1, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__8c1_s_p9_1, + 0 +}; + +static const long _vq_quantlist__8c1_s_p9_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__8c1_s_p9_2[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 9, 9, 9, + 9, 9, 9, 9, 9,11,11,12, 7, 7, 7, 7, 8, 8, 9, 9, + 9, 9,10,10,10,10,10,10,10,10,11,11,11, 7, 7, 7, + 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9,10,10,10,10,11, + 11,12, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10, + 10,10,10,10,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9, 9, + 9,10,10,10,10,10,10,10,10,11,11,11, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,11,11, + 11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,10,10,10,10,10, + 10,10,10,11,12,11, 9, 9, 8, 9, 9, 9, 9, 9,10,10, + 10,10,10,10,10,10,10,10,11,11,11,11,11, 8, 8, 9, + 9, 9, 9,10,10,10,10,10,10,10,10,10,10,11,12,11, + 12,11, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10, + 10,10,11,11,11,11,11, 9, 9, 9, 9,10,10,10,10,10, + 10,10,10,10,10,10,10,12,11,12,11,11, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10,10,10,12,11,11,11, + 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10, + 11,11,11,12,11,11,12,11,10,10,10,10,10,10,10,10, + 10,10,10,10,11,10,11,11,11,11,11,11,11,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,11,11,12,11,12, + 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 11,11,12,11,12,11,11,11,11,10,10,10,10,10,10,10, + 10,10,10,10,10,11,11,12,11,11,12,11,11,12,10,10, + 11,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,12, + 12,11,12,11,11,12,12,12,11,11,10,10,10,10,10,10, + 10,10,10,11,12,12,11,12,12,11,12,11,11,11,11,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _8c1_s_p9_2 = { + 2, 441, + (char *)_vq_lengthlist__8c1_s_p9_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__8c1_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__8c1_s_single[] = { + 4, 6,18, 8,11, 8, 8, 9, 9,10, 4, 4,18, 5, 9, 5, + 6, 7, 8,10,18,18,18,18,17,17,17,17,17,17, 7, 5, + 17, 6,11, 6, 7, 8, 9,12,12, 9,17,12, 8, 8, 9,10, + 10,13, 7, 5,17, 6, 8, 4, 5, 6, 8,10, 6, 5,17, 6, + 8, 5, 4, 5, 7, 9, 7, 7,17, 8, 9, 6, 5, 5, 6, 8, + 8, 8,17, 9,11, 8, 6, 6, 6, 7, 9,10,17,12,12,10, + 9, 7, 7, 8, +}; + +static const static_codebook _huff_book__8c1_s_single = { + 2, 100, + (char *)_huff_lengthlist__8c1_s_single, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c2_s_long[] = { + 6, 6,12,10,10,10, 9,10,12,12, 6, 1,10, 5, 6, 6, + 7, 9,11,14,12, 9, 8,11, 7, 8, 9,11,13,15,10, 5, + 12, 7, 8, 7, 9,12,14,15,10, 6, 7, 8, 5, 6, 7, 9, + 12,14, 9, 6, 8, 7, 6, 6, 7, 9,12,12, 9, 7, 9, 9, + 7, 6, 6, 7,10,10,10, 9,10,11, 8, 7, 6, 6, 8,10, + 12,11,13,13,11,10, 8, 8, 8,10,11,13,15,15,14,13, + 10, 8, 8, 9, +}; + +static const static_codebook _huff_book__44c2_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c2_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c2_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c2_s_p1_0[] = { + 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0, + 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 6, 8, 7, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, 8, 0, 0, + 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 8, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c2_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c2_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c2_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c2_s_p2_0[] = { + 1, 4, 4, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 4, 6, 6, 0, 0, 0, 8, + 8, 0, 0, 0, 8, 8, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 4, 6, 6, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0,11,11, 0, 0, + 0,11,11, 0, 0, 0,12,11, 0, 0, 0, 0, 0, 0, 0, 7, + 8, 8, 0, 0, 0,10,11, 0, 0, 0,11,11, 0, 0, 0,11, + 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 8, 8, 0, 0, 0,11,11, 0, 0, 0,11,11, + 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 6, 8, 8, 0, + 0, 0,10,11, 0, 0, 0,10,11, 0, 0, 0,11,11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 9, 0, 0, 0,11,12, 0, 0, 0,11,12, 0, 0, 0, + 12,11, 0, 0, 0, 0, 0, 0, 0, 8,10, 9, 0, 0, 0,12, + 11, 0, 0, 0,12,11, 0, 0, 0,11,12, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c2_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c2_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c2_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c2_s_p3_0[] = { + 2, 4, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c2_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44c2_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c2_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c2_s_p4_0[] = { + 1, 3, 3, 6, 6, 0, 0, 0, 0, 0, 6, 6, 6, 6, 0, 0, + 0, 0, 0, 6, 6, 6, 6, 0, 0, 0, 0, 0, 7, 7, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c2_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c2_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c2_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c2_s_p5_0[] = { + 1, 3, 3, 6, 6, 7, 7, 9, 9, 0, 7, 7, 7, 7, 7, 7, + 9, 9, 0, 7, 7, 7, 7, 7, 7, 9, 9, 0, 8, 8, 7, 7, + 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, 0, 0, + 9, 9, 8, 8,10,10, 0, 0, 0, 9, 9, 8, 8,10,10, 0, + 0, 0,10,10, 9, 9,11,11, 0, 0, 0, 0, 0, 9, 9,11, + 11, +}; + +static const static_codebook _44c2_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44c2_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c2_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c2_s_p6_0[] = { + 1, 4, 3, 6, 6, 8, 8, 9, 9, 9, 9, 9, 9,10,10,11, + 11, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11, + 12,11, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11, + 11,11,12, 0, 8, 8, 7, 7, 9, 9,10,10, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 7, 7, 9, 9,10,10,10, 9,10, + 10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10, + 11,11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10, + 10,11,11,12,12,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 10,10,10,10,11,11,12,12,13,12,13,13, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,12,12,13,13,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, 0, + 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,13,13,14, + 14, +}; + +static const static_codebook _44c2_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__44c2_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c2_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c2_s_p7_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11, + 9, 9, 4, 7, 7,10, 9, 9,10, 9, 9, 7,10,10,11,10, + 11,11,10,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9, + 11,10,11,11,10,10, 7,11,10,11,11,11,12,11,11, 6, + 9, 9,11,10,10,11,11,10, 6, 9, 9,11,10,10,12,10, + 11, +}; + +static const static_codebook _44c2_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__44c2_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c2_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c2_s_p7_1[] = { + 2, 3, 4, 6, 6, 7, 7, 7, 7, 7, 7, 9, 7, 7, 6, 6, + 7, 7, 8, 8, 8, 8, 9, 6, 6, 6, 6, 7, 7, 8, 8, 8, + 8,10, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 8, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44c2_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c2_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c2_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c2_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c2_s_p8_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 6, 5, 5, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 6, 5, 7, 7, 8, + 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13, + 13, 9, 9,10,10,10,10,11,11,12,12, 0, 0, 0,10,10, + 10,10,11,11,12,12,12,13, 0, 0, 0,10,10,10,10,11, + 11,12,12,12,12, 0, 0, 0,14,14,10,11,11,11,12,12, + 13,13, 0, 0, 0,14,14,11,10,11,11,13,12,13,13, 0, + 0, 0, 0, 0,12,12,11,12,13,12,14,14, 0, 0, 0, 0, + 0,12,12,12,12,13,12,14,14, +}; + +static const static_codebook _44c2_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__44c2_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c2_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c2_s_p8_1[] = { + 2, 4, 4, 5, 4, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c2_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__44c2_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c2_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c2_s_p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c2_s_p9_0[] = { + 1, 5, 4,12,12,12,12,12,12,12,12,12,12, 4, 9, 8, + 11,11,11,11,11,11,11,11,11,11, 2, 8, 7,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,10,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,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,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11, +}; + +static const static_codebook _44c2_s_p9_0 = { + 2, 169, + (char *)_vq_lengthlist__44c2_s_p9_0, + 1, -514541568, 1627103232, 4, 0, + (long *)_vq_quantlist__44c2_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c2_s_p9_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c2_s_p9_1[] = { + 1, 4, 4, 6, 6, 7, 6, 8, 8,10, 9,10,10, 6, 5, 5, + 7, 7, 8, 7,10, 9,11,11,12,13, 6, 5, 5, 7, 7, 8, + 8,10,10,11,11,13,13,18, 8, 8, 8, 8, 9, 9,10,10, + 12,12,12,13,18, 8, 8, 8, 8, 9, 9,10,10,12,12,13, + 13,18,11,11, 8, 8,10,10,11,11,12,11,13,12,18,11, + 11, 9, 7,10,10,11,11,11,12,12,13,17,17,17,10,10, + 11,11,12,12,12,10,12,12,17,17,17,11,10,11,10,13, + 12,11,12,12,12,17,17,17,15,14,11,11,12,11,13,10, + 13,12,17,17,17,14,14,12,10,11,11,13,13,13,13,17, + 17,16,17,16,13,13,12,10,13,10,14,13,17,16,17,16, + 17,13,12,12,10,13,11,14,14, +}; + +static const static_codebook _44c2_s_p9_1 = { + 2, 169, + (char *)_vq_lengthlist__44c2_s_p9_1, + 1, -522616832, 1620115456, 4, 0, + (long *)_vq_quantlist__44c2_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c2_s_p9_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c2_s_p9_2[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8,10, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9,10, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 8, 7, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9,10,11,11, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9,10, 9, 9, 9,10,11,10, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9,10,10,10,10,11,10, 8, 8, 9, 9, 9, 9, + 9, 9,10, 9, 9,10, 9,10,11,10,11,11,11, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9,10,10,11,11,11,11,11, 9, 9, + 9, 9, 9, 9,10, 9, 9, 9,10,10,11,11,11,11,11, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,11,11,11,11,11, + 9, 9, 9, 9,10,10, 9, 9, 9,10,10,10,11,11,11,11, + 11,11,11, 9, 9, 9,10, 9, 9,10,10,10,10,11,11,10, + 11,11,11,11,10, 9,10,10, 9, 9, 9, 9,10,10,11,10, + 11,11,11,11,11, 9, 9, 9, 9,10, 9,10,10,10,10,11, + 10,11,11,11,11,11,10,10, 9, 9,10, 9,10,10,10,10, + 10,10,10,11,11,11,11,11,11, 9, 9,10, 9,10, 9,10, + 10, +}; + +static const static_codebook _44c2_s_p9_2 = { + 2, 289, + (char *)_vq_lengthlist__44c2_s_p9_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c2_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c2_s_short[] = { + 11, 9,13,12,12,11,12,12,13,15, 8, 2,11, 4, 8, 5, + 7,10,12,15,13, 7,10, 9, 8, 8,10,13,17,17,11, 4, + 12, 5, 9, 5, 8,11,14,16,12, 6, 8, 7, 6, 6, 8,11, + 13,16,11, 4, 9, 5, 6, 4, 6,10,13,16,11, 6,11, 7, + 7, 6, 7,10,13,15,13, 9,12, 9, 8, 6, 8,10,12,14, + 14,10,10, 8, 6, 5, 6, 9,11,13,15,11,11, 9, 6, 5, + 6, 8, 9,12, +}; + +static const static_codebook _huff_book__44c2_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c2_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c3_s_long[] = { + 5, 6,11,11,11,11,10,10,12,11, 5, 2,11, 5, 6, 6, + 7, 9,11,13,13,10, 7,11, 6, 7, 8, 9,10,12,11, 5, + 11, 6, 8, 7, 9,11,14,15,11, 6, 6, 8, 4, 5, 7, 8, + 10,13,10, 5, 7, 7, 5, 5, 6, 8,10,11,10, 7, 7, 8, + 6, 5, 5, 7, 9, 9,11, 8, 8,11, 8, 7, 6, 6, 7, 9, + 12,11,10,13, 9, 9, 7, 7, 7, 9,11,13,12,15,12,11, + 9, 8, 8, 8, +}; + +static const static_codebook _huff_book__44c3_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c3_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c3_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c3_s_p1_0[] = { + 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0, + 0, 0, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 6, 8, 7, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 8, 8, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, 8, 0, 0, + 0, 0, 0, 0, 7, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c3_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c3_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c3_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c3_s_p2_0[] = { + 2, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 7, + 7, 0, 0, 0, 7, 7, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 5, 6, 6, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, + 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5, + 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, + 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8,10,10, 0, 0, 0, 9, 9, 0, 0, 0, 9, 9, 0, 0, 0, + 10,10, 0, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, 0, 9, + 9, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c3_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c3_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c3_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c3_s_p3_0[] = { + 2, 4, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c3_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44c3_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c3_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c3_s_p4_0[] = { + 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c3_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c3_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c3_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c3_s_p5_0[] = { + 1, 3, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 7, 8, + 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8, + 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0, + 9, 9, 9, 9,10,10, 0, 0, 0, 9, 9, 9, 9,10,10, 0, + 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0,10,10,11, + 11, +}; + +static const static_codebook _44c3_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44c3_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c3_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c3_s_p6_0[] = { + 2, 3, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 10, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,10, + 11,11, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10, + 10,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,11,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, + 9,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,10,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 8, + 9, 9,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 8, + 8, 9, 9,10,10,11,11,12,11,12,12, 0, 0, 0, 0, 0, + 9,10,10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0, + 0, 0, 0,10,10,10,10,11,11,12,12,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0, 0, + 0, 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0, + 0, 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,13, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13, + 13, +}; + +static const static_codebook _44c3_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__44c3_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c3_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c3_s_p7_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11, + 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11, + 10,12,11,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9, + 11,10,10,11,10,10, 7,11,11,11,11,11,12,11,11, 6, + 9, 9,11,10,10,11,10,10, 6, 9, 9,11,10,10,11,10, + 10, +}; + +static const static_codebook _44c3_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__44c3_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c3_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c3_s_p7_1[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6, + 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, + 7, 8, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 8, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 9, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44c3_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c3_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c3_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c3_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c3_s_p8_0[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 5, 7, 7, 8, + 8, 8, 8, 9, 9,11,10, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,12, 0,13, + 13, 9, 9,10,10,10,10,11,11,12,12, 0, 0, 0,10,10, + 10,10,11,11,12,12,12,12, 0, 0, 0,10,10,10,10,11, + 11,12,12,12,12, 0, 0, 0,14,14,11,11,11,11,12,12, + 13,13, 0, 0, 0,14,14,11,11,11,11,12,12,13,13, 0, + 0, 0, 0, 0,12,12,12,12,13,13,14,13, 0, 0, 0, 0, + 0,13,13,12,12,13,12,14,13, +}; + +static const static_codebook _44c3_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__44c3_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c3_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c3_s_p8_1[] = { + 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 4, 5, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c3_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__44c3_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c3_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c3_s_p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c3_s_p9_0[] = { + 1, 4, 4,12,12,12,12,12,12,12,12,12,12, 4, 9, 8, + 12,12,12,12,12,12,12,12,12,12, 2, 9, 7,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,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,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,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,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, +}; + +static const static_codebook _44c3_s_p9_0 = { + 2, 169, + (char *)_vq_lengthlist__44c3_s_p9_0, + 1, -514332672, 1627381760, 4, 0, + (long *)_vq_quantlist__44c3_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c3_s_p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44c3_s_p9_1[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 7, 9, 9,10,10,10,10, 6, + 5, 5, 7, 7, 8, 8,10, 8,11,10,12,12,13,13, 6, 5, + 5, 7, 7, 8, 8,10, 9,11,11,12,12,13,12,18, 8, 8, + 8, 8, 9, 9,10, 9,11,10,12,12,13,13,18, 8, 8, 8, + 8, 9, 9,10,10,11,11,13,12,14,13,18,11,11, 9, 9, + 10,10,11,11,11,12,13,12,13,14,18,11,11, 9, 8,11, + 10,11,11,11,11,12,12,14,13,18,18,18,10,11,10,11, + 12,12,12,12,13,12,14,13,18,18,18,10,11,11, 9,12, + 11,12,12,12,13,13,13,18,18,17,14,14,11,11,12,12, + 13,12,14,12,14,13,18,18,18,14,14,11,10,12, 9,12, + 13,13,13,13,13,18,18,17,16,18,13,13,12,12,13,11, + 14,12,14,14,17,18,18,17,18,13,12,13,10,12,11,14, + 14,14,14,17,18,18,18,18,15,16,12,12,13,10,14,12, + 14,15,18,18,18,16,17,16,14,12,11,13,10,13,13,14, + 15, +}; + +static const static_codebook _44c3_s_p9_1 = { + 2, 225, + (char *)_vq_lengthlist__44c3_s_p9_1, + 1, -522338304, 1620115456, 4, 0, + (long *)_vq_quantlist__44c3_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c3_s_p9_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c3_s_p9_2[] = { + 2, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8,10, 6, 6, 7, 7, 8, 7, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9,10, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 9,11,11,11, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10, 9,10,10,10,11,11, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,11,11,11, 9, 9, + 9, 9, 9, 9,10,10, 9, 9,10, 9,11,10,11,11,11, 9, + 9, 9, 9, 9, 9, 9, 9,10,10,10, 9,11,11,11,11,11, + 9, 9, 9, 9,10,10, 9, 9, 9, 9,10, 9,11,11,11,11, + 11,11,11, 9, 9, 9, 9, 9, 9,10,10,10,10,11,11,11, + 11,11,11,11,10, 9,10,10, 9,10, 9, 9,10, 9,11,10, + 10,11,11,11,11, 9,10, 9, 9, 9, 9,10,10,10,10,11, + 11,11,11,11,11,10,10,10, 9, 9,10, 9,10, 9,10,10, + 10,10,11,11,11,11,11,11,11, 9, 9, 9, 9, 9,10,10, + 10, +}; + +static const static_codebook _44c3_s_p9_2 = { + 2, 289, + (char *)_vq_lengthlist__44c3_s_p9_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c3_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c3_s_short[] = { + 10, 9,13,11,14,10,12,13,13,14, 7, 2,12, 5,10, 5, + 7,10,12,14,12, 6, 9, 8, 7, 7, 9,11,13,16,10, 4, + 12, 5,10, 6, 8,12,14,16,12, 6, 8, 7, 6, 5, 7,11, + 12,16,10, 4, 8, 5, 6, 4, 6, 9,13,16,10, 6,10, 7, + 7, 6, 7, 9,13,15,12, 9,11, 9, 8, 6, 7,10,12,14, + 14,11,10, 9, 6, 5, 6, 9,11,13,15,13,11,10, 6, 5, + 6, 8, 9,11, +}; + +static const static_codebook _huff_book__44c3_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c3_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c4_s_long[] = { + 4, 7,11,11,11,11,10,11,12,11, 5, 2,11, 5, 6, 6, + 7, 9,11,12,11, 9, 6,10, 6, 7, 8, 9,10,11,11, 5, + 11, 7, 8, 8, 9,11,13,14,11, 6, 5, 8, 4, 5, 7, 8, + 10,11,10, 6, 7, 7, 5, 5, 6, 8, 9,11,10, 7, 8, 9, + 6, 6, 6, 7, 8, 9,11, 9, 9,11, 7, 7, 6, 6, 7, 9, + 12,12,10,13, 9, 8, 7, 7, 7, 8,11,13,11,14,11,10, + 9, 8, 7, 7, +}; + +static const static_codebook _huff_book__44c4_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c4_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c4_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c4_s_p1_0[] = { + 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0, + 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 6, 8, 7, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, 8, 0, 0, + 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 8, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c4_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c4_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c4_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c4_s_p2_0[] = { + 2, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, + 7, 7, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 7, + 7, 0, 0, 0, 7, 7, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 5, 6, 6, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 8, 7, 0, 0, 0, 7, 7, 0, 0, + 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5, + 7, 8, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, + 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, + 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7,10,10, 0, 0, 0, 9, 9, 0, 0, 0, 9, 9, 0, 0, 0, + 10,10, 0, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, 0, 9, + 9, 0, 0, 0, 9, 9, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c4_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c4_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c4_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c4_s_p3_0[] = { + 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 4, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c4_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44c4_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c4_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c4_s_p4_0[] = { + 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c4_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c4_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c4_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c4_s_p5_0[] = { + 2, 3, 3, 6, 6, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7, + 9, 9, 0, 4, 5, 6, 6, 7, 7, 9, 9, 0, 6, 6, 7, 7, + 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10, 9, 0, 0, 0, + 9, 8, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, + 0, 0,10,10, 9, 9,11,11, 0, 0, 0, 0, 0, 9, 9,10, + 10, +}; + +static const static_codebook _44c4_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44c4_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c4_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c4_s_p6_0[] = { + 2, 4, 4, 6, 6, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11, + 11, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,11, + 11,11, 0, 4, 4, 7, 6, 8, 8, 9, 9, 9, 9,10,10,11, + 11,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, + 9,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9, + 9,10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, + 9, 9, 9,10,10,11,11,11,12,12,12, 0, 0, 0, 0, 0, + 10,10,10,10,11,11,11,11,12,12,13,12, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,11,11,12,12,12,12, 0, 0, 0, + 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0, 0, + 0, 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,12,12,13,13,13,13, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,12,13,13, + 13, +}; + +static const static_codebook _44c4_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__44c4_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c4_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c4_s_p7_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11, + 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11, + 10,11,11,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9, + 11,10,10,11,10,10, 7,11,11,12,11,11,12,11,11, 6, + 9, 9,11,10,10,11,10,10, 6, 9, 9,11,10,10,11,10, + 10, +}; + +static const static_codebook _44c4_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__44c4_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c4_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c4_s_p7_1[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6, + 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, + 7, 8, 8, 8, 8, 8, 8,10,10,10, 8, 7, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 9, 8,10,10, + 10,10,10, 8, 8, 8, 8, 9, 9, +}; + +static const static_codebook _44c4_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c4_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c4_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c4_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c4_s_p8_0[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5, + 7, 7, 8, 8, 8, 8, 9,10,11,11, 7, 5, 5, 7, 7, 8, + 8, 9, 9,10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9, 9, 9,10,10,10,10,11,11, 0,13, + 13, 9, 9,10, 9,10,10,11,11,11,12, 0, 0, 0,10,10, + 10,10,10,10,11,11,12,12, 0, 0, 0,10,10,10,10,10, + 10,11,11,12,12, 0, 0, 0,14,14,11,11,11,11,12,12, + 12,12, 0, 0, 0,14,14,11,11,11,11,12,12,12,13, 0, + 0, 0, 0, 0,12,12,12,12,12,12,13,13, 0, 0, 0, 0, + 0,13,12,12,12,12,12,13,13, +}; + +static const static_codebook _44c4_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__44c4_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c4_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c4_s_p8_1[] = { + 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 5, 4, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c4_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__44c4_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c4_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c4_s_p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c4_s_p9_0[] = { + 1, 3, 3,12,12,12,12,12,12,12,12,12,12, 4, 7, 7, + 12,12,12,12,12,12,12,12,12,12, 3, 8, 8,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,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,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,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,12,12,12, + 12,12,12,12,12,12,12,12,12, +}; + +static const static_codebook _44c4_s_p9_0 = { + 2, 169, + (char *)_vq_lengthlist__44c4_s_p9_0, + 1, -513964032, 1628680192, 4, 0, + (long *)_vq_quantlist__44c4_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c4_s_p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44c4_s_p9_1[] = { + 1, 4, 4, 5, 5, 7, 7, 9, 8,10, 9,10,10,10,10, 6, + 5, 5, 7, 7, 9, 8,10, 9,11,10,12,12,13,13, 6, 5, + 5, 7, 7, 9, 9,10,10,11,11,12,12,12,13,19, 8, 8, + 8, 8, 9, 9,10,10,12,11,12,12,13,13,19, 8, 8, 8, + 8, 9, 9,11,11,12,12,13,13,13,13,19,12,12, 9, 9, + 11,11,11,11,12,11,13,12,13,13,18,12,12, 9, 9,11, + 10,11,11,12,12,12,13,13,14,19,18,18,11,11,11,11, + 12,12,13,12,13,13,14,14,16,18,18,11,11,11,10,12, + 11,13,13,13,13,13,14,17,18,18,14,15,11,12,12,13, + 13,13,13,14,14,14,18,18,18,15,15,12,10,13,10,13, + 13,13,13,13,14,18,17,18,17,18,12,13,12,13,13,13, + 14,14,16,14,18,17,18,18,17,13,12,13,10,12,12,14, + 14,14,14,17,18,18,18,18,14,15,12,12,13,12,14,14, + 15,15,18,18,18,17,18,15,14,12,11,12,12,14,14,14, + 15, +}; + +static const static_codebook _44c4_s_p9_1 = { + 2, 225, + (char *)_vq_lengthlist__44c4_s_p9_1, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__44c4_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c4_s_p9_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44c4_s_p9_2[] = { + 2, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9,11, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10,10,11, 6, 6, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,11, + 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9,10,10,10, + 10,10,10,10,12,11,11, 7, 7, 8, 8, 9, 9, 9, 9, 9, + 9,10,10,10,10,10,10,10,10,12,11,12, 8, 8, 8, 8, + 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,11,11, + 11, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,10,10,10, + 10,10,10,11,11,12, 9, 9, 9, 9, 9, 9,10, 9,10,10, + 10,10,10,10,10,10,10,10,11,11,11,11,11, 9, 9, 9, + 9,10,10,10,10,10,10,10,10,10,10,10,10,11,12,11, + 11,11, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10,11,11,11,11,11, 9, 9, 9, 9,10,10,10,10,10, + 10,10,10,10,10,10,10,11,11,11,12,12,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,11,12,11,12, + 11,11,11, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 10,11,12,11,11,11,11,11,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,11,11,11,12,11,11,11,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,12,11,11,12,11, + 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10, + 10,10,10,10,10,11,11,11,11,12,12,11,11,11,11,11, + 11,11,10,10,10,10,10,10,10,10,12,12,12,11,11,11, + 12,11,11,11,10,10,10,10,10,10,10,10,10,10,10,12, + 11,12,12,12,12,12,11,12,11,11,10,10,10,10,10,10, + 10,10,10,10,12,12,12,12,11,11,11,11,11,11,11,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44c4_s_p9_2 = { + 2, 441, + (char *)_vq_lengthlist__44c4_s_p9_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44c4_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c4_s_short[] = { + 4, 7,14,10,15,10,12,15,16,15, 4, 2,11, 5,10, 6, + 8,11,14,14,14,10, 7,11, 6, 8,10,11,13,15, 9, 4, + 11, 5, 9, 6, 9,12,14,15,14, 9, 6, 9, 4, 5, 7,10, + 12,13, 9, 5, 7, 6, 5, 5, 7,10,13,13,10, 8, 9, 8, + 7, 6, 8,10,14,14,13,11,10,10, 7, 7, 8,11,14,15, + 13,12, 9, 9, 6, 5, 7,10,14,17,15,13,11,10, 6, 6, + 7, 9,12,17, +}; + +static const static_codebook _huff_book__44c4_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c4_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c5_s_long[] = { + 3, 8, 9,13,10,12,12,12,12,12, 6, 4, 6, 8, 6, 8, + 10,10,11,12, 8, 5, 4,10, 4, 7, 8, 9,10,11,13, 8, + 10, 8, 9, 9,11,12,13,14,10, 6, 4, 9, 3, 5, 6, 8, + 10,11,11, 8, 6, 9, 5, 5, 6, 7, 9,11,12, 9, 7,11, + 6, 6, 6, 7, 8,10,12,11, 9,12, 7, 7, 6, 6, 7, 9, + 13,12,10,13, 9, 8, 7, 7, 7, 8,11,15,11,15,11,10, + 9, 8, 7, 7, +}; + +static const static_codebook _huff_book__44c5_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c5_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c5_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c5_s_p1_0[] = { + 2, 4, 4, 0, 0, 0, 0, 0, 0, 4, 7, 7, 0, 0, 0, 0, + 0, 0, 4, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 7, 7, 0, 0, 0, 0, + 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 9,10,11, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,10, 0, + 0, 0, 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 9,11,10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c5_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c5_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c5_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c5_s_p2_0[] = { + 2, 4, 4, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, + 8, 7, 0, 0, 0, 0, 0, 0, 0, 4, 6, 6, 0, 0, 0, 8, + 8, 0, 0, 0, 8, 7, 0, 0, 0,10,10, 0, 0, 0, 0, 0, + 0, 0, 4, 6, 6, 0, 0, 0, 8, 8, 0, 0, 0, 7, 8, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 8, 7, 0, 0, 0, 8, 8, 0, 0, + 0, 8, 8, 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 5, + 7, 8, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0,10, + 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0, 8, 8, + 0, 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 5, 8, 8, 0, + 0, 0, 8, 8, 0, 0, 0, 8, 8, 0, 0, 0,10,10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8,10,10, 0, 0, 0,10,10, 0, 0, 0, 9,10, 0, 0, 0, + 11,10, 0, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, 0,10, + 10, 0, 0, 0,10,10, 0, 0, 0,10,11, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c5_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c5_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c5_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c5_s_p3_0[] = { + 2, 4, 3, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 5, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 6, 6, 8, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c5_s_p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44c5_s_p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c5_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c5_s_p4_0[] = { + 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 0, 0, 0, 0, 0, 0, 0, 8, 7, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c5_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c5_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c5_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c5_s_p5_0[] = { + 2, 4, 3, 6, 6, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7, + 9, 9, 0, 4, 4, 6, 6, 7, 7, 9, 9, 0, 6, 6, 7, 7, + 7, 7, 9, 9, 0, 0, 0, 7, 6, 7, 7, 9, 9, 0, 0, 0, + 8, 8, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, + 0, 0, 9, 9, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10, + 10, +}; + +static const static_codebook _44c5_s_p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44c5_s_p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c5_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p6_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c5_s_p6_0[] = { + 2, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,10,11, + 11, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,11, + 12,12, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,11, + 11,12,12, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 7, 7, 9, 9,10,10,10,10, + 11,11,11,11,12,12, 0, 0, 0, 7, 7, 8, 9,10,10,10, + 10,11,11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10, + 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9, + 10,10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, + 9, 9,10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, + 10,10,10,10,11,11,11,12,12,12,13,13, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,11,11,12,12,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,11,11,12,12,12,13,13,13, 0, 0, + 0, 0, 0, 0, 0,11,11,11,11,12,12,12,12,13,13, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,13,12,13,13,13,13, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13, + 13, +}; + +static const static_codebook _44c5_s_p6_0 = { + 2, 289, + (char *)_vq_lengthlist__44c5_s_p6_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c5_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c5_s_p7_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11, + 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11, + 10,11,11,11, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9, + 11,10,10,11,10,10, 7,11,11,12,11,11,12,11,11, 6, + 9, 9,11,10,10,11,10,10, 6, 9, 9,11,10,10,11,10, + 10, +}; + +static const static_codebook _44c5_s_p7_0 = { + 4, 81, + (char *)_vq_lengthlist__44c5_s_p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c5_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c5_s_p7_1[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, + 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, + 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 9,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44c5_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c5_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c5_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c5_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c5_s_p8_0[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5, + 7, 7, 8, 8, 8, 9,10,10,10,10, 7, 5, 5, 7, 7, 8, + 8, 9, 9,10,10,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9, 9,10,10,10,10,10,11,11, 0,13, + 13, 9, 9, 9, 9,10,10,11,11,11,11, 0, 0, 0,10,10, + 10,10,10,10,11,11,11,11, 0, 0, 0,10,10,10,10,10, + 10,11,11,12,12, 0, 0, 0,14,14,11,11,11,11,12,12, + 12,12, 0, 0, 0,14,14,11,11,11,11,12,12,12,12, 0, + 0, 0, 0, 0,12,12,12,12,12,12,13,13, 0, 0, 0, 0, + 0,12,12,12,12,12,12,13,13, +}; + +static const static_codebook _44c5_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__44c5_s_p8_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c5_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p8_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c5_s_p8_1[] = { + 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 4, 5, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c5_s_p8_1 = { + 2, 25, + (char *)_vq_lengthlist__44c5_s_p8_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c5_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c5_s_p9_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44c5_s_p9_0[] = { + 1, 3, 3,13,13,13,13,13,13,13,13,13,13,13,13, 4, + 7, 7,13,13,13,13,13,13,13,13,13,13,13,13, 3, 8, + 6,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,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,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,12,12,12,12,12,12,12, + 12, +}; + +static const static_codebook _44c5_s_p9_0 = { + 2, 225, + (char *)_vq_lengthlist__44c5_s_p9_0, + 1, -512522752, 1628852224, 4, 0, + (long *)_vq_quantlist__44c5_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c5_s_p9_1[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c5_s_p9_1[] = { + 1, 4, 4, 5, 5, 7, 7, 9, 8,10, 9,10,10,11,10,11, + 11, 6, 5, 5, 7, 7, 8, 9,10,10,11,10,12,11,12,11, + 13,12, 6, 5, 5, 7, 7, 9, 9,10,10,11,11,12,12,13, + 12,13,13,18, 8, 8, 8, 8, 9, 9,10,11,11,11,12,11, + 13,11,13,12,18, 8, 8, 8, 8,10,10,11,11,12,12,13, + 13,13,13,13,14,18,12,12, 9, 9,11,11,11,11,12,12, + 13,12,13,12,13,13,20,13,12, 9, 9,11,11,11,11,12, + 12,13,13,13,14,14,13,20,18,19,11,12,11,11,12,12, + 13,13,13,13,13,13,14,13,18,19,19,12,11,11,11,12, + 12,13,12,13,13,13,14,14,13,18,17,19,14,15,12,12, + 12,13,13,13,14,14,14,14,14,14,19,19,19,16,15,12, + 11,13,12,14,14,14,13,13,14,14,14,19,18,19,18,19, + 13,13,13,13,14,14,14,13,14,14,14,14,18,17,19,19, + 19,13,13,13,11,13,11,13,14,14,14,14,14,19,17,17, + 18,18,16,16,13,13,13,13,14,13,15,15,14,14,19,19, + 17,17,18,16,16,13,11,14,10,13,12,14,14,14,14,19, + 19,19,19,19,18,17,13,14,13,11,14,13,14,14,15,15, + 19,19,19,17,19,18,18,14,13,12,11,14,11,15,15,15, + 15, +}; + +static const static_codebook _44c5_s_p9_1 = { + 2, 289, + (char *)_vq_lengthlist__44c5_s_p9_1, + 1, -520814592, 1620377600, 5, 0, + (long *)_vq_quantlist__44c5_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c5_s_p9_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44c5_s_p9_2[] = { + 3, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9,11, 5, 6, 7, 7, 8, 7, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, 5, 5, 7, 7, 7, + 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 9,10, 9,10,11,11,11, 7, 7, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9,10,10,10,10,10,10,11,11,11, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,11,11, + 11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,10,10,10,10,10, + 10,10,10,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,11,11,11,11,11, 9, 9, 9, + 9, 9, 9,10, 9,10,10,10,10,10,10,10,10,11,11,11, + 11,11, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10, + 10,10,11,11,11,11,11, 9, 9, 9, 9, 9, 9,10,10,10, + 10,10,10,10,10,10,10,11,11,11,11,11, 9, 9,10, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11, + 11,11,11, 9, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,11,11,11,11,11,11,11,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11, + 11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10, + 10,10,10,10,10,11,11,11,11,11,11,11,11,11,10,10, + 10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,11, + 11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10, + 10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44c5_s_p9_2 = { + 2, 441, + (char *)_vq_lengthlist__44c5_s_p9_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44c5_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c5_s_short[] = { + 5, 8,10,14,11,11,12,16,15,17, 5, 5, 7, 9, 7, 8, + 10,13,17,17, 7, 5, 5,10, 5, 7, 8,11,13,15,10, 8, + 10, 8, 8, 8,11,15,18,18, 8, 5, 5, 8, 3, 4, 6,10, + 14,16, 9, 7, 6, 7, 4, 3, 5, 9,14,18,10, 9, 8,10, + 6, 5, 6, 9,14,18,12,12,11,12, 8, 7, 8,11,14,18, + 14,13,12,10, 7, 5, 6, 9,14,18,14,14,13,10, 6, 5, + 6, 8,11,16, +}; + +static const static_codebook _huff_book__44c5_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c5_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c6_s_long[] = { + 3, 8,11,13,14,14,13,13,16,14, 6, 3, 4, 7, 9, 9, + 10,11,14,13,10, 4, 3, 5, 7, 7, 9,10,13,15,12, 7, + 4, 4, 6, 6, 8,10,13,15,12, 8, 6, 6, 6, 6, 8,10, + 13,14,11, 9, 7, 6, 6, 6, 7, 8,12,11,13,10, 9, 8, + 7, 6, 6, 7,11,11,13,11,10, 9, 9, 7, 7, 6,10,11, + 13,13,13,13,13,11, 9, 8,10,12,12,15,15,16,15,12, + 11,10,10,12, +}; + +static const static_codebook _huff_book__44c6_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c6_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c6_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c6_s_p1_0[] = { + 1, 5, 5, 0, 5, 5, 0, 5, 5, 5, 8, 7, 0, 9, 9, 0, + 9, 8, 5, 7, 8, 0, 9, 9, 0, 8, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 9, 8, 0, 8, 8, 0, 8, 8, 5, 8, 9, + 0, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 9, 9, 0, 8, 8, 0, 8, 8, 5, 9, 9, 0, 8, 8, 0, 8, + 8, +}; +static const static_codebook _44c6_s_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44c6_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c6_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c6_s_p2_0[] = { + 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, + 7, 7, 9, 9, 0, 0, 0, 9, 9, 5, 7, 7, 9, 9, 0, 8, + 8,10,10, 0, 8, 7,10, 9, 0,10,10,11,11, 0, 0, 0, + 11,11, 5, 7, 7, 9, 9, 0, 8, 8,10,10, 0, 7, 8, 9, + 10, 0,10,10,11,11, 0, 0, 0,11,11, 8, 9, 9,11,11, + 0,11,11,12,12, 0,11,10,12,12, 0,13,14,14,14, 0, + 0, 0,14,13, 8, 9, 9,11,11, 0,11,11,12,12, 0,10, + 11,12,12, 0,14,13,14,14, 0, 0, 0,13,14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 8, 7,11,10, 0, 7, 7,10,10, + 0, 7, 7,10,10, 0, 9, 9,11,10, 0, 0, 0,11,11, 5, + 7, 8,10,11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, + 9,10,11, 0, 0, 0,11,11, 8,10, 9,12,12, 0,10,10, + 12,12, 0,10,10,12,12, 0,12,12,13,13, 0, 0, 0,13, + 13, 8, 9,10,12,12, 0,10,10,11,12, 0,10,10,12,12, + 0,12,12,13,13, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 8, 8,11,11, 0, 7, 7,10,10, 0, 7, 7, + 10,10, 0, 9, 9,10,11, 0, 0, 0,11,10, 5, 8, 8,11, + 11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, 9,11,11, + 0, 0, 0,10,11, 8,10,10,12,12, 0,10,10,12,12, 0, + 10,10,12,12, 0,12,13,13,13, 0, 0, 0,14,13, 8,10, + 10,12,12, 0,10,10,12,12, 0,10,10,12,12, 0,13,12, + 13,13, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7,10,10,14,13, 0, 9, 9,13,12, 0, 9, 9,12,12, 0, + 10,10,12,12, 0, 0, 0,12,12, 7,10,10,13,14, 0, 9, + 9,12,13, 0, 9, 9,12,12, 0,10,10,12,12, 0, 0, 0, + 12,12, 9,11,11,14,13, 0,11,10,14,13, 0,11,11,13, + 13, 0,12,12,13,13, 0, 0, 0,13,13, 9,11,11,13,14, + 0,10,11,13,14, 0,11,11,13,13, 0,12,12,13,13, 0, + 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 11,11,14,14, 0,11,11,13,13, 0,11,10,13,13, 0,12, + 12,13,13, 0, 0, 0,13,13, 9,11,11,14,14, 0,11,11, + 13,13, 0,10,11,13,13, 0,12,12,14,13, 0, 0, 0,13, + 13, +}; + +static const static_codebook _44c6_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c6_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c6_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c6_s_p3_0[] = { + 2, 3, 4, 6, 6, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7, + 9,10, 0, 4, 4, 6, 6, 7, 7,10, 9, 0, 5, 5, 7, 7, + 8, 8,10,10, 0, 0, 0, 7, 6, 8, 8,10,10, 0, 0, 0, + 7, 7, 9, 9,11,11, 0, 0, 0, 7, 7, 9, 9,11,11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c6_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c6_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c6_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c6_s_p4_0[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9,10,10, + 10, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,10, + 11,11, 0, 4, 4, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10, + 10,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,11,11, 0, 0, 0, 7, 7, 9, 9,10,10,10,10, + 11,11,11,11,12,12, 0, 0, 0, 7, 7, 9, 9,10,10,10, + 10,11,11,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, + 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 8, 8, 9, + 9,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c6_s_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__44c6_s_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c6_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c6_s_p5_0[] = { + 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 6, 6, 9, 9,10,10, + 10, 9, 4, 6, 6, 9,10, 9,10, 9,10, 6, 9, 9,10,12, + 11,10,11,11, 7,10, 9,11,12,12,12,12,12, 7,10,10, + 11,12,12,12,12,12, 6,10,10,10,12,12,11,12,12, 7, + 9,10,11,12,12,12,12,12, 7,10, 9,12,12,12,12,12, + 12, +}; + +static const static_codebook _44c6_s_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__44c6_s_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c6_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c6_s_p5_1[] = { + 3, 5, 4, 6, 6, 7, 7, 8, 8, 8, 8,11, 4, 4, 6, 6, + 7, 7, 8, 8, 8, 8,11, 4, 4, 6, 6, 7, 7, 8, 8, 8, + 8,11, 6, 6, 6, 6, 8, 8, 8, 8, 9, 9,11,11,11, 6, + 6, 7, 8, 8, 8, 8, 9,11,11,11, 7, 7, 8, 8, 8, 8, + 8, 8,11,11,11, 7, 7, 8, 8, 8, 8, 8, 8,11,11,11, + 8, 8, 8, 8, 8, 8, 8, 8,11,11,11,10,10, 8, 8, 8, + 8, 8, 8,11,11,11,10,10, 8, 8, 8, 8, 8, 8,11,11, + 11,10,10, 7, 7, 8, 8, 8, 8, +}; + +static const static_codebook _44c6_s_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__44c6_s_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c6_s_p5_1, + 0 +}; + +static const long _vq_quantlist__44c6_s_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c6_s_p6_0[] = { + 1, 4, 4, 6, 6, 8, 8, 8, 8,10, 9,10,10, 6, 5, 5, + 7, 7, 9, 9, 9, 9,10,10,11,11, 6, 5, 5, 7, 7, 9, + 9,10, 9,11,10,11,11, 0, 6, 6, 7, 7, 9, 9,10,10, + 11,11,12,12, 0, 7, 7, 7, 7, 9, 9,10,10,11,11,12, + 12, 0,11,11, 8, 8,10,10,11,11,12,12,12,12, 0,11, + 12, 9, 8,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const static_codebook _44c6_s_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44c6_s_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c6_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c6_s_p6_1[] = { + 3, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c6_s_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44c6_s_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c6_s_p6_1, + 0 +}; + +static const long _vq_quantlist__44c6_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c6_s_p7_0[] = { + 1, 4, 4, 6, 6, 8, 8, 8, 8,10,10,11,10, 6, 5, 5, + 7, 7, 8, 8, 9, 9,10,10,12,11, 6, 5, 5, 7, 7, 8, + 8, 9, 9,10,10,12,11,21, 7, 7, 7, 7, 9, 9,10,10, + 11,11,12,12,21, 7, 7, 7, 7, 9, 9,10,10,11,11,12, + 12,21,12,12, 9, 9,10,10,11,11,11,11,12,12,21,12, + 12, 9, 9,10,10,11,11,12,12,12,12,21,21,21,11,11, + 10,10,11,12,12,12,13,13,21,21,21,11,11,10,10,12, + 12,12,12,13,13,21,21,21,15,15,11,11,12,12,13,13, + 13,13,21,21,21,15,16,11,11,12,12,13,13,14,14,21, + 21,21,21,20,13,13,13,13,13,13,14,14,20,20,20,20, + 20,13,13,13,13,13,13,14,14, +}; + +static const static_codebook _44c6_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c6_s_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__44c6_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c6_s_p7_1[] = { + 3, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 9, 5, 5, 6, 6, + 7, 7, 7, 7, 8, 7, 8, 5, 5, 6, 6, 7, 7, 7, 7, 7, + 7, 9, 6, 6, 7, 7, 7, 7, 8, 7, 7, 8, 9, 9, 9, 7, + 7, 7, 7, 7, 7, 7, 8, 9, 9, 9, 7, 7, 7, 7, 8, 8, + 8, 8, 9, 9, 9, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, + 8, 8, 8, 8, 7, 7, 8, 8, 9, 9, 9, 9, 8, 8, 8, 7, + 7, 8, 8, 9, 9, 9, 8, 8, 8, 8, 7, 7, 8, 8, 9, 9, + 9, 8, 8, 7, 7, 7, 7, 8, 8, +}; + +static const static_codebook _44c6_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c6_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c6_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c6_s_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44c6_s_p8_0[] = { + 1, 4, 4, 7, 7, 8, 8, 7, 7, 8, 7, 9, 8,10, 9, 6, + 5, 5, 8, 8, 9, 9, 8, 8, 9, 9,11,10,11,10, 6, 5, + 5, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11,11,18, 8, 8, + 9, 8,10,10, 9, 9,10,10,10,10,11,10,18, 8, 8, 9, + 9,10,10, 9, 9,10,10,11,11,12,12,18,12,13, 9,10, + 10,10, 9,10,10,10,11,11,12,11,18,13,13, 9, 9,10, + 10,10,10,10,10,11,11,12,12,18,18,18,10,10, 9, 9, + 11,11,11,11,11,12,12,12,18,18,18,10, 9,10, 9,11, + 10,11,11,11,11,13,12,18,18,18,14,13,10,10,11,11, + 12,12,12,12,12,12,18,18,18,14,13,10,10,11,10,12, + 12,12,12,12,12,18,18,18,18,18,12,12,11,11,12,12, + 13,13,13,14,18,18,18,18,18,12,12,11,11,12,11,13, + 13,14,13,18,18,18,18,18,16,16,11,12,12,13,13,13, + 14,13,18,18,18,18,18,16,15,12,11,12,11,13,11,15, + 14, +}; + +static const static_codebook _44c6_s_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__44c6_s_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__44c6_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44c6_s_p8_1[] = { + 3, 5, 5, 6, 6, 7, 7, 7, 7, 8, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8, + 8, 8, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9,10, + 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9,10,11,11, 8, 7, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11,11, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11, + 11, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,11,11,11,11,11, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,11,11,11, + 11,11, 9, 9, 9, 9, 9, 9,10, 9, 9,10, 9,10, 9, 9, + 10, 9,11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9,10,10, + 10,10, 9,10,10, 9,10,11,11,11,11,11, 9, 9, 9, 9, + 10,10,10, 9,10,10,10,10, 9,10,10, 9,11,11,11,11, + 11,11,11, 9, 9, 9, 9,10,10,10,10, 9,10,10,10,10, + 10,11,11,11,11,11,11,11,10, 9,10,10,10,10,10,10, + 10, 9,10, 9,10,10,11,11,11,11,11,11,11,10, 9,10, + 9,10,10, 9,10,10,10,10,10,10,10,11,11,11,11,11, + 11,11,10,10,10,10,10,10,10, 9,10,10,10,10,10, 9, + 11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10, + 10,10,10,10,10,11,11,11,11,11,11,11,11,11,10,10, + 10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,10,10,10,10,10,10,10,10,10, 9,10,10,11, + 11,11,11,11,11,11,11,11,10,10,10, 9,10,10,10,10, + 10,10,10,10,10,11,11,11,11,11,11,11,11,10,11, 9, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44c6_s_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__44c6_s_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44c6_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c6_s_p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c6_s_p9_0[] = { + 1, 3, 3,11,11,11,11,11,11,11,11,11,11, 4, 7, 7, + 11,11,11,11,11,11,11,11,11,11, 5, 8, 9,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44c6_s_p9_0 = { + 2, 169, + (char *)_vq_lengthlist__44c6_s_p9_0, + 1, -511845376, 1630791680, 4, 0, + (long *)_vq_quantlist__44c6_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c6_s_p9_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c6_s_p9_1[] = { + 1, 4, 4, 7, 7, 7, 7, 7, 6, 8, 8, 8, 8, 6, 6, 6, + 8, 8, 8, 8, 8, 7, 9, 8,10,10, 5, 6, 6, 8, 8, 9, + 9, 8, 8,10,10,10,10,16, 9, 9, 9, 9, 9, 9, 9, 8, + 10, 9,11,11,16, 8, 9, 9, 9, 9, 9, 9, 9,10,10,11, + 11,16,13,13, 9, 9,10, 9, 9,10,11,11,11,12,16,13, + 14, 9, 8,10, 8, 9, 9,10,10,12,11,16,14,16, 9, 9, + 9, 9,11,11,12,11,12,11,16,16,16, 9, 7, 9, 6,11, + 11,11,10,11,11,16,16,16,11,12, 9,10,11,11,12,11, + 13,13,16,16,16,12,11,10, 7,12,10,12,12,12,12,16, + 16,15,16,16,10,11,10,11,13,13,14,12,16,16,16,15, + 15,12,10,11,11,13,11,12,13, +}; + +static const static_codebook _44c6_s_p9_1 = { + 2, 169, + (char *)_vq_lengthlist__44c6_s_p9_1, + 1, -518889472, 1622704128, 4, 0, + (long *)_vq_quantlist__44c6_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c6_s_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__44c6_s_p9_2[] = { + 2, 4, 3, 4, 5, 5, 5, 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, +}; + +static const static_codebook _44c6_s_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__44c6_s_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__44c6_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c6_s_short[] = { + 3, 9,11,11,13,14,19,17,17,19, 5, 4, 5, 8,10,10, + 13,16,18,19, 7, 4, 4, 5, 8, 9,12,14,17,19, 8, 6, + 5, 5, 7, 7,10,13,16,18,10, 8, 7, 6, 5, 5, 8,11, + 17,19,11, 9, 7, 7, 5, 4, 5, 8,17,19,13,11, 8, 7, + 7, 5, 5, 7,16,18,14,13, 8, 6, 6, 5, 5, 7,16,18, + 18,16,10, 8, 8, 7, 7, 9,16,18,18,18,12,10,10, 9, + 9,10,17,18, +}; + +static const static_codebook _huff_book__44c6_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c6_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c7_s_long[] = { + 3, 8,11,13,15,14,14,13,15,14, 6, 4, 5, 7, 9,10, + 11,11,14,13,10, 4, 3, 5, 7, 8, 9,10,13,13,12, 7, + 4, 4, 5, 6, 8, 9,12,14,13, 9, 6, 5, 5, 6, 8, 9, + 12,14,12, 9, 7, 6, 5, 5, 6, 8,11,11,12,11, 9, 8, + 7, 6, 6, 7,10,11,13,11,10, 9, 8, 7, 6, 6, 9,11, + 13,13,12,12,12,10, 9, 8, 9,11,12,14,15,15,14,12, + 11,10,10,12, +}; + +static const static_codebook _huff_book__44c7_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c7_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c7_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c7_s_p1_0[] = { + 1, 5, 5, 0, 5, 5, 0, 5, 5, 5, 8, 7, 0, 9, 9, 0, + 9, 8, 5, 7, 8, 0, 9, 9, 0, 8, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 9, 9, 0, 8, 8, 0, 8, 8, 5, 8, 9, + 0, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 9, 9, 0, 8, 8, 0, 8, 8, 5, 8, 9, 0, 8, 8, 0, 8, + 8, +}; + +static const static_codebook _44c7_s_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44c7_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c7_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c7_s_p2_0[] = { + 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, + 7, 7, 9, 9, 0, 0, 0, 9, 9, 5, 7, 7, 9, 9, 0, 8, + 8,10,10, 0, 8, 7,10, 9, 0,10,10,11,11, 0, 0, 0, + 11,11, 5, 7, 7, 9, 9, 0, 8, 8,10,10, 0, 7, 8, 9, + 10, 0,10,10,11,11, 0, 0, 0,11,11, 8, 9, 9,11,10, + 0,11,11,12,12, 0,11,10,12,12, 0,13,14,14,14, 0, + 0, 0,14,13, 8, 9, 9,10,11, 0,11,11,12,12, 0,10, + 11,12,12, 0,13,13,14,14, 0, 0, 0,13,14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 8, 7,11,10, 0, 7, 7,10,10, + 0, 7, 7,10,10, 0, 9, 9,11,10, 0, 0, 0,11,11, 5, + 7, 8,10,11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, + 9,10,11, 0, 0, 0,11,11, 8,10, 9,12,12, 0,10,10, + 12,12, 0,10,10,12,12, 0,12,12,13,13, 0, 0, 0,13, + 13, 8, 9,10,12,12, 0,10,10,12,12, 0,10,10,11,12, + 0,12,12,13,13, 0, 0, 0,13,13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 8, 8,11,11, 0, 7, 7,10,10, 0, 7, 7, + 10,10, 0, 9, 9,10,11, 0, 0, 0,11,10, 5, 8, 8,10, + 11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, 9,11,10, + 0, 0, 0,10,11, 9,10,10,12,12, 0,10,10,12,12, 0, + 10,10,12,12, 0,12,13,13,13, 0, 0, 0,13,12, 9,10, + 10,12,12, 0,10,10,12,12, 0,10,10,12,12, 0,13,12, + 13,13, 0, 0, 0,12,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7,10,10,14,13, 0, 9, 9,12,12, 0, 9, 9,12,12, 0, + 10,10,12,12, 0, 0, 0,12,12, 7,10,10,13,14, 0, 9, + 9,12,13, 0, 9, 9,12,12, 0,10,10,12,12, 0, 0, 0, + 12,12, 9,11,11,14,13, 0,11,10,13,12, 0,11,11,13, + 13, 0,12,12,13,13, 0, 0, 0,13,13, 9,11,11,13,14, + 0,10,11,12,13, 0,11,11,13,13, 0,12,12,13,13, 0, + 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 11,11,14,14, 0,10,11,13,13, 0,11,10,13,13, 0,12, + 12,13,13, 0, 0, 0,13,12, 9,11,11,14,14, 0,11,10, + 13,13, 0,10,11,13,13, 0,12,12,14,13, 0, 0, 0,13, + 13, +}; + +static const static_codebook _44c7_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c7_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c7_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c7_s_p3_0[] = { + 2, 4, 4, 5, 5, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7, + 9, 9, 0, 4, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 6, 6, + 8, 8,10,10, 0, 0, 0, 6, 6, 8, 8,10,10, 0, 0, 0, + 7, 7, 9, 9,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c7_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c7_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c7_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c7_s_p4_0[] = { + 3, 4, 4, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11, + 12,12, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11, + 11,12,12, 0, 5, 5, 6, 6, 8, 8, 9, 9, 9, 9,10,10, + 11,12,12,12, 0, 0, 0, 6, 6, 8, 7, 9, 9, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10, + 11,11,12,12,13,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10, + 10,11,11,12,12,12,13, 0, 0, 0, 7, 7, 8, 8, 9, 9, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9, + 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c7_s_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__44c7_s_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c7_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c7_s_p5_0[] = { + 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 6, 7,10,10,10,10, + 10, 9, 4, 6, 6,10,10,10,10, 9,10, 5,10,10, 9,11, + 12,10,11,12, 7,10,10,11,12,12,12,12,12, 7,10,10, + 11,12,12,12,12,12, 6,10,10,10,12,12,11,12,12, 7, + 10,10,12,12,12,12,11,12, 7,10,10,11,12,12,12,12, + 12, +}; + +static const static_codebook _44c7_s_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__44c7_s_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c7_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c7_s_p5_1[] = { + 3, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8,11, 4, 4, 6, 6, + 7, 7, 8, 8, 9, 9,11, 4, 4, 6, 6, 7, 7, 8, 8, 9, + 9,12, 5, 5, 6, 6, 7, 7, 9, 9, 9, 9,12,12,12, 6, + 6, 7, 7, 9, 9, 9, 9,11,11,11, 7, 7, 7, 7, 8, 8, + 9, 9,11,11,11, 7, 7, 7, 7, 8, 8, 9, 9,11,11,11, + 7, 7, 8, 8, 8, 8, 9, 9,11,11,11,11,11, 8, 8, 8, + 8, 8, 9,11,11,11,11,11, 8, 8, 8, 8, 8, 8,11,11, + 11,11,11, 7, 7, 8, 8, 8, 8, +}; + +static const static_codebook _44c7_s_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__44c7_s_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c7_s_p5_1, + 0 +}; + +static const long _vq_quantlist__44c7_s_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c7_s_p6_0[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 7, 9, 8,10,10, 6, 5, 5, + 7, 7, 8, 8, 9, 9, 9,10,11,11, 7, 5, 5, 7, 7, 8, + 8, 9, 9,10,10,11,11, 0, 7, 7, 7, 7, 9, 8, 9, 9, + 10,10,11,11, 0, 8, 8, 7, 7, 8, 9, 9, 9,10,10,11, + 11, 0,11,11, 9, 9,10,10,11,10,11,11,12,12, 0,12, + 12, 9, 9,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const static_codebook _44c7_s_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44c7_s_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c7_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c7_s_p6_1[] = { + 3, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c7_s_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44c7_s_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c7_s_p6_1, + 0 +}; + +static const long _vq_quantlist__44c7_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c7_s_p7_0[] = { + 1, 4, 4, 6, 6, 7, 8, 9, 9,10,10,12,11, 6, 5, 5, + 7, 7, 8, 8, 9,10,11,11,12,12, 7, 5, 5, 7, 7, 8, + 8,10,10,11,11,12,12,20, 7, 7, 7, 7, 8, 9,10,10, + 11,11,12,13,20, 7, 7, 7, 7, 9, 9,10,10,11,12,13, + 13,20,11,11, 8, 8, 9, 9,11,11,12,12,13,13,20,11, + 11, 8, 8, 9, 9,11,11,12,12,13,13,20,20,20,10,10, + 10,10,12,12,13,13,13,13,20,20,20,10,10,10,10,12, + 12,13,13,13,14,20,20,20,14,14,11,11,12,12,13,13, + 14,14,20,20,20,14,14,11,11,12,12,13,13,14,14,20, + 20,20,20,19,13,13,13,13,14,14,15,14,19,19,19,19, + 19,13,13,13,13,14,14,15,15, +}; + +static const static_codebook _44c7_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c7_s_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__44c7_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c7_s_p7_1[] = { + 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 8, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, + 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 7, +}; + +static const static_codebook _44c7_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c7_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c7_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c7_s_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44c7_s_p8_0[] = { + 1, 4, 4, 7, 7, 8, 8, 8, 7, 9, 8, 9, 9,10,10, 6, + 5, 5, 7, 7, 9, 9, 8, 8,10, 9,11,10,12,11, 6, 5, + 5, 8, 7, 9, 9, 8, 8,10,10,11,11,12,11,19, 8, 8, + 8, 8,10,10, 9, 9,10,10,11,11,12,11,19, 8, 8, 8, + 8,10,10, 9, 9,10,10,11,11,12,12,19,12,12, 9, 9, + 10,10, 9,10,10,10,11,11,12,12,19,12,12, 9, 9,10, + 10,10,10,10,10,12,12,12,12,19,19,19, 9, 9, 9, 9, + 11,10,11,11,12,11,13,13,19,19,19, 9, 9, 9, 9,11, + 10,11,11,11,12,13,13,19,19,19,13,13,10,10,11,11, + 12,12,12,12,13,12,19,19,19,14,13,10,10,11,11,12, + 12,12,13,13,13,19,19,19,19,19,12,12,12,11,12,13, + 14,13,13,13,19,19,19,19,19,12,12,12,11,12,12,13, + 14,13,14,19,19,19,19,19,16,16,12,13,12,13,13,14, + 15,14,19,18,18,18,18,16,15,12,11,12,11,14,12,14, + 14, +}; + +static const static_codebook _44c7_s_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__44c7_s_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__44c7_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44c7_s_p8_1[] = { + 3, 5, 5, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, + 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, + 10, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,11,10,10,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9,10, 9, 9,10, 9, 9,10,11,10, + 11,10, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9,10, 9, 9, + 9, 9,11,10,11,10,10, 9, 9, 9, 9, 9, 9,10, 9, 9, + 10, 9, 9,10, 9, 9,10,11,10,10,11,10, 9, 9, 9, 9, + 9,10,10, 9,10,10,10,10, 9,10,10,10,10,10,10,11, + 11,11,10, 9, 9, 9,10,10,10,10,10,10,10,10,10,10, + 10,10,10,11,11,10,10,10,10,10,10,10,10,10,10,10, + 10, 9,10,10, 9,10,11,11,10,11,10,11,10, 9,10,10, + 9,10,10,10,10,10,10,10,10,10,10,11,11,11,11,10, + 11,11,10,10,10,10,10,10, 9,10, 9,10,10, 9,10, 9, + 10,10,10,11,10,11,10,11,11,10,10,10,10,10,10, 9, + 10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,11,10,11, + 11,10,10,10,10, 9, 9,10,10, 9, 9,10, 9,10,10,10, + 10,11,11,10,10,10,10,10,10,10, 9, 9,10,10,10, 9, + 9,10,10,10,10,10,11,10,11,10,10,10,10,10,10, 9, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44c7_s_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__44c7_s_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44c7_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c7_s_p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c7_s_p9_0[] = { + 1, 3, 3,11,11,11,11,11,11,11,11,11,11, 4, 6, 6, + 11,11,11,11,11,11,11,11,11,11, 4, 7, 7,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,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,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, +}; + +static const static_codebook _44c7_s_p9_0 = { + 2, 169, + (char *)_vq_lengthlist__44c7_s_p9_0, + 1, -511845376, 1630791680, 4, 0, + (long *)_vq_quantlist__44c7_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c7_s_p9_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c7_s_p9_1[] = { + 1, 4, 4, 7, 7, 7, 7, 7, 6, 8, 8, 8, 8, 6, 6, 6, + 8, 8, 9, 8, 8, 7, 9, 8,11,10, 5, 6, 6, 8, 8, 9, + 8, 8, 8,10, 9,11,11,16, 8, 8, 9, 8, 9, 9, 9, 8, + 10, 9,11,10,16, 8, 8, 9, 9,10,10, 9, 9,10,10,11, + 11,16,13,13, 9, 9,10,10, 9,10,11,11,12,11,16,13, + 13, 9, 8,10, 9,10,10,10,10,11,11,16,14,16, 8, 9, + 9, 9,11,10,11,11,12,11,16,16,16, 9, 7,10, 7,11, + 10,11,11,12,11,16,16,16,12,12, 9,10,11,11,12,11, + 12,12,16,16,16,12,10,10, 7,11, 8,12,11,12,12,16, + 16,15,16,16,11,12,10,10,12,11,12,12,16,16,16,15, + 15,11,11,10,10,12,12,12,12, +}; + +static const static_codebook _44c7_s_p9_1 = { + 2, 169, + (char *)_vq_lengthlist__44c7_s_p9_1, + 1, -518889472, 1622704128, 4, 0, + (long *)_vq_quantlist__44c7_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c7_s_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__44c7_s_p9_2[] = { + 2, 4, 3, 4, 5, 5, 5, 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, +}; + +static const static_codebook _44c7_s_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__44c7_s_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__44c7_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c7_s_short[] = { + 4,11,12,14,15,15,17,17,18,18, 5, 6, 6, 8, 9,10, + 13,17,18,19, 7, 5, 4, 6, 8, 9,11,15,19,19, 8, 6, + 5, 5, 6, 7,11,14,16,17, 9, 7, 7, 6, 7, 7,10,13, + 15,19,10, 8, 7, 6, 7, 6, 7, 9,14,16,12,10, 9, 7, + 7, 6, 4, 5,10,15,14,13,11, 7, 6, 6, 4, 2, 7,13, + 16,16,15, 9, 8, 8, 8, 6, 9,13,19,19,17,12,11,10, + 10, 9,11,14, +}; + +static const static_codebook _huff_book__44c7_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c7_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c8_s_long[] = { + 3, 8,12,13,14,14,14,13,14,14, 6, 4, 5, 8,10,10, + 11,11,14,13, 9, 5, 4, 5, 7, 8, 9,10,13,13,12, 7, + 5, 4, 5, 6, 8, 9,12,13,13, 9, 6, 5, 5, 5, 7, 9, + 11,14,12,10, 7, 6, 5, 4, 6, 7,10,11,12,11, 9, 8, + 7, 5, 5, 6,10,10,13,12,10, 9, 8, 6, 6, 5, 8,10, + 14,13,12,12,11,10, 9, 7, 8,10,12,13,14,14,13,12, + 11, 9, 9,10, +}; + +static const static_codebook _huff_book__44c8_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c8_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c8_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c8_s_p1_0[] = { + 1, 5, 5, 0, 5, 5, 0, 5, 5, 5, 7, 7, 0, 9, 8, 0, + 9, 8, 6, 7, 7, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 9, 8, 0, 8, 8, 0, 8, 8, 5, 8, 9, + 0, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 9, 8, 0, 8, 8, 0, 8, 8, 5, 8, 9, 0, 8, 8, 0, 8, + 8, +}; + +static const static_codebook _44c8_s_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44c8_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c8_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c8_s_p2_0[] = { + 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, + 7, 7, 9, 9, 0, 0, 0, 9, 9, 5, 7, 7, 9, 9, 0, 8, + 7,10, 9, 0, 8, 7,10, 9, 0,10,10,11,11, 0, 0, 0, + 11,11, 5, 7, 7, 9, 9, 0, 7, 8, 9,10, 0, 7, 8, 9, + 10, 0,10,10,11,11, 0, 0, 0,11,11, 8, 9, 9,11,10, + 0,11,10,12,11, 0,11,10,12,12, 0,13,13,14,14, 0, + 0, 0,14,13, 8, 9, 9,10,11, 0,10,11,12,12, 0,10, + 11,12,12, 0,13,13,14,14, 0, 0, 0,13,14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 8, 7,11,10, 0, 7, 7,10,10, + 0, 7, 7,10,10, 0, 9, 9,10,10, 0, 0, 0,11,10, 5, + 7, 8,10,11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, + 9,10,10, 0, 0, 0,10,10, 8,10, 9,12,12, 0,10,10, + 12,11, 0,10,10,12,12, 0,12,12,13,12, 0, 0, 0,13, + 12, 8, 9,10,12,12, 0,10,10,11,12, 0,10,10,11,12, + 0,12,12,13,13, 0, 0, 0,12,13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 8, 7,11,10, 0, 7, 7,10,10, 0, 7, 7, + 10,10, 0, 9, 9,10,11, 0, 0, 0,10,10, 6, 7, 8,10, + 11, 0, 7, 7,10,10, 0, 7, 7,10,10, 0, 9, 9,10,10, + 0, 0, 0,10,10, 9,10, 9,12,12, 0,10,10,12,12, 0, + 10,10,12,11, 0,12,12,13,13, 0, 0, 0,13,12, 8, 9, + 10,12,12, 0,10,10,12,12, 0,10,10,11,12, 0,12,12, + 13,13, 0, 0, 0,12,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7,10,10,13,13, 0, 9, 9,12,12, 0, 9, 9,12,12, 0, + 10,10,12,12, 0, 0, 0,12,12, 7,10,10,13,13, 0, 9, + 9,12,12, 0, 9, 9,12,12, 0,10,10,12,12, 0, 0, 0, + 12,12, 9,11,11,14,13, 0,10,10,13,12, 0,11,10,13, + 12, 0,12,12,13,12, 0, 0, 0,13,13, 9,11,11,13,14, + 0,10,11,12,13, 0,10,11,13,13, 0,12,12,12,13, 0, + 0, 0,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 11,11,14,14, 0,10,11,13,13, 0,11,10,13,13, 0,11, + 12,13,13, 0, 0, 0,13,12, 9,11,11,14,14, 0,11,10, + 13,13, 0,10,11,13,13, 0,12,12,13,13, 0, 0, 0,12, + 13, +}; + +static const static_codebook _44c8_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c8_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c8_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c8_s_p3_0[] = { + 2, 4, 4, 5, 5, 7, 7, 9, 9, 0, 4, 4, 6, 6, 7, 7, + 9, 9, 0, 4, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 6, 6, + 8, 8,10,10, 0, 0, 0, 6, 6, 8, 8,10,10, 0, 0, 0, + 7, 7, 9, 9,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c8_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c8_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c8_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c8_s_p4_0[] = { + 3, 4, 4, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 8,10,10,11,11, + 11,11, 0, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11, + 11,11,11, 0, 6, 5, 6, 6, 7, 7, 9, 9, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 6, 6, 7, 7, 9, 9, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10, + 11,11,11,12,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10, + 10,11,11,11,12,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9, + 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c8_s_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__44c8_s_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c8_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c8_s_p5_0[] = { + 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 7, 6,10,10,10,10, + 10,10, 4, 6, 6,10,10,10,10, 9,10, 5,10,10, 9,11, + 11,10,11,11, 7,10,10,11,12,12,12,12,12, 7,10,10, + 11,12,12,12,12,12, 6,10,10,10,12,12,10,12,12, 7, + 10,10,11,12,12,12,12,12, 7,10,10,11,12,12,12,12, + 12, +}; + +static const static_codebook _44c8_s_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__44c8_s_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c8_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c8_s_p5_1[] = { + 3, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8,11, 4, 5, 6, 6, + 7, 7, 8, 8, 8, 8,11, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 9,12, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,12,12,12, 6, + 6, 7, 7, 8, 8, 9, 9,11,11,11, 6, 6, 7, 7, 8, 8, + 8, 8,11,11,11, 6, 6, 7, 7, 8, 8, 8, 8,11,11,11, + 7, 7, 7, 8, 8, 8, 8, 8,11,11,11,11,11, 7, 7, 8, + 8, 8, 8,11,11,11,11,11, 7, 7, 7, 7, 8, 8,11,11, + 11,11,11, 7, 7, 7, 7, 8, 8, +}; + +static const static_codebook _44c8_s_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__44c8_s_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c8_s_p5_1, + 0 +}; + +static const long _vq_quantlist__44c8_s_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c8_s_p6_0[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5, + 7, 7, 8, 8, 9, 9,10,10,11,11, 6, 5, 5, 7, 7, 8, + 8, 9, 9,10,10,11,11, 0, 7, 7, 7, 7, 9, 9,10,10, + 10,10,11,11, 0, 7, 7, 7, 7, 9, 9,10,10,10,10,11, + 11, 0,11,11, 9, 9,10,10,11,11,11,11,12,12, 0,12, + 12, 9, 9,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const static_codebook _44c8_s_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44c8_s_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c8_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c8_s_p6_1[] = { + 3, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c8_s_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44c8_s_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c8_s_p6_1, + 0 +}; + +static const long _vq_quantlist__44c8_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c8_s_p7_0[] = { + 1, 4, 4, 6, 6, 8, 7, 9, 9,10,10,12,12, 6, 5, 5, + 7, 7, 8, 8,10,10,11,11,12,12, 7, 5, 5, 7, 7, 8, + 8,10,10,11,11,12,12,21, 7, 7, 7, 7, 8, 9,10,10, + 11,11,12,12,21, 7, 7, 7, 7, 9, 9,10,10,12,12,13, + 13,21,11,11, 8, 8, 9, 9,11,11,12,12,13,13,21,11, + 11, 8, 8, 9, 9,11,11,12,12,13,13,21,21,21,10,10, + 10,10,11,11,12,13,13,13,21,21,21,10,10,10,10,11, + 11,13,13,14,13,21,21,21,13,13,11,11,12,12,13,13, + 14,14,21,21,21,14,14,11,11,12,12,13,13,14,14,21, + 21,21,21,20,13,13,13,12,14,14,16,15,20,20,20,20, + 20,13,13,13,13,14,13,15,15, +}; + +static const static_codebook _44c8_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c8_s_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__44c8_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c8_s_p7_1[] = { + 4, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 6, 6, 6, 7, + 7, 7, 7, 7, 7, 7, 8, 6, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 8, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, + 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 7, +}; + +static const static_codebook _44c8_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c8_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c8_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c8_s_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44c8_s_p8_0[] = { + 1, 4, 4, 7, 6, 8, 8, 8, 7, 9, 8,10,10,11,10, 6, + 5, 5, 7, 7, 9, 9, 8, 8,10,10,11,11,12,11, 6, 5, + 5, 7, 7, 9, 9, 9, 9,10,10,11,11,12,12,20, 8, 8, + 8, 8, 9, 9, 9, 9,10,10,11,11,12,12,20, 8, 8, 8, + 8,10, 9, 9, 9,10,10,11,11,12,12,20,12,12, 9, 9, + 10,10,10,10,10,11,12,12,12,12,20,12,12, 9, 9,10, + 10,10,10,11,11,12,12,13,13,20,20,20, 9, 9, 9, 9, + 11,10,11,11,12,12,12,13,20,19,19, 9, 9, 9, 9,11, + 11,11,12,12,12,13,13,19,19,19,13,13,10,10,11,11, + 12,12,13,13,13,13,19,19,19,14,13,11,10,11,11,12, + 12,12,13,13,13,19,19,19,19,19,12,12,12,12,13,13, + 13,13,14,13,19,19,19,19,19,12,12,12,11,12,12,13, + 14,14,14,19,19,19,19,19,16,15,13,12,13,13,13,14, + 14,14,19,19,19,19,19,17,17,13,12,13,11,14,13,15, + 15, +}; + +static const static_codebook _44c8_s_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__44c8_s_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__44c8_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44c8_s_p8_1[] = { + 4, 5, 5, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, + 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, + 10, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, + 10,10, 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9, 9, 9, + 9, 9,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9,10,10,10,10, + 10,10,10, 9, 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, + 9,10,10,10,10,10,10,10, 9,10,10, 9,10,10,10,10, + 9,10, 9,10,10, 9,10,10,10,10,10,10,10, 9,10,10, + 10,10,10,10, 9, 9,10,10, 9,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, 9, 9, 9,10, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, + 10, 9,10, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10, 9, 9,10, 9, 9, 9,10,10,10,10,10,10, + 10,10,10,10,10, 9, 9, 9, 9, 9, 9,10, 9, 9,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 9,10, 9, + 9,10, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 10, 9, 9,10,10, 9,10, 9, 9, +}; + +static const static_codebook _44c8_s_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__44c8_s_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44c8_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c8_s_p9_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c8_s_p9_0[] = { + 1, 4, 3,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11, 4, 7, 7,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11, 4, 8,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,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,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,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,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _44c8_s_p9_0 = { + 2, 289, + (char *)_vq_lengthlist__44c8_s_p9_0, + 1, -509798400, 1631393792, 5, 0, + (long *)_vq_quantlist__44c8_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c8_s_p9_1[] = { + 9, + 8, + 10, + 7, + 11, + 6, + 12, + 5, + 13, + 4, + 14, + 3, + 15, + 2, + 16, + 1, + 17, + 0, + 18, +}; + +static const char _vq_lengthlist__44c8_s_p9_1[] = { + 1, 4, 4, 7, 6, 7, 7, 7, 7, 8, 8, 9, 9,10,10,10, + 10,11,11, 6, 6, 6, 8, 8, 9, 8, 8, 7,10, 8,11,10, + 12,11,12,12,13,13, 5, 5, 6, 8, 8, 9, 9, 8, 8,10, + 9,11,11,12,12,13,13,13,13,17, 8, 8, 9, 9, 9, 9, + 9, 9,10, 9,12,10,12,12,13,12,13,13,17, 9, 8, 9, + 9, 9, 9, 9, 9,10,10,12,12,12,12,13,13,13,13,17, + 13,13, 9, 9,10,10,10,10,11,11,12,11,13,12,13,13, + 14,15,17,13,13, 9, 8,10, 9,10,10,11,11,12,12,14, + 13,15,13,14,15,17,17,17, 9,10, 9,10,11,11,12,12, + 12,12,13,13,14,14,15,15,17,17,17, 9, 8, 9, 8,11, + 11,12,12,12,12,14,13,14,14,14,15,17,17,17,12,14, + 9,10,11,11,12,12,14,13,13,14,15,13,15,15,17,17, + 17,13,11,10, 8,11, 9,13,12,13,13,13,13,13,14,14, + 14,17,17,17,17,17,11,12,11,11,13,13,14,13,15,14, + 13,15,16,15,17,17,17,17,17,11,11,12, 8,13,12,14, + 13,17,14,15,14,15,14,17,17,17,17,17,15,15,12,12, + 12,12,13,14,14,14,15,14,17,14,17,17,17,17,17,16, + 17,12,12,13,12,13,13,14,14,14,14,14,14,17,17,17, + 17,17,17,17,14,14,13,12,13,13,15,15,14,13,15,17, + 17,17,17,17,17,17,17,13,14,13,13,13,13,14,15,15, + 15,14,15,17,17,17,17,17,17,17,16,15,13,14,13,13, + 14,14,15,14,14,16,17,17,17,17,17,17,17,16,16,13, + 14,13,13,14,14,15,14,15,14, +}; + +static const static_codebook _44c8_s_p9_1 = { + 2, 361, + (char *)_vq_lengthlist__44c8_s_p9_1, + 1, -518287360, 1622704128, 5, 0, + (long *)_vq_quantlist__44c8_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c8_s_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__44c8_s_p9_2[] = { + 2, 4, 4, 4, 5, 5, 5, 5, 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, +}; + +static const static_codebook _44c8_s_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__44c8_s_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__44c8_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c8_s_short[] = { + 4,11,13,14,15,15,18,17,19,17, 5, 6, 8, 9,10,10, + 12,15,19,19, 6, 6, 6, 6, 8, 8,11,14,18,19, 8, 6, + 5, 4, 6, 7,10,13,16,17, 9, 7, 6, 5, 6, 7, 9,12, + 15,19,10, 8, 7, 6, 6, 6, 7, 9,13,15,12,10, 9, 8, + 7, 6, 4, 5,10,15,13,13,11, 8, 6, 6, 4, 2, 7,12, + 17,15,16,10, 8, 8, 7, 6, 9,12,19,18,17,13,11,10, + 10, 9,11,14, +}; + +static const static_codebook _huff_book__44c8_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c8_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c9_s_long[] = { + 3, 8,12,14,15,15,15,13,15,15, 6, 5, 8,10,12,12, + 13,12,14,13,10, 6, 5, 6, 8, 9,11,11,13,13,13, 8, + 5, 4, 5, 6, 8,10,11,13,14,10, 7, 5, 4, 5, 7, 9, + 11,12,13,11, 8, 6, 5, 4, 5, 7, 9,11,12,11,10, 8, + 7, 5, 4, 5, 9,10,13,13,11,10, 8, 6, 5, 4, 7, 9, + 15,14,13,12,10, 9, 8, 7, 8, 9,12,12,14,13,12,11, + 10, 9, 8, 9, +}; + +static const static_codebook _huff_book__44c9_s_long = { + 2, 100, + (char *)_huff_lengthlist__44c9_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c9_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c9_s_p1_0[] = { + 1, 5, 5, 0, 5, 5, 0, 5, 5, 6, 8, 8, 0, 9, 8, 0, + 9, 8, 6, 8, 8, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 8, 8, 0, 7, 7, 0, 8, 8, 5, 8, 8, + 0, 7, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 9, 8, 0, 8, 8, 0, 7, 7, 5, 8, 9, 0, 8, 8, 0, 7, + 7, +}; + +static const static_codebook _44c9_s_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44c9_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c9_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c9_s_p2_0[] = { + 3, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, 5, 5, 8, 8, 0, + 7, 7, 9, 9, 0, 0, 0, 9, 9, 6, 7, 7, 9, 8, 0, 8, + 8, 9, 9, 0, 8, 7, 9, 9, 0, 9,10,10,10, 0, 0, 0, + 11,10, 6, 7, 7, 8, 9, 0, 8, 8, 9, 9, 0, 7, 8, 9, + 9, 0,10, 9,11,10, 0, 0, 0,10,10, 8, 9, 8,10,10, + 0,10,10,12,11, 0,10,10,11,11, 0,12,13,13,13, 0, + 0, 0,13,12, 8, 8, 9,10,10, 0,10,10,11,12, 0,10, + 10,11,11, 0,13,12,13,13, 0, 0, 0,13,13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 8, 7,10,10, 0, 7, 7,10, 9, + 0, 7, 7,10,10, 0, 9, 9,10,10, 0, 0, 0,10,10, 6, + 7, 8,10,10, 0, 7, 7, 9,10, 0, 7, 7,10,10, 0, 9, + 9,10,10, 0, 0, 0,10,10, 8, 9, 9,11,11, 0,10,10, + 11,11, 0,10,10,11,11, 0,12,12,12,12, 0, 0, 0,12, + 12, 8, 9,10,11,11, 0, 9,10,11,11, 0,10,10,11,11, + 0,12,12,12,12, 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 8, 7,10,10, 0, 7, 7,10,10, 0, 7, 7, + 10, 9, 0, 9, 9,10,10, 0, 0, 0,10,10, 6, 7, 8,10, + 10, 0, 7, 7,10,10, 0, 7, 7, 9,10, 0, 9, 9,10,10, + 0, 0, 0,10,10, 8,10, 9,12,11, 0,10,10,12,11, 0, + 10, 9,11,11, 0,11,12,12,12, 0, 0, 0,12,12, 8, 9, + 10,11,12, 0,10,10,11,11, 0, 9,10,11,11, 0,12,11, + 12,12, 0, 0, 0,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7,10, 9,12,12, 0, 9, 9,12,11, 0, 9, 9,11,11, 0, + 10,10,12,11, 0, 0, 0,11,12, 7, 9,10,12,12, 0, 9, + 9,11,12, 0, 9, 9,11,11, 0,10,10,11,12, 0, 0, 0, + 11,11, 9,11,10,13,12, 0,10,10,12,12, 0,10,10,12, + 12, 0,11,11,12,12, 0, 0, 0,13,12, 9,10,11,12,13, + 0,10,10,12,12, 0,10,10,12,12, 0,11,12,12,12, 0, + 0, 0,12,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 11,10,13,13, 0,10,10,12,12, 0,10,10,12,12, 0,11, + 12,12,12, 0, 0, 0,12,12, 9,10,11,13,13, 0,10,10, + 12,12, 0,10,10,12,12, 0,12,11,13,12, 0, 0, 0,12, + 12, +}; + +static const static_codebook _44c9_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c9_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c9_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c9_s_p3_0[] = { + 3, 4, 4, 5, 5, 6, 6, 8, 8, 0, 4, 4, 5, 5, 6, 7, + 8, 8, 0, 4, 4, 5, 5, 7, 7, 8, 8, 0, 5, 5, 6, 6, + 7, 7, 9, 9, 0, 0, 0, 6, 6, 7, 7, 9, 9, 0, 0, 0, + 7, 7, 8, 8, 9, 9, 0, 0, 0, 7, 7, 8, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c9_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c9_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c9_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c9_s_p4_0[] = { + 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10, + 10, 0, 5, 4, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9,10,10, + 11,11, 0, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10, + 10,11,11, 0, 6, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10, + 11,11,11,12, 0, 0, 0, 6, 6, 7, 7, 8, 8, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 7, 7, 7, 7, 9, 9, 9, 9, + 10,10,11,11,12,12, 0, 0, 0, 7, 7, 7, 8, 9, 9, 9, + 9,10,10,11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 8, 8, 9, + 9,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c9_s_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__44c9_s_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c9_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c9_s_p5_0[] = { + 1, 4, 4, 5, 7, 7, 6, 7, 7, 4, 7, 6, 9,10,10,10, + 10, 9, 4, 6, 7, 9,10,10,10, 9,10, 5, 9, 9, 9,11, + 11,10,11,11, 7,10, 9,11,12,11,12,12,12, 7, 9,10, + 11,11,12,12,12,12, 6,10,10,10,12,12,10,12,11, 7, + 10,10,11,12,12,11,12,12, 7,10,10,11,12,12,12,12, + 12, +}; + +static const static_codebook _44c9_s_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__44c9_s_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c9_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c9_s_p5_1[] = { + 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7,11, 5, 5, 6, 6, + 7, 7, 7, 7, 8, 8,11, 5, 5, 6, 6, 7, 7, 7, 7, 8, + 8,11, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8,11,11,11, 6, + 6, 7, 7, 7, 8, 8, 8,11,11,11, 6, 6, 7, 7, 7, 8, + 8, 8,11,11,11, 6, 6, 7, 7, 7, 7, 8, 8,11,11,11, + 7, 7, 7, 7, 7, 7, 8, 8,11,11,11,10,10, 7, 7, 7, + 7, 8, 8,11,11,11,11,11, 7, 7, 7, 7, 7, 7,11,11, + 11,11,11, 7, 7, 7, 7, 7, 7, +}; + +static const static_codebook _44c9_s_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__44c9_s_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c9_s_p5_1, + 0 +}; + +static const long _vq_quantlist__44c9_s_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c9_s_p6_0[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 5, 4, 4, + 6, 6, 8, 8, 9, 9, 9, 9,10,10, 6, 4, 4, 6, 6, 8, + 8, 9, 9, 9, 9,10,10, 0, 6, 6, 7, 7, 8, 8, 9, 9, + 10,10,11,11, 0, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11, + 11, 0,10,10, 8, 8, 9, 9,10,10,11,11,12,12, 0,11, + 11, 8, 8, 9, 9,10,10,11,11,12,12, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const static_codebook _44c9_s_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44c9_s_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c9_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c9_s_p6_1[] = { + 4, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44c9_s_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44c9_s_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c9_s_p6_1, + 0 +}; + +static const long _vq_quantlist__44c9_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c9_s_p7_0[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8,10,10,11,11, 6, 4, 4, + 6, 6, 8, 8, 9, 9,10,10,12,12, 6, 4, 5, 6, 6, 8, + 8, 9, 9,10,10,12,12,20, 6, 6, 6, 6, 8, 8, 9,10, + 11,11,12,12,20, 6, 6, 6, 6, 8, 8,10,10,11,11,12, + 12,20,10,10, 7, 7, 9, 9,10,10,11,11,12,12,20,11, + 11, 7, 7, 9, 9,10,10,11,11,12,12,20,20,20, 9, 9, + 9, 9,11,11,12,12,13,13,20,20,20, 9, 9, 9, 9,11, + 11,12,12,13,13,20,20,20,13,13,10,10,11,11,12,13, + 13,13,20,20,20,13,13,10,10,11,11,12,13,13,13,20, + 20,20,20,19,12,12,12,12,13,13,14,15,19,19,19,19, + 19,12,12,12,12,13,13,14,14, +}; + +static const static_codebook _44c9_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c9_s_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__44c9_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c9_s_p7_1[] = { + 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 8, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 6, + 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 7, +}; + +static const static_codebook _44c9_s_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44c9_s_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c9_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c9_s_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44c9_s_p8_0[] = { + 1, 4, 4, 7, 6, 8, 8, 8, 8, 9, 9,10,10,11,10, 6, + 5, 5, 7, 7, 9, 9, 8, 9,10,10,11,11,12,12, 6, 5, + 5, 7, 7, 9, 9, 9, 9,10,10,11,11,12,12,21, 7, 8, + 8, 8, 9, 9, 9, 9,10,10,11,11,12,12,21, 8, 8, 8, + 8, 9, 9, 9, 9,10,10,11,11,12,12,21,11,12, 9, 9, + 10,10,10,10,10,11,11,12,12,12,21,12,12, 9, 8,10, + 10,10,10,11,11,12,12,13,13,21,21,21, 9, 9, 9, 9, + 11,11,11,11,12,12,12,13,21,20,20, 9, 9, 9, 9,10, + 11,11,11,12,12,13,13,20,20,20,13,13,10,10,11,11, + 12,12,13,13,13,13,20,20,20,13,13,10,10,11,11,12, + 12,13,13,13,13,20,20,20,20,20,12,12,12,12,12,12, + 13,13,14,14,20,20,20,20,20,12,12,12,11,13,12,13, + 13,14,14,20,20,20,20,20,15,16,13,12,13,13,14,13, + 14,14,20,20,20,20,20,16,15,12,12,13,12,14,13,14, + 14, +}; + +static const static_codebook _44c9_s_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__44c9_s_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__44c9_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44c9_s_p8_1[] = { + 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 6, 6, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, + 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, + 10, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, + 10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9,10,10,10,10, + 10,10,10, 9, 9, 9, 9, 9, 9,10, 9, 9, 9, 9, 9, 9, + 9,10,10,10,10,10,10,10, 9, 9, 9,10,10,10,10,10, + 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10, 9, 9,10, + 9,10, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10, + 10,10,10,10, 9, 9,10,10, 9, 9, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, + 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10, 9, 9,10, 9, 9, 9, 9, 9,10,10,10,10,10,10, + 10,10,10,10,10, 9, 9,10,10, 9, 9,10, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10, 9, 9,10, 9, 9, 9, + 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10, 9, + 9, 9, 9,10, 9, 9, 9, 9, 9, +}; + +static const static_codebook _44c9_s_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__44c9_s_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44c9_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c9_s_p9_0[] = { + 9, + 8, + 10, + 7, + 11, + 6, + 12, + 5, + 13, + 4, + 14, + 3, + 15, + 2, + 16, + 1, + 17, + 0, + 18, +}; + +static const char _vq_lengthlist__44c9_s_p9_0[] = { + 1, 4, 3,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12, 4, 5, 6,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12, 4, 6, 6,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,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,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,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,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,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,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,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,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,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, +}; + +static const static_codebook _44c9_s_p9_0 = { + 2, 361, + (char *)_vq_lengthlist__44c9_s_p9_0, + 1, -508535424, 1631393792, 5, 0, + (long *)_vq_quantlist__44c9_s_p9_0, + 0 +}; + +static const long _vq_quantlist__44c9_s_p9_1[] = { + 9, + 8, + 10, + 7, + 11, + 6, + 12, + 5, + 13, + 4, + 14, + 3, + 15, + 2, + 16, + 1, + 17, + 0, + 18, +}; + +static const char _vq_lengthlist__44c9_s_p9_1[] = { + 1, 4, 4, 7, 7, 7, 7, 8, 7, 9, 8, 9, 9,10,10,11, + 11,11,11, 6, 5, 5, 8, 8, 9, 9, 9, 8,10, 9,11,10, + 12,12,13,12,13,13, 5, 5, 5, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12,13,12,13,13,17, 8, 8, 9, 9, 9, 9, + 9, 9,10,10,12,11,13,12,13,13,13,13,18, 8, 8, 9, + 9, 9, 9, 9, 9,11,11,12,12,13,13,13,13,13,13,17, + 13,12, 9, 9,10,10,10,10,11,11,12,12,12,13,13,13, + 14,14,18,13,12, 9, 9,10,10,10,10,11,11,12,12,13, + 13,13,14,14,14,17,18,18,10,10,10,10,11,11,11,12, + 12,12,14,13,14,13,13,14,18,18,18,10, 9,10, 9,11, + 11,12,12,12,12,13,13,15,14,14,14,18,18,16,13,14, + 10,11,11,11,12,13,13,13,13,14,13,13,14,14,18,18, + 18,14,12,11, 9,11,10,13,12,13,13,13,14,14,14,13, + 14,18,18,17,18,18,11,12,12,12,13,13,14,13,14,14, + 13,14,14,14,18,18,18,18,17,12,10,12, 9,13,11,13, + 14,14,14,14,14,15,14,18,18,17,17,18,14,15,12,13, + 13,13,14,13,14,14,15,14,15,14,18,17,18,18,18,15, + 15,12,10,14,10,14,14,13,13,14,14,14,14,18,16,18, + 18,18,18,17,14,14,13,14,14,13,13,14,14,14,15,15, + 18,18,18,18,17,17,17,14,14,14,12,14,13,14,14,15, + 14,15,14,18,18,18,18,18,18,18,17,16,13,13,13,14, + 14,14,14,15,16,15,18,18,18,18,18,18,18,17,17,13, + 13,13,13,14,13,14,15,15,15, +}; + +static const static_codebook _44c9_s_p9_1 = { + 2, 361, + (char *)_vq_lengthlist__44c9_s_p9_1, + 1, -518287360, 1622704128, 5, 0, + (long *)_vq_quantlist__44c9_s_p9_1, + 0 +}; + +static const long _vq_quantlist__44c9_s_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__44c9_s_p9_2[] = { + 2, 4, 4, 5, 5, 5, 5, 5, 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, +}; + +static const static_codebook _44c9_s_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__44c9_s_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__44c9_s_p9_2, + 0 +}; + +static const char _huff_lengthlist__44c9_s_short[] = { + 5,13,18,16,17,17,19,18,19,19, 5, 7,10,11,12,12, + 13,16,17,18, 6, 6, 7, 7, 9, 9,10,14,17,19, 8, 7, + 6, 5, 6, 7, 9,12,19,17, 8, 7, 7, 6, 5, 6, 8,11, + 15,19, 9, 8, 7, 6, 5, 5, 6, 8,13,15,11,10, 8, 8, + 7, 5, 4, 4,10,14,12,13,11, 9, 7, 6, 4, 2, 6,12, + 18,16,16,13, 8, 7, 7, 5, 8,13,16,17,18,15,11, 9, + 9, 8,10,13, +}; + +static const static_codebook _huff_book__44c9_s_short = { + 2, 100, + (char *)_huff_lengthlist__44c9_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c0_s_long[] = { + 5, 4, 8, 9, 8, 9,10,12,15, 4, 1, 5, 5, 6, 8,11, + 12,12, 8, 5, 8, 9, 9,11,13,12,12, 9, 5, 8, 5, 7, + 9,12,13,13, 8, 6, 8, 7, 7, 9,11,11,11, 9, 7, 9, + 7, 7, 7, 7,10,12,10,10,11, 9, 8, 7, 7, 9,11,11, + 12,13,12,11, 9, 8, 9,11,13,16,16,15,15,12,10,11, + 12, +}; + +static const static_codebook _huff_book__44c0_s_long = { + 2, 81, + (char *)_huff_lengthlist__44c0_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c0_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c0_s_p1_0[] = { + 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 9,10,11, 0, 0, 0, 0, 0, 0, 9,11,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 9,11, 9, 0, 0, 0, 0, 0, 0, 9,10,11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,11,10, 0, + 0, 0, 0, 0, 0, 9, 9,11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9,10, 0, 0, 0, 0, 0, 0, 9,10,11, + 0, 0, 0, 0, 0, 0, 9,11,10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c0_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c0_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c0_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c0_s_p2_0[] = { + 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 7, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c0_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c0_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c0_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c0_s_p3_0[] = { + 1, 3, 2, 8, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c0_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c0_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c0_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c0_s_p4_0[] = { + 1, 3, 3, 6, 6, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7, + 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0, 7, 7, + 7, 8, 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0, + 9, 9, 8, 8,10,10, 0, 0, 0, 8, 9, 8, 8,10,10, 0, + 0, 0,10,10, 9, 9,10,10, 0, 0, 0, 0, 0, 9, 9,10, + 10, +}; + +static const static_codebook _44c0_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c0_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c0_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p5_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c0_s_p5_0[] = { + 1, 4, 3, 6, 6, 8, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9, 9,10,10,10, + 11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10, + 10,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,11,11, 0, 0, 0, 8, 8, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9, 9, 9,10, + 10,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,11,12,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9, + 10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 10,10,11,11,11,11,11,12,12,12,13,13, 0, 0, 0, 0, + 0, 0, 0,11,10,11,11,11,11,12,12,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,12,11,12,12,12,12,13,13, 0, 0, + 0, 0, 0, 0, 0,11,11,11,12,12,12,12,13,13,13, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,12,13,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14, + 14, +}; + +static const static_codebook _44c0_s_p5_0 = { + 2, 289, + (char *)_vq_lengthlist__44c0_s_p5_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c0_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c0_s_p6_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,10, + 9, 9, 4, 6, 7,10, 9, 9,11, 9, 9, 7,10,10,11,11, + 11,12,10,11, 6, 9, 9,11,10,11,11,10,10, 6, 9, 9, + 11,10,11,11,10,10, 7,11,10,12,11,11,11,11,11, 7, + 9, 9,10,10,10,11,11,10, 6, 9, 9,11,10,10,11,10, + 10, +}; + +static const static_codebook _44c0_s_p6_0 = { + 4, 81, + (char *)_vq_lengthlist__44c0_s_p6_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c0_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p6_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c0_s_p6_1[] = { + 2, 3, 3, 6, 6, 7, 7, 7, 7, 7, 8,10,10,10, 6, 6, + 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8, + 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 7, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44c0_s_p6_1 = { + 2, 121, + (char *)_vq_lengthlist__44c0_s_p6_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c0_s_p6_1, + 0 +}; + +static const long _vq_quantlist__44c0_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c0_s_p7_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 5, 5, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 6, 7, 7, 8, + 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13, + 13, 9, 9, 9, 9,10,10,11,11,11,12, 0, 0, 0,10,10, + 10,10,11,11,11,11,12,12, 0, 0, 0,10,10, 9, 9,11, + 11,11,12,12,12, 0, 0, 0,13,13,10,10,11,11,12,12, + 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0, + 0, 0, 0, 0,11,11,11,11,13,12,13,13, 0, 0, 0, 0, + 0,12,12,11,11,12,12,13,13, +}; + +static const static_codebook _44c0_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c0_s_p7_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c0_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c0_s_p7_1[] = { + 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6, + 6, 6, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c0_s_p7_1 = { + 2, 25, + (char *)_vq_lengthlist__44c0_s_p7_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c0_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c0_s_p8_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c0_s_p8_0[] = { + 1, 5, 5,10,10, 6, 9, 8,10,10, 6,10, 9,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 8,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,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,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,10,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,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,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,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,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,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,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,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11, +}; + +static const static_codebook _44c0_s_p8_0 = { + 4, 625, + (char *)_vq_lengthlist__44c0_s_p8_0, + 1, -518283264, 1627103232, 3, 0, + (long *)_vq_quantlist__44c0_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c0_s_p8_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c0_s_p8_1[] = { + 1, 4, 4, 6, 6, 7, 7, 9, 9,11,12,13,12, 6, 5, 5, + 7, 7, 8, 8,10, 9,12,12,12,12, 6, 5, 5, 7, 7, 8, + 8,10, 9,12,11,11,13,16, 7, 7, 8, 8, 9, 9,10,10, + 12,12,13,12,16, 7, 7, 8, 7, 9, 9,10,10,11,12,12, + 13,16,10,10, 8, 8,10,10,11,12,12,12,13,13,16,11, + 10, 8, 7,11,10,11,11,12,11,13,13,16,16,16,10,10, + 10,10,11,11,13,12,13,13,16,16,16,11, 9,11, 9,15, + 13,12,13,13,13,16,16,16,15,13,11,11,12,13,12,12, + 14,13,16,16,16,14,13,11,11,13,12,14,13,13,13,16, + 16,16,16,16,13,13,13,12,14,13,14,14,16,16,16,16, + 16,13,13,12,12,14,14,15,13, +}; + +static const static_codebook _44c0_s_p8_1 = { + 2, 169, + (char *)_vq_lengthlist__44c0_s_p8_1, + 1, -522616832, 1620115456, 4, 0, + (long *)_vq_quantlist__44c0_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c0_s_p8_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c0_s_p8_2[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8,10,10,10, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9,10,10,10, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, + 9,10, 9, 9,10,10,10, 7, 7, 8, 8, 9, 8, 9, 9, 9, + 9,10, 9, 9,10,10,10,10, 8, 8, 8, 8, 9, 8, 9, 9, + 9, 9, 9,10, 9,10,10,10,10, 7, 7, 8, 8, 9, 9, 9, + 9, 9, 9,10, 9,10,10,10,10,10, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 9,11,10,10,10,10, 8, 8, 9, + 9, 9, 9, 9,10, 9, 9, 9,10,10,10,10,11,11, 9, 9, + 9, 9, 9, 9, 9, 9,10, 9, 9,10,11,10,10,11,11, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,11,10,11,11, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,10,10,11, + 11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, + 11,11,11,11, 9,10, 9,10, 9, 9, 9, 9,10, 9,10,11, + 10,11,10,10,10,10,10, 9, 9, 9,10, 9, 9, 9,10,11, + 11,10,11,11,10,11,10,10,10, 9, 9, 9, 9,10, 9, 9, + 10,11,10,11,11,11,11,10,11,10,10, 9,10, 9, 9, 9, + 10, +}; + +static const static_codebook _44c0_s_p8_2 = { + 2, 289, + (char *)_vq_lengthlist__44c0_s_p8_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c0_s_p8_2, + 0 +}; + +static const char _huff_lengthlist__44c0_s_short[] = { + 9, 8,12,11,12,13,14,14,16, 6, 1, 5, 6, 6, 9,12, + 14,17, 9, 4, 5, 9, 7, 9,13,15,16, 8, 5, 8, 6, 8, + 10,13,17,17, 9, 6, 7, 7, 8, 9,13,15,17,11, 8, 9, + 9, 9,10,12,16,16,13, 7, 8, 7, 7, 9,12,14,15,13, + 6, 7, 5, 5, 7,10,13,13,14, 7, 8, 5, 6, 7, 9,10, + 12, +}; + +static const static_codebook _huff_book__44c0_s_short = { + 2, 81, + (char *)_huff_lengthlist__44c0_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c0_sm_long[] = { + 5, 4, 9,10, 9,10,11,12,13, 4, 1, 5, 7, 7, 9,11, + 12,14, 8, 5, 7, 9, 8,10,13,13,13,10, 7, 9, 4, 6, + 7,10,12,14, 9, 6, 7, 6, 6, 7,10,12,12, 9, 8, 9, + 7, 6, 7, 8,11,12,11,11,11, 9, 8, 7, 8,10,12,12, + 13,14,12,11, 9, 9, 9,12,12,17,17,15,16,12,10,11, + 13, +}; + +static const static_codebook _huff_book__44c0_sm_long = { + 2, 81, + (char *)_huff_lengthlist__44c0_sm_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c0_sm_p1_0[] = { + 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 7, 0, 0, 0, 0, + 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 9,10,10, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 8, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 9, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 9,10,10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c0_sm_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c0_sm_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c0_sm_p1_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c0_sm_p2_0[] = { + 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c0_sm_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c0_sm_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c0_sm_p2_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c0_sm_p3_0[] = { + 1, 3, 3, 7, 7, 0, 0, 0, 0, 0, 5, 4, 7, 7, 0, 0, + 0, 0, 0, 5, 5, 7, 7, 0, 0, 0, 0, 0, 6, 7, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, + 9,10, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, + 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c0_sm_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c0_sm_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c0_sm_p3_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c0_sm_p4_0[] = { + 1, 4, 3, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 8, 7, + 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8, + 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0, + 9, 9, 9, 9,11,11, 0, 0, 0, 9, 9, 9, 9,11,11, 0, + 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0, 9, 9,11, + 11, +}; + +static const static_codebook _44c0_sm_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c0_sm_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c0_sm_p4_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p5_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c0_sm_p5_0[] = { + 1, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,11, + 11,11, 0, 5, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10, + 11,11,11, 0, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10, + 11,11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10, + 10,11,11,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,12,13, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 10,10,11,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,11,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 10,10,10,10,11,11,12,12,12,13,13,13, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,12,12,12,13,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14, 0, 0, + 0, 0, 0, 0, 0,11,11,12,11,12,12,13,13,13,13, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14, + 14, +}; + +static const static_codebook _44c0_sm_p5_0 = { + 2, 289, + (char *)_vq_lengthlist__44c0_sm_p5_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c0_sm_p5_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c0_sm_p6_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11, + 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,10,11, + 11,11,10,10, 6, 9, 9,11,11,10,11,10,10, 6, 9, 9, + 11,10,11,11,10,10, 7,11,10,11,11,11,11,11,11, 6, + 9, 9,11,10,10,11,11,10, 6, 9, 9,11,10,10,11,10, + 11, +}; + +static const static_codebook _44c0_sm_p6_0 = { + 4, 81, + (char *)_vq_lengthlist__44c0_sm_p6_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c0_sm_p6_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p6_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c0_sm_p6_1[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 7, 8, 9, 5, 5, 6, 6, + 7, 7, 8, 8, 8, 8, 9, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 8,10, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, + 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44c0_sm_p6_1 = { + 2, 121, + (char *)_vq_lengthlist__44c0_sm_p6_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c0_sm_p6_1, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c0_sm_p7_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 5, 5, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 6, 5, 7, 7, 8, + 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13, + 13, 9, 9, 9, 9,10,10,11,11,11,12, 0, 0, 0, 9,10, + 10,10,11,11,12,11,12,12, 0, 0, 0,10,10, 9, 9,11, + 11,12,12,12,12, 0, 0, 0,13,13,10,10,11,11,12,12, + 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0, + 0, 0, 0, 0,11,12,11,11,13,12,13,13, 0, 0, 0, 0, + 0,12,12,11,11,13,12,14,14, +}; + +static const static_codebook _44c0_sm_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c0_sm_p7_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c0_sm_p7_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c0_sm_p7_1[] = { + 2, 4, 4, 4, 4, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, + 6, 6, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c0_sm_p7_1 = { + 2, 25, + (char *)_vq_lengthlist__44c0_sm_p7_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c0_sm_p7_1, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p8_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c0_sm_p8_0[] = { + 1, 3, 3,11,11,11,11,11,11, 3, 7, 6,11,11,11,11, + 11,11, 4, 8, 7,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,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, +}; + +static const static_codebook _44c0_sm_p8_0 = { + 2, 81, + (char *)_vq_lengthlist__44c0_sm_p8_0, + 1, -516186112, 1627103232, 4, 0, + (long *)_vq_quantlist__44c0_sm_p8_0, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p8_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c0_sm_p8_1[] = { + 1, 4, 4, 6, 6, 7, 7, 9, 9,10,11,12,12, 6, 5, 5, + 7, 7, 8, 8,10,10,12,11,12,12, 6, 5, 5, 7, 7, 8, + 8,10,10,12,11,12,12,17, 7, 7, 8, 8, 9, 9,10,10, + 12,12,13,13,18, 7, 7, 8, 7, 9, 9,10,10,12,12,12, + 13,19,10,10, 8, 8,10,10,11,11,12,12,13,14,19,11, + 10, 8, 7,10,10,11,11,12,12,13,12,19,19,19,10,10, + 10,10,11,11,12,12,13,13,19,19,19,11, 9,11, 9,14, + 12,13,12,13,13,19,20,18,13,14,11,11,12,12,13,13, + 14,13,20,20,20,15,13,11,10,13,11,13,13,14,13,20, + 20,20,20,20,13,14,12,12,13,13,13,13,20,20,20,20, + 20,13,13,12,12,16,13,15,13, +}; + +static const static_codebook _44c0_sm_p8_1 = { + 2, 169, + (char *)_vq_lengthlist__44c0_sm_p8_1, + 1, -522616832, 1620115456, 4, 0, + (long *)_vq_quantlist__44c0_sm_p8_1, + 0 +}; + +static const long _vq_quantlist__44c0_sm_p8_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c0_sm_p8_2[] = { + 2, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8,10, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9,10, 6, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 9, 8, 9, 9, 9, + 9,10, 9, 9,10,10,10,11, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9,10, 9,10,10,10,10, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9,10,10,11,10,10, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10,10,10,11,11, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,11,11,11,11,11, 9, 9, + 9, 9, 9, 9, 9, 9,10, 9,10, 9,11,11,10,11,11, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,11,10,11,11, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11,10,11,11, + 11,11,11, 9, 9,10, 9, 9, 9, 9, 9, 9, 9,10,11,10, + 11,11,11,11,10,10,10,10, 9, 9, 9, 9, 9, 9,10,11, + 11,11,11,11,11, 9,10, 9, 9, 9, 9, 9, 9, 9, 9,11, + 11,10,11,11,11,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, + 10,11,10,11,11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, + 9, +}; + +static const static_codebook _44c0_sm_p8_2 = { + 2, 289, + (char *)_vq_lengthlist__44c0_sm_p8_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c0_sm_p8_2, + 0 +}; + +static const char _huff_lengthlist__44c0_sm_short[] = { + 6, 6,12,13,13,14,16,17,17, 4, 2, 5, 8, 7, 9,12, + 15,15, 9, 4, 5, 9, 7, 9,12,16,18,11, 6, 7, 4, 6, + 8,11,14,18,10, 5, 6, 5, 5, 7,10,14,17,10, 5, 7, + 7, 6, 7,10,13,16,11, 5, 7, 7, 7, 8,10,12,15,13, + 6, 7, 5, 5, 7, 9,12,13,16, 8, 9, 6, 6, 7, 9,10, + 12, +}; + +static const static_codebook _huff_book__44c0_sm_short = { + 2, 81, + (char *)_huff_lengthlist__44c0_sm_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c1_s_long[] = { + 5, 5, 9,10, 9, 9,10,11,12, 5, 1, 5, 6, 6, 7,10, + 12,14, 9, 5, 6, 8, 8,10,12,14,14,10, 5, 8, 5, 6, + 8,11,13,14, 9, 5, 7, 6, 6, 8,10,12,11, 9, 7, 9, + 7, 6, 6, 7,10,10,10, 9,12, 9, 8, 7, 7,10,12,11, + 11,13,12,10, 9, 8, 9,11,11,14,15,15,13,11, 9, 9, + 11, +}; + +static const static_codebook _huff_book__44c1_s_long = { + 2, 81, + (char *)_huff_lengthlist__44c1_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c1_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c1_s_p1_0[] = { + 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 7, 6, 0, 0, 0, 0, + 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 7, 7, 0, 0, 0, 0, + 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, + 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, 8, 0, 0, + 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, + 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, 8,10, 9, 0, + 0, 0, 0, 0, 0, 8, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, + 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c1_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c1_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c1_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c1_s_p2_0[] = { + 2, 3, 4, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 6, 8, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c1_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c1_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c1_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c1_s_p3_0[] = { + 1, 3, 2, 7, 7, 0, 0, 0, 0, 0,13,13, 6, 6, 0, 0, + 0, 0, 0,12, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0,11,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c1_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c1_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c1_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c1_s_p4_0[] = { + 1, 3, 3, 6, 5, 6, 6, 8, 8, 0, 0, 0, 7, 7, 7, 7, + 9, 9, 0, 0, 0, 7, 7, 7, 7, 9, 9, 0, 0, 0, 7, 7, + 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, 0, 0, + 9, 9, 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, + 0, 0,10,10, 9, 9,11,11, 0, 0, 0, 0, 0, 9, 9,11, + 11, +}; + +static const static_codebook _44c1_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c1_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c1_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p5_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c1_s_p5_0[] = { + 1, 4, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,10, + 11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10, + 10,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,11, 0, 0, 0, 8, 8, 9, 9, 9,10,10,10, + 10,10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10, 9,10, + 10,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9, + 10,10,10,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 10,10,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,13, 0, 0, + 0, 0, 0, 0, 0,11,11,11,11,12,12,13,13,13,13, 0, + 0, 0, 0, 0, 0, 0,12,12,12,12,12,12,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14, + 14, +}; + +static const static_codebook _44c1_s_p5_0 = { + 2, 289, + (char *)_vq_lengthlist__44c1_s_p5_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c1_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c1_s_p6_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11, + 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 6,10,10,11,11, + 11,11,10,10, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9, + 11,10,11,11,10,10, 7,11,10,11,11,11,12,11,11, 7, + 9, 9,11,10,10,11,11,10, 6, 9, 9,10,10,10,12,10, + 11, +}; + +static const static_codebook _44c1_s_p6_0 = { + 4, 81, + (char *)_vq_lengthlist__44c1_s_p6_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c1_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p6_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c1_s_p6_1[] = { + 2, 3, 3, 6, 6, 7, 7, 7, 7, 8, 8,10,10,10, 6, 6, + 7, 7, 8, 8, 8, 8,10,10,10, 6, 6, 7, 7, 8, 8, 8, + 8,10,10,10, 7, 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 8, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44c1_s_p6_1 = { + 2, 121, + (char *)_vq_lengthlist__44c1_s_p6_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c1_s_p6_1, + 0 +}; + +static const long _vq_quantlist__44c1_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c1_s_p7_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 9, 7, 5, 6, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 5, 7, 7, 8, + 8, 8, 8, 9, 9,10,10, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,10, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9, 9,10,10,10,11,11,11,11, 0,13, + 13, 9, 9, 9, 9,10,10,11,11,11,11, 0, 0, 0,10,10, + 10,10,11,11,12,11,12,12, 0, 0, 0,10,10,10, 9,11, + 11,12,11,13,12, 0, 0, 0,13,13,10,10,11,11,12,12, + 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0, + 0, 0, 0, 0,11,12,11,11,12,12,14,13, 0, 0, 0, 0, + 0,12,11,11,11,13,10,14,13, +}; + +static const static_codebook _44c1_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c1_s_p7_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c1_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c1_s_p7_1[] = { + 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6, + 6, 6, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c1_s_p7_1 = { + 2, 25, + (char *)_vq_lengthlist__44c1_s_p7_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c1_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44c1_s_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c1_s_p8_0[] = { + 1, 4, 3,10,10,10,10,10,10,10,10,10,10, 4, 8, 6, + 10,10,10,10,10,10,10,10,10,10, 4, 8, 7,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44c1_s_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__44c1_s_p8_0, + 1, -514541568, 1627103232, 4, 0, + (long *)_vq_quantlist__44c1_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44c1_s_p8_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c1_s_p8_1[] = { + 1, 4, 4, 6, 5, 7, 7, 9, 9,10,10,12,12, 6, 5, 5, + 7, 7, 8, 8,10,10,12,11,12,12, 6, 5, 5, 7, 7, 8, + 8,10,10,11,11,12,12,15, 7, 7, 8, 8, 9, 9,11,11, + 12,12,13,12,15, 8, 8, 8, 7, 9, 9,10,10,12,12,13, + 13,16,11,10, 8, 8,10,10,11,11,12,12,13,13,16,11, + 11, 9, 8,11,10,11,11,12,12,13,12,16,16,16,10,11, + 10,11,12,12,12,12,13,13,16,16,16,11, 9,11, 9,14, + 12,12,12,13,13,16,16,16,12,14,11,12,12,12,13,13, + 14,13,16,16,16,15,13,12,10,13,10,13,14,13,13,16, + 16,16,16,16,13,14,12,13,13,12,13,13,16,16,16,16, + 16,13,12,12,11,14,12,15,13, +}; + +static const static_codebook _44c1_s_p8_1 = { + 2, 169, + (char *)_vq_lengthlist__44c1_s_p8_1, + 1, -522616832, 1620115456, 4, 0, + (long *)_vq_quantlist__44c1_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44c1_s_p8_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c1_s_p8_2[] = { + 2, 4, 4, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8,10,10,10, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9,10,10,10, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, + 9,10, 9, 9,10,10,10, 7, 7, 8, 8, 9, 8, 9, 9, 9, + 9,10, 9, 9,10,10,11,11, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9,10, 9, 9,10,10,10,10, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9,10,10,11,11,11, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10,10,11,11,11, 8, 8, 9, + 9, 9, 9,10, 9, 9, 9, 9, 9,11,11,11,11,11, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,10,11,11, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,11,10,11,11, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,10,10,11,11, + 11,11,11, 9, 9, 9,10, 9, 9, 9, 9, 9, 9,10,11,11, + 11,11,11,11,10,10,10,10, 9, 9, 9, 9, 9, 9,10,11, + 11,11,11,11,11, 9,10, 9, 9, 9, 9,10, 9, 9, 9,11, + 11,11,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9,10, 9, + 11,11,10,11,11,11,11,10,11, 9, 9, 9, 9, 9, 9, 9, + 9, +}; + +static const static_codebook _44c1_s_p8_2 = { + 2, 289, + (char *)_vq_lengthlist__44c1_s_p8_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c1_s_p8_2, + 0 +}; + +static const char _huff_lengthlist__44c1_s_short[] = { + 6, 8,13,12,13,14,15,16,16, 4, 2, 4, 7, 6, 8,11, + 13,15,10, 4, 4, 8, 6, 8,11,14,17,11, 5, 6, 5, 6, + 8,12,14,17,11, 5, 5, 6, 5, 7,10,13,16,12, 6, 7, + 8, 7, 8,10,13,15,13, 8, 8, 7, 7, 8,10,12,15,15, + 7, 7, 5, 5, 7, 9,12,14,15, 8, 8, 6, 6, 7, 8,10, + 11, +}; + +static const static_codebook _huff_book__44c1_s_short = { + 2, 81, + (char *)_huff_lengthlist__44c1_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44c1_sm_long[] = { + 5, 4, 8,10, 9, 9,10,11,12, 4, 2, 5, 6, 6, 8,10, + 11,13, 8, 4, 6, 8, 7, 9,12,12,14,10, 6, 8, 4, 5, + 6, 9,11,12, 9, 5, 6, 5, 5, 6, 9,11,11, 9, 7, 9, + 6, 5, 5, 7,10,10,10, 9,11, 8, 7, 6, 7, 9,11,11, + 12,13,10,10, 9, 8, 9,11,11,15,15,12,13,11, 9,10, + 11, +}; + +static const static_codebook _huff_book__44c1_sm_long = { + 2, 81, + (char *)_huff_lengthlist__44c1_sm_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c1_sm_p1_0[] = { + 1, 5, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 7, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 7, 0, 0, 0, 0, + 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, + 0, 0, 0, 9, 9,10, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 7, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 9,10, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c1_sm_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44c1_sm_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44c1_sm_p1_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c1_sm_p2_0[] = { + 2, 3, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c1_sm_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44c1_sm_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c1_sm_p2_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c1_sm_p3_0[] = { + 1, 3, 3, 7, 7, 0, 0, 0, 0, 0, 5, 5, 6, 6, 0, 0, + 0, 0, 0, 5, 5, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44c1_sm_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44c1_sm_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c1_sm_p3_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44c1_sm_p4_0[] = { + 1, 3, 3, 6, 6, 7, 7, 9, 9, 0, 6, 6, 7, 7, 8, 8, + 9, 9, 0, 6, 6, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8, + 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0, + 8, 8, 9, 9,11,11, 0, 0, 0, 9, 9, 9, 9,11,11, 0, + 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0, 9, 9,11, + 11, +}; + +static const static_codebook _44c1_sm_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44c1_sm_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44c1_sm_p4_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p5_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c1_sm_p5_0[] = { + 2, 3, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 0, 5, 5, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10,10, + 11,11, 0, 5, 5, 6, 6, 8, 8, 9, 9, 9, 9,10,10,10, + 10,11,11, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9,10,10, + 10,11,11,11,12,12, 0, 0, 0, 8, 8, 8, 8, 9, 9,10, + 10,10,10,11,11,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 9, 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9, 9, 9,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 9, 9,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, 0, + 0, 0, 0,10,10,11,11,12,12,12,12,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,11,11,12,12,13,13,13,13, 0, 0, + 0, 0, 0, 0, 0,11,11,11,11,12,12,13,13,13,13, 0, + 0, 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,13,13,14, + 14, +}; + +static const static_codebook _44c1_sm_p5_0 = { + 2, 289, + (char *)_vq_lengthlist__44c1_sm_p5_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c1_sm_p5_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44c1_sm_p6_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7,10, 9, 9,11, + 9, 9, 4, 7, 7,10, 9, 9,11, 9, 9, 7,10,10,10,11, + 11,11,10,10, 6, 9, 9,11,11,10,11,10,10, 6, 9, 9, + 11,10,11,11,10,10, 7,11,11,11,11,11,11,11,11, 6, + 9, 9,11,10,10,11,11,10, 6, 9, 9,10,10,10,11,10, + 11, +}; + +static const static_codebook _44c1_sm_p6_0 = { + 4, 81, + (char *)_vq_lengthlist__44c1_sm_p6_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44c1_sm_p6_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p6_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44c1_sm_p6_1[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6, + 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 8,10, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, + 8, 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 9, 8,10,10,10,10,10, 8, 8, 8, + 8, 8, 8,10,10,10,10,10, 9, 9, 8, 8, 8, 8,10,10, + 10,10,10, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44c1_sm_p6_1 = { + 2, 121, + (char *)_vq_lengthlist__44c1_sm_p6_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44c1_sm_p6_1, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c1_sm_p7_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 7, 5, 5, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 7, 5, 6, 7, 7, 8, + 8, 8, 8, 9, 9,11,10, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9,10,10,10,10,11,11,11,11, 0,13, + 13, 9, 9, 9, 9,10,10,11,11,12,12, 0, 0, 0, 9,10, + 9,10,11,11,12,11,13,12, 0, 0, 0,10,10, 9, 9,11, + 11,12,12,13,12, 0, 0, 0,13,13,10,10,11,11,12,12, + 13,13, 0, 0, 0,14,14,10,10,11,11,12,12,13,13, 0, + 0, 0, 0, 0,11,12,11,11,12,13,14,13, 0, 0, 0, 0, + 0,12,12,11,11,13,12,14,13, +}; + +static const static_codebook _44c1_sm_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44c1_sm_p7_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44c1_sm_p7_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44c1_sm_p7_1[] = { + 2, 4, 4, 4, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44c1_sm_p7_1 = { + 2, 25, + (char *)_vq_lengthlist__44c1_sm_p7_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44c1_sm_p7_1, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p8_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c1_sm_p8_0[] = { + 1, 3, 3,13,13,13,13,13,13,13,13,13,13, 3, 6, 6, + 13,13,13,13,13,13,13,13,13,13, 4, 8, 7,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,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,13,13,13, + 13,13,13,13,13,13,13,13,13, +}; + +static const static_codebook _44c1_sm_p8_0 = { + 2, 169, + (char *)_vq_lengthlist__44c1_sm_p8_0, + 1, -514541568, 1627103232, 4, 0, + (long *)_vq_quantlist__44c1_sm_p8_0, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p8_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44c1_sm_p8_1[] = { + 1, 4, 4, 6, 6, 7, 7, 9, 9,10,11,12,12, 6, 5, 5, + 7, 7, 8, 7,10,10,11,11,12,12, 6, 5, 5, 7, 7, 8, + 8,10,10,11,11,12,12,16, 7, 7, 8, 8, 9, 9,11,11, + 12,12,13,13,17, 7, 7, 8, 7, 9, 9,11,10,12,12,13, + 13,19,11,10, 8, 8,10,10,11,11,12,12,13,13,19,11, + 11, 9, 7,11,10,11,11,12,12,13,12,19,19,19,10,10, + 10,10,11,12,12,12,13,14,18,19,19,11, 9,11, 9,13, + 12,12,12,13,13,19,20,19,13,15,11,11,12,12,13,13, + 14,13,18,19,20,15,13,12,10,13,10,13,13,13,14,20, + 20,20,20,20,13,14,12,12,13,12,13,13,20,20,20,20, + 20,13,12,12,12,14,12,14,13, +}; + +static const static_codebook _44c1_sm_p8_1 = { + 2, 169, + (char *)_vq_lengthlist__44c1_sm_p8_1, + 1, -522616832, 1620115456, 4, 0, + (long *)_vq_quantlist__44c1_sm_p8_1, + 0 +}; + +static const long _vq_quantlist__44c1_sm_p8_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44c1_sm_p8_2[] = { + 2, 5, 5, 6, 6, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8,10, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9,10, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9,10,11,11, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9,10,10, 9,10,10,10,10, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9,10,10,11,10,10, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10, 9,10,10,10,11,11, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11,11,11,11, 9, 9, + 9, 9, 9, 9, 9, 9,10, 9,10, 9,11,11,11,11,11, 9, + 8, 9, 9, 9, 9, 9, 9, 9,10,10, 9,11,11,10,11,11, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,11,11,11,11, + 11,11,11, 9, 9,10, 9, 9, 9, 9,10, 9,10,10,11,10, + 11,11,11,11, 9,10,10,10, 9, 9, 9, 9, 9, 9,10,11, + 11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,11, + 11,10,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9,10, 9, + 10,11,10,11,11,11,11,11,11, 9, 9,10, 9, 9, 9, 9, + 9, +}; + +static const static_codebook _44c1_sm_p8_2 = { + 2, 289, + (char *)_vq_lengthlist__44c1_sm_p8_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44c1_sm_p8_2, + 0 +}; + +static const char _huff_lengthlist__44c1_sm_short[] = { + 4, 7,13,14,14,15,16,18,18, 4, 2, 5, 8, 7, 9,12, + 15,15,10, 4, 5,10, 6, 8,11,15,17,12, 5, 7, 5, 6, + 8,11,14,17,11, 5, 6, 6, 5, 6, 9,13,17,12, 6, 7, + 6, 5, 6, 8,12,14,14, 7, 8, 6, 6, 7, 9,11,14,14, + 8, 9, 6, 5, 6, 9,11,13,16,10,10, 7, 6, 7, 8,10, + 11, +}; + +static const static_codebook _huff_book__44c1_sm_short = { + 2, 81, + (char *)_huff_lengthlist__44c1_sm_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44cn1_s_long[] = { + 4, 4, 7, 8, 7, 8,10,12,17, 3, 1, 6, 6, 7, 8,10, + 12,15, 7, 6, 9, 9, 9,11,12,14,17, 8, 6, 9, 6, 7, + 9,11,13,17, 7, 6, 9, 7, 7, 8, 9,12,15, 8, 8,10, + 8, 7, 7, 7,10,14, 9,10,12,10, 8, 8, 8,10,14,11, + 13,15,13,12,11,11,12,16,17,18,18,19,20,18,16,16, + 20, +}; + +static const static_codebook _huff_book__44cn1_s_long = { + 2, 81, + (char *)_huff_lengthlist__44cn1_s_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44cn1_s_p1_0[] = { + 1, 4, 4, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, + 0, 0, 0, 7, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7,10, 9, 0, 0, + 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 8, 0, 0, 0, 0, + 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 8, 9,10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,10,10, 0, 0, 0, + 0, 0, 0, 9, 9,11, 0, 0, 0, 0, 0, 0,10,11,11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,10,10, 0, 0, + 0, 0, 0, 0, 9,11, 9, 0, 0, 0, 0, 0, 0,10,11,11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8,10,10, 0, 0, + 0, 0, 0, 0, 8,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7,10,10, 0, 0, 0, 0, 0, 0,10,11,11, 0, + 0, 0, 0, 0, 0, 9, 9,11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7,10,10, 0, 0, 0, 0, 0, 0,10,11,11, + 0, 0, 0, 0, 0, 0, 9,11, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44cn1_s_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44cn1_s_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44cn1_s_p1_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44cn1_s_p2_0[] = { + 1, 4, 4, 7, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 7, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44cn1_s_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44cn1_s_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44cn1_s_p2_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44cn1_s_p3_0[] = { + 1, 2, 3, 7, 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, + 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 9, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44cn1_s_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44cn1_s_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44cn1_s_p3_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44cn1_s_p4_0[] = { + 1, 3, 3, 6, 6, 6, 6, 8, 8, 0, 0, 0, 6, 6, 7, 7, + 9, 9, 0, 0, 0, 6, 6, 7, 7, 9, 9, 0, 0, 0, 7, 7, + 8, 8,10,10, 0, 0, 0, 7, 7, 8, 8,10,10, 0, 0, 0, + 9, 9, 9, 9,10,10, 0, 0, 0, 9, 9, 9, 9,10,10, 0, + 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0,10,10,11, + 11, +}; + +static const static_codebook _44cn1_s_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44cn1_s_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44cn1_s_p4_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p5_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44cn1_s_p5_0[] = { + 1, 4, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,10, + 10, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10,10, + 11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10,10, + 10,11,11, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,12, 0, 0, 0, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,11,11, 0, 0, 0, 8, 8, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12, 0, 0, 0, 8, 8, 9, 9, 9, 9,10, + 10,10,11,11,11,12,12, 0, 0, 0, 9, 9,10, 9,10,10, + 10,10,11,11,11,11,12,12, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,12,12, 0, 0, 0, 0, 0, 9, 9, + 10,10,10,11,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, + 10,10,11,10,11,11,11,12,13,12,13,13, 0, 0, 0, 0, + 0, 0, 0,11,10,11,11,12,12,12,12,13,13, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, 0, + 0, 0, 0, 0, 0,11,11,12,12,12,12,13,13,13,14, 0, + 0, 0, 0, 0, 0, 0,12,12,12,13,13,13,13,13,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,12,13,13,14, + 14, +}; + +static const static_codebook _44cn1_s_p5_0 = { + 2, 289, + (char *)_vq_lengthlist__44cn1_s_p5_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44cn1_s_p5_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44cn1_s_p6_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 6, 6,10, 9, 9,11, + 9, 9, 4, 6, 6,10, 9, 9,10, 9, 9, 7,10,10,11,11, + 11,12,11,11, 7, 9, 9,11,11,10,11,10,10, 7, 9, 9, + 11,10,11,11,10,10, 7,10,10,11,11,11,12,11,11, 7, + 9, 9,11,10,10,11,10,10, 7, 9, 9,11,10,10,11,10, + 10, +}; + +static const static_codebook _44cn1_s_p6_0 = { + 4, 81, + (char *)_vq_lengthlist__44cn1_s_p6_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44cn1_s_p6_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p6_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44cn1_s_p6_1[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8,10,10,10, 7, 6, + 8, 8, 8, 8, 8, 8,10,10,10, 7, 6, 7, 7, 8, 8, 8, + 8,10,10,10, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, + 7, 8, 8, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 9, 9, + 9, 9,10,10,10, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10, 9, 9, 9, + 9, 9, 9,10,10,10,10,10, 9, 9, 9, 9, 9, 9,10,10, + 10,10,10, 9, 9, 9, 9, 9, 9, +}; + +static const static_codebook _44cn1_s_p6_1 = { + 2, 121, + (char *)_vq_lengthlist__44cn1_s_p6_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44cn1_s_p6_1, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44cn1_s_p7_0[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 6, 5, 5, + 7, 7, 8, 8, 8, 8, 9, 9,11,11, 7, 5, 5, 7, 7, 8, + 8, 8, 8, 9,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9, 9,10,10,10,11,11,11,12, 0,13, + 13, 9, 9, 9, 9,10,10,11,11,11,12, 0, 0, 0,10,10, + 10,10,11,11,12,12,12,13, 0, 0, 0,10,10,10,10,11, + 11,12,12,13,12, 0, 0, 0,14,14,11,10,11,12,12,13, + 13,14, 0, 0, 0,15,15,11,11,12,11,12,12,14,13, 0, + 0, 0, 0, 0,12,12,12,12,13,13,14,14, 0, 0, 0, 0, + 0,13,13,12,12,13,13,13,14, +}; + +static const static_codebook _44cn1_s_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44cn1_s_p7_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44cn1_s_p7_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44cn1_s_p7_1[] = { + 2, 3, 3, 5, 5, 6, 6, 6, 5, 5, 6, 6, 6, 5, 5, 6, + 6, 6, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44cn1_s_p7_1 = { + 2, 25, + (char *)_vq_lengthlist__44cn1_s_p7_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44cn1_s_p7_1, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p8_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44cn1_s_p8_0[] = { + 1, 7, 7,11,11, 8,11,11,11,11, 4,11, 3,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,10,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,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11, 7,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10, + 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,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11, 8,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,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,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,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,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,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,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,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,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, +}; + +static const static_codebook _44cn1_s_p8_0 = { + 4, 625, + (char *)_vq_lengthlist__44cn1_s_p8_0, + 1, -518283264, 1627103232, 3, 0, + (long *)_vq_quantlist__44cn1_s_p8_0, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p8_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44cn1_s_p8_1[] = { + 1, 4, 4, 6, 6, 8, 8, 9,10,10,11,11,11, 6, 5, 5, + 7, 7, 8, 8, 9,10, 9,11,11,12, 5, 5, 5, 7, 7, 8, + 9,10,10,12,12,14,13,15, 7, 7, 8, 8, 9,10,11,11, + 10,12,10,11,15, 7, 8, 8, 8, 9, 9,11,11,13,12,12, + 13,15,10,10, 8, 8,10,10,12,12,11,14,10,10,15,11, + 11, 8, 8,10,10,12,13,13,14,15,13,15,15,15,10,10, + 10,10,12,12,13,12,13,10,15,15,15,10,10,11,10,13, + 11,13,13,15,13,15,15,15,13,13,10,11,11,11,12,10, + 14,11,15,15,14,14,13,10,10,12,11,13,13,14,14,15, + 15,15,15,15,11,11,11,11,12,11,15,12,15,15,15,15, + 15,12,12,11,11,14,12,13,14, +}; + +static const static_codebook _44cn1_s_p8_1 = { + 2, 169, + (char *)_vq_lengthlist__44cn1_s_p8_1, + 1, -522616832, 1620115456, 4, 0, + (long *)_vq_quantlist__44cn1_s_p8_1, + 0 +}; + +static const long _vq_quantlist__44cn1_s_p8_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44cn1_s_p8_2[] = { + 3, 4, 3, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9,10,11,11, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9,10,10,10, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9,10,10,10, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, + 9, 9,10, 9,10,11,10, 7, 6, 7, 7, 8, 8, 9, 9, 9, + 9, 9, 9, 9,10,10,10,11, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10, 7, 7, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9,10,11,11,11, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9,11,10,10,11,11, 8, 8, 8, + 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,11,11, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,11,10,11,11, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,11,10,11,11, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,10,11, + 11,11,11, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,11,11, + 10,11,11,11, 9,10,10, 9, 9, 9, 9, 9, 9, 9,10,11, + 11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, + 11,11,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9, 9, 9, + 11,11,11,10,11,11,11,11,11, 9, 9, 9,10, 9, 9, 9, + 9, +}; + +static const static_codebook _44cn1_s_p8_2 = { + 2, 289, + (char *)_vq_lengthlist__44cn1_s_p8_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44cn1_s_p8_2, + 0 +}; + +static const char _huff_lengthlist__44cn1_s_short[] = { + 10, 9,12,15,12,13,16,14,16, 7, 1, 5,14, 7,10,13, + 16,16, 9, 4, 6,16, 8,11,16,16,16,14, 4, 7,16, 9, + 12,14,16,16,10, 5, 7,14, 9,12,14,15,15,13, 8, 9, + 14,10,12,13,14,15,13, 9, 9, 7, 6, 8,11,12,12,14, + 8, 8, 5, 4, 5, 8,11,12,16,10,10, 6, 5, 6, 8, 9, + 10, +}; + +static const static_codebook _huff_book__44cn1_s_short = { + 2, 81, + (char *)_huff_lengthlist__44cn1_s_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44cn1_sm_long[] = { + 3, 3, 8, 8, 8, 8,10,12,14, 3, 2, 6, 7, 7, 8,10, + 12,16, 7, 6, 7, 9, 8,10,12,14,16, 8, 6, 8, 4, 5, + 7, 9,11,13, 7, 6, 8, 5, 6, 7, 9,11,14, 8, 8,10, + 7, 7, 6, 8,10,13, 9,11,12, 9, 9, 7, 8,10,12,10, + 13,15,11,11,10, 9,10,13,13,16,17,14,15,14,13,14, + 17, +}; + +static const static_codebook _huff_book__44cn1_sm_long = { + 2, 81, + (char *)_huff_lengthlist__44cn1_sm_long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44cn1_sm_p1_0[] = { + 1, 4, 5, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, + 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, + 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 7, 9, 8, 0, 0, + 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 8, 0, 0, 0, 0, + 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,10, 9, 0, 0, 0, + 0, 0, 0, 9, 9,10, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 9, 0, 0, + 0, 0, 0, 0, 8,10, 9, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, + 0, 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 9, 9, 0, 0, 0, 0, 0, 0, 9,10,10, 0, + 0, 0, 0, 0, 0, 8, 9,10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 9,10, 0, 0, 0, 0, 0, 0, 9,10,10, + 0, 0, 0, 0, 0, 0, 9,10, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44cn1_sm_p1_0 = { + 8, 6561, + (char *)_vq_lengthlist__44cn1_sm_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44cn1_sm_p1_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44cn1_sm_p2_0[] = { + 1, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44cn1_sm_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44cn1_sm_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44cn1_sm_p2_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44cn1_sm_p3_0[] = { + 1, 3, 4, 7, 7, 0, 0, 0, 0, 0, 4, 4, 7, 7, 0, 0, + 0, 0, 0, 4, 5, 7, 7, 0, 0, 0, 0, 0, 6, 7, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 0, 0, 0, 0, 0, 0, 0,10, 9, 0, 0, 0, 0, 0, + 0, 0,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const static_codebook _44cn1_sm_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44cn1_sm_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44cn1_sm_p3_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p4_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44cn1_sm_p4_0[] = { + 1, 4, 3, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 8, 7, + 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8, + 8, 8,10,10, 0, 0, 0, 8, 8, 8, 8,10,10, 0, 0, 0, + 9, 9, 9, 9,10,10, 0, 0, 0, 9, 9, 9, 9,10,10, 0, + 0, 0,10,10,10,10,11,11, 0, 0, 0, 0, 0,10,10,11, + 11, +}; + +static const static_codebook _44cn1_sm_p4_0 = { + 2, 81, + (char *)_vq_lengthlist__44cn1_sm_p4_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44cn1_sm_p4_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p5_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44cn1_sm_p5_0[] = { + 1, 4, 4, 6, 6, 8, 8, 9, 9, 8, 8, 9, 9,10,10,11, + 11, 0, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11,11, + 12,12, 0, 6, 5, 7, 7, 8, 8, 9, 9, 9, 9,10,10,11, + 11,12,12, 0, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 0, 0, 0, 7, 7, 8, 8, 9, 9,10,10,11, + 11,11,11,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10,10, + 11,11,12,12,12,12, 0, 0, 0, 8, 8, 9, 9,10,10,10, + 10,11,11,12,12,12,12, 0, 0, 0, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9,10, + 10,10,10,11,11,12,12,13,13, 0, 0, 0, 0, 0, 9, 9, + 10,10,11,11,12,12,13,13,13,13, 0, 0, 0, 0, 0, 9, + 9,10,10,11,11,12,12,12,13,13,13, 0, 0, 0, 0, 0, + 10,10,11,11,11,11,12,12,13,13,14,14, 0, 0, 0, 0, + 0, 0, 0,11,11,11,11,12,12,13,13,14,14, 0, 0, 0, + 0, 0, 0, 0,11,11,12,12,13,13,13,13,14,14, 0, 0, + 0, 0, 0, 0, 0,11,11,12,12,13,13,13,13,14,14, 0, + 0, 0, 0, 0, 0, 0,12,12,12,13,13,13,14,14,14,14, + 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,13,13,14,14,14, + 14, +}; + +static const static_codebook _44cn1_sm_p5_0 = { + 2, 289, + (char *)_vq_lengthlist__44cn1_sm_p5_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44cn1_sm_p5_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p6_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44cn1_sm_p6_0[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 6,10, 9, 9,11, + 9, 9, 4, 6, 7,10, 9, 9,11, 9, 9, 7,10,10,10,11, + 11,11,11,10, 6, 9, 9,11,10,10,11,10,10, 6, 9, 9, + 11,10,11,11,10,10, 7,11,11,11,11,11,12,11,11, 7, + 9, 9,11,10,10,12,10,10, 7, 9, 9,11,10,10,11,10, + 10, +}; + +static const static_codebook _44cn1_sm_p6_0 = { + 4, 81, + (char *)_vq_lengthlist__44cn1_sm_p6_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44cn1_sm_p6_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p6_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44cn1_sm_p6_1[] = { + 2, 4, 4, 5, 5, 7, 7, 7, 7, 8, 8,10, 5, 5, 6, 6, + 7, 7, 8, 8, 8, 8,10, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 8,10, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,10,10,10, 7, + 7, 7, 7, 8, 8, 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, + 8, 8,10,10,10, 8, 8, 8, 8, 8, 8, 8, 8,10,10,10, + 8, 8, 8, 8, 8, 8, 9, 9,10,10,10,10,10, 8, 8, 8, + 8, 9, 9,10,10,10,10,10, 9, 9, 9, 9, 8, 9,10,10, + 10,10,10, 8, 9, 8, 8, 9, 8, +}; + +static const static_codebook _44cn1_sm_p6_1 = { + 2, 121, + (char *)_vq_lengthlist__44cn1_sm_p6_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44cn1_sm_p6_1, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44cn1_sm_p7_0[] = { + 1, 4, 4, 6, 6, 7, 7, 7, 7, 9, 9,10,10, 7, 5, 5, + 7, 7, 8, 8, 8, 8,10, 9,11,10, 7, 5, 5, 7, 7, 8, + 8, 8, 8, 9,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,11, 0, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11, + 11, 0,12,12, 9, 9, 9,10,10,10,11,11,12,12, 0,13, + 13, 9, 9, 9, 9,10,10,11,11,12,12, 0, 0, 0,10,10, + 10,10,11,11,12,12,12,13, 0, 0, 0,10,10,10,10,11, + 11,12,12,12,12, 0, 0, 0,14,14,11,11,11,11,12,13, + 13,13, 0, 0, 0,14,14,11,10,11,11,12,12,13,13, 0, + 0, 0, 0, 0,12,12,12,12,13,13,13,14, 0, 0, 0, 0, + 0,13,12,12,12,13,13,13,14, +}; + +static const static_codebook _44cn1_sm_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44cn1_sm_p7_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44cn1_sm_p7_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p7_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44cn1_sm_p7_1[] = { + 2, 4, 4, 4, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const static_codebook _44cn1_sm_p7_1 = { + 2, 25, + (char *)_vq_lengthlist__44cn1_sm_p7_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44cn1_sm_p7_1, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p8_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44cn1_sm_p8_0[] = { + 1, 4, 4,12,11,13,13,14,14, 4, 7, 7,11,13,14,14, + 14,14, 3, 8, 3,14,14,14,14,14,14,14,10,12,14,14, + 14,14,14,14,14,14, 5,14, 8,14,14,14,14,14,12,14, + 13,14,14,14,14,14,14,14,13,14,10,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14, +}; + +static const static_codebook _44cn1_sm_p8_0 = { + 2, 81, + (char *)_vq_lengthlist__44cn1_sm_p8_0, + 1, -516186112, 1627103232, 4, 0, + (long *)_vq_quantlist__44cn1_sm_p8_0, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p8_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44cn1_sm_p8_1[] = { + 1, 4, 4, 6, 6, 8, 8, 9, 9,10,11,11,11, 6, 5, 5, + 7, 7, 8, 8,10,10,10,11,11,11, 6, 5, 5, 7, 7, 8, + 8,10,10,11,12,12,12,14, 7, 7, 7, 8, 9, 9,11,11, + 11,12,11,12,17, 7, 7, 8, 7, 9, 9,11,11,12,12,12, + 12,14,11,11, 8, 8,10,10,11,12,12,13,11,12,14,11, + 11, 8, 8,10,10,11,12,12,13,13,12,14,15,14,10,10, + 10,10,11,12,12,12,12,11,14,13,16,10,10,10, 9,12, + 11,12,12,13,14,14,15,14,14,13,10,10,11,11,12,11, + 13,11,14,12,15,13,14,11,10,12,10,12,12,13,13,13, + 13,14,15,15,12,12,11,11,12,11,13,12,14,14,14,14, + 17,12,12,11,10,13,11,13,13, +}; + +static const static_codebook _44cn1_sm_p8_1 = { + 2, 169, + (char *)_vq_lengthlist__44cn1_sm_p8_1, + 1, -522616832, 1620115456, 4, 0, + (long *)_vq_quantlist__44cn1_sm_p8_1, + 0 +}; + +static const long _vq_quantlist__44cn1_sm_p8_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44cn1_sm_p8_2[] = { + 3, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9,10, 6, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9,10, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9,10, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9,10,10,10, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9,11,10,11, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,11,11, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9,11,10,11,11,11, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,10,11,11, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,11,10,11,11, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,10,11,11, + 11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,11,11, + 11,11,11,11, 9,10,10,10, 9, 9, 9, 9, 9, 9,11,10, + 11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, + 11,11,11,11,11,11,10,10, 9, 9, 9, 9, 9, 9, 9, 9, + 10,11,11,11,11,11,11,11,11, 9, 9, 9, 9, 9, 9, 9, + 9, +}; + +static const static_codebook _44cn1_sm_p8_2 = { + 2, 289, + (char *)_vq_lengthlist__44cn1_sm_p8_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44cn1_sm_p8_2, + 0 +}; + +static const char _huff_lengthlist__44cn1_sm_short[] = { + 5, 6,12,14,12,14,16,17,18, 4, 2, 5,11, 7,10,12, + 14,15, 9, 4, 5,11, 7,10,13,15,18,15, 6, 7, 5, 6, + 8,11,13,16,11, 5, 6, 5, 5, 6, 9,13,15,12, 5, 7, + 6, 5, 6, 9,12,14,12, 6, 7, 8, 6, 7, 9,12,13,14, + 8, 8, 7, 5, 5, 8,10,12,16, 9, 9, 8, 6, 6, 7, 9, + 9, +}; + +static const static_codebook _huff_book__44cn1_sm_short = { + 2, 81, + (char *)_huff_lengthlist__44cn1_sm_short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + diff --git a/vendor/vorbis/lib/books/floor/Makefile.am b/vendor/vorbis/lib/books/floor/Makefile.am new file mode 100644 index 0000000..272ab1a --- /dev/null +++ b/vendor/vorbis/lib/books/floor/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = floor_books.h diff --git a/vendor/vorbis/lib/books/floor/floor_books.h b/vendor/vorbis/lib/books/floor/floor_books.h new file mode 100644 index 0000000..d26664f --- /dev/null +++ b/vendor/vorbis/lib/books/floor/floor_books.h @@ -0,0 +1,1546 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: static codebooks autogenerated by huff/huffbuld + + ********************************************************************/ + +#include "codebook.h" + +static const char _huff_lengthlist_line_256x7_0sub1[] = { + 0, 2, 3, 3, 3, 3, 4, 3, 4, +}; + +static const static_codebook _huff_book_line_256x7_0sub1 = { + 1, 9, + (char *)_huff_lengthlist_line_256x7_0sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x7_0sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 4, 3, 5, 3, + 6, 3, 6, 4, 6, 4, 7, 5, 7, +}; + +static const static_codebook _huff_book_line_256x7_0sub2 = { + 1, 25, + (char *)_huff_lengthlist_line_256x7_0sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x7_0sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 2, 5, 3, 5, 3, + 6, 3, 6, 4, 7, 6, 7, 8, 7, 9, 8, 9, 9, 9,10, 9, + 11,13,11,13,10,10,13,13,13,13,13,13,12,12,12,12, +}; + +static const static_codebook _huff_book_line_256x7_0sub3 = { + 1, 64, + (char *)_huff_lengthlist_line_256x7_0sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x7_1sub1[] = { + 0, 3, 3, 3, 3, 2, 4, 3, 4, +}; + +static const static_codebook _huff_book_line_256x7_1sub1 = { + 1, 9, + (char *)_huff_lengthlist_line_256x7_1sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x7_1sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 4, 3, 4, 4, + 5, 4, 6, 5, 6, 7, 6, 8, 8, +}; + +static const static_codebook _huff_book_line_256x7_1sub2 = { + 1, 25, + (char *)_huff_lengthlist_line_256x7_1sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x7_1sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 3, 6, 3, 7, + 3, 8, 5, 8, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, +}; + +static const static_codebook _huff_book_line_256x7_1sub3 = { + 1, 64, + (char *)_huff_lengthlist_line_256x7_1sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x7_class0[] = { + 7, 5, 5, 9, 9, 6, 6, 9,12, 8, 7, 8,11, 8, 9,15, + 6, 3, 3, 7, 7, 4, 3, 6, 9, 6, 5, 6, 8, 6, 8,15, + 8, 5, 5, 9, 8, 5, 4, 6,10, 7, 5, 5,11, 8, 7,15, + 14,15,13,13,13,13, 8,11,15,10, 7, 6,11, 9,10,15, +}; + +static const static_codebook _huff_book_line_256x7_class0 = { + 1, 64, + (char *)_huff_lengthlist_line_256x7_class0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x7_class1[] = { + 5, 6, 8,15, 6, 9,10,15,10,11,12,15,15,15,15,15, + 4, 6, 7,15, 6, 7, 8,15, 9, 8, 9,15,15,15,15,15, + 6, 8, 9,15, 7, 7, 8,15,10, 9,10,15,15,15,15,15, + 15,13,15,15,15,10,11,15,15,13,13,15,15,15,15,15, + 4, 6, 7,15, 6, 8, 9,15,10,10,12,15,15,15,15,15, + 2, 5, 6,15, 5, 6, 7,15, 8, 6, 7,15,15,15,15,15, + 5, 6, 8,15, 5, 6, 7,15, 9, 6, 7,15,15,15,15,15, + 14,12,13,15,12,10,11,15,15,15,15,15,15,15,15,15, + 7, 8, 9,15, 9,10,10,15,15,14,14,15,15,15,15,15, + 5, 6, 7,15, 7, 8, 9,15,12, 9,10,15,15,15,15,15, + 7, 7, 9,15, 7, 7, 8,15,12, 8, 9,15,15,15,15,15, + 13,13,14,15,12,11,12,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, + 13,13,13,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,12,13,15,15,12,13,15,15,14,15,15,15,15,15,15, + 15,15,15,15,15,15,13,15,15,15,15,15,15,15,15,15, +}; + +static const static_codebook _huff_book_line_256x7_class1 = { + 1, 256, + (char *)_huff_lengthlist_line_256x7_class1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_0sub0[] = { + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 6, 5, 6, 6, 6, 6, 5, 6, 6, 7, 6, 7, 6, 7, 6, + 7, 6, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 9, 7, 9, 7, + 9, 7, 9, 8, 9, 8,10, 8,10, 8,10, 7,10, 6,10, 8, + 10, 8,11, 7,10, 7,11, 8,11,11,12,12,11,11,12,11, + 13,11,13,11,13,12,15,12,13,13,14,14,14,14,14,15, + 15,15,16,14,17,19,19,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, +}; + +static const static_codebook _huff_book_line_512x17_0sub0 = { + 1, 128, + (char *)_huff_lengthlist_line_512x17_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_1sub0[] = { + 2, 4, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 6, 5, + 6, 5, 6, 6, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, 8, 7, +}; + +static const static_codebook _huff_book_line_512x17_1sub0 = { + 1, 32, + (char *)_huff_lengthlist_line_512x17_1sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_1sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 3, 5, 3, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 6, 5, + 6, 5, 7, 5, 8, 6, 8, 6, 8, 6, 8, 6, 8, 7, 9, 7, + 9, 7,11, 9,11,11,12,11,14,12,14,16,14,16,13,16, + 14,16,12,15,13,16,14,16,13,14,12,15,13,15,13,13, + 13,15,12,14,14,15,13,15,12,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +}; + +static const static_codebook _huff_book_line_512x17_1sub1 = { + 1, 128, + (char *)_huff_lengthlist_line_512x17_1sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_2sub1[] = { + 0, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 5, 4, 5, 3, + 5, 3, +}; + +static const static_codebook _huff_book_line_512x17_2sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_512x17_2sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_2sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 6, 4, 6, 5, + 6, 5, 7, 5, 7, 6, 8, 6, 8, 6, 8, 7, 8, 7, 9, 7, + 9, 8, +}; + +static const static_codebook _huff_book_line_512x17_2sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_512x17_2sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_2sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 3, 3, 3, 4, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 7, 8, 8,11, 8, 9, 9, 9,10,11,11,11, 9,10,10,11, + 11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _huff_book_line_512x17_2sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_512x17_2sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_3sub1[] = { + 0, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 5, 4, 5, + 5, 5, +}; + +static const static_codebook _huff_book_line_512x17_3sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_512x17_3sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_3sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 3, 3, 4, 3, 5, 4, 6, 4, 6, 5, 7, 6, 7, + 6, 8, 6, 8, 7, 9, 8,10, 8,12, 9,13,10,15,10,15, + 11,14, +}; + +static const static_codebook _huff_book_line_512x17_3sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_512x17_3sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_3sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 8, 4, 8, 4, 8, 4, 8, 5, 8, 5, 8, 6, 8, + 4, 8, 4, 8, 5, 8, 5, 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 static_codebook _huff_book_line_512x17_3sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_512x17_3sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_class1[] = { + 1, 2, 3, 6, 5, 4, 7, 7, +}; + +static const static_codebook _huff_book_line_512x17_class1 = { + 1, 8, + (char *)_huff_lengthlist_line_512x17_class1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_class2[] = { + 3, 3, 3,14, 5, 4, 4,11, 8, 6, 6,10,17,12,11,17, + 6, 5, 5,15, 5, 3, 4,11, 8, 5, 5, 8,16, 9,10,14, + 10, 8, 9,17, 8, 6, 6,13,10, 7, 7,10,16,11,13,14, + 17,17,17,17,17,16,16,16,16,15,16,16,16,16,16,16, +}; + +static const static_codebook _huff_book_line_512x17_class2 = { + 1, 64, + (char *)_huff_lengthlist_line_512x17_class2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_512x17_class3[] = { + 2, 4, 6,17, 4, 5, 7,17, 8, 7,10,17,17,17,17,17, + 3, 4, 6,15, 3, 3, 6,15, 7, 6, 9,17,17,17,17,17, + 6, 8,10,17, 6, 6, 8,16, 9, 8,10,17,17,15,16,17, + 17,17,17,17,12,15,15,16,12,15,15,16,16,16,16,16, +}; + +static const static_codebook _huff_book_line_512x17_class3 = { + 1, 64, + (char *)_huff_lengthlist_line_512x17_class3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x4_class0[] = { + 7, 7, 7,11, 6, 6, 7,11, 7, 6, 6,10,12,10,10,13, + 7, 7, 8,11, 7, 7, 7,11, 7, 6, 7,10,11,10,10,13, + 10,10, 9,12, 9, 9, 9,11, 8, 8, 8,11,13,11,10,14, + 15,15,14,15,15,14,13,14,15,12,12,17,17,17,17,17, + 7, 7, 6, 9, 6, 6, 6, 9, 7, 6, 6, 8,11,11,10,12, + 7, 7, 7, 9, 7, 6, 6, 9, 7, 6, 6, 9,13,10,10,11, + 10, 9, 8,10, 9, 8, 8,10, 8, 8, 7, 9,13,12,10,11, + 17,14,14,13,15,14,12,13,17,13,12,15,17,17,14,17, + 7, 6, 6, 7, 6, 6, 5, 7, 6, 6, 6, 6,11, 9, 9, 9, + 7, 7, 6, 7, 7, 6, 6, 7, 6, 6, 6, 6,10, 9, 8, 9, + 10, 9, 8, 8, 9, 8, 7, 8, 8, 7, 6, 8,11,10, 9,10, + 17,17,12,15,15,15,12,14,14,14,10,12,15,13,12,13, + 11,10, 8,10,11,10, 8, 8,10, 9, 7, 7,10, 9, 9,11, + 11,11, 9,10,11,10, 8, 9,10, 8, 6, 8,10, 9, 9,11, + 14,13,10,12,12,11,10,10, 8, 7, 8,10,10,11,11,12, + 17,17,15,17,17,17,17,17,17,13,12,17,17,17,14,17, +}; + +static const static_codebook _huff_book_line_128x4_class0 = { + 1, 256, + (char *)_huff_lengthlist_line_128x4_class0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x4_0sub0[] = { + 2, 2, 2, 2, +}; + +static const static_codebook _huff_book_line_128x4_0sub0 = { + 1, 4, + (char *)_huff_lengthlist_line_128x4_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x4_0sub1[] = { + 0, 0, 0, 0, 3, 2, 3, 2, 3, 3, +}; + +static const static_codebook _huff_book_line_128x4_0sub1 = { + 1, 10, + (char *)_huff_lengthlist_line_128x4_0sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x4_0sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 3, 4, 3, + 4, 4, 5, 4, 5, 4, 6, 5, 6, +}; + +static const static_codebook _huff_book_line_128x4_0sub2 = { + 1, 25, + (char *)_huff_lengthlist_line_128x4_0sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x4_0sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 3, 5, 3, 5, 3, + 5, 4, 6, 5, 6, 5, 7, 6, 6, 7, 7, 9, 9,11,11,16, + 11,14,10,11,11,13,16,15,15,15,15,15,15,15,15,15, +}; + +static const static_codebook _huff_book_line_128x4_0sub3 = { + 1, 64, + (char *)_huff_lengthlist_line_128x4_0sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4_class0[] = { + 6, 7, 7,12, 6, 6, 7,12, 7, 6, 6,10,15,12,11,13, + 7, 7, 8,13, 7, 7, 8,12, 7, 7, 7,11,12,12,11,13, + 10, 9, 9,11, 9, 9, 9,10,10, 8, 8,12,14,12,12,14, + 11,11,12,14,11,12,11,15,15,12,13,15,15,15,15,15, + 6, 6, 7,10, 6, 6, 6,11, 7, 6, 6, 9,14,12,11,13, + 7, 7, 7,10, 6, 6, 7, 9, 7, 7, 6,10,13,12,10,12, + 9, 9, 9,11, 9, 9, 8, 9, 9, 8, 8,10,13,12,10,12, + 12,12,11,13,12,12,11,12,15,13,12,15,15,15,14,14, + 6, 6, 6, 8, 6, 6, 5, 6, 7, 7, 6, 5,11,10, 9, 8, + 7, 6, 6, 7, 6, 6, 5, 6, 7, 7, 6, 6,11,10, 9, 8, + 8, 8, 8, 9, 8, 8, 7, 8, 8, 8, 6, 7,11,10, 9, 9, + 14,11,10,14,14,11,10,15,13,11, 9,11,15,12,12,11, + 11, 9, 8, 8,10, 9, 8, 9,11,10, 9, 8,12,11,12,11, + 13,10, 8, 9,11,10, 8, 9,10, 9, 8, 9,10, 8,12,12, + 15,11,10,10,13,11,10,10, 8, 8, 7,12,10, 9,11,12, + 15,12,11,15,13,11,11,15,12,14,11,13,15,15,13,13, +}; + +static const static_codebook _huff_book_line_256x4_class0 = { + 1, 256, + (char *)_huff_lengthlist_line_256x4_class0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4_0sub0[] = { + 2, 2, 2, 2, +}; + +static const static_codebook _huff_book_line_256x4_0sub0 = { + 1, 4, + (char *)_huff_lengthlist_line_256x4_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4_0sub1[] = { + 0, 0, 0, 0, 2, 2, 3, 3, 3, 3, +}; + +static const static_codebook _huff_book_line_256x4_0sub1 = { + 1, 10, + (char *)_huff_lengthlist_line_256x4_0sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4_0sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 3, 4, 3, 4, 3, + 5, 3, 5, 4, 5, 4, 6, 4, 6, +}; + +static const static_codebook _huff_book_line_256x4_0sub2 = { + 1, 25, + (char *)_huff_lengthlist_line_256x4_0sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4_0sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 3, 5, 3, 5, 3, + 6, 4, 7, 4, 7, 5, 7, 6, 7, 6, 7, 8,10,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12, +}; + +static const static_codebook _huff_book_line_256x4_0sub3 = { + 1, 64, + (char *)_huff_lengthlist_line_256x4_0sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_class0[] = { + 10, 7, 8,13, 9, 6, 7,11,10, 8, 8,12,17,17,17,17, + 7, 5, 5, 9, 6, 4, 4, 8, 8, 5, 5, 8,16,14,13,16, + 7, 5, 5, 7, 6, 3, 3, 5, 8, 5, 4, 7,14,12,12,15, + 10, 7, 8, 9, 7, 5, 5, 6, 9, 6, 5, 5,15,12, 9,10, +}; + +static const static_codebook _huff_book_line_128x7_class0 = { + 1, 64, + (char *)_huff_lengthlist_line_128x7_class0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_class1[] = { + 8,13,17,17, 8,11,17,17,11,13,17,17,17,17,17,17, + 6,10,16,17, 6,10,15,17, 8,10,16,17,17,17,17,17, + 9,13,15,17, 8,11,17,17,10,12,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 6,11,15,17, 7,10,15,17, 8,10,17,17,17,15,17,17, + 4, 8,13,17, 4, 7,13,17, 6, 8,15,17,16,15,17,17, + 6,11,15,17, 6, 9,13,17, 8,10,17,17,15,17,17,17, + 16,17,17,17,12,14,15,17,13,14,15,17,17,17,17,17, + 5,10,14,17, 5, 9,14,17, 7, 9,15,17,15,15,17,17, + 3, 7,12,17, 3, 6,11,17, 5, 7,13,17,12,12,17,17, + 5, 9,14,17, 3, 7,11,17, 5, 8,13,17,13,11,16,17, + 12,17,17,17, 9,14,15,17,10,11,14,17,16,14,17,17, + 8,12,17,17, 8,12,17,17,10,12,17,17,17,17,17,17, + 5,10,17,17, 5, 9,15,17, 7, 9,17,17,13,13,17,17, + 7,11,17,17, 6,10,15,17, 7, 9,15,17,12,11,17,17, + 12,15,17,17,11,14,17,17,11,10,15,17,17,16,17,17, +}; + +static const static_codebook _huff_book_line_128x7_class1 = { + 1, 256, + (char *)_huff_lengthlist_line_128x7_class1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_0sub1[] = { + 0, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static const static_codebook _huff_book_line_128x7_0sub1 = { + 1, 9, + (char *)_huff_lengthlist_line_128x7_0sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_0sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4, 4, 4, 4, + 5, 4, 5, 4, 5, 4, 6, 4, 6, +}; + +static const static_codebook _huff_book_line_128x7_0sub2 = { + 1, 25, + (char *)_huff_lengthlist_line_128x7_0sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_0sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 3, 5, 3, 5, 4, + 5, 4, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, + 7, 8, 9,11,13,13,13,13,13,13,13,13,13,13,13,13, +}; + +static const static_codebook _huff_book_line_128x7_0sub3 = { + 1, 64, + (char *)_huff_lengthlist_line_128x7_0sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_1sub1[] = { + 0, 3, 3, 2, 3, 3, 4, 3, 4, +}; + +static const static_codebook _huff_book_line_128x7_1sub1 = { + 1, 9, + (char *)_huff_lengthlist_line_128x7_1sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_1sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 6, 3, 6, 3, + 6, 3, 7, 3, 8, 4, 9, 4, 9, +}; + +static const static_codebook _huff_book_line_128x7_1sub2 = { + 1, 25, + (char *)_huff_lengthlist_line_128x7_1sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x7_1sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7, 2, 7, 3, 8, 4, + 9, 5, 9, 8,10,11,11,12,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,13,13,13,13, +}; + +static const static_codebook _huff_book_line_128x7_1sub3 = { + 1, 64, + (char *)_huff_lengthlist_line_128x7_1sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_class1[] = { + 1, 6, 3, 7, 2, 4, 5, 7, +}; + +static const static_codebook _huff_book_line_128x11_class1 = { + 1, 8, + (char *)_huff_lengthlist_line_128x11_class1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_class2[] = { + 1, 6,12,16, 4,12,15,16, 9,15,16,16,16,16,16,16, + 2, 5,11,16, 5,11,13,16, 9,13,16,16,16,16,16,16, + 4, 8,12,16, 5, 9,12,16, 9,13,15,16,16,16,16,16, + 15,16,16,16,11,14,13,16,12,15,16,16,16,16,16,15, +}; + +static const static_codebook _huff_book_line_128x11_class2 = { + 1, 64, + (char *)_huff_lengthlist_line_128x11_class2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_class3[] = { + 7, 6, 9,17, 7, 6, 8,17,12, 9,11,16,16,16,16,16, + 5, 4, 7,16, 5, 3, 6,14, 9, 6, 8,15,16,16,16,16, + 5, 4, 6,13, 3, 2, 4,11, 7, 4, 6,13,16,11,10,14, + 12,12,12,16, 9, 7,10,15,12, 9,11,16,16,15,15,16, +}; + +static const static_codebook _huff_book_line_128x11_class3 = { + 1, 64, + (char *)_huff_lengthlist_line_128x11_class3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_0sub0[] = { + 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, + 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 6, 6, 6, 7, 6, + 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 8, 6, 8, 6, 8, 7, + 8, 7, 8, 7, 8, 7, 9, 7, 9, 8, 9, 8, 9, 8,10, 8, + 10, 9,10, 9,10, 9,11, 9,11, 9,10,10,11,10,11,10, + 11,11,11,11,11,11,12,13,14,14,14,15,15,16,16,16, + 17,15,16,15,16,16,17,17,16,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 static_codebook _huff_book_line_128x11_0sub0 = { + 1, 128, + (char *)_huff_lengthlist_line_128x11_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_1sub0[] = { + 2, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 5, 6, 5, 6, 5, 7, 6, 7, 6, 7, 6, 8, 6, 8, 6, +}; + +static const static_codebook _huff_book_line_128x11_1sub0 = { + 1, 32, + (char *)_huff_lengthlist_line_128x11_1sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_1sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 3, 5, 3, 6, 4, 6, 4, 7, 4, 7, 4, 7, 4, 8, 4, + 8, 4, 9, 5, 9, 5, 9, 5, 9, 6,10, 6,10, 6,11, 7, + 10, 7,10, 8,11, 9,11, 9,11,10,11,11,12,11,11,12, + 15,15,12,14,11,14,12,14,11,14,13,14,12,14,11,14, + 11,14,12,14,11,14,11,14,13,13,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, +}; + +static const static_codebook _huff_book_line_128x11_1sub1 = { + 1, 128, + (char *)_huff_lengthlist_line_128x11_1sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_2sub1[] = { + 0, 4, 5, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, 4, 4, + 5, 5, +}; + +static const static_codebook _huff_book_line_128x11_2sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_128x11_2sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_2sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 3, 3, 4, 4, 4, 4, 5, 4, 5, 4, 6, 5, 7, + 5, 7, 6, 8, 6, 8, 6, 9, 7, 9, 7,10, 7, 9, 8,11, + 8,11, +}; + +static const static_codebook _huff_book_line_128x11_2sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_128x11_2sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_2sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 8, 3, 8, 4, 8, 4, 8, 6, 8, 5, 8, 4, 8, + 4, 8, 6, 8, 7, 8, 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 static_codebook _huff_book_line_128x11_2sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_128x11_2sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_3sub1[] = { + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, + 5, 4, +}; + +static const static_codebook _huff_book_line_128x11_3sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_128x11_3sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_3sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 3, 5, 4, 6, 4, 6, 4, 7, 4, 7, 4, 8, 4, + 8, 4, 9, 4, 9, 4,10, 4,10, 5,10, 5,11, 5,12, 6, + 12, 6, +}; + +static const static_codebook _huff_book_line_128x11_3sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_128x11_3sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x11_3sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 1, 6, 3, 7, 3, 8, 4, 8, 5, 8, 8, 8, 9, + 7, 8, 8, 7, 7, 7, 8, 9,10, 9, 9,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, +}; + +static const static_codebook _huff_book_line_128x11_3sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_128x11_3sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_class1[] = { + 1, 3, 4, 7, 2, 5, 6, 7, +}; + +static const static_codebook _huff_book_line_128x17_class1 = { + 1, 8, + (char *)_huff_lengthlist_line_128x17_class1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_class2[] = { + 1, 4,10,19, 3, 8,13,19, 7,12,19,19,19,19,19,19, + 2, 6,11,19, 8,13,19,19, 9,11,19,19,19,19,19,19, + 6, 7,13,19, 9,13,19,19,10,13,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, +}; + +static const static_codebook _huff_book_line_128x17_class2 = { + 1, 64, + (char *)_huff_lengthlist_line_128x17_class2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_class3[] = { + 3, 6,10,17, 4, 8,11,20, 8,10,11,20,20,20,20,20, + 2, 4, 8,18, 4, 6, 8,17, 7, 8,10,20,20,17,20,20, + 3, 5, 8,17, 3, 4, 6,17, 8, 8,10,17,17,12,16,20, + 13,13,15,20,10,10,12,20,15,14,15,20,20,20,19,19, +}; + +static const static_codebook _huff_book_line_128x17_class3 = { + 1, 64, + (char *)_huff_lengthlist_line_128x17_class3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_0sub0[] = { + 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, + 7, 5, 7, 5, 7, 5, 7, 5, 7, 5, 7, 5, 8, 5, 8, 5, + 8, 5, 8, 5, 8, 6, 8, 6, 8, 6, 9, 6, 9, 6, 9, 6, + 9, 6, 9, 7, 9, 7, 9, 7, 9, 7,10, 7,10, 8,10, 8, + 10, 8,10, 8,10, 8,11, 8,11, 8,11, 8,11, 8,11, 9, + 12, 9,12, 9,12, 9,12, 9,12,10,12,10,13,11,13,11, + 14,12,14,13,15,14,16,14,17,15,18,16,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +}; + +static const static_codebook _huff_book_line_128x17_0sub0 = { + 1, 128, + (char *)_huff_lengthlist_line_128x17_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_1sub0[] = { + 2, 5, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 6, 5, + 6, 5, 6, 5, 7, 6, 7, 6, 7, 6, 8, 6, 9, 7, 9, 7, +}; + +static const static_codebook _huff_book_line_128x17_1sub0 = { + 1, 32, + (char *)_huff_lengthlist_line_128x17_1sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_1sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 3, 5, 3, 5, 3, 6, 3, 6, 4, 6, 4, 7, 4, 7, 5, + 8, 5, 8, 6, 9, 7, 9, 7, 9, 8,10, 9,10, 9,11,10, + 11,11,11,11,11,11,12,12,12,13,12,13,12,14,12,15, + 12,14,12,16,13,17,13,17,14,17,14,16,13,17,14,17, + 14,17,15,17,15,15,16,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, +}; + +static const static_codebook _huff_book_line_128x17_1sub1 = { + 1, 128, + (char *)_huff_lengthlist_line_128x17_1sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_2sub1[] = { + 0, 4, 5, 4, 6, 4, 8, 3, 9, 3, 9, 2, 9, 3, 8, 4, + 9, 4, +}; + +static const static_codebook _huff_book_line_128x17_2sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_128x17_2sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_2sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 1, 5, 3, 5, 3, 5, 4, 7, 5,10, 7,10, 7, + 12,10,14,10,14, 9,14,11,14,14,14,13,13,13,13,13, + 13,13, +}; + +static const static_codebook _huff_book_line_128x17_2sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_128x17_2sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_2sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 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, 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, +}; + +static const static_codebook _huff_book_line_128x17_2sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_128x17_2sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_3sub1[] = { + 0, 4, 4, 4, 4, 4, 4, 4, 5, 3, 5, 3, 5, 4, 6, 4, + 6, 4, +}; + +static const static_codebook _huff_book_line_128x17_3sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_128x17_3sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_3sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 3, 6, 3, 6, 4, 7, 4, 7, 4, 7, 4, 8, 4, + 8, 4, 8, 4, 8, 4, 9, 4, 9, 5,10, 5,10, 7,10, 8, + 10, 8, +}; + +static const static_codebook _huff_book_line_128x17_3sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_128x17_3sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_128x17_3sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 2, 4, 3, 4, 4, 4, 5, 4, 7, 5, 8, 5,11, + 6,10, 6,12, 7,12, 7,12, 8,12, 8,12,10,12,12,12, + 12,12,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, +}; + +static const static_codebook _huff_book_line_128x17_3sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_128x17_3sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_class1[] = { + 2,10, 8,14, 7,12,11,14, 1, 5, 3, 7, 4, 9, 7,13, +}; + +static const static_codebook _huff_book_line_1024x27_class1 = { + 1, 16, + (char *)_huff_lengthlist_line_1024x27_class1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_class2[] = { + 1, 4, 2, 6, 3, 7, 5, 7, +}; + +static const static_codebook _huff_book_line_1024x27_class2 = { + 1, 8, + (char *)_huff_lengthlist_line_1024x27_class2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_class3[] = { + 1, 5, 7,21, 5, 8, 9,21,10, 9,12,20,20,16,20,20, + 4, 8, 9,20, 6, 8, 9,20,11,11,13,20,20,15,17,20, + 9,11,14,20, 8,10,15,20,11,13,15,20,20,20,20,20, + 20,20,20,20,13,20,20,20,18,18,20,20,20,20,20,20, + 3, 6, 8,20, 6, 7, 9,20,10, 9,12,20,20,20,20,20, + 5, 7, 9,20, 6, 6, 9,20,10, 9,12,20,20,20,20,20, + 8,10,13,20, 8, 9,12,20,11,10,12,20,20,20,20,20, + 18,20,20,20,15,17,18,20,18,17,18,20,20,20,20,20, + 7,10,12,20, 8, 9,11,20,14,13,14,20,20,20,20,20, + 6, 9,12,20, 7, 8,11,20,12,11,13,20,20,20,20,20, + 9,11,15,20, 8,10,14,20,12,11,14,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 11,16,18,20,15,15,17,20,20,17,20,20,20,20,20,20, + 9,14,16,20,12,12,15,20,17,15,18,20,20,20,20,20, + 16,19,18,20,15,16,20,20,17,17,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +}; + +static const static_codebook _huff_book_line_1024x27_class3 = { + 1, 256, + (char *)_huff_lengthlist_line_1024x27_class3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_class4[] = { + 2, 3, 7,13, 4, 4, 7,15, 8, 6, 9,17,21,16,15,21, + 2, 5, 7,11, 5, 5, 7,14, 9, 7,10,16,17,15,16,21, + 4, 7,10,17, 7, 7, 9,15,11, 9,11,16,21,18,15,21, + 18,21,21,21,15,17,17,19,21,19,18,20,21,21,21,20, +}; + +static const static_codebook _huff_book_line_1024x27_class4 = { + 1, 64, + (char *)_huff_lengthlist_line_1024x27_class4, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_0sub0[] = { + 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, + 6, 5, 6, 5, 6, 5, 6, 5, 7, 5, 7, 5, 7, 5, 7, 5, + 8, 6, 8, 6, 8, 6, 9, 6, 9, 6,10, 6,10, 6,11, 6, + 11, 7,11, 7,12, 7,12, 7,12, 7,12, 7,12, 7,12, 7, + 12, 7,12, 8,13, 8,12, 8,12, 8,13, 8,13, 9,13, 9, + 13, 9,13, 9,12,10,12,10,13,10,14,11,14,12,14,13, + 14,13,14,14,15,16,15,15,15,14,15,17,21,22,22,21, + 22,22,22,22,22,22,21,21,21,21,21,21,21,21,21,21, +}; + +static const static_codebook _huff_book_line_1024x27_0sub0 = { + 1, 128, + (char *)_huff_lengthlist_line_1024x27_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_1sub0[] = { + 2, 5, 5, 4, 5, 4, 5, 4, 5, 4, 6, 5, 6, 5, 6, 5, + 6, 5, 7, 5, 7, 6, 8, 6, 8, 6, 8, 6, 9, 6, 9, 6, +}; + +static const static_codebook _huff_book_line_1024x27_1sub0 = { + 1, 32, + (char *)_huff_lengthlist_line_1024x27_1sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_1sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 5, 8, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 4, + 9, 4, 9, 4, 9, 4, 8, 4, 8, 4, 9, 5, 9, 5, 9, 5, + 9, 5, 9, 6,10, 6,10, 7,10, 8,11, 9,11,11,12,13, + 12,14,13,15,13,15,14,16,14,17,15,17,15,15,16,16, + 15,16,16,16,15,18,16,15,17,17,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +static const static_codebook _huff_book_line_1024x27_1sub1 = { + 1, 128, + (char *)_huff_lengthlist_line_1024x27_1sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_2sub0[] = { + 1, 5, 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, + 6, 6, 7, 7, 7, 7, 8, 7, 8, 8, 9, 8,10, 9,10, 9, +}; + +static const static_codebook _huff_book_line_1024x27_2sub0 = { + 1, 32, + (char *)_huff_lengthlist_line_1024x27_2sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_2sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 5, 5, 6, 5, 6, 5, + 7, 5, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, 9, 8, 9, 9, + 9, 9,10,10,10,11, 9,12, 9,12, 9,15,10,14, 9,13, + 10,13,10,12,10,12,10,13,10,12,11,13,11,14,12,13, + 13,14,14,13,14,15,14,16,13,13,14,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,15, +}; + +static const static_codebook _huff_book_line_1024x27_2sub1 = { + 1, 128, + (char *)_huff_lengthlist_line_1024x27_2sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_3sub1[] = { + 0, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, 4, 4, 4, 5, + 5, 5, +}; + +static const static_codebook _huff_book_line_1024x27_3sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_1024x27_3sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_3sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 3, 4, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, + 5, 7, 5, 8, 6, 8, 6, 9, 7,10, 7,10, 8,10, 8,11, + 9,11, +}; + +static const static_codebook _huff_book_line_1024x27_3sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_1024x27_3sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_3sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 7, 3, 8, 3,10, 3, 8, 3, 9, 3, 8, 4, 9, + 4, 9, 5, 9, 6,10, 6, 9, 7,11, 7,12, 9,13,10,13, + 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, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, +}; + +static const static_codebook _huff_book_line_1024x27_3sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_1024x27_3sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_4sub1[] = { + 0, 4, 5, 4, 5, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, + 5, 4, +}; + +static const static_codebook _huff_book_line_1024x27_4sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_1024x27_4sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_4sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 2, 4, 2, 5, 3, 5, 4, 6, 6, 6, 7, 7, 8, + 7, 8, 7, 8, 7, 9, 8, 9, 8, 9, 8,10, 8,11, 9,12, + 9,12, +}; + +static const static_codebook _huff_book_line_1024x27_4sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_1024x27_4sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_1024x27_4sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 5, 2, 6, 3, 6, 4, 7, 4, 7, 5, 9, 5,11, + 6,11, 6,11, 7,11, 6,11, 6,11, 9,11, 8,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,10,10,10,10,10,10, +}; + +static const static_codebook _huff_book_line_1024x27_4sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_1024x27_4sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_class1[] = { + 2, 6, 8, 9, 7,11,13,13, 1, 3, 5, 5, 6, 6,12,10, +}; + +static const static_codebook _huff_book_line_2048x27_class1 = { + 1, 16, + (char *)_huff_lengthlist_line_2048x27_class1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_class2[] = { + 1, 2, 3, 6, 4, 7, 5, 7, +}; + +static const static_codebook _huff_book_line_2048x27_class2 = { + 1, 8, + (char *)_huff_lengthlist_line_2048x27_class2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_class3[] = { + 3, 3, 6,16, 5, 5, 7,16, 9, 8,11,16,16,16,16,16, + 5, 5, 8,16, 5, 5, 7,16, 8, 7, 9,16,16,16,16,16, + 9, 9,12,16, 6, 8,11,16, 9,10,11,16,16,16,16,16, + 16,16,16,16,13,16,16,16,15,16,16,16,16,16,16,16, + 5, 4, 7,16, 6, 5, 8,16, 9, 8,10,16,16,16,16,16, + 5, 5, 7,15, 5, 4, 6,15, 7, 6, 8,16,16,16,16,16, + 9, 9,11,15, 7, 7, 9,16, 8, 8, 9,16,16,16,16,16, + 16,16,16,16,15,15,15,16,15,15,14,16,16,16,16,16, + 8, 8,11,16, 8, 9,10,16,11,10,14,16,16,16,16,16, + 6, 8,10,16, 6, 7,10,16, 8, 8,11,16,14,16,16,16, + 10,11,14,16, 9, 9,11,16,10,10,11,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,15,16,16,16,16,16,16,16,16,16,16,16, + 12,16,15,16,12,14,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +}; + +static const static_codebook _huff_book_line_2048x27_class3 = { + 1, 256, + (char *)_huff_lengthlist_line_2048x27_class3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_class4[] = { + 2, 4, 7,13, 4, 5, 7,15, 8, 7,10,16,16,14,16,16, + 2, 4, 7,16, 3, 4, 7,14, 8, 8,10,16,16,16,15,16, + 6, 8,11,16, 7, 7, 9,16,11, 9,13,16,16,16,15,16, + 16,16,16,16,14,16,16,16,16,16,16,16,16,16,16,16, +}; + +static const static_codebook _huff_book_line_2048x27_class4 = { + 1, 64, + (char *)_huff_lengthlist_line_2048x27_class4, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_0sub0[] = { + 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, + 6, 5, 7, 5, 7, 5, 7, 5, 8, 5, 8, 5, 8, 5, 9, 5, + 9, 6,10, 6,10, 6,11, 6,11, 6,11, 6,11, 6,11, 6, + 11, 6,11, 6,12, 7,11, 7,11, 7,11, 7,11, 7,10, 7, + 11, 7,11, 7,12, 7,11, 8,11, 8,11, 8,11, 8,13, 8, + 12, 9,11, 9,11, 9,11,10,12,10,12, 9,12,10,12,11, + 14,12,16,12,12,11,14,16,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16, +}; + +static const static_codebook _huff_book_line_2048x27_0sub0 = { + 1, 128, + (char *)_huff_lengthlist_line_2048x27_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_1sub0[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 6, 6, 6, 6, 6, 6, 7, 6, 7, 6, 7, 6, 7, 6, +}; + +static const static_codebook _huff_book_line_2048x27_1sub0 = { + 1, 32, + (char *)_huff_lengthlist_line_2048x27_1sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_1sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 5, 7, 5, 7, 4, 7, 4, 8, 4, 8, 4, 8, 4, 8, 3, + 8, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 5, 9, 5, 9, 6, + 9, 7, 9, 8, 9, 9, 9,10, 9,11, 9,14, 9,15,10,15, + 10,15,10,15,10,15,11,15,10,14,12,14,11,14,13,14, + 13,15,15,15,12,15,15,15,13,15,13,15,13,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14, +}; + +static const static_codebook _huff_book_line_2048x27_1sub1 = { + 1, 128, + (char *)_huff_lengthlist_line_2048x27_1sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_2sub0[] = { + 2, 4, 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 5, 6, 5, + 6, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, +}; + +static const static_codebook _huff_book_line_2048x27_2sub0 = { + 1, 32, + (char *)_huff_lengthlist_line_2048x27_2sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_2sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 4, 3, 4, 3, 4, 4, 5, 4, 5, 5, 5, 6, 6, 6, 7, + 6, 8, 6, 8, 6, 9, 7,10, 7,10, 7,10, 7,12, 7,12, + 7,12, 9,12,11,12,10,12,10,12,11,12,12,12,10,12, + 10,12,10,12, 9,12,11,12,12,12,12,12,11,12,11,12, + 12,12,12,12,12,12,12,12,10,10,12,12,12,12,12,10, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, +}; + +static const static_codebook _huff_book_line_2048x27_2sub1 = { + 1, 128, + (char *)_huff_lengthlist_line_2048x27_2sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_3sub1[] = { + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, +}; + +static const static_codebook _huff_book_line_2048x27_3sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_2048x27_3sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_3sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, + 6, 7, 6, 7, 6, 8, 6, 9, 7, 9, 7, 9, 9,11, 9,12, + 10,12, +}; + +static const static_codebook _huff_book_line_2048x27_3sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_2048x27_3sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_3sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 6, 3, 7, 3, 7, 5, 7, 7, 7, 7, 7, 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, +}; + +static const static_codebook _huff_book_line_2048x27_3sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_2048x27_3sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_4sub1[] = { + 0, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 5, 4, 5, 4, + 4, 5, +}; + +static const static_codebook _huff_book_line_2048x27_4sub1 = { + 1, 18, + (char *)_huff_lengthlist_line_2048x27_4sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_4sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 2, 4, 3, 4, 4, 4, 5, 5, 6, 5, 6, 5, 7, + 6, 6, 6, 7, 7, 7, 8, 9, 9, 9,12,10,11,10,10,12, + 10,10, +}; + +static const static_codebook _huff_book_line_2048x27_4sub2 = { + 1, 50, + (char *)_huff_lengthlist_line_2048x27_4sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_2048x27_4sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 6, 5, 7, 5, 7, 7, 7, 7, 7, 5, 7, 5, 7, + 5, 7, 5, 7, 7, 7, 7, 7, 4, 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, +}; + +static const static_codebook _huff_book_line_2048x27_4sub3 = { + 1, 128, + (char *)_huff_lengthlist_line_2048x27_4sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4low_class0[] = { + 4, 5, 6,11, 5, 5, 6,10, 7, 7, 6, 6,14,13, 9, 9, + 6, 6, 6,10, 6, 6, 6, 9, 8, 7, 7, 9,14,12, 8,11, + 8, 7, 7,11, 8, 8, 7,11, 9, 9, 7, 9,13,11, 9,13, + 19,19,18,19,15,16,16,19,11,11,10,13,10,10, 9,15, + 5, 5, 6,13, 6, 6, 6,11, 8, 7, 6, 7,14,11,10,11, + 6, 6, 6,12, 7, 6, 6,11, 8, 7, 7,11,13,11, 9,11, + 9, 7, 6,12, 8, 7, 6,12, 9, 8, 8,11,13,10, 7,13, + 19,19,17,19,17,14,14,19,12,10, 8,12,13,10, 9,16, + 7, 8, 7,12, 7, 7, 7,11, 8, 7, 7, 8,12,12,11,11, + 8, 8, 7,12, 8, 7, 6,11, 8, 7, 7,10,10,11,10,11, + 9, 8, 8,13, 9, 8, 7,12,10, 9, 7,11, 9, 8, 7,11, + 18,18,15,18,18,16,17,18,15,11,10,18,11, 9, 9,18, + 16,16,13,16,12,11,10,16,12,11, 9, 6,15,12,11,13, + 16,16,14,14,13,11,12,16,12, 9, 9,13,13,10,10,12, + 17,18,17,17,14,15,14,16,14,12,14,15,12,10,11,12, + 18,18,18,18,18,18,18,18,18,12,13,18,16,11, 9,18, +}; + +static const static_codebook _huff_book_line_256x4low_class0 = { + 1, 256, + (char *)_huff_lengthlist_line_256x4low_class0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4low_0sub0[] = { + 1, 3, 2, 3, +}; + +static const static_codebook _huff_book_line_256x4low_0sub0 = { + 1, 4, + (char *)_huff_lengthlist_line_256x4low_0sub0, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4low_0sub1[] = { + 0, 0, 0, 0, 2, 3, 2, 3, 3, 3, +}; + +static const static_codebook _huff_book_line_256x4low_0sub1 = { + 1, 10, + (char *)_huff_lengthlist_line_256x4low_0sub1, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4low_0sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4, 3, 4, + 4, 4, 4, 4, 5, 5, 5, 6, 6, +}; + +static const static_codebook _huff_book_line_256x4low_0sub2 = { + 1, 25, + (char *)_huff_lengthlist_line_256x4low_0sub2, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist_line_256x4low_0sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 2, 4, 3, 5, 4, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 8, 6, 9, + 7,12,11,16,13,16,12,15,13,15,12,14,12,15,15,15, +}; + +static const static_codebook _huff_book_line_256x4low_0sub3 = { + 1, 64, + (char *)_huff_lengthlist_line_256x4low_0sub3, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + diff --git a/vendor/vorbis/lib/books/uncoupled/Makefile.am b/vendor/vorbis/lib/books/uncoupled/Makefile.am new file mode 100644 index 0000000..93ff417 --- /dev/null +++ b/vendor/vorbis/lib/books/uncoupled/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = res_books_uncoupled.h diff --git a/vendor/vorbis/lib/books/uncoupled/res_books_uncoupled.h b/vendor/vorbis/lib/books/uncoupled/res_books_uncoupled.h new file mode 100644 index 0000000..107e22f --- /dev/null +++ b/vendor/vorbis/lib/books/uncoupled/res_books_uncoupled.h @@ -0,0 +1,7757 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: static codebooks autogenerated by huff/huffbuld + + ********************************************************************/ + +#include "codebook.h" + +static const long _vq_quantlist__16u0__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u0__p1_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 8, 5, 8, 8, 8,10,10, 8, + 10,11, 5, 8, 8, 8,10,10, 8,10,10, 4, 9, 9, 9,12, + 11, 8,11,11, 8,12,11,10,12,14,10,13,13, 7,11,11, + 10,14,12,11,14,14, 4, 9, 9, 8,11,11, 9,11,12, 7, + 11,11,10,13,14,10,12,14, 8,11,12,10,14,14,10,13, + 12, +}; + +static const static_codebook _16u0__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__16u0__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16u0__p1_0, + 0 +}; + +static const long _vq_quantlist__16u0__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u0__p2_0[] = { + 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 9, 7, + 8, 9, 5, 7, 7, 7, 9, 8, 7, 9, 7, 4, 7, 7, 7, 9, + 9, 7, 8, 8, 6, 9, 8, 7, 8,11, 9,11,10, 6, 8, 9, + 8,11, 8, 9,10,11, 4, 7, 7, 7, 8, 8, 7, 9, 9, 6, + 9, 8, 9,11,10, 8, 8,11, 6, 8, 9, 9,10,11, 8,11, + 8, +}; + +static const static_codebook _16u0__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__16u0__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16u0__p2_0, + 0 +}; + +static const long _vq_quantlist__16u0__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16u0__p3_0[] = { + 1, 5, 5, 7, 7, 6, 7, 7, 8, 8, 6, 7, 8, 8, 8, 8, + 9, 9,11,11, 8, 9, 9,11,11, 6, 9, 8,10,10, 8,10, + 10,11,11, 8,10,10,11,11,10,11,10,13,12, 9,11,10, + 13,13, 6, 8, 9,10,10, 8,10,10,11,11, 8,10,10,11, + 11, 9,10,11,13,12,10,10,11,12,12, 8,11,11,14,13, + 10,12,11,15,13, 9,12,11,15,14,12,14,13,16,14,12, + 13,13,17,14, 8,11,11,13,14, 9,11,12,14,15,10,11, + 12,13,15,11,13,13,14,16,12,13,14,14,16, 5, 9, 9, + 11,11, 9,11,11,12,12, 8,11,11,12,12,11,12,12,15, + 14,10,12,12,15,15, 8,11,11,13,12,10,12,12,13,13, + 10,12,12,14,13,12,12,13,14,15,11,13,13,17,16, 7, + 11,11,13,13,10,12,12,14,13,10,12,12,13,14,12,13, + 12,15,14,11,13,13,15,14, 9,12,12,16,15,11,13,13, + 17,16,10,13,13,16,16,13,14,15,15,16,13,15,14,19, + 17, 9,12,12,14,16,11,13,13,15,16,10,13,13,17,16, + 13,14,13,17,15,12,15,15,16,17, 5, 9, 9,11,11, 8, + 11,11,13,12, 9,11,11,12,12,10,12,12,14,15,11,12, + 12,14,14, 7,11,10,13,12,10,12,12,14,13,10,11,12, + 13,13,11,13,13,15,16,12,12,13,15,15, 7,11,11,13, + 13,10,13,13,14,14,10,12,12,13,13,11,13,13,16,15, + 12,13,13,15,14, 9,12,12,15,15,10,13,13,17,16,11, + 12,13,15,15,12,15,14,18,18,13,14,14,16,17, 9,12, + 12,15,16,10,13,13,15,16,11,13,13,15,16,13,15,15, + 17,17,13,15,14,16,15, 7,11,11,15,16,10,13,12,16, + 17,10,12,13,15,17,15,16,16,18,17,13,15,15,17,18, + 8,12,12,16,16,11,13,14,17,18,11,13,13,18,16,15, + 17,16,17,19,14,15,15,17,16, 8,12,12,16,15,11,14, + 13,18,17,11,13,14,18,17,15,16,16,18,17,13,16,16, + 18,18,11,15,14,18,17,13,14,15,18, 0,12,15,15, 0, + 17,17,16,17,17,18,14,16,18,18, 0,11,14,14,17, 0, + 12,15,14,17,19,12,15,14,18, 0,15,18,16, 0,17,14, + 18,16,18, 0, 7,11,11,16,15,10,12,12,18,16,10,13, + 13,16,15,13,15,14,17,17,14,16,16,19,18, 8,12,12, + 16,16,11,13,13,18,16,11,13,14,17,16,14,15,15,19, + 18,15,16,16, 0,19, 8,12,12,16,17,11,13,13,17,17, + 11,14,13,17,17,13,15,15,17,19,15,17,17,19, 0,11, + 14,15,19,17,12,15,16,18,18,12,14,15,19,17,14,16, + 17, 0,18,16,16,19,17, 0,11,14,14,18,19,12,15,14, + 17,17,13,16,14,17,16,14,17,16,18,18,15,18,15, 0, + 18, +}; + +static const static_codebook _16u0__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__16u0__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16u0__p3_0, + 0 +}; + +static const long _vq_quantlist__16u0__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16u0__p4_0[] = { + 3, 5, 5, 8, 8, 6, 6, 6, 9, 9, 6, 6, 6, 9, 9, 9, + 10, 9,11,11, 9, 9, 9,11,11, 6, 7, 7,10,10, 7, 7, + 8,10,10, 7, 7, 8,10,10,10,10,10,11,12, 9,10,10, + 11,12, 6, 7, 7,10,10, 7, 8, 7,10,10, 7, 8, 7,10, + 10,10,11,10,12,11,10,10,10,13,10, 9,10,10,12,12, + 10,11,10,14,12, 9,11,11,13,13,11,12,13,13,13,11, + 12,12,15,13, 9,10,10,12,13, 9,11,10,12,13,10,10, + 11,12,13,11,12,12,12,13,11,12,12,13,13, 5, 7, 7, + 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,10,12, + 13,10,10,11,12,12, 6, 8, 8,11,10, 7, 8, 9,10,12, + 8, 9, 9,11,11,11,10,11,11,12,10,11,11,13,12, 7, + 8, 8,10,11, 8, 9, 8,11,10, 8, 9, 9,11,11,10,12, + 10,13,11,10,11,11,13,13,10,11,10,14,13,10,10,11, + 13,13,10,12,11,14,13,12,11,13,12,13,13,12,13,14, + 14,10,11,11,13,13,10,11,10,12,13,10,12,12,12,14, + 12,12,12,14,12,12,13,12,17,15, 5, 7, 7,10,10, 7, + 8, 8,10,10, 7, 8, 8,11,10,10,10,11,12,12,10,11, + 11,12,13, 6, 8, 8,11,10, 8, 9, 9,11,11, 7, 8, 9, + 10,11,11,11,11,12,12,10,10,11,12,13, 6, 8, 8,10, + 11, 8, 9, 9,11,11, 7, 9, 7,11,10,10,12,12,13,13, + 11,11,10,13,11, 9,11,10,14,13,11,11,11,15,13,10, + 10,11,13,13,12,13,13,14,14,12,11,12,12,13,10,11, + 11,12,13,10,11,12,13,13,10,11,10,13,12,12,12,13, + 14, 0,12,13,11,13,11, 8,10,10,13,13,10,11,11,14, + 13,10,11,11,13,12,13,14,14,14,15,12,12,12,15,14, + 9,11,10,13,12,10,10,11,13,14,11,11,11,15,12,13, + 12,14,15,16,13,13,13,14,13, 9,11,11,12,12,10,12, + 11,13,13,10,11,11,13,14,13,13,13,15,15,13,13,14, + 17,15,11,12,12,14,14,10,11,12,13,15,12,13,13, 0, + 15,13,11,14,12,16,14,16,14, 0,15,11,12,12,14,16, + 11,13,12,16,15,12,13,13,14,15,12,14,12,15,13,15, + 14,14,16,16, 8,10,10,13,13,10,11,10,13,14,10,11, + 11,13,13,13,13,12,14,14,14,13,13,16,17, 9,10,10, + 12,14,10,12,11,14,13,10,11,12,13,14,12,12,12,15, + 15,13,13,13,14,14, 9,10,10,13,13,10,11,12,12,14, + 10,11,10,13,13,13,13,13,14,16,13,13,13,14,14,11, + 12,13,15,13,12,14,13,14,16,12,12,13,13,14,13,14, + 14,17,15,13,12,17,13,16,11,12,13,14,15,12,13,14, + 14,17,11,12,11,14,14,13,16,14,16, 0,14,15,11,15, + 11, +}; + +static const static_codebook _16u0__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__16u0__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16u0__p4_0, + 0 +}; + +static const long _vq_quantlist__16u0__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16u0__p5_0[] = { + 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8, + 9, 9, 4, 6, 6, 8, 8, 8, 8, 9, 9, 7, 8, 8, 9, 9, + 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,11, 7, 8, 8, + 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9, + 9, 9,10,10,11,11,12,12, 9, 9, 9,10,10,11,11,12, + 12, +}; + +static const static_codebook _16u0__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__16u0__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16u0__p5_0, + 0 +}; + +static const long _vq_quantlist__16u0__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16u0__p6_0[] = { + 1, 4, 4, 7, 7,10,10,12,12,13,13,18,17, 3, 6, 6, + 9, 9,11,11,13,13,14,14,18,17, 3, 6, 6, 9, 9,11, + 11,13,13,14,14,17,18, 7, 9, 9,11,11,13,13,14,14, + 15,15, 0, 0, 7, 9, 9,11,11,13,13,14,14,15,16,19, + 18,10,11,11,13,13,14,14,16,15,17,18, 0, 0,10,11, + 11,13,13,14,14,15,15,16,18, 0, 0,11,13,13,14,14, + 15,15,17,17, 0,19, 0, 0,11,13,13,14,14,14,15,16, + 18, 0,19, 0, 0,13,14,14,15,15,18,17,18,18, 0,19, + 0, 0,13,14,14,15,16,16,16,18,18,19, 0, 0, 0,16, + 17,17, 0,17,19,19, 0,19, 0, 0, 0, 0,16,19,16,17, + 18, 0,19, 0, 0, 0, 0, 0, 0, +}; + +static const static_codebook _16u0__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__16u0__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__16u0__p6_0, + 0 +}; + +static const long _vq_quantlist__16u0__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16u0__p6_1[] = { + 1, 4, 5, 6, 6, 4, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, + 6, 6, 7, 7, 6, 6, 6, 7, 7, +}; + +static const static_codebook _16u0__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__16u0__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16u0__p6_1, + 0 +}; + +static const long _vq_quantlist__16u0__p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u0__p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 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 static_codebook _16u0__p7_0 = { + 4, 81, + (char *)_vq_lengthlist__16u0__p7_0, + 1, -518803456, 1628680192, 2, 0, + (long *)_vq_quantlist__16u0__p7_0, + 0 +}; + +static const long _vq_quantlist__16u0__p7_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16u0__p7_1[] = { + 1, 5, 5, 6, 5, 9,10,11,11,10,10,10,10,10,10, 5, + 8, 8, 8,10,10,10,10,10,10,10,10,10,10,10, 5, 8, + 9, 9, 9,10,10,10,10,10,10,10,10,10,10, 5,10, 8, + 10,10,10,10,10,10,10,10,10,10,10,10, 4, 8, 9,10, + 10,10,10,10,10,10,10,10,10,10,10, 9,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10, 9,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _16u0__p7_1 = { + 2, 225, + (char *)_vq_lengthlist__16u0__p7_1, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__16u0__p7_1, + 0 +}; + +static const long _vq_quantlist__16u0__p7_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__16u0__p7_2[] = { + 1, 6, 6, 7, 8, 7, 7,10, 9,10, 9,11,10, 9,11,10, + 9, 9, 9, 9,10, 6, 8, 7, 9, 9, 8, 8,10,10, 9,11, + 11,12,12,10, 9,11, 9,12,10, 9, 6, 9, 8, 9,12, 8, + 8,11, 9,11,11,12,11,12,12,10,11,11,10,10,11, 7, + 10, 9, 9, 9, 9, 9,10, 9,10, 9,10,10,12,10,10,10, + 11,12,10,10, 7, 9, 9, 9,10, 9, 9,10,10, 9, 9, 9, + 11,11,10,10,10,10, 9, 9,12, 7, 9,10, 9,11, 9,10, + 9,10,11,11,11,10,11,12, 9,12,11,10,10,10, 7, 9, + 9, 9, 9,10,12,10, 9,11,12,10,11,12,12,11, 9,10, + 11,10,11, 7, 9,10,10,11,10, 9,10,11,11,11,10,12, + 12,12,11,11,10,11,11,12, 8, 9,10,12,11,10,10,12, + 12,12,12,12,10,11,11, 9,11,10,12,11,11, 8, 9,10, + 10,11,12,11,11,10,10,10,12,12,12, 9,10,12,12,12, + 12,12, 8,10,11,10,10,12, 9,11,12,12,11,12,12,12, + 12,10,12,10,10,10,10, 8,12,11,11,11,10,10,11,12, + 12,12,12,11,12,12,12,11,11,11,12,10, 9,10,10,12, + 10,12,10,12,12,10,10,10,11,12,12,12,11,12,12,12, + 11,10,11,12,12,12,11,12,12,11,12,12,11,12,12,12, + 12,11,12,12,10,10,10,10,11,11,12,11,12,12,12,12, + 12,12,12,11,12,11,10,11,11,12,11,11, 9,10,10,10, + 12,10,10,11, 9,11,12,11,12,11,12,12,10,11,10,12, + 9, 9, 9,12,11,10,11,10,12,10,12,10,12,12,12,11, + 11,11,11,11,10, 9,10,10,11,10,11,11,12,11,10,11, + 12,12,12,11,11, 9,12,10,12, 9,10,12,10,10,11,10, + 11,11,12,11,10,11,10,11,11,11,11,12,11,11,10, 9, + 10,10,10, 9,11,11,10, 9,12,10,11,12,11,12,12,11, + 12,11,12,11,10,11,10,12,11,12,11,12,11,12,10,11, + 10,10,12,11,10,11,11,11,10, +}; + +static const static_codebook _16u0__p7_2 = { + 2, 441, + (char *)_vq_lengthlist__16u0__p7_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__16u0__p7_2, + 0 +}; + +static const char _huff_lengthlist__16u0__single[] = { + 3, 5, 8, 7,14, 8, 9,19, 5, 2, 5, 5, 9, 6, 9,19, + 8, 4, 5, 7, 8, 9,13,19, 7, 4, 6, 5, 9, 6, 9,19, + 12, 8, 7, 9,10,11,13,19, 8, 5, 8, 6, 9, 6, 7,19, + 8, 8,10, 7, 7, 4, 5,19,12,17,19,15,18,13,11,18, +}; + +static const static_codebook _huff_book__16u0__single = { + 2, 64, + (char *)_huff_lengthlist__16u0__single, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__16u1__long[] = { + 3, 6,10, 8,12, 8,14, 8,14,19, 5, 3, 5, 5, 7, 6, + 11, 7,16,19, 7, 5, 6, 7, 7, 9,11,12,19,19, 6, 4, + 7, 5, 7, 6,10, 7,18,18, 8, 6, 7, 7, 7, 7, 8, 9, + 18,18, 7, 5, 8, 5, 7, 5, 8, 6,18,18,12, 9,10, 9, + 9, 9, 8, 9,18,18, 8, 7,10, 6, 8, 5, 6, 4,11,18, + 11,15,16,12,11, 8, 8, 6, 9,18,14,18,18,18,16,16, + 16,13,16,18, +}; + +static const static_codebook _huff_book__16u1__long = { + 2, 100, + (char *)_huff_lengthlist__16u1__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__16u1__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u1__p1_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 7, 7,10,10, 7, + 9,10, 5, 7, 8, 7,10, 9, 7,10,10, 5, 8, 8, 8,10, + 10, 8,10,10, 7,10,10,10,11,12,10,12,13, 7,10,10, + 9,13,11,10,12,13, 5, 8, 8, 8,10,10, 8,10,10, 7, + 10,10,10,12,12, 9,11,12, 7,10,11,10,12,12,10,13, + 11, +}; + +static const static_codebook _16u1__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__16u1__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16u1__p1_0, + 0 +}; + +static const long _vq_quantlist__16u1__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u1__p2_0[] = { + 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 7, 8, 6, + 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 7, 5, 6, 6, 6, 8, + 8, 6, 8, 8, 6, 8, 8, 7, 7,10, 8, 9, 9, 6, 8, 8, + 7, 9, 8, 8, 9,10, 5, 6, 6, 6, 8, 8, 7, 8, 8, 6, + 8, 8, 8,10, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 7,10, + 8, +}; + +static const static_codebook _16u1__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__16u1__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16u1__p2_0, + 0 +}; + +static const long _vq_quantlist__16u1__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16u1__p3_0[] = { + 1, 5, 5, 8, 8, 6, 7, 7, 9, 9, 5, 7, 7, 9, 9, 9, + 10, 9,11,11, 9, 9,10,11,11, 6, 8, 8,10,10, 8, 9, + 10,11,11, 8, 9,10,11,11,10,11,11,12,13,10,11,11, + 13,13, 6, 8, 8,10,10, 8,10, 9,11,11, 8,10, 9,11, + 11,10,11,11,13,13,10,11,11,13,12, 9,11,11,14,13, + 10,12,12,15,14,10,12,11,14,13,12,13,13,15,15,12, + 13,13,16,14, 9,11,11,13,14,10,11,12,14,14,10,12, + 12,14,15,12,13,13,14,15,12,13,14,15,16, 5, 8, 8, + 11,11, 8,10,10,12,12, 8,10,10,12,12,11,12,12,14, + 14,11,12,12,14,14, 8,10,10,12,12, 9,11,12,12,13, + 10,12,12,13,13,12,12,13,14,15,11,13,13,15,15, 7, + 10,10,12,12, 9,12,11,13,12,10,11,12,13,13,12,13, + 12,15,14,11,12,13,15,15,10,12,12,15,14,11,13,13, + 16,15,11,13,13,16,15,14,13,14,15,16,13,15,15,17, + 17,10,12,12,14,15,11,12,12,15,15,11,13,13,15,16, + 13,15,13,16,15,13,15,15,16,17, 5, 8, 8,11,11, 8, + 10,10,12,12, 8,10,10,12,12,11,12,12,14,14,11,12, + 12,14,14, 7,10,10,12,12,10,12,12,14,13, 9,11,12, + 12,13,12,13,13,15,15,12,12,13,13,15, 7,10,10,12, + 13,10,11,12,13,13,10,12,11,13,13,11,13,13,15,15, + 12,13,12,15,14, 9,12,12,15,14,11,13,13,15,15,11, + 12,13,15,15,13,14,14,17,19,13,13,14,16,16,10,12, + 12,14,15,11,13,13,15,16,11,13,12,16,15,13,15,15, + 17,18,14,15,13,16,15, 8,11,11,15,14,10,12,12,16, + 15,10,12,12,16,16,14,15,15,18,17,13,14,15,16,18, + 9,12,12,15,15,11,12,14,16,17,11,13,13,16,15,15, + 15,15,17,18,14,15,16,17,17, 9,12,12,15,15,11,14, + 13,16,16,11,13,13,16,16,15,16,15,17,18,14,16,15, + 17,16,12,14,14,17,16,12,14,15,18,17,13,15,15,17, + 17,15,15,18,16,20,15,16,17,18,18,11,14,14,16,17, + 13,15,14,18,17,13,15,15,17,17,15,17,15,18,17,15, + 17,16,19,18, 8,11,11,14,15,10,12,12,15,15,10,12, + 12,16,16,13,14,14,17,16,14,15,15,17,17, 9,12,12, + 15,16,11,13,13,16,16,11,12,13,16,16,14,16,15,20, + 17,14,16,16,17,17, 9,12,12,15,16,11,13,13,16,17, + 11,13,13,17,16,14,15,15,17,18,15,15,15,18,18,11, + 14,14,17,16,13,15,15,17,17,13,14,14,18,17,15,16, + 16,18,19,15,15,17,17,19,11,14,14,16,17,13,15,14, + 17,19,13,15,14,18,17,15,17,16,18,18,15,17,15,18, + 16, +}; + +static const static_codebook _16u1__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__16u1__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16u1__p3_0, + 0 +}; + +static const long _vq_quantlist__16u1__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16u1__p4_0[] = { + 4, 5, 5, 8, 8, 6, 6, 7, 9, 9, 6, 6, 6, 9, 9, 9, + 10, 9,11,11, 9, 9,10,11,11, 6, 7, 7,10, 9, 7, 7, + 8, 9,10, 7, 7, 8,10,10,10,10,10,10,12, 9, 9,10, + 11,12, 6, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 7,10, + 10, 9,10, 9,12,11,10,10, 9,12,10, 9,10,10,12,11, + 10,10,10,12,12, 9,10,10,12,12,12,11,12,13,13,11, + 11,12,12,13, 9,10,10,11,12, 9,10,10,12,12,10,10, + 10,12,12,11,12,11,14,13,11,12,12,14,13, 5, 7, 7, + 10,10, 7, 8, 8,10,10, 7, 8, 7,10,10,10,10,10,12, + 12,10,10,10,12,12, 6, 8, 7,10,10, 7, 7, 9,10,11, + 8, 9, 9,11,10,10,10,11,11,13,10,10,11,12,13, 6, + 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,10,11,10,11, + 10,13,11,10,11,10,12,12,10,11,10,12,11,10,10,10, + 12,13,10,11,11,13,12,11,11,13,11,14,12,12,13,14, + 14, 9,10,10,12,13,10,11,10,13,12,10,11,11,12,13, + 11,12,11,14,12,12,13,13,15,14, 5, 7, 7,10,10, 7, + 7, 8,10,10, 7, 8, 8,10,10,10,10,10,11,12,10,10, + 10,12,12, 7, 8, 8,10,10, 8, 9, 8,11,10, 7, 8, 9, + 10,11,10,11,11,12,12,10,10,11,11,13, 7, 7, 8,10, + 10, 8, 8, 9,10,11, 7, 9, 7,11,10,10,11,11,13,12, + 11,11,10,13,11, 9,10,10,12,12,10,11,11,13,12,10, + 10,11,12,12,12,13,13,14,14,11,11,12,12,14,10,10, + 11,12,12,10,11,11,12,13,10,10,10,13,12,12,13,13, + 15,14,12,13,10,14,11, 8,10,10,12,12,10,11,10,13, + 13, 9,10,10,12,12,12,13,13,15,14,11,12,12,13,13, + 9,10,10,13,12,10,10,11,13,13,10,11,10,13,12,12, + 12,13,14,15,12,13,12,15,13, 9,10,10,12,13,10,11, + 10,13,12,10,10,11,12,13,12,14,12,15,13,12,12,13, + 14,15,11,12,11,14,13,11,11,12,14,15,12,13,12,15, + 14,13,11,15,11,16,13,14,14,16,15,11,12,12,14,14, + 11,12,11,14,13,12,12,13,14,15,13,14,12,16,12,14, + 14,14,15,15, 8,10,10,12,12, 9,10,10,12,12,10,10, + 11,13,13,11,12,12,13,13,12,13,13,14,15, 9,10,10, + 13,12,10,11,11,13,12,10,10,11,13,13,12,13,12,15, + 14,12,12,13,13,16, 9, 9,10,12,13,10,10,11,12,13, + 10,11,10,13,13,12,12,13,13,15,13,13,12,15,13,11, + 12,12,14,14,12,13,12,15,14,11,11,12,13,14,14,14, + 14,16,15,13,12,15,12,16,11,11,12,13,14,12,13,13, + 14,15,10,12,11,14,13,14,15,14,16,16,13,14,11,15, + 11, +}; + +static const static_codebook _16u1__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__16u1__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16u1__p4_0, + 0 +}; + +static const long _vq_quantlist__16u1__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16u1__p5_0[] = { + 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8, + 10,10, 4, 5, 6, 8, 8, 8, 8,10,10, 7, 8, 8, 9, 9, + 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 7, 8, 8, + 10, 9,11,11,12,11, 7, 8, 8, 9, 9,11,11,12,12, 9, + 10,10,11,11,12,12,13,12, 9,10,10,11,11,12,12,12, + 13, +}; + +static const static_codebook _16u1__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__16u1__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16u1__p5_0, + 0 +}; + +static const long _vq_quantlist__16u1__p6_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16u1__p6_0[] = { + 3, 4, 4, 6, 6, 7, 7, 9, 9, 4, 4, 4, 6, 6, 8, 8, + 9, 9, 4, 4, 4, 6, 6, 7, 7, 9, 9, 6, 6, 6, 7, 7, + 8, 8,10, 9, 6, 6, 6, 7, 7, 8, 8, 9,10, 7, 8, 7, + 8, 8, 9, 9,10,10, 7, 8, 8, 8, 8, 9, 9,10,10, 9, + 9, 9,10,10,10,10,11,11, 9, 9, 9,10,10,10,10,11, + 11, +}; + +static const static_codebook _16u1__p6_0 = { + 2, 81, + (char *)_vq_lengthlist__16u1__p6_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16u1__p6_0, + 0 +}; + +static const long _vq_quantlist__16u1__p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u1__p7_0[] = { + 1, 4, 4, 4, 8, 8, 4, 8, 8, 5,11, 9, 8,12,11, 8, + 12,11, 5,10,11, 8,11,12, 8,11,12, 4,11,11,11,14, + 13,10,13,13, 8,14,13,12,14,16,12,16,15, 8,14,14, + 13,16,14,12,15,16, 4,11,11,10,14,13,11,14,14, 8, + 15,14,12,15,15,12,14,16, 8,14,14,11,16,15,12,15, + 13, +}; + +static const static_codebook _16u1__p7_0 = { + 4, 81, + (char *)_vq_lengthlist__16u1__p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__16u1__p7_0, + 0 +}; + +static const long _vq_quantlist__16u1__p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16u1__p7_1[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 6, 5, 7, 7, + 8, 8, 8, 8, 8, 8, 4, 5, 6, 7, 7, 8, 8, 8, 8, 8, + 8, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 7, 8, 8, 8, 8, 9, 9, 9,10, + 9,10, 7, 8, 8, 8, 8, 9, 9, 9, 9,10, 9, 8, 8, 8, + 9, 9,10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9,10, + 10,10,10, 8, 8, 8, 9, 9, 9,10,10,10,10,10, 8, 8, + 8, 9, 9,10,10,10,10,10,10, +}; + +static const static_codebook _16u1__p7_1 = { + 2, 121, + (char *)_vq_lengthlist__16u1__p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16u1__p7_1, + 0 +}; + +static const long _vq_quantlist__16u1__p8_0[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16u1__p8_0[] = { + 1, 4, 4, 5, 5, 8, 8,10,10,12,12, 4, 7, 7, 8, 8, + 9, 9,12,11,14,13, 4, 7, 7, 7, 8, 9,10,11,11,13, + 12, 5, 8, 8, 9, 9,11,11,12,13,15,14, 5, 7, 8, 9, + 9,11,11,13,13,17,15, 8, 9,10,11,11,12,13,17,14, + 17,16, 8,10, 9,11,11,12,12,13,15,15,17,10,11,11, + 12,13,14,15,15,16,16,17, 9,11,11,12,12,14,15,17, + 15,15,16,11,14,12,14,15,16,15,16,16,16,15,11,13, + 13,14,14,15,15,16,16,15,16, +}; + +static const static_codebook _16u1__p8_0 = { + 2, 121, + (char *)_vq_lengthlist__16u1__p8_0, + 1, -524582912, 1618345984, 4, 0, + (long *)_vq_quantlist__16u1__p8_0, + 0 +}; + +static const long _vq_quantlist__16u1__p8_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16u1__p8_1[] = { + 2, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 4, 6, 6, 7, 7, + 8, 7, 8, 8, 8, 8, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, +}; + +static const static_codebook _16u1__p8_1 = { + 2, 121, + (char *)_vq_lengthlist__16u1__p8_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16u1__p8_1, + 0 +}; + +static const long _vq_quantlist__16u1__p9_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16u1__p9_0[] = { + 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, +}; + +static const static_codebook _16u1__p9_0 = { + 2, 225, + (char *)_vq_lengthlist__16u1__p9_0, + 1, -514071552, 1627381760, 4, 0, + (long *)_vq_quantlist__16u1__p9_0, + 0 +}; + +static const long _vq_quantlist__16u1__p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16u1__p9_1[] = { + 1, 6, 5, 9, 9,10,10, 6, 7, 9, 9,10,10,10,10, 5, + 10, 8,10, 8,10,10, 8, 8,10, 9,10,10,10,10, 5, 8, + 9,10,10,10,10, 8,10,10,10,10,10,10,10, 9,10,10, + 10,10,10,10, 9, 9,10,10,10,10,10,10, 9, 9, 8, 9, + 10,10,10, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10, 8,10,10,10,10, + 10,10,10,10,10,10,10,10,10, 6, 8, 8,10,10,10, 8, + 10,10,10,10,10,10,10,10, 5, 8, 8,10,10,10, 9, 9, + 10,10,10,10,10,10,10,10, 9,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, 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, +}; + +static const static_codebook _16u1__p9_1 = { + 2, 225, + (char *)_vq_lengthlist__16u1__p9_1, + 1, -522338304, 1620115456, 4, 0, + (long *)_vq_quantlist__16u1__p9_1, + 0 +}; + +static const long _vq_quantlist__16u1__p9_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__16u1__p9_2[] = { + 1, 6, 6, 7, 8, 8,11,10, 9, 9,11, 9,10, 9,11,11, + 9, 6, 7, 6,11, 8,11, 9,10,10,11, 9,11,10,10,10, + 11, 9, 5, 7, 7, 8, 8,10,11, 8, 8,11, 9, 9,10,11, + 9,10,11, 8, 9, 6, 8, 8, 9, 9,10,10,11,11,11, 9, + 11,10, 9,11, 8, 8, 8, 9, 8, 9,10,11, 9, 9,11,11, + 10, 9, 9,11,10, 8,11, 8, 9, 8,11, 9,10, 9,10,11, + 11,10,10, 9,10,10, 8, 8, 9,10,10,10, 9,11, 9,10, + 11,11,11,11,10, 9,11, 9, 9,11,11,10, 8,11,11,11, + 9,10,10,11,10,11,11, 9,11,10, 9,11,10,10,10,10, + 9,11,10,11,10, 9, 9,10,11, 9, 8,10,11,11,10,10, + 11, 9,11,10,11,11,10,11, 9, 9, 8,10, 8, 9,11, 9, + 8,10,10, 9,11,10,11,10,11, 9,11, 8,10,11,11,11, + 11,10,10,11,11,11,11,10,11,11,10, 9, 8,10,10, 9, + 11,10,11,11,11, 9, 9, 9,11,11,11,10,10, 9, 9,10, + 9,11,11,11,11, 8,10,11,10,11,11,10,11,11, 9, 9, + 9,10, 9,11, 9,11,11,11,11,11,10,11,11,10,11,10, + 11,11, 9,11,10,11,10, 9,10, 9,10,10,11,11,11,11, + 9,10, 9,10,11,11,10,11,11,11,11,11,11,10,11,11, + 10, +}; + +static const static_codebook _16u1__p9_2 = { + 2, 289, + (char *)_vq_lengthlist__16u1__p9_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__16u1__p9_2, + 0 +}; + +static const char _huff_lengthlist__16u1__short[] = { + 5, 7,10, 9,11,10,15,11,13,16, 6, 4, 6, 6, 7, 7, + 10, 9,12,16,10, 6, 5, 6, 6, 7,10,11,16,16, 9, 6, + 7, 6, 7, 7,10, 8,14,16,11, 6, 5, 4, 5, 6, 8, 9, + 15,16, 9, 6, 6, 5, 6, 6, 9, 8,14,16,12, 7, 6, 6, + 5, 6, 6, 7,13,16, 8, 6, 7, 6, 5, 5, 4, 4,11,16, + 9, 8, 9, 9, 7, 7, 6, 5,13,16,14,14,16,15,16,15, + 16,16,16,16, +}; + +static const static_codebook _huff_book__16u1__short = { + 2, 100, + (char *)_huff_lengthlist__16u1__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__16u2__long[] = { + 5, 8,10,10,10,11,11,12,14,18, 7, 5, 5, 6, 8, 9, + 10,12,14,17, 9, 5, 4, 5, 6, 8,10,11,13,19, 9, 5, + 4, 4, 5, 6, 9,10,12,17, 8, 6, 5, 4, 4, 5, 7,10, + 11,15, 8, 7, 7, 6, 5, 5, 6, 9,11,14, 8, 9, 8, 7, + 6, 5, 6, 7,11,14, 9,11,11, 9, 7, 6, 6, 6, 9,14, + 11,14,15,13, 9, 8, 7, 7, 9,14,13,15,19,17,12,11, + 10, 9,10,14, +}; + +static const static_codebook _huff_book__16u2__long = { + 2, 100, + (char *)_huff_lengthlist__16u2__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__16u2_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u2_p1_0[] = { + 1, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 9, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 8, 9, 9, 5, 7, 7, 8, 9, + 9, 7, 9, 9, 7, 9, 9, 9,10,11, 9,10,10, 7, 9, 9, + 9,10, 9, 9,10,11, 5, 8, 7, 7, 9, 9, 8, 9, 9, 7, + 9, 9, 9,11,10, 9, 9,10, 7, 9, 9, 9,10,10, 9,11, + 10, +}; + +static const static_codebook _16u2_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__16u2_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__16u2_p1_0, + 0 +}; + +static const long _vq_quantlist__16u2_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16u2_p2_0[] = { + 3, 5, 5, 8, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 9, + 10, 9,11,11, 9, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8, + 8,10,10, 7, 8, 8,10,10,10,10,10,12,12, 9,10,10, + 11,12, 5, 7, 7, 9, 9, 7, 8, 8,10,10, 7, 8, 8,10, + 10, 9,10,10,12,11,10,10,10,12,12, 9,10,10,12,12, + 10,10,10,12,12, 9,10,10,12,12,12,12,12,14,14,11, + 12,12,13,14, 9,10,10,12,12, 9,10,10,12,12,10,10, + 10,12,12,11,12,12,14,13,12,12,12,14,13, 5, 7, 7, + 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12, + 12,10,10,10,12,12, 7, 8, 8,11,10, 8, 9, 9,11,11, + 8, 9, 9,11,11,10,11,11,12,13,10,11,11,12,13, 7, + 8, 8,10,10, 8, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,13,12,10,11,11,13,13,10,11,10,13,12,10,11,11, + 13,13,10,11,11,13,13,12,12,13,13,14,12,13,13,14, + 14, 9,10,10,12,12,10,11,10,13,12,10,11,11,13,13, + 12,13,12,14,13,12,13,13,14,15, 5, 7, 7, 9,10, 7, + 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,12,10,10, + 11,12,12, 7, 8, 8,10,10, 8, 9, 9,11,11, 8, 8, 9, + 10,11,10,11,11,13,13,10,10,11,12,13, 7, 8, 8,10, + 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,11,13,12, + 10,11,11,13,12, 9,10,10,12,12,10,11,11,13,13,10, + 10,11,12,13,12,13,13,15,14,12,12,13,12,14, 9,10, + 11,12,13,10,11,11,13,13,10,11,11,13,13,12,13,13, + 14,14,12,13,12,14,13, 8,10,10,12,12, 9,11,10,13, + 12, 9,10,10,12,13,12,13,13,14,14,12,12,12,14,14, + 9,10,10,13,13,10,11,11,13,13,10,11,11,13,13,13, + 13,13,14,15,12,13,13,14,15, 9,10,10,12,13,10,11, + 10,13,13,10,11,11,12,13,12,13,12,15,14,12,13,13, + 14,15,11,12,12,15,14,12,12,13,14,15,12,13,13,15, + 14,13,13,15,14,16,14,14,14,16,15,11,12,12,14,14, + 11,12,12,14,14,12,13,13,14,15,13,14,13,15,13,14, + 14,14,15,16, 8, 9,10,12,12, 9,10,10,13,12, 9,10, + 11,12,13,12,12,12,14,14,12,13,13,14,14, 9,10,10, + 13,12,10,11,11,13,13,10,10,11,13,13,12,13,13,15, + 14,12,12,13,14,15, 9,10,10,13,13,10,11,11,13,13, + 10,11,11,13,13,12,13,13,14,14,13,13,13,15,15,11, + 12,12,14,13,12,13,13,15,14,11,12,12,14,14,14,14, + 14,16,15,13,13,14,13,16,11,12,12,14,14,12,13,13, + 14,15,12,13,12,14,14,14,14,14,16,16,14,15,13,16, + 14, +}; + +static const static_codebook _16u2_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__16u2_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16u2_p2_0, + 0 +}; + +static const long _vq_quantlist__16u2_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__16u2_p3_0[] = { + 2, 4, 4, 6, 6, 7, 7, 9, 9, 4, 5, 5, 6, 6, 8, 7, + 9, 9, 4, 5, 5, 6, 6, 7, 8, 9, 9, 6, 6, 6, 7, 7, + 8, 8,10,10, 6, 6, 6, 7, 7, 8, 8,10,10, 7, 8, 7, + 8, 8, 9, 9,11,10, 7, 7, 8, 8, 8, 9, 9,10,11, 9, + 9, 9,10,10,11,10,11,11, 9, 9, 9,10,10,10,11,11, + 11, +}; + +static const static_codebook _16u2_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__16u2_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__16u2_p3_0, + 0 +}; + +static const long _vq_quantlist__16u2_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__16u2_p4_0[] = { + 2, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,11, + 11, 5, 5, 5, 7, 6, 8, 7, 9, 9, 9, 9,10,10,11,11, + 12,12, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,11, + 11,12,12, 6, 7, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10, + 11,11,11,11,12,12, 7, 7, 8, 8, 8, 9, 9, 9, 9,10, + 10,11,11,11,11,12,12, 8, 9, 9, 9, 9, 9, 9,10,10, + 10,10,11,11,12,12,12,12, 8, 9, 9, 9, 9, 9, 9,10, + 10,10,10,11,11,12,12,12,12, 9, 9, 9, 9, 9,10,10, + 10,10,10,11,11,11,12,12,13,13, 9, 9, 9, 9, 9,10, + 10,10,10,11,10,11,11,12,12,13,13,10,10,10,10,10, + 11,11,11,11,11,11,11,12,12,12,13,13,10,10,10,10, + 10,11,11,11,11,11,11,12,11,12,12,13,13,11,11,11, + 11,11,11,11,12,12,12,12,12,12,13,13,13,13,11,11, + 11,11,11,11,11,12,12,12,12,13,12,13,13,13,13,11, + 12,12,12,12,12,12,12,12,13,13,13,13,13,13,14,14, + 11,12,12,12,12,12,12,12,13,13,13,13,13,13,13,14, + 14, +}; + +static const static_codebook _16u2_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__16u2_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__16u2_p4_0, + 0 +}; + +static const long _vq_quantlist__16u2_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__16u2_p5_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 7, 9, 9, 7, + 9,10, 5, 8, 8, 7,10, 9, 7,10, 9, 5, 8, 8, 8,11, + 10, 8,10,10, 7,10,10, 9, 9,12,10,12,12, 7,10,10, + 9,12,10,10,11,12, 5, 8, 8, 8,10,10, 8,11,11, 7, + 11,10,10,12,11, 9,10,12, 7,10,11,10,12,12, 9,12, + 9, +}; + +static const static_codebook _16u2_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__16u2_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__16u2_p5_0, + 0 +}; + +static const long _vq_quantlist__16u2_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16u2_p5_1[] = { + 2, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 5, 6, 6, 7, 7, + 7, 7, 8, 8, 8, 8, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, + 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, +}; + +static const static_codebook _16u2_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__16u2_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16u2_p5_1, + 0 +}; + +static const long _vq_quantlist__16u2_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16u2_p6_0[] = { + 1, 5, 4, 7, 7, 8, 8, 8, 8,10,10,11,11, 4, 6, 6, + 7, 7, 9, 9, 9, 9,10,10,11,11, 4, 6, 6, 7, 7, 9, + 9, 9, 9,10,10,11,11, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 7, 7, 7, 9, 8,10, 9,10,10,11,11,12, + 12, 8, 9, 9, 9,10,10,10,11,11,12,12,13,13, 8, 9, + 9,10, 9,10,10,11,11,12,12,13,13, 8, 9, 9,10,10, + 11,11,11,11,12,12,13,13, 8, 9, 9,10,10,11,11,12, + 11,12,12,13,13,10,10,10,11,11,12,12,12,12,13,13, + 14,14,10,10,10,11,11,12,12,12,12,13,13,14,14,11, + 11,11,12,12,13,13,13,13,14,14,14,14,11,11,11,12, + 12,13,13,13,13,14,14,14,14, +}; + +static const static_codebook _16u2_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__16u2_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__16u2_p6_0, + 0 +}; + +static const long _vq_quantlist__16u2_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__16u2_p6_1[] = { + 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _16u2_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__16u2_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__16u2_p6_1, + 0 +}; + +static const long _vq_quantlist__16u2_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__16u2_p7_0[] = { + 1, 4, 4, 7, 7, 8, 8, 8, 8, 9, 9,10,10, 4, 6, 6, + 8, 8, 9, 9, 9, 9,10,10,11,10, 4, 6, 6, 8, 8, 9, + 9, 9, 9,10,10,11,11, 7, 8, 8,10, 9,10,10,10,10, + 11,11,12,12, 7, 8, 8,10,10,10,10,10,10,11,11,12, + 12, 8, 9, 9,10,10,11,11,11,11,12,12,13,13, 8, 9, + 9,10,10,11,11,11,11,12,12,13,13, 8, 9, 9,11,10, + 11,11,12,12,13,13,14,13, 8, 9, 9,10,10,11,11,12, + 12,13,13,13,13, 9,10,10,11,11,12,12,13,13,13,13, + 14,14, 9,10,10,11,11,12,12,13,13,13,13,14,14,10, + 11,11,12,12,13,13,14,13,14,14,15,14,10,11,11,12, + 12,13,13,14,13,14,14,15,14, +}; + +static const static_codebook _16u2_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__16u2_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__16u2_p7_0, + 0 +}; + +static const long _vq_quantlist__16u2_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__16u2_p7_1[] = { + 2, 5, 5, 7, 7, 7, 7, 7, 7, 8, 8, 5, 6, 6, 7, 7, + 7, 7, 8, 8, 8, 8, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _16u2_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__16u2_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__16u2_p7_1, + 0 +}; + +static const long _vq_quantlist__16u2_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16u2_p8_0[] = { + 1, 4, 4, 7, 7, 8, 8, 7, 7, 9, 8,10, 9,11,11, 4, + 7, 6, 9, 8, 9, 9, 9, 9,10, 9,11, 9,12, 9, 4, 6, + 7, 8, 8, 9, 9, 9, 9,10,10,10,11,11,12, 7, 9, 8, + 10,10,11,11,10,10,11,11,12,12,13,12, 7, 8, 8,10, + 10,10,11,10,10,11,11,11,12,12,13, 8, 9, 9,11,11, + 11,11,11,11,12,12,13,13,13,13, 8, 9, 9,11,11,11, + 11,11,11,12,12,13,13,13,14, 8, 9, 9,10,10,11,11, + 12,11,13,13,14,13,14,14, 8, 9, 9,10,10,11,11,12, + 12,12,12,13,13,14,14, 9,10,10,11,11,12,12,13,12, + 13,13,14,14,15,15, 9,10,10,11,11,12,12,12,13,13, + 13,14,14,14,15,10,11,11,12,12,13,13,14,13,14,14, + 15,14,15,15,10,11,11,12,12,13,12,13,14,14,14,14, + 14,15,15,11,12,12,13,13,13,13,14,14,15,14,15,15, + 16,16,11,12,12,13,13,13,13,14,14,14,15,15,15,16, + 16, +}; + +static const static_codebook _16u2_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__16u2_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__16u2_p8_0, + 0 +}; + +static const long _vq_quantlist__16u2_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__16u2_p8_1[] = { + 3, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10,10, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, + 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9,10,10,10,10, + 10,10,10,10, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9,10, 9,10,10,10, 9,10, 9, 8, 8, 8, 9, 8, 9, 9, + 9, 9,10, 9,10,10,10,10,10,10,10,10,10,10, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10, + 10,10,10, 8, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10, + 10,10,10,10,10,10,10,10, 8, 9, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, + 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, + 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10, 9, 9, 9,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10, 9, 9,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10, 9,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10, 9,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _16u2_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__16u2_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__16u2_p8_1, + 0 +}; + +static const long _vq_quantlist__16u2_p9_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__16u2_p9_0[] = { + 1, 5, 3, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, + 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 7, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _16u2_p9_0 = { + 2, 225, + (char *)_vq_lengthlist__16u2_p9_0, + 1, -510036736, 1631393792, 4, 0, + (long *)_vq_quantlist__16u2_p9_0, + 0 +}; + +static const long _vq_quantlist__16u2_p9_1[] = { + 9, + 8, + 10, + 7, + 11, + 6, + 12, + 5, + 13, + 4, + 14, + 3, + 15, + 2, + 16, + 1, + 17, + 0, + 18, +}; + +static const char _vq_lengthlist__16u2_p9_1[] = { + 1, 4, 4, 7, 7, 7, 7, 7, 6, 9, 7,10, 8,12,12,13, + 13,14,14, 4, 7, 7, 9, 9, 9, 8, 9, 8,10, 9,11, 9, + 14, 9,14,10,13,11, 4, 7, 7, 9, 9, 9, 9, 8, 9,10, + 10,11,11,12,13,12,13,14,15, 7, 9, 9,10,11,10,10, + 10,10,11,12,13,13,13,14,17,14,15,16, 7, 9, 9,10, + 10,10,10,10,10,11,12,13,13,14,14,15,15,18,18, 8, + 9, 9,11,10,11,11,11,12,13,12,14,14,16,15,15,17, + 18,15, 8, 9, 9,10,10,11,11,11,11,13,13,14,14,15, + 15,15,16,16,18, 7, 9, 8,10,10,11,11,12,12,14,14, + 15,15,16,16,15,17,16,18, 8, 9, 9,10,10,11,12,12, + 12,13,13,16,15,17,16,17,18,17,18, 9,10,10,12,11, + 13,13,14,13,14,14,15,17,16,18,17,18,17,18, 9,10, + 10,12,11,12,13,13,14,15,16,14,15,16,18,18,18,18, + 17,11,11,11,13,13,14,14,16,15,15,15,16,15,15,18, + 18,18,17,16,11,11,12,13,13,15,14,15,16,16,16,17, + 16,15,18,17,18,16,18,12,13,13,15,15,15,16,18,16, + 17,16,17,16,17,17,17,18,18,17,13,13,13,15,13,16, + 15,17,16,16,16,18,18,18,18,16,17,17,18,13,15,14, + 15,15,18,17,18,18,18,16,18,17,18,17,18,16,17,17, + 14,14,14,15,16,17,16,18,18,18,17,18,17,18,18,18, + 16,16,16,14,17,16,17,15,16,18,18,17,18,17,18,17, + 18,18,18,17,18,17,15,16,15,18,15,18,17,16,18,18, + 18,18,18,18,17,18,16,18,17, +}; + +static const static_codebook _16u2_p9_1 = { + 2, 361, + (char *)_vq_lengthlist__16u2_p9_1, + 1, -518287360, 1622704128, 5, 0, + (long *)_vq_quantlist__16u2_p9_1, + 0 +}; + +static const long _vq_quantlist__16u2_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__16u2_p9_2[] = { + 2, 3, 4, 4, 4, 5, 5, 6, 5, 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, 8, 8, 7, 8, 8, 8, 8, 8, + 8, +}; + +static const static_codebook _16u2_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__16u2_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__16u2_p9_2, + 0 +}; + +static const char _huff_lengthlist__16u2__short[] = { + 8,11,13,13,15,16,19,19,19,19,11, 8, 8, 9, 9,11, + 13,15,19,20,14, 8, 7, 7, 8, 9,12,13,15,20,15, 9, + 6, 5, 5, 7,10,12,14,18,14, 9, 7, 5, 3, 4, 7,10, + 12,16,13,10, 8, 6, 3, 3, 5, 8,11,14,11,10, 9, 7, + 5, 4, 4, 6,11,14,10,10,10, 8, 6, 5, 5, 6,10,14, + 10,10,10, 9, 8, 7, 7, 7,10,14,11,12,12,12,11,10, + 10,10,12,16, +}; + +static const static_codebook _huff_book__16u2__short = { + 2, 100, + (char *)_huff_lengthlist__16u2__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__8u0__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8u0__p1_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7, + 10,10, 5, 8, 8, 7,10,10, 8,10,10, 4, 9, 8, 8,11, + 11, 8,11,11, 7,11,11,10,11,13,10,13,13, 7,11,11, + 10,13,12,10,13,13, 5, 9, 8, 8,11,11, 8,11,11, 7, + 11,11, 9,13,13,10,12,13, 7,11,11,10,13,13,10,13, + 11, +}; + +static const static_codebook _8u0__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__8u0__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__8u0__p1_0, + 0 +}; + +static const long _vq_quantlist__8u0__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8u0__p2_0[] = { + 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 6, 7, 8, 6, + 7, 8, 5, 7, 7, 6, 8, 8, 7, 9, 7, 5, 7, 7, 7, 9, + 9, 7, 8, 8, 6, 9, 8, 7, 7,10, 8,10,10, 6, 8, 8, + 8,10, 8, 8,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 9, 6, + 8, 8, 8,10,10, 8, 8,10, 6, 8, 9, 8,10,10, 7,10, + 8, +}; + +static const static_codebook _8u0__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__8u0__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__8u0__p2_0, + 0 +}; + +static const long _vq_quantlist__8u0__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8u0__p3_0[] = { + 1, 5, 5, 7, 7, 6, 7, 7, 9, 9, 6, 7, 7, 9, 9, 8, + 10, 9,11,11, 8, 9, 9,11,11, 6, 8, 8,10,10, 8,10, + 10,11,11, 8,10,10,11,11,10,11,11,12,12,10,11,11, + 12,13, 6, 8, 8,10,10, 8,10,10,11,11, 8,10,10,11, + 11, 9,10,11,12,12,10,11,11,12,12, 8,11,11,14,13, + 10,12,11,15,13,10,12,11,14,14,12,13,12,16,14,12, + 14,12,16,15, 8,11,11,13,14,10,11,12,13,15,10,11, + 12,13,15,11,12,13,14,15,12,12,14,14,16, 5, 8, 8, + 11,11, 9,11,11,12,12, 8,10,11,12,12,11,12,12,15, + 14,11,12,12,14,14, 7,11,10,13,12,10,11,12,13,14, + 10,12,12,14,13,12,13,13,14,15,12,13,13,15,15, 7, + 10,11,12,13,10,12,11,14,13,10,12,13,13,15,12,13, + 12,14,14,11,13,13,15,16, 9,12,12,15,14,11,13,13, + 15,16,11,13,13,16,16,13,14,15,15,15,12,14,15,17, + 16, 9,12,12,14,15,11,13,13,15,16,11,13,13,16,18, + 13,14,14,17,16,13,15,15,17,18, 5, 8, 9,11,11, 8, + 11,11,12,12, 8,10,11,12,12,11,12,12,14,14,11,12, + 12,14,15, 7,11,10,12,13,10,12,12,14,13,10,11,12, + 13,14,11,13,13,15,14,12,13,13,14,15, 7,10,11,13, + 13,10,12,12,13,14,10,12,12,13,13,11,13,13,16,16, + 12,13,13,15,14, 9,12,12,16,15,10,13,13,15,15,11, + 13,13,17,15,12,15,15,18,17,13,14,14,15,16, 9,12, + 12,15,15,11,13,13,15,16,11,13,13,15,15,12,15,15, + 16,16,13,15,14,17,15, 7,11,11,15,15,10,13,13,16, + 15,10,13,13,15,16,14,15,15,17,19,13,15,14,15,18, + 9,12,12,16,16,11,13,14,17,16,11,13,13,17,16,15, + 15,16,17,19,13,15,16, 0,18, 9,12,12,16,15,11,14, + 13,17,17,11,13,14,16,16,15,16,16,19,18,13,15,15, + 17,19,11,14,14,19,16,12,14,15, 0,18,12,16,15,18, + 17,15,15,18,16,19,14,15,17,19,19,11,14,14,18,19, + 13,15,14,19,19,12,16,15,18,17,15,17,15, 0,16,14, + 17,16,19, 0, 7,11,11,14,14,10,12,12,15,15,10,13, + 13,16,15,13,15,15,17, 0,14,15,15,16,19, 9,12,12, + 16,16,11,14,14,16,16,11,13,13,16,16,14,17,16,19, + 0,14,18,17,17,19, 9,12,12,15,16,11,13,13,15,17, + 12,14,13,19,16,13,15,15,17,19,15,17,16,17,19,11, + 14,14,19,16,12,15,15,19,17,13,14,15,17,19,14,16, + 17,19,19,16,15,16,17,19,11,15,14,16,16,12,15,15, + 19, 0,12,14,15,19,19,14,16,16, 0,18,15,19,14,18, + 16, +}; + +static const static_codebook _8u0__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__8u0__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8u0__p3_0, + 0 +}; + +static const long _vq_quantlist__8u0__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8u0__p4_0[] = { + 3, 5, 5, 8, 8, 5, 6, 7, 9, 9, 6, 7, 6, 9, 9, 9, + 9, 9,10,11, 9, 9, 9,11,10, 6, 7, 7,10,10, 7, 7, + 8,10,10, 7, 8, 8,10,10,10,10,10,10,11, 9,10,10, + 11,12, 6, 7, 7,10,10, 7, 8, 8,10,10, 7, 8, 7,10, + 10, 9,10,10,12,11,10,10,10,11,10, 9,10,10,12,11, + 10,10,10,13,11, 9,10,10,12,12,11,11,12,12,13,11, + 11,11,12,13, 9,10,10,12,12,10,10,11,12,12,10,10, + 11,12,12,11,11,11,13,13,11,12,12,13,13, 5, 7, 7, + 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,11,12, + 12,10,11,10,12,12, 7, 8, 8,11,11, 7, 8, 9,10,11, + 8, 9, 9,11,11,11,10,11,10,12,10,11,11,12,13, 7, + 8, 8,10,11, 8, 9, 8,12,10, 8, 9, 9,11,12,10,11, + 10,13,11,10,11,11,13,12, 9,11,10,13,12,10,10,11, + 12,12,10,11,11,13,13,12,10,13,11,14,11,12,12,15, + 13, 9,11,11,13,13,10,11,11,13,12,10,11,11,12,14, + 12,13,11,14,12,12,12,12,14,14, 5, 7, 7,10,10, 7, + 8, 8,10,10, 7, 8, 8,11,10,10,11,11,12,12,10,11, + 10,12,12, 7, 8, 8,10,11, 8, 9, 9,12,11, 8, 8, 9, + 10,11,10,11,11,12,13,11,10,11,11,13, 6, 8, 8,10, + 11, 8, 9, 9,11,11, 7, 9, 7,11,10,10,11,11,12,12, + 10,11,10,13,10, 9,11,10,13,12,10,12,11,13,13,10, + 10,11,12,13,11,12,13,15,14,11,11,13,12,13, 9,10, + 11,12,13,10,11,11,12,13,10,11,10,13,12,12,13,13, + 13,14,12,12,11,14,11, 8,10,10,12,13,10,11,11,13, + 13,10,11,10,13,13,12,13,14,15,14,12,12,12,14,13, + 9,10,10,13,12,10,10,12,13,13,10,11,11,15,12,12, + 12,13,15,14,12,13,13,15,13, 9,10,11,12,13,10,12, + 10,13,12,10,11,11,12,13,12,14,12,15,13,12,12,12, + 15,14,11,12,11,14,13,11,11,12,14,14,12,13,13,14, + 13,13,11,15,11,15,14,14,14,16,15,11,12,12,13,14, + 11,13,11,14,14,12,12,13,14,15,12,14,12,15,12,13, + 15,14,16,15, 8,10,10,12,12,10,10,10,12,13,10,11, + 11,13,13,12,12,12,13,14,13,13,13,15,15, 9,10,10, + 12,12,10,11,11,13,12,10,10,11,13,13,12,12,12,14, + 14,12,12,13,15,14, 9,10,10,13,12,10,10,12,12,13, + 10,11,10,13,13,12,13,13,14,14,12,13,12,14,13,11, + 12,12,14,13,12,13,12,14,14,10,12,12,14,14,14,14, + 14,16,14,13,12,14,12,15,10,12,12,14,15,12,13,13, + 14,16,11,12,11,15,14,13,14,14,14,15,13,14,11,14, + 12, +}; + +static const static_codebook _8u0__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__8u0__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8u0__p4_0, + 0 +}; + +static const long _vq_quantlist__8u0__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__8u0__p5_0[] = { + 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 7, 8, 8, + 10,10, 4, 6, 6, 8, 8, 8, 8,10,10, 6, 8, 8, 9, 9, + 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 7, 8, 8, + 9, 9,10,10,12,11, 7, 8, 8, 9, 9,10,10,11,11, 9, + 10,10,11,11,11,12,12,12, 9,10,10,11,11,12,12,12, + 12, +}; + +static const static_codebook _8u0__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__8u0__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__8u0__p5_0, + 0 +}; + +static const long _vq_quantlist__8u0__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__8u0__p6_0[] = { + 1, 4, 4, 7, 7, 9, 9,11,11,12,12,16,16, 3, 6, 6, + 9, 9,11,11,12,12,13,14,18,16, 3, 6, 7, 9, 9,11, + 11,13,12,14,14,17,16, 7, 9, 9,11,11,12,12,14,14, + 14,14,17,16, 7, 9, 9,11,11,13,12,13,13,14,14,17, + 0, 9,11,11,12,13,14,14,14,13,15,14,17,17, 9,11, + 11,12,12,14,14,13,14,14,15, 0, 0,11,12,12,15,14, + 15,14,15,14,15,16,17, 0,11,12,13,13,13,14,14,15, + 14,15,15, 0, 0,12,14,14,15,15,14,16,15,15,17,16, + 0,18,13,14,14,15,14,15,14,15,16,17,16, 0, 0,17, + 17,18, 0,16,18,16, 0, 0, 0,17, 0, 0,16, 0, 0,16, + 16, 0,15, 0,17, 0, 0, 0, 0, +}; + +static const static_codebook _8u0__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__8u0__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__8u0__p6_0, + 0 +}; + +static const long _vq_quantlist__8u0__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8u0__p6_1[] = { + 1, 4, 4, 6, 6, 4, 6, 5, 7, 7, 4, 5, 6, 7, 7, 6, + 7, 7, 7, 7, 6, 7, 7, 7, 7, +}; + +static const static_codebook _8u0__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__8u0__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8u0__p6_1, + 0 +}; + +static const long _vq_quantlist__8u0__p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8u0__p7_0[] = { + 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 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 static_codebook _8u0__p7_0 = { + 4, 81, + (char *)_vq_lengthlist__8u0__p7_0, + 1, -518803456, 1628680192, 2, 0, + (long *)_vq_quantlist__8u0__p7_0, + 0 +}; + +static const long _vq_quantlist__8u0__p7_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__8u0__p7_1[] = { + 1, 5, 5, 5, 5,10,10,11,11,11,11,11,11,11,11, 5, + 7, 6, 8, 8, 9,10,11,11,11,11,11,11,11,11, 6, 6, + 7, 9, 7,11,10,11,11,11,11,11,11,11,11, 5, 6, 6, + 11, 8,11,11,11,11,11,11,11,11,11,11, 5, 6, 6, 9, + 10,11,10,11,11,11,11,11,11,11,11, 7,10,10,11,11, + 11,11,11,11,11,11,11,11,11,11, 7,11, 8,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,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,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _8u0__p7_1 = { + 2, 225, + (char *)_vq_lengthlist__8u0__p7_1, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__8u0__p7_1, + 0 +}; + +static const long _vq_quantlist__8u0__p7_2[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__8u0__p7_2[] = { + 1, 6, 5, 7, 7, 9, 9, 9, 9,10,12,12,10,11,11,10, + 11,11,11,10,11, 6, 8, 8, 9, 9,10,10, 9,10,11,11, + 10,11,11,11,11,10,11,11,11,11, 6, 7, 8, 9, 9, 9, + 10,11,10,11,12,11,10,11,11,11,11,11,11,12,10, 8, + 9, 9,10, 9,10,10, 9,10,10,10,10,10, 9,10,10,10, + 10, 9,10,10, 9, 9, 9, 9,10,10, 9, 9,10,10,11,10, + 9,12,10,11,10, 9,10,10,10, 8, 9, 9,10, 9,10, 9, + 9,10,10, 9,10, 9,11,10,10,10,10,10, 9,10, 8, 8, + 9, 9,10, 9,11, 9, 8, 9, 9,10,11,10,10,10,11,12, + 9, 9,11, 8, 9, 8,11,10,11,10,10, 9,11,10,10,10, + 10,10,10,10,11,11,11,11, 8, 9, 9, 9,10,10,10,11, + 11,12,11,12,11,10,10,10,12,11,11,11,10, 8,10, 9, + 11,10,10,11,12,10,11,12,11,11,12,11,12,12,10,11, + 11,10, 9, 9,10,11,12,10,10,10,11,10,11,11,10,12, + 12,10,11,10,11,12,10, 9,10,10,11,10,11,11,11,11, + 11,12,11,11,11, 9,11,10,11,10,11,10, 9, 9,10,11, + 11,11,10,10,11,12,12,11,12,11,11,11,12,12,12,12, + 11, 9,11,11,12,10,11,11,11,11,11,11,12,11,11,12, + 11,11,11,10,11,11, 9,11,10,11,11,11,10,10,10,11, + 11,11,12,10,11,10,11,11,11,11,12, 9,11,10,11,11, + 10,10,11,11, 9,11,11,12,10,10,10,10,10,11,11,10, + 9,10,11,11,12,11,10,10,12,11,11,12,11,12,11,11, + 10,10,11,11,10,12,11,10,11,10,11,10,10,10,11,11, + 10,10,11,11,11,11,10,10,10,12,11,11,11,11,10, 9, + 10,11,11,11,12,11,11,11,12,10,11,11,11, 9,10,11, + 11,11,11,11,11,10,10,11,11,12,11,10,11,12,11,10, + 10,11, 9,10,11,11,11,11,11,10,11,11,10,12,11,11, + 11,12,11,11,11,10,10,11,11, +}; + +static const static_codebook _8u0__p7_2 = { + 2, 441, + (char *)_vq_lengthlist__8u0__p7_2, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__8u0__p7_2, + 0 +}; + +static const char _huff_lengthlist__8u0__single[] = { + 4, 7,11, 9,12, 8, 7,10, 6, 4, 5, 5, 7, 5, 6,16, + 9, 5, 5, 6, 7, 7, 9,16, 7, 4, 6, 5, 7, 5, 7,17, + 10, 7, 7, 8, 7, 7, 8,18, 7, 5, 6, 4, 5, 4, 5,15, + 7, 6, 7, 5, 6, 4, 5,15,12,13,18,12,17,11, 9,17, +}; + +static const static_codebook _huff_book__8u0__single = { + 2, 64, + (char *)_huff_lengthlist__8u0__single, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__8u1__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8u1__p1_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 7, 9,10, 7, + 9, 9, 5, 8, 8, 7,10, 9, 7, 9, 9, 5, 8, 8, 8,10, + 10, 8,10,10, 7,10,10, 9,10,12,10,12,12, 7,10,10, + 9,12,11,10,12,12, 5, 8, 8, 8,10,10, 8,10,10, 7, + 10,10,10,12,12, 9,11,12, 7,10,10,10,12,12, 9,12, + 10, +}; + +static const static_codebook _8u1__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__8u1__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__8u1__p1_0, + 0 +}; + +static const long _vq_quantlist__8u1__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8u1__p2_0[] = { + 3, 4, 5, 5, 6, 6, 5, 6, 6, 5, 7, 6, 6, 7, 8, 6, + 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 7, 5, 6, 6, 7, 8, + 8, 6, 7, 7, 6, 8, 7, 7, 7, 9, 8, 9, 9, 6, 7, 8, + 7, 9, 7, 8, 9, 9, 5, 6, 6, 6, 7, 7, 7, 8, 8, 6, + 8, 7, 8, 9, 9, 7, 7, 9, 6, 7, 8, 8, 9, 9, 7, 9, + 7, +}; + +static const static_codebook _8u1__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__8u1__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__8u1__p2_0, + 0 +}; + +static const long _vq_quantlist__8u1__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8u1__p3_0[] = { + 1, 5, 5, 7, 7, 6, 7, 7, 9, 9, 6, 7, 7, 9, 9, 8, + 10, 9,11,11, 9, 9, 9,11,11, 6, 8, 8,10,10, 8,10, + 10,11,11, 8, 9,10,11,11,10,11,11,12,12,10,11,11, + 12,13, 6, 8, 8,10,10, 8,10, 9,11,11, 8,10, 9,11, + 11,10,11,11,12,12,10,11,11,12,12, 9,11,11,14,13, + 10,12,11,14,14,10,12,11,14,13,12,13,13,15,14,12, + 13,13,15,14, 8,11,11,13,14,10,11,12,13,15,10,11, + 12,14,14,12,13,13,14,15,12,13,13,14,15, 5, 8, 8, + 11,11, 8,10,10,12,12, 8,10,10,12,12,11,12,12,14, + 13,11,12,12,13,14, 8,10,10,12,12, 9,11,12,13,14, + 10,12,12,13,13,12,12,13,14,14,11,13,13,15,15, 7, + 10,10,12,12, 9,12,11,14,12,10,11,12,13,14,12,13, + 12,14,14,12,13,13,15,16,10,12,12,15,14,11,12,13, + 15,15,11,13,13,15,16,14,14,15,15,16,13,14,15,17, + 15, 9,12,12,14,15,11,13,12,15,15,11,13,13,15,15, + 13,14,13,15,14,13,14,14,17, 0, 5, 8, 8,11,11, 8, + 10,10,12,12, 8,10,10,12,12,11,12,12,14,14,11,12, + 12,14,14, 7,10,10,12,12,10,12,12,13,13, 9,11,12, + 12,13,11,12,13,15,15,11,12,13,14,15, 8,10,10,12, + 12,10,12,11,13,13,10,12,11,13,13,11,13,13,15,14, + 12,13,12,15,13, 9,12,12,14,14,11,13,13,16,15,11, + 12,13,16,15,13,14,15,16,16,13,13,15,15,16,10,12, + 12,15,14,11,13,13,14,16,11,13,13,15,16,13,15,15, + 16,17,13,15,14,16,15, 8,11,11,14,15,10,12,12,15, + 15,10,12,12,15,16,14,15,15,16,17,13,14,14,16,16, + 9,12,12,15,15,11,13,14,15,17,11,13,13,15,16,14, + 15,16,19,17,13,15,15, 0,17, 9,12,12,15,15,11,14, + 13,16,15,11,13,13,15,16,15,15,15,18,17,13,15,15, + 17,17,11,15,14,18,16,12,14,15,17,17,12,15,15,18, + 18,15,15,16,15,19,14,16,16, 0, 0,11,14,14,16,17, + 12,15,14,18,17,12,15,15,18,18,15,17,15,18,16,14, + 16,16,18,18, 7,11,11,14,14,10,12,12,15,15,10,12, + 13,15,15,13,14,15,16,16,14,15,15,18,18, 9,12,12, + 15,15,11,13,13,16,15,11,12,13,16,16,14,15,15,17, + 16,15,16,16,17,17, 9,12,12,15,15,11,13,13,15,17, + 11,14,13,16,15,13,15,15,17,17,15,15,15,18,17,11, + 14,14,17,15,12,14,15,17,18,13,13,15,17,17,14,16, + 16,19,18,16,15,17,17, 0,11,14,14,17,17,12,15,15, + 18, 0,12,15,14,18,16,14,17,17,19, 0,16,18,15, 0, + 16, +}; + +static const static_codebook _8u1__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__8u1__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8u1__p3_0, + 0 +}; + +static const long _vq_quantlist__8u1__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__8u1__p4_0[] = { + 4, 5, 5, 9, 9, 6, 7, 7, 9, 9, 6, 7, 7, 9, 9, 9, + 9, 9,11,11, 9, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 7, + 8, 9,10, 7, 7, 8, 9,10, 9, 9,10,10,11, 9, 9,10, + 10,12, 6, 7, 7, 9, 9, 7, 8, 7,10, 9, 7, 8, 7,10, + 9, 9,10, 9,12,11,10,10, 9,12,10, 9,10,10,12,11, + 9,10,10,12,11, 9,10,10,12,12,11,11,12,12,13,11, + 11,12,12,13, 9, 9,10,12,11, 9,10,10,12,12,10,10, + 10,12,12,11,12,11,13,12,11,12,11,13,12, 6, 7, 7, + 9, 9, 7, 8, 8,10,10, 7, 8, 7,10, 9,10,10,10,12, + 12,10,10,10,12,11, 7, 8, 7,10,10, 7, 7, 9,10,11, + 8, 9, 9,11,10,10,10,11,10,12,10,10,11,12,12, 7, + 8, 8,10,10, 7, 9, 8,11,10, 8, 8, 9,11,11,10,11, + 10,12,11,10,11,11,12,12, 9,10,10,12,12, 9,10,10, + 12,12,10,11,11,13,12,11,10,12,10,14,12,12,12,13, + 14, 9,10,10,12,12, 9,11,10,12,12,10,11,11,12,12, + 11,12,11,14,12,12,12,12,14,14, 5, 7, 7, 9, 9, 7, + 7, 7, 9,10, 7, 8, 8,10,10,10,10,10,11,11,10,10, + 10,12,12, 7, 8, 8,10,10, 8, 9, 8,11,10, 7, 8, 9, + 10,11,10,10,10,11,12,10,10,11,11,13, 6, 7, 8,10, + 10, 8, 9, 9,10,10, 7, 9, 7,11,10,10,11,10,12,12, + 10,11,10,12,10, 9,10,10,12,12,10,11,11,13,12, 9, + 10,10,12,12,12,12,12,14,13,11,11,12,11,14, 9,10, + 10,11,12,10,11,11,12,13, 9,10,10,12,12,12,12,12, + 14,13,11,12,10,14,11, 9, 9,10,11,12, 9,10,10,12, + 12, 9,10,10,12,12,12,12,12,14,14,11,12,12,13,12, + 9,10, 9,12,12, 9,10,11,12,13,10,11,10,13,11,12, + 12,13,13,14,12,12,12,13,13, 9,10,10,12,12,10,11, + 10,13,12,10,10,11,12,13,12,13,12,14,13,12,12,12, + 13,14,11,12,11,14,13,10,10,11,13,13,12,12,12,14, + 13,12,10,14,10,15,13,14,14,14,14,11,11,12,13,14, + 10,12,11,13,13,12,12,12,13,15,12,13,11,15,12,13, + 13,14,14,14, 9,10, 9,12,12, 9,10,10,12,12,10,10, + 10,12,12,11,11,12,12,13,12,12,12,14,14, 9,10,10, + 12,12,10,11,10,13,12,10,10,11,12,13,12,12,12,14, + 13,12,12,13,13,14, 9,10,10,12,13,10,10,11,11,12, + 9,11,10,13,12,12,12,12,13,14,12,13,12,14,13,11, + 12,11,13,13,12,13,12,14,13,10,11,12,13,13,13,13, + 13,14,15,12,11,14,12,14,11,11,12,12,13,12,12,12, + 13,14,10,12,10,14,13,13,13,13,14,15,12,14,11,15, + 10, +}; + +static const static_codebook _8u1__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__8u1__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__8u1__p4_0, + 0 +}; + +static const long _vq_quantlist__8u1__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__8u1__p5_0[] = { + 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 5, 8, 7, 8, 8, + 10,10, 4, 6, 6, 8, 8, 8, 8,10,10, 7, 8, 8, 9, 9, + 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 8, 8, 8, + 9, 9,10,10,12,11, 8, 8, 8, 9, 9,10,10,11,11, 9, + 10,10,11,11,11,11,13,12, 9,10,10,11,11,12,12,12, + 13, +}; + +static const static_codebook _8u1__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__8u1__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__8u1__p5_0, + 0 +}; + +static const long _vq_quantlist__8u1__p6_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__8u1__p6_0[] = { + 3, 4, 4, 6, 6, 7, 7, 9, 9, 4, 4, 5, 6, 6, 7, 7, + 9, 9, 4, 4, 4, 6, 6, 7, 7, 9, 9, 6, 6, 6, 7, 7, + 8, 8, 9, 9, 6, 6, 6, 7, 7, 8, 8, 9, 9, 7, 7, 7, + 8, 8, 8, 9,10,10, 7, 7, 7, 8, 8, 9, 8,10,10, 9, + 9, 9, 9, 9,10,10,10,10, 9, 9, 9, 9, 9,10,10,10, + 10, +}; + +static const static_codebook _8u1__p6_0 = { + 2, 81, + (char *)_vq_lengthlist__8u1__p6_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__8u1__p6_0, + 0 +}; + +static const long _vq_quantlist__8u1__p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__8u1__p7_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 9, 8,10,10, 8, + 10,10, 5, 9, 9, 7,10,10, 8,10,10, 4,10,10, 9,12, + 12, 9,11,11, 7,12,11,10,11,13,10,13,13, 7,12,12, + 10,13,12,10,13,13, 4,10,10, 9,12,12, 9,12,12, 7, + 12,12,10,13,13,10,12,13, 7,11,12,10,13,13,10,13, + 11, +}; + +static const static_codebook _8u1__p7_0 = { + 4, 81, + (char *)_vq_lengthlist__8u1__p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__8u1__p7_0, + 0 +}; + +static const long _vq_quantlist__8u1__p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__8u1__p7_1[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 7, 7, + 8, 8, 9, 9, 9, 9, 4, 5, 5, 7, 7, 8, 8, 9, 9, 9, + 9, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 9, 9, + 9, 9, 9, 9,10,10,10,10, 8, 9, 9, 9, 9, 9, 9,10, + 10,10,10, 8, 9, 9, 9, 9, 9, 9,10,10,10,10, 8, 9, + 9, 9, 9, 9, 9,10,10,10,10, +}; + +static const static_codebook _8u1__p7_1 = { + 2, 121, + (char *)_vq_lengthlist__8u1__p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__8u1__p7_1, + 0 +}; + +static const long _vq_quantlist__8u1__p8_0[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__8u1__p8_0[] = { + 1, 4, 4, 6, 6, 8, 8,10,10,11,11, 4, 6, 6, 7, 7, + 9, 9,11,11,13,12, 4, 6, 6, 7, 7, 9, 9,11,11,12, + 12, 6, 7, 7, 9, 9,11,11,12,12,13,13, 6, 7, 7, 9, + 9,11,11,12,12,13,13, 8, 9, 9,11,11,12,12,13,13, + 14,14, 8, 9, 9,11,11,12,12,13,13,14,14, 9,11,11, + 12,12,13,13,14,14,15,15, 9,11,11,12,12,13,13,14, + 14,15,14,11,12,12,13,13,14,14,15,15,16,16,11,12, + 12,13,13,14,14,15,15,15,15, +}; + +static const static_codebook _8u1__p8_0 = { + 2, 121, + (char *)_vq_lengthlist__8u1__p8_0, + 1, -524582912, 1618345984, 4, 0, + (long *)_vq_quantlist__8u1__p8_0, + 0 +}; + +static const long _vq_quantlist__8u1__p8_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__8u1__p8_1[] = { + 2, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 5, 6, 6, 7, 7, + 7, 7, 8, 8, 8, 8, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 8, 9, 9, 7, 8, 8, 8, 8, 8, 8, 9, + 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, +}; + +static const static_codebook _8u1__p8_1 = { + 2, 121, + (char *)_vq_lengthlist__8u1__p8_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__8u1__p8_1, + 0 +}; + +static const long _vq_quantlist__8u1__p9_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__8u1__p9_0[] = { + 1, 4, 4,11,11,11,11,11,11,11,11,11,11,11,11, 3, + 11, 8,11,11,11,11,11,11,11,11,11,11,11,11, 3, 9, + 9,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,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,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,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _8u1__p9_0 = { + 2, 225, + (char *)_vq_lengthlist__8u1__p9_0, + 1, -514071552, 1627381760, 4, 0, + (long *)_vq_quantlist__8u1__p9_0, + 0 +}; + +static const long _vq_quantlist__8u1__p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__8u1__p9_1[] = { + 1, 4, 4, 7, 7, 9, 9, 7, 7, 8, 8,10,10,11,11, 4, + 7, 7, 9, 9,10,10, 8, 8,10,10,10,11,10,11, 4, 7, + 7, 9, 9,10,10, 8, 8,10, 9,11,11,11,11, 7, 9, 9, + 12,12,11,12,10,10,11,10,12,11,11,11, 7, 9, 9,11, + 11,13,12, 9, 9,11,10,11,11,12,11, 9,10,10,12,12, + 14,14,10,10,11,12,12,11,11,11, 9,10,11,11,13,14, + 13,10,11,11,11,12,11,12,12, 7, 8, 8,10, 9,11,10, + 11,12,12,11,12,14,12,13, 7, 8, 8, 9,10,10,11,12, + 12,12,11,12,12,12,13, 9, 9, 9,11,11,13,12,12,12, + 12,11,12,12,13,12, 8,10,10,11,10,11,12,12,12,12, + 12,12,14,12,12, 9,11,11,11,12,12,12,12,13,13,12, + 12,13,13,12,10,11,11,12,11,12,12,12,11,12,13,12, + 12,12,13,11,11,12,12,12,13,12,12,11,12,13,13,12, + 12,13,12,11,12,12,13,13,12,13,12,13,13,13,13,14, + 13, +}; + +static const static_codebook _8u1__p9_1 = { + 2, 225, + (char *)_vq_lengthlist__8u1__p9_1, + 1, -522338304, 1620115456, 4, 0, + (long *)_vq_quantlist__8u1__p9_1, + 0 +}; + +static const long _vq_quantlist__8u1__p9_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__8u1__p9_2[] = { + 2, 5, 4, 6, 6, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 5, 6, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 9,10,10, 9, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9,10,10, 8, 8, 8, 9, 9, 9, 9,10,10,10, 9, + 10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9,10, + 10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,10,10, + 10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, + 9,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9,10, + 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, 9, + 10, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _8u1__p9_2 = { + 2, 289, + (char *)_vq_lengthlist__8u1__p9_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__8u1__p9_2, + 0 +}; + +static const char _huff_lengthlist__8u1__single[] = { + 4, 7,13, 9,15, 9,16, 8,10,13, 7, 5, 8, 6, 9, 7, + 10, 7,10,11,11, 6, 7, 8, 8, 9, 9, 9,12,16, 8, 5, + 8, 6, 8, 6, 9, 7,10,12,11, 7, 7, 7, 6, 7, 7, 7, + 11,15, 7, 5, 8, 6, 7, 5, 7, 6, 9,13,13, 9, 9, 8, + 6, 6, 5, 5, 9,14, 8, 6, 8, 6, 6, 4, 5, 3, 5,13, + 9, 9,11, 8,10, 7, 8, 4, 5,12,11,16,17,15,17,12, + 13, 8, 8,15, +}; + +static const static_codebook _huff_book__8u1__single = { + 2, 100, + (char *)_huff_lengthlist__8u1__single, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u0__long[] = { + 5, 8,13,10,17,11,11,15, 7, 2, 4, 5, 8, 7, 9,16, + 13, 4, 3, 5, 6, 8,11,20,10, 4, 5, 5, 7, 6, 8,18, + 15, 7, 6, 7, 8,10,14,20,10, 6, 7, 6, 9, 7, 8,17, + 9, 8,10, 8,10, 5, 4,11,12,17,19,14,16,10, 7,12, +}; + +static const static_codebook _huff_book__44u0__long = { + 2, 64, + (char *)_huff_lengthlist__44u0__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u0__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u0__p1_0[] = { + 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,11,11, 8, + 10,10, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11, + 11, 8,11,11, 8,12,11,11,13,13,11,13,14, 7,11,11, + 10,13,12,11,13,14, 4, 8, 8, 8,11,11, 8,11,12, 8, + 11,11,11,13,13,10,12,13, 8,11,11,11,14,13,11,14, + 13, +}; + +static const static_codebook _44u0__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u0__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u0__p1_0, + 0 +}; + +static const long _vq_quantlist__44u0__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u0__p2_0[] = { + 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 8, 6, + 8, 8, 5, 7, 7, 6, 8, 8, 7, 8, 8, 4, 7, 7, 7, 8, + 8, 7, 8, 8, 7, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8, + 8,10, 8, 8,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 8, 6, + 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10, + 9, +}; + +static const static_codebook _44u0__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u0__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u0__p2_0, + 0 +}; + +static const long _vq_quantlist__44u0__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u0__p3_0[] = { + 1, 5, 5, 8, 8, 5, 8, 7, 9, 9, 5, 7, 8, 9, 9, 9, + 10, 9,12,12, 9, 9,10,12,12, 6, 8, 8,11,10, 8,10, + 10,11,11, 8, 9,10,11,11,10,11,11,14,13,10,11,11, + 13,13, 5, 8, 8,10,10, 8,10,10,11,11, 8,10,10,11, + 11,10,11,11,13,13,10,11,11,13,13, 9,11,11,15,14, + 10,12,12,15,14,10,12,11,15,14,13,14,14,16,16,12, + 14,13,17,15, 9,11,11,14,15,10,11,12,14,16,10,11, + 12,14,16,12,13,14,16,16,13,13,15,15,18, 5, 8, 8, + 11,11, 8,10,10,12,12, 8,10,10,12,13,11,12,12,14, + 14,11,12,12,15,15, 8,10,10,13,13,10,12,12,13,13, + 10,12,12,14,14,12,13,13,15,15,12,13,13,16,16, 7, + 10,10,12,12,10,12,11,13,13,10,12,12,13,14,12,13, + 12,15,14,12,13,13,16,16,10,12,12,17,16,12,13,13, + 16,15,11,13,13,17,17,15,15,15,16,17,14,15,15,19, + 19,10,12,12,15,16,11,13,12,15,18,11,13,13,16,16, + 14,15,15,17,17,14,15,15,17,19, 5, 8, 8,11,11, 8, + 10,10,12,12, 8,10,10,12,12,11,12,12,16,15,11,12, + 12,14,15, 7,10,10,13,13,10,12,12,14,13,10,11,12, + 13,13,12,13,13,16,16,12,12,13,15,15, 8,10,10,13, + 13,10,12,12,14,14,10,12,12,13,13,12,13,13,16,16, + 12,13,13,15,15,10,12,12,16,15,11,13,13,17,16,11, + 12,13,16,15,13,15,15,19,17,14,15,14,17,16,10,12, + 12,16,16,11,13,13,16,17,12,13,13,15,17,14,15,15, + 17,19,14,15,15,17,17, 8,11,11,16,16,10,13,12,17, + 17,10,12,13,16,16,15,17,16,20,19,14,15,17,18,19, + 9,12,12,16,17,11,13,14,17,18,11,13,13,19,18,16, + 17,18,19,19,15,16,16,19,19, 9,12,12,16,17,11,14, + 13,18,17,11,13,13,17,17,16,17,16,20,19,14,16,16, + 18,18,12,15,15,19,17,14,15,16, 0,20,13,15,16,20, + 17,18,16,20, 0, 0,15,16,19,20, 0,12,15,14,18,19, + 13,16,15,20,19,13,16,15,20,18,17,18,17, 0,20,16, + 17,16, 0, 0, 8,11,11,16,15,10,12,12,17,17,10,13, + 13,17,16,14,16,15,18,20,15,16,16,19,19, 9,12,12, + 16,16,11,13,13,17,16,11,13,14,17,18,15,15,16,20, + 20,16,16,17,19,19, 9,13,12,16,17,11,14,13,17,17, + 11,14,14,18,17,14,16,15,18,19,16,17,18,18,19,12, + 14,15,19,18,13,15,16,18, 0,13,14,15, 0, 0,16,16, + 17,20, 0,17,17,20,20, 0,12,15,15,19,20,13,15,15, + 0, 0,14,16,15, 0, 0,15,18,16, 0, 0,17,18,16, 0, + 19, +}; + +static const static_codebook _44u0__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u0__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u0__p3_0, + 0 +}; + +static const long _vq_quantlist__44u0__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u0__p4_0[] = { + 4, 5, 5, 9, 9, 5, 6, 6, 9, 9, 5, 6, 6, 9, 9, 9, + 10, 9,12,12, 9, 9,10,12,12, 5, 7, 7,10,10, 7, 7, + 8,10,10, 6, 7, 8,10,10,10,10,10,11,13,10, 9,10, + 12,13, 5, 7, 7,10,10, 6, 8, 7,10,10, 7, 8, 7,10, + 10, 9,10,10,12,12,10,10,10,13,11, 9,10,10,13,13, + 10,11,10,13,13,10,10,10,13,13,12,12,13,14,14,12, + 12,13,14,14, 9,10,10,13,13,10,10,10,13,13,10,10, + 10,13,13,12,13,12,15,14,12,13,12,15,15, 5, 7, 6, + 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,10,13, + 13,10,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,10,11, + 8, 9, 9,11,11,11,10,11,11,14,11,11,11,13,13, 6, + 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,14,11,10,11,11,13,13,10,11,11,14,13,10,10,11, + 14,13,10,11,11,14,14,12,11,13,12,16,13,14,14,15, + 15,10,10,11,13,14,10,11,10,14,13,10,11,11,14,14, + 12,13,12,15,13,13,13,14,15,16, 5, 7, 7,10,10, 7, + 8, 8,10,10, 7, 8, 8,10,10,10,10,10,13,13,10,10, + 11,12,13, 6, 8, 8,11,10, 8, 9, 9,11,11, 7, 8, 9, + 10,11,10,11,11,13,13,10,10,11,11,13, 6, 8, 8,10, + 11, 8, 9, 9,11,11, 8, 9, 8,12,10,10,11,11,13,13, + 10,11,10,14,11,10,10,10,14,13,10,11,11,14,13,10, + 10,11,13,13,12,14,14,16,16,12,12,13,13,15,10,11, + 11,13,14,10,11,11,14,15,10,11,10,13,13,13,14,13, + 16,16,12,13,11,15,12, 9,10,10,13,13,10,11,11,14, + 13,10,10,11,13,14,13,14,13,16,16,13,13,13,15,16, + 9,10,10,13,13,10,10,11,13,14,10,11,11,15,13,13, + 13,14,14,18,13,13,14,16,15, 9,10,10,13,14,10,11, + 10,14,13,10,11,11,13,14,13,14,13,16,15,13,13,14, + 15,16,12,13,12,16,14,11,11,13,15,15,13,14,13,16, + 15,15,12,16,12,17,14,15,15,17,17,12,13,13,14,16, + 11,13,11,16,15,12,13,14,15,16,14,15,13, 0,14,14, + 16,16, 0, 0, 9,10,10,13,13,10,11,10,14,14,10,11, + 11,13,13,12,13,13,14,16,13,14,14,16,16, 9,10,10, + 14,14,11,11,11,14,13,10,10,11,14,14,13,13,13,16, + 16,13,13,14,14,17, 9,10,10,13,14,10,11,11,13,15, + 10,11,10,14,14,13,13,13,14,17,13,14,13,17,14,12, + 13,13,16,14,13,14,13,16,15,12,12,13,15,16,15,15, + 16,18,16,15,13,15,14, 0,12,12,13,14,16,13,13,14, + 15,16,11,12,11,16,14,15,16,16,17,17,14,15,12,17, + 12, +}; + +static const static_codebook _44u0__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u0__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u0__p4_0, + 0 +}; + +static const long _vq_quantlist__44u0__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u0__p5_0[] = { + 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8, + 9, 9, 4, 6, 6, 8, 8, 8, 8, 9, 9, 7, 8, 8, 9, 9, + 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,10, 7, 8, 8, + 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9, + 9, 9,10,10,11,11,12,12, 9, 9, 9,10,11,11,11,12, + 12, +}; + +static const static_codebook _44u0__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u0__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u0__p5_0, + 0 +}; + +static const long _vq_quantlist__44u0__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u0__p6_0[] = { + 1, 4, 4, 6, 6, 8, 8,10, 9,11,10,14,13, 4, 6, 5, + 8, 8, 9, 9,11,10,11,11,14,14, 4, 5, 6, 8, 8, 9, + 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11, + 12,12,16,15, 7, 8, 8, 9, 9,10,10,11,11,12,12,15, + 15, 9,10,10,10,10,11,11,12,12,12,12,15,15, 9,10, + 9,10,11,11,11,12,12,12,13,15,15,10,10,11,11,11, + 12,12,13,12,13,13,16,15,10,11,11,11,11,12,12,13, + 12,13,13,16,17,11,11,12,12,12,13,13,13,14,14,15, + 17,17,11,11,12,12,12,13,13,13,14,14,14,16,18,14, + 15,15,15,15,16,16,16,16,17,18, 0, 0,14,15,15,15, + 15,17,16,17,18,17,17,18, 0, +}; + +static const static_codebook _44u0__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44u0__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44u0__p6_0, + 0 +}; + +static const long _vq_quantlist__44u0__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u0__p6_1[] = { + 2, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 5, 6, 6, 6, 6, +}; + +static const static_codebook _44u0__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44u0__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u0__p6_1, + 0 +}; + +static const long _vq_quantlist__44u0__p7_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u0__p7_0[] = { + 1, 4, 4,11,11, 9,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, 9,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,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,10,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, + 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,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,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,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,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,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,11,11,11,11, + 11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _44u0__p7_0 = { + 4, 625, + (char *)_vq_lengthlist__44u0__p7_0, + 1, -518709248, 1626677248, 3, 0, + (long *)_vq_quantlist__44u0__p7_0, + 0 +}; + +static const long _vq_quantlist__44u0__p7_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u0__p7_1[] = { + 1, 4, 4, 6, 6, 6, 6, 7, 7, 8, 8, 9, 9, 5, 7, 7, + 8, 7, 7, 7, 9, 8,10, 9,10,11, 5, 7, 7, 8, 8, 7, + 7, 8, 9,10,10,11,11, 6, 8, 8, 9, 9, 9, 9,11,10, + 12,12,15,12, 6, 8, 8, 9, 9, 9, 9,11,11,12,11,14, + 12, 7, 8, 8,10,10,12,12,13,13,13,15,13,13, 7, 8, + 8,10,10,11,11,13,12,14,15,15,15, 9,10,10,11,12, + 13,13,14,15,14,15,14,15, 8,10,10,12,12,14,14,15, + 14,14,15,15,14,10,12,12,14,14,15,14,15,15,15,14, + 15,15,10,12,12,13,14,15,14,15,15,14,15,15,15,12, + 15,13,15,14,15,15,15,15,15,15,15,15,13,13,15,15, + 15,15,15,15,15,15,15,15,15, +}; + +static const static_codebook _44u0__p7_1 = { + 2, 169, + (char *)_vq_lengthlist__44u0__p7_1, + 1, -523010048, 1618608128, 4, 0, + (long *)_vq_quantlist__44u0__p7_1, + 0 +}; + +static const long _vq_quantlist__44u0__p7_2[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u0__p7_2[] = { + 2, 5, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 5, 5, 6, + 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 5, 6, 5, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8, 8, 8, 8, 9, 8, + 9, 9, 9, 9, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 7, 8, + 8, 9, 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, + 9, 9, 9, 9, 9, 9,10,10, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9,10, 9,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, + 9, 9, 9,10, 9, 9,10,10, 9, +}; + +static const static_codebook _44u0__p7_2 = { + 2, 169, + (char *)_vq_lengthlist__44u0__p7_2, + 1, -531103744, 1611661312, 4, 0, + (long *)_vq_quantlist__44u0__p7_2, + 0 +}; + +static const char _huff_lengthlist__44u0__short[] = { + 12,13,14,13,17,12,15,17, 5, 5, 6,10,10,11,15,16, + 4, 3, 3, 7, 5, 7,10,16, 7, 7, 7,10, 9,11,12,16, + 6, 5, 5, 9, 5, 6,10,16, 8, 7, 7, 9, 6, 7, 9,16, + 11, 7, 3, 6, 4, 5, 8,16,12, 9, 4, 8, 5, 7, 9,16, +}; + +static const static_codebook _huff_book__44u0__short = { + 2, 64, + (char *)_huff_lengthlist__44u0__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u1__long[] = { + 5, 8,13,10,17,11,11,15, 7, 2, 4, 5, 8, 7, 9,16, + 13, 4, 3, 5, 6, 8,11,20,10, 4, 5, 5, 7, 6, 8,18, + 15, 7, 6, 7, 8,10,14,20,10, 6, 7, 6, 9, 7, 8,17, + 9, 8,10, 8,10, 5, 4,11,12,17,19,14,16,10, 7,12, +}; + +static const static_codebook _huff_book__44u1__long = { + 2, 64, + (char *)_huff_lengthlist__44u1__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u1__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u1__p1_0[] = { + 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,11,11, 8, + 10,10, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11, + 11, 8,11,11, 8,12,11,11,13,13,11,13,14, 7,11,11, + 10,13,12,11,13,14, 4, 8, 8, 8,11,11, 8,11,12, 8, + 11,11,11,13,13,10,12,13, 8,11,11,11,14,13,11,14, + 13, +}; + +static const static_codebook _44u1__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u1__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u1__p1_0, + 0 +}; + +static const long _vq_quantlist__44u1__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u1__p2_0[] = { + 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 8, 6, + 8, 8, 5, 7, 7, 6, 8, 8, 7, 8, 8, 4, 7, 7, 7, 8, + 8, 7, 8, 8, 7, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8, + 8,10, 8, 8,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 8, 6, + 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10, + 9, +}; + +static const static_codebook _44u1__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u1__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u1__p2_0, + 0 +}; + +static const long _vq_quantlist__44u1__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u1__p3_0[] = { + 1, 5, 5, 8, 8, 5, 8, 7, 9, 9, 5, 7, 8, 9, 9, 9, + 10, 9,12,12, 9, 9,10,12,12, 6, 8, 8,11,10, 8,10, + 10,11,11, 8, 9,10,11,11,10,11,11,14,13,10,11,11, + 13,13, 5, 8, 8,10,10, 8,10,10,11,11, 8,10,10,11, + 11,10,11,11,13,13,10,11,11,13,13, 9,11,11,15,14, + 10,12,12,15,14,10,12,11,15,14,13,14,14,16,16,12, + 14,13,17,15, 9,11,11,14,15,10,11,12,14,16,10,11, + 12,14,16,12,13,14,16,16,13,13,15,15,18, 5, 8, 8, + 11,11, 8,10,10,12,12, 8,10,10,12,13,11,12,12,14, + 14,11,12,12,15,15, 8,10,10,13,13,10,12,12,13,13, + 10,12,12,14,14,12,13,13,15,15,12,13,13,16,16, 7, + 10,10,12,12,10,12,11,13,13,10,12,12,13,14,12,13, + 12,15,14,12,13,13,16,16,10,12,12,17,16,12,13,13, + 16,15,11,13,13,17,17,15,15,15,16,17,14,15,15,19, + 19,10,12,12,15,16,11,13,12,15,18,11,13,13,16,16, + 14,15,15,17,17,14,15,15,17,19, 5, 8, 8,11,11, 8, + 10,10,12,12, 8,10,10,12,12,11,12,12,16,15,11,12, + 12,14,15, 7,10,10,13,13,10,12,12,14,13,10,11,12, + 13,13,12,13,13,16,16,12,12,13,15,15, 8,10,10,13, + 13,10,12,12,14,14,10,12,12,13,13,12,13,13,16,16, + 12,13,13,15,15,10,12,12,16,15,11,13,13,17,16,11, + 12,13,16,15,13,15,15,19,17,14,15,14,17,16,10,12, + 12,16,16,11,13,13,16,17,12,13,13,15,17,14,15,15, + 17,19,14,15,15,17,17, 8,11,11,16,16,10,13,12,17, + 17,10,12,13,16,16,15,17,16,20,19,14,15,17,18,19, + 9,12,12,16,17,11,13,14,17,18,11,13,13,19,18,16, + 17,18,19,19,15,16,16,19,19, 9,12,12,16,17,11,14, + 13,18,17,11,13,13,17,17,16,17,16,20,19,14,16,16, + 18,18,12,15,15,19,17,14,15,16, 0,20,13,15,16,20, + 17,18,16,20, 0, 0,15,16,19,20, 0,12,15,14,18,19, + 13,16,15,20,19,13,16,15,20,18,17,18,17, 0,20,16, + 17,16, 0, 0, 8,11,11,16,15,10,12,12,17,17,10,13, + 13,17,16,14,16,15,18,20,15,16,16,19,19, 9,12,12, + 16,16,11,13,13,17,16,11,13,14,17,18,15,15,16,20, + 20,16,16,17,19,19, 9,13,12,16,17,11,14,13,17,17, + 11,14,14,18,17,14,16,15,18,19,16,17,18,18,19,12, + 14,15,19,18,13,15,16,18, 0,13,14,15, 0, 0,16,16, + 17,20, 0,17,17,20,20, 0,12,15,15,19,20,13,15,15, + 0, 0,14,16,15, 0, 0,15,18,16, 0, 0,17,18,16, 0, + 19, +}; + +static const static_codebook _44u1__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u1__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u1__p3_0, + 0 +}; + +static const long _vq_quantlist__44u1__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u1__p4_0[] = { + 4, 5, 5, 9, 9, 5, 6, 6, 9, 9, 5, 6, 6, 9, 9, 9, + 10, 9,12,12, 9, 9,10,12,12, 5, 7, 7,10,10, 7, 7, + 8,10,10, 6, 7, 8,10,10,10,10,10,11,13,10, 9,10, + 12,13, 5, 7, 7,10,10, 6, 8, 7,10,10, 7, 8, 7,10, + 10, 9,10,10,12,12,10,10,10,13,11, 9,10,10,13,13, + 10,11,10,13,13,10,10,10,13,13,12,12,13,14,14,12, + 12,13,14,14, 9,10,10,13,13,10,10,10,13,13,10,10, + 10,13,13,12,13,12,15,14,12,13,12,15,15, 5, 7, 6, + 10,10, 7, 8, 8,10,10, 7, 8, 8,10,10,10,11,10,13, + 13,10,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,10,11, + 8, 9, 9,11,11,11,10,11,11,14,11,11,11,13,13, 6, + 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,14,11,10,11,11,13,13,10,11,11,14,13,10,10,11, + 14,13,10,11,11,14,14,12,11,13,12,16,13,14,14,15, + 15,10,10,11,13,14,10,11,10,14,13,10,11,11,14,14, + 12,13,12,15,13,13,13,14,15,16, 5, 7, 7,10,10, 7, + 8, 8,10,10, 7, 8, 8,10,10,10,10,10,13,13,10,10, + 11,12,13, 6, 8, 8,11,10, 8, 9, 9,11,11, 7, 8, 9, + 10,11,10,11,11,13,13,10,10,11,11,13, 6, 8, 8,10, + 11, 8, 9, 9,11,11, 8, 9, 8,12,10,10,11,11,13,13, + 10,11,10,14,11,10,10,10,14,13,10,11,11,14,13,10, + 10,11,13,13,12,14,14,16,16,12,12,13,13,15,10,11, + 11,13,14,10,11,11,14,15,10,11,10,13,13,13,14,13, + 16,16,12,13,11,15,12, 9,10,10,13,13,10,11,11,14, + 13,10,10,11,13,14,13,14,13,16,16,13,13,13,15,16, + 9,10,10,13,13,10,10,11,13,14,10,11,11,15,13,13, + 13,14,14,18,13,13,14,16,15, 9,10,10,13,14,10,11, + 10,14,13,10,11,11,13,14,13,14,13,16,15,13,13,14, + 15,16,12,13,12,16,14,11,11,13,15,15,13,14,13,16, + 15,15,12,16,12,17,14,15,15,17,17,12,13,13,14,16, + 11,13,11,16,15,12,13,14,15,16,14,15,13, 0,14,14, + 16,16, 0, 0, 9,10,10,13,13,10,11,10,14,14,10,11, + 11,13,13,12,13,13,14,16,13,14,14,16,16, 9,10,10, + 14,14,11,11,11,14,13,10,10,11,14,14,13,13,13,16, + 16,13,13,14,14,17, 9,10,10,13,14,10,11,11,13,15, + 10,11,10,14,14,13,13,13,14,17,13,14,13,17,14,12, + 13,13,16,14,13,14,13,16,15,12,12,13,15,16,15,15, + 16,18,16,15,13,15,14, 0,12,12,13,14,16,13,13,14, + 15,16,11,12,11,16,14,15,16,16,17,17,14,15,12,17, + 12, +}; + +static const static_codebook _44u1__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u1__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u1__p4_0, + 0 +}; + +static const long _vq_quantlist__44u1__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u1__p5_0[] = { + 1, 4, 4, 7, 7, 7, 7, 9, 9, 4, 6, 6, 8, 8, 8, 8, + 9, 9, 4, 6, 6, 8, 8, 8, 8, 9, 9, 7, 8, 8, 9, 9, + 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,10, 7, 8, 8, + 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9, + 9, 9,10,10,11,11,12,12, 9, 9, 9,10,11,11,11,12, + 12, +}; + +static const static_codebook _44u1__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u1__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u1__p5_0, + 0 +}; + +static const long _vq_quantlist__44u1__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u1__p6_0[] = { + 1, 4, 4, 6, 6, 8, 8,10, 9,11,10,14,13, 4, 6, 5, + 8, 8, 9, 9,11,10,11,11,14,14, 4, 5, 6, 8, 8, 9, + 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11, + 12,12,16,15, 7, 8, 8, 9, 9,10,10,11,11,12,12,15, + 15, 9,10,10,10,10,11,11,12,12,12,12,15,15, 9,10, + 9,10,11,11,11,12,12,12,13,15,15,10,10,11,11,11, + 12,12,13,12,13,13,16,15,10,11,11,11,11,12,12,13, + 12,13,13,16,17,11,11,12,12,12,13,13,13,14,14,15, + 17,17,11,11,12,12,12,13,13,13,14,14,14,16,18,14, + 15,15,15,15,16,16,16,16,17,18, 0, 0,14,15,15,15, + 15,17,16,17,18,17,17,18, 0, +}; + +static const static_codebook _44u1__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44u1__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44u1__p6_0, + 0 +}; + +static const long _vq_quantlist__44u1__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u1__p6_1[] = { + 2, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 5, 6, 6, 6, 6, +}; + +static const static_codebook _44u1__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44u1__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u1__p6_1, + 0 +}; + +static const long _vq_quantlist__44u1__p7_0[] = { + 3, + 2, + 4, + 1, + 5, + 0, + 6, +}; + +static const char _vq_lengthlist__44u1__p7_0[] = { + 1, 3, 2, 9, 9, 7, 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, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, +}; + +static const static_codebook _44u1__p7_0 = { + 2, 49, + (char *)_vq_lengthlist__44u1__p7_0, + 1, -518017024, 1626677248, 3, 0, + (long *)_vq_quantlist__44u1__p7_0, + 0 +}; + +static const long _vq_quantlist__44u1__p7_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u1__p7_1[] = { + 1, 4, 4, 6, 6, 6, 6, 7, 7, 8, 8, 9, 9, 5, 7, 7, + 8, 7, 7, 7, 9, 8,10, 9,10,11, 5, 7, 7, 8, 8, 7, + 7, 8, 9,10,10,11,11, 6, 8, 8, 9, 9, 9, 9,11,10, + 12,12,15,12, 6, 8, 8, 9, 9, 9, 9,11,11,12,11,14, + 12, 7, 8, 8,10,10,12,12,13,13,13,15,13,13, 7, 8, + 8,10,10,11,11,13,12,14,15,15,15, 9,10,10,11,12, + 13,13,14,15,14,15,14,15, 8,10,10,12,12,14,14,15, + 14,14,15,15,14,10,12,12,14,14,15,14,15,15,15,14, + 15,15,10,12,12,13,14,15,14,15,15,14,15,15,15,12, + 15,13,15,14,15,15,15,15,15,15,15,15,13,13,15,15, + 15,15,15,15,15,15,15,15,15, +}; + +static const static_codebook _44u1__p7_1 = { + 2, 169, + (char *)_vq_lengthlist__44u1__p7_1, + 1, -523010048, 1618608128, 4, 0, + (long *)_vq_quantlist__44u1__p7_1, + 0 +}; + +static const long _vq_quantlist__44u1__p7_2[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u1__p7_2[] = { + 2, 5, 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 5, 5, 6, + 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 5, 6, 5, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 6, 7, 7, 8, 8, 8, 8, 9, 8, + 9, 9, 9, 9, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 7, 8, + 8, 9, 8, 9, 8, 9, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, + 9, 9, 9, 9, 9, 9,10,10, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9,10, 9,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9, 9, 9, 9, 9, + 9, 9, 9,10, 9, 9,10,10, 9, +}; + +static const static_codebook _44u1__p7_2 = { + 2, 169, + (char *)_vq_lengthlist__44u1__p7_2, + 1, -531103744, 1611661312, 4, 0, + (long *)_vq_quantlist__44u1__p7_2, + 0 +}; + +static const char _huff_lengthlist__44u1__short[] = { + 12,13,14,13,17,12,15,17, 5, 5, 6,10,10,11,15,16, + 4, 3, 3, 7, 5, 7,10,16, 7, 7, 7,10, 9,11,12,16, + 6, 5, 5, 9, 5, 6,10,16, 8, 7, 7, 9, 6, 7, 9,16, + 11, 7, 3, 6, 4, 5, 8,16,12, 9, 4, 8, 5, 7, 9,16, +}; + +static const static_codebook _huff_book__44u1__short = { + 2, 64, + (char *)_huff_lengthlist__44u1__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u2__long[] = { + 5, 9,14,12,15,13,10,13, 7, 4, 5, 6, 8, 7, 8,12, + 13, 4, 3, 5, 5, 6, 9,15,12, 6, 5, 6, 6, 6, 7,14, + 14, 7, 4, 6, 4, 6, 8,15,12, 6, 6, 5, 5, 5, 6,14, + 9, 7, 8, 6, 7, 5, 4,10,10,13,14,14,15,10, 6, 8, +}; + +static const static_codebook _huff_book__44u2__long = { + 2, 64, + (char *)_huff_lengthlist__44u2__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u2__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u2__p1_0[] = { + 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,11,11, 8, + 10,11, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11, + 11, 8,11,11, 8,11,11,11,13,14,11,13,13, 7,11,11, + 10,13,12,11,14,14, 4, 8, 8, 8,11,11, 8,11,11, 8, + 11,11,11,14,13,10,12,13, 8,11,11,11,13,13,11,13, + 13, +}; + +static const static_codebook _44u2__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u2__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u2__p1_0, + 0 +}; + +static const long _vq_quantlist__44u2__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u2__p2_0[] = { + 2, 5, 5, 5, 6, 6, 5, 6, 6, 5, 6, 6, 7, 8, 8, 6, + 8, 8, 5, 6, 6, 6, 8, 7, 7, 8, 8, 5, 6, 6, 7, 8, + 8, 6, 8, 8, 6, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8, + 7,10, 8, 8,10,10, 5, 6, 6, 6, 8, 8, 7, 8, 8, 6, + 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10, + 9, +}; + +static const static_codebook _44u2__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u2__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u2__p2_0, + 0 +}; + +static const long _vq_quantlist__44u2__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u2__p3_0[] = { + 2, 4, 4, 7, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 8, + 9, 9,12,11, 8, 9, 9,11,12, 5, 7, 7,10,10, 7, 9, + 9,11,11, 7, 9, 9,10,11,10,11,11,13,13, 9,10,11, + 12,13, 5, 7, 7,10,10, 7, 9, 9,11,10, 7, 9, 9,11, + 11, 9,11,10,13,13,10,11,11,13,13, 8,10,10,14,13, + 10,11,11,15,14, 9,11,11,15,14,13,14,13,16,14,12, + 13,13,15,16, 8,10,10,13,14, 9,11,11,14,15,10,11, + 11,14,15,12,13,13,15,15,12,13,14,15,16, 5, 7, 7, + 10,10, 7, 9, 9,11,11, 7, 9, 9,11,12,10,11,11,14, + 13,10,11,11,14,14, 7, 9, 9,12,12, 9,11,11,13,13, + 9,11,11,13,13,12,13,12,14,14,11,12,13,15,15, 7, + 9, 9,12,12, 8,11,10,13,12, 9,11,11,13,13,11,13, + 12,15,13,11,13,13,15,16, 9,12,11,15,15,11,12,12, + 16,15,11,12,13,16,16,13,14,15,16,15,13,15,15,17, + 17, 9,11,11,14,15,10,12,12,15,15,11,13,12,15,16, + 13,15,14,16,16,13,15,15,17,19, 5, 7, 7,10,10, 7, + 9, 9,12,11, 7, 9, 9,11,11,10,11,11,14,14,10,11, + 11,13,14, 7, 9, 9,12,12, 9,11,11,13,13, 9,10,11, + 12,13,11,13,12,16,15,11,12,12,14,15, 7, 9, 9,12, + 12, 9,11,11,13,13, 9,11,11,13,12,11,13,12,15,16, + 12,13,13,15,14, 9,11,11,15,14,11,13,12,16,15,10, + 11,12,15,15,13,14,14,18,17,13,14,14,15,17,10,11, + 11,14,15,11,13,12,15,17,11,13,12,15,16,13,15,14, + 18,17,14,15,15,16,18, 7,10,10,14,14,10,12,12,15, + 15,10,12,12,15,15,14,15,15,18,17,13,15,15,16,16, + 9,11,11,16,15,11,13,13,16,18,11,13,13,16,16,15, + 16,16, 0, 0,14,15,16,18,17, 9,11,11,15,15,10,13, + 12,17,16,11,12,13,16,17,14,15,16,19,19,14,15,15, + 0,20,12,14,14, 0, 0,13,14,16,19,18,13,15,16,20, + 17,16,18, 0, 0, 0,15,16,17,18,19,11,14,14, 0,19, + 12,15,14,17,17,13,15,15, 0, 0,16,17,15,20,19,15, + 17,16,19, 0, 8,10,10,14,15,10,12,11,15,15,10,11, + 12,16,15,13,14,14,19,17,14,15,15, 0, 0, 9,11,11, + 16,15,11,13,13,17,16,10,12,13,16,17,14,15,15,18, + 18,14,15,16,20,19, 9,12,12, 0,15,11,13,13,16,17, + 11,13,13,19,17,14,16,16,18,17,15,16,16,17,19,11, + 14,14,18,18,13,14,15, 0, 0,12,14,15,19,18,15,16, + 19, 0,19,15,16,19,19,17,12,14,14,16,19,13,15,15, + 0,17,13,15,14,18,18,15,16,15, 0,18,16,17,17, 0, + 0, +}; + +static const static_codebook _44u2__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u2__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u2__p3_0, + 0 +}; + +static const long _vq_quantlist__44u2__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u2__p4_0[] = { + 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 9, + 9, 9,11,11, 9, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8, + 8,10,10, 7, 7, 8,10,10,10,10,10,11,12, 9,10,10, + 11,12, 5, 7, 7, 9, 9, 6, 8, 7,10,10, 7, 8, 8,10, + 10, 9,10,10,12,11, 9,10,10,12,11, 9,10,10,12,12, + 10,10,10,13,12, 9,10,10,12,13,12,12,12,14,14,11, + 12,12,13,14, 9,10,10,12,12, 9,10,10,12,13,10,10, + 10,12,13,11,12,12,14,13,12,12,12,14,13, 5, 7, 7, + 10, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12, + 12,10,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,11,11, + 8, 9, 9,11,11,10,11,11,12,13,10,11,11,13,13, 6, + 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,13,11,10,11,11,13,13, 9,10,10,13,13,10,11,11, + 13,13,10,11,11,14,13,12,11,13,12,15,12,13,13,15, + 15, 9,10,10,12,13,10,11,10,13,13,10,11,11,13,13, + 12,13,11,15,13,12,13,13,15,15, 5, 7, 7, 9,10, 7, + 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12,12,10,10, + 11,12,12, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 8, 9, + 10,11,10,11,11,13,13,10,10,11,11,13, 7, 8, 8,10, + 11, 8, 9, 9,11,11, 8, 9, 8,11,11,10,11,11,13,13, + 10,11,11,13,12, 9,10,10,13,12,10,11,11,14,13,10, + 10,11,13,13,12,13,13,15,15,12,11,13,12,14, 9,10, + 10,12,13,10,11,11,13,14,10,11,11,13,13,12,13,13, + 15,15,12,13,12,15,12, 8, 9, 9,12,12, 9,11,10,13, + 13, 9,10,10,13,13,12,13,13,15,15,12,12,12,14,14, + 9,10,10,13,13,10,11,11,13,14,10,11,11,14,12,13, + 13,14,14,16,12,13,13,15,14, 9,10,10,13,13,10,11, + 10,14,13,10,11,11,13,14,12,14,13,16,14,13,13,13, + 14,15,11,13,12,15,14,11,12,13,14,15,12,13,13,16, + 15,14,12,15,12,16,14,15,15,17,16,11,12,12,14,15, + 11,13,11,15,14,12,13,13,15,16,13,15,12,17,13,14, + 15,15,16,16, 8, 9, 9,12,12, 9,10,10,13,13, 9,10, + 10,13,13,12,13,12,14,14,12,13,13,15,15, 9,10,10, + 13,13,10,11,11,14,13,10,10,11,13,14,12,13,13,15, + 14,12,12,14,14,16, 9,10,10,13,13,10,11,11,13,14, + 10,11,11,14,13,13,13,13,15,15,13,14,13,16,14,11, + 12,12,14,14,12,13,13,16,15,11,12,13,14,15,14,15, + 15,16,16,14,13,15,13,17,11,12,12,14,15,12,13,13, + 15,16,11,13,12,15,15,14,15,14,16,16,14,15,12,17, + 13, +}; + +static const static_codebook _44u2__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u2__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u2__p4_0, + 0 +}; + +static const long _vq_quantlist__44u2__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u2__p5_0[] = { + 1, 4, 4, 7, 7, 8, 8, 9, 9, 4, 6, 5, 8, 8, 8, 8, + 10,10, 4, 5, 6, 8, 8, 8, 8,10,10, 7, 8, 8, 9, 9, + 9, 9,11,11, 7, 8, 8, 9, 9, 9, 9,11,11, 8, 8, 8, + 9, 9,10,11,12,12, 8, 8, 8, 9, 9,10,10,12,12,10, + 10,10,11,11,12,12,13,13,10,10,10,11,11,12,12,13, + 13, +}; + +static const static_codebook _44u2__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u2__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u2__p5_0, + 0 +}; + +static const long _vq_quantlist__44u2__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u2__p6_0[] = { + 1, 4, 4, 6, 6, 8, 8,10,10,11,11,14,13, 4, 6, 5, + 8, 8, 9, 9,11,10,12,11,15,14, 4, 5, 6, 8, 8, 9, + 9,11,11,11,11,14,14, 6, 8, 8,10, 9,11,11,11,11, + 12,12,15,15, 6, 8, 8, 9, 9,11,11,11,12,12,12,15, + 15, 8,10,10,11,11,11,11,12,12,13,13,15,16, 8,10, + 10,11,11,11,11,12,12,13,13,16,16,10,11,11,12,12, + 12,12,13,13,13,13,17,16,10,11,11,12,12,12,12,13, + 13,13,14,16,17,11,12,12,13,13,13,13,14,14,15,14, + 18,17,11,12,12,13,13,13,13,14,14,14,15,19,18,14, + 15,15,15,15,16,16,18,19,18,18, 0, 0,14,15,15,16, + 15,17,17,16,18,17,18, 0, 0, +}; + +static const static_codebook _44u2__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44u2__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44u2__p6_0, + 0 +}; + +static const long _vq_quantlist__44u2__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u2__p6_1[] = { + 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5, + 6, 5, 6, 6, 5, 5, 6, 6, 6, +}; + +static const static_codebook _44u2__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44u2__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u2__p6_1, + 0 +}; + +static const long _vq_quantlist__44u2__p7_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u2__p7_0[] = { + 1, 3, 2,12,12,12,12,12,12, 4,12,12,12,12,12,12, + 12,12, 5,12,12,12,12,12,12,12,12,12,12,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,11, + 11, +}; + +static const static_codebook _44u2__p7_0 = { + 2, 81, + (char *)_vq_lengthlist__44u2__p7_0, + 1, -516612096, 1626677248, 4, 0, + (long *)_vq_quantlist__44u2__p7_0, + 0 +}; + +static const long _vq_quantlist__44u2__p7_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u2__p7_1[] = { + 1, 4, 4, 7, 6, 7, 6, 8, 7, 9, 7, 9, 8, 4, 7, 6, + 8, 8, 9, 8,10, 9,10,10,11,11, 4, 7, 7, 8, 8, 8, + 8, 9,10,11,11,11,11, 6, 8, 8,10,10,10,10,11,11, + 12,12,12,12, 7, 8, 8,10,10,10,10,11,11,12,12,13, + 13, 7, 9, 9,11,10,12,12,13,13,14,13,14,14, 7, 9, + 9,10,11,11,12,13,13,13,13,16,14, 9,10,10,12,12, + 13,13,14,14,15,16,15,16, 9,10,10,12,12,12,13,14, + 14,14,15,16,15,10,12,12,13,13,15,13,16,16,15,17, + 17,17,10,11,11,12,14,14,14,15,15,17,17,15,17,11, + 12,12,14,14,14,15,15,15,17,16,17,17,10,12,12,13, + 14,14,14,17,15,17,17,17,17, +}; + +static const static_codebook _44u2__p7_1 = { + 2, 169, + (char *)_vq_lengthlist__44u2__p7_1, + 1, -523010048, 1618608128, 4, 0, + (long *)_vq_quantlist__44u2__p7_1, + 0 +}; + +static const long _vq_quantlist__44u2__p7_2[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u2__p7_2[] = { + 2, 5, 5, 6, 6, 7, 7, 8, 7, 8, 8, 8, 8, 5, 6, 6, + 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 5, 6, 6, 7, 7, 8, + 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 6, 7, 7, 8, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 7, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, +}; + +static const static_codebook _44u2__p7_2 = { + 2, 169, + (char *)_vq_lengthlist__44u2__p7_2, + 1, -531103744, 1611661312, 4, 0, + (long *)_vq_quantlist__44u2__p7_2, + 0 +}; + +static const char _huff_lengthlist__44u2__short[] = { + 13,15,17,17,15,15,12,17,11, 9, 7,10,10, 9,12,17, + 10, 6, 3, 6, 5, 7,10,17,15,10, 6, 9, 8, 9,11,17, + 15, 8, 4, 7, 3, 5, 9,16,16,10, 5, 8, 4, 5, 8,16, + 13,11, 5, 8, 3, 3, 5,14,13,12, 7,10, 5, 5, 7,14, +}; + +static const static_codebook _huff_book__44u2__short = { + 2, 64, + (char *)_huff_lengthlist__44u2__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u3__long[] = { + 6, 9,13,12,14,11,10,13, 8, 4, 5, 7, 8, 7, 8,12, + 11, 4, 3, 5, 5, 7, 9,14,11, 6, 5, 6, 6, 6, 7,13, + 13, 7, 5, 6, 4, 5, 7,14,11, 7, 6, 6, 5, 5, 6,13, + 9, 7, 8, 6, 7, 5, 3, 9, 9,12,13,12,14,10, 6, 7, +}; + +static const static_codebook _huff_book__44u3__long = { + 2, 64, + (char *)_huff_lengthlist__44u3__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u3__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u3__p1_0[] = { + 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,10,11, 8, + 10,11, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11, + 11, 8,11,11, 8,11,11,11,13,14,11,14,14, 8,11,11, + 10,14,12,11,14,14, 4, 8, 8, 8,11,11, 8,11,11, 7, + 11,11,11,14,14,10,12,14, 8,11,11,11,14,14,11,14, + 13, +}; + +static const static_codebook _44u3__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u3__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u3__p1_0, + 0 +}; + +static const long _vq_quantlist__44u3__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u3__p2_0[] = { + 2, 5, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 7, 8, 8, 6, + 8, 8, 5, 6, 6, 6, 8, 8, 7, 8, 8, 5, 7, 6, 7, 8, + 8, 6, 8, 8, 7, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8, + 8,10, 8, 8,10,10, 5, 6, 6, 6, 8, 8, 7, 8, 8, 6, + 8, 8, 8,10,10, 8, 8,10, 7, 8, 8, 8,10,10, 8,10, + 9, +}; + +static const static_codebook _44u3__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u3__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u3__p2_0, + 0 +}; + +static const long _vq_quantlist__44u3__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u3__p3_0[] = { + 2, 4, 4, 7, 7, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 8, + 9, 9,12,12, 8, 9, 9,11,12, 5, 7, 7,10,10, 7, 9, + 9,11,11, 7, 9, 9,10,11,10,11,11,13,13, 9,10,11, + 13,13, 5, 7, 7,10,10, 7, 9, 9,11,10, 7, 9, 9,11, + 11, 9,11,10,13,13,10,11,11,14,13, 8,10,10,14,13, + 10,11,11,15,14, 9,11,11,14,14,13,14,13,16,16,12, + 13,13,15,15, 8,10,10,13,14, 9,11,11,14,14,10,11, + 11,14,15,12,13,13,15,15,13,14,14,15,16, 5, 7, 7, + 10,10, 7, 9, 9,11,11, 7, 9, 9,11,12,10,11,11,14, + 14,10,11,11,14,14, 7, 9, 9,12,12, 9,11,11,13,13, + 9,11,11,13,13,12,12,13,15,15,11,12,13,15,16, 7, + 9, 9,11,11, 8,11,10,13,12, 9,11,11,13,13,11,13, + 12,15,13,11,13,13,15,16, 9,12,11,15,14,11,12,13, + 16,15,11,13,13,15,16,14,14,15,17,16,13,15,16, 0, + 17, 9,11,11,15,15,10,13,12,15,15,11,13,13,15,16, + 13,15,13,16,15,14,16,15, 0,19, 5, 7, 7,10,10, 7, + 9, 9,11,11, 7, 9, 9,11,11,10,12,11,14,14,10,11, + 12,14,14, 7, 9, 9,12,12, 9,11,11,14,13, 9,10,11, + 12,13,11,13,13,16,16,11,12,13,13,16, 7, 9, 9,12, + 12, 9,11,11,13,13, 9,11,11,13,13,11,13,13,15,15, + 12,13,12,15,14, 9,11,11,15,14,11,13,12,16,16,10, + 12,12,15,15,13,15,15,17,19,13,14,15,16,17,10,12, + 12,15,15,11,13,13,16,16,11,13,13,15,16,13,15,15, + 0, 0,14,15,15,16,16, 8,10,10,14,14,10,12,12,15, + 15,10,12,11,15,16,14,15,15,19,20,13,14,14,18,16, + 9,11,11,15,15,11,13,13,17,16,11,13,13,16,16,15, + 17,17,20,20,14,15,16,17,20, 9,11,11,15,15,10,13, + 12,16,15,11,13,13,15,17,14,16,15,18, 0,14,16,15, + 18,20,12,14,14, 0, 0,14,14,16, 0, 0,13,16,15, 0, + 0,17,17,18, 0, 0,16,17,19,19, 0,12,14,14,18, 0, + 12,16,14, 0,17,13,15,15,18, 0,16,18,17, 0,17,16, + 18,17, 0, 0, 7,10,10,14,14,10,12,11,15,15,10,12, + 12,16,15,13,15,15,18, 0,14,15,15,17, 0, 9,11,11, + 15,15,11,13,13,16,16,11,12,13,16,16,14,15,16,17, + 17,14,16,16,16,18, 9,11,12,16,16,11,13,13,17,17, + 11,14,13,20,17,15,16,16,19, 0,15,16,17, 0,19,11, + 13,14,17,16,14,15,15,20,18,13,14,15,17,19,16,18, + 18, 0,20,16,16,19,17, 0,12,15,14,17, 0,14,15,15, + 18,19,13,16,15,19,20,15,18,18, 0,20,17, 0,16, 0, + 0, +}; + +static const static_codebook _44u3__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u3__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u3__p3_0, + 0 +}; + +static const long _vq_quantlist__44u3__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u3__p4_0[] = { + 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 9, + 9, 9,11,11, 9, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8, + 8,10,10, 7, 7, 8,10,10, 9,10,10,11,12, 9,10,10, + 11,12, 5, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 8,10, + 10, 9,10, 9,12,11, 9,10,10,12,11, 9,10, 9,12,12, + 9,10,10,13,12, 9,10,10,12,13,12,12,12,14,14,11, + 12,12,13,14, 9, 9,10,12,12, 9,10,10,12,12, 9,10, + 10,12,13,11,12,11,14,13,12,12,12,14,13, 5, 7, 7, + 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12, + 12, 9,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,11,11, + 8, 9, 9,11,11,11,11,11,12,13,10,11,11,13,13, 6, + 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,13,11,10,11,11,13,13, 9,11,10,13,12,10,11,11, + 13,13,10,11,11,13,13,12,12,13,12,15,12,13,13,15, + 15, 9,10,10,12,13,10,11,10,13,12,10,11,11,13,14, + 12,13,11,15,13,12,13,13,15,15, 5, 7, 7, 9, 9, 7, + 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12,10,10, + 11,12,12, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 8, 9, + 10,11,10,11,11,13,13,10,10,11,11,13, 7, 8, 8,10, + 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,11,13,13, + 11,11,11,13,12, 9,10,10,13,12,10,11,11,14,13,10, + 10,11,12,13,12,13,13,15,15,12,11,13,13,14, 9,10, + 11,12,13,10,11,11,13,13,10,11,11,13,13,12,13,13, + 15,15,12,13,12,15,12, 8, 9, 9,12,12, 9,11,10,13, + 13, 9,10,10,13,13,12,13,13,15,14,12,12,12,14,13, + 9,10,10,13,12,10,11,11,13,13,10,11,11,14,12,13, + 13,14,14,16,12,13,13,15,15, 9,10,10,13,13,10,11, + 10,14,13,10,11,11,13,14,12,14,13,15,14,13,13,13, + 15,15,11,13,12,15,14,11,12,13,14,15,12,13,13,16, + 14,14,12,15,12,16,14,15,15,17,15,11,12,12,14,14, + 11,13,11,15,14,12,13,13,15,15,13,15,12,17,13,14, + 15,15,16,16, 8, 9, 9,12,12, 9,10,10,12,13, 9,10, + 10,13,13,12,12,12,14,14,12,13,13,15,15, 9,10,10, + 13,12,10,11,11,14,13,10,10,11,13,14,12,13,13,15, + 15,12,12,13,14,16, 9,10,10,13,13,10,11,11,13,14, + 10,11,11,14,13,12,13,13,14,15,13,14,13,16,14,11, + 12,12,14,14,12,13,13,15,14,11,12,13,14,15,14,15, + 15,16,16,13,13,15,13,16,11,12,12,14,15,12,13,13, + 14,15,11,13,12,15,14,14,15,15,16,16,14,15,12,16, + 13, +}; + +static const static_codebook _44u3__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u3__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u3__p4_0, + 0 +}; + +static const long _vq_quantlist__44u3__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u3__p5_0[] = { + 2, 3, 3, 6, 6, 7, 7, 9, 9, 4, 5, 5, 7, 7, 8, 8, + 10,10, 4, 5, 5, 7, 7, 8, 8,10,10, 6, 7, 7, 8, 8, + 9, 9,11,10, 6, 7, 7, 8, 8, 9, 9,10,10, 7, 8, 8, + 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9, + 10,10,11,10,11,11,12,12, 9,10,10,10,10,11,11,12, + 12, +}; + +static const static_codebook _44u3__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u3__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u3__p5_0, + 0 +}; + +static const long _vq_quantlist__44u3__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u3__p6_0[] = { + 1, 4, 4, 6, 6, 8, 8, 9, 9,10,11,13,14, 4, 6, 5, + 8, 8, 9, 9,10,10,11,11,14,14, 4, 6, 6, 8, 8, 9, + 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11, + 12,12,15,15, 6, 8, 8, 9, 9,10,11,11,11,12,12,15, + 15, 8, 9, 9,11,10,11,11,12,12,13,13,15,16, 8, 9, + 9,10,11,11,11,12,12,13,13,16,16,10,10,11,11,11, + 12,12,13,13,13,14,17,16, 9,10,11,12,11,12,12,13, + 13,13,13,16,18,11,12,11,12,12,13,13,13,14,15,14, + 17,17,11,11,12,12,12,13,13,13,14,14,15,18,17,14, + 15,15,15,15,16,16,17,17,19,18, 0,20,14,15,14,15, + 15,16,16,16,17,18,16,20,18, +}; + +static const static_codebook _44u3__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44u3__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44u3__p6_0, + 0 +}; + +static const long _vq_quantlist__44u3__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u3__p6_1[] = { + 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5, + 6, 5, 6, 6, 5, 5, 6, 6, 6, +}; + +static const static_codebook _44u3__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44u3__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u3__p6_1, + 0 +}; + +static const long _vq_quantlist__44u3__p7_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u3__p7_0[] = { + 1, 3, 3,10,10,10,10,10,10, 4,10,10,10,10,10,10, + 10,10, 4,10,10,10,10,10,10,10,10,10,10, 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, +}; + +static const static_codebook _44u3__p7_0 = { + 2, 81, + (char *)_vq_lengthlist__44u3__p7_0, + 1, -515907584, 1627381760, 4, 0, + (long *)_vq_quantlist__44u3__p7_0, + 0 +}; + +static const long _vq_quantlist__44u3__p7_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u3__p7_1[] = { + 1, 4, 4, 6, 6, 7, 6, 8, 7, 9, 8,10, 9,11,11, 4, + 7, 7, 8, 7, 9, 9,10,10,11,11,11,11,12,12, 4, 7, + 7, 7, 7, 9, 9,10,10,11,11,12,12,12,11, 6, 8, 8, + 9, 9,10,10,11,11,12,12,13,12,13,13, 6, 8, 8, 9, + 9,10,11,11,11,12,12,13,14,13,13, 8, 9, 9,11,11, + 12,12,12,13,14,13,14,14,14,15, 8, 9, 9,11,11,11, + 12,13,14,13,14,15,17,14,15, 9,10,10,12,12,13,13, + 13,14,15,15,15,16,16,16, 9,11,11,12,12,13,13,14, + 14,14,15,16,16,16,16,10,12,12,13,13,14,14,15,15, + 15,16,17,17,17,17,10,12,11,13,13,15,14,15,14,16, + 17,16,16,16,16,11,13,12,14,14,14,14,15,16,17,16, + 17,17,17,17,11,13,12,14,14,14,15,17,16,17,17,17, + 17,17,17,12,13,13,15,16,15,16,17,17,16,16,17,17, + 17,17,12,13,13,15,15,15,16,17,17,17,16,17,16,17, + 17, +}; + +static const static_codebook _44u3__p7_1 = { + 2, 225, + (char *)_vq_lengthlist__44u3__p7_1, + 1, -522338304, 1620115456, 4, 0, + (long *)_vq_quantlist__44u3__p7_1, + 0 +}; + +static const long _vq_quantlist__44u3__p7_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44u3__p7_2[] = { + 2, 5, 5, 7, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 10,10, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 8, 9, 9, 9, + 9,10, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 10,10,10,10, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10, + 9,10,10,10,10, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10, 7, 8, 8, 9, 8, 9, 9, 9, 9,10, + 9,10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9,10,10,10,10,10,10,10, 8, 9, 8, 9, 9, 9, 9,10, + 9,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9,10, + 9,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10, + 9,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,10, 9, + 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,11, 9,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,11, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9,10,10,10,10,10,10,10,10,10,10,10,11,11,11,10, + 11, +}; + +static const static_codebook _44u3__p7_2 = { + 2, 289, + (char *)_vq_lengthlist__44u3__p7_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44u3__p7_2, + 0 +}; + +static const char _huff_lengthlist__44u3__short[] = { + 14,14,14,15,13,15,12,16,10, 8, 7, 9, 9, 8,12,16, + 10, 5, 4, 6, 5, 6, 9,16,14, 8, 6, 8, 7, 8,10,16, + 14, 7, 4, 6, 3, 5, 8,16,15, 9, 5, 7, 4, 4, 7,16, + 13,10, 6, 7, 4, 3, 4,13,13,12, 7, 9, 5, 5, 6,12, +}; + +static const static_codebook _huff_book__44u3__short = { + 2, 64, + (char *)_huff_lengthlist__44u3__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u4__long[] = { + 3, 8,12,12,13,12,11,13, 5, 4, 6, 7, 8, 8, 9,13, + 9, 5, 4, 5, 5, 7, 9,13, 9, 6, 5, 6, 6, 7, 8,12, + 12, 7, 5, 6, 4, 5, 8,13,11, 7, 6, 6, 5, 5, 6,12, + 10, 8, 8, 7, 7, 5, 3, 8,10,12,13,12,12, 9, 6, 7, +}; + +static const static_codebook _huff_book__44u4__long = { + 2, 64, + (char *)_huff_lengthlist__44u4__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u4__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u4__p1_0[] = { + 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,10,11, 8, + 10,11, 5, 8, 8, 8,11,10, 8,11,11, 4, 8, 8, 8,11, + 11, 8,11,11, 8,11,11,11,13,14,11,15,14, 8,11,11, + 10,13,12,11,14,14, 4, 8, 8, 8,11,11, 8,11,11, 7, + 11,11,11,15,14,10,12,14, 8,11,11,11,14,14,11,14, + 13, +}; + +static const static_codebook _44u4__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u4__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u4__p1_0, + 0 +}; + +static const long _vq_quantlist__44u4__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u4__p2_0[] = { + 2, 5, 5, 5, 6, 6, 5, 6, 6, 5, 6, 6, 7, 8, 8, 6, + 8, 8, 5, 6, 6, 6, 8, 8, 7, 8, 8, 5, 7, 6, 6, 8, + 8, 6, 8, 8, 6, 8, 8, 8, 9,10, 8,10,10, 6, 8, 8, + 8,10, 8, 8,10,10, 5, 6, 6, 6, 8, 8, 6, 8, 8, 6, + 8, 8, 8,10,10, 8, 8,10, 6, 8, 8, 8,10,10, 8,10, + 9, +}; + +static const static_codebook _44u4__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u4__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u4__p2_0, + 0 +}; + +static const long _vq_quantlist__44u4__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u4__p3_0[] = { + 2, 4, 4, 8, 8, 5, 7, 7, 9, 9, 5, 7, 7, 9, 9, 8, + 10, 9,12,12, 8, 9,10,12,12, 5, 7, 7,10,10, 7, 9, + 9,11,11, 7, 9, 9,11,11,10,12,11,14,14, 9,10,11, + 13,14, 5, 7, 7,10,10, 7, 9, 9,11,11, 7, 9, 9,11, + 11, 9,11,10,14,13,10,11,11,14,14, 8,10,10,14,13, + 10,12,12,15,14, 9,11,11,15,14,13,14,14,17,17,12, + 14,14,16,16, 8,10,10,14,14, 9,11,11,14,15,10,12, + 12,14,15,12,14,13,16,16,13,14,15,15,18, 4, 7, 7, + 10,10, 7, 9, 9,12,11, 7, 9, 9,11,12,10,12,11,15, + 14,10,11,12,14,15, 7, 9, 9,12,12, 9,11,12,13,13, + 9,11,12,13,13,12,13,13,15,16,11,13,13,15,16, 7, + 9, 9,12,12, 9,11,10,13,12, 9,11,12,13,14,11,13, + 12,16,14,12,13,13,15,16,10,12,12,16,15,11,13,13, + 17,16,11,13,13,17,16,14,15,15,17,17,14,16,16,18, + 20, 9,11,11,15,16,11,13,12,16,16,11,13,13,16,17, + 14,15,14,18,16,14,16,16,17,20, 5, 7, 7,10,10, 7, + 9, 9,12,11, 7, 9,10,11,12,10,12,11,15,15,10,12, + 12,14,14, 7, 9, 9,12,12, 9,12,11,14,13, 9,10,11, + 12,13,12,13,14,16,16,11,12,13,14,16, 7, 9, 9,12, + 12, 9,12,11,13,13, 9,12,11,13,13,11,13,13,16,16, + 12,13,13,16,15, 9,11,11,16,14,11,13,13,16,16,11, + 12,13,16,16,14,16,16,17,17,13,14,15,16,17,10,12, + 12,15,15,11,13,13,16,17,11,13,13,16,16,14,16,15, + 19,19,14,15,15,17,18, 8,10,10,14,14,10,12,12,15, + 15,10,12,12,16,16,14,16,15,20,19,13,15,15,17,16, + 9,12,12,16,16,11,13,13,16,18,11,14,13,16,17,16, + 17,16,20, 0,15,16,18,18,20, 9,11,11,15,15,11,14, + 12,17,16,11,13,13,17,17,15,17,15,20,20,14,16,16, + 17, 0,13,15,14,18,16,14,15,16, 0,18,14,16,16, 0, + 0,18,16, 0, 0,20,16,18,18, 0, 0,12,14,14,17,18, + 13,15,14,20,18,14,16,15,19,19,16,20,16, 0,18,16, + 19,17,19, 0, 8,10,10,14,14,10,12,12,16,15,10,12, + 12,16,16,13,15,15,18,17,14,16,16,19, 0, 9,11,11, + 16,15,11,14,13,18,17,11,12,13,17,18,14,17,16,18, + 18,15,16,17,18,18, 9,12,12,16,16,11,13,13,16,18, + 11,14,13,17,17,15,16,16,18,20,16,17,17,20,20,12, + 14,14,18,17,14,16,16, 0,19,13,14,15,18, 0,16, 0, + 0, 0, 0,16,16, 0,19,20,13,15,14, 0, 0,14,16,16, + 18,19,14,16,15, 0,20,16,20,18, 0,20,17,20,17, 0, + 0, +}; + +static const static_codebook _44u4__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u4__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u4__p3_0, + 0 +}; + +static const long _vq_quantlist__44u4__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u4__p4_0[] = { + 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 9, + 9, 9,11,11, 8, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8, + 8,10,10, 7, 7, 8,10,10, 9,10,10,11,12, 9,10,10, + 11,12, 5, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 8,10, + 10, 9,10,10,12,11, 9,10,10,12,11, 9,10, 9,12,12, + 9,10,10,13,12, 9,10,10,12,12,12,12,12,14,14,11, + 12,12,13,14, 9, 9,10,12,12, 9,10,10,13,13, 9,10, + 10,12,13,11,12,12,14,13,11,12,12,14,14, 5, 7, 7, + 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10,10,10,10,12, + 12, 9,10,10,12,12, 7, 8, 8,11,10, 8, 8, 9,11,11, + 8, 9, 9,11,11,11,11,11,12,13,10,11,11,13,13, 6, + 8, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,13,11,10,11,11,13,13, 9,11,10,13,12,10,11,11, + 13,14,10,11,11,14,13,12,12,13,12,15,12,13,13,15, + 15, 9,10,10,12,13,10,11,10,13,12,10,11,11,13,14, + 12,13,11,15,13,13,13,13,15,15, 5, 7, 7, 9, 9, 7, + 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12,10,10, + 11,12,13, 6, 8, 8,10,10, 8, 9, 9,11,11, 7, 8, 9, + 10,11,10,11,11,13,13,10,10,11,11,13, 7, 8, 8,10, + 11, 8, 9, 9,11,11, 8, 9, 8,11,11,10,11,11,13,13, + 11,12,11,13,12, 9,10,10,13,12,10,11,11,14,13,10, + 10,11,12,13,12,13,13,15,15,12,11,13,13,14, 9,10, + 11,12,13,10,11,11,13,14,10,11,11,13,13,12,13,13, + 15,15,12,13,12,15,12, 8, 9, 9,12,12, 9,11,10,13, + 13, 9,10,10,13,13,12,13,13,15,15,12,12,12,14,14, + 9,10,10,13,13,10,11,11,13,14,10,11,11,14,13,13, + 13,14,14,16,13,13,13,15,15, 9,10,10,13,13,10,11, + 10,14,13,10,11,11,13,14,12,14,13,16,14,12,13,13, + 14,15,11,12,12,15,14,11,12,13,14,15,12,13,13,16, + 15,14,12,15,12,16,14,15,15,16,16,11,12,12,14,14, + 11,13,12,15,14,12,13,13,15,16,13,15,13,17,13,14, + 15,15,16,17, 8, 9, 9,12,12, 9,10,10,12,13, 9,10, + 10,13,13,12,12,12,14,14,12,13,13,15,15, 9,10,10, + 13,12,10,11,11,14,13,10,10,11,13,14,13,13,13,15, + 15,12,13,14,14,16, 9,10,10,13,13,10,11,11,13,14, + 10,11,11,14,14,13,13,13,15,15,13,14,13,16,14,11, + 12,12,15,14,12,13,13,16,15,11,12,13,14,15,14,15, + 15,17,16,13,13,15,13,16,11,12,13,14,15,13,13,13, + 15,16,11,13,12,15,14,14,15,15,16,16,14,15,12,17, + 13, +}; + +static const static_codebook _44u4__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u4__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u4__p4_0, + 0 +}; + +static const long _vq_quantlist__44u4__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u4__p5_0[] = { + 2, 3, 3, 6, 6, 7, 7, 9, 9, 4, 5, 5, 7, 7, 8, 8, + 10, 9, 4, 5, 5, 7, 7, 8, 8,10,10, 6, 7, 7, 8, 8, + 9, 9,11,10, 6, 7, 7, 8, 8, 9, 9,10,11, 7, 8, 8, + 9, 9,10,10,11,11, 7, 8, 8, 9, 9,10,10,11,11, 9, + 10,10,11,10,11,11,12,12, 9,10,10,10,11,11,11,12, + 12, +}; + +static const static_codebook _44u4__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u4__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u4__p5_0, + 0 +}; + +static const long _vq_quantlist__44u4__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u4__p6_0[] = { + 1, 4, 4, 6, 6, 8, 8, 9, 9,11,10,13,13, 4, 6, 5, + 8, 8, 9, 9,10,10,11,11,14,14, 4, 6, 6, 8, 8, 9, + 9,10,10,11,11,14,14, 6, 8, 8, 9, 9,10,10,11,11, + 12,12,15,15, 6, 8, 8, 9, 9,10,11,11,11,12,12,15, + 15, 8, 9, 9,11,10,11,11,12,12,13,13,16,16, 8, 9, + 9,10,10,11,11,12,12,13,13,16,16,10,10,10,12,11, + 12,12,13,13,14,14,16,16,10,10,10,11,12,12,12,13, + 13,13,14,16,17,11,12,11,12,12,13,13,14,14,15,14, + 18,17,11,11,12,12,12,13,13,14,14,14,15,19,18,14, + 15,14,15,15,17,16,17,17,17,17,21, 0,14,15,15,16, + 16,16,16,17,17,18,17,20,21, +}; + +static const static_codebook _44u4__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44u4__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44u4__p6_0, + 0 +}; + +static const long _vq_quantlist__44u4__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u4__p6_1[] = { + 2, 4, 4, 5, 5, 4, 5, 5, 6, 5, 4, 5, 5, 5, 6, 5, + 6, 5, 6, 6, 5, 5, 6, 6, 6, +}; + +static const static_codebook _44u4__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44u4__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u4__p6_1, + 0 +}; + +static const long _vq_quantlist__44u4__p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u4__p7_0[] = { + 1, 3, 3,12,12,12,12,12,12,12,12,12,12, 3,12,11, + 12,12,12,12,12,12,12,12,12,12, 4,11,10,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,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,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,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, +}; + +static const static_codebook _44u4__p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44u4__p7_0, + 1, -514332672, 1627381760, 4, 0, + (long *)_vq_quantlist__44u4__p7_0, + 0 +}; + +static const long _vq_quantlist__44u4__p7_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u4__p7_1[] = { + 1, 4, 4, 6, 6, 7, 7, 9, 8,10, 8,10, 9,11,11, 4, + 7, 6, 8, 7, 9, 9,10,10,11,10,11,10,12,10, 4, 6, + 7, 8, 8, 9, 9,10,10,11,11,11,11,12,12, 6, 8, 8, + 10, 9,11,10,12,11,12,12,12,12,13,13, 6, 8, 8,10, + 10,10,11,11,11,12,12,13,12,13,13, 8, 9, 9,11,11, + 12,11,12,12,13,13,13,13,13,13, 8, 9, 9,11,11,11, + 12,12,12,13,13,13,13,13,13, 9,10,10,12,11,13,13, + 13,13,14,13,13,14,14,14, 9,10,11,11,12,12,13,13, + 13,13,13,14,15,14,14,10,11,11,12,12,13,13,14,14, + 14,14,14,15,16,16,10,11,11,12,13,13,13,13,15,14, + 14,15,16,15,16,10,12,12,13,13,14,14,14,15,15,15, + 15,15,15,16,11,12,12,13,13,14,14,14,15,15,15,16, + 15,17,16,11,12,12,13,13,13,15,15,14,16,16,16,16, + 16,17,11,12,12,13,13,14,14,15,14,15,15,17,17,16, + 16, +}; + +static const static_codebook _44u4__p7_1 = { + 2, 225, + (char *)_vq_lengthlist__44u4__p7_1, + 1, -522338304, 1620115456, 4, 0, + (long *)_vq_quantlist__44u4__p7_1, + 0 +}; + +static const long _vq_quantlist__44u4__p7_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44u4__p7_2[] = { + 2, 5, 5, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 10,10,10,10, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10, + 9,10, 9,10,10, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9,10,10,10,10,10,10, 8, 9, 8, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10,10, + 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9,10, + 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,11,10,10,10, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, + 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, + 10, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9,10, 9,10,10,10,10,10,10,10,10,10,10,11,10,10, + 10, +}; + +static const static_codebook _44u4__p7_2 = { + 2, 289, + (char *)_vq_lengthlist__44u4__p7_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44u4__p7_2, + 0 +}; + +static const char _huff_lengthlist__44u4__short[] = { + 14,17,15,17,16,14,13,16,10, 7, 7,10,13,10,15,16, + 9, 4, 4, 6, 5, 7, 9,16,12, 8, 7, 8, 8, 8,11,16, + 14, 7, 4, 6, 3, 5, 8,15,13, 8, 5, 7, 4, 5, 7,16, + 12, 9, 6, 8, 3, 3, 5,16,14,13, 7,10, 5, 5, 7,15, +}; + +static const static_codebook _huff_book__44u4__short = { + 2, 64, + (char *)_huff_lengthlist__44u4__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u5__long[] = { + 3, 8,13,12,14,12,16,11,13,14, 5, 4, 5, 6, 7, 8, + 10, 9,12,15,10, 5, 5, 5, 6, 8, 9, 9,13,15,10, 5, + 5, 6, 6, 7, 8, 8,11,13,12, 7, 5, 6, 4, 6, 7, 7, + 11,14,11, 7, 7, 6, 6, 6, 7, 6,10,14,14, 9, 8, 8, + 6, 7, 7, 7,11,16,11, 8, 8, 7, 6, 6, 7, 4, 7,12, + 10,10,12,10,10, 9,10, 5, 6, 9,10,12,15,13,14,14, + 14, 8, 7, 8, +}; + +static const static_codebook _huff_book__44u5__long = { + 2, 100, + (char *)_huff_lengthlist__44u5__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u5__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u5__p1_0[] = { + 1, 4, 4, 5, 8, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7, + 9,10, 5, 8, 8, 7,10, 9, 8,10,10, 5, 8, 8, 8,10, + 10, 8,10,10, 8,10,10,10,12,13,10,13,13, 7,10,10, + 10,13,11,10,13,13, 4, 8, 8, 8,11,10, 8,10,10, 7, + 10,10,10,13,13,10,11,13, 8,10,11,10,13,13,10,13, + 12, +}; + +static const static_codebook _44u5__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u5__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u5__p1_0, + 0 +}; + +static const long _vq_quantlist__44u5__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u5__p2_0[] = { + 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 8, 8, 6, + 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 8, 5, 6, 6, 6, 8, + 8, 6, 8, 8, 6, 8, 8, 8, 9, 9, 8, 9, 9, 6, 8, 7, + 7, 9, 8, 8, 9, 9, 5, 6, 6, 6, 8, 7, 6, 8, 8, 6, + 8, 7, 8, 9, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 8, 9, + 9, +}; + +static const static_codebook _44u5__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u5__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u5__p2_0, + 0 +}; + +static const long _vq_quantlist__44u5__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u5__p3_0[] = { + 2, 4, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8, + 10, 9,13,12, 8, 9,10,12,12, 5, 7, 7,10,10, 7, 9, + 9,11,11, 6, 8, 9,11,11,10,11,11,14,14, 9,10,11, + 13,14, 5, 7, 7, 9,10, 7, 9, 8,11,11, 7, 9, 9,11, + 11, 9,11,10,14,13,10,11,11,14,14, 8,10,10,13,13, + 10,11,11,15,14, 9,11,11,14,14,13,14,14,17,16,12, + 13,13,15,16, 8,10,10,13,13, 9,11,11,14,15,10,11, + 11,14,15,12,14,13,16,16,13,15,14,15,17, 5, 7, 7, + 10,10, 7, 9, 9,11,11, 7, 9, 9,11,11,10,11,11,14, + 14,10,11,12,14,14, 7, 9, 9,12,11, 9,11,11,13,13, + 9,11,11,13,13,12,13,13,15,16,11,12,13,15,16, 6, + 9, 9,11,11, 8,11,10,13,12, 9,11,11,13,14,11,13, + 12,16,14,11,13,13,16,17,10,12,11,15,15,11,13,13, + 16,16,11,13,13,17,16,14,15,15,17,17,14,16,16,17, + 18, 9,11,11,14,15,10,12,12,15,15,11,13,13,16,17, + 13,15,13,17,15,14,15,16,18, 0, 5, 7, 7,10,10, 7, + 9, 9,11,11, 7, 9, 9,11,11,10,11,11,14,14,10,11, + 12,14,15, 6, 9, 9,12,11, 9,11,11,13,13, 8,10,11, + 12,13,11,13,13,16,15,11,12,13,14,15, 7, 9, 9,11, + 12, 9,11,11,13,13, 9,11,11,13,13,11,13,13,15,16, + 11,13,13,15,14, 9,11,11,15,14,11,13,13,17,15,10, + 12,12,15,15,14,16,16,17,17,13,13,15,15,17,10,11, + 12,15,15,11,13,13,16,16,11,13,13,15,15,14,15,15, + 18,18,14,15,15,17,17, 8,10,10,13,13,10,12,11,15, + 15,10,11,12,15,15,14,15,15,18,18,13,14,14,18,18, + 9,11,11,15,16,11,13,13,17,17,11,13,13,16,16,15, + 15,16,17, 0,14,15,17, 0, 0, 9,11,11,15,15,10,13, + 12,18,16,11,13,13,15,16,14,16,15,20,20,14,15,16, + 17, 0,13,14,14,20,16,14,15,16,19,18,14,15,15,19, + 0,18,16, 0,20,20,16,18,18, 0, 0,12,14,14,18,18, + 13,15,14,18,16,14,15,16,18,20,16,19,16, 0,17,17, + 18,18,19, 0, 8,10,10,14,14,10,11,11,14,15,10,11, + 12,15,15,13,15,14,19,17,13,15,15,17, 0, 9,11,11, + 16,15,11,13,13,16,16,10,12,13,15,17,14,16,16,18, + 18,14,15,15,18, 0, 9,11,11,15,15,11,13,13,16,17, + 11,13,13,18,17,14,18,16,18,18,15,17,17,18, 0,12, + 14,14,18,18,14,15,15,20, 0,13,14,15,17, 0,16,18, + 17, 0, 0,16,16, 0,17,20,12,14,14,18,18,14,16,15, + 0,18,14,16,15,18, 0,16,19,17, 0, 0,17,18,16, 0, + 0, +}; + +static const static_codebook _44u5__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u5__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u5__p3_0, + 0 +}; + +static const long _vq_quantlist__44u5__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u5__p4_0[] = { + 4, 5, 5, 8, 8, 6, 7, 6, 9, 9, 6, 6, 7, 9, 9, 8, + 9, 9,11,11, 8, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 8, + 8,10,10, 6, 7, 8, 9,10, 9,10,10,11,12, 9, 9,10, + 11,12, 6, 7, 7, 9, 9, 6, 8, 7,10, 9, 7, 8, 8,10, + 10, 9,10, 9,12,11, 9,10,10,12,11, 8, 9, 9,12,11, + 9,10,10,12,12, 9,10,10,12,12,11,12,12,13,14,11, + 11,12,13,14, 8, 9, 9,11,12, 9,10,10,12,12, 9,10, + 10,12,12,11,12,11,14,13,11,12,12,13,13, 5, 7, 7, + 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12, + 12, 9,10,10,12,12, 7, 8, 8,10,10, 8, 8, 9,10,11, + 8, 9, 9,11,11,10,10,11,11,13,10,11,11,12,13, 6, + 7, 8,10,10, 7, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,13,11,10,11,11,12,12, 9,10,10,12,12,10,10,11, + 12,13,10,11,11,13,13,12,11,13,12,15,12,13,13,14, + 15, 9,10,10,12,12, 9,11,10,13,12,10,11,11,13,13, + 11,13,11,14,12,12,13,13,14,15, 5, 7, 7, 9, 9, 7, + 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12, 9,10, + 10,12,12, 6, 8, 7,10,10, 8, 9, 9,11,11, 7, 8, 9, + 10,11,10,11,11,12,12,10,10,11,11,13, 7, 8, 8,10, + 10, 8, 9, 9,11,11, 8, 9, 8,11,10,10,11,11,13,12, + 10,11,10,13,11, 9,10,10,12,12,10,11,11,13,12, 9, + 10,10,12,13,12,13,13,14,15,11,11,13,12,14, 9,10, + 10,12,12,10,11,11,13,13,10,11,10,13,12,12,13,13, + 14,14,12,13,11,14,12, 8, 9, 9,12,12, 9,10,10,12, + 12, 9,10,10,12,12,12,12,12,14,14,11,12,12,14,13, + 9,10,10,12,12,10,11,11,13,13,10,11,11,13,12,12, + 12,13,14,15,12,13,13,15,14, 9,10,10,12,12,10,11, + 10,13,12,10,11,11,12,13,12,13,12,15,13,12,13,13, + 14,15,11,12,12,14,13,11,12,12,14,15,12,13,13,15, + 14,13,12,14,12,16,13,14,14,15,15,11,11,12,14,14, + 11,12,11,14,13,12,13,13,14,15,13,14,12,16,12,14, + 14,15,16,16, 8, 9, 9,11,12, 9,10,10,12,12, 9,10, + 10,12,13,11,12,12,13,13,12,12,13,14,14, 9,10,10, + 12,12,10,11,10,13,12,10,10,11,12,13,12,13,13,15, + 14,12,12,13,13,15, 9,10,10,12,13,10,11,11,12,13, + 10,11,11,13,13,12,13,13,14,15,12,13,12,15,14,11, + 12,11,14,13,12,13,13,15,14,11,11,12,13,14,14,15, + 14,16,15,13,12,14,13,16,11,12,12,13,14,12,13,13, + 14,15,11,12,11,14,14,14,14,14,15,16,13,15,12,16, + 12, +}; + +static const static_codebook _44u5__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u5__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u5__p4_0, + 0 +}; + +static const long _vq_quantlist__44u5__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u5__p5_0[] = { + 2, 3, 3, 6, 6, 8, 8,10,10, 4, 5, 5, 8, 7, 8, 8, + 11,10, 3, 5, 5, 7, 8, 8, 8,10,11, 6, 8, 7,10, 9, + 10,10,11,11, 6, 7, 8, 9, 9, 9,10,11,12, 8, 8, 8, + 10,10,11,11,13,12, 8, 8, 9, 9,10,11,11,12,13,10, + 11,10,12,11,13,12,14,14,10,10,11,11,12,12,13,14, + 14, +}; + +static const static_codebook _44u5__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u5__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u5__p5_0, + 0 +}; + +static const long _vq_quantlist__44u5__p6_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u5__p6_0[] = { + 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 7, 7, + 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7, + 8, 8,10,10, 6, 6, 6, 7, 7, 8, 8,10,10, 7, 7, 7, + 8, 8, 9, 9,11,10, 7, 7, 7, 8, 8, 9, 9,10,11, 9, + 9, 9,10,10,11,10,11,11, 9, 9, 9,10,10,11,10,11, + 11, +}; + +static const static_codebook _44u5__p6_0 = { + 2, 81, + (char *)_vq_lengthlist__44u5__p6_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u5__p6_0, + 0 +}; + +static const long _vq_quantlist__44u5__p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u5__p7_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 9, 8,11,10, 7, + 11,10, 5, 9, 9, 7,10,10, 8,10,11, 4, 9, 9, 9,12, + 12, 9,12,12, 8,12,12,11,12,12,10,12,13, 7,12,12, + 11,12,12,10,12,13, 4, 9, 9, 9,12,12, 9,12,12, 7, + 12,11,10,13,13,11,12,12, 7,12,12,10,13,13,11,12, + 12, +}; + +static const static_codebook _44u5__p7_0 = { + 4, 81, + (char *)_vq_lengthlist__44u5__p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44u5__p7_0, + 0 +}; + +static const long _vq_quantlist__44u5__p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u5__p7_1[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 7, 7, + 8, 8, 9, 8, 8, 9, 4, 5, 5, 7, 7, 8, 8, 9, 9, 8, + 9, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 6, 7, 7, 8, + 8, 9, 9, 9, 9, 9, 9, 7, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, + 9, 9, 9, 9,10,10,10,10, 8, 9, 9, 9, 9, 9, 9,10, + 10,10,10, 8, 9, 9, 9, 9, 9, 9,10,10,10,10, 8, 9, + 9, 9, 9, 9, 9,10,10,10,10, +}; + +static const static_codebook _44u5__p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44u5__p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u5__p7_1, + 0 +}; + +static const long _vq_quantlist__44u5__p8_0[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u5__p8_0[] = { + 1, 4, 4, 6, 6, 8, 8, 9, 9,10,10, 4, 6, 6, 7, 7, + 9, 9,10,10,11,11, 4, 6, 6, 7, 7, 9, 9,10,10,11, + 11, 6, 8, 7, 9, 9,10,10,11,11,13,12, 6, 8, 8, 9, + 9,10,10,11,11,12,13, 8, 9, 9,10,10,12,12,13,12, + 14,13, 8, 9, 9,10,10,12,12,13,13,14,14, 9,11,11, + 12,12,13,13,14,14,15,14, 9,11,11,12,12,13,13,14, + 14,15,14,11,12,12,13,13,14,14,15,14,15,14,11,11, + 12,13,13,14,14,14,14,15,15, +}; + +static const static_codebook _44u5__p8_0 = { + 2, 121, + (char *)_vq_lengthlist__44u5__p8_0, + 1, -524582912, 1618345984, 4, 0, + (long *)_vq_quantlist__44u5__p8_0, + 0 +}; + +static const long _vq_quantlist__44u5__p8_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u5__p8_1[] = { + 3, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 5, 7, 6, + 7, 7, 8, 8, 8, 8, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, + 8, 6, 7, 6, 7, 7, 8, 8, 8, 8, 8, 8, 6, 6, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44u5__p8_1 = { + 2, 121, + (char *)_vq_lengthlist__44u5__p8_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u5__p8_1, + 0 +}; + +static const long _vq_quantlist__44u5__p9_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u5__p9_0[] = { + 1, 3, 2,12,10,13,13,13,13,13,13,13,13, 4, 9, 9, + 13,13,13,13,13,13,13,13,13,13, 5,10, 9,13,13,13, + 13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,13, + 13,13,13,13,11,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,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,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, +}; + +static const static_codebook _44u5__p9_0 = { + 2, 169, + (char *)_vq_lengthlist__44u5__p9_0, + 1, -514332672, 1627381760, 4, 0, + (long *)_vq_quantlist__44u5__p9_0, + 0 +}; + +static const long _vq_quantlist__44u5__p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u5__p9_1[] = { + 1, 4, 4, 7, 7, 8, 8, 8, 7, 8, 7, 9, 8, 9, 9, 4, + 7, 6, 9, 8,10,10, 9, 8, 9, 9, 9, 9, 9, 8, 5, 6, + 6, 8, 9,10,10, 9, 9, 9,10,10,10,10,11, 7, 8, 8, + 10,10,11,11,10,10,11,11,11,12,11,11, 7, 8, 8,10, + 10,11,11,10,10,11,11,12,11,11,11, 8, 9, 9,11,11, + 12,12,11,11,12,11,12,12,12,12, 8, 9,10,11,11,12, + 12,11,11,12,12,12,12,12,12, 8, 9, 9,10,10,12,11, + 12,12,12,12,12,12,12,13, 8, 9, 9,11,11,11,11,12, + 12,12,12,13,12,13,13, 9,10,10,11,11,12,12,12,13, + 12,13,13,13,14,13, 9,10,10,11,11,12,12,12,13,13, + 12,13,13,14,13, 9,11,10,12,11,13,12,12,13,13,13, + 13,13,13,14, 9,10,10,12,12,12,12,12,13,13,13,13, + 13,14,14,10,11,11,12,12,12,13,13,13,14,14,13,14, + 14,14,10,11,11,12,12,12,12,13,12,13,14,13,14,14, + 14, +}; + +static const static_codebook _44u5__p9_1 = { + 2, 225, + (char *)_vq_lengthlist__44u5__p9_1, + 1, -522338304, 1620115456, 4, 0, + (long *)_vq_quantlist__44u5__p9_1, + 0 +}; + +static const long _vq_quantlist__44u5__p9_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44u5__p9_2[] = { + 2, 5, 5, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 5, 6, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 5, 6, 6, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 7, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 7, 7, 7, 8, 8, 9, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9,10, 9,10,10,10, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, + 9, 9,10, 9,10, 9,10, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 9,10, 9,10,10,10,10,10, 8, 9, 9, 9, 9, 9, 9,10, + 9,10, 9,10,10,10,10,10,10, 9, 9, 9, 9, 9,10, 9, + 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, + 9,10, 9,10, 9,10,10,10,10,10,10, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, + 9, 9,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, + 9,10,10, 9,10,10,10,10,10,10,10,10,10,10, 9, 9, + 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, 9, + 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 9, 9, 9,10, 9,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _44u5__p9_2 = { + 2, 289, + (char *)_vq_lengthlist__44u5__p9_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44u5__p9_2, + 0 +}; + +static const char _huff_lengthlist__44u5__short[] = { + 4,10,17,13,17,13,17,17,17,17, 3, 6, 8, 9,11, 9, + 15,12,16,17, 6, 5, 5, 7, 7, 8,10,11,17,17, 7, 8, + 7, 9, 9,10,13,13,17,17, 8, 6, 5, 7, 4, 7, 5, 8, + 14,17, 9, 9, 8, 9, 7, 9, 8,10,16,17,12,10, 7, 8, + 4, 7, 4, 7,16,17,12,11, 9,10, 6, 9, 5, 7,14,17, + 14,13,10,15, 4, 8, 3, 5,14,17,17,14,11,15, 6,10, + 6, 8,15,17, +}; + +static const static_codebook _huff_book__44u5__short = { + 2, 100, + (char *)_huff_lengthlist__44u5__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u6__long[] = { + 3, 9,14,13,14,13,16,12,13,14, 5, 4, 6, 6, 8, 9, + 11,10,12,15,10, 5, 5, 6, 6, 8,10,10,13,16,10, 6, + 6, 6, 6, 8, 9, 9,12,14,13, 7, 6, 6, 4, 6, 6, 7, + 11,14,10, 7, 7, 7, 6, 6, 6, 7,10,13,15,10, 9, 8, + 5, 6, 5, 6,10,14,10, 9, 8, 8, 6, 6, 5, 4, 6,11, + 11,11,12,11,10, 9, 9, 5, 5, 9,10,12,15,13,13,13, + 13, 8, 7, 7, +}; + +static const static_codebook _huff_book__44u6__long = { + 2, 100, + (char *)_huff_lengthlist__44u6__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u6__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u6__p1_0[] = { + 1, 4, 4, 4, 8, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7, + 9,10, 5, 8, 8, 7,10, 9, 8,10,10, 5, 8, 8, 8,10, + 10, 8,10,10, 8,10,10,10,12,13,10,13,13, 7,10,10, + 10,13,11,10,13,13, 5, 8, 8, 8,11,10, 8,10,10, 7, + 10,10,10,13,13,10,11,13, 8,10,11,10,13,13,10,13, + 12, +}; + +static const static_codebook _44u6__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u6__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u6__p1_0, + 0 +}; + +static const long _vq_quantlist__44u6__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u6__p2_0[] = { + 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 8, 8, 6, + 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 8, 5, 6, 6, 6, 8, + 8, 6, 8, 8, 6, 8, 8, 8, 9, 9, 8, 9, 9, 6, 7, 7, + 7, 9, 8, 8, 9, 9, 5, 6, 6, 6, 8, 7, 6, 8, 8, 6, + 8, 8, 8, 9, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 8, 9, + 9, +}; + +static const static_codebook _44u6__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u6__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u6__p2_0, + 0 +}; + +static const long _vq_quantlist__44u6__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u6__p3_0[] = { + 2, 5, 4, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8, + 9, 9,13,12, 8, 9,10,12,13, 5, 7, 7,10, 9, 7, 9, + 9,11,11, 7, 8, 9,11,11,10,11,11,14,14, 9,10,11, + 13,14, 5, 7, 7, 9,10, 6, 9, 8,11,11, 7, 9, 9,11, + 11, 9,11,10,14,13,10,11,11,14,13, 8,10,10,13,13, + 10,11,11,15,15, 9,11,11,14,14,13,14,14,17,16,12, + 13,14,16,16, 8,10,10,13,14, 9,11,11,14,15,10,11, + 12,14,15,12,14,13,16,15,13,14,14,15,17, 5, 7, 7, + 10,10, 7, 9, 9,11,11, 7, 9, 9,11,11,10,12,11,14, + 14,10,11,11,14,14, 7, 9, 9,12,11, 9,11,11,13,13, + 9,11,11,13,13,11,13,13,14,15,11,12,13,15,16, 6, + 9, 9,11,12, 8,11,10,13,12, 9,11,11,13,14,11,13, + 12,16,14,11,13,13,15,16,10,12,11,14,15,11,13,13, + 15,17,11,13,13,17,16,15,15,16,17,16,14,15,16,18, + 0, 9,11,11,14,15,10,12,12,16,15,11,13,13,16,16, + 13,15,14,18,15,14,16,16, 0, 0, 5, 7, 7,10,10, 7, + 9, 9,11,11, 7, 9, 9,11,11,10,11,11,14,14,10,11, + 12,14,14, 6, 9, 9,11,11, 9,11,11,13,13, 8,10,11, + 12,13,11,13,13,16,15,11,12,13,14,16, 7, 9, 9,11, + 12, 9,11,11,13,13, 9,11,11,13,13,11,13,13,16,15, + 11,13,12,15,15, 9,11,11,15,14,11,13,13,17,16,10, + 12,13,15,16,14,16,16, 0,18,14,14,15,15,17,10,11, + 12,15,15,11,13,13,16,16,11,13,13,16,16,14,16,16, + 19,17,14,15,15,17,17, 8,10,10,14,14,10,12,11,15, + 15,10,11,12,16,15,14,15,15,18,20,13,14,16,17,18, + 9,11,11,15,16,11,13,13,17,17,11,13,13,17,16,15, + 16,16, 0, 0,15,16,16, 0, 0, 9,11,11,15,15,10,13, + 12,17,15,11,13,13,17,16,15,17,15,20,19,15,16,16, + 19, 0,13,15,14, 0,17,14,15,16, 0,20,15,16,16, 0, + 19,17,18, 0, 0, 0,16,17,18, 0, 0,12,14,14,19,18, + 13,15,14, 0,17,14,15,16,19,19,16,18,16, 0,19,19, + 20,17,20, 0, 8,10,10,13,14,10,11,11,15,15,10,12, + 12,15,16,14,15,14,19,16,14,15,15, 0,18, 9,11,11, + 16,15,11,13,13, 0,16,11,12,13,16,17,14,16,17, 0, + 19,15,16,16,18, 0, 9,11,11,15,16,11,13,13,16,16, + 11,14,13,18,17,15,16,16,18,20,15,17,19, 0, 0,12, + 14,14,17,17,14,16,15, 0, 0,13,14,15,19, 0,16,18, + 20, 0, 0,16,16,18,18, 0,12,14,14,17,20,14,16,16, + 19, 0,14,16,14, 0,20,16,20,17, 0, 0,17, 0,15, 0, + 19, +}; + +static const static_codebook _44u6__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u6__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u6__p3_0, + 0 +}; + +static const long _vq_quantlist__44u6__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u6__p4_0[] = { + 4, 5, 5, 8, 8, 6, 7, 6, 9, 9, 6, 6, 7, 9, 9, 8, + 9, 9,11,11, 8, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 8, + 8,10,10, 7, 7, 8, 9,10, 9,10,10,11,11, 9, 9,10, + 11,12, 6, 7, 7, 9, 9, 7, 8, 7,10, 9, 7, 8, 8,10, + 10, 9,10, 9,12,11, 9,10,10,12,11, 8, 9, 9,11,11, + 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,13,11, + 11,12,13,13, 8, 9, 9,11,11, 9,10,10,12,12, 9,10, + 10,12,12,11,12,11,13,12,11,12,12,13,13, 5, 7, 7, + 9, 9, 7, 8, 7,10,10, 7, 7, 8,10,10, 9,10,10,12, + 11, 9,10,10,11,12, 7, 8, 8,10,10, 8, 8, 9,11,11, + 8, 9, 9,11,11,10,10,11,12,13,10,10,11,12,12, 6, + 7, 7,10,10, 7, 9, 8,11,10, 8, 8, 9,10,11,10,11, + 10,13,11,10,11,11,12,12, 9,10,10,12,12,10,10,11, + 13,13,10,11,11,12,13,12,12,12,13,14,12,12,13,14, + 14, 9,10,10,12,12, 9,10,10,13,12,10,11,11,13,13, + 11,12,11,14,12,12,13,13,14,14, 6, 7, 7, 9, 9, 7, + 8, 7,10,10, 7, 8, 8,10,10, 9,10,10,12,11, 9,10, + 10,11,12, 6, 7, 7,10,10, 8, 9, 8,11,10, 7, 8, 9, + 10,11,10,11,11,12,12,10,10,11,11,13, 7, 8, 8,10, + 10, 8, 9, 9,11,11, 8, 9, 8,11,11,10,11,10,13,12, + 10,11,11,13,12, 9,10,10,12,12,10,11,11,13,12, 9, + 10,10,12,13,12,13,12,14,14,11,11,12,12,14, 9,10, + 10,12,12,10,11,11,13,13,10,11,10,13,12,12,12,12, + 14,14,12,13,12,14,13, 8, 9, 9,11,11, 9,10,10,12, + 12, 9,10,10,12,12,11,12,12,14,13,11,12,12,13,14, + 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12, + 12,13,14,15,12,12,13,14,14, 9,10,10,12,12, 9,11, + 10,13,12,10,10,11,12,13,12,13,12,14,13,12,12,13, + 14,15,11,12,12,14,13,11,12,12,14,14,12,13,13,14, + 14,13,13,14,14,16,13,14,14,15,15,11,12,11,13,13, + 11,12,11,14,13,12,12,13,14,15,12,14,12,15,12,13, + 14,15,15,16, 8, 9, 9,11,11, 9,10,10,12,12, 9,10, + 10,12,12,11,12,12,14,13,11,12,12,13,13, 9,10,10, + 12,12,10,11,10,13,12, 9,10,11,12,13,12,13,12,14, + 14,12,12,13,13,14, 9,10,10,12,12,10,11,11,13,13, + 10,11,11,13,13,12,13,12,14,14,12,13,13,14,14,11, + 11,11,13,13,12,13,12,14,14,11,11,12,13,14,14,14, + 14,16,15,12,12,14,12,15,11,12,12,13,14,12,13,13, + 14,15,11,12,12,14,14,13,14,14,16,16,13,14,13,16, + 13, +}; + +static const static_codebook _44u6__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u6__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u6__p4_0, + 0 +}; + +static const long _vq_quantlist__44u6__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u6__p5_0[] = { + 2, 3, 3, 6, 6, 8, 8,10,10, 4, 5, 5, 8, 7, 8, 8, + 11,11, 3, 5, 5, 7, 8, 8, 8,11,11, 6, 8, 7, 9, 9, + 10, 9,12,11, 6, 7, 8, 9, 9, 9,10,11,12, 8, 8, 8, + 10, 9,12,11,13,13, 8, 8, 9, 9,10,11,12,13,13,10, + 11,11,12,12,13,13,14,14,10,10,11,11,12,13,13,14, + 14, +}; + +static const static_codebook _44u6__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u6__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u6__p5_0, + 0 +}; + +static const long _vq_quantlist__44u6__p6_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u6__p6_0[] = { + 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 7, 7, + 9, 9, 4, 4, 5, 6, 6, 7, 8, 9, 9, 5, 6, 6, 7, 7, + 8, 8,10,10, 5, 6, 6, 7, 7, 8, 8,10,10, 7, 8, 7, + 8, 8,10, 9,11,11, 7, 7, 8, 8, 8, 9,10,10,11, 9, + 9, 9,10,10,11,11,12,11, 9, 9, 9,10,10,11,11,11, + 12, +}; + +static const static_codebook _44u6__p6_0 = { + 2, 81, + (char *)_vq_lengthlist__44u6__p6_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u6__p6_0, + 0 +}; + +static const long _vq_quantlist__44u6__p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u6__p7_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 8, 7,10,10, 8, + 10,10, 5, 8, 9, 7,10,10, 7,10, 9, 4, 8, 8, 9,11, + 11, 8,11,11, 7,11,11,10,10,13,10,13,13, 7,11,11, + 10,13,12,10,13,13, 5, 9, 8, 8,11,11, 9,11,11, 7, + 11,11,10,13,13,10,12,13, 7,11,11,10,13,13, 9,13, + 10, +}; + +static const static_codebook _44u6__p7_0 = { + 4, 81, + (char *)_vq_lengthlist__44u6__p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44u6__p7_0, + 0 +}; + +static const long _vq_quantlist__44u6__p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u6__p7_1[] = { + 3, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 7, 6, + 8, 8, 8, 8, 8, 8, 4, 5, 5, 6, 7, 8, 8, 8, 8, 8, + 8, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, +}; + +static const static_codebook _44u6__p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44u6__p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u6__p7_1, + 0 +}; + +static const long _vq_quantlist__44u6__p8_0[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u6__p8_0[] = { + 1, 4, 4, 6, 6, 8, 8, 9, 9,10,10, 4, 6, 6, 7, 7, + 9, 9,10,10,11,11, 4, 6, 6, 7, 7, 9, 9,10,10,11, + 11, 6, 8, 8, 9, 9,10,10,11,11,12,12, 6, 8, 8, 9, + 9,10,10,11,11,12,12, 8, 9, 9,10,10,11,11,12,12, + 13,13, 8, 9, 9,10,10,11,11,12,12,13,13,10,10,10, + 11,11,13,13,13,13,15,14, 9,10,10,12,11,12,13,13, + 13,14,15,11,12,12,13,13,13,13,15,14,15,15,11,11, + 12,13,13,14,14,14,15,15,15, +}; + +static const static_codebook _44u6__p8_0 = { + 2, 121, + (char *)_vq_lengthlist__44u6__p8_0, + 1, -524582912, 1618345984, 4, 0, + (long *)_vq_quantlist__44u6__p8_0, + 0 +}; + +static const long _vq_quantlist__44u6__p8_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u6__p8_1[] = { + 3, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 5, 7, 7, + 7, 7, 8, 7, 8, 8, 5, 5, 6, 6, 7, 7, 7, 7, 7, 8, + 8, 6, 7, 7, 7, 7, 8, 7, 8, 8, 8, 8, 6, 6, 7, 7, + 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44u6__p8_1 = { + 2, 121, + (char *)_vq_lengthlist__44u6__p8_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u6__p8_1, + 0 +}; + +static const long _vq_quantlist__44u6__p9_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u6__p9_0[] = { + 1, 3, 2, 9, 8,15,15,15,15,15,15,15,15,15,15, 4, + 8, 9,13,14,14,14,14,14,14,14,14,14,14,14, 5, 8, + 9,14,14,14,14,14,14,14,14,14,14,14,14,11,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,11,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,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,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, +}; + +static const static_codebook _44u6__p9_0 = { + 2, 225, + (char *)_vq_lengthlist__44u6__p9_0, + 1, -514071552, 1627381760, 4, 0, + (long *)_vq_quantlist__44u6__p9_0, + 0 +}; + +static const long _vq_quantlist__44u6__p9_1[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u6__p9_1[] = { + 1, 4, 4, 7, 7, 8, 9, 8, 8, 9, 8, 9, 8, 9, 9, 4, + 7, 6, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 4, 7, + 6, 9, 9,10,10, 9, 9,10,10,10,10,11,11, 7, 9, 8, + 10,10,11,11,10,10,11,11,11,11,11,11, 7, 8, 9,10, + 10,11,11,10,10,11,11,11,11,11,12, 8,10,10,11,11, + 12,12,11,11,12,12,12,12,13,12, 8,10,10,11,11,12, + 11,11,11,11,12,12,12,12,13, 8, 9, 9,11,10,11,11, + 12,12,12,12,13,12,13,12, 8, 9, 9,11,11,11,11,12, + 12,12,12,12,13,13,13, 9,10,10,11,12,12,12,12,12, + 13,13,13,13,13,13, 9,10,10,11,11,12,12,12,12,13, + 13,13,13,14,13,10,10,10,12,11,12,12,13,13,13,13, + 13,13,13,13,10,10,11,11,11,12,12,13,13,13,13,13, + 13,13,13,10,11,11,12,12,13,12,12,13,13,13,13,13, + 13,14,10,11,11,12,12,13,12,13,13,13,14,13,13,14, + 13, +}; + +static const static_codebook _44u6__p9_1 = { + 2, 225, + (char *)_vq_lengthlist__44u6__p9_1, + 1, -522338304, 1620115456, 4, 0, + (long *)_vq_quantlist__44u6__p9_1, + 0 +}; + +static const long _vq_quantlist__44u6__p9_2[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44u6__p9_2[] = { + 3, 5, 5, 7, 7, 8, 8, 8, 8, 8, 8, 9, 8, 8, 9, 9, + 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 5, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 8, 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,10,10, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9,10, 9, 9, 9,10, 9, 9,10, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, 9,10, 9,10,10, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,10,10, 9, 9, + 10, +}; + +static const static_codebook _44u6__p9_2 = { + 2, 289, + (char *)_vq_lengthlist__44u6__p9_2, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44u6__p9_2, + 0 +}; + +static const char _huff_lengthlist__44u6__short[] = { + 4,11,16,13,17,13,17,16,17,17, 4, 7, 9, 9,13,10, + 16,12,16,17, 7, 6, 5, 7, 8, 9,12,12,16,17, 6, 9, + 7, 9,10,10,15,15,17,17, 6, 7, 5, 7, 5, 7, 7,10, + 16,17, 7, 9, 8, 9, 8,10,11,11,15,17, 7, 7, 7, 8, + 5, 8, 8, 9,15,17, 8, 7, 9, 9, 7, 8, 7, 2, 7,15, + 14,13,13,15, 5,10, 4, 3, 6,17,17,15,13,17, 7,11, + 7, 6, 9,16, +}; + +static const static_codebook _huff_book__44u6__short = { + 2, 100, + (char *)_huff_lengthlist__44u6__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u7__long[] = { + 3, 9,14,13,15,14,16,13,13,14, 5, 5, 7, 7, 8, 9, + 11,10,12,15,10, 6, 5, 6, 6, 9,10,10,13,16,10, 6, + 6, 6, 6, 8, 9, 9,12,15,14, 7, 6, 6, 5, 6, 6, 8, + 12,15,10, 8, 7, 7, 6, 7, 7, 7,11,13,14,10, 9, 8, + 5, 6, 4, 5, 9,12,10, 9, 9, 8, 6, 6, 5, 3, 6,11, + 12,11,12,12,10, 9, 8, 5, 5, 8,10,11,15,13,13,13, + 12, 8, 6, 7, +}; + +static const static_codebook _huff_book__44u7__long = { + 2, 100, + (char *)_huff_lengthlist__44u7__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u7__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u7__p1_0[] = { + 1, 4, 4, 4, 7, 7, 5, 7, 7, 5, 8, 8, 8,10,10, 7, + 10,10, 5, 8, 8, 7,10,10, 8,10,10, 5, 8, 8, 8,11, + 10, 8,10,10, 8,10,10,10,12,13,10,13,13, 7,10,10, + 10,13,12,10,13,13, 5, 8, 8, 8,11,10, 8,10,11, 7, + 10,10,10,13,13,10,12,13, 8,11,11,10,13,13,10,13, + 12, +}; + +static const static_codebook _44u7__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u7__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u7__p1_0, + 0 +}; + +static const long _vq_quantlist__44u7__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u7__p2_0[] = { + 3, 4, 4, 5, 6, 6, 5, 6, 6, 5, 6, 6, 6, 8, 8, 6, + 7, 8, 5, 6, 6, 6, 8, 7, 6, 8, 8, 5, 6, 6, 6, 8, + 7, 6, 8, 8, 6, 8, 8, 8, 9, 9, 8, 9, 9, 6, 8, 7, + 7, 9, 8, 8, 9, 9, 5, 6, 6, 6, 8, 7, 6, 8, 8, 6, + 8, 8, 8, 9, 9, 7, 8, 9, 6, 8, 8, 8, 9, 9, 8, 9, + 9, +}; + +static const static_codebook _44u7__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44u7__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u7__p2_0, + 0 +}; + +static const long _vq_quantlist__44u7__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u7__p3_0[] = { + 2, 5, 4, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8, + 9, 9,13,12, 8, 9,10,12,13, 5, 7, 7,10, 9, 7, 9, + 9,11,11, 6, 8, 9,11,11,10,11,11,14,14, 9,10,11, + 13,14, 5, 7, 7, 9, 9, 7, 9, 8,11,11, 7, 9, 9,11, + 11, 9,11,10,14,13,10,11,11,14,14, 8,10,10,14,13, + 10,11,12,15,14, 9,11,11,15,14,13,14,14,16,16,12, + 13,14,17,16, 8,10,10,13,13, 9,11,11,14,15,10,11, + 12,14,15,12,14,13,16,16,13,14,15,15,17, 5, 7, 7, + 10,10, 7, 9, 9,11,11, 7, 9, 9,11,11,10,12,11,15, + 14,10,11,12,14,14, 7, 9, 9,12,12, 9,11,11,13,13, + 9,11,11,13,13,11,13,13,14,17,11,13,13,15,16, 6, + 9, 9,11,11, 8,11,10,13,12, 9,11,11,13,13,11,13, + 12,16,14,11,13,13,16,16,10,12,12,15,15,11,13,13, + 16,16,11,13,13,16,15,14,16,17,17,19,14,16,16,18, + 0, 9,11,11,14,15,10,13,12,16,15,11,13,13,16,16, + 14,15,14, 0,16,14,16,16,18, 0, 5, 7, 7,10,10, 7, + 9, 9,12,11, 7, 9, 9,11,12,10,11,11,15,14,10,11, + 12,14,14, 6, 9, 9,11,11, 9,11,11,13,13, 8,10,11, + 12,13,11,13,13,17,15,11,12,13,14,15, 7, 9, 9,11, + 12, 9,11,11,13,13, 9,11,11,13,13,11,13,12,16,16, + 11,13,13,15,14, 9,11,11,14,15,11,13,13,16,15,10, + 12,13,16,16,15,16,16, 0, 0,14,13,15,16,18,10,11, + 11,15,15,11,13,14,16,18,11,13,13,16,15,15,16,16, + 19, 0,14,15,15,16,16, 8,10,10,13,13,10,12,11,16, + 15,10,11,11,16,15,13,15,16,18, 0,13,14,15,17,17, + 9,11,11,15,15,11,13,13,16,18,11,13,13,16,17,15, + 16,16, 0, 0,15,18,16, 0,17, 9,11,11,15,15,11,13, + 12,17,15,11,13,14,16,17,15,18,15, 0,17,15,16,16, + 18,19,13,15,14, 0,18,14,16,16,19,18,14,16,15,19, + 19,16,18,19, 0, 0,16,17, 0, 0, 0,12,14,14,17,17, + 13,16,14, 0,18,14,16,15,18, 0,16,18,16,19,17,18, + 19,17, 0, 0, 8,10,10,14,14, 9,12,11,15,15,10,11, + 12,15,17,13,15,15,18,16,14,16,15,18,17, 9,11,11, + 16,15,11,13,13, 0,16,11,12,13,16,15,15,16,16, 0, + 17,15,15,16,18,17, 9,12,11,15,17,11,13,13,16,16, + 11,14,13,16,16,15,15,16,18,19,16,18,16, 0, 0,12, + 14,14, 0,16,14,16,16, 0,18,13,14,15,16, 0,17,16, + 18, 0, 0,16,16,17,19, 0,13,14,14,17, 0,14,17,16, + 0,19,14,15,15,18,19,17,16,18, 0, 0,15,19,16, 0, + 0, +}; + +static const static_codebook _44u7__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44u7__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u7__p3_0, + 0 +}; + +static const long _vq_quantlist__44u7__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u7__p4_0[] = { + 4, 5, 5, 8, 8, 6, 7, 6, 9, 9, 6, 6, 7, 9, 9, 8, + 9, 9,11,11, 8, 9, 9,10,11, 6, 7, 7, 9, 9, 7, 8, + 8,10,10, 6, 7, 8, 9,10, 9,10,10,12,12, 9, 9,10, + 11,12, 6, 7, 7, 9, 9, 6, 8, 7,10, 9, 7, 8, 8,10, + 10, 9,10, 9,12,11, 9,10,10,12,11, 8, 9, 9,11,11, + 9,10,10,12,12, 9,10,10,12,12,11,12,12,13,14,11, + 11,12,13,13, 8, 9, 9,11,11, 9,10,10,12,11, 9,10, + 10,12,12,11,12,11,13,13,11,12,12,13,13, 6, 7, 7, + 9, 9, 7, 8, 7,10,10, 7, 7, 8,10,10, 9,10,10,12, + 11, 9,10,10,12,12, 7, 8, 8,10,10, 8, 8, 9,11,11, + 8, 9, 9,11,11,10,11,11,12,12,10,10,11,12,13, 6, + 7, 7,10,10, 7, 9, 8,11,10, 8, 8, 9,10,11,10,11, + 10,13,11,10,11,11,12,12, 9,10,10,12,12,10,10,11, + 13,13,10,11,11,13,12,12,12,13,13,14,12,12,13,14, + 14, 9,10,10,12,12, 9,10,10,12,12,10,11,11,13,13, + 11,12,11,14,12,12,13,13,14,14, 6, 7, 7, 9, 9, 7, + 8, 7,10,10, 7, 7, 8,10,10, 9,10,10,12,11, 9,10, + 10,11,12, 6, 7, 7,10,10, 8, 9, 8,11,10, 7, 8, 9, + 10,11,10,11,11,13,12,10,10,11,11,13, 7, 8, 8,10, + 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,10,13,12, + 10,11,11,12,12, 9,10,10,12,12,10,11,11,13,12, 9, + 10,10,12,13,12,13,12,14,14,11,11,12,12,14, 9,10, + 10,12,12,10,11,11,13,13,10,11,11,13,13,12,13,12, + 14,14,12,13,12,14,13, 8, 9, 9,11,11, 9,10,10,12, + 12, 9,10,10,12,12,11,12,12,14,13,11,12,12,13,13, + 9,10,10,12,12,10,11,11,13,13,10,11,11,13,12,12, + 13,13,14,14,12,12,13,14,14, 9,10,10,12,12, 9,11, + 10,13,12,10,10,11,12,13,11,13,12,14,13,12,12,13, + 14,14,11,12,12,13,13,11,12,13,14,14,12,13,13,14, + 14,13,13,14,14,16,13,14,14,16,16,11,11,11,13,13, + 11,12,11,14,13,12,12,13,14,15,13,14,12,16,13,14, + 14,14,15,16, 8, 9, 9,11,11, 9,10,10,12,12, 9,10, + 10,12,12,11,12,12,14,13,11,12,12,13,14, 9,10,10, + 12,12,10,11,10,13,12, 9,10,11,12,13,12,13,12,14, + 14,12,12,13,13,14, 9,10,10,12,12,10,11,11,12,13, + 10,11,11,13,13,12,13,12,14,14,12,13,13,14,14,11, + 12,12,13,13,12,13,12,14,14,11,11,12,13,14,13,15, + 14,16,15,13,12,14,13,16,11,12,12,13,13,12,13,13, + 14,14,12,12,12,14,14,13,14,14,15,15,13,14,13,16, + 14, +}; + +static const static_codebook _44u7__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44u7__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u7__p4_0, + 0 +}; + +static const long _vq_quantlist__44u7__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u7__p5_0[] = { + 2, 3, 3, 6, 6, 7, 8,10,10, 4, 5, 5, 8, 7, 8, 8, + 11,11, 3, 5, 5, 7, 7, 8, 9,11,11, 6, 8, 7, 9, 9, + 10,10,12,12, 6, 7, 8, 9,10,10,10,12,12, 8, 8, 8, + 10,10,12,11,13,13, 8, 8, 9,10,10,11,11,13,13,10, + 11,11,12,12,13,13,14,14,10,11,11,12,12,13,13,14, + 14, +}; + +static const static_codebook _44u7__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44u7__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u7__p5_0, + 0 +}; + +static const long _vq_quantlist__44u7__p6_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u7__p6_0[] = { + 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 8, 7, + 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7, + 8, 8,10,10, 5, 6, 6, 7, 7, 8, 8,10,10, 7, 8, 7, + 8, 8,10, 9,11,11, 7, 7, 8, 8, 8, 9,10,11,11, 9, + 9, 9,10,10,11,10,12,11, 9, 9, 9,10,10,11,11,11, + 12, +}; + +static const static_codebook _44u7__p6_0 = { + 2, 81, + (char *)_vq_lengthlist__44u7__p6_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u7__p6_0, + 0 +}; + +static const long _vq_quantlist__44u7__p7_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u7__p7_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 9, 8, 8, 9, 9, 7, + 10,10, 5, 8, 9, 7, 9,10, 8, 9, 9, 4, 9, 9, 9,11, + 10, 8,10,10, 7,11,10,10,10,12,10,12,12, 7,10,10, + 10,12,11,10,12,12, 5, 9, 9, 8,10,10, 9,11,11, 7, + 11,10,10,12,12,10,11,12, 7,10,11,10,12,12,10,12, + 10, +}; + +static const static_codebook _44u7__p7_0 = { + 4, 81, + (char *)_vq_lengthlist__44u7__p7_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44u7__p7_0, + 0 +}; + +static const long _vq_quantlist__44u7__p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u7__p7_1[] = { + 3, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8, 4, 5, 5, 6, 6, + 8, 7, 8, 8, 8, 8, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, + 8, 6, 7, 6, 7, 7, 8, 8, 9, 9, 9, 9, 6, 6, 7, 7, + 7, 8, 8, 9, 9, 9, 9, 7, 8, 7, 8, 8, 9, 9, 9, 9, + 9, 9, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 9, 9, 9, 9,10, 9, 9, 9, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9,10, 8, 8, 8, 9, 9, 9, 9,10, 9,10,10, 8, 8, + 8, 9, 9, 9, 9, 9,10,10,10, +}; + +static const static_codebook _44u7__p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44u7__p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u7__p7_1, + 0 +}; + +static const long _vq_quantlist__44u7__p8_0[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u7__p8_0[] = { + 1, 4, 4, 6, 6, 8, 8,10,10,11,11, 4, 6, 6, 7, 7, + 9, 9,11,10,12,12, 5, 6, 5, 7, 7, 9, 9,10,11,12, + 12, 6, 7, 7, 8, 8,10,10,11,11,13,13, 6, 7, 7, 8, + 8,10,10,11,12,13,13, 8, 9, 9,10,10,11,11,12,12, + 14,14, 8, 9, 9,10,10,11,11,12,12,14,14,10,10,10, + 11,11,13,12,14,14,15,15,10,10,10,12,12,13,13,14, + 14,15,15,11,12,12,13,13,14,14,15,14,16,15,11,12, + 12,13,13,14,14,15,15,15,16, +}; + +static const static_codebook _44u7__p8_0 = { + 2, 121, + (char *)_vq_lengthlist__44u7__p8_0, + 1, -524582912, 1618345984, 4, 0, + (long *)_vq_quantlist__44u7__p8_0, + 0 +}; + +static const long _vq_quantlist__44u7__p8_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u7__p8_1[] = { + 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 7, 7, 7, 7, 7, 8, 7, 8, 8, + 8, 8, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44u7__p8_1 = { + 2, 121, + (char *)_vq_lengthlist__44u7__p8_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u7__p8_1, + 0 +}; + +static const long _vq_quantlist__44u7__p9_0[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u7__p9_0[] = { + 1, 3, 3,10,10,10,10,10,10,10,10, 4,10,10,10,10, + 10,10,10,10,10,10, 4,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, +}; + +static const static_codebook _44u7__p9_0 = { + 2, 121, + (char *)_vq_lengthlist__44u7__p9_0, + 1, -512171520, 1630791680, 4, 0, + (long *)_vq_quantlist__44u7__p9_0, + 0 +}; + +static const long _vq_quantlist__44u7__p9_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u7__p9_1[] = { + 1, 4, 4, 6, 5, 8, 6, 9, 8,10, 9,11,10, 4, 6, 6, + 8, 8, 9, 9,11,10,11,11,11,11, 4, 6, 6, 8, 8,10, + 9,11,11,11,11,11,12, 6, 8, 8,10,10,11,11,12,12, + 13,12,13,13, 6, 8, 8,10,10,11,11,12,12,12,13,14, + 13, 8,10,10,11,11,12,13,14,14,14,14,15,15, 8,10, + 10,11,12,12,13,13,14,14,14,14,15, 9,11,11,13,13, + 14,14,15,14,16,15,17,15, 9,11,11,12,13,14,14,15, + 14,15,15,15,16,10,12,12,13,14,15,15,15,15,16,17, + 16,17,10,13,12,13,14,14,16,16,16,16,15,16,17,11, + 13,13,14,15,14,17,15,16,17,17,17,17,11,13,13,14, + 15,15,15,15,17,17,16,17,16, +}; + +static const static_codebook _44u7__p9_1 = { + 2, 169, + (char *)_vq_lengthlist__44u7__p9_1, + 1, -518889472, 1622704128, 4, 0, + (long *)_vq_quantlist__44u7__p9_1, + 0 +}; + +static const long _vq_quantlist__44u7__p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__44u7__p9_2[] = { + 2, 4, 4, 4, 4, 5, 5, 5, 5, 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, 8, 8, 8, + 8, +}; + +static const static_codebook _44u7__p9_2 = { + 1, 49, + (char *)_vq_lengthlist__44u7__p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__44u7__p9_2, + 0 +}; + +static const char _huff_lengthlist__44u7__short[] = { + 5,12,17,16,16,17,17,17,17,17, 4, 7,11,11,12, 9, + 17,10,17,17, 7, 7, 8, 9, 7, 9,11,10,15,17, 7, 9, + 10,11,10,12,14,12,16,17, 7, 8, 5, 7, 4, 7, 7, 8, + 16,16, 6,10, 9,10, 7,10,11,11,16,17, 6, 8, 8, 9, + 5, 7, 5, 8,16,17, 5, 5, 8, 7, 6, 7, 7, 6, 6,14, + 12,10,12,11, 7,11, 4, 4, 2, 7,17,15,15,15, 8,15, + 6, 8, 5, 9, +}; + +static const static_codebook _huff_book__44u7__short = { + 2, 100, + (char *)_huff_lengthlist__44u7__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u8__long[] = { + 3, 9,13,14,14,15,14,14,15,15, 5, 4, 6, 8,10,12, + 12,14,15,15, 9, 5, 4, 5, 8,10,11,13,16,16,10, 7, + 4, 3, 5, 7, 9,11,13,13,10, 9, 7, 4, 4, 6, 8,10, + 12,14,13,11, 9, 6, 5, 5, 6, 8,12,14,13,11,10, 8, + 7, 6, 6, 7,10,14,13,11,12,10, 8, 7, 6, 6, 9,13, + 12,11,14,12,11, 9, 8, 7, 9,11,11,12,14,13,14,11, + 10, 8, 8, 9, +}; + +static const static_codebook _huff_book__44u8__long = { + 2, 100, + (char *)_huff_lengthlist__44u8__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u8__short[] = { + 6,14,18,18,17,17,17,17,17,17, 4, 7, 9, 9,10,13, + 15,17,17,17, 6, 7, 5, 6, 8,11,16,17,16,17, 5, 7, + 5, 4, 6,10,14,17,17,17, 6, 6, 6, 5, 7,10,13,16, + 17,17, 7, 6, 7, 7, 7, 8, 7,10,15,16,12, 9, 9, 6, + 6, 5, 3, 5,11,15,14,14,13, 5, 5, 7, 3, 4, 8,15, + 17,17,13, 7, 7,10, 6, 6,10,15,17,17,16,10,11,14, + 10,10,15,17, +}; + +static const static_codebook _huff_book__44u8__short = { + 2, 100, + (char *)_huff_lengthlist__44u8__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u8_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u8_p1_0[] = { + 1, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 8, 9, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 8, 9, 9, 5, 7, 7, 7, 9, + 9, 7, 9, 9, 7, 9, 9, 9,10,11, 9,11,10, 7, 9, 9, + 9,11,10, 9,10,11, 5, 7, 7, 7, 9, 9, 7, 9, 9, 7, + 9, 9, 9,11,10, 9,10,10, 8, 9, 9, 9,11,11, 9,11, + 10, +}; + +static const static_codebook _44u8_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u8_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u8_p1_0, + 0 +}; + +static const long _vq_quantlist__44u8_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u8_p2_0[] = { + 4, 5, 5, 8, 8, 5, 7, 6, 9, 9, 5, 6, 7, 9, 9, 8, + 9, 9,11,11, 8, 9, 9,11,11, 5, 7, 7, 9, 9, 7, 8, + 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12, 9,10,10, + 11,12, 5, 7, 7, 9, 9, 7, 8, 7,10,10, 7, 8, 8,10, + 10, 9,10, 9,12,11, 9,10,10,12,12, 8, 9, 9,12,11, + 9,10,10,12,12, 9,10,10,12,12,11,12,12,14,14,11, + 11,12,13,14, 8, 9, 9,11,11, 9,10,10,12,12, 9,10, + 10,12,12,11,12,11,13,13,11,12,12,14,14, 5, 7, 7, + 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12, + 12, 9,10,10,11,12, 7, 8, 8,10,10, 8, 9, 9,11,11, + 8, 9, 9,11,11,10,11,11,12,13,10,11,11,12,13, 6, + 8, 8,10,10, 8, 9, 8,11,10, 8, 9, 9,11,11,10,11, + 10,13,12,10,11,11,13,13, 9,10,10,12,12,10,11,11, + 13,13,10,11,11,13,13,12,12,13,13,14,12,13,13,14, + 14, 9,10,10,12,12,10,11,10,13,12,10,11,11,13,13, + 11,13,12,14,13,12,13,13,14,14, 5, 7, 7, 9, 9, 7, + 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12,12, 9,10, + 10,12,12, 7, 8, 8,10,10, 8, 9, 9,11,11, 8, 8, 9, + 10,11,10,11,11,13,13,10,10,11,12,13, 7, 8, 8,10, + 10, 8, 9, 9,11,11, 8, 9, 9,11,11,10,11,11,13,13, + 10,11,11,13,12, 9,10,10,12,12,10,11,11,13,13,10, + 10,11,12,13,12,13,13,14,14,12,12,13,13,14, 9,10, + 10,12,12,10,11,11,13,13,10,11,11,13,13,12,13,13, + 15,14,12,13,13,14,13, 8, 9, 9,11,11, 9,10,10,12, + 12, 9,10,10,12,12,12,12,12,14,13,11,12,12,14,14, + 9,10,10,12,12,10,11,11,13,13,10,11,11,13,13,12, + 13,13,14,15,12,13,13,14,15, 9,10,10,12,12,10,11, + 10,13,12,10,11,11,13,13,12,13,12,15,14,12,13,13, + 14,15,11,12,12,14,14,12,13,13,14,14,12,13,13,15, + 14,14,14,14,14,16,14,14,15,16,16,11,12,12,14,14, + 11,12,12,14,14,12,13,13,14,15,13,14,13,16,14,14, + 14,14,16,16, 8, 9, 9,11,11, 9,10,10,12,12, 9,10, + 10,12,12,11,12,12,14,13,11,12,12,14,14, 9,10,10, + 12,12,10,11,11,13,13,10,10,11,12,13,12,13,13,15, + 14,12,12,13,13,14, 9,10,10,12,12,10,11,11,13,13, + 10,11,11,13,13,12,13,13,14,14,12,13,13,15,14,11, + 12,12,14,13,12,13,13,15,14,11,12,12,13,14,14,15, + 14,16,15,13,13,14,13,16,11,12,12,14,14,12,13,13, + 14,15,12,13,12,15,14,14,14,14,16,15,14,15,13,16, + 14, +}; + +static const static_codebook _44u8_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44u8_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u8_p2_0, + 0 +}; + +static const long _vq_quantlist__44u8_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u8_p3_0[] = { + 3, 4, 4, 5, 5, 7, 7, 9, 9, 4, 5, 4, 6, 6, 7, 7, + 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7, + 8, 8,10,10, 6, 6, 6, 7, 7, 8, 8,10,10, 7, 7, 7, + 8, 8, 9, 9,11,10, 7, 7, 7, 8, 8, 9, 9,10,11, 9, + 9, 9,10,10,11,10,12,11, 9, 9, 9, 9,10,11,11,11, + 12, +}; + +static const static_codebook _44u8_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44u8_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u8_p3_0, + 0 +}; + +static const long _vq_quantlist__44u8_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44u8_p4_0[] = { + 4, 4, 4, 6, 6, 7, 7, 8, 8, 8, 8,10,10,11,11,11, + 11, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11, + 12,12, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11, + 11,12,12, 6, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10,10, + 11,11,12,12, 6, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9,10, + 10,11,11,12,12, 7, 7, 7, 8, 8, 9, 8,10, 9,10, 9, + 11,10,12,11,13,12, 7, 7, 7, 8, 8, 8, 9, 9,10, 9, + 10,10,11,11,12,12,13, 8, 8, 8, 9, 9, 9, 9,10,10, + 11,10,11,11,12,12,13,13, 8, 8, 8, 9, 9, 9,10,10, + 10,10,11,11,11,12,12,12,13, 8, 9, 9, 9, 9,10, 9, + 11,10,11,11,12,11,13,12,13,13, 8, 9, 9, 9, 9, 9, + 10,10,11,11,11,11,12,12,13,13,13,10,10,10,10,10, + 11,10,11,11,12,11,13,12,13,13,14,13,10,10,10,10, + 10,10,11,11,11,11,12,12,13,13,13,13,14,11,11,11, + 11,11,12,11,12,12,13,12,13,13,14,13,14,14,11,11, + 11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,11, + 12,12,12,12,13,12,13,12,13,13,14,13,14,14,14,14, + 11,12,12,12,12,12,12,13,13,13,13,13,14,14,14,14, + 14, +}; + +static const static_codebook _44u8_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__44u8_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44u8_p4_0, + 0 +}; + +static const long _vq_quantlist__44u8_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u8_p5_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 8, 9, 9, 7, + 9, 9, 5, 8, 8, 7, 9, 9, 8, 9, 9, 5, 8, 8, 8,10, + 10, 8,10,10, 7,10,10, 9,10,12, 9,12,11, 7,10,10, + 9,11,10, 9,11,12, 5, 8, 8, 8,10,10, 8,10,10, 7, + 10,10, 9,11,11, 9,10,11, 7,10,10, 9,11,11,10,12, + 10, +}; + +static const static_codebook _44u8_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__44u8_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44u8_p5_0, + 0 +}; + +static const long _vq_quantlist__44u8_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u8_p5_1[] = { + 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 5, 5, 5, 6, 6, + 7, 7, 8, 8, 8, 8, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, + 8, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 6, 6, 6, 7, + 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 7, 8, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 9, +}; + +static const static_codebook _44u8_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__44u8_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u8_p5_1, + 0 +}; + +static const long _vq_quantlist__44u8_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u8_p6_0[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 4, 6, 5, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 4, 6, 6, 7, 7, 8, + 8, 8, 8, 9, 9,10,10, 6, 7, 7, 7, 8, 8, 8, 8, 9, + 9,10,10,10, 6, 7, 7, 8, 8, 8, 8, 9, 8,10, 9,11, + 10, 7, 8, 8, 8, 8, 8, 9, 9, 9,10,10,11,11, 7, 8, + 8, 8, 8, 9, 8, 9, 9,10,10,11,11, 8, 8, 8, 9, 9, + 9, 9, 9,10,10,10,11,11, 8, 8, 8, 9, 9, 9, 9,10, + 9,10,10,11,11, 9, 9, 9, 9,10,10,10,10,10,10,11, + 11,12, 9, 9, 9,10, 9,10,10,10,10,11,10,12,11,10, + 10,10,10,10,11,11,11,11,11,12,12,12,10,10,10,10, + 11,11,11,11,11,12,11,12,12, +}; + +static const static_codebook _44u8_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44u8_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44u8_p6_0, + 0 +}; + +static const long _vq_quantlist__44u8_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u8_p6_1[] = { + 3, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44u8_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44u8_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u8_p6_1, + 0 +}; + +static const long _vq_quantlist__44u8_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u8_p7_0[] = { + 1, 4, 5, 6, 6, 7, 7, 8, 8,10,10,11,11, 5, 6, 6, + 7, 7, 8, 8, 9, 9,11,10,12,11, 5, 6, 6, 7, 7, 8, + 8, 9, 9,10,11,11,12, 6, 7, 7, 8, 8, 9, 9,10,10, + 11,11,12,12, 6, 7, 7, 8, 8, 9, 9,10,10,11,12,13, + 12, 7, 8, 8, 9, 9,10,10,11,11,12,12,13,13, 8, 8, + 8, 9, 9,10,10,11,11,12,12,13,13, 9, 9, 9,10,10, + 11,11,12,12,13,13,14,14, 9, 9, 9,10,10,11,11,12, + 12,13,13,14,14,10,11,11,12,11,13,12,13,13,14,14, + 15,15,10,11,11,11,12,12,13,13,14,14,14,15,15,11, + 12,12,13,13,14,13,15,14,15,15,16,15,11,11,12,13, + 13,13,14,14,14,15,15,15,16, +}; + +static const static_codebook _44u8_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44u8_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__44u8_p7_0, + 0 +}; + +static const long _vq_quantlist__44u8_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u8_p7_1[] = { + 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 5, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, + 8, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44u8_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44u8_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u8_p7_1, + 0 +}; + +static const long _vq_quantlist__44u8_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u8_p8_0[] = { + 1, 4, 4, 7, 7, 8, 8, 8, 7, 9, 8,10, 9,11,10, 4, + 6, 6, 8, 8,10, 9, 9, 9,10,10,11,10,12,10, 4, 6, + 6, 8, 8,10,10, 9, 9,10,10,11,11,11,12, 7, 8, 8, + 10,10,11,11,11,10,12,11,12,12,13,11, 7, 8, 8,10, + 10,11,11,10,10,11,11,12,12,13,13, 8,10,10,11,11, + 12,11,12,11,13,12,13,12,14,13, 8,10, 9,11,11,12, + 12,12,12,12,12,13,13,14,13, 8, 9, 9,11,10,12,11, + 13,12,13,13,14,13,14,13, 8, 9, 9,10,11,12,12,12, + 12,13,13,14,15,14,14, 9,10,10,12,11,13,12,13,13, + 14,13,14,14,14,14, 9,10,10,12,12,12,12,13,13,14, + 14,14,15,14,14,10,11,11,13,12,13,12,14,14,14,14, + 14,14,15,15,10,11,11,12,12,13,13,14,14,14,15,15, + 14,16,15,11,12,12,13,12,14,14,14,13,15,14,15,15, + 15,17,11,12,12,13,13,14,14,14,15,15,14,15,15,14, + 17, +}; + +static const static_codebook _44u8_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__44u8_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__44u8_p8_0, + 0 +}; + +static const long _vq_quantlist__44u8_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44u8_p8_1[] = { + 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 6, 6, 7, 7, 8, + 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, + 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10, 9,10, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10, + 10, 9,10, 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9,10, 9, + 10,10,10,10,10,10,10,10, 8, 9, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10,10, 9,10,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,10,10, + 10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10, + 10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9,10, 9, + 10,10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10, + 10, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, + 9, 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10, 9, 9, 9,10, 9,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9,10, + 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, + 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10, 9, 9, 9,10, 9,10, 9,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44u8_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__44u8_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44u8_p8_1, + 0 +}; + +static const long _vq_quantlist__44u8_p9_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u8_p9_0[] = { + 1, 3, 3, 9, 9, 9, 9, 9, 9, 4, 9, 9, 9, 9, 9, 9, + 9, 9, 5, 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, 8, 8, 8, + 8, +}; + +static const static_codebook _44u8_p9_0 = { + 2, 81, + (char *)_vq_lengthlist__44u8_p9_0, + 1, -511895552, 1631393792, 4, 0, + (long *)_vq_quantlist__44u8_p9_0, + 0 +}; + +static const long _vq_quantlist__44u8_p9_1[] = { + 9, + 8, + 10, + 7, + 11, + 6, + 12, + 5, + 13, + 4, + 14, + 3, + 15, + 2, + 16, + 1, + 17, + 0, + 18, +}; + +static const char _vq_lengthlist__44u8_p9_1[] = { + 1, 4, 4, 7, 7, 8, 7, 8, 6, 9, 7,10, 8,11,10,11, + 11,11,11, 4, 7, 6, 9, 9,10, 9, 9, 9,10,10,11,10, + 11,10,11,11,13,11, 4, 7, 7, 9, 9, 9, 9, 9, 9,10, + 10,11,10,11,11,11,12,11,12, 7, 9, 8,11,11,11,11, + 10,10,11,11,12,12,12,12,12,12,14,13, 7, 8, 9,10, + 11,11,11,10,10,11,11,11,11,12,12,14,12,13,14, 8, + 9, 9,11,11,11,11,11,11,12,12,14,12,15,14,14,14, + 15,14, 8, 9, 9,11,11,11,11,12,11,12,12,13,13,13, + 13,13,13,14,14, 8, 9, 9,11,10,12,11,12,12,13,13, + 13,13,15,14,14,14,16,16, 8, 9, 9,10,11,11,12,12, + 12,13,13,13,14,14,14,15,16,15,15, 9,10,10,11,12, + 12,13,13,13,14,14,16,14,14,16,16,16,16,15, 9,10, + 10,11,11,12,13,13,14,15,14,16,14,15,16,16,16,16, + 15,10,11,11,12,13,13,14,15,15,15,15,15,16,15,16, + 15,16,15,15,10,11,11,13,13,14,13,13,15,14,15,15, + 16,15,15,15,16,15,16,10,12,12,14,14,14,14,14,16, + 16,15,15,15,16,16,16,16,16,16,11,12,12,14,14,14, + 14,15,15,16,15,16,15,16,15,16,16,16,16,12,12,13, + 14,14,15,16,16,16,16,16,16,15,16,16,16,16,16,16, + 12,13,13,14,14,14,14,15,16,15,16,16,16,16,16,16, + 16,16,16,12,13,14,14,14,16,15,16,15,16,16,16,16, + 16,16,16,16,16,16,12,14,13,14,15,15,15,16,15,16, + 16,15,16,16,16,16,16,16,16, +}; + +static const static_codebook _44u8_p9_1 = { + 2, 361, + (char *)_vq_lengthlist__44u8_p9_1, + 1, -518287360, 1622704128, 5, 0, + (long *)_vq_quantlist__44u8_p9_1, + 0 +}; + +static const long _vq_quantlist__44u8_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__44u8_p9_2[] = { + 2, 3, 4, 5, 5, 5, 5, 5, 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, +}; + +static const static_codebook _44u8_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__44u8_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__44u8_p9_2, + 0 +}; + +static const char _huff_lengthlist__44u9__long[] = { + 3, 9,13,13,14,15,14,14,15,15, 5, 5, 9,10,12,12, + 13,14,16,15,10, 6, 6, 6, 8,11,12,13,16,15,11, 7, + 5, 3, 5, 8,10,12,15,15,10,10, 7, 4, 3, 5, 8,10, + 12,12,12,12, 9, 7, 5, 4, 6, 8,10,13,13,12,11, 9, + 7, 5, 5, 6, 9,12,14,12,12,10, 8, 6, 6, 6, 7,11, + 13,12,14,13,10, 8, 7, 7, 7,10,11,11,12,13,12,11, + 10, 8, 8, 9, +}; + +static const static_codebook _huff_book__44u9__long = { + 2, 100, + (char *)_huff_lengthlist__44u9__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const char _huff_lengthlist__44u9__short[] = { + 9,16,18,18,17,17,17,17,17,17, 5, 8,11,12,11,12, + 17,17,16,16, 6, 6, 8, 8, 9,10,14,15,16,16, 6, 7, + 7, 4, 6, 9,13,16,16,16, 6, 6, 7, 4, 5, 8,11,15, + 17,16, 7, 6, 7, 6, 6, 8, 9,10,14,16,11, 8, 8, 7, + 6, 6, 3, 4,10,15,14,12,12,10, 5, 6, 3, 3, 8,13, + 15,17,15,11, 6, 8, 6, 6, 9,14,17,15,15,12, 8,10, + 9, 9,12,15, +}; + +static const static_codebook _huff_book__44u9__short = { + 2, 100, + (char *)_huff_lengthlist__44u9__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44u9_p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u9_p1_0[] = { + 1, 5, 5, 5, 7, 7, 5, 7, 7, 5, 7, 7, 7, 9, 9, 7, + 9, 9, 5, 7, 7, 7, 9, 9, 7, 9, 9, 5, 7, 7, 7, 9, + 9, 7, 9, 9, 8, 9, 9, 9,10,11, 9,11,11, 7, 9, 9, + 9,11,10, 9,11,11, 5, 7, 7, 7, 9, 9, 8, 9,10, 7, + 9, 9, 9,11,11, 9,10,11, 7, 9,10, 9,11,11, 9,11, + 10, +}; + +static const static_codebook _44u9_p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44u9_p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44u9_p1_0, + 0 +}; + +static const long _vq_quantlist__44u9_p2_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u9_p2_0[] = { + 3, 5, 5, 8, 8, 5, 7, 7, 9, 9, 6, 7, 7, 9, 9, 8, + 9, 9,11,10, 8, 9, 9,11,11, 6, 7, 7, 9, 9, 7, 8, + 8,10,10, 7, 8, 8, 9,10, 9,10,10,11,11, 9, 9,10, + 11,11, 6, 7, 7, 9, 9, 7, 8, 8,10, 9, 7, 8, 8,10, + 10, 9,10, 9,11,11, 9,10,10,11,11, 8, 9, 9,11,11, + 9,10,10,12,11, 9,10,10,11,12,11,11,11,13,13,11, + 11,11,12,13, 8, 9, 9,11,11, 9,10,10,11,11, 9,10, + 10,12,11,11,12,11,13,12,11,11,12,13,13, 6, 7, 7, + 9, 9, 7, 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,12, + 11, 9,10,10,11,12, 7, 8, 8,10,10, 8, 9, 9,11,11, + 8, 9, 9,10,10,10,11,11,12,12,10,10,11,12,12, 7, + 8, 8,10,10, 8, 9, 8,10,10, 8, 9, 9,10,10,10,11, + 10,12,11,10,10,11,12,12, 9,10,10,11,12,10,11,11, + 12,12,10,11,10,12,12,12,12,12,13,13,11,12,12,13, + 13, 9,10,10,11,11, 9,10,10,12,12,10,11,11,12,13, + 11,12,11,13,12,12,12,12,13,14, 6, 7, 7, 9, 9, 7, + 8, 8,10,10, 7, 8, 8,10,10, 9,10,10,11,11, 9,10, + 10,11,12, 7, 8, 8,10,10, 8, 9, 9,11,10, 8, 8, 9, + 10,10,10,11,10,12,12,10,10,11,11,12, 7, 8, 8,10, + 10, 8, 9, 9,10,10, 8, 9, 9,10,10,10,11,10,12,12, + 10,11,10,12,12, 9,10,10,12,11,10,11,11,12,12, 9, + 10,10,12,12,12,12,12,13,13,11,11,12,12,14, 9,10, + 10,11,12,10,11,11,12,12,10,11,11,12,12,11,12,12, + 14,14,12,12,12,13,13, 8, 9, 9,11,11, 9,10,10,12, + 11, 9,10,10,12,12,11,12,11,13,13,11,11,12,13,13, + 9,10,10,12,12,10,11,11,12,12,10,11,11,12,12,12, + 12,12,14,14,12,12,12,13,13, 9,10,10,12,11,10,11, + 10,12,12,10,11,11,12,12,11,12,12,14,13,12,12,12, + 13,14,11,12,11,13,13,11,12,12,13,13,12,12,12,14, + 14,13,13,13,13,15,13,13,14,15,15,11,11,11,13,13, + 11,12,11,13,13,11,12,12,13,13,12,13,12,15,13,13, + 13,14,14,15, 8, 9, 9,11,11, 9,10,10,11,12, 9,10, + 10,11,12,11,12,11,13,13,11,12,12,13,13, 9,10,10, + 11,12,10,11,10,12,12,10,10,11,12,13,12,12,12,14, + 13,11,12,12,13,14, 9,10,10,12,12,10,11,11,12,12, + 10,11,11,12,12,12,12,12,14,13,12,12,12,14,13,11, + 11,11,13,13,11,12,12,14,13,11,11,12,13,13,13,13, + 13,15,14,12,12,13,13,15,11,12,12,13,13,12,12,12, + 13,14,11,12,12,13,13,13,13,14,14,15,13,13,13,14, + 14, +}; + +static const static_codebook _44u9_p2_0 = { + 4, 625, + (char *)_vq_lengthlist__44u9_p2_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u9_p2_0, + 0 +}; + +static const long _vq_quantlist__44u9_p3_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44u9_p3_0[] = { + 3, 4, 4, 5, 5, 7, 7, 8, 8, 4, 5, 5, 6, 6, 7, 7, + 9, 9, 4, 4, 5, 6, 6, 7, 7, 9, 9, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 5, 6, 6, 7, 7, 8, 8, 9, 9, 7, 7, 7, + 8, 8, 9, 9,10,10, 7, 7, 7, 8, 8, 9, 9,10,10, 8, + 9, 9,10, 9,10,10,11,11, 8, 9, 9, 9,10,10,10,11, + 11, +}; + +static const static_codebook _44u9_p3_0 = { + 2, 81, + (char *)_vq_lengthlist__44u9_p3_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44u9_p3_0, + 0 +}; + +static const long _vq_quantlist__44u9_p4_0[] = { + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + 0, + 16, +}; + +static const char _vq_lengthlist__44u9_p4_0[] = { + 4, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,11, + 11, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10, + 11,11, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,10, + 10,11,11, 6, 6, 6, 7, 6, 7, 7, 8, 8, 9, 9,10,10, + 11,11,12,11, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9,10, + 10,11,11,11,12, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, + 10,10,11,11,12,12, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, + 9,10,10,11,11,12,12, 8, 8, 8, 8, 8, 9, 8,10, 9, + 10,10,11,10,12,11,13,12, 8, 8, 8, 8, 8, 9, 9, 9, + 10,10,10,10,11,11,12,12,12, 8, 8, 8, 9, 9, 9, 9, + 10,10,11,10,12,11,12,12,13,12, 8, 8, 8, 9, 9, 9, + 9,10,10,10,11,11,11,12,12,12,13, 9, 9, 9,10,10, + 10,10,11,10,11,11,12,11,13,12,13,13, 9, 9,10,10, + 10,10,10,10,11,11,11,11,12,12,13,13,13,10,11,10, + 11,11,11,11,12,11,12,12,13,12,13,13,14,13,10,10, + 10,11,11,11,11,11,12,12,12,12,13,13,13,13,14,11, + 11,11,12,11,12,12,12,12,13,13,13,13,14,13,14,14, + 11,11,11,11,12,12,12,12,12,12,13,13,13,13,14,14, + 14, +}; + +static const static_codebook _44u9_p4_0 = { + 2, 289, + (char *)_vq_lengthlist__44u9_p4_0, + 1, -529530880, 1611661312, 5, 0, + (long *)_vq_quantlist__44u9_p4_0, + 0 +}; + +static const long _vq_quantlist__44u9_p5_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44u9_p5_0[] = { + 1, 4, 4, 5, 7, 7, 5, 7, 7, 5, 8, 8, 8, 9, 9, 7, + 9, 9, 5, 8, 8, 7, 9, 9, 8, 9, 9, 5, 8, 8, 8,10, + 10, 8,10,10, 7,10,10, 9,10,12, 9,11,11, 7,10,10, + 9,11,10, 9,11,12, 5, 8, 8, 8,10,10, 8,10,10, 7, + 10,10, 9,12,11, 9,10,11, 7,10,10, 9,11,11,10,12, + 10, +}; + +static const static_codebook _44u9_p5_0 = { + 4, 81, + (char *)_vq_lengthlist__44u9_p5_0, + 1, -529137664, 1618345984, 2, 0, + (long *)_vq_quantlist__44u9_p5_0, + 0 +}; + +static const long _vq_quantlist__44u9_p5_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u9_p5_1[] = { + 5, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 5, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 7, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 6, 6, 6, 7, + 7, 7, 7, 7, 7, 8, 8, 7, 7, 7, 7, 7, 8, 7, 8, 8, + 8, 8, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 7, 7, 7, + 8, 7, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const static_codebook _44u9_p5_1 = { + 2, 121, + (char *)_vq_lengthlist__44u9_p5_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u9_p5_1, + 0 +}; + +static const long _vq_quantlist__44u9_p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u9_p6_0[] = { + 2, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 4, 6, 5, + 7, 7, 8, 8, 8, 8, 9, 9,10,10, 4, 5, 6, 7, 7, 8, + 8, 8, 8, 9, 9,10,10, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 10,10,10,10, 6, 7, 7, 8, 8, 8, 8, 9, 9,10,10,10, + 10, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,11,11, 7, 8, + 8, 8, 8, 9, 9, 9, 9,10,10,11,11, 8, 8, 8, 9, 9, + 9, 9, 9,10,10,10,11,11, 8, 8, 8, 9, 9, 9, 9,10, + 9,10,10,11,11, 9, 9, 9,10,10,10,10,10,11,11,11, + 11,12, 9, 9, 9,10,10,10,10,10,10,11,10,12,11,10, + 10,10,10,10,11,11,11,11,11,12,12,12,10,10,10,10, + 10,11,11,11,11,12,11,12,12, +}; + +static const static_codebook _44u9_p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44u9_p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44u9_p6_0, + 0 +}; + +static const long _vq_quantlist__44u9_p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44u9_p6_1[] = { + 4, 4, 4, 5, 5, 4, 5, 4, 5, 5, 4, 4, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, +}; + +static const static_codebook _44u9_p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44u9_p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44u9_p6_1, + 0 +}; + +static const long _vq_quantlist__44u9_p7_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44u9_p7_0[] = { + 1, 4, 5, 6, 6, 7, 7, 8, 9,10,10,11,11, 5, 6, 6, + 7, 7, 8, 8, 9, 9,10,10,11,11, 5, 6, 6, 7, 7, 8, + 8, 9, 9,10,10,11,11, 6, 7, 7, 8, 8, 9, 9,10,10, + 11,11,12,12, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12, + 12, 8, 8, 8, 9, 9,10,10,11,11,12,12,13,13, 8, 8, + 8, 9, 9,10,10,11,11,12,12,13,13, 9, 9, 9,10,10, + 11,11,12,12,13,13,13,13, 9, 9, 9,10,10,11,11,12, + 12,13,13,14,14,10,10,10,11,11,12,12,13,13,14,13, + 15,14,10,10,10,11,11,12,12,13,13,14,14,14,14,11, + 11,12,12,12,13,13,14,14,14,14,15,15,11,11,12,12, + 12,13,13,14,14,14,15,15,15, +}; + +static const static_codebook _44u9_p7_0 = { + 2, 169, + (char *)_vq_lengthlist__44u9_p7_0, + 1, -523206656, 1618345984, 4, 0, + (long *)_vq_quantlist__44u9_p7_0, + 0 +}; + +static const long _vq_quantlist__44u9_p7_1[] = { + 5, + 4, + 6, + 3, + 7, + 2, + 8, + 1, + 9, + 0, + 10, +}; + +static const char _vq_lengthlist__44u9_p7_1[] = { + 5, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 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, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 8, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 8, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, +}; + +static const static_codebook _44u9_p7_1 = { + 2, 121, + (char *)_vq_lengthlist__44u9_p7_1, + 1, -531365888, 1611661312, 4, 0, + (long *)_vq_quantlist__44u9_p7_1, + 0 +}; + +static const long _vq_quantlist__44u9_p8_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u9_p8_0[] = { + 1, 4, 4, 7, 7, 8, 8, 8, 8, 9, 9,10, 9,11,10, 4, + 6, 6, 8, 8, 9, 9, 9, 9,10,10,11,10,12,10, 4, 6, + 6, 8, 8, 9,10, 9, 9,10,10,11,11,12,12, 7, 8, 8, + 10,10,11,11,10,10,11,11,12,12,13,12, 7, 8, 8,10, + 10,11,11,10,10,11,11,12,12,12,13, 8,10, 9,11,11, + 12,12,11,11,12,12,13,13,14,13, 8, 9, 9,11,11,12, + 12,11,12,12,12,13,13,14,13, 8, 9, 9,10,10,12,11, + 13,12,13,13,14,13,15,14, 8, 9, 9,10,10,11,12,12, + 12,13,13,13,14,14,14, 9,10,10,12,11,13,12,13,13, + 14,13,14,14,14,15, 9,10,10,11,12,12,12,13,13,14, + 14,14,15,15,15,10,11,11,12,12,13,13,14,14,14,14, + 15,14,16,15,10,11,11,12,12,13,13,13,14,14,14,14, + 14,15,16,11,12,12,13,13,14,13,14,14,15,14,15,16, + 16,16,11,12,12,13,13,14,13,14,14,15,15,15,16,15, + 15, +}; + +static const static_codebook _44u9_p8_0 = { + 2, 225, + (char *)_vq_lengthlist__44u9_p8_0, + 1, -520986624, 1620377600, 4, 0, + (long *)_vq_quantlist__44u9_p8_0, + 0 +}; + +static const long _vq_quantlist__44u9_p8_1[] = { + 10, + 9, + 11, + 8, + 12, + 7, + 13, + 6, + 14, + 5, + 15, + 4, + 16, + 3, + 17, + 2, + 18, + 1, + 19, + 0, + 20, +}; + +static const char _vq_lengthlist__44u9_p8_1[] = { + 4, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, + 7, 7, 8, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9,10,10, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 10, 9,10, 9,10,10,10,10, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9,10,10, 9,10,10,10,10,10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,10,10, + 10,10, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10, + 10,10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,10,10, + 10, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10,10,10, + 10,10,10,10,10,10, 9, 9, 9, 9, 9, 9, 9, 9,10,10, + 10,10,10,10,10,10,10,10,10,10,10, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9, 9, 9, 9,10, 9, 9,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10, 9, 9, 9,10, 9,10, 9,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10, 9, 9, 9,10, 9,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 9, + 9, 9, 9, 9,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10, 9, 9, 9,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10, +}; + +static const static_codebook _44u9_p8_1 = { + 2, 441, + (char *)_vq_lengthlist__44u9_p8_1, + 1, -529268736, 1611661312, 5, 0, + (long *)_vq_quantlist__44u9_p8_1, + 0 +}; + +static const long _vq_quantlist__44u9_p9_0[] = { + 7, + 6, + 8, + 5, + 9, + 4, + 10, + 3, + 11, + 2, + 12, + 1, + 13, + 0, + 14, +}; + +static const char _vq_lengthlist__44u9_p9_0[] = { + 1, 3, 3,11,11,11,11,11,11,11,11,11,11,11,11, 4, + 10,11,11,11,11,11,11,11,11,11,11,11,11,11, 4,10, + 10,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,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,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,11,11,11,11,11,11,11,11,11, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _44u9_p9_0 = { + 2, 225, + (char *)_vq_lengthlist__44u9_p9_0, + 1, -510036736, 1631393792, 4, 0, + (long *)_vq_quantlist__44u9_p9_0, + 0 +}; + +static const long _vq_quantlist__44u9_p9_1[] = { + 9, + 8, + 10, + 7, + 11, + 6, + 12, + 5, + 13, + 4, + 14, + 3, + 15, + 2, + 16, + 1, + 17, + 0, + 18, +}; + +static const char _vq_lengthlist__44u9_p9_1[] = { + 1, 4, 4, 7, 7, 8, 7, 8, 7, 9, 8,10, 9,10,10,11, + 11,12,12, 4, 7, 6, 9, 9,10, 9, 9, 8,10,10,11,10, + 12,10,13,12,13,12, 4, 6, 6, 9, 9, 9, 9, 9, 9,10, + 10,11,11,11,12,12,12,12,12, 7, 9, 8,11,10,10,10, + 11,10,11,11,12,12,13,12,13,13,13,13, 7, 8, 9,10, + 10,11,11,10,10,11,11,11,12,13,13,13,13,14,14, 8, + 9, 9,11,11,12,11,12,12,13,12,12,13,13,14,15,14, + 14,14, 8, 9, 9,10,11,11,11,12,12,13,12,13,13,14, + 14,14,15,14,16, 8, 9, 9,11,10,12,12,12,12,15,13, + 13,13,17,14,15,15,15,14, 8, 9, 9,10,11,11,12,13, + 12,13,13,13,14,15,14,14,14,16,15, 9,11,10,12,12, + 13,13,13,13,14,14,16,15,14,14,14,15,15,17, 9,10, + 10,11,11,13,13,13,14,14,13,15,14,15,14,15,16,15, + 16,10,11,11,12,12,13,14,15,14,15,14,14,15,17,16, + 15,15,17,17,10,12,11,13,12,14,14,13,14,15,15,15, + 15,16,17,17,15,17,16,11,12,12,14,13,15,14,15,16, + 17,15,17,15,17,15,15,16,17,15,11,11,12,14,14,14, + 14,14,15,15,16,15,17,17,17,16,17,16,15,12,12,13, + 14,14,14,15,14,15,15,16,16,17,16,17,15,17,17,16, + 12,14,12,14,14,15,15,15,14,14,16,16,16,15,16,16, + 15,17,15,12,13,13,14,15,14,15,17,15,17,16,17,17, + 17,16,17,16,17,17,12,13,13,14,16,15,15,15,16,15, + 17,17,15,17,15,17,16,16,17, +}; + +static const static_codebook _44u9_p9_1 = { + 2, 361, + (char *)_vq_lengthlist__44u9_p9_1, + 1, -518287360, 1622704128, 5, 0, + (long *)_vq_quantlist__44u9_p9_1, + 0 +}; + +static const long _vq_quantlist__44u9_p9_2[] = { + 24, + 23, + 25, + 22, + 26, + 21, + 27, + 20, + 28, + 19, + 29, + 18, + 30, + 17, + 31, + 16, + 32, + 15, + 33, + 14, + 34, + 13, + 35, + 12, + 36, + 11, + 37, + 10, + 38, + 9, + 39, + 8, + 40, + 7, + 41, + 6, + 42, + 5, + 43, + 4, + 44, + 3, + 45, + 2, + 46, + 1, + 47, + 0, + 48, +}; + +static const char _vq_lengthlist__44u9_p9_2[] = { + 2, 4, 4, 5, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 6, 7, 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, +}; + +static const static_codebook _44u9_p9_2 = { + 1, 49, + (char *)_vq_lengthlist__44u9_p9_2, + 1, -526909440, 1611661312, 6, 0, + (long *)_vq_quantlist__44u9_p9_2, + 0 +}; + +static const char _huff_lengthlist__44un1__long[] = { + 5, 6,12, 9,14, 9, 9,19, 6, 1, 5, 5, 8, 7, 9,19, + 12, 4, 4, 7, 7, 9,11,18, 9, 5, 6, 6, 8, 7, 8,17, + 14, 8, 7, 8, 8,10,12,18, 9, 6, 8, 6, 8, 6, 8,18, + 9, 8,11, 8,11, 7, 5,15,16,18,18,18,17,15,11,18, +}; + +static const static_codebook _huff_book__44un1__long = { + 2, 64, + (char *)_huff_lengthlist__44un1__long, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + +static const long _vq_quantlist__44un1__p1_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44un1__p1_0[] = { + 1, 4, 4, 5, 8, 7, 5, 7, 8, 5, 8, 8, 8,10,11, 8, + 10,11, 5, 8, 8, 8,11,10, 8,11,10, 4, 9, 9, 8,11, + 11, 8,11,11, 8,12,11,10,12,14,11,13,13, 7,11,11, + 10,13,11,11,13,14, 4, 8, 9, 8,11,11, 8,11,12, 7, + 11,11,11,14,13,10,11,13, 8,11,12,11,13,13,10,14, + 12, +}; + +static const static_codebook _44un1__p1_0 = { + 4, 81, + (char *)_vq_lengthlist__44un1__p1_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44un1__p1_0, + 0 +}; + +static const long _vq_quantlist__44un1__p2_0[] = { + 1, + 0, + 2, +}; + +static const char _vq_lengthlist__44un1__p2_0[] = { + 2, 4, 4, 5, 6, 6, 5, 6, 6, 5, 7, 7, 7, 8, 8, 6, + 7, 9, 5, 7, 7, 6, 8, 7, 7, 9, 8, 4, 7, 7, 7, 9, + 8, 7, 8, 8, 7, 9, 8, 8, 8,10, 9,10,10, 6, 8, 8, + 7,10, 8, 9,10,10, 5, 7, 7, 7, 8, 8, 7, 8, 9, 6, + 8, 8, 9,10,10, 7, 8,10, 6, 8, 9, 9,10,10, 8,10, + 8, +}; + +static const static_codebook _44un1__p2_0 = { + 4, 81, + (char *)_vq_lengthlist__44un1__p2_0, + 1, -535822336, 1611661312, 2, 0, + (long *)_vq_quantlist__44un1__p2_0, + 0 +}; + +static const long _vq_quantlist__44un1__p3_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44un1__p3_0[] = { + 1, 5, 5, 8, 8, 5, 8, 7, 9, 9, 5, 7, 8, 9, 9, 9, + 10, 9,12,12, 9, 9,10,11,12, 6, 8, 8,10,10, 8,10, + 10,11,11, 8, 9,10,11,11,10,11,11,13,13,10,11,11, + 12,13, 6, 8, 8,10,10, 8,10, 9,11,11, 8,10,10,11, + 11,10,11,11,13,12,10,11,11,13,12, 9,11,11,15,13, + 10,12,11,15,13,10,11,11,15,14,12,14,13,16,15,12, + 13,13,17,16, 9,11,11,13,15,10,11,12,14,15,10,11, + 12,14,15,12,13,13,15,16,12,13,13,16,16, 5, 8, 8, + 11,11, 8,10,10,12,12, 8,10,10,12,12,11,12,12,14, + 14,11,12,12,14,14, 8,11,10,13,12,10,11,12,12,13, + 10,12,12,13,13,12,12,13,13,15,11,12,13,15,14, 7, + 10,10,12,12, 9,12,11,13,12,10,12,12,13,14,12,13, + 12,15,13,11,13,12,14,15,10,12,12,16,14,11,12,12, + 16,15,11,13,12,17,16,13,13,15,15,17,13,15,15,20, + 17,10,12,12,14,16,11,12,12,15,15,11,13,13,15,18, + 13,14,13,15,15,13,15,14,16,16, 5, 8, 8,11,11, 8, + 10,10,12,12, 8,10,10,12,12,11,12,12,14,14,11,12, + 12,14,15, 7,10,10,13,12,10,12,12,14,13, 9,10,12, + 12,13,11,13,13,15,15,11,12,13,13,15, 8,10,10,12, + 13,10,12,12,13,13,10,12,11,13,13,11,13,12,15,15, + 12,13,12,15,13,10,12,12,16,14,11,12,12,16,15,10, + 12,12,16,14,14,15,14,18,16,13,13,14,15,16,10,12, + 12,14,16,11,13,13,16,16,11,13,12,14,16,13,15,15, + 18,18,13,15,13,16,14, 8,11,11,16,16,10,13,13,17, + 16,10,12,12,16,15,14,16,15,20,17,13,14,14,17,17, + 9,12,12,16,16,11,13,14,16,17,11,13,13,16,16,15, + 15,19,18, 0,14,15,15,18,18, 9,12,12,17,16,11,13, + 12,17,16,11,12,13,15,17,15,16,15, 0,19,14,15,14, + 19,18,12,14,14, 0,16,13,14,14,19,18,13,15,16,17, + 16,15,15,17,18, 0,14,16,16,19, 0,12,14,14,16,18, + 13,15,13,17,18,13,15,14,17,18,15,18,14,18,18,16, + 17,16, 0,17, 8,11,11,15,15,10,12,12,16,16,10,13, + 13,16,16,13,15,14,17,17,14,15,17,17,18, 9,12,12, + 16,15,11,13,13,16,16,11,12,13,17,17,14,14,15,17, + 17,14,15,16, 0,18, 9,12,12,16,17,11,13,13,16,17, + 11,14,13,18,17,14,16,14,17,17,15,17,17,18,18,12, + 14,14, 0,16,13,15,15,19, 0,12,13,15, 0, 0,14,17, + 16,19, 0,16,15,18,18, 0,12,14,14,17, 0,13,14,14, + 17, 0,13,15,14, 0,18,15,16,16, 0,18,15,18,15, 0, + 17, +}; + +static const static_codebook _44un1__p3_0 = { + 4, 625, + (char *)_vq_lengthlist__44un1__p3_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44un1__p3_0, + 0 +}; + +static const long _vq_quantlist__44un1__p4_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44un1__p4_0[] = { + 3, 5, 5, 9, 9, 5, 6, 6,10, 9, 5, 6, 6, 9,10,10, + 10,10,12,11, 9,10,10,12,12, 5, 7, 7,10,10, 7, 7, + 8,10,11, 7, 7, 8,10,11,10,10,11,11,13,10,10,11, + 11,13, 6, 7, 7,10,10, 7, 8, 7,11,10, 7, 8, 7,10, + 10,10,11, 9,13,11,10,11,10,13,11,10,10,10,14,13, + 10,11,11,14,13,10,10,11,13,14,12,12,13,15,15,12, + 12,13,13,14,10,10,10,12,13,10,11,10,13,13,10,11, + 11,13,13,12,13,12,14,13,12,13,13,14,13, 5, 7, 7, + 10,10, 7, 8, 8,11,10, 7, 8, 8,10,10,11,11,11,13, + 13,10,11,11,12,12, 7, 8, 8,11,11, 7, 8, 9,10,12, + 8, 9, 9,11,11,11,10,12,11,14,11,11,12,13,13, 6, + 8, 8,10,11, 7, 9, 7,12,10, 8, 9,10,11,12,10,12, + 10,14,11,11,12,11,13,13,10,11,11,14,14,10,10,11, + 13,14,11,12,12,15,13,12,11,14,12,16,12,13,14,15, + 16,10,10,11,13,14,10,11,10,14,12,11,12,12,13,14, + 12,13,11,15,12,14,14,14,15,15, 5, 7, 7,10,10, 7, + 8, 8,10,10, 7, 8, 8,10,11,10,11,10,12,12,10,11, + 11,12,13, 6, 8, 8,11,11, 8, 9, 9,12,11, 7, 7, 9, + 10,12,11,11,11,12,13,11,10,12,11,15, 7, 8, 8,11, + 11, 8, 9, 9,11,11, 7, 9, 8,12,10,11,12,11,13,12, + 11,12,10,15,11,10,11,10,14,12,11,12,11,14,13,10, + 10,11,13,14,13,13,13,17,15,12,11,14,12,15,10,10, + 11,13,14,11,12,12,14,14,10,11,10,14,13,13,14,13, + 16,17,12,14,11,16,12, 9,10,10,14,13,10,11,10,14, + 14,10,11,11,13,13,13,14,14,16,15,12,13,13,14,14, + 9,11,10,14,13,10,10,12,13,14,11,12,11,14,13,13, + 14,14,14,15,13,14,14,15,15, 9,10,11,13,14,10,11, + 10,15,13,11,11,12,12,15,13,14,12,15,14,13,13,14, + 14,15,12,13,12,16,14,11,11,12,15,14,13,15,13,16, + 14,13,12,15,12,17,15,16,15,16,16,12,12,13,13,15, + 11,13,11,15,14,13,13,14,15,17,13,14,12, 0,13,14, + 15,14,15, 0, 9,10,10,13,13,10,11,11,13,13,10,11, + 11,13,13,12,13,12,14,14,13,14,14,15,17, 9,10,10, + 13,13,11,12,11,15,12,10,10,11,13,16,13,14,13,15, + 14,13,13,14,15,16,10,10,11,13,14,11,11,12,13,14, + 10,12,11,14,14,13,13,13,14,15,13,15,13,16,15,12, + 13,12,15,13,12,15,13,15,15,11,11,13,14,15,15,15, + 15,15,17,13,12,14,13,17,12,12,14,14,15,13,13,14, + 14,16,11,13,11,16,15,14,16,16,17, 0,14,13,11,16, + 12, +}; + +static const static_codebook _44un1__p4_0 = { + 4, 625, + (char *)_vq_lengthlist__44un1__p4_0, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44un1__p4_0, + 0 +}; + +static const long _vq_quantlist__44un1__p5_0[] = { + 4, + 3, + 5, + 2, + 6, + 1, + 7, + 0, + 8, +}; + +static const char _vq_lengthlist__44un1__p5_0[] = { + 1, 4, 4, 7, 7, 8, 8, 9, 9, 4, 6, 5, 8, 7, 8, 8, + 10, 9, 4, 6, 6, 8, 8, 8, 8,10,10, 7, 8, 7, 9, 9, + 9, 9,11,10, 7, 8, 8, 9, 9, 9, 9,10,11, 8, 8, 8, + 9, 9,10,10,11,11, 8, 8, 8, 9, 9,10,10,11,11, 9, + 10,10,11,10,11,11,12,12, 9,10,10,10,11,11,11,12, + 12, +}; + +static const static_codebook _44un1__p5_0 = { + 2, 81, + (char *)_vq_lengthlist__44un1__p5_0, + 1, -531628032, 1611661312, 4, 0, + (long *)_vq_quantlist__44un1__p5_0, + 0 +}; + +static const long _vq_quantlist__44un1__p6_0[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44un1__p6_0[] = { + 1, 4, 4, 6, 6, 8, 8,10,10,11,11,15,15, 4, 5, 5, + 8, 8, 9, 9,11,11,12,12,16,16, 4, 5, 6, 8, 8, 9, + 9,11,11,12,12,14,14, 7, 8, 8, 9, 9,10,10,11,12, + 13,13,16,17, 7, 8, 8, 9, 9,10,10,12,12,12,13,15, + 15, 9,10,10,10,10,11,11,12,12,13,13,15,16, 9, 9, + 9,10,10,11,11,13,12,13,13,17,17,10,11,11,11,12, + 12,12,13,13,14,15, 0,18,10,11,11,12,12,12,13,14, + 13,14,14,17,16,11,12,12,13,13,14,14,14,14,15,16, + 17,16,11,12,12,13,13,14,14,14,14,15,15,17,17,14, + 15,15,16,16,16,17,17,16, 0,17, 0,18,14,15,15,16, + 16, 0,15,18,18, 0,16, 0, 0, +}; + +static const static_codebook _44un1__p6_0 = { + 2, 169, + (char *)_vq_lengthlist__44un1__p6_0, + 1, -526516224, 1616117760, 4, 0, + (long *)_vq_quantlist__44un1__p6_0, + 0 +}; + +static const long _vq_quantlist__44un1__p6_1[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44un1__p6_1[] = { + 2, 4, 4, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 6, 5, 5, + 6, 5, 6, 6, 5, 6, 6, 6, 6, +}; + +static const static_codebook _44un1__p6_1 = { + 2, 25, + (char *)_vq_lengthlist__44un1__p6_1, + 1, -533725184, 1611661312, 3, 0, + (long *)_vq_quantlist__44un1__p6_1, + 0 +}; + +static const long _vq_quantlist__44un1__p7_0[] = { + 2, + 1, + 3, + 0, + 4, +}; + +static const char _vq_lengthlist__44un1__p7_0[] = { + 1, 5, 3,11,11,11,11,11,11,11, 8,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,10,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,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11, 8,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,10, + 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,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11, 7,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,10,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,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,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,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,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,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, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10, +}; + +static const static_codebook _44un1__p7_0 = { + 4, 625, + (char *)_vq_lengthlist__44un1__p7_0, + 1, -518709248, 1626677248, 3, 0, + (long *)_vq_quantlist__44un1__p7_0, + 0 +}; + +static const long _vq_quantlist__44un1__p7_1[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44un1__p7_1[] = { + 1, 4, 4, 6, 6, 6, 6, 9, 8, 9, 8, 8, 8, 5, 7, 7, + 7, 7, 8, 8, 8,10, 8,10, 8, 9, 5, 7, 7, 8, 7, 7, + 8,10,10,11,10,12,11, 7, 8, 8, 9, 9, 9,10,11,11, + 11,11,11,11, 7, 8, 8, 8, 9, 9, 9,10,10,10,11,11, + 12, 7, 8, 8, 9, 9,10,11,11,12,11,12,11,11, 7, 8, + 8, 9, 9,10,10,11,11,11,12,12,11, 8,10,10,10,10, + 11,11,14,11,12,12,12,13, 9,10,10,10,10,12,11,14, + 11,14,11,12,13,10,11,11,11,11,13,11,14,14,13,13, + 13,14,11,11,11,12,11,12,12,12,13,14,14,13,14,12, + 11,12,12,12,12,13,13,13,14,13,14,14,11,12,12,14, + 12,13,13,12,13,13,14,14,14, +}; + +static const static_codebook _44un1__p7_1 = { + 2, 169, + (char *)_vq_lengthlist__44un1__p7_1, + 1, -523010048, 1618608128, 4, 0, + (long *)_vq_quantlist__44un1__p7_1, + 0 +}; + +static const long _vq_quantlist__44un1__p7_2[] = { + 6, + 5, + 7, + 4, + 8, + 3, + 9, + 2, + 10, + 1, + 11, + 0, + 12, +}; + +static const char _vq_lengthlist__44un1__p7_2[] = { + 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 9, 8, 4, 5, 5, + 6, 6, 8, 8, 9, 8, 9, 9, 9, 9, 4, 5, 5, 7, 6, 8, + 8, 8, 8, 9, 8, 9, 8, 6, 7, 7, 7, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, + 9, 7, 8, 8, 8, 8, 9, 8, 9, 9,10, 9, 9,10, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9,10,10, 8, 9, 9, 9, 9, + 9, 9, 9, 9,10,10, 9,10, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9,10,10, 9, 9, 9,10, 9, 9,10, 9, 9,10,10, + 10,10, 9, 9, 9, 9, 9, 9, 9,10, 9,10,10,10,10, 9, + 9, 9,10, 9, 9,10,10, 9,10,10,10,10, 9, 9, 9,10, + 9, 9, 9,10,10,10,10,10,10, +}; + +static const static_codebook _44un1__p7_2 = { + 2, 169, + (char *)_vq_lengthlist__44un1__p7_2, + 1, -531103744, 1611661312, 4, 0, + (long *)_vq_quantlist__44un1__p7_2, + 0 +}; + +static const char _huff_lengthlist__44un1__short[] = { + 12,12,14,12,14,14,14,14,12, 6, 6, 8, 9, 9,11,14, + 12, 4, 2, 6, 6, 7,11,14,13, 6, 5, 7, 8, 9,11,14, + 13, 8, 5, 8, 6, 8,12,14,12, 7, 7, 8, 8, 8,10,14, + 12, 6, 3, 4, 4, 4, 7,14,11, 7, 4, 6, 6, 6, 8,14, +}; + +static const static_codebook _huff_book__44un1__short = { + 2, 64, + (char *)_huff_lengthlist__44un1__short, + 0, 0, 0, 0, 0, + NULL, + 0 +}; + diff --git a/vendor/vorbis/lib/codebook.c b/vendor/vorbis/lib/codebook.c new file mode 100644 index 0000000..7a0c206 --- /dev/null +++ b/vendor/vorbis/lib/codebook.c @@ -0,0 +1,461 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: basic codebook pack/unpack/code/decode operations + + ********************************************************************/ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codebook.h" +#include "scales.h" +#include "misc.h" +#include "os.h" + +/* packs the given codebook into the bitstream **************************/ + +int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){ + long i,j; + int ordered=0; + + /* first the basic parameters */ + oggpack_write(opb,0x564342,24); + oggpack_write(opb,c->dim,16); + oggpack_write(opb,c->entries,24); + + /* pack the codewords. There are two packings; length ordered and + length random. Decide between the two now. */ + + for(i=1;ientries;i++) + if(c->lengthlist[i-1]==0 || c->lengthlist[i]lengthlist[i-1])break; + if(i==c->entries)ordered=1; + + if(ordered){ + /* length ordered. We only need to say how many codewords of + each length. The actual codewords are generated + deterministically */ + + long count=0; + oggpack_write(opb,1,1); /* ordered */ + oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */ + + for(i=1;ientries;i++){ + char this=c->lengthlist[i]; + char last=c->lengthlist[i-1]; + if(this>last){ + for(j=last;jentries-count)); + count=i; + } + } + } + oggpack_write(opb,i-count,ov_ilog(c->entries-count)); + + }else{ + /* length random. Again, we don't code the codeword itself, just + the length. This time, though, we have to encode each length */ + oggpack_write(opb,0,1); /* unordered */ + + /* algortihmic mapping has use for 'unused entries', which we tag + here. The algorithmic mapping happens as usual, but the unused + entry has no codeword. */ + for(i=0;ientries;i++) + if(c->lengthlist[i]==0)break; + + if(i==c->entries){ + oggpack_write(opb,0,1); /* no unused entries */ + for(i=0;ientries;i++) + oggpack_write(opb,c->lengthlist[i]-1,5); + }else{ + oggpack_write(opb,1,1); /* we have unused entries; thus we tag */ + for(i=0;ientries;i++){ + if(c->lengthlist[i]==0){ + oggpack_write(opb,0,1); + }else{ + oggpack_write(opb,1,1); + oggpack_write(opb,c->lengthlist[i]-1,5); + } + } + } + } + + /* is the entry number the desired return value, or do we have a + mapping? If we have a mapping, what type? */ + oggpack_write(opb,c->maptype,4); + switch(c->maptype){ + case 0: + /* no mapping */ + break; + case 1:case 2: + /* implicitly populated value mapping */ + /* explicitly populated value mapping */ + + if(!c->quantlist){ + /* no quantlist? error */ + return(-1); + } + + /* values that define the dequantization */ + oggpack_write(opb,c->q_min,32); + oggpack_write(opb,c->q_delta,32); + oggpack_write(opb,c->q_quant-1,4); + oggpack_write(opb,c->q_sequencep,1); + + { + int quantvals; + switch(c->maptype){ + case 1: + /* a single column of (c->entries/c->dim) quantized values for + building a full value list algorithmically (square lattice) */ + quantvals=_book_maptype1_quantvals(c); + break; + case 2: + /* every value (c->entries*c->dim total) specified explicitly */ + quantvals=c->entries*c->dim; + break; + default: /* NOT_REACHABLE */ + quantvals=-1; + } + + /* quantized values */ + for(i=0;iquantlist[i]),c->q_quant); + + } + break; + default: + /* error case; we don't have any other map types now */ + return(-1); + } + + return(0); +} + +/* unpacks a codebook from the packet buffer into the codebook struct, + readies the codebook auxiliary structures for decode *************/ +static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){ + long i,j; + static_codebook *s=_ogg_calloc(1,sizeof(*s)); + s->allocedp=1; + + /* make sure alignment is correct */ + if(oggpack_read(opb,24)!=0x564342)goto _eofout; + + /* first the basic parameters */ + s->dim=oggpack_read(opb,16); + s->entries=oggpack_read(opb,24); + if(s->entries==-1)goto _eofout; + + if(ov_ilog(s->dim)+ov_ilog(s->entries)>24)goto _eofout; + + /* codeword ordering.... length ordered or unordered? */ + switch((int)oggpack_read(opb,1)){ + case 0:{ + long unused; + /* allocated but unused entries? */ + unused=oggpack_read(opb,1); + if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb)) + goto _eofout; + /* unordered */ + s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries); + + /* allocated but unused entries? */ + if(unused){ + /* yes, unused entries */ + + for(i=0;ientries;i++){ + if(oggpack_read(opb,1)){ + long num=oggpack_read(opb,5); + if(num==-1)goto _eofout; + s->lengthlist[i]=num+1; + }else + s->lengthlist[i]=0; + } + }else{ + /* all entries used; no tagging */ + for(i=0;ientries;i++){ + long num=oggpack_read(opb,5); + if(num==-1)goto _eofout; + s->lengthlist[i]=num+1; + } + } + + break; + } + case 1: + /* ordered */ + { + long length=oggpack_read(opb,5)+1; + if(length==0)goto _eofout; + s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries); + + for(i=0;ientries;){ + long num=oggpack_read(opb,ov_ilog(s->entries-i)); + if(num==-1)goto _eofout; + if(length>32 || num>s->entries-i || + (num>0 && (num-1)>>(length-1)>1)){ + goto _errout; + } + if(length>32)goto _errout; + for(j=0;jlengthlist[i]=length; + length++; + } + } + break; + default: + /* EOF */ + goto _eofout; + } + + /* Do we have a mapping to unpack? */ + switch((s->maptype=oggpack_read(opb,4))){ + case 0: + /* no mapping */ + break; + case 1: case 2: + /* implicitly populated value mapping */ + /* explicitly populated value mapping */ + + s->q_min=oggpack_read(opb,32); + s->q_delta=oggpack_read(opb,32); + s->q_quant=oggpack_read(opb,4)+1; + s->q_sequencep=oggpack_read(opb,1); + if(s->q_sequencep==-1)goto _eofout; + + { + int quantvals=0; + switch(s->maptype){ + case 1: + quantvals=(s->dim==0?0:_book_maptype1_quantvals(s)); + break; + case 2: + quantvals=s->entries*s->dim; + break; + } + + /* quantized values */ + if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb)) + goto _eofout; + s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals); + for(i=0;iquantlist[i]=oggpack_read(opb,s->q_quant); + + if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout; + } + break; + default: + goto _errout; + } + + /* all set */ + return(s); + + _errout: + _eofout: + vorbis_staticbook_destroy(s); + return(NULL); +} + +/* returns the number of bits ************************************************/ +int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){ + if(a<0 || a>=book->c->entries)return(0); + oggpack_write(b,book->codelist[a],book->c->lengthlist[a]); + return(book->c->lengthlist[a]); +} + +/* the 'eliminate the decode tree' optimization actually requires the + codewords to be MSb first, not LSb. This is an annoying inelegancy + (and one of the first places where carefully thought out design + turned out to be wrong; Vorbis II and future Ogg codecs should go + to an MSb bitpacker), but not actually the huge hit it appears to + be. The first-stage decode table catches most words so that + bitreverse is not in the main execution path. */ + +static ogg_uint32_t bitreverse(ogg_uint32_t x){ + x= ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000); + x= ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00); + x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0); + x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc); + return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa); +} + +STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){ + int read=book->dec_maxlength; + long lo,hi; + long lok = oggpack_look(b,book->dec_firsttablen); + + if (lok >= 0) { + long entry = book->dec_firsttable[lok]; + if(entry&0x80000000UL){ + lo=(entry>>15)&0x7fff; + hi=book->used_entries-(entry&0x7fff); + }else{ + oggpack_adv(b, book->dec_codelengths[entry-1]); + return(entry-1); + } + }else{ + lo=0; + hi=book->used_entries; + } + + /* Single entry codebooks use a firsttablen of 1 and a + dec_maxlength of 1. If a single-entry codebook gets here (due to + failure to read one bit above), the next look attempt will also + fail and we'll correctly kick out instead of trying to walk the + underformed tree */ + + lok = oggpack_look(b, read); + + while(lok<0 && read>1) + lok = oggpack_look(b, --read); + if(lok<0)return -1; + + /* bisect search for the codeword in the ordered list */ + { + ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok); + + while(hi-lo>1){ + long p=(hi-lo)>>1; + long test=book->codelist[lo+p]>testword; + lo+=p&(test-1); + hi-=p&(-test); + } + + if(book->dec_codelengths[lo]<=read){ + oggpack_adv(b, book->dec_codelengths[lo]); + return(lo); + } + } + + oggpack_adv(b, read); + + return(-1); +} + +/* Decode side is specced and easier, because we don't need to find + matches using different criteria; we simply read and map. There are + two things we need to do 'depending': + + We may need to support interleave. We don't really, but it's + convenient to do it here rather than rebuild the vector later. + + Cascades may be additive or multiplicitive; this is not inherent in + the codebook, but set in the code using the codebook. Like + interleaving, it's easiest to do it here. + addmul==0 -> declarative (set the value) + addmul==1 -> additive + addmul==2 -> multiplicitive */ + +/* returns the [original, not compacted] entry number or -1 on eof *********/ +long vorbis_book_decode(codebook *book, oggpack_buffer *b){ + if(book->used_entries>0){ + long packed_entry=decode_packed_entry_number(book,b); + if(packed_entry>=0) + return(book->dec_index[packed_entry]); + } + + /* if there's no dec_index, the codebook unpacking isn't collapsed */ + return(-1); +} + +/* returns 0 on OK or -1 on eof *************************************/ +/* decode vector / dim granularity gaurding is done in the upper layer */ +long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){ + if(book->used_entries>0){ + int step=n/book->dim; + long *entry = alloca(sizeof(*entry)*step); + float **t = alloca(sizeof(*t)*step); + int i,j,o; + + for (i = 0; i < step; i++) { + entry[i]=decode_packed_entry_number(book,b); + if(entry[i]==-1)return(-1); + t[i] = book->valuelist+entry[i]*book->dim; + } + for(i=0,o=0;idim;i++,o+=step) + for (j=0;o+jused_entries>0){ + int i,j,entry; + float *t; + + for(i=0;ivaluelist+entry*book->dim; + for(j=0;idim;) + a[i++]+=t[j++]; + } + } + return(0); +} + +/* unlike the others, we guard against n not being an integer number + of internally rather than in the upper layer (called only by + floor0) */ +long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){ + if(book->used_entries>0){ + int i,j,entry; + float *t; + + for(i=0;ivaluelist+entry*book->dim; + for (j=0;idim;){ + a[i++]=t[j++]; + } + } + }else{ + int i; + + for(i=0;iused_entries>0){ + int m=(offset+n)/ch; + for(i=offset/ch;ivaluelist+entry*book->dim; + for (j=0;idim;j++){ + a[chptr++][i]+=t[j]; + if(chptr==ch){ + chptr=0; + i++; + } + } + } + } + } + return(0); +} diff --git a/vendor/vorbis/lib/codebook.h b/vendor/vorbis/lib/codebook.h new file mode 100644 index 0000000..7d4e2aa --- /dev/null +++ b/vendor/vorbis/lib/codebook.h @@ -0,0 +1,117 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: basic shared codebook operations + + ********************************************************************/ + +#ifndef _V_CODEBOOK_H_ +#define _V_CODEBOOK_H_ + +#include + +/* This structure encapsulates huffman and VQ style encoding books; it + doesn't do anything specific to either. + + valuelist/quantlist are nonNULL (and q_* significant) only if + there's entry->value mapping to be done. + + If encode-side mapping must be done (and thus the entry needs to be + hunted), the auxiliary encode pointer will point to a decision + tree. This is true of both VQ and huffman, but is mostly useful + with VQ. + +*/ + +typedef struct static_codebook{ + long dim; /* codebook dimensions (elements per vector) */ + long entries; /* codebook entries */ + char *lengthlist; /* codeword lengths in bits */ + + /* mapping ***************************************************************/ + int maptype; /* 0=none + 1=implicitly populated values from map column + 2=listed arbitrary values */ + + /* The below does a linear, single monotonic sequence mapping. */ + long q_min; /* packed 32 bit float; quant value 0 maps to minval */ + long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */ + int q_quant; /* bits: 0 < quant <= 16 */ + int q_sequencep; /* bitflag */ + + long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map + map == 2: list of dim*entries quantized entry vals + */ + int allocedp; +} static_codebook; + +typedef struct codebook{ + long dim; /* codebook dimensions (elements per vector) */ + long entries; /* codebook entries */ + long used_entries; /* populated codebook entries */ + const static_codebook *c; + + /* for encode, the below are entry-ordered, fully populated */ + /* for decode, the below are ordered by bitreversed codeword and only + used entries are populated */ + float *valuelist; /* list of dim*entries actual entry values */ + ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */ + + int *dec_index; /* only used if sparseness collapsed */ + char *dec_codelengths; + ogg_uint32_t *dec_firsttable; + int dec_firsttablen; + int dec_maxlength; + + /* The current encoder uses only centered, integer-only lattice books. */ + int quantvals; + int minval; + int delta; +} codebook; + +extern void vorbis_staticbook_destroy(static_codebook *b); +extern int vorbis_book_init_encode(codebook *dest,const static_codebook *source); +extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source); +extern void vorbis_book_clear(codebook *b); + +extern float *_book_unquantize(const static_codebook *b,int n,int *map); +extern float *_book_logdist(const static_codebook *b,float *vals); +extern float _float32_unpack(long val); +extern long _float32_pack(float val); +extern int _best(codebook *book, float *a, int step); +extern long _book_maptype1_quantvals(const static_codebook *b); + +extern int vorbis_book_besterror(codebook *book,float *a,int step,int addmul); +extern long vorbis_book_codeword(codebook *book,int entry); +extern long vorbis_book_codelen(codebook *book,int entry); + + + +extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b); +extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b); + +extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b); + +extern long vorbis_book_decode(codebook *book, oggpack_buffer *b); +extern long vorbis_book_decodevs_add(codebook *book, float *a, + oggpack_buffer *b,int n); +extern long vorbis_book_decodev_set(codebook *book, float *a, + oggpack_buffer *b,int n); +extern long vorbis_book_decodev_add(codebook *book, float *a, + oggpack_buffer *b,int n); +extern long vorbis_book_decodevv_add(codebook *book, float **a, + long off,int ch, + oggpack_buffer *b,int n); + + + +#endif diff --git a/vendor/vorbis/lib/codec_internal.h b/vendor/vorbis/lib/codec_internal.h new file mode 100644 index 0000000..2ecf5e5 --- /dev/null +++ b/vendor/vorbis/lib/codec_internal.h @@ -0,0 +1,166 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: libvorbis codec headers + + ********************************************************************/ + +#ifndef _V_CODECI_H_ +#define _V_CODECI_H_ + +#include "envelope.h" +#include "codebook.h" + +#define BLOCKTYPE_IMPULSE 0 +#define BLOCKTYPE_PADDING 1 +#define BLOCKTYPE_TRANSITION 0 +#define BLOCKTYPE_LONG 1 + +#define PACKETBLOBS 15 + +typedef struct vorbis_block_internal{ + float **pcmdelay; /* this is a pointer into local storage */ + float ampmax; + int blocktype; + + oggpack_buffer *packetblob[PACKETBLOBS]; /* initialized, must be freed; + blob [PACKETBLOBS/2] points to + the oggpack_buffer in the + main vorbis_block */ +} vorbis_block_internal; + +typedef void vorbis_look_floor; +typedef void vorbis_look_residue; +typedef void vorbis_look_transform; + +/* mode ************************************************************/ +typedef struct { + int blockflag; + int windowtype; + int transformtype; + int mapping; +} vorbis_info_mode; + +typedef void vorbis_info_floor; +typedef void vorbis_info_residue; +typedef void vorbis_info_mapping; + +#include "psy.h" +#include "bitrate.h" + +typedef struct private_state { + /* local lookup storage */ + envelope_lookup *ve; /* envelope lookup */ + int window[2]; + vorbis_look_transform **transform[2]; /* block, type */ + drft_lookup fft_look[2]; + + int modebits; + vorbis_look_floor **flr; + vorbis_look_residue **residue; + vorbis_look_psy *psy; + vorbis_look_psy_global *psy_g_look; + + /* local storage, only used on the encoding side. This way the + application does not need to worry about freeing some packets' + memory and not others'; packet storage is always tracked. + Cleared next call to a _dsp_ function */ + unsigned char *header; + unsigned char *header1; + unsigned char *header2; + + bitrate_manager_state bms; + + ogg_int64_t sample_count; +} private_state; + +/* codec_setup_info contains all the setup information specific to the + specific compression/decompression mode in progress (eg, + psychoacoustic settings, channel setup, options, codebook + etc). +*********************************************************************/ + +#include "highlevel.h" +typedef struct codec_setup_info { + + /* Vorbis supports only short and long blocks, but allows the + encoder to choose the sizes */ + + long blocksizes[2]; + + /* modes are the primary means of supporting on-the-fly different + blocksizes, different channel mappings (LR or M/A), + different residue backends, etc. Each mode consists of a + blocksize flag and a mapping (along with the mapping setup */ + + int modes; + int maps; + int floors; + int residues; + int books; + int psys; /* encode only */ + + vorbis_info_mode *mode_param[64]; + int map_type[64]; + vorbis_info_mapping *map_param[64]; + int floor_type[64]; + vorbis_info_floor *floor_param[64]; + int residue_type[64]; + vorbis_info_residue *residue_param[64]; + static_codebook *book_param[256]; + codebook *fullbooks; + + vorbis_info_psy *psy_param[4]; /* encode only */ + vorbis_info_psy_global psy_g_param; + + bitrate_manager_info bi; + highlevel_encode_setup hi; /* used only by vorbisenc.c. It's a + highly redundant structure, but + improves clarity of program flow. */ + int halfrate_flag; /* painless downsample for decode */ +} codec_setup_info; + +extern vorbis_look_psy_global *_vp_global_look(vorbis_info *vi); +extern void _vp_global_free(vorbis_look_psy_global *look); + + + +typedef struct { + int sorted_index[VIF_POSIT+2]; + int forward_index[VIF_POSIT+2]; + int reverse_index[VIF_POSIT+2]; + + int hineighbor[VIF_POSIT]; + int loneighbor[VIF_POSIT]; + int posts; + + int n; + int quant_q; + vorbis_info_floor1 *vi; + + long phrasebits; + long postbits; + long frames; +} vorbis_look_floor1; + + + +extern int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look, + const float *logmdct, /* in */ + const float *logmask); +extern int *floor1_interpolate_fit(vorbis_block *vb,vorbis_look_floor1 *look, + int *A,int *B, + int del); +extern int floor1_encode(oggpack_buffer *opb,vorbis_block *vb, + vorbis_look_floor1 *look, + int *post,int *ilogmask); +#endif diff --git a/vendor/vorbis/lib/envelope.c b/vendor/vorbis/lib/envelope.c new file mode 100644 index 0000000..22d39aa --- /dev/null +++ b/vendor/vorbis/lib/envelope.c @@ -0,0 +1,374 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: PCM data envelope analysis + + ********************************************************************/ + +#include +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" + +#include "os.h" +#include "scales.h" +#include "envelope.h" +#include "mdct.h" +#include "misc.h" + +void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy_global *gi=&ci->psy_g_param; + int ch=vi->channels; + int i,j; + int n=e->winlength=128; + e->searchstep=64; /* not random */ + + e->minenergy=gi->preecho_minenergy; + e->ch=ch; + e->storage=128; + e->cursor=ci->blocksizes[1]/2; + e->mdct_win=_ogg_calloc(n,sizeof(*e->mdct_win)); + mdct_init(&e->mdct,n); + + for(i=0;imdct_win[i]=sin(i/(n-1.)*M_PI); + e->mdct_win[i]*=e->mdct_win[i]; + } + + /* magic follows */ + e->band[0].begin=2; e->band[0].end=4; + e->band[1].begin=4; e->band[1].end=5; + e->band[2].begin=6; e->band[2].end=6; + e->band[3].begin=9; e->band[3].end=8; + e->band[4].begin=13; e->band[4].end=8; + e->band[5].begin=17; e->band[5].end=8; + e->band[6].begin=22; e->band[6].end=8; + + for(j=0;jband[j].end; + e->band[j].window=_ogg_malloc(n*sizeof(*e->band[0].window)); + for(i=0;iband[j].window[i]=sin((i+.5)/n*M_PI); + e->band[j].total+=e->band[j].window[i]; + } + e->band[j].total=1./e->band[j].total; + } + + e->filter=_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter)); + e->mark=_ogg_calloc(e->storage,sizeof(*e->mark)); + +} + +void _ve_envelope_clear(envelope_lookup *e){ + int i; + mdct_clear(&e->mdct); + for(i=0;iband[i].window); + _ogg_free(e->mdct_win); + _ogg_free(e->filter); + _ogg_free(e->mark); + memset(e,0,sizeof(*e)); +} + +/* fairly straight threshhold-by-band based until we find something + that works better and isn't patented. */ + +static int _ve_amp(envelope_lookup *ve, + vorbis_info_psy_global *gi, + float *data, + envelope_band *bands, + envelope_filter_state *filters){ + long n=ve->winlength; + int ret=0; + long i,j; + float decay; + + /* we want to have a 'minimum bar' for energy, else we're just + basing blocks on quantization noise that outweighs the signal + itself (for low power signals) */ + + float minV=ve->minenergy; + float *vec=alloca(n*sizeof(*vec)); + + /* stretch is used to gradually lengthen the number of windows + considered prevoius-to-potential-trigger */ + int stretch=max(VE_MINSTRETCH,ve->stretch/2); + float penalty=gi->stretch_penalty-(ve->stretch/2-VE_MINSTRETCH); + if(penalty<0.f)penalty=0.f; + if(penalty>gi->stretch_penalty)penalty=gi->stretch_penalty; + + /*_analysis_output_always("lpcm",seq2,data,n,0,0, + totalshift+pos*ve->searchstep);*/ + + /* window and transform */ + for(i=0;imdct_win[i]; + mdct_forward(&ve->mdct,vec,vec); + + /*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */ + + /* near-DC spreading function; this has nothing to do with + psychoacoustics, just sidelobe leakage and window size */ + { + float temp=vec[0]*vec[0]+.7*vec[1]*vec[1]+.2*vec[2]*vec[2]; + int ptr=filters->nearptr; + + /* the accumulation is regularly refreshed from scratch to avoid + floating point creep */ + if(ptr==0){ + decay=filters->nearDC_acc=filters->nearDC_partialacc+temp; + filters->nearDC_partialacc=temp; + }else{ + decay=filters->nearDC_acc+=temp; + filters->nearDC_partialacc+=temp; + } + filters->nearDC_acc-=filters->nearDC[ptr]; + filters->nearDC[ptr]=temp; + + decay*=(1./(VE_NEARDC+1)); + filters->nearptr++; + if(filters->nearptr>=VE_NEARDC)filters->nearptr=0; + decay=todB(&decay)*.5-15.f; + } + + /* perform spreading and limiting, also smooth the spectrum. yes, + the MDCT results in all real coefficients, but it still *behaves* + like real/imaginary pairs */ + for(i=0;i>1]=val; + decay-=8.; + } + + /*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/ + + /* perform preecho/postecho triggering by band */ + for(j=0;j=VE_AMP)filters[j].ampptr=0; + } + + /* look at min/max, decide trigger */ + if(valmax>gi->preecho_thresh[j]+penalty){ + ret|=1; + ret|=4; + } + if(valminpostecho_thresh[j]-penalty)ret|=2; + } + + return(ret); +} + +#if 0 +static int seq=0; +static ogg_int64_t totalshift=-1024; +#endif + +long _ve_envelope_search(vorbis_dsp_state *v){ + vorbis_info *vi=v->vi; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy_global *gi=&ci->psy_g_param; + envelope_lookup *ve=((private_state *)(v->backend_state))->ve; + long i,j; + + int first=ve->current/ve->searchstep; + int last=v->pcm_current/ve->searchstep-VE_WIN; + if(first<0)first=0; + + /* make sure we have enough storage to match the PCM */ + if(last+VE_WIN+VE_POST>ve->storage){ + ve->storage=last+VE_WIN+VE_POST; /* be sure */ + ve->mark=_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark)); + } + + for(j=first;jstretch++; + if(ve->stretch>VE_MAXSTRETCH*2) + ve->stretch=VE_MAXSTRETCH*2; + + for(i=0;ich;i++){ + float *pcm=v->pcm[i]+ve->searchstep*(j); + ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS); + } + + ve->mark[j+VE_POST]=0; + if(ret&1){ + ve->mark[j]=1; + ve->mark[j+1]=1; + } + + if(ret&2){ + ve->mark[j]=1; + if(j>0)ve->mark[j-1]=1; + } + + if(ret&4)ve->stretch=-1; + } + + ve->current=last*ve->searchstep; + + { + long centerW=v->centerW; + long testW= + centerW+ + ci->blocksizes[v->W]/4+ + ci->blocksizes[1]/2+ + ci->blocksizes[0]/4; + + j=ve->cursor; + + while(jcurrent-(ve->searchstep)){/* account for postecho + working back one window */ + if(j>=testW)return(1); + + ve->cursor=j; + + if(ve->mark[j/ve->searchstep]){ + if(j>centerW){ + +#if 0 + if(j>ve->curmark){ + float *marker=alloca(v->pcm_current*sizeof(*marker)); + int l,m; + memset(marker,0,sizeof(*marker)*v->pcm_current); + fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n", + seq, + (totalshift+ve->cursor)/44100., + (totalshift+j)/44100.); + _analysis_output_always("pcmL",seq,v->pcm[0],v->pcm_current,0,0,totalshift); + _analysis_output_always("pcmR",seq,v->pcm[1],v->pcm_current,0,0,totalshift); + + _analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift); + _analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift); + + for(m=0;msearchstep]=ve->filter[m].markers[l]*.1; + _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); + } + + for(m=0;msearchstep]=ve->filter[m+VE_BANDS].markers[l]*.1; + _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); + } + + for(l=0;lsearchstep]=ve->mark[l]*.4; + _analysis_output_always("mark",seq,marker,v->pcm_current,0,0,totalshift); + + + seq++; + + } +#endif + + ve->curmark=j; + if(j>=testW)return(1); + return(0); + } + } + j+=ve->searchstep; + } + } + + return(-1); +} + +int _ve_envelope_mark(vorbis_dsp_state *v){ + envelope_lookup *ve=((private_state *)(v->backend_state))->ve; + vorbis_info *vi=v->vi; + codec_setup_info *ci=vi->codec_setup; + long centerW=v->centerW; + long beginW=centerW-ci->blocksizes[v->W]/4; + long endW=centerW+ci->blocksizes[v->W]/4; + if(v->W){ + beginW-=ci->blocksizes[v->lW]/4; + endW+=ci->blocksizes[v->nW]/4; + }else{ + beginW-=ci->blocksizes[0]/4; + endW+=ci->blocksizes[0]/4; + } + + if(ve->curmark>=beginW && ve->curmarksearchstep; + long last=endW/ve->searchstep; + long i; + for(i=first;imark[i])return(1); + } + return(0); +} + +void _ve_envelope_shift(envelope_lookup *e,long shift){ + int smallsize=e->current/e->searchstep+VE_POST; /* adjust for placing marks + ahead of ve->current */ + int smallshift=shift/e->searchstep; + + memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark)); + +#if 0 + for(i=0;ich;i++) + memmove(e->filter[i].markers, + e->filter[i].markers+smallshift, + (1024-smallshift)*sizeof(*(*e->filter).markers)); + totalshift+=shift; +#endif + + e->current-=shift; + if(e->curmark>=0) + e->curmark-=shift; + e->cursor-=shift; +} diff --git a/vendor/vorbis/lib/envelope.h b/vendor/vorbis/lib/envelope.h new file mode 100644 index 0000000..2ef60a8 --- /dev/null +++ b/vendor/vorbis/lib/envelope.h @@ -0,0 +1,79 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: PCM data envelope analysis and manipulation + + ********************************************************************/ + +#ifndef _V_ENVELOPE_ +#define _V_ENVELOPE_ + +#include "mdct.h" + +#define VE_PRE 16 +#define VE_WIN 4 +#define VE_POST 2 +#define VE_AMP (VE_PRE+VE_POST-1) + +#define VE_BANDS 7 +#define VE_NEARDC 15 + +#define VE_MINSTRETCH 2 /* a bit less than short block */ +#define VE_MAXSTRETCH 12 /* one-third full block */ + +typedef struct { + float ampbuf[VE_AMP]; + int ampptr; + + float nearDC[VE_NEARDC]; + float nearDC_acc; + float nearDC_partialacc; + int nearptr; + +} envelope_filter_state; + +typedef struct { + int begin; + int end; + float *window; + float total; +} envelope_band; + +typedef struct { + int ch; + int winlength; + int searchstep; + float minenergy; + + mdct_lookup mdct; + float *mdct_win; + + envelope_band band[VE_BANDS]; + envelope_filter_state *filter; + int stretch; + + int *mark; + + long storage; + long current; + long curmark; + long cursor; +} envelope_lookup; + +extern void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi); +extern void _ve_envelope_clear(envelope_lookup *e); +extern long _ve_envelope_search(vorbis_dsp_state *v); +extern void _ve_envelope_shift(envelope_lookup *e,long shift); +extern int _ve_envelope_mark(vorbis_dsp_state *v); + + +#endif diff --git a/vendor/vorbis/lib/floor0.c b/vendor/vorbis/lib/floor0.c new file mode 100644 index 0000000..f4a6d4d --- /dev/null +++ b/vendor/vorbis/lib/floor0.c @@ -0,0 +1,223 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: floor backend 0 implementation + + ********************************************************************/ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "registry.h" +#include "lpc.h" +#include "lsp.h" +#include "codebook.h" +#include "scales.h" +#include "misc.h" +#include "os.h" + +#include "misc.h" +#include + +typedef struct { + int ln; + int m; + int **linearmap; + int n[2]; + + vorbis_info_floor0 *vi; + + long bits; + long frames; +} vorbis_look_floor0; + + +/***********************************************/ + +static void floor0_free_info(vorbis_info_floor *i){ + vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; + if(info){ + memset(info,0,sizeof(*info)); + _ogg_free(info); + } +} + +static void floor0_free_look(vorbis_look_floor *i){ + vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; + if(look){ + + if(look->linearmap){ + + if(look->linearmap[0])_ogg_free(look->linearmap[0]); + if(look->linearmap[1])_ogg_free(look->linearmap[1]); + + _ogg_free(look->linearmap); + } + memset(look,0,sizeof(*look)); + _ogg_free(look); + } +} + +static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){ + codec_setup_info *ci=vi->codec_setup; + int j; + + vorbis_info_floor0 *info=_ogg_malloc(sizeof(*info)); + info->order=oggpack_read(opb,8); + info->rate=oggpack_read(opb,16); + info->barkmap=oggpack_read(opb,16); + info->ampbits=oggpack_read(opb,6); + info->ampdB=oggpack_read(opb,8); + info->numbooks=oggpack_read(opb,4)+1; + + if(info->order<1)goto err_out; + if(info->rate<1)goto err_out; + if(info->barkmap<1)goto err_out; + if(info->numbooks<1)goto err_out; + + for(j=0;jnumbooks;j++){ + info->books[j]=oggpack_read(opb,8); + if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out; + if(ci->book_param[info->books[j]]->maptype==0)goto err_out; + if(ci->book_param[info->books[j]]->dim<1)goto err_out; + } + return(info); + + err_out: + floor0_free_info(info); + return(NULL); +} + +/* initialize Bark scale and normalization lookups. We could do this + with static tables, but Vorbis allows a number of possible + combinations, so it's best to do it computationally. + + The below is authoritative in terms of defining scale mapping. + Note that the scale depends on the sampling rate as well as the + linear block and mapping sizes */ + +static void floor0_map_lazy_init(vorbis_block *vb, + vorbis_info_floor *infoX, + vorbis_look_floor0 *look){ + if(!look->linearmap[vb->W]){ + vorbis_dsp_state *vd=vb->vd; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_floor0 *info=(vorbis_info_floor0 *)infoX; + int W=vb->W; + int n=ci->blocksizes[W]/2,j; + + /* we choose a scaling constant so that: + floor(bark(rate/2-1)*C)=mapped-1 + floor(bark(rate/2)*C)=mapped */ + float scale=look->ln/toBARK(info->rate/2.f); + + /* the mapping from a linear scale to a smaller bark scale is + straightforward. We do *not* make sure that the linear mapping + does not skip bark-scale bins; the decoder simply skips them and + the encoder may do what it wishes in filling them. They're + necessary in some mapping combinations to keep the scale spacing + accurate */ + look->linearmap[W]=_ogg_malloc((n+1)*sizeof(**look->linearmap)); + for(j=0;jrate/2.f)/n*j) + *scale); /* bark numbers represent band edges */ + if(val>=look->ln)val=look->ln-1; /* guard against the approximation */ + look->linearmap[W][j]=val; + } + look->linearmap[W][j]=-1; + look->n[W]=n; + } +} + +static vorbis_look_floor *floor0_look(vorbis_dsp_state *vd, + vorbis_info_floor *i){ + vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; + vorbis_look_floor0 *look=_ogg_calloc(1,sizeof(*look)); + + (void)vd; + + look->m=info->order; + look->ln=info->barkmap; + look->vi=info; + + look->linearmap=_ogg_calloc(2,sizeof(*look->linearmap)); + + return look; +} + +static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){ + vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; + vorbis_info_floor0 *info=look->vi; + int j,k; + + int ampraw=oggpack_read(&vb->opb,info->ampbits); + if(ampraw>0){ /* also handles the -1 out of data case */ + long maxval=(1<ampbits)-1; + float amp=(float)ampraw/maxval*info->ampdB; + int booknum=oggpack_read(&vb->opb,ov_ilog(info->numbooks)); + + if(booknum!=-1 && booknumnumbooks){ /* be paranoid */ + codec_setup_info *ci=vb->vd->vi->codec_setup; + codebook *b=ci->fullbooks+info->books[booknum]; + float last=0.f; + + /* the additional b->dim is a guard against any possible stack + smash; b->dim is provably more than we can overflow the + vector */ + float *lsp=_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+b->dim+1)); + + if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m)==-1)goto eop; + for(j=0;jm;){ + for(k=0;jm && kdim;k++,j++)lsp[j]+=last; + last=lsp[j-1]; + } + + lsp[look->m]=amp; + return(lsp); + } + } + eop: + return(NULL); +} + +static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i, + void *memo,float *out){ + vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; + vorbis_info_floor0 *info=look->vi; + + floor0_map_lazy_init(vb,info,look); + + if(memo){ + float *lsp=(float *)memo; + float amp=lsp[look->m]; + + /* take the coefficients back to a spectral envelope curve */ + vorbis_lsp_to_curve(out, + look->linearmap[vb->W], + look->n[vb->W], + look->ln, + lsp,look->m,amp,(float)info->ampdB); + return(1); + } + memset(out,0,sizeof(*out)*look->n[vb->W]); + return(0); +} + +/* export hooks */ +const vorbis_func_floor floor0_exportbundle={ + NULL,&floor0_unpack,&floor0_look,&floor0_free_info, + &floor0_free_look,&floor0_inverse1,&floor0_inverse2 +}; diff --git a/vendor/vorbis/lib/floor1.c b/vendor/vorbis/lib/floor1.c new file mode 100644 index 0000000..c4fe3ea --- /dev/null +++ b/vendor/vorbis/lib/floor1.c @@ -0,0 +1,1086 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: floor backend 1 implementation + + ********************************************************************/ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "registry.h" +#include "codebook.h" +#include "misc.h" +#include "scales.h" + +#include + +#define floor1_rangedB 140 /* floor 1 fixed at -140dB to 0dB range */ + +typedef struct lsfit_acc{ + int x0; + int x1; + + int xa; + int ya; + int x2a; + int y2a; + int xya; + int an; + + int xb; + int yb; + int x2b; + int y2b; + int xyb; + int bn; +} lsfit_acc; + +/***********************************************/ + +static void floor1_free_info(vorbis_info_floor *i){ + vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; + if(info){ + memset(info,0,sizeof(*info)); + _ogg_free(info); + } +} + +static void floor1_free_look(vorbis_look_floor *i){ + vorbis_look_floor1 *look=(vorbis_look_floor1 *)i; + if(look){ + /*fprintf(stderr,"floor 1 bit usage %f:%f (%f total)\n", + (float)look->phrasebits/look->frames, + (float)look->postbits/look->frames, + (float)(look->postbits+look->phrasebits)/look->frames);*/ + + memset(look,0,sizeof(*look)); + _ogg_free(look); + } +} + +static void floor1_pack (vorbis_info_floor *i,oggpack_buffer *opb){ + vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; + int j,k; + int count=0; + int rangebits; + int maxposit=info->postlist[1]; + int maxclass=-1; + + /* save out partitions */ + oggpack_write(opb,info->partitions,5); /* only 0 to 31 legal */ + for(j=0;jpartitions;j++){ + oggpack_write(opb,info->partitionclass[j],4); /* only 0 to 15 legal */ + if(maxclasspartitionclass[j])maxclass=info->partitionclass[j]; + } + + /* save out partition classes */ + for(j=0;jclass_dim[j]-1,3); /* 1 to 8 */ + oggpack_write(opb,info->class_subs[j],2); /* 0 to 3 */ + if(info->class_subs[j])oggpack_write(opb,info->class_book[j],8); + for(k=0;k<(1<class_subs[j]);k++) + oggpack_write(opb,info->class_subbook[j][k]+1,8); + } + + /* save out the post list */ + oggpack_write(opb,info->mult-1,2); /* only 1,2,3,4 legal now */ + /* maxposit cannot legally be less than 1; this is encode-side, we + can assume our setup is OK */ + oggpack_write(opb,ov_ilog(maxposit-1),4); + rangebits=ov_ilog(maxposit-1); + + for(j=0,k=0;jpartitions;j++){ + count+=info->class_dim[info->partitionclass[j]]; + for(;kpostlist[k+2],rangebits); + } +} + +static int icomp(const void *a,const void *b){ + return(**(int **)a-**(int **)b); +} + +static vorbis_info_floor *floor1_unpack (vorbis_info *vi,oggpack_buffer *opb){ + codec_setup_info *ci=vi->codec_setup; + int j,k,count=0,maxclass=-1,rangebits; + + vorbis_info_floor1 *info=_ogg_calloc(1,sizeof(*info)); + /* read partitions */ + info->partitions=oggpack_read(opb,5); /* only 0 to 31 legal */ + for(j=0;jpartitions;j++){ + info->partitionclass[j]=oggpack_read(opb,4); /* only 0 to 15 legal */ + if(info->partitionclass[j]<0)goto err_out; + if(maxclasspartitionclass[j])maxclass=info->partitionclass[j]; + } + + /* read partition classes */ + for(j=0;jclass_dim[j]=oggpack_read(opb,3)+1; /* 1 to 8 */ + info->class_subs[j]=oggpack_read(opb,2); /* 0,1,2,3 bits */ + if(info->class_subs[j]<0) + goto err_out; + if(info->class_subs[j])info->class_book[j]=oggpack_read(opb,8); + if(info->class_book[j]<0 || info->class_book[j]>=ci->books) + goto err_out; + for(k=0;k<(1<class_subs[j]);k++){ + info->class_subbook[j][k]=oggpack_read(opb,8)-1; + if(info->class_subbook[j][k]<-1 || info->class_subbook[j][k]>=ci->books) + goto err_out; + } + } + + /* read the post list */ + info->mult=oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */ + rangebits=oggpack_read(opb,4); + if(rangebits<0)goto err_out; + + for(j=0,k=0;jpartitions;j++){ + count+=info->class_dim[info->partitionclass[j]]; + if(count>VIF_POSIT) goto err_out; + for(;kpostlist[k+2]=oggpack_read(opb,rangebits); + if(t<0 || t>=(1<postlist[0]=0; + info->postlist[1]=1<postlist+j; + qsort(sortpointer,count+2,sizeof(*sortpointer),icomp); + + for(j=1;jvi=info; + look->n=info->postlist[1]; + + /* we drop each position value in-between already decoded values, + and use linear interpolation to predict each new value past the + edges. The positions are read in the order of the position + list... we precompute the bounding positions in the lookup. Of + course, the neighbors can change (if a position is declined), but + this is an initial mapping */ + + for(i=0;ipartitions;i++)n+=info->class_dim[info->partitionclass[i]]; + n+=2; + look->posts=n; + + /* also store a sorted position index */ + for(i=0;ipostlist+i; + qsort(sortpointer,n,sizeof(*sortpointer),icomp); + + /* points from sort order back to range number */ + for(i=0;iforward_index[i]=sortpointer[i]-info->postlist; + /* points from range order to sorted position */ + for(i=0;ireverse_index[look->forward_index[i]]=i; + /* we actually need the post values too */ + for(i=0;isorted_index[i]=info->postlist[look->forward_index[i]]; + + /* quantize values to multiplier spec */ + switch(info->mult){ + case 1: /* 1024 -> 256 */ + look->quant_q=256; + break; + case 2: /* 1024 -> 128 */ + look->quant_q=128; + break; + case 3: /* 1024 -> 86 */ + look->quant_q=86; + break; + case 4: /* 1024 -> 64 */ + look->quant_q=64; + break; + } + + /* discover our neighbors for decode where we don't use fit flags + (that would push the neighbors outward) */ + for(i=0;in; + int currentx=info->postlist[i+2]; + for(j=0;jpostlist[j]; + if(x>lx && xcurrentx){ + hi=j; + hx=x; + } + } + look->loneighbor[i]=lo; + look->hineighbor[i]=hi; + } + + return(look); +} + +static int render_point(int x0,int x1,int y0,int y1,int x){ + y0&=0x7fff; /* mask off flag */ + y1&=0x7fff; + + { + int dy=y1-y0; + int adx=x1-x0; + int ady=abs(dy); + int err=ady*(x-x0); + + int off=err/adx; + if(dy<0)return(y0-off); + return(y0+off); + } +} + +static int vorbis_dBquant(const float *x){ + int i= *x*7.3142857f+1023.5f; + if(i>1023)return(1023); + if(i<0)return(0); + return i; +} + +static const float FLOOR1_fromdB_LOOKUP[256]={ + 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, + 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, + 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, + 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, + 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, + 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, + 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, + 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, + 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, + 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, + 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, + 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, + 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, + 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, + 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, + 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, + 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, + 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, + 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, + 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, + 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, + 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, + 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, + 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, + 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, + 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, + 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, + 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, + 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, + 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, + 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, + 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, + 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, + 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, + 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, + 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, + 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, + 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, + 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, + 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, + 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, + 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, + 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, + 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, + 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, + 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, + 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, + 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, + 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, + 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, + 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, + 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, + 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, + 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, + 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, + 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, + 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, + 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, + 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, + 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, + 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, + 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, + 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, + 0.82788260F, 0.88168307F, 0.9389798F, 1.F, +}; + +static void render_line(int n, int x0,int x1,int y0,int y1,float *d){ + int dy=y1-y0; + int adx=x1-x0; + int ady=abs(dy); + int base=dy/adx; + int sy=(dy<0?base-1:base+1); + int x=x0; + int y=y0; + int err=0; + + ady-=abs(base*adx); + + if(n>x1)n=x1; + + if(x=adx){ + err-=adx; + y+=sy; + }else{ + y+=base; + } + d[x]*=FLOOR1_fromdB_LOOKUP[y]; + } +} + +static void render_line0(int n, int x0,int x1,int y0,int y1,int *d){ + int dy=y1-y0; + int adx=x1-x0; + int ady=abs(dy); + int base=dy/adx; + int sy=(dy<0?base-1:base+1); + int x=x0; + int y=y0; + int err=0; + + ady-=abs(base*adx); + + if(n>x1)n=x1; + + if(x=adx){ + err-=adx; + y+=sy; + }else{ + y+=base; + } + d[x]=y; + } +} + +/* the floor has already been filtered to only include relevant sections */ +static int accumulate_fit(const float *flr,const float *mdct, + int x0, int x1,lsfit_acc *a, + int n,vorbis_info_floor1 *info){ + long i; + + int xa=0,ya=0,x2a=0,y2a=0,xya=0,na=0, xb=0,yb=0,x2b=0,y2b=0,xyb=0,nb=0; + + memset(a,0,sizeof(*a)); + a->x0=x0; + a->x1=x1; + if(x1>=n)x1=n-1; + + for(i=x0;i<=x1;i++){ + int quantized=vorbis_dBquant(flr+i); + if(quantized){ + if(mdct[i]+info->twofitatten>=flr[i]){ + xa += i; + ya += quantized; + x2a += i*i; + y2a += quantized*quantized; + xya += i*quantized; + na++; + }else{ + xb += i; + yb += quantized; + x2b += i*i; + y2b += quantized*quantized; + xyb += i*quantized; + nb++; + } + } + } + + a->xa=xa; + a->ya=ya; + a->x2a=x2a; + a->y2a=y2a; + a->xya=xya; + a->an=na; + + a->xb=xb; + a->yb=yb; + a->x2b=x2b; + a->y2b=y2b; + a->xyb=xyb; + a->bn=nb; + + return(na); +} + +static int fit_line(lsfit_acc *a,int fits,int *y0,int *y1, + vorbis_info_floor1 *info){ + double xb=0,yb=0,x2b=0,y2b=0,xyb=0,bn=0; + int i; + int x0=a[0].x0; + int x1=a[fits-1].x1; + + for(i=0;itwofitweight/(a[i].an+1)+1.; + + xb+=a[i].xb + a[i].xa * weight; + yb+=a[i].yb + a[i].ya * weight; + x2b+=a[i].x2b + a[i].x2a * weight; + y2b+=a[i].y2b + a[i].y2a * weight; + xyb+=a[i].xyb + a[i].xya * weight; + bn+=a[i].bn + a[i].an * weight; + } + + if(*y0>=0){ + xb+= x0; + yb+= *y0; + x2b+= x0 * x0; + y2b+= *y0 * *y0; + xyb+= *y0 * x0; + bn++; + } + + if(*y1>=0){ + xb+= x1; + yb+= *y1; + x2b+= x1 * x1; + y2b+= *y1 * *y1; + xyb+= *y1 * x1; + bn++; + } + + { + double denom=(bn*x2b-xb*xb); + + if(denom>0.){ + double a=(yb*x2b-xyb*xb)/denom; + double b=(bn*xyb-xb*yb)/denom; + *y0=rint(a+b*x0); + *y1=rint(a+b*x1); + + /* limit to our range! */ + if(*y0>1023)*y0=1023; + if(*y1>1023)*y1=1023; + if(*y0<0)*y0=0; + if(*y1<0)*y1=0; + + return 0; + }else{ + *y0=0; + *y1=0; + return 1; + } + } +} + +static int inspect_error(int x0,int x1,int y0,int y1,const float *mask, + const float *mdct, + vorbis_info_floor1 *info){ + int dy=y1-y0; + int adx=x1-x0; + int ady=abs(dy); + int base=dy/adx; + int sy=(dy<0?base-1:base+1); + int x=x0; + int y=y0; + int err=0; + int val=vorbis_dBquant(mask+x); + int mse=0; + int n=0; + + ady-=abs(base*adx); + + mse=(y-val); + mse*=mse; + n++; + if(mdct[x]+info->twofitatten>=mask[x]){ + if(y+info->maxovermaxunder>val)return(1); + } + + while(++x=adx){ + err-=adx; + y+=sy; + }else{ + y+=base; + } + + val=vorbis_dBquant(mask+x); + mse+=((y-val)*(y-val)); + n++; + if(mdct[x]+info->twofitatten>=mask[x]){ + if(val){ + if(y+info->maxovermaxunder>val)return(1); + } + } + } + + if(info->maxover*info->maxover/n>info->maxerr)return(0); + if(info->maxunder*info->maxunder/n>info->maxerr)return(0); + if(mse/n>info->maxerr)return(1); + return(0); +} + +static int post_Y(int *A,int *B,int pos){ + if(A[pos]<0) + return B[pos]; + if(B[pos]<0) + return A[pos]; + + return (A[pos]+B[pos])>>1; +} + +int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look, + const float *logmdct, /* in */ + const float *logmask){ + long i,j; + vorbis_info_floor1 *info=look->vi; + long n=look->n; + long posts=look->posts; + long nonzero=0; + lsfit_acc fits[VIF_POSIT+1]; + int fit_valueA[VIF_POSIT+2]; /* index by range list position */ + int fit_valueB[VIF_POSIT+2]; /* index by range list position */ + + int loneighbor[VIF_POSIT+2]; /* sorted index of range list position (+2) */ + int hineighbor[VIF_POSIT+2]; + int *output=NULL; + int memo[VIF_POSIT+2]; + + for(i=0;isorted_index[i], + look->sorted_index[i+1],fits+i, + n,info); + } + + if(nonzero){ + /* start by fitting the implicit base case.... */ + int y0=-200; + int y1=-200; + fit_line(fits,posts-1,&y0,&y1,info); + + fit_valueA[0]=y0; + fit_valueB[0]=y0; + fit_valueB[1]=y1; + fit_valueA[1]=y1; + + /* Non degenerate case */ + /* start progressive splitting. This is a greedy, non-optimal + algorithm, but simple and close enough to the best + answer. */ + for(i=2;ireverse_index[i]; + int ln=loneighbor[sortpos]; + int hn=hineighbor[sortpos]; + + /* eliminate repeat searches of a particular range with a memo */ + if(memo[ln]!=hn){ + /* haven't performed this error search yet */ + int lsortpos=look->reverse_index[ln]; + int hsortpos=look->reverse_index[hn]; + memo[ln]=hn; + + { + /* A note: we want to bound/minimize *local*, not global, error */ + int lx=info->postlist[ln]; + int hx=info->postlist[hn]; + int ly=post_Y(fit_valueA,fit_valueB,ln); + int hy=post_Y(fit_valueA,fit_valueB,hn); + + if(ly==-1 || hy==-1){ + exit(1); + } + + if(inspect_error(lx,hx,ly,hy,logmask,logmdct,info)){ + /* outside error bounds/begin search area. Split it. */ + int ly0=-200; + int ly1=-200; + int hy0=-200; + int hy1=-200; + int ret0=fit_line(fits+lsortpos,sortpos-lsortpos,&ly0,&ly1,info); + int ret1=fit_line(fits+sortpos,hsortpos-sortpos,&hy0,&hy1,info); + + if(ret0){ + ly0=ly; + ly1=hy0; + } + if(ret1){ + hy0=ly1; + hy1=hy; + } + + if(ret0 && ret1){ + fit_valueA[i]=-200; + fit_valueB[i]=-200; + }else{ + /* store new edge values */ + fit_valueB[ln]=ly0; + if(ln==0)fit_valueA[ln]=ly0; + fit_valueA[i]=ly1; + fit_valueB[i]=hy0; + fit_valueA[hn]=hy1; + if(hn==1)fit_valueB[hn]=hy1; + + if(ly1>=0 || hy0>=0){ + /* store new neighbor values */ + for(j=sortpos-1;j>=0;j--) + if(hineighbor[j]==hn) + hineighbor[j]=i; + else + break; + for(j=sortpos+1;jloneighbor[i-2]; + int hn=look->hineighbor[i-2]; + int x0=info->postlist[ln]; + int x1=info->postlist[hn]; + int y0=output[ln]; + int y1=output[hn]; + + int predicted=render_point(x0,x1,y0,y1,info->postlist[i]); + int vx=post_Y(fit_valueA,fit_valueB,i); + + if(vx>=0 && predicted!=vx){ + output[i]=vx; + }else{ + output[i]= predicted|0x8000; + } + } + } + + return(output); + +} + +int *floor1_interpolate_fit(vorbis_block *vb,vorbis_look_floor1 *look, + int *A,int *B, + int del){ + + long i; + long posts=look->posts; + int *output=NULL; + + if(A && B){ + output=_vorbis_block_alloc(vb,sizeof(*output)*posts); + + /* overly simpleminded--- look again post 1.2 */ + for(i=0;i>16; + if(A[i]&0x8000 && B[i]&0x8000)output[i]|=0x8000; + } + } + + return(output); +} + + +int floor1_encode(oggpack_buffer *opb,vorbis_block *vb, + vorbis_look_floor1 *look, + int *post,int *ilogmask){ + + long i,j; + vorbis_info_floor1 *info=look->vi; + long posts=look->posts; + codec_setup_info *ci=vb->vd->vi->codec_setup; + int out[VIF_POSIT+2]; + static_codebook **sbooks=ci->book_param; + codebook *books=ci->fullbooks; + + /* quantize values to multiplier spec */ + if(post){ + for(i=0;imult){ + case 1: /* 1024 -> 256 */ + val>>=2; + break; + case 2: /* 1024 -> 128 */ + val>>=3; + break; + case 3: /* 1024 -> 86 */ + val/=12; + break; + case 4: /* 1024 -> 64 */ + val>>=4; + break; + } + post[i]=val | (post[i]&0x8000); + } + + out[0]=post[0]; + out[1]=post[1]; + + /* find prediction values for each post and subtract them */ + for(i=2;iloneighbor[i-2]; + int hn=look->hineighbor[i-2]; + int x0=info->postlist[ln]; + int x1=info->postlist[hn]; + int y0=post[ln]; + int y1=post[hn]; + + int predicted=render_point(x0,x1,y0,y1,info->postlist[i]); + + if((post[i]&0x8000) || (predicted==post[i])){ + post[i]=predicted|0x8000; /* in case there was roundoff jitter + in interpolation */ + out[i]=0; + }else{ + int headroom=(look->quant_q-predictedquant_q-predicted:predicted); + + int val=post[i]-predicted; + + /* at this point the 'deviation' value is in the range +/- max + range, but the real, unique range can always be mapped to + only [0-maxrange). So we want to wrap the deviation into + this limited range, but do it in the way that least screws + an essentially gaussian probability distribution. */ + + if(val<0) + if(val<-headroom) + val=headroom-val-1; + else + val=-1-(val<<1); + else + if(val>=headroom) + val= val+headroom; + else + val<<=1; + + out[i]=val; + post[ln]&=0x7fff; + post[hn]&=0x7fff; + } + } + + /* we have everything we need. pack it out */ + /* mark nontrivial floor */ + oggpack_write(opb,1,1); + + /* beginning/end post */ + look->frames++; + look->postbits+=ov_ilog(look->quant_q-1)*2; + oggpack_write(opb,out[0],ov_ilog(look->quant_q-1)); + oggpack_write(opb,out[1],ov_ilog(look->quant_q-1)); + + + /* partition by partition */ + for(i=0,j=2;ipartitions;i++){ + int class=info->partitionclass[i]; + int cdim=info->class_dim[class]; + int csubbits=info->class_subs[class]; + int csub=1<class_subbook[class][k]; + if(booknum<0){ + maxval[k]=1; + }else{ + maxval[k]=sbooks[info->class_subbook[class][k]]->entries; + } + } + for(k=0;kphrasebits+= + vorbis_book_encode(books+info->class_book[class],cval,opb); + +#ifdef TRAIN_FLOOR1 + { + FILE *of; + char buffer[80]; + sprintf(buffer,"line_%dx%ld_class%d.vqd", + vb->pcmend/2,posts-2,class); + of=fopen(buffer,"a"); + fprintf(of,"%d\n",cval); + fclose(of); + } +#endif + } + + /* write post values */ + for(k=0;kclass_subbook[class][bookas[k]]; + if(book>=0){ + /* hack to allow training with 'bad' books */ + if(out[j+k]<(books+book)->entries) + look->postbits+=vorbis_book_encode(books+book, + out[j+k],opb); + /*else + fprintf(stderr,"+!");*/ + +#ifdef TRAIN_FLOOR1 + { + FILE *of; + char buffer[80]; + sprintf(buffer,"line_%dx%ld_%dsub%d.vqd", + vb->pcmend/2,posts-2,class,bookas[k]); + of=fopen(buffer,"a"); + fprintf(of,"%d\n",out[j+k]); + fclose(of); + } +#endif + } + } + j+=cdim; + } + + { + /* generate quantized floor equivalent to what we'd unpack in decode */ + /* render the lines */ + int hx=0; + int lx=0; + int ly=post[0]*info->mult; + int n=ci->blocksizes[vb->W]/2; + + for(j=1;jposts;j++){ + int current=look->forward_index[j]; + int hy=post[current]&0x7fff; + if(hy==post[current]){ + + hy*=info->mult; + hx=info->postlist[current]; + + render_line0(n,lx,hx,ly,hy,ilogmask); + + lx=hx; + ly=hy; + } + } + for(j=hx;jpcmend/2;j++)ilogmask[j]=ly; /* be certain */ + return(1); + } + }else{ + oggpack_write(opb,0,1); + memset(ilogmask,0,vb->pcmend/2*sizeof(*ilogmask)); + return(0); + } +} + +static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){ + vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; + vorbis_info_floor1 *info=look->vi; + codec_setup_info *ci=vb->vd->vi->codec_setup; + + int i,j,k; + codebook *books=ci->fullbooks; + + /* unpack wrapped/predicted values from stream */ + if(oggpack_read(&vb->opb,1)==1){ + int *fit_value=_vorbis_block_alloc(vb,(look->posts)*sizeof(*fit_value)); + + fit_value[0]=oggpack_read(&vb->opb,ov_ilog(look->quant_q-1)); + fit_value[1]=oggpack_read(&vb->opb,ov_ilog(look->quant_q-1)); + + /* partition by partition */ + for(i=0,j=2;ipartitions;i++){ + int class=info->partitionclass[i]; + int cdim=info->class_dim[class]; + int csubbits=info->class_subs[class]; + int csub=1<class_book[class],&vb->opb); + + if(cval==-1)goto eop; + } + + for(k=0;kclass_subbook[class][cval&(csub-1)]; + cval>>=csubbits; + if(book>=0){ + if((fit_value[j+k]=vorbis_book_decode(books+book,&vb->opb))==-1) + goto eop; + }else{ + fit_value[j+k]=0; + } + } + j+=cdim; + } + + /* unwrap positive values and reconsitute via linear interpolation */ + for(i=2;iposts;i++){ + int predicted=render_point(info->postlist[look->loneighbor[i-2]], + info->postlist[look->hineighbor[i-2]], + fit_value[look->loneighbor[i-2]], + fit_value[look->hineighbor[i-2]], + info->postlist[i]); + int hiroom=look->quant_q-predicted; + int loroom=predicted; + int room=(hiroom=room){ + if(hiroom>loroom){ + val = val-loroom; + }else{ + val = -1-(val-hiroom); + } + }else{ + if(val&1){ + val= -((val+1)>>1); + }else{ + val>>=1; + } + } + + fit_value[i]=(val+predicted)&0x7fff; + fit_value[look->loneighbor[i-2]]&=0x7fff; + fit_value[look->hineighbor[i-2]]&=0x7fff; + + }else{ + fit_value[i]=predicted|0x8000; + } + + } + + return(fit_value); + } + eop: + return(NULL); +} + +static int floor1_inverse2(vorbis_block *vb,vorbis_look_floor *in,void *memo, + float *out){ + vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; + vorbis_info_floor1 *info=look->vi; + + codec_setup_info *ci=vb->vd->vi->codec_setup; + int n=ci->blocksizes[vb->W]/2; + int j; + + if(memo){ + /* render the lines */ + int *fit_value=(int *)memo; + int hx=0; + int lx=0; + int ly=fit_value[0]*info->mult; + /* guard lookup against out-of-range values */ + ly=(ly<0?0:ly>255?255:ly); + + for(j=1;jposts;j++){ + int current=look->forward_index[j]; + int hy=fit_value[current]&0x7fff; + if(hy==fit_value[current]){ + + hx=info->postlist[current]; + hy*=info->mult; + /* guard lookup against out-of-range values */ + hy=(hy<0?0:hy>255?255:hy); + + render_line(n,lx,hx,ly,hy,out); + + lx=hx; + ly=hy; + } + } + for(j=hx;j header packets + + ********************************************************************/ + +/* general handling of the header and the vorbis_info structure (and + substructures) */ + +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "codebook.h" +#include "registry.h" +#include "window.h" +#include "psy.h" +#include "misc.h" +#include "os.h" + +#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){ + + while(bytes--){ + oggpack_write(o,*s++,8); + } +} + +static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ + while(bytes--){ + *buf++=oggpack_read(o,8); + } +} + +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)); +} + +void vorbis_comment_add(vorbis_comment *vc,const char *comment){ + vc->user_comments=_ogg_realloc(vc->user_comments, + (vc->comments+2)*sizeof(*vc->user_comments)); + vc->comment_lengths=_ogg_realloc(vc->comment_lengths, + (vc->comments+2)*sizeof(*vc->comment_lengths)); + vc->comment_lengths[vc->comments]=strlen(comment); + vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1); + strcpy(vc->user_comments[vc->comments], comment); + vc->comments++; + vc->user_comments[vc->comments]=NULL; +} + +void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents){ + /* Length for key and value +2 for = and \0 */ + char *comment=_ogg_malloc(strlen(tag)+strlen(contents)+2); + strcpy(comment, tag); + strcat(comment, "="); + strcat(comment, contents); + vorbis_comment_add(vc, comment); + _ogg_free(comment); +} + +/* This is more or less the same as strncasecmp - but that doesn't exist + * everywhere, and this is a fairly trivial function, so we include it */ +static int tagcompare(const char *s1, const char *s2, int n){ + int c=0; + while(c < n){ + if(_v_toupper(s1[c]) != _v_toupper(s2[c])) + return !0; + c++; + } + return 0; +} + +char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count){ + long i; + int found = 0; + int taglen = strlen(tag)+1; /* +1 for the = we append */ + char *fulltag = _ogg_malloc(taglen+1); + + strcpy(fulltag, tag); + strcat(fulltag, "="); + + for(i=0;icomments;i++){ + if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ + if(count == found) { + /* We return a pointer to the data, not a copy */ + _ogg_free(fulltag); + return vc->user_comments[i] + taglen; + } else { + found++; + } + } + } + _ogg_free(fulltag); + return NULL; /* didn't find anything */ +} + +int vorbis_comment_query_count(vorbis_comment *vc, const char *tag){ + int i,count=0; + int taglen = strlen(tag)+1; /* +1 for the = we append */ + char *fulltag = _ogg_malloc(taglen+1); + strcpy(fulltag,tag); + strcat(fulltag, "="); + + for(i=0;icomments;i++){ + if(!tagcompare(vc->user_comments[i], fulltag, taglen)) + count++; + } + + _ogg_free(fulltag); + return count; +} + +void vorbis_comment_clear(vorbis_comment *vc){ + if(vc){ + long i; + if(vc->user_comments){ + for(i=0;icomments;i++) + if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); + _ogg_free(vc->user_comments); + } + if(vc->comment_lengths)_ogg_free(vc->comment_lengths); + if(vc->vendor)_ogg_free(vc->vendor); + memset(vc,0,sizeof(*vc)); + } +} + +/* blocksize 0 is guaranteed to be short, 1 is guaranteed to be long. + They may be equal, but short will never ge greater than long */ +int vorbis_info_blocksize(vorbis_info *vi,int zo){ + codec_setup_info *ci = vi->codec_setup; + return ci ? ci->blocksizes[zo] : -1; +} + +/* used by synthesis, which has a full, alloced vi */ +void vorbis_info_init(vorbis_info *vi){ + memset(vi,0,sizeof(*vi)); + vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info)); +} + +void vorbis_info_clear(vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + int i; + + if(ci){ + + for(i=0;imodes;i++) + if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); + + for(i=0;imaps;i++) /* unpack does the range checking */ + if(ci->map_param[i]) /* this may be cleaning up an aborted + unpack, in which case the below type + cannot be trusted */ + _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); + + for(i=0;ifloors;i++) /* unpack does the range checking */ + if(ci->floor_param[i]) /* this may be cleaning up an aborted + unpack, in which case the below type + cannot be trusted */ + _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); + + for(i=0;iresidues;i++) /* unpack does the range checking */ + if(ci->residue_param[i]) /* this may be cleaning up an aborted + unpack, in which case the below type + cannot be trusted */ + _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); + + for(i=0;ibooks;i++){ + if(ci->book_param[i]){ + /* knows if the book was not alloced */ + vorbis_staticbook_destroy(ci->book_param[i]); + } + if(ci->fullbooks) + vorbis_book_clear(ci->fullbooks+i); + } + if(ci->fullbooks) + _ogg_free(ci->fullbooks); + + for(i=0;ipsys;i++) + _vi_psy_free(ci->psy_param[i]); + + _ogg_free(ci); + } + + memset(vi,0,sizeof(*vi)); +} + +/* Header packing/unpacking ********************************************/ + +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); + if(vi->version!=0)return(OV_EVERSION); + + vi->channels=oggpack_read(opb,8); + vi->rate=oggpack_read(opb,32); + + vi->bitrate_upper=(ogg_int32_t)oggpack_read(opb,32); + vi->bitrate_nominal=(ogg_int32_t)oggpack_read(opb,32); + vi->bitrate_lower=(ogg_int32_t)oggpack_read(opb,32); + + bs = oggpack_read(opb,4); + if(bs<0)goto err_out; + ci->blocksizes[0]=1<blocksizes[1]=1<rate<1)goto err_out; + if(vi->channels<1)goto err_out; + if(ci->blocksizes[0]<64)goto err_out; + if(ci->blocksizes[1]blocksizes[0])goto err_out; + if(ci->blocksizes[1]>8192)goto err_out; + + if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ + + return(0); + err_out: + vorbis_info_clear(vi); + return(OV_EBADHEADER); +} + +static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ + int i; + int vendorlen=oggpack_read(opb,32); + if(vendorlen<0)goto err_out; + if(vendorlen>opb->storage-8)goto err_out; + vc->vendor=_ogg_calloc(vendorlen+1,1); + _v_readstring(opb,vc->vendor,vendorlen); + i=oggpack_read(opb,32); + if(i<0)goto err_out; + if(i>((opb->storage-oggpack_bytes(opb))>>2))goto err_out; + vc->comments=i; + vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); + vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); + + for(i=0;icomments;i++){ + int len=oggpack_read(opb,32); + if(len<0)goto err_out; + if(len>opb->storage-oggpack_bytes(opb))goto err_out; + vc->comment_lengths[i]=len; + vc->user_comments[i]=_ogg_calloc(len+1,1); + _v_readstring(opb,vc->user_comments[i],len); + } + if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ + + return(0); + err_out: + vorbis_comment_clear(vc); + return(OV_EBADHEADER); +} + +/* all of the real encoding details are here. The modes, books, + everything */ +static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ + codec_setup_info *ci=vi->codec_setup; + int i; + + /* codebooks */ + ci->books=oggpack_read(opb,8)+1; + if(ci->books<=0)goto err_out; + for(i=0;ibooks;i++){ + ci->book_param[i]=vorbis_staticbook_unpack(opb); + if(!ci->book_param[i])goto err_out; + } + + /* time backend settings; hooks are unused */ + { + int times=oggpack_read(opb,6)+1; + if(times<=0)goto err_out; + for(i=0;i=VI_TIMEB)goto err_out; + } + } + + /* floor backend settings */ + ci->floors=oggpack_read(opb,6)+1; + if(ci->floors<=0)goto err_out; + for(i=0;ifloors;i++){ + ci->floor_type[i]=oggpack_read(opb,16); + if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; + ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); + if(!ci->floor_param[i])goto err_out; + } + + /* residue backend settings */ + ci->residues=oggpack_read(opb,6)+1; + if(ci->residues<=0)goto err_out; + for(i=0;iresidues;i++){ + ci->residue_type[i]=oggpack_read(opb,16); + if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; + ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); + if(!ci->residue_param[i])goto err_out; + } + + /* map backend settings */ + ci->maps=oggpack_read(opb,6)+1; + if(ci->maps<=0)goto err_out; + for(i=0;imaps;i++){ + ci->map_type[i]=oggpack_read(opb,16); + if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; + ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); + if(!ci->map_param[i])goto err_out; + } + + /* mode settings */ + ci->modes=oggpack_read(opb,6)+1; + if(ci->modes<=0)goto err_out; + for(i=0;imodes;i++){ + ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i])); + ci->mode_param[i]->blockflag=oggpack_read(opb,1); + ci->mode_param[i]->windowtype=oggpack_read(opb,16); + ci->mode_param[i]->transformtype=oggpack_read(opb,16); + ci->mode_param[i]->mapping=oggpack_read(opb,8); + + if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; + if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; + if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; + if(ci->mode_param[i]->mapping<0)goto err_out; + } + + if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ + + return(0); + err_out: + vorbis_info_clear(vi); + return(OV_EBADHEADER); +} + +/* Is this packet a vorbis ID header? */ +int vorbis_synthesis_idheader(ogg_packet *op){ + oggpack_buffer opb; + char buffer[6]; + + if(op){ + oggpack_readinit(&opb,op->packet,op->bytes); + + if(!op->b_o_s) + return(0); /* Not the initial packet */ + + if(oggpack_read(&opb,8) != 1) + return 0; /* not an ID header */ + + memset(buffer,0,6); + _v_readstring(&opb,buffer,6); + if(memcmp(buffer,"vorbis",6)) + return 0; /* not vorbis */ + + return 1; + } + + return 0; +} + +/* The Vorbis header is in three packets; the initial small packet in + the first page that identifies basic parameters, a second packet + with bitstream comments and a third packet that holds the + codebook. */ + +int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ + oggpack_buffer opb; + + if(op){ + oggpack_readinit(&opb,op->packet,op->bytes); + + /* Which of the three types of header is this? */ + /* Also verify header-ness, vorbis */ + { + char buffer[6]; + int packtype=oggpack_read(&opb,8); + memset(buffer,0,6); + _v_readstring(&opb,buffer,6); + if(memcmp(buffer,"vorbis",6)){ + /* not a vorbis header */ + return(OV_ENOTVORBIS); + } + switch(packtype){ + case 0x01: /* least significant *bit* is read first */ + if(!op->b_o_s){ + /* Not the initial packet */ + return(OV_EBADHEADER); + } + if(vi->rate!=0){ + /* previously initialized info header */ + return(OV_EBADHEADER); + } + + return(_vorbis_unpack_info(vi,&opb)); + + case 0x03: /* least significant *bit* is read first */ + if(vi->rate==0){ + /* um... we didn't get the initial header */ + return(OV_EBADHEADER); + } + if(vc->vendor!=NULL){ + /* previously initialized comment header */ + return(OV_EBADHEADER); + } + + return(_vorbis_unpack_comment(vc,&opb)); + + case 0x05: /* least significant *bit* is read first */ + if(vi->rate==0 || vc->vendor==NULL){ + /* um... we didn;t get the initial header or comments yet */ + return(OV_EBADHEADER); + } + if(vi->codec_setup==NULL){ + /* improperly initialized vorbis_info */ + return(OV_EFAULT); + } + if(((codec_setup_info *)vi->codec_setup)->books>0){ + /* previously initialized setup header */ + return(OV_EBADHEADER); + } + + return(_vorbis_unpack_books(vi,&opb)); + + default: + /* Not a valid vorbis header type */ + return(OV_EBADHEADER); + break; + } + } + } + return(OV_EBADHEADER); +} + +/* pack side **********************************************************/ + +static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + if(!ci|| + ci->blocksizes[0]<64|| + ci->blocksizes[1]blocksizes[0]){ + return(OV_EFAULT); + } + + /* preamble */ + oggpack_write(opb,0x01,8); + _v_writestring(opb,"vorbis", 6); + + /* basic information about the stream */ + oggpack_write(opb,0x00,32); + oggpack_write(opb,vi->channels,8); + oggpack_write(opb,vi->rate,32); + + oggpack_write(opb,vi->bitrate_upper,32); + oggpack_write(opb,vi->bitrate_nominal,32); + oggpack_write(opb,vi->bitrate_lower,32); + + oggpack_write(opb,ov_ilog(ci->blocksizes[0]-1),4); + oggpack_write(opb,ov_ilog(ci->blocksizes[1]-1),4); + oggpack_write(opb,1,1); + + return(0); +} + +static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){ + int bytes = strlen(ENCODE_VENDOR_STRING); + + /* preamble */ + oggpack_write(opb,0x03,8); + _v_writestring(opb,"vorbis", 6); + + /* vendor */ + oggpack_write(opb,bytes,32); + _v_writestring(opb,ENCODE_VENDOR_STRING, bytes); + + /* comments */ + + oggpack_write(opb,vc->comments,32); + if(vc->comments){ + int i; + for(i=0;icomments;i++){ + if(vc->user_comments[i]){ + oggpack_write(opb,vc->comment_lengths[i],32); + _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]); + }else{ + oggpack_write(opb,0,32); + } + } + } + oggpack_write(opb,1,1); + + return(0); +} + +static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + int i; + if(!ci)return(OV_EFAULT); + + oggpack_write(opb,0x05,8); + _v_writestring(opb,"vorbis", 6); + + /* books */ + oggpack_write(opb,ci->books-1,8); + for(i=0;ibooks;i++) + if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out; + + /* times; hook placeholders */ + oggpack_write(opb,0,6); + oggpack_write(opb,0,16); + + /* floors */ + oggpack_write(opb,ci->floors-1,6); + for(i=0;ifloors;i++){ + oggpack_write(opb,ci->floor_type[i],16); + if(_floor_P[ci->floor_type[i]]->pack) + _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb); + else + goto err_out; + } + + /* residues */ + oggpack_write(opb,ci->residues-1,6); + for(i=0;iresidues;i++){ + oggpack_write(opb,ci->residue_type[i],16); + _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb); + } + + /* maps */ + oggpack_write(opb,ci->maps-1,6); + for(i=0;imaps;i++){ + oggpack_write(opb,ci->map_type[i],16); + _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb); + } + + /* modes */ + oggpack_write(opb,ci->modes-1,6); + for(i=0;imodes;i++){ + oggpack_write(opb,ci->mode_param[i]->blockflag,1); + oggpack_write(opb,ci->mode_param[i]->windowtype,16); + oggpack_write(opb,ci->mode_param[i]->transformtype,16); + oggpack_write(opb,ci->mode_param[i]->mapping,8); + } + oggpack_write(opb,1,1); + + return(0); +err_out: + return(-1); +} + +int vorbis_commentheader_out(vorbis_comment *vc, + ogg_packet *op){ + + oggpack_buffer opb; + + oggpack_writeinit(&opb); + if(_vorbis_pack_comment(&opb,vc)){ + oggpack_writeclear(&opb); + return OV_EIMPL; + } + + op->packet = _ogg_malloc(oggpack_bytes(&opb)); + memcpy(op->packet, opb.buffer, oggpack_bytes(&opb)); + + op->bytes=oggpack_bytes(&opb); + op->b_o_s=0; + op->e_o_s=0; + op->granulepos=0; + op->packetno=1; + + oggpack_writeclear(&opb); + return 0; +} + +int vorbis_analysis_headerout(vorbis_dsp_state *v, + vorbis_comment *vc, + ogg_packet *op, + ogg_packet *op_comm, + ogg_packet *op_code){ + int ret=OV_EIMPL; + vorbis_info *vi=v->vi; + oggpack_buffer opb; + private_state *b=v->backend_state; + + if(!b||vi->channels<=0||vi->channels>256){ + b = NULL; + ret=OV_EFAULT; + goto err_out; + } + + /* first header packet **********************************************/ + + oggpack_writeinit(&opb); + if(_vorbis_pack_info(&opb,vi))goto err_out; + + /* build the packet */ + if(b->header)_ogg_free(b->header); + b->header=_ogg_malloc(oggpack_bytes(&opb)); + memcpy(b->header,opb.buffer,oggpack_bytes(&opb)); + op->packet=b->header; + op->bytes=oggpack_bytes(&opb); + op->b_o_s=1; + op->e_o_s=0; + op->granulepos=0; + op->packetno=0; + + /* second header packet (comments) **********************************/ + + oggpack_reset(&opb); + if(_vorbis_pack_comment(&opb,vc))goto err_out; + + if(b->header1)_ogg_free(b->header1); + b->header1=_ogg_malloc(oggpack_bytes(&opb)); + memcpy(b->header1,opb.buffer,oggpack_bytes(&opb)); + op_comm->packet=b->header1; + op_comm->bytes=oggpack_bytes(&opb); + op_comm->b_o_s=0; + op_comm->e_o_s=0; + op_comm->granulepos=0; + op_comm->packetno=1; + + /* third header packet (modes/codebooks) ****************************/ + + oggpack_reset(&opb); + if(_vorbis_pack_books(&opb,vi))goto err_out; + + if(b->header2)_ogg_free(b->header2); + b->header2=_ogg_malloc(oggpack_bytes(&opb)); + memcpy(b->header2,opb.buffer,oggpack_bytes(&opb)); + op_code->packet=b->header2; + op_code->bytes=oggpack_bytes(&opb); + op_code->b_o_s=0; + op_code->e_o_s=0; + op_code->granulepos=0; + op_code->packetno=2; + + oggpack_writeclear(&opb); + return(0); + err_out: + memset(op,0,sizeof(*op)); + memset(op_comm,0,sizeof(*op_comm)); + memset(op_code,0,sizeof(*op_code)); + + if(b){ + if(vi->channels>0)oggpack_writeclear(&opb); + if(b->header)_ogg_free(b->header); + if(b->header1)_ogg_free(b->header1); + if(b->header2)_ogg_free(b->header2); + b->header=NULL; + b->header1=NULL; + b->header2=NULL; + } + return(ret); +} + +double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){ + if(granulepos == -1) return -1; + + /* We're not guaranteed a 64 bit unsigned type everywhere, so we + have to put the unsigned granpo in a signed type. */ + if(granulepos>=0){ + return((double)granulepos/v->vi->rate); + }else{ + ogg_int64_t granuleoff=0xffffffff; + granuleoff<<=31; + granuleoff|=0x7ffffffff; + return(((double)granulepos+2+granuleoff+granuleoff)/v->vi->rate); + } +} + +const char *vorbis_version_string(void){ + return GENERAL_VENDOR_STRING; +} diff --git a/vendor/vorbis/lib/lookup.c b/vendor/vorbis/lib/lookup.c new file mode 100644 index 0000000..7cd01a4 --- /dev/null +++ b/vendor/vorbis/lib/lookup.c @@ -0,0 +1,93 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: lookup based functions + + ********************************************************************/ + +#include +#include "lookup.h" +#include "lookup_data.h" +#include "os.h" +#include "misc.h" + +#ifdef FLOAT_LOOKUP + +/* interpolated lookup based cos function, domain 0 to PI only */ +float vorbis_coslook(float a){ + double d=a*(.31830989*(float)COS_LOOKUP_SZ); + int i=vorbis_ftoi(d-.5); + + return COS_LOOKUP[i]+ (d-i)*(COS_LOOKUP[i+1]-COS_LOOKUP[i]); +} + +/* interpolated 1./sqrt(p) where .5 <= p < 1. */ +float vorbis_invsqlook(float a){ + double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ; + int i=vorbis_ftoi(d-.5f); + return INVSQ_LOOKUP[i]+ (d-i)*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]); +} + +/* interpolated 1./sqrt(p) where .5 <= p < 1. */ +float vorbis_invsq2explook(int a){ + return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN]; +} + +#include +/* interpolated lookup based fromdB function, domain -140dB to 0dB only */ +float vorbis_fromdBlook(float a){ + int i=vorbis_ftoi(a*((float)(-(1<=(FROMdB_LOOKUP_SZ<>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]); +} + +#endif + +#ifdef INT_LOOKUP +/* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in + 16.16 format + + returns in m.8 format */ +long vorbis_invsqlook_i(long a,long e){ + long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1); + long d=(a&INVSQ_LOOKUP_I_MASK)<<(16-INVSQ_LOOKUP_I_SHIFT); /* 0.16 */ + long val=INVSQ_LOOKUP_I[i]- /* 1.16 */ + (((INVSQ_LOOKUP_I[i]-INVSQ_LOOKUP_I[i+1])* /* 0.16 */ + d)>>16); /* result 1.16 */ + + e+=32; + if(e&1)val=(val*5792)>>13; /* multiply val by 1/sqrt(2) */ + e=(e>>1)-8; + + return(val>>e); +} + +/* interpolated lookup based fromdB function, domain -140dB to 0dB only */ +/* a is in n.12 format */ +float vorbis_fromdBlook_i(long a){ + int i=(-a)>>(12-FROMdB2_SHIFT); + return (i<0)?1.f: + ((i>=(FROMdB_LOOKUP_SZ<>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]); +} + +/* interpolated lookup based cos function, domain 0 to PI only */ +/* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */ +long vorbis_coslook_i(long a){ + int i=a>>COS_LOOKUP_I_SHIFT; + int d=a&COS_LOOKUP_I_MASK; + return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>> + COS_LOOKUP_I_SHIFT); +} + +#endif diff --git a/vendor/vorbis/lib/lookup.h b/vendor/vorbis/lib/lookup.h new file mode 100644 index 0000000..ec05014 --- /dev/null +++ b/vendor/vorbis/lib/lookup.h @@ -0,0 +1,31 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: lookup based functions + + ********************************************************************/ + +#ifndef _V_LOOKUP_H_ + +#ifdef FLOAT_LOOKUP +extern float vorbis_coslook(float a); +extern float vorbis_invsqlook(float a); +extern float vorbis_invsq2explook(int a); +extern float vorbis_fromdBlook(float a); +#endif +#ifdef INT_LOOKUP +extern long vorbis_invsqlook_i(long a,long e); +extern long vorbis_coslook_i(long a); +extern float vorbis_fromdBlook_i(long a); +#endif + +#endif diff --git a/vendor/vorbis/lib/lookup_data.h b/vendor/vorbis/lib/lookup_data.h new file mode 100644 index 0000000..7935715 --- /dev/null +++ b/vendor/vorbis/lib/lookup_data.h @@ -0,0 +1,191 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: lookup data; generated by lookups.pl; edit there + + ********************************************************************/ + +#ifndef _V_LOOKUP_DATA_H_ + +#ifdef FLOAT_LOOKUP +#define COS_LOOKUP_SZ 128 +static const float COS_LOOKUP[COS_LOOKUP_SZ+1]={ + +1.0000000000000f,+0.9996988186962f,+0.9987954562052f,+0.9972904566787f, + +0.9951847266722f,+0.9924795345987f,+0.9891765099648f,+0.9852776423889f, + +0.9807852804032f,+0.9757021300385f,+0.9700312531945f,+0.9637760657954f, + +0.9569403357322f,+0.9495281805930f,+0.9415440651830f,+0.9329927988347f, + +0.9238795325113f,+0.9142097557035f,+0.9039892931234f,+0.8932243011955f, + +0.8819212643484f,+0.8700869911087f,+0.8577286100003f,+0.8448535652497f, + +0.8314696123025f,+0.8175848131516f,+0.8032075314806f,+0.7883464276266f, + +0.7730104533627f,+0.7572088465065f,+0.7409511253550f,+0.7242470829515f, + +0.7071067811865f,+0.6895405447371f,+0.6715589548470f,+0.6531728429538f, + +0.6343932841636f,+0.6152315905806f,+0.5956993044924f,+0.5758081914178f, + +0.5555702330196f,+0.5349976198871f,+0.5141027441932f,+0.4928981922298f, + +0.4713967368260f,+0.4496113296546f,+0.4275550934303f,+0.4052413140050f, + +0.3826834323651f,+0.3598950365350f,+0.3368898533922f,+0.3136817403989f, + +0.2902846772545f,+0.2667127574749f,+0.2429801799033f,+0.2191012401569f, + +0.1950903220161f,+0.1709618887603f,+0.1467304744554f,+0.1224106751992f, + +0.0980171403296f,+0.0735645635997f,+0.0490676743274f,+0.0245412285229f, + +0.0000000000000f,-0.0245412285229f,-0.0490676743274f,-0.0735645635997f, + -0.0980171403296f,-0.1224106751992f,-0.1467304744554f,-0.1709618887603f, + -0.1950903220161f,-0.2191012401569f,-0.2429801799033f,-0.2667127574749f, + -0.2902846772545f,-0.3136817403989f,-0.3368898533922f,-0.3598950365350f, + -0.3826834323651f,-0.4052413140050f,-0.4275550934303f,-0.4496113296546f, + -0.4713967368260f,-0.4928981922298f,-0.5141027441932f,-0.5349976198871f, + -0.5555702330196f,-0.5758081914178f,-0.5956993044924f,-0.6152315905806f, + -0.6343932841636f,-0.6531728429538f,-0.6715589548470f,-0.6895405447371f, + -0.7071067811865f,-0.7242470829515f,-0.7409511253550f,-0.7572088465065f, + -0.7730104533627f,-0.7883464276266f,-0.8032075314806f,-0.8175848131516f, + -0.8314696123025f,-0.8448535652497f,-0.8577286100003f,-0.8700869911087f, + -0.8819212643484f,-0.8932243011955f,-0.9039892931234f,-0.9142097557035f, + -0.9238795325113f,-0.9329927988347f,-0.9415440651830f,-0.9495281805930f, + -0.9569403357322f,-0.9637760657954f,-0.9700312531945f,-0.9757021300385f, + -0.9807852804032f,-0.9852776423889f,-0.9891765099648f,-0.9924795345987f, + -0.9951847266722f,-0.9972904566787f,-0.9987954562052f,-0.9996988186962f, + -1.0000000000000f, +}; + +#define INVSQ_LOOKUP_SZ 32 +static const float INVSQ_LOOKUP[INVSQ_LOOKUP_SZ+1]={ + 1.414213562373f,1.392621247646f,1.371988681140f,1.352246807566f, + 1.333333333333f,1.315191898443f,1.297771369046f,1.281025230441f, + 1.264911064067f,1.249390095109f,1.234426799697f,1.219988562661f, + 1.206045378311f,1.192569588000f,1.179535649239f,1.166919931983f, + 1.154700538379f,1.142857142857f,1.131370849898f,1.120224067222f, + 1.109400392450f,1.098884511590f,1.088662107904f,1.078719779941f, + 1.069044967650f,1.059625885652f,1.050451462878f,1.041511287847f, + 1.032795558989f,1.024295039463f,1.016001016002f,1.007905261358f, + 1.000000000000f, +}; + +#define INVSQ2EXP_LOOKUP_MIN (-32) +#define INVSQ2EXP_LOOKUP_MAX 32 +static const float INVSQ2EXP_LOOKUP[INVSQ2EXP_LOOKUP_MAX-\ + INVSQ2EXP_LOOKUP_MIN+1]={ + 65536.f, 46340.95001f, 32768.f, 23170.47501f, + 16384.f, 11585.2375f, 8192.f, 5792.618751f, + 4096.f, 2896.309376f, 2048.f, 1448.154688f, + 1024.f, 724.0773439f, 512.f, 362.038672f, + 256.f, 181.019336f, 128.f, 90.50966799f, + 64.f, 45.254834f, 32.f, 22.627417f, + 16.f, 11.3137085f, 8.f, 5.656854249f, + 4.f, 2.828427125f, 2.f, 1.414213562f, + 1.f, 0.7071067812f, 0.5f, 0.3535533906f, + 0.25f, 0.1767766953f, 0.125f, 0.08838834765f, + 0.0625f, 0.04419417382f, 0.03125f, 0.02209708691f, + 0.015625f, 0.01104854346f, 0.0078125f, 0.005524271728f, + 0.00390625f, 0.002762135864f, 0.001953125f, 0.001381067932f, + 0.0009765625f, 0.000690533966f, 0.00048828125f, 0.000345266983f, + 0.000244140625f,0.0001726334915f,0.0001220703125f,8.631674575e-05f, + 6.103515625e-05f,4.315837288e-05f,3.051757812e-05f,2.157918644e-05f, + 1.525878906e-05f, +}; + +#endif + +#define FROMdB_LOOKUP_SZ 35 +#define FROMdB2_LOOKUP_SZ 32 +#define FROMdB_SHIFT 5 +#define FROMdB2_SHIFT 3 +#define FROMdB2_MASK 31 + +#ifdef FLOAT_LOOKUP +static const float FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={ + 1.f, 0.6309573445f, 0.3981071706f, 0.2511886432f, + 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f, + 0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f, + 0.003981071706f, 0.002511886432f, 0.001584893192f, 0.001f, + 0.0006309573445f,0.0003981071706f,0.0002511886432f,0.0001584893192f, + 0.0001f,6.309573445e-05f,3.981071706e-05f,2.511886432e-05f, + 1.584893192e-05f, 1e-05f,6.309573445e-06f,3.981071706e-06f, + 2.511886432e-06f,1.584893192e-06f, 1e-06f,6.309573445e-07f, + 3.981071706e-07f,2.511886432e-07f,1.584893192e-07f, +}; + +static const float FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={ + 0.9928302478f, 0.9786445908f, 0.9646616199f, 0.9508784391f, + 0.9372921937f, 0.92390007f, 0.9106992942f, 0.8976871324f, + 0.8848608897f, 0.8722179097f, 0.8597555737f, 0.8474713009f, + 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f, + 0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f, + 0.7445176537f, 0.7338799116f, 0.7233941627f, 0.7130582353f, + 0.7028699885f, 0.6928273125f, 0.6829281272f, 0.6731703824f, + 0.6635520573f, 0.6540711597f, 0.6447257262f, 0.6355138211f, +}; +#endif + +#ifdef INT_LOOKUP + +#define INVSQ_LOOKUP_I_SHIFT 10 +#define INVSQ_LOOKUP_I_MASK 1023 +static const long INVSQ_LOOKUP_I[64+1]={ + 92682l, 91966l, 91267l, 90583l, + 89915l, 89261l, 88621l, 87995l, + 87381l, 86781l, 86192l, 85616l, + 85051l, 84497l, 83953l, 83420l, + 82897l, 82384l, 81880l, 81385l, + 80899l, 80422l, 79953l, 79492l, + 79039l, 78594l, 78156l, 77726l, + 77302l, 76885l, 76475l, 76072l, + 75674l, 75283l, 74898l, 74519l, + 74146l, 73778l, 73415l, 73058l, + 72706l, 72359l, 72016l, 71679l, + 71347l, 71019l, 70695l, 70376l, + 70061l, 69750l, 69444l, 69141l, + 68842l, 68548l, 68256l, 67969l, + 67685l, 67405l, 67128l, 66855l, + 66585l, 66318l, 66054l, 65794l, + 65536l, +}; + +#define COS_LOOKUP_I_SHIFT 9 +#define COS_LOOKUP_I_MASK 511 +#define COS_LOOKUP_I_SZ 128 +static const long COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={ + 16384l, 16379l, 16364l, 16340l, + 16305l, 16261l, 16207l, 16143l, + 16069l, 15986l, 15893l, 15791l, + 15679l, 15557l, 15426l, 15286l, + 15137l, 14978l, 14811l, 14635l, + 14449l, 14256l, 14053l, 13842l, + 13623l, 13395l, 13160l, 12916l, + 12665l, 12406l, 12140l, 11866l, + 11585l, 11297l, 11003l, 10702l, + 10394l, 10080l, 9760l, 9434l, + 9102l, 8765l, 8423l, 8076l, + 7723l, 7366l, 7005l, 6639l, + 6270l, 5897l, 5520l, 5139l, + 4756l, 4370l, 3981l, 3590l, + 3196l, 2801l, 2404l, 2006l, + 1606l, 1205l, 804l, 402l, + 0l, -401l, -803l, -1204l, + -1605l, -2005l, -2403l, -2800l, + -3195l, -3589l, -3980l, -4369l, + -4755l, -5138l, -5519l, -5896l, + -6269l, -6638l, -7004l, -7365l, + -7722l, -8075l, -8422l, -8764l, + -9101l, -9433l, -9759l, -10079l, + -10393l, -10701l, -11002l, -11296l, + -11584l, -11865l, -12139l, -12405l, + -12664l, -12915l, -13159l, -13394l, + -13622l, -13841l, -14052l, -14255l, + -14448l, -14634l, -14810l, -14977l, + -15136l, -15285l, -15425l, -15556l, + -15678l, -15790l, -15892l, -15985l, + -16068l, -16142l, -16206l, -16260l, + -16304l, -16339l, -16363l, -16378l, + -16383l, +}; + +#endif + +#endif diff --git a/vendor/vorbis/lib/lookups.pl b/vendor/vorbis/lib/lookups.pl new file mode 100644 index 0000000..87e2cad --- /dev/null +++ b/vendor/vorbis/lib/lookups.pl @@ -0,0 +1,141 @@ +#!/usr/bin/perl +print <<'EOD'; +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: lookup data; generated by lookups.pl; edit there + + ********************************************************************/ + +#ifndef _V_LOOKUP_DATA_H_ + +#ifdef FLOAT_LOOKUP +EOD + +$cos_sz=128; +$invsq_sz=32; +$invsq2exp_min=-32; +$invsq2exp_max=32; + +$fromdB_sz=35; +$fromdB_shift=5; +$fromdB2_shift=3; + +$invsq_i_shift=10; +$cos_i_shift=9; +$delta_shift=6; + +print "#define COS_LOOKUP_SZ $cos_sz\n"; +print "static float COS_LOOKUP[COS_LOOKUP_SZ+1]={\n"; + +for($i=0;$i<=$cos_sz;){ + print "\t"; + for($j=0;$j<4 && $i<=$cos_sz;$j++){ + printf "%+.13f,", cos(3.14159265358979323846*($i++)/$cos_sz) ; + } + print "\n"; +} +print "};\n\n"; + +print "#define INVSQ_LOOKUP_SZ $invsq_sz\n"; +print "static float INVSQ_LOOKUP[INVSQ_LOOKUP_SZ+1]={\n"; + +for($i=0;$i<=$invsq_sz;){ + print "\t"; + for($j=0;$j<4 && $i<=$invsq_sz;$j++){ + my$indexmap=$i++/$invsq_sz*.5+.5; + printf "%.12f,", 1./sqrt($indexmap); + } + print "\n"; +} +print "};\n\n"; + +print "#define INVSQ2EXP_LOOKUP_MIN $invsq2exp_min\n"; +print "#define INVSQ2EXP_LOOKUP_MAX $invsq2exp_max\n"; +print "static float INVSQ2EXP_LOOKUP[INVSQ2EXP_LOOKUP_MAX-\\\n". + " INVSQ2EXP_LOOKUP_MIN+1]={\n"; + +for($i=$invsq2exp_min;$i<=$invsq2exp_max;){ + print "\t"; + for($j=0;$j<4 && $i<=$invsq2exp_max;$j++){ + printf "%15.10g,", 2**($i++*-.5); + } + print "\n"; +} +print "};\n\n#endif\n\n"; + + +# 0 to -140 dB +$fromdB2_sz=1<<$fromdB_shift; +$fromdB_gran=1<<($fromdB_shift-$fromdB2_shift); +print "#define FROMdB_LOOKUP_SZ $fromdB_sz\n"; +print "#define FROMdB2_LOOKUP_SZ $fromdB2_sz\n"; +print "#define FROMdB_SHIFT $fromdB_shift\n"; +print "#define FROMdB2_SHIFT $fromdB2_shift\n"; +print "#define FROMdB2_MASK ".((1<<$fromdB_shift)-1)."\n"; + +print "static float FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={\n"; + +for($i=0;$i<$fromdB_sz;){ + print "\t"; + for($j=0;$j<4 && $i<$fromdB_sz;$j++){ + printf "%15.10g,", 10**(.05*(-$fromdB_gran*$i++)); + } + print "\n"; +} +print "};\n\n"; + +print "static float FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={\n"; + +for($i=0;$i<$fromdB2_sz;){ + print "\t"; + for($j=0;$j<4 && $i<$fromdB_sz;$j++){ + printf "%15.10g,", 10**(.05*(-$fromdB_gran/$fromdB2_sz*(.5+$i++))); + } + print "\n"; +} +print "};\n\n#ifdef INT_LOOKUP\n\n"; + + +$iisz=0x10000>>$invsq_i_shift; +print "#define INVSQ_LOOKUP_I_SHIFT $invsq_i_shift\n"; +print "#define INVSQ_LOOKUP_I_MASK ".(0x0ffff>>(16-$invsq_i_shift))."\n"; +print "static long INVSQ_LOOKUP_I[$iisz+1]={\n"; +for($i=0;$i<=$iisz;){ + print "\t"; + for($j=0;$j<4 && $i<=$iisz;$j++){ + my$indexmap=$i++/$iisz*.5+.5; + printf "%8d,", int(1./sqrt($indexmap)*65536.+.5); + } + print "\n"; +} +print "};\n\n"; + +$cisz=0x10000>>$cos_i_shift; +print "#define COS_LOOKUP_I_SHIFT $cos_i_shift\n"; +print "#define COS_LOOKUP_I_MASK ".(0x0ffff>>(16-$cos_i_shift))."\n"; +print "#define COS_LOOKUP_I_SZ $cisz\n"; +print "static long COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={\n"; + +for($i=0;$i<=$cisz;){ + print "\t"; + for($j=0;$j<4 && $i<=$cisz;$j++){ + printf "%8d,", int(cos(3.14159265358979323846*($i++)/$cos_sz)*16384.+.5) ; + } + print "\n"; +} +print "};\n\n"; + + +print "#endif\n\n#endif\n"; + + diff --git a/vendor/vorbis/lib/lpc.c b/vendor/vorbis/lib/lpc.c new file mode 100644 index 0000000..877da47 --- /dev/null +++ b/vendor/vorbis/lib/lpc.c @@ -0,0 +1,159 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: LPC low level routines + + ********************************************************************/ + +/* Some of these routines (autocorrelator, LPC coefficient estimator) + are derived from code written by Jutta Degener and Carsten Bormann; + thus we include their copyright below. The entirety of this file + is freely redistributable on the condition that both of these + copyright notices are preserved without modification. */ + +/* Preserved Copyright: *********************************************/ + +/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universita"t Berlin + +Any use of this software is permitted provided that this notice is not +removed and that neither the authors nor the Technische Universita"t +Berlin are deemed to have made any representations as to the +suitability of this software for any purpose nor are held responsible +for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR +THIS SOFTWARE. + +As a matter of courtesy, the authors request to be informed about uses +this software has found, about bugs in this software, and about any +improvements that may be of general interest. + +Berlin, 28.11.1994 +Jutta Degener +Carsten Bormann + +*********************************************************************/ + +#include +#include +#include +#include "os.h" +#include "smallft.h" +#include "lpc.h" +#include "scales.h" +#include "misc.h" + +/* Autocorrelation LPC coeff generation algorithm invented by + N. Levinson in 1947, modified by J. Durbin in 1959. */ + +/* Input : n elements of time doamin data + Output: m lpc coefficients, excitation energy */ + +float vorbis_lpc_from_data(float *data,float *lpci,int n,int m){ + double *aut=alloca(sizeof(*aut)*(m+1)); + double *lpc=alloca(sizeof(*lpc)*(m)); + double error; + double epsilon; + int i,j; + + /* autocorrelation, p+1 lag coefficients */ + j=m+1; + while(j--){ + double d=0; /* double needed for accumulator depth */ + for(i=j;i +#include +#include +#include "lsp.h" +#include "os.h" +#include "misc.h" +#include "lookup.h" +#include "scales.h" + +/* three possible LSP to f curve functions; the exact computation + (float), a lookup based float implementation, and an integer + implementation. The float lookup is likely the optimal choice on + any machine with an FPU. The integer implementation is *not* fixed + point (due to the need for a large dynamic range and thus a + separately tracked exponent) and thus much more complex than the + relatively simple float implementations. It's mostly for future + work on a fully fixed point implementation for processors like the + ARM family. */ + +/* define either of these (preferably FLOAT_LOOKUP) to have faster + but less precise implementation. */ +#undef FLOAT_LOOKUP +#undef INT_LOOKUP + +#ifdef FLOAT_LOOKUP +#include "lookup.c" /* catch this in the build system; we #include for + compilers (like gcc) that can't inline across + modules */ + +/* side effect: changes *lsp to cosines of lsp */ +void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m, + float amp,float ampoffset){ + int i; + float wdel=M_PI/ln; + vorbis_fpu_control fpu; + + vorbis_fpu_setround(&fpu); + for(i=0;i>1; + + while(c--){ + q*=ftmp[0]-w; + p*=ftmp[1]-w; + ftmp+=2; + } + + if(m&1){ + /* odd order filter; slightly assymetric */ + /* the last coefficient */ + q*=ftmp[0]-w; + q*=q; + p*=p*(1.f-w*w); + }else{ + /* even order filter; still symmetric */ + q*=q*(1.f+w); + p*=p*(1.f-w); + } + + q=frexp(p+q,&qexp); + q=vorbis_fromdBlook(amp* + vorbis_invsqlook(q)* + vorbis_invsq2explook(qexp+m)- + ampoffset); + + do{ + curve[i++]*=q; + }while(map[i]==k); + } + vorbis_fpu_restore(fpu); +} + +#else + +#ifdef INT_LOOKUP +#include "lookup.c" /* catch this in the build system; we #include for + compilers (like gcc) that can't inline across + modules */ + +static const int MLOOP_1[64]={ + 0,10,11,11, 12,12,12,12, 13,13,13,13, 13,13,13,13, + 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, +}; + +static const int MLOOP_2[64]={ + 0,4,5,5, 6,6,6,6, 7,7,7,7, 7,7,7,7, + 8,8,8,8, 8,8,8,8, 8,8,8,8, 8,8,8,8, + 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, +}; + +static const int MLOOP_3[8]={0,1,2,2,3,3,3,3}; + + +/* side effect: changes *lsp to cosines of lsp */ +void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m, + float amp,float ampoffset){ + + /* 0 <= m < 256 */ + + /* set up for using all int later */ + int i; + int ampoffseti=rint(ampoffset*4096.f); + int ampi=rint(amp*16.f); + long *ilsp=alloca(m*sizeof(*ilsp)); + for(i=0;i>25])) + if(!(shift=MLOOP_2[(pi|qi)>>19])) + shift=MLOOP_3[(pi|qi)>>16]; + qi=(qi>>shift)*labs(ilsp[j-1]-wi); + pi=(pi>>shift)*labs(ilsp[j]-wi); + qexp+=shift; + } + if(!(shift=MLOOP_1[(pi|qi)>>25])) + if(!(shift=MLOOP_2[(pi|qi)>>19])) + shift=MLOOP_3[(pi|qi)>>16]; + + /* pi,qi normalized collectively, both tracked using qexp */ + + if(m&1){ + /* odd order filter; slightly assymetric */ + /* the last coefficient */ + qi=(qi>>shift)*labs(ilsp[j-1]-wi); + pi=(pi>>shift)<<14; + qexp+=shift; + + if(!(shift=MLOOP_1[(pi|qi)>>25])) + if(!(shift=MLOOP_2[(pi|qi)>>19])) + shift=MLOOP_3[(pi|qi)>>16]; + + pi>>=shift; + qi>>=shift; + qexp+=shift-14*((m+1)>>1); + + pi=((pi*pi)>>16); + qi=((qi*qi)>>16); + qexp=qexp*2+m; + + pi*=(1<<14)-((wi*wi)>>14); + qi+=pi>>14; + + }else{ + /* even order filter; still symmetric */ + + /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't + worth tracking step by step */ + + pi>>=shift; + qi>>=shift; + qexp+=shift-7*m; + + pi=((pi*pi)>>16); + qi=((qi*qi)>>16); + qexp=qexp*2+m; + + pi*=(1<<14)-wi; + qi*=(1<<14)+wi; + qi=(qi+pi)>>14; + + } + + + /* we've let the normalization drift because it wasn't important; + however, for the lookup, things must be normalized again. We + need at most one right shift or a number of left shifts */ + + if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */ + qi>>=1; qexp++; + }else + while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/ + qi<<=1; qexp--; + } + + amp=vorbis_fromdBlook_i(ampi* /* n.4 */ + vorbis_invsqlook_i(qi,qexp)- + /* m.8, m+n<=8 */ + ampoffseti); /* 8.12[0] */ + + curve[i]*=amp; + while(map[++i]==k)curve[i]*=amp; + } +} + +#else + +/* old, nonoptimized but simple version for any poor sap who needs to + figure out what the hell this code does, or wants the other + fraction of a dB precision */ + +/* side effect: changes *lsp to cosines of lsp */ +void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m, + float amp,float ampoffset){ + int i; + float wdel=M_PI/ln; + for(i=0;i= i; j--) { + g[j-2] -= g[j]; + g[j] += g[j]; + } + } +} + +static int comp(const void *a,const void *b){ + return (*(float *)a<*(float *)b)-(*(float *)a>*(float *)b); +} + +/* Newton-Raphson-Maehly actually functioned as a decent root finder, + but there are root sets for which it gets into limit cycles + (exacerbated by zero suppression) and fails. We can't afford to + fail, even if the failure is 1 in 100,000,000, so we now use + Laguerre and later polish with Newton-Raphson (which can then + afford to fail) */ + +#define EPSILON 10e-7 +static int Laguerre_With_Deflation(float *a,int ord,float *r){ + int i,m; + double *defl=alloca(sizeof(*defl)*(ord+1)); + for(i=0;i<=ord;i++)defl[i]=a[i]; + + for(m=ord;m>0;m--){ + double new=0.f,delta; + + /* iterate a root */ + while(1){ + double p=defl[m],pp=0.f,ppp=0.f,denom; + + /* eval the polynomial and its first two derivatives */ + for(i=m;i>0;i--){ + ppp = new*ppp + pp; + pp = new*pp + p; + p = new*p + defl[i-1]; + } + + /* Laguerre's method */ + denom=(m-1) * ((m-1)*pp*pp - m*p*ppp); + if(denom<0) + return(-1); /* complex root! The LPC generator handed us a bad filter */ + + if(pp>0){ + denom = pp + sqrt(denom); + if(denom-(EPSILON))denom=-(EPSILON); + } + + delta = m*p/denom; + new -= delta; + + if(delta<0.f)delta*=-1; + + if(fabs(delta/new)<10e-12)break; + } + + r[m-1]=new; + + /* forward deflation */ + + for(i=m;i>0;i--) + defl[i-1]+=new*defl[i]; + defl++; + + } + return(0); +} + + +/* for spit-and-polish only */ +static int Newton_Raphson(float *a,int ord,float *r){ + int i, k, count=0; + double error=1.f; + double *root=alloca(ord*sizeof(*root)); + + for(i=0; i1e-20){ + error=0; + + for(i=0; i= 0; k--) { + + pp= pp* rooti + p; + p = p * rooti + a[k]; + } + + delta = p/pp; + root[i] -= delta; + error+= delta*delta; + } + + if(count>40)return(-1); + + count++; + } + + /* Replaced the original bubble sort with a real sort. With your + help, we can eliminate the bubble sort in our lifetime. --Monty */ + + for(i=0; i>1; + int g1_order,g2_order; + float *g1=alloca(sizeof(*g1)*(order2+1)); + float *g2=alloca(sizeof(*g2)*(order2+1)); + float *g1r=alloca(sizeof(*g1r)*(order2+1)); + float *g2r=alloca(sizeof(*g2r)*(order2+1)); + int i; + + /* even and odd are slightly different base cases */ + g1_order=(m+1)>>1; + g2_order=(m) >>1; + + /* Compute the lengths of the x polynomials. */ + /* Compute the first half of K & R F1 & F2 polynomials. */ + /* Compute half of the symmetric and antisymmetric polynomials. */ + /* Remove the roots at +1 and -1. */ + + g1[g1_order] = 1.f; + for(i=1;i<=g1_order;i++) g1[g1_order-i] = lpc[i-1]+lpc[m-i]; + g2[g2_order] = 1.f; + for(i=1;i<=g2_order;i++) g2[g2_order-i] = lpc[i-1]-lpc[m-i]; + + if(g1_order>g2_order){ + for(i=2; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+2]; + }else{ + for(i=1; i<=g1_order;i++) g1[g1_order-i] -= g1[g1_order-i+1]; + for(i=1; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+1]; + } + + /* Convert into polynomials in cos(alpha) */ + cheby(g1,g1_order); + cheby(g2,g2_order); + + /* Find the roots of the 2 even polynomials.*/ + if(Laguerre_With_Deflation(g1,g1_order,g1r) || + Laguerre_With_Deflation(g2,g2_order,g2r)) + return(-1); + + Newton_Raphson(g1,g1_order,g1r); /* if it fails, it leaves g1r alone */ + Newton_Raphson(g2,g2_order,g2r); /* if it fails, it leaves g2r alone */ + + qsort(g1r,g1_order,sizeof(*g1r),comp); + qsort(g2r,g2_order,sizeof(*g2r),comp); + + for(i=0;i +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "codebook.h" +#include "window.h" +#include "registry.h" +#include "psy.h" +#include "misc.h" + +/* simplistic, wasteful way of doing this (unique lookup for each + mode/submapping); there should be a central repository for + identical lookups. That will require minor work, so I'm putting it + off as low priority. + + Why a lookup for each backend in a given mode? Because the + blocksize is set by the mode, and low backend lookups may require + parameters from other areas of the mode/mapping */ + +static void mapping0_free_info(vorbis_info_mapping *i){ + vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; + if(info){ + memset(info,0,sizeof(*info)); + _ogg_free(info); + } +} + +static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm, + oggpack_buffer *opb){ + int i; + vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm; + + /* another 'we meant to do it this way' hack... up to beta 4, we + packed 4 binary zeros here to signify one submapping in use. We + now redefine that to mean four bitflags that indicate use of + deeper features; bit0:submappings, bit1:coupling, + bit2,3:reserved. This is backward compatable with all actual uses + of the beta code. */ + + if(info->submaps>1){ + oggpack_write(opb,1,1); + oggpack_write(opb,info->submaps-1,4); + }else + oggpack_write(opb,0,1); + + if(info->coupling_steps>0){ + oggpack_write(opb,1,1); + oggpack_write(opb,info->coupling_steps-1,8); + + for(i=0;icoupling_steps;i++){ + oggpack_write(opb,info->coupling_mag[i],ov_ilog(vi->channels-1)); + oggpack_write(opb,info->coupling_ang[i],ov_ilog(vi->channels-1)); + } + }else + oggpack_write(opb,0,1); + + oggpack_write(opb,0,2); /* 2,3:reserved */ + + /* we don't write the channel submappings if we only have one... */ + if(info->submaps>1){ + for(i=0;ichannels;i++) + oggpack_write(opb,info->chmuxlist[i],4); + } + for(i=0;isubmaps;i++){ + oggpack_write(opb,0,8); /* time submap unused */ + oggpack_write(opb,info->floorsubmap[i],8); + oggpack_write(opb,info->residuesubmap[i],8); + } +} + +/* also responsible for range checking */ +static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ + int i,b; + vorbis_info_mapping0 *info=_ogg_calloc(1,sizeof(*info)); + codec_setup_info *ci=vi->codec_setup; + if(vi->channels<=0)goto err_out; + + b=oggpack_read(opb,1); + if(b<0)goto err_out; + if(b){ + info->submaps=oggpack_read(opb,4)+1; + if(info->submaps<=0)goto err_out; + }else + info->submaps=1; + + b=oggpack_read(opb,1); + if(b<0)goto err_out; + if(b){ + info->coupling_steps=oggpack_read(opb,8)+1; + if(info->coupling_steps<=0)goto err_out; + for(i=0;icoupling_steps;i++){ + /* vi->channels > 0 is enforced in the caller */ + int testM=info->coupling_mag[i]= + oggpack_read(opb,ov_ilog(vi->channels-1)); + int testA=info->coupling_ang[i]= + oggpack_read(opb,ov_ilog(vi->channels-1)); + + if(testM<0 || + testA<0 || + testM==testA || + testM>=vi->channels || + testA>=vi->channels) goto err_out; + } + + } + + if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */ + + if(info->submaps>1){ + for(i=0;ichannels;i++){ + info->chmuxlist[i]=oggpack_read(opb,4); + if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out; + } + } + for(i=0;isubmaps;i++){ + oggpack_read(opb,8); /* time submap unused */ + info->floorsubmap[i]=oggpack_read(opb,8); + if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out; + info->residuesubmap[i]=oggpack_read(opb,8); + if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0)goto err_out; + } + + return info; + + err_out: + mapping0_free_info(info); + return(NULL); +} + +#include "os.h" +#include "lpc.h" +#include "lsp.h" +#include "envelope.h" +#include "mdct.h" +#include "psy.h" +#include "scales.h" + +#if 0 +static long seq=0; +static ogg_int64_t total=0; +static float FLOOR1_fromdB_LOOKUP[256]={ + 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, + 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, + 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, + 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, + 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, + 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, + 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, + 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, + 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, + 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, + 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, + 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, + 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, + 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, + 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, + 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, + 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, + 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, + 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, + 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, + 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, + 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, + 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, + 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, + 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, + 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, + 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, + 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, + 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, + 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, + 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, + 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, + 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, + 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, + 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, + 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, + 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, + 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, + 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, + 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, + 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, + 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, + 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, + 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, + 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, + 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, + 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, + 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, + 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, + 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, + 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, + 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, + 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, + 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, + 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, + 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, + 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, + 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, + 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, + 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, + 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, + 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, + 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, + 0.82788260F, 0.88168307F, 0.9389798F, 1.F, +}; + +#endif + + +static int mapping0_forward(vorbis_block *vb){ + vorbis_dsp_state *vd=vb->vd; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + private_state *b=vb->vd->backend_state; + vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal; + int n=vb->pcmend; + int i,j,k; + + int *nonzero = alloca(sizeof(*nonzero)*vi->channels); + float **gmdct = _vorbis_block_alloc(vb,vi->channels*sizeof(*gmdct)); + int **iwork = _vorbis_block_alloc(vb,vi->channels*sizeof(*iwork)); + int ***floor_posts = _vorbis_block_alloc(vb,vi->channels*sizeof(*floor_posts)); + + float global_ampmax=vbi->ampmax; + float *local_ampmax=alloca(sizeof(*local_ampmax)*vi->channels); + int blocktype=vbi->blocktype; + + int modenumber=vb->W; + vorbis_info_mapping0 *info=ci->map_param[modenumber]; + vorbis_look_psy *psy_look=b->psy+blocktype+(vb->W?2:0); + + vb->mode=modenumber; + + for(i=0;ichannels;i++){ + float scale=4.f/n; + float scale_dB; + + float *pcm =vb->pcm[i]; + float *logfft =pcm; + + iwork[i]=_vorbis_block_alloc(vb,n/2*sizeof(**iwork)); + gmdct[i]=_vorbis_block_alloc(vb,n/2*sizeof(**gmdct)); + + scale_dB=todB(&scale) + .345; /* + .345 is a hack; the original + todB estimation used on IEEE 754 + compliant machines had a bug that + returned dB values about a third + of a decibel too high. The bug + was harmless because tunings + implicitly took that into + account. However, fixing the bug + in the estimator requires + changing all the tunings as well. + For now, it's easier to sync + things back up here, and + recalibrate the tunings in the + next major model upgrade. */ + +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("pcmL",seq,pcm,n,0,0,total-n/2); + else + _analysis_output("pcmR",seq,pcm,n,0,0,total-n/2); + }else{ + _analysis_output("pcm",seq,pcm,n,0,0,total-n/2); + } +#endif + + /* window the PCM data */ + _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); + +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("windowedL",seq,pcm,n,0,0,total-n/2); + else + _analysis_output("windowedR",seq,pcm,n,0,0,total-n/2); + }else{ + _analysis_output("windowed",seq,pcm,n,0,0,total-n/2); + } +#endif + + /* transform the PCM data */ + /* only MDCT right now.... */ + mdct_forward(b->transform[vb->W][0],pcm,gmdct[i]); + + /* FFT yields more accurate tonal estimation (not phase sensitive) */ + drft_forward(&b->fft_look[vb->W],pcm); + logfft[0]=scale_dB+todB(pcm) + .345; /* + .345 is a hack; the + original todB estimation used on + IEEE 754 compliant machines had a + bug that returned dB values about + a third of a decibel too high. + The bug was harmless because + tunings implicitly took that into + account. However, fixing the bug + in the estimator requires + changing all the tunings as well. + For now, it's easier to sync + things back up here, and + recalibrate the tunings in the + next major model upgrade. */ + local_ampmax[i]=logfft[0]; + for(j=1;j>1]=scale_dB+.5f*todB(&temp) + .345; /* + + .345 is a hack; the original todB + estimation used on IEEE 754 + compliant machines had a bug that + returned dB values about a third + of a decibel too high. The bug + was harmless because tunings + implicitly took that into + account. However, fixing the bug + in the estimator requires + changing all the tunings as well. + For now, it's easier to sync + things back up here, and + recalibrate the tunings in the + next major model upgrade. */ + if(temp>local_ampmax[i])local_ampmax[i]=temp; + } + + if(local_ampmax[i]>0.f)local_ampmax[i]=0.f; + if(local_ampmax[i]>global_ampmax)global_ampmax=local_ampmax[i]; + +#if 0 + if(vi->channels==2){ + if(i==0){ + _analysis_output("fftL",seq,logfft,n/2,1,0,0); + }else{ + _analysis_output("fftR",seq,logfft,n/2,1,0,0); + } + }else{ + _analysis_output("fft",seq,logfft,n/2,1,0,0); + } +#endif + + } + + { + float *noise = _vorbis_block_alloc(vb,n/2*sizeof(*noise)); + float *tone = _vorbis_block_alloc(vb,n/2*sizeof(*tone)); + + for(i=0;ichannels;i++){ + /* the encoder setup assumes that all the modes used by any + specific bitrate tweaking use the same floor */ + + int submap=info->chmuxlist[i]; + + /* the following makes things clearer to *me* anyway */ + float *mdct =gmdct[i]; + float *logfft =vb->pcm[i]; + + float *logmdct =logfft+n/2; + float *logmask =logfft; + + vb->mode=modenumber; + + floor_posts[i]=_vorbis_block_alloc(vb,PACKETBLOBS*sizeof(**floor_posts)); + memset(floor_posts[i],0,sizeof(**floor_posts)*PACKETBLOBS); + + for(j=0;jchannels==2){ + if(i==0) + _analysis_output("mdctL",seq,logmdct,n/2,1,0,0); + else + _analysis_output("mdctR",seq,logmdct,n/2,1,0,0); + }else{ + _analysis_output("mdct",seq,logmdct,n/2,1,0,0); + } +#endif + + /* first step; noise masking. Not only does 'noise masking' + give us curves from which we can decide how much resolution + to give noise parts of the spectrum, it also implicitly hands + us a tonality estimate (the larger the value in the + 'noise_depth' vector, the more tonal that area is) */ + + _vp_noisemask(psy_look, + logmdct, + noise); /* noise does not have by-frequency offset + bias applied yet */ +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("noiseL",seq,noise,n/2,1,0,0); + else + _analysis_output("noiseR",seq,noise,n/2,1,0,0); + }else{ + _analysis_output("noise",seq,noise,n/2,1,0,0); + } +#endif + + /* second step: 'all the other crap'; all the stuff that isn't + computed/fit for bitrate management goes in the second psy + vector. This includes tone masking, peak limiting and ATH */ + + _vp_tonemask(psy_look, + logfft, + tone, + global_ampmax, + local_ampmax[i]); + +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("toneL",seq,tone,n/2,1,0,0); + else + _analysis_output("toneR",seq,tone,n/2,1,0,0); + }else{ + _analysis_output("tone",seq,tone,n/2,1,0,0); + } +#endif + + /* third step; we offset the noise vectors, overlay tone + masking. We then do a floor1-specific line fit. If we're + performing bitrate management, the line fit is performed + multiple times for up/down tweakage on demand. */ + +#if 0 + { + float aotuv[psy_look->n]; +#endif + + _vp_offset_and_mix(psy_look, + noise, + tone, + 1, + logmask, + mdct, + logmdct); + +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("aotuvM1_L",seq,aotuv,psy_look->n,1,1,0); + else + _analysis_output("aotuvM1_R",seq,aotuv,psy_look->n,1,1,0); + }else{ + _analysis_output("aotuvM1",seq,aotuv,psy_look->n,1,1,0); + } + } +#endif + + +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("mask1L",seq,logmask,n/2,1,0,0); + else + _analysis_output("mask1R",seq,logmask,n/2,1,0,0); + }else{ + _analysis_output("mask1",seq,logmask,n/2,1,0,0); + } +#endif + + /* this algorithm is hardwired to floor 1 for now; abort out if + we're *not* floor1. This won't happen unless someone has + broken the encode setup lib. Guard it anyway. */ + if(ci->floor_type[info->floorsubmap[submap]]!=1)return(-1); + + floor_posts[i][PACKETBLOBS/2]= + floor1_fit(vb,b->flr[info->floorsubmap[submap]], + logmdct, + logmask); + + /* are we managing bitrate? If so, perform two more fits for + later rate tweaking (fits represent hi/lo) */ + if(vorbis_bitrate_managed(vb) && floor_posts[i][PACKETBLOBS/2]){ + /* higher rate by way of lower noise curve */ + + _vp_offset_and_mix(psy_look, + noise, + tone, + 2, + logmask, + mdct, + logmdct); + +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("mask2L",seq,logmask,n/2,1,0,0); + else + _analysis_output("mask2R",seq,logmask,n/2,1,0,0); + }else{ + _analysis_output("mask2",seq,logmask,n/2,1,0,0); + } +#endif + + floor_posts[i][PACKETBLOBS-1]= + floor1_fit(vb,b->flr[info->floorsubmap[submap]], + logmdct, + logmask); + + /* lower rate by way of higher noise curve */ + _vp_offset_and_mix(psy_look, + noise, + tone, + 0, + logmask, + mdct, + logmdct); + +#if 0 + if(vi->channels==2){ + if(i==0) + _analysis_output("mask0L",seq,logmask,n/2,1,0,0); + else + _analysis_output("mask0R",seq,logmask,n/2,1,0,0); + }else{ + _analysis_output("mask0",seq,logmask,n/2,1,0,0); + } +#endif + + floor_posts[i][0]= + floor1_fit(vb,b->flr[info->floorsubmap[submap]], + logmdct, + logmask); + + /* we also interpolate a range of intermediate curves for + intermediate rates */ + for(k=1;kflr[info->floorsubmap[submap]], + floor_posts[i][0], + floor_posts[i][PACKETBLOBS/2], + k*65536/(PACKETBLOBS/2)); + for(k=PACKETBLOBS/2+1;kflr[info->floorsubmap[submap]], + floor_posts[i][PACKETBLOBS/2], + floor_posts[i][PACKETBLOBS-1], + (k-PACKETBLOBS/2)*65536/(PACKETBLOBS/2)); + } + } + } + vbi->ampmax=global_ampmax; + + /* + the next phases are performed once for vbr-only and PACKETBLOB + times for bitrate managed modes. + + 1) encode actual mode being used + 2) encode the floor for each channel, compute coded mask curve/res + 3) normalize and couple. + 4) encode residue + 5) save packet bytes to the packetblob vector + + */ + + /* iterate over the many masking curve fits we've created */ + + { + int **couple_bundle=alloca(sizeof(*couple_bundle)*vi->channels); + int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels); + + for(k=(vorbis_bitrate_managed(vb)?0:PACKETBLOBS/2); + k<=(vorbis_bitrate_managed(vb)?PACKETBLOBS-1:PACKETBLOBS/2); + k++){ + oggpack_buffer *opb=vbi->packetblob[k]; + + /* start out our new packet blob with packet type and mode */ + /* Encode the packet type */ + oggpack_write(opb,0,1); + /* Encode the modenumber */ + /* Encode frame mode, pre,post windowsize, then dispatch */ + oggpack_write(opb,modenumber,b->modebits); + if(vb->W){ + oggpack_write(opb,vb->lW,1); + oggpack_write(opb,vb->nW,1); + } + + /* encode floor, compute masking curve, sep out residue */ + for(i=0;ichannels;i++){ + int submap=info->chmuxlist[i]; + int *ilogmask=iwork[i]; + + nonzero[i]=floor1_encode(opb,vb,b->flr[info->floorsubmap[submap]], + floor_posts[i][k], + ilogmask); +#if 0 + { + char buf[80]; + sprintf(buf,"maskI%c%d",i?'R':'L',k); + float work[n/2]; + for(j=0;jpsy_g_param, + psy_look, + info, + gmdct, + iwork, + nonzero, + ci->psy_g_param.sliding_lowpass[vb->W][k], + vi->channels); + +#if 0 + for(i=0;ichannels;i++){ + char buf[80]; + sprintf(buf,"res%c%d",i?'R':'L',k); + float work[n/2]; + for(j=0;jsubmaps;i++){ + int ch_in_bundle=0; + long **classifications; + int resnum=info->residuesubmap[i]; + + for(j=0;jchannels;j++){ + if(info->chmuxlist[j]==i){ + zerobundle[ch_in_bundle]=0; + if(nonzero[j])zerobundle[ch_in_bundle]=1; + couple_bundle[ch_in_bundle++]=iwork[j]; + } + } + + classifications=_residue_P[ci->residue_type[resnum]]-> + class(vb,b->residue[resnum],couple_bundle,zerobundle,ch_in_bundle); + + ch_in_bundle=0; + for(j=0;jchannels;j++) + if(info->chmuxlist[j]==i) + couple_bundle[ch_in_bundle++]=iwork[j]; + + _residue_P[ci->residue_type[resnum]]-> + forward(opb,vb,b->residue[resnum], + couple_bundle,zerobundle,ch_in_bundle,classifications,i); + } + + /* ok, done encoding. Next protopacket. */ + } + + } + +#if 0 + seq++; + total+=ci->blocksizes[vb->W]/4+ci->blocksizes[vb->nW]/4; +#endif + return(0); +} + +static int mapping0_inverse(vorbis_block *vb,vorbis_info_mapping *l){ + vorbis_dsp_state *vd=vb->vd; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + private_state *b=vd->backend_state; + vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)l; + + int i,j; + long n=vb->pcmend=ci->blocksizes[vb->W]; + + float **pcmbundle=alloca(sizeof(*pcmbundle)*vi->channels); + int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels); + + int *nonzero =alloca(sizeof(*nonzero)*vi->channels); + void **floormemo=alloca(sizeof(*floormemo)*vi->channels); + + /* recover the spectral envelope; store it in the PCM vector for now */ + for(i=0;ichannels;i++){ + int submap=info->chmuxlist[i]; + floormemo[i]=_floor_P[ci->floor_type[info->floorsubmap[submap]]]-> + inverse1(vb,b->flr[info->floorsubmap[submap]]); + if(floormemo[i]) + nonzero[i]=1; + else + nonzero[i]=0; + memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); + } + + /* channel coupling can 'dirty' the nonzero listing */ + for(i=0;icoupling_steps;i++){ + if(nonzero[info->coupling_mag[i]] || + nonzero[info->coupling_ang[i]]){ + nonzero[info->coupling_mag[i]]=1; + nonzero[info->coupling_ang[i]]=1; + } + } + + /* recover the residue into our working vectors */ + for(i=0;isubmaps;i++){ + int ch_in_bundle=0; + for(j=0;jchannels;j++){ + if(info->chmuxlist[j]==i){ + if(nonzero[j]) + zerobundle[ch_in_bundle]=1; + else + zerobundle[ch_in_bundle]=0; + pcmbundle[ch_in_bundle++]=vb->pcm[j]; + } + } + + _residue_P[ci->residue_type[info->residuesubmap[i]]]-> + inverse(vb,b->residue[info->residuesubmap[i]], + pcmbundle,zerobundle,ch_in_bundle); + } + + /* channel coupling */ + for(i=info->coupling_steps-1;i>=0;i--){ + float *pcmM=vb->pcm[info->coupling_mag[i]]; + float *pcmA=vb->pcm[info->coupling_ang[i]]; + + for(j=0;j0) + if(ang>0){ + pcmM[j]=mag; + pcmA[j]=mag-ang; + }else{ + pcmA[j]=mag; + pcmM[j]=mag+ang; + } + else + if(ang>0){ + pcmM[j]=mag; + pcmA[j]=mag+ang; + }else{ + pcmA[j]=mag; + pcmM[j]=mag-ang; + } + } + } + + /* compute and apply spectral envelope */ + for(i=0;ichannels;i++){ + float *pcm=vb->pcm[i]; + int submap=info->chmuxlist[i]; + _floor_P[ci->floor_type[info->floorsubmap[submap]]]-> + inverse2(vb,b->flr[info->floorsubmap[submap]], + floormemo[i],pcm); + } + + /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ + /* only MDCT right now.... */ + for(i=0;ichannels;i++){ + float *pcm=vb->pcm[i]; + mdct_backward(b->transform[vb->W][0],pcm,pcm); + } + + /* all done! */ + return(0); +} + +/* export hooks */ +const vorbis_func_mapping mapping0_exportbundle={ + &mapping0_pack, + &mapping0_unpack, + &mapping0_free_info, + &mapping0_forward, + &mapping0_inverse +}; diff --git a/vendor/vorbis/lib/masking.h b/vendor/vorbis/lib/masking.h new file mode 100644 index 0000000..7a196a3 --- /dev/null +++ b/vendor/vorbis/lib/masking.h @@ -0,0 +1,784 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: masking curve data for psychoacoustics + + ********************************************************************/ + +#ifndef _V_MASKING_H_ +#define _V_MASKING_H_ + +/* more detailed ATH; the bass if flat to save stressing the floor + overly for only a bin or two of savings. */ + +#define MAX_ATH 88 +static const float ATH[]={ + /*15*/ -51, -52, -53, -54, -55, -56, -57, -58, + /*31*/ -59, -60, -61, -62, -63, -64, -65, -66, + /*63*/ -67, -68, -69, -70, -71, -72, -73, -74, + /*125*/ -75, -76, -77, -78, -80, -81, -82, -83, + /*250*/ -84, -85, -86, -87, -88, -88, -89, -89, + /*500*/ -90, -91, -91, -92, -93, -94, -95, -96, + /*1k*/ -96, -97, -98, -98, -99, -99,-100,-100, + /*2k*/ -101,-102,-103,-104,-106,-107,-107,-107, + /*4k*/ -107,-105,-103,-102,-101, -99, -98, -96, + /*8k*/ -95, -95, -96, -97, -96, -95, -93, -90, + /*16k*/ -80, -70, -50, -40, -30, -30, -30, -30 +}; + +/* The tone masking curves from Ehmer's and Fielder's papers have been + replaced by an empirically collected data set. The previously + published values were, far too often, simply on crack. */ + +#define EHMER_OFFSET 16 +#define EHMER_MAX 56 + +/* masking tones from -50 to 0dB, 62.5 through 16kHz at half octaves + test tones from -2 octaves to +5 octaves sampled at eighth octaves */ +/* (Vorbis 0dB, the loudest possible tone, is assumed to be ~100dB SPL + for collection of these curves) */ + +static const float tonemasks[P_BANDS][6][EHMER_MAX]={ + /* 62.5 Hz */ + {{ -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -62, -62, -65, -73, + -69, -68, -68, -67, -70, -70, -72, -74, + -75, -79, -79, -80, -83, -88, -93, -100, + -110, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -53, -61, -66, + -66, -68, -67, -70, -76, -76, -72, -73, + -75, -76, -78, -79, -83, -88, -93, -100, + -110, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -37, -37, -37, -37, -37, -37, -37, -37, + -38, -40, -42, -46, -48, -53, -55, -62, + -65, -58, -56, -56, -61, -60, -65, -67, + -69, -71, -77, -77, -78, -80, -82, -84, + -88, -93, -98, -106, -112, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -25, -25, -25, -25, -25, -25, -25, -25, + -25, -26, -27, -29, -32, -38, -48, -52, + -52, -50, -48, -48, -51, -52, -54, -60, + -67, -67, -66, -68, -69, -73, -73, -76, + -80, -81, -81, -85, -85, -86, -88, -93, + -100, -110, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -16, -16, -16, -16, -16, -16, -16, -16, + -17, -19, -20, -22, -26, -28, -31, -40, + -47, -39, -39, -40, -42, -43, -47, -51, + -57, -52, -55, -55, -60, -58, -62, -63, + -70, -67, -69, -72, -73, -77, -80, -82, + -83, -87, -90, -94, -98, -104, -115, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -10, -11, -15, -19, -25, -30, + -34, -31, -30, -31, -29, -32, -35, -42, + -48, -42, -44, -46, -50, -50, -51, -52, + -59, -54, -55, -55, -58, -62, -63, -66, + -72, -73, -76, -75, -78, -80, -80, -81, + -84, -88, -90, -94, -98, -101, -106, -110}}, + /* 88Hz */ + {{ -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -67, -67, -67, + -76, -72, -71, -74, -76, -76, -75, -78, + -79, -79, -81, -83, -86, -89, -93, -97, + -100, -105, -110, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -48, -51, -55, -59, -66, + -66, -66, -67, -66, -68, -69, -70, -74, + -79, -77, -77, -78, -80, -81, -82, -84, + -86, -88, -91, -95, -100, -108, -116, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -36, -36, -36, -36, -36, -36, -36, -36, + -36, -37, -37, -41, -44, -48, -51, -58, + -62, -60, -57, -59, -59, -60, -63, -65, + -72, -71, -70, -72, -74, -77, -76, -78, + -81, -81, -80, -83, -86, -91, -96, -100, + -105, -110, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -28, -28, -28, -28, -28, -28, -28, -28, + -28, -30, -32, -32, -33, -35, -41, -49, + -50, -49, -47, -48, -48, -52, -51, -57, + -65, -61, -59, -61, -64, -69, -70, -74, + -77, -77, -78, -81, -84, -85, -87, -90, + -92, -96, -100, -107, -112, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -19, -19, -19, -19, -19, -19, -19, -19, + -20, -21, -23, -27, -30, -35, -36, -41, + -46, -44, -42, -40, -41, -41, -43, -48, + -55, -53, -52, -53, -56, -59, -58, -60, + -67, -66, -69, -71, -72, -75, -79, -81, + -84, -87, -90, -93, -97, -101, -107, -114, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -9, -9, -9, -9, -9, -9, -9, -9, + -11, -12, -12, -15, -16, -20, -23, -30, + -37, -34, -33, -34, -31, -32, -32, -38, + -47, -44, -41, -40, -47, -49, -46, -46, + -58, -50, -50, -54, -58, -62, -64, -67, + -67, -70, -72, -76, -79, -83, -87, -91, + -96, -100, -104, -110, -999, -999, -999, -999}}, + /* 125 Hz */ + {{ -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -63, -64, -66, -67, -66, -68, + -75, -72, -76, -75, -76, -78, -79, -82, + -84, -85, -90, -94, -101, -110, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -60, -60, -61, -63, -66, + -71, -68, -70, -70, -71, -72, -72, -75, + -81, -78, -79, -82, -83, -86, -90, -97, + -103, -113, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -53, -53, -53, -53, -53, -53, -53, -53, + -53, -54, -55, -57, -56, -57, -55, -61, + -65, -60, -60, -62, -63, -63, -66, -68, + -74, -73, -75, -75, -78, -80, -80, -82, + -85, -90, -96, -101, -108, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -47, -47, -47, -47, -48, -51, + -57, -51, -49, -50, -51, -53, -54, -59, + -66, -60, -62, -67, -67, -70, -72, -75, + -76, -78, -81, -85, -88, -94, -97, -104, + -112, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -36, -36, -36, -36, -36, -36, -36, -36, + -39, -41, -42, -42, -39, -38, -41, -43, + -52, -44, -40, -39, -37, -37, -40, -47, + -54, -50, -48, -50, -55, -61, -59, -62, + -66, -66, -66, -69, -69, -73, -74, -74, + -75, -77, -79, -82, -87, -91, -95, -100, + -108, -115, -999, -999, -999, -999, -999, -999}, + { -28, -26, -24, -22, -20, -20, -23, -29, + -30, -31, -28, -27, -28, -28, -28, -35, + -40, -33, -32, -29, -30, -30, -30, -37, + -45, -41, -37, -38, -45, -47, -47, -48, + -53, -49, -48, -50, -49, -49, -51, -52, + -58, -56, -57, -56, -60, -61, -62, -70, + -72, -74, -78, -83, -88, -93, -100, -106}}, + /* 177 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -110, -105, -100, -95, -91, -87, -83, + -80, -78, -76, -78, -78, -81, -83, -85, + -86, -85, -86, -87, -90, -97, -107, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -110, -105, -100, -95, -90, + -85, -81, -77, -73, -70, -67, -67, -68, + -75, -73, -70, -69, -70, -72, -75, -79, + -84, -83, -84, -86, -88, -89, -89, -93, + -98, -105, -112, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-105, -100, -95, -90, -85, -80, -76, -71, + -68, -68, -65, -63, -63, -62, -62, -64, + -65, -64, -61, -62, -63, -64, -66, -68, + -73, -73, -74, -75, -76, -81, -83, -85, + -88, -89, -92, -95, -100, -108, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -80, -75, -71, -68, -65, -63, -62, -61, + -61, -61, -61, -59, -56, -57, -53, -50, + -58, -52, -50, -50, -52, -53, -54, -58, + -67, -63, -67, -68, -72, -75, -78, -80, + -81, -81, -82, -85, -89, -90, -93, -97, + -101, -107, -114, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + { -65, -61, -59, -57, -56, -55, -55, -56, + -56, -57, -55, -53, -52, -47, -44, -44, + -50, -44, -41, -39, -39, -42, -40, -46, + -51, -49, -50, -53, -54, -63, -60, -61, + -62, -66, -66, -66, -70, -73, -74, -75, + -76, -75, -79, -85, -89, -91, -96, -102, + -110, -999, -999, -999, -999, -999, -999, -999}, + { -52, -50, -49, -49, -48, -48, -48, -49, + -50, -50, -49, -46, -43, -39, -35, -33, + -38, -36, -32, -29, -32, -32, -32, -35, + -44, -39, -38, -38, -46, -50, -45, -46, + -53, -50, -50, -50, -54, -54, -53, -53, + -56, -57, -59, -66, -70, -72, -74, -79, + -83, -85, -90, -97, -114, -999, -999, -999}}, + /* 250 Hz */ + {{-999, -999, -999, -999, -999, -999, -110, -105, + -100, -95, -90, -86, -80, -75, -75, -79, + -80, -79, -80, -81, -82, -88, -95, -103, + -110, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -108, -103, -98, -93, + -88, -83, -79, -78, -75, -71, -67, -68, + -73, -73, -72, -73, -75, -77, -80, -82, + -88, -93, -100, -107, -114, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -110, -105, -101, -96, -90, + -86, -81, -77, -73, -69, -66, -61, -62, + -66, -64, -62, -65, -66, -70, -72, -76, + -81, -80, -84, -90, -95, -102, -110, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -107, -103, -97, -92, -88, + -83, -79, -74, -70, -66, -59, -53, -58, + -62, -55, -54, -54, -54, -58, -61, -62, + -72, -70, -72, -75, -78, -80, -81, -80, + -83, -83, -88, -93, -100, -107, -115, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -105, -100, -95, -90, -85, + -80, -75, -70, -66, -62, -56, -48, -44, + -48, -46, -46, -43, -46, -48, -48, -51, + -58, -58, -59, -60, -62, -62, -61, -61, + -65, -64, -65, -68, -70, -74, -75, -78, + -81, -86, -95, -110, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -105, -100, -95, -90, -85, -80, + -75, -70, -65, -61, -55, -49, -39, -33, + -40, -35, -32, -38, -40, -33, -35, -37, + -46, -41, -45, -44, -46, -42, -45, -46, + -52, -50, -50, -50, -54, -54, -55, -57, + -62, -64, -66, -68, -70, -76, -81, -90, + -100, -110, -999, -999, -999, -999, -999, -999}}, + /* 354 hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -105, -98, -90, -85, -82, -83, -80, -78, + -84, -79, -80, -83, -87, -89, -91, -93, + -99, -106, -117, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -105, -98, -90, -85, -80, -75, -70, -68, + -74, -72, -74, -77, -80, -82, -85, -87, + -92, -89, -91, -95, -100, -106, -112, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -105, -98, -90, -83, -75, -71, -63, -64, + -67, -62, -64, -67, -70, -73, -77, -81, + -84, -83, -85, -89, -90, -93, -98, -104, + -109, -114, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -103, -96, -88, -81, -75, -68, -58, -54, + -56, -54, -56, -56, -58, -60, -63, -66, + -74, -69, -72, -72, -75, -74, -77, -81, + -81, -82, -84, -87, -93, -96, -99, -104, + -110, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -108, -102, -96, + -91, -85, -80, -74, -68, -60, -51, -46, + -48, -46, -43, -45, -47, -47, -49, -48, + -56, -53, -55, -58, -57, -63, -58, -60, + -66, -64, -67, -70, -70, -74, -77, -84, + -86, -89, -91, -93, -94, -101, -109, -118, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -108, -103, -98, -93, -88, + -83, -78, -73, -68, -60, -53, -44, -35, + -38, -38, -34, -34, -36, -40, -41, -44, + -51, -45, -46, -47, -46, -54, -50, -49, + -50, -50, -50, -51, -54, -57, -58, -60, + -66, -66, -66, -64, -65, -68, -77, -82, + -87, -95, -110, -999, -999, -999, -999, -999}}, + /* 500 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -107, -102, -97, -92, -87, -83, -78, -75, + -82, -79, -83, -85, -89, -92, -95, -98, + -101, -105, -109, -113, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -106, + -100, -95, -90, -86, -81, -78, -74, -69, + -74, -74, -76, -79, -83, -84, -86, -89, + -92, -97, -93, -100, -103, -107, -110, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -106, -100, + -95, -90, -87, -83, -80, -75, -69, -60, + -66, -66, -68, -70, -74, -78, -79, -81, + -81, -83, -84, -87, -93, -96, -99, -103, + -107, -110, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -108, -103, -98, + -93, -89, -85, -82, -78, -71, -62, -55, + -58, -58, -54, -54, -55, -59, -61, -62, + -70, -66, -66, -67, -70, -72, -75, -78, + -84, -84, -84, -88, -91, -90, -95, -98, + -102, -103, -106, -110, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -108, -103, -98, -94, + -90, -87, -82, -79, -73, -67, -58, -47, + -50, -45, -41, -45, -48, -44, -44, -49, + -54, -51, -48, -47, -49, -50, -51, -57, + -58, -60, -63, -69, -70, -69, -71, -74, + -78, -82, -90, -95, -101, -105, -110, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -105, -101, -97, -93, -90, + -85, -80, -77, -72, -65, -56, -48, -37, + -40, -36, -34, -40, -50, -47, -38, -41, + -47, -38, -35, -39, -38, -43, -40, -45, + -50, -45, -44, -47, -50, -55, -48, -48, + -52, -66, -70, -76, -82, -90, -97, -105, + -110, -999, -999, -999, -999, -999, -999, -999}}, + /* 707 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -108, -103, -98, -93, -86, -79, -76, + -83, -81, -85, -87, -89, -93, -98, -102, + -107, -112, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -108, -103, -98, -93, -86, -79, -71, + -77, -74, -77, -79, -81, -84, -85, -90, + -92, -93, -92, -98, -101, -108, -112, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -108, -103, -98, -93, -87, -78, -68, -65, + -66, -62, -65, -67, -70, -73, -75, -78, + -82, -82, -83, -84, -91, -93, -98, -102, + -106, -110, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -105, -100, -95, -90, -82, -74, -62, -57, + -58, -56, -51, -52, -52, -54, -54, -58, + -66, -59, -60, -63, -66, -69, -73, -79, + -83, -84, -80, -81, -81, -82, -88, -92, + -98, -105, -113, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -107, + -102, -97, -92, -84, -79, -69, -57, -47, + -52, -47, -44, -45, -50, -52, -42, -42, + -53, -43, -43, -48, -51, -56, -55, -52, + -57, -59, -61, -62, -67, -71, -78, -83, + -86, -94, -98, -103, -110, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -105, -100, + -95, -90, -84, -78, -70, -61, -51, -41, + -40, -38, -40, -46, -52, -51, -41, -40, + -46, -40, -38, -38, -41, -46, -41, -46, + -47, -43, -43, -45, -41, -45, -56, -67, + -68, -83, -87, -90, -95, -102, -107, -113, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 1000 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -109, -105, -101, -96, -91, -84, -77, + -82, -82, -85, -89, -94, -100, -106, -110, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -106, -103, -98, -92, -85, -80, -71, + -75, -72, -76, -80, -84, -86, -89, -93, + -100, -107, -113, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -107, + -104, -101, -97, -92, -88, -84, -80, -64, + -66, -63, -64, -66, -69, -73, -77, -83, + -83, -86, -91, -98, -104, -111, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -107, + -104, -101, -97, -92, -90, -84, -74, -57, + -58, -52, -55, -54, -50, -52, -50, -52, + -63, -62, -69, -76, -77, -78, -78, -79, + -82, -88, -94, -100, -106, -111, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -106, -102, + -98, -95, -90, -85, -83, -78, -70, -50, + -50, -41, -44, -49, -47, -50, -50, -44, + -55, -46, -47, -48, -48, -54, -49, -49, + -58, -62, -71, -81, -87, -92, -97, -102, + -108, -114, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -106, -102, + -98, -95, -90, -85, -83, -78, -70, -45, + -43, -41, -47, -50, -51, -50, -49, -45, + -47, -41, -44, -41, -39, -43, -38, -37, + -40, -41, -44, -50, -58, -65, -73, -79, + -85, -92, -97, -101, -105, -109, -113, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 1414 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -107, -100, -95, -87, -81, + -85, -83, -88, -93, -100, -107, -114, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -107, -101, -95, -88, -83, -76, + -73, -72, -79, -84, -90, -95, -100, -105, + -110, -115, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -104, -98, -92, -87, -81, -70, + -65, -62, -67, -71, -74, -80, -85, -91, + -95, -99, -103, -108, -111, -114, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -103, -97, -90, -85, -76, -60, + -56, -54, -60, -62, -61, -56, -63, -65, + -73, -74, -77, -75, -78, -81, -86, -87, + -88, -91, -94, -98, -103, -110, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -105, + -100, -97, -92, -86, -81, -79, -70, -57, + -51, -47, -51, -58, -60, -56, -53, -50, + -58, -52, -50, -50, -53, -55, -64, -69, + -71, -85, -82, -78, -81, -85, -95, -102, + -112, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -105, + -100, -97, -92, -85, -83, -79, -72, -49, + -40, -43, -43, -54, -56, -51, -50, -40, + -43, -38, -36, -35, -37, -38, -37, -44, + -54, -60, -57, -60, -70, -75, -84, -92, + -103, -112, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 2000 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -102, -95, -89, -82, + -83, -84, -90, -92, -99, -107, -113, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -107, -101, -95, -89, -83, -72, + -74, -78, -85, -88, -88, -90, -92, -98, + -105, -111, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -109, -103, -97, -93, -87, -81, -70, + -70, -67, -75, -73, -76, -79, -81, -83, + -88, -89, -97, -103, -110, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -107, -100, -94, -88, -83, -75, -63, + -59, -59, -63, -66, -60, -62, -67, -67, + -77, -76, -81, -88, -86, -92, -96, -102, + -109, -116, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -105, -98, -92, -86, -81, -73, -56, + -52, -47, -55, -60, -58, -52, -51, -45, + -49, -50, -53, -54, -61, -71, -70, -69, + -78, -79, -87, -90, -96, -104, -112, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -103, -96, -90, -86, -78, -70, -51, + -42, -47, -48, -55, -54, -54, -53, -42, + -35, -28, -33, -38, -37, -44, -47, -49, + -54, -63, -68, -78, -82, -89, -94, -99, + -104, -109, -114, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 2828 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -110, -100, -90, -79, + -85, -81, -82, -82, -89, -94, -99, -103, + -109, -115, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -105, -97, -85, -72, + -74, -70, -70, -70, -76, -85, -91, -93, + -97, -103, -109, -115, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -112, -93, -81, -68, + -62, -60, -60, -57, -63, -70, -77, -82, + -90, -93, -98, -104, -109, -113, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -113, -100, -93, -84, -63, + -58, -48, -53, -54, -52, -52, -57, -64, + -66, -76, -83, -81, -85, -85, -90, -95, + -98, -101, -103, -106, -108, -111, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -105, -95, -86, -74, -53, + -50, -38, -43, -49, -43, -42, -39, -39, + -46, -52, -57, -56, -72, -69, -74, -81, + -87, -92, -94, -97, -99, -102, -105, -108, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -108, -99, -90, -76, -66, -45, + -43, -41, -44, -47, -43, -47, -40, -30, + -31, -31, -39, -33, -40, -41, -43, -53, + -59, -70, -73, -77, -79, -82, -84, -87, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 4000 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -110, -91, -76, + -75, -85, -93, -98, -104, -110, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -110, -91, -70, + -70, -75, -86, -89, -94, -98, -101, -106, + -110, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -110, -95, -80, -60, + -65, -64, -74, -83, -88, -91, -95, -99, + -103, -107, -110, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -110, -95, -80, -58, + -55, -49, -66, -68, -71, -78, -78, -80, + -88, -85, -89, -97, -100, -105, -110, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -110, -95, -80, -53, + -52, -41, -59, -59, -49, -58, -56, -63, + -86, -79, -90, -93, -98, -103, -107, -112, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -97, -91, -73, -45, + -40, -33, -53, -61, -49, -54, -50, -50, + -60, -52, -67, -74, -81, -92, -96, -100, + -105, -110, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 5657 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -113, -106, -99, -92, -77, + -80, -88, -97, -106, -115, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -116, -109, -102, -95, -89, -74, + -72, -88, -87, -95, -102, -109, -116, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -116, -109, -102, -95, -89, -75, + -66, -74, -77, -78, -86, -87, -90, -96, + -105, -115, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -115, -108, -101, -94, -88, -66, + -56, -61, -70, -65, -78, -72, -83, -84, + -93, -98, -105, -110, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -110, -105, -95, -89, -82, -57, + -52, -52, -59, -56, -59, -58, -69, -67, + -88, -82, -82, -89, -94, -100, -108, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -110, -101, -96, -90, -83, -77, -54, + -43, -38, -50, -48, -52, -48, -42, -42, + -51, -52, -53, -59, -65, -71, -78, -85, + -95, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 8000 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -120, -105, -86, -68, + -78, -79, -90, -100, -110, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -120, -105, -86, -66, + -73, -77, -88, -96, -105, -115, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -120, -105, -92, -80, -61, + -64, -68, -80, -87, -92, -100, -110, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -120, -104, -91, -79, -52, + -60, -54, -64, -69, -77, -80, -82, -84, + -85, -87, -88, -90, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -118, -100, -87, -77, -49, + -50, -44, -58, -61, -61, -67, -65, -62, + -62, -62, -65, -68, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -115, -98, -84, -62, -49, + -44, -38, -46, -49, -49, -46, -39, -37, + -39, -40, -42, -43, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 11314 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -110, -88, -74, + -77, -82, -82, -85, -90, -94, -99, -104, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -110, -88, -66, + -70, -81, -80, -81, -84, -88, -91, -93, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -110, -88, -61, + -63, -70, -71, -74, -77, -80, -83, -85, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -110, -86, -62, + -63, -62, -62, -58, -52, -50, -50, -52, + -54, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -118, -108, -84, -53, + -50, -50, -50, -55, -47, -45, -40, -40, + -40, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -118, -100, -73, -43, + -37, -42, -43, -53, -38, -37, -35, -35, + -38, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}}, + /* 16000 Hz */ + {{-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -100, -91, -84, -74, + -80, -80, -80, -80, -80, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -100, -91, -84, -74, + -68, -68, -68, -68, -68, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -100, -86, -78, -70, + -60, -45, -30, -21, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -100, -87, -78, -67, + -48, -38, -29, -21, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -100, -86, -69, -56, + -45, -35, -33, -29, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}, + {-999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -110, -100, -83, -71, -48, + -27, -38, -37, -34, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999, + -999, -999, -999, -999, -999, -999, -999, -999}} +}; + +#endif diff --git a/vendor/vorbis/lib/mdct.c b/vendor/vorbis/lib/mdct.c new file mode 100644 index 0000000..2a0ff8d --- /dev/null +++ b/vendor/vorbis/lib/mdct.c @@ -0,0 +1,562 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: normalized modified discrete cosine transform + power of two length transform only [64 <= n ] + + Original algorithm adapted long ago from _The use of multirate filter + banks for coding of high quality digital audio_, by T. Sporer, + K. Brandenburg and B. Edler, collection of the European Signal + Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pp + 211-214 + + The below code implements an algorithm that no longer looks much like + that presented in the paper, but the basic structure remains if you + dig deep enough to see it. + + This module DOES NOT INCLUDE code to generate/apply the window + function. Everybody has their own weird favorite including me... I + happen to like the properties of y=sin(.5PI*sin^2(x)), but others may + vehemently disagree. + + ********************************************************************/ + +/* this can also be run as an integer transform by uncommenting a + define in mdct.h; the integerization is a first pass and although + it's likely stable for Vorbis, the dynamic range is constrained and + roundoff isn't done (so it's noisy). Consider it functional, but + only a starting point. There's no point on a machine with an FPU */ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "mdct.h" +#include "os.h" +#include "misc.h" + +/* build lookups for trig functions; also pre-figure scaling and + some window function algebra. */ + +void mdct_init(mdct_lookup *lookup,int n){ + int *bitrev=_ogg_malloc(sizeof(*bitrev)*(n/4)); + DATA_TYPE *T=_ogg_malloc(sizeof(*T)*(n+n/4)); + + int i; + int n2=n>>1; + int log2n=lookup->log2n=rint(log((float)n)/log(2.f)); + lookup->n=n; + lookup->trig=T; + lookup->bitrev=bitrev; + +/* trig lookups... */ + + for(i=0;i>j;j++) + if((msb>>j)&i)acc|=1<scale=FLOAT_CONV(4.f/n); +} + +/* 8 point butterfly (in place, 4 register) */ +STIN void mdct_butterfly_8(DATA_TYPE *x){ + REG_TYPE r0 = x[6] + x[2]; + REG_TYPE r1 = x[6] - x[2]; + REG_TYPE r2 = x[4] + x[0]; + REG_TYPE r3 = x[4] - x[0]; + + x[6] = r0 + r2; + x[4] = r0 - r2; + + r0 = x[5] - x[1]; + r2 = x[7] - x[3]; + x[0] = r1 + r0; + x[2] = r1 - r0; + + r0 = x[5] + x[1]; + r1 = x[7] + x[3]; + x[3] = r2 + r3; + x[1] = r2 - r3; + x[7] = r1 + r0; + x[5] = r1 - r0; + +} + +/* 16 point butterfly (in place, 4 register) */ +STIN void mdct_butterfly_16(DATA_TYPE *x){ + REG_TYPE r0 = x[1] - x[9]; + REG_TYPE r1 = x[0] - x[8]; + + x[8] += x[0]; + x[9] += x[1]; + x[0] = MULT_NORM((r0 + r1) * cPI2_8); + x[1] = MULT_NORM((r0 - r1) * cPI2_8); + + r0 = x[3] - x[11]; + r1 = x[10] - x[2]; + x[10] += x[2]; + x[11] += x[3]; + x[2] = r0; + x[3] = r1; + + r0 = x[12] - x[4]; + r1 = x[13] - x[5]; + x[12] += x[4]; + x[13] += x[5]; + x[4] = MULT_NORM((r0 - r1) * cPI2_8); + x[5] = MULT_NORM((r0 + r1) * cPI2_8); + + r0 = x[14] - x[6]; + r1 = x[15] - x[7]; + x[14] += x[6]; + x[15] += x[7]; + x[6] = r0; + x[7] = r1; + + mdct_butterfly_8(x); + mdct_butterfly_8(x+8); +} + +/* 32 point butterfly (in place, 4 register) */ +STIN void mdct_butterfly_32(DATA_TYPE *x){ + REG_TYPE r0 = x[30] - x[14]; + REG_TYPE r1 = x[31] - x[15]; + + x[30] += x[14]; + x[31] += x[15]; + x[14] = r0; + x[15] = r1; + + r0 = x[28] - x[12]; + r1 = x[29] - x[13]; + x[28] += x[12]; + x[29] += x[13]; + x[12] = MULT_NORM( r0 * cPI1_8 - r1 * cPI3_8 ); + x[13] = MULT_NORM( r0 * cPI3_8 + r1 * cPI1_8 ); + + r0 = x[26] - x[10]; + r1 = x[27] - x[11]; + x[26] += x[10]; + x[27] += x[11]; + x[10] = MULT_NORM(( r0 - r1 ) * cPI2_8); + x[11] = MULT_NORM(( r0 + r1 ) * cPI2_8); + + r0 = x[24] - x[8]; + r1 = x[25] - x[9]; + x[24] += x[8]; + x[25] += x[9]; + x[8] = MULT_NORM( r0 * cPI3_8 - r1 * cPI1_8 ); + x[9] = MULT_NORM( r1 * cPI3_8 + r0 * cPI1_8 ); + + r0 = x[22] - x[6]; + r1 = x[7] - x[23]; + x[22] += x[6]; + x[23] += x[7]; + x[6] = r1; + x[7] = r0; + + r0 = x[4] - x[20]; + r1 = x[5] - x[21]; + x[20] += x[4]; + x[21] += x[5]; + x[4] = MULT_NORM( r1 * cPI1_8 + r0 * cPI3_8 ); + x[5] = MULT_NORM( r1 * cPI3_8 - r0 * cPI1_8 ); + + r0 = x[2] - x[18]; + r1 = x[3] - x[19]; + x[18] += x[2]; + x[19] += x[3]; + x[2] = MULT_NORM(( r1 + r0 ) * cPI2_8); + x[3] = MULT_NORM(( r1 - r0 ) * cPI2_8); + + r0 = x[0] - x[16]; + r1 = x[1] - x[17]; + x[16] += x[0]; + x[17] += x[1]; + x[0] = MULT_NORM( r1 * cPI3_8 + r0 * cPI1_8 ); + x[1] = MULT_NORM( r1 * cPI1_8 - r0 * cPI3_8 ); + + mdct_butterfly_16(x); + mdct_butterfly_16(x+16); + +} + +/* N point first stage butterfly (in place, 2 register) */ +STIN void mdct_butterfly_first(DATA_TYPE *T, + DATA_TYPE *x, + int points){ + + DATA_TYPE *x1 = x + points - 8; + DATA_TYPE *x2 = x + (points>>1) - 8; + REG_TYPE r0; + REG_TYPE r1; + + do{ + + r0 = x1[6] - x2[6]; + r1 = x1[7] - x2[7]; + x1[6] += x2[6]; + x1[7] += x2[7]; + x2[6] = MULT_NORM(r1 * T[1] + r0 * T[0]); + x2[7] = MULT_NORM(r1 * T[0] - r0 * T[1]); + + r0 = x1[4] - x2[4]; + r1 = x1[5] - x2[5]; + x1[4] += x2[4]; + x1[5] += x2[5]; + x2[4] = MULT_NORM(r1 * T[5] + r0 * T[4]); + x2[5] = MULT_NORM(r1 * T[4] - r0 * T[5]); + + r0 = x1[2] - x2[2]; + r1 = x1[3] - x2[3]; + x1[2] += x2[2]; + x1[3] += x2[3]; + x2[2] = MULT_NORM(r1 * T[9] + r0 * T[8]); + x2[3] = MULT_NORM(r1 * T[8] - r0 * T[9]); + + r0 = x1[0] - x2[0]; + r1 = x1[1] - x2[1]; + x1[0] += x2[0]; + x1[1] += x2[1]; + x2[0] = MULT_NORM(r1 * T[13] + r0 * T[12]); + x2[1] = MULT_NORM(r1 * T[12] - r0 * T[13]); + + x1-=8; + x2-=8; + T+=16; + + }while(x2>=x); +} + +/* N/stage point generic N stage butterfly (in place, 2 register) */ +STIN void mdct_butterfly_generic(DATA_TYPE *T, + DATA_TYPE *x, + int points, + int trigint){ + + DATA_TYPE *x1 = x + points - 8; + DATA_TYPE *x2 = x + (points>>1) - 8; + REG_TYPE r0; + REG_TYPE r1; + + do{ + + r0 = x1[6] - x2[6]; + r1 = x1[7] - x2[7]; + x1[6] += x2[6]; + x1[7] += x2[7]; + x2[6] = MULT_NORM(r1 * T[1] + r0 * T[0]); + x2[7] = MULT_NORM(r1 * T[0] - r0 * T[1]); + + T+=trigint; + + r0 = x1[4] - x2[4]; + r1 = x1[5] - x2[5]; + x1[4] += x2[4]; + x1[5] += x2[5]; + x2[4] = MULT_NORM(r1 * T[1] + r0 * T[0]); + x2[5] = MULT_NORM(r1 * T[0] - r0 * T[1]); + + T+=trigint; + + r0 = x1[2] - x2[2]; + r1 = x1[3] - x2[3]; + x1[2] += x2[2]; + x1[3] += x2[3]; + x2[2] = MULT_NORM(r1 * T[1] + r0 * T[0]); + x2[3] = MULT_NORM(r1 * T[0] - r0 * T[1]); + + T+=trigint; + + r0 = x1[0] - x2[0]; + r1 = x1[1] - x2[1]; + x1[0] += x2[0]; + x1[1] += x2[1]; + x2[0] = MULT_NORM(r1 * T[1] + r0 * T[0]); + x2[1] = MULT_NORM(r1 * T[0] - r0 * T[1]); + + T+=trigint; + x1-=8; + x2-=8; + + }while(x2>=x); +} + +STIN void mdct_butterflies(mdct_lookup *init, + DATA_TYPE *x, + int points){ + + DATA_TYPE *T=init->trig; + int stages=init->log2n-5; + int i,j; + + if(--stages>0){ + mdct_butterfly_first(T,x,points); + } + + for(i=1;--stages>0;i++){ + for(j=0;j<(1<>i)*j,points>>i,4<trig)_ogg_free(l->trig); + if(l->bitrev)_ogg_free(l->bitrev); + memset(l,0,sizeof(*l)); + } +} + +STIN void mdct_bitreverse(mdct_lookup *init, + DATA_TYPE *x){ + int n = init->n; + int *bit = init->bitrev; + DATA_TYPE *w0 = x; + DATA_TYPE *w1 = x = w0+(n>>1); + DATA_TYPE *T = init->trig+n; + + do{ + DATA_TYPE *x0 = x+bit[0]; + DATA_TYPE *x1 = x+bit[1]; + + REG_TYPE r0 = x0[1] - x1[1]; + REG_TYPE r1 = x0[0] + x1[0]; + REG_TYPE r2 = MULT_NORM(r1 * T[0] + r0 * T[1]); + REG_TYPE r3 = MULT_NORM(r1 * T[1] - r0 * T[0]); + + w1 -= 4; + + r0 = HALVE(x0[1] + x1[1]); + r1 = HALVE(x0[0] - x1[0]); + + w0[0] = r0 + r2; + w1[2] = r0 - r2; + w0[1] = r1 + r3; + w1[3] = r3 - r1; + + x0 = x+bit[2]; + x1 = x+bit[3]; + + r0 = x0[1] - x1[1]; + r1 = x0[0] + x1[0]; + r2 = MULT_NORM(r1 * T[2] + r0 * T[3]); + r3 = MULT_NORM(r1 * T[3] - r0 * T[2]); + + r0 = HALVE(x0[1] + x1[1]); + r1 = HALVE(x0[0] - x1[0]); + + w0[2] = r0 + r2; + w1[0] = r0 - r2; + w0[3] = r1 + r3; + w1[1] = r3 - r1; + + T += 4; + bit += 4; + w0 += 4; + + }while(w0n; + int n2=n>>1; + int n4=n>>2; + + /* rotate */ + + DATA_TYPE *iX = in+n2-7; + DATA_TYPE *oX = out+n2+n4; + DATA_TYPE *T = init->trig+n4; + + do{ + oX -= 4; + oX[0] = MULT_NORM(-iX[2] * T[3] - iX[0] * T[2]); + oX[1] = MULT_NORM (iX[0] * T[3] - iX[2] * T[2]); + oX[2] = MULT_NORM(-iX[6] * T[1] - iX[4] * T[0]); + oX[3] = MULT_NORM (iX[4] * T[1] - iX[6] * T[0]); + iX -= 8; + T += 4; + }while(iX>=in); + + iX = in+n2-8; + oX = out+n2+n4; + T = init->trig+n4; + + do{ + T -= 4; + oX[0] = MULT_NORM (iX[4] * T[3] + iX[6] * T[2]); + oX[1] = MULT_NORM (iX[4] * T[2] - iX[6] * T[3]); + oX[2] = MULT_NORM (iX[0] * T[1] + iX[2] * T[0]); + oX[3] = MULT_NORM (iX[0] * T[0] - iX[2] * T[1]); + iX -= 8; + oX += 4; + }while(iX>=in); + + mdct_butterflies(init,out+n2,n2); + mdct_bitreverse(init,out); + + /* roatate + window */ + + { + DATA_TYPE *oX1=out+n2+n4; + DATA_TYPE *oX2=out+n2+n4; + DATA_TYPE *iX =out; + T =init->trig+n2; + + do{ + oX1-=4; + + oX1[3] = MULT_NORM (iX[0] * T[1] - iX[1] * T[0]); + oX2[0] = -MULT_NORM (iX[0] * T[0] + iX[1] * T[1]); + + oX1[2] = MULT_NORM (iX[2] * T[3] - iX[3] * T[2]); + oX2[1] = -MULT_NORM (iX[2] * T[2] + iX[3] * T[3]); + + oX1[1] = MULT_NORM (iX[4] * T[5] - iX[5] * T[4]); + oX2[2] = -MULT_NORM (iX[4] * T[4] + iX[5] * T[5]); + + oX1[0] = MULT_NORM (iX[6] * T[7] - iX[7] * T[6]); + oX2[3] = -MULT_NORM (iX[6] * T[6] + iX[7] * T[7]); + + oX2+=4; + iX += 8; + T += 8; + }while(iXoX2); + } +} + +void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out){ + int n=init->n; + int n2=n>>1; + int n4=n>>2; + int n8=n>>3; + DATA_TYPE *w=alloca(n*sizeof(*w)); /* forward needs working space */ + DATA_TYPE *w2=w+n2; + + /* rotate */ + + /* window + rotate + step 1 */ + + REG_TYPE r0; + REG_TYPE r1; + DATA_TYPE *x0=in+n2+n4; + DATA_TYPE *x1=x0+1; + DATA_TYPE *T=init->trig+n2; + + int i=0; + + for(i=0;itrig+n2; + x0=out+n2; + + for(i=0;iscale); + x0[0] =MULT_NORM((w[0]*T[1]-w[1]*T[0])*init->scale); + w+=2; + T+=2; + } +} diff --git a/vendor/vorbis/lib/mdct.h b/vendor/vorbis/lib/mdct.h new file mode 100644 index 0000000..ceaea61 --- /dev/null +++ b/vendor/vorbis/lib/mdct.h @@ -0,0 +1,70 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: modified discrete cosine transform prototypes + + ********************************************************************/ + +#ifndef _OGG_mdct_H_ +#define _OGG_mdct_H_ + +#include "vorbis/codec.h" + + + + + +/*#define MDCT_INTEGERIZED <- be warned there could be some hurt left here*/ +#ifdef MDCT_INTEGERIZED + +#define DATA_TYPE int +#define REG_TYPE register int +#define TRIGBITS 14 +#define cPI3_8 6270 +#define cPI2_8 11585 +#define cPI1_8 15137 + +#define FLOAT_CONV(x) ((int)((x)*(1<>TRIGBITS) +#define HALVE(x) ((x)>>1) + +#else + +#define DATA_TYPE float +#define REG_TYPE float +#define cPI3_8 .38268343236508977175F +#define cPI2_8 .70710678118654752441F +#define cPI1_8 .92387953251128675613F + +#define FLOAT_CONV(x) (x) +#define MULT_NORM(x) (x) +#define HALVE(x) ((x)*.5f) + +#endif + + +typedef struct { + int n; + int log2n; + + DATA_TYPE *trig; + int *bitrev; + + DATA_TYPE scale; +} mdct_lookup; + +extern void mdct_init(mdct_lookup *lookup,int n); +extern void mdct_clear(mdct_lookup *l); +extern void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out); +extern void mdct_backward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out); + +#endif diff --git a/vendor/vorbis/lib/misc.c b/vendor/vorbis/lib/misc.c new file mode 100644 index 0000000..70a091d --- /dev/null +++ b/vendor/vorbis/lib/misc.c @@ -0,0 +1,216 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ********************************************************************/ + +#define HEAD_ALIGN 32 +#include +#include +#include +#include +#include "vorbis/codec.h" +#define MISC_C +#include "misc.h" +#include + +static pthread_mutex_t memlock=PTHREAD_MUTEX_INITIALIZER; +static void **pointers=NULL; +static long *insertlist=NULL; /* We can't embed this in the pointer list; + a pointer can have any value... */ + +static char **files=NULL; +static long *file_bytes=NULL; +static int filecount=0; + +static int ptop=0; +static int palloced=0; +static int pinsert=0; + +typedef struct { + char *file; + long line; + long ptr; + long bytes; +} head; + +long global_bytes=0; +long start_time=-1; + +static void *_insert(void *ptr,long bytes,char *file,long line){ + ((head *)ptr)->file=file; + ((head *)ptr)->line=line; + ((head *)ptr)->ptr=pinsert; + ((head *)ptr)->bytes=bytes-HEAD_ALIGN; + + pthread_mutex_lock(&memlock); + if(pinsert>=palloced){ + palloced+=64; + if(pointers){ + pointers=(void **)realloc(pointers,sizeof(void **)*palloced); + insertlist=(long *)realloc(insertlist,sizeof(long *)*palloced); + }else{ + pointers=(void **)malloc(sizeof(void **)*palloced); + insertlist=(long *)malloc(sizeof(long *)*palloced); + } + } + + pointers[pinsert]=ptr; + + if(pinsert==ptop) + pinsert=++ptop; + else + pinsert=insertlist[pinsert]; + +#ifdef _VDBG_GRAPHFILE + { + FILE *out; + struct timeval tv; + static struct timezone tz; + int i; + char buffer[80]; + gettimeofday(&tv,&tz); + + for(i=0;ifile; + long bytes =((head *)ptr)->bytes; + int i; + + gettimeofday(&tv,&tz); + fprintf(out,"%ld, %ld\n",-start_time+(tv.tv_sec*1000)+(tv.tv_usec/1000), + global_bytes); + fprintf(out,"%ld, %ld\n",-start_time+(tv.tv_sec*1000)+(tv.tv_usec/1000), + global_bytes-((head *)ptr)->bytes); + fclose(out); + + for(i=0;ibytes; + + insert=((head *)ptr)->ptr; + insertlist[insert]=pinsert; + pinsert=insert; + + if(pointers[insert]==NULL){ + fprintf(stderr,"DEBUGGING MALLOC ERROR: freeing previously freed memory\n"); + fprintf(stderr,"\t%s %ld\n",((head *)ptr)->file,((head *)ptr)->line); + } + + if(global_bytes<0){ + fprintf(stderr,"DEBUGGING MALLOC ERROR: freeing unmalloced memory\n"); + } + + pointers[insert]=NULL; + pthread_mutex_unlock(&memlock); +} + +void _VDBG_dump(void){ + int i; + pthread_mutex_lock(&memlock); + for(i=0;ifile,ptr->line); + } + + pthread_mutex_unlock(&memlock); +} + +void *_VDBG_malloc(void *ptr,long bytes,char *file,long line){ + if(bytes<=0) + fprintf(stderr,"bad malloc request (%ld bytes) from %s:%ld\n",bytes,file,line); + + bytes+=HEAD_ALIGN; + if(ptr){ + ptr-=HEAD_ALIGN; + _ripremove(ptr); + ptr=realloc(ptr,bytes); + }else{ + ptr=malloc(bytes); + memset(ptr,0,bytes); + } + return _insert(ptr,bytes,file,line); +} + +void _VDBG_free(void *ptr,char *file,long line){ + if(ptr){ + ptr-=HEAD_ALIGN; + _ripremove(ptr); + free(ptr); + } +} + diff --git a/vendor/vorbis/lib/misc.h b/vendor/vorbis/lib/misc.h new file mode 100644 index 0000000..eac5160 --- /dev/null +++ b/vendor/vorbis/lib/misc.h @@ -0,0 +1,57 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: miscellaneous prototypes + + ********************************************************************/ + +#ifndef _V_RANDOM_H_ +#define _V_RANDOM_H_ +#include "vorbis/codec.h" + +extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes); +extern void _vorbis_block_ripcord(vorbis_block *vb); +extern int ov_ilog(ogg_uint32_t v); + +#ifdef ANALYSIS +extern int analysis_noisy; +extern void _analysis_output(char *base,int i,float *v,int n,int bark,int dB, + ogg_int64_t off); +extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB, + ogg_int64_t off); +#endif + +#ifdef DEBUG_MALLOC + +#define _VDBG_GRAPHFILE "malloc.m" +#undef _VDBG_GRAPHFILE +extern void *_VDBG_malloc(void *ptr,long bytes,char *file,long line); +extern void _VDBG_free(void *ptr,char *file,long line); + +#ifndef MISC_C +#undef _ogg_malloc +#undef _ogg_calloc +#undef _ogg_realloc +#undef _ogg_free + +#define _ogg_malloc(x) _VDBG_malloc(NULL,(x),__FILE__,__LINE__) +#define _ogg_calloc(x,y) _VDBG_malloc(NULL,(x)*(y),__FILE__,__LINE__) +#define _ogg_realloc(x,y) _VDBG_malloc((x),(y),__FILE__,__LINE__) +#define _ogg_free(x) _VDBG_free((x),__FILE__,__LINE__) +#endif +#endif + +#endif + + + + diff --git a/vendor/vorbis/lib/modes/Makefile.am b/vendor/vorbis/lib/modes/Makefile.am new file mode 100644 index 0000000..5c7ffef --- /dev/null +++ b/vendor/vorbis/lib/modes/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = floor_all.h psych_44.h residue_44.h setup_11.h setup_32.h \ + setup_8.h psych_11.h psych_8.h residue_44u.h setup_16.h \ + setup_44.h setup_X.h psych_16.h residue_16.h residue_8.h \ + setup_22.h setup_44u.h setup_44p51.h residue_44p51.h diff --git a/vendor/vorbis/lib/modes/floor_all.h b/vendor/vorbis/lib/modes/floor_all.h new file mode 100644 index 0000000..2e3d4a5 --- /dev/null +++ b/vendor/vorbis/lib/modes/floor_all.h @@ -0,0 +1,259 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: key floor settings + + ********************************************************************/ + +#include "vorbis/codec.h" +#include "backends.h" +#include "books/floor/floor_books.h" + +static const static_codebook*const _floor_128x4_books[]={ + &_huff_book_line_128x4_class0, + &_huff_book_line_128x4_0sub0, + &_huff_book_line_128x4_0sub1, + &_huff_book_line_128x4_0sub2, + &_huff_book_line_128x4_0sub3, +}; +static const static_codebook*const _floor_256x4_books[]={ + &_huff_book_line_256x4_class0, + &_huff_book_line_256x4_0sub0, + &_huff_book_line_256x4_0sub1, + &_huff_book_line_256x4_0sub2, + &_huff_book_line_256x4_0sub3, +}; +static const static_codebook*const _floor_128x7_books[]={ + &_huff_book_line_128x7_class0, + &_huff_book_line_128x7_class1, + + &_huff_book_line_128x7_0sub1, + &_huff_book_line_128x7_0sub2, + &_huff_book_line_128x7_0sub3, + &_huff_book_line_128x7_1sub1, + &_huff_book_line_128x7_1sub2, + &_huff_book_line_128x7_1sub3, +}; +static const static_codebook*const _floor_256x7_books[]={ + &_huff_book_line_256x7_class0, + &_huff_book_line_256x7_class1, + + &_huff_book_line_256x7_0sub1, + &_huff_book_line_256x7_0sub2, + &_huff_book_line_256x7_0sub3, + &_huff_book_line_256x7_1sub1, + &_huff_book_line_256x7_1sub2, + &_huff_book_line_256x7_1sub3, +}; +static const static_codebook*const _floor_128x11_books[]={ + &_huff_book_line_128x11_class1, + &_huff_book_line_128x11_class2, + &_huff_book_line_128x11_class3, + + &_huff_book_line_128x11_0sub0, + &_huff_book_line_128x11_1sub0, + &_huff_book_line_128x11_1sub1, + &_huff_book_line_128x11_2sub1, + &_huff_book_line_128x11_2sub2, + &_huff_book_line_128x11_2sub3, + &_huff_book_line_128x11_3sub1, + &_huff_book_line_128x11_3sub2, + &_huff_book_line_128x11_3sub3, +}; +static const static_codebook*const _floor_128x17_books[]={ + &_huff_book_line_128x17_class1, + &_huff_book_line_128x17_class2, + &_huff_book_line_128x17_class3, + + &_huff_book_line_128x17_0sub0, + &_huff_book_line_128x17_1sub0, + &_huff_book_line_128x17_1sub1, + &_huff_book_line_128x17_2sub1, + &_huff_book_line_128x17_2sub2, + &_huff_book_line_128x17_2sub3, + &_huff_book_line_128x17_3sub1, + &_huff_book_line_128x17_3sub2, + &_huff_book_line_128x17_3sub3, +}; +static const static_codebook*const _floor_256x4low_books[]={ + &_huff_book_line_256x4low_class0, + &_huff_book_line_256x4low_0sub0, + &_huff_book_line_256x4low_0sub1, + &_huff_book_line_256x4low_0sub2, + &_huff_book_line_256x4low_0sub3, +}; +static const static_codebook*const _floor_1024x27_books[]={ + &_huff_book_line_1024x27_class1, + &_huff_book_line_1024x27_class2, + &_huff_book_line_1024x27_class3, + &_huff_book_line_1024x27_class4, + + &_huff_book_line_1024x27_0sub0, + &_huff_book_line_1024x27_1sub0, + &_huff_book_line_1024x27_1sub1, + &_huff_book_line_1024x27_2sub0, + &_huff_book_line_1024x27_2sub1, + &_huff_book_line_1024x27_3sub1, + &_huff_book_line_1024x27_3sub2, + &_huff_book_line_1024x27_3sub3, + &_huff_book_line_1024x27_4sub1, + &_huff_book_line_1024x27_4sub2, + &_huff_book_line_1024x27_4sub3, +}; +static const static_codebook*const _floor_2048x27_books[]={ + &_huff_book_line_2048x27_class1, + &_huff_book_line_2048x27_class2, + &_huff_book_line_2048x27_class3, + &_huff_book_line_2048x27_class4, + + &_huff_book_line_2048x27_0sub0, + &_huff_book_line_2048x27_1sub0, + &_huff_book_line_2048x27_1sub1, + &_huff_book_line_2048x27_2sub0, + &_huff_book_line_2048x27_2sub1, + &_huff_book_line_2048x27_3sub1, + &_huff_book_line_2048x27_3sub2, + &_huff_book_line_2048x27_3sub3, + &_huff_book_line_2048x27_4sub1, + &_huff_book_line_2048x27_4sub2, + &_huff_book_line_2048x27_4sub3, +}; + +static const static_codebook*const _floor_512x17_books[]={ + &_huff_book_line_512x17_class1, + &_huff_book_line_512x17_class2, + &_huff_book_line_512x17_class3, + + &_huff_book_line_512x17_0sub0, + &_huff_book_line_512x17_1sub0, + &_huff_book_line_512x17_1sub1, + &_huff_book_line_512x17_2sub1, + &_huff_book_line_512x17_2sub2, + &_huff_book_line_512x17_2sub3, + &_huff_book_line_512x17_3sub1, + &_huff_book_line_512x17_3sub2, + &_huff_book_line_512x17_3sub3, +}; + +static const static_codebook*const _floor_Xx0_books[]={ + 0 +}; + +static const static_codebook*const *const _floor_books[11]={ + _floor_128x4_books, + _floor_256x4_books, + _floor_128x7_books, + _floor_256x7_books, + _floor_128x11_books, + _floor_128x17_books, + _floor_256x4low_books, + _floor_1024x27_books, + _floor_2048x27_books, + _floor_512x17_books, + _floor_Xx0_books, +}; + +static const vorbis_info_floor1 _floor[11]={ + /* 0: 128 x 4 */ + { + 1,{0},{4},{2},{0}, + {{1,2,3,4}}, + 4,{0,128, 33,8,16,70}, + + 60,30,500, 1.,18., 128 + }, + /* 1: 256 x 4 */ + { + 1,{0},{4},{2},{0}, + {{1,2,3,4}}, + 4,{0,256, 66,16,32,140}, + + 60,30,500, 1.,18., 256 + }, + /* 2: 128 x 7 */ + { + 2,{0,1},{3,4},{2,2},{0,1}, + {{-1,2,3,4},{-1,5,6,7}}, + 4,{0,128, 14,4,58, 2,8,28,90}, + + 60,30,500, 1.,18., 128 + }, + /* 3: 256 x 7 */ + { + 2,{0,1},{3,4},{2,2},{0,1}, + {{-1,2,3,4},{-1,5,6,7}}, + 4,{0,256, 28,8,116, 4,16,56,180}, + + 60,30,500, 1.,18., 256 + }, + /* 4: 128 x 11 */ + { + 4,{0,1,2,3},{2,3,3,3},{0,1,2,2},{-1,0,1,2}, + {{3},{4,5},{-1,6,7,8},{-1,9,10,11}}, + + 2,{0,128, 8,33, 4,16,70, 2,6,12, 23,46,90}, + + 60,30,500, 1,18., 128 + }, + /* 5: 128 x 17 */ + { + 6,{0,1,1,2,3,3},{2,3,3,3},{0,1,2,2},{-1,0,1,2}, + {{3},{4,5},{-1,6,7,8},{-1,9,10,11}}, + 2,{0,128, 12,46, 4,8,16, 23,33,70, 2,6,10, 14,19,28, 39,58,90}, + + 60,30,500, 1,18., 128 + }, + /* 6: 256 x 4 (low bitrate version) */ + { + 1,{0},{4},{2},{0}, + {{1,2,3,4}}, + 4,{0,256, 66,16,32,140}, + + 60,30,500, 1.,18., 256 + }, + /* 7: 1024 x 27 */ + { + 8,{0,1,2,2,3,3,4,4},{3,4,3,4,3},{0,1,1,2,2},{-1,0,1,2,3}, + {{4},{5,6},{7,8},{-1,9,10,11},{-1,12,13,14}}, + 2,{0,1024, 93,23,372, 6,46,186,750, 14,33,65, 130,260,556, + 3,10,18,28, 39,55,79,111, 158,220,312, 464,650,850}, + + 60,30,500, 3,18., 1024 + }, + /* 8: 2048 x 27 */ + { + 8,{0,1,2,2,3,3,4,4},{3,4,3,4,3},{0,1,1,2,2},{-1,0,1,2,3}, + {{4},{5,6},{7,8},{-1,9,10,11},{-1,12,13,14}}, + 2,{0,2048, 186,46,744, 12,92,372,1500, 28,66,130, 260,520,1112, + 6,20,36,56, 78,110,158,222, 316,440,624, 928,1300,1700}, + + 60,30,500, 3,18., 2048 + }, + /* 9: 512 x 17 */ + { + 6,{0,1,1,2,3,3},{2,3,3,3},{0,1,2,2},{-1,0,1,2}, + {{3},{4,5},{-1,6,7,8},{-1,9,10,11}}, + 2,{0,512, 46,186, 16,33,65, 93,130,278, + 7,23,39, 55,79,110, 156,232,360}, + + 60,30,500, 1,18., 512 + }, + + /* 10: X x 0 (LFE floor; edge posts only) */ + { + 0,{0}, {0},{0},{-1}, + {{-1}}, + 2,{0,12}, + 60,30,500, 1.,18., 10 + }, + +}; diff --git a/vendor/vorbis/lib/modes/psych_11.h b/vendor/vorbis/lib/modes/psych_11.h new file mode 100644 index 0000000..9d8ed35 --- /dev/null +++ b/vendor/vorbis/lib/modes/psych_11.h @@ -0,0 +1,50 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: 11kHz settings + + ********************************************************************/ + +static const double _psy_lowpass_11[3]={4.5,5.5,30.,}; + +static const att3 _psy_tone_masteratt_11[3]={ + {{ 30, 25, 12}, 0, 0}, /* 0 */ + {{ 30, 25, 12}, 0, 0}, /* 0 */ + {{ 20, 0, -14}, 0, 0}, /* 0 */ +}; + +static const vp_adjblock _vp_tonemask_adj_11[3]={ + /* adjust for mode zero */ + /* 63 125 250 500 1 2 4 8 16 */ + {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0,10, 2, 0,99,99,99}}, /* 0 */ + {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0, 5, 0, 0,99,99,99}}, /* 1 */ + {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0, 0, 0, 0,99,99,99}}, /* 2 */ +}; + + +static const noise3 _psy_noisebias_11[3]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 10, 10, 12, 12, 12, 99, 99, 99}, + {-15,-15,-15,-15,-10,-10, -5, 0, 0, 4, 4, 5, 5, 10, 99, 99, 99}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}}, + + {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 10, 10, 12, 12, 12, 99, 99, 99}, + {-15,-15,-15,-15,-10,-10, -5, -5, -5, 0, 0, 0, 0, 0, 99, 99, 99}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 99, 99, 99}, + {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10, 99, 99, 99}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24, 99, 99, 99}}}, +}; + +static const double _noise_thresh_11[3]={ .3,.5,.5 }; + diff --git a/vendor/vorbis/lib/modes/psych_16.h b/vendor/vorbis/lib/modes/psych_16.h new file mode 100644 index 0000000..49cbf7c --- /dev/null +++ b/vendor/vorbis/lib/modes/psych_16.h @@ -0,0 +1,132 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: 16kHz settings + + ********************************************************************/ + +/* stereo mode by base quality level */ +static const adj_stereo _psy_stereo_modes_16[4]={ + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */ + {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, + { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, + { 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + {{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + { 5, 4, 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}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, +}; + +static const double _psy_lowpass_16[4]={6.5,8,30.,99.}; + +static const att3 _psy_tone_masteratt_16[4]={ + {{ 30, 25, 12}, 0, 0}, /* 0 */ + {{ 25, 22, 12}, 0, 0}, /* 0 */ + {{ 20, 12, 0}, 0, 0}, /* 0 */ + {{ 15, 0, -14}, 0, 0}, /* 0 */ +}; + +static const vp_adjblock _vp_tonemask_adj_16[4]={ + /* adjust for mode zero */ + /* 63 125 250 500 1 2 4 8 16 */ + {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0,10, 0, 0, 0, 0, 0}}, /* 0 */ + {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0,10, 0, 0, 0, 0, 0}}, /* 1 */ + {{-20,-20,-20,-20,-20,-16,-10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 2 */ + {{-30,-30,-30,-30,-30,-26,-20,-10, -5, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 2 */ +}; + + +static const noise3 _psy_noisebias_16_short[4]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 10, 10, 10, 10, 12, 12, 14, 20}, + {-15,-15,-15,-15,-15,-10,-10, -5, 0, 0, 4, 5, 5, 6, 8, 8, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}}, + + {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 6, 6, 6, 6, 8, 10, 12, 20}, + {-15,-15,-15,-15,-15,-15,-15,-10, -5, -5, -5, 4, 5, 6, 8, 8, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10,-10,-10,-10,-10,-10,-10,-10,-10}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 12}, + {-20,-20,-20,-20,-16,-12,-20,-14,-10,-10, -8, 0, 0, 0, 0, 2, 5}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, -5, -5, -5, -5, -5, 0, 0, 0, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10,-10,-10, -6}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}}, +}; + +static const noise3 _psy_noisebias_16_impulse[4]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 10, 10, 10, 10, 12, 12, 14, 20}, + {-15,-15,-15,-15,-15,-10,-10, -5, 0, 0, 4, 5, 5, 6, 8, 8, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}}, + + {{{-15,-15,-15,-15,-15,-10,-10,-5, 4, 4, 4, 4, 5, 5, 6, 8, 15}, + {-15,-15,-15,-15,-15,-15,-15,-10, -5, -5, -5, 0, 0, 0, 0, 4, 10}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10,-10,-10,-10,-10,-10,-10,-10,-10}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 4, 10}, + {-20,-20,-20,-20,-16,-12,-20,-14,-10,-10,-10,-10,-10,-10,-10, -7, -5}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, -5, -5, -5, -5, -5, 0, 0, 0, 6}, + {-30,-30,-30,-30,-26,-22,-20,-18,-18,-18,-20,-20,-20,-20,-20,-20,-16}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}}, +}; + +static const noise3 _psy_noisebias_16[4]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 6, 8, 8, 10, 10, 10, 14, 20}, + {-10,-10,-10,-10,-10, -5, -2, -2, 0, 0, 0, 4, 5, 6, 8, 8, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}}, + + {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 6, 6, 6, 6, 8, 10, 12, 20}, + {-15,-15,-15,-15,-15,-10, -5, -5, 0, 0, 0, 4, 5, 6, 8, 8, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -6, -6}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 12}, + {-20,-20,-20,-20,-16,-12,-20,-10, -5, -5, 0, 0, 0, 0, 0, 2, 5}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, -5, -5, -5, -5, -5, 0, 0, 0, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10,-10,-10, -6}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24,-20,-20,-20}}}, +}; + +static const noiseguard _psy_noiseguards_16[4]={ + {10,10,-1}, + {10,10,-1}, + {20,20,-1}, + {20,20,-1}, +}; + +static const double _noise_thresh_16[4]={ .3,.5,.5,.5 }; + +static const int _noise_start_16[3]={ 256,256,9999 }; +static const int _noise_part_16[4]={ 8,8,8,8 }; + +static const int _psy_ath_floater_16[4]={ + -100,-100,-100,-105, +}; + +static const int _psy_ath_abs_16[4]={ + -130,-130,-130,-140, +}; diff --git a/vendor/vorbis/lib/modes/psych_44.h b/vendor/vorbis/lib/modes/psych_44.h new file mode 100644 index 0000000..d15509b --- /dev/null +++ b/vendor/vorbis/lib/modes/psych_44.h @@ -0,0 +1,641 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: key psychoacoustic settings for 44.1/48kHz + + ********************************************************************/ + + +/* preecho trigger settings *****************************************/ + +static const vorbis_info_psy_global _psy_global_44[5]={ + + {8, /* lines per eighth octave */ + {20.f,14.f,12.f,12.f,12.f,12.f,12.f}, + {-60.f,-30.f,-40.f,-40.f,-40.f,-40.f,-40.f}, 2,-75.f, + -6.f, + {99.},{{99.},{99.}},{0},{0},{{0.},{0.}} + }, + {8, /* lines per eighth octave */ + {14.f,10.f,10.f,10.f,10.f,10.f,10.f}, + {-40.f,-30.f,-25.f,-25.f,-25.f,-25.f,-25.f}, 2,-80.f, + -6.f, + {99.},{{99.},{99.}},{0},{0},{{0.},{0.}} + }, + {8, /* lines per eighth octave */ + {12.f,10.f,10.f,10.f,10.f,10.f,10.f}, + {-20.f,-20.f,-15.f,-15.f,-15.f,-15.f,-15.f}, 0,-80.f, + -6.f, + {99.},{{99.},{99.}},{0},{0},{{0.},{0.}} + }, + {8, /* lines per eighth octave */ + {10.f,8.f,8.f,8.f,8.f,8.f,8.f}, + {-20.f,-15.f,-12.f,-12.f,-12.f,-12.f,-12.f}, 0,-80.f, + -6.f, + {99.},{{99.},{99.}},{0},{0},{{0.},{0.}} + }, + {8, /* lines per eighth octave */ + {10.f,6.f,6.f,6.f,6.f,6.f,6.f}, + {-15.f,-15.f,-12.f,-12.f,-12.f,-12.f,-12.f}, 0,-85.f, + -6.f, + {99.},{{99.},{99.}},{0},{0},{{0.},{0.}} + }, +}; + +/* noise compander lookups * low, mid, high quality ****************/ +static const compandblock _psy_compand_44[6]={ + /* sub-mode Z short */ + {{ + 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */ + 8, 9,10,11,12,13,14, 15, /* 15dB */ + 16,17,18,19,20,21,22, 23, /* 23dB */ + 24,25,26,27,28,29,30, 31, /* 31dB */ + 32,33,34,35,36,37,38, 39, /* 39dB */ + }}, + /* mode_Z nominal short */ + {{ + 0, 1, 2, 3, 4, 5, 6, 6, /* 7dB */ + 7, 7, 7, 7, 6, 6, 6, 7, /* 15dB */ + 7, 8, 9,10,11,12,13, 14, /* 23dB */ + 15,16,17,17,17,18,18, 19, /* 31dB */ + 19,19,20,21,22,23,24, 25, /* 39dB */ + }}, + /* mode A short */ + {{ + 0, 1, 2, 3, 4, 5, 5, 5, /* 7dB */ + 6, 6, 6, 5, 4, 4, 4, 4, /* 15dB */ + 4, 4, 5, 5, 5, 6, 6, 6, /* 23dB */ + 7, 7, 7, 8, 8, 8, 9, 10, /* 31dB */ + 11,12,13,14,15,16,17, 18, /* 39dB */ + }}, + /* sub-mode Z long */ + {{ + 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */ + 8, 9,10,11,12,13,14, 15, /* 15dB */ + 16,17,18,19,20,21,22, 23, /* 23dB */ + 24,25,26,27,28,29,30, 31, /* 31dB */ + 32,33,34,35,36,37,38, 39, /* 39dB */ + }}, + /* mode_Z nominal long */ + {{ + 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */ + 8, 9,10,11,12,12,13, 13, /* 15dB */ + 13,14,14,14,15,15,15, 15, /* 23dB */ + 16,16,17,17,17,18,18, 19, /* 31dB */ + 19,19,20,21,22,23,24, 25, /* 39dB */ + }}, + /* mode A long */ + {{ + 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */ + 8, 8, 7, 6, 5, 4, 4, 4, /* 15dB */ + 4, 4, 5, 5, 5, 6, 6, 6, /* 23dB */ + 7, 7, 7, 8, 8, 8, 9, 10, /* 31dB */ + 11,12,13,14,15,16,17, 18, /* 39dB */ + }} +}; + +/* tonal masking curve level adjustments *************************/ + +static const vp_adjblock _vp_tonemask_adj_longblock[12]={ + + /* 63 125 250 500 1 2 4 8 16 */ + + {{ -3, -8,-13,-15,-10,-10,-10,-10,-10,-10,-10, 0, 0, 0, 0, 0, 0}}, /* -1 */ + +/* {{-15,-15,-15,-15,-10, -8, -4, -2, 0, 0, 0, 10, 0, 0, 0, 0, 0}}, 0 */ + {{ -4,-10,-14,-16,-15,-14,-13,-12,-12,-12,-11, -1, -1, -1, -1, -1, 0}}, /* 0 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 5, 0, 0, 0, 0, 0}}, 1 */ + {{ -6,-12,-14,-16,-15,-15,-14,-13,-13,-12,-12, -2, -2, -1, -1, -1, 0}}, /* 1 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 2 */ + {{-12,-13,-14,-16,-16,-16,-15,-14,-13,-12,-12, -6, -3, -1, -1, -1, 0}}, /* 2 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 3 */ + {{-15,-15,-15,-16,-16,-16,-16,-14,-13,-13,-13,-10, -4, -2, -1, -1, 0}}, /* 3 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, *//* 4 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 4 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 5 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 5 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 6 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -8, -4, -2, -2, 0}}, /* 6 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 7 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 7 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 8 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 8 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 9 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 9 */ + +/* {{-15,-15,-15,-15,-15,-12,-10, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 10 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 10 */ +}; + +static const vp_adjblock _vp_tonemask_adj_otherblock[12]={ + /* 63 125 250 500 1 2 4 8 16 */ + + {{ -3, -8,-13,-15,-10,-10, -9, -9, -9, -9, -9, 1, 1, 1, 1, 1, 1}}, /* -1 */ + +/* {{-20,-20,-20,-20,-14,-12,-10, -8, -4, 0, 0, 10, 0, 0, 0, 0, 0}}, 0 */ + {{ -4,-10,-14,-16,-14,-13,-12,-12,-11,-11,-10, 0, 0, 0, 0, 0, 0}}, /* 0 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 5, 0, 0, 0, 0, 0}}, 1 */ + {{ -6,-12,-14,-16,-15,-15,-14,-13,-13,-12,-12, -2, -2, -1, 0, 0, 0}}, /* 1 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 2 */ + {{-12,-13,-14,-16,-16,-16,-15,-14,-13,-12,-12, -5, -2, -1, 0, 0, 0}}, /* 2 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 3 */ + {{-15,-15,-15,-16,-16,-16,-16,-14,-13,-13,-13,-10, -4, -2, 0, 0, 0}}, /* 3 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 4 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 4 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 5 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-13,-11, -7 -3, -1, -1 , 0}}, /* 5 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 6 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -8, -4, -2, -2, 0}}, /* 6 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 7 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 7 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 8 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 8 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 9 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 9 */ + +/* {{-20,-20,-20,-20,-20,-18,-16,-14,-10, 0, 0, 0, 0, 0, 0, 0, 0}}, 10 */ + {{-16,-16,-16,-16,-16,-16,-16,-15,-14,-14,-14,-12, -9, -4, -2, -2, 0}}, /* 10 */ +}; + +/* noise bias (transition block) */ +static const noise3 _psy_noisebias_trans[12]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + /* -1 */ + {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-20,-16, -8, -6, -6, -2, 2, 2, 3, 6, 6, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}}, + /* 0 + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14, -8, -4, 0, 0, 0, 0, 2, 4, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -6, -4, -4, -4, -2}}},*/ + {{{-15,-15,-15,-15,-15,-12, -6, -4, 0, 2, 4, 4, 5, 5, 5, 8, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14, -8, -4, 0, 0, 0, 0, 2, 3, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -6, -4, -4, -4, -2}}}, + /* 1 + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 8}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}},*/ + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 5, 8, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, -2, -2, -2, 0, 1, 4}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}}, + /* 2 + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}}, */ + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -2, -1, 0, 3}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -7, -4}}}, + /* 3 + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/ + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -2, 0, 2}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}}, + /* 4 + {{{-20,-20,-20,-20,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 5}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/ + {{{-20,-20,-20,-20,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -3, -3, -2, -1, 1}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}}, + /* 5 + {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-32,-32,-32,-32,-28,-24,-22,-16,-12, -6, -4, -4, -4, -4, -2, -1, 2}, + {-34,-34,-34,-34,-30,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -5}}}, */ + {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-32,-32,-32,-32,-28,-24,-22,-16,-12, -6, -4, -4, -4, -4, -3, -1, 0}, + {-34,-34,-34,-34,-30,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -5}}}, + /* 6 + {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-32,-32,-32,-32,-28,-24,-24,-18,-14, -8, -6, -6, -6, -6, -4, -2, 1}, + {-34,-34,-34,-34,-30,-26,-24,-18,-17,-15,-15,-15,-15,-13,-13,-12, -8}}},*/ + {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-32,-32,-32,-32,-28,-24,-24,-18,-14, -8, -6, -6, -6, -6, -5, -2, 0}, + {-34,-34,-34,-34,-30,-26,-26,-24,-22,-19,-19,-19,-19,-18,-17,-16,-12}}}, + /* 7 + {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-32,-32,-32,-32,-28,-24,-24,-18,-14,-12,-10, -8, -8, -8, -6, -4, 0}, + {-34,-34,-34,-34,-30,-26,-26,-24,-22,-19,-19,-19,-19,-18,-17,-16,-12}}},*/ + {{{-24,-24,-24,-24,-20,-18,-14, -8, -1, 1, 1, 1, 2, 3, 3, 4, 7}, + {-32,-32,-32,-32,-28,-24,-24,-24,-18,-14,-12,-10,-10,-10, -8, -6, -2}, + {-34,-34,-34,-34,-30,-26,-26,-26,-24,-24,-24,-24,-24,-24,-24,-20,-16}}}, + /* 8 + {{{-24,-24,-24,-24,-22,-20,-15,-10, -8, -2, 0, 0, 0, 1, 2, 3, 7}, + {-36,-36,-36,-36,-30,-30,-30,-24,-18,-14,-12,-10,-10,-10, -8, -6, -2}, + {-36,-36,-36,-36,-34,-30,-28,-26,-24,-24,-24,-24,-24,-24,-24,-20,-16}}},*/ + {{{-24,-24,-24,-24,-22,-20,-15,-10, -8, -2, 0, 0, 0, 1, 2, 3, 7}, + {-36,-36,-36,-36,-30,-30,-30,-24,-20,-16,-16,-16,-16,-14,-12,-10, -7}, + {-36,-36,-36,-36,-34,-30,-28,-26,-24,-30,-30,-30,-30,-30,-30,-24,-20}}}, + /* 9 + {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2}, + {-36,-36,-36,-36,-34,-32,-32,-28,-20,-16,-16,-16,-16,-14,-12,-10, -7}, + {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-24,-20}}},*/ + {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2}, + {-38,-38,-38,-38,-36,-34,-34,-30,-24,-20,-20,-20,-20,-18,-16,-12,-10}, + {-40,-40,-40,-40,-40,-40,-40,-38,-35,-35,-35,-35,-35,-35,-35,-35,-30}}}, + /* 10 */ + {{{-30,-30,-30,-30,-30,-30,-30,-28,-20,-14,-14,-14,-14,-14,-14,-12,-10}, + {-40,-40,-40,-40,-40,-40,-40,-40,-35,-30,-30,-30,-30,-30,-30,-30,-20}, + {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}}, +}; + +/* noise bias (long block) */ +static const noise3 _psy_noisebias_long[12]={ + /*63 125 250 500 1k 2k 4k 8k 16k*/ + /* -1 */ + {{{-10,-10,-10,-10,-10, -4, 0, 0, 0, 6, 6, 6, 6, 10, 10, 12, 20}, + {-20,-20,-20,-20,-20,-20,-10, -2, 0, 0, 0, 0, 0, 2, 4, 6, 15}, + {-20,-20,-20,-20,-20,-20,-20,-10, -6, -6, -6, -6, -6, -4, -4, -4, -2}}}, + + /* 0 */ + /* {{{-10,-10,-10,-10,-10,-10, -8, 2, 2, 2, 4, 4, 5, 5, 5, 8, 10}, + {-20,-20,-20,-20,-20,-20,-20,-14, -6, 0, 0, 0, 0, 0, 2, 4, 10}, + {-20,-20,-20,-20,-20,-20,-20,-14, -8, -6, -6, -6, -6, -4, -4, -4, -2}}},*/ + {{{-10,-10,-10,-10,-10,-10, -8, 2, 2, 2, 4, 4, 5, 5, 5, 8, 10}, + {-20,-20,-20,-20,-20,-20,-20,-14, -6, 0, 0, 0, 0, 0, 2, 3, 6}, + {-20,-20,-20,-20,-20,-20,-20,-14, -8, -6, -6, -6, -6, -4, -4, -4, -2}}}, + /* 1 */ + /* {{{-10,-10,-10,-10,-10,-10, -8, -4, 0, 2, 4, 4, 5, 5, 5, 8, 10}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 8}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}},*/ + {{{-10,-10,-10,-10,-10,-10, -8, -4, 0, 2, 4, 4, 5, 5, 5, 8, 10}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -2, -2, -2, -2, 0, 1, 4}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -8, -8, -8, -8, -6, -6, -6, -4}}}, + /* 2 */ + /* {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -2, -2, -2, -2, 0, 2, 6}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/ + {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 5, 6, 10}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -2, -1, 0, 3}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}}, + /* 3 */ + /* {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 6}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/ + {{{-10,-10,-10,-10,-10,-10,-10, -8, 0, 2, 2, 2, 4, 4, 4, 5, 8}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -2, 0, 2}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -5}}}, + /* 4 */ + /* {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -1, 1, 5}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -4}}},*/ + {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10, -4, -3, -3, -3, -3, -2, -1, 1}, + {-20,-20,-20,-20,-20,-20,-20,-14,-10,-10,-10,-10,-10, -8, -8, -8, -7}}}, + /* 5 */ + /* {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7}, + {-22,-22,-22,-22,-22,-22,-22,-16,-12, -6, -4, -4, -4, -4, -2, -1, 2}, + {-24,-24,-24,-24,-24,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -5}}},*/ + {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7}, + {-22,-22,-22,-22,-22,-22,-22,-16,-12, -6, -4, -4, -4, -4, -3, -1, 0}, + {-24,-24,-24,-24,-24,-24,-24,-18,-14,-12,-12,-12,-12,-10,-10, -9, -8}}}, + /* 6 */ + /* {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7}, + {-24,-24,-24,-24,-24,-24,-24,-18,-14, -8, -6, -6, -6, -6, -4, -2, 1}, + {-26,-26,-26,-26,-26,-26,-26,-18,-16,-15,-15,-15,-15,-13,-13,-12, -8}}},*/ + {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7}, + {-24,-24,-24,-24,-24,-24,-24,-18,-14, -8, -6, -6, -6, -6, -5, -2, 0}, + {-26,-26,-26,-26,-26,-26,-26,-18,-16,-15,-15,-15,-15,-13,-13,-12,-10}}}, + /* 7 */ + {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 1, 1, 1, 2, 3, 3, 4, 7}, + {-24,-24,-24,-24,-24,-24,-24,-18,-14,-10, -8, -8, -8, -8, -6, -4, 0}, + {-26,-26,-26,-26,-26,-26,-26,-22,-20,-19,-19,-19,-19,-18,-17,-16,-12}}}, + /* 8 */ + {{{-15,-15,-15,-15,-15,-15,-15,-10, -4, 0, 0, 0, 0, 1, 2, 3, 7}, + {-26,-26,-26,-26,-26,-26,-26,-20,-16,-12,-10,-10,-10,-10, -8, -6, -2}, + {-28,-28,-28,-28,-28,-28,-28,-26,-24,-24,-24,-24,-24,-24,-24,-20,-16}}}, + /* 9 */ + {{{-22,-22,-22,-22,-22,-22,-22,-18,-14, -8, -4, -4, -4, -4, -4, -2, 2}, + {-26,-26,-26,-26,-26,-26,-26,-22,-18,-16,-16,-16,-16,-14,-12,-10, -7}, + {-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-24,-20}}}, + /* 10 */ + {{{-24,-24,-24,-24,-24,-24,-24,-24,-24,-18,-14,-14,-14,-14,-14,-12,-10}, + {-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-20}, + {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}}, +}; + +/* noise bias (impulse block) */ +static const noise3 _psy_noisebias_impulse[12]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + /* -1 */ + {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-20,-16, -8, -6, -6, -2, 2, 2, 3, 6, 6, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}}, + + /* 0 */ + /* {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 4, 8, 8, 8, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-22,-20,-14, -6, -2, 0, 0, 0, 0, 2, 4, 10}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}},*/ + {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 4, 8, 8, 8, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-22,-20,-14, -6, -2, 0, 0, 0, 0, 2, 3, 6}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}}, + /* 1 */ + {{{-12,-12,-12,-12,-12, -8, -6, -4, 0, 4, 4, 4, 4, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -4, -4, -2, -2, -2, -2, 2}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8,-10,-10, -8, -8, -8, -6, -4}}}, + /* 2 */ + {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 8, 10, 10, 16}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, 0}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10,-10,-10, -8, -4}}}, + /* 3 */ + {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 6, 8, 8, 14}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, 0}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10,-10,-10, -8, -4}}}, + /* 4 */ + {{{-16,-16,-16,-16,-16,-12,-10, -6, -2, 0, 0, 0, 0, 4, 6, 6, 12}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, 0}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10,-10,-10,-10,-10,-10,-10, -8, -4}}}, + /* 5 */ + {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 4, 6, 11}, + {-32,-32,-32,-32,-28,-24,-22,-16,-10, -6, -8, -8, -6, -6, -6, -4, -2}, + {-34,-34,-34,-34,-30,-26,-24,-18,-14,-12,-12,-12,-12,-12,-10, -9, -5}}}, + /* 6 + {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 4, 6, 11}, + {-34,-34,-34,-34,-30,-30,-24,-20,-12,-12,-14,-14,-10, -9, -8, -6, -4}, + {-34,-34,-34,-34,-34,-30,-26,-20,-16,-15,-15,-15,-15,-15,-13,-12, -8}}},*/ + {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 4, 6, 11}, + {-34,-34,-34,-34,-30,-30,-30,-24,-16,-16,-16,-16,-16,-16,-14,-14,-12}, + {-36,-36,-36,-36,-36,-34,-28,-24,-20,-20,-20,-20,-20,-20,-20,-18,-16}}}, + /* 7 */ + /* {{{-22,-22,-22,-22,-22,-20,-14,-10, -6, 0, 0, 0, 0, 4, 4, 6, 11}, + {-34,-34,-34,-34,-30,-30,-24,-20,-14,-14,-16,-16,-14,-12,-10,-10,-10}, + {-34,-34,-34,-34,-32,-32,-30,-24,-20,-19,-19,-19,-19,-19,-17,-16,-12}}},*/ + {{{-22,-22,-22,-22,-22,-20,-14,-10, -6, 0, 0, 0, 0, 4, 4, 6, 11}, + {-34,-34,-34,-34,-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-24,-22}, + {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-30,-24}}}, + /* 8 */ + /* {{{-24,-24,-24,-24,-24,-22,-14,-10, -6, -1, -1, -1, -1, 3, 3, 5, 10}, + {-34,-34,-34,-34,-30,-30,-30,-24,-20,-20,-20,-20,-20,-18,-16,-16,-14}, + {-36,-36,-36,-36,-36,-34,-28,-24,-24,-24,-24,-24,-24,-24,-24,-20,-16}}},*/ + {{{-24,-24,-24,-24,-24,-22,-14,-10, -6, -1, -1, -1, -1, 3, 3, 5, 10}, + {-34,-34,-34,-34,-34,-32,-32,-30,-26,-26,-26,-26,-26,-26,-26,-26,-24}, + {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-30,-24}}}, + /* 9 */ + /* {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2}, + {-36,-36,-36,-36,-34,-32,-32,-30,-26,-26,-26,-26,-26,-22,-20,-20,-18}, + {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-24,-20}}},*/ + {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -4, -4, -4, -4, -4, -2, 2}, + {-36,-36,-36,-36,-34,-32,-32,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26}, + {-40,-40,-40,-40,-40,-40,-40,-32,-30,-30,-30,-30,-30,-30,-30,-24,-20}}}, + /* 10 */ + {{{-30,-30,-30,-30,-30,-26,-24,-24,-24,-20,-16,-16,-16,-16,-16,-14,-12}, + {-40,-40,-40,-40,-40,-40,-40,-40,-35,-30,-30,-30,-30,-30,-30,-30,-26}, + {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}}, +}; + +/* noise bias (padding block) */ +static const noise3 _psy_noisebias_padding[12]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + + /* -1 */ + {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-20,-16, -8, -6, -6, -2, 2, 2, 3, 6, 6, 15}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}}}, + + /* 0 */ + {{{-10,-10,-10,-10,-10, -4, 0, 0, 4, 8, 8, 8, 8, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -2, 2, 3, 6, 6, 8, 10}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -4, -4, -4, -4, -2, 0, 2}}}, + /* 1 */ + {{{-12,-12,-12,-12,-12, -8, -6, -4, 0, 4, 4, 4, 4, 10, 12, 14, 20}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, 0, 0, 0, 2, 2, 4, 8}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -6, -6, -4, -2, 0}}}, + /* 2 */ + /* {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 8, 10, 10, 16}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, 0, 0, 0, 2, 2, 4, 8}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}},*/ + {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 8, 10, 10, 16}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -1, -1, -1, 0, 0, 2, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}}, + /* 3 */ + {{{-14,-14,-14,-14,-14,-10, -8, -6, -2, 2, 2, 2, 2, 6, 8, 8, 14}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -1, -1, -1, 0, 0, 2, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}}, + /* 4 */ + {{{-16,-16,-16,-16,-16,-12,-10, -6, -2, 0, 0, 0, 0, 4, 6, 6, 12}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -1, -1, -1, -1, 0, 2, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -8, -8, -8, -8, -8, -6, -4, -2}}}, + /* 5 */ + {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 6, 6, 12}, + {-32,-32,-32,-32,-28,-24,-22,-16,-12, -6, -3, -3, -3, -3, -2, 0, 4}, + {-34,-34,-34,-34,-30,-26,-24,-18,-14,-10,-10,-10,-10,-10, -8, -5, -3}}}, + /* 6 */ + {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 6, 6, 12}, + {-34,-34,-34,-34,-30,-30,-24,-20,-14, -8, -4, -4, -4, -4, -3, -1, 4}, + {-34,-34,-34,-34,-34,-30,-26,-20,-16,-13,-13,-13,-13,-13,-11, -8, -6}}}, + /* 7 */ + {{{-20,-20,-20,-20,-20,-18,-14,-10, -4, 0, 0, 0, 0, 4, 6, 6, 12}, + {-34,-34,-34,-34,-30,-30,-30,-24,-16,-10, -8, -6, -6, -6, -5, -3, 1}, + {-34,-34,-34,-34,-32,-32,-28,-22,-18,-16,-16,-16,-16,-16,-14,-12,-10}}}, + /* 8 */ + {{{-22,-22,-22,-22,-22,-20,-14,-10, -4, 0, 0, 0, 0, 3, 5, 5, 11}, + {-34,-34,-34,-34,-30,-30,-30,-24,-16,-12,-10, -8, -8, -8, -7, -5, -2}, + {-36,-36,-36,-36,-36,-34,-28,-22,-20,-20,-20,-20,-20,-20,-20,-16,-14}}}, + /* 9 */ + {{{-28,-28,-28,-28,-28,-28,-28,-20,-14, -8, -2, -2, -2, -2, 0, 2, 6}, + {-36,-36,-36,-36,-34,-32,-32,-24,-16,-12,-12,-12,-12,-12,-10, -8, -5}, + {-40,-40,-40,-40,-40,-40,-40,-32,-26,-24,-24,-24,-24,-24,-24,-20,-18}}}, + /* 10 */ + {{{-30,-30,-30,-30,-30,-26,-24,-24,-24,-20,-12,-12,-12,-12,-12,-10, -8}, + {-40,-40,-40,-40,-40,-40,-40,-40,-35,-30,-25,-25,-25,-25,-25,-25,-15}, + {-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40}}}, +}; + + +static const noiseguard _psy_noiseguards_44[4]={ + {3,3,15}, + {3,3,15}, + {10,10,100}, + {10,10,100}, +}; + +static const int _psy_tone_suppress[12]={ + -20,-20,-20,-20,-20,-24,-30,-40,-40,-45,-45,-45, +}; +static const int _psy_tone_0dB[12]={ + 90,90,95,95,95,95,105,105,105,105,105,105, +}; +static const int _psy_noise_suppress[12]={ + -20,-20,-24,-24,-24,-24,-30,-40,-40,-45,-45,-45, +}; + +static const vorbis_info_psy _psy_info_template={ + /* blockflag */ + -1, + /* ath_adjatt, ath_maxatt */ + -140.,-140., + /* tonemask att boost/decay,suppr,curves */ + {0.f,0.f,0.f}, 0.,0., -40.f, {0.}, + + /*noisemaskp,supp, low/high window, low/hi guard, minimum */ + 1, -0.f, .5f, .5f, 0,0,0, + /* noiseoffset*3, noisecompand, max_curve_dB */ + {{-1},{-1},{-1}},{-1},105.f, + /* noise normalization - noise_p, start, partition, thresh. */ + 0,-1,-1,0., +}; + +/* ath ****************/ + +static const int _psy_ath_floater[12]={ + -100,-100,-100,-100,-100,-100,-105,-105,-105,-105,-110,-120, +}; +static const int _psy_ath_abs[12]={ + -130,-130,-130,-130,-140,-140,-140,-140,-140,-140,-140,-150, +}; + +/* stereo setup. These don't map directly to quality level, there's + an additional indirection as several of the below may be used in a + single bitmanaged stream + +****************/ + +/* various stereo possibilities */ + +/* stereo mode by base quality level */ +static const adj_stereo _psy_stereo_modes_44[12]={ + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -1 */ + {{ 4, 4, 4, 4, 4, 4, 4, 3, 2, 2, 1, 0, 0, 0, 0}, + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 4, 3}, + { 1, 2, 3, 4, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8}, + { 12,12.5, 13,13.5, 14,14.5, 15, 99, 99, 99, 99, 99, 99, 99, 99}}, + +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 */ + {{ 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0}, + { 8, 8, 8, 8, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 3}, + { 1, 2, 3, 4, 4, 5, 6, 6, 6, 6, 6, 8, 8, 8, 8}, + { 12,12.5, 13,13.5, 14,14.5, 15, 99, 99, 99, 99, 99, 99, 99, 99}}, + + + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 */ + {{ 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, 0, 0, 0, 0}, + { 8, 8, 8, 8, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 3}, + { 1, 2, 3, 4, 4, 5, 6, 6, 6, 6, 6, 8, 8, 8, 8}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + + + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 2 */ + {{ 3, 3, 3, 3, 3, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0}, + { 8, 8, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 3, 2, 1}, + { 3, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 3 */ + {{ 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, + { 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1}, + { 4, 4, 5, 6, 6, 6, 6, 6, 8, 8, 10, 10, 10, 10, 10}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 4 */ + {{ 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 1, 0}, + { 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 5 */ + {{ 2, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0}, + { 6, 7, 8, 8, 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 6 */ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 8, 8, 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 7 */ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 8, 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 8 */ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 8, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 9 */ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 10 */ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, +}; + +/* tone master attenuation by base quality mode and bitrate tweak */ +static const att3 _psy_tone_masteratt_44[12]={ + {{ 35, 21, 9}, 0, 0}, /* -1 */ + {{ 30, 20, 8}, -2, 1.25}, /* 0 */ + /* {{ 25, 14, 4}, 0, 0}, *//* 1 */ + {{ 25, 12, 2}, 0, 0}, /* 1 */ + /* {{ 20, 10, -2}, 0, 0}, *//* 2 */ + {{ 20, 9, -3}, 0, 0}, /* 2 */ + {{ 20, 9, -4}, 0, 0}, /* 3 */ + {{ 20, 9, -4}, 0, 0}, /* 4 */ + {{ 20, 6, -6}, 0, 0}, /* 5 */ + {{ 20, 3, -10}, 0, 0}, /* 6 */ + {{ 18, 1, -14}, 0, 0}, /* 7 */ + {{ 18, 0, -16}, 0, 0}, /* 8 */ + {{ 18, -2, -16}, 0, 0}, /* 9 */ + {{ 12, -2, -20}, 0, 0}, /* 10 */ +}; + +/* lowpass by mode **************/ +static const double _psy_lowpass_44[12]={ + /* 15.1,15.8,16.5,17.9,20.5,48.,999.,999.,999.,999.,999. */ + 13.9,15.1,15.8,16.5,17.2,18.9,20.1,48.,999.,999.,999.,999. +}; + +/* noise normalization **********/ + +static const int _noise_start_short_44[11]={ + /* 16,16,16,16,32,32,9999,9999,9999,9999 */ + 32,16,16,16,32,9999,9999,9999,9999,9999,9999 +}; +static const int _noise_start_long_44[11]={ + /* 128,128,128,256,512,512,9999,9999,9999,9999 */ + 256,128,128,256,512,9999,9999,9999,9999,9999,9999 +}; + +static const int _noise_part_short_44[11]={ + 8,8,8,8,8,8,8,8,8,8,8 +}; +static const int _noise_part_long_44[11]={ + 32,32,32,32,32,32,32,32,32,32,32 +}; + +static const double _noise_thresh_44[11]={ + /* .2,.2,.3,.4,.5,.5,9999.,9999.,9999.,9999., */ + .2,.2,.2,.4,.6,9999.,9999.,9999.,9999.,9999.,9999., +}; + +static const double _noise_thresh_5only[2]={ + .5,.5, +}; diff --git a/vendor/vorbis/lib/modes/psych_8.h b/vendor/vorbis/lib/modes/psych_8.h new file mode 100644 index 0000000..a19817f --- /dev/null +++ b/vendor/vorbis/lib/modes/psych_8.h @@ -0,0 +1,100 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: 8kHz psychoacoustic settings + + ********************************************************************/ + +static const att3 _psy_tone_masteratt_8[3]={ + {{ 32, 25, 12}, 0, 0}, /* 0 */ + {{ 30, 25, 12}, 0, 0}, /* 0 */ + {{ 20, 0, -14}, 0, 0}, /* 0 */ +}; + +static const vp_adjblock _vp_tonemask_adj_8[3]={ + /* adjust for mode zero */ + /* 63 125 250 500 1 2 4 8 16 */ + {{-15,-15,-15,-15,-10,-10, -6, 0, 0, 0, 0,10, 0, 0,99,99,99}}, /* 1 */ + {{-15,-15,-15,-15,-10,-10, -6, 0, 0, 0, 0,10, 0, 0,99,99,99}}, /* 1 */ + {{-15,-15,-15,-15,-10,-10, -6, 0, 0, 0, 0, 0, 0, 0,99,99,99}}, /* 1 */ +}; + + +static const noise3 _psy_noisebias_8[3]={ + /* 63 125 250 500 1k 2k 4k 8k 16k*/ + {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 8, 8, 8, 10, 10, 99, 99, 99}, + {-10,-10,-10,-10, -5, -5, -5, 0, 0, 4, 4, 4, 4, 4, 99, 99, 99}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}}, + + {{{-10,-10,-10,-10, -5, -5, -5, 0, 4, 8, 8, 8, 10, 10, 99, 99, 99}, + {-10,-10,-10,-10,-10,-10, -5, -5, -5, 0, 0, 0, 0, 0, 99, 99, 99}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, 99, 99, 99}}}, + + {{{-15,-15,-15,-15,-15,-12,-10, -8, 0, 2, 4, 4, 5, 5, 99, 99, 99}, + {-30,-30,-30,-30,-26,-22,-20,-14,-12,-12,-10,-10,-10,-10, 99, 99, 99}, + {-30,-30,-30,-30,-26,-26,-26,-26,-26,-26,-26,-26,-26,-24, 99, 99, 99}}}, +}; + +/* stereo mode by base quality level */ +static const adj_stereo _psy_stereo_modes_8[3]={ + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */ + {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + {{ 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + { 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, + {{ 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}, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}, +}; + +static const noiseguard _psy_noiseguards_8[2]={ + {10,10,-1}, + {10,10,-1}, +}; + +static const compandblock _psy_compand_8[2]={ + {{ + 0, 1, 2, 3, 4, 5, 6, 7, /* 7dB */ + 8, 8, 9, 9,10,10,11, 11, /* 15dB */ + 12,12,13,13,14,14,15, 15, /* 23dB */ + 16,16,17,17,17,18,18, 19, /* 31dB */ + 19,19,20,21,22,23,24, 25, /* 39dB */ + }}, + {{ + 0, 1, 2, 3, 4, 5, 6, 6, /* 7dB */ + 7, 7, 6, 6, 5, 5, 4, 4, /* 15dB */ + 3, 3, 3, 4, 5, 6, 7, 8, /* 23dB */ + 9,10,11,12,13,14,15, 16, /* 31dB */ + 17,18,19,20,21,22,23, 24, /* 39dB */ + }}, +}; + +static const double _psy_lowpass_8[3]={3.,4.,4.}; +static const int _noise_start_8[2]={ + 64,64, +}; +static const int _noise_part_8[2]={ + 8,8, +}; + +static const int _psy_ath_floater_8[3]={ + -100,-100,-105, +}; + +static const int _psy_ath_abs_8[3]={ + -130,-130,-140, +}; diff --git a/vendor/vorbis/lib/modes/residue_16.h b/vendor/vorbis/lib/modes/residue_16.h new file mode 100644 index 0000000..15e161c --- /dev/null +++ b/vendor/vorbis/lib/modes/residue_16.h @@ -0,0 +1,162 @@ +/******************************************************************** + * * + * This FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel residue templates 16/22kHz + + ********************************************************************/ + +/***** residue backends *********************************************/ + +static const static_bookblock _resbook_16s_0={ + { + {0}, + {0,0,&_16c0_s_p1_0}, + {0}, + {0,0,&_16c0_s_p3_0}, + {0,0,&_16c0_s_p4_0}, + {0,0,&_16c0_s_p5_0}, + {0,0,&_16c0_s_p6_0}, + {&_16c0_s_p7_0,&_16c0_s_p7_1}, + {&_16c0_s_p8_0,&_16c0_s_p8_1}, + {&_16c0_s_p9_0,&_16c0_s_p9_1,&_16c0_s_p9_2} + } +}; +static const static_bookblock _resbook_16s_1={ + { + {0}, + {0,0,&_16c1_s_p1_0}, + {0}, + {0,0,&_16c1_s_p3_0}, + {0,0,&_16c1_s_p4_0}, + {0,0,&_16c1_s_p5_0}, + {0,0,&_16c1_s_p6_0}, + {&_16c1_s_p7_0,&_16c1_s_p7_1}, + {&_16c1_s_p8_0,&_16c1_s_p8_1}, + {&_16c1_s_p9_0,&_16c1_s_p9_1,&_16c1_s_p9_2} + } +}; +static const static_bookblock _resbook_16s_2={ + { + {0}, + {0,0,&_16c2_s_p1_0}, + {0,0,&_16c2_s_p2_0}, + {0,0,&_16c2_s_p3_0}, + {0,0,&_16c2_s_p4_0}, + {&_16c2_s_p5_0,&_16c2_s_p5_1}, + {&_16c2_s_p6_0,&_16c2_s_p6_1}, + {&_16c2_s_p7_0,&_16c2_s_p7_1}, + {&_16c2_s_p8_0,&_16c2_s_p8_1}, + {&_16c2_s_p9_0,&_16c2_s_p9_1,&_16c2_s_p9_2} + } +}; + +static const vorbis_residue_template _res_16s_0[]={ + {2,0,32, &_residue_44_mid, + &_huff_book__16c0_s_single,&_huff_book__16c0_s_single, + &_resbook_16s_0,&_resbook_16s_0}, +}; +static const vorbis_residue_template _res_16s_1[]={ + {2,0,32, &_residue_44_mid, + &_huff_book__16c1_s_short,&_huff_book__16c1_s_short, + &_resbook_16s_1,&_resbook_16s_1}, + + {2,0,32, &_residue_44_mid, + &_huff_book__16c1_s_long,&_huff_book__16c1_s_long, + &_resbook_16s_1,&_resbook_16s_1} +}; +static const vorbis_residue_template _res_16s_2[]={ + {2,0,32, &_residue_44_high, + &_huff_book__16c2_s_short,&_huff_book__16c2_s_short, + &_resbook_16s_2,&_resbook_16s_2}, + + {2,0,32, &_residue_44_high, + &_huff_book__16c2_s_long,&_huff_book__16c2_s_long, + &_resbook_16s_2,&_resbook_16s_2} +}; + +static const vorbis_mapping_template _mapres_template_16_stereo[3]={ + { _map_nominal, _res_16s_0 }, /* 0 */ + { _map_nominal, _res_16s_1 }, /* 1 */ + { _map_nominal, _res_16s_2 }, /* 2 */ +}; + +static const static_bookblock _resbook_16u_0={ + { + {0}, + {0,0,&_16u0__p1_0}, + {0,0,&_16u0__p2_0}, + {0,0,&_16u0__p3_0}, + {0,0,&_16u0__p4_0}, + {0,0,&_16u0__p5_0}, + {&_16u0__p6_0,&_16u0__p6_1}, + {&_16u0__p7_0,&_16u0__p7_1,&_16u0__p7_2} + } +}; +static const static_bookblock _resbook_16u_1={ + { + {0}, + {0,0,&_16u1__p1_0}, + {0,0,&_16u1__p2_0}, + {0,0,&_16u1__p3_0}, + {0,0,&_16u1__p4_0}, + {0,0,&_16u1__p5_0}, + {0,0,&_16u1__p6_0}, + {&_16u1__p7_0,&_16u1__p7_1}, + {&_16u1__p8_0,&_16u1__p8_1}, + {&_16u1__p9_0,&_16u1__p9_1,&_16u1__p9_2} + } +}; +static const static_bookblock _resbook_16u_2={ + { + {0}, + {0,0,&_16u2_p1_0}, + {0,0,&_16u2_p2_0}, + {0,0,&_16u2_p3_0}, + {0,0,&_16u2_p4_0}, + {&_16u2_p5_0,&_16u2_p5_1}, + {&_16u2_p6_0,&_16u2_p6_1}, + {&_16u2_p7_0,&_16u2_p7_1}, + {&_16u2_p8_0,&_16u2_p8_1}, + {&_16u2_p9_0,&_16u2_p9_1,&_16u2_p9_2} + } +}; + +static const vorbis_residue_template _res_16u_0[]={ + {1,0,32, &_residue_44_low_un, + &_huff_book__16u0__single,&_huff_book__16u0__single, + &_resbook_16u_0,&_resbook_16u_0}, +}; +static const vorbis_residue_template _res_16u_1[]={ + {1,0,32, &_residue_44_mid_un, + &_huff_book__16u1__short,&_huff_book__16u1__short, + &_resbook_16u_1,&_resbook_16u_1}, + + {1,0,32, &_residue_44_mid_un, + &_huff_book__16u1__long,&_huff_book__16u1__long, + &_resbook_16u_1,&_resbook_16u_1} +}; +static const vorbis_residue_template _res_16u_2[]={ + {1,0,32, &_residue_44_hi_un, + &_huff_book__16u2__short,&_huff_book__16u2__short, + &_resbook_16u_2,&_resbook_16u_2}, + + {1,0,32, &_residue_44_hi_un, + &_huff_book__16u2__long,&_huff_book__16u2__long, + &_resbook_16u_2,&_resbook_16u_2} +}; + + +static const vorbis_mapping_template _mapres_template_16_uncoupled[3]={ + { _map_nominal_u, _res_16u_0 }, /* 0 */ + { _map_nominal_u, _res_16u_1 }, /* 1 */ + { _map_nominal_u, _res_16u_2 }, /* 2 */ +}; diff --git a/vendor/vorbis/lib/modes/residue_44.h b/vendor/vorbis/lib/modes/residue_44.h new file mode 100644 index 0000000..3f98269 --- /dev/null +++ b/vendor/vorbis/lib/modes/residue_44.h @@ -0,0 +1,291 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel residue templates for 32/44.1/48kHz + + ********************************************************************/ + +#include "vorbis/codec.h" +#include "backends.h" +#include "books/coupled/res_books_stereo.h" + +/***** residue backends *********************************************/ + +static const vorbis_info_residue0 _residue_44_low={ + 0,-1, -1, 9,-1,-1, + /* 0 1 2 3 4 5 6 7 */ + {0}, + {-1}, + { 0, 1, 2, 2, 4, 8, 16, 32}, + { 0, 0, 0,999, 4, 8, 16, 32}, +}; + +static const vorbis_info_residue0 _residue_44_mid={ + 0,-1, -1, 10,-1,-1, + /* 0 1 2 3 4 5 6 7 8 */ + {0}, + {-1}, + { 0, 1, 1, 2, 2, 4, 8, 16, 32}, + { 0, 0,999, 0,999, 4, 8, 16, 32}, +}; + +static const vorbis_info_residue0 _residue_44_high={ + 0,-1, -1, 10,-1,-1, + /* 0 1 2 3 4 5 6 7 8 */ + {0}, + {-1}, + { 0, 1, 2, 4, 8, 16, 32, 71,157}, + { 0, 1, 2, 3, 4, 8, 16, 71,157}, +}; + +static const static_bookblock _resbook_44s_n1={ + { + {0},{0,0,&_44cn1_s_p1_0},{0,0,&_44cn1_s_p2_0}, + {0,0,&_44cn1_s_p3_0},{0,0,&_44cn1_s_p4_0},{0,0,&_44cn1_s_p5_0}, + {&_44cn1_s_p6_0,&_44cn1_s_p6_1},{&_44cn1_s_p7_0,&_44cn1_s_p7_1}, + {&_44cn1_s_p8_0,&_44cn1_s_p8_1,&_44cn1_s_p8_2} + } +}; +static const static_bookblock _resbook_44sm_n1={ + { + {0},{0,0,&_44cn1_sm_p1_0},{0,0,&_44cn1_sm_p2_0}, + {0,0,&_44cn1_sm_p3_0},{0,0,&_44cn1_sm_p4_0},{0,0,&_44cn1_sm_p5_0}, + {&_44cn1_sm_p6_0,&_44cn1_sm_p6_1},{&_44cn1_sm_p7_0,&_44cn1_sm_p7_1}, + {&_44cn1_sm_p8_0,&_44cn1_sm_p8_1,&_44cn1_sm_p8_2} + } +}; + +static const static_bookblock _resbook_44s_0={ + { + {0},{0,0,&_44c0_s_p1_0},{0,0,&_44c0_s_p2_0}, + {0,0,&_44c0_s_p3_0},{0,0,&_44c0_s_p4_0},{0,0,&_44c0_s_p5_0}, + {&_44c0_s_p6_0,&_44c0_s_p6_1},{&_44c0_s_p7_0,&_44c0_s_p7_1}, + {&_44c0_s_p8_0,&_44c0_s_p8_1,&_44c0_s_p8_2} + } +}; +static const static_bookblock _resbook_44sm_0={ + { + {0},{0,0,&_44c0_sm_p1_0},{0,0,&_44c0_sm_p2_0}, + {0,0,&_44c0_sm_p3_0},{0,0,&_44c0_sm_p4_0},{0,0,&_44c0_sm_p5_0}, + {&_44c0_sm_p6_0,&_44c0_sm_p6_1},{&_44c0_sm_p7_0,&_44c0_sm_p7_1}, + {&_44c0_sm_p8_0,&_44c0_sm_p8_1,&_44c0_sm_p8_2} + } +}; + +static const static_bookblock _resbook_44s_1={ + { + {0},{0,0,&_44c1_s_p1_0},{0,0,&_44c1_s_p2_0}, + {0,0,&_44c1_s_p3_0},{0,0,&_44c1_s_p4_0},{0,0,&_44c1_s_p5_0}, + {&_44c1_s_p6_0,&_44c1_s_p6_1},{&_44c1_s_p7_0,&_44c1_s_p7_1}, + {&_44c1_s_p8_0,&_44c1_s_p8_1,&_44c1_s_p8_2} + } +}; +static const static_bookblock _resbook_44sm_1={ + { + {0},{0,0,&_44c1_sm_p1_0},{0,0,&_44c1_sm_p2_0}, + {0,0,&_44c1_sm_p3_0},{0,0,&_44c1_sm_p4_0},{0,0,&_44c1_sm_p5_0}, + {&_44c1_sm_p6_0,&_44c1_sm_p6_1},{&_44c1_sm_p7_0,&_44c1_sm_p7_1}, + {&_44c1_sm_p8_0,&_44c1_sm_p8_1,&_44c1_sm_p8_2} + } +}; + +static const static_bookblock _resbook_44s_2={ + { + {0},{0,0,&_44c2_s_p1_0},{0,0,&_44c2_s_p2_0},{0,0,&_44c2_s_p3_0}, + {0,0,&_44c2_s_p4_0},{0,0,&_44c2_s_p5_0},{0,0,&_44c2_s_p6_0}, + {&_44c2_s_p7_0,&_44c2_s_p7_1},{&_44c2_s_p8_0,&_44c2_s_p8_1}, + {&_44c2_s_p9_0,&_44c2_s_p9_1,&_44c2_s_p9_2} + } +}; +static const static_bookblock _resbook_44s_3={ + { + {0},{0,0,&_44c3_s_p1_0},{0,0,&_44c3_s_p2_0},{0,0,&_44c3_s_p3_0}, + {0,0,&_44c3_s_p4_0},{0,0,&_44c3_s_p5_0},{0,0,&_44c3_s_p6_0}, + {&_44c3_s_p7_0,&_44c3_s_p7_1},{&_44c3_s_p8_0,&_44c3_s_p8_1}, + {&_44c3_s_p9_0,&_44c3_s_p9_1,&_44c3_s_p9_2} + } +}; +static const static_bookblock _resbook_44s_4={ + { + {0},{0,0,&_44c4_s_p1_0},{0,0,&_44c4_s_p2_0},{0,0,&_44c4_s_p3_0}, + {0,0,&_44c4_s_p4_0},{0,0,&_44c4_s_p5_0},{0,0,&_44c4_s_p6_0}, + {&_44c4_s_p7_0,&_44c4_s_p7_1},{&_44c4_s_p8_0,&_44c4_s_p8_1}, + {&_44c4_s_p9_0,&_44c4_s_p9_1,&_44c4_s_p9_2} + } +}; +static const static_bookblock _resbook_44s_5={ + { + {0},{0,0,&_44c5_s_p1_0},{0,0,&_44c5_s_p2_0},{0,0,&_44c5_s_p3_0}, + {0,0,&_44c5_s_p4_0},{0,0,&_44c5_s_p5_0},{0,0,&_44c5_s_p6_0}, + {&_44c5_s_p7_0,&_44c5_s_p7_1},{&_44c5_s_p8_0,&_44c5_s_p8_1}, + {&_44c5_s_p9_0,&_44c5_s_p9_1,&_44c5_s_p9_2} + } +}; +static const static_bookblock _resbook_44s_6={ + { + {0},{0,0,&_44c6_s_p1_0},{0,0,&_44c6_s_p2_0},{0,0,&_44c6_s_p3_0}, + {0,0,&_44c6_s_p4_0}, + {&_44c6_s_p5_0,&_44c6_s_p5_1}, + {&_44c6_s_p6_0,&_44c6_s_p6_1}, + {&_44c6_s_p7_0,&_44c6_s_p7_1}, + {&_44c6_s_p8_0,&_44c6_s_p8_1}, + {&_44c6_s_p9_0,&_44c6_s_p9_1,&_44c6_s_p9_2} + } +}; +static const static_bookblock _resbook_44s_7={ + { + {0},{0,0,&_44c7_s_p1_0},{0,0,&_44c7_s_p2_0},{0,0,&_44c7_s_p3_0}, + {0,0,&_44c7_s_p4_0}, + {&_44c7_s_p5_0,&_44c7_s_p5_1}, + {&_44c7_s_p6_0,&_44c7_s_p6_1}, + {&_44c7_s_p7_0,&_44c7_s_p7_1}, + {&_44c7_s_p8_0,&_44c7_s_p8_1}, + {&_44c7_s_p9_0,&_44c7_s_p9_1,&_44c7_s_p9_2} + } +}; +static const static_bookblock _resbook_44s_8={ + { + {0},{0,0,&_44c8_s_p1_0},{0,0,&_44c8_s_p2_0},{0,0,&_44c8_s_p3_0}, + {0,0,&_44c8_s_p4_0}, + {&_44c8_s_p5_0,&_44c8_s_p5_1}, + {&_44c8_s_p6_0,&_44c8_s_p6_1}, + {&_44c8_s_p7_0,&_44c8_s_p7_1}, + {&_44c8_s_p8_0,&_44c8_s_p8_1}, + {&_44c8_s_p9_0,&_44c8_s_p9_1,&_44c8_s_p9_2} + } +}; +static const static_bookblock _resbook_44s_9={ + { + {0},{0,0,&_44c9_s_p1_0},{0,0,&_44c9_s_p2_0},{0,0,&_44c9_s_p3_0}, + {0,0,&_44c9_s_p4_0}, + {&_44c9_s_p5_0,&_44c9_s_p5_1}, + {&_44c9_s_p6_0,&_44c9_s_p6_1}, + {&_44c9_s_p7_0,&_44c9_s_p7_1}, + {&_44c9_s_p8_0,&_44c9_s_p8_1}, + {&_44c9_s_p9_0,&_44c9_s_p9_1,&_44c9_s_p9_2} + } +}; + +static const vorbis_residue_template _res_44s_n1[]={ + {2,0,32, &_residue_44_low, + &_huff_book__44cn1_s_short,&_huff_book__44cn1_sm_short, + &_resbook_44s_n1,&_resbook_44sm_n1}, + + {2,0,32, &_residue_44_low, + &_huff_book__44cn1_s_long,&_huff_book__44cn1_sm_long, + &_resbook_44s_n1,&_resbook_44sm_n1} +}; +static const vorbis_residue_template _res_44s_0[]={ + {2,0,16, &_residue_44_low, + &_huff_book__44c0_s_short,&_huff_book__44c0_sm_short, + &_resbook_44s_0,&_resbook_44sm_0}, + + {2,0,32, &_residue_44_low, + &_huff_book__44c0_s_long,&_huff_book__44c0_sm_long, + &_resbook_44s_0,&_resbook_44sm_0} +}; +static const vorbis_residue_template _res_44s_1[]={ + {2,0,16, &_residue_44_low, + &_huff_book__44c1_s_short,&_huff_book__44c1_sm_short, + &_resbook_44s_1,&_resbook_44sm_1}, + + {2,0,32, &_residue_44_low, + &_huff_book__44c1_s_long,&_huff_book__44c1_sm_long, + &_resbook_44s_1,&_resbook_44sm_1} +}; + +static const vorbis_residue_template _res_44s_2[]={ + {2,0,16, &_residue_44_mid, + &_huff_book__44c2_s_short,&_huff_book__44c2_s_short, + &_resbook_44s_2,&_resbook_44s_2}, + + {2,0,32, &_residue_44_mid, + &_huff_book__44c2_s_long,&_huff_book__44c2_s_long, + &_resbook_44s_2,&_resbook_44s_2} +}; +static const vorbis_residue_template _res_44s_3[]={ + {2,0,16, &_residue_44_mid, + &_huff_book__44c3_s_short,&_huff_book__44c3_s_short, + &_resbook_44s_3,&_resbook_44s_3}, + + {2,0,32, &_residue_44_mid, + &_huff_book__44c3_s_long,&_huff_book__44c3_s_long, + &_resbook_44s_3,&_resbook_44s_3} +}; +static const vorbis_residue_template _res_44s_4[]={ + {2,0,16, &_residue_44_mid, + &_huff_book__44c4_s_short,&_huff_book__44c4_s_short, + &_resbook_44s_4,&_resbook_44s_4}, + + {2,0,32, &_residue_44_mid, + &_huff_book__44c4_s_long,&_huff_book__44c4_s_long, + &_resbook_44s_4,&_resbook_44s_4} +}; +static const vorbis_residue_template _res_44s_5[]={ + {2,0,16, &_residue_44_mid, + &_huff_book__44c5_s_short,&_huff_book__44c5_s_short, + &_resbook_44s_5,&_resbook_44s_5}, + + {2,0,32, &_residue_44_mid, + &_huff_book__44c5_s_long,&_huff_book__44c5_s_long, + &_resbook_44s_5,&_resbook_44s_5} +}; +static const vorbis_residue_template _res_44s_6[]={ + {2,0,16, &_residue_44_high, + &_huff_book__44c6_s_short,&_huff_book__44c6_s_short, + &_resbook_44s_6,&_resbook_44s_6}, + + {2,0,32, &_residue_44_high, + &_huff_book__44c6_s_long,&_huff_book__44c6_s_long, + &_resbook_44s_6,&_resbook_44s_6} +}; +static const vorbis_residue_template _res_44s_7[]={ + {2,0,16, &_residue_44_high, + &_huff_book__44c7_s_short,&_huff_book__44c7_s_short, + &_resbook_44s_7,&_resbook_44s_7}, + + {2,0,32, &_residue_44_high, + &_huff_book__44c7_s_long,&_huff_book__44c7_s_long, + &_resbook_44s_7,&_resbook_44s_7} +}; +static const vorbis_residue_template _res_44s_8[]={ + {2,0,16, &_residue_44_high, + &_huff_book__44c8_s_short,&_huff_book__44c8_s_short, + &_resbook_44s_8,&_resbook_44s_8}, + + {2,0,32, &_residue_44_high, + &_huff_book__44c8_s_long,&_huff_book__44c8_s_long, + &_resbook_44s_8,&_resbook_44s_8} +}; +static const vorbis_residue_template _res_44s_9[]={ + {2,0,16, &_residue_44_high, + &_huff_book__44c9_s_short,&_huff_book__44c9_s_short, + &_resbook_44s_9,&_resbook_44s_9}, + + {2,0,32, &_residue_44_high, + &_huff_book__44c9_s_long,&_huff_book__44c9_s_long, + &_resbook_44s_9,&_resbook_44s_9} +}; + +static const vorbis_mapping_template _mapres_template_44_stereo[]={ + { _map_nominal, _res_44s_n1 }, /* -1 */ + { _map_nominal, _res_44s_0 }, /* 0 */ + { _map_nominal, _res_44s_1 }, /* 1 */ + { _map_nominal, _res_44s_2 }, /* 2 */ + { _map_nominal, _res_44s_3 }, /* 3 */ + { _map_nominal, _res_44s_4 }, /* 4 */ + { _map_nominal, _res_44s_5 }, /* 5 */ + { _map_nominal, _res_44s_6 }, /* 6 */ + { _map_nominal, _res_44s_7 }, /* 7 */ + { _map_nominal, _res_44s_8 }, /* 8 */ + { _map_nominal, _res_44s_9 }, /* 9 */ +}; diff --git a/vendor/vorbis/lib/modes/residue_44p51.h b/vendor/vorbis/lib/modes/residue_44p51.h new file mode 100644 index 0000000..8ac5f65 --- /dev/null +++ b/vendor/vorbis/lib/modes/residue_44p51.h @@ -0,0 +1,450 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel residue templates for 32/44.1/48kHz uncoupled + + ********************************************************************/ + +#include "vorbis/codec.h" +#include "backends.h" + +#include "books/coupled/res_books_51.h" + +/***** residue backends *********************************************/ + +static const vorbis_info_residue0 _residue_44p_lo={ + 0,-1, -1, 7,-1,-1, + /* 0 1 2 3 4 5 6 7 8 */ + {0}, + {-1}, + { 0, 1, 2, 7, 17, 31}, + { 0, 0, 99, 7, 17, 31}, +}; + +static const vorbis_info_residue0 _residue_44p={ + 0,-1, -1, 8,-1,-1, + /* 0 1 2 3 4 5 6 7 8 */ + {0}, + {-1}, + { 0, 1, 1, 2, 7, 17, 31}, + { 0, 0, 99, 99, 7, 17, 31}, +}; + +static const vorbis_info_residue0 _residue_44p_hi={ + 0,-1, -1, 8,-1,-1, + /* 0 1 2 3 4 5 6 7 8 */ + {0}, + {-1}, + { 0, 1, 2, 4, 7, 17, 31}, + { 0, 1, 2, 4, 7, 17, 31}, +}; + +static const vorbis_info_residue0 _residue_44p_lfe={ + 0,-1, -1, 2,-1,-1, + /* 0 1 2 3 4 5 6 7 8 */ + {0}, + {-1}, + { 32}, + { -1} +}; + +static const static_bookblock _resbook_44p_n1={ + { + {0}, + {0,&_44pn1_p1_0}, + + {&_44pn1_p2_0,&_44pn1_p2_1,0}, + {&_44pn1_p3_0,&_44pn1_p3_1,0}, + {&_44pn1_p4_0,&_44pn1_p4_1,0}, + + {&_44pn1_p5_0,&_44pn1_p5_1,&_44pn1_p4_1}, + {&_44pn1_p6_0,&_44pn1_p6_1,&_44pn1_p6_2}, + } +}; + +static const static_bookblock _resbook_44p_0={ + { + {0}, + {0,&_44p0_p1_0}, + + {&_44p0_p2_0,&_44p0_p2_1,0}, + {&_44p0_p3_0,&_44p0_p3_1,0}, + {&_44p0_p4_0,&_44p0_p4_1,0}, + + {&_44p0_p5_0,&_44p0_p5_1,&_44p0_p4_1}, + {&_44p0_p6_0,&_44p0_p6_1,&_44p0_p6_2}, + } +}; + +static const static_bookblock _resbook_44p_1={ + { + {0}, + {0,&_44p1_p1_0}, + + {&_44p1_p2_0,&_44p1_p2_1,0}, + {&_44p1_p3_0,&_44p1_p3_1,0}, + {&_44p1_p4_0,&_44p1_p4_1,0}, + + {&_44p1_p5_0,&_44p1_p5_1,&_44p1_p4_1}, + {&_44p1_p6_0,&_44p1_p6_1,&_44p1_p6_2}, + } +}; + +static const static_bookblock _resbook_44p_2={ + { + {0}, + {0,0,&_44p2_p1_0}, + {0,&_44p2_p2_0,0}, + + {&_44p2_p3_0,&_44p2_p3_1,0}, + {&_44p2_p4_0,&_44p2_p4_1,0}, + {&_44p2_p5_0,&_44p2_p5_1,0}, + + {&_44p2_p6_0,&_44p2_p6_1,&_44p2_p5_1}, + {&_44p2_p7_0,&_44p2_p7_1,&_44p2_p7_2,&_44p2_p7_3} + } +}; +static const static_bookblock _resbook_44p_3={ + { + {0}, + {0,0,&_44p3_p1_0}, + {0,&_44p3_p2_0,0}, + + {&_44p3_p3_0,&_44p3_p3_1,0}, + {&_44p3_p4_0,&_44p3_p4_1,0}, + {&_44p3_p5_0,&_44p3_p5_1,0}, + + {&_44p3_p6_0,&_44p3_p6_1,&_44p3_p5_1}, + {&_44p3_p7_0,&_44p3_p7_1,&_44p3_p7_2,&_44p3_p7_3} + } +}; +static const static_bookblock _resbook_44p_4={ + { + {0}, + {0,0,&_44p4_p1_0}, + {0,&_44p4_p2_0,0}, + + {&_44p4_p3_0,&_44p4_p3_1,0}, + {&_44p4_p4_0,&_44p4_p4_1,0}, + {&_44p4_p5_0,&_44p4_p5_1,0}, + + {&_44p4_p6_0,&_44p4_p6_1,&_44p4_p5_1}, + {&_44p4_p7_0,&_44p4_p7_1,&_44p4_p7_2,&_44p4_p7_3} + } +}; +static const static_bookblock _resbook_44p_5={ + { + {0}, + {0,0,&_44p5_p1_0}, + {0,&_44p5_p2_0,0}, + + {&_44p5_p3_0,&_44p5_p3_1,0}, + {&_44p5_p4_0,&_44p5_p4_1,0}, + {&_44p5_p5_0,&_44p5_p5_1,0}, + + {&_44p5_p6_0,&_44p5_p6_1,&_44p5_p5_1}, + {&_44p5_p7_0,&_44p5_p7_1,&_44p5_p7_2,&_44p5_p7_3} + } +}; +static const static_bookblock _resbook_44p_6={ + { + {0}, + {0,0,&_44p6_p1_0}, + {0,&_44p6_p2_0,0}, + + {&_44p6_p3_0,&_44p6_p3_1,0}, + {&_44p6_p4_0,&_44p6_p4_1,0}, + {&_44p6_p5_0,&_44p6_p5_1,0}, + + {&_44p6_p6_0,&_44p6_p6_1,&_44p6_p5_1}, + {&_44p6_p7_0,&_44p6_p7_1,&_44p6_p7_2,&_44p6_p7_3} + } +}; +static const static_bookblock _resbook_44p_7={ + { + {0}, + {0,0,&_44p7_p1_0}, + {0,&_44p7_p2_0,0}, + + {&_44p7_p3_0,&_44p7_p3_1,0}, + {&_44p7_p4_0,&_44p7_p4_1,0}, + {&_44p7_p5_0,&_44p7_p5_1,0}, + + {&_44p7_p6_0,&_44p7_p6_1,&_44p7_p5_1}, + {&_44p7_p7_0,&_44p7_p7_1,&_44p7_p7_2,&_44p7_p7_3} + } +}; +static const static_bookblock _resbook_44p_8={ + { + {0}, + {0,0,&_44p8_p1_0}, + {0,&_44p8_p2_0,0}, + + {&_44p8_p3_0,&_44p8_p3_1,0}, + {&_44p8_p4_0,&_44p8_p4_1,0}, + {&_44p8_p5_0,&_44p8_p5_1,0}, + + {&_44p8_p6_0,&_44p8_p6_1,&_44p8_p5_1}, + {&_44p8_p7_0,&_44p8_p7_1,&_44p8_p7_2,&_44p8_p7_3} + } +}; +static const static_bookblock _resbook_44p_9={ + { + {0}, + {0,0,&_44p9_p1_0}, + {0,&_44p9_p2_0,0}, + + {&_44p9_p3_0,&_44p9_p3_1,0}, + {&_44p9_p4_0,&_44p9_p4_1,0}, + {&_44p9_p5_0,&_44p9_p5_1,0}, + + {&_44p9_p6_0,&_44p9_p6_1,&_44p9_p5_1}, + {&_44p9_p7_0,&_44p9_p7_1,&_44p9_p7_2,&_44p9_p7_3} + } +}; + +static const static_bookblock _resbook_44p_ln1={ + { + {&_44pn1_l0_0,&_44pn1_l0_1,0}, + {&_44pn1_l1_0,&_44pn1_p6_1,&_44pn1_p6_2}, + } +}; +static const static_bookblock _resbook_44p_l0={ + { + {&_44p0_l0_0,&_44p0_l0_1,0}, + {&_44p0_l1_0,&_44p0_p6_1,&_44p0_p6_2}, + } +}; +static const static_bookblock _resbook_44p_l1={ + { + {&_44p1_l0_0,&_44p1_l0_1,0}, + {&_44p1_l1_0,&_44p1_p6_1,&_44p1_p6_2}, + } +}; +static const static_bookblock _resbook_44p_l2={ + { + {&_44p2_l0_0,&_44p2_l0_1,0}, + {&_44p2_l1_0,&_44p2_p7_2,&_44p2_p7_3}, + } +}; +static const static_bookblock _resbook_44p_l3={ + { + {&_44p3_l0_0,&_44p3_l0_1,0}, + {&_44p3_l1_0,&_44p3_p7_2,&_44p3_p7_3}, + } +}; +static const static_bookblock _resbook_44p_l4={ + { + {&_44p4_l0_0,&_44p4_l0_1,0}, + {&_44p4_l1_0,&_44p4_p7_2,&_44p4_p7_3}, + } +}; +static const static_bookblock _resbook_44p_l5={ + { + {&_44p5_l0_0,&_44p5_l0_1,0}, + {&_44p5_l1_0,&_44p5_p7_2,&_44p5_p7_3}, + } +}; +static const static_bookblock _resbook_44p_l6={ + { + {&_44p6_l0_0,&_44p6_l0_1,0}, + {&_44p6_l1_0,&_44p6_p7_2,&_44p6_p7_3}, + } +}; +static const static_bookblock _resbook_44p_l7={ + { + {&_44p7_l0_0,&_44p7_l0_1,0}, + {&_44p7_l1_0,&_44p7_p7_2,&_44p7_p7_3}, + } +}; +static const static_bookblock _resbook_44p_l8={ + { + {&_44p8_l0_0,&_44p8_l0_1,0}, + {&_44p8_l1_0,&_44p8_p7_2,&_44p8_p7_3}, + } +}; +static const static_bookblock _resbook_44p_l9={ + { + {&_44p9_l0_0,&_44p9_l0_1,0}, + {&_44p9_l1_0,&_44p9_p7_2,&_44p9_p7_3}, + } +}; + + +static const vorbis_info_mapping0 _map_nominal_51[2]={ + {2, {0,0,0,0,0,1}, {0,2}, {0,2}, 4,{0,3,0,0},{2,4,1,3}}, + {2, {0,0,0,0,0,1}, {1,2}, {1,2}, 4,{0,3,0,0},{2,4,1,3}} +}; +static const vorbis_info_mapping0 _map_nominal_51u[2]={ + {2, {0,0,0,0,0,1}, {0,2}, {0,2}, 0,{0},{0}}, + {2, {0,0,0,0,0,1}, {1,2}, {1,2}, 0,{0},{0}} +}; + +static const vorbis_residue_template _res_44p51_n1[]={ + {2,0,30, &_residue_44p_lo, + &_huff_book__44pn1_short,&_huff_book__44pn1_short, + &_resbook_44p_n1,&_resbook_44p_n1}, + + {2,0,30, &_residue_44p_lo, + &_huff_book__44pn1_long,&_huff_book__44pn1_long, + &_resbook_44p_n1,&_resbook_44p_n1}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44pn1_lfe,&_huff_book__44pn1_lfe, + &_resbook_44p_ln1,&_resbook_44p_ln1} +}; +static const vorbis_residue_template _res_44p51_0[]={ + {2,0,15, &_residue_44p_lo, + &_huff_book__44p0_short,&_huff_book__44p0_short, + &_resbook_44p_0,&_resbook_44p_0}, + + {2,0,30, &_residue_44p_lo, + &_huff_book__44p0_long,&_huff_book__44p0_long, + &_resbook_44p_0,&_resbook_44p_0}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p0_lfe,&_huff_book__44p0_lfe, + &_resbook_44p_l0,&_resbook_44p_l0} +}; +static const vorbis_residue_template _res_44p51_1[]={ + {2,0,15, &_residue_44p_lo, + &_huff_book__44p1_short,&_huff_book__44p1_short, + &_resbook_44p_1,&_resbook_44p_1}, + + {2,0,30, &_residue_44p_lo, + &_huff_book__44p1_long,&_huff_book__44p1_long, + &_resbook_44p_1,&_resbook_44p_1}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p1_lfe,&_huff_book__44p1_lfe, + &_resbook_44p_l1,&_resbook_44p_l1} +}; +static const vorbis_residue_template _res_44p51_2[]={ + {2,0,15, &_residue_44p, + &_huff_book__44p2_short,&_huff_book__44p2_short, + &_resbook_44p_2,&_resbook_44p_2}, + + {2,0,30, &_residue_44p, + &_huff_book__44p2_long,&_huff_book__44p2_long, + &_resbook_44p_2,&_resbook_44p_2}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p2_lfe,&_huff_book__44p2_lfe, + &_resbook_44p_l2,&_resbook_44p_l2} +}; +static const vorbis_residue_template _res_44p51_3[]={ + {2,0,15, &_residue_44p, + &_huff_book__44p3_short,&_huff_book__44p3_short, + &_resbook_44p_3,&_resbook_44p_3}, + + {2,0,30, &_residue_44p, + &_huff_book__44p3_long,&_huff_book__44p3_long, + &_resbook_44p_3,&_resbook_44p_3}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p3_lfe,&_huff_book__44p3_lfe, + &_resbook_44p_l3,&_resbook_44p_l3} +}; +static const vorbis_residue_template _res_44p51_4[]={ + {2,0,15, &_residue_44p, + &_huff_book__44p4_short,&_huff_book__44p4_short, + &_resbook_44p_4,&_resbook_44p_4}, + + {2,0,30, &_residue_44p, + &_huff_book__44p4_long,&_huff_book__44p4_long, + &_resbook_44p_4,&_resbook_44p_4}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p4_lfe,&_huff_book__44p4_lfe, + &_resbook_44p_l4,&_resbook_44p_l4} +}; +static const vorbis_residue_template _res_44p51_5[]={ + {2,0,15, &_residue_44p_hi, + &_huff_book__44p5_short,&_huff_book__44p5_short, + &_resbook_44p_5,&_resbook_44p_5}, + + {2,0,30, &_residue_44p_hi, + &_huff_book__44p5_long,&_huff_book__44p5_long, + &_resbook_44p_5,&_resbook_44p_5}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p5_lfe,&_huff_book__44p5_lfe, + &_resbook_44p_l5,&_resbook_44p_l5} +}; +static const vorbis_residue_template _res_44p51_6[]={ + {2,0,15, &_residue_44p_hi, + &_huff_book__44p6_short,&_huff_book__44p6_short, + &_resbook_44p_6,&_resbook_44p_6}, + + {2,0,30, &_residue_44p_hi, + &_huff_book__44p6_long,&_huff_book__44p6_long, + &_resbook_44p_6,&_resbook_44p_6}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p6_lfe,&_huff_book__44p6_lfe, + &_resbook_44p_l6,&_resbook_44p_l6} +}; + + +static const vorbis_residue_template _res_44p51_7[]={ + {2,0,15, &_residue_44p_hi, + &_huff_book__44p7_short,&_huff_book__44p7_short, + &_resbook_44p_7,&_resbook_44p_7}, + + {2,0,30, &_residue_44p_hi, + &_huff_book__44p7_long,&_huff_book__44p7_long, + &_resbook_44p_7,&_resbook_44p_7}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p6_lfe,&_huff_book__44p6_lfe, + &_resbook_44p_l6,&_resbook_44p_l6} +}; +static const vorbis_residue_template _res_44p51_8[]={ + {2,0,15, &_residue_44p_hi, + &_huff_book__44p8_short,&_huff_book__44p8_short, + &_resbook_44p_8,&_resbook_44p_8}, + + {2,0,30, &_residue_44p_hi, + &_huff_book__44p8_long,&_huff_book__44p8_long, + &_resbook_44p_8,&_resbook_44p_8}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p6_lfe,&_huff_book__44p6_lfe, + &_resbook_44p_l6,&_resbook_44p_l6} +}; +static const vorbis_residue_template _res_44p51_9[]={ + {2,0,15, &_residue_44p_hi, + &_huff_book__44p9_short,&_huff_book__44p9_short, + &_resbook_44p_9,&_resbook_44p_9}, + + {2,0,30, &_residue_44p_hi, + &_huff_book__44p9_long,&_huff_book__44p9_long, + &_resbook_44p_9,&_resbook_44p_9}, + + {1,2,6, &_residue_44p_lfe, + &_huff_book__44p6_lfe,&_huff_book__44p6_lfe, + &_resbook_44p_l6,&_resbook_44p_l6} +}; + +static const vorbis_mapping_template _mapres_template_44_51[]={ + { _map_nominal_51, _res_44p51_n1 }, /* -1 */ + { _map_nominal_51, _res_44p51_0 }, /* 0 */ + { _map_nominal_51, _res_44p51_1 }, /* 1 */ + { _map_nominal_51, _res_44p51_2 }, /* 2 */ + { _map_nominal_51, _res_44p51_3 }, /* 3 */ + { _map_nominal_51, _res_44p51_4 }, /* 4 */ + { _map_nominal_51u, _res_44p51_5 }, /* 5 */ + { _map_nominal_51u, _res_44p51_6 }, /* 6 */ + { _map_nominal_51u, _res_44p51_7 }, /* 7 */ + { _map_nominal_51u, _res_44p51_8 }, /* 8 */ + { _map_nominal_51u, _res_44p51_9 }, /* 9 */ +}; diff --git a/vendor/vorbis/lib/modes/residue_44u.h b/vendor/vorbis/lib/modes/residue_44u.h new file mode 100644 index 0000000..2f3595e --- /dev/null +++ b/vendor/vorbis/lib/modes/residue_44u.h @@ -0,0 +1,317 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel residue templates for 32/44.1/48kHz uncoupled + + ********************************************************************/ + +#include "vorbis/codec.h" +#include "backends.h" +#include "books/uncoupled/res_books_uncoupled.h" + +/***** residue backends *********************************************/ + + +static const vorbis_info_residue0 _residue_44_low_un={ + 0,-1, -1, 8,-1,-1, + {0}, + {-1}, + { 0, 1, 1, 2, 2, 4, 28}, + { -1, 25, -1, 45, -1, -1, -1} +}; + +static const vorbis_info_residue0 _residue_44_mid_un={ + 0,-1, -1, 10,-1,-1, + /* 0 1 2 3 4 5 6 7 8 9 */ + {0}, + {-1}, + { 0, 1, 1, 2, 2, 4, 4, 16, 60}, + { -1, 30, -1, 50, -1, 80, -1, -1, -1} +}; + +static const vorbis_info_residue0 _residue_44_hi_un={ + 0,-1, -1, 10,-1,-1, + /* 0 1 2 3 4 5 6 7 8 9 */ + {0}, + {-1}, + { 0, 1, 2, 4, 8, 16, 32, 71,157}, + { -1, -1, -1, -1, -1, -1, -1, -1, -1} +}; + +/* mapping conventions: + only one submap (this would change for efficient 5.1 support for example)*/ +/* Four psychoacoustic profiles are used, one for each blocktype */ +static const vorbis_info_mapping0 _map_nominal_u[2]={ + {1, {0,0,0,0,0,0}, {0}, {0}, 0,{0},{0}}, + {1, {0,0,0,0,0,0}, {1}, {1}, 0,{0},{0}} +}; + +static const static_bookblock _resbook_44u_n1={ + { + {0}, + {0,0,&_44un1__p1_0}, + {0,0,&_44un1__p2_0}, + {0,0,&_44un1__p3_0}, + {0,0,&_44un1__p4_0}, + {0,0,&_44un1__p5_0}, + {&_44un1__p6_0,&_44un1__p6_1}, + {&_44un1__p7_0,&_44un1__p7_1,&_44un1__p7_2} + } +}; +static const static_bookblock _resbook_44u_0={ + { + {0}, + {0,0,&_44u0__p1_0}, + {0,0,&_44u0__p2_0}, + {0,0,&_44u0__p3_0}, + {0,0,&_44u0__p4_0}, + {0,0,&_44u0__p5_0}, + {&_44u0__p6_0,&_44u0__p6_1}, + {&_44u0__p7_0,&_44u0__p7_1,&_44u0__p7_2} + } +}; +static const static_bookblock _resbook_44u_1={ + { + {0}, + {0,0,&_44u1__p1_0}, + {0,0,&_44u1__p2_0}, + {0,0,&_44u1__p3_0}, + {0,0,&_44u1__p4_0}, + {0,0,&_44u1__p5_0}, + {&_44u1__p6_0,&_44u1__p6_1}, + {&_44u1__p7_0,&_44u1__p7_1,&_44u1__p7_2} + } +}; +static const static_bookblock _resbook_44u_2={ + { + {0}, + {0,0,&_44u2__p1_0}, + {0,0,&_44u2__p2_0}, + {0,0,&_44u2__p3_0}, + {0,0,&_44u2__p4_0}, + {0,0,&_44u2__p5_0}, + {&_44u2__p6_0,&_44u2__p6_1}, + {&_44u2__p7_0,&_44u2__p7_1,&_44u2__p7_2} + } +}; +static const static_bookblock _resbook_44u_3={ + { + {0}, + {0,0,&_44u3__p1_0}, + {0,0,&_44u3__p2_0}, + {0,0,&_44u3__p3_0}, + {0,0,&_44u3__p4_0}, + {0,0,&_44u3__p5_0}, + {&_44u3__p6_0,&_44u3__p6_1}, + {&_44u3__p7_0,&_44u3__p7_1,&_44u3__p7_2} + } +}; +static const static_bookblock _resbook_44u_4={ + { + {0}, + {0,0,&_44u4__p1_0}, + {0,0,&_44u4__p2_0}, + {0,0,&_44u4__p3_0}, + {0,0,&_44u4__p4_0}, + {0,0,&_44u4__p5_0}, + {&_44u4__p6_0,&_44u4__p6_1}, + {&_44u4__p7_0,&_44u4__p7_1,&_44u4__p7_2} + } +}; +static const static_bookblock _resbook_44u_5={ + { + {0}, + {0,0,&_44u5__p1_0}, + {0,0,&_44u5__p2_0}, + {0,0,&_44u5__p3_0}, + {0,0,&_44u5__p4_0}, + {0,0,&_44u5__p5_0}, + {0,0,&_44u5__p6_0}, + {&_44u5__p7_0,&_44u5__p7_1}, + {&_44u5__p8_0,&_44u5__p8_1}, + {&_44u5__p9_0,&_44u5__p9_1,&_44u5__p9_2} + } +}; +static const static_bookblock _resbook_44u_6={ + { + {0}, + {0,0,&_44u6__p1_0}, + {0,0,&_44u6__p2_0}, + {0,0,&_44u6__p3_0}, + {0,0,&_44u6__p4_0}, + {0,0,&_44u6__p5_0}, + {0,0,&_44u6__p6_0}, + {&_44u6__p7_0,&_44u6__p7_1}, + {&_44u6__p8_0,&_44u6__p8_1}, + {&_44u6__p9_0,&_44u6__p9_1,&_44u6__p9_2} + } +}; +static const static_bookblock _resbook_44u_7={ + { + {0}, + {0,0,&_44u7__p1_0}, + {0,0,&_44u7__p2_0}, + {0,0,&_44u7__p3_0}, + {0,0,&_44u7__p4_0}, + {0,0,&_44u7__p5_0}, + {0,0,&_44u7__p6_0}, + {&_44u7__p7_0,&_44u7__p7_1}, + {&_44u7__p8_0,&_44u7__p8_1}, + {&_44u7__p9_0,&_44u7__p9_1,&_44u7__p9_2} + } +}; +static const static_bookblock _resbook_44u_8={ + { + {0}, + {0,0,&_44u8_p1_0}, + {0,0,&_44u8_p2_0}, + {0,0,&_44u8_p3_0}, + {0,0,&_44u8_p4_0}, + {&_44u8_p5_0,&_44u8_p5_1}, + {&_44u8_p6_0,&_44u8_p6_1}, + {&_44u8_p7_0,&_44u8_p7_1}, + {&_44u8_p8_0,&_44u8_p8_1}, + {&_44u8_p9_0,&_44u8_p9_1,&_44u8_p9_2} + } +}; +static const static_bookblock _resbook_44u_9={ + { + {0}, + {0,0,&_44u9_p1_0}, + {0,0,&_44u9_p2_0}, + {0,0,&_44u9_p3_0}, + {0,0,&_44u9_p4_0}, + {&_44u9_p5_0,&_44u9_p5_1}, + {&_44u9_p6_0,&_44u9_p6_1}, + {&_44u9_p7_0,&_44u9_p7_1}, + {&_44u9_p8_0,&_44u9_p8_1}, + {&_44u9_p9_0,&_44u9_p9_1,&_44u9_p9_2} + } +}; + +static const vorbis_residue_template _res_44u_n1[]={ + {1,0,32, &_residue_44_low_un, + &_huff_book__44un1__short,&_huff_book__44un1__short, + &_resbook_44u_n1,&_resbook_44u_n1}, + + {1,0,32, &_residue_44_low_un, + &_huff_book__44un1__long,&_huff_book__44un1__long, + &_resbook_44u_n1,&_resbook_44u_n1} +}; +static const vorbis_residue_template _res_44u_0[]={ + {1,0,16, &_residue_44_low_un, + &_huff_book__44u0__short,&_huff_book__44u0__short, + &_resbook_44u_0,&_resbook_44u_0}, + + {1,0,32, &_residue_44_low_un, + &_huff_book__44u0__long,&_huff_book__44u0__long, + &_resbook_44u_0,&_resbook_44u_0} +}; +static const vorbis_residue_template _res_44u_1[]={ + {1,0,16, &_residue_44_low_un, + &_huff_book__44u1__short,&_huff_book__44u1__short, + &_resbook_44u_1,&_resbook_44u_1}, + + {1,0,32, &_residue_44_low_un, + &_huff_book__44u1__long,&_huff_book__44u1__long, + &_resbook_44u_1,&_resbook_44u_1} +}; +static const vorbis_residue_template _res_44u_2[]={ + {1,0,16, &_residue_44_low_un, + &_huff_book__44u2__short,&_huff_book__44u2__short, + &_resbook_44u_2,&_resbook_44u_2}, + + {1,0,32, &_residue_44_low_un, + &_huff_book__44u2__long,&_huff_book__44u2__long, + &_resbook_44u_2,&_resbook_44u_2} +}; +static const vorbis_residue_template _res_44u_3[]={ + {1,0,16, &_residue_44_low_un, + &_huff_book__44u3__short,&_huff_book__44u3__short, + &_resbook_44u_3,&_resbook_44u_3}, + + {1,0,32, &_residue_44_low_un, + &_huff_book__44u3__long,&_huff_book__44u3__long, + &_resbook_44u_3,&_resbook_44u_3} +}; +static const vorbis_residue_template _res_44u_4[]={ + {1,0,16, &_residue_44_low_un, + &_huff_book__44u4__short,&_huff_book__44u4__short, + &_resbook_44u_4,&_resbook_44u_4}, + + {1,0,32, &_residue_44_low_un, + &_huff_book__44u4__long,&_huff_book__44u4__long, + &_resbook_44u_4,&_resbook_44u_4} +}; + +static const vorbis_residue_template _res_44u_5[]={ + {1,0,16, &_residue_44_mid_un, + &_huff_book__44u5__short,&_huff_book__44u5__short, + &_resbook_44u_5,&_resbook_44u_5}, + + {1,0,32, &_residue_44_mid_un, + &_huff_book__44u5__long,&_huff_book__44u5__long, + &_resbook_44u_5,&_resbook_44u_5} +}; + +static const vorbis_residue_template _res_44u_6[]={ + {1,0,16, &_residue_44_mid_un, + &_huff_book__44u6__short,&_huff_book__44u6__short, + &_resbook_44u_6,&_resbook_44u_6}, + + {1,0,32, &_residue_44_mid_un, + &_huff_book__44u6__long,&_huff_book__44u6__long, + &_resbook_44u_6,&_resbook_44u_6} +}; + +static const vorbis_residue_template _res_44u_7[]={ + {1,0,16, &_residue_44_mid_un, + &_huff_book__44u7__short,&_huff_book__44u7__short, + &_resbook_44u_7,&_resbook_44u_7}, + + {1,0,32, &_residue_44_mid_un, + &_huff_book__44u7__long,&_huff_book__44u7__long, + &_resbook_44u_7,&_resbook_44u_7} +}; + +static const vorbis_residue_template _res_44u_8[]={ + {1,0,16, &_residue_44_hi_un, + &_huff_book__44u8__short,&_huff_book__44u8__short, + &_resbook_44u_8,&_resbook_44u_8}, + + {1,0,32, &_residue_44_hi_un, + &_huff_book__44u8__long,&_huff_book__44u8__long, + &_resbook_44u_8,&_resbook_44u_8} +}; +static const vorbis_residue_template _res_44u_9[]={ + {1,0,16, &_residue_44_hi_un, + &_huff_book__44u9__short,&_huff_book__44u9__short, + &_resbook_44u_9,&_resbook_44u_9}, + + {1,0,32, &_residue_44_hi_un, + &_huff_book__44u9__long,&_huff_book__44u9__long, + &_resbook_44u_9,&_resbook_44u_9} +}; + +static const vorbis_mapping_template _mapres_template_44_uncoupled[]={ + { _map_nominal_u, _res_44u_n1 }, /* -1 */ + { _map_nominal_u, _res_44u_0 }, /* 0 */ + { _map_nominal_u, _res_44u_1 }, /* 1 */ + { _map_nominal_u, _res_44u_2 }, /* 2 */ + { _map_nominal_u, _res_44u_3 }, /* 3 */ + { _map_nominal_u, _res_44u_4 }, /* 4 */ + { _map_nominal_u, _res_44u_5 }, /* 5 */ + { _map_nominal_u, _res_44u_6 }, /* 6 */ + { _map_nominal_u, _res_44u_7 }, /* 7 */ + { _map_nominal_u, _res_44u_8 }, /* 8 */ + { _map_nominal_u, _res_44u_9 }, /* 9 */ +}; diff --git a/vendor/vorbis/lib/modes/residue_8.h b/vendor/vorbis/lib/modes/residue_8.h new file mode 100644 index 0000000..b836f79 --- /dev/null +++ b/vendor/vorbis/lib/modes/residue_8.h @@ -0,0 +1,108 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel residue templates 8/11kHz + + ********************************************************************/ + +#include "vorbis/codec.h" +#include "backends.h" + +/***** residue backends *********************************************/ + +static const static_bookblock _resbook_8s_0={ + { + {0}, + {0,0,&_8c0_s_p1_0}, + {0}, + {0,0,&_8c0_s_p3_0}, + {0,0,&_8c0_s_p4_0}, + {0,0,&_8c0_s_p5_0}, + {0,0,&_8c0_s_p6_0}, + {&_8c0_s_p7_0,&_8c0_s_p7_1}, + {&_8c0_s_p8_0,&_8c0_s_p8_1}, + {&_8c0_s_p9_0,&_8c0_s_p9_1,&_8c0_s_p9_2} + } +}; +static const static_bookblock _resbook_8s_1={ + { + {0}, + {0,0,&_8c1_s_p1_0}, + {0}, + {0,0,&_8c1_s_p3_0}, + {0,0,&_8c1_s_p4_0}, + {0,0,&_8c1_s_p5_0}, + {0,0,&_8c1_s_p6_0}, + {&_8c1_s_p7_0,&_8c1_s_p7_1}, + {&_8c1_s_p8_0,&_8c1_s_p8_1}, + {&_8c1_s_p9_0,&_8c1_s_p9_1,&_8c1_s_p9_2} + } +}; + +static const vorbis_residue_template _res_8s_0[]={ + {2,0,32, &_residue_44_mid, + &_huff_book__8c0_s_single,&_huff_book__8c0_s_single, + &_resbook_8s_0,&_resbook_8s_0}, +}; +static const vorbis_residue_template _res_8s_1[]={ + {2,0,32, &_residue_44_mid, + &_huff_book__8c1_s_single,&_huff_book__8c1_s_single, + &_resbook_8s_1,&_resbook_8s_1}, +}; + +static const vorbis_mapping_template _mapres_template_8_stereo[2]={ + { _map_nominal, _res_8s_0 }, /* 0 */ + { _map_nominal, _res_8s_1 }, /* 1 */ +}; + +static const static_bookblock _resbook_8u_0={ + { + {0}, + {0,0,&_8u0__p1_0}, + {0,0,&_8u0__p2_0}, + {0,0,&_8u0__p3_0}, + {0,0,&_8u0__p4_0}, + {0,0,&_8u0__p5_0}, + {&_8u0__p6_0,&_8u0__p6_1}, + {&_8u0__p7_0,&_8u0__p7_1,&_8u0__p7_2} + } +}; +static const static_bookblock _resbook_8u_1={ + { + {0}, + {0,0,&_8u1__p1_0}, + {0,0,&_8u1__p2_0}, + {0,0,&_8u1__p3_0}, + {0,0,&_8u1__p4_0}, + {0,0,&_8u1__p5_0}, + {0,0,&_8u1__p6_0}, + {&_8u1__p7_0,&_8u1__p7_1}, + {&_8u1__p8_0,&_8u1__p8_1}, + {&_8u1__p9_0,&_8u1__p9_1,&_8u1__p9_2} + } +}; + +static const vorbis_residue_template _res_8u_0[]={ + {1,0,32, &_residue_44_low_un, + &_huff_book__8u0__single,&_huff_book__8u0__single, + &_resbook_8u_0,&_resbook_8u_0}, +}; +static const vorbis_residue_template _res_8u_1[]={ + {1,0,32, &_residue_44_mid_un, + &_huff_book__8u1__single,&_huff_book__8u1__single, + &_resbook_8u_1,&_resbook_8u_1}, +}; + +static const vorbis_mapping_template _mapres_template_8_uncoupled[2]={ + { _map_nominal_u, _res_8u_0 }, /* 0 */ + { _map_nominal_u, _res_8u_1 }, /* 1 */ +}; diff --git a/vendor/vorbis/lib/modes/setup_11.h b/vendor/vorbis/lib/modes/setup_11.h new file mode 100644 index 0000000..5ade5dd --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_11.h @@ -0,0 +1,142 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: 11kHz settings + + ********************************************************************/ + +#include "psych_11.h" + +static const int blocksize_11[2]={ + 512,512 +}; + +static const int _floor_mapping_11a[]={ + 6,6 +}; +static const int *_floor_mapping_11[]={ + _floor_mapping_11a +}; + +static const double rate_mapping_11[3]={ + 8000.,13000.,44000., +}; + +static const double rate_mapping_11_uncoupled[3]={ + 12000.,20000.,50000., +}; + +static const double quality_mapping_11[3]={ + -.1,.0,1. +}; + +static const ve_setup_data_template ve_setup_11_stereo={ + 2, + rate_mapping_11, + quality_mapping_11, + 2, + 9000, + 15000, + + blocksize_11, + blocksize_11, + + _psy_tone_masteratt_11, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_11, + NULL, + _vp_tonemask_adj_11, + + _psy_noiseguards_8, + _psy_noisebias_11, + _psy_noisebias_11, + NULL, + NULL, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_8_mapping, + NULL, + + {_noise_start_8,_noise_start_8}, + {_noise_part_8,_noise_part_8}, + _noise_thresh_11, + + _psy_ath_floater_8, + _psy_ath_abs_8, + + _psy_lowpass_11, + + _psy_global_44, + _global_mapping_8, + _psy_stereo_modes_8, + + _floor_books, + _floor, + 1, + _floor_mapping_11, + + _mapres_template_8_stereo +}; + +static const ve_setup_data_template ve_setup_11_uncoupled={ + 2, + rate_mapping_11_uncoupled, + quality_mapping_11, + -1, + 9000, + 15000, + + blocksize_11, + blocksize_11, + + _psy_tone_masteratt_11, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_11, + NULL, + _vp_tonemask_adj_11, + + _psy_noiseguards_8, + _psy_noisebias_11, + _psy_noisebias_11, + NULL, + NULL, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_8_mapping, + NULL, + + {_noise_start_8,_noise_start_8}, + {_noise_part_8,_noise_part_8}, + _noise_thresh_11, + + _psy_ath_floater_8, + _psy_ath_abs_8, + + _psy_lowpass_11, + + _psy_global_44, + _global_mapping_8, + _psy_stereo_modes_8, + + _floor_books, + _floor, + 1, + _floor_mapping_11, + + _mapres_template_8_uncoupled +}; diff --git a/vendor/vorbis/lib/modes/setup_16.h b/vendor/vorbis/lib/modes/setup_16.h new file mode 100644 index 0000000..8b2daaf --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_16.h @@ -0,0 +1,152 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: 16kHz settings + + ********************************************************************/ + +#include "psych_16.h" +#include "residue_16.h" + +static const int blocksize_16_short[3]={ + 1024,512,512 +}; +static const int blocksize_16_long[3]={ + 1024,1024,1024 +}; + +static const int _floor_mapping_16a[]={ + 9,3,3 +}; +static const int _floor_mapping_16b[]={ + 9,9,9 +}; +static const int *_floor_mapping_16[]={ + _floor_mapping_16a, + _floor_mapping_16b +}; + +static const double rate_mapping_16[4]={ + 12000.,20000.,44000.,86000. +}; + +static const double rate_mapping_16_uncoupled[4]={ + 16000.,28000.,64000.,100000. +}; + +static const double _global_mapping_16[4]={ 1., 2., 3., 4. }; + +static const double quality_mapping_16[4]={ -.1,.05,.5,1. }; + +static const double _psy_compand_16_mapping[4]={ 0., .8, 1., 1.}; + +static const ve_setup_data_template ve_setup_16_stereo={ + 3, + rate_mapping_16, + quality_mapping_16, + 2, + 15000, + 19000, + + blocksize_16_short, + blocksize_16_long, + + _psy_tone_masteratt_16, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + + _psy_noiseguards_16, + _psy_noisebias_16_impulse, + _psy_noisebias_16_short, + _psy_noisebias_16_short, + _psy_noisebias_16, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_16_mapping, + _psy_compand_16_mapping, + + {_noise_start_16,_noise_start_16}, + { _noise_part_16, _noise_part_16}, + _noise_thresh_16, + + _psy_ath_floater_16, + _psy_ath_abs_16, + + _psy_lowpass_16, + + _psy_global_44, + _global_mapping_16, + _psy_stereo_modes_16, + + _floor_books, + _floor, + 2, + _floor_mapping_16, + + _mapres_template_16_stereo +}; + +static const ve_setup_data_template ve_setup_16_uncoupled={ + 3, + rate_mapping_16_uncoupled, + quality_mapping_16, + -1, + 15000, + 19000, + + blocksize_16_short, + blocksize_16_long, + + _psy_tone_masteratt_16, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + + _psy_noiseguards_16, + _psy_noisebias_16_impulse, + _psy_noisebias_16_short, + _psy_noisebias_16_short, + _psy_noisebias_16, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_16_mapping, + _psy_compand_16_mapping, + + {_noise_start_16,_noise_start_16}, + { _noise_part_16, _noise_part_16}, + _noise_thresh_16, + + _psy_ath_floater_16, + _psy_ath_abs_16, + + _psy_lowpass_16, + + _psy_global_44, + _global_mapping_16, + _psy_stereo_modes_16, + + _floor_books, + _floor, + 2, + _floor_mapping_16, + + _mapres_template_16_uncoupled +}; diff --git a/vendor/vorbis/lib/modes/setup_22.h b/vendor/vorbis/lib/modes/setup_22.h new file mode 100644 index 0000000..eef5a4e --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_22.h @@ -0,0 +1,127 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: 22kHz settings + + ********************************************************************/ + +static const double rate_mapping_22[4]={ + 15000.,20000.,44000.,86000. +}; + +static const double rate_mapping_22_uncoupled[4]={ + 16000.,28000.,50000.,90000. +}; + +static const double _psy_lowpass_22[4]={9.5,11.,30.,99.}; + +static const ve_setup_data_template ve_setup_22_stereo={ + 3, + rate_mapping_22, + quality_mapping_16, + 2, + 19000, + 26000, + + blocksize_16_short, + blocksize_16_long, + + _psy_tone_masteratt_16, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + + _psy_noiseguards_16, + _psy_noisebias_16_impulse, + _psy_noisebias_16_short, + _psy_noisebias_16_short, + _psy_noisebias_16, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_16_mapping, + _psy_compand_16_mapping, + + {_noise_start_16,_noise_start_16}, + { _noise_part_16, _noise_part_16}, + _noise_thresh_16, + + _psy_ath_floater_16, + _psy_ath_abs_16, + + _psy_lowpass_22, + + _psy_global_44, + _global_mapping_16, + _psy_stereo_modes_16, + + _floor_books, + _floor, + 2, + _floor_mapping_16, + + _mapres_template_16_stereo +}; + +static const ve_setup_data_template ve_setup_22_uncoupled={ + 3, + rate_mapping_22_uncoupled, + quality_mapping_16, + -1, + 19000, + 26000, + + blocksize_16_short, + blocksize_16_long, + + _psy_tone_masteratt_16, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + _vp_tonemask_adj_16, + + _psy_noiseguards_16, + _psy_noisebias_16_impulse, + _psy_noisebias_16_short, + _psy_noisebias_16_short, + _psy_noisebias_16, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_16_mapping, + _psy_compand_16_mapping, + + {_noise_start_16,_noise_start_16}, + { _noise_part_16, _noise_part_16}, + _noise_thresh_16, + + _psy_ath_floater_16, + _psy_ath_abs_16, + + _psy_lowpass_22, + + _psy_global_44, + _global_mapping_16, + _psy_stereo_modes_16, + + _floor_books, + _floor, + 2, + _floor_mapping_16, + + _mapres_template_16_uncoupled +}; diff --git a/vendor/vorbis/lib/modes/setup_32.h b/vendor/vorbis/lib/modes/setup_32.h new file mode 100644 index 0000000..f87cb76 --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_32.h @@ -0,0 +1,131 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel settings for 32kHz + + ********************************************************************/ + +static const double rate_mapping_32[12]={ + 18000.,28000.,35000.,45000.,56000.,60000., + 75000.,90000.,100000.,115000.,150000.,190000., +}; + +static const double rate_mapping_32_un[12]={ + 30000.,42000.,52000.,64000.,72000.,78000., + 86000.,92000.,110000.,120000.,140000.,190000., +}; + +static const double _psy_lowpass_32[12]={ + 12.3,13.,13.,14.,15.,99.,99.,99.,99.,99.,99.,99. +}; + +static const ve_setup_data_template ve_setup_32_stereo={ + 11, + rate_mapping_32, + quality_mapping_44, + 2, + 26000, + 40000, + + blocksize_short_44, + blocksize_long_44, + + _psy_tone_masteratt_44, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_otherblock, + _vp_tonemask_adj_longblock, + _vp_tonemask_adj_otherblock, + + _psy_noiseguards_44, + _psy_noisebias_impulse, + _psy_noisebias_padding, + _psy_noisebias_trans, + _psy_noisebias_long, + _psy_noise_suppress, + + _psy_compand_44, + _psy_compand_short_mapping, + _psy_compand_long_mapping, + + {_noise_start_short_44,_noise_start_long_44}, + {_noise_part_short_44,_noise_part_long_44}, + _noise_thresh_44, + + _psy_ath_floater, + _psy_ath_abs, + + _psy_lowpass_32, + + _psy_global_44, + _global_mapping_44, + _psy_stereo_modes_44, + + _floor_books, + _floor, + 2, + _floor_mapping_44, + + _mapres_template_44_stereo +}; + +static const ve_setup_data_template ve_setup_32_uncoupled={ + 11, + rate_mapping_32_un, + quality_mapping_44, + -1, + 26000, + 40000, + + blocksize_short_44, + blocksize_long_44, + + _psy_tone_masteratt_44, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_otherblock, + _vp_tonemask_adj_longblock, + _vp_tonemask_adj_otherblock, + + _psy_noiseguards_44, + _psy_noisebias_impulse, + _psy_noisebias_padding, + _psy_noisebias_trans, + _psy_noisebias_long, + _psy_noise_suppress, + + _psy_compand_44, + _psy_compand_short_mapping, + _psy_compand_long_mapping, + + {_noise_start_short_44,_noise_start_long_44}, + {_noise_part_short_44,_noise_part_long_44}, + _noise_thresh_44, + + _psy_ath_floater, + _psy_ath_abs, + + _psy_lowpass_32, + + _psy_global_44, + _global_mapping_44, + NULL, + + _floor_books, + _floor, + 2, + _floor_mapping_44, + + _mapres_template_44_uncoupled +}; diff --git a/vendor/vorbis/lib/modes/setup_44.h b/vendor/vorbis/lib/modes/setup_44.h new file mode 100644 index 0000000..12d5928 --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_44.h @@ -0,0 +1,116 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel settings for 44.1/48kHz + + ********************************************************************/ + +#include "modes/floor_all.h" +#include "modes/residue_44.h" +#include "modes/psych_44.h" + +static const double rate_mapping_44_stereo[12]={ + 22500.,32000.,40000.,48000.,56000.,64000., + 80000.,96000.,112000.,128000.,160000.,250001. +}; + +static const double quality_mapping_44[12]={ + -.1,.0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1.0 +}; + +static const int blocksize_short_44[11]={ + 512,256,256,256,256,256,256,256,256,256,256 +}; +static const int blocksize_long_44[11]={ + 4096,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048 +}; + +static const double _psy_compand_short_mapping[12]={ + 0.5, 1., 1., 1.3, 1.6, 2., 2., 2., 2., 2., 2., 2. +}; +static const double _psy_compand_long_mapping[12]={ + 3.5, 4., 4., 4.3, 4.6, 5., 5., 5., 5., 5., 5., 5. +}; + +static const double _global_mapping_44[12]={ + /* 1., 1., 1.5, 2., 2., 2.5, 2.7, 3.0, 3.5, 4., 4. */ + 0., 1., 1., 1.5, 2., 2., 2.5, 2.7, 3.0, 3.7, 4., 4. +}; + +static const int _floor_mapping_44a[11]={ + 1,0,0,2,2,4,5,5,5,5,5 +}; + +static const int _floor_mapping_44b[11]={ + 8,7,7,7,7,7,7,7,7,7,7 +}; + +static const int _floor_mapping_44c[11]={ + 10,10,10,10,10,10,10,10,10,10,10 +}; + +static const int *_floor_mapping_44[]={ + _floor_mapping_44a, + _floor_mapping_44b, + _floor_mapping_44c, +}; + +static const ve_setup_data_template ve_setup_44_stereo={ + 11, + rate_mapping_44_stereo, + quality_mapping_44, + 2, + 40000, + 50000, + + blocksize_short_44, + blocksize_long_44, + + _psy_tone_masteratt_44, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_otherblock, + _vp_tonemask_adj_longblock, + _vp_tonemask_adj_otherblock, + + _psy_noiseguards_44, + _psy_noisebias_impulse, + _psy_noisebias_padding, + _psy_noisebias_trans, + _psy_noisebias_long, + _psy_noise_suppress, + + _psy_compand_44, + _psy_compand_short_mapping, + _psy_compand_long_mapping, + + {_noise_start_short_44,_noise_start_long_44}, + {_noise_part_short_44,_noise_part_long_44}, + _noise_thresh_44, + + _psy_ath_floater, + _psy_ath_abs, + + _psy_lowpass_44, + + _psy_global_44, + _global_mapping_44, + _psy_stereo_modes_44, + + _floor_books, + _floor, + 2, + _floor_mapping_44, + + _mapres_template_44_stereo +}; diff --git a/vendor/vorbis/lib/modes/setup_44p51.h b/vendor/vorbis/lib/modes/setup_44p51.h new file mode 100644 index 0000000..4d49173 --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_44p51.h @@ -0,0 +1,73 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel settings for 44.1/48kHz 5.1 surround modes + + ********************************************************************/ + +#include "modes/residue_44p51.h" + +static const double rate_mapping_44p51[12]={ + 14000.,20000.,28000.,38000.,46000.,54000., + 75000.,96000.,120000.,140000.,180000.,240001. +}; + +static const ve_setup_data_template ve_setup_44_51={ + 11, + rate_mapping_44p51, + quality_mapping_44, + 6, + 40000, + 70000, + + blocksize_short_44, + blocksize_long_44, + + _psy_tone_masteratt_44, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_otherblock, + _vp_tonemask_adj_longblock, + _vp_tonemask_adj_otherblock, + + _psy_noiseguards_44, + _psy_noisebias_impulse, + _psy_noisebias_padding, + _psy_noisebias_trans, + _psy_noisebias_long, + _psy_noise_suppress, + + _psy_compand_44, + _psy_compand_short_mapping, + _psy_compand_long_mapping, + + {_noise_start_short_44,_noise_start_long_44}, + {_noise_part_short_44,_noise_part_long_44}, + _noise_thresh_44, + + _psy_ath_floater, + _psy_ath_abs, + + _psy_lowpass_44, + + _psy_global_44, + _global_mapping_44, + _psy_stereo_modes_44, + + _floor_books, + _floor, + 3, + _floor_mapping_44, + + _mapres_template_44_51 +}; diff --git a/vendor/vorbis/lib/modes/setup_44u.h b/vendor/vorbis/lib/modes/setup_44u.h new file mode 100644 index 0000000..2dd8bf7 --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_44u.h @@ -0,0 +1,73 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: toplevel settings for 44.1/48kHz uncoupled modes + + ********************************************************************/ + +#include "modes/residue_44u.h" + +static const double rate_mapping_44_un[12]={ + 32000.,48000.,60000.,70000.,80000.,86000., + 96000.,110000.,120000.,140000.,160000.,240001. +}; + +static const ve_setup_data_template ve_setup_44_uncoupled={ + 11, + rate_mapping_44_un, + quality_mapping_44, + -1, + 40000, + 50000, + + blocksize_short_44, + blocksize_long_44, + + _psy_tone_masteratt_44, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_otherblock, + _vp_tonemask_adj_longblock, + _vp_tonemask_adj_otherblock, + + _psy_noiseguards_44, + _psy_noisebias_impulse, + _psy_noisebias_padding, + _psy_noisebias_trans, + _psy_noisebias_long, + _psy_noise_suppress, + + _psy_compand_44, + _psy_compand_short_mapping, + _psy_compand_long_mapping, + + {_noise_start_short_44,_noise_start_long_44}, + {_noise_part_short_44,_noise_part_long_44}, + _noise_thresh_44, + + _psy_ath_floater, + _psy_ath_abs, + + _psy_lowpass_44, + + _psy_global_44, + _global_mapping_44, + _psy_stereo_modes_44, + + _floor_books, + _floor, + 2, + _floor_mapping_44, + + _mapres_template_44_uncoupled +}; diff --git a/vendor/vorbis/lib/modes/setup_8.h b/vendor/vorbis/lib/modes/setup_8.h new file mode 100644 index 0000000..16b02e0 --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_8.h @@ -0,0 +1,148 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: 8kHz settings + + ********************************************************************/ + +#include "psych_8.h" +#include "residue_8.h" + +static const int blocksize_8[2]={ + 512,512 +}; + +static const int _floor_mapping_8a[]={ + 6,6 +}; + +static const int *_floor_mapping_8[]={ + _floor_mapping_8a +}; + +static const double rate_mapping_8[3]={ + 6000.,9000.,32000., +}; + +static const double rate_mapping_8_uncoupled[3]={ + 8000.,14000.,42000., +}; + +static const double quality_mapping_8[3]={ + -.1,.0,1. +}; + +static const double _psy_compand_8_mapping[3]={ 0., 1., 1.}; + +static const double _global_mapping_8[3]={ 1., 2., 3. }; + +static const ve_setup_data_template ve_setup_8_stereo={ + 2, + rate_mapping_8, + quality_mapping_8, + 2, + 8000, + 9000, + + blocksize_8, + blocksize_8, + + _psy_tone_masteratt_8, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_8, + NULL, + _vp_tonemask_adj_8, + + _psy_noiseguards_8, + _psy_noisebias_8, + _psy_noisebias_8, + NULL, + NULL, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_8_mapping, + NULL, + + {_noise_start_8,_noise_start_8}, + {_noise_part_8,_noise_part_8}, + _noise_thresh_5only, + + _psy_ath_floater_8, + _psy_ath_abs_8, + + _psy_lowpass_8, + + _psy_global_44, + _global_mapping_8, + _psy_stereo_modes_8, + + _floor_books, + _floor, + 1, + _floor_mapping_8, + + _mapres_template_8_stereo +}; + +static const ve_setup_data_template ve_setup_8_uncoupled={ + 2, + rate_mapping_8_uncoupled, + quality_mapping_8, + -1, + 8000, + 9000, + + blocksize_8, + blocksize_8, + + _psy_tone_masteratt_8, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_8, + NULL, + _vp_tonemask_adj_8, + + _psy_noiseguards_8, + _psy_noisebias_8, + _psy_noisebias_8, + NULL, + NULL, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_8_mapping, + NULL, + + {_noise_start_8,_noise_start_8}, + {_noise_part_8,_noise_part_8}, + _noise_thresh_5only, + + _psy_ath_floater_8, + _psy_ath_abs_8, + + _psy_lowpass_8, + + _psy_global_44, + _global_mapping_8, + _psy_stereo_modes_8, + + _floor_books, + _floor, + 1, + _floor_mapping_8, + + _mapres_template_8_uncoupled +}; diff --git a/vendor/vorbis/lib/modes/setup_X.h b/vendor/vorbis/lib/modes/setup_X.h new file mode 100644 index 0000000..27807c1 --- /dev/null +++ b/vendor/vorbis/lib/modes/setup_X.h @@ -0,0 +1,224 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: catch-all toplevel settings for q modes only + + ********************************************************************/ + +static const double rate_mapping_X[12]={ + -1.,-1.,-1.,-1.,-1.,-1., + -1.,-1.,-1.,-1.,-1.,-1. +}; + +static const ve_setup_data_template ve_setup_X_stereo={ + 11, + rate_mapping_X, + quality_mapping_44, + 2, + 50000, + 200000, + + blocksize_short_44, + blocksize_long_44, + + _psy_tone_masteratt_44, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_otherblock, + _vp_tonemask_adj_longblock, + _vp_tonemask_adj_otherblock, + + _psy_noiseguards_44, + _psy_noisebias_impulse, + _psy_noisebias_padding, + _psy_noisebias_trans, + _psy_noisebias_long, + _psy_noise_suppress, + + _psy_compand_44, + _psy_compand_short_mapping, + _psy_compand_long_mapping, + + {_noise_start_short_44,_noise_start_long_44}, + {_noise_part_short_44,_noise_part_long_44}, + _noise_thresh_44, + + _psy_ath_floater, + _psy_ath_abs, + + _psy_lowpass_44, + + _psy_global_44, + _global_mapping_44, + _psy_stereo_modes_44, + + _floor_books, + _floor, + 2, + _floor_mapping_44, + + _mapres_template_44_stereo +}; + +static const ve_setup_data_template ve_setup_X_uncoupled={ + 11, + rate_mapping_X, + quality_mapping_44, + -1, + 50000, + 200000, + + blocksize_short_44, + blocksize_long_44, + + _psy_tone_masteratt_44, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_otherblock, + _vp_tonemask_adj_longblock, + _vp_tonemask_adj_otherblock, + + _psy_noiseguards_44, + _psy_noisebias_impulse, + _psy_noisebias_padding, + _psy_noisebias_trans, + _psy_noisebias_long, + _psy_noise_suppress, + + _psy_compand_44, + _psy_compand_short_mapping, + _psy_compand_long_mapping, + + {_noise_start_short_44,_noise_start_long_44}, + {_noise_part_short_44,_noise_part_long_44}, + _noise_thresh_44, + + _psy_ath_floater, + _psy_ath_abs, + + _psy_lowpass_44, + + _psy_global_44, + _global_mapping_44, + NULL, + + _floor_books, + _floor, + 2, + _floor_mapping_44, + + _mapres_template_44_uncoupled +}; + +static const ve_setup_data_template ve_setup_XX_stereo={ + 2, + rate_mapping_X, + quality_mapping_8, + 2, + 0, + 8000, + + blocksize_8, + blocksize_8, + + _psy_tone_masteratt_8, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_8, + NULL, + _vp_tonemask_adj_8, + + _psy_noiseguards_8, + _psy_noisebias_8, + _psy_noisebias_8, + NULL, + NULL, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_8_mapping, + NULL, + + {_noise_start_8,_noise_start_8}, + {_noise_part_8,_noise_part_8}, + _noise_thresh_5only, + + _psy_ath_floater_8, + _psy_ath_abs_8, + + _psy_lowpass_8, + + _psy_global_44, + _global_mapping_8, + _psy_stereo_modes_8, + + _floor_books, + _floor, + 1, + _floor_mapping_8, + + _mapres_template_8_stereo +}; + +static const ve_setup_data_template ve_setup_XX_uncoupled={ + 2, + rate_mapping_X, + quality_mapping_8, + -1, + 0, + 8000, + + blocksize_8, + blocksize_8, + + _psy_tone_masteratt_8, + _psy_tone_0dB, + _psy_tone_suppress, + + _vp_tonemask_adj_8, + NULL, + _vp_tonemask_adj_8, + + _psy_noiseguards_8, + _psy_noisebias_8, + _psy_noisebias_8, + NULL, + NULL, + _psy_noise_suppress, + + _psy_compand_8, + _psy_compand_8_mapping, + NULL, + + {_noise_start_8,_noise_start_8}, + {_noise_part_8,_noise_part_8}, + _noise_thresh_5only, + + _psy_ath_floater_8, + _psy_ath_abs_8, + + _psy_lowpass_8, + + _psy_global_44, + _global_mapping_8, + _psy_stereo_modes_8, + + _floor_books, + _floor, + 1, + _floor_mapping_8, + + _mapres_template_8_uncoupled +}; diff --git a/vendor/vorbis/lib/os.h b/vendor/vorbis/lib/os.h new file mode 100644 index 0000000..9ded735 --- /dev/null +++ b/vendor/vorbis/lib/os.h @@ -0,0 +1,189 @@ +#ifndef _OS_H +#define _OS_H +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + + ********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "misc.h" + +#ifndef _V_IFDEFJAIL_H_ +# define _V_IFDEFJAIL_H_ + +# ifdef __GNUC__ +# define STIN static __inline__ +# elif defined(_WIN32) +# define STIN static __inline +# else +# define STIN static +# endif + +#ifdef DJGPP +# define rint(x) (floor((x)+0.5f)) +#endif + +#ifndef M_PI +# define M_PI (3.1415926536f) +#endif + +#if defined(_WIN32) && !defined(__SYMBIAN32__) +# include +# define rint(x) (floor((x)+0.5f)) +# define NO_FLOAT_MATH_LIB +# define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b)) +#endif + +#if defined(__SYMBIAN32__) && defined(__WINS__) +void *_alloca(size_t size); +# define alloca _alloca +#endif + +#ifndef FAST_HYPOT +# define FAST_HYPOT hypot +#endif + +#endif /* _V_IFDEFJAIL_H_ */ + +#ifdef HAVE_ALLOCA_H +# include +#endif + +#ifdef USE_MEMORY_H +# include +#endif + +#ifndef min +# define min(x,y) ((x)>(y)?(y):(x)) +#endif + +#ifndef max +# define max(x,y) ((x)<(y)?(y):(x)) +#endif + + +/* Special i386 GCC implementation */ +#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 + block and so we end up doing stupid things like a store/load that + is collectively a noop), we do it this way */ + +/* we must set up the fpu before this works!! */ + +typedef ogg_int16_t vorbis_fpu_control; + +static inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ + ogg_int16_t ret; + ogg_int16_t temp; + __asm__ __volatile__("fnstcw %0\n\t" + "movw %0,%%dx\n\t" + "andw $62463,%%dx\n\t" + "movw %%dx,%1\n\t" + "fldcw %1\n\t":"=m"(ret):"m"(temp): "dx"); + *fpu=ret; +} + +static inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ + __asm__ __volatile__("fldcw %0":: "m"(fpu)); +} + +/* assumes the FPU is in round mode! */ +static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise, + we get extra fst/fld to + truncate precision */ + int i; + __asm__("fistl %0": "=m"(i) : "t"(f)); + return(i); +} +#endif /* Special i386 GCC implementation */ + + +/* 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(_M_IX86) && !defined(_WIN32_WCE) +# define VORBIS_FPU_CONTROL + +typedef ogg_int16_t vorbis_fpu_control; + +static __inline int vorbis_ftoi(double f){ + int i; + __asm{ + fld f + fistp i + } + return i; +} + +static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ + (void)fpu; +} + +static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ + (void)fpu; +} + +#endif /* Special MSVC 32 bit implementation */ + + +/* 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(_M_X64)) || (defined(__GNUC__) && defined (__SSE2_MATH__)) +# define VORBIS_FPU_CONTROL + +typedef ogg_int16_t vorbis_fpu_control; + +#include +static __inline int vorbis_ftoi(double f){ + return _mm_cvtsd_si32(_mm_load_sd(&f)); +} + +static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ + (void)fpu; +} + +static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ + (void)fpu; +} + +#endif /* Special MSVC x64 implementation */ + + +/* If no special implementation was found for the current compiler / platform, + use the default implementation here: */ +#ifndef VORBIS_FPU_CONTROL + +typedef int vorbis_fpu_control; + +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 */ + return (int)floor(f+.5); +} + +/* We don't have special code for this compiler/arch, so do it the slow way */ +# define vorbis_fpu_setround(vorbis_fpu_control) {} +# define vorbis_fpu_restore(vorbis_fpu_control) {} + +#endif /* default implementation */ + +#endif /* _OS_H */ diff --git a/vendor/vorbis/lib/psy.c b/vendor/vorbis/lib/psy.c new file mode 100644 index 0000000..036b094 --- /dev/null +++ b/vendor/vorbis/lib/psy.c @@ -0,0 +1,1209 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: psychoacoustics not including preecho + + ********************************************************************/ + +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" + +#include "masking.h" +#include "psy.h" +#include "os.h" +#include "lpc.h" +#include "smallft.h" +#include "scales.h" +#include "misc.h" + +#define NEGINF -9999.f +static const double stereo_threshholds[]={0.0, .5, 1.0, 1.5, 2.5, 4.5, 8.5, 16.5, 9e10}; +static const double stereo_threshholds_limited[]={0.0, .5, 1.0, 1.5, 2.0, 2.5, 4.5, 8.5, 9e10}; + +vorbis_look_psy_global *_vp_global_look(vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy_global *gi=&ci->psy_g_param; + vorbis_look_psy_global *look=_ogg_calloc(1,sizeof(*look)); + + look->channels=vi->channels; + + look->ampmax=-9999.; + look->gi=gi; + return(look); +} + +void _vp_global_free(vorbis_look_psy_global *look){ + if(look){ + memset(look,0,sizeof(*look)); + _ogg_free(look); + } +} + +void _vi_gpsy_free(vorbis_info_psy_global *i){ + if(i){ + memset(i,0,sizeof(*i)); + _ogg_free(i); + } +} + +void _vi_psy_free(vorbis_info_psy *i){ + if(i){ + memset(i,0,sizeof(*i)); + _ogg_free(i); + } +} + +static void min_curve(float *c, + float *c2){ + int i; + for(i=0;ic[i])c[i]=c2[i]; +} + +static void attenuate_curve(float *c,float att){ + int i; + for(i=0;iATH[j+k+ath_offset])min=ATH[j+k+ath_offset]; + }else{ + if(min>ATH[MAX_ATH-1])min=ATH[MAX_ATH-1]; + } + ath[j]=min; + } + + /* copy curves into working space, replicate the 50dB curve to 30 + and 40, replicate the 100dB curve to 110 */ + for(j=0;j<6;j++) + memcpy(workc[i][j+2],tonemasks[i][j],EHMER_MAX*sizeof(*tonemasks[i][j])); + memcpy(workc[i][0],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0])); + memcpy(workc[i][1],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0])); + + /* apply centered curve boost/decay */ + for(j=0;j0)adj=0.; + if(adj>0. && center_boost<0)adj=0.; + workc[i][j][k]+=adj; + } + } + + /* normalize curves so the driving amplitude is 0dB */ + /* make temp curves with the ATH overlayed */ + for(j=0;j an eighth of an octave and that the eighth + octave values may also be composited. */ + + /* which octave curves will we be compositing? */ + bin=floor(fromOC(i*.5)/binHz); + lo_curve= ceil(toOC(bin*binHz+1)*2); + hi_curve= floor(toOC((bin+1)*binHz)*2); + if(lo_curve>i)lo_curve=i; + if(lo_curve<0)lo_curve=0; + if(hi_curve>=P_BANDS)hi_curve=P_BANDS-1; + + for(m=0;mn)lo_bin=n; + if(lo_binn)hi_bin=n; + + for(;lworkc[k][m][j]) + brute_buffer[l]=workc[k][m][j]; + } + + for(;lworkc[k][m][EHMER_MAX-1]) + brute_buffer[l]=workc[k][m][EHMER_MAX-1]; + + } + + /* be equally paranoid about being valid up to next half ocatve */ + if(i+1n)lo_bin=n; + if(lo_binn)hi_bin=n; + + for(;lworkc[k][m][j]) + brute_buffer[l]=workc[k][m][j]; + } + + for(;lworkc[k][m][EHMER_MAX-1]) + brute_buffer[l]=workc[k][m][EHMER_MAX-1]; + + } + + + for(j=0;j=n){ + ret[i][m][j+2]=-999.; + }else{ + ret[i][m][j+2]=brute_buffer[bin]; + } + } + } + + /* add fenceposts */ + for(j=0;j-200.f)break; + ret[i][m][0]=j; + + for(j=EHMER_MAX-1;j>EHMER_OFFSET+1;j--) + if(ret[i][m][j+2]>-200.f) + break; + ret[i][m][1]=j; + + } + } + + return(ret); +} + +void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi, + vorbis_info_psy_global *gi,int n,long rate){ + long i,j,lo=-99,hi=1; + long maxoc; + memset(p,0,sizeof(*p)); + + p->eighth_octave_lines=gi->eighth_octave_lines; + p->shiftoc=rint(log(gi->eighth_octave_lines*8.f)/log(2.f))-1; + + p->firstoc=toOC(.25f*rate*.5/n)*(1<<(p->shiftoc+1))-gi->eighth_octave_lines; + maxoc=toOC((n+.25f)*rate*.5/n)*(1<<(p->shiftoc+1))+.5f; + p->total_octave_lines=maxoc-p->firstoc+1; + p->ath=_ogg_malloc(n*sizeof(*p->ath)); + + p->octave=_ogg_malloc(n*sizeof(*p->octave)); + p->bark=_ogg_malloc(n*sizeof(*p->bark)); + p->vi=vi; + p->n=n; + p->rate=rate; + + /* AoTuV HF weighting */ + p->m_val = 1.; + if(rate < 26000) p->m_val = 0; + else if(rate < 38000) p->m_val = .94; /* 32kHz */ + else if(rate > 46000) p->m_val = 1.275; /* 48kHz */ + + /* set up the lookups for a given blocksize and sample rate */ + + for(i=0,j=0;iath[j]=base+100.; + base+=delta; + } + } + } + + for(;jath[j]=p->ath[j-1]; + } + + for(i=0;inoisewindowlominnoisewindowlo);lo++); + + for(;hi<=n && (hinoisewindowhimin || + toBARK(rate/(2*n)*hi)<(bark+vi->noisewindowhi));hi++); + + p->bark[i]=((lo-1)<<16)+(hi-1); + + } + + for(i=0;ioctave[i]=toOC((i+.25f)*.5*rate/n)*(1<<(p->shiftoc+1))+.5f; + + p->tonecurves=setup_tone_curves(vi->toneatt,rate*.5/n,n, + vi->tone_centerboost,vi->tone_decay); + + /* set up rolling noise median */ + p->noiseoffset=_ogg_malloc(P_NOISECURVES*sizeof(*p->noiseoffset)); + for(i=0;inoiseoffset[i]=_ogg_malloc(n*sizeof(**p->noiseoffset)); + + for(i=0;i=P_BANDS-1)halfoc=P_BANDS-1; + inthalfoc=(int)halfoc; + del=halfoc-inthalfoc; + + for(j=0;jnoiseoffset[j][i]= + p->vi->noiseoff[j][inthalfoc]*(1.-del) + + p->vi->noiseoff[j][inthalfoc+1]*del; + + } +#if 0 + { + static int ls=0; + _analysis_output_always("noiseoff0",ls,p->noiseoffset[0],n,1,0,0); + _analysis_output_always("noiseoff1",ls,p->noiseoffset[1],n,1,0,0); + _analysis_output_always("noiseoff2",ls++,p->noiseoffset[2],n,1,0,0); + } +#endif +} + +void _vp_psy_clear(vorbis_look_psy *p){ + int i,j; + if(p){ + if(p->ath)_ogg_free(p->ath); + if(p->octave)_ogg_free(p->octave); + if(p->bark)_ogg_free(p->bark); + if(p->tonecurves){ + for(i=0;itonecurves[i][j]); + } + _ogg_free(p->tonecurves[i]); + } + _ogg_free(p->tonecurves); + } + if(p->noiseoffset){ + for(i=0;inoiseoffset[i]); + } + _ogg_free(p->noiseoffset); + } + memset(p,0,sizeof(*p)); + } +} + +/* octave/(8*eighth_octave_lines) x scale and dB y scale */ +static void seed_curve(float *seed, + const float **curves, + float amp, + int oc, int n, + int linesper,float dBoffset){ + int i,post1; + int seedptr; + const float *posts,*curve; + + int choice=(int)((amp+dBoffset-P_LEVEL_0)*.1f); + choice=max(choice,0); + choice=min(choice,P_LEVELS-1); + posts=curves[choice]; + curve=posts+2; + post1=(int)posts[1]; + seedptr=oc+(posts[0]-EHMER_OFFSET)*linesper-(linesper>>1); + + for(i=posts[0];i0){ + float lin=amp+curve[i]; + if(seed[seedptr]=n)break; + } +} + +static void seed_loop(vorbis_look_psy *p, + const float ***curves, + const float *f, + const float *flr, + float *seed, + float specmax){ + vorbis_info_psy *vi=p->vi; + long n=p->n,i; + float dBoffset=vi->max_curve_dB-specmax; + + /* prime the working vector with peak values */ + + for(i=0;ioctave[i]; + while(i+1octave[i+1]==oc){ + i++; + if(f[i]>max)max=f[i]; + } + + if(max+6.f>flr[i]){ + oc=oc>>p->shiftoc; + + if(oc>=P_BANDS)oc=P_BANDS-1; + if(oc<0)oc=0; + + seed_curve(seed, + curves[oc], + max, + p->octave[i]-p->firstoc, + p->total_octave_lines, + p->eighth_octave_lines, + dBoffset); + } + } +} + +static void seed_chase(float *seeds, int linesper, long n){ + long *posstack=alloca(n*sizeof(*posstack)); + float *ampstack=alloca(n*sizeof(*ampstack)); + long stack=0; + long pos=0; + long i; + + for(i=0;i1 && ampstack[stack-1]<=ampstack[stack-2] && + iampstack[i]){ + endpos=posstack[i+1]; + }else{ + endpos=posstack[i]+linesper+1; /* +1 is important, else bin 0 is + discarded in short frames */ + } + if(endpos>n)endpos=n; + for(;pos +static void max_seeds(vorbis_look_psy *p, + float *seed, + float *flr){ + long n=p->total_octave_lines; + int linesper=p->eighth_octave_lines; + long linpos=0; + long pos; + + seed_chase(seed,linesper,n); /* for masking */ + + pos=p->octave[0]-p->firstoc-(linesper>>1); + + while(linpos+1n){ + float minV=seed[pos]; + long end=((p->octave[linpos]+p->octave[linpos+1])>>1)-p->firstoc; + if(minV>p->vi->tone_abs_limit)minV=p->vi->tone_abs_limit; + while(pos+1<=end){ + pos++; + if((seed[pos]>NEGINF && seed[pos]firstoc; + for(;linposn && p->octave[linpos]<=end;linpos++) + if(flr[linpos]total_octave_lines-1]; + for(;linposn;linpos++) + if(flr[linpos]> 16; + hi = b[i] & 0xffff; + if( lo>=0 || -lo>=n ) break; + if( hi>=n ) break; + + tN = N[hi] + N[-lo]; + tX = X[hi] - X[-lo]; + tXX = XX[hi] + XX[-lo]; + tY = Y[hi] + Y[-lo]; + tXY = XY[hi] - XY[-lo]; + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + if (R < 0.f) R = 0.f; + + noise[i] = R - offset; + } + + for ( ; i < n; i++, x += 1.f) { + + lo = b[i] >> 16; + hi = b[i] & 0xffff; + if( lo<0 || lo>=n ) break; + if( hi>=n ) break; + + tN = N[hi] - N[lo]; + tX = X[hi] - X[lo]; + tXX = XX[hi] - XX[lo]; + tY = Y[hi] - Y[lo]; + tXY = XY[hi] - XY[lo]; + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + if (R < 0.f) R = 0.f; + + noise[i] = R - offset; + } + + for ( ; i < n; i++, x += 1.f) { + + R = (A + x * B) / D; + if (R < 0.f) R = 0.f; + + noise[i] = R - offset; + } + + if (fixed <= 0) return; + + for (i = 0, x = 0.f; i < n; i++, x += 1.f) { + hi = i + fixed / 2; + lo = hi - fixed; + if ( hi>=n ) break; + if ( lo>=0 ) break; + + tN = N[hi] + N[-lo]; + tX = X[hi] - X[-lo]; + tXX = XX[hi] + XX[-lo]; + tY = Y[hi] + Y[-lo]; + tXY = XY[hi] - XY[-lo]; + + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + + if (R - offset < noise[i]) noise[i] = R - offset; + } + for ( ; i < n; i++, x += 1.f) { + + hi = i + fixed / 2; + lo = hi - fixed; + if ( hi>=n ) break; + if ( lo<0 ) break; + + tN = N[hi] - N[lo]; + tX = X[hi] - X[lo]; + tXX = XX[hi] - XX[lo]; + tY = Y[hi] - Y[lo]; + tXY = XY[hi] - XY[lo]; + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + + if (R - offset < noise[i]) noise[i] = R - offset; + } + for ( ; i < n; i++, x += 1.f) { + R = (A + x * B) / D; + if (R - offset < noise[i]) noise[i] = R - offset; + } +} + +void _vp_noisemask(vorbis_look_psy *p, + float *logmdct, + float *logmask){ + + int i,n=p->n; + float *work=alloca(n*sizeof(*work)); + + bark_noise_hybridmp(n,p->bark,logmdct,logmask, + 140.,-1); + + for(i=0;ibark,work,logmask,0., + p->vi->noisewindowfixed); + + for(i=0;i=NOISE_COMPAND_LEVELS)dB=NOISE_COMPAND_LEVELS-1; + if(dB<0)dB=0; + logmask[i]= work[i]+p->vi->noisecompand[dB]; + } + +} + +void _vp_tonemask(vorbis_look_psy *p, + float *logfft, + float *logmask, + float global_specmax, + float local_specmax){ + + int i,n=p->n; + + float *seed=alloca(sizeof(*seed)*p->total_octave_lines); + float att=local_specmax+p->vi->ath_adjatt; + for(i=0;itotal_octave_lines;i++)seed[i]=NEGINF; + + /* set the ATH (floating below localmax, not global max by a + specified att) */ + if(attvi->ath_maxatt)att=p->vi->ath_maxatt; + + for(i=0;iath[i]+att; + + /* tone masking */ + seed_loop(p,(const float ***)p->tonecurves,logfft,logmask,seed,global_specmax); + max_seeds(p,seed,logmask); + +} + +void _vp_offset_and_mix(vorbis_look_psy *p, + float *noise, + float *tone, + int offset_select, + float *logmask, + float *mdct, + float *logmdct){ + int i,n=p->n; + float de, coeffi, cx;/* AoTuV */ + float toneatt=p->vi->tone_masteratt[offset_select]; + + cx = p->m_val; + + for(i=0;inoiseoffset[offset_select][i]; + if(val>p->vi->noisemaxsupp)val=p->vi->noisemaxsupp; + logmask[i]=max(val,tone[i]+toneatt); + + + /* AoTuV */ + /** @ M1 ** + The following codes improve a noise problem. + A fundamental idea uses the value of masking and carries out + the relative compensation of the MDCT. + However, this code is not perfect and all noise problems cannot be solved. + by Aoyumi @ 2004/04/18 + */ + + if(offset_select == 1) { + coeffi = -17.2; /* coeffi is a -17.2dB threshold */ + val = val - logmdct[i]; /* val == mdct line value relative to floor in dB */ + + if(val > coeffi){ + /* mdct value is > -17.2 dB below floor */ + + de = 1.0-((val-coeffi)*0.005*cx); + /* pro-rated attenuation: + -0.00 dB boost if mdct value is -17.2dB (relative to floor) + -0.77 dB boost if mdct value is 0dB (relative to floor) + -1.64 dB boost if mdct value is +17.2dB (relative to floor) + etc... */ + + if(de < 0) de = 0.0001; + }else + /* mdct value is <= -17.2 dB below floor */ + + de = 1.0-((val-coeffi)*0.0003*cx); + /* pro-rated attenuation: + +0.00 dB atten if mdct value is -17.2dB (relative to floor) + +0.45 dB atten if mdct value is -34.4dB (relative to floor) + etc... */ + + mdct[i] *= de; + + } + } +} + +float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd){ + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy_global *gi=&ci->psy_g_param; + + int n=ci->blocksizes[vd->W]/2; + float secs=(float)n/vi->rate; + + amp+=secs*gi->ampmax_att_per_sec; + if(amp<-9999)amp=-9999; + return(amp); +} + +static float FLOOR1_fromdB_LOOKUP[256]={ + 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, + 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, + 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, + 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, + 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, + 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, + 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, + 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, + 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, + 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, + 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, + 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, + 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, + 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, + 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, + 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, + 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, + 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, + 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, + 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, + 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, + 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, + 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, + 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, + 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, + 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, + 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, + 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, + 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, + 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, + 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, + 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, + 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, + 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, + 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, + 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, + 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, + 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, + 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, + 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, + 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, + 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, + 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, + 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, + 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, + 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, + 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, + 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, + 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, + 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, + 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, + 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, + 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, + 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, + 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, + 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, + 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, + 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, + 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, + 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, + 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, + 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, + 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, + 0.82788260F, 0.88168307F, 0.9389798F, 1.F, +}; + +/* this is for per-channel noise normalization */ +static int apsort(const void *a, const void *b){ + float f1=**(float**)a; + float f2=**(float**)b; + return (f1f2); +} + +static void flag_lossless(int limit, float prepoint, float postpoint, float *mdct, + float *floor, int *flag, int i, int jn){ + int j; + for(j=0;j=limit-i ? postpoint : prepoint; + float r = fabs(mdct[j])/floor[j]; + if(rvi; + float **sort = alloca(n*sizeof(*sort)); + int j,count=0; + int start = (vi->normal_p ? vi->normal_start-i : n); + if(start>n)start=n; + + /* force classic behavior where only energy in the current band is considered */ + acc=0.f; + + /* still responsible for populating *out where noise norm not in + effect. There's no need to [re]populate *q in these areas */ + for(j=0;j pointlimit */ + if(ve<.25f && (!flags || j>=limit-i)){ + acc += ve; + sort[count++]=q+j; /* q is fabs(r) for unflagged element */ + }else{ + /* For now: no acc adjustment for nonzero quantization. populate *out and q as this value is final. */ + if(r[j]<0) + out[j] = -rint(sqrt(ve)); + else + out[j] = rint(sqrt(ve)); + q[j] = out[j]*out[j]*f[j]; + } + }/* else{ + again, no energy adjustment for error in nonzero quant-- for now + }*/ + } + + if(count){ + /* noise norm to do */ + qsort(sort,count,sizeof(*sort),apsort); + for(j=0;j=vi->normal_thresh){ + out[k]=unitnorm(r[k]); + acc-=1.f; + q[k]=f[k]; + }else{ + out[k]=0; + q[k]=0.f; + } + } + } + + return acc; +} + +/* Noise normalization, quantization and coupling are not wholly + seperable processes in depth>1 coupling. */ +void _vp_couple_quantize_normalize(int blobno, + vorbis_info_psy_global *g, + vorbis_look_psy *p, + vorbis_info_mapping0 *vi, + float **mdct, + int **iwork, + int *nonzero, + int sliding_lowpass, + int ch){ + + int i; + int n = p->n; + int partition=(p->vi->normal_p ? p->vi->normal_partition : 16); + int limit = g->coupling_pointlimit[p->vi->blockflag][blobno]; + float prepoint=stereo_threshholds[g->coupling_prepointamp[blobno]]; + float postpoint=stereo_threshholds[g->coupling_postpointamp[blobno]]; +#if 0 + float de=0.1*p->m_val; /* a blend of the AoTuV M2 and M3 code here and below */ +#endif + + /* mdct is our raw mdct output, floor not removed. */ + /* inout passes in the ifloor, passes back quantized result */ + + /* unquantized energy (negative indicates amplitude has negative sign) */ + float **raw = alloca(ch*sizeof(*raw)); + + /* dual pupose; quantized energy (if flag set), othersize fabs(raw) */ + float **quant = alloca(ch*sizeof(*quant)); + + /* floor energy */ + float **floor = alloca(ch*sizeof(*floor)); + + /* flags indicating raw/quantized status of elements in raw vector */ + int **flag = alloca(ch*sizeof(*flag)); + + /* non-zero flag working vector */ + int *nz = alloca(ch*sizeof(*nz)); + + /* energy surplus/defecit tracking */ + float *acc = alloca((ch+vi->coupling_steps)*sizeof(*acc)); + + /* The threshold of a stereo is changed with the size of n */ + if(n > 1000) + postpoint=stereo_threshholds_limited[g->coupling_postpointamp[blobno]]; + + raw[0] = alloca(ch*partition*sizeof(**raw)); + quant[0] = alloca(ch*partition*sizeof(**quant)); + floor[0] = alloca(ch*partition*sizeof(**floor)); + flag[0] = alloca(ch*partition*sizeof(**flag)); + + for(i=1;icoupling_steps;i++) + acc[i]=0.f; + + for(i=0;i n-i ? n-i : partition; + int step,track = 0; + + memcpy(nz,nonzero,sizeof(*nz)*ch); + + /* prefill */ + memset(flag[0],0,ch*partition*sizeof(**flag)); + for(k=0;kcoupling_steps;step++){ + int Mi = vi->coupling_mag[step]; + int Ai = vi->coupling_ang[step]; + int *iM = &iwork[Mi][i]; + int *iA = &iwork[Ai][i]; + float *reM = raw[Mi]; + float *reA = raw[Ai]; + float *qeM = quant[Mi]; + float *qeA = quant[Ai]; + float *floorM = floor[Mi]; + float *floorA = floor[Ai]; + int *fM = flag[Mi]; + int *fA = flag[Ai]; + + if(nz[Mi] || nz[Ai]){ + nz[Mi] = nz[Ai] = 1; + + for(j=0;jabs(B)){ + iA[j]=(A>0?A-B:B-A); + }else{ + iA[j]=(B>0?A-B:B-A); + iM[j]=B; + } + + /* collapse two equivalent tuples to one */ + if(iA[j]>=abs(iM[j])*2){ + iA[j]= -iA[j]; + iM[j]= -iM[j]; + } + + } + + }else{ + /* lossy (point) coupling */ + if(jcoupling_steps;i++){ + /* make sure coupling a zero and a nonzero channel results in two + nonzero channels. */ + if(nonzero[vi->coupling_mag[i]] || + nonzero[vi->coupling_ang[i]]){ + nonzero[vi->coupling_mag[i]]=1; + nonzero[vi->coupling_ang[i]]=1; + } + } +} diff --git a/vendor/vorbis/lib/psy.h b/vendor/vorbis/lib/psy.h new file mode 100644 index 0000000..d9a04e8 --- /dev/null +++ b/vendor/vorbis/lib/psy.h @@ -0,0 +1,153 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: random psychoacoustics (not including preecho) + + ********************************************************************/ + +#ifndef _V_PSY_H_ +#define _V_PSY_H_ +#include "smallft.h" + +#include "backends.h" +#include "envelope.h" + +#ifndef EHMER_MAX +#define EHMER_MAX 56 +#endif + +/* psychoacoustic setup ********************************************/ +#define P_BANDS 17 /* 62Hz to 16kHz */ +#define P_LEVELS 8 /* 30dB to 100dB */ +#define P_LEVEL_0 30. /* 30 dB */ +#define P_NOISECURVES 3 + +#define NOISE_COMPAND_LEVELS 40 +typedef struct vorbis_info_psy{ + int blockflag; + + float ath_adjatt; + float ath_maxatt; + + float tone_masteratt[P_NOISECURVES]; + float tone_centerboost; + float tone_decay; + float tone_abs_limit; + float toneatt[P_BANDS]; + + int noisemaskp; + float noisemaxsupp; + float noisewindowlo; + float noisewindowhi; + int noisewindowlomin; + int noisewindowhimin; + int noisewindowfixed; + float noiseoff[P_NOISECURVES][P_BANDS]; + float noisecompand[NOISE_COMPAND_LEVELS]; + + float max_curve_dB; + + int normal_p; + int normal_start; + int normal_partition; + double normal_thresh; +} vorbis_info_psy; + +typedef struct{ + int eighth_octave_lines; + + /* for block long/short tuning; encode only */ + float preecho_thresh[VE_BANDS]; + float postecho_thresh[VE_BANDS]; + float stretch_penalty; + float preecho_minenergy; + + float ampmax_att_per_sec; + + /* channel coupling config */ + int coupling_pkHz[PACKETBLOBS]; + int coupling_pointlimit[2][PACKETBLOBS]; + int coupling_prepointamp[PACKETBLOBS]; + int coupling_postpointamp[PACKETBLOBS]; + int sliding_lowpass[2][PACKETBLOBS]; + +} vorbis_info_psy_global; + +typedef struct { + float ampmax; + int channels; + + vorbis_info_psy_global *gi; + int coupling_pointlimit[2][P_NOISECURVES]; +} vorbis_look_psy_global; + + +typedef struct { + int n; + struct vorbis_info_psy *vi; + + float ***tonecurves; + float **noiseoffset; + + float *ath; + long *octave; /* in n.ocshift format */ + long *bark; + + long firstoc; + long shiftoc; + int eighth_octave_lines; /* power of two, please */ + int total_octave_lines; + long rate; /* cache it */ + + float m_val; /* Masking compensation value */ + +} vorbis_look_psy; + +extern void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi, + vorbis_info_psy_global *gi,int n,long rate); +extern void _vp_psy_clear(vorbis_look_psy *p); +extern void *_vi_psy_dup(void *source); + +extern void _vi_psy_free(vorbis_info_psy *i); +extern vorbis_info_psy *_vi_psy_copy(vorbis_info_psy *i); + +extern void _vp_noisemask(vorbis_look_psy *p, + float *logmdct, + float *logmask); + +extern void _vp_tonemask(vorbis_look_psy *p, + float *logfft, + float *logmask, + float global_specmax, + float local_specmax); + +extern void _vp_offset_and_mix(vorbis_look_psy *p, + float *noise, + float *tone, + int offset_select, + float *logmask, + float *mdct, + float *logmdct); + +extern float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd); + +extern void _vp_couple_quantize_normalize(int blobno, + vorbis_info_psy_global *g, + vorbis_look_psy *p, + vorbis_info_mapping0 *vi, + float **mdct, + int **iwork, + int *nonzero, + int sliding_lowpass, + int ch); + +#endif diff --git a/vendor/vorbis/lib/psytune.c b/vendor/vorbis/lib/psytune.c new file mode 100644 index 0000000..67223e5 --- /dev/null +++ b/vendor/vorbis/lib/psytune.c @@ -0,0 +1,523 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: simple utility that runs audio through the psychoacoustics + without encoding + + ********************************************************************/ + +/* NB: this is dead code, retained purely for doc and reference value + don't try to compile it */ + +#include +#include +#include +#include + +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "os.h" +#include "misc.h" +#include "psy.h" +#include "mdct.h" +#include "smallft.h" +#include "window.h" +#include "scales.h" +#include "lpc.h" +#include "lsp.h" +#include "masking.h" +#include "registry.h" + +static vorbis_info_psy_global _psy_set0G={ + 0, /* decaydBpms */ + 8, /* lines per eighth octave */ + + /* thresh sample period, preecho clamp trigger threshhold, range, minenergy */ + 256, {26.f,26.f,26.f,30.f}, {-90.f,-90.f,-90.f,-90.f}, -90.f, + -6.f, + + 0, + + 0., + 0., +}; + +static vp_part _vp_part0[]={ + { 1,9e10f, 9e10f, 1.f,9999.f}, + { 9999, .75f, 9e10f, .5f,9999.f}, +/*{ 9999, 1.5f, 9e10f, .5f,9999.f},*/ + { 18,9e10f, 9e10f, .5f, 30.f}, + { 9999,9e10f, 9e10f, .5f, 30.f} +}; + +static vp_couple _vp_couple0[]={ + { 1, {9e10f,9e10f,0}, { 0.f, 0.f,0}, { 0.f, 0.f,0}, {0.f,0.f,0}}, + { 18, {9e10f,9e10f,0}, { 0.f, 0.f,0}, { 0.f, 0.f,0}, {0.f,0.f,0}}, + { 9999, {9e10f,9e10f,0}, { 0.f, 9e10f,0}, { 0.f,22.f,1}, {0.f,0.f,0}} +}; + +static vorbis_info_psy _psy_set0={ + ATH_Bark_dB_lineaggressive, + + -100.f, + -140.f, + 6.f, /* floor master att */ + + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */ + /* x: 63 88 125 175 250 350 500 700 1k 1.4k 2k 2.8k 4k 5.6k 8k 11.5k 16k Hz */ + /* y: 0 10 20 30 40 50 60 70 80 90 100 dB */ + 1, /* tonemaskp */ + 0.f, /* tone master att */ + /* 0 10 20 30 40 50 60 70 80 90 100 */ + { + {-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f}, /*63*/ + {-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f}, /*88*/ + {-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f}, /*125*/ + + {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*175*/ + {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*250*/ + {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*350*/ + {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*500*/ + {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*700*/ + {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*1000*/ + {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*1400*/ + {-40.f,-40.f,-40.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*2000*/ + {-40.f,-40.f,-40.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*2800*/ + {-40.f,-40.f,-40.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*4000*/ + + {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*5600*/ + + {-30.f,-30.f,-33.f,-35.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*8000*/ + {-30.f,-30.f,-33.f,-35.f,-40.f,-45.f,-50.f,-60.f,-70.f,-85.f,-100.f}, /*11500*/ + {-24.f,-24.f,-26.f,-32.f,-32.f,-42.f,-50.f,-60.f,-70.f,-85.f,-100.f}, /*16000*/ + + }, + + 1,/* peakattp */ + {{-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*63*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*88*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*125*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*175*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*250*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*350*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*500*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*700*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*1000*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*1400*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*2000*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*2800*/ + {-14.f,-20.f,-20.f,-20.f,-26.f,-32.f,-40.f,-40.f,-40.f,-40.f,-40.f},/*4000*/ + {-10.f,-12.f,-14.f,-16.f,-16.f,-20.f,-24.f,-30.f,-32.f,-40.f,-40.f},/*5600*/ + {-10.f,-12.f,-14.f,-16.f,-16.f,-20.f,-24.f,-30.f,-32.f,-40.f,-40.f},/*8000*/ + {-10.f,-10.f,-10.f,-12.f,-14.f,-18.f,-22.f,-28.f,-32.f,-40.f,-40.f},/*11500*/ + {-10.f,-10.f,-10.f,-12.f,-14.f,-18.f,-22.f,-28.f,-32.f,-40.f,-40.f},/*16000*/ + }, + + 1,/*noisemaskp */ + -10.f, /* suppress any noise curve over maxspec+n */ + .5f, /* low window */ + .5f, /* high window */ + 10, + 10, + 25, + {.000f, 0.f, /*63*/ + .000f, 0.f, /*88*/ + .000f, 0.f, /*125*/ + .000f, 0.f, /*175*/ + .000f, 0.f, /*250*/ + .000f, 0.f, /*350*/ + .000f, 0.f, /*500*/ + .000f, 0.f, /*700*/ + .000f, 0.f, /*1000*/ + .300f, 0.f, /*1400*/ + .300f, 0.f, /*2000*/ + .300f, 0.f, /*2800*/ + .500f, 0.f, /*4000*/ + .700f, 0.f, /*5600*/ + .850f, 0.f, /*8000*/ + .900f, 0.f, /*11500*/ + .900f, 1.f, /*16000*/ + }, + + 95.f, /* even decade + 5 is important; saves an rint() later in a + tight loop) */ + -44., + + 32, + _vp_part0,_vp_couple0 +}; + +static vorbis_info_floor1 _floor_set0={1, + {0}, + + {32}, + {0}, + {0}, + {{-1}}, + + 2, + {0,1024, + + 88,31,243, + + 14,54,143,460, + + 6,3,10, 22,18,26, 41,36,47, + 69,61,78, 112,99,126, 185,162,211, + 329,282,387, 672,553,825 + }, + + 60,30,400, + 20,8,1,18., + 20,600, + 960}; + + +static vorbis_info_mapping0 mapping_info={1,{0,1},{0},{0},{0},0, 1, {0},{1}}; +static codec_setup_info codec_setup0={ {0,0}, + 1,1,1,1,1,0,1, + {NULL}, + {0},{&mapping_info}, + {0},{NULL}, + {1},{&_floor_set0}, + {2},{NULL}, + {NULL}, + {&_psy_set0}, + &_psy_set0G}; + +static int noisy=0; +void analysis(char *base,int i,float *v,int n,int bark,int dB){ + if(noisy){ + int j; + FILE *of; + char buffer[80]; + sprintf(buffer,"%s_%d.m",base,i); + of=fopen(buffer,"w"); + + for(j=0;jlook(NULL,NULL,&_floor_set0); + + /* we cheat on the WAV header; we just bypass 44 bytes and never + verify that it matches 16bit/stereo/44.1kHz. */ + + fread(buffer,1,44,stdin); + fwrite(buffer,1,44,stdout); + memset(buffer,0,framesize*2); + + analysis("window",0,window,framesize,0,0); + + fprintf(stderr,"Processing for frame size %d...\n",framesize); + + while(!eos){ + long bytes=fread(buffer2,1,framesize*2,stdin); + if(bytes>1]=todB(&temp); + if(temp>local_ampmax[i])local_ampmax[i]=temp; + } + if(local_ampmax[i]>ampmax)ampmax=local_ampmax[i]; + + mdct_forward(&m_look,pcm[i],mdct); + for(j=0;jforward(&vb,floor_look, + mdct, + logmdct, + mask, + logmax, + + flr[i]); + } + + _vp_remove_floor(&p_look, + pg_look, + logmdct, + mdct, + flr[i], + pcm[i], + local_ampmax[i]); + + for(j=0;j1500) + fprintf(stderr,"%ld ",frameno+i); + + analysis("res",frameno+i,pcm[i],framesize/2,1,0); + analysis("codedflr",frameno+i,flr[i],framesize/2,1,1); + } + + /* residue prequantization */ + _vp_partition_prequant(&p_look, + &vi, + pcm, + nonzero); + + for(i=0;i<2;i++) + analysis("quant",frameno+i,pcm[i],framesize/2,1,0); + + /* channel coupling / stereo quantization */ + + _vp_couple(&p_look, + &mapping_info, + pcm, + nonzero); + + for(i=0;i<2;i++) + analysis("coupled",frameno+i,pcm[i],framesize/2,1,0); + + /* decoupling */ + for(i=mapping_info.coupling_steps-1;i>=0;i--){ + float *pcmM=pcm[mapping_info.coupling_mag[i]]; + float *pcmA=pcm[mapping_info.coupling_ang[i]]; + + for(j=0;j0) + if(ang>0){ + pcmM[j]=mag; + pcmA[j]=mag-ang; + }else{ + pcmA[j]=mag; + pcmM[j]=mag+ang; + } + else + if(ang>0){ + pcmM[j]=mag; + pcmA[j]=mag+ang; + }else{ + pcmA[j]=mag; + pcmM[j]=mag-ang; + } + } + } + + for(i=0;i<2;i++) + analysis("decoupled",frameno+i,pcm[i],framesize/2,1,0); + + for(i=0;i<2;i++){ + float amp; + + for(j=0;j32767){ + if(!flag)fprintf(stderr,"clipping in frame %ld ",frameno+i); + flag=1; + val=32767; + } + if(val<-32768){ + if(!flag)fprintf(stderr,"clipping in frame %ld ",frameno+i); + flag=1; + val=-32768; + } + ptr[0]=val&0xff; + ptr[1]=(val>>8)&0xff; + ptr+=4; + } + } + + fprintf(stderr,"*"); + fwrite(buffer,1,framesize*2,stdout); + memmove(buffer,buffer2,framesize*2); + + for(i=0;i<2;i++){ + for(j=0,k=framesize/2;j +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "registry.h" +#include "codebook.h" +#include "misc.h" +#include "os.h" + +#if defined(TRAIN_RES) || defined (TRAIN_RESAUX) +#include +#endif + +typedef struct { + vorbis_info_residue0 *info; + + int parts; + int stages; + codebook *fullbooks; + codebook *phrasebook; + codebook ***partbooks; + + int partvals; + int **decodemap; + + long postbits; + long phrasebits; + long frames; + +#if defined(TRAIN_RES) || defined(TRAIN_RESAUX) + int train_seq; + long *training_data[8][64]; + float training_max[8][64]; + float training_min[8][64]; + float tmin; + float tmax; + int submap; +#endif + +} vorbis_look_residue0; + +void res0_free_info(vorbis_info_residue *i){ + vorbis_info_residue0 *info=(vorbis_info_residue0 *)i; + if(info){ + memset(info,0,sizeof(*info)); + _ogg_free(info); + } +} + +void res0_free_look(vorbis_look_residue *i){ + int j; + if(i){ + + vorbis_look_residue0 *look=(vorbis_look_residue0 *)i; + +#ifdef TRAIN_RES + { + int j,k,l; + for(j=0;jparts;j++){ + /*fprintf(stderr,"partition %d: ",j);*/ + for(k=0;k<8;k++) + if(look->training_data[k][j]){ + char buffer[80]; + FILE *of; + codebook *statebook=look->partbooks[j][k]; + + /* long and short into the same bucket by current convention */ + sprintf(buffer,"res_sub%d_part%d_pass%d.vqd",look->submap,j,k); + of=fopen(buffer,"a"); + + for(l=0;lentries;l++) + fprintf(of,"%d:%ld\n",l,look->training_data[k][j][l]); + + fclose(of); + + /*fprintf(stderr,"%d(%.2f|%.2f) ",k, + look->training_min[k][j],look->training_max[k][j]);*/ + + _ogg_free(look->training_data[k][j]); + look->training_data[k][j]=NULL; + } + /*fprintf(stderr,"\n");*/ + } + } + fprintf(stderr,"min/max residue: %g::%g\n",look->tmin,look->tmax); + + /*fprintf(stderr,"residue bit usage %f:%f (%f total)\n", + (float)look->phrasebits/look->frames, + (float)look->postbits/look->frames, + (float)(look->postbits+look->phrasebits)/look->frames);*/ +#endif + + + /*vorbis_info_residue0 *info=look->info; + + fprintf(stderr, + "%ld frames encoded in %ld phrasebits and %ld residue bits " + "(%g/frame) \n",look->frames,look->phrasebits, + look->resbitsflat, + (look->phrasebits+look->resbitsflat)/(float)look->frames); + + for(j=0;jparts;j++){ + long acc=0; + fprintf(stderr,"\t[%d] == ",j); + for(k=0;kstages;k++) + if((info->secondstages[j]>>k)&1){ + fprintf(stderr,"%ld,",look->resbits[j][k]); + acc+=look->resbits[j][k]; + } + + fprintf(stderr,":: (%ld vals) %1.2fbits/sample\n",look->resvals[j], + acc?(float)acc/(look->resvals[j]*info->grouping):0); + } + fprintf(stderr,"\n");*/ + + for(j=0;jparts;j++) + if(look->partbooks[j])_ogg_free(look->partbooks[j]); + _ogg_free(look->partbooks); + for(j=0;jpartvals;j++) + _ogg_free(look->decodemap[j]); + _ogg_free(look->decodemap); + + memset(look,0,sizeof(*look)); + _ogg_free(look); + } +} + +static int icount(unsigned int v){ + int ret=0; + while(v){ + ret+=v&1; + v>>=1; + } + return(ret); +} + + +void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){ + vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr; + int j,acc=0; + oggpack_write(opb,info->begin,24); + oggpack_write(opb,info->end,24); + + oggpack_write(opb,info->grouping-1,24); /* residue vectors to group and + code with a partitioned book */ + oggpack_write(opb,info->partitions-1,6); /* possible partition choices */ + oggpack_write(opb,info->groupbook,8); /* group huffman book */ + + /* secondstages is a bitmask; as encoding progresses pass by pass, a + bitmask of one indicates this partition class has bits to write + this pass */ + for(j=0;jpartitions;j++){ + if(ov_ilog(info->secondstages[j])>3){ + /* yes, this is a minor hack due to not thinking ahead */ + oggpack_write(opb,info->secondstages[j],3); + oggpack_write(opb,1,1); + oggpack_write(opb,info->secondstages[j]>>3,5); + }else + oggpack_write(opb,info->secondstages[j],4); /* trailing zero */ + acc+=icount(info->secondstages[j]); + } + for(j=0;jbooklist[j],8); + +} + +/* vorbis_info is for range checking */ +vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){ + int j,acc=0; + vorbis_info_residue0 *info=_ogg_calloc(1,sizeof(*info)); + codec_setup_info *ci=vi->codec_setup; + + info->begin=oggpack_read(opb,24); + info->end=oggpack_read(opb,24); + info->grouping=oggpack_read(opb,24)+1; + info->partitions=oggpack_read(opb,6)+1; + info->groupbook=oggpack_read(opb,8); + + /* check for premature EOP */ + if(info->groupbook<0)goto errout; + + for(j=0;jpartitions;j++){ + int cascade=oggpack_read(opb,3); + int cflag=oggpack_read(opb,1); + if(cflag<0) goto errout; + if(cflag){ + int c=oggpack_read(opb,5); + if(c<0) goto errout; + cascade|=(c<<3); + } + info->secondstages[j]=cascade; + + acc+=icount(cascade); + } + for(j=0;jbooklist[j]=book; + } + + if(info->groupbook>=ci->books)goto errout; + for(j=0;jbooklist[j]>=ci->books)goto errout; + if(ci->book_param[info->booklist[j]]->maptype==0)goto errout; + } + + /* verify the phrasebook is not specifying an impossible or + inconsistent partitioning scheme. */ + /* modify the phrasebook ranging check from r16327; an early beta + encoder had a bug where it used an oversized phrasebook by + accident. These files should continue to be playable, but don't + allow an exploit */ + { + int entries = ci->book_param[info->groupbook]->entries; + int dim = ci->book_param[info->groupbook]->dim; + int partvals = 1; + if (dim<1) goto errout; + while(dim>0){ + partvals *= info->partitions; + if(partvals > entries) goto errout; + dim--; + } + info->partvals = partvals; + } + + return(info); + errout: + res0_free_info(info); + return(NULL); +} + +vorbis_look_residue *res0_look(vorbis_dsp_state *vd, + vorbis_info_residue *vr){ + vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr; + vorbis_look_residue0 *look=_ogg_calloc(1,sizeof(*look)); + codec_setup_info *ci=vd->vi->codec_setup; + + int j,k,acc=0; + int dim; + int maxstage=0; + look->info=info; + + look->parts=info->partitions; + look->fullbooks=ci->fullbooks; + look->phrasebook=ci->fullbooks+info->groupbook; + dim=look->phrasebook->dim; + + look->partbooks=_ogg_calloc(look->parts,sizeof(*look->partbooks)); + + for(j=0;jparts;j++){ + int stages=ov_ilog(info->secondstages[j]); + if(stages){ + if(stages>maxstage)maxstage=stages; + look->partbooks[j]=_ogg_calloc(stages,sizeof(*look->partbooks[j])); + for(k=0;ksecondstages[j]&(1<partbooks[j][k]=ci->fullbooks+info->booklist[acc++]; +#ifdef TRAIN_RES + look->training_data[k][j]=_ogg_calloc(look->partbooks[j][k]->entries, + sizeof(***look->training_data)); +#endif + } + } + } + + look->partvals=1; + for(j=0;jpartvals*=look->parts; + + look->stages=maxstage; + look->decodemap=_ogg_malloc(look->partvals*sizeof(*look->decodemap)); + for(j=0;jpartvals;j++){ + long val=j; + long mult=look->partvals/look->parts; + look->decodemap[j]=_ogg_malloc(dim*sizeof(*look->decodemap[j])); + for(k=0;kparts; + look->decodemap[j][k]=deco; + } + } +#if defined(TRAIN_RES) || defined (TRAIN_RESAUX) + { + static int train_seq=0; + look->train_seq=train_seq++; + } +#endif + return(look); +} + +/* break an abstraction and copy some code for performance purposes */ +static int local_book_besterror(codebook *book,int *a){ + int dim=book->dim; + int i,j,o; + int minval=book->minval; + int del=book->delta; + int qv=book->quantvals; + int ze=(qv>>1); + int index=0; + /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ + int p[8]={0,0,0,0,0,0,0,0}; + + if(del!=1){ + for(i=0,o=dim;i>1))/del; + int m = (v=qv?qv-1:m)); + p[o]=v*del+minval; + } + }else{ + for(i=0,o=dim;i=qv?qv-1:m)); + p[o]=v*del+minval; + } + } + + if(book->c->lengthlist[index]<=0){ + const static_codebook *c=book->c; + int best=-1; + /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ + int e[8]={0,0,0,0,0,0,0,0}; + int maxval = book->minval + book->delta*(book->quantvals-1); + for(i=0;ientries;i++){ + if(c->lengthlist[i]>0){ + int this=0; + for(j=0;j=maxval) + e[j++]=0; + if(e[j]>=0) + e[j]+=book->delta; + e[j]= -e[j]; + } + } + + if(index>-1){ + for(i=0;idim; + int step=n/dim; + + for(i=0;i=0) + acc[entry]++; +#endif + + bits+=vorbis_book_encode(book,entry,opb); + + } + + return(bits); +} + +static long **_01class(vorbis_block *vb,vorbis_look_residue *vl, + int **in,int ch){ + long i,j,k; + vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; + vorbis_info_residue0 *info=look->info; + + /* move all this setup out later */ + int samples_per_partition=info->grouping; + int possible_partitions=info->partitions; + int n=info->end-info->begin; + + int partvals=n/samples_per_partition; + long **partword=_vorbis_block_alloc(vb,ch*sizeof(*partword)); + float scale=100./samples_per_partition; + + /* we find the partition type for each partition of each + channel. We'll go back and do the interleaved encoding in a + bit. For now, clarity */ + + for(i=0;ibegin; + for(j=0;jmax)max=abs(in[j][offset+k]); + ent+=abs(in[j][offset+k]); + } + ent*=scale; + + for(k=0;kclassmetric1[k] && + (info->classmetric2[k]<0 || entclassmetric2[k])) + break; + + partword[j][i]=k; + } + } + +#ifdef TRAIN_RESAUX + { + FILE *of; + char buffer[80]; + + for(i=0;itrain_seq); + of=fopen(buffer,"a"); + for(j=0;jframes++; + + return(partword); +} + +/* designed for stereo or other modes where the partition size is an + integer multiple of the number of channels encoded in the current + submap */ +static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,int **in, + int ch){ + long i,j,k,l; + vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; + vorbis_info_residue0 *info=look->info; + + /* move all this setup out later */ + int samples_per_partition=info->grouping; + int possible_partitions=info->partitions; + int n=info->end-info->begin; + + int partvals=n/samples_per_partition; + long **partword=_vorbis_block_alloc(vb,sizeof(*partword)); + +#if defined(TRAIN_RES) || defined (TRAIN_RESAUX) + FILE *of; + char buffer[80]; +#endif + + partword[0]=_vorbis_block_alloc(vb,partvals*sizeof(*partword[0])); + memset(partword[0],0,partvals*sizeof(*partword[0])); + + for(i=0,l=info->begin/ch;imagmax)magmax=abs(in[0][l]); + for(k=1;kangmax)angmax=abs(in[k][l]); + l++; + } + + for(j=0;jclassmetric1[j] && + angmax<=info->classmetric2[j]) + break; + + partword[0][i]=j; + + } + +#ifdef TRAIN_RESAUX + sprintf(buffer,"resaux_%d.vqd",look->train_seq); + of=fopen(buffer,"a"); + for(i=0;iframes++; + + return(partword); +} + +static int _01forward(oggpack_buffer *opb, + vorbis_look_residue *vl, + int **in,int ch, + long **partword, +#ifdef TRAIN_RES + int (*encode)(oggpack_buffer *,int *,int, + codebook *,long *), + int submap +#else + int (*encode)(oggpack_buffer *,int *,int, + codebook *) +#endif +){ + long i,j,k,s; + vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; + vorbis_info_residue0 *info=look->info; + +#ifdef TRAIN_RES + look->submap=submap; +#endif + + /* move all this setup out later */ + int samples_per_partition=info->grouping; + int possible_partitions=info->partitions; + int partitions_per_word=look->phrasebook->dim; + int n=info->end-info->begin; + + int partvals=n/samples_per_partition; + long resbits[128]; + long resvals[128]; + +#ifdef TRAIN_RES + for(i=0;ibegin;jend;j++){ + if(in[i][j]>look->tmax)look->tmax=in[i][j]; + if(in[i][j]tmin)look->tmin=in[i][j]; + } +#endif + + memset(resbits,0,sizeof(resbits)); + memset(resvals,0,sizeof(resvals)); + + /* we code the partition words for each channel, then the residual + words for a partition per channel until we've written all the + residual words for that partition word. Then write the next + partition channel words... */ + + for(s=0;sstages;s++){ + + for(i=0;iphrasebook->entries) + look->phrasebits+=vorbis_book_encode(look->phrasebook,val,opb); +#if 0 /*def TRAIN_RES*/ + else + fprintf(stderr,"!"); +#endif + + } + } + + /* now we encode interleaved residual values for the partitions */ + for(k=0;kbegin; + + for(j=0;jsecondstages[partword[j][i]]&(1<partbooks[partword[j][i]][s]; + if(statebook){ + int ret; +#ifdef TRAIN_RES + long *accumulator=NULL; + accumulator=look->training_data[s][partword[j][i]]; + { + int l; + int *samples=in[j]+offset; + for(l=0;ltraining_min[s][partword[j][i]]) + look->training_min[s][partword[j][i]]=samples[l]; + if(samples[l]>look->training_max[s][partword[j][i]]) + look->training_max[s][partword[j][i]]=samples[l]; + } + } + ret=encode(opb,in[j]+offset,samples_per_partition, + statebook,accumulator); +#else + ret=encode(opb,in[j]+offset,samples_per_partition, + statebook); +#endif + + look->postbits+=ret; + resbits[partword[j][i]]+=ret; + } + } + } + } + } + } + + return(0); +} + +/* a truncated packet here just means 'stop working'; it's not an error */ +static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl, + float **in,int ch, + long (*decodepart)(codebook *, float *, + oggpack_buffer *,int)){ + + long i,j,k,l,s; + vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; + vorbis_info_residue0 *info=look->info; + + /* move all this setup out later */ + int samples_per_partition=info->grouping; + int partitions_per_word=look->phrasebook->dim; + int max=vb->pcmend>>1; + int end=(info->endend:max); + int n=end-info->begin; + + if(n>0){ + int partvals=n/samples_per_partition; + int partwords=(partvals+partitions_per_word-1)/partitions_per_word; + int ***partword=alloca(ch*sizeof(*partword)); + + for(j=0;jstages;s++){ + + /* each loop decodes on partition codeword containing + partitions_per_word partitions */ + for(i=0,l=0;iphrasebook,&vb->opb); + + if(temp==-1 || temp>=info->partvals)goto eopbreak; + partword[j][l]=look->decodemap[temp]; + if(partword[j][l]==NULL)goto errout; + } + } + + /* now we decode residual values for the partitions */ + for(k=0;kbegin+i*samples_per_partition; + if(info->secondstages[partword[j][l][k]]&(1<partbooks[partword[j][l][k]][s]; + if(stagebook){ + if(decodepart(stagebook,in[j]+offset,&vb->opb, + samples_per_partition)==-1)goto eopbreak; + } + } + } + } + } + } + errout: + eopbreak: + return(0); +} + +int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl, + float **in,int *nonzero,int ch){ + int i,used=0; + for(i=0;ipcmend/2,used=0; + + /* don't duplicate the code; use a working vector hack for now and + reshape ourselves into a single channel res1 */ + /* ugly; reallocs for each coupling pass :-( */ + int *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work)); + for(i=0;iinfo; + + /* move all this setup out later */ + int samples_per_partition=info->grouping; + int partitions_per_word=look->phrasebook->dim; + int max=(vb->pcmend*ch)>>1; + int end=(info->endend:max); + int n=end-info->begin; + + if(n>0){ + int partvals=n/samples_per_partition; + int partwords=(partvals+partitions_per_word-1)/partitions_per_word; + int **partword=_vorbis_block_alloc(vb,partwords*sizeof(*partword)); + + for(i=0;istages;s++){ + for(i=0,l=0;iphrasebook,&vb->opb); + if(temp==-1 || temp>=info->partvals)goto eopbreak; + partword[l]=look->decodemap[temp]; + if(partword[l]==NULL)goto errout; + } + + /* now we decode residual values for the partitions */ + for(k=0;ksecondstages[partword[l][k]]&(1<partbooks[partword[l][k]][s]; + + if(stagebook){ + if(vorbis_book_decodevv_add(stagebook,in, + i*samples_per_partition+info->begin,ch, + &vb->opb,samples_per_partition)==-1) + goto eopbreak; + } + } + } + } + } + errout: + eopbreak: + return(0); +} + + +const vorbis_func_residue residue0_exportbundle={ + NULL, + &res0_unpack, + &res0_look, + &res0_free_info, + &res0_free_look, + NULL, + NULL, + &res0_inverse +}; + +const vorbis_func_residue residue1_exportbundle={ + &res0_pack, + &res0_unpack, + &res0_look, + &res0_free_info, + &res0_free_look, + &res1_class, + &res1_forward, + &res1_inverse +}; + +const vorbis_func_residue residue2_exportbundle={ + &res0_pack, + &res0_unpack, + &res0_look, + &res0_free_info, + &res0_free_look, + &res2_class, + &res2_forward, + &res2_inverse +}; diff --git a/vendor/vorbis/lib/scales.h b/vendor/vorbis/lib/scales.h new file mode 100644 index 0000000..3c2ae48 --- /dev/null +++ b/vendor/vorbis/lib/scales.h @@ -0,0 +1,89 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: linear scale -> dB, Bark and Mel scales + + ********************************************************************/ + +#ifndef _V_SCALES_H_ +#define _V_SCALES_H_ + +#include +#include "os.h" + +#ifdef _MSC_VER +/* MS Visual Studio doesn't have C99 inline keyword. */ +#define inline __inline +#endif + +/* 20log10(x) */ +#define VORBIS_IEEE_FLOAT32 1 +#ifdef VORBIS_IEEE_FLOAT32 + +static inline float unitnorm(float x){ + union { + ogg_uint32_t i; + float f; + } ix; + ix.f = x; + ix.i = (ix.i & 0x80000000U) | (0x3f800000U); + return ix.f; +} + +/* Segher was off (too high) by ~ .3 decibel. Center the conversion correctly. */ +static inline float todB(const float *x){ + union { + ogg_uint32_t i; + float f; + } ix; + ix.f = *x; + ix.i = ix.i&0x7fffffff; + return (float)(ix.i * 7.17711438e-7f -764.6161886f); +} + +#define todB_nn(x) todB(x) + +#else + +static float unitnorm(float x){ + if(x<0)return(-1.f); + return(1.f); +} + +#define todB(x) (*(x)==0?-400.f:log(*(x)**(x))*4.34294480f) +#define todB_nn(x) (*(x)==0.f?-400.f:log(*(x))*8.6858896f) + +#endif + +#define fromdB(x) (exp((x)*.11512925f)) + +/* The bark scale equations are approximations, since the original + table was somewhat hand rolled. The below are chosen to have the + best possible fit to the rolled tables, thus their somewhat odd + appearance (these are more accurate and over a longer range than + the oft-quoted bark equations found in the texts I have). The + approximations are valid from 0 - 30kHz (nyquist) or so. + + all f in Hz, z in Bark */ + +#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) +#define fromBARK(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f) +#define toMEL(n) (log(1.f+(n)*.001f)*1442.695f) +#define fromMEL(m) (1000.f*exp((m)/1442.695f)-1000.f) + +/* Frequency to octave. We arbitrarily declare 63.5 Hz to be octave + 0.0 */ + +#define toOC(n) (log(n)*1.442695f-5.965784f) +#define fromOC(o) (exp(((o)+5.965784f)*.693147f)) + +#endif diff --git a/vendor/vorbis/lib/sharedbook.c b/vendor/vorbis/lib/sharedbook.c new file mode 100644 index 0000000..62a9a00 --- /dev/null +++ b/vendor/vorbis/lib/sharedbook.c @@ -0,0 +1,604 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: basic shared codebook operations + + ********************************************************************/ + +#include +#include +#include +#include +#include +#include "os.h" +#include "misc.h" +#include "vorbis/codec.h" +#include "codebook.h" +#include "scales.h" + +/**** pack/unpack helpers ******************************************/ + +int ov_ilog(ogg_uint32_t v){ + int ret; + for(ret=0;v;ret++)v>>=1; + return ret; +} + +/* 32 bit float (not IEEE; nonnormalized mantissa + + biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm + Why not IEEE? It's just not that important here. */ + +#define VQ_FEXP 10 +#define VQ_FMAN 21 +#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */ + +/* doesn't currently guard under/overflow */ +long _float32_pack(float val){ + int sign=0; + long exp; + long mant; + if(val<0){ + sign=0x80000000; + val= -val; + } + exp= floor(log(val)/log(2.f)+.001); /* +epsilon */ + mant=rint(ldexp(val,(VQ_FMAN-1)-exp)); + exp=(exp+VQ_FEXP_BIAS)<>VQ_FMAN; + if(sign)mant= -mant; + 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 + for length ordered or unordered, always assigns the lowest valued + codewords first. Extended to handle unused entries (length 0) */ +ogg_uint32_t *_make_words(char *l,long n,long sparsecount){ + long i,j,count=0; + ogg_uint32_t marker[33]; + ogg_uint32_t *r=_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r)); + memset(marker,0,sizeof(marker)); + + for(i=0;i0){ + ogg_uint32_t entry=marker[length]; + + /* when we claim a node for an entry, we also claim the nodes + below it (pruning off the imagined tree that may have dangled + from it) as well as blocking the use of any nodes directly + above for leaves */ + + /* update ourself */ + if(length<32 && (entry>>length)){ + /* error condition; the lengths must specify an overpopulated tree */ + _ogg_free(r); + return(NULL); + } + r[count++]=entry; + + /* Look to see if the next shorter marker points to the node + above. if so, update it and repeat. */ + { + for(j=length;j>0;j--){ + + if(marker[j]&1){ + /* have to jump branches */ + if(j==1) + marker[1]++; + else + marker[j]=marker[j-1]<<1; + break; /* invariant says next upper marker would already + have been moved if it was on the same path */ + } + marker[j]++; + } + } + + /* prune the tree; the implicit invariant says all the longer + markers were dangling from our just-taken node. Dangle them + from our *new* node. */ + for(j=length+1;j<33;j++) + if((marker[j]>>1) == entry){ + entry=marker[j]; + marker[j]=marker[j-1]<<1; + }else + break; + }else + if(sparsecount==0)count++; + } + + /* any underpopulated tree must be rejected. */ + /* Single-entry codebooks are a retconned extension to the spec. + They have a single codeword '0' of length 1 that results in an + underpopulated tree. Shield that case from the underformed tree check. */ + if(!(count==1 && marker[2]==2)){ + for(i=1;i<33;i++) + if(marker[i] & (0xffffffffUL>>(32-i))){ + _ogg_free(r); + return(NULL); + } + } + + /* bitreverse the words because our bitwise packer/unpacker is LSb + endian */ + for(i=0,count=0;i>j)&1; + } + + if(sparsecount){ + if(l[i]) + r[count++]=temp; + }else + r[count++]=temp; + } + + return(r); +} + +/* there might be a straightforward one-line way to do the below + that's portable and totally safe against roundoff, but I haven't + thought of it. Therefore, we opt on the side of caution */ +long _book_maptype1_quantvals(const static_codebook *b){ + long vals; + if(b->entries<1){ + return(0); + } + vals=floor(pow((float)b->entries,1.f/b->dim)); + + /* the above *should* be reliable, but we'll not assume that FP is + ever reliable when bitstream sync is at stake; verify via integer + means that vals really is the greatest value of dim for which + vals^b->bim <= b->entries */ + /* treat the above as an initial guess */ + if(vals<1){ + vals=1; + } + while(1){ + long acc=1; + long acc1=1; + int i; + for(i=0;idim;i++){ + if(b->entries/vals=b->dim && acc<=b->entries && acc1>b->entries){ + return(vals); + }else{ + if(idim || acc>b->entries){ + vals--; + }else{ + vals++; + } + } + } +} + +/* unpack the quantized list of values for encode/decode ***********/ +/* we need to deal with two map types: in map type 1, the values are + generated algorithmically (each column of the vector counts through + the values in the quant vector). in map type 2, all the values came + in in an explicit list. Both value lists must be unpacked */ +float *_book_unquantize(const static_codebook *b,int n,int *sparsemap){ + long j,k,count=0; + if(b->maptype==1 || b->maptype==2){ + int quantvals; + float mindel=_float32_unpack(b->q_min); + float delta=_float32_unpack(b->q_delta); + float *r=_ogg_calloc(n*b->dim,sizeof(*r)); + + /* maptype 1 and 2 both use a quantized value vector, but + different sizes */ + switch(b->maptype){ + case 1: + /* most of the time, entries%dimensions == 0, but we need to be + well defined. We define that the possible vales at each + scalar is values == entries/dim. If entries%dim != 0, we'll + have 'too few' values (values*dimentries;j++){ + if((sparsemap && b->lengthlist[j]) || !sparsemap){ + float last=0.f; + int indexdiv=1; + for(k=0;kdim;k++){ + int index= (j/indexdiv)%quantvals; + float val=b->quantlist[index]; + val=fabs(val)*delta+mindel+last; + if(b->q_sequencep)last=val; + if(sparsemap) + r[sparsemap[count]*b->dim+k]=val; + else + r[count*b->dim+k]=val; + indexdiv*=quantvals; + } + count++; + } + + } + break; + case 2: + for(j=0;jentries;j++){ + if((sparsemap && b->lengthlist[j]) || !sparsemap){ + float last=0.f; + + for(k=0;kdim;k++){ + float val=b->quantlist[j*b->dim+k]; + val=fabs(val)*delta+mindel+last; + if(b->q_sequencep)last=val; + if(sparsemap) + r[sparsemap[count]*b->dim+k]=val; + else + r[count*b->dim+k]=val; + } + count++; + } + } + break; + } + + return(r); + } + return(NULL); +} + +void vorbis_staticbook_destroy(static_codebook *b){ + if(b->allocedp){ + if(b->quantlist)_ogg_free(b->quantlist); + if(b->lengthlist)_ogg_free(b->lengthlist); + memset(b,0,sizeof(*b)); + _ogg_free(b); + } /* otherwise, it is in static memory */ +} + +void vorbis_book_clear(codebook *b){ + /* static book is not cleared; we're likely called on the lookup and + the static codebook belongs to the info struct */ + if(b->valuelist)_ogg_free(b->valuelist); + if(b->codelist)_ogg_free(b->codelist); + + if(b->dec_index)_ogg_free(b->dec_index); + if(b->dec_codelengths)_ogg_free(b->dec_codelengths); + if(b->dec_firsttable)_ogg_free(b->dec_firsttable); + + memset(b,0,sizeof(*b)); +} + +int vorbis_book_init_encode(codebook *c,const static_codebook *s){ + + memset(c,0,sizeof(*c)); + c->c=s; + c->entries=s->entries; + 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->quantvals=_book_maptype1_quantvals(s); + c->minval=(int)rint(_float32_unpack(s->q_min)); + c->delta=(int)rint(_float32_unpack(s->q_delta)); + + return(0); +} + +static ogg_uint32_t bitreverse(ogg_uint32_t x){ + x= ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL); + x= ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL); + x= ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL); + x= ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL); + return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL); +} + +static int sort32a(const void *a,const void *b){ + return ( **(ogg_uint32_t **)a>**(ogg_uint32_t **)b)- + ( **(ogg_uint32_t **)a<**(ogg_uint32_t **)b); +} + +/* decode codebook arrangement is more heavily optimized than encode */ +int vorbis_book_init_decode(codebook *c,const static_codebook *s){ + int i,j,n=0,tabn; + int *sortindex; + + memset(c,0,sizeof(*c)); + + /* count actually used entries and find max length */ + for(i=0;ientries;i++) + if(s->lengthlist[i]>0) + n++; + + c->entries=s->entries; + c->used_entries=n; + c->dim=s->dim; + + if(n>0){ + /* two different remappings go on here. + + First, we collapse the likely sparse codebook down only to + actually represented values/words. This collapsing needs to be + indexed as map-valueless books are used to encode original entry + positions as integers. + + Second, we reorder all vectors, including the entry index above, + by sorted bitreversed codeword to allow treeless decode. */ + + /* perform sort */ + ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries); + ogg_uint32_t **codep=alloca(sizeof(*codep)*n); + + if(codes==NULL)goto err_out; + + for(i=0;icodelist=_ogg_malloc(n*sizeof(*c->codelist)); + /* the index is a reverse index */ + for(i=0;icodelist[sortindex[i]]=codes[i]; + _ogg_free(codes); + + c->valuelist=_book_unquantize(s,n,sortindex); + c->dec_index=_ogg_malloc(n*sizeof(*c->dec_index)); + + for(n=0,i=0;ientries;i++) + if(s->lengthlist[i]>0) + c->dec_index[sortindex[n++]]=i; + + c->dec_codelengths=_ogg_malloc(n*sizeof(*c->dec_codelengths)); + c->dec_maxlength=0; + for(n=0,i=0;ientries;i++) + if(s->lengthlist[i]>0){ + c->dec_codelengths[sortindex[n++]]=s->lengthlist[i]; + if(s->lengthlist[i]>c->dec_maxlength) + c->dec_maxlength=s->lengthlist[i]; + } + + if(n==1 && c->dec_maxlength==1){ + /* special case the 'single entry codebook' with a single bit + fastpath table (that always returns entry 0 )in order to use + unmodified decode paths. */ + c->dec_firsttablen=1; + c->dec_firsttable=_ogg_calloc(2,sizeof(*c->dec_firsttable)); + c->dec_firsttable[0]=c->dec_firsttable[1]=1; + + }else{ + c->dec_firsttablen=ov_ilog(c->used_entries)-4; /* this is magic */ + if(c->dec_firsttablen<5)c->dec_firsttablen=5; + if(c->dec_firsttablen>8)c->dec_firsttablen=8; + + tabn=1<dec_firsttablen; + c->dec_firsttable=_ogg_calloc(tabn,sizeof(*c->dec_firsttable)); + + for(i=0;idec_codelengths[i]<=c->dec_firsttablen){ + ogg_uint32_t orig=bitreverse(c->codelist[i]); + for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++) + c->dec_firsttable[orig|(j<dec_codelengths[i])]=i+1; + } + } + + /* now fill in 'unused' entries in the firsttable with hi/lo search + hints for the non-direct-hits */ + { + ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen); + long lo=0,hi=0; + + for(i=0;idec_firsttablen); + if(c->dec_firsttable[bitreverse(word)]==0){ + while((lo+1)codelist[lo+1]<=word)lo++; + while( hi=(c->codelist[hi]&mask))hi++; + + /* we only actually have 15 bits per hint to play with here. + In order to overflow gracefully (nothing breaks, efficiency + just drops), encode as the difference from the extremes. */ + { + unsigned long loval=lo; + unsigned long hival=n-hi; + + if(loval>0x7fff)loval=0x7fff; + if(hival>0x7fff)hival=0x7fff; + c->dec_firsttable[bitreverse(word)]= + 0x80000000UL | (loval<<15) | hival; + } + } + } + } + } + } + + return(0); + err_out: + vorbis_book_clear(c); + return(-1); +} + +long vorbis_book_codeword(codebook *book,int entry){ + if(book->c) /* only use with encode; decode optimizations are + allowed to break this */ + return book->codelist[entry]; + return -1; +} + +long vorbis_book_codelen(codebook *book,int entry){ + if(book->c) /* only use with encode; decode optimizations are + allowed to break this */ + return book->c->lengthlist[entry]; + return -1; +} + +#ifdef _V_SELFTEST + +/* Unit tests of the dequantizer; this stuff will be OK + cross-platform, I simply want to be sure that special mapping cases + actually work properly; a bug could go unnoticed for a while */ + +#include + +/* cases: + + no mapping + full, explicit mapping + algorithmic mapping + + nonsequential + sequential +*/ + +static long full_quantlist1[]={0,1,2,3, 4,5,6,7, 8,3,6,1}; +static long partial_quantlist1[]={0,7,2}; + +/* no mapping */ +static_codebook test1={ + 4,16, + NULL, + 0, + 0,0,0,0, + NULL, + 0 +}; +static float *test1_result=NULL; + +/* linear, full mapping, nonsequential */ +static_codebook test2={ + 4,3, + NULL, + 2, + -533200896,1611661312,4,0, + full_quantlist1, + 0 +}; +static float test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2}; + +/* linear, full mapping, sequential */ +static_codebook test3={ + 4,3, + NULL, + 2, + -533200896,1611661312,4,1, + full_quantlist1, + 0 +}; +static float test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6}; + +/* linear, algorithmic mapping, nonsequential */ +static_codebook test4={ + 3,27, + NULL, + 1, + -533200896,1611661312,4,0, + partial_quantlist1, + 0 +}; +static float test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3, + -3, 4,-3, 4, 4,-3, -1, 4,-3, + -3,-1,-3, 4,-1,-3, -1,-1,-3, + -3,-3, 4, 4,-3, 4, -1,-3, 4, + -3, 4, 4, 4, 4, 4, -1, 4, 4, + -3,-1, 4, 4,-1, 4, -1,-1, 4, + -3,-3,-1, 4,-3,-1, -1,-3,-1, + -3, 4,-1, 4, 4,-1, -1, 4,-1, + -3,-1,-1, 4,-1,-1, -1,-1,-1}; + +/* linear, algorithmic mapping, sequential */ +static_codebook test5={ + 3,27, + NULL, + 1, + -533200896,1611661312,4,1, + partial_quantlist1, + 0 +}; +static float test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7, + -3, 1,-2, 4, 8, 5, -1, 3, 0, + -3,-4,-7, 4, 3, 0, -1,-2,-5, + -3,-6,-2, 4, 1, 5, -1,-4, 0, + -3, 1, 5, 4, 8,12, -1, 3, 7, + -3,-4, 0, 4, 3, 7, -1,-2, 2, + -3,-6,-7, 4, 1, 0, -1,-4,-5, + -3, 1, 0, 4, 8, 7, -1, 3, 2, + -3,-4,-5, 4, 3, 2, -1,-2,-3}; + +void run_test(static_codebook *b,float *comp){ + float *out=_book_unquantize(b,b->entries,NULL); + int i; + + if(comp){ + if(!out){ + fprintf(stderr,"_book_unquantize incorrectly returned NULL\n"); + exit(1); + } + + for(i=0;ientries*b->dim;i++) + if(fabs(out[i]-comp[i])>.0001){ + fprintf(stderr,"disagreement in unquantized and reference data:\n" + "position %d, %g != %g\n",i,out[i],comp[i]); + exit(1); + } + + }else{ + if(out){ + fprintf(stderr,"_book_unquantize returned a value array: \n" + " correct result should have been NULL\n"); + exit(1); + } + } + free(out); +} + +int main(){ + /* run the nine dequant tests, and compare to the hand-rolled results */ + fprintf(stderr,"Dequant test 1... "); + run_test(&test1,test1_result); + fprintf(stderr,"OK\nDequant test 2... "); + run_test(&test2,test2_result); + fprintf(stderr,"OK\nDequant test 3... "); + run_test(&test3,test3_result); + fprintf(stderr,"OK\nDequant test 4... "); + run_test(&test4,test4_result); + fprintf(stderr,"OK\nDequant test 5... "); + run_test(&test5,test5_result); + fprintf(stderr,"OK\n\n"); + + return(0); +} + +#endif diff --git a/vendor/vorbis/lib/smallft.c b/vendor/vorbis/lib/smallft.c new file mode 100644 index 0000000..4ffabab --- /dev/null +++ b/vendor/vorbis/lib/smallft.c @@ -0,0 +1,1254 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: *unnormalized* fft transform + + ********************************************************************/ + +/* FFT implementation from OggSquish, minus cosine transforms, + * minus all but radix 2/4 case. In Vorbis we only need this + * cut-down version. + * + * To do more than just power-of-two sized vectors, see the full + * version I wrote for NetLib. + * + * Note that the packing is a little strange; rather than the FFT r/i + * packing following R_0, I_n, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, + * it follows R_0, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, I_n like the + * FORTRAN version + */ + +#include +#include +#include +#include "smallft.h" +#include "os.h" +#include "misc.h" + +static void drfti1(int n, float *wa, int *ifac){ + static int ntryh[4] = { 4,2,3,5 }; + static float tpi = 6.28318530717958648f; + float arg,argh,argld,fi; + int ntry=0,i,j=-1; + int k1, l1, l2, ib; + int ld, ii, ip, is, nq, nr; + int ido, ipm, nfm1; + int nl=n; + int nf=0; + + L101: + j++; + if (j < 4) + ntry=ntryh[j]; + else + ntry+=2; + + L104: + nq=nl/ntry; + nr=nl-ntry*nq; + if (nr!=0) goto L101; + + nf++; + ifac[nf+1]=ntry; + nl=nq; + if(ntry!=2)goto L107; + if(nf==1)goto L107; + + for (i=1;i>1; + ipp2=ip; + idp2=ido; + nbd=(ido-1)>>1; + t0=l1*ido; + t10=ip*ido; + + if(ido==1)goto L119; + for(ik=0;ikl1){ + for(j=1;j>1; + ipp2=ip; + ipph=(ip+1)>>1; + if(idol1)goto L139; + + is= -ido-1; + t1=0; + for(j=1;jn==1)return; + drftf1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void drft_backward(drft_lookup *l,float *data){ + if (l->n==1)return; + drftb1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void drft_init(drft_lookup *l,int n){ + l->n=n; + l->trigcache=_ogg_calloc(3*n,sizeof(*l->trigcache)); + l->splitcache=_ogg_calloc(32,sizeof(*l->splitcache)); + fdrffti(n, l->trigcache, l->splitcache); +} + +void drft_clear(drft_lookup *l){ + if(l){ + if(l->trigcache)_ogg_free(l->trigcache); + if(l->splitcache)_ogg_free(l->splitcache); + memset(l,0,sizeof(*l)); + } +} diff --git a/vendor/vorbis/lib/smallft.h b/vendor/vorbis/lib/smallft.h new file mode 100644 index 0000000..02fe8f9 --- /dev/null +++ b/vendor/vorbis/lib/smallft.h @@ -0,0 +1,33 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: fft transform + + ********************************************************************/ + +#ifndef _V_SMFT_H_ +#define _V_SMFT_H_ + +#include "vorbis/codec.h" + +typedef struct { + int n; + float *trigcache; + int *splitcache; +} drft_lookup; + +extern void drft_forward(drft_lookup *l,float *data); +extern void drft_backward(drft_lookup *l,float *data); +extern void drft_init(drft_lookup *l,int n); +extern void drft_clear(drft_lookup *l); + +#endif diff --git a/vendor/vorbis/lib/synthesis.c b/vendor/vorbis/lib/synthesis.c new file mode 100644 index 0000000..3e2d681 --- /dev/null +++ b/vendor/vorbis/lib/synthesis.c @@ -0,0 +1,179 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: single-block PCM synthesis + + ********************************************************************/ + +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "registry.h" +#include "misc.h" +#include "os.h" + +int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){ + vorbis_dsp_state *vd= vb ? vb->vd : 0; + private_state *b= vd ? vd->backend_state : 0; + vorbis_info *vi= vd ? vd->vi : 0; + codec_setup_info *ci= vi ? vi->codec_setup : 0; + oggpack_buffer *opb=vb ? &vb->opb : 0; + int type,mode,i; + + if (!vd || !b || !vi || !ci || !opb) { + return OV_EBADPACKET; + } + + /* first things first. Make sure decode is ready */ + _vorbis_block_ripcord(vb); + oggpack_readinit(opb,op->packet,op->bytes); + + /* Check the packet type */ + if(oggpack_read(opb,1)!=0){ + /* Oops. This is not an audio data packet */ + return(OV_ENOTAUDIO); + } + + /* read our mode and pre/post windowsize */ + mode=oggpack_read(opb,b->modebits); + if(mode==-1){ + return(OV_EBADPACKET); + } + + vb->mode=mode; + if(!ci->mode_param[mode]){ + return(OV_EBADPACKET); + } + + vb->W=ci->mode_param[mode]->blockflag; + if(vb->W){ + + /* this doesn;t get mapped through mode selection as it's used + only for window selection */ + vb->lW=oggpack_read(opb,1); + vb->nW=oggpack_read(opb,1); + if(vb->nW==-1){ + return(OV_EBADPACKET); + } + }else{ + vb->lW=0; + vb->nW=0; + } + + /* more setup */ + vb->granulepos=op->granulepos; + vb->sequence=op->packetno; + vb->eofflag=op->e_o_s; + + /* alloc pcm passback storage */ + vb->pcmend=ci->blocksizes[vb->W]; + vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels); + for(i=0;ichannels;i++) + vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i])); + + /* unpack_header enforces range checking */ + type=ci->map_type[ci->mode_param[mode]->mapping]; + + return(_mapping_P[type]->inverse(vb,ci->map_param[ci->mode_param[mode]-> + mapping])); +} + +/* used to track pcm position without actually performing decode. + Useful for sequential 'fast forward' */ +int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){ + vorbis_dsp_state *vd=vb->vd; + private_state *b=vd->backend_state; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + oggpack_buffer *opb=&vb->opb; + int mode; + + /* first things first. Make sure decode is ready */ + _vorbis_block_ripcord(vb); + oggpack_readinit(opb,op->packet,op->bytes); + + /* Check the packet type */ + if(oggpack_read(opb,1)!=0){ + /* Oops. This is not an audio data packet */ + return(OV_ENOTAUDIO); + } + + /* read our mode and pre/post windowsize */ + mode=oggpack_read(opb,b->modebits); + if(mode==-1)return(OV_EBADPACKET); + + vb->mode=mode; + if(!ci->mode_param[mode]){ + return(OV_EBADPACKET); + } + + vb->W=ci->mode_param[mode]->blockflag; + if(vb->W){ + vb->lW=oggpack_read(opb,1); + vb->nW=oggpack_read(opb,1); + if(vb->nW==-1) return(OV_EBADPACKET); + }else{ + vb->lW=0; + vb->nW=0; + } + + /* more setup */ + vb->granulepos=op->granulepos; + vb->sequence=op->packetno; + vb->eofflag=op->e_o_s; + + /* no pcm */ + vb->pcmend=0; + vb->pcm=NULL; + + return(0); +} + +long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){ + codec_setup_info *ci=vi->codec_setup; + oggpack_buffer opb; + int mode; + + if(ci==NULL || ci->modes<=0){ + /* codec setup not properly intialized */ + return(OV_EFAULT); + } + + oggpack_readinit(&opb,op->packet,op->bytes); + + /* Check the packet type */ + if(oggpack_read(&opb,1)!=0){ + /* Oops. This is not an audio data packet */ + return(OV_ENOTAUDIO); + } + + /* read our mode and pre/post windowsize */ + mode=oggpack_read(&opb,ov_ilog(ci->modes-1)); + if(mode==-1 || !ci->mode_param[mode])return(OV_EBADPACKET); + return(ci->blocksizes[ci->mode_param[mode]->blockflag]); +} + +int vorbis_synthesis_halfrate(vorbis_info *vi,int flag){ + /* set / clear half-sample-rate mode */ + codec_setup_info *ci=vi->codec_setup; + + /* right now, our MDCT can't handle < 64 sample windows. */ + if(ci->blocksizes[0]<=64 && flag)return -1; + ci->halfrate_flag=(flag?1:0); + return 0; +} + +int vorbis_synthesis_halfrate_p(vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + return ci->halfrate_flag; +} diff --git a/vendor/vorbis/lib/tone.c b/vendor/vorbis/lib/tone.c new file mode 100644 index 0000000..5b8b020 --- /dev/null +++ b/vendor/vorbis/lib/tone.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +void usage(){ + fprintf(stderr,"tone ,[] [,[]...]\n"); + exit(1); +} + +int main (int argc,char *argv[]){ + int i,j; + double *f; + double *amp; + + if(argc<2)usage(); + + f=alloca(sizeof(*f)*(argc-1)); + amp=alloca(sizeof(*amp)*(argc-1)); + + i=0; + while(argv[i+1]){ + char *pos=strchr(argv[i+1],','); + + f[i]=atof(argv[i+1]); + if(pos) + amp[i]=atof(pos+1)*32767.f; + else + amp[i]=32767.f; + + fprintf(stderr,"%g Hz, %g amp\n",f[i],amp[i]); + + i++; + } + + for(i=0;i<44100*10;i++){ + float val=0; + int ival; + for(j=0;j32767.f)ival=32767.f; + if(ival<-32768.f)ival=-32768.f; + + fprintf(stdout,"%c%c%c%c", + (char)(ival&0xff), + (char)((ival>>8)&0xff), + (char)(ival&0xff), + (char)((ival>>8)&0xff)); + } + return(0); +} + diff --git a/vendor/vorbis/lib/vorbisenc.c b/vendor/vorbis/lib/vorbisenc.c new file mode 100644 index 0000000..cf3806a --- /dev/null +++ b/vendor/vorbis/lib/vorbisenc.c @@ -0,0 +1,1224 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: simple programmatic interface for encoder mode setup + + ********************************************************************/ + +#include +#include +#include + +#include "vorbis/codec.h" +#include "vorbis/vorbisenc.h" + +#include "codec_internal.h" + +#include "os.h" +#include "misc.h" + +/* careful with this; it's using static array sizing to make managing + all the modes a little less annoying. If we use a residue backend + with > 12 partition types, or a different division of iteration, + this needs to be updated. */ +typedef struct { + const static_codebook *books[12][4]; +} static_bookblock; + +typedef struct { + int res_type; + int limit_type; /* 0 lowpass limited, 1 point stereo limited */ + int grouping; + const vorbis_info_residue0 *res; + const static_codebook *book_aux; + const static_codebook *book_aux_managed; + const static_bookblock *books_base; + const static_bookblock *books_base_managed; +} vorbis_residue_template; + +typedef struct { + const vorbis_info_mapping0 *map; + const vorbis_residue_template *res; +} vorbis_mapping_template; + +typedef struct vp_adjblock{ + int block[P_BANDS]; +} vp_adjblock; + +typedef struct { + int data[NOISE_COMPAND_LEVELS]; +} compandblock; + +/* high level configuration information for setting things up + step-by-step with the detailed vorbis_encode_ctl interface. + There's a fair amount of redundancy such that interactive setup + does not directly deal with any vorbis_info or codec_setup_info + initialization; it's all stored (until full init) in this highlevel + setup, then flushed out to the real codec setup structs later. */ + +typedef struct { + int att[P_NOISECURVES]; + float boost; + float decay; +} att3; +typedef struct { int data[P_NOISECURVES]; } adj3; + +typedef struct { + int pre[PACKETBLOBS]; + int post[PACKETBLOBS]; + float kHz[PACKETBLOBS]; + float lowpasskHz[PACKETBLOBS]; +} adj_stereo; + +typedef struct { + int lo; + int hi; + int fixed; +} noiseguard; +typedef struct { + int data[P_NOISECURVES][17]; +} noise3; + +typedef struct { + int mappings; + const double *rate_mapping; + const double *quality_mapping; + int coupling_restriction; + long samplerate_min_restriction; + long samplerate_max_restriction; + + + const int *blocksize_short; + const int *blocksize_long; + + const att3 *psy_tone_masteratt; + const int *psy_tone_0dB; + const int *psy_tone_dBsuppress; + + const vp_adjblock *psy_tone_adj_impulse; + const vp_adjblock *psy_tone_adj_long; + const vp_adjblock *psy_tone_adj_other; + + const noiseguard *psy_noiseguards; + const noise3 *psy_noise_bias_impulse; + const noise3 *psy_noise_bias_padding; + const noise3 *psy_noise_bias_trans; + const noise3 *psy_noise_bias_long; + const int *psy_noise_dBsuppress; + + const compandblock *psy_noise_compand; + const double *psy_noise_compand_short_mapping; + const double *psy_noise_compand_long_mapping; + + const int *psy_noise_normal_start[2]; + const int *psy_noise_normal_partition[2]; + const double *psy_noise_normal_thresh; + + const int *psy_ath_float; + const int *psy_ath_abs; + + const double *psy_lowpass; + + const vorbis_info_psy_global *global_params; + const double *global_mapping; + const adj_stereo *stereo_modes; + + const static_codebook *const *const *const floor_books; + const vorbis_info_floor1 *floor_params; + const int floor_mappings; + const int **floor_mapping_list; + + const vorbis_mapping_template *maps; +} ve_setup_data_template; + +/* a few static coder conventions */ +static const vorbis_info_mode _mode_template[2]={ + {0,0,0,0}, + {1,0,0,1} +}; + +static const vorbis_info_mapping0 _map_nominal[2]={ + {1, {0,0}, {0}, {0}, 1,{0},{1}}, + {1, {0,0}, {1}, {1}, 1,{0},{1}} +}; + +#include "modes/setup_44.h" +#include "modes/setup_44u.h" +#include "modes/setup_44p51.h" +#include "modes/setup_32.h" +#include "modes/setup_8.h" +#include "modes/setup_11.h" +#include "modes/setup_16.h" +#include "modes/setup_22.h" +#include "modes/setup_X.h" + +static const ve_setup_data_template *const setup_list[]={ + &ve_setup_44_stereo, + &ve_setup_44_51, + &ve_setup_44_uncoupled, + + &ve_setup_32_stereo, + &ve_setup_32_uncoupled, + + &ve_setup_22_stereo, + &ve_setup_22_uncoupled, + &ve_setup_16_stereo, + &ve_setup_16_uncoupled, + + &ve_setup_11_stereo, + &ve_setup_11_uncoupled, + &ve_setup_8_stereo, + &ve_setup_8_uncoupled, + + &ve_setup_X_stereo, + &ve_setup_X_uncoupled, + &ve_setup_XX_stereo, + &ve_setup_XX_uncoupled, + 0 +}; + +static void vorbis_encode_floor_setup(vorbis_info *vi,int s, + const static_codebook *const *const *const books, + const vorbis_info_floor1 *in, + const int *x){ + int i,k,is=s; + vorbis_info_floor1 *f=_ogg_calloc(1,sizeof(*f)); + codec_setup_info *ci=vi->codec_setup; + + memcpy(f,in+x[is],sizeof(*f)); + + /* books */ + { + int partitions=f->partitions; + int maxclass=-1; + int maxbook=-1; + for(i=0;ipartitionclass[i]>maxclass)maxclass=f->partitionclass[i]; + for(i=0;i<=maxclass;i++){ + if(f->class_book[i]>maxbook)maxbook=f->class_book[i]; + f->class_book[i]+=ci->books; + for(k=0;k<(1<class_subs[i]);k++){ + if(f->class_subbook[i][k]>maxbook)maxbook=f->class_subbook[i][k]; + if(f->class_subbook[i][k]>=0)f->class_subbook[i][k]+=ci->books; + } + } + + for(i=0;i<=maxbook;i++) + ci->book_param[ci->books++]=(static_codebook *)books[x[is]][i]; + } + + /* for now, we're only using floor 1 */ + ci->floor_type[ci->floors]=1; + ci->floor_param[ci->floors]=f; + ci->floors++; + + return; +} + +static void vorbis_encode_global_psych_setup(vorbis_info *vi,double s, + const vorbis_info_psy_global *in, + const double *x){ + int i,is=s; + double ds=s-is; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy_global *g=&ci->psy_g_param; + + memcpy(g,in+(int)x[is],sizeof(*g)); + + ds=x[is]*(1.-ds)+x[is+1]*ds; + is=(int)ds; + ds-=is; + if(ds==0 && is>0){ + is--; + ds=1.; + } + + /* interpolate the trigger threshholds */ + for(i=0;i<4;i++){ + g->preecho_thresh[i]=in[is].preecho_thresh[i]*(1.-ds)+in[is+1].preecho_thresh[i]*ds; + g->postecho_thresh[i]=in[is].postecho_thresh[i]*(1.-ds)+in[is+1].postecho_thresh[i]*ds; + } + g->ampmax_att_per_sec=ci->hi.amplitude_track_dBpersec; + return; +} + +static void vorbis_encode_global_stereo(vorbis_info *vi, + const highlevel_encode_setup *const hi, + const adj_stereo *p){ + float s=hi->stereo_point_setting; + int i,is=s; + double ds=s-is; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy_global *g=&ci->psy_g_param; + + if(p){ + memcpy(g->coupling_prepointamp,p[is].pre,sizeof(*p[is].pre)*PACKETBLOBS); + memcpy(g->coupling_postpointamp,p[is].post,sizeof(*p[is].post)*PACKETBLOBS); + + if(hi->managed){ + /* interpolate the kHz threshholds */ + for(i=0;icoupling_pointlimit[0][i]=kHz*1000./vi->rate*ci->blocksizes[0]; + g->coupling_pointlimit[1][i]=kHz*1000./vi->rate*ci->blocksizes[1]; + g->coupling_pkHz[i]=kHz; + + kHz=p[is].lowpasskHz[i]*(1.-ds)+p[is+1].lowpasskHz[i]*ds; + g->sliding_lowpass[0][i]=kHz*1000./vi->rate*ci->blocksizes[0]; + g->sliding_lowpass[1][i]=kHz*1000./vi->rate*ci->blocksizes[1]; + + } + }else{ + float kHz=p[is].kHz[PACKETBLOBS/2]*(1.-ds)+p[is+1].kHz[PACKETBLOBS/2]*ds; + for(i=0;icoupling_pointlimit[0][i]=kHz*1000./vi->rate*ci->blocksizes[0]; + g->coupling_pointlimit[1][i]=kHz*1000./vi->rate*ci->blocksizes[1]; + g->coupling_pkHz[i]=kHz; + } + + kHz=p[is].lowpasskHz[PACKETBLOBS/2]*(1.-ds)+p[is+1].lowpasskHz[PACKETBLOBS/2]*ds; + for(i=0;isliding_lowpass[0][i]=kHz*1000./vi->rate*ci->blocksizes[0]; + g->sliding_lowpass[1][i]=kHz*1000./vi->rate*ci->blocksizes[1]; + } + } + }else{ + for(i=0;isliding_lowpass[0][i]=ci->blocksizes[0]; + g->sliding_lowpass[1][i]=ci->blocksizes[1]; + } + } + return; +} + +static void vorbis_encode_psyset_setup(vorbis_info *vi,double s, + const int *nn_start, + const int *nn_partition, + const double *nn_thresh, + int block){ + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + highlevel_encode_setup *hi=&ci->hi; + int is=s; + + if(block>=ci->psys) + ci->psys=block+1; + if(!p){ + p=_ogg_calloc(1,sizeof(*p)); + ci->psy_param[block]=p; + } + + memcpy(p,&_psy_info_template,sizeof(*p)); + p->blockflag=block>>1; + + if(hi->noise_normalize_p){ + p->normal_p=1; + p->normal_start=nn_start[is]; + p->normal_partition=nn_partition[is]; + p->normal_thresh=nn_thresh[is]; + } + + return; +} + +static void vorbis_encode_tonemask_setup(vorbis_info *vi,double s,int block, + const att3 *att, + const int *max, + const vp_adjblock *in){ + int i,is=s; + double ds=s-is; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + /* 0 and 2 are only used by bitmanagement, but there's no harm to always + filling the values in here */ + p->tone_masteratt[0]=att[is].att[0]*(1.-ds)+att[is+1].att[0]*ds; + p->tone_masteratt[1]=att[is].att[1]*(1.-ds)+att[is+1].att[1]*ds; + p->tone_masteratt[2]=att[is].att[2]*(1.-ds)+att[is+1].att[2]*ds; + p->tone_centerboost=att[is].boost*(1.-ds)+att[is+1].boost*ds; + p->tone_decay=att[is].decay*(1.-ds)+att[is+1].decay*ds; + + p->max_curve_dB=max[is]*(1.-ds)+max[is+1]*ds; + + for(i=0;itoneatt[i]=in[is].block[i]*(1.-ds)+in[is+1].block[i]*ds; + return; +} + + +static void vorbis_encode_compand_setup(vorbis_info *vi,double s,int block, + const compandblock *in, + const double *x){ + int i,is=s; + double ds=s-is; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + ds=x[is]*(1.-ds)+x[is+1]*ds; + is=(int)ds; + ds-=is; + if(ds==0 && is>0){ + is--; + ds=1.; + } + + /* interpolate the compander settings */ + for(i=0;inoisecompand[i]=in[is].data[i]*(1.-ds)+in[is+1].data[i]*ds; + return; +} + +static void vorbis_encode_peak_setup(vorbis_info *vi,double s,int block, + const int *suppress){ + int is=s; + double ds=s-is; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + p->tone_abs_limit=suppress[is]*(1.-ds)+suppress[is+1]*ds; + + return; +} + +static void vorbis_encode_noisebias_setup(vorbis_info *vi,double s,int block, + const int *suppress, + const noise3 *in, + const noiseguard *guard, + double userbias){ + int i,is=s,j; + double ds=s-is; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + p->noisemaxsupp=suppress[is]*(1.-ds)+suppress[is+1]*ds; + p->noisewindowlomin=guard[block].lo; + p->noisewindowhimin=guard[block].hi; + p->noisewindowfixed=guard[block].fixed; + + for(j=0;jnoiseoff[j][i]=in[is].data[j][i]*(1.-ds)+in[is+1].data[j][i]*ds; + + /* impulse blocks may take a user specified bias to boost the + nominal/high noise encoding depth */ + for(j=0;jnoiseoff[j][0]+6; /* the lowest it can go */ + for(i=0;inoiseoff[j][i]+=userbias; + if(p->noiseoff[j][i]noiseoff[j][i]=min; + } + } + + return; +} + +static void vorbis_encode_ath_setup(vorbis_info *vi,int block){ + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + p->ath_adjatt=ci->hi.ath_floating_dB; + p->ath_maxatt=ci->hi.ath_absolute_dB; + return; +} + + +static int book_dup_or_new(codec_setup_info *ci,const static_codebook *book){ + int i; + for(i=0;ibooks;i++) + if(ci->book_param[i]==book)return(i); + + return(ci->books++); +} + +static void vorbis_encode_blocksize_setup(vorbis_info *vi,double s, + const int *shortb,const int *longb){ + + codec_setup_info *ci=vi->codec_setup; + int is=s; + + int blockshort=shortb[is]; + int blocklong=longb[is]; + ci->blocksizes[0]=blockshort; + ci->blocksizes[1]=blocklong; + +} + +static void vorbis_encode_residue_setup(vorbis_info *vi, + int number, int block, + const vorbis_residue_template *res){ + + codec_setup_info *ci=vi->codec_setup; + int i; + + vorbis_info_residue0 *r=ci->residue_param[number]= + _ogg_malloc(sizeof(*r)); + + memcpy(r,res->res,sizeof(*r)); + if(ci->residues<=number)ci->residues=number+1; + + r->grouping=res->grouping; + ci->residue_type[number]=res->res_type; + + /* fill in all the books */ + { + int booklist=0,k; + + if(ci->hi.managed){ + for(i=0;ipartitions;i++) + for(k=0;k<4;k++) + if(res->books_base_managed->books[i][k]) + r->secondstages[i]|=(1<groupbook=book_dup_or_new(ci,res->book_aux_managed); + ci->book_param[r->groupbook]=(static_codebook *)res->book_aux_managed; + + for(i=0;ipartitions;i++){ + for(k=0;k<4;k++){ + if(res->books_base_managed->books[i][k]){ + int bookid=book_dup_or_new(ci,res->books_base_managed->books[i][k]); + r->booklist[booklist++]=bookid; + ci->book_param[bookid]=(static_codebook *)res->books_base_managed->books[i][k]; + } + } + } + + }else{ + + for(i=0;ipartitions;i++) + for(k=0;k<4;k++) + if(res->books_base->books[i][k]) + r->secondstages[i]|=(1<groupbook=book_dup_or_new(ci,res->book_aux); + ci->book_param[r->groupbook]=(static_codebook *)res->book_aux; + + for(i=0;ipartitions;i++){ + for(k=0;k<4;k++){ + if(res->books_base->books[i][k]){ + int bookid=book_dup_or_new(ci,res->books_base->books[i][k]); + r->booklist[booklist++]=bookid; + ci->book_param[bookid]=(static_codebook *)res->books_base->books[i][k]; + } + } + } + } + } + + /* lowpass setup/pointlimit */ + { + double freq=ci->hi.lowpass_kHz*1000.; + vorbis_info_floor1 *f=ci->floor_param[block]; /* by convention */ + double nyq=vi->rate/2.; + long blocksize=ci->blocksizes[block]>>1; + + /* lowpass needs to be set in the floor and the residue. */ + if(freq>nyq)freq=nyq; + /* in the floor, the granularity can be very fine; it doesn't alter + the encoding structure, only the samples used to fit the floor + approximation */ + f->n=freq/nyq*blocksize; + + /* this res may by limited by the maximum pointlimit of the mode, + not the lowpass. the floor is always lowpass limited. */ + switch(res->limit_type){ + case 1: /* point stereo limited */ + if(ci->hi.managed) + freq=ci->psy_g_param.coupling_pkHz[PACKETBLOBS-1]*1000.; + else + freq=ci->psy_g_param.coupling_pkHz[PACKETBLOBS/2]*1000.; + if(freq>nyq)freq=nyq; + break; + case 2: /* LFE channel; lowpass at ~ 250Hz */ + freq=250; + break; + default: + /* already set */ + break; + } + + /* in the residue, we're constrained, physically, by partition + boundaries. We still lowpass 'wherever', but we have to round up + here to next boundary, or the vorbis spec will round it *down* to + previous boundary in encode/decode */ + if(ci->residue_type[number]==2){ + /* residue 2 bundles together multiple channels; used by stereo + and surround. Count the channels in use */ + /* Multiple maps/submaps can point to the same residue. In the case + of residue 2, they all better have the same number of + channels/samples. */ + int j,k,ch=0; + for(i=0;imaps&&ch==0;i++){ + vorbis_info_mapping0 *mi=(vorbis_info_mapping0 *)ci->map_param[i]; + for(j=0;jsubmaps && ch==0;j++) + if(mi->residuesubmap[j]==number) /* we found a submap referencing theis residue backend */ + for(k=0;kchannels;k++) + if(mi->chmuxlist[k]==j) /* this channel belongs to the submap */ + ch++; + } + + r->end=(int)((freq/nyq*blocksize*ch)/r->grouping+.9)* /* round up only if we're well past */ + r->grouping; + /* the blocksize and grouping may disagree at the end */ + if(r->end>blocksize*ch)r->end=blocksize*ch/r->grouping*r->grouping; + + }else{ + + r->end=(int)((freq/nyq*blocksize)/r->grouping+.9)* /* round up only if we're well past */ + r->grouping; + /* the blocksize and grouping may disagree at the end */ + if(r->end>blocksize)r->end=blocksize/r->grouping*r->grouping; + + } + + if(r->end==0)r->end=r->grouping; /* LFE channel */ + + } +} + +/* we assume two maps in this encoder */ +static void vorbis_encode_map_n_res_setup(vorbis_info *vi,double s, + const vorbis_mapping_template *maps){ + + codec_setup_info *ci=vi->codec_setup; + int i,j,is=s,modes=2; + const vorbis_info_mapping0 *map=maps[is].map; + const vorbis_info_mode *mode=_mode_template; + const vorbis_residue_template *res=maps[is].res; + + if(ci->blocksizes[0]==ci->blocksizes[1])modes=1; + + for(i=0;imap_param[i]=_ogg_calloc(1,sizeof(*map)); + ci->mode_param[i]=_ogg_calloc(1,sizeof(*mode)); + + memcpy(ci->mode_param[i],mode+i,sizeof(*_mode_template)); + if(i>=ci->modes)ci->modes=i+1; + + ci->map_type[i]=0; + memcpy(ci->map_param[i],map+i,sizeof(*map)); + if(i>=ci->maps)ci->maps=i+1; + + for(j=0;jcodec_setup; + highlevel_encode_setup *hi=&ci->hi; + ve_setup_data_template *setup=(ve_setup_data_template *)hi->setup; + int is=hi->base_setting; + double ds=hi->base_setting-is; + int ch=vi->channels; + const double *r=setup->rate_mapping; + + if(r==NULL) + return(-1); + + return((r[is]*(1.-ds)+r[is+1]*ds)*ch); +} + +static const void *get_setup_template(long ch,long srate, + double req,int q_or_bitrate, + double *base_setting){ + int i=0,j; + if(q_or_bitrate)req/=ch; + + while(setup_list[i]){ + if(setup_list[i]->coupling_restriction==-1 || + setup_list[i]->coupling_restriction==ch){ + if(srate>=setup_list[i]->samplerate_min_restriction && + srate<=setup_list[i]->samplerate_max_restriction){ + int mappings=setup_list[i]->mappings; + const double *map=(q_or_bitrate? + setup_list[i]->rate_mapping: + setup_list[i]->quality_mapping); + + /* the template matches. Does the requested quality mode + fall within this template's modes? */ + if(reqmap[setup_list[i]->mappings]){++i;continue;} + for(j=0;j=map[j] && reqcodec_setup; + ve_setup_data_template *setup=NULL; + 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 */ + if(hi->ath_floating_dB>-80)hi->ath_floating_dB=-80; + if(hi->ath_floating_dB<-200)hi->ath_floating_dB=-200; + + /* again, bound this to avoid the app shooting itself int he foot + too badly */ + if(hi->amplitude_track_dBpersec>0.)hi->amplitude_track_dBpersec=0.; + if(hi->amplitude_track_dBpersec<-99999.)hi->amplitude_track_dBpersec=-99999.; + + /* get the appropriate setup template; matches the fetch in previous + stages */ + setup=(ve_setup_data_template *)hi->setup; + if(setup==NULL)return(OV_EINVAL); + + hi->set_in_stone=1; + /* choose block sizes from configured sizes as well as paying + attention to long_block_p and short_block_p. If the configured + short and long blocks are the same length, we set long_block_p + and unset short_block_p */ + vorbis_encode_blocksize_setup(vi,hi->base_setting, + setup->blocksize_short, + setup->blocksize_long); + if(ci->blocksizes[0]==ci->blocksizes[1])singleblock=1; + + /* floor setup; choose proper floor params. Allocated on the floor + stack in order; if we alloc only a single long floor, it's 0 */ + for(i=0;ifloor_mappings;i++) + vorbis_encode_floor_setup(vi,hi->base_setting, + setup->floor_books, + setup->floor_params, + setup->floor_mapping_list[i]); + + /* setup of [mostly] short block detection and stereo*/ + vorbis_encode_global_psych_setup(vi,hi->trigger_setting, + setup->global_params, + setup->global_mapping); + vorbis_encode_global_stereo(vi,hi,setup->stereo_modes); + + /* basic psych setup and noise normalization */ + vorbis_encode_psyset_setup(vi,hi->base_setting, + setup->psy_noise_normal_start[0], + setup->psy_noise_normal_partition[0], + setup->psy_noise_normal_thresh, + 0); + vorbis_encode_psyset_setup(vi,hi->base_setting, + setup->psy_noise_normal_start[0], + setup->psy_noise_normal_partition[0], + setup->psy_noise_normal_thresh, + 1); + if(!singleblock){ + vorbis_encode_psyset_setup(vi,hi->base_setting, + setup->psy_noise_normal_start[1], + setup->psy_noise_normal_partition[1], + setup->psy_noise_normal_thresh, + 2); + vorbis_encode_psyset_setup(vi,hi->base_setting, + setup->psy_noise_normal_start[1], + setup->psy_noise_normal_partition[1], + setup->psy_noise_normal_thresh, + 3); + } + + /* tone masking setup */ + vorbis_encode_tonemask_setup(vi,hi->block[i0].tone_mask_setting,0, + setup->psy_tone_masteratt, + setup->psy_tone_0dB, + setup->psy_tone_adj_impulse); + vorbis_encode_tonemask_setup(vi,hi->block[1].tone_mask_setting,1, + setup->psy_tone_masteratt, + setup->psy_tone_0dB, + setup->psy_tone_adj_other); + if(!singleblock){ + vorbis_encode_tonemask_setup(vi,hi->block[2].tone_mask_setting,2, + setup->psy_tone_masteratt, + setup->psy_tone_0dB, + setup->psy_tone_adj_other); + vorbis_encode_tonemask_setup(vi,hi->block[3].tone_mask_setting,3, + setup->psy_tone_masteratt, + setup->psy_tone_0dB, + setup->psy_tone_adj_long); + } + + /* noise companding setup */ + vorbis_encode_compand_setup(vi,hi->block[i0].noise_compand_setting,0, + setup->psy_noise_compand, + setup->psy_noise_compand_short_mapping); + vorbis_encode_compand_setup(vi,hi->block[1].noise_compand_setting,1, + setup->psy_noise_compand, + setup->psy_noise_compand_short_mapping); + if(!singleblock){ + vorbis_encode_compand_setup(vi,hi->block[2].noise_compand_setting,2, + setup->psy_noise_compand, + setup->psy_noise_compand_long_mapping); + vorbis_encode_compand_setup(vi,hi->block[3].noise_compand_setting,3, + setup->psy_noise_compand, + setup->psy_noise_compand_long_mapping); + } + + /* peak guarding setup */ + vorbis_encode_peak_setup(vi,hi->block[i0].tone_peaklimit_setting,0, + setup->psy_tone_dBsuppress); + vorbis_encode_peak_setup(vi,hi->block[1].tone_peaklimit_setting,1, + setup->psy_tone_dBsuppress); + if(!singleblock){ + vorbis_encode_peak_setup(vi,hi->block[2].tone_peaklimit_setting,2, + setup->psy_tone_dBsuppress); + vorbis_encode_peak_setup(vi,hi->block[3].tone_peaklimit_setting,3, + setup->psy_tone_dBsuppress); + } + + /* noise bias setup */ + vorbis_encode_noisebias_setup(vi,hi->block[i0].noise_bias_setting,0, + setup->psy_noise_dBsuppress, + setup->psy_noise_bias_impulse, + setup->psy_noiseguards, + (i0==0?hi->impulse_noisetune:0.)); + vorbis_encode_noisebias_setup(vi,hi->block[1].noise_bias_setting,1, + setup->psy_noise_dBsuppress, + setup->psy_noise_bias_padding, + setup->psy_noiseguards,0.); + if(!singleblock){ + vorbis_encode_noisebias_setup(vi,hi->block[2].noise_bias_setting,2, + setup->psy_noise_dBsuppress, + setup->psy_noise_bias_trans, + setup->psy_noiseguards,0.); + vorbis_encode_noisebias_setup(vi,hi->block[3].noise_bias_setting,3, + setup->psy_noise_dBsuppress, + setup->psy_noise_bias_long, + setup->psy_noiseguards,0.); + } + + vorbis_encode_ath_setup(vi,0); + vorbis_encode_ath_setup(vi,1); + if(!singleblock){ + vorbis_encode_ath_setup(vi,2); + vorbis_encode_ath_setup(vi,3); + } + + vorbis_encode_map_n_res_setup(vi,hi->base_setting,setup->maps); + + /* set bitrate readonlies and management */ + if(hi->bitrate_av>0) + vi->bitrate_nominal=hi->bitrate_av; + else{ + vi->bitrate_nominal=setting_to_approx_bitrate(vi); + } + + vi->bitrate_lower=hi->bitrate_min; + vi->bitrate_upper=hi->bitrate_max; + if(hi->bitrate_av) + vi->bitrate_window=(double)hi->bitrate_reservoir/hi->bitrate_av; + else + vi->bitrate_window=0.; + + if(hi->managed){ + ci->bi.avg_rate=hi->bitrate_av; + ci->bi.min_rate=hi->bitrate_min; + ci->bi.max_rate=hi->bitrate_max; + + ci->bi.reservoir_bits=hi->bitrate_reservoir; + ci->bi.reservoir_bias= + hi->bitrate_reservoir_bias; + + ci->bi.slew_damp=hi->bitrate_av_damp; + + } + + return(0); + +} + +static void vorbis_encode_setup_setting(vorbis_info *vi, + long channels, + long rate){ + int i,is; + codec_setup_info *ci=vi->codec_setup; + highlevel_encode_setup *hi=&ci->hi; + const ve_setup_data_template *setup=hi->setup; + double ds; + + vi->version=0; + vi->channels=channels; + vi->rate=rate; + + hi->impulse_block_p=1; + hi->noise_normalize_p=1; + + is=hi->base_setting; + ds=hi->base_setting-is; + + hi->stereo_point_setting=hi->base_setting; + + if(!hi->lowpass_altered) + hi->lowpass_kHz= + setup->psy_lowpass[is]*(1.-ds)+setup->psy_lowpass[is+1]*ds; + + hi->ath_floating_dB=setup->psy_ath_float[is]*(1.-ds)+ + setup->psy_ath_float[is+1]*ds; + hi->ath_absolute_dB=setup->psy_ath_abs[is]*(1.-ds)+ + setup->psy_ath_abs[is+1]*ds; + + hi->amplitude_track_dBpersec=-6.; + hi->trigger_setting=hi->base_setting; + + for(i=0;i<4;i++){ + hi->block[i].tone_mask_setting=hi->base_setting; + hi->block[i].tone_peaklimit_setting=hi->base_setting; + hi->block[i].noise_bias_setting=hi->base_setting; + hi->block[i].noise_compand_setting=hi->base_setting; + } +} + +int vorbis_encode_setup_vbr(vorbis_info *vi, + long channels, + long rate, + float quality){ + codec_setup_info *ci; + highlevel_encode_setup *hi; + if(rate<=0) return OV_EINVAL; + + ci=vi->codec_setup; + hi=&ci->hi; + + quality+=.0000001; + if(quality>=1.)quality=.9999; + + hi->req=quality; + hi->setup=get_setup_template(channels,rate,quality,0,&hi->base_setting); + if(!hi->setup)return OV_EIMPL; + + vorbis_encode_setup_setting(vi,channels,rate); + hi->managed=0; + hi->coupling_p=1; + + return 0; +} + +int vorbis_encode_init_vbr(vorbis_info *vi, + long channels, + long rate, + + float base_quality /* 0. to 1. */ + ){ + int ret=0; + + ret=vorbis_encode_setup_vbr(vi,channels,rate,base_quality); + + if(ret){ + vorbis_info_clear(vi); + return ret; + } + ret=vorbis_encode_setup_init(vi); + if(ret) + vorbis_info_clear(vi); + return(ret); +} + +int vorbis_encode_setup_managed(vorbis_info *vi, + long channels, + long rate, + + long max_bitrate, + long nominal_bitrate, + long min_bitrate){ + + codec_setup_info *ci; + highlevel_encode_setup *hi; + double tnominal; + if(rate<=0) return OV_EINVAL; + + ci=vi->codec_setup; + hi=&ci->hi; + tnominal=nominal_bitrate; + + if(nominal_bitrate<=0.){ + if(max_bitrate>0.){ + if(min_bitrate>0.) + nominal_bitrate=(max_bitrate+min_bitrate)*.5; + else + nominal_bitrate=max_bitrate*.875; + }else{ + if(min_bitrate>0.){ + nominal_bitrate=min_bitrate; + }else{ + return(OV_EINVAL); + } + } + } + + hi->req=nominal_bitrate; + hi->setup=get_setup_template(channels,rate,nominal_bitrate,1,&hi->base_setting); + if(!hi->setup)return OV_EIMPL; + + vorbis_encode_setup_setting(vi,channels,rate); + + /* initialize management with sane defaults */ + hi->coupling_p=1; + hi->managed=1; + hi->bitrate_min=min_bitrate; + hi->bitrate_max=max_bitrate; + hi->bitrate_av=tnominal; + hi->bitrate_av_damp=1.5f; /* full range in no less than 1.5 second */ + hi->bitrate_reservoir=nominal_bitrate*2; + hi->bitrate_reservoir_bias=.1; /* bias toward hoarding bits */ + + return(0); + +} + +int vorbis_encode_init(vorbis_info *vi, + long channels, + long rate, + + long max_bitrate, + long nominal_bitrate, + long min_bitrate){ + + int ret=vorbis_encode_setup_managed(vi,channels,rate, + max_bitrate, + nominal_bitrate, + min_bitrate); + if(ret){ + vorbis_info_clear(vi); + return(ret); + } + + ret=vorbis_encode_setup_init(vi); + if(ret) + vorbis_info_clear(vi); + return(ret); +} + +int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg){ + if(vi){ + codec_setup_info *ci=vi->codec_setup; + highlevel_encode_setup *hi=&ci->hi; + int setp=(number&0xf); /* a read request has a low nibble of 0 */ + + if(setp && hi->set_in_stone)return(OV_EINVAL); + + switch(number){ + + /* now deprecated *****************/ + case OV_ECTL_RATEMANAGE_GET: + { + + struct ovectl_ratemanage_arg *ai= + (struct ovectl_ratemanage_arg *)arg; + + ai->management_active=hi->managed; + ai->bitrate_hard_window=ai->bitrate_av_window= + (double)hi->bitrate_reservoir/vi->rate; + ai->bitrate_av_window_center=1.; + ai->bitrate_hard_min=hi->bitrate_min; + ai->bitrate_hard_max=hi->bitrate_max; + ai->bitrate_av_lo=hi->bitrate_av; + ai->bitrate_av_hi=hi->bitrate_av; + + } + return(0); + + /* now deprecated *****************/ + case OV_ECTL_RATEMANAGE_SET: + { + struct ovectl_ratemanage_arg *ai= + (struct ovectl_ratemanage_arg *)arg; + if(ai==NULL){ + hi->managed=0; + }else{ + hi->managed=ai->management_active; + vorbis_encode_ctl(vi,OV_ECTL_RATEMANAGE_AVG,arg); + vorbis_encode_ctl(vi,OV_ECTL_RATEMANAGE_HARD,arg); + } + } + return 0; + + /* now deprecated *****************/ + case OV_ECTL_RATEMANAGE_AVG: + { + struct ovectl_ratemanage_arg *ai= + (struct ovectl_ratemanage_arg *)arg; + if(ai==NULL){ + hi->bitrate_av=0; + }else{ + hi->bitrate_av=(ai->bitrate_av_lo+ai->bitrate_av_hi)*.5; + } + } + return(0); + /* now deprecated *****************/ + case OV_ECTL_RATEMANAGE_HARD: + { + struct ovectl_ratemanage_arg *ai= + (struct ovectl_ratemanage_arg *)arg; + if(ai==NULL){ + hi->bitrate_min=0; + hi->bitrate_max=0; + }else{ + hi->bitrate_min=ai->bitrate_hard_min; + hi->bitrate_max=ai->bitrate_hard_max; + hi->bitrate_reservoir=ai->bitrate_hard_window* + (hi->bitrate_max+hi->bitrate_min)*.5; + } + if(hi->bitrate_reservoir<128.) + hi->bitrate_reservoir=128.; + } + return(0); + + /* replacement ratemanage interface */ + case OV_ECTL_RATEMANAGE2_GET: + { + struct ovectl_ratemanage2_arg *ai= + (struct ovectl_ratemanage2_arg *)arg; + if(ai==NULL)return OV_EINVAL; + + ai->management_active=hi->managed; + ai->bitrate_limit_min_kbps=hi->bitrate_min/1000; + ai->bitrate_limit_max_kbps=hi->bitrate_max/1000; + ai->bitrate_average_kbps=hi->bitrate_av/1000; + ai->bitrate_average_damping=hi->bitrate_av_damp; + ai->bitrate_limit_reservoir_bits=hi->bitrate_reservoir; + ai->bitrate_limit_reservoir_bias=hi->bitrate_reservoir_bias; + } + return (0); + case OV_ECTL_RATEMANAGE2_SET: + { + struct ovectl_ratemanage2_arg *ai= + (struct ovectl_ratemanage2_arg *)arg; + if(ai==NULL){ + hi->managed=0; + }else{ + /* sanity check; only catch invariant violations */ + if(ai->bitrate_limit_min_kbps>0 && + ai->bitrate_average_kbps>0 && + ai->bitrate_limit_min_kbps>ai->bitrate_average_kbps) + return OV_EINVAL; + + if(ai->bitrate_limit_max_kbps>0 && + ai->bitrate_average_kbps>0 && + ai->bitrate_limit_max_kbpsbitrate_average_kbps) + return OV_EINVAL; + + if(ai->bitrate_limit_min_kbps>0 && + ai->bitrate_limit_max_kbps>0 && + ai->bitrate_limit_min_kbps>ai->bitrate_limit_max_kbps) + return OV_EINVAL; + + if(ai->bitrate_average_damping <= 0.) + return OV_EINVAL; + + if(ai->bitrate_limit_reservoir_bits < 0) + return OV_EINVAL; + + if(ai->bitrate_limit_reservoir_bias < 0.) + return OV_EINVAL; + + if(ai->bitrate_limit_reservoir_bias > 1.) + return OV_EINVAL; + + hi->managed=ai->management_active; + hi->bitrate_min=ai->bitrate_limit_min_kbps * 1000; + hi->bitrate_max=ai->bitrate_limit_max_kbps * 1000; + hi->bitrate_av=ai->bitrate_average_kbps * 1000; + hi->bitrate_av_damp=ai->bitrate_average_damping; + hi->bitrate_reservoir=ai->bitrate_limit_reservoir_bits; + hi->bitrate_reservoir_bias=ai->bitrate_limit_reservoir_bias; + } + } + return 0; + + case OV_ECTL_LOWPASS_GET: + { + double *farg=(double *)arg; + *farg=hi->lowpass_kHz; + } + return(0); + case OV_ECTL_LOWPASS_SET: + { + double *farg=(double *)arg; + hi->lowpass_kHz=*farg; + + if(hi->lowpass_kHz<2.)hi->lowpass_kHz=2.; + if(hi->lowpass_kHz>99.)hi->lowpass_kHz=99.; + hi->lowpass_altered=1; + } + return(0); + case OV_ECTL_IBLOCK_GET: + { + double *farg=(double *)arg; + *farg=hi->impulse_noisetune; + } + return(0); + case OV_ECTL_IBLOCK_SET: + { + double *farg=(double *)arg; + hi->impulse_noisetune=*farg; + + if(hi->impulse_noisetune>0.)hi->impulse_noisetune=0.; + if(hi->impulse_noisetune<-15.)hi->impulse_noisetune=-15.; + } + return(0); + case OV_ECTL_COUPLING_GET: + { + int *iarg=(int *)arg; + *iarg=hi->coupling_p; + } + return(0); + case OV_ECTL_COUPLING_SET: + { + const void *new_template; + double new_base=0.; + int *iarg=(int *)arg; + hi->coupling_p=((*iarg)!=0); + + /* Fetching a new template can alter the base_setting, which + many other parameters are based on. Right now, the only + parameter drawn from the base_setting that can be altered + by an encctl is the lowpass, so that is explictly flagged + to not be overwritten when we fetch a new template and + recompute the dependant settings */ + new_template = get_setup_template(hi->coupling_p?vi->channels:-1, + vi->rate, + hi->req, + hi->managed, + &new_base); + if(!new_template)return OV_EIMPL; + hi->setup=new_template; + hi->base_setting=new_base; + vorbis_encode_setup_setting(vi,vi->channels,vi->rate); + } + return(0); + } + return(OV_EIMPL); + } + return(OV_EINVAL); +} diff --git a/vendor/vorbis/lib/vorbisfile.c b/vendor/vorbis/lib/vorbisfile.c new file mode 100644 index 0000000..9219c2f --- /dev/null +++ b/vendor/vorbis/lib/vorbisfile.c @@ -0,0 +1,2427 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + + ********************************************************************/ + +#include +#include +#include +#include +#include + +#include "vorbis/codec.h" + +/* we don't need or want the static callback symbols here */ +#define OV_EXCLUDE_STATIC_CALLBACKS +#include "vorbis/vorbisfile.h" + +#include "os.h" +#include "misc.h" + +/* A 'chained bitstream' is a Vorbis bitstream that contains more than + one logical bitstream arranged end to end (the only form of Ogg + multiplexing allowed in a Vorbis bitstream; grouping [parallel + multiplexing] is not allowed in Vorbis) */ + +/* A Vorbis file can be played beginning to end (streamed) without + worrying ahead of time about chaining (see decoder_example.c). If + we have the whole file, however, and want random access + (seeking/scrubbing) or desire to know the total length/time of a + file, we need to account for the possibility of chaining. */ + +/* We can handle things a number of ways; we can determine the entire + bitstream structure right off the bat, or find pieces on demand. + This example determines and caches structure for the entire + bitstream, but builds a virtual decoder on the fly when moving + between links in the chain. */ + +/* There are also different ways to implement seeking. Enough + information exists in an Ogg bitstream to seek to + sample-granularity positions in the output. Or, one can seek by + picking some portion of the stream roughly in the desired area if + we only want coarse navigation through the stream. */ + +/************************************************************************* + * Many, many internal helpers. The intention is not to be confusing; + * rampant duplication and monolithic function implementation would be + * harder to understand anyway. The high level functions are last. Begin + * grokking near the end of the file */ + +/* read a little more data from the file/pipe into the ogg_sync framer +*/ +#define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */ +#define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */ + +static long _get_data(OggVorbis_File *vf){ + errno=0; + if(!(vf->callbacks.read_func))return(-1); + if(vf->datasource){ + char *buffer=ogg_sync_buffer(&vf->oy,READSIZE); + long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource); + if(bytes>0)ogg_sync_wrote(&vf->oy,bytes); + if(bytes==0 && errno)return(-1); + return(bytes); + }else + return(0); +} + +/* save a tiny smidge of verbosity to make the code more readable */ +static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ + if(vf->datasource){ + /* only seek if the file position isn't already there */ + if(vf->offset != offset){ + if(!(vf->callbacks.seek_func)|| + (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1) + return OV_EREAD; + vf->offset=offset; + ogg_sync_reset(&vf->oy); + } + }else{ + /* shouldn't happen unless someone writes a broken callback */ + return OV_EFAULT; + } + return 0; +} + +/* The read/seek functions track absolute position within the stream */ + +/* from the head of the stream, get the next page. boundary specifies + if the function is allowed to fetch more data from the stream (and + how much) or only use internally buffered data. + + boundary: -1) unbounded search + 0) read no additional data; use cached only + n) search for a new page beginning for n bytes + + return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD) + n) found a page at absolute offset n */ + +static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, + ogg_int64_t boundary){ + if(boundary>0)boundary+=vf->offset; + while(1){ + long more; + + if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); + more=ogg_sync_pageseek(&vf->oy,og); + + if(more<0){ + /* skipped n bytes */ + vf->offset-=more; + }else{ + if(more==0){ + /* send more paramedics */ + if(!boundary)return(OV_FALSE); + { + long ret=_get_data(vf); + if(ret==0)return(OV_EOF); + if(ret<0)return(OV_EREAD); + } + }else{ + /* got a page. Return the offset at the page beginning, + advance the internal offset past the page end */ + ogg_int64_t ret=vf->offset; + vf->offset+=more; + return(ret); + + } + } + } +} + +/* find the latest page beginning before the passed in position. Much + dirtier than the above as Ogg doesn't have any backward search + linkage. no 'readp' as it will certainly have to read. */ +/* returns offset or OV_EREAD, OV_FAULT */ +static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_int64_t begin,ogg_page *og){ + ogg_int64_t end = begin; + ogg_int64_t ret; + ogg_int64_t offset=-1; + + while(offset==-1){ + begin-=CHUNKSIZE; + if(begin<0) + begin=0; + + ret=_seek_helper(vf,begin); + if(ret)return(ret); + + while(vf->offsetoffset); + if(ret==OV_EREAD)return(OV_EREAD); + if(ret<0){ + break; + }else{ + offset=ret; + } + } + } + + /* In a fully compliant, non-multiplexed stream, we'll still be + holding the last page. In multiplexed (or noncompliant streams), + we will probably have to re-read the last page we saw */ + if(og->header_len==0){ + ret=_seek_helper(vf,offset); + if(ret)return(ret); + + ret=_get_next_page(vf,og,CHUNKSIZE); + if(ret<0) + /* this shouldn't be possible */ + return(OV_EFAULT); + } + + return(offset); +} + +static void _add_serialno(ogg_page *og,long **serialno_list, int *n){ + long s = ogg_page_serialno(og); + (*n)++; + + if(*serialno_list){ + *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n)); + }else{ + *serialno_list = _ogg_malloc(sizeof(**serialno_list)); + } + + (*serialno_list)[(*n)-1] = s; +} + +/* returns nonzero if found */ +static int _lookup_serialno(long s, long *serialno_list, int n){ + if(serialno_list){ + while(n--){ + if(*serialno_list == s) return 1; + serialno_list++; + } + } + return 0; +} + +static int _lookup_page_serialno(ogg_page *og, long *serialno_list, int n){ + long s = ogg_page_serialno(og); + return _lookup_serialno(s,serialno_list,n); +} + +/* performs the same search as _get_prev_page, but prefers pages of + the specified serial number. If a page of the specified serialno is + spotted during the seek-back-and-read-forward, it will return the + info of last page of the matching serial number instead of the very + last page. If no page of the specified serialno is seen, it will + return the info of last page and alter *serialno. */ +static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin, + long *serial_list, int serial_n, + int *serialno, ogg_int64_t *granpos){ + ogg_page og; + ogg_int64_t end=begin; + ogg_int64_t ret; + + ogg_int64_t prefoffset=-1; + ogg_int64_t offset=-1; + ogg_int64_t ret_serialno=-1; + ogg_int64_t ret_gran=-1; + + while(offset==-1){ + begin-=CHUNKSIZE; + if(begin<0) + begin=0; + + ret=_seek_helper(vf,begin); + if(ret)return(ret); + + while(vf->offsetoffset); + if(ret==OV_EREAD)return(OV_EREAD); + if(ret<0){ + break; + }else{ + ret_serialno=ogg_page_serialno(&og); + ret_gran=ogg_page_granulepos(&og); + offset=ret; + + if(ret_serialno == *serialno){ + prefoffset=ret; + *granpos=ret_gran; + } + + if(!_lookup_serialno(ret_serialno,serial_list,serial_n)){ + /* we fell off the end of the link, which means we seeked + back too far and shouldn't have been looking in that link + to begin with. If we found the preferred serial number, + forget that we saw it. */ + prefoffset=-1; + } + } + } + /*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. */ + if(prefoffset>=0)return(prefoffset); + + *serialno = ret_serialno; + *granpos = ret_gran; + return(offset); + +} + +/* uses the local ogg_stream storage in vf; this is important for + non-streaming input sources */ +static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, + long **serialno_list, int *serialno_n, + ogg_page *og_ptr){ + ogg_page og; + ogg_packet op; + int i,ret; + int allbos=0; + + if(!og_ptr){ + ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); + if(llret==OV_EREAD)return(OV_EREAD); + if(llret<0)return(OV_ENOTVORBIS); + og_ptr=&og; + } + + vorbis_info_init(vi); + vorbis_comment_init(vc); + vf->ready_state=OPENED; + + /* extract the serialnos of all BOS pages + the first set of vorbis + headers we see in the link */ + + while(ogg_page_bos(og_ptr)){ + if(serialno_list){ + if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){ + /* a dupe serialnumber in an initial header packet set == invalid stream */ + if(*serialno_list)_ogg_free(*serialno_list); + *serialno_list=0; + *serialno_n=0; + ret=OV_EBADHEADER; + goto bail_header; + } + + _add_serialno(og_ptr,serialno_list,serialno_n); + } + + if(vf->ready_stateos,ogg_page_serialno(og_ptr)); + ogg_stream_pagein(&vf->os,og_ptr); + + if(ogg_stream_packetout(&vf->os,&op) > 0 && + vorbis_synthesis_idheader(&op)){ + /* vorbis header; continue setup */ + vf->ready_state=STREAMSET; + if((ret=vorbis_synthesis_headerin(vi,vc,&op))){ + ret=OV_EBADHEADER; + goto bail_header; + } + } + } + + /* get next page */ + { + ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE); + if(llret==OV_EREAD){ + ret=OV_EREAD; + goto bail_header; + } + if(llret<0){ + ret=OV_ENOTVORBIS; + goto bail_header; + } + + /* if this page also belongs to our vorbis stream, submit it and break */ + if(vf->ready_state==STREAMSET && + vf->os.serialno == ogg_page_serialno(og_ptr)){ + ogg_stream_pagein(&vf->os,og_ptr); + break; + } + } + } + + if(vf->ready_state!=STREAMSET){ + ret = OV_ENOTVORBIS; + goto bail_header; + } + + while(1){ + + i=0; + while(i<2){ /* get a page loop */ + + while(i<2){ /* get a packet loop */ + + int result=ogg_stream_packetout(&vf->os,&op); + if(result==0)break; + if(result==-1){ + ret=OV_EBADHEADER; + goto bail_header; + } + + if((ret=vorbis_synthesis_headerin(vi,vc,&op))) + goto bail_header; + + i++; + } + + while(i<2){ + if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ + ret=OV_EBADHEADER; + goto bail_header; + } + + /* if this page belongs to the correct stream, go parse it */ + if(vf->os.serialno == ogg_page_serialno(og_ptr)){ + ogg_stream_pagein(&vf->os,og_ptr); + break; + } + + /* if we never see the final vorbis headers before the link + ends, abort */ + if(ogg_page_bos(og_ptr)){ + if(allbos){ + ret = OV_EBADHEADER; + goto bail_header; + }else + allbos=1; + } + + /* otherwise, keep looking */ + } + } + + return 0; + } + + bail_header: + vorbis_info_clear(vi); + vorbis_comment_clear(vc); + vf->ready_state=OPENED; + + return ret; +} + +/* Starting from current cursor position, get initial PCM offset of + next page. Consumes the page in the process without decoding + audio, however this is only called during stream parsing upon + seekable open. */ +static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ + ogg_page og; + ogg_int64_t accumulated=0; + long lastblock=-1; + int result; + int serialno = vf->os.serialno; + + while(1){ + ogg_packet op; + if(_get_next_page(vf,&og,-1)<0) + break; /* should not be possible unless the file is truncated/mangled */ + + if(ogg_page_bos(&og)) break; + if(ogg_page_serialno(&og)!=serialno) continue; + + /* count blocksizes of all frames in the page */ + ogg_stream_pagein(&vf->os,&og); + while((result=ogg_stream_packetout(&vf->os,&op))){ + if(result>0){ /* ignore holes */ + long thisblock=vorbis_packet_blocksize(vi,&op); + if(thisblock>=0){ + if(lastblock!=-1) + accumulated+=(lastblock+thisblock)>>2; + lastblock=thisblock; + } + } + } + + if(ogg_page_granulepos(&og)!=-1){ + /* pcm offset of last packet on the first audio page */ + accumulated= ogg_page_granulepos(&og)-accumulated; + break; + } + } + + /* less than zero? Either a corrupt file or a stream with samples + trimmed off the beginning, a normal occurrence; in both cases set + the offset to zero */ + if(accumulated<0)accumulated=0; + + return accumulated; +} + +/* finds each bitstream link one at a time using a bisection search + (has to begin by knowing the offset of the lb's initial page). + Recurses for each link so it can alloc the link storage after + finding them all, then unroll and fill the cache at the same time */ +static int _bisect_forward_serialno(OggVorbis_File *vf, + ogg_int64_t begin, + ogg_int64_t searched, + ogg_int64_t end, + ogg_int64_t endgran, + int endserial, + long *currentno_list, + int currentnos, + long m){ + ogg_int64_t pcmoffset; + ogg_int64_t dataoffset=searched; + ogg_int64_t endsearched=end; + ogg_int64_t next=end; + ogg_int64_t searchgran=-1; + ogg_page og; + ogg_int64_t ret,last; + int serialno = vf->os.serialno; + + /* invariants: + we have the headers and serialnos for the link beginning at 'begin' + we have the offset and granpos of the last page in the file (potentially + not a page we care about) + */ + + /* Is the last page in our list of current serialnumbers? */ + if(_lookup_serialno(endserial,currentno_list,currentnos)){ + + /* last page is in the starting serialno list, so we've bisected + down to (or just started with) a single link. Now we need to + find the last vorbis page belonging to the first vorbis stream + for this link. */ + searched = end; + while(endserial != serialno){ + endserial = serialno; + searched=_get_prev_page_serial(vf,searched,currentno_list,currentnos,&endserial,&endgran); + } + + vf->links=m+1; + if(vf->offsets)_ogg_free(vf->offsets); + if(vf->serialnos)_ogg_free(vf->serialnos); + if(vf->dataoffsets)_ogg_free(vf->dataoffsets); + + vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets)); + vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi)); + vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc)); + vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos)); + vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets)); + vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths)); + + vf->offsets[m+1]=end; + vf->offsets[m]=begin; + vf->pcmlengths[m*2+1]=(endgran<0?0:endgran); + + }else{ + + /* last page is not in the starting stream's serial number list, + so we have multiple links. Find where the stream that begins + our bisection ends. */ + + long *next_serialno_list=NULL; + int next_serialnos=0; + vorbis_info vi; + vorbis_comment vc; + int testserial = serialno+1; + + /* the below guards against garbage seperating the last and + first pages of two links. */ + while(searched=0)next=last; + }else{ + searched=vf->offset; + } + } + + /* Bisection point found */ + /* for the time being, fetch end PCM offset the simple way */ + searched = next; + while(testserial != serialno){ + testserial = serialno; + searched = _get_prev_page_serial(vf,searched,currentno_list,currentnos,&testserial,&searchgran); + } + + ret=_seek_helper(vf,next); + if(ret)return(ret); + + ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL); + if(ret)return(ret); + serialno = vf->os.serialno; + dataoffset = vf->offset; + + /* this will consume a page, however the next bisection always + starts with a raw seek */ + pcmoffset = _initial_pcmoffset(vf,&vi); + + ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial, + next_serialno_list,next_serialnos,m+1); + if(ret)return(ret); + + if(next_serialno_list)_ogg_free(next_serialno_list); + + vf->offsets[m+1]=next; + vf->serialnos[m+1]=serialno; + vf->dataoffsets[m+1]=dataoffset; + + vf->vi[m+1]=vi; + vf->vc[m+1]=vc; + + vf->pcmlengths[m*2+1]=searchgran; + vf->pcmlengths[m*2+2]=pcmoffset; + vf->pcmlengths[m*2+3]-=pcmoffset; + if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0; + } + return(0); +} + +static int _make_decode_ready(OggVorbis_File *vf){ + if(vf->ready_state>STREAMSET)return 0; + if(vf->ready_stateseekable){ + if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link)) + return OV_EBADLINK; + }else{ + if(vorbis_synthesis_init(&vf->vd,vf->vi)) + return OV_EBADLINK; + } + vorbis_block_init(&vf->vd,&vf->vb); + vf->ready_state=INITSET; + vf->bittrack=0.f; + vf->samptrack=0.f; + return 0; +} + +static int _open_seekable2(OggVorbis_File *vf){ + ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1; + int endserial=vf->os.serialno; + int serialno=vf->os.serialno; + + /* we're partially open and have a first link header state in + storage in vf */ + + /* fetch initial PCM offset */ + ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi); + + /* we can seek, so set out learning all about this file */ + if(vf->callbacks.seek_func && vf->callbacks.tell_func){ + (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); + vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); + }else{ + vf->offset=vf->end=-1; + } + + /* If seek_func is implemented, tell_func must also be implemented */ + if(vf->end==-1) return(OV_EINVAL); + + /* Get the offset of the last page of the physical bitstream, or, if + we're lucky the last vorbis page of this link as most OggVorbis + files will contain a single logical bitstream */ + end=_get_prev_page_serial(vf,vf->end,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran); + if(end<0)return(end); + + /* now determine bitstream structure recursively */ + if(_bisect_forward_serialno(vf,0,dataoffset,end,endgran,endserial, + vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD); + + vf->offsets[0]=0; + vf->serialnos[0]=serialno; + vf->dataoffsets[0]=dataoffset; + vf->pcmlengths[0]=pcmoffset; + vf->pcmlengths[1]-=pcmoffset; + if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0; + + return(ov_raw_seek(vf,dataoffset)); +} + +/* clear out the current logical bitstream decoder */ +static void _decode_clear(OggVorbis_File *vf){ + vorbis_dsp_clear(&vf->vd); + vorbis_block_clear(&vf->vb); + vf->ready_state=OPENED; +} + +/* fetch and process a packet. Handles the case where we're at a + bitstream boundary and dumps the decoding machine. If the decoding + machine is unloaded, it loads it. It also keeps pcm_offset up to + date (seek and read both use this. seek uses a special hack with + readp). + + return: <0) error, OV_HOLE (lost packet) or OV_EOF + 0) need more data (only if readp==0) + 1) got a packet +*/ + +static int _fetch_and_process_packet(OggVorbis_File *vf, + ogg_packet *op_in, + int readp, + int spanp){ + ogg_page og; + + /* handle one packet. Try to fetch it from current stream state */ + /* extract packets from page */ + while(1){ + + if(vf->ready_state==STREAMSET){ + int ret=_make_decode_ready(vf); + if(ret<0)return ret; + } + + /* process a packet if we can. */ + + if(vf->ready_state==INITSET){ + int hs=vorbis_synthesis_halfrate_p(vf->vi); + + while(1) { + ogg_packet op; + ogg_packet *op_ptr=(op_in?op_in:&op); + int result=ogg_stream_packetout(&vf->os,op_ptr); + ogg_int64_t granulepos; + + op_in=NULL; + if(result==-1)return(OV_HOLE); /* hole in the data. */ + if(result>0){ + /* got a packet. process it */ + granulepos=op_ptr->granulepos; + if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy + header handling. The + header packets aren't + audio, so if/when we + submit them, + vorbis_synthesis will + reject them */ + + /* suck in the synthesis data and track bitrate */ + { + int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); + /* for proper use of libvorbis within libvorbisfile, + oldsamples will always be zero. */ + if(oldsamples)return(OV_EFAULT); + + vorbis_synthesis_blockin(&vf->vd,&vf->vb); + vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<bittrack+=op_ptr->bytes*8; + } + + /* update the pcm offset. */ + if(granulepos!=-1 && !op_ptr->e_o_s){ + int link=(vf->seekable?vf->current_link:0); + int i,samples; + + /* this packet has a pcm_offset on it (the last packet + completed on a page carries the offset) After processing + (above), we know the pcm position of the *last* sample + ready to be returned. Find the offset of the *first* + + As an aside, this trick is inaccurate if we begin + reading anew right at the last page; the end-of-stream + granulepos declares the last frame in the stream, and the + last packet of the last page may be a partial frame. + So, we need a previous granulepos from an in-sequence page + to have a reference point. Thus the !op_ptr->e_o_s clause + above */ + + if(vf->seekable && link>0) + granulepos-=vf->pcmlengths[link*2]; + if(granulepos<0)granulepos=0; /* actually, this + shouldn't be possible + here unless the stream + is very broken */ + + samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<pcmlengths[i*2+1]; + vf->pcm_offset=granulepos; + } + return(1); + } + } + else + break; + } + } + + if(vf->ready_state>=OPENED){ + ogg_int64_t ret; + + while(1){ + /* the loop is not strictly necessary, but there's no sense in + doing the extra checks of the larger loop for the common + case in a multiplexed bistream where the page is simply + part of a different logical bitstream; keep reading until + we get one with the correct serialno */ + + if(!readp)return(0); + if((ret=_get_next_page(vf,&og,-1))<0){ + return(OV_EOF); /* eof. leave unitialized */ + } + + /* bitrate tracking; add the header's bytes here, the body bytes + are done by packet above */ + vf->bittrack+=og.header_len*8; + + if(vf->ready_state==INITSET){ + if(vf->current_serialno!=ogg_page_serialno(&og)){ + + /* two possibilities: + 1) our decoding just traversed a bitstream boundary + 2) another stream is multiplexed into this logical section */ + + if(ogg_page_bos(&og)){ + /* boundary case */ + if(!spanp) + return(OV_EOF); + + _decode_clear(vf); + + if(!vf->seekable){ + vorbis_info_clear(vf->vi); + vorbis_comment_clear(vf->vc); + } + break; + + }else + continue; /* possibility #2 */ + } + } + + break; + } + } + + /* Do we need to load a new machine before submitting the page? */ + /* This is different in the seekable and non-seekable cases. + + In the seekable case, we already have all the header + information loaded and cached; we just initialize the machine + with it and continue on our merry way. + + In the non-seekable (streaming) case, we'll only be at a + boundary if we just left the previous logical bitstream and + we're now nominally at the header of the next bitstream + */ + + if(vf->ready_state!=INITSET){ + int link; + + if(vf->ready_stateseekable){ + long serialno = ogg_page_serialno(&og); + + /* match the serialno to bitstream section. We use this rather than + offset positions to avoid problems near logical bitstream + boundaries */ + + for(link=0;linklinks;link++) + if(vf->serialnos[link]==serialno)break; + + if(link==vf->links) continue; /* not the desired Vorbis + bitstream section; keep + trying */ + + vf->current_serialno=serialno; + vf->current_link=link; + + ogg_stream_reset_serialno(&vf->os,vf->current_serialno); + vf->ready_state=STREAMSET; + + }else{ + /* we're streaming */ + /* fetch the three header packets, build the info struct */ + + int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og); + if(ret)return(ret); + vf->current_serialno=vf->os.serialno; + vf->current_link++; + link=0; + } + } + } + + /* the buffered page is the data we want, and we're ready for it; + add it to the stream state */ + ogg_stream_pagein(&vf->os,&og); + + } +} + +/* if, eg, 64 bit stdio is configured by default, this will build with + fseek64 */ +static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ + if(f==NULL)return(-1); + return fseek(f,off,whence); +} + +static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, + long ibytes, ov_callbacks callbacks){ + int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1); + long *serialno_list=NULL; + int serialno_list_size=0; + int ret; + + memset(vf,0,sizeof(*vf)); + vf->datasource=f; + vf->callbacks = callbacks; + + /* init the framing state */ + ogg_sync_init(&vf->oy); + + /* perhaps some data was previously read into a buffer for testing + against other stream types. Allow initialization from this + previously read data (especially as we may be reading from a + non-seekable stream) */ + if(initial){ + char *buffer=ogg_sync_buffer(&vf->oy,ibytes); + memcpy(buffer,initial,ibytes); + ogg_sync_wrote(&vf->oy,ibytes); + } + + /* can we seek? Stevens suggests the seek test was portable */ + if(offsettest!=-1)vf->seekable=1; + + /* No seeking yet; Set up a 'single' (current) logical bitstream + entry for partial open */ + vf->links=1; + vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi)); + vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); + ogg_stream_init(&vf->os,-1); /* fill in the serialno later */ + + /* Fetch all BOS pages, store the vorbis header and all seen serial + numbers, load subsequent vorbis setup headers */ + if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){ + vf->datasource=NULL; + ov_clear(vf); + }else{ + /* serial number list for first link needs to be held somewhere + for second stage of seekable stream open; this saves having to + seek/reread first link's serialnumber data then. */ + vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos)); + vf->serialnos[0]=vf->current_serialno=vf->os.serialno; + vf->serialnos[1]=serialno_list_size; + memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos)); + + vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets)); + vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets)); + vf->offsets[0]=0; + vf->dataoffsets[0]=vf->offset; + + vf->ready_state=PARTOPEN; + } + if(serialno_list)_ogg_free(serialno_list); + return(ret); +} + +static int _ov_open2(OggVorbis_File *vf){ + if(vf->ready_state != PARTOPEN) return OV_EINVAL; + vf->ready_state=OPENED; + if(vf->seekable){ + int ret=_open_seekable2(vf); + if(ret){ + vf->datasource=NULL; + ov_clear(vf); + } + return(ret); + }else + vf->ready_state=STREAMSET; + + return 0; +} + + +/* clear out the OggVorbis_File struct */ +int ov_clear(OggVorbis_File *vf){ + if(vf){ + vorbis_block_clear(&vf->vb); + vorbis_dsp_clear(&vf->vd); + ogg_stream_clear(&vf->os); + + if(vf->vi && vf->links){ + int i; + for(i=0;ilinks;i++){ + vorbis_info_clear(vf->vi+i); + vorbis_comment_clear(vf->vc+i); + } + _ogg_free(vf->vi); + _ogg_free(vf->vc); + } + if(vf->dataoffsets)_ogg_free(vf->dataoffsets); + if(vf->pcmlengths)_ogg_free(vf->pcmlengths); + if(vf->serialnos)_ogg_free(vf->serialnos); + if(vf->offsets)_ogg_free(vf->offsets); + ogg_sync_clear(&vf->oy); + if(vf->datasource && vf->callbacks.close_func) + (vf->callbacks.close_func)(vf->datasource); + memset(vf,0,sizeof(*vf)); + } +#ifdef DEBUG_LEAKS + _VDBG_dump(); +#endif + return(0); +} + +/* inspects the OggVorbis file and finds/documents all the logical + bitstreams contained in it. Tries to be tolerant of logical + bitstream sections that are truncated/woogie. + + return: -1) error + 0) OK +*/ + +int ov_open_callbacks(void *f,OggVorbis_File *vf, + const char *initial,long ibytes,ov_callbacks callbacks){ + int ret=_ov_open1(f,vf,initial,ibytes,callbacks); + if(ret)return ret; + return _ov_open2(vf); +} + +int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ + ov_callbacks callbacks = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, + (int (*)(void *)) fclose, + (long (*)(void *)) ftell + }; + + return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); +} + +int ov_fopen(const char *path,OggVorbis_File *vf){ + int ret; + FILE *f = fopen(path,"rb"); + if(!f) return -1; + + ret = ov_open(f,vf,NULL,0); + if(ret) fclose(f); + return ret; +} + + +/* cheap hack for game usage where downsampling is desirable; there's + no need for SRC as we can just do it cheaply in libvorbis. */ + +int ov_halfrate(OggVorbis_File *vf,int flag){ + int i; + if(vf->vi==NULL)return OV_EINVAL; + if(vf->ready_state>STREAMSET){ + /* clear out stream state; dumping the decode machine is needed to + reinit the MDCT lookups. */ + vorbis_dsp_clear(&vf->vd); + vorbis_block_clear(&vf->vb); + vf->ready_state=STREAMSET; + if(vf->pcm_offset>=0){ + ogg_int64_t pos=vf->pcm_offset; + vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */ + ov_pcm_seek(vf,pos); + } + } + + for(i=0;ilinks;i++){ + if(vorbis_synthesis_halfrate(vf->vi+i,flag)){ + if(flag) ov_halfrate(vf,0); + return OV_EINVAL; + } + } + return 0; +} + +int ov_halfrate_p(OggVorbis_File *vf){ + if(vf->vi==NULL)return OV_EINVAL; + return vorbis_synthesis_halfrate_p(vf->vi); +} + +/* Only partially open the vorbis file; test for Vorbisness, and load + the headers for the first chain. Do not seek (although test for + seekability). Use ov_test_open to finish opening the file, else + ov_clear to close/free it. Same return codes as open. + + Note that vorbisfile does _not_ take ownership of the file if the + call fails; the calling applicaiton is responsible for closing the file + if this call returns an error. */ + +int ov_test_callbacks(void *f,OggVorbis_File *vf, + const char *initial,long ibytes,ov_callbacks callbacks) +{ + return _ov_open1(f,vf,initial,ibytes,callbacks); +} + +int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ + ov_callbacks callbacks = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, + (int (*)(void *)) fclose, + (long (*)(void *)) ftell + }; + + return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks); +} + +int ov_test_open(OggVorbis_File *vf){ + if(vf->ready_state!=PARTOPEN)return(OV_EINVAL); + return _ov_open2(vf); +} + +/* How many logical bitstreams in this physical bitstream? */ +long ov_streams(OggVorbis_File *vf){ + return vf->links; +} + +/* Is the FILE * associated with vf seekable? */ +long ov_seekable(OggVorbis_File *vf){ + return vf->seekable; +} + +/* returns the bitrate for a given logical bitstream or the entire + physical bitstream. If the file is open for random access, it will + find the *actual* average bitrate. If the file is streaming, it + returns the nominal bitrate (if set) else the average of the + upper/lower bounds (if set) else -1 (unset). + + If you want the actual bitrate field settings, get them from the + vorbis_info structs */ + +long ov_bitrate(OggVorbis_File *vf,int i){ + if(vf->ready_state=vf->links)return(OV_EINVAL); + if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); + if(i<0){ + ogg_int64_t bits=0; + int i; + float br; + for(i=0;ilinks;i++) + bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; + /* This once read: return(rint(bits/ov_time_total(vf,-1))); + * gcc 3.x on x86 miscompiled this at optimisation level 2 and above, + * so this is slightly transformed to make it work. + */ + br = bits/ov_time_total(vf,-1); + return(rint(br)); + }else{ + if(vf->seekable){ + /* return the actual bitrate */ + return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i))); + }else{ + /* return nominal if set */ + if(vf->vi[i].bitrate_nominal>0){ + return vf->vi[i].bitrate_nominal; + }else{ + if(vf->vi[i].bitrate_upper>0){ + if(vf->vi[i].bitrate_lower>0){ + return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; + }else{ + return vf->vi[i].bitrate_upper; + } + } + return(OV_FALSE); + } + } + } +} + +/* returns the actual bitrate since last call. returns -1 if no + additional data to offer since last call (or at beginning of stream), + EINVAL if stream is only partially open +*/ +long ov_bitrate_instant(OggVorbis_File *vf){ + int link=(vf->seekable?vf->current_link:0); + long ret; + if(vf->ready_statesamptrack==0)return(OV_FALSE); + ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5; + vf->bittrack=0.f; + vf->samptrack=0.f; + return(ret); +} + +/* Guess */ +long ov_serialnumber(OggVorbis_File *vf,int i){ + if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1)); + if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); + if(i<0){ + return(vf->current_serialno); + }else{ + return(vf->serialnos[i]); + } +} + +/* returns: total raw (compressed) length of content if i==-1 + raw (compressed) length of that logical bitstream for i==0 to n + OV_EINVAL if the stream is not seekable (we can't know the length) + or if stream is only partially open +*/ +ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); + if(i<0){ + ogg_int64_t acc=0; + int i; + for(i=0;ilinks;i++) + acc+=ov_raw_total(vf,i); + return(acc); + }else{ + return(vf->offsets[i+1]-vf->offsets[i]); + } +} + +/* returns: total PCM length (samples) of content if i==-1 PCM length + (samples) of that logical bitstream for i==0 to n + OV_EINVAL if the stream is not seekable (we can't know the + length) or only partially open +*/ +ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); + if(i<0){ + ogg_int64_t acc=0; + int i; + for(i=0;ilinks;i++) + acc+=ov_pcm_total(vf,i); + return(acc); + }else{ + return(vf->pcmlengths[i*2+1]); + } +} + +/* returns: total seconds of content if i==-1 + seconds in that logical bitstream for i==0 to n + OV_EINVAL if the stream is not seekable (we can't know the + length) or only partially open +*/ +double ov_time_total(OggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); + if(i<0){ + double acc=0; + int i; + for(i=0;ilinks;i++) + acc+=ov_time_total(vf,i); + return(acc); + }else{ + return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate); + } +} + +/* seek to an offset relative to the *compressed* data. This also + scans packets to update the PCM cursor. It will cross a logical + bitstream boundary, but only if it can't get any packets out of the + tail of the bitstream we seek to (so no surprises). + + returns zero on success, nonzero on failure */ + +int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ + ogg_stream_state work_os; + + if(vf->ready_stateseekable) + return(OV_ENOSEEK); /* don't dump machine if we can't seek */ + + if(pos<0 || pos>vf->end)return(OV_EINVAL); + + /* is the seek position outside our current link [if any]? */ + if(vf->ready_state>=STREAMSET){ + if(posoffsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1]) + _decode_clear(vf); /* clear out stream state */ + } + + /* don't yet clear out decoding machine (if it's initialized), in + the case we're in the same link. Restart the decode lapping, and + let _fetch_and_process_packet deal with a potential bitstream + boundary */ + vf->pcm_offset=-1; + ogg_stream_reset_serialno(&vf->os, + vf->current_serialno); /* must set serialno */ + vorbis_synthesis_restart(&vf->vd); + + 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 + with a granulepos. That's not equivalent behavior to beginning + decoding as immediately after the seek position as possible. + + So, a hack. We use two stream states; a local scratch state and + the shared vf->os stream state. We use the local state to + scan, and the shared state as a buffer for later decode. + + Unfortuantely, on the last page we still advance to last packet + because the granulepos on the last page is not necessarily on a + packet boundary, and we need to make sure the granpos is + correct. + */ + + { + ogg_page og; + ogg_packet op; + int lastblock=0; + int accblock=0; + int thisblock=0; + int lastflag=0; + int firstflag=0; + ogg_int64_t pagepos=-1; + + ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */ + ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE + return from not necessarily + starting from the beginning */ + + while(1){ + if(vf->ready_state>=STREAMSET){ + /* snarf/scan a packet if we can */ + int result=ogg_stream_packetout(&work_os,&op); + + if(result>0){ + + if(vf->vi[vf->current_link].codec_setup){ + thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); + if(thisblock<0){ + ogg_stream_packetout(&vf->os,NULL); + thisblock=0; + }else{ + + /* We can't get a guaranteed correct pcm position out of the + last page in a stream because it might have a 'short' + granpos, which can only be detected in the presence of a + preceding page. However, if the last page is also the first + page, the granpos rules of a first page take precedence. Not + only that, but for first==last, the EOS page must be treated + as if its a normal first page for the stream to open/play. */ + if(lastflag && !firstflag) + ogg_stream_packetout(&vf->os,NULL); + else + if(lastblock)accblock+=(lastblock+thisblock)>>2; + } + + if(op.granulepos!=-1){ + int i,link=vf->current_link; + ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; + if(granulepos<0)granulepos=0; + + for(i=0;ipcmlengths[i*2+1]; + vf->pcm_offset=granulepos-accblock; + if(vf->pcm_offset<0)vf->pcm_offset=0; + break; + } + lastblock=thisblock; + continue; + }else + ogg_stream_packetout(&vf->os,NULL); + } + } + + if(!lastblock){ + pagepos=_get_next_page(vf,&og,-1); + if(pagepos<0){ + vf->pcm_offset=ov_pcm_total(vf,-1); + break; + } + }else{ + /* huh? Bogus stream with packets but no granulepos */ + vf->pcm_offset=-1; + break; + } + + /* has our decoding just traversed a bitstream boundary? */ + if(vf->ready_state>=STREAMSET){ + if(vf->current_serialno!=ogg_page_serialno(&og)){ + + /* two possibilities: + 1) our decoding just traversed a bitstream boundary + 2) another stream is multiplexed into this logical section? */ + + if(ogg_page_bos(&og)){ + /* we traversed */ + _decode_clear(vf); /* clear out stream state */ + ogg_stream_clear(&work_os); + } /* else, do nothing; next loop will scoop another page */ + } + } + + if(vf->ready_statelinks;link++) + if(vf->serialnos[link]==serialno)break; + + if(link==vf->links) continue; /* not the desired Vorbis + bitstream section; keep + trying */ + vf->current_link=link; + vf->current_serialno=serialno; + ogg_stream_reset_serialno(&vf->os,serialno); + ogg_stream_reset_serialno(&work_os,serialno); + vf->ready_state=STREAMSET; + firstflag=(pagepos<=vf->dataoffsets[link]); + } + + ogg_stream_pagein(&vf->os,&og); + ogg_stream_pagein(&work_os,&og); + lastflag=ogg_page_eos(&og); + + } + } + + ogg_stream_clear(&work_os); + vf->bittrack=0.f; + vf->samptrack=0.f; + return(0); +} + +/* Page granularity seek (faster than sample granularity because we + don't do the last bit of decode to find a specific sample). + + Seek to the last [granule marked] page preceding the specified pos + location, such that decoding past the returned point will quickly + arrive at the requested position. */ +int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ + int link=-1; + ogg_int64_t result=0; + ogg_int64_t total=ov_pcm_total(vf,-1); + + if(vf->ready_stateseekable)return(OV_ENOSEEK); + + if(pos<0 || pos>total)return(OV_EINVAL); + + /* which bitstream section does this pcm offset occur in? */ + for(link=vf->links-1;link>=0;link--){ + total-=vf->pcmlengths[link*2+1]; + if(pos>=total)break; + } + + /* Search within the logical bitstream for the page with the highest + pcm_pos preceding pos. If we're looking for a position on the + first page, bisection will halt without finding our position as + it's before the first explicit granulepos fencepost. That case is + handled separately below. + + There is a danger here; missing pages or incorrect frame number + information in the bitstream could make our task impossible. + Account for that (it would be an error condition) */ + + /* new search algorithm originally by HB (Nicholas Vinen) */ + + { + ogg_int64_t end=vf->offsets[link+1]; + ogg_int64_t begin=vf->dataoffsets[link]; + ogg_int64_t begintime = vf->pcmlengths[link*2]; + ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; + ogg_int64_t target=pos-total+begintime; + ogg_int64_t best=-1; + int got_page=0; + + ogg_page og; + + /* if we have only one page, there will be no bisection. Grab the page here */ + if(begin==end){ + result=_seek_helper(vf,begin); + if(result) goto seek_error; + + result=_get_next_page(vf,&og,1); + if(result<0) goto seek_error; + + got_page=1; + } + + /* bisection loop */ + while(beginoffset); + if(result==OV_EREAD) goto seek_error; + if(result<0){ + /* there is no next page! */ + if(bisect<=begin+1) + /* No bisection left to perform. We've either found the + best candidate already or failed. Exit loop. */ + end=begin; + else{ + /* We tried to load a fraction of the last page; back up a + bit and try to get the whole last page */ + if(bisect==0) goto seek_error; + bisect-=CHUNKSIZE; + + /* don't repeat/loop on a read we've already performed */ + if(bisect<=begin)bisect=begin+1; + + /* seek and cntinue bisection */ + result=_seek_helper(vf,bisect); + if(result) goto seek_error; + } + }else{ + ogg_int64_t granulepos; + got_page=1; + + /* got a page. analyze it */ + /* only consider pages from primary vorbis stream */ + if(ogg_page_serialno(&og)!=vf->serialnos[link]) + continue; + + /* only consider pages with the granulepos set */ + granulepos=ogg_page_granulepos(&og); + if(granulepos==-1)continue; + + if(granuleposoffset; /* raw offset of next page */ + begintime=granulepos; + + /* if we're before our target but within a short distance, + don't bisect; read forward */ + if(target-begintime>44100)break; + + bisect=begin; /* *not* begin + 1 as above */ + }else{ + + /* This is one of our pages, but the granpos is + post-target; it is not a bisection return + candidate. (The only way we'd use it is if it's the + first page in the stream; we handle that case later + outside the bisection) */ + if(bisect<=begin+1){ + /* No bisection left to perform. We've either found the + best candidate already or failed. Exit loop. */ + end=begin; + }else{ + if(end==vf->offset){ + /* bisection read to the end; use the known page + boundary (result) to update bisection, back up a + little bit, and try again */ + end=result; + bisect-=CHUNKSIZE; + if(bisect<=begin)bisect=begin+1; + result=_seek_helper(vf,bisect); + if(result) goto seek_error; + }else{ + /* Normal bisection */ + end=bisect; + endtime=granulepos; + break; + } + } + } + } + } + } + + /* Out of bisection: did it 'fail?' */ + if(best == -1){ + + /* Check the 'looking for data in first page' special case; + bisection would 'fail' because our search target was before the + first PCM granule position fencepost. */ + + if(got_page && + begin == vf->dataoffsets[link] && + ogg_page_serialno(&og)==vf->serialnos[link]){ + + /* Yes, this is the beginning-of-stream case. We already have + our page, right at the beginning of PCM data. Set state + and return. */ + + vf->pcm_offset=total; + + if(link!=vf->current_link){ + /* Different link; dump entire decode machine */ + _decode_clear(vf); + + vf->current_link=link; + vf->current_serialno=vf->serialnos[link]; + vf->ready_state=STREAMSET; + + }else{ + vorbis_synthesis_restart(&vf->vd); + } + + ogg_stream_reset_serialno(&vf->os,vf->current_serialno); + ogg_stream_pagein(&vf->os,&og); + + }else + goto seek_error; + + }else{ + + /* Bisection found our page. seek to it, update pcm offset. Easier case than + raw_seek, don't keep packets preceding granulepos. */ + + ogg_page og; + ogg_packet op; + + /* seek */ + result=_seek_helper(vf,best); + vf->pcm_offset=-1; + if(result) goto seek_error; + result=_get_next_page(vf,&og,-1); + if(result<0) goto seek_error; + + if(link!=vf->current_link){ + /* Different link; dump entire decode machine */ + _decode_clear(vf); + + vf->current_link=link; + vf->current_serialno=vf->serialnos[link]; + vf->ready_state=STREAMSET; + + }else{ + vorbis_synthesis_restart(&vf->vd); + } + + ogg_stream_reset_serialno(&vf->os,vf->current_serialno); + ogg_stream_pagein(&vf->os,&og); + + /* pull out all but last packet; the one with granulepos */ + while(1){ + result=ogg_stream_packetpeek(&vf->os,&op); + if(result==0){ + /* No packet returned; we exited the bisection with 'best' + pointing to a page with a granule position, so the packet + finishing this page ('best') originated on a preceding + page. Keep fetching previous pages until we get one with + a granulepos or without the 'continued' flag set. Then + just use raw_seek for simplicity. */ + /* Do not rewind past the beginning of link data; if we do, + it's either a bug or a broken stream */ + result=best; + while(result>vf->dataoffsets[link]){ + result=_get_prev_page(vf,result,&og); + if(result<0) goto seek_error; + if(ogg_page_serialno(&og)==vf->current_serialno && + (ogg_page_granulepos(&og)>-1 || + !ogg_page_continued(&og))){ + return ov_raw_seek(vf,result); + } + } + } + if(result<0){ + result = OV_EBADPACKET; + goto seek_error; + } + if(op.granulepos!=-1){ + vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; + if(vf->pcm_offset<0)vf->pcm_offset=0; + vf->pcm_offset+=total; + break; + }else + result=ogg_stream_packetout(&vf->os,NULL); + } + } + } + + /* verify result */ + if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){ + result=OV_EFAULT; + goto seek_error; + } + vf->bittrack=0.f; + vf->samptrack=0.f; + return(0); + + seek_error: + /* dump machine so we're in a known state */ + vf->pcm_offset=-1; + _decode_clear(vf); + return (int)result; +} + +/* seek to a sample offset relative to the decompressed pcm stream + returns zero on success, nonzero on failure */ + +int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ + int thisblock,lastblock=0; + int ret=ov_pcm_seek_page(vf,pos); + if(ret<0)return(ret); + if((ret=_make_decode_ready(vf)))return ret; + + /* discard leading packets we don't need for the lapping of the + position we want; don't decode them */ + + while(1){ + ogg_packet op; + ogg_page og; + + int ret=ogg_stream_packetpeek(&vf->os,&op); + if(ret>0){ + thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); + if(thisblock<0){ + ogg_stream_packetout(&vf->os,NULL); + continue; /* non audio packet */ + } + if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2; + + if(vf->pcm_offset+((thisblock+ + vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break; + + /* remove the packet from packet queue and track its granulepos */ + ogg_stream_packetout(&vf->os,NULL); + vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with + only tracking, no + pcm_decode */ + vorbis_synthesis_blockin(&vf->vd,&vf->vb); + + /* end of logical stream case is hard, especially with exact + length positioning. */ + + if(op.granulepos>-1){ + int i; + /* always believe the stream markers */ + vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; + if(vf->pcm_offset<0)vf->pcm_offset=0; + for(i=0;icurrent_link;i++) + vf->pcm_offset+=vf->pcmlengths[i*2+1]; + } + + lastblock=thisblock; + + }else{ + if(ret<0 && ret!=OV_HOLE)break; + + /* suck in a new page */ + if(_get_next_page(vf,&og,-1)<0)break; + if(ogg_page_bos(&og))_decode_clear(vf); + + if(vf->ready_statelinks;link++) + if(vf->serialnos[link]==serialno)break; + if(link==vf->links) continue; + vf->current_link=link; + + vf->ready_state=STREAMSET; + vf->current_serialno=ogg_page_serialno(&og); + ogg_stream_reset_serialno(&vf->os,serialno); + ret=_make_decode_ready(vf); + if(ret)return ret; + lastblock=0; + } + + ogg_stream_pagein(&vf->os,&og); + } + } + + vf->bittrack=0.f; + vf->samptrack=0.f; + /* discard samples until we reach the desired position. Crossing a + logical bitstream boundary with abandon is OK. */ + { + /* note that halfrate could be set differently in each link, but + vorbisfile encoforces all links are set or unset */ + int hs=vorbis_synthesis_halfrate_p(vf->vi); + while(vf->pcm_offset<((pos>>hs)<pcm_offset)>>hs; + long samples=vorbis_synthesis_pcmout(&vf->vd,NULL); + + if(samples>target)samples=target; + vorbis_synthesis_read(&vf->vd,samples); + vf->pcm_offset+=samples<pcm_offset=ov_pcm_total(vf,-1); /* eof */ + } + } + return 0; +} + +/* seek to a playback time relative to the decompressed pcm stream + returns zero on success, nonzero on failure */ +int ov_time_seek(OggVorbis_File *vf,double seconds){ + /* translate time to PCM position and call ov_pcm_seek */ + + int link=-1; + ogg_int64_t pcm_total=0; + double time_total=0.; + + if(vf->ready_stateseekable)return(OV_ENOSEEK); + if(seconds<0)return(OV_EINVAL); + + /* which bitstream section does this time offset occur in? */ + for(link=0;linklinks;link++){ + double addsec = ov_time_total(vf,link); + if(secondspcmlengths[link*2+1]; + } + + if(link==vf->links)return(OV_EINVAL); + + /* enough information to convert time offset to pcm offset */ + { + ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate; + return(ov_pcm_seek(vf,target)); + } +} + +/* page-granularity version of ov_time_seek + returns zero on success, nonzero on failure */ +int ov_time_seek_page(OggVorbis_File *vf,double seconds){ + /* translate time to PCM position and call ov_pcm_seek */ + + int link=-1; + ogg_int64_t pcm_total=0; + double time_total=0.; + + if(vf->ready_stateseekable)return(OV_ENOSEEK); + if(seconds<0)return(OV_EINVAL); + + /* which bitstream section does this time offset occur in? */ + for(link=0;linklinks;link++){ + double addsec = ov_time_total(vf,link); + if(secondspcmlengths[link*2+1]; + } + + if(link==vf->links)return(OV_EINVAL); + + /* enough information to convert time offset to pcm offset */ + { + ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate; + return(ov_pcm_seek_page(vf,target)); + } +} + +/* tell the current stream offset cursor. Note that seek followed by + tell will likely not give the set offset due to caching */ +ogg_int64_t ov_raw_tell(OggVorbis_File *vf){ + if(vf->ready_stateoffset); +} + +/* return PCM offset (sample) of next PCM sample to be read */ +ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ + if(vf->ready_statepcm_offset); +} + +/* return time offset (seconds) of next PCM sample to be read */ +double ov_time_tell(OggVorbis_File *vf){ + int link=0; + ogg_int64_t pcm_total=0; + double time_total=0.f; + + if(vf->ready_stateseekable){ + pcm_total=ov_pcm_total(vf,-1); + time_total=ov_time_total(vf,-1); + + /* which bitstream section does this time offset occur in? */ + for(link=vf->links-1;link>=0;link--){ + pcm_total-=vf->pcmlengths[link*2+1]; + time_total-=ov_time_total(vf,link); + if(vf->pcm_offset>=pcm_total)break; + } + } + + return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate); +} + +/* link: -1) return the vorbis_info struct for the bitstream section + currently being decoded + 0-n) to request information for a specific bitstream section + + In the case of a non-seekable bitstream, any call returns the + current bitstream. NULL in the case that the machine is not + initialized */ + +vorbis_info *ov_info(OggVorbis_File *vf,int link){ + if(vf->seekable){ + if(link<0) + if(vf->ready_state>=STREAMSET) + return vf->vi+vf->current_link; + else + return vf->vi; + else + if(link>=vf->links) + return NULL; + else + return vf->vi+link; + }else{ + return vf->vi; + } +} + +/* grr, strong typing, grr, no templates/inheritence, grr */ +vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ + if(vf->seekable){ + if(link<0) + if(vf->ready_state>=STREAMSET) + return vf->vc+vf->current_link; + else + return vf->vc; + else + if(link>=vf->links) + return NULL; + else + return vf->vc+link; + }else{ + return vf->vc; + } +} + +static int host_is_big_endian() { + ogg_int32_t pattern = 0xfeedface; /* deadbeef */ + unsigned char *bytewise = (unsigned char *)&pattern; + if (bytewise[0] == 0xfe) return 1; + return 0; +} + +/* up to this point, everything could more or less hide the multiple + logical bitstream nature of chaining from the toplevel application + if the toplevel application didn't particularly care. However, at + the point that we actually read audio back, the multiple-section + nature must surface: Multiple bitstream sections do not necessarily + have to have the same number of channels or sampling rate. + + ov_read returns the sequential logical bitstream number currently + being decoded along with the PCM data in order that the toplevel + application can take action on channel/sample rate changes. This + number will be incremented even for streamed (non-seekable) streams + (for seekable streams, it represents the actual logical bitstream + index within the physical bitstream. Note that the accessor + functions above are aware of this dichotomy). + + ov_read_filter is exactly the same as ov_read except that it processes + the decoded audio data through a filter before packing it into the + requested format. This gives greater accuracy than applying a filter + after the audio has been converted into integral PCM. + + input values: buffer) a buffer to hold packed PCM data for return + length) the byte length requested to be placed into buffer + bigendianp) should the data be packed LSB first (0) or + MSB first (1) + word) word size for output. currently 1 (byte) or + 2 (16 bit short) + + return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) + 0) EOF + n) number of bytes of PCM actually returned. The + below works on a packet-by-packet basis, so the + return length is not related to the 'length' passed + in, just guaranteed to fit. + + *section) set to the logical bitstream number */ + +long ov_read_filter(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream, + void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){ + int i,j; + int host_endian = host_is_big_endian(); + int hs; + + float **pcm; + long samples; + + if(vf->ready_stateready_state==INITSET){ + samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); + if(samples)break; + } + + /* suck in another packet */ + { + int ret=_fetch_and_process_packet(vf,NULL,1,1); + if(ret==OV_EOF) + return(0); + if(ret<=0) + return(ret); + } + + } + + if(samples>0){ + + /* yay! proceed to pack data into the byte buffer */ + + 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) + return OV_EINVAL; + + /* Here. */ + if(filter) + filter(pcm,channels,samples,filter_param); + + /* a tight loop to pack each size */ + { + int val; + if(word==1){ + int off=(sgned?0:128); + vorbis_fpu_setround(&fpu); + for(j=0;j127)val=127; + else if(val<-128)val=-128; + *buffer++=val+off; + } + vorbis_fpu_restore(fpu); + }else{ + int off=(sgned?0:32768); + + if(host_endian==bigendianp){ + if(sgned){ + + vorbis_fpu_setround(&fpu); + for(i=0;i32767)val=32767; + else if(val<-32768)val=-32768; + *dest=val; + dest+=channels; + } + } + vorbis_fpu_restore(fpu); + + }else{ + + vorbis_fpu_setround(&fpu); + for(i=0;i32767)val=32767; + else if(val<-32768)val=-32768; + *dest=val+off; + dest+=channels; + } + } + vorbis_fpu_restore(fpu); + + } + }else if(bigendianp){ + + vorbis_fpu_setround(&fpu); + for(j=0;j32767)val=32767; + else if(val<-32768)val=-32768; + val+=off; + *buffer++=(val>>8); + *buffer++=(val&0xff); + } + vorbis_fpu_restore(fpu); + + }else{ + int val; + vorbis_fpu_setround(&fpu); + for(j=0;j32767)val=32767; + else if(val<-32768)val=-32768; + val+=off; + *buffer++=(val&0xff); + *buffer++=(val>>8); + } + vorbis_fpu_restore(fpu); + + } + } + } + + vorbis_synthesis_read(&vf->vd,samples); + hs=vorbis_synthesis_halfrate_p(vf->vi); + vf->pcm_offset+=(samples<current_link; + return(samples*bytespersample); + }else{ + return(samples); + } +} + +long ov_read(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream){ + return ov_read_filter(vf, buffer, length, bigendianp, word, sgned, bitstream, NULL, NULL); +} + +/* input values: pcm_channels) a float vector per channel of output + length) the sample length being read by the app + + return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) + 0) EOF + n) number of samples of PCM actually returned. The + below works on a packet-by-packet basis, so the + return length is not related to the 'length' passed + in, just guaranteed to fit. + + *section) set to the logical bitstream number */ + + + +long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length, + int *bitstream){ + + if(vf->ready_stateready_state==INITSET){ + float **pcm; + long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); + if(samples){ + int hs=vorbis_synthesis_halfrate_p(vf->vi); + if(pcm_channels)*pcm_channels=pcm; + if(samples>length)samples=length; + vorbis_synthesis_read(&vf->vd,samples); + vf->pcm_offset+=samples<current_link; + return samples; + + } + } + + /* suck in another packet */ + { + int ret=_fetch_and_process_packet(vf,NULL,1,1); + if(ret==OV_EOF)return(0); + if(ret<=0)return(ret); + } + + } +} + +extern const float *vorbis_window(vorbis_dsp_state *v,int W); + +static void _ov_splice(float **pcm,float **lappcm, + int n1, int n2, + int ch1, int ch2, + const float *w1, const float *w2){ + int i,j; + const float *w=w1; + int n=n1; + + if(n1>n2){ + n=n2; + w=w2; + } + + /* splice */ + for(j=0;jready_state==INITSET)break; + /* suck in another packet */ + { + int ret=_fetch_and_process_packet(vf,NULL,1,0); + if(ret<0 && ret!=OV_HOLE)return(ret); + } + } + return 0; +} + +/* make sure vf is INITSET and that we have a primed buffer; if + we're crosslapping at a stream section boundary, this also makes + sure we're sanity checking against the right stream information */ +static int _ov_initprime(OggVorbis_File *vf){ + vorbis_dsp_state *vd=&vf->vd; + while(1){ + if(vf->ready_state==INITSET) + if(vorbis_synthesis_pcmout(vd,NULL))break; + + /* suck in another packet */ + { + int ret=_fetch_and_process_packet(vf,NULL,1,0); + if(ret<0 && ret!=OV_HOLE)return(ret); + } + } + return 0; +} + +/* grab enough data for lapping from vf; this may be in the form of + unreturned, already-decoded pcm, remaining PCM we will need to + decode, or synthetic postextrapolation from last packets. */ +static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd, + float **lappcm,int lapsize){ + int lapcount=0,i; + float **pcm; + + /* try first to decode the lapping data */ + while(lapcountlapsize-lapcount)samples=lapsize-lapcount; + for(i=0;ichannels;i++) + memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples); + lapcount+=samples; + vorbis_synthesis_read(vd,samples); + }else{ + /* suck in another packet */ + int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */ + if(ret==OV_EOF)break; + } + } + if(lapcountvd,&pcm); + if(samples==0){ + for(i=0;ichannels;i++) + memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount); + lapcount=lapsize; + }else{ + if(samples>lapsize-lapcount)samples=lapsize-lapcount; + for(i=0;ichannels;i++) + memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples); + lapcount+=samples; + } + } +} + +/* this sets up crosslapping of a sample by using trailing data from + sample 1 and lapping it into the windowing buffer of sample 2 */ +int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){ + vorbis_info *vi1,*vi2; + float **lappcm; + float **pcm; + const float *w1,*w2; + int n1,n2,i,ret,hs1,hs2; + + if(vf1==vf2)return(0); /* degenerate case */ + if(vf1->ready_stateready_statechannels); + n1=vorbis_info_blocksize(vi1,0)>>(1+hs1); + n2=vorbis_info_blocksize(vi2,0)>>(1+hs2); + w1=vorbis_window(&vf1->vd,0); + w2=vorbis_window(&vf2->vd,0); + + for(i=0;ichannels;i++) + lappcm[i]=alloca(sizeof(**lappcm)*n1); + + _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1); + + /* have a lapping buffer from vf1; now to splice it into the lapping + buffer of vf2 */ + /* consolidate and expose the buffer. */ + vorbis_synthesis_lapout(&vf2->vd,&pcm); + +#if 0 + _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0); + _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0); +#endif + + /* splice */ + _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2); + + /* done */ + return(0); +} + +static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos, + int (*localseek)(OggVorbis_File *,ogg_int64_t)){ + vorbis_info *vi; + float **lappcm; + float **pcm; + const float *w1,*w2; + int n1,n2,ch1,ch2,hs; + int i,ret; + + if(vf->ready_statechannels; + n1=vorbis_info_blocksize(vi,0)>>(1+hs); + w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are + persistent; even if the decode state + from this link gets dumped, this + window array continues to exist */ + + lappcm=alloca(sizeof(*lappcm)*ch1); + for(i=0;ivd,lappcm,n1); + + /* have lapping data; seek and prime the buffer */ + ret=localseek(vf,pos); + if(ret)return ret; + ret=_ov_initprime(vf); + if(ret)return(ret); + + /* Guard against cross-link changes; they're perfectly legal */ + vi=ov_info(vf,-1); + ch2=vi->channels; + n2=vorbis_info_blocksize(vi,0)>>(1+hs); + w2=vorbis_window(&vf->vd,0); + + /* consolidate and expose the buffer. */ + vorbis_synthesis_lapout(&vf->vd,&pcm); + + /* splice */ + _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2); + + /* done */ + return(0); +} + +int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){ + return _ov_64_seek_lap(vf,pos,ov_raw_seek); +} + +int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){ + return _ov_64_seek_lap(vf,pos,ov_pcm_seek); +} + +int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){ + return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page); +} + +static int _ov_d_seek_lap(OggVorbis_File *vf,double pos, + int (*localseek)(OggVorbis_File *,double)){ + vorbis_info *vi; + float **lappcm; + float **pcm; + const float *w1,*w2; + int n1,n2,ch1,ch2,hs; + int i,ret; + + if(vf->ready_statechannels; + n1=vorbis_info_blocksize(vi,0)>>(1+hs); + w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are + persistent; even if the decode state + from this link gets dumped, this + window array continues to exist */ + + lappcm=alloca(sizeof(*lappcm)*ch1); + for(i=0;ivd,lappcm,n1); + + /* have lapping data; seek and prime the buffer */ + ret=localseek(vf,pos); + if(ret)return ret; + ret=_ov_initprime(vf); + if(ret)return(ret); + + /* Guard against cross-link changes; they're perfectly legal */ + vi=ov_info(vf,-1); + ch2=vi->channels; + n2=vorbis_info_blocksize(vi,0)>>(1+hs); + w2=vorbis_window(&vf->vd,0); + + /* consolidate and expose the buffer. */ + vorbis_synthesis_lapout(&vf->vd,&pcm); + + /* splice */ + _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2); + + /* done */ + return(0); +} + +int ov_time_seek_lap(OggVorbis_File *vf,double pos){ + return _ov_d_seek_lap(vf,pos,ov_time_seek); +} + +int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){ + return _ov_d_seek_lap(vf,pos,ov_time_seek_page); +} diff --git a/vendor/vorbis/lib/window.c b/vendor/vorbis/lib/window.c new file mode 100644 index 0000000..2151b27 --- /dev/null +++ b/vendor/vorbis/lib/window.c @@ -0,0 +1,2135 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: window functions + + ********************************************************************/ + +#include +#include +#include "os.h" +#include "misc.h" +#include "window.h" + +static const float vwin64[32] = { + 0.0009460463F, 0.0085006468F, 0.0235352254F, 0.0458950567F, + 0.0753351908F, 0.1115073077F, 0.1539457973F, 0.2020557475F, + 0.2551056759F, 0.3122276645F, 0.3724270287F, 0.4346027792F, + 0.4975789974F, 0.5601459521F, 0.6211085051F, 0.6793382689F, + 0.7338252629F, 0.7837245849F, 0.8283939355F, 0.8674186656F, + 0.9006222429F, 0.9280614787F, 0.9500073081F, 0.9669131782F, + 0.9793740220F, 0.9880792941F, 0.9937636139F, 0.9971582668F, + 0.9989462667F, 0.9997230082F, 0.9999638688F, 0.9999995525F, +}; + +static const float vwin128[64] = { + 0.0002365472F, 0.0021280687F, 0.0059065254F, 0.0115626550F, + 0.0190823442F, 0.0284463735F, 0.0396300935F, 0.0526030430F, + 0.0673285281F, 0.0837631763F, 0.1018564887F, 0.1215504095F, + 0.1427789367F, 0.1654677960F, 0.1895342001F, 0.2148867160F, + 0.2414252576F, 0.2690412240F, 0.2976177952F, 0.3270303960F, + 0.3571473350F, 0.3878306189F, 0.4189369387F, 0.4503188188F, + 0.4818259135F, 0.5133064334F, 0.5446086751F, 0.5755826278F, + 0.6060816248F, 0.6359640047F, 0.6650947483F, 0.6933470543F, + 0.7206038179F, 0.7467589810F, 0.7717187213F, 0.7954024542F, + 0.8177436264F, 0.8386902831F, 0.8582053981F, 0.8762669622F, + 0.8928678298F, 0.9080153310F, 0.9217306608F, 0.9340480615F, + 0.9450138200F, 0.9546851041F, 0.9631286621F, 0.9704194171F, + 0.9766389810F, 0.9818741197F, 0.9862151938F, 0.9897546035F, + 0.9925852598F, 0.9947991032F, 0.9964856900F, 0.9977308602F, + 0.9986155015F, 0.9992144193F, 0.9995953200F, 0.9998179155F, + 0.9999331503F, 0.9999825563F, 0.9999977357F, 0.9999999720F, +}; + +static const float vwin256[128] = { + 0.0000591390F, 0.0005321979F, 0.0014780301F, 0.0028960636F, + 0.0047854363F, 0.0071449926F, 0.0099732775F, 0.0132685298F, + 0.0170286741F, 0.0212513119F, 0.0259337111F, 0.0310727950F, + 0.0366651302F, 0.0427069140F, 0.0491939614F, 0.0561216907F, + 0.0634851102F, 0.0712788035F, 0.0794969160F, 0.0881331402F, + 0.0971807028F, 0.1066323515F, 0.1164803426F, 0.1267164297F, + 0.1373318534F, 0.1483173323F, 0.1596630553F, 0.1713586755F, + 0.1833933062F, 0.1957555184F, 0.2084333404F, 0.2214142599F, + 0.2346852280F, 0.2482326664F, 0.2620424757F, 0.2761000481F, + 0.2903902813F, 0.3048975959F, 0.3196059553F, 0.3344988887F, + 0.3495595160F, 0.3647705766F, 0.3801144597F, 0.3955732382F, + 0.4111287047F, 0.4267624093F, 0.4424557009F, 0.4581897696F, + 0.4739456913F, 0.4897044744F, 0.5054471075F, 0.5211546088F, + 0.5368080763F, 0.5523887395F, 0.5678780103F, 0.5832575361F, + 0.5985092508F, 0.6136154277F, 0.6285587300F, 0.6433222619F, + 0.6578896175F, 0.6722449294F, 0.6863729144F, 0.7002589187F, + 0.7138889597F, 0.7272497662F, 0.7403288154F, 0.7531143679F, + 0.7655954985F, 0.7777621249F, 0.7896050322F, 0.8011158947F, + 0.8122872932F, 0.8231127294F, 0.8335866365F, 0.8437043850F, + 0.8534622861F, 0.8628575905F, 0.8718884835F, 0.8805540765F, + 0.8888543947F, 0.8967903616F, 0.9043637797F, 0.9115773078F, + 0.9184344360F, 0.9249394562F, 0.9310974312F, 0.9369141608F, + 0.9423961446F, 0.9475505439F, 0.9523851406F, 0.9569082947F, + 0.9611289005F, 0.9650563408F, 0.9687004405F, 0.9720714191F, + 0.9751798427F, 0.9780365753F, 0.9806527301F, 0.9830396204F, + 0.9852087111F, 0.9871715701F, 0.9889398207F, 0.9905250941F, + 0.9919389832F, 0.9931929973F, 0.9942985174F, 0.9952667537F, + 0.9961087037F, 0.9968351119F, 0.9974564312F, 0.9979827858F, + 0.9984239359F, 0.9987892441F, 0.9990876435F, 0.9993276081F, + 0.9995171241F, 0.9996636648F, 0.9997741654F, 0.9998550016F, + 0.9999119692F, 0.9999502656F, 0.9999744742F, 0.9999885497F, + 0.9999958064F, 0.9999989077F, 0.9999998584F, 0.9999999983F, +}; + +static const float vwin512[256] = { + 0.0000147849F, 0.0001330607F, 0.0003695946F, 0.0007243509F, + 0.0011972759F, 0.0017882983F, 0.0024973285F, 0.0033242588F, + 0.0042689632F, 0.0053312973F, 0.0065110982F, 0.0078081841F, + 0.0092223540F, 0.0107533880F, 0.0124010466F, 0.0141650703F, + 0.0160451800F, 0.0180410758F, 0.0201524373F, 0.0223789233F, + 0.0247201710F, 0.0271757958F, 0.0297453914F, 0.0324285286F, + 0.0352247556F, 0.0381335972F, 0.0411545545F, 0.0442871045F, + 0.0475306997F, 0.0508847676F, 0.0543487103F, 0.0579219038F, + 0.0616036982F, 0.0653934164F, 0.0692903546F, 0.0732937809F, + 0.0774029356F, 0.0816170305F, 0.0859352485F, 0.0903567428F, + 0.0948806375F, 0.0995060259F, 0.1042319712F, 0.1090575056F, + 0.1139816300F, 0.1190033137F, 0.1241214941F, 0.1293350764F, + 0.1346429333F, 0.1400439046F, 0.1455367974F, 0.1511203852F, + 0.1567934083F, 0.1625545735F, 0.1684025537F, 0.1743359881F, + 0.1803534820F, 0.1864536069F, 0.1926349000F, 0.1988958650F, + 0.2052349715F, 0.2116506555F, 0.2181413191F, 0.2247053313F, + 0.2313410275F, 0.2380467105F, 0.2448206500F, 0.2516610835F, + 0.2585662164F, 0.2655342226F, 0.2725632448F, 0.2796513950F, + 0.2867967551F, 0.2939973773F, 0.3012512852F, 0.3085564739F, + 0.3159109111F, 0.3233125375F, 0.3307592680F, 0.3382489922F, + 0.3457795756F, 0.3533488602F, 0.3609546657F, 0.3685947904F, + 0.3762670121F, 0.3839690896F, 0.3916987634F, 0.3994537572F, + 0.4072317788F, 0.4150305215F, 0.4228476653F, 0.4306808783F, + 0.4385278181F, 0.4463861329F, 0.4542534630F, 0.4621274424F, + 0.4700057001F, 0.4778858615F, 0.4857655502F, 0.4936423891F, + 0.5015140023F, 0.5093780165F, 0.5172320626F, 0.5250737772F, + 0.5329008043F, 0.5407107971F, 0.5485014192F, 0.5562703465F, + 0.5640152688F, 0.5717338914F, 0.5794239366F, 0.5870831457F, + 0.5947092801F, 0.6023001235F, 0.6098534829F, 0.6173671907F, + 0.6248391059F, 0.6322671161F, 0.6396491384F, 0.6469831217F, + 0.6542670475F, 0.6614989319F, 0.6686768267F, 0.6757988210F, + 0.6828630426F, 0.6898676592F, 0.6968108799F, 0.7036909564F, + 0.7105061843F, 0.7172549043F, 0.7239355032F, 0.7305464154F, + 0.7370861235F, 0.7435531598F, 0.7499461068F, 0.7562635986F, + 0.7625043214F, 0.7686670148F, 0.7747504721F, 0.7807535410F, + 0.7866751247F, 0.7925141825F, 0.7982697296F, 0.8039408387F, + 0.8095266395F, 0.8150263196F, 0.8204391248F, 0.8257643590F, + 0.8310013848F, 0.8361496236F, 0.8412085555F, 0.8461777194F, + 0.8510567129F, 0.8558451924F, 0.8605428730F, 0.8651495278F, + 0.8696649882F, 0.8740891432F, 0.8784219392F, 0.8826633797F, + 0.8868135244F, 0.8908724888F, 0.8948404441F, 0.8987176157F, + 0.9025042831F, 0.9062007791F, 0.9098074886F, 0.9133248482F, + 0.9167533451F, 0.9200935163F, 0.9233459472F, 0.9265112712F, + 0.9295901680F, 0.9325833632F, 0.9354916263F, 0.9383157705F, + 0.9410566504F, 0.9437151618F, 0.9462922398F, 0.9487888576F, + 0.9512060252F, 0.9535447882F, 0.9558062262F, 0.9579914516F, + 0.9601016078F, 0.9621378683F, 0.9641014348F, 0.9659935361F, + 0.9678154261F, 0.9695683830F, 0.9712537071F, 0.9728727198F, + 0.9744267618F, 0.9759171916F, 0.9773453842F, 0.9787127293F, + 0.9800206298F, 0.9812705006F, 0.9824637665F, 0.9836018613F, + 0.9846862258F, 0.9857183066F, 0.9866995544F, 0.9876314227F, + 0.9885153662F, 0.9893528393F, 0.9901452948F, 0.9908941823F, + 0.9916009470F, 0.9922670279F, 0.9928938570F, 0.9934828574F, + 0.9940354423F, 0.9945530133F, 0.9950369595F, 0.9954886562F, + 0.9959094633F, 0.9963007242F, 0.9966637649F, 0.9969998925F, + 0.9973103939F, 0.9975965351F, 0.9978595598F, 0.9981006885F, + 0.9983211172F, 0.9985220166F, 0.9987045311F, 0.9988697776F, + 0.9990188449F, 0.9991527924F, 0.9992726499F, 0.9993794157F, + 0.9994740570F, 0.9995575079F, 0.9996306699F, 0.9996944099F, + 0.9997495605F, 0.9997969190F, 0.9998372465F, 0.9998712678F, + 0.9998996704F, 0.9999231041F, 0.9999421807F, 0.9999574732F, + 0.9999695157F, 0.9999788026F, 0.9999857885F, 0.9999908879F, + 0.9999944746F, 0.9999968817F, 0.9999984010F, 0.9999992833F, + 0.9999997377F, 0.9999999317F, 0.9999999911F, 0.9999999999F, +}; + +static const float vwin1024[512] = { + 0.0000036962F, 0.0000332659F, 0.0000924041F, 0.0001811086F, + 0.0002993761F, 0.0004472021F, 0.0006245811F, 0.0008315063F, + 0.0010679699F, 0.0013339631F, 0.0016294757F, 0.0019544965F, + 0.0023090133F, 0.0026930125F, 0.0031064797F, 0.0035493989F, + 0.0040217533F, 0.0045235250F, 0.0050546946F, 0.0056152418F, + 0.0062051451F, 0.0068243817F, 0.0074729278F, 0.0081507582F, + 0.0088578466F, 0.0095941655F, 0.0103596863F, 0.0111543789F, + 0.0119782122F, 0.0128311538F, 0.0137131701F, 0.0146242260F, + 0.0155642855F, 0.0165333111F, 0.0175312640F, 0.0185581042F, + 0.0196137903F, 0.0206982797F, 0.0218115284F, 0.0229534910F, + 0.0241241208F, 0.0253233698F, 0.0265511886F, 0.0278075263F, + 0.0290923308F, 0.0304055484F, 0.0317471241F, 0.0331170013F, + 0.0345151222F, 0.0359414274F, 0.0373958560F, 0.0388783456F, + 0.0403888325F, 0.0419272511F, 0.0434935347F, 0.0450876148F, + 0.0467094213F, 0.0483588828F, 0.0500359261F, 0.0517404765F, + 0.0534724575F, 0.0552317913F, 0.0570183983F, 0.0588321971F, + 0.0606731048F, 0.0625410369F, 0.0644359070F, 0.0663576272F, + 0.0683061077F, 0.0702812571F, 0.0722829821F, 0.0743111878F, + 0.0763657775F, 0.0784466526F, 0.0805537129F, 0.0826868561F, + 0.0848459782F, 0.0870309736F, 0.0892417345F, 0.0914781514F, + 0.0937401128F, 0.0960275056F, 0.0983402145F, 0.1006781223F, + 0.1030411101F, 0.1054290568F, 0.1078418397F, 0.1102793336F, + 0.1127414119F, 0.1152279457F, 0.1177388042F, 0.1202738544F, + 0.1228329618F, 0.1254159892F, 0.1280227980F, 0.1306532471F, + 0.1333071937F, 0.1359844927F, 0.1386849970F, 0.1414085575F, + 0.1441550230F, 0.1469242403F, 0.1497160539F, 0.1525303063F, + 0.1553668381F, 0.1582254875F, 0.1611060909F, 0.1640084822F, + 0.1669324936F, 0.1698779549F, 0.1728446939F, 0.1758325362F, + 0.1788413055F, 0.1818708232F, 0.1849209084F, 0.1879913785F, + 0.1910820485F, 0.1941927312F, 0.1973232376F, 0.2004733764F, + 0.2036429541F, 0.2068317752F, 0.2100396421F, 0.2132663552F, + 0.2165117125F, 0.2197755102F, 0.2230575422F, 0.2263576007F, + 0.2296754753F, 0.2330109540F, 0.2363638225F, 0.2397338646F, + 0.2431208619F, 0.2465245941F, 0.2499448389F, 0.2533813719F, + 0.2568339669F, 0.2603023956F, 0.2637864277F, 0.2672858312F, + 0.2708003718F, 0.2743298135F, 0.2778739186F, 0.2814324472F, + 0.2850051576F, 0.2885918065F, 0.2921921485F, 0.2958059366F, + 0.2994329219F, 0.3030728538F, 0.3067254799F, 0.3103905462F, + 0.3140677969F, 0.3177569747F, 0.3214578205F, 0.3251700736F, + 0.3288934718F, 0.3326277513F, 0.3363726468F, 0.3401278914F, + 0.3438932168F, 0.3476683533F, 0.3514530297F, 0.3552469734F, + 0.3590499106F, 0.3628615659F, 0.3666816630F, 0.3705099239F, + 0.3743460698F, 0.3781898204F, 0.3820408945F, 0.3858990095F, + 0.3897638820F, 0.3936352274F, 0.3975127601F, 0.4013961936F, + 0.4052852405F, 0.4091796123F, 0.4130790198F, 0.4169831732F, + 0.4208917815F, 0.4248045534F, 0.4287211965F, 0.4326414181F, + 0.4365649248F, 0.4404914225F, 0.4444206167F, 0.4483522125F, + 0.4522859146F, 0.4562214270F, 0.4601584538F, 0.4640966984F, + 0.4680358644F, 0.4719756548F, 0.4759157726F, 0.4798559209F, + 0.4837958024F, 0.4877351199F, 0.4916735765F, 0.4956108751F, + 0.4995467188F, 0.5034808109F, 0.5074128550F, 0.5113425550F, + 0.5152696149F, 0.5191937395F, 0.5231146336F, 0.5270320028F, + 0.5309455530F, 0.5348549910F, 0.5387600239F, 0.5426603597F, + 0.5465557070F, 0.5504457754F, 0.5543302752F, 0.5582089175F, + 0.5620814145F, 0.5659474793F, 0.5698068262F, 0.5736591704F, + 0.5775042283F, 0.5813417176F, 0.5851713571F, 0.5889928670F, + 0.5928059689F, 0.5966103856F, 0.6004058415F, 0.6041920626F, + 0.6079687761F, 0.6117357113F, 0.6154925986F, 0.6192391705F, + 0.6229751612F, 0.6267003064F, 0.6304143441F, 0.6341170137F, + 0.6378080569F, 0.6414872173F, 0.6451542405F, 0.6488088741F, + 0.6524508681F, 0.6560799742F, 0.6596959469F, 0.6632985424F, + 0.6668875197F, 0.6704626398F, 0.6740236662F, 0.6775703649F, + 0.6811025043F, 0.6846198554F, 0.6881221916F, 0.6916092892F, + 0.6950809269F, 0.6985368861F, 0.7019769510F, 0.7054009085F, + 0.7088085484F, 0.7121996632F, 0.7155740484F, 0.7189315023F, + 0.7222718263F, 0.7255948245F, 0.7289003043F, 0.7321880760F, + 0.7354579530F, 0.7387097518F, 0.7419432921F, 0.7451583966F, + 0.7483548915F, 0.7515326059F, 0.7546913723F, 0.7578310265F, + 0.7609514077F, 0.7640523581F, 0.7671337237F, 0.7701953535F, + 0.7732371001F, 0.7762588195F, 0.7792603711F, 0.7822416178F, + 0.7852024259F, 0.7881426654F, 0.7910622097F, 0.7939609356F, + 0.7968387237F, 0.7996954579F, 0.8025310261F, 0.8053453193F, + 0.8081382324F, 0.8109096638F, 0.8136595156F, 0.8163876936F, + 0.8190941071F, 0.8217786690F, 0.8244412960F, 0.8270819086F, + 0.8297004305F, 0.8322967896F, 0.8348709171F, 0.8374227481F, + 0.8399522213F, 0.8424592789F, 0.8449438672F, 0.8474059356F, + 0.8498454378F, 0.8522623306F, 0.8546565748F, 0.8570281348F, + 0.8593769787F, 0.8617030779F, 0.8640064080F, 0.8662869477F, + 0.8685446796F, 0.8707795899F, 0.8729916682F, 0.8751809079F, + 0.8773473059F, 0.8794908626F, 0.8816115819F, 0.8837094713F, + 0.8857845418F, 0.8878368079F, 0.8898662874F, 0.8918730019F, + 0.8938569760F, 0.8958182380F, 0.8977568194F, 0.8996727552F, + 0.9015660837F, 0.9034368465F, 0.9052850885F, 0.9071108577F, + 0.9089142057F, 0.9106951869F, 0.9124538591F, 0.9141902832F, + 0.9159045233F, 0.9175966464F, 0.9192667228F, 0.9209148257F, + 0.9225410313F, 0.9241454187F, 0.9257280701F, 0.9272890704F, + 0.9288285075F, 0.9303464720F, 0.9318430576F, 0.9333183603F, + 0.9347724792F, 0.9362055158F, 0.9376175745F, 0.9390087622F, + 0.9403791881F, 0.9417289644F, 0.9430582055F, 0.9443670283F, + 0.9456555521F, 0.9469238986F, 0.9481721917F, 0.9494005577F, + 0.9506091252F, 0.9517980248F, 0.9529673894F, 0.9541173540F, + 0.9552480557F, 0.9563596334F, 0.9574522282F, 0.9585259830F, + 0.9595810428F, 0.9606175542F, 0.9616356656F, 0.9626355274F, + 0.9636172915F, 0.9645811114F, 0.9655271425F, 0.9664555414F, + 0.9673664664F, 0.9682600774F, 0.9691365355F, 0.9699960034F, + 0.9708386448F, 0.9716646250F, 0.9724741103F, 0.9732672685F, + 0.9740442683F, 0.9748052795F, 0.9755504729F, 0.9762800205F, + 0.9769940950F, 0.9776928703F, 0.9783765210F, 0.9790452223F, + 0.9796991504F, 0.9803384823F, 0.9809633954F, 0.9815740679F, + 0.9821706784F, 0.9827534063F, 0.9833224312F, 0.9838779332F, + 0.9844200928F, 0.9849490910F, 0.9854651087F, 0.9859683274F, + 0.9864589286F, 0.9869370940F, 0.9874030054F, 0.9878568447F, + 0.9882987937F, 0.9887290343F, 0.9891477481F, 0.9895551169F, + 0.9899513220F, 0.9903365446F, 0.9907109658F, 0.9910747662F, + 0.9914281260F, 0.9917712252F, 0.9921042433F, 0.9924273593F, + 0.9927407516F, 0.9930445982F, 0.9933390763F, 0.9936243626F, + 0.9939006331F, 0.9941680631F, 0.9944268269F, 0.9946770982F, + 0.9949190498F, 0.9951528537F, 0.9953786808F, 0.9955967011F, + 0.9958070836F, 0.9960099963F, 0.9962056061F, 0.9963940787F, + 0.9965755786F, 0.9967502693F, 0.9969183129F, 0.9970798704F, + 0.9972351013F, 0.9973841640F, 0.9975272151F, 0.9976644103F, + 0.9977959036F, 0.9979218476F, 0.9980423932F, 0.9981576901F, + 0.9982678862F, 0.9983731278F, 0.9984735596F, 0.9985693247F, + 0.9986605645F, 0.9987474186F, 0.9988300248F, 0.9989085193F, + 0.9989830364F, 0.9990537085F, 0.9991206662F, 0.9991840382F, + 0.9992439513F, 0.9993005303F, 0.9993538982F, 0.9994041757F, + 0.9994514817F, 0.9994959330F, 0.9995376444F, 0.9995767286F, + 0.9996132960F, 0.9996474550F, 0.9996793121F, 0.9997089710F, + 0.9997365339F, 0.9997621003F, 0.9997857677F, 0.9998076311F, + 0.9998277836F, 0.9998463156F, 0.9998633155F, 0.9998788692F, + 0.9998930603F, 0.9999059701F, 0.9999176774F, 0.9999282586F, + 0.9999377880F, 0.9999463370F, 0.9999539749F, 0.9999607685F, + 0.9999667820F, 0.9999720773F, 0.9999767136F, 0.9999807479F, + 0.9999842344F, 0.9999872249F, 0.9999897688F, 0.9999919127F, + 0.9999937009F, 0.9999951749F, 0.9999963738F, 0.9999973342F, + 0.9999980900F, 0.9999986724F, 0.9999991103F, 0.9999994297F, + 0.9999996543F, 0.9999998049F, 0.9999999000F, 0.9999999552F, + 0.9999999836F, 0.9999999957F, 0.9999999994F, 1.0000000000F, +}; + +static const float vwin2048[1024] = { + 0.0000009241F, 0.0000083165F, 0.0000231014F, 0.0000452785F, + 0.0000748476F, 0.0001118085F, 0.0001561608F, 0.0002079041F, + 0.0002670379F, 0.0003335617F, 0.0004074748F, 0.0004887765F, + 0.0005774661F, 0.0006735427F, 0.0007770054F, 0.0008878533F, + 0.0010060853F, 0.0011317002F, 0.0012646969F, 0.0014050742F, + 0.0015528307F, 0.0017079650F, 0.0018704756F, 0.0020403610F, + 0.0022176196F, 0.0024022497F, 0.0025942495F, 0.0027936173F, + 0.0030003511F, 0.0032144490F, 0.0034359088F, 0.0036647286F, + 0.0039009061F, 0.0041444391F, 0.0043953253F, 0.0046535621F, + 0.0049191472F, 0.0051920781F, 0.0054723520F, 0.0057599664F, + 0.0060549184F, 0.0063572052F, 0.0066668239F, 0.0069837715F, + 0.0073080449F, 0.0076396410F, 0.0079785566F, 0.0083247884F, + 0.0086783330F, 0.0090391871F, 0.0094073470F, 0.0097828092F, + 0.0101655700F, 0.0105556258F, 0.0109529726F, 0.0113576065F, + 0.0117695237F, 0.0121887200F, 0.0126151913F, 0.0130489335F, + 0.0134899422F, 0.0139382130F, 0.0143937415F, 0.0148565233F, + 0.0153265536F, 0.0158038279F, 0.0162883413F, 0.0167800889F, + 0.0172790660F, 0.0177852675F, 0.0182986882F, 0.0188193231F, + 0.0193471668F, 0.0198822141F, 0.0204244594F, 0.0209738974F, + 0.0215305225F, 0.0220943289F, 0.0226653109F, 0.0232434627F, + 0.0238287784F, 0.0244212519F, 0.0250208772F, 0.0256276481F, + 0.0262415582F, 0.0268626014F, 0.0274907711F, 0.0281260608F, + 0.0287684638F, 0.0294179736F, 0.0300745833F, 0.0307382859F, + 0.0314090747F, 0.0320869424F, 0.0327718819F, 0.0334638860F, + 0.0341629474F, 0.0348690586F, 0.0355822122F, 0.0363024004F, + 0.0370296157F, 0.0377638502F, 0.0385050960F, 0.0392533451F, + 0.0400085896F, 0.0407708211F, 0.0415400315F, 0.0423162123F, + 0.0430993552F, 0.0438894515F, 0.0446864926F, 0.0454904698F, + 0.0463013742F, 0.0471191969F, 0.0479439288F, 0.0487755607F, + 0.0496140836F, 0.0504594879F, 0.0513117642F, 0.0521709031F, + 0.0530368949F, 0.0539097297F, 0.0547893979F, 0.0556758894F, + 0.0565691941F, 0.0574693019F, 0.0583762026F, 0.0592898858F, + 0.0602103410F, 0.0611375576F, 0.0620715250F, 0.0630122324F, + 0.0639596688F, 0.0649138234F, 0.0658746848F, 0.0668422421F, + 0.0678164838F, 0.0687973985F, 0.0697849746F, 0.0707792005F, + 0.0717800645F, 0.0727875547F, 0.0738016591F, 0.0748223656F, + 0.0758496620F, 0.0768835359F, 0.0779239751F, 0.0789709668F, + 0.0800244985F, 0.0810845574F, 0.0821511306F, 0.0832242052F, + 0.0843037679F, 0.0853898056F, 0.0864823050F, 0.0875812525F, + 0.0886866347F, 0.0897984378F, 0.0909166480F, 0.0920412513F, + 0.0931722338F, 0.0943095813F, 0.0954532795F, 0.0966033140F, + 0.0977596702F, 0.0989223336F, 0.1000912894F, 0.1012665227F, + 0.1024480185F, 0.1036357616F, 0.1048297369F, 0.1060299290F, + 0.1072363224F, 0.1084489014F, 0.1096676504F, 0.1108925534F, + 0.1121235946F, 0.1133607577F, 0.1146040267F, 0.1158533850F, + 0.1171088163F, 0.1183703040F, 0.1196378312F, 0.1209113812F, + 0.1221909370F, 0.1234764815F, 0.1247679974F, 0.1260654674F, + 0.1273688740F, 0.1286781995F, 0.1299934263F, 0.1313145365F, + 0.1326415121F, 0.1339743349F, 0.1353129866F, 0.1366574490F, + 0.1380077035F, 0.1393637315F, 0.1407255141F, 0.1420930325F, + 0.1434662677F, 0.1448452004F, 0.1462298115F, 0.1476200814F, + 0.1490159906F, 0.1504175195F, 0.1518246482F, 0.1532373569F, + 0.1546556253F, 0.1560794333F, 0.1575087606F, 0.1589435866F, + 0.1603838909F, 0.1618296526F, 0.1632808509F, 0.1647374648F, + 0.1661994731F, 0.1676668546F, 0.1691395880F, 0.1706176516F, + 0.1721010238F, 0.1735896829F, 0.1750836068F, 0.1765827736F, + 0.1780871610F, 0.1795967468F, 0.1811115084F, 0.1826314234F, + 0.1841564689F, 0.1856866221F, 0.1872218600F, 0.1887621595F, + 0.1903074974F, 0.1918578503F, 0.1934131947F, 0.1949735068F, + 0.1965387630F, 0.1981089393F, 0.1996840117F, 0.2012639560F, + 0.2028487479F, 0.2044383630F, 0.2060327766F, 0.2076319642F, + 0.2092359007F, 0.2108445614F, 0.2124579211F, 0.2140759545F, + 0.2156986364F, 0.2173259411F, 0.2189578432F, 0.2205943168F, + 0.2222353361F, 0.2238808751F, 0.2255309076F, 0.2271854073F, + 0.2288443480F, 0.2305077030F, 0.2321754457F, 0.2338475493F, + 0.2355239869F, 0.2372047315F, 0.2388897560F, 0.2405790329F, + 0.2422725350F, 0.2439702347F, 0.2456721043F, 0.2473781159F, + 0.2490882418F, 0.2508024539F, 0.2525207240F, 0.2542430237F, + 0.2559693248F, 0.2576995986F, 0.2594338166F, 0.2611719498F, + 0.2629139695F, 0.2646598466F, 0.2664095520F, 0.2681630564F, + 0.2699203304F, 0.2716813445F, 0.2734460691F, 0.2752144744F, + 0.2769865307F, 0.2787622079F, 0.2805414760F, 0.2823243047F, + 0.2841106637F, 0.2859005227F, 0.2876938509F, 0.2894906179F, + 0.2912907928F, 0.2930943447F, 0.2949012426F, 0.2967114554F, + 0.2985249520F, 0.3003417009F, 0.3021616708F, 0.3039848301F, + 0.3058111471F, 0.3076405901F, 0.3094731273F, 0.3113087266F, + 0.3131473560F, 0.3149889833F, 0.3168335762F, 0.3186811024F, + 0.3205315294F, 0.3223848245F, 0.3242409552F, 0.3260998886F, + 0.3279615918F, 0.3298260319F, 0.3316931758F, 0.3335629903F, + 0.3354354423F, 0.3373104982F, 0.3391881247F, 0.3410682882F, + 0.3429509551F, 0.3448360917F, 0.3467236642F, 0.3486136387F, + 0.3505059811F, 0.3524006575F, 0.3542976336F, 0.3561968753F, + 0.3580983482F, 0.3600020179F, 0.3619078499F, 0.3638158096F, + 0.3657258625F, 0.3676379737F, 0.3695521086F, 0.3714682321F, + 0.3733863094F, 0.3753063055F, 0.3772281852F, 0.3791519134F, + 0.3810774548F, 0.3830047742F, 0.3849338362F, 0.3868646053F, + 0.3887970459F, 0.3907311227F, 0.3926667998F, 0.3946040417F, + 0.3965428125F, 0.3984830765F, 0.4004247978F, 0.4023679403F, + 0.4043124683F, 0.4062583455F, 0.4082055359F, 0.4101540034F, + 0.4121037117F, 0.4140546246F, 0.4160067058F, 0.4179599190F, + 0.4199142277F, 0.4218695956F, 0.4238259861F, 0.4257833627F, + 0.4277416888F, 0.4297009279F, 0.4316610433F, 0.4336219983F, + 0.4355837562F, 0.4375462803F, 0.4395095337F, 0.4414734797F, + 0.4434380815F, 0.4454033021F, 0.4473691046F, 0.4493354521F, + 0.4513023078F, 0.4532696345F, 0.4552373954F, 0.4572055533F, + 0.4591740713F, 0.4611429123F, 0.4631120393F, 0.4650814151F, + 0.4670510028F, 0.4690207650F, 0.4709906649F, 0.4729606651F, + 0.4749307287F, 0.4769008185F, 0.4788708972F, 0.4808409279F, + 0.4828108732F, 0.4847806962F, 0.4867503597F, 0.4887198264F, + 0.4906890593F, 0.4926580213F, 0.4946266753F, 0.4965949840F, + 0.4985629105F, 0.5005304176F, 0.5024974683F, 0.5044640255F, + 0.5064300522F, 0.5083955114F, 0.5103603659F, 0.5123245790F, + 0.5142881136F, 0.5162509328F, 0.5182129997F, 0.5201742774F, + 0.5221347290F, 0.5240943178F, 0.5260530070F, 0.5280107598F, + 0.5299675395F, 0.5319233095F, 0.5338780330F, 0.5358316736F, + 0.5377841946F, 0.5397355596F, 0.5416857320F, 0.5436346755F, + 0.5455823538F, 0.5475287304F, 0.5494737691F, 0.5514174337F, + 0.5533596881F, 0.5553004962F, 0.5572398218F, 0.5591776291F, + 0.5611138821F, 0.5630485449F, 0.5649815818F, 0.5669129570F, + 0.5688426349F, 0.5707705799F, 0.5726967564F, 0.5746211290F, + 0.5765436624F, 0.5784643212F, 0.5803830702F, 0.5822998743F, + 0.5842146984F, 0.5861275076F, 0.5880382669F, 0.5899469416F, + 0.5918534968F, 0.5937578981F, 0.5956601107F, 0.5975601004F, + 0.5994578326F, 0.6013532732F, 0.6032463880F, 0.6051371429F, + 0.6070255039F, 0.6089114372F, 0.6107949090F, 0.6126758856F, + 0.6145543334F, 0.6164302191F, 0.6183035092F, 0.6201741706F, + 0.6220421700F, 0.6239074745F, 0.6257700513F, 0.6276298674F, + 0.6294868903F, 0.6313410873F, 0.6331924262F, 0.6350408745F, + 0.6368864001F, 0.6387289710F, 0.6405685552F, 0.6424051209F, + 0.6442386364F, 0.6460690702F, 0.6478963910F, 0.6497205673F, + 0.6515415682F, 0.6533593625F, 0.6551739194F, 0.6569852082F, + 0.6587931984F, 0.6605978593F, 0.6623991609F, 0.6641970728F, + 0.6659915652F, 0.6677826081F, 0.6695701718F, 0.6713542268F, + 0.6731347437F, 0.6749116932F, 0.6766850461F, 0.6784547736F, + 0.6802208469F, 0.6819832374F, 0.6837419164F, 0.6854968559F, + 0.6872480275F, 0.6889954034F, 0.6907389556F, 0.6924786566F, + 0.6942144788F, 0.6959463950F, 0.6976743780F, 0.6993984008F, + 0.7011184365F, 0.7028344587F, 0.7045464407F, 0.7062543564F, + 0.7079581796F, 0.7096578844F, 0.7113534450F, 0.7130448359F, + 0.7147320316F, 0.7164150070F, 0.7180937371F, 0.7197681970F, + 0.7214383620F, 0.7231042077F, 0.7247657098F, 0.7264228443F, + 0.7280755871F, 0.7297239147F, 0.7313678035F, 0.7330072301F, + 0.7346421715F, 0.7362726046F, 0.7378985069F, 0.7395198556F, + 0.7411366285F, 0.7427488034F, 0.7443563584F, 0.7459592717F, + 0.7475575218F, 0.7491510873F, 0.7507399471F, 0.7523240803F, + 0.7539034661F, 0.7554780839F, 0.7570479136F, 0.7586129349F, + 0.7601731279F, 0.7617284730F, 0.7632789506F, 0.7648245416F, + 0.7663652267F, 0.7679009872F, 0.7694318044F, 0.7709576599F, + 0.7724785354F, 0.7739944130F, 0.7755052749F, 0.7770111035F, + 0.7785118815F, 0.7800075916F, 0.7814982170F, 0.7829837410F, + 0.7844641472F, 0.7859394191F, 0.7874095408F, 0.7888744965F, + 0.7903342706F, 0.7917888476F, 0.7932382124F, 0.7946823501F, + 0.7961212460F, 0.7975548855F, 0.7989832544F, 0.8004063386F, + 0.8018241244F, 0.8032365981F, 0.8046437463F, 0.8060455560F, + 0.8074420141F, 0.8088331080F, 0.8102188253F, 0.8115991536F, + 0.8129740810F, 0.8143435957F, 0.8157076861F, 0.8170663409F, + 0.8184195489F, 0.8197672994F, 0.8211095817F, 0.8224463853F, + 0.8237777001F, 0.8251035161F, 0.8264238235F, 0.8277386129F, + 0.8290478750F, 0.8303516008F, 0.8316497814F, 0.8329424083F, + 0.8342294731F, 0.8355109677F, 0.8367868841F, 0.8380572148F, + 0.8393219523F, 0.8405810893F, 0.8418346190F, 0.8430825345F, + 0.8443248294F, 0.8455614974F, 0.8467925323F, 0.8480179285F, + 0.8492376802F, 0.8504517822F, 0.8516602292F, 0.8528630164F, + 0.8540601391F, 0.8552515928F, 0.8564373733F, 0.8576174766F, + 0.8587918990F, 0.8599606368F, 0.8611236868F, 0.8622810460F, + 0.8634327113F, 0.8645786802F, 0.8657189504F, 0.8668535195F, + 0.8679823857F, 0.8691055472F, 0.8702230025F, 0.8713347503F, + 0.8724407896F, 0.8735411194F, 0.8746357394F, 0.8757246489F, + 0.8768078479F, 0.8778853364F, 0.8789571146F, 0.8800231832F, + 0.8810835427F, 0.8821381942F, 0.8831871387F, 0.8842303777F, + 0.8852679127F, 0.8862997456F, 0.8873258784F, 0.8883463132F, + 0.8893610527F, 0.8903700994F, 0.8913734562F, 0.8923711263F, + 0.8933631129F, 0.8943494196F, 0.8953300500F, 0.8963050083F, + 0.8972742985F, 0.8982379249F, 0.8991958922F, 0.9001482052F, + 0.9010948688F, 0.9020358883F, 0.9029712690F, 0.9039010165F, + 0.9048251367F, 0.9057436357F, 0.9066565195F, 0.9075637946F, + 0.9084654678F, 0.9093615456F, 0.9102520353F, 0.9111369440F, + 0.9120162792F, 0.9128900484F, 0.9137582595F, 0.9146209204F, + 0.9154780394F, 0.9163296248F, 0.9171756853F, 0.9180162296F, + 0.9188512667F, 0.9196808057F, 0.9205048559F, 0.9213234270F, + 0.9221365285F, 0.9229441704F, 0.9237463629F, 0.9245431160F, + 0.9253344404F, 0.9261203465F, 0.9269008453F, 0.9276759477F, + 0.9284456648F, 0.9292100080F, 0.9299689889F, 0.9307226190F, + 0.9314709103F, 0.9322138747F, 0.9329515245F, 0.9336838721F, + 0.9344109300F, 0.9351327108F, 0.9358492275F, 0.9365604931F, + 0.9372665208F, 0.9379673239F, 0.9386629160F, 0.9393533107F, + 0.9400385220F, 0.9407185637F, 0.9413934501F, 0.9420631954F, + 0.9427278141F, 0.9433873208F, 0.9440417304F, 0.9446910576F, + 0.9453353176F, 0.9459745255F, 0.9466086968F, 0.9472378469F, + 0.9478619915F, 0.9484811463F, 0.9490953274F, 0.9497045506F, + 0.9503088323F, 0.9509081888F, 0.9515026365F, 0.9520921921F, + 0.9526768723F, 0.9532566940F, 0.9538316742F, 0.9544018300F, + 0.9549671786F, 0.9555277375F, 0.9560835241F, 0.9566345562F, + 0.9571808513F, 0.9577224275F, 0.9582593027F, 0.9587914949F, + 0.9593190225F, 0.9598419038F, 0.9603601571F, 0.9608738012F, + 0.9613828546F, 0.9618873361F, 0.9623872646F, 0.9628826591F, + 0.9633735388F, 0.9638599227F, 0.9643418303F, 0.9648192808F, + 0.9652922939F, 0.9657608890F, 0.9662250860F, 0.9666849046F, + 0.9671403646F, 0.9675914861F, 0.9680382891F, 0.9684807937F, + 0.9689190202F, 0.9693529890F, 0.9697827203F, 0.9702082347F, + 0.9706295529F, 0.9710466953F, 0.9714596828F, 0.9718685362F, + 0.9722732762F, 0.9726739240F, 0.9730705005F, 0.9734630267F, + 0.9738515239F, 0.9742360134F, 0.9746165163F, 0.9749930540F, + 0.9753656481F, 0.9757343198F, 0.9760990909F, 0.9764599829F, + 0.9768170175F, 0.9771702164F, 0.9775196013F, 0.9778651941F, + 0.9782070167F, 0.9785450909F, 0.9788794388F, 0.9792100824F, + 0.9795370437F, 0.9798603449F, 0.9801800080F, 0.9804960554F, + 0.9808085092F, 0.9811173916F, 0.9814227251F, 0.9817245318F, + 0.9820228343F, 0.9823176549F, 0.9826090160F, 0.9828969402F, + 0.9831814498F, 0.9834625674F, 0.9837403156F, 0.9840147169F, + 0.9842857939F, 0.9845535692F, 0.9848180654F, 0.9850793052F, + 0.9853373113F, 0.9855921062F, 0.9858437127F, 0.9860921535F, + 0.9863374512F, 0.9865796287F, 0.9868187085F, 0.9870547136F, + 0.9872876664F, 0.9875175899F, 0.9877445067F, 0.9879684396F, + 0.9881894112F, 0.9884074444F, 0.9886225619F, 0.9888347863F, + 0.9890441404F, 0.9892506468F, 0.9894543284F, 0.9896552077F, + 0.9898533074F, 0.9900486502F, 0.9902412587F, 0.9904311555F, + 0.9906183633F, 0.9908029045F, 0.9909848019F, 0.9911640779F, + 0.9913407550F, 0.9915148557F, 0.9916864025F, 0.9918554179F, + 0.9920219241F, 0.9921859437F, 0.9923474989F, 0.9925066120F, + 0.9926633054F, 0.9928176012F, 0.9929695218F, 0.9931190891F, + 0.9932663254F, 0.9934112527F, 0.9935538932F, 0.9936942686F, + 0.9938324012F, 0.9939683126F, 0.9941020248F, 0.9942335597F, + 0.9943629388F, 0.9944901841F, 0.9946153170F, 0.9947383593F, + 0.9948593325F, 0.9949782579F, 0.9950951572F, 0.9952100516F, + 0.9953229625F, 0.9954339111F, 0.9955429186F, 0.9956500062F, + 0.9957551948F, 0.9958585056F, 0.9959599593F, 0.9960595769F, + 0.9961573792F, 0.9962533869F, 0.9963476206F, 0.9964401009F, + 0.9965308483F, 0.9966198833F, 0.9967072261F, 0.9967928971F, + 0.9968769164F, 0.9969593041F, 0.9970400804F, 0.9971192651F, + 0.9971968781F, 0.9972729391F, 0.9973474680F, 0.9974204842F, + 0.9974920074F, 0.9975620569F, 0.9976306521F, 0.9976978122F, + 0.9977635565F, 0.9978279039F, 0.9978908736F, 0.9979524842F, + 0.9980127547F, 0.9980717037F, 0.9981293499F, 0.9981857116F, + 0.9982408073F, 0.9982946554F, 0.9983472739F, 0.9983986810F, + 0.9984488947F, 0.9984979328F, 0.9985458132F, 0.9985925534F, + 0.9986381711F, 0.9986826838F, 0.9987261086F, 0.9987684630F, + 0.9988097640F, 0.9988500286F, 0.9988892738F, 0.9989275163F, + 0.9989647727F, 0.9990010597F, 0.9990363938F, 0.9990707911F, + 0.9991042679F, 0.9991368404F, 0.9991685244F, 0.9991993358F, + 0.9992292905F, 0.9992584038F, 0.9992866914F, 0.9993141686F, + 0.9993408506F, 0.9993667526F, 0.9993918895F, 0.9994162761F, + 0.9994399273F, 0.9994628576F, 0.9994850815F, 0.9995066133F, + 0.9995274672F, 0.9995476574F, 0.9995671978F, 0.9995861021F, + 0.9996043841F, 0.9996220573F, 0.9996391352F, 0.9996556310F, + 0.9996715579F, 0.9996869288F, 0.9997017568F, 0.9997160543F, + 0.9997298342F, 0.9997431088F, 0.9997558905F, 0.9997681914F, + 0.9997800236F, 0.9997913990F, 0.9998023292F, 0.9998128261F, + 0.9998229009F, 0.9998325650F, 0.9998418296F, 0.9998507058F, + 0.9998592044F, 0.9998673362F, 0.9998751117F, 0.9998825415F, + 0.9998896358F, 0.9998964047F, 0.9999028584F, 0.9999090066F, + 0.9999148590F, 0.9999204253F, 0.9999257148F, 0.9999307368F, + 0.9999355003F, 0.9999400144F, 0.9999442878F, 0.9999483293F, + 0.9999521472F, 0.9999557499F, 0.9999591457F, 0.9999623426F, + 0.9999653483F, 0.9999681708F, 0.9999708175F, 0.9999732959F, + 0.9999756132F, 0.9999777765F, 0.9999797928F, 0.9999816688F, + 0.9999834113F, 0.9999850266F, 0.9999865211F, 0.9999879009F, + 0.9999891721F, 0.9999903405F, 0.9999914118F, 0.9999923914F, + 0.9999932849F, 0.9999940972F, 0.9999948336F, 0.9999954989F, + 0.9999960978F, 0.9999966349F, 0.9999971146F, 0.9999975411F, + 0.9999979185F, 0.9999982507F, 0.9999985414F, 0.9999987944F, + 0.9999990129F, 0.9999992003F, 0.9999993596F, 0.9999994939F, + 0.9999996059F, 0.9999996981F, 0.9999997732F, 0.9999998333F, + 0.9999998805F, 0.9999999170F, 0.9999999444F, 0.9999999643F, + 0.9999999784F, 0.9999999878F, 0.9999999937F, 0.9999999972F, + 0.9999999990F, 0.9999999997F, 1.0000000000F, 1.0000000000F, +}; + +static const float vwin4096[2048] = { + 0.0000002310F, 0.0000020791F, 0.0000057754F, 0.0000113197F, + 0.0000187121F, 0.0000279526F, 0.0000390412F, 0.0000519777F, + 0.0000667623F, 0.0000833949F, 0.0001018753F, 0.0001222036F, + 0.0001443798F, 0.0001684037F, 0.0001942754F, 0.0002219947F, + 0.0002515616F, 0.0002829761F, 0.0003162380F, 0.0003513472F, + 0.0003883038F, 0.0004271076F, 0.0004677584F, 0.0005102563F, + 0.0005546011F, 0.0006007928F, 0.0006488311F, 0.0006987160F, + 0.0007504474F, 0.0008040251F, 0.0008594490F, 0.0009167191F, + 0.0009758351F, 0.0010367969F, 0.0010996044F, 0.0011642574F, + 0.0012307558F, 0.0012990994F, 0.0013692880F, 0.0014413216F, + 0.0015151998F, 0.0015909226F, 0.0016684898F, 0.0017479011F, + 0.0018291565F, 0.0019122556F, 0.0019971983F, 0.0020839845F, + 0.0021726138F, 0.0022630861F, 0.0023554012F, 0.0024495588F, + 0.0025455588F, 0.0026434008F, 0.0027430847F, 0.0028446103F, + 0.0029479772F, 0.0030531853F, 0.0031602342F, 0.0032691238F, + 0.0033798538F, 0.0034924239F, 0.0036068338F, 0.0037230833F, + 0.0038411721F, 0.0039610999F, 0.0040828664F, 0.0042064714F, + 0.0043319145F, 0.0044591954F, 0.0045883139F, 0.0047192696F, + 0.0048520622F, 0.0049866914F, 0.0051231569F, 0.0052614583F, + 0.0054015953F, 0.0055435676F, 0.0056873748F, 0.0058330166F, + 0.0059804926F, 0.0061298026F, 0.0062809460F, 0.0064339226F, + 0.0065887320F, 0.0067453738F, 0.0069038476F, 0.0070641531F, + 0.0072262899F, 0.0073902575F, 0.0075560556F, 0.0077236838F, + 0.0078931417F, 0.0080644288F, 0.0082375447F, 0.0084124891F, + 0.0085892615F, 0.0087678614F, 0.0089482885F, 0.0091305422F, + 0.0093146223F, 0.0095005281F, 0.0096882592F, 0.0098778153F, + 0.0100691958F, 0.0102624002F, 0.0104574281F, 0.0106542791F, + 0.0108529525F, 0.0110534480F, 0.0112557651F, 0.0114599032F, + 0.0116658618F, 0.0118736405F, 0.0120832387F, 0.0122946560F, + 0.0125078917F, 0.0127229454F, 0.0129398166F, 0.0131585046F, + 0.0133790090F, 0.0136013292F, 0.0138254647F, 0.0140514149F, + 0.0142791792F, 0.0145087572F, 0.0147401481F, 0.0149733515F, + 0.0152083667F, 0.0154451932F, 0.0156838304F, 0.0159242777F, + 0.0161665345F, 0.0164106001F, 0.0166564741F, 0.0169041557F, + 0.0171536443F, 0.0174049393F, 0.0176580401F, 0.0179129461F, + 0.0181696565F, 0.0184281708F, 0.0186884883F, 0.0189506084F, + 0.0192145303F, 0.0194802535F, 0.0197477772F, 0.0200171008F, + 0.0202882236F, 0.0205611449F, 0.0208358639F, 0.0211123801F, + 0.0213906927F, 0.0216708011F, 0.0219527043F, 0.0222364019F, + 0.0225218930F, 0.0228091769F, 0.0230982529F, 0.0233891203F, + 0.0236817782F, 0.0239762259F, 0.0242724628F, 0.0245704880F, + 0.0248703007F, 0.0251719002F, 0.0254752858F, 0.0257804565F, + 0.0260874117F, 0.0263961506F, 0.0267066722F, 0.0270189760F, + 0.0273330609F, 0.0276489263F, 0.0279665712F, 0.0282859949F, + 0.0286071966F, 0.0289301753F, 0.0292549303F, 0.0295814607F, + 0.0299097656F, 0.0302398442F, 0.0305716957F, 0.0309053191F, + 0.0312407135F, 0.0315778782F, 0.0319168122F, 0.0322575145F, + 0.0325999844F, 0.0329442209F, 0.0332902231F, 0.0336379900F, + 0.0339875208F, 0.0343388146F, 0.0346918703F, 0.0350466871F, + 0.0354032640F, 0.0357616000F, 0.0361216943F, 0.0364835458F, + 0.0368471535F, 0.0372125166F, 0.0375796339F, 0.0379485046F, + 0.0383191276F, 0.0386915020F, 0.0390656267F, 0.0394415008F, + 0.0398191231F, 0.0401984927F, 0.0405796086F, 0.0409624698F, + 0.0413470751F, 0.0417334235F, 0.0421215141F, 0.0425113457F, + 0.0429029172F, 0.0432962277F, 0.0436912760F, 0.0440880610F, + 0.0444865817F, 0.0448868370F, 0.0452888257F, 0.0456925468F, + 0.0460979992F, 0.0465051816F, 0.0469140931F, 0.0473247325F, + 0.0477370986F, 0.0481511902F, 0.0485670064F, 0.0489845458F, + 0.0494038074F, 0.0498247899F, 0.0502474922F, 0.0506719131F, + 0.0510980514F, 0.0515259060F, 0.0519554756F, 0.0523867590F, + 0.0528197550F, 0.0532544624F, 0.0536908800F, 0.0541290066F, + 0.0545688408F, 0.0550103815F, 0.0554536274F, 0.0558985772F, + 0.0563452297F, 0.0567935837F, 0.0572436377F, 0.0576953907F, + 0.0581488412F, 0.0586039880F, 0.0590608297F, 0.0595193651F, + 0.0599795929F, 0.0604415117F, 0.0609051202F, 0.0613704170F, + 0.0618374009F, 0.0623060704F, 0.0627764243F, 0.0632484611F, + 0.0637221795F, 0.0641975781F, 0.0646746555F, 0.0651534104F, + 0.0656338413F, 0.0661159469F, 0.0665997257F, 0.0670851763F, + 0.0675722973F, 0.0680610873F, 0.0685515448F, 0.0690436684F, + 0.0695374567F, 0.0700329081F, 0.0705300213F, 0.0710287947F, + 0.0715292269F, 0.0720313163F, 0.0725350616F, 0.0730404612F, + 0.0735475136F, 0.0740562172F, 0.0745665707F, 0.0750785723F, + 0.0755922207F, 0.0761075143F, 0.0766244515F, 0.0771430307F, + 0.0776632505F, 0.0781851092F, 0.0787086052F, 0.0792337371F, + 0.0797605032F, 0.0802889018F, 0.0808189315F, 0.0813505905F, + 0.0818838773F, 0.0824187903F, 0.0829553277F, 0.0834934881F, + 0.0840332697F, 0.0845746708F, 0.0851176899F, 0.0856623252F, + 0.0862085751F, 0.0867564379F, 0.0873059119F, 0.0878569954F, + 0.0884096867F, 0.0889639840F, 0.0895198858F, 0.0900773902F, + 0.0906364955F, 0.0911972000F, 0.0917595019F, 0.0923233995F, + 0.0928888909F, 0.0934559745F, 0.0940246485F, 0.0945949110F, + 0.0951667604F, 0.0957401946F, 0.0963152121F, 0.0968918109F, + 0.0974699893F, 0.0980497454F, 0.0986310773F, 0.0992139832F, + 0.0997984614F, 0.1003845098F, 0.1009721267F, 0.1015613101F, + 0.1021520582F, 0.1027443692F, 0.1033382410F, 0.1039336718F, + 0.1045306597F, 0.1051292027F, 0.1057292990F, 0.1063309466F, + 0.1069341435F, 0.1075388878F, 0.1081451776F, 0.1087530108F, + 0.1093623856F, 0.1099732998F, 0.1105857516F, 0.1111997389F, + 0.1118152597F, 0.1124323121F, 0.1130508939F, 0.1136710032F, + 0.1142926379F, 0.1149157960F, 0.1155404755F, 0.1161666742F, + 0.1167943901F, 0.1174236211F, 0.1180543652F, 0.1186866202F, + 0.1193203841F, 0.1199556548F, 0.1205924300F, 0.1212307078F, + 0.1218704860F, 0.1225117624F, 0.1231545349F, 0.1237988013F, + 0.1244445596F, 0.1250918074F, 0.1257405427F, 0.1263907632F, + 0.1270424667F, 0.1276956512F, 0.1283503142F, 0.1290064537F, + 0.1296640674F, 0.1303231530F, 0.1309837084F, 0.1316457312F, + 0.1323092193F, 0.1329741703F, 0.1336405820F, 0.1343084520F, + 0.1349777782F, 0.1356485582F, 0.1363207897F, 0.1369944704F, + 0.1376695979F, 0.1383461700F, 0.1390241842F, 0.1397036384F, + 0.1403845300F, 0.1410668567F, 0.1417506162F, 0.1424358061F, + 0.1431224240F, 0.1438104674F, 0.1444999341F, 0.1451908216F, + 0.1458831274F, 0.1465768492F, 0.1472719844F, 0.1479685308F, + 0.1486664857F, 0.1493658468F, 0.1500666115F, 0.1507687775F, + 0.1514723422F, 0.1521773031F, 0.1528836577F, 0.1535914035F, + 0.1543005380F, 0.1550110587F, 0.1557229631F, 0.1564362485F, + 0.1571509124F, 0.1578669524F, 0.1585843657F, 0.1593031499F, + 0.1600233024F, 0.1607448205F, 0.1614677017F, 0.1621919433F, + 0.1629175428F, 0.1636444975F, 0.1643728047F, 0.1651024619F, + 0.1658334665F, 0.1665658156F, 0.1672995067F, 0.1680345371F, + 0.1687709041F, 0.1695086050F, 0.1702476372F, 0.1709879978F, + 0.1717296843F, 0.1724726938F, 0.1732170237F, 0.1739626711F, + 0.1747096335F, 0.1754579079F, 0.1762074916F, 0.1769583819F, + 0.1777105760F, 0.1784640710F, 0.1792188642F, 0.1799749529F, + 0.1807323340F, 0.1814910049F, 0.1822509628F, 0.1830122046F, + 0.1837747277F, 0.1845385292F, 0.1853036062F, 0.1860699558F, + 0.1868375751F, 0.1876064613F, 0.1883766114F, 0.1891480226F, + 0.1899206919F, 0.1906946164F, 0.1914697932F, 0.1922462194F, + 0.1930238919F, 0.1938028079F, 0.1945829643F, 0.1953643583F, + 0.1961469868F, 0.1969308468F, 0.1977159353F, 0.1985022494F, + 0.1992897859F, 0.2000785420F, 0.2008685145F, 0.2016597005F, + 0.2024520968F, 0.2032457005F, 0.2040405084F, 0.2048365175F, + 0.2056337247F, 0.2064321269F, 0.2072317211F, 0.2080325041F, + 0.2088344727F, 0.2096376240F, 0.2104419547F, 0.2112474618F, + 0.2120541420F, 0.2128619923F, 0.2136710094F, 0.2144811902F, + 0.2152925315F, 0.2161050301F, 0.2169186829F, 0.2177334866F, + 0.2185494381F, 0.2193665340F, 0.2201847712F, 0.2210041465F, + 0.2218246565F, 0.2226462981F, 0.2234690680F, 0.2242929629F, + 0.2251179796F, 0.2259441147F, 0.2267713650F, 0.2275997272F, + 0.2284291979F, 0.2292597739F, 0.2300914518F, 0.2309242283F, + 0.2317581001F, 0.2325930638F, 0.2334291160F, 0.2342662534F, + 0.2351044727F, 0.2359437703F, 0.2367841431F, 0.2376255875F, + 0.2384681001F, 0.2393116776F, 0.2401563165F, 0.2410020134F, + 0.2418487649F, 0.2426965675F, 0.2435454178F, 0.2443953122F, + 0.2452462474F, 0.2460982199F, 0.2469512262F, 0.2478052628F, + 0.2486603262F, 0.2495164129F, 0.2503735194F, 0.2512316421F, + 0.2520907776F, 0.2529509222F, 0.2538120726F, 0.2546742250F, + 0.2555373760F, 0.2564015219F, 0.2572666593F, 0.2581327845F, + 0.2589998939F, 0.2598679840F, 0.2607370510F, 0.2616070916F, + 0.2624781019F, 0.2633500783F, 0.2642230173F, 0.2650969152F, + 0.2659717684F, 0.2668475731F, 0.2677243257F, 0.2686020226F, + 0.2694806601F, 0.2703602344F, 0.2712407419F, 0.2721221789F, + 0.2730045417F, 0.2738878265F, 0.2747720297F, 0.2756571474F, + 0.2765431760F, 0.2774301117F, 0.2783179508F, 0.2792066895F, + 0.2800963240F, 0.2809868505F, 0.2818782654F, 0.2827705647F, + 0.2836637447F, 0.2845578016F, 0.2854527315F, 0.2863485307F, + 0.2872451953F, 0.2881427215F, 0.2890411055F, 0.2899403433F, + 0.2908404312F, 0.2917413654F, 0.2926431418F, 0.2935457567F, + 0.2944492061F, 0.2953534863F, 0.2962585932F, 0.2971645230F, + 0.2980712717F, 0.2989788356F, 0.2998872105F, 0.3007963927F, + 0.3017063781F, 0.3026171629F, 0.3035287430F, 0.3044411145F, + 0.3053542736F, 0.3062682161F, 0.3071829381F, 0.3080984356F, + 0.3090147047F, 0.3099317413F, 0.3108495414F, 0.3117681011F, + 0.3126874163F, 0.3136074830F, 0.3145282972F, 0.3154498548F, + 0.3163721517F, 0.3172951841F, 0.3182189477F, 0.3191434385F, + 0.3200686525F, 0.3209945856F, 0.3219212336F, 0.3228485927F, + 0.3237766585F, 0.3247054271F, 0.3256348943F, 0.3265650560F, + 0.3274959081F, 0.3284274465F, 0.3293596671F, 0.3302925657F, + 0.3312261382F, 0.3321603804F, 0.3330952882F, 0.3340308574F, + 0.3349670838F, 0.3359039634F, 0.3368414919F, 0.3377796651F, + 0.3387184789F, 0.3396579290F, 0.3405980113F, 0.3415387216F, + 0.3424800556F, 0.3434220091F, 0.3443645779F, 0.3453077578F, + 0.3462515446F, 0.3471959340F, 0.3481409217F, 0.3490865036F, + 0.3500326754F, 0.3509794328F, 0.3519267715F, 0.3528746873F, + 0.3538231759F, 0.3547722330F, 0.3557218544F, 0.3566720357F, + 0.3576227727F, 0.3585740610F, 0.3595258964F, 0.3604782745F, + 0.3614311910F, 0.3623846417F, 0.3633386221F, 0.3642931280F, + 0.3652481549F, 0.3662036987F, 0.3671597548F, 0.3681163191F, + 0.3690733870F, 0.3700309544F, 0.3709890167F, 0.3719475696F, + 0.3729066089F, 0.3738661299F, 0.3748261285F, 0.3757866002F, + 0.3767475406F, 0.3777089453F, 0.3786708100F, 0.3796331302F, + 0.3805959014F, 0.3815591194F, 0.3825227796F, 0.3834868777F, + 0.3844514093F, 0.3854163698F, 0.3863817549F, 0.3873475601F, + 0.3883137810F, 0.3892804131F, 0.3902474521F, 0.3912148933F, + 0.3921827325F, 0.3931509650F, 0.3941195865F, 0.3950885925F, + 0.3960579785F, 0.3970277400F, 0.3979978725F, 0.3989683716F, + 0.3999392328F, 0.4009104516F, 0.4018820234F, 0.4028539438F, + 0.4038262084F, 0.4047988125F, 0.4057717516F, 0.4067450214F, + 0.4077186172F, 0.4086925345F, 0.4096667688F, 0.4106413155F, + 0.4116161703F, 0.4125913284F, 0.4135667854F, 0.4145425368F, + 0.4155185780F, 0.4164949044F, 0.4174715116F, 0.4184483949F, + 0.4194255498F, 0.4204029718F, 0.4213806563F, 0.4223585987F, + 0.4233367946F, 0.4243152392F, 0.4252939281F, 0.4262728566F, + 0.4272520202F, 0.4282314144F, 0.4292110345F, 0.4301908760F, + 0.4311709343F, 0.4321512047F, 0.4331316828F, 0.4341123639F, + 0.4350932435F, 0.4360743168F, 0.4370555794F, 0.4380370267F, + 0.4390186540F, 0.4400004567F, 0.4409824303F, 0.4419645701F, + 0.4429468716F, 0.4439293300F, 0.4449119409F, 0.4458946996F, + 0.4468776014F, 0.4478606418F, 0.4488438162F, 0.4498271199F, + 0.4508105483F, 0.4517940967F, 0.4527777607F, 0.4537615355F, + 0.4547454165F, 0.4557293991F, 0.4567134786F, 0.4576976505F, + 0.4586819101F, 0.4596662527F, 0.4606506738F, 0.4616351687F, + 0.4626197328F, 0.4636043614F, 0.4645890499F, 0.4655737936F, + 0.4665585880F, 0.4675434284F, 0.4685283101F, 0.4695132286F, + 0.4704981791F, 0.4714831570F, 0.4724681577F, 0.4734531766F, + 0.4744382089F, 0.4754232501F, 0.4764082956F, 0.4773933406F, + 0.4783783806F, 0.4793634108F, 0.4803484267F, 0.4813334237F, + 0.4823183969F, 0.4833033419F, 0.4842882540F, 0.4852731285F, + 0.4862579608F, 0.4872427462F, 0.4882274802F, 0.4892121580F, + 0.4901967751F, 0.4911813267F, 0.4921658083F, 0.4931502151F, + 0.4941345427F, 0.4951187863F, 0.4961029412F, 0.4970870029F, + 0.4980709667F, 0.4990548280F, 0.5000385822F, 0.5010222245F, + 0.5020057505F, 0.5029891553F, 0.5039724345F, 0.5049555834F, + 0.5059385973F, 0.5069214716F, 0.5079042018F, 0.5088867831F, + 0.5098692110F, 0.5108514808F, 0.5118335879F, 0.5128155277F, + 0.5137972956F, 0.5147788869F, 0.5157602971F, 0.5167415215F, + 0.5177225555F, 0.5187033945F, 0.5196840339F, 0.5206644692F, + 0.5216446956F, 0.5226247086F, 0.5236045035F, 0.5245840759F, + 0.5255634211F, 0.5265425344F, 0.5275214114F, 0.5285000474F, + 0.5294784378F, 0.5304565781F, 0.5314344637F, 0.5324120899F, + 0.5333894522F, 0.5343665461F, 0.5353433670F, 0.5363199102F, + 0.5372961713F, 0.5382721457F, 0.5392478287F, 0.5402232159F, + 0.5411983027F, 0.5421730845F, 0.5431475569F, 0.5441217151F, + 0.5450955548F, 0.5460690714F, 0.5470422602F, 0.5480151169F, + 0.5489876368F, 0.5499598155F, 0.5509316484F, 0.5519031310F, + 0.5528742587F, 0.5538450271F, 0.5548154317F, 0.5557854680F, + 0.5567551314F, 0.5577244174F, 0.5586933216F, 0.5596618395F, + 0.5606299665F, 0.5615976983F, 0.5625650302F, 0.5635319580F, + 0.5644984770F, 0.5654645828F, 0.5664302709F, 0.5673955370F, + 0.5683603765F, 0.5693247850F, 0.5702887580F, 0.5712522912F, + 0.5722153800F, 0.5731780200F, 0.5741402069F, 0.5751019362F, + 0.5760632034F, 0.5770240042F, 0.5779843341F, 0.5789441889F, + 0.5799035639F, 0.5808624549F, 0.5818208575F, 0.5827787673F, + 0.5837361800F, 0.5846930910F, 0.5856494961F, 0.5866053910F, + 0.5875607712F, 0.5885156324F, 0.5894699703F, 0.5904237804F, + 0.5913770586F, 0.5923298004F, 0.5932820016F, 0.5942336578F, + 0.5951847646F, 0.5961353179F, 0.5970853132F, 0.5980347464F, + 0.5989836131F, 0.5999319090F, 0.6008796298F, 0.6018267713F, + 0.6027733292F, 0.6037192993F, 0.6046646773F, 0.6056094589F, + 0.6065536400F, 0.6074972162F, 0.6084401833F, 0.6093825372F, + 0.6103242736F, 0.6112653884F, 0.6122058772F, 0.6131457359F, + 0.6140849604F, 0.6150235464F, 0.6159614897F, 0.6168987862F, + 0.6178354318F, 0.6187714223F, 0.6197067535F, 0.6206414213F, + 0.6215754215F, 0.6225087501F, 0.6234414028F, 0.6243733757F, + 0.6253046646F, 0.6262352654F, 0.6271651739F, 0.6280943862F, + 0.6290228982F, 0.6299507057F, 0.6308778048F, 0.6318041913F, + 0.6327298612F, 0.6336548105F, 0.6345790352F, 0.6355025312F, + 0.6364252945F, 0.6373473211F, 0.6382686070F, 0.6391891483F, + 0.6401089409F, 0.6410279808F, 0.6419462642F, 0.6428637869F, + 0.6437805452F, 0.6446965350F, 0.6456117524F, 0.6465261935F, + 0.6474398544F, 0.6483527311F, 0.6492648197F, 0.6501761165F, + 0.6510866174F, 0.6519963186F, 0.6529052162F, 0.6538133064F, + 0.6547205854F, 0.6556270492F, 0.6565326941F, 0.6574375162F, + 0.6583415117F, 0.6592446769F, 0.6601470079F, 0.6610485009F, + 0.6619491521F, 0.6628489578F, 0.6637479143F, 0.6646460177F, + 0.6655432643F, 0.6664396505F, 0.6673351724F, 0.6682298264F, + 0.6691236087F, 0.6700165157F, 0.6709085436F, 0.6717996889F, + 0.6726899478F, 0.6735793167F, 0.6744677918F, 0.6753553697F, + 0.6762420466F, 0.6771278190F, 0.6780126832F, 0.6788966357F, + 0.6797796728F, 0.6806617909F, 0.6815429866F, 0.6824232562F, + 0.6833025961F, 0.6841810030F, 0.6850584731F, 0.6859350031F, + 0.6868105894F, 0.6876852284F, 0.6885589168F, 0.6894316510F, + 0.6903034275F, 0.6911742430F, 0.6920440939F, 0.6929129769F, + 0.6937808884F, 0.6946478251F, 0.6955137837F, 0.6963787606F, + 0.6972427525F, 0.6981057560F, 0.6989677678F, 0.6998287845F, + 0.7006888028F, 0.7015478194F, 0.7024058309F, 0.7032628340F, + 0.7041188254F, 0.7049738019F, 0.7058277601F, 0.7066806969F, + 0.7075326089F, 0.7083834929F, 0.7092333457F, 0.7100821640F, + 0.7109299447F, 0.7117766846F, 0.7126223804F, 0.7134670291F, + 0.7143106273F, 0.7151531721F, 0.7159946602F, 0.7168350885F, + 0.7176744539F, 0.7185127534F, 0.7193499837F, 0.7201861418F, + 0.7210212247F, 0.7218552293F, 0.7226881526F, 0.7235199914F, + 0.7243507428F, 0.7251804039F, 0.7260089715F, 0.7268364426F, + 0.7276628144F, 0.7284880839F, 0.7293122481F, 0.7301353040F, + 0.7309572487F, 0.7317780794F, 0.7325977930F, 0.7334163868F, + 0.7342338579F, 0.7350502033F, 0.7358654202F, 0.7366795059F, + 0.7374924573F, 0.7383042718F, 0.7391149465F, 0.7399244787F, + 0.7407328655F, 0.7415401041F, 0.7423461920F, 0.7431511261F, + 0.7439549040F, 0.7447575227F, 0.7455589797F, 0.7463592723F, + 0.7471583976F, 0.7479563532F, 0.7487531363F, 0.7495487443F, + 0.7503431745F, 0.7511364244F, 0.7519284913F, 0.7527193726F, + 0.7535090658F, 0.7542975683F, 0.7550848776F, 0.7558709910F, + 0.7566559062F, 0.7574396205F, 0.7582221314F, 0.7590034366F, + 0.7597835334F, 0.7605624194F, 0.7613400923F, 0.7621165495F, + 0.7628917886F, 0.7636658072F, 0.7644386030F, 0.7652101735F, + 0.7659805164F, 0.7667496292F, 0.7675175098F, 0.7682841556F, + 0.7690495645F, 0.7698137341F, 0.7705766622F, 0.7713383463F, + 0.7720987844F, 0.7728579741F, 0.7736159132F, 0.7743725994F, + 0.7751280306F, 0.7758822046F, 0.7766351192F, 0.7773867722F, + 0.7781371614F, 0.7788862848F, 0.7796341401F, 0.7803807253F, + 0.7811260383F, 0.7818700769F, 0.7826128392F, 0.7833543230F, + 0.7840945263F, 0.7848334471F, 0.7855710833F, 0.7863074330F, + 0.7870424941F, 0.7877762647F, 0.7885087428F, 0.7892399264F, + 0.7899698137F, 0.7906984026F, 0.7914256914F, 0.7921516780F, + 0.7928763607F, 0.7935997375F, 0.7943218065F, 0.7950425661F, + 0.7957620142F, 0.7964801492F, 0.7971969692F, 0.7979124724F, + 0.7986266570F, 0.7993395214F, 0.8000510638F, 0.8007612823F, + 0.8014701754F, 0.8021777413F, 0.8028839784F, 0.8035888849F, + 0.8042924592F, 0.8049946997F, 0.8056956048F, 0.8063951727F, + 0.8070934020F, 0.8077902910F, 0.8084858381F, 0.8091800419F, + 0.8098729007F, 0.8105644130F, 0.8112545774F, 0.8119433922F, + 0.8126308561F, 0.8133169676F, 0.8140017251F, 0.8146851272F, + 0.8153671726F, 0.8160478598F, 0.8167271874F, 0.8174051539F, + 0.8180817582F, 0.8187569986F, 0.8194308741F, 0.8201033831F, + 0.8207745244F, 0.8214442966F, 0.8221126986F, 0.8227797290F, + 0.8234453865F, 0.8241096700F, 0.8247725781F, 0.8254341097F, + 0.8260942636F, 0.8267530385F, 0.8274104334F, 0.8280664470F, + 0.8287210782F, 0.8293743259F, 0.8300261889F, 0.8306766662F, + 0.8313257566F, 0.8319734591F, 0.8326197727F, 0.8332646963F, + 0.8339082288F, 0.8345503692F, 0.8351911167F, 0.8358304700F, + 0.8364684284F, 0.8371049907F, 0.8377401562F, 0.8383739238F, + 0.8390062927F, 0.8396372618F, 0.8402668305F, 0.8408949977F, + 0.8415217626F, 0.8421471245F, 0.8427710823F, 0.8433936354F, + 0.8440147830F, 0.8446345242F, 0.8452528582F, 0.8458697844F, + 0.8464853020F, 0.8470994102F, 0.8477121084F, 0.8483233958F, + 0.8489332718F, 0.8495417356F, 0.8501487866F, 0.8507544243F, + 0.8513586479F, 0.8519614568F, 0.8525628505F, 0.8531628283F, + 0.8537613897F, 0.8543585341F, 0.8549542611F, 0.8555485699F, + 0.8561414603F, 0.8567329315F, 0.8573229832F, 0.8579116149F, + 0.8584988262F, 0.8590846165F, 0.8596689855F, 0.8602519327F, + 0.8608334577F, 0.8614135603F, 0.8619922399F, 0.8625694962F, + 0.8631453289F, 0.8637197377F, 0.8642927222F, 0.8648642821F, + 0.8654344172F, 0.8660031272F, 0.8665704118F, 0.8671362708F, + 0.8677007039F, 0.8682637109F, 0.8688252917F, 0.8693854460F, + 0.8699441737F, 0.8705014745F, 0.8710573485F, 0.8716117953F, + 0.8721648150F, 0.8727164073F, 0.8732665723F, 0.8738153098F, + 0.8743626197F, 0.8749085021F, 0.8754529569F, 0.8759959840F, + 0.8765375835F, 0.8770777553F, 0.8776164996F, 0.8781538162F, + 0.8786897054F, 0.8792241670F, 0.8797572013F, 0.8802888082F, + 0.8808189880F, 0.8813477407F, 0.8818750664F, 0.8824009653F, + 0.8829254375F, 0.8834484833F, 0.8839701028F, 0.8844902961F, + 0.8850090636F, 0.8855264054F, 0.8860423218F, 0.8865568131F, + 0.8870698794F, 0.8875815212F, 0.8880917386F, 0.8886005319F, + 0.8891079016F, 0.8896138479F, 0.8901183712F, 0.8906214719F, + 0.8911231503F, 0.8916234067F, 0.8921222417F, 0.8926196556F, + 0.8931156489F, 0.8936102219F, 0.8941033752F, 0.8945951092F, + 0.8950854244F, 0.8955743212F, 0.8960618003F, 0.8965478621F, + 0.8970325071F, 0.8975157359F, 0.8979975490F, 0.8984779471F, + 0.8989569307F, 0.8994345004F, 0.8999106568F, 0.9003854005F, + 0.9008587323F, 0.9013306526F, 0.9018011623F, 0.9022702619F, + 0.9027379521F, 0.9032042337F, 0.9036691074F, 0.9041325739F, + 0.9045946339F, 0.9050552882F, 0.9055145376F, 0.9059723828F, + 0.9064288246F, 0.9068838638F, 0.9073375013F, 0.9077897379F, + 0.9082405743F, 0.9086900115F, 0.9091380503F, 0.9095846917F, + 0.9100299364F, 0.9104737854F, 0.9109162397F, 0.9113573001F, + 0.9117969675F, 0.9122352430F, 0.9126721275F, 0.9131076219F, + 0.9135417273F, 0.9139744447F, 0.9144057750F, 0.9148357194F, + 0.9152642787F, 0.9156914542F, 0.9161172468F, 0.9165416576F, + 0.9169646877F, 0.9173863382F, 0.9178066102F, 0.9182255048F, + 0.9186430232F, 0.9190591665F, 0.9194739359F, 0.9198873324F, + 0.9202993574F, 0.9207100120F, 0.9211192973F, 0.9215272147F, + 0.9219337653F, 0.9223389504F, 0.9227427713F, 0.9231452290F, + 0.9235463251F, 0.9239460607F, 0.9243444371F, 0.9247414557F, + 0.9251371177F, 0.9255314245F, 0.9259243774F, 0.9263159778F, + 0.9267062270F, 0.9270951264F, 0.9274826774F, 0.9278688814F, + 0.9282537398F, 0.9286372540F, 0.9290194254F, 0.9294002555F, + 0.9297797458F, 0.9301578976F, 0.9305347125F, 0.9309101919F, + 0.9312843373F, 0.9316571503F, 0.9320286323F, 0.9323987849F, + 0.9327676097F, 0.9331351080F, 0.9335012816F, 0.9338661320F, + 0.9342296607F, 0.9345918694F, 0.9349527596F, 0.9353123330F, + 0.9356705911F, 0.9360275357F, 0.9363831683F, 0.9367374905F, + 0.9370905042F, 0.9374422108F, 0.9377926122F, 0.9381417099F, + 0.9384895057F, 0.9388360014F, 0.9391811985F, 0.9395250989F, + 0.9398677043F, 0.9402090165F, 0.9405490371F, 0.9408877680F, + 0.9412252110F, 0.9415613678F, 0.9418962402F, 0.9422298301F, + 0.9425621392F, 0.9428931695F, 0.9432229226F, 0.9435514005F, + 0.9438786050F, 0.9442045381F, 0.9445292014F, 0.9448525971F, + 0.9451747268F, 0.9454955926F, 0.9458151963F, 0.9461335399F, + 0.9464506253F, 0.9467664545F, 0.9470810293F, 0.9473943517F, + 0.9477064238F, 0.9480172474F, 0.9483268246F, 0.9486351573F, + 0.9489422475F, 0.9492480973F, 0.9495527087F, 0.9498560837F, + 0.9501582243F, 0.9504591325F, 0.9507588105F, 0.9510572603F, + 0.9513544839F, 0.9516504834F, 0.9519452609F, 0.9522388186F, + 0.9525311584F, 0.9528222826F, 0.9531121932F, 0.9534008923F, + 0.9536883821F, 0.9539746647F, 0.9542597424F, 0.9545436171F, + 0.9548262912F, 0.9551077667F, 0.9553880459F, 0.9556671309F, + 0.9559450239F, 0.9562217272F, 0.9564972429F, 0.9567715733F, + 0.9570447206F, 0.9573166871F, 0.9575874749F, 0.9578570863F, + 0.9581255236F, 0.9583927890F, 0.9586588849F, 0.9589238134F, + 0.9591875769F, 0.9594501777F, 0.9597116180F, 0.9599719003F, + 0.9602310267F, 0.9604889995F, 0.9607458213F, 0.9610014942F, + 0.9612560206F, 0.9615094028F, 0.9617616433F, 0.9620127443F, + 0.9622627083F, 0.9625115376F, 0.9627592345F, 0.9630058016F, + 0.9632512411F, 0.9634955555F, 0.9637387471F, 0.9639808185F, + 0.9642217720F, 0.9644616100F, 0.9647003349F, 0.9649379493F, + 0.9651744556F, 0.9654098561F, 0.9656441534F, 0.9658773499F, + 0.9661094480F, 0.9663404504F, 0.9665703593F, 0.9667991774F, + 0.9670269071F, 0.9672535509F, 0.9674791114F, 0.9677035909F, + 0.9679269921F, 0.9681493174F, 0.9683705694F, 0.9685907506F, + 0.9688098636F, 0.9690279108F, 0.9692448948F, 0.9694608182F, + 0.9696756836F, 0.9698894934F, 0.9701022503F, 0.9703139569F, + 0.9705246156F, 0.9707342291F, 0.9709428000F, 0.9711503309F, + 0.9713568243F, 0.9715622829F, 0.9717667093F, 0.9719701060F, + 0.9721724757F, 0.9723738210F, 0.9725741446F, 0.9727734490F, + 0.9729717369F, 0.9731690109F, 0.9733652737F, 0.9735605279F, + 0.9737547762F, 0.9739480212F, 0.9741402656F, 0.9743315120F, + 0.9745217631F, 0.9747110216F, 0.9748992901F, 0.9750865714F, + 0.9752728681F, 0.9754581829F, 0.9756425184F, 0.9758258775F, + 0.9760082627F, 0.9761896768F, 0.9763701224F, 0.9765496024F, + 0.9767281193F, 0.9769056760F, 0.9770822751F, 0.9772579193F, + 0.9774326114F, 0.9776063542F, 0.9777791502F, 0.9779510023F, + 0.9781219133F, 0.9782918858F, 0.9784609226F, 0.9786290264F, + 0.9787962000F, 0.9789624461F, 0.9791277676F, 0.9792921671F, + 0.9794556474F, 0.9796182113F, 0.9797798615F, 0.9799406009F, + 0.9801004321F, 0.9802593580F, 0.9804173813F, 0.9805745049F, + 0.9807307314F, 0.9808860637F, 0.9810405046F, 0.9811940568F, + 0.9813467232F, 0.9814985065F, 0.9816494095F, 0.9817994351F, + 0.9819485860F, 0.9820968650F, 0.9822442750F, 0.9823908186F, + 0.9825364988F, 0.9826813184F, 0.9828252801F, 0.9829683868F, + 0.9831106413F, 0.9832520463F, 0.9833926048F, 0.9835323195F, + 0.9836711932F, 0.9838092288F, 0.9839464291F, 0.9840827969F, + 0.9842183351F, 0.9843530464F, 0.9844869337F, 0.9846199998F, + 0.9847522475F, 0.9848836798F, 0.9850142993F, 0.9851441090F, + 0.9852731117F, 0.9854013101F, 0.9855287073F, 0.9856553058F, + 0.9857811087F, 0.9859061188F, 0.9860303388F, 0.9861537717F, + 0.9862764202F, 0.9863982872F, 0.9865193756F, 0.9866396882F, + 0.9867592277F, 0.9868779972F, 0.9869959993F, 0.9871132370F, + 0.9872297131F, 0.9873454304F, 0.9874603918F, 0.9875746001F, + 0.9876880581F, 0.9878007688F, 0.9879127348F, 0.9880239592F, + 0.9881344447F, 0.9882441941F, 0.9883532104F, 0.9884614962F, + 0.9885690546F, 0.9886758883F, 0.9887820001F, 0.9888873930F, + 0.9889920697F, 0.9890960331F, 0.9891992859F, 0.9893018312F, + 0.9894036716F, 0.9895048100F, 0.9896052493F, 0.9897049923F, + 0.9898040418F, 0.9899024006F, 0.9900000717F, 0.9900970577F, + 0.9901933616F, 0.9902889862F, 0.9903839343F, 0.9904782087F, + 0.9905718122F, 0.9906647477F, 0.9907570180F, 0.9908486259F, + 0.9909395742F, 0.9910298658F, 0.9911195034F, 0.9912084899F, + 0.9912968281F, 0.9913845208F, 0.9914715708F, 0.9915579810F, + 0.9916437540F, 0.9917288928F, 0.9918134001F, 0.9918972788F, + 0.9919805316F, 0.9920631613F, 0.9921451707F, 0.9922265626F, + 0.9923073399F, 0.9923875052F, 0.9924670615F, 0.9925460114F, + 0.9926243577F, 0.9927021033F, 0.9927792508F, 0.9928558032F, + 0.9929317631F, 0.9930071333F, 0.9930819167F, 0.9931561158F, + 0.9932297337F, 0.9933027728F, 0.9933752362F, 0.9934471264F, + 0.9935184462F, 0.9935891985F, 0.9936593859F, 0.9937290112F, + 0.9937980771F, 0.9938665864F, 0.9939345418F, 0.9940019460F, + 0.9940688018F, 0.9941351118F, 0.9942008789F, 0.9942661057F, + 0.9943307950F, 0.9943949494F, 0.9944585717F, 0.9945216645F, + 0.9945842307F, 0.9946462728F, 0.9947077936F, 0.9947687957F, + 0.9948292820F, 0.9948892550F, 0.9949487174F, 0.9950076719F, + 0.9950661212F, 0.9951240679F, 0.9951815148F, 0.9952384645F, + 0.9952949196F, 0.9953508828F, 0.9954063568F, 0.9954613442F, + 0.9955158476F, 0.9955698697F, 0.9956234132F, 0.9956764806F, + 0.9957290746F, 0.9957811978F, 0.9958328528F, 0.9958840423F, + 0.9959347688F, 0.9959850351F, 0.9960348435F, 0.9960841969F, + 0.9961330977F, 0.9961815486F, 0.9962295521F, 0.9962771108F, + 0.9963242274F, 0.9963709043F, 0.9964171441F, 0.9964629494F, + 0.9965083228F, 0.9965532668F, 0.9965977840F, 0.9966418768F, + 0.9966855479F, 0.9967287998F, 0.9967716350F, 0.9968140559F, + 0.9968560653F, 0.9968976655F, 0.9969388591F, 0.9969796485F, + 0.9970200363F, 0.9970600250F, 0.9970996170F, 0.9971388149F, + 0.9971776211F, 0.9972160380F, 0.9972540683F, 0.9972917142F, + 0.9973289783F, 0.9973658631F, 0.9974023709F, 0.9974385042F, + 0.9974742655F, 0.9975096571F, 0.9975446816F, 0.9975793413F, + 0.9976136386F, 0.9976475759F, 0.9976811557F, 0.9977143803F, + 0.9977472521F, 0.9977797736F, 0.9978119470F, 0.9978437748F, + 0.9978752593F, 0.9979064029F, 0.9979372079F, 0.9979676768F, + 0.9979978117F, 0.9980276151F, 0.9980570893F, 0.9980862367F, + 0.9981150595F, 0.9981435600F, 0.9981717406F, 0.9981996035F, + 0.9982271511F, 0.9982543856F, 0.9982813093F, 0.9983079246F, + 0.9983342336F, 0.9983602386F, 0.9983859418F, 0.9984113456F, + 0.9984364522F, 0.9984612638F, 0.9984857825F, 0.9985100108F, + 0.9985339507F, 0.9985576044F, 0.9985809743F, 0.9986040624F, + 0.9986268710F, 0.9986494022F, 0.9986716583F, 0.9986936413F, + 0.9987153535F, 0.9987367969F, 0.9987579738F, 0.9987788864F, + 0.9987995366F, 0.9988199267F, 0.9988400587F, 0.9988599348F, + 0.9988795572F, 0.9988989278F, 0.9989180487F, 0.9989369222F, + 0.9989555501F, 0.9989739347F, 0.9989920780F, 0.9990099820F, + 0.9990276487F, 0.9990450803F, 0.9990622787F, 0.9990792460F, + 0.9990959841F, 0.9991124952F, 0.9991287812F, 0.9991448440F, + 0.9991606858F, 0.9991763084F, 0.9991917139F, 0.9992069042F, + 0.9992218813F, 0.9992366471F, 0.9992512035F, 0.9992655525F, + 0.9992796961F, 0.9992936361F, 0.9993073744F, 0.9993209131F, + 0.9993342538F, 0.9993473987F, 0.9993603494F, 0.9993731080F, + 0.9993856762F, 0.9993980559F, 0.9994102490F, 0.9994222573F, + 0.9994340827F, 0.9994457269F, 0.9994571918F, 0.9994684793F, + 0.9994795910F, 0.9994905288F, 0.9995012945F, 0.9995118898F, + 0.9995223165F, 0.9995325765F, 0.9995426713F, 0.9995526029F, + 0.9995623728F, 0.9995719829F, 0.9995814349F, 0.9995907304F, + 0.9995998712F, 0.9996088590F, 0.9996176954F, 0.9996263821F, + 0.9996349208F, 0.9996433132F, 0.9996515609F, 0.9996596656F, + 0.9996676288F, 0.9996754522F, 0.9996831375F, 0.9996906862F, + 0.9996981000F, 0.9997053804F, 0.9997125290F, 0.9997195474F, + 0.9997264371F, 0.9997331998F, 0.9997398369F, 0.9997463500F, + 0.9997527406F, 0.9997590103F, 0.9997651606F, 0.9997711930F, + 0.9997771089F, 0.9997829098F, 0.9997885973F, 0.9997941728F, + 0.9997996378F, 0.9998049936F, 0.9998102419F, 0.9998153839F, + 0.9998204211F, 0.9998253550F, 0.9998301868F, 0.9998349182F, + 0.9998395503F, 0.9998440847F, 0.9998485226F, 0.9998528654F, + 0.9998571146F, 0.9998612713F, 0.9998653370F, 0.9998693130F, + 0.9998732007F, 0.9998770012F, 0.9998807159F, 0.9998843461F, + 0.9998878931F, 0.9998913581F, 0.9998947424F, 0.9998980473F, + 0.9999012740F, 0.9999044237F, 0.9999074976F, 0.9999104971F, + 0.9999134231F, 0.9999162771F, 0.9999190601F, 0.9999217733F, + 0.9999244179F, 0.9999269950F, 0.9999295058F, 0.9999319515F, + 0.9999343332F, 0.9999366519F, 0.9999389088F, 0.9999411050F, + 0.9999432416F, 0.9999453196F, 0.9999473402F, 0.9999493044F, + 0.9999512132F, 0.9999530677F, 0.9999548690F, 0.9999566180F, + 0.9999583157F, 0.9999599633F, 0.9999615616F, 0.9999631116F, + 0.9999646144F, 0.9999660709F, 0.9999674820F, 0.9999688487F, + 0.9999701719F, 0.9999714526F, 0.9999726917F, 0.9999738900F, + 0.9999750486F, 0.9999761682F, 0.9999772497F, 0.9999782941F, + 0.9999793021F, 0.9999802747F, 0.9999812126F, 0.9999821167F, + 0.9999829878F, 0.9999838268F, 0.9999846343F, 0.9999854113F, + 0.9999861584F, 0.9999868765F, 0.9999875664F, 0.9999882287F, + 0.9999888642F, 0.9999894736F, 0.9999900577F, 0.9999906172F, + 0.9999911528F, 0.9999916651F, 0.9999921548F, 0.9999926227F, + 0.9999930693F, 0.9999934954F, 0.9999939015F, 0.9999942883F, + 0.9999946564F, 0.9999950064F, 0.9999953390F, 0.9999956547F, + 0.9999959541F, 0.9999962377F, 0.9999965062F, 0.9999967601F, + 0.9999969998F, 0.9999972260F, 0.9999974392F, 0.9999976399F, + 0.9999978285F, 0.9999980056F, 0.9999981716F, 0.9999983271F, + 0.9999984724F, 0.9999986081F, 0.9999987345F, 0.9999988521F, + 0.9999989613F, 0.9999990625F, 0.9999991562F, 0.9999992426F, + 0.9999993223F, 0.9999993954F, 0.9999994625F, 0.9999995239F, + 0.9999995798F, 0.9999996307F, 0.9999996768F, 0.9999997184F, + 0.9999997559F, 0.9999997895F, 0.9999998195F, 0.9999998462F, + 0.9999998698F, 0.9999998906F, 0.9999999088F, 0.9999999246F, + 0.9999999383F, 0.9999999500F, 0.9999999600F, 0.9999999684F, + 0.9999999754F, 0.9999999811F, 0.9999999858F, 0.9999999896F, + 0.9999999925F, 0.9999999948F, 0.9999999965F, 0.9999999978F, + 0.9999999986F, 0.9999999992F, 0.9999999996F, 0.9999999998F, + 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F, +}; + +static const float vwin8192[4096] = { + 0.0000000578F, 0.0000005198F, 0.0000014438F, 0.0000028299F, + 0.0000046780F, 0.0000069882F, 0.0000097604F, 0.0000129945F, + 0.0000166908F, 0.0000208490F, 0.0000254692F, 0.0000305515F, + 0.0000360958F, 0.0000421021F, 0.0000485704F, 0.0000555006F, + 0.0000628929F, 0.0000707472F, 0.0000790635F, 0.0000878417F, + 0.0000970820F, 0.0001067842F, 0.0001169483F, 0.0001275744F, + 0.0001386625F, 0.0001502126F, 0.0001622245F, 0.0001746984F, + 0.0001876343F, 0.0002010320F, 0.0002148917F, 0.0002292132F, + 0.0002439967F, 0.0002592421F, 0.0002749493F, 0.0002911184F, + 0.0003077493F, 0.0003248421F, 0.0003423967F, 0.0003604132F, + 0.0003788915F, 0.0003978316F, 0.0004172335F, 0.0004370971F, + 0.0004574226F, 0.0004782098F, 0.0004994587F, 0.0005211694F, + 0.0005433418F, 0.0005659759F, 0.0005890717F, 0.0006126292F, + 0.0006366484F, 0.0006611292F, 0.0006860716F, 0.0007114757F, + 0.0007373414F, 0.0007636687F, 0.0007904576F, 0.0008177080F, + 0.0008454200F, 0.0008735935F, 0.0009022285F, 0.0009313250F, + 0.0009608830F, 0.0009909025F, 0.0010213834F, 0.0010523257F, + 0.0010837295F, 0.0011155946F, 0.0011479211F, 0.0011807090F, + 0.0012139582F, 0.0012476687F, 0.0012818405F, 0.0013164736F, + 0.0013515679F, 0.0013871235F, 0.0014231402F, 0.0014596182F, + 0.0014965573F, 0.0015339576F, 0.0015718190F, 0.0016101415F, + 0.0016489251F, 0.0016881698F, 0.0017278754F, 0.0017680421F, + 0.0018086698F, 0.0018497584F, 0.0018913080F, 0.0019333185F, + 0.0019757898F, 0.0020187221F, 0.0020621151F, 0.0021059690F, + 0.0021502837F, 0.0021950591F, 0.0022402953F, 0.0022859921F, + 0.0023321497F, 0.0023787679F, 0.0024258467F, 0.0024733861F, + 0.0025213861F, 0.0025698466F, 0.0026187676F, 0.0026681491F, + 0.0027179911F, 0.0027682935F, 0.0028190562F, 0.0028702794F, + 0.0029219628F, 0.0029741066F, 0.0030267107F, 0.0030797749F, + 0.0031332994F, 0.0031872841F, 0.0032417289F, 0.0032966338F, + 0.0033519988F, 0.0034078238F, 0.0034641089F, 0.0035208539F, + 0.0035780589F, 0.0036357237F, 0.0036938485F, 0.0037524331F, + 0.0038114775F, 0.0038709817F, 0.0039309456F, 0.0039913692F, + 0.0040522524F, 0.0041135953F, 0.0041753978F, 0.0042376599F, + 0.0043003814F, 0.0043635624F, 0.0044272029F, 0.0044913028F, + 0.0045558620F, 0.0046208806F, 0.0046863585F, 0.0047522955F, + 0.0048186919F, 0.0048855473F, 0.0049528619F, 0.0050206356F, + 0.0050888684F, 0.0051575601F, 0.0052267108F, 0.0052963204F, + 0.0053663890F, 0.0054369163F, 0.0055079025F, 0.0055793474F, + 0.0056512510F, 0.0057236133F, 0.0057964342F, 0.0058697137F, + 0.0059434517F, 0.0060176482F, 0.0060923032F, 0.0061674166F, + 0.0062429883F, 0.0063190183F, 0.0063955066F, 0.0064724532F, + 0.0065498579F, 0.0066277207F, 0.0067060416F, 0.0067848205F, + 0.0068640575F, 0.0069437523F, 0.0070239051F, 0.0071045157F, + 0.0071855840F, 0.0072671102F, 0.0073490940F, 0.0074315355F, + 0.0075144345F, 0.0075977911F, 0.0076816052F, 0.0077658768F, + 0.0078506057F, 0.0079357920F, 0.0080214355F, 0.0081075363F, + 0.0081940943F, 0.0082811094F, 0.0083685816F, 0.0084565108F, + 0.0085448970F, 0.0086337401F, 0.0087230401F, 0.0088127969F, + 0.0089030104F, 0.0089936807F, 0.0090848076F, 0.0091763911F, + 0.0092684311F, 0.0093609276F, 0.0094538805F, 0.0095472898F, + 0.0096411554F, 0.0097354772F, 0.0098302552F, 0.0099254894F, + 0.0100211796F, 0.0101173259F, 0.0102139281F, 0.0103109863F, + 0.0104085002F, 0.0105064700F, 0.0106048955F, 0.0107037766F, + 0.0108031133F, 0.0109029056F, 0.0110031534F, 0.0111038565F, + 0.0112050151F, 0.0113066289F, 0.0114086980F, 0.0115112222F, + 0.0116142015F, 0.0117176359F, 0.0118215252F, 0.0119258695F, + 0.0120306686F, 0.0121359225F, 0.0122416312F, 0.0123477944F, + 0.0124544123F, 0.0125614847F, 0.0126690116F, 0.0127769928F, + 0.0128854284F, 0.0129943182F, 0.0131036623F, 0.0132134604F, + 0.0133237126F, 0.0134344188F, 0.0135455790F, 0.0136571929F, + 0.0137692607F, 0.0138817821F, 0.0139947572F, 0.0141081859F, + 0.0142220681F, 0.0143364037F, 0.0144511927F, 0.0145664350F, + 0.0146821304F, 0.0147982791F, 0.0149148808F, 0.0150319355F, + 0.0151494431F, 0.0152674036F, 0.0153858168F, 0.0155046828F, + 0.0156240014F, 0.0157437726F, 0.0158639962F, 0.0159846723F, + 0.0161058007F, 0.0162273814F, 0.0163494142F, 0.0164718991F, + 0.0165948361F, 0.0167182250F, 0.0168420658F, 0.0169663584F, + 0.0170911027F, 0.0172162987F, 0.0173419462F, 0.0174680452F, + 0.0175945956F, 0.0177215974F, 0.0178490504F, 0.0179769545F, + 0.0181053098F, 0.0182341160F, 0.0183633732F, 0.0184930812F, + 0.0186232399F, 0.0187538494F, 0.0188849094F, 0.0190164200F, + 0.0191483809F, 0.0192807923F, 0.0194136539F, 0.0195469656F, + 0.0196807275F, 0.0198149394F, 0.0199496012F, 0.0200847128F, + 0.0202202742F, 0.0203562853F, 0.0204927460F, 0.0206296561F, + 0.0207670157F, 0.0209048245F, 0.0210430826F, 0.0211817899F, + 0.0213209462F, 0.0214605515F, 0.0216006057F, 0.0217411086F, + 0.0218820603F, 0.0220234605F, 0.0221653093F, 0.0223076066F, + 0.0224503521F, 0.0225935459F, 0.0227371879F, 0.0228812779F, + 0.0230258160F, 0.0231708018F, 0.0233162355F, 0.0234621169F, + 0.0236084459F, 0.0237552224F, 0.0239024462F, 0.0240501175F, + 0.0241982359F, 0.0243468015F, 0.0244958141F, 0.0246452736F, + 0.0247951800F, 0.0249455331F, 0.0250963329F, 0.0252475792F, + 0.0253992720F, 0.0255514111F, 0.0257039965F, 0.0258570281F, + 0.0260105057F, 0.0261644293F, 0.0263187987F, 0.0264736139F, + 0.0266288747F, 0.0267845811F, 0.0269407330F, 0.0270973302F, + 0.0272543727F, 0.0274118604F, 0.0275697930F, 0.0277281707F, + 0.0278869932F, 0.0280462604F, 0.0282059723F, 0.0283661287F, + 0.0285267295F, 0.0286877747F, 0.0288492641F, 0.0290111976F, + 0.0291735751F, 0.0293363965F, 0.0294996617F, 0.0296633706F, + 0.0298275231F, 0.0299921190F, 0.0301571583F, 0.0303226409F, + 0.0304885667F, 0.0306549354F, 0.0308217472F, 0.0309890017F, + 0.0311566989F, 0.0313248388F, 0.0314934211F, 0.0316624459F, + 0.0318319128F, 0.0320018220F, 0.0321721732F, 0.0323429663F, + 0.0325142013F, 0.0326858779F, 0.0328579962F, 0.0330305559F, + 0.0332035570F, 0.0333769994F, 0.0335508829F, 0.0337252074F, + 0.0338999728F, 0.0340751790F, 0.0342508259F, 0.0344269134F, + 0.0346034412F, 0.0347804094F, 0.0349578178F, 0.0351356663F, + 0.0353139548F, 0.0354926831F, 0.0356718511F, 0.0358514588F, + 0.0360315059F, 0.0362119924F, 0.0363929182F, 0.0365742831F, + 0.0367560870F, 0.0369383297F, 0.0371210113F, 0.0373041315F, + 0.0374876902F, 0.0376716873F, 0.0378561226F, 0.0380409961F, + 0.0382263077F, 0.0384120571F, 0.0385982443F, 0.0387848691F, + 0.0389719315F, 0.0391594313F, 0.0393473683F, 0.0395357425F, + 0.0397245537F, 0.0399138017F, 0.0401034866F, 0.0402936080F, + 0.0404841660F, 0.0406751603F, 0.0408665909F, 0.0410584576F, + 0.0412507603F, 0.0414434988F, 0.0416366731F, 0.0418302829F, + 0.0420243282F, 0.0422188088F, 0.0424137246F, 0.0426090755F, + 0.0428048613F, 0.0430010819F, 0.0431977371F, 0.0433948269F, + 0.0435923511F, 0.0437903095F, 0.0439887020F, 0.0441875285F, + 0.0443867889F, 0.0445864830F, 0.0447866106F, 0.0449871717F, + 0.0451881661F, 0.0453895936F, 0.0455914542F, 0.0457937477F, + 0.0459964738F, 0.0461996326F, 0.0464032239F, 0.0466072475F, + 0.0468117032F, 0.0470165910F, 0.0472219107F, 0.0474276622F, + 0.0476338452F, 0.0478404597F, 0.0480475056F, 0.0482549827F, + 0.0484628907F, 0.0486712297F, 0.0488799994F, 0.0490891998F, + 0.0492988306F, 0.0495088917F, 0.0497193830F, 0.0499303043F, + 0.0501416554F, 0.0503534363F, 0.0505656468F, 0.0507782867F, + 0.0509913559F, 0.0512048542F, 0.0514187815F, 0.0516331376F, + 0.0518479225F, 0.0520631358F, 0.0522787775F, 0.0524948475F, + 0.0527113455F, 0.0529282715F, 0.0531456252F, 0.0533634066F, + 0.0535816154F, 0.0538002515F, 0.0540193148F, 0.0542388051F, + 0.0544587222F, 0.0546790660F, 0.0548998364F, 0.0551210331F, + 0.0553426561F, 0.0555647051F, 0.0557871801F, 0.0560100807F, + 0.0562334070F, 0.0564571587F, 0.0566813357F, 0.0569059378F, + 0.0571309649F, 0.0573564168F, 0.0575822933F, 0.0578085942F, + 0.0580353195F, 0.0582624689F, 0.0584900423F, 0.0587180396F, + 0.0589464605F, 0.0591753049F, 0.0594045726F, 0.0596342635F, + 0.0598643774F, 0.0600949141F, 0.0603258735F, 0.0605572555F, + 0.0607890597F, 0.0610212862F, 0.0612539346F, 0.0614870049F, + 0.0617204968F, 0.0619544103F, 0.0621887451F, 0.0624235010F, + 0.0626586780F, 0.0628942758F, 0.0631302942F, 0.0633667331F, + 0.0636035923F, 0.0638408717F, 0.0640785710F, 0.0643166901F, + 0.0645552288F, 0.0647941870F, 0.0650335645F, 0.0652733610F, + 0.0655135765F, 0.0657542108F, 0.0659952636F, 0.0662367348F, + 0.0664786242F, 0.0667209316F, 0.0669636570F, 0.0672068000F, + 0.0674503605F, 0.0676943384F, 0.0679387334F, 0.0681835454F, + 0.0684287742F, 0.0686744196F, 0.0689204814F, 0.0691669595F, + 0.0694138536F, 0.0696611637F, 0.0699088894F, 0.0701570307F, + 0.0704055873F, 0.0706545590F, 0.0709039458F, 0.0711537473F, + 0.0714039634F, 0.0716545939F, 0.0719056387F, 0.0721570975F, + 0.0724089702F, 0.0726612565F, 0.0729139563F, 0.0731670694F, + 0.0734205956F, 0.0736745347F, 0.0739288866F, 0.0741836510F, + 0.0744388277F, 0.0746944166F, 0.0749504175F, 0.0752068301F, + 0.0754636543F, 0.0757208899F, 0.0759785367F, 0.0762365946F, + 0.0764950632F, 0.0767539424F, 0.0770132320F, 0.0772729319F, + 0.0775330418F, 0.0777935616F, 0.0780544909F, 0.0783158298F, + 0.0785775778F, 0.0788397349F, 0.0791023009F, 0.0793652755F, + 0.0796286585F, 0.0798924498F, 0.0801566492F, 0.0804212564F, + 0.0806862712F, 0.0809516935F, 0.0812175231F, 0.0814837597F, + 0.0817504031F, 0.0820174532F, 0.0822849097F, 0.0825527724F, + 0.0828210412F, 0.0830897158F, 0.0833587960F, 0.0836282816F, + 0.0838981724F, 0.0841684682F, 0.0844391688F, 0.0847102740F, + 0.0849817835F, 0.0852536973F, 0.0855260150F, 0.0857987364F, + 0.0860718614F, 0.0863453897F, 0.0866193211F, 0.0868936554F, + 0.0871683924F, 0.0874435319F, 0.0877190737F, 0.0879950175F, + 0.0882713632F, 0.0885481105F, 0.0888252592F, 0.0891028091F, + 0.0893807600F, 0.0896591117F, 0.0899378639F, 0.0902170165F, + 0.0904965692F, 0.0907765218F, 0.0910568740F, 0.0913376258F, + 0.0916187767F, 0.0919003268F, 0.0921822756F, 0.0924646230F, + 0.0927473687F, 0.0930305126F, 0.0933140545F, 0.0935979940F, + 0.0938823310F, 0.0941670653F, 0.0944521966F, 0.0947377247F, + 0.0950236494F, 0.0953099704F, 0.0955966876F, 0.0958838007F, + 0.0961713094F, 0.0964592136F, 0.0967475131F, 0.0970362075F, + 0.0973252967F, 0.0976147805F, 0.0979046585F, 0.0981949307F, + 0.0984855967F, 0.0987766563F, 0.0990681093F, 0.0993599555F, + 0.0996521945F, 0.0999448263F, 0.1002378506F, 0.1005312671F, + 0.1008250755F, 0.1011192757F, 0.1014138675F, 0.1017088505F, + 0.1020042246F, 0.1022999895F, 0.1025961450F, 0.1028926909F, + 0.1031896268F, 0.1034869526F, 0.1037846680F, 0.1040827729F, + 0.1043812668F, 0.1046801497F, 0.1049794213F, 0.1052790813F, + 0.1055791294F, 0.1058795656F, 0.1061803894F, 0.1064816006F, + 0.1067831991F, 0.1070851846F, 0.1073875568F, 0.1076903155F, + 0.1079934604F, 0.1082969913F, 0.1086009079F, 0.1089052101F, + 0.1092098975F, 0.1095149699F, 0.1098204270F, 0.1101262687F, + 0.1104324946F, 0.1107391045F, 0.1110460982F, 0.1113534754F, + 0.1116612359F, 0.1119693793F, 0.1122779055F, 0.1125868142F, + 0.1128961052F, 0.1132057781F, 0.1135158328F, 0.1138262690F, + 0.1141370863F, 0.1144482847F, 0.1147598638F, 0.1150718233F, + 0.1153841631F, 0.1156968828F, 0.1160099822F, 0.1163234610F, + 0.1166373190F, 0.1169515559F, 0.1172661714F, 0.1175811654F, + 0.1178965374F, 0.1182122874F, 0.1185284149F, 0.1188449198F, + 0.1191618018F, 0.1194790606F, 0.1197966960F, 0.1201147076F, + 0.1204330953F, 0.1207518587F, 0.1210709976F, 0.1213905118F, + 0.1217104009F, 0.1220306647F, 0.1223513029F, 0.1226723153F, + 0.1229937016F, 0.1233154615F, 0.1236375948F, 0.1239601011F, + 0.1242829803F, 0.1246062319F, 0.1249298559F, 0.1252538518F, + 0.1255782195F, 0.1259029586F, 0.1262280689F, 0.1265535501F, + 0.1268794019F, 0.1272056241F, 0.1275322163F, 0.1278591784F, + 0.1281865099F, 0.1285142108F, 0.1288422805F, 0.1291707190F, + 0.1294995259F, 0.1298287009F, 0.1301582437F, 0.1304881542F, + 0.1308184319F, 0.1311490766F, 0.1314800881F, 0.1318114660F, + 0.1321432100F, 0.1324753200F, 0.1328077955F, 0.1331406364F, + 0.1334738422F, 0.1338074129F, 0.1341413479F, 0.1344756472F, + 0.1348103103F, 0.1351453370F, 0.1354807270F, 0.1358164801F, + 0.1361525959F, 0.1364890741F, 0.1368259145F, 0.1371631167F, + 0.1375006805F, 0.1378386056F, 0.1381768917F, 0.1385155384F, + 0.1388545456F, 0.1391939129F, 0.1395336400F, 0.1398737266F, + 0.1402141724F, 0.1405549772F, 0.1408961406F, 0.1412376623F, + 0.1415795421F, 0.1419217797F, 0.1422643746F, 0.1426073268F, + 0.1429506358F, 0.1432943013F, 0.1436383231F, 0.1439827008F, + 0.1443274342F, 0.1446725229F, 0.1450179667F, 0.1453637652F, + 0.1457099181F, 0.1460564252F, 0.1464032861F, 0.1467505006F, + 0.1470980682F, 0.1474459888F, 0.1477942620F, 0.1481428875F, + 0.1484918651F, 0.1488411942F, 0.1491908748F, 0.1495409065F, + 0.1498912889F, 0.1502420218F, 0.1505931048F, 0.1509445376F, + 0.1512963200F, 0.1516484516F, 0.1520009321F, 0.1523537612F, + 0.1527069385F, 0.1530604638F, 0.1534143368F, 0.1537685571F, + 0.1541231244F, 0.1544780384F, 0.1548332987F, 0.1551889052F, + 0.1555448574F, 0.1559011550F, 0.1562577978F, 0.1566147853F, + 0.1569721173F, 0.1573297935F, 0.1576878135F, 0.1580461771F, + 0.1584048838F, 0.1587639334F, 0.1591233255F, 0.1594830599F, + 0.1598431361F, 0.1602035540F, 0.1605643131F, 0.1609254131F, + 0.1612868537F, 0.1616486346F, 0.1620107555F, 0.1623732160F, + 0.1627360158F, 0.1630991545F, 0.1634626319F, 0.1638264476F, + 0.1641906013F, 0.1645550926F, 0.1649199212F, 0.1652850869F, + 0.1656505892F, 0.1660164278F, 0.1663826024F, 0.1667491127F, + 0.1671159583F, 0.1674831388F, 0.1678506541F, 0.1682185036F, + 0.1685866872F, 0.1689552044F, 0.1693240549F, 0.1696932384F, + 0.1700627545F, 0.1704326029F, 0.1708027833F, 0.1711732952F, + 0.1715441385F, 0.1719153127F, 0.1722868175F, 0.1726586526F, + 0.1730308176F, 0.1734033121F, 0.1737761359F, 0.1741492886F, + 0.1745227698F, 0.1748965792F, 0.1752707164F, 0.1756451812F, + 0.1760199731F, 0.1763950918F, 0.1767705370F, 0.1771463083F, + 0.1775224054F, 0.1778988279F, 0.1782755754F, 0.1786526477F, + 0.1790300444F, 0.1794077651F, 0.1797858094F, 0.1801641771F, + 0.1805428677F, 0.1809218810F, 0.1813012165F, 0.1816808739F, + 0.1820608528F, 0.1824411530F, 0.1828217739F, 0.1832027154F, + 0.1835839770F, 0.1839655584F, 0.1843474592F, 0.1847296790F, + 0.1851122175F, 0.1854950744F, 0.1858782492F, 0.1862617417F, + 0.1866455514F, 0.1870296780F, 0.1874141211F, 0.1877988804F, + 0.1881839555F, 0.1885693461F, 0.1889550517F, 0.1893410721F, + 0.1897274068F, 0.1901140555F, 0.1905010178F, 0.1908882933F, + 0.1912758818F, 0.1916637828F, 0.1920519959F, 0.1924405208F, + 0.1928293571F, 0.1932185044F, 0.1936079625F, 0.1939977308F, + 0.1943878091F, 0.1947781969F, 0.1951688939F, 0.1955598998F, + 0.1959512141F, 0.1963428364F, 0.1967347665F, 0.1971270038F, + 0.1975195482F, 0.1979123990F, 0.1983055561F, 0.1986990190F, + 0.1990927873F, 0.1994868607F, 0.1998812388F, 0.2002759212F, + 0.2006709075F, 0.2010661974F, 0.2014617904F, 0.2018576862F, + 0.2022538844F, 0.2026503847F, 0.2030471865F, 0.2034442897F, + 0.2038416937F, 0.2042393982F, 0.2046374028F, 0.2050357071F, + 0.2054343107F, 0.2058332133F, 0.2062324145F, 0.2066319138F, + 0.2070317110F, 0.2074318055F, 0.2078321970F, 0.2082328852F, + 0.2086338696F, 0.2090351498F, 0.2094367255F, 0.2098385962F, + 0.2102407617F, 0.2106432213F, 0.2110459749F, 0.2114490220F, + 0.2118523621F, 0.2122559950F, 0.2126599202F, 0.2130641373F, + 0.2134686459F, 0.2138734456F, 0.2142785361F, 0.2146839168F, + 0.2150895875F, 0.2154955478F, 0.2159017972F, 0.2163083353F, + 0.2167151617F, 0.2171222761F, 0.2175296780F, 0.2179373670F, + 0.2183453428F, 0.2187536049F, 0.2191621529F, 0.2195709864F, + 0.2199801051F, 0.2203895085F, 0.2207991961F, 0.2212091677F, + 0.2216194228F, 0.2220299610F, 0.2224407818F, 0.2228518850F, + 0.2232632699F, 0.2236749364F, 0.2240868839F, 0.2244991121F, + 0.2249116204F, 0.2253244086F, 0.2257374763F, 0.2261508229F, + 0.2265644481F, 0.2269783514F, 0.2273925326F, 0.2278069911F, + 0.2282217265F, 0.2286367384F, 0.2290520265F, 0.2294675902F, + 0.2298834292F, 0.2302995431F, 0.2307159314F, 0.2311325937F, + 0.2315495297F, 0.2319667388F, 0.2323842207F, 0.2328019749F, + 0.2332200011F, 0.2336382988F, 0.2340568675F, 0.2344757070F, + 0.2348948166F, 0.2353141961F, 0.2357338450F, 0.2361537629F, + 0.2365739493F, 0.2369944038F, 0.2374151261F, 0.2378361156F, + 0.2382573720F, 0.2386788948F, 0.2391006836F, 0.2395227380F, + 0.2399450575F, 0.2403676417F, 0.2407904902F, 0.2412136026F, + 0.2416369783F, 0.2420606171F, 0.2424845185F, 0.2429086820F, + 0.2433331072F, 0.2437577936F, 0.2441827409F, 0.2446079486F, + 0.2450334163F, 0.2454591435F, 0.2458851298F, 0.2463113747F, + 0.2467378779F, 0.2471646389F, 0.2475916573F, 0.2480189325F, + 0.2484464643F, 0.2488742521F, 0.2493022955F, 0.2497305940F, + 0.2501591473F, 0.2505879549F, 0.2510170163F, 0.2514463311F, + 0.2518758989F, 0.2523057193F, 0.2527357916F, 0.2531661157F, + 0.2535966909F, 0.2540275169F, 0.2544585931F, 0.2548899193F, + 0.2553214948F, 0.2557533193F, 0.2561853924F, 0.2566177135F, + 0.2570502822F, 0.2574830981F, 0.2579161608F, 0.2583494697F, + 0.2587830245F, 0.2592168246F, 0.2596508697F, 0.2600851593F, + 0.2605196929F, 0.2609544701F, 0.2613894904F, 0.2618247534F, + 0.2622602586F, 0.2626960055F, 0.2631319938F, 0.2635682230F, + 0.2640046925F, 0.2644414021F, 0.2648783511F, 0.2653155391F, + 0.2657529657F, 0.2661906305F, 0.2666285329F, 0.2670666725F, + 0.2675050489F, 0.2679436616F, 0.2683825101F, 0.2688215940F, + 0.2692609127F, 0.2697004660F, 0.2701402532F, 0.2705802739F, + 0.2710205278F, 0.2714610142F, 0.2719017327F, 0.2723426830F, + 0.2727838644F, 0.2732252766F, 0.2736669191F, 0.2741087914F, + 0.2745508930F, 0.2749932235F, 0.2754357824F, 0.2758785693F, + 0.2763215837F, 0.2767648251F, 0.2772082930F, 0.2776519870F, + 0.2780959066F, 0.2785400513F, 0.2789844207F, 0.2794290143F, + 0.2798738316F, 0.2803188722F, 0.2807641355F, 0.2812096211F, + 0.2816553286F, 0.2821012574F, 0.2825474071F, 0.2829937773F, + 0.2834403673F, 0.2838871768F, 0.2843342053F, 0.2847814523F, + 0.2852289174F, 0.2856765999F, 0.2861244996F, 0.2865726159F, + 0.2870209482F, 0.2874694962F, 0.2879182594F, 0.2883672372F, + 0.2888164293F, 0.2892658350F, 0.2897154540F, 0.2901652858F, + 0.2906153298F, 0.2910655856F, 0.2915160527F, 0.2919667306F, + 0.2924176189F, 0.2928687171F, 0.2933200246F, 0.2937715409F, + 0.2942232657F, 0.2946751984F, 0.2951273386F, 0.2955796856F, + 0.2960322391F, 0.2964849986F, 0.2969379636F, 0.2973911335F, + 0.2978445080F, 0.2982980864F, 0.2987518684F, 0.2992058534F, + 0.2996600409F, 0.3001144305F, 0.3005690217F, 0.3010238139F, + 0.3014788067F, 0.3019339995F, 0.3023893920F, 0.3028449835F, + 0.3033007736F, 0.3037567618F, 0.3042129477F, 0.3046693306F, + 0.3051259102F, 0.3055826859F, 0.3060396572F, 0.3064968236F, + 0.3069541847F, 0.3074117399F, 0.3078694887F, 0.3083274307F, + 0.3087855653F, 0.3092438920F, 0.3097024104F, 0.3101611199F, + 0.3106200200F, 0.3110791103F, 0.3115383902F, 0.3119978592F, + 0.3124575169F, 0.3129173627F, 0.3133773961F, 0.3138376166F, + 0.3142980238F, 0.3147586170F, 0.3152193959F, 0.3156803598F, + 0.3161415084F, 0.3166028410F, 0.3170643573F, 0.3175260566F, + 0.3179879384F, 0.3184500023F, 0.3189122478F, 0.3193746743F, + 0.3198372814F, 0.3203000685F, 0.3207630351F, 0.3212261807F, + 0.3216895048F, 0.3221530069F, 0.3226166865F, 0.3230805430F, + 0.3235445760F, 0.3240087849F, 0.3244731693F, 0.3249377285F, + 0.3254024622F, 0.3258673698F, 0.3263324507F, 0.3267977045F, + 0.3272631306F, 0.3277287286F, 0.3281944978F, 0.3286604379F, + 0.3291265482F, 0.3295928284F, 0.3300592777F, 0.3305258958F, + 0.3309926821F, 0.3314596361F, 0.3319267573F, 0.3323940451F, + 0.3328614990F, 0.3333291186F, 0.3337969033F, 0.3342648525F, + 0.3347329658F, 0.3352012427F, 0.3356696825F, 0.3361382849F, + 0.3366070492F, 0.3370759749F, 0.3375450616F, 0.3380143087F, + 0.3384837156F, 0.3389532819F, 0.3394230071F, 0.3398928905F, + 0.3403629317F, 0.3408331302F, 0.3413034854F, 0.3417739967F, + 0.3422446638F, 0.3427154860F, 0.3431864628F, 0.3436575938F, + 0.3441288782F, 0.3446003158F, 0.3450719058F, 0.3455436478F, + 0.3460155412F, 0.3464875856F, 0.3469597804F, 0.3474321250F, + 0.3479046189F, 0.3483772617F, 0.3488500527F, 0.3493229914F, + 0.3497960774F, 0.3502693100F, 0.3507426887F, 0.3512162131F, + 0.3516898825F, 0.3521636965F, 0.3526376545F, 0.3531117559F, + 0.3535860003F, 0.3540603870F, 0.3545349157F, 0.3550095856F, + 0.3554843964F, 0.3559593474F, 0.3564344381F, 0.3569096680F, + 0.3573850366F, 0.3578605432F, 0.3583361875F, 0.3588119687F, + 0.3592878865F, 0.3597639402F, 0.3602401293F, 0.3607164533F, + 0.3611929117F, 0.3616695038F, 0.3621462292F, 0.3626230873F, + 0.3631000776F, 0.3635771995F, 0.3640544525F, 0.3645318360F, + 0.3650093496F, 0.3654869926F, 0.3659647645F, 0.3664426648F, + 0.3669206930F, 0.3673988484F, 0.3678771306F, 0.3683555390F, + 0.3688340731F, 0.3693127322F, 0.3697915160F, 0.3702704237F, + 0.3707494549F, 0.3712286091F, 0.3717078857F, 0.3721872840F, + 0.3726668037F, 0.3731464441F, 0.3736262047F, 0.3741060850F, + 0.3745860843F, 0.3750662023F, 0.3755464382F, 0.3760267915F, + 0.3765072618F, 0.3769878484F, 0.3774685509F, 0.3779493686F, + 0.3784303010F, 0.3789113475F, 0.3793925076F, 0.3798737809F, + 0.3803551666F, 0.3808366642F, 0.3813182733F, 0.3817999932F, + 0.3822818234F, 0.3827637633F, 0.3832458124F, 0.3837279702F, + 0.3842102360F, 0.3846926093F, 0.3851750897F, 0.3856576764F, + 0.3861403690F, 0.3866231670F, 0.3871060696F, 0.3875890765F, + 0.3880721870F, 0.3885554007F, 0.3890387168F, 0.3895221349F, + 0.3900056544F, 0.3904892748F, 0.3909729955F, 0.3914568160F, + 0.3919407356F, 0.3924247539F, 0.3929088702F, 0.3933930841F, + 0.3938773949F, 0.3943618021F, 0.3948463052F, 0.3953309035F, + 0.3958155966F, 0.3963003838F, 0.3967852646F, 0.3972702385F, + 0.3977553048F, 0.3982404631F, 0.3987257127F, 0.3992110531F, + 0.3996964838F, 0.4001820041F, 0.4006676136F, 0.4011533116F, + 0.4016390976F, 0.4021249710F, 0.4026109313F, 0.4030969779F, + 0.4035831102F, 0.4040693277F, 0.4045556299F, 0.4050420160F, + 0.4055284857F, 0.4060150383F, 0.4065016732F, 0.4069883899F, + 0.4074751879F, 0.4079620665F, 0.4084490252F, 0.4089360635F, + 0.4094231807F, 0.4099103763F, 0.4103976498F, 0.4108850005F, + 0.4113724280F, 0.4118599315F, 0.4123475107F, 0.4128351648F, + 0.4133228934F, 0.4138106959F, 0.4142985716F, 0.4147865201F, + 0.4152745408F, 0.4157626330F, 0.4162507963F, 0.4167390301F, + 0.4172273337F, 0.4177157067F, 0.4182041484F, 0.4186926583F, + 0.4191812359F, 0.4196698805F, 0.4201585915F, 0.4206473685F, + 0.4211362108F, 0.4216251179F, 0.4221140892F, 0.4226031241F, + 0.4230922221F, 0.4235813826F, 0.4240706050F, 0.4245598887F, + 0.4250492332F, 0.4255386379F, 0.4260281022F, 0.4265176256F, + 0.4270072075F, 0.4274968473F, 0.4279865445F, 0.4284762984F, + 0.4289661086F, 0.4294559743F, 0.4299458951F, 0.4304358704F, + 0.4309258996F, 0.4314159822F, 0.4319061175F, 0.4323963050F, + 0.4328865441F, 0.4333768342F, 0.4338671749F, 0.4343575654F, + 0.4348480052F, 0.4353384938F, 0.4358290306F, 0.4363196149F, + 0.4368102463F, 0.4373009241F, 0.4377916478F, 0.4382824168F, + 0.4387732305F, 0.4392640884F, 0.4397549899F, 0.4402459343F, + 0.4407369212F, 0.4412279499F, 0.4417190198F, 0.4422101305F, + 0.4427012813F, 0.4431924717F, 0.4436837010F, 0.4441749686F, + 0.4446662742F, 0.4451576169F, 0.4456489963F, 0.4461404118F, + 0.4466318628F, 0.4471233487F, 0.4476148690F, 0.4481064230F, + 0.4485980103F, 0.4490896302F, 0.4495812821F, 0.4500729654F, + 0.4505646797F, 0.4510564243F, 0.4515481986F, 0.4520400021F, + 0.4525318341F, 0.4530236942F, 0.4535155816F, 0.4540074959F, + 0.4544994365F, 0.4549914028F, 0.4554833941F, 0.4559754100F, + 0.4564674499F, 0.4569595131F, 0.4574515991F, 0.4579437074F, + 0.4584358372F, 0.4589279881F, 0.4594201595F, 0.4599123508F, + 0.4604045615F, 0.4608967908F, 0.4613890383F, 0.4618813034F, + 0.4623735855F, 0.4628658841F, 0.4633581984F, 0.4638505281F, + 0.4643428724F, 0.4648352308F, 0.4653276028F, 0.4658199877F, + 0.4663123849F, 0.4668047940F, 0.4672972143F, 0.4677896451F, + 0.4682820861F, 0.4687745365F, 0.4692669958F, 0.4697594634F, + 0.4702519387F, 0.4707444211F, 0.4712369102F, 0.4717294052F, + 0.4722219056F, 0.4727144109F, 0.4732069204F, 0.4736994336F, + 0.4741919498F, 0.4746844686F, 0.4751769893F, 0.4756695113F, + 0.4761620341F, 0.4766545571F, 0.4771470797F, 0.4776396013F, + 0.4781321213F, 0.4786246392F, 0.4791171544F, 0.4796096663F, + 0.4801021744F, 0.4805946779F, 0.4810871765F, 0.4815796694F, + 0.4820721561F, 0.4825646360F, 0.4830571086F, 0.4835495732F, + 0.4840420293F, 0.4845344763F, 0.4850269136F, 0.4855193407F, + 0.4860117569F, 0.4865041617F, 0.4869965545F, 0.4874889347F, + 0.4879813018F, 0.4884736551F, 0.4889659941F, 0.4894583182F, + 0.4899506268F, 0.4904429193F, 0.4909351952F, 0.4914274538F, + 0.4919196947F, 0.4924119172F, 0.4929041207F, 0.4933963046F, + 0.4938884685F, 0.4943806116F, 0.4948727335F, 0.4953648335F, + 0.4958569110F, 0.4963489656F, 0.4968409965F, 0.4973330032F, + 0.4978249852F, 0.4983169419F, 0.4988088726F, 0.4993007768F, + 0.4997926539F, 0.5002845034F, 0.5007763247F, 0.5012681171F, + 0.5017598801F, 0.5022516132F, 0.5027433157F, 0.5032349871F, + 0.5037266268F, 0.5042182341F, 0.5047098086F, 0.5052013497F, + 0.5056928567F, 0.5061843292F, 0.5066757664F, 0.5071671679F, + 0.5076585330F, 0.5081498613F, 0.5086411520F, 0.5091324047F, + 0.5096236187F, 0.5101147934F, 0.5106059284F, 0.5110970230F, + 0.5115880766F, 0.5120790887F, 0.5125700587F, 0.5130609860F, + 0.5135518700F, 0.5140427102F, 0.5145335059F, 0.5150242566F, + 0.5155149618F, 0.5160056208F, 0.5164962331F, 0.5169867980F, + 0.5174773151F, 0.5179677837F, 0.5184582033F, 0.5189485733F, + 0.5194388931F, 0.5199291621F, 0.5204193798F, 0.5209095455F, + 0.5213996588F, 0.5218897190F, 0.5223797256F, 0.5228696779F, + 0.5233595755F, 0.5238494177F, 0.5243392039F, 0.5248289337F, + 0.5253186063F, 0.5258082213F, 0.5262977781F, 0.5267872760F, + 0.5272767146F, 0.5277660932F, 0.5282554112F, 0.5287446682F, + 0.5292338635F, 0.5297229965F, 0.5302120667F, 0.5307010736F, + 0.5311900164F, 0.5316788947F, 0.5321677079F, 0.5326564554F, + 0.5331451366F, 0.5336337511F, 0.5341222981F, 0.5346107771F, + 0.5350991876F, 0.5355875290F, 0.5360758007F, 0.5365640021F, + 0.5370521327F, 0.5375401920F, 0.5380281792F, 0.5385160939F, + 0.5390039355F, 0.5394917034F, 0.5399793971F, 0.5404670159F, + 0.5409545594F, 0.5414420269F, 0.5419294179F, 0.5424167318F, + 0.5429039680F, 0.5433911261F, 0.5438782053F, 0.5443652051F, + 0.5448521250F, 0.5453389644F, 0.5458257228F, 0.5463123995F, + 0.5467989940F, 0.5472855057F, 0.5477719341F, 0.5482582786F, + 0.5487445387F, 0.5492307137F, 0.5497168031F, 0.5502028063F, + 0.5506887228F, 0.5511745520F, 0.5516602934F, 0.5521459463F, + 0.5526315103F, 0.5531169847F, 0.5536023690F, 0.5540876626F, + 0.5545728649F, 0.5550579755F, 0.5555429937F, 0.5560279189F, + 0.5565127507F, 0.5569974884F, 0.5574821315F, 0.5579666794F, + 0.5584511316F, 0.5589354875F, 0.5594197465F, 0.5599039080F, + 0.5603879716F, 0.5608719367F, 0.5613558026F, 0.5618395689F, + 0.5623232350F, 0.5628068002F, 0.5632902642F, 0.5637736262F, + 0.5642568858F, 0.5647400423F, 0.5652230953F, 0.5657060442F, + 0.5661888883F, 0.5666716272F, 0.5671542603F, 0.5676367870F, + 0.5681192069F, 0.5686015192F, 0.5690837235F, 0.5695658192F, + 0.5700478058F, 0.5705296827F, 0.5710114494F, 0.5714931052F, + 0.5719746497F, 0.5724560822F, 0.5729374023F, 0.5734186094F, + 0.5738997029F, 0.5743806823F, 0.5748615470F, 0.5753422965F, + 0.5758229301F, 0.5763034475F, 0.5767838480F, 0.5772641310F, + 0.5777442960F, 0.5782243426F, 0.5787042700F, 0.5791840778F, + 0.5796637654F, 0.5801433322F, 0.5806227778F, 0.5811021016F, + 0.5815813029F, 0.5820603814F, 0.5825393363F, 0.5830181673F, + 0.5834968737F, 0.5839754549F, 0.5844539105F, 0.5849322399F, + 0.5854104425F, 0.5858885179F, 0.5863664653F, 0.5868442844F, + 0.5873219746F, 0.5877995353F, 0.5882769660F, 0.5887542661F, + 0.5892314351F, 0.5897084724F, 0.5901853776F, 0.5906621500F, + 0.5911387892F, 0.5916152945F, 0.5920916655F, 0.5925679016F, + 0.5930440022F, 0.5935199669F, 0.5939957950F, 0.5944714861F, + 0.5949470396F, 0.5954224550F, 0.5958977317F, 0.5963728692F, + 0.5968478669F, 0.5973227244F, 0.5977974411F, 0.5982720163F, + 0.5987464497F, 0.5992207407F, 0.5996948887F, 0.6001688932F, + 0.6006427537F, 0.6011164696F, 0.6015900405F, 0.6020634657F, + 0.6025367447F, 0.6030098770F, 0.6034828621F, 0.6039556995F, + 0.6044283885F, 0.6049009288F, 0.6053733196F, 0.6058455606F, + 0.6063176512F, 0.6067895909F, 0.6072613790F, 0.6077330152F, + 0.6082044989F, 0.6086758295F, 0.6091470065F, 0.6096180294F, + 0.6100888977F, 0.6105596108F, 0.6110301682F, 0.6115005694F, + 0.6119708139F, 0.6124409011F, 0.6129108305F, 0.6133806017F, + 0.6138502139F, 0.6143196669F, 0.6147889599F, 0.6152580926F, + 0.6157270643F, 0.6161958746F, 0.6166645230F, 0.6171330088F, + 0.6176013317F, 0.6180694910F, 0.6185374863F, 0.6190053171F, + 0.6194729827F, 0.6199404828F, 0.6204078167F, 0.6208749841F, + 0.6213419842F, 0.6218088168F, 0.6222754811F, 0.6227419768F, + 0.6232083032F, 0.6236744600F, 0.6241404465F, 0.6246062622F, + 0.6250719067F, 0.6255373795F, 0.6260026799F, 0.6264678076F, + 0.6269327619F, 0.6273975425F, 0.6278621487F, 0.6283265800F, + 0.6287908361F, 0.6292549163F, 0.6297188201F, 0.6301825471F, + 0.6306460966F, 0.6311094683F, 0.6315726617F, 0.6320356761F, + 0.6324985111F, 0.6329611662F, 0.6334236410F, 0.6338859348F, + 0.6343480472F, 0.6348099777F, 0.6352717257F, 0.6357332909F, + 0.6361946726F, 0.6366558704F, 0.6371168837F, 0.6375777122F, + 0.6380383552F, 0.6384988123F, 0.6389590830F, 0.6394191668F, + 0.6398790631F, 0.6403387716F, 0.6407982916F, 0.6412576228F, + 0.6417167645F, 0.6421757163F, 0.6426344778F, 0.6430930483F, + 0.6435514275F, 0.6440096149F, 0.6444676098F, 0.6449254119F, + 0.6453830207F, 0.6458404356F, 0.6462976562F, 0.6467546820F, + 0.6472115125F, 0.6476681472F, 0.6481245856F, 0.6485808273F, + 0.6490368717F, 0.6494927183F, 0.6499483667F, 0.6504038164F, + 0.6508590670F, 0.6513141178F, 0.6517689684F, 0.6522236185F, + 0.6526780673F, 0.6531323146F, 0.6535863598F, 0.6540402024F, + 0.6544938419F, 0.6549472779F, 0.6554005099F, 0.6558535373F, + 0.6563063598F, 0.6567589769F, 0.6572113880F, 0.6576635927F, + 0.6581155906F, 0.6585673810F, 0.6590189637F, 0.6594703380F, + 0.6599215035F, 0.6603724598F, 0.6608232064F, 0.6612737427F, + 0.6617240684F, 0.6621741829F, 0.6626240859F, 0.6630737767F, + 0.6635232550F, 0.6639725202F, 0.6644215720F, 0.6648704098F, + 0.6653190332F, 0.6657674417F, 0.6662156348F, 0.6666636121F, + 0.6671113731F, 0.6675589174F, 0.6680062445F, 0.6684533538F, + 0.6689002450F, 0.6693469177F, 0.6697933712F, 0.6702396052F, + 0.6706856193F, 0.6711314129F, 0.6715769855F, 0.6720223369F, + 0.6724674664F, 0.6729123736F, 0.6733570581F, 0.6738015194F, + 0.6742457570F, 0.6746897706F, 0.6751335596F, 0.6755771236F, + 0.6760204621F, 0.6764635747F, 0.6769064609F, 0.6773491204F, + 0.6777915525F, 0.6782337570F, 0.6786757332F, 0.6791174809F, + 0.6795589995F, 0.6800002886F, 0.6804413477F, 0.6808821765F, + 0.6813227743F, 0.6817631409F, 0.6822032758F, 0.6826431785F, + 0.6830828485F, 0.6835222855F, 0.6839614890F, 0.6844004585F, + 0.6848391936F, 0.6852776939F, 0.6857159589F, 0.6861539883F, + 0.6865917815F, 0.6870293381F, 0.6874666576F, 0.6879037398F, + 0.6883405840F, 0.6887771899F, 0.6892135571F, 0.6896496850F, + 0.6900855733F, 0.6905212216F, 0.6909566294F, 0.6913917963F, + 0.6918267218F, 0.6922614055F, 0.6926958471F, 0.6931300459F, + 0.6935640018F, 0.6939977141F, 0.6944311825F, 0.6948644066F, + 0.6952973859F, 0.6957301200F, 0.6961626085F, 0.6965948510F, + 0.6970268470F, 0.6974585961F, 0.6978900980F, 0.6983213521F, + 0.6987523580F, 0.6991831154F, 0.6996136238F, 0.7000438828F, + 0.7004738921F, 0.7009036510F, 0.7013331594F, 0.7017624166F, + 0.7021914224F, 0.7026201763F, 0.7030486779F, 0.7034769268F, + 0.7039049226F, 0.7043326648F, 0.7047601531F, 0.7051873870F, + 0.7056143662F, 0.7060410902F, 0.7064675586F, 0.7068937711F, + 0.7073197271F, 0.7077454264F, 0.7081708684F, 0.7085960529F, + 0.7090209793F, 0.7094456474F, 0.7098700566F, 0.7102942066F, + 0.7107180970F, 0.7111417274F, 0.7115650974F, 0.7119882066F, + 0.7124110545F, 0.7128336409F, 0.7132559653F, 0.7136780272F, + 0.7140998264F, 0.7145213624F, 0.7149426348F, 0.7153636433F, + 0.7157843874F, 0.7162048668F, 0.7166250810F, 0.7170450296F, + 0.7174647124F, 0.7178841289F, 0.7183032786F, 0.7187221613F, + 0.7191407765F, 0.7195591239F, 0.7199772030F, 0.7203950135F, + 0.7208125550F, 0.7212298271F, 0.7216468294F, 0.7220635616F, + 0.7224800233F, 0.7228962140F, 0.7233121335F, 0.7237277813F, + 0.7241431571F, 0.7245582604F, 0.7249730910F, 0.7253876484F, + 0.7258019322F, 0.7262159422F, 0.7266296778F, 0.7270431388F, + 0.7274563247F, 0.7278692353F, 0.7282818700F, 0.7286942287F, + 0.7291063108F, 0.7295181160F, 0.7299296440F, 0.7303408944F, + 0.7307518669F, 0.7311625609F, 0.7315729763F, 0.7319831126F, + 0.7323929695F, 0.7328025466F, 0.7332118435F, 0.7336208600F, + 0.7340295955F, 0.7344380499F, 0.7348462226F, 0.7352541134F, + 0.7356617220F, 0.7360690478F, 0.7364760907F, 0.7368828502F, + 0.7372893259F, 0.7376955176F, 0.7381014249F, 0.7385070475F, + 0.7389123849F, 0.7393174368F, 0.7397222029F, 0.7401266829F, + 0.7405308763F, 0.7409347829F, 0.7413384023F, 0.7417417341F, + 0.7421447780F, 0.7425475338F, 0.7429500009F, 0.7433521791F, + 0.7437540681F, 0.7441556674F, 0.7445569769F, 0.7449579960F, + 0.7453587245F, 0.7457591621F, 0.7461593084F, 0.7465591631F, + 0.7469587259F, 0.7473579963F, 0.7477569741F, 0.7481556590F, + 0.7485540506F, 0.7489521486F, 0.7493499526F, 0.7497474623F, + 0.7501446775F, 0.7505415977F, 0.7509382227F, 0.7513345521F, + 0.7517305856F, 0.7521263229F, 0.7525217636F, 0.7529169074F, + 0.7533117541F, 0.7537063032F, 0.7541005545F, 0.7544945076F, + 0.7548881623F, 0.7552815182F, 0.7556745749F, 0.7560673323F, + 0.7564597899F, 0.7568519474F, 0.7572438046F, 0.7576353611F, + 0.7580266166F, 0.7584175708F, 0.7588082235F, 0.7591985741F, + 0.7595886226F, 0.7599783685F, 0.7603678116F, 0.7607569515F, + 0.7611457879F, 0.7615343206F, 0.7619225493F, 0.7623104735F, + 0.7626980931F, 0.7630854078F, 0.7634724171F, 0.7638591209F, + 0.7642455188F, 0.7646316106F, 0.7650173959F, 0.7654028744F, + 0.7657880459F, 0.7661729100F, 0.7665574664F, 0.7669417150F, + 0.7673256553F, 0.7677092871F, 0.7680926100F, 0.7684756239F, + 0.7688583284F, 0.7692407232F, 0.7696228080F, 0.7700045826F, + 0.7703860467F, 0.7707671999F, 0.7711480420F, 0.7715285728F, + 0.7719087918F, 0.7722886989F, 0.7726682938F, 0.7730475762F, + 0.7734265458F, 0.7738052023F, 0.7741835454F, 0.7745615750F, + 0.7749392906F, 0.7753166921F, 0.7756937791F, 0.7760705514F, + 0.7764470087F, 0.7768231508F, 0.7771989773F, 0.7775744880F, + 0.7779496827F, 0.7783245610F, 0.7786991227F, 0.7790733676F, + 0.7794472953F, 0.7798209056F, 0.7801941982F, 0.7805671729F, + 0.7809398294F, 0.7813121675F, 0.7816841869F, 0.7820558873F, + 0.7824272684F, 0.7827983301F, 0.7831690720F, 0.7835394940F, + 0.7839095957F, 0.7842793768F, 0.7846488373F, 0.7850179767F, + 0.7853867948F, 0.7857552914F, 0.7861234663F, 0.7864913191F, + 0.7868588497F, 0.7872260578F, 0.7875929431F, 0.7879595055F, + 0.7883257445F, 0.7886916601F, 0.7890572520F, 0.7894225198F, + 0.7897874635F, 0.7901520827F, 0.7905163772F, 0.7908803468F, + 0.7912439912F, 0.7916073102F, 0.7919703035F, 0.7923329710F, + 0.7926953124F, 0.7930573274F, 0.7934190158F, 0.7937803774F, + 0.7941414120F, 0.7945021193F, 0.7948624991F, 0.7952225511F, + 0.7955822752F, 0.7959416711F, 0.7963007387F, 0.7966594775F, + 0.7970178875F, 0.7973759685F, 0.7977337201F, 0.7980911422F, + 0.7984482346F, 0.7988049970F, 0.7991614292F, 0.7995175310F, + 0.7998733022F, 0.8002287426F, 0.8005838519F, 0.8009386299F, + 0.8012930765F, 0.8016471914F, 0.8020009744F, 0.8023544253F, + 0.8027075438F, 0.8030603298F, 0.8034127831F, 0.8037649035F, + 0.8041166906F, 0.8044681445F, 0.8048192647F, 0.8051700512F, + 0.8055205038F, 0.8058706222F, 0.8062204062F, 0.8065698556F, + 0.8069189702F, 0.8072677499F, 0.8076161944F, 0.8079643036F, + 0.8083120772F, 0.8086595151F, 0.8090066170F, 0.8093533827F, + 0.8096998122F, 0.8100459051F, 0.8103916613F, 0.8107370806F, + 0.8110821628F, 0.8114269077F, 0.8117713151F, 0.8121153849F, + 0.8124591169F, 0.8128025108F, 0.8131455666F, 0.8134882839F, + 0.8138306627F, 0.8141727027F, 0.8145144038F, 0.8148557658F, + 0.8151967886F, 0.8155374718F, 0.8158778154F, 0.8162178192F, + 0.8165574830F, 0.8168968067F, 0.8172357900F, 0.8175744328F, + 0.8179127349F, 0.8182506962F, 0.8185883164F, 0.8189255955F, + 0.8192625332F, 0.8195991295F, 0.8199353840F, 0.8202712967F, + 0.8206068673F, 0.8209420958F, 0.8212769820F, 0.8216115256F, + 0.8219457266F, 0.8222795848F, 0.8226131000F, 0.8229462721F, + 0.8232791009F, 0.8236115863F, 0.8239437280F, 0.8242755260F, + 0.8246069801F, 0.8249380901F, 0.8252688559F, 0.8255992774F, + 0.8259293544F, 0.8262590867F, 0.8265884741F, 0.8269175167F, + 0.8272462141F, 0.8275745663F, 0.8279025732F, 0.8282302344F, + 0.8285575501F, 0.8288845199F, 0.8292111437F, 0.8295374215F, + 0.8298633530F, 0.8301889382F, 0.8305141768F, 0.8308390688F, + 0.8311636141F, 0.8314878124F, 0.8318116637F, 0.8321351678F, + 0.8324583246F, 0.8327811340F, 0.8331035957F, 0.8334257098F, + 0.8337474761F, 0.8340688944F, 0.8343899647F, 0.8347106867F, + 0.8350310605F, 0.8353510857F, 0.8356707624F, 0.8359900904F, + 0.8363090696F, 0.8366276999F, 0.8369459811F, 0.8372639131F, + 0.8375814958F, 0.8378987292F, 0.8382156130F, 0.8385321472F, + 0.8388483316F, 0.8391641662F, 0.8394796508F, 0.8397947853F, + 0.8401095697F, 0.8404240037F, 0.8407380873F, 0.8410518204F, + 0.8413652029F, 0.8416782347F, 0.8419909156F, 0.8423032456F, + 0.8426152245F, 0.8429268523F, 0.8432381289F, 0.8435490541F, + 0.8438596279F, 0.8441698502F, 0.8444797208F, 0.8447892396F, + 0.8450984067F, 0.8454072218F, 0.8457156849F, 0.8460237959F, + 0.8463315547F, 0.8466389612F, 0.8469460154F, 0.8472527170F, + 0.8475590661F, 0.8478650625F, 0.8481707063F, 0.8484759971F, + 0.8487809351F, 0.8490855201F, 0.8493897521F, 0.8496936308F, + 0.8499971564F, 0.8503003286F, 0.8506031474F, 0.8509056128F, + 0.8512077246F, 0.8515094828F, 0.8518108872F, 0.8521119379F, + 0.8524126348F, 0.8527129777F, 0.8530129666F, 0.8533126015F, + 0.8536118822F, 0.8539108087F, 0.8542093809F, 0.8545075988F, + 0.8548054623F, 0.8551029712F, 0.8554001257F, 0.8556969255F, + 0.8559933707F, 0.8562894611F, 0.8565851968F, 0.8568805775F, + 0.8571756034F, 0.8574702743F, 0.8577645902F, 0.8580585509F, + 0.8583521566F, 0.8586454070F, 0.8589383021F, 0.8592308420F, + 0.8595230265F, 0.8598148556F, 0.8601063292F, 0.8603974473F, + 0.8606882098F, 0.8609786167F, 0.8612686680F, 0.8615583636F, + 0.8618477034F, 0.8621366874F, 0.8624253156F, 0.8627135878F, + 0.8630015042F, 0.8632890646F, 0.8635762690F, 0.8638631173F, + 0.8641496096F, 0.8644357457F, 0.8647215257F, 0.8650069495F, + 0.8652920171F, 0.8655767283F, 0.8658610833F, 0.8661450820F, + 0.8664287243F, 0.8667120102F, 0.8669949397F, 0.8672775127F, + 0.8675597293F, 0.8678415894F, 0.8681230929F, 0.8684042398F, + 0.8686850302F, 0.8689654640F, 0.8692455412F, 0.8695252617F, + 0.8698046255F, 0.8700836327F, 0.8703622831F, 0.8706405768F, + 0.8709185138F, 0.8711960940F, 0.8714733174F, 0.8717501840F, + 0.8720266939F, 0.8723028469F, 0.8725786430F, 0.8728540824F, + 0.8731291648F, 0.8734038905F, 0.8736782592F, 0.8739522711F, + 0.8742259261F, 0.8744992242F, 0.8747721653F, 0.8750447496F, + 0.8753169770F, 0.8755888475F, 0.8758603611F, 0.8761315177F, + 0.8764023175F, 0.8766727603F, 0.8769428462F, 0.8772125752F, + 0.8774819474F, 0.8777509626F, 0.8780196209F, 0.8782879224F, + 0.8785558669F, 0.8788234546F, 0.8790906854F, 0.8793575594F, + 0.8796240765F, 0.8798902368F, 0.8801560403F, 0.8804214870F, + 0.8806865768F, 0.8809513099F, 0.8812156863F, 0.8814797059F, + 0.8817433687F, 0.8820066749F, 0.8822696243F, 0.8825322171F, + 0.8827944532F, 0.8830563327F, 0.8833178556F, 0.8835790219F, + 0.8838398316F, 0.8841002848F, 0.8843603815F, 0.8846201217F, + 0.8848795054F, 0.8851385327F, 0.8853972036F, 0.8856555182F, + 0.8859134764F, 0.8861710783F, 0.8864283239F, 0.8866852133F, + 0.8869417464F, 0.8871979234F, 0.8874537443F, 0.8877092090F, + 0.8879643177F, 0.8882190704F, 0.8884734671F, 0.8887275078F, + 0.8889811927F, 0.8892345216F, 0.8894874948F, 0.8897401122F, + 0.8899923738F, 0.8902442798F, 0.8904958301F, 0.8907470248F, + 0.8909978640F, 0.8912483477F, 0.8914984759F, 0.8917482487F, + 0.8919976662F, 0.8922467284F, 0.8924954353F, 0.8927437871F, + 0.8929917837F, 0.8932394252F, 0.8934867118F, 0.8937336433F, + 0.8939802199F, 0.8942264417F, 0.8944723087F, 0.8947178210F, + 0.8949629785F, 0.8952077815F, 0.8954522299F, 0.8956963239F, + 0.8959400634F, 0.8961834486F, 0.8964264795F, 0.8966691561F, + 0.8969114786F, 0.8971534470F, 0.8973950614F, 0.8976363219F, + 0.8978772284F, 0.8981177812F, 0.8983579802F, 0.8985978256F, + 0.8988373174F, 0.8990764556F, 0.8993152405F, 0.8995536720F, + 0.8997917502F, 0.9000294751F, 0.9002668470F, 0.9005038658F, + 0.9007405317F, 0.9009768446F, 0.9012128048F, 0.9014484123F, + 0.9016836671F, 0.9019185693F, 0.9021531191F, 0.9023873165F, + 0.9026211616F, 0.9028546546F, 0.9030877954F, 0.9033205841F, + 0.9035530210F, 0.9037851059F, 0.9040168392F, 0.9042482207F, + 0.9044792507F, 0.9047099293F, 0.9049402564F, 0.9051702323F, + 0.9053998569F, 0.9056291305F, 0.9058580531F, 0.9060866248F, + 0.9063148457F, 0.9065427159F, 0.9067702355F, 0.9069974046F, + 0.9072242233F, 0.9074506917F, 0.9076768100F, 0.9079025782F, + 0.9081279964F, 0.9083530647F, 0.9085777833F, 0.9088021523F, + 0.9090261717F, 0.9092498417F, 0.9094731623F, 0.9096961338F, + 0.9099187561F, 0.9101410295F, 0.9103629540F, 0.9105845297F, + 0.9108057568F, 0.9110266354F, 0.9112471656F, 0.9114673475F, + 0.9116871812F, 0.9119066668F, 0.9121258046F, 0.9123445945F, + 0.9125630367F, 0.9127811314F, 0.9129988786F, 0.9132162785F, + 0.9134333312F, 0.9136500368F, 0.9138663954F, 0.9140824073F, + 0.9142980724F, 0.9145133910F, 0.9147283632F, 0.9149429890F, + 0.9151572687F, 0.9153712023F, 0.9155847900F, 0.9157980319F, + 0.9160109282F, 0.9162234790F, 0.9164356844F, 0.9166475445F, + 0.9168590595F, 0.9170702296F, 0.9172810548F, 0.9174915354F, + 0.9177016714F, 0.9179114629F, 0.9181209102F, 0.9183300134F, + 0.9185387726F, 0.9187471879F, 0.9189552595F, 0.9191629876F, + 0.9193703723F, 0.9195774136F, 0.9197841119F, 0.9199904672F, + 0.9201964797F, 0.9204021495F, 0.9206074767F, 0.9208124616F, + 0.9210171043F, 0.9212214049F, 0.9214253636F, 0.9216289805F, + 0.9218322558F, 0.9220351896F, 0.9222377821F, 0.9224400335F, + 0.9226419439F, 0.9228435134F, 0.9230447423F, 0.9232456307F, + 0.9234461787F, 0.9236463865F, 0.9238462543F, 0.9240457822F, + 0.9242449704F, 0.9244438190F, 0.9246423282F, 0.9248404983F, + 0.9250383293F, 0.9252358214F, 0.9254329747F, 0.9256297896F, + 0.9258262660F, 0.9260224042F, 0.9262182044F, 0.9264136667F, + 0.9266087913F, 0.9268035783F, 0.9269980280F, 0.9271921405F, + 0.9273859160F, 0.9275793546F, 0.9277724566F, 0.9279652221F, + 0.9281576513F, 0.9283497443F, 0.9285415014F, 0.9287329227F, + 0.9289240084F, 0.9291147586F, 0.9293051737F, 0.9294952536F, + 0.9296849987F, 0.9298744091F, 0.9300634850F, 0.9302522266F, + 0.9304406340F, 0.9306287074F, 0.9308164471F, 0.9310038532F, + 0.9311909259F, 0.9313776654F, 0.9315640719F, 0.9317501455F, + 0.9319358865F, 0.9321212951F, 0.9323063713F, 0.9324911155F, + 0.9326755279F, 0.9328596085F, 0.9330433577F, 0.9332267756F, + 0.9334098623F, 0.9335926182F, 0.9337750434F, 0.9339571380F, + 0.9341389023F, 0.9343203366F, 0.9345014409F, 0.9346822155F, + 0.9348626606F, 0.9350427763F, 0.9352225630F, 0.9354020207F, + 0.9355811498F, 0.9357599503F, 0.9359384226F, 0.9361165667F, + 0.9362943830F, 0.9364718716F, 0.9366490327F, 0.9368258666F, + 0.9370023733F, 0.9371785533F, 0.9373544066F, 0.9375299335F, + 0.9377051341F, 0.9378800087F, 0.9380545576F, 0.9382287809F, + 0.9384026787F, 0.9385762515F, 0.9387494993F, 0.9389224223F, + 0.9390950209F, 0.9392672951F, 0.9394392453F, 0.9396108716F, + 0.9397821743F, 0.9399531536F, 0.9401238096F, 0.9402941427F, + 0.9404641530F, 0.9406338407F, 0.9408032061F, 0.9409722495F, + 0.9411409709F, 0.9413093707F, 0.9414774491F, 0.9416452062F, + 0.9418126424F, 0.9419797579F, 0.9421465528F, 0.9423130274F, + 0.9424791819F, 0.9426450166F, 0.9428105317F, 0.9429757274F, + 0.9431406039F, 0.9433051616F, 0.9434694005F, 0.9436333209F, + 0.9437969232F, 0.9439602074F, 0.9441231739F, 0.9442858229F, + 0.9444481545F, 0.9446101691F, 0.9447718669F, 0.9449332481F, + 0.9450943129F, 0.9452550617F, 0.9454154945F, 0.9455756118F, + 0.9457354136F, 0.9458949003F, 0.9460540721F, 0.9462129292F, + 0.9463714719F, 0.9465297003F, 0.9466876149F, 0.9468452157F, + 0.9470025031F, 0.9471594772F, 0.9473161384F, 0.9474724869F, + 0.9476285229F, 0.9477842466F, 0.9479396584F, 0.9480947585F, + 0.9482495470F, 0.9484040243F, 0.9485581906F, 0.9487120462F, + 0.9488655913F, 0.9490188262F, 0.9491717511F, 0.9493243662F, + 0.9494766718F, 0.9496286683F, 0.9497803557F, 0.9499317345F, + 0.9500828047F, 0.9502335668F, 0.9503840209F, 0.9505341673F, + 0.9506840062F, 0.9508335380F, 0.9509827629F, 0.9511316810F, + 0.9512802928F, 0.9514285984F, 0.9515765982F, 0.9517242923F, + 0.9518716810F, 0.9520187646F, 0.9521655434F, 0.9523120176F, + 0.9524581875F, 0.9526040534F, 0.9527496154F, 0.9528948739F, + 0.9530398292F, 0.9531844814F, 0.9533288310F, 0.9534728780F, + 0.9536166229F, 0.9537600659F, 0.9539032071F, 0.9540460470F, + 0.9541885858F, 0.9543308237F, 0.9544727611F, 0.9546143981F, + 0.9547557351F, 0.9548967723F, 0.9550375100F, 0.9551779485F, + 0.9553180881F, 0.9554579290F, 0.9555974714F, 0.9557367158F, + 0.9558756623F, 0.9560143112F, 0.9561526628F, 0.9562907174F, + 0.9564284752F, 0.9565659366F, 0.9567031017F, 0.9568399710F, + 0.9569765446F, 0.9571128229F, 0.9572488061F, 0.9573844944F, + 0.9575198883F, 0.9576549879F, 0.9577897936F, 0.9579243056F, + 0.9580585242F, 0.9581924497F, 0.9583260824F, 0.9584594226F, + 0.9585924705F, 0.9587252264F, 0.9588576906F, 0.9589898634F, + 0.9591217452F, 0.9592533360F, 0.9593846364F, 0.9595156465F, + 0.9596463666F, 0.9597767971F, 0.9599069382F, 0.9600367901F, + 0.9601663533F, 0.9602956279F, 0.9604246143F, 0.9605533128F, + 0.9606817236F, 0.9608098471F, 0.9609376835F, 0.9610652332F, + 0.9611924963F, 0.9613194733F, 0.9614461644F, 0.9615725699F, + 0.9616986901F, 0.9618245253F, 0.9619500757F, 0.9620753418F, + 0.9622003238F, 0.9623250219F, 0.9624494365F, 0.9625735679F, + 0.9626974163F, 0.9628209821F, 0.9629442656F, 0.9630672671F, + 0.9631899868F, 0.9633124251F, 0.9634345822F, 0.9635564585F, + 0.9636780543F, 0.9637993699F, 0.9639204056F, 0.9640411616F, + 0.9641616383F, 0.9642818359F, 0.9644017549F, 0.9645213955F, + 0.9646407579F, 0.9647598426F, 0.9648786497F, 0.9649971797F, + 0.9651154328F, 0.9652334092F, 0.9653511095F, 0.9654685337F, + 0.9655856823F, 0.9657025556F, 0.9658191538F, 0.9659354773F, + 0.9660515263F, 0.9661673013F, 0.9662828024F, 0.9663980300F, + 0.9665129845F, 0.9666276660F, 0.9667420750F, 0.9668562118F, + 0.9669700766F, 0.9670836698F, 0.9671969917F, 0.9673100425F, + 0.9674228227F, 0.9675353325F, 0.9676475722F, 0.9677595422F, + 0.9678712428F, 0.9679826742F, 0.9680938368F, 0.9682047309F, + 0.9683153569F, 0.9684257150F, 0.9685358056F, 0.9686456289F, + 0.9687551853F, 0.9688644752F, 0.9689734987F, 0.9690822564F, + 0.9691907483F, 0.9692989750F, 0.9694069367F, 0.9695146337F, + 0.9696220663F, 0.9697292349F, 0.9698361398F, 0.9699427813F, + 0.9700491597F, 0.9701552754F, 0.9702611286F, 0.9703667197F, + 0.9704720490F, 0.9705771169F, 0.9706819236F, 0.9707864695F, + 0.9708907549F, 0.9709947802F, 0.9710985456F, 0.9712020514F, + 0.9713052981F, 0.9714082859F, 0.9715110151F, 0.9716134862F, + 0.9717156993F, 0.9718176549F, 0.9719193532F, 0.9720207946F, + 0.9721219794F, 0.9722229080F, 0.9723235806F, 0.9724239976F, + 0.9725241593F, 0.9726240661F, 0.9727237183F, 0.9728231161F, + 0.9729222601F, 0.9730211503F, 0.9731197873F, 0.9732181713F, + 0.9733163027F, 0.9734141817F, 0.9735118088F, 0.9736091842F, + 0.9737063083F, 0.9738031814F, 0.9738998039F, 0.9739961760F, + 0.9740922981F, 0.9741881706F, 0.9742837938F, 0.9743791680F, + 0.9744742935F, 0.9745691707F, 0.9746637999F, 0.9747581814F, + 0.9748523157F, 0.9749462029F, 0.9750398435F, 0.9751332378F, + 0.9752263861F, 0.9753192887F, 0.9754119461F, 0.9755043585F, + 0.9755965262F, 0.9756884496F, 0.9757801291F, 0.9758715650F, + 0.9759627575F, 0.9760537071F, 0.9761444141F, 0.9762348789F, + 0.9763251016F, 0.9764150828F, 0.9765048228F, 0.9765943218F, + 0.9766835802F, 0.9767725984F, 0.9768613767F, 0.9769499154F, + 0.9770382149F, 0.9771262755F, 0.9772140976F, 0.9773016815F, + 0.9773890275F, 0.9774761360F, 0.9775630073F, 0.9776496418F, + 0.9777360398F, 0.9778222016F, 0.9779081277F, 0.9779938182F, + 0.9780792736F, 0.9781644943F, 0.9782494805F, 0.9783342326F, + 0.9784187509F, 0.9785030359F, 0.9785870877F, 0.9786709069F, + 0.9787544936F, 0.9788378484F, 0.9789209714F, 0.9790038631F, + 0.9790865238F, 0.9791689538F, 0.9792511535F, 0.9793331232F, + 0.9794148633F, 0.9794963742F, 0.9795776561F, 0.9796587094F, + 0.9797395345F, 0.9798201316F, 0.9799005013F, 0.9799806437F, + 0.9800605593F, 0.9801402483F, 0.9802197112F, 0.9802989483F, + 0.9803779600F, 0.9804567465F, 0.9805353082F, 0.9806136455F, + 0.9806917587F, 0.9807696482F, 0.9808473143F, 0.9809247574F, + 0.9810019778F, 0.9810789759F, 0.9811557519F, 0.9812323064F, + 0.9813086395F, 0.9813847517F, 0.9814606433F, 0.9815363147F, + 0.9816117662F, 0.9816869981F, 0.9817620108F, 0.9818368047F, + 0.9819113801F, 0.9819857374F, 0.9820598769F, 0.9821337989F, + 0.9822075038F, 0.9822809920F, 0.9823542638F, 0.9824273195F, + 0.9825001596F, 0.9825727843F, 0.9826451940F, 0.9827173891F, + 0.9827893700F, 0.9828611368F, 0.9829326901F, 0.9830040302F, + 0.9830751574F, 0.9831460720F, 0.9832167745F, 0.9832872652F, + 0.9833575444F, 0.9834276124F, 0.9834974697F, 0.9835671166F, + 0.9836365535F, 0.9837057806F, 0.9837747983F, 0.9838436071F, + 0.9839122072F, 0.9839805990F, 0.9840487829F, 0.9841167591F, + 0.9841845282F, 0.9842520903F, 0.9843194459F, 0.9843865953F, + 0.9844535389F, 0.9845202771F, 0.9845868101F, 0.9846531383F, + 0.9847192622F, 0.9847851820F, 0.9848508980F, 0.9849164108F, + 0.9849817205F, 0.9850468276F, 0.9851117324F, 0.9851764352F, + 0.9852409365F, 0.9853052366F, 0.9853693358F, 0.9854332344F, + 0.9854969330F, 0.9855604317F, 0.9856237309F, 0.9856868310F, + 0.9857497325F, 0.9858124355F, 0.9858749404F, 0.9859372477F, + 0.9859993577F, 0.9860612707F, 0.9861229871F, 0.9861845072F, + 0.9862458315F, 0.9863069601F, 0.9863678936F, 0.9864286322F, + 0.9864891764F, 0.9865495264F, 0.9866096826F, 0.9866696454F, + 0.9867294152F, 0.9867889922F, 0.9868483769F, 0.9869075695F, + 0.9869665706F, 0.9870253803F, 0.9870839991F, 0.9871424273F, + 0.9872006653F, 0.9872587135F, 0.9873165721F, 0.9873742415F, + 0.9874317222F, 0.9874890144F, 0.9875461185F, 0.9876030348F, + 0.9876597638F, 0.9877163057F, 0.9877726610F, 0.9878288300F, + 0.9878848130F, 0.9879406104F, 0.9879962225F, 0.9880516497F, + 0.9881068924F, 0.9881619509F, 0.9882168256F, 0.9882715168F, + 0.9883260249F, 0.9883803502F, 0.9884344931F, 0.9884884539F, + 0.9885422331F, 0.9885958309F, 0.9886492477F, 0.9887024838F, + 0.9887555397F, 0.9888084157F, 0.9888611120F, 0.9889136292F, + 0.9889659675F, 0.9890181273F, 0.9890701089F, 0.9891219128F, + 0.9891735392F, 0.9892249885F, 0.9892762610F, 0.9893273572F, + 0.9893782774F, 0.9894290219F, 0.9894795911F, 0.9895299853F, + 0.9895802049F, 0.9896302502F, 0.9896801217F, 0.9897298196F, + 0.9897793443F, 0.9898286961F, 0.9898778755F, 0.9899268828F, + 0.9899757183F, 0.9900243823F, 0.9900728753F, 0.9901211976F, + 0.9901693495F, 0.9902173314F, 0.9902651436F, 0.9903127865F, + 0.9903602605F, 0.9904075659F, 0.9904547031F, 0.9905016723F, + 0.9905484740F, 0.9905951086F, 0.9906415763F, 0.9906878775F, + 0.9907340126F, 0.9907799819F, 0.9908257858F, 0.9908714247F, + 0.9909168988F, 0.9909622086F, 0.9910073543F, 0.9910523364F, + 0.9910971552F, 0.9911418110F, 0.9911863042F, 0.9912306351F, + 0.9912748042F, 0.9913188117F, 0.9913626580F, 0.9914063435F, + 0.9914498684F, 0.9914932333F, 0.9915364383F, 0.9915794839F, + 0.9916223703F, 0.9916650981F, 0.9917076674F, 0.9917500787F, + 0.9917923323F, 0.9918344286F, 0.9918763679F, 0.9919181505F, + 0.9919597769F, 0.9920012473F, 0.9920425621F, 0.9920837217F, + 0.9921247263F, 0.9921655765F, 0.9922062724F, 0.9922468145F, + 0.9922872030F, 0.9923274385F, 0.9923675211F, 0.9924074513F, + 0.9924472294F, 0.9924868557F, 0.9925263306F, 0.9925656544F, + 0.9926048275F, 0.9926438503F, 0.9926827230F, 0.9927214461F, + 0.9927600199F, 0.9927984446F, 0.9928367208F, 0.9928748486F, + 0.9929128285F, 0.9929506608F, 0.9929883459F, 0.9930258841F, + 0.9930632757F, 0.9931005211F, 0.9931376207F, 0.9931745747F, + 0.9932113836F, 0.9932480476F, 0.9932845671F, 0.9933209425F, + 0.9933571742F, 0.9933932623F, 0.9934292074F, 0.9934650097F, + 0.9935006696F, 0.9935361874F, 0.9935715635F, 0.9936067982F, + 0.9936418919F, 0.9936768448F, 0.9937116574F, 0.9937463300F, + 0.9937808629F, 0.9938152565F, 0.9938495111F, 0.9938836271F, + 0.9939176047F, 0.9939514444F, 0.9939851465F, 0.9940187112F, + 0.9940521391F, 0.9940854303F, 0.9941185853F, 0.9941516044F, + 0.9941844879F, 0.9942172361F, 0.9942498495F, 0.9942823283F, + 0.9943146729F, 0.9943468836F, 0.9943789608F, 0.9944109047F, + 0.9944427158F, 0.9944743944F, 0.9945059408F, 0.9945373553F, + 0.9945686384F, 0.9945997902F, 0.9946308112F, 0.9946617017F, + 0.9946924621F, 0.9947230926F, 0.9947535937F, 0.9947839656F, + 0.9948142086F, 0.9948443232F, 0.9948743097F, 0.9949041683F, + 0.9949338995F, 0.9949635035F, 0.9949929807F, 0.9950223315F, + 0.9950515561F, 0.9950806549F, 0.9951096282F, 0.9951384764F, + 0.9951671998F, 0.9951957987F, 0.9952242735F, 0.9952526245F, + 0.9952808520F, 0.9953089564F, 0.9953369380F, 0.9953647971F, + 0.9953925340F, 0.9954201491F, 0.9954476428F, 0.9954750153F, + 0.9955022670F, 0.9955293981F, 0.9955564092F, 0.9955833003F, + 0.9956100720F, 0.9956367245F, 0.9956632582F, 0.9956896733F, + 0.9957159703F, 0.9957421494F, 0.9957682110F, 0.9957941553F, + 0.9958199828F, 0.9958456937F, 0.9958712884F, 0.9958967672F, + 0.9959221305F, 0.9959473784F, 0.9959725115F, 0.9959975300F, + 0.9960224342F, 0.9960472244F, 0.9960719011F, 0.9960964644F, + 0.9961209148F, 0.9961452525F, 0.9961694779F, 0.9961935913F, + 0.9962175930F, 0.9962414834F, 0.9962652627F, 0.9962889313F, + 0.9963124895F, 0.9963359377F, 0.9963592761F, 0.9963825051F, + 0.9964056250F, 0.9964286361F, 0.9964515387F, 0.9964743332F, + 0.9964970198F, 0.9965195990F, 0.9965420709F, 0.9965644360F, + 0.9965866946F, 0.9966088469F, 0.9966308932F, 0.9966528340F, + 0.9966746695F, 0.9966964001F, 0.9967180260F, 0.9967395475F, + 0.9967609651F, 0.9967822789F, 0.9968034894F, 0.9968245968F, + 0.9968456014F, 0.9968665036F, 0.9968873037F, 0.9969080019F, + 0.9969285987F, 0.9969490942F, 0.9969694889F, 0.9969897830F, + 0.9970099769F, 0.9970300708F, 0.9970500651F, 0.9970699601F, + 0.9970897561F, 0.9971094533F, 0.9971290522F, 0.9971485531F, + 0.9971679561F, 0.9971872617F, 0.9972064702F, 0.9972255818F, + 0.9972445968F, 0.9972635157F, 0.9972823386F, 0.9973010659F, + 0.9973196980F, 0.9973382350F, 0.9973566773F, 0.9973750253F, + 0.9973932791F, 0.9974114392F, 0.9974295059F, 0.9974474793F, + 0.9974653599F, 0.9974831480F, 0.9975008438F, 0.9975184476F, + 0.9975359598F, 0.9975533806F, 0.9975707104F, 0.9975879495F, + 0.9976050981F, 0.9976221566F, 0.9976391252F, 0.9976560043F, + 0.9976727941F, 0.9976894950F, 0.9977061073F, 0.9977226312F, + 0.9977390671F, 0.9977554152F, 0.9977716759F, 0.9977878495F, + 0.9978039361F, 0.9978199363F, 0.9978358501F, 0.9978516780F, + 0.9978674202F, 0.9978830771F, 0.9978986488F, 0.9979141358F, + 0.9979295383F, 0.9979448566F, 0.9979600909F, 0.9979752417F, + 0.9979903091F, 0.9980052936F, 0.9980201952F, 0.9980350145F, + 0.9980497515F, 0.9980644067F, 0.9980789804F, 0.9980934727F, + 0.9981078841F, 0.9981222147F, 0.9981364649F, 0.9981506350F, + 0.9981647253F, 0.9981787360F, 0.9981926674F, 0.9982065199F, + 0.9982202936F, 0.9982339890F, 0.9982476062F, 0.9982611456F, + 0.9982746074F, 0.9982879920F, 0.9983012996F, 0.9983145304F, + 0.9983276849F, 0.9983407632F, 0.9983537657F, 0.9983666926F, + 0.9983795442F, 0.9983923208F, 0.9984050226F, 0.9984176501F, + 0.9984302033F, 0.9984426827F, 0.9984550884F, 0.9984674208F, + 0.9984796802F, 0.9984918667F, 0.9985039808F, 0.9985160227F, + 0.9985279926F, 0.9985398909F, 0.9985517177F, 0.9985634734F, + 0.9985751583F, 0.9985867727F, 0.9985983167F, 0.9986097907F, + 0.9986211949F, 0.9986325297F, 0.9986437953F, 0.9986549919F, + 0.9986661199F, 0.9986771795F, 0.9986881710F, 0.9986990946F, + 0.9987099507F, 0.9987207394F, 0.9987314611F, 0.9987421161F, + 0.9987527045F, 0.9987632267F, 0.9987736829F, 0.9987840734F, + 0.9987943985F, 0.9988046584F, 0.9988148534F, 0.9988249838F, + 0.9988350498F, 0.9988450516F, 0.9988549897F, 0.9988648641F, + 0.9988746753F, 0.9988844233F, 0.9988941086F, 0.9989037313F, + 0.9989132918F, 0.9989227902F, 0.9989322269F, 0.9989416021F, + 0.9989509160F, 0.9989601690F, 0.9989693613F, 0.9989784931F, + 0.9989875647F, 0.9989965763F, 0.9990055283F, 0.9990144208F, + 0.9990232541F, 0.9990320286F, 0.9990407443F, 0.9990494016F, + 0.9990580008F, 0.9990665421F, 0.9990750257F, 0.9990834519F, + 0.9990918209F, 0.9991001331F, 0.9991083886F, 0.9991165877F, + 0.9991247307F, 0.9991328177F, 0.9991408491F, 0.9991488251F, + 0.9991567460F, 0.9991646119F, 0.9991724232F, 0.9991801801F, + 0.9991878828F, 0.9991955316F, 0.9992031267F, 0.9992106684F, + 0.9992181569F, 0.9992255925F, 0.9992329753F, 0.9992403057F, + 0.9992475839F, 0.9992548101F, 0.9992619846F, 0.9992691076F, + 0.9992761793F, 0.9992832001F, 0.9992901701F, 0.9992970895F, + 0.9993039587F, 0.9993107777F, 0.9993175470F, 0.9993242667F, + 0.9993309371F, 0.9993375583F, 0.9993441307F, 0.9993506545F, + 0.9993571298F, 0.9993635570F, 0.9993699362F, 0.9993762678F, + 0.9993825519F, 0.9993887887F, 0.9993949785F, 0.9994011216F, + 0.9994072181F, 0.9994132683F, 0.9994192725F, 0.9994252307F, + 0.9994311434F, 0.9994370107F, 0.9994428327F, 0.9994486099F, + 0.9994543423F, 0.9994600303F, 0.9994656739F, 0.9994712736F, + 0.9994768294F, 0.9994823417F, 0.9994878105F, 0.9994932363F, + 0.9994986191F, 0.9995039592F, 0.9995092568F, 0.9995145122F, + 0.9995197256F, 0.9995248971F, 0.9995300270F, 0.9995351156F, + 0.9995401630F, 0.9995451695F, 0.9995501352F, 0.9995550604F, + 0.9995599454F, 0.9995647903F, 0.9995695953F, 0.9995743607F, + 0.9995790866F, 0.9995837734F, 0.9995884211F, 0.9995930300F, + 0.9995976004F, 0.9996021324F, 0.9996066263F, 0.9996110822F, + 0.9996155004F, 0.9996198810F, 0.9996242244F, 0.9996285306F, + 0.9996327999F, 0.9996370326F, 0.9996412287F, 0.9996453886F, + 0.9996495125F, 0.9996536004F, 0.9996576527F, 0.9996616696F, + 0.9996656512F, 0.9996695977F, 0.9996735094F, 0.9996773865F, + 0.9996812291F, 0.9996850374F, 0.9996888118F, 0.9996925523F, + 0.9996962591F, 0.9996999325F, 0.9997035727F, 0.9997071798F, + 0.9997107541F, 0.9997142957F, 0.9997178049F, 0.9997212818F, + 0.9997247266F, 0.9997281396F, 0.9997315209F, 0.9997348708F, + 0.9997381893F, 0.9997414767F, 0.9997447333F, 0.9997479591F, + 0.9997511544F, 0.9997543194F, 0.9997574542F, 0.9997605591F, + 0.9997636342F, 0.9997666797F, 0.9997696958F, 0.9997726828F, + 0.9997756407F, 0.9997785698F, 0.9997814703F, 0.9997843423F, + 0.9997871860F, 0.9997900016F, 0.9997927894F, 0.9997955494F, + 0.9997982818F, 0.9998009869F, 0.9998036648F, 0.9998063157F, + 0.9998089398F, 0.9998115373F, 0.9998141082F, 0.9998166529F, + 0.9998191715F, 0.9998216642F, 0.9998241311F, 0.9998265724F, + 0.9998289884F, 0.9998313790F, 0.9998337447F, 0.9998360854F, + 0.9998384015F, 0.9998406930F, 0.9998429602F, 0.9998452031F, + 0.9998474221F, 0.9998496171F, 0.9998517885F, 0.9998539364F, + 0.9998560610F, 0.9998581624F, 0.9998602407F, 0.9998622962F, + 0.9998643291F, 0.9998663394F, 0.9998683274F, 0.9998702932F, + 0.9998722370F, 0.9998741589F, 0.9998760591F, 0.9998779378F, + 0.9998797952F, 0.9998816313F, 0.9998834464F, 0.9998852406F, + 0.9998870141F, 0.9998887670F, 0.9998904995F, 0.9998922117F, + 0.9998939039F, 0.9998955761F, 0.9998972285F, 0.9998988613F, + 0.9999004746F, 0.9999020686F, 0.9999036434F, 0.9999051992F, + 0.9999067362F, 0.9999082544F, 0.9999097541F, 0.9999112354F, + 0.9999126984F, 0.9999141433F, 0.9999155703F, 0.9999169794F, + 0.9999183709F, 0.9999197449F, 0.9999211014F, 0.9999224408F, + 0.9999237631F, 0.9999250684F, 0.9999263570F, 0.9999276289F, + 0.9999288843F, 0.9999301233F, 0.9999313461F, 0.9999325529F, + 0.9999337437F, 0.9999349187F, 0.9999360780F, 0.9999372218F, + 0.9999383503F, 0.9999394635F, 0.9999405616F, 0.9999416447F, + 0.9999427129F, 0.9999437665F, 0.9999448055F, 0.9999458301F, + 0.9999468404F, 0.9999478365F, 0.9999488185F, 0.9999497867F, + 0.9999507411F, 0.9999516819F, 0.9999526091F, 0.9999535230F, + 0.9999544236F, 0.9999553111F, 0.9999561856F, 0.9999570472F, + 0.9999578960F, 0.9999587323F, 0.9999595560F, 0.9999603674F, + 0.9999611666F, 0.9999619536F, 0.9999627286F, 0.9999634917F, + 0.9999642431F, 0.9999649828F, 0.9999657110F, 0.9999664278F, + 0.9999671334F, 0.9999678278F, 0.9999685111F, 0.9999691835F, + 0.9999698451F, 0.9999704960F, 0.9999711364F, 0.9999717662F, + 0.9999723858F, 0.9999729950F, 0.9999735942F, 0.9999741834F, + 0.9999747626F, 0.9999753321F, 0.9999758919F, 0.9999764421F, + 0.9999769828F, 0.9999775143F, 0.9999780364F, 0.9999785495F, + 0.9999790535F, 0.9999795485F, 0.9999800348F, 0.9999805124F, + 0.9999809813F, 0.9999814417F, 0.9999818938F, 0.9999823375F, + 0.9999827731F, 0.9999832005F, 0.9999836200F, 0.9999840316F, + 0.9999844353F, 0.9999848314F, 0.9999852199F, 0.9999856008F, + 0.9999859744F, 0.9999863407F, 0.9999866997F, 0.9999870516F, + 0.9999873965F, 0.9999877345F, 0.9999880656F, 0.9999883900F, + 0.9999887078F, 0.9999890190F, 0.9999893237F, 0.9999896220F, + 0.9999899140F, 0.9999901999F, 0.9999904796F, 0.9999907533F, + 0.9999910211F, 0.9999912830F, 0.9999915391F, 0.9999917896F, + 0.9999920345F, 0.9999922738F, 0.9999925077F, 0.9999927363F, + 0.9999929596F, 0.9999931777F, 0.9999933907F, 0.9999935987F, + 0.9999938018F, 0.9999940000F, 0.9999941934F, 0.9999943820F, + 0.9999945661F, 0.9999947456F, 0.9999949206F, 0.9999950912F, + 0.9999952575F, 0.9999954195F, 0.9999955773F, 0.9999957311F, + 0.9999958807F, 0.9999960265F, 0.9999961683F, 0.9999963063F, + 0.9999964405F, 0.9999965710F, 0.9999966979F, 0.9999968213F, + 0.9999969412F, 0.9999970576F, 0.9999971707F, 0.9999972805F, + 0.9999973871F, 0.9999974905F, 0.9999975909F, 0.9999976881F, + 0.9999977824F, 0.9999978738F, 0.9999979624F, 0.9999980481F, + 0.9999981311F, 0.9999982115F, 0.9999982892F, 0.9999983644F, + 0.9999984370F, 0.9999985072F, 0.9999985750F, 0.9999986405F, + 0.9999987037F, 0.9999987647F, 0.9999988235F, 0.9999988802F, + 0.9999989348F, 0.9999989873F, 0.9999990379F, 0.9999990866F, + 0.9999991334F, 0.9999991784F, 0.9999992217F, 0.9999992632F, + 0.9999993030F, 0.9999993411F, 0.9999993777F, 0.9999994128F, + 0.9999994463F, 0.9999994784F, 0.9999995091F, 0.9999995384F, + 0.9999995663F, 0.9999995930F, 0.9999996184F, 0.9999996426F, + 0.9999996657F, 0.9999996876F, 0.9999997084F, 0.9999997282F, + 0.9999997469F, 0.9999997647F, 0.9999997815F, 0.9999997973F, + 0.9999998123F, 0.9999998265F, 0.9999998398F, 0.9999998524F, + 0.9999998642F, 0.9999998753F, 0.9999998857F, 0.9999998954F, + 0.9999999045F, 0.9999999130F, 0.9999999209F, 0.9999999282F, + 0.9999999351F, 0.9999999414F, 0.9999999472F, 0.9999999526F, + 0.9999999576F, 0.9999999622F, 0.9999999664F, 0.9999999702F, + 0.9999999737F, 0.9999999769F, 0.9999999798F, 0.9999999824F, + 0.9999999847F, 0.9999999868F, 0.9999999887F, 0.9999999904F, + 0.9999999919F, 0.9999999932F, 0.9999999943F, 0.9999999953F, + 0.9999999961F, 0.9999999969F, 0.9999999975F, 0.9999999980F, + 0.9999999985F, 0.9999999988F, 0.9999999991F, 0.9999999993F, + 0.9999999995F, 0.9999999997F, 0.9999999998F, 0.9999999999F, + 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F, + 1.0000000000F, 1.0000000000F, 1.0000000000F, 1.0000000000F, +}; + +static const float *const vwin[8] = { + vwin64, + vwin128, + vwin256, + vwin512, + vwin1024, + vwin2048, + vwin4096, + vwin8192, +}; + +const float *_vorbis_window_get(int n){ + return vwin[n]; +} + +void _vorbis_apply_window(float *d,int *winno,long *blocksizes, + int lW,int W,int nW){ + lW=(W?lW:0); + nW=(W?nW:0); + + { + const float *windowLW=vwin[winno[lW]]; + const float *windowNW=vwin[winno[nW]]; + + long n=blocksizes[W]; + long ln=blocksizes[lW]; + long rn=blocksizes[nW]; + + long leftbegin=n/4-ln/4; + long leftend=leftbegin+ln/2; + + long rightbegin=n/2+n/4-rn/4; + long rightend=rightbegin+rn/2; + + int i,p; + + for(i=0;i +#include +#include + +#include "util.h" +#include "write_read.h" + +#define DATA_LEN 2048 + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + + +static int check_output (const float * data_in, unsigned len, float allowable); + +int +main(void){ + static float data_out [DATA_LEN] ; + static float data_in [DATA_LEN] ; + + /* Do safest and most used sample rates first. */ + int sample_rates [] = { 44100, 48000, 32000, 22050, 16000, 96000 } ; + unsigned k ; + int errors = 0 ; + int ch; + + gen_windowed_sine (data_out, ARRAY_LEN (data_out), 0.95); + + for(ch=1;ch<=8;ch++){ + float q=-.05; + printf("\nTesting %d channel%s\n\n",ch,ch==1?"":"s"); + while(q<1.){ + for (k = 0 ; k < ARRAY_LEN (sample_rates); k ++) { + char filename [64] ; + snprintf (filename, sizeof (filename), "vorbis_%dch_q%.1f_%u.ogg", ch,q*10,sample_rates [k]); + + printf (" %-20s : ", filename); + fflush (stdout); + + /* Set to know value. */ + set_data_in (data_in, ARRAY_LEN (data_in), 3.141); + + write_vorbis_data_or_die (filename, sample_rates [k], q, data_out, ARRAY_LEN (data_out),ch); + read_vorbis_data_or_die (filename, sample_rates [k], data_in, ARRAY_LEN (data_in)); + + if (check_output (data_in, ARRAY_LEN (data_in), (.15f - .1f*q)) != 0) + errors ++ ; + else { + puts ("ok"); + remove (filename); + } + } + q+=.1; + } + } + + if (errors) + exit (1); + + return 0; +} + +static int +check_output (const float * data_in, unsigned len, float allowable) +{ + float max_abs = 0.0 ; + unsigned k ; + + for (k = 0 ; k < len ; k++) { + float temp = fabs (data_in [k]); + max_abs = MAX (max_abs, temp); + } + + if (max_abs < 0.95-allowable) { + printf ("Error : max_abs (%f) too small.\n", max_abs); + return 1 ; + } else if (max_abs > .95+allowable) { + printf ("Error : max_abs (%f) too big.\n", max_abs); + return 1 ; + } + + return 0 ; +} + diff --git a/vendor/vorbis/test/util.c b/vendor/vorbis/test/util.c new file mode 100644 index 0000000..3dc1597 --- /dev/null +++ b/vendor/vorbis/test/util.c @@ -0,0 +1,52 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: utility functions for vorbis codec test suite. + + ********************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "util.h" + +void +gen_windowed_sine (float *data, int len, float maximum) +{ int k ; + + memset (data, 0, len * sizeof (float)) ; + + len /= 2 ; + + for (k = 0 ; k < len ; k++) + { data [k] = sin (2.0 * k * M_PI * 1.0 / 32.0 + 0.4) ; + + /* Apply Hanning Window. */ + data [k] *= maximum * (0.5 - 0.5 * cos (2.0 * M_PI * k / ((len) - 1))) ; + } + + return ; +} + +void +set_data_in (float * data, unsigned len, float value) +{ unsigned k ; + + for (k = 0 ; k < len ; k++) + data [k] = value ; +} diff --git a/vendor/vorbis/test/util.h b/vendor/vorbis/test/util.h new file mode 100644 index 0000000..9fe471c --- /dev/null +++ b/vendor/vorbis/test/util.h @@ -0,0 +1,23 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: utility functions for vorbis codec test suite. + + ********************************************************************/ + +#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) + +/* Create simple test data consisting of a windowed sine wave. */ +void gen_windowed_sine (float *data, int len, float maximum) ; + +/* Set len values of data array to given value. */ +void set_data_in (float * data, unsigned len, float value) ; diff --git a/vendor/vorbis/test/write_read.c b/vendor/vorbis/test/write_read.c new file mode 100644 index 0000000..9495240 --- /dev/null +++ b/vendor/vorbis/test/write_read.c @@ -0,0 +1,297 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: utility functions for vorbis codec test suite. + + ********************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "write_read.h" + +/* The following function is basically a hacked version of the code in + * examples/encoder_example.c */ +void +write_vorbis_data_or_die (const char *filename, int srate, float q, const float * data, int count, int ch) +{ + FILE * file ; + ogg_stream_state os; + ogg_page og; + ogg_packet op; + vorbis_info vi; + vorbis_comment vc; + vorbis_dsp_state vd; + vorbis_block vb; + + int eos = 0, ret; + + if ((file = fopen (filename, "wb")) == NULL) { + printf("\n\nError : fopen failed : %s\n", strerror (errno)) ; + exit (1) ; + } + + /********** Encode setup ************/ + + vorbis_info_init (&vi); + + ret = vorbis_encode_init_vbr (&vi,ch,srate,q); + if (ret) { + printf ("vorbis_encode_init_vbr return %d\n", ret) ; + exit (1) ; + } + + vorbis_comment_init (&vc); + vorbis_comment_add_tag (&vc,"ENCODER","test/util.c"); + vorbis_analysis_init (&vd,&vi); + vorbis_block_init (&vd,&vb); + + ogg_stream_init (&os,12345678); + + { + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + vorbis_analysis_headerout (&vd,&vc,&header,&header_comm,&header_code); + ogg_stream_packetin (&os,&header); + ogg_stream_packetin (&os,&header_comm); + ogg_stream_packetin (&os,&header_code); + + /* Ensures the audio data will start on a new page. */ + while (!eos){ + int result = ogg_stream_flush (&os,&og); + if (result == 0) + break; + fwrite (og.header,1,og.header_len,file); + fwrite (og.body,1,og.body_len,file); + } + + } + + { + /* expose the buffer to submit data */ + float **buffer = vorbis_analysis_buffer (&vd,count); + int i; + + for(i=0;i 0 && read_total < count) { + int bout = samples < count ? samples : count; + bout = read_total + bout > count ? count - read_total : bout; + + memcpy (data + read_total, pcm[0], bout * sizeof (float)) ; + + vorbis_synthesis_read (&vd,bout); + read_total += bout ; + } + } + } + + if (ogg_page_eos (&og)) eos = 1; + } + } + + if (!eos) { + buffer = ogg_sync_buffer (&oy,4096); + bytes = fread (buffer,1,4096,file); + ogg_sync_wrote (&oy,bytes); + if (bytes == 0) eos = 1; + } + } + + ogg_stream_clear (&os); + + vorbis_block_clear (&vb); + vorbis_dsp_clear (&vd); + vorbis_comment_clear (&vc); + vorbis_info_clear (&vi); + } +done_decode: + + /* OK, clean up the framer */ + ogg_sync_clear (&oy); + + fclose (file) ; +} + diff --git a/vendor/vorbis/test/write_read.h b/vendor/vorbis/test/write_read.h new file mode 100644 index 0000000..b99609a --- /dev/null +++ b/vendor/vorbis/test/write_read.h @@ -0,0 +1,27 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: utility functions for vorbis codec test suite. + + ********************************************************************/ + +/* Write supplied data to an Ogg/Vorbis file with specified filename at + * specified sample rate. Assumes a single channel of audio. */ +void write_vorbis_data_or_die (const char *filename, int srate, float q, + const float * data, int count, int ch) ; + +/* Read given Ogg/Vorbis file into data specified data array. This + * function is basically the inverse of the one above. Again, assumes + * a single channel of audio. */ +void read_vorbis_data_or_die (const char *filename, int srate, + float * data, int count) ; + diff --git a/vendor/vorbis/vq/16.vqs b/vendor/vorbis/vq/16.vqs new file mode 100644 index 0000000..3d15f40 --- /dev/null +++ b/vendor/vorbis/vq/16.vqs @@ -0,0 +1,74 @@ + +GO + +>_16c0_s noninterleaved +haux 16c0_s/resaux_0.vqd _16c0_s_single 0,64,2 10 + +:_p1_0 16c0_s/res_sub0_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 16c0_s/res_sub0_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 16c0_s/res_sub0_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 16c0_s/res_sub0_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 16c0_s/res_sub0_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 16c0_s/res_sub0_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 16c0_s/res_sub0_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 16c0_s/res_sub0_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 16c0_s/res_sub0_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 16c0_s/res_sub0_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 16c0_s/res_sub0_part9_pass0.vqd, 4, nonseq, 0 +- 315 +:_p9_1 16c0_s/res_sub0_part9_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p9_2 16c0_s/res_sub0_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 + +>_16c1s_s noninterleaved +haux 16c1_s/resaux_0.vqd _16c1_s_short 0,64,2 10 + +>_16c1_s noninterleaved +haux 16c1_s/resaux_1.vqd _16c1_s_long 0,64,2 10 + +:_p1_0 16c1_s/res_sub0_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 16c1_s/res_sub0_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 16c1_s/res_sub0_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 16c1_s/res_sub0_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 16c1_s/res_sub0_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 16c1_s/res_sub0_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 16c1_s/res_sub0_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 16c1_s/res_sub0_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 16c1_s/res_sub0_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 16c1_s/res_sub0_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 16c1_s/res_sub0_part9_pass0.vqd, 2, nonseq, 0 +- 315 630 945 1260 1575 1890 +:_p9_1 16c1_s/res_sub0_part9_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p9_2 16c1_s/res_sub0_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 + +>_16c2s_s noninterleaved +haux 16c2_s/resaux_0.vqd _16c2_s_short 0,64,2 10 +>_16c2_s noninterleaved +haux 16c2_s/resaux_1.vqd _16c2_s_long 0,64,2 10 + +:_p1_0 16c2_s/res_sub0_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 16c2_s/res_sub0_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 16c2_s/res_sub0_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 16c2_s/res_sub0_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 16c2_s/res_sub0_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 16c2_s/res_sub0_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 16c2_s/res_sub0_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 16c2_s/res_sub0_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 16c2_s/res_sub0_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 16c2_s/res_sub0_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 16c2_s/res_sub0_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 16c2_s/res_sub0_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 16c2_s/res_sub0_part9_pass0.vqd, 2, nonseq, 0 +- 931 1862 2793 3724 4655 5586 6517 7448 +:_p9_1 16c2_s/res_sub0_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 343 392 441 +:_p9_2 16c2_s/res_sub0_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + diff --git a/vendor/vorbis/vq/16u.vqs b/vendor/vorbis/vq/16u.vqs new file mode 100644 index 0000000..854de98 --- /dev/null +++ b/vendor/vorbis/vq/16u.vqs @@ -0,0 +1,69 @@ + +GO + +>_16u0_ noninterleaved +haux 16u0/resaux_0.vqd _16u0__single 0,64,2 8 + +:_p1_0 16u0/res_sub0_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 16u0/res_sub0_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 16u0/res_sub0_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 16u0/res_sub0_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 16u0/res_sub0_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p6_0 16u0/res_sub0_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 16u0/res_sub0_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 16u0/res_sub0_part7_pass0.vqd, 4, nonseq, 0 +- 315 +:_p7_1 16u0/res_sub0_part7_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p7_2 16u0/res_sub0_part7_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 + + +>_16u1s_ noninterleaved +haux 16u1/resaux_0.vqd _16u1__short 0,64,2 10 +>_16u1_ noninterleaved +haux 16u1/resaux_1.vqd _16u1__long 0,64,2 10 + +:_p1_0 16u1/res_sub0_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 16u1/res_sub0_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 16u1/res_sub0_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 16u1/res_sub0_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 16u1/res_sub0_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 16u1/res_sub0_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p7_0 16u1/res_sub0_part7_pass0.vqd, 4, nonseq, 0 +- 11 +:_p7_1 16u1/res_sub0_part7_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p8_0 16u1/res_sub0_part8_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 +:_p8_1 16u1/res_sub0_part8_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p9_0 16u1/res_sub0_part9_pass0.vqd, 2, nonseq, 0 +- 255 510 765 1020 1275 1530 1785 +:_p9_1 16u1/res_sub0_part9_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 119 +:_p9_2 16u1/res_sub0_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + +>_16u2s noninterleaved +haux 16u2/resaux_0.vqd _16u2__short 0,16,2 10 + +>_16u2 noninterleaved +haux 16u2/resaux_1.vqd _16u2__long 0,64,2 10 + +:_p1_0 16u2/res_sub0_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 16u2/res_sub0_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 16u2/res_sub0_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 16u2/res_sub0_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 16u2/res_sub0_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 16u2/res_sub0_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 16u2/res_sub0_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 16u2/res_sub0_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 16u2/res_sub0_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 16u2/res_sub0_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 16u2/res_sub0_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 16u2/res_sub0_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 16u2/res_sub0_part9_pass0.vqd, 2, nonseq, 0 +- 931 1862 2793 3724 4655 5586 6517 +:_p9_1 16u2/res_sub0_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 343 392 441 +:_p9_2 16u2/res_sub0_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + diff --git a/vendor/vorbis/vq/44c-1.vqs b/vendor/vorbis/vq/44c-1.vqs new file mode 100644 index 0000000..ff30d65 --- /dev/null +++ b/vendor/vorbis/vq/44c-1.vqs @@ -0,0 +1,63 @@ +GO + +>_44cn1s_s noninterleaved +haux 44c-1_s/resaux_0.vqd _44cn1_s_short 0,16,2 9 + +>_44cn1_s noninterleaved +haux 44c-1_s/resaux_1.vqd _44cn1_s_long 0,64,2 9 + +# 0 1 2 2 4 8 16 32 + +# 0 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 +# 1 . . . +# 2 . . . +# 4 . . . . . . + +:_p1_0 44c-1_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c-1_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c-1_s/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c-1_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c-1_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p6_0 44c-1_s/res_part6_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p6_1 44c-1_s/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p7_0 44c-1_s/res_part7_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p7_1 44c-1_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p8_0 44c-1_s/res_part8_pass0.vqd, 4, nonseq, 0 +- 221 442 +:_p8_1 44c-1_s/res_part8_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 +:_p8_2 44c-1_s/res_part8_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + + +>_44cn1s_sm noninterleaved +haux 44c-1_sm/resaux_0.vqd _44cn1_sm_short 0,16,2 9 + +>_44cn1_sm noninterleaved +haux 44c-1_sm/resaux_1.vqd _44cn1_sm_long 0,64,2 9 + +# 0 1 2 2 4 8 16 32 + +# 0 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 +# 1 . . . +# 2 . . . +# 4 . . . . . . + +:_p1_0 44c-1_sm/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c-1_sm/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c-1_sm/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c-1_sm/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c-1_sm/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p6_0 44c-1_sm/res_part6_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p6_1 44c-1_sm/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p7_0 44c-1_sm/res_part7_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p7_1 44c-1_sm/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p8_0 44c-1_sm/res_part8_pass0.vqd, 2, nonseq, 0 +- 221 442 663 884 +:_p8_1 44c-1_sm/res_part8_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 +:_p8_2 44c-1_sm/res_part8_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + diff --git a/vendor/vorbis/vq/44c0.vqs b/vendor/vorbis/vq/44c0.vqs new file mode 100644 index 0000000..f650f8f --- /dev/null +++ b/vendor/vorbis/vq/44c0.vqs @@ -0,0 +1,65 @@ +GO + +>_44c0s_s noninterleaved +haux 44c0_s/resaux_0.vqd _44c0_s_short 0,16,2 9 + +>_44c0_s noninterleaved +haux 44c0_s/resaux_1.vqd _44c0_s_long 0,64,2 9 + +# 0 1 2 2 4 8 16 32 + +# 0 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 +# 1 . . . +# 2 . . . +# 4 . . . . . . + +:_p1_0 44c0_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c0_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c0_s/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c0_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c0_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p6_0 44c0_s/res_part6_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p6_1 44c0_s/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p7_0 44c0_s/res_part7_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p7_1 44c0_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p8_0 44c0_s/res_part8_pass0.vqd, 4, nonseq, 0 +- 221 442 +:_p8_1 44c0_s/res_part8_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 +:_p8_2 44c0_s/res_part8_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + + +>_44c0s_sm noninterleaved +haux 44c0_sm/resaux_0.vqd _44c0_sm_short 0,16,2 9 + +>_44c0_sm noninterleaved +haux 44c0_sm/resaux_1.vqd _44c0_sm_long 0,64,2 9 + +# 0 1 2 2 4 8 16 32 + +# 0 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 +# 1 . . . +# 2 . . . +# 4 . . . . . . + +:_p1_0 44c0_sm/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c0_sm/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c0_sm/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c0_sm/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c0_sm/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p6_0 44c0_sm/res_part6_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p6_1 44c0_sm/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p7_0 44c0_sm/res_part7_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p7_1 44c0_sm/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p8_0 44c0_sm/res_part8_pass0.vqd, 2, nonseq, 0 +- 221 442 663 884 +:_p8_1 44c0_sm/res_part8_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 +:_p8_2 44c0_sm/res_part8_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + diff --git a/vendor/vorbis/vq/44c1.vqs b/vendor/vorbis/vq/44c1.vqs new file mode 100644 index 0000000..c21a6b3 --- /dev/null +++ b/vendor/vorbis/vq/44c1.vqs @@ -0,0 +1,66 @@ + +GO + +>_44c1s_s noninterleaved +haux 44c1_s/resaux_0.vqd _44c1_s_short 0,16,2 9 + +>_44c1_s noninterleaved +haux 44c1_s/resaux_1.vqd _44c1_s_long 0,64,2 9 + +# 0 1 2 2 4 8 16 32 + +# 0 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 +# 1 . . . +# 2 . . . +# 4 . . . . . . + +:_p1_0 44c1_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c1_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c1_s/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c1_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c1_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p6_0 44c1_s/res_part6_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p6_1 44c1_s/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p7_0 44c1_s/res_part7_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p7_1 44c1_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p8_0 44c1_s/res_part8_pass0.vqd, 2, nonseq, 0 +- 221 442 663 884 1105 1326 +:_p8_1 44c1_s/res_part8_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 +:_p8_2 44c1_s/res_part8_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + + +>_44c1s_sm noninterleaved +haux 44c1_sm/resaux_0.vqd _44c1_sm_short 0,16,2 9 + +>_44c1_sm noninterleaved +haux 44c1_sm/resaux_1.vqd _44c1_sm_long 0,64,2 9 + +# 0 1 2 2 4 8 16 32 + +# 0 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 +# 1 . . . +# 2 . . . +# 4 . . . . . . + +:_p1_0 44c1_sm/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c1_sm/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c1_sm/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c1_sm/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c1_sm/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p6_0 44c1_sm/res_part6_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p6_1 44c1_sm/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p7_0 44c1_sm/res_part7_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p7_1 44c1_sm/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p8_0 44c1_sm/res_part8_pass0.vqd, 2, nonseq, 0 +- 221 442 663 884 1105 1326 +:_p8_1 44c1_sm/res_part8_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 +:_p8_2 44c1_sm/res_part8_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + diff --git a/vendor/vorbis/vq/44c2.vqs b/vendor/vorbis/vq/44c2.vqs new file mode 100644 index 0000000..9fdbd03 --- /dev/null +++ b/vendor/vorbis/vq/44c2.vqs @@ -0,0 +1,37 @@ +GO + +>_44c2s_s noninterleaved +haux 44c2_s/resaux_0.vqd _44c2_s_short 0,16,2 10 + +>_44c2_s noninterleaved +haux 44c2_s/resaux_1.vqd _44c2_s_long 0,64,2 10 + +#iter 0 + +# 0 1 1 2 2 4 8 16 32 + +# 0 99 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . +# 2 . . . +# 4 . . . . . . . + +:_p1_0 44c2_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c2_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c2_s/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44c2_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c2_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 44c2_s/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 44c2_s/res_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 44c2_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c2_s/res_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 44c2_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 44c2_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 221 442 663 884 1105 1326 +:_p9_1 44c2_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 +:_p9_2 44c2_s/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + + \ No newline at end of file diff --git a/vendor/vorbis/vq/44c3.vqs b/vendor/vorbis/vq/44c3.vqs new file mode 100644 index 0000000..57a1317 --- /dev/null +++ b/vendor/vorbis/vq/44c3.vqs @@ -0,0 +1,36 @@ + +GO + +>_44c3s_s noninterleaved +haux 44c3_s/resaux_0.vqd _44c3_s_short 0,16,2 10 + +>_44c3_s noninterleaved +haux 44c3_s/resaux_1.vqd _44c3_s_long 0,64,2 10 + +#iter 0 + +# 0 1 1 2 2 4 8 16 32 + +# 0 99 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . +# 2 . . . +# 4 . . . . . . . + +:_p1_0 44c3_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c3_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c3_s/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44c3_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c3_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 44c3_s/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 44c3_s/res_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 44c3_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c3_s/res_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 44c3_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 44c3_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 255 510 765 1020 1275 1530 +:_p9_1 44c3_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 119 +:_p9_2 44c3_s/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 diff --git a/vendor/vorbis/vq/44c4.vqs b/vendor/vorbis/vq/44c4.vqs new file mode 100644 index 0000000..82a36e1 --- /dev/null +++ b/vendor/vorbis/vq/44c4.vqs @@ -0,0 +1,36 @@ + +GO + +>_44c4s_s noninterleaved +haux 44c4_s/resaux_0.vqd _44c4_s_short 0,16,2 10 + +>_44c4_s noninterleaved +haux 44c4_s/resaux_1.vqd _44c4_s_long 0,64,2 10 + +#iter 0 + +# 0 1 1 2 2 4 8 16 32 + +# 0 99 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . +# 2 . . . +# 4 . . . . . . . + +:_p1_0 44c4_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c4_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c4_s/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44c4_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c4_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 44c4_s/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 44c4_s/res_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 44c4_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c4_s/res_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 44c4_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 44c4_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 315 630 945 1260 1575 1890 +:_p9_1 44c4_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p9_2 44c4_s/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 diff --git a/vendor/vorbis/vq/44c5.vqs b/vendor/vorbis/vq/44c5.vqs new file mode 100644 index 0000000..9790843 --- /dev/null +++ b/vendor/vorbis/vq/44c5.vqs @@ -0,0 +1,37 @@ + +GO + +>_44c5s_s noninterleaved +haux 44c5_s/resaux_0.vqd _44c5_s_short 0,16,2 10 + +>_44c5_s noninterleaved +haux 44c5_s/resaux_1.vqd _44c5_s_long 0,64,2 10 + +#iter 0 + +# 0 1 1 2 2 4 8 16 32 + +# 0 99 0 99 4 8 16 32 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . +# 2 . . . +# 4 . . . . . . . + +:_p1_0 44c5_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 44c5_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c5_s/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44c5_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 44c5_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 44c5_s/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 44c5_s/res_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 44c5_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c5_s/res_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 44c5_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 44c5_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 357 714 1071 1428 1785 2142 2499 +:_p9_1 44c5_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 168 +:_p9_2 44c5_s/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 + diff --git a/vendor/vorbis/vq/44c6.vqs b/vendor/vorbis/vq/44c6.vqs new file mode 100644 index 0000000..f420dd0 --- /dev/null +++ b/vendor/vorbis/vq/44c6.vqs @@ -0,0 +1,37 @@ +GO + +>_44c6s_s noninterleaved +haux 44c6_s/resaux_0.vqd _44c6_s_short 0,16,2 10 + +>_44c6_s noninterleaved +haux 44c6_s/resaux_1.vqd _44c6_s_long 0,64,2 10 + + +# 0 1 2 4 8 16 32 71 157 + +# 1 2 3 4 8 16 71 157 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . . . +# 2 . . . . . +# 4 . . . . . + +:_p1_0 44c6_s/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44c6_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c6_s/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c6_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 44c6_s/res_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 44c6_s/res_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 44c6_s/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44c6_s/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44c6_s/res_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 44c6_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c6_s/res_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 44c6_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 44c6_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 637 1274 1911 2548 3185 3822 +:_p9_1 44c6_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 +:_p9_2 44c6_s/res_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 diff --git a/vendor/vorbis/vq/44c7.vqs b/vendor/vorbis/vq/44c7.vqs new file mode 100644 index 0000000..088d81d --- /dev/null +++ b/vendor/vorbis/vq/44c7.vqs @@ -0,0 +1,38 @@ + +GO + +>_44c7s_s noninterleaved +haux 44c7_s/resaux_0.vqd _44c7_s_short 0,16,2 10 + +>_44c7_s noninterleaved +haux 44c7_s/resaux_1.vqd _44c7_s_long 0,64,2 10 + + +# 0 1 2 4 8 16 32 71 157 + +# 1 2 3 4 8 16 71 157 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . . . +# 2 . . . . . +# 4 . . . . . + +:_p1_0 44c7_s/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44c7_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c7_s/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c7_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 44c7_s/res_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 44c7_s/res_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 44c7_s/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44c7_s/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44c7_s/res_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 44c7_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c7_s/res_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 44c7_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 44c7_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 637 1274 1911 2548 3185 3822 +:_p9_1 44c7_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 +:_p9_2 44c7_s/res_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 diff --git a/vendor/vorbis/vq/44c8.vqs b/vendor/vorbis/vq/44c8.vqs new file mode 100644 index 0000000..ce5bdbe --- /dev/null +++ b/vendor/vorbis/vq/44c8.vqs @@ -0,0 +1,39 @@ + +GO + +>_44c8s_s noninterleaved +haux 44c8_s/resaux_0.vqd _44c8_s_short 0,16,2 10 + +>_44c8_s noninterleaved +haux44c8_s/resaux_1.vqd _44c8_s_long 0,64,2 10 + + +# 0 1 2 4 8 16 32 71 157 + +# 1 2 3 4 8 16 71 157 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . . . +# 2 . . . . . +# 4 . . . . . + +:_p1_0 44c8_s/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44c8_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c8_s/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c8_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 44c8_s/res_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 44c8_s/res_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 44c8_s/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44c8_s/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44c8_s/res_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 44c8_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c8_s/res_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 44c8_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 44c8_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 931 1862 2793 3724 4655 5586 6517 7448 +:_p9_1 44c8_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 343 392 441 +:_p9_2 44c8_s/res_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + diff --git a/vendor/vorbis/vq/44c9.vqs b/vendor/vorbis/vq/44c9.vqs new file mode 100644 index 0000000..1c54786 --- /dev/null +++ b/vendor/vorbis/vq/44c9.vqs @@ -0,0 +1,37 @@ +GO + +>_44c9s_s noninterleaved +haux 44c9_s/resaux_0.vqd _44c9_s_short 0,16,2 10 + +>_44c9_s noninterleaved +haux 44c9_s/resaux_1.vqd _44c9_s_long 0,64,2 10 + + +# 0 1 2 4 8 16 32 71 157 + +# 1 2 3 4 8 16 71 157 + + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . . . +# 2 . . . . . +# 4 . . . . . + +:_p1_0 44c9_s/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44c9_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44c9_s/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44c9_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 44c9_s/res_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 44c9_s/res_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 44c9_s/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44c9_s/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44c9_s/res_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 44c9_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44c9_s/res_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 44c9_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 44c9_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 931 1862 2793 3724 4655 5586 6517 7448 8379 +:_p9_1 44c9_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 343 392 441 +:_p9_2 44c9_s/res_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 diff --git a/vendor/vorbis/vq/44p-1.vqs b/vendor/vorbis/vq/44p-1.vqs new file mode 100644 index 0000000..02d26fb --- /dev/null +++ b/vendor/vorbis/vq/44p-1.vqs @@ -0,0 +1,49 @@ +GO + +>_44pn1 noninterleaved +haux 44pn1/resaux_0.vqd _44pn1_short 0,80,2 7 +haux 44pn1/resaux_1.vqd _44pn1_long 0,300,2 7 +haux 44pn1/resaux_2.vqd _44pn1_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 7 17 31 + +# 0 99 7 17 31 + + +# 0 1 2 3 4 5 6 +# 1 . . . . . +# 2 . . . . . . +# 4 . . + +:_p1_0 44pn1/res_sub0_part1_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p2_0 44pn1/res_sub0_part2_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p2_1 44pn1/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p3_0 44pn1/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p3_1 44pn1/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p4_0 44pn1/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p4_1 44pn1/res_sub0_part4_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p5_0 44pn1/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p5_1 44pn1/res_sub0_part5_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p4_1 :_p5_2 + +:_p6_0 44pn1/res_sub0_part6_pass0.vqd, 5, nonseq, 0 +- 625 +:_p6_1 44pn1/res_sub0_part6_pass1.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p6_2 44pn1/res_sub0_part6_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44pn1/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44pn1/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44pn1/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p7_2/3 for l1_1/2 diff --git a/vendor/vorbis/vq/44p0.vqs b/vendor/vorbis/vq/44p0.vqs new file mode 100644 index 0000000..16479ba --- /dev/null +++ b/vendor/vorbis/vq/44p0.vqs @@ -0,0 +1,49 @@ +GO + +>_44p0 noninterleaved +haux 44p0/resaux_0.vqd _44p0_short 0,42,2 7 +haux 44p0/resaux_1.vqd _44p0_long 0,170,2 7 +haux 44p0/resaux_2.vqd _44p0_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 7 17 31 + +# 0 99 7 17 31 + + +# 0 1 2 3 4 5 6 +# 1 . . . . . +# 2 . . . . . . +# 4 . . + +:_p1_0 44p0/res_sub0_part1_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p2_0 44p0/res_sub0_part2_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p2_1 44p0/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p3_0 44p0/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p3_1 44p0/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p4_0 44p0/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p4_1 44p0/res_sub0_part4_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p5_0 44p0/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p5_1 44p0/res_sub0_part5_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p4_1 :_p5_2 + +:_p6_0 44p0/res_sub0_part6_pass0.vqd, 5, nonseq, 0 +- 625 +:_p6_1 44p0/res_sub0_part6_pass1.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p6_2 44p0/res_sub0_part6_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p0/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p0/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p0/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p7_2/3 for l1_1/2 diff --git a/vendor/vorbis/vq/44p1.vqs b/vendor/vorbis/vq/44p1.vqs new file mode 100644 index 0000000..74352c3 --- /dev/null +++ b/vendor/vorbis/vq/44p1.vqs @@ -0,0 +1,49 @@ +GO + +>_44p1 noninterleaved +haux 44p1/resaux_0.vqd _44p1_short 0,42,2 7 +haux 44p1/resaux_1.vqd _44p1_long 0,170,2 7 +haux 44p1/resaux_2.vqd _44p1_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 7 17 31 + +# 0 99 7 17 31 + + +# 0 1 2 3 4 5 6 +# 1 . . . . . +# 2 . . . . . . +# 4 . . + +:_p1_0 44p1/res_sub0_part1_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p2_0 44p1/res_sub0_part2_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p2_1 44p1/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p3_0 44p1/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p3_1 44p1/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p4_0 44p1/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p4_1 44p1/res_sub0_part4_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p5_0 44p1/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p5_1 44p1/res_sub0_part5_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p4_1 :_p5_2 + +:_p6_0 44p1/res_sub0_part6_pass0.vqd, 5, nonseq, 0 +- 625 +:_p6_1 44p1/res_sub0_part6_pass1.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p6_2 44p1/res_sub0_part6_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p1/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p1/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p1/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p7_2/3 for l1_1/2 diff --git a/vendor/vorbis/vq/44p2.vqs b/vendor/vorbis/vq/44p2.vqs new file mode 100644 index 0000000..7eabbab --- /dev/null +++ b/vendor/vorbis/vq/44p2.vqs @@ -0,0 +1,52 @@ +GO + +>_44p2 noninterleaved +haux 44p2/resaux_0.vqd _44p2_short 0,42,2 8 +haux 44p2/resaux_1.vqd _44p2_long 0,170,2 8 +haux 44p2/resaux_2.vqd _44p2_lfe 0,2,2 2 + +#iter 0 + +# 0 1 1 2 7 17 31 + +# 0 99 99 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p2/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p2/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p2/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p2/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p2/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p2/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p2/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p2/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p2/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p2/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 + +:_p7_0 44p2/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 1875 +:_p7_1 44p2/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 +:_p7_2 44p2/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p2/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p2/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p2/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p2/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p7_2/3 for l1_1/2 diff --git a/vendor/vorbis/vq/44p3.vqs b/vendor/vorbis/vq/44p3.vqs new file mode 100644 index 0000000..b1c66a6 --- /dev/null +++ b/vendor/vorbis/vq/44p3.vqs @@ -0,0 +1,52 @@ +GO + +>_44p3 noninterleaved +haux 44p3/resaux_0.vqd _44p3_short 0,42,2 8 +haux 44p3/resaux_1.vqd _44p3_long 0,170,2 8 +haux 44p3/resaux_2.vqd _44p3_lfe 0,2,2 2 + +#iter 0 + +# 0 1 1 2 7 17 31 + +# 0 99 99 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p3/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p3/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p3/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p3/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p3/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p3/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p3/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p3/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p3/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p3/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 44p3/res_sub0_part6_pass2.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p7_0 44p3/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 1875 +:_p7_1 44p3/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 +:_p7_2 44p3/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p3/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p3/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p3/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p3/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p7_2/3 for l1_1/2 diff --git a/vendor/vorbis/vq/44p4.vqs b/vendor/vorbis/vq/44p4.vqs new file mode 100644 index 0000000..4b70436 --- /dev/null +++ b/vendor/vorbis/vq/44p4.vqs @@ -0,0 +1,52 @@ +GO + +>_44p4 noninterleaved +haux 44p4/resaux_0.vqd _44p4_short 0,42,2 8 +haux 44p4/resaux_1.vqd _44p4_long 0,170,2 8 +haux 44p4/resaux_2.vqd _44p4_lfe 0,2,2 2 + +#iter 0 + +# 0 1 1 2 7 17 31 + +# 0 99 99 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p4/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p4/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p4/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p4/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p4/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p4/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p4/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p4/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p4/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p4/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 44p3/res_sub0_part6_pass2.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p7_0 44p4/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 1875 +:_p7_1 44p4/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 +:_p7_2 44p4/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p4/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p4/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p4/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p4/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p7_2/3 for l1_1/2 diff --git a/vendor/vorbis/vq/44p5.vqs b/vendor/vorbis/vq/44p5.vqs new file mode 100644 index 0000000..0372321 --- /dev/null +++ b/vendor/vorbis/vq/44p5.vqs @@ -0,0 +1,52 @@ +GO + +>_44p5 noninterleaved +haux 44p5/resaux_0.vqd _44p5_short 0,42,2 8 +haux 44p5/resaux_1.vqd _44p5_long 0,170,2 8 +haux 44p5/resaux_2.vqd _44p5_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 4 7 17 31 + +# 1 2 4 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p5/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p5/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p5/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p5/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p5/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p5/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p5/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p5/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p5/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p5/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 44p3/res_sub0_part6_pass2.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p7_0 44p5/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 1875 +:_p7_1 44p5/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 +:_p7_2 44p5/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p5/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p5/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p5/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p5/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p6_2/3 for l1_2/3 diff --git a/vendor/vorbis/vq/44p6.vqs b/vendor/vorbis/vq/44p6.vqs new file mode 100644 index 0000000..9daad60 --- /dev/null +++ b/vendor/vorbis/vq/44p6.vqs @@ -0,0 +1,52 @@ +GO + +>_44p6 noninterleaved +haux 44p6/resaux_0.vqd _44p6_short 0,42,2 8 +haux 44p6/resaux_1.vqd _44p6_long 0,170,2 8 +haux 44p6/resaux_2.vqd _44p6_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 4 7 17 31 + +# 1 2 4 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p6/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p6/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p6/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p6/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p6/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p6/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p6/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p6/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p6/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p6/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 44p3/res_sub0_part6_pass2.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p7_0 44p6/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 1875 +:_p7_1 44p6/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 +:_p7_2 44p6/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p6/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p6/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p6/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p6/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 +# reuse p6_2/3 for l1_2/3 diff --git a/vendor/vorbis/vq/44p7.vqs b/vendor/vorbis/vq/44p7.vqs new file mode 100644 index 0000000..9ec5d02 --- /dev/null +++ b/vendor/vorbis/vq/44p7.vqs @@ -0,0 +1,52 @@ +GO + +>_44p7 noninterleaved +haux 44p7/resaux_0.vqd _44p7_short 0,42,2 8 +haux 44p7/resaux_1.vqd _44p7_long 0,170,2 8 +haux 44p7/resaux_2.vqd _44p7_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 4 7 17 31 + +# 1 2 4 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p7/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p7/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p7/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p7/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p7/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p7/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p7/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p7/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p7/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p7/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 44p3/res_sub0_part6_pass2.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p7_0 44p7/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 1875 +:_p7_1 44p7/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 +:_p7_2 44p7/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p7/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p7/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p7/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p7/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 1350 +# reuse p6_2/3 for l1_2/3 diff --git a/vendor/vorbis/vq/44p8.vqs b/vendor/vorbis/vq/44p8.vqs new file mode 100644 index 0000000..a75af84 --- /dev/null +++ b/vendor/vorbis/vq/44p8.vqs @@ -0,0 +1,52 @@ +GO + +>_44p8 noninterleaved +haux 44p8/resaux_0.vqd _44p8_short 0,42,2 8 +haux 44p8/resaux_1.vqd _44p8_long 0,170,2 8 +haux 44p8/resaux_2.vqd _44p8_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 4 7 17 31 + +# 1 2 4 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p8/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p8/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p8/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p8/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p8/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p8/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p8/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p8/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p8/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p8/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 44p3/res_sub0_part6_pass2.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p7_0 44p8/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 3125 +:_p7_1 44p8/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 1250 +:_p7_2 44p8/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p8/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p8/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p8/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p8/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 1350 +# reuse p6_2/3 for l1_2/3 diff --git a/vendor/vorbis/vq/44p9.vqs b/vendor/vorbis/vq/44p9.vqs new file mode 100644 index 0000000..4c00780 --- /dev/null +++ b/vendor/vorbis/vq/44p9.vqs @@ -0,0 +1,52 @@ +GO + +>_44p9 noninterleaved +haux 4pp9/resaux_0.vqd _44p9_short 0,42,2 8 +haux 4pp9/resaux_1.vqd _44p9_long 0,170,2 8 +haux 4pp9/resaux_2.vqd _44p9_lfe 0,2,2 2 + +#iter 0 + +# 0 1 2 4 7 17 31 + +# 1 2 4 7 17 31 + + +# 0 1 2 3 4 5 6 7 +# 1 . . . . . +# 2 . . . . . . +# 4 . . . +# 8 . + +:_p1_0 44p9/res_sub0_part1_pass2.vqd, 5, nonseq cull, 0 +- 1 +:_p2_0 44p9/res_sub0_part2_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p3_0 44p9/res_sub0_part3_pass0.vqd, 5, nonseq cull, 0 +- 3 +:_p3_1 44p9/res_sub0_part3_pass1.vqd, 5, nonseq cull, 0 +- 1 + +:_p4_0 44p9/res_sub0_part4_pass0.vqd, 5, nonseq cull, 0 +- 5 +:_p4_1 44p9/res_sub0_part4_pass1.vqd, 5, nonseq cull, 0 +- 1 2 + +:_p5_0 44p9/res_sub0_part5_pass0.vqd, 5, nonseq cull, 0 +- 7 14 +:_p5_1 44p9/res_sub0_part5_pass1.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p6_0 44p9/res_sub0_part6_pass0.vqd, 5, nonseq cull, 0 +- 21 +:_p6_1 44p9/res_sub0_part6_pass1.vqd, 5, nonseq cull, 0 +- 7 +# reuse p5_1 :_p6_2 44p3/res_sub0_part6_pass2.vqd, 1, nonseq cull, 0 +- 1 2 3 + +:_p7_0 44p9/res_sub0_part7_pass0.vqd, 5, nonseq, 0 +- 3125 6250 +:_p7_1 44p9/res_sub0_part7_pass1.vqd, 5, nonseq, 0 +- 625 1250 +:_p7_2 44p9/res_sub0_part7_pass2.vqd, 1, nonseq, 0 +- 25 50 75 100 125 150 175 200 225 250 275 300 +:_p7_3 44p9/res_sub0_part7_pass3.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 + +# 32 + +# 0 0 +# +# 0 1 +# 1 . . +# 2 . . +# 4 . + +:_l0_0 44p9/res_sub1_part0_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_l0_1 44p9/res_sub1_part0_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_l1_0 44p9/res_sub1_part1_pass0.vqd, 2, nonseq, 0 +- 625 1250 +# reuse p6_2/3 for l1_2/3 diff --git a/vendor/vorbis/vq/44u0.vqs b/vendor/vorbis/vq/44u0.vqs new file mode 100644 index 0000000..5bc3f60 --- /dev/null +++ b/vendor/vorbis/vq/44u0.vqs @@ -0,0 +1,33 @@ +GO + +>_44u0_ noninterleaved +haux 44u0/resaux_0.vqd _44u0__short 0,16,2 8 + +>_44u0_ noninterleaved +haux 44u0/resaux_1.vqd _44u0__long 0,64,2 8 + +#iter 0 + + + +# 0 1 1 2 2 4 32 + +# 25 0 45 0 0 0 0 +# +# 0 1 2 3 4 5 6 7 +# 1 . . +# 2 . . +# 4 . . . . . . + +:_p1_0 44u0/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u0/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u0/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u0/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u0/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p6_0 44u0/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44u0/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44u0/res_part7_pass0.vqd, 4, nonseq, 0 +- 169 338 +:_p7_1 44u0/res_part7_pass1.vqd, 2, nonseq, 0 +- 13 26 39 52 65 78 +:_p7_2 44u0/res_part7_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 + diff --git a/vendor/vorbis/vq/44u1.vqs b/vendor/vorbis/vq/44u1.vqs new file mode 100644 index 0000000..ed19dc6 --- /dev/null +++ b/vendor/vorbis/vq/44u1.vqs @@ -0,0 +1,33 @@ +GO + +>_44u1_ noninterleaved +haux 44u1/resaux_0.vqd _44u1__short 0,16,2 8 + +>_44u1_ noninterleaved +haux 44u1/resaux_1.vqd _44u1__long 0,64,2 8 + +#iter 0 + + + +# 0 1 1 2 2 4 32 + +# 25 0 45 0 0 0 0 +# +# 0 1 2 3 4 5 6 7 +# 1 . . +# 2 . . +# 4 . . . . . . + +:_p1_0 44u1/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u1/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u1/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u1/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u1/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p6_0 44u1/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44u1/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44u1/res_part7_pass0.vqd, 2, nonseq, 0 +- 169 338 507 +:_p7_1 44u1/res_part7_pass1.vqd, 2, nonseq, 0 +- 13 26 39 52 65 78 +:_p7_2 44u1/res_part7_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 + diff --git a/vendor/vorbis/vq/44u2.vqs b/vendor/vorbis/vq/44u2.vqs new file mode 100644 index 0000000..314461e --- /dev/null +++ b/vendor/vorbis/vq/44u2.vqs @@ -0,0 +1,32 @@ +GO + +>_44u2_ noninterleaved +haux 44u2/resaux_0.vqd _44u2__short 0,16,2 8 + +>_44u2_ noninterleaved +haux 44u2/resaux_1.vqd _44u2__long 0,64,2 8 + +#iter 0 + + + +# 0 1 1 2 2 4 32 + +# 25 0 45 0 0 0 0 +# +# 0 1 2 3 4 5 6 7 +# 1 . . +# 2 . . +# 4 . . . . . . + +:_p1_0 44u2/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u2/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u2/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u2/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u2/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p6_0 44u2/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44u2/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44u2/res_part7_pass0.vqd, 2, nonseq, 0 +- 169 338 507 676 +:_p7_1 44u2/res_part7_pass1.vqd, 2, nonseq, 0 +- 13 26 39 52 65 78 +:_p7_2 44u2/res_part7_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 diff --git a/vendor/vorbis/vq/44u3.vqs b/vendor/vorbis/vq/44u3.vqs new file mode 100644 index 0000000..c882109 --- /dev/null +++ b/vendor/vorbis/vq/44u3.vqs @@ -0,0 +1,33 @@ + +GO + +>_44u3_ noninterleaved +haux 44u3/resaux_0.vqd _44u3__short 0,16,2 8 + +>_44u3_ noninterleaved +haux 44u3/resaux_1.vqd _44u3__long 0,64,2 8 + +#iter 0 + + + +# 0 1 1 2 2 4 32 + +# 25 0 45 0 0 0 0 +# +# 0 1 2 3 4 5 6 7 +# 1 . . +# 2 . . +# 4 . . . . . . + +:_p1_0 44u3/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u3/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u3/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u3/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u3/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p6_0 44u3/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44u3/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44u3/res_part7_pass0.vqd, 2, nonseq, 0 +- 255 510 765 1020 +:_p7_1 44u3/res_part7_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 119 +:_p7_2 44u3/res_part7_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 diff --git a/vendor/vorbis/vq/44u4.vqs b/vendor/vorbis/vq/44u4.vqs new file mode 100644 index 0000000..cb4d9ba --- /dev/null +++ b/vendor/vorbis/vq/44u4.vqs @@ -0,0 +1,33 @@ + +GO + +>_44u4_ noninterleaved +haux 44u4/resaux_0.vqd _44u4__short 0,16,2 8 + +>_44u4_ noninterleaved +haux 44u4/resaux_1.vqd _44u4__long 0,64,2 8 + +#iter 0 + + + +# 0 1 1 2 2 4 32 + +# 25 0 45 0 0 0 0 +# +# 0 1 2 3 4 5 6 7 +# 1 . . +# 2 . . +# 4 . . . . . . + +:_p1_0 44u4/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u4/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u4/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u4/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u4/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p6_0 44u4/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44u4/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44u4/res_part7_pass0.vqd, 2, nonseq, 0 +- 255 510 765 1020 1275 1530 +:_p7_1 44u4/res_part7_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 119 +:_p7_2 44u4/res_part7_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 diff --git a/vendor/vorbis/vq/44u5.vqs b/vendor/vorbis/vq/44u5.vqs new file mode 100644 index 0000000..a3c175d --- /dev/null +++ b/vendor/vorbis/vq/44u5.vqs @@ -0,0 +1,35 @@ + +GO + +>_44u5_ noninterleaved +haux 44u5/resaux_0.vqd _44u5__short 0,16,2 10 + +>_44u5_ noninterleaved +haux 44u5/resaux_1.vqd _44u5__long 0,64,2 10 + +#iter 0 + +# 0 1 1 2 2 4 4 16 60 + +# 30 0 50 0 80 0 0 0 +# +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . +# 2 . . . +# 4 . . . . . . . + +:_p1_0 44u5/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u5/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u5/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u5/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u5/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 44u5/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p7_0 44u5/res_part7_pass0.vqd, 4, nonseq, 0 +- 11 +:_p7_1 44u5/res_part7_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p8_0 44u5/res_part8_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 +:_p8_1 44u5/res_part8_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p9_0 44u5/res_part9_pass0.vqd, 2, nonseq, 0 +- 255 510 765 1020 1275 1530 +:_p9_1 44u5/res_part9_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 119 +:_p9_2 44u5/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 diff --git a/vendor/vorbis/vq/44u6.vqs b/vendor/vorbis/vq/44u6.vqs new file mode 100644 index 0000000..ca8b7b1 --- /dev/null +++ b/vendor/vorbis/vq/44u6.vqs @@ -0,0 +1,35 @@ + +GO + +>_44u6_ noninterleaved +haux 44u6/resaux_0.vqd _44u6__short 0,16,2 10 + +>_44u6_ noninterleaved +haux 44u6/resaux_1.vqd _44u6__long 0,64,2 10 + +#iter 0 + +# 0 1 1 2 2 4 4 16 60 + +# 30 0 50 0 80 0 0 0 +# +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . +# 2 . . . +# 4 . . . . . . . + +:_p1_0 44u6/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u6/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u6/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u6/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u6/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 44u6/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p7_0 44u6/res_part7_pass0.vqd, 4, nonseq, 0 +- 11 +:_p7_1 44u6/res_part7_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p8_0 44u6/res_part8_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 +:_p8_1 44u6/res_part8_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p9_0 44u6/res_part9_pass0.vqd, 2, nonseq, 0 +- 255 510 765 1020 1275 1530 1785 +:_p9_1 44u6/res_part9_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 119 +:_p9_2 44u6/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 diff --git a/vendor/vorbis/vq/44u7.vqs b/vendor/vorbis/vq/44u7.vqs new file mode 100644 index 0000000..2efe5aa --- /dev/null +++ b/vendor/vorbis/vq/44u7.vqs @@ -0,0 +1,34 @@ +GO + +>_44u7_ noninterleaved +haux 44u7/resaux_0.vqd _44u7__short 0,16,2 10 + +>_44u7_ noninterleaved +haux 44u7/resaux_1.vqd _44u7__long 0,64,2 10 + +#iter 0 + +# 0 1 1 2 2 4 4 16 60 + +# 30 0 50 0 80 0 0 0 +# +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . +# 2 . . . +# 4 . . . . . . . + +:_p1_0 44u7/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u7/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 44u7/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 44u7/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 44u7/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 44u7/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p7_0 44u7/res_part7_pass0.vqd, 4, nonseq, 0 +- 11 +:_p7_1 44u7/res_part7_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p8_0 44u7/res_part8_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 +:_p8_1 44u7/res_part8_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p9_0 44u7/res_part9_pass0.vqd, 2, nonseq, 0 +- 637 1274 1911 2548 3185 +:_p9_1 44u7/res_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 +:_p9_2 44u7/res_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 diff --git a/vendor/vorbis/vq/44u8.vqs b/vendor/vorbis/vq/44u8.vqs new file mode 100644 index 0000000..ecedb09 --- /dev/null +++ b/vendor/vorbis/vq/44u8.vqs @@ -0,0 +1,35 @@ +GO + +>_44u8s noninterleaved +haux 44u8/resaux_0.vqd _44u8__short 0,16,2 10 + +>_44u8 noninterleaved +haux 44u8/resaux_1.vqd _44u8__long 0,64,2 10 + + +# 0 1 2 4 8 16 32 71 157 + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . . . +# 2 . . . . . +# 4 . . . . . + +:_p1_0 44u8/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u8/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44u8/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44u8/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 44u8/res_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 44u8/res_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 44u8/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44u8/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44u8/res_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 44u8/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44u8/res_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 44u8/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 44u8/res_part9_pass0.vqd, 2, nonseq, 0 +- 931 1862 2793 3724 +:_p9_1 44u8/res_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 343 392 441 +:_p9_2 44u8/res_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 diff --git a/vendor/vorbis/vq/44u9.vqs b/vendor/vorbis/vq/44u9.vqs new file mode 100644 index 0000000..42a3877 --- /dev/null +++ b/vendor/vorbis/vq/44u9.vqs @@ -0,0 +1,36 @@ + +GO + +>_44u9s noninterleaved +haux 44u9/resaux_0.vqd _44u9__short 0,16,2 10 + +>_44u9 noninterleaved +haux 44u9/resaux_1.vqd _44u9__long 0,64,2 10 + + +# 0 1 2 4 8 16 32 71 157 + +# 0 1 2 3 4 5 6 7 8 9 +# 1 . . . . . +# 2 . . . . . +# 4 . . . . . + +:_p1_0 44u9/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 44u9/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 44u9/res_part3_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p4_0 44u9/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + +:_p5_0 44u9/res_part5_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p5_1 44u9/res_part5_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p6_0 44u9/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 44u9/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 44u9/res_part7_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 66 +:_p7_1 44u9/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 44u9/res_part8_pass0.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p8_1 44u9/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 9 10 + +:_p9_0 44u9/res_part9_pass0.vqd, 2, nonseq, 0 +- 931 1862 2793 3724 4655 5586 6517 +:_p9_1 44u9/res_part9_pass1.vqd, 2, nonseq, 0 +- 49 98 147 196 245 294 343 392 441 +:_p9_2 44u9/res_part9_pass2.vqd, 1, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 diff --git a/vendor/vorbis/vq/8.vqs b/vendor/vorbis/vq/8.vqs new file mode 100644 index 0000000..517a589 --- /dev/null +++ b/vendor/vorbis/vq/8.vqs @@ -0,0 +1,43 @@ +GO + +>_8c0_s noninterleaved +haux 8c0_s/resaux_0.vqd _8c0_s_single 0,64,2 10 + +:_p1_0 8c0_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 8c0_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 8c0_s/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 8c0_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 8c0_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 8c0_s/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 8c0_s/res_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 8c0_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 8c0_s/res_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 8c0_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 8c0_s/res_part9_pass0.vqd, 4, nonseq, 0 +- 315 +:_p9_1 8c0_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p9_2 8c0_s/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 + +>_8c1_s noninterleaved +haux 8c1_s/resaux_0.vqd _8c1_s_single 0,64,2 10 + +:_p1_0 8c1_s/res_part1_pass2.vqd, 8, nonseq cull, 0 +- 1 +:_p2_0 8c1_s/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p3_0 8c1_s/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 8c1_s/res_part4_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p5_0 8c1_s/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 8c1_s/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 6 7 8 + + +:_p7_0 8c1_s/res_part7_pass0.vqd, 4, nonseq cull, 0 +- 11 +:_p7_1 8c1_s/res_part7_pass1.vqd, 2, nonseq cull, 0 +- 1 2 3 4 5 + +:_p8_0 8c1_s/res_part8_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p8_1 8c1_s/res_part8_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p9_0 8c1_s/res_part9_pass0.vqd, 2, nonseq, 0 +- 315 630 945 1260 1575 1890 +:_p9_1 8c1_s/res_part9_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p9_2 8c1_s/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 diff --git a/vendor/vorbis/vq/8u.vqs b/vendor/vorbis/vq/8u.vqs new file mode 100644 index 0000000..0ed0ec8 --- /dev/null +++ b/vendor/vorbis/vq/8u.vqs @@ -0,0 +1,41 @@ + +GO + +>_8u0_ noninterleaved +haux 8u0/resaux_0.vqd _8u0__single 0,64,2 8 + + +:_p1_0 8u0/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 8u0/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 8u0/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 8u0/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 8u0/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p6_0 8u0/res_part6_pass0.vqd, 2, nonseq cull, 0 +- 5 10 15 20 25 30 +:_p6_1 8u0/res_part6_pass1.vqd, 2, nonseq cull, 0 +- 1 2 + +:_p7_0 8u0/res_part7_pass0.vqd, 4, nonseq, 0 +- 315 +:_p7_1 8u0/res_part7_pass1.vqd, 2, nonseq, 0 +- 21 42 63 84 105 126 147 +:_p7_2 8u0/res_part7_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 9 10 + + +>_8u1_ noninterleaved +haux 8u1/resaux_0.vqd _8u1__single 0,64,2 10 + +:_p1_0 8u1/res_part1_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p2_0 8u1/res_part2_pass2.vqd, 4, nonseq cull, 0 +- 1 +:_p3_0 8u1/res_part3_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p4_0 8u1/res_part4_pass2.vqd, 4, nonseq cull, 0 +- 1 2 +:_p5_0 8u1/res_part5_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 +:_p6_0 8u1/res_part6_pass2.vqd, 2, nonseq cull, 0 +- 1 2 3 4 + +:_p7_0 8u1/res_part7_pass0.vqd, 4, nonseq, 0 +- 11 +:_p7_1 8u1/res_part7_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p8_0 8u1/res_part8_pass0.vqd, 2, nonseq, 0 +- 11 22 33 44 55 +:_p8_1 8u1/res_part8_pass1.vqd, 2, nonseq, 0 +- 1 2 3 4 5 + +:_p9_0 8u1/res_part9_pass0.vqd, 2, nonseq, 0 +- 255 510 765 1020 1275 1530 1785 +:_p9_1 8u1/res_part9_pass1.vqd, 2, nonseq, 0 +- 17 34 51 68 85 102 119 +:_p9_2 8u1/res_part9_pass2.vqd, 2, nonseq, 0 +- 1 2 3 4 5 6 7 8 + diff --git a/vendor/vorbis/vq/Makefile.am b/vendor/vorbis/vq/Makefile.am new file mode 100644 index 0000000..e9c272e --- /dev/null +++ b/vendor/vorbis/vq/Makefile.am @@ -0,0 +1,36 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_PROGRAMS = latticebuild latticetune huffbuild distribution +CLEANFILES = $(EXTRA_PROGRAMS) + +AM_CPPFLAGS = -I../lib -I$(top_srcdir)/include @OGG_CFLAGS@ +AM_LDFLAGS = -static +LDADD = ../lib/libvorbis.la + +latticebuild_SOURCES = latticebuild.c vqgen.c bookutil.c\ + vqgen.h bookutil.h localcodebook.h +latticetune_SOURCES = latticetune.c vqgen.c bookutil.c\ + vqgen.h bookutil.h localcodebook.h +huffbuild_SOURCES = huffbuild.c vqgen.c bookutil.c\ + vqgen.h bookutil.h localcodebook.h +distribution_SOURCES = distribution.c bookutil.c\ + bookutil.h localcodebook.h + +vqs_files = 16.vqs 16u.vqs 44c-1.vqs 44c0.vqs 44c1.vqs 44c2.vqs \ + 44c3.vqs 44c4.vqs 44c5.vqs 44c6.vqs 44c7.vqs 44c8.vqs 44c9.vqs \ + 44u0.vqs 44u1.vqs 44u2.vqs 44u3.vqs 44u4.vqs 44u5.vqs 44u6.vqs \ + 44u7.vqs 44u8.vqs 44u9.vqs 8.vqs 8u.vqs floor_11.vqs floor_22.vqs \ + floor_44.vqs 44p-1.vqs 44p0.vqs 44p1.vqs 44p2.vqs 44p3.vqs 44p4.vqs \ + 44p5.vqs 44p6.vqs 44p7.vqs 44p8.vqs 44p9.vqs + +EXTRA_DIST = $(vqs_files) make_floor_books.pl make_residue_books.pl \ + metrics.c + +debugvq: + $(MAKE) vq CFLAGS="@DEBUG@" + +profilevq: + $(MAKE) vq CFLAGS="@PROFILE@" + +vq: + $(MAKE) $(EXTRA_PROGRAMS) diff --git a/vendor/vorbis/vq/bookutil.c b/vendor/vorbis/vq/bookutil.c new file mode 100644 index 0000000..c8b894e --- /dev/null +++ b/vendor/vorbis/vq/bookutil.c @@ -0,0 +1,476 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: utility functions for loading .vqh and .vqd files + + ********************************************************************/ + +#include +#include +#include +#include +#include +#include "bookutil.h" + +int _best(codebook *book, float *a, int step){ + + int dim=book->dim; + int i,j,o; + int minval=book->minval; + int del=book->delta; + int qv=book->quantvals; + int ze=(qv>>1); + int index=0; + /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ + + if(del!=1){ + for(i=0,o=step*(dim-1);i>1))/del; + int m = (v=qv?qv-1:m)); + } + }else{ + for(i=0,o=step*(dim-1);i=qv?qv-1:m)); + } + } + + if(book->c->lengthlist[index]<=0){ + const static_codebook *c=book->c; + int best=-1; + /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ + int e[8]={0,0,0,0,0,0,0,0}; + int maxval = book->minval + book->delta*(book->quantvals-1); + for(i=0;ientries;i++){ + if(c->lengthlist[i]>0){ + float this=0; + for(j=0;j=maxval) + e[j++]=0; + if(e[j]>=0) + e[j]+=book->delta; + e[j]= -e[j]; + } + } + + return index; +} + +/* A few little utils for reading files */ +/* read a line. Use global, persistent buffering */ +static char *linebuffer=NULL; +static int lbufsize=0; +char *get_line(FILE *in){ + long sofar=0; + if(feof(in))return NULL; + + while(1){ + int gotline=0; + + while(!gotline){ + if(sofar+1>=lbufsize){ + if(!lbufsize){ + lbufsize=1024; + linebuffer=_ogg_malloc(lbufsize); + }else{ + lbufsize*=2; + linebuffer=_ogg_realloc(linebuffer,lbufsize); + } + } + { + long c=fgetc(in); + switch(c){ + case EOF: + if(sofar==0)return(NULL); + /* fallthrough correct */ + case '\n': + linebuffer[sofar]='\0'; + gotline=1; + break; + default: + linebuffer[sofar++]=c; + linebuffer[sofar]='\0'; + break; + } + } + } + + if(linebuffer[0]=='#'){ + sofar=0; + }else{ + return(linebuffer); + } + } +} + +/* read the next numerical value from the given file */ +static char *value_line_buff=NULL; + +int get_line_value(FILE *in,float *value){ + char *next; + + if(!value_line_buff)return(-1); + + *value=strtod(value_line_buff, &next); + if(next==value_line_buff){ + value_line_buff=NULL; + return(-1); + }else{ + value_line_buff=next; + while(*value_line_buff>44)value_line_buff++; + if(*value_line_buff==44)value_line_buff++; + return(0); + } +} + +int get_next_value(FILE *in,float *value){ + while(1){ + if(get_line_value(in,value)){ + value_line_buff=get_line(in); + if(!value_line_buff)return(-1); + }else{ + return(0); + } + } +} + +int get_next_ivalue(FILE *in,long *ivalue){ + float value; + int ret=get_next_value(in,&value); + *ivalue=value; + return(ret); +} + +static float sequence_base=0.f; +static int v_sofar=0; +void reset_next_value(void){ + value_line_buff=NULL; + sequence_base=0.f; + v_sofar=0; +} + +char *setup_line(FILE *in){ + reset_next_value(); + value_line_buff=get_line(in); + return(value_line_buff); +} + + +int get_vector(codebook *b,FILE *in,int start, int n,float *a){ + int i; + const static_codebook *c=b->c; + + while(1){ + + if(v_sofar==n || get_line_value(in,a)){ + reset_next_value(); + if(get_next_value(in,a)) + break; + for(i=0;idim;i++) + if(get_line_value(in,a+i)) + break; + + if(i==c->dim){ + float temp=a[c->dim-1]; + for(i=0;idim;i++)a[i]-=sequence_base; + if(c->q_sequencep)sequence_base=temp; + v_sofar++; + return(0); + } + sequence_base=0.f; + } + + return(-1); +} + +/* read lines fromt he beginning until we find one containing the + specified string */ +char *find_seek_to(FILE *in,char *s){ + rewind(in); + while(1){ + char *line=get_line(in); + if(line){ + if(strstr(line,s)) + return(line); + }else + return(NULL); + } +} + + +/* this reads the format as written by vqbuild/latticebuild; innocent + (legal) tweaking of the file that would not affect its valid + header-ness will break this routine */ + +codebook *codebook_load(char *filename){ + codebook *b=_ogg_calloc(1,sizeof(codebook)); + static_codebook *c=(static_codebook *)(b->c=_ogg_calloc(1,sizeof(static_codebook))); + int quant_to_read=0; + FILE *in=fopen(filename,"r"); + char *line; + long i; + + if(in==NULL){ + fprintf(stderr,"Couldn't open codebook %s\n",filename); + exit(1); + } + + /* find the codebook struct */ + find_seek_to(in,"static const static_codebook "); + + /* get the major important values */ + line=get_line(in); + if(sscanf(line,"%ld, %ld,", + &(c->dim),&(c->entries))!=2){ + fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line); + exit(1); + } + line=get_line(in); + line=get_line(in); + if(sscanf(line,"%d, %ld, %ld, %d, %d,", + &(c->maptype),&(c->q_min),&(c->q_delta),&(c->q_quant), + &(c->q_sequencep))!=5){ + fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line); + exit(1); + } + + switch(c->maptype){ + case 0: + quant_to_read=0; + break; + case 1: + quant_to_read=_book_maptype1_quantvals(c); + break; + case 2: + quant_to_read=c->entries*c->dim; + break; + } + + /* load the quantized entries */ + find_seek_to(in,"static const long _vq_quantlist_"); + reset_next_value(); + c->quantlist=_ogg_malloc(sizeof(long)*quant_to_read); + for(i=0;iquantlist+i)){ + fprintf(stderr,"out of data while reading codebook %s\n",filename); + exit(1); + } + + /* load the lengthlist */ + find_seek_to(in,"_lengthlist"); + reset_next_value(); + c->lengthlist=_ogg_malloc(sizeof(long)*c->entries); + for(i=0;ientries;i++) + if(get_next_ivalue(in,c->lengthlist+i)){ + fprintf(stderr,"out of data while reading codebook %s\n",filename); + exit(1); + } + + /* got it all */ + fclose(in); + + vorbis_book_init_encode(b,c); + b->valuelist=_book_unquantize(c,c->entries,NULL); + + return(b); +} + +void spinnit(char *s,int n){ + static int p=0; + static long lasttime=0; + long test; + struct timeval thistime; + + gettimeofday(&thistime,NULL); + test=thistime.tv_sec*10+thistime.tv_usec/100000; + if(lasttime!=test){ + lasttime=test; + + fprintf(stderr,"%s%d ",s,n); + + p++;if(p>3)p=0; + switch(p){ + case 0: + fprintf(stderr,"| \r"); + break; + case 1: + fprintf(stderr,"/ \r"); + break; + case 2: + fprintf(stderr,"- \r"); + break; + case 3: + fprintf(stderr,"\\ \r"); + break; + } + fflush(stderr); + } +} + +void build_tree_from_lengths(int vals, long *hist, long *lengths){ + int i,j; + long *membership=_ogg_malloc(vals*sizeof(long)); + long *histsave=alloca(vals*sizeof(long)); + memcpy(histsave,hist,vals*sizeof(long)); + + for(i=0;i1;i--){ + int first=-1,second=-1; + long least=-1; + + spinnit("building... ",i); + + /* find the two nodes to join */ + for(j=0;j0) + newhist[upper++]=hist[i]; + + if(upper != vals){ + fprintf(stderr,"\rEliminating %d unused entries; %d entries remain\n", + vals-upper,upper); + } + + build_tree_from_lengths(upper,newhist,lengthlist); + + upper=0; + for(i=0;i0) + lengths[i]=lengthlist[upper++]; + else + lengths[i]=0; + + free(lengthlist); +} + +void write_codebook(FILE *out,char *name,const static_codebook *c){ + int i,j,k; + + /* save the book in C header form */ + + /* first, the static vectors, then the book structure to tie it together. */ + /* quantlist */ + if(c->quantlist){ + long vals=(c->maptype==1?_book_maptype1_quantvals(c):c->entries*c->dim); + fprintf(out,"static const long _vq_quantlist_%s[] = {\n",name); + for(j=0;jquantlist[j]); + } + fprintf(out,"};\n\n"); + } + + /* lengthlist */ + fprintf(out,"static const char _vq_lengthlist_%s[] = {\n",name); + for(j=0;jentries;){ + fprintf(out,"\t"); + for(k=0;k<16 && jentries;k++,j++) + fprintf(out,"%2ld,",c->lengthlist[j]); + fprintf(out,"\n"); + } + fprintf(out,"};\n\n"); + + /* tie it all together */ + + fprintf(out,"static const static_codebook %s = {\n",name); + + fprintf(out,"\t%ld, %ld,\n",c->dim,c->entries); + fprintf(out,"\t(char *)_vq_lengthlist_%s,\n",name); + fprintf(out,"\t%d, %ld, %ld, %d, %d,\n", + c->maptype,c->q_min,c->q_delta,c->q_quant,c->q_sequencep); + if(c->quantlist) + fprintf(out,"\t(long *)_vq_quantlist_%s,\n",name); + else + fprintf(out,"\tNULL,\n"); + + fprintf(out,"\t0\n};\n\n"); +} diff --git a/vendor/vorbis/vq/bookutil.h b/vendor/vorbis/vq/bookutil.h new file mode 100644 index 0000000..d8fbcbe --- /dev/null +++ b/vendor/vorbis/vq/bookutil.h @@ -0,0 +1,42 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: utility functions for loading .vqh and .vqd files + + ********************************************************************/ + +#ifndef _V_BOOKUTIL_H_ +#define _V_BOOKUTIL_H_ + +#include +#include + +#include "localcodebook.h" + +extern char *get_line(FILE *in); +extern char *setup_line(FILE *in); +extern int get_line_value(FILE *in,float *value); +extern int get_next_value(FILE *in,float *value); +extern int get_next_ivalue(FILE *in,long *ivalue); +extern void reset_next_value(void); +extern int get_vector(codebook *b,FILE *in,int start,int num,float *a); +extern char *find_seek_to(FILE *in,char *s); + +extern codebook *codebook_load(char *filename); +extern void write_codebook(FILE *out,char *name,const static_codebook *c); + +extern void spinnit(char *s,int n); +extern void build_tree_from_lengths(int vals, long *hist, long *lengths); +extern void build_tree_from_lengths0(int vals, long *hist, long *lengths); + +#endif + diff --git a/vendor/vorbis/vq/distribution.c b/vendor/vorbis/vq/distribution.c new file mode 100644 index 0000000..7c0c095 --- /dev/null +++ b/vendor/vorbis/vq/distribution.c @@ -0,0 +1,247 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: utility for finding the distribution in a data set + + ********************************************************************/ + +#include +#include +#include +#include +#include +#include "bookutil.h" + +/* command line: + distribution file.vqd +*/ + +int ascend(const void *a,const void *b){ + return(**((long **)a)-**((long **)b)); +} + +int main(int argc,char *argv[]){ + FILE *in; + long lines=0; + float min; + float max; + long bins=-1; + int flag=0; + long *countarray; + long total=0; + char *line; + + if(argv[1]==NULL){ + fprintf(stderr,"Usage: distribution {data.vqd [bins]| book.vqh} \n\n"); + exit(1); + } + if(argv[2]!=NULL) + bins=atoi(argv[2])-1; + + in=fopen(argv[1],"r"); + if(!in){ + fprintf(stderr,"Could not open input file %s\n",argv[1]); + exit(1); + } + + if(strrchr(argv[1],'.') && strcmp(strrchr(argv[1],'.'),".vqh")==0){ + /* load/decode a book */ + + codebook *b=codebook_load(argv[1]); + static_codebook *c=(static_codebook *)(b->c); + float delta; + int i; + fclose(in); + + switch(c->maptype){ + case 0: + printf("entropy codebook only; no mappings\n"); + exit(0); + break; + case 1: + bins=_book_maptype1_quantvals(c); + break; + case 2: + bins=c->entries*c->dim; + break; + } + + max=min=_float32_unpack(c->q_min); + delta=_float32_unpack(c->q_delta); + + for(i=0;iquantlist[i]*delta+min; + if(val>max)max=val; + } + + printf("Minimum scalar value: %f\n",min); + printf("Maximum scalar value: %f\n",max); + + switch(c->maptype){ + case 1: + { + /* lattice codebook. dump it. */ + int j,k; + long maxcount=0; + long **sort=calloc(bins,sizeof(long *)); + long base=c->lengthlist[0]; + countarray=calloc(bins,sizeof(long)); + + for(i=0;iquantlist+i; + qsort(sort,bins,sizeof(long *),ascend); + + for(i=0;ientries;i++) + if(c->lengthlist[i]>base)base=c->lengthlist[i]; + + /* dump a full, correlated count */ + for(j=0;jentries;j++){ + if(c->lengthlist[j]){ + int indexdiv=1; + printf("%4d: ",j); + for(k=0;kdim;k++){ + int index= (j/indexdiv)%bins; + printf("%+3.1f,", c->quantlist[index]*_float32_unpack(c->q_delta)+ + _float32_unpack(c->q_min)); + indexdiv*=bins; + } + printf("\t|"); + for(k=0;klengthlist[j];k++)printf("*"); + printf("\n"); + } + } + + /* do a rough count */ + for(j=0;jentries;j++){ + int indexdiv=1; + for(k=0;kdim;k++){ + if(c->lengthlist[j]){ + int index= (j/indexdiv)%bins; + countarray[index]+=(1<<(base-c->lengthlist[j])); + indexdiv*=bins; + } + } + } + + /* dump the count */ + + { + long maxcount=0,i,j; + for(i=0;imaxcount)maxcount=countarray[i]; + + for(i=0;iquantlist; + int stars=rint(50./maxcount*countarray[ptr]); + printf("%+08f (%8ld) |",c->quantlist[ptr]*delta+min,countarray[ptr]); + for(j=0;jmax)max=code; + } + + line=setup_line(in); + } + + if(bins<1){ + if((int)(max-min)==min-max){ + bins=max-min; + }else{ + bins=25; + } + } + + printf("\r \r"); + printf("Minimum scalar value: %f\n",min); + printf("Maximum scalar value: %f\n",max); + + if(argv[2]){ + + printf("\n counting hits into %ld bins...\n",bins+1); + countarray=calloc(bins+1,sizeof(long)); + + rewind(in); + line=setup_line(in); + while(line){ + float code; + lines--; + if(!(lines&0xff))spinnit("counting distribution. lines so far...",lines); + + while(line && sscanf(line,"%f",&code)==1){ + line=strchr(line,','); + if(line)line++; + + code-=min; + code/=(max-min); + code*=bins; + countarray[(int)rint(code)]++; + total++; + } + + line=setup_line(in); + } + + /* make a pretty graph */ + { + long maxcount=0,i,j; + for(i=0;imaxcount)maxcount=countarray[i]; + + printf("\r \r"); + printf("Total scalars: %ld\n",total); + for(i=0;ifloor_11 +=8-11c0_s 8-11c1_s + +build line_256x4_class0 0-256 +build line_256x4_0sub0 0-4 +build line_256x4_0sub1 4-10 +build line_256x4_0sub2 10-25 +build line_256x4_0sub3 25-64 + diff --git a/vendor/vorbis/vq/floor_22.vqs b/vendor/vorbis/vq/floor_22.vqs new file mode 100644 index 0000000..b80328e --- /dev/null +++ b/vendor/vorbis/vq/floor_22.vqs @@ -0,0 +1,27 @@ +GO +>floor_22 +=22c0_s 22c1_s 22c2_s + +build line_256x7_class0 0-64 +build line_256x7_class1 0-256 +build line_256x7_0sub1 1-9 +build line_256x7_0sub2 9-25 +build line_256x7_0sub3 25-64 +build line_256x7_1sub1 1-9 +build line_256x7_1sub2 9-25 +build line_256x7_1sub3 25-64 + +build line_512x17_class1 0-8 +build line_512x17_class2 0-64 +build line_512x17_class3 0-64 +build line_512x17_0sub0 0-128 +build line_512x17_1sub0 0-32 +build line_512x17_1sub1 32-128 +build line_512x17_2sub1 1-18 +build line_512x17_2sub2 18-50 +build line_512x17_2sub3 50-128 +build line_512x17_3sub1 1-18 +build line_512x17_3sub2 18-50 +build line_512x17_3sub3 50-128 + + diff --git a/vendor/vorbis/vq/floor_44.vqs b/vendor/vorbis/vq/floor_44.vqs new file mode 100644 index 0000000..dd213f7 --- /dev/null +++ b/vendor/vorbis/vq/floor_44.vqs @@ -0,0 +1,83 @@ +GO +>floor_44 +=44c-1_s 44c0_s 44c1_s 44c2_s 44c3_s 44c4_s 44c5_s 44c6_s 44c7_s 44c8_s 44c9_s + +build line_128x4_class0 0-256 +build line_128x4_0sub0 0-4 +build line_128x4_0sub1 4-10 +build line_128x4_0sub2 10-25 +build line_128x4_0sub3 25-64 + +build line_256x4_class0 0-256 +build line_256x4_0sub0 0-4 +build line_256x4_0sub1 4-10 +build line_256x4_0sub2 10-25 +build line_256x4_0sub3 25-64 + +build line_128x7_class0 0-64 +build line_128x7_class1 0-256 +build line_128x7_0sub1 1-9 +build line_128x7_0sub2 9-25 +build line_128x7_0sub3 25-64 +build line_128x7_1sub1 1-9 +build line_128x7_1sub2 9-25 +build line_128x7_1sub3 25-64 + +build line_128x11_class1 0-8 +build line_128x11_class2 0-64 +build line_128x11_class3 0-64 +build line_128x11_0sub0 0-128 +build line_128x11_1sub0 0-32 +build line_128x11_1sub1 32-128 +build line_128x11_2sub1 1-18 +build line_128x11_2sub2 18-50 +build line_128x11_2sub3 50-128 +build line_128x11_3sub1 1-18 +build line_128x11_3sub2 18-50 +build line_128x11_3sub3 50-128 + +build line_128x17_class1 0-8 +build line_128x17_class2 0-64 +build line_128x17_class3 0-64 +build line_128x17_0sub0 0-128 +build line_128x17_1sub0 0-32 +build line_128x17_1sub1 32-128 +build line_128x17_2sub1 1-18 +build line_128x17_2sub2 18-50 +build line_128x17_2sub3 50-128 +build line_128x17_3sub1 1-18 +build line_128x17_3sub2 18-50 +build line_128x17_3sub3 50-128 + +build line_1024x27_class1 0-16 +build line_1024x27_class2 0-8 +build line_1024x27_class3 0-256 +build line_1024x27_class4 0-64 +build line_1024x27_0sub0 0-128 +build line_1024x27_1sub0 0-32 +build line_1024x27_1sub1 32-128 +build line_1024x27_2sub0 0-32 +build line_1024x27_2sub1 32-128 +build line_1024x27_3sub1 1-18 +build line_1024x27_3sub2 18-50 +build line_1024x27_3sub3 50-128 +build line_1024x27_4sub1 1-18 +build line_1024x27_4sub2 18-50 +build line_1024x27_4sub3 50-128 + +build line_2048x27_class1 0-16 +build line_2048x27_class2 0-8 +build line_2048x27_class3 0-256 +build line_2048x27_class4 0-64 +build line_2048x27_0sub0 0-128 +build line_2048x27_1sub0 0-32 +build line_2048x27_1sub1 32-128 +build line_2048x27_2sub0 0-32 +build line_2048x27_2sub1 32-128 +build line_2048x27_3sub1 1-18 +build line_2048x27_3sub2 18-50 +build line_2048x27_3sub3 50-128 +build line_2048x27_4sub1 1-18 +build line_2048x27_4sub2 18-50 +build line_2048x27_4sub3 50-128 + diff --git a/vendor/vorbis/vq/huffbuild.c b/vendor/vorbis/vq/huffbuild.c new file mode 100644 index 0000000..ba00a2e --- /dev/null +++ b/vendor/vorbis/vq/huffbuild.c @@ -0,0 +1,197 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: hufftree builder + + ********************************************************************/ + +#include +#include +#include +#include +#include "bookutil.h" + +static int nsofar=0; +static int getval(FILE *in,int begin,int n,int group,int max){ + float v; + int i; + long val=0; + + if(nsofar>=n || get_line_value(in,&v)){ + reset_next_value(); + nsofar=0; + if(get_next_value(in,&v)) + return(-1); + for(i=1;i<=begin;i++) + get_line_value(in,&v); + } + + val=(int)v; + nsofar++; + + for(i=1;i=n || get_line_value(in,&v)) + return(getval(in,begin,n,group,max)); + else + val = val*max+(int)v; + return(val); +} + +static void usage(){ + fprintf(stderr, + "usage:\n" + "huffbuild .vqd | [noguard]\n" + " where begin,n,group is first scalar, \n" + " number of scalars of each in line,\n" + " number of scalars in a group\n" + "eg: huffbuild reslongaux.vqd 0,1024,4\n" + "produces reslongaux.vqh\n\n"); + exit(1); +} + +int main(int argc, char *argv[]){ + char *base; + char *infile; + int i,j,k,begin,n,subn,guard=1; + FILE *file; + int maxval=0; + int loval=0; + + if(argc<3)usage(); + if(argc==4)guard=0; + + infile=strdup(argv[1]); + base=strdup(infile); + if(strrchr(base,'.')) + strrchr(base,'.')[0]='\0'; + + { + char *pos=strchr(argv[2],','); + char *dpos=strchr(argv[2],'-'); + if(dpos){ + loval=atoi(argv[2]); + maxval=atoi(dpos+1); + subn=1; + begin=0; + }else{ + begin=atoi(argv[2]); + if(!pos) + usage(); + else + n=atoi(pos+1); + pos=strchr(pos+1,','); + if(!pos) + usage(); + else + subn=atoi(pos+1); + if(n/subn*subn != n){ + fprintf(stderr,"n must be divisible by group\n"); + exit(1); + } + } + } + + /* scan the file for maximum value */ + file=fopen(infile,"r"); + if(!file){ + fprintf(stderr,"Could not open file %s\n",infile); + if(!maxval) + exit(1); + else + fprintf(stderr," making untrained books.\n"); + + } + + if(!maxval){ + i=0; + while(1){ + long v; + if(get_next_ivalue(file,&v))break; + if(v>maxval)maxval=v; + + if(!(i++&0xff))spinnit("loading... ",i); + } + rewind(file); + maxval++; + } + + { + long vals=pow(maxval,subn); + long *hist=_ogg_calloc(vals,sizeof(long)); + long *lengths=_ogg_calloc(vals,sizeof(long)); + + for(j=loval;j=vals)break; + hist[val]++; + if(!(i--&0xff))spinnit("loading... ",i*subn); + } + fclose(file); + } + + /* we have the probabilities, build the tree */ + fprintf(stderr,"Building tree for %ld entries\n",vals); + build_tree_from_lengths0(vals,hist,lengths); + + /* save the book */ + { + char *buffer=alloca(strlen(base)+5); + strcpy(buffer,base); + strcat(buffer,".vqh"); + file=fopen(buffer,"w"); + if(!file){ + fprintf(stderr,"Could not open file %s\n",buffer); + exit(1); + } + } + + /* first, the static vectors, then the book structure to tie it together. */ + /* lengthlist */ + fprintf(file,"static const char _huff_lengthlist_%s[] = {\n",base); + for(j=0;j +#include +#include +#include +#include +#include "bookutil.h" + +/* The purpose of this util is just to finish packaging the + description into a static codebook. It used to count hits for a + histogram, but I've divorced that out to add some flexibility (it + currently generates an equal probability codebook) + + command line: + latticebuild description.vql + + the lattice description file contains two lines: + + + ... + + a threshmap (or pigeonmap) struct is generated by latticehint; + there are fun tricks one can do with the threshmap and cascades, + but the utils don't know them... + + entropy encoding is done by feeding an entry list collected from a + training set and feeding it to latticetune along with the book. + + latticebuild produces a codebook on stdout */ + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +int main(int argc,char *argv[]){ + codebook b; + static_codebook c; + double *quantlist; + long *hits; + + int entries=-1,dim=-1,quantvals=-1,addmul=-1,sequencep=0; + FILE *in=NULL; + char *line,*name; + long i,j; + + memset(&b,0,sizeof(b)); + memset(&c,0,sizeof(c)); + + if(argv[1]==NULL){ + fprintf(stderr,"Need a lattice description file on the command line.\n"); + exit(1); + } + + { + char *ptr; + char *filename=_ogg_calloc(strlen(argv[1])+4,1); + + strcpy(filename,argv[1]); + in=fopen(filename,"r"); + if(!in){ + fprintf(stderr,"Could not open input file %s\n",filename); + exit(1); + } + + ptr=strrchr(filename,'.'); + if(ptr){ + *ptr='\0'; + name=strdup(filename); + }else{ + name=strdup(filename); + } + + } + + /* read the description */ + line=get_line(in); + if(sscanf(line,"%d %d %d %d",&quantvals,&dim,&addmul,&sequencep)!=4){ + if(sscanf(line,"%d %d %d",&quantvals,&dim,&addmul)!=3){ + fprintf(stderr,"Syntax error reading description file (line 1)\n"); + exit(1); + } + } + entries=pow(quantvals,dim); + c.dim=dim; + c.entries=entries; + c.lengthlist=_ogg_malloc(entries*sizeof(long)); + c.maptype=1; + c.q_sequencep=sequencep; + c.quantlist=_ogg_calloc(quantvals,sizeof(long)); + + quantlist=_ogg_malloc(sizeof(double)*c.dim*c.entries); + hits=_ogg_malloc(c.entries*sizeof(long)); + for(j=0;j.00001f) break; + } + if(fac>100)break; + if(jc.q_quant)c.q_quant=ilog(c.quantlist[j]); + } + } + + /* build the [default] codeword lengths */ + memset(c.lengthlist,0,sizeof(long)*entries); + for(i=0;i +#include +#include +#include +#include +#include "bookutil.h" + +static int strrcmp_i(char *s,char *cmp){ + return(strncmp(s+strlen(s)-strlen(cmp),cmp,strlen(cmp))); +} + +/* This util takes a training-collected file listing codewords used in + LSP fitting, then generates new codeword lengths for maximally + efficient integer-bits entropy encoding. + + command line: + latticetune book.vqh input.vqd [unused_entriesp] + + latticetune produces book.vqh on stdout */ + +int main(int argc,char *argv[]){ + codebook *b; + static_codebook *c; + long *lengths; + long *hits; + + int entries=-1,dim=-1,guard=1; + FILE *in=NULL; + char *line,*name; + long j; + + if(argv[1]==NULL){ + fprintf(stderr,"Need a lattice codebook on the command line.\n"); + exit(1); + } + if(argv[2]==NULL){ + fprintf(stderr,"Need a codeword data file on the command line.\n"); + exit(1); + } + if(argv[3]!=NULL)guard=0; + + { + char *ptr; + char *filename=strdup(argv[1]); + + b=codebook_load(filename); + c=(static_codebook *)(b->c); + + ptr=strrchr(filename,'.'); + if(ptr){ + *ptr='\0'; + name=strdup(filename); + }else{ + name=strdup(filename); + } + } + + if(c->maptype!=1){ + fprintf(stderr,"Provided book is not a latticebook.\n"); + exit(1); + } + + entries=b->entries; + dim=b->dim; + + hits=_ogg_malloc(entries*sizeof(long)); + lengths=_ogg_calloc(entries,sizeof(long)); + for(j=0;jlengthlist=lengths; + write_codebook(stdout,name,c); + + { + long bins=_book_maptype1_quantvals(c); + long i,k,base=c->lengthlist[0]; + for(i=0;ilengthlist[i]>base)base=c->lengthlist[i]; + + for(j=0;jlengthlist[j]){ + int indexdiv=1; + fprintf(stderr,"%4ld: ",j); + for(k=0;kdim;k++){ + int index= (j/indexdiv)%bins; + fprintf(stderr,"%+3.1f,", c->quantlist[index]*_float32_unpack(c->q_delta)+ + _float32_unpack(c->q_min)); + indexdiv*=bins; + } + fprintf(stderr,"\t|"); + for(k=0;klengthlist[j];k++)fprintf(stderr,"*"); + fprintf(stderr,"\n"); + } + } + } + + fprintf(stderr,"\r " + "\nDone.\n"); + exit(0); +} diff --git a/vendor/vorbis/vq/localcodebook.h b/vendor/vorbis/vq/localcodebook.h new file mode 100644 index 0000000..dbade0d --- /dev/null +++ b/vendor/vorbis/vq/localcodebook.h @@ -0,0 +1,120 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: basic shared codebook operations + + ********************************************************************/ + +#ifndef _V_CODEBOOK_H_ +#define _V_CODEBOOK_H_ + +#include + +/* This structure encapsulates huffman and VQ style encoding books; it + doesn't do anything specific to either. + + valuelist/quantlist are nonNULL (and q_* significant) only if + there's entry->value mapping to be done. + + If encode-side mapping must be done (and thus the entry needs to be + hunted), the auxiliary encode pointer will point to a decision + tree. This is true of both VQ and huffman, but is mostly useful + with VQ. + +*/ + +typedef struct static_codebook{ + long dim; /* codebook dimensions (elements per vector) */ + long entries; /* codebook entries */ + long *lengthlist; /* codeword lengths in bits */ + + /* mapping ***************************************************************/ + int maptype; /* 0=none + 1=implicitly populated values from map column + 2=listed arbitrary values */ + + /* The below does a linear, single monotonic sequence mapping. */ + long q_min; /* packed 32 bit float; quant value 0 maps to minval */ + long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */ + int q_quant; /* bits: 0 < quant <= 16 */ + int q_sequencep; /* bitflag */ + + long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map + map == 2: list of dim*entries quantized entry vals + */ + int allocedp; +} static_codebook; + +typedef struct codebook{ + long dim; /* codebook dimensions (elements per vector) */ + long entries; /* codebook entries */ + long used_entries; /* populated codebook entries */ + static_codebook *c; + + /* for encode, the below are entry-ordered, fully populated */ + /* for decode, the below are ordered by bitreversed codeword and only + used entries are populated */ + float *valuelist; /* list of dim*entries actual entry values */ + ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */ + + int *dec_index; /* only used if sparseness collapsed */ + char *dec_codelengths; + ogg_uint32_t *dec_firsttable; + int dec_firsttablen; + int dec_maxlength; + + /* The current encoder uses only centered, integer-only lattice books. */ + int quantvals; + int minval; + int delta; + +} codebook; + +extern void vorbis_staticbook_clear(static_codebook *b); +extern void vorbis_staticbook_destroy(static_codebook *b); +extern int vorbis_book_init_encode(codebook *dest,const static_codebook *source); +extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source); +extern void vorbis_book_clear(codebook *b); + +extern float *_book_unquantize(const static_codebook *b,int n,int *map); +extern float *_book_logdist(const static_codebook *b,float *vals); +extern float _float32_unpack(long val); +extern long _float32_pack(float val); +extern int _best(codebook *book, float *a, int step); +extern int _ilog(unsigned int v); +extern long _book_maptype1_quantvals(const static_codebook *b); + +extern int vorbis_book_besterror(codebook *book,float *a,int step,int addmul); +extern long vorbis_book_codeword(codebook *book,int entry); +extern long vorbis_book_codelen(codebook *book,int entry); + + + +extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b); +extern int vorbis_staticbook_unpack(oggpack_buffer *b,static_codebook *c); + +extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b); + +extern long vorbis_book_decode(codebook *book, oggpack_buffer *b); +extern long vorbis_book_decodevs_add(codebook *book, float *a, + oggpack_buffer *b,int n); +extern long vorbis_book_decodev_set(codebook *book, float *a, + oggpack_buffer *b,int n); +extern long vorbis_book_decodev_add(codebook *book, float *a, + oggpack_buffer *b,int n); +extern long vorbis_book_decodevv_add(codebook *book, float **a, + long off,int ch, + oggpack_buffer *b,int n); + + + +#endif diff --git a/vendor/vorbis/vq/make_floor_books.pl b/vendor/vorbis/vq/make_floor_books.pl new file mode 100644 index 0000000..5c37366 --- /dev/null +++ b/vendor/vorbis/vq/make_floor_books.pl @@ -0,0 +1,108 @@ +#!/usr/bin/perl + +# quick, very dirty little script so that we can put all the +# information for building a floor book set in one spec file. + +#eg: + +# >floor_44 +# =44c0_s 44c1_s 44c2_s +# build line_128x4_class0 0-256 +# build line_128x4_0sub0 0-4 + +die "Could not open $ARGV[0]: $!" unless open (F,$ARGV[0]); + +$goflag=0; +while($line=){ + + print "#### $line"; + if($line=~m/^GO/){ + $goflag=1; + next; + } + + if($goflag==0){ + if($line=~m/\S+/ && !($line=~m/^\#/) ){ + my $command=$line; + print ">>> $command"; + die "Couldn't shell command.\n\tcommand:$command\n" + if syst($command); + } + next; + } + + # >floor_44 + # this sets the output bookset file name + if($line=~m/^>(\S+)\s+(\S*)/){ + # set the output name + $globalname=$1; + + $command="rm -f $globalname.vqh"; + die "Couldn't remove file.\n\tcommand:$command\n" + if syst($command); + + next; + } + + #=path1 path2 path3 + #set the search path for input files; each build line will look + #for input files in all of the directories in the search path and + #append them for huffbuild input + if($line=~m/^=(.*)/){ + # set the output name + @paths=split(' ',$1); + next; + } + + # build book.vqd 0-3 [noguard] + if($line=~m/^build (.*)/){ + # build a huffman book (no mapping) + my($datafile,$range,$guard)=split(' ',$1); + + $command="rm -f $datafile.tmp"; + print "\n\n>>> $command\n"; + die "Couldn't remove temp file.\n\tcommand:$command\n" + if syst($command); + + # first find all the inputs we want; they'll need to be collected into a single input file + foreach $dir (@paths){ + if (-e "$dir/$datafile.vqd"){ + $command="cat $dir/$datafile.vqd >> $datafile.tmp"; + print ">>> $command\n"; + die "Couldn't append training data.\n\tcommand:$command\n" + if syst($command); + } + } + + my $command="huffbuild $datafile.tmp $range $guard"; + print ">>> $command\n"; + die "Couldn't build huffbook.\n\tcommand:$command\n" + if syst($command); + + $command="cat $datafile.vqh >> $globalname.vqh"; + print ">>> $command\n"; + die "Couldn't append to output book.\n\tcommand:$command\n" + if syst($command); + + $command="rm $datafile.vqh"; + print ">>> $command\n"; + die "Couldn't remove temporary output file.\n\tcommand:$command\n" + if syst($command); + + $command="rm -f $datafile.tmp"; + print ">>> $command\n"; + die "Couldn't remove temporary output file.\n\tcommand:$command\n" + if syst($command); + next; + } + +} + +$command="rm -f temp$$.vqd"; +print ">>> $command\n"; +die "Couldn't remove temp files.\n\tcommand:$command\n" + if syst($command); + +sub syst{ + system(@_)/256; +} diff --git a/vendor/vorbis/vq/make_residue_books.pl b/vendor/vorbis/vq/make_residue_books.pl new file mode 100644 index 0000000..b37d0dc --- /dev/null +++ b/vendor/vorbis/vq/make_residue_books.pl @@ -0,0 +1,177 @@ +#!/usr/bin/perl + +# quick, very dirty little script so that we can put all the +# information for building a residue book set (except the original +# partitioning) in one spec file. + +#eg: + +# >res0_128_128 interleaved +# haux 44c0_s/resaux_0.vqd res0_96_128aux 0,4,2 9 +# :1 res0_128_128_1.vqd, 4, nonseq cull, 0 +- 1 +# :2 res0_128_128_2.vqd, 4, nonseq, 0 +- 1(.7) 2 +# :3 res0_128_128_3.vqd, 4, nonseq, 0 +- 1(.7) 3 5 +# :4 res0_128_128_4.vqd, 2, nonseq, 0 +- 1(.7) 3 5 8 11 +# :5 res0_128_128_5.vqd, 1, nonseq, 0 +- 1 3 5 8 11 14 17 20 24 28 31 35 39 + + +die "Could not open $ARGV[0]: $!" unless open (F,$ARGV[0]); + +$goflag=0; +while($line=){ + + print "#### $line"; + if($line=~m/^GO/){ + $goflag=1; + next; + } + + if($goflag==0){ + if($line=~m/\S+/ && !($line=~m/^\#/) ){ + my $command=$line; + print ">>> $command"; + die "Couldn't shell command.\n\tcommand:$command\n" + if syst($command); + } + next; + } + + # >res0_128_128 + if($line=~m/^>(\S+)\s+(\S*)/){ + # set the output name + $globalname=$1; + $interleave=$2; + next; + } + + # haux 44c0_s/resaux_0.vqd res0_96_128aux 0,4,2 9 + if($line=~m/^h(.*)/){ + # build a huffman book (no mapping) + my($name,$datafile,$bookname,$interval,$range)=split(' ',$1); + + # check the desired subdir to see if the data file exists + if(-e $datafile){ + my $command="cp $datafile $bookname.tmp"; + print ">>> $command\n"; + die "Couldn't access partition data file.\n\tcommand:$command\n" + if syst($command); + + my $command="huffbuild $bookname.tmp $interval"; + print ">>> $command\n"; + die "Couldn't build huffbook.\n\tcommand:$command\n" + if syst($command); + + my $command="rm $bookname.tmp"; + print ">>> $command\n"; + die "Couldn't remove temporary file.\n\tcommand:$command\n" + if syst($command); + }else{ + my $command="huffbuild $bookname.tmp 0-$range"; + print ">>> $command\n"; + die "Couldn't build huffbook.\n\tcommand:$command\n" + if syst($command); + + } + next; + } + + # :1 res0_128_128_1.vqd, 4, nonseq, 0 +- 1 + if($line=~m/^:(.*)/){ + my($namedata,$dim,$seqp,$vals)=split(',',$1); + my($name,$datafile)=split(' ',$namedata); + # build value list + my$plusminus="+"; + my$list; + my$thlist; + my$count=0; + foreach my$val (split(' ',$vals)){ + if($val=~/\-?\+?\d+/){ + my$th; + + # got an explicit threshhint? + if($val=~/([0-9\.]+)\(([^\)]+)/){ + $val=$1; + $th=$2; + } + + if($plusminus=~/-/){ + $list.="-$val "; + if(defined($th)){ + $thlist.="," if(defined($thlist)); + $thlist.="-$th"; + } + $count++; + } + if($plusminus=~/\+/){ + $list.="$val "; + if(defined($th)){ + $thlist.="," if(defined($thlist)); + $thlist.="$th"; + } + $count++; + } + }else{ + $plusminus=$val; + } + } + die "Couldn't open temp file $globalname$name.vql: $!" unless + open(G,">$globalname$name.vql"); + print G "$count $dim 0 "; + if($seqp=~/non/){ + print G "0\n$list\n"; + }else{ + print G "1\n$list\n"; + } + close(G); + + my $command="latticebuild $globalname$name.vql > $globalname$name.vqh"; + print ">>> $command\n"; + die "Couldn't build latticebook.\n\tcommand:$command\n" + if syst($command); + + if(-e $datafile){ + + if($interleave=~/non/){ + $restune="res1tune"; + }else{ + $restune="res0tune"; + } + + if($seqp=~/cull/){ + my $command="$restune $globalname$name.vqh $datafile 1 > temp$$.vqh"; + print ">>> $command\n"; + die "Couldn't tune latticebook.\n\tcommand:$command\n" + if syst($command); + }else{ + my $command="$restune $globalname$name.vqh $datafile > temp$$.vqh"; + print ">>> $command\n"; + die "Couldn't tune latticebook.\n\tcommand:$command\n" + if syst($command); + } + + my $command="mv temp$$.vqh $globalname$name.vqh"; + print ">>> $command\n"; + die "Couldn't rename latticebook.\n\tcommand:$command\n" + if syst($command); + + }else{ + print "No matching training file; leaving this codebook untrained.\n"; + } + + my $command="rm $globalname$name.vql"; + print ">>> $command\n"; + die "Couldn't remove temp files.\n\tcommand:$command\n" + if syst($command); + + next; + } +} + +$command="rm -f temp$$.vqd"; +print ">>> $command\n"; +die "Couldn't remove temp files.\n\tcommand:$command\n" + if syst($command); + +sub syst{ + system(@_)/256; +} diff --git a/vendor/vorbis/vq/metrics.c b/vendor/vorbis/vq/metrics.c new file mode 100644 index 0000000..d9f0da3 --- /dev/null +++ b/vendor/vorbis/vq/metrics.c @@ -0,0 +1,294 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: function calls to collect codebook metrics + + ********************************************************************/ + + +#include +#include +#include +#include "bookutil.h" + +/* collect the following metrics: + + mean and mean squared amplitude + mean and mean squared error + mean and mean squared error (per sample) by entry + worst case fit by entry + entry cell size + hits by entry + total bits + total samples + (average bits per sample)*/ + + +/* set up metrics */ + +float meanamplitude_acc=0.f; +float meanamplitudesq_acc=0.f; +float meanerror_acc=0.f; +float meanerrorsq_acc=0.f; + +float **histogram=NULL; +float **histogram_error=NULL; +float **histogram_errorsq=NULL; +float **histogram_hi=NULL; +float **histogram_lo=NULL; +float bits=0.f; +float count=0.f; + +static float *_now(codebook *c, int i){ + return c->valuelist+i*c->c->dim; +} + +int books=0; + +void process_preprocess(codebook **bs,char *basename){ + int i; + while(bs[books])books++; + + if(books){ + histogram=_ogg_calloc(books,sizeof(float *)); + histogram_error=_ogg_calloc(books,sizeof(float *)); + histogram_errorsq=_ogg_calloc(books,sizeof(float *)); + histogram_hi=_ogg_calloc(books,sizeof(float *)); + histogram_lo=_ogg_calloc(books,sizeof(float *)); + }else{ + fprintf(stderr,"Specify at least one codebook\n"); + exit(1); + } + + for(i=0;ientries,sizeof(float)); + histogram_error[i]=_ogg_calloc(b->entries*b->dim,sizeof(float)); + histogram_errorsq[i]=_ogg_calloc(b->entries*b->dim,sizeof(float)); + histogram_hi[i]=_ogg_calloc(b->entries*b->dim,sizeof(float)); + histogram_lo[i]=_ogg_calloc(b->entries*b->dim,sizeof(float)); + } +} + +static float _dist(int el,float *a, float *b){ + int i; + float acc=0.f; + for(i=0;ic->entries;j++){ + if(c->c->lengthlist[j]>0){ + float localmin=-1.; + for(k=0;kc->entries;k++){ + if(c->c->lengthlist[k]>0){ + float this=_dist(c->c->dim,_now(c,j),_now(c,k)); + if(j!=k && + (localmin==-1 || thismax)max=localmin; + mean+=sqrt(localmin); + meansq+=localmin; + total++; + } + } + + fprintf(stderr,"\tminimum cell spacing (closest side): %g\n",sqrt(min)); + fprintf(stderr,"\tmaximum cell spacing (closest side): %g\n",sqrt(max)); + fprintf(stderr,"\tmean closest side spacing: %g\n",mean/total); + fprintf(stderr,"\tmean sq closest side spacing: %g\n",sqrt(meansq/total)); +} + +void process_postprocess(codebook **bs,char *basename){ + int i,k,book; + char *buffer=alloca(strlen(basename)+80); + + fprintf(stderr,"Done. Processed %ld data points:\n\n", + (long)count); + + fprintf(stderr,"Global statistics:******************\n\n"); + + fprintf(stderr,"\ttotal samples: %ld\n",(long)count); + fprintf(stderr,"\ttotal bits required to code: %ld\n",(long)bits); + fprintf(stderr,"\taverage bits per sample: %g\n\n",bits/count); + + fprintf(stderr,"\tmean sample amplitude: %g\n", + meanamplitude_acc/count); + fprintf(stderr,"\tmean squared sample amplitude: %g\n\n", + sqrt(meanamplitudesq_acc/count)); + + fprintf(stderr,"\tmean code error: %g\n", + meanerror_acc/count); + fprintf(stderr,"\tmean squared code error: %g\n\n", + sqrt(meanerrorsq_acc/count)); + + for(book=0;bookc->entries; + int dim=b->c->dim; + + fprintf(stderr,"Book %d statistics:------------------\n",book); + + cell_spacing(b); + + sprintf(buffer,"%s-%d-mse.m",basename,book); + out=fopen(buffer,"w"); + if(!out){ + fprintf(stderr,"Could not open file %s for writing\n",buffer); + exit(1); + } + + for(i=0;ivaluelist+i*dim)[k], + sqrt((histogram_errorsq[book]+i*dim)[k]/histogram[book][i])); + } + } + fclose(out); + + sprintf(buffer,"%s-%d-me.m",basename,book); + out=fopen(buffer,"w"); + if(!out){ + fprintf(stderr,"Could not open file %s for writing\n",buffer); + exit(1); + } + + for(i=0;ivaluelist+i*dim)[k], + (histogram_error[book]+i*dim)[k]/histogram[book][i]); + } + } + fclose(out); + + sprintf(buffer,"%s-%d-worst.m",basename,book); + out=fopen(buffer,"w"); + if(!out){ + fprintf(stderr,"Could not open file %s for writing\n",buffer); + exit(1); + } + + for(i=0;ivaluelist+i*dim)[k], + (b->valuelist+i*dim)[k]+(histogram_lo[book]+i*dim)[k], + (b->valuelist+i*dim)[k]+(histogram_hi[book]+i*dim)[k]); + } + } + fclose(out); + } +} + +float process_one(codebook *b,int book,float *a,int dim,int step,int addmul, + float base){ + int j,entry; + float amplitude=0.f; + + if(book==0){ + float last=base; + for(j=0;jc->q_sequencep?last:0); + meanamplitude_acc+=fabs(amplitude); + meanamplitudesq_acc+=amplitude*amplitude; + count++; + last=a[j*step]; + } + } + + if(b->c->q_sequencep){ + float temp; + for(j=0;jerror) + histogram_lo[book][entry*dim+j]=error; + } + return base; +} + + +void process_vector(codebook **bs,int *addmul,int inter,float *a,int n){ + int bi; + int i; + + for(bi=0;bidim; + float base=0.f; + + if(inter){ + for(i=0;i.vqh [ +|* ]... \n" + " datafile.vqd [datafile.vqd]...\n\n" + " data can be taken on stdin. -i indicates interleaved coding.\n" + " Output goes to output files:\n" + " basename-me.m: gnuplot: mean error by entry value\n" + " basename-mse.m: gnuplot: mean square error by entry value\n" + " basename-worst.m: gnuplot: worst error by entry value\n" + " basename-distance.m: gnuplot file showing distance probability\n" + "\n"); + +} diff --git a/vendor/vorbis/vq/vqgen.c b/vendor/vorbis/vq/vqgen.c new file mode 100644 index 0000000..45f7790 --- /dev/null +++ b/vendor/vorbis/vq/vqgen.c @@ -0,0 +1,566 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: train a VQ codebook + + ********************************************************************/ + +/* This code is *not* part of libvorbis. It is used to generate + trained codebooks offline and then spit the results into a + pregenerated codebook that is compiled into libvorbis. It is an + expensive (but good) algorithm. Run it on big iron. */ + +/* There are so many optimizations to explore in *both* stages that + considering the undertaking is almost withering. For now, we brute + force it all */ + +#include +#include +#include +#include + +#include "vqgen.h" +#include "bookutil.h" + +/* Codebook generation happens in two steps: + + 1) Train the codebook with data collected from the encoder: We use + one of a few error metrics (which represent the distance between a + given data point and a candidate point in the training set) to + divide the training set up into cells representing roughly equal + probability of occurring. + + 2) Generate the codebook and auxiliary data from the trained data set +*/ + +/* Codebook training **************************************************** + * + * The basic idea here is that a VQ codebook is like an m-dimensional + * foam with n bubbles. The bubbles compete for space/volume and are + * 'pressurized' [biased] according to some metric. The basic alg + * iterates through allowing the bubbles to compete for space until + * they converge (if the damping is dome properly) on a steady-state + * solution. Individual input points, collected from libvorbis, are + * used to train the algorithm monte-carlo style. */ + +/* internal helpers *****************************************************/ +#define vN(data,i) (data+v->elements*i) + +/* default metric; squared 'distance' from desired value. */ +float _dist(vqgen *v,float *a, float *b){ + int i; + int el=v->elements; + float acc=0.f; + for(i=0;ientries;i++) + memcpy(_now(v,i),_point(v,i),sizeof(float)*v->elements); + v->seeded=1; +} + +int directdsort(const void *a, const void *b){ + float av=*((float *)a); + float bv=*((float *)b); + return (avbv); +} + +void vqgen_cellmetric(vqgen *v){ + int j,k; + float min=-1.f,max=-1.f,mean=0.f,acc=0.f; + long dup=0,unused=0; + #ifdef NOISY + int i; + char buff[80]; + float spacings[v->entries]; + int count=0; + FILE *cells; + sprintf(buff,"cellspace%d.m",v->it); + cells=fopen(buff,"w"); +#endif + + /* minimum, maximum, cell spacing */ + for(j=0;jentries;j++){ + float localmin=-1.; + + for(k=0;kentries;k++){ + if(j!=k){ + float this=_dist(v,_now(v,j),_now(v,k)); + if(this>0){ + if(v->assigned[k] && (localmin==-1 || thisentries)continue; + + if(v->assigned[j]==0){ + unused++; + continue; + } + + localmin=v->max[j]+localmin/2; /* this gives us rough diameter */ + if(min==-1 || localminmax)max=localmin; + mean+=localmin; + acc++; +#ifdef NOISY + spacings[count++]=localmin; +#endif + } + + fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n", + min,mean/acc,max,unused,dup); + +#ifdef NOISY + qsort(spacings,count,sizeof(float),directdsort); + for(i=0;iquant)-1); + + int j,k; + + mindel=maxdel=_now(v,0)[0]; + + for(j=0;jentries;j++){ + float last=0.f; + for(k=0;kelements;k++){ + if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last; + if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last; + if(q->sequencep)last=_now(v,j)[k]; + } + } + + + /* first find the basic delta amount from the maximum span to be + encoded. Loosen the delta slightly to allow for additional error + during sequence quantization */ + + delta=(maxdel-mindel)/((1<quant)-1.5f); + + q->min=_float32_pack(mindel); + q->delta=_float32_pack(delta); + + mindel=_float32_unpack(q->min); + delta=_float32_unpack(q->delta); + + for(j=0;jentries;j++){ + float last=0; + for(k=0;kelements;k++){ + float val=_now(v,j)[k]; + float now=rint((val-last-mindel)/delta); + + _now(v,j)[k]=now; + if(now<0){ + /* be paranoid; this should be impossible */ + fprintf(stderr,"fault; quantized value<0\n"); + exit(1); + } + + if(now>maxquant){ + /* be paranoid; this should be impossible */ + fprintf(stderr,"fault; quantized value>max\n"); + exit(1); + } + if(q->sequencep)last=(now*delta)+mindel+last; + } + } +} + +/* much easier :-). Unlike in the codebook, we don't un-log log + scales; we just make sure they're properly offset. */ +void vqgen_unquantize(vqgen *v,quant_meta *q){ + long j,k; + float mindel=_float32_unpack(q->min); + float delta=_float32_unpack(q->delta); + + for(j=0;jentries;j++){ + float last=0.f; + for(k=0;kelements;k++){ + float now=_now(v,j)[k]; + now=fabs(now)*delta+last+mindel; + if(q->sequencep)last=now; + _now(v,j)[k]=now; + } + } +} + +void vqgen_init(vqgen *v,int elements,int aux,int entries,float mindist, + float (*metric)(vqgen *,float *, float *), + float *(*weight)(vqgen *,float *),int centroid){ + memset(v,0,sizeof(vqgen)); + + v->centroid=centroid; + v->elements=elements; + v->aux=aux; + v->mindist=mindist; + v->allocated=32768; + v->pointlist=_ogg_malloc(v->allocated*(v->elements+v->aux)*sizeof(float)); + + v->entries=entries; + v->entrylist=_ogg_malloc(v->entries*v->elements*sizeof(float)); + v->assigned=_ogg_malloc(v->entries*sizeof(long)); + v->bias=_ogg_calloc(v->entries,sizeof(float)); + v->max=_ogg_calloc(v->entries,sizeof(float)); + if(metric) + v->metric_func=metric; + else + v->metric_func=_dist; + if(weight) + v->weight_func=weight; + else + v->weight_func=_weight_null; + + v->asciipoints=tmpfile(); + +} + +void vqgen_addpoint(vqgen *v, float *p,float *a){ + int k; + for(k=0;kelements;k++) + fprintf(v->asciipoints,"%.12g\n",p[k]); + for(k=0;kaux;k++) + fprintf(v->asciipoints,"%.12g\n",a[k]); + + if(v->points>=v->allocated){ + v->allocated*=2; + v->pointlist=_ogg_realloc(v->pointlist,v->allocated*(v->elements+v->aux)* + sizeof(float)); + } + + memcpy(_point(v,v->points),p,sizeof(float)*v->elements); + if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(float)*v->aux); + + /* quantize to the density mesh if it's selected */ + if(v->mindist>0.f){ + /* quantize to the mesh */ + for(k=0;kelements+v->aux;k++) + _point(v,v->points)[k]= + rint(_point(v,v->points)[k]/v->mindist)*v->mindist; + } + v->points++; + if(!(v->points&0xff))spinnit("loading... ",v->points); +} + +/* yes, not threadsafe. These utils aren't */ +static int sortit=0; +static int sortsize=0; +static int meshcomp(const void *a,const void *b){ + if(((sortit++)&0xfff)==0)spinnit("sorting mesh...",sortit); + return(memcmp(a,b,sortsize)); +} + +void vqgen_sortmesh(vqgen *v){ + sortit=0; + if(v->mindist>0.f){ + long i,march=1; + + /* sort to make uniqueness detection trivial */ + sortsize=(v->elements+v->aux)*sizeof(float); + qsort(v->pointlist,v->points,sortsize,meshcomp); + + /* now march through and eliminate dupes */ + for(i=1;ipoints;i++){ + if(memcmp(_point(v,i),_point(v,i-1),sortsize)){ + /* a new, unique entry. march it down */ + if(i>march)memcpy(_point(v,march),_point(v,i),sortsize); + march++; + } + spinnit("eliminating density... ",v->points-i); + } + + /* we're done */ + fprintf(stderr,"\r%ld training points remining out of %ld" + " after density mesh (%ld%%)\n",march,v->points,march*100/v->points); + v->points=march; + + } + v->sorted=1; +} + +float vqgen_iterate(vqgen *v,int biasp){ + long i,j,k; + + float fdesired; + long desired; + long desired2; + + float asserror=0.f; + float meterror=0.f; + float *new; + float *new2; + long *nearcount; + float *nearbias; + #ifdef NOISY + char buff[80]; + FILE *assig; + FILE *bias; + FILE *cells; + sprintf(buff,"cells%d.m",v->it); + cells=fopen(buff,"w"); + sprintf(buff,"assig%d.m",v->it); + assig=fopen(buff,"w"); + sprintf(buff,"bias%d.m",v->it); + bias=fopen(buff,"w"); + #endif + + + if(v->entries<2){ + fprintf(stderr,"generation requires at least two entries\n"); + exit(1); + } + + if(!v->sorted)vqgen_sortmesh(v); + if(!v->seeded)_vqgen_seed(v); + + fdesired=(float)v->points/v->entries; + desired=fdesired; + desired2=desired*2; + new=_ogg_malloc(sizeof(float)*v->entries*v->elements); + new2=_ogg_malloc(sizeof(float)*v->entries*v->elements); + nearcount=_ogg_malloc(v->entries*sizeof(long)); + nearbias=_ogg_malloc(v->entries*desired2*sizeof(float)); + + /* fill in nearest points for entry biasing */ + /*memset(v->bias,0,sizeof(float)*v->entries);*/ + memset(nearcount,0,sizeof(long)*v->entries); + memset(v->assigned,0,sizeof(long)*v->entries); + if(biasp){ + for(i=0;ipoints;i++){ + float *ppt=v->weight_func(v,_point(v,i)); + float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0]; + float secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1]; + long firstentry=0; + long secondentry=1; + + if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i); + + if(firstmetric>secondmetric){ + float temp=firstmetric; + firstmetric=secondmetric; + secondmetric=temp; + firstentry=1; + secondentry=0; + } + + for(j=2;jentries;j++){ + float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j]; + if(thismetricentries;j++){ + + float thismetric,localmetric; + float *nearbiasptr=nearbias+desired2*j; + long k=nearcount[j]; + + localmetric=v->metric_func(v,_now(v,j),ppt); + /* 'thismetric' is to be the bias value necessary in the current + arrangement for entry j to capture point i */ + if(firstentry==j){ + /* use the secondary entry as the threshhold */ + thismetric=secondmetric-localmetric; + }else{ + /* use the primary entry as the threshhold */ + thismetric=firstmetric-localmetric; + } + + /* support the idea of 'minimum distance'... if we want the + cells in a codebook to be roughly some minimum size (as with + the low resolution residue books) */ + + /* a cute two-stage delayed sorting hack */ + if(kpoints+v->points+v->entries-i); + qsort(nearbiasptr,desired,sizeof(float),directdsort); + } + + }else if(thismetric>nearbiasptr[desired-1]){ + nearbiasptr[k]=thismetric; + k++; + if(k==desired2){ + spinnit("biasing... ",v->points+v->points+v->entries-i); + qsort(nearbiasptr,desired2,sizeof(float),directdsort); + k=desired; + } + } + nearcount[j]=k; + } + } + + /* inflate/deflate */ + + for(i=0;ientries;i++){ + float *nearbiasptr=nearbias+desired2*i; + + spinnit("biasing... ",v->points+v->entries-i); + + /* due to the delayed sorting, we likely need to finish it off....*/ + if(nearcount[i]>desired) + qsort(nearbiasptr,nearcount[i],sizeof(float),directdsort); + + v->bias[i]=nearbiasptr[desired-1]; + + } + }else{ + memset(v->bias,0,v->entries*sizeof(float)); + } + + /* Now assign with new bias and find new midpoints */ + for(i=0;ipoints;i++){ + float *ppt=v->weight_func(v,_point(v,i)); + float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0]; + long firstentry=0; + + if(!(i&0xff))spinnit("centering... ",v->points-i); + + for(j=0;jentries;j++){ + float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j]; + if(thismetricbias[j]; + meterror+=firstmetric; + + if(v->centroid==0){ + /* set up midpoints for next iter */ + if(v->assigned[j]++){ + for(k=0;kelements;k++) + vN(new,j)[k]+=ppt[k]; + if(firstmetric>v->max[j])v->max[j]=firstmetric; + }else{ + for(k=0;kelements;k++) + vN(new,j)[k]=ppt[k]; + v->max[j]=firstmetric; + } + }else{ + /* centroid */ + if(v->assigned[j]++){ + for(k=0;kelements;k++){ + if(vN(new,j)[k]>ppt[k])vN(new,j)[k]=ppt[k]; + if(vN(new2,j)[k]v->max[firstentry])v->max[j]=firstmetric; + }else{ + for(k=0;kelements;k++){ + vN(new,j)[k]=ppt[k]; + vN(new2,j)[k]=ppt[k]; + } + v->max[firstentry]=firstmetric; + } + } + } + + /* assign midpoints */ + + for(j=0;jentries;j++){ +#ifdef NOISY + fprintf(assig,"%ld\n",v->assigned[j]); + fprintf(bias,"%g\n",v->bias[j]); +#endif + asserror+=fabs(v->assigned[j]-fdesired); + if(v->assigned[j]){ + if(v->centroid==0){ + for(k=0;kelements;k++) + _now(v,j)[k]=vN(new,j)[k]/v->assigned[j]; + }else{ + for(k=0;kelements;k++) + _now(v,j)[k]=(vN(new,j)[k]+vN(new2,j)[k])/2.f; + } + } + } + + asserror/=(v->entries*fdesired); + + fprintf(stderr,"Pass #%d... ",v->it); + fprintf(stderr,": dist %g(%g) metric error=%g \n", + asserror,fdesired,meterror/v->points); + v->it++; + + free(new); + free(nearcount); + free(nearbias); +#ifdef NOISY + fclose(assig); + fclose(bias); + fclose(cells); +#endif + return(asserror); +} + diff --git a/vendor/vorbis/vq/vqgen.h b/vendor/vorbis/vq/vqgen.h new file mode 100644 index 0000000..47a7d2d --- /dev/null +++ b/vendor/vorbis/vq/vqgen.h @@ -0,0 +1,84 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: build a VQ codebook + + ********************************************************************/ + +#ifndef _VQGEN_H_ +#define _VQGEN_H_ + +typedef struct vqgen{ + int seeded; + int sorted; + + int it; + int elements; + + int aux; + float mindist; + int centroid; + + /* point cache */ + float *pointlist; + long points; + long allocated; + + /* entries */ + float *entrylist; + long *assigned; + float *bias; + long entries; + float *max; + + float (*metric_func) (struct vqgen *v,float *entry,float *point); + float *(*weight_func) (struct vqgen *v,float *point); + + FILE *asciipoints; +} vqgen; + +typedef struct { + long min; /* packed 24 bit float */ + long delta; /* packed 24 bit float */ + int quant; /* 0 < quant <= 16 */ + int sequencep; /* bitflag */ +} quant_meta; + +static inline float *_point(vqgen *v,long ptr){ + return v->pointlist+((v->elements+v->aux)*ptr); +} + +static inline float *_aux(vqgen *v,long ptr){ + return _point(v,ptr)+v->aux; +} + +static inline float *_now(vqgen *v,long ptr){ + return v->entrylist+(v->elements*ptr); +} + +extern void vqgen_init(vqgen *v, + int elements,int aux,int entries,float mindist, + float (*metric)(vqgen *,float *, float *), + float *(*weight)(vqgen *,float *),int centroid); +extern void vqgen_addpoint(vqgen *v, float *p,float *aux); + +extern float vqgen_iterate(vqgen *v,int biasp); +extern void vqgen_unquantize(vqgen *v,quant_meta *q); +extern void vqgen_quantize(vqgen *v,quant_meta *q); +extern void vqgen_cellmetric(vqgen *v); + +#endif + + + + +
  3. $`PcK)SJ^kzbV}N|y7yz#H9Pw( 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%0D_uuRTEn2aK{XvML#ehF=V|h11JxD6hlK{J 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